FINIT.CONF(5) | File Formats Manual (smm) | FINIT.CONF(5) |
finit.conf
— Finit
configuration file format
/etc/finit.conf |
/etc/finit.d/*.conf |
/etc/finit.d/available/*.conf |
finit
can be configured using only the
original /etc/finit.conf file or in combination with
/etc/finit.d/*.conf. Useful for package-based Linux
distributions — each package can provide its own "script"
file.
Not all configuration directives are available in
/etc/finit.d/*.conf and some directives are only
available at bootstrap, runlevel S
, see the section
Limitations below for details.
Lines starting with `#' are ignored. Note that end-of-line comments are NOT supported, comments must be on a line of their own.
A configuration stanza must be on a single (long) line and cannot be broken up in multiple lines by use of a backslash as the last character.
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 set
RLIMIT_CPU
, use cpu
.
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 infinity
for
unlimited
, 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
rlimit
can 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⟩N
is 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: 2
Note: only read and executed in runlevel S (bootstrap).
run
[LVLS] ⟨COND⟩ /path/to/cmd ARGS [--
Optional description]run
commands 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]run
, but starts in parallel with the
next command.
Both run
and
task
commands 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]task
is the
sysv
stanza, which can be used to call SysV style
start/stop scripts. The primary intention for this command is to be able
to re-use much of existing setup and init scripts in Linux distributions.
When entering an allowed runlevel, Finit calls
init-script start
, when entering a disallowed
runlevel, Finit calls init-script stop
, and if
the Finit .conf, where the sysv
stanza is
declared, is modified, Finit calls init-script
restart
on initctl reload
. Similar to how
service
stanzas work.
Forking services started with sysv
scripts 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]initctl restart NAME
. The number of restarts, the
delay between each restart, and more is configurable, see the options
below.
For 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
sysv
services, using the
pid:!/path/to/pidfile.pid
command modifier
syntax.
Example:
in the case of ospfd
(below), we omit
the -d
flag (daemonize) to prevent it from
forking to the background:
service [2345] <pid/zebra> /sbin/ospfd -- OSPF daemon
[2345]
denote the runlevels
ospfd
is allowed to run in, they are optional
and default to runlevel 2-5 if omitted.
<pid/zebra>
is the condition for
starting ospfd
. In this example Finit waits for
another service, zebra
, to have created its PID
file in /var/run/quagga/zebra.pid before
starting ospfd
. Finit watches *all* files in
/var/run, for each file named
*.pid
, */pid
, Finit
opens it and find the matching NAME:ID
using the
PID.
Some services do not maintain a PID file and rather than
patching each application Finit provides a workaround. A
pid
modifier 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 the
pid
modifier is:
pid[:[!][/path/to/]filename[.pid]]
For example, by adding
pid:/run/foo.pid
to 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.
If a service should not be automatically started, it can be
configured as manual with the manual:yes
command
modifier. The service can then be started at any time by running
initctl start NAME
The name of a service, shown by the
initctl
tool, defaults to the basename of the
service executable. It can be changed with the
name:foo
command modifier.
As mentioned previously, services are automatically restarted should they crash, this is configurable with the following options:
restart:NUM
restart_sec:SEC
norestart
restart:0
oncrash:reboot
oncrash:
actions.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 modifier
kill:SEC
, e.g., kill:10
to wait 10 seconds before sending SIGKILL.
Services support the pre:script
and
post:script
command actions as well. These run
as the same @USER:GROUP
as the service itself,
with any env:file
sourced. The scripts must use
an absolute path, but are executed from the
$HOME
of the given user. The scripts are not
called with any argument (currently), but both get the
SERVICE_IDENT=foo
environment variable set. Here
foo
denotes the identity of the service, which
if there are multiple services named foo
, may be
foo:1
, or any unique identifier specified in the
.conf file. The post:script
is called with an
additional set of environment variables:
EXIT_CODE=[exited,signal]
exited
or
signal
EXIT_STATUS=[num,SIGNAME]
The scripts have a default execution time of 3 seconds before
they are SIGKILLed, this can be adjusted using the
kill:SEC
modifier syntax.
Note: the
pre:script
must be
idempotent, because a service can transition between READY and HALTED
states any number of times before going to RUNNING.
runparts
⟨DIR⟩DIR
to 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⟩log size:BYTES
count:NUM
log
command 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
, or
size:3G
. A value of
size:0
disables log rotation. The default is
size: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]tty
stanza 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]tty
stanza 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 noclear
option disables clearing
the TTY after each session. Clearing the TTY when a user logs out is
usually preferable.
The nowait
option disables the
Please press Enter to activate console
message
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 nologin
option disables getty and
/bin/login, and gives the user a root (login)
shell on the given TTY DEV
immediately. 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 TERM
option
to the built-in getty must be the last argument.
Embedded systems may want to enable automatic `DEV` by
supplying the special @console
device. This
works regardless weather the system uses ttyS0
,
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
@console
to 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 service
stanza to
start a stand-alone shell:
service [12345] /bin/sh -l
tty
[LVLS] ⟨COND⟩ [notty] [rescue]tty
form is for board bringup and the
rescue
boot mode. No device node is required in
this variant, the same output that the kernel uses is reused for stdio. If
the rescue
option is omitted, a shell is started.
The flags nologin
,
noclear
, and nowait
are
implied. If the rescue
option 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.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
run
, task
, or
service
can also list the privileges the
/path/to/cmd
should 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 :ID
somewhere
between the run
, task
,
service
keyword 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 :ID
to the service the
latter will overwrite the former and only the old web server would be
started and supervised.
log:/path/to/file
log:console
log:null
log:prio:facility.level,tag:ident
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
log
prio
is
daemon.info
and the default
tag
identity is the basename of the service or
run/task command.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.
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.
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.
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.
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.
There are three major cgroup configuration directives:
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
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.
finit
was conceived and reverse engineered
by Claudio Matsuoka. Since v1.0, maintained by Joachim Wiberg, with
contributions by many others.
October 17, 2020 | Linux |