S6-SVSCAN(8)

πŸ“¦ version 2.15.1.0, in nixpkgs unstable

πŸŽ€ NAME πŸŽ€

s6-svscan β€” starts and monitors a whole collection of s6-supervise(8) processes. (Yep bestie, this is S6-SVSCAN(8) from the System Manager's Manual, and it's lowkey the mom of your entire supervision tree. 🫢)

✨ SYNOPSIS ✨

s6-svscan [-d notif] [-X consoleholder] [-c max | -C services_max]
          [-L name_max] [-t rescan] [scandir]

🌸 DESCRIPTION 🌸

Okay so picture this: s6-svscan starts and monitors a collection of s6-supervise(8) processes, and each one of those processes is monitoring a single service. Supervisor of supervisors, it's giving main character energy. πŸ‘‘ It's designed to be either the root or a branch of a supervision tree.

If you hand it a scandir argument, it switches to it. If you don't, it just uses its current directory as the s6-scan-directory(7). No drama, no fuss.

It exits 100 if another s6-svscan process is already monitoring this s6-scan-directory(7). One keeper per directory, them's the rules. 🚫

If the ./.s6-svscan control directory does not exist, s6-svscan creates it for you. But honestly it is recommended that you already have a .s6-svscan subdirectory in your scan directory, because that's the thing used to configure how s6-svscan operates β€” see below. πŸ’…

From this point on, s6-svscan never dies. Like, ever. It tries its best to keep control of what's happening. In case of a major system call failure β€” which means the kernel or the hardware is broken in some fashion β€” it executes into the .s6-svscan/crash program. (But if that execution fails, s6-svscan exits 111. 😭)

Then it performs an initial scan of its scan directory.

And after that it occasionally runs scans or reaps, see below. That's the whole loop and it's iconic.

s6-svscan runs until it's told to stop via s6-svscanctl(8), or via an appropriate signal (see below). Then it executes into the .s6-svscan/finish program, if present; if not, it exits 0. 🎬


πŸ“‘ Signals πŸ“‘

s6-svscan has special handling for the following signals, and only these:

  • SIGCHLD
  • SIGALRM
  • SIGABRT
  • SIGHUP
  • SIGINT
  • SIGTERM
  • SIGQUIT
  • SIGUSR1
  • SIGUSR2
  • SIGPWR (on systems that support it)
  • SIGWINCH (on systems that support it)

Signals that are not in the above list are not caught by s6-svscan and will have the system's default effect. So don't come crying if you yeet something random at it. πŸ™ˆ

The behaviour for the first three signals in the list is always fixed, no customization, no opinions:

  • SIGCHLD β€” trigger the reaper.
  • SIGALRM β€” trigger the scanner.
  • SIBABRT β€” immediately exec into .s6-svscan/finish (or exit 0 if that script does not exist), without waiting for any processes to die. (Yes, the page spells it SIBABRT β€” that's the SIGABRT one, and we're keeping the typo for ✨archival integrity✨.)

The behaviour for the rest of the list is configurable: on receipt of a "SIGFOO", s6-svscan will try to run an executable .s6-svscan/SIGFOO file. For instance, an .s6-svscan/SIGTERM executable script will be run on receipt of a SIGTERM. If the file cannot be found, or cannot be executed for any reason, the default behaviour for the signal will be applied. The default behaviours are:

  • SIGHUP β€” rescan and prune the supervision tree, i.e. make sure that new service directories visible from the scan directory have an s6-supervise(8) process running on them, and instruct s6-supervise(8) processes running on service directories that have become invisible from the scan directory to stop their service and exit. You can also get this behaviour via the s6-svscanctl -an scandir command. This is the closest that s6-svscan can get to the traditional "reload your configuration" behaviour. πŸ”„
  • SIGINT β€” same as SIGTERM below.
  • SIGTERM β€” instruct all the s6-supervise(8) processes to stop their service and exit; wait for the whole supervision tree to die, without losing any logs; then exec into .s6-svscan/finish or exit 0. You can also get this behaviour via the s6-svscanctl -t scandir command. πŸ›‘
  • SIGQUIT β€” same as SIGTERM above, except that if a service is logged (i.e. there is a foo service and a foo/log service) then the logging service will also be killed, instead of being allowed to exit naturally after its producer has flushed its output and died. This can solve problems with badly written logging programs, but it can also cause loss of logs, since the logger may die before the producer has finished flushing everything. πŸ’€ The behaviour can also be achieved via the s6-svscanctl -q scandir command; you should only use this if SIGTERM/-t fails to properly tear down the supervision tree.
  • Others β€” no effect if an appropriate executable file in .s6-svscan/ cannot be run.
Real talk: that SIGQUIT one is the break-glass option and it can absolutely eat your logs, so try SIGTERM/-t first, bestie. 🫢

🧹 The reaper 🧹

Upon receipt of a SIGCHLD, or an s6-svscanctl -z command, s6-svscan runs a reaper routine.

The reaper acknowledges (via some wait() function), without blocking, every terminated child of s6-svscan, even ones it doesn't know it has. This is especially important when s6-svscan is run as process 1[1]. πŸ‘‘

If the dead child is an s6-supervise(8) process watched by s6-svscan, and the last scan flagged that process as active, then it is restarted one second later. ⏱️


πŸ” The scanner πŸ”

Upon receipt of a SIGALRM or an s6-svscanctl -a command, s6-svscan runs a scanner routine. (It also runs it every rescan milliseconds if the -t option has been given.)

The scanner scans the current directory for subdirectories (or symbolic links to directories), which must be service directories. It skips names starting with dots. It will not create services for more than max subdirectories.

For every new subdirectory dir it finds, the scanner spawns an s6-supervise(8) process on it. If dir/log exists, it spawns an s6-supervise(8) process on both dir and dir/log, and maintains a never-closing pipe from the service's stdout to the logger's stdin. This is starting the service, with or without a corresponding logger. Every service the scanner finds is flagged as "active". 🟒

The scanner remembers the services it found. If a service has been started in an earlier scan, but the current scan can't find the corresponding directory, the service is then flagged as inactive. No command is sent to stop inactive s6-supervise(8) processes (unless the administrator uses s6-svscanctl -n or a SIGHUP), but inactive s6-supervise(8) processes will not be restarted if they die. πŸ”΄


πŸ“ Notes πŸ“

  • s6-svscan is designed to run until the machine is shut down. It's also designed as a suitable candidate for process 1. So it goes out of its way to stay alive, even in dire situations. When it encounters a fatal situation, something it really cannot handle, it executes into .s6-svscan/crash instead of dying; when it's told to exit, it executes into .s6-svscan/finish. Admins should make sure to design appropriate crash and finish routines. πŸ™
  • s6-svscan is a fully asynchronous state machine. It will read and process commands at any time, even when the computer is in trouble. ⚑
  • s6-svscan does not use malloc(3). That means it will never leak memory. However, s6-svscan uses opendir(3), and most opendir(3) implementations internally use heap memory β€” so unfortunately, it's impossible to guarantee that s6-svscan does not use heap memory at all. 😭
  • Unless run with a nonzero -t option, which is only a legacy feature used to emulate other supervision suites such as daemontools or runit, s6-svscan never polls; it only wakes up on notifications. The s6 supervision tree can be used in energy-critical environments. 🌱

πŸ’… OPTIONS πŸ’…

  • -d notif β€” notify readiness on file descriptor notif. When s6-svscan is ready to accept commands from s6-svscanctl(8), it will write a newline to notif. notif cannot be lesser than 3. By default, no notification is sent. Please note that using this option signals shallow readiness: s6-svscan being "ready" only means that it is ready to accept commands. It does not mean that all the services it launches at start are themselves ready, or even started, or even that the relevant s6-supervise(8) processes have been started. If you need to test for deep readiness, meaning that all the services in the supervision tree have been started and are ready, you cannot rely on this option. 🫠
  • -X consoleholder β€” assume the output console is available on descriptor consoleholder. If this option is given, and a s6-svscan-log service exists, the s6-supervise(8) process for that service will be run with consoleholder as its standard error. This is mainly useful for a setup done via s6-linux-init[2], where all error messages go to the s6-svscan-log catch-all logger service by default, except messages from this service itself, which fall back to consoleholder. If you're not sure what to use this option for, or how, you don't need it. πŸ’
  • -C services_max β€” maintain services for up to services_max service directories, including loggers. Default is 1000. Lower limit is 4. Upper limit is 160000. If you're increasing this value from the default, please note that:
    • The higher max is, the more stack memory s6-svscan will use, up to 200 bytes per service, also depending on the value of name_max.
    • s6-svscan uses 2 file descriptors per logged service.

It is the admin's responsibility to make sure that s6-svscan has enough available descriptors to function properly and does not exceed its stack limit. The default of 1000 is safe and provides enough room for every reasonable system. πŸ›Ÿ

  • -c max β€” a deprecated way of setting services_max. If the -c option is given, the value of max is doubled, and the result is used as services_max. The reason for the change is that previous versions of s6-svscan handled services+loggers as a single entity; but this version of s6-svscan handles services and loggers in the same way, so with the default values it's now possible to handle e.g. 600 unlogged services, whereas previously you were limited to 500 because s6-svscan was reserving room for the loggers. πŸ•°οΈ
  • -L name_max β€” the maximum length of a name in the scan directory. Names longer than name_max won't be taken into account. Default is 251. It cannot be set lower than 11 or higher than 1019. πŸ“
  • -t rescan β€” perform a scan every rescan milliseconds. If rescan is 0 (the default), automatic scans are never performed after the first one and s6-svscan will only detect new services when told to via an s6-svscanctl -a command. Use of this option is discouraged; it should only be given to emulate the behaviour of other supervision suites. (-t5000 for daemontools' svscan, -t14000 for runit's runsvdir.) πŸ™ƒ

🌈 SEE ALSO ✨

okay bestie, when you're done here, these are the sisters of this page β€” go click around, they're all valid πŸ’…

  • s6-notifyoncheck(8) β€” the one that pings you when a service is actually up and ready, not just spawned πŸŽ€
  • s6-permafailon(8) β€” for when a service keeps flopping and you want the supervisor to just stop trying
  • s6-supervise(8) β€” the supervisor per service, the little engine behind the whole thing πŸ”₯
  • s6-svc(8) β€” for sending commands to a supervisor, the "hey do this" tool
  • s6-svdt(8) β€” the down-transitions log keeper, it's giving receipt-keeping πŸ’€
  • s6-svdt-clear(8) β€” wipes that down-transitions record clean, bye felicia 🫢
  • s6-svlisten(8) β€” watches a whole batch of services and waits for the state you want
  • s6-svlisten1(8) β€” same vibe but for just one service, the solo version πŸ‘‘
  • s6-svok(8) β€” quick check, is this thing up? yes/no, no drama
  • s6-svscanctl(8) β€” the control tool for your running s6-svscan, your remote for the main character ✨
  • s6-svstat(8) β€” prints the current stats of a service, the vibe check of services ngl
  • s6-svwait(8) β€” blocks until a service hits the state you asked for, patience is a virtue bestie 🧚

and here are the two links from the original, kept exactly as they are πŸ’–

real talk: this man page is ported from the authoritative documentation at https://skarnet.org/software/s6/s6-svscan.html β€” so if you want the OG, that's where it lives πŸ‘‘

πŸ’œ AUTHORS πŸ’œ

  • Laurent Bercot
  • Alexis <flexibeast@gmail.com> (man page port)

like, thank you both for your service, genuinely 🫢✨


and that's the whole page bestie, you made it πŸŽ‰ this one's a Debian situation, dated November 8, 2023, and it's the manual for S6-SVSCAN(8) β€” go supervise something iconic πŸ’…πŸŒΈ

πŸ“¦ where this page comes from