Finit configuration file format
can be configured using only the
file or in
combination with /etc/finit.d/*.conf
Useful for package-based Linux distributions — each package can provide
its own "script" file.
- Main configuration file
- Snippets, usually one service per file
Not all configuration directives are available in
and some directives are
only available at bootstrap, runlevel
see the section Limitations
below for details.
- Main configuration file
- Static service definitions
- Available services
- Enabled services, symlinks from available
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.
# Escape \# chars if you want them literal in, e.g., descriptions
service name:sysklogd [S123456789] \
syslogd -F $SYSLOGD_ARGS \
-- System log daemon \# 1 # Comments allowed now
This section lists all supported configuration directives. There also exist
deprecated directives, see the Markdown documentation for details on these.
⟨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
without prefix. E.g. to set
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
unlimited, which is still supported,
# 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
- The system runlevel to go to after bootstrap (S) has completed.
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
/path/to/cmd ARGS [
- One-shot command to run in sequence when entering a runlevel, with
optional arguments and 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
also the Examples section
/path/to/cmd ARGS [
- One-shot like
run, but starts in
parallel with the next command.
task commands are run in a shell, so
pipes and redirects can be freely used:
task [s] echo "foo" | cat >/tmp/bar
/path/to/script ARGS [
- Similar to
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
When entering an allowed runlevel, Finit calls
init-script start, when entering a
disallowed runlevel, Finit calls
stop, and if the Finit .conf, where the
sysv stanza is declared, is modified,
init-script restart on
initctl reload. Similar to how
service stanzas work.
Forking services started with
scripts can be monitored by Finit by declaring the PID file to look for:
The leading '!' is to prevent Finit from managing the PID file, which is the
default behavior for the
sysv pid:!/path/to/pidfile.pid /path/to/script ...
/path/to/daemon ARGS [
- 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
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 option
For daemons that support it, we recommend appending
-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
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
Here we let BusyBox
service type:forking ntpd -- NTP daemon
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 full
pid:!/path/to/file.pid option to your
Example: in the case of
ospfd (below), we omit the
-d flag (daemonize) to prevent it from
forking to the background:
service  <pid/zebra> /sbin/ospfd -- OSPF daemon
 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
ospfd. In this example Finit
waits for another service,
have created its PID file in
ospfd. Finit watches *all*
files in /var/run, for each file named
*/pid, Finit opens it and find the
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
the service. The full syntax of the
For example, by adding
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
As an alternative "readiness" notification, Finit supports both
systemd and s6 style notification. This can be enabled by using the
If a service should not be automatically started, it can be configured as
manual with the
- 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 variable
NOTIFY_SOCKET to be set to the
socket where the application can send
READY=10 when it is starting up or
has processed a
- puts Finit in s6 compatibility mode. Compared to the systemd
notification, s6 expect compliant daemons to send
\n and then close their socket. For
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 (
%n is replaced by Finit with then
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:
service notify:s6 mdevd -C -O 4 -D %n
$ initctl -v cond get service/mdevd/ready
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:
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
- 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
- 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
- no upper limit on the number of times Finit tries to restart a
crashing service. Same as
- dont restart on failures, same as
- bypasses the
completely, allows endless restarts. Useful in many use-cases, but not
service was originally
designed for so not the default behavior.
- when all retries have failed, and the service has
crashed, if this option is set the system
- Similar to
instead of rebooting this action calls the
post: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_CODE variable which is set to
halt:SIGPWR. To change the delay
between your halt signal and KILL, use the command modifier
kill:10 to wait 10 seconds before
Services support the
post:script command actions as well.
These run as the same
the service itself, with any
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
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:
The scripts have a default execution time of 3 seconds before they are
SIGKILLed, this can be adjusted using the
kill:SEC modifier syntax.
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
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
- Include another configuration file. Absolute path required.
- Log rotation for run/task/services using the
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`,
size:3G. A value of
size:0 disables log rotation. The
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
- This form of the
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  /dev/ttyAMA0 115200 noclear vt220
CMD DEV [
- This form of the
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
tty  /sbin/getty -L 115200 /dev/ttyAMA0 vt100
tty  /sbin/agetty -L ttyAMA0 115200 vt100 nowait
noclear option disables clearing the
TTY after each session. Clearing the TTY when a user logs out is usually
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.
nologin option disables getty and
/bin/login, and gives the user a root
(login) shell on the given TTY
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
ttyMXC0, or anything else. Finit
figures it out by querying sysfs:
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.
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
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
tty  @console noclear vt220
service stanza to
start a stand-alone shell:
service  /bin/sh -l
- The third
tty form is for board bringup
rescue boot mode. No device
node is required in this variant, the same output that the kernel uses is
reused for stdio. If the
is omitted, a shell is started. The flags
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.
service can also list the privileges
/path/to/cmd should be executed
with. Prefix the command with
@USR[:GRP], group is optional, like
For multiple instances of the same command, e.g. a DHCP client or multiple
web servers, add
run  @joe:users logger "Hello world"
:ID somewhere between
service keyword and the command, like
service :80  httpd -f -h /http -p 80 -- Web server
service :8080 httpd -f -h /http -p 8080 -- Old web server
:ID to the service the latter
will overwrite the former and only the old web server would be started and
- Redirect stdout/stderr of a command to the given log file. See the global
log directive, above, for details on log rotation.
- Redirect stdout/stderr of a command to
/dev/console, only use this for
debugging or bringup.
- Redirect stdout/stderr of a command to
- Redirect stdout/stderr of a command to syslog using the given priority and
service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon
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
option on the kernel command line.
The rescue mode comes in two flavors: traditional
This is what most users expect. A very early maintenance login prompt, served by
the bundled /libexec/finit/sulogin
or the standard
from util-linux or
BusyBox is searched for in the UNIX default
. If a successful login is made, or
the user exits (Ctrl-D), the rescue mode is ended and the system boots up
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:
to enter maintenance mode.
, which opens up a root shell.
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
, and most plugins are skipped
(except those that provide functionality for the condition subsystem).
Instead of reading /etc/finit.conf
system configuration is read from
, which can be freely
modified by the system administrator.
The bundled default `rescue.conf` contains nothing more than:
tty  rescue
option set, which works similar to
the board bring-up tty option
major difference being that `sulogin` is started to query for root/admin
is not found,
and gives a plain root shell prompt.
If Finit cannot find /lib/finit/rescue.conf
it defaults to:
There is no way to exit the fallback
Finit supports sourcing environment variables from
, or similar. This is a
common pattern from SysV init scripts, where the start/stop script is a
generic script for the given service,
and the options for the service are sourced from the file
. Like this:
FOO_OPTIONS=--extra-arg="bar" -s -x
service  env:-/etc/default/foo foo -n $FOO_OPTIONS -- Example foo daemon
Here the service
is started with
], to make sure
it runs in the foreground, and the with the options found in the environment
file. With the
command we can see that
the process is started with:
foo -n --extra-arg=bar -s -x
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
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
file can be put into
, so you can control
the service using
. Then use the
path to the wrapper script in the Finit
service stanza. The following example
employs a wrapper script in /etc/start.d
service  <!> /etc/start.d/program -- Example Program
# Prepare the command line options
OPTIONS="-u $(cat /etc/username)"
# Execute the program
exec /usr/bin/program $OPTIONS
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:
- 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
you to adjust the weight of the above three. We leave
as-is reducing weight of
cgroup system cpu.weight:9700
# Example extra cgroup 'maint'
cgroup maint cpu.weight:100
By default, the
cgroup is selected
for almost everything. The
reserved for PID 1 itself and its closest relatives. The
cgroup is for local TTY logins
spawned by getty.
To select a different top-level cgroup, e.g.
, one can either define it for a
group of run/task/service directives in a
or per each stanza:
service [...] <...> /path/to/foo args -- description
service [...] <...> /path/to/bar args -- description
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
exception to the rule: every cgroup setting maps directly to cgroup v2 syntax.
maps to the file There is no
filtering, except for expanding the shorthand
, 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:
As of Finit v4 there are no limitations to where
settings can be placed. Except for
top-level group declarations, which
can only be set from /etc/finit.conf
it is the first
file Finit reads.
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
There is, however, nothing preventing you from having all configuration settings
was conceived and reverse engineered by
Claudio Matsuoka. Since v1.0, maintained by Joachim Wiberg, with contributions
by many others.