summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortranch <tranch.xiao@gmail.com>2026-08-26 10:41:01 +0800
committertranch <tranch.xiao@gmail.com>2026-08-26 10:41:01 +0800
commit6cb356d3837ef5a9637c2f6df1de7ef85196c280 (patch)
tree2c4cb3d437f311e3f0256540af735709a77e5990
parent0a25c4e957f98df15c5e914fd647c3cd6de54456 (diff)
downloadAeroCore-OS-6cb356d3837ef5a9637c2f6df1de7ef85196c280.tar.gz
AeroCore-OS-6cb356d3837ef5a9637c2f6df1de7ef85196c280.zip
fix(installer): configure the GPT auto-root type
Resolve Anaconda target mounts to their backing partition before marking it as the bootc GPT auto-root partition.
-rw-r--r--.github/workflows/validate-installer-iso.yml3
-rwxr-xr-xinstaller/build.sh25
-rwxr-xr-xinstaller/configure-target-gpt-root.sh40
-rwxr-xr-xtests/test-configure-target-gpt-root.sh51
4 files changed, 119 insertions, 0 deletions
diff --git a/.github/workflows/validate-installer-iso.yml b/.github/workflows/validate-installer-iso.yml
index 5aa6335..2151a23 100644
--- a/.github/workflows/validate-installer-iso.yml
+++ b/.github/workflows/validate-installer-iso.yml
@@ -42,6 +42,9 @@ jobs:
- name: Test Bazzite Deck identity patch
run: tests/test-patch-bazzite-deck-identity.sh
+ - name: Test GPT root configuration
+ run: tests/test-configure-target-gpt-root.sh
+
- name: Validate Anaconda WebUI patch
run: |
fixture="$(mktemp)"
diff --git a/installer/build.sh b/installer/build.sh
index 3d6659f..205f18c 100755
--- a/installer/build.sh
+++ b/installer/build.sh
@@ -23,6 +23,7 @@ dnf --setopt=excludepkgs= install -y \
libblockdev-lvm \
dracut-live \
livesys-scripts \
+ gdisk \
grub2-efi-x64 \
grub2-efi-x64-cdboot
@@ -62,6 +63,10 @@ install -Dm0755 \
"${SCRIPT_DIR}/configure-target-grub.sh" \
/usr/libexec/aerocore-configure-target-grub
+install -Dm0755 \
+ "${SCRIPT_DIR}/configure-target-gpt-root.sh" \
+ /usr/libexec/aerocore-configure-target-gpt-root
+
# Plasma's live-session launcher defaults to start-here, and Fedora keeps
# LOGO=fedora-logo-icon in the base live environment.
for size in 16x16 22x22 24x24 32x32 36x36 48x48 64x64 96x96 128x128 256x256; do
@@ -132,6 +137,26 @@ mount --bind \${target_tmp} /var/tmp
df -h /var/tmp \${target_tmp}
%end
+# bootc relies on systemd's GPT auto-root discovery on the first boot. Anaconda
+# can leave the installed root partition with the generic Linux filesystem
+# type, which makes /dev/gpt-auto-root unavailable even though the filesystem
+# itself is healthy. Normalize the type before ostreecontainer deployment.
+%pre-install --erroronfail --log=/tmp/aerocore-gpt-root.log
+set -eux
+target_root=
+for root in /mnt/sysroot /mnt/sysimage /var/mnt/sysroot /var/mnt/sysimage; do
+ if mountpoint -q \${root}; then
+ target_root=\${root}
+ break
+ fi
+done
+if [ x\${target_root} = x ]; then
+ echo No mounted target system found for GPT root configuration >&2
+ exit 1
+fi
+/usr/libexec/aerocore-configure-target-gpt-root \${target_root}
+%end
+
ostreecontainer --url=${INSTALL_IMAGE_PAYLOAD} --transport=containers-storage --no-signature-verification
# The local containers-storage deployment is intentionally unverified because
diff --git a/installer/configure-target-gpt-root.sh b/installer/configure-target-gpt-root.sh
new file mode 100755
index 0000000..470821e
--- /dev/null
+++ b/installer/configure-target-gpt-root.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+target_root=${1:?usage: configure-target-gpt-root.sh TARGET_ROOT}
+
+source_device="$(findmnt --nofsroot -no SOURCE --target "${target_root}")"
+# For a Btrfs subvolume, findmnt decorates the backing device with the
+# subvolume path (for example, /dev/vda3[/root]). lsblk and the partition
+# validation below require the undecorated block-device path.
+source_device="${source_device%%\[*}"
+# Anaconda can bind-mount the target at /mnt/sysroot. In that case findmnt's
+# human-readable SOURCE is "root", even though the mounted filesystem still
+# has the real target partition's device number. Resolve that number through
+# lsblk before requiring a partition-backed source.
+if [[ ! "${source_device}" =~ ^/dev/ ]]; then
+ source_maj_min="$(findmnt -no MAJ:MIN --target "${target_root}")"
+ source_device="$(lsblk -nrpo NAME,MAJ:MIN | awk -v wanted="${source_maj_min}" '$2 == wanted { print $1; exit }')"
+fi
+
+case "${source_device}" in
+ /dev/*[0-9]) ;;
+ *)
+ echo "Could not resolve a partition-backed target root: ${source_device}" >&2
+ exit 1
+ ;;
+esac
+
+parent_device="$(lsblk -no PKNAME "${source_device}")"
+partition_number="$(lsblk -no PARTN "${source_device}")"
+if [[ -z "${parent_device}" || -z "${partition_number}" ]]; then
+ echo "Could not resolve parent disk and partition number for ${source_device}" >&2
+ exit 1
+fi
+
+disk="/dev/${parent_device}"
+root_type_guid="4f68bce3-e8cd-4db1-96e7-fbcaf984b709"
+echo "Setting ${source_device} (partition ${partition_number} on ${disk}) to GPT root-x86-64 type ${root_type_guid}"
+sgdisk --typecode="${partition_number}:${root_type_guid}" "${disk}"
+partprobe "${disk}" || true
diff --git a/tests/test-configure-target-gpt-root.sh b/tests/test-configure-target-gpt-root.sh
new file mode 100755
index 0000000..ed5e33e
--- /dev/null
+++ b/tests/test-configure-target-gpt-root.sh
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+project_root="$(git rev-parse --show-toplevel)"
+tmp_dir="$(mktemp -d)"
+trap 'rm -rf "${tmp_dir}"' EXIT
+mkdir -p "${tmp_dir}/bin"
+
+# shellcheck disable=SC2016 # The generated fixture expands this in its own process.
+printf '%s\n' \
+ '#!/usr/bin/env bash' \
+ 'if [[ " $* " == *" -no SOURCE "* ]]; then' \
+ ' [[ " $* " == *" --nofsroot "* ]] || exit 97' \
+ ' printf "%s\\n" "${TEST_FINDMNT_SOURCE:?}"' \
+ 'else' \
+ " printf '252:3\\n'" \
+ 'fi' > "${tmp_dir}/bin/findmnt"
+
+printf '%s\n' \
+ '#!/usr/bin/env bash' \
+ 'case " $* " in' \
+ " *\" PKNAME \"*) printf 'vda\\n' ;;" \
+ " *\" PARTN \"*) printf '3\\n' ;;" \
+ " *\" PARTNUM \"*) exit 98 ;;" \
+ " *) printf '/dev/vda3 252:3\\n' ;;" \
+ 'esac' > "${tmp_dir}/bin/lsblk"
+
+# shellcheck disable=SC2016 # The generated fixture expands TEST_OUTPUT itself.
+printf '%s\n' \
+ '#!/usr/bin/env bash' \
+ 'printf "%s\\n" "$*" > "${TEST_OUTPUT:?}"' > "${tmp_dir}/bin/sgdisk"
+
+printf '%s\n' '#!/usr/bin/env bash' 'exit 0' > "${tmp_dir}/bin/partprobe"
+
+chmod +x "${tmp_dir}/bin/"*
+
+run_fixture() {
+ local findmnt_source=$1
+
+ TEST_FINDMNT_SOURCE="${findmnt_source}" TEST_OUTPUT="${tmp_dir}/sgdisk.args" \
+ PATH="${tmp_dir}/bin:${PATH}" \
+ bash "${project_root}/installer/configure-target-gpt-root.sh" /mnt/sysroot
+
+ grep -qx -- '--typecode=3:4f68bce3-e8cd-4db1-96e7-fbcaf984b709 /dev/vda' \
+ "${tmp_dir}/sgdisk.args"
+}
+
+run_fixture root
+run_fixture '/dev/vda3[/root]'
+printf 'GPT root bind-mount and Btrfs subvolume fixtures passed\n'