preflight+install: the default entry is CUBELinux now, and two checks said otherwise

Inverting the default (GRUB_DEFAULT='cubelinux', workhorse kernel as grubenv's
`fallback`) invalidated an assertion rather than tripping it, which is the worse
failure of the two.

verify-box-preflight.sh asked whether the DEFAULT string contains the release:
`default_boots() { case "$DEFAULT" in *"$1"*) ... }`. That works for the form the id
used to have — `gnulinux-<release>-advanced-<uuid>` carries the release verbatim — and
is simply false for `cubelinux`, which does not. So on a same-release reinstall the
check answered "the default boots another kernel, so the way back is untouched" about
an entry that boots exactly the release being replaced: a green light over the one
thing it exists to catch. It now resolves the default entry to the kernel on its
`linux` line (entry_kernel(): grub.cfg and the sourced custom.cfg, stripping a
`submenu>` prefix), and keeps the id's text only as a fallback for a default it cannot
resolve. It reports what is true: NOT READY — 2 of 16. A consequence worth stating
plainly: the next kernel build needs a new release name, because a same-release
reinstall is now refused on purpose.

install-box.sh carried the old arrangement in two comments that are now the opposite
of the truth:
  * pass 1 writes the kernel the DEFAULT entry names while pass 2 has not yet written
    its initramfs, so the window between them is no longer covered by "a reboot lands
    on some other kernel". Nothing reboots in between and each pass writes whole, but
    the window is real where it was not.
  * the closing message told the operator that a panic reboots the machine back to the
    default entry, as if that were safe. The default IS this entry, so panic=30
    reboots straight back into the kernel that just panicked and GRUB's fallback never
    runs. The message now names the boot menu and the grub-reboot command that
    actually get the machine back.

Both files also name the divergence this change exposed and did not fix: install-root.sh
maintains /boot/grub/custom.cfg (id 'cubelinux-<release>'), which is now a SECOND
CUBELinux entry beside the default /etc/grub.d/12_cubelinux (id 'cubelinux'), and only
the default carries cube_boot_record=1. One of them should go.
This commit is contained in:
luulu
2026-09-23 14:42:37 -04:00
parent 275fbab8b7
commit 487678dad8
2 changed files with 65 additions and 9 deletions
+25 -7
View File
@@ -88,9 +88,13 @@ done
[ "$kept" -gt 0 ] || say "kept : nothing — this release is not installed yet"
# ── pass 1: the kernel and its module tree ───────────────────────────────────────────────
# The GRUB entry install-root.sh writes here names an initramfs that does not exist yet, so the
# CUBELinux entry is not bootable until pass 2 completes. That is safe: the default entry is
# untouched, so a reboot in between lands on the kernel this machine runs now.
# The entry names an initramfs that does not exist yet, so the CUBELinux entry is not bootable
# until pass 2 completes — and since 2026-09-23 that entry is the DEFAULT (GRUB_DEFAULT='cubelinux'
# in /etc/default/grub, see /etc/grub.d/12_cubelinux). So the window between the two passes is no
# longer covered by "the default is some other kernel": this pass has just replaced the file the
# default entry names, and the initramfs it names is still the previous install's. Nothing here
# reboots, and each pass writes its artefact whole, but the window is real now where it was not
# before, and it is named here rather than implied by an old comment.
step "kernel + modules"
bash "$HERE/install-root.sh" / --root-spec "UUID=$ROOT_UUID" --fs-uuid "$ROOT_UUID" "${STORE_ARGS[@]}"
@@ -150,10 +154,24 @@ say "default : unchanged ($DEFAULT_AFTER)"
cat <<EOF
installed. nothing has been rebooted. to boot CUBELinux once — and only once:
installed. nothing has been rebooted. CUBELinux is the DEFAULT entry on this machine
(GRUB_DEFAULT='cubelinux'), so a plain reboot boots it — there is nothing to arm:
grub-reboot '$RELEASE' && reboot
reboot
if it panics, panic=30 reboots the machine back to the default entry by itself. to remove the
entry without booting it at all: rm /boot/grub/custom.cfg
the way back is the workhorse kernel 6.19.3-cube+, named as GRUB's `fallback` in
/boot/grub/grubenv. that covers THIS ENTRY FAILING TO LOAD — a missing kernel or initramfs. it does
not cover a kernel that loads and then faults: GRUB has already handed over by then, so panic=30
reboots straight back into this same entry, and the fallback never runs. if that happens, choose the
workhorse entry at the boot menu, or:
grub-reboot gnulinux-6.19.3-cube+-advanced-2a7b1834-83ed-4394-a8ee-816b885b5624 && reboot
to arm that one-shot on purpose, rather than rebooting into CUBELinux — the same command, and the
boot after it returns to the default on its own.
known divergence, not yet fixed: this install maintains /boot/grub/custom.cfg (id
'cubelinux-$RELEASE'), which after 2026-09-23 is a SECOND CUBELinux entry beside the default
/etc/grub.d/12_cubelinux (id 'cubelinux'). they name the same kernel and differ in the command
line — only 12_cubelinux has cube_boot_record=1. one of them should go; see the note for 2026-09-23.
EOF
+40 -2
View File
@@ -30,10 +30,48 @@ echo "running : $RUNNING on $(findmnt -n -o SOURCE / 2>/dev/null || echo '?')"
# boots now" — so the boot entry is what it reads. Asking `uname -r` instead is how this preflight
# came to refuse an install whose way back had never been in question.
GRUB_CFG=/boot/grub/grub.cfg
# The installer's own entry lives here, and is sourced at boot rather than at grub-mkconfig time, so
# an id in it is invisible to a grep of grub.cfg alone.
CUSTOM_CFG=/boot/grub/custom.cfg
DEFAULT="$(sed -n 's/^ *set default="\(.*\)"/\1/p' "$GRUB_CFG" 2>/dev/null | tail -1)"
# A GRUB entry id carries the release verbatim: `gnulinux-6.19.3-cube+-advanced-<uuid>`.
default_boots() { case "$DEFAULT" in *"$1"*) return 0 ;; *) return 1 ;; esac; }
# What a menuentry actually boots is the kernel on its `linux` line. The id is not a substitute: it
# is a name, and the default now names an entry whose id (`cubelinux`) deliberately does NOT carry
# the release — so a substring test on the id answers "the default boots something else" about an
# entry that boots exactly the release in hand. That is the failure this resolves: a green preflight
# over a same-release reinstall of the kernel the default entry boots.
entry_kernel() { # entry_kernel <id|title> -> the vmlinuz path that entry loads
local id="${1##*>}" f ln
for f in "$GRUB_CFG" "$CUSTOM_CFG"; do
[ -f "$f" ] || continue
ln="$(grep -nE '^[[:space:]]*menuentry' "$f" | grep -F "'$id'" | head -1 | cut -d: -f1)"
[ -n "$ln" ] || continue
sed -n "${ln},\$p" "$f" \
| grep -m1 -E '^[[:space:]]*linux[[:space:]]' \
| tr ' \t' '\n\n' \
| grep -m1 -- '/vmlinuz-' && return 0
done
return 1
}
DEFAULT_KERNEL="$(entry_kernel "$DEFAULT" || true)"
DEFAULT_RELEASE=""
[ -n "$DEFAULT_KERNEL" ] && DEFAULT_RELEASE="${DEFAULT_KERNEL##*/vmlinuz-}"
# Resolve by the file when the entry can be read, and fall back to the id's text when it cannot
# (a numeric GRUB_DEFAULT, or an id this script cannot follow) — a weaker answer, not a wrong one.
default_boots() {
if [ -n "$DEFAULT_RELEASE" ]; then
[ "$DEFAULT_RELEASE" = "$1" ]
return
fi
case "$DEFAULT" in *"$1"*) return 0 ;; *) return 1 ;; esac
}
echo "boots : ${DEFAULT:-?} (the default entry, which a plain reboot follows)"
if [ -n "$DEFAULT_RELEASE" ]; then
echo " it loads ${DEFAULT_KERNEL} (release ${DEFAULT_RELEASE})"
else
echo " its kernel could not be resolved from the entry; the id's text is used instead"
fi
echo
# ── the built kernel exists, and installing it cannot cost the way back ──────────────────