Table of Contents
- Runparts & /etc/rc.local
- Hooks, Callbacks & Plugins
- Rebooting & Halting
- Commands & Status
- Origin & References
Finit is an EeePC Fastinit inspired clone with process supervision similar to that of D.J. Bernstein's daemontools and Gerrit Pape's runit. It also supports free-form conditions based on events, e.g. triggering on PID file creation, Netlink events like a default route or interfaces coming up, or even custom events. Similar to systemd.
Finit focuses on small and embedded Linux systems, although fully usable on servers and desktops as well. See the contrib section for Debian and Alpine Linux examples.
Traditional SysV init style systems are scripted. For low-resource embedded systems this is quite resource intensive and often leads to long boot times. Finit reduces context switches and forking of shell scripts to provide a swift system bootstrap written entirely in C.
Configuration is read from /etc/finit.conf which details kernel modules to load, services and TTYs to start. When the initial bootstrap is done, including setting up networking, all services in /etc/finit.d/ and the familiar /etc/rc.local are started.
# Fallback if /etc/hostname is missing host wopr # Runlevel to start after bootstrap, runlevel 'S' runlevel 2 # Services to be monitored and respawned as needed service [S12345] /sbin/watchdogd -L -f -- System watchdog daemon service [S12345] /sbin/syslogd -n -b 3 -D -- System log daemon service [S12345] /sbin/klogd -n -- Kernel log daemon service  /sbin/lldpd -d -c -M1 -H0 -i -- LLDP daemon (IEEE 802.1ab) # For multiple instances of the same service, add :ID somewhere between # the service/run/task keyword and the command. service :1  /sbin/merecat -n -p 80 /var/www -- Web server service :2  /sbin/merecat -n -p 8080 /var/www -- Old web server # Alternative method instead of below runparts, can also use /etc/rc.local #task [S] /etc/init.d/keyboard-setup start -- Setting up preliminary keymap #task [S] /etc/init.d/acpid start -- Starting ACPI Daemon #task [S] /etc/init.d/kbd start -- Preparing console # Inetd services to start on demand, with alternate ports and filtering inetd ftp/tcp nowait  /sbin/uftpd -i -f -- FTP daemon inetd tftp/udp wait  /sbin/uftpd -i -y -- TFTP daemon inetd time/udp wait  internal -- UNIX rdate service inetd time/tcp nowait  internal -- UNIX rdate service inetd 3737/tcp nowait  internal.time -- UNIX rdate service inetd telnet/tcp nowait  /sbin/telnetd -i -F -- Telnet daemon inetd 2323/tcp nowait  /sbin/telnetd -i -F -- Telnet daemon inetd 222/tcp@eth0 nowait  /sbin/dropbear -i -R -F -- SSH service inetd ssh/tcp@*,!eth0 nowait  /sbin/dropbear -i -R -F -- SSH service # Run start scripts from this directory # runparts /etc/start.d # Virtual consoles to start built-in getty on tty  /dev/tty1 115200 linux tty  /dev/ttyAMA0 115200 vt100
service stanza, as well as
inetd and others are
described in full in doc/config.md. Here's a quick
overview of some of the most common components needed to start a UNIX
service [LVLS] <COND> /path/to/daemon ARGS -- Some text ^ ^ ^ ^ ^ ^ | | | | | `-- Optional description | | | | `---------- Daemon arguments | | | `-------------------------- Path to daemon | | `--------------------------------- Optional conditions | `---------------------------------------- Optional Runlevels `------------------------------------------------ Monitored application
Some components are optional. It is important to note, however, is for
the daemon not to fork and detach itself from the controlling TTY.
This is usually an
-f argument to the application. If the
daemon detaches itself, Finit cannot monitor it and will instead try to
Start, monitor and restart services should they fail.
Finit comes with a built-in inetd server. No need to maintain a separate config file for services that you want to start on demand.
All inetd services started can be filtered per port and inbound interface, reducing the need for a full blown firewall.
Built-in optional inetd services:
- echo RFC862
- chargen RFC864
- daytime RFC867
- discard RFC863
- time (rdate) RFC868
For more information, see doc/inetd.md.
Finit also comes with a built-in Getty for Linux console TTYs. It can
/etc/inittab and set the speed. Then
/bin/login handles all
nasty bits with PAM etc.
# /etc/finit.conf tty  /dev/tty1 38400 linux tty  /dev/ttyAMA0 115200 vt100
Support for SysV init-style runlevels is available, in the same
minimal style as everything else in Finit. The
 syntax can be
applied to service, task, run, inetd, and TTY stanzas.
All services in runlevel S(1) are started first, followed by the desired
run-time runlevel. Runlevel S can be started in sequence by using
run [S] cmd. Changing runlevels at runtime is done like any other init,
e.g. init 4, but also using the more advanced
Plugins can extend the functionality of Finit and hook into the
different stages of the boot process and at runtime. Plugins are
written in C and compiled into a dynamic library loaded automatically by
finit at boot. A basic set of plugins are bundled in the
Hook into the boot at predefined points to extend Finit
Listen to external events and control Finit behavior/services
Extend Finit with internal inetd services, for an example, see
Extensions and functionality not purely related to what an
needs to start a system are available as a set of plugins that either
hook into the boot process or respond to various I/O.
For more information, see doc/plugins.md.
Runparts & /etc/rc.local
At the end of the boot, when networking and all services are up, Finit
calls its built-in run-parts(8) on the
runparts <DIR> directory,
/etc/rc.local, in that order if they exist.
No configuration stanza in
/etc/finit.conf is required for
If it exists and is an executable shell script, finit calls it at the
very end of the boot, before calling the
HOOK_SYSTEM_UP. See more on
hooks in doc/plugins.md, and about the system
bootstrap in doc/bootstrap.md.
Basic support for runlevels is included in Finit from v1.8. By
default all services, tasks, run commands and TTYs listed without a set
of runlevels get a default set
 assigned. The default runlevel
after boot is 2.
Finit supports runlevels 0-9, and S, with 0 reserved for halt, 6 reboot and S for services to only run at bootstrap. Runlevel 1 is the single user level, where usually no networking is enabled. In Finit this is more of a policy for the user to define. Normally only runlevels 1-6 are used, and even more commonly, only the default runlevel is used.
To specify an allowed set of runlevels for a
[NNN] to your
/etc/finit.conf, like this:
service [S12345] /sbin/syslogd -n -x -- System log daemon run [S] /etc/init.d/acpid start -- Starting ACPI Daemon task [S] /etc/init.d/kbd start -- Preparing console service [S12345] /sbin/klogd -n -x -- Kernel log daemon tty  /dev/tty1 tty  /dev/tty2 tty  /dev/tty3 tty  /dev/tty4 tty  /dev/tty5 tty  /dev/tty6
In this example syslogd is first started, in parallel, and then acpid is called using a conventional SysV init script. It is called with the run command, meaning the following task command to start the kbd script is not called until the acpid init script has fully completed. Then the keyboard setup script is called in parallel with klogd as a monitored service.
Again, tasks and services are started in parallel, while run commands are called in the order listed and subsequent commands are not started until a run command has completed.
Switching between runlevels can be done by calling init with a single
argument, e.g. init 5 switches to runlevel 5. When changing
runlevels Finit also automatically reloads all
.conf files in the
/etc/finit.d/ directory. So if you want to set a new system config,
switch to runlevel 1, change all config files in the system, and touch
.conf files in
/etc/finit.d before switching back to the
previous runlevel again — that way Finit can both stop old services and
start any new ones for you, without rebooting the system.
Rebooting & Halting
Traditionally, rebooting and halting a UNIX system is done by changing
its runlevel. Finit comes with its own tooling providing:
suspend, but also the traditional
telinit, as well as a more modern
initctl tool, detailed in the next
For compatibility reasons Finit listens to the same set of signals as BusyBox init. This is not 100% compatible with SysV init, but clearly the more common combination for Finit. For more details, see doc/signals.md.
Finit also listens to the classic SysV init FIFO, used by
Support for this is implemented by the
initctl.so plugin. Hence,
telinit q will work as the UNIX beards intended.
~ # telinit -h Usage: telinit [OPTIONS] [q | Q | 0-9] Options: -h, --help This help text -V, --version Show Finit version Commands: 0 Power-off the system, same as initctl poweroff 6 Reboot the system, same as initctl reboot 2, 3, 4, 5 Change runlevel. Starts services in new runlevel, stops any services in prev. runlevel that are not allowed in new. q, Q Reload *.conf in /etc/finit.d/, same as initctl reload or sending SIGHUP to PID 1 1, s, S Enter system rescue mode, runlevel 1
Commands & Status
Finit also implements a more modern API to query status, and start/stop
initctl tool does
not return until the given command has fully completed.
~ $ initctl -h Usage: initctl [OPTIONS] <COMMAND> Options: -d, --debug Debug initctl (client) -v, --verbose Verbose output -h, --help This help text Commands: debug Toggle Finit (daemon) debug help This help text reload Reload *.conf in /etc/finit.d/ and activate changes runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot status | show Show status of services cond set <COND> Set (assert) condition => +COND cond clear <COND> Clear (deassert) condition => -COND cond flux <COND> Emulate flux condition => ~COND cond show Show condition status start <JOB|NAME>[:ID] Start service by job# or name, with optional ID stop <JOB|NAME>[:ID] Stop/Pause a running service by job# or name restart <JOB|NAME>[:ID] Restart (stop/start) service by job# or name reload <JOB|NAME>[:ID] Reload (SIGHUP) service by job# or name version Show Finit version
For services not supporting
<!> notation in the .conf
file must be used to tell Finit to stop and start it on
runlevel changes. If
<> holds more conditions,
these will also affect how a service is maintained.
Note: even though it is possible to start services not belonging in the current runlevel these services will not be respawned automatically by Finit if they exit (crash). Hence, if the runlevel is 2, the below Dropbear SSH service will not be restarted if it is killed or exits.
~ $ initctl status -v 1 running 476 [S12345] /sbin/watchdog -T 16 -t 2 -F /dev/watchdog 2 running 477 [S12345] /sbin/syslogd -n -b 3 -D 3 running 478 [S12345] /sbin/klogd -n 4:1 inetd 0  internal time allow *:37 4:2 inetd 0  internal time allow *:37 4:3 inetd 0  internal 3737 allow *:3737 5:1 inetd 0  /sbin/telnetd allow *:23 deny eth0,eth1 5:2 inetd 0  /sbin/telnetd allow eth0:2323,eth2:2323,eth1:2323 6:1 inetd 0  /sbin/dropbear allow eth0:222 6:2 inetd 0  /sbin/dropbear allow *:22 deny eth0
Finit is capable of running on both desktop/server systems with udev and
embedded systems that usually come with BusyBox mdev. Finit probes for
them at runtime and expects
/dev/ to be writable, usually
It is also possible to run on a statically set up
/dev if needed. It
is however not a good idea to have both udev and mdev installed at the
same time, this will lead to unpredictable results.
At boot Finit calls either
udevd to populate
/dev, this is
done slightly differently and on systems with udev you might want to add
the following one-shot task early in your
run [S] /sbin/udevadm settle --timeout=120 -- Waiting for udev
Finit has a built-in Getty for TTYs, but requires a working
/bin/sh, if no TTYs are configured in
For a fully operational system
/tmp must be set up
/etc/fstab -- which is iterated over at boot.
The built-in Inetd requires
/etc/protocols to work
with port names rather than numbers.
Having successfully built Finit it may now be time to
take it for a test drive. The
make install attempts to set up finit
as the system system init,
/sbin/init, but this is usually a symlink
pointing to the current init.
So either change the symlink, or change your boot loader (GRUB, LOADLIN, LILO, U-Boot/Barebox or RedBoot) configuration to append the following to the kernel command line:
Remember to also set up an initial
/etc/finit.conf before rebooting!
--debug, to the kernel command line to enable
To debug startup issues, in particular issues with getty/login, try
configure --enable-fallback-shell. When no TTYs are detected, and
Finit is configured with this option, Finit will try to start a bare
/bin/sh on the boot console.