Skip to content

Runlevels

Frank Earl edited this page Dec 12, 2019 · 5 revisions

Runlevels in runit are quite a bit more sophisticated than the sysvinit and similar solutions, which are fixed in nature and are on a sliding scale from 0 to 6, with 0 being stop, 6 being reboot, and the others being an odd mix of single user, no-X11, multiuser/X11, etc. with 5 being the typical runlevel in a sysvinit (Multi-user, X11) based system. One of the takeaways from things here is that you do not need to specify a 0 or a 6. These are taken care of explicitly by the supervision system for all services running and you need only define normal operation and special cases for maintenance, etc. of the system which provide for subsets of what services including a root login TTY for single user modes, etc. This describes how one would set up runlevels other than the default one.

Prepare runit

If not yet done, configure your system to use runit as PID 1 by following the instructions for replacing init. Some distributions (e.g. Void Linux/PHA-Linux) will do this for you automatically as they use runit exclusively as the init system.

Once ready, create the following directories and symbolic links if not already provided by the distribution :

# mkdir -p /etc/runit/runsvdir/default
# mkdir -p /etc/runit/runsvdir/single
# ln -s /etc/sv/getty-5 /etc/runit/runsvdir/single/
# ln -s default /etc/runit/runsvdir/current

This will set up a baseline runlevel (default) and a single-user one that can be selected by the runsvdir command later.

Next, if you've had to do the previous step, copy the contents of /service/ to /etc/runit/runsvdir/current/ and replace /service/ with a symbolic link:

# cp -pR /service/* /etc/runit/runsvdir/current/
# mv -f /service /service.old
# ln -s /etc/runit/runsvdir/current /service

At this point, you have now created two runlevels: default and single. The current runlevel is default. It is safe to remove /service.old/ if you don't need it anymore. Finally edit /etc/runit/2 to set the default runlevel when stage 2 starts:

$ cat /etc/runit/2
#!/bin/sh
PATH=/command:/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin

runsvchdir default >/dev/null

exec env - PATH=$PATH \
runsvdir /service 'log: -----------------------------------------------------------------'

Switching runlevels

Switching runlevels with runit is done by switching the directory the runsvdir program is running in. This is done by the runsvchdir program, e.g. to switch to the single user runlevel, do:

# runsvchdir single

To switch back to the default runlevel, do:

# runsvchdir default

See the runsvdir program for a description of what happens when runsvdir sees the directory changed. Note: There is no guarantee that all services from the previous runlevel will have stopped at the time you're dropped into the new runlevel, the runsv processes will have sent the service daemons a SIGTERM and will wait for them to terminate. Typically, they will have all stopped but there may be stragglers due to ill-behaving services. You can check the status of the previous runlevel through /etc/runit/runsvdir/previous/. A kill or force-exit can be issued via the sv command if needed to any services that didn't honor the shutdown for change.

Creating new runlevels

To create a new runlevel, simply create a new directory in /etc/runit/runsvdir/. The name of the directory is the name of the new runlevel. The name must not start with a dot and must not be current, current.new, or previous, e.g.:

# mkdir /etc/runit/runsvdir/maintenance

Add the services you want to run in the runlevel maintenance to the newly created directory, e.g.:

# ln -s /etc/sv/getty-5 /etc/runit/runsvdir/maintenance/
# ln -s /etc/sv/ssh /etc/runit/runsvdir/maintenance/
# ln -s /etc/sv/dnscache /etc/runit/runsvdir/maintenance/

If you want to switch to the runlevel maintenance, do:

# runsvchdir maintenance

Clone this wiki locally