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.
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.
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.
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 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.
Implement supplementary group support for services, allowing them to
access resources owned by multiple groups. Uses the @user:group,sup1,sup2
syntax to explicitly specify supplementary groups, in addition to now
reading group membership from /etc/group.
Implement Linux capability support for services, allowing them to run
with minimal required privileges instead of running as root. This uses
the modern IAB (Inheritable, Ambient, Bounding) API from libcap.
The existing implementation seemed useful enough to warrant a new
helper function. Care was taken to ensure the revised code no longer
suffers any memory leaks.
The tmpfiles.d spec contains entry types that should be acted upon in different modes
of operation: create, clean, remove, and purge - split up create & remove logic to
clarify the modes of operation finit supports.
The tmpfiles.d spec has proven useful in systemd, enough so that some developers
are starting to ship tmpfiles.d configuration files with their software.
By splitting the tmpfiles functionality in finit out into a separate executable
we are providing a useful piece of software that package managers can hook into.