s6 with OpenRC

Usually OpenRC is paired with SysVinit in almost all of it’s implementations, it is however possible to combine OpenRC with other init systems such as s6.

So what is the difference between SysVinit, OpenRC, and s6? Well first off, let’s discuss what an init is. The boot process for a standard GNU/Linux system is as follows:

bootloader:

This is the first thing that is loaded, it handles very basic minimal mounting and setup needed to run the system. Some examples of bootloaders are grub and lilo. The bootloader will load the kernel and initramfs system.

kernel:

The linux kernel is loaded by the boot loader and handles all the most important things with hardware, drivers, etc. Once the linux kernel finishes, it then proceeds to run the following executable: “/sbin/init” as PID 1 which is Process ID 1.

init:

The init is always PID 1. It is the parent of all other processes and is responsible for mounting basic partitions, setting the hostname, etc. It is the most important process that is running on your computer. If it fails or crashes, the linux kernel will get a kernel panic. Naturally it is important for the init to be as stable as possible and to never crash. This is why init should be as basic as possible, the more complex init is, the more likely it is to crash. I great idea to make sure that it stays stable is to split off the things it has to do into scripts, then split this scripts off into another thread, that way if the script fails, it does not crash PID 1.

rc:

The init PID1 should now start running a system to manage the rest of the initialization of the system. Starting ssh, gui, apache, etc. In this case OpenRC handles the starting of the services using runlevels. In particular OpenRC has sysinit which will setup everything needed to work with the kernel and the hardware such as udev. The boot runlevel will mount your partitions based on “/etc/fstab”, set the clock, set the hostname, configure keyboard and language, etc. Then finally the default runlevel will boot all your standard processes such as apache, ssh, xdm, etc.

SysVinit is an init, OpenRC handles services, and s6-linux-init is also an init. There is also a s6-rc software available to use instead of OpenRC but it’s implementation is beyond the scope of this article.

Getting a working s6 init is very easy. The prerequisites that need to be compiled and installed are skalibs, execline, s6-portable-utils, s6-linux-utils, and s6 all of which can be obtained from the s6 website. Once the required software is compiled and installed you can install s6-linux-init.

s6-linux-init once compiled and installed gives you a program that creates a base init system with s6. To make the init system that will be used, the following command must be run:

# s6-linux-init-maker /etc/s6-linux-init

What this command does is create a folder in /etc/s6-linux-init and fill it with the necessary files needed to boot the system. You will find 2 directories in the /etc/s6-linux-init folder, “env” which should contain things needed for the init environment. With OpenRC being uses to manage services, the “env” folder does not need any usage. The other folder is “run-image”. This folder is copied to the tmpfs directory /run directory then s6-svscan will use it to start the services that are located in this folder. In this case the only service is s6-svscan-log which is used for logs. To get a tty running after init is complete, we need to make a service folder for it:

# mkdir /etc/s6-linux-init/run-image/service/tty1

Now make a file called “/etc/s6-linux-init/run-image/service/tty1/run” with the following content:

Don’t forget to change “/sbin/agetty” to the location of your getty program in your particular linux distro. For example in Arch Linux this will be located in “/usr/bin/agetty”. You can also make folders such as tty2, tty3, etc. This will allow you to have various ttys to access. I currently use 6 ttys.

Now in the /etc/s6-linux-init directory you will find a shell file called “init”. This is what will run as the init on your system. What I recommend to do is backup your “/sbin/init” file in case something goes wrong. I would rename it to something like “/sbin/init-bkp” this is important because if your system fails to boot you can fallback by using the kernel argument:

init=/sbin/init-bkp which will boot the system using the old init instead of s6’s init.

To make this easier, I use the following in my grub config file:

So I have 2 grub entries, one that is using s6 as init, and one that falls back to SysVinit if something goes wrong.

Next we need a stage2 script which will be responsible for getting OpenRC to run and get the system bootable. Be default this file should be an executable script located in: /etc/rc.init

The script should contain the following:

This will set the RUNLEVEL needed by OpenRC, then it will start the 3 runlevels: sysinit, boot, and default.  Again, don’t forget to change “/sbin/openrc” to the location of your openrc executable on your system. In Arch Linux this will be in “/usr/bin/openrc”.

Now if everything was done properly, you can reboot using s6 as your init with OpenRC handling rc for services.

This is a basic implementation to help get started with s6 as an init system. A lot more can be done with it to improve the workings between s6 and OpenRC. From my testing so far the s6 init is very stable and seems to be a very good replacement for SysVinit.

1 thought on “s6 with OpenRC”

Leave a Reply