aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2026-05-29 23:48:34 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2026-05-29 23:48:34 +0000
commit241d2079a25d77e090beb0b767984928dbbc8cd6 (patch)
treefa87dee097e6b26b90c7c1a10c2694d947794640
parenta10457d33ca56fba642bb19d6a21ef0390ef36af (diff)
downloads6-rc-241d2079a25d77e090beb0b767984928dbbc8cd6.tar.gz
Prepare for 0.6.1.2; make s6-rc-init idempotent and more resilient
-rw-r--r--INSTALL6
-rw-r--r--NEWS7
-rw-r--r--doc/index.html10
-rw-r--r--doc/s6-rc-init.html3
-rw-r--r--doc/upgrade.html11
-rw-r--r--package/deps-build6
-rw-r--r--package/info2
-rw-r--r--src/s6-rc/s6-rc-init.c157
8 files changed, 158 insertions, 44 deletions
diff --git a/INSTALL b/INSTALL
index 7581084..90b918f 100644
--- a/INSTALL
+++ b/INSTALL
@@ -6,9 +6,9 @@ Build Instructions
- A POSIX-compliant C development environment
- GNU make version 3.81 or later
- - skalibs version 2.15.0.0 or later: https://skarnet.org/software/skalibs/
- - execline version 2.9.9.1 or later: https://skarnet.org/software/execline/
- - s6 version 2.15.0.0 or later: https://skarnet.org/software/s6/
+ - skalibs version 2.15.0.1 or later: https://skarnet.org/software/skalibs/
+ - execline version 2.9.9.2 or later: https://skarnet.org/software/execline/
+ - s6 version 2.15.0.1 or later: https://skarnet.org/software/s6/
This software will run on any operating system that implements
POSIX.1-2024, available at:
diff --git a/NEWS b/NEWS
index e387229..024e549 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,12 @@
Changelog for s6-rc.
+In 0.6.1.2
+----------
+
+ - Bugfixes.
+ - s6-rc-init is now idempotent and behaves better in pathological situations
+
+
In 0.6.1.1
----------
diff --git a/doc/index.html b/doc/index.html
index f643e75..ed486bf 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -50,12 +50,12 @@ scripts are also run in a controlled environment.
<li> A POSIX-compliant system with a standard C development environment </li>
<li> GNU make, version 3.81 or later </li>
<li> <a href="//skarnet.org/software/skalibs/">skalibs</a> version
-2.15.0.0 or later. It's a build-time requirement. It's also a run-time
+2.15.0.1 or later. It's a build-time requirement. It's also a run-time
requirement if you link against the shared version of the skalibs library. </li>
<li> <a href="//skarnet.org/software/execline/">execline</a> version
-2.9.9.1 or later. It's a build-time <em>and</em> run-time requirement. </li>
+2.9.9.2 or later. It's a build-time <em>and</em> run-time requirement. </li>
<li> <a href="//skarnet.org/software/s6/">s6</a> version
-2.15.0.0 or later. It's a build-time <em>and</em> run-time requirement. </li>
+2.15.0.1 or later. It's a build-time <em>and</em> run-time requirement. </li>
</ul>
<h3> Licensing </h3>
@@ -69,8 +69,8 @@ requirement if you link against the shared version of the skalibs library. </li>
<ul>
<li> The current released version of s6-rc is
-<a href="s6-rc-0.6.1.1.tar.gz">0.6.1.1</a>.
-You can access its checksum <a href="s6-rc-0.6.1.1.tar.gz.sha256">here</a>. </li>
+<a href="s6-rc-0.6.1.2.tar.gz">0.6.1.2</a>.
+You can access its checksum <a href="s6-rc-0.6.1.2.tar.gz.sha256">here</a>. </li>
<li> Alternatively, you can checkout a copy of the
<a href="//git.skarnet.org/cgi-bin/cgit.cgi/s6-rc/">s6-rc
git repository</a>:
diff --git a/doc/s6-rc-init.html b/doc/s6-rc-init.html
index 1928534..524057d 100644
--- a/doc/s6-rc-init.html
+++ b/doc/s6-rc-init.html
@@ -148,6 +148,9 @@ without having to change the s6-rc-init invocation in boot scripts. </li>
"live compiled database", and must not be tampered with or deleted.
The only way to free it for deletion is to replace it with another
database, via a call to <a href="s6-rc-update.html">s6-rc-update</a>. </li>
+ <li> <tt>s6-rc-init</tt> is not supposed to be called more than once.
+But if a live s6-rc directory happens to exist, it will attempt to
+reuse it. </li>
</ul>
</body>
diff --git a/doc/upgrade.html b/doc/upgrade.html
index c854a44..d63dc34 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -31,6 +31,17 @@ minor and bugfix version changes.
<h1> What has changed in s6-rc </h1>
+<h2> in 0.6.1.2 </h2>
+
+<ul>
+ <li> <a href="//skarnet.org/software/skalibs/">skalibs</a>
+dependency bumped to 2.15.0.1. </li>
+ <li> <a href="//skarnet.org/software/execline/">execline</a>
+dependency bumped to 2.9.9.2. </li>
+ <li> <a href="//skarnet.org/software/s6/">s6</a>
+dependency bumped to 2.15.0.1. </li>
+</ul>
+
<h2> in 0.6.1.1 </h2>
<ul>
diff --git a/package/deps-build b/package/deps-build
index f7f2355..842d3a2 100644
--- a/package/deps-build
+++ b/package/deps-build
@@ -1,3 +1,3 @@
-true true /package/prog/skalibs 2.15.0.0 libskarnet
-true false /package/admin/execline 2.9.9.1 libexecline
-true true /package/admin/s6 2.15.0.0 libs6
+true true /package/prog/skalibs 2.15.0.1 libskarnet
+true false /package/admin/execline 2.9.9.2 libexecline
+true true /package/admin/s6 2.15.0.1 libs6
diff --git a/package/info b/package/info
index 854e7b3..bc728bb 100644
--- a/package/info
+++ b/package/info
@@ -1,4 +1,4 @@
package=s6-rc
-version=0.6.1.1
+version=0.6.1.2
category=admin
package_macro_name=S6RC
diff --git a/src/s6-rc/s6-rc-init.c b/src/s6-rc/s6-rc-init.c
index a83db2a..b1a9624 100644
--- a/src/s6-rc/s6-rc-init.c
+++ b/src/s6-rc/s6-rc-init.c
@@ -1,5 +1,7 @@
/* ISC license. */
+#include <skalibs/bsdsnowflake.h>
+
#include <string.h>
#include <unistd.h>
#include <errno.h>
@@ -10,9 +12,11 @@
#include <skalibs/types.h>
#include <skalibs/prog.h>
#include <skalibs/gol.h>
+#include <skalibs/stat.h>
#include <skalibs/strerr.h>
#include <skalibs/stralloc.h>
#include <skalibs/tai.h>
+#include <skalibs/direntry.h>
#include <skalibs/djbunix.h>
#include <skalibs/unix-transactional.h>
@@ -22,6 +26,7 @@
#define USAGE "s6-rc-init [ -c bootdb ] [ -l livedir ] [ -p prefix ] [ -t timeout ] [ -d ] [ -b ] scandir"
#define dieusage() strerr_dieusage(100, USAGE)
+#define dienomem() strerr_diefusys(111, "stralloc_catb")
enum golb_e
{
@@ -45,7 +50,7 @@ static void cleanup (stralloc *sa)
errno = e ;
}
-static void check_scandir (char const *sdir)
+static inline void check_scandir (char const *sdir)
{
int r = s6_svc_writectl(sdir, S6_SVSCAN_CTLDIR, "", 0) ;
if (r == -1) strerr_diefusys(111, "check ", sdir) ;
@@ -53,28 +58,95 @@ static void check_scandir (char const *sdir)
if (!r) strerr_dief(100, "s6-svscan is not running on ", sdir) ;
}
-static int check_existing_s6rc (char const *sdir, char const *prefix, stralloc *sa)
+static int check_livedir (char const *live, char const *sdir, char const *prefix, char const *bootdb, stralloc *sa)
{
- size_t sdirlen = strlen(sdir) ;
+ size_t llen = strlen(live) ;
size_t plen = strlen(prefix) ;
- size_t start = sa->len ;
+ size_t w ;
int r ;
- char fn[sdirlen + plen + S6RC_FDHOLDER_LEN + 2] ;
- memcpy(fn, sdir, sdirlen) ;
- fn[sdirlen] = '/' ;
- memcpy(fn + sdirlen + 1, prefix, plen) ;
- memcpy(fn + sdirlen + 1 + plen, S6RC_FDHOLDER, S6RC_FDHOLDER_LEN + 1) ;
+ char fn[llen + 14 + S6RC_FDHOLDER_LEN] ;
+ char pr[plen + 1] ;
+
+ memcpy(fn, live, llen) ;
+ memcpy(fn + llen, "/servicedirs/" S6RC_FDHOLDER, 14 + S6RC_FDHOLDER_LEN) ;
r = s6_svc_ok(fn) ;
- if (r == -1) strerr_diefusys(111, "check the existence of service ", fn) ;
- if (!r) return 0 ;
- if (sarealpath(sa, fn) == -1) strerr_diefusys(111, "realpath ", fn) ;
- if (sa->len - start < 14 + S6RC_FDHOLDER_LEN || memcmp(sa->s + sa->len - S6RC_FDHOLDER_LEN - 14, "/servicedirs/" S6RC_FDHOLDER, 14 + S6RC_FDHOLDER_LEN))
- strerr_dief(111, "service ", fn, " exists but is not part of an s6-rc database") ;
- sa->s[sa->len - S6RC_FDHOLDER_LEN - 14] = 0 ;
+ if (r == -1)
+ {
+ if (errno != ENOENT) strerr_diefusys(111, "check ", fn) ;
+ fn[llen] = 0 ;
+ strerr_warnw("directory ", fn, " looks like a live directory but has no ", "s6rc-fdholder service") ;
+ return 0 ;
+ }
+ else if (!r)
+ {
+ fn[llen] = 0 ;
+ strerr_warnw("directory ", fn, " looks like a live directory but has no ", "supervisors running") ;
+ return 0 ;
+ }
+
+ memcpy(fn + llen, "/scandir", 9) ;
+ if (sareadlink(sa, fn) == -1 || !stralloc_0(sa)) strerr_diefusys(111, "readlink ", fn) ;
+ sa->len = 0 ;
+ if (strcmp(sa->s, sdir))
+ {
+ fn[llen] = 0 ;
+ strerr_dief(102, "existing livedir at ", fn, " uses scandir at ", sa->s, " rather than ", sdir) ;
+ }
+
+ memcpy(fn + llen, "/prefix", 8) ;
+ w = openreadnclose(fn, pr, plen+1) ;
+ if (w == -1) strerr_diefusys(111, "read ", fn) ;
+ if (w != plen || strncmp(pr, prefix, plen))
+ {
+ fn[llen] = 0 ;
+ strerr_dief(102, "prefix mismatch with the existing livedir at ", fn) ;
+ }
+
+ memcpy(fn + llen, "/compiled", 10) ;
+ if (sareadlink(sa, fn) == -1 || !stralloc_0(sa)) strerr_diefusys(111, "readlink ", fn) ;
+ sa->len = 0 ;
+ if (strcmp(sa->s, bootdb))
+ {
+ fn[llen] = 0 ;
+ strerr_dief(102, "existing livedir at ", fn, " uses bootdb at ", sa->s, " rather than ", bootdb) ;
+ }
return 1 ;
}
+static inline size_t find_livedir (char const *live, size_t llen, size_t lpos, char const *sdir, char const *prefix, char const *bootdb, stralloc *sa)
+{
+ DIR *dir ;
+ char fn[llen + 7] ;
+ memcpy(fn, live, llen) ;
+ memcpy(fn + llen, ":s6-rc-", 7) ;
+ fn[lpos] = 0 ;
+ dir = opendir(fn) ;
+ if (!dir) strerr_diefusys(111, "opendir ", fn) ;
+ for (;;)
+ {
+ direntry *d ;
+ errno = 0 ;
+ d = readdir(dir) ;
+ if (!d) break ;
+ if (d->d_name[0] == '.') continue ;
+ if (strncmp(d->d_name, fn + lpos + 1, llen + 6 - lpos)) continue ;
+ size_t sublen = strlen(d->d_name) ;
+ char subfn[lpos + sublen + 2] ;
+ memcpy(subfn, live, lpos) ;
+ subfn[lpos] = '/' ;
+ memcpy(subfn + lpos + 1, d->d_name, sublen + 1) ;
+ if (check_livedir(subfn, sdir, prefix, bootdb, sa))
+ {
+ dir_close(dir) ;
+ if (!stralloc_catb(sa, subfn, lpos + sublen + 2)) dienomem() ;
+ return 1 ;
+ }
+ }
+ if (errno) strerr_diefusys(111, "readdir ", sa->s) ;
+ dir_close(dir) ;
+ return 0 ;
+}
int main (int argc, char const *const *argv)
{
@@ -95,6 +167,7 @@ int main (int argc, char const *const *argv)
tain deadline = TAIN_INFINITE_RELATIVE ;
stralloc sa = STRALLOC_ZERO ;
size_t dirlen ;
+ char *x ;
uint64_t wgolb = 0 ;
char const *wgola[GOLA_N] = { [GOLA_BOOTDB] = S6RC_BOOTDB, [GOLA_LIVEDIR] = S6RC_LIVEDIR, [GOLA_PREFIX] = "", [GOLA_TIMEOUT] = 0, } ;
unsigned int golc ;
@@ -104,6 +177,7 @@ int main (int argc, char const *const *argv)
argc -= golc ; argv += golc ;
if (!argc) dieusage() ;
+ if (argv[0][0] != '/') strerr_dief(100, "scandir", " must be an absolute path") ;
if (wgola[GOLA_TIMEOUT])
{
unsigned int t = 0 ;
@@ -111,28 +185,47 @@ int main (int argc, char const *const *argv)
strerr_dief(100, "timeout", " must be an unsigned integer") ;
if (t) tain_from_millisecs(&deadline, t) ;
}
-
- if (!(wgolb & GOLB_DEREF) && wgola[GOLA_BOOTDB][0] != '/')
- strerr_dief(100, "bootdb", " must be an absolute path") ;
- if (wgola[GOLA_LIVEDIR][0] != '/')
- strerr_dief(100, "livedir", " must be an absolute path") ;
- if (argv[0][0] != '/')
- strerr_dief(100, "scandir", " must be an absolute path") ;
+ if (wgolb & GOLB_DEREF)
+ {
+ x = realpath(wgola[GOLA_BOOTDB], 0) ;
+ if (!x) strerr_diefusys(111, "realpath ", wgola[GOLA_BOOTDB]) ;
+ wgola[GOLA_BOOTDB] = x ;
+ }
+ else if (wgola[GOLA_BOOTDB][0] != '/') strerr_dief(100, "bootdb", " must be an absolute path") ;
if (strchr(wgola[GOLA_PREFIX], '/') || strchr(wgola[GOLA_PREFIX], '\n'))
strerr_dief(100, "prefix", " cannot contain a / or a newline") ;
-
- tain_now_set_stopwatch_g() ;
- tain_add_g(&deadline, &deadline) ;
-
if (!s6rc_livedir_canon(&wgola[GOLA_LIVEDIR]))
- strerr_diefu1sys(111, "canonicalize livedir") ;
- if (wgolb & GOLB_DEREF)
+ strerr_diefusys(111, "canonicalize ", wgola[GOLA_LIVEDIR]) ;
+
+ check_scandir(argv[0]) ;
+ x = realpath(wgola[GOLA_LIVEDIR], 0) ;
+ if (x)
{
- char *x = realpath(wgola[GOLA_BOOTDB], 0) ;
- if (!x) strerr_diefu2sys(111, "realpath ", wgola[GOLA_BOOTDB]) ;
- wgola[GOLA_BOOTDB] = x ;
+ if (check_livedir(x, argv[0], wgola[GOLA_PREFIX], wgola[GOLA_BOOTDB], &sa))
+ {
+ strerr_warni("s6-rc already running on ", x) ;
+ _exit(0) ;
+ }
+ free(x) ;
+ }
+ else
+ {
+ size_t llen = strlen(wgola[GOLA_LIVEDIR]) ;
+ char *d = strrchr(wgola[GOLA_LIVEDIR], '/') ;
+ if (!d || d == wgola[GOLA_LIVEDIR]) strerr_dief(102, "invalid existing livedir: ", wgola[GOLA_LIVEDIR]) ;
+ dirlen = d - wgola[GOLA_LIVEDIR] ;
+ if (find_livedir(wgola[GOLA_LIVEDIR], llen, dirlen, argv[0], wgola[GOLA_PREFIX], wgola[GOLA_BOOTDB], &sa))
+ {
+ strerr_warni("s6-rc already running on ", sa.s, " - recovering it") ;
+ if (!atomic_symlink4(sa.s + dirlen + 1, wgola[GOLA_LIVEDIR], 0, 0))
+ strerr_diefusys(111, "symlink ", sa.s + dirlen + 1, " to ", wgola[GOLA_LIVEDIR]) ;
+ _exit(0) ;
+ }
}
+ tain_now_set_stopwatch_g() ;
+ tain_add_g(&deadline, &deadline) ;
+
{
s6rc_db_t db ;
int r ;
@@ -173,7 +266,7 @@ int main (int argc, char const *const *argv)
strerr_diefusys(111, "symlink ", sa.s + dirlen, " to ", wgola[GOLA_LIVEDIR]) ;
}
- if (s6rc_servicedir_manage_g(wgola[GOLA_LIVEDIR], wgola[GOLA_PREFIX], &deadline) < 0)
+ if (s6rc_servicedir_manage_g(sa.s, wgola[GOLA_PREFIX], &deadline) < 0)
{
unlink_void(wgola[GOLA_LIVEDIR]) ;
cleanup(&sa) ;