The s6-rc program

s6-rc is a service manager, a.k.a machine state manager: a program to manage the live state of a machine - what services are currently up and what services are currently down. It can list active services, or change the live state.

s6-rc is meant to be the one-stop shop of service management: once service definitions have been made into a compiled service database via s6-rc-compile, and the machine state has been initialized via s6-rc-init, any state change - be it initial startup, shutdown, or anything else - should be achieved by a single s6-rc change invocation.

s6-rc should only be run by the user owning the underlying s6 supervision tree. It can also be run by root even if the supervision tree is not owned by root, but in this case the services will always be started and stopped by the user owning the supervision tree - they will not have root privileges.


     s6-rc help
     s6-rc [ -l live ] [ -b ] [ -a ] [ -u | -d ] list servicenames...
     s6-rc [ -l live ] [ -b ] [ -a ] [ -u | -d ] listall servicenames...
     s6-rc [ -l live ] [ -b ] diff
     s6-rc [ -l live ] [ -b ] [ -a ] [ -u | -d | -D ] [ -p ] [ -v verbosity ] [ -n dryrunthrottle ] [ -t timeout ] change [ servicenames... ]

Exit codes

Service selection

The arguments servicenames... may be atomic services or bundles; they are resolved into a set of atomic services, which is called the selection. If the -a option is present, the current set of active services (i.e. services that are up) is added to the selection. The s6-rc command always operates on the selection.


General options

Up or down

These options control what is to be done: bring selected services up or down (for s6-rc change) or whether to use the forward or reverse dependency graph (for s6-rc listall). Default is up.

The -d option is what should normally be used to down a set of services. If a service is marked as essential (there is a flag-essential file in its service definition directory), then s6-rc will refuse to stop that service. The -D option will still force that service to shut down; that option should only be used when the machine is going to be stopped.

s6-rc change control


s6-rc help

Prints a short help message.

s6-rc list servicenames...

Prints the selection. If the -d option has been given, the selection is inverted before it is printed, i.e. all the services but servicenames... will be printed.

This is mostly useful as s6-rc -a list, which simply prints the list of currently active services. s6-rc -da list will print the list of currently down services.

s6-rc listall servicenames...

s6-rc diff

Checks the consistency between s6-rc's view of the state of the longruns it's managing, and s6's view. s6-rc will print one line per service whose s6 state fails to match what s6-rc believes: a + character (if s6 is maintaining the service as up when s6-rc thinks it's down) or a - character (if s6 is not trying to maintain the service when s6-rc thinks it's up), followed by the service name. If s6-rc finds at least one mismatch, it exits 1; else it exits 0.

s6-rc diff normally reports nothing. Currently, the only case where s6-rc's view can diverge from s6's view is when a service has been brought up via a s6-rc change command, then has failed at some point with a permanent failure - which means its supervisor has stopped trying to bring it back up.

s6-rc start

s6-rc start is equivalent to s6-rc -u change, see below. It will run the engine to start a set of services.

s6-rc stop

s6-rc stop is equivalent to s6-rc -d change, see below. It will run the engine to stop a set of services.

s6-rc change

s6-rc change is the service state engine. It will bring the machine to a state where:

(Note that the -p option is inoperant when using the start or stop subcommands.)

To change the machine state, s6-rc does the following:

Longrun transitions

Transitions for longrun services are simple: s6-rc removes or creates a ./down file in the live service directory for the longrun service, then sends a command to the supervision tree to start or stop the service. (A service that is considered down by s6-rc will have a ./down file in its live service directory; a service that is considered up by s6-rc will not.) The transition is considered successful as soon as the daemon dies (for down transitions), or becomes up and ready (for up transitions). If a longrun service does not support readiness notification, the s6-svc command that is invoked by s6-rc will print a warning message, and the transition will be considered successful as soon as the daemon is up, i.e. as soon as the ./run script is executed by s6-supervise.

When a longrun service supports readiness notification, unless a nonzero timeout has been declared in the timeout-up file in the service definition directory, s6-rc will wait forever on an "up" transition for the notification to arrive. The transition will fail if a timeout occurs.

If a down transition fails, s6-rc does nothing with it. The service has already received a SIGTERM, and may be stuck in the process of exiting; or it may already have died but is stuck in a bad finish script that is not timing out. In any case, it is not a situation that s6-rc can recover from; the service is most likely down, but the administrator should manually check their process list. And fix their scripts, or timeout values, because a down transition failure is always a programmer or sysadmin error.

If an up transition fails, s6-rc sends an explicit s6-svc -d command to the longrun. This ensures the service is in a known down state when failing to go up, instead of (for instance) being stuck in a not-ready limbo state.

Note that proper usage of the timeout-kill and timeout-finish values in the longrun's definition directory can considerably reduce the number of cases where the service is left in an unknown state.

Transitions are supposed to be idempotent, but it is a general rule of supervision that run and finish scripts must be idempotent, so a properly designed service directory should work with s6-rc with no additional effort.

Oneshot transitions

Transitions for oneshot services amount to running the up or down script for the service; those scripts are stored in the compiled service database that is linked from the live state. The transition is considered successful if the script exits zero, and unsuccessful otherwise.

s6-rc performs some black magic so that up and down scripts are always run in a reproducible way, no matter when or how s6-rc change is invoked. That black magic involves a special longrun service, s6rc-oneshot-runner, that every oneshot service automatically depends on, and that is actually used to fork the up or down scripts as scions of the s6 supervision tree, instead of children of the s6-rc process.

Transitions should be ideally transactional, or at the very least idempotent. If a transition fails, it should leave the machine in the same state as before the transition was attempted; at the very least, it should not prevent a subsequent run of the same transition from completing successfully. If an s6-rc change invocation fails because some transition experienced a temporary failure, it should be possible to run the exact same s6-rc change invocation later, and be met with success.

This is important: it means that oneshot scripts should be treated as atoms, and that some care should be taken when writing them.

Dry runs

For any manual change, is it recommended to perform a dry run before the state change itself: add the -n dryrunthrottle option to the s6-rc command line. s6-rc will then simulate all the transitions, but not actually perform them or change the real live state. The command lines that s6-rc would have run will be printed to stdout instead, and each simulated transition will take dryrunthrottle milliseconds to complete successfully.


s6-rc change reacts to the following signals:

Usage examples

 s6-rc start myservicebundle 

Brings up all the services represented by myservicebundle, bringing up all its dependencies first (recursively).

 s6-rc -ba down 

Waits for any pending program of the s6-rc family to stop using the live database and current compiled service database, then brings down all the currently running services in an orderly manner. This is typically run at shutdown time. (And it's not necessarily a bad change!)

 s6-rc -l /zork -ua listall myservicebundle 

Prints the names of all atomic services represented by myservicebundle plus the current live services, as well as everything they depend on, recursively. Assumes the live state is stored in the /zork directory instead of /run/s6-rc.

 s6-rc -d listall myservicebundle 

Prints the names of all atomic services represented by myservicebundle, as well as everything that depends on them.

 s6-rc -pun0 change myservicebundle 

Prints what s6-rc would do to bring the state to exactly the contents of myservicebundle as well as its recursive dependencies, and pruning all the rest. Does not wait any extra time between simulated transitions.