Files
Joachim Wiberg e8391864d7 conf: read /run/finit/system before /lib/finit/system
Stanzas in /lib/finit/system cannot use if:keventd, or any other
built-in service: if: is evaluated at parse time, and the generated
.conf files for built-ins were read after the system directory, so the
referenced service did not exist yet and the stanza was dropped.

The late position was deliberate: it kept bundled services from starting
before udev (5d703fd3).  The motivating case was dbus, which has since
moved to a build-time 20-dbus.conf (2e0b1d6f), and the built-ins that
remain want the early slot: watchdogd should start as soon as possible,
keventd is the device manager, and runparts is gated on int/bootstrap so
its position never mattered.

Reading /run/finit/system first also puts the override chain in its
natural order: built-in/generated defaults, then bundled (read-only)
system files in /lib, then the administrator (override) .conf file in
/etc/finit.d, always read last.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-08-17 19:04:52 +02:00

7.6 KiB

Files & Layout

Originally Finit was configured using a single file, /etc/finit.conf, and although still possible to use a single configuration file, today the following layout is recommended:

/
|- etc/
|  |- finit.d/
|  |   |- available/
|  |   |  `- my-service.conf
|  :   |- enabled/
|  :   |  `- my-service.conf -> ../available/my-service.conf
|  :   :
|  :   |- static-service.conf
|  :   `- another-static.conf
|  :
|  `- finit.conf
|- lib
|   `- finit/
|       `- system/
|           |- 10-hotplug.conf
|           `- ...
`- run/
    `- finit/
        |- bus         # Finit's own D-Bus socket, see doc/dbus.md
        `- system/
            |- keventd.conf
            |- runparts.conf
            |- watchdogd.conf
            `- ...

Configuration files in /etc are provided by the user, or projects like finit-skel and extended by the user.

The files in /run/finit/system/*.conf are generated by Finit for its built-in services: runparts, watchdog, and keventd, if they are enabled. They are read before the other .conf directories, so any later file can reference them in if: statements and override them by name.

The files in /lib/finit/system/*.conf are system critical services and setup provided by Finit, e.g. udev/mdev that must run very early at system bootstrap. This system directory was introduced in Finit v4.4 to replace the hard-coded services provided by plugins before.

All .conf files in both directories can be either replaced by a system administrator or overridden by a file with the same name in /etc/finit.d/, which is always read last -- copy a .conf there and modify it, or symlink it to /dev/null to disable it outright.

Services in the available/ and enabled/ sub-directories are called dynamic services, in contrast to static services -- the only difference being where they are installed and if the initctl tool can manage them with the enable and disable commands. An administrator can always create files and symlinks manually.

At bootstrap, and initctl reload, all .conf files are read, starting with finit.conf, then /run/finit/system/*.conf, /lib/finit/system/*.conf, finit.d/*.conf, and finally all finit.d/enabled/*.conf files. Each directory is a unique group, where files within each group are sorted alphabetically.

Example:

/run/finit/system/keventd.conf
/run/finit/system/runparts.conf
/lib/finit/system/10-hotplug.conf
/lib/finit/system/90-testserv.conf
/etc/finit.d/10-abc.conf
/etc/finit.d/20-abc.conf
/etc/finit.d/enabled/1-aaa.conf
/etc/finit.d/enabled/1-abc.conf

The resulting combined configuration is read in order, each run, task, and service added to an ordered list that ensures they are started in the same order. This is important because of the blocking properties of run. For an example on the relation of service and run, and dependency handling between them, see Conditional Loading, below.

Note

The names finit.conf and finit.d/ are only defaults. They can be changed at compile-time with two configure options: --with-config=/etc/foo.conf and --with-rcsd=/var/foo.d.

They can also be overridden from the kernel command line using: -- finit.config=/etc/bar.conf and in that file use the top-level setting rcsd = "/path/to/finit.d".

Filesystem Layout

Finit is most comfortable with a traditional style Linux filesystem layout, as specified in the FHS:

/.
 |- bin/
 |- dev/          # Mounted automatically if devtmpfs is available
 |   |- pts/      # Mounted automatically by Finit if it exists
 |   `- shm/      # Mounted automatically by Finit if it exists
 |- etc/
 |   |- finit.d/
 |   |   |- available/
 |   |   `- enabled/
 |    `- finit.conf
 |- home/
 |- lib/
 |- libexec/
 |- mnt/
 |- proc/         # Mounted automatically by Finit if it exists
 |- root/
 |- run/          # Mounted automatically by Finit if it exists
 |   `- lock/     # Created automatically if Finit mounts /run
 |- sbin/
 |- sys/          # Mounted automatically by Finit if it exists
 |- tmp/          # Mounted automatically by Finit if it exists
 |- usr/
 `- var/
     |- cache/
     |- db/
     |- lib/
     |   `- misc/
     |- lock/
     |- log/
     |- run -> ../run
     |- spool/
     `- tmp/

Finit starts by mounting the critical file systems /dev, /proc/, and /sys, unless they are already mounted. When all plugins and other, core Finit functions, have been set up, all relevant filesystems (where PASS > 0) are checked and mounted from the selected fstab, either the default /etc/fstab, or any custom one selected from the command line, or at build time.

To provide a smooth ride, file system not listed in the given fstab, e.g. /tmp and /run, are automatically mounted by Finit, as listed above, provided their respective mount point exists.

With all filesystems mounted, Finit calls swapon.

Tip

To see what happens when all filesystems are mounted, have a look at the bootmisc.so plugin.

At shutdown, and after having stopped all services and other lingering processes have been killed, filesystems are unmounted in the reverse order, and swapoff is called.

Managing Services

Using initctl disable my-service the symlink (above) is removed and the service is queued for removal. Several changes can be made to the system, but it is not until initctl reload is called that the changes are activated.

To add a new static service, drop a .conf file in /etc/finit.d/ and run initctl reload. (It is also possible to SIGHUP PID 1, or call finit q, but that has been deprecated with the initctl tool). Finit monitors all known active .conf files, so if you want to force a restart of any service you can touch its corresponding .conf file in /etc/finit.d and call initctl reload. Finit handles all conditions and dependencies between services automatically, see the section on Service Synchronization for more details.

On initctl reload the following is checked for all services:

  • If a service's .conf file has been removed, or its conditions are no longer satisfied, the service is stopped.
  • If the file is modified, or a service it depends on has been reloaded, the service is reloaded (stopped and started).
  • If a new service is added it is automatically started — respecting runlevels and return values from any callbacks.

For more info on the different states of a service, see the separate document Finit Services.

Alternate finit.d/

Syntax: rcsd = "/path/to/finit.d"

The Finit rcS.d directory is set at compile time with:

./configure --with-rcsd=/etc/finit.d

A system with multiple use-cases may be bootstrapped with different configurations, starting with the kernel command line option:

-- finit.config=/etc/factory.conf

This file in turn can use the rcsd directive to tell Finit to use another set of .conf files, e.g.:

rcsd = "/etc/factory.d"

Note

This directive is only available from the top-level bootstrap .conf file, usually /etc/finit.conf.

Including Finit Configs

Syntax: include("CONF")

Include another configuration file. Absolute path required.