diff options
-rw-r--r-- | src/supervision/s6-supervise.c | 206 |
1 files changed, 79 insertions, 127 deletions
diff --git a/src/supervision/s6-supervise.c b/src/supervision/s6-supervise.c index 5611b98..488150c 100644 --- a/src/supervision/s6-supervise.c +++ b/src/supervision/s6-supervise.c @@ -11,20 +11,24 @@ #include <limits.h> #include <signal.h> #include <fcntl.h> +#include <sys/resource.h> #include <sys/stat.h> #include <sys/wait.h> +#include <skalibs/posixplz.h> #include <skalibs/allreadwrite.h> #include <skalibs/bytestr.h> #include <skalibs/types.h> #include <skalibs/strerr.h> #include <skalibs/tai.h> #include <skalibs/iopause.h> +#include <skalibs/cspawn.h> #include <skalibs/djbunix.h> #include <skalibs/sig.h> #include <skalibs/selfpipe.h> #include <skalibs/skamisc.h> +#include <s6/config.h> #include <s6/ftrigw.h> #include <s6/supervise.h> @@ -72,6 +76,7 @@ static s6_svstatus_t status = S6_SVSTATUS_ZERO ; static state_t state = DOWN ; static int notifyfd = -1 ; static char const *servicename = 0 ; +static rlim_t maxfd ; static inline void settimeout (int secs) { @@ -248,160 +253,109 @@ static void killr (void) kill(status.pid, read_downsig()) ; } -static void failcoe (int fd) -{ - int e = errno ; - fd_write(fd, "", 1) ; - errno = e ; -} - static void trystart (void) { - int p[2] ; + cspawn_fileaction fa[2] = + { + [0] = { .type = CSPAWN_FA_CLOSE }, + [1] = { .type = CSPAWN_FA_MOVE }, + } ; + char lkfmt[UINT_FMT] ; + char const *cargv[7] = { S6_BINPREFIX "s6-setlock", "-d", lkfmt, "--", "./run", servicename, 0 } ; + size_t orig = 4 ; int notifyp[2] = { -1, -1 } ; - int lfd = -1 ; - int locked = 1 ; - unsigned int notif, lk ; - pid_t pid ; + unsigned int lk = 0, notif = 0 ; + if (read_uint("lock-fd", &lk)) { - if (lk > INT_MAX) strerr_warnw2x("invalid ", "lock-fd") ; + if (lk > maxfd) strerr_warnw2x("invalid ", "lock-fd") ; else { struct stat st ; - lfd = open_write(SLCK) ; + int islocked ; + int lfd = open_write(SLCK) ; if (lfd == -1) { settimeout(60) ; strerr_warnwu4sys("open ", SLCK, " for writing", " (waiting 60 seconds)") ; - return ; + goto errn ; } if (fstat(lfd, &st) == -1) { settimeout(60) ; strerr_warnwu3sys("stat ", SLCK, " (waiting 60 seconds)") ; - goto errl ; + fd_close(lfd) ; + return ; } if (st.st_size) { ftruncate(lfd, 0) ; strerr_warnw1x("a previous instance of the service wrote to the lock file!") ; } - locked = fd_lock(lfd, 1, 1) ; - if (locked == -1) + islocked = fd_islocked(lfd) ; + if (islocked == -1) { settimeout(60) ; - strerr_warnwu3sys("lock ", SLCK, " (waiting 60 seconds)") ; - goto errl ; + strerr_warnwu3sys("read lock state on ", SLCK, " (waiting 60 seconds)") ; + fd_close(lfd) ; + return ; } - if (!locked) + if (islocked) strerr_warnw1x("another instance of the service is already running, child will block") ; + fd_close(lfd) ; + lkfmt[uint_fmt(lkfmt, lk)] = 0 ; + orig = 0 ; } } + if (read_uint("notification-fd", ¬if)) { - if (notif > INT_MAX) strerr_warnw2x("invalid ", "notification-fd") ; - else if (lfd >= 0 && notif == lk) + if (notif > maxfd) strerr_warnw2x("invalid ", "notification-fd") ; + if (!orig && notif == lk) { settimeout_infinite() ; strerr_warnwu1x("start service: notification-fd and lock-fd are the same") ; - goto errl ; + return ; } - else if (pipe(notifyp) < 0) + if (pipe(notifyp) == -1) { settimeout(60) ; - strerr_warnwu2sys("pipe", " (waiting 60 seconds)") ; - goto errl ; + strerr_warnwu2sys("create notification pipe", " (waiting 60 seconds)") ; + return ; } + fa[0].x.fd = notifyp[0] ; + fa[1].x.fd2[0] = notif ; + fa[1].x.fd2[1] = notifyp[1] ; } - if (pipecoe(p) < 0) + + status.pid = cspawn(cargv[orig], cargv + orig, (char const *const *)environ, CSPAWN_FLAGS_SELFPIPE_FINISH | CSPAWN_FLAGS_SETSID, fa, notifyp[1] >= 0 ? 2 : 0) ; + if (!status.pid) { settimeout(60) ; - strerr_warnwu2sys("pipe", " (waiting 60 seconds)") ; + strerr_warnwu3sys("spawn ", cargv[orig], " (waiting 60 seconds)") ; goto errn ; } - pid = fork() ; - if (pid < 0) - { - settimeout(60) ; - strerr_warnwu2sys("fork", " (waiting 60 seconds)") ; - goto errp ; - } - else if (!pid) - { - char const *cargv[3] = { "run", servicename, 0 } ; - ((char *)PROG)[strlen(PROG)] = ' ' ; - selfpipe_finish() ; - if (notifyp[0] >= 0) close(notifyp[0]) ; - close(p[0]) ; - if (notifyp[1] >= 0 && fd_move(notif, notifyp[1]) < 0) - { - failcoe(p[1]) ; - strerr_diefu1sys(127, "move notification descriptor") ; - } - if (lfd >= 0) - { - if (fd_move(lk, lfd) < 0) - { - failcoe(p[1]) ; - strerr_diefu1sys(127, "move lock descriptor") ; - } - if (!locked && fd_lock(lk, 1, 0) == -1) - { - failcoe(p[1]) ; - strerr_diefu2sys(127, "lock ", SLCK) ; - } - } - setsid() ; - execv("./run", (char *const *)cargv) ; - failcoe(p[1]) ; - strerr_dieexec(127, "run") ; - } - fd_close(p[1]) ; - if (notifyp[1] >= 0) fd_close(notifyp[1]) ; - if (lfd >= 0) fd_close(lfd) ; + + if (notifyp[1] >= 0) { - 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(notifyp[1]) ; + notifyfd = notifyp[0] ; } - fd_close(p[0]) ; - notifyfd = notifyp[0] ; settimeout_infinite() ; nextstart = tain_zero ; state = UP ; - status.pid = pid ; status.flagready = 0 ; tain_wallclock_read(&status.stamp) ; announce() ; ftrigw_notifyb_nosig(S6_SUPERVISE_EVENTDIR, "u", 1) ; return ; - errp: - fd_close(p[1]) ; - fd_close(p[0]) ; errn: if (notifyp[1] >= 0) { fd_close(notifyp[1]) ; fd_close(notifyp[0]) ; } - errl: - if (lfd >= 0) fd_close(lfd) ; } static void wantdown (void) @@ -454,6 +408,11 @@ static void down_U (void) static int uplastup_z (void) { + unsigned int n ; + char fmt0[UINT_FMT] ; + char fmt1[UINT_FMT] ; + char const *cargv[5] = { "finish", fmt0, fmt1, servicename, 0 } ; + status.wstat = (int)status.pid ; status.flagpaused = 0 ; status.flagready = 0 ; @@ -464,49 +423,33 @@ static int uplastup_z (void) fd_close(notifyfd) ; notifyfd = -1 ; } + fmt0[uint_fmt(fmt0, WIFSIGNALED(status.wstat) ? 256 : WEXITSTATUS(status.wstat))] = 0 ; + fmt1[uint_fmt(fmt1, WTERMSIG(status.wstat))] = 0 ; + if (!read_uint("max-death-tally", &n)) n = 100 ; + if (n > S6_MAX_DEATH_TALLY) n = S6_MAX_DEATH_TALLY ; + if (n) { - unsigned int n ; - if (!read_uint("max-death-tally", &n)) n = 100 ; - if (n > S6_MAX_DEATH_TALLY) n = S6_MAX_DEATH_TALLY ; - if (n) + s6_dtally_t tab[n+1] ; + ssize_t m = s6_dtally_read(".", tab, n) ; + if (m < 0) strerr_warnwu2sys("read ", S6_DTALLY_FILENAME) ; + else { - s6_dtally_t tab[n+1] ; - ssize_t m = s6_dtally_read(".", tab, n) ; - if (m < 0) strerr_warnwu2sys("read ", S6_DTALLY_FILENAME) ; - else - { - tab[m].stamp = status.stamp ; - tab[m].sig = WIFSIGNALED(status.wstat) ? WTERMSIG(status.wstat) : 0 ; - tab[m].exitcode = WIFSIGNALED(status.wstat) ? 128 + WTERMSIG(status.wstat) : WEXITSTATUS(status.wstat) ; - if (!(m >= n ? s6_dtally_write(".", tab+1, n) : s6_dtally_write(".", tab, m+1))) - strerr_warnwu2sys("write ", S6_DTALLY_FILENAME) ; - } + tab[m].stamp = status.stamp ; + tab[m].sig = WIFSIGNALED(status.wstat) ? WTERMSIG(status.wstat) : 0 ; + tab[m].exitcode = WIFSIGNALED(status.wstat) ? 128 + WTERMSIG(status.wstat) : WEXITSTATUS(status.wstat) ; + if (!(m >= n ? s6_dtally_write(".", tab+1, n) : s6_dtally_write(".", tab, m+1))) + strerr_warnwu2sys("write ", S6_DTALLY_FILENAME) ; } } - status.pid = fork() ; - if (status.pid < 0) + status.pid = cspawn("./finish", cargv, (char const *const *)environ, CSPAWN_FLAGS_SELFPIPE_FINISH | CSPAWN_FLAGS_SETSID, 0, 0) ; + if (!status.pid) { - strerr_warnwu2sys("fork for ", "./finish") ; + strerr_warnwu2sys("spawn ", "./finish") ; set_down_and_ready("dD", 2) ; return 0 ; } - else if (!status.pid) - { - char fmt0[UINT_FMT] ; - char fmt1[UINT_FMT] ; - char *cargv[5] = { "finish", fmt0, fmt1, (char *)servicename, 0 } ; - selfpipe_finish() ; - fmt0[uint_fmt(fmt0, WIFSIGNALED(status.wstat) ? 256 : WEXITSTATUS(status.wstat))] = 0 ; - fmt1[uint_fmt(fmt1, WTERMSIG(status.wstat))] = 0 ; - setsid() ; - execv("./finish", cargv) ; - _exit(127) ; - } - status.flagfinishing = 1 ; - announce() ; - ftrigw_notifyb_nosig(S6_SUPERVISE_EVENTDIR, "d", 1) ; { tain tto ; unsigned int timeout ; @@ -515,6 +458,9 @@ static int uplastup_z (void) tain_add_g(&deadline, &tto) ; else settimeout_infinite() ; } + status.flagfinishing = 1 ; + announce() ; + ftrigw_notifyb_nosig(S6_SUPERVISE_EVENTDIR, "d", 1) ; return 1 ; } @@ -806,6 +752,12 @@ int main (int argc, char const *const *argv) memcpy(progname + proglen + 2 + namelen, "(child)", 8) ; PROG = progname ; if (!fd_sanitize()) strerr_diefu1sys(111, "sanitize stdin and stdout") ; + { + struct rlimit rl ; + if (getrlimit(RLIMIT_NOFILE, &rl) == -1) + strerr_diefu1sys(111, "getrlimit") ; + maxfd = rl.rlim_cur ; + } x[1].fd = control_init() ; x[0].fd = selfpipe_init() ; if (x[0].fd == -1) strerr_diefu1sys(111, "init selfpipe") ; |