s6-linux-init: the s6-linux-init program
Keywords: s6 linux init administration root init boot pid1 pid 1 /sbin/init

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.