diff options
| author | Laurent Bercot <ska-skaware@skarnet.org> | 2025-12-18 09:43:22 +0000 |
|---|---|---|
| committer | Laurent Bercot <ska-skaware@skarnet.org> | 2025-12-18 09:43:22 +0000 |
| commit | 8164ce1f50c03ef3c6548df0e3e1f1d499b90b88 (patch) | |
| tree | b91cd181629b480103b3041e4e1d933f005a4c8a | |
| parent | ac6b458280e3131b4eb752d079f810ccdd4ba185 (diff) | |
| download | s6-linux-init-8164ce1f50c03ef3c6548df0e3e1f1d499b90b88.tar.gz | |
Add -W readyfd support to s6-l-i and s6-l-i-m
| -rw-r--r-- | doc/s6-linux-init-maker.html | 12 | ||||
| -rw-r--r-- | doc/s6-linux-init.html | 14 | ||||
| -rw-r--r-- | src/init/s6-linux-init-maker.c | 12 | ||||
| -rw-r--r-- | src/init/s6-linux-init.c | 34 |
4 files changed, 54 insertions, 18 deletions
diff --git a/doc/s6-linux-init-maker.html b/doc/s6-linux-init-maker.html index fb2880d..ab8044f 100644 --- a/doc/s6-linux-init-maker.html +++ b/doc/s6-linux-init-maker.html @@ -406,7 +406,17 @@ not be the default, but might be useful in some cases. </li> <br> the container so the disks are <tt>sync</tt>ed on container halt. By default, no sync is performed. This option has no effect when the <tt>-C</tt> option is not present: on real machines, a <tt>sync</tt> is <em>always</em> -performed just before a system halt. </li> +performed just before a system halt. </li> <br> + + <li> <tt>-W</tt> <em>readyfd</em> : ensure that at boot time, +before doing anything, s6-linux-init waits +for file descriptor <em>readyfd</em> to signal EOF. This is typically useful in +containers that implement the Docker synchronization mechanism, where the +container manager starts the container with a pipe open to the container's +descriptor 3, does its preparation, and closes the pipe to tell the container's +init that it can proceed. If this option is not given, or <em>readyfd</em> is 0, +s6-linux-init-maker makes no provision for synchronization and s6-linux-init +will boot without waiting. </li> </ul> <h2> Organization of the created directory </h2> diff --git a/doc/s6-linux-init.html b/doc/s6-linux-init.html index 4d800ce..efcbf6c 100644 --- a/doc/s6-linux-init.html +++ b/doc/s6-linux-init.html @@ -27,7 +27,7 @@ and execs into <a href="//skarnet.org/software/s6/s6-svscan.html">s6-svscan</a>. <h2> Interface </h2> <pre> - s6-linux-init [ -c <em>basedir</em> ] [ -p <em>initial_path</em> ] [ -s <em>env_store</em> ] [ -m <em>umask</em> ] [ -d <em>slashdev</em> ] [ -D <em>initdefault</em> ] [ -n | -N ] [ -C ] [ -B ] [ <em>args...</em> ] + s6-linux-init [ -c <em>basedir</em> ] [ -p <em>initial_path</em> ] [ -s <em>env_store</em> ] [ -m <em>umask</em> ] [ -d <em>slashdev</em> ] [ -D <em>initdefault</em> ] [ -n | -N ] [ -C ] [ -B ] [ -W <em>readyfd</em> ] [ <em>args...</em> ] </pre> <ul> @@ -69,16 +69,20 @@ a tmpfs on it, just remount <tt>/run</tt>. </li> <li> <tt>-C</tt> : run in a container. This option modifies a few of the operations described below, to accommodate running in a container instead of on real hardware. For instance: it does not scan the command -line for a specific runlevel, it does not trap ctrl-alt-del, and before -anything else it waits for its descriptor 3, if present, to close. -(Docker uses this fd 3 mechanism as synchronization between the Docker -daemon and the container's <tt>init</tt>.) </li> +line for a specific runlevel, and it does not trap ctrl-alt-del. </li> <li> <tt>-B</tt> : do not run the catch-all logger. This option removes the catch-all-logger-related operations from the list below; <tt>s6-linux-init</tt> will not redirect output descriptors, and will use a different synchronization mechanism to ensure <tt>rc.init</tt> only runs when <a href="//skarnet.org/software/s6/s6-svscan.html">s6-svscan</a> is ready. </li> + <li> <tt>-W</tt> <em>readyfd</em> : before doing anything, wait +for file descriptor <em>readyfd</em> to signal EOF. This is typically useful in +containers that implement the Docker synchronization mechanism, where the +container manager starts the container with a pipe open to the container's +descriptor 3, does its preparation, and closes the pipe to tell the container's +init that it can proceed. If this option is not given, or <em>readyfd</em> is 0, +no synchronization occurs and s6-linux-init boots without waiting. </li> </ul> <h2> Early preparation </h2> diff --git a/src/init/s6-linux-init-maker.c b/src/init/s6-linux-init-maker.c index 50aa7b8..fffbf2e 100644 --- a/src/init/s6-linux-init-maker.c +++ b/src/init/s6-linux-init-maker.c @@ -44,6 +44,7 @@ static unsigned int initial_umask = 0022 ; static unsigned int timestamp_style = 1 ; static unsigned int finalsleep = 3000 ; static unsigned int boot_verbosity = 1 ; +static unsigned int readyfd = 0 ; static int mounttype = 1 ; static int console = 0 ; static int logouthookd = 0 ; @@ -285,6 +286,12 @@ static inline int stage1_script (buffer *b, char const *data) || buffer_put(b, satmp.s + sabase, satmp.len - sabase) < 0) goto err ; satmp.len = sabase ; } + if (readyfd) + { + char fmtw[UINT_FMT] ; + if (buffer_puts(b, " -W ") < 0 + || buffer_put(b, fmtw, uint_fmt(fmtw, readyfd)) < 0) return 0 ; + } if (mounttype == 2) { if (buffer_puts(b, " -n") < 0) return 0 ; @@ -666,7 +673,7 @@ int main (int argc, char const *const *argv, char const *const *envp) subgetopt l = SUBGETOPT_ZERO ; for (;;) { - int opt = subgetopt_r(argc, argv, "V:c:u:G:1Lp:m:t:d:s:e:E:q:D:nNf:R:CBS", &l) ; + int opt = subgetopt_r(argc, argv, "V:c:u:G:1Lp:m:t:d:s:e:E:q:D:W:nNf:R:CBS", &l) ; if (opt == -1) break ; switch (opt) { @@ -691,6 +698,7 @@ int main (int argc, char const *const *argv, char const *const *envp) case 'C' : inns = 1 ; break ; case 'B' : nologger = 1 ; break ; case 'S' : innssync = 1 ; break ; + case 'W' : if (!uint0_scan(l.arg, &readyfd)) dieusage() ; break ; default : dieusage() ; } } @@ -702,6 +710,8 @@ int main (int argc, char const *const *argv, char const *const *envp) strerr_dief3x(100, "base directory ", robase, " is not absolute") ; if (slashdev && slashdev[0] != '/') strerr_dief3x(100, "devtmpfs directory ", slashdev, " is not absolute") ; + if (readyfd && readyfd < 3) + strerr_dief1x(100, "readyfd cannot be 1 or 2") ; if (env_store) { if (env_store[0] != '/') diff --git a/src/init/s6-linux-init.c b/src/init/s6-linux-init.c index dfef029..dab96d0 100644 --- a/src/init/s6-linux-init.c +++ b/src/init/s6-linux-init.c @@ -28,7 +28,7 @@ #include "defaults.h" #include "initctl.h" -#define USAGE "s6-linux-init [ -v verbosity ] [ -c basedir ] [ -p initpath ] [ -s envdumpdir ] [ -m umask ] [ -d devtmpfs ] [ -D initdefault ] [ -n | -N ] [ -C ] [ -B ]" +#define USAGE "s6-linux-init [ -v verbosity ] [ -c basedir ] [ -p initpath ] [ -s envdumpdir ] [ -m umask ] [ -d devtmpfs ] [ -D initdefault ] [ -n | -N ] [ -C ] [ -B ] [ -W readyfd ]" #define dieusage() strerr_dieusage(100, USAGE) #define BANNER "\n s6-linux-init version " S6_LINUX_INIT_VERSION "\n\n" @@ -50,6 +50,7 @@ enum gola_e GOLA_MASK, GOLA_SLASHDEV, GOLA_INITDEFAULT, + GOLA_READYFD, GOLA_N } ; @@ -185,6 +186,7 @@ int main (int argc, char const **argv, char const *const *envp) { .so = 'm', .lo = "umask", .i = GOLA_MASK }, { .so = 'd', .lo = "slashdev", .i = GOLA_SLASHDEV }, { .so = 'D', .lo = "default-runlevel", .i = GOLA_INITDEFAULT }, + { .so = 'W', .lo = "readiness-fd", .i = GOLA_READYFD }, } ; char const *wgola[GOLA_N] = { @@ -195,9 +197,11 @@ int main (int argc, char const **argv, char const *const *envp) [GOLA_MASK] = 0, [GOLA_SLASHDEV] = 0, [GOLA_INITDEFAULT] = "default", + [GOLA_READYFD] = 0, } ; uint64_t wgolb = 0 ; - mode_t mask = 0022 ; + unsigned int mask = 0022 ; + unsigned int readyfd = 0 ; stralloc envmodifs = STRALLOC_ZERO ; char *tty = 0 ; unsigned int golc ; @@ -214,21 +218,29 @@ int main (int argc, char const **argv, char const *const *envp) argc -= golc ; argv += golc ; if (wgola[GOLA_VERBOSITY] && !uint0_scan(wgola[GOLA_VERBOSITY], &verbosity)) dieusage() ; if (wgola[GOLA_MASK] && !uint0_oscan(wgola[GOLA_MASK], &mask)) dieusage() ; + if (wgola[GOLA_READYFD]) + { + if (!uint0_scan(wgola[GOLA_READYFD], &readyfd)) dieusage() ; + if (readyfd && readyfd < 3) dieusage() ; + } hasconsole = fcntl(1, F_GETFD) >= 0 ; - if (wgolb & GOLB_INNS) + if (readyfd) { char c ; - ssize_t r = read(3, &c, 1) ; /* Docker synchronization protocol */ - if (r < 0) + ssize_t r = read(readyfd, &c, 1) ; /* Docker synchronization protocol */ + if (r == -1) { - if (errno != EBADF) strerr_diefu1sys(111, "read from fd 3") ; + if (errno != EBADF) strerr_diefu1sys(111, "read from readiness fd") ; } else { - if (r) if (verbosity) strerr_warnw1x("parent wrote to fd 3!") ; - close(3) ; + if (r) if (verbosity) strerr_warnw1x("parent wrote to readiness fd!") ; + close(readyfd) ; } + } + if (wgolb & GOLB_INNS) + { if (!wgola[GOLA_SLASHDEV] && hasconsole && isatty(1 + !(wgolb & GOLB_NOLOGGER))) { tty = ttyname(1 + !(wgolb & GOLB_NOLOGGER)) ; @@ -248,8 +260,8 @@ int main (int argc, char const **argv, char const *const *envp) /* at this point we're totally in the dark, hoping /dev/console will work */ nope = mount("dev", wgola[GOLA_SLASHDEV], "devtmpfs", MS_NOSUID | MS_NOEXEC, "") < 0 ; e = errno ; - if (open2("/dev/console", O_WRONLY) && open2("/dev/null", O_WRONLY)) return 111 ; - if (fd_move(2, 0) < 0) return 111 ; + if (open2("/dev/console", O_WRONLY) && open2("/dev/null", O_WRONLY)) _exit(111) ; + if (fd_move(2, 0) < 0) _exit(111) ; if (fd_copy(1, 2) < 0) strerr_diefu1sys(111, "fd_copy") ; if (nope) { @@ -263,7 +275,7 @@ int main (int argc, char const **argv, char const *const *envp) { if (!wgola[GOLA_SLASHDEV]) reset_stdin() ; if (open2("/dev/null", O_WRONLY) != 1 || fd_copy(2, 1) == -1) - return 111 ; + _exit(111) ; } if (!(wgolb & GOLB_HANDSOFFRUN)) |
