]>
Commit | Line | Data |
---|---|---|
ee07fff0 YW |
1 | #!/usr/bin/env bash |
2 | # SPDX-License-Identifier: LGPL-2.1-or-later | |
3 | set -eux | |
4 | set -o pipefail | |
5 | ||
6 | if systemd-detect-virt --quiet --container; then | |
7 | echo "running on container, skipping." | |
8 | exit 0 | |
9 | fi | |
10 | ||
11 | if ! command -v bootctl >/dev/null; then | |
12 | echo "bootctl not found, skipping." | |
13 | exit 0 | |
14 | fi | |
15 | ||
26fff16b FB |
16 | if [[ ! -d /usr/lib/systemd/boot/efi ]]; then |
17 | echo "sd-boot is not installed, skipping." | |
18 | exit 0 | |
19 | fi | |
20 | ||
ee07fff0 YW |
21 | # shellcheck source=test/units/util.sh |
22 | . "$(dirname "$0")"/util.sh | |
23 | ||
24 | # shellcheck source=test/units/test-control.sh | |
25 | . "$(dirname "$0")"/test-control.sh | |
26 | ||
27 | basic_tests() { | |
28 | bootctl "$@" --help | |
29 | bootctl "$@" --version | |
30 | ||
31 | bootctl "$@" install --make-entry-directory=yes | |
32 | bootctl "$@" remove --make-entry-directory=yes | |
33 | ||
34 | bootctl "$@" install --all-architectures | |
35 | bootctl "$@" remove --all-architectures | |
36 | ||
37 | bootctl "$@" install --make-entry-directory=yes --all-architectures | |
38 | bootctl "$@" remove --make-entry-directory=yes --all-architectures | |
39 | ||
40 | bootctl "$@" install | |
41 | (! bootctl "$@" update) | |
42 | bootctl "$@" update --graceful | |
43 | ||
44 | bootctl "$@" is-installed | |
45 | bootctl "$@" is-installed --graceful | |
46 | bootctl "$@" random-seed | |
47 | ||
48 | bootctl "$@" | |
49 | bootctl "$@" status | |
50 | bootctl "$@" status --quiet | |
51 | bootctl "$@" list | |
52 | bootctl "$@" list --quiet | |
53 | bootctl "$@" list --json=short | |
54 | bootctl "$@" list --json=pretty | |
55 | ||
56 | bootctl "$@" remove | |
57 | (! bootctl "$@" is-installed) | |
58 | (! bootctl "$@" is-installed --graceful) | |
59 | } | |
60 | ||
61 | testcase_bootctl_basic() { | |
8c9d241c RM |
62 | assert_in "$(bootctl --print-esp-path)" "^(/boot/|/efi)$" |
63 | assert_in "$(bootctl --print-boot-path)" "^(/boot/|/efi)$" | |
ee07fff0 YW |
64 | bootctl --print-root-device |
65 | ||
66 | basic_tests | |
67 | } | |
68 | ||
69 | cleanup_image() ( | |
70 | set +e | |
71 | ||
72 | if [[ -z "${IMAGE_DIR:-}" ]]; then | |
73 | return 0 | |
74 | fi | |
75 | ||
76 | umount "${IMAGE_DIR}/root" | |
77 | ||
78 | if [[ -n "${LOOPDEV:-}" ]]; then | |
79 | losetup -d "${LOOPDEV}" | |
80 | unset LOOPDEV | |
81 | fi | |
82 | ||
83 | udevadm settle | |
84 | ||
85 | rm -rf "${IMAGE_DIR}" | |
86 | unset IMAGE_DIR | |
87 | ||
88 | return 0 | |
89 | ) | |
90 | ||
91 | testcase_bootctl_image() { | |
92 | IMAGE_DIR="$(mktemp --directory /tmp/test-bootctl.XXXXXXXXXX)" | |
93 | trap cleanup_image RETURN | |
94 | ||
95 | truncate -s 256m "${IMAGE_DIR}/image" | |
96 | ||
97 | cat >"${IMAGE_DIR}/partscript" <<EOF | |
98 | label: gpt | |
99 | type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B name=esp size=64M | |
100 | type=0FC63DAF-8483-4772-8E79-3D69D8477DE4 name=root size=64M bootable | |
101 | type=BC13C2FF-59E6-4262-A352-B275FD6F7172 name=boot | |
102 | EOF | |
103 | ||
104 | LOOPDEV="$(losetup --show -P -f "${IMAGE_DIR}/image")" | |
105 | sfdisk "$LOOPDEV" <"${IMAGE_DIR}/partscript" | |
106 | ||
107 | udevadm settle | |
108 | ||
109 | mkfs.vfat -n esp "${LOOPDEV}p1" | |
110 | mkfs.ext4 -L root "${LOOPDEV}p2" | |
111 | mkfs.ext4 -L boot "${LOOPDEV}p3" | |
112 | ||
113 | mkdir -p "${IMAGE_DIR}/root" | |
114 | mount -t ext4 "${LOOPDEV}p2" "${IMAGE_DIR}/root" | |
115 | ||
116 | mkdir -p "${IMAGE_DIR}/root/efi" | |
117 | mkdir -p "${IMAGE_DIR}/root/boot" | |
118 | mkdir -p "${IMAGE_DIR}/root/etc" | |
119 | mkdir -p "${IMAGE_DIR}/root/usr/lib" | |
120 | if [[ -f /usr/lib/os-release ]]; then | |
121 | cp /usr/lib/os-release "${IMAGE_DIR}/root/usr/lib/." | |
122 | ln -s ../usr/lib/os-release "${IMAGE_DIR}/root/etc/os-release" | |
123 | else | |
124 | cp -a /etc/os-release "${IMAGE_DIR}/root/etc/." | |
125 | fi | |
126 | ||
127 | umount "${IMAGE_DIR}/root" | |
128 | ||
129 | assert_eq "$(bootctl --image "${IMAGE_DIR}/image" --print-esp-path)" "/run/systemd/mount-rootfs/efi" | |
130 | assert_eq "$(bootctl --image "${IMAGE_DIR}/image" --print-esp-path --esp-path=/efi)" "/run/systemd/mount-rootfs/efi" | |
131 | assert_eq "$(bootctl --image "${IMAGE_DIR}/image" --print-boot-path)" "/run/systemd/mount-rootfs/boot" | |
132 | assert_eq "$(bootctl --image "${IMAGE_DIR}/image" --print-boot-path --boot-path=/boot)" "/run/systemd/mount-rootfs/boot" | |
133 | ||
134 | # FIXME: This provides spurious result. | |
135 | bootctl --image "${IMAGE_DIR}/image" --print-root-device || : | |
136 | ||
137 | basic_tests --image "${IMAGE_DIR}/image" | |
138 | } | |
139 | ||
140 | cleanup_raid() ( | |
141 | set +e | |
142 | ||
143 | if [[ -z "${IMAGE_DIR:-}" ]]; then | |
144 | return 0 | |
145 | fi | |
146 | ||
147 | systemd-umount "${IMAGE_DIR}/root/efi" | |
148 | systemd-umount "${IMAGE_DIR}/root/boot" | |
149 | systemd-umount "${IMAGE_DIR}/root" | |
150 | ||
151 | mdadm --misc --stop /dev/md/raid-esp | |
152 | mdadm --misc --stop /dev/md/raid-root | |
153 | ||
154 | if [[ -n "${LOOPDEV1:-}" ]]; then | |
155 | mdadm --misc --force --zero-superblock "${LOOPDEV1}p1" | |
156 | mdadm --misc --force --zero-superblock "${LOOPDEV1}p2" | |
157 | fi | |
158 | ||
159 | if [[ -n "${LOOPDEV2:-}" ]]; then | |
160 | mdadm --misc --force --zero-superblock "${LOOPDEV2}p1" | |
161 | mdadm --misc --force --zero-superblock "${LOOPDEV2}p2" | |
162 | fi | |
163 | ||
164 | udevadm settle | |
165 | ||
166 | if [[ -n "${LOOPDEV1:-}" ]]; then | |
167 | mdadm --misc --force --zero-superblock "${LOOPDEV1}p1" | |
168 | mdadm --misc --force --zero-superblock "${LOOPDEV1}p2" | |
169 | losetup -d "${LOOPDEV1}" | |
170 | unset LOOPDEV1 | |
171 | fi | |
172 | ||
173 | if [[ -n "${LOOPDEV2:-}" ]]; then | |
174 | mdadm --misc --force --zero-superblock "${LOOPDEV2}p1" | |
175 | mdadm --misc --force --zero-superblock "${LOOPDEV2}p2" | |
176 | losetup -d "${LOOPDEV2}" | |
177 | unset LOOPDEV2 | |
178 | fi | |
179 | ||
180 | udevadm settle | |
181 | ||
182 | rm -rf "${IMAGE_DIR}" | |
183 | ||
184 | return 0 | |
185 | ) | |
186 | ||
187 | testcase_bootctl_raid() { | |
188 | if ! command -v mdadm >/dev/null; then | |
189 | echo "mdadm not found, skipping." | |
190 | return 0 | |
191 | fi | |
192 | ||
193 | if ! command -v mkfs.btrfs >/dev/null; then | |
194 | echo "mkfs.btrfs not found, skipping." | |
195 | return 0 | |
196 | fi | |
197 | ||
198 | IMAGE_DIR="$(mktemp --directory /tmp/test-bootctl.XXXXXXXXXX)" | |
199 | trap cleanup_raid RETURN | |
200 | ||
201 | truncate -s 256m "${IMAGE_DIR}/image1" | |
202 | truncate -s 256m "${IMAGE_DIR}/image2" | |
203 | ||
204 | cat >"${IMAGE_DIR}/partscript" <<EOF | |
205 | label: gpt | |
206 | type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B name=esp size=64M | |
207 | type=0FC63DAF-8483-4772-8E79-3D69D8477DE4 name=root size=64M bootable | |
208 | type=BC13C2FF-59E6-4262-A352-B275FD6F7172 name=boot | |
209 | EOF | |
210 | ||
211 | LOOPDEV1="$(losetup --show -P -f "${IMAGE_DIR}/image1")" | |
212 | LOOPDEV2="$(losetup --show -P -f "${IMAGE_DIR}/image2")" | |
213 | sfdisk "$LOOPDEV1" <"${IMAGE_DIR}/partscript" | |
214 | sfdisk "$LOOPDEV2" <"${IMAGE_DIR}/partscript" | |
215 | ||
216 | udevadm settle | |
217 | ||
218 | echo y | mdadm --create /dev/md/raid-esp --name "raid-esp" "${LOOPDEV1}p1" "${LOOPDEV2}p1" -v -f --level=1 --raid-devices=2 | |
219 | mkfs.vfat /dev/md/raid-esp | |
220 | echo y | mdadm --create /dev/md/raid-root --name "raid-root" "${LOOPDEV1}p2" "${LOOPDEV2}p2" -v -f --level=1 --raid-devices=2 | |
221 | mkfs.ext4 /dev/md/raid-root | |
222 | mkfs.btrfs -f -M -d raid1 -m raid1 -L "raid-boot" "${LOOPDEV1}p3" "${LOOPDEV2}p3" | |
223 | ||
224 | mkdir -p "${IMAGE_DIR}/root" | |
225 | mount -t ext4 /dev/md/raid-root "${IMAGE_DIR}/root" | |
226 | mkdir -p "${IMAGE_DIR}/root/efi" | |
227 | mount -t vfat /dev/md/raid-esp "${IMAGE_DIR}/root/efi" | |
228 | mkdir -p "${IMAGE_DIR}/root/boot" | |
229 | mount -t btrfs "${LOOPDEV1}p3" "${IMAGE_DIR}/root/boot" | |
230 | ||
231 | mkdir -p "${IMAGE_DIR}/root/etc" | |
232 | mkdir -p "${IMAGE_DIR}/root/usr/lib" | |
233 | if [[ -f /usr/lib/os-release ]]; then | |
234 | cp /usr/lib/os-release "${IMAGE_DIR}/root/usr/lib/." | |
235 | ln -s ../usr/lib/os-release "${IMAGE_DIR}/root/etc/os-release" | |
236 | else | |
237 | cp -a /etc/os-release "${IMAGE_DIR}/root/etc/." | |
238 | fi | |
239 | ||
240 | # find_esp() does not support md RAID partition. | |
241 | (! bootctl --root "${IMAGE_DIR}/root" --print-esp-path) | |
242 | (! bootctl --root "${IMAGE_DIR}/root" --print-esp-path --esp-path=/efi) | |
243 | ||
244 | # If the verification is relaxed, it accepts md RAID partition. | |
245 | assert_eq "$(SYSTEMD_RELAX_ESP_CHECKS=yes bootctl --root "${IMAGE_DIR}/root" --print-esp-path)" "${IMAGE_DIR}/root/efi" | |
246 | assert_eq "$(SYSTEMD_RELAX_ESP_CHECKS=yes bootctl --root "${IMAGE_DIR}/root" --print-esp-path --esp-path=/efi)" "${IMAGE_DIR}/root/efi" | |
247 | ||
248 | # find_xbootldr() does not support btrfs RAID, and bootctl tries to fall back to use ESP. | |
249 | # (but as in the above, the ESP verification is also failed in this case). | |
250 | (! bootctl --root "${IMAGE_DIR}/root" --print-boot-path) | |
251 | (! bootctl --root "${IMAGE_DIR}/root" --print-boot-path --boot-path=/boot) | |
252 | ||
253 | # If the verification for ESP is relaxed, bootctl falls back to use ESP. | |
254 | assert_eq "$(SYSTEMD_RELAX_ESP_CHECKS=yes bootctl --root "${IMAGE_DIR}/root" --print-boot-path)" "${IMAGE_DIR}/root/efi" | |
255 | ||
256 | # If the verification is relaxed, it accepts the xbootldr partition. | |
257 | assert_eq "$(SYSTEMD_RELAX_XBOOTLDR_CHECKS=yes bootctl --root "${IMAGE_DIR}/root" --print-boot-path)" "${IMAGE_DIR}/root/boot" | |
258 | assert_eq "$(SYSTEMD_RELAX_XBOOTLDR_CHECKS=yes bootctl --root "${IMAGE_DIR}/root" --print-boot-path --boot-path=/boot)" "${IMAGE_DIR}/root/boot" | |
259 | ||
260 | # FIXME: This provides spurious result. | |
261 | bootctl --root "${IMAGE_DIR}/root" --print-root-device || : | |
262 | ||
263 | SYSTEMD_RELAX_ESP_CHECKS=yes SYSTEMD_RELAX_XBOOTLDR_CHECKS=yes basic_tests --root "${IMAGE_DIR}/root" | |
264 | } | |
265 | ||
79ec3995 LP |
266 | testcase_bootctl_varlink() { |
267 | varlinkctl call --collect /run/systemd/io.systemd.BootControl io.systemd.BootControl.ListBootEntries '{}' | |
268 | ||
8c9d241c RM |
269 | # We may have UEFI in the test environment. |
270 | # If we don't have UEFI then we can test whether bootctl's varlink API fails cleanly. | |
271 | # If we do have UEFI then the rest of the clean fail tests should be skipped. | |
272 | 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 | |
273 | return 0 | |
274 | fi | |
275 | (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 | |
276 | (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 | |
79ec3995 LP |
277 | } |
278 | ||
ee07fff0 | 279 | run_testcases |