s6-linux-init
Software
skarnet.org
The s6-linux-init program
s6-linux-init is a program that is meant to run as pid 1,
as a stage 1 init: it performs the necessary early system preparation
and execs into s6-svscan.
Interface
s6-linux-init [ -c basedir ] [ -p initial_path ] [ -s env_store ] [ -m umask ] [ -d slashdev ] [ -D initdefault ] [ -n | -N ] [ -C ] [ -B ] [ -W readyfd ] [ args... ]
- If s6-linux-init isn't pid 1, it execs into
s6-linux-init-telinit with the
same arguments.
- Else, it performs some early preparation, spawns a process that
will run the rc.init script, then execs into
s6-svscan.
Options
These options should exactly mirror the options with the same name that
have been given to s6-linux-init-maker.
If there is a discrepancy, the system might not boot.
- -c basedir : read all its initialization
data from basedir. If the data has not indeed been copied to
basedir, the system will not boot.
- -p initial_path : the initial value for
the PATH environment variable.
- -s env_store : the place where to dump
kernel environment variables.
- -m initial_umask : the initial file umask.
- -d slashdev : mount a devtmpfs on
slashdev. By default, no such mount is performed - it is assumed
that a devtmpfs is automounted on /dev at boot time by the kernel.
- -D initdefault : the initial runlevel
to boot to, if it isn't overridden by the kernel command line.
This is only given as a first argument to rc.init.
Default is default.
- -n : instead of unmounting /run and mounting
a tmpfs on it, just remount /run.
- -N : do not touch /run at all.
- -C : 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, and it does not trap ctrl-alt-del.
- -B : do not run the catch-all logger. This option
removes the catch-all-logger-related operations from the list below;
s6-linux-init will not redirect output descriptors, and will
use a different synchronization mechanism to ensure rc.init
only runs when s6-svscan
is ready.
- -W readyfd : before doing anything, wait
for file descriptor readyfd 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 readyfd is 0,
no synchronization occurs and s6-linux-init boots without waiting.
Early preparation
When booting a system, s6-linux-init performs the following
operations:
- It prints a banner to /dev/console.
- It chdirs to /.
- It sets the umask to initial_umask.
- It becomes a session leader.
- It mounts a devtmpfs on slashdev, if requested.
- It uses /dev/null as its stdin (instead of /dev/console).
/dev/console is still used, for now, as stdout and stderr.
- It unmounts /run (or the directory you have given to the
--tmpfsdir configure option at package build time), just in case;
then it creates a tmpfs on it. Alternatively, it remounts /run,
or does not touch it at all.
- It copies the whole basedir/run-image hierarchy to
/run (or your chosen tmpfsdir).
- It reads the initial environment from basedir/env.
- If required, it stores the kernel environment into env_store.
- It performs "the fifo trick", i.e. it redirects its stdout to the
catch-all logger's fifo, without blocking, before the catch-all
logger is even up (because it's a service that will be spawned a bit
later, when s6-svscan
is executed).
- It forks a child.
- The child scans the kernel command line to find a suitable runlevel
(default, 2, 3, 4, or 5). If
it doesn't find any kernel command line argument that defines a runlevel,
it uses initdefault.
- The child becomes a session leader.
- The child blocks until the catch-all logger runs.
- It also makes the catch-all logger's fifo its stderr.
- It traps the ctrl-alt-del keyboard combination.
- It execs into s6-svscan
with /run/service as its scandir (or tmpfsdir/service).
- s6-svscan
spawns the early services that are defined in
basedir/run-image/service, and have been copied into
/run/service (or tmpfsdir/service).
- One of those early services is s6-svscan-log, which is
the catch-all logger. When this service is up, s6-linux-init's
child unblocks.
- The child execs into basedir/scripts/rc.init.
The first argument to rc.init is the chosen runlevel. The kernel
command line, as given by the kernel to s6-linux-init (i.e. without
the key=value arguments, which were passed into s6-linux-init's
environment and were stored into env_store), makes for the rest of
the arguments given to rc.init.
By the time rc.init runs,
s6-svscan is running
as pid 1 and has spawned its early services - at least the catch-all logger,
and the other services, including the early getty if it has been defined, are
started in parallel and will be ready instantly. rc.init can then
perform stage 2 of the initialization process, i.e. the handoff to
the service manager.
Exit codes
s6-linux-init never exits. It spawns the rc.init script
and execs into s6-svscan,
which runs forever until the machine stops or reboots.
Notes
- The s6-linux-init
binary is not meant to be called directly, or be linked to /sbin/init
directly, because it takes command-line options.
Instead, after a
s6-linux-init-maker invocation,
the bin/ subdirectory of the target will contain a script called
init, which execs into s6-linux-init with the appropriate
command-line options, and is suitable as a /sbin/init program.
The bin/ subdirectory
should be copied by the administrator into /sbin for full
interface compatibility with sysvinit.