Configuration ============= * [Introduction](#introduction) * [Service Environment](#service-environment) * [Service Wrapper Scripts](#service-wrapper-scripts) * [Cgroups](#cgroups) * [Configuration File Syntax](#configuration-file-syntax) * [Hostname](#hostname) * [Kernel Modules](#kernel-modules) * [Networking](#networking) * [Resource Limits](#resource-limits) * [Runlevels](#runlevels) * [One-shot Commands (sequence)](#one-shot-commands--sequence-) * [One-shot Commands (parallel)](#one-shot-commands--parallel-) * [SysV Init Scripts](#sysv-init-scripts) * [Services](#services) * [Run-parts Scripts](#run-parts-scripts) * [Including Finit Configs](#including-finit-configs) * [General Logging](#general-logging) * [TTYs and Consoles](#ttys-and-consoles) * [Non-privileged Services](#non-privileged-services) * [Redirecting Output](#redirecting-output) * [Rescue Mode](#rescue-mode) * [Limitations](#limitations) * [/etc/finit.conf](#etcfinitconf) * [/etc/finit.d](#etcfinitd) * [Watchdog](#watchdog) * [keventd](#keventd) Introduction ------------ 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. - `/etc/finit.conf`: main configuration file - `/etc/finit.d/*.conf`: snippets, usually one service per 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](#limitations) below for details. To add a new service, simply drop a `.conf` file in `/etc/finit.d` and run `initctl reload`. (It is also possible to `SIGHUP` to PID 1, or call `finit q`, but that has been deprecated with the `initctl` tool). Finit monitors all known active `.conf` files, so if you want to force a restart of any service you can simply touch its corresponding `.conf` file in `/etc/finit.d` and call `initctl reload`. Finit handle any and all conditions and dependencies between services automatically. It is also possible to drop `.conf` files in `/etc/finit.d/available/` and use `initctl enable` to enable a service `.conf` file. This may be useful in particular to Linux distributions that may want to install all files for a package and let the user decide when to enable a service. On `initctl reload` the following is checked for all services: - If a service's `.conf` file has been removed, or its conditions are no longer satisifed, the service is stopped. - If the file is modified, or a service it depends on has been reloaded, the service is reloaded (stopped and started). - If a new service is added it is automatically started — respecting runlevels and return values from any callbacks. For more info on the different states of a service, see the separate document [Finit Services](service.md). > When running make install no default `/etc/finit.conf` is > installed since system requirements differ too much. There are some > examples in the `contrib/` directory, which can be used as a base. Service Environment ------------------- Finit supports sourcing environment variables from `/etc/default/*`, or similar `--with-sysconfig=DIR`. 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`. **Example:** * `/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. Cgroups ------- There are three major cgroup configuration directives: 1. Global top-level group: init, system, user, or a custom group 2. Selecting a top-level group for a set of run/task/services 3. 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 `/sys/fs/cgroup/maint/foo/cpu.max`. There is not 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: > Configuration File Syntax ------------------------- ### Hostname **Syntax:** `host `, or `hostname ` Set system hostname to NAME, unless `/etc/hostname` exists in which case the contents of that file is used. Deprecated. We recommend using `/etc/hostname` instead. > **Note:** only read and executed in runlevel S ([bootstrap][]). ### Kernel Modules **Syntax:** `module [ARGS]` Load a kernel module, with optional arguments. Similar to `insmod` command line tool. Deprecated, there is both a `modules-load.so` and a `modprobe.so` plugin that can handle module loading better. The former supports loading from `/etc/modules-load.d/`, the latter uses kernel modinfo to automatically load (or coldplug) every required module. For hotplug we recommend the BusyBox mdev tool, add to `/etc/mdev.conf`: $MODALIAS=.* root:root 0660 @modprobe -b "$MODALIAS" > **Note:** only read and executed in runlevel S ([bootstrap][]). ### Networking **Syntax:** `network ` Script or program to bring up networking, with optional arguments. Deprecated. We recommend using dedicated task/run stanzas per runlevel, or `/etc/network/interfaces` if you have a system with `ifupdown`, like Debian, Ubuntu, Linux Mint, or an embedded BusyBox system. > **Note:** only read and executed in runlevel S ([bootstrap][]). ### Resource Limits **Syntax:** `rlimit [hard|soft] RESOURCE ` 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. ### Runlevels **Syntax:** `runlevel ` 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. Default: 2 > **Note:** only read and executed in runlevel S ([bootstrap][]). ### One-shot Commands (sequence) **Syntax:** `run [LVLS] /path/to/cmd ARGS -- Optional description` 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. > `` is described in the [Services](#services) section. ### One-shot Commands (parallel) **Syntax:** `task [LVLS] /path/to/cmd ARGS -- Optional description` One-shot like '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 > `` is described in the [Services](#services) section. ### SysV Init Scripts **Syntax:** `sysv [LVLS] /path/to/init-script -- Optional description` Similar to `task` is the `sysv` stanza, which can be used to call SysV style 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 `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: `pid:!/path/to/pidfile.pid`. > `` is described in the [Services](#services) section. ### Services **Syntax:** `service [LVLS] /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 10 times before giving up, then you have to `initctl restart NAME` it manually. 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` syntax. **Example:** In the case of `ospfd` (below), we omit the `-d` flag (daemonize) to prevent it from forking to the background: service [2345] /sbin/ospfd -- OSPF daemon `[2345]` denote the runlevels `ospfd` is allowed to run in, they are optional and default to level 2-5 if omitted. `<...>` 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`, or `*/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` 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(1)` of the service. The default can be modified with an optional `pid:`-argument: 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 ``. > For a detailed description of conditions, and how to debug them, > see the [Finit Conditions](conditions.md) document. If a service should not be automatically started, it can be configured as manual with the optional `manual` argument. The service can then be started at any time by running `initctl start `. manual:yes The name of a service, shown by the `initctl` tool, defaults to the basename of the service executable. It can be changed with the optional `name` argument: name: 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 option `halt:SIGNAL`, e.g., `halt:SIGPWR`. To change the delay between your halt signal and KILL, use the option `kill:SEC`, e.g., `kill:10` to wait 10 seconds before sending `SIGKILL`. Services support `pre:script` and `post:script` 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]`: set to one of `exited` or `signal` - `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 The scripts have a default execution time of 3 seconds before they are SIGKILLed, this can be adjusted using the above `kill:SEC` 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. ### Run-parts Scripts **Syntax:** `runparts ` Call [run-parts(8)][] on `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 runlevel `S`, [bootstrap][]. 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][]). [run-parts(8)]: http://manpages.debian.org/cgi-bin/man.cgi?query=run-parts ### Including Finit Configs **Syntax:** `include ` Include another configuration file. Absolute path required. ### General Logging **Syntax:** `log size:200k count:5` Log rotation for run/task/services using the `log` sub-option 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 `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. ### TTYs and Consoles **Syntax:** `tty [LVLS] DEV [BAUD] [noclear] [nowait] [nologin] [TERM]` `tty [LVLS] CMD [noclear] [nowait]` `tty [LVLS] [notty] [rescue]` The first variant of this option uses the built-in getty on the given TTY device DEV, in the given runlevels. The DEV may be the special keyword `@console`, or `console`, 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 `` before starting a TTY. **Example:** tty [12345] /dev/ttyAMA0 115200 noclear vt220 The second `tty` syntax variant is for using an external getty, like agetty or the BusyBox getty. The third variant 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 (`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. For more information, see the [Rescue Mode](#rescue-mode) section. By default, the first two syntax variants *clear* the TTY and *wait* for the user to press enter before starting getty. **Example:** 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 `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 `` 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. **Example:** 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 ### Non-privileged Services Every `run`, `task`, or `service` can also list the privileges the `/path/to/cmd` should be executed with. Simply prefix the path with `[@USR[:GRP]]` 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. ### Redirecting Output The `run`, `task`, and `service` stanzas also allow the keyword `log` to redirect `stderr` and `stdout` of the application to a file or syslog using the native `logit` tool. This is useful for programs that do not support syslog on their own, which is sometimes the case when running in the foreground. The full syntax is: log:/path/to/file log:prio:facility.level,tag:ident log:console log:null log Default `prio` is `daemon.info` and default `tag` is the basename of the service or run/task command. Log rotation is controlled using the global `log` setting. **Example:** service log:prio:user.warn,tag:ntpd /sbin/ntpd pool.ntp.org -- NTP daemon Rescue Mode ----------- Finit supports a rescue mode which is activated by the `rescue` option on the kernel command line. See [cmdline docs](cmdline.md) for how to activate it. 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 > `"Press enter to enter maintenance mode."`, prompt 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. Limitations ----------- As of Finit v4 there are no limitations to where `.conf` settings can be placed. Except for the system/global `rlimit`, which can only be set from `/etc/finit.conf`, since it is the first `.conf` file Finit reads. Originally, `/etc/finit.conf` 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`. > **Note:** The `/etc/finit.d` directory was previously the default > Finit [runparts](#run-parts-scripts) directory. Finit no > longer has a default `runparts`, make sure to update your > setup, or the finit configuration, accordingly. Watchdog -------- When built `--with-watchdog` a separate service is built and installed in `/libexec/finit/watchdogd`. If this exists at runtime, and the WDT device node exists, Finit will start it and treat it as the elected watchdog service to delegate its reboot to. See [bootstrap][] for details. This delegation is to ensure that the system is rebooted by a hardware watchdog timer -- on many embedded systems this is crucial to ensure all circuits on the board are properly reset for the next boot, in effect ensuring the system works the same after both a power-on and reboot event. The delegation is performed at the very last steps of system shutdown, if reboot has been selected and an elected watchdog is known, first a `SIGPWR` is sent to advise watchdogd of the pending reboot. Then, when the necessary steps of preparing the system for shutdown (umount etc.) are completed, Finit sends `SIGTERM` to watchdogd and puts itself in a 10 sec timeout loop waiting for the WDT to reset the board. If a reset is not done before the timeout, Finit falls back to`reboot(RB_AUTOBOOT)` which tells the kernel to do the reboot. An external watchdog service can also be used. The more advanced cousin [watchdogd](https://github.com/troglobit/watchdogd/) is the recommended option here. It can register itself with Finit using the same IPC as `initctl`. If the bundled watchdogd is running a hand-over takes place, so it's safe to have both services installed on a system. For the hand-over to work it requires that the WDT driver supports the safe exit functionality where `"V"` is written to the device before closing the device descriptor. If the kernel driver has been built without this, the only option is to remove `/libexec/finit/watchdogd` or build without it at configure time. [bootstrap]: bootstrap.md keventd ------- The kernel event daemon bundled with Finit is a simple uevent monitor for `/sys/class/power_supply`. It provides the `sys/pwr/ac` condition, which can be useful to prevent power hungry services like anacron to run when a laptop is only running on battery, for instance. Since keventd is not an integral part of Finit yet it is not enabled by default. Enable it using `./configuure --with-keventd`. The bundled contrib build scripts for Debian, Alpine, and Void have this enabled. This daemon is planned to be extended with monitoring of other uevents, patches and ideas are welcome in the issue tracker.