| FINIT.CONF(5) | File Formats Manual (smm) | FINIT.CONF(5) |
NAME¶
finit.conf — Finit
configuration file format
SYNOPSIS¶
/etc/finit.conf |
/etc/finit.d/*.conf |
/etc/finit.d/available/*.conf |
/etc/finit.d/enabled/*.conf |
DESCRIPTION¶
Finit based systems can be set up with a
single file: /etc/finit.conf. This is the
traditional way of doing it which can be ideal for some setups since it
gives a great overview of the system configuration.
More comprehensive setups, however, require more careful planning.
The recommendation is per-package *.conf files in
/etc/finit.d/available/. This allows end users to
enable and disable parts of the system configuration at runtime. Finit
tracks which tasks and services belong to a given file, so that when the
user calls initctl reload to activate the changes
they have made, only the affected tasks and services are stopped, started,
or restarted. Hence, this approach is useful for modern package-based Linux
distributions.
The following sections describe the more of this in detail, starting with files, the file format, and available directives. Remember to also visit the other manual pages (references at the bottom).
FILES¶
- /etc/finit.conf
- Main configuration file, optional
- /etc/finit.d/*.conf
- Static (system) service definitions
- /etc/finit.d/available/*.conf
- Available (installed) services
- /etc/finit.d/enabled/*.conf
- Enabled services (symlink back)
Static services, .conf files in
/etc/finit.d/, cannot be enabled or disabled using
initctl [enable | disable]
service[.conf]. An enabled service is a symlink back to the
corresponding ../available/ service
.conf file. Please use the
initctl tool to manage these symlinks to ensure
proper operation.
NOTE:
Previous versions of Finit created symlinks in
/etc/finit.d/ if
/etc/finit.d/enabled/ was missing, this is as of
v4.4 not supported.
FILE FORMAT¶
The file format is line based, empty lines and comments, lines starting with `#', are ignored. A configuration directive starts with a keyword followed by a space and the rest of the line is treated as the value.
As of Finit v4.4, configuration directives can be broken up in multiple lines using the continuation character `\', and trailing comments are also allowed. Example:
# Escape \# chars if you want them literal in, e.g., descriptions
service name:sysklogd [S123456789] \
env:-/etc/default/sysklogd \
syslogd -F $SYSLOGD_ARGS \
-- System log daemon \# 1 # Comments allowed now
DIRECTIVES¶
This section lists all supported configuration directives. There also exist deprecated directives, see the Markdown documentation for details on these.
rlimit[hard|soft] RESOURCE ⟨LIMIT | unlimited⟩-
Set the hard or soft limit for a resource, or both if that argument is omitted. RESOURCE is the lower-case
RLIMIT_string constants from setrlimit(2), without prefix. E.g. to setRLIMIT_CPU, usecpu.LIMIT is an integer that depends on the resource being modified, see the man page, or the kernel /proc/PID/limits file, for details. Finit versions before v3.1 used
infinityforunlimited, which is still supported, albeit deprecated.# No process is allowed more than 8MB of address space rlimit hard as 8388608 # Core dumps may be arbitrarily large rlimit soft core infinity # CPU limit for all services, soft & hard = 10 sec rlimit cpu 10
rlimitcan be set globally, in /etc/finit.conf, or locally per each /etc/finit.d/*.conf read. I.e., a set of task/run/service stanzas can share the same rlimits if they are in the same .conf. runlevel⟨N⟩- The system runlevel to go to after bootstrap (S) has completed.
Nis the runlevel number 0-9, where 6 is reserved for reboot and 0 for halt. All other can be used by operating system administrators. Default: 2It s recommended to keep runlevel 1 as single-user mode, because
finit.confdisables networking in this mode.Note: only read and executed in runlevel S (bootstrap).
run[LVLS] ⟨COND⟩ /path/to/cmd ARGS [-- Optional description]- One-shot command to run in sequence when entering a runlevel, with
optional arguments and description.
runcommands are guaranteed to be completed before running the next command. Highly useful if true serialization is needed. Usually only used in the bootstrap (S) runlevel.⟨COND⟩ conditions are described in finit(8), see also the Examples section below.
task[LVLS] ⟨COND⟩ /path/to/cmd ARGS [-- Optional description]- One-shot like
run, but starts in parallel with the next command.Both
runandtaskcommands are run in a shell, so pipes and redirects can be freely used:task [s] echo "foo" | cat >/tmp/bar
sysv[LVLS] ⟨COND⟩ /path/to/script ARGS [-- Optional description]- Similar to
serviceis thesysvstanza, which can be used to call SysV style start/stop scripts. The primary intention for this command is to be able to re-use traditional SysV init scripts in Linux distributions.When entering an allowed runlevel, Finit calls
init-script start, when entering a disallowed runlevel, Finit callsinit-script stop, and if the Finit .conf, where thesysvstanza is declared, is modified, Finit callsinit-script restartoninitctl reload. Similar to howservicestanzas work.Forking services started with
sysvscripts can be monitored by Finit by declaring the PID file to look for:sysv pid:!/path/to/pidfile.pid /path/to/script ...
The leading '!' is to prevent Finit from managing the PID file, which is the default behavior for the
pid:command modifier. service[LVLS] ⟨COND⟩ /path/to/daemon ARGS [-- Optional description]- Service, or daemon, to be monitored and automatically restarted if it
exits prematurely. Finit tries to restart services that die, by default 10
times, before giving up and marking them as crashed.
After which they have to be restarted manually using
initctl restart NAME. The number of restarts, the delay between each restart, and more is configurable, see the options below.Tip: to allow endless restarts, see below optionrespawnFor daemons that support it, we recommend appending
--foreground,--no-background,-n,-F, or similar command line argument to prevent them from forking off a sub-process in the background. This is the most reliable way to monitor a service.However, not all daemons support running in the foreground, or they may start logging to the foreground as well, these are called forking services and are supported using the same syntax as forking
sysvservices, using thepid:!/path/to/pidfile.pidcommand modifier syntax. There is an alternative syntax that may be more intuitive, where Finit can also guess the PID file based on the daemon's command name:service type:forking ntpd -- NTP daemon
Here we let BusyBox
ntpddaemonize itself. Finit uses the basename of the binary to guess the PID file to watch for the PID: /var/run/ntpd.pid. If Finit guesses wrong, you have to submit the fullpid:!/path/to/file.pidoption to your service stanza.Example: in the case of
ospfd(below), we omit the-dflag (daemonize) to prevent it from forking to the background:service [2345] <pid/zebra> /sbin/ospfd -- OSPF daemon
[2345]denote the runlevelsospfdis allowed to run in, they are optional and default to runlevel 2-5 if omitted.<pid/zebra>is the condition for startingospfd. In this example Finit waits for another service,zebra, to have created its PID file in /var/run/quagga/zebra.pid before startingospfd. Finit watches *all* files in /var/run, for each file named*.pid,*/pid, Finit opens it and find the matchingNAME:IDusing the PID.Some services do not maintain a PID file and rather than patching each application Finit provides a workaround. A
pidmodifier keyword can be set to have Finit automatically create (when starting) and later remove (when stopping) the PID file. The file is created in the /var/run directory using the basename(3) of the service. The full syntax of thepidmodifier is:pid[:[!][/path/to/]filename[.pid]]
For example, by adding
pid:/run/foo.pidto the service/sbin/bar, that PID file will, not only be created and removed automatically, but also be used by the Finit condition subsystem. So a service/run/task can depend on the<pid/bar>condition.As an alternative "readiness" notification, Finit supports both systemd and s6 style notification. This can be enabled by using the `notify` option:
notify:systemd- tells Finit the service uses the
sd_notify()API to signal PID 1 when it has completed its startup and is ready to service events. This API expects the environment variableNOTIFY_SOCKETto be set to the socket where the application can sendREADY=10when it is starting up or has processed aSIGHUP. For details, see:https://www.freedesktop.org/software/systemd/man/sd_notify.html
notify:s6- puts Finit in s6 compatibility mode. Compared to the systemd
notification, s6 expect compliant daemons to send
and then close their socket. For details, see:https://skarnet.org/software/s6/notifywhenup.html
Finit takes care of "hard-wiring" the READY state as long as the application is running, events across any `SIGHUP`. Since s6 can give its applications the descriptor number (must be >3) on then command line, Finit provides the following syntax (
%nis replaced by Finit with then descriptor number):service notify:s6 mdevd -C -O 4 -D %n
When a service is ready, either by Finit detecting its PID file, or their respective readiness mechanism has been triggered, Finit creates then service's ready condition which other services can depend on:
$ initctl -v cond get service/mdevd/ready on
If a service should not be automatically started, it can be configured as manual with the
manual:yescommand modifier. The service can then be started at any time by runninginitctl start NAMEThe name of a service, shown by the
initctltool, defaults to the basename of the service executable. It can be changed with thename:foocommand modifier.As mentioned previously, services are automatically restarted should they crash, this is configurable with the following options:
restart:NUM- number of times Finit tries to restart a crashing service, default: 10. When this limit is reached the service is marked crashed and must be restarted manually with initctl(8).
restart_sec:SEC- number of seconds before Finit tries to restart a crashing service, default: 2 seconds for the first five retries, then back-off to 5 seconds. The maximum of this configured value and the above (2 and 5) will be used
restart:always- no upper limit on the number of times Finit tries to restart a
crashing service. Same as
restart:-1 norestart- dont restart on failures, same as
restart:0 respawn- bypasses the
restartmechanism completely, allows endless restarts. Useful in many use-cases, but not whatservicewas originally designed for so not the default behavior. oncrash:reboot- when all retries have failed, and the service has crashed, if this option is set the system is rebooted.
oncrash:script- Similar to
oncrash:reboot, but instead of rebooting this action calls thepost:script(see below) to let the operator decide the best course of action. If the post:script option is not set, this is a no-op.The post:script is called with the same environment variables except for the
EXIT_CODEvariable which is set tocrashed.
When stopping a service (run/task/sysv/service), either manually or when moving to another runlevel, Finit starts by sending SIGTERM, to allow the process to shut down gracefully. If the process has not been collected within 3 seconds, Finit sends SIGKILL. To halt the process using a different signal, use the command modifier
halt:SIGNAL, e.g.,halt:SIGPWR. To change the delay between your halt signal and KILL, use the command modifierkill:SEC, e.g.,kill:10to wait 10 seconds before sending SIGKILL.Services, including the
sysvvariant, support pre/post/ready and cleanup scripts:pre:[0-3600,]script- called before the sysv/service is stated
post:[0-3600,]script- called after the sysv/service has stopped
ready:[0-3600,]script- called when the sysv/service is ready
cleanup:[0-3600,]script- called when run/task/sysv/service is removed
The optional number (0-3600) is the timeout before Finit kills the script, it defaults to the kill delay value and can be disabled by setting it to zero. These scripts run as the same
@USER:GROUPas the service itself, with anyenv:filesourced. The scripts must use an absolute path, but are executed from the$HOMEof the given user. The scripts are not called with any argument, but both get a set of environment variables:The
post:scriptis called with an additional set of environment variables, and yes the naming looks like it should be swapped:EXIT_CODE=[exited,signal,crashed]- set to one of
exited,signal, orcrashed(see above). EXIT_STATUS=[num,SIGNAME]- set to one of exit status code from the program, if it exited normally, or the signal name (HUP, TERM, etc.) if it exited due to signal
When a run/task/sys/service is removed (disable + reload) it is first stopped and then removed from the runlevel. The
post:scriptalways runs when the process has stopped, and thecleanup:scriptruns when the the stanza has been removed from the runlevel. runparts⟨DIR⟩- Call run-parts(8) on
DIRto run start scripts. All executable files, or scripts, in the directory are called, in alphabetic order. The scripts in this directory are executed at the very end of bootstrap, runlevel S.It can be beneficial to use
S01name,S02othername, etc. if there is a dependency order between the scripts. Symlinks to existing daemons can talso be used, but make sure they daemonize by default.Similar to the /etc/rc.local shell script, make sure that all your services and programs either terminate or start in the background or you will block Finit. Note: only read and executed in runlevel S (bootstrap).
include⟨CONF⟩- Include another configuration file. Absolute path required.
log size:BYTES count:NUM- Log rotation for run/task/services using the
logcommand modifier with redirection to a log file. Global setting, applies to all services.The size can be given as bytes, without a specifier, or in `k`, `M`, or `G`, e.g.
size:10M, orsize:3G. A value ofsize:0disables log rotation. The default issize:200k.The count value is recommended to be between 1-5, with a default 5. Setting count to 0 means the logfile will be truncated when the MAX size limit is reached.
tty[LVLS] ⟨COND⟩ DEV [BAUD] [noclear] [nowait] [nologin] [TERM]- This form of the
ttystanza uses the built-in getty on the given TTY device DEV, in the given runlevels. DEV may be the special keyword@console, or `console`, which is expanded from `/sys/class/tty/console/active`, useful on embedded systems.The default baud rate is 0, i.e., keep kernel default.
The `tty` stanza inherits runlevel, condition (and other feature) parsing from the `service` stanza. So TTYs can run in one or many runlevels and depend on any condition supported by Finit. This is useful e.g. to depend on `<pid/elogind>` before starting a TTY.
tty [12345] /dev/ttyAMA0 115200 noclear vt220
tty[LVLS] ⟨COND⟩ CMD DEV [noclear] [nowait]- This form of the
ttystanza is for using an external getty, like agetty or the BusyBox getty.By default, these first two syntax variants clear the TTY and wait for the user to press enter before starting getty.
tty [12345] /sbin/getty -L 115200 /dev/ttyAMA0 vt100 tty [12345] /sbin/agetty -L ttyAMA0 115200 vt100 nowait
The
noclearoption disables clearing the TTY after each session. Clearing the TTY when a user logs out is usually preferable.The
nowaitoption disables thePlease press Enter to activate consolemessage before actually starting the getty program. On small and embedded systems running multiple unused getty wastes both memory and CPU cycles, so `wait` is the preferred default.The
nologinoption disables getty and /bin/login, and gives the user a root (login) shell on the given TTYDEVimmediately. Needless to say, this is a rather insecure option, but can be very useful for developer builds, during board bringup, or similar.Notice the ordering, the
TERMoption to the built-in getty must be the last argument.Embedded systems may want to enable automatic `DEV` by supplying the special
@consoledevice. This works regardless weather the system usesttyS0,ttyAMA0,ttyMXC0, or anything else. Finit figures it out by querying sysfs: /sys/class/tty/console/active. The speed can be omitted to keep the kernel default.Most systems get by fine by just using `console`, which will evaluate to /dev/console. If you have to use
@consoleto get any output, you may have some issue with your kernel config.tty [12345] @console noclear vt220
On really bare bones systems, or for board bringup, Finit can give you a shell prompt as soon as bootstrap is done, without opening any device node:
tty [12345789] notty
This should of course not be enabled on production systems. Because it may give a user root access without having to log in. However, for board bringup and system debugging it can come in handy.
One can also use the
servicestanza to start a stand-alone shell:service [12345] /bin/sh -l
tty[LVLS] ⟨COND⟩ [notty] [rescue]- The third
ttyform is for board bringup and therescueboot mode. No device node is required in this variant, the same output that the kernel uses is reused for stdio. If therescueoption is omitted, a shell is started. The flagsnologin,noclear, andnowaitare implied. If therescueoption is set the bundled /libexec/finit/sulogin is started to present a bare-bones root login prompt. If the root (uid:0, gid:0) user does not have a password set, no rescue is possible.
COMMAND MODIFIERS¶
The run/task/tty/service/sysv stanzas take modifiers, or options, to control their behavior. This section lists them with their limitations. All modifiers must be placed between the stanza and its command.
@user:group- Every
run,task, orservicecan also list the privileges the/path/to/cmdshould be executed with. Prefix the command with@USR[:GRP], group is optional, like this:run [2345] @joe:users logger "Hello world"
For multiple instances of the same command, e.g. a DHCP client or multiple web servers, add
:IDsomewhere between therun,task,servicekeyword and the command, like this:service :80 [2345] httpd -f -h /http -p 80 -- Web server service :8080[2345] httpd -f -h /http -p 8080 -- Old web server
Without the
:IDto the service the latter will overwrite the former and only the old web server would be started and supervised. log:/path/to/file- Redirect stdout/stderr of a command to the given log file. See the global log directive, above, for details on log rotation.
log:console- Redirect stdout/stderr of a command to /dev/console, only use this for debugging or bringup.
log:null- Redirect stdout/stderr of a command to /dev/null.
log:prio:facility.level,tag:ident- Redirect stdout/stderr of a command to syslog using the given priority and
tag identity.
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
log- Default
prioisdaemon.infoand the defaulttagidentity is the basename of the service or run/task command.
RESCUE MODE¶
Finit supports a rescue mode which is activated by the
rescue option on the kernel command line. The rescue
mode comes in two flavors:
traditional
and fallback.
Traditional¶
This is what most users expect. A very early maintenance login
prompt, served by the bundled /libexec/finit/sulogin
program, or the standard sulogin from util-linux or
BusyBox is searched for in the UNIX default $PATH.
If a successful login is made, or the user exits (Ctrl-D), the rescue mode
is ended and the system boots up normally.
Note: if the user (UID 0 and GID 0)
does not have a password, or
the account is
locked, the user is presented with a password-less prompt:
Press enter to enter maintenance mode., which opens
up a root shell.
Fallback¶
If no sulogin program is found, Finit
tries to bring up as much of its own functionality as possible, yet limiting
many aspects, meaning; no network, no`fsck` of file systems in
/etc/fstab, no
/etc/rc.local, no runparts,
and most plugins are skipped (except those that provide functionality for
the condition subsystem).
Instead of reading /etc/finit.conf et al, system configuration is read from /lib/finit/rescue.conf, which can be freely modified by the system administrator.
The bundled default `rescue.conf` contains nothing more than:
runlevel 1 tty [12345] rescue
The tty has the
rescue option set, which works similar to the board
bring-up tty option notty. The major difference
being that `sulogin` is started to query for root/admin password. If
sulogin is not found, rescue
behaves like notty and gives a plain root shell
prompt.
If Finit cannot find /lib/finit/rescue.conf it defaults to:
tty [12345] rescue
There is no way to exit the fallback rescue mode.
SERVICE ENVIRONMENT¶
Finit supports sourcing environment variables from
/etc/default/*, or similar. This is a common pattern
from SysV init scripts, where the start/stop script is a generic script for
the given service, foo, and the options for the
service are sourced from the file /etc/default/foo.
Like this:
/etc/default/foo:
FOO_OPTIONS=--extra-arg="bar" -s -x
/etc/finit.conf:
service [2345] env:-/etc/default/foo foo -n $FOO_OPTIONS -- Example foo daemon
Here the service foo is started with
[--n], to make sure it runs in the foreground, and
the with the options found in the environment file. With the
ps command we can see that the process is started
with:
foo -n --extra-arg=bar -s -x
Note: the leading `-` determines if Finit should treat a missing environment file as blocking the start of the service or not. When `-` is used, a missing environment file does not block the start.
SERVICE WRAPPER SCRIPTS¶
If your service requires to run additional commands, executed before the service is actually started, like the systemd `ExecStartPre`, you can use a wrapper shell script to start your service.
The Finit service .conf file can be put
into /etc/finit.d/available, so you can control the
service using initctl. Then use the path to the
wrapper script in the Finit .conf service stanza.
The following example employs a wrapper script in
/etc/start.d.
/etc/finit.d/available/program.conf:
service [235] <!> /etc/start.d/program -- Example Program
/etc/start.d/program:
#!/bin/sh
# Prepare the command line options
OPTIONS="-u $(cat /etc/username)"
# Execute the program
exec /usr/bin/program $OPTIONS
Note: the example sets
<!> to denote that it doesn't support SIGHUP.
That way Finit will stop/start the service instead of sending SIGHUP at
restart/reload events.
TEMPLATING¶
Finit comes with rudimentary support for templating, similar to that of systemd. Best illustrated with an example:
$ initctl show avahi-autoipd@ service :%i avahi-autoipd --syslog %i -- ZeroConf for %i
To enable ZeroConf for, e.g., eth0,
use
$ initctl enable avahi-autoipd@eth0.conf
The enabled symlink will be set up to
avahi-autoipd@.conf and every instance of
%i will in the instantiated directive be replaced
with eth0. Inspect the result with:
$ initctl status avahi-autoipd:eth0
CGROUPS¶
There are three major cgroup configuration directives:
- Global top-level group: init, system, user, or a custom group
- Selecting a top-level group for a set of run/task/services
- Per run/task/service limits
Top-level group configuration.
# Top-level cgroups and their default settings. All groups mandatory # but more can be added, max 8 groups in total currently. The cgroup # 'root' is also available, reserved for RT processes. Settings are # as-is, only one shorthand 'mem.' exists, other than that it's the # cgroup v2 controller default names. cgroup init cpu.weight:100 cgroup user cpu.weight:100 cgroup system cpu.weight:9800
Adding an extra cgroup maint/ will require
you to adjust the weight of the above three. We leave
init/ and user/ as-is
reducing weight of system/ to 9700.
cgroup system cpu.weight:9700 # Example extra cgroup 'maint' cgroup maint cpu.weight:100
By default, the system/ cgroup is selected
for almost everything. The init/ cgroup is reserved
for PID 1 itself and its closest relatives. The
user/ cgroup is for local TTY logins spawned by
getty.
To select a different top-level cgroup, e.g.
maint/, one can either define it for a group of
run/task/service directives in a .conf or per each
stanza:
cgroup.maint service [...] <...> /path/to/foo args -- description service [...] <...> /path/to/bar args -- description
or
service [...] <...> cgroup.maint /path/to/foo args -- description
The latter form also allows per-stanza limits on the form:
service [...] <...> cgroup.maint:cpu.max:10000,mem.max:655360 /path/to/foo args -- description
Notice the comma separation and the mem.
exception to the rule: every cgroup setting maps directly to cgroup v2
syntax. I.e., cpu.max maps to the file There is no
filtering, except for expanding the shorthand mem.
to memory., if the file is not available, either the
cgroup controller is not available in your Linux kernel, or the name is
misspelled.
Linux cgroups and details surrounding values are not explained in the Finit documentation. The Linux admin-guide cover this well: https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
LIMITATIONS¶
As of Finit v4 there are no limitations to where
.conf settings can be placed. Except for the
system/global rlimit and
cgroup top-level group declarations, which can only
be set from /etc/finit.conf, since it is the first
.conf file Finit reads.
Originally,
was the only way to set up a Finit system. Today it is mainly used
for bootstrap settings like system hostname, early module loading for
watchdogd, network bringup and system shutdown. These can now also be set in
any .conf file in
/etc/finit.d.
There is, however, nothing preventing you from having all configuration settings in /etc/finit.conf.
SEE ALSO¶
AUTHORS¶
Finit was conceived and reverse engineered
by Claudio Matsuoka. Since v1.0, maintained by Joachim Wiberg, with
contributions by many others.
| July 11, 2023 | Linux |