A service whose condition goes into flux during a reload is paused
with its reload still pending. If another reload was requested in
the meantime, re-parsing its unchanged .conf file cleared the pending
mark, so the service was resumed without ever being reloaded. Seen
with sshd <pid/syslogd> on Infix, where a configuration change that
touched both landed as two reloads in a row and sshd kept its old
listen addresses.
The mark is only ever cleared once the change has been applied, so a
mark that is still set when the file is parsed again means exactly
that: not applied yet. Leave it alone.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Covers the longer user and group names, the tmpfiles mode and owner
work, the shutdown remount order, and the script timeout crash.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Only fall back to the regular mount invocation when both
fstab-independent root remount attempts fail.
This avoids reading an encrypted fstab during a normal shutdown.
Signed-off-by: Anees Rehman <anees.rehman@atlascopco.com>
(cherry picked from commit 263ea929fd)
Service user and group names are stored in 16-byte buffers, limiting
them to 15 characters. This silently truncates longer names before
getpwnam() and getgrnam(), preventing services configured with valid
longer account names from starting.
Increase the buffers to match the existing maximum configuration
argument length.
Signed-off-by: Anees Rehman <anees.rehman@atlascopco.com>
Same treatment as d/D got: e went through fisdir() and a path based
chmod/chown, f/F did the chmod/chown by path after closing the file.
Both now work on the open fd, so the mode and owner end up on the
directory or file that was just checked or written. f/F use open(2)
directly, which lets a plain f rely on O_EXCL for create-if-missing
instead of the earlier stat().
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
makedir() swallows EEXIST, so the chmod branch for directories that
already existed never ran, while chown() ran every time. On finix
/var/empty is immutable, which gave a warning on every boot even
though the owner was already correct.
mksubsys() is the original of this code and has the same shape, the
dbus plugin uses it for /tmp/dbus. Both now go through dirperm(),
which opens the directory and uses fstat/fchmod/fchown on the fd,
changing only what differs. A failed chown in mksubsys() is a warning
now rather than err(1), PID 1 should not exit over a directory it
cannot adjust.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
All workflow runs now warn:
Node.js 20 is deprecated. The following actions target Node.js 20
but are being forced to run on Node.js 24.
Update the actions/* dependencies to their current major versions,
all of which target Node.js 24: checkout v7, upload-artifact v7,
download-artifact v8, setup-python v7, and cache v6. The release
action tracks the floating v1 tag and updates on its own.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
With 5.0 on master, maintenance releases move to a 4.x branch: run
push builds, docs deploy, and weekly distcheck for any N.x branch,
and mark only the highest stable tag as the latest release.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
'make check' refreshes the sysroot through the setup-chroot rule, but
running a test script by hand does not, so the test exercises whichever
finit was installed last and reports on code that is no longer there.
Both a passing and a failing run are then meaningless, and nothing says
so.
Compare the built binary against the installed one at startup and fail
with the command that fixes it.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
A stop: or reload: script written with a timeout killed Finit at
config load:
service stop:5,/bin/true service.sh -- Boom
parse_script() takes the timeout as a pointer and the caller decides
whether it wants one. However, both stop: and reload: scripts so far
have no timeout, i.e., NULL. Guard the branch that reads a leading
number.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Every test left a stray `sleep 300` behind, reparented to PID 1, where
it lingered for up to five minutes after the test had finished.
wdstart() runs the watchdog in a subshell, so $! is the pid of the
subshell, not of the sleep it forks. wdkill() killed the subshell and
orphaned the sleep.
Kill the child first, killing the subshell puts the sleep beyond the
reach of pkill -P. Neither kill is sure to match, and wdkill() runs
from the EXIT trap under set -e, so both must tolerate failure. Also
return early when wdpid is unset, for failures before wdstart() runs.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Finit 5.0 changes the .conf syntax, which has been essentially
unchanged since 1.x. The published docs track master, so when 5.x
lands, 4.x users lose their reference.
Publish the site under a per-major directory, /4.x/ for now, with
the Material version selector to switch between them. The selector
only needs mike's file layout -- a versions.json at the site root --
which the deploy job now generates from the version directories in
the pages repo, so mike itself is not needed.
The major comes from AC_INIT and the future 4.x maintenance branch
is already in the workflow triggers, so once 5.0 is on master, doc
fixes on the 4.x branch keep /4.x/ updated. A root index.html
redirects to the newest version, and a 404.html rewrites
pre-versioned deep links so old bookmarks and search hits land in
the right place.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Both the Finit project and Infix use the same MkDocs Material setup, and
in the latter the User Guide has picked up a lot of polish that never
made it back here: a single sidebar with section indexes instead of
tabs, footnote tooltips, more pymdownx markup, image zoom tuning, and no
generator advert in the footer.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
* 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>
Cover the scenario fixed in "service: clean stale pidfile after
unclean daemon exit": a daemon with a pid:!/path config dies via
SIGKILL, leaving its pidfile behind, and the next instance must
still come up.
Add a 'serv -x' flag (refuse to start when the pidfile already
exists, dbus-style) so the test actually exercises the cleanup --
without it, plain 'serv' would happily overwrite the file and the
test would pass with or without the fix.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The fallback for unknown signal numbers in sig_name() returned the
misspelled "SIGUNKOWN". Now that this string surfaces in user-
facing logs ("killed by …"), fix the typo.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Replace the bare signal number ("by signal: 9") with the symbolic
name ("killed by SIGKILL") and annotate when the kernel wrote a
core:("killed by SIGSEGV, core dumped"). Makes the restart line
self-explanatory and gives operators a strong breadcrumb when a
daemon dies unexpectedly.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
With `pid:!/path` Finit does not manage the file -- the daemon
creates it on start and removes it on graceful exit. If the daemon
dies before cleanup (SIGKILL, OOM, segfault, exit during startup)
the file lingers and can block the next instance from starting,
e.g. dbus-daemon refuses with EEXIST and the restart loop fails.
Remove the file when it still names the just-reaped PID and that
PID is no longer alive (the liveness check guards against reuse).
Called from service_cleanup(), and from service_monitor()'s
forking+starting branch where cleanup was previously skipped.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
status() returns a pointer to a single static buffer, so calling it twice
in the same cprintf() argument list — status(3) and status(rc) — causes
one to overwrite the other before the format string is rendered. When
status(3) wins, the line shows [ ⋯ ] instead of [ OK ]. Fix by copying
status(rc) into a local buffer before calling status(3).
Also drop the delline() calls added to print() — that macro writes \033[2K
to buffered stdout while cprintf() writes unbuffered to stderr, so the
erase sequences can arrive out of order. The \r\e[K already present in
the cprintf format strings makes them redundant anyway.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Check return value of remove() in delete_cb() and log failures via
dbg(), CID 909395
Replace stat() calls with open(O_DIRECTORY)+ fstat() for newroot and "/"
checks. Eliminates the check-then-use race and lets O_DIRECTORY do the
isdir validation atomically, CID 909394
Drop the explicit close(0/1/2) before opening /dev/console. dup2()
closes the old targets itself, so open() returns a fd > STDERR_FILENO
that can always be closed unconditionally, removing the conditional
guard, CID 909393
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Refactor print() to emit description + final status in a single call to
cprintf(), preventing kernel messages from splitting the two parts.
For two-phase print(-1,...) + print_result() sequences used by, e.g.,
run_interactive, save the last description and re-print it before the
[ OK ] / [FAIL] output so the status is never left stranded on a blank
line when command output or kernel messages have scrolled away the
original description.
Finally, add print_exit() which drains the console output buffer with
tcdrain(2) and resets ANSI SGR attributes + cursor visibility before the
kernel takes back the console on reboot/halt, preventing escape code
leakage into bootloader or early-kernel output.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
When a service without SIGHUP reload support (noreload) is touched and
'initctl reload' is called, service_update_rdeps() correctly identifies
its reverse dependencies but only marks them dirty. It does not clear
the service's condition, so when service_step_all() runs:
- rdeps supporting SIGHUP hit the sm_in_reload() guard and break early,
left running while their dependency is being killed.
- rdeps without SIGHUP support may receive SIGTERM too late, after the
dependency has already died and broken their connection, causing them
to exit from RUNNING state and have their restart counter incremented.
Fix by calling cond_clear() on the service's condition immediately in
service_update_rdeps(), before service_step_all() runs. cond_clear()
calls cond_update() which calls service_step() inline on all affected
services, which see COND_OFF and transition to STOPPING_STATE — all
before SIGTERM is ever sent to the dependency itself.
This mirrors the pattern already used in api.c:do_reload() for direct
'initctl reload <svc>' calls.
Fixes: avahi/mdns stop causing mdns-alias restart counter increment
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Add support for the --exclude-prefix=PATH option to skip rules whose
path starts with the specified prefix. The option can be specified
multiple times to exclude multiple path prefixes.
The -E flag is a shortcut for:
--exclude-prefix=/dev --exclude-prefix=/proc \
--exclude-prefix=/run --exclude-prefix=/sys
This is useful to avoid creating files below virtual or memory-backed
file system mount points.
devmon: assert condition immediately if device already exists
1. udev fires early, creates device nodes in /dev/
2. Config is parsed later, calling devmon_add_cond() for each dev/ condition
3. At this point the device already exists but the inotify event was missed
4. The PR's fexist() check catches this — new node is added to the TAILQ and condition is immediately asserted
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The config parsing happens after udev triggers the initial event,
make sure to assert the condition if the device node exists when adding
it from configuration.
Signed-off-by: Mattias Walström <lazzer@gmail.com>
A service that is reloaded should not trigger dependants to be reloaded
unless the new <~cond> is used. Which is reserve for tightly coupled
services.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>