Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions bin/omarchy-mac-kernel-wip
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ m1n1_boot_bin() {
fi
local candidate
for candidate in /boot/m1n1/boot.bin /boot/efi/m1n1/boot.bin; do
if [[ -e $candidate ]]; then
# If boot.bin is missing but a saved image remains, keep its path
# discoverable so --rollback-boot can restore it.
if [[ -e $candidate || -e ${candidate}.omarchy-pre-wip || -e ${candidate}.old ]]; then
printf '%s\n' "$candidate"
return 0
fi
Expand All @@ -61,7 +63,7 @@ snapshot_boot_bin() {
}

rollback_boot_bin() {
local boot previous
local boot previous temporary
boot=$(m1n1_boot_bin) || return 1
if [[ -e ${boot}.omarchy-pre-wip ]]; then
previous=${boot}.omarchy-pre-wip
Expand All @@ -70,7 +72,17 @@ rollback_boot_bin() {
else
return 1
fi
sudo cp -a -- "$previous" "$boot" || return 1
# Copy beside the destination and rename within the ESP. A direct cp can
# leave a truncated boot image if the copy is interrupted.
temporary=$(sudo mktemp "${boot}.omarchy-restore.XXXXXX") || return 1
sudo cp -a -- "$previous" "$temporary" || {
sudo rm -f -- "$temporary"
return 1
}
sudo mv -f -- "$temporary" "$boot" || {
sudo rm -f -- "$temporary"
return 1
}
log "Restored $boot from $(basename "$previous")"
}

Expand All @@ -91,6 +103,15 @@ warn_shared_boot_image() {
log "After a failed boot, from macOS copy m1n1/boot.bin.old over boot.bin."
}

install_wip_package() {
local pkg="$1"
snapshot_boot_bin ||
fail "could not snapshot the current m1n1 boot image; refusing to install the WIP kernel without a recovery copy"
log "Installing $(basename "$pkg")"
sudo pacman -U --noconfirm "$pkg"
refresh_boot
}

main() {
while (( $# )); do
case $1 in
Expand Down Expand Up @@ -158,10 +179,7 @@ main() {

pkg=$(ls -1t "$build_dir"/linux-asahi-wip-*.pkg.tar.* | grep -v '\.sig$' | head -1)
[[ -n $pkg ]] || fail "no package was produced"
snapshot_boot_bin || log "could not snapshot boot.bin; if the new DTBs do not boot, restore boot.bin.old from macOS"
log "Installing $(basename "$pkg")"
sudo pacman -U --noconfirm "$pkg"
refresh_boot
install_wip_package "$pkg"

log "Installed. Reboot and pick the linux-asahi-wip entry in GRUB."
warn_shared_boot_image
Expand Down
36 changes: 35 additions & 1 deletion test/shell.d/apple-kernel-wip-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ cat >"$stub_bin/sudo" <<'SH'
if [[ ${TEST_FAIL_BOOT_COPY:-0} == "1" && $1 == "cp" ]]; then
exit 1
fi
if [[ ${TEST_FAIL_BOOT_MOVE:-0} == "1" && $1 == "mv" ]]; then
exit 1
fi
exec "$@"
SH
chmod +x "$stub_bin/sudo"
Expand Down Expand Up @@ -64,6 +67,37 @@ run_helper rollback_boot_bin || fail "rollback falls back to boot.bin.old"
cmp -s "$boot" <(printf 'update-m1n1-old\n') || fail "rollback uses update-m1n1's boot.bin.old"
pass "rollback_boot_bin falls back to boot.bin.old"

# Recovery must still find the ESP path when a failed update removed boot.bin
# but left the saved image behind.
printf 'released-dtbs\n' >"${boot}.omarchy-pre-wip"
rm -f "$boot" "$boot.old"
run_helper rollback_boot_bin || fail "rollback_boot_bin finds a saved image when boot.bin is missing"
cmp -s "$boot" <(printf 'released-dtbs\n') || fail "rollback restores a missing boot.bin from the saved image"
pass "rollback restores boot.bin when update-m1n1 left only the saved image"

# A stale restore directory from an interrupted run must not be reused as the
# copy destination.
printf 'wip-dtbs\n' >"$boot"
printf 'released-dtbs\n' >"${boot}.omarchy-pre-wip"
mkdir "${boot}.omarchy-restore.stale"
run_helper rollback_boot_bin || fail "rollback ignores a stale restore directory"
cmp -s "$boot" <(printf 'released-dtbs\n') || fail "rollback replaces boot.bin despite a stale restore directory"
[[ -d ${boot}.omarchy-restore.stale ]] || fail "rollback does not remove an unrelated restore directory"
pass "rollback uses a fresh temporary file beside stale restore state"
rmdir "${boot}.omarchy-restore.stale"

# The destination is replaced only after the copy completes; a failed rename
# leaves the previous image intact and cleans up the temporary file.
printf 'wip-dtbs\n' >"$boot"
printf 'released-dtbs\n' >"${boot}.omarchy-pre-wip"
if TEST_FAIL_BOOT_MOVE=1 run_helper rollback_boot_bin >"$test_tmp/rollback-move-log" 2>&1; then
fail "rollback_boot_bin reports a failed atomic replacement"
fi
cmp -s "$boot" <(printf 'wip-dtbs\n') || fail "failed atomic replacement leaves the current boot image intact"
compgen -G "${boot}.omarchy-restore.*" >/dev/null &&
fail "failed atomic replacement cleans up its temporary image"
pass "rollback keeps the current boot image intact when replacement fails"

printf 'wip-dtbs\n' >"$boot"
if TEST_FAIL_BOOT_COPY=1 run_helper conditional_rollback >"$test_tmp/rollback-log" 2>&1; then
fail "rollback_boot_bin fails when copying the saved image fails"
Expand All @@ -72,7 +106,7 @@ fi
cmp -s "$boot" <(printf 'wip-dtbs\n') || fail "failed rollback leaves the boot image unchanged"
pass "rollback_boot_bin reports copy failures even in a conditional"

rm -f "${boot}.old"
rm -f "${boot}.old" "${boot}.omarchy-pre-wip"
! run_helper rollback_boot_bin || fail "rollback fails when no saved image exists"
pass "rollback_boot_bin fails closed without a saved image"

Expand Down