How Linux Implements the Runit Init Scheme

This article explains how the Linux operating system implements the runit initialization scheme, an alternative to systems like systemd and SysVinit. Best known for its primary role in Void Linux, runit handles process initialization, supervision, and shutdown using small, modular components adhering to the Unix philosophy. Below is an overview of the three-stage initialization cycle, the service supervision tree, service directory management, and the control mechanisms that make runit fast, reliable, and resource-efficient.

The Three-Stage Boot Process

When the Linux kernel finishes booting, it starts the primary init process, PID 1, targeting /sbin/init (which is a symlink to /usr/bin/runit or /etc/runit/init). Once executed, runit organizes the machine's life cycle into three distinct, sequential stages handled by three executable shell scripts located in /etc/runit/.

Stage 1: System Initialization

Stage 1 executes /etc/runit/1. This stage runs once at boot to perform essential hardware and system preparation tasks:

Stage 1 must exit successfully (with return code 0) before the system moves on. If it fails, the boot process halts to prevent file corruption.

Stage 2: Runtime and Service Supervision

Upon the successful completion of Stage 1, runit moves to /etc/runit/2. This stage represents the live, running state of the operating system.

Instead of handling individual services directly, /etc/runit/2 launches runsvdir, the primary service supervision daemon. runsvdir runs continuously until the system is instructed to shut down or reboot. If the script /etc/runit/2 crashes or terminates unexpectedly, runit immediately restarts it.

Stage 3: Shutdown and Reboot

When an administrator triggers a reboot or power-off, runit terminates Stage 2 and executes /etc/runit/3. This script handles system shutdown tasks:

Service Supervision: runsvdir and runsv

The supervision architecture of runit relies on a clear parent-child hierarchy managed by two core programs:

runit (PID 1)
 └── runsvdir
      ├── runsv (service A)
      │    └── service A daemon
      ├── runsv (service B)
      │    └── service B daemon
      └── runsv (service C)
           ├── service C daemon
           └── logger daemon
  1. runsvdir: Continuously monitors a target directory (typically /var/service/). For every sub-directory found inside, runsvdir spawns an individual runsv process. If a sub-directory is removed, runsvdir instructs the corresponding runsv process to exit.
  2. runsv: Directly supervises a single service. It runs an executable script named run inside the service's directory. Because runsv runs as the direct parent of the service daemon, it captures exit codes instantly through standard Unix signals without polling. If the daemon crashes or exits, runsv immediately restarts it.

Services in runit are configured to run in the foreground. This eliminates the need for daemons to fork themselves into the background, avoiding orphaned processes and PID file tracking issues.

Service Management in Void Linux

Void Linux uses simple filesystem primitives to enable, disable, and control services:

Control Interface: The sv Command

Administrative control over services is handled using the sv utility, which communicates with the individual runsv supervisors via named pipes (FIFOs) located in the service directories.

Common commands include:

Logging

runit manages logs without a monolithic centralized logging daemon. A service directory can optionally contain a sub-directory named log with its own executable run script.

When present, runsv creates a UNIX pipe connecting the standard output of the primary service directly to the standard input of the logger script. Void Linux typically couples this with utilities like vlogger or socklog (a syslog replacement), providing segregated, low-overhead logging that isolates individual service failures.