aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2026-06-04 09:47:23 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2026-06-04 09:47:23 +0000
commitaf9550cfe7ea35590d9c8e246ebeaa32f6469966 (patch)
tree22063e47aa79f0b437274f10b84d7efaca87c682 /src
parent270fbc30f23b8153f0b618728d8145d636acdfef (diff)
downloads6-af9550cfe7ea35590d9c8e246ebeaa32f6469966.tar.gz
Prepare for 2.15.1.0; add s6-svscanboot
Also fix links on why.html. s6-svscanboot doc coming soon.
Diffstat (limited to 'src')
-rw-r--r--src/alias/s6-alias.c10
-rw-r--r--src/supervision/deps-exe/s6-svscanboot1
-rw-r--r--src/supervision/s6-svscanboot.c270
3 files changed, 280 insertions, 1 deletions
diff --git a/src/alias/s6-alias.c b/src/alias/s6-alias.c
index 568d29d..f530fe9 100644
--- a/src/alias/s6-alias.c
+++ b/src/alias/s6-alias.c
@@ -56,9 +56,17 @@ static void readproctitle (int argc, char const *const *argv)
static void svscanboot (int argc, char const *const *argv)
{
+ char const *newargv[6] ;
+ unsigned int m = 0 ;
+ newargv[m++] = S6_BINPREFIX "s6-svscanboot" ;
+ newargv[m++] = "-c" ;
+ newargv[m++] = "/dev/console" ;
+ newargv[m++] = "--" ;
+ newargv[m++] = "/service" ;
+ newargv[m++] = 0 ;
(void)argc ;
(void)argv ;
- noboot("svscanboot") ;
+ xexec(newargv) ;
}
#endif
diff --git a/src/supervision/deps-exe/s6-svscanboot b/src/supervision/deps-exe/s6-svscanboot
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/supervision/deps-exe/s6-svscanboot
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/supervision/s6-svscanboot.c b/src/supervision/s6-svscanboot.c
new file mode 100644
index 0000000..8de924b
--- /dev/null
+++ b/src/supervision/s6-svscanboot.c
@@ -0,0 +1,270 @@
+/* ISC license. */
+
+#include <skalibs/bsdsnowflake.h>
+
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <pwd.h>
+
+#include <skalibs/types.h>
+#include <skalibs/posixplz.h>
+#include <skalibs/stat.h>
+#include <skalibs/envexec.h>
+#include <skalibs/alloc.h>
+#include <skalibs/buffer.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/skamisc.h>
+
+#include <execline/config.h>
+
+#include <s6/config.h>
+
+#define USAGE "s6-svscanboot [ -c devconsole ] [ -D catchalldir ] [ -m catchallmode ] [ -l catchalluser ] [ -o catchalloptions ] [ -d notif ] [ -C services_max ] [ -L name_max ] [ -t rescan ] scandir"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+enum golb_e
+{
+ GOLB_USER = 0x01,
+} ;
+
+enum gola_e
+{
+ GOLA_CONSOLE,
+ GOLA_DIR,
+ GOLA_MODE,
+ GOLA_USER,
+ GOLA_OPTIONS,
+ GOLA_NOTIF,
+ GOLA_MAXSERVICES,
+ GOLA_MAXLEN,
+ GOLA_TIMEOUT,
+ GOLA_N
+} ;
+
+int main (int argc, char const *const *argv)
+{
+ static gol_bool const rgolb[] =
+ {
+ { .so = 'u', .lo = "user", .clear = 0, .set = GOLB_USER },
+ } ;
+ static gol_arg const rgola[] =
+ {
+ { .so = 'c', .lo = "console", .i = GOLA_CONSOLE },
+ { .so = 'D', .lo = "catchall-directory", .i = GOLA_DIR },
+ { .so = 'm', .lo = "catchall-mode", .i = GOLA_MODE },
+ { .so = 'l', .lo = "catchall-user", .i = GOLA_USER },
+ { .so = 'o', .lo = "catchall-options", .i = GOLA_OPTIONS },
+ { .so = 'd', .lo = "notification-fd", .i = GOLA_NOTIF },
+ { .so = 'C', .lo = "services-max", .i = GOLA_MAXSERVICES },
+ { .so = 'L', .lo = "name-max", .i = GOLA_MAXLEN },
+ { .so = 't', .lo = "timeout", .i = GOLA_TIMEOUT },
+ } ;
+ unsigned int catchall_mode = 02700 ;
+ unsigned int fdconsole = 3 ;
+ unsigned int fdnotif = 0 ;
+ unsigned int servicesmax = 0 ;
+ unsigned int namemax = 0 ;
+ unsigned int timeout = 0 ;
+ uid_t uid = -1 ;
+ gid_t gid = -1 ;
+ stralloc sa = STRALLOC_ZERO ;
+ buffer b ;
+ int fd ;
+ unsigned int m = 0 ;
+ char const *newargv[14] ;
+ uint64_t wgolb = 0 ;
+ char const *wgola[GOLA_N] = { 0 } ;
+ unsigned int golc ;
+ char buf[4096] ;
+ char fmtc[UINT_FMT] ;
+ char fmtd[UINT_FMT] ;
+ char fmtC[UINT_FMT] ;
+ char fmtL[UINT_FMT] ;
+ char fmtt[UINT_FMT] ;
+
+ PROG = "s6-svscanboot" ;
+ wgola[GOLA_OPTIONS] = "t" ;
+
+ golc = GOL_main(argc, argv, rgolb, rgola, &wgolb, wgola) ;
+ argc -= golc ; argv += golc ;
+ if (!argc) dieusage() ;
+
+ if (wgola[GOLA_MODE] && !uint0_oscan(wgola[GOLA_MODE], &catchall_mode))
+ strerr_dief(100, "catchall-mode must be an (octal) unsigned integer") ;
+ if (wgola[GOLA_NOTIF])
+ {
+ if (!uint0_scan(wgola[GOLA_NOTIF], &fdnotif))
+ strerr_dief(100, "notification-fd", " must be an unsigned integer") ;
+ if (fdnotif < 3)
+ strerr_dief(100, "notification-fd", " must be 3 or greater") ;
+ if (fcntl(fdnotif, F_GETFD) == -1)
+ strerr_diefsys(111, "notification-fd", " sanity check failed") ;
+ if (fdnotif == 3) fdconsole = 4 ;
+ }
+ if (wgola[GOLA_MAXSERVICES])
+ {
+ if (!uint0_scan(wgola[GOLA_MAXSERVICES], &servicesmax))
+ strerr_dief(100, "services-max", " must be an unsigned integer") ;
+ if (servicesmax < 4) servicesmax = 4 ;
+ if (servicesmax > 160000) servicesmax = 160000 ;
+ }
+ if (wgola[GOLA_MAXLEN])
+ {
+ if (!uint0_scan(wgola[GOLA_MAXLEN], &namemax))
+ strerr_dief(100, "name-max", " must be an unsigned integer") ;
+ if (namemax < 11) namemax = 11 ;
+ if (namemax > 1019) namemax = 1019 ;
+ }
+ if (wgola[GOLA_TIMEOUT] && !uint0_scan(wgola[GOLA_TIMEOUT], &timeout))
+ strerr_dief(100, "timeout", " must be an unsigned integer") ;
+ if (wgola[GOLA_USER] && geteuid())
+ {
+ wgola[GOLA_USER] = 0 ;
+ strerr_warnw("ignoring catchall-user option when not root") ;
+ }
+ if (wgolb & GOLB_USER && (!wgola[GOLA_DIR] || wgola[GOLA_DIR][0] != '/'))
+ {
+ size_t namelen ;
+ size_t dirlen ;
+ char *logdir ;
+ char *x = getenv("XDG_RUNTIME_DIR") ;
+ if (!x) strerr_dienotset(100, "XDG_RUNTIME_DIR") ;
+ if (!wgola[GOLA_DIR]) wgola[GOLA_DIR] = "uncaught-logs" ;
+ dirlen = strlen(x) ;
+ namelen = strlen(wgola[GOLA_DIR]) ;
+ logdir = alloc(dirlen + namelen + 2) ;
+ if (!logdir) strerr_diefusys(111, "alloc") ;
+ memcpy(logdir, x, dirlen) ;
+ logdir[dirlen] = '/' ;
+ memcpy(logdir + dirlen + 1, wgola[GOLA_DIR], namelen + 1) ;
+ wgola[GOLA_DIR] = logdir ;
+ }
+ if (!wgola[GOLA_DIR]) wgola[GOLA_DIR] = "/run/uncaught-logs" ;
+ if (wgola[GOLA_USER])
+ {
+ struct passwd *pw = getpwnam(wgola[GOLA_USER]) ;
+ if (!pw) strerr_diefsys(111, "getpwnam ", wgola[GOLA_USER]) ;
+ uid = pw->pw_uid ;
+ gid = pw->pw_gid ;
+ }
+
+ if (mkdirp(wgola[GOLA_DIR], catchall_mode) == -1)
+ strerr_diefusys(111, "mkdir ", wgola[GOLA_DIR]) ;
+ if (chown(wgola[GOLA_DIR], uid, gid) == -1)
+ strerr_diefusys(111, "chown ", wgola[GOLA_DIR]) ;
+ if (chmod(wgola[GOLA_DIR], catchall_mode) == -1)
+ strerr_diefusys(111, "chmod ", wgola[GOLA_DIR]) ;
+ if (wgola[GOLA_DIR][0] != '/')
+ {
+ char *x = realpath(wgola[GOLA_DIR], 0) ;
+ if (!x) strerr_diefusys(111, "realpath ", wgola[GOLA_DIR]) ;
+ wgola[GOLA_DIR] = x ;
+ }
+
+ size_t slen = strlen(argv[0]) ;
+ char fn[slen + 31] ;
+ memcpy(fn, argv[0], slen) ;
+ memcpy(fn + slen, "/s6-svscan-log", 15) ;
+ rm_rf(fn) ;
+ if (mkdirp2(fn, 02755) == -1)
+ strerr_diefusys(111, "mkdir ", fn) ;
+
+ memcpy(fn + slen + 14, "/notification-fd", 17) ;
+ if (!openwritenclose_unsafe(fn, "3\n", 2))
+ strerr_diefusys(111, "write to ", fn) ;
+
+ memcpy(fn + slen + 14, "/run", 5) ;
+ fd = openc_create(fn) ;
+ buffer_init(&b, &buffer_write, fd, buf, 4096) ;
+
+#define diew() strerr_diefusys(111, "write to ", fn) ;
+
+ if (buffer_puts(&b,
+ "#!" EXECLINE_SHEBANGPREFIX "execlineb -s1\n"
+ EXECLINE_EXTBINPREFIX "fdmove -c 1 2\n"
+ EXECLINE_EXTBINPREFIX "redirfd -rnb 0 fifo\n") == -1) diew() ;
+ if (wgola[GOLA_USER])
+ {
+ if (!string_quotes(&sa, wgola[GOLA_USER]))
+ strerr_diefusys(111, "quote ", "catchall-user") ;
+ if (buffer_puts(&b, S6_EXTBINPREFIX "s6-setuidgid ") == -1
+ || buffer_put(&b, sa.s, sa.len) == -1
+ || buffer_put(&b, "\n", 1) == -1) diew() ;
+ sa.len = 0 ;
+ }
+ if (!string_quotes(&sa, wgola[GOLA_DIR]))
+ strerr_diefusys(111, "quote ", "catchall-directory") ;
+ if (buffer_puts(&b,
+ EXECLINE_EXTBINPREFIX "exec -c\n"
+ S6_EXTBINPREFIX "s6-log -bpd3 -- ") == -1
+ || buffer_puts(&b, wgola[GOLA_OPTIONS]) == -1
+ || buffer_put(&b, " ", 1) == -1
+ || buffer_put(&b, sa.s, sa.len) == -1
+ || buffer_putflush(&b, "\n", 1) == -1) diew() ;
+ sa.len = 0 ;
+ if (fchmod(fd, 0755) == -1)
+ strerr_diefusys(111, "chmod ", fn) ;
+ fd_close(fd) ;
+
+ memcpy(fn + slen + 14, "/fifo", 6) ;
+ if (mkfifo(fn, 0600) == -1)
+ strerr_diefusys(111, "mkfifo ", fn) ;
+
+ fd = open2("/dev/null", O_RDONLY) ;
+ if (fd == -1) strerr_diefusys(111, "open ", "/dev/null") ;
+ if (fd_move(0, fd) == -1) strerr_diefusys(111, "fd_move ", "/dev/null", " to ", "stdin") ;
+ if (wgola[GOLA_CONSOLE])
+ {
+ fd = open2("/dev/console", O_WRONLY) ;
+ if (fd == -1) strerr_diefusys(111, "open ", "/dev/console") ;
+ if (fd_move(fdconsole, fd) == -1) strerr_diefusys(111, "fd_move ", "/dev/console") ;
+ }
+ else if (fd_copy(fdconsole, 2) == -1) strerr_diefusys(111, "fd_copy ", "stderr") ;
+ b.fd = open2(fn, O_RDONLY | O_NONBLOCK) ;
+ if (b.fd == -1) strerr_diefusys(111, "open ", fn, " for reading") ;
+ fd = open2(fn, O_WRONLY | O_NONBLOCK) ;
+ if (fd == -1) strerr_diefusys(111, "open ", fn, " for writing") ;
+ fd_close(b.fd) ;
+ if (ndelay_off(fd) == -1) strerr_diefusys(111, "ndelay_off ", fn) ;
+ if (fd_move(1, fd) == -1) strerr_diefusys(111, "fd_move ", fn, " to ", "stdout") ;
+ if (fd_copy(2, 1) == -1) strerr_diefusys(111, "copy ", "stdout", " to ", "stderr") ;
+
+ fmtc[uint_fmt(fmtc, fdconsole)] = 0 ;
+
+ newargv[m++] = S6_BINPREFIX "s6-svscan" ;
+ newargv[m++] = "-X" ;
+ newargv[m++] = fmtc ;
+ if (fdnotif)
+ {
+ fmtd[uint_fmt(fmtd, fdnotif)] = 0 ;
+ newargv[m++] = "-d" ;
+ newargv[m++] = fmtd ;
+ }
+ if (servicesmax)
+ {
+ fmtC[uint_fmt(fmtC, servicesmax)] = 0 ;
+ newargv[m++] = "-C" ;
+ newargv[m++] = fmtC ;
+ }
+ if (namemax)
+ {
+ fmtL[uint_fmt(fmtL, namemax)] = 0 ;
+ newargv[m++] = "-L" ;
+ newargv[m++] = fmtL ;
+ }
+ if (timeout)
+ {
+ fmtt[uint_fmt(fmtt, timeout)] = 0 ;
+ newargv[m++] = "-t" ;
+ newargv[m++] = fmtt ;
+ }
+ newargv[m++] = "--" ;
+ newargv[m++] = argv[0] ;
+ newargv[m++] = 0 ;
+
+ exec(newargv) ;
+ _exit(111) ;
+}