When reloading a specific service with 'initctl reload foo', the
pid/foo and service/foo/ready conditions were never cleared, so
dependent services were not notified of the reload.
Clear the service's pid condition and, for pid/none notify types,
the ready condition before reloading. The conditions are then
reasserted by the pidfile inotify handler when the service touches
its PID file after processing SIGHUP.
For s6/systemd services the ready condition is left intact since
their readiness notification may not re-trigger on SIGHUP.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Users starting Finit based systems using U-Boot or Barebox may otherwise
not get a visible cursor at their prompt.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Similar to systemd's RemainAfterExit=yes. Prevents the task from
re-running on runlevel re-entry and ensures the post: script runs
when explicitly stopped or when leaving valid runlevels.
Useful for tasks that set up persistent state like firewall rules:
task [2345] remain:yes \
post:/usr/sbin/teardown-firewall \
/usr/sbin/setup-firewall -- Firewall setup
Not supported for bootstrap-only tasks (runlevel S only) since these
are deleted immediately after completion.
Define __NR_clone3 (435) ourselves when not provided by the toolchain
headers. The syscall number is stable kernel ABI and the same on all
architectures since Linux 5.3.
The existing runtime fallback to fork() handles older kernels that don't
support the syscall.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
In containerized or virtualized environments, standard mount point
directories may not exist at boot. Ensure they are created before
attempting to mount.
When f or F types write content to a file, the mode and ownership
specified in the config should be applied. Previously, ownership was
only applied when create() was used (i.e., when no argument was
specified).
Now we explicitly apply mode and ownership after writing content to
the file.
According to tmpfiles.d(5), the 'e' type adjusts the mode and ownership
of existing paths but should not create them. Previously, mksubsys()
was used which could create directories.
Now we explicitly check if the path is an existing directory before
adjusting its permissions.
Add parse_uid() and parse_gid() helper functions that support both
numeric IDs and name lookups. Update the d/D directory creation
handlers to use these new functions.
This allows config files to specify ownership using numeric UIDs and
GIDs instead of only usernames and group names, matching systemd-tmpfiles
behavior.
The L+ type should replace existing entries with a symlink. Previously,
rmrf() was always called which is only appropriate for directories.
Now we check if the path is a directory first, and use erase() for
files and symlinks.
Allow specifying one or more configuration files as command line
arguments instead of always processing all files in the standard
tmpfiles.d directories.
This enables targeted operations on specific config files:
tmpfiles --create /etc/tmpfiles.d/myapp.conf
tmpfiles --clean /tmp/test.conf /tmp/other.conf
When no config files are specified, the existing behavior of
processing all *.conf files in the standard directories is preserved.
Also refactors file processing into a helper function to reduce
code duplication.
Add support for the --clean (-C) flag to remove files and directories
older than the age specified in tmpfiles.d configuration entries.
The age field (6th column) in tmpfiles.d entries can now be used with
'd', 'D', and 'e' type entries to clean up old files. Supported time
suffixes are: s (seconds), m (minutes), h (hours), d (days), w (weeks).
Example configuration:
d /tmp/cache 0755 root root 10d
When run with --clean, files in /tmp/cache older than 10 days will be
removed. The directory itself is preserved.
Uses a conservative cleanup approach matching systemd-tmpfiles:
- Files: kept if ANY of atime, ctime, mtime is recent
- Directories: kept if ANY of atime, mtime is recent (ctime excluded
because cleanup itself updates directory ctime)
A value of "-" or "0" for age disables cleanup for that entry.
Note: x/X exclusion patterns are recognized but not yet implemented.
Strings like command, description, and environment may contain characters
that need escaping for valid JSON, e.g., embedded quotes in command line
arguments like -V "NanoPi R2S".
Add json_escape() helper to handle quotes, backslashes, and control chars.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The netlink plugin only receives RTM_NEWLINK events for interfaces that
appear after the plugin starts. Interfaces that already exist at boot
(e.g., virtio-net in QEMU) never generate events, so their conditions
like net/eth0/exist were never set.
Moving enumeration to PLUGIN_INIT doesn't work because it runs before
cond_init(), so the condition filesystem isn't ready yet.
Fix by registering an HOOK_SVC_PLUGIN callback that queries existing
interfaces and routes. This hook runs during conf_init(), after the
condition system is initialized.
When a TTY exited with non-zero code (e.g., user with shell=/sbin/false),
it would enter restart state but never recover, requiring manual restart.
The throttling logic from commit f0032ab had two issues:
1. Duplicate exit code check in service_retry() created infinite timer loop
2. TTYs lacked default restart_tmo, causing timer to never start
Fix by removing duplicate check and ensuring TTYs get a 2-second default
restart_tmo for proper throttling.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
When a service is configured to run as a non-root user (@user), finit
correctly drops privileges via setuid() and sets HOME and PATH, but
does not set the USER and LOGNAME environment variables. They remain
set to "root" from boot time.
This causes problems for software that determines its identity from
the environment rather than getuid(). For example, rootless Podman
checks os.Getenv("USER") first when looking up subordinate UID/GID
ranges in /etc/subuid and /etc/subgid.
With USER=root but UID=1000, Podman looks up root's subuid entry
instead of the actual user's, causing applications like newuidmap
to fail. Setting USER and LOGNAME to match the actual user identity
follows POSIX conventions and matches the behavior of su, sudo, and
login.
The do_ prefix is conventionally reserved for local helper functions.
Move switch_root() declaration to private.h alongside iterate_proc()
and remove the now-empty initramfs.h header.
in an initramfs, then transition to the real root filesystem. Useful
for systems requiring early boot tasks like LUKS unlock, LVM activation,
or network boot before mounting the real root.
Adds INIT_CMD_SWITCH_ROOT API command, `initctl switch-root` subcommand,
and HOOK_SWITCH_ROOT plugin hook point. The implementation gracefully
stops services, moves virtual filesystems (/dev, /proc, /sys, /run) to
the new root, deletes initramfs contents to free memory, then execs the
new init as PID 1.
See GitHub Discussion #292 for background.
Add handling for EBUSY when mounting cgroup2 filesystem, which occurs
when cgroups are already mounted. This can happen after switch_root
when cgroups were moved from the initramfs, or in container environments.
Verify the existing mount is actually cgroup2 before proceeding, and
track whether we mounted to avoid unmounting on error if we didn't.
At least the sysvpart.sh regression test cannot run in parallel yet with
other tests (probably runparts.sh), so we must ensure the tests never
run in parallel, in particular at release.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Finit now requires being able to query at least for the root user and
group before starting any services.
Also, add support for using libraries installed in /usr/local
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Finit has support for "Please press Enter to activate this console."
which means there's no getty yet running. However, when profiling
systems with Finit, and embedded systems in general, a common metric
is the time from power-on to getty has started.
This commit makes sure to rename the process so that BusyBox pidof is
capable of detecting that "getty" has started. This is mostly for the
bootchart2 project's bootchartd, the native BusyBox bootchartd does not
have this issue.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This is a refactor of getuser() and getgroup() so that they always
return a valid user, and group, for all normal use-cases. When an
error occurs we now handle it properly in service_fork() so as to
not attempt to start services with an invalid user/group setting
as root.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
When running Finit under boothcartd (bootchart2 project) the PATH is
lost due to a bug. This was a wakeup, so set critical variables in
main() early, before calling fs_init().
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>