From 1bfba3b0be32306b078f5ee527b864e758b2c77b Mon Sep 17 00:00:00 2001
From: Laurent Bercot
Date: Fri, 26 Apr 2019 15:52:54 +0000
Subject: Make a single hpr. Full doc, first draft.
---
doc/s6-linux-init-maker.html | 451 +++++++++++++++++++++----------------------
1 file changed, 224 insertions(+), 227 deletions(-)
(limited to 'doc/s6-linux-init-maker.html')
diff --git a/doc/s6-linux-init-maker.html b/doc/s6-linux-init-maker.html
index a512501..45284ab 100644
--- a/doc/s6-linux-init-maker.html
+++ b/doc/s6-linux-init-maker.html
@@ -21,27 +21,25 @@
s6-linux-init-maker reads configuration options on
the command line, and outputs a directory to place in the
-root filesystem. That directory contains a script suitable
-as an init program, as well as support file hierarchies to
-get a complete
+root filesystem. That directory contains
+a script that is suitable as an /sbin/init program
+as well as all the necessary files that this script needs
+to properly boot and bring up a full
s6
-infrastructure running when the system is booted on that
-script.
+infrastructure.
s6-linux-init-maker only writes scripts. At boot time, these
scripts will call commands provided by other skarnet.org packages
such as
-execline or
+execline and
s6. It is the
responsibility of the administrator to make sure that all the
dependencies are properly installed at boot time, and that the
-correct options have been given to s6-linux-init-maker so that
-the programs are found on the root filesystem of the
-machine - else the scripts will crash.
-
-
+correct options have been given to s6-linux-init-maker
+so that the programs are found on the root filesystem of the
+machine. If it is not the case, the system will fail to boot.
Interface and usage
@@ -49,7 +47,7 @@ machine - else the scripts will crash.
s6-linux-init-maker \
[ -c basedir ] \
- [ -u log_uid -g log_gid | -U ] \
+ [ -u log_user ] \
[ -G early_getty ] \
[ -1 ] \
[ -L ] \
@@ -59,13 +57,15 @@ machine - else the scripts will crash.
[ -d dev_style ] \
[ -s env_store ] \
[ -e initial_envvar ] ... \
- [ -E stage2_envvar ] ... \
[ -q ] finalsleeptime
+ [ -D initdefault ] \
+ [ -U utmp_user ] \
dir
- - s6-linux-init-maker should be run as root.
+ - s6-linux-init-maker must be run as root, on the machine
+that will boot an s6-based system.
- s6-linux-init-maker parses options on its command line.
- It writes data into a directory dir, which must not
exist beforehand.
@@ -75,171 +75,72 @@ or its contents.
- dir should then be copied by the administrator to the place
-declared as basedir. Be careful: it contains fifos, files with
+ Once the command has been run and dir has been created, there
+are a few manual steps to take:
+
+
+
+ - s6-linux-init-maker has copied some scripts from the
+/etc/s6-linux-init/skel directory (or the directory you
+gave as an argument to the --skeldir configure option at
+build time) to the dir/scripts directory. You
+should edit these scripts and adapt them to your use case.
+(Or you could edit the skeleton scripts before running
+s6-linux-init-maker.) The scripts are:
+
+ - rc.init: this script will be run as stage 2
+initialization, i.e. the initialization that happens once
+s6-svscan
+is running as process 1, and should contain all your normal
+system bootup tasks. Typically, it should initialize the service
+manager and then order it to bring the machine state to its
+fully operational state. rc.init is given the default
+runlevel as a first argument (i.e. the name of the state
+the machine should be brought to, traditionally default
+for OpenRC and 2 or 5 for sysv-rc), and the
+rest of the command line is made of the kernel's command line
+except for the kernel arguments of the key=value form,
+which have been stored into env_store.
+ - rc.shutdown: this script will be run as the
+shutdown sequence, when the administrator runs the
+shutdown, halt, poweroff or reboot
+command. (As well as init 0, init 6.
+telinit 0 and telinit 6 for compatibility
+reasons.) It should ask the service manager to bring all the
+services down, and exit when it's done (in other words: it should
+not try to perform a hard halt/poweroff/reboot itself.)
+No arguments are given to this script.
+ - runlevel: this script will be invoked for every
+runlevel change, i.e. change of machine states. It is
+given one argument: the name of the runlevel to change to.
+Typically, the runlevel script should just invoke the
+service manager, asking it to bring the machine state to the
+wanted runlevel.
+
+ - Copy the dir directory to the place declared as
+basedir (/etc/s6-linux-init/current by default).
+ Be careful: it contains fifos, files with
precise uid/gid permissions, and files with non-standard access rights,
so be sure to copy it verbatim. The
s6-hiercopy
-tool can do it, as well as the GNU or busybox cp -a or mv commands.
-
-
-
- The basedir/bin directory contains scripts, or
-links to programs, that are suitable as System V-compatible programs
-of the same name; the administrator should copy them to (or symlink
-them from) a place where those programs are usually found, typically
-/sbin.
-
-
-
- In particular, the basedir/bin/init script
-suitable as a "stage 1" init program, i.e. the first program
-run by the kernel (possibly after an initramfs execution).
-Once this script is copied to, or symlinked from,
-/sbin/init, the machine will be ready to boot on the
-new s6-based system.
-
+tool can do it, as well as the GNU or busybox cp -a or mv commands.
+ - Back up your /sbin. Then copy, link or symlink all the scripts
+and symlinks in the basedir/bin directory into /sbin.
+ In particular, the basedir/bin/init script should
+be accessible as /sbin/init.
+
Boot sequence
When the kernel boots, it may run an initramfs first, but in any
case it then runs the basedir/init script,
-also known as stage 1. This is what happens during stage 1:
-
-
-
- - stage 1 is an
-execline script, so
-the first process run by the kernel is the
-execlineb
-program launcher.
- - stage 1 mounts a
-tmpfs
-filesystem on tmpfsdir.
- - stage 1 copies basedir/run-image verbatim to
-tmpfsdir.
- - stage 1 empties its environment, then reads a global set of environment variables from the
-basedir/env
-environment directory.
- - stage 1 forks a child that will block until
-s6-svscan is running.
- - stage 1 executes, as process 1, into
-s6-svscan,
-with tmpfsdir/service as a
-scan directory.
- - This scan directory already contains at least one service, which is the
-catch-all logger: error messages from the supervision tree, and
-from services that do not have a dedicated logger, are handled by a
-special s6-log
-instance and made available in tmpfsdir/uncaught-logs
-instead of clogging the system console.
- - If the -G option has been given to s6-linux-init-maker, the
-scan directory will also contain a service for an early getty.
- - s6-svscan starts all the services defined in the scan directory,
-and unblocks the child forked by stage 1.
- - This child executes into initscript.
-
-
-
- initscript is the responsibility of the administrator - it will
-not be written automatically!
-It should
-contain all the necessary initialization sequence to bring up a proper
-system. When initscript is executed, the machine state is as follows:
-
-
-
- - initscript's working directory is / and its stdin
-is /dev/null. Its
-stdout and stderr both point either to /dev/console or to the pipe
-to the catch-all logger, depending on the -r option.
- - The system has a valid device directory mounted on /dev.
- - Depending on the kernel boot command line, the root filesystem
-may be in read-only mode.
- - There is a tmpfs available for root only in tmpfsdir.
- - s6-svscan
-is running as process 1. At any time, it is possible to make it supervise a long-lived
-process by linking the appropriate
-service directory
-into tmpfsdir/service, then running the command
-s6-svscanctl -a tmpfsdir/service. Services without a
-dedicated logger will send their output to the catch-all logger.
- - A getty service may already be available. The point of this early
-getty is essentially to make it easier to debug if initscript fails.
-
-
-
- There is nothing else. In particular, no filesystem has been
-mounted yet, including /proc and /sys; and no one-time
-initialization
-has been performed. The point of stage 1 is only to make it
-possible to run initscript with a logging infrastructure and a
-supervision infrastructure already available, and all the
-real machine and service initialization should happen in initscript,
-also known as stage 2.
-
-
- Shutdown sequence
-
-
-
- - A shutdown is performed when the administrator runs one of the
-s6-halt,
-s6-poweroff or
-s6-reboot commands.
-
- - Those commands send a signal to the
-s6-svscan
-process running as pid 1; this signal is caught and s6-svscan runs the
-corresponding "signal handler" script that has been placed by
-s6-linux-init-maker into the
-basedir/run-image/service/.s6-svscan directory (and that
-has been copied at boot time to tmpfsdir/service/.s6-svscan).
-
- - That script first spawns the shutdownscript script, who
-must have been written by the administrator. The purpose of
-shutdownscript is to perform the high-level shutdown sequence
-while the supervision tree is still alive. Typically, when using a
-service manager, shutdownscript would tell the service manager
-to bring all services down. When using
-s6-rc, a typical
-stage2_finish script just contains s6-rc -da change.
- More generally speaking, shutdownscript should undo what
-stage2 has done at boot time.
-
- - The "signal handler" script then tells s6-svscan to exit via an
-appropriate s6-svscanctl
-command: s6-svscan then executes into the final shutdown sequence. This
-sequence is made of the following actions:
-
-
- - The supervision tree gets torn down.
- - All data is flushed to disk.
- - All processes get a SIGTERM, a SIGHUP, and a SIGCONT. This should
-allow all processes to die gracefully. Note that most processes should
-already have been killed during the /etc/rc.shutdown execution;
-this phase only catches stragglers, background processs, etc.
- - The sequence sleeps for finalsleeptime milliseconds, to
-allow all processes to finish their clean exit routine.
- - All processes get a SIGKILL.
- - All zombies are reaped.
- - All filesystems get unmounted, and the root filesystem is remounted
-read-only.
- - The machine performs a hardware reboot, halt or poweroff, depending
-on the command that has been used.
-
-
-
-
-
- The examples/ subdirectory of the s6-linux-init package
-contains an example of /etc/rc.init
-and /etc/rc.shutdown scripts, suitable for
-initscript and shutdownscript
-respectively. Those scripts can practically be used as is if the machine
-is managed by the s6-rc
-service manager.
+also known as stage 1. This script is just an execution
+of the s6-linux-init program with
+some command-line options that are directly transferred from the
+s6-linux-init-maker invocation. Refer to the
+s6-linux-init man page to know
+exactly what it does.
s6-linux-init-maker options
@@ -248,60 +149,50 @@ service manager.
-c basedir : at boot time, stage 1,
which should be accessible as basedir/init,
will read its read-only data from basedir. After running
-s6-linux-init-maker, the administrator should make sure to copy the
+s6-linux-init-maker, you should make sure to copy the
created directory dir to basedir. basedir
must be absolute. Default is
-/etc/s6-linux-init.
-
- -u log_uid : the catch-all
-logger will run with the uid log_uid. Default is 0.
-
- -g log_gid : the catch-all
-logger will run with the gid log_gid. Default is 0.
+/etc/s6-linux-init/current.
- -U : the correct log_uid and
-log_gid values for the catch-all logger will be read from the
-UID and GID environment variables that have been passed to
-s6-linux-init-maker. This allows for invocations such as
-s6-envuidgid nobody s6-linux-init-maker -U ... so that
-the catch-all logger runs as the nobody user. Be aware that
-this option is only safe when the user database on the
-boot-time machine is the same as on the run-time
-machine, else the catch-all logger may run with an unexpected uid
-and gid.
+ -u log_user : the catch-all
+logger will run as the log_user user. Default is root.
-G early_getty : if this option
-is set, s6-linux-init-maker will define a service that will run
-very early, before stage2 is executed. This early service
-should be a getty, to allow logins even if stage2 fails.
+is set, s6-linux-init-maker will define an additional s6 service
+that will be named s6-linux-init-early-getty and started
+at the same time rc.init is executed. This early service
+should be a getty, or equivalent, to allow logins even if stage2 fails.
early_getty should be a simple command line: for instance,
"/sbin/getty 38400 tty1". By default, no early service
is defined.
-1 : make it so that all the messages that are
sent to the catch-all logger (i.e. all the error messages that are not
-caught by a dedicated logger, as well as the output from stage2)
+caught by a dedicated logger, as well as the output from rc.init,
+runlevel and rc.shutdown,
are also copied to /dev/console. This is generally useful to
debug a system at a glance, but if a failing program keeps sending
error messages, it may interfere with comfortable usage of an early
-getty.
+getty. A common workaround is to make the early getty start on
+tty2 and leave tty1 for /dev/console to print on.
+
+ -L : add an early s6-linux-init-logouthookd
+service to clean up utmp records at user logout time. Check the
+s6-linux-init-logouthookd page
+for details.
-p initial_path : the value to
set the PATH environment variable to, for all the starting processes.
-This will be done as early as possible in stage 1. It is
-absolutely necessary for
-execline,
-s6,
-s6-portable-utils and
-s6-linux-utils
+It is absolutely necessary for
+execline and
+s6
binaries to be accessible via initial_path, else the machine
will not boot. Default is
/usr/bin:/bin.
-m initial_umask : the value of
the initial file umask for all the starting processes, in octal.
-Default is
-022.
+Default is 022.
-t timestamp_style : how
logs are timestamped by the catch-all logger. 0 means no
@@ -319,39 +210,37 @@ devtmpfs automounted by the kernel at boot time. Default is
2.
-s env_store : stage 1 init sometimes
-inherits a few environment variables from the kernel. It empties its
-environment before spawning stage2 and executing into s6-svscan, in
+inherits a few environment variables from the kernel. (These variables
+correspond to the arguments on the kernel command line that are of the
+form key=value.) It empties its
+environment before spawning rc.init and executing into s6-svscan, in
order to prevent those "kernel" environment variables from leaking
into the whole process tree. However, sometimes those variables are
needed at a later time; in that case, giving the -s option
-to s6-linux-init-maker makes stage 1 init dump the "kernel" environment
-variables into the env_store directory, via the
-s6-dumpenv
-program, before erasing them. env_store should obviously be
-a writable directory, so it should be located under tmpfsdir!
-If this option is not given (which is the default), the environment
-inherited from the kernel isn't saved anywhere.
+to s6-linux-init-maker makes stage 1 init dump the "kernel" environment
+variables into the env_store directory (under a format that is
+later readable with
+s6-envdir -fn)
+before erasing them. env_store should obviously be
+a writable directory, so it should be located under /run
+(or your chosen tmpfsdir)!
+If this option is not given, the environment inherited from the kernel
+isn't saved anywhere - which is the default.
-e initial_envvar : this option
-can be repeated. For every initial_envvar, s6-linux-init-maker
+can be repeated. For every initial_envvar, s6-linux-init-maker
will adjust the global environment directory in dir/env.
initial_envvar must either be of the form VAR,
to make sure that VAR does not appear in the global
environment, or of the form VAR=VALUE, to add an
environment variable VAR with the value VALUE.
The global environment is the environment that every supervised
-process (as well as the stage2 script) will run with,
+process (as well as the rc.init script) will run with,
so it will be inherited by default by every process running on
the system.
The TZ variable, for instance, is a good candidate to be set in
the global environment.
- -E stage2_envvar : same behaviour
-as the -e option, except that every declared
-stage2_envvar will be put in the environment run by the
-stage2 script. They will not be put in the global
-environment.
-
-q finalsleeptime : when the machine
shuts down, all processes that have not already been killed during
shutdownscript will receive a SIGTERM or a SIGHUP to allow
@@ -361,10 +250,113 @@ will go on. This option configures the amount of time that will
elapse between the SIGTERM/SIGHUP and the SIGKILL.
Default is 2000, meaning a grace period of 2 seconds.
+ -D initdefault : boot the system with
+a runlevel set to initdefault, which can be an arbitrary
+string, but is usually 2, 3, 5 (traditional
+sysvinit behaviour) or default (OpenRC behaviour). Default is
+default. Note that if a 2, 3, 4,
+5, or default argument is encountered in the kernel
+command line, it will be interpreted as the runlevel to boot the system
+on, and will override the default given here.
+
+ -U utmp_user : this option is only
+available when the s6-linux-init package has been built with the
+--enable-utmps configure option, that enables support for the
+utmps package. The option
+defines the user that the utmpd and wtmpd services
+will run as. Default is utmp.
+
+
+ Organization of the created directory
+
+
+ If s6-linux-init-maker returns successfully, dir
+contains data that will be used at boot time. (Actually,
+basedir will be used at boot time, not dir. Do not
+forget to copy dir to basedir once you have checked
+you are happy with what s6-linux-init-maker has created.)
+
+
+
+ This boot-time data is made of several subdirectories:
+
+
+
+ - bin: this subdirectory contains scripts and symlinks
+that should be copied to /sbin or /bin. There is
+an init program performing stage 1 init, a telinit
+program to change runlevels, and utilities to order a machine shutdown.
+ - env: this subdirectory is the envdir that is
+used to store the global environment. It will be read at boot time
+by stage 1 init, and transmitted to all spawned processes.
+ - scripts: this subdirectory contains a copy of the
+skeleton scripts that have been installed in /etc/s6-linux-init/skel
+(or the argument to the --skeldir configure option at
+build time). These scripts should be edited before booting. They are
+described above.
+ - run-image: this is a file hierarchy that will be
+copied verbatim at boot time to the newly made and mounted
+/run tmpfs (or whatever your tmpfsdir is). The
+subdirectories it contains are the following:
+
+ - uncaught-logs: this is the directory where the
+catch-all logger will store and rotate the error messages produced
+by the s6 supervision tree and the services that do not redirect
+their own logs.
+ - service: /run/service will be the scandir.
+It initially contains a .s6-svscan subdirectory that
+tells s6-svscan
+what to do if it receives a signal (typically via the ctrlaltdel
+combination) and ensures a hard reboot if s6-svscan ever fails. It
+also contains a list of early services, i.e. s6 services that will
+be run at boot time as soon as s6-svscan is executed. These
+services are:
+
+ - s6-svscan-log: the catch-all logger.
+ - s6-linux-init-shutdownd: a service that listens
+to shutdown commands such as reboot and triggers the software
+shutdown procedure. The service is asleep for the whole lifetime of
+the machine and uses very few resources.
+ - s6-linux-init-runleveld: a service that listens
+to runlevel change commands such as telinit and calls the
+runlevel script in a reproducible environment to bring the
+machine to the wanted state.
+ - (If the -L option has been given to
+s6-linux-init-maker) s6-linux-init-logouthookd:
+the "clean up user utmp records at logout time" service. See the
+s6-linux-init-logouthookd
+page for details.
+ - (If the -G option has been given to
+s6-linux-init-maker) s6-linux-init-early-getty:
+the early getty service, that will allow a user to log in even if
+rc.init fails to bring the machine to a state where logins
+are possible.
+
+
+
+
+
+ If s6-linux-init has been built with
+utmps support, some more
+directories may exist:
+
+
+
+ - A directory somewhere under run-image, by default utmp,
+that is the location where the utmp and wtmp files will be created.
+ - Two additional early services named utmpd and wtmpd,
+that are the utmps way of
+providing secure utmp functionality.
Notes
+
+ A directory created by s6-linux-init-maker is only valid on
+the machine it has been created on. Pre-creating init directories for
+other machines is not supported.
+
+
The difficult parts of
running
@@ -380,22 +372,27 @@ tree's output away from /dev/console (which is fine for a
first process invocation but impractical for log management of a
whole process tree) and into a logger that is itself managed by the
supervision tree it's reading data from.
+ Keeping appearances of compatibility with another init system
+is difficult: in particular, the mechanisms around the shutdown
+procedure are fundamentally different from about any other init
+system, so even a simple command such as reboot needs an
+ad-hoc implementation.
- The main benefit of s6-linux-init-maker is that it automates those
-parts. This means that it has been designed for real hardware
-where the above issues apply.
- If you are building an init system for a
-virtual machine, a container, or anything similar that does not
-have the /dev/console issue or the read-only rootfs issue,
-you will probably not reap much benefit from using s6-linux-init-maker:
+ The main benefit of s6-linux-init-maker is that it offers
+transparent compatibility while automating the tricky technical part.
+That means that s6-linux-init-maker has been designed for
+real hardware, or at least full-fledged Linux systems,
+where the above issues apply. If you are building an init system for a
+container, or anything similar that does not
+have the /dev/console issue, the read-only rootfs issue,
+or the need for sysvinit compatibility,
+you will probably not reap much benefit from using s6-linux-init-maker:
you could probably invoke
s6-svscan
directly as your process 1, or build a script by hand, which
would result in a simpler init with less dependencies.
-Nevertheless, if you prefer using s6-linux-init-maker, it
-supports this case via the -n option.