about summary refs log tree commit diff
path: root/src/supervision
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2017-03-25 11:25:15 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2017-03-25 11:25:15 +0000
commit9a669c4b3973118dfcce2a2b1fb4babd0aaa6af7 (patch)
tree50298ce1f6a60a19f8b7ff7a594ac8f4fc5d4d67 /src/supervision
parent2654165a84b90af2cbfef967e6e230b2975b644c (diff)
downloads6-9a669c4b3973118dfcce2a2b1fb4babd0aaa6af7.tar.gz
s6-9a669c4b3973118dfcce2a2b1fb4babd0aaa6af7.tar.xz
s6-9a669c4b3973118dfcce2a2b1fb4babd0aaa6af7.zip
Stop using flagwant; new s6-svstat API; s6-svwait's timeout exitcode is now 99
Diffstat (limited to 'src/supervision')
-rw-r--r--src/supervision/s6-supervise.c13
-rw-r--r--src/supervision/s6-svstat.c261
-rw-r--r--src/supervision/s6_svlisten_loop.c2
3 files changed, 229 insertions, 47 deletions
diff --git a/src/supervision/s6-supervise.c b/src/supervision/s6-supervise.c
index 2e8ce6a..a1a52f8 100644
--- a/src/supervision/s6-supervise.c
+++ b/src/supervision/s6-supervise.c
@@ -297,13 +297,13 @@ static void trystart (void)
 
 static void downtimeout (void)
 {
-  if (status.flagwant && status.flagwantup) trystart() ;
+  if (status.flagwantup) trystart() ;
   else settimeout_infinite() ;
 }
 
 static void down_O (void)
 {
-  status.flagwant = 0 ;
+  status.flagwantup = 0 ;
   announce() ;
 }
 
@@ -315,7 +315,6 @@ static void down_o (void)
 
 static void down_u (void)
 {
-  status.flagwant = 1 ;
   status.flagwantup = 1 ;
   announce() ;
   trystart() ;
@@ -323,7 +322,6 @@ static void down_u (void)
 
 static void down_d (void)
 {
-  status.flagwant = 1 ;
   status.flagwantup = 0 ;
   announce() ;
 }
@@ -391,13 +389,12 @@ static void uptimeout (void)
 
 static void up_o (void)
 {
-  status.flagwant = 0 ;
+  status.flagwantup = 0 ;
   announce() ;
 }
 
 static void up_d (void)
 {
-  status.flagwant = 1 ;
   status.flagwantup = 0 ;
   killt() ;
   killc() ;
@@ -405,7 +402,6 @@ static void up_d (void)
 
 static void up_u (void)
 {
-  status.flagwant = 1 ;
   status.flagwantup = 1 ;
   announce() ;
 }
@@ -439,7 +435,7 @@ static void finish_z (void)
   int wstat = (int)status.pid ;
   if (WIFEXITED(wstat) && WEXITSTATUS(wstat) == 125)
   {
-    status.flagwant = 0 ;
+    status.flagwantup = 0 ;
     set_down_and_ready("OD", 2) ;
   }
   else set_down_and_ready("D", 1) ;
@@ -447,7 +443,6 @@ static void finish_z (void)
 
 static void finish_u (void)
 {
-  status.flagwant = 1 ;
   status.flagwantup = 1 ;
   announce() ;
 }
diff --git a/src/supervision/s6-svstat.c b/src/supervision/s6-svstat.c
index 2b4da7a..a30d685 100644
--- a/src/supervision/s6-svstat.c
+++ b/src/supervision/s6-svstat.c
@@ -6,6 +6,7 @@
 #include <errno.h>
 #include <skalibs/uint64.h>
 #include <skalibs/types.h>
+#include <skalibs/bytestr.h>
 #include <skalibs/buffer.h>
 #include <skalibs/strerr2.h>
 #include <skalibs/sgetopt.h>
@@ -14,53 +15,169 @@
 #include <skalibs/djbunix.h>
 #include <s6/s6-supervise.h>
 
-#define USAGE "s6-svstat [ -n ] servicedir"
+#define USAGE "s6-svstat [ -uwNrpest | -o up,wantedup,normallyup,ready,paused,pid,exitcode,signal,signum,updownsince,readysince,updownfor,readyfor ] [ -n ] servicedir"
 #define dieusage() strerr_dieusage(100, USAGE)
 
-int main (int argc, char const *const *argv)
+#define MAXFIELDS 16
+#define checkfields() if (n >= MAXFIELDS) strerr_dief1x(100, "too many option fields")
+
+static int normallyup ;
+
+typedef void prfunc_t (buffer *, s6_svstatus_t const *) ;
+typedef prfunc_t * prfunc_t_ref ;
+
+typedef struct funcmap_s funcmap_t ;
+struct funcmap_s
 {
-  s6_svstatus_t status ;
-  int flagnum = 0 ;
-  int isup, normallyup ;
+  char const *s ;
+  prfunc_t_ref f ;
+} ;
+
+static void pr_up (buffer *b, s6_svstatus_t const *st)
+{
+  buffer_putsnoflush(b, st->pid && !st->flagfinishing ? "true" : "false") ;
+}
+
+static void pr_wantedup (buffer *b, s6_svstatus_t const *st)
+{
+  buffer_putsnoflush(b, st->flagwantup ? "true" : "false") ;
+}
+
+static void pr_ready (buffer *b, s6_svstatus_t const *st)
+{
+  buffer_putsnoflush(b, st->pid && st->flagready ? "true" : "false") ;
+}
+
+static void pr_paused (buffer *b, s6_svstatus_t const *st)
+{
+  buffer_putsnoflush(b, st->flagpaused ? "true" : "false") ;
+}
+
+static void pr_pid (buffer *b, s6_svstatus_t const *st)
+{
+  if (st->pid && !st->flagfinishing)
+  {
+    char fmt[PID_FMT] ;
+    buffer_putnoflush(b, fmt, pid_fmt(fmt, st->pid)) ;
+  }
+  else buffer_putsnoflush(b, "-1") ;
+}
+
+static void pr_tain (buffer *b, tain_t const *a)
+{
+  char fmt[TIMESTAMP] ;
+  buffer_putnoflush(b, fmt, timestamp_fmt(fmt, a)) ;
+}
+
+static void pr_stamp (buffer *b, s6_svstatus_t const *st)
+{
+  pr_tain(b, &st->stamp) ;
+}
+
+static void pr_readystamp (buffer *b, s6_svstatus_t const *st)
+{
+  pr_tain(b, &st->readystamp) ;
+}
+
+static void pr_seconds (buffer *b, tain_t const *a)
+{
+  tain_t d ;
   char fmt[UINT64_FMT] ;
-  PROG = "s6-svstat" ;
+  tain_sub(&d, &STAMP, a) ;
+  buffer_putnoflush(b, fmt, uint64_fmt(fmt, tai_sec(tain_secp(&d)))) ;
+}
+
+static void pr_upseconds (buffer *b, s6_svstatus_t const *st)
+{
+  pr_seconds(b, &st->stamp) ;
+}
+
+static void pr_readyseconds (buffer *b, s6_svstatus_t const *st)
+{
+  pr_seconds(b, &st->readystamp) ;
+}
+
+static void pr_exitcode (buffer *b, s6_svstatus_t const *st)
+{
+  int e = st->pid && !st->flagfinishing ? -1 :
+          WIFEXITED(st->wstat) ? WEXITSTATUS(st->wstat) : -1 ;
+  char fmt[INT_FMT] ;
+  buffer_putnoflush(b, fmt, int_fmt(fmt, e)) ;
+}
+
+static void pr_signum (buffer *b, s6_svstatus_t const *st)
+{
+  int e = st->pid && !st->flagfinishing ? -1 :
+            WIFSIGNALED(st->wstat) ? WTERMSIG(st->wstat) : -1 ;
+  char fmt[INT_FMT] ;
+  buffer_putnoflush(b, fmt, int_fmt(fmt, e)) ;
+}
+
+static void pr_signal (buffer *b, s6_svstatus_t const *st)
+{
+  int e = st->pid && !st->flagfinishing ? -1 :
+            WIFSIGNALED(st->wstat) ? WTERMSIG(st->wstat) : -1 ;
+  if (e == -1) buffer_putsnoflush(b, "NA") ;
+  else
   {
-    subgetopt_t l = SUBGETOPT_ZERO ;
-    for (;;)
-    {
-      int opt = subgetopt_r(argc, argv, "n", &l) ;
-      if (opt == -1) break ;
-      switch (opt)
-      {
-        case 'n' : flagnum = 1 ; break ;
-        default : dieusage() ;
-      }
-    }
-    argc -= l.ind ; argv += l.ind ;
+    buffer_putsnoflush(b, "SIG") ;
+    buffer_putsnoflush(b, sig_name(e)) ;
   }
-  if (!argc) dieusage() ;
+}
 
-  if (!s6_svstatus_read(*argv, &status))
-    strerr_diefu2sys(111, "read status for ", *argv) ;
-  isup = s6_svc_ok(argv[0]) ;
-  if (isup < 0) strerr_diefu2sys(111, "check ", argv[0]) ;
-  if (!isup) strerr_diefu3x(1, "read status for ", argv[0], ": s6-supervise not running") ;
+static void pr_normallyup (buffer *b, s6_svstatus_t const *st)
+{
+  buffer_putsnoflush(b, normallyup ? "true" : "false") ;
+  (void)st ;
+}
 
-  tain_now_g() ;
-  if (tain_future(&status.stamp)) tain_copynow(&status.stamp) ;
+static funcmap_t const fmtable[] =
+{
+  { .s = "up", .f = &pr_up },
+  { .s = "wantedup", .f = &pr_wantedup },
+  { .s = "normallyup", .f = &pr_normallyup },
+  { .s = "ready", .f = &pr_ready },
+  { .s = "paused", .f = &pr_paused },
+  { .s = "pid", .f = &pr_pid },
+  { .s = "exitcode", .f = &pr_exitcode },
+  { .s = "signal", .f = &pr_signal },
+  { .s = "signum", .f = &pr_signum },
+  { .s = "updownsince", .f = &pr_stamp },
+  { .s = "readysince", .f = &pr_readystamp },
+  { .s = "updownfor", .f = &pr_upseconds },
+  { .s = "readyfor", .f = &pr_readyseconds },
+  { .s = 0, .f = 0 }
+} ;
 
+
+static unsigned int parse_options (char const *arg, prfunc_t_ref *fields, unsigned int n)
+{
+  while (*arg)
   {
-    size_t dirlen = strlen(*argv) ;
-    char fn[dirlen + 6] ;
-    memcpy(fn, *argv, dirlen) ;
-    memcpy(fn + dirlen, "/down", 6) ;
-    if (access(fn, F_OK) < 0)
-      if (errno != ENOENT) strerr_diefu2sys(111, "access ", fn) ;
-      else normallyup = 1 ;
-    else normallyup = 0 ;
+    size_t pos = str_chr(arg, ',') ;
+    funcmap_t const *p = fmtable ;
+    if (!pos) strerr_dief1x(100, "invalid null option field") ;
+    for (; p->s ; p++) if (!strncmp(arg, p->s, pos)) break ;
+    if (!p->s)
+    {
+      char blah[pos+1] ;
+      memcpy(blah, arg, pos) ;
+      blah[pos] = 0 ;
+      strerr_dief2x(100, "invalid option field: ", blah) ;
+    }
+    checkfields() ;
+    fields[n++] = p->f ;
+    arg += pos ; if (*arg) arg++ ;
   }
+  return n ;
+}
+
+static void legacy (s6_svstatus_t *st, int flagnum)
+{
+  s6_svstatus_t status = *st ;
+  int isup = status.pid && !status.flagfinishing ;
+  char fmt[UINT64_FMT] ;
 
-  isup = status.pid && !status.flagfinishing ;
   if (isup)
   {
     buffer_putnoflush(buffer_1small,"up (pid ", 8) ;
@@ -99,9 +216,9 @@ int main (int argc, char const *const *argv)
     buffer_putnoflush(buffer_1small, ", normally up", 13) ;
   if (isup && status.flagpaused)
     buffer_putnoflush(buffer_1small, ", paused", 8) ;
-  if (!isup && status.flagwant)
+  if (!isup && status.flagwantup)
     buffer_putnoflush(buffer_1small, ", want up", 10) ;
-  if (isup && !status.flagwant)
+  if (isup && !status.flagwantup)
     buffer_putnoflush(buffer_1small, ", want down", 12) ;
 
   if (status.flagready)
@@ -111,6 +228,76 @@ int main (int argc, char const *const *argv)
     buffer_putnoflush(buffer_1small, fmt, uint64_fmt(fmt, status.readystamp.sec.x)) ;
     buffer_putnoflush(buffer_1small, " seconds", 8) ;
   }
+}
+
+int main (int argc, char const *const *argv)
+{
+  s6_svstatus_t status ;
+  int flagnum = 0 ;
+  prfunc_t_ref fields[MAXFIELDS] ;
+  unsigned int n = 0 ;
+  PROG = "s6-svstat" ;
+
+  {
+    subgetopt_t l = SUBGETOPT_ZERO ;
+    for (;;)
+    {
+      int opt = subgetopt_r(argc, argv, "no:uWNrpest", &l) ;
+      if (opt == -1) break ;
+      switch (opt)
+      {
+        case 'n' : flagnum = 1 ; break ;
+        case 'o' : n = parse_options(l.arg, fields, n) ; break ;
+        case 'u' : checkfields() ; fields[n++] = &pr_up ; break ;
+        case 'w' : checkfields() ; fields[n++] = &pr_wantedup ; break ;
+        case 'N' : checkfields() ; fields[n++] = &pr_normallyup ; break ;
+        case 'r' : checkfields() ; fields[n++] = &pr_ready ; break ;
+        case 'p' : checkfields() ; fields[n++] = &pr_pid ; break ;
+        case 'e' : checkfields() ; fields[n++] = &pr_exitcode ; break ;
+        case 's' : checkfields() ; fields[n++] = &pr_signal ; break ;
+        case 't' : checkfields() ; fields[n++] = &pr_upseconds ; break ;
+        default : dieusage() ;
+      }
+    }
+    argc -= l.ind ; argv += l.ind ;
+  }
+  if (!argc) dieusage() ;
+  fields[n] = 0 ;
+
+  {
+    int r = s6_svc_ok(argv[0]) ;
+    if (r < 0) strerr_diefu2sys(111, "check ", argv[0]) ;
+    if (!r) strerr_diefu3x(1, "read status for ", argv[0], ": s6-supervise not running") ;
+  }
+  if (!s6_svstatus_read(argv[0], &status))
+    strerr_diefu2sys(111, "read status for ", argv[0]) ;
+
+  tain_now_g() ;
+  if (tain_future(&status.stamp)) tain_copynow(&status.stamp) ;
+
+  {
+    size_t dirlen = strlen(*argv) ;
+    char fn[dirlen + 6] ;
+    memcpy(fn, *argv, dirlen) ;
+    memcpy(fn + dirlen, "/down", 6) ;
+    if (access(fn, F_OK) < 0)
+      if (errno != ENOENT) strerr_diefu2sys(111, "access ", fn) ;
+      else normallyup = 1 ;
+    else normallyup = 0 ;
+  }
+
+  if (!n) legacy(&status, flagnum) ;
+  else
+  {
+    unsigned int i = 0 ;
+    for (; fields[i] ; i++)
+    {
+      (*fields[i])(buffer_1small, &status) ;
+      buffer_putsnoflush(buffer_1small, " ") ;
+    }
+    buffer_unput(buffer_1small, 1) ;
+  }
+
   if (buffer_putflush(buffer_1small, "\n", 1) < 0)
     strerr_diefu1sys(111, "write to stdout") ;
   return 0 ;
diff --git a/src/supervision/s6_svlisten_loop.c b/src/supervision/s6_svlisten_loop.c
index 942abf0..d2e776a 100644
--- a/src/supervision/s6_svlisten_loop.c
+++ b/src/supervision/s6_svlisten_loop.c
@@ -52,7 +52,7 @@ int s6_svlisten_loop (s6_svlisten_t *foo, int wantup, int wantready, int or, tai
   {
     int r = iopause_g(x, 1 + (spfd >= 0), deadline) ;
     if (r < 0) strerr_diefu1sys(111, "iopause") ;
-    else if (!r) strerr_dief1x(1, "timed out") ;
+    else if (!r) strerr_dief1x(99, "timed out") ;
     if (x[1].revents & IOPAUSE_READ) (*handler)() ;
     if (x[0].revents & IOPAUSE_READ)
     {