From ad444dd8e85882d2f3d16f2335322416a3be1e9a Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Mon, 15 Apr 2024 17:16:18 +0200 Subject: [PATCH 1/5] man: slightly reword LogFilterPatterns= description As there was something missing in the existing sentence. --- man/systemd.exec.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index b6e75565da..64b7b07fc7 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -3175,8 +3175,8 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX \x7efoobar would add a pattern matching ~foobar to the allow list. Log messages are tested against denied patterns (if any), then against allowed patterns - (if any). If a log message matches any of the denied patterns, it will be discarded, whatever the - allowed patterns. Then, remaining log messages are tested against allowed patterns. Messages matching + (if any). If a log message matches any of the denied patterns, it is discarded immediately without considering + allowed patterns. Remaining log messages are tested against allowed patterns. Messages matching against none of the allowed pattern are discarded. If no allowed patterns are defined, then all messages are processed directly after going through denied filters. From ccb267153989d5b6a6c1decf68ccf3e746c103f2 Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Mon, 15 Apr 2024 19:44:23 +0200 Subject: [PATCH 2/5] test: split TEST-50-DISSECT into smaller parts As the current version has almost 2k lines. --- test/units/testsuite-50.DDI.sh | 50 + test/units/testsuite-50.dissect.sh | 526 +++++++ test/units/testsuite-50.mountnfsd.sh | 74 + test/units/testsuite-50.sh | 2067 ++------------------------ test/units/testsuite-50.sysext.sh | 1149 ++++++++++++++ 5 files changed, 1942 insertions(+), 1924 deletions(-) create mode 100755 test/units/testsuite-50.DDI.sh create mode 100755 test/units/testsuite-50.dissect.sh create mode 100755 test/units/testsuite-50.mountnfsd.sh create mode 100755 test/units/testsuite-50.sysext.sh diff --git a/test/units/testsuite-50.DDI.sh b/test/units/testsuite-50.DDI.sh new file mode 100755 index 0000000000..51f8d5dea2 --- /dev/null +++ b/test/units/testsuite-50.DDI.sh @@ -0,0 +1,50 @@ +#!/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 "$(/run/systemd/system/testservice-50a.service </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 +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 </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 +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" 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" 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" cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1" +cat >/run/systemd/system/testservice-50c.service </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 </run/systemd/system/testservice-50e.service </run/systemd/system/testservice-50f.service </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" 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 </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 \ + 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="$MINIMAL_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 +(! systemctl --quiet is-active foo.service) +systemd-sysext unmerge --no-reload +systemd-sysext merge +# shellcheck disable=SC2016 +timeout 30s bash -xec 'until [[ $(journalctl -b -u foo.service _TRANSPORT=stdout -o cat) == foo ]]; do sleep .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 + +# 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/testsuite-50.mountnfsd.sh b/test/units/testsuite-50.mountnfsd.sh new file mode 100755 index 0000000000..ef99984257 --- /dev/null +++ b/test/units/testsuite-50.mountnfsd.sh @@ -0,0 +1,74 @@ +#!/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 .; then + echo "Skipping mountnfsd/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 | tee /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) + +# 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 | tee /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/testsuite-50.sh b/test/units/testsuite-50.sh index 9c2e6f354c..ab65c86ba8 100755 --- a/test/units/testsuite-50.sh +++ b/test/units/testsuite-50.sh @@ -1,221 +1,118 @@ #!/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 +# shellcheck source=test/units/test-control.sh +. "$(dirname "$0")"/test-control.sh -export SYSTEMD_LOG_LEVEL=debug +# Setup shared stuff & run all subtests -cleanup_image_dir() { - if [ -z "${image_dir}" ]; then +at_exit() { + set +e + + 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}" -} -fake_roots_dir=/fake-roots - -cleanup_fake_rootfses() { - local tries=10 e - local -a lines fake_roots_mounts - - while [[ ${tries} -gt 0 ]]; do - tries=$((tries - 1)) - mapfile -t lines < <(mount | awk '{ print $3 }') - fake_roots_mounts=() - for e in "${lines[@]}"; do - if [[ ${e} = "${fake_roots_dir}"/* ]]; then - fake_roots_mounts+=( "${e}" ) - fi - done - if [[ ${#fake_roots_mounts[@]} -eq 0 ]]; then - break + while read -r dir; do + if mountpoint -q "$dir"; then + umount -Rv "$dir" fi - for e in "${fake_roots_mounts[@]}"; do - umount "${e}" - done - done - rm -rf "${fake_roots_dir}" + done < <(find "${IMAGE_DIR}" -mindepth 1 -maxdepth 1 -type d) + + rm -rf "$IMAGE_DIR" } -# shellcheck disable=SC2317 -cleanup() {( - set +ex +trap at_exit EXIT - cleanup_image_dir - cleanup_fake_rootfses -)} +: "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 testsuite-50.sh, please fix me" + exit 1 +fi udevadm control --log-level=debug -cd /tmp +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")" -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 +OS_RELEASE="$(test -e /etc/os-release && echo /etc/os-release || echo /usr/lib/os-release)" -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" - -if systemctl --version | grep -qF -- "+LIBARCHIVE" ; then - # Make sure tarballs are reproducible - read -r SHA256SUM1 _ < <(systemd-dissect --make-archive "${image}.raw" | sha256sum) - test "$SHA256SUM1" != "" - read -r SHA256SUM2 _ < <(systemd-dissect --make-archive "${image}.raw" | sha256sum) - test "$SHA256SUM2" != "" - test "$SHA256SUM1" = "$SHA256SUM2" - # Also check that a file we expect to be there is there - systemd-dissect --make-archive "${image}.raw" | tar t | grep etc/os-release -fi - -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}" = "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 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 + # 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 - HAVE_OPENSSL=1 OPENSSL_CONFIG="$(mktemp)" # Unfortunately OpenSSL insists on reading some config file, hence provide one with mostly placeholder contents cat >"${OPENSSL_CONFIG:?}" <"${image}.verity-sig" + echo '{"rootHash":"'"$MINIMAL_IMAGE_ROOTHASH"'","signature":"'"$(base64 -w 0 <"$MINIMAL_IMAGE.roothash.p7s")"'"}' >"$MINIMAL_IMAGE.verity-sig" # Pad it - truncate -s "${signature_size}" "${image}.verity-sig" + truncate -s "$signature_size" "$MINIMAL_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 + 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 "${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 +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 "${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" +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 "${image}.gpt")" +loop="$(losetup --show -P -f "$MINIMAL_IMAGE.gpt")" partitions=( "${loop:?}p1" "${loop:?}p2" ) -if [ "${HAVE_OPENSSL}" -eq 1 ]; then - partitions+=( "${loop:?}p3" ) +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="${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" +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}" +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 </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 </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 </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 </run/systemd/system/testservice-50e.service </run/systemd/system/testservice-50f.service </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 "${image}.raw" "$VDIR/${VBASE}_33.raw" -ln -s "${image}.raw" "$VDIR/${VBASE}_34.raw" -ln -s "${image}.raw" "$VDIR/${VBASE}_35.raw" - -systemd-run -P -p RootImage="$VDIR" 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 - -# 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 </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 --unit foo.service | grep -q -P 'echo\[[0-9]+\]: 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 - -if test -f /usr/lib/systemd/system/systemd-mountfsd.socket -a -f /usr/lib/systemd/system/systemd-nsresourced.socket && \ - command -v command -v mksquashfs >/dev/null 2>&1 && \ - grep -q bpf /sys/kernel/security/lsm && \ - test "$(find /usr/lib* -name libbpf.so.1 2>/dev/null)" != "" ; then - - cleanunprivfiles() { - 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 cleanunprivfiles 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 "${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 | tee /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 ) - - # 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 | tee /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 - -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) - -# general systemd-sysext tests - -shopt -s extglob - -die() { - echo "${*}" - exit 1 -} - -prep_root() { - local r=${1}; shift - local h=${1}; shift - - if [[ -d ${r} ]]; then - die "${r@Q} is being reused as a root, possibly a result of copy-pasting some test case and forgetting to rename the root directory name" - fi - - mkdir -p "${r}${h}" "${r}/usr/lib" "${r}/var/lib/extensions" "${r}/var/lib/extensions.mutable" -} - -prep_env() { - local mode=${1}; shift - - export SYSTEMD_SYSEXT_MUTABLE_MODE=${mode} -} - -drop_env() { - unset -v SYSTEMD_SYSEXT_MUTABLE_MODE -} - -gen_os_release() { - local r=${1}; shift - - { - echo "ID=testtest" - echo "VERSION=1.2.3" - } >"${r}/usr/lib/os-release" -} - -gen_test_ext_image() { - local r=${1}; shift - local h=${1}; shift - - local n d f - - n='test-extension' - d="${r}/var/lib/extensions/${n}" - f="${d}/usr/lib/extension-release.d/extension-release.${n}" - mkdir -p "$(dirname "${f}")" - echo "ID=_any" >"${f}" - mkdir -p "${d}/${h}" - touch "${d}${h}/preexisting-file-in-extension-image" -} - -hierarchy_ext_mut_path() { - local r=${1}; shift - local h=${1}; shift - - # /a/b/c -> a.b.c - local n=${h} - n="${n##+(/)}" - n="${n%%+(/)}" - n="${n//\//.}" - - printf '%s' "${r}/var/lib/extensions.mutable/${n}" -} - -prep_ext_mut() { - local p=${1}; shift - - mkdir -p "${p}" - touch "${p}/preexisting-file-in-extensions-mutable" -} - -make_ro() { - local r=${1}; shift - local h=${1}; shift - - mount -o bind "${r}${h}" "${r}${h}" - mount -o bind,remount,ro "${r}${h}" -} - -prep_hierarchy() { - local r=${1}; shift - local h=${1}; shift - - touch "${r}${h}/preexisting-file-in-hierarchy" -} - -prep_ro_hierarchy() { - local r=${1}; shift - local h=${1}; shift - - prep_hierarchy "${r}" "${h}" - make_ro "${r}" "${h}" -} - -# extra args: -# "e" for checking for the preexisting file in extension -# "h" for checking for the preexisting file in hierarchy -# "u" for checking for the preexisting file in upperdir -check_usual_suspects() { - local root=${1}; shift - local hierarchy=${1}; shift - local message=${1}; shift - - local arg - # shellcheck disable=SC2034 # the variables below are used indirectly - local e='' h='' u='' - - for arg; do - case ${arg} in - e|h|u) - local -n v=${arg} - v=x - unset -n v - ;; - *) - die "invalid arg to ${0}: ${arg@Q}" - ;; - esac - done - - # var name, file name - local pairs=( - e:preexisting-file-in-extension-image - h:preexisting-file-in-hierarchy - u:preexisting-file-in-extensions-mutable - ) - local pair name file desc full_path - for pair in "${pairs[@]}"; do - name=${pair%%:*} - file=${pair#*:} - desc=${file//-/ } - full_path="${root}${hierarchy}/${file}" - local -n v=${name} - if [[ -n ${v} ]]; then - test -f "${full_path}" || { - ls -la "$(dirname "${full_path}")" - die "${desc} is missing ${message}" - } - else - test ! -f "${full_path}" || { - ls -la "$(dirname "${full_path}")" - die "${desc} unexpectedly exists ${message}" - } - fi - unset -n v - done -} - -check_usual_suspects_after_merge() { - local r=${1}; shift - local h=${1}; shift - - check_usual_suspects "${r}" "${h}" "after merge" "${@}" -} - -check_usual_suspects_after_unmerge() { - local r=${1}; shift - local h=${1}; shift - - check_usual_suspects "${r}" "${h}" "after unmerge" "${@}" -} - -drop_env - -# -# no extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# mutability disabled by default -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/simple-read-only-with-read-only-hierarchy -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only after unmerge" - - -# -# no extension data in /var/lib/extensions.mutable/…, mutable hierarchy, -# mutability disabled by default -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/simple-read-only-with-mutable-hierarchy -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -prep_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-succeed-on-mutable-fs" || die "${fake_root}${hierarchy} is not mutable" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h - -touch "${fake_root}${hierarchy}/should-succeed-on-mutable-fs-again" || die "${fake_root}${hierarchy} is not mutable after unmerge" - - -# -# no extension data in /var/lib/extensions.mutable/…, no hierarchy either, -# mutability disabled by default -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/simple-read-only-with-missing-hierarchy -hierarchy=/opt - -prep_root "${fake_root}" "${hierarchy}" -rmdir "${fake_root}/${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" - - -# -# no extension data in /var/lib/extensions.mutable/…, an empty hierarchy, -# mutability disabled by default -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/simple-read-only-with-empty-hierarchy -hierarchy=/opt - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -make_ro "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, mutability disabled-by-default -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/simple-mutable-with-read-only-hierarchy-disabled -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/should-be-read-only" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, auto-mutability -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/simple-mutable-with-read-only-hierarchy -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" - - -# -# extension data in /var/lib/extensions.mutable/…, missing hierarchy, -# auto-mutability -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/simple-mutable-with-missing-hierarchy -hierarchy=/opt - -prep_root "${fake_root}" "${hierarchy}" -rmdir "${fake_root}/${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e u -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" - - -# -# extension data in /var/lib/extensions.mutable/…, empty hierarchy, auto-mutability -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/simple-mutable-with-empty-hierarchy -hierarchy=/opt - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -make_ro "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e u -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" - - -# -# /var/lib/extensions.mutable/… is a symlink to /some/other/dir, read-only -# hierarchy, auto-mutability -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/mutable-symlink-with-read-only-hierarchy -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -# generate extension writable data -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -real_ext_dir="${fake_root}/upperdir" -prep_ext_mut "${real_ext_dir}" -ln -sfTr "${real_ext_dir}" "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" -test -f "${real_ext_dir}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test -f "${real_ext_dir}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" - - -# -# /var/lib/extensions.mutable/… is a symlink to the hierarchy itself, auto-mutability -# -# for this to work, hierarchy must be mutable -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/mutable-self-upper -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -# generate extension writable data -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -real_ext_dir="${fake_root}${hierarchy}" -prep_ext_mut "${real_ext_dir}" -ln -sfTr "${real_ext_dir}" "${ext_data_path}" - -# prepare writable hierarchy -touch "${fake_root}${hierarchy}/preexisting-file-in-hierarchy" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" -test -f "${real_ext_dir}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h u -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test -f "${real_ext_dir}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" - - -# -# /var/lib/extensions.mutable/… is a symlink to the hierarchy itself, which is -# read-only, auto-mutability -# -# expecting a failure here -# - - -fake_root=${fake_roots_dir}/failure-self-upper-ro -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -# generate extension writable data -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -real_ext_dir="${fake_root}${hierarchy}" -prep_ext_mut "${real_ext_dir}" -ln -sfTr "${real_ext_dir}" "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge && die "expected merge to fail" - - -# -# /var/lib/extensions.mutable/… is a dangling symlink, auto-mutability -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/read-only-mutable-dangling-symlink -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -ln -sfTr "/should/not/exist/" "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h - - -# -# /var/lib/extensions.mutable/… exists, but it's ignored, mutability disabled explicitly -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/disabled -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=no merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h - - -# -# /var/lib/extensions.mutable/… exists, but it's imported instead -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/imported -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=import merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h - - -# -# /var/lib/extensions.mutable/… does not exist, but mutability is enabled -# explicitly -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/enabled -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -test ! -d "${ext_data_path}" || die "extensions.mutable should not exist" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=yes merge - -test -d "${ext_data_path}" || die "extensions.mutable should exist now" -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" - - -# -# /var/lib/extensions.mutable/… does not exist, auto-mutability -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/simple-read-only-explicit -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h - - -# -# /var/lib/extensions.mutable/… does not exist, but mutability is enabled -# through an env var -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/enabled-env-var -hierarchy=/usr - -prep_env "yes" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -test ! -d "${ext_data_path}" || die "extensions.mutable should not exist" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -test -d "${ext_data_path}" || die "extensions.mutable should exist now" -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" -drop_env - - -# -# /var/lib/extensions.mutable/… does not exist, auto-mutability through an env -# var -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/read-only-auto-env-var -hierarchy=/usr - -prep_env "auto" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -drop_env - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# auto-mutability through an env var -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/auto-mutable-env-var -hierarchy=/usr - -prep_env "auto" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" -drop_env - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# mutability disabled through an env var -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/env-var-disabled -hierarchy=/usr - -prep_env "no" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/should-be-read-only" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -drop_env - - -# -# /var/lib/extensions.mutable/… exists, but it's imported instead through an -# env var -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/imported-env-var -hierarchy=/usr - -prep_env "import" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -drop_env - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# mutability enabled through an env var, but overridden with a command-line -# option -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/env-var-overridden -hierarchy=/usr - -prep_env "yes" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=no merge - -touch "${fake_root}${hierarchy}/should-be-read-only" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -drop_env - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# ephemeral mutability, so extension data contents are ignored -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/ephemeral -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=ephemeral merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not be stored in extension data" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not appear in writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# ephemeral mutability through an env var, so extension data contents are -# ignored -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/ephemeral-env-var -hierarchy=/usr - -prep_env "ephemeral" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not be stored in extension data" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not appear in writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" -drop_env - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# ephemeral import mutability, so extension data contents are imported too -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/ephemeral-import -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=ephemeral-import merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not be stored in extension data" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not appear in writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# ephemeral mutability through an env var, so extension data contents are -# imported too -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/ephemeral-import-env-var -hierarchy=/usr - -prep_env "ephemeral-import" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not be stored in extension data" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not appear in writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" -drop_env - - -# -# extension data pointing to mutable hierarchy, ephemeral import mutability -# -# expecting a failure here -# - - -fake_root=${fake_roots_dir}/ephemeral-import-self -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -real_ext_dir="${fake_root}${hierarchy}" -prep_ext_mut "${real_ext_dir}" -ln -sfTr "${real_ext_dir}" "${ext_data_path}" - -prep_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-succeed-on-read-only-fs" || die "${fake_root}${hierarchy} is not mutable" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=ephemeral-import merge && die 'expected merge to fail' - - -# -# extension data pointing to mutable hierarchy, import mutability -# -# expecting a failure here -# - - -fake_root=${fake_roots_dir}/import-self -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -real_ext_dir="${fake_root}${hierarchy}" -prep_ext_mut "${real_ext_dir}" -ln -sfTr "${real_ext_dir}" "${ext_data_path}" - -prep_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-succeed-on-read-only-fs" || die "${fake_root}${hierarchy} is not mutable" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=import merge && die 'expected merge to fail' - - -# -# done -# +: "Run subtests" +run_subtests touch /testok diff --git a/test/units/testsuite-50.sysext.sh b/test/units/testsuite-50.sysext.sh new file mode 100755 index 0000000000..9b219e557b --- /dev/null +++ b/test/units/testsuite-50.sysext.sh @@ -0,0 +1,1149 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eux +set -o pipefail +shopt -s extglob + +# General systemd-sysext tests + +fake_roots_dir=/fake-roots + +at_exit() { + local tries=10 e + local -a lines fake_roots_mounts + + while [[ ${tries} -gt 0 ]]; do + tries=$((tries - 1)) + mapfile -t lines < <(mount | awk '{ print $3 }') + fake_roots_mounts=() + for e in "${lines[@]}"; do + if [[ ${e} = "${fake_roots_dir}"/* ]]; then + fake_roots_mounts+=( "${e}" ) + fi + done + if [[ ${#fake_roots_mounts[@]} -eq 0 ]]; then + break + fi + for e in "${fake_roots_mounts[@]}"; do + umount "${e}" + done + done + rm -rf "${fake_roots_dir}" +} + +trap at_exit EXIT + +die() { + echo "${*}" + exit 1 +} + +prep_root() { + local r=${1}; shift + local h=${1}; shift + + if [[ -d ${r} ]]; then + die "${r@Q} is being reused as a root, possibly a result of copy-pasting some test case and forgetting to rename the root directory name" + fi + + mkdir -p "${r}${h}" "${r}/usr/lib" "${r}/var/lib/extensions" "${r}/var/lib/extensions.mutable" +} + +prep_env() { + local mode=${1}; shift + + export SYSTEMD_SYSEXT_MUTABLE_MODE=${mode} +} + +drop_env() { + unset -v SYSTEMD_SYSEXT_MUTABLE_MODE +} + +gen_os_release() { + local r=${1}; shift + + { + echo "ID=testtest" + echo "VERSION=1.2.3" + } >"${r}/usr/lib/os-release" +} + +gen_test_ext_image() { + local r=${1}; shift + local h=${1}; shift + + local n d f + + n='test-extension' + d="${r}/var/lib/extensions/${n}" + f="${d}/usr/lib/extension-release.d/extension-release.${n}" + mkdir -p "$(dirname "${f}")" + echo "ID=_any" >"${f}" + mkdir -p "${d}/${h}" + touch "${d}${h}/preexisting-file-in-extension-image" +} + +hierarchy_ext_mut_path() { + local r=${1}; shift + local h=${1}; shift + + # /a/b/c -> a.b.c + local n=${h} + n="${n##+(/)}" + n="${n%%+(/)}" + n="${n//\//.}" + + printf '%s' "${r}/var/lib/extensions.mutable/${n}" +} + +prep_ext_mut() { + local p=${1}; shift + + mkdir -p "${p}" + touch "${p}/preexisting-file-in-extensions-mutable" +} + +make_ro() { + local r=${1}; shift + local h=${1}; shift + + mount -o bind "${r}${h}" "${r}${h}" + mount -o bind,remount,ro "${r}${h}" +} + +prep_hierarchy() { + local r=${1}; shift + local h=${1}; shift + + touch "${r}${h}/preexisting-file-in-hierarchy" +} + +prep_ro_hierarchy() { + local r=${1}; shift + local h=${1}; shift + + prep_hierarchy "${r}" "${h}" + make_ro "${r}" "${h}" +} + +# extra args: +# "e" for checking for the preexisting file in extension +# "h" for checking for the preexisting file in hierarchy +# "u" for checking for the preexisting file in upperdir +check_usual_suspects() { + local root=${1}; shift + local hierarchy=${1}; shift + local message=${1}; shift + + local arg + # shellcheck disable=SC2034 # the variables below are used indirectly + local e='' h='' u='' + + for arg; do + case ${arg} in + e|h|u) + local -n v=${arg} + v=x + unset -n v + ;; + *) + die "invalid arg to ${0}: ${arg@Q}" + ;; + esac + done + + # var name, file name + local pairs=( + e:preexisting-file-in-extension-image + h:preexisting-file-in-hierarchy + u:preexisting-file-in-extensions-mutable + ) + local pair name file desc full_path + for pair in "${pairs[@]}"; do + name=${pair%%:*} + file=${pair#*:} + desc=${file//-/ } + full_path="${root}${hierarchy}/${file}" + local -n v=${name} + if [[ -n ${v} ]]; then + test -f "${full_path}" || { + ls -la "$(dirname "${full_path}")" + die "${desc} is missing ${message}" + } + else + test ! -f "${full_path}" || { + ls -la "$(dirname "${full_path}")" + die "${desc} unexpectedly exists ${message}" + } + fi + unset -n v + done +} + +check_usual_suspects_after_merge() { + local r=${1}; shift + local h=${1}; shift + + check_usual_suspects "${r}" "${h}" "after merge" "${@}" +} + +check_usual_suspects_after_unmerge() { + local r=${1}; shift + local h=${1}; shift + + check_usual_suspects "${r}" "${h}" "after unmerge" "${@}" +} + +# General systemd-sysext tests + +# +# no extension data in /var/lib/extensions.mutable/…, read-only hierarchy, +# mutability disabled by default +# +# read-only merged +# + + +fake_root=${fake_roots_dir}/simple-read-only-with-read-only-hierarchy +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge + +touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h + +touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only after unmerge" + + +# +# no extension data in /var/lib/extensions.mutable/…, mutable hierarchy, +# mutability disabled by default +# +# read-only merged +# + + +fake_root=${fake_roots_dir}/simple-read-only-with-mutable-hierarchy +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +prep_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-succeed-on-mutable-fs" || die "${fake_root}${hierarchy} is not mutable" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h + +touch "${fake_root}${hierarchy}/should-succeed-on-mutable-fs-again" || die "${fake_root}${hierarchy} is not mutable after unmerge" + + +# +# no extension data in /var/lib/extensions.mutable/…, no hierarchy either, +# mutability disabled by default +# +# read-only merged +# + + +fake_root=${fake_roots_dir}/simple-read-only-with-missing-hierarchy +hierarchy=/opt + +prep_root "${fake_root}" "${hierarchy}" +rmdir "${fake_root}/${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge + +touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" + + +# +# no extension data in /var/lib/extensions.mutable/…, an empty hierarchy, +# mutability disabled by default +# +# read-only merged +# + + +fake_root=${fake_roots_dir}/simple-read-only-with-empty-hierarchy +hierarchy=/opt + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +make_ro "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge + +touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" + + +# +# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, mutability disabled-by-default +# +# read-only merged +# + + +fake_root=${fake_roots_dir}/simple-mutable-with-read-only-hierarchy-disabled +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +prep_ext_mut "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge + +touch "${fake_root}${hierarchy}/should-be-read-only" && die "${fake_root}${hierarchy} is not read-only" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h + + +# +# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, auto-mutability +# +# mutable merged +# + + +fake_root=${fake_roots_dir}/simple-mutable-with-read-only-hierarchy +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +prep_ext_mut "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge + +touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" +test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" + + +# +# extension data in /var/lib/extensions.mutable/…, missing hierarchy, +# auto-mutability +# +# mutable merged +# + + +fake_root=${fake_roots_dir}/simple-mutable-with-missing-hierarchy +hierarchy=/opt + +prep_root "${fake_root}" "${hierarchy}" +rmdir "${fake_root}/${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +prep_ext_mut "${ext_data_path}" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge + +touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e u +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" +test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" + + +# +# extension data in /var/lib/extensions.mutable/…, empty hierarchy, auto-mutability +# +# mutable merged +# + + +fake_root=${fake_roots_dir}/simple-mutable-with-empty-hierarchy +hierarchy=/opt + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +prep_ext_mut "${ext_data_path}" + +make_ro "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge + +touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e u +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" +test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" + + +# +# /var/lib/extensions.mutable/… is a symlink to /some/other/dir, read-only +# hierarchy, auto-mutability +# +# mutable merged +# + + +fake_root=${fake_roots_dir}/mutable-symlink-with-read-only-hierarchy +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +# generate extension writable data +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +real_ext_dir="${fake_root}/upperdir" +prep_ext_mut "${real_ext_dir}" +ln -sfTr "${real_ext_dir}" "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge + +touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" +test -f "${real_ext_dir}/now-is-mutable" || die "now-is-mutable is not stored in expected location" + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" +test -f "${real_ext_dir}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" +test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" + + +# +# /var/lib/extensions.mutable/… is a symlink to the hierarchy itself, auto-mutability +# +# for this to work, hierarchy must be mutable +# +# mutable merged +# + + +fake_root=${fake_roots_dir}/mutable-self-upper +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +# generate extension writable data +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +real_ext_dir="${fake_root}${hierarchy}" +prep_ext_mut "${real_ext_dir}" +ln -sfTr "${real_ext_dir}" "${ext_data_path}" + +# prepare writable hierarchy +touch "${fake_root}${hierarchy}/preexisting-file-in-hierarchy" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge + +touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" +test -f "${real_ext_dir}/now-is-mutable" || die "now-is-mutable is not stored in expected location" + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h u +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" +test -f "${real_ext_dir}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" + + +# +# /var/lib/extensions.mutable/… is a symlink to the hierarchy itself, which is +# read-only, auto-mutability +# +# expecting a failure here +# + + +fake_root=${fake_roots_dir}/failure-self-upper-ro +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +# generate extension writable data +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +real_ext_dir="${fake_root}${hierarchy}" +prep_ext_mut "${real_ext_dir}" +ln -sfTr "${real_ext_dir}" "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge && die "expected merge to fail" + + +# +# /var/lib/extensions.mutable/… is a dangling symlink, auto-mutability +# +# read-only merged +# + + +fake_root=${fake_roots_dir}/read-only-mutable-dangling-symlink +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +ln -sfTr "/should/not/exist/" "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge + +touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h + + +# +# /var/lib/extensions.mutable/… exists, but it's ignored, mutability disabled explicitly +# +# read-only merged +# + + +fake_root=${fake_roots_dir}/disabled +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +prep_ext_mut "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=no merge + +touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h + + +# +# /var/lib/extensions.mutable/… exists, but it's imported instead +# +# read-only merged +# + + +fake_root=${fake_roots_dir}/imported +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +prep_ext_mut "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=import merge + +touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h + + +# +# /var/lib/extensions.mutable/… does not exist, but mutability is enabled +# explicitly +# +# mutable merged +# + + +fake_root=${fake_roots_dir}/enabled +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +test ! -d "${ext_data_path}" || die "extensions.mutable should not exist" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=yes merge + +test -d "${ext_data_path}" || die "extensions.mutable should exist now" +touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" +test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" + + +# +# /var/lib/extensions.mutable/… does not exist, auto-mutability +# +# read-only merged +# + + +fake_root=${fake_roots_dir}/simple-read-only-explicit +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge + +touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h + + +# +# /var/lib/extensions.mutable/… does not exist, but mutability is enabled +# through an env var +# +# mutable merged +# + + +fake_root=${fake_roots_dir}/enabled-env-var +hierarchy=/usr + +prep_env "yes" +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +test ! -d "${ext_data_path}" || die "extensions.mutable should not exist" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge + +test -d "${ext_data_path}" || die "extensions.mutable should exist now" +touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" +test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" +drop_env + + +# +# /var/lib/extensions.mutable/… does not exist, auto-mutability through an env +# var +# +# read-only merged +# + + +fake_root=${fake_roots_dir}/read-only-auto-env-var +hierarchy=/usr + +prep_env "auto" +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge + +touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +drop_env + + +# +# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, +# auto-mutability through an env var +# +# mutable merged +# + + +fake_root=${fake_roots_dir}/auto-mutable-env-var +hierarchy=/usr + +prep_env "auto" +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +prep_ext_mut "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge + +touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" +test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" +drop_env + + +# +# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, +# mutability disabled through an env var +# +# read-only merged +# + + +fake_root=${fake_roots_dir}/env-var-disabled +hierarchy=/usr + +prep_env "no" +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +prep_ext_mut "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge + +touch "${fake_root}${hierarchy}/should-be-read-only" && die "${fake_root}${hierarchy} is not read-only" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +drop_env + + +# +# /var/lib/extensions.mutable/… exists, but it's imported instead through an +# env var +# +# read-only merged +# + + +fake_root=${fake_roots_dir}/imported-env-var +hierarchy=/usr + +prep_env "import" +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +prep_ext_mut "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge + +touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +drop_env + + +# +# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, +# mutability enabled through an env var, but overridden with a command-line +# option +# +# read-only merged +# + + +fake_root=${fake_roots_dir}/env-var-overridden +hierarchy=/usr + +prep_env "yes" +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +prep_ext_mut "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=no merge + +touch "${fake_root}${hierarchy}/should-be-read-only" && die "${fake_root}${hierarchy} is not read-only" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +drop_env + + +# +# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, +# ephemeral mutability, so extension data contents are ignored +# +# mutable merged +# + + +fake_root=${fake_roots_dir}/ephemeral +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +prep_ext_mut "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=ephemeral merge + +touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h +test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not be stored in extension data" + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not appear in writable storage after unmerge" +test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" + + +# +# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, +# ephemeral mutability through an env var, so extension data contents are +# ignored +# +# mutable merged +# + + +fake_root=${fake_roots_dir}/ephemeral-env-var +hierarchy=/usr + +prep_env "ephemeral" +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +prep_ext_mut "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge + +touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h +test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not be stored in extension data" + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not appear in writable storage after unmerge" +test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" +drop_env + + +# +# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, +# ephemeral import mutability, so extension data contents are imported too +# +# mutable merged +# + + +fake_root=${fake_roots_dir}/ephemeral-import +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +prep_ext_mut "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=ephemeral-import merge + +touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u +test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not be stored in extension data" + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not appear in writable storage after unmerge" +test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" + + +# +# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, +# ephemeral mutability through an env var, so extension data contents are +# imported too +# +# mutable merged +# + + +fake_root=${fake_roots_dir}/ephemeral-import-env-var +hierarchy=/usr + +prep_env "ephemeral-import" +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +prep_ext_mut "${ext_data_path}" + +prep_ro_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge + +touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" +check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u +test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not be stored in extension data" + +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge + +check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not appear in writable storage after unmerge" +test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" +drop_env + + +# +# extension data pointing to mutable hierarchy, ephemeral import mutability +# +# expecting a failure here +# + + +fake_root=${fake_roots_dir}/ephemeral-import-self +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +real_ext_dir="${fake_root}${hierarchy}" +prep_ext_mut "${real_ext_dir}" +ln -sfTr "${real_ext_dir}" "${ext_data_path}" + +prep_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-succeed-on-read-only-fs" || die "${fake_root}${hierarchy} is not mutable" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=ephemeral-import merge && die 'expected merge to fail' + + +# +# extension data pointing to mutable hierarchy, import mutability +# +# expecting a failure here +# + + +fake_root=${fake_roots_dir}/import-self +hierarchy=/usr + +prep_root "${fake_root}" "${hierarchy}" +gen_os_release "${fake_root}" +gen_test_ext_image "${fake_root}" "${hierarchy}" + +ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +real_ext_dir="${fake_root}${hierarchy}" +prep_ext_mut "${real_ext_dir}" +ln -sfTr "${real_ext_dir}" "${ext_data_path}" + +prep_hierarchy "${fake_root}" "${hierarchy}" + +touch "${fake_root}${hierarchy}/should-succeed-on-read-only-fs" || die "${fake_root}${hierarchy} is not mutable" + +# run systemd-sysext +SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=import merge && die 'expected merge to fail' + +exit 0 From 5d259f1236ffb1446ce68b09cea3bb3670b486b5 Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Mon, 15 Apr 2024 20:27:32 +0200 Subject: [PATCH 3/5] test: split some overly long lines Let's get the line count back up again by splitting some overly long lines in hopes to make the code slightly more readable. --- test/units/testsuite-50.DDI.sh | 30 ++- test/units/testsuite-50.dissect.sh | 277 +++++++++++++++++++++------ test/units/testsuite-50.mountnfsd.sh | 11 +- 3 files changed, 256 insertions(+), 62 deletions(-) diff --git a/test/units/testsuite-50.DDI.sh b/test/units/testsuite-50.DDI.sh index 51f8d5dea2..42c9a4312a 100755 --- a/test/units/testsuite-50.DDI.sh +++ b/test/units/testsuite-50.DDI.sh @@ -14,13 +14,24 @@ if [[ -z "${OPENSSL_CONFIG:?}" ]] || ! command -v mksquashfs &>/dev/null; then 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 +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 +{ + 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 +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 @@ -37,10 +48,19 @@ 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 +{ + 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_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 diff --git a/test/units/testsuite-50.dissect.sh b/test/units/testsuite-50.dissect.sh index c63fd1f297..a1c1c42b96 100755 --- a/test/units/testsuite-50.dissect.sh +++ b/test/units/testsuite-50.dissect.sh @@ -9,13 +9,16 @@ set -o pipefail # shellcheck source=test/units/util.sh . "$(dirname "$0")"/util.sh -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 --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" 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]*$" +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" != "" @@ -36,9 +39,19 @@ fi mv "$MINIMAL_IMAGE.verity" "$MINIMAL_IMAGE.fooverity" mv "$MINIMAL_IMAGE.roothash" "$MINIMAL_IMAGE.foohash" -systemd-dissect --json=short "$MINIMAL_IMAGE.raw" --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") +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" @@ -63,9 +76,17 @@ systemd-dissect --umount "$IMAGE_DIR/mount2" systemd-run -P -p RootImage="$MINIMAL_IMAGE.raw" 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" cat /usr/lib/os-release | grep -q -F "MARKER=1" +systemd-run -P \ + -p RootImage="$MINIMAL_IMAGE.raw" \ + -p RootHash="$MINIMAL_IMAGE.foohash" \ + -p RootVerity="$MINIMAL_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="$MINIMAL_IMAGE.raw" --property RootHash="$MINIMAL_IMAGE_ROOTHASH" --property RootVerity="$MINIMAL_IMAGE.fooverity" cat /usr/lib/os-release | grep -q -F "MARKER=1" +systemd-run -P \ + --property RootImage="$MINIMAL_IMAGE.raw" \ + --property RootHash="$MINIMAL_IMAGE_ROOTHASH" \ + --property RootVerity="$MINIMAL_IMAGE.fooverity" \ + cat /usr/lib/os-release | grep -q -F "MARKER=1" mv "$MINIMAL_IMAGE.fooverity" "$MINIMAL_IMAGE.verity" mv "$MINIMAL_IMAGE.foohash" "$MINIMAL_IMAGE.roothash" @@ -73,10 +94,19 @@ mv "$MINIMAL_IMAGE.foohash" "$MINIMAL_IMAGE.roothash" 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,' +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 -q -E '{"rw":"ro","designator":"root-verity-sig","partition_uuid":"'".*"'","partition_label":"Signature Partition","fstype":"verity_hash_signature","architecture":"'"$ARCHITECTURE"'","verity":null,' + 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") @@ -99,14 +129,53 @@ systemd-dissect --validate "$MINIMAL_IMAGE.gpt" --image-policy=root=signed (! 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 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 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 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 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 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 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 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 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 MountAPIVFS=yes \ + 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 \ + 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 \ + 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 \ + 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 \ + 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 \ + 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 \ + 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 \ + 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" @@ -121,10 +190,19 @@ 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 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" mount | grep -F "squashfs" | grep -q -F "nosuid" -systemd-run -P -p RootImage="$MINIMAL_IMAGE.gpt" -p RootImageOptions="root:ro,noatime root:ro,dev" mount | grep -F "squashfs" | grep -q -F "noatime" +systemd-run -P \ + -p RootImage="$MINIMAL_IMAGE.gpt" \ + -p RootHash="$MINIMAL_IMAGE_ROOTHASH" \ + -p MountAPIVFS=yes \ + 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" \ + mount | grep -F "squashfs" | grep -q -F "nosuid" +systemd-run -P \ + -p RootImage="$MINIMAL_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 </run/systemd/system/testservice-50c.service </run/systemd/system/testservice-50e.service </run/systemd/system/testservice-50f.service < Date: Mon, 15 Apr 2024 20:52:59 +0200 Subject: [PATCH 4/5] test: simplify unit check --- test/units/testsuite-50.dissect.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/units/testsuite-50.dissect.sh b/test/units/testsuite-50.dissect.sh index a1c1c42b96..34e60aa76f 100755 --- a/test/units/testsuite-50.dissect.sh +++ b/test/units/testsuite-50.dissect.sh @@ -318,12 +318,8 @@ 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 - -while systemctl show -P SubState testservice-50d.service | grep -q running -do - sleep 0.1 -done - +# 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 From 236634c82c56e280348f9452129f3cdfd1fb7a45 Mon Sep 17 00:00:00 2001 From: Frantisek Sumsal Date: Mon, 15 Apr 2024 23:28:43 +0200 Subject: [PATCH 5/5] test: rework systemd-sysext test Let's rework the test a bit, namely: - condense the code a bit - drop unnecessary braces around variables - drop unnecessary explanations around `touch` calls - drop/rename functions to make the code more self-explanatory - simplify cleanup a bit - create R/O bind mounts directly (supported since util-linux 2.27) --- test/units/testsuite-50.sysext.sh | 1509 +++++++++++------------------ 1 file changed, 542 insertions(+), 967 deletions(-) diff --git a/test/units/testsuite-50.sysext.sh b/test/units/testsuite-50.sysext.sh index 9b219e557b..de89f64211 100755 --- a/test/units/testsuite-50.sysext.sh +++ b/test/units/testsuite-50.sysext.sh @@ -2,1148 +2,723 @@ # SPDX-License-Identifier: LGPL-2.1-or-later set -eux set -o pipefail -shopt -s extglob -# General systemd-sysext tests - -fake_roots_dir=/fake-roots +FAKE_ROOTS_DIR="$(mktemp -d --tmpdir="" fake-roots-XXX)" +# shellcheck disable=SC2317 at_exit() { - local tries=10 e - local -a lines fake_roots_mounts + set +ex - while [[ ${tries} -gt 0 ]]; do - tries=$((tries - 1)) - mapfile -t lines < <(mount | awk '{ print $3 }') - fake_roots_mounts=() - for e in "${lines[@]}"; do - if [[ ${e} = "${fake_roots_dir}"/* ]]; then - fake_roots_mounts+=( "${e}" ) - fi - done - if [[ ${#fake_roots_mounts[@]} -eq 0 ]]; then - break + 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 chaging file offsets. + # shellcheck disable=SC2002 + cat /proc/mounts | while read -r _ target _ _ _ _; do + if [[ "$target" =~ ^"$FAKE_ROOTS_DIR" ]]; then + umount -Rv "$target" fi - for e in "${fake_roots_mounts[@]}"; do - umount "${e}" - done done - rm -rf "${fake_roots_dir}" + + rm -rf "${FAKE_ROOTS_DIR}" } trap at_exit EXIT -die() { - echo "${*}" - exit 1 -} +prepare_root() { + local root=${1:?} + local hierarchy=${2:?} + local dir -prep_root() { - local r=${1}; shift - local h=${1}; shift - - if [[ -d ${r} ]]; then - die "${r@Q} is being reused as a root, possibly a result of copy-pasting some test case and forgetting to rename the root directory name" + if [[ -d $root ]]; then + echo >&2 "Directory $root already exists, possible copy-paste error?" + exit 1 fi - mkdir -p "${r}${h}" "${r}/usr/lib" "${r}/var/lib/extensions" "${r}/var/lib/extensions.mutable" -} - -prep_env() { - local mode=${1}; shift - - export SYSTEMD_SYSEXT_MUTABLE_MODE=${mode} -} - -drop_env() { - unset -v SYSTEMD_SYSEXT_MUTABLE_MODE -} - -gen_os_release() { - local r=${1}; shift + for dir in "$hierarchy" "/usr/lib" "/var/lib/extensions/" "/var/lib/extensions.mutable"; do + mkdir -p "$root$dir" + done { echo "ID=testtest" echo "VERSION=1.2.3" - } >"${r}/usr/lib/os-release" + } >"$root/usr/lib/os-release" } -gen_test_ext_image() { - local r=${1}; shift - local h=${1}; shift +prepare_extension_image() { + local root="${1:?}" + local hierarchy="${2:?}" + local ext_dir ext_release name - local n d f - - n='test-extension' - d="${r}/var/lib/extensions/${n}" - f="${d}/usr/lib/extension-release.d/extension-release.${n}" - mkdir -p "$(dirname "${f}")" - echo "ID=_any" >"${f}" - mkdir -p "${d}/${h}" - touch "${d}${h}/preexisting-file-in-extension-image" + 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" } -hierarchy_ext_mut_path() { - local r=${1}; shift - local h=${1}; shift +prepare_extension_mutable_dir() { + local dir=${1:?} - # /a/b/c -> a.b.c - local n=${h} - n="${n##+(/)}" - n="${n%%+(/)}" - n="${n//\//.}" - - printf '%s' "${r}/var/lib/extensions.mutable/${n}" + mkdir -p "$dir" + touch "$dir/preexisting-file-in-extensions-mutable" } -prep_ext_mut() { - local p=${1}; shift +make_read_only() { + local root="${1:?}" + local hierarchy="${2:?}" - mkdir -p "${p}" - touch "${p}/preexisting-file-in-extensions-mutable" + mount -o bind,ro "$root$hierarchy" "$root$hierarchy" } -make_ro() { - local r=${1}; shift - local h=${1}; shift +prepare_hierarchy() { + local root="${1:?}" + local hierarchy="${2:?}" - mount -o bind "${r}${h}" "${r}${h}" - mount -o bind,remount,ro "${r}${h}" + touch "$root$hierarchy/preexisting-file-in-hierarchy" } -prep_hierarchy() { - local r=${1}; shift - local h=${1}; shift +prepare_read_only_hierarchy() { + local root="${1:?}" + local hierarchy="${2:?}" - touch "${r}${h}/preexisting-file-in-hierarchy" + prepare_hierarchy "$root" "$hierarchy" + make_read_only "$root" "$hierarchy" } -prep_ro_hierarchy() { - local r=${1}; shift - local h=${1}; shift +# 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 option - prep_hierarchy "${r}" "${h}" - make_ro "${r}" "${h}" -} - -# extra args: -# "e" for checking for the preexisting file in extension -# "h" for checking for the preexisting file in hierarchy -# "u" for checking for the preexisting file in upperdir -check_usual_suspects() { - local root=${1}; shift - local hierarchy=${1}; shift - local message=${1}; shift - - local arg - # shellcheck disable=SC2034 # the variables below are used indirectly - local e='' h='' u='' - - for arg; do - case ${arg} in + while getopts "ehu" opt; do + case "$opt" in e|h|u) - local -n v=${arg} - v=x - unset -n v + args[$opt]=1 ;; *) - die "invalid arg to ${0}: ${arg@Q}" - ;; + echo >&2 "Unxexpected option: $opt" + exit 1 esac done - # var name, file name - local pairs=( - e:preexisting-file-in-extension-image - h:preexisting-file-in-hierarchy - u:preexisting-file-in-extensions-mutable - ) - local pair name file desc full_path - for pair in "${pairs[@]}"; do - name=${pair%%:*} - file=${pair#*:} - desc=${file//-/ } - full_path="${root}${hierarchy}/${file}" - local -n v=${name} - if [[ -n ${v} ]]; then - test -f "${full_path}" || { - ls -la "$(dirname "${full_path}")" - die "${desc} is missing ${message}" - } + echo "${args[@]}" + + 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 - test ! -f "${full_path}" || { - ls -la "$(dirname "${full_path}")" - die "${desc} unexpectedly exists ${message}" - } + 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 - unset -n v done } -check_usual_suspects_after_merge() { - local r=${1}; shift - local h=${1}; shift +extension_verify_after_merge() ( + set +x - check_usual_suspects "${r}" "${h}" "after merge" "${@}" -} + local root="${1:?}" + local hierarchy="${2:?}" + shift 2 -check_usual_suspects_after_unmerge() { - local r=${1}; shift - local h=${1}; shift + extension_verify "$root" "$hierarchy" "after merge" "$@" +) - check_usual_suspects "${r}" "${h}" "after unmerge" "${@}" -} +extension_verify_after_unmerge() ( + set +x + + local root="${1:?}" + local hierarchy="${2:?}" + shift 2 + + extension_verify "$root" "$hierarchy" "after unmerge" "$@" +) # General systemd-sysext tests -# -# no extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# mutability disabled by default -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/simple-read-only-with-read-only-hierarchy +: "No extension data in /var/lib/extensions.mutable/…, R/O hierarchy, mutability disabled by default, read-only merged" +fake_root="$FAKE_ROOTS_DIR/simple-read-only-with-read-only-hierarchy" hierarchy=/usr -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" +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") -prep_ro_hierarchy "${fake_root}" "${hierarchy}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" merge +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only after unmerge" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") -# -# no extension data in /var/lib/extensions.mutable/…, mutable hierarchy, -# mutability disabled by default -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/simple-read-only-with-mutable-hierarchy +: "No extension data in /var/lib/extensions.mutable/…, mutable hierarchy, mutability disabled by default, read-only merged" +fake_root="$FAKE_ROOTS_DIR/simple-read-only-with-mutable-hierarchy" hierarchy=/usr -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" +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" -prep_hierarchy "${fake_root}" "${hierarchy}" +SYSTEMD_SYSEXT_HIERARCHIEe="$hierarchy" systemd-sysext --root="$fake_root" merge +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -touch "${fake_root}${hierarchy}/should-succeed-on-mutable-fs" || die "${fake_root}${hierarchy} is not mutable" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h - -touch "${fake_root}${hierarchy}/should-succeed-on-mutable-fs-again" || die "${fake_root}${hierarchy} is not mutable after unmerge" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +touch "$fake_root$hierarchy/should-succeed-on-mutable-fs-again" -# -# no extension data in /var/lib/extensions.mutable/…, no hierarchy either, -# mutability disabled by default -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/simple-read-only-with-missing-hierarchy +: "No extension data in /var/lib/extensions.mutable/…, no hierarchy either, mutability disabled by default, read-only merged" +fake_root="$FAKE_ROOTS_DIR/simple-read-only-with-missing-hierarchy" hierarchy=/opt -prep_root "${fake_root}" "${hierarchy}" -rmdir "${fake_root}/${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" +prepare_root "$fake_root" "$hierarchy" +rmdir "$fake_root/$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" merge +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -# -# no extension data in /var/lib/extensions.mutable/…, an empty hierarchy, -# mutability disabled by default -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/simple-read-only-with-empty-hierarchy +: "No extension data in /var/lib/extensions.mutable/…, empty hierarchy, mutability disabled by default, read-only merged" +fake_root="$FAKE_ROOTS_DIR/simple-read-only-with-empty-hierarchy" hierarchy=/opt -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${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") -make_ro "${fake_root}" "${hierarchy}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" merge +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, mutability disabled-by-default -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/simple-mutable-with-read-only-hierarchy-disabled +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, mutability disabled by default, read-only merged" +fake_root="$FAKE_ROOTS_DIR/simple-mutable-with-read-only-hierarchy-disabled" hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${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") -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" merge +(! touch "$fake_root$hierarchy/should-be-read-only") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -prep_ro_hierarchy "${fake_root}" "${hierarchy}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/should-be-read-only" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, auto-mutability -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/simple-mutable-with-read-only-hierarchy +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, auto-mutability, mutable merged" +fake_root="$FAKE_ROOTS_DIR/simple-mutable-with-read-only-hierarchy" hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${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") -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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" -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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" -# -# extension data in /var/lib/extensions.mutable/…, missing hierarchy, -# auto-mutability -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/simple-mutable-with-missing-hierarchy +: "Extension data in /var/lib/extensions.mutable/…, missing hierarchy, auto-mutability, mutable merged" +fake_root="$FAKE_ROOTS_DIR/simple-mutable-with-missing-hierarchy" hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" -prep_root "${fake_root}" "${hierarchy}" -rmdir "${fake_root}/${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${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" -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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 -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e u -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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" -# -# extension data in /var/lib/extensions.mutable/…, empty hierarchy, auto-mutability -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/simple-mutable-with-empty-hierarchy +: "Extension data in /var/lib/extensions.mutable/…, empty hierarchy, auto-mutability, mutable merged" +fake_root="$FAKE_ROOTS_DIR/simple-mutable-with-empty-hierarchy" hierarchy=/opt +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${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") -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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" -make_ro "${fake_root}" "${hierarchy}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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" -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" + +: "/var/lib/extensions.mutable/… is a symlink to other dir, R/O hierarchy, auto-mutability, mutable merged" +fake_root="$FAKE_ROOTS_DIR/mutable-symlink-with-read-only-hierarchy" +hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" +extension_real_dir="$fake_root/upperdir" + +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" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") + +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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" + +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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" + + +: "/var/lib/extensions.mutable/… is a symlink to the hierarchy itself, mutable hierarchy, auto-mutability, mutable merged" +fake_root="$FAKE_ROOTS_DIR/mutable-self-upper" +hierarchy=/usr +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" +touch "$fake_root$hierarchy/preexisting-file-in-hierarchy" + +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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" + +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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" + + +: "/var/lib/extensions.mutable/… is a symlink to the hierarchy itself, R/O hierarchy, auto-mutability, expected fail" +fake_root="$FAKE_ROOTS_DIR/failure-self-upper-ro" +hierarchy=/usr +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" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +(! SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" --mutable=auto merge) + + +: "/var/lib/extensions.mutable/… is a dangling symlink, auto-mutability, read-only merged" +fake_root="$FAKE_ROOTS_DIR/read-only-mutable-dangling-symlink" +hierarchy=/usr +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" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" +(! touch "$fake_root$hierarchy/should-fail-on-read-only-fs") # run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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 -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e u -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h -# -# /var/lib/extensions.mutable/… is a symlink to /some/other/dir, read-only -# hierarchy, auto-mutability -# -# mutable merged -# +: "/var/lib/extensions.mutable/… exists but ignored, mutability disabled explicitly, read-only merged" +fake_root="$FAKE_ROOTS_DIR/disabled" +hierarchy=/usr +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 +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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 + +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h -fake_root=${fake_roots_dir}/mutable-symlink-with-read-only-hierarchy +: "/var/lib/extensions.mutable/… exists but is imported instead, read-only merged" +fake_root="$FAKE_ROOTS_DIR/imported" +hierarchy=/usr +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 +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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 + +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h + + +: "/var/lib/extensions.mutable/… doesn't exists, mutability enabled, mutable merged" +fake_root="$FAKE_ROOTS_DIR/enabled" +hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +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_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" --mutable=yes merge +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_HIERARCHIES="$hierarchy" systemd-sysext --root="$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" + + +: "/var/lib/extensions.mutable/… doesn't exists, auto-mutability, read-only merged" +fake_root="$FAKE_ROOTS_DIR/simple-read-only-explicit" hierarchy=/usr -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" +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") -# generate extension writable data -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -real_ext_dir="${fake_root}/upperdir" -prep_ext_mut "${real_ext_dir}" -ln -sfTr "${real_ext_dir}" "${ext_data_path}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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 -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" -test -f "${real_ext_dir}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test -f "${real_ext_dir}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h -# -# /var/lib/extensions.mutable/… is a symlink to the hierarchy itself, auto-mutability -# -# for this to work, hierarchy must be mutable -# -# mutable merged -# +: "/var/lib/extensions.mutable/… doesn't exists, mutability enabled through env var, mutable merged" +fake_root="$FAKE_ROOTS_DIR/enabled-env-var" +hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" + +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_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=yes systemd-sysext --root="$fake_root" merge +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_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=yes systemd-sysext --root="$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" -fake_root=${fake_roots_dir}/mutable-self-upper +: "/var/lib/extensions.mutable/… doesn't exists, auto-mutability enabled through env var, read-only merged" +fake_root="$FAKE_ROOTS_DIR/read-only-auto-env-var" hierarchy=/usr -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" +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") -# generate extension writable data -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -real_ext_dir="${fake_root}${hierarchy}" -prep_ext_mut "${real_ext_dir}" -ln -sfTr "${real_ext_dir}" "${ext_data_path}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=auto systemd-sysext --root="$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 -# prepare writable hierarchy -touch "${fake_root}${hierarchy}/preexisting-file-in-hierarchy" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" -test -f "${real_ext_dir}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h u -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test -f "${real_ext_dir}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=auto systemd-sysext --root="$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h -# -# /var/lib/extensions.mutable/… is a symlink to the hierarchy itself, which is -# read-only, auto-mutability -# -# expecting a failure here -# - - -fake_root=${fake_roots_dir}/failure-self-upper-ro +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, auto-mutability enabled through env var, mutable merged" +fake_root="$FAKE_ROOTS_DIR/auto-mutable-env-var" hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${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") -# generate extension writable data -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -real_ext_dir="${fake_root}${hierarchy}" -prep_ext_mut "${real_ext_dir}" -ln -sfTr "${real_ext_dir}" "${ext_data_path}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=auto systemd-sysext --root="$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" -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge && die "expected merge to fail" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=auto systemd-sysext --root="$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" -# -# /var/lib/extensions.mutable/… is a dangling symlink, auto-mutability -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/read-only-mutable-dangling-symlink +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, mutability disabled through env var, read-only merged" +fake_root="$FAKE_ROOTS_DIR/env-var-disabled" hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${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") -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -ln -sfTr "/should/not/exist/" "${ext_data_path}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=no systemd-sysext --root="$fake_root" merge +(! touch "$fake_root$hierarchy/should-be-read-only") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=no systemd-sysext --root="$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h -# -# /var/lib/extensions.mutable/… exists, but it's ignored, mutability disabled explicitly -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/disabled +: "/var/lib/extensions.mutable/… exists but is imported through env var, read-only merged" +fake_root="$FAKE_ROOTS_DIR/imported-env-var" hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${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") -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=import systemd-sysext --root="$fake_root" merge +(! touch "$fake_root$hierarchy/should-still-fail-on-read-only-fs") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -u -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=no merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=import systemd-sysext --root="$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h -# -# /var/lib/extensions.mutable/… exists, but it's imported instead -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/imported +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, mutability enabled through env var but overriden via CLI option, read-only merged" +fake_root="$FAKE_ROOTS_DIR/env-var-overridden" hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${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") -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=yes systemd-sysext --root="$fake_root" --mutable=no merge +(! touch "$fake_root$hierarchy/should-be-read-only") +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=import merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=yes systemd-sysext --root="$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h -# -# /var/lib/extensions.mutable/… does not exist, but mutability is enabled -# explicitly -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/enabled +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, ephemeral mutability, mutable merged" +fake_root="$FAKE_ROOTS_DIR/ephemeral" hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${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") -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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" -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -test ! -d "${ext_data_path}" || die "extensions.mutable should not exist" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=yes merge - -test -d "${ext_data_path}" || die "extensions.mutable should exist now" -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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" -# -# /var/lib/extensions.mutable/… does not exist, auto-mutability -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/simple-read-only-explicit +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, ephemeral mutability through env var, mutable merged" +fake_root="$FAKE_ROOTS_DIR/ephemeral-env-var" hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${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") -prep_ro_hierarchy "${fake_root}" "${hierarchy}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=ephemeral systemd-sysext --root="$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" -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=ephemeral systemd-sysext --root="$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" -# -# /var/lib/extensions.mutable/… does not exist, but mutability is enabled -# through an env var -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/enabled-env-var +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, ephemeral import mutability, mutable merged" +fake_root="$FAKE_ROOTS_DIR/ephemeral-import" hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" -prep_env "yes" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -test ! -d "${ext_data_path}" || die "extensions.mutable should not exist" +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 -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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" -test -d "${ext_data_path}" || die "extensions.mutable should exist now" -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" -drop_env +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$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" -# -# /var/lib/extensions.mutable/… does not exist, auto-mutability through an env -# var -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/read-only-auto-env-var +: "Extension data in /var/lib/extensions.mutable/…, R/O hierarchy, ephemeral import mutability through env var, mutable merged" +fake_root="$FAKE_ROOTS_DIR/ephemeral-import-env-var" hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" -prep_env "auto" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${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") -prep_ro_hierarchy "${fake_root}" "${hierarchy}" +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=ephemeral-import systemd-sysext --root="$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" -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=auto merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -drop_env +SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" SYSTEMD_SYSEXT_MUTABLE_MODE=ephemeral-import systemd-sysext --root="$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" -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# auto-mutability through an env var -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/auto-mutable-env-var +: "Extension data pointing to mutable hierarchy, ephemeral import mutability, expected fail" +fake_root="$FAKE_ROOTS_DIR/ephemeral-import-self" hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" +extension_real_dir="$fake_root$hierarchy" -prep_env "auto" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${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" +prepare_hierarchy "$fake_root" "$hierarchy" +touch "$fake_root$hierarchy/should-succeed-on-read-only-fs" -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable is not stored in expected location" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable disappeared from writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" -drop_env +(! SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" --mutable=ephemeral-import merge) -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# mutability disabled through an env var -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/env-var-disabled +: "Extension data pointing to mutable hierarchy, import mutability, expected fail" +fake_root="$FAKE_ROOTS_DIR/import-self" hierarchy=/usr +extension_data_dir="$fake_root/var/lib/extensions.mutable$hierarchy" +extension_real_dir="$fake_root$hierarchy" -prep_env "no" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${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" +prepare_hierarchy "$fake_root" "$hierarchy" +touch "$fake_root$hierarchy/should-succeed-on-read-only-fs" -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/should-be-read-only" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -drop_env - - -# -# /var/lib/extensions.mutable/… exists, but it's imported instead through an -# env var -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/imported-env-var -hierarchy=/usr - -prep_env "import" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/should-still-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -drop_env - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# mutability enabled through an env var, but overridden with a command-line -# option -# -# read-only merged -# - - -fake_root=${fake_roots_dir}/env-var-overridden -hierarchy=/usr - -prep_env "yes" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=no merge - -touch "${fake_root}${hierarchy}/should-be-read-only" && die "${fake_root}${hierarchy} is not read-only" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -drop_env - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# ephemeral mutability, so extension data contents are ignored -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/ephemeral -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=ephemeral merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not be stored in extension data" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not appear in writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# ephemeral mutability through an env var, so extension data contents are -# ignored -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/ephemeral-env-var -hierarchy=/usr - -prep_env "ephemeral" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not be stored in extension data" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not appear in writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" -drop_env - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# ephemeral import mutability, so extension data contents are imported too -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/ephemeral-import -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=ephemeral-import merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not be stored in extension data" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not appear in writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" - - -# -# extension data in /var/lib/extensions.mutable/…, read-only hierarchy, -# ephemeral mutability through an env var, so extension data contents are -# imported too -# -# mutable merged -# - - -fake_root=${fake_roots_dir}/ephemeral-import-env-var -hierarchy=/usr - -prep_env "ephemeral-import" -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -prep_ext_mut "${ext_data_path}" - -prep_ro_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-fail-on-read-only-fs" && die "${fake_root}${hierarchy} is not read-only" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" merge - -touch "${fake_root}${hierarchy}/now-is-mutable" || die "${fake_root}${hierarchy} is not mutable" -check_usual_suspects_after_merge "${fake_root}" "${hierarchy}" e h u -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not be stored in extension data" - -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" unmerge - -check_usual_suspects_after_unmerge "${fake_root}" "${hierarchy}" h -test ! -f "${ext_data_path}/now-is-mutable" || die "now-is-mutable should not appear in writable storage after unmerge" -test ! -f "${fake_root}${hierarchy}/now-is-mutable" || die "now-is-mutable did not disappear from hierarchy after unmerge" -drop_env - - -# -# extension data pointing to mutable hierarchy, ephemeral import mutability -# -# expecting a failure here -# - - -fake_root=${fake_roots_dir}/ephemeral-import-self -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -real_ext_dir="${fake_root}${hierarchy}" -prep_ext_mut "${real_ext_dir}" -ln -sfTr "${real_ext_dir}" "${ext_data_path}" - -prep_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-succeed-on-read-only-fs" || die "${fake_root}${hierarchy} is not mutable" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=ephemeral-import merge && die 'expected merge to fail' - - -# -# extension data pointing to mutable hierarchy, import mutability -# -# expecting a failure here -# - - -fake_root=${fake_roots_dir}/import-self -hierarchy=/usr - -prep_root "${fake_root}" "${hierarchy}" -gen_os_release "${fake_root}" -gen_test_ext_image "${fake_root}" "${hierarchy}" - -ext_data_path=$(hierarchy_ext_mut_path "${fake_root}" "${hierarchy}") -real_ext_dir="${fake_root}${hierarchy}" -prep_ext_mut "${real_ext_dir}" -ln -sfTr "${real_ext_dir}" "${ext_data_path}" - -prep_hierarchy "${fake_root}" "${hierarchy}" - -touch "${fake_root}${hierarchy}/should-succeed-on-read-only-fs" || die "${fake_root}${hierarchy} is not mutable" - -# run systemd-sysext -SYSTEMD_SYSEXT_HIERARCHIES="${hierarchy}" systemd-sysext --root="${fake_root}" --mutable=import merge && die 'expected merge to fail' +(! SYSTEMD_SYSEXT_HIERARCHIES="$hierarchy" systemd-sysext --root="$fake_root" --mutable=import merge) exit 0