#ifndef __supervise_h #define __supervise_h #include "config.h" #include #include #include #include #include #ifndef HAVE_SYSLOG static void inline supervise(char *x) { fatal("You probably don't want to supervise when you cannot log"); } #else static int supervised_pid = -1; static int supervised_quit = 0; static void handle_sign(int signo) { if (supervised_pid != -1) { kill(supervised_pid, signo); supervised_quit = 1; } } static void inline supervise(char *x) { int fd, status; int super_pid; /* GOOD DAEMON PRACTICES */ /* do first fork */ signal(SIGCHLD, SIG_IGN); switch (fork()) { case -1: cfatal("fork: %s"); case 0: break; default: exit(0); }; /* be a proper daemon */ fd = open("/dev/null", O_RDWR); if (fd != 0) { close(0); dup2(fd, 0); } if (fd != 1) { close(1); dup2(fd, 1); } if (fd != 2) { close(2); dup2(fd, 2); } if (fd > 2) { close(fd); } super_pid = getpid(); #ifdef HAVE_SETSID /* change session ID if possible */ (void) setsid(); #endif /* signore Sigpipe */ signal(SIGPIPE, SIG_IGN); /* we want child notification */ signal(SIGCHLD, SIG_DFL); /* setup other signals */ signal(SIGSTOP, handle_sign); signal(SIGCONT, handle_sign); signal(SIGTERM, handle_sign); signal(SIGHUP, handle_sign); signal(SIGINT, handle_sign); /* do second fork */ restart_from_child_l: switch ((supervised_pid = fork())) { case -1: cfatal("fork: %s"); case 0: /* child */ return; }; /* pid file */ if (x && *x == '/') { FILE *fp; fp = fopen(x, "w"); fprintf(fp, "%d\n", super_pid); fclose(fp); } wait_some_more_l: #ifdef HAVE_WAITPID waitpid(supervised_pid, &status, 0); #else #ifdef HAVE_WAIT4 wait4(supervised_pid, &status, 0, NULL); #else while (wait(&status) != supervised_pid); #endif #endif if (kill(supervised_pid, 0) == -1) { sleep(1); /* go to sleep for 1 second */ if ((volatile)supervised_quit) exit(0); /* wasn't supposed to be dead yet... */ goto restart_from_child_l; } supervised_quit = 0; goto wait_some_more_l; } #endif #endif