fix: UEFI boot fallback — search by file when label fails

The embedded GRUB EFI config only searched by volume label ARCHIPELAGO.
Some UEFI firmware presents USB devices differently, causing the search
to fail and GRUB to stall.

Added fallbacks:
1. search --file /archipelago/auto-install.sh (known ISO file)
2. Fall back to $cmdpath (EFI partition itself)
3. Use configfile before normal for explicit config loading
4. Added search_fs_file module to grub-mkstandalone

Also added same fallback to the main ISO grub.cfg.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian 2026-03-28 23:58:42 +00:00
parent 6e356412b8
commit e9903e7b4b

View File

@ -561,9 +561,10 @@ export INSTALLER_STARTED=1
sleep 1 sleep 1
clear clear
echo "" echo ""
echo -e "\033[1;37m a r c h i p e l a g o\033[0m" echo -e "\033[38;5;208m ▄▀█ █▀▄ █▀▀ █ █ █ █▀█ █▀▀ █ ▄▀█ █▀▀ █▀█\033[0m"
echo -e "\033[1;33m ━━━━━━━━━━━━━━━━━━━━━\033[0m" echo -e "\033[38;5;208m █▀█ █▀▄ █ █▀█ █ █▀▀ ██▀ █ █▀█ █ █ █ █\033[0m"
echo -e "\033[37m automatic installer\033[0m" echo -e "\033[38;5;208m ▀ ▀ ▀ ▀ ▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀ ▀▀▀\033[0m"
echo -e " \033[38;5;130mbitcoin node os\033[0m"
echo "" echo ""
BOOT_MEDIA="" BOOT_MEDIA=""
@ -687,19 +688,38 @@ mksquashfs /installer /output/filesystem.squashfs -comp xz -Xbcj x86 -noappend -
echo " [container] Building GRUB EFI image..." echo " [container] Building GRUB EFI image..."
cat > /tmp/grub-embed.cfg <<GRUBEMBED cat > /tmp/grub-embed.cfg <<GRUBEMBED
insmod part_gpt insmod part_gpt
insmod part_msdos
insmod fat insmod fat
insmod iso9660 insmod iso9660
insmod search
insmod search_label insmod search_label
insmod search_fs_file
insmod normal insmod normal
insmod linux insmod linux
insmod all_video insmod all_video
# Try label first (standard path)
search --no-floppy --set=root --label ARCHIPELAGO search --no-floppy --set=root --label ARCHIPELAGO
# Fallback: search for a known file on the ISO
if [ -z "\$root" ]; then
search --no-floppy --set=root --file /archipelago/auto-install.sh
fi
# Fallback: try configfile from the EFI partition path
if [ -z "\$root" ]; then
set root=\$cmdpath
fi
set prefix=(\$root)/boot/grub set prefix=(\$root)/boot/grub
configfile (\$root)/boot/grub/grub.cfg
# If configfile fails, try normal
normal normal
GRUBEMBED GRUBEMBED
grub-mkstandalone -O x86_64-efi \ grub-mkstandalone -O x86_64-efi \
--modules="part_gpt part_msdos fat iso9660 search search_label normal linux all_video font gfxterm configfile echo cat ls test true loopback png" \ --modules="part_gpt part_msdos fat iso9660 search search_label search_fs_file normal linux all_video font gfxterm configfile echo cat ls test true loopback png" \
--locales="" \ --locales="" \
--themes="" \ --themes="" \
--fonts="" \ --fonts="" \
@ -1405,81 +1425,56 @@ case "$(uname -m)" in
;; ;;
esac esac
# Colors (basic ANSI — works on bare-metal Linux console) # Colors — 256-color ANSI (works on Linux fbcon console)
ORANGE=$'\033[38;5;208m'
ORANGE_DIM=$'\033[38;5;130m'
ORANGE_BRIGHT=$'\033[38;5;214m'
RED=$'\033[31m' RED=$'\033[31m'
GREEN=$'\033[32m' GREEN=$'\033[32m'
YELLOW=$'\033[1;33m'
ORANGE=$'\033[1;33m'
DIM=$'\033[37m'
CYAN=$'\033[36m'
WHITE=$'\033[1;37m' WHITE=$'\033[1;37m'
DIM=$'\033[38;5;242m'
DIMMER=$'\033[38;5;238m'
NC=$'\033[0m' NC=$'\033[0m'
BOLD=$'\033[1m'
# Adaptive centering # Fixed left-margin layout (no more mixed centering)
TW=$(tput cols 2>/dev/null || echo 60) TW=$(tput cols 2>/dev/null || echo 60)
[ "$TW" -gt 120 ] && TW=120 [ "$TW" -gt 100 ] && TW=100
cc() { local s=$(echo -e "$1" | sed 's/\x1b\[[0-9;]*m//g'); local p=$(( (TW - ${#s}) / 2 )); [ $p -lt 0 ] && p=0; printf "%*s" "$p" ""; echo -e "$1"; } PAD=$(( (TW - 50) / 2 ))
hrule() { local len=$((TW > 50 ? 50 : TW - 4)); local hr=""; for i in $(seq 1 $len); do hr="${hr}"; done; cc "${DIM}${hr}${NC}"; } [ "$PAD" -lt 0 ] && PAD=0
PADS=$(printf "%*s" "$PAD" "")
box() { p() { printf "%s%b\n" "$PADS" "$1"; }
local bw=$((TW > 52 ? 52 : TW - 4)) hrule() { local hr=""; for i in $(seq 1 48); do hr="${hr}*"; done; p "${ORANGE_DIM}${hr}${NC}"; }
local inner=$((bw - 2))
local top="╭"; local bot="╰"
for i in $(seq 1 $inner); do top="${top}"; bot="${bot}"; done
top="${top}"; bot="${bot}"
cc "${DIM}${top}${NC}"
}
boxend() {
local bw=$((TW > 52 ? 52 : TW - 4))
local inner=$((bw - 2))
local bot="╰"
for i in $(seq 1 $inner); do bot="${bot}"; done
bot="${bot}"
cc "${DIM}${bot}${NC}"
}
boxline() {
local bw=$((TW > 52 ? 52 : TW - 4))
local inner=$((bw - 2))
local stripped=$(echo -e "$1" | sed 's/\x1b\[[0-9;]*m//g')
local pad=$((inner - ${#stripped}))
[ $pad -lt 0 ] && pad=0
local right=""
for i in $(seq 1 $pad); do right="${right} "; done
cc "${DIM}${NC} $1${right}${DIM}${NC}"
}
# TUI helpers — Claude Code-inspired status display # Phase display
STEP=0 STEP=0
TOTAL_STEPS=8 TOTAL_STEPS=8
step() { step() {
STEP=$((STEP + 1)) STEP=$((STEP + 1))
echo "" echo ""
cc "${WHITE}[$STEP/$TOTAL_STEPS]${NC} ${DIM}$1${NC}" p "${ORANGE}[$STEP/$TOTAL_STEPS] $1${NC}"
} }
ok() { cc " ${GREEN}$1${NC}"; } ok() { p " ${ORANGE_BRIGHT}$1${NC}"; }
warn() { cc " ${YELLOW}$1${NC}"; } warn() { p " ${ORANGE}$1${NC}"; }
fail() { cc " ${RED}$1${NC}"; } fail() { p " ${RED}$1${NC}"; }
spinner() { spinner() {
local pid=$1 msg=$2 local pid=$1 msg=$2
local frames='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏' local frames='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
local i=0 local i=0
while kill -0 "$pid" 2>/dev/null; do while kill -0 "$pid" 2>/dev/null; do
printf "\r ${DIM}%s %s${NC}" "${frames:i%10:1}" "$msg" printf "\r%s %b%s %s%b" "$PADS" "$ORANGE" "${frames:i%10:1}" "$msg" "$NC"
i=$((i + 1)) i=$((i + 1))
sleep 0.1 sleep 0.1
done done
printf "\r ${GREEN}✓ %s${NC}\n" "$msg" printf "\r%s %b✓ %s%b\n" "$PADS" "$ORANGE_BRIGHT" "$msg" "$NC"
} }
clear clear
echo "" echo -e " ${ORANGE}▄▀█ █▀▄ █▀▀ █ █ █ █▀█ █▀▀ █ ▄▀█ █▀▀ █▀█${NC}"
box echo -e " ${ORANGE}█▀█ █▀▄ █ █▀█ █ █▀▀ ██▀ █ █▀█ █ █ █ █${NC}"
boxline "" echo -e " ${ORANGE}▀ ▀ ▀ ▀ ▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀ ▀▀▀${NC}"
boxline "${WHITE}a r c h i p e l a g o${NC}" echo -e " ${ORANGE_DIM}bitcoin node os${NC}"
boxline "${ORANGE}━━━━━━━━━━━━━━━━━━━━━${NC}"
boxline "${DIM}automatic installation${NC}"
boxline ""
boxend
echo "" echo ""
# Check required tools are present (should be bundled in ISO) # Check required tools are present (should be bundled in ISO)
@ -1582,9 +1577,9 @@ ok "$TARGET_DISK ($TARGET_SIZE)"
echo "" echo ""
hrule hrule
echo "" echo ""
cc "${RED}all data on $TARGET_DISK will be erased${NC}" p "${ORANGE}all data on $TARGET_DISK will be erased${NC}"
echo "" echo ""
cc "${DIM}press enter to install | ctrl+c to cancel${NC}" p "${ORANGE_DIM} press enter to install | ctrl+c to cancel${NC}"
read -s read -s
echo "" echo ""
@ -1631,7 +1626,7 @@ mkfs.ext4 -F -L archipelago "$ROOT_PART"
# Mount root + extract rootfs (need cryptsetup from rootfs for LUKS) # Mount root + extract rootfs (need cryptsetup from rootfs for LUKS)
ok "Partitions created" ok "Partitions created"
echo "" echo ""
cc "${DIM}Mounting filesystems...${NC}" p " ${ORANGE_DIM}Mounting filesystems...${NC}"
mkdir -p /mnt/target mkdir -p /mnt/target
mount "$ROOT_PART" /mnt/target mount "$ROOT_PART" /mnt/target
mkdir -p /mnt/target/boot/efi mkdir -p /mnt/target/boot/efi
@ -1877,31 +1872,29 @@ if [ -t 0 ] && [ -z "$ARCHIPELAGO_WELCOMED" ]; then
done done
O='\033[38;5;208m' O='\033[38;5;208m'
D='\033[38;5;242m' OD='\033[38;5;130m'
W='\033[1;37m'
N='\033[0m' N='\033[0m'
clear clear
echo "" echo -e " ${O}▄▀█ █▀▄ █▀▀ █ █ █ █▀█ █▀▀ █ ▄▀█ █▀▀ █▀█${N}"
echo -e " ${O}█▀█ █▀▄ █▀▀ █ █ █ █▀▄▀█ █▀▀ █ █▀█ █▀▀ █▀█${N}" echo -e " ${O}█▀█ █▀▄ █ █▀█ █ █▀▀ ██▀ █ █▀█ █ █ █ █${N}"
echo -e " ${O}█▀█ █▀▄ █ █▀█ █ █ ▀ █ ██▀ █ █▀█ █ █ █ █${N}" echo -e " ${O}▀ ▀ ▀ ▀ ▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀ ▀▀▀${N}"
echo -e " ${O}▀ ▀ ▀ ▀ ▀▀▀ ▀ ▀ ▀ ▀ ▀ ▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀ ▀▀▀${N}" echo -e " ${OD}bitcoin node os${N}"
echo -e " ${D}bitcoin node os${N}"
echo ""
if [ -n "$IP" ]; then if [ -n "$IP" ]; then
echo -e " ${D}web ui${N} http://$IP" echo -e " ${W}web ui http://$IP${N}"
echo -e " ${D}ssh${N} archipelago@$IP" echo -e " ${W}ssh archipelago@$IP${N}"
echo -e " ${D}password${N} archipelago (SSH) / password123 (Web)" echo -e " ${W}password archipelago (SSH) / password123 (Web)${N}"
else else
echo -e " ${D}Waiting for network...${N}" echo -e " ${OD}Waiting for network...${N}"
fi fi
echo ""
if [ -b /dev/mapper/archipelago-data ]; then if [ -b /dev/mapper/archipelago-data ]; then
echo -e " ${D}storage${N} LUKS2 encrypted" echo -e " ${OD}storage LUKS2 encrypted${N}"
fi fi
if systemctl is-active archipelago-kiosk.service >/dev/null 2>&1; then if systemctl is-active archipelago-kiosk.service >/dev/null 2>&1; then
echo -e " ${D}display${N} Kiosk active (Ctrl+Alt+F1 for terminal)" echo -e " ${OD}display Kiosk active (Ctrl+Alt+F1 for terminal)${N}"
else else
echo -e " ${D}display${N} Console (Ctrl+Alt+F7 for kiosk)" echo -e " ${OD}display Console (Ctrl+Alt+F7 for kiosk)${N}"
fi fi
echo "" echo ""
fi fi
@ -2533,25 +2526,20 @@ cryptsetup close archipelago-data 2>/dev/null || true
umount /mnt/target 2>/dev/null || true umount /mnt/target 2>/dev/null || true
echo "" echo ""
echo -e " ${ORANGE}▄▀█ █▀▄ █▀▀ █ █ █ █▀█ █▀▀ █ ▄▀█ █▀▀ █▀█${NC}"
echo -e " ${ORANGE}█▀█ █▀▄ █ █▀█ █ █▀▀ ██▀ █ █▀█ █ █ █ █${NC}"
echo -e " ${ORANGE}▀ ▀ ▀ ▀ ▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀ ▀▀▀${NC}"
echo -e " ${ORANGE_DIM}bitcoin node os${NC}"
echo "" echo ""
box p "${ORANGE_BRIGHT} ✓ Installation Complete${NC}"
boxline ""
boxline "${WHITE}A R C H I P E L A G O${NC}"
boxline "${GREEN}━━━━━━━━━━━━━━━━━━━━━${NC}"
boxline "${GREEN}Installation Complete${NC}"
boxline ""
boxend
echo "" echo ""
cc "${DIM}After reboot, open the Web UI from any device on your network.${NC}" p "${ORANGE_DIM} After reboot, access from any device:${NC}"
echo "" echo ""
cc "${DIM}Web UI:${NC} ${WHITE}http://<this machine's IP>${NC}" p "${ORANGE} http://<this machine's IP>${NC}"
cc "${DIM}SSH:${NC} ${DIM}ssh archipelago@<IP>${NC}"
cc "${DIM}Password:${NC} ${DIM}archipelago${NC}"
cc "${DIM}Web Login:${NC} ${DIM}password123${NC}"
echo "" echo ""
cc "${DIM}Pre-loaded apps (start via Web UI):${NC}" p "${WHITE} SSH ssh archipelago@<IP>${NC}"
cc "${DIM}Bitcoin Knots, LND, Home Assistant,${NC}" p "${WHITE} Password archipelago${NC}"
cc "${DIM}BTCPay Server, Mempool, Nostr Relay${NC}" p "${WHITE} Web Login password123${NC}"
echo "" echo ""
hrule hrule
echo "" echo ""
@ -2562,19 +2550,19 @@ echo 1 > /proc/sys/kernel/printk 2>/dev/null || true
cat > /tmp/archipelago-reboot.sh <<'REBOOTSCRIPT' cat > /tmp/archipelago-reboot.sh <<'REBOOTSCRIPT'
#!/bin/bash #!/bin/bash
# This script runs from tmpfs — safe after USB removal # This script runs from tmpfs — safe after USB removal
TW=$(tput cols 2>/dev/null || echo 60) O=$'\033[38;5;208m'
[ "$TW" -gt 120 ] && TW=120 OD=$'\033[38;5;130m'
cc() { local s=$(echo -e "$1" | sed 's/\x1b\[[0-9;]*m//g'); local p=$(( (TW - ${#s}) / 2 )); [ $p -lt 0 ] && p=0; printf "%*s" "$p" ""; echo -e "$1"; } N=$'\033[0m'
cc "\033[1;33m>>> REMOVE THE USB DRIVE NOW <<<\033[0m" echo -e " ${O}>>> REMOVE THE USB DRIVE NOW <<<${N}"
echo "" echo ""
cc "\033[37mPress Enter to reboot (or wait 30 seconds)\033[0m" echo -e " ${OD}Press Enter to reboot (or wait 30 seconds)${N}"
# Wait for Enter or timeout # Wait for Enter or timeout
read -t 30 -s 2>/dev/null || true read -t 30 -s 2>/dev/null || true
echo "" echo ""
cc "\033[37mRebooting...\033[0m" echo -e " ${OD}Rebooting...${N}"
sleep 1 sleep 1
reboot -f reboot -f
REBOOTSCRIPT REBOOTSCRIPT
@ -2628,8 +2616,15 @@ insmod part_msdos
insmod fat insmod fat
insmod iso9660 insmod iso9660
insmod all_video insmod all_video
insmod search
insmod search_label
insmod search_fs_file
# Find boot media — try label first, then known file fallback
search --no-floppy --set=root --label ARCHIPELAGO search --no-floppy --set=root --label ARCHIPELAGO
if [ -z "$root" ]; then
search --no-floppy --set=root --file /archipelago/auto-install.sh
fi
set timeout=5 set timeout=5
set default=0 set default=0