OpenDNSSEC-signer 1.3.0
|
00001 /* 00002 * $Id: cmdhandler.c 5320 2011-07-12 10:42:26Z jakob $ 00003 * 00004 * Copyright (c) 2009 NLNet Labs. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00019 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00020 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00021 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 00023 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00025 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 * 00027 */ 00028 00034 #include "daemon/cmdhandler.h" 00035 #include "daemon/engine.h" 00036 #include "scheduler/schedule.h" 00037 #include "scheduler/task.h" 00038 #include "shared/allocator.h" 00039 #include "shared/file.h" 00040 #include "shared/locks.h" 00041 #include "shared/log.h" 00042 #include "shared/status.h" 00043 00044 #include <errno.h> 00045 #include <fcntl.h> 00046 #include <ldns/ldns.h> 00047 #include <stdio.h> 00048 #include <stdlib.h> 00049 #include <string.h> 00050 #include <strings.h> 00051 #include <sys/select.h> 00052 #include <sys/socket.h> 00053 #ifdef HAVE_SYS_TYPES_H 00054 # include <sys/types.h> 00055 #endif 00056 #include <unistd.h> 00057 /* According to earlier standards: select() sys/time.h sys/types.h unistd.h */ 00058 #include <sys/time.h> 00059 #include <sys/types.h> 00060 00061 #define SE_CMDH_CMDLEN 7 00062 00063 #ifndef SUN_LEN 00064 #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) 00065 #endif 00066 00067 static int count = 0; 00068 static char* cmdh_str = "cmdhandler"; 00069 00070 00075 static void 00076 cmdhandler_handle_cmd_help(int sockfd) 00077 { 00078 char buf[ODS_SE_MAXLINE]; 00079 00080 (void) snprintf(buf, ODS_SE_MAXLINE, 00081 "Commands:\n" 00082 "zones show the currently known zones.\n" 00083 "sign <zone> read zone and schedule for immediate (re-)sign.\n" 00084 "sign --all read all zones and schedule all for immediate " 00085 "(re-)sign.\n" 00086 "clear <zone> delete the internal storage of this zone.\n" 00087 " All signatures will be regenerated on the next " 00088 "re-sign.\n" 00089 "queue show the current task queue.\n" 00090 ); 00091 ods_writen(sockfd, buf, strlen(buf)); 00092 00093 (void) snprintf(buf, ODS_SE_MAXLINE, 00094 "flush execute all scheduled tasks immediately.\n" 00095 "update <zone> update this zone signer configurations.\n" 00096 "update [--all] update zone list and all signer configurations.\n" 00097 "start start the engine.\n" 00098 "running check if the engine is running.\n" 00099 "reload reload the engine.\n" 00100 "stop stop the engine.\n" 00101 "verbosity <nr> set verbosity.\n" 00102 ); 00103 ods_writen(sockfd, buf, strlen(buf)); 00104 return; 00105 } 00106 00107 00112 static void 00113 cmdhandler_handle_cmd_zones(int sockfd, cmdhandler_type* cmdc) 00114 { 00115 char buf[ODS_SE_MAXLINE]; 00116 size_t i; 00117 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00118 zone_type* zone = NULL; 00119 00120 ods_log_assert(cmdc); 00121 ods_log_assert(cmdc->engine); 00122 if (!cmdc->engine->zonelist || !cmdc->engine->zonelist->zones) { 00123 (void)snprintf(buf, ODS_SE_MAXLINE, "I have no zones configured\n"); 00124 ods_writen(sockfd, buf, strlen(buf)); 00125 return; 00126 } 00127 00128 lock_basic_lock(&cmdc->engine->zonelist->zl_lock); 00129 /* how many zones */ 00130 /* [LOCK] zonelist */ 00131 (void)snprintf(buf, ODS_SE_MAXLINE, "I have %i zones configured\n", 00132 (int) cmdc->engine->zonelist->zones->count); 00133 ods_writen(sockfd, buf, strlen(buf)); 00134 00135 /* list zones */ 00136 node = ldns_rbtree_first(cmdc->engine->zonelist->zones); 00137 while (node && node != LDNS_RBTREE_NULL) { 00138 zone = (zone_type*) node->data; 00139 for (i=0; i < ODS_SE_MAXLINE; i++) { 00140 buf[i] = 0; 00141 } 00142 (void)snprintf(buf, ODS_SE_MAXLINE, "- %s\n", zone->name); 00143 ods_writen(sockfd, buf, strlen(buf)); 00144 node = ldns_rbtree_next(node); 00145 } 00146 /* [UNLOCK] zonelist */ 00147 lock_basic_unlock(&cmdc->engine->zonelist->zl_lock); 00148 return; 00149 } 00150 00151 00156 static void 00157 cmdhandler_handle_cmd_update(int sockfd, cmdhandler_type* cmdc, 00158 const char* tbd) 00159 { 00160 char buf[ODS_SE_MAXLINE]; 00161 ods_status status = ODS_STATUS_OK; 00162 zone_type* zone = NULL; 00163 task_type* task = NULL; 00164 int zl_changed = 0; 00165 00166 ods_log_assert(tbd); 00167 ods_log_assert(cmdc); 00168 ods_log_assert(cmdc->engine); 00169 ods_log_assert(cmdc->engine->taskq); 00170 00171 if (ods_strcmp(tbd, "--all") == 0) { 00172 /* [LOCK] zonelist */ 00173 lock_basic_lock(&cmdc->engine->zonelist->zl_lock); 00174 zl_changed = zonelist_update(cmdc->engine->zonelist, 00175 cmdc->engine->config->zonelist_filename); 00176 /* [UNLOCK] zonelist */ 00177 if (zl_changed == ODS_STATUS_UNCHANGED) { 00178 lock_basic_unlock(&cmdc->engine->zonelist->zl_lock); 00179 (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has not changed." 00180 "\n"); 00181 ods_writen(sockfd, buf, strlen(buf)); 00182 } else if (zl_changed == ODS_STATUS_OK) { 00183 (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list updated: %i " 00184 "removed, %i added, %i updated.\n", 00185 cmdc->engine->zonelist->just_removed, 00186 cmdc->engine->zonelist->just_added, 00187 cmdc->engine->zonelist->just_updated); 00188 ods_writen(sockfd, buf, strlen(buf)); 00189 00190 cmdc->engine->zonelist->just_removed = 0; 00191 cmdc->engine->zonelist->just_added = 0; 00192 cmdc->engine->zonelist->just_updated = 0; 00193 lock_basic_unlock(&cmdc->engine->zonelist->zl_lock); 00194 00195 ods_log_debug("[%s] commit zone list changes", cmdh_str); 00196 engine_update_zones(cmdc->engine); 00197 ods_log_debug("[%s] signer configurations updated", cmdh_str); 00198 } else { 00199 lock_basic_unlock(&cmdc->engine->zonelist->zl_lock); 00200 (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has errors.\n"); 00201 ods_writen(sockfd, buf, strlen(buf)); 00202 } 00203 return; 00204 } else { 00205 /* look up zone */ 00206 lock_basic_lock(&cmdc->engine->zonelist->zl_lock); 00207 /* [LOCK] zonelist */ 00208 zone = zonelist_lookup_zone_by_name(cmdc->engine->zonelist, tbd, 00209 LDNS_RR_CLASS_IN); 00210 if (zone && zone->just_added) { 00211 zone = NULL; 00212 } 00213 /* [UNLOCK] zonelist */ 00214 lock_basic_unlock(&cmdc->engine->zonelist->zl_lock); 00215 if (!zone) { 00216 (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s not found.\n", 00217 tbd); 00218 ods_writen(sockfd, buf, strlen(buf)); 00219 /* update all */ 00220 cmdhandler_handle_cmd_update(sockfd, cmdc, "--all"); 00221 return; 00222 } 00223 00224 lock_basic_lock(&zone->zone_lock); 00225 ods_log_assert(zone->task); 00226 00227 lock_basic_lock(&cmdc->engine->taskq->schedule_lock); 00228 /* [LOCK] schedule */ 00229 task = unschedule_task(cmdc->engine->taskq, (task_type*) zone->task); 00230 if (task != NULL) { 00231 ods_log_debug("[%s] reschedule task for zone %s", cmdh_str, 00232 zone->name); 00233 if (task->what != TASK_SIGNCONF) { 00234 task->halted = task->what; 00235 task->interrupt = TASK_SIGNCONF; 00236 } 00237 task->what = TASK_SIGNCONF; 00238 task->when = time_now(); 00239 status = schedule_task(cmdc->engine->taskq, task, 0); 00240 } else { 00241 /* task not queued, being worked on? */ 00242 ods_log_verbose("[%s] worker busy with zone %s, will update " 00243 "signconf as soon as possible", cmdh_str, zone->name); 00244 task = (task_type*) zone->task; 00245 task->interrupt = TASK_SIGNCONF; 00246 /* task->halted set by worker */ 00247 } 00248 /* [UNLOCK] schedule */ 00249 lock_basic_unlock(&cmdc->engine->taskq->schedule_lock); 00250 00251 zone->task = task; 00252 lock_basic_unlock(&zone->zone_lock); 00253 00254 if (status != ODS_STATUS_OK) { 00255 ods_log_crit("[%s] cannot schedule task for zone %s: %s", 00256 cmdh_str, zone->name, ods_status2str(status)); 00257 task_cleanup(task); 00258 zone->task = NULL; 00259 } else { 00260 engine_wakeup_workers(cmdc->engine); 00261 } 00262 00263 (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s config being updated.\n", 00264 tbd); 00265 ods_writen(sockfd, buf, strlen(buf)); 00266 } 00267 return; 00268 } 00269 00270 00275 static void 00276 cmdhandler_handle_cmd_sign(int sockfd, cmdhandler_type* cmdc, const char* tbd) 00277 { 00278 zone_type* zone = NULL; 00279 task_type* task = NULL; 00280 ods_status status = ODS_STATUS_OK; 00281 char buf[ODS_SE_MAXLINE]; 00282 00283 ods_log_assert(tbd); 00284 ods_log_assert(cmdc); 00285 ods_log_assert(cmdc->engine); 00286 ods_log_assert(cmdc->engine->taskq); 00287 00288 if (ods_strcmp(tbd, "--all") == 0) { 00289 lock_basic_lock(&cmdc->engine->taskq->schedule_lock); 00290 /* [LOCK] schedule */ 00291 schedule_flush(cmdc->engine->taskq, TASK_READ); 00292 /* [UNLOCK] schedule */ 00293 lock_basic_unlock(&cmdc->engine->taskq->schedule_lock); 00294 engine_wakeup_workers(cmdc->engine); 00295 (void)snprintf(buf, ODS_SE_MAXLINE, "All zones scheduled for " 00296 "immediate re-sign.\n"); 00297 ods_writen(sockfd, buf, strlen(buf)); 00298 ods_log_verbose("[%s] all zones scheduled for immediate re-sign", 00299 cmdh_str); 00300 return; 00301 } else { 00302 lock_basic_lock(&cmdc->engine->zonelist->zl_lock); 00303 /* [LOCK] zonelist */ 00304 zone = zonelist_lookup_zone_by_name(cmdc->engine->zonelist, tbd, 00305 LDNS_RR_CLASS_IN); 00306 if (zone && zone->just_added) { 00307 zone = NULL; 00308 } 00309 /* [UNLOCK] zonelist */ 00310 lock_basic_unlock(&cmdc->engine->zonelist->zl_lock); 00311 00312 if (!zone) { 00313 (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s not found.\n", 00314 tbd); 00315 ods_writen(sockfd, buf, strlen(buf)); 00316 return; 00317 } 00318 00319 lock_basic_lock(&zone->zone_lock); 00320 ods_log_assert(zone->task); 00321 00322 lock_basic_lock(&cmdc->engine->taskq->schedule_lock); 00323 /* [LOCK] schedule */ 00324 task = unschedule_task(cmdc->engine->taskq, (task_type*) zone->task); 00325 if (task != NULL) { 00326 ods_log_debug("[%s] reschedule task for zone %s", cmdh_str, 00327 zone->name); 00328 if (task->what != TASK_READ) { 00329 task->halted = task->what; 00330 task->interrupt = TASK_READ; 00331 } 00332 task->what = TASK_READ; 00333 task->when = time_now(); 00334 status = schedule_task(cmdc->engine->taskq, task, 0); 00335 } else { 00336 /* task now queued, being worked on? */ 00337 ods_log_verbose("[%s] worker busy with zone %s, will read " 00338 "zone input as soon as possible", cmdh_str, zone->name); 00339 task = (task_type*) zone->task; 00340 task->interrupt = TASK_READ; 00341 /* task->halted set by worker */ 00342 } 00343 /* [UNLOCK] schedule */ 00344 lock_basic_unlock(&cmdc->engine->taskq->schedule_lock); 00345 00346 zone->task = task; 00347 lock_basic_unlock(&zone->zone_lock); 00348 00349 if (status != ODS_STATUS_OK) { 00350 (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Cannot schedule task for " 00351 "zone %s.\n", tbd); 00352 ods_writen(sockfd, buf, strlen(buf)); 00353 ods_log_crit("[%s] cannot schedule task for zone %s: %s", 00354 cmdh_str, zone->name, ods_status2str(status)); 00355 task_cleanup(task); 00356 zone->task = NULL; 00357 } else { 00358 (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s scheduled for immediate " 00359 "re-sign.\n", tbd); 00360 ods_writen(sockfd, buf, strlen(buf)); 00361 ods_log_verbose("[%s] zone %s scheduled for immediate re-sign", 00362 cmdh_str, tbd); 00363 engine_wakeup_workers(cmdc->engine); 00364 } 00365 } 00366 return; 00367 } 00368 00369 00374 static void 00375 unlink_backup_file(const char* filename, const char* extension) 00376 { 00377 char* tmpname = ods_build_path(filename, extension, 0); 00378 ods_log_debug("[%s] unlink file %s", cmdh_str, tmpname); 00379 unlink(tmpname); 00380 free((void*)tmpname); 00381 return; 00382 } 00383 00388 static void 00389 cmdhandler_handle_cmd_clear(int sockfd, cmdhandler_type* cmdc, const char* tbd) 00390 { 00391 char buf[ODS_SE_MAXLINE]; 00392 zone_type* zone = NULL; 00393 task_type* task = NULL; 00394 uint32_t inbound_serial = 0; 00395 uint32_t internal_serial = 0; 00396 uint32_t outbound_serial = 0; 00397 ods_status status = ODS_STATUS_OK; 00398 00399 ods_log_assert(tbd); 00400 ods_log_assert(cmdc); 00401 ods_log_assert(cmdc->engine); 00402 00403 unlink_backup_file(tbd, ".inbound"); 00404 unlink_backup_file(tbd, ".backup"); 00405 00406 lock_basic_lock(&cmdc->engine->zonelist->zl_lock); 00407 /* [LOCK] zonelist */ 00408 zone = zonelist_lookup_zone_by_name(cmdc->engine->zonelist, tbd, 00409 LDNS_RR_CLASS_IN); 00410 /* [UNLOCK] zonelist */ 00411 lock_basic_unlock(&cmdc->engine->zonelist->zl_lock); 00412 if (zone) { 00413 /* [LOCK] zone */ 00414 lock_basic_lock(&zone->zone_lock); 00415 inbound_serial = zone->zonedata->inbound_serial; 00416 internal_serial = zone->zonedata->internal_serial; 00417 outbound_serial = zone->zonedata->outbound_serial; 00418 zonedata_cleanup(zone->zonedata); 00419 zone->zonedata = NULL; 00420 zone->zonedata = zonedata_create(zone->allocator); 00421 zone->zonedata->initialized = 1; 00422 zone->zonedata->inbound_serial = inbound_serial; 00423 zone->zonedata->internal_serial = internal_serial; 00424 zone->zonedata->outbound_serial = outbound_serial; 00425 00426 status = zone_publish_dnskeys(zone, 1); 00427 if (status == ODS_STATUS_OK) { 00428 status = zone_prepare_nsec3(zone, 1); 00429 } else { 00430 ods_log_warning("[%s] unable to restore DNSKEY RRset for zone %s," 00431 " reloading signconf", cmdh_str, zone->name); 00432 } 00433 if (status == ODS_STATUS_OK) { 00434 status = zonedata_commit(zone->zonedata); 00435 } else { 00436 ods_log_warning("[%s] unable to restore NSEC3PARAM RRset for " 00437 " zone %s d1reloading signconf", cmdh_str, zone->name); 00438 } 00439 00440 task = (task_type*) zone->task; 00441 task->what = TASK_READ; 00442 if (status != ODS_STATUS_OK) { 00443 ods_log_warning("[%s] unable to restore DNSKEY/NSEC3PARAM RRset " 00444 " for zone %s d1reloading signconf", cmdh_str, zone->name); 00445 task->what = TASK_SIGNCONF; 00446 } 00447 /* [UNLOCK] zone */ 00448 lock_basic_unlock(&zone->zone_lock); 00449 00450 (void)snprintf(buf, ODS_SE_MAXLINE, "Internal zone information about " 00451 "%s cleared", tbd?tbd:"(null)"); 00452 ods_log_info("[%s] internal zone information about %s cleared", 00453 cmdh_str, tbd?tbd:"(null)"); 00454 } else { 00455 (void)snprintf(buf, ODS_SE_MAXLINE, "Cannot clear zone %s, zone not " 00456 "found", tbd?tbd:"(null)"); 00457 ods_log_warning("[%s] cannot clear zone %s, zone not found", 00458 cmdh_str, tbd?tbd:"(null)"); 00459 } 00460 00461 ods_writen(sockfd, buf, strlen(buf)); 00462 return; 00463 } 00464 00465 00470 static void 00471 cmdhandler_handle_cmd_queue(int sockfd, cmdhandler_type* cmdc) 00472 { 00473 char* strtime = NULL; 00474 char buf[ODS_SE_MAXLINE]; 00475 size_t i = 0; 00476 time_t now = 0; 00477 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00478 task_type* task = NULL; 00479 00480 ods_log_assert(cmdc); 00481 ods_log_assert(cmdc->engine); 00482 if (!cmdc->engine->taskq || !cmdc->engine->taskq->tasks) { 00483 (void)snprintf(buf, ODS_SE_MAXLINE, "I have no tasks scheduled.\n"); 00484 ods_writen(sockfd, buf, strlen(buf)); 00485 return; 00486 } 00487 00488 lock_basic_lock(&cmdc->engine->taskq->schedule_lock); 00489 /* [LOCK] schedule */ 00490 00491 /* time */ 00492 now = time_now(); 00493 strtime = ctime(&now); 00494 (void)snprintf(buf, ODS_SE_MAXLINE, "It is now %s", 00495 strtime?strtime:"(null)"); 00496 ods_writen(sockfd, buf, strlen(buf)); 00497 00498 /* current work */ 00499 for (i=0; i < (size_t) cmdc->engine->config->num_worker_threads; i++) { 00500 task = cmdc->engine->workers[i]->task; 00501 if (task) { 00502 (void)snprintf(buf, ODS_SE_MAXLINE, "Working with task %s on " 00503 "zone %s\n", 00504 task_what2str(cmdc->engine->workers[i]->working_with), 00505 task_who2str(task->who)); 00506 ods_writen(sockfd, buf, strlen(buf)); 00507 } 00508 } 00509 00510 /* how many tasks */ 00511 (void)snprintf(buf, ODS_SE_MAXLINE, "\nI have %i tasks scheduled.\n", 00512 (int) cmdc->engine->taskq->tasks->count); 00513 ods_writen(sockfd, buf, strlen(buf)); 00514 00515 /* list tasks */ 00516 node = ldns_rbtree_first(cmdc->engine->taskq->tasks); 00517 while (node && node != LDNS_RBTREE_NULL) { 00518 task = (task_type*) node->data; 00519 for (i=0; i < ODS_SE_MAXLINE; i++) { 00520 buf[i] = 0; 00521 } 00522 (void)task2str(task, (char*) &buf[0]); 00523 ods_writen(sockfd, buf, strlen(buf)); 00524 node = ldns_rbtree_next(node); 00525 } 00526 00527 /* [UNLOCK] schedule */ 00528 lock_basic_unlock(&cmdc->engine->taskq->schedule_lock); 00529 return; 00530 } 00531 00532 00537 static void 00538 cmdhandler_handle_cmd_flush(int sockfd, cmdhandler_type* cmdc) 00539 { 00540 char buf[ODS_SE_MAXLINE]; 00541 00542 ods_log_assert(cmdc); 00543 ods_log_assert(cmdc->engine); 00544 ods_log_assert(cmdc->engine->taskq); 00545 00546 lock_basic_lock(&cmdc->engine->taskq->schedule_lock); 00547 /* [LOCK] schedule */ 00548 schedule_flush(cmdc->engine->taskq, TASK_NONE); 00549 /* [UNLOCK] schedule */ 00550 lock_basic_unlock(&cmdc->engine->taskq->schedule_lock); 00551 00552 engine_wakeup_workers(cmdc->engine); 00553 00554 (void)snprintf(buf, ODS_SE_MAXLINE, "All tasks scheduled immediately.\n"); 00555 ods_writen(sockfd, buf, strlen(buf)); 00556 ods_log_verbose("[%s] all tasks scheduled immediately", cmdh_str); 00557 return; 00558 } 00559 00560 00565 static void 00566 cmdhandler_handle_cmd_reload(int sockfd, cmdhandler_type* cmdc) 00567 { 00568 char buf[ODS_SE_MAXLINE]; 00569 00570 ods_log_assert(cmdc); 00571 ods_log_assert(cmdc->engine); 00572 00573 cmdc->engine->need_to_reload = 1; 00574 00575 lock_basic_lock(&cmdc->engine->signal_lock); 00576 /* [LOCK] signal */ 00577 lock_basic_alarm(&cmdc->engine->signal_cond); 00578 /* [UNLOCK] signal */ 00579 lock_basic_unlock(&cmdc->engine->signal_lock); 00580 00581 (void)snprintf(buf, ODS_SE_MAXLINE, "Reloading engine.\n"); 00582 ods_writen(sockfd, buf, strlen(buf)); 00583 return; 00584 } 00585 00586 00591 static void 00592 cmdhandler_handle_cmd_stop(int sockfd, cmdhandler_type* cmdc) 00593 { 00594 char buf[ODS_SE_MAXLINE]; 00595 00596 ods_log_assert(cmdc); 00597 ods_log_assert(cmdc->engine); 00598 00599 cmdc->engine->need_to_exit = 1; 00600 00601 lock_basic_lock(&cmdc->engine->signal_lock); 00602 /* [LOCK] signal */ 00603 lock_basic_alarm(&cmdc->engine->signal_cond); 00604 /* [UNLOCK] signal */ 00605 lock_basic_unlock(&cmdc->engine->signal_lock); 00606 00607 (void)snprintf(buf, ODS_SE_MAXLINE, ODS_SE_STOP_RESPONSE); 00608 ods_writen(sockfd, buf, strlen(buf)); 00609 return; 00610 } 00611 00612 00617 static void 00618 cmdhandler_handle_cmd_start(int sockfd) 00619 { 00620 char buf[ODS_SE_MAXLINE]; 00621 00622 (void)snprintf(buf, ODS_SE_MAXLINE, "Engine already running.\n"); 00623 ods_writen(sockfd, buf, strlen(buf)); 00624 return; 00625 } 00626 00627 00632 static void 00633 cmdhandler_handle_cmd_running(int sockfd) 00634 { 00635 char buf[ODS_SE_MAXLINE]; 00636 00637 (void)snprintf(buf, ODS_SE_MAXLINE, "Engine running.\n"); 00638 ods_writen(sockfd, buf, strlen(buf)); 00639 return; 00640 } 00641 00642 00647 static void 00648 cmdhandler_handle_cmd_verbosity(int sockfd, cmdhandler_type* cmdc, int val) 00649 { 00650 char buf[ODS_SE_MAXLINE]; 00651 00652 ods_log_assert(cmdc); 00653 ods_log_assert(cmdc->engine); 00654 ods_log_assert(cmdc->engine->config); 00655 00656 ods_log_init(cmdc->engine->config->log_filename, 00657 cmdc->engine->config->use_syslog, val); 00658 00659 (void)snprintf(buf, ODS_SE_MAXLINE, "Verbosity level set to %i.\n", val); 00660 ods_writen(sockfd, buf, strlen(buf)); 00661 } 00662 00663 00668 static void 00669 cmdhandler_handle_cmd_error(int sockfd, const char* str) 00670 { 00671 char buf[ODS_SE_MAXLINE]; 00672 (void)snprintf(buf, ODS_SE_MAXLINE, "Error: %s.\n", str?str:"(null)"); 00673 ods_writen(sockfd, buf, strlen(buf)); 00674 return; 00675 } 00676 00677 00682 static void 00683 cmdhandler_handle_cmd_unknown(int sockfd, const char* str) 00684 { 00685 char buf[ODS_SE_MAXLINE]; 00686 (void)snprintf(buf, ODS_SE_MAXLINE, "Unknown command %s.\n", 00687 str?str:"(null)"); 00688 ods_writen(sockfd, buf, strlen(buf)); 00689 return; 00690 } 00691 00692 00711 static void 00712 cmdhandler_handle_cmd(cmdhandler_type* cmdc) 00713 { 00714 ssize_t n = 0; 00715 int sockfd = 0; 00716 char buf[ODS_SE_MAXLINE]; 00717 00718 ods_log_assert(cmdc); 00719 sockfd = cmdc->client_fd; 00720 00721 again: 00722 while ((n = read(sockfd, buf, ODS_SE_MAXLINE)) > 0) { 00723 buf[n-1] = '\0'; 00724 n--; 00725 if (n <= 0) { 00726 return; 00727 } 00728 ods_log_verbose("[%s] received command %s[%i]", cmdh_str, buf, n); 00729 00730 if (n == 4 && strncmp(buf, "help", n) == 0) { 00731 ods_log_debug("[%s] help command", cmdh_str); 00732 cmdhandler_handle_cmd_help(sockfd); 00733 } else if (n == 5 && strncmp(buf, "zones", n) == 0) { 00734 ods_log_debug("[%s] list zones command", cmdh_str); 00735 cmdhandler_handle_cmd_zones(sockfd, cmdc); 00736 } else if (n >= 4 && strncmp(buf, "sign", 4) == 0) { 00737 ods_log_debug("[%s] sign zone command", cmdh_str); 00738 if (buf[4] == '\0') { 00739 /* NOTE: wouldn't it be nice that we default to --all? */ 00740 cmdhandler_handle_cmd_error(sockfd, "sign command needs " 00741 "an argument (either '--all' or a zone name)"); 00742 } else if (buf[4] != ' ') { 00743 cmdhandler_handle_cmd_unknown(sockfd, buf); 00744 } else { 00745 cmdhandler_handle_cmd_sign(sockfd, cmdc, &buf[5]); 00746 } 00747 } else if (n >= 5 && strncmp(buf, "clear", 5) == 0) { 00748 ods_log_debug("[%s] clear zone command", cmdh_str); 00749 if (buf[5] == '\0') { 00750 cmdhandler_handle_cmd_error(sockfd, "clear command needs " 00751 "a zone name"); 00752 } else if (buf[5] != ' ') { 00753 cmdhandler_handle_cmd_unknown(sockfd, buf); 00754 } else { 00755 cmdhandler_handle_cmd_clear(sockfd, cmdc, &buf[6]); 00756 } 00757 } else if (n == 5 && strncmp(buf, "queue", n) == 0) { 00758 ods_log_debug("[%s] list tasks command", cmdh_str); 00759 cmdhandler_handle_cmd_queue(sockfd, cmdc); 00760 } else if (n == 5 && strncmp(buf, "flush", n) == 0) { 00761 ods_log_debug("[%s] flush tasks command", cmdh_str); 00762 cmdhandler_handle_cmd_flush(sockfd, cmdc); 00763 } else if (n >= 6 && strncmp(buf, "update", 6) == 0) { 00764 ods_log_debug("[%s] update command", cmdh_str); 00765 if (buf[6] == '\0') { 00766 cmdhandler_handle_cmd_update(sockfd, cmdc, "--all"); 00767 } else if (buf[6] != ' ') { 00768 cmdhandler_handle_cmd_unknown(sockfd, buf); 00769 } else { 00770 cmdhandler_handle_cmd_update(sockfd, cmdc, &buf[7]); 00771 } 00772 } else if (n == 4 && strncmp(buf, "stop", n) == 0) { 00773 ods_log_debug("[%s] shutdown command", cmdh_str); 00774 cmdhandler_handle_cmd_stop(sockfd, cmdc); 00775 return; 00776 } else if (n == 5 && strncmp(buf, "start", n) == 0) { 00777 ods_log_debug("[%s] start command", cmdh_str); 00778 cmdhandler_handle_cmd_start(sockfd); 00779 } else if (n == 6 && strncmp(buf, "reload", n) == 0) { 00780 ods_log_debug("[%s] reload command", cmdh_str); 00781 cmdhandler_handle_cmd_reload(sockfd, cmdc); 00782 } else if (n == 7 && strncmp(buf, "running", n) == 0) { 00783 ods_log_debug("[%s] running command", cmdh_str); 00784 cmdhandler_handle_cmd_running(sockfd); 00785 } else if (n >= 9 && strncmp(buf, "verbosity", 9) == 0) { 00786 ods_log_debug("[%s] verbosity command", cmdh_str); 00787 if (buf[9] == '\0') { 00788 cmdhandler_handle_cmd_error(sockfd, "verbosity command " 00789 "an argument (verbosity level)"); 00790 } else if (buf[9] != ' ') { 00791 cmdhandler_handle_cmd_unknown(sockfd, buf); 00792 } else { 00793 cmdhandler_handle_cmd_verbosity(sockfd, cmdc, atoi(&buf[10])); 00794 } 00795 } else { 00796 ods_log_debug("[%s] unknown command", cmdh_str); 00797 cmdhandler_handle_cmd_unknown(sockfd, buf); 00798 } 00799 00800 ods_log_debug("[%s] done handling command %s[%i]", cmdh_str, buf, n); 00801 (void)snprintf(buf, SE_CMDH_CMDLEN, "\ncmd> "); 00802 ods_writen(sockfd, buf, strlen(buf)); 00803 } 00804 00805 if (n < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) ) { 00806 goto again; 00807 } else if (n < 0 && errno == ECONNRESET) { 00808 ods_log_debug("[%s] done handling client: %s", cmdh_str, 00809 strerror(errno)); 00810 } else if (n < 0 ) { 00811 ods_log_error("[%s] read error: %s", cmdh_str, strerror(errno)); 00812 } 00813 return; 00814 } 00815 00816 00821 static void* 00822 cmdhandler_accept_client(void* arg) 00823 { 00824 cmdhandler_type* cmdc = (cmdhandler_type*) arg; 00825 00826 ods_thread_blocksigs(); 00827 ods_thread_detach(cmdc->thread_id); 00828 00829 ods_log_debug("[%s] accept client %i", cmdh_str, cmdc->client_fd); 00830 cmdhandler_handle_cmd(cmdc); 00831 if (cmdc->client_fd) { 00832 close(cmdc->client_fd); 00833 } 00834 free(cmdc); 00835 count--; 00836 return NULL; 00837 } 00838 00839 00844 cmdhandler_type* 00845 cmdhandler_create(allocator_type* allocator, const char* filename) 00846 { 00847 cmdhandler_type* cmdh = NULL; 00848 struct sockaddr_un servaddr; 00849 int listenfd = 0; 00850 int flags = 0; 00851 int ret = 0; 00852 00853 if (!allocator) { 00854 ods_log_error("[%s] unable to create: no allocator", cmdh_str); 00855 return NULL; 00856 } 00857 ods_log_assert(allocator); 00858 00859 if (!filename) { 00860 ods_log_error("[%s] unable to create: no socket filename", cmdh_str); 00861 return NULL; 00862 } 00863 ods_log_assert(filename); 00864 ods_log_debug("[%s] create socket %s", cmdh_str, filename); 00865 00866 /* new socket */ 00867 listenfd = socket(AF_UNIX, SOCK_STREAM, 0); 00868 if (listenfd <= 0) { 00869 ods_log_error("[%s] unable to create, socket() failed: %s", cmdh_str, 00870 strerror(errno)); 00871 return NULL; 00872 } 00873 /* set it to non-blocking */ 00874 flags = fcntl(listenfd, F_GETFL, 0); 00875 if (flags < 0) { 00876 ods_log_error("[%s] unable to create, fcntl(F_GETFL) failed: %s", 00877 cmdh_str, strerror(errno)); 00878 close(listenfd); 00879 return NULL; 00880 } 00881 flags |= O_NONBLOCK; 00882 if (fcntl(listenfd, F_SETFL, flags) < 0) { 00883 ods_log_error("[%s] unable to create, fcntl(F_SETFL) failed: %s", 00884 cmdh_str, strerror(errno)); 00885 close(listenfd); 00886 return NULL; 00887 } 00888 00889 /* no surprises */ 00890 if (filename) { 00891 unlink(filename); 00892 } 00893 bzero(&servaddr, sizeof(servaddr)); 00894 servaddr.sun_family = AF_UNIX; 00895 strncpy(servaddr.sun_path, filename, sizeof(servaddr.sun_path) - 1); 00896 00897 /* bind and listen... */ 00898 ret = bind(listenfd, (const struct sockaddr*) &servaddr, 00899 SUN_LEN(&servaddr)); 00900 if (ret != 0) { 00901 ods_log_error("[%s] unable to create, bind() failed: %s", cmdh_str, 00902 strerror(errno)); 00903 close(listenfd); 00904 return NULL; 00905 } 00906 ret = listen(listenfd, ODS_SE_MAX_HANDLERS); 00907 if (ret != 0) { 00908 ods_log_error("[%s] unable to create, listen() failed: %s", cmdh_str, 00909 strerror(errno)); 00910 close(listenfd); 00911 return NULL; 00912 } 00913 00914 /* all ok */ 00915 cmdh = (cmdhandler_type*) allocator_alloc(allocator, 00916 sizeof(cmdhandler_type)); 00917 if (!cmdh) { 00918 close(listenfd); 00919 return NULL; 00920 } 00921 cmdh->allocator = allocator; 00922 cmdh->listen_fd = listenfd; 00923 cmdh->listen_addr = servaddr; 00924 cmdh->need_to_exit = 0; 00925 return cmdh; 00926 } 00927 00928 00933 void 00934 cmdhandler_start(cmdhandler_type* cmdhandler) 00935 { 00936 struct sockaddr_un cliaddr; 00937 socklen_t clilen; 00938 cmdhandler_type* cmdc = NULL; 00939 engine_type* engine = NULL; 00940 fd_set rset; 00941 int connfd = 0; 00942 int ret = 0; 00943 00944 ods_log_assert(cmdhandler); 00945 ods_log_assert(cmdhandler->engine); 00946 ods_log_debug("[%s] start", cmdh_str); 00947 00948 engine = cmdhandler->engine; 00949 ods_thread_detach(cmdhandler->thread_id); 00950 FD_ZERO(&rset); 00951 while (cmdhandler->need_to_exit == 0) { 00952 clilen = sizeof(cliaddr); 00953 FD_SET(cmdhandler->listen_fd, &rset); 00954 ret = select(ODS_SE_MAX_HANDLERS+1, &rset, NULL, NULL, NULL); 00955 if (ret < 0) { 00956 if (errno != EINTR && errno != EWOULDBLOCK) { 00957 ods_log_warning("[%s] select() error: %s", cmdh_str, 00958 strerror(errno)); 00959 } 00960 continue; 00961 } 00962 if (FD_ISSET(cmdhandler->listen_fd, &rset)) { 00963 connfd = accept(cmdhandler->listen_fd, 00964 (struct sockaddr *) &cliaddr, &clilen); 00965 if (connfd < 0) { 00966 if (errno != EINTR && errno != EWOULDBLOCK) { 00967 ods_log_warning("[%s] accept error: %s", cmdh_str, 00968 strerror(errno)); 00969 } 00970 continue; 00971 } 00972 /* client accepted, create new thread */ 00973 cmdc = (cmdhandler_type*) malloc(sizeof(cmdhandler_type)); 00974 if (!cmdc) { 00975 ods_log_crit("[%s] unable to create thread for client: " 00976 "malloc failed", cmdh_str); 00977 cmdhandler->need_to_exit = 1; 00978 break; 00979 } 00980 cmdc->listen_fd = cmdhandler->listen_fd; 00981 cmdc->client_fd = connfd; 00982 cmdc->listen_addr = cmdhandler->listen_addr; 00983 cmdc->engine = cmdhandler->engine; 00984 cmdc->need_to_exit = cmdhandler->need_to_exit; 00985 ods_thread_create(&cmdc->thread_id, &cmdhandler_accept_client, 00986 (void*) cmdc); 00987 count++; 00988 ods_log_debug("[%s] %i clients in progress...", cmdh_str, count); 00989 } 00990 } 00991 00992 ods_log_debug("[%s] done", cmdh_str); 00993 engine = cmdhandler->engine; 00994 engine->cmdhandler_done = 1; 00995 return; 00996 } 00997 00998 01003 void 01004 cmdhandler_cleanup(cmdhandler_type* cmdhandler) 01005 { 01006 allocator_type* allocator; 01007 if (!cmdhandler) { 01008 return; 01009 } 01010 allocator = cmdhandler->allocator; 01011 allocator_deallocate(allocator, (void*) cmdhandler); 01012 return; 01013 } 01014