summaryrefslogtreecommitdiffstats
path: root/test/units
diff options
context:
space:
mode:
Diffstat (limited to 'test/units')
-rwxr-xr-xtest/units/TEST-04-JOURNAL.bsod.sh4
-rwxr-xr-xtest/units/TEST-04-JOURNAL.stopped-socket-activation.sh10
-rwxr-xr-xtest/units/TEST-07-PID1.issue-31752.sh44
-rwxr-xr-xtest/units/TEST-09-REBOOT.sh4
-rwxr-xr-xtest/units/TEST-17-UDEV.credentials.sh2
-rwxr-xr-xtest/units/TEST-19-CGROUP.delegate.sh183
-rwxr-xr-xtest/units/TEST-54-CREDS.sh5
-rwxr-xr-xtest/units/TEST-58-REPART.sh8
-rwxr-xr-xtest/units/TEST-70-TPM2.cryptsetup.sh2
-rwxr-xr-xtest/units/TEST-70-TPM2.pcrlock.sh5
-rwxr-xr-xtest/units/TEST-73-LOCALE.sh11
-rwxr-xr-xtest/units/TEST-74-AUX-UTILS.firstboot.sh79
-rwxr-xr-xtest/units/TEST-82-SOFTREBOOT.sh15
13 files changed, 260 insertions, 112 deletions
diff --git a/test/units/TEST-04-JOURNAL.bsod.sh b/test/units/TEST-04-JOURNAL.bsod.sh
index 83feb89..802d474 100755
--- a/test/units/TEST-04-JOURNAL.bsod.sh
+++ b/test/units/TEST-04-JOURNAL.bsod.sh
@@ -4,12 +4,12 @@ set -eux
set -o pipefail
if systemd-detect-virt -cq; then
- echo "This test requires a VM, skipping the test" | tee --append /skipped
+ echo "This test requires a VM, skipping the test"
exit 0
fi
if [[ ! -x /usr/lib/systemd/systemd-bsod ]]; then
- echo "systemd-bsod is not installed, skipping the test" | tee --append /skipped
+ echo "systemd-bsod is not installed, skipping the test"
exit 0
fi
diff --git a/test/units/TEST-04-JOURNAL.stopped-socket-activation.sh b/test/units/TEST-04-JOURNAL.stopped-socket-activation.sh
new file mode 100755
index 0000000..083f5fa
--- /dev/null
+++ b/test/units/TEST-04-JOURNAL.stopped-socket-activation.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -eux
+set -o pipefail
+
+systemctl stop systemd-journald.service
+systemd-cat date
+
+# shellcheck disable=SC2016
+timeout 30 bash -xec 'until test "$(systemctl show -p SubState --value systemd-journald.service)" = "running"; do sleep 1; done'
diff --git a/test/units/TEST-07-PID1.issue-31752.sh b/test/units/TEST-07-PID1.issue-31752.sh
new file mode 100755
index 0000000..89ec07e
--- /dev/null
+++ b/test/units/TEST-07-PID1.issue-31752.sh
@@ -0,0 +1,44 @@
+#!/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
+
+# shellcheck source=test/units/util.sh
+. "$(dirname "$0")"/util.sh
+
+# Make sure NeedDaemonReload= considers newly created drop-ins.
+# Issue: https://github.com/systemd/systemd/issues/31752
+
+UNIT=test-issue-31752.service
+
+cleanup() {
+ rm -rf /run/systemd/system/"$UNIT" /run/systemd/system/"$UNIT".d
+ systemctl daemon-reload
+}
+
+trap cleanup EXIT
+
+cat > /run/systemd/system/"$UNIT" <<EOF
+[Service]
+ExecStart=/usr/bin/true
+RemainAfterExit=yes
+EOF
+
+systemctl daemon-reload
+systemctl start "$UNIT"
+assert_eq "$(systemctl show -P NeedDaemonReload "$UNIT")" no
+
+mkdir /run/systemd/system/"$UNIT".d
+cat > /run/systemd/system/"$UNIT".d/desc.conf <<EOF
+[Unit]
+Description=Test NeedDaemonReload status after creating drop-in
+EOF
+
+assert_eq "$(systemctl show -P NeedDaemonReload "$UNIT")" yes
+
+rm /run/systemd/system/"$UNIT".d/desc.conf
+
+assert_eq "$(systemctl show -P NeedDaemonReload "$UNIT")" no
diff --git a/test/units/TEST-09-REBOOT.sh b/test/units/TEST-09-REBOOT.sh
index 85630b6..014ea31 100755
--- a/test/units/TEST-09-REBOOT.sh
+++ b/test/units/TEST-09-REBOOT.sh
@@ -17,7 +17,11 @@ systemd-cat journalctl --list-boots
run_subtests
if [[ "$REBOOT_COUNT" -lt "$NUM_REBOOT" ]]; then
+ SYSTEMCTL_SKIP_AUTO_SOFT_REBOOT=1
+ export SYSTEMCTL_SKIP_AUTO_SOFT_REBOOT
systemctl_final reboot
+ # Now block until the reboot killing spree kills us.
+ exec sleep infinity
elif [[ "$REBOOT_COUNT" -gt "$NUM_REBOOT" ]]; then
assert_not_reached
fi
diff --git a/test/units/TEST-17-UDEV.credentials.sh b/test/units/TEST-17-UDEV.credentials.sh
index 42d3883..2552dc6 100755
--- a/test/units/TEST-17-UDEV.credentials.sh
+++ b/test/units/TEST-17-UDEV.credentials.sh
@@ -5,7 +5,7 @@ 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
+ echo "Missing systemd-udev-load-credentials.service"
exit 0
fi
diff --git a/test/units/TEST-19-CGROUP.delegate.sh b/test/units/TEST-19-CGROUP.delegate.sh
index 022515f..7f3a705 100755
--- a/test/units/TEST-19-CGROUP.delegate.sh
+++ b/test/units/TEST-19-CGROUP.delegate.sh
@@ -5,6 +5,8 @@ set -o pipefail
# Test cgroup delegation in the unified hierarchy
+# shellcheck source=test/units/test-control.sh
+. "$(dirname "$0")"/test-control.sh
# shellcheck source=test/units/util.sh
. "$(dirname "$0")"/util.sh
@@ -13,104 +15,109 @@ if [[ "$(get_cgroup_hierarchy)" != unified ]]; then
exit 0
fi
-at_exit() {
- set +e
- userdel -r test
+testcase_controllers() {
+ systemd-run --wait \
+ --unit=test-0.service \
+ --property="DynamicUser=1" \
+ --property="Delegate=" \
+ test -w /sys/fs/cgroup/system.slice/test-0.service/ -a \
+ -w /sys/fs/cgroup/system.slice/test-0.service/cgroup.procs -a \
+ -w /sys/fs/cgroup/system.slice/test-0.service/cgroup.subtree_control
+
+ systemd-run --wait \
+ --unit=test-1.service \
+ --property="DynamicUser=1" \
+ --property="Delegate=memory pids" \
+ grep -q memory /sys/fs/cgroup/system.slice/test-1.service/cgroup.controllers
+
+ systemd-run --wait \
+ --unit=test-2.service \
+ --property="DynamicUser=1" \
+ --property="Delegate=memory pids" \
+ grep -q pids /sys/fs/cgroup/system.slice/test-2.service/cgroup.controllers
+
+ # "io" is not among the controllers enabled by default for all units, verify that
+ grep -qv io /sys/fs/cgroup/system.slice/cgroup.controllers
+
+ # Run a service with "io" enabled, and verify it works
+ systemd-run --wait \
+ --unit=test-3.service \
+ --property="IOAccounting=yes" \
+ --property="Slice=system-foo-bar-baz.slice" \
+ grep -q io /sys/fs/cgroup/system.slice/system-foo.slice/system-foo-bar.slice/system-foo-bar-baz.slice/test-3.service/cgroup.controllers
+
+ # We want to check if "io" is removed again from the controllers
+ # list. However, PID 1 (rightfully) does this asynchronously. In order
+ # to force synchronization on this, let's start a short-lived service
+ # which requires PID 1 to refresh the cgroup tree, so that we can
+ # verify that this all works.
+ systemd-run --wait --unit=test-4.service true
+
+ # And now check again, "io" should have vanished
+ grep -qv io /sys/fs/cgroup/system.slice/cgroup.controllers
}
-systemd-run --wait \
- --unit=test-0.service \
- --property="DynamicUser=1" \
- --property="Delegate=" \
- test -w /sys/fs/cgroup/system.slice/test-0.service/ -a \
- -w /sys/fs/cgroup/system.slice/test-0.service/cgroup.procs -a \
- -w /sys/fs/cgroup/system.slice/test-0.service/cgroup.subtree_control
+testcase_attributes() {
+ # Test if delegation also works for some of the more recent attrs the kernel might or might not support
+ 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 \
+ -w /sys/fs/cgroup/system.slice/test-0.service/"$attr"
+ fi
+ done
+}
-# Test if this also works for some of the more recent attrs the kernel might or might not support
-for attr in cgroup.threads memory.oom.group memory.reclaim ; do
+testcase_scope_unpriv_delegation() {
+ # Check that unprivileged delegation works for scopes
+ useradd test
+ trap "userdel -r test" RETURN
+ systemd-run --uid=test \
+ --property="User=test" \
+ --property="Delegate=yes" \
+ --slice workload.slice \
+ --unit test-workload0.scope\
+ --scope \
+ test -w /sys/fs/cgroup/workload.slice/test-workload0.scope -a \
+ -w /sys/fs/cgroup/workload.slice/test-workload0.scope/cgroup.procs -a \
+ -w /sys/fs/cgroup/workload.slice/test-workload0.scope/cgroup.subtree_control
+}
- if grep -q "$attr" /sys/kernel/cgroup/delegate ; then
+testcase_subgroup() {
+ # Verify that DelegateSubgroup= affects ownership correctly
+ unit="test-subgroup-$RANDOM.service"
+ systemd-run --wait \
+ --unit="$unit" \
+ --property="DynamicUser=1" \
+ --property="Delegate=pids" \
+ --property="DelegateSubgroup=foo" \
+ test -w "/sys/fs/cgroup/system.slice/$unit" -a \
+ -w "/sys/fs/cgroup/system.slice/$unit/foo"
+
+ # Check that for the subgroup also attributes that aren't covered by
+ # regular (i.e. main cgroup) delegation ownership rules are delegated properly
+ if test -f /sys/fs/cgroup/cgroup.max.depth; then
+ unit="test-subgroup-$RANDOM.service"
systemd-run --wait \
- --unit=test-0.service \
- --property="MemoryAccounting=1" \
+ --unit="$unit" \
--property="DynamicUser=1" \
- --property="Delegate=" \
- test -w /sys/fs/cgroup/system.slice/test-0.service/ -a \
- -w /sys/fs/cgroup/system.slice/test-0.service/"$attr"
+ --property="Delegate=pids" \
+ --property="DelegateSubgroup=zzz" \
+ test -w "/sys/fs/cgroup/system.slice/$unit/zzz/cgroup.max.depth"
fi
-done
-
-systemd-run --wait \
- --unit=test-1.service \
- --property="DynamicUser=1" \
- --property="Delegate=memory pids" \
- grep -q memory /sys/fs/cgroup/system.slice/test-1.service/cgroup.controllers
-
-systemd-run --wait \
- --unit=test-2.service \
- --property="DynamicUser=1" \
- --property="Delegate=memory pids" \
- grep -q pids /sys/fs/cgroup/system.slice/test-2.service/cgroup.controllers
-
-# "io" is not among the controllers enabled by default for all units, verify that
-grep -qv io /sys/fs/cgroup/system.slice/cgroup.controllers
-
-# Run a service with "io" enabled, and verify it works
-systemd-run --wait \
- --unit=test-3.service \
- --property="IOAccounting=yes" \
- --property="Slice=system-foo-bar-baz.slice" \
- grep -q io /sys/fs/cgroup/system.slice/system-foo.slice/system-foo-bar.slice/system-foo-bar-baz.slice/test-3.service/cgroup.controllers
-
-# We want to check if "io" is removed again from the controllers
-# list. However, PID 1 (rightfully) does this asynchronously. In order
-# to force synchronization on this, let's start a short-lived service
-# which requires PID 1 to refresh the cgroup tree, so that we can
-# verify that this all works.
-systemd-run --wait --unit=test-4.service true
-
-# And now check again, "io" should have vanished
-grep -qv io /sys/fs/cgroup/system.slice/cgroup.controllers
-
-# Check that unprivileged delegation works for scopes
-useradd test ||:
-systemd-run --uid=test \
- --property="User=test" \
- --property="Delegate=yes" \
- --slice workload.slice \
- --unit test-workload0.scope\
- --scope \
- test -w /sys/fs/cgroup/workload.slice/test-workload0.scope -a \
- -w /sys/fs/cgroup/workload.slice/test-workload0.scope/cgroup.procs -a \
- -w /sys/fs/cgroup/workload.slice/test-workload0.scope/cgroup.subtree_control
-
-# Verify that DelegateSubgroup= affects ownership correctly
-unit="test-subgroup-$RANDOM.service"
-systemd-run --wait \
- --unit="$unit" \
- --property="DynamicUser=1" \
- --property="Delegate=pids" \
- --property="DelegateSubgroup=foo" \
- test -w "/sys/fs/cgroup/system.slice/$unit" -a \
- -w "/sys/fs/cgroup/system.slice/$unit/foo"
-
-# Check that for the subgroup also attributes that aren't covered by
-# regular (i.e. main cgroup) delegation ownership rules are delegated properly
-if test -f /sys/fs/cgroup/cgroup.max.depth; then
+
+ # Check that the invoked process itself is also in the subgroup
unit="test-subgroup-$RANDOM.service"
systemd-run --wait \
--unit="$unit" \
--property="DynamicUser=1" \
--property="Delegate=pids" \
- --property="DelegateSubgroup=zzz" \
- test -w "/sys/fs/cgroup/system.slice/$unit/zzz/cgroup.max.depth"
-fi
+ --property="DelegateSubgroup=bar" \
+ grep -q -x -F "0::/system.slice/$unit/bar" /proc/self/cgroup
+}
-# Check that the invoked process itself is also in the subgroup
-unit="test-subgroup-$RANDOM.service"
-systemd-run --wait \
- --unit="$unit" \
- --property="DynamicUser=1" \
- --property="Delegate=pids" \
- --property="DelegateSubgroup=bar" \
- grep -q -x -F "0::/system.slice/$unit/bar" /proc/self/cgroup
+run_testcases
diff --git a/test/units/TEST-54-CREDS.sh b/test/units/TEST-54-CREDS.sh
index fe410d5..89d6dcd 100755
--- a/test/units/TEST-54-CREDS.sh
+++ b/test/units/TEST-54-CREDS.sh
@@ -273,8 +273,11 @@ rm -rf /tmp/ts54-creds
# Check that globs work as expected
mkdir -p /run/credstore
echo -n a >/run/credstore/test.creds.first
-echo -n b >/run/credstore/test.creds.second
+# Make sure that when multiple credentials of the same name are found, the first one is used (/etc/credstore
+# is searched before /run/credstore).
+echo -n ignored >/run/credstore/test.creds.second
mkdir -p /etc/credstore
+echo -n b >/etc/credstore/test.creds.second
echo -n c >/etc/credstore/test.creds.third
systemd-run -p "ImportCredential=test.creds.*" \
--unit=test-54-ImportCredential.service \
diff --git a/test/units/TEST-58-REPART.sh b/test/units/TEST-58-REPART.sh
index 743baad..f8c22ab 100755
--- a/test/units/TEST-58-REPART.sh
+++ b/test/units/TEST-58-REPART.sh
@@ -358,14 +358,14 @@ label-id: 1D2CE291-7CCE-4F7D-BC83-FDB49AD74EBD
device: $imgs/zzz
unit: sectors
first-lba: 2048
-last-lba: 6389726
+last-lba: 6422494
$imgs/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=4980595D-D74A-483A-AA9E-9903879A0EE5, name=\"home-first\", attrs=\"GUID:59\"
$imgs/zzz2 : start= 593904, size= 591856, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\", attrs=\"GUID:59\"
$imgs/zzz3 : start= 1185760, size= 591864, type=${root_guid}, uuid=${root_uuid2}, name=\"root-${architecture}-2\", attrs=\"GUID:59\"
$imgs/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=78C92DB8-3D2B-4823-B0DC-792B78F66F1E, name=\"swap\"
$imgs/zzz5 : start= 1908696, size= 2285568, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=A0A1A2A3-A4A5-A6A7-A8A9-AAABACADAEAF, name=\"custom_label\"
$imgs/zzz6 : start= 4194264, size= 2097152, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=2A1D97E1-D0A3-46CC-A26E-ADC643926617, name=\"block-copy\"
-$imgs/zzz7 : start= 6291416, size= 98304, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=7B93D1F2-595D-4CE3-B0B9-837FBD9E63B0, name=\"luks-format-copy\""
+$imgs/zzz7 : start= 6291416, size= 131072, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=7B93D1F2-595D-4CE3-B0B9-837FBD9E63B0, name=\"luks-format-copy\""
if systemd-detect-virt --quiet --container; then
echo "Skipping encrypt mount tests in container."
@@ -566,8 +566,8 @@ EOF
output=$(sfdisk --dump "$imgs/zzz")
assert_in "$imgs/zzz1 : start= 2048, size= 20480, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, uuid=39107B09-615D-48FB-BA37-C663885FCE67, name=\"esp\"" "$output"
- assert_in "$imgs/zzz2 : start= 22528, size= 20480, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\", attrs=\"GUID:59\"" "$output"
- assert_in "$imgs/zzz3 : start= 43008, size= 20480, type=${usr_guid}, uuid=${usr_uuid}, name=\"usr-${architecture}\", attrs=\"GUID:60\"" "$output"
+ assert_in "$imgs/zzz2 : start= 22528, size= 65536, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\", attrs=\"GUID:59\"" "$output"
+ assert_in "$imgs/zzz3 : start= 88064, size= 65536, type=${usr_guid}, uuid=${usr_uuid}, name=\"usr-${architecture}\", attrs=\"GUID:60\"" "$output"
if systemd-detect-virt --quiet --container; then
echo "Skipping second part of copy blocks tests in container."
diff --git a/test/units/TEST-70-TPM2.cryptsetup.sh b/test/units/TEST-70-TPM2.cryptsetup.sh
index cb7c8b1..b5dd4df 100755
--- a/test/units/TEST-70-TPM2.cryptsetup.sh
+++ b/test/units/TEST-70-TPM2.cryptsetup.sh
@@ -210,7 +210,7 @@ Format=ext4
CopyFiles=/tmp/dditest:/
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=
+ PASSWORD=passphrase systemd-repart --tpm2-device-key=/tmp/srk.pub --definitions=/tmp/dditest --empty=create --size=80M /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
diff --git a/test/units/TEST-70-TPM2.pcrlock.sh b/test/units/TEST-70-TPM2.pcrlock.sh
index fd51161..10fa7a9 100755
--- a/test/units/TEST-70-TPM2.pcrlock.sh
+++ b/test/units/TEST-70-TPM2.pcrlock.sh
@@ -89,6 +89,11 @@ systemd-cryptenroll --unlock-key-file=/tmp/pcrlockpwd --tpm2-device=auto --tpm2-
systemd-cryptsetup attach pcrlock "$img" - tpm2-device=auto,tpm2-pcrlock=/var/lib/systemd/pcrlock.json,headless
systemd-cryptsetup detach pcrlock
+# Ensure systemd-pcrlock not crashing on empty variant directory
+mkdir -p /var/lib/pcrlock.d/123-empty.pcrlock.d
+"$SD_PCRLOCK" predict --pcr="$PCRS"
+rm -rf /var/lib/pcrlock.d/123-empty.pcrlock.d
+
# Measure something into PCR 16 (the "debug" PCR), which should make the activation fail
"$SD_PCREXTEND" --pcr=16 test70
diff --git a/test/units/TEST-73-LOCALE.sh b/test/units/TEST-73-LOCALE.sh
index 06c8c56..0617bd0 100755
--- a/test/units/TEST-73-LOCALE.sh
+++ b/test/units/TEST-73-LOCALE.sh
@@ -666,14 +666,9 @@ cat >/etc/dbus-1/system.d/systemd-localed-read-only.conf <<EOF
"https://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
- <allow send_member="SetLocale"/>
- <allow send_member="SetVConsoleKeyboard"/>
- <allow send_member="SetX11Keyboard"/>
- </policy>
- <policy context="default">
- <allow send_member="SetLocale"/>
- <allow send_member="SetVConsoleKeyboard"/>
- <allow send_member="SetX11Keyboard"/>
+ <allow send_destination="org.freedesktop.locale1" send_interface="org.freedesktop.locale1" send_member="SetLocale"/>
+ <allow send_destination="org.freedesktop.locale1" send_interface="org.freedesktop.locale1" send_member="SetVConsoleKeyboard"/>
+ <allow send_destination="org.freedesktop.locale1" send_interface="org.freedesktop.locale1" send_member="SetX11Keyboard"/>
</policy>
</busconfig>
EOF
diff --git a/test/units/TEST-74-AUX-UTILS.firstboot.sh b/test/units/TEST-74-AUX-UTILS.firstboot.sh
index 7bab009..d9e5f59 100755
--- a/test/units/TEST-74-AUX-UTILS.firstboot.sh
+++ b/test/units/TEST-74-AUX-UTILS.firstboot.sh
@@ -14,6 +14,7 @@ fi
at_exit() {
if [[ -n "${ROOT:-}" ]]; then
ls -lR "$ROOT"
+ grep -r . "$ROOT/etc" || :
rm -fr "$ROOT"
fi
@@ -83,15 +84,42 @@ grep -q "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "$ROOT/etc/machine-id"
rm -fv "$ROOT/etc/passwd" "$ROOT/etc/shadow"
systemd-firstboot --root="$ROOT" --root-password=foo
grep -q "^root:x:0:0:" "$ROOT/etc/passwd"
-grep -q "^root:" "$ROOT/etc/shadow"
+grep -q "^root:[^!*]" "$ROOT/etc/shadow"
rm -fv "$ROOT/etc/passwd" "$ROOT/etc/shadow"
echo "foo" >root.passwd
systemd-firstboot --root="$ROOT" --root-password-file=root.passwd
grep -q "^root:x:0:0:" "$ROOT/etc/passwd"
-grep -q "^root:" "$ROOT/etc/shadow"
+grep -q "^root:[^!*]" "$ROOT/etc/shadow"
rm -fv "$ROOT/etc/passwd" "$ROOT/etc/shadow" root.passwd
-# Set the shell together with the password, as firstboot won't touch
-# /etc/passwd if it already exists
+# Make sure the root password is set if /etc/passwd and /etc/shadow exist but
+# don't have a root entry.
+touch "$ROOT/etc/passwd" "$ROOT/etc/shadow"
+systemd-firstboot --root="$ROOT" --root-password=foo
+grep -q "^root:x:0:0:" "$ROOT/etc/passwd"
+grep -q "^root:[^!*]" "$ROOT/etc/shadow"
+rm -fv "$ROOT/etc/passwd" "$ROOT/etc/shadow"
+# If /etc/passwd and /etc/shadow exist, they will only be updated if the shadow
+# password is !unprovisioned.
+echo "root:x:0:0:root:/root:/bin/sh" >"$ROOT/etc/passwd"
+echo "root:!test:::::::" >"$ROOT/etc/shadow"
+systemd-firstboot --root="$ROOT" --root-password=foo
+grep -q "^root:x:0:0:" "$ROOT/etc/passwd"
+grep -q "^root:!test:" "$ROOT/etc/shadow"
+rm -fv "$ROOT/etc/passwd" "$ROOT/etc/shadow"
+echo "root:x:0:0:root:/root:/bin/sh" >"$ROOT/etc/passwd"
+echo "root:!unprovisioned:::::::" >"$ROOT/etc/shadow"
+systemd-firstboot --root="$ROOT" --root-password=foo
+grep -q "^root:x:0:0:" "$ROOT/etc/passwd"
+grep -q "^root:[^!*]" "$ROOT/etc/shadow"
+rm -fv "$ROOT/etc/passwd" "$ROOT/etc/shadow"
+systemd-firstboot --root="$ROOT" --root-password-hashed="$ROOT_HASHED_PASSWORD1"
+grep -q "^root:x:0:0:" "$ROOT/etc/passwd"
+grep -q "^root:$ROOT_HASHED_PASSWORD1:" "$ROOT/etc/shadow"
+rm -fv "$ROOT/etc/passwd" "$ROOT/etc/shadow"
+systemd-firstboot --root="$ROOT" --root-shell=/bin/fooshell
+grep -q "^root:x:0:0:.*:/bin/fooshell$" "$ROOT/etc/passwd"
+grep -q "^root:!\*:" "$ROOT/etc/shadow"
+rm -fv "$ROOT/etc/passwd" "$ROOT/etc/shadow"
systemd-firstboot --root="$ROOT" --root-password-hashed="$ROOT_HASHED_PASSWORD1" --root-shell=/bin/fooshell
grep -q "^root:x:0:0:.*:/bin/fooshell$" "$ROOT/etc/passwd"
grep -q "^root:$ROOT_HASHED_PASSWORD1:" "$ROOT/etc/shadow"
@@ -176,8 +204,9 @@ mkdir -p "$ROOT/bin"
touch "$ROOT/bin/fooshell" "$ROOT/bin/barshell"
# Temporarily disable pipefail to avoid `echo: write error: Broken pipe
set +o pipefail
-# We can do only limited testing here, since it's all an interactive stuff,
-# so --prompt and --prompt-root-password are skipped on purpose
+# We can do only limited testing here, since it's all an interactive stuff, so
+# --prompt is skipped on purpose and only limited --prompt-root-password
+# testing can be done.
echo -ne "\nfoo\nbar\n" | systemd-firstboot --root="$ROOT" --prompt-locale
grep -q "LANG=foo" "$ROOT$LOCALE_PATH"
grep -q "LC_MESSAGES=bar" "$ROOT$LOCALE_PATH"
@@ -193,6 +222,11 @@ echo -ne "\nEurope/Berlin\n" | systemd-firstboot --root="$ROOT" --prompt-timezon
readlink "$ROOT/etc/localtime" | grep -q "Europe/Berlin$"
echo -ne "\nfoobar\n" | systemd-firstboot --root="$ROOT" --prompt-hostname
grep -q "foobar" "$ROOT/etc/hostname"
+# With no root password provided, a locked account should be created.
+systemd-firstboot --root="$ROOT" --prompt-root-password </dev/null
+grep -q "^root:x:0:0:" "$ROOT/etc/passwd"
+grep -q "^root:!\*:" "$ROOT/etc/shadow"
+rm -fv "$ROOT/etc/passwd" "$ROOT/etc/shadow"
echo -ne "\n/bin/fooshell\n" | systemd-firstboot --root="$ROOT" --prompt-root-shell
grep -q "^root:.*:0:0:.*:/bin/fooshell$" "$ROOT/etc/passwd"
# Existing files should not get overwritten
@@ -204,15 +238,46 @@ grep -q "^root:.*:0:0:.*:/bin/barshell$" "$ROOT/etc/passwd"
# Re-enable pipefail
set -o pipefail
+# --prompt-* options with credentials. Unfortunately, with --root the
+# --systemd.firstboot kernel command line option is ignored, so that can't be
+# --tested.
+rm -fr "$ROOT"
+mkdir -p "$ROOT/bin"
+touch "$ROOT/bin/fooshell" "$ROOT/bin/barshell"
+systemd-run --wait --pipe --service-type=exec \
+ -p SetCredential=firstboot.locale:foo \
+ -p SetCredential=firstboot.locale-messages:bar \
+ -p SetCredential=firstboot.keymap:foo \
+ -p SetCredential=firstboot.timezone:Europe/Berlin \
+ -p SetCredential=passwd.hashed-password.root:"$ROOT_HASHED_PASSWORD1" \
+ -p SetCredential=passwd.shell.root:/bin/fooshell \
+ systemd-firstboot \
+ --root="$ROOT" \
+ --prompt-locale \
+ --prompt-keymap \
+ --prompt-timezone \
+ --prompt-root-password \
+ --prompt-root-shell \
+ </dev/null
+grep -q "LANG=foo" "$ROOT$LOCALE_PATH"
+grep -q "LC_MESSAGES=bar" "$ROOT$LOCALE_PATH"
+grep -q "KEYMAP=foo" "$ROOT/etc/vconsole.conf"
+readlink "$ROOT/etc/localtime" | grep -q "Europe/Berlin$"
+grep -q "^root:x:0:0:.*:/bin/fooshell$" "$ROOT/etc/passwd"
+grep -q "^root:$ROOT_HASHED_PASSWORD1:" "$ROOT/etc/shadow"
+
# Assorted tests
rm -fr "$ROOT"
mkdir "$ROOT"
systemd-firstboot --root="$ROOT" --setup-machine-id
grep -E "[a-z0-9]{32}" "$ROOT/etc/machine-id"
+rm -fv "$ROOT/etc/machine-id"
systemd-firstboot --root="$ROOT" --delete-root-password
-diff <(echo) <(awk -F: '/^root/ { print $2; }' "$ROOT/etc/shadow")
+grep -q "^root:x:0:0:" "$ROOT/etc/passwd"
+grep -q "^root::" "$ROOT/etc/shadow"
+rm -fv "$ROOT/etc/passwd" "$ROOT/etc/shadow"
(! systemd-firstboot --root="$ROOT" --root-shell=/bin/nonexistentshell)
(! systemd-firstboot --root="$ROOT" --machine-id=invalidmachineid)
diff --git a/test/units/TEST-82-SOFTREBOOT.sh b/test/units/TEST-82-SOFTREBOOT.sh
index f86bc92..9f3d406 100755
--- a/test/units/TEST-82-SOFTREBOOT.sh
+++ b/test/units/TEST-82-SOFTREBOOT.sh
@@ -19,6 +19,21 @@ at_exit() {
trap at_exit EXIT
+# Because this test tests soft-reboot, we have to get rid of the symlink we put at
+# /run/nextroot to allow rebooting into the previous snapshot if the test fails for
+# the duration of the test. However, let's make sure we put the symlink back in place
+# if the test fails.
+if [[ -L /run/nextroot ]]; then
+ at_error() {
+ mountpoint -q /run/nextroot && umount -R /run/nextroot
+ rm -rf /run/nextroot
+ ln -sf /snapshot /run/nextroot
+ }
+
+ trap at_error ERR
+ rm -f /run/nextroot
+fi
+
systemd-analyze log-level debug
export SYSTEMD_LOG_LEVEL=debug