S6-rc

s6-rc is Article description::a service manager for [[s6-based systems]], i.e. a suite of programs that can start and stop services, both long-running daemons and one-time initialization scripts, in the proper order according to a dependency tree. It can be used as an init system component, with a role similar to that of OpenRC for sysvinit + OpenRC systems. A high level overview of s6-rc is available here. The package's documentation is provided in HTML format, and can be read on a text user interface using for example.

Files

 * - Default live state directory.
 * - Default pathname of the compiled service database used by to initialize s6-rc.

Usage
s6-rc manages services. A service is usually thought of as being provided by a server program that runs as a long-lived process. In this case, the service is up while the program is running and ready to provide the service, and down otherwise. s6-rc calls this kind of service a longrun, and arranges to run the corresponding program as a supervised process using s6 tools.

A service can also be thought of as being provided after some sequence of actions is performed, without involving a long-lived process. For example, making a filesystem available by mounting it, or making a network interface ready for traffic by bringing it up and configuring it with a static address, could also be considered services. In this case the service is up after the corresponding actions are successfully performed. s6-rc calls this kind of service a oneshot, and arranges to perform the corresponding actions in a controlled, reproducible environment. This environment is also set up by an s6 supervision tree even though oneshots do not involve supervised processes. For a oneshot, a transition to down state might mean just doing nothing and 'forgetting' that the corresponding actions were performed, so a subsequent transition to up would simply redo them. Or it might mean performing some sort of inverse procedure, like e.g. unmounting a filesystem or bringing down a network interface.

Services can also depend on other services. This generally means that a service can only transition to and remain in up state only as long as all of the services it depends on are also in up state. The dependencies of a service might in turn have dependencies, creating dependency chains. s6-rc supports dependency specifications and arranges to perform service state transitions accordingly.

Compiled service databases
Performing requested state transitions for a set of services submitted to s6-rc (called the selection) requires it to compute a dependency graph, and then use it to compute, from the full set of managed services, the complete subset of those that need state transitions (called the closed selection), so that the requested operation can be performed while also honoring all dependency specifications. For this purpose, s6-rc stores its managed longruns and oneshots in a compiled service database. This database is a directory that contains a set of files and subdirectories with formats optimized for efficient computation of dependency graphs and closed selections. A compiled database is created with the program. It cannot be modified except by using the program (see live updates to the service database), and can be placed in a read-only filesystem.

accepts the (absoulte or relative to its working directory) pathname of the database to create, and a nonempty set of directory pathnames. These directories must contain service definitions in a format called 's source format. A service definition is a subdirectory, or symbolic link to directory, that must contain a regular file named. This file specifies one of the s6-rc's supported service types: longrun, oneshot and bundle (see service bundles). The contents of a service definition directory depend on the service's type. The name of the directory defines the service name that is used by all s6-rc programs to refer to the service. Service 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.

Currently, also unconditionally adds two s6-rc support services to each compiled service database:, a longrun that is used to implement oneshots (see oneshot definitions), and , a longrun that is used to implement pipelines (see longrun pipelining). Service names that start with s6rc- or s6-rc- are reserved, and fails with an error if it finds one in the submitted service definitions. also ignores, in any of the supplied directories, files that are not directories or symbolic links to directory, and subdirectories with names that start with a dot ('.'). For the full description of, please consult the HTML documentation in the package's subdirectory.

The directory in the package's  subdirectory contains an example set of service definitions in 's source format for a few programs, taken from a working Linux system running Busybox and skarnet.org packages (without private information and without the supporting files elsewhere, like e.g. program configuration files in ).

Longrun definitions
A longrun definition in 's source format is a variation of an s6 service directory. It must contain a file named, and can contain files named , , , , and , with the same meaning and required content as for s6. On the other hand, files are ignored because longruns are managed using s6-rc tools that take care of these files themselves (see later). And subdirectories or symbolic links are ignored too, because their functionality is replaced by pipelines (see longrun pipelining).

The file of a longrun definition must contain the word longrun followed by a newline. A longrun definition can also contain optional, regular files named (see service dependencies),  and  (see managing services). If the service is a member of a pipeline, the definition must also contain a regular file named or, and can contain an optional, regular file named. And finally, a longrun definition can also contain subdirectories named and, for use by the  and  files. Their content is ignored by. is customarily an environment directory used by an invocation in  or, and  is customarily used for other support files. For example, to hold rules directories or rules files for tools like and, or to hold a  file for.

Longrun definitions are 'compiled' by to actual s6 service directories. The program atomatically sets appropriate permissions for files with meaning defined by s6 (e.g. 0755 for and, 0644 for , etc.), so s6-rc service definitions do not need to have them set correctly, it only matters that 's effective user is allowed to read them. The compiled s6 service directories are copied to the live state directory and linked from the scan directory of a running process by the  program (see initializing s6-rc). The and  subdirectories are copied verbatim to the s6 service directory, and  files are created or removed in it as needed by s6-rc programs. For the full description of the longrun definition source format, please consult 's HTML documentation in the package's subdirectory.

Example definition in source format for a longrun named test-longrun:

This service's transition to up state spawns a long-lived process that executes a hypothetical program. It is assumed that it supports the s6 readiness notification protocol when passed an  option. The notification channel's file descriptor is 3, so there is a file specifying that. The file indicates that this service is a longrun, and the rest of the files are standard s6 service directory files. Messages are printed to 's and 's standard output, so that service events can be tracked.

Oneshot definitions
A oneshot definition in 's source format is a directory that must contain a regular file named, and can optionally contain a regular file named. This files encode the actions that must be performed to bring the service to up and down state, respectively. When s6-rc is asked to start or stop the service, it behaves as if it executed a s6-sudo -e supervision-socket up, and s6-sudo -e supervision-socket down command, respectively, where supervision-socket would be the UNIX domain socket of an process that runs with the same environment that is set up for longruns, and has been invoked as s6-sudod execlineb -P. is the script parser and launcher from the execline package. This means that the and  files can have execline syntax (quoted strings, {}-blocks, backslash sequences, #-coments, etc.), and that it is possible to have them contain full execline scripts. However, because a program name that can be found by PATH search, or a program's absolute pathname, followed by program arguments, is a valid execline script, it is possible to use shell scripts for the oneshot's actions by simply invoking them in the and  files.

An absent file is equivalent to an empty  file. Because invoking with an empty file does nothing but making it exit with a 0 code, stopping the corresponding service performs no actions other than updating s6-rc's notion of the service state. The file of a oneshot definition must contain the word oneshot followed by a newline. A oneshot definition can also contain regular files named (see service dependencies),  and  (see managing services). For the full description of the oneshot definition source format, please consult 's HTML documentation in the package's subdirectory.

Oneshot definitions are 'compiled' by to an array of strings, suitable as the 'argv' argument of a POSIX   call. actually performs execlineb-style parsing itself using the execline package's library,. At the time of a service state transition, what s6-rc actually does is perform an invocation with the   option and the UNIX domain socket mantained by an internal support service named. spawns a long-lived process; when a connection is made by an  client to this process' socket, an s6-rc internal program,, is executed with the arguments supplied by the client. accepts an action name ('up' or 'down') and the numerical encoding of a oneshot, that it uses to retrieve the corresponding compiled array of strings from the service database, and makes the  call that actually performs the oneshot's actions. This ensures that the -  mechanism is only used to run, so that only actions explicitly encoded in the database are executed. Because the service is an s6-rc longrun, the corresponding  process is supervised. Therefore, it runs with the environment set up by the s6 supervision tree used for longruns, which is inherited by its child process. This ensures that oneshot's actions are always performed in this known environment, and using 's  option ensures that it is not accidentally modified by the  client's environment. automatically makes a direct dependency of every oneshot. For further information about, please consult the HTML documentation in the package's subdirectory.

Example definition in source format for a oneshot named test-oneshot:

This service's transition to up state executes a hypothetical shell script, located in, with a start argument. Its transition to down state executes the same script, but with a stop argument instead. This shows how to use shell scripts, or any external executable file, with s6-rc. Messages are printed before the script's invocation so that service events can be tracked. The file indicates that this service is a oneshot. The oneshot's actions are actually encoded in :

Service bundles
A service bundle is just a named group of services, created for administrative purposes. Because a bundle is also created with a service definition directory supplied to, and bundle names can be used in most places that expect a service name, the term service is loosely used to also refer to bundles, and the term atomic service is used to refer to either longruns or oneshots, but not bundles, when the distinction matters. In particular, bundles can be used to implement runlevel-like functionality if so desired, combined with the command (see service dependencies). For examples of this, see live updates to the service database.

A service bundle definition in 's source format must contain a regular file named. The file of a bundle definition must contain the word bundle followed by a newline. The file must contain a list of service names, one per line. Whitespace at the beginning of a line is ignored, but trailing whitespace is not. Lines starting with a hash sign ('#') are ignored. The service bundle will cointain all services named in. Names that refer to other bundles can be used in ; interprets them as referring to the set of atomic services contained in the named bundle. For the full description of the bundle definition source format, please consult 's HTML documentation in the package's subdirectory.

Example definition in source format for a service bundle named test-bundle:

This bundle is comprised by atomic services test-longrun and test-oneshot. The file indicates that this service is not an atomic service, but a bundle.

Extracting information from a compiled database
Because the format of an s6-rc compiled service database is not human-readable, the package provides the program for analyzing a compiled database, extracting information from it, and printing it in a user-friendly format. By default, the database read by is the one currently associated with live state directory  (see managing services), unless it is passed an   option followed by the (absolute or relative to the working directory) pathname of a different live state directory, or it is passed a   option followed by the pathname of the database.

accepts a subcommand that tells it what to print. Some of these subcommands are:


 * help: prints a help message.
 * list: lists service names that satisfy some condition specified by the subcommand's argument:
 * all (i.e. s6-rc-db list all ): lists the names of all atomic services and service bundles contained in the database.
 * services: lists the names of all atomic services contained in the database, i.e. the list does no include service bundle names.
 * bundles: lists the names of all service bundles contained in the database.
 * longruns: lists the names of all longruns contained in the database. This includes the s6-rc supporting services automatically added by.
 * oneshots: lists the names of all oneshots contained in the database.
 * type: displays the type of the service ('oneshot', 'longrun' or 'bundle') corresponding to the name supplied as the subcommand's argument.
 * contents: displays the list of atomic services contained in the service bundle corresponding to the name supplied as the subcommand's argument.
 * atomics: displays the fully resolved list of atomic services represented by a list of service names supplied as the subcommand's arguments. If a name in the list is the name of an atomic service, the output will simply include that service's name, but if it is the name of a bundle, the corresponding output will include the names of the atomic services contained in the bundle. This computation of a list of atomic services is also performed by the program, see managing services.
 * script: displays the actions executed during state transitions of the oneshot corresponding to the name supplied as the subcommand's argument. If a  option is passed to  (before the subcommand name), the output is the string sequence produced by 's parsing of the  file from the oneshot's definition in 's source format. If a   option is passed to, the output is the string sequence produced by 's parsing of the  file from the oneshot's definition. If there is neither a   option nor a   option,  behaves as if the   option had been specified. Each string in the sequence is terminated by a null character, so it is usually necessary to pipe 's output to something like.

Other subcommands can be used to display dependency information (see service dependencies), state transition timeouts (see managing services) and pipeline information (see longrun pipelining). For the full description of, please consult the HTML documentation in the package's subdirectory.

Example directories srv-src1 and srv-src2 containing service definition subdirectories in 's source format:

Directory srv-src1 contains definitions for the example services described in previous sections. Directory srv-src2 contains another set of service definitions. all-services is a bundle:

Note that the file contains names of both atomic services (another-longrun and another-oneshot) and bundles (test-bundle).

An s6-rc compiled service database test-database1 can be created from and  by invoking  with their pathnames as arguments:

The  option is needed so that the  program can be used to manage oneshots by the nonprivileged user that created the database. The  option makes the output of  more verbose. The resulting database is a directory:

The subdirectory contains the s6 service directories generated for all longruns, including those of automatically included s6-rc supporting services:

This shows that the and  are executable, as expected by, even if the corresponding ones in the s6-rc service definition were not. Listing all service names in the resulting compiled database:

This shows that the created database contains the union of the services defined in subdirectories of, and the services defined in subdirectories of. Listing service names by type:

Displaying the type of different services:

Displaying the contents of service bundles:

This shows that, because the file in the definition of bundle  named the bundle, all atomic services contained in the latter became members of the former. Displaying the string sequence compiled from the and  files of a oneshot:

Notice the result of execlineb-style processing: the quoted strings that were arguments of the utility become single elements in the compiled sequence of strings even if they contain whitespace, and {}-blocks become a sequence of arguments that start with a space, terminated by an empty string, a format recognized by all execline programs, including.

Resolving some atomic service sets:

This shows that because is an atomic service, it is included as-is in the output, and because  is a bundle, it is replaced in the output by the set of atomic services it contains.

This shows that bundle all-services is replaced by the set of atomic services it contains, and because that includes, this service is listed only once.

Initializing s6-rc
s6-rc must be initialized with a compiled service database and an s6 supervision tree, that is used to supervise longruns and to provide the environment used for performing oneshots' actions. The program that performs this initialization is.

accepts the absolute pathname of a scan directory, that must have a corresponding process already running. The service database is assumed to be. A different (absolute) pathname can be specified with the  option. creates a live state directory that associates the s6-rc service database with the s6 supervision tree, and keeps track of service states. The live state directory must be in a read-write filesystem, and defines an s6-rc 'instance'. The live state directory is by default; a different (absolute) pathname can be specified with the   option. is actually a symbolic link to a directory created by in ; this is necessary for the operation of the  program (see live updates to the service database). Similarly, if the  option is used,  it will create both a symbolic link with that pathname, and a subdirectory in the directory containing the symlink.

A compiled database becomes associated with a live state directory by using, or  is said to be live. A database that is not live can be freely moved around in the filesystem, but once it becomes live, it must not move anymore and must not be deleted. A database stops being live if it is deassociated from the live state directory by or, or if the corresponding s6 supervision torn down (e.g. by ).

The s6-rc live state directory also contains a copy of the compiled s6 service directories of all longruns contained in the service database. creates a symbolic link to each of them in the specified scan directory, so that the corresponding program can be run as a supervised process, and performs the equivalent an command to make  perform a scan. The initial state of all atomic services after the invocation of is down. In the case of longruns, enforces this by creating  files in each of their service directories, so that their  processes do not execute the  file. also accepts a  option followed by a prefix, that prepends the specified prefix to the name of every longrun when creating the symlinks in the scan directory. For example, if a longrun's name is name, s6-rc-init -p instance-1: will name the symlink instance-1:name. This allows the sharing of single s6 supervision tree among different 'instances' of s6-rc, i.e. a set of s6-rc-managed services associated with different live state directories.

The s6 supervision tree processes that correspond to and  use UNIX domain sockets, and s6 access control tools to decide whether to grant or refuse service to clients that connect to these sockets. By default, they only grant access to root, but this can be modified by passing  and   options to, followed by a comma-separated list of numerical user IDs and group IDs, respectively. These options are used to construct rules directories: user IDs specified with  are used for the  subdirectory, and group IDs specified with   are used for the  subdirectory. If any of these options are used, root's UID or the GID of a group it is a member of must be explicitly specified to grant it access. For further information about, please consult the HTML documentation in the package's subdirectory.

Example s6 scan directory containing a supervised logger with a FIFO, that logs supervision tree messages in a similar way to that of the catch-all logger of an s6 and s6-rc-based init system:

Starting the supervision tree, assuming that the working directory is the scan directory:

Initializing s6-rc with this supervision tree and the example database test-database1 from section "extracting information from a compiled database", assuming that it is located in :

This creates the live state directory in, and, as shown, symbolic links in the scan directory.

This shows that is actually a symbolic link to a subdirectory of :

Updated supervision tree:

This shows that none of the longruns is in up state: only their supervisor is running. Service directory of test-longrun:

This shows that created a  file. Subdirectories and  are created by the corresponding  process (process 2471 in this example). From s6's point of view, the service is down:

Another example using prefixes:

Service definitions in directories srv-src1 and srv-src2 are now compiled to separate databases, db-instance-1 and db-instance-2. The definition directory of bundle all-services was renamed to start with a dot so that ingores it. After changing to scan directory and starting a supervision tree again with command redirfd -wnb 1 logger/fifo s6-svscan & :

This shows that the symbolic links to the s6 service directories have different prefixes depending on which live state directory the corresponding logrun is associated with. Live state directory is associated with compiled service database db-instance-1, and live state directory  is associated with compiled service database db-instance-2. Each of these can be thought as a different s6-rc 'instance', even if they share the same s6 supervision tree and scan directory. The corresponding services are independent:

Managing services
The s6-rc package provides one program, also named, to perform most of the service management tasks after initialization has been done. accepts a subcommand that specifies what to do. The subcommands are:


 * help: prints a help message.
 * list: displays the fully resolved list of atomic services represented by a list of service names supplied as the subcommand's arguments, the same way as (see extracting information from a compiled database). This list of atomic services is called the selection.
 * change: computes the selection in the same way as the  subcommand, and performs state transitions for all atomic services in the resulting list. If a   option ('up') is passed to  (before the subcommand name), the requested action is to start all services in the selection, i.e. transition them to up state. If a   option ('down') is passed to, the requested action is to stop all services in the selection, i.e. transition them to down state. If there is neither a   nor a   option,  behaves as if the   option had been supplied. If an   option ('dry run') followed by an integral value is passed to , state transitions are simulated instead of actually performed (see later).
 * diff: checks the consistency between s6-rc's view of the service state of all longruns (as recorded in the live state directory), and s6's view (as recorded in the file of the service's  control directory). This subcommand should normally report nothing, but directly using some s6 programs with s6-rc-managed longruns can cause state discrepancies. For example, if a longrun is in down state, and an  command with the pathname of the service's symlink in the scan directory is used instead of an  command with its service name, not only would that run the underlying program (without also starting services that were specified as dependencies), but it would also make s6 view the process' state as up (as reported by ), while s6-rc would still view the corresponding service as down. The   subcommand prints a line for each longrun it finds that has a state inconsistency, prepended by a plus sign ('+') if s6 considers it to be up, and a minus plus sign ('-') if s6 considers it to be down.
 * listall: displays the computed closed selection, see service dependencies).

Unlike, which operates exclusively on a compiled database, operates on the live state directory. Therefore, it has knowledge of not only the associated database, but also of service states. The live state directory is by default, but a different one can be used by passing an   option to  with the directory's pathname (absoulte or relative to 's working directory). can be used both with live and non-live databases, but in the latter case, the database's pathname needs to be specified with a  option.

Because is aware of service states, it accepts an   ('active') option for both its   and   subcommands, that adds the current set of atomic services in up state to the initial selection derived from the subcomannd's arguments. also accepts the  option for its   subcommand, but the meaning in this case is to complement the initial selection, i.e. the final selection is the set of all atomic services in the live state directory's associated database that are not in the initial selection. For completeness, also accepts an explicit   option for its   subcommand, that does nothing. For both  and , the supplied list of service names can be empty, meaning an (initial) empty selection. is mostly useful in conjunction with the  or   options.

s6-rc also has a notion of transition success and transition failure. For a longrun, if its underlying program supports the s6 readiness notification protocol, transition to up state is considered successful if the supervised process is up and ready before the expiry of a timeout. Otherwise, transition to up is considered successful if the supervised process is up before the expiry of a timeout, i.e. when its supervisor has spawned a child. The command uses an  command or  command, respectively, to start the supervised process, so it will wait until it receives a notification of the relevant event from. Transition to down state is considered successful if the supervised process is really down before the expiry of a timeout, i.e. if it is down and the file, if present, was executed and has exited (or got killed by ). The command uses an  command to stop the supervised process, so it will wait until it receives the really down notification from. If a transition to up fails, the command then uses an  command to bring the supervised process to a known down state. For a oneshot, transition to up or down state is considered successful if the equivalent of executing the or  file from its service definition, respectively, that is performed by the  program, exits with code 0 before the expiry of a timeout (see oneshot definitions). The command waits for  to finish. For the full description of the program, please consult the HTML documentation in the package's  subdirectory.

s6-rc supporting service uses a rules directory to decide whether to grant or refuse service to clients that connect to its UNIX domain socket. The program executes a  command with 's socket to start or stop a oneshot, so 's effective user must be allowed by this service's rules directory. Setup of 's rules directory can be done using 's  and   options, see initializing s6-rc.

The timeout for a state transition can be configured by including regular files named and  in the definition of an atomic service submitted to, that must contain an integral time value in milliseconds. The former specifies the timeout for the transition to up, and the latter, for the transition to down. If any of these files is absent or contains the value 0, the corresponding timeout is infinite, i.e. the command will wait forever for the notification of the relevant event from  in the case of a longrun, and will wait forever for  to exit, in the case of a oneshot. For further information about configuration of state transition timeouts, please consult 's HTML documentation in the package's subdirectory. The timeout subcommand of the program prints the state transition timeouts. The up timeout is printed if the  option is passed to, and the down timeout is printed if the   option is passed to. If there is neither a  option nor a   option,  behaves as if the   option had been specified. For further information, please consult 's HTML documentation in the package's subdirectory.

calls the internal program instead of  or  when the   option is specified, which makes  print to standard output what the command would have done without the   option. The option must be followed by integral time value in milliseconds; will sleep for the specified time before exiting, to simulate an  or  invocation that does not complete immediately. For further information about, please consult the HTML documentation in the package's subdirectory.

Example usage of to print list of all atomic services in the live compiled database, assuming the setup from the first example of section "initializing s6-rc":

This works because no service names are provided, so the initial selection is empty, and then the  option complements the selection. The complement of the empty set is 'the universe', i.e. the set of all atomic services in the compiled database. So it is the same as using an s6-rc-db -l ../live list services | sort command. Simulating a transition to up for service test-longrun:

The service is a longrun, and this shows that it would be started with an command. Option  makes the command wait for an up and ready notification from. Actually starting the service:

This shows that waited the approximately 10 seconds that were necessary for  become ready and notify.

This shows that the file created by  was removed from 's compiled s6 service directory by the  command. Simulating a transition to up for service test-oneshot:

The service is a oneshot, and this shows that it would be started with an command that connects to the UNIX domain socket in supporting service 's s6 service directory, an passes arguments 'up' and '3'. This in turn triggers execution of an command. The output of is intended to be human readable, so it shows that numerical identifier 3 corresponds indeed to service  in the compiled service database. Because is a dependency of  and was in down state,  would start it first (see service dependencies), and because  is a longrun, it would use an  command to do that. Actually starting the service:

Because the -  mechanism is used for s6-rc-managed oneshots, and  transmits the file descriptors of its standard input, output and error to  via fd-passing, messages from the oneshot's executed programs are printed on 's standard output, which is the interactive shell's controlling terminal in this case. Displaying the list of atomic services in the up state:

This works because no service names are provided, so the initial selection is empty, and then the  option adds the set of atomic services in up state to it. It is also shown that is now also in up state.

Service bundle names can be used with as a substitute of their contained atomic services:

This shows that stopping bundle test-bundle is the same as individually stopping and. would be stopped with an command; option   makes the command wait for a really down notification from. would be stopped with an command that connects to the UNIX domain socket in supporting service 's s6 service directory, an passes arguments 'down' and '3'. This in turn triggers execution of an command.

This shows that stopped all atomic services contained in the bundle.

This shows that created a  file in this longrun's s6 service directory.

Here the resulting selection of the command is the contents of bundle all-service, so that's what is shown. It is the same as using an s6-rc-db -l ../live atomics all-services | sort command. Starting all atomic services in this selection:

Updated supervision tree:

This shows that longrun another-longrun just spawns another process, with readiness notification turned off, and that  launches an  process that, in turn, spawns an  child for each client connection to its corresponding socket. executes program with the arguments supplied by the client.

Service another-longrun is now actually in down state, because the underlying program is no longer running, but s6-rc doesn't know about it. This type of inconsistencies can be reported by an command:

The minus sign ('-') confirms that s6 considers it down. A subsequent command that that contains another-longrun in its closed selection (see service dependencies) will bring the service state in sync again:

The command uses an  command, which is equivalent to. The command is a no operation, since the service is already down, and the  command will return immediatly for the same reason. But the service state is now also down in s6-rc's view, so the the output of is empty.

Stopping all services in the live compiled database:

Requesting a list of atomic services in the up state should now return an empty result:

This shows all of 's state transitions, as shown by messages printed by its and  scripts and logged by the supervised  process. To demonstrate usage of once more, service test-longrun can transition to up with an  command without s6-rc noticing:

The plus sign ('+') confirms that s6 considers it up. Consistency can be restored by using an s6-rc -ul ../live change test-longrun command to align s6-rc's view of service state with s6, or an s6-svc -d test-longrun command to align s6's view of service state with s6-rc.

Service dependencies
s6-rc supports the specification of dependencies between services. Service A can be defined to directly depend on service B, with the following meaning:


 * If s6-rc it is asked to start A, then B is automatically started first, and if that transition was successful, the requested operation is performed.
 * If s6-rc it is asked to stop B, then A is automatically stopped first, and if that transition was successful, the requested operation is performed.

Therefore, transition failures (see managing services) might result in not performing the requested operation, leaving the service in the state it was before.

In turn, a service's dependencies can have dependencies themselves, forming dependency chains: if service A directly depends on service B, and B directly depends on service C, then service A is said to depend (with no qualification) on both B and C. The aforementioned procedure for state transitions is performed recursively when there are dependency chains, so asking s6-rc to start A will result in a cascade of transitions to up to honor dependencies: C first, B second, A last. Similarly, asking s6-rc to stop C will result in transitions to down for A, B and C, in that order. This means that dependencies introduce, for the purpose of state transitions, a partial ordering of services. The command parallelizes the transitions as much as it can. Independent services are processed in parallel, but ordering constraints introduced by dependencies may result in serial processing for one or more subsets of services.

A service definition in 's source format can specify direct dependencies by including a regular file named, that must contain a list of service names, one per line. Whitespace at the beginning of a line is ignored, but trailing whitespace is not. Lines starting with a hash sign ('#') are ignored. Only atomic service definitions can contain a file, service bundle definitions cannot. files can contain service bundle names; s6-rc considers the service being defined to directly depend on every atomic service contained in the specified bundle. For further information about configuration of service dependencies, please consult 's HTML documentation in the package's subdirectory.

Because dependencies may cause state transitions for services that are not in the computed selection of an command, the  program must also compute a forward dependency graph for transitions to up, or a reverse dependency graph for transitions to down, and then it must computed the closed selection, which is the set of all atomic services in the database that need a state transition. An atomic service is in the command's closed selection if:
 * it is in the selection, or
 * a service in the selection depends on it and the requested operation was to start services, or
 * it depends on a service in the selection and the requested operation was to stop services.

The format of a compiled service database allows to perform these computations efficiently. Dependency correctness, i.e. the absence of dependency cycles in the submitted set of service definitions, is verified by at the time of database creation.

The program (see extracting information from a compiled database) has two subcommands that display depencency information:
 * dependencies: displays the direct dependencies of the service corresponding to the name supplied as the subcommand's argument. If the name corresponds to a service bundle, it displays the union of the direct dependencies of all the atomic services contained in the bundle.
 * all-dependencies: displays the fully resolved list of atomic services represented by the list of service names supplied as the subcommand's arguments, in the same way as the  subcommand, and all services in either the forward or the reverse dependency graph. The forward dependency graph is used if the   option is passed to, and the reverse dependency graph is used if the   option is passed to.

Finally, the program has a listall subcommand that displays the closed selection computed from the service names supplied as arguments. Since this is done with a depencency graph, the result is the same as that of s6-rc-db all-dependencies, except that the latter can also be used with a compiled database that is not live. The forward dependency graph is used if the  option is passed to, and the reverse dependency graph is used if the   option is passed to. If a  option ('prune') is passed to  combined with the   command, if a transition to up was requested, services in the computed closed selection are started and every other service not in down state is stopped. If a transition to down was requested, services in the computed closed selection are stopped and every other service not in up state is started. In both cases, all transitions to down are performed before all transitions to up.

For further information about the and  programs, please consult the HTML documentation in the package's  subdirectory.

Example set of service defitions with dependencies:

Dependency specifications for this set of services are set up according to this diagram: A <-- B <--+ D          | C <--+

E <-- F

G

Legend  means "Y directly depends on X". This diagram shows that service D depends on services A, B and C. Service A is a longrun with no dependencies:

The underlying program is a hypothetical program that supports the s6 readiness notification protocol when passed an   option. The notification channel's file descriptor is 3, so there is a file specifying that. The time taken by this service to be up and ready is the value of environment variable LONGRUN_TIME (1 second if unset), plus the actual time takes to be up and ready. A timeout value of 15 seconds (15000 milliseconds) is set for this service's transition to up. The environment is set by the s6 supervision tree and modified by the contents of environment subdirectory, which will be copied verbatim to service A's compiled s6 service directory. Both the and  scripts print messages to standard output, so that service events can be tracked.

Service B also runs, and has service A as a direct dependency:

Service C is a oneshot with no dependencies that prints messages to standard output, so that service events can be tracked, but does nothing else:

The and  files contain full execline scripts in this case. The former can have different exit codes depending on environment variable ONESHOT_STATUS (0 if unset). The environment is set by the s6 supervision tree, inherited by, and modified by the contents of environment directory. Because oneshots don't have a corresponding s6 service directory, this envdir must be elsewhere, and specified via an absolute pathname. invocations are used to prepend a timestamp to printed messages.

Service D also runs with readiness notification turned off, and has two direct dependencies:

This means it has both a longrun (service B) and a oneshot (service C) as dependencies.

Service E is a longrun with no dependencies:

This execline script exits 1 if environment variable LONGRUN_FAIL has the value yes, and runs  otherwise. The environment is set by the s6 supervision tree and modified by the contents of environment subdirectory.

This execline script exits 125 if environment variable LONGRUN_FAIL has the value yes, signalling permanent failure to.

Service F is a oneshot that only prints messages to standard output, and that has a longrun as its direct dependency:

And finally, service G is a longrun with no dependencies and no relation with any other service, that also runs with readiness notification turned off:

Creating an s6-rc compiled database with this set of services and using to show direct dependencies:

Note that for every oneshot the implicit dependency on service s6rc-oneshot-runner is also displayed (see oneshot definitions). Initializing s6-rc, assuming that there is a supervision tree with as the scan directory and with a logger like in the example from section "initializing s6-rc", that database test-database2 is in, and that the working directory is the scan directory:

Here 's selection is the same as the list of services provided as arguments, because they are all atomic services, and shows the resulting closed selection using the forward dependency graph: services D, F and G are included because they are in the selection, services A, B and C are included because they are dependencies of service D, service E is included because it is a dependency of service F, and  is included because services C and F are oneshots and depend on it. An s6-rc-db -ul ../live all-dependencies service-{D,F,G} | sort command would have produced the same output. Simulating the transition of services to up state:

Services D and G are longruns that don't use readiness notificacion, so 's  option (wait for the up notification) is used instead of   (wait for the up and ready notification). An because service A's definition specified an up timeout of 15 seconds, the corresponding invocation uses a   option instead of   ("infinite").

Actually starting the services:

This shows how tried to paralellize state transitions as much as it could: services A, C, E and G were started immediately and in paralell, but services B, D and F were not. Service B's transition happens approximately 11 seconds after service A's, because it is a dependency and that is the time it took service A to become up and ready, and service D's transition happens approximately 10 seconds after service B's for the same reason. It didn't happen later than that because its other dependencies, services A and C, had already successfully transitioned to up. Service F's transition happens approximately 10 seconds after service E's, because it is a dependency and that is the time it took service E to become up and ready. Service D's, F's, and G's transitions are almost instant, because service F is a oneshot, and services D and G do not wait for readiness, so the whole operation took about 21 seconds, and finished after service D's transition to up. Because all state transitions were successful, all services in the selection are now in up state. Stopping all services:

This shows that most state transitions were almost instant except service F's, because of the command in its  file. Service E's transition happens after service F's transition completed because it is a dependency, so the whole operation took about 10 seconds and finished after service E's transition to down.

Forcing a rotation of the logging directory with an command so that the  file gets emptied, and redoing the steps with one modification:

This shows that the attempt to start service A failed: an extra delay of 10 seconds caused by the setting of environment variable LONGRUN_TIME caused the transition to take longer than the maximum 15 seconds configured in its service definiton. And because of that failure, services that depend on service A were not started -in this case, services B and D-. The whole operation took about 15 seconds and finished after service A's transition timed out. The final "Service A stopping" message in the log is caused by the extra command that  executes for longruns that fail to start.

This shows that after the command, services A, B and D are not in up state. Stopping all services with an s6-rc -dal ../live change, forcing another rotation of the logging directory, and redoing the steps with more modifications:

This shows that the attempt to start service C failed: the equivalent of executing the file of its service definition that program  performs exited with a nonzero code (7), caused by the setting of environment variable ONESHOT_STATUS. And because service D depends on service C, the former was not stated. The whole operation took about 21 seconds and finished after service B's transition to up.

This shows that after the command, services C and D are not in up state. Stopping all services, forcing another rotation of the logging directory, and redoing the steps with more modifications:

This shows that the attempt to start service E failed: the setting of environment variable LONGRUN_FAIL to yes caused the script in its s6 service directory to exit immediately, and the  script to exit with code 125, which signals permanent failure to s6. And because service F depends on service E, the former was not stated. The whole operation took about 21 seconds and finished after service D's transition to up.

This shows that after the command, services E and F are not in up state.

Live updates to the service database
The s6-rc package provides a program,, that allows adding or removing service bundles to or from a compiled database, without having to recompile it from source using. It is also notable in that it can be used even if the database is live, i.e. already associated with an s6 supervision tree and an s6-rc live state directory. accepts a subcommand that tells it what to do:
 * add: adds a service bundle to the database. It accepts a list of service names: the first one is the name of the bundle, and the others are the contents of the bundle. The effect is the same as that of a bundle definition in 's source format that contains those service names in the file.
 * delete: removes a service bundle from the database. It accepts a single argument specifying the name of the bundle.
 * multiple: allows removal and addition of several service bundles in one go. It expects its arguments to be in the format execline's program generates when parsing the block syntax, so the forward compatible way to use it is in an execline script or  command: the invocation can be written using a the syntax s6-rc-bundle multiple { d1 d2 ... } n1 { c11 c12 ... } n2 { c21 c22 ... } ..., where d1, d2, ... are service names specifying bundles to delete, n1, n2, ... are service names specifying bundles to add, c11, c12, ... are service names specifying the contents of bundle n1, c21, c22, ... are service names specifying the contents of bundle n2, and so on. The list d1 d2 ... can be empty, resulting in no deletions. Everything after the first {}-block can be ommited, resulting in no additions.

operates on the database associated with live state directory, unless it is passed an  option followed by the (absolute or relative to the working directory) pathname of a different live state directory, or it is passed a   option followed by the pathname of a database. For more information about, please consult the HTML documentation in the package's subdirectory.

Using is the only way to modify a compiled database. Any other modification has to be done on the service definitions in source format that were used to create the database, and then must be used to make a new database. Because a database that is live cannot be deleted, the s6-rc package provides a tool that allows its replacement: the program, an online service database switcher. If the replaced database contained a service that is not present in the replacing database, the affected service will be deleted: its name will no longer be recognized as valid by tools like the and  programs. Therefore, the replacing database must contain all wanted services, both modified and unmodified ones, and generally means that service definitions in 's source format must be kept around.

accepts the replacing database's absolute pathname as an argument, and performs the database switch for live state directory, unless it is passed an  option followed by the absolute pathname of a different live state directory. It also ensures consistency of service states: it analyses both the replaced and replacing database's contents to determine which services are present in both (based on name), and preserves their corresponding state, except for services that change types (longrun to oneshot and vice-versa, atomic service to bundle and vice-versa) or direct dependencies. In those cases, if the service is in up state at program startup, restarts it: it stops it before the database replacement, and then starts it after the database replacement, so if there are new services defined as direct dependencies,  starts them too after the database replacement. Deleted services are stopped before the replacement.

also accepts an  option followed by the pathname of a file, the conversion file, that can currently be used for two purposes: service renaming and forced restarts. The file must contain a sequence of lines of text, each of which is independently lexed into words as if by the program, so it can contain #-comments, quoted strings, etc. Lines of the form   rename service old-service to new-service. Therefore, all appearances of name old-service in service definitions of the replaced database, and all appearances of name new-service in service definitions of the replacing database, are understood to refer to the same service for the purpose of computing needed state transitions. Otherwise, they are considered to name unrelate services. Lines of the form  makes  forcibly restart service service-name, and lines of the form   make  perform both a rename and a forced restart.

performs the computed state transitions using an command before the database switch, and an  command after the database switch. It also accepts an  ('dry run') option that makes it simulate the state transitions without switching the database, printing the  invocations to standard output with the  internal program. For the full description of, please consult the HTML documentation in the package's subdirectory.

Finally, s6-rc provides the program, that can be used to upgrade the format of a compiled service database that is live and was created with an earlier incompatible version of. It is intended to be used after upgrading the s6-rc package to a backwards-incompatible version, without disrupting the live state directory and associated s6 supervision tree (e.g. if s6-rc is used as an init system component) and currently works for upgrades from version 0.3.0.0 to version 0.4.0.0. It actually performs a database switch like does, it accepts the absolute path of a compiled database, and operates on live state directory, unless it is passed an   option followed by the (absolute or relative to the working directory) pathname of a different live state directory. For more information about, please consult the HTML documentation in the package's subdirectory.

Example usage of, assuming the setup from section "service dependencies", and assuming that the working directory is the scan directory:

List of services in up state:

The associated service database is going to be replaced by one created from this set of service definitions in 's source format:

This shows that directories containing service definitions are allowed to have symbolic links to files and directories placed elsewhere. The new database is mostly the same as database test-database2, except that it contains no service A, so it will be removed after the database switch, renames service C, and turn service E into a oneshot. So all references to service A must be removed, and all references to service C must use the new name:

Service A is gone from, and so is file. Service E needs a new definition:

To actually rename service C, a conversion file must be supplied:

Compiling the new database using an s6-rc-compile -u $(id -u) test-database3 srv-src4 command, assuming it will be placed in along with the conversion file, and simulating the effect of invoking :

This shows that would use an  command to stop some services, switch the database, and then use an  command to start some other services, which implies that (possibly updated) dependency specifications would be honored. Actually performing the database switch:

This shows that because service E changes type, the original longrun was stopped, and the new oneshot was started. Longruns' messages appear in the supervision tree's logging directory, but because of 's fd-passing, oneshots' messages are printed to 's standard output. Therefore, the "Service E stopping" and "Service E starting" messages appear in different places. This also shows that because service A was removed, it was stopped first, and because services B and D depended on it and were up before the database switch, both were restarted. Note that transitions to down have to be serial in the order D, B, A, and transitions to up have to be serial in the order B, D. Finally, because service F continues to depend on service E, and the latter had to restart, F was restarted too, again using serial transitions. Service F was stopped first, and service E was stopped about 10 seconds later, because that was the duration of service F's transition. Then, after the database switch, their transitions to up were almost instant. The whole operation took about 20 seconds: 10 to stop service F plus 10 to start service B.

The symbolic link to the live state directory was updated:

The output of previously showed. The s6 scan directory has also updated all symbolic links:

There is neither a symlink, because the corresponding service no longer exists, nor a  symlink, because the corresponding service is no longer a longrun.

This shows that, except for service A, the same set of services are in up state after the database switch, and that the renaming of service C has been performed indeed. Note that the service has not been restarted; there were no "Service C starting" or "Service C stopping" messages printed to 's standard output.

One more example with another set of service definitions:

Service B is is going to be renamed, and a new service H is going to be created as a dependency of service D:

Service H is a longrun with no dependencies that runs program with readiness notification turned off:

Conversion file for renaming service B that also forces a restart of service G (which is otherwise unmodified):

Compiling a new database with these service definitions using a s6-rc-compile -u $(id -u) test-database4 srv-src5 command, assuming it will also be placed in along with the conversion file, forcing a rotation of the supervision tree's logging directory with an s6-svc -a logger, and then performing the database switch:

This shows that service G was restarted indeed because of the conversion file, but also service D, because it was in up state before the database switch and its dependencies changed: service H was added as a direct dependency after the database switch. On the other hand, service B was only renamed, so it didn't restart. The whole operation took place almost instantly, because not waiting for readiness notification makes service D's, G's and H's transitions almost instant.

This shows that the live state directory symlink was modified once again; the output of previously showed

This shows that the symlink for service B in the s6 scan directory was renamed, and that a new symlink was created for service H.

This shows again that the same set of services are in up state after the database switch, and that the renaming of service B has been performed indeed. Adding two runlevel-like bundles to the compiled service database while it is live:

This shows that both bundles were simultaneously added. It is equivalent to using an s6-rc-bundle -l ../live add runlevel-X service-D command followed by an s6-rc-bundle -l ../live add runlevel-Y service-F service-G command. Forcing another rotation of the supervision tree's logging directory, and then using an s6-rc -pu change command to emulate a runlevel change:

This shows that only atomic services members of bundle runlevel-X are now up. Deleting the bundle from the compiled service database:

This shows that only bundle runlevel-Y remains. It is equivalent to using an execlineb -Pc 's6-rc-bundle -l ../live multiple { runlevel-X }' command. Performing another 'runlevel change':

This shows that atomic services members of (former) bundle runlevel-X were stopped, and only atomic services members of bundle runlevel-Y are now up.

Longrun pipelining
The s6 supervision tools support the daemontools mechanism that allows connecting the standard output of a supervised process to the standard input of another one with a pipe, normally for logging purposes. This mechanism is used when a subdirectory or symbolic link to directory named is present in a service directory. s6-rc generalizes this idea with pipelines: it allows arbirary length chains of longruns that have their standard output connected to the standard input of the next one in the chain with a pipe. Moreover, as of version 0.4.0.0, s6-rc also allows tying the standard input of a longrun with the standard output of two or more other longruns, so that multiple streams of messages from different supervised processes can be collapsed into a single stream. This means that s6-rc pipelines are really funnels, but the name 'pipeline' is retained for compatibility with earlier versions that did not support this feature.

The program creates pipelines when the definition directories of their member services contain regular files named  and. A file must contain a single service name; the standard output of the service being defined will then be connected to the standard input of the service named in the file as a result. s6-rc requires that the definition directory of the latter also contain a file that names the former, and  implicitly makes the latter a direct dependency of the former, as if by the presence a  file. This ensures that if the pipeline mechanism is used for logging, loggers will be up before starting the 'main' services. A file must contain a list of service names. If more that one service is named in a file, the funnel-style collapsing of message streams will take place. Pipeline consistency, e.g. absence of collisions or cycles, is verified by at service database creation time, as well as the existence of a  file in the definition of each service named in a  file, and a  file in the definition of each service named in a  file. To create a logging chain with s6-rc services, definitions of 'main' services must contain a file naming their loggers, and the loggers must be created just like any other s6-rc service, with definitions that contain a  file naming (only) their main services.

The definition directory of a service with a and no  file, named the corresponding pipeline's last consumer, can also contain an optional, regular file named, that must contain a single service name;  will then create a service bundle with this name that contains all the services that are members of the pipeline. A in the definition directory of a service that is not a pipeline's last consumer is ignored. For further information about pipelines, please consult 's HTML documentation in the package's subdirectory.

s6-rc implements pipelines using an internal support service named s6rc-fdholder. This service spawns a long-lived process that executes the program, i.e. the fd-holder daemon from s6, and runs an internal s6-rc program,, chained from. is a short-lived UCSPI IPC client, that reads a file containing service names, creates a pipe for each of them using the POSIX  call, connects to the socket of an  process, and transfers the file descriptors associated with the reading and writing end of all pipes to the server with a set dump operation, i.e. as if by. The file with service names is created by in 's s6 service directory. also automatically makes a direct dependency of every longrun that is a member of a pipeline, and creates a wrapper  execline script in their compiled s6 service directory. The wrapper script retrieves the file descriptors that correspond to the reading and / or writing ends of the pipes the service needs with invocations, and then executes the actual  file supplied in its s6-rc definition (currently installed as  in the compiled s6 service directory). The same happens with the file, if there is one. For further information about, please consult the HTML documentation in the package's subdirectory.

uses a rules directory to decide whether to grant or refuse service to clients that connect to its UNIX domain socket of its process. The effective user of all processes in an s6 supervision tree is initially that of. The process of every longrun that is a member of a pipeline will spawn a child process that executes the wrapper  execline script that contains  invocations, so 's effective user must be allowed by 's rules directory. Setup of this rules directory can be done using 's  and   options, see initializing s6-rc. If 's effective user is root, the effective user of the process can be adjusted by passing an   option to  followed by an account's username; 's  script will then include an  invocation to drop privileges. For further information about, please consult the HTML documentation in the package's subdirectory.

Finally, the program (see extracting information from a compiled database) has a pipeline subcommand that displays information about the pipeline that the service corresponding to the name supplied as the subcommand's argument is a member of. If the service is not a member of a pipeline, it just prints the name supplied as argument. For further information about, please consult the HTML documentation in the package's subdirectory.

Example set of service definitions using pipelines:

Service A spawns a process that executes a hypothetical program. It is assumed that this program prints a message of the form "Message #N", where N is an incrementing number, each time it receives a  signal.

Reader A spawns a process that reads lines of text from its standard input and prints them to its standard output, prepended with the string "This comes from service A:":

Service A's standard ouput is connected to reader A's standard input with a pipe. Service B and reader B constitute a similar pair of services:

And finally, service final-reader spawns an process. Messages read from its standard input are logged in logging directory :

The s6-rc pipeline ties reader A's and B's standard output with this logger's standard input:

This service is the last consumer, so it has a file that specifies a name for the pipeline:

A diagram that represents this pipeline: service A --> reader A -->+ | service B --> reader B -->+ |                         +--> final-logger

After creating a database with these service definitions using a s6-rc-compile -u $(id -u) test-database5 srv-src6 command:

This shows that the database contains an actual service named service-AB-pipeline, and that it is a bundle. must be invoked with an  option so that the nonprivileged effective user of each longrun's process is allowed to retrieve the file descriptors associated with this pipeline from the fd-holder.

This shows that the bundle contains all services associated this pipeline.

This shows that made  a direct dependency of all members of the pipeline and made each service associated with the  writing end of a pipe a dependency of the service associated with the corresponding reading end.

Starting all the services after launching an s6 supervision tree and initializing s6-rc, assuming that the working directory is the scan directory and that is the relative pathname of the live state directory:

This shows that all services in the pipeline are now in up state, including, which is a supervised process. Sending a few  signals to the  processes that correspond to services A and B:

This shows that all messages passed through the pipeline and got logged in the logging directory. Using to display information about the pipeline:

Reader B is a member of pipeline, so that is what is printed.

s6-rc as an init system component
s6-rc can be used as the service manager of an init system based on s6. Such an init system runs program from the s6 package as process 1 for most of the machine's uptime, and separate programs (usually execline scripts), the stage1 init and the stage3 init, during the boot and shutdown sequences, respectively. Therefore, process 1 is the root of an s6 supervision tree for most of the machine's uptime, and has an associated scan directory, usually in a read-write tmpfs. s6-rc uses this supervision tree and a compiled service database, the boot-time service database, that must be available during the machine's boot sequence, usually in the rootfs.

Because s6-rc must be initialized using the program (see initializing s6-rc) when the  process is already running, this takes place in the stage2 init, a program (usually an execline or shell script) that is launched by the stage1 init and blocks until the init system's catch-all logger is started. The s6-rc live state database is usually created in the same read-write tmpfs that is used for the init system's scan directory. The tmpfs is customarily mounted on, and the live state directory is left to be , s6-rc's default, so that no  options have to be specified each time to s6-rc tools. After initializing s6-rc, atomic services (oneshots and longruns) that are needed to complete the machine's initialization, and longruns that are wanted in up state at the end of the boot sequence, must be started. This is can be usually done by defining a service bundle containing all those services, and starting it in the stage2 init with an command naming that bundle.

The boot-time service database becomes live during the machine's boot sequence, so any service modification must be generally performed by creating a new service database using, and then replacing the current one with it using the program (see live updates to the service database). Service bundles can be direclty modified in the live database with the, so a database switch is not strictly required in this case. If during the machine's uptime the s6-rc package is upgraded to a backwards-incompatible version, the current live database must be recompiled after the package upgrade using the same service definitions in 's source format, and the  program must be used to switch databases.

Here is a summary of possible ways of performing service modification:
 * Bundle modifications in the live database performed with are 'sticky' (i.e. are preserved across machine reboots).
 * Contents of longrun's and  subdirectories can be modified using the service directory symlinks in the init system's scan directory, but changes like this are not 'sticky'. They 'reset' to the contents in the corresponding service definition used to create the boot-time database after a machine reboot.
 * Files with meaning defined by s6 (,, etc.) could be modified directly using a longrun's service directory symlink in the init system's scan directory, but the modification of service directory contents is inherently a non-atomic operation that can have issues if the corresponding supervised process dies and gets restarted by its supervisor in the middle of the process . Also, the changes are not 'sticky', so this is discouraged.
 * Supporting files of oneshots (e.g. external scripts invoked from an or  file) or longurns that are not placed in  and  subdirectories generally must referred to by absolute path, can be modified in their corresponding locations, and the changes are 'sticky'.
 * Any other modification must generally be done with a new database and, changes are 'sticky' this way and safe.

Finally, before replaces itself with the stage3 init during the shutdown sequence, all s6-rc-managed services must be stopped, usually with an  command. This takes place in an an execline or shell script, the shutdown script, that is invoked from an diverted signal handler.

Unmerge
All live state directories, compiled service databases and service definitions in 's source format must be manually deleted if no longer wanted after removing the package. And obviously, if s6-rc is being used as an init system component, an alternative init system must be installed in parallel, and the machine rebooted to use it (possibly by reconfiguring the bootloader), before the package is removed, or otherwise the machine will become unbootable.