s6: the s6-background-watch program
Keywords: s6 command s6-background-watch fork supervision auto-backgrounding daemon bg fg fghack s6-fghack

s6
Software
skarnet.org

# The s6-background-watch program

s6-background-watch spawns an auto-backgrounding daemon that writes a pidfile. It reads the pidfile then transmits the signals it receives to the corresponding process. It dies when the corresponding process dies, with an approximation of its exit code.

s6-background-watch is meant as a workaround to auto-backgrounding daemons. (Not a solution, because the solution is to fix the daemon so it runs without backgrounding itself!) It should be run on the command line of a run script, right before the invocation of the auto-backgrounding daemon.

s6-background-watch only works on Linux (or any systems implementing prctl with PR_SET_CHILD_SUBREAPER) and the BSDs (or any system implementing procctl with PROC_REAP_ACQUIRE or kevent with EVFILT_PROC and NOTE_EXIT fflag). Most modern systems will implement one of these.

## Interface

         s6-background-watch [ -t timeout ] [ -d notif ] pidfile prog...

- s6-background-watch spawns prog... as a child.
- prog... is expected to fork. The child process is supposed to be long-lived, i.e. the child the daemon that is to be supervised.
- The parent is expected to write the child's pid to the pidfile file.
- The parent is expected to exit 0 when the child is ready.
- Once the parent has exited, s6-background-watch reads pidfile to get the pid of the daemon.
- s6-background-watch transmits all the signals it receives to the daemon. Non-catchable signals, such as SIGKILL, will obviously not work, so, don't do this.
- s6-background-watch exits when the daemon exits, with an approximation of the daemon's exit code. (In most cases it will be the exact same exit code.)

## Options

`-t timeout`, `--timeout-ready=timeout`
  If the parent daemon has not exited after timeout milliseconds, kill it and exit. By default, there is no timeout, s6-background-watch will wait as long as needed.
`-d notif`, `--notification-fd=notif`
  Write a newline to file descriptor notif when the parent has exited 0 and s6-background-watch has successfully read pidfile. This is useful when the daemon follows the convention that the child is ready when the parent exits: use the `-d` option in conjunction with the `notification-fd` file, and s6-supervise will accurately report the daemon's readiness.

## Exit codes

100
  Bad usage.
111
  System call failed. This is generally a temporary error, or indicates a problem with the underlying system.
112
  Functionality not supported. You cannot run s6-background-watch on this OS, because it lacks the necessary features.
128+n
  The parent daemon was killed with signal n. In particular, 137 can happen if the `-t` option has been given and the parent daemon times out: s6-background-watch kills it with SIGKILL.
n
  The child daemon exited with code n.

## Notes

s6-background-watch acts as a proxy between s6-supervise and the forking daemon. It stays in the foreground, keeping s6-supervise happy; and it keeps track of the daemon as best as it can, transmitting it signals. It is a better iteration of s6-fghack, which is obsolescent. However, it is not perfect, because it cannot be:

- `s6-svc -k`, i.e. SIGKILL, is very bad. It will kill s6-background-watch without killing the backgrounded daemon, and all links to the daemon are lost. If the service restarts, it will probably fail, because the previous instance of the daemon is still alive. You may be able to mitigate that with the use of a lock-fd file.
- The race condition inherent to pidfiles is there: between the moment the daemon writes its pidfile and the moment s6-background-watch reads it and attempts to track it, the daemon could have died and another pid taken its place. The design of s6-background-watch makes this race window minimal (the system has to loop over the whole pid space between the moment the pidfile is written and the moment s6-background-watch reads it, which is right afterwards, so it's not as bad as most uses of pidfiles, but the race theoretically still exists.
- In order to detect the death of a process that isn't a direct child, which isn't a functionality guaranteed by POSIX, OS-specific mechanisms have to be used, and not all the supported OSes have such mechanisms. If the OS has no usable mechanism for this, s6-background-watch will immediately exit with an error message.