about summary refs log tree commit diff
path: root/src/supervision
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2023-09-11 17:26:46 +0000
committerLaurent Bercot <ska@appnovation.com>2023-09-11 17:26:46 +0000
commit970bbeb622573a80381f0f32e6f287195182c0e0 (patch)
tree5c061d6f7b6ab9ac31173d8947ac41eba01de4e9 /src/supervision
parentde03e80a55ec78c93a749f41dfc69e806e655b0e (diff)
downloads6-970bbeb622573a80381f0f32e6f287195182c0e0.tar.gz
s6-970bbeb622573a80381f0f32e6f287195182c0e0.tar.xz
s6-970bbeb622573a80381f0f32e6f287195182c0e0.zip
Defork s6-supervise (!)
Signed-off-by: Laurent Bercot <ska@appnovation.com>
Diffstat (limited to 'src/supervision')
-rw-r--r--src/supervision/s6-supervise.c206
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", &notif))
   {
-    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") ;