S6-BACKGROUND-WATCH(8)
π s6-background-watch β bestie edition
okay so this is the s6-background-watch page, from section 8 of the System Manager's Manual, and it's literally the "make your auto-backgrounding daemon behave" hack you've been looking for π
β¨ NAME β¨
s6-background-watch β spawn an auto-backgrounding daemon that writes a pidfile, no cap π
πΈ SYNOPSIS πΈ
s6-background-watch [-t timeout] [-d notif] pidfile prog...
π¦ DESCRIPTION π¦
okay so s6-background-watch spawns an auto-backgrounding daemon that writes a pidfile. Then it reads that pidfile and transmits the signals it receives to the corresponding process. It dies when the corresponding process dies, with an approximation (cf. execline-exitcodes(7)) of its exit code. iconic behavior, honestly π«Ά
s6-background-watch is meant as a workaround to auto-backgrounding daemons. Note the word workaround β not a solution, because the actual 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 (cf. PR_SET_CHILD_SUBREAPER(2const))) and the BSDs (or any system implementing procctl with PROC_REAP_ACQUIRE (cf. procctl(2)) or kevent with EVFILT_PROC and NOTE_EXIT fflag (cf. kqueue(2))). Most modern systems will implement one of these, so like, vibe check your OS first π
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 is 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 (cf. execline-exitcodes(7)) of the daemon's exit code. (In most cases it will be the exact same exit code, slay.)
π Notes π
s6-background-watch acts as a proxy between s6-supervise(8) 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(8), which is obsolescent. However β and this is the part where we get real β it is not perfect, because it cannot be:
s6-svc -k(cf.s6-svc(8)), i.e.SIGKILL, is very bad. It will kills6-background-watchwithout 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 (cf.s6-service-directory(7)). like, genuinely be careful here π₯- The race condition inherent to pidfiles is there: between the moment the daemon writes its pidfile and the moment
s6-background-watchreads it and attempts to track it, the daemon could have died and another pid taken its place. The design ofs6-background-watchmakes this race window minimal (the system has to loop over the whole pid space between the moment the pidfile is written and the moments6-background-watchreads it, which is right afterwards, so it's not as bad as most uses of pidfiles) β but the race theoretically still exists. not me being honest about theoretical problems π - 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-watchwill immediately exit with an error message.
π 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, ands6-background-watchwill wait as long as needed. patient queen energy β-d notif,--notification-fd=notifβ write a newline to file descriptor notif when the parent has exited0ands6-background-watchhas successfully read pidfile. This is useful when the daemon follows the convention that the child is ready when the parent exits: use the-doption in conjunction with the notification-fd file, ands6-supervise(8)will accurately report the daemon's readiness. communication, bestie π
π₯ EXIT STATUS π₯
100β Bad usage. (you typed something cursed)111β System call failed. This is generally a temporary error, or indicates a problem with the underlying system.112β Functionality not supported. You cannot runs6-background-watchon this OS, because it lacks the necessary features. wrong OS, bestie π128+nβ The parent daemon was killed with signal n. In particular,137can happen if the-toption has been given and the parent daemon times out:s6-background-watchkills it withSIGKILL.nβ The child daemon exited with code n.
π SEE ALSO π
kqueue(2), procctl(2), PR_SET_CHILD_SUBREAPER(2const), execline-exitcodes(7), execline-exitcodes(7), s6-service-directory(7), s6-fghack(8), s6-supervise(8), s6-supervise(8), s6-svc(8)
(yes, execline-exitcodes(7) and s6-supervise(8) are each listed twice β that's how the original rolls, we don't edit the source, periodt π«Ά)
This man page is ported from the authoritative documentation at: https://skarnet.org/software/s6/s6-background-watch.html
π AUTHORS π
- Laurent Bercot
- Lennart Jablonka
<humm@ljabl.com>(man page port)
that's the whole thing, bestie π this page came from the Debian packaging of the manual, dated October 22, 2025 β slay, go supervise something π§β¨
π¦ where this page comes from
- nixpkgs unstable: s6 2.15.1.0
- nixpkgs unstable: s6-man-pages 2.14.0.1.4
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms