mirror of
https://github.com/troglobit/finit.git
synced 2026-10-01 05:22:48 +07:00
Aaron Andersen points out in the #492 discussion that the *Directory settings carry more contract than create-and-chown: per-directory modes, specific ownership rules, and cleanup toggles. Without them config-dir was chowned to the service user, which systemd never does, an existing directory with drifted ownership was left wrong, and the runtime directory could not survive a restart. Now matching systemd.exec(5), and where the man page is vague, the code in setup_exec_directory(): - each directory takes a matching -mode key, octal with the leading zero, default 0755. The mode of the named directory is locked down again on every start, also when it already exists - config-dir is created but never chowned - the contents of an existing directory are left alone as long as the owner is right; on drift everything under it is chowned back - runtime-dir-preserve = no | restart | yes maps RuntimeDirectoryPreserve=. A service still qualified to run when the runtime directory would be removed is restarting, not stopping, which is what svc_enabled() answers The dir mechanics move to mksubsysd(), taking resolved ids, with mksubsys() reduced to a name-resolving wrapper for the dbus plugin. The child resolves uid/gid once for both directory setup and privilege drop. The symlink form, RuntimeDirectory=foo:bar, is not adopted. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
121 lines
3.8 KiB
Bash
Executable File
121 lines
3.8 KiB
Bash
Executable File
#!/bin/sh
|
|
# Verify the per-service directory settings: runtime-dir, state-dir,
|
|
# cache-dir, logs-dir, and config-dir. The directory is created before
|
|
# the service starts, owned by the service user, and exported to the
|
|
# environment. The runtime directory is removed again when the service
|
|
# stops, the others persist.
|
|
set -eu
|
|
|
|
TEST_DIR=$(dirname "$0")
|
|
|
|
# shellcheck disable=SC2034
|
|
BOOTSTRAP="service owned {
|
|
runlevel = \"S12345\"
|
|
user = \"daemon\"
|
|
group = \"daemon\"
|
|
runtime-dir = \"owned\"
|
|
state-dir = \"owned\"
|
|
pidfile = \"/run/owned/serv.pid\"
|
|
command = \"/sbin/serv -np -P /run/owned/serv.pid -i owned -e STATE_DIRECTORY:/var/lib/owned\"
|
|
}
|
|
task probe {
|
|
runlevel = \"S12345\"
|
|
runtime-dir = \"probe\"
|
|
cache-dir = \"probe\"
|
|
command = \"/sbin/serv -h -e RUNTIME_DIRECTORY:/run/probe -e CACHE_DIRECTORY:/var/cache/probe\"
|
|
}
|
|
service escape {
|
|
runlevel = \"S12345\"
|
|
runtime-dir = \"../escape\"
|
|
command = \"serv -np -i escape\"
|
|
}
|
|
service modes {
|
|
runlevel = \"S12345\"
|
|
user = \"daemon\"
|
|
runtime-dir = \"modes\"
|
|
runtime-dir-mode = 0700
|
|
runtime-dir-preserve = \"restart\"
|
|
config-dir = \"modes\"
|
|
command = \"/sbin/serv -np -P /run/modes/serv.pid -i modes\"
|
|
}"
|
|
|
|
# ls output is empty for an empty directory, so test -d instead
|
|
assert_dir()
|
|
{
|
|
assert "Directory $1 exists" "$(texec test -d "$1" && echo yes)" = "yes"
|
|
}
|
|
|
|
assert_nodir()
|
|
{
|
|
assert "Directory $1 removed" "$(texec test -d "$1" || echo gone)" = "gone"
|
|
}
|
|
|
|
assert_owner()
|
|
{
|
|
assert "$1 owned by $2" "$(texec stat -c %U:%G "$1")" = "$2"
|
|
}
|
|
|
|
# shellcheck source=/dev/null
|
|
. "$TEST_DIR/lib/setup.sh"
|
|
|
|
say 'Directory created before start, owned by the service user'
|
|
retry 'assert_status owned running'
|
|
assert_dir /run/owned
|
|
assert_owner /run/owned daemon:daemon
|
|
assert_dir /var/lib/owned
|
|
assert_owner /var/lib/owned daemon:daemon
|
|
|
|
say 'The paths are exported to the process environment; both commands'
|
|
say 'verify their own with serv -e, and refuse to run on a mismatch'
|
|
|
|
say 'A completed task no longer holds its runtime directory'
|
|
retry 'assert_status probe done'
|
|
assert_nodir /run/probe
|
|
assert_dir /var/cache/probe
|
|
|
|
say 'Stopping the service removes the runtime directory, state persists'
|
|
run "initctl stop owned"
|
|
retry 'assert_status owned stopped'
|
|
assert_nodir /run/owned
|
|
assert_dir /var/lib/owned
|
|
|
|
say 'Starting again recreates it'
|
|
run "initctl start owned"
|
|
retry 'assert_status owned running'
|
|
assert_dir /run/owned
|
|
|
|
say 'A path escaping the base directory is refused, service still runs'
|
|
retry 'assert_status escape running'
|
|
assert_nodir /escape
|
|
|
|
say 'runtime-dir-mode sets the mode, config-dir is never chowned'
|
|
retry 'assert_status modes running'
|
|
assert "mode is 0700" "$(texec stat -c %a /run/modes)" = "700"
|
|
assert_owner /run/modes daemon:root
|
|
assert_owner /etc/modes root:root
|
|
|
|
say 'runtime-dir-preserve restart keeps the directory across a restart'
|
|
run "touch /run/modes/keepsake" || texec touch /run/modes/keepsake
|
|
run "initctl restart modes"
|
|
retry 'assert_status modes running'
|
|
assert_file_exists /run/modes/keepsake
|
|
|
|
say 'but a real stop still removes it'
|
|
run "initctl stop modes"
|
|
retry 'assert_status modes stopped'
|
|
assert_nodir /run/modes
|
|
|
|
say 'An existing directory with the wrong owner is chowned back, and'
|
|
say 'its mode is locked down again'
|
|
run "initctl stop owned"
|
|
retry 'assert_status owned stopped'
|
|
texec mkdir -p /var/lib/owned/sub
|
|
texec touch /var/lib/owned/sub/file
|
|
texec chown -R 0:0 /var/lib/owned
|
|
texec chmod 0700 /var/lib/owned
|
|
run "initctl start owned"
|
|
retry 'assert_status owned running'
|
|
assert "mode locked down to 0755" "$(texec stat -c %a /var/lib/owned)" = "755"
|
|
assert_owner /var/lib/owned daemon:daemon
|
|
assert_owner /var/lib/owned/sub/file daemon:daemon
|