diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-27 22:08:28 -0400 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-27 22:08:28 -0400 |
| commit | 2ead67458add6accda226cca3e21592162d05bfd (patch) | |
| tree | 0f180ac7f1132d1e8dc6b1845e4d48e622f4eee4 | |
| parent | 89691a0dc9eb7dcbf8583797d7cdc34aecec0d56 (diff) | |
| download | archangel-2ead67458add6accda226cca3e21592162d05bfd.tar.gz archangel-2ead67458add6accda226cca3e21592162d05bfd.zip | |
The baked AUR set installed unconditionally, so zfs-auto-snapshot reached every target. On a btrfs install there's no zfs to satisfy its dependency, and pacstrap aborted the whole transaction. The ISO still bakes the full set. install_base now filters the manifest names through filter_aur_for_fs, dropping zfs-only tooling (zfs-auto-snapshot, zrepl) on a non-zfs target.
strip_repo_stanza mv'd a 0600 mktemp file onto the target, so a clean install shipped /etc/pacman.conf root-only and every user-level makepkg/yay failed to read it. It now truncate-writes through the existing file, preserving the pristine 0644.
Tested in test_common.bats.
| -rwxr-xr-x | installer/archangel | 5 | ||||
| -rw-r--r-- | installer/lib/common.sh | 41 | ||||
| -rw-r--r-- | tests/unit/test_common.bats | 70 |
3 files changed, 115 insertions, 1 deletions
diff --git a/installer/archangel b/installer/archangel index f90b158..4805796 100755 --- a/installer/archangel +++ b/installer/archangel @@ -791,6 +791,11 @@ EOF info "Exposing baked AUR repo to pacstrap..." append_aur_repo /etc/pacman.conf "file://$aur_repo_dir" mapfile -t aur_packages < <(aur_manifest_names "$aur_repo_dir/manifest.tsv") + # Drop ZFS-only AUR tooling on a non-ZFS target. The baked repo carries + # the full set on every ISO, but e.g. zfs-auto-snapshot has a hard zfs + # dependency that can't resolve on a btrfs install and would abort the + # whole pacstrap transaction. + mapfile -t aur_packages < <(filter_aur_for_fs "$FILESYSTEM" "${aur_packages[@]}") info "Baked AUR packages to install: ${aur_packages[*]:-none}" fi diff --git a/installer/lib/common.sh b/installer/lib/common.sh index 0317034..0378756 100644 --- a/installer/lib/common.sh +++ b/installer/lib/common.sh @@ -166,6 +166,38 @@ aur_manifest_names() { awk -F'\t' 'NR>1 {print $1}' "$manifest" } +# Print the baked AUR packages that are ZFS-only tooling, one per line. The ISO +# bakes the full AUR set on every build, but these require a ZFS root: +# zfs-auto-snapshot has a hard `zfs` dependency, and zrepl is ZFS replication. +# On a non-ZFS install neither dependency exists, so installing them is at best +# pointless and at worst aborts pacstrap (zfs-auto-snapshot's unmet `zfs` dep +# fails the whole transaction). Keep in lockstep with build-aur.sh's +# aur_v1_packages: a new ZFS-only AUR package added there belongs here too. +aur_zfs_only_packages() { + printf '%s\n' \ + zfs-auto-snapshot \ + zrepl +} + +# Filter a list of AUR package names for the target filesystem, printing the +# kept names one per line in input order. On a ZFS target every package passes +# through. On any other filesystem the ZFS-only tooling (aur_zfs_only_packages) +# is dropped so it never reaches pacstrap. install_base runs the baked manifest +# names through this before appending them to the pacstrap set. +filter_aur_for_fs() { + local fs="$1"; shift + local -A drop=() + if [[ "$fs" != zfs ]]; then + local z + while IFS= read -r z; do drop["$z"]=1; done < <(aur_zfs_only_packages) + fi + local pkg + for pkg in "$@"; do + [[ -n "${drop[$pkg]:-}" ]] && continue + printf '%s\n' "$pkg" + done +} + # Remove the named repo's stanza (its [name] header and the config lines up to # the next [section] or EOF) from the pacman.conf at $2. Used to ensure the # installed target never references the baked [aur] repo, whose @@ -181,7 +213,14 @@ strip_repo_stanza() { skip { next } { print } ' "$pacman_conf" > "$tmp" - mv "$tmp" "$pacman_conf" + # Truncate-write in place rather than `mv` the temp over the target: mktemp + # creates the temp 0600, and a mv would carry that onto pacman.conf, + # clobbering its pristine 0644 and leaving the installed config root-only. + # That broke every user-level makepkg/yay ("config file /etc/pacman.conf + # could not be read: Permission denied"). Writing through the existing file + # keeps its inode and mode. + cat "$tmp" > "$pacman_conf" + rm -f "$tmp" } ############################# diff --git a/tests/unit/test_common.bats b/tests/unit/test_common.bats index 6f9d1b1..c76b6a4 100644 --- a/tests/unit/test_common.bats +++ b/tests/unit/test_common.bats @@ -666,6 +666,26 @@ Boot0001* ZFSBootMenu" rm -f "$f" } +@test "strip_repo_stanza preserves the target file mode (no 0600 clobber)" { + local f + f=$(mktemp) + printf '%s\n' '[core]' '[aur]' 'Server = file:///usr/share/aur-packages' '[extra]' > "$f" + chmod 644 "$f" + strip_repo_stanza aur "$f" + [ "$(stat -c %a "$f")" = "644" ] + rm -f "$f" +} + +@test "strip_repo_stanza preserves a non-default file mode" { + local f + f=$(mktemp) + printf '%s\n' '[core]' '[aur]' 'Server = x' '[extra]' > "$f" + chmod 640 "$f" + strip_repo_stanza aur "$f" + [ "$(stat -c %a "$f")" = "640" ] + rm -f "$f" +} + ############################# # aur_repo_available ############################# @@ -720,3 +740,53 @@ Boot0001* ZFSBootMenu" [ "$status" -eq 0 ] [ -z "$output" ] } + +############################# +# aur_zfs_only_packages / filter_aur_for_fs +############################# + +@test "aur_zfs_only_packages lists zfs-auto-snapshot and zrepl" { + run aur_zfs_only_packages + [ "$status" -eq 0 ] + [[ "$output" == *"zfs-auto-snapshot"* ]] + [[ "$output" == *"zrepl"* ]] +} + +@test "filter_aur_for_fs zfs keeps every package including zfs-only tooling" { + run filter_aur_for_fs zfs downgrade yay zrepl zfs-auto-snapshot topgrade + [ "$status" -eq 0 ] + [ "${#lines[@]}" -eq 5 ] + [[ "$output" == *"zfs-auto-snapshot"* ]] + [[ "$output" == *"zrepl"* ]] + [[ "$output" == *"yay"* ]] +} + +@test "filter_aur_for_fs btrfs drops zfs-only tooling, keeps the rest" { + run filter_aur_for_fs btrfs downgrade yay zrepl zfs-auto-snapshot topgrade + [ "$status" -eq 0 ] + [ "${#lines[@]}" -eq 3 ] + [[ "$output" != *"zfs-auto-snapshot"* ]] + [[ "$output" != *"zrepl"* ]] + [[ "$output" == *"downgrade"* ]] + [[ "$output" == *"yay"* ]] + [[ "$output" == *"topgrade"* ]] +} + +@test "filter_aur_for_fs btrfs with only zfs-only tooling prints nothing" { + run filter_aur_for_fs btrfs zfs-auto-snapshot zrepl + [ "$status" -eq 0 ] + [ -z "$output" ] +} + +@test "filter_aur_for_fs with no package arguments prints nothing" { + run filter_aur_for_fs btrfs + [ "$status" -eq 0 ] + [ -z "$output" ] +} + +@test "filter_aur_for_fs preserves input order" { + run filter_aur_for_fs zfs yay downgrade topgrade + [ "$status" -eq 0 ] + [ "${lines[0]}" = "yay" ] + [ "${lines[2]}" = "topgrade" ] +} |
