2023-06-01 09:47:51 +03:00
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
# shellcheck disable=SC2016
set -eux
set -o pipefail
# shellcheck source=test/units/util.sh
. " $( dirname " $0 " ) " /util.sh
systemd-run --help --no-pager
systemd-run --version
systemd-run --no-ask-password true
2023-06-02 17:53:45 +03:00
systemd-run --no-block --collect true
2023-06-01 09:47:51 +03:00
export PARENT_FOO = bar
touch /tmp/public-marker
: "Transient service (system daemon)"
systemd-run --wait --pipe \
bash -xec '[[ "$(</proc/self/cgroup)" =~ /system\.slice/run-.+\.service$ ]]'
systemd-run --wait --pipe --system \
bash -xec '[[ "$(</proc/self/cgroup)" =~ /system\.slice/run-.+\.service$ ]]'
systemd-run --wait --pipe --slice= foo \
bash -xec '[[ "$(</proc/self/cgroup)" =~ /foo\.slice/run-.+\.service$ ]]'
systemd-run --wait --pipe --slice= foo.slice \
bash -xec '[[ "$(</proc/self/cgroup)" =~ /foo\.slice/run-.+\.service$ ]]'
systemd-run --wait --pipe --slice-inherit \
bash -xec '[[ "$(</proc/self/cgroup)" =~ /system\.slice/run-.+\.service$ ]]'
systemd-run --wait --pipe --slice-inherit --slice= foo \
bash -xec '[[ "$(</proc/self/cgroup)" =~ /system\.slice/system-foo\.slice/run-.+\.service$ ]]'
# We should not inherit caller's environment
systemd-run --wait --pipe bash -xec '[[ -z "$PARENT_FOO" ]]'
2023-06-02 17:53:45 +03:00
systemd-run --wait --pipe bash -xec '[[ "$PWD" == / && -n "$INVOCATION_ID" ]]'
2023-06-01 09:47:51 +03:00
systemd-run --wait --pipe \
2023-06-02 17:53:45 +03:00
--send-sighup \
2023-06-01 09:47:51 +03:00
--working-directory= "" \
--working-directory= /tmp \
bash -xec '[[ "$PWD" == /tmp ]]'
systemd-run --wait --pipe --same-dir bash -xec " [[ \"\$PWD\" == $PWD ]] "
systemd-run --wait --pipe \
--property= LimitCORE = 1M:2M \
--property= LimitCORE = 16M:32M \
--property= PrivateTmp = yes \
bash -xec '[[ "$(ulimit -c -S)" -eq 16384 && "$(ulimit -c -H)" -eq 32768 && ! -e /tmp/public-marker ]]'
systemd-run --wait --pipe \
--uid= testuser \
bash -xec '[[ "$(id -nu)" == testuser && "$(id -ng)" == testuser ]]'
systemd-run --wait --pipe \
--gid= testuser \
bash -xec '[[ "$(id -nu)" == root && "$(id -ng)" == testuser ]]'
systemd-run --wait --pipe \
--uid= testuser \
--gid= root \
bash -xec '[[ "$(id -nu)" == testuser && "$(id -ng)" == root ]]'
systemd-run --wait --pipe --expand-environment= no \
--nice= 10 \
bash -xec 'read -r -a SELF_STAT </proc/self/stat && [[ "${SELF_STAT[18]}" -eq 10 ]]'
systemd-run --wait --pipe \
--setenv= ENV_HELLO = "nope" \
--setenv= ENV_HELLO = "env world" \
--setenv= EMPTY = \
--setenv= PARENT_FOO \
--property= Environment = "ALSO_HELLO='also world'" \
bash -xec '[[ "$ENV_HELLO" == "env world" && -z "$EMPTY" && "$PARENT_FOO" == bar && "$ALSO_HELLO" == "also world" ]]'
UNIT = " service-0- $RANDOM "
systemd-run --remain-after-exit --unit= " $UNIT " \
--service-type= simple \
--service-type= oneshot \
true
systemctl cat " $UNIT "
grep -q "^Type=oneshot" " /run/systemd/transient/ $UNIT .service "
systemctl stop " $UNIT "
( ! systemctl cat " $UNIT " )
: "Transient service (user daemon)"
systemd-run --wait --pipe --user --machine= testuser@ \
bash -xec '[[ "$(</proc/self/cgroup)" =~ /user\.slice/.+/run-.+\.service$ ]]'
systemd-run --wait --pipe --user --machine= testuser@ \
bash -xec '[[ "$(id -nu)" == testuser && "$(id -ng)" == testuser ]]'
2023-06-02 17:53:45 +03:00
systemd-run --wait --pipe --user --machine= testuser@ \
bash -xec '[[ "$PWD" == /home/testuser && -n "$INVOCATION_ID" ]]'
2024-01-18 23:29:46 +03:00
# PrivateTmp=yes implies PrivateUsers=yes for user manager, so skip this if we
# don't have unprivileged user namespaces.
if [ [ " $( sysctl -ne kernel.apparmor_restrict_unprivileged_userns) " -ne 1 ] ] ; then
systemd-run --wait --pipe --user --machine= testuser@ \
--property= LimitCORE = 1M:2M \
--property= LimitCORE = 16M:32M \
--property= PrivateTmp = yes \
bash -xec '[[ "$(ulimit -c -S)" -eq 16384 && "$(ulimit -c -H)" -eq 32768 && ! -e /tmp/public-marker ]]'
fi
2023-06-01 09:47:51 +03:00
: "Transient scope (system daemon)"
systemd-run --scope \
bash -xec '[[ "$(</proc/self/cgroup)" =~ /system\.slice/run-.+\.scope$ ]]'
systemd-run --scope --system \
bash -xec '[[ "$(</proc/self/cgroup)" =~ /system\.slice/run-.+\.scope$ ]]'
systemd-run --scope --slice= foo \
bash -xec '[[ "$(</proc/self/cgroup)" =~ /foo\.slice/run-.+\.scope$ ]]'
systemd-run --scope --slice= foo.slice \
bash -xec '[[ "$(</proc/self/cgroup)" =~ /foo\.slice/run-.+\.scope$ ]]'
systemd-run --scope --slice-inherit \
bash -xec '[[ "$(</proc/self/cgroup)" =~ /system\.slice/run-.+\.scope$ ]]'
systemd-run --scope --slice-inherit --slice= foo \
bash -xec '[[ "$(</proc/self/cgroup)" =~ /system\.slice/system-foo\.slice/run-.+\.scope$ ]]'
# We should inherit caller's environment
systemd-run --scope bash -xec '[[ "$PARENT_FOO" == bar ]]'
2023-06-02 17:53:45 +03:00
systemd-run --scope \
--property= RuntimeMaxSec = 10 \
--property= RuntimeMaxSec = infinity \
true
2023-06-01 09:47:51 +03:00
: "Transient scope (user daemon)"
# FIXME: https://github.com/systemd/systemd/issues/27883
#systemd-run --scope --user --machine=testuser@ \
# bash -xec '[[ "$(</proc/self/cgroup)" =~ /user\.slice/run-.+\.scope$ ]]'
# We should inherit caller's environment
#systemd-run --scope --user --machine=testuser@ bash -xec '[[ "$PARENT_FOO" == bar ]]'
: "Transient timer unit"
UNIT = " timer-0- $RANDOM "
systemd-run --remain-after-exit \
--unit= " $UNIT " \
--timer-property= OnUnitInactiveSec = 16h \
true
systemctl cat " $UNIT .service " " $UNIT .timer "
grep -q " ^OnUnitInactiveSec=16h $" " /run/systemd/transient/ $UNIT .timer "
grep -qE " ^ExecStart=.*/bin/true.* $" " /run/systemd/transient/ $UNIT .service "
systemctl stop " $UNIT .timer " " $UNIT .service " || :
UNIT = " timer-1- $RANDOM "
systemd-run --remain-after-exit \
--unit= " $UNIT " \
--on-active= 10 \
--on-active= 30s \
--on-boot= 1s \
--on-startup= 2m \
--on-unit-active= 3h20m \
--on-unit-inactive= "5d 4m 32s" \
--on-calendar= "mon,fri *-1/2-1,3 *:30:45" \
--on-clock-change \
--on-clock-change \
--on-timezone-change \
--timer-property= After = systemd-journald.service \
--description= "Hello world" \
--description= "My Fancy Timer" \
true
systemctl cat " $UNIT .service " " $UNIT .timer "
systemd-analyze verify --recursive-errors= no " /run/systemd/transient/ $UNIT .service "
systemd-analyze verify --recursive-errors= no " /run/systemd/transient/ $UNIT .timer "
grep -q " ^Description=My Fancy Timer $" " /run/systemd/transient/ $UNIT .timer "
grep -q " ^OnActiveSec=10s $" " /run/systemd/transient/ $UNIT .timer "
grep -q " ^OnActiveSec=30s $" " /run/systemd/transient/ $UNIT .timer "
grep -q " ^OnBootSec=1s $" " /run/systemd/transient/ $UNIT .timer "
grep -q " ^OnStartupSec=2min $" " /run/systemd/transient/ $UNIT .timer "
grep -q " ^OnUnitActiveSec=3h 20min $" " /run/systemd/transient/ $UNIT .timer "
grep -q " ^OnUnitInactiveSec=5d 4min 32s $" " /run/systemd/transient/ $UNIT .timer "
grep -q " ^OnCalendar=mon,fri \*\-1/2\-1,3 \*:30:45 $" " /run/systemd/transient/ $UNIT .timer "
grep -q " ^OnClockChange=yes $" " /run/systemd/transient/ $UNIT .timer "
grep -q " ^OnTimezoneChange=yes $" " /run/systemd/transient/ $UNIT .timer "
grep -q " ^After=systemd-journald.service $" " /run/systemd/transient/ $UNIT .timer "
grep -q " ^Description=My Fancy Timer $" " /run/systemd/transient/ $UNIT .service "
grep -q " ^RemainAfterExit=yes $" " /run/systemd/transient/ $UNIT .service "
grep -qE " ^ExecStart=.*/bin/true.* $" " /run/systemd/transient/ $UNIT .service "
( ! grep -q " ^After=systemd-journald.service $" " /run/systemd/transient/ $UNIT .service " )
systemctl stop " $UNIT .timer " " $UNIT .service " || :
: "Transient path unit"
UNIT = " path-0- $RANDOM "
systemd-run --remain-after-exit \
--unit= " $UNIT " \
--path-property= PathExists = /tmp \
--path-property= PathExists = /tmp/foo \
--path-property= PathChanged = /root/bar \
true
systemctl cat " $UNIT .service " " $UNIT .path "
systemd-analyze verify --recursive-errors= no " /run/systemd/transient/ $UNIT .service "
systemd-analyze verify --recursive-errors= no " /run/systemd/transient/ $UNIT .path "
grep -q " ^PathExists=/tmp $" " /run/systemd/transient/ $UNIT .path "
grep -q " ^PathExists=/tmp/foo $" " /run/systemd/transient/ $UNIT .path "
grep -q " ^PathChanged=/root/bar $" " /run/systemd/transient/ $UNIT .path "
grep -qE " ^ExecStart=.*/bin/true.* $" " /run/systemd/transient/ $UNIT .service "
systemctl stop " $UNIT .path " " $UNIT .service " || :
: "Transient socket unit"
UNIT = " socket-0- $RANDOM "
systemd-run --remain-after-exit \
--unit= " $UNIT " \
--socket-property= ListenFIFO = /tmp/socket.fifo \
--socket-property= SocketMode = 0666 \
--socket-property= SocketMode = 0644 \
true
systemctl cat " $UNIT .service " " $UNIT .socket "
systemd-analyze verify --recursive-errors= no " /run/systemd/transient/ $UNIT .service "
systemd-analyze verify --recursive-errors= no " /run/systemd/transient/ $UNIT .socket "
grep -q " ^ListenFIFO=/tmp/socket.fifo $" " /run/systemd/transient/ $UNIT .socket "
grep -q " ^SocketMode=0666 $" " /run/systemd/transient/ $UNIT .socket "
grep -q " ^SocketMode=0644 $" " /run/systemd/transient/ $UNIT .socket "
grep -qE " ^ExecStart=.*/bin/true.* $" " /run/systemd/transient/ $UNIT .service "
systemctl stop " $UNIT .socket " " $UNIT .service " || :
2023-06-02 17:53:45 +03:00
: "Interactive options"
SHELL = /bin/true systemd-run --shell
SHELL = /bin/true systemd-run --scope --shell
systemd-run --wait --pty true
systemd-run --wait --machine= .host --pty true
2024-08-12 16:15:15 +03:00
systemd-run --json= short /bin/true | jq . >/dev/null
systemd-run --json= pretty /bin/true | jq . >/dev/null
2023-06-02 17:53:45 +03:00
( ! SHELL = /bin/false systemd-run --quiet --shell)
2023-06-01 09:47:51 +03:00
( ! systemd-run)
( ! systemd-run "" )
2023-06-02 17:53:45 +03:00
( ! systemd-run --foo= bar)
2023-06-01 09:47:51 +03:00
( ! systemd-run --wait --pipe --slice= foo.service true )
for opt in nice on-{ active,boot,calendar,startup,unit-active,unit-inactive} property service-type setenv; do
( ! systemd-run " -- $opt = " true )
( ! systemd-run " -- $opt ='' " true )
done
2023-06-23 19:27:45 +03:00
# Let's make sure that ProtectProc= properly moves submounts of the original /proc over to the new proc
2023-12-22 16:16:56 +03:00
BOOT_ID = " $( </proc/sys/kernel/random/boot_id) "
UNIT_BOOT_ID = " $( systemd-run -q --wait --pipe -p ProtectProc = invisible cat /proc/sys/kernel/random/boot_id) "
assert_eq " $BOOT_ID " " $UNIT_BOOT_ID "
TMP_KVER = " /tmp/version. $RANDOM "
KVER = " $( </proc/version) .piff "
echo " $KVER " >" $TMP_KVER "
mount --bind " $TMP_KVER " /proc/version
UNIT_KVER = " $( systemd-run -q --wait --pipe -p ProtectProc = invisible cat /proc/version) "
assert_eq " $KVER " " $UNIT_KVER "
umount /proc/version
rm -f " $TMP_KVER "
2023-06-23 19:27:45 +03:00
2024-05-03 15:09:27 +03:00
if [ [ -e /usr/lib/pam.d/systemd-run0 ] ] || [ [ -e /etc/pam.d/systemd-run0 ] ] ; then
# Check that invoking the tool under the run0 alias name works
run0 ls /
assert_eq " $( run0 echo foo) " "foo"
# Check if we set some expected environment variables
2024-10-24 23:51:49 +03:00
for arg in "" "--user=root" "--user=0" "--user=testuser" ; do
2024-05-03 15:09:27 +03:00
assert_eq " $( run0 ${ arg : + " $arg " } bash -c 'echo $SUDO_USER' ) " " $USER "
assert_eq " $( run0 ${ arg : + " $arg " } bash -c 'echo $SUDO_UID' ) " " $( id -u " $USER " ) "
assert_eq " $( run0 ${ arg : + " $arg " } bash -c 'echo $SUDO_GID' ) " " $( id -u " $USER " ) "
2024-10-24 23:51:49 +03:00
# Validate that we actually went properly through PAM (XDG_SESSION_TYPE is set by pam_systemd)
assert_eq " $( run0 ${ arg : + " $arg " } bash -c 'echo $XDG_SESSION_TYPE' ) " "unspecified"
2024-05-03 15:09:27 +03:00
done
# Let's chain a couple of run0 calls together, for fun
readarray -t cmdline < <( printf "%.0srun0\n" { 0..31} )
assert_eq " $( " ${ cmdline [@] } " bash -c 'echo $SUDO_USER' ) " " $USER "
2024-10-15 09:00:18 +03:00
# Tests for working directory, especially for specifying "/" (see PR #34771).
cd /
assert_eq " $( run0 pwd ) " "/"
assert_eq " $( run0 -D /tmp pwd ) " "/tmp"
assert_eq " $( run0 --user= testuser pwd ) " "/home/testuser"
assert_eq " $( run0 -D /tmp --user= testuser pwd ) " "/tmp"
cd /tmp
assert_eq " $( run0 pwd ) " "/tmp"
assert_eq " $( run0 -D / pwd ) " "/"
assert_eq " $( run0 --user= testuser pwd ) " "/home/testuser"
assert_eq " $( run0 -D / --user= testuser pwd ) " "/"
2024-10-25 10:29:38 +03:00
# Verify that all combinations of --pty/--pipe come to the sam results
assert_eq " $( run0 echo -n foo) " "foo"
assert_eq " $( run0 --pty echo -n foo) " "foo"
assert_eq " $( run0 --pipe echo -n foo) " "foo"
assert_eq " $( run0 --pipe --pty echo -n foo) " "foo"
# Validate when we invoke run0 without a tty, that depending on --pty it either allocates a tty or not
assert_neq " $( run0 --pty tty < /dev/null) " "not a tty"
assert_eq " $( run0 --pipe tty < /dev/null) " "not a tty"
2024-05-03 15:09:27 +03:00
fi
2024-10-25 12:31:38 +03:00
# Tests whether intermediate disconnects corrupt us (modified testcase from https://github.com/systemd/systemd/issues/27204)
assert_rc "37" systemd-run --unit= disconnecttest --wait --pipe --user -M testuser@.host bash -ec 'systemctl --user daemon-reexec; sleep 3; exit 37'