aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2026-01-24 08:12:42 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2026-01-24 08:12:42 +0000
commitdbaaee871996024e083bbdb83de85f8c287ee999 (patch)
tree4dc7ac412d4969de71212c95e008d4c374a180b4
parent38e8fd341f427a1395c1d5869d69eb67a3c24698 (diff)
downloads6-rc-dbaaee871996024e083bbdb83de85f8c287ee999.tar.gz
Support bringing down essential services in s6-rc-update
Also adjust verbosity of s6-rc-compile
-rw-r--r--doc/s6-rc-update.html40
-rw-r--r--src/s6-rc/s6-rc-compile.c3
-rw-r--r--src/s6-rc/s6-rc-update.c101
3 files changed, 90 insertions, 54 deletions
diff --git a/doc/s6-rc-update.html b/doc/s6-rc-update.html
index d0182c2..b3ad96a 100644
--- a/doc/s6-rc-update.html
+++ b/doc/s6-rc-update.html
@@ -75,34 +75,46 @@ live compiled service database. </li>
<h2> Options </h2>
+<dl>
<ul>
- <li> <tt>-n</tt>&nbsp;: dry run. s6-rc-update will compute the service
+ <dt> -n, --dry-run </dt>
+ <dd> Dry run. s6-rc-update will compute the service
transitions, and print the <a href="s6-rc.html">s6-rc</a> command lines
it would execute to perform those transitions. It will not actually
-run them or modify the live database. </li>
- <li> <tt>-v&nbsp;<em>verbosity</em></tt>&nbsp;: be more or less
+run them or modify the live database. </dd>
+ <dt> -v <em>verbosity</em>, --verbosity=<em>verbosity</em> </dt>
+ <dd> Be more or less
verbose. Default is 1: warning and error messages will be printed to
stderr. 0 silences warnings. 2 adds a bit more information about
-what s6-rc-update is doing. 3 or more is heavy debug output. </li>
- <li> <tt>-t&nbsp;<em>timeout</em></tt>&nbsp;: if s6-rc-update cannot
+what s6-rc-update is doing. 3 or more is heavy debug output. </dd>
+ <dt> -t <em>timeout</em>, --timeout=<em>timeout</em> </dt>
+ <dd> If s6-rc-update cannot
perform its job within <em>timeout</em> milliseconds, it will exit.
The default is 0, meaning infinite (no timeout). Be aware that timing
out and exiting may leave the live database in an inconsistent state,
-so use of this option is not recommended. </li>
- <li> <tt>-l&nbsp;<em>live</em></tt>&nbsp;: look for the
-live state in <em>live</em>. It must be an absolute path.
+so use of this option is not recommended. </dd>
+ <dt> -l <em>live</em>, --livedir=<em>live</em> </dt>
+ <dd> Look for the live state in <em>live</em>. It must be an absolute path.
Default is <tt>/run/s6-rc</tt>.
The default can be changed at compile-time by giving the
-<tt>--livedir=<em>live</em></tt> option to <tt>./configure</tt>. </li>
- <li> <tt>-f&nbsp;<em>convfile</em></tt>&nbsp;: use the conversion
+<tt>--livedir=<em>live</em></tt> option to <tt>./configure</tt>. </dd>
+ <dt> -f <em>convfile</em>, --conversion-file=<em>convfile</em> </dt>
+ <dd> Use the conversion
file located at <em>convfile</em>. Default is <tt>/dev/null</tt>,
-meaning no special instructions. </li>
- <li> <tt>-b</tt>&nbsp;: blocking lock. If the database is currently
+meaning no special instructions. </dd>
+ <dt> -b, --block </dt>
+ <dd> Blocking lock. If the database is currently
being used by another program, s6-rc-update will wait until that
other program has released its lock on the database, then proceed.
By default, s6-rc-update fails with an error message if the database
-is currently in use. </li>
-</ul>
+is currently in use. </dd>
+ <dt> -E, --no-force-essentials </dt>
+ <dd> If essential services are scheduled to be stopped for the transition,
+ignore them, i.e. keep them alive. This is the default. </dd>
+ <dt> -e, --force-essentials </dt>
+ <dd> If essential services are scheduled to be stopped for the transition,
+stop them just like any other service. </dd>
+</dl>
<h2> Transition details </h2>
diff --git a/src/s6-rc/s6-rc-compile.c b/src/s6-rc/s6-rc-compile.c
index 6bc59ed..b9b6955 100644
--- a/src/s6-rc/s6-rc-compile.c
+++ b/src/s6-rc/s6-rc-compile.c
@@ -545,7 +545,7 @@ static inline void add_bundle (before_t *be, int dfd, char const *srcdir, char c
static inline void add_source (before_t *be, int dfd, char const *srcdir, char const *name)
{
- if (verbosity >= 2) strerr_warni4x("parsing ", srcdir, "/", name) ;
+ if (verbosity >= 3) strerr_warni4x("parsing ", srcdir, "/", name) ;
switch (type_check(dfd))
{
case 0 : strerr_dief6x(1, "invalid ", srcdir, "/", name, "/type", ": must be oneshot, longrun, or bundle") ;
@@ -562,6 +562,7 @@ static inline void add_sources (before_t *be, char const *srcdir, stralloc *sa)
int fdsrc ;
DIR *dir = opendir(srcdir) ;
if (!dir) strerr_diefu2sys(111, "opendir ", srcdir) ;
+ if (verbosity >= 2) strerr_warni("adding sources from ", srcdir) ;
fdsrc = dir_fd(dir) ;
for (;;)
{
diff --git a/src/s6-rc/s6-rc-update.c b/src/s6-rc/s6-rc-update.c
index 82f2a6e..0b7a053 100644
--- a/src/s6-rc/s6-rc-update.c
+++ b/src/s6-rc/s6-rc-update.c
@@ -13,15 +13,13 @@
#include <skalibs/types.h>
#include <skalibs/allreadwrite.h>
#include <skalibs/buffer.h>
-#include <skalibs/strerr.h>
-#include <skalibs/sgetopt.h>
+#include <skalibs/envexec.h>
#include <skalibs/bitarray.h>
#include <skalibs/cdb.h>
#include <skalibs/stralloc.h>
#include <skalibs/tai.h>
#include <skalibs/cspawn.h>
#include <skalibs/djbunix.h>
-#include <skalibs/exec.h>
#include <skalibs/skamisc.h>
#include <skalibs/unix-transactional.h>
@@ -37,7 +35,7 @@
#include <skalibs/posixishard.h>
-#define USAGE "s6-rc-update [ -n ] [ -v verbosity ] [ -t timeout ] [ -l live ] [ -f conversion_file ] [ -b ] newdb"
+#define USAGE "s6-rc-update [ -n ] [ -v verbosity ] [ -t timeout ] [ -l live ] [ -f conversion_file ] [ -E | -e ] [ -b ] newdb"
#define dieusage() strerr_dieusage(100, USAGE)
#define dienomem() strerr_diefu1sys(111, "build string") ;
@@ -560,36 +558,61 @@ static unsigned int want_count (unsigned char const *state, unsigned int n)
return count ;
}
+enum golb_e
+{
+ GOLB_DRYRUN = 0x01,
+ GOLB_BLOCK = 0x02,
+ GOLB_FORCEESSENTIALS = 0x04,
+} ;
+
+enum gola_e
+{
+ GOLA_VERBOSITY,
+ GOLA_TIMEOUT,
+ GOLA_LIVEDIR,
+ GOLA_CONVFILE,
+ GOLA_N
+} ;
+
int main (int argc, char const *const *argv, char const *const *envp)
{
- char const *convfile = "/dev/null" ;
- tain deadline ;
- int dryrun = 0 ;
- int blocking = 0 ;
+ static gol_bool const rgolb[] =
+ {
+ { .so = 'n', .lo = "dry-run", .clear = 0, .set = GOLB_DRYRUN },
+ { .so = 'b', .lo = "block", .clear = 0, .set = GOLB_BLOCK },
+ { .so = 'E', .lo = "no-force-essentials", .clear = GOLB_FORCEESSENTIALS, .set = 0 },
+ { .so = 'e', .lo = "force-essentials", .clear = 0, .set = GOLB_FORCEESSENTIALS },
+ } ;
+ static gol_arg const rgola[] =
+ {
+ { .so = 'v', .lo = "verbosity", .i = GOLA_VERBOSITY },
+ { .so = 't', .lo = "timeout", .i = GOLA_TIMEOUT },
+ { .so = 'l', .lo = "livedir", .i = GOLA_LIVEDIR },
+ { .so = 'f', .lo = "conversion-file", .i = GOLA_CONVFILE },
+ } ;
+ uint64_t wgolb = 0 ;
+ char const *wgola[GOLA_N] = { 0 } ;
+ tain deadline = TAIN_INFINITE_RELATIVE ;
PROG = "s6-rc-update" ;
+ wgola[GOLA_CONVFILE] = "/dev/null" ;
+
{
- unsigned int t = 0 ;
- subgetopt l = SUBGETOPT_ZERO ;
- for (;;)
- {
- int opt = subgetopt_r(argc, argv, "v:t:nl:f:b", &l) ;
- if (opt == -1) break ;
- switch (opt)
- {
- case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ;
- case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
- case 'n' : dryrun = 1 ; break ;
- case 'l' : live = l.arg ; break ;
- case 'f' : convfile = l.arg ; 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 (!argc) dieusage() ;
+ }
+
+ if (wgola[GOLA_VERBOSITY] && !uint0_scan(wgola[GOLA_VERBOSITY], &verbosity))
+ strerr_dief1x(100, "verbosity must be an unsigned integer") ;
+ 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 (!argc) dieusage() ;
+ if (wgola[GOLA_LIVEDIR]) live = wgola[GOLA_LIVEDIR] ;
+
if (live[0] != '/')
strerr_dief2x(100, live, " is not an absolute path") ;
if (argv[0][0] != '/')
@@ -615,9 +638,9 @@ int main (int argc, char const *const *argv, char const *const *envp)
memcpy(dbfn, live, livelen) ;
memcpy(dbfn + livelen, "/compiled", 10) ;
- if (!s6rc_lock(live, 2, &livelock, dbfn, 1, &oldlock, blocking))
+ if (!s6rc_lock(live, 2, &livelock, dbfn, 1, &oldlock, !!(wgolb & GOLB_BLOCK)))
strerr_diefu4sys(111, "take lock on ", live, " and ", dbfn) ;
- if (!s6rc_lock(0, 0, 0, argv[0], 1, &newlock, blocking))
+ if (!s6rc_lock(0, 0, 0, argv[0], 1, &newlock, !!(wgolb & GOLB_BLOCK)))
strerr_diefu2sys(111, "take lock on ", argv[0]) ;
@@ -705,7 +728,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
/* Read the conversion file and compute what to do */
if (verbosity >= 2) strerr_warni1x("computing state adjustments") ;
- compute_transitions(convfile, oldstate, fdoldc, &olddb, newstate, invimage, fdnewc, argv[0], &newdb, &sa) ;
+ compute_transitions(wgola[GOLA_CONVFILE], oldstate, fdoldc, &olddb, newstate, invimage, fdnewc, argv[0], &newdb, &sa) ;
tain_now_g() ;
if (!tain_future(&deadline)) strerr_dief1x(10, "timed out while computing state adjutments") ;
@@ -713,14 +736,14 @@ int main (int argc, char const *const *argv, char const *const *envp)
/* Down transition */
{
- char const *newargv[12 + (dryrun * 4) + want_count(oldstate, oldn)] ;
+ char const *newargv[12 + (!!(wgolb & GOLB_DRYRUN) * 4) + want_count(oldstate, oldn)] ;
unsigned int m = 0, i = oldn ;
int wstat ;
char vfmt[UINT_FMT] ;
char tfmt[UINT_FMT] ;
vfmt[uint_fmt(vfmt, verbosity)] = 0 ;
fill_tfmt(tfmt, &deadline) ;
- if (dryrun)
+ if (wgolb & GOLB_DRYRUN)
{
newargv[m++] = S6RC_BINPREFIX "s6-rc-dryrun" ;
newargv[m++] = "-v" ;
@@ -735,8 +758,8 @@ int main (int argc, char const *const *argv, char const *const *envp)
newargv[m++] = tfmt ;
newargv[m++] = "-l" ;
newargv[m++] = live ;
- if (!dryrun) newargv[m++] = "--no-lock" ;
- newargv[m++] = "-d" ;
+ if (!(wgolb & GOLB_DRYRUN)) newargv[m++] = "--no-lock" ;
+ newargv[m++] = wgolb & GOLB_FORCEESSENTIALS ? "-D" : "-d" ;
newargv[m++] = "--" ;
newargv[m++] = "change" ;
while (i--) if (oldstate[i] & 2)
@@ -756,7 +779,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
}
}
- if (!dryrun)
+ if (!(wgolb & GOLB_DRYRUN))
{
/* Update state and service directories */
@@ -798,13 +821,13 @@ int main (int argc, char const *const *argv, char const *const *envp)
/* Up transition */
{
- char const *newargv[12 + (dryrun * 4) + want_count(newstate, newn)] ;
+ char const *newargv[12 + (!!(wgolb & GOLB_DRYRUN) * 4) + want_count(newstate, newn)] ;
unsigned int m = 0, i = newn ;
char vfmt[UINT_FMT] ;
char tfmt[UINT_FMT] ;
vfmt[uint_fmt(vfmt, verbosity)] = 0 ;
fill_tfmt(tfmt, &deadline) ;
- if (dryrun)
+ if (wgolb & GOLB_DRYRUN)
{
newargv[m++] = S6RC_BINPREFIX "s6-rc-dryrun" ;
newargv[m++] = "-v" ;
@@ -819,7 +842,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
newargv[m++] = tfmt ;
newargv[m++] = "-l" ;
newargv[m++] = live ;
- if (!dryrun) newargv[m++] = "--no-lock" ;
+ if (!(wgolb & GOLB_DRYRUN)) newargv[m++] = "--no-lock" ;
newargv[m++] = "-u" ;
newargv[m++] = "--" ;
newargv[m++] = "change" ;