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) ; }
pid_t child_spawn1_internal (char const *prog, char const *const *argv, char const *const *envp, int *p, int to) { int e ; int syncp[2] ; pid_t pid ; if (coe(p[0]) < 0 || pipecoe(syncp) < 0) { e = errno ; fd_close(p[1]) ; fd_close(p[0]) ; errno = e ; return 0 ; } pid = fork() ; if (pid < 0) { e = errno ; fd_close(syncp[1]) ; fd_close(syncp[0]) ; fd_close(p[1]) ; fd_close(p[0]) ; errno = e ; return 0 ; } if (!pid) { fd_close(syncp[0]) ; fd_close(p[!(to & 1)]) ; if (fd_move(to & 1, p[to & 1]) < 0) goto err ; if ((to & 2) && (fd_copy(!(to & 1), to & 1) < 0)) goto err ; sig_blocknone() ; pathexec_run(prog, argv, envp) ; err: e = errno ; fd_write(syncp[1], (char *)&e, sizeof(e)) ; _exit(127) ; } fd_close(syncp[1]) ; fd_close(p[to & 1]) ; syncp[1] = fd_read(syncp[0], (char *)&e, sizeof(e)) ; if (syncp[1] < 0) { e = errno ; fd_close(syncp[0]) ; fd_close(p[!(to & 1)]) ; errno = e ; return 0 ; } fd_close(syncp[0]) ; if (syncp[1] == sizeof(e)) { fd_close(p[!(to & 1)]) ; wait_pid(pid, &syncp[1]) ; errno = e ; return 0 ; } return pid ; }
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] ; } }