s6-rc
Software
skarnet.org

The s6-rc-compile program

s6-rc-compile is a service database compiler. It takes a series of service definitions in the source format, and compiles them into a directory, which is the compiled format.

The administrator can then examine that compiled database via s6-rc-db, put it into a place where it will be registered at boot time as the current compiled database by s6-rc-init, or even live update the current service database via s6-rc-update.

Interface

     s6-rc-compile [ -v verbosity ] [ -u uids ] [ -g gids ] [ -h fdhuser ] compiled source...

Exit codes

Options

If the -u or -g option is used, then 0 must be explicitly listed in uids in order to allow root to operate the database. If neither option is used, then root (and only root) is implicitly allowed.

Source format

s6-rc-compile scans every source directory to find service definition directories in it. It ignores every file that is not a directory, or that starts with a dot. For every service definition directory that it finds, it creates a service with the same name as the directory. Names cannot be duplicated and cannot contain a slash or a newline; they can contain spaces and tabs, but using anything else than alphanumerical characters, underscores and dashes is discouraged - the s6-rc programs will handle weird names just fine, but other tools, especially shell scripts, may not. Names are also forbidden to use the reserved s6rc- and s6-rc- prefixes.

Every service definition directory service is expected to contain the following files:

For every service

For bundles

It is possible to use bundle names in a contents file. However, if s6-rc-compile detects a cycle in bundle definitions, it will complain and exit 1.

For atomic services

It is unnecessary to manually define complete sets of dependencies in the dependency file, because s6-rc will properly handle dependency chains. anyway. If A depends on B, no matter the underlying implementation of B, and the current implementation of B depends on C, then you should just put B in A/dependencies; when starting the set, s6-rc will start C first, then B, then A. If the underlying implementation of B changes and does not depend on C, then you will just have to modify the dependencies for B, not for A

Of course, if A depends on C anyway, you should add both B and C to A/dependencies.

If s6-rc-compile detects a cycle in dependencies across services, it will complain and exit 1.

For oneshots

up and down are interpreted by execlineb, but that does not mean they have to be entirely written in the execline language. The execlineb lexer is only used because it can compile a Unix command line from a text file and store the compiled result, whereas a shell would have to be invoked everytime the script is run. There are many ways to write up and down scripts:

Don't think you have to learn all the intricacies of the execline language just because the up and down scripts get lexed by it. You don't.

For longruns

The s6-rc service definition directory for a longrun service is similar to a s6 service directory, but there are a few differences:

The following files must or may appear in a longrun definition directory:

Be aware that service directories will be relocated, and copied at boot time, so if your run or finish scripts refer to files in the service directory (probably in the data or env subdirectories!), they should use relative paths, not absolute ones.

Note that you cannot create a down file in a generated service directory. Even if such a file exists in the definition directory, it will be ignored. This is intentional: s6-rc internally uses down files to mark longrun services that are down.

The producer-for, consumer-for and pipeline-name files are used to set up automatic longrun pipelining.

Longrun pipelining

Users of supervision suites know about logged services: a service acts as a producer, and is coupled with another service, its logger; the supervision system automatically maintains an open pipe between the producer's stdout and the logger's stdin.

s6-rc comes with an extension of this mechanism. Rather than only allowing two longrun services to be pipelined, it can set up an indefinite number of longrun services this way.

s6-rc-compile will detect pipelines, and set up the service directories so that every producer's stdout is connected to its consumer's stdin, and that the pipes are not broken whenever one element in the chain dies.

s6-rc-compile checks for pipeline consistency. It must see a producer-for file in the producer's definition that is consistent with the consumer-for file in the consumer's definition. It will detect and reject cycles as well as collisions.

The pipe linking a producer and a consumer is created by an automatically generated oneshot service that both the producer and consumer depend on, and stored in a s6-fdholder-daemon instance created by an automatically generated longrun service.

A complete example

The examples/source subdirectory of the s6-rc package contains a set of service definition directories, which is actually a working, valid set for a Linux system running busybox and the skarnet.org packages; of course, only the service definition set has been kept, and private information has been removed, so it won't work out-of-the-box without the proper specific files, notably configuration in /etc/ - but nevertheless, you can browse the source and understand what it does, and adapt it to your own needs. It will compile as is with s6-rc-compile, and you can examine the resulting compiled database with s6-rc-db.