diff --git a/doc/ChangeLog.md b/doc/ChangeLog.md index 35c61552..e7ae2f06 100644 --- a/doc/ChangeLog.md +++ b/doc/ChangeLog.md @@ -8,6 +8,10 @@ All relevant changes are documented in this file. ### Changes +- The `command` setting in a block takes a list of candidates for the + same service, `command = { "/lib/systemd/systemd-udevd", "-udevd" }`, + and Finit starts the first one it finds. The line-based format could + only express this by repeating the whole stanza per candidate - Restart log now spells out the signal name and flags core dumps, e.g. `killed by SIGKILL` or `killed by SIGSEGV, core dumped`, in place of the bare numeric `by signal: N`. Gives operators a much @@ -15,6 +19,13 @@ All relevant changes are documented in this file. ### Fixes +- Reject a .conf file that declares the same block title twice. The + title is the service identity and libConfuse merges two sections + sharing one, so the file loaded as a single service holding a mix of + both declarations, silently. This hit `system/10-hotplug.conf`, + where the two `udevd` blocks left only the second command, dropping + the service on systems that only have `systemd-udevd`. The same + title in another file is still how a system .conf is overridden - Remove stale daemon-owned (`pid:!`) pidfiles after unclean exits. When a daemon dies via SIGKILL/OOM/segfault, or exits early during startup, its pidfile lingers and can prevent the next instance from diff --git a/doc/build.md b/doc/build.md index ae25f7b8..65bf5365 100644 --- a/doc/build.md +++ b/doc/build.md @@ -2,10 +2,11 @@ Building Finit ============== Finit comes with a traditional configure script to control features and -optional plugins to enable. It depends on two external libraries: +optional plugins to enable. It depends on three external libraries: - [libuEv][], the event loop - [libite][] (-lite), much needed frog DNA +- [libConfuse][], the parser behind the .conf format > [!IMPORTANT] > Most free/open source software packages that use `configure` default @@ -22,6 +23,7 @@ version of the above mentioned libraries. Currently required versions: - libite v2.2.0, or later - libuEv v2.2.0, or later +- libConfuse v3.3, or later Configure @@ -193,3 +195,4 @@ it only for debugging start up issues when Finit crashes. [1]: https://github.com/finit-project/finit/releases/download/4.3/finit-4.3.tar.gz [libuEv]: https://github.com/troglobit/libuev [libite]: https://github.com/troglobit/libite +[libConfuse]: https://github.com/libconfuse/libconfuse diff --git a/doc/config/migration.md b/doc/config/migration.md index 30c24be4..57060793 100644 --- a/doc/config/migration.md +++ b/doc/config/migration.md @@ -82,6 +82,63 @@ Service options | `nowarn` | leading `-` on `command` or `envfile` | | `restarttmo:` | dropped, was already an alias for `restart_sec:` | +Repeated stanzas +---------------- + +The line-based format has no titles, so the same service could be +declared more than once and Finit would sort out which line applied. +A block title *is* the identity, and two blocks sharing one in the +same file are rejected. The two shapes that relied on the repetition +convert differently. + +**Several candidate binaries for one service.** The daemon is known +under more than one name and the stanzas were repeated once per name, +each with `nowarn` so the ones that were not installed were skipped: + + service nowarn pid:!/run/udevd.pid [S12345789] /lib/systemd/systemd-udevd -- Device event daemon + service nowarn pid:!/run/udevd.pid [S12345789] udevd -- Device event daemon + +The candidates now go in one block, and Finit starts the first one it +finds: + + service udevd { + description = "Device event daemon" + runlevel = "S12345789" + pidfile = "/run/udevd.pid" + command = { "/lib/systemd/systemd-udevd", "-udevd" } + } + +**One service gated differently per platform.** The command is the +same every time, only `if:` and the conditions differ, e.g. a syslog +daemon that has to wait for whichever hotplug daemon the system has: + + service if:udevd nowarn env:-/etc/default/sysklogd \ + [S0123456789] syslogd -F $SYSLOGD_ARGS -- System log daemon + service if:mdev nowarn env:-/etc/default/sysklogd \ + [S0123456789] syslogd -F $SYSLOGD_ARGS -- System log daemon + +All of these are one service, `syslogd`, providing one `pid/syslogd` +barrier for everything downstream, so they cannot be given separate +titles without renaming that barrier. There are two ways to keep the +identity: + + * put each variant in its own .conf file, since the ban on duplicate + titles is per file, or + * leave this one file in the line-based format, which Finit still + reads. Format is detected per file, so the rest of the system can + be block format. + +A single variant converts the way anything else does: + + service syslogd { + description = "System log daemon" + runlevel = "S0123456789" + if = "udevd" + conditions = { "run/udevadm:5/success" } + envfile = "-/etc/default/sysklogd" + command = "-syslogd -F $SYSLOGD_ARGS" + } + Cgroups ------- @@ -170,8 +227,11 @@ Worth knowing exactly like its legacy counterpart. * A list cannot hold comments; the lexer reads entries after a `#` regardless. Put commented-out candidates above the list. - * `$VAR` in a value is expanded when the file is read, against - Finit's environment. An unset variable expands to nothing. + * `${VAR}` in a value is expanded when the file is read, against + Finit's environment, and `${VAR:-default}` works too. An unset + variable expands to nothing. A plain `$VAR` is left alone and + reaches the service, which is what keeps `command = "syslogd -F + $SYSLOGD_ARGS"` working with an `envfile`. * New settings only appear in the block format. The first are the [per-service directories](service-opts.md#service-directories), `runtime-dir` and friends. diff --git a/doc/config/service-opts.md b/doc/config/service-opts.md index 2eeb8b56..af97384e 100644 --- a/doc/config/service-opts.md +++ b/doc/config/service-opts.md @@ -61,6 +61,58 @@ Other run/task/service settings are: * a leading `-` on `command` -- see [Conditional Loading](services.md#conditional-loading) +Command Candidates +------------------ + +The `command` setting may list several candidates for the same +service, in which case Finit starts the first one it finds: + + service udevd { + command = { "/lib/systemd/systemd-udevd", "-udevd" } + } + +A candidate that is not installed is skipped without a warning, that +is the point of listing more than one. The leading `-` is read from +the candidate that wins, or from the last one when none are found, so +a block with a single command behaves as it always has. + +The candidates are alternative spellings of one service, not a +fallback for a service that fails to start. Finit chooses when the +.conf file is read and does not revisit the choice. + +A [`tty`](tty.md) block takes the same list, where the candidates are +the getty to run: + + tty ttyAMA0 { + command = { "/sbin/agetty -L ttyAMA0 115200 vt100", + "/sbin/getty -L 115200 /dev/ttyAMA0 vt100" } + } + +Duplicate Titles +---------------- + +The title is the service identity, so two blocks sharing a title in +one file are two declarations of one service. The parser underneath +merges them without a word, leaving a single service holding a mix of +both, so Finit rejects the file and names the title: + + /etc/finit.d/hotplug.conf:12: found duplicate title 'udevd' + +Nothing from a rejected file is loaded and the rest of the +configuration is unaffected. + +The same title in *another* file is fine. That is how a system .conf +is overridden, the later file wins, see [Files & Layout](files.md). + +Two shapes need a single identity and used to be written as repeated +declarations. One is a service with several candidate binaries, which +is now a [command list](#command-candidates). The other is a service +gated differently per platform, e.g. a syslog daemon waiting for +whichever hotplug daemon the system happens to have. For that one, +give each variant its own file, or keep them as one-liners in the +line-based format, which has no titles. The [migration +guide](migration.md) works through it. + Restarting ---------- diff --git a/doc/config/services.md b/doc/config/services.md index 570a94f7..1e242f0e 100644 --- a/doc/config/services.md +++ b/doc/config/services.md @@ -226,23 +226,26 @@ Finit supports conditional loading of blocks. The following example is taken from the `system/10-hotplug.conf` file in the Finit distribution. Here we only show a simplified subset. -Starting with the leading `-` on `command`. +Starting with the udev daemon, which goes by two names depending on +how it was built. Both are candidates for the same service: service udevd { pidfile = "udevd" - command = "-/lib/systemd/systemd-udevd" - } - - service udevd { - pidfile = "udevd" - command = "-udevd" + command = { "/lib/systemd/systemd-udevd", "-udevd" } } When loading the .conf file Finit looks for -`/lib/systemd/systemd-udevd`, and if that is not found it logs a -warning. The leading `-` says a missing binary is expected here, so -the block is skipped quietly and the second one can be evaluated, -which also provides a service named `udevd`. +`/lib/systemd/systemd-udevd`, and if that is not there it moves on to +`udevd`. A candidate that is not installed is expected, so no warning +is logged for the ones that are skipped. The leading `-` on the last +one says it is also fine if none of them are found, in which case the +block is dropped quietly and no service named `udevd` exists. + +> [!NOTE] +> This needs to be one block. The title is the service identity, so +> two blocks titled `udevd` in the same file are two declarations of +> one service, which Finit rejects. See [Duplicate +> titles](service-opts.md#duplicate-titles). run udevadm:1 { runlevel = "S" diff --git a/doc/config/tty.md b/doc/config/tty.md index 945c5f2a..138a7b81 100644 --- a/doc/config/tty.md +++ b/doc/config/tty.md @@ -11,6 +11,10 @@ may be the special keyword `@console`, expanded from `/sys/class/tty/console/active`, useful on embedded systems. `command` hands the TTY to an external getty. `notty` opens nothing at all. +`command` may name several candidates, `{ "agetty ...", "getty ..." }`, +and Finit runs the first one it finds. See [Command +Candidates](service-opts.md#command-candidates). + Settings common to all three: | Setting | Alias | Description |