- Notifications
You must be signed in to change notification settings - Fork65
Fast init for Linux. Cookies included
License
troglobit/finit
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
- Introduction
- Features
- Runlevels
- Syntax
- Rebooting & Halting
- Commands & Status
- Tips & Tricks with the kernel cmdline
- Building
- Requirements
- Origin & References
Fast init for Linux systems. Reverse engineered from theEeePCfastinit byClaudio Matsuoka — "gaps filled with frog DNA …"
Figure 1: Screenshot of Finit bootingAlpine Linux (HowTo).
Features include:
- Runlevels, defined per service
- One-shot tasks, services (daemons), orSysV init start/stop scripts
- Runparts and
/etc/rc.local
support - Process supervision similar tosystemd
- Sourcing environment files
- Conditions for network/process/custom dependencies
- Readiness notification; PID files (native) for synchronizing systemstartup, support for systemdsd_notify(), ors6 style too
- Limited support fortmpfiles.d(5) (no aging, attributes, or subvolumes)
- Pre/Post script actions
- Rudimentarytemplating support
- Tooling to enable/disable services
- Built-in getty
- Built-in watchdog, with support for hand-over towatchdogd
- Built-in support for Debian/BusyBox
/etc/network/interfaces
- Cgroups v2, both configuration and monitoring in
initctl top
- Plugin support for customization
- Proper rescue mode with bundled
sulogin
for protected maintenance shell - Integration withwatchdogd for full system supervision
- Logging to kernel ring buffer before
syslogd
has started, see therecommendedsysklogd project for complete logging integrationand how to log to the kernel ring buffer from scripts usinglogger
Focus is on small and embedded systems, although Finit is fully usableon server and desktop systems as well. For working examples, see thecontrib/ section with tutorials for the following Linuxdistributions:
- Void Linux,
- Alpine Linux, and
- Debian GNU/Linux, also works on Ubuntu/Linux Mint
Note: support for various Linux distributions does not mean Finitinstalls easily on all architectures. The bundled install scripts areexamples for standard installations, tested on amd64 (x86_64) systems.Custom setups, e.g., for embedded systems, can be found in any of thefollowingBuildroot based examples:myLinux,Infix, or theplainbr2-finit-demo.
This example/etc/finit.conf
can also be split up in multiple.conf
files in/etc/finit.d
. Available, but not yet enabled, services canbe placed in/etc/finit.d/available
and enabled by an operator usingtheinitctl tool. See the above mentioned Linuxdistributions, ormyLinux.
Note: as of Finit v4.4, .conf lines can be broken up using thestandard UNIX continuation character (
\
), also trailing comments arenow supported. The latter means you need to escape any hashes used indirectives and descriptions (\#
). For more on this and examples,see thefinit.conf(5) manual ordoc/config.md.
# Fallback if /etc/hostname is missinghost default# Runlevel to start after bootstrap, 'S', default: 2#runlevel 2# Support for setting global environment variables, using foo=bar syntax# be careful though with variables like PATH, SHELL, LOGNAME, etc.#PATH=/usr/bin:/bin:/usr/sbin:/sbin# Max file size for each log file: 100 kiB, rotate max 4 copies:# log => log.1 => log.2.gz => log.3.gz => log.4.gzlog size=100k count=4# Services to be monitored and respawned as neededservice [S12345] env:-/etc/conf.d/watchdog watchdog $WATCHDOG_OPTS $WATCHDOG_DEV -- System watchdog daemonservice [S12345] env:-/etc/conf.d/syslog syslogd -n $SYSLOGD_OPTS -- System log daemonservice [S12345] <pid/syslogd> env:-/etc/conf.d/klogd klogd -n $KLOGD_OPTS -- Kernel log daemonservice [2345] env:-/etc/conf.d/lldpd lldpd -d $LLDPD_OPTS -- LLDP daemon (IEEE 802.1ab)# The BusyBox ntpd does not use syslog when running in the foreground# So we use this trick to redirect stdout/stderr to a log file. The# log file is rotated with the above settings. The condition declares# a dependency on a system default route (gateway) to be set. A single# <!> at the beginning means ntpd does not respect SIGHUP for restart.service [2345] log:/var/log/ntpd.log <!net/route/default> ntpd -n -l -I eth0 -- NTP daemon# For multiple instances of the same service, add :ID somewhere between# the service/run/task keyword and the command.service :80 [2345] merecat -n -p 80 /var/www -- Web serverservice :8080 [2345] merecat -n -p 8080 /var/www -- Old web server# Alternative method instead of below runparts, can also use /etc/rc.local#sysv [S] /etc/init.d/keyboard-setup -- Setting up preliminary keymap#sysv [S] /etc/init.d/acpid -- Starting ACPI Daemon#task [S] /etc/init.d/kbd -- Preparing console# Hidden from boot progress, using empty `--` description#sysv [S] /etc/init.d/keyboard-setup --#sysv [S] /etc/init.d/acpid --#task [S] /etc/init.d/kbd --# Run start scripts from this directory# runparts /etc/start.d# Virtual consoles run BusyBox getty, keep kernel default speedtty [12345] /sbin/getty -L 0 /dev/tty1 linux nowait nocleartty [2345] /sbin/getty -L 0 /dev/tty2 linux nowait nocleartty [2345] /sbin/getty -L 0 /dev/tty3 linux nowait noclear# Use built-in getty for serial port and USB serial#tty [12345] /dev/ttyAMA0 noclear nowait#tty [12345] /dev/ttyUSB0 noclear# Just give me a shell, I need to debug this embedded system!#tty [12345] console noclear nologin
Theservice
stanza, as well astask
,run
and others are describedin full indoc/config.md. Here's a quick overview ofsome of the most common components needed to start a UNIX daemon:
service [LVLS] <COND> log env:[-]/etc/default/daemon daemon ARGS -- Daemon daemon^ ^ ^ ^ ^ ^ ^ ^| | | | | | | `---------- Optional description| | | | | | `------------------ Daemon arguments| | | | | `------------------------- Path to daemon| | | | `---------------------------------------------------- Optional env. file| | | `-------------------------------------------------------- Redirect output to log| | `--------------------------------------------------------------- Optional conditions| `---------------------------------------------------------------------- Optional Runlevels `------------------------------------------------------------------------------ Monitored application
Some components are optional: runlevel(s), condition(s) and description,making it easy to create simple start scripts and still possible for moreadvanced uses as well:
service /usr/sbin/sshd -D
Dependencies are handled usingconditions. One ofthe most common conditions is to wait for basic networking to becomeavailable:
service <net/route/default> nginx -- High performance HTTP server
Here is another example where we instruct Finit to not start BusyBoxntpd
untilsyslogd
has started properly. Finit waits forsyslogd
to create its PID file, by default/var/run/syslogd.pid
.
service [2345] log <!pid/syslogd> ntpd -n -N -p pool.ntp.orgservice [S12345] syslogd -n -- Syslog daemon
Notice thelog
keyword, BusyBoxntpd
usesstderr
for logging whenrun in the foreground. Withlog
Finit redirectsstdout
+stderr
to the system log daemon using the command linelogger(1)
tool.
A service, or task, can have multiple dependencies listed. Here we waitforbothsyslogd
to have started and basic networking to be up:
service [2345] log <pid/syslogd,net/route/default> ntpd -n -N -p pool.ntp.org
If either condition fails, e.g. loss of networking,ntpd
is stoppedand as soon as it comes back up againntpd
is restarted automatically.
Note: Make sure daemonsdo not fork and detach themselves from thecontrolling TTY, usually an-n
or-f
flag, or-D
as in the caseof OpenSSH above. If it detaches itself, Finit cannot monitor it andwill instead try to restart it.
Process Supervision
Start, monitor and restart services should they fail.
Getty
Finit supports external getty but also comes with a limited built-inGetty, useful for really small systems. A getty sets up the TTY andwaits for user input before handing over to/bin/login
, which isresponsible for handling the actual authentication.
tty [12345] /dev/tty1 nowait linuxtty [12345] /dev/ttyAMA0 noclear vt100tty [12345] /sbin/getty -L /dev/ttyAMA0 vt100
Users of embedded systems may want to enable automatic serial consolewith the special@console
device. This works regardless weather thesystem usesttyS0
,ttyAMA0
,ttyMXC0
, or anything else. Finitfigures it out by querying sysfs:/sys/class/tty/console/active
.
tty [12345] @console linux noclear
Notice the optionalnoclear
,nowait
, andnologin
flags. Thelatter is for skipping the login process entirely. For more information,seedoc/config.md.
Runlevels
Support for SysV init-stylerunlevels is available, in the sameminimal style as everything else in Finit. The[2345]
syntax can beapplied to service, task, run, and TTY stanzas.
Reserved runlevels are 0 and 6, halt and reboot, respectively just likeSysV init. Runlevel 1 can be configured freely, but is recommended tobe kept as the system single-user runlevel since Finit will not startnetworking here. The configuredrunlevel NUM
from/etc/finit.conf
is what Finit changes to after bootstrap, unless 'single' (or 'S') isgiven on the kernel cmdline, in which case runlevel 1 is started.
All services in runlevel S) are started first, followed by the desiredrun-time runlevel. Run tasks in runlevel S can be started in sequenceby usingrun [S] cmd
. Changing runlevels at runtime is done like anyother init, e.g.init 4, but also using the more advancedintictl
tool.
Conditions
As mentioned previously, Finit has an advanced dependency system tohandle synchronization, calledconditions. It canbe used in many ways; depend on another service, network availability,etc.
Onereally cool example useful for embedded systems is to run certainscripts if a board has a certain feature encoded in its device tree. Atbootstrap we run the followingident
script:
#!/bin/shconddir=/var/run/finit/cond/hw/modeldtmodel=/sys/firmware/devicetree/base/modelif!test -e$dtmodel;thenexit 0fimodel=$(cat$dtmodel| tr"[A-Z]""[a-z]-")mkdir -p$conddir&& ln -s ../../reconf$conddir/$model
Provided the device tree node exists, and is a string, we can then usethe condition<hw/model/foo>
when starting other scripts. Here is anexample:
run [S] /path/to/ident --task [2] <hw/model/foo> /path/to/foo-init -- Initializing Foo board
Notice the trick with an empty description to hide the call to
ident
in the Finit progress output.
Plugins
Plugins canextend the functionality of Finit andhook into thedifferent stages of the boot process and at runtime. Plugins arewritten in C and compiled into a dynamic library loaded automatically byfinit at boot. A basic set of plugins are bundled in theplugins/
directory.
Capabilities:
- Hooks
Hook into the boot at predefined points to extend Finit - I/O
Listen to external events and control Finit behavior/services
Extensions and functionality not purely related to what an/sbin/init
needs to start a system are available as a set of plugins that eitherhook into the boot process or respond to various I/O.
For more information, seedoc/plugins.md.
Automatic Reload
By default, Finit monitors/etc/finit.d/
and/etc/finit.d/enabled/
registering any changes to.conf
files. To activate a change the usermust callinitctl reload
, which reloads all modified files, stops anyremoved services, starts new ones, and restarts any modified ones. If thecommand line arguments of a service have changed, the process will beterminated and then started again with the updated arguments. If the argumentshave not been modified and the process supports SIGHUP, the process willreceive a SIGHUP rather than being terminated and started.
For some use-cases the extra step of callinginitctl reload
creates anunnecessary overhead, which can be removed at build-time using:
configure --enable-auto-reload
Cgroups
Finit supports cgroups v2 and comes with the following default groups inwhich services and user sessions are placed in:
/sys/fs/cgroup |-- init/ # cpu.weight:100 |-- system/ # cpu.weight:9800 `-- user/ # cpu.weight:100
Finit itself and its helper scripts and services are placed in thetop-level leaf-node groupinit/
, which also isreserved.
All run/task/service/sysv processes are placed in their own sub-groupinsystem/
. The name of each sub-group is taken from the respective.conf
file from/etc/finit.d
.
All getty/tty processes are placed in their own sub-group inuser/
.The name of each sub-group is taken from the username.
A fourth group also exists, theroot
group. It is alsoreserved andprimarily intended for RT tasks. If you have RT tasks they need to bedeclared as such in their service stanza like this:
service [...] <...> cgroup.root /path/to/foo args -- description
or
cgroup.rootservice [...] <...> /path/to/foo args -- descriptionservice [...] <...> /path/to/bar args -- description
Seedoc/config.md for more information, e.g.,how to configure per-group limits.
Theinitctl
tool has three commands to help debug and optimize thesetup and monitoring of cgroups. See theps
,top
, andcgroup
commands for details.
Note: systems that do not support cgroups, specifically version 2,are automatically detected. On such systems the above functionalityis disabled early at boot.
At the end of the boot, when all bootstrap (S
) tasks and services havestarted, but not networking, Finit calls its built-inrun-parts(8)command on any configuredrunparts <DIR>
directory. This happens justbefore changing to the configured runlevel (default 2). (Networking isenabled just prior to changing from single user mode.)
runparts /etc/rc.d/
Right after the runlevel change when all services have started properly,/etc/rc.local
is called.
No configuration stanza in/etc/finit.conf
is required forrc.local
.If it exists and is an executable shell script Finit calls it at the veryend of the boot, before calling theHOOK_SYSTEM_UP
. See more on hooksindoc/plugins.md.
It is not possible to call Finit via signals or useinitctl
in anyrunparts or/etc/rc.local
script. This because Finit is singlethreaded and is calling these scripts in a blocking fashion at the endof runlevel S, at which point the event loop has not yet been started.
The event loop is the whole thing which Finit is built around, exceptfor runlevel S, which remains a slow procession through a lot of set up,with a few hooks and blocking call outs to external scripts.
However, not allinitctl
commands are prohibited. Supported commands:
inictl cond
: only operate of files in/run/finit/cond
initctl enable/disable
: enabled run/task/service is activated onthe runlevel change from S to 2initctl touch/show/create/delete/list
:create
, provided thenon-interactive mode is used, again changes take effect in therunlevel change directly after bootstrapinitctl -f reboot/poweroff/halt
: provided the-f
flag is used toforce direct kernel commands
Example: you can set ausr/
condition in/etc/rc.local
and havea service/task in runlevel 2 depend on it to execute.
Basic support forrunlevels is included in Finit from v1.8. Bydefault all services, tasks, run commands and TTYs listed without a setof runlevels get a default set[234]
assigned. The default runlevelafter boot is 2.
Finit supports runlevels 0-9, and S, with 0 reserved for halt, 6 rebootand S for services to only run at bootstrap. Runlevel 1 is the singleuser level, where usually no networking is enabled. In Finit this ismore of a policy for the user to define. Normally only runlevels 1-6are used, and even more commonly, only the default runlevel is used.
To specify an allowed set of runlevels for aservice
,run
command,task
, ortty
, add[NNN]
to your/etc/finit.conf
, like this:
service [S12345] syslogd -n -x -- System log daemonrun [S] /etc/init.d/acpid start -- Starting ACPI Daemontask [S] /etc/init.d/kbd start -- Preparing consoleservice [S12345] <pid/syslogd> klogd -n -x -- Kernel log daemontty [12345] /dev/tty1tty [2] /dev/tty2tty [2] /dev/tty3tty [2] /dev/tty4tty [2] /dev/tty5tty [2] /dev/tty6
In this example syslogd is first started, in parallel, and then acpid iscalled using a conventional SysV init script. It is called with the runcommand, meaning the following task command to start the kbd script isnot called until the acpid init script has fully completed. Then thekeyboard setup script is called in parallel with klogd as a monitoredservice.
Again, tasks and services are started in parallel, while run commandsare called in the order listed and subsequent commands are not starteduntil a run command has completed. Also, task and run commands are runin a shell, so pipes and redirects can be used.
The following examples illustrate this. Bootstrap task and run commandsare also removed when they have completed,initctl show
will not listthem.
task [S] echo "foo" | cat >/tmp/barrun [S] echo "$HOME" >/tmp/secret
Switching between runlevels can be done by calling init with a singleargument, e.g.init 5, or usinginitctl runlevel 5
, bothswitch to runlevel 5. When changing runlevels Finit also automaticallyreloads all.conf
files in the/etc/finit.d/
directory. So if youwant to set a new system config, switch to runlevel 1, change all configfiles in the system, and touch all.conf
files in/etc/finit.d
before switching back to the previous runlevel again — that way Finitcan both stop old services and start any new ones for you, withoutrebooting the system.
Traditionally, rebooting and halting a UNIX system is done by changingits runlevel. Finit comes with its own tooling providing:shutdown
,reboot
,poweroff
, andsuspend
, but also theinitctl
tool,detailed in the next section.
For compatibility reasons Finit listens to the same set of signals asBusyBox init. This is not 100% compatible with SysV init, but clearlythe more common combination for Finit. For more details, seedoc/signals.md.
Finit also implements a modern API to query status, and start/stopservices, calledinitctl
. Unliketelinit
theinitctl
tool doesnot return until the given command has fully completed.
Usage: initctl [OPTIONS] [COMMAND]Options: -b, --batch Batch mode, no screen size probing -c, --create Create missing paths (and files) as needed -f, --force Ignore missing files and arguments, never prompt -h, --help This help text -j, --json JSON output in 'status' and 'cond' commands -1, --once Only one lap in commands like 'top' -p, --plain Use plain table headings, no ctrl chars -q, --quiet Silent, only return status of command -t, --no-heading Skip table headings -v, --verbose Verbose output -V, --version Show program versionCommands: debug Toggle Finit (daemon) debug help This help text version Show program version ls | list List all .conf in /etc/finit.d create <CONF> Create .conf in /etc/finit.d/available delete <CONF> Delete .conf in /etc/finit.d/available show <CONF> Show .conf in /etc/finit.d/available edit <CONF> Edit .conf in /etc/finit.d/available touch <CONF> Change .conf in /etc/finit.d/available enable <CONF> Enable .conf in /etc/finit.d/available disable <CONF> Disable .conf in /etc/finit.d/enabled reload Reload *.conf in /etc/finit.d (activate changes) cond set <COND> Set (assert) user-defined conditions +usr/COND cond get <COND> Get status of user-defined condition, see $? and -v cond clear <COND> Clear (deassert) user-defined conditions -usr/COND cond status Show condition status, default cond command cond dump [TYPE] Dump all, or a type of, conditions and their status log [NAME] Show ten last Finit, or NAME, messages from syslog start <NAME>[:ID] Start service by name, with optional ID stop <NAME>[:ID] Stop/Pause a running service by name reload <NAME>[:ID] Reload service as if .conf changed (SIGHUP or restart) This allows restart of run/tasks that have already run Note: Finit .conf file(s) are *not* reloaded! restart <NAME>[:ID] Restart (stop/start) service by name signal <NAME>[:ID] <S> Send signal S to service by name, with optional ID ident [NAME] Show matching identities for NAME, or all status <NAME>[:ID] Show service status, by name status Show status of services, default command cgroup List cgroup config overview ps List processes based on cgroups top Show top-like listing based on cgroups plugins List installed plugins runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot reboot Reboot system halt Halt system poweroff Halt and power off system suspend Suspend system utmp show Raw dump of UTMP/WTMP db
For servicesnot supportingSIGHUP
the<!>
notation in the .conffile must be used to tell Finit to stop and start it onreload
andrunlevel
changes. If<>
holds moreconditions,these will also affect how a service is maintained.
Note: even though it is possible to start services not belonging inthe current runlevel these services will not be respawned automaticallyby Finit if they exit (crash). Hence, if the runlevel is 2, the belowDropbear SSH service will not be restarted if it is killed or exits.
Thestatus
command is the default, it displays a quick overview of allmonitored run/task/services. Here we callinitctl -p
, suitable forscripting and documentation:
alpine:~# initctl -pPID IDENT STATUS RUNLEVELS DESCRIPTION======================================================================1506 acpid running [---2345----] ACPI daemon1509 crond running [---2345----] Cron daemon1489 dropbear running [---2345----] Dropbear SSH daemon1511 klogd running [S-12345----] Kernel log daemon1512 ntpd running [---2345----] NTP daemon1473 syslogd running [S-12345----] Syslog daemonalpine:~# initctl -pvPID IDENT STATUS RUNLEVELS COMMAND======================================================================1506 acpid running [---2345----] acpid -f1509 crond running [---2345----] crond -f -S $CRON_OPTS1489 dropbear running [---2345----] dropbear -R -F $DROPBEAR_OPTS1511 klogd running [S-12345----] klogd -n $KLOGD_OPTS1512 ntpd running [---2345----] ntpd -n $NTPD_OPTS1473 syslogd running [S-12345----] syslogd -n
The environment variables to each of the services above are read from,in the case of Alpine Linux,/etc/conf.d/
. Other distributions mayhave other directories, e.g., Debian use/etc/default/
.
Thestatus
command takes an optionalNAME:ID
argument. Here wecheck the status ofdropbear
, which only has one instance in thissystem:
alpine:~# initctl -p status dropbear Status : running Identity : dropbearDescription : Dropbear SSH daemon Origin : /etc/finit.d/enabled/dropbear.confEnvironment : -/etc/conf.d/dropbearCondition(s): Command : dropbear -R -F $DROPBEAR_OPTS PID file : !/run/dropbear.pid PID : 1485 User : root Group : root Uptime : 2 hour 46 min 56 sec Runlevels : [---2345----] Memory : 1.2M CGroup : /system/dropbear cpu 0 [100, max] mem [--.--, max] |- 1485 dropbear -R -F |- 2634 dropbear -R -F |- 2635 ash `- 2652 initctl -p status dropbearApr 8 12:19:49 alpine authpriv.info dropbear[1485]: Not backgroundingApr 8 12:37:45 alpine authpriv.info dropbear[2300]: Child connection from 192.168.121.1:47834Apr 8 12:37:46 alpine authpriv.notice dropbear[2300]: Password auth succeeded for 'root' from 192.168.121.1:47834Apr 8 12:37:46 alpine authpriv.info dropbear[2300]: Exit (root) from <192.168.121.1:47834>: Disconnect receivedApr 8 15:02:11 alpine authpriv.info dropbear[2634]: Child connection from 192.168.121.1:48576Apr 8 15:02:12 alpine authpriv.notice dropbear[2634]: Password auth succeeded for 'root' from 192.168.121.1:48576
Finit is capable of running on both desktop/server systems with udev andembedded systems that usually come with BusyBox mdev. Some systems havesystemd-udev or eudev today instead of the original udev, Finit probesfor all of them at runtime and expects/dev/
to be a writable filesystem usingdevtmpfs
. It is also possible to run on a statically setup/dev
if needed. It is however not a good idea to have both udevand mdev installed at the same time, this will lead to unpredictableresults.
At boot Finit calls eithermdev
orudevd
to populate/dev
, this isdone slightly differently and on systems with udev you might want to addthe following one-shot task early in your/etc/finit.conf
:
run [S] udevadm settle --timeout=120 -- Waiting for udev
Finit has a built-in Getty for TTYs, but requires a working/bin/login
or/bin/sh
, if no TTYs are configured in/etc/finit.conf
.
For a fully operational system/var
,/run
and/tmp
must be set upproperly in/etc/fstab
-- which is iterated over at boot.
This project is based on theoriginal finit byClaudio Matsuokawhich was reverse engineered from syscalls of theEeePC fastinit —"gaps filled with frog DNA …"
Finit is developed and maintained byJoachim Wiberg atGitHub.Please file bug reports, clone it, or send pull requests for bug fixesand proposed extensions.
About
Fast init for Linux. Cookies included