diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 03:50:40 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 03:50:40 +0000 |
commit | fc53809803cd2bc2434e312b19a18fa36776da12 (patch) | |
tree | b4b43bd6538f51965ce32856e9c053d0f90919c8 /test/units | |
parent | Adding upstream version 255.5. (diff) | |
download | systemd-fc53809803cd2bc2434e312b19a18fa36776da12.tar.xz systemd-fc53809803cd2bc2434e312b19a18fa36776da12.zip |
Adding upstream version 256.upstream/256
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | test/TEST-07-PID1/TEST-07-PID1.service (renamed from test/units/testsuite-07.service) | 3 | ||||
-rw-r--r-- | test/TEST-16-EXTEND-TIMEOUT/TEST-16-EXTEND-TIMEOUT.service (renamed from test/units/testsuite-16.service) | 10 | ||||
-rw-r--r-- | test/TEST-23-UNIT-FILE/TEST-23-UNIT-FILE.units/TEST-23-UNIT-FILE-openfile-server.socket (renamed from test/units/testsuite-77-server.socket) | 2 | ||||
-rw-r--r-- | test/TEST-23-UNIT-FILE/TEST-23-UNIT-FILE.units/TEST-23-UNIT-FILE-openfile-server@.service (renamed from test/units/testsuite-77-server@.service) | 2 | ||||
-rw-r--r-- | test/TEST-54-CREDS/systemd.extra-unit.my-service.service (renamed from test/units/testsuite-69.service) | 4 | ||||
-rw-r--r-- | test/TEST-82-SOFTREBOOT/TEST-82-SOFTREBOOT.service (renamed from test/units/testsuite-82.service) | 2 | ||||
-rwxr-xr-x | test/units/TEST-01-BASIC.sh (renamed from test/units/testsuite-01.sh) | 16 | ||||
-rwxr-xr-x | test/units/TEST-02-UNITTESTS.sh | 102 | ||||
-rwxr-xr-x | test/units/TEST-03-JOBS.sh (renamed from test/units/testsuite-03.sh) | 4 | ||||
-rwxr-xr-x | test/units/TEST-04-JOURNAL.LogFilterPatterns.sh | 93 | ||||
-rwxr-xr-x | test/units/TEST-04-JOURNAL.SYSTEMD_JOURNAL_COMPRESS.sh (renamed from test/units/testsuite-04.SYSTEMD_JOURNAL_COMPRESS.sh) | 7 | ||||
-rwxr-xr-x | test/units/TEST-04-JOURNAL.bsod.sh (renamed from test/units/testsuite-04.bsod.sh) | 22 | ||||
-rwxr-xr-x | test/units/TEST-04-JOURNAL.cat.sh | 15 | ||||
-rwxr-xr-x | test/units/TEST-04-JOURNAL.corrupted-journals.sh (renamed from test/units/testsuite-04.corrupted-journals.sh) | 4 | ||||
-rwxr-xr-x | test/units/TEST-04-JOURNAL.fss.sh (renamed from test/units/testsuite-04.fss.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-04-JOURNAL.journal-append.sh (renamed from test/units/testsuite-04.journal-append.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-04-JOURNAL.journal-corrupt.sh (renamed from test/units/testsuite-04.journal-corrupt.sh) | 2 | ||||
-rwxr-xr-x | test/units/TEST-04-JOURNAL.journal-gatewayd.sh | 223 | ||||
-rwxr-xr-x | test/units/TEST-04-JOURNAL.journal-remote.sh (renamed from test/units/testsuite-04.journal-remote.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-04-JOURNAL.journal.sh (renamed from test/units/testsuite-04.journal.sh) | 24 | ||||
-rwxr-xr-x | test/units/TEST-04-JOURNAL.sh (renamed from test/units/testsuite-04.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-05-RLIMITS.effective-limit.sh | 68 | ||||
-rwxr-xr-x | test/units/TEST-05-RLIMITS.rlimit.sh (renamed from test/units/testsuite-05.sh) | 6 | ||||
-rwxr-xr-x | test/units/TEST-05-RLIMITS.sh (renamed from test/units/testsuite-13.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-06-SELINUX.sh (renamed from test/units/testsuite-06.sh) | 6 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.aux-scope.sh | 34 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.exec-context.sh (renamed from test/units/testsuite-07.exec-context.sh) | 19 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.exec-deserialization.sh | 221 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.exec-timestamps.sh | 17 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.issue-14566.sh (renamed from test/units/testsuite-07.issue-14566.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.issue-16115.sh (renamed from test/units/testsuite-07.issue-16115.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.issue-1981.sh (renamed from test/units/testsuite-07.issue-1981.sh) | 2 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.issue-2467.sh (renamed from test/units/testsuite-07.issue-2467.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.issue-27953.sh (renamed from test/units/testsuite-07.issue-27953.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.issue-30412.sh (renamed from test/units/testsuite-07.issue-30412.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.issue-3166.sh (renamed from test/units/testsuite-07.issue-3166.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.issue-3171.sh (renamed from test/units/testsuite-07.issue-3171.sh) | 2 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.main-PID-change.sh (renamed from test/units/testsuite-07.main-PID-change.sh) | 20 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.mount-invalid-chars.sh (renamed from test/units/testsuite-07.mount-invalid-chars.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.poll-limit.sh (renamed from test/units/testsuite-07.poll-limit.sh) | 8 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.pr-31351.sh | 22 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.private-network.sh (renamed from test/units/testsuite-07.private-network.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.sh (renamed from test/units/testsuite-07.sh) | 1 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.socket-pass-fds.sh | 11 | ||||
-rwxr-xr-x | test/units/TEST-07-PID1.type-exec-parallel.sh | 9 | ||||
-rwxr-xr-x | test/units/TEST-08-INITRD.sh (renamed from test/units/testsuite-08.sh) | 6 | ||||
-rwxr-xr-x | test/units/TEST-09-REBOOT.journal.sh (renamed from test/units/testsuite-09.journal.sh) | 60 | ||||
-rwxr-xr-x | test/units/TEST-09-REBOOT.sh (renamed from test/units/testsuite-09.sh) | 2 | ||||
-rwxr-xr-x | test/units/TEST-13-NSPAWN.importctl.sh | 66 | ||||
-rwxr-xr-x | test/units/TEST-13-NSPAWN.machinectl.sh (renamed from test/units/testsuite-13.machinectl.sh) | 48 | ||||
-rwxr-xr-x | test/units/TEST-13-NSPAWN.nspawn-oci.sh (renamed from test/units/testsuite-13.nspawn-oci.sh) | 6 | ||||
-rwxr-xr-x | test/units/TEST-13-NSPAWN.nspawn.sh (renamed from test/units/testsuite-13.nspawn.sh) | 139 | ||||
-rwxr-xr-x | test/units/TEST-13-NSPAWN.nss-mymachines.sh (renamed from test/units/testsuite-13.nss-mymachines.sh) | 7 | ||||
-rwxr-xr-x | test/units/TEST-13-NSPAWN.sh | 18 | ||||
-rwxr-xr-x | test/units/TEST-15-DROPIN.sh (renamed from test/units/testsuite-15.sh) | 18 | ||||
-rwxr-xr-x | test/units/TEST-16-EXTEND-TIMEOUT.sh (renamed from test/units/testsuite-16.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.00.sh (renamed from test/units/testsuite-17.00.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.01.sh (renamed from test/units/testsuite-17.01.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.02.sh (renamed from test/units/testsuite-17.02.sh) | 6 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.03.sh | 114 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.04.sh (renamed from test/units/testsuite-17.04.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.05.sh (renamed from test/units/testsuite-17.05.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.06.sh (renamed from test/units/testsuite-17.06.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.07.sh (renamed from test/units/testsuite-17.07.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.08.sh (renamed from test/units/testsuite-17.08.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.09.sh (renamed from test/units/testsuite-17.09.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.10.sh (renamed from test/units/testsuite-17.10.sh) | 4 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.11.sh (renamed from test/units/testsuite-17.11.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.12.sh (renamed from test/units/testsuite-17.12.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.13.sh (renamed from test/units/testsuite-17.13.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.credentials.sh | 38 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.link-property.sh | 203 | ||||
-rwxr-xr-x | test/units/TEST-17-UDEV.sh (renamed from test/units/testsuite-17.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-18-FAILUREACTION.sh (renamed from test/units/testsuite-18.sh) | 2 | ||||
-rwxr-xr-x | test/units/TEST-19-CGROUP.ExitType-cgroup.sh (renamed from test/units/testsuite-19.ExitType-cgroup.sh) | 5 | ||||
-rwxr-xr-x | test/units/TEST-19-CGROUP.cleanup-slice.sh (renamed from test/units/testsuite-19.cleanup-slice.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-19-CGROUP.delegate.sh (renamed from test/units/testsuite-19.delegate.sh) | 1 | ||||
-rwxr-xr-x | test/units/TEST-19-CGROUP.sh (renamed from test/units/testsuite-19.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-21-DFUZZER.sh (renamed from test/units/testsuite-21.sh) | 28 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.01.sh (renamed from test/units/testsuite-22.01.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.02.sh (renamed from test/units/testsuite-22.02.sh) | 16 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.03.sh (renamed from test/units/testsuite-22.03.sh) | 29 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.04.sh (renamed from test/units/testsuite-22.04.sh) | 6 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.05.sh (renamed from test/units/testsuite-22.05.sh) | 9 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.06.sh (renamed from test/units/testsuite-22.06.sh) | 9 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.07.sh (renamed from test/units/testsuite-22.07.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.08.sh (renamed from test/units/testsuite-22.08.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.09.sh (renamed from test/units/testsuite-22.09.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.10.sh (renamed from test/units/testsuite-22.10.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.11.sh (renamed from test/units/testsuite-22.11.sh) | 118 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.12.sh (renamed from test/units/testsuite-22.12.sh) | 10 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.13.sh (renamed from test/units/testsuite-22.13.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.14.sh (renamed from test/units/testsuite-22.14.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.15.sh (renamed from test/units/testsuite-22.15.sh) | 12 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.16.sh (renamed from test/units/testsuite-22.16.sh) | 5 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.17.sh (renamed from test/units/testsuite-22.17.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.18.sh | 34 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.19.sh | 29 | ||||
-rwxr-xr-x | test/units/TEST-22-TMPFILES.sh (renamed from test/units/testsuite-22.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE-openfile-child.sh | 15 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE-short-lived.sh | 18 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.ExecReload.sh (renamed from test/units/testsuite-23.ExecReload.sh) | 6 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.ExecStopPost.sh (renamed from test/units/testsuite-23.ExecStopPost.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.JoinsNamespaceOf.sh | 31 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.RuntimeDirectoryPreserve.sh (renamed from test/units/testsuite-23.RuntimeDirectoryPreserve.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.StandardOutput.sh (renamed from test/units/testsuite-23.StandardOutput.sh) | 8 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.Upholds.sh | 99 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.clean-unit.sh (renamed from test/units/testsuite-23.clean-unit.sh) | 4 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.exec-command-ex.sh (renamed from test/units/testsuite-23.exec-command-ex.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.oneshot-restart.sh | 101 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.openfile.sh | 55 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.percentj-wantedby.sh (renamed from test/units/testsuite-23.percentj-wantedby.sh) | 4 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.runtime-bind-paths.sh | 43 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.sh (renamed from test/units/testsuite-23.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.start-stop-no-reload.sh | 93 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.statedir.sh (renamed from test/units/testsuite-23.statedir.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.success-failure.sh (renamed from test/units/testsuite-23.success-failure.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.type-exec.sh (renamed from test/units/testsuite-23.type-exec.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.utmp.sh (renamed from test/units/testsuite-23.utmp.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.verify-unit-files.sh | 45 | ||||
-rwxr-xr-x | test/units/TEST-23-UNIT-FILE.whoami.sh (renamed from test/units/testsuite-23.whoami.sh) | 6 | ||||
-rwxr-xr-x | test/units/TEST-24-CRYPTSETUP.sh (renamed from test/units/testsuite-24.sh) | 71 | ||||
-rwxr-xr-x | test/units/TEST-25-IMPORT.sh (renamed from test/units/testsuite-25.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-26-SYSTEMCTL.sh (renamed from test/units/testsuite-26.sh) | 46 | ||||
-rwxr-xr-x | test/units/TEST-29-PORTABLE.sh (renamed from test/units/testsuite-29.sh) | 120 | ||||
-rwxr-xr-x | test/units/TEST-30-ONCLOCKCHANGE.sh (renamed from test/units/testsuite-30.sh) | 2 | ||||
-rwxr-xr-x | test/units/TEST-31-DEVICE-ENUMERATION.sh (renamed from test/units/testsuite-31.sh) | 2 | ||||
-rwxr-xr-x | test/units/TEST-32-OOMPOLICY.sh (renamed from test/units/testsuite-32.sh) | 2 | ||||
-rwxr-xr-x | test/units/TEST-34-DYNAMICUSERMIGRATE.sh (renamed from test/units/testsuite-34.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-35-LOGIN.sh (renamed from test/units/testsuite-35.sh) | 154 | ||||
-rwxr-xr-x | test/units/TEST-36-NUMAPOLICY.sh (renamed from test/units/testsuite-36.sh) | 9 | ||||
-rw-r--r-- | test/units/TEST-38-FREEZER-sleep.service (renamed from test/units/testsuite-38-sleep.service) | 2 | ||||
-rwxr-xr-x | test/units/TEST-38-FREEZER.sh (renamed from test/units/testsuite-38.sh) | 168 | ||||
-rwxr-xr-x | test/units/TEST-43-PRIVATEUSER-UNPRIV.sh (renamed from test/units/testsuite-43.sh) | 6 | ||||
-rwxr-xr-x | test/units/TEST-44-LOG-NAMESPACE.sh (renamed from test/units/testsuite-44.sh) | 12 | ||||
-rwxr-xr-x | test/units/TEST-45-TIMEDATE.sh (renamed from test/units/testsuite-45.sh) | 18 | ||||
-rwxr-xr-x | test/units/TEST-46-HOMED.sh | 620 | ||||
-rwxr-xr-x | test/units/TEST-50-DISSECT.DDI.sh | 70 | ||||
-rwxr-xr-x | test/units/TEST-50-DISSECT.dissect.sh | 745 | ||||
-rwxr-xr-x | test/units/TEST-50-DISSECT.mountfsd.sh | 92 | ||||
-rwxr-xr-x | test/units/TEST-50-DISSECT.sh | 215 | ||||
-rwxr-xr-x | test/units/TEST-50-DISSECT.sysext.sh | 1012 | ||||
-rwxr-xr-x | test/units/TEST-52-HONORFIRSTSHUTDOWN.sh (renamed from test/units/testsuite-52.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-53-ISSUE-16347.sh (renamed from test/units/testsuite-53.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-54-CREDS.sh (renamed from test/units/testsuite-54.sh) | 91 | ||||
-rw-r--r-- | test/units/TEST-55-OOMD-testbloat.service (renamed from test/units/testsuite-55-testbloat.service) | 2 | ||||
-rw-r--r-- | test/units/TEST-55-OOMD-testchill.service (renamed from test/units/testsuite-55-testchill.service) | 2 | ||||
-rw-r--r-- | test/units/TEST-55-OOMD-testmunch.service (renamed from test/units/testsuite-55-testmunch.service) | 2 | ||||
-rw-r--r-- | test/units/TEST-55-OOMD-workload.slice (renamed from test/units/testsuite-55-workload.slice) | 0 | ||||
-rwxr-xr-x | test/units/TEST-55-OOMD.sh (renamed from test/units/testsuite-55.sh) | 68 | ||||
-rwxr-xr-x | test/units/TEST-58-REPART.sh (renamed from test/units/testsuite-58.sh) | 16 | ||||
-rwxr-xr-x | test/units/TEST-59-RELOADING-RESTART.sh (renamed from test/units/testsuite-59.sh) | 14 | ||||
-rwxr-xr-x | test/units/TEST-60-MOUNT-RATELIMIT.sh (renamed from test/units/testsuite-60.sh) | 30 | ||||
-rw-r--r-- | test/units/TEST-62-RESTRICT-IFACES-1.service | 9 | ||||
-rw-r--r-- | test/units/TEST-62-RESTRICT-IFACES-2.service | 10 | ||||
-rw-r--r-- | test/units/TEST-62-RESTRICT-IFACES-3.service (renamed from test/units/testsuite-62-3.service) | 6 | ||||
-rw-r--r-- | test/units/TEST-62-RESTRICT-IFACES-4.service (renamed from test/units/testsuite-62-4.service) | 6 | ||||
-rw-r--r-- | test/units/TEST-62-RESTRICT-IFACES-5.service (renamed from test/units/testsuite-62-5.service) | 6 | ||||
-rw-r--r-- | test/units/TEST-62-RESTRICT-IFACES-6.service (renamed from test/units/testsuite-62-2.service) | 6 | ||||
-rwxr-xr-x | test/units/TEST-62-RESTRICT-IFACES.sh (renamed from test/units/testsuite-62.sh) | 25 | ||||
-rwxr-xr-x | test/units/TEST-63-PATH.sh (renamed from test/units/testsuite-63.sh) | 2 | ||||
-rwxr-xr-x | test/units/TEST-64-UDEV-STORAGE.sh (renamed from test/units/testsuite-64.sh) | 124 | ||||
-rwxr-xr-x | test/units/TEST-65-ANALYZE.sh (renamed from test/units/testsuite-65.sh) | 47 | ||||
-rw-r--r-- | test/units/TEST-66-DEVICE-ISOLATION-device-isolation.service | 10 | ||||
-rwxr-xr-x | test/units/TEST-66-DEVICE-ISOLATION.sh (renamed from test/units/testsuite-66.sh) | 6 | ||||
-rwxr-xr-x | test/units/TEST-67-INTEGRITY.sh (renamed from test/units/testsuite-67.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-68-PROPAGATE-EXIT-STATUS.sh (renamed from test/units/testsuite-68.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-69-SHUTDOWN.py | 58 | ||||
-rwxr-xr-x | test/units/TEST-70-TPM2.creds.sh (renamed from test/units/testsuite-70.creds.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-70-TPM2.cryptenroll.sh (renamed from test/units/testsuite-70.cryptenroll.sh) | 12 | ||||
-rwxr-xr-x | test/units/TEST-70-TPM2.cryptsetup.sh (renamed from test/units/testsuite-70.cryptsetup.sh) | 1 | ||||
-rwxr-xr-x | test/units/TEST-70-TPM2.measure.sh (renamed from test/units/testsuite-70.measure.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-70-TPM2.pcrextend.sh (renamed from test/units/testsuite-70.pcrextend.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-70-TPM2.pcrlock.sh (renamed from test/units/testsuite-70.pcrlock.sh) | 41 | ||||
-rwxr-xr-x | test/units/TEST-70-TPM2.sh (renamed from test/units/testsuite-70.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-70-TPM2.tpm2-setup.sh (renamed from test/units/testsuite-70.tpm2-setup.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-71-HOSTNAME.sh (renamed from test/units/testsuite-71.sh) | 24 | ||||
-rwxr-xr-x | test/units/TEST-72-SYSUPDATE.sh (renamed from test/units/testsuite-72.sh) | 165 | ||||
-rwxr-xr-x | test/units/TEST-73-LOCALE.sh (renamed from test/units/testsuite-73.sh) | 34 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.battery-check.sh (renamed from test/units/testsuite-74.battery-check.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.bootctl.sh (renamed from test/units/testsuite-74.bootctl.sh) | 17 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.busctl.sh (renamed from test/units/testsuite-74.busctl.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.capsule.sh | 53 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.cgls.sh (renamed from test/units/testsuite-74.cgls.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.cgtop.sh (renamed from test/units/testsuite-74.cgtop.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.coredump.sh (renamed from test/units/testsuite-74.coredump.sh) | 28 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.delta.sh (renamed from test/units/testsuite-74.delta.sh) | 4 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.escape.sh (renamed from test/units/testsuite-74.escape.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.firstboot.sh (renamed from test/units/testsuite-74.firstboot.sh) | 22 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.id128.sh (renamed from test/units/testsuite-74.id128.sh) | 7 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.machine-id-setup.sh (renamed from test/units/testsuite-74.machine-id-setup.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.modules-load.sh (renamed from test/units/testsuite-74.modules-load.sh) | 42 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.mount.sh (renamed from test/units/testsuite-74.mount.sh) | 73 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.network-generator.sh | 37 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.networkctl.sh (renamed from test/units/testsuite-74.networkctl.sh) | 42 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.path.sh (renamed from test/units/testsuite-74.path.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.pstore.sh (renamed from test/units/testsuite-74.pstore.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.run.sh (renamed from test/units/testsuite-74.run.sh) | 41 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.sh (renamed from test/units/testsuite-74.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.socket.sh | 84 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.ssh.sh | 60 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.varlinkctl.sh (renamed from test/units/testsuite-74.varlinkctl.sh) | 35 | ||||
-rwxr-xr-x | test/units/TEST-74-AUX-UTILS.vpick.sh | 116 | ||||
-rwxr-xr-x | test/units/TEST-75-RESOLVED.sh (renamed from test/units/testsuite-75.sh) | 219 | ||||
-rwxr-xr-x | test/units/TEST-76-SYSCTL.sh (renamed from test/units/testsuite-76.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-78-SIGQUEUE.sh (renamed from test/units/testsuite-78.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-79-MEMPRESS.sh (renamed from test/units/testsuite-79.sh) | 14 | ||||
-rwxr-xr-x | test/units/TEST-80-NOTIFYACCESS.sh (renamed from test/units/testsuite-80.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-81-GENERATORS.debug-generator.sh (renamed from test/units/testsuite-81.debug-generator.sh) | 7 | ||||
-rwxr-xr-x | test/units/TEST-81-GENERATORS.environment-d-generator.sh (renamed from test/units/testsuite-81.environment-d-generator.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-81-GENERATORS.fstab-generator.sh (renamed from test/units/testsuite-81.fstab-generator.sh) | 7 | ||||
-rwxr-xr-x | test/units/TEST-81-GENERATORS.getty-generator.sh (renamed from test/units/testsuite-81.getty-generator.sh) | 2 | ||||
-rwxr-xr-x | test/units/TEST-81-GENERATORS.run-generator.sh (renamed from test/units/testsuite-81.run-generator.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-81-GENERATORS.sh (renamed from test/units/testsuite-81.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-81-GENERATORS.system-update-generator.sh (renamed from test/units/testsuite-81.system-update-generator.sh) | 0 | ||||
-rwxr-xr-x | test/units/TEST-82-SOFTREBOOT.sh (renamed from test/units/testsuite-82.sh) | 111 | ||||
-rwxr-xr-x | test/units/TEST-83-BTRFS.sh (renamed from test/units/testsuite-83.sh) | 7 | ||||
-rwxr-xr-x | test/units/TEST-84-STORAGETM.sh (renamed from test/units/testsuite-84.sh) | 0 | ||||
-rw-r--r-- | test/units/a-conj.service | 2 | ||||
-rw-r--r-- | test/units/a.service | 2 | ||||
-rw-r--r-- | test/units/autorelabel.service | 8 | ||||
-rw-r--r-- | test/units/b.service | 2 | ||||
-rw-r--r-- | test/units/c.service | 2 | ||||
-rw-r--r-- | test/units/d.service | 2 | ||||
-rw-r--r-- | test/units/daughter.service | 2 | ||||
-rwxr-xr-x | test/units/delegated_cgroup_filtering_payload.sh | 11 | ||||
-rwxr-xr-x | test/units/delegated_cgroup_filtering_payload_child.sh | 9 | ||||
-rw-r--r-- | test/units/dml-discard-empty.service | 2 | ||||
-rw-r--r-- | test/units/dml-discard-set-ml.service | 2 | ||||
-rw-r--r-- | test/units/dml-override-empty.service | 2 | ||||
-rw-r--r-- | test/units/dml-passthrough-empty.service | 2 | ||||
-rw-r--r-- | test/units/dml-passthrough-set-dml.service | 2 | ||||
-rw-r--r-- | test/units/dml-passthrough-set-ml.service | 2 | ||||
-rw-r--r-- | test/units/e.service | 2 | ||||
-rwxr-xr-x | test/units/end.sh | 10 | ||||
-rw-r--r-- | test/units/f.service | 2 | ||||
-rw-r--r-- | test/units/g.service | 2 | ||||
-rwxr-xr-x | test/units/generator-utils.sh | 2 | ||||
-rw-r--r-- | test/units/grandchild.service | 2 | ||||
-rw-r--r-- | test/units/h.service | 2 | ||||
-rw-r--r-- | test/units/i.service | 2 | ||||
-rw-r--r-- | test/units/loopy.service | 2 | ||||
-rw-r--r-- | test/units/loopy2.service | 2 | ||||
-rw-r--r-- | test/units/loopy3.service | 2 | ||||
-rw-r--r-- | test/units/loopy4.service | 2 | ||||
-rw-r--r-- | test/units/nomemleaf.service | 2 | ||||
-rw-r--r-- | test/units/sched_idle_bad.service | 2 | ||||
-rw-r--r-- | test/units/sched_idle_ok.service | 2 | ||||
-rw-r--r-- | test/units/sched_rr_bad.service | 2 | ||||
-rw-r--r-- | test/units/sched_rr_change.service | 2 | ||||
-rw-r--r-- | test/units/sched_rr_ok.service | 2 | ||||
-rw-r--r-- | test/units/son.service | 2 | ||||
-rw-r--r-- | test/units/test-control.sh | 2 | ||||
-rw-r--r-- | test/units/testsuite-01.service | 10 | ||||
-rw-r--r-- | test/units/testsuite-02.service | 8 | ||||
-rwxr-xr-x | test/units/testsuite-02.sh | 113 | ||||
-rw-r--r-- | test/units/testsuite-03.service | 9 | ||||
-rwxr-xr-x | test/units/testsuite-04.LogFilterPatterns.sh | 86 | ||||
-rwxr-xr-x | test/units/testsuite-04.journal-gatewayd.sh | 119 | ||||
-rw-r--r-- | test/units/testsuite-04.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-05.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-06.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-08.service | 9 | ||||
-rw-r--r-- | test/units/testsuite-09.service | 9 | ||||
-rw-r--r-- | test/units/testsuite-13.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-15.service | 8 | ||||
-rwxr-xr-x | test/units/testsuite-17.03.sh | 75 | ||||
-rw-r--r-- | test/units/testsuite-17.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-18.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-19.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-21.service | 10 | ||||
-rw-r--r-- | test/units/testsuite-22.service | 11 | ||||
-rwxr-xr-x | test/units/testsuite-23-short-lived.sh | 18 | ||||
-rwxr-xr-x | test/units/testsuite-23.JoinsNamespaceOf.sh | 31 | ||||
-rwxr-xr-x | test/units/testsuite-23.Upholds.sh | 99 | ||||
-rwxr-xr-x | test/units/testsuite-23.oneshot-restart.sh | 52 | ||||
-rwxr-xr-x | test/units/testsuite-23.runtime-bind-paths.sh | 43 | ||||
-rw-r--r-- | test/units/testsuite-23.service | 8 | ||||
-rwxr-xr-x | test/units/testsuite-23.start-stop-no-reload.sh | 93 | ||||
-rw-r--r-- | test/units/testsuite-24.service | 9 | ||||
-rw-r--r-- | test/units/testsuite-25.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-26.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-29.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-30.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-31.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-32.service | 9 | ||||
-rw-r--r-- | test/units/testsuite-34.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-35.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-36.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-38.service | 7 | ||||
-rw-r--r-- | test/units/testsuite-43.service | 10 | ||||
-rw-r--r-- | test/units/testsuite-44.service | 12 | ||||
-rw-r--r-- | test/units/testsuite-45.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-46.service | 13 | ||||
-rwxr-xr-x | test/units/testsuite-46.sh | 319 | ||||
-rw-r--r-- | test/units/testsuite-50.service | 8 | ||||
-rwxr-xr-x | test/units/testsuite-50.sh | 718 | ||||
-rw-r--r-- | test/units/testsuite-52.service | 7 | ||||
-rw-r--r-- | test/units/testsuite-53.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-54.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-55.service | 10 | ||||
-rw-r--r-- | test/units/testsuite-58.service | 7 | ||||
-rw-r--r-- | test/units/testsuite-59.service | 7 | ||||
-rw-r--r-- | test/units/testsuite-60.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-62-1.service | 9 | ||||
-rw-r--r-- | test/units/testsuite-62.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-63.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-64.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-65.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-66-deviceisolation.service | 10 | ||||
-rw-r--r-- | test/units/testsuite-66.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-67.service | 9 | ||||
-rw-r--r-- | test/units/testsuite-68.service | 7 | ||||
-rw-r--r-- | test/units/testsuite-70.service | 7 | ||||
-rw-r--r-- | test/units/testsuite-71.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-72.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-73.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-74.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-75.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-76.service | 8 | ||||
-rwxr-xr-x | test/units/testsuite-77-client.sh | 14 | ||||
-rwxr-xr-x | test/units/testsuite-77-run.sh | 14 | ||||
-rw-r--r-- | test/units/testsuite-77.service | 10 | ||||
-rwxr-xr-x | test/units/testsuite-77.sh | 38 | ||||
-rw-r--r-- | test/units/testsuite-78.service | 7 | ||||
-rw-r--r-- | test/units/testsuite-79.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-80.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-81.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-83.service | 8 | ||||
-rw-r--r-- | test/units/testsuite-84.service | 9 | ||||
-rw-r--r-- | test/units/unit-with-multiple-dashes.service | 2 | ||||
-rwxr-xr-x | test/units/util.sh | 166 |
332 files changed, 7320 insertions, 3069 deletions
diff --git a/test/units/testsuite-07.service b/test/TEST-07-PID1/TEST-07-PID1.service index 92302bf..53dd54c 100644 --- a/test/units/testsuite-07.service +++ b/test/TEST-07-PID1/TEST-07-PID1.service @@ -1,6 +1,9 @@ # SPDX-License-Identifier: LGPL-2.1-or-later [Unit] Description=TEST-07-PID1 +Wants=basic.target multi-user.target +After=basic.target +Before=getty-pre.target [Service] Type=oneshot diff --git a/test/units/testsuite-16.service b/test/TEST-16-EXTEND-TIMEOUT/TEST-16-EXTEND-TIMEOUT.service index d5494ae..3be8ef5 100644 --- a/test/units/testsuite-16.service +++ b/test/TEST-16-EXTEND-TIMEOUT/TEST-16-EXTEND-TIMEOUT.service @@ -3,6 +3,10 @@ Description=TEST-16-EXTEND-TIMEOUT # Testsuite: Assess all other testsuite-*.services worked as expected +Wants=basic.target multi-user.target +After=basic.target +Before=getty-pre.target + Wants=success-all.service Wants=success-start.service Wants=success-runtime.service @@ -14,7 +18,5 @@ StopWhenUnneeded=yes [Service] ExecStartPre=rm -f /failed /testok -Type=exec -TimeoutStartSec=infinity -ExecStartPre=/usr/lib/systemd/tests/testdata/units/%N.sh -ExecStart=true +Type=oneshot +ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh diff --git a/test/units/testsuite-77-server.socket b/test/TEST-23-UNIT-FILE/TEST-23-UNIT-FILE.units/TEST-23-UNIT-FILE-openfile-server.socket index 4305077..c8f7595 100644 --- a/test/units/testsuite-77-server.socket +++ b/test/TEST-23-UNIT-FILE/TEST-23-UNIT-FILE.units/TEST-23-UNIT-FILE-openfile-server.socket @@ -1,5 +1,5 @@ [Unit] -Description=TEST-77-OPENFILE server socket +Description=OpenFile= test server socket [Socket] ListenStream=/tmp/test.sock diff --git a/test/units/testsuite-77-server@.service b/test/TEST-23-UNIT-FILE/TEST-23-UNIT-FILE.units/TEST-23-UNIT-FILE-openfile-server@.service index 8e99ac8..a57c804 100644 --- a/test/units/testsuite-77-server@.service +++ b/test/TEST-23-UNIT-FILE/TEST-23-UNIT-FILE.units/TEST-23-UNIT-FILE-openfile-server@.service @@ -1,5 +1,5 @@ [Unit] -Description=TEST-77-OPENFILE server +Description=OpenFile= test server service [Service] ExecStart=echo "Socket" diff --git a/test/units/testsuite-69.service b/test/TEST-54-CREDS/systemd.extra-unit.my-service.service index 7aa0664..e29d0ee 100644 --- a/test/units/testsuite-69.service +++ b/test/TEST-54-CREDS/systemd.extra-unit.my-service.service @@ -1,7 +1,5 @@ # SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-69-SHUTDOWN [Service] Type=oneshot -ExecStart=/bin/true +ExecStart=touch /tmp/unit-cred diff --git a/test/units/testsuite-82.service b/test/TEST-82-SOFTREBOOT/TEST-82-SOFTREBOOT.service index a8fc4f9..f3892a7 100644 --- a/test/units/testsuite-82.service +++ b/test/TEST-82-SOFTREBOOT/TEST-82-SOFTREBOOT.service @@ -2,7 +2,9 @@ [Unit] Description=TEST-82-SOFTREBOOT DefaultDependencies=no +Wants=basic.target multi-user.target After=basic.target +Before=getty-pre.target [Service] Type=oneshot diff --git a/test/units/testsuite-01.sh b/test/units/TEST-01-BASIC.sh index 870b62d..bb3ff2f 100755 --- a/test/units/testsuite-01.sh +++ b/test/units/TEST-01-BASIC.sh @@ -48,14 +48,16 @@ systemd-analyze blame # Test for 'systemd-update-utmp runlevel' vs 'systemctl daemon-reexec'. # See issue #27163. # shellcheck disable=SC2034 -for _ in {0..10}; do - systemctl daemon-reexec & - pid_reexec=$! - # shellcheck disable=SC2034 +if [[ -x /usr/lib/systemd/systemd-update-utmp ]]; then for _ in {0..10}; do - SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/systemd-update-utmp runlevel + systemctl daemon-reexec & + pid_reexec=$! + # shellcheck disable=SC2034 + for _ in {0..10}; do + SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/systemd-update-utmp runlevel + done + wait "$pid_reexec" done - wait "$pid_reexec" -done +fi touch /testok diff --git a/test/units/TEST-02-UNITTESTS.sh b/test/units/TEST-02-UNITTESTS.sh new file mode 100755 index 0000000..6392425 --- /dev/null +++ b/test/units/TEST-02-UNITTESTS.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +if ! systemd-detect-virt -qc && [[ "${TEST_CMDLINE_NEWLINE:-}" != bar ]]; then + cat /proc/cmdline + echo >&2 "Expected TEST_CMDLINE_NEWLINE=bar from the kernel command line" + exit 1 +fi + +# If we're running with TEST_PREFER_NSPAWN=1 limit the set of tests we run +# in QEMU to only those that can't run in a container to avoid running +# the same tests again in a, most likely, very slow environment +if ! systemd-detect-virt -qc && [[ "${TEST_PREFER_NSPAWN:-0}" -ne 0 ]]; then + TESTS_GLOB="test-loop-block" +else + TESTS_GLOB=${TESTS_GLOB:-test-*} +fi + +NPROC=$(nproc) +MAX_QUEUE_SIZE=${NPROC:-2} + +# Reset state +rm -fv /failed /skipped /testok +touch /lock + +if ! systemd-detect-virt -qc; then + # Make sure ping works for unprivileged users (for test-bpf-firewall) + sysctl net.ipv4.ping_group_range="0 2147483647" +fi + +# Check & report test results +# Arguments: +# $1: test path +# $2: test exit code +run_test() { + if [[ $# -ne 1 ]]; then + echo >&2 "run_test: missing arguments" + exit 1 + fi + + local test="$1" + local name="${test##*/}" + local environment= + + echo "Executing test $name as unit $name.service" + + case "$name" in + test-journal-flush) + environment="SYSTEMD_LOG_LEVEL=info" + ;; + test-journal-verify) + environment="SYSTEMD_LOG_LEVEL=crit" + ;; + esac + + systemd-run \ + --quiet \ + --property Delegate=1 \ + --property EnvironmentFile=-/usr/lib/systemd/systemd-asan-env \ + --property "Environment=$environment" \ + --unit="$name" \ + --wait "$test" && ret=0 || ret=$? + + exec {LOCK_FD}> /lock + flock --exclusive ${LOCK_FD} + + if [[ $ret -eq 77 ]] || [[ $ret -eq 127 ]]; then + echo "$name skipped" + echo "$name" >>/skipped-tests + { + echo "--- $name begin ---" + journalctl --unit="$name" --no-hostname -o short-monotonic + echo "--- $name end ---" + } >>/skipped + elif [[ $ret -ne 0 ]]; then + echo "$name failed with $ret" + echo "$name" >>/failed-tests + { + echo "--- $name begin ---" + journalctl --unit="$name" --no-hostname -o short-monotonic + echo "--- $name end ---" + } >>/failed + else + echo "$name OK" + echo "$name" >>/testok + fi + + exec {LOCK_FD}<&- +} + +export -f run_test + +find /usr/lib/systemd/tests/unit-tests/ -maxdepth 1 -type f -name "${TESTS_GLOB}" -print0 | + xargs -0 -I {} --max-procs="$MAX_QUEUE_SIZE" bash -ec "run_test {}" + +# Test logs are sometimes lost, as the system shuts down immediately after +journalctl --sync + +test ! -s /failed +touch /testok diff --git a/test/units/testsuite-03.sh b/test/units/TEST-03-JOBS.sh index e3567c2..115b941 100755 --- a/test/units/testsuite-03.sh +++ b/test/units/TEST-03-JOBS.sh @@ -80,13 +80,13 @@ cat <<EOF >/run/systemd/system/wait2.service [Unit] Description=Wait for 2 seconds [Service] -ExecStart=/bin/sh -ec 'sleep 2' +ExecStart=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' +ExecStart=sh -ec 'sleep 5; false' EOF # wait2 succeeds diff --git a/test/units/TEST-04-JOURNAL.LogFilterPatterns.sh b/test/units/TEST-04-JOURNAL.LogFilterPatterns.sh new file mode 100755 index 0000000..ec99b86 --- /dev/null +++ b/test/units/TEST-04-JOURNAL.LogFilterPatterns.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +if ! cgroupfs_supports_user_xattrs; then + echo "CGroup does not support user xattrs, skipping LogFilterPatterns= tests." + exit 0 +fi + +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +NEEDS_RELOAD= + +add_logs_filtering_override() { + local unit="${1:?}" + local override_name="${2:?}" + local log_filter="${3:-}" + + mkdir -p "/run/systemd/system/$unit.d/" + echo -ne "[Service]\nLogFilterPatterns=$log_filter" >"/run/systemd/system/$unit.d/$override_name.conf" + NEEDS_RELOAD=1 +} + +run_service_and_fetch_logs() { + local unit="${1:?}" + local start + + if [[ -n "$NEEDS_RELOAD" ]]; then + systemctl daemon-reload + NEEDS_RELOAD= + fi + + journalctl --sync + start="$(date '+%Y-%m-%d %T.%6N')" + systemctl start "$unit" + journalctl -q -u "$unit" -S "$start" -p notice +} + +at_exit() { + rm -rf /run/systemd/system/{logs-filtering,delegated-cgroup-filtering}.service.d + systemctl daemon-reload +} + +trap at_exit EXIT + +# Accept all log messages +add_logs_filtering_override "logs-filtering.service" "00-reset" "" +[[ -n $(run_service_and_fetch_logs "logs-filtering.service") ]] + +add_logs_filtering_override "logs-filtering.service" "01-allow-all" ".*" +[[ -n $(run_service_and_fetch_logs "logs-filtering.service") ]] + +# Discard all log messages +add_logs_filtering_override "logs-filtering.service" "02-discard-all" "~.*" +[[ -z $(run_service_and_fetch_logs "logs-filtering.service") ]] + +# Accept all test messages +add_logs_filtering_override "logs-filtering.service" "03-reset" "" +[[ -n $(run_service_and_fetch_logs "logs-filtering.service") ]] + +# Discard all test messages +add_logs_filtering_override "logs-filtering.service" "04-discard-gg" "~.*gg.*" +[[ -z $(run_service_and_fetch_logs "logs-filtering.service") ]] + +# Deny filter takes precedence +add_logs_filtering_override "logs-filtering.service" "05-allow-all-but-too-late" ".*" +[[ -z $(run_service_and_fetch_logs "logs-filtering.service") ]] + +# Use tilde in a deny pattern +add_logs_filtering_override "logs-filtering.service" "06-reset" "" +add_logs_filtering_override "logs-filtering.service" "07-prevent-tilde" "~~more~" +[[ -z $(run_service_and_fetch_logs "logs-filtering.service") ]] + +# Only allow a pattern that won't be matched +add_logs_filtering_override "logs-filtering.service" "08-reset" "" +add_logs_filtering_override "logs-filtering.service" "09-allow-only-non-existing" "non-existing string" +[[ -z $(run_service_and_fetch_logs "logs-filtering.service") ]] + +# Allow a pattern starting with a tilde +add_logs_filtering_override "logs-filtering.service" "10-allow-with-escape-char" "\\\\x7emore~" +[[ -n $(run_service_and_fetch_logs "logs-filtering.service") ]] + +add_logs_filtering_override "logs-filtering.service" "11-reset" "" +add_logs_filtering_override "logs-filtering.service" "12-allow-with-spaces" "foo bar" +[[ -n $(run_service_and_fetch_logs "logs-filtering.service") ]] + +add_logs_filtering_override "delegated-cgroup-filtering.service" "00-allow-all" ".*" +[[ -n $(run_service_and_fetch_logs "delegated-cgroup-filtering.service") ]] + +add_logs_filtering_override "delegated-cgroup-filtering.service" "01-discard-hello" "~hello" +[[ -z $(run_service_and_fetch_logs "delegated-cgroup-filtering.service") ]] diff --git a/test/units/testsuite-04.SYSTEMD_JOURNAL_COMPRESS.sh b/test/units/TEST-04-JOURNAL.SYSTEMD_JOURNAL_COMPRESS.sh index 96d096d..6da9f5e 100755 --- a/test/units/testsuite-04.SYSTEMD_JOURNAL_COMPRESS.sh +++ b/test/units/TEST-04-JOURNAL.SYSTEMD_JOURNAL_COMPRESS.sh @@ -7,6 +7,12 @@ set -o pipefail mkdir /run/systemd/system/systemd-journald.service.d MACHINE_ID="$(</etc/machine-id)" +mkdir -p /run/systemd/journald.conf.d +cat <<EOF >/run/systemd/journald.conf.d/compress.conf +[Journal] +Compress=yes +EOF + # Reset the start-limit counters, as we're going to restart journald a couple of times systemctl reset-failed systemd-journald.service @@ -35,6 +41,7 @@ EOF fi done +rm /run/systemd/journald.conf.d/compress.conf rm /run/systemd/system/systemd-journald.service.d/compress.conf systemctl daemon-reload systemctl restart systemd-journald.service diff --git a/test/units/testsuite-04.bsod.sh b/test/units/TEST-04-JOURNAL.bsod.sh index 30f0cb0..83feb89 100755 --- a/test/units/testsuite-04.bsod.sh +++ b/test/units/TEST-04-JOURNAL.bsod.sh @@ -4,7 +4,12 @@ set -eux set -o pipefail if systemd-detect-virt -cq; then - echo "This test requires a VM, skipping the test" + echo "This test requires a VM, skipping the test" | tee --append /skipped + exit 0 +fi + +if [[ ! -x /usr/lib/systemd/systemd-bsod ]]; then + echo "systemd-bsod is not installed, skipping the test" | tee --append /skipped exit 0 fi @@ -17,8 +22,22 @@ at_exit() { fi if mountpoint -q /var/log/journal; then + # In order to preserve the journal from the just run test we need to do a little dance, as + # --relinquish-var is not a "true" opposite of --flush, meaning that it won't move the existing + # journal(s) from /var/log/ to /run/log/. To do that, let's rotate the journal first, so all + # important bits are in the archived journal(s)... + journalctl --rotate + # ...then instruct sd-journald to write further entries to the runtime journal... journalctl --relinquish-var + # ...make sure there are no outstanding writes to the persistent journal that might block us from + # unmounting the tmpfs... + journalctl --sync + # ...move the archived journals to the runtime storage... + mv -v "/var/log/journal/$(</etc/machine-id)"/system@*.journal "/run/log/journal/$(</etc/machine-id)/" + # ...get rid of the tmpfs on /var/log/journal/... umount /var/log/journal + # ...and finally flush everything to the "real" persistent journal, so we can collect it after the + # test finishes. journalctl --flush fi @@ -88,6 +107,7 @@ systemctl daemon-reload systemctl start systemd-bsod systemd-cat -p emerg echo "Service emergency message" vcs_dump_and_check "Service emergency message" +systemctl status systemd-bsod systemctl stop systemd-bsod # Wipe the journal diff --git a/test/units/TEST-04-JOURNAL.cat.sh b/test/units/TEST-04-JOURNAL.cat.sh new file mode 100755 index 0000000..bef3e18 --- /dev/null +++ b/test/units/TEST-04-JOURNAL.cat.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +systemctl enable --now systemd-journald@cat-test.socket + +systemd-cat --namespace cat-test env CAT_TEST_RESULT=1 + +timeout 30 bash -c "until systemctl -q is-active systemd-journald@cat-test.service; do sleep .5; done" + +journalctl --namespace cat-test --grep "JOURNAL_STREAM=" +journalctl --namespace cat-test --grep "CAT_TEST_RESULT=1" + +systemctl disable --now systemd-journald@cat-test.socket diff --git a/test/units/testsuite-04.corrupted-journals.sh b/test/units/TEST-04-JOURNAL.corrupted-journals.sh index 2123b10..479011e 100755 --- a/test/units/testsuite-04.corrupted-journals.sh +++ b/test/units/TEST-04-JOURNAL.corrupted-journals.sh @@ -6,11 +6,11 @@ set -o pipefail JOURNAL_DIR="$(mktemp -d)" REMOTE_OUT="$(mktemp -d)" # tar on C8S doesn't support the --zstd option -unzstd --stdout "/test-journals/afl-corrupted-journals.tar.zst" | tar -xC "$JOURNAL_DIR/" +unzstd --stdout "/usr/lib/systemd/tests/testdata/test-journals/afl-corrupted-journals.tar.zst" | tar -xC "$JOURNAL_DIR/" while read -r file; do filename="${file##*/}" unzstd "$file" -o "$JOURNAL_DIR/${filename%*.zst}" -done < <(find /test-journals/corrupted/ -name "*.zst") +done < <(find /usr/lib/systemd/tests/testdata/test-journals/corrupted/ -name "*.zst") # First, try each of them sequentially. Skip this part when running with plain # QEMU, as it is excruciatingly slow # Note: we care only about exit code 124 (timeout) and special bash exit codes diff --git a/test/units/testsuite-04.fss.sh b/test/units/TEST-04-JOURNAL.fss.sh index 03351b8..03351b8 100755 --- a/test/units/testsuite-04.fss.sh +++ b/test/units/TEST-04-JOURNAL.fss.sh diff --git a/test/units/testsuite-04.journal-append.sh b/test/units/TEST-04-JOURNAL.journal-append.sh index 35f9433..35f9433 100755 --- a/test/units/testsuite-04.journal-append.sh +++ b/test/units/TEST-04-JOURNAL.journal-append.sh diff --git a/test/units/testsuite-04.journal-corrupt.sh b/test/units/TEST-04-JOURNAL.journal-corrupt.sh index 051d0ab..c25cf54 100755 --- a/test/units/testsuite-04.journal-corrupt.sh +++ b/test/units/TEST-04-JOURNAL.journal-corrupt.sh @@ -10,6 +10,7 @@ rm -f "/var/log/journal/$(</etc/machine-id)"/user-*@*.journal journalctl --header | grep path # Make sure the user instance is active when we rotate journals +loginctl enable-linger testuser systemd-run --unit user-sleep.service --user -M testuser@ sleep infinity for _ in {0..9}; do @@ -20,6 +21,7 @@ for _ in {0..9}; do done systemctl stop --user -M testuser@ user-sleep.service +loginctl disable-linger testuser journalctl --sync journalctl --rotate --vacuum-files=1 diff --git a/test/units/TEST-04-JOURNAL.journal-gatewayd.sh b/test/units/TEST-04-JOURNAL.journal-gatewayd.sh new file mode 100755 index 0000000..9c7a3d0 --- /dev/null +++ b/test/units/TEST-04-JOURNAL.journal-gatewayd.sh @@ -0,0 +1,223 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +if [[ ! -x /usr/lib/systemd/systemd-journal-gatewayd ]]; then + echo "Built without systemd-journal-gatewayd support, skipping the test" + exit 0 +fi + +LOG_FILE="$(mktemp)" + +at_exit() { + if [[ $? -ne 0 ]]; then + # The $LOG_FILE is potentially huge (as it might be a full copy of the current journal), so let's + # dump it at debug level under a specific syslog tag, so it's clearly separated from the actual test + # journal; things get very confusing otherwise. + systemd-cat -t log-file-dump -p debug cat "$LOG_FILE" + fi + + rm -f "$LOG_FILE" +} + +trap at_exit EXIT + +TEST_MESSAGE="-= This is a test message $RANDOM =-" +TEST_TAG="$(systemd-id128 new)" + +BEFORE_TIMESTAMP="$(date +%s)" +echo "$TEST_MESSAGE" | systemd-cat -t "$TEST_TAG" +sleep 1 +journalctl --sync +TEST_CURSOR="$(journalctl -q -t "$TEST_TAG" -n 0 --show-cursor | awk '{ print $3; }')" +BOOT_CURSOR="$(journalctl -q -b -n 0 --show-cursor | awk '{ print $3; }')" +AFTER_TIMESTAMP="$(date +%s)" + +/usr/lib/systemd/systemd-journal-gatewayd --version +/usr/lib/systemd/systemd-journal-gatewayd --help + +# Default configuration (HTTP, socket activated) +systemctl start systemd-journal-gatewayd.socket + +# /browse +# We should get redirected to /browse by default +curl -LSfs http://localhost:19531 >"$LOG_FILE" +grep -qF "<title>Journal</title>" "$LOG_FILE" +curl -LSfs http://localhost:19531/browse >"$LOG_FILE" +grep -qF "<title>Journal</title>" "$LOG_FILE" +(! curl -LSfs http://localhost:19531/foo/bar/baz) +(! curl -LSfs http://localhost:19531/foo/../../../bar/../baz) + +# /entries +# Accept: text/plain should be the default +curl -LSfs http://localhost:19531/entries >"$LOG_FILE" +grep -qE " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" "$LOG_FILE" +curl -LSfs --header "Accept: text/plain" http://localhost:19531/entries >"$LOG_FILE" +grep -qE " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" "$LOG_FILE" +curl -LSfs --header "Accept: application/json" http://localhost:19531/entries >"$LOG_FILE" +jq -se ".[] | select(.MESSAGE == \"$TEST_MESSAGE\")" "$LOG_FILE" +curl -LSfs --header "Accept: application/json" http://localhost:19531/entries?boot >"$LOG_FILE" +jq -se ".[] | select(.MESSAGE == \"$TEST_MESSAGE\")" "$LOG_FILE" +curl -LSfs --header "Accept: application/json" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" >"$LOG_FILE" +jq -se "length == 1 and select(.[].MESSAGE == \"$TEST_MESSAGE\")" "$LOG_FILE" +# Show 10 entries starting from $BOOT_CURSOR, skip the first 5 +curl -LSfs \ + --header "Accept: application/json" \ + --header "Range: entries=$BOOT_CURSOR:5:10" \ + http://localhost:19531/entries >"$LOG_FILE" +jq -se "length == 10" "$LOG_FILE" +# Check if the specified cursor refers to an existing entry and return just that entry +curl -LSfs \ + --header "Accept: application/json" \ + --header "Range: entries=$TEST_CURSOR" \ + http://localhost:19531/entries?discrete >"$LOG_FILE" +jq -se "length == 1 and select(.[].MESSAGE == \"$TEST_MESSAGE\")" "$LOG_FILE" +# Check entry is present (resp. absent) when filtering by timestamp +curl -LSfs \ + --header "Range: realtime=$BEFORE_TIMESTAMP:" \ + http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" >"$LOG_FILE" +grep -qE " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" "$LOG_FILE" +curl -LSfs \ + --header "Range: realtime=:$AFTER_TIMESTAMP" \ + http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" >"$LOG_FILE" +grep -qE " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" "$LOG_FILE" +curl -LSfs \ + --header "Accept: application/json" \ + --header "Range: realtime=:$BEFORE_TIMESTAMP" \ + http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" >"$LOG_FILE" +jq -se "length == 0" "$LOG_FILE" +curl -LSfs \ + --header "Accept: application/json" \ + --header "Range: realtime=$AFTER_TIMESTAMP:" \ + http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" >"$LOG_FILE" +jq -se "length == 0" "$LOG_FILE" +# Check positive and negative skip when filtering by timestamp +echo "-= This is a second test message =-" | systemd-cat -t "$TEST_TAG" +journalctl --sync +TEST2_CURSOR="$(journalctl -q -t "$TEST_TAG" -n 0 --show-cursor | awk '{ print $3; }')" +echo "-= This is a third test message =-" | systemd-cat -t "$TEST_TAG" +journalctl --sync +sleep 1 +END_TIMESTAMP="$(date +%s)" +curl -LSfs \ + --header "Accept: application/json" \ + --header "Range: realtime=$BEFORE_TIMESTAMP::1:1" \ + http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" >"$LOG_FILE" +jq -se "length == 1 and select(.[].__CURSOR == \"$TEST2_CURSOR\")" "$LOG_FILE" +curl -LSfs \ + --header "Accept: application/json" \ + --header "Range: realtime=$END_TIMESTAMP::-1:1" \ + http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" >"$LOG_FILE" +jq -se "length == 1 and select(.[].__CURSOR == \"$TEST2_CURSOR\")" "$LOG_FILE" + +# No idea how to properly parse this (jq won't cut it), so let's at least do some sanity checks that every +# line is either empty or begins with data: +curl -LSfs --header "Accept: text/event-stream" http://localhost:19531/entries >"$LOG_FILE" +awk '!/^(data: \{.+\}|)$/ { exit 1; }' "$LOG_FILE" +# Same thing as journalctl --output=export +mkdir /tmp/remote-journal +curl -LSfs --header "Accept: application/vnd.fdo.journal" http://localhost:19531/entries >"$LOG_FILE" +/usr/lib/systemd/systemd-journal-remote --output=/tmp/remote-journal/system.journal --split-mode=none "$LOG_FILE" +journalctl --directory=/tmp/remote-journal -t "$TEST_TAG" --grep "$TEST_MESSAGE" +rm -rf /tmp/remote-journal/* +# Let's do the same thing again, but let systemd-journal-remote spawn curl itself +/usr/lib/systemd/systemd-journal-remote --url=http://localhost:19531/entries \ + --output=/tmp/remote-journal/system.journal \ + --split-mode=none +journalctl --directory=/tmp/remote-journal -t "$TEST_TAG" --grep "$TEST_MESSAGE" +rm -rf /tmp/remote-journal + +# /machine +curl -LSfs http://localhost:19531/machine >"$LOG_FILE" +jq . "$LOG_FILE" + +# /fields +curl -LSfs http://localhost:19531/fields/MESSAGE >"$LOG_FILE" +grep -qE -- "$TEST_MESSAGE" "$LOG_FILE" +curl -LSfs http://localhost:19531/fields/_TRANSPORT +(! curl -LSfs http://localhost:19531/fields) +(! curl -LSfs http://localhost:19531/fields/foo-bar-baz) + +systemctl stop systemd-journal-gatewayd.{socket,service} + +if ! command -v openssl >/dev/null; then + echo "openssl command not available, skipping the HTTPS tests" + exit 0 +fi + +# Generate a self-signed certificate for systemd-journal-gatewayd +# +# Note: older OpenSSL requires a config file with some extra options, unfortunately +cat >/tmp/openssl.conf <<EOF +[ req ] +prompt = no +distinguished_name = req_distinguished_name + +[ req_distinguished_name ] +C = CZ +L = Brno +O = Foo +OU = Bar +CN = localhost +EOF +openssl req -x509 -nodes -newkey rsa:2048 -sha256 -days 7 \ + -config /tmp/openssl.conf \ + -keyout /tmp/key.pem -out /tmp/cert.pem +# Start HTTPS version of gatewayd via the systemd-socket-activate tool to give it some coverage as well +systemd-socket-activate --listen=19531 -- \ + /usr/lib/systemd/systemd-journal-gatewayd \ + --cert=/tmp/cert.pem \ + --key=/tmp/key.pem \ + --file="/var/log/journal/*/*.journal" & +GATEWAYD_PID=$! +sleep 1 + +# Do a limited set of tests, since the underlying code should be the same past the HTTPS transport +curl -LSfsk https://localhost:19531 >"$LOG_FILE" +grep -qF "<title>Journal</title>" "$LOG_FILE" +curl -LSfsk https://localhost:19531/entries >"$LOG_FILE" +grep -qE " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" "$LOG_FILE" +curl -LSfsk --header "Accept: application/json" https://localhost:19531/entries >"$LOG_FILE" +jq -se ".[] | select(.MESSAGE == \"$TEST_MESSAGE\")" "$LOG_FILE" +curl -LSfsk https://localhost:19531/machine >"$LOG_FILE" +jq . "$LOG_FILE" +curl -LSfsk https://localhost:19531/fields/_TRANSPORT + +kill "$GATEWAYD_PID" + +# Test a couple of error scenarios +GATEWAYD_FILE="$(mktemp /tmp/test-gatewayd-XXX.journal)" + +/usr/lib/systemd/systemd-journal-remote --output="$GATEWAYD_FILE" --getter="journalctl -n5 -o export" +systemd-run --unit="test-gatewayd.service" --socket-property="ListenStream=19531" \ + /usr/lib/systemd/systemd-journal-gatewayd --file="$GATEWAYD_FILE" + +# Call an unsupported endpoint together with some garbage data - gatewayd should not send garbage in return +# See: https://github.com/systemd/systemd/issues/9858 +OUT="$(mktemp)" +for _ in {0..4}; do + (! curl --fail-with-body -d "please process this🐱 $RANDOM" -L http://localhost:19531/upload | tee "$OUT") + (! grep '[^[:print:]]' "$OUT") +done +(! curl --fail-with-body --upload-file "$GATEWAYD_FILE" -L http://localhost:19531/upload | tee "$OUT") +(! grep '[^[:print:]]' "$OUT") +rm -rf "$OUT" + +curl -LSfs http://localhost:19531/browse >"$LOG_FILE" +grep -qF "<title>Journal</title>" "$LOG_FILE" +# Nuke the file behind the /browse endpoint +mv /usr/share/systemd/gatewayd/browse.html /usr/share/systemd/gatewayd/browse.html.bak +(! curl --fail-with-body -L http://localhost:19531/browse) +mv /usr/share/systemd/gatewayd/browse.html.bak /usr/share/systemd/gatewayd/browse.html +curl -LSfs http://localhost:19531/browse >"$LOG_FILE" +grep -qF "<title>Journal</title>" "$LOG_FILE" + +# Nuke the journal file +mv "$GATEWAYD_FILE" "$GATEWAYD_FILE.bak" +(! curl --fail-with-body -L http://localhost:19531/fields/_PID) +mv "$GATEWAYD_FILE.bak" "$GATEWAYD_FILE" +curl -LSfs http://localhost:19531/fields/_PID + +systemctl stop test-gatewayd.{socket,service} +rm -f "$GATEWAYD_FILE" diff --git a/test/units/testsuite-04.journal-remote.sh b/test/units/TEST-04-JOURNAL.journal-remote.sh index c7b99b1..c7b99b1 100755 --- a/test/units/testsuite-04.journal-remote.sh +++ b/test/units/TEST-04-JOURNAL.journal-remote.sh diff --git a/test/units/testsuite-04.journal.sh b/test/units/TEST-04-JOURNAL.journal.sh index 3b72aa4..bd9f8a5 100755 --- a/test/units/testsuite-04.journal.sh +++ b/test/units/TEST-04-JOURNAL.journal.sh @@ -1,6 +1,5 @@ #!/usr/bin/env bash # SPDX-License-Identifier: LGPL-2.1-or-later -# shellcheck disable=SC2317 set -eux set -o pipefail @@ -105,9 +104,16 @@ diff /tmp/expected /tmp/output # test that LogLevelMax can also suppress logging about services, not only by services systemctl start silent-success -journalctl --sync [[ -z "$(journalctl -b -q -u silent-success.service)" ]] +# Test syslog identifiers exclusion +systemctl start verbose-success.service +[[ -n "$(journalctl -b -q -u verbose-success.service -t systemd)" ]] +[[ -n "$(journalctl -b -q -u verbose-success.service -t echo)" ]] +[[ -n "$(journalctl -b -q -u verbose-success.service -T systemd)" ]] +[[ -n "$(journalctl -b -q -u verbose-success.service -T echo)" ]] +[[ -z "$(journalctl -b -q -u verbose-success.service -T echo -T '(echo)' -T sleep -T '(sleep)' -T systemd -T '(systemd)' -T systemd-executor)" ]] + # Exercise the matching machinery SYSTEMD_LOG_LEVEL=debug journalctl -b -n 1 /dev/null /dev/zero /dev/null /dev/null /dev/null journalctl -b -n 1 /bin/true /bin/false @@ -124,6 +130,8 @@ journalctl -b -n 1 -r --user-unit "*" # Facilities & priorities journalctl --facility help +journalctl --facility help | grep -F 'kern' +journalctl --facility help | grep -F 'mail' journalctl --facility kern -n 1 journalctl --facility syslog --priority 0..3 -n 1 journalctl --facility syslog --priority 3..0 -n 1 @@ -135,6 +143,8 @@ journalctl --facility daemon --priority 5..crit -n 1 # Assorted combinations journalctl -o help +journalctl -o help | grep -F 'short' +journalctl -o help | grep -F 'export' journalctl -q -n all -a | grep . >/dev/null journalctl -q --no-full | grep . >/dev/null journalctl -q --user --system | grep . >/dev/null @@ -235,7 +245,7 @@ JOURNAL_DIR="$(mktemp -d)" while read -r file; do filename="${file##*/}" unzstd "$file" -o "$JOURNAL_DIR/${filename%*.zst}" -done < <(find /test-journals/no-rtc -name "*.zst") +done < <(find /usr/lib/systemd/tests/testdata/test-journals/no-rtc -name "*.zst") journalctl --directory="$JOURNAL_DIR" --list-boots --output=json >/tmp/lb1 diff -u /tmp/lb1 - <<'EOF' @@ -243,9 +253,6 @@ diff -u /tmp/lb1 - <<'EOF' EOF rm -rf "$JOURNAL_DIR" /tmp/lb1 -# v255-only: skip the following test case, as it suffers from systemd/systemd#30886 -exit 0 - # Check that using --after-cursor/--cursor-file= together with journal filters doesn't # skip over entries matched by the filter # See: https://github.com/systemd/systemd/issues/30288 @@ -253,8 +260,8 @@ UNIT_NAME="test-cursor-$RANDOM.service" CURSOR_FILE="$(mktemp)" # Generate some messages we can match against journalctl --cursor-file="$CURSOR_FILE" -n1 -systemd-run --unit="$UNIT_NAME" --wait --service-type=exec bash -xec "echo hello; echo world" -journalctl --sync +systemd-run --unit="$UNIT_NAME" --wait --service-type=exec -p LogLevelMax=info \ + bash -ec "set -x; echo hello; echo world; set +x; journalctl --sync" # --after-cursor= + --unit= # The format of the "Starting ..." message depends on StatusUnitFormat=, so match only the beginning # which should be enough in this case @@ -267,6 +274,7 @@ diff <(journalctl --cursor-file="$CURSOR_FILE" -p info -o cat _SYSTEMD_UNIT="$UN hello + echo world world ++ set +x EOF rm -f "$CURSOR_FILE" diff --git a/test/units/testsuite-04.sh b/test/units/TEST-04-JOURNAL.sh index 9c2a033..9c2a033 100755 --- a/test/units/testsuite-04.sh +++ b/test/units/TEST-04-JOURNAL.sh diff --git a/test/units/TEST-05-RLIMITS.effective-limit.sh b/test/units/TEST-05-RLIMITS.effective-limit.sh new file mode 100755 index 0000000..f6639f1 --- /dev/null +++ b/test/units/TEST-05-RLIMITS.effective-limit.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +pre=test05 +cat >/run/systemd/system/"$pre"alpha.slice <<EOF +[Slice] +MemoryMax=400M +MemoryHigh=400M +TasksMax=400 +EOF + +cat >/run/systemd/system/"$pre"alpha-beta.slice <<EOF +[Slice] +MemoryMax=100M +MemoryHigh=100M +TasksMax=100 +EOF + +cat >/run/systemd/system/"$pre"alpha-beta-gamma.slice <<EOF +[Slice] +MemoryMax=200M +MemoryHigh=200M +TasksMax=200 +EOF + +systemctl daemon-reload + +srv=probe.service +slc0="$pre"alpha.slice +slc="$pre"alpha-beta-gamma.slice + +systemd-run --unit "$srv" --slice "$slc" \ + -p MemoryMax=50M \ + -p MemoryHigh=50M \ + -p TasksMax=50 \ + sleep inf + +# Compare with inequality because test can run in a constrained container +assert_le "$(systemctl show -P EffectiveMemoryMax "$srv")" "52428800" +assert_le "$(systemctl show -P EffectiveMemoryHigh "$srv")" "52428800" +assert_le "$(systemctl show -P EffectiveTasksMax "$srv")" "50" + +systemctl stop "$srv" + +systemd-run --unit "$srv" --slice "$slc" \ + sleep inf + +assert_le "$(systemctl show -P EffectiveMemoryMax "$srv")" "104857600" +assert_le "$(systemctl show -P EffectiveMemoryHigh "$srv")" "104857600" +assert_le "$(systemctl show -P EffectiveTasksMax "$srv")" "100" + +systemctl set-property "$slc0" \ + MemoryMax=50M \ + MemoryHigh=50M \ + TasksMax=50 + +assert_le "$(systemctl show -P EffectiveMemoryMax "$srv")" "52428800" +assert_le "$(systemctl show -P EffectiveMemoryHigh "$srv")" "52428800" +assert_le "$(systemctl show -P EffectiveTasksMax "$srv")" "50" + +systemctl stop "$srv" + +rm -f /run/systemd/system/"$pre"* || : diff --git a/test/units/testsuite-05.sh b/test/units/TEST-05-RLIMITS.rlimit.sh index 870845d..6b425d4 100755 --- a/test/units/testsuite-05.sh +++ b/test/units/TEST-05-RLIMITS.rlimit.sh @@ -16,12 +16,10 @@ systemctl daemon-reload [[ "$(systemctl show -P DefaultLimitNOFILESoft)" = "10000" ]] [[ "$(systemctl show -P DefaultLimitNOFILE)" = "16384" ]] -[[ "$(systemctl show -P LimitNOFILESoft testsuite-05.service)" = "10000" ]] -[[ "$(systemctl show -P LimitNOFILE testsuite-05.service)" = "16384" ]] +[[ "$(systemctl show -P LimitNOFILESoft TEST-05-RLIMITS.service)" = "10000" ]] +[[ "$(systemctl show -P LimitNOFILE TEST-05-RLIMITS.service)" = "16384" ]] # shellcheck disable=SC2016 systemd-run --wait -t bash -c '[[ "$(ulimit -n -S)" = "10000" ]]' # shellcheck disable=SC2016 systemd-run --wait -t bash -c '[[ "$(ulimit -n -H)" = "16384" ]]' - -touch /testok diff --git a/test/units/testsuite-13.sh b/test/units/TEST-05-RLIMITS.sh index 9c2a033..9c2a033 100755 --- a/test/units/testsuite-13.sh +++ b/test/units/TEST-05-RLIMITS.sh diff --git a/test/units/testsuite-06.sh b/test/units/TEST-06-SELINUX.sh index 7fc3c37..937a040 100755 --- a/test/units/testsuite-06.sh +++ b/test/units/TEST-06-SELINUX.sh @@ -3,6 +3,12 @@ set -eux set -o pipefail +. /etc/os-release +if ! [[ "$ID" =~ centos|fedora ]]; then + echo "Skipping because only CentOS and Fedora support SELinux tests" >>/skipped + exit 77 +fi + # Note: ATTOW the following checks should work with both Fedora and upstream reference policy # (with or without MCS/MLS) diff --git a/test/units/TEST-07-PID1.aux-scope.sh b/test/units/TEST-07-PID1.aux-scope.sh new file mode 100755 index 0000000..8e2a99c --- /dev/null +++ b/test/units/TEST-07-PID1.aux-scope.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -ex +set -o pipefail + +export SYSTEMD_PAGER=cat + +if ! grep -q pidfd_open /proc/kallsyms; then + echo "pidfds not available, skipping the test..." + exit 0 +fi + +systemd-run --unit test-aux-scope.service \ + --service-type notify -p Slice=aux.slice -p TasksMax=99 -p CPUWeight=199 -p IPAccounting=yes \ + /usr/lib/systemd/tests/unit-tests/manual/test-aux-scope +kill -s USR1 "$(systemctl show --value --property MainPID test-aux-scope.service)" + +timeout 30s bash -xec 'until systemctl is-active test-aux-scope.scope; do sleep 1; done' + +systemctl status test-aux-scope.service +# shellcheck disable=SC2009 +test "$(ps -eo pid,unit | grep -c test-aux-scope.service)" = 1 + +systemctl status test-aux-scope.scope +# shellcheck disable=SC2009 +test "$(ps -eo pid,unit | grep -c test-aux-scope.scope)" = 10 + +test "$(systemctl show -p Slice --value test-aux-scope.scope)" = aux.slice +test "$(systemctl show -p TasksMax --value test-aux-scope.scope)" = 99 +test "$(systemctl show -p CPUWeight --value test-aux-scope.scope)" = 199 +test "$(systemctl show -p IPAccounting --value test-aux-scope.scope)" = yes + +systemctl stop test-aux-scope.scope +systemctl stop test-aux-scope.service diff --git a/test/units/testsuite-07.exec-context.sh b/test/units/TEST-07-PID1.exec-context.sh index b44658f..a3379ef 100755 --- a/test/units/testsuite-07.exec-context.sh +++ b/test/units/TEST-07-PID1.exec-context.sh @@ -32,10 +32,19 @@ proc_supports_option() { # the transient stuff from systemd-run. Let's just skip the following tests # in that case instead of complicating the test setup even more */ if [[ -z "${COVERAGE_BUILD_DIR:-}" ]]; then + if ! systemd-detect-virt -cq && command -v bootctl >/dev/null; then + boot_path="$(bootctl --print-boot-path)" + esp_path="$(bootctl --print-esp-path)" + + # If the mount points are handled by automount units, make sure we trigger + # them before proceeding further + ls -l "$boot_path" "$esp_path" + fi + systemd-run --wait --pipe -p ProtectSystem=yes \ - bash -xec "test ! -w /usr; test ! -w /boot; test -w /etc; test -w /var" + bash -xec "test ! -w /usr; ${boot_path:+"test ! -w $boot_path; test ! -w $esp_path;"} test -w /etc; test -w /var" systemd-run --wait --pipe -p ProtectSystem=full \ - bash -xec "test ! -w /usr; test ! -w /boot; test ! -w /etc; test -w /var" + bash -xec "test ! -w /usr; ${boot_path:+"test ! -w $boot_path; test ! -w $esp_path;"} test ! -w /etc; test -w /var" systemd-run --wait --pipe -p ProtectSystem=strict \ bash -xec "test ! -w /; test ! -w /etc; test ! -w /var; test -w /dev; test -w /proc" systemd-run --wait --pipe -p ProtectSystem=no \ @@ -149,13 +158,13 @@ if ! systemd-detect-virt -cq; then -p DevicePolicy=closed -p DevicePolicy=strict -p DeviceAllow="char-mem rm" # Allow read & mknod for /dev/{null,zero,...} - -p DeviceAllow="/dev/loop0 rw" - -p DeviceAllow="/dev/loop0 w" # Allow write for /dev/loop0 + -p DeviceAllow="$LODEV rw" + -p DeviceAllow="$LODEV w" # Allow write for the loop # Everything else should be disallowed per the strict policy ) systemd-run --wait --pipe --unit "$SERVICE_NAME" "${ARGUMENTS[@]}" \ - bash -xec 'test -r /dev/null; test ! -w /dev/null; test ! -r /dev/loop0; test -w /dev/loop0; test ! -r /dev/tty; test ! -w /dev/tty' + bash -xec "test -r /dev/null; test ! -w /dev/null; test ! -r $LODEV; test -w $LODEV; test ! -r /dev/tty; test ! -w /dev/tty" if ! systemctl --version | grep -qF -- "-BPF_FRAMEWORK"; then # SocketBind*= diff --git a/test/units/TEST-07-PID1.exec-deserialization.sh b/test/units/TEST-07-PID1.exec-deserialization.sh new file mode 100755 index 0000000..04f17c8 --- /dev/null +++ b/test/units/TEST-07-PID1.exec-deserialization.sh @@ -0,0 +1,221 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2016 +set -eux +set -o pipefail + +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +setup_base_unit() { + local unit_path="${1:?}" + local log_file="${2:?}" + local unit_name="${unit_path##*/}" + + cat >"$unit_path" <<EOF +[Service] +Type=oneshot +ExecStart=sleep 3 +ExecStart=bash -c "echo foo >>$log_file" +EOF + systemctl daemon-reload + + systemctl --job-mode=replace --no-block start "$unit_name" + # Wait until the unit leaves the "inactive" state + timeout 5s bash -xec "while [[ \"\$(systemctl show -P ActiveState $unit_name)\" == inactive ]]; do sleep .1; done" + # Sleep for 1 second from the unit start to get well "into" the first (or second) ExecStart= directive + sleep 1 +} + +check_output() { + local unit_name="${1:?}" + local log_file="${2:?}" + local expected="${3?}" + local unit_name="${unit_path##*/}" + + # Wait until the unit becomes inactive before checking the log + timeout 10s bash -xec "while [[ \"\$(systemctl show -P ActiveState $unit_name)\" != inactive ]]; do sleep .5; done" + + diff "$log_file" <(echo -ne "$expected") +} + +testcase_no_change() { + local unit_path log_file + + unit_path="$(mktemp /run/systemd/system/test-deserialization-no-change-XXX.service)" + log_file="$(mktemp)" + + setup_base_unit "$unit_path" "$log_file" + + # Simple sanity test without any reordering shenanignans, to check if the base unit works as expected. + check_output "$unit_path" "$log_file" "foo\n" + + rm -f "$unit_path" "$log_file" +} + +testcase_swapped() { + local unit_path log_file + + unit_path="$(mktemp /run/systemd/system/test-deserialization-swapped-XXX.service)" + log_file="$(mktemp)" + + setup_base_unit "$unit_path" "$log_file" + + # Swap the two ExecStart= lines. + # + # Since we should be in the first "sleep" of the base unit, after replacing the unit with the following + # one we should continue running from the respective "ExecStart=sleep 3" line, which is now the last + # one, resulting no output in the final log file. + cat >"$unit_path" <<EOF +[Service] +Type=oneshot +ExecStart=bash -c "echo foo >>$log_file" +ExecStart=sleep 3 +EOF + systemctl daemon-reload + + check_output "$unit_path" "$log_file" "" + + rm -f "$unit_path" "$log_file" +} + +testcase_added_before() { + local unit_path log_file + + unit_path="$(mktemp /run/systemd/system/test-deserialization-added-before-XXX.service)" + log_file="$(mktemp)" + + setup_base_unit "$unit_path" "$log_file" + + # Add one new ExecStart= before the existing ones. + # + # Since, after reload, we should continue running from the "sleep 3" statement, the newly added "echo + # bar" one will have no effect and we should end up with the same output as in the previous case. + cat >"$unit_path" <<EOF +[Service] +Type=oneshot +ExecStart=bash -c "echo bar >>$log_file" +ExecStart=sleep 3 +ExecStart=bash -c "echo foo >>$log_file" +EOF + systemctl daemon-reload + + check_output "$unit_path" "$log_file" "foo\n" + + rm -f "$unit_path" "$log_file" +} + +testcase_added_after() { + local unit_path log_file + + unit_path="$(mktemp /run/systemd/system/test-deserialization-added-after-XXX.service)" + log_file="$(mktemp)" + + setup_base_unit "$unit_path" "$log_file" + + # Add an ExecStart= line after the existing ones. + # + # Same case as above, except the newly added ExecStart= should get executed, as it was added after the + # "sleep 3" statement. + cat >"$unit_path" <<EOF +[Service] +Type=oneshot +ExecStart=sleep 3 +ExecStart=bash -c "echo foo >>$log_file" +ExecStart=bash -c "echo bar >>$log_file" +EOF + systemctl daemon-reload + + check_output "$unit_path" "$log_file" "foo\nbar\n" + + rm -f "$unit_path" "$log_file" +} + +testcase_interleaved() { + local unit_path log_file + + unit_path="$(mktemp /run/systemd/system/test-deserialization-interleaved-XXX.service)" + log_file="$(mktemp)" + + setup_base_unit "$unit_path" "$log_file" + + # Combination of the two previous cases. + cat >"$unit_path" <<EOF +[Service] +Type=oneshot +ExecStart=bash -c "echo baz >>$log_file" +ExecStart=sleep 3 +ExecStart=bash -c "echo foo >>$log_file" +ExecStart=bash -c "echo bar >>$log_file" +EOF + systemctl daemon-reload + + check_output "$unit_path" "$log_file" "foo\nbar\n" + + rm -f "$unit_path" "$log_file" +} + +testcase_removal() { + local unit_path log_file + + unit_path="$(mktemp /run/systemd/system/test-deserialization-removal-XXX.service)" + log_file="$(mktemp)" + + setup_base_unit "$unit_path" "$log_file" + + # Remove the currently executed ExecStart= line. + # + # In this case we completely drop the currently executed "sleep 3" statement, so after reload systemd + # should complain that the currently executed command vanished and simply finish executing the unit, + # resulting in an empty log. + cat >"$unit_path" <<EOF +[Service] +Type=oneshot +ExecStart=bash -c "echo bar >>$log_file" +ExecStart=bash -c "echo baz >>$log_file" +EOF + systemctl daemon-reload + + check_output "$unit_path" "$log_file" "" + + rm -f "$unit_path" "$log_file" +} + +testcase_issue_6533() { + local unit_path unit_name log_file + + unit_path="$(mktemp /run/systemd/system/test-deserialization-issue-6533-XXX.service)" + unit_name="${unit_path##*/}" + log_file="$(mktemp)" + + cat >"$unit_path" <<EOF +[Service] +Type=simple +ExecStart=/bin/sleep 5 +EOF + systemctl daemon-reload + + systemctl --job-mode=replace --no-block start "$unit_name" + sleep 2 + + # Make sure we try to execute the next command only for oneshot services, as for other types we allow + # only one ExecStart= directive. + # + # See: https://github.com/systemd/systemd/issues/6533 + cat >"$unit_path" <<EOF +[Service] +Type=simple +ExecStart=/bin/sleep 5 +ExecStart=bash -c "echo foo >>$log_file" +EOF + systemctl daemon-reload + + check_output "$unit_path" "$log_file" "" + (! journalctl -b --grep "Freezing execution" _PID=1) +} + +mkdir -p /run/systemd/system/ +run_testcases +systemctl daemon-reload diff --git a/test/units/TEST-07-PID1.exec-timestamps.sh b/test/units/TEST-07-PID1.exec-timestamps.sh new file mode 100755 index 0000000..0211166 --- /dev/null +++ b/test/units/TEST-07-PID1.exec-timestamps.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +# Check that timestamps of a Type=notify service are consistent + +systemd-run --service-type notify --property NotifyAccess=all --unit notify.service --wait sh -c 'systemd-notify --ready; exit 1' || : + +start=$(systemctl show --property=ExecMainStartTimestampMonotonic --value notify.service) +handoff=$(systemctl show --property=ExecMainHandoffTimestampMonotonic --value notify.service) +active=$(systemctl show --property=ActiveEnterTimestampMonotonic --value notify.service) +exit=$(systemctl show --property=ExecMainExitTimestampMonotonic --value notify.service) + +[[ $start -le $handoff ]] +[[ $handoff -le $active ]] +[[ $active -le $exit ]] diff --git a/test/units/testsuite-07.issue-14566.sh b/test/units/TEST-07-PID1.issue-14566.sh index d4be5b5..d4be5b5 100755 --- a/test/units/testsuite-07.issue-14566.sh +++ b/test/units/TEST-07-PID1.issue-14566.sh diff --git a/test/units/testsuite-07.issue-16115.sh b/test/units/TEST-07-PID1.issue-16115.sh index 8f63826..8f63826 100755 --- a/test/units/testsuite-07.issue-16115.sh +++ b/test/units/TEST-07-PID1.issue-16115.sh diff --git a/test/units/testsuite-07.issue-1981.sh b/test/units/TEST-07-PID1.issue-1981.sh index 6eb802c..dcfa9b1 100755 --- a/test/units/testsuite-07.issue-1981.sh +++ b/test/units/TEST-07-PID1.issue-1981.sh @@ -24,7 +24,7 @@ Type=oneshot ExecStartPre=sh -c 'test "$TRIGGER_UNIT" = my.timer' ExecStartPre=sh -c 'test -n "$TRIGGER_TIMER_REALTIME_USEC"' ExecStartPre=sh -c 'test -n "$TRIGGER_TIMER_MONOTONIC_USEC"' -ExecStart=/bin/echo Timer runs me +ExecStart=echo Timer runs me EOF cat >/run/systemd/system/my.timer <<EOF diff --git a/test/units/testsuite-07.issue-2467.sh b/test/units/TEST-07-PID1.issue-2467.sh index de0577b..de0577b 100755 --- a/test/units/testsuite-07.issue-2467.sh +++ b/test/units/TEST-07-PID1.issue-2467.sh diff --git a/test/units/testsuite-07.issue-27953.sh b/test/units/TEST-07-PID1.issue-27953.sh index 8659970..8659970 100755 --- a/test/units/testsuite-07.issue-27953.sh +++ b/test/units/TEST-07-PID1.issue-27953.sh diff --git a/test/units/testsuite-07.issue-30412.sh b/test/units/TEST-07-PID1.issue-30412.sh index c1cb00e..c1cb00e 100755 --- a/test/units/testsuite-07.issue-30412.sh +++ b/test/units/TEST-07-PID1.issue-30412.sh diff --git a/test/units/testsuite-07.issue-3166.sh b/test/units/TEST-07-PID1.issue-3166.sh index 6677901..6677901 100755 --- a/test/units/testsuite-07.issue-3166.sh +++ b/test/units/TEST-07-PID1.issue-3166.sh diff --git a/test/units/testsuite-07.issue-3171.sh b/test/units/TEST-07-PID1.issue-3171.sh index db17c25..374df54 100755 --- a/test/units/testsuite-07.issue-3171.sh +++ b/test/units/TEST-07-PID1.issue-3171.sh @@ -24,7 +24,7 @@ cat >/run/systemd/system/issue-3171@.service <<EOF Description=Test service [Service] StandardInput=socket -ExecStart=/bin/sh -x -c cat +ExecStart=sh -x -c cat EOF systemctl start issue-3171.socket diff --git a/test/units/testsuite-07.main-PID-change.sh b/test/units/TEST-07-PID1.main-PID-change.sh index bd1144c..16f3510 100755 --- a/test/units/testsuite-07.main-PID-change.sh +++ b/test/units/TEST-07-PID1.main-PID-change.sh @@ -10,7 +10,7 @@ set -o pipefail # The main service PID should be the parent bash process MAINPID="${PPID:?}" -test "$(systemctl show -P MainPID testsuite-07.service)" -eq "$MAINPID" +test "$(systemctl show -P MainPID TEST-07-PID1.service)" -eq "$MAINPID" # Start a test process inside of our own cgroup sleep infinity & @@ -23,41 +23,41 @@ EXTERNALPID="$(systemctl show -P MainPID test-sleep.service)" # Update our own main PID to the external test PID, this should work systemd-notify MAINPID="$EXTERNALPID" -test "$(systemctl show -P MainPID testsuite-07.service)" -eq "$EXTERNALPID" +test "$(systemctl show -P MainPID TEST-07-PID1.service)" -eq "$EXTERNALPID" # Update our own main PID to the internal test PID, this should work, too systemd-notify MAINPID=$INTERNALPID -test "$(systemctl show -P MainPID testsuite-07.service)" -eq "$INTERNALPID" +test "$(systemctl show -P MainPID TEST-07-PID1.service)" -eq "$INTERNALPID" # Update it back to our own PID, this should also work systemd-notify MAINPID="$MAINPID" -test "$(systemctl show -P MainPID testsuite-07.service)" -eq "$MAINPID" +test "$(systemctl show -P MainPID TEST-07-PID1.service)" -eq "$MAINPID" # Try to set it to PID 1, which it should ignore, because that's the manager systemd-notify MAINPID=1 -test "$(systemctl show -P MainPID testsuite-07.service)" -eq "$MAINPID" +test "$(systemctl show -P MainPID TEST-07-PID1.service)" -eq "$MAINPID" # Try to set it to PID 0, which is invalid and should be ignored systemd-notify MAINPID=0 -test "$(systemctl show -P MainPID testsuite-07.service)" -eq "$MAINPID" +test "$(systemctl show -P MainPID TEST-07-PID1.service)" -eq "$MAINPID" # Try to set it to a valid but non-existing PID, which should be ignored. (Note # that we set the PID to a value well above any known /proc/sys/kernel/pid_max, # which means we can be pretty sure it doesn't exist by coincidence) systemd-notify MAINPID=1073741824 -test "$(systemctl show -P MainPID testsuite-07.service)" -eq "$MAINPID" +test "$(systemctl show -P MainPID TEST-07-PID1.service)" -eq "$MAINPID" # Change it again to the external PID, without privileges this time. This should be ignored, because the PID is from outside of our cgroup and we lack privileges. systemd-notify --uid=1000 MAINPID="$EXTERNALPID" -test "$(systemctl show -P MainPID testsuite-07.service)" -eq "$MAINPID" +test "$(systemctl show -P MainPID TEST-07-PID1.service)" -eq "$MAINPID" # Change it again to the internal PID, without privileges this time. This should work, as the process is on our cgroup, and that's enough even if we lack privileges. systemd-notify --uid=1000 MAINPID="$INTERNALPID" -test "$(systemctl show -P MainPID testsuite-07.service)" -eq "$INTERNALPID" +test "$(systemctl show -P MainPID TEST-07-PID1.service)" -eq "$INTERNALPID" # Update it back to our own PID, this should also work systemd-notify --uid=1000 MAINPID="$MAINPID" -test "$(systemctl show -P MainPID testsuite-07.service)" -eq "$MAINPID" +test "$(systemctl show -P MainPID TEST-07-PID1.service)" -eq "$MAINPID" cat >/tmp/test-mainpid.sh <<\EOF #!/usr/bin/env bash diff --git a/test/units/testsuite-07.mount-invalid-chars.sh b/test/units/TEST-07-PID1.mount-invalid-chars.sh index a879334..a879334 100755 --- a/test/units/testsuite-07.mount-invalid-chars.sh +++ b/test/units/TEST-07-PID1.mount-invalid-chars.sh diff --git a/test/units/testsuite-07.poll-limit.sh b/test/units/TEST-07-PID1.poll-limit.sh index 480d7ee..ca988b2 100755 --- a/test/units/testsuite-07.poll-limit.sh +++ b/test/units/TEST-07-PID1.poll-limit.sh @@ -5,12 +5,12 @@ set -o pipefail systemd-analyze log-level debug -cat > /run/systemd/system/floodme@.service <<EOF +cat >/run/systemd/system/floodme@.service <<EOF [Service] -ExecStart=/bin/true +ExecStart=true EOF -cat > /run/systemd/system/floodme.socket <<EOF +cat >/run/systemd/system/floodme.socket <<EOF [Socket] ListenStream=/tmp/floodme PollLimitIntervalSec=10s @@ -24,7 +24,7 @@ systemctl start floodme.socket START=$(date +%s%N) # Trigger this 100 times in a flood -for (( i=0 ; i < 100; i++ )) ; do +for _ in {1..100}; do logger -u /tmp/floodme foo & done diff --git a/test/units/TEST-07-PID1.pr-31351.sh b/test/units/TEST-07-PID1.pr-31351.sh new file mode 100755 index 0000000..f6911f2 --- /dev/null +++ b/test/units/TEST-07-PID1.pr-31351.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +cat >/run/systemd/system/nonexistent-execstart-exit-status.service <<EOF +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=-/foo/bar/not-exist +EOF + +systemctl start nonexistent-execstart-exit-status.service +systemctl is-active nonexistent-execstart-exit-status.service +assert_eq "$(systemctl show nonexistent-execstart-exit-status.service -P Result)" "success" +(( $(systemctl show nonexistent-execstart-exit-status.service -P ExecMainStatus) > 0 )) + +systemctl stop nonexistent-execstart-exit-status.service +rm /run/systemd/system/nonexistent-execstart-exit-status.service diff --git a/test/units/testsuite-07.private-network.sh b/test/units/TEST-07-PID1.private-network.sh index 37658f7..37658f7 100755 --- a/test/units/testsuite-07.private-network.sh +++ b/test/units/TEST-07-PID1.private-network.sh diff --git a/test/units/testsuite-07.sh b/test/units/TEST-07-PID1.sh index 2ee1457..873d638 100755 --- a/test/units/testsuite-07.sh +++ b/test/units/TEST-07-PID1.sh @@ -13,3 +13,4 @@ mountpoint /issue2730 run_subtests touch /testok +systemctl --no-block exit 123 diff --git a/test/units/TEST-07-PID1.socket-pass-fds.sh b/test/units/TEST-07-PID1.socket-pass-fds.sh new file mode 100755 index 0000000..a61b1c0 --- /dev/null +++ b/test/units/TEST-07-PID1.socket-pass-fds.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +# Test PassFileDescriptorsToExec= option in socket units + +for u in pass-fds-to-exec-{no,yes}.socket; do + systemctl start "$u" + systemctl stop "$u" +done diff --git a/test/units/TEST-07-PID1.type-exec-parallel.sh b/test/units/TEST-07-PID1.type-exec-parallel.sh new file mode 100755 index 0000000..30f80c5 --- /dev/null +++ b/test/units/TEST-07-PID1.type-exec-parallel.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +# Make sure that we never mistake a process starting but failing quickly for a process failing to start, with Type=exec. +# See https://github.com/systemd/systemd/pull/30799 + +seq 25 | xargs -n 1 -P 0 systemd-run -p Type=exec /bin/false diff --git a/test/units/testsuite-08.sh b/test/units/TEST-08-INITRD.sh index 5c6b4ce..4804527 100755 --- a/test/units/testsuite-08.sh +++ b/test/units/TEST-08-INITRD.sh @@ -13,7 +13,7 @@ fi if [[ "$(systemctl show -P InitRDTimestampMonotonic)" -eq 0 ]]; then echo "systemd didn't run in the initrd, skipping the test" touch /skipped - exit 0 + exit 77 fi # We should've created a mount under /run in initrd (see the other half of the test) @@ -22,9 +22,9 @@ test -d /run/initrd-mount-target mountpoint /run/initrd-mount-target [[ -e /run/initrd-mount-target/hello-world ]] -# Copy the prepared shutdown initrd to its intended location. Check the respective +# Copy the prepared exitrd to its intended location. Check the respective # test.sh file for details mkdir -p /run/initramfs -cp -r /shutdown-initrd/* /run/initramfs/ +cp -r /exitrd/* /run/initramfs/ touch /testok diff --git a/test/units/testsuite-09.journal.sh b/test/units/TEST-09-REBOOT.journal.sh index 2ef192c..726e800 100755 --- a/test/units/testsuite-09.journal.sh +++ b/test/units/TEST-09-REBOOT.journal.sh @@ -22,6 +22,22 @@ get_last_timestamp() { journalctl -b "${1:?}" -o json -n 1 | jq -r '.__REALTIME_TIMESTAMP' } +# There may be huge amount of pending messages in sockets. Processing them may cause journal rotation. +# If the journal is rotated in the loop below, some journal file may not be loaded and an unexpected +# result may be provided. To mitigate such, flush (if not yet) and sync before reading journals. +# Workaround for #32890. +journalctl --flush +journalctl --sync +# Sometimes, loading partially written .journal file, and journalctl handled that as 'truncated': +# === +# May 21 02:25:55 TEST-09-REBOOT.sh[433]: + journalctl --list-boots -o json +# May 21 02:25:55 journalctl[433]: Journal file /var/log/journal/173da2fad3064e3e9211a7ed7d59360b/system.journal is truncated, ignoring file. +# === +# If that happens, the entries stored in the journal file are ignored, and the results of --list-boots +# and subsequent call of journalctl may become inconsistent. To prevent such issue, let's also rotate +# the journal. Then, all journal entries we are interested in are stored in the archived journal files. +journalctl --rotate + # Issue: #29275, second part # Now let's check if the boot entries are in the correct/expected order index=0 @@ -70,3 +86,47 @@ journalctl --list-boots -o json | jq -r '.[] | [.index, .boot_id, .first_entry, assert_eq "$entry_ts" "$last_ts" fi done + +verify_seqnum() { + if [[ "$REBOOT_COUNT" -ne "$NUM_REBOOT" ]]; then + return 0 + fi + + journalctl --flush + journalctl --sync + + ls -lR /var/log/journal/ + ls -lR /run/log/journal/ + + journalctl --system --header + + (! journalctl --system -q -o short-monotonic -u systemd-journald.service --grep 'Journal file uses a different sequence number ID, rotating') + + set +x + previous_seqnum=0 + previous_seqnum_id= + previous_boot_id= + journalctl --system -q -o json | jq -r '[.__SEQNUM, .__SEQNUM_ID, ._BOOT_ID] | @tsv' | + while read -r seqnum seqnum_id boot_id; do + + if [[ -n "$previous_seqnum_id" ]]; then + if ! test "$seqnum" -gt "$previous_seqnum"; then + echo "seqnum=$seqnum is not greater than previous_seqnum=$previous_seqnum" + echo "seqnum_id=$seqnum_id, previous_seqnum_id=$previous_seqnum_id" + echo "boot_id=$boot_id, previous_boot_id=$previous_boot_id" + return 1 + fi + + assert_eq "$seqnum_id" "$previous_seqnum_id" + fi + + previous_seqnum="$seqnum" + previous_seqnum_id="$seqnum_id" + previous_boot_id="$boot_id" + done + set -x + + return 0 +} + +verify_seqnum diff --git a/test/units/testsuite-09.sh b/test/units/TEST-09-REBOOT.sh index cd95660..85630b6 100755 --- a/test/units/testsuite-09.sh +++ b/test/units/TEST-09-REBOOT.sh @@ -3,7 +3,7 @@ set -eux set -o pipefail -NUM_REBOOT=4 +export NUM_REBOOT=4 # shellcheck source=test/units/test-control.sh . "$(dirname "$0")"/test-control.sh diff --git a/test/units/TEST-13-NSPAWN.importctl.sh b/test/units/TEST-13-NSPAWN.importctl.sh new file mode 100755 index 0000000..a13e3fd --- /dev/null +++ b/test/units/TEST-13-NSPAWN.importctl.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2016 +set -eux +set -o pipefail + +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +export PAGER= + +at_exit() { + set +e + umount -l -R /var/lib/confexts + rm -f /var/tmp/importtest /var/tmp/importtest2 /var/tmp/importtest.tar.gz /var/tmp/importtest2.tar.gz +} + +trap at_exit EXIT + +systemctl service-log-level systemd-importd debug + +# Mount tmpfs over /var/lib/confexts to not pollute the image +mkdir -p /var/lib/confexts +mount -t tmpfs tmpfs /var/lib/confexts -o mode=755 + +importctl +importctl --no-pager --help +importctl --version +importctl list-transfers +importctl list-transfers --no-legend --no-ask-password +importctl list-transfers -j +importctl list-images +importctl list-images --no-legend --no-ask-password +importctl list-images -j + +(! importctl cancel-transfer 4711) + +dd if=/dev/urandom of=/var/tmp/importtest bs=4096 count=10 + +importctl import-raw --class=confext /var/tmp/importtest +cmp /var/tmp/importtest /var/lib/confexts/importtest.raw +importctl export-raw --class=confext importtest /var/tmp/importtest2 +cmp /var/tmp/importtest /var/tmp/importtest2 + +(! importctl pull-raw --class=confext file:///var/tmp/importtest) +importctl pull-raw --verify=no --class=confext file:///var/tmp/importtest importtest3 +cmp /var/tmp/importtest /var/lib/confexts/importtest3.raw + +tar czf /var/tmp/importtest.tar.gz -C /var/tmp importtest + +importctl import-tar --class=confext /var/tmp/importtest.tar.gz importtest4 +cmp /var/tmp/importtest /var/lib/confexts/importtest4/importtest + +importctl export-tar --class=confext importtest4 /var/tmp/importtest2.tar.gz +importctl import-tar --class=confext /var/tmp/importtest2.tar.gz importtest5 +cmp /var/tmp/importtest /var/lib/confexts/importtest5/importtest + +importctl import-fs --class=confext /var/lib/confexts/importtest5 importtest6 +cmp /var/tmp/importtest /var/lib/confexts/importtest6/importtest + +(! importctl pull-tar --class=confext file:///var/tmp/importtest.tar.gz importtest7) +importctl pull-tar --class=confext --verify=no file:///var/tmp/importtest.tar.gz importtest7 +cmp /var/tmp/importtest /var/lib/confexts/importtest7/importtest + +importctl list-images +importctl list-images -j diff --git a/test/units/testsuite-13.machinectl.sh b/test/units/TEST-13-NSPAWN.machinectl.sh index b5f90f6..462cc6a 100755 --- a/test/units/testsuite-13.machinectl.sh +++ b/test/units/TEST-13-NSPAWN.machinectl.sh @@ -20,9 +20,12 @@ at_exit() { trap at_exit EXIT -# Mount tmpfs over /var/lib/machines to not pollute the image +systemctl service-log-level systemd-machined debug +systemctl service-log-level systemd-importd debug + +# Mount temporary directory over /var/lib/machines to not pollute the image mkdir -p /var/lib/machines -mount -t tmpfs tmpfs /var/lib/machines +mount --bind "$(mktemp --tmpdir=/var/tmp -d)" /var/lib/machines # Create a couple of containers we can refer to in tests for i in {0..4}; do @@ -32,7 +35,7 @@ done # Create one "long running" container with some basic signal handling create_dummy_container /var/lib/machines/long-running cat >/var/lib/machines/long-running/sbin/init <<\EOF -#!/usr/bin/bash -x +#!/usr/bin/bash PID=0 @@ -129,6 +132,9 @@ machinectl show-image clone1 machinectl rename clone1 clone2 (! machinectl show-image clone1) machinectl show-image clone2 +# `machinectl read-only` uses chattr (ioctl(FS_IOC_SETFLAGS)) when the container is backed by a directory, +# and this operation might not be implemented on certain filesystems (i.e. tmpfs on older kernels), so check +# if we have chattr support before running following tests if lsattr -d /var/lib/machines >/dev/null; then [[ "$(machinectl show-image --property=ReadOnly --value clone2)" == no ]] machinectl read-only clone2 yes @@ -151,37 +157,37 @@ test ! -d /var/lib/machines/.hidden1 # Prepare a simple raw container mkdir -p /tmp/mnt -dd if=/dev/zero of=/tmp/container.raw bs=1M count=64 -mkfs.ext4 /tmp/container.raw -mount -o loop /tmp/container.raw /tmp/mnt +dd if=/dev/zero of=/var/tmp/container.raw bs=1M count=256 +mkfs.ext4 /var/tmp/container.raw +mount -o loop /var/tmp/container.raw /tmp/mnt cp -r /var/lib/machines/container1/* /tmp/mnt umount /tmp/mnt # Try to import it, run it, export it, and re-import it -machinectl import-raw /tmp/container.raw container-raw +machinectl import-raw /var/tmp/container.raw container-raw [[ "$(machinectl show-image --property=Type --value container-raw)" == "raw" ]] machinectl start container-raw -machinectl export-raw container-raw /tmp/container-export.raw -machinectl import-raw /tmp/container-export.raw container-raw-reimport +machinectl export-raw container-raw /var/tmp/container-export.raw +machinectl import-raw /var/tmp/container-export.raw container-raw-reimport [[ "$(machinectl show-image --property=Type --value container-raw-reimport)" == "raw" ]] -rm -f /tmp/container{,-export}.raw +rm -f /var/tmp/container{,-export}.raw # Prepare a simple tar.gz container -tar -pczf /tmp/container.tar.gz -C /var/lib/machines/container1 . +tar -pczf /var/tmp/container.tar.gz -C /var/lib/machines/container1 . # Try to import it, run it, export it, and re-import it -machinectl import-tar /tmp/container.tar.gz container-tar -[[ "$(machinectl show-image --property=Type --value container-tar)" == "directory" ]] +machinectl import-tar /var/tmp/container.tar.gz container-tar +[[ "$(machinectl show-image --property=Type --value container-tar)" =~ directory|subvolume ]] machinectl start container-tar -machinectl export-tar container-tar /tmp/container-export.tar.gz -machinectl import-tar /tmp/container-export.tar.gz container-tar-reimport -[[ "$(machinectl show-image --property=Type --value container-tar-reimport)" == "directory" ]] -rm -f /tmp/container{,-export}.tar.gz +machinectl export-tar container-tar /var/tmp/container-export.tar.gz +machinectl import-tar /var/tmp/container-export.tar.gz container-tar-reimport +[[ "$(machinectl show-image --property=Type --value container-tar-reimport)" =~ directory|subvolume ]] +rm -f /var/tmp/container{,-export}.tar.gz # Try to import a container directory & run it -cp -r /var/lib/machines/container1 /tmp/container.dir -machinectl import-fs /tmp/container.dir container-dir -[[ "$(machinectl show-image --property=Type --value container-dir)" == "directory" ]] +cp -r /var/lib/machines/container1 /var/tmp/container.dir +machinectl import-fs /var/tmp/container.dir container-dir +[[ "$(machinectl show-image --property=Type --value container-dir)" =~ directory|subvolume ]] machinectl start container-dir -rm -fr /tmp/container.dir +rm -fr /var/tmp/container.dir timeout 10 bash -c "until machinectl clean --all; do sleep .5; done" diff --git a/test/units/testsuite-13.nspawn-oci.sh b/test/units/TEST-13-NSPAWN.nspawn-oci.sh index 8fa0bc4..65dcc96 100755 --- a/test/units/testsuite-13.nspawn-oci.sh +++ b/test/units/TEST-13-NSPAWN.nspawn-oci.sh @@ -23,9 +23,9 @@ at_exit() { trap at_exit EXIT -# Mount tmpfs over /var/lib/machines to not pollute the image +# Mount temporary directory over /var/lib/machines to not pollute the image mkdir -p /var/lib/machines -mount -t tmpfs tmpfs /var/lib/machines +mount --bind "$(mktemp --tmpdir=/var/tmp -d)" /var/lib/machines # Setup a couple of dirs/devices for the OCI containers DEV="$(mktemp -u /dev/oci-dev-XXX)" @@ -34,7 +34,7 @@ NETNS="$(mktemp /var/tmp/netns.XXX)" mount --bind /proc/self/ns/net "$NETNS" TMPDIR="$(mktemp -d)" touch "$TMPDIR/hello" -OCI="$(mktemp -d /var/lib/machines/testsuite-13.oci-bundle.XXX)" +OCI="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.oci-bundle.XXX)" create_dummy_container "$OCI/rootfs" mkdir -p "$OCI/rootfs/opt/var" mkdir -p "$OCI/rootfs/opt/readonly" diff --git a/test/units/testsuite-13.nspawn.sh b/test/units/TEST-13-NSPAWN.nspawn.sh index 01f6eb6..7901e98 100755 --- a/test/units/testsuite-13.nspawn.sh +++ b/test/units/TEST-13-NSPAWN.nspawn.sh @@ -71,9 +71,9 @@ if unshare -U bash -c :; then IS_USERNS_SUPPORTED=yes fi -# Mount tmpfs over /var/lib/machines to not pollute the image +# Mount temporary directory over /var/lib/machines to not pollute the image mkdir -p /var/lib/machines -mount -t tmpfs tmpfs /var/lib/machines +mount --bind "$(mktemp --tmpdir=/var/tmp -d)" /var/lib/machines testcase_sanity() { local template root image uuid tmpdir @@ -82,8 +82,8 @@ testcase_sanity() { template="$(mktemp -d /tmp/nspawn-template.XXX)" create_dummy_container "$template" # Create a simple image from the just created container template - image="$(mktemp /var/lib/machines/testsuite-13.image-XXX.img)" - dd if=/dev/zero of="$image" bs=1M count=64 + image="$(mktemp /var/lib/machines/TEST-13-NSPAWN.image-XXX.img)" + dd if=/dev/zero of="$image" bs=1M count=256 mkfs.ext4 "$image" mkdir -p /mnt mount -o loop "$image" /mnt @@ -94,7 +94,7 @@ testcase_sanity() { systemd-nspawn --version # --template= - root="$(mktemp -u -d /var/lib/machines/testsuite-13.sanity.XXX)" + root="$(mktemp -u -d /var/lib/machines/TEST-13-NSPAWN.sanity.XXX)" coverage_create_nspawn_dropin "$root" (! systemd-nspawn --directory="$root" bash -xec 'echo hello') # Initialize $root from $template (the $root directory must not exist, hence @@ -271,6 +271,13 @@ EOF --load-credential=cred.path:/tmp/cred.path \ --set-credential="cred.set:hello world" \ bash -xec '[[ "$(</run/host/credentials/cred.path)" == "foo bar" ]]; [[ "$(</run/host/credentials/cred.set)" == "hello world" ]]' + # Combine with --user to ensure creds are still readable + systemd-nspawn --directory="$root" \ + --user=testuser \ + --no-new-privileges=yes \ + --load-credential=cred.path:/tmp/cred.path \ + --set-credential="cred.set:hello world" \ + bash -xec '[[ "$(</run/host/credentials/cred.path)" == "foo bar" ]]; [[ "$(</run/host/credentials/cred.set)" == "hello world" ]]' rm -f /tmp/cred.path # Assorted tests @@ -324,7 +331,7 @@ EOF } nspawn_settings_cleanup() { - for dev in sd-host-only sd-shared{1,2} sd-macvlan{1,2} sd-ipvlan{1,2}; do + for dev in sd-host-only sd-shared{1,2,3} sd-macvlan{1,2} sd-ipvlan{1,2}; do ip link del "$dev" || : done @@ -332,19 +339,25 @@ nspawn_settings_cleanup() { } testcase_nspawn_settings() { - local root container dev private_users + local root container dev private_users wlan_names mkdir -p /run/systemd/nspawn - root="$(mktemp -d /var/lib/machines/testsuite-13.nspawn-settings.XXX)" + root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.nspawn-settings.XXX)" container="$(basename "$root")" create_dummy_container "$root" rm -f "/etc/systemd/nspawn/$container.nspawn" mkdir -p "$root/tmp" "$root"/opt/{tmp,inaccessible,also-inaccessible} - for dev in sd-host-only sd-shared{1,2} sd-macvlan{1,2} sd-macvlanloong sd-ipvlan{1,2} sd-ipvlanlooong; do + # add virtual wlan interfaces + if modprobe mac80211_hwsim radios=2; then + wlan_names="wlan0 wlan1:wl-renamed1" + fi + + for dev in sd-host-only sd-shared{1,2,3} sd-macvlan{1,2} sd-macvlanloong sd-ipvlan{1,2} sd-ipvlanlooong; do ip link add "$dev" type dummy done udevadm settle + ip link property add dev sd-shared3 altname sd-altname3 altname sd-altname-tooooooooooooo-long ip link trap nspawn_settings_cleanup RETURN @@ -394,7 +407,7 @@ Private=yes VirtualEthernet=yes VirtualEthernetExtra=my-fancy-veth1 VirtualEthernetExtra=fancy-veth2:my-fancy-veth2 -Interface=sd-shared1 sd-shared2:sd-shared2 +Interface=sd-shared1 sd-shared2:sd-renamed2 sd-shared3:sd-altname3 ${wlan_names:-} MACVLAN=sd-macvlan1 sd-macvlan2:my-macvlan2 sd-macvlanloong IPVLAN=sd-ipvlan1 sd-ipvlan2:my-ipvlan2 sd-ipvlanlooong Zone=sd-zone0 @@ -440,12 +453,22 @@ ip link | grep host0@ ip link | grep my-fancy-veth1@ ip link | grep my-fancy-veth2@ ip link | grep sd-shared1 -ip link | grep sd-shared2 +ip link | grep sd-renamed2 +ip link | grep sd-shared3 +ip link | grep sd-altname3 +ip link | grep sd-altname-tooooooooooooo-long ip link | grep mv-sd-macvlan1@ ip link | grep my-macvlan2@ ip link | grep iv-sd-ipvlan1@ ip link | grep my-ipvlan2@ EOF + if [[ -n "${wlan_names:-}" ]]; then + cat >>"$root/entrypoint.sh" <<\EOF +ip link | grep wlan0 +ip link | grep wl-renamed1 +EOF + fi + timeout 30 systemd-nspawn --directory="$root" # And now for stuff that needs to run separately @@ -482,7 +505,7 @@ bind_user_cleanup() { testcase_bind_user() { local root - root="$(mktemp -d /var/lib/machines/testsuite-13.bind-user.XXX)" + root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.bind-user.XXX)" create_dummy_container "$root" useradd --create-home --user-group nspawn-bind-user-1 useradd --create-home --user-group nspawn-bind-user-2 @@ -531,7 +554,7 @@ testcase_bind_tmp_path() { # https://github.com/systemd/systemd/issues/4789 local root - root="$(mktemp -d /var/lib/machines/testsuite-13.bind-tmp-path.XXX)" + root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.bind-tmp-path.XXX)" create_dummy_container "$root" : >/tmp/bind systemd-nspawn --register=no \ @@ -546,7 +569,7 @@ testcase_norbind() { # https://github.com/systemd/systemd/issues/13170 local root - root="$(mktemp -d /var/lib/machines/testsuite-13.norbind-path.XXX)" + root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.norbind-path.XXX)" mkdir -p /tmp/binddir/subdir echo -n "outer" >/tmp/binddir/subdir/file mount -t tmpfs tmpfs /tmp/binddir/subdir @@ -573,7 +596,7 @@ testcase_rootidmap() { local root cmd permissions local owner=1000 - root="$(mktemp -d /var/lib/machines/testsuite-13.rootidmap-path.XXX)" + root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.rootidmap-path.XXX)" # Create ext4 image, as ext4 supports idmapped-mounts. mkdir -p /tmp/rootidmap/bind dd if=/dev/zero of=/tmp/rootidmap/ext4.img bs=4k count=2048 @@ -606,12 +629,82 @@ testcase_rootidmap() { fi } +owneridmap_cleanup() { + local dir="${1:?}" + + mountpoint -q "$dir/bind" && umount "$dir/bind" + rm -fr "$dir" +} + +testcase_owneridmap() { + local root cmd permissions + local owner=1000 + + root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.owneridmap-path.XXX)" + # Create ext4 image, as ext4 supports idmapped-mounts. + mkdir -p /tmp/owneridmap/bind + dd if=/dev/zero of=/tmp/owneridmap/ext4.img bs=4k count=2048 + mkfs.ext4 /tmp/owneridmap/ext4.img + mount /tmp/owneridmap/ext4.img /tmp/owneridmap/bind + trap "owneridmap_cleanup /tmp/owneridmap/" RETURN + + touch /tmp/owneridmap/bind/file + chown -R "$owner:$owner" /tmp/owneridmap/bind + + # Allow users to read and execute / in order to execute binaries + chmod o+rx "$root" + + create_dummy_container "$root" + + # --user= + # "Fake" getent passwd's bare minimum, so we don't have to pull it in + # with all the DSO shenanigans + cat >"$root/bin/getent" <<\EOF +#!/bin/bash + +if [[ $# -eq 0 ]]; then + : +elif [[ $1 == passwd ]]; then + echo "testuser:x:1010:1010:testuser:/:/bin/sh" +elif [[ $1 == initgroups ]]; then + echo "testuser" +fi +EOF + chmod +x "$root/bin/getent" + + mkdir -p "$root/home/testuser" + chown 1010:1010 "$root/home/testuser" + + cmd='PERMISSIONS=$(stat -c "%u:%g" /home/testuser/file); if [[ $PERMISSIONS != "1010:1010" ]]; then echo "*** wrong permissions: $PERMISSIONS"; return 1; fi; touch /home/testuser/other_file' + if ! SYSTEMD_LOG_TARGET=console \ + systemd-nspawn --register=no \ + --directory="$root" \ + -U \ + --user=testuser \ + --bind=/tmp/owneridmap/bind:/home/testuser:owneridmap \ + ${COVERAGE_BUILD_DIR:+--bind="$COVERAGE_BUILD_DIR"} \ + /usr/bin/bash -c "$cmd" |& tee nspawn.out; then + if grep -q "Failed to map ids for bind mount.*: Function not implemented" nspawn.out; then + echo "idmapped mounts are not supported, skipping the test..." + return 0 + fi + + return 1 + fi + + permissions=$(stat -c "%u:%g" /tmp/owneridmap/bind/other_file) + if [[ $permissions != "$owner:$owner" ]]; then + echo "*** wrong permissions: $permissions" + [[ "$IS_USERNS_SUPPORTED" == "yes" ]] && return 1 + fi +} + testcase_notification_socket() { # https://github.com/systemd/systemd/issues/4944 local root local cmd='echo a | nc -U -u -w 1 /run/host/notify' - root="$(mktemp -d /var/lib/machines/testsuite-13.check_notification_socket.XXX)" + root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.check_notification_socket.XXX)" create_dummy_container "$root" systemd-nspawn --register=no --directory="$root" bash -x -c "$cmd" @@ -623,7 +716,7 @@ testcase_notification_socket() { testcase_os_release() { local root entrypoint os_release_source - root="$(mktemp -d /var/lib/machines/testsuite-13.os-release.XXX)" + root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.os-release.XXX)" create_dummy_container "$root" entrypoint="$root/entrypoint.sh" cat >"$entrypoint" <<\EOF @@ -665,7 +758,7 @@ testcase_machinectl_bind() { local service_path service_name root container_name ec local cmd='for i in $(seq 1 20); do if test -f /tmp/marker; then exit 0; fi; sleep .5; done; exit 1;' - root="$(mktemp -d /var/lib/machines/testsuite-13.machinectl-bind.XXX)" + root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.machinectl-bind.XXX)" create_dummy_container "$root" container_name="$(basename "$root")" @@ -700,7 +793,7 @@ testcase_selinux() { local root - root="$(mktemp -d /var/lib/machines/testsuite-13.selinux.XXX)" + root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.selinux.XXX)" create_dummy_container "$root" chcon -R -t container_t "$root" @@ -717,7 +810,7 @@ testcase_ephemeral_config() { # https://github.com/systemd/systemd/issues/13297 local root container_name - root="$(mktemp -d /var/lib/machines/testsuite-13.ephemeral-config.XXX)" + root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.ephemeral-config.XXX)" create_dummy_container "$root" container_name="$(basename "$root")" @@ -760,7 +853,7 @@ matrix_run_one() { return 0 fi - root="$(mktemp -d "/var/lib/machines/testsuite-13.unified-$1-cgns-$2-api-vfs-writable-$3.XXX")" + root="$(mktemp -d "/var/lib/machines/TEST-13-NSPAWN.unified-$1-cgns-$2-api-vfs-writable-$3.XXX")" create_dummy_container "$root" SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \ @@ -848,8 +941,8 @@ testcase_check_os_release() { # https://github.com/systemd/systemd/issues/29185 local base common_opts root - base="$(mktemp -d /var/lib/machines/testsuite-13.check_os_release_base.XXX)" - root="$(mktemp -d /var/lib/machines/testsuite-13.check_os_release.XXX)" + base="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.check_os_release_base.XXX)" + root="$(mktemp -d /var/lib/machines/TEST-13-NSPAWN.check_os_release.XXX)" create_dummy_container "$base" cp -d "$base"/{bin,sbin,lib,lib64} "$root/" common_opts=( diff --git a/test/units/testsuite-13.nss-mymachines.sh b/test/units/TEST-13-NSPAWN.nss-mymachines.sh index b566c73..817431b 100755 --- a/test/units/testsuite-13.nss-mymachines.sh +++ b/test/units/TEST-13-NSPAWN.nss-mymachines.sh @@ -17,8 +17,9 @@ at_exit() { trap at_exit EXIT +# Mount temporary directory over /var/lib/machines to not pollute the image mkdir -p /var/lib/machines -mount -t tmpfs tmpfs /var/lib/machines +mount --bind "$(mktemp --tmpdir=/var/tmp -d)" /var/lib/machines # Create a bunch of containers that: # 1) Have no IP addresses assigned @@ -56,7 +57,7 @@ ip addr add 10.2.0.2/24 dev ve-manyips for i in {100..120}; do ip addr add 10.2.0.$i/24 dev ve-manyips done -ip addr add fd00:dead:beef:cafe::2/64 dev ve-manyips +ip addr add fd00:dead:beef:cafe::2/64 dev ve-manyips nodad ip addr show dev ve-manyips touch /initialized sleep infinity @@ -90,7 +91,7 @@ done # getaddrinfo() return EAI_NONAME without ever asking nss-mymachines. ip addr add 10.1.0.1/24 dev ve-singleip ip addr add 10.2.0.1/24 dev ve-manyips -ip addr add fd00:dead:beef:cafe::1/64 dev ve-manyips +ip addr add fd00:dead:beef:cafe::1/64 dev ve-manyips nodad getent hosts -s mymachines getent ahosts -s mymachines diff --git a/test/units/TEST-13-NSPAWN.sh b/test/units/TEST-13-NSPAWN.sh new file mode 100755 index 0000000..dd7f274 --- /dev/null +++ b/test/units/TEST-13-NSPAWN.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +FSTYPE="$(stat --file-system --format "%T" /)" + +if [[ "$FSTYPE" == "fuseblk" ]]; then + echo "Root filesystem is virtiofs, skipping" + exit 77 +fi + +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh + +run_subtests + +touch /testok diff --git a/test/units/testsuite-15.sh b/test/units/TEST-15-DROPIN.sh index e790b37..5e4df52 100755 --- a/test/units/testsuite-15.sh +++ b/test/units/TEST-15-DROPIN.sh @@ -5,6 +5,8 @@ set -o pipefail # shellcheck source=test/units/test-control.sh . "$(dirname "$0")"/test-control.sh +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh clear_unit() { local unit_name="${1:?}" @@ -256,6 +258,8 @@ EOF 'MemoryMax' t 1000000002 \ 0 + timeout 1m bash -c 'until systemctl is-active a-b-c.slice; do sleep 1s; done' + # The override takes precedence for MemoryMax check_ok a-b-c.slice MemoryMax "1000000000" # The transient setting replaces the default @@ -273,6 +277,8 @@ EOF StopUnit 'ss' \ 'a-b-c.slice' 'replace' + timeout 1m bash -c 'while systemctl is-active a-b-c.slice; do sleep 1s; done' + rm -f "/run/systemd/system/$dropin/override.conf" done @@ -692,15 +698,15 @@ testcase_symlink_dropin_directory() { echo "Testing symlink drop-in directory..." create_services test15-a rmdir /{etc,run,usr/lib}/systemd/system/test15-a.service.d - mkdir -p /tmp/testsuite-15-test15-a-dropin-directory - ln -s /tmp/testsuite-15-test15-a-dropin-directory /etc/systemd/system/test15-a.service.d - cat >/tmp/testsuite-15-test15-a-dropin-directory/override.conf <<EOF + mkdir -p /tmp/TEST-15-DROPIN-test15-a-dropin-directory + ln -s /tmp/TEST-15-DROPIN-test15-a-dropin-directory /etc/systemd/system/test15-a.service.d + cat >/tmp/TEST-15-DROPIN-test15-a-dropin-directory/override.conf <<EOF [Unit] Description=hogehoge EOF - ln -s /tmp/testsuite-15-test15-a-dropin-directory-nonexistent /run/systemd/system/test15-a.service.d - touch /tmp/testsuite-15-test15-a-dropin-directory-regular - ln -s /tmp/testsuite-15-test15-a-dropin-directory-regular /usr/lib/systemd/system/test15-a.service.d + ln -s /tmp/TEST-15-DROPIN-test15-a-dropin-directory-nonexistent /run/systemd/system/test15-a.service.d + touch /tmp/TEST-15-DROPIN-test15-a-dropin-directory-regular + ln -s /tmp/TEST-15-DROPIN-test15-a-dropin-directory-regular /usr/lib/systemd/system/test15-a.service.d check_ok test15-a Description hogehoge clear_units test15-a.service diff --git a/test/units/testsuite-16.sh b/test/units/TEST-16-EXTEND-TIMEOUT.sh index c60995a..c60995a 100755 --- a/test/units/testsuite-16.sh +++ b/test/units/TEST-16-EXTEND-TIMEOUT.sh diff --git a/test/units/testsuite-17.00.sh b/test/units/TEST-17-UDEV.00.sh index d2aec60..d2aec60 100755 --- a/test/units/testsuite-17.00.sh +++ b/test/units/TEST-17-UDEV.00.sh diff --git a/test/units/testsuite-17.01.sh b/test/units/TEST-17-UDEV.01.sh index 44f36f5..44f36f5 100755 --- a/test/units/testsuite-17.01.sh +++ b/test/units/TEST-17-UDEV.01.sh diff --git a/test/units/testsuite-17.02.sh b/test/units/TEST-17-UDEV.02.sh index b232fca..96430e6 100755 --- a/test/units/testsuite-17.02.sh +++ b/test/units/TEST-17-UDEV.02.sh @@ -145,6 +145,7 @@ EOF # make sure that 'udevadm monitor' actually monitor uevents sleep 1 + journalctl --sync since="$(date '+%H:%M:%S')" # add another interface which will conflict with an existing interface @@ -172,7 +173,10 @@ EOF done test -n "$found" - timeout 30 bash -c "until journalctl _PID=1 _COMM=systemd --since $since | grep -q 'foobar: systemd-udevd failed to process the device, ignoring: File exists'; do sleep 1; done" + journalctl --sync + set +o pipefail + timeout -v 30 journalctl _PID=1 _COMM=systemd --since "$since" -n all --follow | grep -m 1 -q -F 'foobar: systemd-udevd failed to process the device, ignoring: File exists' + set -o pipefail # check if the invalid SYSTEMD_ALIAS property for the interface foobar is ignored by PID1 assert_eq "$(systemctl show --property=SysFSPath --value /sys/subsystem/net/devices/hoge)" "/sys/devices/virtual/net/hoge" } diff --git a/test/units/TEST-17-UDEV.03.sh b/test/units/TEST-17-UDEV.03.sh new file mode 100755 index 0000000..d6b3162 --- /dev/null +++ b/test/units/TEST-17-UDEV.03.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux + +TMPDIR= +TEST_RULE="/run/udev/rules.d/49-test.rules" +TEST_CONF="/run/udev/udev.conf.d/test-17.conf" +KILL_PID= + +setup() { + mkdir -p "${TEST_RULE%/*}" + mkdir -p /run/udev/udev.conf.d + + cat >"${TEST_RULE}" <<EOF +ACTION!="add", GOTO="test_end" +SUBSYSTEM!="mem", GOTO="test_end" +KERNEL!="null", GOTO="test_end" + +OPTIONS="log_level=debug" +PROGRAM=="/bin/touch /tmp/test-udev-marker" +PROGRAM!="/bin/sleep 60", ENV{PROGRAM_RESULT}="KILLED" + +LABEL="test_end" +EOF + cat >"$TEST_CONF" <<EOF +event_timeout=10 +timeout_signal=SIGABRT +EOF + + systemctl restart systemd-udevd.service +} + +# shellcheck disable=SC2317 +teardown() { + set +e + + if [[ -n "$KILL_PID" ]]; then + kill "$KILL_PID" + fi + + rm -rf "$TMPDIR" + rm -f "$TEST_RULE" "$TEST_CONF" + systemctl restart systemd-udevd.service +} + +run_test_timeout() { + TMPDIR=$(mktemp -d -p /tmp udev-tests.XXXXXX) + udevadm monitor --udev --property --subsystem-match=mem >"$TMPDIR"/monitor.txt & + KILL_PID="$!" + + SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --action add /dev/null + + for _ in {1..40}; do + if grep -q 'PROGRAM_RESULT=KILLED' "$TMPDIR"/monitor.txt; then + sleep .5 + kill "$KILL_PID" + KILL_PID= + + cat "$TMPDIR"/monitor.txt + (! grep -q 'UDEV_WORKER_FAILED=1' "$TMPDIR"/monitor.txt) + (! grep -q 'UDEV_WORKER_SIGNAL=6' "$TMPDIR"/monitor.txt) + (! grep -q 'UDEV_WORKER_SIGNAL_NAME=ABRT' "$TMPDIR"/monitor.txt) + grep -q 'PROGRAM_RESULT=KILLED' "$TMPDIR"/monitor.txt + rm -rf "$TMPDIR" + return 0 + fi + sleep .5 + done + + return 1 +} + +run_test_killed() { + local killed= + + TMPDIR=$(mktemp -d -p /tmp udev-tests.XXXXXX) + udevadm monitor --udev --property --subsystem-match=mem >"$TMPDIR"/monitor.txt & + KILL_PID="$!" + + rm -f /tmp/test-udev-marker + SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --action add /dev/null + + for _ in {1..40}; do + if [[ -z "$killed" ]]; then + if [[ -e /tmp/test-udev-marker ]]; then + killall --signal ABRT --regexp udev-worker + killed=1 + fi + elif grep -q 'UDEV_WORKER_FAILED=1' "$TMPDIR"/monitor.txt; then + sleep .5 + kill "$KILL_PID" + KILL_PID= + + cat "$TMPDIR"/monitor.txt + grep -q 'UDEV_WORKER_FAILED=1' "$TMPDIR"/monitor.txt + grep -q 'UDEV_WORKER_SIGNAL=6' "$TMPDIR"/monitor.txt + grep -q 'UDEV_WORKER_SIGNAL_NAME=ABRT' "$TMPDIR"/monitor.txt + (! grep -q 'PROGRAM_RESULT=KILLED' "$TMPDIR"/monitor.txt) + rm -rf "$TMPDIR" + return 0 + fi + sleep .5 + done + + return 1 +} + +trap teardown EXIT + +setup +run_test_timeout +run_test_killed + +exit 0 diff --git a/test/units/testsuite-17.04.sh b/test/units/TEST-17-UDEV.04.sh index d1c3c85..d1c3c85 100755 --- a/test/units/testsuite-17.04.sh +++ b/test/units/TEST-17-UDEV.04.sh diff --git a/test/units/testsuite-17.05.sh b/test/units/TEST-17-UDEV.05.sh index 60be31a..60be31a 100755 --- a/test/units/testsuite-17.05.sh +++ b/test/units/TEST-17-UDEV.05.sh diff --git a/test/units/testsuite-17.06.sh b/test/units/TEST-17-UDEV.06.sh index 6d83645..6d83645 100755 --- a/test/units/testsuite-17.06.sh +++ b/test/units/TEST-17-UDEV.06.sh diff --git a/test/units/testsuite-17.07.sh b/test/units/TEST-17-UDEV.07.sh index 629393a..629393a 100755 --- a/test/units/testsuite-17.07.sh +++ b/test/units/TEST-17-UDEV.07.sh diff --git a/test/units/testsuite-17.08.sh b/test/units/TEST-17-UDEV.08.sh index e570c69..e570c69 100755 --- a/test/units/testsuite-17.08.sh +++ b/test/units/TEST-17-UDEV.08.sh diff --git a/test/units/testsuite-17.09.sh b/test/units/TEST-17-UDEV.09.sh index 9993196..9993196 100755 --- a/test/units/testsuite-17.09.sh +++ b/test/units/TEST-17-UDEV.09.sh diff --git a/test/units/testsuite-17.10.sh b/test/units/TEST-17-UDEV.10.sh index f229dcf..a2b8b14 100755 --- a/test/units/testsuite-17.10.sh +++ b/test/units/TEST-17-UDEV.10.sh @@ -45,8 +45,8 @@ udevadm control -S udevadm control -R udevadm control -p HELLO=world udevadm control -m 42 -udevadm control --ping -udevadm control -t 5 +udevadm control --ping -t 5 +udevadm control --load-credentials udevadm control -h udevadm info /dev/null diff --git a/test/units/testsuite-17.11.sh b/test/units/TEST-17-UDEV.11.sh index 42b925f..42b925f 100755 --- a/test/units/testsuite-17.11.sh +++ b/test/units/TEST-17-UDEV.11.sh diff --git a/test/units/testsuite-17.12.sh b/test/units/TEST-17-UDEV.12.sh index ccc91bf..ccc91bf 100755 --- a/test/units/testsuite-17.12.sh +++ b/test/units/TEST-17-UDEV.12.sh diff --git a/test/units/testsuite-17.13.sh b/test/units/TEST-17-UDEV.13.sh index d9dfdd7..d9dfdd7 100755 --- a/test/units/testsuite-17.13.sh +++ b/test/units/TEST-17-UDEV.13.sh diff --git a/test/units/TEST-17-UDEV.credentials.sh b/test/units/TEST-17-UDEV.credentials.sh new file mode 100755 index 0000000..42d3883 --- /dev/null +++ b/test/units/TEST-17-UDEV.credentials.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2016 +set -eux +set -o pipefail + +if [[ $(systemctl is-enabled systemd-udev-load-credentials.service) == not-found ]]; then + echo "Missing systemd-udev-load-credentials.service" >>/skipped + exit 0 +fi + +at_exit() { + rm -f /run/credstore/udev.* + rm -f /run/udev/udev.conf.d/* + rm -f /run/udev/rules.d/* + rm -rf /run/systemd/system/systemd-udev-load-credentials.service.d +} + +trap at_exit EXIT + +mkdir -p /run/credstore +cat > /run/credstore/udev.conf.50-testme <<EOF +udev_log=debug +EOF +cat > /run/credstore/udev.rules.50-testme <<EOF +SUBSYSTEM=="net", OPTIONS="log_level=debug" +EOF + +systemctl edit systemd-udev-load-credentials.service --stdin --drop-in=50-testme.conf <<EOF +[Service] +LoadCredential=udev.conf.50-testme +LoadCredential=udev.rules.50-testme +EOF + +systemctl restart systemd-udev-load-credentials.service + +diff /run/credstore/udev.conf.50-testme /run/udev/udev.conf.d/50-testme.conf +diff /run/credstore/udev.rules.50-testme /run/udev/rules.d/50-testme.rules diff --git a/test/units/TEST-17-UDEV.link-property.sh b/test/units/TEST-17-UDEV.link-property.sh new file mode 100755 index 0000000..517cc3f --- /dev/null +++ b/test/units/TEST-17-UDEV.link-property.sh @@ -0,0 +1,203 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -ex +set -o pipefail + +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +udevadm control --log-level=debug + +mkdir -p /run/systemd/network/ +cat >/run/systemd/network/10-test.link <<EOF +[Match] +Kind=dummy +MACAddress=00:50:56:c0:00:19 + +[Link] +Name=test1 +EOF + +mkdir /run/systemd/network/10-test.link.d +cat >/run/systemd/network/10-test.link.d/10-override.conf <<EOF +[Link] +Property=HOGE=foo BAR=baz SHOULD_BE_UNSET=unset +UnsetProperty=SHOULD_BE_UNSET +EOF + +udevadm control --reload + +ip link add address 00:50:56:c0:00:19 type dummy +udevadm wait --settle --timeout=30 /sys/class/net/test1 +output=$(udevadm info --query property /sys/class/net/test1) +assert_in "HOGE=foo" "$output" +assert_in "BAR=baz" "$output" +assert_not_in "SHOULD_BE_UNSET=" "$output" +assert_in "ID_NET_LINK_FILE=/run/systemd/network/10-test.link" "$output" +assert_in "ID_NET_LINK_FILE_DROPINS=/run/systemd/network/10-test.link.d/10-override.conf" "$output" +assert_in "ID_NET_NAME=test1" "$output" + +cat >/run/systemd/network/10-test.link.d/11-override.conf <<EOF +[Link] +Property= +Property=HOGE2=foo2 BAR2=baz2 SHOULD_BE_UNSET=unset +ImportProperty=HOGE +EOF + +udevadm control --reload + +udevadm trigger --settle --action add /sys/class/net/test1 +output=$(udevadm info --query property /sys/class/net/test1) +assert_in "HOGE=foo" "$output" +assert_in "HOGE2=foo2" "$output" +assert_not_in "BAR=" "$output" +assert_in "BAR2=baz2" "$output" +assert_not_in "SHOULD_BE_UNSET=" "$output" +assert_in "ID_NET_LINK_FILE=/run/systemd/network/10-test.link" "$output" +assert_in "ID_NET_LINK_FILE_DROPINS=/run/systemd/network/10-test.link.d/10-override.conf:/run/systemd/network/10-test.link.d/11-override.conf" "$output" +assert_in "ID_NET_NAME=test1" "$output" + +# On change event, .link file will not be applied. +udevadm trigger --settle --action change /sys/class/net/test1 +output=$(udevadm info --query property /sys/class/net/test1) +assert_not_in "HOGE=" "$output" +assert_not_in "HOGE2=" "$output" +assert_not_in "BAR=" "$output" +assert_not_in "BAR2=" "$output" +assert_not_in "SHOULD_BE_UNSET=" "$output" +assert_in "ID_NET_LINK_FILE=/run/systemd/network/10-test.link" "$output" +assert_in "ID_NET_LINK_FILE_DROPINS=/run/systemd/network/10-test.link.d/10-override.conf:/run/systemd/network/10-test.link.d/11-override.conf" "$output" +assert_in "ID_NET_NAME=test1" "$output" + +### testing with udevadm test-builtin +output=$(udevadm test-builtin --action add net_setup_link /sys/class/net/test1) +assert_not_in "HOGE=" "$output" +assert_in "HOGE2=foo2" "$output" +assert_not_in "BAR=" "$output" +assert_in "BAR2=baz2" "$output" +assert_in "SHOULD_BE_UNSET=" "$output" # this is expected, as an empty assignment is also logged. +assert_in "ID_NET_LINK_FILE=/run/systemd/network/10-test.link" "$output" +assert_in "ID_NET_LINK_FILE_DROPINS=/run/systemd/network/10-test.link.d/10-override.conf:/run/systemd/network/10-test.link.d/11-override.conf" "$output" +assert_in "ID_NET_NAME=test1" "$output" + +# check that test-builtin command does not update udev database. +output=$(udevadm info --query property /sys/class/net/test1) +assert_not_in "HOGE=" "$output" +assert_not_in "HOGE2=" "$output" +assert_not_in "BAR=" "$output" +assert_not_in "BAR2=" "$output" +assert_not_in "SHOULD_BE_UNSET=" "$output" +assert_in "ID_NET_LINK_FILE=/run/systemd/network/10-test.link" "$output" +assert_in "ID_NET_LINK_FILE_DROPINS=/run/systemd/network/10-test.link.d/10-override.conf:/run/systemd/network/10-test.link.d/11-override.conf" "$output" +assert_in "ID_NET_NAME=test1" "$output" + +output=$(udevadm test-builtin --action change net_setup_link /sys/class/net/test1) +assert_not_in "HOGE=" "$output" +assert_not_in "HOGE2=" "$output" +assert_not_in "BAR=" "$output" +assert_not_in "BAR2=" "$output" +assert_not_in "SHOULD_BE_UNSET=" "$output" +assert_in "ID_NET_LINK_FILE=/run/systemd/network/10-test.link" "$output" +assert_in "ID_NET_LINK_FILE_DROPINS=/run/systemd/network/10-test.link.d/10-override.conf:/run/systemd/network/10-test.link.d/11-override.conf" "$output" +assert_in "ID_NET_NAME=test1" "$output" + +output=$(udevadm info --query property /sys/class/net/test1) +assert_not_in "HOGE=" "$output" +assert_not_in "HOGE2=" "$output" +assert_not_in "BAR=" "$output" +assert_not_in "BAR2=" "$output" +assert_not_in "SHOULD_BE_UNSET=" "$output" +assert_in "ID_NET_LINK_FILE=/run/systemd/network/10-test.link" "$output" +assert_in "ID_NET_LINK_FILE_DROPINS=/run/systemd/network/10-test.link.d/10-override.conf:/run/systemd/network/10-test.link.d/11-override.conf" "$output" +assert_in "ID_NET_NAME=test1" "$output" + +### testing with udevadm test +output=$(udevadm test --action add /sys/class/net/test1) +assert_not_in "HOGE=" "$output" +assert_in "HOGE2=foo2" "$output" +assert_not_in "BAR=" "$output" +assert_in "BAR2=baz2" "$output" +assert_not_in "SHOULD_BE_UNSET=" "$output" +assert_in "ID_NET_LINK_FILE=/run/systemd/network/10-test.link" "$output" +assert_in "ID_NET_LINK_FILE_DROPINS=/run/systemd/network/10-test.link.d/10-override.conf:/run/systemd/network/10-test.link.d/11-override.conf" "$output" +assert_in "ID_NET_NAME=test1" "$output" + +# check that test command does not update udev database. +output=$(udevadm info --query property /sys/class/net/test1) +assert_not_in "HOGE=" "$output" +assert_not_in "HOGE2=" "$output" +assert_not_in "BAR=" "$output" +assert_not_in "BAR2=" "$output" +assert_not_in "SHOULD_BE_UNSET=" "$output" +assert_in "ID_NET_LINK_FILE=/run/systemd/network/10-test.link" "$output" +assert_in "ID_NET_LINK_FILE_DROPINS=/run/systemd/network/10-test.link.d/10-override.conf:/run/systemd/network/10-test.link.d/11-override.conf" "$output" +assert_in "ID_NET_NAME=test1" "$output" + +output=$(udevadm test --action change /sys/class/net/test1) +assert_not_in "HOGE=" "$output" +assert_not_in "HOGE2=" "$output" +assert_not_in "BAR=" "$output" +assert_not_in "BAR2=" "$output" +assert_not_in "SHOULD_BE_UNSET=" "$output" +assert_in "ID_NET_LINK_FILE=/run/systemd/network/10-test.link" "$output" +assert_in "ID_NET_LINK_FILE_DROPINS=/run/systemd/network/10-test.link.d/10-override.conf:/run/systemd/network/10-test.link.d/11-override.conf" "$output" +assert_in "ID_NET_NAME=test1" "$output" + +output=$(udevadm info --query property /sys/class/net/test1) +assert_not_in "HOGE=" "$output" +assert_not_in "HOGE2=" "$output" +assert_not_in "BAR=" "$output" +assert_not_in "BAR2=" "$output" +assert_not_in "SHOULD_BE_UNSET=" "$output" +assert_in "ID_NET_LINK_FILE=/run/systemd/network/10-test.link" "$output" +assert_in "ID_NET_LINK_FILE_DROPINS=/run/systemd/network/10-test.link.d/10-override.conf:/run/systemd/network/10-test.link.d/11-override.conf" "$output" +assert_in "ID_NET_NAME=test1" "$output" + +# test for specifiers +cat >/run/systemd/network/10-test.link.d/12-override.conf <<EOF +[Link] +Property= +Property=LINK_VERSION=%v +EOF + +udevadm control --reload + +output=$(udevadm test --action add /sys/class/net/test1) +assert_in "LINK_VERSION=$(uname -r)" "$output" + +udevadm trigger --settle --action add /sys/class/net/test1 +output=$(udevadm info --query property /sys/class/net/test1) +assert_in "LINK_VERSION=$(uname -r)" "$output" + +# test for constant properties +cat >/run/systemd/network/10-test.link.d/13-override.conf <<EOF +[Link] +Property= +Property=ACTION=foo IFINDEX=bar +UnsetProperty=DEVPATH +EOF + +udevadm control --reload + +output=$(udevadm test --action add /sys/class/net/test1) +assert_in "ACTION=add" "$output" +assert_not_in "ACTION=foo" "$output" +assert_in "IFINDEX=" "$output" +assert_not_in "IFINDEX=bar" "$output" +assert_in "DEVPATH=" "$output" + +udevadm trigger --settle --action add /sys/class/net/test1 +output=$(udevadm info --query property /sys/class/net/test1) +assert_not_in "ACTION=foo" "$output" +assert_in "IFINDEX=" "$output" +assert_not_in "IFINDEX=bar" "$output" +assert_in "DEVPATH=" "$output" + +# cleanup +ip link del dev test1 + +rm -f /run/systemd/network/10-test.link +rm -rf /run/systemd/network/10-test.link.d +udevadm control --reload --log-level=info + +exit 0 diff --git a/test/units/testsuite-17.sh b/test/units/TEST-17-UDEV.sh index 14ceeba..14ceeba 100755 --- a/test/units/testsuite-17.sh +++ b/test/units/TEST-17-UDEV.sh diff --git a/test/units/testsuite-18.sh b/test/units/TEST-18-FAILUREACTION.sh index 44b792f..364c20d 100755 --- a/test/units/testsuite-18.sh +++ b/test/units/TEST-18-FAILUREACTION.sh @@ -11,7 +11,7 @@ if ! test -f /firstphase ; then systemd-run --wait -p SuccessAction=reboot true else echo OK >/testok - systemd-run --wait -p FailureAction=poweroff false + systemd-run --wait -p FailureAction=exit -p FailureActionExitStatus=123 false fi sleep infinity diff --git a/test/units/testsuite-19.ExitType-cgroup.sh b/test/units/TEST-19-CGROUP.ExitType-cgroup.sh index cd221d7..65c2606 100755 --- a/test/units/testsuite-19.ExitType-cgroup.sh +++ b/test/units/TEST-19-CGROUP.ExitType-cgroup.sh @@ -27,8 +27,9 @@ disown systemd-notify --ready -# Run the stop/kill command -\$1 & +# Run the stop/kill command, but sleep a bit to make the sleep infinity +# below actually started before stopping/killing the service. +(sleep 1; \$1) & # process tree: systemd -> bash -> sleep sleep infinity diff --git a/test/units/testsuite-19.cleanup-slice.sh b/test/units/TEST-19-CGROUP.cleanup-slice.sh index 5d63160..5d63160 100755 --- a/test/units/testsuite-19.cleanup-slice.sh +++ b/test/units/TEST-19-CGROUP.cleanup-slice.sh diff --git a/test/units/testsuite-19.delegate.sh b/test/units/TEST-19-CGROUP.delegate.sh index 74d36c4..022515f 100755 --- a/test/units/testsuite-19.delegate.sh +++ b/test/units/TEST-19-CGROUP.delegate.sh @@ -32,6 +32,7 @@ for attr in cgroup.threads memory.oom.group memory.reclaim ; do if grep -q "$attr" /sys/kernel/cgroup/delegate ; then systemd-run --wait \ --unit=test-0.service \ + --property="MemoryAccounting=1" \ --property="DynamicUser=1" \ --property="Delegate=" \ test -w /sys/fs/cgroup/system.slice/test-0.service/ -a \ diff --git a/test/units/testsuite-19.sh b/test/units/TEST-19-CGROUP.sh index 9c2a033..9c2a033 100755 --- a/test/units/testsuite-19.sh +++ b/test/units/TEST-19-CGROUP.sh diff --git a/test/units/testsuite-21.sh b/test/units/TEST-21-DFUZZER.sh index 02673ab..08ebfd9 100755 --- a/test/units/testsuite-21.sh +++ b/test/units/TEST-21-DFUZZER.sh @@ -3,6 +3,12 @@ set -eux set -o pipefail +# check dfuzzer is present before testing +if ! command -v dfuzzer &>/dev/null; then + echo "dfuzzer is not installed, skipping" | tee --append /skipped + exit 77 +fi + # Save the end.service state before we start fuzzing, as it might get changed # on the fly by one of the fuzzers systemctl list-jobs | grep -F 'end.service' && SHUTDOWN_AT_EXIT=1 || SHUTDOWN_AT_EXIT=0 @@ -21,14 +27,32 @@ at_exit() { fi } +add_suppression() { + local interface="${1:?}" + local suppression="${2:?}" + + sed -i "\%\[$interface\]%a$suppression" /etc/dfuzzer.conf +} + trap at_exit EXIT systemctl log-level info # FIXME: systemd-run doesn't play well with daemon-reexec # See: https://github.com/systemd/systemd/issues/27204 -sed -i '/\[org.freedesktop.systemd1\]/aorg.freedesktop.systemd1.Manager:Reexecute FIXME' /etc/dfuzzer.conf -sed -i '/\[org.freedesktop.systemd1\]/aorg.freedesktop.systemd1.Manager:SoftReboot destructive' /etc/dfuzzer.conf +add_suppression "org.freedesktop.systemd1" "org.freedesktop.systemd1.Manager:Reexecute FIXME" + +add_suppression "org.freedesktop.systemd1" "org.freedesktop.systemd1.Manager:SoftReboot destructive" +add_suppression "org.freedesktop.login1" "Sleep destructive" + +# Skip calling start and stop methods on unit objects, as doing that is not only time consuming, but it also +# starts/stops units that interfere with the machine state. The actual code paths should be covered (to some +# degree) by the respective method counterparts on the manager object. +for method in Start Stop Restart ReloadOrRestart ReloadOrTryRestart Kill; do + add_suppression "org.freedesktop.systemd1" "org.freedesktop.systemd1.Unit:$method" +done + +cat /etc/dfuzzer.conf # TODO # * check for possibly newly introduced buses? diff --git a/test/units/testsuite-22.01.sh b/test/units/TEST-22-TMPFILES.01.sh index 2276b75..2276b75 100755 --- a/test/units/testsuite-22.01.sh +++ b/test/units/TEST-22-TMPFILES.01.sh diff --git a/test/units/testsuite-22.02.sh b/test/units/TEST-22-TMPFILES.02.sh index b883a96..f191ae3 100755 --- a/test/units/testsuite-22.02.sh +++ b/test/units/TEST-22-TMPFILES.02.sh @@ -14,6 +14,14 @@ mkdir /tmp/{C,d,D,e} mkdir /tmp/d/2 chmod 777 /tmp/d/2 +systemd-tmpfiles --dry-run --create - <<EOF +d /tmp/d/1 0755 daemon daemon - - +d /tmp/d/2 0755 daemon daemon - - +EOF + +test ! -d /tmp/d/1 +test -d /tmp/d/2 + systemd-tmpfiles --create - <<EOF d /tmp/d/1 0755 daemon daemon - - d /tmp/d/2 0755 daemon daemon - - @@ -104,6 +112,14 @@ chmod 755 /tmp/C/{1,2,3}-origin/f1 mkdir /tmp/C/{2,3} touch /tmp/C/3/f1 +systemd-tmpfiles --dry-run --create - <<EOF +C /tmp/C/1 0755 daemon daemon - /tmp/C/1-origin +C /tmp/C/2 0755 daemon daemon - /tmp/C/2-origin +EOF + +test ! -d /tmp/C/1 +test -d /tmp/C/2 + systemd-tmpfiles --create - <<EOF C /tmp/C/1 0755 daemon daemon - /tmp/C/1-origin C /tmp/C/2 0755 daemon daemon - /tmp/C/2-origin diff --git a/test/units/testsuite-22.03.sh b/test/units/TEST-22-TMPFILES.03.sh index 6fce4c0..d158498 100755 --- a/test/units/testsuite-22.03.sh +++ b/test/units/TEST-22-TMPFILES.03.sh @@ -12,6 +12,14 @@ touch /tmp/file-owned-by-root # # 'f' # +systemd-tmpfiles --dry-run --create - <<EOF +f /tmp/f/1 0644 - - - - +f /tmp/f/2 0644 - - - This string should be written +EOF + +test ! -e /tmp/f/1 +test ! -e /tmp/f/2 + systemd-tmpfiles --create - <<EOF f /tmp/f/1 0644 - - - - f /tmp/f/2 0644 - - - This string should be written @@ -189,6 +197,11 @@ touch /tmp/w/overwritten touch /tmp/w/appended ### nop if the target does not exist. +systemd-tmpfiles --dry-run --create - <<EOF +w /tmp/w/unexistent 0644 - - - new content +EOF +test ! -e /tmp/w/unexistent + systemd-tmpfiles --create - <<EOF w /tmp/w/unexistent 0644 - - - new content EOF @@ -200,6 +213,12 @@ w /tmp/w/unexistent 0644 - - - - EOF ### write into an empty file. +systemd-tmpfiles --dry-run --create - <<EOF +w /tmp/w/overwritten 0644 - - - old content +EOF +test -f /tmp/w/overwritten +test -z "$(< /tmp/w/overwritten)" + systemd-tmpfiles --create - <<EOF w /tmp/w/overwritten 0644 - - - old content EOF @@ -207,6 +226,12 @@ test -f /tmp/w/overwritten test "$(< /tmp/w/overwritten)" = "old content" ### old content is overwritten +systemd-tmpfiles --dry-run --create - <<EOF +w /tmp/w/overwritten 0644 - - - new content +EOF +test -f /tmp/w/overwritten +test "$(< /tmp/w/overwritten)" = "old content" + systemd-tmpfiles --create - <<EOF w /tmp/w/overwritten 0644 - - - new content EOF @@ -223,6 +248,10 @@ test -f /tmp/w/appended test "$(< /tmp/w/appended)" = "$(echo -ne '12\n3')" ### writing into an 'exotic' file should be allowed. +systemd-tmpfiles --dry-run --create - <<EOF +w /dev/null - - - - new content +EOF + systemd-tmpfiles --create - <<EOF w /dev/null - - - - new content EOF diff --git a/test/units/testsuite-22.04.sh b/test/units/TEST-22-TMPFILES.04.sh index 7bf2b28..2c0ffe3 100755 --- a/test/units/testsuite-22.04.sh +++ b/test/units/TEST-22-TMPFILES.04.sh @@ -9,6 +9,12 @@ rm -fr /tmp/p mkdir /tmp/p touch /tmp/p/f1 +systemd-tmpfiles --dry-run --create - <<EOF +p /tmp/p/fifo1 0666 - - - - +EOF + +test ! -p /tmp/p/fifo1 + systemd-tmpfiles --create - <<EOF p /tmp/p/fifo1 0666 - - - - EOF diff --git a/test/units/testsuite-22.05.sh b/test/units/TEST-22-TMPFILES.05.sh index cde9b5d..d78e7ee 100755 --- a/test/units/testsuite-22.05.sh +++ b/test/units/TEST-22-TMPFILES.05.sh @@ -12,6 +12,15 @@ mkdir /tmp/{z,Z} mkdir /tmp/z/d{1,2} touch /tmp/z/f1 /tmp/z/d1/f11 /tmp/z/d2/f21 +systemd-tmpfiles --dry-run --create - <<EOF +z /tmp/z/f1 0755 daemon daemon - - +z /tmp/z/d1 0755 daemon daemon - - +EOF + +test "$(stat -c %U /tmp/z/f1)" = "$USER" +test "$(stat -c %U /tmp/z/d1)" = "$USER" +test "$(stat -c %U /tmp/z/d1/f11)" = "$USER" + systemd-tmpfiles --create - <<EOF z /tmp/z/f1 0755 daemon daemon - - z /tmp/z/d1 0755 daemon daemon - - diff --git a/test/units/testsuite-22.06.sh b/test/units/TEST-22-TMPFILES.06.sh index f64a95c..45aea9c 100755 --- a/test/units/testsuite-22.06.sh +++ b/test/units/TEST-22-TMPFILES.06.sh @@ -6,7 +6,14 @@ set -eux set -o pipefail test_snippet() { - systemd-tmpfiles "$@" - <<EOF + # First call with --dry-run to test the code paths + systemd-tmpfiles --dry-run "$@" - <<EOF +d /var/tmp/foobar-test-06 +d /var/tmp/foobar-test-06/important +R /var/tmp/foobar-test-06 +EOF + + systemd-tmpfiles "$@" - <<EOF d /var/tmp/foobar-test-06 d /var/tmp/foobar-test-06/important R /var/tmp/foobar-test-06 diff --git a/test/units/testsuite-22.07.sh b/test/units/TEST-22-TMPFILES.07.sh index de20d5e..de20d5e 100755 --- a/test/units/testsuite-22.07.sh +++ b/test/units/TEST-22-TMPFILES.07.sh diff --git a/test/units/testsuite-22.08.sh b/test/units/TEST-22-TMPFILES.08.sh index 40fafd3..40fafd3 100755 --- a/test/units/testsuite-22.08.sh +++ b/test/units/TEST-22-TMPFILES.08.sh diff --git a/test/units/testsuite-22.09.sh b/test/units/TEST-22-TMPFILES.09.sh index 0857773..0857773 100755 --- a/test/units/testsuite-22.09.sh +++ b/test/units/TEST-22-TMPFILES.09.sh diff --git a/test/units/testsuite-22.10.sh b/test/units/TEST-22-TMPFILES.10.sh index 99052c8..99052c8 100755 --- a/test/units/testsuite-22.10.sh +++ b/test/units/TEST-22-TMPFILES.10.sh diff --git a/test/units/testsuite-22.11.sh b/test/units/TEST-22-TMPFILES.11.sh index f71a95f..6f75888 100755 --- a/test/units/testsuite-22.11.sh +++ b/test/units/TEST-22-TMPFILES.11.sh @@ -12,6 +12,19 @@ mkdir /tmp/x mkdir -p /tmp/x/{1,2} touch /tmp/x/1/{x1,x2} /tmp/x/2/{y1,y2} /tmp/x/{z1,z2} +systemd-tmpfiles --clean --dry-run - <<EOF +d /tmp/x - - - 0 +x /tmp/x/1 +EOF + +find /tmp/x | sort +test -f /tmp/x/1/x1 +test -f /tmp/x/1/x2 +test -f /tmp/x/2/y1 +test -f /tmp/x/2/y2 +test -f /tmp/x/z1 +test -f /tmp/x/z2 + systemd-tmpfiles --clean - <<EOF d /tmp/x - - - 0 x /tmp/x/1 @@ -34,6 +47,19 @@ test ! -f /tmp/x/z2 mkdir -p /tmp/x/{1,2} touch /tmp/x/1/{x1,x2} /tmp/x/2/{y1,y2} /tmp/x/{z1,z2} +systemd-tmpfiles --dry-run --clean - <<EOF +d /tmp/x - - - 0 +X /tmp/x/1 +EOF + +find /tmp/x | sort +test -f /tmp/x/1/x1 +test -f /tmp/x/1/x2 +test -f /tmp/x/2/y1 +test -f /tmp/x/2/y2 +test -f /tmp/x/z1 +test -f /tmp/x/z2 + systemd-tmpfiles --clean - <<EOF d /tmp/x - - - 0 X /tmp/x/1 @@ -56,6 +82,20 @@ test ! -f /tmp/x/z2 mkdir -p /tmp/x/{1,2} touch /tmp/x/1/{x1,x2} /tmp/x/2/{y1,y2} /tmp/x/{z1,z2} +systemd-tmpfiles --dry-run --clean - <<EOF +d /tmp/x - - - 0 +x /tmp/x/[1345] +x /tmp/x/z* +EOF + +find /tmp/x | sort +test -f /tmp/x/1/x1 +test -f /tmp/x/1/x2 +test -f /tmp/x/2/y1 +test -f /tmp/x/2/y2 +test -f /tmp/x/z1 +test -f /tmp/x/z2 + systemd-tmpfiles --clean - <<EOF d /tmp/x - - - 0 x /tmp/x/[1345] @@ -79,6 +119,20 @@ test -f /tmp/x/z2 mkdir -p /tmp/x/{1,2} touch /tmp/x/1/{x1,x2} /tmp/x/2/{y1,y2} /tmp/x/{z1,z2} +systemd-tmpfiles --dry-run --clean - <<EOF +d /tmp/x - - - 0 +X /tmp/x/[1345] +X /tmp/x/?[12] +EOF + +find /tmp/x | sort +test -f /tmp/x/1/x1 +test -f /tmp/x/1/x2 +test -f /tmp/x/2/y1 +test -f /tmp/x/2/y2 +test -f /tmp/x/z1 +test -f /tmp/x/z2 + systemd-tmpfiles --clean - <<EOF d /tmp/x - - - 0 X /tmp/x/[1345] @@ -102,6 +156,19 @@ test -f /tmp/x/z2 mkdir -p /tmp/x/{1,2}/a touch /tmp/x/1/a/{x1,x2} /tmp/x/2/a/{y1,y2} +systemd-tmpfiles --dry-run --clean - <<EOF +# x/X is not supposed to influence r +x /tmp/x/1/a +X /tmp/x/2/a +r /tmp/x/1 +r /tmp/x/2 +EOF + +test -f /tmp/x/1/a/x1 +test -f /tmp/x/1/a/x2 +test -f /tmp/x/2/a/y1 +test -f /tmp/x/2/a/y2 + systemd-tmpfiles --clean - <<EOF # x/X is not supposed to influence r x /tmp/x/1/a @@ -125,17 +192,58 @@ test -f /tmp/x/2/a/y2 mkdir -p /tmp/x/{1,2}/a touch /tmp/x/1/a/{x1,x2} /tmp/x/2/a/{y1,y2} +systemd-tmpfiles --dry-run --remove - <<EOF +# Check that X is honoured below R +X /tmp/x/1/a +X /tmp/x/2/a +R /tmp/x/1 +EOF + +test -f /tmp/x/1/a/x1 +test -f /tmp/x/1/a/x2 +test -f /tmp/x/2/a/y1 +test -f /tmp/x/2/a/y2 + systemd-tmpfiles --remove - <<EOF -# X is not supposed to influence R +# Check that X is honoured below R X /tmp/x/1/a X /tmp/x/2/a R /tmp/x/1 EOF find /tmp/x | sort -test ! -d /tmp/x/1 -test ! -d /tmp/x/1/a -test ! -f /tmp/x/1/a/x1 -test ! -f /tmp/x/1/a/x2 +test -d /tmp/x/1 +test -d /tmp/x/1/a +test -f /tmp/x/1/a/x1 +test -f /tmp/x/1/a/x2 test -f /tmp/x/2/a/y1 test -f /tmp/x/2/a/y2 + +# +# 'r/R/D' and non-directories +# + +touch /tmp/x/{11,22,33} + +systemd-tmpfiles --dry-run --remove - <<EOF +# Check that X is honoured below R +r /tmp/x/11 +R /tmp/x/22 +D /tmp/x/33 +EOF + +test -f /tmp/x/11 +test -f /tmp/x/22 +test -f /tmp/x/33 + +systemd-tmpfiles --remove - <<EOF +# Check that X is honoured below R +r /tmp/x/11 +R /tmp/x/22 +D /tmp/x/33 +EOF + +find /tmp/x | sort +test ! -f /tmp/x/11 +test ! -f /tmp/x/22 +test -f /tmp/x/33 diff --git a/test/units/testsuite-22.12.sh b/test/units/TEST-22-TMPFILES.12.sh index b8c4da8..57788da 100755 --- a/test/units/testsuite-22.12.sh +++ b/test/units/TEST-22-TMPFILES.12.sh @@ -52,6 +52,16 @@ sleep 1 touch /tmp/ageby/d{3,4}/f{2..4} # Check for cleanup of "f1" in each of "/tmp/d{1..4}". +systemd-tmpfiles --dry-run --clean - <<-EOF +d /tmp/ageby/d1 - - - a:1m - +e /tmp/ageby/d2 - - - m:3m - +D /tmp/ageby/d3 - - - c:2s - +EOF + +for d in d{1..3}; do + test -f "/tmp/ageby/${d}/f1" +done + systemd-tmpfiles --clean - <<-EOF d /tmp/ageby/d1 - - - a:1m - e /tmp/ageby/d2 - - - m:3m - diff --git a/test/units/testsuite-22.13.sh b/test/units/TEST-22-TMPFILES.13.sh index 33ef451..33ef451 100755 --- a/test/units/testsuite-22.13.sh +++ b/test/units/TEST-22-TMPFILES.13.sh diff --git a/test/units/testsuite-22.14.sh b/test/units/TEST-22-TMPFILES.14.sh index 2132de7..2132de7 100755 --- a/test/units/testsuite-22.14.sh +++ b/test/units/TEST-22-TMPFILES.14.sh diff --git a/test/units/testsuite-22.15.sh b/test/units/TEST-22-TMPFILES.15.sh index 6cbb498..6ee0e63 100755 --- a/test/units/testsuite-22.15.sh +++ b/test/units/TEST-22-TMPFILES.15.sh @@ -13,6 +13,12 @@ home='/somewhere' dst='/tmp/L/1' src="$home" HOME="$home" \ +systemd-tmpfiles --dry-run --create - <<EOF +L $dst - - - - %h +EOF +test ! -h "$dst" + +HOME="$home" \ systemd-tmpfiles --create - <<EOF L $dst - - - - %h EOF @@ -26,6 +32,12 @@ src="/usr/share/factory$home" mkdir -p "$root$src" dst="$root$home" HOME="$home" \ +systemd-tmpfiles --create --dry-run --root="$root" - <<EOF +L %h - - - - +EOF +test ! -h "$dst" + +HOME="$home" \ systemd-tmpfiles --create --root="$root" - <<EOF L %h - - - - EOF diff --git a/test/units/testsuite-22.16.sh b/test/units/TEST-22-TMPFILES.16.sh index 555e07f..3d3d0c8 100755 --- a/test/units/testsuite-22.16.sh +++ b/test/units/TEST-22-TMPFILES.16.sh @@ -12,6 +12,11 @@ rm -f /tmp/acl_exec touch /tmp/acl_exec # No ACL set yet +systemd-tmpfiles --dry-run --create - <<EOF +a /tmp/acl_exec - - - - u:root:rwX +EOF +assert_not_in 'user:root:rw-' "$(getfacl -Ec /tmp/acl_exec)" + systemd-tmpfiles --create - <<EOF a /tmp/acl_exec - - - - u:root:rwX EOF diff --git a/test/units/testsuite-22.17.sh b/test/units/TEST-22-TMPFILES.17.sh index f43aba5..f43aba5 100755 --- a/test/units/testsuite-22.17.sh +++ b/test/units/TEST-22-TMPFILES.17.sh diff --git a/test/units/TEST-22-TMPFILES.18.sh b/test/units/TEST-22-TMPFILES.18.sh new file mode 100755 index 0000000..5d24197 --- /dev/null +++ b/test/units/TEST-22-TMPFILES.18.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Tests for the --purge switch +# +set -eux +set -o pipefail + +export SYSTEMD_LOG_LEVEL=debug + +c=' +d /tmp/somedir +f /tmp/somedir/somefile - - - - baz +' + +systemd-tmpfiles --create - <<<"$c" +test -f /tmp/somedir/somefile +grep -q baz /tmp/somedir/somefile + +systemd-tmpfiles --purge --dry-run - <<<"$c" +test -f /tmp/somedir/somefile +grep -q baz /tmp/somedir/somefile + +systemd-tmpfiles --purge - <<<"$c" +test ! -f /tmp/somedir/somefile +test ! -d /tmp/somedir/ + +systemd-tmpfiles --create --purge --dry-run - <<<"$c" +test ! -f /tmp/somedir/somefile +test ! -d /tmp/somedir/ + +systemd-tmpfiles --create --purge - <<<"$c" +test -f /tmp/somedir/somefile +grep -q baz /tmp/somedir/somefile diff --git a/test/units/TEST-22-TMPFILES.19.sh b/test/units/TEST-22-TMPFILES.19.sh new file mode 100755 index 0000000..c5a0966 --- /dev/null +++ b/test/units/TEST-22-TMPFILES.19.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Tests for character and block device creation +# +set -eux +set -o pipefail + +rm -rf /tmp/dev +mkdir /tmp/dev + +# We are running tests in /tmp, which would normally be mounted nodev, +# so we only try with --dry-run. + +systemd-tmpfiles --dry-run --create - <<EOF +c /tmp/dev/char - - - - 11:12 +b /tmp/dev/block - - - - 11:14 +EOF + +test ! -e /tmp/dev/char +test ! -e /tmp/dev/block + +systemd-tmpfiles --dry-run --create - <<EOF +c+ /tmp/dev/char - - - - 11:12 +b+ /tmp/dev/block - - - - 11:14 +EOF + +test ! -e /tmp/dev/char +test ! -e /tmp/dev/block diff --git a/test/units/testsuite-22.sh b/test/units/TEST-22-TMPFILES.sh index 9c2a033..9c2a033 100755 --- a/test/units/testsuite-22.sh +++ b/test/units/TEST-22-TMPFILES.sh diff --git a/test/units/TEST-23-UNIT-FILE-openfile-child.sh b/test/units/TEST-23-UNIT-FILE-openfile-child.sh new file mode 100755 index 0000000..4828b9d --- /dev/null +++ b/test/units/TEST-23-UNIT-FILE-openfile-child.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +assert_eq "$LISTEN_FDS" "$1" +assert_eq "$LISTEN_FDNAMES" "$2" + +for ((i = 3; i < 3 + LISTEN_FDS; i++)); do + read -r -u "$i" text + assert_eq "$text" "${!i}" # Dereference $i to get i'th arg +done diff --git a/test/units/TEST-23-UNIT-FILE-short-lived.sh b/test/units/TEST-23-UNIT-FILE-short-lived.sh new file mode 100755 index 0000000..4b13070 --- /dev/null +++ b/test/units/TEST-23-UNIT-FILE-short-lived.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -ex + +if [ -f /tmp/TEST-23-UNIT-FILE.counter ] ; then + read -r counter < /tmp/TEST-23-UNIT-FILE.counter + counter=$((counter + 1)) +else + counter=0 +fi + +echo "$counter" >/tmp/TEST-23-UNIT-FILE.counter + +if [ "$counter" -eq 5 ] ; then + systemctl kill --kill-whom=main -sUSR1 TEST-23-UNIT-FILE.service +fi + +exec sleep 1.5 diff --git a/test/units/testsuite-23.ExecReload.sh b/test/units/TEST-23-UNIT-FILE.ExecReload.sh index b497f73..d544ce6 100755 --- a/test/units/testsuite-23.ExecReload.sh +++ b/test/units/TEST-23-UNIT-FILE.ExecReload.sh @@ -14,7 +14,7 @@ SERVICE_NAME="${SERVICE_PATH##*/}" echo "[#1] Failing ExecReload= should not kill the service" cat >"$SERVICE_PATH" <<EOF [Service] -ExecStart=/bin/sleep infinity +ExecStart=sleep infinity ExecReload=/bin/false EOF @@ -30,7 +30,7 @@ systemctl stop "$SERVICE_NAME" echo "[#2] Failing ExecReload= should not kill the service (multiple ExecReload=)" cat >"$SERVICE_PATH" <<EOF [Service] -ExecStart=/bin/sleep infinity +ExecStart=sleep infinity ExecReload=/bin/true ExecReload=/bin/false ExecReload=/bin/true @@ -47,7 +47,7 @@ systemctl stop "$SERVICE_NAME" echo "[#3] Failing ExecReload=- should not affect reload's exit code" cat >"$SERVICE_PATH" <<EOF [Service] -ExecStart=/bin/sleep infinity +ExecStart=sleep infinity ExecReload=-/bin/false EOF diff --git a/test/units/testsuite-23.ExecStopPost.sh b/test/units/TEST-23-UNIT-FILE.ExecStopPost.sh index aeaf3aa..aeaf3aa 100755 --- a/test/units/testsuite-23.ExecStopPost.sh +++ b/test/units/TEST-23-UNIT-FILE.ExecStopPost.sh diff --git a/test/units/TEST-23-UNIT-FILE.JoinsNamespaceOf.sh b/test/units/TEST-23-UNIT-FILE.JoinsNamespaceOf.sh new file mode 100755 index 0000000..4fd68d8 --- /dev/null +++ b/test/units/TEST-23-UNIT-FILE.JoinsNamespaceOf.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later + +set -eux +set -o pipefail + +# Test JoinsNamespaceOf= with PrivateTmp=yes + +systemd-analyze log-level debug +systemd-analyze log-target journal + +# simple case +systemctl start TEST-23-UNIT-FILE-joins-namespace-of-1.service +systemctl start TEST-23-UNIT-FILE-joins-namespace-of-2.service +systemctl start TEST-23-UNIT-FILE-joins-namespace-of-3.service +systemctl stop TEST-23-UNIT-FILE-joins-namespace-of-1.service + +# inverse dependency +systemctl start TEST-23-UNIT-FILE-joins-namespace-of-4.service +systemctl start TEST-23-UNIT-FILE-joins-namespace-of-5.service +systemctl stop TEST-23-UNIT-FILE-joins-namespace-of-4.service + +# transitive dependency +systemctl start TEST-23-UNIT-FILE-joins-namespace-of-6.service +systemctl start TEST-23-UNIT-FILE-joins-namespace-of-7.service +systemctl start TEST-23-UNIT-FILE-joins-namespace-of-8.service +systemctl start TEST-23-UNIT-FILE-joins-namespace-of-9.service +systemctl stop TEST-23-UNIT-FILE-joins-namespace-of-6.service +systemctl stop TEST-23-UNIT-FILE-joins-namespace-of-8.service + +systemd-analyze log-level info diff --git a/test/units/testsuite-23.RuntimeDirectoryPreserve.sh b/test/units/TEST-23-UNIT-FILE.RuntimeDirectoryPreserve.sh index ca57702..ca57702 100755 --- a/test/units/testsuite-23.RuntimeDirectoryPreserve.sh +++ b/test/units/TEST-23-UNIT-FILE.RuntimeDirectoryPreserve.sh diff --git a/test/units/testsuite-23.StandardOutput.sh b/test/units/TEST-23-UNIT-FILE.StandardOutput.sh index 50b9ac2..a951b13 100755 --- a/test/units/testsuite-23.StandardOutput.sh +++ b/test/units/TEST-23-UNIT-FILE.StandardOutput.sh @@ -7,7 +7,7 @@ set -o pipefail systemd-analyze log-level debug -systemd-run --wait --unit=testsuite-23-standard-output-one \ +systemd-run --wait --unit=TEST-23-UNIT-FILE-standard-output-one \ -p StandardOutput=file:/tmp/stdout \ -p StandardError=file:/tmp/stderr \ -p Type=exec \ @@ -19,7 +19,7 @@ cmp /tmp/stderr <<EOF y EOF -systemd-run --wait --unit=testsuite-23-standard-output-two \ +systemd-run --wait --unit=TEST-23-UNIT-FILE-standard-output-two \ -p StandardOutput=file:/tmp/stdout \ -p StandardError=file:/tmp/stderr \ -p Type=exec \ @@ -31,7 +31,7 @@ cmp /tmp/stderr <<EOF a EOF -systemd-run --wait --unit=testsuite-23-standard-output-three \ +systemd-run --wait --unit=TEST-23-UNIT-FILE-standard-output-three \ -p StandardOutput=append:/tmp/stdout \ -p StandardError=append:/tmp/stderr \ -p Type=exec \ @@ -45,7 +45,7 @@ a c EOF -systemd-run --wait --unit=testsuite-23-standard-output-four \ +systemd-run --wait --unit=TEST-23-UNIT-FILE-standard-output-four \ -p StandardOutput=truncate:/tmp/stdout \ -p StandardError=truncate:/tmp/stderr \ -p Type=exec \ diff --git a/test/units/TEST-23-UNIT-FILE.Upholds.sh b/test/units/TEST-23-UNIT-FILE.Upholds.sh new file mode 100755 index 0000000..20d2d2b --- /dev/null +++ b/test/units/TEST-23-UNIT-FILE.Upholds.sh @@ -0,0 +1,99 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later + +set -eux +set -o pipefail + +# Test OnSuccess= + Uphold= + PropagatesStopTo= + BindsTo= + +systemd-analyze log-level debug +systemd-analyze log-target journal + +# Idea is this: +# 1. we start TEST-23-UNIT-FILE-success.service +# 2. which through OnSuccess= starts TEST-23-UNIT-FILE-fail.service, +# 3. which through OnFailure= starts TEST-23-UNIT-FILE-uphold.service, +# 4. which through Uphold= starts/keeps TEST-23-UNIT-FILE-short-lived.service running, +# 5. which will sleep 1s when invoked, and on the 5th invocation send us a SIGUSR1 +# 6. once we got that we finish cleanly + +sigusr1=0 +trap sigusr1=1 SIGUSR1 + +trap -p SIGUSR1 + +systemctl start TEST-23-UNIT-FILE-success.service + +while [ "$sigusr1" -eq 0 ] ; do + sleep .5 +done + +systemctl stop TEST-23-UNIT-FILE-uphold.service + +systemctl enable TEST-23-UNIT-FILE-upheldby-install.service + +# Idea is this: +# 1. we start TEST-23-UNIT-FILE-retry-uphold.service +# 2. which through Uphold= starts TEST-23-UNIT-FILE-retry-upheld.service +# 3. which through Requires= starts TEST-23-UNIT-FILE-retry-fail.service +# 4. which fails as /tmp/TEST-23-UNIT-FILE-retry-fail does not exist, so TEST-23-UNIT-FILE-retry-upheld.service +# is no longer restarted +# 5. we create /tmp/TEST-23-UNIT-FILE-retry-fail +# 6. now TEST-23-UNIT-FILE-retry-upheld.service will be restarted since upheld, and its dependency will +# be satisfied + +rm -f /tmp/TEST-23-UNIT-FILE-retry-fail +systemctl start TEST-23-UNIT-FILE-retry-uphold.service +systemctl is-active TEST-23-UNIT-FILE-upheldby-install.service + +until systemctl is-failed TEST-23-UNIT-FILE-retry-fail.service ; do + sleep .5 +done + +(! systemctl is-active TEST-23-UNIT-FILE-retry-upheld.service) + +touch /tmp/TEST-23-UNIT-FILE-retry-fail + +until systemctl is-active TEST-23-UNIT-FILE-retry-upheld.service ; do + sleep .5 +done + +systemctl stop TEST-23-UNIT-FILE-retry-uphold.service TEST-23-UNIT-FILE-retry-fail.service TEST-23-UNIT-FILE-retry-upheld.service + +# Idea is this: +# 1. we start TEST-23-UNIT-FILE-prop-stop-one.service +# 2. which through Wants=/After= pulls in TEST-23-UNIT-FILE-prop-stop-two.service as well +# 3. TEST-23-UNIT-FILE-prop-stop-one.service then sleeps indefinitely +# 4. TEST-23-UNIT-FILE-prop-stop-two.service sleeps a short time and exits +# 5. the StopPropagatedFrom= dependency between the two should ensure *both* will exit as result +# 6. an ExecStopPost= line on TEST-23-UNIT-FILE-prop-stop-one.service will send us a SIGUSR2 +# 7. once we got that we finish cleanly + +sigusr2=0 +trap sigusr2=1 SIGUSR2 + +systemctl start TEST-23-UNIT-FILE-prop-stop-one.service + +while [ "$sigusr2" -eq 0 ] ; do + sleep .5 +done + + +# Idea is this: +# 1. we start TEST-23-UNIT-FILE-binds-to.service +# 2. which through BindsTo=/After= pulls in TEST-23-UNIT-FILE-bound-by.service as well +# 3. TEST-23-UNIT-FILE-bound-by.service suddenly dies +# 4. TEST-23-UNIT-FILE-binds-to.service should then also be pulled down (it otherwise just hangs) +# 6. an ExecStopPost= line on TEST-23-UNIT-FILE-binds-to.service will send us a SIGRTMIN1+1 +# 7. once we got that we finish cleanly + +sigrtmin1=0 +trap sigrtmin1=1 SIGRTMIN+1 + +systemctl start TEST-23-UNIT-FILE-binds-to.service + +while [ "$sigrtmin1" -eq 0 ] ; do + sleep .5 +done + +systemd-analyze log-level info diff --git a/test/units/testsuite-23.clean-unit.sh b/test/units/TEST-23-UNIT-FILE.clean-unit.sh index a82b54f..a883243 100755 --- a/test/units/testsuite-23.clean-unit.sh +++ b/test/units/TEST-23-UNIT-FILE.clean-unit.sh @@ -26,7 +26,7 @@ StateDirectory=test-service CacheDirectory=test-service LogsDirectory=test-service RuntimeDirectoryPreserve=yes -ExecStart=/bin/sleep infinity +ExecStart=sleep infinity Type=exec EOF @@ -97,7 +97,7 @@ StateDirectory=test-service CacheDirectory=test-service LogsDirectory=test-service RuntimeDirectoryPreserve=yes -ExecStart=/bin/sleep infinity +ExecStart=sleep infinity Type=exec EOF diff --git a/test/units/testsuite-23.exec-command-ex.sh b/test/units/TEST-23-UNIT-FILE.exec-command-ex.sh index f926e7d..f926e7d 100755 --- a/test/units/testsuite-23.exec-command-ex.sh +++ b/test/units/TEST-23-UNIT-FILE.exec-command-ex.sh diff --git a/test/units/TEST-23-UNIT-FILE.oneshot-restart.sh b/test/units/TEST-23-UNIT-FILE.oneshot-restart.sh new file mode 100755 index 0000000..d06dbaa --- /dev/null +++ b/test/units/TEST-23-UNIT-FILE.oneshot-restart.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +# Test oneshot unit restart on failure + +# wait this many secs for each test service to succeed in what is being tested +MAX_SECS=60 + +systemctl log-level debug + +# test one: Restart=on-failure should restart the service +(! systemd-run --unit=oneshot-restart-one -p Type=oneshot -p Restart=on-failure /bin/bash -c "exit 1") + +for ((secs = 0; secs < MAX_SECS; secs++)); do + [[ "$(systemctl show oneshot-restart-one.service -P NRestarts)" -le 0 ]] || break + sleep 1 +done +if [[ "$(systemctl show oneshot-restart-one.service -P NRestarts)" -le 0 ]]; then + exit 1 +fi + +TMP_FILE="/tmp/test-23-oneshot-restart-test$RANDOM" + +: >$TMP_FILE + +# test two: make sure StartLimitBurst correctly limits the number of restarts +# and restarts execution of the unit from the first ExecStart= +(! systemd-run --unit=oneshot-restart-two \ + -p StartLimitIntervalSec=120 \ + -p StartLimitBurst=3 \ + -p Type=oneshot \ + -p Restart=on-failure \ + -p ExecStart="/bin/bash -c 'printf a >>$TMP_FILE'" /bin/bash -c "exit 1") + +# wait for at least 3 restarts +for ((secs = 0; secs < MAX_SECS; secs++)); do + [[ $(cat $TMP_FILE) != "aaa" ]] || break + sleep 1 +done +if [[ $(cat $TMP_FILE) != "aaa" ]]; then + exit 1 +fi + +# wait for 5 more seconds to make sure there aren't excess restarts +sleep 5 +if [[ $(cat $TMP_FILE) != "aaa" ]]; then + exit 1 +fi +rm "$TMP_FILE" + +# Test RestartForceExitStatus=. Note that success exit statuses are meant to be skipped + +TMP_FILE="/tmp/test-23-oneshot-restart-test$RANDOM" +UNIT_NAME="TEST-23-UNIT-FILE-oneshot-restartforce.service" +ONSUCCESS_UNIT_NAME="TEST-23-UNIT-FILE-oneshot-restartforce-onsuccess.service" +FIFO_FILE="/tmp/test-23-oneshot-restart-test-fifo" + +cat >"/run/systemd/system/$UNIT_NAME" <<EOF +[Unit] +OnSuccess=$ONSUCCESS_UNIT_NAME + +[Service] +Type=oneshot +RestartForceExitStatus=0 2 +ExecStart=/usr/lib/systemd/tests/testdata/TEST-23-UNIT-FILE.units/TEST-23-UNIT-FILE-oneshot-restartforce.sh "$TMP_FILE" + +[Install] +WantedBy=multi-user.target +EOF + +cat >"/run/systemd/system/$ONSUCCESS_UNIT_NAME" <<EOF +[Service] +Type=oneshot +ExecStart=bash -c 'echo finished >$FIFO_FILE' +EOF + +mkfifo "$FIFO_FILE" + +# Pin the unit in memory +systemctl enable "$UNIT_NAME" +# Initial run should fail +(! systemctl start "$UNIT_NAME") +# Wait for OnSuccess= +read -r x <"$FIFO_FILE" +assert_eq "$x" "finished" + +cmp -b <(systemctl show "$UNIT_NAME" -p Result -p NRestarts -p SubState) <<EOF +Result=success +NRestarts=1 +SubState=dead +EOF + +systemctl disable "$UNIT_NAME" +rm "$TMP_FILE" /run/systemd/system/{"$UNIT_NAME","$ONSUCCESS_UNIT_NAME"} "$FIFO_FILE" + +systemctl log-level info diff --git a/test/units/TEST-23-UNIT-FILE.openfile.sh b/test/units/TEST-23-UNIT-FILE.openfile.sh new file mode 100755 index 0000000..644b6f4 --- /dev/null +++ b/test/units/TEST-23-UNIT-FILE.openfile.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +at_exit() { + set +e + + rm -rf /tmp/test-open-file/ +} + +trap at_exit EXIT + +systemctl log-level debug + +# Existing files + +mkdir /tmp/test-open-file +echo "Open" >'/tmp/test-open-file/open.txt' +echo "File" >'/tmp/test-open-file/file:colon.txt' + +systemd-run -p DynamicUser=yes -p EnvironmentFile=-/usr/lib/systemd/systemd-asan-env \ + -p OpenFile='/tmp/test-open-file/open.txt::read-only' \ + -p OpenFile='/tmp/test-open-file/file\x3Acolon.txt:colon' \ + -p RemainAfterExit=yes \ + --unit=test-23-openfile-existing.service \ + --service-type=oneshot \ + /usr/lib/systemd/tests/testdata/units/TEST-23-UNIT-FILE-openfile-child.sh 2 "open.txt:colon" "Open" "File" + +cmp <(systemctl show -p OpenFile test-23-openfile-existing.service) <<EOF +OpenFile=/tmp/test-open-file/open.txt::read-only +OpenFile=/tmp/test-open-file/file\\x3acolon.txt:colon +EOF + +systemctl stop test-23-openfile-existing.service + +# Sockets + +systemctl start TEST-23-UNIT-FILE-openfile-server.socket + +systemd-run -p OpenFile=/tmp/test.sock:socket:read-only \ + --wait \ + /usr/lib/systemd/tests/testdata/units/TEST-23-UNIT-FILE-openfile-child.sh 1 "socket" "Socket" + +systemctl stop TEST-23-UNIT-FILE-openfile-server.socket + +# Ignore when missing + +assert_rc 202 systemd-run -p OpenFile=/run/missing/foo:missing-file:read-only --wait true +assert_rc 0 systemd-run -p OpenFile=/run/missing/foo:missing-file:read-only,graceful --wait true + +systemctl log-level info diff --git a/test/units/testsuite-23.percentj-wantedby.sh b/test/units/TEST-23-UNIT-FILE.percentj-wantedby.sh index e9ffaba..c091bd6 100755 --- a/test/units/testsuite-23.percentj-wantedby.sh +++ b/test/units/TEST-23-UNIT-FILE.percentj-wantedby.sh @@ -8,8 +8,8 @@ set -o pipefail # Ensure %j Wants directives work systemd-run --wait \ --property="Type=oneshot" \ - --property="Wants=testsuite-23-specifier-j-wants.service" \ - --property="After=testsuite-23-specifier-j-wants.service" \ + --property="Wants=TEST-23-UNIT-FILE-specifier-j-wants.service" \ + --property="After=TEST-23-UNIT-FILE-specifier-j-wants.service" \ true test -f /tmp/tetsuite-23-specifier-j-done diff --git a/test/units/TEST-23-UNIT-FILE.runtime-bind-paths.sh b/test/units/TEST-23-UNIT-FILE.runtime-bind-paths.sh new file mode 100755 index 0000000..3a78234 --- /dev/null +++ b/test/units/TEST-23-UNIT-FILE.runtime-bind-paths.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2016 +set -eux +set -o pipefail + +# Test adding new BindPaths while unit is already running + +at_exit() { + set +e + + rm -f /run/TEST-23-UNIT-FILE-marker-{fixed,runtime} + rm -fr /run/inaccessible +} + +trap at_exit EXIT + +echo "MARKER_FIXED" >/run/TEST-23-UNIT-FILE-marker-fixed +mkdir /run/inaccessible + +systemctl start TEST-23-UNIT-FILE-namespaced.service + +# Ensure that inaccessible paths aren't bypassed by the runtime setup, +(! systemctl bind --mkdir TEST-23-UNIT-FILE-namespaced.service /run/TEST-23-UNIT-FILE-marker-fixed /run/inaccessible/testfile-marker-fixed) + +echo "MARKER_WRONG" >/run/TEST-23-UNIT-FILE-marker-wrong +echo "MARKER_RUNTIME" >/run/TEST-23-UNIT-FILE-marker-runtime + +# Mount twice to exercise mount-beneath (on kernel 6.5+, on older kernels it will just overmount) +systemctl bind --mkdir TEST-23-UNIT-FILE-namespaced.service /run/TEST-23-UNIT-FILE-marker-wrong /tmp/testfile-marker-runtime +test "$(systemctl show -P SubState TEST-23-UNIT-FILE-namespaced.service)" = "running" +systemctl bind --mkdir TEST-23-UNIT-FILE-namespaced.service /run/TEST-23-UNIT-FILE-marker-runtime /tmp/testfile-marker-runtime + +timeout 10 bash -xec 'while [[ "$(systemctl show -P SubState TEST-23-UNIT-FILE-namespaced.service)" == running ]]; do sleep .5; done' +systemctl is-active TEST-23-UNIT-FILE-namespaced.service + +# Now test that systemctl bind fails when attempted on a non-namespaced unit +systemctl start TEST-23-UNIT-FILE-non-namespaced.service + +(! systemctl bind --mkdir TEST-23-UNIT-FILE-non-namespaced.service /run/TEST-23-UNIT-FILE-marker-runtime /tmp/testfile-marker-runtime) + +timeout 10 bash -xec 'while [[ "$(systemctl show -P SubState TEST-23-UNIT-FILE-non-namespaced.service)" == running ]]; do sleep .5; done' +(! systemctl is-active TEST-23-UNIT-FILE-non-namespaced.service) diff --git a/test/units/testsuite-23.sh b/test/units/TEST-23-UNIT-FILE.sh index a929c8b..a929c8b 100755 --- a/test/units/testsuite-23.sh +++ b/test/units/TEST-23-UNIT-FILE.sh diff --git a/test/units/TEST-23-UNIT-FILE.start-stop-no-reload.sh b/test/units/TEST-23-UNIT-FILE.start-stop-no-reload.sh new file mode 100755 index 0000000..61a6592 --- /dev/null +++ b/test/units/TEST-23-UNIT-FILE.start-stop-no-reload.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +set -eux +set -o pipefail + +# Test start & stop operations without daemon-reload + +at_exit() { + set +e + + rm -f /run/systemd/system/TEST-23-UNIT-FILE-no-reload.{service,target} +} + +trap at_exit EXIT + +cat >/run/systemd/system/TEST-23-UNIT-FILE-no-reload.target <<EOF +[Unit] +Wants=TEST-23-UNIT-FILE-no-reload.service +EOF + +systemctl daemon-reload + +systemctl start TEST-23-UNIT-FILE-no-reload.target + +# The filesystem on the test image, despite being ext4, seems to have a mtime +# granularity of one second, which means the manager's unit cache won't be +# marked as dirty when writing the unit file, unless we wait at least a full +# second after the previous daemon-reload. +# May 07 23:12:20 H TEST-23-UNIT-FILE.sh[30]: + cat +# May 07 23:12:20 H TEST-23-UNIT-FILE.sh[30]: + ls -l --full-time /etc/systemd/system/TEST-23-UNIT-FILE-no-reload.service +# May 07 23:12:20 H TEST-23-UNIT-FILE.sh[52]: -rw-r--r-- 1 root root 50 2020-05-07 23:12:20.000000000 +0100 / +# May 07 23:12:20 H TEST-23-UNIT-FILE.sh[30]: + stat -f --format=%t /etc/systemd/system/TEST-23-UNIT-FILE-no-reload.servic +# May 07 23:12:20 H TEST-23-UNIT-FILE.sh[53]: ef53 +sleep 3.1 + +cat >/run/systemd/system/TEST-23-UNIT-FILE-no-reload.service <<EOF +[Service] +ExecStart=sleep infinity +EOF + +systemctl start TEST-23-UNIT-FILE-no-reload.service + +systemctl is-active TEST-23-UNIT-FILE-no-reload.service + +# Stop and remove, and try again to exercise https://github.com/systemd/systemd/issues/15992 +systemctl stop TEST-23-UNIT-FILE-no-reload.service +rm -f /run/systemd/system/TEST-23-UNIT-FILE-no-reload.service +systemctl daemon-reload + +sleep 3.1 + +cat >/run/systemd/system/TEST-23-UNIT-FILE-no-reload.service <<EOF +[Service] +ExecStart=sleep infinity +EOF + +# Start a non-existing unit first, so that the cache is reloaded for an unrelated +# reason. Starting the existing unit later should still work thanks to the check +# for the last load attempt vs cache timestamp. +systemctl start TEST-23-UNIT-FILE-no-reload-nonexistent.service || true + +systemctl start TEST-23-UNIT-FILE-no-reload.service + +systemctl is-active TEST-23-UNIT-FILE-no-reload.service + +# Stop and remove, and try again to exercise the transaction setup code path by +# having the target pull in the unloaded but available unit +systemctl stop TEST-23-UNIT-FILE-no-reload.service TEST-23-UNIT-FILE-no-reload.target +rm -f /run/systemd/system/TEST-23-UNIT-FILE-no-reload.service /run/systemd/system/TEST-23-UNIT-FILE-no-reload.target +systemctl daemon-reload + +sleep 3.1 + +cat >/run/systemd/system/TEST-23-UNIT-FILE-no-reload.target <<EOF +[Unit] +Conflicts=shutdown.target +Wants=TEST-23-UNIT-FILE-no-reload.service +EOF + +systemctl daemon-reload + +systemctl start TEST-23-UNIT-FILE-no-reload.target + +cat >/run/systemd/system/TEST-23-UNIT-FILE-no-reload.service <<EOF +[Service] +ExecStart=sleep infinity +EOF + +systemctl restart TEST-23-UNIT-FILE-no-reload.target + +systemctl is-active TEST-23-UNIT-FILE-no-reload.service diff --git a/test/units/testsuite-23.statedir.sh b/test/units/TEST-23-UNIT-FILE.statedir.sh index b592314..b592314 100755 --- a/test/units/testsuite-23.statedir.sh +++ b/test/units/TEST-23-UNIT-FILE.statedir.sh diff --git a/test/units/testsuite-23.success-failure.sh b/test/units/TEST-23-UNIT-FILE.success-failure.sh index 8fc9596..8fc9596 100755 --- a/test/units/testsuite-23.success-failure.sh +++ b/test/units/TEST-23-UNIT-FILE.success-failure.sh diff --git a/test/units/testsuite-23.type-exec.sh b/test/units/TEST-23-UNIT-FILE.type-exec.sh index 87f32cc..87f32cc 100755 --- a/test/units/testsuite-23.type-exec.sh +++ b/test/units/TEST-23-UNIT-FILE.type-exec.sh diff --git a/test/units/testsuite-23.utmp.sh b/test/units/TEST-23-UNIT-FILE.utmp.sh index 4f84315..4f84315 100755 --- a/test/units/testsuite-23.utmp.sh +++ b/test/units/TEST-23-UNIT-FILE.utmp.sh diff --git a/test/units/TEST-23-UNIT-FILE.verify-unit-files.sh b/test/units/TEST-23-UNIT-FILE.verify-unit-files.sh new file mode 100755 index 0000000..3e83d44 --- /dev/null +++ b/test/units/TEST-23-UNIT-FILE.verify-unit-files.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2016 +set -eux +set -o pipefail + +# Verify our own unit files (where applicable) + +# This is generated by meson during build +UNIT_FILE_LIST="/usr/lib/systemd/tests/testdata/installed-unit-files.txt" + +if [[ ! -f "$UNIT_FILE_LIST" ]]; then + echo "Couldn't find the list of installed units, skipping the test" + exit 0 +fi + +if ! command -v systemd-analyze >/dev/null; then + echo "Built without systemd-analyze, skipping the test" + exit 0 +fi + +mapfile -t UNIT_FILES <"$UNIT_FILE_LIST" + +if [[ "${#UNIT_FILES[@]}" -le 0 ]]; then + echo >&2 "The unit file list is empty, this is most likely a bug" + exit 1 +fi + +for unit_file in "${UNIT_FILES[@]}"; do + # Skip the check for a couple of units, namely: + # - syslog.socket: the corresponding syslog.service might not be installed + # - rc-local.service: compat API, /etc/rc.d/rc.local most likely won't be present + if [[ "$unit_file" =~ /(syslog.socket|rc-local.service)$ ]]; then + continue + fi + + # Skip missing unit files - this is useful for $NO_BUILD runs, where certain unit files might be dropped + # in distro packaging + if [[ ! -e "$unit_file" ]]; then + echo "$unit_file not found, skipping" + continue + fi + + systemd-analyze --recursive-errors=no --man=no verify "$unit_file" +done diff --git a/test/units/testsuite-23.whoami.sh b/test/units/TEST-23-UNIT-FILE.whoami.sh index a0c73b8..b538d94 100755 --- a/test/units/testsuite-23.whoami.sh +++ b/test/units/TEST-23-UNIT-FILE.whoami.sh @@ -5,11 +5,11 @@ set -eux set -o pipefail -test "$(systemctl whoami)" = testsuite-23.service -test "$(systemctl whoami $$)" = testsuite-23.service +test "$(systemctl whoami)" = TEST-23-UNIT-FILE.service +test "$(systemctl whoami $$)" = TEST-23-UNIT-FILE.service systemctl whoami 1 $$ 1 | cmp - /dev/fd/3 3<<'EOF' init.scope -testsuite-23.service +TEST-23-UNIT-FILE.service init.scope EOF diff --git a/test/units/testsuite-24.sh b/test/units/TEST-24-CRYPTSETUP.sh index c815f90..b788c82 100755 --- a/test/units/testsuite-24.sh +++ b/test/units/TEST-24-CRYPTSETUP.sh @@ -5,8 +5,6 @@ set -o pipefail # TODO: # - /proc/cmdline parsing -# - figure out token support (apart from TPM2, as that's covered by TEST-70-TPM2) -# - this might help https://www.qemu.org/docs/master/system/devices/ccid.html # - expect + interactive auth? # We set up an encrypted /var partition which should get mounted automatically @@ -35,6 +33,7 @@ trap at_exit EXIT cryptsetup_start_and_check() { local expect_fail=0 + local umount_header_and_key=0 local ec volume unit if [[ "${1:?}" == "-f" ]]; then @@ -42,6 +41,11 @@ cryptsetup_start_and_check() { shift fi + if [[ "${1:?}" == "-u" ]]; then + umount_header_and_key=1 + shift + fi + for volume in "$@"; do unit="systemd-cryptsetup@$volume.service" @@ -64,6 +68,12 @@ cryptsetup_start_and_check() { return 1 fi + if [[ "$umount_header_and_key" -ne 0 ]]; then + umount "$TMPFS_DETACHED_KEYFILE" + umount "$TMPFS_DETACHED_HEADER" + udevadm settle --timeout=60 + fi + systemctl status "$unit" test -e "/dev/mapper/$volume" systemctl stop "$unit" @@ -133,22 +143,31 @@ cryptsetup luksAddKey --batch-mode \ STORE_IMAGE="$WORKDIR/store.img" truncate -s 64M "$STORE_IMAGE" STORE_LOOP="$(losetup --show --find --partscan "$STORE_IMAGE")" -sfdisk "$STORE_LOOP" <<EOF +udevadm lock --device "$STORE_LOOP" sfdisk "$STORE_LOOP" <<EOF label: gpt type=0FC63DAF-8483-4772-8E79-3D69D8477DE4 name=header_store size=32M type=0FC63DAF-8483-4772-8E79-3D69D8477DE4 name=keyfile_store EOF -udevadm settle --timeout=30 +udevadm settle --timeout=60 mkdir -p /mnt -mkfs.ext4 -L header_store "/dev/disk/by-partlabel/header_store" +udevadm lock --device "/dev/disk/by-partlabel/header_store" mkfs.ext4 -L header_store "/dev/disk/by-partlabel/header_store" mount "/dev/disk/by-partlabel/header_store" /mnt cp "$IMAGE_DETACHED_HEADER" /mnt/header umount /mnt -mkfs.ext4 -L keyfile_store "/dev/disk/by-partlabel/keyfile_store" +udevadm lock --device "/dev/disk/by-partlabel/keyfile_store" mkfs.ext4 -L keyfile_store "/dev/disk/by-partlabel/keyfile_store" mount "/dev/disk/by-partlabel/keyfile_store" /mnt cp "$IMAGE_DETACHED_KEYFILE2" /mnt/keyfile umount /mnt -udevadm settle --timeout=30 + +# Also copy the key and header on a tmpfs that we will umount after unlocking +TMPFS_DETACHED_KEYFILE="$(mktemp -d)" +TMPFS_DETACHED_HEADER="$(mktemp -d)" +mount -t tmpfs -o size=32M tmpfs "$TMPFS_DETACHED_KEYFILE" +mount -t tmpfs -o size=32M tmpfs "$TMPFS_DETACHED_HEADER" +cp "$IMAGE_DETACHED_KEYFILE" "$TMPFS_DETACHED_KEYFILE/keyfile" +cp "$IMAGE_DETACHED_HEADER" "$TMPFS_DETACHED_HEADER/header" + +udevadm settle --timeout=60 # Prepare our test crypttab [[ -e /etc/crypttab ]] && cp -fv /etc/crypttab /tmp/crypttab.bak @@ -164,6 +183,7 @@ empty0 $IMAGE_EMPTY - headless=1, empty1 $IMAGE_EMPTY - headless=1,try-empty-password=1 # This one expects the key to be under /{etc,run}/cryptsetup-keys.d/empty_nokey.key empty_nokey $IMAGE_EMPTY - headless=1 +empty_pkcs11_auto $IMAGE_EMPTY - headless=1,pkcs11-uri=auto detached $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE headless=1,header=$IMAGE_DETACHED_HEADER,keyfile-offset=32,keyfile-size=16 detached_store0 $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE headless=1,header=/header:LABEL=header_store,keyfile-offset=32,keyfile-size=16 @@ -177,6 +197,7 @@ detached_fail4 $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE headless=1, detached_slot0 $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE2 headless=1,header=$IMAGE_DETACHED_HEADER detached_slot1 $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE2 headless=1,header=$IMAGE_DETACHED_HEADER,key-slot=8 detached_slot_fail $IMAGE_DETACHED $IMAGE_DETACHED_KEYFILE2 headless=1,header=$IMAGE_DETACHED_HEADER,key-slot=0 +detached_nofail $IMAGE_DETACHED $TMPFS_DETACHED_KEYFILE/keyfile headless=1,header=$TMPFS_DETACHED_HEADER/header,keyfile-offset=32,keyfile-size=16,nofail EOF # Temporarily drop luks.name=/luks.uuid= from the kernel command line, as it makes @@ -207,10 +228,46 @@ mkdir -p /run/cryptsetup-keys.d cp "$IMAGE_EMPTY_KEYFILE" /run/cryptsetup-keys.d/empty_nokey.key cryptsetup_start_and_check empty_nokey +if [[ -d /usr/lib/softhsm/tokens ]]; then + # Test unlocking with a PKCS#11 token + export SOFTHSM2_CONF="/etc/softhsm2.conf" + + PIN="1234" systemd-cryptenroll --pkcs11-token-uri="pkcs11:token=TestToken;object=RSATestKey" --unlock-key-file="$IMAGE_EMPTY_KEYFILE" "$IMAGE_EMPTY" + cryptsetup_start_and_check empty_pkcs11_auto + cryptsetup luksKillSlot -q "$IMAGE_EMPTY" 2 + cryptsetup token remove --token-id 0 "$IMAGE_EMPTY" + + PIN="1234" systemd-cryptenroll --pkcs11-token-uri="pkcs11:token=TestToken;object=RSATestKey;type=cert" --unlock-key-file="$IMAGE_EMPTY_KEYFILE" "$IMAGE_EMPTY" + cryptsetup_start_and_check empty_pkcs11_auto + cryptsetup luksKillSlot -q "$IMAGE_EMPTY" 2 + cryptsetup token remove --token-id 0 "$IMAGE_EMPTY" + + PIN="1234" systemd-cryptenroll --pkcs11-token-uri="pkcs11:token=TestToken;object=RSATestKey;type=public" --unlock-key-file="$IMAGE_EMPTY_KEYFILE" "$IMAGE_EMPTY" + cryptsetup_start_and_check empty_pkcs11_auto + cryptsetup luksKillSlot -q "$IMAGE_EMPTY" 2 + cryptsetup token remove --token-id 0 "$IMAGE_EMPTY" + + PIN="1234" systemd-cryptenroll --pkcs11-token-uri="pkcs11:token=TestToken;object=ECTestKey" --unlock-key-file="$IMAGE_EMPTY_KEYFILE" "$IMAGE_EMPTY" + cryptsetup_start_and_check empty_pkcs11_auto + cryptsetup luksKillSlot -q "$IMAGE_EMPTY" 2 + cryptsetup token remove --token-id 0 "$IMAGE_EMPTY" + + PIN="1234" systemd-cryptenroll --pkcs11-token-uri="pkcs11:token=TestToken;object=ECTestKey;type=cert" --unlock-key-file="$IMAGE_EMPTY_KEYFILE" "$IMAGE_EMPTY" + cryptsetup_start_and_check empty_pkcs11_auto + cryptsetup luksKillSlot -q "$IMAGE_EMPTY" 2 + cryptsetup token remove --token-id 0 "$IMAGE_EMPTY" + + PIN="1234" systemd-cryptenroll --pkcs11-token-uri="pkcs11:token=TestToken;object=ECTestKey;type=public" --unlock-key-file="$IMAGE_EMPTY_KEYFILE" "$IMAGE_EMPTY" + cryptsetup_start_and_check empty_pkcs11_auto + cryptsetup luksKillSlot -q "$IMAGE_EMPTY" 2 + cryptsetup token remove --token-id 0 "$IMAGE_EMPTY" +fi + cryptsetup_start_and_check detached cryptsetup_start_and_check detached_store{0..2} cryptsetup_start_and_check -f detached_fail{0..4} cryptsetup_start_and_check detached_slot{0..1} cryptsetup_start_and_check -f detached_slot_fail +cryptsetup_start_and_check -u detached_nofail touch /testok diff --git a/test/units/testsuite-25.sh b/test/units/TEST-25-IMPORT.sh index b298c50..b298c50 100755 --- a/test/units/testsuite-25.sh +++ b/test/units/TEST-25-IMPORT.sh diff --git a/test/units/testsuite-26.sh b/test/units/TEST-26-SYSTEMCTL.sh index 1e11c42..ae7a5d6 100755 --- a/test/units/testsuite-26.sh +++ b/test/units/TEST-26-SYSTEMCTL.sh @@ -16,12 +16,12 @@ at_exit() { return 0 } -trap at_exit EXIT - # Create a simple unit file for testing # Note: the service file is created under /usr on purpose to test # the 'revert' verb as well export UNIT_NAME="systemctl-test-$RANDOM.service" +export UNIT_NAME2="systemctl-test-$RANDOM.service" + cat >"/usr/lib/systemd/system/$UNIT_NAME" <<\EOF [Unit] Description=systemctl test @@ -56,6 +56,20 @@ printf '%b' '[Service]\n' 'ExecStart=\n' 'ExecStart=sleep 10d' >"+4" EDITOR='mv' script -ec 'systemctl edit "$UNIT_NAME"' /dev/null printf '%s\n' '[Service]' 'ExecStart=' 'ExecStart=sleep 10d' | cmp - "/etc/systemd/system/$UNIT_NAME.d/override.conf" +systemctl edit "$UNIT_NAME" --stdin --drop-in=override2.conf <<EOF +[Unit] +Description=spectacular +# this comment should remain + +EOF +printf '%s\n' '[Unit]' 'Description=spectacular' '# this comment should remain' | \ + cmp - "/etc/systemd/system/$UNIT_NAME.d/override2.conf" + +# Test simultaneous editing of two units and creation of drop-in for a nonexistent unit +systemctl edit "$UNIT_NAME" "$UNIT_NAME2" --stdin --force --drop-in=override2.conf <<<'[X-Section]' +printf '%s\n' '[X-Section]' | cmp - "/etc/systemd/system/$UNIT_NAME.d/override2.conf" +printf '%s\n' '[X-Section]' | cmp - "/etc/systemd/system/$UNIT_NAME2.d/override2.conf" + # Double free when editing a template unit (#26483) EDITOR='true' script -ec 'systemctl edit user@0' /dev/null @@ -127,7 +141,7 @@ systemctl reload -T "$UNIT_NAME" systemctl restart -T "$UNIT_NAME" systemctl try-restart --show-transaction "$UNIT_NAME" systemctl try-reload-or-restart --show-transaction "$UNIT_NAME" -systemctl kill "$UNIT_NAME" +timeout 10 systemctl kill --wait "$UNIT_NAME" (! systemctl is-active "$UNIT_NAME") systemctl restart "$UNIT_NAME" systemctl is-active "$UNIT_NAME" @@ -188,6 +202,24 @@ test_mask_unmask_revert() { test_mask_unmask_revert test_mask_unmask_revert --root=/ +# disable --now with template unit +cat >/run/systemd/system/test-disable@.service <<EOF +[Service] +ExecStart=sleep infinity + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable --now test-disable@1.service test-disable@2.service +systemctl is-active test-disable@1.service +systemctl is-active test-disable@2.service +systemctl disable --now test-disable@.service +for u in test-disable@{1,2}.service; do + (! systemctl is-active "$u") + (! systemctl is-enabled "$u") +done +rm /run/systemd/system/test-disable@.service + # add-wants/add-requires (! systemctl show -P Wants "$UNIT_NAME" | grep "systemd-journald.service") systemctl add-wants "$UNIT_NAME" "systemd-journald.service" @@ -209,7 +241,7 @@ systemctl revert "$UNIT_NAME" systemctl set-property --runtime "$UNIT_NAME" CPUAccounting=no CPUQuota=10% systemctl cat "$UNIT_NAME" grep -r "CPUAccounting=no" "/run/systemd/system.control/${UNIT_NAME}.d/" -grep -r "CPUQuota=10%" "/run/systemd/system.control/${UNIT_NAME}.d/" +grep -r "CPUQuota=10.00%" "/run/systemd/system.control/${UNIT_NAME}.d/" systemctl revert "$UNIT_NAME" (! grep -r "CPUAccounting=" "/run/systemd/system.control/${UNIT_NAME}.d/") (! grep -r "CPUQuota=" "/run/systemd/system.control/${UNIT_NAME}.d/") @@ -306,7 +338,7 @@ done # Aux verbs & assorted checks systemctl is-active "*-journald.service" -systemctl cat "*journal*" +systemctl cat "*udevd*" systemctl cat "$UNIT_NAME" systemctl help "$UNIT_NAME" systemctl service-watchdogs @@ -348,6 +380,10 @@ if [[ -x /usr/lib/systemd/system-generators/systemd-sysv-generator ]]; then # at runtime, so let's just support the two most common paths for now. [[ -d /etc/rc.d/init.d ]] && SYSVINIT_PATH="/etc/rc.d/init.d" || SYSVINIT_PATH="/etc/init.d" + # OpenSUSE leaves sysvinit-path enabled, which means systemd-sysv-generator is built + # but may not create the directory if there's no services that use it. + mkdir -p "$SYSVINIT_PATH" + # invalid dependency cat >"${SYSVINIT_PATH:?}/issue-24990" <<\EOF #!/bin/bash diff --git a/test/units/testsuite-29.sh b/test/units/TEST-29-PORTABLE.sh index 676330c..27c24a0 100755 --- a/test/units/testsuite-29.sh +++ b/test/units/TEST-29-PORTABLE.sh @@ -5,6 +5,11 @@ set -eux set -o pipefail +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +install_extension_images + # Set longer timeout for slower machines, e.g. non-KVM vm. mkdir -p /run/systemd/system.conf.d cat >/run/systemd/system.conf.d/10-timeout.conf <<EOF @@ -31,9 +36,9 @@ fi systemd-dissect --no-pager /usr/share/minimal_0.raw | grep -q '✓ portable service' systemd-dissect --no-pager /usr/share/minimal_1.raw | grep -q '✓ portable service' -systemd-dissect --no-pager /usr/share/app0.raw | grep -q '✓ sysext for portable service' -systemd-dissect --no-pager /usr/share/app1.raw | grep -q '✓ sysext for portable service' -systemd-dissect --no-pager /usr/share/conf0.raw | grep -q '✓ confext for portable service' +systemd-dissect --no-pager /tmp/app0.raw | grep -q '✓ sysext for portable service' +systemd-dissect --no-pager /tmp/app1.raw | grep -q '✓ sysext for portable service' +systemd-dissect --no-pager /tmp/conf0.raw | grep -q '✓ confext for portable service' export SYSTEMD_LOG_LEVEL=debug mkdir -p /run/systemd/system/systemd-portabled.service.d/ @@ -117,7 +122,7 @@ portablectl detach --now --enable --runtime /tmp/minimal_1 minimal-app0 portablectl list | grep -q -F "No images." busctl tree org.freedesktop.portable1 --no-pager | grep -q -F '/org/freedesktop/portable1/image/minimal_5f1' && exit 1 -portablectl "${ARGS[@]}" attach --now --runtime --extension /usr/share/app0.raw /usr/share/minimal_0.raw app0 +portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app0 systemctl is-active app0.service status="$(portablectl is-attached --extension app0 minimal_0)" @@ -127,7 +132,7 @@ grep -q -F "LogExtraFields=PORTABLE_ROOT=minimal_0.raw" /run/systemd/system.atta grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app0.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd/system.attached/app0.service.d/20-portable.conf -portablectl "${ARGS[@]}" reattach --now --runtime --extension /usr/share/app0.raw /usr/share/minimal_1.raw app0 +portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app0.raw /usr/share/minimal_1.raw app0 systemctl is-active app0.service status="$(portablectl is-attached --extension app0 minimal_1)" @@ -137,12 +142,12 @@ grep -q -F "LogExtraFields=PORTABLE_ROOT=minimal_1.raw" /run/systemd/system.atta grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app0.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd/system.attached/app0.service.d/20-portable.conf -portablectl detach --now --runtime --extension /usr/share/app0.raw /usr/share/minimal_1.raw app0 +portablectl detach --now --runtime --extension /tmp/app0.raw /usr/share/minimal_1.raw app0 # Ensure versioned images are accepted without needing to use --force to override the extension-release # matching -cp /usr/share/app0.raw /tmp/app0_1.0.raw +cp /tmp/app0.raw /tmp/app0_1.0.raw portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app0_1.0.raw /usr/share/minimal_0.raw app0 systemctl is-active app0.service @@ -152,28 +157,28 @@ status="$(portablectl is-attached --extension app0_1 minimal_0)" portablectl detach --now --runtime --extension /tmp/app0_1.0.raw /usr/share/minimal_1.raw app0 rm -f /tmp/app0_1.0.raw -portablectl "${ARGS[@]}" attach --now --runtime --extension /usr/share/app1.raw /usr/share/minimal_0.raw app1 +portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app1 systemctl is-active app1.service status="$(portablectl is-attached --extension app1 minimal_0)" [[ "${status}" == "running-runtime" ]] # Ensure that adding or removing a version to the image doesn't break reattaching -cp /usr/share/app1.raw /tmp/app1_2.raw +cp /tmp/app1.raw /tmp/app1_2.raw portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app1_2.raw /usr/share/minimal_1.raw app1 systemctl is-active app1.service status="$(portablectl is-attached --extension app1_2 minimal_1)" [[ "${status}" == "running-runtime" ]] -portablectl "${ARGS[@]}" reattach --now --runtime --extension /usr/share/app1.raw /usr/share/minimal_1.raw app1 +portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app1.raw /usr/share/minimal_1.raw app1 systemctl is-active app1.service status="$(portablectl is-attached --extension app1 minimal_1)" [[ "${status}" == "running-runtime" ]] -portablectl detach --force --no-reload --runtime --extension /usr/share/app1.raw /usr/share/minimal_1.raw app1 -portablectl "${ARGS[@]}" attach --force --no-reload --runtime --extension /usr/share/app1.raw /usr/share/minimal_0.raw app1 +portablectl detach --force --no-reload --runtime --extension /tmp/app1.raw /usr/share/minimal_1.raw app1 +portablectl "${ARGS[@]}" attach --force --no-reload --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app1 systemctl daemon-reload systemctl restart app1.service @@ -181,7 +186,27 @@ systemctl is-active app1.service status="$(portablectl is-attached --extension app1 minimal_0)" [[ "${status}" == "running-runtime" ]] -portablectl detach --now --runtime --extension /usr/share/app1.raw /usr/share/minimal_0.raw app1 +portablectl detach --now --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app1 + +# Ensure vpick works, including reattaching to a new image +mkdir -p /tmp/app1.v/ +cp /tmp/app1.raw /tmp/app1.v/app1_1.0.raw +cp /tmp/app1_2.raw /tmp/app1.v/app1_2.0.raw +portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_1.raw app1 + +systemctl is-active app1.service +status="$(portablectl is-attached --extension app1_2.0.raw minimal_1)" +[[ "${status}" == "running-runtime" ]] + +rm -f /tmp/app1.v/app1_2.0.raw +portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_1.raw app1 + +systemctl is-active app1.service +status="$(portablectl is-attached --extension app1_1.0.raw minimal_1)" +[[ "${status}" == "running-runtime" ]] + +portablectl detach --now --runtime --extension /tmp/app1.v/ /usr/share/minimal_0.raw app1 +rm -f /tmp/app1.v/app1_1.0.raw # Ensure that the combination of read-only images, state directory and dynamic user works, and that # state is retained. Check after detaching, as on slow systems (eg: sanitizers) it might take a while @@ -190,7 +215,7 @@ grep -q -F bar "${STATE_DIRECTORY}/app0/foo" grep -q -F baz "${STATE_DIRECTORY}/app1/foo" # Ensure that we can override the check on extension-release.NAME -cp /usr/share/app0.raw /tmp/app10.raw +cp /tmp/app0.raw /tmp/app10.raw portablectl "${ARGS[@]}" attach --force --now --runtime --extension /tmp/app10.raw /usr/share/minimal_0.raw app0 systemctl is-active app0.service @@ -206,21 +231,59 @@ systemctl stop app0.service portablectl detach --force --runtime --extension /tmp/app10.raw /usr/share/minimal_0.raw app0 # portablectl also accepts confexts -portablectl "${ARGS[@]}" attach --now --runtime --extension /usr/share/app0.raw --extension /usr/share/conf0.raw /usr/share/minimal_0.raw app0 +portablectl "${ARGS[@]}" attach --now --runtime --extension /tmp/app0.raw --extension /tmp/conf0.raw /usr/share/minimal_0.raw app0 systemctl is-active app0.service -status="$(portablectl is-attached --extension /usr/share/app0.raw --extension /usr/share/conf0.raw /usr/share/minimal_0.raw)" +status="$(portablectl is-attached --extension /tmp/app0.raw --extension /tmp/conf0.raw /usr/share/minimal_0.raw)" [[ "${status}" == "running-runtime" ]] -portablectl inspect --force --cat --extension /usr/share/app0.raw --extension /usr/share/conf0.raw /usr/share/minimal_0.raw app0 | grep -q -F "Extension Release: /usr/share/conf0.raw" +portablectl inspect --force --cat --extension /tmp/app0.raw --extension /tmp/conf0.raw /usr/share/minimal_0.raw app0 | grep -q -F "Extension Release: /tmp/conf0.raw" + +portablectl detach --now --runtime --extension /tmp/app0.raw --extension /tmp/conf0.raw /usr/share/minimal_0.raw app0 + +# Ensure that mixed mode copies the images and units (client-owned) but symlinks the profile (OS owned) +portablectl "${ARGS[@]}" attach --copy=mixed --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app0 +test -f /run/portables/app0.raw +test -f /run/portables/minimal_0.raw +test -f /run/systemd/system.attached/app0.service +test -L /run/systemd/system.attached/app0.service.d/10-profile.conf +portablectl detach --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app0 + +# Ensure that when two portables share the same base image, removing one doesn't remove the other too + +portablectl "${ARGS[@]}" attach --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app0 +portablectl "${ARGS[@]}" attach --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app1 + +status="$(portablectl is-attached --extension app0 minimal_0)" +[[ "${status}" == "attached-runtime" ]] +status="$(portablectl is-attached --extension app1 minimal_0)" +[[ "${status}" == "attached-runtime" ]] + +(! portablectl detach --runtime /usr/share/minimal_0.raw app) + +status="$(portablectl is-attached --extension app0 minimal_0)" +[[ "${status}" == "attached-runtime" ]] +status="$(portablectl is-attached --extension app1 minimal_0)" +[[ "${status}" == "attached-runtime" ]] + +# Ensure 'portablectl list' shows the correct status for both images +portablectl list +portablectl list | grep -F "minimal_0" | grep -q -F "attached-runtime" +portablectl list | grep -F "app0" | grep -q -F "attached-runtime" +portablectl list | grep -F "app1" | grep -q -F "attached-runtime" + +portablectl detach --runtime --extension /tmp/app0.raw /usr/share/minimal_0.raw app + +status="$(portablectl is-attached --extension app1 minimal_0)" +[[ "${status}" == "attached-runtime" ]] -portablectl detach --now --runtime --extension /usr/share/app0.raw --extension /usr/share/conf0.raw /usr/share/minimal_0.raw app0 +portablectl detach --runtime --extension /tmp/app1.raw /usr/share/minimal_0.raw app # portablectl also works with directory paths rather than images mkdir /tmp/rootdir /tmp/app0 /tmp/app1 /tmp/overlay /tmp/os-release-fix /tmp/os-release-fix/etc -mount /usr/share/app0.raw /tmp/app0 -mount /usr/share/app1.raw /tmp/app1 +mount /tmp/app0.raw /tmp/app0 +mount /tmp/app1.raw /tmp/app1 mount /usr/share/minimal_0.raw /tmp/rootdir # Fix up os-release to drop the valid PORTABLE_SERVICES field (because we are @@ -266,7 +329,22 @@ grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app1" /run/systemd/system.attached/app1.service.d/20-portable.conf grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app_1" /run/systemd/system.attached/app1.service.d/20-portable.conf -portablectl detach --now --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1 +portablectl detach --clean --now --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1 + +# Ensure --clean remove state and other directories belonging to the portable image being detached +test ! -d /var/lib/app0 +test ! -d /run/app0 + +# Ensure that mixed mode copies the images and units (client-owned) but symlinks the profile (OS owned) +portablectl "${ARGS[@]}" attach --copy=mixed --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1 +test -d /run/portables/app0 +test -d /run/portables/app1 +test -d /run/portables/rootdir +test -f /run/systemd/system.attached/app0.service +test -f /run/systemd/system.attached/app1.service +test -L /run/systemd/system.attached/app0.service.d/10-profile.conf +test -L /run/systemd/system.attached/app1.service.d/10-profile.conf +portablectl detach --runtime --extension /tmp/app0 --extension /tmp/app1 /tmp/rootdir app0 app1 # Attempt to disable the app unit during detaching. Requires --copy=symlink to reproduce. # Provides coverage for https://github.com/systemd/systemd/issues/23481 diff --git a/test/units/testsuite-30.sh b/test/units/TEST-30-ONCLOCKCHANGE.sh index 104c87b..83698b8 100755 --- a/test/units/testsuite-30.sh +++ b/test/units/TEST-30-ONCLOCKCHANGE.sh @@ -16,7 +16,7 @@ systemd-run --on-clock-change touch /tmp/clock-changed test ! -f /tmp/timezone-changed test ! -f /tmp/clock-changed -timedatectl set-timezone Europe/Kiev +timedatectl set-timezone Europe/Kyiv while test ! -f /tmp/timezone-changed ; do sleep .5 ; done diff --git a/test/units/testsuite-31.sh b/test/units/TEST-31-DEVICE-ENUMERATION.sh index 03aba36..5e99302 100755 --- a/test/units/testsuite-31.sh +++ b/test/units/TEST-31-DEVICE-ENUMERATION.sh @@ -3,7 +3,7 @@ set -eux set -o pipefail -if journalctl -b -t systemd --grep '\.device: Changed plugged -> dead'; then +if journalctl -b -t systemd --grep '(?<!loop.|diskseq-.)\.device: Changed plugged -> dead'; then exit 1 fi diff --git a/test/units/testsuite-32.sh b/test/units/TEST-32-OOMPOLICY.sh index 83b548a..046b8b9 100755 --- a/test/units/testsuite-32.sh +++ b/test/units/TEST-32-OOMPOLICY.sh @@ -9,7 +9,7 @@ set -o pipefail # an easier thing to test for, and also: let's not get confused by older # kernels where the concept was still new. -if test -f /sys/fs/cgroup/system.slice/testsuite-32.service/memory.oom.group; then +if test -f /sys/fs/cgroup/system.slice/TEST-32-OOMPOLICY.service/memory.oom.group; then systemd-analyze log-level debug # Run a service that is guaranteed to be the first candidate for OOM killing diff --git a/test/units/testsuite-34.sh b/test/units/TEST-34-DYNAMICUSERMIGRATE.sh index d15b675..d15b675 100755 --- a/test/units/testsuite-34.sh +++ b/test/units/TEST-34-DYNAMICUSERMIGRATE.sh diff --git a/test/units/testsuite-35.sh b/test/units/TEST-35-LOGIN.sh index 36e26da..78e0c1e 100755 --- a/test/units/testsuite-35.sh +++ b/test/units/TEST-35-LOGIN.sh @@ -25,14 +25,22 @@ setup_test_user() { trap cleanup_test_user EXIT } -test_enable_debug() { - mkdir -p /run/systemd/system/systemd-logind.service.d - cat >/run/systemd/system/systemd-logind.service.d/debug.conf <<EOF +test_write_dropin() { + systemctl edit --runtime --stdin systemd-logind.service --drop-in=debug.conf <<EOF [Service] Environment=SYSTEMD_LOG_LEVEL=debug EOF - systemctl daemon-reload - systemctl stop systemd-logind.service + + # We test "coldplug" (completely stop and start logind) here. So we need to preserve + # the fdstore, which might contain session leader pidfds. This is extremely rare use case + # and shall not be considered fully supported. + # See also: https://github.com/systemd/systemd/pull/30610#discussion_r1440507850 + systemctl edit --runtime --stdin systemd-logind.service --drop-in=fdstore-preserve.conf <<EOF +[Service] +FileDescriptorStorePreserve=yes +EOF + + systemctl restart systemd-logind.service } testcase_properties() { @@ -57,6 +65,25 @@ EOF rm -rf /run/systemd/logind.conf.d } +testcase_sleep_automated() { + assert_eq "$(busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager SleepOperation)" 'as 3 "suspend-then-hibernate" "suspend" "hibernate"' + + mkdir -p /run/systemd/logind.conf.d + + cat >/run/systemd/logind.conf.d/sleep-operations.conf <<EOF +[Login] +SleepOperation=suspend hybrid-sleep +EOF + + systemctl restart systemd-logind.service + + assert_eq "$(busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager SleepOperation)" 'as 2 "hybrid-sleep" "suspend"' + + busctl call org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager CanSleep + + rm -rf /run/systemd/logind.conf.d +} + testcase_started() { local pid @@ -231,7 +258,7 @@ cleanup_session() ( systemctl stop getty@tty2.service - for s in $(loginctl --no-legend list-sessions | awk '$3 == "logind-test-user" { print $1 }'); do + for s in $(loginctl --no-legend list-sessions | grep -v manager | awk '$3 == "logind-test-user" { print $1 }'); do echo "INFO: stopping session $s" loginctl terminate-session "$s" done @@ -281,18 +308,18 @@ check_session() ( local seat session leader_pid - if [[ $(loginctl --no-legend | grep -c "logind-test-user") != 1 ]]; then + if [[ $(loginctl --no-legend | grep -v manager | grep -c "logind-test-user") != 1 ]]; then echo "no session or multiple sessions for logind-test-user." >&2 return 1 fi - seat=$(loginctl --no-legend | grep 'logind-test-user *seat' | awk '{ print $4 }') + seat=$(loginctl --no-legend | grep -v manager | grep 'logind-test-user *seat' | awk '{ print $4 }') if [[ -z "$seat" ]]; then echo "no seat found for user logind-test-user" >&2 return 1 fi - session=$(loginctl --no-legend | awk '$3 == "logind-test-user" { print $1 }') + session=$(loginctl --no-legend | grep -v manager | awk '$3 == "logind-test-user" { print $1 }') if [[ -z "$session" ]]; then echo "no session found for user logind-test-user" >&2 return 1 @@ -337,7 +364,7 @@ EOF check_session && break done check_session - assert_eq "$(loginctl --no-legend | awk '$3=="logind-test-user" { print $5 }')" "tty2" + assert_eq "$(loginctl --no-legend | grep -v manager | awk '$3=="logind-test-user" { print $7 }')" "tty2" } testcase_sanity_check() { @@ -355,13 +382,15 @@ testcase_sanity_check() { # the seat/session autodetection work-ish systemd-run --user --pipe --wait -M "logind-test-user@.host" bash -eux <<\EOF loginctl list-sessions + loginctl list-sessions -j + loginctl list-sessions --json=short loginctl session-status loginctl show-session loginctl show-session -P DelayInhibited # We're not in the same session scope, so in this case we need to specify # the session ID explicitly - session=$(loginctl --no-legend | awk '$3 == "logind-test-user" { print $1; exit; }') + session=$(loginctl --no-legend | grep -v manager | awk '$3 == "logind-test-user" { print $1; exit; }') loginctl kill-session --signal=SIGCONT "$session" # FIXME(?) #loginctl kill-session --signal=SIGCONT --kill-whom=leader "$session" @@ -428,7 +457,7 @@ EOF udevadm info "$dev" # trigger logind and activate session - loginctl activate "$(loginctl --no-legend | awk '$3 == "logind-test-user" { print $1 }')" + loginctl activate "$(loginctl --no-legend | grep -v manager | awk '$3 == "logind-test-user" { print $1 }')" # check ACL sleep 1 @@ -469,7 +498,7 @@ testcase_lock_idle_action() { return fi - if loginctl --no-legend | grep -q logind-test-user; then + if loginctl --no-legend | grep -v manager | grep -q logind-test-user; then echo >&2 "Session of the 'logind-test-user' is already present." exit 1 fi @@ -478,6 +507,7 @@ testcase_lock_idle_action() { create_session + journalctl --sync ts="$(date '+%H:%M:%S')" mkdir -p /run/systemd/logind.conf.d @@ -493,18 +523,24 @@ EOF # session active again and next we slept for another 35s so sessions have # become idle again. 'Lock' signal is sent out for each session, we have at # least one session, so minimum of 2 "Lock" signals must have been sent. - timeout 35 bash -c "while [[ \"\$(journalctl -b -u systemd-logind.service --since=$ts | grep -c 'Sent message type=signal .* member=Lock')\" -lt 1 ]]; do sleep 1; done" + journalctl --sync + set +o pipefail + timeout -v 35 journalctl -b -u systemd-logind.service --since="$ts" -n all --follow | grep -m 1 -q 'Sent message type=signal .* member=Lock' + set -o pipefail + + # We need to know that a new message was sent after waking up, + # so we must track how many happened before sleeping to check we have extra. + locks="$(journalctl -b -u systemd-logind.service --since="$ts" | grep -c 'Sent message type=signal .* member=Lock')" # Wakeup touch /dev/tty2 # Wait again - timeout 35 bash -c "while [[ \"\$(journalctl -b -u systemd-logind.service --since=$ts | grep -c 'Sent message type=signal .* member=Lock')\" -lt 2 ]]; do sleep 1; done" - - if [[ "$(journalctl -b -u systemd-logind.service --since="$ts" | grep -c 'System idle. Will be locked now.')" -lt 2 ]]; then - echo >&2 "System haven't entered idle state at least 2 times." - exit 1 - fi + journalctl --sync + set +o pipefail + timeout -v 35 journalctl -b -u systemd-logind.service --since="$ts" -n all --follow | grep -m "$((locks + 1))" -q 'Sent message type=signal .* member=Lock' + timeout -v 35 journalctl -b -u systemd-logind.service --since="$ts" -n all --follow | grep -m 2 -q -F 'System idle. Will be locked now.' + set -o pipefail } testcase_session_properties() { @@ -518,7 +554,7 @@ testcase_session_properties() { trap cleanup_session RETURN create_session - s=$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $1 }') + s=$(loginctl list-sessions --no-legend | grep -v manager | awk '$3 == "logind-test-user" { print $1 }') /usr/lib/systemd/tests/unit-tests/manual/test-session-properties "/org/freedesktop/login1/session/_3${s?}" /dev/tty2 } @@ -534,17 +570,17 @@ testcase_list_users_sessions_seats() { create_session # Activate the session - loginctl activate "$(loginctl --no-legend | awk '$3 == "logind-test-user" { print $1 }')" + loginctl activate "$(loginctl --no-legend | grep -v manager | awk '$3 == "logind-test-user" { print $1 }')" - session=$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $1 }') + session=$(loginctl list-sessions --no-legend | grep -v manager | awk '$3 == "logind-test-user" { print $1 }') : check that we got a valid session id busctl get-property org.freedesktop.login1 "/org/freedesktop/login1/session/_3${session?}" org.freedesktop.login1.Session Id - assert_eq "$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $2 }')" "$(id -ru logind-test-user)" - seat=$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $4 }') - assert_eq "$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $5 }')" tty2 - assert_eq "$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $6 }')" active - assert_eq "$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $7 }')" no - assert_eq "$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $8 }')" '-' + assert_eq "$(loginctl list-sessions --no-legend | grep -v manager | awk '$3 == "logind-test-user" { print $2 }')" "$(id -ru logind-test-user)" + seat=$(loginctl list-sessions --no-legend | grep -v manager | awk '$3 == "logind-test-user" { print $4 }') + assert_eq "$(loginctl list-sessions --no-legend | grep -v manager | awk '$3 == "logind-test-user" { print $6 }')" user + assert_eq "$(loginctl list-sessions --no-legend | grep -v manager | awk '$3 == "logind-test-user" { print $7 }')" tty2 + assert_eq "$(loginctl list-sessions --no-legend | grep -v manager | awk '$3 == "logind-test-user" { print $8 }')" no + assert_eq "$(loginctl list-sessions --no-legend | grep -v manager | awk '$3 == "logind-test-user" { print $9 }')" '-' loginctl list-seats --no-legend | grep -Fwq "${seat?}" @@ -555,15 +591,15 @@ testcase_list_users_sessions_seats() { loginctl enable-linger logind-test-user assert_eq "$(loginctl list-users --no-legend | awk '$2 == "logind-test-user" { print $3 }')" yes - for s in $(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $1 }'); do + for s in $(loginctl list-sessions --no-legend | grep tty | awk '$3 == "logind-test-user" { print $1 }'); do loginctl terminate-session "$s" done - if ! timeout 30 bash -c "while loginctl --no-legend | grep -q logind-test-user; do sleep 1; done"; then + if ! timeout 30 bash -c "while loginctl --no-legend | grep tty | grep -q logind-test-user; do sleep 1; done"; then echo "WARNING: session for logind-test-user still active, ignoring." return fi - assert_eq "$(loginctl list-users --no-legend | awk '$2 == "logind-test-user" { print $4 }')" lingering + timeout 30 bash -c "until [[ \"\$(loginctl list-users --no-legend | awk '\$2 == \"logind-test-user\" { print \$4 }')\" == lingering ]]; do sleep 1; done" } teardown_stop_idle_session() ( @@ -586,7 +622,9 @@ testcase_stop_idle_session() { create_session trap teardown_stop_idle_session RETURN - id="$(loginctl --no-legend | awk '$3 == "logind-test-user" { print $1; }')" + id="$(loginctl --no-legend | grep tty | awk '$3 == "logind-test-user" { print $1; }')" + + journalctl --sync ts="$(date '+%H:%M:%S')" mkdir -p /run/systemd/logind.conf.d @@ -597,8 +635,9 @@ EOF systemctl restart systemd-logind.service sleep 5 + journalctl --sync assert_eq "$(journalctl -b -u systemd-logind.service --since="$ts" --grep "Session \"$id\" of user \"logind-test-user\" is idle, stopping." | wc -l)" 1 - assert_eq "$(loginctl --no-legend | grep -c "logind-test-user")" 0 + assert_eq "$(loginctl --no-legend | grep -v manager | grep -c "logind-test-user")" 0 } testcase_ambient_caps() { @@ -653,8 +692,53 @@ EOF rm -f "$SCRIPT" "$PAMSERVICE" } +background_at_return() { + rm -f /etc/pam.d/"$PAMSERVICE" + unset PAMSERVICE +} + +testcase_background() { + + local uid TRANSIENTUNIT1 TRANSIENTUNIT2 + + uid=$(id -u logind-test-user) + + systemctl stop user@"$uid".service + + PAMSERVICE="pamserv$RANDOM" + TRANSIENTUNIT1="bg$RANDOM.service" + TRANSIENTUNIT2="bgg$RANDOM.service" + + trap background_at_return RETURN + + cat > /etc/pam.d/"$PAMSERVICE" <<EOF +auth sufficient pam_unix.so +auth required pam_deny.so +account sufficient pam_unix.so +account required pam_permit.so +session optional pam_systemd.so debug +session required pam_unix.so +EOF + + systemd-run -u "$TRANSIENTUNIT1" -p PAMName="$PAMSERVICE" -p "Environment=XDG_SESSION_CLASS=background-light" -p Type=exec -p User=logind-test-user sleep infinity + + # This was a 'light' background service, hence the service manager should not be running + (! systemctl is-active user@"$uid".service ) + + systemctl stop "$TRANSIENTUNIT1" + + systemd-run -u "$TRANSIENTUNIT2" -p PAMName="$PAMSERVICE" -p "Environment=XDG_SESSION_CLASS=background" -p Type=exec -p User=logind-test-user sleep infinity + + # This was a regular background service, hence the service manager should be running + systemctl is-active user@"$uid".service + + systemctl stop "$TRANSIENTUNIT2" + + systemctl stop user@"$uid".service +} + setup_test_user -test_enable_debug +test_write_dropin run_testcases touch /testok diff --git a/test/units/testsuite-36.sh b/test/units/TEST-36-NUMAPOLICY.sh index 8a53b98..fcd3d6d 100755 --- a/test/units/testsuite-36.sh +++ b/test/units/TEST-36-NUMAPOLICY.sh @@ -3,6 +3,11 @@ set -eux set -o pipefail +if [[ -n "${ASAN_OPTIONS:-}" ]]; then + echo "This test does not support running with sanitizers, skipping the test" | tee --append /skipped + exit 77 +fi + # shellcheck disable=SC2317 at_exit() { # shellcheck disable=SC2181 @@ -29,7 +34,7 @@ testUnitFile="/run/systemd/system/$testUnit" testUnitNUMAConf="$testUnitFile.d/numa.conf" # Sleep constants (we should probably figure out something better but nothing comes to mind) -sleepAfterStart=1 +sleepAfterStart=3 # Journal cursor for easier navigation journalCursorFile="jounalCursorFile" @@ -80,7 +85,7 @@ EOF writeTestUnit() { mkdir -p "$testUnitFile.d/" - printf "[Service]\nExecStart=/bin/sleep 3600\n" >"$testUnitFile" + printf "[Service]\nExecStart=sleep 3600\n" >"$testUnitFile" } writeTestUnitNUMAPolicy() { diff --git a/test/units/testsuite-38-sleep.service b/test/units/TEST-38-FREEZER-sleep.service index c116c80..1bb9ddf 100644 --- a/test/units/testsuite-38-sleep.service +++ b/test/units/TEST-38-FREEZER-sleep.service @@ -1,3 +1,3 @@ # SPDX-License-Identifier: LGPL-2.1-or-later [Service] -ExecStart=/bin/sleep 3600 +ExecStart=sleep 3600 diff --git a/test/units/testsuite-38.sh b/test/units/TEST-38-FREEZER.sh index 5fc87fc..0759784 100755 --- a/test/units/testsuite-38.sh +++ b/test/units/TEST-38-FREEZER.sh @@ -9,7 +9,7 @@ set -o pipefail systemd-analyze log-level debug -unit=testsuite-38-sleep.service +unit=TEST-38-FREEZER-sleep.service start_test_service() { systemctl daemon-reload @@ -94,7 +94,7 @@ check_freezer_state() { # Ignore the intermediate freezing & thawing states in case we check # the unit state too quickly - [[ "$state" =~ ^(freezing|thawing)$ ]] || break + [[ "$state" =~ ^(freezing|thawing) ]] || break sleep .5 done @@ -105,7 +105,14 @@ check_freezer_state() { } check_cgroup_state() { - grep -q "frozen $2" /sys/fs/cgroup/system.slice/"$1"/cgroup.events + # foo.unit -> /system.slice/foo.unit/ + # foo.slice/ -> /foo.slice/./ + # foo.slice/foo.unit -> /foo.slice/foo.unit/ + local slice unit + unit="${1##*/}" + slice="${1%"$unit"}" + slice="${slice%/}" + grep -q "frozen $2" /sys/fs/cgroup/"${slice:-system.slice}"/"${unit:-.}"/cgroup.events } testcase_dbus_api() { @@ -142,31 +149,6 @@ testcase_dbus_api() { echo } -testcase_jobs() { - local pid_before= - local pid_after= - echo "Test that it is possible to apply jobs on frozen units:" - - systemctl start "${unit}" - dbus_freeze "${unit}" - check_freezer_state "${unit}" "frozen" - - echo -n " - restart: " - pid_before=$(systemctl show -p MainPID "${unit}" --value) - systemctl restart "${unit}" - pid_after=$(systemctl show -p MainPID "${unit}" --value) - [ "$pid_before" != "$pid_after" ] && echo "[ OK ]" - - dbus_freeze "${unit}" - check_freezer_state "${unit}" "frozen" - - echo -n " - stop: " - timeout 5s systemctl stop "${unit}" - echo "[ OK ]" - - echo -} - testcase_systemctl() { echo "Test that systemctl freeze/thaw verbs:" @@ -224,22 +206,101 @@ testcase_recursive() { echo "Test recursive freezing:" - echo -n " - freeze: " + echo -n " - freeze/thaw parent: " systemctl freeze "$slice" - check_freezer_state "${slice}" "frozen" - check_freezer_state "${unit}" "frozen" - grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/cgroup.events - grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events + check_freezer_state "$slice" "frozen" + check_freezer_state "$unit" "frozen-by-parent" + check_cgroup_state "$slice/" 1 + check_cgroup_state "$slice/$unit" 1 + systemctl thaw "$slice" + check_freezer_state "$slice" "running" + check_freezer_state "$unit" "running" + check_cgroup_state "$slice/" 0 + check_cgroup_state "$slice/$unit" 0 echo "[ OK ]" - echo -n " - thaw: " + echo -n " - child freeze/thaw during frozen parent: " + systemctl freeze "$slice" + check_freezer_state "$slice" "frozen" + check_freezer_state "$unit" "frozen-by-parent" + check_cgroup_state "$slice/" 1 + check_cgroup_state "$slice/$unit" 1 + systemctl freeze "$unit" + check_freezer_state "$slice" "frozen" + check_freezer_state "$unit" "frozen" + check_cgroup_state "$slice/" 1 + check_cgroup_state "$slice/$unit" 1 + systemctl thaw "$unit" + check_freezer_state "$slice" "frozen" + check_freezer_state "$unit" "frozen-by-parent" + check_cgroup_state "$slice/" 1 + check_cgroup_state "$slice/$unit" 1 systemctl thaw "$slice" - check_freezer_state "${unit}" "running" - check_freezer_state "${slice}" "running" - grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/cgroup.events - grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events + check_freezer_state "$slice" "running" + check_freezer_state "$unit" "running" + check_cgroup_state "$slice/" 0 + check_cgroup_state "$slice/$unit" 0 echo "[ OK ]" + echo -n " - pre-frozen child not thawed by parent: " + systemctl freeze "$unit" + check_freezer_state "$slice" "running" + check_freezer_state "$unit" "frozen" + check_cgroup_state "$slice/" 0 + check_cgroup_state "$slice/$unit" 1 + systemctl freeze "$slice" + check_freezer_state "$slice" "frozen" + check_freezer_state "$unit" "frozen" + check_cgroup_state "$slice/" 1 + check_cgroup_state "$slice/$unit" 1 + systemctl thaw "$slice" + check_freezer_state "$slice" "running" + check_freezer_state "$unit" "frozen" + check_cgroup_state "$slice/" 0 + check_cgroup_state "$slice/$unit" 1 + echo "[ OK ]" + + echo -n " - pre-frozen child demoted and thawed by parent: " + systemctl freeze "$slice" + check_freezer_state "$slice" "frozen" + check_freezer_state "$unit" "frozen" + check_cgroup_state "$slice/" 1 + check_cgroup_state "$slice/$unit" 1 + systemctl thaw "$unit" + check_freezer_state "$slice" "frozen" + check_freezer_state "$unit" "frozen-by-parent" + check_cgroup_state "$slice/" 1 + check_cgroup_state "$slice/$unit" 1 + systemctl thaw "$slice" + check_freezer_state "$slice" "running" + check_freezer_state "$unit" "running" + check_cgroup_state "$slice/" 0 + check_cgroup_state "$slice/$unit" 0 + echo "[ OK ]" + + echo -n " - child promoted and not thawed by parent: " + systemctl freeze "$slice" + check_freezer_state "$slice" "frozen" + check_freezer_state "$unit" "frozen-by-parent" + check_cgroup_state "$slice/" 1 + check_cgroup_state "$slice/$unit" 1 + systemctl freeze "$unit" + check_freezer_state "$slice" "frozen" + check_freezer_state "$unit" "frozen" + check_cgroup_state "$slice/" 1 + check_cgroup_state "$slice/$unit" 1 + systemctl thaw "$slice" + check_freezer_state "$slice" "running" + check_freezer_state "$unit" "frozen" + check_cgroup_state "$slice/" 0 + check_cgroup_state "$slice/$unit" 1 + echo "[ OK ]" + + echo -n " - can't stop a frozen unit: " + (! systemctl -q stop "$unit" ) + echo "[ OK ]" + systemctl thaw "$unit" + systemctl stop "$unit" systemctl stop "$slice" @@ -255,38 +316,39 @@ testcase_preserve_state() { echo "Test that freezer state is preserved when recursive freezing is initiated from outside (e.g. by manager up the tree):" echo -n " - freeze from outside: " - echo 1 >/sys/fs/cgroup/"${slice}"/cgroup.freeze + echo 1 >/sys/fs/cgroup/"$slice"/cgroup.freeze # Give kernel some time to freeze the slice sleep 1 # Our state should not be affected - check_freezer_state "${slice}" "running" - check_freezer_state "${unit}" "running" + check_freezer_state "$slice" "running" + check_freezer_state "$unit" "running" # However actual kernel state should be frozen - grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/cgroup.events - grep -q "frozen 1" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events + check_cgroup_state "$slice/" 1 + check_cgroup_state "$slice/$unit" 1 echo "[ OK ]" echo -n " - thaw from outside: " - echo 0 >/sys/fs/cgroup/"${slice}"/cgroup.freeze + echo 0 >/sys/fs/cgroup/"$slice"/cgroup.freeze sleep 1 - check_freezer_state "${unit}" "running" - check_freezer_state "${slice}" "running" - grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/cgroup.events - grep -q "frozen 0" /sys/fs/cgroup/"${slice}"/"${unit}"/cgroup.events + check_freezer_state "$unit" "running" + check_freezer_state "$slice" "running" + check_cgroup_state "$slice/" 0 + check_cgroup_state "$slice/$unit" 0 echo "[ OK ]" echo -n " - thaw from outside while inner service is frozen: " systemctl freeze "$unit" - check_freezer_state "${unit}" "frozen" - echo 1 >/sys/fs/cgroup/"${slice}"/cgroup.freeze - echo 0 >/sys/fs/cgroup/"${slice}"/cgroup.freeze - check_freezer_state "${slice}" "running" - check_freezer_state "${unit}" "frozen" + check_freezer_state "$unit" "frozen" + echo 1 >/sys/fs/cgroup/"$slice"/cgroup.freeze + echo 0 >/sys/fs/cgroup/"$slice"/cgroup.freeze + check_freezer_state "$slice" "running" + check_freezer_state "$unit" "frozen" echo "[ OK ]" + systemctl thaw "$unit" systemctl stop "$unit" systemctl stop "$slice" diff --git a/test/units/testsuite-43.sh b/test/units/TEST-43-PRIVATEUSER-UNPRIV.sh index 4f31a33..165af47 100755 --- a/test/units/testsuite-43.sh +++ b/test/units/TEST-43-PRIVATEUSER-UNPRIV.sh @@ -6,9 +6,11 @@ set -o pipefail # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh +install_extension_images + if [[ "$(sysctl -ne kernel.apparmor_restrict_unprivileged_userns)" -eq 1 ]]; then echo "Cannot create unprivileged user namespaces" >/skipped - exit 0 + exit 77 fi systemd-analyze log-level debug @@ -130,7 +132,7 @@ umount /tmp/img_bind # Unprivileged overlayfs was added to Linux 5.11, so try to detect it first mkdir -p /tmp/a /tmp/b /tmp/c if unshare --mount --user --map-root-user mount -t overlay overlay /tmp/c -o lowerdir=/tmp/a:/tmp/b; then - unsquashfs -no-xattrs -d /tmp/app2 /usr/share/app1.raw + unsquashfs -no-xattrs -d /tmp/app2 /tmp/app1.raw runas testuser systemd-run --wait --user --unit=test-extension-dir \ -p ExtensionDirectories=/tmp/app2 \ -p TemporaryFileSystem=/run -p RootDirectory=/tmp/img \ diff --git a/test/units/testsuite-44.sh b/test/units/TEST-44-LOG-NAMESPACE.sh index fbd4ae6..0819a4b 100755 --- a/test/units/testsuite-44.sh +++ b/test/units/TEST-44-LOG-NAMESPACE.sh @@ -4,12 +4,24 @@ set -eux systemd-analyze log-level debug +journalctl --list-namespaces -o json | jq . + systemd-run --wait -p LogNamespace=foobar echo "hello world" +systemd-run --wait -p LogNamespace=foobaz echo "hello world" journalctl --namespace=foobar --sync +journalctl --namespace=foobaz --sync +ls -l /var/log/journal/ +journalctl --list-namespaces + journalctl -o cat --namespace=foobar >/tmp/hello-world journalctl -o cat >/tmp/no-hello-world +journalctl --list-namespaces | grep foobar +journalctl --list-namespaces | grep foobaz +journalctl --list-namespaces -o json | jq . +[[ "$(journalctl --root=/tmp --list-namespaces --quiet)" == "" ]] + grep "^hello world$" /tmp/hello-world (! grep "^hello world$" /tmp/no-hello-world) diff --git a/test/units/testsuite-45.sh b/test/units/TEST-45-TIMEDATE.sh index b426927..dff3ed0 100755 --- a/test/units/testsuite-45.sh +++ b/test/units/TEST-45-TIMEDATE.sh @@ -57,12 +57,12 @@ testcase_timezone() { assert_in "Local time:" "$(timedatectl --no-pager)" echo 'change timezone' - assert_eq "$(timedatectl --no-pager set-timezone Europe/Kiev 2>&1)" "" - assert_eq "$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')" "Europe/Kiev" + assert_eq "$(timedatectl --no-pager set-timezone Europe/Kyiv 2>&1)" "" + assert_eq "$(readlink /etc/localtime | sed 's#^.*zoneinfo/##')" "Europe/Kyiv" if [[ -f /etc/timezone ]]; then - assert_eq "$(cat /etc/timezone)" "Europe/Kiev" + assert_eq "$(cat /etc/timezone)" "Europe/Kyiv" fi - assert_in "Time zone: Europe/Kiev \(EES*T, \+0[0-9]00\)" "$(timedatectl)" + assert_in "Time zone: Europe/Kyiv \(EES*T, \+0[0-9]00\)" "$(timedatectl)" if [[ -n "$ORIG_TZ" ]]; then echo 'reset timezone to original' @@ -218,7 +218,7 @@ assert_ntp() { assert_timedated_signal() { local timestamp="${1:?}" local value="${2:?}" - local args=(-q -n 1 --since="$timestamp" -p info _SYSTEMD_UNIT="busctl-monitor" + SYSLOG_IDENTIFIER="busctl-monitor") + local args=(-q -n 1 --since="$timestamp" -p info _SYSTEMD_UNIT="busctl-monitor.service") journalctl --sync @@ -258,12 +258,12 @@ ConditionVirtualization= Type=simple AmbientCapabilities= ExecStart= -ExecStart=/bin/sleep infinity +ExecStart=sleep infinity EOF systemctl daemon-reload fi - systemd-run --unit busctl-monitor.service -p SyslogIdentifier=busctl-monitor --service-type=notify \ + systemd-run --unit busctl-monitor.service --service-type=notify \ busctl monitor --json=short --match="type=signal,sender=org.freedesktop.timedate1,member=PropertiesChanged,path=/org/freedesktop/timedate1" : 'Disable NTP' @@ -298,7 +298,7 @@ assert_timesyncd_signal() { local timestamp="${1:?}" local property="${2:?}" local value="${3:?}" - local args=(-q --since="$timestamp" -p info _SYSTEMD_UNIT="busctl-monitor.service" + SYSLOG_IDENTIFIER="busctl-monitor") + local args=(-q --since="$timestamp" -p info _SYSTEMD_UNIT="busctl-monitor.service") journalctl --sync @@ -359,7 +359,7 @@ EOF systemctl restart systemd-networkd networkctl status ntp99 - systemd-run --unit busctl-monitor.service -p SyslogIdentifier=busctl-monitor --service-type=notify \ + systemd-run --unit busctl-monitor.service --service-type=notify \ busctl monitor --json=short --match="type=signal,sender=org.freedesktop.timesync1,member=PropertiesChanged,path=/org/freedesktop/timesync1" # LinkNTPServers diff --git a/test/units/TEST-46-HOMED.sh b/test/units/TEST-46-HOMED.sh new file mode 100755 index 0000000..61590a1 --- /dev/null +++ b/test/units/TEST-46-HOMED.sh @@ -0,0 +1,620 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +# Check if homectl is installed, and if it isn't bail out early instead of failing +if ! test -x /usr/bin/homectl ; then + echo "no homed" >/skipped + exit 77 +fi + +inspect() { + # As updating disk-size-related attributes can take some time on some + # filesystems, let's drop these fields before comparing the outputs to + # avoid unexpected fails. To see the full outputs of both homectl & + # userdbctl (for debugging purposes) drop the fields just before the + # comparison. + local USERNAME="${1:?}" + homectl inspect "$USERNAME" | tee /tmp/a + userdbctl user "$USERNAME" | tee /tmp/b + + # diff uses the grep BREs for pattern matching + diff -I '^\s*Disk \(Size\|Free\|Floor\|Ceiling\|Usage\):' /tmp/{a,b} + rm /tmp/{a,b} + + homectl inspect --json=pretty "$USERNAME" +} + +wait_for_state() { + for i in {1..10}; do + (( i > 1 )) && sleep 0.5 + homectl inspect "$1" | grep -qF "State: $2" && break + done +} + +FSTYPE="$(stat --file-system --format "%T" /)" + +systemctl start systemd-homed.service systemd-userdbd.socket + +systemd-analyze log-level debug +systemctl service-log-level systemd-homed debug + +# Create a tmpfs to use as backing store for the home dir. That way we can enforce a size limit nicely. +mkdir -p /home +mount -t tmpfs tmpfs /home -o size=290M + +TMP_SKEL=$(mktemp -d) +echo hogehoge >"$TMP_SKEL"/hoge + +# we enable --luks-discard= since we run our tests in a tight VM, hence don't +# needlessly pressure for storage. We also set the cheapest KDF, since we don't +# want to waste CI CPU cycles on it. We also effectively disable rate-limiting on +# the user by allowing 1000 logins per second +NEWPASSWORD=xEhErW0ndafV4s homectl create test-user \ + --disk-size=min \ + --luks-discard=yes \ + --image-path=/home/test-user.home \ + --luks-pbkdf-type=pbkdf2 \ + --luks-pbkdf-time-cost=1ms \ + --rate-limit-interval=1s \ + --rate-limit-burst=1000 \ + --skel="$TMP_SKEL" +inspect test-user + +PASSWORD=xEhErW0ndafV4s homectl authenticate test-user + +PASSWORD=xEhErW0ndafV4s homectl activate test-user +inspect test-user + +PASSWORD=xEhErW0ndafV4s homectl update test-user --real-name="Inline test" +inspect test-user + +homectl deactivate test-user +inspect test-user + +PASSWORD=xEhErW0ndafV4s NEWPASSWORD=yPN4N0fYNKUkOq homectl passwd test-user +inspect test-user + +PASSWORD=yPN4N0fYNKUkOq homectl activate test-user +inspect test-user + +SYSTEMD_LOG_LEVEL=debug PASSWORD=yPN4N0fYNKUkOq NEWPASSWORD=xEhErW0ndafV4s homectl passwd test-user +inspect test-user + +homectl deactivate test-user +inspect test-user + +homectl update test-user --real-name "Offline test" --offline +inspect test-user + +PASSWORD=xEhErW0ndafV4s homectl activate test-user +inspect test-user + +# Ensure that the offline changes were propagated in +grep "Offline test" /home/test-user/.identity + +homectl deactivate test-user +inspect test-user + +PASSWORD=xEhErW0ndafV4s homectl update test-user --real-name="Inactive test" +inspect test-user + +PASSWORD=xEhErW0ndafV4s homectl activate test-user +inspect test-user + +homectl deactivate test-user +inspect test-user + +# Do some keyring tests, but only on real kernels, since keyring access inside of containers will fail +# (See: https://github.com/systemd/systemd/issues/17606) +if ! systemd-detect-virt -cq ; then + PASSWORD=xEhErW0ndafV4s homectl activate test-user + inspect test-user + + # Key should now be in the keyring + homectl update test-user --real-name "Keyring Test" + inspect test-user + + # These commands shouldn't use the keyring + (! timeout 5s homectl authenticate test-user ) + (! NEWPASSWORD="foobar" timeout 5s homectl passwd test-user ) + + homectl lock test-user + inspect test-user + + # Key should be gone from keyring + (! timeout 5s homectl update test-user --real-name "Keyring Test 2" ) + + PASSWORD=xEhErW0ndafV4s homectl unlock test-user + inspect test-user + + # Key should have been re-instantiated into the keyring + homectl update test-user --real-name "Keyring Test 3" + inspect test-user + + homectl deactivate test-user + inspect test-user +fi + +# Do some resize tests, but only if we run on real kernels and are on btrfs, as quota inside of containers +# will fail and minimizing while active only works on btrfs. +if ! systemd-detect-virt -cq && [[ "$FSTYPE" == "btrfs" ]]; then + # grow while inactive + PASSWORD=xEhErW0ndafV4s homectl resize test-user 300M + inspect test-user + + # minimize while inactive + PASSWORD=xEhErW0ndafV4s homectl resize test-user min + inspect test-user + + PASSWORD=xEhErW0ndafV4s homectl activate test-user + inspect test-user + + # grow while active + PASSWORD=xEhErW0ndafV4s homectl resize test-user max + inspect test-user + + # minimize while active + PASSWORD=xEhErW0ndafV4s homectl resize test-user 0 + inspect test-user + + # grow while active + PASSWORD=xEhErW0ndafV4s homectl resize test-user 300M + inspect test-user + + # shrink to original size while active + PASSWORD=xEhErW0ndafV4s homectl resize test-user 256M + inspect test-user + + # minimize again + PASSWORD=xEhErW0ndafV4s homectl resize test-user min + inspect test-user + + # Increase space, so that we can reasonably rebalance free space between to home dirs + mount /home -o remount,size=800M + + # create second user + NEWPASSWORD=uuXoo8ei homectl create test-user2 \ + --disk-size=min \ + --luks-discard=yes \ + --image-path=/home/test-user2.home \ + --luks-pbkdf-type=pbkdf2 \ + --luks-pbkdf-time-cost=1ms \ + --rate-limit-interval=1s \ + --rate-limit-burst=1000 + inspect test-user2 + + # activate second user + PASSWORD=uuXoo8ei homectl activate test-user2 + inspect test-user2 + + # set second user's rebalance weight to 100 + PASSWORD=uuXoo8ei homectl update test-user2 --rebalance-weight=100 + inspect test-user2 + + # set first user's rebalance weight to quarter of that of the second + PASSWORD=xEhErW0ndafV4s homectl update test-user --rebalance-weight=25 + inspect test-user + + # synchronously rebalance + homectl rebalance + inspect test-user + inspect test-user2 + + wait_for_state test-user2 active + homectl deactivate test-user2 + wait_for_state test-user2 inactive + homectl remove test-user2 +fi + +PASSWORD=xEhErW0ndafV4s homectl with test-user -- test ! -f /home/test-user/xyz +(! PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz) +PASSWORD=xEhErW0ndafV4s homectl with test-user -- touch /home/test-user/xyz +PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz +PASSWORD=xEhErW0ndafV4s homectl with test-user -- rm /home/test-user/xyz +PASSWORD=xEhErW0ndafV4s homectl with test-user -- test ! -f /home/test-user/xyz +(! PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz) +[[ $(PASSWORD=xEhErW0ndafV4s homectl with test-user -- stat -c %U /home/test-user/hoge) == "test-user" ]] +[[ $(PASSWORD=xEhErW0ndafV4s homectl with test-user -- cat /home/test-user/hoge) == "$(cat "$TMP_SKEL"/hoge)" ]] + +# Regression tests +wait_for_state test-user inactive +/usr/lib/systemd/tests/unit-tests/manual/test-homed-regression-31896 test-user + +wait_for_state test-user inactive +homectl remove test-user + +# blob directory tests +# See docs/USER_RECORD_BLOB_DIRS.md +checkblob() { + test -f "/var/cache/systemd/home/blob-user/$1" + stat -c "%u %#a" "/var/cache/systemd/home/blob-user/$1" | grep "^0 0644" + test -f "/home/blob-user/.identity-blob/$1" + stat -c "%u %#a" "/home/blob-user/.identity-blob/$1" | grep "^12345 0644" + + diff "/var/cache/systemd/home/blob-user/$1" "$2" + diff "/var/cache/systemd/home/blob-user/$1" "/home/blob-user/.identity-blob/$1" +} + +mkdir /tmp/blob1 /tmp/blob2 +echo data1 blob1 >/tmp/blob1/test1 +echo data1 blob2 >/tmp/blob2/test1 +echo data2 blob1 >/tmp/blob1/test2 +echo data2 blob2 >/tmp/blob2/test2 +echo invalid filename >/tmp/blob1/файл +echo data3 >/tmp/external-test3 +echo avatardata >/tmp/external-avatar +ln -s /tmp/external-avatar /tmp/external-avatar-lnk +dd if=/dev/urandom of=/tmp/external-barely-fits bs=1M count=64 +dd if=/dev/urandom of=/tmp/external-toobig bs=1M count=65 + +# create w/ prepopulated blob dir +NEWPASSWORD=EMJuc3zQaMibJo homectl create blob-user \ + --disk-size=min --luks-discard=yes \ + --luks-pbkdf-type=pbkdf2 --luks-pbkdf-time-cost=1ms \ + --rate-limit-interval=1s --rate-limit-burst=1000 \ + --uid=12345 \ + --blob=/tmp/blob1 +inspect blob-user +PASSWORD=EMJuc3zQaMibJo homectl activate blob-user +inspect blob-user + +test -d /var/cache/systemd/home/blob-user +stat -c "%u %#a" /var/cache/systemd/home/blob-user | grep "^0 0755" +test -d /home/blob-user/.identity-blob +stat -c "%u %#a" /home/blob-user/.identity-blob | grep "^12345 0700" + +checkblob test1 /tmp/blob1/test1 +(! checkblob test1 /tmp/blob2/test1 ) +checkblob test2 /tmp/blob1/test2 +(! checkblob test2 /tmp/blob2/test2 ) +(! checkblob фаил /tmp/blob1/фаил ) +(! checkblob test3 /tmp/external-test3 ) +(! checkblob avatar /tmp/external-avatar ) + +# append files to existing blob, both well-known and other +PASSWORD=EMJuc3zQaMibJo homectl update blob-user \ + -b test3=/tmp/external-test3 --avatar=/tmp/external-avatar +inspect blob-user +checkblob test1 /tmp/blob1/test1 +(! checkblob test1 /tmp/blob2/test1 ) +checkblob test2 /tmp/blob1/test2 +(! checkblob test2 /tmp/blob2/test2 ) +(! checkblob фаил /tmp/blob1/фаил ) +checkblob test3 /tmp/external-test3 +checkblob avatar /tmp/external-avatar + +# delete files from existing blob, both well-known and other +PASSWORD=EMJuc3zQaMibJo homectl update blob-user \ + -b test3= --avatar= +inspect blob-user +checkblob test1 /tmp/blob1/test1 +(! checkblob test1 /tmp/blob2/test1 ) +checkblob test2 /tmp/blob1/test2 +(! checkblob test2 /tmp/blob2/test2 ) +(! checkblob фаил /tmp/blob1/фаил ) +(! checkblob test3 /tmp/external-test3 ) +(! checkblob avatar /tmp/external-avatar ) + +# swap entire blob directory +PASSWORD=EMJuc3zQaMibJo homectl update blob-user \ + -b /tmp/blob2 +inspect blob-user +(! checkblob test1 /tmp/blob1/test1 ) +checkblob test1 /tmp/blob2/test1 +(! checkblob test2 /tmp/blob1/test2 ) +checkblob test2 /tmp/blob2/test2 +(! checkblob фаил /tmp/blob1/фаил ) +(! checkblob test3 /tmp/external-test3 ) +(! checkblob avatar /tmp/external-avatar ) + +# create and delete files while swapping blob directory. Also symlinks. +PASSWORD=EMJuc3zQaMibJo homectl update blob-user \ + -b /tmp/blob1 -b test2= -b test3=/tmp/external-test3 --avatar=/tmp/external-avatar-lnk +inspect blob-user +checkblob test1 /tmp/blob1/test1 +(! checkblob test1 /tmp/blob2/test1 ) +(! checkblob test2 /tmp/blob1/test2 ) +(! checkblob test2 /tmp/blob2/test2 ) +(! checkblob фаил /tmp/blob1/фаил ) +checkblob test3 /tmp/external-test3 +checkblob avatar /tmp/external-avatar # target of the link + +# clear the blob directory +PASSWORD=EMJuc3zQaMibJo homectl update blob-user \ + -b /tmp/blob2 -b test3=/tmp/external-test3 --blob= +inspect blob-user +(! checkblob test1 /tmp/blob1/test1 ) +(! checkblob test1 /tmp/blob2/test1 ) +(! checkblob test2 /tmp/blob1/test2 ) +(! checkblob test2 /tmp/blob2/test2 ) +(! checkblob фаил /tmp/blob1/фаил ) +(! checkblob test3 /tmp/external-test3 ) +(! checkblob avatar /tmp/external-avatar ) + +# file that's exactly 64M still fits +# FIXME: Figure out why this fails on ext4. +if [[ "$FSTYPE" != "ext2/ext3" ]]; then + PASSWORD=EMJuc3zQaMibJo homectl update blob-user \ + -b barely-fits=/tmp/external-barely-fits + (! checkblob test1 /tmp/blob1/test1 ) + (! checkblob test1 /tmp/blob2/test1 ) + (! checkblob test2 /tmp/blob1/test2 ) + (! checkblob test2 /tmp/blob2/test2 ) + (! checkblob фаил /tmp/blob1/фаил ) + (! checkblob test3 /tmp/external-test3 ) + (! checkblob avatar /tmp/external-avatar ) + checkblob barely-fits /tmp/external-barely-fits +fi + +# error out if the file is too big +(! PASSWORD=EMJuc3zQaMibJo homectl update blob-user -b huge=/tmp/external-toobig ) + +# error out if filenames are invalid +(! PASSWORD=EMJuc3zQaMibJo homectl update blob-user -b .hidden=/tmp/external-test3 ) +(! PASSWORD=EMJuc3zQaMibJo homectl update blob-user -b "with spaces=/tmp/external-test3" ) +(! PASSWORD=EMJuc3zQaMibJo homectl update blob-user -b with=equals=/tmp/external-test3 ) +(! PASSWORD=EMJuc3zQaMibJo homectl update blob-user -b файл=/tmp/external-test3 ) +(! PASSWORD=EMJuc3zQaMibJo homectl update blob-user -b special@chars=/tmp/external-test3 ) + +# Make sure offline updates to blobs get propagated in +homectl deactivate blob-user +inspect blob-user +homectl update blob-user --offline -b barely-fits= -b propagated=/tmp/external-test3 +inspect blob-user +PASSWORD=EMJuc3zQaMibJo homectl activate blob-user +inspect blob-user +(! checkblob barely-fits /tmp/external-barely-fits ) +checkblob propagated /tmp/external-test3 + +homectl deactivate blob-user +wait_for_state blob-user inactive +homectl remove blob-user + +# userdbctl tests +export PAGER= + +# Create a couple of user/group records to test io.systemd.DropIn +# See docs/USER_RECORD.md and docs/GROUP_RECORD.md +mkdir -p /run/userdb/ +cat >"/run/userdb/dropingroup.group" <<\EOF +{ + "groupName" : "dropingroup", + "gid" : 1000000 +} +EOF +cat >"/run/userdb/dropinuser.user" <<\EOF +{ + "userName" : "dropinuser", + "uid" : 2000000, + "realName" : "🐱", + "memberOf" : [ + "dropingroup" + ] +} +EOF +cat >"/run/userdb/dropinuser.user-privileged" <<\EOF +{ + "privileged" : { + "hashedPassword" : [ + "$6$WHBKvAFFT9jKPA4k$OPY4D4TczKN/jOnJzy54DDuOOagCcvxxybrwMbe1SVdm.Bbr.zOmBdATp.QrwZmvqyr8/SafbbQu.QZ2rRvDs/" + ], + "sshAuthorizedKeys" : [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA//dxI2xLg4MgxIKKZv1nqwTEIlE/fdakii2Fb75pG+ foo@bar.tld", + "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMlaqG2rTMje5CQnfjXJKmoSpEVJ2gWtx4jBvsQbmee2XbU/Qdq5+SRisssR9zVuxgg5NA5fv08MgjwJQMm+csc= hello@world.tld" + ] + } +} +EOF +# Set permissions and create necessary symlinks as described in nss-systemd(8) +chmod 0600 "/run/userdb/dropinuser.user-privileged" +ln -svrf "/run/userdb/dropingroup.group" "/run/userdb/1000000.group" +ln -svrf "/run/userdb/dropinuser.user" "/run/userdb/2000000.user" +ln -svrf "/run/userdb/dropinuser.user-privileged" "/run/userdb/2000000.user-privileged" + +userdbctl +userdbctl --version +userdbctl --help --no-pager +userdbctl --no-legend +userdbctl --output=classic +userdbctl --output=friendly +userdbctl --output=table +userdbctl --output=json | jq +userdbctl -j --json=pretty | jq +userdbctl -j --json=short | jq +userdbctl --with-varlink=no + +userdbctl user +userdbctl user testuser +userdbctl user root +userdbctl user testuser root +userdbctl user -j testuser root | jq +# Check only UID for the nobody user, since the name is build-configurable +userdbctl user --with-nss=no --synthesize=yes +userdbctl user --with-nss=no --synthesize=yes 0 root 65534 +userdbctl user dropinuser +userdbctl user 2000000 +userdbctl user --with-nss=no --with-varlink=no --synthesize=no --multiplexer=no dropinuser +userdbctl user --with-nss=no 2000000 +(! userdbctl user '') +(! userdbctl user 🐱) +(! userdbctl user 🐱 '' bar) +(! userdbctl user i-do-not-exist) +(! userdbctl user root i-do-not-exist testuser) +(! userdbctl user --with-nss=no --synthesize=no 0 root 65534) +(! userdbctl user -N root nobody) +(! userdbctl user --with-dropin=no dropinuser) +(! userdbctl user --with-dropin=no 2000000) + +userdbctl group +userdbctl group testuser +userdbctl group root +userdbctl group testuser root +userdbctl group -j testuser root | jq +# Check only GID for the nobody group, since the name is build-configurable +userdbctl group --with-nss=no --synthesize=yes +userdbctl group --with-nss=no --synthesize=yes 0 root 65534 +userdbctl group dropingroup +userdbctl group 1000000 +userdbctl group --with-nss=no --with-varlink=no --synthesize=no --multiplexer=no dropingroup +userdbctl group --with-nss=no 1000000 +(! userdbctl group '') +(! userdbctl group 🐱) +(! userdbctl group 🐱 '' bar) +(! userdbctl group i-do-not-exist) +(! userdbctl group root i-do-not-exist testuser) +(! userdbctl group --with-nss=no --synthesize=no 0 root 65534) +(! userdbctl group --with-dropin=no dropingroup) +(! userdbctl group --with-dropin=no 1000000) + +userdbctl users-in-group +userdbctl users-in-group testuser +userdbctl users-in-group testuser root +userdbctl users-in-group -j testuser root | jq +userdbctl users-in-group 🐱 +(! userdbctl users-in-group '') +(! userdbctl users-in-group foo '' bar) + +userdbctl groups-of-user +userdbctl groups-of-user testuser +userdbctl groups-of-user testuser root +userdbctl groups-of-user -j testuser root | jq +userdbctl groups-of-user 🐱 +(! userdbctl groups-of-user '') +(! userdbctl groups-of-user foo '' bar) + +userdbctl services +userdbctl services -j | jq + +varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"testuser","service":"io.systemd.Multiplexer"}' +varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"root","service":"io.systemd.Multiplexer"}' +varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"dropinuser","service":"io.systemd.Multiplexer"}' +varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"uid":2000000,"service":"io.systemd.Multiplexer"}' +(! varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"","service":"io.systemd.Multiplexer"}') +(! varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"🐱","service":"io.systemd.Multiplexer"}') +(! varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"i-do-not-exist","service":"io.systemd.Multiplexer"}') + +userdbctl ssh-authorized-keys dropinuser | tee /tmp/authorized-keys +grep "ssh-ed25519" /tmp/authorized-keys +grep "ecdsa-sha2-nistp256" /tmp/authorized-keys +echo "my-top-secret-key 🐱" >/tmp/my-top-secret-key +userdbctl ssh-authorized-keys dropinuser --chain /bin/cat /tmp/my-top-secret-key | tee /tmp/authorized-keys +grep "ssh-ed25519" /tmp/authorized-keys +grep "ecdsa-sha2-nistp256" /tmp/authorized-keys +grep "my-top-secret-key 🐱" /tmp/authorized-keys +(! userdbctl ssh-authorized-keys 🐱) +(! userdbctl ssh-authorized-keys dropin-user --chain) +(! userdbctl ssh-authorized-keys dropin-user --chain '') +(! SYSTEMD_LOG_LEVEL=debug userdbctl ssh-authorized-keys dropin-user --chain /bin/false) + +(! userdbctl '') +for opt in json multiplexer output synthesize with-dropin with-nss with-varlink; do + (! userdbctl "--$opt=''") + (! userdbctl "--$opt='🐱'") + (! userdbctl "--$opt=foo") + (! userdbctl "--$opt=foo" "--$opt=''" "--$opt=🐱") +done + +# FIXME: sshd seems to crash inside asan currently, skip the actual ssh test hence +if command -v ssh &>/dev/null && command -v sshd &>/dev/null && ! [[ -v ASAN_OPTIONS ]]; then + at_exit() { + set +e + + systemctl is-active -q mysshserver.socket && systemctl stop mysshserver.socket + rm -f /tmp/homed.id_ecdsa /run/systemd/system/mysshserver{@.service,.socket} + systemctl daemon-reload + homectl remove homedsshtest + for dir in /etc /usr/lib; do + if [[ -f "$dir/pam.d/sshd.bak" ]]; then + mv "$dir/pam.d/sshd.bak" "$dir/pam.d/sshd" + fi + done + } + + trap at_exit EXIT + + # Test that SSH logins work with delayed unlocking + ssh-keygen -N '' -C '' -t ecdsa -f /tmp/homed.id_ecdsa + NEWPASSWORD=hunter4711 homectl create \ + --disk-size=min \ + --luks-discard=yes \ + --luks-pbkdf-type=pbkdf2 \ + --luks-pbkdf-time-cost=1ms \ + --rate-limit-interval=1s \ + --rate-limit-burst=1000 \ + --enforce-password-policy=no \ + --ssh-authorized-keys=@/tmp/homed.id_ecdsa.pub \ + --stop-delay=0 \ + homedsshtest + homectl inspect homedsshtest + + mkdir -p /etc/ssh + test -f /etc/ssh/ssh_host_ecdsa_key || ssh-keygen -t ecdsa -C '' -N '' -f /etc/ssh/ssh_host_ecdsa_key + + # ssh wants this dir around, but distros cannot agree on a common name for it, let's just create all that + # are aware of distros use + mkdir -p /usr/share/empty.sshd /var/empty /var/empty/sshd /run/sshd + + for dir in /etc /usr/lib; do + if [[ -f "$dir/pam.d/sshd" ]]; then + mv "$dir/pam.d/sshd" "$dir/pam.d/sshd.bak" + cat >"$dir/pam.d/sshd" <<EOF +auth sufficient pam_unix.so nullok +auth sufficient pam_systemd_home.so debug +auth required pam_deny.so +account sufficient pam_systemd_home.so debug +account sufficient pam_unix.so +account required pam_permit.so +session optional pam_systemd_home.so debug +session optional pam_systemd.so +session required pam_unix.so +EOF + break + fi + done + + mkdir -p /etc/sshd/ + cat >/etc/ssh/sshd_config <<EOF +AuthorizedKeysCommand /usr/bin/userdbctl ssh-authorized-keys %u +AuthorizedKeysCommandUser root +UsePAM yes +AcceptEnv PASSWORD +LogLevel DEBUG3 +EOF + + cat >/run/systemd/system/mysshserver.socket <<EOF +[Socket] +ListenStream=4711 +Accept=yes +EOF + + cat >/run/systemd/system/mysshserver@.service <<EOF +[Service] +ExecStart=-/usr/sbin/sshd -i -d -e +StandardInput=socket +StandardOutput=socket +StandardError=journal +EOF + + systemctl daemon-reload + systemctl start mysshserver.socket + + userdbctl user -j homedsshtest + + ssh -t -t -4 -p 4711 -i /tmp/homed.id_ecdsa \ + -o "SetEnv PASSWORD=hunter4711" -o "StrictHostKeyChecking no" \ + homedsshtest@localhost echo zzz | tr -d '\r' | tee /tmp/homedsshtest.out + grep -E "^zzz$" /tmp/homedsshtest.out + rm /tmp/homedsshtest.out + + ssh -t -t -4 -p 4711 -i /tmp/homed.id_ecdsa \ + -o "SetEnv PASSWORD=hunter4711" -o "StrictHostKeyChecking no" \ + homedsshtest@localhost env + + wait_for_state homedsshtest inactive +fi + +systemd-analyze log-level info + +touch /testok diff --git a/test/units/TEST-50-DISSECT.DDI.sh b/test/units/TEST-50-DISSECT.DDI.sh new file mode 100755 index 0000000..42c9a43 --- /dev/null +++ b/test/units/TEST-50-DISSECT.DDI.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +# Check that the /sbin/mount.ddi helper works +dir="/tmp/mounthelper.$RANDOM" +mount -t ddi "$MINIMAL_IMAGE.gpt" "$dir" -o ro,X-mount.mkdir,discard +umount -R "$dir" + +# Test systemd-repart --make-ddi=: +if [[ -z "${OPENSSL_CONFIG:?}" ]] || ! command -v mksquashfs &>/dev/null; then + echo "Skipping --make-ddi= tests" + exit 0 +fi + +openssl req -config "$OPENSSL_CONFIG" -subj="/CN=waldo" \ + -x509 -sha256 -nodes -days 365 -newkey rsa:4096 \ + -keyout /tmp/test-50-privkey.key -out /tmp/test-50-cert.crt +mkdir -p /tmp/test-50-confext/etc/extension-release.d/ +echo "foobar50" >/tmp/test-50-confext/etc/waldo +{ + grep -e '^\(ID\|VERSION_ID\)=' /etc/os-release + echo IMAGE_ID=waldo + echo IMAGE_VERSION=7 +} >/tmp/test-50-confext/etc/extension-release.d/extension-release.waldo +mkdir -p /run/confexts + +SYSTEMD_REPART_OVERRIDE_FSTYPE=squashfs \ + systemd-repart -C \ + -s /tmp/test-50-confext \ + --certificate=/tmp/test-50-cert.crt \ + --private-key=/tmp/test-50-privkey.key \ + /run/confexts/waldo.confext.raw +rm -rf /tmp/test-50-confext + +mkdir -p /run/verity.d +cp /tmp/test-50-cert.crt /run/verity.d/ +systemd-dissect --mtree /run/confexts/waldo.confext.raw + +systemd-confext refresh +test "$(</etc/waldo)" = foobar50 +rm /run/confexts/waldo.confext.raw +systemd-confext refresh +test ! -f /etc/waldo + +mkdir -p /tmp/test-50-sysext/usr/lib/extension-release.d/ +# Make sure the sysext is big enough to not fit in the minimum partition size of repart so we know the +# Minimize= logic is working. +truncate --size=50M /tmp/test-50-sysext/usr/waldo +{ + grep -e '^\(ID\|VERSION_ID\)=' /etc/os-release + echo IMAGE_ID=waldo + echo IMAGE_VERSION=7 +} >/tmp/test-50-sysext/usr/lib/extension-release.d/extension-release.waldo +mkdir -p /run/extensions + +SYSTEMD_REPART_OVERRIDE_FSTYPE=squashfs \ + systemd-repart -S \ + -s /tmp/test-50-sysext \ + --certificate=/tmp/test-50-cert.crt \ + --private-key=/tmp/test-50-privkey.key \ + /run/extensions/waldo.sysext.raw + +systemd-dissect --mtree /run/extensions/waldo.sysext.raw +systemd-sysext refresh +test -f /usr/waldo +rm /run/verity.d/test-50-cert.crt /run/extensions/waldo.sysext.raw /tmp/test-50-cert.crt /tmp/test-50-privkey.key +systemd-sysext refresh +test ! -f /usr/waldo diff --git a/test/units/TEST-50-DISSECT.dissect.sh b/test/units/TEST-50-DISSECT.dissect.sh new file mode 100755 index 0000000..563206c --- /dev/null +++ b/test/units/TEST-50-DISSECT.dissect.sh @@ -0,0 +1,745 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +# shellcheck disable=SC2233,SC2235 +set -eux +set -o pipefail + +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +BIND_LOG_SOCKETS=( + --property BindReadOnlyPaths=/dev/log + --property BindReadOnlyPaths=/run/systemd/journal/socket + --property BindReadOnlyPaths=/run/systemd/journal/stdout +) + +systemd-dissect --json=short "$MINIMAL_IMAGE.raw" | \ + grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"' +systemd-dissect "$MINIMAL_IMAGE.raw" | grep -q -F "MARKER=1" +# shellcheck disable=SC2153 +systemd-dissect "$MINIMAL_IMAGE.raw" | grep -q -F -f <(sed 's/"//g' "$OS_RELEASE") + +systemd-dissect --list "$MINIMAL_IMAGE.raw" | grep -q '^etc/os-release$' +systemd-dissect --mtree "$MINIMAL_IMAGE.raw" --mtree-hash yes | \ + grep -qe "^./usr/bin/cat type=file mode=0755 uid=0 gid=0 size=[0-9]* sha256sum=[a-z0-9]*$" +systemd-dissect --mtree "$MINIMAL_IMAGE.raw" --mtree-hash no | \ + grep -qe "^./usr/bin/cat type=file mode=0755 uid=0 gid=0 size=[0-9]*$" + +read -r SHA256SUM1 _ < <(systemd-dissect --copy-from "$MINIMAL_IMAGE.raw" etc/os-release | sha256sum) +test "$SHA256SUM1" != "" +read -r SHA256SUM2 _ < <(systemd-dissect --read-only --with "$MINIMAL_IMAGE.raw" sha256sum etc/os-release) +test "$SHA256SUM2" != "" +test "$SHA256SUM1" = "$SHA256SUM2" + +if systemctl --version | grep -qF -- "+LIBARCHIVE" ; then + # Make sure tarballs are reproducible + read -r SHA256SUM1 _ < <(systemd-dissect --make-archive "$MINIMAL_IMAGE.raw" | sha256sum) + test "$SHA256SUM1" != "" + read -r SHA256SUM2 _ < <(systemd-dissect --make-archive "$MINIMAL_IMAGE.raw" | sha256sum) + test "$SHA256SUM2" != "" + test "$SHA256SUM1" = "$SHA256SUM2" + # Also check that a file we expect to be there is there + systemd-dissect --make-archive "$MINIMAL_IMAGE.raw" | tar t | grep etc/os-release +fi + +mv "$MINIMAL_IMAGE.verity" "$MINIMAL_IMAGE.fooverity" +mv "$MINIMAL_IMAGE.roothash" "$MINIMAL_IMAGE.foohash" +systemd-dissect "$MINIMAL_IMAGE.raw" \ + --json=short \ + --root-hash="$MINIMAL_IMAGE_ROOTHASH" \ + --verity-data="$MINIMAL_IMAGE.fooverity" | \ + grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"' +systemd-dissect "$MINIMAL_IMAGE.raw" \ + --root-hash="$MINIMAL_IMAGE_ROOTHASH" \ + --verity-data="$MINIMAL_IMAGE.fooverity" | \ + grep -q -F "MARKER=1" +systemd-dissect "$MINIMAL_IMAGE.raw" \ + --root-hash="$MINIMAL_IMAGE_ROOTHASH" \ + --verity-data="$MINIMAL_IMAGE.fooverity" | \ + grep -q -F -f <(sed 's/"//g' "$OS_RELEASE") +mv "$MINIMAL_IMAGE.fooverity" "$MINIMAL_IMAGE.verity" +mv "$MINIMAL_IMAGE.foohash" "$MINIMAL_IMAGE.roothash" + +mkdir -p "$IMAGE_DIR/mount" "$IMAGE_DIR/mount2" +systemd-dissect --mount "$MINIMAL_IMAGE.raw" "$IMAGE_DIR/mount" +grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/usr/lib/os-release" +grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/etc/os-release" +grep -q -F "MARKER=1" "$IMAGE_DIR/mount/usr/lib/os-release" +# Verity volume should be shared (opened only once) +systemd-dissect --mount "$MINIMAL_IMAGE.raw" "$IMAGE_DIR/mount2" +verity_count=$(find /dev/mapper/ -name "*verity*" | wc -l) +# In theory we should check that count is exactly one. In practice, libdevmapper +# randomly and unpredictably fails with an unhelpful EINVAL when a device is open +# (and even mounted and in use), so best-effort is the most we can do for now +if [[ "$verity_count" -lt 1 ]]; then + echo "Verity device $MINIMAL_IMAGE.raw not found in /dev/mapper/" + exit 1 +fi +systemd-dissect --umount "$IMAGE_DIR/mount" +systemd-dissect --umount "$IMAGE_DIR/mount2" + +systemd-run -P -p RootImage="$MINIMAL_IMAGE.raw" "${BIND_LOG_SOCKETS[@]}" cat /usr/lib/os-release | grep -q -F "MARKER=1" +mv "$MINIMAL_IMAGE.verity" "$MINIMAL_IMAGE.fooverity" +mv "$MINIMAL_IMAGE.roothash" "$MINIMAL_IMAGE.foohash" +systemd-run -P \ + -p RootImage="$MINIMAL_IMAGE.raw" \ + -p RootHash="$MINIMAL_IMAGE.foohash" \ + -p RootVerity="$MINIMAL_IMAGE.fooverity" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/os-release | grep -q -F "MARKER=1" +# Let's use the long option name just here as a test +systemd-run -P \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + --property RootHash="$MINIMAL_IMAGE_ROOTHASH" \ + --property RootVerity="$MINIMAL_IMAGE.fooverity" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/os-release | grep -q -F "MARKER=1" +mv "$MINIMAL_IMAGE.fooverity" "$MINIMAL_IMAGE.verity" +mv "$MINIMAL_IMAGE.foohash" "$MINIMAL_IMAGE.roothash" + +# Derive partition UUIDs from root hash, in UUID syntax +ROOT_UUID="$(systemd-id128 -u show "$(head -c 32 "$MINIMAL_IMAGE.roothash")" -u | tail -n 1 | cut -b 6-)" +VERITY_UUID="$(systemd-id128 -u show "$(tail -c 32 "$MINIMAL_IMAGE.roothash")" -u | tail -n 1 | cut -b 6-)" + +systemd-dissect --json=short \ + --root-hash "$MINIMAL_IMAGE_ROOTHASH" \ + "$MINIMAL_IMAGE.gpt" | \ + grep -q '{"rw":"ro","designator":"root","partition_uuid":"'"$ROOT_UUID"'","partition_label":"Root Partition","fstype":"squashfs","architecture":"'"$ARCHITECTURE"'","verity":"signed",' +systemd-dissect --json=short \ + --root-hash "$MINIMAL_IMAGE_ROOTHASH" \ + "$MINIMAL_IMAGE.gpt" | \ + grep -q '{"rw":"ro","designator":"root-verity","partition_uuid":"'"$VERITY_UUID"'","partition_label":"Verity Partition","fstype":"DM_verity_hash","architecture":"'"$ARCHITECTURE"'","verity":null,' +if [[ -n "${OPENSSL_CONFIG:-}" ]]; then + systemd-dissect --json=short \ + --root-hash "$MINIMAL_IMAGE_ROOTHASH" \ + "$MINIMAL_IMAGE.gpt" | \ + grep -qE '{"rw":"ro","designator":"root-verity-sig","partition_uuid":"'".*"'","partition_label":"Signature Partition","fstype":"verity_hash_signature","architecture":"'"$ARCHITECTURE"'","verity":null,' +fi +systemd-dissect --root-hash "$MINIMAL_IMAGE_ROOTHASH" "$MINIMAL_IMAGE.gpt" | grep -q -F "MARKER=1" +systemd-dissect --root-hash "$MINIMAL_IMAGE_ROOTHASH" "$MINIMAL_IMAGE.gpt" | grep -q -F -f <(sed 's/"//g' "$OS_RELEASE") + +# Test image policies +systemd-dissect --validate "$MINIMAL_IMAGE.gpt" +systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy='*' +(! systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy='~') +(! systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy='-') +(! systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=absent) +(! systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=swap=unprotected+encrypted+verity) +systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=unprotected +systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=verity +systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=verity:root-verity-sig=unused+absent +systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=verity:swap=absent +systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=verity:swap=absent+unprotected +(! systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=verity:root-verity=unused+absent) +systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=signed +(! systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=signed:root-verity-sig=unused+absent) +(! systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=signed:root-verity=unused+absent) + +# Test RootImagePolicy= unit file setting +systemd-run --wait -P \ + -p RootImage="$MINIMAL_IMAGE.gpt" \ + -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \ + -p MountAPIVFS=yes \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/os-release | grep -q -F "MARKER=1" +systemd-run --wait -P \ + -p RootImage="$MINIMAL_IMAGE.gpt" \ + -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \ + -p RootImagePolicy='*' \ + -p MountAPIVFS=yes \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/os-release | grep -q -F "MARKER=1" +(! systemd-run --wait -P \ + -p RootImage="$MINIMAL_IMAGE.gpt" \ + -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \ + -p RootImagePolicy='~' \ + -p MountAPIVFS=yes \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/os-release | grep -q -F "MARKER=1") +(! systemd-run --wait -P \ + -p RootImage="$MINIMAL_IMAGE.gpt" \ + -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \ + -p RootImagePolicy='-' \ + -p MountAPIVFS=yes \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/os-release | grep -q -F "MARKER=1") +(! systemd-run --wait -P \ + -p RootImage="$MINIMAL_IMAGE.gpt" \ + -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \ + -p RootImagePolicy='root=absent' \ + -p MountAPIVFS=yes \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/os-release | grep -q -F "MARKER=1") +systemd-run --wait -P \ + -p RootImage="$MINIMAL_IMAGE.gpt" \ + -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \ + -p RootImagePolicy='root=verity' \ + -p MountAPIVFS=yes \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/os-release | grep -q -F "MARKER=1" +systemd-run --wait -P \ + -p RootImage="$MINIMAL_IMAGE.gpt" \ + -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \ + -p RootImagePolicy='root=signed' \ + -p MountAPIVFS=yes \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/os-release | grep -q -F "MARKER=1" +(! systemd-run --wait -P \ + -p RootImage="$MINIMAL_IMAGE.gpt" \ + -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \ + -p RootImagePolicy='root=encrypted' \ + -p MountAPIVFS=yes \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/os-release | grep -q -F "MARKER=1") + +systemd-dissect --root-hash "$MINIMAL_IMAGE_ROOTHASH" --mount "$MINIMAL_IMAGE.gpt" "$IMAGE_DIR/mount" +grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/usr/lib/os-release" +grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/etc/os-release" +grep -q -F "MARKER=1" "$IMAGE_DIR/mount/usr/lib/os-release" +systemd-dissect --umount "$IMAGE_DIR/mount" + +systemd-dissect --root-hash "$MINIMAL_IMAGE_ROOTHASH" --mount "$MINIMAL_IMAGE.gpt" --in-memory "$IMAGE_DIR/mount" +grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/usr/lib/os-release" +grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/etc/os-release" +grep -q -F "MARKER=1" "$IMAGE_DIR/mount/usr/lib/os-release" +systemd-dissect --umount "$IMAGE_DIR/mount" + +# add explicit -p MountAPIVFS=yes once to test the parser +systemd-run -P \ + -p RootImage="$MINIMAL_IMAGE.gpt" \ + -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \ + -p MountAPIVFS=yes \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/os-release | grep -q -F "MARKER=1" +systemd-run -P \ + -p RootImage="$MINIMAL_IMAGE.raw" \ + -p RootImageOptions="root:nosuid,dev home:ro,dev ro,noatime" \ + "${BIND_LOG_SOCKETS[@]}" \ + mount | grep -F "squashfs" | grep -q -F "nosuid" +systemd-run -P \ + -p RootImage="$MINIMAL_IMAGE.gpt" \ + -p RootImageOptions="root:ro,noatime root:ro,dev" \ + "${BIND_LOG_SOCKETS[@]}" \ + mount | grep -F "squashfs" | grep -q -F "noatime" + +mkdir -p "$IMAGE_DIR/result" +cat >/run/systemd/system/testservice-50a.service <<EOF +[Service] +Type=oneshot +ExecStart=bash -c "mount >/run/result/a" +BindPaths=$IMAGE_DIR/result:/run/result +TemporaryFileSystem=/run +RootImage=$MINIMAL_IMAGE.raw +RootImageOptions=root:ro,noatime home:ro,dev relatime,dev +RootImageOptions=nosuid,dev +BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout +EOF +systemctl start testservice-50a.service +grep -F "squashfs" "$IMAGE_DIR/result/a" | grep -q -F "noatime" +grep -F "squashfs" "$IMAGE_DIR/result/a" | grep -q -F -v "nosuid" + +cat >/run/systemd/system/testservice-50b.service <<EOF +[Service] +Type=oneshot +ExecStart=bash -c "mount >/run/result/b" +BindPaths=$IMAGE_DIR/result:/run/result +TemporaryFileSystem=/run +RootImage=$MINIMAL_IMAGE.gpt +RootImageOptions=root:ro,noatime,nosuid home:ro,dev nosuid,dev +RootImageOptions=home:ro,dev nosuid,dev,%%foo +# this is the default, but let's specify once to test the parser +MountAPIVFS=yes +BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout +EOF +systemctl start testservice-50b.service +grep -F "squashfs" "$IMAGE_DIR/result/b" | grep -q -F "noatime" + +# Check that specifier escape is applied %%foo → %foo +busctl get-property org.freedesktop.systemd1 \ + /org/freedesktop/systemd1/unit/testservice_2d50b_2eservice \ + org.freedesktop.systemd1.Service RootImageOptions | grep -F "nosuid,dev,%foo" + +# Now do some checks with MountImages, both by itself, with options and in combination with RootImage, and as single FS or GPT image +systemd-run -P \ + -p MountImages="$MINIMAL_IMAGE.gpt:/run/img1 $MINIMAL_IMAGE.raw:/run/img2" \ + cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1" +systemd-run -P \ + -p MountImages="$MINIMAL_IMAGE.gpt:/run/img1 $MINIMAL_IMAGE.raw:/run/img2" \ + cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1" +systemd-run -P \ + -p MountImages="$MINIMAL_IMAGE.gpt:/run/img1 $MINIMAL_IMAGE.raw:/run/img2:nosuid,dev" \ + mount | grep -F "squashfs" | grep -q -F "nosuid" +systemd-run -P \ + -p MountImages="$MINIMAL_IMAGE.gpt:/run/img1:root:nosuid $MINIMAL_IMAGE.raw:/run/img2:home:suid" \ + mount | grep -F "squashfs" | grep -q -F "nosuid" +systemd-run -P \ + -p MountImages="$MINIMAL_IMAGE.raw:/run/img2\:3" \ + cat /run/img2:3/usr/lib/os-release | grep -q -F "MARKER=1" +systemd-run -P \ + -p MountImages="$MINIMAL_IMAGE.raw:/run/img2\:3:nosuid" \ + mount | grep -F "squashfs" | grep -q -F "nosuid" +systemd-run -P \ + -p TemporaryFileSystem=/run \ + -p RootImage="$MINIMAL_IMAGE.raw" \ + -p MountImages="$MINIMAL_IMAGE.gpt:/run/img1 $MINIMAL_IMAGE.raw:/run/img2" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/os-release | grep -q -F "MARKER=1" +systemd-run -P \ + -p TemporaryFileSystem=/run \ + -p RootImage="$MINIMAL_IMAGE.raw" \ + -p MountImages="$MINIMAL_IMAGE.gpt:/run/img1 $MINIMAL_IMAGE.raw:/run/img2" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1" +systemd-run -P \ + -p TemporaryFileSystem=/run \ + -p RootImage="$MINIMAL_IMAGE.gpt" \ + -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \ + -p MountImages="$MINIMAL_IMAGE.gpt:/run/img1 $MINIMAL_IMAGE.raw:/run/img2" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1" +cat >/run/systemd/system/testservice-50c.service <<EOF +[Service] +MountAPIVFS=yes +TemporaryFileSystem=/run +RootImage=$MINIMAL_IMAGE.raw +BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout +MountImages=$MINIMAL_IMAGE.gpt:/run/img1:root:noatime:home:relatime +MountImages=$MINIMAL_IMAGE.raw:/run/img2\:3:nosuid +ExecStart=bash -c "cat /run/img1/usr/lib/os-release >/run/result/c" +ExecStart=bash -c "cat /run/img2:3/usr/lib/os-release >>/run/result/c" +ExecStart=bash -c "mount >>/run/result/c" +BindPaths=$IMAGE_DIR/result:/run/result +Type=oneshot +EOF +systemctl start testservice-50c.service +grep -q -F "MARKER=1" "$IMAGE_DIR/result/c" +grep -F "squashfs" "$IMAGE_DIR/result/c" | grep -q -F "noatime" +grep -F "squashfs" "$IMAGE_DIR/result/c" | grep -q -F -v "nosuid" + +# Adding a new mounts at runtime works if the unit is in the active state, +# so use Type=notify to make sure there's no race condition in the test +cat >/run/systemd/system/testservice-50d.service <<EOF +[Service] +RuntimeMaxSec=300 +Type=notify +RemainAfterExit=yes +MountAPIVFS=yes +PrivateTmp=yes +ExecStart=sh -c ' \\ + systemd-notify --ready; \\ + while [ ! -f /tmp/img/usr/lib/os-release ] || ! grep -q -F MARKER /tmp/img/usr/lib/os-release; do \\ + sleep 0.1; \\ + done; \\ + mount; \\ + mount | grep -F "on /tmp/img type squashfs" | grep -q -F "nosuid"; \\ +' +EOF +systemctl start testservice-50d.service + +# Mount twice to exercise mount-beneath (on kernel 6.5+, on older kernels it will just overmount) +mkdir -p /tmp/wrong/foo +mksquashfs /tmp/wrong/foo /tmp/wrong.raw +systemctl mount-image --mkdir testservice-50d.service /tmp/wrong.raw /tmp/img +test "$(systemctl show -P SubState testservice-50d.service)" = "running" +systemctl mount-image --mkdir testservice-50d.service "$MINIMAL_IMAGE.raw" /tmp/img root:nosuid +# shellcheck disable=SC2016 +timeout 30s bash -xec 'while [[ $(systemctl show -P SubState testservice-50d.service) == running ]]; do sleep .2; done' +systemctl is-active testservice-50d.service + +# ExtensionImages will set up an overlay +systemd-run -P \ + --property ExtensionImages=/tmp/app0.raw \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /opt/script0.sh | grep -q -F "extension-release.app0" +systemd-run -P \ + --property ExtensionImages=/tmp/app0.raw \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" +systemd-run -P \ + --property ExtensionImages="/tmp/app0.raw /tmp/app1.raw" \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /opt/script0.sh | grep -q -F "extension-release.app0" +systemd-run -P \ + --property ExtensionImages="/tmp/app0.raw /tmp/app1.raw" \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" +systemd-run -P \ + --property ExtensionImages="/tmp/app0.raw /tmp/app1.raw" \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /opt/script1.sh | grep -q -F "extension-release.app2" +systemd-run -P \ + --property ExtensionImages="/tmp/app0.raw /tmp/app1.raw" \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1" +systemd-run -P \ + --property ExtensionImages=/tmp/app-nodistro.raw \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" +systemd-run -P \ + --property ExtensionImages=/etc/service-scoped-test.raw \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123" +# Check that using a symlink to NAME-VERSION.raw works as long as the symlink has the correct name NAME.raw +mkdir -p /tmp/symlink-test/ +cp /tmp/app-nodistro.raw /tmp/symlink-test/app-nodistro-v1.raw +ln -fs /tmp/symlink-test/app-nodistro-v1.raw /tmp/symlink-test/app-nodistro.raw +systemd-run -P \ + --property ExtensionImages=/tmp/symlink-test/app-nodistro.raw \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" + +# Symlink check again but for confext +mkdir -p /etc/symlink-test/ +cp /etc/service-scoped-test.raw /etc/symlink-test/service-scoped-test-v1.raw +ln -fs /etc/symlink-test/service-scoped-test-v1.raw /etc/symlink-test/service-scoped-test.raw +systemd-run -P \ + --property ExtensionImages=/etc/symlink-test/service-scoped-test.raw \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123" +# And again mixing sysext and confext +systemd-run -P \ + --property ExtensionImages=/tmp/symlink-test/app-nodistro.raw \ + --property ExtensionImages=/etc/symlink-test/service-scoped-test.raw \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123" +systemd-run -P \ + --property ExtensionImages=/tmp/symlink-test/app-nodistro.raw \ + --property ExtensionImages=/etc/symlink-test/service-scoped-test.raw \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" + +cat >/run/systemd/system/testservice-50e.service <<EOF +[Service] +MountAPIVFS=yes +TemporaryFileSystem=/run /var/lib +StateDirectory=app0 +RootImage=$MINIMAL_IMAGE.raw +ExtensionImages=/tmp/app0.raw /tmp/app1.raw:nosuid +BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout +# Relevant only for sanitizer runs +UnsetEnvironment=LD_PRELOAD +ExecStart=bash -c '/opt/script0.sh | grep ID' +ExecStart=bash -c '/opt/script1.sh | grep ID' +Type=oneshot +RemainAfterExit=yes +EOF +systemctl start testservice-50e.service +systemctl is-active testservice-50e.service + +# Check vpick support in ExtensionImages= +VBASE="vtest$RANDOM" +VDIR="/tmp/$VBASE.v" +mkdir "$VDIR" + +ln -s /tmp/app0.raw "$VDIR/${VBASE}_0.raw" +ln -s /tmp/app1.raw "$VDIR/${VBASE}_1.raw" + +systemd-run -P -p ExtensionImages="$VDIR" bash -c '/opt/script1.sh | grep ID' + +rm -rf "$VDIR" + +# ExtensionDirectories will set up an overlay +mkdir -p "$IMAGE_DIR/app0" "$IMAGE_DIR/app1" "$IMAGE_DIR/app-nodistro" "$IMAGE_DIR/service-scoped-test" +(! systemd-run -P \ + --property ExtensionDirectories="$IMAGE_DIR/nonexistent" \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /opt/script0.sh) +(! systemd-run -P \ + --property ExtensionDirectories="$IMAGE_DIR/app0" \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /opt/script0.sh) +systemd-dissect --mount /tmp/app0.raw "$IMAGE_DIR/app0" +systemd-dissect --mount /tmp/app1.raw "$IMAGE_DIR/app1" +systemd-dissect --mount /tmp/app-nodistro.raw "$IMAGE_DIR/app-nodistro" +systemd-dissect --mount /etc/service-scoped-test.raw "$IMAGE_DIR/service-scoped-test" +systemd-run -P \ + --property ExtensionDirectories="$IMAGE_DIR/app0" \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /opt/script0.sh | grep -q -F "extension-release.app0" +systemd-run -P \ + --property ExtensionDirectories="$IMAGE_DIR/app0" \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" +systemd-run -P \ + --property ExtensionDirectories="$IMAGE_DIR/app0 $IMAGE_DIR/app1" \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /opt/script0.sh | grep -q -F "extension-release.app0" +systemd-run -P \ + --property ExtensionDirectories="$IMAGE_DIR/app0 $IMAGE_DIR/app1" \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" +systemd-run -P \ + --property ExtensionDirectories="$IMAGE_DIR/app0 $IMAGE_DIR/app1" \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /opt/script1.sh | grep -q -F "extension-release.app2" +systemd-run -P \ + --property ExtensionDirectories="$IMAGE_DIR/app0 $IMAGE_DIR/app1" \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1" +systemd-run -P \ + --property ExtensionDirectories="$IMAGE_DIR/app-nodistro" \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" +systemd-run -P \ + --property ExtensionDirectories="$IMAGE_DIR/service-scoped-test" \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + "${BIND_LOG_SOCKETS[@]}" \ + cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123" +cat >/run/systemd/system/testservice-50f.service <<EOF +[Service] +MountAPIVFS=yes +TemporaryFileSystem=/run /var/lib +StateDirectory=app0 +RootImage=$MINIMAL_IMAGE.raw +BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout +ExtensionDirectories=$IMAGE_DIR/app0 $IMAGE_DIR/app1 +# Relevant only for sanitizer runs +UnsetEnvironment=LD_PRELOAD +ExecStart=bash -c '/opt/script0.sh | grep ID' +ExecStart=bash -c '/opt/script1.sh | grep ID' +Type=oneshot +RemainAfterExit=yes +EOF +systemctl start testservice-50f.service +systemctl is-active testservice-50f.service + +# Check vpick support in ExtensionDirectories= +VBASE="vtest$RANDOM" +VDIR="/tmp/$VBASE.v" +mkdir "$VDIR" + +ln -s "$IMAGE_DIR/app0" "$VDIR/${VBASE}_0" +ln -s "$IMAGE_DIR/app1" "$VDIR/${VBASE}_1" + +systemd-run -P --property ExtensionDirectories="$VDIR" cat /opt/script1.sh | grep -q -F "extension-release.app2" + +rm -rf "$VDIR" + +systemd-dissect --umount "$IMAGE_DIR/app0" +systemd-dissect --umount "$IMAGE_DIR/app1" + +# Test that an extension consisting of an empty directory under /etc/extensions/ takes precedence +mkdir -p /var/lib/extensions/ +ln -s /tmp/app-nodistro.raw /var/lib/extensions/app-nodistro.raw +systemd-sysext merge +grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file +systemd-sysext unmerge +mkdir -p /etc/extensions/app-nodistro +systemd-sysext merge +test ! -e /usr/lib/systemd/system/some_file +systemd-sysext unmerge +rmdir /etc/extensions/app-nodistro + +# Similar, but go via varlink +varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.List '{}' +(! grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file ) +varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.Merge '{}' +grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file +varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.Refresh '{}' +grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file +varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.Unmerge '{}' +(! grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file ) + +# Check that extensions cannot contain os-release +mkdir -p /run/extensions/app-reject/usr/lib/{extension-release.d/,systemd/system} +echo "ID=_any" >/run/extensions/app-reject/usr/lib/extension-release.d/extension-release.app-reject +echo "ID=_any" >/run/extensions/app-reject/usr/lib/os-release +touch /run/extensions/app-reject/usr/lib/systemd/system/other_file +(! systemd-sysext merge) +test ! -e /usr/lib/systemd/system/some_file +test ! -e /usr/lib/systemd/system/other_file +systemd-sysext unmerge +rm -rf /run/extensions/app-reject +rm /var/lib/extensions/app-nodistro.raw + +# Some super basic test that RootImage= works with .v/ dirs +VBASE="vtest$RANDOM" +VDIR="/tmp/$VBASE.v" +mkdir "$VDIR" + +ln -s "$MINIMAL_IMAGE.raw" "$VDIR/${VBASE}_33.raw" +ln -s "$MINIMAL_IMAGE.raw" "$VDIR/${VBASE}_34.raw" +ln -s "$MINIMAL_IMAGE.raw" "$VDIR/${VBASE}_35.raw" + +systemd-run -P -p RootImage="$VDIR" "${BIND_LOG_SOCKETS[@]}" cat /usr/lib/os-release | grep -q -F "MARKER=1" + +rm "$VDIR/${VBASE}_33.raw" "$VDIR/${VBASE}_34.raw" "$VDIR/${VBASE}_35.raw" +rmdir "$VDIR" + +mkdir -p /run/machines /run/portables /run/extensions +touch /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw + +systemd-dissect --discover --json=short >/tmp/discover.json +grep -q -F '{"name":"a","type":"raw","class":"machine","ro":false,"path":"/run/machines/a.raw"' /tmp/discover.json +grep -q -F '{"name":"b","type":"raw","class":"portable","ro":false,"path":"/run/portables/b.raw"' /tmp/discover.json +grep -q -F '{"name":"c","type":"raw","class":"sysext","ro":false,"path":"/run/extensions/c.raw"' /tmp/discover.json +rm /tmp/discover.json /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw + +LOOP="$(systemd-dissect --attach --loop-ref=waldo "$MINIMAL_IMAGE.raw")" + +# Wait until the symlinks we want to test are established +udevadm trigger -w "$LOOP" + +# Check if the /dev/loop/* symlinks really reference the right device +test /dev/disk/by-loop-ref/waldo -ef "$LOOP" + +if [ "$(stat -c '%Hd:%Ld' "$MINIMAL_IMAGE.raw")" != '?d:?d' ] ; then + # Old stat didn't know the %Hd and %Ld specifiers and turned them into ?d + # instead. Let's simply skip the test on such old systems. + test "$(stat -c '/dev/disk/by-loop-inode/%Hd:%Ld-%i' "$MINIMAL_IMAGE.raw")" -ef "$LOOP" +fi + +# Detach by loopback device +systemd-dissect --detach "$LOOP" + +# Test long reference name. +# Note, sizeof_field(struct loop_info64, lo_file_name) == 64, +# and --loop-ref accepts upto 63 characters, and udev creates symlink +# based on the name when it has upto _62_ characters. +name="$(for _ in {1..62}; do echo -n 'x'; done)" +LOOP="$(systemd-dissect --attach --loop-ref="$name" "$MINIMAL_IMAGE.raw")" +udevadm trigger -w "$LOOP" + +# Check if the /dev/disk/by-loop-ref/$name symlink really references the right device +test "/dev/disk/by-loop-ref/$name" -ef "$LOOP" + +# Detach by the /dev/disk/by-loop-ref symlink +systemd-dissect --detach "/dev/disk/by-loop-ref/$name" + +name="$(for _ in {1..63}; do echo -n 'x'; done)" +LOOP="$(systemd-dissect --attach --loop-ref="$name" "$MINIMAL_IMAGE.raw")" +udevadm trigger -w "$LOOP" + +# Check if the /dev/disk/by-loop-ref/$name symlink does not exist +test ! -e "/dev/disk/by-loop-ref/$name" + +# Detach by backing inode +systemd-dissect --detach "$MINIMAL_IMAGE.raw" +(! systemd-dissect --detach "$MINIMAL_IMAGE.raw") + +# check for confext functionality +mkdir -p /run/confexts/test/etc/extension-release.d +echo "ID=_any" >/run/confexts/test/etc/extension-release.d/extension-release.test +echo "ARCHITECTURE=_any" >>/run/confexts/test/etc/extension-release.d/extension-release.test +echo "MARKER_CONFEXT_123" >/run/confexts/test/etc/testfile +cat <<EOF >/run/confexts/test/etc/testscript +#!/bin/bash +echo "This should not happen" +EOF +chmod +x /run/confexts/test/etc/testscript +systemd-confext merge +grep -q -F "MARKER_CONFEXT_123" /etc/testfile +(! /etc/testscript) +systemd-confext status +systemd-confext unmerge +rm -rf /run/confexts/ + +unsquashfs -no-xattrs -d /tmp/img "$MINIMAL_IMAGE.raw" +systemd-run --unit=test-root-ephemeral \ + -p RootDirectory=/tmp/img \ + -p RootEphemeral=yes \ + -p Type=exec \ + "${BIND_LOG_SOCKETS[@]}" \ + bash -c "touch /abc && sleep infinity" +test -n "$(ls -A /var/lib/systemd/ephemeral-trees)" +systemctl stop test-root-ephemeral +# shellcheck disable=SC2016 +timeout 10 bash -c 'until test -z "$(ls -A /var/lib/systemd/ephemeral-trees)"; do sleep .5; done' +test ! -f /tmp/img/abc + +systemd-dissect --mtree /tmp/img >/dev/null +systemd-dissect --list /tmp/img >/dev/null + +read -r SHA256SUM1 _ < <(systemd-dissect --copy-from /tmp/img etc/os-release | sha256sum) +test "$SHA256SUM1" != "" + +echo abc > abc +systemd-dissect --copy-to /tmp/img abc /abc +test -f /tmp/img/abc + +# Test for dissect tool support with systemd-sysext +mkdir -p /run/extensions/ testkit/usr/lib/extension-release.d/ +echo "ID=_any" >testkit/usr/lib/extension-release.d/extension-release.testkit +echo "ARCHITECTURE=_any" >>testkit/usr/lib/extension-release.d/extension-release.testkit +echo "MARKER_SYSEXT_123" >testkit/usr/lib/testfile +mksquashfs testkit/ testkit.raw +cp testkit.raw /run/extensions/ +unsquashfs -l /run/extensions/testkit.raw +systemd-dissect --no-pager /run/extensions/testkit.raw | grep -q '✓ sysext for portable service' +systemd-dissect --no-pager /run/extensions/testkit.raw | grep -q '✓ sysext for system' +systemd-sysext merge +systemd-sysext status +grep -q -F "MARKER_SYSEXT_123" /usr/lib/testfile +systemd-sysext unmerge +rm -rf /run/extensions/ testkit/ + +# Test for dissect tool support with systemd-confext +mkdir -p /run/confexts/ testjob/etc/extension-release.d/ +echo "ID=_any" >testjob/etc/extension-release.d/extension-release.testjob +echo "ARCHITECTURE=_any" >>testjob/etc/extension-release.d/extension-release.testjob +echo "MARKER_CONFEXT_123" >testjob/etc/testfile +mksquashfs testjob/ testjob.raw +cp testjob.raw /run/confexts/ +unsquashfs -l /run/confexts/testjob.raw +systemd-dissect --no-pager /run/confexts/testjob.raw | grep -q '✓ confext for system' +systemd-dissect --no-pager /run/confexts/testjob.raw | grep -q '✓ confext for portable service' +systemd-confext merge +systemd-confext status +grep -q -F "MARKER_CONFEXT_123" /etc/testfile +systemd-confext unmerge +rm -rf /run/confexts/ testjob/ + +systemd-run -P -p RootImage="$MINIMAL_IMAGE.raw" "${BIND_LOG_SOCKETS[@]}" cat /run/host/os-release | cmp "$OS_RELEASE" + +# Test that systemd-sysext reloads the daemon. +mkdir -p /var/lib/extensions/ +ln -s /tmp/app-reload.raw /var/lib/extensions/app-reload.raw +systemd-sysext merge --no-reload +# the service should not be running +(! systemctl --quiet is-active foo.service) +systemd-sysext unmerge --no-reload +systemd-sysext merge +journalctl --sync +set +o pipefail +# "journalctl -u foo.service" may not work as expected, especially entries for _TRANSPORT=stdout, +# for short-living services or when the service manager generates debugging logs. +# Instead, SYSLOG_IDENTIFIER= should be reliable for stdout. Let's use it. +timeout -v 30s journalctl -b SYSLOG_IDENTIFIER=echo _TRANSPORT=stdout -o cat -n all --follow | grep -m 1 -q '^foo$' +set -o pipefail +systemd-sysext unmerge --no-reload +# Grep on the Warning to find the warning helper mentioning the daemon reload. +systemctl status foo.service 2>&1 | grep -q -F "Warning" +systemd-sysext merge +systemd-sysext unmerge +systemctl status foo.service 2>&1 | grep -v -q -F "Warning" +rm /var/lib/extensions/app-reload.raw + +# Sneak in a couple of expected-to-fail invocations to cover +# https://github.com/systemd/systemd/issues/29610 +(! systemd-run -P -p MountImages="/this/should/definitely/not/exist.img:/run/img2\:3:nosuid" false) +(! systemd-run -P -p ExtensionImages="/this/should/definitely/not/exist.img" false) +(! systemd-run -P -p RootImage="/this/should/definitely/not/exist.img" false) +(! systemd-run -P -p ExtensionDirectories="/foo/bar /foo/baz" false) diff --git a/test/units/TEST-50-DISSECT.mountfsd.sh b/test/units/TEST-50-DISSECT.mountfsd.sh new file mode 100755 index 0000000..604a9db --- /dev/null +++ b/test/units/TEST-50-DISSECT.mountfsd.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +if [[ ! -f /usr/lib/systemd/system/systemd-mountfsd.socket ]] || \ + [[ ! -f /usr/lib/systemd/system/systemd-nsresourced.socket ]] || \ + ! command -v mksquashfs || \ + ! grep -q bpf /sys/kernel/security/lsm || + ! find /usr/lib* -name libbpf.so.1 2>/dev/null | grep . || \ + systemd-analyze compare-versions "$(uname -r)" lt 6.5 || \ + systemd-analyze compare-versions "$(pkcheck --version | awk '{print $3}')" lt 124; then + echo "Skipping mountfsd/nsresourced tests" + exit 0 +fi + +at_exit() { + set +e + + umount -R /tmp/unpriv/mount + rmdir /tmp/unpriv + rm -f /tmp/test-50-unpriv-privkey.key /tmp/test-50-unpriv-cert.crt /run/verity.d/test-50-unpriv-cert.crt + rm -f /var/tmp/unpriv.raw /tmp/unpriv.raw.mtree /tmp/unpriv2.raw.mtree + rm -f /tmp/unpriv.out /tmp/unpriv.out2 /tmp/unpriv.out3 +} + +trap at_exit EXIT + +systemctl start systemd-mountfsd.socket systemd-nsresourced.socket + +openssl req -config "$OPENSSL_CONFIG" -subj="/CN=waldo" \ + -x509 -sha256 -nodes -days 365 -newkey rsa:4096 \ + -keyout /tmp/test-50-unpriv-privkey.key -out /tmp/test-50-unpriv-cert.crt + +systemd-dissect --mkdir --mount "$MINIMAL_IMAGE.raw" /tmp/unpriv/mount +SYSTEMD_REPART_OVERRIDE_FSTYPE=squashfs \ + systemd-repart -P \ + -s /tmp/unpriv/mount \ + --certificate=/tmp/test-50-unpriv-cert.crt \ + --private-key=/tmp/test-50-unpriv-privkey.key \ + /var/tmp/unpriv.raw +systemd-dissect --rmdir --umount /tmp/unpriv/mount + +systemd-dissect --image-policy='root=unprotected:=absent+unused' /var/tmp/unpriv.raw +systemd-dissect --image-policy='root=unprotected:=absent+unused' --mtree /var/tmp/unpriv.raw >/tmp/unpriv.raw.mtree + +# Run unpriv, should fail due to lack of privs +(! runas testuser systemd-dissect /var/tmp/unpriv.raw) +(! runas testuser systemd-dissect --mtree /var/tmp/unpriv.raw) + +if (SYSTEMD_LOG_TARGET=console varlinkctl call \ + /run/systemd/userdb/io.systemd.NamespaceResource \ + io.systemd.NamespaceResource.AllocateUserRange \ + '{"name":"test-supported","size":65536,"userNamespaceFileDescriptor":0}' 2>&1 || true) | + grep -q "io.systemd.NamespaceResource.UserNamespaceInterfaceNotSupported"; then + echo "User namespace interface not supported, skipping mountfsd/nsresourced tests" + exit 0 +fi + +# Install key in keychain +cp /tmp/test-50-unpriv-cert.crt /run/verity.d + +# Now run unpriv again, should be OK now. +runas testuser systemd-dissect /var/tmp/unpriv.raw +runas testuser systemd-dissect --mtree /var/tmp/unpriv.raw >/tmp/unpriv2.raw.mtree + +# Check that unpriv and priv run yielded same results +cmp /tmp/unpriv.raw.mtree /tmp/unpriv2.raw.mtree + +# Make sure nspawn works unpriv, too (for now do not nest) +if ! systemd-detect-virt -c; then + systemd-nspawn --pipe -i /var/tmp/unpriv.raw --read-only echo thisisatest > /tmp/unpriv.out + echo thisisatest | cmp /tmp/unpriv.out - + + # The unpriv user has no rights to lock the image or write to it. Let's + # turn off both for this test, so that we don't have to copy the image + # around. + systemd-run -M testuser@ --user --pipe \ + -p Environment=SYSTEMD_NSPAWN_LOCK=0 \ + -p Delegate=1 \ + -p DelegateSubgroup=supervisor \ + -p Environment=SYSTEMD_LOG_LEVEL=debug \ + --wait -- \ + systemd-nspawn --keep-unit -i /var/tmp/unpriv.raw --read-only --pipe echo thisisatest >/tmp/unpriv.out2 + echo thisisatest | cmp /tmp/unpriv.out2 - +fi + +systemd-run -M testuser@ --user --pipe -p RootImage=/var/tmp/unpriv.raw -p PrivateUsers=1 --wait echo thisisatest >/tmp/unpriv.out3 +echo thisisatest | cmp /tmp/unpriv.out3 - diff --git a/test/units/TEST-50-DISSECT.sh b/test/units/TEST-50-DISSECT.sh new file mode 100755 index 0000000..0e378a8 --- /dev/null +++ b/test/units/TEST-50-DISSECT.sh @@ -0,0 +1,215 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh + +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +# Setup shared stuff & run all subtests + +at_exit() { + set +e + + if [[ -z "${IMAGE_DIR:-}" ]]; then + return + fi + + while read -r dir; do + if mountpoint -q "$dir"; then + umount -Rv "$dir" + fi + done < <(find "${IMAGE_DIR}" -mindepth 1 -maxdepth 1 -type d) + + rm -rf "$IMAGE_DIR" +} + +trap at_exit EXIT + +: "Setup base images" + +export SYSTEMD_LOG_LEVEL=debug +export ARCHITECTURE +export IMAGE_DIR +export MACHINE +export MINIMAL_IMAGE +export MINIMAL_IMAGE_ROOTHASH +export OPENSSL_CONFIG +export OS_RELEASE +export ROOT_GUID +export SIGNATURE_GUID +export VERITY_GUID + +machine="$(uname -m)" +if [[ "$machine" == "x86_64" ]]; then + ROOT_GUID=4f68bce3-e8cd-4db1-96e7-fbcaf984b709 + VERITY_GUID=2c7357ed-ebd2-46d9-aec1-23d437ec2bf5 + SIGNATURE_GUID=41092b05-9fc8-4523-994f-2def0408b176 + ARCHITECTURE="x86-64" +elif [[ "$machine" =~ ^(i386|i686|x86)$ ]]; then + ROOT_GUID=44479540-f297-41b2-9af7-d131d5f0458a + VERITY_GUID=d13c5d3b-b5d1-422a-b29f-9454fdc89d76 + SIGNATURE_GUID=5996fc05-109c-48de-808b-23fa0830b676 + ARCHITECTURE="x86" +elif [[ "$machine" =~ ^(aarch64|aarch64_be|armv8b|armv8l)$ ]]; then + ROOT_GUID=b921b045-1df0-41c3-af44-4c6f280d3fae + VERITY_GUID=df3300ce-d69f-4c92-978c-9bfb0f38d820 + SIGNATURE_GUID=6db69de6-29f4-4758-a7a5-962190f00ce3 + ARCHITECTURE="arm64" +elif [[ "$machine" == "arm" ]]; then + ROOT_GUID=69dad710-2ce4-4e3c-b16c-21a1d49abed3 + VERITY_GUID=7386cdf2-203c-47a9-a498-f2ecce45a2d6 + SIGNATURE_GUID=42b0455f-eb11-491d-98d3-56145ba9d037 + ARCHITECTURE="arm" +elif [[ "$machine" == "ia64" ]]; then + ROOT_GUID=993d8d3d-f80e-4225-855a-9daf8ed7ea97 + VERITY_GUID=86ed10d5-b607-45bb-8957-d350f23d0571 + SIGNATURE_GUID=e98b36ee-32ba-4882-9b12-0ce14655f46a + ARCHITECTURE="ia64" +elif [[ "$machine" == "loongarch64" ]]; then + ROOT_GUID=77055800-792c-4f94-b39a-98c91b762bb6 + VERITY_GUID=f3393b22-e9af-4613-a948-9d3bfbd0c535 + SIGNATURE_GUID=5afb67eb-ecc8-4f85-ae8e-ac1e7c50e7d0 + ARCHITECTURE="loongarch64" +elif [[ "$machine" == "s390x" ]]; then + ROOT_GUID=5eead9a9-fe09-4a1e-a1d7-520d00531306 + VERITY_GUID=b325bfbe-c7be-4ab8-8357-139e652d2f6b + SIGNATURE_GUID=c80187a5-73a3-491a-901a-017c3fa953e9 + ARCHITECTURE="s390x" +elif [[ "$machine" == "ppc64le" ]]; then + ROOT_GUID=c31c45e6-3f39-412e-80fb-4809c4980599 + VERITY_GUID=906bd944-4589-4aae-a4e4-dd983917446a + SIGNATURE_GUID=d4a236e7-e873-4c07-bf1d-bf6cf7f1c3c6 + ARCHITECTURE="ppc64-le" +elif [[ "$machine" == "riscv64" ]]; then + ROOT_GUID=72ec70a6-cf74-40e6-bd49-4bda08e8f224 + VERITY_GUID=b6ed5582-440b-4209-b8da-5ff7c419ea3d + SIGNATURE_GUID=efe0f087-ea8d-4469-821a-4c2a96a8386a + ARCHITECTURE="riscv64" +elif [[ "$machine" == "riscv32" ]]; then + ROOT_GUID=60d5a7fe-8e7d-435c-b714-3dd8162144e1 + VERITY_GUID=ae0253be-1167-4007-ac68-43926c14c5de + SIGNATURE_GUID=3a112a75-8729-4380-b4cf-764d79934448 + ARCHITECTURE="riscv32" +else + echo "Unexpected uname -m: $machine in TEST-50-DISSECT.sh, please fix me" + exit 1 +fi + +udevadm control --log-level=debug + +IMAGE_DIR="$(mktemp -d --tmpdir="" TEST-50-IMAGES.XXX)" +cp -v /usr/share/minimal* "$IMAGE_DIR/" +MINIMAL_IMAGE="$IMAGE_DIR/minimal_0" +MINIMAL_IMAGE_ROOTHASH="$(<"$MINIMAL_IMAGE.roothash")" + +install_extension_images + +OS_RELEASE="$(test -e /etc/os-release && echo /etc/os-release || echo /usr/lib/os-release)" + +if systemctl --version | grep -q -- +OPENSSL ; then + # The openssl binary is installed conditionally. If we have OpenSSL support enabled and openssl is + # missing, fail early with a proper error message. + if ! command -v openssl &>/dev/null; then + echo "openssl binary is missing" >/failed + exit 1 + fi + + OPENSSL_CONFIG="$(mktemp)" + # Unfortunately OpenSSL insists on reading some config file, hence provide one with mostly placeholder contents + cat >"${OPENSSL_CONFIG:?}" <<EOF +[ req ] +prompt = no +distinguished_name = req_distinguished_name + +[ req_distinguished_name ] +C = DE +ST = Test State +L = Test Locality +O = Org Name +OU = Org Unit Name +CN = Common Name +emailAddress = test@email.com +EOF +fi + +# Make a GPT disk on the fly, with the squashfs as partition 1 and the verity hash tree as partition 2 +# +# du rounds up to block size, which is more helpful for partitioning +root_size="$(du --apparent-size -k "$MINIMAL_IMAGE.raw" | cut -f1)" +verity_size="$(du --apparent-size -k "$MINIMAL_IMAGE.verity" | cut -f1)" +signature_size=4 +# 4MB seems to be the minimum size blkid will accept, below that probing fails +dd if=/dev/zero of="$MINIMAL_IMAGE.gpt" bs=512 count=$((8192+root_size*2+verity_size*2+signature_size*2)) +# sfdisk seems unhappy if the size overflows into the next unit, eg: 1580KiB will be interpreted as 1MiB +# so do some basic rounding up if the minimal image is more than 1 MB +if [[ "$root_size" -ge 1024 ]]; then + root_size="$((root_size/1024 + 1))MiB" +else + root_size="${root_size}KiB" +fi +verity_size="$((verity_size * 2))KiB" +signature_size="$((signature_size * 2))KiB" + +if [[ -n "${OPENSSL_CONFIG:-}" ]]; then + # Create key pair + openssl req -config "$OPENSSL_CONFIG" -new -x509 -newkey rsa:1024 \ + -keyout "$MINIMAL_IMAGE.key" -out "$MINIMAL_IMAGE.crt" -days 365 -nodes + # Sign Verity root hash with it + openssl smime -sign -nocerts -noattr -binary \ + -in "$MINIMAL_IMAGE.roothash" \ + -inkey "$MINIMAL_IMAGE.key" \ + -signer "$MINIMAL_IMAGE.crt" \ + -outform der \ + -out "$MINIMAL_IMAGE.roothash.p7s" + # Generate signature partition JSON data + echo '{"rootHash":"'"$MINIMAL_IMAGE_ROOTHASH"'","signature":"'"$(base64 -w 0 <"$MINIMAL_IMAGE.roothash.p7s")"'"}' >"$MINIMAL_IMAGE.verity-sig" + # Pad it + truncate -s "$signature_size" "$MINIMAL_IMAGE.verity-sig" + # Register certificate in the (userspace) verity key ring + mkdir -p /run/verity.d + ln -s "$MINIMAL_IMAGE.crt" /run/verity.d/ok.crt +fi + +# Construct a UUID from hash +# input: 11111111222233334444555566667777 +# output: 11111111-2222-3333-4444-555566667777 +uuid="$(head -c 32 "$MINIMAL_IMAGE.roothash" | sed -r 's/(.{8})(.{4})(.{4})(.{4})(.+)/\1-\2-\3-\4-\5/')" +echo -e "label: gpt\nsize=$root_size, type=$ROOT_GUID, uuid=$uuid" | sfdisk "$MINIMAL_IMAGE.gpt" +uuid="$(tail -c 32 "$MINIMAL_IMAGE.roothash" | sed -r 's/(.{8})(.{4})(.{4})(.{4})(.+)/\1-\2-\3-\4-\5/')" +echo -e "size=$verity_size, type=$VERITY_GUID, uuid=$uuid" | sfdisk "$MINIMAL_IMAGE.gpt" --append +if [[ -n "${OPENSSL_CONFIG:-}" ]]; then + echo -e "size=$signature_size, type=$SIGNATURE_GUID" | sfdisk "$MINIMAL_IMAGE.gpt" --append +fi +sfdisk --part-label "$MINIMAL_IMAGE.gpt" 1 "Root Partition" +sfdisk --part-label "$MINIMAL_IMAGE.gpt" 2 "Verity Partition" +if [[ -n "${OPENSSL_CONFIG:-}" ]]; then + sfdisk --part-label "$MINIMAL_IMAGE.gpt" 3 "Signature Partition" +fi +loop="$(losetup --show -P -f "$MINIMAL_IMAGE.gpt")" +partitions=( + "${loop:?}p1" + "${loop:?}p2" +) +if [[ -n "${OPENSSL_CONFIG:-}" ]]; then + partitions+=("${loop:?}p3") +fi +# The kernel sometimes(?) does not emit "add" uevent for loop block partition devices. +# Let's not expect the devices to be initialized. +udevadm wait --timeout 60 --settle --initialized=no "${partitions[@]}" +udevadm lock --device="${loop}p1" dd if="$MINIMAL_IMAGE.raw" of="${loop}p1" +udevadm lock --device="${loop}p2" dd if="$MINIMAL_IMAGE.verity" of="${loop}p2" +if [[ -n "${OPENSSL_CONFIG:-}" ]]; then + udevadm lock --device="${loop}p3" dd if="$MINIMAL_IMAGE.verity-sig" of="${loop}p3" +fi +losetup -d "$loop" +udevadm settle --timeout=60 + +: "Run subtests" + +run_subtests + +touch /testok diff --git a/test/units/TEST-50-DISSECT.sysext.sh b/test/units/TEST-50-DISSECT.sysext.sh new file mode 100755 index 0000000..3bc8899 --- /dev/null +++ b/test/units/TEST-50-DISSECT.sysext.sh @@ -0,0 +1,1012 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +FAKE_ROOTS_DIR="$(mktemp -d --tmpdir="" fake-roots-XXX)" +FSTYPE=$(stat --file-system --format "%T" /usr) + +shopt -s nullglob + +# shellcheck disable=SC2317 +at_exit() { + set +ex + + local target + + # Note: `cat` here is used intentionally, so we iterate over our own copy of /proc/mounts. Otherwise + # things get very confusing once we start unmounting things, due to changing file offsets. + # shellcheck disable=SC2002 + cat /proc/mounts | while read -r _ target _ _ _ _; do + if [[ "$target" =~ ^"$FAKE_ROOTS_DIR" ]]; then + umount -Rv "$target" + fi + done + + rm -rf "${FAKE_ROOTS_DIR}" +} + +trap at_exit EXIT + +# Clears the trap command - it needs to be invoked for every test-case subshell +# so prepending commands with prepend_trap inside the subshell won't preserve +# the trap commands from outer shell. +init_trap() { + trap - EXIT +} + +prepend_trap() { + set +x + + local command=${1}; shift + local previous_commands + + previous_commands=$(trap -p EXIT) + if [[ -z $previous_commands ]]; then + previous_commands=':' + else + previous_commands=${previous_commands#'trap -- '} + previous_commands=${previous_commands%' EXIT'} + previous_commands=$(xargs <<<"$previous_commands") + fi + + # shellcheck disable=SC2064 # We use double quotes on purpose here. + trap "${command}; ${previous_commands}" EXIT + + set -x +} + +prepare_root() { + local root=${1:-} + local hierarchy=${2:?} + local dir + + if [[ -n $root ]] && [[ -d $root ]]; then + echo >&2 "Directory $root already exists, possible copy-paste error?" + exit 1 + fi + + local -a leftovers=( "$root/var/lib/extensions/"* "$root/var/lib/extensions.mutable/"* ) + if [[ ${#leftovers[@]} -gt 0 ]]; then + echo >&2 "Leftovers remained, make sure to clean them up in the test case: ${leftovers[*]}" + exit 1 + fi + + for dir in "$hierarchy" "/usr/lib" "/var/lib/extensions/" "/var/lib/extensions.mutable"; do + mkdir -p "$root$dir" + done + + if [[ -e $root/usr/lib/os-release ]]; then + mv "$root/usr/lib/os-release" "$root/usr/lib/os-release.orig" + fi + + { + echo "ID=testtest" + echo "VERSION=1.2.3" + } >"$root/usr/lib/os-release" + + prepend_trap "cleanup_os_release ${root@Q}" +} + +cleanup_os_release() { + # shellcheck disable=SC2317 # It is not unreachable, used in a trap couple lines above. + local root=${1:-} + + # shellcheck disable=SC2317 # It is not unreachable, used in a trap couple lines above. + rm -f "$root/usr/lib/os-release" + # shellcheck disable=SC2317 # It is not unreachable, used in a trap couple lines above. + if [[ -e $root/usr/lib/os-release.orig ]]; then + # shellcheck disable=SC2317 # It is not unreachable, used in a trap couple lines above. + mv "$root/usr/lib/os-release.orig" "$root/usr/lib/os-release" + fi +} + +prepare_extension_image() { + local root=${1:-} + local hierarchy=${2:?} + local ext_dir ext_release name + + name="test-extension" + ext_dir="$root/var/lib/extensions/$name" + ext_release="$ext_dir/usr/lib/extension-release.d/extension-release.$name" + mkdir -p "${ext_release%/*}" + echo "ID=_any" >"$ext_release" + mkdir -p "$ext_dir/$hierarchy" + touch "$ext_dir$hierarchy/preexisting-file-in-extension-image" + + prepend_trap "rm -rf ${ext_dir@Q}" +} + +prepare_extension_mutable_dir() { + local dir=${1:?} + + mkdir -p "$dir" + touch "$dir/preexisting-file-in-extensions-mutable" + prepend_trap "rm -rf ${dir@Q}" +} + +make_read_only() { + local root=${1:-} + local hierarchy=${2:?} + + mount -o bind,ro "$root$hierarchy" "$root$hierarchy" + prepend_trap "umount ${root@Q}${hierarchy@Q}" +} + +prepare_hierarchy() { + local root=${1:-} + local hierarchy=${2:?} + local file + + file="$root$hierarchy/preexisting-file-in-hierarchy" + touch "$file" + prepend_trap "rm -f ${file@Q}" +} + +prepare_read_only_hierarchy() { + local root=${1:-} + local hierarchy=${2:?} + + prepare_hierarchy "$root" "$hierarchy" + make_read_only "$root" "$hierarchy" +} + +move_existing_hierarchy_aside() { + local root=${1:-} + local hierarchy=${2:?} + + if [[ -z $root ]] && [[ $hierarchy = /usr ]]; then + echo >&2 "Hell no, not moving /usr aside" + exit 1 + fi + + local path=$root$hierarchy + + if [[ -e $path ]]; then + mv "$path" "$path.orig" + prepend_trap "mv ${path@Q}.orig ${path@Q}" + fi +} + +# Extra arguments: +# -e: check for a preexisting file in extension +# -h: check for a preexisting file in hierarchy +# -u: check for a preexisting file in upperdir +extension_verify() { + local root=${1:-} + local hierarchy=${2:?} + local message=${3:?} + shift 3 + # Map each option to a pre-defined file name + local -A option_files_map=( + [e]="preexisting-file-in-extension-image" + [h]="preexisting-file-in-hierarchy" + [u]="preexisting-file-in-extensions-mutable" + ) + local -A args=( + [e]=0 + [h]=0 + [u]=0 + ) + local file full_path opt option + + while getopts "ehu" opt; do + case "$opt" in + e|h|u) + args["$opt"]=1 + ;; + *) + echo >&2 "Unxexpected option: $opt" + exit 1 + esac + done + + for option in "${!option_files_map[@]}"; do + file=${option_files_map["$option"]} + full_path="$root$hierarchy/$file" + + if [[ ${args["$option"]} -ne 0 ]]; then + if [[ ! -f $full_path ]]; then + ls -la "$root$hierarchy" + echo >&2 "Expected file '$file' to exist under $root$hierarchy $message" + exit 1 + fi + else + if [[ -f $full_path ]]; then + ls -la "$root$hierarchy" + echo >&2 "Expected file '$file' to not exist under $root$hierarchy $message" + exit 1 + fi + fi + done +} + +extension_verify_after_merge() ( + set +x + + local root=${1:-} + local hierarchy=${2:?} + shift 2 + + extension_verify "$root" "$hierarchy" "after merge" "$@" +) + +extension_verify_after_unmerge() ( + set +x + + local root=${1:-} + local hierarchy=${2:?} + shift 2 + + extension_verify "$root" "$hierarchy" "after unmerge" "$@" +) + +run_systemd_sysext() { + local root=${1:-} + shift + + local -a sysext_args + sysext_args=() + + if [[ -n $root ]]; then + sysext_args+=( "--root=$root" ) + fi + sysext_args+=( "$@" ) + systemd-sysext "${sysext_args[@]}" +} + +# General systemd-sysext tests + +run_sysext_tests() { + # The roots_dir variable may be empty - in such case all the tests will run + # on /, otherwise they will run on $roots_dir/<SEPARATE_DIR_FOR_TEST>. + local roots_dir=${1}; shift + + # Each test runs in a subshell, so we can use traps for cleanups without + # clobbering toplevel traps, and we can do skips by invoking "exit 0". + +( init_trap +: "No extension data in /var/lib/extensions.mutable/…, R/O hierarchy, mutability disabled by default, read-only merged" +fake_root=${roots_dir:+"$roots_dir/simple-read-only-with-read-only-hierarchy"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +run_systemd_sysext "$fake_root" merge +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") +) + + +( init_trap +: "No extension data in /var/lib/extensions.mutable/…, mutable hierarchy, mutability disabled by default, read-only merged" +fake_root=${roots_dir:+"$roots_dir/simple-read-only-with-mutable-hierarchy"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_hierarchy "$fake_root" "$hierarchy" +touch "$fake_root$hierarchy/should-succeed-on-mutable-fs" + +run_systemd_sysext "$fake_root" merge +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +touch "$fake_root$hierarchy/should-succeed-on-mutable-fs-again" +) + + +( init_trap +: "No extension data in /var/lib/extensions.mutable/…, no hierarchy either, mutability disabled by default, read-only merged" +fake_root=${roots_dir:+"$roots_dir/simple-read-only-with-missing-hierarchy"} +hierarchy=/opt + +move_existing_hierarchy_aside "$fake_root" "$hierarchy" +prepare_root "$fake_root" "$hierarchy" +rmdir "$fake_root/$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" +) + + +( init_trap +: "No extension data in /var/lib/extensions.mutable/…, empty hierarchy, mutability disabled by default, read-only merged" +fake_root=${roots_dir:+"$roots_dir/simple-read-only-with-empty-hierarchy"} +hierarchy=/opt + +move_existing_hierarchy_aside "$fake_root" "$hierarchy" +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +make_read_only "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +run_systemd_sysext "$fake_root" merge +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" +) + + +( init_trap +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, mutability disabled by default, read-only merged" +fake_root=${roots_dir:+"$roots_dir/simple-mutable-with-read-only-hierarchy-disabled"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +run_systemd_sysext "$fake_root" merge +(! touch "$fake_root$hierarchy/should-be-read-only") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +) + + +( init_trap +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, auto-mutability, mutable merged" +fake_root=${roots_dir:+"$roots_dir/simple-mutable-with-read-only-hierarchy"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +[[ "$FSTYPE" == "fuseblk" ]] && exit 0 + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +run_systemd_sysext "$fake_root" --mutable=auto merge +touch "$fake_root$hierarchy/now-is-mutable" +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -u +test -f "$extension_data_dir/now-is-mutable" + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +test -f "$extension_data_dir/now-is-mutable" +test ! -f "$fake_root$hierarchy/now-is-mutable" +) + + +( init_trap +: "Extension data in /var/lib/extensions.mutable/…, missing hierarchy, auto-mutability, mutable merged" +fake_root=${roots_dir:+"$roots_dir/simple-mutable-with-missing-hierarchy"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +[[ "$FSTYPE" == "fuseblk" ]] && exit 0 + +move_existing_hierarchy_aside "$fake_root" "$hierarchy" +prepare_root "$fake_root" "$hierarchy" +rmdir "$fake_root/$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" + +run_systemd_sysext "$fake_root" --mutable=auto merge +touch "$fake_root$hierarchy/now-is-mutable" +extension_verify_after_merge "$fake_root" "$hierarchy" -e -u +test -f "$extension_data_dir/now-is-mutable" + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" +test -f "$extension_data_dir/now-is-mutable" +test ! -f "$fake_root$hierarchy/now-is-mutable" +) + + +( init_trap +: "Extension data in /var/lib/extensions.mutable/…, empty hierarchy, auto-mutability, mutable merged" +fake_root=${roots_dir:+"$roots_dir/simple-mutable-with-empty-hierarchy"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +[[ "$FSTYPE" == "fuseblk" ]] && exit 0 + +move_existing_hierarchy_aside "$fake_root" "$hierarchy" +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" +make_read_only "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +run_systemd_sysext "$fake_root" --mutable=auto merge +touch "$fake_root$hierarchy/now-is-mutable" +extension_verify_after_merge "$fake_root" "$hierarchy" -e -u +test -f "$extension_data_dir/now-is-mutable" + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" +test -f "$extension_data_dir/now-is-mutable" +test ! -f "$fake_root$hierarchy/now-is-mutable" +) + + +( init_trap +: "/var/lib/extensions.mutable/… is a symlink to other dir, R/O hierarchy, auto-mutability, mutable merged" +fake_root=${roots_dir:+"$roots_dir/mutable-symlink-with-read-only-hierarchy"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" +extension_real_dir="$fake_root/upperdir" + +[[ "$FSTYPE" == "fuseblk" ]] && exit 0 + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_real_dir" +ln -sfTr "$extension_real_dir" "$extension_data_dir" +prepend_trap "rm -f ${extension_data_dir@Q}" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +run_systemd_sysext "$fake_root" --mutable=auto merge +touch "$fake_root$hierarchy/now-is-mutable" +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -u +test -f "$extension_data_dir/now-is-mutable" +test -f "$extension_real_dir/now-is-mutable" + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +test -f "$extension_data_dir/now-is-mutable" +test -f "$extension_real_dir/now-is-mutable" +test ! -f "$fake_root$hierarchy/now-is-mutable" +) + + +( init_trap +: "/var/lib/extensions.mutable/… is a symlink to the hierarchy itself, mutable hierarchy, auto-mutability, mutable merged" +fake_root=${roots_dir:+"$roots_dir/mutable-self-upper"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" +extension_real_dir="$fake_root$hierarchy" + +[[ "$FSTYPE" == "fuseblk" ]] && exit 0 + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_real_dir" +ln -sfTr "$extension_real_dir" "$extension_data_dir" +prepend_trap "rm -f ${extension_data_dir@Q}" +touch "$fake_root$hierarchy/preexisting-file-in-hierarchy" + +run_systemd_sysext "$fake_root" --mutable=auto merge +touch "$fake_root$hierarchy/now-is-mutable" +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -u +test -f "$extension_data_dir/now-is-mutable" +test -f "$extension_real_dir/now-is-mutable" + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h -u +test -f "$extension_data_dir/now-is-mutable" +test -f "$extension_real_dir/now-is-mutable" +) + + +( init_trap +: "/var/lib/extensions.mutable/… is a symlink to the hierarchy itself, R/O hierarchy, auto-mutability, expected fail" +fake_root=${roots_dir:+"$roots_dir/failure-self-upper-ro"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" +extension_real_dir="$fake_root$hierarchy" + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_real_dir" +ln -sfTr "$extension_real_dir" "$extension_data_dir" +prepend_trap "rm -f ${extension_data_dir@Q}" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +(! run_systemd_sysext "$fake_root" --mutable=auto merge) +) + + +( init_trap +: "/var/lib/extensions.mutable/… is a dangling symlink, auto-mutability, read-only merged" +fake_root=${roots_dir:+"$roots_dir/read-only-mutable-dangling-symlink"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +ln -sfTr "/should/not/exist/" "$extension_data_dir" +prepend_trap "rm -f ${extension_data_dir@Q}" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +run_systemd_sysext "$fake_root" --mutable=auto merge +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +) + + +( init_trap +: "/var/lib/extensions.mutable/… exists but ignored, mutability disabled explicitly, read-only merged" +fake_root=${roots_dir:+"$roots_dir/disabled"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +run_systemd_sysext "$fake_root" --mutable=no merge +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +) + + +( init_trap +: "/var/lib/extensions.mutable/… exists but is imported instead, read-only merged" +fake_root=${roots_dir:+"$roots_dir/imported"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +run_systemd_sysext "$fake_root" --mutable=import merge +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -u + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +) + + +( init_trap +: "/var/lib/extensions.mutable/… does not exist, mutability enabled, mutable merged" +fake_root=${roots_dir:+"$roots_dir/enabled"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" +extension_data_dir_usr="$fake_root/var/lib/extensions.mutable/usr" + +[[ "$FSTYPE" == "fuseblk" ]] && exit 0 + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") +test ! -d "$extension_data_dir" + +run_systemd_sysext "$fake_root" --mutable=yes merge +# systemd-sysext with --mutable=yes creates extensions.mutable directory for +# the hierarchy, so delete it after the test +prepend_trap "rm -rf ${extension_data_dir@Q}" +# systemd-sysext with --mutable=yes creates extensions.mutable directory also +# for the /usr hierarchy, because the image needs to have +# /usr/lib/extension-release.d/extension-release.<NAME> file - this causes the +# /usr hierarchy to also become mutable +prepend_trap "rm -rf ${extension_data_dir_usr@Q}" +test -d "$extension_data_dir" +touch "$fake_root$hierarchy/now-is-mutable" +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h +test -f "$extension_data_dir/now-is-mutable" + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +test -f "$extension_data_dir/now-is-mutable" +test ! -f "$fake_root$hierarchy/now-is-mutable" +) + + +( init_trap +: "/var/lib/extensions.mutable/… does not exist, auto-mutability, read-only merged" +fake_root=${roots_dir:+"$roots_dir/simple-read-only-explicit"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +run_systemd_sysext "$fake_root" --mutable=auto merge +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +) + + +( init_trap +: "/var/lib/extensions.mutable/… does not exist, mutability enabled through env var, mutable merged" +fake_root=${roots_dir:+"$roots_dir/enabled-env-var"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" +extension_data_dir_usr="$fake_root/var/lib/extensions.mutable/usr" + +[[ "$FSTYPE" == "fuseblk" ]] && exit 0 + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") +test ! -d "$extension_data_dir" + +SYSTEMD_SYSEXT_MUTABLE_MODE=yes run_systemd_sysext "$fake_root" merge +# systemd-sysext with --mutable=yes creates extensions.mutable directory for +# the hierarchy, so delete it after the test +prepend_trap "rm -rf ${extension_data_dir@Q}" +# systemd-sysext with --mutable=yes creates extensions.mutable directory also +# for the /usr hierarchy, because the image needs to have +# /usr/lib/extension-release.d/extension-release.<NAME> file - this causes the +# /usr hierarchy to also become mutable +prepend_trap "rm -rf ${extension_data_dir_usr@Q}" +test -d "$extension_data_dir" +touch "$fake_root$hierarchy/now-is-mutable" +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h +test -f "$extension_data_dir/now-is-mutable" + +SYSTEMD_SYSEXT_MUTABLE_MODE=yes run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +test -f "$extension_data_dir/now-is-mutable" +test ! -f "$fake_root$hierarchy/now-is-mutable" +) + + +( init_trap +: "/var/lib/extensions.mutable/… does not exist, auto-mutability enabled through env var, read-only merged" +fake_root=${roots_dir:+"$roots_dir/read-only-auto-env-var"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +SYSTEMD_SYSEXT_MUTABLE_MODE=auto run_systemd_sysext "$fake_root" --mutable=auto merge +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +SYSTEMD_SYSEXT_MUTABLE_MODE=auto run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +) + + +( init_trap +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, auto-mutability enabled through env var, mutable merged" +fake_root=${roots_dir:+"$roots_dir/auto-mutable-env-var"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +[[ "$FSTYPE" == "fuseblk" ]] && exit 0 + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +SYSTEMD_SYSEXT_MUTABLE_MODE=auto run_systemd_sysext "$fake_root" merge +touch "$fake_root$hierarchy/now-is-mutable" +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -u +test -f "$extension_data_dir/now-is-mutable" + +SYSTEMD_SYSEXT_MUTABLE_MODE=auto run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +test -f "$extension_data_dir/now-is-mutable" +test ! -f "$fake_root$hierarchy/now-is-mutable" +) + + +( init_trap +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, mutability disabled through env var, read-only merged" +fake_root=${roots_dir:+"$roots_dir/env-var-disabled"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +SYSTEMD_SYSEXT_MUTABLE_MODE=no run_systemd_sysext "$fake_root" merge +(! touch "$fake_root$hierarchy/should-be-read-only") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +SYSTEMD_SYSEXT_MUTABLE_MODE=no run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +) + + +( init_trap +: "/var/lib/extensions.mutable/… exists but is imported through env var, read-only merged" +fake_root=${roots_dir:+"$roots_dir/imported-env-var"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +SYSTEMD_SYSEXT_MUTABLE_MODE=import run_systemd_sysext "$fake_root" merge +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -u + +SYSTEMD_SYSEXT_MUTABLE_MODE=import run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +) + + +( init_trap +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, mutability enabled through env var but overridden via CLI option, read-only merged" +fake_root=${roots_dir:+"$roots_dir/env-var-overridden"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +SYSTEMD_SYSEXT_MUTABLE_MODE=yes run_systemd_sysext "$fake_root" --mutable=no merge +(! touch "$fake_root$hierarchy/should-be-read-only") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +SYSTEMD_SYSEXT_MUTABLE_MODE=yes run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +) + + +( init_trap +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, ephemeral mutability, mutable merged" +fake_root=${roots_dir:+"$roots_dir/ephemeral"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +[[ "$FSTYPE" == "fuseblk" ]] && exit 0 + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +run_systemd_sysext "$fake_root" --mutable=ephemeral merge +touch "$fake_root$hierarchy/now-is-mutable" +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h +test ! -f "$extension_data_dir/now-is-mutable" + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +test ! -f "$extension_data_dir/now-is-mutable" +test ! -f "$fake_root$hierarchy/now-is-mutable" +) + + +( init_trap +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, ephemeral mutability through env var, mutable merged" +fake_root=${roots_dir:+"$roots_dir/ephemeral-env-var"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +[[ "$FSTYPE" == "fuseblk" ]] && exit 0 + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +SYSTEMD_SYSEXT_MUTABLE_MODE=ephemeral run_systemd_sysext "$fake_root" merge +touch "$fake_root$hierarchy/now-is-mutable" +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h +test ! -f "$extension_data_dir/now-is-mutable" + +SYSTEMD_SYSEXT_MUTABLE_MODE=ephemeral run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +test ! -f "$extension_data_dir/now-is-mutable" +test ! -f "$fake_root$hierarchy/now-is-mutable" +) + + +( init_trap +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, ephemeral import mutability, mutable merged" +fake_root=${roots_dir:+"$roots_dir/ephemeral-import"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +[[ "$FSTYPE" == "fuseblk" ]] && exit 0 + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +run_systemd_sysext "$fake_root" --mutable=ephemeral-import merge +touch "$fake_root$hierarchy/now-is-mutable" +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -u +test ! -f "$extension_data_dir/now-is-mutable" + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +test ! -f "$extension_data_dir/now-is-mutable" +test ! -f "$fake_root$hierarchy/now-is-mutable" +) + + +( init_trap +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, ephemeral import mutability through env var, mutable merged" +fake_root=${roots_dir:+"$roots_dir/ephemeral-import-env-var"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +[[ "$FSTYPE" == "fuseblk" ]] && exit 0 + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +SYSTEMD_SYSEXT_MUTABLE_MODE=ephemeral-import run_systemd_sysext "$fake_root" merge +touch "$fake_root$hierarchy/now-is-mutable" +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -u +test ! -f "$extension_data_dir/now-is-mutable" + +SYSTEMD_SYSEXT_MUTABLE_MODE=ephemeral-import run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +test ! -f "$extension_data_dir/now-is-mutable" +test ! -f "$fake_root$hierarchy/now-is-mutable" +) + + +( init_trap +: "Extension data pointing to mutable hierarchy, ephemeral import mutability, expected fail" +fake_root=${roots_dir:+"$roots_dir/ephemeral-import-self"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" +extension_real_dir="$fake_root$hierarchy" + +[[ "$FSTYPE" == "fuseblk" ]] && exit 0 + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_real_dir" +ln -sfTr "$extension_real_dir" "$extension_data_dir" +prepend_trap "rm -f ${extension_data_dir@Q}" +prepare_hierarchy "$fake_root" "$hierarchy" +touch "$fake_root$hierarchy/should-succeed-on-read-only-fs" + +(! run_systemd_sysext "$fake_root" --mutable=ephemeral-import merge) +) + + +( init_trap +: "Extension data pointing to mutable hierarchy, import mutability, expected fail" +fake_root=${roots_dir:+"$roots_dir/import-self"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" +extension_real_dir="$fake_root$hierarchy" + +[[ "$FSTYPE" == "fuseblk" ]] && exit 0 + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_real_dir" +ln -sfTr "$extension_real_dir" "$extension_data_dir" +prepend_trap "rm -f ${extension_data_dir@Q}" +prepare_hierarchy "$fake_root" "$hierarchy" +touch "$fake_root$hierarchy/should-succeed-on-read-only-fs" + +(! run_systemd_sysext "$fake_root" --mutable=import merge) +) + + +for mutable_mode in no yes ephemeral; do + ( init_trap + : "Check if merging the hierarchy does not change its permissions, checking with --mutable=${mutable_mode}" + + fake_root=${roots_dir:+"$roots_dir/perm-checks-mutable-$mutable_mode"} + hierarchy=/opt + extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + + [[ "$FSTYPE" == "fuseblk" ]] && exit 0 + + prepare_root "$fake_root" "$hierarchy" + prepare_extension_image "$fake_root" "$hierarchy" + prepare_extension_mutable_dir "$extension_data_dir" + prepare_read_only_hierarchy "${fake_root}" "${hierarchy}" + + full_path="$fake_root$hierarchy" + permissions_before_merge=$(stat --format=%A "$full_path") + + run_systemd_sysext "$fake_root" "--mutable=$mutable_mode" merge + if [[ $mutable_mode = yes ]]; then + # systemd-sysext with --mutable=yes creates extensions.mutable + # directory also for the /usr hierarchy, because the image needs to + # have /usr/lib/extension-release.d/extension-release.<NAME> file - + # this causes the /usr hierarchy to also become mutable + extension_data_dir_usr="$fake_root/var/lib/extensions.mutable/usr" + prepend_trap "rm -rf ${extension_data_dir_usr@Q}" + fi + + permissions_after_merge=$(stat --format=%A "$full_path") + + run_systemd_sysext "$fake_root" unmerge + + permissions_after_unmerge=$(stat --format=%A "$full_path") + + if [[ "$permissions_before_merge" != "$permissions_after_merge" ]]; then + echo >&2 "Broken hierarchy permissions after merging with mutable mode ${mutable_mode@Q}, expected ${permissions_before_merge@Q}, got ${permissions_after_merge@Q}" + exit 1 + fi + + if [[ "$permissions_before_merge" != "$permissions_after_unmerge" ]]; then + echo >&2 "Broken hierarchy permissions after unmerging with mutable mode ${mutable_mode@Q}, expected ${permissions_before_merge@Q}, got ${permissions_after_unmerge@Q}" + exit 1 + fi + ) +done + + +( init_trap +: "Check if merging fails in case of invalid mutable directory permissions" + +fake_root=${roots_dir:+"$roots_dir/mutable-directory-with-invalid-permissions"} +hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +prepare_extension_mutable_dir "$extension_data_dir" +prepare_hierarchy "$fake_root" "$hierarchy" + +old_mode=$(stat --format '%#a' "$fake_root$hierarchy") +chmod 0755 "$fake_root$hierarchy" +prepend_trap "chmod ${old_mode@Q} ${fake_root@Q}${hierarchy@Q}" +chmod 0700 "$extension_data_dir" + +(! run_systemd_sysext "$fake_root" --mutable=yes merge) +) + +} # End of run_sysext_tests + + +# For preparing /, we need mutable /usr/. If it is read only, skip running the +# sysext tests on /. +if [[ -w /usr ]]; then + run_sysext_tests '' +fi +run_sysext_tests "$FAKE_ROOTS_DIR" + + +exit 0 diff --git a/test/units/testsuite-52.sh b/test/units/TEST-52-HONORFIRSTSHUTDOWN.sh index 16ff507..16ff507 100755 --- a/test/units/testsuite-52.sh +++ b/test/units/TEST-52-HONORFIRSTSHUTDOWN.sh diff --git a/test/units/testsuite-53.sh b/test/units/TEST-53-ISSUE-16347.sh index 84cd661..84cd661 100755 --- a/test/units/testsuite-53.sh +++ b/test/units/TEST-53-ISSUE-16347.sh diff --git a/test/units/testsuite-54.sh b/test/units/TEST-54-CREDS.sh index bcbe7a1..fe410d5 100755 --- a/test/units/testsuite-54.sh +++ b/test/units/TEST-54-CREDS.sh @@ -3,15 +3,25 @@ # shellcheck disable=SC2016 set -eux +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + systemd-analyze log-level debug -run_with_cred_compare() { +run_with_cred_compare() ( local cred="${1:?}" local exp="${2?}" + local log_file shift 2 - diff <(systemd-run -p SetCredential="$cred" --wait --pipe -- systemd-creds "$@") <(echo -ne "$exp") -} + log_file="$(mktemp)" + # shellcheck disable=SC2064 + trap "rm -f '$log_file'" RETURN + + set -o pipefail + systemd-run -p SetCredential="$cred" --wait --pipe -- systemd-creds "$@" | tee "$log_file" + diff "$log_file" <(echo -ne "$exp") +) # Sanity checks # @@ -197,6 +207,12 @@ elif [ -d /sys/firmware/qemu_fw_cfg/by_name ]; then [ "$(cat /tmp/sourcedfromcredential)" = "tmpfilessecret" ] [ "$(cat /etc/motd.d/50-provision.conf)" = "hello" ] [ "$(cat /etc/issue.d/50-provision.conf)" = "welcome" ] + + # Verify that adding a unit and drop-in via credentials worked + systemctl start my-service + test -f /tmp/unit-cred + test -f /tmp/unit-dropin + test -f /tmp/unit-named-dropin else echo "qemu_fw_cfg support missing in kernel. Sniff!" expected_credential="" @@ -297,11 +313,40 @@ fi systemd-run -p DynamicUser=yes -p 'LoadCredential=os:/etc/os-release' \ -p 'ExecStartPre=true' \ -p 'ExecStartPre=systemd-creds cat os' \ - --unit=test-54-exec-start.service \ + --unit=test-54-exec-start-pre.service \ --wait \ --pipe \ true | cmp /etc/os-release +# https://github.com/systemd/systemd/issues/31194 +systemd-run -p DynamicUser=yes -p 'LoadCredential=os:/etc/os-release' \ + -p 'ExecStartPost=systemd-creds cat os' \ + --unit=test-54-exec-start-post.service \ + --service-type=oneshot --wait --pipe \ + true | cmp /etc/os-release + +# https://github.com/systemd/systemd/pull/24734#issuecomment-1925440546 +# Also ExecStartPre= should be able to update creds +dd if=/dev/urandom of=/tmp/cred-huge bs=600K count=1 +chmod 777 /tmp/cred-huge +systemd-run -p ProtectSystem=full \ + -p 'LoadCredential=huge:/tmp/cred-huge' \ + -p 'ExecStartPre=true' \ + -p 'ExecStartPre=bash -c "echo fresh >/tmp/cred-huge"' \ + --unit=test-54-huge-cred.service \ + --wait --pipe \ + systemd-creds cat huge | cmp - <(echo "fresh") +rm /tmp/cred-huge + +echo stable >/tmp/cred-stable +systemd-run -p 'LoadCredential=stable:/tmp/cred-stable' \ + -p 'ExecStartPost=systemd-creds cat stable' \ + --unit=test-54-stable.service \ + --service-type=oneshot --wait --pipe \ + bash -c "echo bogus >/tmp/cred-stable" | cmp - <(echo "stable") +assert_eq "$(cat /tmp/cred-stable)" "bogus" +rm /tmp/cred-stable + if ! systemd-detect-virt -q -c ; then # Validate that the credential we inserted via the initrd logic arrived test "$(systemd-creds cat --system myinitrdcred)" = "guatemala" @@ -314,6 +359,44 @@ if ! systemd-detect-virt -q -c ; then systemctl -P Wants show getty.target | grep -q container-getty@idontexist.service fi +# Decrypt/encrypt via varlink + +echo '{"data":"Zm9vYmFyCg=="}' > /tmp/vlcredsdata + +varlinkctl call /run/systemd/io.systemd.Credentials io.systemd.Credentials.Encrypt "$(cat /tmp/vlcredsdata)" | \ + varlinkctl call --json=short /run/systemd/io.systemd.Credentials io.systemd.Credentials.Decrypt > /tmp/vlcredsdata2 + +cmp /tmp/vlcredsdata /tmp/vlcredsdata2 +rm /tmp/vlcredsdata /tmp/vlcredsdata2 + +clean_usertest() { + rm -f /tmp/usertest.data /tmp/usertest.data +} + +trap clean_usertest EXIT +dd if=/dev/urandom of=/tmp/usertest.data bs=4096 count=1 + +systemd-creds encrypt --user /tmp/usertest.data /tmp/usertest.cred + +systemd-creds decrypt --user /tmp/usertest.cred - | cmp /tmp/usertest.data + +# Decryption must fail if it's not done in user context +(! systemd-creds decrypt /tmp/usertest.cred - ) + +# Decryption must also fail if a different user is used +(! systemd-creds decrypt --user --uid=65534 /tmp/usertest.cred - ) + +# Try the reverse +systemd-creds encrypt --user --uid=65534 /tmp/usertest.data /tmp/usertest.cred +(! systemd-creds decrypt --user /tmp/usertest.cred - ) +systemd-creds decrypt --user --uid=65534 /tmp/usertest.cred - | cmp /tmp/usertest.data + +systemd-creds encrypt --user /tmp/usertest.data /tmp/usertest.creds --name=mytest + +# Make sure we actually can decode this in user context +systemctl start user@0.service +XDG_RUNTIME_DIR=/run/user/0 systemd-run --pipe --user --unit=waldi.service -p LoadCredentialEncrypted=mytest:/tmp/usertest.creds cat /run/user/0/credentials/waldi.service/mytest | cmp /tmp/usertest.data + systemd-analyze log-level info touch /testok diff --git a/test/units/testsuite-55-testbloat.service b/test/units/TEST-55-OOMD-testbloat.service index 6c8e3c9..ba4f2bc 100644 --- a/test/units/testsuite-55-testbloat.service +++ b/test/units/TEST-55-OOMD-testbloat.service @@ -6,5 +6,5 @@ Description=Create a lot of memory pressure # A VERY small memory.high will cause the 'stress' (trying to use a lot of memory) # to throttle and be put under heavy pressure. MemoryHigh=3M -Slice=testsuite-55-workload.slice +Slice=TEST-55-OOMD-workload.slice ExecStart=stress --timeout 3m --vm 10 --vm-bytes 200M --vm-keep --vm-stride 1 diff --git a/test/units/testsuite-55-testchill.service b/test/units/TEST-55-OOMD-testchill.service index 369b802..1f708dd 100644 --- a/test/units/testsuite-55-testchill.service +++ b/test/units/TEST-55-OOMD-testchill.service @@ -4,5 +4,5 @@ Description=No memory pressure [Service] MemoryHigh=3M -Slice=testsuite-55-workload.slice +Slice=TEST-55-OOMD-workload.slice ExecStart=sleep infinity diff --git a/test/units/testsuite-55-testmunch.service b/test/units/TEST-55-OOMD-testmunch.service index 3730059..5659906 100644 --- a/test/units/testsuite-55-testmunch.service +++ b/test/units/TEST-55-OOMD-testmunch.service @@ -4,5 +4,5 @@ Description=Create some memory pressure [Service] MemoryHigh=12M -Slice=testsuite-55-workload.slice +Slice=TEST-55-OOMD-workload.slice ExecStart=stress --timeout 3m --vm 10 --vm-bytes 200M --vm-keep --vm-stride 1 diff --git a/test/units/testsuite-55-workload.slice b/test/units/TEST-55-OOMD-workload.slice index d117b75..d117b75 100644 --- a/test/units/testsuite-55-workload.slice +++ b/test/units/TEST-55-OOMD-workload.slice diff --git a/test/units/testsuite-55.sh b/test/units/TEST-55-OOMD.sh index 81617db..b04ebca 100755 --- a/test/units/testsuite-55.sh +++ b/test/units/TEST-55-OOMD.sh @@ -6,6 +6,14 @@ set -o pipefail # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh +. /etc/os-release +# OpenSUSE does not have the stress tool packaged. It does have stress-ng but the stress-ng does not support +# --vm-stride which this test uses. +if [[ "$ID" =~ "opensuse" ]]; then + echo "Skipping due to missing stress package in OpenSUSE" >>/skipped + exit 77 +fi + systemd-analyze log-level debug # Ensure that the init.scope.d drop-in is applied on boot @@ -16,13 +24,14 @@ test "$(cat /sys/fs/cgroup/init.scope/memory.high)" != "max" [[ "$(get_cgroup_hierarchy)" == "unified" ]] || echo "no cgroupsv2" >>/skipped [[ -x /usr/lib/systemd/systemd-oomd ]] || echo "no oomd" >>/skipped if [[ -s /skipped ]]; then - exit 0 + exit 77 fi -rm -rf /run/systemd/system/testsuite-55-testbloat.service.d +rm -rf /run/systemd/system/TEST-55-OOMD-testbloat.service.d # Activate swap file if we are in a VM if systemd-detect-virt --vm --quiet; then + swapoff --all if [[ "$(findmnt -n -o FSTYPE /)" == btrfs ]]; then btrfs filesystem mkswapfile -s 64M /swapfile else @@ -78,35 +87,34 @@ if [[ -v ASAN_OPTIONS || -v UBSAN_OPTIONS ]]; then # go on a killing spree. This fact is exacerbated further on Arch Linux which ships unstripped gcc-libs, # so sd-executor pulls in over 30M of libs on startup. Let's make the MemoryHigh= limit a bit more # generous when running with sanitizers to make the test happy. - mkdir -p /run/systemd/system/testsuite-55-testchill.service.d/ - cat >/run/systemd/system/testsuite-55-testchill.service.d/99-MemoryHigh.conf <<EOF + systemctl edit --runtime --stdin --drop-in=99-MemoryHigh.conf TEST-55-OOMD-testchill.service <<EOF [Service] MemoryHigh=60M EOF # Do the same for the user instance as well mkdir -p /run/systemd/user/ - cp -rfv /run/systemd/system/testsuite-55-testchill.service.d/ /run/systemd/user/ + cp -rfv /run/systemd/system/TEST-55-OOMD-testchill.service.d/ /run/systemd/user/ else # Ensure that we can start services even with a very low hard memory cap without oom-kills, but skip # under sanitizers as they balloon memory usage. systemd-run -t -p MemoryMax=10M -p MemorySwapMax=0 -p MemoryZSwapMax=0 /bin/true fi -systemctl start testsuite-55-testchill.service -systemctl start testsuite-55-testbloat.service +systemctl start TEST-55-OOMD-testchill.service +systemctl start TEST-55-OOMD-testbloat.service # Verify systemd-oomd is monitoring the expected units -timeout 1m bash -xec 'until oomctl | grep "/testsuite-55-workload.slice"; do sleep 1; done' -oomctl | grep "/testsuite-55-workload.slice" +timeout 1m bash -xec 'until oomctl | grep "/TEST-55-OOMD-workload.slice"; do sleep 1; done' +oomctl | grep "/TEST-55-OOMD-workload.slice" oomctl | grep "20.00%" oomctl | grep "Default Memory Pressure Duration: 2s" -systemctl status testsuite-55-testchill.service +systemctl status TEST-55-OOMD-testchill.service # systemd-oomd watches for elevated pressure for 2 seconds before acting. # It can take time to build up pressure so either wait 2 minutes or for the service to fail. for _ in {0..59}; do - if ! systemctl status testsuite-55-testbloat.service; then + if ! systemctl status TEST-55-OOMD-testbloat.service; then break fi oomctl @@ -114,28 +122,28 @@ for _ in {0..59}; do done # testbloat should be killed and testchill should be fine -if systemctl status testsuite-55-testbloat.service; then exit 42; fi -if ! systemctl status testsuite-55-testchill.service; then exit 24; fi +if systemctl status TEST-55-OOMD-testbloat.service; then exit 42; fi +if ! systemctl status TEST-55-OOMD-testchill.service; then exit 24; fi # Make sure we also work correctly on user units. loginctl enable-linger testuser -systemctl start --machine "testuser@.host" --user testsuite-55-testchill.service -systemctl start --machine "testuser@.host" --user testsuite-55-testbloat.service +systemctl start --machine "testuser@.host" --user TEST-55-OOMD-testchill.service +systemctl start --machine "testuser@.host" --user TEST-55-OOMD-testbloat.service # Verify systemd-oomd is monitoring the expected units # Try to avoid racing the oomctl output check by checking in a loop with a timeout -timeout 1m bash -xec 'until oomctl | grep "/testsuite-55-workload.slice"; do sleep 1; done' -oomctl | grep -E "/user.slice.*/testsuite-55-workload.slice" +timeout 1m bash -xec 'until oomctl | grep "/TEST-55-OOMD-workload.slice"; do sleep 1; done' +oomctl | grep -E "/user.slice.*/TEST-55-OOMD-workload.slice" oomctl | grep "20.00%" oomctl | grep "Default Memory Pressure Duration: 2s" -systemctl --machine "testuser@.host" --user status testsuite-55-testchill.service +systemctl --machine "testuser@.host" --user status TEST-55-OOMD-testchill.service # systemd-oomd watches for elevated pressure for 2 seconds before acting. # It can take time to build up pressure so either wait 2 minutes or for the service to fail. for _ in {0..59}; do - if ! systemctl --machine "testuser@.host" --user status testsuite-55-testbloat.service; then + if ! systemctl --machine "testuser@.host" --user status TEST-55-OOMD-testbloat.service; then break fi oomctl @@ -143,8 +151,8 @@ for _ in {0..59}; do done # testbloat should be killed and testchill should be fine -if systemctl --machine "testuser@.host" --user status testsuite-55-testbloat.service; then exit 42; fi -if ! systemctl --machine "testuser@.host" --user status testsuite-55-testchill.service; then exit 24; fi +if systemctl --machine "testuser@.host" --user status TEST-55-OOMD-testbloat.service; then exit 42; fi +if ! systemctl --machine "testuser@.host" --user status TEST-55-OOMD-testchill.service; then exit 24; fi loginctl disable-linger testuser @@ -152,19 +160,19 @@ loginctl disable-linger testuser if cgroupfs_supports_user_xattrs; then sleep 120 # wait for systemd-oomd kill cool down and elevated memory pressure to come down - mkdir -p /run/systemd/system/testsuite-55-testbloat.service.d/ - cat >/run/systemd/system/testsuite-55-testbloat.service.d/override.conf <<EOF + mkdir -p /run/systemd/system/TEST-55-OOMD-testbloat.service.d/ + cat >/run/systemd/system/TEST-55-OOMD-testbloat.service.d/override.conf <<EOF [Service] ManagedOOMPreference=avoid EOF systemctl daemon-reload - systemctl start testsuite-55-testchill.service - systemctl start testsuite-55-testmunch.service - systemctl start testsuite-55-testbloat.service + systemctl start TEST-55-OOMD-testchill.service + systemctl start TEST-55-OOMD-testmunch.service + systemctl start TEST-55-OOMD-testbloat.service for _ in {0..59}; do - if ! systemctl status testsuite-55-testmunch.service; then + if ! systemctl status TEST-55-OOMD-testmunch.service; then break fi oomctl @@ -172,9 +180,9 @@ EOF done # testmunch should be killed since testbloat had the avoid xattr on it - if ! systemctl status testsuite-55-testbloat.service; then exit 25; fi - if systemctl status testsuite-55-testmunch.service; then exit 43; fi - if ! systemctl status testsuite-55-testchill.service; then exit 24; fi + if ! systemctl status TEST-55-OOMD-testbloat.service; then exit 25; fi + if systemctl status TEST-55-OOMD-testmunch.service; then exit 43; fi + if ! systemctl status TEST-55-OOMD-testchill.service; then exit 24; fi fi systemd-analyze log-level info diff --git a/test/units/testsuite-58.sh b/test/units/TEST-58-REPART.sh index c64b203..8a014ac 100755 --- a/test/units/testsuite-58.sh +++ b/test/units/TEST-58-REPART.sh @@ -9,7 +9,7 @@ set -o pipefail if ! command -v systemd-repart >/dev/null; then echo "no systemd-repart" >/skipped - exit 0 + exit 77 fi # shellcheck source=test/units/test-control.sh @@ -87,7 +87,7 @@ elif [ "${machine}" = "ppc64le" ]; then usr_uuid=C0D0823B-8040-4C7C-A629-026248E297FB architecture="ppc64-le" else - echo "Unexpected uname -m: ${machine} in testsuite-58.sh, please fix me" + echo "Unexpected uname -m: ${machine} in TEST-58-REPART.sh, please fix me" exit 1 fi @@ -373,7 +373,7 @@ $imgs/zzz7 : start= 6291416, size= 98304, type=0FC63DAF-8483-4772-8E79 fi loop="$(losetup -P --show --find "$imgs/zzz")" - udevadm wait --timeout 60 --settle "${loop:?}" + udevadm wait --timeout 60 --settle "${loop:?}p7" volume="test-repart-$RANDOM" @@ -435,7 +435,7 @@ EOF "offset" : 1048576, "old_size" : 0, "raw_size" : 33554432, - "size" : "-> 32.0M", + "size" : "-> 32M", "old_padding" : 0, "raw_padding" : 0, "padding" : "-> 0B", @@ -496,7 +496,7 @@ EOF "offset" : 1048576, "old_size" : 0, "raw_size" : 33554432, - "size" : "-> 32.0M", + "size" : "-> 32M", "old_padding" : 0, "raw_padding" : 0, "padding" : "-> 0B", @@ -512,7 +512,7 @@ EOF "offset" : 34603008, "old_size" : 0, "raw_size" : 33554432, - "size" : "-> 32.0M", + "size" : "-> 32M", "old_padding" : 0, "raw_padding" : 0, "padding" : "-> 0B", @@ -961,7 +961,7 @@ EOF # shellcheck disable=SC2064 trap "rm -rf '$defs' '$imgs' ; losetup -d '$loop'" RETURN ERR - udevadm wait --timeout 60 --settle "${loop:?}" + udevadm wait --timeout 60 --settle "${loop:?}p1" "${loop:?}p2" # Check that the verity block sizes are as expected veritysetup dump "${loop}p2" | grep 'Data block size:' | grep -q '4096' @@ -1026,7 +1026,7 @@ EOF fi loop=$(losetup -P --show -f "$imgs/zzz") - udevadm wait --timeout 60 --settle "${loop:?}" + udevadm wait --timeout 60 --settle "${loop:?}p1" "${loop:?}p2" # Test that /usr/def did not end up in the root partition but other files did. mkdir "$imgs/mnt" diff --git a/test/units/testsuite-59.sh b/test/units/TEST-59-RELOADING-RESTART.sh index 1b622b3..0e04403 100755 --- a/test/units/testsuite-59.sh +++ b/test/units/TEST-59-RELOADING-RESTART.sh @@ -36,7 +36,7 @@ Description=TEST-59-RELOADING-RESTART Normal exit [Service] Type=notify -ExecStart=/bin/bash -c "systemd-notify --ready; systemd-notify RELOADING=1; sleep 1; exit 1" +ExecStart=bash -c "systemd-notify --ready; systemd-notify RELOADING=1; sleep 1; exit 1" EOF cat >/run/systemd/system/testservice-fail-restart-59.service <<EOF @@ -45,7 +45,7 @@ Description=TEST-59-RELOADING-RESTART Restart=on-failure [Service] Type=notify -ExecStart=/bin/bash -c "systemd-notify --ready; systemd-notify RELOADING=1; sleep 1; exit 1" +ExecStart=bash -c "systemd-notify --ready; systemd-notify RELOADING=1; sleep 1; exit 1" Restart=on-failure StartLimitBurst=1 EOF @@ -57,7 +57,7 @@ Description=TEST-59-RELOADING-RESTART Restart=on-abort [Service] Type=notify -ExecStart=/bin/bash -c "systemd-notify --ready; systemd-notify RELOADING=1; sleep 5; exit 1" +ExecStart=bash -c "systemd-notify --ready; systemd-notify RELOADING=1; sleep 5; exit 1" Restart=on-abort EOF @@ -104,6 +104,14 @@ sleep 10 systemctl daemon-reload +# Same test for reexec, but we wait here +timeout 15 bash -c 'while systemctl daemon-reexec; do true; done' + +# Rate limit should reset after 9s +sleep 10 + +systemctl daemon-reexec + # Let's now test the notify-reload logic cat >/run/notify-reload-test.sh <<EOF diff --git a/test/units/testsuite-60.sh b/test/units/TEST-60-MOUNT-RATELIMIT.sh index e800a7a..a0e99dc 100755 --- a/test/units/testsuite-60.sh +++ b/test/units/TEST-60-MOUNT-RATELIMIT.sh @@ -23,8 +23,8 @@ teardown_test_dependencies() ( losetup -d "${LOOP_1}" || : fi - rm -f /tmp/testsuite-60-dependencies-0.img - rm -f /tmp/testsuite-60-dependencies-1.img + rm -f /tmp/TEST-60-MOUNT-RATELIMIT-dependencies-0.img + rm -f /tmp/TEST-60-MOUNT-RATELIMIT-dependencies-1.img rm -f /run/systemd/system/tmp-deptest.mount systemctl daemon-reload @@ -33,13 +33,13 @@ teardown_test_dependencies() ( ) setup_loop() { - truncate -s 30m "/tmp/testsuite-60-dependencies-${1?}.img" - sfdisk --wipe=always "/tmp/testsuite-60-dependencies-${1?}.img" <<EOF + truncate -s 30m "/tmp/TEST-60-MOUNT-RATELIMIT-dependencies-${1?}.img" + sfdisk --wipe=always "/tmp/TEST-60-MOUNT-RATELIMIT-dependencies-${1?}.img" <<EOF label:gpt name="loop${1?}-part1" EOF - LOOP=$(losetup -P --show -f "/tmp/testsuite-60-dependencies-${1?}.img") + LOOP=$(losetup -P --show -f "/tmp/TEST-60-MOUNT-RATELIMIT-dependencies-${1?}.img") udevadm wait --settle --timeout=10 "${LOOP}" udevadm lock --device="${LOOP}" mkfs.ext4 -L "partname${1?}-1" "${LOOP}p1" } @@ -203,7 +203,7 @@ EOF } test_issue_23796() { - local mount_path mount_mytmpfs + local mount_path mount_mytmpfs since mount_path="$(command -v mount 2>/dev/null)" mount_mytmpfs="${mount_path/\/bin/\/sbin}.mytmpfs" @@ -225,6 +225,9 @@ EOF # shellcheck disable=SC2064 trap "rm -f /run/systemd/system/tmp-hoge.mount '$mount_mytmpfs'" RETURN + journalctl --sync + since="$(date '+%H:%M:%S')" + for _ in {1..10}; do systemctl --no-block start tmp-hoge.mount sleep ".$RANDOM" @@ -233,7 +236,7 @@ EOF sleep 1 if [[ "$(systemctl is-failed tmp-hoge.mount)" == "failed" ]] || \ - journalctl -u tmp-hoge.mount -q --grep "but there is no mount"; then + journalctl --since="$since" -u tmp-hoge.mount -q --grep "but there is no mount"; then exit 1 fi @@ -249,6 +252,8 @@ NUM_DIRS=20 # make sure we can handle mounts at very long paths such that mount unit name must be hashed to fall within our unit name limit LONGPATH="$(printf "/$(printf "x%0.s" {1..255})%0.s" {1..7})" LONGMNT="$(systemd-escape --suffix=mount --path "$LONGPATH")" + +journalctl --sync TS="$(date '+%H:%M:%S')" mkdir -p "$LONGPATH" @@ -271,6 +276,9 @@ for ((i = 0; i < NUM_DIRS; i++)); do mkdir "/tmp/meow${i}" done +# The following loop may produce many journal entries. +# Let's process all pending entries before testing. +journalctl --sync TS="$(date '+%H:%M:%S')" for ((i = 0; i < NUM_DIRS; i++)); do @@ -286,9 +294,13 @@ done # Figure out if we have entered the rate limit state. # If the infra is slow we might not enter the rate limit state; in that case skip the exit check. -if timeout 2m bash -c "until journalctl -u init.scope --since=$TS | grep -q '(mount-monitor-dispatch) entered rate limit'; do sleep 1; done"; then - timeout 2m bash -c "until journalctl -u init.scope --since=$TS | grep -q '(mount-monitor-dispatch) left rate limit'; do sleep 1; done" +set +o pipefail +journalctl --sync +if timeout 2m journalctl -u init.scope --since="$TS" -n all --follow | grep -m 1 -q -F '(mount-monitor-dispatch) entered rate limit'; then + journalctl --sync + timeout 2m journalctl -u init.scope --since="$TS" -n all --follow | grep -m 1 -q -F '(mount-monitor-dispatch) left rate limit' fi +set -o pipefail # Verify that the mount units are always cleaned up at the end. # Give some time for units to settle so we don't race between exiting the rate limit state and cleaning up the units. diff --git a/test/units/TEST-62-RESTRICT-IFACES-1.service b/test/units/TEST-62-RESTRICT-IFACES-1.service new file mode 100644 index 0000000..16695c1 --- /dev/null +++ b/test/units/TEST-62-RESTRICT-IFACES-1.service @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Unit] +Description=TEST-62-RESTRICT-IFACES-all-pings-work +[Service] +ExecStart=sh -c 'ping -c 1 -W 0.2 192.168.113.1' +ExecStart=sh -c 'ping -c 1 -W 0.2 192.168.113.5' +ExecStart=sh -c 'ping -c 1 -W 0.2 192.168.113.9' +RestrictNetworkInterfaces= +Type=oneshot diff --git a/test/units/TEST-62-RESTRICT-IFACES-2.service b/test/units/TEST-62-RESTRICT-IFACES-2.service new file mode 100644 index 0000000..bce7e8e --- /dev/null +++ b/test/units/TEST-62-RESTRICT-IFACES-2.service @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Unit] +Description=TEST-62-RESTRICT-IFACES-allow-list +[Service] +ExecStart=sh -c 'ping -c 1 -W 0.2 192.168.113.1' +ExecStart=sh -c 'ping -c 1 -W 0.2 192.168.113.5' +ExecStart=sh -c '! ping -c 1 -W 0.2 192.168.113.9' +RestrictNetworkInterfaces=veth0 +RestrictNetworkInterfaces=veth1 +Type=oneshot diff --git a/test/units/testsuite-62-3.service b/test/units/TEST-62-RESTRICT-IFACES-3.service index b6c8e7a..116530b 100644 --- a/test/units/testsuite-62-3.service +++ b/test/units/TEST-62-RESTRICT-IFACES-3.service @@ -2,9 +2,9 @@ [Unit] Description=TEST-62-RESTRICT-IFACES-deny-list [Service] -ExecStart=/bin/sh -c '! ping -c 1 -W 0.2 192.168.113.1' -ExecStart=/bin/sh -c '! ping -c 1 -W 0.2 192.168.113.5' -ExecStart=/bin/sh -c 'ping -c 1 -W 0.2 192.168.113.9' +ExecStart=sh -c '! ping -c 1 -W 0.2 192.168.113.1' +ExecStart=sh -c '! ping -c 1 -W 0.2 192.168.113.5' +ExecStart=sh -c 'ping -c 1 -W 0.2 192.168.113.9' RestrictNetworkInterfaces=~veth0 RestrictNetworkInterfaces=~veth1 Type=oneshot diff --git a/test/units/testsuite-62-4.service b/test/units/TEST-62-RESTRICT-IFACES-4.service index 053e6d2..200a383 100644 --- a/test/units/testsuite-62-4.service +++ b/test/units/TEST-62-RESTRICT-IFACES-4.service @@ -2,9 +2,9 @@ [Unit] Description=TEST-62-RESTRICT-IFACES-empty-assignment [Service] -ExecStart=/bin/sh -c 'ping -c 1 -W 0.2 192.168.113.1' -ExecStart=/bin/sh -c 'ping -c 1 -W 0.2 192.168.113.5' -ExecStart=/bin/sh -c 'ping -c 1 -W 0.2 192.168.113.9' +ExecStart=sh -c 'ping -c 1 -W 0.2 192.168.113.1' +ExecStart=sh -c 'ping -c 1 -W 0.2 192.168.113.5' +ExecStart=sh -c 'ping -c 1 -W 0.2 192.168.113.9' RestrictNetworkInterfaces=veth0 RestrictNetworkInterfaces= Type=oneshot diff --git a/test/units/testsuite-62-5.service b/test/units/TEST-62-RESTRICT-IFACES-5.service index a8f268d..51761ba 100644 --- a/test/units/testsuite-62-5.service +++ b/test/units/TEST-62-RESTRICT-IFACES-5.service @@ -2,9 +2,9 @@ [Unit] Description=TEST-62-RESTRICT-IFACES-invert-assignment [Service] -ExecStart=/bin/sh -c '! ping -c 1 -W 0.2 192.168.113.1' -ExecStart=/bin/sh -c 'ping -c 1 -W 0.2 192.168.113.5' -ExecStart=/bin/sh -c '! ping -c 1 -W 0.2 192.168.113.9' +ExecStart=sh -c '! ping -c 1 -W 0.2 192.168.113.1' +ExecStart=sh -c 'ping -c 1 -W 0.2 192.168.113.5' +ExecStart=sh -c '! ping -c 1 -W 0.2 192.168.113.9' RestrictNetworkInterfaces=veth0 RestrictNetworkInterfaces=veth0 veth1 RestrictNetworkInterfaces=~veth0 diff --git a/test/units/testsuite-62-2.service b/test/units/TEST-62-RESTRICT-IFACES-6.service index b83362d..876d8f3 100644 --- a/test/units/testsuite-62-2.service +++ b/test/units/TEST-62-RESTRICT-IFACES-6.service @@ -1,10 +1,10 @@ # SPDX-License-Identifier: LGPL-2.1-or-later [Unit] -Description=TEST-62-RESTRICT-IFACES-allow-list +Description=TEST-62-RESTRICT-IFACES-altname [Service] ExecStart=/bin/sh -c 'ping -c 1 -W 0.2 192.168.113.1' ExecStart=/bin/sh -c 'ping -c 1 -W 0.2 192.168.113.5' ExecStart=/bin/sh -c '! ping -c 1 -W 0.2 192.168.113.9' -RestrictNetworkInterfaces=veth0 -RestrictNetworkInterfaces=veth1 +RestrictNetworkInterfaces=veth0-altname-with-more-than-15-chars +RestrictNetworkInterfaces=veth1-altname-with-more-than-15-chars Type=oneshot diff --git a/test/units/testsuite-62.sh b/test/units/TEST-62-RESTRICT-IFACES.sh index ed40821..35ab862 100755 --- a/test/units/testsuite-62.sh +++ b/test/units/TEST-62-RESTRICT-IFACES.sh @@ -17,6 +17,7 @@ setup() { ip -n "ns${i}" link set dev lo up ip -n "ns${i}" addr add "192.168.113."$((4*i+1))/30 dev "veth${i}_" ip link set dev "veth${i}" up + ip link property add dev "veth${i}" altname "veth${i}-altname-with-more-than-15-chars" ip addr add "192.168.113."$((4*i+2))/30 dev "veth${i}" done } @@ -33,31 +34,23 @@ teardown() { systemd-analyze log-level info } -KERNEL_VERSION="$(uname -r)" -KERNEL_MAJOR="${KERNEL_VERSION%%.*}" -KERNEL_MINOR="${KERNEL_VERSION#"$KERNEL_MAJOR".}" -KERNEL_MINOR="${KERNEL_MINOR%%.*}" - -MAJOR_REQUIRED=5 -MINOR_REQUIRED=7 - -if [[ "$KERNEL_MAJOR" -lt $MAJOR_REQUIRED || ("$KERNEL_MAJOR" -eq $MAJOR_REQUIRED && "$KERNEL_MINOR" -lt $MINOR_REQUIRED) ]]; then +if systemd-analyze compare-versions "$(uname -r)" lt 5.7; then echo "kernel is not 5.7+" >>/skipped - exit 0 + exit 77 fi if systemctl --version | grep -q -F -- "-BPF_FRAMEWORK"; then echo "bpf-framework is disabled" >>/skipped - exit 0 + exit 77 fi trap teardown EXIT setup -systemctl start --wait testsuite-62-1.service -systemctl start --wait testsuite-62-2.service -systemctl start --wait testsuite-62-3.service -systemctl start --wait testsuite-62-4.service -systemctl start --wait testsuite-62-5.service +systemctl start --wait TEST-62-RESTRICT-IFACES-1.service +systemctl start --wait TEST-62-RESTRICT-IFACES-2.service +systemctl start --wait TEST-62-RESTRICT-IFACES-3.service +systemctl start --wait TEST-62-RESTRICT-IFACES-4.service +systemctl start --wait TEST-62-RESTRICT-IFACES-5.service touch /testok diff --git a/test/units/testsuite-63.sh b/test/units/TEST-63-PATH.sh index ea8cd94..cdd323c 100755 --- a/test/units/testsuite-63.sh +++ b/test/units/TEST-63-PATH.sh @@ -118,7 +118,7 @@ timeout 30 bash -c 'until test "$(systemctl show test63-pr-30768.service -P Acti diff /tmp/copyme /tmp/copied echo test2 > /tmp/copyme exec {lock}<&- -timeout 30 bash -c 'until diff /tmp/copyme /tmp/copied; do sleep .2; done' +timeout 30 bash -c 'until diff /tmp/copyme /tmp/copied >/dev/null; do sleep .2; done' systemctl log-level info diff --git a/test/units/testsuite-64.sh b/test/units/TEST-64-UDEV-STORAGE.sh index 65e5f6c..5ddddf5 100755 --- a/test/units/testsuite-64.sh +++ b/test/units/TEST-64-UDEV-STORAGE.sh @@ -148,7 +148,7 @@ check_device_units() {( if ! check_device_unit "$log_level" "$path"; then return 1 fi - done < <(systemctl list-units --all --type=device --no-legend dev-* | awk '$1 !~ /dev-tty.+/ { print $1 }' | sed -e 's/\.device$//') + done < <(systemctl list-units --all --type=device --no-legend dev-* | awk '$1 !~ /dev-tty.+/ && $4 == "plugged" { print $1 }' | sed -e 's/\.device$//') return 0 )} @@ -168,7 +168,7 @@ helper_check_device_units() {( check_device_units 1 "$@" )} -testcase_megasas2_basic() { +testcase_virtio_scsi_basic() { lsblk -S [[ "$(lsblk --scsi --noheadings | wc -l)" -ge 128 ]] } @@ -239,16 +239,28 @@ testcase_nvme_subsystem() { } testcase_virtio_scsi_identically_named_partitions() { - local num + local num_part num_disk i j if [[ -v ASAN_OPTIONS || "$(systemd-detect-virt -v)" == "qemu" ]]; then - num=$((4 * 4)) + num_part=4 + num_disk=4 else - num=$((16 * 8)) + num_part=8 + num_disk=16 fi + for ((i = 0; i < num_disk; i++)); do + udevadm lock --device "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive$i" \ + sfdisk "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive$i" <<EOF +label: gpt + +$(for ((j = 1; j <= num_part; j++)); do echo 'name="Hello world", size=2M'; done) +EOF + done + + udevadm settle lsblk --noheadings -a -o NAME,PARTLABEL - [[ "$(lsblk --noheadings -a -o NAME,PARTLABEL | grep -c "Hello world")" -eq "$num" ]] + [[ "$(lsblk --noheadings -a -o NAME,PARTLABEL | grep -c "Hello world")" -eq "$((num_part * num_disk))" ]] } testcase_multipath_basic_failover() { @@ -270,6 +282,18 @@ blacklist_exceptions { blacklist { } EOF + + udevadm lock --device /dev/disk/by-id/wwn-0xdeaddeadbeef0000 \ + sfdisk /dev/disk/by-id/wwn-0xdeaddeadbeef0000 <<EOF +label: gpt + +name="first_partition", size=5M +uuid="deadbeef-dead-dead-beef-000000000000", name="failover_part", size=5M +EOF + udevadm settle + udevadm lock --device /dev/disk/by-id/wwn-0xdeaddeadbeef0000-part2 \ + mkfs.ext4 -U "deadbeef-dead-dead-beef-111111111111" -L "failover_vol" /dev/disk/by-id/wwn-0xdeaddeadbeef0000-part2 + modprobe -v dm_multipath systemctl start multipathd.service systemctl status multipathd.service @@ -362,7 +386,7 @@ testcase_simultaneous_events_1() { else num_part=10 iterations=100 - timeout=30 + timeout=60 fi for disk in {0..9}; do @@ -521,9 +545,15 @@ testcase_lvm_basic() { local i iterations partitions part timeout local vgroup="MyTestGroup$RANDOM" local devices=( - /dev/disk/by-id/ata-foobar_deadbeeflvm{0..3} + /dev/disk/by-id/scsi-0systemd_foobar_deadbeeflvm{0..3} ) + . /etc/os-release + if [[ "$ID" == "ubuntu" ]]; then + echo "LVM on Ubuntu is broken, skipping the test" | tee --append /skipped + exit 77 + fi + if [[ -v ASAN_OPTIONS || "$(systemd-detect-virt -v)" == "qemu" ]]; then timeout=180 else @@ -544,6 +574,7 @@ testcase_lvm_basic() { lvm lvs udevadm wait --settle --timeout="$timeout" "/dev/$vgroup/mypart1" "/dev/$vgroup/mypart2" mkfs.ext4 -L mylvpart1 "/dev/$vgroup/mypart1" + udevadm trigger --settle "/dev/$vgroup/mypart1" udevadm wait --settle --timeout="$timeout" "/dev/disk/by-label/mylvpart1" helper_check_device_symlinks "/dev/disk" "/dev/$vgroup" helper_check_device_units @@ -599,6 +630,7 @@ testcase_lvm_basic() { cryptsetup open --key-file=/etc/lvm_keyfile "/dev/$vgroup/mypart2" "lvmluksmap" udevadm wait --settle --timeout="$timeout" "/dev/mapper/lvmluksmap" mkfs.ext4 -L lvmluksfs "/dev/mapper/lvmluksmap" + udevadm trigger --settle "/dev/mapper/lvmluksmap" udevadm wait --settle --timeout="$timeout" "/dev/disk/by-label/lvmluksfs" # Make systemd "interested" in the mount by adding it to /etc/fstab echo "/dev/disk/by-label/lvmluksfs /tmp/lvmluksmnt ext4 defaults 0 2" >>/etc/fstab @@ -693,9 +725,14 @@ testcase_lvm_basic() { testcase_btrfs_basic() { local dev_stub i label mpoint uuid local devices=( - /dev/disk/by-id/ata-foobar_deadbeefbtrfs{0..3} + /dev/disk/by-id/scsi-0systemd_foobar_deadbeefbtrfs{0..3} ) + if ! modinfo btrfs; then + echo "This test requires the btrfs kernel module but it is not installed, skipping the test" | tee --append /skipped + exit 77 + fi + ls -l "${devices[@]}" echo "Single device: default settings" @@ -731,10 +768,10 @@ EOF uuid="deadbeef-dead-dead-beef-000000000002" label="btrfs_mdisk" udevadm lock \ - --device=/dev/disk/by-id/ata-foobar_deadbeefbtrfs0 \ - --device=/dev/disk/by-id/ata-foobar_deadbeefbtrfs1 \ - --device=/dev/disk/by-id/ata-foobar_deadbeefbtrfs2 \ - --device=/dev/disk/by-id/ata-foobar_deadbeefbtrfs3 \ + --device=/dev/disk/by-id/scsi-0systemd_foobar_deadbeefbtrfs0 \ + --device=/dev/disk/by-id/scsi-0systemd_foobar_deadbeefbtrfs1 \ + --device=/dev/disk/by-id/scsi-0systemd_foobar_deadbeefbtrfs2 \ + --device=/dev/disk/by-id/scsi-0systemd_foobar_deadbeefbtrfs3 \ mkfs.btrfs -f -M -d raid10 -m raid10 -L "$label" -U "$uuid" "${devices[@]}" udevadm wait --settle --timeout=30 "/dev/disk/by-uuid/$uuid" "/dev/disk/by-label/$label" btrfs filesystem show @@ -755,9 +792,10 @@ EOF for ((i = 0; i < ${#devices[@]}; i++)); do # Intentionally use weaker cipher-related settings, since we don't care # about security here as it's a throwaway LUKS partition - cryptsetup luksFormat -q \ - --use-urandom --pbkdf pbkdf2 --pbkdf-force-iterations 1000 \ - --uuid "deadbeef-dead-dead-beef-11111111111$i" --label "encdisk$i" "${devices[$i]}" /etc/btrfs_keyfile + udevadm lock --device="${devices[$i]}" \ + cryptsetup luksFormat -q \ + --use-urandom --pbkdf pbkdf2 --pbkdf-force-iterations 1000 \ + --uuid "deadbeef-dead-dead-beef-11111111111$i" --label "encdisk$i" "${devices[$i]}" /etc/btrfs_keyfile udevadm wait --settle --timeout=30 "/dev/disk/by-uuid/deadbeef-dead-dead-beef-11111111111$i" "/dev/disk/by-label/encdisk$i" # Add the device into /etc/crypttab, reload systemd, and then activate # the device so we can create a filesystem on it later @@ -824,14 +862,28 @@ testcase_iscsi_lvm() { local vgroup="iscsi_lvm$RANDOM" local expected_symlinks=() local devices=( - /dev/disk/by-id/ata-foobar_deadbeefiscsi{0..3} + /dev/disk/by-id/scsi-0systemd_foobar_deadbeefiscsi{0..3} ) + . /etc/os-release + if [[ "$ID" == "ubuntu" ]]; then + echo "LVM on Ubuntu is broken, skipping the test" | tee --append /skipped + exit 77 + fi + ls -l "${devices[@]}" - # Start the target daemon - systemctl start tgtd - systemctl status tgtd + # Start the target daemon (debian names it tgt.service so make sure we handle that) + if systemctl list-unit-files tgt.service; then + systemctl start tgt + systemctl status tgt + elif systemctl list-unit-files tgtd.service; then + systemctl start tgtd + systemctl status tgtd + else + echo "This test requires tgtd but it is not installed, skipping ..." | tee --append /skipped + exit 77 + fi echo "iSCSI LUNs backed by devices" # See RFC3721 and RFC7143 @@ -867,7 +919,7 @@ testcase_iscsi_lvm() { mpoint="$(mktemp -d /iscsi_storeXXX)" expected_symlinks=() # Use the first device as it's configured with larger capacity - mkfs.ext4 -L iscsi_store "${devices[0]}" + udevadm lock --device "${devices[0]}" mkfs.ext4 -L iscsi_store "${devices[0]}" udevadm wait --settle --timeout=30 "${devices[0]}" mount "${devices[0]}" "$mpoint" for i in {1..4}; do @@ -903,6 +955,7 @@ testcase_iscsi_lvm() { lvm lvs udevadm wait --settle --timeout=30 "/dev/$vgroup/mypart1" "/dev/$vgroup/mypart2" mkfs.ext4 -L mylvpart1 "/dev/$vgroup/mypart1" + udevadm trigger --settle "/dev/$vgroup/mypart1" udevadm wait --settle --timeout=30 "/dev/disk/by-label/mylvpart1" helper_check_device_symlinks "/dev/disk" "/dev/$vgroup" helper_check_device_units @@ -950,6 +1003,16 @@ testcase_long_sysfs_path() { stat /sys/block/vda readlink -f /sys/block/vda/dev + dev="/dev/vda" + udevadm lock --device "$dev" sfdisk "$dev" <<EOF +label: gpt + +name="test_swap", size=32M +uuid="deadbeef-dead-dead-beef-000000000000", name="test_part", size=5M +EOF + udevadm settle + udevadm lock --device "${dev}1" mkswap -U "deadbeef-dead-dead-beef-111111111111" -L "swap_vol" "${dev}1" + udevadm lock --device "${dev}2" mkfs.ext4 -U "deadbeef-dead-dead-beef-222222222222" -L "data_vol" "${dev}2" udevadm wait --settle --timeout=30 "${expected_symlinks[@]}" # Try to mount the data partition manually (using its label) @@ -992,7 +1055,7 @@ testcase_mdadm_basic() { local i part_name raid_name raid_dev uuid local expected_symlinks=() local devices=( - /dev/disk/by-id/ata-foobar_deadbeefmdadm{0..4} + /dev/disk/by-id/scsi-0systemd_foobar_deadbeefmdadm{0..4} ) ls -l "${devices[@]}" @@ -1009,9 +1072,11 @@ testcase_mdadm_basic() { "/dev/disk/by-label/$part_name" # ext4 partition ) # Create a simple RAID 1 with an ext4 filesystem - echo y | mdadm --create "$raid_dev" --name "$raid_name" --uuid "$uuid" /dev/disk/by-id/ata-foobar_deadbeefmdadm{0..1} -v -f --level=1 --raid-devices=2 + echo y | mdadm --create "$raid_dev" --name "$raid_name" --uuid "$uuid" /dev/disk/by-id/scsi-0systemd_foobar_deadbeefmdadm{0..1} -v -f --level=1 --raid-devices=2 udevadm wait --settle --timeout=30 "$raid_dev" + # udevd does not lock md devices, hence we need to trigger uevent after creating filesystem. mkfs.ext4 -L "$part_name" "$raid_dev" + udevadm trigger --settle "$raid_dev" udevadm wait --settle --timeout=30 "${expected_symlinks[@]}" for i in {0..9}; do echo "Disassemble - reassemble loop, iteration #$i" @@ -1038,9 +1103,10 @@ testcase_mdadm_basic() { "/dev/disk/by-label/$part_name" # ext4 partition ) # Create a simple RAID 5 with an ext4 filesystem - echo y | mdadm --create "$raid_dev" --name "$raid_name" --uuid "$uuid" /dev/disk/by-id/ata-foobar_deadbeefmdadm{0..2} -v -f --level=5 --raid-devices=3 + echo y | mdadm --create "$raid_dev" --name "$raid_name" --uuid "$uuid" /dev/disk/by-id/scsi-0systemd_foobar_deadbeefmdadm{0..2} -v -f --level=5 --raid-devices=3 udevadm wait --settle --timeout=30 "$raid_dev" mkfs.ext4 -L "$part_name" "$raid_dev" + udevadm trigger --settle "$raid_dev" udevadm wait --settle --timeout=30 "${expected_symlinks[@]}" for i in {0..9}; do echo "Disassemble - reassemble loop, iteration #$i" @@ -1078,10 +1144,11 @@ testcase_mdadm_basic() { "/dev/disk/by-id/md-uuid-$uuid-part3" ) # Create a simple RAID 10 with an ext4 filesystem - echo y | mdadm --create "$raid_dev" --name "$raid_name" --uuid "$uuid" /dev/disk/by-id/ata-foobar_deadbeefmdadm{0..3} -v -f --level=10 --raid-devices=4 + echo y | mdadm --create "$raid_dev" --name "$raid_name" --uuid "$uuid" /dev/disk/by-id/scsi-0systemd_foobar_deadbeefmdadm{0..3} -v -f --level=10 --raid-devices=4 udevadm wait --settle --timeout=30 "$raid_dev" # Partition the raid device # Here, 'udevadm lock' is meaningless, as udevd does not lock MD devices. + # We need to trigger uevents after sfdisk and mkfs. sfdisk --wipe=always "$raid_dev" <<EOF label: gpt @@ -1089,8 +1156,10 @@ uuid="deadbeef-dead-dead-beef-111111111111", name="mdpart1", size=8M uuid="deadbeef-dead-dead-beef-222222222222", name="mdpart2", size=32M uuid="deadbeef-dead-dead-beef-333333333333", name="mdpart3", size=16M EOF + udevadm trigger --settle --parent-match "$raid_dev" udevadm wait --settle --timeout=30 "/dev/disk/by-id/md-uuid-$uuid-part2" mkfs.ext4 -L "$part_name" "/dev/disk/by-id/md-uuid-$uuid-part2" + udevadm trigger --settle "/dev/disk/by-id/md-uuid-$uuid-part2" udevadm wait --settle --timeout=30 "${expected_symlinks[@]}" for i in {0..9}; do echo "Disassemble - reassemble loop, iteration #$i" @@ -1112,7 +1181,7 @@ testcase_mdadm_lvm() { local part_name raid_name raid_dev uuid vgroup local expected_symlinks=() local devices=( - /dev/disk/by-id/ata-foobar_deadbeefmdadmlvm{0..4} + /dev/disk/by-id/scsi-0systemd_foobar_deadbeefmdadmlvm{0..4} ) ls -l "${devices[@]}" @@ -1131,7 +1200,7 @@ testcase_mdadm_lvm() { "/dev/disk/by-label/$part_name" # ext4 partition ) # Create a RAID 10 with LVM + ext4 - echo y | mdadm --create "$raid_dev" --name "$raid_name" --uuid "$uuid" /dev/disk/by-id/ata-foobar_deadbeefmdadmlvm{0..3} -v -f --level=10 --raid-devices=4 + echo y | mdadm --create "$raid_dev" --name "$raid_name" --uuid "$uuid" /dev/disk/by-id/scsi-0systemd_foobar_deadbeefmdadmlvm{0..3} -v -f --level=10 --raid-devices=4 udevadm wait --settle --timeout=30 "$raid_dev" # Create an LVM on the MD lvm pvcreate -y "$raid_dev" @@ -1144,6 +1213,7 @@ testcase_mdadm_lvm() { lvm lvs udevadm wait --settle --timeout=30 "/dev/$vgroup/mypart1" "/dev/$vgroup/mypart2" mkfs.ext4 -L "$part_name" "/dev/$vgroup/mypart2" + udevadm trigger --settle "/dev/$vgroup/mypart2" udevadm wait --settle --timeout=30 "${expected_symlinks[@]}" # Disassemble the array lvm vgchange -an "$vgroup" diff --git a/test/units/testsuite-65.sh b/test/units/TEST-65-ANALYZE.sh index a6bb38d..18f5c4d 100755 --- a/test/units/testsuite-65.sh +++ b/test/units/TEST-65-ANALYZE.sh @@ -20,6 +20,7 @@ systemd-analyze critical-chain || : # blame systemd-analyze blame systemd-run --wait --user --pipe -M testuser@.host systemd-analyze blame +(! systemd-analyze blame --global) # plot systemd-analyze plot >/dev/null || : systemd-analyze plot --json=pretty >/dev/null || : @@ -30,6 +31,7 @@ systemd-analyze plot --json=short --no-legend >/dev/null || : systemd-analyze plot --json=off --no-legend >/dev/null || : systemd-analyze plot --table >/dev/null || : systemd-analyze plot --table --no-legend >/dev/null || : +(! systemd-analyze plot --global) # legacy/deprecated options (moved to systemctl, but still usable from analyze) systemd-analyze log-level systemd-analyze log-level "$(systemctl log-level)" @@ -52,6 +54,7 @@ systemd-analyze dot --order systemd-journald.service systemd-logind.service >/de systemd-analyze dot --require systemd-journald.service systemd-logind.service >/dev/null systemd-analyze dot "systemd-*.service" >/dev/null (! systemd-analyze dot systemd-journald.service systemd-logind.service "*" bbb ccc) +(! systemd-analyze dot --global systemd-journald.service) # dump # this should be rate limited to 10 calls in 10 minutes for unprivileged callers for _ in {1..10}; do @@ -73,8 +76,11 @@ systemd-analyze dump "*" >/dev/null systemd-analyze dump "*.socket" >/dev/null systemd-analyze dump "*.socket" "*.service" aaaaaaa ... >/dev/null systemd-analyze dump systemd-journald.service >/dev/null -systemd-analyze malloc >/dev/null (! systemd-analyze dump "") +(! systemd-analyze dump --global systemd-journald.service) +# malloc +systemd-analyze malloc >/dev/null +(! systemd-analyze malloc --global) # unit-files systemd-analyze unit-files >/dev/null systemd-analyze unit-files systemd-journald.service >/dev/null @@ -82,6 +88,7 @@ systemd-analyze unit-files "*" >/dev/null systemd-analyze unit-files "*" aaaaaa "*.service" "*.target" >/dev/null systemd-analyze unit-files --user >/dev/null systemd-analyze unit-files --user "*" aaaaaa "*.service" "*.target" >/dev/null +(! systemd-analyze unit-files --global) # unit-paths systemd-analyze unit-paths systemd-analyze unit-paths --user @@ -91,11 +98,13 @@ systemd-analyze exit-status systemd-analyze exit-status STDOUT BPF systemd-analyze exit-status 0 1 {63..65} (! systemd-analyze exit-status STDOUT BPF "hello*") +(! systemd-analyze exit-status --global) # capability systemd-analyze capability systemd-analyze capability cap_chown CAP_KILL systemd-analyze capability 0 1 {30..32} (! systemd-analyze capability cap_chown CAP_KILL "hello*") +(! systemd-analyze capability --global) # condition mkdir -p /run/systemd/system UNIT_NAME="analyze-condition-$RANDOM.service" @@ -107,7 +116,7 @@ ConditionKernelVersion=>1.0 ConditionPathExists=/etc/os-release [Service] -ExecStart=/bin/true +ExecStart=true EOF systemctl daemon-reload systemd-analyze condition --unit="$UNIT_NAME" @@ -119,17 +128,20 @@ systemd-analyze condition 'ConditionKernelVersion = ! <4.0' \ (! systemd-analyze condition 'ConditionArchitecture=|!arm' 'AssertXYZ=foo') (! systemd-analyze condition 'ConditionKernelVersion=<1.0') (! systemd-analyze condition 'AssertKernelVersion=<1.0') +(! systemd-analyze condition --global 'ConditionKernelVersion = ! <4.0') # syscall-filter systemd-analyze syscall-filter >/dev/null systemd-analyze syscall-filter @chown @sync systemd-analyze syscall-filter @sync @sync @sync (! systemd-analyze syscall-filter @chown @sync @foobar) +(! systemd-analyze syscall-filter --global) # filesystems (requires libbpf support) if systemctl --version | grep "+BPF_FRAMEWORK"; then systemd-analyze filesystems >/dev/null systemd-analyze filesystems @basic-api systemd-analyze filesystems @basic-api @basic-api @basic-api (! systemd-analyze filesystems @basic-api @basic-api @foobar @basic-api) + (! systemd-analyze filesystems --global @basic-api) fi # calendar systemd-analyze calendar '*-2-29 0:0:0' @@ -144,6 +156,7 @@ systemd-analyze calendar --base-time=yesterday --iterations=5 '*-* *:*:*' (! systemd-analyze calendar --base-time=never '*-* *:*:*') (! systemd-analyze calendar 1) (! systemd-analyze calendar "") +(! systemd-analyze calendar --global '*-2-29 0:0:0') # timestamp systemd-analyze timestamp now systemd-analyze timestamp -- -1 @@ -152,6 +165,7 @@ systemd-analyze timestamp yesterday now tomorrow (! systemd-analyze timestamp 1) (! systemd-analyze timestamp '*-2-29 0:0:0') (! systemd-analyze timestamp "") +(! systemd-analyze timestamp --global now) # timespan systemd-analyze timespan 1 systemd-analyze timespan 1s 300s '1year 0.000001s' @@ -159,6 +173,7 @@ systemd-analyze timespan 1s 300s '1year 0.000001s' (! systemd-analyze timespan -- -1) (! systemd-analyze timespan '*-2-29 0:0:0') (! systemd-analyze timespan "") +(! systemd-analyze timespan --global 1) # cat-config systemd-analyze cat-config systemd/system.conf >/dev/null systemd-analyze cat-config /etc/systemd/system.conf >/dev/null @@ -170,16 +185,21 @@ systemd-analyze cat-config --tldr /etc/systemd/system.conf >/dev/null systemd-analyze cat-config --tldr systemd/system.conf systemd/journald.conf >/dev/null systemd-analyze cat-config --tldr systemd/system.conf foo/bar systemd/journald.conf >/dev/null systemd-analyze cat-config --tldr foo/bar +(! systemd-analyze cat-config --global systemd/system.conf) # security systemd-analyze security systemd-analyze security --json=off systemd-analyze security --json=pretty | jq systemd-analyze security --json=short | jq +(! systemd-analyze security --global) if [[ ! -v ASAN_OPTIONS ]]; then # check that systemd-analyze cat-config paths work in a chroot mkdir -p /tmp/root mount --bind / /tmp/root + if mountpoint -q /usr; then + mount --bind /usr /tmp/root/usr + fi systemd-analyze cat-config systemd/system-preset >/tmp/out1 chroot /tmp/root systemd-analyze cat-config systemd/system-preset >/tmp/out2 diff /tmp/out{1,2} @@ -282,6 +302,11 @@ systemd-analyze security --offline=true /tmp/testfile.service # Ensure we print the list of ACLs, see https://github.com/systemd/systemd/issues/23185 systemd-analyze security --offline=true /tmp/testfile.service | grep -q -F "/dev/sda" +# Make sure that running generators under systemd-analyze verify works. +# Note: sd-analyze spawns generators in a sandbox which makes gcov unhapy, so temporarily override +# $GCOV_PREFIX to make it skip generating any coverage reports +GCOV_PREFIX=/tmp systemd-analyze verify --generators /tmp/testfile.service + rm /tmp/testfile.service cat <<EOF >/tmp/img/usr/lib/systemd/system/testfile.service @@ -334,6 +359,17 @@ systemd-analyze verify /tmp/hoge@test.service (! systemd-analyze verify /tmp/hoge@nonexist.service) (! systemd-analyze verify /tmp/hoge@.service) +# test that all commands are verified. +cat <<EOF >/tmp/multi-exec-start.service +[Service] +Type=oneshot +ExecStart=true +ExecStart=ls +EOF +systemd-analyze verify /tmp/multi-exec-start.service +echo 'ExecStart=command-should-not-exist' >>/tmp/multi-exec-start.service +(! systemd-analyze verify /tmp/multi-exec-start.service) + # Added an additional "INVALID_ID" id to the .json to verify that nothing breaks when input is malformed # The PrivateNetwork id description and weight was changed to verify that 'security' is actually reading in # values from the .json file when required. The default weight for "PrivateNetwork" is 2500, and the new weight @@ -904,6 +940,13 @@ systemd-analyze pcrs systemd-analyze pcrs --json=pretty systemd-analyze pcrs 14 7 0 ima +systemd-analyze architectures +systemd-analyze architectures --json=pretty +systemd-analyze architectures x86 +systemd-analyze architectures x86-64 +systemd-analyze architectures native +systemd-analyze architectures uname + systemd-analyze log-level info touch /testok diff --git a/test/units/TEST-66-DEVICE-ISOLATION-device-isolation.service b/test/units/TEST-66-DEVICE-ISOLATION-device-isolation.service new file mode 100644 index 0000000..85b3d0d --- /dev/null +++ b/test/units/TEST-66-DEVICE-ISOLATION-device-isolation.service @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Unit] +Description=Service that uses device isolation + +[Service] +DevicePolicy=strict +DeviceAllow=/dev/null r +StandardOutput=file:/tmp/TEST-66-DEVICE-ISOLATION.serviceresults +ExecStartPre=rm -f /tmp/TEST-66-DEVICE-ISOLATION.serviceresults +ExecStart=bash -c "while true; do sleep 0.01 && echo meow >/dev/null && echo thisshouldnotbehere; done" diff --git a/test/units/testsuite-66.sh b/test/units/TEST-66-DEVICE-ISOLATION.sh index 147335a..ccdfcb2 100755 --- a/test/units/testsuite-66.sh +++ b/test/units/TEST-66-DEVICE-ISOLATION.sh @@ -3,11 +3,11 @@ set -eux set -o pipefail -RESULTS_FILE=/tmp/testsuite66serviceresults +RESULTS_FILE=/tmp/TEST-66-DEVICE-ISOLATION.serviceresults systemd-analyze log-level debug -systemctl start testsuite-66-deviceisolation.service +systemctl start TEST-66-DEVICE-ISOLATION-device-isolation.service sleep 5 grep -q "Operation not permitted" "$RESULTS_FILE" @@ -15,7 +15,7 @@ grep -q "Operation not permitted" "$RESULTS_FILE" systemctl daemon-reload systemctl daemon-reexec -systemctl stop testsuite-66-deviceisolation.service +systemctl stop TEST-66-DEVICE-ISOLATION-device-isolation.service grep -q "thisshouldnotbehere" "$RESULTS_FILE" && exit 42 diff --git a/test/units/testsuite-67.sh b/test/units/TEST-67-INTEGRITY.sh index a42fd66..a42fd66 100755 --- a/test/units/testsuite-67.sh +++ b/test/units/TEST-67-INTEGRITY.sh diff --git a/test/units/testsuite-68.sh b/test/units/TEST-68-PROPAGATE-EXIT-STATUS.sh index 11da48a..11da48a 100755 --- a/test/units/testsuite-68.sh +++ b/test/units/TEST-68-PROPAGATE-EXIT-STATUS.sh diff --git a/test/units/TEST-69-SHUTDOWN.py b/test/units/TEST-69-SHUTDOWN.py new file mode 100755 index 0000000..eb790f4 --- /dev/null +++ b/test/units/TEST-69-SHUTDOWN.py @@ -0,0 +1,58 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: LGPL-2.1-or-later +# pylint: disable=broad-except + +import logging +import sys + +import pexpect + + +def main(): + logger = logging.getLogger("test-shutdown") + + consoles = [] + for _ in range(2): + # Use script to allocate a separate pseudo tty to run the login shell in. + console = pexpect.spawn( + "script", ["--quiet", "--return", "--flush", "--command", "login -f root", "/dev/null"], + logfile=sys.stdout, + env={"TERM": "dumb"}, + encoding="utf-8", + timeout=60, + ) + + logger.info("waiting for login prompt") + console.expect(".*# ", 10) + + consoles += [console] + + consoles[1].sendline("tty") + consoles[1].expect(r"/dev/(pts/\d+)") + pty = console.match.group(1) + logger.info("window 1 at tty %s", pty) + + logger.info("schedule reboot") + consoles[1].sendline("shutdown -r") + consoles[1].expect("Reboot scheduled for (?P<date>.*), use 'shutdown -c' to cancel", 2) + date = consoles[1].match.group("date") + logger.info("reboot scheduled for %s", date) + + logger.info("verify broadcast message") + consoles[0].expect(f"Broadcast message from root@H on {pty}", 2) + consoles[0].expect(f"The system will reboot at {date}!", 2) + + logger.info("check show output") + consoles[1].sendline("shutdown --show") + consoles[1].expect(f"Reboot scheduled for {date}, use 'shutdown -c' to cancel", 2) + + logger.info("cancel shutdown") + consoles[1].sendline("shutdown -c") + consoles[0].expect("System shutdown has been cancelled", 2) + + consoles[0].sendline("> /testok") + +if __name__ == "__main__": + main() + +# vim: sw=4 et diff --git a/test/units/testsuite-70.creds.sh b/test/units/TEST-70-TPM2.creds.sh index e66bfd1..e66bfd1 100755 --- a/test/units/testsuite-70.creds.sh +++ b/test/units/TEST-70-TPM2.creds.sh diff --git a/test/units/testsuite-70.cryptenroll.sh b/test/units/TEST-70-TPM2.cryptenroll.sh index 3f8c14e..f18ef02 100755 --- a/test/units/testsuite-70.cryptenroll.sh +++ b/test/units/TEST-70-TPM2.cryptenroll.sh @@ -59,6 +59,18 @@ systemd-cryptenroll --fido2-with-user-verification=false "$IMAGE" systemd-cryptenroll --tpm2-pcrs=8 "$IMAGE" systemd-cryptenroll --tpm2-pcrs=boot-loader-code+boot-loader-config "$IMAGE" +# Unlocking using TPM2 +PASSWORD=foo systemd-cryptenroll --tpm2-device=auto "$IMAGE" +systemd-cryptenroll --unlock-tpm2-device=auto --recovery-key "$IMAGE" +systemd-cryptenroll --unlock-tpm2-device=auto --tpm2-device=auto --wipe-slot=tpm2 "$IMAGE" + +# Add PIN to TPM2 enrollment +NEWPIN=1234 systemd-cryptenroll --unlock-tpm2-device=auto --tpm2-device=auto --tpm2-with-pin=yes "$IMAGE" + +# Change PIN on TPM2 enrollment +PIN=1234 NEWPIN=4321 systemd-cryptenroll --unlock-tpm2-device=auto --tpm2-device=auto --tpm2-with-pin=yes "$IMAGE" +PIN=4321 systemd-cryptenroll --unlock-tpm2-device=auto --recovery-key "$IMAGE" + (! systemd-cryptenroll --fido2-with-client-pin=false) (! systemd-cryptenroll --fido2-with-user-presence=f "$IMAGE" /tmp/foo) (! systemd-cryptenroll --fido2-with-client-pin=1234 "$IMAGE") diff --git a/test/units/testsuite-70.cryptsetup.sh b/test/units/TEST-70-TPM2.cryptsetup.sh index 4cd627f..cb7c8b1 100755 --- a/test/units/testsuite-70.cryptsetup.sh +++ b/test/units/TEST-70-TPM2.cryptsetup.sh @@ -212,6 +212,7 @@ Encrypt=tpm2 EOF PASSWORD=passphrase systemd-repart --tpm2-device-key=/tmp/srk.pub --definitions=/tmp/dditest --empty=create --size=50M /tmp/dditest.raw --tpm2-pcrs= DEVICE="$(systemd-dissect --attach /tmp/dditest.raw)" + udevadm wait --settle --timeout=10 "$DEVICE"p1 systemd-cryptsetup attach dditest "$DEVICE"p1 - tpm2-device=auto,headless=yes mkdir /tmp/dditest.mnt mount -t ext4 /dev/mapper/dditest /tmp/dditest.mnt diff --git a/test/units/testsuite-70.measure.sh b/test/units/TEST-70-TPM2.measure.sh index 3336f38..3336f38 100755 --- a/test/units/testsuite-70.measure.sh +++ b/test/units/TEST-70-TPM2.measure.sh diff --git a/test/units/testsuite-70.pcrextend.sh b/test/units/TEST-70-TPM2.pcrextend.sh index 318fce0..318fce0 100755 --- a/test/units/testsuite-70.pcrextend.sh +++ b/test/units/TEST-70-TPM2.pcrextend.sh diff --git a/test/units/testsuite-70.pcrlock.sh b/test/units/TEST-70-TPM2.pcrlock.sh index 3da9926..fd51161 100755 --- a/test/units/testsuite-70.pcrlock.sh +++ b/test/units/TEST-70-TPM2.pcrlock.sh @@ -74,7 +74,7 @@ if [[ -n "$SD_STUB" ]]; then "$SD_PCRLOCK" lock-uki <"$SD_STUB" fi -PIN=huhu "$SD_PCRLOCK" make-policy --pcr="$PCRS" --recovery-pin=yes +PIN=huhu "$SD_PCRLOCK" make-policy --pcr="$PCRS" --recovery-pin=query # Repeat immediately (this call will have to reuse the nvindex, rather than create it) "$SD_PCRLOCK" make-policy --pcr="$PCRS" "$SD_PCRLOCK" make-policy --pcr="$PCRS" --force @@ -85,7 +85,7 @@ echo -n hoho >/tmp/pcrlockpwd chmod 0600 /tmp/pcrlockpwd cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom "$img" /tmp/pcrlockpwd -systemd-cryptenroll --unlock-key-file=/tmp/pcrlockpwd --tpm2-device=auto --tpm2-pcrlock=/var/lib/systemd/pcrlock.json --tpm2-public-key= --wipe-slot=tpm2 "$img" +systemd-cryptenroll --unlock-key-file=/tmp/pcrlockpwd --tpm2-device=auto --tpm2-pcrlock=/var/lib/systemd/pcrlock.json --wipe-slot=tpm2 "$img" systemd-cryptsetup attach pcrlock "$img" - tpm2-device=auto,tpm2-pcrlock=/var/lib/systemd/pcrlock.json,headless systemd-cryptsetup detach pcrlock @@ -102,7 +102,7 @@ systemd-cryptsetup detach pcrlock # work. echo -n test70 | "$SD_PCRLOCK" lock-raw --pcrlock=/var/lib/pcrlock.d/910-test70.pcrlock --pcr=16 (! "$SD_PCRLOCK" make-policy --pcr="$PCRS") -PIN=huhu "$SD_PCRLOCK" make-policy --pcr="$PCRS" --recovery-pin=yes +PIN=huhu "$SD_PCRLOCK" make-policy --pcr="$PCRS" --recovery-pin=query systemd-cryptsetup attach pcrlock "$img" - tpm2-device=auto,tpm2-pcrlock=/var/lib/systemd/pcrlock.json,headless systemd-cryptsetup detach pcrlock @@ -110,6 +110,10 @@ systemd-cryptsetup detach pcrlock # And now let's do it the clean way, and generate the right policy ahead of time. echo -n test70-take-two | "$SD_PCRLOCK" lock-raw --pcrlock=/var/lib/pcrlock.d/920-test70.pcrlock --pcr=16 "$SD_PCRLOCK" make-policy --pcr="$PCRS" +# the next one should be skipped because redundant +"$SD_PCRLOCK" make-policy --pcr="$PCRS" +# but this one should not be skipped, even if redundant, because we force it +"$SD_PCRLOCK" make-policy --pcr="$PCRS" --force --recovery-pin=show "$SD_PCREXTEND" --pcr=16 test70-take-two @@ -118,7 +122,20 @@ echo -n test70-take-two | "$SD_PCRLOCK" lock-raw --pcrlock=/var/lib/pcrlock.d/92 systemd-cryptsetup attach pcrlock "$img" - tpm2-device=auto,tpm2-pcrlock=/var/lib/systemd/pcrlock.json,headless systemd-cryptsetup detach pcrlock -"$SD_PCRLOCK" remove-policy +# Now use the root fs support, i.e. make the tool write a copy of the pcrlock +# file as service credential to some temporary dir and remove the local copy, so that +# it has to use the credential version. +mkdir /tmp/fakexbootldr +SYSTEMD_XBOOTLDR_PATH=/tmp/fakexbootldr SYSTEMD_RELAX_XBOOTLDR_CHECKS=1 "$SD_PCRLOCK" make-policy --pcr="$PCRS" --force +mv /var/lib/systemd/pcrlock.json /var/lib/systemd/pcrlock.json.gone + +systemd-creds decrypt /tmp/fakexbootldr/loader/credentials/pcrlock.*.cred + +SYSTEMD_ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY=/tmp/fakexbootldr/loader/credentials systemd-cryptsetup attach pcrlock "$img" - tpm2-device=auto,headless +systemd-cryptsetup detach pcrlock + +mv /var/lib/systemd/pcrlock.json.gone /var/lib/systemd/pcrlock.json +SYSTEMD_XBOOTLDR_PATH=/tmp/fakexbootldr SYSTEMD_RELAX_XBOOTLDR_CHECKS=1 "$SD_PCRLOCK" remove-policy "$SD_PCRLOCK" unlock-firmware-config "$SD_PCRLOCK" unlock-gpt @@ -143,4 +160,20 @@ systemd-cryptsetup detach pcrlock (! "$SD_PCRLOCK" lock-uki /bin/true) (! "$SD_PCRLOCK" lock-file-system "") +# Exercise Varlink API a bit (but first turn off condition) + +mkdir -p /run/systemd/system/systemd-pcrlock.socket.d +cat > /run/systemd/system/systemd-pcrlock.socket.d/50-no-condition.conf <<EOF +[Unit] +# Turn off all conditions +ConditionSecurity= +EOF + +systemctl daemon-reload +systemctl restart systemd-pcrlock.socket + +varlinkctl call /run/systemd/io.systemd.PCRLock io.systemd.PCRLock.RemovePolicy '{}' +varlinkctl call /run/systemd/io.systemd.PCRLock io.systemd.PCRLock.MakePolicy '{}' +varlinkctl call --collect --json=pretty /run/systemd/io.systemd.PCRLock io.systemd.PCRLock.ReadEventLog '{}' + rm "$img" /tmp/pcrlockpwd diff --git a/test/units/testsuite-70.sh b/test/units/TEST-70-TPM2.sh index 9c2a033..9c2a033 100755 --- a/test/units/testsuite-70.sh +++ b/test/units/TEST-70-TPM2.sh diff --git a/test/units/testsuite-70.tpm2-setup.sh b/test/units/TEST-70-TPM2.tpm2-setup.sh index faf6fe7..faf6fe7 100755 --- a/test/units/testsuite-70.tpm2-setup.sh +++ b/test/units/TEST-70-TPM2.tpm2-setup.sh diff --git a/test/units/testsuite-71.sh b/test/units/TEST-71-HOSTNAME.sh index da765a9..dc3f587 100755 --- a/test/units/testsuite-71.sh +++ b/test/units/TEST-71-HOSTNAME.sh @@ -61,6 +61,12 @@ get_chassis() ( echo "$CHASSIS" ) +stop_hostnamed() { + systemctl stop systemd-hostnamed.service + # Reset trigger limit. This might fail if the unit was unloaded already, so ignore any errors. + systemctl reset-failed systemd-hostnamed || : +} + testcase_chassis() { local i @@ -80,7 +86,7 @@ testcase_chassis() { assert_eq "$(get_chassis)" "$i" done - systemctl stop systemd-hostnamed.service + stop_hostnamed rm -f /etc/machine-info # fallback chassis type @@ -95,7 +101,7 @@ restore_sysfs_dmi() { umount /sys/class/dmi/id rm -rf /run/systemd/system/systemd-hostnamed.service.d systemctl daemon-reload - systemctl stop systemd-hostnamed + stop_hostnamed } testcase_firmware_date() { @@ -120,15 +126,15 @@ EOF echo '1' >/sys/class/dmi/id/uevent echo '09/08/2000' >/sys/class/dmi/id/bios_date - systemctl stop systemd-hostnamed + stop_hostnamed assert_in '2000-09-08' "$(hostnamectl)" echo '2022' >/sys/class/dmi/id/bios_date - systemctl stop systemd-hostnamed + stop_hostnamed assert_not_in 'Firmware Date' "$(hostnamectl)" echo 'garbage' >/sys/class/dmi/id/bios_date - systemctl stop systemd-hostnamed + stop_hostnamed assert_not_in 'Firmware Date' "$(hostnamectl)" } @@ -223,6 +229,14 @@ testcase_nss-myhostname() { (! getent hosts -s myhostname fd00:dead:beef:cafe::1) } +test_varlink() { + A="$(mktemp -u)" + B="$(mktemp -u)" + varlinkctl call /run/systemd/io.systemd.Hostname io.systemd.Hostname.Describe '{}' --json=short > "$A" + hostnamectl --json=short > "$B" + cmp "$A" "$B" +} + run_testcases touch /testok diff --git a/test/units/testsuite-72.sh b/test/units/TEST-72-SYSUPDATE.sh index de657a2..5e658e0 100755 --- a/test/units/testsuite-72.sh +++ b/test/units/TEST-72-SYSUPDATE.sh @@ -6,16 +6,17 @@ set -eux set -o pipefail SYSUPDATE=/lib/systemd/systemd-sysupdate -SECTOR_SIZES="512 4096" -BACKING_FILE=/var/tmp/72-joined.raw -export SYSTEMD_ESP_PATH=/var/tmp/72-esp -export SYSTEMD_XBOOTLDR_PATH=/var/tmp/72-xbootldr +SECTOR_SIZES=(512 4096) +WORKDIR="$(mktemp -d /var/tmp/test-72-XXXXXX)" +BACKING_FILE="$WORKDIR/joined.raw" +export SYSTEMD_ESP_PATH="$WORKDIR/esp" +export SYSTEMD_XBOOTLDR_PATH="$WORKDIR/xbootldr" export SYSTEMD_PAGER=cat export SYSTEMD_LOG_LEVEL=debug -if ! test -x "$SYSUPDATE"; then +if [[ ! -x "$SYSUPDATE" ]]; then echo "no systemd-sysupdate" >/skipped - exit 0 + exit 77 fi # Loopback devices may not be supported. They are used because sfdisk cannot @@ -24,93 +25,93 @@ fi # size, and the underlying device is likely to have a sector size of 512 bytes. if [[ ! -e /dev/loop-control ]]; then echo "No loopback device support" - SECTOR_SIZES="512" + SECTOR_SIZES=(512) fi -trap cleanup ERR -cleanup() { - set +o pipefail - blockdev="$( losetup --list --output NAME,BACK-FILE | grep $BACKING_FILE | cut -d' ' -f1)" - [ -n "$blockdev" ] && losetup --detach "$blockdev" - rm -f "$BACKING_FILE" - rm -rf /var/tmp/72-{dirs,defs,source,xbootldr,esp} - rm -f /testok +at_exit() { + set +e + + losetup -n --output NAME --associated "$BACKING_FILE" | while read -r loop_dev; do + losetup --detach "$loop_dev" + done + + rm -rf "$WORKDIR" } +trap at_exit EXIT + new_version() { - # Inputs: - # $1: sector size - # $2: version + local sector_size="${1:?}" + local version="${2:?}" # Create a pair of random partition payloads, and compress one - dd if=/dev/urandom of="/var/tmp/72-source/part1-$2.raw" bs="$1" count=2048 - dd if=/dev/urandom of="/var/tmp/72-source/part2-$2.raw" bs="$1" count=2048 - gzip -k -f "/var/tmp/72-source/part2-$2.raw" + dd if=/dev/urandom of="$WORKDIR/source/part1-$version.raw" bs="$sector_size" count=2048 + dd if=/dev/urandom of="$WORKDIR/source/part2-$version.raw" bs="$sector_size" count=2048 + gzip -k -f "$WORKDIR/source/part2-$version.raw" # Create a random "UKI" payload - echo $RANDOM >"/var/tmp/72-source/uki-$2.efi" + echo $RANDOM >"$WORKDIR/source/uki-$version.efi" # Create a random extra payload - echo $RANDOM >"/var/tmp/72-source/uki-extra-$2.efi" + echo $RANDOM >"$WORKDIR/source/uki-extra-$version.efi" # Create tarball of a directory - mkdir -p "/var/tmp/72-source/dir-$2" - echo $RANDOM >"/var/tmp/72-source/dir-$2/foo.txt" - echo $RANDOM >"/var/tmp/72-source/dir-$2/bar.txt" - tar --numeric-owner -C "/var/tmp/72-source/dir-$2/" -czf "/var/tmp/72-source/dir-$2.tar.gz" . + mkdir -p "$WORKDIR/source/dir-$version" + echo $RANDOM >"$WORKDIR/source/dir-$version/foo.txt" + echo $RANDOM >"$WORKDIR/source/dir-$version/bar.txt" + tar --numeric-owner -C "$WORKDIR/source/dir-$version/" -czf "$WORKDIR/source/dir-$version.tar.gz" . - ( cd /var/tmp/72-source/ && sha256sum uki* part* dir-*.tar.gz >SHA256SUMS ) + (cd "$WORKDIR/source" && sha256sum uki* part* dir-*.tar.gz >SHA256SUMS) } update_now() { # Update to newest version. First there should be an update ready, then we # do the update, and then there should not be any ready anymore - "$SYSUPDATE" --definitions=/var/tmp/72-defs --verify=no check-new - "$SYSUPDATE" --definitions=/var/tmp/72-defs --verify=no update - ( ! "$SYSUPDATE" --definitions=/var/tmp/72-defs --verify=no check-new ) + "$SYSUPDATE" --definitions="$WORKDIR/defs" --verify=no check-new + "$SYSUPDATE" --definitions="$WORKDIR/defs" --verify=no update + (! "$SYSUPDATE" --definitions="$WORKDIR/defs" --verify=no check-new) } verify_version() { - # Inputs: - # $1: block device - # $2: sector size - # $3: version - # $4: partition number of part1 - # $5: partition number of part2 + local block_device="${1:?}" + local sector_size="${2:?}" + local version="${3:?}" + local part1_number="${4:?}" + local part2_number="${5:?}" + local gpt_reserved_sectors part1_offset part2_offset - gpt_reserved_sectors=$(( 1024 * 1024 / $2 )) - part1_offset=$(( ( $4 - 1 ) * 2048 + gpt_reserved_sectors )) - part2_offset=$(( ( $5 - 1 ) * 2048 + gpt_reserved_sectors )) + gpt_reserved_sectors=$((1024 * 1024 / sector_size)) + part1_offset=$(((part1_number - 1) * 2048 + gpt_reserved_sectors)) + part2_offset=$(((part2_number - 1) * 2048 + gpt_reserved_sectors)) # Check the partitions - dd if="$1" bs="$2" skip="$part1_offset" count=2048 | cmp "/var/tmp/72-source/part1-$3.raw" - dd if="$1" bs="$2" skip="$part2_offset" count=2048 | cmp "/var/tmp/72-source/part2-$3.raw" + dd if="$block_device" bs="$sector_size" skip="$part1_offset" count=2048 | cmp "$WORKDIR/source/part1-$version.raw" + dd if="$block_device" bs="$sector_size" skip="$part2_offset" count=2048 | cmp "$WORKDIR/source/part2-$version.raw" # Check the UKI - cmp "/var/tmp/72-source/uki-$3.efi" "/var/tmp/72-xbootldr/EFI/Linux/uki_$3+3-0.efi" - test -z "$(ls -A /var/tmp/72-esp/EFI/Linux)" + cmp "$WORKDIR/source/uki-$version.efi" "$WORKDIR/xbootldr/EFI/Linux/uki_$version+3-0.efi" + test -z "$(ls -A "$WORKDIR/esp/EFI/Linux")" # Check the extra efi - cmp "/var/tmp/72-source/uki-extra-$3.efi" "/var/tmp/72-xbootldr/EFI/Linux/uki_$3.efi.extra.d/extra.addon.efi" + cmp "$WORKDIR/source/uki-extra-$version.efi" "$WORKDIR/xbootldr/EFI/Linux/uki_$version.efi.extra.d/extra.addon.efi" # Check the directories - cmp "/var/tmp/72-source/dir-$3/foo.txt" /var/tmp/72-dirs/current/foo.txt - cmp "/var/tmp/72-source/dir-$3/bar.txt" /var/tmp/72-dirs/current/bar.txt + cmp "$WORKDIR/source/dir-$version/foo.txt" "$WORKDIR/dirs/current/foo.txt" + cmp "$WORKDIR/source/dir-$version/bar.txt" "$WORKDIR/dirs/current/bar.txt" } -for sector_size in $SECTOR_SIZES ; do +for sector_size in "${SECTOR_SIZES[@]}"; do # Disk size of: # - 1MB for GPT # - 4 partitions of 2048 sectors each # - 1MB for backup GPT - disk_size=$(( sector_size * 2048 * 4 + 1024 * 1024 * 2 )) + disk_size=$((sector_size * 2048 * 4 + 1024 * 1024 * 2)) rm -f "$BACKING_FILE" truncate -s "$disk_size" "$BACKING_FILE" if [[ -e /dev/loop-control ]]; then - # shellcheck disable=SC2086 - blockdev="$(losetup --find --show --sector-size $sector_size $BACKING_FILE)" + blockdev="$(losetup --find --show --sector-size "$sector_size" "$BACKING_FILE")" else blockdev="$BACKING_FILE" fi @@ -126,16 +127,15 @@ size=2048, type=2c7357ed-ebd2-46d9-aec1-23d437ec2bf5, name=_empty size=2048, type=2c7357ed-ebd2-46d9-aec1-23d437ec2bf5, name=_empty EOF - rm -rf /var/tmp/72-dirs - mkdir -p /var/tmp/72-dirs + for d in "dirs" "defs"; do + rm -rf "${WORKDIR:?}/$d" + mkdir -p "$WORKDIR/$d" + done - rm -rf /var/tmp/72-defs - mkdir -p /var/tmp/72-defs - - cat >/var/tmp/72-defs/01-first.conf <<EOF + cat >"$WORKDIR/defs/01-first.conf" <<EOF [Source] Type=regular-file -Path=/var/tmp/72-source +Path=$WORKDIR/source MatchPattern=part1-@v.raw [Target] @@ -145,10 +145,10 @@ MatchPattern=part1-@v MatchPartitionType=root-x86-64 EOF - cat >/var/tmp/72-defs/02-second.conf <<EOF + cat >"$WORKDIR/defs/02-second.conf" <<EOF [Source] Type=regular-file -Path=/var/tmp/72-source +Path=$WORKDIR/source MatchPattern=part2-@v.raw.gz [Target] @@ -158,24 +158,24 @@ MatchPattern=part2-@v MatchPartitionType=root-x86-64-verity EOF - cat >/var/tmp/72-defs/03-third.conf <<EOF + cat >"$WORKDIR/defs/03-third.conf" <<EOF [Source] Type=directory -Path=/var/tmp/72-source +Path=$WORKDIR/source MatchPattern=dir-@v [Target] Type=directory -Path=/var/tmp/72-dirs -CurrentSymlink=/var/tmp/72-dirs/current +Path=$WORKDIR/dirs +CurrentSymlink=$WORKDIR/dirs/current MatchPattern=dir-@v InstancesMax=3 EOF - cat >/var/tmp/72-defs/04-fourth.conf <<EOF + cat >"$WORKDIR/defs/04-fourth.conf" <<EOF [Source] Type=regular-file -Path=/var/tmp/72-source +Path=$WORKDIR/source MatchPattern=uki-@v.efi [Target] @@ -191,10 +191,10 @@ TriesDone=0 InstancesMax=2 EOF - cat >/var/tmp/72-defs/05-fifth.conf <<EOF + cat >"$WORKDIR/defs/05-fifth.conf" <<EOF [Source] Type=regular-file -Path=/var/tmp/72-source +Path=$WORKDIR/source MatchPattern=uki-extra-@v.efi [Target] @@ -206,11 +206,8 @@ Mode=0444 InstancesMax=2 EOF - rm -rf /var/tmp/72-esp /var/tmp/72-xbootldr - mkdir -p /var/tmp/72-esp/EFI/Linux /var/tmp/72-xbootldr/EFI/Linux - - rm -rf /var/tmp/72-source - mkdir -p /var/tmp/72-source + rm -rf "${WORKDIR:?}"/{esp,xbootldr,source} + mkdir -p "$WORKDIR"/{source,esp/EFI/Linux,xbootldr/EFI/Linux} # Install initial version and verify new_version "$sector_size" v1 @@ -226,9 +223,9 @@ EOF new_version "$sector_size" v3 update_now verify_version "$blockdev" "$sector_size" v3 1 3 - test ! -f "/var/tmp/72-xbootldr/EFI/Linux/uki_v1+3-0.efi" - test ! -f "/var/tmp/72-xbootldr/EFI/Linux/uki_v1.efi.extra.d/extra.addon.efi" - test ! -d "/var/tmp/72-xbootldr/EFI/Linux/uki_v1.efi.extra.d" + test ! -f "$WORKDIR/xbootldr/EFI/Linux/uki_v1+3-0.efi" + test ! -f "$WORKDIR/xbootldr/EFI/Linux/uki_v1.efi.extra.d/extra.addon.efi" + test ! -d "$WORKDIR/xbootldr/EFI/Linux/uki_v1.efi.extra.d" # Create fourth version, and update through a file:// URL. This should be # almost as good as testing HTTP, but is simpler for us to set up. file:// is @@ -238,10 +235,10 @@ EOF # see above) new_version "$sector_size" v4 - cat >/var/tmp/72-defs/02-second.conf <<EOF + cat >"$WORKDIR/defs/02-second.conf" <<EOF [Source] Type=url-file -Path=file:///var/tmp/72-source +Path=file://$WORKDIR/source MatchPattern=part2-@v.raw.gz [Target] @@ -251,16 +248,16 @@ MatchPattern=part2-@v MatchPartitionType=root-x86-64-verity EOF - cat >/var/tmp/72-defs/03-third.conf <<EOF + cat >"$WORKDIR/defs/03-third.conf" <<EOF [Source] Type=url-tar -Path=file:///var/tmp/72-source +Path=file://$WORKDIR/source MatchPattern=dir-@v.tar.gz [Target] Type=directory -Path=/var/tmp/72-dirs -CurrentSymlink=/var/tmp/72-dirs/current +Path=$WORKDIR/dirs +CurrentSymlink=$WORKDIR/dirs/current MatchPattern=dir-@v InstancesMax=3 EOF @@ -269,10 +266,8 @@ EOF verify_version "$blockdev" "$sector_size" v4 2 4 # Cleanup - [ -b "$blockdev" ] && losetup --detach "$blockdev" + [[ -b "$blockdev" ]] && losetup --detach "$blockdev" rm "$BACKING_FILE" done -rm -r /var/tmp/72-{dirs,defs,source,xbootldr,esp} - touch /testok diff --git a/test/units/testsuite-73.sh b/test/units/TEST-73-LOCALE.sh index df5af4b..18539b8 100755 --- a/test/units/testsuite-73.sh +++ b/test/units/TEST-73-LOCALE.sh @@ -28,31 +28,6 @@ EOF systemctl daemon-reload } -restore_locale() { - if [[ -d /usr/lib/locale/xx_XX.UTF-8 ]]; then - rmdir /usr/lib/locale/xx_XX.UTF-8 - fi - - if [[ -f /tmp/locale.conf.bak ]]; then - mv /tmp/locale.conf.bak /etc/locale.conf - else - rm -f /etc/locale.conf - fi - - if [[ -f /tmp/default-locale.bak ]]; then - mv /tmp/default-locale.bak /etc/default/locale - else - rm -f /etc/default/locale - rmdir --ignore-fail-on-non-empty /etc/default - fi - - if [[ -f /tmp/locale.gen.bak ]]; then - mv /tmp/locale.gen.bak /etc/locale.gen - else - rm -f /etc/locale.gen - fi -} - testcase_locale() { local i output @@ -77,13 +52,8 @@ testcase_locale() { mkdir -p /etc/default trap restore_locale RETURN - - if command -v locale-gen >/dev/null 2>&1 && - ! localectl list-locales | grep -F "en_US.UTF-8"; then - # ensure at least one utf8 locale exist - echo "en_US.UTF-8 UTF-8" >/etc/locale.gen - locale-gen en_US.UTF-8 - fi + # Ensure at least one UTF-8 locale exists. + generate_locale en_US.UTF-8 # create invalid locale mkdir -p /usr/lib/locale/xx_XX.UTF-8 diff --git a/test/units/testsuite-74.battery-check.sh b/test/units/TEST-74-AUX-UTILS.battery-check.sh index 52a92b8..52a92b8 100755 --- a/test/units/testsuite-74.battery-check.sh +++ b/test/units/TEST-74-AUX-UTILS.battery-check.sh diff --git a/test/units/testsuite-74.bootctl.sh b/test/units/TEST-74-AUX-UTILS.bootctl.sh index 4be7bfd..78c0e6e 100755 --- a/test/units/testsuite-74.bootctl.sh +++ b/test/units/TEST-74-AUX-UTILS.bootctl.sh @@ -59,8 +59,8 @@ basic_tests() { } testcase_bootctl_basic() { - assert_eq "$(bootctl --print-esp-path)" "/efi" - assert_eq "$(bootctl --print-boot-path)" "/boot" + assert_in "$(bootctl --print-esp-path)" "^(/boot/|/efi)$" + assert_in "$(bootctl --print-boot-path)" "^(/boot/|/efi)$" bootctl --print-root-device basic_tests @@ -263,4 +263,17 @@ EOF SYSTEMD_RELAX_ESP_CHECKS=yes SYSTEMD_RELAX_XBOOTLDR_CHECKS=yes basic_tests --root "${IMAGE_DIR}/root" } +testcase_bootctl_varlink() { + varlinkctl call --collect /run/systemd/io.systemd.BootControl io.systemd.BootControl.ListBootEntries '{}' + + # We may have UEFI in the test environment. + # If we don't have UEFI then we can test whether bootctl's varlink API fails cleanly. + # If we do have UEFI then the rest of the clean fail tests should be skipped. + if ! (SYSTEMD_LOG_TARGET=console varlinkctl call --json=short /run/systemd/io.systemd.BootControl io.systemd.BootControl.GetRebootToFirmware '{}' || true) |& grep -q io.systemd.BootControl.RebootToFirmwareNotSupported; then + return 0 + fi + (SYSTEMD_LOG_TARGET=console varlinkctl call --json=short /run/systemd/io.systemd.BootControl io.systemd.BootControl.SetRebootToFirmware '{"state":true}' || true) |& grep -q io.systemd.BootControl.RebootToFirmwareNotSupported + (SYSTEMD_LOG_TARGET=console varlinkctl call --json=short /run/systemd/io.systemd.BootControl io.systemd.BootControl.SetRebootToFirmware '{"state":false}' || true) |& grep -q io.systemd.BootControl.RebootToFirmwareNotSupported +} + run_testcases diff --git a/test/units/testsuite-74.busctl.sh b/test/units/TEST-74-AUX-UTILS.busctl.sh index aaf96d0..aaf96d0 100755 --- a/test/units/testsuite-74.busctl.sh +++ b/test/units/TEST-74-AUX-UTILS.busctl.sh diff --git a/test/units/TEST-74-AUX-UTILS.capsule.sh b/test/units/TEST-74-AUX-UTILS.capsule.sh new file mode 100755 index 0000000..e7b5c87 --- /dev/null +++ b/test/units/TEST-74-AUX-UTILS.capsule.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2235 +set -eux +set -o pipefail + +at_exit() { + set +e + systemctl --no-block stop capsule@foobar.service + rm -rf /run/capsules/foobar + rm -rf /var/lib/capsules/foobar + rm -f /run/systemd/system/capsule@.service.d/99-asan.conf +} + +trap at_exit EXIT + +# Appease ASan, since the capsule@.service uses DynamicUser=yes +systemctl edit --runtime --stdin capsule@.service --drop-in=99-asan.conf <<EOF +[Service] +EnvironmentFile=-/usr/lib/systemd/systemd-asan-env +EOF + +(! test -f /run/capsules/foobar ) +(! test -f /var/lib/capsules/foobar ) +(! id -u c-foobar ) + +systemctl start capsule@foobar.service + +test -d /run/capsules/foobar +test -d /var/lib/capsules/foobar +id -u c-foobar + +systemctl status capsule@foobar.service + +busctl -C foobar + +systemctl -C foobar + +systemd-run -C foobar -u sleepinfinity /bin/sleep infinity + +systemctl -C foobar status sleepinfinity + +systemctl -C foobar stop sleepinfinity + +(! systemctl clean capsule@foobar.service ) + +systemctl stop capsule@foobar.service + +systemctl clean capsule@foobar.service --what=all + +(! test -f /run/capsules/foobar ) +(! test -f /var/lib/capsules/foobar ) +(! id -u c-foobar ) diff --git a/test/units/testsuite-74.cgls.sh b/test/units/TEST-74-AUX-UTILS.cgls.sh index 9268f42..9268f42 100755 --- a/test/units/testsuite-74.cgls.sh +++ b/test/units/TEST-74-AUX-UTILS.cgls.sh diff --git a/test/units/testsuite-74.cgtop.sh b/test/units/TEST-74-AUX-UTILS.cgtop.sh index cf98279..cf98279 100755 --- a/test/units/testsuite-74.cgtop.sh +++ b/test/units/TEST-74-AUX-UTILS.cgtop.sh diff --git a/test/units/testsuite-74.coredump.sh b/test/units/TEST-74-AUX-UTILS.coredump.sh index 6552643..b9c8fde 100755 --- a/test/units/testsuite-74.coredump.sh +++ b/test/units/TEST-74-AUX-UTILS.coredump.sh @@ -77,24 +77,26 @@ rm -fv /run/systemd/coredump.conf.d/99-external.conf # Wait a bit for the coredumps to get processed timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $CORE_TEST_BIN | wc -l) -lt 4 ]]; do sleep 1; done" -# Make sure we can forward crashes back to containers -CONTAINER="testsuite-74-container" - -mkdir -p "/var/lib/machines/$CONTAINER" -mkdir -p "/run/systemd/system/systemd-nspawn@$CONTAINER.service.d" -# Bind-mounting /etc into the container kinda defeats the purpose of --volatile=, -# but we need the ASan-related overrides scattered across /etc -cat > "/run/systemd/system/systemd-nspawn@$CONTAINER.service.d/override.conf" << EOF +if cgroupfs_supports_user_xattrs; then + # Make sure we can forward crashes back to containers + CONTAINER="TEST-74-AUX-UTILS-container" + + mkdir -p "/var/lib/machines/$CONTAINER" + mkdir -p "/run/systemd/system/systemd-nspawn@$CONTAINER.service.d" + # Bind-mounting /etc into the container kinda defeats the purpose of --volatile=, + # but we need the ASan-related overrides scattered across /etc + cat > "/run/systemd/system/systemd-nspawn@$CONTAINER.service.d/override.conf" <<EOF [Service] ExecStart= ExecStart=systemd-nspawn --quiet --link-journal=try-guest --keep-unit --machine=%i --boot \ --volatile=yes --directory=/ --bind-ro=/etc --inaccessible=/etc/machine-id EOF -systemctl daemon-reload + systemctl daemon-reload + + [[ "$(systemd-detect-virt)" == "qemu" ]] && TIMEOUT=120 || TIMEOUT=60 -if cgroupfs_supports_user_xattrs; then machinectl start "$CONTAINER" - timeout 60 bash -xec "until systemd-run -M '$CONTAINER' -q --wait --pipe true; do sleep .5; done" + timeout "$TIMEOUT" bash -xec "until systemd-run -M '$CONTAINER' -q --wait --pipe true; do sleep .5; done" [[ "$(systemd-run -M "$CONTAINER" -q --wait --pipe coredumpctl list -q --no-legend /usr/bin/sleep | wc -l)" -eq 0 ]] machinectl copy-to "$CONTAINER" "$MAKE_DUMP_SCRIPT" @@ -102,6 +104,10 @@ if cgroupfs_supports_user_xattrs; then systemd-run -M "$CONTAINER" -q --wait --pipe "$MAKE_DUMP_SCRIPT" "/usr/bin/sleep" "SIGTRAP" # Wait a bit for the coredumps to get processed timeout 30 bash -c "while [[ \$(systemd-run -M $CONTAINER -q --wait --pipe coredumpctl list -q --no-legend /usr/bin/sleep | wc -l) -lt 2 ]]; do sleep 1; done" + + machinectl stop "$CONTAINER" + rm -rf "/var/lib/machines/$CONTAINER" + unset CONTAINER fi coredumpctl diff --git a/test/units/testsuite-74.delta.sh b/test/units/TEST-74-AUX-UTILS.delta.sh index a0e1cb5..dabe234 100755 --- a/test/units/testsuite-74.delta.sh +++ b/test/units/TEST-74-AUX-UTILS.delta.sh @@ -14,14 +14,14 @@ trap at_exit EXIT # Extended unit cat >"/run/systemd/system/delta-test-unit-extended.service" <<EOF [Service] -ExecStart=/bin/true +ExecStart=true EOF mkdir -p "/run/systemd/system/delta-test-unit-extended.service.d" cat >"/run/systemd/system/delta-test-unit-extended.service.d/override.conf" <<EOF [Unit] Description=Foo Bar [Service] -ExecStartPre=/bin/true +ExecStartPre=true EOF # Masked unit cp -fv /run/systemd/system/delta-test-unit-extended.service /run/systemd/system/delta-test-unit-masked.service diff --git a/test/units/testsuite-74.escape.sh b/test/units/TEST-74-AUX-UTILS.escape.sh index e398d40..e398d40 100755 --- a/test/units/testsuite-74.escape.sh +++ b/test/units/TEST-74-AUX-UTILS.escape.sh diff --git a/test/units/testsuite-74.firstboot.sh b/test/units/TEST-74-AUX-UTILS.firstboot.sh index be08575..7bab009 100755 --- a/test/units/testsuite-74.firstboot.sh +++ b/test/units/TEST-74-AUX-UTILS.firstboot.sh @@ -3,6 +3,9 @@ set -eux set -o pipefail +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + if ! command -v systemd-firstboot >/dev/null; then echo "systemd-firstboot not found, skipping the test" exit 0 @@ -13,6 +16,8 @@ at_exit() { ls -lR "$ROOT" rm -fr "$ROOT" fi + + restore_locale } trap at_exit EXIT @@ -24,6 +29,23 @@ ROOT_HASHED_PASSWORD1='$6$foobarsalt$YbwdaATX6IsFxvWbY3QcZj2gB31R/LFRFrjlFrJtTTq # shellcheck disable=SC2016 ROOT_HASHED_PASSWORD2='$6$foobarsalt$q.P2932zYMLbKnjFwIxPI8y3iuxeuJ2BgE372LcZMMnj3Gcg/9mJg2LPKUl.ha0TG/.fRNNnRQcLfzM0SNot3.' +if [[ -f /etc/locale.conf ]]; then + cp /etc/locale.conf /tmp/locale.conf.bak +fi + +# Debian/Ubuntu specific file +if [[ -f /etc/default/locale ]]; then + cp /etc/default/locale /tmp/default-locale.bak +fi + +if [[ -f /etc/locale.gen ]]; then + cp /etc/locale.gen /tmp/locale.gen.bak +fi + +# Make sure at least two locales exist (C.UTF-8 and en_US.UTF-8) as systemd-firstboot --prompt-locale will +# skip writing the locale if it detects only one is installed. +generate_locale en_US.UTF-8 + # Debian and Ubuntu use /etc/default/locale instead of /etc/locale.conf. Make # sure we use the appropriate path for locale configuration. LOCALE_PATH="/etc/locale.conf" diff --git a/test/units/testsuite-74.id128.sh b/test/units/TEST-74-AUX-UTILS.id128.sh index c1b80d6..f91cd5f 100755 --- a/test/units/testsuite-74.id128.sh +++ b/test/units/TEST-74-AUX-UTILS.id128.sh @@ -22,6 +22,13 @@ systemd-id128 show root-x86-64 --app-specific=4f68bce3e8cd4db196e7fbcaf984b709 systemd-id128 show --pretty root-x86-64 --app-specific=4f68bce3e8cd4db196e7fbcaf984b709 [[ "$(systemd-id128 show root-x86-64 --app-specific=4f68bce3e8cd4db196e7fbcaf984b709 -P)" = "8ee5535e7cb14c249e1d28b8dfbb939c" ]] +systemd-id128 show -j +systemd-id128 show --no-pager +systemd-id128 show --json=short +systemd-id128 show --no-legend +systemd-id128 show --no-pager --no-legend +systemd-id128 show root -P -u + [[ "$(systemd-id128 new | wc -c)" -eq 33 ]] systemd-id128 new -p systemd-id128 new -u diff --git a/test/units/testsuite-74.machine-id-setup.sh b/test/units/TEST-74-AUX-UTILS.machine-id-setup.sh index c2b9db5..c2b9db5 100755 --- a/test/units/testsuite-74.machine-id-setup.sh +++ b/test/units/TEST-74-AUX-UTILS.machine-id-setup.sh diff --git a/test/units/testsuite-74.modules-load.sh b/test/units/TEST-74-AUX-UTILS.modules-load.sh index 3d00e07..ceac826 100755 --- a/test/units/testsuite-74.modules-load.sh +++ b/test/units/TEST-74-AUX-UTILS.modules-load.sh @@ -17,8 +17,10 @@ if systemd-detect-virt -cq; then exit 0 fi +ORIG_MODULES_LOAD_CONFIG="$(systemd-analyze cat-config modules-load.d)" + # Check if we have required kernel modules -modprobe --all --resolve-alias loop dummy +modprobe --all --resolve-alias dummy mkdir -p /run/modules-load.d/ @@ -27,62 +29,58 @@ mkdir -p /run/modules-load.d/ "$MODULES_LOAD_BIN" --version # Explicit config file -modprobe -v --all --remove loop dummy -printf "loop\ndummy" >"$CONFIG_FILE" +modprobe -v --all --remove dummy +printf "dummy" >"$CONFIG_FILE" "$MODULES_LOAD_BIN" "$CONFIG_FILE" |& tee /tmp/out.log -grep -E "Inserted module .*loop" /tmp/out.log grep -E "Inserted module .*dummy" /tmp/out.log # Implicit config file -modprobe -v --all --remove loop dummy -printf "loop\ndummy" >"$CONFIG_FILE" +modprobe -v --all --remove dummy +printf "dummy" >"$CONFIG_FILE" "$MODULES_LOAD_BIN" |& tee /tmp/out.log -grep -E "Inserted module .*loop" /tmp/out.log grep -E "Inserted module .*dummy" /tmp/out.log # Valid & invalid data mixed together -modprobe -v --all --remove loop dummy +modprobe -v --all --remove dummy cat >"$CONFIG_FILE" <<EOF -loop -loop -loop - loop +dummy +dummy +dummy + dummy dummy \\n\n\n\\\\\\ - -loo!@@123##2455 + +dumm!@@123##2455 # This is a comment $(printf "%.0sx" {0..4096}) dummy -loop +dummy foo-bar-baz 1 " ' EOF "$MODULES_LOAD_BIN" |& tee /tmp/out.log -grep -E "^Inserted module .*loop" /tmp/out.log grep -E "^Inserted module .*dummy" /tmp/out.log grep -E "^Failed to find module .*foo-bar-baz" /tmp/out.log (! grep -E "This is a comment" /tmp/out.log) # Each module should be loaded only once, even if specified multiple times -[[ "$(grep -Ec "^Inserted module" /tmp/out.log)" -eq 2 ]] +[[ "$(grep -Ec "^Inserted module" /tmp/out.log)" -eq 1 ]] [[ "$(grep -Ec "^Failed to find module" /tmp/out.log)" -eq 7 ]] # Command line arguments -modprobe -v --all --remove loop dummy +modprobe -v --all --remove dummy # Make sure we have no config files left over that might interfere with # following tests rm -fv "$CONFIG_FILE" -[[ -z "$(systemd-analyze cat-config modules-load.d)" ]] -CMDLINE="ro root= modules_load= modules_load=, / = modules_load=foo-bar-baz,dummy modules_load=loop,loop,loop" +[[ "$ORIG_MODULES_LOAD_CONFIG" == "$(systemd-analyze cat-config modules-load.d)" ]] +CMDLINE="ro root= modules_load= modules_load=, / = modules_load=foo-bar-baz,dummy modules_load=dummy,dummy,dummy" SYSTEMD_PROC_CMDLINE="$CMDLINE" "$MODULES_LOAD_BIN" |& tee /tmp/out.log -grep -E "^Inserted module .*loop" /tmp/out.log grep -E "^Inserted module .*dummy" /tmp/out.log grep -E "^Failed to find module .*foo-bar-baz" /tmp/out.log # Each module should be loaded only once, even if specified multiple times -[[ "$(grep -Ec "^Inserted module" /tmp/out.log)" -eq 2 ]] +[[ "$(grep -Ec "^Inserted module" /tmp/out.log)" -eq 1 ]] (! "$MODULES_LOAD_BIN" --nope) (! "$MODULES_LOAD_BIN" /foo/bar/baz) diff --git a/test/units/testsuite-74.mount.sh b/test/units/TEST-74-AUX-UTILS.mount.sh index 41c5c86..14253c3 100755 --- a/test/units/testsuite-74.mount.sh +++ b/test/units/TEST-74-AUX-UTILS.mount.sh @@ -6,13 +6,6 @@ set -o pipefail # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh -# We're going to play around with block/loop devices, so bail out early -# if we're running in nspawn -if systemd-detect-virt --container >/dev/null; then - echo "Container detected, skipping the test" - exit 0 -fi - at_exit() { set +e @@ -23,6 +16,7 @@ at_exit() { trap at_exit EXIT WORK_DIR="$(mktemp -d)" +mkdir -p "$WORK_DIR/mnt" systemd-mount --list systemd-mount --list --full @@ -30,15 +24,43 @@ systemd-mount --list --no-legend systemd-mount --list --no-pager systemd-mount --list --quiet +# tmpfs +mkdir -p "$WORK_DIR/mnt/foo/bar" +systemd-mount --tmpfs "$WORK_DIR/mnt/foo" +test ! -d "$WORK_DIR/mnt/foo/bar" +touch "$WORK_DIR/mnt/foo/baz" +systemd-umount "$WORK_DIR/mnt/foo" +test -d "$WORK_DIR/mnt/foo/bar" +test ! -e "$WORK_DIR/mnt/foo/baz" + +# overlay +systemd-mount --type=overlay --options="lowerdir=/etc,upperdir=$WORK_DIR/upper,workdir=$WORK_DIR/work" /etc "$WORK_DIR/overlay" +touch "$WORK_DIR/overlay/foo" +test -e "$WORK_DIR/upper/foo" +systemd-umount "$WORK_DIR/overlay" + +# We're going to play around with block/loop devices, so bail out early +# if we're running in nspawn +if systemd-detect-virt --container >/dev/null; then + echo "Container detected, skipping the test" + exit 0 +fi + # Set up a simple block device for further tests dd if=/dev/zero of="$WORK_DIR/simple.img" bs=1M count=16 +mkfs.ext4 -L sd-mount-test "$WORK_DIR/simple.img" LOOP="$(losetup --show --find "$WORK_DIR/simple.img")" -mkfs.ext4 -L sd-mount-test "$LOOP" -mkdir "$WORK_DIR/mnt" +udevadm wait --timeout 60 --settle "$LOOP" +# Also wait for the .device unit for the loop device is active. Otherwise, the .device unit activation +# that is triggered by the .mount unit introduced by systemd-mount below may time out. +timeout 60 bash -c "until systemctl is-active $LOOP; do sleep 1; done" mount "$LOOP" "$WORK_DIR/mnt" touch "$WORK_DIR/mnt/foo.bar" umount "$LOOP" (! mountpoint "$WORK_DIR/mnt") +# Wait for the mount unit to be unloaded. Otherwise, creation of the transient unit below may fail. +MOUNT_UNIT=$(systemd-escape --path --suffix=mount "$WORK_DIR/mnt") +timeout 60 bash -c "while [[ -n \$(systemctl list-units --all --no-legend $MOUNT_UNIT) ]]; do sleep 1; done" # Mount with both source and destination set systemd-mount "$LOOP" "$WORK_DIR/mnt" @@ -123,15 +145,37 @@ test -e /run/media/system/simple.img/foo.bar # systemd-mount --list and systemd-umount require the loopback block device is initialized by udevd. udevadm settle --timeout 30 assert_in "/dev/loop.* ext4 +sd-mount-test" "$(systemd-mount --list --full)" +LOOP_AUTO=$(systemd-mount --list --full --no-legend | awk '$6 == "sd-mount-test" { print $1 }') +LOOP_AUTO_DEVPATH=$(udevadm info --query property --property DEVPATH --value "$LOOP_AUTO") systemd-umount "$WORK_DIR/simple.img" +# Wait for 'change' uevent for the device with DISK_MEDIA_CHANGE=1. +# After the event, the backing_file attribute should be removed. +timeout 60 bash -c "while [[ -e /sys/$LOOP_AUTO_DEVPATH/loop/backing_file ]]; do sleep 1; done" # --owner + vfat # # Create a vfat image, as ext4 doesn't support uid=/gid= fixating for all # files/directories dd if=/dev/zero of="$WORK_DIR/owner-vfat.img" bs=1M count=16 +mkfs.vfat -n owner-vfat "$WORK_DIR/owner-vfat.img" LOOP="$(losetup --show --find "$WORK_DIR/owner-vfat.img")" -mkfs.vfat -n owner-vfat "$LOOP" +# If the synthesized uevent triggered by inotify event has been processed earlier than the kernel finishes to +# attach the backing file, then SYSTEMD_READY=0 is set for the device. As a workaround, monitor sysattr +# and re-trigger uevent after that. +LOOP_DEVPATH=$(udevadm info --query property --property DEVPATH --value "$LOOP") +timeout 60 bash -c "until [[ -e /sys/$LOOP_DEVPATH/loop/backing_file ]]; do sleep 1; done" +udevadm trigger --settle "$LOOP" +# Also wait for the .device unit for the loop device is active. Otherwise, the .device unit activation +# that is triggered by the .mount unit introduced by systemd-mount below may time out. +if ! timeout 60 bash -c "until systemctl is-active $LOOP; do sleep 1; done"; then + # For debugging issue like + # https://github.com/systemd/systemd/issues/32680#issuecomment-2120959238 + # https://github.com/systemd/systemd/issues/32680#issuecomment-2122074805 + udevadm info "$LOOP" + udevadm info --attribute-walk "$LOOP" + cat /sys/"$(udevadm info --query property --property DEVPATH --value "$LOOP")"/loop/backing_file || : + false +fi # Mount it and check the UID/GID [[ "$(stat -c "%U:%G" "$WORK_DIR/mnt")" == "root:root" ]] systemd-mount --owner=testuser "$LOOP" "$WORK_DIR/mnt" @@ -140,12 +184,3 @@ systemctl status "$WORK_DIR/mnt" touch "$WORK_DIR/mnt/hello" [[ "$(stat -c "%U:%G" "$WORK_DIR/mnt/hello")" == "testuser:testuser" ]] systemd-umount LABEL=owner-vfat - -# tmpfs -mkdir -p "$WORK_DIR/mnt/foo/bar" -systemd-mount --tmpfs "$WORK_DIR/mnt/foo" -test ! -d "$WORK_DIR/mnt/foo/bar" -touch "$WORK_DIR/mnt/foo/baz" -systemd-umount "$WORK_DIR/mnt/foo" -test -d "$WORK_DIR/mnt/foo/bar" -test ! -e "$WORK_DIR/mnt/foo/baz" diff --git a/test/units/TEST-74-AUX-UTILS.network-generator.sh b/test/units/TEST-74-AUX-UTILS.network-generator.sh new file mode 100755 index 0000000..5b5b0a1 --- /dev/null +++ b/test/units/TEST-74-AUX-UTILS.network-generator.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2016 +set -eux +set -o pipefail + +at_exit() { + rm -f /run/credstore/network.conf.50-testme + rm -f /run/credstore/network.network.50-testme + rm -f /run/systemd/networkd.conf.d/50-testme.conf + rm -f /run/systemd/network/50-testme.network + rm -f /run/systemd/system/systemd-network-generator.service.d/50-testme.conf +} + +trap at_exit EXIT + +mkdir -p /run/credstore +cat > /run/credstore/network.conf.50-testme <<EOF +[Network] +SpeedMeter=yes +EOF + +cat > /run/credstore/network.network.50-testme <<EOF +[Match] +Property=IDONTEXIST +EOF + +systemctl edit systemd-network-generator.service --stdin --drop-in=50-testme.conf <<EOF +[Service] +LoadCredential=network.conf.50-testme +LoadCredential=network.network.50-testme +EOF + +systemctl restart systemd-network-generator + +diff /run/credstore/network.conf.50-testme /run/systemd/networkd.conf.d/50-testme.conf +diff /run/credstore/network.network.50-testme /run/systemd/network/50-testme.network diff --git a/test/units/testsuite-74.networkctl.sh b/test/units/TEST-74-AUX-UTILS.networkctl.sh index 0a687af..3e333a2 100755 --- a/test/units/testsuite-74.networkctl.sh +++ b/test/units/TEST-74-AUX-UTILS.networkctl.sh @@ -11,10 +11,12 @@ at_exit() { systemctl stop systemd-networkd if [[ -v NETWORK_NAME && -v NETDEV_NAME && -v LINK_NAME ]]; then - rm -fvr {/usr/lib,/etc}/systemd/network/"$NETWORK_NAME" "/usr/lib/systemd/network/$NETDEV_NAME" \ + rm -fvr {/usr/lib,/etc,/run}/systemd/network/"$NETWORK_NAME" "/usr/lib/systemd/network/$NETDEV_NAME" \ {/usr/lib,/etc}/systemd/network/"$LINK_NAME" "/etc/systemd/network/${NETWORK_NAME}.d" \ "new" "+4" fi + + rm -f /run/systemd/networkd.conf.d/10-hoge.conf } trap at_exit EXIT @@ -28,6 +30,16 @@ Name=test EOF # Test files + +networkctl mask --runtime "donotexist.network" +assert_eq "$(readlink /run/systemd/network/donotexist.network)" "/dev/null" +networkctl unmask "donotexist.network" # unmask should work even without --runtime +[[ ! -e /run/systemd/network/donotexist.network ]] + +touch /usr/lib/systemd/network/donotexist.network +(! networkctl unmask "donotexist.network") +rm /usr/lib/systemd/network/donotexist.network + networkctl cat "$NETWORK_NAME" | tail -n +2 | cmp - "/usr/lib/systemd/network/$NETWORK_NAME" cat >new <<EOF @@ -35,9 +47,23 @@ cat >new <<EOF Name=test2 EOF -EDITOR='mv new' script -ec 'networkctl edit "$NETWORK_NAME"' /dev/null +EDITOR='mv new' script -ec 'networkctl edit --runtime "$NETWORK_NAME"' /dev/null +(! networkctl mask --runtime "$NETWORK_NAME") +printf '%s\n' '[Match]' 'Name=test2' | cmp - "/run/systemd/network/$NETWORK_NAME" + +networkctl mask "$NETWORK_NAME" +assert_eq "$(readlink "/etc/systemd/network/$NETWORK_NAME")" "/dev/null" +(! networkctl edit "$NETWORK_NAME") +(! networkctl edit --runtime "$NETWORK_NAME") +(! networkctl cat "$NETWORK_NAME") +networkctl unmask "$NETWORK_NAME" + +EDITOR='true' script -ec 'networkctl edit "$NETWORK_NAME"' /dev/null printf '%s\n' '[Match]' 'Name=test2' | cmp - "/etc/systemd/network/$NETWORK_NAME" +(! networkctl mask "$NETWORK_NAME") +(! EDITOR='true' script -ec 'networkctl edit --runtime "$NETWORK_NAME"' /dev/null) + cat >"+4" <<EOF [Network] IPv6AcceptRA=no @@ -80,7 +106,19 @@ networkctl cat @test2:network | cmp - <(networkctl cat "$NETWORK_NAME") EDITOR='cp' script -ec 'networkctl edit @test2 --drop-in test2.conf' /dev/null cmp "+4" "/etc/systemd/network/${NETWORK_NAME}.d/test2.conf" +SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/systemd-networkd-wait-online -i test2:carrier --timeout 20 +(! EDITOR='true' script -ec 'networkctl edit @test2 --runtime --drop-in test2.conf' /dev/null) + ip_link="$(ip link show test2)" if systemctl --quiet is-active systemd-udevd; then assert_in 'alias test_alias' "$ip_link" fi + +mkdir -p /run/systemd/networkd.conf.d +cat >/run/systemd/networkd.conf.d/10-hoge.conf <<EOF +# TEST DROP-IN FILE +[Network] +SpeedMeter=yes +EOF + +assert_in '# TEST DROP-IN FILE' "$(networkctl cat)" diff --git a/test/units/testsuite-74.path.sh b/test/units/TEST-74-AUX-UTILS.path.sh index 79056a5..79056a5 100755 --- a/test/units/testsuite-74.path.sh +++ b/test/units/TEST-74-AUX-UTILS.path.sh diff --git a/test/units/testsuite-74.pstore.sh b/test/units/TEST-74-AUX-UTILS.pstore.sh index 9be8066..9be8066 100755 --- a/test/units/testsuite-74.pstore.sh +++ b/test/units/TEST-74-AUX-UTILS.pstore.sh diff --git a/test/units/testsuite-74.run.sh b/test/units/TEST-74-AUX-UTILS.run.sh index e894932..b4ff72e 100755 --- a/test/units/testsuite-74.run.sh +++ b/test/units/TEST-74-AUX-UTILS.run.sh @@ -218,19 +218,30 @@ for opt in nice on-{active,boot,calendar,startup,unit-active,unit-inactive} prop done # Let's make sure that ProtectProc= properly moves submounts of the original /proc over to the new proc - -A=$(cat /proc/sys/kernel/random/boot_id) -B=$(systemd-run -q --wait --pipe -p ProtectProc=invisible cat /proc/sys/kernel/random/boot_id) -assert_eq "$A" "$B" - -V="/tmp/version.$RANDOM" -A="$(cat /proc/version).piff" -echo "$A" > "$V" -mount --bind "$V" /proc/version - -B=$(systemd-run -q --wait --pipe -p ProtectProc=invisible cat /proc/version) - -assert_eq "$A" "$B" - +BOOT_ID="$(</proc/sys/kernel/random/boot_id)" +UNIT_BOOT_ID="$(systemd-run -q --wait --pipe -p ProtectProc=invisible cat /proc/sys/kernel/random/boot_id)" +assert_eq "$BOOT_ID" "$UNIT_BOOT_ID" + +TMP_KVER="/tmp/version.$RANDOM" +KVER="$(</proc/version).piff" +echo "$KVER" >"$TMP_KVER" +mount --bind "$TMP_KVER" /proc/version +UNIT_KVER="$(systemd-run -q --wait --pipe -p ProtectProc=invisible cat /proc/version)" +assert_eq "$KVER" "$UNIT_KVER" umount /proc/version -rm "$V" +rm -f "$TMP_KVER" + +if [[ -e /usr/lib/pam.d/systemd-run0 ]] || [[ -e /etc/pam.d/systemd-run0 ]]; then + # Check that invoking the tool under the run0 alias name works + run0 ls / + assert_eq "$(run0 echo foo)" "foo" + # Check if we set some expected environment variables + for arg in "" "--user=root" "--user=testuser"; do + assert_eq "$(run0 ${arg:+"$arg"} bash -c 'echo $SUDO_USER')" "$USER" + assert_eq "$(run0 ${arg:+"$arg"} bash -c 'echo $SUDO_UID')" "$(id -u "$USER")" + assert_eq "$(run0 ${arg:+"$arg"} bash -c 'echo $SUDO_GID')" "$(id -u "$USER")" + done + # Let's chain a couple of run0 calls together, for fun + readarray -t cmdline < <(printf "%.0srun0\n" {0..31}) + assert_eq "$("${cmdline[@]}" bash -c 'echo $SUDO_USER')" "$USER" +fi diff --git a/test/units/testsuite-74.sh b/test/units/TEST-74-AUX-UTILS.sh index 9c2a033..9c2a033 100755 --- a/test/units/testsuite-74.sh +++ b/test/units/TEST-74-AUX-UTILS.sh diff --git a/test/units/TEST-74-AUX-UTILS.socket.sh b/test/units/TEST-74-AUX-UTILS.socket.sh new file mode 100755 index 0000000..7ef85fa --- /dev/null +++ b/test/units/TEST-74-AUX-UTILS.socket.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2016 +set -eux +set -o pipefail + +# shellcheck source=test/units/util.sh +. "$(dirname "$0")"/util.sh + +at_exit() { + systemctl stop per-source-limit.socket + rm -f /run/systemd/system/per-source-limit{@.service,.socket} /run/foo.conn{1..4} + systemctl daemon-reload +} + +trap at_exit EXIT + +cat >/run/systemd/system/per-source-limit.socket <<EOF +[Socket] +ListenStream=/run/per-source-limit.sk +MaxConnectionsPerSource=2 +Accept=yes +EOF + +cat >/run/systemd/system/per-source-limit@.service <<EOF +[Unit] +BindsTo=per-source-limit.socket +After=per-source-limit.socket + +[Service] +ExecStartPre=echo waldo +ExecStart=sleep infinity +StandardOutput=socket +EOF + +systemctl daemon-reload +systemctl start per-source-limit.socket +systemctl status per-source-limit.socket + +# So these two should take up the first two connection slots +socat -U - UNIX-CONNECT:/run/per-source-limit.sk | tee /tmp/foo.conn1 & +J1="$!" +socat -U - UNIX-CONNECT:/run/per-source-limit.sk | tee /tmp/foo.conn2 & +J2="$!" + +waitfor() { + local file="${1:?}" + + for _ in {0..20}; do + if grep -q waldo "$file"; then + return 0 + fi + + sleep .5 + done + + echo >&2 "Timeout while waiting for the expected output" + return 1 +} + +# Wait until the word "waldo" shows in the output files +waitfor /tmp/foo.conn1 +waitfor /tmp/foo.conn2 + +# The next connection should fail, because the limit is hit +socat -U - UNIX-CONNECT:/run/per-source-limit.sk | tee /tmp/foo.conn3 & +J3="$!" + +# But this one should work, because done under a different UID +setpriv --reuid=1 socat -U - UNIX-CONNECT:/run/per-source-limit.sk | tee /tmp/foo.conn4 & +J4="$!" + +waitfor /tmp/foo.conn4 + +# The third job should fail quickly, wait for it +wait "$J3" + +# The other jobs will hang forever, since we run "sleep infinity" on the server side. Let's kill the jobs now. +kill "$J1" +kill "$J2" +kill "$J4" + +# The 3rd connection should not have seen "waldo", since it should have been refused too early +(! grep -q "waldo" /tmp/foo.conn3 ) diff --git a/test/units/TEST-74-AUX-UTILS.ssh.sh b/test/units/TEST-74-AUX-UTILS.ssh.sh new file mode 100755 index 0000000..5d87d9f --- /dev/null +++ b/test/units/TEST-74-AUX-UTILS.ssh.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +if ! command -v ssh &> /dev/null || ! command -v sshd &> /dev/null ; then + echo "ssh/sshd not found, skipping test." >&2 + exit 0 +fi + +systemctl -q is-active sshd-unix-local.socket + +if test -e /dev/vsock ; then + systemctl -q is-active sshd-vsock.socket +fi + +if test -d /run/host/unix-export ; then + systemctl -q is-active sshd-unix-export.socket +fi + +# FIXME: sshd seems to crash inside asan currently, skip the actual ssh test hence +if [[ -v ASAN_OPTIONS ]] ; then + exit 0 +fi + +ROOTID=$(mktemp -u) + +removesshid() { + rm -f "$ROOTID" "$ROOTID".pub +} + +ssh-keygen -N '' -C '' -t rsa -f "$ROOTID" + +mkdir -p 0700 /root/.ssh +# Add a newline in case authorized_keys wasn't terminated correctly. +echo >>/root/.ssh/authorized_keys +cat "$ROOTID".pub >>/root/.ssh/authorized_keys + +# set root pw to "foo", just to set it to something valid +# shellcheck disable=SC2016 +usermod -p '$5$AAy6BYJ6rzz.QELv$6LpVEU3/RQmVz.svHu/33qoJWWWzZuJ3DM2fo9JgcUD' root +usermod -U root + +mkdir -p /etc/ssh +test -f /etc/ssh/ssh_host_rsa_key || ssh-keygen -t rsa -C '' -N '' -f /etc/ssh/ssh_host_rsa_key +echo "PermitRootLogin yes" >> /etc/ssh/sshd_config +echo "LogLevel DEBUG3" >> /etc/ssh/sshd_config + +test -f /etc/ssh/ssh_config || echo 'Include /etc/ssh/ssh_config.d/*.conf' > /etc/ssh/ssh_config + +# ssh wants this dir around, but distros cannot agree on a common name for it, let's just create all that are aware of distros use +mkdir -p /usr/share/empty.sshd /var/empty /var/empty/sshd /run/sshd + +ssh -o StrictHostKeyChecking=no -v -i "$ROOTID" .host cat /etc/machine-id | cmp - /etc/machine-id +ssh -o StrictHostKeyChecking=no -v -i "$ROOTID" unix/run/ssh-unix-local/socket cat /etc/machine-id | cmp - /etc/machine-id + +modprobe vsock_loopback ||: +if test -e /dev/vsock -a -d /sys/module/vsock_loopback ; then + ssh -o StrictHostKeyChecking=no -v -i "$ROOTID" vsock/1 cat /etc/machine-id | cmp - /etc/machine-id +fi diff --git a/test/units/testsuite-74.varlinkctl.sh b/test/units/TEST-74-AUX-UTILS.varlinkctl.sh index 5a96269..1d5a98b 100755 --- a/test/units/testsuite-74.varlinkctl.sh +++ b/test/units/TEST-74-AUX-UTILS.varlinkctl.sh @@ -32,8 +32,9 @@ if command -v userdbctl >/dev/null; then systemctl start systemd-userdbd varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{ "userName" : "testuser", "service" : "io.systemd.Multiplexer" }' varlinkctl call -j /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{ "userName" : "testuser", "service" : "io.systemd.Multiplexer" }' | jq . - varlinkctl call --more /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetMemberships '{ "service" : "io.systemd.Multiplexer" }' - varlinkctl call --more -j /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetMemberships '{ "service" : "io.systemd.Multiplexer" }' | jq --seq . + # We ignore the return value of the following two calls, since if no memberships are defined at all this will return a NotFound error, which is OK + (varlinkctl call --more /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetMemberships '{ "service" : "io.systemd.Multiplexer" }' ||:) + (varlinkctl call --more -j /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetMemberships '{ "service" : "io.systemd.Multiplexer" }' ||:) | jq --seq . varlinkctl call --oneway /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetMemberships '{ "service" : "io.systemd.Multiplexer" }' (! varlinkctl call --oneway /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetMemberships '{ "service" : "io.systemd.Multiplexer" }' | grep .) fi @@ -53,6 +54,32 @@ if [[ -x /usr/lib/systemd/systemd-pcrextend ]]; then varlinkctl introspect /usr/lib/systemd/systemd-pcrextend io.systemd.PCRExtend fi +# SSH transport +SSHBINDIR="$(mktemp -d)" + +rm_rf_sshbindir() { + rm -rf "$SSHBINDIR" +} + +trap rm_rf_sshbindir EXIT + +# Create a fake "ssh" binary that validates everything works as expected +cat > "$SSHBINDIR"/ssh <<'EOF' +#!/bin/sh + +set -xe + +test "$1" = "-W" +test "$2" = "/run/systemd/journal/io.systemd.journal" +test "$3" = "foobar" + +exec socat - UNIX-CONNECT:/run/systemd/journal/io.systemd.journal +EOF + +chmod +x "$SSHBINDIR"/ssh + +SYSTEMD_SSH="$SSHBINDIR/ssh" varlinkctl info ssh:foobar:/run/systemd/journal/io.systemd.journal + # Go through all varlink sockets we can find under /run/systemd/ for some extra coverage find /run/systemd/ -name "io.systemd*" -type s | while read -r socket; do varlinkctl info "$socket" @@ -87,3 +114,7 @@ done (! varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord </dev/null) (! varlinkctl validate-idl "") (! varlinkctl validate-idl </dev/null) + +varlinkctl info /run/systemd/io.systemd.Hostname +varlinkctl introspect /run/systemd/io.systemd.Hostname io.systemd.Hostname +varlinkctl call /run/systemd/io.systemd.Hostname io.systemd.Hostname.Describe '{}' diff --git a/test/units/TEST-74-AUX-UTILS.vpick.sh b/test/units/TEST-74-AUX-UTILS.vpick.sh new file mode 100755 index 0000000..400097f --- /dev/null +++ b/test/units/TEST-74-AUX-UTILS.vpick.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail + +at_exit() { + set +e + rm -rf /var/lib/machines/mymachine.raw.v + rm -rf /var/lib/machines/mytree.v + rm -rf /var/lib/machines/testroot.v + umount -l /tmp/dotvroot + rmdir /tmp/dotvroot +} + +trap at_exit EXIT + +mkdir -p /var/lib/machines/mymachine.raw.v + +touch /var/lib/machines/mymachine.raw.v/mymachine_7.5.13.raw +touch /var/lib/machines/mymachine.raw.v/mymachine_7.5.14_x86-64.raw +touch /var/lib/machines/mymachine.raw.v/mymachine_7.6.0_arm64.raw +touch /var/lib/machines/mymachine.raw.v/mymachine_7.7.0_x86-64+0-5.raw + +mkdir -p /var/lib/machines/mytree.v + +mkdir /var/lib/machines/mytree.v/mytree_33.4 +mkdir /var/lib/machines/mytree.v/mytree_33.5 +mkdir /var/lib/machines/mytree.v/mytree_36.0+0-5 +mkdir /var/lib/machines/mytree.v/mytree_37.0_arm64+2-3 +mkdir /var/lib/machines/mytree.v/mytree_38.0_arm64+0-5 + +ARCH="$(busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager Architecture | cut -d\" -f 2)" + +export SYSTEMD_LOG_LEVEL=debug + +if [ "$ARCH" = "x86-64" ] ; then + test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw)" = "/var/lib/machines/mymachine.raw.v/mymachine_7.5.14_x86-64.raw" + + test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -V 7.5.13)" = "/var/lib/machines/mymachine.raw.v/mymachine_7.5.13.raw" + test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -V 7.5.14)" = "/var/lib/machines/mymachine.raw.v/mymachine_7.5.14_x86-64.raw" + (! systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -V 7.6.0) + test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -V 7.7.0)" = "/var/lib/machines/mymachine.raw.v/mymachine_7.7.0_x86-64+0-5.raw" + + systemd-dissect --discover | grep "/var/lib/machines/mymachine.raw.v/mymachine_7.5.14_x86-64.raw" +elif [ "$ARCH" = "arm64" ] ; then + test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw)" = "/var/lib/machines/mymachine.raw.v/mymachine_7.6.0_arm64.raw" + + test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -V 7.5.13)" = "/var/lib/machines/mymachine.raw.v/mymachine_7.5.13.raw" + (! systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -V 7.5.14) + test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -V 7.6.0)" = "/var/lib/machines/mymachine.raw.v/mymachine_7.6.0_arm64.raw" + (! systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -V 7.7.0) + + systemd-dissect --discover | grep "/var/lib/machines/mymachine.raw.v/mymachine_7.6.0_arm64.raw" +else + test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw)" = "/var/lib/machines/mymachine.raw.v/mymachine_7.5.13.raw" + + test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -V 7.5.13)" = "/var/lib/machines/mymachine.raw.v/mymachine_7.5.13.raw" + (! systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -V 7.5.14) + (! systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -V 7.6.0) + (! systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -V 7.7.0) + + systemd-dissect --discover | grep "/var/lib/machines/mymachine.raw.v/mymachine_7.5.13.raw" +fi + +test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -A x86-64)" = "/var/lib/machines/mymachine.raw.v/mymachine_7.5.14_x86-64.raw" +test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -A arm64)" = "/var/lib/machines/mymachine.raw.v/mymachine_7.6.0_arm64.raw" +(! systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -A ia64) + +test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -A arm64 -p version)" = "7.6.0" +test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -A arm64 -p type)" = "reg" +test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -A arm64 -p filename)" = "mymachine_7.6.0_arm64.raw" +test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -A arm64 -p arch)" = "arm64" + +test "$(systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -A arm64 -t reg)" = "/var/lib/machines/mymachine.raw.v/mymachine_7.6.0_arm64.raw" +(! systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -A arm64 -t dir) +(! systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -A arm64 -t fifo) +(! systemd-vpick /var/lib/machines/mymachine.raw.v --suffix=.raw -A arm64 -t sock) + +if [ "$ARCH" != "arm64" ] ; then + test "$(systemd-vpick /var/lib/machines/mytree.v)" = "/var/lib/machines/mytree.v/mytree_33.5/" + test "$(systemd-vpick /var/lib/machines/mytree.v --type=dir)" = "/var/lib/machines/mytree.v/mytree_33.5/" +else + test "$(systemd-vpick /var/lib/machines/mytree.v)" = "/var/lib/machines/mytree.v/mytree_37.0_arm64+2-3/" + test "$(systemd-vpick /var/lib/machines/mytree.v --type=dir)" = "/var/lib/machines/mytree.v/mytree_37.0_arm64+2-3/" +fi + +(! systemd-vpick /var/lib/machines/mytree.v --type=reg) + +mkdir /tmp/dotvroot +mount --bind / /tmp/dotvroot + +mkdir /var/lib/machines/testroot.v +mkdir /var/lib/machines/testroot.v/testroot_32 +ln -s /tmp/dotvroot /var/lib/machines/testroot.v/testroot_33 +mkdir /var/lib/machines/testroot.v/testroot_34 + +ls -l /var/lib/machines/testroot.v + +test "$(systemd-vpick /var/lib/machines/testroot.v)" = /var/lib/machines/testroot.v/testroot_34/ +test "$(systemd-vpick --resolve=yes /var/lib/machines/testroot.v)" = /var/lib/machines/testroot.v/testroot_34/ +(! systemd-run --wait -p RootDirectory=/var/lib/machines/testroot.v /bin/true) + +find /var/lib/machines/testroot.v/testroot_34 +rm -rf /var/lib/machines/testroot.v/testroot_34 +test "$(systemd-vpick /var/lib/machines/testroot.v)" = /var/lib/machines/testroot.v/testroot_33/ +test "$(systemd-vpick --resolve=yes /var/lib/machines/testroot.v)" = /tmp/dotvroot/ +systemd-run --wait -p RootDirectory=/var/lib/machines/testroot.v /bin/true + +rm /var/lib/machines/testroot.v/testroot_33 +test "$(systemd-vpick /var/lib/machines/testroot.v)" = /var/lib/machines/testroot.v/testroot_32/ +test "$(systemd-vpick --resolve=yes /var/lib/machines/testroot.v)" = /var/lib/machines/testroot.v/testroot_32/ +(! systemd-run --wait -p RootDirectory=/var/lib/machines/testroot.v /bin/true) + +rm -rf /var/lib/machines/testroot.v/testroot_32 +(! systemd-vpick /var/lib/machines/testroot.v) +(! systemd-run --wait -p RootDirectory=/var/lib/machines/testroot.v /bin/true) diff --git a/test/units/testsuite-75.sh b/test/units/TEST-75-RESOLVED.sh index 86d602d..a4417ce 100755 --- a/test/units/testsuite-75.sh +++ b/test/units/TEST-75-RESOLVED.sh @@ -14,6 +14,12 @@ set -o pipefail # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh +# We need at least Knot 3.0 which support (among others) the ds-push directive +if ! knotc -c /usr/lib/systemd/tests/testdata/knot-data/knot.conf conf-check; then + echo "This test requires at least Knot 3.0. skipping..." | tee --append /skipped + exit 77 +fi + RUN_OUT="$(mktemp)" run() { @@ -46,8 +52,7 @@ monitor_check_rr() ( # displayed. We turn off pipefail for this, since we don't care about the # lhs of this pipe expression, we only care about the rhs' result to be # clean - # v255-only: match against a syslog tag as well to work around systemd/systemd#30886 - timeout -v 30s journalctl --since "$since" -f --full _SYSTEMD_UNIT="resolvectl-monitor.service" + SYSLOG_IDENTIFIER="resolvectl-monitor" | grep -m1 "$match" + timeout -v 30s journalctl -u resolvectl-monitor.service --since "$since" -f --full | grep -m1 "$match" ) restart_resolved() { @@ -103,12 +108,21 @@ assert_in '_localdnsproxy' "$(dig @127.0.0.53 -x 127.0.0.54)" mkdir -p /run/systemd/resolved.conf.d { echo "[Resolve]" - echo "MulticastDNS=yes" - echo "LLMNR=yes" + echo "MulticastDNS=no" + echo "LLMNR=no" } >/run/systemd/resolved.conf.d/mdns-llmnr.conf restart_resolved # make sure networkd is not running. systemctl stop systemd-networkd.service +assert_in 'no' "$(resolvectl mdns hoge)" +assert_in 'no' "$(resolvectl llmnr hoge)" +# Tests that reloading works +{ + echo "[Resolve]" + echo "MulticastDNS=yes" + echo "LLMNR=yes" +} >/run/systemd/resolved.conf.d/mdns-llmnr.conf +systemctl reload systemd-resolved.service # defaults to yes (both the global and per-link settings are yes) assert_in 'yes' "$(resolvectl mdns hoge)" assert_in 'yes' "$(resolvectl llmnr hoge)" @@ -131,7 +145,7 @@ assert_in 'no' "$(resolvectl llmnr hoge)" echo "MulticastDNS=resolve" echo "LLMNR=resolve" } >/run/systemd/resolved.conf.d/mdns-llmnr.conf -restart_resolved +systemctl reload systemd-resolved.service # set per-link setting resolvectl mdns hoge yes resolvectl llmnr hoge yes @@ -151,7 +165,7 @@ assert_in 'no' "$(resolvectl llmnr hoge)" echo "MulticastDNS=no" echo "LLMNR=no" } >/run/systemd/resolved.conf.d/mdns-llmnr.conf -restart_resolved +systemctl reload systemd-resolved.service # set per-link setting resolvectl mdns hoge yes resolvectl llmnr hoge yes @@ -181,23 +195,44 @@ fd00:dead:beef:cafe::1 ns1.unsigned.test 127.128.0.5 localhost5 localhost5.localdomain localhost5.localdomain4 localhost.localdomain5 localhost5.localdomain5 EOF -mkdir -p /etc/systemd/network -cat >/etc/systemd/network/10-dns0.netdev <<EOF +mkdir -p /run/systemd/network +cat >/run/systemd/network/10-dns0.netdev <<EOF [NetDev] Name=dns0 Kind=dummy EOF -cat >/etc/systemd/network/10-dns0.network <<EOF +cat >/run/systemd/network/10-dns0.network <<EOF [Match] Name=dns0 [Network] +IPv6AcceptRA=no Address=10.0.0.1/24 Address=fd00:dead:beef:cafe::1/64 DNSSEC=allow-downgrade DNS=10.0.0.1 DNS=fd00:dead:beef:cafe::1 EOF +cat >/run/systemd/network/10-dns1.netdev <<EOF +[NetDev] +Name=dns1 +Kind=dummy +EOF +cat >/run/systemd/network/10-dns1.network <<EOF +[Match] +Name=dns1 + +[Network] +IPv6AcceptRA=no +Address=10.99.0.1/24 +DNSSEC=no +EOF +systemctl edit --stdin --full --runtime --force "resolved-dummy-server.service" <<EOF +[Service] +Type=notify +Environment=SYSTEMD_LOG_LEVEL=debug +ExecStart=/usr/lib/systemd/tests/unit-tests/manual/test-resolved-dummy-server 10.99.0.1:53 +EOF DNS_ADDRESSES=( "10.0.0.1" @@ -217,6 +252,14 @@ ln -svf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf mkdir -p "/etc/dnssec-trust-anchors.d/" echo local >/etc/dnssec-trust-anchors.d/local.negative +# Copy over our knot configuration +mkdir -p /var/lib/knot/zones/ /etc/knot/ +cp -rfv /usr/lib/systemd/tests/testdata/knot-data/zones/* /var/lib/knot/zones/ +cp -fv /usr/lib/systemd/tests/testdata/knot-data/knot.conf /etc/knot/knot.conf +chgrp -R knot /etc/knot/ /var/lib/knot/ +chmod -R ug+rwX /var/lib/knot/ +chmod -R g+r /etc/knot/ + # Sign the root zone keymgr . generate algorithm=ECDSAP256SHA256 ksk=yes zsk=yes # Create a trust anchor for resolved with our root zone @@ -235,8 +278,11 @@ ln -svf /etc/bind.keys /etc/bind/bind.keys # Start the services systemctl unmask systemd-networkd -systemctl start systemd-networkd -restart_resolved +systemctl restart systemd-networkd +/usr/lib/systemd/systemd-networkd-wait-online --interface=dns1:routable --timeout=60 +systemctl reload systemd-resolved +systemctl start resolved-dummy-server + # Create knot's runtime dir, since from certain version it's provided only by # the package and not created by tmpfiles/systemd if [[ ! -d /run/knot ]]; then @@ -247,17 +293,22 @@ systemctl start knot # Wait a bit for the keys to propagate sleep 4 +systemctl status resolved-dummy-server networkctl status resolvectl status resolvectl log-level debug # Start monitoring queries -systemd-run -u resolvectl-monitor.service -p SyslogIdentifier=resolvectl-monitor -p Type=notify resolvectl monitor -systemd-run -u resolvectl-monitor-json.service -p SyslogIdentifier=resolvectl-monitor-json -p Type=notify resolvectl monitor --json=short +systemd-run -u resolvectl-monitor.service -p Type=notify resolvectl monitor +systemd-run -u resolvectl-monitor-json.service -p Type=notify resolvectl monitor --json=short -# Check if all the zones are valid (zone-check always returns 0, so let's check -# if it produces any errors/warnings) -run knotc zone-check +# FIXME: knot, unfortunately, incorrectly complains about missing zone files for zones +# that are forwarded using the `dnsproxy` module. Until the issue is resolved, +# let's fall back to pre-processing the `zone-check` output a bit before checking it +# +# See: https://gitlab.nic.cz/knot/knot-dns/-/issues/913 +run knotc zone-check || : +sed -i '/forwarded.test./d' "$RUN_OUT" [[ ! -s "$RUN_OUT" ]] # We need to manually propagate the DS records of onlinesign.test. to the parent # zone, since they're generated online @@ -273,6 +324,7 @@ done < <(keymgr onlinesign.test. ds) knotc zone-commit test. knotc reload +sleep 2 ### SETUP END ### @@ -348,6 +400,12 @@ run dig +noall +authority +comments SRV . grep -qF "status: NOERROR" "$RUN_OUT" grep -qE "IN\s+SOA\s+ns1\.unsigned\.test\." "$RUN_OUT" +run resolvectl query -t SVCB svcb.test +grep -qF 'alpn="dot"' "$RUN_OUT" +grep -qF "ipv4hint=10.0.0.1" "$RUN_OUT" + +run resolvectl query -t HTTPS https.test +grep -qF 'alpn="h2,h3"' "$RUN_OUT" : "--- ZONE: unsigned.test. ---" run dig @ns1.unsigned.test +short unsigned.test A unsigned.test AAAA @@ -405,6 +463,27 @@ grep -qF "myservice.signed.test:1234" "$RUN_OUT" grep -qF "10.0.0.20" "$RUN_OUT" grep -qF "fd00:dead:beef:cafe::17" "$RUN_OUT" grep -qF "authenticated: yes" "$RUN_OUT" + +# Test service resolve over Varlink +run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"name":"","type":"_mysvc._tcp","domain":"signed.test"}' +grep -qF '"services":[{"priority":10,"weight":5,"port":1234,"hostname":"myservice.signed.test","canonicalName":"myservice.signed.test","addresses":[{"ifindex":' "$RUN_OUT" +grep -qF '"family":10,"address":[253,0,222,173,190,239,202,254,0,0,0,0,0,0,0,23]' "$RUN_OUT" +grep -qF '"family":2,"address":[10,0,0,20]' "$RUN_OUT" +grep -qF '}]}],"txt":["This is TXT for myservice"],"canonical":{"name":null,"type":"_mysvc._tcp","domain":"signed.test"},"flags":' "$RUN_OUT" + +# without name +run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"type":"_mysvc._tcp","domain":"signed.test"}' +# without txt (SD_RESOLVE_NO_TXT) +run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"type":"_mysvc._tcp","domain":"signed.test","flags":64}' +(! grep -qF '"txt"' "$RUN_OUT") +# without address (SD_RESOLVE_NO_ADDRESS) +run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"type":"_mysvc._tcp","domain":"signed.test","flags":128}' +(! grep -qF '"addresses"' "$RUN_OUT") +# without txt and address +run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"type":"_mysvc._tcp","domain":"signed.test","flags":192}' +(! grep -qF '"txt"' "$RUN_OUT") +(! grep -qF '"addresses"' "$RUN_OUT") + (! run resolvectl service _invalidsvc._udp signed.test) grep -qE "invalidservice\.signed\.test' not found" "$RUN_OUT" run resolvectl service _untrustedsvc._udp signed.test @@ -418,6 +497,18 @@ grep -qF "; fully validated" "$RUN_OUT" run resolvectl openpgp mr.smith@signed.test grep -qF "5a786cdc59c161cdafd818143705026636962198c66ed4c5b3da321e._openpgpkey.signed.test" "$RUN_OUT" grep -qF "authenticated: yes" "$RUN_OUT" +# Check zone transfers (AXFR/IXFR) +# Note: since resolved doesn't support zone transfers, let's just make sure it +# simply refuses such requests without choking on them +# See: https://github.com/systemd/systemd/pull/30809#issuecomment-1880102804 +run dig @ns1.unsigned.test AXFR signed.test +grep -qE "SOA\s+ns1.unsigned.test. root.unsigned.test." "$RUN_OUT" +run dig AXFR signed.test +grep -qF "; Transfer failed" "$RUN_OUT" +run dig @ns1.unsigned.test IXFR=43 signed.test +grep -qE "SOA\s+ns1.unsigned.test. root.unsigned.test." "$RUN_OUT" +run dig IXFR=43 signed.test +grep -qF "; Transfer failed" "$RUN_OUT" # DNSSEC validation with multiple records of the same type for the same name # Issue: https://github.com/systemd/systemd/issues/22002 @@ -460,9 +551,9 @@ monitor_check_rr "$TIMESTAMP" "follow13.almost.final.signed.test IN CNAME follow monitor_check_rr "$TIMESTAMP" "follow14.final.signed.test IN A 10.0.0.14" # Non-existing RR + CNAME chain -run dig +dnssec AAAA cname-chain.signed.test -grep -qF "status: NOERROR" "$RUN_OUT" -grep -qE "^follow14\.final\.signed\.test\..+IN\s+NSEC\s+" "$RUN_OUT" +#run dig +dnssec AAAA cname-chain.signed.test +#grep -qF "status: NOERROR" "$RUN_OUT" +#grep -qE "^follow14\.final\.signed\.test\..+IN\s+NSEC\s+" "$RUN_OUT" : "--- ZONE: onlinesign.test (dynamic DNSSEC) ---" @@ -545,6 +636,61 @@ grep -qF "fd00:dead:beef:cafe::123" "$RUN_OUT" #run dig +dnssec this.does.not.exist.untrusted.test #grep -qF "status: NXDOMAIN" "$RUN_OUT" +: "--- ZONE: forwarded.test (queries forwarded to our dummy test server) ---" +JOURNAL_CURSOR="$(mktemp)" +journalctl -n0 -q --cursor-file="$JOURNAL_CURSOR" + +# See "test-resolved-dummy-server.c" for the server part +(! run resolvectl query nope.forwarded.test) +grep -qF "nope.forwarded.test" "$RUN_OUT" +grep -qF "not found" "$RUN_OUT" + +# SERVFAIL + EDE code 6: DNSSEC Bogus +(! run resolvectl query edns-bogus-dnssec.forwarded.test) +grep -qE "^edns-bogus-dnssec.forwarded.test:.+: upstream-failure \(DNSSEC Bogus\)" "$RUN_OUT" +# Same thing, but over Varlink +(! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name" : "edns-bogus-dnssec.forwarded.test"}') +grep -qF "io.systemd.Resolve.DNSSECValidationFailed" "$RUN_OUT" +grep -qF '{"result":"upstream-failure","extendedDNSErrorCode":6}' "$RUN_OUT" +journalctl --sync +journalctl -u systemd-resolved.service --cursor-file="$JOURNAL_CURSOR" --grep "Server returned error: SERVFAIL \(DNSSEC Bogus\). Lookup failed." + +# SERVFAIL + EDE code 16: Censored + extra text +(! run resolvectl query edns-extra-text.forwarded.test) +grep -qE "^edns-extra-text.forwarded.test.+: SERVFAIL \(Censored: Nothing to see here!\)" "$RUN_OUT" +(! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name" : "edns-extra-text.forwarded.test"}') +grep -qF "io.systemd.Resolve.DNSError" "$RUN_OUT" +grep -qF '{"rcode":2,"extendedDNSErrorCode":16,"extendedDNSErrorMessage":"Nothing to see here!"}' "$RUN_OUT" +journalctl --sync +journalctl -u systemd-resolved.service --cursor-file="$JOURNAL_CURSOR" --grep "Server returned error: SERVFAIL \(Censored: Nothing to see here!\)" + +# SERVFAIL + EDE code 0: Other + extra text +(! run resolvectl query edns-code-zero.forwarded.test) +grep -qE "^edns-code-zero.forwarded.test:.+: SERVFAIL \(Other: 🐱\)" "$RUN_OUT" +(! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name" : "edns-code-zero.forwarded.test"}') +grep -qF "io.systemd.Resolve.DNSError" "$RUN_OUT" +grep -qF '{"rcode":2,"extendedDNSErrorCode":0,"extendedDNSErrorMessage":"🐱"}' "$RUN_OUT" +journalctl --sync +journalctl -u systemd-resolved.service --cursor-file="$JOURNAL_CURSOR" --grep "Server returned error: SERVFAIL \(Other: 🐱\)" + +# SERVFAIL + invalid EDE code +(! run resolvectl query edns-invalid-code.forwarded.test) +grep -qE "^edns-invalid-code.forwarded.test:.+: SERVFAIL \([0-9]+\)" "$RUN_OUT" +(! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name" : "edns-invalid-code.forwarded.test"}') +grep -qF "io.systemd.Resolve.DNSError" "$RUN_OUT" +grep -qE '{"rcode":2,"extendedDNSErrorCode":[0-9]+}' "$RUN_OUT" +journalctl --sync +journalctl -u systemd-resolved.service --cursor-file="$JOURNAL_CURSOR" --grep "Server returned error: SERVFAIL \(\d+\)" + +# SERVFAIL + invalid EDE code + extra text +(! run resolvectl query edns-invalid-code-with-extra-text.forwarded.test) +grep -qE '^edns-invalid-code-with-extra-text.forwarded.test:.+: SERVFAIL \([0-9]+: Hello \[#\]\$%~ World\)' "$RUN_OUT" +(! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name" : "edns-invalid-code-with-extra-text.forwarded.test"}') +grep -qF "io.systemd.Resolve.DNSError" "$RUN_OUT" +grep -qE '{"rcode":2,"extendedDNSErrorCode":[0-9]+,"extendedDNSErrorMessage":"Hello \[#\]\$%~ World"}' "$RUN_OUT" +journalctl --sync +journalctl -u systemd-resolved.service --cursor-file="$JOURNAL_CURSOR" --grep "Server returned error: SERVFAIL \(\d+: Hello \[\#\]\\$%~ World\)" + ### Test resolvectl show-cache run resolvectl show-cache run resolvectl show-cache --json=short @@ -559,10 +705,10 @@ systemctl stop resolvectl-monitor-json.service # Issue: https://github.com/systemd/systemd/issues/29580 (part #2) # # Check for any warnings regarding malformed messages -(! journalctl -p warning --grep malformed _SYSTEMD_UNIT="resolvectl-monitor-json.service" + SYSLOG_IDENTIFIER="resolvectl-monitor-json") +(! journalctl -u resolvectl-monitor.service -u reseolvectl-monitor-json.service -p warning --grep malformed) # Verify that all queries recorded by `resolvectl monitor --json` produced a valid JSON # with expected fields -journalctl -p info -o cat _SYSTEMD_UNIT="resolvectl-monitor-json.service" + SYSLOG_IDENTIFIER="resolvectl-monitor-json" | while read -r line; do +journalctl -p info -o cat _SYSTEMD_UNIT="resolvectl-monitor-json.service" | while read -r line; do # Check that both "question" and "answer" fields are arrays # # The expression is slightly more complicated due to the fact that the "answer" field is optional, @@ -589,7 +735,9 @@ if command -v nft >/dev/null; then sleep 2 drop_dns_outbound_traffic set +e - run dig stale1.unsigned.test -t A + # Make sure we give sd-resolved enough time to timeout (5-10s) before giving up + # See: https://github.com/systemd/systemd/issues/31639#issuecomment-2009152617 + run dig +tries=1 +timeout=15 stale1.unsigned.test -t A set -eux grep -qE "no servers could be reached" "$RUN_OUT" nft flush ruleset @@ -602,13 +750,14 @@ if command -v nft >/dev/null; then echo "StaleRetentionSec=1d" } >/run/systemd/resolved.conf.d/test.conf ln -svf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf - restart_resolved + systemctl reload systemd-resolved.service run dig stale1.unsigned.test -t A grep -qE "NOERROR" "$RUN_OUT" sleep 2 drop_dns_outbound_traffic - run dig stale1.unsigned.test -t A + # Make sure we give sd-resolved enough time to timeout (5-10s) and serve the stale data (see above) + run dig +tries=1 +timeout=15 stale1.unsigned.test -t A grep -qE "NOERROR" "$RUN_OUT" grep -qE "10.0.0.112" "$RUN_OUT" @@ -725,6 +874,28 @@ run resolvectl reset-statistics --json=pretty run resolvectl reset-statistics --json=short +test "$(resolvectl --json=short query -t AAAA localhost)" == '{"key":{"class":1,"type":28,"name":"localhost"},"address":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]}' +test "$(resolvectl --json=short query -t A localhost)" == '{"key":{"class":1,"type":1,"name":"localhost"},"address":[127,0,0,1]}' + +# Test ResolveRecord RR resolving via Varlink +test "$(varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveRecord '{"name":"localhost","type":1}' --json=short | jq -rc 'del(.rrs | .[] | .ifindex)')" == '{"rrs":[{"rr":{"key":{"class":1,"type":1,"name":"localhost"},"address":[127,0,0,1]},"raw":"CWxvY2FsaG9zdAAAAQABAAAAAAAEfwAAAQ=="}],"flags":786945}' +test "$(varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveRecord '{"name":"localhost","type":28}' --json=short | jq -rc 'del(.rrs | .[] | .ifindex)')" == '{"rrs":[{"rr":{"key":{"class":1,"type":28,"name":"localhost"},"address":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]},"raw":"CWxvY2FsaG9zdAAAHAABAAAAAAAQAAAAAAAAAAAAAAAAAAAAAQ=="}],"flags":786945}' + +# Ensure that reloading keeps the manually configured address +{ + echo "[Resolve]" + echo "DNS=8.8.8.8" +} >/run/systemd/resolved.conf.d/reload.conf +resolvectl dns dns0 1.1.1.1 +systemctl reload systemd-resolved.service +resolvectl status +resolvectl dns dns0 | grep -qF "1.1.1.1" +# For some reason piping this last command to grep fails with: +# 'resolvectl[1378]: Failed to print table: Broken pipe' +# so use an intermediate file in /tmp/ +resolvectl >/tmp/output +grep -qF "DNS Servers: 8.8.8.8" /tmp/output + # Check if resolved exits cleanly. restart_resolved diff --git a/test/units/testsuite-76.sh b/test/units/TEST-76-SYSCTL.sh index 855d0ef..855d0ef 100755 --- a/test/units/testsuite-76.sh +++ b/test/units/TEST-76-SYSCTL.sh diff --git a/test/units/testsuite-78.sh b/test/units/TEST-78-SIGQUEUE.sh index 46afd3c..46afd3c 100755 --- a/test/units/testsuite-78.sh +++ b/test/units/TEST-78-SIGQUEUE.sh diff --git a/test/units/testsuite-79.sh b/test/units/TEST-79-MEMPRESS.sh index 205f7f3..2b1de20 100755 --- a/test/units/testsuite-79.sh +++ b/test/units/TEST-79-MEMPRESS.sh @@ -15,7 +15,7 @@ fi systemd-analyze log-level debug -CGROUP=/sys/fs/cgroup/"$(systemctl show testsuite-79.service -P ControlGroup)" +CGROUP=/sys/fs/cgroup/"$(systemctl show TEST-79-MEMPRESS.service -P ControlGroup)" test -d "$CGROUP" if ! test -f "$CGROUP"/memory.pressure ; then @@ -49,7 +49,17 @@ EOF chmod +x "$SCRIPT" -systemd-run -u "$UNIT" -p Type=exec -p ProtectControlGroups=1 -p DynamicUser=1 -p MemoryPressureWatch=on -p MemoryPressureThresholdSec=123ms -p BindPaths=$SCRIPT --wait "$SCRIPT" +systemd-run \ + -u "$UNIT" \ + -p Type=exec \ + -p ProtectControlGroups=1 \ + -p DynamicUser=1 \ + -p MemoryPressureWatch=on \ + -p MemoryPressureThresholdSec=123ms \ + -p BindPaths=$SCRIPT \ + `# Make sanitizers happy when DynamicUser=1 pulls in instrumented systemd NSS modules` \ + -p EnvironmentFile=-/usr/lib/systemd/systemd-asan-env \ + --wait "$SCRIPT" rm "$SCRIPT" diff --git a/test/units/testsuite-80.sh b/test/units/TEST-80-NOTIFYACCESS.sh index 97b222a..97b222a 100755 --- a/test/units/testsuite-80.sh +++ b/test/units/TEST-80-NOTIFYACCESS.sh diff --git a/test/units/testsuite-81.debug-generator.sh b/test/units/TEST-81-GENERATORS.debug-generator.sh index fddf85a..ef1e205 100755 --- a/test/units/testsuite-81.debug-generator.sh +++ b/test/units/TEST-81-GENERATORS.debug-generator.sh @@ -62,6 +62,13 @@ SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR" link_endswith "$OUT_DIR/early/default.target.wants/debug-shell.service" /lib/systemd/system/debug-shell.service grep -F "/dev/tty666" "$OUT_DIR/early/debug-shell.service.d/50-tty.conf" +# Same thing, but with custom tty using systemd.default_debug_tty +: "debug-shell: regular + systemd.default_debug_tty=/dev/tty666 systemd.debug_shell=yes" +CMDLINE="$CMDLINE systemd.default_debug_tty=/dev/tty666 systemd.debug_shell=yes" +SYSTEMD_PROC_CMDLINE="$CMDLINE" run_and_list "$GENERATOR_BIN" "$OUT_DIR" +link_endswith "$OUT_DIR/early/default.target.wants/debug-shell.service" /lib/systemd/system/debug-shell.service +grep -F "/dev/tty666" "$OUT_DIR/early/debug-shell.service.d/50-tty.conf" + # Now override the default target via systemd.unit= : "debug-shell: regular + systemd.unit=" CMDLINE="$CMDLINE systemd.unit=my-fancy.target" diff --git a/test/units/testsuite-81.environment-d-generator.sh b/test/units/TEST-81-GENERATORS.environment-d-generator.sh index 5bc3978..5bc3978 100755 --- a/test/units/testsuite-81.environment-d-generator.sh +++ b/test/units/TEST-81-GENERATORS.environment-d-generator.sh diff --git a/test/units/testsuite-81.fstab-generator.sh b/test/units/TEST-81-GENERATORS.fstab-generator.sh index 50c4b2f..0c1b27e 100755 --- a/test/units/testsuite-81.fstab-generator.sh +++ b/test/units/TEST-81-GENERATORS.fstab-generator.sh @@ -13,6 +13,7 @@ OUT_DIR="$(mktemp -d /tmp/fstab-generator.XXX)" FSTAB="$(mktemp)" at_exit() { + mountpoint -q /proc/cmdline && umount /proc/cmdline rm -fr "${OUT_DIR:?}" "${FSTAB:?}" } @@ -148,7 +149,7 @@ check_fstab_mount_units() { fi if [[ -n "$opts" ]] && [[ "$opts" != defaults ]]; then # Some options are not propagated to the generated unit - if [[ "$where" == / ]]; then + if [[ "$where" == / || "$where" == /usr ]]; then filtered_options="$(opt_filter "$opts" "(noauto|nofail|x-systemd.(wanted-by=|required-by=|automount|device-timeout=))")" else filtered_options="$(opt_filter "$opts" "^x-systemd.device-timeout=")" @@ -325,7 +326,7 @@ SYSTEMD_IN_INITRD=1 SYSTEMD_FSTAB=/dev/null SYSTEMD_SYSROOT_FSTAB="$FSTAB" check # Check the default stuff that we (almost) always create in initrd : "fstab-generator: initrd default" -SYSTEMD_IN_INITRD=1 SYSTEMD_FSTAB=/dev/null SYSTEMD_SYSROOT_FSTAB=/dev/null run_and_list "$GENERATOR_BIN" "$OUT_DIR" +SYSTEMD_PROC_CMDLINE="root=/dev/sda2" SYSTEMD_IN_INITRD=1 SYSTEMD_FSTAB=/dev/null SYSTEMD_SYSROOT_FSTAB=/dev/null run_and_list "$GENERATOR_BIN" "$OUT_DIR" test -e "$OUT_DIR/normal/sysroot.mount" test -e "$OUT_DIR/normal/systemd-fsck-root.service" link_eq "$OUT_DIR/normal/initrd-root-fs.target.requires/sysroot.mount" "../sysroot.mount" @@ -347,7 +348,7 @@ cat "$FSTAB" printf "%s\n" "${FSTAB_INVALID[@]}" >"$FSTAB" cat "$FSTAB" # Don't care about the exit code here -SYSTEMD_FSTAB="$FSTAB" run_and_list "$GENERATOR_BIN" "$OUT_DIR" || : +SYSTEMD_PROC_CMDLINE="" SYSTEMD_FSTAB="$FSTAB" run_and_list "$GENERATOR_BIN" "$OUT_DIR" || : # No mounts should get created here [[ "$(find "$OUT_DIR" -name "*.mount" | wc -l)" -eq 0 ]] diff --git a/test/units/testsuite-81.getty-generator.sh b/test/units/TEST-81-GENERATORS.getty-generator.sh index 103e966..d1dd22c 100755 --- a/test/units/testsuite-81.getty-generator.sh +++ b/test/units/TEST-81-GENERATORS.getty-generator.sh @@ -85,5 +85,5 @@ PID1_ENVIRON="SYSTEMD_GETTY_AUTO=0" run_and_list "$GENERATOR_BIN" "$OUT_DIR" [[ "$(find "$OUT_DIR" ! -type d | wc -l)" -eq 0 ]] # Cleanup -umount /sys/class/tty/console/active +umount /sys/class/tty/console/active --lazy rm -f "${DUMMY_CONSOLES[@]/#//dev/}" /dev/notatty99 diff --git a/test/units/testsuite-81.run-generator.sh b/test/units/TEST-81-GENERATORS.run-generator.sh index 9bd74ef..9bd74ef 100755 --- a/test/units/testsuite-81.run-generator.sh +++ b/test/units/TEST-81-GENERATORS.run-generator.sh diff --git a/test/units/testsuite-81.sh b/test/units/TEST-81-GENERATORS.sh index 9c2a033..9c2a033 100755 --- a/test/units/testsuite-81.sh +++ b/test/units/TEST-81-GENERATORS.sh diff --git a/test/units/testsuite-81.system-update-generator.sh b/test/units/TEST-81-GENERATORS.system-update-generator.sh index 8ee1fee..8ee1fee 100755 --- a/test/units/testsuite-81.system-update-generator.sh +++ b/test/units/TEST-81-GENERATORS.system-update-generator.sh diff --git a/test/units/testsuite-82.sh b/test/units/TEST-82-SOFTREBOOT.sh index b5e6ded..f86bc92 100755 --- a/test/units/testsuite-82.sh +++ b/test/units/TEST-82-SOFTREBOOT.sh @@ -23,11 +23,13 @@ systemd-analyze log-level debug export SYSTEMD_LOG_LEVEL=debug -if [ -f /run/testsuite82.touch3 ]; then +if [ -f /run/TEST-82-SOFTREBOOT.touch3 ]; then echo "This is the fourth boot!" systemd-notify --status="Fourth Boot" - rm /run/testsuite82.touch3 + test "$(busctl -j get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager SoftRebootsCount | jq -r '.data')" -eq 3 + + rm /run/TEST-82-SOFTREBOOT.touch3 mount rmdir /original-root /run/nextroot @@ -37,22 +39,31 @@ if [ -f /run/testsuite82.touch3 ]; then test "$x" = "oinkoink" # Check that the surviving services are still around - test "$(systemctl show -P ActiveState testsuite-82-survive.service)" = "active" - test "$(systemctl show -P ActiveState testsuite-82-survive-argv.service)" = "active" - test "$(systemctl show -P ActiveState testsuite-82-nosurvive-sigterm.service)" != "active" - test "$(systemctl show -P ActiveState testsuite-82-nosurvive.service)" != "active" - + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive.service)" = "active" + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active" + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive-sigterm.service)" != "active" + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive.service)" != "active" + + [[ ! -e /run/credentials/TEST-82-SOFTREBOOT-nosurvive.service ]] + assert_eq "$(cat /run/credentials/TEST-82-SOFTREBOOT-survive-argv.service/preserve)" "yay" + + # There may be huge amount of pending messages in sockets. Processing them may cause journal rotation and + # removal of old archived journal files. If a journal file is removed during journalctl reading it, + # the command may fail. To mitigate such, sync before reading journals. Workaround for #32834. + journalctl --sync # Check journals journalctl -o short-monotonic --no-hostname --grep '(will soft-reboot|KILL|corrupt)' assert_eq "$(journalctl -q -o short-monotonic -u systemd-journald.service --grep 'corrupt')" "" # All succeeded, exit cleanly now -elif [ -f /run/testsuite82.touch2 ]; then +elif [ -f /run/TEST-82-SOFTREBOOT.touch2 ]; then echo "This is the third boot!" systemd-notify --status="Third Boot" - rm /run/testsuite82.touch2 + test "$(busctl -j get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager SoftRebootsCount | jq -r '.data')" -eq 2 + + rm /run/TEST-82-SOFTREBOOT.touch2 # Check that the fdstore entry still exists test "$LISTEN_FDS" -eq 2 @@ -66,10 +77,10 @@ elif [ -f /run/testsuite82.touch2 ]; then rm "$T" # Check that the surviving services are still around - test "$(systemctl show -P ActiveState testsuite-82-survive.service)" = "active" - test "$(systemctl show -P ActiveState testsuite-82-survive-argv.service)" = "active" - test "$(systemctl show -P ActiveState testsuite-82-nosurvive-sigterm.service)" != "active" - test "$(systemctl show -P ActiveState testsuite-82-nosurvive.service)" != "active" + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive.service)" = "active" + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active" + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive-sigterm.service)" != "active" + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive.service)" != "active" # Test that we really are in the new overlayfs root fs read -r x </lower @@ -82,21 +93,23 @@ elif [ -f /run/testsuite82.touch2 ]; then mount # Restart the unit that is not supposed to survive - systemd-run --collect --service-type=exec --unit=testsuite-82-nosurvive.service sleep infinity + systemd-run --collect --service-type=exec --unit=TEST-82-SOFTREBOOT-nosurvive.service sleep infinity # Now issue the soft reboot. We should be right back soon. - touch /run/testsuite82.touch3 + touch /run/TEST-82-SOFTREBOOT.touch3 systemctl --no-block soft-reboot # Now block until the soft-boot killing spree kills us exec sleep infinity -elif [ -f /run/testsuite82.touch ]; then +elif [ -f /run/TEST-82-SOFTREBOOT.touch ]; then echo "This is the second boot!" systemd-notify --status="Second Boot" + test "$(busctl -j get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager SoftRebootsCount | jq -r '.data')" -eq 1 + # Clean up what we created earlier - rm /run/testsuite82.touch + rm /run/TEST-82-SOFTREBOOT.touch # Check that the fdstore entry still exists test "$LISTEN_FDS" -eq 1 @@ -104,8 +117,11 @@ elif [ -f /run/testsuite82.touch ]; then test "$x" = "wuffwuff" # Check that we got a PrepareForShutdownWithMetadata signal with the right type - cat /run/testsuite82.signal - test "$(jq -r '.payload.data[1].type.data' </run/testsuite82.signal)" = "soft-reboot" + cat /run/TEST-82-SOFTREBOOT.signal + test "$(jq -r '.payload.data[1].type.data' </run/TEST-82-SOFTREBOOT.signal)" = "soft-reboot" + + # Check that the system credentials survived the soft reboot. + test "$(systemd-creds cat --system kernelcmdlinecred)" = "uff" # Upload another entry T="/dev/shm/fdstore.$RANDOM" @@ -114,10 +130,10 @@ elif [ -f /run/testsuite82.touch ]; then rm "$T" # Check that the surviving services are still around - test "$(systemctl show -P ActiveState testsuite-82-survive.service)" = "active" - test "$(systemctl show -P ActiveState testsuite-82-survive-argv.service)" = "active" - test "$(systemctl show -P ActiveState testsuite-82-nosurvive-sigterm.service)" != "active" - test "$(systemctl show -P ActiveState testsuite-82-nosurvive.service)" != "active" + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive.service)" = "active" + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-survive-argv.service)" = "active" + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive-sigterm.service)" != "active" + test "$(systemctl show -P ActiveState TEST-82-SOFTREBOOT-nosurvive.service)" != "active" # This time we test the /run/nextroot/ root switching logic. (We synthesize a new rootfs from the old via overlayfs) mkdir -p /run/nextroot /tmp/nextroot-lower /original-root @@ -138,11 +154,16 @@ elif [ -f /run/testsuite82.touch ]; then mount --bind / /run/nextroot/original-root # Restart the unit that is not supposed to survive - systemd-run --collect --service-type=exec --unit=testsuite-82-nosurvive.service sleep infinity + systemd-run --collect --service-type=exec --unit=TEST-82-SOFTREBOOT-nosurvive.service sleep infinity + + # Now ensure there are no naming clashes and a bunch of transient units all succeed + for _ in $(seq 1 25); do + systemd-run --wait true + done # Now issue the soft reboot. We should be right back soon. Given /run/nextroot exists, we should # automatically do a softreboot instead of normal reboot. - touch /run/testsuite82.touch2 + touch /run/TEST-82-SOFTREBOOT.touch2 systemctl --no-block reboot # Now block until the soft-boot killing spree kills us @@ -151,6 +172,8 @@ else # This is the first boot systemd-notify --status="First Boot" + test "$(busctl -j get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager SoftRebootsCount | jq -r '.data')" -eq 0 + # Let's upload an fd to the fdstore, so that we can verify fdstore passing works correctly T="/dev/shm/fdstore.$RANDOM" echo "wuffwuff" >"$T" @@ -178,39 +201,61 @@ EOF # This sets DefaultDependencies=no so that they remain running until the very end, and # IgnoreOnIsolate=yes so that they aren't stopped via the "testsuite.target" isolation we do on next boot, # and will be killed by the final sigterm/sigkill spree. - systemd-run --collect --service-type=notify -p DefaultDependencies=no -p IgnoreOnIsolate=yes --unit=testsuite-82-nosurvive-sigterm.service "$survive_sigterm" - systemd-run --collect --service-type=exec -p DefaultDependencies=no -p IgnoreOnIsolate=yes --unit=testsuite-82-nosurvive.service sleep infinity + systemd-run --collect --service-type=notify -p DefaultDependencies=no -p IgnoreOnIsolate=yes --unit=TEST-82-SOFTREBOOT-nosurvive-sigterm.service "$survive_sigterm" + systemd-run --collect --service-type=exec -p DefaultDependencies=no -p IgnoreOnIsolate=yes -p SetCredential=gone:hoge --unit=TEST-82-SOFTREBOOT-nosurvive.service sleep infinity + + # Ensure that the unit doesn't get deactivated by dependencies on the source file. Given it's a verity + # image that is already open, even if the tmpfs with the image goes away, the file will be pinned by the + # kernel and will keep working. + cp /usr/share/minimal_0.* /tmp/ # Configure these transient units to survive the soft reboot - they will not conflict with shutdown.target # and it will be ignored on the isolate that happens in the next boot. The first will use argv[0][0] = # '@', and the second will use SurviveFinalKillSignal=yes. Both should survive. - systemd-run --service-type=notify --unit=testsuite-82-survive-argv.service \ + # By writing to stdout, which is connected to the journal, we also ensure logging doesn't break across + # soft reboots due to journald being temporarily stopped. + systemd-run --service-type=notify --unit=TEST-82-SOFTREBOOT-survive-argv.service \ --property SurviveFinalKillSignal=no \ --property IgnoreOnIsolate=yes \ --property DefaultDependencies=no \ --property After=basic.target \ --property "Conflicts=reboot.target kexec.target poweroff.target halt.target emergency.target rescue.target" \ --property "Before=reboot.target kexec.target poweroff.target halt.target emergency.target rescue.target" \ + --property SetCredential=preserve:yay \ "$survive_argv" - systemd-run --service-type=exec --unit=testsuite-82-survive.service \ + # shellcheck disable=SC2016 + systemd-run --service-type=exec --unit=TEST-82-SOFTREBOOT-survive.service \ + --property TemporaryFileSystem="/run /tmp /var" \ + --property RootImage=/tmp/minimal_0.raw \ + --property BindReadOnlyPaths=/dev/log \ + --property BindReadOnlyPaths=/run/systemd/journal/socket \ + --property BindReadOnlyPaths=/run/systemd/journal/stdout \ --property SurviveFinalKillSignal=yes \ --property IgnoreOnIsolate=yes \ --property DefaultDependencies=no \ --property After=basic.target \ --property "Conflicts=reboot.target kexec.target poweroff.target halt.target emergency.target rescue.target" \ --property "Before=reboot.target kexec.target poweroff.target halt.target emergency.target rescue.target" \ - sleep infinity + bash -c 'count=0; while echo "$count"; do count=$[$count +1]; sleep 1; done' # Check that we can set up an inhibitor, and that busctl monitor sees the # PrepareForShutdownWithMetadata signal and that it says 'soft-reboot'. - systemd-run --unit busctl.service --service-type=exec --property StandardOutput=file:/run/testsuite82.signal \ + systemd-run --unit busctl.service --service-type=exec --property StandardOutput=file:/run/TEST-82-SOFTREBOOT.signal \ busctl monitor --json=pretty --match 'sender=org.freedesktop.login1,path=/org/freedesktop/login1,interface=org.freedesktop.login1.Manager,member=PrepareForShutdownWithMetadata,type=signal' systemd-run --unit inhibit.service --service-type=exec \ systemd-inhibit --what=shutdown --who=test --why=test --mode=delay \ sleep infinity + # Enqueue a bunch of failing units to try and trigger the transient name clash that happens due to D-Bus + # being restarted and the "unique" bus IDs not being unique across restarts + for _ in $(seq 1 25); do + # Use --wait to ensure we connect to the system bus instead of the private bus (otherwise a UUID is + # used instead of the bus ID) + systemd-run --wait false || true + done + # Now issue the soft reboot. We should be right back soon. - touch /run/testsuite82.touch + touch /run/TEST-82-SOFTREBOOT.touch systemctl --no-block --check-inhibitors=yes soft-reboot # Now block until the soft-boot killing spree kills us @@ -220,4 +265,4 @@ fi systemd-analyze log-level info touch /testok -systemctl --no-block poweroff +systemctl --no-block exit 123 diff --git a/test/units/testsuite-83.sh b/test/units/TEST-83-BTRFS.sh index a722c79..4f10ae7 100755 --- a/test/units/testsuite-83.sh +++ b/test/units/TEST-83-BTRFS.sh @@ -3,6 +3,13 @@ set -eux set -o pipefail +FSTYPE="$(stat --file-system --format "%T" /)" + +if [[ "$FSTYPE" != "btrfs" ]]; then + echo "Root filesystem is $FSTYPE instead of btrfs, skipping" + exit 77 +fi + TEST_BTRFS_OFFSET=/usr/lib/systemd/tests/unit-tests/manual/test-btrfs-physical-offset SWAPFILE=/var/tmp/swapfile diff --git a/test/units/testsuite-84.sh b/test/units/TEST-84-STORAGETM.sh index eae87d5..eae87d5 100755 --- a/test/units/testsuite-84.sh +++ b/test/units/TEST-84-STORAGETM.sh diff --git a/test/units/a-conj.service b/test/units/a-conj.service index 3a7c9e1..13927e7 100644 --- a/test/units/a-conj.service +++ b/test/units/a-conj.service @@ -6,4 +6,4 @@ After=a.service Before=a.service [Service] -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/a.service b/test/units/a.service index ec5d059..0cc1320 100644 --- a/test/units/a.service +++ b/test/units/a.service @@ -5,4 +5,4 @@ Requires=b.service Before=b.service [Service] -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/autorelabel.service b/test/units/autorelabel.service index 7e5f9a2..5f8386e 100644 --- a/test/units/autorelabel.service +++ b/test/units/autorelabel.service @@ -3,17 +3,17 @@ Description=Relabel all filesystems DefaultDependencies=no Requires=local-fs.target -Conflicts=shutdown.target After=local-fs.target -Before=sysinit.target shutdown.target +Conflicts=shutdown.target +Before=shutdown.target basic.target ConditionSecurity=selinux ConditionPathExists=|/.autorelabel +SuccessAction=reboot [Service] -ExecStart=sh -xec 'echo 0 >/sys/fs/selinux/enforce; fixfiles -f -F relabel; rm /.autorelabel; systemctl --force reboot' +ExecStart=sh -xec 'echo 0 >/sys/fs/selinux/enforce; fixfiles -f -F relabel; rm /.autorelabel;' Type=oneshot TimeoutSec=infinity -RemainAfterExit=yes [Install] WantedBy=basic.target diff --git a/test/units/b.service b/test/units/b.service index 4503cf3..e875714 100644 --- a/test/units/b.service +++ b/test/units/b.service @@ -4,4 +4,4 @@ Description=B Wants=f.service [Service] -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/c.service b/test/units/c.service index a1ce28c..3fc3717 100644 --- a/test/units/c.service +++ b/test/units/c.service @@ -4,4 +4,4 @@ Description=C Requires=a.service [Service] -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/d.service b/test/units/d.service index 8202325..0438607 100644 --- a/test/units/d.service +++ b/test/units/d.service @@ -6,4 +6,4 @@ Before=a.service Requires=a.service [Service] -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/daughter.service b/test/units/daughter.service index 385fbed..0ee4f24 100644 --- a/test/units/daughter.service +++ b/test/units/daughter.service @@ -5,5 +5,5 @@ Description=Daughter Service [Service] Slice=parent.slice Type=oneshot -ExecStart=/bin/true +ExecStart=true CPUAccounting=true diff --git a/test/units/delegated_cgroup_filtering_payload.sh b/test/units/delegated_cgroup_filtering_payload.sh index 50d01a5..1181fbb 100755 --- a/test/units/delegated_cgroup_filtering_payload.sh +++ b/test/units/delegated_cgroup_filtering_payload.sh @@ -2,11 +2,8 @@ # SPDX-License-Identifier: LGPL-2.1-or-later mkdir /sys/fs/cgroup/system.slice/delegated-cgroup-filtering.service/the_child -/bin/sh /usr/lib/systemd/tests/testdata/units/delegated_cgroup_filtering_payload_child.sh & +/bin/sh /usr/lib/systemd/tests/testdata/units/delegated_cgroup_filtering_payload_child.sh -while true -do - echo "parent_process: hello, world!" - echo "parent_process: hello, people!" - sleep .15 -done +echo "parent_process: hello, world!" +echo "parent_process: hello, people!" +sleep 2 diff --git a/test/units/delegated_cgroup_filtering_payload_child.sh b/test/units/delegated_cgroup_filtering_payload_child.sh index b5635b5..94f0d3a 100755 --- a/test/units/delegated_cgroup_filtering_payload_child.sh +++ b/test/units/delegated_cgroup_filtering_payload_child.sh @@ -3,9 +3,6 @@ echo $$ >/sys/fs/cgroup/system.slice/delegated-cgroup-filtering.service/the_child/cgroup.procs -while true -do - echo "child_process: hello, world!" - echo "child_process: hello, people!" - sleep .15 -done +echo "child_process: hello, world!" +echo "child_process: hello, people!" +sleep .15 diff --git a/test/units/dml-discard-empty.service b/test/units/dml-discard-empty.service index 720c1da..c176989 100644 --- a/test/units/dml-discard-empty.service +++ b/test/units/dml-discard-empty.service @@ -5,4 +5,4 @@ Description=DML discard empty service [Service] Slice=dml-discard.slice Type=oneshot -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/dml-discard-set-ml.service b/test/units/dml-discard-set-ml.service index 93246ac..0fba2ac 100644 --- a/test/units/dml-discard-set-ml.service +++ b/test/units/dml-discard-set-ml.service @@ -5,5 +5,5 @@ Description=DML discard set ml service [Service] Slice=dml-discard.slice Type=oneshot -ExecStart=/bin/true +ExecStart=true MemoryLow=15 diff --git a/test/units/dml-override-empty.service b/test/units/dml-override-empty.service index ac96de0..5f0c143 100644 --- a/test/units/dml-override-empty.service +++ b/test/units/dml-override-empty.service @@ -5,4 +5,4 @@ Description=DML override empty service [Service] Slice=dml-override.slice Type=oneshot -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/dml-passthrough-empty.service b/test/units/dml-passthrough-empty.service index 1e1ba34..8966226 100644 --- a/test/units/dml-passthrough-empty.service +++ b/test/units/dml-passthrough-empty.service @@ -5,4 +5,4 @@ Description=DML passthrough empty service [Service] Slice=dml-passthrough.slice Type=oneshot -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/dml-passthrough-set-dml.service b/test/units/dml-passthrough-set-dml.service index 9a15311..ec82174 100644 --- a/test/units/dml-passthrough-set-dml.service +++ b/test/units/dml-passthrough-set-dml.service @@ -5,5 +5,5 @@ Description=DML passthrough set DML service [Service] Slice=dml-passthrough.slice Type=oneshot -ExecStart=/bin/true +ExecStart=true DefaultMemoryLow=15 diff --git a/test/units/dml-passthrough-set-ml.service b/test/units/dml-passthrough-set-ml.service index 65083bc..63ec305 100644 --- a/test/units/dml-passthrough-set-ml.service +++ b/test/units/dml-passthrough-set-ml.service @@ -5,5 +5,5 @@ Description=DML passthrough set ML service [Service] Slice=dml-passthrough.slice Type=oneshot -ExecStart=/bin/true +ExecStart=true MemoryLow=0 diff --git a/test/units/e.service b/test/units/e.service index 5bbcde2..c2acb92 100644 --- a/test/units/e.service +++ b/test/units/e.service @@ -6,4 +6,4 @@ Before=a.service Wants=a.service [Service] -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/end.sh b/test/units/end.sh index 230b716..cc1d7ee 100755 --- a/test/units/end.sh +++ b/test/units/end.sh @@ -4,10 +4,14 @@ set -eux set -o pipefail -(! journalctl -q -o short-monotonic --grep "didn't pass validation" >>/failed) +(! journalctl -q -o short-monotonic --grep "didn't pass validation" | grep -v "test-varlink-idl" >>/failed) -# Here, the redundant '[.]' at the end is for making not the logged self command hit the grep. -(! journalctl -q -o short-monotonic --grep 'Attempted to close sd-bus after fork whose connection is opened before the fork, this should not happen[.]' >>/failed) +# Here, the redundant '[ ]' in the pattern is required in order not to match the logged command itself. +(! journalctl -q -o short-monotonic --grep 'Warning: cannot close sd-bus connection[ ].*after fork' >>/failed) + +# Check if sd-executor doesn't complain about not being able to (de)serialize stuff +(! journalctl -q -o short-monotonic --grep "[F]ailed to parse serialized line" >>/failed) +(! journalctl -q -o short-monotonic --grep "[F]ailed to (de)?serialize \w+" >>/failed) systemctl poweroff --no-block exit 0 diff --git a/test/units/f.service b/test/units/f.service index ca20053..a66043e 100644 --- a/test/units/f.service +++ b/test/units/f.service @@ -3,4 +3,4 @@ Description=F [Service] -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/g.service b/test/units/g.service index 5fd794d..bfb3d78 100644 --- a/test/units/g.service +++ b/test/units/g.service @@ -4,4 +4,4 @@ Description=G Conflicts=e.service [Service] -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/generator-utils.sh b/test/units/generator-utils.sh index fb62747..97a63d8 100755 --- a/test/units/generator-utils.sh +++ b/test/units/generator-utils.sh @@ -72,7 +72,7 @@ run_and_list() { ls -lR "$out_dir" if [[ -n "${environ:-}" ]]; then - umount /proc/1/environ + umount /proc/1/environ --lazy rm -f "$environ" fi } diff --git a/test/units/grandchild.service b/test/units/grandchild.service index 4fe77b4..bdccfe1 100644 --- a/test/units/grandchild.service +++ b/test/units/grandchild.service @@ -5,4 +5,4 @@ Description=Grandchild Service [Service] Slice=parent-deep.slice Type=oneshot -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/h.service b/test/units/h.service index 5361d42..1c4dbb4 100644 --- a/test/units/h.service +++ b/test/units/h.service @@ -4,4 +4,4 @@ Description=H Wants=g.service [Service] -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/i.service b/test/units/i.service index 2b5e821..783ac65 100644 --- a/test/units/i.service +++ b/test/units/i.service @@ -6,4 +6,4 @@ Wants=b.service After=b.service [Service] -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/loopy.service b/test/units/loopy.service index 7fc0e42..4c1a4a3 100644 --- a/test/units/loopy.service +++ b/test/units/loopy.service @@ -1,3 +1,3 @@ # SPDX-License-Identifier: LGPL-2.1-or-later [Service] -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/loopy2.service b/test/units/loopy2.service index 7fc0e42..4c1a4a3 100644 --- a/test/units/loopy2.service +++ b/test/units/loopy2.service @@ -1,3 +1,3 @@ # SPDX-License-Identifier: LGPL-2.1-or-later [Service] -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/loopy3.service b/test/units/loopy3.service index b2af20a..f7a2f67 100644 --- a/test/units/loopy3.service +++ b/test/units/loopy3.service @@ -1,6 +1,6 @@ # SPDX-License-Identifier: LGPL-2.1-or-later [Service] -ExecStart=/bin/true +ExecStart=true [Unit] Conflicts=loopy4.service diff --git a/test/units/loopy4.service b/test/units/loopy4.service index b2af20a..f7a2f67 100644 --- a/test/units/loopy4.service +++ b/test/units/loopy4.service @@ -1,6 +1,6 @@ # SPDX-License-Identifier: LGPL-2.1-or-later [Service] -ExecStart=/bin/true +ExecStart=true [Unit] Conflicts=loopy4.service diff --git a/test/units/nomemleaf.service b/test/units/nomemleaf.service index 14ce5ad..2e5c8ce 100644 --- a/test/units/nomemleaf.service +++ b/test/units/nomemleaf.service @@ -5,6 +5,6 @@ Description=Nomem Leaf Service [Service] Slice=nomem.slice Type=oneshot -ExecStart=/bin/true +ExecStart=true IOWeight=200 MemoryAccounting=true diff --git a/test/units/sched_idle_bad.service b/test/units/sched_idle_bad.service index be8f1c2..d9fd6cc 100644 --- a/test/units/sched_idle_bad.service +++ b/test/units/sched_idle_bad.service @@ -3,5 +3,5 @@ Description=Bad sched priority for Idle [Service] -ExecStart=/bin/true +ExecStart=true CPUSchedulingPriority=1 diff --git a/test/units/sched_idle_ok.service b/test/units/sched_idle_ok.service index 5a1d809..a7238ed 100644 --- a/test/units/sched_idle_ok.service +++ b/test/units/sched_idle_ok.service @@ -3,5 +3,5 @@ Description=Sched idle with prio 0 [Service] -ExecStart=/bin/true +ExecStart=true CPUSchedulingPriority=0 diff --git a/test/units/sched_rr_bad.service b/test/units/sched_rr_bad.service index b51b868..3f3bf39 100644 --- a/test/units/sched_rr_bad.service +++ b/test/units/sched_rr_bad.service @@ -3,7 +3,7 @@ Description=Bad sched priority for RR [Service] -ExecStart=/bin/true +ExecStart=true CPUSchedulingPriority=-1 CPUSchedulingPriority=100 CPUSchedulingPolicy=rr diff --git a/test/units/sched_rr_change.service b/test/units/sched_rr_change.service index 6ae1feb..3a72bd6 100644 --- a/test/units/sched_rr_change.service +++ b/test/units/sched_rr_change.service @@ -3,7 +3,7 @@ Description=Change prio [Service] -ExecStart=/bin/true +ExecStart=true CPUSchedulingPriority=1 CPUSchedulingPriority=2 CPUSchedulingPriority=99 diff --git a/test/units/sched_rr_ok.service b/test/units/sched_rr_ok.service index 00b9822..5c71f30 100644 --- a/test/units/sched_rr_ok.service +++ b/test/units/sched_rr_ok.service @@ -3,5 +3,5 @@ Description=Default prio for RR [Service] -ExecStart=/bin/true +ExecStart=true CPUSchedulingPolicy=rr diff --git a/test/units/son.service b/test/units/son.service index 2059118..0242509 100644 --- a/test/units/son.service +++ b/test/units/son.service @@ -5,5 +5,5 @@ Description=Son Service [Service] Slice=parent.slice Type=oneshot -ExecStart=/bin/true +ExecStart=true CPUShares=100 diff --git a/test/units/test-control.sh b/test/units/test-control.sh index 0a1611b..4cede74 100644 --- a/test/units/test-control.sh +++ b/test/units/test-control.sh @@ -107,7 +107,7 @@ run_subtests_with_signals() { _show_summary } -# Run all subtests (i.e. files named as testsuite-<testid>.<subtest_name>.sh) +# Run all subtests (i.e. files named as $TESTNAME.<subtest_name>.sh) run_subtests() { local subtests=("${0%.sh}".*.sh) local subtest diff --git a/test/units/testsuite-01.service b/test/units/testsuite-01.service deleted file mode 100644 index 9074e09..0000000 --- a/test/units/testsuite-01.service +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-01-BASIC -After=multi-user.target -Wants=systemd-resolved.service systemd-networkd.service - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-02.service b/test/units/testsuite-02.service deleted file mode 100644 index dea2c4f..0000000 --- a/test/units/testsuite-02.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-02-UNITTESTS - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-02.sh b/test/units/testsuite-02.sh deleted file mode 100755 index 2a3cb08..0000000 --- a/test/units/testsuite-02.sh +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later -set -eux -set -o pipefail - -if ! systemd-detect-virt -qc && [[ "${TEST_CMDLINE_NEWLINE:-}" != bar ]]; then - cat /proc/cmdline - echo >&2 "Expected TEST_CMDLINE_NEWLINE=bar from the kernel command line" - exit 1 -fi - -# If we're running with TEST_PREFER_NSPAWN=1 limit the set of tests we run -# in QEMU to only those that can't run in a container to avoid running -# the same tests again in a, most likely, very slow environment -if ! systemd-detect-virt -qc && [[ "${TEST_PREFER_NSPAWN:-0}" -ne 0 ]]; then - TESTS_GLOB="test-loop-block" -else - TESTS_GLOB=${TESTS_GLOB:-test-*} -fi - -NPROC=$(nproc) -MAX_QUEUE_SIZE=${NPROC:-2} -mapfile -t TEST_LIST < <(find /usr/lib/systemd/tests/unit-tests/ -maxdepth 1 -type f -name "${TESTS_GLOB}") - -# Reset state -rm -fv /failed /skipped /testok - -if ! systemd-detect-virt -qc; then - # Make sure ping works for unprivileged users (for test-bpf-firewall) - sysctl net.ipv4.ping_group_range="0 2147483647" -fi - -# Check & report test results -# Arguments: -# $1: test path -# $2: test exit code -report_result() { - if [[ $# -ne 2 ]]; then - echo >&2 "check_result: missing arguments" - exit 1 - fi - - local name="${1##*/}" - local ret=$2 - - if [[ $ret -ne 0 && $ret != 77 && $ret != 127 ]]; then - echo "$name failed with $ret" - echo "$name" >>/failed-tests - { - echo "--- $name begin ---" - cat "/$name.log" - echo "--- $name end ---" - } >>/failed - elif [[ $ret == 77 || $ret == 127 ]]; then - echo "$name skipped" - echo "$name" >>/skipped-tests - { - echo "--- $name begin ---" - cat "/$name.log" - echo "--- $name end ---" - } >>/skipped - else - echo "$name OK" - echo "$name" >>/testok - fi -} - -set +x -# Associative array for running tasks, where running[test-path]=PID -declare -A running=() -for task in "${TEST_LIST[@]}"; do - # If there's MAX_QUEUE_SIZE running tasks, keep checking the running queue - # until one of the tasks finishes, so we can replace it. - while [[ ${#running[@]} -ge $MAX_QUEUE_SIZE ]]; do - for key in "${!running[@]}"; do - if ! kill -0 "${running[$key]}" &>/dev/null; then - # Task has finished, report its result and drop it from the queue - wait "${running[$key]}" && ec=0 || ec=$? - report_result "$key" "$ec" - unset "running[$key]" - # Break from inner for loop and outer while loop to skip - # the sleep below when we find a free slot in the queue - break 2 - fi - done - - # Precisely* calculated constant to keep the spinlock from burning the CPU(s) - sleep 0.01 - done - - if [[ -x $task ]]; then - echo "Executing test '$task'" - log_file="/${task##*/}.log" - $task &>"$log_file" & - running[$task]=$! - fi -done - -# Wait for remaining running tasks -for key in "${!running[@]}"; do - echo "Waiting for test '$key' to finish" - wait "${running[$key]}" && ec=0 || ec=$? - report_result "$key" "$ec" - unset "running[$key]" -done - -set -x - -# Test logs are sometimes lost, as the system shuts down immediately after -journalctl --sync - -test ! -s /failed -touch /testok diff --git a/test/units/testsuite-03.service b/test/units/testsuite-03.service deleted file mode 100644 index 836f962..0000000 --- a/test/units/testsuite-03.service +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-03-JOBS -After=multi-user.target - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-04.LogFilterPatterns.sh b/test/units/testsuite-04.LogFilterPatterns.sh deleted file mode 100755 index 2192e84..0000000 --- a/test/units/testsuite-04.LogFilterPatterns.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later -set -eux -set -o pipefail - -# This fails due to https://github.com/systemd/systemd/issues/30886 -# but it is too complex and risky to backport, so disable the test -exit 0 - -# shellcheck source=test/units/util.sh - . "$(dirname "$0")"/util.sh - -add_logs_filtering_override() { - local unit="${1:?}" - local override_name="${2:?}" - local log_filter="${3:-}" - - mkdir -p "/run/systemd/system/$unit.d/" - echo -ne "[Service]\nLogFilterPatterns=$log_filter" >"/run/systemd/system/$unit.d/$override_name.conf" - systemctl daemon-reload -} - -run_service_and_fetch_logs() { - local unit="${1:?}" - local start end - - start="$(date '+%Y-%m-%d %T.%6N')" - systemctl restart "$unit" - sleep .5 - journalctl --sync - end="$(date '+%Y-%m-%d %T.%6N')" - - journalctl -q -u "$unit" -S "$start" -U "$end" -p notice - systemctl stop "$unit" -} - -if cgroupfs_supports_user_xattrs; then - # Accept all log messages - add_logs_filtering_override "logs-filtering.service" "00-reset" "" - [[ -n $(run_service_and_fetch_logs "logs-filtering.service") ]] - - add_logs_filtering_override "logs-filtering.service" "01-allow-all" ".*" - [[ -n $(run_service_and_fetch_logs "logs-filtering.service") ]] - - # Discard all log messages - add_logs_filtering_override "logs-filtering.service" "02-discard-all" "~.*" - [[ -z $(run_service_and_fetch_logs "logs-filtering.service") ]] - - # Accept all test messages - add_logs_filtering_override "logs-filtering.service" "03-reset" "" - [[ -n $(run_service_and_fetch_logs "logs-filtering.service") ]] - - # Discard all test messages - add_logs_filtering_override "logs-filtering.service" "04-discard-gg" "~.*gg.*" - [[ -z $(run_service_and_fetch_logs "logs-filtering.service") ]] - - # Deny filter takes precedence - add_logs_filtering_override "logs-filtering.service" "05-allow-all-but-too-late" ".*" - [[ -z $(run_service_and_fetch_logs "logs-filtering.service") ]] - - # Use tilde in a deny pattern - add_logs_filtering_override "logs-filtering.service" "06-reset" "" - add_logs_filtering_override "logs-filtering.service" "07-prevent-tilde" "~~more~" - [[ -z $(run_service_and_fetch_logs "logs-filtering.service") ]] - - # Only allow a pattern that won't be matched - add_logs_filtering_override "logs-filtering.service" "08-reset" "" - add_logs_filtering_override "logs-filtering.service" "09-allow-only-non-existing" "non-existing string" - [[ -z $(run_service_and_fetch_logs "logs-filtering.service") ]] - - # Allow a pattern starting with a tilde - add_logs_filtering_override "logs-filtering.service" "10-allow-with-escape-char" "\\\\x7emore~" - [[ -n $(run_service_and_fetch_logs "logs-filtering.service") ]] - - add_logs_filtering_override "logs-filtering.service" "11-reset" "" - add_logs_filtering_override "logs-filtering.service" "12-allow-with-spaces" "foo bar" - [[ -n $(run_service_and_fetch_logs "logs-filtering.service") ]] - - add_logs_filtering_override "delegated-cgroup-filtering.service" "00-allow-all" ".*" - [[ -n $(run_service_and_fetch_logs "delegated-cgroup-filtering.service") ]] - - add_logs_filtering_override "delegated-cgroup-filtering.service" "01-discard-hello" "~hello" - [[ -z $(run_service_and_fetch_logs "delegated-cgroup-filtering.service") ]] - - rm -rf /run/systemd/system/{logs-filtering,delegated-cgroup-filtering}.service.d -fi diff --git a/test/units/testsuite-04.journal-gatewayd.sh b/test/units/testsuite-04.journal-gatewayd.sh deleted file mode 100755 index 5755ef1..0000000 --- a/test/units/testsuite-04.journal-gatewayd.sh +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later -set -eux -# pipefail is disabled intentionally, as `curl | grep -q` is very SIGPIPE happy - -if [[ ! -x /usr/lib/systemd/systemd-journal-gatewayd ]]; then - echo "Built without systemd-journal-gatewayd support, skipping the test" - exit 0 -fi - -TEST_MESSAGE="-= This is a test message $RANDOM =-" -TEST_TAG="$(systemd-id128 new)" - -echo "$TEST_MESSAGE" | systemd-cat -t "$TEST_TAG" -journalctl --sync -TEST_CURSOR="$(journalctl -q -t "$TEST_TAG" -n 0 --show-cursor | awk '{ print $3; }')" -BOOT_CURSOR="$(journalctl -q -b -n 0 --show-cursor | awk '{ print $3; }')" - -/usr/lib/systemd/systemd-journal-gatewayd --version -/usr/lib/systemd/systemd-journal-gatewayd --help - -# Default configuration (HTTP, socket activated) -systemctl start systemd-journal-gatewayd.socket - -# /browse -# We should get redirected to /browse by default -curl -Lfs http://localhost:19531 | grep -qF "<title>Journal</title>" -curl -Lfs http://localhost:19531/browse | grep -qF "<title>Journal</title>" -(! curl -Lfs http://localhost:19531/foo/bar/baz) -(! curl -Lfs http://localhost:19531/foo/../../../bar/../baz) - -# /entries -# Accept: text/plain should be the default -curl -Lfs http://localhost:19531/entries | \ - grep -qE " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" -curl -Lfs --header "Accept: text/plain" http://localhost:19531/entries | \ - grep -qE " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" -curl -Lfs --header "Accept: application/json" http://localhost:19531/entries | \ - jq -se ".[] | select(.MESSAGE == \"$TEST_MESSAGE\")" -curl -Lfs --header "Accept: application/json" http://localhost:19531/entries?boot | \ - jq -se ".[] | select(.MESSAGE == \"$TEST_MESSAGE\")" -curl -Lfs --header "Accept: application/json" http://localhost:19531/entries?SYSLOG_IDENTIFIER="$TEST_TAG" | \ - jq -se "length == 1 and select(.[].MESSAGE == \"$TEST_MESSAGE\")" -# Show 10 entries starting from $BOOT_CURSOR, skip the first 5 -curl -Lfs --header "Accept: application/json" --header "Range: entries=$BOOT_CURSOR:5:10" http://localhost:19531/entries | \ - jq -se "length == 10" -# Check if the specified cursor refers to an existing entry and return just that entry -curl -Lfs --header "Accept: application/json" --header "Range: entries=$TEST_CURSOR" http://localhost:19531/entries?discrete | \ - jq -se "length == 1 and select(.[].MESSAGE == \"$TEST_MESSAGE\")" -# No idea how to properly parse this (jq won't cut it), so let's at least do some sanity checks that every -# line is either empty or begins with data: -curl -Lfs --header "Accept: text/event-stream" http://localhost:19531/entries | \ - awk '!/^(data: \{.+\}|)$/ { exit 1; }' -# Same thing as journalctl --output=export -mkdir /tmp/remote-journal -curl -Lfs --header "Accept: application/vnd.fdo.journal" http://localhost:19531/entries | \ - /usr/lib/systemd/systemd-journal-remote --output=/tmp/remote-journal/system.journal --split-mode=none - -journalctl --directory=/tmp/remote-journal -t "$TEST_TAG" --grep "$TEST_MESSAGE" -rm -rf /tmp/remote-journal/* -# Let's do the same thing again, but let systemd-journal-remote spawn curl itself -/usr/lib/systemd/systemd-journal-remote --url=http://localhost:19531/entries \ - --output=/tmp/remote-journal/system.journal \ - --split-mode=none -journalctl --directory=/tmp/remote-journal -t "$TEST_TAG" --grep "$TEST_MESSAGE" -rm -rf /tmp/remote-journal - -# /machine -curl -Lfs http://localhost:19531/machine | jq - -# /fields -curl -Lfs http://localhost:19531/fields/MESSAGE | grep -qE -- "$TEST_MESSAGE" -curl -Lfs http://localhost:19531/fields/_TRANSPORT -(! curl -Lfs http://localhost:19531/fields) -(! curl -Lfs http://localhost:19531/fields/foo-bar-baz) - -systemctl stop systemd-journal-gatewayd.{socket,service} - -if ! command -v openssl >/dev/null; then - echo "openssl command not available, skipping the HTTPS tests" - exit 0 -fi - -# Generate a self-signed certificate for systemd-journal-gatewayd -# -# Note: older OpenSSL requires a config file with some extra options, unfortunately -cat >/tmp/openssl.conf <<EOF -[ req ] -prompt = no -distinguished_name = req_distinguished_name - -[ req_distinguished_name ] -C = CZ -L = Brno -O = Foo -OU = Bar -CN = localhost -EOF -openssl req -x509 -nodes -newkey rsa:2048 -sha256 -days 7 \ - -config /tmp/openssl.conf \ - -keyout /tmp/key.pem -out /tmp/cert.pem -# Start HTTPS version of gatewayd via the systemd-socket-activate tool to give it some coverage as well -systemd-socket-activate --listen=19531 -- \ - /usr/lib/systemd/systemd-journal-gatewayd \ - --cert=/tmp/cert.pem \ - --key=/tmp/key.pem \ - --file="/var/log/journal/*/*.journal" & -GATEWAYD_PID=$! -sleep 1 - -# Do a limited set of tests, since the underlying code should be the same past the HTTPS transport -curl -Lfsk https://localhost:19531 | grep -qF "<title>Journal</title>" -curl -Lfsk https://localhost:19531/entries | \ - grep -qE " $TEST_TAG\[[0-9]+\]: $TEST_MESSAGE" -curl -Lfsk --header "Accept: application/json" https://localhost:19531/entries | \ - jq -se ".[] | select(.MESSAGE == \"$TEST_MESSAGE\")" -curl -Lfsk https://localhost:19531/machine | jq -curl -Lfsk https://localhost:19531/fields/_TRANSPORT - -kill "$GATEWAYD_PID" diff --git a/test/units/testsuite-04.service b/test/units/testsuite-04.service deleted file mode 100644 index 63a0104..0000000 --- a/test/units/testsuite-04.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-04-JOURNAL - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-05.service b/test/units/testsuite-05.service deleted file mode 100644 index ab72d8f..0000000 --- a/test/units/testsuite-05.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-05-RLIMITS - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-06.service b/test/units/testsuite-06.service deleted file mode 100644 index c4c1d87..0000000 --- a/test/units/testsuite-06.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-06-SELINUX - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-08.service b/test/units/testsuite-08.service deleted file mode 100644 index 2db35cf..0000000 --- a/test/units/testsuite-08.service +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-08-INITRD -After=multi-user.target - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-09.service b/test/units/testsuite-09.service deleted file mode 100644 index 6c957ec..0000000 --- a/test/units/testsuite-09.service +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-09-REBOOT -After=multi-user.target - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-13.service b/test/units/testsuite-13.service deleted file mode 100644 index 95c9a02..0000000 --- a/test/units/testsuite-13.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-13-NSPAWN - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-15.service b/test/units/testsuite-15.service deleted file mode 100644 index 10af93f..0000000 --- a/test/units/testsuite-15.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-15-DROPIN - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-17.03.sh b/test/units/testsuite-17.03.sh deleted file mode 100755 index 56e352e..0000000 --- a/test/units/testsuite-17.03.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later -set -ex - -TEST_RULE="/run/udev/rules.d/49-test.rules" -KILL_PID= - -setup() { - mkdir -p "${TEST_RULE%/*}" - [[ -e /etc/udev/udev.conf ]] && cp -f /etc/udev/udev.conf /etc/udev/udev.conf.bak - # Don't bother storing the coredumps in journal for this particular test - mkdir -p /run/systemd/coredump.conf.d/ - echo -ne "[Coredump]\nStorage=external\n" >/run/systemd/coredump.conf.d/99-storage-journal.conf - - cat >"${TEST_RULE}" <<EOF -ACTION=="add", SUBSYSTEM=="mem", KERNEL=="null", OPTIONS="log_level=debug" -ACTION=="add", SUBSYSTEM=="mem", KERNEL=="null", PROGRAM=="/bin/sleep 60" -EOF - cat >/etc/udev/udev.conf <<EOF -event_timeout=10 -timeout_signal=SIGABRT -EOF - - systemctl restart systemd-udevd.service -} - -# shellcheck disable=SC2317 -teardown() { - set +e - - if [[ -n "$KILL_PID" ]]; then - kill "$KILL_PID" - fi - - rm -rf "$TMPDIR" - rm -f "$TEST_RULE" - [[ -e /etc/udev/udev.conf.bak ]] && mv -f /etc/udev/udev.conf.bak /etc/udev/udev.conf - rm /run/systemd/coredump.conf.d/99-storage-journal.conf - systemctl restart systemd-udevd.service -} - -run_test() { - local since - - since="$(date '+%F %T')" - - TMPDIR=$(mktemp -d -p /tmp udev-tests.XXXXXX) - udevadm monitor --udev --property --subsystem-match=mem >"$TMPDIR"/monitor.txt & - KILL_PID="$!" - - SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --action add /dev/null - - for _ in {1..40}; do - if coredumpctl --since "$since" --no-legend --no-pager | grep /bin/udevadm ; then - kill "$KILL_PID" - KILL_PID= - - cat "$TMPDIR"/monitor.txt - grep -q 'UDEV_WORKER_FAILED=1' "$TMPDIR"/monitor.txt - grep -q 'UDEV_WORKER_SIGNAL=6' "$TMPDIR"/monitor.txt - grep -q 'UDEV_WORKER_SIGNAL_NAME=ABRT' "$TMPDIR"/monitor.txt - return 0 - fi - sleep .5 - done - - return 1 -} - -trap teardown EXIT - -setup -run_test - -exit 0 diff --git a/test/units/testsuite-17.service b/test/units/testsuite-17.service deleted file mode 100644 index d218d72..0000000 --- a/test/units/testsuite-17.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-17-UDEV - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-18.service b/test/units/testsuite-18.service deleted file mode 100644 index 16d90a1..0000000 --- a/test/units/testsuite-18.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-18-FAILUREACTION - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-19.service b/test/units/testsuite-19.service deleted file mode 100644 index 9ee5fc9..0000000 --- a/test/units/testsuite-19.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-19-DELEGATE - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-21.service b/test/units/testsuite-21.service deleted file mode 100644 index a5f77d0..0000000 --- a/test/units/testsuite-21.service +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=Fuzz our D-Bus interfaces with dfuzzer -After=dbus.service multi-user.target -Wants=dbus.service multi-user.target - -[Service] -ExecStartPre=rm -f /failed /skipped /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-22.service b/test/units/testsuite-22.service deleted file mode 100644 index a5ed660..0000000 --- a/test/units/testsuite-22.service +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-22-TMPFILES -After=systemd-tmpfiles-setup.service -Before=getty-pre.target -Wants=getty-pre.target - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-23-short-lived.sh b/test/units/testsuite-23-short-lived.sh deleted file mode 100755 index 4a12c7f..0000000 --- a/test/units/testsuite-23-short-lived.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later -set -ex - -if [ -f /tmp/testsuite-23.counter ] ; then - read -r counter < /tmp/testsuite-23.counter - counter=$((counter + 1)) -else - counter=0 -fi - -echo "$counter" >/tmp/testsuite-23.counter - -if [ "$counter" -eq 5 ] ; then - systemctl kill --kill-whom=main -sUSR1 testsuite-23.service -fi - -exec sleep 1.5 diff --git a/test/units/testsuite-23.JoinsNamespaceOf.sh b/test/units/testsuite-23.JoinsNamespaceOf.sh deleted file mode 100755 index 68ba465..0000000 --- a/test/units/testsuite-23.JoinsNamespaceOf.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later - -set -eux -set -o pipefail - -# Test JoinsNamespaceOf= with PrivateTmp=yes - -systemd-analyze log-level debug -systemd-analyze log-target journal - -# simple case -systemctl start testsuite-23-joins-namespace-of-1.service -systemctl start testsuite-23-joins-namespace-of-2.service -systemctl start testsuite-23-joins-namespace-of-3.service -systemctl stop testsuite-23-joins-namespace-of-1.service - -# inverse dependency -systemctl start testsuite-23-joins-namespace-of-4.service -systemctl start testsuite-23-joins-namespace-of-5.service -systemctl stop testsuite-23-joins-namespace-of-4.service - -# transitive dependency -systemctl start testsuite-23-joins-namespace-of-6.service -systemctl start testsuite-23-joins-namespace-of-7.service -systemctl start testsuite-23-joins-namespace-of-8.service -systemctl start testsuite-23-joins-namespace-of-9.service -systemctl stop testsuite-23-joins-namespace-of-6.service -systemctl stop testsuite-23-joins-namespace-of-8.service - -systemd-analyze log-level info diff --git a/test/units/testsuite-23.Upholds.sh b/test/units/testsuite-23.Upholds.sh deleted file mode 100755 index e62f9c6..0000000 --- a/test/units/testsuite-23.Upholds.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later - -set -eux -set -o pipefail - -# Test OnSuccess= + Uphold= + PropagatesStopTo= + BindsTo= - -systemd-analyze log-level debug -systemd-analyze log-target journal - -# Idea is this: -# 1. we start testsuite-23-success.service -# 2. which through OnSuccess= starts testsuite-23-fail.service, -# 3. which through OnFailure= starts testsuite-23-uphold.service, -# 4. which through Uphold= starts/keeps testsuite-23-short-lived.service running, -# 5. which will sleep 1s when invoked, and on the 5th invocation send us a SIGUSR1 -# 6. once we got that we finish cleanly - -sigusr1=0 -trap sigusr1=1 SIGUSR1 - -trap -p SIGUSR1 - -systemctl start testsuite-23-success.service - -while [ "$sigusr1" -eq 0 ] ; do - sleep .5 -done - -systemctl stop testsuite-23-uphold.service - -systemctl enable testsuite-23-upheldby-install.service - -# Idea is this: -# 1. we start testsuite-23-retry-uphold.service -# 2. which through Uphold= starts testsuite-23-retry-upheld.service -# 3. which through Requires= starts testsuite-23-retry-fail.service -# 4. which fails as /tmp/testsuite-23-retry-fail does not exist, so testsuite-23-retry-upheld.service -# is no longer restarted -# 5. we create /tmp/testsuite-23-retry-fail -# 6. now testsuite-23-retry-upheld.service will be restarted since upheld, and its dependency will -# be satisfied - -rm -f /tmp/testsuite-23-retry-fail -systemctl start testsuite-23-retry-uphold.service -systemctl is-active testsuite-23-upheldby-install.service - -until systemctl is-failed testsuite-23-retry-fail.service ; do - sleep .5 -done - -(! systemctl is-active testsuite-23-retry-upheld.service) - -touch /tmp/testsuite-23-retry-fail - -until systemctl is-active testsuite-23-retry-upheld.service ; do - sleep .5 -done - -systemctl stop testsuite-23-retry-uphold.service testsuite-23-retry-fail.service testsuite-23-retry-upheld.service - -# Idea is this: -# 1. we start testsuite-23-prop-stop-one.service -# 2. which through Wants=/After= pulls in testsuite-23-prop-stop-two.service as well -# 3. testsuite-23-prop-stop-one.service then sleeps indefinitely -# 4. testsuite-23-prop-stop-two.service sleeps a short time and exits -# 5. the StopPropagatedFrom= dependency between the two should ensure *both* will exit as result -# 6. an ExecStopPost= line on testsuite-23-prop-stop-one.service will send us a SIGUSR2 -# 7. once we got that we finish cleanly - -sigusr2=0 -trap sigusr2=1 SIGUSR2 - -systemctl start testsuite-23-prop-stop-one.service - -while [ "$sigusr2" -eq 0 ] ; do - sleep .5 -done - - -# Idea is this: -# 1. we start testsuite-23-binds-to.service -# 2. which through BindsTo=/After= pulls in testsuite-23-bound-by.service as well -# 3. testsuite-23-bound-by.service suddenly dies -# 4. testsuite-23-binds-to.service should then also be pulled down (it otherwise just hangs) -# 6. an ExecStopPost= line on testsuite-23-binds-to.service will send us a SIGRTMIN1+1 -# 7. once we got that we finish cleanly - -sigrtmin1=0 -trap sigrtmin1=1 SIGRTMIN+1 - -systemctl start testsuite-23-binds-to.service - -while [ "$sigrtmin1" -eq 0 ] ; do - sleep .5 -done - -systemd-analyze log-level info diff --git a/test/units/testsuite-23.oneshot-restart.sh b/test/units/testsuite-23.oneshot-restart.sh deleted file mode 100755 index 433cd69..0000000 --- a/test/units/testsuite-23.oneshot-restart.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later -set -eux -set -o pipefail - -# Test oneshot unit restart on failure - -# wait this many secs for each test service to succeed in what is being tested -MAX_SECS=60 - -systemd-analyze log-level debug - -# test one: Restart=on-failure should restart the service -(! systemd-run --unit=oneshot-restart-one -p Type=oneshot -p Restart=on-failure /bin/bash -c "exit 1") - -for ((secs = 0; secs < MAX_SECS; secs++)); do - [[ "$(systemctl show oneshot-restart-one.service -P NRestarts)" -le 0 ]] || break - sleep 1 -done -if [[ "$(systemctl show oneshot-restart-one.service -P NRestarts)" -le 0 ]]; then - exit 1 -fi - -TMP_FILE="/tmp/test-41-oneshot-restart-test" - -: >$TMP_FILE - -# test two: make sure StartLimitBurst correctly limits the number of restarts -# and restarts execution of the unit from the first ExecStart= -(! systemd-run --unit=oneshot-restart-two \ - -p StartLimitIntervalSec=120 \ - -p StartLimitBurst=3 \ - -p Type=oneshot \ - -p Restart=on-failure \ - -p ExecStart="/bin/bash -c \"printf a >>$TMP_FILE\"" /bin/bash -c "exit 1") - -# wait for at least 3 restarts -for ((secs = 0; secs < MAX_SECS; secs++)); do - [[ $(cat $TMP_FILE) != "aaa" ]] || break - sleep 1 -done -if [[ $(cat $TMP_FILE) != "aaa" ]]; then - exit 1 -fi - -# wait for 5 more seconds to make sure there aren't excess restarts -sleep 5 -if [[ $(cat $TMP_FILE) != "aaa" ]]; then - exit 1 -fi - -systemd-analyze log-level info diff --git a/test/units/testsuite-23.runtime-bind-paths.sh b/test/units/testsuite-23.runtime-bind-paths.sh deleted file mode 100755 index 65c2dbf..0000000 --- a/test/units/testsuite-23.runtime-bind-paths.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later -# shellcheck disable=SC2016 -set -eux -set -o pipefail - -# Test adding new BindPaths while unit is already running - -at_exit() { - set +e - - rm -f /run/testsuite-23-marker-{fixed,runtime} - rm -fr /run/inaccessible -} - -trap at_exit EXIT - -echo "MARKER_FIXED" >/run/testsuite-23-marker-fixed -mkdir /run/inaccessible - -systemctl start testsuite-23-namespaced.service - -# Ensure that inaccessible paths aren't bypassed by the runtime setup, -(! systemctl bind --mkdir testsuite-23-namespaced.service /run/testsuite-23-marker-fixed /run/inaccessible/testfile-marker-fixed) - -echo "MARKER_WRONG" >/run/testsuite-23-marker-wrong -echo "MARKER_RUNTIME" >/run/testsuite-23-marker-runtime - -# Mount twice to exercise mount-beneath (on kernel 6.5+, on older kernels it will just overmount) -systemctl bind --mkdir testsuite-23-namespaced.service /run/testsuite-23-marker-wrong /tmp/testfile-marker-runtime -test "$(systemctl show -P SubState testsuite-23-namespaced.service)" = "running" -systemctl bind --mkdir testsuite-23-namespaced.service /run/testsuite-23-marker-runtime /tmp/testfile-marker-runtime - -timeout 10 bash -xec 'while [[ "$(systemctl show -P SubState testsuite-23-namespaced.service)" == running ]]; do sleep .5; done' -systemctl is-active testsuite-23-namespaced.service - -# Now test that systemctl bind fails when attempted on a non-namespaced unit -systemctl start testsuite-23-non-namespaced.service - -(! systemctl bind --mkdir testsuite-49-non-namespaced.service /run/testsuite-23-marker-runtime /tmp/testfile-marker-runtime) - -timeout 10 bash -xec 'while [[ "$(systemctl show -P SubState testsuite-23-non-namespaced.service)" == running ]]; do sleep .5; done' -(! systemctl is-active testsuite-23-non-namespaced.service) diff --git a/test/units/testsuite-23.service b/test/units/testsuite-23.service deleted file mode 100644 index 26f5226..0000000 --- a/test/units/testsuite-23.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-23-TYPE-EXEC - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-23.start-stop-no-reload.sh b/test/units/testsuite-23.start-stop-no-reload.sh deleted file mode 100755 index 9c4f17d..0000000 --- a/test/units/testsuite-23.start-stop-no-reload.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later -# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- -# ex: ts=8 sw=4 sts=4 et filetype=sh -set -eux -set -o pipefail - -# Test start & stop operations without daemon-reload - -at_exit() { - set +e - - rm -f /run/systemd/system/testsuite-23-no-reload.{service,target} -} - -trap at_exit EXIT - -cat >/run/systemd/system/testsuite-23-no-reload.target <<EOF -[Unit] -Wants=testsuite-23-no-reload.service -EOF - -systemctl daemon-reload - -systemctl start testsuite-23-no-reload.target - -# The filesystem on the test image, despite being ext4, seems to have a mtime -# granularity of one second, which means the manager's unit cache won't be -# marked as dirty when writing the unit file, unless we wait at least a full -# second after the previous daemon-reload. -# May 07 23:12:20 H testsuite-48.sh[30]: + cat -# May 07 23:12:20 H testsuite-48.sh[30]: + ls -l --full-time /etc/systemd/system/testsuite-23-no-reload.service -# May 07 23:12:20 H testsuite-48.sh[52]: -rw-r--r-- 1 root root 50 2020-05-07 23:12:20.000000000 +0100 / -# May 07 23:12:20 H testsuite-48.sh[30]: + stat -f --format=%t /etc/systemd/system/testsuite-23-no-reload.servic -# May 07 23:12:20 H testsuite-48.sh[53]: ef53 -sleep 3.1 - -cat >/run/systemd/system/testsuite-23-no-reload.service <<EOF -[Service] -ExecStart=/bin/sleep infinity -EOF - -systemctl start testsuite-23-no-reload.service - -systemctl is-active testsuite-23-no-reload.service - -# Stop and remove, and try again to exercise https://github.com/systemd/systemd/issues/15992 -systemctl stop testsuite-23-no-reload.service -rm -f /run/systemd/system/testsuite-23-no-reload.service -systemctl daemon-reload - -sleep 3.1 - -cat >/run/systemd/system/testsuite-23-no-reload.service <<EOF -[Service] -ExecStart=/bin/sleep infinity -EOF - -# Start a non-existing unit first, so that the cache is reloaded for an unrelated -# reason. Starting the existing unit later should still work thanks to the check -# for the last load attempt vs cache timestamp. -systemctl start testsuite-23-no-reload-nonexistent.service || true - -systemctl start testsuite-23-no-reload.service - -systemctl is-active testsuite-23-no-reload.service - -# Stop and remove, and try again to exercise the transaction setup code path by -# having the target pull in the unloaded but available unit -systemctl stop testsuite-23-no-reload.service testsuite-23-no-reload.target -rm -f /run/systemd/system/testsuite-23-no-reload.service /run/systemd/system/testsuite-23-no-reload.target -systemctl daemon-reload - -sleep 3.1 - -cat >/run/systemd/system/testsuite-23-no-reload.target <<EOF -[Unit] -Conflicts=shutdown.target -Wants=testsuite-23-no-reload.service -EOF - -systemctl daemon-reload - -systemctl start testsuite-23-no-reload.target - -cat >/run/systemd/system/testsuite-23-no-reload.service <<EOF -[Service] -ExecStart=/bin/sleep infinity -EOF - -systemctl restart testsuite-23-no-reload.target - -systemctl is-active testsuite-23-no-reload.service diff --git a/test/units/testsuite-24.service b/test/units/testsuite-24.service deleted file mode 100644 index e192d1c..0000000 --- a/test/units/testsuite-24.service +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-24-CRYPTSETUP -After=multi-user.target - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-25.service b/test/units/testsuite-25.service deleted file mode 100644 index 503eabb..0000000 --- a/test/units/testsuite-25.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-25-IMPORT - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-26.service b/test/units/testsuite-26.service deleted file mode 100644 index d8fdaff..0000000 --- a/test/units/testsuite-26.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-26-SYSTEMCTL - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-29.service b/test/units/testsuite-29.service deleted file mode 100644 index 035c6bf..0000000 --- a/test/units/testsuite-29.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-29-PORTABLE - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-30.service b/test/units/testsuite-30.service deleted file mode 100644 index 253f7b5..0000000 --- a/test/units/testsuite-30.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-30-ONCLOCKCHANGE - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-31.service b/test/units/testsuite-31.service deleted file mode 100644 index f0e78a9..0000000 --- a/test/units/testsuite-31.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-31-DEVICE-ENUMERATION - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-32.service b/test/units/testsuite-32.service deleted file mode 100644 index 50f5823..0000000 --- a/test/units/testsuite-32.service +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-32-OOMPOLICY - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot -MemoryAccounting=yes diff --git a/test/units/testsuite-34.service b/test/units/testsuite-34.service deleted file mode 100644 index 6917afe..0000000 --- a/test/units/testsuite-34.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-34-DYNAMICUSERMIGRATE - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-35.service b/test/units/testsuite-35.service deleted file mode 100644 index 0599f61..0000000 --- a/test/units/testsuite-35.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-35-LOGIN - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-36.service b/test/units/testsuite-36.service deleted file mode 100644 index 5746dc1..0000000 --- a/test/units/testsuite-36.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-36-NUMAPOLICY - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-38.service b/test/units/testsuite-38.service deleted file mode 100644 index ac77836..0000000 --- a/test/units/testsuite-38.service +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-38-FREEZER - -[Service] -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-43.service b/test/units/testsuite-43.service deleted file mode 100644 index e36afea..0000000 --- a/test/units/testsuite-43.service +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-43-PRIVATEUSER-UNPRIV -After=systemd-logind.service user@4711.service -Wants=user@4711.service - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-44.service b/test/units/testsuite-44.service deleted file mode 100644 index 4dffdea..0000000 --- a/test/units/testsuite-44.service +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TESTSUITE-44-LOG-NAMESPACE -Before=getty-pre.target -Wants=getty-pre.target -Wants=systemd-journald@foobar.socket systemd-journald-varlink@foobar.socket -After=systemd-journald@foobar.socket systemd-journald-varlink@foobar.socket - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-45.service b/test/units/testsuite-45.service deleted file mode 100644 index b16ce99..0000000 --- a/test/units/testsuite-45.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-45-TIMEDATE - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-46.service b/test/units/testsuite-46.service deleted file mode 100644 index 5efb9cc..0000000 --- a/test/units/testsuite-46.service +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-46-HOMED -Wants=getty-pre.target -Before=getty-pre.target -Requires=systemd-homed.service systemd-userdbd.socket -After=systemd-homed.service systemd-userdbd.socket - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot -NotifyAccess=all diff --git a/test/units/testsuite-46.sh b/test/units/testsuite-46.sh deleted file mode 100755 index a77683b..0000000 --- a/test/units/testsuite-46.sh +++ /dev/null @@ -1,319 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later -set -eux -set -o pipefail - -# Check if homectl is installed, and if it isn't bail out early instead of failing -if ! test -x /usr/bin/homectl ; then - echo "no homed" >/skipped - exit 0 -fi - -inspect() { - # As updating disk-size-related attributes can take some time on some - # filesystems, let's drop these fields before comparing the outputs to - # avoid unexpected fails. To see the full outputs of both homectl & - # userdbctl (for debugging purposes) drop the fields just before the - # comparison. - local USERNAME="${1:?}" - homectl inspect "$USERNAME" | tee /tmp/a - userdbctl user "$USERNAME" | tee /tmp/b - - # diff uses the grep BREs for pattern matching - diff -I '^\s*Disk \(Size\|Free\|Floor\|Ceiling\):' /tmp/{a,b} - rm /tmp/{a,b} - - homectl inspect --json=pretty "$USERNAME" -} - -wait_for_state() { - for i in {1..10}; do - (( i > 1 )) && sleep 0.5 - homectl inspect "$1" | grep -qF "State: $2" && break - done -} - -systemd-analyze log-level debug -systemctl service-log-level systemd-homed debug - -# Create a tmpfs to use as backing store for the home dir. That way we can enforce a size limit nicely. -mkdir -p /home -mount -t tmpfs tmpfs /home -o size=290M - -# we enable --luks-discard= since we run our tests in a tight VM, hence don't -# needlessly pressure for storage. We also set the cheapest KDF, since we don't -# want to waste CI CPU cycles on it. -NEWPASSWORD=xEhErW0ndafV4s homectl create test-user \ - --disk-size=min \ - --luks-discard=yes \ - --image-path=/home/test-user.home \ - --luks-pbkdf-type=pbkdf2 \ - --luks-pbkdf-time-cost=1ms -inspect test-user - -PASSWORD=xEhErW0ndafV4s homectl authenticate test-user - -PASSWORD=xEhErW0ndafV4s homectl activate test-user -inspect test-user - -PASSWORD=xEhErW0ndafV4s homectl update test-user --real-name="Inline test" -inspect test-user - -homectl deactivate test-user -inspect test-user - -PASSWORD=xEhErW0ndafV4s NEWPASSWORD=yPN4N0fYNKUkOq homectl passwd test-user -inspect test-user - -PASSWORD=yPN4N0fYNKUkOq homectl activate test-user -inspect test-user - -SYSTEMD_LOG_LEVEL=debug PASSWORD=yPN4N0fYNKUkOq NEWPASSWORD=xEhErW0ndafV4s homectl passwd test-user -inspect test-user - -homectl deactivate test-user -inspect test-user - -PASSWORD=xEhErW0ndafV4s homectl activate test-user -inspect test-user - -homectl deactivate test-user -inspect test-user - -PASSWORD=xEhErW0ndafV4s homectl update test-user --real-name="Offline test" -inspect test-user - -PASSWORD=xEhErW0ndafV4s homectl activate test-user -inspect test-user - -homectl deactivate test-user -inspect test-user - -# Do some resize tests, but only if we run on real kernels, as quota inside of containers will fail -if ! systemd-detect-virt -cq ; then - # grow while inactive - PASSWORD=xEhErW0ndafV4s homectl resize test-user 300M - inspect test-user - - # minimize while inactive - PASSWORD=xEhErW0ndafV4s homectl resize test-user min - inspect test-user - - PASSWORD=xEhErW0ndafV4s homectl activate test-user - inspect test-user - - # grow while active - PASSWORD=xEhErW0ndafV4s homectl resize test-user max - inspect test-user - - # minimize while active - PASSWORD=xEhErW0ndafV4s homectl resize test-user 0 - inspect test-user - - # grow while active - PASSWORD=xEhErW0ndafV4s homectl resize test-user 300M - inspect test-user - - # shrink to original size while active - PASSWORD=xEhErW0ndafV4s homectl resize test-user 256M - inspect test-user - - # minimize again - PASSWORD=xEhErW0ndafV4s homectl resize test-user min - inspect test-user - - # Increase space, so that we can reasonably rebalance free space between to home dirs - mount /home -o remount,size=800M - - # create second user - NEWPASSWORD=uuXoo8ei homectl create test-user2 \ - --disk-size=min \ - --luks-discard=yes \ - --image-path=/home/test-user2.home \ - --luks-pbkdf-type=pbkdf2 \ - --luks-pbkdf-time-cost=1ms - inspect test-user2 - - # activate second user - PASSWORD=uuXoo8ei homectl activate test-user2 - inspect test-user2 - - # set second user's rebalance weight to 100 - PASSWORD=uuXoo8ei homectl update test-user2 --rebalance-weight=100 - inspect test-user2 - - # set first user's rebalance weight to quarter of that of the second - PASSWORD=xEhErW0ndafV4s homectl update test-user --rebalance-weight=25 - inspect test-user - - # synchronously rebalance - homectl rebalance - inspect test-user - inspect test-user2 -fi - -PASSWORD=xEhErW0ndafV4s homectl with test-user -- test ! -f /home/test-user/xyz -(! PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz) -PASSWORD=xEhErW0ndafV4s homectl with test-user -- touch /home/test-user/xyz -PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz -PASSWORD=xEhErW0ndafV4s homectl with test-user -- rm /home/test-user/xyz -PASSWORD=xEhErW0ndafV4s homectl with test-user -- test ! -f /home/test-user/xyz -(! PASSWORD=xEhErW0ndafV4s homectl with test-user -- test -f /home/test-user/xyz) - -wait_for_state test-user inactive -homectl remove test-user - -if ! systemd-detect-virt -cq ; then - wait_for_state test-user2 active - homectl deactivate test-user2 - wait_for_state test-user2 inactive - homectl remove test-user2 -fi - -# userdbctl tests -export PAGER= - -# Create a couple of user/group records to test io.systemd.DropIn -# See docs/USER_RECORD.md and docs/GROUP_RECORD.md -mkdir -p /run/userdb/ -cat >"/run/userdb/dropingroup.group" <<\EOF -{ - "groupName" : "dropingroup", - "gid" : 1000000 -} -EOF -cat >"/run/userdb/dropinuser.user" <<\EOF -{ - "userName" : "dropinuser", - "uid" : 2000000, - "realName" : "🐱", - "memberOf" : [ - "dropingroup" - ] -} -EOF -cat >"/run/userdb/dropinuser.user-privileged" <<\EOF -{ - "privileged" : { - "hashedPassword" : [ - "$6$WHBKvAFFT9jKPA4k$OPY4D4TczKN/jOnJzy54DDuOOagCcvxxybrwMbe1SVdm.Bbr.zOmBdATp.QrwZmvqyr8/SafbbQu.QZ2rRvDs/" - ], - "sshAuthorizedKeys" : [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA//dxI2xLg4MgxIKKZv1nqwTEIlE/fdakii2Fb75pG+ foo@bar.tld", - "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMlaqG2rTMje5CQnfjXJKmoSpEVJ2gWtx4jBvsQbmee2XbU/Qdq5+SRisssR9zVuxgg5NA5fv08MgjwJQMm+csc= hello@world.tld" - ] - } -} -EOF -# Set permissions and create necessary symlinks as described in nss-systemd(8) -chmod 0600 "/run/userdb/dropinuser.user-privileged" -ln -svrf "/run/userdb/dropingroup.group" "/run/userdb/1000000.group" -ln -svrf "/run/userdb/dropinuser.user" "/run/userdb/2000000.user" -ln -svrf "/run/userdb/dropinuser.user-privileged" "/run/userdb/2000000.user-privileged" - -userdbctl -userdbctl --version -userdbctl --help --no-pager -userdbctl --no-legend -userdbctl --output=classic -userdbctl --output=friendly -userdbctl --output=table -userdbctl --output=json | jq -userdbctl -j --json=pretty | jq -userdbctl -j --json=short | jq -userdbctl --with-varlink=no - -userdbctl user -userdbctl user testuser -userdbctl user root -userdbctl user testuser root -userdbctl user -j testuser root | jq -# Check only UID for the nobody user, since the name is build-configurable -userdbctl user --with-nss=no --synthesize=yes -userdbctl user --with-nss=no --synthesize=yes 0 root 65534 -userdbctl user dropinuser -userdbctl user 2000000 -userdbctl user --with-nss=no --with-varlink=no --synthesize=no --multiplexer=no dropinuser -userdbctl user --with-nss=no 2000000 -(! userdbctl user '') -(! userdbctl user 🐱) -(! userdbctl user 🐱 '' bar) -(! userdbctl user i-do-not-exist) -(! userdbctl user root i-do-not-exist testuser) -(! userdbctl user --with-nss=no --synthesize=no 0 root 65534) -(! userdbctl user -N root nobody) -(! userdbctl user --with-dropin=no dropinuser) -(! userdbctl user --with-dropin=no 2000000) - -userdbctl group -userdbctl group testuser -userdbctl group root -userdbctl group testuser root -userdbctl group -j testuser root | jq -# Check only GID for the nobody group, since the name is build-configurable -userdbctl group --with-nss=no --synthesize=yes -userdbctl group --with-nss=no --synthesize=yes 0 root 65534 -userdbctl group dropingroup -userdbctl group 1000000 -userdbctl group --with-nss=no --with-varlink=no --synthesize=no --multiplexer=no dropingroup -userdbctl group --with-nss=no 1000000 -(! userdbctl group '') -(! userdbctl group 🐱) -(! userdbctl group 🐱 '' bar) -(! userdbctl group i-do-not-exist) -(! userdbctl group root i-do-not-exist testuser) -(! userdbctl group --with-nss=no --synthesize=no 0 root 65534) -(! userdbctl group --with-dropin=no dropingroup) -(! userdbctl group --with-dropin=no 1000000) - -userdbctl users-in-group -userdbctl users-in-group testuser -userdbctl users-in-group testuser root -userdbctl users-in-group -j testuser root | jq -userdbctl users-in-group 🐱 -(! userdbctl users-in-group '') -(! userdbctl users-in-group foo '' bar) - -userdbctl groups-of-user -userdbctl groups-of-user testuser -userdbctl groups-of-user testuser root -userdbctl groups-of-user -j testuser root | jq -userdbctl groups-of-user 🐱 -(! userdbctl groups-of-user '') -(! userdbctl groups-of-user foo '' bar) - -userdbctl services -userdbctl services -j | jq - -varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"testuser","service":"io.systemd.Multiplexer"}' -varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"root","service":"io.systemd.Multiplexer"}' -varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"dropinuser","service":"io.systemd.Multiplexer"}' -varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"uid":2000000,"service":"io.systemd.Multiplexer"}' -(! varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"","service":"io.systemd.Multiplexer"}') -(! varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"🐱","service":"io.systemd.Multiplexer"}') -(! varlinkctl call /run/systemd/userdb/io.systemd.Multiplexer io.systemd.UserDatabase.GetUserRecord '{"userName":"i-do-not-exist","service":"io.systemd.Multiplexer"}') - -userdbctl ssh-authorized-keys dropinuser | tee /tmp/authorized-keys -grep "ssh-ed25519" /tmp/authorized-keys -grep "ecdsa-sha2-nistp256" /tmp/authorized-keys -echo "my-top-secret-key 🐱" >/tmp/my-top-secret-key -userdbctl ssh-authorized-keys dropinuser --chain /bin/cat /tmp/my-top-secret-key | tee /tmp/authorized-keys -grep "ssh-ed25519" /tmp/authorized-keys -grep "ecdsa-sha2-nistp256" /tmp/authorized-keys -grep "my-top-secret-key 🐱" /tmp/authorized-keys -(! userdbctl ssh-authorized-keys 🐱) -(! userdbctl ssh-authorized-keys dropin-user --chain) -(! userdbctl ssh-authorized-keys dropin-user --chain '') -(! SYSTEMD_LOG_LEVEL=debug userdbctl ssh-authorized-keys dropin-user --chain /bin/false) - -(! userdbctl '') -for opt in json multiplexer output synthesize with-dropin with-nss with-varlink; do - (! userdbctl "--$opt=''") - (! userdbctl "--$opt='🐱'") - (! userdbctl "--$opt=foo") - (! userdbctl "--$opt=foo" "--$opt=''" "--$opt=🐱") -done - -systemd-analyze log-level info - -touch /testok diff --git a/test/units/testsuite-50.service b/test/units/testsuite-50.service deleted file mode 100644 index bcafe6e..0000000 --- a/test/units/testsuite-50.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-50-DISSECT - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-50.sh b/test/units/testsuite-50.sh deleted file mode 100755 index 3726b32..0000000 --- a/test/units/testsuite-50.sh +++ /dev/null @@ -1,718 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later -# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- -# ex: ts=8 sw=4 sts=4 et filetype=sh -# shellcheck disable=SC2233,SC2235 -set -eux -set -o pipefail - -export SYSTEMD_LOG_LEVEL=debug - -# shellcheck disable=SC2317 -cleanup() {( - set +ex - - if [ -z "${image_dir}" ]; then - return - fi - umount "${image_dir}/app0" - umount "${image_dir}/app1" - umount "${image_dir}/app-nodistro" - umount "${image_dir}/service-scoped-test" - rm -rf "${image_dir}" -)} - -udevadm control --log-level=debug - -cd /tmp - -image_dir="$(mktemp -d -t -p /tmp tmp.XXXXXX)" -if [ -z "${image_dir}" ] || [ ! -d "${image_dir}" ]; then - echo "mktemp under /tmp failed" - exit 1 -fi - -trap cleanup EXIT - -cp /usr/share/minimal* "${image_dir}/" -image="${image_dir}/minimal_0" -roothash="$(cat "${image}.roothash")" - -os_release="$(test -e /etc/os-release && echo /etc/os-release || echo /usr/lib/os-release)" - -systemd-dissect --json=short "${image}.raw" | grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"' -systemd-dissect "${image}.raw" | grep -q -F "MARKER=1" -systemd-dissect "${image}.raw" | grep -q -F -f <(sed 's/"//g' "$os_release") - -systemd-dissect --list "${image}.raw" | grep -q '^etc/os-release$' -systemd-dissect --mtree "${image}.raw" --mtree-hash yes | grep -qe "^./usr/bin/cat type=file mode=0755 uid=0 gid=0 size=[0-9]* sha256sum=[a-z0-9]*$" -systemd-dissect --mtree "${image}.raw" --mtree-hash no | grep -qe "^./usr/bin/cat type=file mode=0755 uid=0 gid=0 size=[0-9]*$" - -read -r SHA256SUM1 _ < <(systemd-dissect --copy-from "${image}.raw" etc/os-release | sha256sum) -test "$SHA256SUM1" != "" -read -r SHA256SUM2 _ < <(systemd-dissect --read-only --with "${image}.raw" sha256sum etc/os-release) -test "$SHA256SUM2" != "" -test "$SHA256SUM1" = "$SHA256SUM2" - -mv "${image}.verity" "${image}.fooverity" -mv "${image}.roothash" "${image}.foohash" -systemd-dissect --json=short "${image}.raw" --root-hash="${roothash}" --verity-data="${image}.fooverity" | grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"' -systemd-dissect "${image}.raw" --root-hash="${roothash}" --verity-data="${image}.fooverity" | grep -q -F "MARKER=1" -systemd-dissect "${image}.raw" --root-hash="${roothash}" --verity-data="${image}.fooverity" | grep -q -F -f <(sed 's/"//g' "$os_release") -mv "${image}.fooverity" "${image}.verity" -mv "${image}.foohash" "${image}.roothash" - -mkdir -p "${image_dir}/mount" "${image_dir}/mount2" -systemd-dissect --mount "${image}.raw" "${image_dir}/mount" -grep -q -F -f "$os_release" "${image_dir}/mount/usr/lib/os-release" -grep -q -F -f "$os_release" "${image_dir}/mount/etc/os-release" -grep -q -F "MARKER=1" "${image_dir}/mount/usr/lib/os-release" -# Verity volume should be shared (opened only once) -systemd-dissect --mount "${image}.raw" "${image_dir}/mount2" -verity_count=$(find /dev/mapper/ -name "*verity*" | wc -l) -# In theory we should check that count is exactly one. In practice, libdevmapper -# randomly and unpredictably fails with an unhelpful EINVAL when a device is open -# (and even mounted and in use), so best-effort is the most we can do for now -if [ "${verity_count}" -lt 1 ]; then - echo "Verity device ${image}.raw not found in /dev/mapper/" - exit 1 -fi -systemd-dissect --umount "${image_dir}/mount" -systemd-dissect --umount "${image_dir}/mount2" - -systemd-run -P -p RootImage="${image}.raw" cat /usr/lib/os-release | grep -q -F "MARKER=1" -mv "${image}.verity" "${image}.fooverity" -mv "${image}.roothash" "${image}.foohash" -systemd-run -P -p RootImage="${image}.raw" -p RootHash="${image}.foohash" -p RootVerity="${image}.fooverity" cat /usr/lib/os-release | grep -q -F "MARKER=1" -# Let's use the long option name just here as a test -systemd-run -P --property RootImage="${image}.raw" --property RootHash="${roothash}" --property RootVerity="${image}.fooverity" cat /usr/lib/os-release | grep -q -F "MARKER=1" -mv "${image}.fooverity" "${image}.verity" -mv "${image}.foohash" "${image}.roothash" - -# Make a GPT disk on the fly, with the squashfs as partition 1 and the verity hash tree as partition 2 -machine="$(uname -m)" -if [ "${machine}" = "x86_64" ]; then - root_guid=4f68bce3-e8cd-4db1-96e7-fbcaf984b709 - verity_guid=2c7357ed-ebd2-46d9-aec1-23d437ec2bf5 - signature_guid=41092b05-9fc8-4523-994f-2def0408b176 - architecture="x86-64" -elif [ "${machine}" = "i386" ] || [ "${machine}" = "i686" ] || [ "${machine}" = "x86" ]; then - root_guid=44479540-f297-41b2-9af7-d131d5f0458a - verity_guid=d13c5d3b-b5d1-422a-b29f-9454fdc89d76 - signature_guid=5996fc05-109c-48de-808b-23fa0830b676 - architecture="x86" -elif [ "${machine}" = "aarch64" ] || [ "${machine}" = "aarch64_be" ] || [ "${machine}" = "armv8b" ] || [ "${machine}" = "armv8l" ]; then - root_guid=b921b045-1df0-41c3-af44-4c6f280d3fae - verity_guid=df3300ce-d69f-4c92-978c-9bfb0f38d820 - signature_guid=6db69de6-29f4-4758-a7a5-962190f00ce3 - architecture="arm64" -elif [ "${machine}" = "arm" ]; then - root_guid=69dad710-2ce4-4e3c-b16c-21a1d49abed3 - verity_guid=7386cdf2-203c-47a9-a498-f2ecce45a2d6 - signature_guid=42b0455f-eb11-491d-98d3-56145ba9d037 - architecture="arm" -elif [ "${machine}" = "loongarch64" ]; then - root_guid=77055800-792c-4f94-b39a-98c91b762bb6 - verity_guid=f3393b22-e9af-4613-a948-9d3bfbd0c535 - signature_guid=5afb67eb-ecc8-4f85-ae8e-ac1e7c50e7d0 - architecture="loongarch64" -elif [ "${machine}" = "ia64" ]; then - root_guid=993d8d3d-f80e-4225-855a-9daf8ed7ea97 - verity_guid=86ed10d5-b607-45bb-8957-d350f23d0571 - signature_guid=e98b36ee-32ba-4882-9b12-0ce14655f46a - architecture="ia64" -elif [ "${machine}" = "s390x" ]; then - root_guid=5eead9a9-fe09-4a1e-a1d7-520d00531306 - verity_guid=b325bfbe-c7be-4ab8-8357-139e652d2f6b - signature_guid=c80187a5-73a3-491a-901a-017c3fa953e9 - architecture="s390x" -elif [ "${machine}" = "ppc64le" ]; then - root_guid=c31c45e6-3f39-412e-80fb-4809c4980599 - verity_guid=906bd944-4589-4aae-a4e4-dd983917446a - signature_guid=d4a236e7-e873-4c07-bf1d-bf6cf7f1c3c6 - architecture="ppc64-le" -else - echo "Unexpected uname -m: ${machine} in testsuite-50.sh, please fix me" - exit 1 -fi -# du rounds up to block size, which is more helpful for partitioning -root_size="$(du -k "${image}.raw" | cut -f1)" -verity_size="$(du -k "${image}.verity" | cut -f1)" -signature_size=4 -# 4MB seems to be the minimum size blkid will accept, below that probing fails -dd if=/dev/zero of="${image}.gpt" bs=512 count=$((8192+root_size*2+verity_size*2+signature_size*2)) -# sfdisk seems unhappy if the size overflows into the next unit, eg: 1580KiB will be interpreted as 1MiB -# so do some basic rounding up if the minimal image is more than 1 MB -if [ "${root_size}" -ge 1024 ]; then - root_size="$((root_size/1024 + 1))MiB" -else - root_size="${root_size}KiB" -fi -verity_size="$((verity_size * 2))KiB" -signature_size="$((signature_size * 2))KiB" - -HAVE_OPENSSL=0 -if systemctl --version | grep -q -- +OPENSSL ; then - # The openssl binary is installed conditionally. - # If we have OpenSSL support enabled and openssl is missing, fail early - # with a proper error message. - if ! command -v openssl >/dev/null 2>&1; then - echo "openssl missing" >/failed - exit 1 - fi - - HAVE_OPENSSL=1 - OPENSSL_CONFIG="$(mktemp)" - # Unfortunately OpenSSL insists on reading some config file, hence provide one with mostly placeholder contents - cat >"${OPENSSL_CONFIG:?}" <<EOF -[ req ] -prompt = no -distinguished_name = req_distinguished_name - -[ req_distinguished_name ] -C = DE -ST = Test State -L = Test Locality -O = Org Name -OU = Org Unit Name -CN = Common Name -emailAddress = test@email.com -EOF - - # Create key pair - openssl req -config "$OPENSSL_CONFIG" -new -x509 -newkey rsa:1024 -keyout "${image}.key" -out "${image}.crt" -days 365 -nodes - # Sign Verity root hash with it - openssl smime -sign -nocerts -noattr -binary -in "${image}.roothash" -inkey "${image}.key" -signer "${image}.crt" -outform der -out "${image}.roothash.p7s" - # Generate signature partition JSON data - echo '{"rootHash":"'"${roothash}"'","signature":"'"$(base64 -w 0 <"${image}.roothash.p7s")"'"}' >"${image}.verity-sig" - # Pad it - truncate -s "${signature_size}" "${image}.verity-sig" - # Register certificate in the (userspace) verity key ring - mkdir -p /run/verity.d - ln -s "${image}.crt" /run/verity.d/ok.crt -fi - -# Construct a UUID from hash -# input: 11111111222233334444555566667777 -# output: 11111111-2222-3333-4444-555566667777 -uuid="$(head -c 32 "${image}.roothash" | sed -r 's/(.{8})(.{4})(.{4})(.{4})(.+)/\1-\2-\3-\4-\5/')" -echo -e "label: gpt\nsize=${root_size}, type=${root_guid}, uuid=${uuid}" | sfdisk "${image}.gpt" -uuid="$(tail -c 32 "${image}.roothash" | sed -r 's/(.{8})(.{4})(.{4})(.{4})(.+)/\1-\2-\3-\4-\5/')" -echo -e "size=${verity_size}, type=${verity_guid}, uuid=${uuid}" | sfdisk "${image}.gpt" --append -if [ "${HAVE_OPENSSL}" -eq 1 ]; then - echo -e "size=${signature_size}, type=${signature_guid}" | sfdisk "${image}.gpt" --append -fi -sfdisk --part-label "${image}.gpt" 1 "Root Partition" -sfdisk --part-label "${image}.gpt" 2 "Verity Partition" -if [ "${HAVE_OPENSSL}" -eq 1 ]; then - sfdisk --part-label "${image}.gpt" 3 "Signature Partition" -fi -loop="$(losetup --show -P -f "${image}.gpt")" -partitions=( - "${loop:?}p1" - "${loop:?}p2" -) -if [ "${HAVE_OPENSSL}" -eq 1 ]; then - partitions+=( "${loop:?}p3" ) -fi -# The kernel sometimes(?) does not emit "add" uevent for loop block partition devices. -# Let's not expect the devices to be initialized. -udevadm wait --timeout 60 --settle --initialized=no "${partitions[@]}" -udevadm lock --device="${loop}p1" dd if="${image}.raw" of="${loop}p1" -udevadm lock --device="${loop}p2" dd if="${image}.verity" of="${loop}p2" -if [ "${HAVE_OPENSSL}" -eq 1 ]; then - udevadm lock --device="${loop}p3" dd if="${image}.verity-sig" of="${loop}p3" -fi -losetup -d "${loop}" - -# Derive partition UUIDs from root hash, in UUID syntax -ROOT_UUID="$(systemd-id128 -u show "$(head -c 32 "${image}.roothash")" -u | tail -n 1 | cut -b 6-)" -VERITY_UUID="$(systemd-id128 -u show "$(tail -c 32 "${image}.roothash")" -u | tail -n 1 | cut -b 6-)" - -systemd-dissect --json=short --root-hash "${roothash}" "${image}.gpt" | grep -q '{"rw":"ro","designator":"root","partition_uuid":"'"$ROOT_UUID"'","partition_label":"Root Partition","fstype":"squashfs","architecture":"'"$architecture"'","verity":"signed",' -systemd-dissect --json=short --root-hash "${roothash}" "${image}.gpt" | grep -q '{"rw":"ro","designator":"root-verity","partition_uuid":"'"$VERITY_UUID"'","partition_label":"Verity Partition","fstype":"DM_verity_hash","architecture":"'"$architecture"'","verity":null,' -if [ "${HAVE_OPENSSL}" -eq 1 ]; then - systemd-dissect --json=short --root-hash "${roothash}" "${image}.gpt" | grep -q -E '{"rw":"ro","designator":"root-verity-sig","partition_uuid":"'".*"'","partition_label":"Signature Partition","fstype":"verity_hash_signature","architecture":"'"$architecture"'","verity":null,' -fi -systemd-dissect --root-hash "${roothash}" "${image}.gpt" | grep -q -F "MARKER=1" -systemd-dissect --root-hash "${roothash}" "${image}.gpt" | grep -q -F -f <(sed 's/"//g' "$os_release") - -# Test image policies -systemd-dissect --validate "${image}.gpt" -systemd-dissect --validate "${image}.gpt" --image-policy='*' -(! systemd-dissect --validate "${image}.gpt" --image-policy='~') -(! systemd-dissect --validate "${image}.gpt" --image-policy='-') -(! systemd-dissect --validate "${image}.gpt" --image-policy=root=absent) -(! systemd-dissect --validate "${image}.gpt" --image-policy=swap=unprotected+encrypted+verity) -systemd-dissect --validate "${image}.gpt" --image-policy=root=unprotected -systemd-dissect --validate "${image}.gpt" --image-policy=root=verity -systemd-dissect --validate "${image}.gpt" --image-policy=root=verity:root-verity-sig=unused+absent -systemd-dissect --validate "${image}.gpt" --image-policy=root=verity:swap=absent -systemd-dissect --validate "${image}.gpt" --image-policy=root=verity:swap=absent+unprotected -(! systemd-dissect --validate "${image}.gpt" --image-policy=root=verity:root-verity=unused+absent) -systemd-dissect --validate "${image}.gpt" --image-policy=root=signed -(! systemd-dissect --validate "${image}.gpt" --image-policy=root=signed:root-verity-sig=unused+absent) -(! systemd-dissect --validate "${image}.gpt" --image-policy=root=signed:root-verity=unused+absent) - -# Test RootImagePolicy= unit file setting -systemd-run --wait -P -p RootImage="${image}.gpt" -p RootHash="${roothash}" -p MountAPIVFS=yes cat /usr/lib/os-release | grep -q -F "MARKER=1" -systemd-run --wait -P -p RootImage="${image}.gpt" -p RootHash="${roothash}" -p RootImagePolicy='*' -p MountAPIVFS=yes cat /usr/lib/os-release | grep -q -F "MARKER=1" -(! systemd-run --wait -P -p RootImage="${image}.gpt" -p RootHash="${roothash}" -p RootImagePolicy='~' -p MountAPIVFS=yes cat /usr/lib/os-release | grep -q -F "MARKER=1") -(! systemd-run --wait -P -p RootImage="${image}.gpt" -p RootHash="${roothash}" -p RootImagePolicy='-' -p MountAPIVFS=yes cat /usr/lib/os-release | grep -q -F "MARKER=1") -(! systemd-run --wait -P -p RootImage="${image}.gpt" -p RootHash="${roothash}" -p RootImagePolicy='root=absent' -p MountAPIVFS=yes cat /usr/lib/os-release | grep -q -F "MARKER=1") -systemd-run --wait -P -p RootImage="${image}.gpt" -p RootHash="${roothash}" -p RootImagePolicy='root=verity' -p MountAPIVFS=yes cat /usr/lib/os-release | grep -q -F "MARKER=1" -systemd-run --wait -P -p RootImage="${image}.gpt" -p RootHash="${roothash}" -p RootImagePolicy='root=signed' -p MountAPIVFS=yes cat /usr/lib/os-release | grep -q -F "MARKER=1" -(! systemd-run --wait -P -p RootImage="${image}.gpt" -p RootHash="${roothash}" -p RootImagePolicy='root=encrypted' -p MountAPIVFS=yes cat /usr/lib/os-release | grep -q -F "MARKER=1") - -systemd-dissect --root-hash "${roothash}" --mount "${image}.gpt" "${image_dir}/mount" -grep -q -F -f "$os_release" "${image_dir}/mount/usr/lib/os-release" -grep -q -F -f "$os_release" "${image_dir}/mount/etc/os-release" -grep -q -F "MARKER=1" "${image_dir}/mount/usr/lib/os-release" -systemd-dissect --umount "${image_dir}/mount" - -systemd-dissect --root-hash "${roothash}" --mount "${image}.gpt" --in-memory "${image_dir}/mount" -grep -q -F -f "$os_release" "${image_dir}/mount/usr/lib/os-release" -grep -q -F -f "$os_release" "${image_dir}/mount/etc/os-release" -grep -q -F "MARKER=1" "${image_dir}/mount/usr/lib/os-release" -systemd-dissect --umount "${image_dir}/mount" - -# add explicit -p MountAPIVFS=yes once to test the parser -systemd-run -P -p RootImage="${image}.gpt" -p RootHash="${roothash}" -p MountAPIVFS=yes cat /usr/lib/os-release | grep -q -F "MARKER=1" - -systemd-run -P -p RootImage="${image}.raw" -p RootImageOptions="root:nosuid,dev home:ro,dev ro,noatime" mount | grep -F "squashfs" | grep -q -F "nosuid" -systemd-run -P -p RootImage="${image}.gpt" -p RootImageOptions="root:ro,noatime root:ro,dev" mount | grep -F "squashfs" | grep -q -F "noatime" - -mkdir -p "${image_dir}/result" -cat >/run/systemd/system/testservice-50a.service <<EOF -[Service] -Type=oneshot -ExecStart=bash -c "mount >/run/result/a" -BindPaths=${image_dir}/result:/run/result -TemporaryFileSystem=/run -RootImage=${image}.raw -RootImageOptions=root:ro,noatime home:ro,dev relatime,dev -RootImageOptions=nosuid,dev -EOF -systemctl start testservice-50a.service -grep -F "squashfs" "${image_dir}/result/a" | grep -q -F "noatime" -grep -F "squashfs" "${image_dir}/result/a" | grep -q -F -v "nosuid" - -cat >/run/systemd/system/testservice-50b.service <<EOF -[Service] -Type=oneshot -ExecStart=bash -c "mount >/run/result/b" -BindPaths=${image_dir}/result:/run/result -TemporaryFileSystem=/run -RootImage=${image}.gpt -RootImageOptions=root:ro,noatime,nosuid home:ro,dev nosuid,dev -RootImageOptions=home:ro,dev nosuid,dev,%%foo -# this is the default, but let's specify once to test the parser -MountAPIVFS=yes -EOF -systemctl start testservice-50b.service -grep -F "squashfs" "${image_dir}/result/b" | grep -q -F "noatime" - -# Check that specifier escape is applied %%foo → %foo -busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/testservice_2d50b_2eservice org.freedesktop.systemd1.Service RootImageOptions | grep -F "nosuid,dev,%foo" - -# Now do some checks with MountImages, both by itself, with options and in combination with RootImage, and as single FS or GPT image -systemd-run -P -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1" -systemd-run -P -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1" -systemd-run -P -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2:nosuid,dev" mount | grep -F "squashfs" | grep -q -F "nosuid" -systemd-run -P -p MountImages="${image}.gpt:/run/img1:root:nosuid ${image}.raw:/run/img2:home:suid" mount | grep -F "squashfs" | grep -q -F "nosuid" -systemd-run -P -p MountImages="${image}.raw:/run/img2\:3" cat /run/img2:3/usr/lib/os-release | grep -q -F "MARKER=1" -systemd-run -P -p MountImages="${image}.raw:/run/img2\:3:nosuid" mount | grep -F "squashfs" | grep -q -F "nosuid" -systemd-run -P -p TemporaryFileSystem=/run -p RootImage="${image}.raw" -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /usr/lib/os-release | grep -q -F "MARKER=1" -systemd-run -P -p TemporaryFileSystem=/run -p RootImage="${image}.raw" -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1" -systemd-run -P -p TemporaryFileSystem=/run -p RootImage="${image}.gpt" -p RootHash="${roothash}" -p MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1" -cat >/run/systemd/system/testservice-50c.service <<EOF -[Service] -MountAPIVFS=yes -TemporaryFileSystem=/run -RootImage=${image}.raw -MountImages=${image}.gpt:/run/img1:root:noatime:home:relatime -MountImages=${image}.raw:/run/img2\:3:nosuid -ExecStart=bash -c "cat /run/img1/usr/lib/os-release >/run/result/c" -ExecStart=bash -c "cat /run/img2:3/usr/lib/os-release >>/run/result/c" -ExecStart=bash -c "mount >>/run/result/c" -BindPaths=${image_dir}/result:/run/result -Type=oneshot -EOF -systemctl start testservice-50c.service -grep -q -F "MARKER=1" "${image_dir}/result/c" -grep -F "squashfs" "${image_dir}/result/c" | grep -q -F "noatime" -grep -F "squashfs" "${image_dir}/result/c" | grep -q -F -v "nosuid" - -# Adding a new mounts at runtime works if the unit is in the active state, -# so use Type=notify to make sure there's no race condition in the test -cat >/run/systemd/system/testservice-50d.service <<EOF -[Service] -RuntimeMaxSec=300 -Type=notify -RemainAfterExit=yes -MountAPIVFS=yes -PrivateTmp=yes -ExecStart=/bin/sh -c ' \\ - systemd-notify --ready; \\ - while [ ! -f /tmp/img/usr/lib/os-release ] || ! grep -q -F MARKER /tmp/img/usr/lib/os-release; do \\ - sleep 0.1; \\ - done; \\ - mount; \\ - mount | grep -F "on /tmp/img type squashfs" | grep -q -F "nosuid"; \\ -' -EOF -systemctl start testservice-50d.service - -# Mount twice to exercise mount-beneath (on kernel 6.5+, on older kernels it will just overmount) -mkdir -p /tmp/wrong/foo -mksquashfs /tmp/wrong/foo /tmp/wrong.raw -systemctl mount-image --mkdir testservice-50d.service /tmp/wrong.raw /tmp/img -test "$(systemctl show -P SubState testservice-50d.service)" = "running" -systemctl mount-image --mkdir testservice-50d.service "${image}.raw" /tmp/img root:nosuid - -while systemctl show -P SubState testservice-50d.service | grep -q running -do - sleep 0.1 -done - -systemctl is-active testservice-50d.service - -# ExtensionImages will set up an overlay -systemd-run -P --property ExtensionImages=/usr/share/app0.raw --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0" -systemd-run -P --property ExtensionImages=/usr/share/app0.raw --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" -systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0" -systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" -systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /opt/script1.sh | grep -q -F "extension-release.app2" -systemd-run -P --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1" -systemd-run -P --property ExtensionImages=/usr/share/app-nodistro.raw --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" -systemd-run -P --property ExtensionImages=/etc/service-scoped-test.raw --property RootImage="${image}.raw" cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123" -# Check that using a symlink to NAME-VERSION.raw works as long as the symlink has the correct name NAME.raw -mkdir -p /usr/share/symlink-test/ -cp /usr/share/app-nodistro.raw /usr/share/symlink-test/app-nodistro-v1.raw -ln -fs /usr/share/symlink-test/app-nodistro-v1.raw /usr/share/symlink-test/app-nodistro.raw -systemd-run -P --property ExtensionImages=/usr/share/symlink-test/app-nodistro.raw --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" - -# Symlink check again but for confext -mkdir -p /etc/symlink-test/ -cp /etc/service-scoped-test.raw /etc/symlink-test/service-scoped-test-v1.raw -ln -fs /etc/symlink-test/service-scoped-test-v1.raw /etc/symlink-test/service-scoped-test.raw -systemd-run -P --property ExtensionImages=/etc/symlink-test/service-scoped-test.raw --property RootImage="${image}.raw" cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123" -# And again mixing sysext and confext -systemd-run -P \ - --property ExtensionImages=/usr/share/symlink-test/app-nodistro.raw \ - --property ExtensionImages=/etc/symlink-test/service-scoped-test.raw \ - --property RootImage="${image}.raw" cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123" -systemd-run -P \ - --property ExtensionImages=/usr/share/symlink-test/app-nodistro.raw \ - --property ExtensionImages=/etc/symlink-test/service-scoped-test.raw \ - --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" - -cat >/run/systemd/system/testservice-50e.service <<EOF -[Service] -MountAPIVFS=yes -TemporaryFileSystem=/run /var/lib -StateDirectory=app0 -RootImage=${image}.raw -ExtensionImages=/usr/share/app0.raw /usr/share/app1.raw:nosuid -# Relevant only for sanitizer runs -UnsetEnvironment=LD_PRELOAD -ExecStart=/bin/bash -c '/opt/script0.sh | grep ID' -ExecStart=/bin/bash -c '/opt/script1.sh | grep ID' -Type=oneshot -RemainAfterExit=yes -EOF -systemctl start testservice-50e.service -systemctl is-active testservice-50e.service - -# ExtensionDirectories will set up an overlay -mkdir -p "${image_dir}/app0" "${image_dir}/app1" "${image_dir}/app-nodistro" "${image_dir}/service-scoped-test" -(! systemd-run -P --property ExtensionDirectories="${image_dir}/nonexistent" --property RootImage="${image}.raw" cat /opt/script0.sh) -(! systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /opt/script0.sh) -systemd-dissect --mount /usr/share/app0.raw "${image_dir}/app0" -systemd-dissect --mount /usr/share/app1.raw "${image_dir}/app1" -systemd-dissect --mount /usr/share/app-nodistro.raw "${image_dir}/app-nodistro" -systemd-dissect --mount /etc/service-scoped-test.raw "${image_dir}/service-scoped-test" -systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0" -systemd-run -P --property ExtensionDirectories="${image_dir}/app0" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" -systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /opt/script0.sh | grep -q -F "extension-release.app0" -systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" -systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /opt/script1.sh | grep -q -F "extension-release.app2" -systemd-run -P --property ExtensionDirectories="${image_dir}/app0 ${image_dir}/app1" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1" -systemd-run -P --property ExtensionDirectories="${image_dir}/app-nodistro" --property RootImage="${image}.raw" cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1" -systemd-run -P --property ExtensionDirectories="${image_dir}/service-scoped-test" --property RootImage="${image}.raw" cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123" -cat >/run/systemd/system/testservice-50f.service <<EOF -[Service] -MountAPIVFS=yes -TemporaryFileSystem=/run /var/lib -StateDirectory=app0 -RootImage=${image}.raw -ExtensionDirectories=${image_dir}/app0 ${image_dir}/app1 -# Relevant only for sanitizer runs -UnsetEnvironment=LD_PRELOAD -ExecStart=/bin/bash -c '/opt/script0.sh | grep ID' -ExecStart=/bin/bash -c '/opt/script1.sh | grep ID' -Type=oneshot -RemainAfterExit=yes -EOF -systemctl start testservice-50f.service -systemctl is-active testservice-50f.service -systemd-dissect --umount "${image_dir}/app0" -systemd-dissect --umount "${image_dir}/app1" - -# Test that an extension consisting of an empty directory under /etc/extensions/ takes precedence -mkdir -p /var/lib/extensions/ -ln -s /usr/share/app-nodistro.raw /var/lib/extensions/app-nodistro.raw -systemd-sysext merge -grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file -systemd-sysext unmerge -mkdir -p /etc/extensions/app-nodistro -systemd-sysext merge -test ! -e /usr/lib/systemd/system/some_file -systemd-sysext unmerge -rmdir /etc/extensions/app-nodistro - -# Similar, but go via varlink -varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.List '{}' -(! grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file ) -varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.Merge '{}' -grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file -varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.Refresh '{}' -grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file -varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.Unmerge '{}' -(! grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file ) - -# Check that extensions cannot contain os-release -mkdir -p /run/extensions/app-reject/usr/lib/{extension-release.d/,systemd/system} -echo "ID=_any" >/run/extensions/app-reject/usr/lib/extension-release.d/extension-release.app-reject -echo "ID=_any" >/run/extensions/app-reject/usr/lib/os-release -touch /run/extensions/app-reject/usr/lib/systemd/system/other_file -(! systemd-sysext merge) -test ! -e /usr/lib/systemd/system/some_file -test ! -e /usr/lib/systemd/system/other_file -systemd-sysext unmerge -rm -rf /run/extensions/app-reject -rm /var/lib/extensions/app-nodistro.raw - -mkdir -p /run/machines /run/portables /run/extensions -touch /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw - -systemd-dissect --discover --json=short >/tmp/discover.json -grep -q -F '{"name":"a","type":"raw","class":"machine","ro":false,"path":"/run/machines/a.raw"' /tmp/discover.json -grep -q -F '{"name":"b","type":"raw","class":"portable","ro":false,"path":"/run/portables/b.raw"' /tmp/discover.json -grep -q -F '{"name":"c","type":"raw","class":"sysext","ro":false,"path":"/run/extensions/c.raw"' /tmp/discover.json -rm /tmp/discover.json /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw - -# Check that the /sbin/mount.ddi helper works -T="/tmp/mounthelper.$RANDOM" -mount -t ddi "${image}.gpt" "$T" -o ro,X-mount.mkdir,discard -umount -R "$T" -rmdir "$T" - -LOOP="$(systemd-dissect --attach --loop-ref=waldo "${image}.raw")" - -# Wait until the symlinks we want to test are established -udevadm trigger -w "$LOOP" - -# Check if the /dev/loop/* symlinks really reference the right device -test /dev/disk/by-loop-ref/waldo -ef "$LOOP" - -if [ "$(stat -c '%Hd:%Ld' "${image}.raw")" != '?d:?d' ] ; then - # Old stat didn't know the %Hd and %Ld specifiers and turned them into ?d - # instead. Let's simply skip the test on such old systems. - test "$(stat -c '/dev/disk/by-loop-inode/%Hd:%Ld-%i' "${image}.raw")" -ef "$LOOP" -fi - -# Detach by loopback device -systemd-dissect --detach "$LOOP" - -# Test long reference name. -# Note, sizeof_field(struct loop_info64, lo_file_name) == 64, -# and --loop-ref accepts upto 63 characters, and udev creates symlink -# based on the name when it has upto _62_ characters. -name="$(for _ in {1..62}; do echo -n 'x'; done)" -LOOP="$(systemd-dissect --attach --loop-ref="$name" "${image}.raw")" -udevadm trigger -w "$LOOP" - -# Check if the /dev/disk/by-loop-ref/$name symlink really references the right device -test "/dev/disk/by-loop-ref/$name" -ef "$LOOP" - -# Detach by the /dev/disk/by-loop-ref symlink -systemd-dissect --detach "/dev/disk/by-loop-ref/$name" - -name="$(for _ in {1..63}; do echo -n 'x'; done)" -LOOP="$(systemd-dissect --attach --loop-ref="$name" "${image}.raw")" -udevadm trigger -w "$LOOP" - -# Check if the /dev/disk/by-loop-ref/$name symlink does not exist -test ! -e "/dev/disk/by-loop-ref/$name" - -# Detach by backing inode -systemd-dissect --detach "${image}.raw" -(! systemd-dissect --detach "${image}.raw") - -# check for confext functionality -mkdir -p /run/confexts/test/etc/extension-release.d -echo "ID=_any" >/run/confexts/test/etc/extension-release.d/extension-release.test -echo "ARCHITECTURE=_any" >>/run/confexts/test/etc/extension-release.d/extension-release.test -echo "MARKER_CONFEXT_123" >/run/confexts/test/etc/testfile -cat <<EOF >/run/confexts/test/etc/testscript -#!/bin/bash -echo "This should not happen" -EOF -chmod +x /run/confexts/test/etc/testscript -systemd-confext merge -grep -q -F "MARKER_CONFEXT_123" /etc/testfile -(! /etc/testscript) -systemd-confext status -systemd-confext unmerge -rm -rf /run/confexts/ - -unsquashfs -no-xattrs -d /tmp/img "${image}.raw" -systemd-run --unit=test-root-ephemeral \ - -p RootDirectory=/tmp/img \ - -p RootEphemeral=yes \ - -p Type=exec \ - bash -c "touch /abc && sleep infinity" -test -n "$(ls -A /var/lib/systemd/ephemeral-trees)" -systemctl stop test-root-ephemeral -# shellcheck disable=SC2016 -timeout 10 bash -c 'until test -z "$(ls -A /var/lib/systemd/ephemeral-trees)"; do sleep .5; done' -test ! -f /tmp/img/abc - -systemd-dissect --mtree /tmp/img -systemd-dissect --list /tmp/img - -read -r SHA256SUM1 _ < <(systemd-dissect --copy-from /tmp/img etc/os-release | sha256sum) -test "$SHA256SUM1" != "" - -echo abc > abc -systemd-dissect --copy-to /tmp/img abc /abc -test -f /tmp/img/abc - -# Test for dissect tool support with systemd-sysext -mkdir -p /run/extensions/ testkit/usr/lib/extension-release.d/ -echo "ID=_any" >testkit/usr/lib/extension-release.d/extension-release.testkit -echo "ARCHITECTURE=_any" >>testkit/usr/lib/extension-release.d/extension-release.testkit -echo "MARKER_SYSEXT_123" >testkit/usr/lib/testfile -mksquashfs testkit/ testkit.raw -cp testkit.raw /run/extensions/ -unsquashfs -l /run/extensions/testkit.raw -systemd-dissect --no-pager /run/extensions/testkit.raw | grep -q '✓ sysext for portable service' -systemd-dissect --no-pager /run/extensions/testkit.raw | grep -q '✓ sysext for system' -systemd-sysext merge -systemd-sysext status -grep -q -F "MARKER_SYSEXT_123" /usr/lib/testfile -systemd-sysext unmerge -rm -rf /run/extensions/ testkit/ - -# Test for dissect tool support with systemd-confext -mkdir -p /run/confexts/ testjob/etc/extension-release.d/ -echo "ID=_any" >testjob/etc/extension-release.d/extension-release.testjob -echo "ARCHITECTURE=_any" >>testjob/etc/extension-release.d/extension-release.testjob -echo "MARKER_CONFEXT_123" >testjob/etc/testfile -mksquashfs testjob/ testjob.raw -cp testjob.raw /run/confexts/ -unsquashfs -l /run/confexts/testjob.raw -systemd-dissect --no-pager /run/confexts/testjob.raw | grep -q '✓ confext for system' -systemd-dissect --no-pager /run/confexts/testjob.raw | grep -q '✓ confext for portable service' -systemd-confext merge -systemd-confext status -grep -q -F "MARKER_CONFEXT_123" /etc/testfile -systemd-confext unmerge -rm -rf /run/confexts/ testjob/ - -systemd-run -P -p RootImage="${image}.raw" cat /run/host/os-release | cmp "${os_release}" - -# Test that systemd-sysext reloads the daemon. -mkdir -p /var/lib/extensions/ -ln -s /usr/share/app-reload.raw /var/lib/extensions/app-reload.raw -systemd-sysext merge --no-reload -# the service should not be running -if systemctl --quiet is-active foo.service; then - echo "foo.service should not be active" - exit 1 -fi -systemd-sysext unmerge --no-reload -systemd-sysext merge -for RETRY in $(seq 60) LAST; do - if [[ "$(journalctl --boot _SYSTEMD_UNIT="foo.service" + SYSLOG_IDENTIFIER="sysext-foo" -p info -o cat)" == "foo" ]]; then - break - fi - if [ "${RETRY}" = LAST ]; then - echo "Output of foo.service not found" - exit 1 - fi - sleep 0.5 -done -systemd-sysext unmerge --no-reload -# Grep on the Warning to find the warning helper mentioning the daemon reload. -systemctl status foo.service 2>&1 | grep -q -F "Warning" -systemd-sysext merge -systemd-sysext unmerge -systemctl status foo.service 2>&1 | grep -v -q -F "Warning" -rm /var/lib/extensions/app-reload.raw - -# Test systemd-repart --make-ddi=: -if command -v mksquashfs >/dev/null 2>&1; then - - openssl req -config "$OPENSSL_CONFIG" -subj="/CN=waldo" -x509 -sha256 -nodes -days 365 -newkey rsa:4096 -keyout /tmp/test-50-privkey.key -out /tmp/test-50-cert.crt - - mkdir -p /tmp/test-50-confext/etc/extension-release.d/ - - echo "foobar50" > /tmp/test-50-confext/etc/waldo - - ( grep -e '^\(ID\|VERSION_ID\)=' /etc/os-release ; echo IMAGE_ID=waldo ; echo IMAGE_VERSION=7 ) > /tmp/test-50-confext/etc/extension-release.d/extension-release.waldo - - mkdir -p /run/confexts - - SYSTEMD_REPART_OVERRIDE_FSTYPE=squashfs systemd-repart -C -s /tmp/test-50-confext --certificate=/tmp/test-50-cert.crt --private-key=/tmp/test-50-privkey.key /run/confexts/waldo.confext.raw - rm -rf /tmp/test-50-confext - - mkdir -p /run/verity.d - cp /tmp/test-50-cert.crt /run/verity.d/ - systemd-dissect --mtree /run/confexts/waldo.confext.raw - - systemd-confext refresh - - read -r X < /etc/waldo - test "$X" = foobar50 - - rm /run/confexts/waldo.confext.raw - - systemd-confext refresh - - (! test -f /etc/waldo ) - - mkdir -p /tmp/test-50-sysext/usr/lib/extension-release.d/ - - # Make sure the sysext is big enough to not fit in the minimum partition size of repart so we know the - # Minimize= logic is working. - truncate --size=50M /tmp/test-50-sysext/usr/waldo - - ( grep -e '^\(ID\|VERSION_ID\)=' /etc/os-release ; echo IMAGE_ID=waldo ; echo IMAGE_VERSION=7 ) > /tmp/test-50-sysext/usr/lib/extension-release.d/extension-release.waldo - - mkdir -p /run/extensions - - SYSTEMD_REPART_OVERRIDE_FSTYPE=squashfs systemd-repart -S -s /tmp/test-50-sysext --certificate=/tmp/test-50-cert.crt --private-key=/tmp/test-50-privkey.key /run/extensions/waldo.sysext.raw - - systemd-dissect --mtree /run/extensions/waldo.sysext.raw - - systemd-sysext refresh - - test -f /usr/waldo - - rm /run/verity.d/test-50-cert.crt /run/extensions/waldo.sysext.raw /tmp/test-50-cert.crt /tmp/test-50-privkey.key - - systemd-sysext refresh - - (! test -f /usr/waldo) -fi - -# Sneak in a couple of expected-to-fail invocations to cover -# https://github.com/systemd/systemd/issues/29610 -(! systemd-run -P -p MountImages="/this/should/definitely/not/exist.img:/run/img2\:3:nosuid" false) -(! systemd-run -P -p ExtensionImages="/this/should/definitely/not/exist.img" false) -(! systemd-run -P -p RootImage="/this/should/definitely/not/exist.img" false) -(! systemd-run -P -p ExtensionDirectories="/foo/bar /foo/baz" false) - -touch /testok diff --git a/test/units/testsuite-52.service b/test/units/testsuite-52.service deleted file mode 100644 index b9f2909..0000000 --- a/test/units/testsuite-52.service +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=Testsuite service - -[Service] -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-53.service b/test/units/testsuite-53.service deleted file mode 100644 index cf3adbb..0000000 --- a/test/units/testsuite-53.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-53-ISSUE-16347 - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-54.service b/test/units/testsuite-54.service deleted file mode 100644 index ba8cdad..0000000 --- a/test/units/testsuite-54.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TESTSUITE-54-CREDS - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-55.service b/test/units/testsuite-55.service deleted file mode 100644 index 00fb499..0000000 --- a/test/units/testsuite-55.service +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TESTSUITE-55-OOMD -After=user@4711.service -Wants=user@4711.service - -[Service] -ExecStartPre=rm -f /failed /skipped /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-58.service b/test/units/testsuite-58.service deleted file mode 100644 index f843527..0000000 --- a/test/units/testsuite-58.service +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-58-REPART - -[Service] -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-59.service b/test/units/testsuite-59.service deleted file mode 100644 index f85cfab..0000000 --- a/test/units/testsuite-59.service +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-59-RELOADING-RESTART - -[Service] -Type=oneshot -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh diff --git a/test/units/testsuite-60.service b/test/units/testsuite-60.service deleted file mode 100644 index 1a929e4..0000000 --- a/test/units/testsuite-60.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-60-MOUNT-RATELIMIT - -[Service] -Type=oneshot -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh diff --git a/test/units/testsuite-62-1.service b/test/units/testsuite-62-1.service deleted file mode 100644 index fa3a7e7..0000000 --- a/test/units/testsuite-62-1.service +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-62-RESTRICT-IFACES-all-pings-work -[Service] -ExecStart=/bin/sh -c 'ping -c 1 -W 0.2 192.168.113.1' -ExecStart=/bin/sh -c 'ping -c 1 -W 0.2 192.168.113.5' -ExecStart=/bin/sh -c 'ping -c 1 -W 0.2 192.168.113.9' -RestrictNetworkInterfaces= -Type=oneshot diff --git a/test/units/testsuite-62.service b/test/units/testsuite-62.service deleted file mode 100644 index 5c3f94d..0000000 --- a/test/units/testsuite-62.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-62-RESTRICT-IFACES - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-63.service b/test/units/testsuite-63.service deleted file mode 100644 index 483c6a8..0000000 --- a/test/units/testsuite-63.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-63-PATH - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-64.service b/test/units/testsuite-64.service deleted file mode 100644 index f75a3d7..0000000 --- a/test/units/testsuite-64.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-64-UDEV - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-65.service b/test/units/testsuite-65.service deleted file mode 100644 index 3610baf..0000000 --- a/test/units/testsuite-65.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-65-ANALYZE - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-66-deviceisolation.service b/test/units/testsuite-66-deviceisolation.service deleted file mode 100644 index 2d815a9..0000000 --- a/test/units/testsuite-66-deviceisolation.service +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=Service that uses device isolation - -[Service] -DevicePolicy=strict -DeviceAllow=/dev/null r -StandardOutput=file:/tmp/testsuite66serviceresults -ExecStartPre=rm -f /tmp/testsuite66serviceresults -ExecStart=/bin/bash -c "while true; do sleep 0.01 && echo meow >/dev/null && echo thisshouldnotbehere; done" diff --git a/test/units/testsuite-66.service b/test/units/testsuite-66.service deleted file mode 100644 index 7e9dc3b..0000000 --- a/test/units/testsuite-66.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TESTSUITE-66-DEVICEISOLATION - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-67.service b/test/units/testsuite-67.service deleted file mode 100644 index 82f998e..0000000 --- a/test/units/testsuite-67.service +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-67-INTEGRITY -After=multi-user.target - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-68.service b/test/units/testsuite-68.service deleted file mode 100644 index 2d86e1f..0000000 --- a/test/units/testsuite-68.service +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-68-PROPAGATE-EXIT-STATUS - -[Service] -Type=oneshot -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh diff --git a/test/units/testsuite-70.service b/test/units/testsuite-70.service deleted file mode 100644 index c13c2d5..0000000 --- a/test/units/testsuite-70.service +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-70-TPM2 - -[Service] -Type=oneshot -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh diff --git a/test/units/testsuite-71.service b/test/units/testsuite-71.service deleted file mode 100644 index 1718629..0000000 --- a/test/units/testsuite-71.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-71-HOSTNAME - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-72.service b/test/units/testsuite-72.service deleted file mode 100644 index 1640350..0000000 --- a/test/units/testsuite-72.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-72-SYSUPDATE - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-73.service b/test/units/testsuite-73.service deleted file mode 100644 index 3ebd24d..0000000 --- a/test/units/testsuite-73.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-73-LOCALE - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-74.service b/test/units/testsuite-74.service deleted file mode 100644 index f782132..0000000 --- a/test/units/testsuite-74.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-74-AUX-UTILS - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-75.service b/test/units/testsuite-75.service deleted file mode 100644 index 111cde3..0000000 --- a/test/units/testsuite-75.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=Tests for systemd-resolved - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-76.service b/test/units/testsuite-76.service deleted file mode 100644 index 3c8a9e8..0000000 --- a/test/units/testsuite-76.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-76-SYSCTL - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-77-client.sh b/test/units/testsuite-77-client.sh deleted file mode 100755 index 0d9487a..0000000 --- a/test/units/testsuite-77-client.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later -set -eux -set -o pipefail - -# shellcheck source=test/units/util.sh -. "$(dirname "$0")"/util.sh - -export SYSTEMD_LOG_LEVEL=debug - -assert_eq "$LISTEN_FDS" "1" -assert_eq "$LISTEN_FDNAMES" "socket" -read -r -u 3 text -assert_eq "$text" "Socket" diff --git a/test/units/testsuite-77-run.sh b/test/units/testsuite-77-run.sh deleted file mode 100755 index fadd34d..0000000 --- a/test/units/testsuite-77-run.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later -set -eux -set -o pipefail - -# shellcheck source=test/units/util.sh -. "$(dirname "$0")"/util.sh - -export SYSTEMD_LOG_LEVEL=debug - -assert_eq "$LISTEN_FDS" "1" -assert_eq "$LISTEN_FDNAMES" "new-file" -read -r -u 3 text -assert_eq "$text" "New" diff --git a/test/units/testsuite-77.service b/test/units/testsuite-77.service deleted file mode 100644 index 6ed8add..0000000 --- a/test/units/testsuite-77.service +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-77-OPENFILE - -[Service] -OpenFile=/test-77-open.dat:open:read-only -OpenFile=/test-77-file.dat -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-77.sh b/test/units/testsuite-77.sh deleted file mode 100755 index 2b85a8c..0000000 --- a/test/units/testsuite-77.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash -# SPDX-License-Identifier: LGPL-2.1-or-later -set -eux -set -o pipefail - -# shellcheck source=test/units/util.sh -. "$(dirname "$0")"/util.sh - -export SYSTEMD_LOG_LEVEL=debug - -assert_eq "$LISTEN_FDS" "2" -assert_eq "$LISTEN_FDNAMES" "open:test-77-file.dat" -read -r -u 3 text -assert_eq "$text" "Open" -read -r -u 4 text -assert_eq "$text" "File" - -# Test for socket -systemctl start testsuite-77-server.socket -systemd-run -p OpenFile=/tmp/test.sock:socket:read-only \ - --wait \ - --pipe \ - /usr/lib/systemd/tests/testdata/units/testsuite-77-client.sh - -# Tests for D-Bus -diff <(systemctl show -p OpenFile testsuite-77) - <<EOF -OpenFile=/test-77-open.dat:open:read-only -OpenFile=/test-77-file.dat -EOF -echo "New" >/test-77-new-file.dat -systemd-run --wait -p OpenFile=/test-77-new-file.dat:new-file:read-only "$(dirname "$0")"/testsuite-77-run.sh - -assert_rc 202 systemd-run --wait -p OpenFile=/test-77-new-file.dat:new-file:read-only -p OpenFile=/test-77-mssing-file.dat:missing-file:read-only "$(dirname "$0")"/testsuite-77-run.sh - -assert_rc 0 systemd-run --wait -p OpenFile=/test-77-new-file.dat:new-file:read-only -p OpenFile=/test-77-mssing-file.dat:missing-file:read-only,graceful "$(dirname "$0")"/testsuite-77-run.sh - -# End -touch /testok diff --git a/test/units/testsuite-78.service b/test/units/testsuite-78.service deleted file mode 100644 index 05f3eff..0000000 --- a/test/units/testsuite-78.service +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-78-SIGQUEUE - -[Service] -Type=oneshot -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh diff --git a/test/units/testsuite-79.service b/test/units/testsuite-79.service deleted file mode 100644 index f2d24df..0000000 --- a/test/units/testsuite-79.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-79-MEMPRESS - -[Service] -Type=oneshot -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -MemoryAccounting=1 diff --git a/test/units/testsuite-80.service b/test/units/testsuite-80.service deleted file mode 100644 index 4c7f5d5..0000000 --- a/test/units/testsuite-80.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-80-NOTIFYACCESS - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-81.service b/test/units/testsuite-81.service deleted file mode 100644 index 3b697b3..0000000 --- a/test/units/testsuite-81.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-81-GENERATORS - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-83.service b/test/units/testsuite-83.service deleted file mode 100644 index 55ebb45..0000000 --- a/test/units/testsuite-83.service +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-83-BTRFS - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-84.service b/test/units/testsuite-84.service deleted file mode 100644 index 2c25770..0000000 --- a/test/units/testsuite-84.service +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -[Unit] -Description=TEST-84-STORAGETM -After=multi-user.target - -[Service] -ExecStartPre=rm -f /failed /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/unit-with-multiple-dashes.service b/test/units/unit-with-multiple-dashes.service index 4aca904..9ac3c8c 100644 --- a/test/units/unit-with-multiple-dashes.service +++ b/test/units/unit-with-multiple-dashes.service @@ -4,4 +4,4 @@ Description=A unit with multiple dashes Documentation=man:test [Service] -ExecStart=/bin/true +ExecStart=true diff --git a/test/units/util.sh b/test/units/util.sh index b5ed732..f5f6786 100755 --- a/test/units/util.sh +++ b/test/units/util.sh @@ -28,6 +28,15 @@ assert_eq() {( fi )} +assert_le() {( + set +ex + + if [[ "${1:?}" -gt "${2:?}" ]]; then + echo "FAIL: '$1' > '$2'" >&2 + exit 1 + fi +)} + assert_in() {( set +ex @@ -147,13 +156,13 @@ coverage_create_nspawn_dropin() { create_dummy_container() { local root="${1:?}" - if [[ ! -d /testsuite-13-container-template ]]; then + if [[ ! -d /usr/share/TEST-13-NSPAWN-container-template ]]; then echo >&2 "Missing container template, probably not running in TEST-13-NSPAWN?" exit 1 fi mkdir -p "$root" - cp -a /testsuite-13-container-template/* "$root" + cp -a /usr/share/TEST-13-NSPAWN-container-template/* "$root" coverage_create_nspawn_dropin "$root" } @@ -216,3 +225,156 @@ kernel_supports_lsm() { return 1 } + +install_extension_images() { + local os_release + os_release="$(test -e /etc/os-release && echo /etc/os-release || echo /usr/lib/os-release)" + + # Rolling distros like Arch do not set VERSION_ID + local version_id="" + if grep -q "^VERSION_ID=" "$os_release"; then + version_id="$(grep "^VERSION_ID=" "$os_release")" + fi + + local initdir="/var/tmp/app0" + mkdir -p "$initdir/usr/lib/extension-release.d" "$initdir/usr/lib/systemd/system" "$initdir/opt" + grep "^ID=" "$os_release" >"$initdir/usr/lib/extension-release.d/extension-release.app0" + echo "$version_id" >>"$initdir/usr/lib/extension-release.d/extension-release.app0" + ( + echo "$version_id" + echo "SYSEXT_IMAGE_ID=app" + ) >>"$initdir/usr/lib/extension-release.d/extension-release.app0" + cat >"$initdir/usr/lib/systemd/system/app0.service" <<EOF +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/opt/script0.sh +TemporaryFileSystem=/var/lib +StateDirectory=app0 +RuntimeDirectory=app0 +EOF + cat >"$initdir/opt/script0.sh" <<EOF +#!/bin/bash +set -e +test -e /usr/lib/os-release +echo bar >\${STATE_DIRECTORY}/foo +cat /usr/lib/extension-release.d/extension-release.app0 +EOF + chmod +x "$initdir/opt/script0.sh" + echo MARKER=1 >"$initdir/usr/lib/systemd/system/some_file" + mksquashfs "$initdir" /tmp/app0.raw -noappend + + initdir="/var/tmp/conf0" + mkdir -p "$initdir/etc/extension-release.d" "$initdir/etc/systemd/system" "$initdir/opt" + grep "^ID=" "$os_release" >"$initdir/etc/extension-release.d/extension-release.conf0" + echo "$version_id" >>"$initdir/etc/extension-release.d/extension-release.conf0" + ( + echo "$version_id" + echo "CONFEXT_IMAGE_ID=app" + ) >>"$initdir/etc/extension-release.d/extension-release.conf0" + echo MARKER_1 >"$initdir/etc/systemd/system/some_file" + mksquashfs "$initdir" /tmp/conf0.raw -noappend + + initdir="/var/tmp/app1" + mkdir -p "$initdir/usr/lib/extension-release.d" "$initdir/usr/lib/systemd/system" "$initdir/opt" + grep "^ID=" "$os_release" >"$initdir/usr/lib/extension-release.d/extension-release.app2" + ( + echo "$version_id" + echo "SYSEXT_SCOPE=portable" + echo "SYSEXT_IMAGE_ID=app" + echo "SYSEXT_IMAGE_VERSION=1" + echo "PORTABLE_PREFIXES=app1" + ) >>"$initdir/usr/lib/extension-release.d/extension-release.app2" + setfattr -n user.extension-release.strict -v false "$initdir/usr/lib/extension-release.d/extension-release.app2" + cat >"$initdir/usr/lib/systemd/system/app1.service" <<EOF +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/opt/script1.sh +StateDirectory=app1 +RuntimeDirectory=app1 +EOF + cat >"$initdir/opt/script1.sh" <<EOF +#!/bin/bash +set -e +test -e /usr/lib/os-release +echo baz >\${STATE_DIRECTORY}/foo +cat /usr/lib/extension-release.d/extension-release.app2 +EOF + chmod +x "$initdir/opt/script1.sh" + echo MARKER=1 >"$initdir/usr/lib/systemd/system/other_file" + mksquashfs "$initdir" /tmp/app1.raw -noappend + + initdir="/var/tmp/app-nodistro" + mkdir -p "$initdir/usr/lib/extension-release.d" "$initdir/usr/lib/systemd/system" + ( + echo "ID=_any" + echo "ARCHITECTURE=_any" + ) >"$initdir/usr/lib/extension-release.d/extension-release.app-nodistro" + echo MARKER=1 >"$initdir/usr/lib/systemd/system/some_file" + mksquashfs "$initdir" /tmp/app-nodistro.raw -noappend + + initdir="/var/tmp/service-scoped-test" + mkdir -p "$initdir/etc/extension-release.d" "$initdir/etc/systemd/system" + ( + echo "ID=_any" + echo "ARCHITECTURE=_any" + ) >"$initdir/etc/extension-release.d/extension-release.service-scoped-test" + echo MARKER_CONFEXT_123 >"$initdir/etc/systemd/system/some_file" + mksquashfs "$initdir" /etc/service-scoped-test.raw -noappend + + # We need to create a dedicated sysext image to test the reload mechanism. If we share an image to install the + # 'foo.service' it will be loaded from another test run, which will impact the targeted test. + initdir="/var/tmp/app-reload" + mkdir -p "$initdir/usr/lib/extension-release.d" "$initdir/usr/lib/systemd/system" + ( + echo "ID=_any" + echo "ARCHITECTURE=_any" + echo "EXTENSION_RELOAD_MANAGER=1" + ) >"$initdir/usr/lib/extension-release.d/extension-release.app-reload" + mkdir -p "$initdir/usr/lib/systemd/system/multi-user.target.d" + cat >"$initdir/usr/lib/systemd/system/foo.service" <<EOF +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=echo foo + +[Install] +WantedBy=multi-user.target +EOF + echo -e "[Unit]\nUpholds=foo.service" >"$initdir/usr/lib/systemd/system/multi-user.target.d/10-foo-service.conf" + mksquashfs "$initdir" /tmp/app-reload.raw -noappend +} + +restore_locale() { + if [[ -d /usr/lib/locale/xx_XX.UTF-8 ]]; then + rmdir /usr/lib/locale/xx_XX.UTF-8 + fi + + if [[ -f /tmp/locale.conf.bak ]]; then + mv /tmp/locale.conf.bak /etc/locale.conf + else + rm -f /etc/locale.conf + fi + + if [[ -f /tmp/default-locale.bak ]]; then + mv /tmp/default-locale.bak /etc/default/locale + else + rm -rf /etc/default + fi + + if [[ -f /tmp/locale.gen.bak ]]; then + mv /tmp/locale.gen.bak /etc/locale.gen + else + rm -f /etc/locale.gen + fi +} + +generate_locale() { + local locale="${1:?}" + + if command -v locale-gen >/dev/null && ! localectl list-locales | grep -F "$locale"; then + echo "$locale UTF-8" >/etc/locale.gen + locale-gen "$locale" + fi +} |