about summary refs log tree commit diff
path: root/src/supervision
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2020-12-04 07:25:12 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2020-12-04 07:25:12 +0000
commit5a318ce649a7a5f754892518a4452a519b41dac8 (patch)
treead4a8447fd8dc6cce82c1586bbb62566ea8f7e93 /src/supervision
parentffb0a8fd2045bb8f7f097905cb9d0814803c6060 (diff)
downloads6-5a318ce649a7a5f754892518a4452a519b41dac8.tar.gz
s6-5a318ce649a7a5f754892518a4452a519b41dac8.tar.xz
s6-5a318ce649a7a5f754892518a4452a519b41dac8.zip
Big signal/command semantics change to svscan/supervise; add s6-svperms.
Diffstat (limited to 'src/supervision')
-rw-r--r--src/supervision/deps-exe/s6-supervise2
-rw-r--r--src/supervision/deps-exe/s6-svperms1
-rw-r--r--src/supervision/s6-supervise.c108
-rw-r--r--src/supervision/s6-svc.c3
-rw-r--r--src/supervision/s6-svperms.c272
-rw-r--r--src/supervision/s6-svscan.c2
6 files changed, 320 insertions, 68 deletions
diff --git a/src/supervision/deps-exe/s6-supervise b/src/supervision/deps-exe/s6-supervise
index b1e57e4..34dc00e 100644
--- a/src/supervision/deps-exe/s6-supervise
+++ b/src/supervision/deps-exe/s6-supervise
@@ -1,3 +1,3 @@
-${LIBS6}
+libs6.a.xyzzy
 -lskarnet
 ${SYSCLOCK_LIB}
diff --git a/src/supervision/deps-exe/s6-svperms b/src/supervision/deps-exe/s6-svperms
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/supervision/deps-exe/s6-svperms
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/supervision/s6-supervise.c b/src/supervision/s6-supervise.c
index a8be37d..a175f0a 100644
--- a/src/supervision/s6-supervise.c
+++ b/src/supervision/s6-supervise.c
@@ -40,9 +40,9 @@
 typedef enum trans_e trans_t, *trans_t_ref ;
 enum trans_e
 {
-  V_TIMEOUT, V_CHLD, V_TERM, V_HUP, V_QUIT,
-  V_a, V_b, V_q, V_h, V_k, V_t, V_i, V_1, V_2, V_f, V_F, V_p, V_c, V_y, V_r,
-  V_o, V_d, V_u, V_x, V_O, V_X
+  V_TIMEOUT, V_CHLD, V_TERM, V_HUP, V_QUIT, V_INT,
+  V_a, V_b, V_q, V_h, V_k, V_t, V_i, V_1, V_2, V_p, V_c, V_y, V_r,
+  V_o, V_d, V_u, V_x, V_O
 } ;
 
 typedef enum state_e state_t, *state_t_ref ;
@@ -140,14 +140,22 @@ static void bail (void)
   cont = 0 ;
 }
 
+static void sigint (void)
+{
+  pid_t pgid = getpgid(status.pid) ;
+  if (pgid == -1) strerr_warnwu1sys("getpgid") ;
+  else killpg(pgid, SIGINT) ;
+  bail() ;
+}
+
 static void closethem (void)
 {
-  close(0) ;
-  close(1) ;
-  close(2) ;
-  open_readb("/dev/null") ;
-  open_write("/dev/null") ; ndelay_off(1) ;
-  open_write("/dev/null") ; ndelay_off(2) ;
+  fd_close(0) ;
+  fd_close(1) ;
+  if (open_readb("/dev/null"))
+    strerr_warnwu2sys("open /dev/null for ", "reading") ;
+  else if (open_write("/dev/null") != 1 || ndelay_off(1) < 0)
+      strerr_warnwu2sys("open /dev/null for ", "writing") ;
 }
 
 static void killa (void)
@@ -226,24 +234,6 @@ static void failcoe (int fd)
   errno = e ;
 }
 
-static int maybesetsid (void)
-{
-  char buf[8] = "-------" ;
-  ssize_t r = openreadnclose("nosetsid", buf, 8) ;
-  if (r < 0)
-  {
-    if (errno != ENOENT) return 0 ;
-    setsid() ;
-  }
-  else
-  {
-    if (r == 8 && buf[7] == '\n') buf[--r] = 0 ;
-    if (r == 7 && !strncasecmp(buf, "setpgrp", 7))
-      setpgid(0, 0) ;
-  }
-  return 1 ;
-}
-
 static void trystart (void)
 {
   int p[2] ;
@@ -285,11 +275,7 @@ static void trystart (void)
       failcoe(p[1]) ;
       strerr_diefu1sys(127, "move notification descriptor") ;
     }
-    if (!maybesetsid())
-    {
-      failcoe(p[1]) ;
-      strerr_diefu1sys(127, "access ./nosetsid") ;
-    }
+    setsid() ;
     execv("./run", (char *const *)cargv) ;
     failcoe(p[1]) ;
     strerr_dieexec(127, "run") ;
@@ -407,7 +393,7 @@ static int uplastup_z (void)
     selfpipe_finish() ;
     fmt0[uint_fmt(fmt0, WIFSIGNALED(status.wstat) ? 256 : WEXITSTATUS(status.wstat))] = 0 ;
     fmt1[uint_fmt(fmt1, WTERMSIG(status.wstat))] = 0 ;
-    maybesetsid() ;
+    setsid() ;
     execv("./finish", cargv) ;
     _exit(127) ;
   }
@@ -481,17 +467,12 @@ static void up_u (void)
 static void up_x (void)
 {
   state = LASTUP ;
-}
-
-static void up_X (void)
-{
   closethem() ;
-  up_x() ;
 }
 
 static void up_term (void)
 {
-  up_x() ;
+  state = LASTUP ;
   up_d() ;
 }
 
@@ -522,12 +503,7 @@ static void finish_u (void)
 static void finish_x (void)
 {
   state = LASTFINISH ;
-}
-
-static void finish_X (void)
-{
   closethem() ;
-  finish_x() ;
 }
 
 static void lastfinish_z (void)
@@ -536,23 +512,23 @@ static void lastfinish_z (void)
   bail() ;
 }
 
-static action_t_ref const actions[5][26] =
-{
-  { &downtimeout, &nop, &bail, &bail, &bail,
-    &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop,
-    &down_o, &down_d, &down_u, &bail, &down_O, &bail },
-  { &uptimeout, &up_z, &up_term, &up_x, &up_X,
-    &killa, &killb, &killq, &killh, &killk, &killt, &killi, &kill1, &kill2, &nop, &nop, &killp, &killc, &killy, &killr,
-    &up_o, &up_d, &up_u, &up_x, &up_o, &up_X },
-  { &finishtimeout, &finish_z, &finish_x, &finish_x, &finish_X,
-    &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop,
-    &up_o, &down_d, &finish_u, &finish_x, &up_o, &finish_X },
-  { &uptimeout, &lastup_z, &up_d, &nop, &closethem,
-    &killa, &killb, &killq, &killh, &killk, &killt, &killi, &kill1, &kill2, &nop, &nop, &killp, &killc, &killy, &killr,
-    &up_o, &up_d, &nop, &nop, &up_o, &closethem },
-  { &finishtimeout, &lastfinish_z, &nop, &nop, &closethem,
-    &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop,
-    &nop, &nop, &nop, &nop, &nop, &closethem }
+static action_t_ref const actions[5][24] =
+{
+  { &downtimeout, &nop, &bail, &bail, &bail, &bail,
+    &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop,
+    &down_o, &down_d, &down_u, &bail, &down_O },
+  { &uptimeout, &up_z, &up_term, &up_x, &bail, &sigint,
+    &killa, &killb, &killq, &killh, &killk, &killt, &killi, &kill1, &kill2, &killp, &killc, &killy, &killr,
+    &up_o, &up_d, &up_u, &up_x, &up_o },
+  { &finishtimeout, &finish_z, &finish_x, &finish_x, &bail, &sigint,
+    &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop,
+    &up_o, &down_d, &finish_u, &finish_x, &up_o },
+  { &uptimeout, &lastup_z, &up_d, &closethem, &bail, &sigint,
+    &killa, &killb, &killq, &killh, &killk, &killt, &killi, &kill1, &kill2, &killp, &killc, &killy, &killr,
+    &up_o, &up_d, &nop, &nop, &up_o },
+  { &finishtimeout, &lastfinish_z, &nop, &closethem, &bail, &sigint,
+    &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop, &nop,
+    &nop, &nop, &nop, &nop, &nop }
 } ;
 
 
@@ -615,6 +591,9 @@ static inline void handle_signals (void)
       case SIGQUIT :
         (*actions[state][V_QUIT])() ;
         break ;
+      case SIGINT :
+        (*actions[state][V_INT])() ;
+        break ;
       default :
         strerr_dief1x(101, "internal error: inconsistent signal state. Please submit a bug-report.") ;
     }
@@ -631,8 +610,8 @@ static inline void handle_control (int fd)
     else if (!r) break ;
     else
     {
-      size_t pos = byte_chr("abqhkti12fFpcyroduxOX", 21, c) ;
-      if (pos < 21) (*actions[state][V_a + pos])() ;
+      size_t pos = byte_chr("abqhkti12pcyroduxO", 18, c) ;
+      if (pos < 18) (*actions[state][V_a + pos])() ;
     }
   }
 }
@@ -736,10 +715,11 @@ int main (int argc, char const *const *argv)
     {
       sigset_t set ;
       sigemptyset(&set) ;
+      sigaddset(&set, SIGCHLD) ;
       sigaddset(&set, SIGTERM) ;
       sigaddset(&set, SIGHUP) ;
       sigaddset(&set, SIGQUIT) ;
-      sigaddset(&set, SIGCHLD) ;
+      sigaddset(&set, SIGINT) ;
       if (selfpipe_trapset(&set) < 0) strerr_diefu1sys(111, "trap signals") ;
     }
     
diff --git a/src/supervision/s6-svc.c b/src/supervision/s6-svc.c
index 3e024d6..a189d24 100644
--- a/src/supervision/s6-svc.c
+++ b/src/supervision/s6-svc.c
@@ -28,7 +28,7 @@ int main (int argc, char const *const *argv)
     subgetopt_t l = SUBGETOPT_ZERO ;
     for (;;)
     {
-      int opt = subgetopt_r(argc, argv, "abqhkti12pcyroduxOXT:w:", &l) ;
+      int opt = subgetopt_r(argc, argv, "abqhkti12pcyroduxOT:w:", &l) ;
       if (opt == -1) break ;
       switch (opt)
       {
@@ -50,7 +50,6 @@ int main (int argc, char const *const *argv)
         case 'u' :
         case 'x' :
         case 'O' :
-        case 'X' :
         {
           if (datalen >= DATASIZE) strerr_dief1x(100, "too many commands") ;
           data[datalen++] = opt ;
diff --git a/src/supervision/s6-svperms.c b/src/supervision/s6-svperms.c
new file mode 100644
index 0000000..178ea08
--- /dev/null
+++ b/src/supervision/s6-svperms.c
@@ -0,0 +1,272 @@
+/* ISC license. */
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <skalibs/types.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/buffer.h>
+#include <skalibs/strerr2.h>
+
+#include <s6/s6-supervise.h>
+
+#define USAGE "s6-svperms [ -v ] [ -u | -g group | -G group | -o | -O group ] [ -e | -E group ] servicedir..."
+#define dieusage() strerr_dieusage(100, USAGE)
+
+static gid_t scangid (char const *s)
+{
+  if (s[0] == ':')
+  {
+    gid_t g ;
+    if (!gid0_scan(s+1, &g)) dieusage() ;
+    return g ;
+  }
+  else
+  {
+    struct group *gr ;
+    errno = 0 ;
+    gr = getgrnam(s) ;
+    if (!gr)
+    {
+      if (errno) strerr_diefu1sys(111, "getgrnam") ;
+      else strerr_diefu3x(100, "find entry for ", s, " in group database") ;
+    }
+    return gr->gr_gid ;
+  }
+}
+
+static char *gidname (gid_t gid)
+{
+  struct group *gr ;
+  errno = 0 ;
+  gr = getgrgid(gid) ;
+  if (!gr)
+  {
+    static char fmt[GID_FMT] ;
+    fmt[gid_fmt(fmt, gid)] = 0 ;
+    if (errno) strerr_warnwu2sys("getgrgid ", fmt) ;
+    return fmt ;
+  }
+  return gr->gr_name ;
+}
+
+static void out (char const *s)
+{
+  if (buffer_puts(buffer_1, s) < 0)
+    strerr_diefu1sys(111, "write to stdout") ;
+}
+
+static inline int printsupervise (char const *dir)
+{
+  struct stat st ;
+  size_t len = strlen(dir) ;
+  char fn[len + sizeof(S6_SUPERVISE_CTLDIR) + 9] ;
+  memcpy(fn, dir, len) ;
+  memcpy(fn + len, "/" S6_SUPERVISE_CTLDIR, sizeof(S6_SUPERVISE_CTLDIR) + 1) ;
+  if (stat(fn, &st) < 0)
+  {
+    strerr_warnwu2sys("stat ", fn) ;
+    return 1 ;
+  }
+  if (!S_ISDIR(st.st_mode))
+  {
+    strerr_warnw2x(fn, " is not a directory") ;
+    return 1 ;
+  }
+  if (st.st_mode & 05066 || (st.st_mode & 0700) != 0700 || ((st.st_mode & 0001) && !(st.st_mode & 0010)))
+  {
+    char fmt[UINT_OFMT] ;
+    fmt[uint_ofmt(fmt, st.st_mode & 07777)] = 0 ;
+    strerr_warnw3x(fn, " has incorrect permissions: ", fmt) ;
+    return 1 ;
+  }
+  out(dir) ;
+  out(" status: ") ;
+  if (st.st_mode & 0011)
+  {
+    if (st.st_mode & 0001) buffer_puts(buffer_1, "public") ;
+    else
+    {
+      out("group ") ;
+      out(gidname(st.st_gid)) ;
+    }
+  }
+  else out("owner") ;
+  out("\n") ;
+  memcpy(fn + len + sizeof(S6_SUPERVISE_CTLDIR), "/control", 9) ;
+  if (stat(fn, &st) < 0)
+  {
+    strerr_warnwu2sys("stat ", fn) ;
+    return 1 ;
+  }
+  if (!S_ISFIFO(st.st_mode))
+  {
+    strerr_warnw2x(fn, " is not a named pipe") ;
+    return 1 ;
+  }
+  if (st.st_mode & 0157)
+  {
+    char fmt[UINT_OFMT] ;
+    fmt[uint_ofmt(fmt, st.st_mode & 07777)] = 0 ;
+    strerr_warnw3x(fn, " has incorrect permissions: ", fmt) ;
+    return 1 ;
+  }
+  out(dir) ;
+  out(" control: ") ;
+  if (st.st_mode & 0020)
+  {
+    out("group ") ;
+    out(gidname(st.st_gid)) ;
+  }
+  else out("owner") ;
+  out("\n") ;
+  return 0 ;
+}
+
+static inline int printevent (char const *dir)
+{
+  struct stat st ;
+  size_t len = strlen(dir) ;
+  char fn[len + sizeof(S6_SUPERVISE_EVENTDIR) + 1] ;
+  memcpy(fn, dir, len) ;
+  memcpy(fn + len, "/" S6_SUPERVISE_EVENTDIR, sizeof(S6_SUPERVISE_EVENTDIR) + 1) ;
+  if (stat(fn, &st) < 0)
+  {
+    strerr_warnwu2sys("stat ", fn) ;
+    return 1 ;
+  }
+  if (!S_ISDIR(st.st_mode))
+  {
+    strerr_warnw2x(fn, " is not a directory") ;
+    return 1 ;
+  }
+  if ((st.st_mode & 07777) != 01733 && (st.st_mode & 07777) != 03730)
+  {
+    char fmt[UINT_OFMT] ;
+    fmt[uint_ofmt(fmt, st.st_mode & 07777)] = 0 ;
+    strerr_warnw3x(fn, " has incorrect permissions: ", fmt) ;
+    return 1 ;
+  }
+  out(dir) ;
+  out(" events: ") ;
+  if ((st.st_mode & 07777) == 03730)
+  {
+    out("group ") ;
+    out(gidname(st.st_gid)) ;
+  }
+  else out("public") ;
+  out("\n") ;
+  return 0 ;
+}
+
+static gid_t primarygid (char const *fn)
+{
+  struct passwd *pw ;
+  struct stat st ;
+  if (stat(fn, &st) < 0) strerr_diefu2sys(111, "stat ", fn) ;
+  errno = 0 ;
+  pw = getpwuid(st.st_uid) ;
+  if (!pw)
+  {
+    strerr_warnwu3sys("determine primary gid for the owner of ", fn, " (using root instead)") ;
+    return 0 ;
+  }
+  else return pw->pw_gid ;
+}
+
+static inline void modsupervise (char const *dir, unsigned int what, gid_t gid)
+{
+  size_t len = strlen(dir) ;
+  gid_t cgid  = 0 ;
+  mode_t mode = 0700 ;
+  char fn[len + sizeof(S6_SUPERVISE_CTLDIR) + 9] ;
+  memcpy(fn, dir, len) ;
+  memcpy(fn + len, "/" S6_SUPERVISE_CTLDIR, sizeof(S6_SUPERVISE_CTLDIR) + 1) ;
+  switch (what & 3)
+  {
+    case 0 : cgid = primarygid(fn) ; mode = 0700 ; break ;
+    case 1 : cgid = gid ; mode = 0710 ; break ;
+    case 2 : cgid = primarygid(fn) ; mode = 0711 ; break ;
+  }
+  if (chown(fn, -1, cgid) < 0)
+    strerr_diefu2sys(111, "chown ", fn) ;
+  if (chmod(fn, mode) < 0)
+    strerr_diefu2sys(111, "chmod ", fn) ;
+  memcpy(fn + len + sizeof(S6_SUPERVISE_CTLDIR), "/control", 9) ;
+  if (what & 4) mode = 0620 ;
+  else
+  {
+    gid = primarygid(fn) ;
+    mode = 0600 ;
+  }
+  if (chown(fn, -1, gid) < 0)
+    strerr_diefu2sys(111, "chown ", fn) ;
+  if (chmod(fn, mode) < 0)
+    strerr_diefu2sys(111, "chmod ", fn) ;
+}
+
+static inline void modevent (char const *dir, gid_t gid)
+{
+  size_t len = strlen(dir) ;
+  mode_t mode ;
+  char fn[len + sizeof(S6_SUPERVISE_EVENTDIR) + 1] ;
+  memcpy(fn, dir, len) ;
+  memcpy(fn + len, "/" S6_SUPERVISE_EVENTDIR, sizeof(S6_SUPERVISE_EVENTDIR) + 1) ;
+  if (gid == (gid_t)-1)
+  {
+    gid = primarygid(fn) ;
+    mode = 01733 ;
+  }
+  else mode = 03730 ;
+  if (chown(fn, -1, gid) < 0)
+    strerr_diefu2sys(111, "chown ", fn) ;
+  if (chmod(fn, mode) < 0)
+    strerr_diefu2sys(111, "chmod ", fn) ;
+}
+
+int main (int argc, char const *const *argv)
+{
+  int e = 0 ;
+  gid_t gid = -1 ;
+  gid_t eventgid = -1 ;
+  int rw = 0 ;
+  unsigned int what = 0 ;
+  PROG = "s6-svperms" ;
+  {
+    subgetopt_t l = SUBGETOPT_ZERO ;
+    for (;;)
+    {
+      int opt = subgetopt_r(argc, argv, "vug:G:oO:eE:", &l) ;
+      if (opt == -1) break ;
+      switch (opt)
+      {
+        case 'v' : rw |= 1 ; break ;
+        case 'u' : rw |= 2 ; what = 0 ; break ;
+        case 'g' : rw |= 2 ; what = 1 ; gid = scangid(l.arg) ; break ;
+        case 'G' : rw |= 2 ; what = 5 ; gid = scangid(l.arg) ; break ;
+        case 'o' : rw |= 2 ; what = 2 ; break ;
+        case 'O' : rw |= 2 ; what = 6 ; gid = scangid(l.arg) ; break ;
+        case 'e' : rw |= 4 ; eventgid = -1 ; break ;
+        case 'E' : rw |= 4 ; eventgid = scangid(l.arg) ; break ;
+        default : dieusage() ;
+      }
+    }
+    argc -= l.ind ; argv += l.ind ;
+  }
+  if (!argc) dieusage() ;
+
+  if (!rw) rw = 1 ;
+  for (; *argv ; argv++)
+  {
+    if (rw & 2) modsupervise(*argv, what, gid) ;
+    if (rw & 4) modevent(*argv, eventgid) ;
+    if (rw & 1) { e |= printsupervise(*argv) ; e |= printevent(*argv) ; }
+  }
+  if (rw & 1 && !buffer_flush(buffer_1))
+    strerr_diefu1sys(111, "write to stdout") ;
+  return e ;
+}
diff --git a/src/supervision/s6-svscan.c b/src/supervision/s6-svscan.c
index 0a3c286..1d17a3a 100644
--- a/src/supervision/s6-svscan.c
+++ b/src/supervision/s6-svscan.c
@@ -497,7 +497,7 @@ static inline int control_init (void)
       strerr_dief1x(100, S6_SVSCAN_CTLDIR " exists and is not a directory") ;
   }
 
-  fdlck = open(LCK, O_WRONLY | O_NONBLOCK | O_CREAT | O_CLOEXEC, 0644) ;
+  fdlck = open(LCK, O_WRONLY | O_NONBLOCK | O_CREAT | O_CLOEXEC, 0600) ;
   if (fdlck < 0) strerr_diefu1sys(111, "open " LCK) ;
   r = fd_lock(fdlck, 1, 1) ;
   if (r < 0) strerr_diefu1sys(111, "lock " LCK) ;