OpenDNSSEC-signer 1.3.0rc3
/build/buildd2-opendnssec_1.3.0~rc3-1-mips-lpJjcT/opendnssec-1.3.0~rc3/signer/src/daemon/engine.c
Go to the documentation of this file.
00001 /*
00002  * $Id: engine.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 "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/locks.h"
00045 #include "shared/log.h"
00046 #include "shared/privdrop.h"
00047 #include "shared/status.h"
00048 #include "shared/util.h"
00049 #include "signer/zone.h"
00050 #include "signer/zonelist.h"
00051 #include "tools/zone_fetcher.h"
00052 
00053 #include <errno.h>
00054 #include <libhsm.h>
00055 #include <libxml/parser.h>
00056 #include <signal.h>
00057 #include <stdio.h>
00058 #include <stdlib.h>
00059 #include <string.h>
00060 #include <strings.h>
00061 #include <sys/socket.h>
00062 #include <sys/types.h>
00063 #include <sys/un.h>
00064 #include <time.h>
00065 #include <unistd.h>
00066 
00067 static const char* engine_str = "engine";
00068 
00069 
00074 static engine_type*
00075 engine_create(void)
00076 {
00077     engine_type* engine;
00078     allocator_type* allocator = allocator_create(malloc, free);
00079     if (!allocator) {
00080         return NULL;
00081     }
00082     engine = (engine_type*) allocator_alloc(allocator, sizeof(engine_type));
00083     if (!engine) {
00084         allocator_cleanup(allocator);
00085         return NULL;
00086     }
00087     engine->allocator = allocator;
00088     engine->config = NULL;
00089     engine->workers = NULL;
00090     engine->drudgers = NULL;
00091     engine->cmdhandler = NULL;
00092     engine->cmdhandler_done = 0;
00093     engine->pid = -1;
00094     engine->zfpid = -1;
00095     engine->uid = -1;
00096     engine->gid = -1;
00097     engine->daemonize = 0;
00098     engine->need_to_exit = 0;
00099     engine->need_to_reload = 0;
00100 
00101     lock_basic_init(&engine->signal_lock);
00102     lock_basic_set(&engine->signal_cond);
00103     lock_basic_lock(&engine->signal_lock);
00104     engine->signal = SIGNAL_INIT;
00105     lock_basic_unlock(&engine->signal_lock);
00106 
00107     engine->zonelist = zonelist_create(engine->allocator);
00108     if (!engine->zonelist) {
00109         engine_cleanup(engine);
00110         return NULL;
00111     }
00112     engine->taskq = schedule_create(engine->allocator);
00113     if (!engine->taskq) {
00114         engine_cleanup(engine);
00115         return NULL;
00116     }
00117     engine->signq = fifoq_create(engine->allocator);
00118     if (!engine->signq) {
00119         engine_cleanup(engine);
00120         return NULL;
00121     }
00122     return engine;
00123 }
00124 
00125 
00130 static void*
00131 cmdhandler_thread_start(void* arg)
00132 {
00133     cmdhandler_type* cmd = (cmdhandler_type*) arg;
00134     ods_thread_blocksigs();
00135     cmdhandler_start(cmd);
00136     return NULL;
00137 }
00138 static void
00139 engine_start_cmdhandler(engine_type* engine)
00140 {
00141     ods_log_assert(engine);
00142     ods_log_debug("[%s] start command handler", engine_str);
00143     engine->cmdhandler->engine = engine;
00144     ods_thread_create(&engine->cmdhandler->thread_id,
00145         cmdhandler_thread_start, engine->cmdhandler);
00146     return;
00147 }
00152 static int
00153 self_pipe_trick(engine_type* engine)
00154 {
00155     int sockfd, ret;
00156     struct sockaddr_un servaddr;
00157     const char* servsock_filename = ODS_SE_SOCKFILE;
00158 
00159     ods_log_assert(engine);
00160     ods_log_assert(engine->cmdhandler);
00161 
00162     sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
00163     if (sockfd <= 0) {
00164         ods_log_error("[%s] cannot connect to command handler: "
00165             "socket() failed: %s\n", engine_str, strerror(errno));
00166         return 1;
00167     } else {
00168         bzero(&servaddr, sizeof(servaddr));
00169         servaddr.sun_family = AF_UNIX;
00170         strncpy(servaddr.sun_path, servsock_filename,
00171             sizeof(servaddr.sun_path) - 1);
00172 
00173         ret = connect(sockfd, (const struct sockaddr*) &servaddr,
00174             sizeof(servaddr));
00175         if (ret != 0) {
00176             ods_log_error("[%s] cannot connect to command handler: "
00177                 "connect() failed: %s\n", engine_str, strerror(errno));
00178             close(sockfd);
00179             return 1;
00180         } else {
00181             /* self-pipe trick */
00182             ods_writen(sockfd, "", 1);
00183             close(sockfd);
00184         }
00185     }
00186     return 0;
00187 }
00192 static void
00193 engine_stop_cmdhandler(engine_type* engine)
00194 {
00195     ods_log_assert(engine);
00196     if (!engine->cmdhandler) {
00197         return;
00198     }
00199     ods_log_debug("[%s] stop command handler", engine_str);
00200     engine->cmdhandler->need_to_exit = 1;
00201     if (self_pipe_trick(engine) == 0) {
00202         while (!engine->cmdhandler_done) {
00203             ods_log_debug("[%s] waiting for command handler to exit...",
00204                 engine_str);
00205             sleep(1);
00206         }
00207     } else {
00208         ods_log_error("[%s] command handler self pipe trick failed, "
00209             "unclean shutdown", engine_str);
00210     }
00211     return;
00212 }
00213 
00214 
00219 static ods_status
00220 engine_privdrop(engine_type* engine)
00221 {
00222     ods_status status = ODS_STATUS_OK;
00223     uid_t uid = -1;
00224     gid_t gid = -1;
00225 
00226     ods_log_assert(engine);
00227     ods_log_assert(engine->config);
00228     ods_log_debug("[%s] drop privileges", engine_str);
00229 
00230     if (engine->config->username && engine->config->group) {
00231         ods_log_verbose("[%s] drop privileges to user %s, group %s",
00232            engine_str, engine->config->username, engine->config->group);
00233     } else if (engine->config->username) {
00234         ods_log_verbose("[%s] drop privileges to user %s", engine_str,
00235            engine->config->username);
00236     } else if (engine->config->group) {
00237         ods_log_verbose("[%s] drop privileges to group %s", engine_str,
00238            engine->config->group);
00239     }
00240     if (engine->config->chroot) {
00241         ods_log_verbose("[%s] chroot to %s", engine_str,
00242             engine->config->chroot);
00243     }
00244     status = privdrop(engine->config->username, engine->config->group,
00245         engine->config->chroot, &uid, &gid);
00246     engine->uid = uid;
00247     engine->gid = gid;
00248     privclose(engine->config->username, engine->config->group);
00249     return status;
00250 }
00251 
00252 
00257 static void
00258 engine_create_workers(engine_type* engine)
00259 {
00260     size_t i = 0;
00261     ods_log_assert(engine);
00262     ods_log_assert(engine->config);
00263     ods_log_assert(engine->allocator);
00264     engine->workers = (worker_type**) allocator_alloc(engine->allocator,
00265         ((size_t)engine->config->num_worker_threads) * sizeof(worker_type*));
00266     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00267         engine->workers[i] = worker_create(engine->allocator, i,
00268             WORKER_WORKER);
00269     }
00270     return;
00271 }
00272 static void
00273 engine_create_drudgers(engine_type* engine)
00274 {
00275     size_t i = 0;
00276     ods_log_assert(engine);
00277     ods_log_assert(engine->config);
00278     ods_log_assert(engine->allocator);
00279     engine->drudgers = (worker_type**) allocator_alloc(engine->allocator,
00280         ((size_t)engine->config->num_signer_threads) * sizeof(worker_type*));
00281     for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
00282         engine->drudgers[i] = worker_create(engine->allocator, i,
00283             WORKER_DRUDGER);
00284     }
00285     return;
00286 }
00287 static void*
00288 worker_thread_start(void* arg)
00289 {
00290     worker_type* worker = (worker_type*) arg;
00291     ods_thread_blocksigs();
00292     worker_start(worker);
00293     return NULL;
00294 }
00295 static void
00296 engine_start_workers(engine_type* engine)
00297 {
00298     size_t i = 0;
00299 
00300     ods_log_assert(engine);
00301     ods_log_assert(engine->config);
00302     ods_log_debug("[%s] start workers", engine_str);
00303     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00304         engine->workers[i]->need_to_exit = 0;
00305         engine->workers[i]->engine = (struct engine_struct*) engine;
00306         ods_thread_create(&engine->workers[i]->thread_id, worker_thread_start,
00307             engine->workers[i]);
00308     }
00309     return;
00310 }
00311 static void
00312 engine_start_drudgers(engine_type* engine)
00313 {
00314     size_t i = 0;
00315 
00316     ods_log_assert(engine);
00317     ods_log_assert(engine->config);
00318     ods_log_debug("[%s] start drudgers", engine_str);
00319     for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
00320         engine->drudgers[i]->need_to_exit = 0;
00321         engine->drudgers[i]->engine = (struct engine_struct*) engine;
00322         ods_thread_create(&engine->drudgers[i]->thread_id, worker_thread_start,
00323             engine->drudgers[i]);
00324     }
00325     return;
00326 }
00327 static void
00328 engine_stop_workers(engine_type* engine)
00329 {
00330     size_t i = 0;
00331 
00332     ods_log_assert(engine);
00333     ods_log_assert(engine->config);
00334     ods_log_debug("[%s] stop workers", engine_str);
00335     /* tell them to exit and wake up sleepyheads */
00336     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00337         engine->workers[i]->need_to_exit = 1;
00338         worker_wakeup(engine->workers[i]);
00339     }
00340     /* head count */
00341     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00342         ods_log_debug("[%s] join worker %i", engine_str, i+1);
00343         ods_thread_join(engine->workers[i]->thread_id);
00344         engine->workers[i]->engine = NULL;
00345     }
00346     return;
00347 }
00348 static void
00349 engine_stop_drudgers(engine_type* engine)
00350 {
00351     size_t i = 0;
00352 
00353     ods_log_assert(engine);
00354     ods_log_assert(engine->config);
00355     ods_log_debug("[%s] stop drudgers", engine_str);
00356     /* tell them to exit and wake up sleepyheads */
00357     for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
00358         engine->drudgers[i]->need_to_exit = 1;
00359     }
00360     worker_notify_all(&engine->signq->q_lock, &engine->signq->q_threshold);
00361 
00362     /* head count */
00363     for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
00364         ods_log_debug("[%s] join drudger %i", engine_str, i+1);
00365         ods_thread_join(engine->drudgers[i]->thread_id);
00366         engine->drudgers[i]->engine = NULL;
00367     }
00368     return;
00369 }
00370 
00371 
00376 void
00377 engine_wakeup_workers(engine_type* engine)
00378 {
00379     size_t i = 0;
00380 
00381     ods_log_assert(engine);
00382     ods_log_assert(engine->config);
00383     ods_log_debug("[%s] wake up workers", engine_str);
00384     /* wake up sleepyheads */
00385     for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
00386         worker_wakeup(engine->workers[i]);
00387     }
00388     return;
00389 }
00390 
00391 
00396 static int
00397 start_zonefetcher(engine_type* engine)
00398 {
00399     pid_t zfpid = 0;
00400     int result = 0;
00401     char* zf_filename = NULL;
00402     char* zl_filename = NULL;
00403     char* log_filename = NULL;
00404     char* grp = NULL;
00405     char* usr = NULL;
00406     char* chrt = NULL;
00407     int use_syslog = 0;
00408     int verbosity = 0;
00409 
00410     ods_log_assert(engine);
00411     ods_log_assert(engine->config);
00412 
00413     if (!engine->config->zonefetch_filename) {
00414         /* zone fetcher disabled */
00415         return 0;
00416     }
00417 
00418     switch ((zfpid = fork())) {
00419         case -1: /* error */
00420             ods_log_error("failed to fork zone fetcher: %s",
00421                 strerror(errno));
00422             return 1;
00423         case 0: /* child */
00424             break;
00425         default: /* parent */
00426             engine->zfpid = zfpid;
00427             return 0;
00428     }
00429 
00430     if (setsid() == -1) {
00431         ods_log_error("failed to setsid zone fetcher: %s",
00432             strerror(errno));
00433         return 1;
00434     }
00435 
00436     hsm_close();
00437     ods_log_verbose("zone fetcher running as pid %lu",
00438         (unsigned long) getpid());
00439 
00440     if (engine->config->zonefetch_filename) {
00441         zf_filename = strdup(engine->config->zonefetch_filename);
00442     }
00443     if (engine->config->zonelist_filename) {
00444         zl_filename = strdup(engine->config->zonelist_filename);
00445     }
00446     if (engine->config->group) {
00447         grp = strdup(engine->config->group);
00448     }
00449     if (engine->config->username) {
00450         usr = strdup(engine->config->username);
00451     }
00452     if (engine->config->chroot) {
00453         chrt = strdup(engine->config->chroot);
00454     }
00455     if (engine->config->log_filename) {
00456         log_filename = strdup(engine->config->log_filename);
00457     }
00458     use_syslog = engine->config->use_syslog;
00459     verbosity = engine->config->verbosity;
00460 
00461     result = tools_zone_fetcher(zf_filename, zl_filename, grp, usr,
00462         chrt, log_filename, use_syslog, verbosity);
00463 
00464     ods_log_verbose("zone fetcher done", result);
00465     if (zf_filename)  { free((void*)zf_filename); }
00466     if (zl_filename)  { free((void*)zl_filename); }
00467     if (grp)          { free((void*)grp); }
00468     if (usr)          { free((void*)usr); }
00469     if (chrt)         { free((void*)chrt); }
00470     if (log_filename) { free((void*)log_filename); }
00471 
00472     engine_cleanup(engine);
00473     engine = NULL;
00474     ods_log_close();
00475     xmlCleanupParser();
00476     xmlCleanupGlobals();
00477     xmlCleanupThreads();
00478     exit(result);
00479 
00480     return 0;
00481 }
00482 
00483 
00488 static void
00489 reload_zonefetcher(engine_type* engine)
00490 {
00491     int result = 0;
00492 
00493     ods_log_assert(engine);
00494     ods_log_assert(engine->config);
00495 
00496     if (engine->config->zonefetch_filename) {
00497         if (engine->zfpid > 0) {
00498             result = kill(engine->zfpid, SIGHUP);
00499             if (result == -1) {
00500                 ods_log_error("cannot reload zone fetcher: %s",
00501                     strerror(errno));
00502             } else {
00503                 ods_log_info("zone fetcher reloaded (pid=%i)", engine->zfpid);
00504             }
00505         } else {
00506             ods_log_error("cannot reload zone fetcher: process id unknown");
00507         }
00508     }
00509     return;
00510 }
00511 
00512 
00517 static void
00518 stop_zonefetcher(engine_type* engine)
00519 {
00520     int result = 0;
00521 
00522     ods_log_assert(engine);
00523     ods_log_assert(engine->config);
00524 
00525     if (engine->config->zonefetch_filename) {
00526         if (engine->zfpid > 0) {
00527             result = kill(engine->zfpid, SIGTERM);
00528             if (result == -1) {
00529                 ods_log_error("cannot stop zone fetcher: %s", strerror(errno));
00530             } else {
00531                 ods_log_info("zone fetcher stopped (pid=%i)", engine->zfpid);
00532             }
00533             engine->zfpid = -1;
00534         } else {
00535             ods_log_error("cannot stop zone fetcher: process id unknown");
00536         }
00537     }
00538     return;
00539 }
00540 
00541 
00546 static ods_status
00547 engine_init_adapters(engine_type* engine)
00548 {
00549     size_t i = 0;
00550     ods_status status = ODS_STATUS_OK;
00551 
00552     ods_log_assert(engine);
00553     ods_log_assert(engine->config);
00554     ods_log_debug("[%s] initialize adapters", engine_str);
00555     for (i=0; i < (size_t) engine->config->num_adapters; i++) {
00556         status = adapter_init(engine->config->adapters[i]);
00557         if (status != ODS_STATUS_OK) {
00558             return status;
00559         }
00560     }
00561     return status;
00562 }
00563 
00564 
00569 static ods_status
00570 engine_setup(engine_type* engine)
00571 {
00572     struct sigaction action;
00573     int result = 0;
00574     ods_status status = ODS_STATUS_OK;
00575 
00576     ods_log_debug("[%s] signer setup", engine_str);
00577     if (!engine || !engine->config) {
00578         return ODS_STATUS_ASSERT_ERR;
00579     }
00580 
00581     /* create command handler (before chowning socket file) */
00582     engine->cmdhandler = cmdhandler_create(engine->allocator,
00583         engine->config->clisock_filename);
00584     if (!engine->cmdhandler) {
00585         ods_log_error("[%s] create command handler to %s failed",
00586             engine_str, engine->config->clisock_filename);
00587         return ODS_STATUS_CMDHANDLER_ERR;
00588     }
00589 
00590     /* fork of fetcher */
00591     if (start_zonefetcher(engine) != 0) {
00592         ods_log_error("[%s] cannot start zonefetcher", engine_str);
00593         return ODS_STATUS_ERR;
00594     }
00595 
00596     /* initialize adapters */
00597     status = engine_init_adapters(engine);
00598     if (status != ODS_STATUS_OK) {
00599         ods_log_error("[%s] initializing adapters failed", engine_str);
00600         return status;
00601     }
00602 
00603     /* privdrop */
00604     engine->uid = privuid(engine->config->username);
00605     engine->gid = privgid(engine->config->group);
00606     /* TODO: does piddir exists? */
00607     /* remove the chown stuff: piddir? */
00608     ods_chown(engine->config->pid_filename, engine->uid, engine->gid, 1);
00609     ods_chown(engine->config->clisock_filename, engine->uid, engine->gid, 0);
00610     ods_chown(engine->config->working_dir, engine->uid, engine->gid, 0);
00611     if (engine->config->log_filename && !engine->config->use_syslog) {
00612         ods_chown(engine->config->log_filename, engine->uid, engine->gid, 0);
00613     }
00614     if (engine->config->working_dir &&
00615         chdir(engine->config->working_dir) != 0) {
00616         ods_log_error("[%s] chdir to %s failed: %s", engine_str,
00617             engine->config->working_dir, strerror(errno));
00618         return ODS_STATUS_CHDIR_ERR;
00619     }
00620     if (engine_privdrop(engine) != ODS_STATUS_OK) {
00621         ods_log_error("[%s] unable to drop privileges", engine_str);
00622         return ODS_STATUS_PRIVDROP_ERR;
00623     }
00624 
00625     /* daemonize */
00626     if (engine->daemonize) {
00627         switch ((engine->pid = fork())) {
00628             case -1: /* error */
00629                 ods_log_error("[%s] unable to fork daemon: %s",
00630                     engine_str, strerror(errno));
00631                 return ODS_STATUS_FORK_ERR;
00632             case 0: /* child */
00633                 break;
00634             default: /* parent */
00635                 engine_cleanup(engine);
00636                 engine = NULL;
00637                 xmlCleanupParser();
00638                 xmlCleanupGlobals();
00639                 xmlCleanupThreads();
00640                 exit(0);
00641         }
00642         if (setsid() == -1) {
00643             ods_log_error("[%s] unable to setsid daemon (%s)",
00644                 engine_str, strerror(errno));
00645             return ODS_STATUS_SETSID_ERR;
00646         }
00647     }
00648     engine->pid = getpid();
00649     ods_log_verbose("[%s] running as pid %lu", engine_str,
00650         (unsigned long) engine->pid);
00651 
00652     /* catch signals */
00653     signal_set_engine(engine);
00654     action.sa_handler = signal_handler;
00655     sigfillset(&action.sa_mask);
00656     action.sa_flags = 0;
00657     sigaction(SIGHUP, &action, NULL);
00658     sigaction(SIGTERM, &action, NULL);
00659 
00660     /* set up hsm */ /* LEAK */
00661     result = hsm_open(engine->config->cfg_filename, hsm_prompt_pin, NULL);
00662     if (result != HSM_OK) {
00663         ods_log_error("[%s] error initializing libhsm (errno %i)",
00664             engine_str, result);
00665         return ODS_STATUS_HSM_ERR;
00666     }
00667 
00668     /* create workers */
00669     engine_create_workers(engine);
00670     engine_create_drudgers(engine);
00671 
00672     /* start command handler */
00673     engine_start_cmdhandler(engine);
00674 
00675     /* write pidfile */
00676     if (util_write_pidfile(engine->config->pid_filename, engine->pid) == -1) {
00677         hsm_close();
00678         ods_log_error("[%s] unable to write pid file", engine_str);
00679         return ODS_STATUS_WRITE_PIDFILE_ERR;
00680     }
00681 
00682     return ODS_STATUS_OK;
00683 }
00684 
00685 
00690 static int
00691 engine_all_zones_processed(engine_type* engine)
00692 {
00693     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00694     zone_type* zone = NULL;
00695 
00696     ods_log_assert(engine);
00697     ods_log_assert(engine->zonelist);
00698     ods_log_assert(engine->zonelist->zones);
00699 
00700     node = ldns_rbtree_first(engine->zonelist->zones);
00701     while (node && node != LDNS_RBTREE_NULL) {
00702         zone = (zone_type*) node->key;
00703         if (!zone->processed) {
00704                 return 0;
00705         }
00706         node = ldns_rbtree_next(node);
00707     }
00708     return 1;
00709 }
00710 
00711 
00716 static void
00717 engine_run(engine_type* engine, int single_run)
00718 {
00719     if (!engine) {
00720         return;
00721     }
00722     ods_log_assert(engine);
00723 
00724     engine_start_workers(engine);
00725     engine_start_drudgers(engine);
00726 
00727     lock_basic_lock(&engine->signal_lock);
00728     /* [LOCK] signal */
00729     engine->signal = SIGNAL_RUN;
00730     /* [UNLOCK] signal */
00731     lock_basic_unlock(&engine->signal_lock);
00732 
00733     while (!engine->need_to_exit && !engine->need_to_reload) {
00734         lock_basic_lock(&engine->signal_lock);
00735         /* [LOCK] signal */
00736         engine->signal = signal_capture(engine->signal);
00737         switch (engine->signal) {
00738             case SIGNAL_RUN:
00739                 ods_log_assert(1);
00740                 break;
00741             case SIGNAL_RELOAD:
00742                 engine->need_to_reload = 1;
00743                 break;
00744             case SIGNAL_SHUTDOWN:
00745                 engine->need_to_exit = 1;
00746                 break;
00747             default:
00748                 ods_log_warning("[%s] invalid signal captured: %d, "
00749                     "keep running", engine_str, signal);
00750                 engine->signal = SIGNAL_RUN;
00751                 break;
00752         }
00753         /* [UNLOCK] signal */
00754         lock_basic_unlock(&engine->signal_lock);
00755 
00756         if (single_run) {
00757            engine->need_to_exit = engine_all_zones_processed(engine);
00758         }
00759 
00760         lock_basic_lock(&engine->signal_lock);
00761         /* [LOCK] signal */
00762         if (engine->signal == SIGNAL_RUN && !single_run) {
00763            ods_log_debug("[%s] taking a break", engine_str);
00764            lock_basic_sleep(&engine->signal_cond, &engine->signal_lock, 3600);
00765         }
00766         /* [UNLOCK] signal */
00767         lock_basic_unlock(&engine->signal_lock);
00768     }
00769     ods_log_debug("[%s] signer halted", engine_str);
00770     engine_stop_drudgers(engine);
00771     engine_stop_workers(engine);
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                 lock_basic_lock(&engine->taskq->schedule_lock);
00877                 /* [LOCK] schedule */
00878                 status = schedule_task(engine->taskq, task, 0);
00879                 /* [UNLOCK] schedule */
00880                 lock_basic_unlock(&engine->taskq->schedule_lock);
00881                 wake_up = 1;
00882             }
00883             /* zone fetcher enabled? */
00884             zone->fetch = (engine->config->zonefetch_filename != NULL);
00885             lock_basic_unlock(&zone->zone_lock);
00886         } else if (zone->just_updated) {
00887             lock_basic_lock(&zone->zone_lock);
00888             ods_log_assert(zone->task);
00889             zone->just_updated = 0;
00890             /* reschedule task */
00891             lock_basic_lock(&engine->taskq->schedule_lock);
00892             /* [LOCK] schedule */
00893             task = unschedule_task(engine->taskq, (task_type*) zone->task);
00894             if (task != NULL) {
00895                 ods_log_debug("[%s] reschedule task for zone %s", engine_str,
00896                     zone->name);
00897                 if (task->what != TASK_SIGNCONF) {
00898                     task->halted = task->what;
00899                     task->interrupt = TASK_SIGNCONF;
00900                 }
00901                 task->what = TASK_SIGNCONF;
00902                 task->when = now;
00903                 status = schedule_task(engine->taskq, task, 0);
00904             } else {
00905                 /* task now queued, being worked on? */
00906                 ods_log_debug("[%s] worker busy with zone %s, will update "
00907                     "signconf as soon as possible", engine_str, zone->name);
00908                 task = (task_type*) zone->task;
00909                 task->interrupt = TASK_SIGNCONF;
00910                 /* task->halted set by worker */
00911             }
00912             /* [UNLOCK] schedule */
00913             lock_basic_unlock(&engine->taskq->schedule_lock);
00914             lock_basic_unlock(&zone->zone_lock);
00915 
00916             wake_up = 1;
00917         }
00918 
00919         zone->task = task;
00920         if (status != ODS_STATUS_OK) {
00921             ods_log_crit("[%s] failed to schedule task for zone %s: %s",
00922                 engine_str, zone->name, ods_status2str(status));
00923             task_cleanup(task);
00924             zone->task = NULL;
00925         }
00926         node = ldns_rbtree_next(node);
00927     }
00928     /* [UNLOCK] zonelist */
00929     lock_basic_unlock(&engine->zonelist->zl_lock);
00930 
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             /* hsm has been opened */
01068             hsm_close();
01069         }
01070     } else {
01071         /* setup ok, mark hsm open */
01072         close_hsm = 1;
01073     }
01074 
01075     /* run */
01076     while (engine->need_to_exit == 0) {
01077         /* update zone list */
01078         lock_basic_lock(&engine->zonelist->zl_lock);
01079         /* [LOCK] zonelist */
01080         zl_changed = zonelist_update(engine->zonelist,
01081             engine->config->zonelist_filename);
01082         engine->zonelist->just_removed = 0;
01083         engine->zonelist->just_added = 0;
01084         engine->zonelist->just_updated = 0;
01085         /* [UNLOCK] zonelist */
01086         lock_basic_unlock(&engine->zonelist->zl_lock);
01087 
01088         if (engine->need_to_reload) {
01089             ods_log_info("[%s] signer reloading", engine_str);
01090             engine->need_to_reload = 0;
01091         } else {
01092             ods_log_info("[%s] signer started", engine_str);
01093             zl_changed = engine_recover(engine);
01094         }
01095 
01096         /* update zones */
01097         if (zl_changed == ODS_STATUS_OK) {
01098             ods_log_debug("[%s] commit zone list changes", engine_str);
01099             engine_update_zones(engine);
01100             ods_log_debug("[%s] signer configurations updated", engine_str);
01101             zl_changed = ODS_STATUS_UNCHANGED;
01102         }
01103 
01104         engine_run(engine, single_run);
01105     }
01106 
01107     /* shutdown */
01108     ods_log_info("[%s] signer shutdown", engine_str);
01109     stop_zonefetcher(engine);
01110     if (close_hsm) {
01111         hsm_close();
01112     }
01113     if (engine->cmdhandler != NULL) {
01114         engine_stop_cmdhandler(engine);
01115     }
01116 
01117 earlyexit:
01118     if (engine && engine->config) {
01119         if (engine->config->pid_filename) {
01120             (void)unlink(engine->config->pid_filename);
01121         }
01122         if (engine->config->clisock_filename) {
01123             (void)unlink(engine->config->clisock_filename);
01124         }
01125     }
01126     engine_cleanup(engine);
01127     engine = NULL;
01128     ods_log_close();
01129     xmlCleanupParser();
01130     xmlCleanupGlobals();
01131     xmlCleanupThreads();
01132     return;
01133 }
01134 
01135 
01140 void
01141 engine_cleanup(engine_type* engine)
01142 {
01143     size_t i = 0;
01144     allocator_type* allocator;
01145     cond_basic_type signal_cond;
01146     lock_basic_type signal_lock;
01147 
01148     if (!engine) {
01149         return;
01150     }
01151     allocator = engine->allocator;
01152     signal_cond = engine->signal_cond;
01153     signal_lock = engine->signal_lock;
01154 
01155     if (engine->workers && engine->config) {
01156         for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
01157             worker_cleanup(engine->workers[i]);
01158         }
01159         allocator_deallocate(allocator, (void*) engine->workers);
01160     }
01161     if (engine->drudgers && engine->config) {
01162        for (i=0; i < (size_t) engine->config->num_signer_threads; i++) {
01163            worker_cleanup(engine->drudgers[i]);
01164        }
01165         allocator_deallocate(allocator, (void*) engine->drudgers);
01166     }
01167     zonelist_cleanup(engine->zonelist);
01168     schedule_cleanup(engine->taskq);
01169     fifoq_cleanup(engine->signq);
01170     cmdhandler_cleanup(engine->cmdhandler);
01171     engine_config_cleanup(engine->config);
01172     allocator_deallocate(allocator, (void*) engine);
01173 
01174     lock_basic_destroy(&signal_lock);
01175     lock_basic_off(&signal_cond);
01176     allocator_cleanup(allocator);
01177     return;
01178 }