aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2025-12-18 09:43:22 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2025-12-18 09:43:22 +0000
commit8164ce1f50c03ef3c6548df0e3e1f1d499b90b88 (patch)
treeb91cd181629b480103b3041e4e1d933f005a4c8a
parentac6b458280e3131b4eb752d079f810ccdd4ba185 (diff)
downloads6-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.html12
-rw-r--r--doc/s6-linux-init.html14
-rw-r--r--src/init/s6-linux-init-maker.c12
-rw-r--r--src/init/s6-linux-init.c34
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>&nbsp;<em>readyfd</em>&nbsp;: 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>&nbsp;: 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>&nbsp;: 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>&nbsp;<em>readyfd</em>&nbsp;: 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))