]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/units/testsuite-50.dissect.sh
TEST-50-DISSECT: Don't log image contents to console
[thirdparty/systemd.git] / test / units / testsuite-50.dissect.sh
CommitLineData
ccb26715
FS
1#!/usr/bin/env bash
2# SPDX-License-Identifier: LGPL-2.1-or-later
3# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
4# ex: ts=8 sw=4 sts=4 et filetype=sh
5# shellcheck disable=SC2233,SC2235
6set -eux
7set -o pipefail
8
9# shellcheck source=test/units/util.sh
10. "$(dirname "$0")"/util.sh
11
69dc36f6
DDM
12BIND_LOG_SOCKETS=(
13 --property BindReadOnlyPaths=/dev/log
14 --property BindReadOnlyPaths=/run/systemd/journal/socket
15 --property BindReadOnlyPaths=/run/systemd/journal/stdout
16)
17
5d259f12
FS
18systemd-dissect --json=short "$MINIMAL_IMAGE.raw" | \
19 grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"'
ccb26715 20systemd-dissect "$MINIMAL_IMAGE.raw" | grep -q -F "MARKER=1"
c77dad70 21# shellcheck disable=SC2153
ccb26715
FS
22systemd-dissect "$MINIMAL_IMAGE.raw" | grep -q -F -f <(sed 's/"//g' "$OS_RELEASE")
23
24systemd-dissect --list "$MINIMAL_IMAGE.raw" | grep -q '^etc/os-release$'
5d259f12
FS
25systemd-dissect --mtree "$MINIMAL_IMAGE.raw" --mtree-hash yes | \
26 grep -qe "^./usr/bin/cat type=file mode=0755 uid=0 gid=0 size=[0-9]* sha256sum=[a-z0-9]*$"
27systemd-dissect --mtree "$MINIMAL_IMAGE.raw" --mtree-hash no | \
28 grep -qe "^./usr/bin/cat type=file mode=0755 uid=0 gid=0 size=[0-9]*$"
ccb26715
FS
29
30read -r SHA256SUM1 _ < <(systemd-dissect --copy-from "$MINIMAL_IMAGE.raw" etc/os-release | sha256sum)
31test "$SHA256SUM1" != ""
32read -r SHA256SUM2 _ < <(systemd-dissect --read-only --with "$MINIMAL_IMAGE.raw" sha256sum etc/os-release)
33test "$SHA256SUM2" != ""
34test "$SHA256SUM1" = "$SHA256SUM2"
35
36if systemctl --version | grep -qF -- "+LIBARCHIVE" ; then
37 # Make sure tarballs are reproducible
38 read -r SHA256SUM1 _ < <(systemd-dissect --make-archive "$MINIMAL_IMAGE.raw" | sha256sum)
39 test "$SHA256SUM1" != ""
40 read -r SHA256SUM2 _ < <(systemd-dissect --make-archive "$MINIMAL_IMAGE.raw" | sha256sum)
41 test "$SHA256SUM2" != ""
42 test "$SHA256SUM1" = "$SHA256SUM2"
43 # Also check that a file we expect to be there is there
44 systemd-dissect --make-archive "$MINIMAL_IMAGE.raw" | tar t | grep etc/os-release
45fi
46
47mv "$MINIMAL_IMAGE.verity" "$MINIMAL_IMAGE.fooverity"
48mv "$MINIMAL_IMAGE.roothash" "$MINIMAL_IMAGE.foohash"
5d259f12
FS
49systemd-dissect "$MINIMAL_IMAGE.raw" \
50 --json=short \
51 --root-hash="$MINIMAL_IMAGE_ROOTHASH" \
52 --verity-data="$MINIMAL_IMAGE.fooverity" | \
53 grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"'
54systemd-dissect "$MINIMAL_IMAGE.raw" \
55 --root-hash="$MINIMAL_IMAGE_ROOTHASH" \
56 --verity-data="$MINIMAL_IMAGE.fooverity" | \
57 grep -q -F "MARKER=1"
58systemd-dissect "$MINIMAL_IMAGE.raw" \
59 --root-hash="$MINIMAL_IMAGE_ROOTHASH" \
60 --verity-data="$MINIMAL_IMAGE.fooverity" | \
61 grep -q -F -f <(sed 's/"//g' "$OS_RELEASE")
ccb26715
FS
62mv "$MINIMAL_IMAGE.fooverity" "$MINIMAL_IMAGE.verity"
63mv "$MINIMAL_IMAGE.foohash" "$MINIMAL_IMAGE.roothash"
64
65mkdir -p "$IMAGE_DIR/mount" "$IMAGE_DIR/mount2"
66systemd-dissect --mount "$MINIMAL_IMAGE.raw" "$IMAGE_DIR/mount"
67grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/usr/lib/os-release"
68grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/etc/os-release"
69grep -q -F "MARKER=1" "$IMAGE_DIR/mount/usr/lib/os-release"
70# Verity volume should be shared (opened only once)
71systemd-dissect --mount "$MINIMAL_IMAGE.raw" "$IMAGE_DIR/mount2"
72verity_count=$(find /dev/mapper/ -name "*verity*" | wc -l)
73# In theory we should check that count is exactly one. In practice, libdevmapper
74# randomly and unpredictably fails with an unhelpful EINVAL when a device is open
75# (and even mounted and in use), so best-effort is the most we can do for now
76if [[ "$verity_count" -lt 1 ]]; then
77 echo "Verity device $MINIMAL_IMAGE.raw not found in /dev/mapper/"
78 exit 1
79fi
80systemd-dissect --umount "$IMAGE_DIR/mount"
81systemd-dissect --umount "$IMAGE_DIR/mount2"
82
69dc36f6 83systemd-run -P -p RootImage="$MINIMAL_IMAGE.raw" "${BIND_LOG_SOCKETS[@]}" cat /usr/lib/os-release | grep -q -F "MARKER=1"
ccb26715
FS
84mv "$MINIMAL_IMAGE.verity" "$MINIMAL_IMAGE.fooverity"
85mv "$MINIMAL_IMAGE.roothash" "$MINIMAL_IMAGE.foohash"
5d259f12
FS
86systemd-run -P \
87 -p RootImage="$MINIMAL_IMAGE.raw" \
88 -p RootHash="$MINIMAL_IMAGE.foohash" \
89 -p RootVerity="$MINIMAL_IMAGE.fooverity" \
69dc36f6 90 "${BIND_LOG_SOCKETS[@]}" \
5d259f12 91 cat /usr/lib/os-release | grep -q -F "MARKER=1"
ccb26715 92# Let's use the long option name just here as a test
5d259f12
FS
93systemd-run -P \
94 --property RootImage="$MINIMAL_IMAGE.raw" \
95 --property RootHash="$MINIMAL_IMAGE_ROOTHASH" \
96 --property RootVerity="$MINIMAL_IMAGE.fooverity" \
69dc36f6 97 "${BIND_LOG_SOCKETS[@]}" \
5d259f12 98 cat /usr/lib/os-release | grep -q -F "MARKER=1"
ccb26715
FS
99mv "$MINIMAL_IMAGE.fooverity" "$MINIMAL_IMAGE.verity"
100mv "$MINIMAL_IMAGE.foohash" "$MINIMAL_IMAGE.roothash"
101
102# Derive partition UUIDs from root hash, in UUID syntax
103ROOT_UUID="$(systemd-id128 -u show "$(head -c 32 "$MINIMAL_IMAGE.roothash")" -u | tail -n 1 | cut -b 6-)"
104VERITY_UUID="$(systemd-id128 -u show "$(tail -c 32 "$MINIMAL_IMAGE.roothash")" -u | tail -n 1 | cut -b 6-)"
105
5d259f12
FS
106systemd-dissect --json=short \
107 --root-hash "$MINIMAL_IMAGE_ROOTHASH" \
108 "$MINIMAL_IMAGE.gpt" | \
109 grep -q '{"rw":"ro","designator":"root","partition_uuid":"'"$ROOT_UUID"'","partition_label":"Root Partition","fstype":"squashfs","architecture":"'"$ARCHITECTURE"'","verity":"signed",'
110systemd-dissect --json=short \
111 --root-hash "$MINIMAL_IMAGE_ROOTHASH" \
112 "$MINIMAL_IMAGE.gpt" | \
113 grep -q '{"rw":"ro","designator":"root-verity","partition_uuid":"'"$VERITY_UUID"'","partition_label":"Verity Partition","fstype":"DM_verity_hash","architecture":"'"$ARCHITECTURE"'","verity":null,'
ccb26715 114if [[ -n "${OPENSSL_CONFIG:-}" ]]; then
5d259f12
FS
115 systemd-dissect --json=short \
116 --root-hash "$MINIMAL_IMAGE_ROOTHASH" \
117 "$MINIMAL_IMAGE.gpt" | \
118 grep -qE '{"rw":"ro","designator":"root-verity-sig","partition_uuid":"'".*"'","partition_label":"Signature Partition","fstype":"verity_hash_signature","architecture":"'"$ARCHITECTURE"'","verity":null,'
ccb26715
FS
119fi
120systemd-dissect --root-hash "$MINIMAL_IMAGE_ROOTHASH" "$MINIMAL_IMAGE.gpt" | grep -q -F "MARKER=1"
121systemd-dissect --root-hash "$MINIMAL_IMAGE_ROOTHASH" "$MINIMAL_IMAGE.gpt" | grep -q -F -f <(sed 's/"//g' "$OS_RELEASE")
122
123# Test image policies
124systemd-dissect --validate "$MINIMAL_IMAGE.gpt"
125systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy='*'
126(! systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy='~')
127(! systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy='-')
128(! systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=absent)
129(! systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=swap=unprotected+encrypted+verity)
130systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=unprotected
131systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=verity
132systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=verity:root-verity-sig=unused+absent
133systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=verity:swap=absent
134systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=verity:swap=absent+unprotected
135(! systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=verity:root-verity=unused+absent)
136systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=signed
137(! systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=signed:root-verity-sig=unused+absent)
138(! systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=signed:root-verity=unused+absent)
139
140# Test RootImagePolicy= unit file setting
5d259f12
FS
141systemd-run --wait -P \
142 -p RootImage="$MINIMAL_IMAGE.gpt" \
143 -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \
144 -p MountAPIVFS=yes \
69dc36f6 145 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
146 cat /usr/lib/os-release | grep -q -F "MARKER=1"
147systemd-run --wait -P \
148 -p RootImage="$MINIMAL_IMAGE.gpt" \
149 -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \
150 -p RootImagePolicy='*' \
151 -p MountAPIVFS=yes \
69dc36f6 152 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
153 cat /usr/lib/os-release | grep -q -F "MARKER=1"
154(! systemd-run --wait -P \
155 -p RootImage="$MINIMAL_IMAGE.gpt" \
156 -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \
157 -p RootImagePolicy='~' \
158 -p MountAPIVFS=yes \
69dc36f6 159 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
160 cat /usr/lib/os-release | grep -q -F "MARKER=1")
161(! systemd-run --wait -P \
162 -p RootImage="$MINIMAL_IMAGE.gpt" \
163 -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \
164 -p RootImagePolicy='-' \
165 -p MountAPIVFS=yes \
69dc36f6 166 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
167 cat /usr/lib/os-release | grep -q -F "MARKER=1")
168(! systemd-run --wait -P \
169 -p RootImage="$MINIMAL_IMAGE.gpt" \
170 -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \
171 -p RootImagePolicy='root=absent' \
172 -p MountAPIVFS=yes \
69dc36f6 173 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
174 cat /usr/lib/os-release | grep -q -F "MARKER=1")
175systemd-run --wait -P \
176 -p RootImage="$MINIMAL_IMAGE.gpt" \
177 -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \
178 -p RootImagePolicy='root=verity' \
179 -p MountAPIVFS=yes \
69dc36f6 180 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
181 cat /usr/lib/os-release | grep -q -F "MARKER=1"
182systemd-run --wait -P \
183 -p RootImage="$MINIMAL_IMAGE.gpt" \
184 -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \
185 -p RootImagePolicy='root=signed' \
186 -p MountAPIVFS=yes \
69dc36f6 187 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
188 cat /usr/lib/os-release | grep -q -F "MARKER=1"
189(! systemd-run --wait -P \
190 -p RootImage="$MINIMAL_IMAGE.gpt" \
191 -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \
192 -p RootImagePolicy='root=encrypted' \
193 -p MountAPIVFS=yes \
69dc36f6 194 "${BIND_LOG_SOCKETS[@]}" \
5d259f12 195 cat /usr/lib/os-release | grep -q -F "MARKER=1")
ccb26715
FS
196
197systemd-dissect --root-hash "$MINIMAL_IMAGE_ROOTHASH" --mount "$MINIMAL_IMAGE.gpt" "$IMAGE_DIR/mount"
198grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/usr/lib/os-release"
199grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/etc/os-release"
200grep -q -F "MARKER=1" "$IMAGE_DIR/mount/usr/lib/os-release"
201systemd-dissect --umount "$IMAGE_DIR/mount"
202
203systemd-dissect --root-hash "$MINIMAL_IMAGE_ROOTHASH" --mount "$MINIMAL_IMAGE.gpt" --in-memory "$IMAGE_DIR/mount"
204grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/usr/lib/os-release"
205grep -q -F -f "$OS_RELEASE" "$IMAGE_DIR/mount/etc/os-release"
206grep -q -F "MARKER=1" "$IMAGE_DIR/mount/usr/lib/os-release"
207systemd-dissect --umount "$IMAGE_DIR/mount"
208
209# add explicit -p MountAPIVFS=yes once to test the parser
5d259f12
FS
210systemd-run -P \
211 -p RootImage="$MINIMAL_IMAGE.gpt" \
212 -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \
213 -p MountAPIVFS=yes \
69dc36f6 214 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
215 cat /usr/lib/os-release | grep -q -F "MARKER=1"
216systemd-run -P \
217 -p RootImage="$MINIMAL_IMAGE.raw" \
218 -p RootImageOptions="root:nosuid,dev home:ro,dev ro,noatime" \
69dc36f6 219 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
220 mount | grep -F "squashfs" | grep -q -F "nosuid"
221systemd-run -P \
222 -p RootImage="$MINIMAL_IMAGE.gpt" \
223 -p RootImageOptions="root:ro,noatime root:ro,dev" \
69dc36f6 224 "${BIND_LOG_SOCKETS[@]}" \
5d259f12 225 mount | grep -F "squashfs" | grep -q -F "noatime"
ccb26715
FS
226
227mkdir -p "$IMAGE_DIR/result"
228cat >/run/systemd/system/testservice-50a.service <<EOF
229[Service]
230Type=oneshot
231ExecStart=bash -c "mount >/run/result/a"
232BindPaths=$IMAGE_DIR/result:/run/result
233TemporaryFileSystem=/run
234RootImage=$MINIMAL_IMAGE.raw
235RootImageOptions=root:ro,noatime home:ro,dev relatime,dev
236RootImageOptions=nosuid,dev
69dc36f6 237BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout
ccb26715
FS
238EOF
239systemctl start testservice-50a.service
240grep -F "squashfs" "$IMAGE_DIR/result/a" | grep -q -F "noatime"
241grep -F "squashfs" "$IMAGE_DIR/result/a" | grep -q -F -v "nosuid"
242
243cat >/run/systemd/system/testservice-50b.service <<EOF
244[Service]
245Type=oneshot
246ExecStart=bash -c "mount >/run/result/b"
247BindPaths=$IMAGE_DIR/result:/run/result
248TemporaryFileSystem=/run
249RootImage=$MINIMAL_IMAGE.gpt
250RootImageOptions=root:ro,noatime,nosuid home:ro,dev nosuid,dev
251RootImageOptions=home:ro,dev nosuid,dev,%%foo
252# this is the default, but let's specify once to test the parser
253MountAPIVFS=yes
69dc36f6 254BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout
ccb26715
FS
255EOF
256systemctl start testservice-50b.service
257grep -F "squashfs" "$IMAGE_DIR/result/b" | grep -q -F "noatime"
258
259# Check that specifier escape is applied %%foo → %foo
5d259f12
FS
260busctl get-property org.freedesktop.systemd1 \
261 /org/freedesktop/systemd1/unit/testservice_2d50b_2eservice \
262 org.freedesktop.systemd1.Service RootImageOptions | grep -F "nosuid,dev,%foo"
ccb26715
FS
263
264# Now do some checks with MountImages, both by itself, with options and in combination with RootImage, and as single FS or GPT image
5d259f12
FS
265systemd-run -P \
266 -p MountImages="$MINIMAL_IMAGE.gpt:/run/img1 $MINIMAL_IMAGE.raw:/run/img2" \
267 cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1"
268systemd-run -P \
269 -p MountImages="$MINIMAL_IMAGE.gpt:/run/img1 $MINIMAL_IMAGE.raw:/run/img2" \
270 cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1"
271systemd-run -P \
272 -p MountImages="$MINIMAL_IMAGE.gpt:/run/img1 $MINIMAL_IMAGE.raw:/run/img2:nosuid,dev" \
273 mount | grep -F "squashfs" | grep -q -F "nosuid"
274systemd-run -P \
275 -p MountImages="$MINIMAL_IMAGE.gpt:/run/img1:root:nosuid $MINIMAL_IMAGE.raw:/run/img2:home:suid" \
276 mount | grep -F "squashfs" | grep -q -F "nosuid"
277systemd-run -P \
278 -p MountImages="$MINIMAL_IMAGE.raw:/run/img2\:3" \
279 cat /run/img2:3/usr/lib/os-release | grep -q -F "MARKER=1"
280systemd-run -P \
281 -p MountImages="$MINIMAL_IMAGE.raw:/run/img2\:3:nosuid" \
282 mount | grep -F "squashfs" | grep -q -F "nosuid"
283systemd-run -P \
284 -p TemporaryFileSystem=/run \
285 -p RootImage="$MINIMAL_IMAGE.raw" \
286 -p MountImages="$MINIMAL_IMAGE.gpt:/run/img1 $MINIMAL_IMAGE.raw:/run/img2" \
69dc36f6 287 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
288 cat /usr/lib/os-release | grep -q -F "MARKER=1"
289systemd-run -P \
290 -p TemporaryFileSystem=/run \
291 -p RootImage="$MINIMAL_IMAGE.raw" \
292 -p MountImages="$MINIMAL_IMAGE.gpt:/run/img1 $MINIMAL_IMAGE.raw:/run/img2" \
69dc36f6 293 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
294 cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1"
295systemd-run -P \
296 -p TemporaryFileSystem=/run \
297 -p RootImage="$MINIMAL_IMAGE.gpt" \
298 -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \
299 -p MountImages="$MINIMAL_IMAGE.gpt:/run/img1 $MINIMAL_IMAGE.raw:/run/img2" \
69dc36f6 300 "${BIND_LOG_SOCKETS[@]}" \
5d259f12 301 cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1"
ccb26715
FS
302cat >/run/systemd/system/testservice-50c.service <<EOF
303[Service]
304MountAPIVFS=yes
305TemporaryFileSystem=/run
306RootImage=$MINIMAL_IMAGE.raw
69dc36f6 307BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout
ccb26715
FS
308MountImages=$MINIMAL_IMAGE.gpt:/run/img1:root:noatime:home:relatime
309MountImages=$MINIMAL_IMAGE.raw:/run/img2\:3:nosuid
310ExecStart=bash -c "cat /run/img1/usr/lib/os-release >/run/result/c"
311ExecStart=bash -c "cat /run/img2:3/usr/lib/os-release >>/run/result/c"
312ExecStart=bash -c "mount >>/run/result/c"
313BindPaths=$IMAGE_DIR/result:/run/result
314Type=oneshot
315EOF
316systemctl start testservice-50c.service
317grep -q -F "MARKER=1" "$IMAGE_DIR/result/c"
318grep -F "squashfs" "$IMAGE_DIR/result/c" | grep -q -F "noatime"
319grep -F "squashfs" "$IMAGE_DIR/result/c" | grep -q -F -v "nosuid"
320
321# Adding a new mounts at runtime works if the unit is in the active state,
322# so use Type=notify to make sure there's no race condition in the test
323cat >/run/systemd/system/testservice-50d.service <<EOF
324[Service]
325RuntimeMaxSec=300
326Type=notify
327RemainAfterExit=yes
328MountAPIVFS=yes
329PrivateTmp=yes
330ExecStart=sh -c ' \\
331 systemd-notify --ready; \\
332 while [ ! -f /tmp/img/usr/lib/os-release ] || ! grep -q -F MARKER /tmp/img/usr/lib/os-release; do \\
333 sleep 0.1; \\
334 done; \\
335 mount; \\
336 mount | grep -F "on /tmp/img type squashfs" | grep -q -F "nosuid"; \\
337'
338EOF
339systemctl start testservice-50d.service
340
341# Mount twice to exercise mount-beneath (on kernel 6.5+, on older kernels it will just overmount)
342mkdir -p /tmp/wrong/foo
343mksquashfs /tmp/wrong/foo /tmp/wrong.raw
344systemctl mount-image --mkdir testservice-50d.service /tmp/wrong.raw /tmp/img
345test "$(systemctl show -P SubState testservice-50d.service)" = "running"
346systemctl mount-image --mkdir testservice-50d.service "$MINIMAL_IMAGE.raw" /tmp/img root:nosuid
5f42fae2
FS
347# shellcheck disable=SC2016
348timeout 30s bash -xec 'while [[ $(systemctl show -P SubState testservice-50d.service) == running ]]; do sleep .2; done'
ccb26715
FS
349systemctl is-active testservice-50d.service
350
351# ExtensionImages will set up an overlay
5d259f12 352systemd-run -P \
c77dad70 353 --property ExtensionImages=/tmp/app0.raw \
5d259f12 354 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 355 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
356 cat /opt/script0.sh | grep -q -F "extension-release.app0"
357systemd-run -P \
c77dad70 358 --property ExtensionImages=/tmp/app0.raw \
5d259f12 359 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 360 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
361 cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
362systemd-run -P \
c77dad70 363 --property ExtensionImages="/tmp/app0.raw /tmp/app1.raw" \
5d259f12 364 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 365 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
366 cat /opt/script0.sh | grep -q -F "extension-release.app0"
367systemd-run -P \
c77dad70 368 --property ExtensionImages="/tmp/app0.raw /tmp/app1.raw" \
5d259f12 369 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 370 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
371 cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
372systemd-run -P \
c77dad70 373 --property ExtensionImages="/tmp/app0.raw /tmp/app1.raw" \
5d259f12 374 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 375 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
376 cat /opt/script1.sh | grep -q -F "extension-release.app2"
377systemd-run -P \
c77dad70 378 --property ExtensionImages="/tmp/app0.raw /tmp/app1.raw" \
5d259f12 379 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 380 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
381 cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1"
382systemd-run -P \
c77dad70 383 --property ExtensionImages=/tmp/app-nodistro.raw \
5d259f12 384 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 385 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
386 cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
387systemd-run -P \
388 --property ExtensionImages=/etc/service-scoped-test.raw \
389 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 390 "${BIND_LOG_SOCKETS[@]}" \
5d259f12 391 cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123"
ccb26715 392# Check that using a symlink to NAME-VERSION.raw works as long as the symlink has the correct name NAME.raw
c77dad70
DDM
393mkdir -p /tmp/symlink-test/
394cp /tmp/app-nodistro.raw /tmp/symlink-test/app-nodistro-v1.raw
395ln -fs /tmp/symlink-test/app-nodistro-v1.raw /tmp/symlink-test/app-nodistro.raw
5d259f12 396systemd-run -P \
c77dad70 397 --property ExtensionImages=/tmp/symlink-test/app-nodistro.raw \
5d259f12 398 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 399 "${BIND_LOG_SOCKETS[@]}" \
5d259f12 400 cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
ccb26715
FS
401
402# Symlink check again but for confext
403mkdir -p /etc/symlink-test/
404cp /etc/service-scoped-test.raw /etc/symlink-test/service-scoped-test-v1.raw
405ln -fs /etc/symlink-test/service-scoped-test-v1.raw /etc/symlink-test/service-scoped-test.raw
5d259f12
FS
406systemd-run -P \
407 --property ExtensionImages=/etc/symlink-test/service-scoped-test.raw \
408 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 409 "${BIND_LOG_SOCKETS[@]}" \
5d259f12 410 cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123"
ccb26715
FS
411# And again mixing sysext and confext
412systemd-run -P \
c77dad70 413 --property ExtensionImages=/tmp/symlink-test/app-nodistro.raw \
ccb26715 414 --property ExtensionImages=/etc/symlink-test/service-scoped-test.raw \
5d259f12 415 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 416 "${BIND_LOG_SOCKETS[@]}" \
5d259f12 417 cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123"
ccb26715 418systemd-run -P \
c77dad70 419 --property ExtensionImages=/tmp/symlink-test/app-nodistro.raw \
ccb26715 420 --property ExtensionImages=/etc/symlink-test/service-scoped-test.raw \
5d259f12 421 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 422 "${BIND_LOG_SOCKETS[@]}" \
5d259f12 423 cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
ccb26715
FS
424
425cat >/run/systemd/system/testservice-50e.service <<EOF
426[Service]
427MountAPIVFS=yes
428TemporaryFileSystem=/run /var/lib
429StateDirectory=app0
430RootImage=$MINIMAL_IMAGE.raw
c77dad70 431ExtensionImages=/tmp/app0.raw /tmp/app1.raw:nosuid
69dc36f6 432BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout
ccb26715
FS
433# Relevant only for sanitizer runs
434UnsetEnvironment=LD_PRELOAD
435ExecStart=bash -c '/opt/script0.sh | grep ID'
436ExecStart=bash -c '/opt/script1.sh | grep ID'
437Type=oneshot
438RemainAfterExit=yes
439EOF
440systemctl start testservice-50e.service
441systemctl is-active testservice-50e.service
442
443# Check vpick support in ExtensionImages=
444VBASE="vtest$RANDOM"
445VDIR="/tmp/$VBASE.v"
446mkdir "$VDIR"
447
c77dad70
DDM
448ln -s /tmp/app0.raw "$VDIR/${VBASE}_0.raw"
449ln -s /tmp/app1.raw "$VDIR/${VBASE}_1.raw"
ccb26715
FS
450
451systemd-run -P -p ExtensionImages="$VDIR" bash -c '/opt/script1.sh | grep ID'
452
453rm -rf "$VDIR"
454
455# ExtensionDirectories will set up an overlay
456mkdir -p "$IMAGE_DIR/app0" "$IMAGE_DIR/app1" "$IMAGE_DIR/app-nodistro" "$IMAGE_DIR/service-scoped-test"
5d259f12
FS
457(! systemd-run -P \
458 --property ExtensionDirectories="$IMAGE_DIR/nonexistent" \
459 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 460 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
461 cat /opt/script0.sh)
462(! systemd-run -P \
463 --property ExtensionDirectories="$IMAGE_DIR/app0" \
464 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 465 "${BIND_LOG_SOCKETS[@]}" \
5d259f12 466 cat /opt/script0.sh)
c77dad70
DDM
467systemd-dissect --mount /tmp/app0.raw "$IMAGE_DIR/app0"
468systemd-dissect --mount /tmp/app1.raw "$IMAGE_DIR/app1"
469systemd-dissect --mount /tmp/app-nodistro.raw "$IMAGE_DIR/app-nodistro"
ccb26715 470systemd-dissect --mount /etc/service-scoped-test.raw "$IMAGE_DIR/service-scoped-test"
5d259f12
FS
471systemd-run -P \
472 --property ExtensionDirectories="$IMAGE_DIR/app0" \
473 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 474 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
475 cat /opt/script0.sh | grep -q -F "extension-release.app0"
476systemd-run -P \
477 --property ExtensionDirectories="$IMAGE_DIR/app0" \
478 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 479 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
480 cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
481systemd-run -P \
482 --property ExtensionDirectories="$IMAGE_DIR/app0 $IMAGE_DIR/app1" \
483 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 484 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
485 cat /opt/script0.sh | grep -q -F "extension-release.app0"
486systemd-run -P \
487 --property ExtensionDirectories="$IMAGE_DIR/app0 $IMAGE_DIR/app1" \
488 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 489 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
490 cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
491systemd-run -P \
492 --property ExtensionDirectories="$IMAGE_DIR/app0 $IMAGE_DIR/app1" \
493 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 494 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
495 cat /opt/script1.sh | grep -q -F "extension-release.app2"
496systemd-run -P \
497 --property ExtensionDirectories="$IMAGE_DIR/app0 $IMAGE_DIR/app1" \
498 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 499 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
500 cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1"
501systemd-run -P \
502 --property ExtensionDirectories="$IMAGE_DIR/app-nodistro" \
503 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 504 "${BIND_LOG_SOCKETS[@]}" \
5d259f12
FS
505 cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
506systemd-run -P \
507 --property ExtensionDirectories="$IMAGE_DIR/service-scoped-test" \
508 --property RootImage="$MINIMAL_IMAGE.raw" \
69dc36f6 509 "${BIND_LOG_SOCKETS[@]}" \
5d259f12 510 cat /etc/systemd/system/some_file | grep -q -F "MARKER_CONFEXT_123"
ccb26715
FS
511cat >/run/systemd/system/testservice-50f.service <<EOF
512[Service]
513MountAPIVFS=yes
514TemporaryFileSystem=/run /var/lib
515StateDirectory=app0
516RootImage=$MINIMAL_IMAGE.raw
69dc36f6 517BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout
ccb26715
FS
518ExtensionDirectories=$IMAGE_DIR/app0 $IMAGE_DIR/app1
519# Relevant only for sanitizer runs
520UnsetEnvironment=LD_PRELOAD
521ExecStart=bash -c '/opt/script0.sh | grep ID'
522ExecStart=bash -c '/opt/script1.sh | grep ID'
523Type=oneshot
524RemainAfterExit=yes
525EOF
526systemctl start testservice-50f.service
527systemctl is-active testservice-50f.service
528
529# Check vpick support in ExtensionDirectories=
530VBASE="vtest$RANDOM"
531VDIR="/tmp/$VBASE.v"
532mkdir "$VDIR"
533
534ln -s "$IMAGE_DIR/app0" "$VDIR/${VBASE}_0"
535ln -s "$IMAGE_DIR/app1" "$VDIR/${VBASE}_1"
536
537systemd-run -P --property ExtensionDirectories="$VDIR" cat /opt/script1.sh | grep -q -F "extension-release.app2"
538
539rm -rf "$VDIR"
540
541systemd-dissect --umount "$IMAGE_DIR/app0"
542systemd-dissect --umount "$IMAGE_DIR/app1"
543
544# Test that an extension consisting of an empty directory under /etc/extensions/ takes precedence
545mkdir -p /var/lib/extensions/
c77dad70 546ln -s /tmp/app-nodistro.raw /var/lib/extensions/app-nodistro.raw
ccb26715
FS
547systemd-sysext merge
548grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file
549systemd-sysext unmerge
550mkdir -p /etc/extensions/app-nodistro
551systemd-sysext merge
552test ! -e /usr/lib/systemd/system/some_file
553systemd-sysext unmerge
554rmdir /etc/extensions/app-nodistro
555
556# Similar, but go via varlink
557varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.List '{}'
558(! grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file )
559varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.Merge '{}'
560grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file
561varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.Refresh '{}'
562grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file
563varlinkctl call /run/systemd/io.systemd.sysext io.systemd.sysext.Unmerge '{}'
564(! grep -q -F "MARKER=1" /usr/lib/systemd/system/some_file )
565
566# Check that extensions cannot contain os-release
567mkdir -p /run/extensions/app-reject/usr/lib/{extension-release.d/,systemd/system}
568echo "ID=_any" >/run/extensions/app-reject/usr/lib/extension-release.d/extension-release.app-reject
569echo "ID=_any" >/run/extensions/app-reject/usr/lib/os-release
570touch /run/extensions/app-reject/usr/lib/systemd/system/other_file
571(! systemd-sysext merge)
572test ! -e /usr/lib/systemd/system/some_file
573test ! -e /usr/lib/systemd/system/other_file
574systemd-sysext unmerge
575rm -rf /run/extensions/app-reject
576rm /var/lib/extensions/app-nodistro.raw
577
578# Some super basic test that RootImage= works with .v/ dirs
579VBASE="vtest$RANDOM"
580VDIR="/tmp/$VBASE.v"
581mkdir "$VDIR"
582
583ln -s "$MINIMAL_IMAGE.raw" "$VDIR/${VBASE}_33.raw"
584ln -s "$MINIMAL_IMAGE.raw" "$VDIR/${VBASE}_34.raw"
585ln -s "$MINIMAL_IMAGE.raw" "$VDIR/${VBASE}_35.raw"
586
69dc36f6 587systemd-run -P -p RootImage="$VDIR" "${BIND_LOG_SOCKETS[@]}" cat /usr/lib/os-release | grep -q -F "MARKER=1"
ccb26715
FS
588
589rm "$VDIR/${VBASE}_33.raw" "$VDIR/${VBASE}_34.raw" "$VDIR/${VBASE}_35.raw"
590rmdir "$VDIR"
591
592mkdir -p /run/machines /run/portables /run/extensions
593touch /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw
594
595systemd-dissect --discover --json=short >/tmp/discover.json
596grep -q -F '{"name":"a","type":"raw","class":"machine","ro":false,"path":"/run/machines/a.raw"' /tmp/discover.json
597grep -q -F '{"name":"b","type":"raw","class":"portable","ro":false,"path":"/run/portables/b.raw"' /tmp/discover.json
598grep -q -F '{"name":"c","type":"raw","class":"sysext","ro":false,"path":"/run/extensions/c.raw"' /tmp/discover.json
599rm /tmp/discover.json /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw
600
601LOOP="$(systemd-dissect --attach --loop-ref=waldo "$MINIMAL_IMAGE.raw")"
602
603# Wait until the symlinks we want to test are established
604udevadm trigger -w "$LOOP"
605
606# Check if the /dev/loop/* symlinks really reference the right device
607test /dev/disk/by-loop-ref/waldo -ef "$LOOP"
608
609if [ "$(stat -c '%Hd:%Ld' "$MINIMAL_IMAGE.raw")" != '?d:?d' ] ; then
610 # Old stat didn't know the %Hd and %Ld specifiers and turned them into ?d
611 # instead. Let's simply skip the test on such old systems.
612 test "$(stat -c '/dev/disk/by-loop-inode/%Hd:%Ld-%i' "$MINIMAL_IMAGE.raw")" -ef "$LOOP"
613fi
614
615# Detach by loopback device
616systemd-dissect --detach "$LOOP"
617
618# Test long reference name.
619# Note, sizeof_field(struct loop_info64, lo_file_name) == 64,
620# and --loop-ref accepts upto 63 characters, and udev creates symlink
621# based on the name when it has upto _62_ characters.
622name="$(for _ in {1..62}; do echo -n 'x'; done)"
623LOOP="$(systemd-dissect --attach --loop-ref="$name" "$MINIMAL_IMAGE.raw")"
624udevadm trigger -w "$LOOP"
625
626# Check if the /dev/disk/by-loop-ref/$name symlink really references the right device
627test "/dev/disk/by-loop-ref/$name" -ef "$LOOP"
628
629# Detach by the /dev/disk/by-loop-ref symlink
630systemd-dissect --detach "/dev/disk/by-loop-ref/$name"
631
632name="$(for _ in {1..63}; do echo -n 'x'; done)"
633LOOP="$(systemd-dissect --attach --loop-ref="$name" "$MINIMAL_IMAGE.raw")"
634udevadm trigger -w "$LOOP"
635
636# Check if the /dev/disk/by-loop-ref/$name symlink does not exist
637test ! -e "/dev/disk/by-loop-ref/$name"
638
639# Detach by backing inode
640systemd-dissect --detach "$MINIMAL_IMAGE.raw"
641(! systemd-dissect --detach "$MINIMAL_IMAGE.raw")
642
643# check for confext functionality
644mkdir -p /run/confexts/test/etc/extension-release.d
645echo "ID=_any" >/run/confexts/test/etc/extension-release.d/extension-release.test
646echo "ARCHITECTURE=_any" >>/run/confexts/test/etc/extension-release.d/extension-release.test
647echo "MARKER_CONFEXT_123" >/run/confexts/test/etc/testfile
648cat <<EOF >/run/confexts/test/etc/testscript
649#!/bin/bash
650echo "This should not happen"
651EOF
652chmod +x /run/confexts/test/etc/testscript
653systemd-confext merge
654grep -q -F "MARKER_CONFEXT_123" /etc/testfile
655(! /etc/testscript)
656systemd-confext status
657systemd-confext unmerge
658rm -rf /run/confexts/
659
660unsquashfs -no-xattrs -d /tmp/img "$MINIMAL_IMAGE.raw"
661systemd-run --unit=test-root-ephemeral \
662 -p RootDirectory=/tmp/img \
663 -p RootEphemeral=yes \
664 -p Type=exec \
69dc36f6 665 "${BIND_LOG_SOCKETS[@]}" \
ccb26715
FS
666 bash -c "touch /abc && sleep infinity"
667test -n "$(ls -A /var/lib/systemd/ephemeral-trees)"
668systemctl stop test-root-ephemeral
669# shellcheck disable=SC2016
670timeout 10 bash -c 'until test -z "$(ls -A /var/lib/systemd/ephemeral-trees)"; do sleep .5; done'
671test ! -f /tmp/img/abc
672
dcbf0be1
DDM
673systemd-dissect --mtree /tmp/img >/dev/null
674systemd-dissect --list /tmp/img >/dev/null
ccb26715
FS
675
676read -r SHA256SUM1 _ < <(systemd-dissect --copy-from /tmp/img etc/os-release | sha256sum)
677test "$SHA256SUM1" != ""
678
679echo abc > abc
680systemd-dissect --copy-to /tmp/img abc /abc
681test -f /tmp/img/abc
682
683# Test for dissect tool support with systemd-sysext
684mkdir -p /run/extensions/ testkit/usr/lib/extension-release.d/
685echo "ID=_any" >testkit/usr/lib/extension-release.d/extension-release.testkit
686echo "ARCHITECTURE=_any" >>testkit/usr/lib/extension-release.d/extension-release.testkit
687echo "MARKER_SYSEXT_123" >testkit/usr/lib/testfile
688mksquashfs testkit/ testkit.raw
689cp testkit.raw /run/extensions/
690unsquashfs -l /run/extensions/testkit.raw
691systemd-dissect --no-pager /run/extensions/testkit.raw | grep -q '✓ sysext for portable service'
692systemd-dissect --no-pager /run/extensions/testkit.raw | grep -q '✓ sysext for system'
693systemd-sysext merge
694systemd-sysext status
695grep -q -F "MARKER_SYSEXT_123" /usr/lib/testfile
696systemd-sysext unmerge
697rm -rf /run/extensions/ testkit/
698
699# Test for dissect tool support with systemd-confext
700mkdir -p /run/confexts/ testjob/etc/extension-release.d/
701echo "ID=_any" >testjob/etc/extension-release.d/extension-release.testjob
702echo "ARCHITECTURE=_any" >>testjob/etc/extension-release.d/extension-release.testjob
703echo "MARKER_CONFEXT_123" >testjob/etc/testfile
704mksquashfs testjob/ testjob.raw
705cp testjob.raw /run/confexts/
706unsquashfs -l /run/confexts/testjob.raw
707systemd-dissect --no-pager /run/confexts/testjob.raw | grep -q '✓ confext for system'
708systemd-dissect --no-pager /run/confexts/testjob.raw | grep -q '✓ confext for portable service'
709systemd-confext merge
710systemd-confext status
711grep -q -F "MARKER_CONFEXT_123" /etc/testfile
712systemd-confext unmerge
713rm -rf /run/confexts/ testjob/
714
69dc36f6 715systemd-run -P -p RootImage="$MINIMAL_IMAGE.raw" "${BIND_LOG_SOCKETS[@]}" cat /run/host/os-release | cmp "$OS_RELEASE"
ccb26715
FS
716
717# Test that systemd-sysext reloads the daemon.
718mkdir -p /var/lib/extensions/
c77dad70 719ln -s /tmp/app-reload.raw /var/lib/extensions/app-reload.raw
ccb26715
FS
720systemd-sysext merge --no-reload
721# the service should not be running
722(! systemctl --quiet is-active foo.service)
723systemd-sysext unmerge --no-reload
724systemd-sysext merge
725# shellcheck disable=SC2016
726timeout 30s bash -xec 'until [[ $(journalctl -b -u foo.service _TRANSPORT=stdout -o cat) == foo ]]; do sleep .5; done'
727systemd-sysext unmerge --no-reload
728# Grep on the Warning to find the warning helper mentioning the daemon reload.
729systemctl status foo.service 2>&1 | grep -q -F "Warning"
730systemd-sysext merge
731systemd-sysext unmerge
732systemctl status foo.service 2>&1 | grep -v -q -F "Warning"
733rm /var/lib/extensions/app-reload.raw
734
735# Sneak in a couple of expected-to-fail invocations to cover
736# https://github.com/systemd/systemd/issues/29610
737(! systemd-run -P -p MountImages="/this/should/definitely/not/exist.img:/run/img2\:3:nosuid" false)
738(! systemd-run -P -p ExtensionImages="/this/should/definitely/not/exist.img" false)
739(! systemd-run -P -p RootImage="/this/should/definitely/not/exist.img" false)
740(! systemd-run -P -p ExtensionDirectories="/foo/bar /foo/baz" false)