From 9a669c4b3973118dfcce2a2b1fb4babd0aaa6af7 Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Sat, 25 Mar 2017 11:25:15 +0000 Subject: Stop using flagwant; new s6-svstat API; s6-svwait's timeout exitcode is now 99 --- doc/s6-svlisten.html | 2 +- doc/s6-svlisten1.html | 2 +- doc/s6-svstat.html | 93 ++++++++++++- doc/s6-svwait.html | 2 +- src/include/s6/s6-supervise.h | 2 +- src/supervision/s6-supervise.c | 13 +- src/supervision/s6-svstat.c | 261 +++++++++++++++++++++++++++++++------ src/supervision/s6_svlisten_loop.c | 2 +- 8 files changed, 319 insertions(+), 58 deletions(-) diff --git a/doc/s6-svlisten.html b/doc/s6-svlisten.html index e3d8044..0a3f427 100644 --- a/doc/s6-svlisten.html +++ b/doc/s6-svlisten.html @@ -85,7 +85,7 @@ given services comes up or down. given services come up or down. This is the default.
  • -t timeout : if the requested events have not happened after timeout milliseconds, s6-svlisten will print a message -to stderr and exit 1. By default, timeout is 0, which means no time +to stderr and exit 99. By default, timeout is 0, which means no time limit.
  • diff --git a/doc/s6-svlisten1.html b/doc/s6-svlisten1.html index be64e4f..762c3ff 100644 --- a/doc/s6-svlisten1.html +++ b/doc/s6-svlisten1.html @@ -68,7 +68,7 @@ the service has been started or restarted and has notified readiness.
  • -t timeout : if the requested event has not happened after timeout milliseconds, s6-svlisten1 will print a message -to stderr and exit 1. By default, timeout is 0, which means no time +to stderr and exit 99. By default, timeout is 0, which means no time limit.
  • diff --git a/doc/s6-svstat.html b/doc/s6-svstat.html index bb3d66b..afa6d39 100644 --- a/doc/s6-svstat.html +++ b/doc/s6-svstat.html @@ -26,13 +26,22 @@ monitored by s6-supervise.

    Interface

    -     s6-svstat [ -n ] servicedir
    +     s6-svstat [ -uwNrpest | -o up,wantedup,normallyup,ready,paused,pid,exitcode,signal,signum,updownsince,readysince,updownfor,readyfor ] [ -n ] servicedir
     

    s6-svstat gives information about the process being monitored at the servicedir service directory, then -exits 0. The information includes the following: +exits 0. +

    + +

    + When s6-svstat is invoked without options, or with only the -n option, +it prints a human-readable summary of all the +available information on the service. In this case, the -n option +instructs it to print a signal number (instead of a signal name) if the +supervised process was killed by a signal. The summary includes the +following data:

    +

    + When s6-svstat is invoked with one or several options other than -n, +it outputs programmatically parsable information instead. The output is a series of +space-separated values, one value per requested field. The valid options +are as follows. +

    +

    Options

    Exit codes

    @@ -70,5 +131,23 @@ printed instead.
  • 111: system call failed
  • +

    Examples

    + + + diff --git a/doc/s6-svwait.html b/doc/s6-svwait.html index c3df0fa..681dd8f 100644 --- a/doc/s6-svwait.html +++ b/doc/s6-svwait.html @@ -64,7 +64,7 @@ given services comes up or down. given services come up or down. This is the default.
  • -t timeout : if the requested events have not happened after timeout milliseconds, s6-svwait will print a message -to stderr and exit 1. By default, timeout is 0, which means no time +to stderr and exit 99. By default, timeout is 0, which means no time limit.
  • diff --git a/src/include/s6/s6-supervise.h b/src/include/s6/s6-supervise.h index 7fc70d7..f0b08e7 100644 --- a/src/include/s6/s6-supervise.h +++ b/src/include/s6/s6-supervise.h @@ -26,7 +26,7 @@ struct s6_svstatus_s int wstat ; unsigned int flagpaused : 1 ; unsigned int flagfinishing : 1 ; - unsigned int flagwant : 1 ; + unsigned int flagwant : 1 ; /* unused */ unsigned int flagwantup : 1 ; unsigned int flagready : 1 ; } ; 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 #include #include +#include #include #include #include @@ -14,53 +15,169 @@ #include #include -#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) { -- cgit v1.2.3