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 stop/reload script timeout.
Signed-off-by: Joachim Wiberg <troglobit@gmail.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>
(cherry picked from commit 75739fbeef)
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>
(cherry picked from commit 3a72d1263c)
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>
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>
Apply a PAM session to run/task/sysv/services Finit starts, pam_limits
above all, so a service running as a given user picks up that user's
limits the way a login does.
Add a new `pam` setting for the new block format (only), like the
per-service directories, naming a file in /etc/pam.d:
service weston {
user = "weston"
pam = "weston-autologin"
command = "/usr/bin/weston --continue-without-input"
}
pam_close_session() has to be called by a process still holding the
handle, and the handle does not survive exec(). Hence the keeper: it
holds the handle, drops to the service's credentials, and waits for a
parent-death signal before closing the session. Same shape as
systemd's (sd-pam), for the same reason, and one per fork, so the
script hooks open and close their own.
The keeper closes the descriptors it inherited from Finit and only
those. Closing everything would also take out what pam_open_session()
opened for itself, a keyring fd or a lock file, and leave the modules
to close a session with those pulled out from under them. Closing
nothing, as (sd-pam) does, would leave it holding the write end of the
notify pipe for the service's whole lifetime and starve notify = "s6"
services of their ready signal. So the fds open before pam_start()
are snapshotted and exactly those are closed, while the ones PAM opens
after are marked close-on-exec so the daemon does not inherit them
either.
A refused value, a denied account stack, an uninstalled pam.d file,
and a build without PAM support all keep the service from starting
rather than running it with the stacks skipped: one that quietly loses
pam_limits and its private /tmp, with nothing said. Capabilities a
module like pam_cap.so granted are merged into the IAB Finit applies
instead of being replaced by it, which only helps a service that also
sets capabilities, the other arm being a plain setuid() with nothing
left to restore once permitted is empty.
The test sysroot gains pam_permit.so, pam_deny.so and pam_limits.so,
which ldd cannot see, libpam dlopen()s them, and the test skips when
the host has none to stage. The negative cases pin the exit status
rather than only asserting crashed, which serv reports for any early
exit, so a bad command or an unwritable pidfile cannot pass for a
rejected session.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The ChangeLog is hard-wrapped at 72 columns, which the GitHub releases
page renders verbatim as a ragged right edge. Join the continuation
lines of each paragraph and list item, as already done in Infix, and
let the browser do the wrapping.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
GitHub now shows a sha256 digest for every uploaded release asset, so
the sidecar hash files only clutter the asset list.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Building it by default installs our libsystemd.so.0 in $libdir. Where
the real one is already present, and contrib/debian/build.sh configures
--prefix=/usr --exec-prefix= on a Debian host, ours outranks it in the
loader cache, and every program linking libsystemd loses
sd_journal_stream_fd and the LIBSYSTEMD_209 symbol versions. The test
sysroot ran into exactly that, dbus-daemon exited 127 on every restart.
Restore the default to no. sulogin and watchdogd stay on, they only add
binaries. distcheck asks for the library so it stays covered.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
dbus-broker fails, the bus never comes up:
Service dbus[19] died (exit status: 127), restarting
The sysroot stages dbus-daemon from the host, which links the real
libsystemd, and since v5.0 builds ours by default the install puts a
second libsystemd.so.0 in the sysroot. It wins the ld.so cache, and
dbus-daemon finds neither sd_journal_stream_fd nor the LIBSYSTEMD_209
symbol versions in it.
Uninstall the library from the sysroot after the install. The test serv
compiles sd-daemon.c in, so nothing there needs it.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
v5.0 ships keventd and the D-Bus support enabled out of the box, but the
remaining bundled pieces stayed opt-in, and the help text for two of them
already claimed otherwise.
Default all three to yes; --without-sulogin, --without-watchdog, and
--without-libsystemd opt out. The distcheck and CI configure lines drop
the flags they no longer need, so CI exercises the defaults.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
make distcheck fails in install:
/usr/bin/install: cannot create regular file '/etc/dbus-1/system.d/org.finit.conf': Permission denied
The policy was installed to $sysconfdir/dbus-1/system.d. distcheck only
overrides the prefix, so the file escaped its sandbox and aimed for the
real /etc.
Install it where dbus looks for package owned policy, leaving
/etc/dbus-1/system.d to the admin. The test bus config reads it
relative to itself.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
fuzz-msg-parse.sh looked for its driver next to the script, which only
holds when srcdir and builddir are the same. Every VPATH build skipped
the sweep, claiming D-Bus was off:
SKIP: fuzz-msg-parse.sh
distcheck, and with it the release job, is a VPATH build. Use
top_builddir, which the test environment already exports.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
make distcheck fails in dbus-device:
sh: /libexec/finit/keventd: not found
distcheck configures with --prefix=$(distdir)/_inst, so the bundled
helpers install below that prefix, not in /libexec/finit, which the test
had hard coded.
Export the configured pkglibexecdir as FINIT_EXECPATH in test.env and
run keventd from there, the same path finit itself is built with.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The engine covers most of the udev grammar but not all of it, and the
gaps are invisible until a rule silently does nothing. Write down what
is implemented and where it parts ways with udev(7), rather than
leaving people to infer it from a ruleset that happens to work. The
man page gets the directory precedence and a pointer to udev(7) and
the User's Guide, which hold the details.
Rename the menu entry to Device Manager while here, matching how the
watchdog daemon is listed.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The rules directories were read one after the other, each sorted on
its own. udev instead sorts all files from all directories together
and lets a file mask one of the same name in a lower priority
directory. The difference broke both standard override idioms
without a sound: copying a rules file to /etc/udev/rules.d/ to edit
it left the original running too, and symlinking a name to /dev/null
disabled nothing.
Collect everything with glob(), drop entries shadowed by a later
directory, and sort the survivors by filename, same as udev and the
tmpfiles.d handling in Finit itself. The -r directory sits above
/etc/ so a test ruleset can override anything shipped.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Two races, both around the post:script Finit runs when it gives up on a
service.
Finit marks the service crashed before it forks post:script, so the file
the test greps for lands a moment later. Waiting for the state is not
enough.
slay then takes the PID from initctl status, and service_post_script()
sets svc->pid to the script's PID, so once Finit has given up the PID
reported for the service is the post:script. Killing that takes out the
script instead of the service and the file never arrives at all. The
guard for this was already there, with a comment describing it, but
inside the loop that waits for a PID to appear, so it only covered the
case where there was none. A PID that was already there went straight
to kill -9. Hence the gcc leg killing once more at lap 13, after Finit
had stopped restarting, where clang stopped at 12.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Stanzas in /lib/finit/system cannot use if:keventd, or any other
built-in service: if: is evaluated at parse time, and the generated
.conf files for built-ins were read after the system directory, so the
referenced service did not exist yet and the stanza was dropped.
The late position was deliberate: it kept bundled services from starting
before udev (5d703fd3). The motivating case was dbus, which has since
moved to a build-time 20-dbus.conf (2e0b1d6f), and the built-ins that
remain want the early slot: watchdogd should start as soon as possible,
keventd is the device manager, and runparts is gated on int/bootstrap so
its position never mattered.
Reading /run/finit/system first also puts the override chain in its
natural order: built-in/generated defaults, then bundled (read-only)
system files in /lib, then the administrator (override) .conf file in
/etc/finit.d, always read last.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
A failed move of /dev, /proc, /sys or /run is logged at dbg() level
and ignored, so the new init boots without its virtual filesystems
and falls over much later in some unrelated way. The steps after,
chdir/mount/chroot and the final execl(), do return -1 on failure,
but by then all services are dead and the API socket is gone, so
there is nobody left to report to: the system hangs with a live but
useless PID 1.
Make a failed move fatal, and try all four moves even if one fails,
so a bad /dev does not also skip /proc, /sys and /run. A plain
directory is not an error though: /run stays a plain directory on a
tmpfs rootfs, so only a path on a different device than / is treated
as a mount point and moved.
Any failure past the point of no return now drops to sulogin(1) for
a maintenance shell that reboots on exit, same as a fatal fsck() at
boot. Signals are unblocked before the moves so the shell does not
inherit finit's blocked signal mask.
Signed-off-by: Paweł Sobczak <github@fixeq.qzz.io>
The precheck accepts a directory as new init: access(path, X_OK)
only checks search permission, which directories almost always have,
so the mistake is not caught until after teardown. The snprintf()
building init_path also never checks for truncation, so an overlong
newroot + newinit validates the wrong path.
Require a regular file, with EISDIR or ENOEXEC to match what is
printed, and fail with ENAMETOOLONG on a truncated init path.
Signed-off-by: Paweł Sobczak <github@fixeq.qzz.io>
initctl switch-root always exits 0, no matter what happens on the
finit side. do_switch_root_api() sends the ACK before switch_root()
has validated anything, so any failure after that point never reaches
the client -- the error only shows up in the log. The runlevel guard
in api_cb() has the same problem: it rejects the request but still
sends an ACK.
Split the validation out of switch_root() into switch_root_precheck()
and run it before the ACK. A failed check now sends a NACK with the
error message, which initctl prints before exiting 1:
initctl switch-root /mnt
switch-root: /mnt is not a mount point
The ACK is only sent once the precheck passes, since after that point
we are committed. On success finit execs the new init and the
connection dies with no reply at all, so initctl treats only an
explicit NACK as failure.
Signed-off-by: Paweł Sobczak <github@fixeq.qzz.io>
Half the daemon was missing: -p, -r, -S, -t from SYNOPSIS and
OPTIONS, class/ and driver/ conditions, SIGHUP rules reload, the
rules engine and its directories, /run/udev/data, and the D-Bus
socket in FILES.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Three copies of read-first-line-from-a-file (sysfs_read_file, a
static sysfs_read, fgetline), two condition emitters symlinking the
same reconf marker (cond_emit, sys_cond), two seqnum-stable loops,
and five hand-rolled logit() prototypes, none with a printf
attribute, so no format string was ever checked.
Keep one of each: cond_emit() is exported and mkpaths its parents,
which also retires init_dev_condition_dir() and the sys/ directory
priming loop; logit() moves to keventd.h with the format attribute;
the stability test becomes seqnum_stable(), shared by the coldplug
gate and settle; kev_now_ms() serves dbus.c too. rule_ctx_free()
and kev_seq_baseline() had one caller each in their own files, now
static.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
initctl reload freezes conditions to the old generation and each
owner re-asserts. Finit's own providers do this in-process; an
external provider whose conditions are generation files, rather than
the oneshot symlinks keventd uses, has no way to know the moment.
Emit Manager1.ConfigReloaded when reconfiguration completes.
keventd needs no subscriber: its conditions are symlinks to the
reconf marker itself, so they read the current generation by
construction and never flux, which the device bus test now pins
down.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Introspection, queue-state properties, immediate and bus-first
settle, Info by devpath, Trigger(add, net) observed via the
DeviceProcessed signal, and RulesReload -- driven by dummy interface
hotplug like keventd.sh. New call-ss and call-u client modes, and
getprop learns the b and t variants.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The udev parity gaps that were blocked on IPC -- settle, trigger,
info, queue introspection, runtime rule reload -- become bus methods.
keventd serves its own socket the way Finit serves /run/finit/bus:
brokerless, libink, one socket per daemon, no forwarding between the
two.
Settle(u) -> b parked until the queue drains or the timeout
passes; true when settled
Trigger(s, s) replay events, action + subsystem glob
Info(s) -> a{ss} /run/udev/data properties for a devpath
RulesReload() -> u re-read rules dirs, returns rule count
QueueEmpty (b), SeqnumProcessed (t) properties
DeviceProcessed (ss) signal after each fully handled event
The queue state is the highest kernel seqnum keventd has handled,
baselined at startup, against /sys/kernel/uevent_seqnum. keventd -S
now asks the running daemon first and falls back to seqnum polling.
In passive mode Trigger and RulesReload refuse. Adds
link_call_connection() for the park bookkeeping.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
udevdb_read_parent() contained the general capability, keyed from
sysfs when no uevent is in hand. Split it out as
udevdb_read_devpath() for the D-Bus Info method; parent lookup
becomes a wrapper.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
coldplug_trigger(action, subsystem-glob) replays events for a subset
of devices, the D-Bus Trigger method needs both knobs; coldplug() is
now the ("add", NULL) case. nftw() has no user cookie, so the
parameters ride in file statics.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The park machinery was welded to broker uid resolution; a handler
that cannot answer yet, like a device-settle call waiting for the
event queue to drain, had no way to defer. link_call_park() holds
the request, link_call_resume() re-runs the handler with
link_call_resumed() reading true, and the expire sweep remains the
backstop for a resume that never comes.
Resume also no longer drops a local caller's kernel group set in the
privileged re-check: group source now keys on broker-ness.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Device seqnums are 64-bit; the writer and reader stopped at u32.
Adds t/x/d to the skip path so a{sv} consumers tolerate them.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
dbus.md was orphaned: not in dist_docs_DATA, not linked from the
user guide. Wire it into the doc dist and link it from the index
features list, features.md, initctl.md, and plugins.md, where the
dbus.so plugin entry now disambiguates the external system bus from
the built-in org.finit API.
Document the 64-peer cap, the supported AddMatch keys, the busconfig
policy file, the legacy-parity edge semantics with the deliberate
SetRunlevel InvalidArgs divergence, the reload-signal behavior of
Service1.Reload, and the reboot family timeout. Refresh the stale
initctl.md usage paste, add monitor and the D-Bus transport to
initctl(8), add /run/finit/bus to the filesystem layout, and flatten
the ChangeLog D-Bus entry to house style.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The D-Bus support is default-enabled, so the HAVE_DBUS paths only
bit-rot silently without this: the leg caught initctl failing to
build with --disable-dbus on its first local run. Also asserts the
binaries carry no bus references and smoke-runs one non-dbus test.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
initctl_CPPFLAGS is only assigned under the DBUS conditional, but an
automake per-target variable exists even when its conditional is
false, so a --disable-dbus build dropped AM_CPPFLAGS entirely:
util.c:319:16: error: invalid use of undefined type 'struct FTW'
Assign the base flags unconditionally and append under DBUS.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The path encoding in libink/path.c was untested for identities with
separators; dbus-service.sh only used the bare keventd identity.
Declare a dhcp-client:eth1 service and verify the escaped path, that
the object introspects, and that Identity round-trips.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
All three org.finit signals were invisible to generated proxies, and
org.freedesktop.DBus was missing from the standard interfaces even
though Hello, AddMatch, and RemoveMatch are answered.
Add a link_signal_t table to the vtable, emitted like methods and
properties, declare the Manager1 and Cond1 signals, and complete the
static XML with PropertiesChanged and org.freedesktop.DBus.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The D-Bus methods carried byte-for-byte copies of api.c's static
start/stop/restart helpers. Promote them to service.c alongside
service_reload(), which already serves both callers, and reduce both
sides to svc_parse_jobstr-style adapters.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Regression tests for the recent handler fixes: bogus SetRunlevel is
InvalidArgs, Signal on a stopped service is Failed, and the reboot
family declares the timeout argument. Reboot cannot be invoked
without taking down the sandbox, so the latter is asserted via
introspection. New call-u and call-su modes in dbus-auth-client.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
initctl -t N reboot arms an emergency bypass timer over the legacy
socket, but the bus methods took no argument, so the timeout was
silently dropped whenever D-Bus was up.
Reboot, Halt, and Poweroff now take a timeout in seconds, 0 for
none, armed via the same shutdown_bypass() the legacy path uses.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>