diff options
| -rw-r--r-- | INSTALL | 6 | ||||
| -rw-r--r-- | NEWS | 7 | ||||
| -rw-r--r-- | doc/index.html | 10 | ||||
| -rw-r--r-- | doc/s6-rc-init.html | 3 | ||||
| -rw-r--r-- | doc/upgrade.html | 11 | ||||
| -rw-r--r-- | package/deps-build | 6 | ||||
| -rw-r--r-- | package/info | 2 | ||||
| -rw-r--r-- | src/s6-rc/s6-rc-init.c | 157 |
8 files changed, 158 insertions, 44 deletions
@@ -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: @@ -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) ; |
