static void trystart (void) { int p[2] ; pid_t pid ; if (pipecoe(p) < 0) { settimeout(60) ; strerr_warnwu1sys("pipecoe (waiting 60 seconds)") ; return ; } pid = fork() ; if (pid < 0) { settimeout(60) ; strerr_warnwu1sys("fork (waiting 60 seconds)") ; fd_close(p[1]) ; fd_close(p[0]) ; return ; } else if (!pid) { char const *cargv[2] = { "run", 0 } ; PROG = "s6-supervise (child)" ; selfpipe_finish() ; fd_close(p[0]) ; if (unlink(S6_SUPERVISE_READY_FILENAME) < 0 && errno != ENOENT) strerr_warnwu1sys("unlink " S6_SUPERVISE_READY_FILENAME) ; if (flagsetsid) setsid() ; execve("./run", (char *const *)cargv, (char *const *)environ) ; fd_write(p[1], "", 1) ; strerr_dieexec(127, "run") ; } fd_close(p[1]) ; { char c ; switch (fd_read(p[0], &c, 1)) { case -1 : fd_close(p[0]) ; settimeout(60) ; strerr_warnwu1sys("read pipe (waiting 60 seconds)") ; kill(pid, SIGKILL) ; return ; case 1 : { fd_close(p[0]) ; settimeout(10) ; strerr_warnwu1x("spawn ./run - waiting 10 seconds") ; return ; } } } fd_close(p[0]) ; settimeout_infinite() ; state = UP ; status.pid = pid ; tain_copynow(&status.stamp) ; announce() ; ftrigw_notifyb_nosig(S6_SUPERVISE_EVENTDIR, "u", 1) ; }
int aa_service_status_set_err (aa_service_status *svst, int err, const char *msg) { svst->event = AA_EVT_ERROR; svst->code = err; tain_copynow (&svst->stamp); return aa_service_status_set_msg (svst, (msg) ? msg : ""); }
static void uplastup_z (int islast) { status.wstat = status.pid ; status.pid = 0 ; tain_copynow(&status.stamp) ; tryfinish(islast) ; announce() ; ftrigw_notifyb_nosig(S6_SUPERVISE_EVENTDIR, "d", 1) ; if (unlink(S6_SUPERVISE_READY_FILENAME) < 0 && errno != ENOENT) strerr_warnwu1sys("unlink " S6_SUPERVISE_READY_FILENAME) ; settimeout(5) ; }
static void check (char const *name) { struct stat st ; unsigned int namelen ; unsigned int i = 0 ; if (name[0] == '.') return ; if (stat(name, &st) == -1) { strerr_warnwu2sys("stat ", name) ; retrydirlater() ; return ; } if (!S_ISDIR(st.st_mode)) return ; namelen = str_len(name) ; for (; i < n ; i++) if ((services[i].ino == st.st_ino) && (services[i].dev == st.st_dev)) break ; if (i < n) { if (services[i].flaglog && (services[i].p[0] < 0)) { /* See BLACK MAGIC above. */ services[i].p[0] = -2 ; return ; } } else { if (n >= max) { strerr_warnwu3x("start supervisor for ", name, ": too many services") ; return ; } else { struct stat su ; char tmp[namelen + 5] ; byte_copy(tmp, namelen, name) ; byte_copy(tmp + namelen, 5, "/log") ; if (stat(tmp, &su) < 0) if (errno == ENOENT) services[i].flaglog = 0 ; else { strerr_warnwu2sys("stat ", tmp) ; retrydirlater() ; return ; } else if (!S_ISDIR(su.st_mode)) services[i].flaglog = 0 ; else { if (pipecoe(services[i].p) < 0) { strerr_warnwu1sys("pipecoe") ; retrydirlater() ; return ; } services[i].flaglog = 1 ; } services[i].ino = st.st_ino ; services[i].dev = st.st_dev ; tain_copynow(&services[i].restartafter[0]) ; tain_copynow(&services[i].restartafter[1]) ; services[i].pid[0] = 0 ; services[i].pid[1] = 0 ; n++ ; } } services[i].flagactive = 1 ; if (services[i].flaglog && !services[i].pid[1]) { if (!tain_future(&services[i].restartafter[1])) { char tmp[namelen + 5] ; byte_copy(tmp, namelen, name) ; byte_copy(tmp + namelen, 5, "/log") ; trystart(i, tmp, 1) ; } else if (tain_less(&services[i].restartafter[1], &deadline)) deadline = services[i].restartafter[1] ; } if (!services[i].pid[0]) { if (!tain_future(&services[i].restartafter[0])) trystart(i, name, 0) ; else if (tain_less(&services[i].restartafter[0], &deadline)) deadline = services[i].restartafter[0] ; } }
int main (int argc, char const *const *argv) { iopause_fd x[2] = { { -1, IOPAUSE_READ, 0 }, { -1, IOPAUSE_READ, 0 } } ; PROG = "s6-supervise" ; if (argc < 2) strerr_dieusage(100, USAGE) ; if (chdir(argv[1]) < 0) strerr_diefu2sys(111, "chdir to ", argv[1]) ; { register unsigned int proglen = str_len(PROG) ; register unsigned int namelen = str_len(argv[1]) ; char progname[proglen + namelen + 2] ; byte_copy(progname, proglen, PROG) ; progname[proglen] = ' ' ; byte_copy(progname + proglen + 1, namelen + 1, argv[1]) ; PROG = progname ; if (!fd_sanitize()) strerr_diefu1sys(111, "sanitize stdin and stdout") ; x[1].fd = s6_supervise_lock(S6_SUPERVISE_CTLDIR) ; if (!ftrigw_fifodir_make(S6_SUPERVISE_EVENTDIR, getegid(), 0)) strerr_diefu2sys(111, "mkfifodir ", S6_SUPERVISE_EVENTDIR) ; x[0].fd = selfpipe_init() ; if (x[0].fd == -1) strerr_diefu1sys(111, "init selfpipe") ; if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ; { sigset_t set ; sigemptyset(&set) ; sigaddset(&set, SIGTERM) ; sigaddset(&set, SIGHUP) ; sigaddset(&set, SIGQUIT) ; sigaddset(&set, SIGCHLD) ; if (selfpipe_trapset(&set) < 0) strerr_diefu1sys(111, "trap signals") ; } if (!ftrigw_clean(S6_SUPERVISE_EVENTDIR)) strerr_warnwu2sys("ftrigw_clean ", S6_SUPERVISE_EVENTDIR) ; { struct stat st ; if (stat("down", &st) == -1) { if (errno != ENOENT) strerr_diefu1sys(111, "stat down") ; } else status.flagwantup = 0 ; if (stat("nosetsid", &st) == -1) { if (errno != ENOENT) strerr_diefu1sys(111, "stat nosetsid") ; } else flagsetsid = 0 ; } tain_now_g() ; settimeout(0) ; tain_copynow(&status.stamp) ; announce() ; ftrigw_notifyb_nosig(S6_SUPERVISE_EVENTDIR, "s", 1) ; while (cont) { register int r = iopause_g(x, 2, &deadline) ; if (r < 0) strerr_diefu1sys(111, "iopause") ; else if (!r) (*actions[state][V_TIMEOUT])() ; else { if ((x[0].revents | x[1].revents) & IOPAUSE_EXCEPT) strerr_diefu1x(111, "iopause: trouble with pipes") ; if (x[0].revents & IOPAUSE_READ) handle_signals() ; else if (x[1].revents & IOPAUSE_READ) handle_control(x[1].fd) ; } } ftrigw_notifyb_nosig(S6_SUPERVISE_EVENTDIR, "x", 1) ; } return 0 ; }