An overview of s6-rc
A manager for services
s6-rc is a service manager, or, in other words, a machine state manager: given a database of services, with dependencies between them, it can safely bring the global machine state, or live state, to the desired point, making sure dependencies are never broken.
The live state
The live state, by definition, is the tuple of all service states on the machine. Changing the live state means bringing services up, or bringing services down.
Two and a half kinds of services
Supervision suites manage long-lived processes, a.k.a daemons, and sometimes call them services. With s6-rc, things are a little different: a long-lived process is also called a longrun and is a service, but a service does not have to be a longrun. There is a second kind of service, which is called a oneshot, and which represents a change of system state that is not embodied by the presence of a long-lived process. For instance, "mounting a filesystem" is a system state change, but in most cases there is no process hanging around while the filesystem is mounted.
s6-rc handles both oneshots and longruns.
- A longrun is the exact equivalent of a service in the supervision sense. It is defined by a service directory, with a run script and optional other data. The service is considered up as long as the long-lived process is alive and, for daemons that support it, has notified its readiness. It is considered down otherwise.
- A oneshot, on the other hand, is totally unknown from supervision suites, because there is no daemon to manage. A oneshot is represented by two short-lived scripts, up and down, used to bring the service respectively up and down. The service is considered up when the up program has exited successfully, and until the down program has exited successfully.
Services can depend on one another. If service A has been declared as depending on service B, then s6-rc will make sure to never start A until it knows that B is up, and will make sure to never stop B until it knows that A is down. This works whether A and B are both oneshots, both longruns, or a oneshot and a longrun.
Oneshots and longruns are called atomic services. By opposition to atomic services, s6-rc also handles an additional kind of service that it calls a bundle. A bundle is just a collection of atomic services, described under a single name. A bundle definition can even contain other bundles, but ultimately a bundle will always represent a set of one or more atomic services. Bundle names can be used anywhere with the s6-rc user interface, and they will internally be converted to a set of atomic services. An atomic service can depend on a bundle: it will simply depend on all the atomic services represented by the bundle. A bundle, however, cannot have dependencies.
A two-part operation
Unlike other service managers such as anopa, s6-rc separates the work of analyzing a set of service definitions, resolving dependencies, and so on, from the work of actually applying the dependency graph to perform live state changes. The former is the compilation phase, and is done offline; the latter is the live phase, and is of course done online - it impacts the actual state of the machine.
The compilation phase
- Users are expected to write their service definitions - be it oneshots, longruns or bundles - in one or more source directories, in the s6-rc source format. The source format is simple to parse automatically - which is one of the main reasons why it has been designed that way - and it is also simple to generate automatically: it is easy to write converters from a given service definition format to the s6-rc source format.
- Users then run the s6-rc-compile program, that takes a set of service definitions in one or more source directories and makes a compiled service database, abbreviated as compiled. This compiled should be stored by the administrator on the root filesystem.
- The s6-rc-db tool can be used to examine compiled service databases and extract information from them in a human-friendly format.
The live phase
When the machine boots up:
- First, the chosen init should make sure that a s6 supervision tree is up and running. s6-rc will only work if there is an active s6-svscan process monitoring a scan directory. On Linux, for instance, it is possible to achieve such a state by using an init created by the s6-linux-init-maker tool: when control reaches stage 2, s6-svscan is guaranteed to run, so using s6-rc in the stage 2 script is the way to go.
- The boot process, let's name it stage2, should then call the s6-rc-init program. This program will set up an area for s6-rc in a writable directory (which can be on a RAM filesystem such as tmpfs) to host its live information such as the machine state, a working copy of all service directories for longruns, and a link to the current compiled state database. s6-rc-init initializes the machine state as "every declared service is down".
- stage2 should then invoke the s6-rc program (s6-rc change) with, as arguments, the names of the services that should be brought up. Of course, bundles can be used for shortcuts.
- That's it, the services are up and the initialization should be over. If the service database has been properly written, a stage2 script can actually be really short: an invocation of s6-rc-init and an invocation of s6-rc.
Other state changes and shutdown
The administrator can make changes to the live state of the machine by manually calling s6-rc again with the proper arguments. This is more powerful than the old runlevels: it is possible to change the live state to any set of services, not only predefined ones. The only thing that s6-rc will not allow is a state that would break service dependencies; it will always respect the dependency graph.
The s6-rc command is the engine for machine state changes, and it is also true for shutdown. When shutting a machine down, all the services managed by s6-rc should be brought down in the proper order (via the s6-rc -da change command). Once all those services have been brought down successfully, the final shutdown procedure can take place; for instance, if s6-svscan is running as process 1 with the s6-linux-init defaults, s6-svscanctl -6 /run/service will kill the supervision tree and call /etc/rc.shutdown reboot, which should reboot the machine.
Live updates to the service database
The s6-rc command is a one-stop shop for service management as long as the compiled database doesn't change. If an administrator wishes to make a new compiled database the current live one, without rebooting the machine, a bit more work is needed, and that's the job of the s6-rc-update command. This command has been specifically written with Unix distributions in mind: when new packages ship, they come with new service definitions, or upgraded ones, and it is necessary to compile a new service database and update the live state so it matches; if source definitions for s6-rc are provided in the packages, an invocation of s6-rc-compile followed by an invocation of s6-rc-update should be all it takes to keep the live state up to date.
Management of source definition directories
Starting with version 0.6.0.0, s6-rc provides tools to help users and distributions — typically using a package manager — organize their source definition directories and their compiled service databases. This is known as the "repo" subset of the s6-rc programs, identifiable by their names starting with s6-rc-repo- and s6-rc-set. The key concepts behind these programs and links to their documentation are listed here.
