set -o pipefail
SYSUPDATE=/lib/systemd/systemd-sysupdate
+SECTOR_SIZES="512 4096"
+BACKING_FILE=/var/tmp/72-joined.raw
+export SYSTEMD_ESP_PATH=/var/tmp/72-esp
+export SYSTEMD_XBOOTLDR_PATH=/var/tmp/72-xbootldr
+export SYSTEMD_PAGER=cat
+export SYSTEMD_LOG_LEVEL=debug
if ! test -x "$SYSUPDATE"; then
echo "no systemd-sysupdate" >/skipped
exit 0
fi
-export SYSTEMD_PAGER=cat
-export SYSTEMD_LOG_LEVEL=debug
+# Loopback devices may not be supported. They are used because sfdisk cannot
+# change the sector size of a file, and we want to test both 512 and 4096 byte
+# sectors. If loopback devices are not supported, we can only test one sector
+# size, and the underlying device is likely to have a sector size of 512 bytes.
+if ! losetup --find >/dev/null 2>&1; then
+ echo "No loopback device support"
+ SECTOR_SIZES="512"
+fi
-rm -f /var/tmp/72-joined.raw
-truncate -s 10M /var/tmp/72-joined.raw
+trap cleanup ERR
+cleanup() {
+ set +o pipefail
+ blockdev="$( losetup --list --output NAME,BACK-FILE | grep $BACKING_FILE | cut -d' ' -f1)"
+ [ -n "$blockdev" ] && losetup --detach "$blockdev"
+ rm -f "$BACKING_FILE"
+ rm -rf /var/tmp/72-{dirs,defs,source,xbootldr,esp}
+ rm -f /testok
+}
+
+new_version() {
+ # Inputs:
+ # $1: sector size
+ # $2: version
+
+ # Create a pair of random partition payloads, and compress one
+ dd if=/dev/urandom of="/var/tmp/72-source/part1-$2.raw" bs="$1" count=2048
+ dd if=/dev/urandom of="/var/tmp/72-source/part2-$2.raw" bs="$1" count=2048
+ gzip -k -f "/var/tmp/72-source/part2-$2.raw"
+
+ # Create a random "UKI" payload
+ echo $RANDOM >"/var/tmp/72-source/uki-$2.efi"
+
+ # Create tarball of a directory
+ mkdir -p "/var/tmp/72-source/dir-$2"
+ echo $RANDOM >"/var/tmp/72-source/dir-$2/foo.txt"
+ echo $RANDOM >"/var/tmp/72-source/dir-$2/bar.txt"
+ tar --numeric-owner -C "/var/tmp/72-source/dir-$2/" -czf "/var/tmp/72-source/dir-$2.tar.gz" .
+
+ ( cd /var/tmp/72-source/ && sha256sum uki* part* dir-*.tar.gz >SHA256SUMS )
+}
-sfdisk /var/tmp/72-joined.raw <<EOF
+update_now() {
+ # Update to newest version. First there should be an update ready, then we
+ # do the update, and then there should not be any ready anymore
+
+ "$SYSUPDATE" --definitions=/var/tmp/72-defs --verify=no check-new
+ "$SYSUPDATE" --definitions=/var/tmp/72-defs --verify=no update
+ ( ! "$SYSUPDATE" --definitions=/var/tmp/72-defs --verify=no check-new )
+}
+
+verify_version() {
+ # Inputs:
+ # $1: block device
+ # $2: sector size
+ # $3: version
+ # $4: partiton number of part1
+ # $5: partiton number of part2
+
+ gpt_reserved_sectors=$(( 1024 * 1024 / $2 ))
+ part1_offset=$(( ( $4 - 1 ) * 2048 + gpt_reserved_sectors ))
+ part2_offset=$(( ( $5 - 1 ) * 2048 + gpt_reserved_sectors ))
+
+ # Check the partitions
+ dd if="$1" bs="$2" skip="$part1_offset" count=2048 | cmp "/var/tmp/72-source/part1-$3.raw"
+ dd if="$1" bs="$2" skip="$part2_offset" count=2048 | cmp "/var/tmp/72-source/part2-$3.raw"
+
+ # Check the UKI
+ cmp "/var/tmp/72-source/uki-$3.efi" "/var/tmp/72-xbootldr/EFI/Linux/uki_$3+3-0.efi"
+ test -z "$(ls -A /var/tmp/72-esp/EFI/Linux)"
+
+ # Check the directories
+ cmp "/var/tmp/72-source/dir-$3/foo.txt" /var/tmp/72-dirs/current/foo.txt
+ cmp "/var/tmp/72-source/dir-$3/bar.txt" /var/tmp/72-dirs/current/bar.txt
+}
+
+for sector_size in $SECTOR_SIZES ; do
+ # Disk size of:
+ # - 1MB for GPT
+ # - 4 partitions of 2048 sectors each
+ # - 1MB for backup GPT
+ disk_size=$(( sector_size * 2048 * 4 + 1024 * 1024 * 2 ))
+ rm -f "$BACKING_FILE"
+ truncate -s "$disk_size" "$BACKING_FILE"
+
+ if losetup --find >/dev/null 2>&1; then
+ # shellcheck disable=SC2086
+ blockdev="$(losetup --find --show --sector-size $sector_size $BACKING_FILE)"
+ else
+ blockdev="$BACKING_FILE"
+ fi
+
+ sfdisk "$blockdev" <<EOF
label: gpt
unit: sectors
-sector-size: 512
+sector-size: $sector_size
size=2048, type=4f68bce3-e8cd-4db1-96e7-fbcaf984b709, name=_empty
size=2048, type=4f68bce3-e8cd-4db1-96e7-fbcaf984b709, name=_empty
size=2048, type=2c7357ed-ebd2-46d9-aec1-23d437ec2bf5, name=_empty
EOF
-rm -rf /var/tmp/72-dirs
-mkdir -p /var/tmp/72-dirs
+ rm -rf /var/tmp/72-dirs
+ mkdir -p /var/tmp/72-dirs
-rm -rf /var/tmp/72-defs
-mkdir -p /var/tmp/72-defs
+ rm -rf /var/tmp/72-defs
+ mkdir -p /var/tmp/72-defs
-cat >/var/tmp/72-defs/01-first.conf <<"EOF"
+ cat >/var/tmp/72-defs/01-first.conf <<EOF
[Source]
Type=regular-file
Path=/var/tmp/72-source
[Target]
Type=partition
-Path=/var/tmp/72-joined.raw
+Path=$blockdev
MatchPattern=part1-@v
MatchPartitionType=root-x86-64
EOF
-cat >/var/tmp/72-defs/02-second.conf <<"EOF"
+ cat >/var/tmp/72-defs/02-second.conf <<EOF
[Source]
Type=regular-file
Path=/var/tmp/72-source
[Target]
Type=partition
-Path=/var/tmp/72-joined.raw
+Path=$blockdev
MatchPattern=part2-@v
MatchPartitionType=root-x86-64-verity
EOF
-cat >/var/tmp/72-defs/03-third.conf <<"EOF"
+ cat >/var/tmp/72-defs/03-third.conf <<EOF
[Source]
Type=directory
Path=/var/tmp/72-source
InstancesMax=3
EOF
-cat >/var/tmp/72-defs/04-fourth.conf <<"EOF"
+ cat >/var/tmp/72-defs/04-fourth.conf <<EOF
[Source]
Type=regular-file
Path=/var/tmp/72-source
Path=/EFI/Linux
PathRelativeTo=boot
MatchPattern=uki_@v+@l-@d.efi \
- uki_@v+@l.efi \
- uki_@v.efi
+ uki_@v+@l.efi \
+ uki_@v.efi
Mode=0444
TriesLeft=3
TriesDone=0
InstancesMax=2
EOF
-rm -rf /var/tmp/72-esp /var/tmp/72-xbootldr
-mkdir -p /var/tmp/72-esp/EFI/Linux /var/tmp/72-xbootldr/EFI/Linux
-export SYSTEMD_ESP_PATH=/var/tmp/72-esp
-export SYSTEMD_XBOOTLDR_PATH=/var/tmp/72-xbootldr
-
-rm -rf /var/tmp/72-source
-mkdir -p /var/tmp/72-source
-
-new_version() {
- # Create a pair of random partition payloads, and compress one
- dd if=/dev/urandom of="/var/tmp/72-source/part1-$1.raw" bs=1024 count=1024
- dd if=/dev/urandom of="/var/tmp/72-source/part2-$1.raw" bs=1024 count=1024
- gzip -k -f "/var/tmp/72-source/part2-$1.raw"
-
- # Create a random "UKI" payload
- echo $RANDOM >"/var/tmp/72-source/uki-$1.efi"
-
- # Create tarball of a directory
- mkdir -p "/var/tmp/72-source/dir-$1"
- echo $RANDOM >"/var/tmp/72-source/dir-$1/foo.txt"
- echo $RANDOM >"/var/tmp/72-source/dir-$1/bar.txt"
- tar --numeric-owner -C "/var/tmp/72-source/dir-$1/" -czf "/var/tmp/72-source/dir-$1.tar.gz" .
-
- ( cd /var/tmp/72-source/ && sha256sum uki* part* dir-*.tar.gz >SHA256SUMS )
-}
-
-update_now() {
- # Update to newest version. First there should be an update ready, then we
- # do the update, and then there should not be any ready anymore
-
- "$SYSUPDATE" --definitions=/var/tmp/72-defs --verify=no check-new
- "$SYSUPDATE" --definitions=/var/tmp/72-defs --verify=no update
- ( ! "$SYSUPDATE" --definitions=/var/tmp/72-defs --verify=no check-new )
-}
-
-verify_version() {
- # Expects: version ID + sector offset of both partitions to compare
-
- # Check the partitions
- dd if=/var/tmp/72-joined.raw bs=1024 skip="$2" count=1024 | cmp "/var/tmp/72-source/part1-$1.raw"
- dd if=/var/tmp/72-joined.raw bs=1024 skip="$3" count=1024 | cmp "/var/tmp/72-source/part2-$1.raw"
-
- # Check the UKI
- cmp "/var/tmp/72-source/uki-$1.efi" "/var/tmp/72-xbootldr/EFI/Linux/uki_$1+3-0.efi"
- test -z "$(ls -A /var/tmp/72-esp/EFI/Linux)"
-
- # Check the directories
- cmp "/var/tmp/72-source/dir-$1/foo.txt" /var/tmp/72-dirs/current/foo.txt
- cmp "/var/tmp/72-source/dir-$1/bar.txt" /var/tmp/72-dirs/current/bar.txt
-}
-
-# Install initial version and verify
-new_version v1
-update_now
-verify_version v1 1024 3072
-
-# Create second version, update and verify that it is added
-new_version v2
-update_now
-verify_version v2 2048 4096
-
-# Create third version, update and verify it replaced the first version
-new_version v3
-update_now
-verify_version v3 1024 3072
-test ! -f "/var/tmp/72-xbootldr/EFI/Linux/uki_v1+3-0.efi"
-
-# Create fourth version, and update through a file:// URL. This should be
-# almost as good as testing HTTP, but is simpler for us to set up. file:// is
-# abstracted in curl for us, and since our main goal is to test our own code
-# (and not curl) this test should be quite good even if not comprehensive. This
-# will test the SHA256SUMS logic at least (we turn off GPG validation though,
-# see above)
-new_version v4
-
-cat >/var/tmp/72-defs/02-second.conf <<"EOF"
+ rm -rf /var/tmp/72-esp /var/tmp/72-xbootldr
+ mkdir -p /var/tmp/72-esp/EFI/Linux /var/tmp/72-xbootldr/EFI/Linux
+
+ rm -rf /var/tmp/72-source
+ mkdir -p /var/tmp/72-source
+
+ # Install initial version and verify
+ new_version "$sector_size" v1
+ update_now
+ verify_version "$blockdev" "$sector_size" v1 1 3
+
+ # Create second version, update and verify that it is added
+ new_version "$sector_size" v2
+ update_now
+ verify_version "$blockdev" "$sector_size" v2 2 4
+
+ # Create third version, update and verify it replaced the first version
+ new_version "$sector_size" v3
+ update_now
+ verify_version "$blockdev" "$sector_size" v3 1 3
+ test ! -f "/var/tmp/72-xbootldr/EFI/Linux/uki_v1+3-0.efi"
+
+ # Create fourth version, and update through a file:// URL. This should be
+ # almost as good as testing HTTP, but is simpler for us to set up. file:// is
+ # abstracted in curl for us, and since our main goal is to test our own code
+ # (and not curl) this test should be quite good even if not comprehensive. This
+ # will test the SHA256SUMS logic at least (we turn off GPG validation though,
+ # see above)
+ new_version "$sector_size" v4
+
+ cat >/var/tmp/72-defs/02-second.conf <<EOF
[Source]
Type=url-file
Path=file:///var/tmp/72-source
[Target]
Type=partition
-Path=/var/tmp/72-joined.raw
+Path=$blockdev
MatchPattern=part2-@v
MatchPartitionType=root-x86-64-verity
EOF
-cat >/var/tmp/72-defs/03-third.conf <<"EOF"
+ cat >/var/tmp/72-defs/03-third.conf <<EOF
[Source]
Type=url-tar
Path=file:///var/tmp/72-source
InstancesMax=3
EOF
-update_now
-verify_version v4 2048 4096
+ update_now
+ verify_version "$blockdev" "$sector_size" v4 2 4
+
+ # Cleanup
+ [ -b "$blockdev" ] && losetup --detach "$blockdev"
+ rm "$BACKING_FILE"
+done
-rm /var/tmp/72-joined.raw
rm -r /var/tmp/72-{dirs,defs,source,xbootldr,esp}
touch /testok