diff options
Diffstat (limited to 'test')
123 files changed, 2361 insertions, 131 deletions
diff --git a/test/README.testsuite b/test/README.testsuite index 5c7aca43a8..fa7e73ce3a 100644 --- a/test/README.testsuite +++ b/test/README.testsuite @@ -36,7 +36,7 @@ you can even skip the "clean" and "setup" if you want to run the machine again. $ sudo make KERNEL_APPEND="systemd.unit=multi-user.target" run You can specify a different kernel and initramfs with $KERNEL_BIN and $INITRD. -(Fedora's default kernel path and initramfs are used by default) +(Fedora's or Debian's default kernel path and initramfs are used by default) $ sudo make KERNEL_BIN=/boot/vmlinuz-foo INITRD=/boot/initramfs-bar clean check diff --git a/test/TEST-01-BASIC/test.sh b/test/TEST-01-BASIC/test.sh index d97fbe24d4..041195dcd8 100755 --- a/test/TEST-01-BASIC/test.sh +++ b/test/TEST-01-BASIC/test.sh @@ -11,7 +11,7 @@ check_result_qemu() { mount ${LOOPDEV}p1 $TESTDIR/root [[ -e $TESTDIR/root/testok ]] && ret=0 [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR - [[ -f $TESTDIR/root/var/log/journal ]] && cp -a $TESTDIR/root/var/log/journal $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR umount $TESTDIR/root [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed ls -l $TESTDIR/journal/*/*.journal @@ -25,8 +25,7 @@ test_run() { else dwarn "can't run QEMU, skipping" fi - if check_nspawn; then - run_nspawn + if run_nspawn; then check_result_nspawn || return 1 else dwarn "can't run systemd-nspawn, skipping" @@ -53,14 +52,21 @@ Description=Testsuite service After=multi-user.target [Service] -ExecStart=/bin/bash -c 'set -x; systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok; while : ;do echo "testsuite service waiting for journal to move to /var/log/journal" > /dev/console ; for i in /var/log/journal/*;do [ -d "\$i" ] && echo "\$i" && break 2; done; sleep 1; done; sleep 1; exit 0;' +ExecStart=/bin/sh -x -c 'systemctl --state=failed --no-legend --no-pager > /failed ; echo OK > /testok' Type=oneshot EOF setup_testsuite - ) + ) || return 1 setup_nspawn_root + # mask some services that we do not want to run in these tests + ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket + ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service + ddebug "umount $TESTDIR/root" umount $TESTDIR/root } diff --git a/test/TEST-02-CRYPTSETUP/test.sh b/test/TEST-02-CRYPTSETUP/test.sh index 4be2365e2f..aea0fc53f6 100755 --- a/test/TEST-02-CRYPTSETUP/test.sh +++ b/test/TEST-02-CRYPTSETUP/test.sh @@ -13,7 +13,7 @@ check_result_qemu() { [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR cryptsetup luksOpen ${LOOPDEV}p2 varcrypt <$TESTDIR/keyfile mount /dev/mapper/varcrypt $TESTDIR/root/var - [[ -f $TESTDIR/root/var/log/journal ]] && cp -a $TESTDIR/root/var/log/journal $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR umount $TESTDIR/root/var umount $TESTDIR/root cryptsetup luksClose /dev/mapper/varcrypt @@ -59,7 +59,7 @@ Description=Testsuite service After=multi-user.target [Service] -ExecStart=/bin/bash -c 'set -x; systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok; while : ;do systemd-cat echo "testsuite service waiting for /var/log/journal" ; echo "testsuite service waiting for journal to move to /var/log/journal" > /dev/console ; for i in /var/log/journal/*;do [ -d "\$i" ] && echo "\$i" && break 2; done; sleep 1; done; sleep 1; exit 0;' +ExecStart=/bin/sh -x -c 'systemctl --state=failed --no-legend --no-pager > /failed ; echo OK > /testok' Type=oneshot EOF @@ -76,8 +76,7 @@ EOF cat >>$initdir/etc/fstab <<EOF /dev/mapper/varcrypt /var ext3 defaults 0 1 EOF - ) - setup_nspawn_root + ) || return 1 ddebug "umount $TESTDIR/root/var" umount $TESTDIR/root/var diff --git a/test/TEST-03-JOBS/test-jobs.sh b/test/TEST-03-JOBS/test-jobs.sh index 6f32c240cd..fa6cf4181a 100755 --- a/test/TEST-03-JOBS/test-jobs.sh +++ b/test/TEST-03-JOBS/test-jobs.sh @@ -4,9 +4,12 @@ # installed job. systemctl start --no-block hello-after-sleep.target -# sleep is now running, hello/start is waiting. Verify that: + systemctl list-jobs > /root/list-jobs.txt -grep 'sleep\.service.*running' /root/list-jobs.txt || exit 1 +while ! grep 'sleep\.service.*running' /root/list-jobs.txt; do + systemctl list-jobs > /root/list-jobs.txt +done + grep 'hello\.service.*waiting' /root/list-jobs.txt || exit 1 # This is supposed to finish quickly, not wait for sleep to finish. @@ -23,7 +26,7 @@ grep 'sleep\.service.*running' /root/list-jobs.txt || exit 1 grep 'hello\.service' /root/list-jobs.txt && exit 1 systemctl stop sleep.service hello-after-sleep.target || exit 1 -# Test for a crash when enqueueing a JOB_NOP when other job already exists +# Test for a crash when enqueuing a JOB_NOP when other job already exists systemctl start --no-block hello-after-sleep.target || exit 1 # hello.service should still be waiting, so these try-restarts will collapse # into NOPs. @@ -46,5 +49,32 @@ systemctl stop --job-mode=replace-irreversibly unstoppable.service || exit 1 # Shutdown of the container/VM will hang if not. systemctl start unstoppable.service || exit 1 +# Test waiting for a started unit(s) to terminate again +cat <<EOF > /run/systemd/system/wait2.service +[Unit] +Description=Wait for 2 seconds +[Service] +ExecStart=/bin/sh -ec 'sleep 2' +EOF +cat <<EOF > /run/systemd/system/wait5fail.service +[Unit] +Description=Wait for 5 seconds and fail +[Service] +ExecStart=/bin/sh -ec 'sleep 5; false' +EOF + +# wait2 succeeds +START_SEC=$(date -u '+%s') +systemctl start --wait wait2.service || exit 1 +END_SEC=$(date -u '+%s') +ELAPSED=$(($END_SEC-$START_SEC)) +[[ "$ELAPSED" -ge 2 ]] && [[ "$ELAPSED" -le 3 ]] || exit 1 + +# wait5fail fails, so systemctl should fail +START_SEC=$(date -u '+%s') +! systemctl start --wait wait2.service wait5fail.service || exit 1 +END_SEC=$(date -u '+%s') +ELAPSED=$(($END_SEC-$START_SEC)) +[[ "$ELAPSED" -ge 5 ]] && [[ "$ELAPSED" -le 7 ]] || exit 1 + touch /testok -exit 0 diff --git a/test/TEST-03-JOBS/test.sh b/test/TEST-03-JOBS/test.sh index 41e02e2c8a..ab0de0bfd1 100755 --- a/test/TEST-03-JOBS/test.sh +++ b/test/TEST-03-JOBS/test.sh @@ -25,8 +25,7 @@ test_run() { else dwarn "can't run QEMU, skipping" fi - if check_nspawn; then - run_nspawn + if run_nspawn; then check_result_nspawn || return 1 else dwarn "can't run systemd-nspawn, skipping" @@ -63,7 +62,7 @@ EOF cp test-jobs.sh $initdir/ setup_testsuite - ) + ) || return 1 setup_nspawn_root ddebug "umount $TESTDIR/root" diff --git a/test/TEST-04-JOURNAL/Makefile b/test/TEST-04-JOURNAL/Makefile new file mode 120000 index 0000000000..e9f93b1104 --- /dev/null +++ b/test/TEST-04-JOURNAL/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile
\ No newline at end of file diff --git a/test/TEST-04-JOURNAL/test-journal.sh b/test/TEST-04-JOURNAL/test-journal.sh new file mode 100755 index 0000000000..6646eccfa7 --- /dev/null +++ b/test/TEST-04-JOURNAL/test-journal.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +set -x +set -e +set -o pipefail + +# Test stdout stream + +# Skip empty lines +ID=$(journalctl --new-id128 | sed -n 2p) +>/expected +printf $'\n\n\n' | systemd-cat -t "$ID" --level-prefix false +journalctl --sync +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +ID=$(journalctl --new-id128 | sed -n 2p) +>/expected +printf $'<5>\n<6>\n<7>\n' | systemd-cat -t "$ID" --level-prefix true +journalctl --sync +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +# Remove trailing spaces +ID=$(journalctl --new-id128 | sed -n 2p) +printf "Trailing spaces\n">/expected +printf $'<5>Trailing spaces \t \n' | systemd-cat -t "$ID" --level-prefix true +journalctl --sync +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +ID=$(journalctl --new-id128 | sed -n 2p) +printf "Trailing spaces\n">/expected +printf $'Trailing spaces \t \n' | systemd-cat -t "$ID" --level-prefix false +journalctl --sync +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +# Don't remove leading spaces +ID=$(journalctl --new-id128 | sed -n 2p) +printf $' \t Leading spaces\n'>/expected +printf $'<5> \t Leading spaces\n' | systemd-cat -t "$ID" --level-prefix true +journalctl --sync +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +ID=$(journalctl --new-id128 | sed -n 2p) +printf $' \t Leading spaces\n'>/expected +printf $' \t Leading spaces\n' | systemd-cat -t "$ID" --level-prefix false +journalctl --sync +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +# Don't lose streams on restart +systemctl start forever-print-hola +sleep 3 +systemctl restart systemd-journald +sleep 3 +systemctl stop forever-print-hola +[[ ! -f "/i-lose-my-logs" ]] + +touch /testok diff --git a/test/TEST-04-JOURNAL/test.sh b/test/TEST-04-JOURNAL/test.sh new file mode 100755 index 0000000000..3ccf113019 --- /dev/null +++ b/test/TEST-04-JOURNAL/test.sh @@ -0,0 +1,84 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="Journal-related tests" + +. $TEST_BASE_DIR/test-functions + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + return $ret +} + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + if run_nspawn; then + check_result_nspawn || return 1 + else + dwarn "can't run systemd-nspawn, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service <<EOF +[Unit] +Description=Testsuite service +After=multi-user.target + +[Service] +ExecStart=/test-journal.sh +Type=oneshot +EOF + + cat >$initdir/etc/systemd/system/forever-print-hola.service <<EOF +[Unit] +Description=ForeverPrintHola service + +[Service] +Type=simple +ExecStart=/bin/sh -x -c 'while :; do printf "Hola\n" || touch /i-lose-my-logs; sleep 1; done' +EOF + + cp test-journal.sh $initdir/ + + setup_testsuite + ) || return 1 + setup_nspawn_root + + ddebug "umount $TESTDIR/root" + umount $TESTDIR/root +} + +test_cleanup() { + umount $TESTDIR/root 2>/dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-05-RLIMITS/Makefile b/test/TEST-05-RLIMITS/Makefile new file mode 120000 index 0000000000..e9f93b1104 --- /dev/null +++ b/test/TEST-05-RLIMITS/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile
\ No newline at end of file diff --git a/test/TEST-05-RLIMITS/test-rlimits.sh b/test/TEST-05-RLIMITS/test-rlimits.sh new file mode 100755 index 0000000000..ba665c5968 --- /dev/null +++ b/test/TEST-05-RLIMITS/test-rlimits.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -x +set -e +set -o pipefail + +[[ "$(systemctl show -p DefaultLimitNOFILESoft)" = "DefaultLimitNOFILESoft=10000" ]] +[[ "$(systemctl show -p DefaultLimitNOFILE)" = "DefaultLimitNOFILE=16384" ]] + +[[ "$(systemctl show -p LimitNOFILESoft testsuite.service)" = "LimitNOFILESoft=10000" ]] +[[ "$(systemctl show -p LimitNOFILE testsuite.service)" = "LimitNOFILE=16384" ]] + +[[ "$(ulimit -n -S)" = "10000" ]] +[[ "$(ulimit -n -H)" = "16384" ]] + +touch /testok diff --git a/test/TEST-05-RLIMITS/test.sh b/test/TEST-05-RLIMITS/test.sh new file mode 100755 index 0000000000..a5f7e8de0b --- /dev/null +++ b/test/TEST-05-RLIMITS/test.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="Resource limits-related tests" + +. $TEST_BASE_DIR/test-functions + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + return $ret +} + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + if run_nspawn; then + check_result_nspawn || return 1 + else + dwarn "can't run systemd-nspawn, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + cat >$initdir/etc/systemd/system.conf <<EOF +[Manager] +DefaultLimitNOFILE=10000:16384 +EOF + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service <<EOF +[Unit] +Description=Testsuite service +After=multi-user.target + +[Service] +ExecStart=/test-rlimits.sh +Type=oneshot +EOF + + cp test-rlimits.sh $initdir/ + + setup_testsuite + ) || return 1 + setup_nspawn_root + + ddebug "umount $TESTDIR/root" + umount $TESTDIR/root +} + +test_cleanup() { + umount $TESTDIR/root 2>/dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-06-SELINUX/Makefile b/test/TEST-06-SELINUX/Makefile new file mode 120000 index 0000000000..e9f93b1104 --- /dev/null +++ b/test/TEST-06-SELINUX/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile
\ No newline at end of file diff --git a/test/TEST-06-SELINUX/systemd_test.if b/test/TEST-06-SELINUX/systemd_test.if new file mode 100644 index 0000000000..25c91adce9 --- /dev/null +++ b/test/TEST-06-SELINUX/systemd_test.if @@ -0,0 +1,8 @@ +template(`systemd_test_base_template', ` + gen_require(` + attribute systemd_test_domain_type; + ') + + type $1_t, systemd_test_domain_type; + domain_type($1_t) +') diff --git a/test/TEST-06-SELINUX/systemd_test.te b/test/TEST-06-SELINUX/systemd_test.te new file mode 100644 index 0000000000..ff01c09b5e --- /dev/null +++ b/test/TEST-06-SELINUX/systemd_test.te @@ -0,0 +1,50 @@ +policy_module(systemd_test, 0.0.1) + +# declarations +attribute systemd_test_domain_type; + +systemd_test_base_template(systemd_test) +systemd_test_base_template(systemd_test_status) +systemd_test_base_template(systemd_test_start) +systemd_test_base_template(systemd_test_stop) +systemd_test_base_template(systemd_test_reload) + +# systemd_test_domain_type + +require { + role system_r; + role unconfined_r; + type bin_t; + type initrc_t; + type systemd_systemctl_exec_t; + type unconfined_service_t; +} + +role system_r types systemd_test_domain_type; +role unconfined_r types systemd_test_domain_type; + +allow systemd_test_domain_type bin_t: file entrypoint; +allow systemd_test_domain_type systemd_systemctl_exec_t: file entrypoint; +allow initrc_t systemd_test_domain_type: process transition; +allow unconfined_service_t systemd_test_domain_type: process transition; +corecmd_exec_bin(systemd_test_domain_type) +init_signal_script(systemd_test_domain_type) +init_sigchld_script(systemd_test_domain_type) +systemd_exec_systemctl(systemd_test_domain_type) +userdom_use_user_ttys(systemd_test_domain_type) +userdom_use_user_ptys(systemd_test_domain_type) + +optional_policy(` + dbus_system_bus_client(systemd_test_domain_type) + init_dbus_chat(systemd_test_domain_type) +') + +# systemd_test_*_t +require { + type systemd_unit_file_t; +} + +allow systemd_test_status_t systemd_unit_file_t: service { status }; +allow systemd_test_start_t systemd_unit_file_t: service { start }; +allow systemd_test_stop_t systemd_unit_file_t: service { stop }; +allow systemd_test_reload_t systemd_unit_file_t: service { reload }; diff --git a/test/TEST-06-SELINUX/test-selinux-checks.sh b/test/TEST-06-SELINUX/test-selinux-checks.sh new file mode 100755 index 0000000000..153fab3aac --- /dev/null +++ b/test/TEST-06-SELINUX/test-selinux-checks.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -x +set -e +set -o pipefail + +echo 1 >/sys/fs/selinux/enforce +runcon -t systemd_test_start_t systemctl start hola +runcon -t systemd_test_reload_t systemctl reload hola +runcon -t systemd_test_stop_t systemctl stop hola + +touch /testok diff --git a/test/TEST-06-SELINUX/test.sh b/test/TEST-06-SELINUX/test.sh new file mode 100755 index 0000000000..1ae4a7c0d9 --- /dev/null +++ b/test/TEST-06-SELINUX/test.sh @@ -0,0 +1,135 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="SELinux tests" + +# Requirements: +# Fedora 23 +# selinux-policy-targeted +# selinux-policy-devel + +. $TEST_BASE_DIR/test-functions +SETUP_SELINUX=yes +KERNEL_APPEND="$KERNEL_APPEND selinux=1 security=selinux" + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + return $ret +} + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + # setup the testsuite service + cat <<EOF >$initdir/etc/systemd/system/testsuite.service +[Unit] +Description=Testsuite service +After=multi-user.target + +[Service] +ExecStart=/test-selinux-checks.sh +Type=oneshot +EOF + + cat <<EOF >$initdir/etc/systemd/system/hola.service +[Service] +Type=oneshot +ExecStart=/bin/echo Start Hola +ExecReload=/bin/echo Reload Hola +ExecStop=/bin/echo Stop Hola +RemainAfterExit=yes +EOF + + setup_testsuite + + cat <<EOF >$initdir/etc/systemd/system/load-systemd-test-module.service +[Unit] +Description=Load systemd-test module +DefaultDependencies=no +Requires=local-fs.target +Conflicts=shutdown.target +After=local-fs.target +Before=sysinit.target shutdown.target autorelabel.service +ConditionSecurity=selinux +ConditionPathExists=|/.load-systemd-test-module + +[Service] +ExecStart=/bin/sh -x -c 'echo 0 >/sys/fs/selinux/enforce && cd /systemd-test-module && make -f /usr/share/selinux/devel/Makefile load && rm /.load-systemd-test-module' +Type=oneshot +TimeoutSec=0 +RemainAfterExit=yes +EOF + + touch $initdir/.load-systemd-test-module + mkdir -p $initdir/etc/systemd/system/basic.target.wants + ln -fs load-systemd-test-module.service $initdir/etc/systemd/system/basic.target.wants/load-systemd-test-module.service + + local _modules_dir=/var/lib/selinux + rm -rf $initdir/$_modules_dir + if ! cp -ar $_modules_dir $initdir/$_modules_dir; then + dfatal "Failed to copy $_modules_dir" + exit 1 + fi + + local _policy_headers_dir=/usr/share/selinux/devel + rm -rf $initdir/$_policy_headers_dir + inst_dir /usr/share/selinux + if ! cp -ar $_policy_headers_dir $initdir/$_policy_headers_dir; then + dfatal "Failed to copy $_policy_headers_dir" + exit 1 + fi + + mkdir $initdir/systemd-test-module + cp systemd_test.te $initdir/systemd-test-module + cp systemd_test.if $initdir/systemd-test-module + cp test-selinux-checks.sh $initdir + dracut_install -o sesearch + dracut_install runcon + dracut_install checkmodule semodule semodule_package m4 make /usr/libexec/selinux/hll/pp load_policy sefcontext_compile + ) || return 1 + + # mask some services that we do not want to run in these tests + ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket + ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service + + ddebug "umount $TESTDIR/root" + umount $TESTDIR/root +} + +test_cleanup() { + umount $TESTDIR/root 2>/dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-07-ISSUE-1981/Makefile b/test/TEST-07-ISSUE-1981/Makefile new file mode 120000 index 0000000000..e9f93b1104 --- /dev/null +++ b/test/TEST-07-ISSUE-1981/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile
\ No newline at end of file diff --git a/test/TEST-07-ISSUE-1981/test-segfault.sh b/test/TEST-07-ISSUE-1981/test-segfault.sh new file mode 100755 index 0000000000..48f05d89fb --- /dev/null +++ b/test/TEST-07-ISSUE-1981/test-segfault.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +set -x +set -e + +>/failed + +cat <<'EOL' >/lib/systemd/system/my.service +[Service] +Type=oneshot +ExecStart=/bin/echo Timer runs me +EOL + +cat <<'EOL' >/lib/systemd/system/my.timer +[Timer] +OnBootSec=10s +OnUnitInactiveSec=1h +EOL + +systemctl unmask my.timer + +systemctl start my.timer + +mkdir -p /etc/systemd/system/my.timer.d/ +cat <<'EOL' >/etc/systemd/system/my.timer.d/override.conf +[Timer] +OnBootSec=10s +OnUnitInactiveSec=1h +EOL + +systemctl daemon-reload + +systemctl mask my.timer + +touch /testok +rm /failed diff --git a/test/TEST-07-ISSUE-1981/test.sh b/test/TEST-07-ISSUE-1981/test.sh new file mode 100755 index 0000000000..2f7f01058e --- /dev/null +++ b/test/TEST-07-ISSUE-1981/test.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/1981" + +. $TEST_BASE_DIR/test-functions + +NSPAWN_TIMEOUT=30s + +test_run() { + dwarn "skipping QEMU" + if run_nspawn; then + check_result_nspawn || return 1 + else + dwarn "can't run systemd-nspawn, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service <<EOF +[Unit] +Description=Testsuite service +After=multi-user.target + +[Service] +ExecStart=/test-segfault.sh +Type=oneshot +EOF + + cp test-segfault.sh $initdir/ + + setup_testsuite + ) || return 1 + setup_nspawn_root + + ddebug "umount $TESTDIR/root" + umount $TESTDIR/root +} + +test_cleanup() { + umount $TESTDIR/root 2>/dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-08-ISSUE-2730/Makefile b/test/TEST-08-ISSUE-2730/Makefile new file mode 120000 index 0000000000..e9f93b1104 --- /dev/null +++ b/test/TEST-08-ISSUE-2730/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile
\ No newline at end of file diff --git a/test/TEST-08-ISSUE-2730/test.sh b/test/TEST-08-ISSUE-2730/test.sh new file mode 100755 index 0000000000..44831983b3 --- /dev/null +++ b/test/TEST-08-ISSUE-2730/test.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/2730" + +. $TEST_BASE_DIR/test-functions +SKIP_INITRD=yes +QEMU_TIMEOUT=180 +FSTYPE=ext4 + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + [ -n "$TIMED_OUT" ] && ret=$(($ret+1)) + return $ret +} + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service <<EOF +[Unit] +Description=Testsuite service +After=multi-user.target + +[Service] +ExecStart=/bin/sh -x -c 'mount -o remount,rw /dev/sda1 && echo OK > /testok; systemctl poweroff' +Type=oneshot +EOF + + rm $initdir/etc/fstab + cat >$initdir/etc/systemd/system/-.mount <<EOF +[Unit] +Before=local-fs.target + +[Mount] +What=/dev/sda1 +Where=/ +Type=ext4 +Options=errors=remount-ro,noatime + +[Install] +WantedBy=local-fs.target +Alias=root.mount +EOF + + cat >$initdir/etc/systemd/system/systemd-remount-fs.service <<EOF +[Unit] +DefaultDependencies=no +Conflicts=shutdown.target +After=systemd-fsck-root.service +Before=local-fs-pre.target local-fs.target shutdown.target +Wants=local-fs-pre.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/systemctl reload / +EOF + + setup_testsuite + ) || return 1 + + ln -s /etc/systemd/system/-.mount $initdir/etc/systemd/system/root.mount + mkdir -p $initdir/etc/systemd/system/local-fs.target.wants + ln -s /etc/systemd/system/-.mount $initdir/etc/systemd/system/local-fs.target.wants/-.mount + + # mask some services that we do not want to run in these tests + ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket + ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service + + ddebug "umount $TESTDIR/root" + umount $TESTDIR/root +} + +test_cleanup() { + umount $TESTDIR/root 2>/dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-09-ISSUE-2691/Makefile b/test/TEST-09-ISSUE-2691/Makefile new file mode 120000 index 0000000000..e9f93b1104 --- /dev/null +++ b/test/TEST-09-ISSUE-2691/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile
\ No newline at end of file diff --git a/test/TEST-09-ISSUE-2691/test.sh b/test/TEST-09-ISSUE-2691/test.sh new file mode 100755 index 0000000000..8ae02e61ac --- /dev/null +++ b/test/TEST-09-ISSUE-2691/test.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/2691" + +. $TEST_BASE_DIR/test-functions +SKIP_INITRD=yes +QEMU_TIMEOUT=90 + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + [ -n "$TIMED_OUT" ] && ret=$(($ret+1)) + return $ret +} + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service <<'EOF' +[Unit] +Description=Testsuite service +After=multi-user.target + +[Service] +Type=oneshot +ExecStart=/bin/sh -c '>/testok' +RemainAfterExit=yes +ExecStop=/bin/sh -c 'kill -SEGV $$$$' +TimeoutStopSec=180s +EOF + + setup_testsuite + ) || return 1 + + # mask some services that we do not want to run in these tests + ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket + ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service + + ddebug "umount $TESTDIR/root" + umount $TESTDIR/root +} + +test_cleanup() { + umount $TESTDIR/root 2>/dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-10-ISSUE-2467/Makefile b/test/TEST-10-ISSUE-2467/Makefile new file mode 120000 index 0000000000..e9f93b1104 --- /dev/null +++ b/test/TEST-10-ISSUE-2467/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile
\ No newline at end of file diff --git a/test/TEST-10-ISSUE-2467/test.sh b/test/TEST-10-ISSUE-2467/test.sh new file mode 100755 index 0000000000..4eca6784bc --- /dev/null +++ b/test/TEST-10-ISSUE-2467/test.sh @@ -0,0 +1,91 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/2467" + +. $TEST_BASE_DIR/test-functions +SKIP_INITRD=yes + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + return $ret +} + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + dracut_install nc true rm + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service <<'EOF' +[Unit] +Description=Testsuite service +After=multi-user.target + +[Service] +Type=oneshot +ExecStart=/bin/sh -e -x -c 'rm -f /tmp/nonexistent; systemctl start test.socket; echo a | nc -U /run/test.ctl; >/testok' +TimeoutStartSec=10s +EOF + + cat >$initdir/etc/systemd/system/test.socket <<'EOF' +[Socket] +ListenStream=/run/test.ctl +EOF + + cat > $initdir/etc/systemd/system/test.service <<'EOF' +[Unit] +Requires=test.socket +ConditionPathExistsGlob=/tmp/nonexistent + +[Service] +ExecStart=/bin/true +EOF + + setup_testsuite + ) || return 1 + + # mask some services that we do not want to run in these tests + ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket + ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service + + ddebug "umount $TESTDIR/root" + umount $TESTDIR/root +} + +test_cleanup() { + umount $TESTDIR/root 2>/dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-11-ISSUE-3166/Makefile b/test/TEST-11-ISSUE-3166/Makefile new file mode 120000 index 0000000000..e9f93b1104 --- /dev/null +++ b/test/TEST-11-ISSUE-3166/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile
\ No newline at end of file diff --git a/test/TEST-11-ISSUE-3166/test.sh b/test/TEST-11-ISSUE-3166/test.sh new file mode 100755 index 0000000000..0f269c8211 --- /dev/null +++ b/test/TEST-11-ISSUE-3166/test.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/3166" + +. $TEST_BASE_DIR/test-functions +SKIP_INITRD=yes + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + return $ret +} + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + dracut_install false touch + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service <<EOF +[Unit] +Description=Testsuite service +After=multi-user.target + +[Service] +ExecStart=/test-fail-on-restart.sh +Type=oneshot +EOF + + cat >$initdir/etc/systemd/system/fail-on-restart.service <<EOF +[Unit] +Description=Fail on restart + +[Service] +Type=simple +ExecStart=/bin/false +Restart=always +EOF + + + cat >$initdir/test-fail-on-restart.sh <<'EOF' +#!/bin/bash -x + +systemctl start fail-on-restart.service +active_state=$(systemctl show --property ActiveState fail-on-restart.service) +while [[ "$active_state" == "ActiveState=activating" || "$active_state" == "ActiveState=active" ]]; do + sleep 1 + active_state=$(systemctl show --property ActiveState fail-on-restart.service) +done +systemctl is-failed fail-on-restart.service || exit 1 +touch /testok +EOF + + chmod 0755 $initdir/test-fail-on-restart.sh + setup_testsuite + ) || return 1 + + ddebug "umount $TESTDIR/root" + umount $TESTDIR/root +} + +test_cleanup() { + umount $TESTDIR/root 2>/dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-12-ISSUE-3171/Makefile b/test/TEST-12-ISSUE-3171/Makefile new file mode 120000 index 0000000000..e9f93b1104 --- /dev/null +++ b/test/TEST-12-ISSUE-3171/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile
\ No newline at end of file diff --git a/test/TEST-12-ISSUE-3171/test.sh b/test/TEST-12-ISSUE-3171/test.sh new file mode 100755 index 0000000000..e20f470143 --- /dev/null +++ b/test/TEST-12-ISSUE-3171/test.sh @@ -0,0 +1,109 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/3171" + +. $TEST_BASE_DIR/test-functions + +test_run() { + if run_nspawn; then + check_result_nspawn || return 1 + else + dwarn "can't run systemd-nspawn, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + dracut_install cat mv stat nc + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service <<EOF +[Unit] +Description=Testsuite service +After=multi-user.target + +[Service] +ExecStart=/test-socket-group.sh +Type=oneshot +EOF + + + cat >$initdir/test-socket-group.sh <<'EOF' +#!/bin/bash +set -x +set -e +set -o pipefail + +U=/run/systemd/system/test.socket +cat <<'EOL' >$U +[Unit] +Description=Test socket +[Socket] +Accept=yes +ListenStream=/run/test.socket +SocketGroup=adm +SocketMode=0660 +EOL + +cat <<'EOL' > /run/systemd/system/test@.service +[Unit] +Description=Test service +[Service] +StandardInput=socket +ExecStart=/bin/sh -x -c cat +EOL + +systemctl start test.socket +systemctl is-active test.socket +[[ "$(stat --format='%G' /run/test.socket)" == adm ]] +echo A | nc -U /run/test.socket + +mv $U ${U}.disabled +systemctl daemon-reload +systemctl is-active test.socket +[[ "$(stat --format='%G' /run/test.socket)" == adm ]] +echo B | nc -U /run/test.socket && exit 1 + +mv ${U}.disabled $U +systemctl daemon-reload +systemctl is-active test.socket +echo C | nc -U /run/test.socket && exit 1 +[[ "$(stat --format='%G' /run/test.socket)" == adm ]] + +systemctl restart test.socket +systemctl is-active test.socket +echo D | nc -U /run/test.socket +[[ "$(stat --format='%G' /run/test.socket)" == adm ]] + + +touch /testok +EOF + + chmod 0755 $initdir/test-socket-group.sh + setup_testsuite + ) || return 1 + + setup_nspawn_root + + ddebug "umount $TESTDIR/root" + umount $TESTDIR/root +} + +test_cleanup() { + umount $TESTDIR/root 2>/dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/end.service b/test/end.service new file mode 100644 index 0000000000..6e1996fd02 --- /dev/null +++ b/test/end.service @@ -0,0 +1,10 @@ +[Unit] +Description=End the test +After=testsuite.service +OnFailure=poweroff.target +OnFailureJobMode=replace-irreversibly + +[Service] +Type=oneshot +ExecStart=/bin/sh -x -c 'systemctl poweroff --no-block' +TimeoutStartSec=5m diff --git a/test/end.service.in b/test/end.service.in deleted file mode 100644 index 4857ffe02b..0000000000 --- a/test/end.service.in +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=End the test -After=testsuite.service - -[Service] -ExecStart=@SYSTEMCTL@ poweroff --no-block diff --git a/test/exec-environment-empty.service b/test/exec-environment-empty.service deleted file mode 100644 index 0219ca4fd7..0000000000 --- a/test/exec-environment-empty.service +++ /dev/null @@ -1,7 +0,0 @@ -[Unit] -Description=Test for Environment - -[Service] -ExecStart=/bin/sh -c 'exit $(test ! "$VAR1" = "word1 word2") && $(test ! "$VAR2" = word3) && $(test ! "$VAR3" = \'$word 5 6\')' -Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6" -Environment= diff --git a/test/exec-environment.service b/test/exec-environment.service deleted file mode 100644 index 4586b4c4a9..0000000000 --- a/test/exec-environment.service +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=Test for Environment - -[Service] -ExecStart=/bin/sh -c 'exit $(test "$VAR1" = "word1 word2") && $(test "$VAR2" = word3) && $(test "$VAR3" = \'$word 5 6\')' -Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6" diff --git a/test/exec-group.service b/test/exec-group.service deleted file mode 100644 index 1aa04b5bd2..0000000000 --- a/test/exec-group.service +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=Test for Group - -[Service] -ExecStart=/bin/sh -c 'exit $(test $(id -n -g) = nobody)' -Group=nobody diff --git a/test/exec-umask-0177.service b/test/exec-umask-0177.service deleted file mode 100644 index af9295888e..0000000000 --- a/test/exec-umask-0177.service +++ /dev/null @@ -1,7 +0,0 @@ -[Unit] -Description=Test for UMask - -[Service] -ExecStart=/bin/sh -c 'touch /tmp/test-exec-umask; s=$(stat -c %a /tmp/test-exec-umask); echo $s; exit $(test $s = "600")' -UMask=0177 -PrivateTmp=yes diff --git a/test/exec-umask-default.service b/test/exec-umask-default.service deleted file mode 100644 index 41e20a60a1..0000000000 --- a/test/exec-umask-default.service +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=Test for UMask default - -[Service] -ExecStart=/bin/sh -c 'touch /tmp/test-exec-umask; s=$(stat -c %a /tmp/test-exec-umask); echo $s; exit $(test $s = "644")' -PrivateTmp=yes diff --git a/test/exec-user.service b/test/exec-user.service deleted file mode 100644 index 2ca08ebb42..0000000000 --- a/test/exec-user.service +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=Test for User - -[Service] -ExecStart=/bin/sh -c 'exit $(test "$USER" = nobody)' -User=nobody diff --git a/test/networkd-test.py b/test/networkd-test.py new file mode 100755 index 0000000000..3091722fc1 --- /dev/null +++ b/test/networkd-test.py @@ -0,0 +1,599 @@ +#!/usr/bin/env python3 +# +# networkd integration test +# This uses temporary configuration in /run and temporary veth devices, and +# does not write anything on disk or change any system configuration; +# but it assumes (and checks at the beginning) that networkd is not currently +# running. +# +# This can be run on a normal installation, in QEMU, nspawn (with +# --private-network), LXD (with "--config raw.lxc=lxc.aa_profile=unconfined"), +# or LXC system containers. You need at least the "ip" tool from the iproute +# package; it is recommended to install dnsmasq too to get full test coverage. +# +# ATTENTION: This uses the *installed* networkd, not the one from the built +# source tree. +# +# (C) 2015 Canonical Ltd. +# Author: Martin Pitt <martin.pitt@ubuntu.com> +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see <http://www.gnu.org/licenses/>. + +import os +import sys +import time +import unittest +import tempfile +import subprocess +import shutil + +networkd_active = subprocess.call(['systemctl', 'is-active', '--quiet', + 'systemd-networkd']) == 0 +have_dnsmasq = shutil.which('dnsmasq') + +RESOLV_CONF = '/run/systemd/resolve/resolv.conf' + + +@unittest.skipIf(networkd_active, + 'networkd is already active') +class ClientTestBase: + def setUp(self): + self.iface = 'test_eth42' + self.if_router = 'router_eth42' + self.workdir_obj = tempfile.TemporaryDirectory() + self.workdir = self.workdir_obj.name + self.config = '/run/systemd/network/test_eth42.network' + + # avoid "Failed to open /dev/tty" errors in containers + os.environ['SYSTEMD_LOG_TARGET'] = 'journal' + + # determine path to systemd-networkd-wait-online + for p in ['/usr/lib/systemd/systemd-networkd-wait-online', + '/lib/systemd/systemd-networkd-wait-online']: + if os.path.exists(p): + self.networkd_wait_online = p + break + else: + self.fail('systemd-networkd-wait-online not found') + + # get current journal cursor + out = subprocess.check_output(['journalctl', '-b', '--quiet', + '--no-pager', '-n0', '--show-cursor'], + universal_newlines=True) + self.assertTrue(out.startswith('-- cursor:')) + self.journal_cursor = out.split()[-1] + + def tearDown(self): + self.shutdown_iface() + subprocess.call(['systemctl', 'stop', 'systemd-networkd']) + + def writeConfig(self, fname, contents): + os.makedirs(os.path.dirname(fname), exist_ok=True) + with open(fname, 'w') as f: + f.write(contents) + self.addCleanup(os.remove, fname) + + def show_journal(self, unit): + '''Show journal of given unit since start of the test''' + + print('---- %s ----' % unit) + sys.stdout.flush() + subprocess.call(['journalctl', '-b', '--no-pager', '--quiet', + '--cursor', self.journal_cursor, '-u', unit]) + + def create_iface(self, ipv6=False): + '''Create test interface with DHCP server behind it''' + + raise NotImplementedError('must be implemented by a subclass') + + def shutdown_iface(self): + '''Remove test interface and stop DHCP server''' + + raise NotImplementedError('must be implemented by a subclass') + + def print_server_log(self): + '''Print DHCP server log for debugging failures''' + + raise NotImplementedError('must be implemented by a subclass') + + def do_test(self, coldplug=True, ipv6=False, extra_opts='', + online_timeout=10, dhcp_mode='yes'): + subprocess.check_call(['systemctl', 'start', 'systemd-resolved']) + self.writeConfig(self.config, '''\ +[Match] +Name=%s +[Network] +DHCP=%s +%s''' % (self.iface, dhcp_mode, extra_opts)) + + if coldplug: + # create interface first, then start networkd + self.create_iface(ipv6=ipv6) + subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) + else: + # start networkd first, then create interface + subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) + self.create_iface(ipv6=ipv6) + + try: + subprocess.check_call([self.networkd_wait_online, '--interface', + self.iface, '--timeout=%i' % online_timeout]) + + if ipv6: + # check iface state and IP 6 address; FIXME: we need to wait a bit + # longer, as the iface is "configured" already with IPv4 *or* + # IPv6, but we want to wait for both + for timeout in range(10): + out = subprocess.check_output(['ip', 'a', 'show', 'dev', self.iface]) + if b'state UP' in out and b'inet6 2600' in out and b'inet 192.168' in out: + break + time.sleep(1) + else: + self.fail('timed out waiting for IPv6 configuration') + + self.assertRegex(out, b'inet6 2600::.* scope global .*dynamic') + self.assertRegex(out, b'inet6 fe80::.* scope link') + else: + # should have link-local address on IPv6 only + out = subprocess.check_output(['ip', '-6', 'a', 'show', 'dev', self.iface]) + self.assertRegex(out, b'inet6 fe80::.* scope link') + self.assertNotIn(b'scope global', out) + + # should have IPv4 address + out = subprocess.check_output(['ip', '-4', 'a', 'show', 'dev', self.iface]) + self.assertIn(b'state UP', out) + self.assertRegex(out, b'inet 192.168.5.\d+/.* scope global dynamic') + + # check networkctl state + out = subprocess.check_output(['networkctl']) + self.assertRegex(out, ('%s\s+ether\s+routable\s+unmanaged' % self.if_router).encode()) + self.assertRegex(out, ('%s\s+ether\s+routable\s+configured' % self.iface).encode()) + + out = subprocess.check_output(['networkctl', 'status', self.iface]) + self.assertRegex(out, b'Type:\s+ether') + self.assertRegex(out, b'State:\s+routable.*configured') + self.assertRegex(out, b'Address:\s+192.168.5.\d+') + if ipv6: + self.assertRegex(out, b'2600::') + else: + self.assertNotIn(b'2600::', out) + self.assertRegex(out, b'fe80::') + self.assertRegex(out, b'Gateway:\s+192.168.5.1') + self.assertRegex(out, b'DNS:\s+192.168.5.1') + except (AssertionError, subprocess.CalledProcessError): + # show networkd status, journal, and DHCP server log on failure + with open(self.config) as f: + print('\n---- %s ----\n%s' % (self.config, f.read())) + print('---- interface status ----') + sys.stdout.flush() + subprocess.call(['ip', 'a', 'show', 'dev', self.iface]) + print('---- networkctl status %s ----' % self.iface) + sys.stdout.flush() + subprocess.call(['networkctl', 'status', self.iface]) + self.show_journal('systemd-networkd.service') + self.print_server_log() + raise + + for timeout in range(50): + with open(RESOLV_CONF) as f: + contents = f.read() + if 'nameserver 192.168.5.1\n' in contents: + break + time.sleep(0.1) + else: + self.fail('nameserver 192.168.5.1 not found in ' + RESOLV_CONF) + + if not coldplug: + # check post-down.d hook + self.shutdown_iface() + + def test_coldplug_dhcp_yes_ip4(self): + # we have a 12s timeout on RA, so we need to wait longer + self.do_test(coldplug=True, ipv6=False, online_timeout=15) + + def test_coldplug_dhcp_yes_ip4_no_ra(self): + # with disabling RA explicitly things should be fast + self.do_test(coldplug=True, ipv6=False, + extra_opts='IPv6AcceptRA=False') + + def test_coldplug_dhcp_ip4_only(self): + # we have a 12s timeout on RA, so we need to wait longer + self.do_test(coldplug=True, ipv6=False, dhcp_mode='ipv4', + online_timeout=15) + + def test_coldplug_dhcp_ip4_only_no_ra(self): + # with disabling RA explicitly things should be fast + self.do_test(coldplug=True, ipv6=False, dhcp_mode='ipv4', + extra_opts='IPv6AcceptRA=False') + + def test_coldplug_dhcp_ip6(self): + self.do_test(coldplug=True, ipv6=True) + + def test_hotplug_dhcp_ip4(self): + # With IPv4 only we have a 12s timeout on RA, so we need to wait longer + self.do_test(coldplug=False, ipv6=False, online_timeout=15) + + def test_hotplug_dhcp_ip6(self): + self.do_test(coldplug=False, ipv6=True) + + def test_route_only_dns(self): + self.writeConfig('/run/systemd/network/myvpn.netdev', '''\ +[NetDev] +Name=dummy0 +Kind=dummy +MACAddress=12:34:56:78:9a:bc''') + self.writeConfig('/run/systemd/network/myvpn.network', '''\ +[Match] +Name=dummy0 +[Network] +Address=192.168.42.100 +DNS=192.168.42.1 +Domains= ~company''') + + self.do_test(coldplug=True, ipv6=False, + extra_opts='IPv6AcceptRouterAdvertisements=False') + + with open(RESOLV_CONF) as f: + contents = f.read() + # ~company is not a search domain, only a routing domain + self.assertNotRegex(contents, 'search.*company') + # our global server should appear + self.assertIn('nameserver 192.168.5.1\n', contents) + # should not have domain-restricted server as global server + self.assertNotIn('nameserver 192.168.42.1\n', contents) + + def test_route_only_dns_all_domains(self): + with open('/run/systemd/network/myvpn.netdev', 'w') as f: + f.write('''[NetDev] +Name=dummy0 +Kind=dummy +MACAddress=12:34:56:78:9a:bc''') + with open('/run/systemd/network/myvpn.network', 'w') as f: + f.write('''[Match] +Name=dummy0 +[Network] +Address=192.168.42.100 +DNS=192.168.42.1 +Domains= ~company ~.''') + self.addCleanup(os.remove, '/run/systemd/network/myvpn.netdev') + self.addCleanup(os.remove, '/run/systemd/network/myvpn.network') + + self.do_test(coldplug=True, ipv6=False, + extra_opts='IPv6AcceptRouterAdvertisements=False') + + with open(RESOLV_CONF) as f: + contents = f.read() + + # ~company is not a search domain, only a routing domain + self.assertNotRegex(contents, 'search.*company') + + # our global server should appear + self.assertIn('nameserver 192.168.5.1\n', contents) + # should have company server as global server due to ~. + self.assertIn('nameserver 192.168.42.1\n', contents) + + +@unittest.skipUnless(have_dnsmasq, 'dnsmasq not installed') +class DnsmasqClientTest(ClientTestBase, unittest.TestCase): + '''Test networkd client against dnsmasq''' + + def setUp(self): + super().setUp() + self.dnsmasq = None + + def create_iface(self, ipv6=False, dnsmasq_opts=None): + '''Create test interface with DHCP server behind it''' + + # add veth pair + subprocess.check_call(['ip', 'link', 'add', 'name', self.iface, 'type', + 'veth', 'peer', 'name', self.if_router]) + + # give our router an IP + subprocess.check_call(['ip', 'a', 'flush', 'dev', self.if_router]) + subprocess.check_call(['ip', 'a', 'add', '192.168.5.1/24', 'dev', self.if_router]) + if ipv6: + subprocess.check_call(['ip', 'a', 'add', '2600::1/64', 'dev', self.if_router]) + subprocess.check_call(['ip', 'link', 'set', self.if_router, 'up']) + + # add DHCP server + self.dnsmasq_log = os.path.join(self.workdir, 'dnsmasq.log') + lease_file = os.path.join(self.workdir, 'dnsmasq.leases') + if ipv6: + extra_opts = ['--enable-ra', '--dhcp-range=2600::10,2600::20'] + else: + extra_opts = [] + if dnsmasq_opts: + extra_opts += dnsmasq_opts + self.dnsmasq = subprocess.Popen( + ['dnsmasq', '--keep-in-foreground', '--log-queries', + '--log-facility=' + self.dnsmasq_log, '--conf-file=/dev/null', + '--dhcp-leasefile=' + lease_file, '--bind-interfaces', + '--interface=' + self.if_router, '--except-interface=lo', + '--dhcp-range=192.168.5.10,192.168.5.200'] + extra_opts) + + def shutdown_iface(self): + '''Remove test interface and stop DHCP server''' + + if self.if_router: + subprocess.check_call(['ip', 'link', 'del', 'dev', self.if_router]) + self.if_router = None + if self.dnsmasq: + self.dnsmasq.kill() + self.dnsmasq.wait() + self.dnsmasq = None + + def print_server_log(self): + '''Print DHCP server log for debugging failures''' + + with open(self.dnsmasq_log) as f: + sys.stdout.write('\n\n---- dnsmasq log ----\n%s\n------\n\n' % f.read()) + + def test_resolved_domain_restricted_dns(self): + '''resolved: domain-restricted DNS servers''' + + # create interface for generic connections; this will map all DNS names + # to 192.168.42.1 + self.create_iface(dnsmasq_opts=['--address=/#/192.168.42.1']) + self.writeConfig('/run/systemd/network/general.network', '''\ +[Match] +Name=%s +[Network] +DHCP=ipv4 +IPv6AcceptRA=False''' % self.iface) + + # create second device/dnsmasq for a .company/.lab VPN interface + # static IPs for simplicity + subprocess.check_call(['ip', 'link', 'add', 'name', 'testvpnclient', 'type', + 'veth', 'peer', 'name', 'testvpnrouter']) + self.addCleanup(subprocess.call, ['ip', 'link', 'del', 'dev', 'testvpnrouter']) + subprocess.check_call(['ip', 'a', 'flush', 'dev', 'testvpnrouter']) + subprocess.check_call(['ip', 'a', 'add', '10.241.3.1/24', 'dev', 'testvpnrouter']) + subprocess.check_call(['ip', 'link', 'set', 'testvpnrouter', 'up']) + + vpn_dnsmasq_log = os.path.join(self.workdir, 'dnsmasq-vpn.log') + vpn_dnsmasq = subprocess.Popen( + ['dnsmasq', '--keep-in-foreground', '--log-queries', + '--log-facility=' + vpn_dnsmasq_log, '--conf-file=/dev/null', + '--dhcp-leasefile=/dev/null', '--bind-interfaces', + '--interface=testvpnrouter', '--except-interface=lo', + '--address=/math.lab/10.241.3.3', '--address=/cantina.company/10.241.4.4']) + self.addCleanup(vpn_dnsmasq.wait) + self.addCleanup(vpn_dnsmasq.kill) + + self.writeConfig('/run/systemd/network/vpn.network', '''\ +[Match] +Name=testvpnclient +[Network] +IPv6AcceptRA=False +Address=10.241.3.2/24 +DNS=10.241.3.1 +Domains= ~company ~lab''') + + subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) + subprocess.check_call([self.networkd_wait_online, '--interface', self.iface, + '--interface=testvpnclient', '--timeout=20']) + + # ensure we start fresh with every test + subprocess.check_call(['systemctl', 'restart', 'systemd-resolved']) + + # test vpnclient specific domains; these should *not* be answered by + # the general DNS + out = subprocess.check_output(['systemd-resolve', 'math.lab']) + self.assertIn(b'math.lab: 10.241.3.3', out) + out = subprocess.check_output(['systemd-resolve', 'kettle.cantina.company']) + self.assertIn(b'kettle.cantina.company: 10.241.4.4', out) + + # test general domains + out = subprocess.check_output(['systemd-resolve', 'megasearch.net']) + self.assertIn(b'megasearch.net: 192.168.42.1', out) + + with open(self.dnsmasq_log) as f: + general_log = f.read() + with open(vpn_dnsmasq_log) as f: + vpn_log = f.read() + + # VPN domains should only be sent to VPN DNS + self.assertRegex(vpn_log, 'query.*math.lab') + self.assertRegex(vpn_log, 'query.*cantina.company') + self.assertNotIn('lab', general_log) + self.assertNotIn('company', general_log) + + # general domains should not be sent to the VPN DNS + self.assertRegex(general_log, 'query.*megasearch.net') + self.assertNotIn('megasearch.net', vpn_log) + + +class NetworkdClientTest(ClientTestBase, unittest.TestCase): + '''Test networkd client against networkd server''' + + def setUp(self): + super().setUp() + self.dnsmasq = None + + def create_iface(self, ipv6=False): + '''Create test interface with DHCP server behind it''' + + # run "router-side" networkd in own mount namespace to shield it from + # "client-side" configuration and networkd + (fd, script) = tempfile.mkstemp(prefix='networkd-router.sh') + self.addCleanup(os.remove, script) + with os.fdopen(fd, 'w+') as f: + f.write('''\ +#!/bin/sh -eu +mkdir -p /run/systemd/network +mkdir -p /run/systemd/netif +mount -t tmpfs none /run/systemd/network +mount -t tmpfs none /run/systemd/netif +[ ! -e /run/dbus ] || mount -t tmpfs none /run/dbus +# create router/client veth pair +cat << EOF > /run/systemd/network/test.netdev +[NetDev] +Name=%(ifr)s +Kind=veth + +[Peer] +Name=%(ifc)s +EOF + +cat << EOF > /run/systemd/network/test.network +[Match] +Name=%(ifr)s + +[Network] +Address=192.168.5.1/24 +%(addr6)s +DHCPServer=yes + +[DHCPServer] +PoolOffset=10 +PoolSize=50 +DNS=192.168.5.1 +EOF + +# run networkd as in systemd-networkd.service +exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ { s/^.*=//; p}') +''' % {'ifr': self.if_router, 'ifc': self.iface, 'addr6': ipv6 and 'Address=2600::1/64' or ''}) + + os.fchmod(fd, 0o755) + + subprocess.check_call(['systemd-run', '--unit=networkd-test-router.service', + '-p', 'InaccessibleDirectories=-/etc/systemd/network', + '-p', 'InaccessibleDirectories=-/run/systemd/network', + '-p', 'InaccessibleDirectories=-/run/systemd/netif', + '--service-type=notify', script]) + + # wait until devices got created + for timeout in range(50): + out = subprocess.check_output(['ip', 'a', 'show', 'dev', self.if_router]) + if b'state UP' in out and b'scope global' in out: + break + time.sleep(0.1) + + def shutdown_iface(self): + '''Remove test interface and stop DHCP server''' + + if self.if_router: + subprocess.check_call(['systemctl', 'stop', 'networkd-test-router.service']) + # ensure failed transient unit does not stay around + subprocess.call(['systemctl', 'reset-failed', 'networkd-test-router.service']) + subprocess.call(['ip', 'link', 'del', 'dev', self.if_router]) + self.if_router = None + + def print_server_log(self): + '''Print DHCP server log for debugging failures''' + + self.show_journal('networkd-test-router.service') + + @unittest.skip('networkd does not have DHCPv6 server support') + def test_hotplug_dhcp_ip6(self): + pass + + @unittest.skip('networkd does not have DHCPv6 server support') + def test_coldplug_dhcp_ip6(self): + pass + + def test_search_domains(self): + + # we don't use this interface for this test + self.if_router = None + + self.writeConfig('/run/systemd/network/test.netdev', '''\ +[NetDev] +Name=dummy0 +Kind=dummy +MACAddress=12:34:56:78:9a:bc''') + self.writeConfig('/run/systemd/network/test.network', '''\ +[Match] +Name=dummy0 +[Network] +Address=192.168.42.100 +DNS=192.168.42.1 +Domains= one two three four five six seven eight nine ten''') + + subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) + + for timeout in range(50): + with open(RESOLV_CONF) as f: + contents = f.read() + if ' one' in contents: + break + time.sleep(0.1) + self.assertRegex(contents, 'search .*one two three four') + self.assertNotIn('seven\n', contents) + self.assertIn('# Too many search domains configured, remaining ones ignored.\n', contents) + + def test_search_domains_too_long(self): + + # we don't use this interface for this test + self.if_router = None + + name_prefix = 'a' * 60 + + self.writeConfig('/run/systemd/network/test.netdev', '''\ +[NetDev] +Name=dummy0 +Kind=dummy +MACAddress=12:34:56:78:9a:bc''') + self.writeConfig('/run/systemd/network/test.network', '''\ +[Match] +Name=dummy0 +[Network] +Address=192.168.42.100 +DNS=192.168.42.1 +Domains={p}0 {p}1 {p}2 {p}3 {p}4'''.format(p=name_prefix)) + + subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) + + for timeout in range(50): + with open(RESOLV_CONF) as f: + contents = f.read() + if ' one' in contents: + break + time.sleep(0.1) + self.assertRegex(contents, 'search .*{p}0 {p}1 {p}2'.format(p=name_prefix)) + self.assertIn('# Total length of all search domains is too long, remaining ones ignored.', contents) + + def test_dropin(self): + # we don't use this interface for this test + self.if_router = None + + self.writeConfig('/run/systemd/network/test.netdev', '''\ +[NetDev] +Name=dummy0 +Kind=dummy +MACAddress=12:34:56:78:9a:bc''') + self.writeConfig('/run/systemd/network/test.network', '''\ +[Match] +Name=dummy0 +[Network] +Address=192.168.42.100 +DNS=192.168.42.1''') + self.writeConfig('/run/systemd/network/test.network.d/dns.conf', '''\ +[Network] +DNS=127.0.0.1''') + + subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) + + for timeout in range(50): + with open(RESOLV_CONF) as f: + contents = f.read() + if ' 127.0.0.1' in contents: + break + time.sleep(0.1) + self.assertIn('nameserver 192.168.42.1\n', contents) + self.assertIn('nameserver 127.0.0.1\n', contents) + +if __name__ == '__main__': + unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, + verbosity=2)) diff --git a/test/parent.slice b/test/parent.slice index 0222f8eb47..a95f90392d 100644 --- a/test/parent.slice +++ b/test/parent.slice @@ -2,4 +2,4 @@ Description=Parent Slice [Slice] -BlockIOWeight=200 +IOWeight=200 diff --git a/test/paths.target b/test/paths.target deleted file mode 120000 index e9939c9801..0000000000 --- a/test/paths.target +++ /dev/null @@ -1 +0,0 @@ -../units/paths.target
\ No newline at end of file diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py index 721e53a4ee..838dd57a6f 100644..100755 --- a/test/sysv-generator-test.py +++ b/test/sysv-generator-test.py @@ -1,3 +1,5 @@ +#!/usr/bin/python +# # systemd-sysv-generator integration test # # (C) 2015 Canonical Ltd. @@ -23,6 +25,7 @@ import subprocess import tempfile import shutil from glob import glob +import collections try: from configparser import RawConfigParser @@ -32,6 +35,12 @@ except ImportError: sysv_generator = os.path.join(os.environ.get('builddir', '.'), 'systemd-sysv-generator') +class MultiDict(collections.OrderedDict): + def __setitem__(self, key, value): + if isinstance(value, list) and key in self: + self[key].extend(value) + else: + super(MultiDict, self).__setitem__(key, value) class SysvGeneratorTest(unittest.TestCase): def setUp(self): @@ -77,7 +86,14 @@ class SysvGeneratorTest(unittest.TestCase): for service in glob(self.out_dir + '/*.service'): if os.path.islink(service): continue - cp = RawConfigParser() + try: + # for python3 we need here strict=False to parse multiple + # lines with the same key + cp = RawConfigParser(dict_type=MultiDict, strict=False) + except TypeError: + # RawConfigParser in python2 does not have the strict option + # but it allows multiple lines with the same key by default + cp = RawConfigParser(dict_type=MultiDict) cp.optionxform = lambda o: o # don't lower-case option names with open(service) as f: cp.readfp(f) @@ -224,7 +240,7 @@ class SysvGeneratorTest(unittest.TestCase): s = self.run_generator()[1]['foo.service'] self.assertEqual(set(s.options('Unit')), set(['Documentation', 'SourcePath', 'Description', 'After'])) - self.assertEqual(s.get('Unit', 'After'), 'nss-lookup.target rpcbind.target') + self.assertEqual(s.get('Unit', 'After').split(), ['nss-lookup.target', 'rpcbind.target']) def test_lsb_deps(self): '''LSB header dependencies to other services''' @@ -381,11 +397,12 @@ class SysvGeneratorTest(unittest.TestCase): # backup files (not enabled in rcN.d/) shutil.copy(script, script + '.bak') shutil.copy(script, script + '.old') + shutil.copy(script, script + '.tmp') + shutil.copy(script, script + '.new') err, results = self.run_generator() print(err) - self.assertEqual(sorted(results), - ['foo.bak.service', 'foo.old.service', 'foo.service']) + self.assertEqual(sorted(results), ['foo.service', 'foo.tmp.service']) # ensure we don't try to create a symlink to itself self.assertNotIn('itself', err) diff --git a/test/test-efi-create-disk.sh b/test/test-efi-create-disk.sh index 56dd09abd7..cd4699dc18 100755 --- a/test/test-efi-create-disk.sh +++ b/test/test-efi-create-disk.sh @@ -11,8 +11,8 @@ mkfs.vfat -F32 ${LOOP}p1 mkdir -p mnt mount ${LOOP}p1 mnt -mkdir -p mnt/EFI/{Boot,systemd} -cp systemd-bootx64.efi mnt/EFI/Boot/bootx64.efi +mkdir -p mnt/EFI/{BOOT,systemd} +cp systemd-bootx64.efi mnt/EFI/BOOT/BOOTX64.efi [ -e /boot/shellx64.efi ] && cp /boot/shellx64.efi mnt/ diff --git a/test/test-execute/exec-capabilityambientset-merge-nfsnobody.service b/test/test-execute/exec-capabilityambientset-merge-nfsnobody.service new file mode 100644 index 0000000000..00bec581b5 --- /dev/null +++ b/test/test-execute/exec-capabilityambientset-merge-nfsnobody.service @@ -0,0 +1,9 @@ +[Unit] +Description=Test for AmbientCapabilities + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"' +Type=oneshot +User=nfsnobody +AmbientCapabilities=CAP_NET_ADMIN +AmbientCapabilities=CAP_NET_RAW diff --git a/test/test-execute/exec-capabilityambientset-merge.service b/test/test-execute/exec-capabilityambientset-merge.service new file mode 100644 index 0000000000..64964380e2 --- /dev/null +++ b/test/test-execute/exec-capabilityambientset-merge.service @@ -0,0 +1,9 @@ +[Unit] +Description=Test for AmbientCapabilities + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"' +Type=oneshot +User=nobody +AmbientCapabilities=CAP_NET_ADMIN +AmbientCapabilities=CAP_NET_RAW diff --git a/test/test-execute/exec-capabilityambientset-nfsnobody.service b/test/test-execute/exec-capabilityambientset-nfsnobody.service new file mode 100644 index 0000000000..614cfdd584 --- /dev/null +++ b/test/test-execute/exec-capabilityambientset-nfsnobody.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for AmbientCapabilities + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"' +Type=oneshot +User=nfsnobody +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW diff --git a/test/test-execute/exec-capabilityambientset.service b/test/test-execute/exec-capabilityambientset.service new file mode 100644 index 0000000000..d63f884ef8 --- /dev/null +++ b/test/test-execute/exec-capabilityambientset.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for AmbientCapabilities + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"' +Type=oneshot +User=nobody +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW diff --git a/test/test-execute/exec-capabilityboundingset-invert.service b/test/test-execute/exec-capabilityboundingset-invert.service new file mode 100644 index 0000000000..fd5d248702 --- /dev/null +++ b/test/test-execute/exec-capabilityboundingset-invert.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for CapabilityBoundingSet + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "^Bounding set .*cap_chown"); test -z "$$c"' +Type=oneshot +CapabilityBoundingSet=~CAP_CHOWN diff --git a/test/test-execute/exec-capabilityboundingset-merge.service b/test/test-execute/exec-capabilityboundingset-merge.service new file mode 100644 index 0000000000..5c7fcaf437 --- /dev/null +++ b/test/test-execute/exec-capabilityboundingset-merge.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for CapabilityBoundingSet + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set =cap_chown,cap_fowner,cap_kill"' +Type=oneshot +CapabilityBoundingSet=CAP_FOWNER +CapabilityBoundingSet=CAP_KILL CAP_CHOWN diff --git a/test/test-execute/exec-capabilityboundingset-reset.service b/test/test-execute/exec-capabilityboundingset-reset.service new file mode 100644 index 0000000000..d7d3320204 --- /dev/null +++ b/test/test-execute/exec-capabilityboundingset-reset.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for CapabilityBoundingSet + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set ="' +Type=oneshot +CapabilityBoundingSet=CAP_FOWNER CAP_KILL +CapabilityBoundingSet= diff --git a/test/test-execute/exec-capabilityboundingset-simple.service b/test/test-execute/exec-capabilityboundingset-simple.service new file mode 100644 index 0000000000..bf1a7f575a --- /dev/null +++ b/test/test-execute/exec-capabilityboundingset-simple.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for CapabilityBoundingSet + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set =cap_fowner,cap_kill"' +Type=oneshot +CapabilityBoundingSet=CAP_FOWNER CAP_KILL diff --git a/test/test-execute/exec-environment-empty.service b/test/test-execute/exec-environment-empty.service new file mode 100644 index 0000000000..9c92d4bc81 --- /dev/null +++ b/test/test-execute/exec-environment-empty.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for Environment + +[Service] +ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"' +Type=oneshot +Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6" +Environment= diff --git a/test/exec-environment-multiple.service b/test/test-execute/exec-environment-multiple.service index 479005a5d8..b9bc225635 100644 --- a/test/exec-environment-multiple.service +++ b/test/test-execute/exec-environment-multiple.service @@ -2,6 +2,7 @@ Description=Test for Environment [Service] -ExecStart=/bin/sh -c 'exit $(test "$VAR1" = "word1 word2") && $(test "$VAR2" = word3) && $(test "$VAR3" = foobar)' +ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = foobar' +Type=oneshot Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6" Environment="VAR3=foobar" diff --git a/test/test-execute/exec-environment.service b/test/test-execute/exec-environment.service new file mode 100644 index 0000000000..06e77af220 --- /dev/null +++ b/test/test-execute/exec-environment.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for Environment + +[Service] +ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"' +Type=oneshot +Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6" diff --git a/test/test-execute/exec-environmentfile.service b/test/test-execute/exec-environmentfile.service new file mode 100644 index 0000000000..f6b8462719 --- /dev/null +++ b/test/test-execute/exec-environmentfile.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for EnvironmentFile + +[Service] +ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"' +Type=oneshot +EnvironmentFile=/tmp/test-exec_environmentfile.conf diff --git a/test/test-execute/exec-group-nfsnobody.service b/test/test-execute/exec-group-nfsnobody.service new file mode 100644 index 0000000000..e02100a869 --- /dev/null +++ b/test/test-execute/exec-group-nfsnobody.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for Group + +[Service] +ExecStart=/bin/sh -x -c 'test "$$(id -n -g)" = "nfsnobody"' +Type=oneshot +Group=nfsnobody diff --git a/test/test-execute/exec-group.service b/test/test-execute/exec-group.service new file mode 100644 index 0000000000..be7c796912 --- /dev/null +++ b/test/test-execute/exec-group.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for Group + +[Service] +ExecStart=/bin/sh -x -c 'test "$$(id -n -g)" = "nobody"' +Type=oneshot +Group=nobody diff --git a/test/exec-ignoresigpipe-no.service b/test/test-execute/exec-ignoresigpipe-no.service index 69b2e9d8a8..73addf5f05 100644 --- a/test/exec-ignoresigpipe-no.service +++ b/test/test-execute/exec-ignoresigpipe-no.service @@ -2,6 +2,6 @@ Description=Test for IgnoreSIGPIPE=no [Service] -ExecStart=/bin/sh -c 'kill -PIPE 0' +ExecStart=/bin/sh -x -c 'kill -PIPE 0' Type=oneshot IgnoreSIGPIPE=no diff --git a/test/exec-ignoresigpipe-yes.service b/test/test-execute/exec-ignoresigpipe-yes.service index 877ec8aed0..f81c01719e 100644 --- a/test/exec-ignoresigpipe-yes.service +++ b/test/test-execute/exec-ignoresigpipe-yes.service @@ -2,6 +2,6 @@ Description=Test for IgnoreSIGPIPE=yes [Service] -ExecStart=/bin/sh -c 'kill -PIPE 0' +ExecStart=/bin/sh -x -c 'kill -PIPE 0' Type=oneshot IgnoreSIGPIPE=yes diff --git a/test/test-execute/exec-inaccessiblepaths-mount-propagation.service b/test/test-execute/exec-inaccessiblepaths-mount-propagation.service new file mode 100644 index 0000000000..23c6ff3f93 --- /dev/null +++ b/test/test-execute/exec-inaccessiblepaths-mount-propagation.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test to make sure that InaccessiblePaths= disconnect mount propagation + +[Service] +InaccessiblePaths=-/i-dont-exist +ExecStart=/bin/sh -x -c 'mkdir -p /TEST; mount -t tmpfs tmpfs /TEST; grep TEST /proc/self/mountinfo && ! grep TEST /proc/$${PPID}/mountinfo && ! grep TEST /proc/1/mountinfo' +Type=oneshot diff --git a/test/test-execute/exec-ioschedulingclass-best-effort.service b/test/test-execute/exec-ioschedulingclass-best-effort.service new file mode 100644 index 0000000000..29bb8510b4 --- /dev/null +++ b/test/test-execute/exec-ioschedulingclass-best-effort.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for IOSchedulingClass=best-effort + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "best-effort"' +Type=oneshot +IOSchedulingClass=best-effort diff --git a/test/test-execute/exec-ioschedulingclass-idle.service b/test/test-execute/exec-ioschedulingclass-idle.service new file mode 100644 index 0000000000..87dbed14c1 --- /dev/null +++ b/test/test-execute/exec-ioschedulingclass-idle.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for IOSchedulingClass=idle + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "idle"' +Type=oneshot +IOSchedulingClass=idle diff --git a/test/test-execute/exec-ioschedulingclass-none.service b/test/test-execute/exec-ioschedulingclass-none.service new file mode 100644 index 0000000000..b6af122a1e --- /dev/null +++ b/test/test-execute/exec-ioschedulingclass-none.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for IOSchedulingClass=none + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "none"' +Type=oneshot +IOSchedulingClass=none diff --git a/test/test-execute/exec-ioschedulingclass-realtime.service b/test/test-execute/exec-ioschedulingclass-realtime.service new file mode 100644 index 0000000000..d920d5c687 --- /dev/null +++ b/test/test-execute/exec-ioschedulingclass-realtime.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for IOSchedulingClass=realtime + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "realtime"' +Type=oneshot +IOSchedulingClass=realtime diff --git a/test/test-execute/exec-oomscoreadjust-negative.service b/test/test-execute/exec-oomscoreadjust-negative.service new file mode 100644 index 0000000000..2234c53c3f --- /dev/null +++ b/test/test-execute/exec-oomscoreadjust-negative.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for OOMScoreAdjust + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(cat /proc/self/oom_score_adj); test "$$c" -eq -100' +Type=oneshot +OOMScoreAdjust=-100 diff --git a/test/test-execute/exec-oomscoreadjust-positive.service b/test/test-execute/exec-oomscoreadjust-positive.service new file mode 100644 index 0000000000..456a8f80cf --- /dev/null +++ b/test/test-execute/exec-oomscoreadjust-positive.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for OOMScoreAdjust + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(cat /proc/self/oom_score_adj); test "$$c" -eq 100' +Type=oneshot +OOMScoreAdjust=100 diff --git a/test/test-execute/exec-passenvironment-absent.service b/test/test-execute/exec-passenvironment-absent.service new file mode 100644 index 0000000000..7d5e32a4eb --- /dev/null +++ b/test/test-execute/exec-passenvironment-absent.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for PassEnvironment with variables absent from the execution environment + +[Service] +ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"' +Type=oneshot +PassEnvironment=VAR1 VAR2 VAR3 diff --git a/test/test-execute/exec-passenvironment-empty.service b/test/test-execute/exec-passenvironment-empty.service new file mode 100644 index 0000000000..c93c197c10 --- /dev/null +++ b/test/test-execute/exec-passenvironment-empty.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for PassEnvironment and erasing the variable list + +[Service] +ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"' +Type=oneshot +PassEnvironment=VAR1 VAR2 VAR3 +PassEnvironment= diff --git a/test/test-execute/exec-passenvironment-repeated.service b/test/test-execute/exec-passenvironment-repeated.service new file mode 100644 index 0000000000..5e8c56f26a --- /dev/null +++ b/test/test-execute/exec-passenvironment-repeated.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for PassEnvironment with a variable name repeated + +[Service] +ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"' +Type=oneshot +PassEnvironment=VAR1 VAR2 +PassEnvironment=VAR1 VAR3 diff --git a/test/test-execute/exec-passenvironment.service b/test/test-execute/exec-passenvironment.service new file mode 100644 index 0000000000..b4a9909682 --- /dev/null +++ b/test/test-execute/exec-passenvironment.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for PassEnvironment + +[Service] +ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"' +Type=oneshot +PassEnvironment=VAR1 VAR2 VAR3 diff --git a/test/test-execute/exec-personality-aarch64.service b/test/test-execute/exec-personality-aarch64.service new file mode 100644 index 0000000000..40b6d95e3a --- /dev/null +++ b/test/test-execute/exec-personality-aarch64.service @@ -0,0 +1,7 @@ +Unit] +Description=Test for Personality=aarch64 + +[Service] +ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "aarch64")' +Type=oneshot +Personality=aarch64 diff --git a/test/exec-personality-x86.service b/test/test-execute/exec-personality-ppc64.service index 0b370a6480..ccc2c8d83d 100644 --- a/test/exec-personality-x86.service +++ b/test/test-execute/exec-personality-ppc64.service @@ -1,7 +1,7 @@ [Unit] -Description=Test for Personality=x86 +Description=Test for Personality=ppc64 [Service] -ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "i686")' +ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "ppc64")' Type=oneshot -Personality=x86 +Personality=ppc64 diff --git a/test/exec-personality-x86-64.service b/test/test-execute/exec-personality-ppc64le.service index 5bb5d910d0..2a7625087d 100644 --- a/test/exec-personality-x86-64.service +++ b/test/test-execute/exec-personality-ppc64le.service @@ -1,7 +1,7 @@ [Unit] -Description=Test for Personality=x86-64 +Description=Test for Personality=ppc64le [Service] -ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "x86_64")' +ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "ppc64le")' Type=oneshot -Personality=x86-64 +Personality=ppc64le diff --git a/test/test-execute/exec-personality-s390.service b/test/test-execute/exec-personality-s390.service new file mode 100644 index 0000000000..89f7de89d0 --- /dev/null +++ b/test/test-execute/exec-personality-s390.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for Personality=s390 + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "s390"' +Type=oneshot +Personality=s390 diff --git a/test/test-execute/exec-personality-x86-64.service b/test/test-execute/exec-personality-x86-64.service new file mode 100644 index 0000000000..433e69a6d1 --- /dev/null +++ b/test/test-execute/exec-personality-x86-64.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for Personality=x86-64 + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "x86_64"' +Type=oneshot +Personality=x86-64 diff --git a/test/test-execute/exec-personality-x86.service b/test/test-execute/exec-personality-x86.service new file mode 100644 index 0000000000..a623a08cbe --- /dev/null +++ b/test/test-execute/exec-personality-x86.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for Personality=x86 + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "i686"' +Type=oneshot +Personality=x86 diff --git a/test/test-execute/exec-privatedevices-no-capability-mknod.service b/test/test-execute/exec-privatedevices-no-capability-mknod.service new file mode 100644 index 0000000000..6d39469da8 --- /dev/null +++ b/test/test-execute/exec-privatedevices-no-capability-mknod.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test CAP_MKNOD capability for PrivateDevices=no + +[Service] +PrivateDevices=no +ExecStart=/bin/sh -x -c 'capsh --print | grep cap_mknod' +Type=oneshot diff --git a/test/exec-privatedevices-no.service b/test/test-execute/exec-privatedevices-no.service index cf4f275fb6..77aeb951b5 100644 --- a/test/exec-privatedevices-no.service +++ b/test/test-execute/exec-privatedevices-no.service @@ -2,6 +2,6 @@ Description=Test for PrivateDev=no [Service] -ExecStart=/bin/sh -c 'exit $(test -c /dev/mem)' +ExecStart=/bin/sh -x -c 'test -c /dev/mem' Type=oneshot PrivateDevices=no diff --git a/test/test-execute/exec-privatedevices-yes-capability-mknod.service b/test/test-execute/exec-privatedevices-yes-capability-mknod.service new file mode 100644 index 0000000000..fb1fc2875a --- /dev/null +++ b/test/test-execute/exec-privatedevices-yes-capability-mknod.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test CAP_MKNOD capability for PrivateDevices=yes + +[Service] +PrivateDevices=yes +ExecStart=/bin/sh -x -c '! capsh --print | grep cap_mknod' +Type=oneshot diff --git a/test/exec-privatedevices-yes.service b/test/test-execute/exec-privatedevices-yes.service index 85b3f4f981..ab958b646e 100644 --- a/test/exec-privatedevices-yes.service +++ b/test/test-execute/exec-privatedevices-yes.service @@ -2,6 +2,6 @@ Description=Test for PrivateDev=yes [Service] -ExecStart=/bin/sh -c 'exit $(test ! -c /dev/mem)' +ExecStart=/bin/sh -c 'test ! -c /dev/mem' Type=oneshot PrivateDevices=yes diff --git a/test/test-execute/exec-privatenetwork-yes.service b/test/test-execute/exec-privatenetwork-yes.service new file mode 100644 index 0000000000..3df543ec93 --- /dev/null +++ b/test/test-execute/exec-privatenetwork-yes.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for PrivateNetwork + +[Service] +ExecStart=/bin/sh -x -c 'i=$$(ip link | grep ": " | grep -v ": lo:"); test -z "$$i"' +Type=oneshot +PrivateNetwork=yes diff --git a/test/exec-privatetmp-no.service b/test/test-execute/exec-privatetmp-no.service index d69e552a63..59f60f4755 100644 --- a/test/exec-privatetmp-no.service +++ b/test/test-execute/exec-privatetmp-no.service @@ -2,6 +2,6 @@ Description=Test for PrivateTmp=no [Service] -ExecStart=/bin/sh -c 'exit $(test -f /tmp/test-exec_privatetmp)' +ExecStart=/bin/sh -x -c 'test -f /tmp/test-exec_privatetmp' Type=oneshot PrivateTmp=no diff --git a/test/exec-privatetmp-yes.service b/test/test-execute/exec-privatetmp-yes.service index 881a040b87..907c291b81 100644 --- a/test/exec-privatetmp-yes.service +++ b/test/test-execute/exec-privatetmp-yes.service @@ -2,6 +2,6 @@ Description=Test for PrivateTmp=yes [Service] -ExecStart=/bin/sh -c 'exit $(test ! -f /tmp/test-exec_privatetmp)' +ExecStart=/bin/sh -x -c 'test ! -f /tmp/test-exec_privatetmp' Type=oneshot PrivateTmp=yes diff --git a/test/test-execute/exec-readonlypaths-mount-propagation.service b/test/test-execute/exec-readonlypaths-mount-propagation.service new file mode 100644 index 0000000000..237cbb2efb --- /dev/null +++ b/test/test-execute/exec-readonlypaths-mount-propagation.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test to make sure that passing ReadOnlyPaths= disconnect mount propagation + +[Service] +ReadOnlyPaths=-/i-dont-exist +ExecStart=/bin/sh -x -c 'mkdir -p /TEST; mount -t tmpfs tmpfs /TEST; grep TEST /proc/self/mountinfo && ! grep TEST /proc/$${PPID}/mountinfo && ! grep TEST /proc/1/mountinfo' +Type=oneshot diff --git a/test/test-execute/exec-readonlypaths.service b/test/test-execute/exec-readonlypaths.service new file mode 100644 index 0000000000..6866fdc700 --- /dev/null +++ b/test/test-execute/exec-readonlypaths.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for ReadOnlyPaths= + +[Service] +ReadOnlyPaths=/etc -/i-dont-exist /usr +ExecStart=/bin/sh -x -c 'test ! -w /etc && test ! -w /usr && test ! -e /i-dont-exist && test -w /var' +Type=oneshot diff --git a/test/test-execute/exec-readwritepaths-mount-propagation.service b/test/test-execute/exec-readwritepaths-mount-propagation.service new file mode 100644 index 0000000000..466ce6c747 --- /dev/null +++ b/test/test-execute/exec-readwritepaths-mount-propagation.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test to make sure that passing ReadWritePaths= disconnect mount propagation + +[Service] +ReadWritePaths=-/i-dont-exist +ExecStart=/bin/sh -x -c 'mkdir -p /TEST; mount -t tmpfs tmpfs /TEST; grep TEST /proc/self/mountinfo && ! grep TEST /proc/$${PPID}/mountinfo && ! grep TEST /proc/1/mountinfo' +Type=oneshot diff --git a/test/test-execute/exec-runtimedirectory-mode.service b/test/test-execute/exec-runtimedirectory-mode.service new file mode 100644 index 0000000000..842721d5c2 --- /dev/null +++ b/test/test-execute/exec-runtimedirectory-mode.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for RuntimeDirectoryMode + +[Service] +ExecStart=/bin/sh -x -c 'mode=$$(stat -c %%a /tmp/test-exec_runtimedirectory-mode); test "$$mode" = "750"' +Type=oneshot +RuntimeDirectory=test-exec_runtimedirectory-mode +RuntimeDirectoryMode=0750 diff --git a/test/test-execute/exec-runtimedirectory-owner-nfsnobody.service b/test/test-execute/exec-runtimedirectory-owner-nfsnobody.service new file mode 100644 index 0000000000..e962af8a4b --- /dev/null +++ b/test/test-execute/exec-runtimedirectory-owner-nfsnobody.service @@ -0,0 +1,9 @@ +[Unit] +Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set) + +[Service] +ExecStart=/bin/sh -x -c 'group=$$(stat -c %%G /tmp/test-exec_runtimedirectory-owner); test "$$group" = "nfsnobody"' +Type=oneshot +Group=nfsnobody +User=root +RuntimeDirectory=test-exec_runtimedirectory-owner diff --git a/test/test-execute/exec-runtimedirectory-owner.service b/test/test-execute/exec-runtimedirectory-owner.service new file mode 100644 index 0000000000..1f438c182e --- /dev/null +++ b/test/test-execute/exec-runtimedirectory-owner.service @@ -0,0 +1,9 @@ +[Unit] +Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set) + +[Service] +ExecStart=/bin/sh -x -c 'group=$$(stat -c %%G /tmp/test-exec_runtimedirectory-owner); test "$$group" = "nobody"' +Type=oneshot +Group=nobody +User=root +RuntimeDirectory=test-exec_runtimedirectory-owner diff --git a/test/test-execute/exec-runtimedirectory.service b/test/test-execute/exec-runtimedirectory.service new file mode 100644 index 0000000000..ec46c9d49b --- /dev/null +++ b/test/test-execute/exec-runtimedirectory.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for RuntimeDirectory + +[Service] +ExecStart=/bin/sh -x -c 'test -d /tmp/test-exec_runtimedirectory' +Type=oneshot +RuntimeDirectory=test-exec_runtimedirectory diff --git a/test/test-execute/exec-spec-interpolation.service b/test/test-execute/exec-spec-interpolation.service new file mode 100644 index 0000000000..3e62662aa9 --- /dev/null +++ b/test/test-execute/exec-spec-interpolation.service @@ -0,0 +1,6 @@ +[Unit] +Description=https://github.com/systemd/systemd/issues/2637 + +[Service] +Type=oneshot +ExecStart=/bin/sh -x -c "perl -e 'exit(!(qq{%%U} eq qq{\\x25U}))'" diff --git a/test/exec-systemcallerrornumber.service b/test/test-execute/exec-systemcallerrornumber.service index 255a8b231a..ff7da3c1a4 100644 --- a/test/exec-systemcallerrornumber.service +++ b/test/test-execute/exec-systemcallerrornumber.service @@ -2,6 +2,7 @@ Description=Test for SystemCallErrorNumber [Service] -ExecStart=/usr/bin/uname -a +ExecStart=/bin/sh -x -c 'uname -a' +Type=oneshot SystemCallFilter=~uname SystemCallErrorNumber=EACCES diff --git a/test/exec-systemcallfilter-failing.service b/test/test-execute/exec-systemcallfilter-failing.service index c6ce9368c9..5c6422f0fd 100644 --- a/test/exec-systemcallfilter-failing.service +++ b/test/test-execute/exec-systemcallfilter-failing.service @@ -3,6 +3,7 @@ Description=Test for SystemCallFilter [Service] ExecStart=/bin/echo "This should not be seen" +Type=oneshot SystemCallFilter=ioperm SystemCallFilter=~ioperm SystemCallFilter=ioperm diff --git a/test/exec-systemcallfilter-failing2.service b/test/test-execute/exec-systemcallfilter-failing2.service index b7f7c2aff9..3516078e1f 100644 --- a/test/exec-systemcallfilter-failing2.service +++ b/test/test-execute/exec-systemcallfilter-failing2.service @@ -3,4 +3,5 @@ Description=Test for SystemCallFilter [Service] ExecStart=/bin/echo "This should not be seen" +Type=oneshot SystemCallFilter=~write open execve exit_group close mmap munmap fstat DONOTEXIST diff --git a/test/exec-systemcallfilter-not-failing.service b/test/test-execute/exec-systemcallfilter-not-failing.service index feb206ab6d..c794b67edd 100644 --- a/test/exec-systemcallfilter-not-failing.service +++ b/test/test-execute/exec-systemcallfilter-not-failing.service @@ -3,6 +3,7 @@ Description=Test for SystemCallFilter [Service] ExecStart=/bin/echo "Foo bar" +Type=oneshot SystemCallFilter=~read write open execve ioperm SystemCallFilter=ioctl SystemCallFilter=read write open execve diff --git a/test/exec-systemcallfilter-not-failing2.service b/test/test-execute/exec-systemcallfilter-not-failing2.service index cca469aa3d..a62c81bd48 100644 --- a/test/exec-systemcallfilter-not-failing2.service +++ b/test/test-execute/exec-systemcallfilter-not-failing2.service @@ -3,4 +3,5 @@ Description=Test for SystemCallFilter [Service] ExecStart=/bin/echo "Foo bar" +Type=oneshot SystemCallFilter= diff --git a/test/test-execute/exec-systemcallfilter-system-user-nfsnobody.service b/test/test-execute/exec-systemcallfilter-system-user-nfsnobody.service new file mode 100644 index 0000000000..9393e0a998 --- /dev/null +++ b/test/test-execute/exec-systemcallfilter-system-user-nfsnobody.service @@ -0,0 +1,11 @@ +[Unit] +Description=Test for SystemCallFilter in system mode with User set + +[Service] +ExecStart=/bin/echo "Foo bar" +Type=oneshot +User=nfsnobody +SystemCallFilter=~read write open execve ioperm +SystemCallFilter=ioctl +SystemCallFilter=read write open execve +SystemCallFilter=~ioperm diff --git a/test/test-execute/exec-systemcallfilter-system-user.service b/test/test-execute/exec-systemcallfilter-system-user.service new file mode 100644 index 0000000000..462f94133d --- /dev/null +++ b/test/test-execute/exec-systemcallfilter-system-user.service @@ -0,0 +1,11 @@ +[Unit] +Description=Test for SystemCallFilter in system mode with User set + +[Service] +ExecStart=/bin/echo "Foo bar" +Type=oneshot +User=nobody +SystemCallFilter=~read write open execve ioperm +SystemCallFilter=ioctl +SystemCallFilter=read write open execve +SystemCallFilter=~ioperm diff --git a/test/test-execute/exec-umask-0177.service b/test/test-execute/exec-umask-0177.service new file mode 100644 index 0000000000..a5e8fc4dbc --- /dev/null +++ b/test/test-execute/exec-umask-0177.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for UMask + +[Service] +ExecStart=/bin/sh -x -c 'touch /tmp/test-exec-umask; mode=$$(stat -c %%a /tmp/test-exec-umask); test "$$mode" = "600"' +Type=oneshot +UMask=0177 +PrivateTmp=yes diff --git a/test/test-execute/exec-umask-default.service b/test/test-execute/exec-umask-default.service new file mode 100644 index 0000000000..487f5e9b94 --- /dev/null +++ b/test/test-execute/exec-umask-default.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for UMask default + +[Service] +ExecStart=/bin/sh -x -c 'touch /tmp/test-exec-umask; mode=$$(stat -c %%a /tmp/test-exec-umask); test "$$mode" = "644"' +Type=oneshot +PrivateTmp=yes diff --git a/test/test-execute/exec-user-nfsnobody.service b/test/test-execute/exec-user-nfsnobody.service new file mode 100644 index 0000000000..aafda3aa26 --- /dev/null +++ b/test/test-execute/exec-user-nfsnobody.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for User + +[Service] +ExecStart=/bin/sh -x -c 'test "$$USER" = "nfsnobody"' +Type=oneshot +User=nfsnobody diff --git a/test/test-execute/exec-user.service b/test/test-execute/exec-user.service new file mode 100644 index 0000000000..0a00c1abc4 --- /dev/null +++ b/test/test-execute/exec-user.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for User + +[Service] +ExecStart=/bin/sh -x -c 'test "$$USER" = "nobody"' +Type=oneshot +User=nobody diff --git a/test/exec-workingdirectory.service b/test/test-execute/exec-workingdirectory.service index 10855d682a..fe3c420d2d 100644 --- a/test/exec-workingdirectory.service +++ b/test/test-execute/exec-workingdirectory.service @@ -2,6 +2,6 @@ Description=Test for WorkingDirectory [Service] -ExecStart=/bin/sh -c 'echo $PWD; exit $(test $PWD = "/tmp/test-exec_workingdirectory")' +ExecStart=/bin/sh -x -c 'test "$$PWD" = "/tmp/test-exec_workingdirectory"' Type=oneshot WorkingDirectory=/tmp/test-exec_workingdirectory diff --git a/test/test-functions b/test/test-functions index 8272e52e17..2a21a64c5c 100644 --- a/test/test-functions +++ b/test/test-functions @@ -4,16 +4,22 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin export PATH +LOOKS_LIKE_DEBIAN=$(source /etc/os-release && [[ "$ID" = "debian" || "$ID_LIKE" = "debian" ]] && echo yes) KERNEL_VER=${KERNEL_VER-$(uname -r)} KERNEL_MODS="/lib/modules/$KERNEL_VER/" +QEMU_TIMEOUT="${QEMU_TIMEOUT:-infinity}" +NSPAWN_TIMEOUT="${NSPAWN_TIMEOUT:-infinity}" +TIMED_OUT= # will be 1 after run_* if *_TIMEOUT is set and test timed out +FSTYPE="${FSTYPE:-ext3}" +UNIFIED_CGROUP_HIERARCHY="${UNIFIED_CGROUP_HIERARCHY:-no}" if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then echo "WARNING! Cannot determine rootlibdir from pkg-config, assuming /usr/lib/systemd" >&2 ROOTLIBDIR=/usr/lib/systemd fi -BASICTOOLS="sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe" -DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname" +BASICTOOLS="sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm" +DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname find" function find_qemu_bin() { # SUSE and Red Hat call the binary qemu-kvm @@ -41,6 +47,8 @@ function find_qemu_bin() { fi } +# Return 0 if QEMU did run (then you must check the result state/logs for actual +# success), or 1 if QEMU is not available. run_qemu() { if [ -f /etc/machine-id ]; then read MACHINE_ID < /etc/machine-id @@ -50,42 +58,77 @@ run_qemu() { && KERNEL_BIN="/boot/$MACHINE_ID/$KERNEL_VER/linux" fi + default_fedora_initrd=/boot/initramfs-${KERNEL_VER}.img + default_debian_initrd=/boot/initrd.img-${KERNEL_VER} [ "$KERNEL_BIN" ] || KERNEL_BIN=/boot/vmlinuz-$KERNEL_VER - [ "$INITRD" ] || INITRD=/boot/initramfs-${KERNEL_VER}.img + [ "$INITRD" ] || { [ -e "$default_fedora_initrd" ] && INITRD=$default_fedora_initrd; } + [ "$INITRD" ] || { [ "$LOOKS_LIKE_DEBIAN" ] && [ -e "$default_debian_initrd" ] && INITRD=$default_debian_initrd; } [ "$QEMU_SMP" ] || QEMU_SMP=1 find_qemu_bin || return 1 KERNEL_APPEND="root=/dev/sda1 \ -systemd.log_level=debug \ raid=noautodetect \ loglevel=2 \ init=$ROOTLIBDIR/systemd \ ro \ console=ttyS0 \ selinux=0 \ +systemd.unified_cgroup_hierarchy=$UNIFIED_CGROUP_HIERARCHY \ $KERNEL_APPEND \ " - QEMU_OPTIONS="-machine accel=kvm:tcg \ --smp $QEMU_SMP \ + QEMU_OPTIONS="-smp $QEMU_SMP \ -net none \ -m 512M \ -nographic \ -kernel $KERNEL_BIN \ +-drive format=raw,cache=unsafe,file=${TESTDIR}/rootdisk.img \ " - if [ "$INITRD" ]; then + if [[ "$INITRD" && "$SKIP_INITRD" != "yes" ]]; then QEMU_OPTIONS="$QEMU_OPTIONS -initrd $INITRD" fi - ( set -x - $QEMU_BIN $QEMU_OPTIONS -append "$KERNEL_APPEND" $TESTDIR/rootdisk.img ) || return 1 + if [ -c /dev/kvm ]; then + QEMU_OPTIONS="$QEMU_OPTIONS -machine accel=kvm -enable-kvm -cpu host" + fi + + if [[ "$QEMU_TIMEOUT" != "infinity" ]]; then + QEMU_BIN="timeout --foreground $QEMU_TIMEOUT $QEMU_BIN" + fi + (set -x; $QEMU_BIN $QEMU_OPTIONS -append "$KERNEL_APPEND") + rc=$? + if [ "$rc" = 124 ] && [ "$QEMU_TIMEOUT" != "infinity" ]; then + derror "test timed out after $QEMU_TIMEOUT s" + TIMED_OUT=1 + else + [ "$rc" != 0 ] && derror "QEMU failed with exit code $rc" + fi + return 0 } +# Return 0 if nspawn did run (then you must check the result state/logs for actual +# success), or 1 if nspawn is not available. run_nspawn() { - set -x - ../../systemd-nspawn --boot --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND + [[ -d /run/systemd/system ]] || return 1 + + local _nspawn_cmd="../../systemd-nspawn --register=no --kill-signal=SIGKILL --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND" + if [[ "$NSPAWN_TIMEOUT" != "infinity" ]]; then + _nspawn_cmd="timeout --foreground $NSPAWN_TIMEOUT $_nspawn_cmd" + fi + + _nspawn_cmd="env UNIFIED_CGROUP_HIERARCHY=$UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd" + + (set -x; $_nspawn_cmd) + rc=$? + if [ "$rc" = 124 ] && [ "$NSPAWN_TIMEOUT" != "infinity" ]; then + derror "test timed out after $NSPAWN_TIMEOUT s" + TIMED_OUT=1 + else + [ "$rc" != 0 ] && derror "nspawn failed with exit code $rc" + fi + return 0 } setup_basic_environment() { @@ -104,21 +147,120 @@ setup_basic_environment() { install_keymaps install_terminfo install_execs + install_fsck install_plymouth install_debug_tools install_ld_so_conf + setup_selinux strip_binaries install_depmod_files generate_module_dependencies - # softlink mtab - ln -fs /proc/self/mounts $initdir/etc/mtab +} + +setup_selinux() { + # don't forget KERNEL_APPEND='... selinux=1 ...' + if [[ "$SETUP_SELINUX" != "yes" ]]; then + ddebug "Don't setup SELinux" + return 0 + fi + ddebug "Setup SELinux" + local _conf_dir=/etc/selinux + local _fixfiles_tools="bash uname cat sort uniq awk grep egrep head expr find rm secon setfiles" + + rm -rf $initdir/$_conf_dir + if ! cp -ar $_conf_dir $initdir/$_conf_dir; then + dfatal "Failed to copy $_conf_dir" + exit 1 + fi + + cat <<EOF >$initdir/etc/systemd/system/autorelabel.service +[Unit] +Description=Relabel all filesystems +DefaultDependencies=no +Requires=local-fs.target +Conflicts=shutdown.target +After=local-fs.target +Before=sysinit.target shutdown.target +ConditionSecurity=selinux +ConditionPathExists=|/.autorelabel + +[Service] +ExecStart=/bin/sh -x -c 'echo 0 >/sys/fs/selinux/enforce && fixfiles -f -F relabel && rm /.autorelabel && systemctl --force reboot' +Type=oneshot +TimeoutSec=0 +RemainAfterExit=yes +EOF + + touch $initdir/.autorelabel + mkdir -p $initdir/etc/systemd/system/basic.target.wants + ln -fs autorelabel.service $initdir/etc/systemd/system/basic.target.wants/autorelabel.service + + dracut_install $_fixfiles_tools + dracut_install fixfiles + dracut_install sestatus +} + +install_valgrind() { + if ! type -p valgrind; then + dfatal "Failed to install valgrind" + exit 1 + fi + + local _valgrind_bins=$(strace -e execve valgrind /bin/true 2>&1 >/dev/null | perl -lne 'print $1 if /^execve\("([^"]+)"/') + dracut_install $_valgrind_bins + + local _valgrind_libs=$(LD_DEBUG=files valgrind /bin/true 2>&1 >/dev/null | perl -lne 'print $1 if m{calling init: (/.*vgpreload_.*)}') + dracut_install $_valgrind_libs + + local _valgrind_dbg_and_supp=$( + strace -e open valgrind /bin/true 2>&1 >/dev/null | + perl -lne 'if (my ($fname) = /^open\("([^"]+).*= (?!-)\d+/) { print $fname if $fname =~ /debug|\.supp$/ }' + ) + dracut_install $_valgrind_dbg_and_supp +} + +create_valgrind_wrapper() { + local _valgrind_wrapper=$initdir/$ROOTLIBDIR/systemd-under-valgrind + ddebug "Create $_valgrind_wrapper" + cat >$_valgrind_wrapper <<EOF +#!/bin/bash + +mount -t proc proc /proc +exec valgrind --leak-check=full --log-file=/valgrind.out $ROOTLIBDIR/systemd "\$@" +EOF + chmod 0755 $_valgrind_wrapper +} + +create_strace_wrapper() { + local _strace_wrapper=$initdir/$ROOTLIBDIR/systemd-under-strace + ddebug "Create $_strace_wrapper" + cat >$_strace_wrapper <<EOF +#!/bin/bash + +exec strace -D -o /strace.out $ROOTLIBDIR/systemd "\$@" +EOF + chmod 0755 $_strace_wrapper +} + +install_fsck() { + dracut_install /sbin/fsck* + dracut_install -o /bin/fsck* + + # fskc.reiserfs calls reiserfsck. so, install it + dracut_install -o reiserfsck } install_dmevent() { instmods dm_crypt =crypto type -P dmeventd >/dev/null && dracut_install dmeventd inst_libdir_file "libdevmapper-event.so*" - inst_rules 10-dm.rules 13-dm-disk.rules 95-dm-notify.rules + if [[ "$LOOKS_LIKE_DEBIAN" ]]; then + # dmsetup installs 55-dm and 60-persistent-storage-dm on Debian/Ubuntu + # see https://anonscm.debian.org/cgit/pkg-lvm/lvm2.git/tree/debian/patches/0007-udev.patch + inst_rules 55-dm.rules 60-persistent-storage-dm.rules + else + inst_rules 10-dm.rules 13-dm-disk.rules 95-dm-notify.rules + fi } install_systemd() { @@ -129,28 +271,42 @@ install_systemd() { # we strip binaries since debug symbols increase binaries size a lot # and it could fill the available space strip_binaries + + # enable debug logging in PID1 + echo LogLevel=debug >> $initdir/etc/systemd/system.conf +} + +get_ldpath() { + local _bin="$1" + objdump -p "$_bin" 2>/dev/null | awk "/R(UN)?PATH/ { print \"$initdir\" \$2 }" | paste -sd : } install_missing_libraries() { # install possible missing libraries - for i in $initdir/{sbin,bin}/* $initdir/lib/systemd/*; do - inst_libs $i + for i in $initdir{,/usr}/{sbin,bin}/* $initdir{,/usr}/lib/systemd/*; do + LD_LIBRARY_PATH=$(get_ldpath $i) inst_libs $i done } create_empty_image() { rm -f "$TESTDIR/rootdisk.img" # Create the blank file to use as a root filesystem - dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek=300 + dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek=400 LOOPDEV=$(losetup --show -P -f $TESTDIR/rootdisk.img) [ -b "$LOOPDEV" ] || return 1 echo "LOOPDEV=$LOOPDEV" >> $STATEFILE sfdisk "$LOOPDEV" <<EOF -,290M +,390M , EOF - mkfs.ext3 -L systemd "${LOOPDEV}p1" + local _label="-L systemd" + # mkfs.reiserfs doesn't know -L. so, use --label instead + [[ "$FSTYPE" == "reiserfs" ]] && _label="--label systemd" + if ! mkfs -t "${FSTYPE}" ${_label} "${LOOPDEV}p1" -q; then + dfatal "Failed to mkfs -t ${FSTYPE}" + exit 1 + fi } check_result_nspawn() { @@ -161,10 +317,15 @@ check_result_nspawn() { [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed ls -l $TESTDIR/journal/*/*.journal test -s $TESTDIR/failed && ret=$(($ret+1)) + [ -n "$TIMED_OUT" ] && ret=$(($ret+1)) return $ret } strip_binaries() { + if [[ "$STRIP_BINARIES" = "no" ]]; then + ddebug "Don't strip binaries" + return 0 + fi ddebug "Strip binaries" find "$initdir" -executable -not -path '*/lib/modules/*.ko' -type f | xargs strip --strip-unneeded | ddebug } @@ -179,12 +340,17 @@ EOF } install_execs() { - # install any Execs from the service files - egrep -ho '^Exec[^ ]*=[^ ]+' $initdir/lib/systemd/system/*.service \ - | while read i; do - i=${i##Exec*=}; i=${i##-} - inst $i - done + ddebug "install any Execs from the service files" + ( + export PKG_CONFIG_PATH=$TEST_BASE_DIR/../src/core/ + systemdsystemunitdir=$(pkg-config --variable=systemdsystemunitdir systemd) + systemduserunitdir=$(pkg-config --variable=systemduserunitdir systemd) + egrep -ho '^Exec[^ ]*=[^ ]+' $initdir/{$systemdsystemunitdir,$systemduserunitdir}/*.service \ + | while read i; do + i=${i##Exec*=}; i=${i##-} + inst $i + done + ) } generate_module_dependencies() { @@ -220,6 +386,7 @@ install_config_files() { inst /etc/sysconfig/init inst /etc/passwd inst /etc/shadow + inst /etc/login.defs inst /etc/group inst /etc/shells inst /etc/nsswitch.conf @@ -234,7 +401,7 @@ install_config_files() { echo systemd-testsuite > $initdir/etc/hostname # fstab cat >$initdir/etc/fstab <<EOF -LABEL=systemd / ext3 rw 0 1 +LABEL=systemd / ${FSTYPE} rw 0 1 EOF } @@ -260,21 +427,33 @@ install_dbus() { inst $ROOTLIBDIR/system/dbus.service find \ - /etc/dbus-1 -xtype f \ + /etc/dbus-1 /usr/share/dbus-1 -xtype f \ | while read file; do inst $file done } install_pam() { + ( + [[ "$LOOKS_LIKE_DEBIAN" ]] && type -p dpkg-architecture &>/dev/null && find "/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/security" -xtype f find \ /etc/pam.d \ /etc/security \ /lib64/security \ /lib/security -xtype f \ - | while read file; do + ) | while read file; do inst $file done + + # pam_unix depends on unix_chkpwd. + # see http://www.linux-pam.org/Linux-PAM-html/sag-pam_unix.html + dracut_install -o unix_chkpwd + + [[ "$LOOKS_LIKE_DEBIAN" ]] && + cp /etc/pam.d/systemd-user $initdir/etc/pam.d/ + + # set empty root password for easy debugging + sed -i 's/^root:x:/root::/' $initdir/etc/passwd } install_keymaps() { @@ -305,7 +484,7 @@ install_terminfo() { setup_testsuite() { cp $TEST_BASE_DIR/testsuite.target $initdir/etc/systemd/system/ - sed "s#@SYSTEMCTL@#$(type -P systemctl)#g" $TEST_BASE_DIR/end.service.in > $initdir/etc/systemd/system/end.service + cp $TEST_BASE_DIR/end.service $initdir/etc/systemd/system/ mkdir -p $initdir/etc/systemd/system/testsuite.target.wants ln -fs $TEST_BASE_DIR/testsuite.service $initdir/etc/systemd/system/testsuite.target.wants/testsuite.service @@ -1115,11 +1294,6 @@ inst_libdir_file() { fi } -check_nspawn() { - [[ -d /sys/fs/cgroup/systemd ]] -} - - do_test() { if [[ $UID != "0" ]]; then echo "TEST: $TEST_DESCRIPTION [SKIPPED]: not root" >&2 diff --git a/test/test-path/basic.target b/test/test-path/basic.target new file mode 120000 index 0000000000..a882b72cc9 --- /dev/null +++ b/test/test-path/basic.target @@ -0,0 +1 @@ +../../units/basic.target
\ No newline at end of file diff --git a/test/path-changed.path b/test/test-path/path-changed.path index e58bdd925f..e58bdd925f 100644 --- a/test/path-changed.path +++ b/test/test-path/path-changed.path diff --git a/test/path-changed.service b/test/test-path/path-changed.service index 8bdf178830..8bdf178830 120000 --- a/test/path-changed.service +++ b/test/test-path/path-changed.service diff --git a/test/path-directorynotempty.path b/test/test-path/path-directorynotempty.path index 17e599fc0e..17e599fc0e 100644 --- a/test/path-directorynotempty.path +++ b/test/test-path/path-directorynotempty.path diff --git a/test/path-directorynotempty.service b/test/test-path/path-directorynotempty.service index 8bdf178830..8bdf178830 120000 --- a/test/path-directorynotempty.service +++ b/test/test-path/path-directorynotempty.service diff --git a/test/path-exists.path b/test/test-path/path-exists.path index c4c9105af4..c4c9105af4 100644 --- a/test/path-exists.path +++ b/test/test-path/path-exists.path diff --git a/test/path-exists.service b/test/test-path/path-exists.service index 8bdf178830..8bdf178830 120000 --- a/test/path-exists.service +++ b/test/test-path/path-exists.service diff --git a/test/path-existsglob.path b/test/test-path/path-existsglob.path index a058599605..a058599605 100644 --- a/test/path-existsglob.path +++ b/test/test-path/path-existsglob.path diff --git a/test/path-existsglob.service b/test/test-path/path-existsglob.service index 8bdf178830..8bdf178830 120000 --- a/test/path-existsglob.service +++ b/test/test-path/path-existsglob.service diff --git a/test/path-makedirectory.path b/test/test-path/path-makedirectory.path index 9408479c0f..9408479c0f 100644 --- a/test/path-makedirectory.path +++ b/test/test-path/path-makedirectory.path diff --git a/test/path-makedirectory.service b/test/test-path/path-makedirectory.service index 8bdf178830..8bdf178830 120000 --- a/test/path-makedirectory.service +++ b/test/test-path/path-makedirectory.service diff --git a/test/path-modified.path b/test/test-path/path-modified.path index 18363227ba..18363227ba 100644 --- a/test/path-modified.path +++ b/test/test-path/path-modified.path diff --git a/test/path-modified.service b/test/test-path/path-modified.service index 8bdf178830..8bdf178830 120000 --- a/test/path-modified.service +++ b/test/test-path/path-modified.service diff --git a/test/path-mycustomunit.service b/test/test-path/path-mycustomunit.service index 172ac0d0d5..172ac0d0d5 100644 --- a/test/path-mycustomunit.service +++ b/test/test-path/path-mycustomunit.service diff --git a/test/path-service.service b/test/test-path/path-service.service index f8499ec619..f8499ec619 100644 --- a/test/path-service.service +++ b/test/test-path/path-service.service diff --git a/test/path-unit.path b/test/test-path/path-unit.path index 95e572d6d5..95e572d6d5 100644 --- a/test/path-unit.path +++ b/test/test-path/path-unit.path diff --git a/test/test-path/paths.target b/test/test-path/paths.target new file mode 120000 index 0000000000..b402796cb9 --- /dev/null +++ b/test/test-path/paths.target @@ -0,0 +1 @@ +../../units/paths.target
\ No newline at end of file diff --git a/test/test-path/sysinit.target b/test/test-path/sysinit.target new file mode 120000 index 0000000000..9d10e5b2e2 --- /dev/null +++ b/test/test-path/sysinit.target @@ -0,0 +1 @@ +../../units/sysinit.target
\ No newline at end of file diff --git a/test/udev-test.pl b/test/udev-test.pl index 64d7f93444..9723386b23 100755 --- a/test/udev-test.pl +++ b/test/udev-test.pl @@ -23,14 +23,23 @@ use strict; my $udev_bin = "./test-udev"; my $valgrind = 0; my $gdb = 0; +my $strace = 0; my $udev_bin_valgrind = "valgrind --tool=memcheck --leak-check=yes --track-origins=yes --quiet $udev_bin"; my $udev_bin_gdb = "gdb --args $udev_bin"; -my $udev_dev = "test/dev"; +my $udev_bin_strace = "strace -efile $udev_bin"; my $udev_run = "test/run"; +my $udev_tmpfs = "test/tmpfs"; +my $udev_sys = "${udev_tmpfs}/sys"; +my $udev_dev = "${udev_tmpfs}/dev"; my $udev_rules_dir = "$udev_run/udev/rules.d"; my $udev_rules = "$udev_rules_dir/udev-test.rules"; my $EXIT_TEST_SKIP = 77; +my $rules_10k_tags = ""; +for (my $i = 1; $i <= 10000; ++$i) { + $rules_10k_tags .= 'KERNEL=="sda", TAG+="test' . $i . "\"\n"; +} + my @tests = ( { desc => "no rules", @@ -1315,6 +1324,25 @@ KERNEL=="sda", IMPORT{builtin}="path_id" KERNEL=="sda", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/\$env{ID_PATH}" EOF }, + { + desc => "add and match tag", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "found", + not_exp_name => "bad" , + rules => <<EOF +SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", TAG+="green" +TAGS=="green", SYMLINK+="found" +TAGS=="blue", SYMLINK+="bad" +EOF + }, + { + desc => "don't crash with lots of tags", + devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", + exp_name => "found", + rules => $rules_10k_tags . <<EOF +TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="found" +EOF + }, ); sub udev { @@ -1327,11 +1355,13 @@ sub udev { close CONF; if ($valgrind > 0) { - system("$udev_bin_valgrind $action $devpath"); + return system("$udev_bin_valgrind $action $devpath"); } elsif ($gdb > 0) { - system("$udev_bin_gdb $action $devpath"); + return system("$udev_bin_gdb $action $devpath"); + } elsif ($strace > 0) { + return system("$udev_bin_strace $action $devpath"); } else { - system("$udev_bin", "$action", "$devpath"); + return system("$udev_bin", "$action", "$devpath"); } } @@ -1401,23 +1431,34 @@ sub major_minor_test { } sub udev_setup { - system("rm", "-rf", "$udev_dev"); + system("umount", $udev_tmpfs); + rmdir($udev_tmpfs); + mkdir($udev_tmpfs) || die "unable to create udev_tmpfs: $udev_tmpfs\n"; + system("mount", "-o", "rw,mode=755,nosuid,noexec,nodev", "-t", "tmpfs", "tmpfs", $udev_tmpfs) && die "unable to mount tmpfs"; + mkdir($udev_dev) || die "unable to create udev_dev: $udev_dev\n"; # setting group and mode of udev_dev ensures the tests work # even if the parent directory has setgid bit enabled. chown (0, 0, $udev_dev) || die "unable to chown $udev_dev\n"; chmod (0755, $udev_dev) || die "unable to chmod $udev_dev\n"; + system("cp", "-r", "test/sys/", $udev_sys) && die "unable to copy test/sys"; + system("rm", "-rf", "$udev_run"); } sub run_test { my ($rules, $number) = @_; + my $rc; print "TEST $number: $rules->{desc}\n"; print "device \'$rules->{devpath}\' expecting node/link \'$rules->{exp_name}\'\n"; - udev("add", $rules->{devpath}, \$rules->{rules}); + $rc = udev("add", $rules->{devpath}, \$rules->{rules}); + if ($rc != 0) { + print "$udev_bin add failed with code $rc\n"; + $error++; + } if (defined($rules->{not_exp_name})) { if ((-e "$udev_dev/$rules->{not_exp_name}") || (-l "$udev_dev/$rules->{not_exp_name}")) { @@ -1458,7 +1499,11 @@ sub run_test { return; } - udev("remove", $rules->{devpath}, \$rules->{rules}); + $rc = udev("remove", $rules->{devpath}, \$rules->{rules}); + if ($rc != 0) { + print "$udev_bin remove failed with code $rc\n"; + $error++; + } if ((-e "$udev_dev/$rules->{exp_name}") || (-l "$udev_dev/$rules->{exp_name}")) { print "remove: error"; @@ -1487,14 +1532,21 @@ sub run_test { # due to mknod restrictions if (!($<==0)) { print "Must have root permissions to run properly.\n"; - exit; + exit($EXIT_TEST_SKIP); +} + +# skip the test when running in a chroot +system("systemd-detect-virt", "-r", "-q"); +if ($? >> 8 == 0) { + print "Running in a chroot, skipping the test.\n"; + exit($EXIT_TEST_SKIP); } # skip the test when running in a container system("systemd-detect-virt", "-c", "-q"); if ($? >> 8 == 0) { - print "Running in a container, skipping the test.\n"; - exit($EXIT_TEST_SKIP); + print "Running in a container, skipping the test.\n"; + exit($EXIT_TEST_SKIP); } udev_setup(); @@ -1509,6 +1561,9 @@ foreach my $arg (@ARGV) { } elsif ($arg =~ m/--gdb/) { $gdb = 1; printf("using gdb\n"); + } elsif ($arg =~ m/--strace/) { + $strace = 1; + printf("using strace\n"); } else { push(@list, $arg); } @@ -1536,10 +1591,11 @@ if ($list[0]) { print "$error errors occurred\n\n"; # cleanup -system("rm", "-rf", "$udev_dev"); system("rm", "-rf", "$udev_run"); +system("umount", "$udev_tmpfs"); +rmdir($udev_tmpfs); if ($error > 0) { - exit(1); + exit(1); } exit(0); diff --git a/test/unstoppable.service b/test/unstoppable.service index 24fb0a25e1..56b72c98f7 100644 --- a/test/unstoppable.service +++ b/test/unstoppable.service @@ -1,5 +1,5 @@ [Service] Type=oneshot RemainAfterExit=yes -ExecStart=/bin/echo 'I'm unstoppable!' +ExecStart=/bin/echo "I'm unstoppable!" ExecStop=/bin/systemctl start --no-block unstoppable.service |