#ifndef lint static char rcsId[] = "$Id: restart.c,v 1.2 2000/03/15 14:00:21 claude Exp $"; #endif /* lint */ /* * restart * * Keeps alive fragiles daemons like xfs.... * * Claude Scarpelli , 18 janvier 1999 * * $Log: restart.c,v $ * Revision 1.2 2000/03/15 14:00:21 claude * improved english translation * * Revision 1.1 1999/01/18 15:50:22 claude * Initial revision * * * * * perldoc: * =head1 NAME B - controls and restart daemons. =head1 SYNOPSIS B [B<-fv>] [B<-n> nexec] [B<-t> time] command [arguments...] =head1 FLAGS B<-f> starts the daemon B in the foreground, ie it does not B, B<-v> verbose B<-n> number of process that can be started in the time interval specified with B<-t> (default 30), B<-t> time interval (default 60 seconds). No more that B process can be started in the time interval. If this condition occurs, B stops. =head1 PARAMETERS B The name of a utility that is to be invoked. B Any string to be supplied as an argument to the command. =head1 DESCRIPTION Some daemons, like B, crash very often. B can be used to automagically restart them, in a controlled fashion. =head1 NOTES B logs in B, B LOG_LOCAL5, B LOG_INFO. =head1 AUTHOR Claude Scarpelli, CNS-Genoscope, $Source: /usr/local/src/system/divers/RCS/restart.c,v $ $Id: restart.c,v 1.2 2000/03/15 14:00:21 claude Exp $ =cut */ #include #include #include #include #include #include #include #include #include static char usage[] = "%s: uage: %s [-fv] [-t time] [-n nb_exec] command [argument...]\n"; static int nexec = 30; /* no more that nexec exec().... */ static unsigned int tslot = 60; /* ....each 60 seconds */ static int verbose = 0; static int foregroundmode = 0; /* default: daemon mode */ static unsigned int n = 0; /* number of exec in this time slot */ static int inprogress = 0; /* != 0 if alarm() in progress */ static void die_with_usage(char *progname){ char *p = basename(progname); fprintf(stderr, usage, p, p); exit(1); } static void daemonize(){ pid_t pid = fork(); pid_t pgid; switch(pid){ case -1: perror("fork"); syslog(LOG_INFO, "fork failed: %m"); exit(1); break; case 0: if (verbose) syslog(LOG_INFO, "daemon running, pid = %d", getpid()); pgid = setpgrp(); if (verbose) syslog(LOG_INFO, "Process group ID is %d", pgid); return; break; default: if (verbose) syslog(LOG_INFO, "child started, with pid = %d", pid); exit(0); break; } } static pid_t spawn(char **argv){ pid_t pid; switch (pid = fork()){ case -1: if (foregroundmode) perror ("fork"); syslog(LOG_INFO, "fork failed: %m"); exit(1); break; case 0: execvp(argv[0], argv); if (foregroundmode) perror(argv[0]); syslog(LOG_INFO, "%s: %m", argv[0]); _exit(1); break; } return pid; } static void doc(int signum){ return; } static void bip(int signum){ inprogress = 0; return; } int main(int argc, char **argv){ int c; int error = 0; struct sigaction s; openlog(basename(argv[0]), LOG_PID, LOG_LOCAL5); while((c = getopt(argc, argv, "fvt:n:")) != EOF) switch (c){ case 'f': foregroundmode++; break; case 't': tslot = atoi(optarg); break; case 'n': nexec = atoi(optarg); break; case 'v': verbose++; break; default: error++; break; } if ((tslot <= 0) || (nexec <= 0)){ fprintf(stderr, "-t and -n args (%d %d) must be > 0\n", tslot, nexec); syslog(LOG_INFO, "-t and -n args (%d %d) must be > 0\n", tslot, nexec); error++; } if ((argc - optind) < 1) error++; if (error) die_with_usage(argv[0]); if (!foregroundmode) daemonize(); if (verbose){ if (foregroundmode) fprintf(stderr, "launching and controlling %s, but not more than %d times per %d seconds\n", argv[optind], nexec, tslot); syslog(LOG_INFO, "launching and controlling %s, but not more than %d times per %d seconds\n", argv[optind], nexec, tslot); } s.sa_sigaction = doc; s.sa_mask = 0; s.sa_flags = SA_RESTART; sigaction(SIGCHLD, &s, NULL); s.sa_sigaction = bip; s.sa_mask = 0; s.sa_flags = SA_RESTART; sigaction(SIGALRM, &s, NULL); argv += optind; for(;;){ pid_t pid, wpid; int wstatus; if (!inprogress){ inprogress++; n = 0; alarm(tslot); } n++; if (n >= nexec){ if (foregroundmode) fprintf(stderr, "%d exec() in this time slot, exiting\n", n); syslog(LOG_INFO, "%d exec() in this time slot, exiting\n", n); exit(1); } if (verbose){ if (foregroundmode) fprintf(stderr, "starting %s, %dth in this time slot\n", argv[0], n); syslog(LOG_INFO, "starting %s, %dth in this time slot\n", argv[0], n); } if ((pid = spawn(argv)) <= 0){ if (foregroundmode) fprintf(stderr, "spawn failed, exiting\n"); syslog(LOG_INFO, "spawn failed, exiting\n"); exit(1); } if (verbose){ if (foregroundmode) fprintf(stderr, "child process %d started\n", pid); syslog(LOG_INFO, "child process %d started\n", pid); } for (;;){ wpid = wait(&wstatus); if (verbose){ if (foregroundmode) fprintf(stderr, "wait: pid = %d, status = 0x%08x\n", wpid, wstatus); syslog(LOG_INFO, "wait: pid = %d, status = 0x%08x\n", wpid, wstatus); } if (wpid != pid){ if (foregroundmode) fprintf(stderr, "spurious wait (pid = %d, status 0x%08x, errno = %d)\n", wpid, wstatus, errno); syslog(LOG_INFO, "spurious wait (pid = %d, status 0x%08x, %m)\n", wpid, wstatus); continue; } if (wstatus){ if (WIFSTOPPED(wstatus) || WIFCONTINUED(wstatus)) continue; if (WIFSIGNALED(wstatus)){ if (foregroundmode) fprintf(stderr, "child process terminated by signal %d\n", WTERMSIG(wstatus)); syslog(LOG_INFO, "child process terminated by signal %d\n", WTERMSIG(wstatus)); break; } if (foregroundmode) fprintf(stderr, "child process terminated with return code %d\n", WEXITSTATUS(wstatus)); syslog(LOG_INFO, "child process terminated with return code %d\n", WEXITSTATUS(wstatus)); break; } if (foregroundmode) fprintf(stderr, "child process terminated with return code %d\n", WEXITSTATUS(wstatus)); syslog(LOG_INFO, "child process terminated with return code %d\n", WEXITSTATUS(wstatus)); break; } } }