Running svscan as process 1

While I'm keeping this page available for historical interest, I no longer run this configuration, and I wouldn't recommend it today. These days, I'd use s6 instead.

I run the svscan program from Dan Bernstein's daemontools package as process 1. This setup is discussed on the supervision list, and sometimes on the log list as well. I've written a package to take care of some of the issues described here. If you're interested in how this setup has changed over time, you can also read the message I sent to the log list back around when I first started.

Rationale

Why bother replacing init at all? The main idea behind this setup is that one-time system initialization is a completely separate task from ongoing service management. They should therefore be handled by separate code. svscan is superior to init for running services, so the only use I could have for init is system initialization. But init is extreme overkill for this task; I don't want to keep all that dead code (runlevels, login accounting, etc.) on disk and in memory. Once initialization is complete, the service manager can be exec'ed by process 1; there's no need to keep the initializer around in a running process.

Duties of process 1

Let's consider the usual ongoing duties of process 1. (For now, we ignore all tasks related to system initialization. What is presented here ought to be compatible with any method you might use to handle initialization.)

Have I missed any? It looks like it ought to be possible to put the svscan peg in the init hole. So I did, and it happened to work.

Booting

There are (at least) two general ways to handle system initialization:

In any case, the traditional init program does not need to run at all; all services can run under supervise instead of from init scripts.

svscan's output

Output from svscan and some supervises (and their services) will go to the console by default. It could be redirected to a file or, with some effort, to readproctitle, but multilog (or some other supervised logger) would obviously be preferable. So I wrote grabconsole, which is also useful for grabbing logs meant for syslogd when syslogd isn't running. But svclean handles this even better: we can run a logger for svscan's output as a normal service, without involving /dev/console.

Runlevels

I don't need or use runlevels, but there are ways to have them with daemontools. E.g., you can have a runlevel directory containing a subset of the symlinks in /service, and you can run svc -u dir/* to change to that runlevel. See also the related links below.

Shutdown

For a clean shutdown, we want to kill each service and ensure that its logger has written all the logs before killing the logger. We want to be able to unmount (or remount read-only) all local disk filesystems, but supervise keeps a writable descriptor open to a lock file. We can kill each supervise, but svscan will respawn them. We need to prevent that somehow.

So we give svscan a specialized $PATH containing a supervise wrapper; during shutdown, if svscan starts this wrapper to replace a supervise that has exited, the wrapper exits immediately instead of running supervise. After we svc -dx all services, svscan will try to restart supervise, but it will actually start our wrapper instead. supervise will not run, and no files will be held open for writing. The wrapper also allows the logger to read as much data as is in the log pipe, and exit afterwards.

Some people might want the shutdown script to be spawned from process 1, to ensure a clean process state. This can be done by making a shutdown service. To shut down, you link the service into /service; it then tells its own supervise to exit, removes itself from /service, and forks into the background so supervise will think it is finished, before doing the real work.

#!/bin/sh -e
svc -ox .
rm /service/shutdown
do-real-shutdown &

You would also add rm -f /service/shutdown to your boot scripts, just to be careful.

Some code

I also wrote a modular set of boot scripts, with a dependency-ordering system implemented in pure sh code (i.e., using no external commands, like ls or mv). I haven't published (and do not currently use) an init system based on this technique, but the core of it would be load.sh from prjlibs.

Related links

Please let me know about other related sites.