test: report subtest skips (#43387)

`run_subtests` now handle exit 77 as skip status, making successful
subtests distinguishable from passed tests. Introduce
`run_subtests_and_exit` as a helper to automatically write `/testok` if
all subtests passed, and to write `/skipped` and exit 77 if all subtests
were skipped.
This commit is contained in:
Paul Meyer
2026-08-17 11:44:56 +02:00
committed by GitHub
60 changed files with 185 additions and 216 deletions
@@ -8,7 +8,7 @@ set -o pipefail
if ! cgroupfs_supports_user_xattrs; then
echo "CGroup does not support user xattrs, skipping LogFilterPatterns= tests."
exit 0
exit 77
fi
# Unfortunately, journalctl -I/--invocation= is unstable when debug logging is enabled on service manager.
+2 -2
View File
@@ -5,12 +5,12 @@ set -o pipefail
if systemd-detect-virt -cq; then
echo "This test requires a VM, skipping the test"
exit 0
exit 77
fi
if [[ ! -x /usr/lib/systemd/systemd-bsod ]]; then
echo "systemd-bsod is not installed, skipping the test"
exit 0
exit 77
fi
# shellcheck disable=SC2317
+1 -1
View File
@@ -7,7 +7,7 @@ set -o pipefail
if ! journalctl --version | grep -F +OPENSSL >/dev/null; then
echo "Built without openssl, skipping the FSS tests"
exit 0
exit 77
fi
# output key and related info in json format
@@ -5,7 +5,7 @@ set -o pipefail
if [[ ! -x /usr/lib/systemd/systemd-journal-gatewayd ]]; then
echo "Built without systemd-journal-gatewayd support, skipping the test"
exit 0
exit 77
fi
LOG_FILE="$(mktemp)"
+2 -2
View File
@@ -6,12 +6,12 @@ set -o pipefail
if [[ ! -x /usr/lib/systemd/systemd-journal-remote || ! -x /usr/lib/systemd/systemd-journal-upload ]]; then
echo "Built without systemd-journal-remote/upload support, skipping the test"
exit 0
exit 77
fi
if ! command -v openssl >/dev/null; then
echo "openssl command not available, skipping the tests"
exit 0
exit 77
fi
at_exit() {
+1 -3
View File
@@ -6,6 +6,4 @@ set -o pipefail
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh
run_subtests
touch /testok
run_subtests_and_exit
+1 -3
View File
@@ -6,6 +6,4 @@ set -o pipefail
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh
run_subtests
touch /testok
run_subtests_and_exit
+1 -1
View File
@@ -8,7 +8,7 @@ if [[ -v ASAN_OPTIONS ]]; then
# Under sanitizers the service is slow enough that the calendar timer with 5s resolution ends up
# missing ticks, making the test flaky
echo "Sanitizers detected, skipping the test..."
exit 0
exit 77
fi
systemctl start defer-reactivation.timer
+1 -1
View File
@@ -11,7 +11,7 @@ private_ipcns=$(systemd-run --quiet --wait --pipe -p PrivateIPC=yes readlink /pr
if [[ ! -d /proc/sys/fs/mqueue ]]; then
echo "POSIX message queues are not supported, skipping ownership checks"
exit 0
exit 77
fi
# Verify ownership attributes are applied to message queues
+1 -1
View File
@@ -5,7 +5,7 @@ set -o pipefail
if ! command -v nft >/dev/null; then
echo "nftables is not installed. Skipped NFTSet= tests."
exit 0
exit 77
fi
RUN_OUT="$(mktemp)"
+2 -2
View File
@@ -9,7 +9,7 @@ set -o pipefail
if ! can_do_rootless_nspawn; then
echo "Skipping unpriv nspawn test"
exit 0
exit 77
fi
# We need FSCONFIG_SET_FD support in overlayfs for .mstack to work. Let's skip
@@ -18,7 +18,7 @@ fi
# support for this from shell, hence let's do a version check instead.
if systemd-analyze condition 'ConditionVersion= < 6.13' ; then
echo "Kernel too old for FSCONFIG_SET_FD support on overlayfs, skipping pull-oci test".
exit 0
exit 77
fi
export SYSTEMD_LOG_LEVEL=debug
+1 -3
View File
@@ -18,6 +18,4 @@ fi
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh
run_subtests
touch /testok
run_subtests_and_exit
+1 -1
View File
@@ -9,7 +9,7 @@ set -o pipefail
if ! can_do_rootless_nspawn; then
echo "Skipping unpriv nspawn test"
exit 0
exit 77
fi
at_exit() {
+1 -1
View File
@@ -5,7 +5,7 @@ set -o pipefail
if ! command -v systemd-hwdb >/dev/null; then
echo "systemd-hwdb not found, skipping."
exit 0
exit 77
fi
# shellcheck source=test/units/util.sh
+1 -1
View File
@@ -28,7 +28,7 @@ udevadm wait --settle --timeout=30 /sys/class/net/test1
output=$(ip link show dev test1)
if ! [[ "$output" =~ altname ]]; then
echo "alternative name for network interface not supported, skipping test."
exit 0
exit 77
fi
assert_not_in "altname test1" "$output"
assert_in "altname test2" "$output"
+1 -3
View File
@@ -8,6 +8,4 @@ set -o pipefail
udevadm settle
run_subtests
touch /testok
run_subtests_and_exit
+1 -1
View File
@@ -8,7 +8,7 @@ set -eux
if [[ "$(get_cgroup_hierarchy)" != unified ]]; then
echo "Skipping $0 as we're not running with the unified cgroup hierarchy"
exit 0
exit 77
fi
# Multiple level process tree, parent process stays up
@@ -8,12 +8,12 @@ set -o pipefail
if [[ "$(get_cgroup_hierarchy)" != unified ]]; then
echo "Skipping $0 as we're not running with the unified cgroup hierarchy."
exit 0
exit 77
fi
if systemd-detect-virt --container --quiet; then
echo "Skipping $0 as we're running on container."
exit 0
exit 77
fi
ip netns add test-ns
@@ -22,7 +22,7 @@ set -o pipefail
. /etc/os-release
if [[ "$ID" =~ opensuse ]]; then
echo "Skipping cgroup test with too small MemoryMax= setting on openSUSE."
exit 0
exit 77
fi
cat >/run/systemd/system/testslice.slice <<EOF
+1 -1
View File
@@ -13,7 +13,7 @@ set -o pipefail
if [[ "$(get_cgroup_hierarchy)" != unified ]]; then
echo "Skipping $0 as we're not running with the unified cgroup hierarchy"
exit 0
exit 77
fi
testcase_controllers() {
@@ -10,7 +10,7 @@ set -o pipefail
if [[ "$(get_cgroup_hierarchy)" != unified ]]; then
echo "Skipping $0 as we're not running with the unified cgroup hierarchy"
exit 0
exit 77
fi
testcase_iodevice_dbus () {
+1 -3
View File
@@ -6,6 +6,4 @@ set -o pipefail
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh
run_subtests
touch /testok
run_subtests_and_exit
+1 -3
View File
@@ -14,6 +14,4 @@ if systemd-detect-virt --quiet --container; then
ln -s /dev/null /run/tmpfiles.d/selinux-policy.conf
fi
run_subtests
touch /testok
run_subtests_and_exit
+1 -3
View File
@@ -7,6 +7,4 @@ set -o pipefail
. "$(dirname "$0")"/test-control.sh
# Note: the signal shenanigans are necessary for the Upholds= tests
run_subtests_with_signals SIGUSR1 SIGUSR2 SIGRTMIN+1
touch /testok
run_subtests_with_signals_and_exit SIGUSR1 SIGUSR2 SIGRTMIN+1
@@ -11,12 +11,12 @@ UNIT_FILE_LIST="/usr/lib/systemd/tests/testdata/installed-unit-files.txt"
if [[ ! -f "$UNIT_FILE_LIST" ]]; then
echo "Couldn't find the list of installed units, skipping the test"
exit 0
exit 77
fi
if ! command -v systemd-analyze >/dev/null; then
echo "Built without systemd-analyze, skipping the test"
exit 0
exit 77
fi
mapfile -t UNIT_FILES <"$UNIT_FILE_LIST"
+1 -1
View File
@@ -18,7 +18,7 @@ if [[ ! -f /usr/lib/systemd/system/systemd-mountfsd.socket ]] ||
systemd-analyze compare-versions "$(pkcheck --version | awk '{print $3}')" lt 124 ||
systemctl --version | grep -- "-BTF" >/dev/null; then
echo "Skipping mountfsd/nsresourced tests"
exit 0
exit 77
fi
systemctl start systemd-mountfsd.socket systemd-nsresourced.socket
+1 -1
View File
@@ -14,7 +14,7 @@ if [[ ! -f /usr/lib/systemd/system/systemd-mountfsd.socket ]] ||
systemd-analyze compare-versions "$(uname -r)" lt 6.5 ||
systemd-analyze compare-versions "$(pkcheck --version | awk '{print $3}')" lt 124; then
echo "Skipping mountfsd/nsresourced tests"
exit 0
exit 77
fi
at_exit() {
+1 -3
View File
@@ -6,6 +6,4 @@ set -o pipefail
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh
run_subtests
touch /testok
run_subtests_and_exit
+1 -1
View File
@@ -20,7 +20,7 @@ trap at_exit EXIT
# There is an external issue with libcryptsetup on ppc64 that hits 95% of Ubuntu ppc64 test runs, so skip it
if [[ "$(uname -m)" == "ppc64le" ]]; then
echo "Skipping systemd-cryptenroll tests on ppc64le, see https://github.com/systemd/systemd/issues/27716"
exit 0
exit 77
fi
export SYSTEMD_LOG_LEVEL=debug
@@ -17,7 +17,7 @@ export SYSTEMD_LOG_LEVEL=debug
if ! command -v systemd-cryptsetup >/dev/null || ! tpm_has_pcr sha256 15; then
echo "systemd-cryptsetup or PCR 15 (sha256) not available, skipping cryptsetup measurement test"
exit 0
exit 77
fi
IMAGE=""
+1 -1
View File
@@ -11,7 +11,7 @@ SD_MEASURE="/usr/lib/systemd/systemd-measure"
if [[ ! -x "${SD_MEASURE:?}" ]]; then
echo "$SD_MEASURE not found, skipping the test"
exit 0
exit 77
fi
at_exit() {
+1 -1
View File
@@ -13,7 +13,7 @@ SD_MEASURE="/usr/lib/systemd/systemd-measure"
if [[ ! -x "${SD_PCREXTEND:?}" ]] || [[ ! -x "${SD_MEASURE:?}" ]] || ! tpm_has_pcr sha256 11; then
echo "$SD_PCREXTEND, $SD_MEASURE or PCR sysfs files not found, skipping PCR extension tests"
exit 0
exit 77
fi
at_exit() {
+1 -1
View File
@@ -11,7 +11,7 @@ SD_PCREXTEND="/usr/lib/systemd/systemd-pcrextend"
if [[ ! -x "${SD_PCREXTEND:?}" ]] || ! tpm_has_pcr sha256 16 || ! tpm_has_pcr sha256 15; then
echo "$SD_PCREXTEND or PCR sysfs files not found, skipping PCR extension tests"
exit 0
exit 77
fi
at_exit() {
+1 -1
View File
@@ -14,7 +14,7 @@ SD_MEASURE="/usr/lib/systemd/systemd-measure"
if [[ ! -x "${SD_PCREXTEND:?}" ]] || [[ ! -x "${SD_PCRLOCK:?}" ]] || [[ ! -x "${SD_MEASURE:?}" ]] ; then
echo "$SD_PCREXTEND or $SD_PCRLOCK or $SD_MEASURE not found, skipping pcrlock tests"
exit 0
exit 77
fi
at_exit() {
+1 -3
View File
@@ -6,6 +6,4 @@ set -o pipefail
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh
run_subtests
touch /testok
run_subtests_and_exit
+1 -1
View File
@@ -8,7 +8,7 @@ SD_TPM2SETUP="/usr/lib/systemd/systemd-tpm2-setup"
if [[ ! -x "${SD_TPM2SETUP:?}" ]]; then
echo "$SD_TPM2SETUP not found, skipping the test"
exit 0
exit 77
fi
# systemd-tpm2-setup returns EX_UNAVAILABLE rather than 0 when it cannot set something up but this
+1 -1
View File
@@ -8,7 +8,7 @@ set -o pipefail
if ! command -v systemd-firstboot >/dev/null; then
echo "systemd-firstboot not found, skipping the test"
exit 0
exit 77
fi
restore_etc_hostname() {
+1 -1
View File
@@ -9,7 +9,7 @@ set -o pipefail
if ! test -x /usr/lib/systemd/systemd-imdsd ; then
echo "No imdsd installed, skipping test."
exit 0
exit 77
fi
at_exit() {
+1 -1
View File
@@ -11,7 +11,7 @@ set -o pipefail
if ! command -v /usr/lib/systemd/systemd-keyutil >/dev/null; then
echo "systemd-keyutil not found, skipping."
exit 0
exit 77
fi
cat >/tmp/openssl.conf <<EOF
+1 -1
View File
@@ -9,7 +9,7 @@ set -o pipefail
if ! command -v hostnamectl >/dev/null; then
echo "hostnamectl not found, skipping the test"
exit 0
exit 77
fi
at_exit() {
+1 -1
View File
@@ -5,7 +5,7 @@ set -o pipefail
if ! command -v systemd-mute-console >/dev/null; then
echo "systemd-mute-console is not installed, skipping the test"
exit 0
exit 77
fi
PID="$(systemd-notify --fork -- systemd-mute-console)"
+2 -2
View File
@@ -9,12 +9,12 @@ set -o pipefail
if ! command -v /usr/lib/systemd/systemd-sbsign >/dev/null; then
echo "systemd-sbsign not found, skipping."
exit 0
exit 77
fi
if [[ ! -d /usr/lib/systemd/boot/efi ]]; then
echo "systemd-boot is not installed, skipping."
exit 0
exit 77
fi
cat >/tmp/openssl.conf <<EOF
+1 -3
View File
@@ -6,6 +6,4 @@ set -o pipefail
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh
run_subtests
touch /testok
run_subtests_and_exit
+1 -1
View File
@@ -12,7 +12,7 @@ set -o pipefail
# indicator.
if ! socket_inode_supports_user_xattrs; then
echo "Socket inode extended attributes unsupported on this kernel, skipping." >&2
exit 0
exit 77
fi
UNIT_SOCKET_PATH="/run/test-socket-xattr.sock"
+1 -1
View File
@@ -5,7 +5,7 @@ set -o pipefail
if ! command -v ssh >/dev/null || ! command -v sshd >/dev/null ; then
echo "ssh/sshd not found, skipping test." >&2
exit 0
exit 77
fi
systemctl -q is-active sshd-unix-local.socket
+1 -1
View File
@@ -5,7 +5,7 @@ set -o pipefail
if ! command -v userdbctl >/dev/null; then
echo "userdbctl is not installed, skipping the test."
exit 0
exit 77
fi
# shellcheck source=test/units/util.sh
@@ -11,7 +11,7 @@ set -o pipefail
# unavailable, since the kernel version alone is not a reliable indicator.
if ! socket_inode_supports_user_xattrs; then
echo "Socket inode extended attributes unsupported on this kernel, skipping." >&2
exit 0
exit 77
fi
ENTRYPOINT_PATH="/run/test-list-sockets-entrypoint.sock"
+1 -3
View File
@@ -6,6 +6,4 @@ set -o pipefail
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh
run_subtests
touch /testok
run_subtests_and_exit
+7 -25
View File
@@ -17,33 +17,33 @@ set -o pipefail
if [[ -v ASAN_OPTIONS ]]; then
echo "vmspawn launches QEMU which doesn't work under ASan, skipping"
exit 0
exit 77
fi
if ! command -v systemd-vmspawn >/dev/null 2>&1; then
echo "systemd-vmspawn not found, skipping"
exit 0
exit 77
fi
if ! command -v storagectl >/dev/null 2>&1; then
echo "storagectl not found, skipping"
exit 0
exit 77
fi
if ! find_qemu_binary; then
echo "QEMU not found, skipping"
exit 0
exit 77
fi
if ! command -v mke2fs >/dev/null 2>&1; then
echo "mke2fs not found, skipping"
exit 0
exit 77
fi
# Storage providers are socket-activated; skip if the fs provider socket isn't present.
if ! test -S /run/systemd/io.systemd.StorageProvider/fs; then
echo "StorageProvider fs socket not found, skipping"
exit 0
exit 77
fi
# Find a kernel for direct boot
@@ -57,7 +57,7 @@ done
if [[ -z "$KERNEL" ]]; then
echo "No kernel found for direct VM boot, skipping"
exit 0
exit 77
fi
WORKDIR="$(mktemp -d /tmp/test-bind-volume.XXXXXXXXXX)"
@@ -90,24 +90,6 @@ mke2fs -t ext4 -q -d "$WORKDIR/rootfs" "$WORKDIR/root.raw"
BOOT_VOL="test-bind-volume-boot-$$"
RUNTIME_VOL="test-bind-volume-runtime-$$"
wait_for_machine() {
local machine="$1" pid="$2" log="$3"
timeout 30 bash -c "
while ! machinectl list --no-legend 2>/dev/null | grep >/dev/null '$machine'; do
if ! kill -0 $pid 2>/dev/null; then
echo 'vmspawn exited before machine registration'
cat '$log'
exit 77
fi
sleep .5
done
" || {
local rc=$?
if [[ $rc -eq 77 ]]; then exit 0; fi
exit "$rc"
}
}
# --- Boot the VM with one boot-time bind-volume ---
MACHINE="test-bind-volume-$$"
systemd-vmspawn \
+2 -2
View File
@@ -5,12 +5,12 @@ set -o pipefail
if ! command -v bootctl >/dev/null; then
echo "bootctl not found, skipping."
exit 0
exit 77
fi
if [[ ! -d /usr/lib/systemd/boot/efi ]]; then
echo "sd-boot is not installed, skipping."
exit 0
exit 77
fi
# shellcheck source=test/units/util.sh
@@ -18,32 +18,32 @@ set -o pipefail
if [[ -v ASAN_OPTIONS ]]; then
echo "vmspawn launches QEMU which doesn't work under ASan, skipping"
exit 0
exit 77
fi
if ! command -v systemd-vmspawn >/dev/null 2>&1; then
echo "systemd-vmspawn not found, skipping"
exit 0
exit 77
fi
if ! command -v storagectl >/dev/null 2>&1; then
echo "storagectl not found, skipping"
exit 0
exit 77
fi
if ! find_qemu_binary; then
echo "QEMU not found, skipping"
exit 0
exit 77
fi
if ! command -v mke2fs >/dev/null 2>&1; then
echo "mke2fs not found, skipping"
exit 0
exit 77
fi
if ! test -S /run/systemd/io.systemd.StorageProvider/fs; then
echo "StorageProvider fs socket not found, skipping"
exit 0
exit 77
fi
KERNEL=""
@@ -56,7 +56,7 @@ done
if [[ -z "$KERNEL" ]]; then
echo "No kernel found for direct VM boot, skipping"
exit 0
exit 77
fi
WORKDIR="$(mktemp -d /tmp/test-replace-storage.XXXXXXXXXX)"
@@ -92,24 +92,6 @@ RUNTIME_VOL="test-replace-storage-runtime-$$"
truncate -s 32M "$WORKDIR/new-backing-1.raw"
truncate -s 32M "$WORKDIR/new-backing-2.raw"
wait_for_machine() {
local machine="$1" pid="$2" log="$3"
timeout 30 bash -c "
while ! machinectl list --no-legend 2>/dev/null | grep >/dev/null '$machine'; do
if ! kill -0 $pid 2>/dev/null; then
echo 'vmspawn exited before machine registration'
cat '$log'
exit 77
fi
sleep .5
done
" || {
local rc=$?
if [[ $rc -eq 77 ]]; then exit 0; fi
exit "$rc"
}
}
MACHINE="test-replace-storage-$$"
systemd-vmspawn \
--machine="$MACHINE" \
@@ -5,33 +5,33 @@ set -o pipefail
if ! command -v systemd-sysinstall >/dev/null; then
echo "systemd-sysinstall not found, skipping."
exit 0
exit 77
fi
if ! command -v systemd-repart >/dev/null; then
echo "systemd-repart not found, skipping."
exit 0
exit 77
fi
if ! command -v bootctl >/dev/null; then
echo "bootctl not found, skipping."
exit 0
exit 77
fi
if ! command -v ukify >/dev/null; then
echo "ukify not found, skipping."
exit 0
exit 77
fi
if [[ ! -d /usr/lib/systemd/boot/efi ]]; then
echo "sd-boot is not installed, skipping."
exit 0
exit 77
fi
# We need a real environment to fiddle with loop devices.
if systemd-detect-virt -cq; then
echo "Running in a container, skipping."
exit 0
exit 77
fi
# shellcheck source=test/units/test-control.sh
@@ -16,22 +16,22 @@ set -o pipefail
if [[ -v ASAN_OPTIONS ]]; then
echo "vmspawn launches QEMU which doesn't work under ASan, skipping"
exit 0
exit 77
fi
if ! command -v systemd-vmspawn >/dev/null 2>&1; then
echo "systemd-vmspawn not found, skipping"
exit 0
exit 77
fi
if ! find_qemu_binary; then
echo "QEMU not found, skipping"
exit 0
exit 77
fi
if ! command -v mke2fs >/dev/null 2>&1; then
echo "mke2fs not found, skipping"
exit 0
exit 77
fi
# Find a kernel for direct boot
@@ -45,7 +45,7 @@ done
if [[ -z "$KERNEL" ]]; then
echo "No kernel found for direct VM boot, skipping"
exit 0
exit 77
fi
echo "Using kernel: $KERNEL"
@@ -83,20 +83,6 @@ mke2fs -t ext4 -q -d "$WORKDIR/rootfs" "$WORKDIR/root.raw"
truncate -s 64M "$WORKDIR/extra1.raw"
truncate -s 32M "$WORKDIR/extra2.raw"
wait_for_machine() {
local machine="$1" pid="$2" log="$3"
timeout 30 bash -c "
while ! machinectl list --no-legend 2>/dev/null | grep >/dev/null '$machine'; do
if ! kill -0 $pid 2>/dev/null; then
echo 'vmspawn exited before machine registration'
cat '$log'
exit 1
fi
sleep .5
done
"
}
# --- Test 1: Multi-drive setup (root + 2 extra drives) ---
# Verifies that --image with multiple --extra-drive flags works with the async
# QMP pipeline. Three drives means three fdset allocations, three blockdev-add
+5 -29
View File
@@ -9,17 +9,17 @@ set -o pipefail
if [[ -v ASAN_OPTIONS ]]; then
echo "vmspawn launches QEMU which doesn't work under ASan, skipping"
exit 0
exit 77
fi
if ! command -v systemd-vmspawn >/dev/null 2>&1; then
echo "systemd-vmspawn not found, skipping"
exit 0
exit 77
fi
if ! find_qemu_binary; then
echo "QEMU not found, skipping"
exit 0
exit 77
fi
# --directory= needs virtiofsd (on Fedora it lives in /usr/libexec, not in PATH)
@@ -27,7 +27,7 @@ if ! command -v virtiofsd >/dev/null 2>&1 &&
! test -x /usr/libexec/virtiofsd &&
! test -x /usr/lib/virtiofsd; then
echo "virtiofsd not found, skipping"
exit 0
exit 77
fi
# Find a kernel for direct boot
@@ -41,7 +41,7 @@ done
if [[ -z "$KERNEL" ]]; then
echo "No kernel found for direct VM boot, skipping"
exit 0
exit 77
fi
echo "Using kernel: $KERNEL"
@@ -77,30 +77,6 @@ exec sleep infinity
EOF
chmod +x "$WORKDIR/root/sbin/init"
# Wait for a vmspawn machine to register with machined.
# Skips the test gracefully if vmspawn fails due to missing vhost-user-fs support (nested VM).
wait_for_machine() {
local machine="$1" pid="$2" log="$3"
timeout 30 bash -c "
while ! machinectl list --no-legend 2>/dev/null | grep >/dev/null '$machine'; do
if ! kill -0 $pid 2>/dev/null; then
if grep >/dev/null 'virtiofs.*QMP\|vhost-user-fs-pci' '$log'; then
echo 'vhost-user-fs not supported (nested VM?), skipping'
exit 77
fi
echo 'vmspawn exited before registering'
cat '$log'
exit 1
fi
sleep .5
done
" || {
local rc=$?
if [[ $rc -eq 77 ]]; then exit 0; fi
exit "$rc"
}
}
# Launch vmspawn in the background with direct kernel boot and headless console.
systemd-vmspawn \
--machine="$MACHINE" \
@@ -16,7 +16,7 @@ set -o pipefail
# RestrictFileSystemAccess= requires +BPF_FRAMEWORK at compile time
if systemctl --version | grep -F -- "-BPF_FRAMEWORK" >/dev/null; then
echo "BPF framework not compiled in, skipping"
exit 0
exit 77
fi
HELPER=/usr/lib/systemd/tests/unit-tests/manual/test-bpf-restrict-fsaccess
@@ -13,24 +13,24 @@ set -o pipefail
if systemctl --version | grep -F -- "-BPF_FRAMEWORK" >/dev/null; then
echo "BPF framework not compiled in, skipping"
exit 0
exit 77
fi
if ! kernel_supports_lsm bpf; then
echo "BPF LSM not available in kernel, skipping"
exit 0
exit 77
fi
if command -v bpftool >/dev/null 2>&1; then
if ! bpftool btf dump file /sys/kernel/btf/vmlinux 2>/dev/null | grep 'bpf_lsm_bdev_setintegrity' >/dev/null; then
echo "Kernel lacks bdev_setintegrity LSM hook, skipping"
exit 0
exit 77
fi
fi
if [[ -v ASAN_OPTIONS ]]; then
echo "Skipping under sanitizers"
exit 0
exit 77
fi
HELPER="/usr/lib/systemd/tests/unit-tests/manual/test-bpf-restrict-fsaccess"
@@ -45,7 +45,7 @@ rc=0
"$HELPER" check >/dev/null 2>&1 || rc=$?
if [[ "$rc" -eq 77 ]]; then
echo "test-bpf-restrict-fsaccess built without BPF attach support, skipping"
exit 0
exit 77
fi
if [[ ! -e /sys/module/dm_verity/parameters/require_signatures ]]; then
@@ -54,7 +54,7 @@ fi
val="$(cat /sys/module/dm_verity/parameters/require_signatures 2>/dev/null || echo)"
if [[ "$val" != "Y" && "$val" != "1" ]]; then
echo "require_signatures not enabled, skipping"
exit 0
exit 77
fi
# Provision the .dm-verity keyring. Empty description lets the kernel derive
@@ -63,7 +63,7 @@ keyid=$(openssl x509 -in /usr/share/mkosi.crt -outform DER |
keyctl padd asymmetric '' %:.dm-verity 2>/dev/null) || keyid=""
if [[ -z "$keyid" ]]; then
echo ".dm-verity keyring not provisionable (kernel < v7.0?), skipping"
exit 0
exit 77
fi
if ! keyctl restrict_keyring %:.dm-verity; then
keyctl unlink "$keyid" %:.dm-verity 2>/dev/null || true
@@ -19,12 +19,12 @@ set -o pipefail
# Skip if prerequisites not met
if systemctl --version | grep -F -- "-BPF_FRAMEWORK" >/dev/null; then
echo "BPF framework not compiled in, skipping"
exit 0
exit 77
fi
if ! kernel_supports_lsm bpf; then
echo "BPF LSM not available in kernel, skipping"
exit 0
exit 77
fi
# Check that the kernel has the bdev_setintegrity LSM hook in BTF.
@@ -32,13 +32,13 @@ fi
if command -v bpftool >/dev/null 2>&1; then
if ! bpftool btf dump file /sys/kernel/btf/vmlinux 2>/dev/null | grep 'bpf_lsm_bdev_setintegrity' >/dev/null; then
echo "Kernel lacks bdev_setintegrity LSM hook (required for RestrictFileSystemAccess=), skipping"
exit 0
exit 77
fi
fi
if [[ -v ASAN_OPTIONS ]]; then
echo "Skipping enforcement test under sanitizers"
exit 0
exit 77
fi
HELPER="/usr/lib/systemd/tests/unit-tests/manual/test-bpf-restrict-fsaccess"
@@ -53,7 +53,7 @@ rc=0
"$HELPER" check >/dev/null 2>&1 || rc=$?
if [[ "$rc" -eq 77 ]]; then
echo "test-bpf-restrict-fsaccess built without BPF attach support, skipping"
exit 0
exit 77
fi
# require_signatures is read-only — must be set via kernel cmdline
@@ -62,12 +62,12 @@ if [[ ! -e /sys/module/dm_verity/parameters/require_signatures ]]; then
fi
if [[ ! -e /sys/module/dm_verity/parameters/require_signatures ]]; then
echo "dm_verity module not available, skipping enforcement test"
exit 0
exit 77
fi
val="$(cat /sys/module/dm_verity/parameters/require_signatures)"
if [[ "$val" != "Y" && "$val" != "1" ]]; then
echo "require_signatures not enabled (need dm-verity.require_signatures=1 on cmdline), skipping"
exit 0
exit 77
fi
at_exit() {
@@ -106,7 +106,7 @@ if ! /tmp/restrict-fsaccess-baseline/true 2>/dev/null; then
echo "WARNING: tmpfs exec blocked BEFORE BPF attach (another LSM?)" >&2
echo "Skipping enforcement test, baseline tmpfs exec fails"
umount /tmp/restrict-fsaccess-baseline; rm -rf /tmp/restrict-fsaccess-baseline
exit 0
exit 77
fi
echo "Baseline: tmpfs exec works without BPF"
umount /tmp/restrict-fsaccess-baseline; rm -rf /tmp/restrict-fsaccess-baseline
+1 -3
View File
@@ -6,6 +6,4 @@ set -o pipefail
# shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh
run_subtests
touch /testok
run_subtests_and_exit
+61 -15
View File
@@ -8,6 +8,11 @@ fi
declare -i _CHILD_PID=0
_PASSED_TESTS=()
_SKIPPED_TESTS=()
# A subtest may exit with this code to report that it skipped itself,
# matching the skip code used by the integration test harness.
_SUBTEST_SKIP_RC=77
# Like trap, but passes the signal name as the first argument
_trap_with_sig() {
@@ -56,7 +61,7 @@ _wait_harder() {
_show_summary() {(
set +x
if [[ ${#_PASSED_TESTS[@]} -eq 0 ]]; then
if [[ ${#_PASSED_TESTS[@]} -eq 0 && ${#_SKIPPED_TESTS[@]} -eq 0 ]]; then
echo >&2 "No tests were executed, this is most likely an error"
exit 1
fi
@@ -66,12 +71,34 @@ _show_summary() {(
for t in "${_PASSED_TESTS[@]}"; do
echo "$t"
done
if [[ ${#_SKIPPED_TESTS[@]} -gt 0 ]]; then
printf "SKIPPED TESTS: %3d:\n" "${#_SKIPPED_TESTS[@]}"
echo "-------------------"
for t in "${_SKIPPED_TESTS[@]}"; do
echo "$t"
done
fi
)}
_record_subtest_rc() {
local subtest="${1:?}" rc="${2:?}"
if [[ $rc -eq $_SUBTEST_SKIP_RC ]]; then
echo "Subtest $subtest skipped"
_SKIPPED_TESTS+=("$subtest")
elif [[ $rc -ne 0 ]]; then
echo "Subtest $subtest failed"
return 1
else
_PASSED_TESTS+=("$subtest")
fi
}
# Like run_subtests, but propagate specified signals to the subtest script
run_subtests_with_signals() {
local subtests=("${0%.sh}".*.sh)
local subtest
local subtest rc
if [[ "${#subtests[@]}" -eq 0 ]]; then
echo >&2 "No subtests found for file $0"
@@ -100,14 +127,11 @@ run_subtests_with_signals() {
: "--- $subtest BEGIN ---"
SECONDS=0
rc=0
"./$subtest" &
_CHILD_PID=$!
if ! _wait_harder "$_CHILD_PID"; then
echo "Subtest $subtest failed"
return 1
fi
_PASSED_TESTS+=("$subtest")
_wait_harder "$_CHILD_PID" || rc=$?
_record_subtest_rc "$subtest" "$rc" || return 1
: "--- $subtest END (${SECONDS}s) ---"
done
@@ -117,7 +141,7 @@ run_subtests_with_signals() {
# Run all subtests (i.e. files named as $TESTNAME.<subtest_name>.sh)
run_subtests() {
local subtests=("${0%.sh}".*.sh)
local subtest
local subtest rc
if [[ "${#subtests[@]}" -eq 0 ]]; then
echo >&2 "No subtests found for file $0"
@@ -139,18 +163,40 @@ run_subtests() {
: "--- $subtest BEGIN ---"
SECONDS=0
if ! "./$subtest"; then
echo "Subtest $subtest failed"
return 1
fi
_PASSED_TESTS+=("$subtest")
rc=0
"./$subtest" || rc=$?
_record_subtest_rc "$subtest" "$rc" || return 1
: "--- $subtest END (${SECONDS}s) ---"
done
_show_summary
}
_finalize_subtests() {
if [[ ${#_PASSED_TESTS[@]} -eq 0 && ${#_SKIPPED_TESTS[@]} -gt 0 ]]; then
echo "All subtests skipped" | tee --append /skipped
exit "$_SUBTEST_SKIP_RC"
fi
touch /testok
exit 0
}
# Run all subtests and finalize the test in one shot: exit 77 (skipped) if every subtest skipped,
# otherwise mark success (/testok) and exit. Use this ONLY for tests whose body is just subtests.
# Do NOT use it if the parent script has meaningful test content of its own.
run_subtests_and_exit() {
run_subtests
_finalize_subtests
}
# Like run_subtests_and_exit, but propagates the given signals to the subtests (see
# run_subtests_with_signals).
run_subtests_with_signals_and_exit() {
run_subtests_with_signals "$@"
_finalize_subtests
}
# Run all test cases (i.e. functions prefixed with testcase_ in the current namespace)
run_testcases() {
local testcase testcases
+21
View File
@@ -576,3 +576,24 @@ find_qemu_binary() {
command -v "qemu-system-$arch" >/dev/null 2>&1
}
# Waits for a systemd-vmspawn machine to register with machined. If vmspawn bailed out because
# vhost-user-fs isn't available (e.g. inside a nested VM) the test is skipped gracefully; any other
# early vmspawn exit is treated as a failure. Args: machine name, vmspawn PID, vmspawn console log.
wait_for_machine() {
local machine="$1" pid="$2" log="$3"
timeout 30 bash -c "
while ! machinectl list --no-legend 2>/dev/null | grep >/dev/null '$machine'; do
if ! kill -0 $pid 2>/dev/null; then
if grep >/dev/null 'virtiofs.*QMP\|vhost-user-fs-pci' '$log'; then
echo 'vhost-user-fs not supported (nested VM?), skipping'
exit 77
fi
echo 'vmspawn exited before registering'
cat '$log'
exit 1
fi
sleep .5
done
"
}