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