by goku12 | 2025-11-17 15:32:46+00:00
I'm sure that anyone who likes to hack their systems will surely appreciate runit. But I wonder if the larger crowd is familiar with the philosophy and ecosystem behind runit that makes it such a pleasure to work with. Runit is a member of a family of supervision suites known as the daemontools family. daemontools [1] is a process supervision suite that Daniel J Bernstein released in 1997, and is still in use today.

The daemontools family is the exact opposite of what we've come to expect from an init or process supervision system. It pioneered an approach that eschews large complex monolithic daemons in favor of the unix philosophy. They're made of numerous small and simple applications - a few dozen sometimes. Unlike the traditional init systems that most of us prudently stay away from (other than writing their service configurations), these applications are very easy to understand and tinker with independently. They have a coreutils feel - you can easily find other uses for them and mix and match them freely (because they're all very specialized). Sometimes it feels like they designed the utility suite first and then designed a supervision/init suite around it. It isn't just easy to setup a service hierarchy with it. The applications are so small and simple that implementing the suite yourself isn't a big stretch either.

The way they set up an init system or supervision tree is out of scope here. The blog post "Celebrating Daemontools" [2] by G.D. Ritter is the best description I could find. Instead, let's focus on the individual applications. Simplicity is a virtue in engineering. These tools try to get away with as little work as possible. For example, there is no complex config language, API or wire-format. Instead, these tools communicate the intent (config or commands) and the state of the service tree using the filesystem. Its API is a tree of directories, files, symlinks and FIFOs called a 'scan directory' - somewhat reminiscent of the /sys and /proc directories. Each service is started, monitored and restarted upon crash by a very small and stable daemon that takes its instructions from a sub-directory of the scan directory (a service directory). The files inside these sub-directories are arbitrary executables (scripts/binaries) or others that either contain a single value or are completely empty (the file itself is the data). They religiously avoid parsing.

Another trick they use heavily is 'chain loading' of applications (a.k.a 'Bernstein loading'). Here, one application 'execs' into another application, with the latter completely replacing the former in memory. This is used to, for example, set the environment variables (from files - one per variable) before execing into the required service. Sometimes, these chains are several commands long. There is even a scripting language called execline [3] that works entirely by chain loading. Unlike traditional scripting languages, the shell/interpreter doesn't stay resident in memory and babysit the child processes. It (execlineb) does some very simple initial processing and then completely exits the scene. The rest of the execution is a bunch commands invoking others using traditional syscalls. Writing execline scripts takes some getting used to, but it's very nifty afterwards.

They use these simple techniques to do everything including parallel service initialization with dependencies, setting up envvars, gid, uid, resource limits, logging and even socket activation. They are super light and extremely fast. They have such straightforward interfaces that composing systems with tools from different suites is also possible. Though I haven't seen it in practice yet, starting and managing containers (like systemd-nspawn) should be trivial to achieve. These suites grow on you once you start using them and remind you what could have been. They really show you that something as complex as init systems and process supervision doesn't require prodigious talent or the resources of MNCs. You just need to stick to the fundamentals.

Finally, some other members of this family that deserves some mention. Bruce Guenter's daemontools-encore [4] expands on daemontools with backwards-compatible changes including extra service states (besides just up and down). And then there are Gerrit Pape's Runit [5], Laurent Bercot's s6 [6] and Jonathan de Boyne Pollard's nosh [7]. These three can run as init systems on Linux and BSDs. Nosh features a systemd and upstart shim layer to make it feel familiar to the users of those software. Nosh also has utils that convert systemd service files and upstart scripts to its native service bundles.

[1] http://cr.yp.to/daemontools.html

[2] https://journal.infinitenegativeutility.com/celebrating-daem...

[3] http://skarnet.org/software/execline/

[4] http://untroubled.org/daemontools-encore/

[5] http://smarden.org/runit

[6] http://skarnet.org/software/s6/

[7] https://jdebp.uk/Softwares/nosh/

[8] https://jdebp.uk/FGA/daemontools-family.html