aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2026-01-12 22:27:18 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2026-01-12 22:27:18 +0000
commit993e827e1816ccdd0c64401aa8562932527ebf1b (patch)
treeba9064c3b7aad878f16baa1b691c1ca93dcf868c
parentadfd7c547c7366831b1e5daafce13520b4feca46 (diff)
downloads6-rc-993e827e1816ccdd0c64401aa8562932527ebf1b.tar.gz
Modernize s6-rc; add -E and -e options (with/out essentials)
-rw-r--r--doc/s6-rc.html13
-rw-r--r--src/s6-rc/s6-rc.c216
2 files changed, 136 insertions, 93 deletions
diff --git a/doc/s6-rc.html b/doc/s6-rc.html
index d5013c4..c852594 100644
--- a/doc/s6-rc.html
+++ b/doc/s6-rc.html
@@ -47,8 +47,8 @@ root privileges.
<pre>
s6-rc help
- s6-rc [ -l live ] [ -b ] [ -a ] [ -u | -d ] list <em>servicenames...</em>
- s6-rc [ -l live ] [ -b ] [ -a ] [ -u | -d ] listall <em>servicenames...</em>
+ s6-rc [ -l live ] [ -b ] [ -a ] [ -u | -d ] [ -E | -e ] list <em>servicenames...</em>
+ s6-rc [ -l live ] [ -b ] [ -a ] [ -u | -d ] [ -E | -e ] listall <em>servicenames...</em>
s6-rc [ -l live ] [ -b ] diff
s6-rc [ -l live ] [ -b ] [ -a ] [ -u | -d | -D ] [ -p ] [ -v <em>verbosity</em> ] [ -n <em>dryrunthrottle</em> ] [ -t timeout ] change [ <em>servicenames...</em> ]
</pre>
@@ -184,6 +184,12 @@ the list of currently active services. <tt>s6-rc -da list</tt>
will print the list of currently down services.
</p>
+<p>
+ If the <tt>-e</tt> option has been given, the services marked as
+essential (i.e. which have the <tt>flag-essential</tt> file in
+their source definition directories) will not be printed.
+</p>
+
<h3> s6-rc listall <em>servicenames...</em> </h3>
<ul>
@@ -196,6 +202,9 @@ called the <em>closed selection</em>. </li>
<li> It prints the closed selection to its standard output.
Note that the closed selection may be a very long list of services,
including the most basic ones. </li>
+ <li> If the <tt>-e</tt> option has been given, the services marked as
+essential (i.e. which have the <tt>flag-essential</tt> file in
+their source definition directories) will not be printed. </li>
</ul>
<h3> s6-rc diff </h3>
diff --git a/src/s6-rc/s6-rc.c b/src/s6-rc/s6-rc.c
index 8a3302e..1b753e9 100644
--- a/src/s6-rc/s6-rc.c
+++ b/src/s6-rc/s6-rc.c
@@ -6,19 +6,11 @@
#include <unistd.h>
#include <errno.h>
#include <signal.h>
+#include <stdlib.h>
#include <skalibs/posixplz.h>
-#include <skalibs/types.h>
-#include <skalibs/cdb.h>
-#include <skalibs/sgetopt.h>
-#include <skalibs/buffer.h>
-#include <skalibs/strerr.h>
-#include <skalibs/tai.h>
-#include <skalibs/sig.h>
-#include <skalibs/cspawn.h>
-#include <skalibs/djbunix.h>
-#include <skalibs/selfpipe.h>
-#include <skalibs/iopause.h>
+#include <skalibs/envexec.h>
+#include <skalibs/stddjb.h>
#include <skalibs/unix-transactional.h>
#include <s6/config.h>
@@ -27,7 +19,7 @@
#include <s6-rc/config.h>
#include <s6-rc/s6rc.h>
-#define USAGE "s6-rc [ -v verbosity ] [ -n dryrunthrottle ] [ -t timeout ] [ -l live ] [ -b ] [ -u | -d | -D ] [ -p ] [ -a ] help|list|listall|diff|start|stop|change [ servicenames... ]"
+#define USAGE "s6-rc [ -v verbosity ] [ -n dryrunthrottle ] [ -t timeout ] [ -l live ] [ -b ] [ -E | -e ] [ -u | -d | -D ] [ -p ] [ -a ] help|list|listall|diff|start|stop|change [ servicenames... ]"
#define dieusage() strerr_dieusage(100, USAGE)
typedef struct pidindex_s pidindex_t ;
@@ -37,6 +29,43 @@ struct pidindex_s
unsigned int i ;
} ;
+enum what_e
+{
+ WHAT_HELP,
+ WHAT_LIST,
+ WHAT_LISTALL,
+ WHAT_DIFF,
+ WHAT_CHANGE,
+ WHAT_START,
+ WHAT_STOP,
+} ;
+
+struct what_s
+{
+ char const *s ;
+ enum what_e e ;
+} ;
+
+enum golb_e
+{
+ GOLB_DOWN = 0x01,
+ GOLB_HIDEESSENTIALS = 0x02,
+ GOLB_PRUNE = 0x04,
+ GOLB_SELECTLIVE = 0x08,
+ GOLB_BLOCK = 0x10,
+ GOLB_NOLOCK = 0x80
+} ;
+
+enum gola_e
+{
+ GOLA_VERBOSITY,
+ GOLA_DRYRUN,
+ GOLA_TIMEOUT,
+ GOLA_LIVEDIR,
+ GOLA_N
+} ;
+
+static uint64_t wgolb = 0 ;
static unsigned int verbosity = 1 ;
static char const *live = S6RC_LIVEDIR ;
static size_t livelen ;
@@ -46,9 +75,8 @@ static s6rc_db_t *db ;
static unsigned int n ;
static unsigned char *state ;
static unsigned int *pendingdeps ;
-static tain deadline ;
+static tain deadline = TAIN_INFINITE_RELATIVE ;
static int lameduck = 0 ;
-static int forcestop = 0 ;
static char dryrun[UINT_FMT] = "" ;
static inline void announce (void)
@@ -66,13 +94,15 @@ static inline void announce (void)
static inline int print_services (void)
{
- unsigned int i = 0 ;
- for (; i < n ; i++)
+ for (unsigned int i = 0 ; i < n ; i++)
+ {
+ if (wgolb & GOLB_HIDEESSENTIALS && db->services[i].flags & S6RC_DB_FLAG_ESSENTIAL) continue ;
if (state[i] & 2)
{
if (buffer_puts(buffer_1, db->string + db->services[i].name) < 0
|| buffer_put(buffer_1, "\n", 1) < 0) goto err ;
}
+ }
if (!buffer_flush(buffer_1)) goto err ;
return 0 ;
@@ -218,13 +248,13 @@ static inline void success_longrun (unsigned int i, int h)
memcpy(fn + livelen + 13 + svdlen, "/down", 6) ;
if (h)
{
- if (unlink(fn) < 0 && verbosity)
+ if (unlink(fn) == -1 && verbosity)
strerr_warnwu2sys("unlink ", fn) ;
}
else
{
int fd = open_trunc(fn) ;
- if (fd < 0)
+ if (fd == -1)
{
if (verbosity)
strerr_warnwu2sys("touch ", fn) ;
@@ -263,7 +293,7 @@ static void examine (unsigned int i, int h)
strerr_warni4x("service ", name, ": already ", h ? "up" : "down") ;
broadcast_success(i, h) ;
}
- else if (!h && !forcestop && db->services[i].flags & S6RC_DB_FLAG_ESSENTIAL)
+ else if (!h && !(wgolb & GOLB_HIDEESSENTIALS) && db->services[i].flags & S6RC_DB_FLAG_ESSENTIAL)
{
if (verbosity)
strerr_warnw3x("service ", name, " is marked as essential, not stopping it") ;
@@ -427,29 +457,21 @@ static void invert_selection (void)
while (i--) state[i] ^= 2 ;
}
-static inline unsigned int lookup (char const *const *table, char const *command)
-{
- unsigned int i = 0 ;
- for (; table[i] ; i++) if (!strcmp(command, table[i])) break ;
- return i ;
-}
-
-static inline unsigned int parse_command (char const *command)
+static inline enum what_e parse_command (char const *command)
{
- static char const *const command_table[] =
+ static struct what_s const command_table[] =
{
- "help",
- "list",
- "listall",
- "diff",
- "change",
- "start",
- "stop",
- 0
+ { .s = "change", .e = WHAT_CHANGE },
+ { .s = "diff", .e = WHAT_DIFF },
+ { .s = "help", .e = WHAT_HELP },
+ { .s = "list", .e = WHAT_LIST },
+ { .s = "listall", .e = WHAT_LISTALL },
+ { .s = "start", .e = WHAT_START },
+ { .s = "stop", .e = WHAT_STOP },
} ;
- unsigned int i = lookup(command_table, command) ;
- if (!command_table[i]) dieusage() ;
- return i ;
+ struct what_s const *p = bsearch(command, command_table, sizeof(command_table)/sizeof(struct what_s), sizeof(struct what_s), &stringkey_bcmp) ;
+ if (!p) strerr_dief2x(100, "unknown command: ", command) ;
+ return p->e ;
}
static inline void print_help (void)
@@ -466,56 +488,66 @@ static inline void print_help (void)
int main (int argc, char const *const *argv)
{
- int up = 1, prune = 0, selectlive = 0, takelocks = 1, blocking = 0 ;
- unsigned int what ;
+ static gol_bool const rgolb[] =
+ {
+ { .so = 'u', .lo = "up", .clear = GOLB_DOWN, .set = 0 },
+ { .so = 'd', .lo = "down", .clear = 0, .set = GOLB_DOWN },
+ { .so = 'D', .lo = "all-down", .clear = 0, .set = GOLB_DOWN | GOLB_HIDEESSENTIALS },
+ { .so = 'p', .lo = "prune", .clear = 0, .set = GOLB_PRUNE },
+ { .so = 'a', .lo = "add", .clear = 0, .set = GOLB_SELECTLIVE },
+ { .so = 'b', .lo = "block", .clear = 0, .set = GOLB_BLOCK },
+ { .so = 'E', .lo = "with-essentials", .clear = GOLB_HIDEESSENTIALS, .set = 0 },
+ { .so = 'e', .lo = "without-essentials", .clear = 0, .set = GOLB_HIDEESSENTIALS },
+ { .so = 'X', .lo = "no-lock", .clear = 0, .set = GOLB_NOLOCK },
+ } ;
+ static gol_arg const rgola[] =
+ {
+ { .so = 'v', .lo = "verbosity", .i = GOLA_VERBOSITY },
+ { .so = 'n', .lo = "dry-run", .i = GOLA_DRYRUN },
+ { .so = 't', .lo = "timeout", .i = GOLA_TIMEOUT },
+ { .so = 'l', .lo = "livedir", .i = GOLA_LIVEDIR },
+ } ;
+ char const *wgola[GOLA_N] = { 0 } ;
+ enum what_e what ;
PROG = "s6-rc" ;
+
{
- unsigned int t = 0 ;
- subgetopt l = SUBGETOPT_ZERO ;
- for (;;)
- {
- int opt = subgetopt_r(argc, argv, "v:n:t:l:uDdpaXb", &l) ;
- if (opt == -1) break ;
- switch (opt)
- {
- case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ;
- case 'n' :
- {
- unsigned int d ;
- if (!uint0_scan(l.arg, &d)) dieusage() ;
- dryrun[uint_fmt(dryrun, d)] = 0 ;
- break ;
- }
- case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
- case 'l' : live = l.arg ; break ;
- case 'u' : up = 1 ; break ;
- case 'D' : forcestop = 1 ;
- case 'd' : up = 0 ; break ;
- case 'p' : prune = 1 ; break ;
- case 'a' : selectlive = 1 ; break ;
- case 'X' : takelocks = 0 ; break ;
- case 'b' : blocking = 1 ; break ;
- default : dieusage() ;
- }
- }
- argc -= l.ind ; argv += l.ind ;
+ unsigned int golc = GOL_main(argc, argv, rgolb, rgola, &wgolb, wgola) ;
+ argc -= golc ; argv += golc ;
+ }
+
+ if (wgola[GOLA_VERBOSITY] && !uint0_scan(wgola[GOLA_VERBOSITY], &verbosity))
+ strerr_dief1x(100, "verbosity must be an unsigned integer") ;
+ if (wgola[GOLA_DRYRUN])
+ {
+ unsigned int d ;
+ if (!uint0_scan(wgola[GOLA_DRYRUN], &d))
+ strerr_dief1x(100, "dry-run must be an unsigned integer") ;
+ dryrun[uint_fmt(dryrun, d)] = 0 ;
+ }
+ if (wgola[GOLA_TIMEOUT])
+ {
+ unsigned int t ;
+ if (!uint0_scan(wgola[GOLA_TIMEOUT], &t))
+ strerr_dief1x(100, "verbosity must be an unsigned integer") ;
if (t) tain_from_millisecs(&deadline, t) ;
- else deadline = tain_infinite_relative ;
}
+ if (wgola[GOLA_LIVEDIR]) live = wgola[GOLA_LIVEDIR] ;
+
if (!argc) dieusage() ;
what = parse_command(*argv++) ;
- if (!what)
+ if (what == WHAT_HELP)
{
print_help() ;
- return 0 ;
+ _exit(0) ;
}
- if (what == 5)
+ if (what == WHAT_START)
{
- what = 4 ; up = 1 ; prune = 0 ;
+ what = WHAT_CHANGE ; wgolb &= ~(GOLB_DOWN | GOLB_PRUNE) ;
}
- else if (what == 6)
+ else if (what == WHAT_STOP)
{
- what = 4 ; up = 0 ; prune = 0 ;
+ what = WHAT_CHANGE ; wgolb &= ~GOLB_PRUNE ; wgolb |= GOLB_DOWN ;
}
livelen = strlen(live) ;
@@ -531,10 +563,10 @@ int main (int argc, char const *const *argv)
/* Take the locks on live and compiled */
- if (takelocks)
+ if (!(wgolb & GOLB_NOLOCK))
{
int livelock, compiledlock ;
- if (!s6rc_lock(live, 1 + (what >= 4), &livelock, dbfn, 1, &compiledlock, blocking))
+ if (!s6rc_lock(live, 1 + (what >= 4), &livelock, dbfn, 1, &compiledlock, !!(wgolb & GOLB_BLOCK)))
strerr_diefu1sys(111, "take locks") ;
if (coe(livelock) < 0)
strerr_diefu3sys(111, "coe ", live, "/lock") ;
@@ -595,7 +627,7 @@ int main (int argc, char const *const *argv)
/* s6-rc diff */
- if (what == 3) return print_diff() ;
+ if (what == WHAT_DIFF) _exit(print_diff()) ;
/* Resolve the args and add them to the selection */
@@ -630,7 +662,7 @@ int main (int argc, char const *const *argv)
/* Add live state to selection */
- if (selectlive)
+ if (wgolb & GOLB_SELECTLIVE)
{
unsigned int i = n ;
while (i--) if (state[i] & 1) state[i] |= 2 ;
@@ -639,18 +671,18 @@ int main (int argc, char const *const *argv)
/* Print the selection before closure */
- if (what == 1)
+ if (what == WHAT_LIST)
{
- if (!up) invert_selection() ;
- return print_services() ;
+ if (wgolb & GOLB_DOWN) invert_selection() ;
+ _exit(print_services()) ;
}
- s6rc_graph_closure(db, state, 1, up) ;
+ s6rc_graph_closure(db, state, 1, !(wgolb & GOLB_DOWN)) ;
/* Print the selection after closure */
- if (what == 2) return print_services() ;
+ if (what == WHAT_LISTALL) _exit(print_services()) ;
tain_now_set_stopwatch_g() ;
tain_add_g(&deadline, &deadline) ;
@@ -658,7 +690,9 @@ int main (int argc, char const *const *argv)
/* Perform a state change */
- if (selfpipe_init() == -1) strerr_diefu1sys(111, "init selfpipe") ;
+ if (selfpipe_init() == -1)
+ strerr_diefu1sys(111, "init selfpipe") ;
+
{
sigset_t set ;
sigemptyset(&set) ;
@@ -669,16 +703,16 @@ int main (int argc, char const *const *argv)
strerr_diefu1sys(111, "trap signals") ;
}
- if (prune)
+ if (wgolb & GOLB_PRUNE)
{
int r ;
- if (up) invert_selection() ;
+ if (!(wgolb & GOLB_DOWN)) invert_selection() ;
r = doit(0) ;
if (r) return r ;
invert_selection() ;
- return doit(1) ;
+ _exit(doit(1)) ;
}
- else return doit(up) ;
+ else _exit(doit(!(wgolb & GOLB_DOWN))) ;
}
}
}