#!/bin/sh
# alloy-boot-entry — make the firmware boot menu say Alloy, after the install.
#
# WHY THIS EXISTS AND WHY THE CONTAINERFILE'S CSV IS NOT ENOUGH. The image ships
# a patched BOOTX64.CSV in the bootupd payload, and it reaches the ESP intact:
# measured on a fresh fw12 install 2026-09-07, the installed ESP's
# EFI/fedora/BOOTX64.CSV reads `shimx64.efi,Alloy,,...`. The machine still came
# up with two entries named Fedora.
#
# The reason is that the CSV is read by fbx64.efi, and fbx64 runs only when the
# firmware has no entry pointing at shim. Something on the install path creates
# those entries itself, so fbx64's fallback never runs and the CSV is never
# read. The Containerfile comment beside that RUN says the opposite -- "bootupd
# writes the ESP and calls no efibootmgr" -- and that is measured to be false.
#
# So the CSV is necessary and not sufficient. It is what a machine whose NVRAM
# is cleared will use; this is what every ordinary install needs.
#
# WHAT IT DOES NOT DO, matching the Containerfile: the vendor directory stays
# EFI/fedora and the loader stays shimx64.efi. Both are baked into the signed
# shim, so changing either is a Secure Boot question rather than a branding one.
# Only the description changes.
#
# ORDERING IS THE SAFETY PROPERTY. efibootmgr has no rename verb, so each entry
# is recreated and verified BEFORE the old one is deleted. There is no moment at
# which the machine has no entry pointing at shim, and a failure anywhere leaves
# either the old entry or both. Both boot.
#
# EXIT STATUS IS A CONTRACT. This runs as the last thing in an install that has
# otherwise succeeded, and the name in a firmware menu is not worth failing a
# good install over. So every reason to do nothing -- not an EFI boot, no
# efibootmgr, nothing left to rename -- exits 0. A non-zero exit means NVRAM was
# left worse than it was found, which is the only outcome worth stopping for.
#
# --report EXISTS SO THE WRITE CAN BE LOOKED AT FIRST. Reading NVRAM needs no
# privilege and writing it needs root, so without a read-only mode the only way
# to find out what this would do was to let it do it. Everything up to the first
# efibootmgr write runs identically in both modes, so a report is the plan and
# not a second implementation of it.

set -eu

NAME="Alloy"
DRY=0

usage() {
    sed -n '2,39p' "$0"
    echo
    echo "Usage: alloy-boot-entry [--report]"
    echo "  --report, -n   say what would change and write nothing. Needs no root."
}

while [ $# -gt 0 ]; do
    case "$1" in
        --report|--dry-run|-n) DRY=1; shift ;;
        -h|--help) usage; exit 0 ;;
        *) printf 'error: unknown argument %s\n' "$1" >&2; exit 2 ;;
    esac
done

[ -d /sys/firmware/efi ] || { echo "not an EFI boot; no entry to name"; exit 0; }
command -v efibootmgr >/dev/null 2>&1 || { echo "no efibootmgr; leaving the boot entry alone"; exit 0; }

dump="$(efibootmgr -v)" || { echo "efibootmgr could not read NVRAM; leaving it alone"; exit 0; }

# Entries pointing at a shim on an ESP whose description is not already ours.
stale="$(printf '%s\n' "$dump" \
    | grep -E '^Boot[0-9A-Fa-f]{4}\*?[[:space:]]' \
    | grep -iE '\\EFI\\[^\\]+\\shim' \
    | grep -viE "[[:space:]]${NAME}[[:space:]]" || true)"

if [ -z "$stale" ]; then
    echo "the firmware boot entry already says $NAME"
    exit 0
fi

order="$(printf '%s\n' "$dump" | sed -nE 's/^BootOrder: (.*)$/\1/p')"
new_order="$order"

# Looped from a file rather than from a pipe. A `while read` on the right of a
# pipe runs in a subshell, where the order this builds would be discarded at the
# end of the loop and an `exit 1` would end the subshell rather than the script.
# Both halves of this loop's job are exactly those two things.
entries="$(mktemp)"
trap 'rm -f "$entries"' EXIT
printf '%s\n' "$stale" > "$entries"

while read -r entry; do
    [ -n "$entry" ] || continue
    num="$(printf '%s\n' "$entry" | sed -nE 's/^Boot([0-9A-Fa-f]{4})\*?[[:space:]].*/\1/p')"
    loader="$(printf '%s\n' "$entry" | sed -nE 's/.*(\\EFI\\[^\\]+\\[^ \t]*\.efi).*/\1/p' | head -1)"
    uuid="$(printf '%s\n' "$entry" | sed -nE 's/.*HD\([0-9]+,GPT,([0-9a-fA-F-]+),.*/\1/p')"
    [ -n "$num" ] && [ -n "$loader" ] && [ -n "$uuid" ] || {
        echo "could not read an entry off: $entry" >&2
        continue
    }

    # The disk and partition the entry already names, so the replacement points
    # at the same place the firmware boots from rather than at a device this
    # script guessed. It also keeps it off the installer medium, which carries
    # an EFI System partition of its own and is still plugged in.
    dev="$(lsblk -rno PATH,PARTUUID 2>/dev/null | awk -v u="$uuid" 'tolower($2)==tolower(u){print $1}' | head -1)"
    [ -n "$dev" ] || { echo "no device carries PARTUUID $uuid; leaving Boot$num alone" >&2; continue; }
    disk="/dev/$(lsblk -no PKNAME "$dev" | head -1)"
    partn="$(cat "/sys/class/block/$(basename "$dev")/partition" 2>/dev/null || true)"
    [ -b "$disk" ] && [ -n "$partn" ] || { echo "could not place $dev; leaving Boot$num alone" >&2; continue; }

    # The last point both modes share. Everything above is a read; everything
    # below writes NVRAM, so the report stops exactly here and the plan it
    # prints is the one the write would follow.
    if [ "$DRY" -eq 1 ]; then
        printf 'would rename: Boot%s -> a new entry "%s" (%s on %s partition %s), then delete Boot%s\n' \
            "$num" "$NAME" "$loader" "$disk" "$partn" "$num"
        continue
    fi

    before="$(efibootmgr | sed -nE 's/^Boot([0-9A-Fa-f]{4})\*?.*/\1/p' | sort -u)"
    efibootmgr -q -c -d "$disk" -p "$partn" -L "$NAME" -l "$loader"
    after="$(efibootmgr | sed -nE 's/^Boot([0-9A-Fa-f]{4})\*?.*/\1/p' | sort -u)"
    created="$(printf '%s\n' "$before" "$after" | sort | uniq -u | head -1)"

    # From here the machine has two entries pointing at shim and boots either
    # way, so every exit below is safe. Non-zero because NVRAM now holds
    # something this script put there and could not finish accounting for.
    [ -n "$created" ] || {
        echo "no new boot entry appeared; Boot$num is unchanged" >&2
        exit 1
    }
    efibootmgr | grep -q "^Boot${created}\*\?[[:space:]]*${NAME}\b" || {
        echo "Boot$created is not the $NAME entry expected; Boot$num is unchanged" >&2
        exit 1
    }

    efibootmgr -q -b "$num" -B
    # printf, not echo: the loader path is full of backslashes and `echo` in
    # dash interprets them, so `\EFI\fedora\shimx64.efi` logs as
    # `\EFIedora\shimx64.efi` and the line quietly misreports what was done.
    printf 'boot entry: Boot%s -> Boot%s "%s" (%s)\n' "$num" "$created" "$NAME" "$loader"

    new_order="$(printf '%s' "$new_order" | sed "s/\b$num\b/$created/I")"
done < "$entries"

if [ "$DRY" -eq 1 ]; then
    # The new numbers are assigned by the firmware at creation, so a report
    # cannot name the order it would write. It can say the slots are kept,
    # which is the property worth checking.
    echo "boot order: $order, each renamed entry taking the slot of the one it replaces"
    echo "nothing was written"
    exit 0
fi

if [ -n "$new_order" ] && [ "$new_order" != "$order" ]; then
    efibootmgr -q -o "$new_order"
    echo "boot order: $order -> $new_order"
fi
