Using the `runit` init system

This post reports investigations into how runit is implemented in various
Linux distributions.

The goal is to learn how runit works and to find the most appropriate way of
using runit in a home desktop situation.

The post consists of several ‘chapters’ each written in markdown and copied into
this itsFOSS topic as a series of separate replies.

Contents

  1. Introduction
  2. How runit works
  3. Distributions which offer runit preinstalled
    3a. Runit in Void Linux
    3b. Runit in Antix LInux
    3c. Runit in Artix Linux
  4. Distributions which offer runit as a choice during install
    4a. Runit in PeppermintOS Devuan Edition
  5. Distributions which offer runit as an optional package.
    5a. Runit inDevuan
    5b. Runit in Debian
    5c. Runit in Gentoo Linux
  6. Recommendations
5 Likes

Introduction

The init system in Linux is responsible for two important tasks

  • starting the first process after the kernel is running
  • supervising daemon processes ( often called services) - eg. starting and stopping a service, service logs, restarting a failed service.

The official runit site is here
http://smarden.org/runit/

Runit is a modern implementation of and old-fashioned set of init tools called
daemontools.

https://wiki.gentoo.org/wiki/Daemontools

Runit is an alternative to sysvinit or systemd. Runit can be used on its own, or in conjunction with OpenRC. It is a lot easier to switch between runit and sysvinit than between runit and systemd.

The best way to learn runit is to use a distro that comes with runit preinstalled. Runit is not set up in exactly the same way in all distros, so we are going to look at several distros with preinstalled runit , and later look at some distros where runit can be added as a package.

3 Likes

How runit works

Runit consists of a directory structure in /etc plus a number of daemon processes. If you look at the daemons running in any Linux system with runit you will see something like the following

$ ps ax | grep run
    1 ?        Ss     0:01 runit
 1394 ?        Ss     0:00 runsvdir -P /etc/service log: ..................................................................................................................................................................................................................................................................................00:00:00.000 [INFO] [seatd/seat.c:39] Created VT-bound seat seat0 00:00:00.000 [INFO] [seatd/seatd.c:194] seatd started .
 1444 ?        Ss     0:00 runsv ssh
 1445 ?        Ss     0:00 runsv getty-tty3
 1446 ?        Ss     0:00 runsv seatd
 1447 ?        Ss     0:00 runsv getty-tty6
 1448 ?        Ss     0:00 runsv getty-tty4
 1449 ?        Ss     0:00 runsv udevd
 1450 ?        Ss     0:00 runsv getty-tty5
 1451 ?        Ss     0:00 runsv getty-tty1
 1452 ?        Ss     0:00 runsv getty-tty2
 1453 ?        Ss     0:00 runsv ntp
 1454 ?        Ss     0:00 runsv connman
 1455 ?        Ss     0:00 runsv dbus
 1462 ?        Ss     0:00 runsv cups
 1463 ?        Ss     0:00 runsv slimski
 1473 ?        S      0:00 svlogd -tt /var/log/runit/connman
 1475 ?        S      0:00 svlogd -tt /var/log/runit/ssh

We can identify 4 differnet daemons here

  • runit - is process #1 . It replaces the process called init which is used
    in sysVinit and OpenRC. It is the first process to run in user space once the kernel is up and going. It executes various scripts which start other user-space processes, so all other user-space processes are chidren of the runit process.

  • runsvdir - watches a directory called /etc/service which contains files used to setup a service. Inside /etc/service each service has a subdirectory containing a run script and other things. If runsvdir finds a new subdirectory ( ie a new service) it starts a runsv process to manage that service. That is about all runsvdir does. It is a cockatoo daemon.

  • runsv - there is one of these for every service started by runsvdir. You can see 14 runsv processes in the above example.
    Each runsvstarts a service, and waits for commands issued
    by the sv utility, which can stop/start a running service or query its status.
    If there is logging, runsv starts the logging daemon.

  • svlogd - if a service has logging set up, there will be a svlogd process in addition to the runsv process, for that service. In the above example there are two log daemons running, for connman and ssh services. Logging is setup by putting a log script alongside the run script in /etc/service subdirectory.

The only command runit has in addition to the 4 daemons, is the sv utility command referred to above. Everything else is information stored in its directory structure.

It is common practice, but not essential, to put all the service subdirectories with their run and log scripts not in /etc/service but in a staging directory where they can be edited and tested before enabling. If this is done /etc/service becomes a symbolic link to the staging directory , for example

$ ls -l /etc/service
lrwxrwxrwx 1 root root 22 Oct 19  2022 /etc/service -> runit/runsvdir/current

so here the staging directory is /etc/runit/runsvdir/current
and,
this in turn is commonly also a set of links, for example

nevj@antixvm:/etc/runit/runsvdir
$ ls -l current
lrwxrwxrwx 1 root root 7 Jul  5 20:45 current -> default
nevj@antixvm:/etc/runit/runsvdir
$ ls -l default
total 0
lrwxrwxrwx 1 root root 16 Oct 19  2022 connman -> /etc/sv/connman/
lrwxrwxrwx 1 root root 13 Jul 10 18:07 cups -> /etc/sv/cups/
lrwxrwxrwx 1 root root 13 Oct 19  2022 dbus -> /etc/sv/dbus/
lrwxrwxrwx 1 root root 22 Oct 19  2022 getty-tty1 -> ../../../sv/getty-tty1
lrwxrwxrwx 1 root root 18 Oct 19  2022 getty-tty2 -> /etc/sv/getty-tty2
lrwxrwxrwx 1 root root 18 Oct 19  2022 getty-tty3 -> /etc/sv/getty-tty3
lrwxrwxrwx 1 root root 18 Oct 19  2022 getty-tty4 -> /etc/sv/getty-tty4
lrwxrwxrwx 1 root root 18 Oct 19  2022 getty-tty5 -> /etc/sv/getty-tty5
lrwxrwxrwx 1 root root 18 Oct 19  2022 getty-tty6 -> /etc/sv/getty-tty6
lrwxrwxrwx 1 root root 12 Jul 10 08:06 ntp -> /etc/sv/ntp/
lrwxrwxrwx 1 root root 14 Oct 19  2022 seatd -> /etc/sv/seatd/
lrwxrwxrwx 1 root root 16 Oct 19  2022 slimski -> /etc/sv/slimski/
lrwxrwxrwx 1 root root 11 Nov  4 15:43 ssh -> /etc/sv/ssh
lrwxrwxrwx 1 root root 14 Oct 19  2022 udevd -> /etc/sv/udevd/

in this case current is the same as default, but what you see is a whole heap of symbolic links, one to each service to be started, and they all point to the subdirectories in the etc/sv directory which contain the run script and others for tahe service.

So this set of links is an elegant way of controlling two things

  • choosing an appropriate set of services to start depending on whether linux is
    in multiuser or single user ( ie recovery ) mode, or others like current versus default versus previous, and solo which is special.

  • choosing which services to start in a particular run mode.

This approach is sometimes referred to as a “link farm” , but that term also has another connotation in relation to web site links.
Used in a filesystem, it is a powerful technique that allows switching between similar alternatives.

That is all there is to how runit works, it relies on 4 daemons and a staging directory containing sets of run scripts, accessed via a link farm. The only user interface is the sv command, which communicates with the runsv daemons.

The only remaining thing is to look at an example run script. Here is the script for cupsd


nevj@antixvm:/etc/sv/cups
$ cat run
#!/usr/bin/env /lib/runit/invoke-run
set -e

NAME="cups"
DAEMON=/usr/sbin/cupsd

# Exit service if DAEMON is not installed
if [ ! -x $DAEMON ]; then
	exit 161
fi

#~ # Prepare cups run folder
#~ mkdir -p /run/cups/certs
#~ [ -x /sbin/restorecon ] && /sbin/restorecon -R /run/cups

exec 2>&1

exec $DAEMON -f

So all it does is define the daemon name, divert STDERR to STDOUT, and execute the daemon. Nothing like the complex structured sysVinit scripts. A runit run script does one thing, run the daemon. That is characteristic of runit, it breaks the job up into a number of singleminded tasks.

2 Likes

Distributions with runit preinstalled

Several distributions come either with runit as the
default init system, or provide a separate .iso file for a runit version…
For example Antix and Artix offer .iso files with runit as the
init system.

All runit implementations keep certain directories, mostly in /etc, and these contain

  • run , supervise and log scripts for each installed service. These are typically located in a directory called sv ( usually /etc/sv)… one directory per service.

  • a record of the services to be started … called current plus several other
    sets of services called ‘default’, ‘previous’, ‘single’, ‘solo’, etc. These are usually in /etc/runit/runsvdir)

  • startup scripts for 3 runlevels , called 1, 2, and 3. These are usually in /etc/runit)

There are variations on the above.

Runit has a unique mechanism for setting up services to be started… it uses symbolic links located in a services directory, and pointing to the relevant service in the sv directory. If you make a link, the service starts immediately, and also autostarts at boot. The collection of links is sometimes referred to as
a “link farm”.

Void Linux

In Void Linux, runit is the only available init system. So a downloaded Void .iso will contain a preinstalled runit.
Void is a suitable place to look , if you want to see runit doing everything.

When Void boots you see messages about runlevels fly across the screen. They are the runit runlevel scripts found in /etc/runit/1 and /etc/runit/2. You should see levels 1 and 2. Level 3 is for shutdown.

After Void is running, you can see the init daemon

$ ps ax | grep runit
    1 ?        Ss     0:00 runit

Yes , the init daemon is called runit and it is process no 1.

If you look in the /etc directory in Void, you find two subdirectories related to
runit operations

  • sv subdirectory contains all the scripts to run or supervise every service that has been installed
  • runit subdirectory contains the three runlevel scripts which run at startup and shutdown, and an important subdirectory called runsvdir which contains all the symbolic links set by default or by the user to start services.

Void also has a symbolic link in /var

$ ls -l /var
....
lrwxrwxrwx  1 root root   29 Apr 14  2023 service -> ../run/runit/runsvdir/current

which points to the current set of symbolic links.
Void differs from other runit distros, in that it puts this link in /var/service instead of in /etc/service.
Void users are encouraged to use /var/service to simplify setting of links
For example

ln -s /etc/sv/sshd /var/service/sshd

will make a link in current which will start the sshd daemon.

In addition to making links, runit has the sv command which can get the status of a service, or start or stop it, for example

#sv status /var/service/*
run: /var/service/NetworkManager: (pid 1084) 4185s; run: log: (pid 1083) 4185s
run: /var/service/acpid: (pid 1038) 4185s
run: /var/service/agetty-hvc0: (pid 21437) 5s
.....
run: /var/service/sshd: (pid 1060) 4185s; run: log: (pid 1059) 4185s
....
run: /var/service/virtstoraged: (pid 1051) 4185s; run: log: (pid 1050) 4185s
run: /var/service/virtvboxd: (pid 1069) 4185s; run: log: (pid 1067) 4185s
down: /var/service/virtxend: 1s, normally up, want up; run: log: (pid 1065) 4185

which lists the status of all services supposed to be running.

There is also
sv up <servicename>
sv down <servicename>
sv status <servicename>
which bring a given service up or down or list its status.
The sv commands only work after a service has been enabled by making a link.

When you install a service in Void ( as a Void package) the package system ( called xbps) installs the service but does not start it. One has to follow up the package install by doing two things

  • check that the service has a subdirectory in /etc/sv containing at least a run
    script and preferably also a supervise and a log script.
  • make a symbolic link to start the service.

Most Void packages will install the required entries in /etc/sv , but not all.
I had to make a run script for ftpd. It is simple, here is what I used

#!/bin/sh
exec ftpd -D

all it does is start the daemon… without starting another shell to run it in ( that is what exec is for). Most run scripts are that simple.

Unless you want to get into supervising daemons ( not really needed in a home
computer) that is really all there is to setting up runit. In a server you may wish to use supervision.

The reason that runit is simple in Void , is that the package system is setup to work with runit. Installing a package that is a service usually provides all the necessary files in /etc/sv All the user has to do to start the service is to make the necessary link.

Void has several packages relevant to runit in addition to the two basic packages runit and runit-void which come preinstalled

$ xbps-query -Rs runit
[-] rsv-1.3.3_3                    Runit sv command rewritten in rust with nic...
[*] runit-2.1.2_15                 UNIX init scheme with service supervision
[-] runit-iptables-20180616_2      Restore iptables rules on boot
[-] runit-kdump-20150226_5         Crashkernel/kdump support for runit to save...
[-] runit-nftables-20200123_2      Restore nftables rules on boot
[-] runit-swap-2.0.0_2             Script to manage swapspaces
[*] runit-void-20231124_1          Void Linux runit scripts
[-] runit-void-apparmor-20231124_1 Void Linux runit scripts - AppArmor initial...
[-] socklog-2.1.0_6                Small and secure syslogd replacement for us...
[-] sv-helper-2.0.2_2              Utilities to help administer a runit-as-pid...
[-] svctl-1_9                      Interactive controller for runit
[-] vsv-2.0.0_1                    Manage and view runit services

You can see that I have not installed any of these extra packages ([-]).
I tried vsv

It is neat but terminal based, not GUI. There are lots of services running in my Void, those called virt... are supporting virsh and virt-manager.

Learning runit is probably the most challenging part of learning Void. In a distro like Debian one can get away with never touching the init system. In Void, because the package system only installs services, and does not enable them, you have to enable services by hand, and that means learning `runit’

Artix Linux

Artix is Arch with a choice of non-systemd init systems (dinit, OpenRC, runit or S6). You can download an iso with runit preinstalled (eg. artix-xfce-runit-20230814-x86_64.iso is what I used).
When you bring up a freshly installed Artix, you see the following runit files in
/etc/runit

What you see above in /runit/runsvdir/default is the “link farm” for a number of services. They are mostly very essential services like dbus and the tty's.

So those are the default links. The actual services installed are in /etc/runit/sv.
You can just see the /etc/runit/sv directory at the bottom of the tree above.
The first couple of entries in /etc/runit/sv are

There you see the entry for acpid along with its various subdirectories.
The full set of available services in /etc/runit/sv is

There are more services installed, than have been activated by the “link farm”

What we have in Artix, is almost exactly the same as in Void, except

  • the sv subdirectory is inside the /etc/runit directory,
    instead of in /etc
  • the service directory is in /run/runit/service

Now let us see what happens when we install a new package.
We shall try vsftpd
So look at the packages available for vsftp

tr~# pacman -Ss vsftpd
world/vsftpd 3.0.3-9
    Very Secure FTP daemon
world/vsftpd-dinit 20211103-3 (dinit-world)
    dinit service scripts for vsftpd
world/vsftpd-openrc 20210505-1 (openrc-galaxy)
    OpenRC vsftpd init script
world/vsftpd-runit 20200614-3 (runit-galaxy)
    Runit service script for vsftpd
world/vsftpd-s6 20230829-1 (s6-world)
    s6-rc service scripts for vsftpd

Well, apart from vsftpd itself, there are packages of scripts for each init
system that Artix offers.
This is interesting, Artix has solved the problem of packages needing to supply different sets of files , depending on which init system is running, by having separate packages of script files for each init system. That is neat.

So I need to install vsftpd and vsftpd-runit

pacman -S vsftpd
pacman -S vsftpd-runit
...
(1/1) Displaying runit service help ...
	==> Add a service:
	ln -s /etc/runit/sv/<service> /run/runit/service/
	==> Start/stop/restart a service:
	sv <start/stop/restart> <service>

So it displays a little helpful message about how to add the service.
So lets do it. There is a directory /run/runit/service/ but I am going
to ignore that suggestion and put the link directly
in /etc/runit/runsvdir/current

ln -s /etc/runit/sv/vsftpd /etc/runit/runsvdir/current/vsftps

and the link appears in /etc/runit/runsvdir/current , and the ftp daemon is now running

# ps ax | grep vsftpd
 3000 ?        Ss     0:00 runsv vsftpd
 3001 ?        S      0:00 vsftpd -obackground=no

Process 3001 is the vsftpd daemon, process 3000 is the runit supervisor.
You get a runsv process for every service that is activated.
My Artix now supports ftp access.

Artix runit setup is almost identical to Void, except for the location
of the sv directory and the service pointer.
What Artix brings is a a superior way of organizing the package system, so that
it can properly support alternative init systems. The idea of having separate packages for each init system’s script files for each service, is brilliant.

Antix Linux

Antix linux provides .iso files with either sysvinit or runit init systems.
I used artix-xfce-runit-20230814-x86_64.iso.

Antix with runit is a classic runit installation,
exactly as described in the official runit site.
The examples I used in the “How runit works” section were taken from Antix. There is no need to repeat them here. We might just summarize

  • the service directory is /etc/service, it is actually a link

  • /etc/sv contains the collection of run script directories

  • /etc/runit contains the runlevel scripts ( 1, 2, 3) and the runsvdir
    directory which contains the current, default, previous, single and solo link
    farms.

But Antix has more than that. Anti has a GUI interface to runit. If you bring up the Control Centre, choose System, and then choose Choose Startup Services, you get the Runit Service Manager

You can use the Runit Service Manager to do everything that the sv command will do, plus you can enable and disable logging on a per service basis.
Antix is , as far as I know, the only distribution with GUI interface to runit. I believe the GUI Runit Service Manager is provided by Xecure, but I was unable to verify it.

Antix also has one peculiarity. There are a small number of services, mostly very basic startup services, to be found in /etc/init.d directory

These are sysVinit scripts, not runit run scripts.
Runit, at least in Debian based distros, has the property that if it can not find a run script for a service in the /etc/sv directory it looks in /etc/init.d for a sysVinit script and launches that. Antix is Debian based.

I think developers have left some of the very basic scripts used at startup in sysVinit format. You will also see there qemu-guest-agent and spice-vdagent. My Antix is a VM, and I installed these, so clearly the packages I installed had not been converted to supply a runit script directory… they supplied a sysVinit script, so the installer put it in init.d.
On the other hand, I also installed ntp from the package system, and it provided a set of ntp runit scripts in /etc/sv

So some parts of Antix's package system supply runit files. Antix has a compound set of repositories, some being Debian, others Antix.

So Antix is not quite completely runit, it does not have the elegant init-aware package system that Artix has, but it does have some nice features.

2 Likes

Distributions which provide runit as a choice at install time

Some distributions provide a choice of init system in their installer.
This means that they package several init systems into one .iso file, then set an option in the installer
to choose one or more init systems.

PeppermintOS Devuan Edition

The Devuan edition of Peppermint uses the calamares installer, and it offers a choice of
sysVinit, runit, or OpenRC.
I used PeppermintOS-devuan_64_xfce.iso and chose runit as the init system.
After the install completed it booted with the following processes executing

$ ps ax | grep run
    1 ?        Ss     0:00 runit
 1573 ?        Ss     0:00 runsvdir -P /etc/service log: ...........................................................................................................................................................................................................................................................................................................................................................................................................
 1959 ?        Ss     0:00 runsv getty-tty6
 1960 ?        Ss     0:00 runsv getty-ttyS0
 1961 ?        Ss     0:00 runsv getty-tty3
 1962 ?        Ss     0:00 runsv getty-tty5
 1963 ?        Ss     0:00 runsv getty-tty4
 1964 ?        Ss     0:00 runsv getty-tty1
 1965 ?        Ss     0:00 runsv getty-tty2
 1966 ?        Ss     0:00 runsv default-syslog

So runit is process #1, runsvdir is watching /etc/service, and there are 8 runsv processes supervising
several getty’s and syslog. No other services are running

In /etc we have

  • init.d directory containing sysvinit scripts for lots of services
  • sv directory containing subdirectories and run scrips for the getty’s and syslog
    services listed above.
  • runit directory containing
nevj@trinity:/etc/runit$ ls -F
1*  2*  3*  ctrlaltdel*  rc.shutdown  README@  runsvdir/
  • runit/runsvdir directory containing
nevj@trinity:/etc/runit$ ls -lF runsvdir
total 20
lrwxrwxrwx 1 root root   27 Nov 18 21:23 current -> /etc/runit/runsvdir/default/
drwxr-xr-x 2 root root 4096 Nov 20 20:50 default/
drwxr-xr-x 2 root root 4096 Feb 10  2023 default.run/
drwxr-xr-x 3 root root 4096 Nov 18 21:23 single/
drwxr-xr-x 2 root root 4096 Nov 18 21:23 solo/
drwxr-xr-x 2 root root 4096 Feb 10  2023 svmanaged/

and the links are in default

nevj@trinity:/etc/runit$ ls -lF runsvdir/default
total 0
lrwxrwxrwx 1 root root 22 Nov 18 21:23 default-syslog -> /etc/sv/default-syslog/
lrwxrwxrwx 1 root root 22 Feb 10  2023 getty-tty1 -> ../../../sv/getty-tty1/
lrwxrwxrwx 1 root root 18 Nov 18 21:23 getty-tty2 -> /etc/sv/getty-tty2/
lrwxrwxrwx 1 root root 18 Nov 18 21:23 getty-tty3 -> /etc/sv/getty-tty3/
lrwxrwxrwx 1 root root 18 Nov 18 21:23 getty-tty4 -> /etc/sv/getty-tty4/
lrwxrwxrwx 1 root root 18 Nov 18 21:23 getty-tty5 -> /etc/sv/getty-tty5/
lrwxrwxrwx 1 root root 18 Nov 18 21:23 getty-tty6 -> /etc/sv/getty-tty6/
lrwxrwxrwx 1 root root 19 Nov 18 21:23 getty-ttyS0 -> /etc/sv/getty-ttyS0/

So the runit installed in Peppermint is quite minimal. Only the fundamental
getty and syslog services are under runit script control. All the other
services are still sysVinit scripts… you can see them in /etc/init.d

nevj@trinity:~$ ls -F /etc/init.d
alsa-utils*              keyboard-setup.sh*            rc.local*
apparmor*                killprocs*                    rcS@
avahi-daemon*            kmod*                         README@
binfmt-support*          lightdm*                      reboot*
bluetooth*               live-config                   rmnologin*
bootlogd*                lm-sensors*                   rsyslog*
bootlogs*                mountall-bootclean.sh*        saned*
bootmisc.sh*             mountall.sh*                  sendsigs*
brightness*              mount-configfs*               single*
checkfs.sh*              mountdevsubfs.sh*             smartmontools*
checkroot-bootclean.sh*  mountkernfs.sh*               spice-vdagent*
checkroot.sh*            mountnfs-bootclean.sh*        stop-bootlogd*
console-setup.sh*        mountnfs.sh*                  stop-bootlogd-single*
cron*                    networking*                   sudo*
cups*                    network-manager*              umountfs*
cups-browsed*            ntpsec*                       umountnfs.sh*
dbus*                    openbsd-inetd*                umountroot*
elogind*                 plymouth*                     urandom*
eudev*                   plymouth-log*                 uuidd*
halt*                    procps*                       vsftpd*
hostname.sh*             pulseaudio-enable-autospawn*  x11-common*
hwclock.sh*              rc@

All those executable files ( marked with *) are sysvinit scripts).
They wer all present at install time, except vsftpd which I installed as a test.
All these services are running. It is not clear to me whether runit automatically executes
all scripts in /etc/init.d, or whether it is triggered in some way.

There is a link /etc/init.d/rc which points to /lib/init/rc which is a script that starts and stops servics according to runlevel.
There is also a link /etc/init.d/rcS which points to a script /lib/init/rcS which
again is a script and it executes `/etc/init.d/rc’.
This is sysVinit stuff. I dont understand it, but I think starting and stopping of services in
Peppermint is still under control of sysVinit. Runit only provides process #1
and a few basic services.
At some point during startup, the runit process #1 must launch these sysVinit scripts

So Peppermint Devuan with runit is a hybrid. The package system only supplies sysVinit scripts.
They have not dealt with the problem of package system support for runit.

2 Likes

Distributions in which runit is available a package

Some distributions provide a runit package, but do not have it as the default init
system. In this case it is up to the user
to install a runit package and to configure runit. If the runit package is replacing sysVinit, or OpenRC, the changeover from init to runit is quite easy. If the runit package is to replace systemd, the changeover is much more complicated and involves some additional transitional packages.

In any case, the amount of support for runit provided by the package system will determine how effectively a swapover to runit can be implemnented.

Devuan

Devuan comes only with sysVinit. It provides packages for OpenRC, S6 and runit. There is no init option in the installer, if the install is from a .iso file, but I believe the netinstall provides an init choice.

When you install Devuan from the .iso file, you get the following in /etc

  • an /etc/init.d directory containing all the sysVinit scripts.
  • an /etc/sv directory containing only the runit run and log files for acpid
  • a /etc/runit directory containing only the runsvdir subdirectory, which in turn contains only a default subdirectory containing only one link which points to
    /etc/sv/acpid

and you get the init process as process #1.
In other words, you get sysVinit fully configured, plus an example setup for runit
which configures only the acpid service.

Now what happens if you install runit as a package on top of sysVinit?

$ apt-cache search runit
dh-runit - debhelper add-on to handle runit runscripts
golang-github-soundcloud-go-runit-dev - Go library wrapping runit service status
mini-httpd-run - Small HTTP server (Runit integration)
runit - system-wide service supervision
runit-helper - dh-runit implementation detail
runit-init - system-wide service supervision (as init system)
runit-run - service supervision (systemd and sysv integration)
runit-services - UNIX init scheme with service supervision (services)
runit-systemd - transitional package for runit-systemd users
socklog-run - system and kernel logging services - runit services
init-system-helpers - helper tools for all init systems
live-config-runit - Live System Configuration Components (runit backend)

Which package? Well I installed runit-init because I wanted runit to be process #1
and to supervise services. This dragged in several other packages, runit, runit-helper, fgetty, getty-run, and sysuser-helper. It also removed some packages, live-config, live-config-sysvinit, refractasnapshotbox, refractasnapshotgi, sysvinit-core. I assume the removed packages are all to do with sysvinit…

After this, my Devuan has the following

  • /etc/init.d still contains a large number of sysVinit scripts. Exactly the same as before.
  • /etc/sv now has the following
$ cd /etc
nevj@trinity:/etc$ ls sv
acpid         dbus            exim4       getty-tty4   mdadm
acpi-fakekey  dbus.dep-fixer  getty-hvc0  getty-tty5   rsyslog
anacron       default-syslog  getty-tty1  getty-tty6   slim
cron          dhclient        getty-tty2  getty-ttyS0  svlogd
cups          elogind         getty-tty3  getty-ttyv0  wicd
  • /etc/runit now has
$ ls runit
1  2  3  ctrlaltdel  rc.shutdown  README  runsvdir

  • /etc/service is now a link to /etc/runit/runsvdir/current
  • /etc/runit/runsvdir/current has the following link
nevj@trinity:/etc$ ls -l /etc/runit/runsvdir/current
lrwxrwxrwx 1 root root 27 Dec  1  2021 /etc/runit/runsvdir/current -> /etc/runit/runsvdir/default

and /etc/runit/runsvdir/default has

c$ ls -l /etc/runit/runsvdir/default
total 0
lrwxrwxrwx 1 root root 13 Dec  1  2021 acpid -> /etc/sv/acpid
lrwxrwxrwx 1 root root 20 Nov  8 22:35 acpi-fakekey -> /etc/sv/acpi-fakekey
lrwxrwxrwx 1 root root 15 Nov  8 22:35 anacron -> /etc/sv/anacron
lrwxrwxrwx 1 root root 12 Nov  8 22:35 cron -> /etc/sv/cron
lrwxrwxrwx 1 root root 12 Nov  8 22:35 cups -> /etc/sv/cups
lrwxrwxrwx 1 root root 12 Nov  8 22:35 dbus -> /etc/sv/dbus
lrwxrwxrwx 1 root root 22 Nov  8 22:35 dbus.dep-fixer -> /etc/sv/dbus.dep-fixer
lrwxrwxrwx 1 root root 22 Nov  8 21:46 default-syslog -> /etc/sv/default-syslog
lrwxrwxrwx 1 root root 16 Nov  8 22:35 dhclient -> /etc/sv/dhclient
lrwxrwxrwx 1 root root 15 Nov  8 22:35 elogind -> /etc/sv/elogind
lrwxrwxrwx 1 root root 22 Mar 10  2019 getty-tty1 -> ../../../sv/getty-tty1
lrwxrwxrwx 1 root root 18 Jun 20  2021 getty-tty2 -> /etc/sv/getty-tty2
lrwxrwxrwx 1 root root 18 Jun 20  2021 getty-tty3 -> /etc/sv/getty-tty3
lrwxrwxrwx 1 root root 18 Jun 20  2021 getty-tty4 -> /etc/sv/getty-tty4
lrwxrwxrwx 1 root root 18 Jun 20  2021 getty-tty5 -> /etc/sv/getty-tty5
lrwxrwxrwx 1 root root 18 Jun 20  2021 getty-tty6 -> /etc/sv/getty-tty6
lrwxrwxrwx 1 root root 19 Nov  8 21:42 getty-ttyS0 -> /etc/sv/getty-ttyS0
lrwxrwxrwx 1 root root 13 Nov  8 22:35 mdadm -> /etc/sv/mdadm
lrwxrwxrwx 1 root root 15 Nov  8 22:35 rsyslog -> /etc/sv/rsyslog
lrwxrwxrwx 1 root root 12 Nov  8 22:35 slim -> /etc/sv/slim

in other words, a link to every service in /etc/sv.

The services in /etc/sv duplicate some of the services in /etc/init.d,
but by no means all. What this means is that some of the services have
been configured for runit while the remainder have been left as sysVinit scripts,
which the runit process will execute if it does not find a run file in /etc/sv.

So what I end up with is a hybrid system. I suspect that there are still many
packages that do not provide runit support.

One might conclude that Devuan has not completely solved the alternate init system
problem. It goes a long way by removing systemd, and providing alternate init system
packages, but its package system has not been adapted to deal properly with
init alternatives. This is not surprising, as Devuan depends on Debian for most
of its package system.

Debian

Debian comes only with systemd, but Debian (since Debian 11) does provide a runit package , plus some transitional packages for converting from systemd. There is also a procedure for doing a chmod during the install and installing runit there.
The packages provided are


nevj@debianvm:~$ apt-cache search runit
dh-runit - debhelper add-on to handle runit runscripts
runit-helper - dh-runit implementation detail
djbdns-conf - programs to create service directories
mini-httpd-run - Small HTTP server (Runit integration)
getty-run - runscripts to supervise getty processes
runit - system-wide service supervision
runit-init - system-wide service supervision (as init system)
runit-run - service supervision (systemd and sysv integration)
runit-systemd - transitional package for runit-systemd users
runit-services - UNIX init scheme with service supervision (services)
libs6-2.11 - small and secure supervision software suite (shared library)
libs6-dev - small and secure supervision software suite (development files)
s6 - small and secure supervision software suite
s6-doc - small and secure supervision software suite (documentation)
snooze - run a command at a particular time
socklog - system and kernel logging services - binaries
socklog-run - system and kernel logging services - runit services

The instructions for doing a runit conversion are here

I have not tried it. It would seem to be very complicated, particularly the
package system issues. It would be much simpler to start from Devuan and not have the systemd transitional problems.

It is worth noting that Devuan seem to have backtracked on the systemd only
decision, and now provide several alternative init systems. They still have some way to go to provide package system support for these alternatives.

Gentoo

Gentoo comes with the OpenRC init system. You can add systemd or runit
by emerging packages.
I left my Gentoo install with OpenRC, and I blocked it from installing any package requiring systemd by setting USE= -systemd in /etc/portage/make.conf
and by putting sys-apps/systemd in /etc/portage/package.mask/package.mask

OpenRC is not much more than a friendly frontend to sysVinit.
It has 3 commands rc-status, rc-update, and rc-serviceand it has therunlevel` concept of sysVinit.

My Gentoo, as installed, has the following

  • init is process #1
  • /etc/init.d contains sysVinit scripts for all the services
  • there are no runit directories like sv, or runit, or service.
  • /etc/runlevels contains subdirectories boot, default, nonetwork,
    shutdown, and sysinit, each of which contains a set of symbolic links
    to scripts in /etc/init.d

Now what happens if I emerge the runit package?
Lets find it first

nevj@mary ~ $ emerge --search runit

[ Results for search key : runit ]
Searching...
*  sys-process/runit
      Latest version available: 2.1.2-r1
      Latest version installed: [ Not Installed ]
      Size of files: 109 KiB
      Homepage:      http://smarden.org/runit/
      Description:   A UNIX init scheme with service supervision
      License:       BSD

Now lets see wjhat it would do if I installed it

nevj@mary ~ $ emerge --ask --pretend sys-process/runit

These are the packages that would be merged, in order:

Calculating dependencies... done!
Dependency resolution took 1.47 s (backtrack: 0/20).

[ebuild  N     ] sys-process/runit-2.1.2-r1  USE="-static"

Nothing very dangerous there, it does not remove anything , so lets try it

mary /home/nevj # emerge --ask sys-process/runit

These are the packages that would be merged, in order:

Calculating dependencies... done!
Dependency resolution took 1.38 s (backtrack: 0/20).

[ebuild  N     ] sys-process/runit-2.1.2-r1  USE="-static" 

Would you like to merge these packages? [Yes/No] yes

>>> Verifying ebuild manifests

>>> Emerging (1 of 1) sys-process/runit-2.1.2-r1::gentoo
>>> Downloading 'https://mirror.aarnet.edu.au/pub/gentoo/distfiles/09/runit-2.1.2.tar.gz'
--2023-12-09 21:25:01--  https://mirror.aarnet.edu.au/pub/gentoo/distfiles/09/runit-2.1.2.tar.gz
Resolving mirror.aarnet.edu.au... 2001:388:30bc:cafe::beef, 202.158.214.106
Connecting to mirror.aarnet.edu.au|2001:388:30bc:cafe::beef|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 110916 (108K) [application/x-gzip]
Saving to: ‘/var/cache/distfiles/runit-2.1.2.tar.gz.__download__’

/var/cache/distfile 100%[===================>] 108.32K  --.-KB/s    in 0.1s    

2023-12-09 21:25:01 (834 KB/s) - ‘/var/cache/distfiles/runit-2.1.2.tar.gz.__download__’ saved [110916/110916]

 * runit-2.1.2.tar.gz BLAKE2B SHA512 size ;-) ...                         [ ok ]
>>> Unpacking source...
>>> Unpacking runit-2.1.2.tar.gz to /var/tmp/portage/sys-process/runit-2.1.2-r1/work
>>> Source unpacked in /var/tmp/portage/sys-process/runit-2.1.2-r1/work
>>> Preparing source in /var/tmp/portage/sys-process/runit-2.1.2-r1/work/admin/runit-2.1.2/src ...
>>> Source prepared.
>>> Configuring source in /var/tmp/portage/sys-process/runit-2.1.2-r1/work/admin/runit-2.1.2/src ...
>>> Source configured.
>>> Compiling source in /var/tmp/portage/sys-process/runit-2.1.2-r1/work/admin/runit-2.1.2/src ...
make -j4 
   ..........
   lots of compiling
   ..........
>>> Source compiled.
>>> Test phase [not enabled]: sys-process/runit-2.1.2-r1

>>> Install sys-process/runit-2.1.2-r1 into /var/tmp/portage/sys-process/runit-2.1.2-r1/image/
>>> Completed installing sys-process/runit-2.1.2-r1 into /var/tmp/portage/sys-process/runit-2.1.2-r1/image/

 * Final size of build directory: 2444 KiB (2.3 MiB)
 * Final size of installed tree:   736 KiB

strip: x86_64-pc-linux-gnu-strip --strip-unneeded -N __gentoo_check_ldflags__ -R .comment -R .GCC.command.line -R .note.gnu.gold-version
   /bin/chpst
   /sbin/runit
   /sbin/runit-init
   /bin/runsv
   /bin/runsvchdir
   /bin/runsvdir
   /bin/sv
   /bin/svlogd
   /sbin/utmpset

>>> Installing (1 of 1) sys-process/runit-2.1.2-r1::gentoo
 * The links to services runit will supervise are installed
 * in /etc/service.
 * If you need multiple runlevels, please see the documentation
 * for how to set them up.
 * 
 * To make sure sv works correctly in your currently open
 * shells, please run the following command:
 * 
 * source /etc/profile
 * 

>>> Recording sys-process/runit in "world" favorites file...

>>> Completed (1 of 1) sys-process/runit-2.1.2-r1::gentoo

 * Messages for package sys-process/runit-2.1.2-r1:

 * To make sure sv works correctly in your currently open
 * shells, please run the following command:
 * 
 * source /etc/profile
 * 

 * GNU info directory index is up-to-date.

 * IMPORTANT: 4 config files in '/etc' need updating.
 * See the CONFIGURATION FILES and CONFIGURATION FILES UPDATE TOOLS
 * sections of the emerge man page to learn how to update config files.
mary /home/nevj # exit
exit
Script done.
mary /home/nevj # 

So what do we have now in /etc?

  • /etc/sv exists and contains the following
  nevj@mary /etc $ ls sv
  
getty-tty1  getty-tty2  getty-tty3  getty-tty4  getty-tty5  getty-tty6

in other words , just the getty processes that support terminals

  • etc/runit contains
    nevj@mary /etc $ ls runit
1  2  3  ctrlaltdel

in other words, just the 3 runlevels that runit uses

- `/etc/service` contains
    nevj@mary /etc $ ls -l service
total 0
lrwxrwxrwx 1 root root 18 Dec  9 21:25 getty-tty1 -> /etc/sv/getty-tty1
lrwxrwxrwx 1 root root 18 Dec  9 21:25 getty-tty2 -> /etc/sv/getty-tty2
lrwxrwxrwx 1 root root 18 Dec  9 21:25 getty-tty3 -> /etc/sv/getty-tty3
lrwxrwxrwx 1 root root 18 Dec  9 21:25 getty-tty4 -> /etc/sv/getty-tty4
lrwxrwxrwx 1 root root 18 Dec  9 21:25 getty-tty5 -> /etc/sv/getty-tty5
lrwxrwxrwx 1 root root 18 Dec  9 21:25 getty-tty6 -> /etc/sv/getty-tty6

in other words , links to the runit services in sv

  • everything else is still in init.d
   nevj@mary /etc $ ls init.d
agetty                 hwclock            runsvdir
binfmt                 ip6tables          s6-svscan
bluetooth              iptables           savecache
bootlogd               keymaps            save-keymaps
bootmisc               killprocs          save-termencoding
cgroups                kmod-static-nodes  seedrng
chronyd                local              sshd
consolefont            localmount         swap
cups-browsed           loopback           swclock
cupsd                  modules            sysctl
dbus                   mount-ro           sysfs
devfs                  mtab               sysklogd
device-mapper          net.lo             systemd-tmpfiles-setup
dhcpcd                 netmount           systemd-tmpfiles-setup-dev
display-manager        net-online         termencoding
display-manager-setup  nullmailer         transmission-daemon
dmcrypt                numlock            udev
dmesg                  osclock            udev-settle
elogind                pciparm            udev-trigger
fsck                   procfs             vsftpd
functions.sh           pydoc-3.11         wpa_supplicant
git-daemon             pydoc-3.12         xdm
gpm                    root
hostname               rsyncd

in other words, they are all still sysVinit scripts

  • openrc is still present, and its commands still work

  • process #1 is still init… not runit.

Now what happens if I reboot?

nevj@mary /etc $ ps ax | grep init
    1 ?        Ss     0:00 init [3]

Process #1 is still init… runit did not take control of the init process?
Why?

There it is in the dmesg output

[    1.396489] Run /init as init process
[    1.396551]   with arguments:
[    1.396552]     /init
[    1.396553]   with environment:
[    1.396553]     HOME=/
[    1.396554]     TERM=linux
[    1.396554]     BOOT_IMAGE=/boot/vmlinuz-6.6.0-gentoo-x86_64

So, time to read the manual.
Gentoo has a wiki page on runit

https://wiki.gentoo.org/wiki/Runit

and a wiki talk page

https://wiki.gentoo.org/wiki/Talk:Runit

both are really essential reading if you want to implement runit in Gentoo.
It seems there are several ways of using runit

  • as init and RC with OpenRC
  • as init and RC without OpenRC
  • as PID 1 but not RC
  • as service supervisor but not init

I will try the third case … replace init with runit but let OpenRC handle all the services. I edit /etc/runit/1 and insert the line

RUNLEVEL=S /sbin/rc default

Then reboot, and … it does not work.
OK, maybe I have to tell the kernel to use runit-init… so add

init=/sbin/runit-init

to the linux line in the grub menu, let it boot,
and, …it boots with runit as PID #1, and there is also a runsvdir process running, and a runsv process for each of getty1 to getty6, but no services and no logs. Also I only have a console login… Xfce will not start… not surprising if there are no services.

I will try to start some services. I edit /etc/runit/1 and insert the line

RUNLEVEL=S /sbin/rc default

This should use rc to start the default set of daemons, which are

$ rc-status default
Runlevel: default
 sysklogd       
 wpa_supplicant
 dhcpcd       
 vsftpd      
 chronyd    
 dbus      
 cupsd    
 netmount
 display-manager  
 local           
 

It might help to have a display-manager and dbus.
Reboot, again with the modified CMDLINE , and this time it works.

 nevj@mary ~ $ ps ax | grep run
    1 ?        Ss     0:00 runit
 2474 ?        Ss     0:00 runsvdir -P /etc/service log: ...........................................................................................................................................................................................................................................................................................................................................................................................................
 2477 ?        Ss     0:00 runsv getty-tty5
 2478 ?        Ss     0:00 runsv getty-tty3
 2479 ?        Ss     0:00 runsv getty-tty6
 2480 ?        Ss     0:00 runsv getty-tty4
 2481 ?        Ss     0:00 runsv getty-tty2
 2482 ?        Ss     0:00 runsv getty-tty1
 2500 tty7     Ssl+   0:01 /usr/bin/X :0 -seat seat0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch
 2749 ?        S      0:00 /usr/bin/dbus-daemon --config-file=/usr/share/defaults/at-spi2/accessibility.conf --nofork --print-address 11 --address=unix:path=/run/user/1000/at-spi/bus_0
 2820 ?        Sl     0:00 xfce4-terminal --geometry=80x24 --display :0.0 .................

So runit still only supervises the getty processes, but all the default services are running under control of OpenRC

Now, I dont want to have to edit the grub menu every time I boot it,
so I need to set the kernel boot parameter in /etc/default/grub

# Boot with runit instead of sysvinit
GRUB_CMDLINE_LINUX="init=/sbin/runit-init"

Then, after much soul searching, I find that I have to run
grub-mkconfig -o /boot/grub/grub.cfg
in Gentoo, and then run update-grub in Debian, with os-prober enabled, because Debian controls my grub, and os-prober needs to see the updated grub.cfg in Gentoo.

After that It boots Gentoo with runit automatically.

There is still one issue, if I have Gentoo with runit as process #1, it does not halt or reboot or shutdown. This is documented. One needs to do a shutdown with
runit-init 0
and to do a reboot with
runit-init 6

We now come to the difficult business of using runit to control services, either with or without OpenRC.
I am not going to attempt this, for the simple reasion that it is not
properly supported by the Gentoo package system - Gentoo packages
provide sysVinit scripts , not runit scripts.

There are some third party runit scripts available

and

https://github.com/powerman/powerman-overlay/blob/master/power-misc/runit-scripts/runit-scripts-1.5.0.ebuild

but they are not in the Gentoo repo, one has to obtain them from Github.The other option would be to write your own scripts.
It is not worth the trouble.

So, concluding remarks for Gentoo are

  • it supplies a runit package
  • it is easy to use runit as the init process
  • it is not easy to use runit to manage services
  • the Gentoo runit documentation is excellent. It tells you exactly
    what the situation is and how to go about doing things.
2 Likes

Recommendations

I found the following

  • The best implementations of runit are Void and Artix. Antix is a close second.
  • If you want a GUI controlled init system use Antix
  • If you want to try runit , try a system with it pre-installed - either
    Void or Artix or Antix.
  • It is important that a distro provides package support for runit. Just providing a runit package is inadequate. Every package that installs a daemon should
    come with a runit script.
  • the best package system design for using multiple init systems in Artix.
  • the fact that Debian now makes a runit package available is interesting. They have backed down on the systemd only approach. They have not adapted the package system.
  • Devuan is supposed to support multiple init systems, but it has a long way to go to provide something as good as the Artix package system. Same applies to Peppermint Devuan Edition.
  • Gentoo has the best runit documentation. It spells out all the limitations.
  • Runit has some merit over sysVinit. It boots faster, and its scripts are simpler.
6 Likes

Hi Neville, :wave:

congratulations on your brilliant treatise on runit. :+1: :fireworks:

It clearly shows you´ve put a lot of work, time and effort into dealing with this subject.

As you already mentioned:

I´m using Linux Lite 6.2 (which is based on ubuntu, that one is based on debian, of course) and I have to admit your statement is certainly true in my case. I never ever even thought about init systems.

Your discourse shows in a perfect way that there´s a lot of variety and difference in the complexity of init systems.
I´d never have thought runit was so complex.

Although I read through all of your posts very carefully I´m not ashamed to admit I may have to do so a couple more times in order to even begin to be able to cope with how runit works.

Thanks a lot for introducing us to the concept of init together with its intricacies. :heart:

Many greetings from Rosika :slightly_smiling_face:

2 Likes

They’re probably starting to see systemd tends to destroy init freedom. It’ll be interesting what they’ll be doing in future with this.

I’ve toyed with Void Linux. Runit is a wonderful little init system. It has its flaws, mostly uncertain init order, but that can easily be worked around for the daemons that need some other services to be started before them.

Please, continue these articles on alternative init systems. They need the exposure. S6 next, perhaps? s6-linux-init - tools for a Linux init system

3 Likes

Hi Xander,
Yes, because runit can start daemons in parallel , it can have problems with dependencies between daemons.

Void is about the best you will get in a
single-init-system-non-systemd-linux

The big issue with mult-init-system-linuxes
is package system support. Even Devuan has not mastered that. The Artix approach is
perhaps the best.

Will try again next year
Regards
Neville

2 Likes

Hi Rosika,
Thank you for kind words.
Variety happens when something is rapidly
evolving.
Be prepared for a period of diversity in init systems. Then something will win, and it will settle down to one or two major options.
Regards
Neville

2 Likes

Great text Neville! Thanks for the hard work and detailed information!

3 Likes

Hi ihasama,
Thank you for kind words.
Neville

2 Likes

Hi Neville,

This is hands down the best overview of using runit available. Thank you for the huge amount of work you’ve put into it, I for one really appreciate it.

I had installed Devuan using runit and couldn’t work out why all those Sysvinit scripts were still there. It took me a while to work out that Devuan was not supplying runit scripts for a lot of the packages. It would be nice to see them adding these scripts, maybe in the way that Artix does.

One of the biggest benefits of runit is its simplicity, meaning you can understand it and confirm nothing malign is happening, all in stark contrast to systemd.

Al

3 Likes

Yes, I have fond memories of working with runit in Void Linux.

Service needs to be initialized before another service? Just call the needed service from the init script and you’re golden.

Alas, I changed. My needs changed with me. Now I run Linux Mint. But I know runit is a lot of non-suck and really simple to deal with. I like keeping up-to-date on articles and stuff, even though I technically don’t need them :slight_smile:

3 Likes

Hi Al,
Welcome to itsFOSS
Well what a lovely message to receive Christmas morning.
Thank you. I am glad someone found it useful.

I too had problems with Devuan, even though I had prior
experience with Void.
It took me ages to realize that the culprit was the package system not supplying runit scripts.
I have had some more practice since writing that topic. This time with Peppermint Devuan edition, which is same as Devuan. I learnt that if I do write a runit script for an installed service, I need to disable the sysVinit script, otherwise both sysVinit and runit will try to start the daemon. You disable sysVinit scripts in the /etc/rc*.d files. The traditional method is to find the rc.d entry, which is a link, and prefix it with an underscore (that hides it and you can get it back easily). You need to grasp runlevels to work with sysVinit.

Maybe I should write some more on that. Need more practice first. There is nothing like doing it to make sure you get things correct. SysVinit scripts are more complicated than runit scripts.

There is also S6… which is a sort of a simplified fork of runit.
Have not tried S6 yet, but It seems to be worth attdntion

I am really impressed with the way Artix have setup runit to work alongside other init systems. They alone have conquered the package system problem with multiple inits.

Void is another fine example of runit, but it is runit only, no choice of init.

Merry Christmas
Regards
Neville

1 Like

Being able to look at the filesystem and see what commands do is a basic property of Unix and Linux. Systemd undermines that . You say it well.

You have a lot of experience. itsFOSS is a good place to share it. If you have the time, try writing an article.

The markdown files used to construct this topic are available here

2 Likes