This is ninit.c in view mode; [Download] [Up]
/* * Named init --- sits around and restarts named when necessary * * Written by Theodore Ts'o. Copyright 1991. * * Use this code however you want, as long as you don't try to make * money off of it and as long as you don't claim it's yours. * * $Header: /afs/net.mit.edu/project/bind/named/RCS/ninit.c,v 1.3 91/05/13 17:30:58 tytso Exp $ * $Source: /afs/net.mit.edu/project/bind/named/RCS/ninit.c,v $ * * Note that ninit requires that named be modified so that it accepts * the -n option. This option to named asks named not to fork into * the background when it is started up. This is necessary because * ninit wants to be notified when the named process exits. * * Usage: ninit [options] [named boot file] * * Options: * -n <negative niceness> Run the named process with the nice level * *reduced* argument level. This is useful * on mailhub, when you have 30+ sendmail * processes and one named process, and you * want to give the named process a * higher priority. * * -s <stats interval> This option controls how often (in * seconds) named should be strobed to * update the named.stats file. * * -c <check interval> This option controls how often (in * seconds) ninit should check to make * sure named is still working. * * -f <syslog facility> This option controls which syslog facility * ninit should use. * * -d <debug level> This option is passed to named to turn * on nameserver debugging. * * -N This option tells ninit not fork and go * into the background when it is started * up. * */ #include <stdio.h> #include <sys/types.h> #include <syslog.h> #include <errno.h> #include <signal.h> #include <netdb.h> #include <ctype.h> #include <sys/socket.h> #include <arpa/nameser.h> #include <netinet/in.h> #include <resolv.h> #include <sys/wait.h> #include <sys/file.h> #include <sys/time.h> #include <sys/resource.h> /* * Configuration section. It should be fairly obvious..... * * FORKING_NAMED is intended for site who do not have source code to * their named, and so cannot add the -n option to named. * * TEST_HOST specifies the host which ninit should try to resolve when * checking to see if named is working. */ #define TEST_HOST "MIT.EDU" #define NAMED "/etc/named" #define NAMED_PID_FILE "/etc/named.pid" #define PID_FILE "/etc/ninit.pid" #define DEFAULT_FACILITY LOG_LOCAL4 /* #define FORKING_NAMED */ extern int h_errno; int named_pid = -1; int terminating_named = 0; int named_restarting = 0; int child_died = 0; int stats_timer = 0; int check_timer = 0; char *named_file = 0; int named_nice = 0; int debug = 0; int syslog_facility = DEFAULT_FACILITY; char *progname = 0; int nofork = 0; int stats_interval = 300; int check_interval = 60; struct in_addr local_addr; void start_named(), PRS(), usage(); int decode_facility(); struct code { char *name; int facility; }; struct code FacNames[] = { "kern", LOG_KERN, "user", LOG_USER, "mail", LOG_MAIL, "daemon", LOG_DAEMON, "auth", LOG_AUTH, "syslog", LOG_SYSLOG, "lpr", LOG_LPR, #ifdef LOG_NEWS "news", LOG_NEWS, #endif #ifdef LOG_UUCP "uucp", LOG_UUCP, #endif "local0", LOG_LOCAL0, "local1", LOG_LOCAL1, "local2", LOG_LOCAL2, "local3", LOG_LOCAL3, "local4", LOG_LOCAL4, "local5", LOG_LOCAL5, "local6", LOG_LOCAL6, "local7", LOG_LOCAL7, "security", LOG_AUTH, #ifdef LOG_MARK "mark", LOG_MARK, #endif NULL, -1 }; int alarm_chk() { int named_active = 1; int do_check = 0; int next_alarm; if ((named_pid <= 0) || named_restarting || terminating_named) { named_active = 0; } /* * We could put something here to increment the timers by alarm(0), * but we won't bother for now. * * Check to see if the timers have expired; if so, run the events */ if (named_active && (stats_timer <= 0)) { (void) rename("/usr/tmp/named.stats", "/usr/tmp/named.stats.old"); kill(named_pid, SIGIOT); stats_timer = stats_interval; } if (named_active && (check_timer <= 0)) { /* * We run this one after restarting the alarm because * it might take a while */ do_check++; check_timer = check_interval; } /* * Now figure out when the next time we need to run. */ if (stats_timer < check_timer) next_alarm = stats_timer; else next_alarm = check_timer; stats_timer -= next_alarm; check_timer -= next_alarm; alarm(next_alarm); /* * Now, perform the named check if necessary */ if (do_check) { (void) gethostbyname(TEST_HOST); if (h_errno == TRY_AGAIN) { syslog(LOG_ERR, "Named hosed! Restarting..."); restart_named(); } } } int restart_named() { if ((named_pid <= 0) || named_restarting || terminating_named) return; terminating_named++; kill(named_pid, SIGTERM); } int die() { syslog(LOG_NOTICE, "/etc/ninit received SIGTERM, exiting"); if (named_pid > 0) { kill(named_pid, SIGTERM); syslog(LOG_NOTICE, "named killed as part of ninit shutdown"); } (void) unlink(NAMED_PID_FILE); (void) unlink(PID_FILE); exit(0); } int mourner() { child_died++; } main(argc, argv) int argc; char **argv; { int pid; union wait status; PRS(argc, argv); daemon_setup(); openlog("ninit", LOG_PID|LOG_CONS, syslog_facility); syslog(LOG_INFO, "ninit started, pid = %d", getpid()); signal(SIGALRM, alarm_chk); signal(SIGHUP, restart_named); signal(SIGTERM, die); signal(SIGCHLD, mourner); start_named(); alarm_chk(); while (1) { pid = wait(&status); if (pid == -1) { if (errno == ECHILD) { named_pid = -1; start_named(); continue; } else { syslog(LOG_CRIT, "Error in wait: %s", sys_errlist[errno]); sleep(120); continue; } } named_pid = -1; if (terminating_named || (status.w_termsig == SIGTERM)) { terminating_named = 0; } else if (status.w_termsig) { syslog(LOG_ERR, "Named terinated with signal %d%s", status.w_termsig, status.w_coredump ? " (core dumped)" : ""); } else { syslog(status.w_retcode ? LOG_ERR : LOG_NOTICE, "named termined with exit status %d", status.w_retcode); } start_named(); } } void start_named() { int pid; int tries = 3; FILE *f; char debug_buf[24]; char *argv[10]; int argc = 0; if (f = fopen(NAMED_PID_FILE, "r")) { fscanf(f, "%d", &pid); fclose(f); if ((pid > 0) && !kill(pid, 0)) { /* There is a running named already, kill it. */ syslog(LOG_WARNING, "Killing already existing named, pid = %d", pid); kill(pid, 15); } } if (named_restarting++ > 3) { syslog(LOG_ALERT, "Couldn't start named after three tries, sleeping"); sleep(180); named_restarting = 1; } child_died = 0; if ((pid = vfork()) == 0) { argv[argc++] = "named"; if (debug) { argv[argc++] = "-d"; sprintf(debug_buf, "%d", debug); argv[argc++] = debug_buf; } #ifdef FORKING_NAMED else argv[argc++] = "-d"; #else argv[argc++] = "-n"; #endif argv[argc++] = named_file; argv[argc++] = 0; execv(NAMED, argv); syslog(LOG_ERR, "Couldn't start named: %s", sys_errlist[errno]); exit(1); } else if (pid == -1) { syslog(LOG_ERR, "Couldn't fork to start named: %s", sys_errlist[errno]); sleep(180); return; } else { syslog(LOG_DEBUG, "Named process started, pid = %d", pid); named_pid = pid; setpriority(PRIO_PROCESS, pid, named_nice); named_restarting++; /* Stall until the named is really working */ do { if (child_died) return; (void) gethostbyname(TEST_HOST); } while (h_errno == TRY_AGAIN); syslog(LOG_INFO, "Named successfully started, pid = %d\n", pid); named_restarting = 0; #ifdef FORKING_NAMED /* Turn off debugging */ if (!debug) kill(named_pid, SIGUSR2); #endif /* * Reset timers... */ stats_timer = stats_interval; check_timer = check_interval; alarm_chk(); } } void PRS(argc, argv) int argc; char **argv; { register char *word, ch; char *buf; char *fac = NULL; local_addr.s_addr = inet_addr("127.0.0.1"); res_init(); _res.nscount = 1; /* One nameserver --- the local one */ _res.nsaddr.sin_addr = local_addr; _res.retry = 2; _res.retrans = RES_TIMEOUT; progname = *argv++; while (word = *argv++) { if (*word == '-') { word++; while (word && (ch = *word++)) { switch(ch){ case 'n': /* Niceness */ if (*word) buf = word; else buf = *argv++; if (!buf) usage(); named_nice = 0 - atoi(buf); word = 0; break; case 's': /* Stats int. */ if (*word) buf = word; else buf = *argv++; if (!buf) usage(); stats_interval = atoi(buf); word = 0; break; case 'c': /* Check int. */ if (*word) buf = word; else buf = *argv++; if (!buf) usage(); check_interval = atoi(buf); word = 0; break; case 'f': /* Syslog facility */ if (*word) fac = word; else fac = *argv++; if (!fac) usage(); word = 0; break; case 'd': /* Debug */ if (*word) buf = word; else buf = *argv++; if (!buf) usage(); debug = atoi(buf); word = 0; break; case 'N': /* Nofork */ nofork++; break; default: usage(); } } } else { if (named_file) usage(); else named_file = word; } } if (fac) { syslog_facility = decode_facility(fac); if (syslog_facility < 0) { fprintf(stderr, "%s is not a valid facility\n", fac); exit(1); } } } void usage() { fprintf(stderr, "Usage: %s [OPTIONS] named_boot_file\n\n", progname); fprintf(stderr, "Where the options can be: \n"); fprintf(stderr, "\t-d debug_level\tTurns on debugging\n"); fprintf(stderr, "\t-n nice arg\tRenices the named by -nice arg\n"); fprintf(stderr, "\t-f facility\tUses the specified syslog facility\n"); fprintf(stderr, "\t-s stats_interval\tSpecifies the statistics polling interval\n"); fprintf(stderr, "\t-c check_interval\tSpecifies the named check interval\n"); fprintf(stderr, "\t-N\t\tCauses ninit not to fork on startup.\n"); exit(1); } daemon_setup() { int n, pid; FILE *f; if (f = fopen(PID_FILE, "r")) { fscanf(f, "%d", &pid); fclose(f); if (!kill(pid, 0)) { fprintf(stderr, "ninit is already running on pid = %d\n", pid); exit(1); } } if (!nofork) { if (fork() > 0) exit(0); n = open("/dev/null", O_RDONLY); (void) dup2(n, 0); (void) dup2(n, 1); (void) dup2(n, 2); if (n > 2) (void) close(n); } if ((f = fopen(PID_FILE, "w")) == NULL) syslog(LOG_ERR, "Couldn't open pid file for write, %s", sys_errlist[errno]); fprintf(f, "%d\n", getpid()); fclose(f); } int decode_facility(name) char *name; { char buf[40], *src, *dest; struct code *p; int i; for (src = name, dest = buf, i = 0; *src && i < 40; src++, dest++, i++) *dest = (isupper(*src)) ? tolower(*src) : *src; for (p = FacNames; p->name; p++) if (!strcmp(buf, p->name)) return(p->facility); return(-1); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.