A RVNIT MANUAL 2022-01-27 Overview Rvnit is a small but flexible init-system and supervision daemon. There are three main applications it is designed for: - As init for a Linux machine - As init for a Linux container - As unprivileged supervision daemon Rvnit is configured by a directory of scripts, defaulting to /etc/rvnit. In this directory, rvnit looks into executable files (called tasks) that start with two digits and do not end with ~. rvnit distinguishes between several kinds of tasks identfied by the third letter of the file name: - 'S': startup scripts - 'K': shutdown scripts - 'D': daemons - 'L': loggers - 'G': global loggers - 'E': error handlers Modes of operation The lifecycle of a machine/container/session using rvnit consists of three phases. First, the system is *booted*, by spawning tasks in order from 00 to 99. This means that for each level 00 to 99: - startup scripts are run - daemons are run - loggers are run, and connected to daemons - global loggers are run, and connected to the global log - if a startup script failed, the first error handler of the same or lower level is run, then the startup script is run again; if the error handler returns 111, the startup script is skipped. - the level is finished when all startup scripts ran successfully. After reaching level 99, the system is in the second phase, the *uptime*. During uptime, rvnit - respawns daemons that have exited, but no more than once a second - responds to commands sent by rvnitctl - waits for a SIGINT, SIGTERM (containers and non-pid 1 only), Ctrl-Alt-Delete, or rvnitctl command to start the shutdown *Shutdown* progresses in levels again, this time from 99 to 00 backwards. For each level: - shutdown scripts are run - daemons are stopped, first by SIGTERM and after 7s by SIGKILL - loggers are stopped by closing their stdin Upon reaching level 0, rvnit will poweroff or reboot the machine/container. Controlling rvnit with rvnitctl During the uptime of the system, you can remote control rvnit using the tool rvnitctl. Usage: rvnitctl [COMMAND] [SERVICE] Only the first letter of command is relevant, but mnemonic: - status: show a list of daemons, loggers, and global logger, and their state, pid, uptime and last exit status. - up: start SERVICE - down: stop SERVICE - p: send signal SIGSTOP to SERVICE - c: send signal SIGCONT to SERVICE - h: send signal SIGHUP to SERVICE - a: send signal SIGALRM to SERVICE - i: send signal SIGINT to SERVICE - q: send signal SIGQUIT to SERVICE - 1: send signal SIGUSR1 to SERVICE - 2: send signal SIGUSR2 to SERVICE - t: send signal SIGTERM to SERVICE - k: send signal SIGKILL to SERVICE - rescan: re-read /etc/rvnit, start added daemons, stop removed daemons - Shutdown: shutdown (poweroff) the system - Reboot: reboot the system Logging with rvnit Rvnit distinguishes two kinds of logging mechanism: - Loggers are associated to one daemon and get the daemon stdout as stdin. This is a 1:1 correspondence between daemons and loggers, and they must be named exactly the same, except one has a 'D' and one a 'L'. Rvnit keeps the pipes between daemons and loggers open and can respawn daemons and loggers without loss of data. - The global logger gets logs from all tasks that don't have a custom logger, as well as rvnit's own log output. Rvnit keeps a global log pipe and associates logged lines with their origin pid and time. This pipe is written to even before the global logger is started, so the global logger will get all messages since boot time. Rvnit as init for Linux Rvnit is self-contained and can be booted directly as pid 1. It will mount /dev and /run when required, everything else is left to startup scripts. When receiving Ctrl-Alt-Delete, rvnit triggers an orderly reboot. Rvnit as init for a Docker container Fresh binary releases are provided in Alpine containers at https://hub.docker.com/r/leahneukirchen/rvnit/tags rvnit is compiled statically, so you can copy it out if you have different needs: COPY --from=docker.io/leahneukirchen/rvnit:latest /bin/rvnit /bin/ CMD ["/bin/rvnit"] Note that /run must exist in the container if you want to use the default control socket name. You can put the control socket onto a bind-mount and remote-control rvnit using rvnitctl from the outside by pointing RVNIT_SOCK to the appropriate target.