OpenDNSSEC-signer  1.3.8
/build/buildd/opendnssec-1.3.8/signer/src/daemon/engine.c
Go to the documentation of this file.
00001 /*
00002  * $Id: engine.c 6238 2012-04-03 09:53:56Z matthijs $
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 "config.h"
00035 #include "daemon/cfg.h"
00036 #include "daemon/cmdhandler.h"
00037 #include "daemon/engine.h"
00038 #include "daemon/signal.h"
00039 #include "daemon/worker.h"
00040 #include "scheduler/schedule.h"
00041 #include "scheduler/task.h"
00042 #include "shared/allocator.h"
00043 #include "shared/file.h"
00044 #include "shared/hsm.h"
00045 #include "shared/locks.h"
00046 #include "shared/log.h"
00047 #include "shared/privdrop.h"
00048 #include "shared/status.h"
00049 #include "shared/util.h"
00050 #include "signer/zone.h"
00051 #include "signer/zonelist.h"
00052 #include "tools/zone_fetcher.h"
00053 
00054 #include <errno.h>
00055 #include <libhsm.h>
00056 #include <libxml/parser.h>
00057 #include <signal.h>
00058 #include <stdio.h>
00059 #include <stdlib.h>
00060 #include <string.h>
00061 #include <strings.h>
00062 #include <sys/socket.h>
00063 #include <sys/types.h>
00064 #include <sys/un.h>
00065 #include <time.h>
00066 #include <unistd.h>
00067 
00068 static const char* engine_str = "engine";
00069 
00070 
00075 static engine_type*
00076 engine_create(void)
00077 {
00078     engine_type* engine;
00079     allocator_type* allocator = allocator_create(malloc, free);
00080     if (!allocator) {
00081         return NULL;
00082     }
00083     engine = (engine_type*) allocator_alloc(allocator, sizeof(engine_type));
00084     if (!engine) {
00085         allocator_cleanup(allocator);
00086         return NULL;
00087     }
00088     engine->allocator = allocator;
00089     engine->config = NULL;
00090     engine->workers = NULL;
00091     engine->drudgers = NULL;
00092     engine->cmdhandler = NULL;
00093     engine->cmdhandler_done = 0;
00094     engine->pid = -1;
00095     engine->zfpid = -1;
00096     engine->uid = -1;
00097     engine->gid = -1;
00098     engine->daemonize = 0;
00099     engine->need_to_exit = 0;
00100     engine->need_to_reload = 0;
00101 
00102     lock_basic_init(&engine->signal_lock);
00103     lock_basic_set(&engine->signal_cond);
00104     lock_basic_lock(&engine->signal_lock);
00105     engine->signal = SIGNAL_INIT;
00106     lock_basic_unlock(&engine->signal_lock);
00107 
00108     engine->zonelist = zonelist_create(engine->allocator);
00109     if (!engine->zonelist) {
00110         engine_cleanup(engine);
00111         return NULL;
00112     }
00113     engine->taskq = schedule_create(engine->allocator);
00114     if (!engine->taskq) {
00115         engine_cleanup(engine);
00116         return NULL;
00117     }
00118     engine->signq = fifoq_create(engine->allocator);
00119     if (!engine->signq) {
00120         engine_cleanup(engine);
00121         return NULL;
00122     }
00123     return engine;
00124 }
00125 
00126 
00131 static void*
00132 cmdhandler_thread_start(void* arg)
00133 {
00134     cmdhandler_type* cmd = (cmdhandler_type*) arg;
00135     ods_thread_blocksigs();
00136     cmdhandler_start(cmd);
00137     return NULL;
00138 }
00139 static void
00140 engine_start_cmdhandler(engine_type* engine)
00141 {
00142     ods_log_assert(engine);
00143     ods_log_debug("[%s] start command handler", engine_str);
00144     engine->cmdhandler->engine = engine;
00145     ods_thread_create(&engine->cmdhandler->thread_id,
00146         cmdhandler_thread_start, engine->cmdhandler);
00147     return;
00148 }
00153 static int
00154 self_pipe_trick(engine_type* engine)
00155 {
00156     int sockfd, ret;
00157     struct sockaddr_un servaddr;
00158     const char* servsock_filename = ODS_SE_SOCKFILE;
00159 
00160     ods_log_assert(engine);
00161     ods_log_assert(engine->cmdhandler);
00162 
00163     sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
00164     if (sockfd < 0) {
00165         ods_log_error("[%s] cannot connect to command handler: "
00166             "socket() failed: %s\n", engine_str, strerror(errno));
00167         return 1;
00168     } else {
00169         bzero(&servaddr, sizeof(servaddr));
00170         servaddr.sun_family = AF_UNIX;
00171         strncpy(servaddr.sun_path, servsock_filename,
00172             sizeof(servaddr.sun_path) - 1);
00173 
00174         ret = connect(sockfd, (const struct sockaddr*) &servaddr,
00175             sizeof(servaddr));
00176         if (ret != 0) {
00177             ods_log_error("[%s] cannot connect to command handler: "
00178                 "connect() failed: %s\n", engine_str, strerror(errno));
00179             close(sockfd);
00180             return 1;
00181         } else {
00182             /* self-pipe trick */
00183             ods_writen(sockfd, "", 1);
00184             close(sockfd);
00185         }
00186     }
00187     return 0;
00188 }
00193 static void
00194 engine_stop_cmdhandler(engine_type* engine)
00195 {
00196     ods_log_assert(engine);
00197     if (!engine->cmdhandler) {
00198         return;
00199     }
00200     ods_log_debug("[%s] stop command handler", engine_str);
00201     engine->cmdhandler->need_to_exit = 1;
00202     if (self_pipe_trick(engine) == 0) {
00203         while (!engine->cmdhandler_done) {
00204             ods_log_debug("[%s] waiting for command handler to exit...",
00205                 engine_str);
00206             sleep(1);
00207         }
00208     } else {
00209         ods_log_error("[%s] command handler self pipe trick failed, "
00210             "unclean shutdown", engine_str);
00211     }
00212     return;
00213 }
00214 
00215 
00220 static ods_status
00221 engine_privdrop(engine_type* engine)
00222 {
00223     ods_status status = ODS_STATUS_OK;
00224     uid_t uid = -1;
00225     gid_t gid = -1;
00226 
00227     ods_log_assert(engine);
00228     ods_log_assert(engine->config);
00229     ods_log_debug("[%s] drop privileges", engine_str);
00230 
00231     if (engine->config->username && engine->config->group) {
00232         ods_log_verbose("[%s] drop privileges to user %s, group %s",
00233            engine_str, engine->config->username, engine->config->group);
00234     } else if (engine->config->username) {
00235         ods_log_verbose("[%s] drop privileges to user %s", engine_str,
00236            engine->config->username);
00237     } else if (engine->config->group) {
00238         ods_log_verbose("[%s] drop privileges to group %s", engine_str,
00239            engine->config->group);
00240     }
00241     if (engine->config->chroot) {
00242         ods_log_verbose("[%s] chroot to %s", engine_str,
00243             engine->config->chroot);
00244     }
00245     status = privdrop(engine->config->username, engine->config->group,
00246         engine->config->chroot, &uid, &gid);
00247     engine->uid = uid;
00248     engine->gid = gid;
00249     privclose(engine->config->username, engine->config->group);
00250     return status;
00251 }
00252 
00253 
00258 static void
00259 engine_create_workers(engine_type* engine)
00260 {
00261     size_t i = 0;
00262     ods_log_assert(engine);
00263     ods_log_assert(engine->config);
00264     ods_log_assert(engine->allocator);
00265     engine->workers = (worker_type**) allocator_alloc(engine->allocator,
00266         ((size_t)engine->config->num_worker_threads) * sizeof(worker_type*));
00267     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00268         engine->workers[i] = worker_create(engine->allocator, i,
00269             WORKER_WORKER);
00270     }
00271     return;
00272 }
00273 static void
00274 engine_create_drudgers(engine_type* engine)
00275 {
00276     size_t i = 0;
00277     ods_log_assert(engine);
00278     ods_log_assert(engine->config);
00279     ods_log_assert(engine->allocator);
00280     engine->drudgers = (worker_type**) allocator_alloc(engine->allocator,
00281         ((size_t)engine->config->num_signer_threads) * sizeof(worker_type*));
00282     for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
00283         engine->drudgers[i] = worker_create(engine->allocator, i,
00284             WORKER_DRUDGER);
00285     }
00286     return;
00287 }
00288 static void*
00289 worker_thread_start(void* arg)
00290 {
00291     worker_type* worker = (worker_type*) arg;
00292     ods_thread_blocksigs();
00293     worker_start(worker);
00294     return NULL;
00295 }
00296 static void
00297 engine_start_workers(engine_type* engine)
00298 {
00299     size_t i = 0;
00300 
00301     ods_log_assert(engine);
00302     ods_log_assert(engine->config);
00303     ods_log_debug("[%s] start workers", engine_str);
00304     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00305         engine->workers[i]->need_to_exit = 0;
00306         engine->workers[i]->engine = (struct engine_struct*) engine;
00307         ods_thread_create(&engine->workers[i]->thread_id, worker_thread_start,
00308             engine->workers[i]);
00309     }
00310     return;
00311 }
00312 void
00313 engine_start_drudgers(engine_type* engine)
00314 {
00315     size_t i = 0;
00316 
00317     ods_log_assert(engine);
00318     ods_log_assert(engine->config);
00319     ods_log_debug("[%s] start drudgers", engine_str);
00320     for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
00321         engine->drudgers[i]->need_to_exit = 0;
00322         engine->drudgers[i]->engine = (struct engine_struct*) engine;
00323         ods_thread_create(&engine->drudgers[i]->thread_id, worker_thread_start,
00324             engine->drudgers[i]);
00325     }
00326     return;
00327 }
00328 static void
00329 engine_stop_workers(engine_type* engine)
00330 {
00331     size_t i = 0;
00332 
00333     ods_log_assert(engine);
00334     ods_log_assert(engine->config);
00335     ods_log_debug("[%s] stop workers", engine_str);
00336     /* tell them to exit and wake up sleepyheads */
00337     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00338         engine->workers[i]->need_to_exit = 1;
00339         worker_wakeup(engine->workers[i]);
00340     }
00341     worker_notify_all(&engine->signq->q_lock, &engine->signq->q_nonfull);
00342     /* head count */
00343     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00344         ods_log_debug("[%s] join worker %i", engine_str, i+1);
00345         ods_thread_join(engine->workers[i]->thread_id);
00346         engine->workers[i]->engine = NULL;
00347     }
00348     return;
00349 }
00350 void
00351 engine_stop_drudgers(engine_type* engine)
00352 {
00353     size_t i = 0;
00354 
00355     ods_log_assert(engine);
00356     ods_log_assert(engine->config);
00357     ods_log_debug("[%s] stop drudgers", engine_str);
00358     /* tell them to exit and wake up sleepyheads */
00359     for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
00360         engine->drudgers[i]->need_to_exit = 1;
00361     }
00362     worker_notify_all(&engine->signq->q_lock, &engine->signq->q_threshold);
00363 
00364     /* head count */
00365     for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
00366         ods_log_debug("[%s] join drudger %i", engine_str, i+1);
00367         ods_thread_join(engine->drudgers[i]->thread_id);
00368         engine->drudgers[i]->engine = NULL;
00369     }
00370     return;
00371 }
00372 
00373 
00378 void
00379 engine_wakeup_workers(engine_type* engine)
00380 {
00381     size_t i = 0;
00382 
00383     ods_log_assert(engine);
00384     ods_log_assert(engine->config);
00385     ods_log_debug("[%s] wake up workers", engine_str);
00386     /* wake up sleepyheads */
00387     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00388         worker_wakeup(engine->workers[i]);
00389     }
00390     return;
00391 }
00392 
00393 
00398 static int
00399 start_zonefetcher(engine_type* engine)
00400 {
00401     pid_t zfpid = 0;
00402     int result = 0;
00403     char* zf_filename = NULL;
00404     char* zl_filename = NULL;
00405     char* log_filename = NULL;
00406     char* grp = NULL;
00407     char* usr = NULL;
00408     char* chrt = NULL;
00409     int use_syslog = 0;
00410     int verbosity = 0;
00411 
00412     ods_log_assert(engine);
00413     ods_log_assert(engine->config);
00414 
00415     if (!engine->config->zonefetch_filename) {
00416         /* zone fetcher disabled */
00417         return 0;
00418     }
00419 
00420     switch ((zfpid = fork())) {
00421         case -1: /* error */
00422             ods_log_error("failed to fork zone fetcher: %s",
00423                 strerror(errno));
00424             return 1;
00425         case 0: /* child */
00426             break;
00427         default: /* parent */
00428             engine->zfpid = zfpid;
00429             return 0;
00430     }
00431 
00432     if (setsid() == -1) {
00433         ods_log_error("failed to setsid zone fetcher: %s",
00434             strerror(errno));
00435         return 1;
00436     }
00437 
00438     ods_log_verbose("zone fetcher running as pid %lu",
00439         (unsigned long) getpid());
00440 
00441     if (engine->config->zonefetch_filename) {
00442         zf_filename = strdup(engine->config->zonefetch_filename);
00443     }
00444     if (engine->config->zonelist_filename) {
00445         zl_filename = strdup(engine->config->zonelist_filename);
00446     }
00447     if (engine->config->group) {
00448         grp = strdup(engine->config->group);
00449     }
00450     if (engine->config->username) {
00451         usr = strdup(engine->config->username);
00452     }
00453     if (engine->config->chroot) {
00454         chrt = strdup(engine->config->chroot);
00455     }
00456     if (engine->config->log_filename) {
00457         log_filename = strdup(engine->config->log_filename);
00458     }
00459     use_syslog = engine->config->use_syslog;
00460     verbosity = engine->config->verbosity;
00461 
00462     result = tools_zone_fetcher(zf_filename, zl_filename, grp, usr,
00463         chrt, log_filename, use_syslog, verbosity);
00464 
00465     ods_log_verbose("zone fetcher done", result);
00466     if (zf_filename)  { free((void*)zf_filename); }
00467     if (zl_filename)  { free((void*)zl_filename); }
00468     if (grp)          { free((void*)grp); }
00469     if (usr)          { free((void*)usr); }
00470     if (chrt)         { free((void*)chrt); }
00471     if (log_filename) { free((void*)log_filename); }
00472 
00473     engine_cleanup(engine);
00474     engine = NULL;
00475     ods_log_close();
00476     xmlCleanupParser();
00477     xmlCleanupGlobals();
00478     xmlCleanupThreads();
00479     exit(result);
00480 
00481     return 0;
00482 }
00483 
00484 
00489 static void
00490 reload_zonefetcher(engine_type* engine)
00491 {
00492     int result = 0;
00493 
00494     ods_log_assert(engine);
00495     ods_log_assert(engine->config);
00496 
00497     if (engine->config->zonefetch_filename) {
00498         if (engine->zfpid > 0) {
00499             result = kill(engine->zfpid, SIGHUP);
00500             if (result == -1) {
00501                 ods_log_error("cannot reload zone fetcher: %s",
00502                     strerror(errno));
00503             } else {
00504                 ods_log_info("zone fetcher reloaded (pid=%i)", engine->zfpid);
00505             }
00506         } else {
00507             ods_log_error("cannot reload zone fetcher: process id unknown");
00508         }
00509     }
00510     return;
00511 }
00512 
00513 
00518 static void
00519 stop_zonefetcher(engine_type* engine)
00520 {
00521     int result = 0;
00522 
00523     ods_log_assert(engine);
00524     ods_log_assert(engine->config);
00525 
00526     if (engine->config->zonefetch_filename) {
00527         if (engine->zfpid > 0) {
00528             result = kill(engine->zfpid, SIGTERM);
00529             if (result == -1) {
00530                 ods_log_error("cannot stop zone fetcher: %s", strerror(errno));
00531             } else {
00532                 ods_log_info("zone fetcher stopped (pid=%i)", engine->zfpid);
00533             }
00534             engine->zfpid = -1;
00535         } else {
00536             ods_log_error("cannot stop zone fetcher: process id unknown");
00537         }
00538     }
00539     return;
00540 }
00541 
00542 
00547 static ods_status
00548 engine_init_adapters(engine_type* engine)
00549 {
00550     size_t i = 0;
00551     ods_status status = ODS_STATUS_OK;
00552 
00553     ods_log_assert(engine);
00554     ods_log_assert(engine->config);
00555     ods_log_debug("[%s] initialize adapters", engine_str);
00556     for (i=0; i < (size_t) engine->config->num_adapters; i++) {
00557         status = adapter_init(engine->config->adapters[i]);
00558         if (status != ODS_STATUS_OK) {
00559             return status;
00560         }
00561     }
00562     return status;
00563 }
00564 
00565 
00570 static ods_status
00571 engine_setup(engine_type* engine)
00572 {
00573     struct sigaction action;
00574     int result = 0;
00575     ods_status status = ODS_STATUS_OK;
00576 
00577     ods_log_debug("[%s] signer setup", engine_str);
00578     if (!engine || !engine->config) {
00579         return ODS_STATUS_ASSERT_ERR;
00580     }
00581 
00582     /* create command handler (before chowning socket file) */
00583     engine->cmdhandler = cmdhandler_create(engine->allocator,
00584         engine->config->clisock_filename);
00585     if (!engine->cmdhandler) {
00586         ods_log_error("[%s] create command handler to %s failed",
00587             engine_str, engine->config->clisock_filename);
00588         return ODS_STATUS_CMDHANDLER_ERR;
00589     }
00590 
00591     /* fork of fetcher */
00592     if (start_zonefetcher(engine) != 0) {
00593         ods_log_error("[%s] cannot start zonefetcher", engine_str);
00594         return ODS_STATUS_ERR;
00595     }
00596 
00597     /* initialize adapters */
00598     status = engine_init_adapters(engine);
00599     if (status != ODS_STATUS_OK) {
00600         ods_log_error("[%s] initializing adapters failed", engine_str);
00601         return status;
00602     }
00603 
00604     /* privdrop */
00605     engine->uid = privuid(engine->config->username);
00606     engine->gid = privgid(engine->config->group);
00607     /* TODO: does piddir exists? */
00608     /* remove the chown stuff: piddir? */
00609     ods_chown(engine->config->pid_filename, engine->uid, engine->gid, 1);
00610     ods_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0);
00611     ods_chown(engine->config->working_dir, engine->uid, engine->gid, 0);
00612     if (engine->config->log_filename && !engine->config->use_syslog) {
00613         ods_chown(engine->config->log_filename, engine->uid, engine->gid, 0);
00614     }
00615     if (engine->config->working_dir &&
00616         chdir(engine->config->working_dir) != 0) {
00617         ods_log_error("[%s] chdir to %s failed: %s", engine_str,
00618             engine->config->working_dir, strerror(errno));
00619         return ODS_STATUS_CHDIR_ERR;
00620     }
00621     if (engine_privdrop(engine) != ODS_STATUS_OK) {
00622         ods_log_error("[%s] unable to drop privileges", engine_str);
00623         return ODS_STATUS_PRIVDROP_ERR;
00624     }
00625 
00626     /* daemonize */
00627     if (engine->daemonize) {
00628         switch ((engine->pid = fork())) {
00629             case -1: /* error */
00630                 ods_log_error("[%s] unable to fork daemon: %s",
00631                     engine_str, strerror(errno));
00632                 return ODS_STATUS_FORK_ERR;
00633             case 0: /* child */
00634                 break;
00635             default: /* parent */
00636                 engine_cleanup(engine);
00637                 engine = NULL;
00638                 xmlCleanupParser();
00639                 xmlCleanupGlobals();
00640                 xmlCleanupThreads();
00641                 exit(0);
00642         }
00643         if (setsid() == -1) {
00644             ods_log_error("[%s] unable to setsid daemon (%s)",
00645                 engine_str, strerror(errno));
00646             return ODS_STATUS_SETSID_ERR;
00647         }
00648     }
00649     engine->pid = getpid();
00650     ods_log_verbose("[%s] running as pid %lu", engine_str,
00651         (unsigned long) engine->pid);
00652 
00653     /* catch signals */
00654     signal_set_engine(engine);
00655     action.sa_handler = signal_handler;
00656     sigfillset(&action.sa_mask);
00657     action.sa_flags = 0;
00658     sigaction(SIGHUP, &action, NULL);
00659     sigaction(SIGTERM, &action, NULL);
00660 
00661     /* set up hsm */ /* LEAK */
00662     result = lhsm_open(engine->config->cfg_filename);
00663     if (result != HSM_OK) {
00664         return ODS_STATUS_HSM_ERR;
00665     }
00666 
00667     /* create workers */
00668     engine_create_workers(engine);
00669     engine_create_drudgers(engine);
00670 
00671     /* start command handler */
00672     engine_start_cmdhandler(engine);
00673 
00674     /* write pidfile */
00675     if (util_write_pidfile(engine->config->pid_filename, engine->pid) == -1) {
00676         hsm_close();
00677         ods_log_error("[%s] unable to write pid file", engine_str);
00678         return ODS_STATUS_WRITE_PIDFILE_ERR;
00679     }
00680 
00681     return ODS_STATUS_OK;
00682 }
00683 
00684 
00689 static int
00690 engine_all_zones_processed(engine_type* engine)
00691 {
00692     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00693     zone_type* zone = NULL;
00694 
00695     ods_log_assert(engine);
00696     ods_log_assert(engine->zonelist);
00697     ods_log_assert(engine->zonelist->zones);
00698 
00699     node = ldns_rbtree_first(engine->zonelist->zones);
00700     while (node && node != LDNS_RBTREE_NULL) {
00701         zone = (zone_type*) node->key;
00702         if (!zone->processed) {
00703                 return 0;
00704         }
00705         node = ldns_rbtree_next(node);
00706     }
00707     return 1;
00708 }
00709 
00710 
00715 static void
00716 engine_run(engine_type* engine, int single_run)
00717 {
00718     if (!engine) {
00719         return;
00720     }
00721     ods_log_assert(engine);
00722 
00723     engine_start_workers(engine);
00724     engine_start_drudgers(engine);
00725 
00726     lock_basic_lock(&engine->signal_lock);
00727     /* [LOCK] signal */
00728     engine->signal = SIGNAL_RUN;
00729     /* [UNLOCK] signal */
00730     lock_basic_unlock(&engine->signal_lock);
00731 
00732     while (!engine->need_to_exit && !engine->need_to_reload) {
00733         lock_basic_lock(&engine->signal_lock);
00734         /* [LOCK] signal */
00735         engine->signal = signal_capture(engine->signal);
00736         switch (engine->signal) {
00737             case SIGNAL_RUN:
00738                 ods_log_assert(1);
00739                 break;
00740             case SIGNAL_RELOAD:
00741                 engine->need_to_reload = 1;
00742                 break;
00743             case SIGNAL_SHUTDOWN:
00744                 engine->need_to_exit = 1;
00745                 break;
00746             default:
00747                 ods_log_warning("[%s] invalid signal captured: %d, "
00748                     "keep running", engine_str, signal);
00749                 engine->signal = SIGNAL_RUN;
00750                 break;
00751         }
00752         /* [UNLOCK] signal */
00753         lock_basic_unlock(&engine->signal_lock);
00754 
00755         if (single_run) {
00756            engine->need_to_exit = engine_all_zones_processed(engine);
00757         }
00758 
00759         lock_basic_lock(&engine->signal_lock);
00760         /* [LOCK] signal */
00761         if (engine->signal == SIGNAL_RUN && !single_run) {
00762            ods_log_debug("[%s] taking a break", engine_str);
00763            lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600);
00764         }
00765         /* [UNLOCK] signal */
00766         lock_basic_unlock(&engine->signal_lock);
00767     }
00768     ods_log_debug("[%s] signer halted", engine_str);
00769     engine_stop_drudgers(engine);
00770     engine_stop_workers(engine);
00771     (void)lhsm_reopen(engine->config->cfg_filename);
00772     return;
00773 }
00774 
00775 
00780 static void
00781 set_notify_ns(zone_type* zone, const char* cmd)
00782 {
00783     const char* str = NULL;
00784     const char* str2 = NULL;
00785 
00786     ods_log_assert(cmd);
00787     ods_log_assert(zone);
00788     ods_log_assert(zone->name);
00789     ods_log_assert(zone->adoutbound);
00790 
00791     if (zone->adoutbound->type == ADAPTER_FILE) {
00792         str = ods_replace(cmd, "%zonefile", zone->adoutbound->configstr);
00793     } else {
00794         str = cmd;
00795     }
00796 
00797     str2 = ods_replace(str, "%zone", zone->name);
00798     free((void*)str);
00799     zone->notify_ns = (const char*) str2;
00800     ods_log_debug("[%s] set notify ns: %s", engine_str, zone->notify_ns);
00801     return;
00802 }
00803 
00804 
00809 void
00810 engine_update_zones(engine_type* engine)
00811 {
00812     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00813     zone_type* zone = NULL;
00814     zone_type* delzone = NULL;
00815     task_type* task = NULL;
00816     ods_status status = ODS_STATUS_OK;
00817     int wake_up = 0;
00818     time_t now;
00819 
00820     if (!engine || !engine->zonelist || !engine->zonelist->zones) {
00821         ods_log_error("[%s] cannot update zones: no engine or zonelist",
00822             engine_str);
00823         return;
00824     }
00825     ods_log_assert(engine);
00826     ods_log_assert(engine->zonelist);
00827     ods_log_assert(engine->zonelist->zones);
00828 
00829     now = time_now();
00830     reload_zonefetcher(engine);
00831 
00832     lock_basic_lock(&engine->zonelist->zl_lock);
00833     /* [LOCK] zonelist */
00834     node = ldns_rbtree_first(engine->zonelist->zones);
00835     while (node && node != LDNS_RBTREE_NULL) {
00836         zone = (zone_type*) node->data;
00837         task = NULL; /* reset task */
00838 
00839         if (zone->tobe_removed) {
00840             node = ldns_rbtree_next(node);
00841 
00842             lock_basic_lock(&zone->zone_lock);
00843             /* [LOCK] zone */
00844             delzone = zonelist_del_zone(engine->zonelist, zone);
00845             if (delzone) {
00846                 lock_basic_lock(&engine->taskq->schedule_lock);
00847                 /* [LOCK] schedule */
00848                 task = unschedule_task(engine->taskq,
00849                     (task_type*) zone->task);
00850                 /* [UNLOCK] schedule */
00851                 lock_basic_unlock(&engine->taskq->schedule_lock);
00852             }
00853             task_cleanup(task);
00854             task = NULL;
00855             /* [UNLOCK] zone */
00856             lock_basic_unlock(&zone->zone_lock);
00857 
00858             zone_cleanup(zone);
00859             zone = NULL;
00860             continue;
00861         } else if (zone->just_added) {
00862 
00863             lock_basic_lock(&zone->zone_lock);
00864             ods_log_assert(!zone->task);
00865             zone->just_added = 0;
00866             /* notify nameserver */
00867             if (engine->config->notify_command && !zone->notify_ns) {
00868                 set_notify_ns(zone, engine->config->notify_command);
00869             }
00870             /* schedule task */
00871             task = task_create(TASK_SIGNCONF, now, zone->name, zone);
00872             if (!task) {
00873                 ods_log_crit("[%s] failed to create task for zone %s",
00874                     engine_str, zone->name);
00875             } else {
00876                 zone->task = task;
00877                 lock_basic_lock(&engine->taskq->schedule_lock);
00878                 /* [LOCK] schedule */
00879                 status = schedule_task(engine->taskq, task, 0);
00880                 /* [UNLOCK] schedule */
00881                 lock_basic_unlock(&engine->taskq->schedule_lock);
00882                 wake_up = 1;
00883             }
00884             /* zone fetcher enabled? */
00885             zone->fetch = (engine->config->zonefetch_filename != NULL);
00886             lock_basic_unlock(&zone->zone_lock);
00887         } else { /* always try to update signconf */
00888             lock_basic_lock(&zone->zone_lock);
00889             ods_log_assert(zone->task);
00890             zone->just_updated = 0;
00891             /* reschedule task */
00892             lock_basic_lock(&engine->taskq->schedule_lock);
00893             /* [LOCK] schedule */
00894             task = unschedule_task(engine->taskq, (task_type*) zone->task);
00895             if (task != NULL) {
00896                 ods_log_debug("[%s] reschedule task for zone %s", engine_str,
00897                     zone->name);
00898                 if (task->what != TASK_SIGNCONF) {
00899                     task->halted = task->what;
00900                     task->interrupt = TASK_SIGNCONF;
00901                 }
00902                 task->what = TASK_SIGNCONF;
00903                 task->when = now;
00904                 status = schedule_task(engine->taskq, task, 0);
00905                 zone->task = task;
00906             } else {
00907                 /* task not queued, being worked on? */
00908                 ods_log_debug("[%s] worker busy with zone %s, will update "
00909                     "signconf as soon as possible", engine_str, zone->name);
00910                 task = (task_type*) zone->task;
00911                 task->interrupt = TASK_SIGNCONF;
00912                 /* task->halted set by worker */
00913             }
00914             /* [UNLOCK] schedule */
00915             lock_basic_unlock(&engine->taskq->schedule_lock);
00916             lock_basic_unlock(&zone->zone_lock);
00917 
00918             wake_up = 1;
00919         }
00920 
00921         if (status != ODS_STATUS_OK) {
00922             ods_log_crit("[%s] failed to schedule task for zone %s: %s",
00923                 engine_str, zone->name, ods_status2str(status));
00924             task_cleanup(task);
00925             zone->task = NULL;
00926         }
00927         node = ldns_rbtree_next(node);
00928     }
00929     /* [UNLOCK] zonelist */
00930     lock_basic_unlock(&engine->zonelist->zl_lock);
00931     if (wake_up) {
00932         engine_wakeup_workers(engine);
00933     }
00934     return;
00935 }
00936 
00937 
00942 static ods_status
00943 engine_recover(engine_type* engine)
00944 {
00945     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00946     zone_type* zone = NULL;
00947     ods_status status = ODS_STATUS_OK;
00948     ods_status result = ODS_STATUS_UNCHANGED;
00949 
00950     if (!engine || !engine->zonelist || !engine->zonelist->zones) {
00951         ods_log_error("[%s] cannot update zones: no engine or zonelist",
00952             engine_str);
00953         return ODS_STATUS_OK; /* will trigger update zones */
00954     }
00955     ods_log_assert(engine);
00956     ods_log_assert(engine->zonelist);
00957     ods_log_assert(engine->zonelist->zones);
00958 
00959     lock_basic_lock(&engine->zonelist->zl_lock);
00960     /* [LOCK] zonelist */
00961     node = ldns_rbtree_first(engine->zonelist->zones);
00962     while (node && node != LDNS_RBTREE_NULL) {
00963         zone = (zone_type*) node->data;
00964 
00965         ods_log_assert(zone->just_added);
00966         status = zone_recover(zone);
00967         if (status == ODS_STATUS_OK) {
00968             ods_log_assert(zone->task);
00969             ods_log_assert(zone->zonedata);
00970             ods_log_assert(zone->signconf);
00971             /* notify nameserver */
00972             if (engine->config->notify_command && !zone->notify_ns) {
00973                 set_notify_ns(zone, engine->config->notify_command);
00974             }
00975             /* zone fetcher enabled? */
00976             zone->fetch = (engine->config->zonefetch_filename != NULL);
00977             /* schedule task */
00978             lock_basic_lock(&engine->taskq->schedule_lock);
00979             /* [LOCK] schedule */
00980             status = schedule_task(engine->taskq, (task_type*) zone->task, 0);
00981             /* [UNLOCK] schedule */
00982             lock_basic_unlock(&engine->taskq->schedule_lock);
00983 
00984             if (status != ODS_STATUS_OK) {
00985                 ods_log_crit("[%s] unable to schedule task for zone %s: %s",
00986                     engine_str, zone->name, ods_status2str(status));
00987                 task_cleanup((task_type*) zone->task);
00988                 zone->task = NULL;
00989                 result = ODS_STATUS_OK; /* will trigger update zones */
00990             } else {
00991                 ods_log_verbose("[%s] recovered zone %s", engine_str,
00992                     zone->name);
00993                 /* recovery done */
00994                 zone->just_added = 0;
00995             }
00996         } else {
00997             if (status != ODS_STATUS_UNCHANGED) {
00998                 ods_log_warning("[%s] unable to recover zone %s from backup,"
00999                 " performing full sign", engine_str, zone->name);
01000             }
01001             result = ODS_STATUS_OK; /* will trigger update zones */
01002         }
01003         node = ldns_rbtree_next(node);
01004     }
01005     /* [UNLOCK] zonelist */
01006     lock_basic_unlock(&engine->zonelist->zl_lock);
01007     return result;
01008 }
01009 
01010 
01015 void
01016 engine_start(const char* cfgfile, int cmdline_verbosity, int daemonize,
01017     int info, int single_run)
01018 {
01019     engine_type* engine = NULL;
01020     int use_syslog = 0;
01021     ods_status zl_changed = ODS_STATUS_UNCHANGED;
01022     ods_status status = ODS_STATUS_OK;
01023     int close_hsm = 0;
01024 
01025     ods_log_assert(cfgfile);
01026     ods_log_init(NULL, use_syslog, cmdline_verbosity);
01027     ods_log_verbose("[%s] starting signer", engine_str);
01028 
01029     /* initialize */
01030     xmlInitGlobals();
01031     xmlInitParser();
01032     xmlInitThreads();
01033     engine = engine_create();
01034     if (!engine) {
01035         ods_fatal_exit("[%s] create failed", engine_str);
01036         return;
01037     }
01038     engine->daemonize = daemonize;
01039 
01040     /* config */
01041     engine->config = engine_config(engine->allocator, cfgfile,
01042         cmdline_verbosity);
01043     status = engine_config_check(engine->config);
01044     if (status != ODS_STATUS_OK) {
01045         ods_log_error("[%s] cfgfile %s has errors", engine_str, cfgfile);
01046         goto earlyexit;
01047     }
01048     if (info) {
01049         engine_config_print(stdout, engine->config); /* for debugging */
01050         goto earlyexit;
01051     }
01052 
01053     /* open log */
01054     ods_log_init(engine->config->log_filename, engine->config->use_syslog,
01055        engine->config->verbosity);
01056 
01057     /* setup */
01058     tzset(); /* for portability */
01059     status = engine_setup(engine);
01060     if (status != ODS_STATUS_OK) {
01061         ods_log_error("[%s] setup failed: %s", engine_str,
01062             ods_status2str(status));
01063         engine->need_to_exit = 1;
01064         if (status != ODS_STATUS_WRITE_PIDFILE_ERR) {
01065             /* command handler had not yet been started */
01066             engine->cmdhandler_done = 1;
01067         }
01068     } else {
01069         /* setup ok, mark hsm open */
01070         close_hsm = 1;
01071     }
01072 
01073     /* run */
01074     while (engine->need_to_exit == 0) {
01075         /* update zone list */
01076         lock_basic_lock(&engine->zonelist->zl_lock);
01077         /* [LOCK] zonelist */
01078         zl_changed = zonelist_update(engine->zonelist,
01079             engine->config->zonelist_filename);
01080         engine->zonelist->just_removed = 0;
01081         engine->zonelist->just_added = 0;
01082         engine->zonelist->just_updated = 0;
01083         /* [UNLOCK] zonelist */
01084         lock_basic_unlock(&engine->zonelist->zl_lock);
01085 
01086         if (engine->need_to_reload) {
01087             ods_log_info("[%s] signer reloading", engine_str);
01088             engine->need_to_reload = 0;
01089         } else {
01090             ods_log_info("[%s] signer started", engine_str);
01091             zl_changed = engine_recover(engine);
01092         }
01093 
01094         /* update zones */
01095         if (zl_changed == ODS_STATUS_OK) {
01096             ods_log_debug("[%s] commit zone list changes", engine_str);
01097             engine_update_zones(engine);
01098             ods_log_debug("[%s] signer configurations updated", engine_str);
01099             zl_changed = ODS_STATUS_UNCHANGED;
01100         }
01101 
01102         engine_run(engine, single_run);
01103     }
01104 
01105     /* shutdown */
01106     ods_log_info("[%s] signer shutdown", engine_str);
01107     stop_zonefetcher(engine);
01108     if (close_hsm) {
01109         hsm_close();
01110     }
01111     if (engine->cmdhandler != NULL) {
01112         engine_stop_cmdhandler(engine);
01113     }
01114 
01115 earlyexit:
01116     if (engine && engine->config) {
01117         if (engine->config->pid_filename) {
01118             (void)unlink(engine->config->pid_filename);
01119         }
01120         if (engine->config->clisock_filename) {
01121             (void)unlink(engine->config->clisock_filename);
01122         }
01123     }
01124     engine_cleanup(engine);
01125     engine = NULL;
01126     ods_log_close();
01127     xmlCleanupParser();
01128     xmlCleanupGlobals();
01129     xmlCleanupThreads();
01130     return;
01131 }
01132 
01133 
01138 void
01139 engine_cleanup(engine_type* engine)
01140 {
01141     size_t i = 0;
01142     allocator_type* allocator;
01143     cond_basic_type signal_cond;
01144     lock_basic_type signal_lock;
01145 
01146     if (!engine) {
01147         return;
01148     }
01149     allocator = engine->allocator;
01150     signal_cond = engine->signal_cond;
01151     signal_lock = engine->signal_lock;
01152 
01153     if (engine->workers && engine->config) {
01154         for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
01155             worker_cleanup(engine->workers[i]);
01156         }
01157         allocator_deallocate(allocator, (void*) engine->workers);
01158     }
01159     if (engine->drudgers && engine->config) {
01160        for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
01161            worker_cleanup(engine->drudgers[i]);
01162        }
01163         allocator_deallocate(allocator, (void*) engine->drudgers);
01164     }
01165     zonelist_cleanup(engine->zonelist);
01166     schedule_cleanup(engine->taskq);
01167     fifoq_cleanup(engine->signq);
01168     cmdhandler_cleanup(engine->cmdhandler);
01169     engine_config_cleanup(engine->config);
01170     allocator_deallocate(allocator, (void*) engine);
01171 
01172     lock_basic_destroy(&signal_lock);
01173     lock_basic_off(&signal_cond);
01174     allocator_cleanup(allocator);
01175     return;
01176 }