doc: document stale pidfile cleanup and new restart log

* src/pid.c: note the stale-pidfile-cleanup exception to the
  documented "Finit does not touch pid:! pidfiles" rule.
* doc/config/services.md: add a user-facing paragraph on the same.
* doc/ChangeLog.md: add Unreleased section covering this PR --
  stale pidfile cleanup, restart log with signal name and core
  dump flag, and the SIGUNKOWN typo fix.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg committed 2026-05-12 10:11:50 +02:00
1 parent 3febc7d513
commit 7d09e34b80
3 files changed
+37 -1

No files matched your search

+25
View File
@@ -3,6 +3,31 @@ Change Log
All relevant changes are documented in this file.
[Unreleased]
------------
### Changes
- 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
stronger breadcrumb when a daemon dies unexpectedly
### Fixes
- 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
starting -- `dbus-daemon` for example refuses to start when its
pidfile already exists, so Finit's restart loop gives up. Finit now
drops the file when it still names the just-reaped PID and that PID
is no longer alive (the liveness check guards against PID reuse).
This is a controlled exception to the long-standing rule that Finit
does not touch service-owned pidfiles
- Fix misspelled `SIGUNKOWN` returned by `sig_name()` for unknown
signal numbers, now spelled correctly as `SIGUNKNOWN`. Surfaced by
the new restart log above
[4.17][] - 2026-04-28
---------------------
+8
View File
@@ -31,6 +31,14 @@ 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`.
With `pid:!/path`, the file belongs to the service: Finit reads it
but does not create or remove it. The one exception is *stale*
cleanup — if the service dies without removing its own pidfile
(SIGKILL, OOM, segfault), and the file still names the just-reaped
PID, Finit removes it before the next retry. This prevents daemons
that refuse to start on an existing pidfile (e.g. `dbus-daemon`)
from getting stuck in a crash-restart loop.
**Example:**
In the case of `ospfd` (below), we omit the `-d` flag (daemonize) to
+4 -1
View File
@@ -201,7 +201,10 @@ int pid_file_set(svc_t *svc, char *file, int not)
* pid:!foo --> !/run/foo.pid
* pid:!/run/foo.pid --> !/run/foo.pid
*
* Note, nothing is created or removed by Finit in this latter form.
* Nothing is created or removed by Finit in this latter form, with one
* exception: a verifiably stale pidfile (still names the just-reaped
* PID, and that PID is no longer alive) is removed so the next instance
* can start. See service_clean_pidfile() in src/service.c.
*/
int pid_file_parse(svc_t *svc, char *arg)
{