Fast, extensible init for Linux systems. Cookies included.
C Shell M4 Makefile
Latest commit c2ec25e Aug 17, 2016 @troglobit Use logit() for _d() and _e() messages as well
The new logit() function takes care to print to stderr if syslogd has
not yet started.  The _d(), _e(), and _pe() macros have an additional
requirement: to always print on stderr.

After the boot we also want to see what happned during, so this patch
simply adds syslog() support to _d(), _e(), and _pe().

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
Failed to load latest commit information.
contrib Fix GRUB menu entry generation for Debian & Ubuntu Aug 15, 2016
doc Rephrase Aug 5, 2016
images Cleanup Introduction and add Bootstrap section. Jan 21, 2015
m4 Add convenient SysV init /etc/rc.local compat Jul 15, 2016
plugins Clean up logging, log to stderr until syslogd has started Aug 17, 2016
.gitignore Initial contrib/debian support for Jessie Jul 28, 2016
.gitmodules Remove local GIT submodules for libuEv and libite Apr 9, 2016
.travis.yml Update Travis-CI build script for Coverity Scan Jun 4, 2016
AUTHORS Embedded finit for small embedded Linux systems and servers. Sep 14, 2012
ChangeLog.md ChangeLog: Add missing links to referenced previous versions Feb 5, 2016
LICENSE Bump version for release and update copyright years. Apr 21, 2014
Makefile.am Initial support for mdadm RAID arrays Aug 14, 2016
README.md Add missing bracket Aug 5, 2016
TODO.md Remember to shift use state machine in sig.c:do_shutdown() Aug 14, 2016
api.c Adopt BusyBox init signal handling for halt/reboot/poweroff Jul 29, 2016
autogen.sh Initial conversion to GNU Configure & Build System Mar 14, 2016
client.c Use <> instead of "" for external header includes Jul 12, 2016
common.mk Increase indentation in pretty printing slightly for autotools Feb 5, 2016
cond-w.c Allow conditions for tasklets and runlets as well Jul 21, 2016
cond.c Update include path for libuEv and libite Apr 9, 2016
cond.h Remove Emacs version-control handling Mar 21, 2016
conf.c Clean up logging, log to stderr until syslogd has started Aug 17, 2016
conf.h Remove Emacs version-control handling Mar 21, 2016
configure.ac Remove --enable-embedded configure option Aug 14, 2016
exec.c UTMP: Only account for getty processes Aug 17, 2016
finit.c Remove --enable-embedded configure option Aug 14, 2016
finit.conf Change syntax for multiple instances: #ID --> :ID Jun 7, 2015
finit.h initctl: Add SysV compat support for setenv Jul 30, 2016
getty.c Clean up logging, log to stderr until syslogd has started Aug 17, 2016
helpers.c Use logit() for _d() and _e() messages as well Aug 17, 2016
helpers.h Use logit() for _d() and _e() messages as well Aug 17, 2016
inetd.c Clean up logging, log to stderr until syslogd has started Aug 17, 2016
inetd.h Add protection against UDP inetd looping attacks Jul 18, 2016
initctl.c initctl: Add missing signal.h include for older systems, e.g. Travis CI Aug 10, 2016
mdadm.c Initial support for mdadm RAID arrays Aug 14, 2016
mount.c Only unmount non-protected filesystems at shutdown Aug 14, 2016
pid.c Use <> instead of "" for external header includes Jul 12, 2016
plugin.c Plugin loader fixes for dep handling and unload Jul 30, 2016
plugin.h Migrate to libite version (newer) of BSD queue.h Jul 12, 2016
private.h Plugin and API init/exit for conformance Jul 28, 2016
reboot.c Fix build on older (G)LIBC's w/o RB_SW_SUSPEND Aug 17, 2016
service Add simple service script for SysV init compat. Sep 19, 2015
service.c Clean up logging, log to stderr until syslogd has started Aug 17, 2016
service.h Merge branch 'finit-sm' of https://github.com/westermo/finit into wes… Jun 4, 2016
sig.c Initial support for mdadm RAID arrays Aug 14, 2016
sig.h initctl: Add SysV compat support for setenv Jul 30, 2016
sm.c Adopt BusyBox init signal handling for halt/reboot/poweroff Jul 29, 2016
sm.h Minor audit of new top-level state machine Jun 7, 2016
svc.c Service status 'crashing' --> 'crashed' Aug 5, 2016
svc.h Use <> instead of "" for external header includes Jul 12, 2016
tty.c UTMP: Only account for getty processes Aug 17, 2016
tty.h TTY: Major overhaul, move to built-in getty Jul 28, 2016
utmp-api.c Copy all chars of UTMP fields: id, line, and user Aug 9, 2016
utmp-api.h UTMP: Add support for INIT_PROCESS & DEAD_PROCESS Aug 8, 2016

README.md

                      _______  __    _____  ___    __  ___________  _______
                     /"     "||" \  (\"   \|"  \  |" \("     _   ")/" __   )
                    (: ______)||  | |.\\   \    | ||  |)__/  \\__/(__/ _) ./
                     \/    |  |:  | |: \.   \\  | |:  |   \\_ /       /  //
                     // ___)  |.  | |.  \    \. | |.  |   |.  |    __ \_ \\
                    (:  (     /\  |\|    \    \ | /\  |\  \:  |   (: \__) :\
                     \__/    (__\_|_)\___|\____\)(__\_|_)  \__|    \_______) ... Yes, we need a new logo!

Fast init for Linux

Travis Status Coverity Status

Table of Contents

Introduction

Finit is a plugin-based init with process supervision similar to that of D.J. Bernstein's daemontools and Gerrit Pape's runit. The main focus of Finit is on small and embedded Linux systems, yet fully usable on server and desktop installations as well. See the contrib section for Debian and Alpine 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 initial bootstrap is done, including setting up networking, /etc/finit.d/ and the familiar /etc/rc.local are run.

Example /etc/finit.conf:

    # 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   [2345] /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 [2345] /sbin/merecat -n -p 80   /var/www -- Web server
    service :2 [2345] /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 [2345] /sbin/uftpd -i -f       -- FTP daemon
    inetd tftp/udp           wait [2345] /sbin/uftpd -i -y       -- TFTP daemon
    inetd time/udp           wait [2345] internal                -- UNIX rdate service
    inetd time/tcp         nowait [2345] internal                -- UNIX rdate service
    inetd 3737/tcp         nowait [2345] internal.time           -- UNIX rdate service
    inetd telnet/tcp       nowait [2345] /sbin/telnetd -i -F     -- Telnet daemon
    inetd 2323/tcp         nowait [2345] /sbin/telnetd -i -F     -- Telnet daemon
    inetd 222/tcp@eth0     nowait [2345] /sbin/dropbear -i -R -F -- SSH service
    inetd ssh/tcp@*,!eth0  nowait [2345] /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 [12345] /dev/tty1    115200 linux
    tty [12345] /dev/ttyAMA0 115200 vt100

For an example of a full blown embedded Linux, see TroglOS, or take a look at the contrib/ section with Alpine Linux, Debian, support and more.

Features

Process Supervision

Start, monitor and restart services should they fail.

Inetd

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.

Getty

Finit also comes with a built-in Getty for Linux console TTYs. It can parse /etc/inittab and set the speed. Then /bin/login handles all nasty bits with PAM etc.

# /etc/finit.conf
tty [12345] /dev/tty1    38400  linux
tty [12345] /dev/ttyAMA0 115200 vt100

Runlevels

Runlevels are optional in Finit, but support for SysV runlevels is available if needed. 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

Plugins

Finit plugins can be callbacks, boot hooks into different stages of the boot process, or pure extensions. Plugins are written in C and compiled into a dynamic library that is loaded automatically by finit at boot. A basic set of plugins that extend and modify the basic behavior are bundled in the plugins/ directory.

Capabilities:

  • Task/Run/Service callbacks
    Modify service arguments, override service monitor's decisions to start/stop/reload a service.
  • Hooks
    Hook into the boot at predefined points to extend Finit
  • I/O
    Listen to external events and control Finit behavior/services
  • Inetd
    Extend Finit with internal inetd services, for an example, see plugins/time.c

Extensions and functionality not purely related to what an /sbin/init 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, and /etc/rc.local, in that order if they exist.

    runparts /etc/rc.d/

No configuration stanza in /etc/finit.conf is required for rc.local. 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.

Runlevels

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 [234] 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 service, run command, task, or tty, add [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     [12345]  /dev/tty1
    tty     [2]      /dev/tty2
    tty     [2]      /dev/tty3
    tty     [2]      /dev/tty4
    tty     [2]      /dev/tty5
    tty     [2]      /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 all .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

Finit is often used on embedded and small Linux systems with BusyBox. For compatibility with its existing toolset (halt, poweroff, reboot), the following signals have been adopted:

  • SIGUSR1
    Same effect as finit q, reloads all *.conf files in /etc/finit.d/
  • SIGUSR1
    Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running processes, and unmounts all file systems. Then tells kernel to halt. Most people these days want SIGUSR2 though.

    SysV init and systemd use this to re-open their FIFO/D-Bus.

  • SIGUSR2
    Like SIGUSR1, but tell kernel to power-off the system, if ACPI or similar exists to actually do this. If the kernel fails power-off, Finit falls back to halt.

    SysV init N/A, systemd dumps its internal state to log.

  • SIGTERM
    Like SIGUSR1, but tell kernel to reboot the system when done.

    SysV init N/A, systemd rexecutes itself.

  • SIGINT
    Sent from kernel when the CTRL-ALT-DEL key combo is pressed. SysV init and systemd default to reboot with shutdown -r.
    Finit currently forwards this to SIGTERM.
  • SIGPWR
    Sent from a power daemon, like powstatd(8), on changes to the UPS status. Traditionally SysV init read /etc/powerstatus and acted on "OK", "FAIL", or "LOW" and then removed the file.
    Finit currently forwards this to SIGUSR2.

Finit also listens to the classic SysV init FIFO, which used to be located in /dev but these days default to /run/initctl. So existing tools like, poweroff, halt, reboot, and shutdown work as expected. Support for this old-style handling is implemented in the optional initctl.so plugin and can be accessed with the traditional telinit command line tool, symlinked to finit. Hence, if finit is your system init, then init q will work as the UNIX beards intended.

    ~ $ telinit
    Usage: telinit [OPTIONS] [q | Q | 0-9]

    Options:
      -h, --help            This help text
      -v, --version         Show Finit version

    Commands:
      q | Q           Reload *.conf in /etc/finit.d/, like SIGHUP
      0 - 9           Change runlevel: 0 halt, 6 reboot

Commands & Status

Finit also implements a more modern API to query status, and start/stop services, called initctl. Unlike telinit the 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

The <!> notation to a service stanza can be used empty, then it will apply to reload and runlevel commands. I.e., when a service's .conf file has been changed Finit will stop and start it instead. If a service does not have <!> declared, the service will be reloaded (SIGHUP:ed) in the START phase instead. The latter is the preferred behaviour, but not all daemons support this, unfortunately.

Note: even though it is possible to start services not belonging to 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       [2345]     internal time allow *:37
    4:2       inetd  0       [2345]     internal time allow *:37
    4:3       inetd  0       [2345]     internal 3737 allow *:3737
    5:1       inetd  0       [2345]     /sbin/telnetd allow *:23 deny eth0,eth1
    5:2       inetd  0       [2345]     /sbin/telnetd allow eth0:2323,eth2:2323,eth1:2323
    6:1       inetd  0       [345]      /sbin/dropbear allow eth0:222
    6:2       inetd  0       [345]      /sbin/dropbear allow *:22 deny eth0

Running

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:

    init=/sbin/finit

Remember to also set up an initial /etc/finit.conf before rebooting!

Finit starting Debian 6.0

Debugging

Add finit_debug, or --debug, to the kernel command line to enable debug messages. See the output from configure --help for more on how to assist debugging.

    init=/sbin/finit --debug

Origin & References

This project is based on the original finit by Claudio Matsuoka which was reverse engineered from syscalls of the EeePC fastinit — "gaps filled with frog DNA …"

Finit is developed and maintained by Joachim Nilsson at GitHub. Please file bug reports, clone it, or send pull requests for bug fixes and proposed extensions.