Debian 13 (trixie) + ZFSBootMenu container build + mkinitcpio + Dropbear + Tailscale.
Last validated against live host <HOST_OS> on 2026-03-02.
This document is the reproducible build/operate runbook for the current <HOST_OS> setup:
- Build ZFSBootMenu on Debian via the upstream OCI builder (
zbm-builder.sh+ podman). - Use mkinitcpio mode.
- Enable pre-boot remote shell with dropbear.
- Enable pre-boot tailnet access with
mkinitcpio-tailscale. - Keep upgrades low risk with staged EFI image + one-time test boot.
Primary docs used:
- https://docs.zfsbootmenu.org/en/v3.1.x/general/mkinitcpio.html
- https://docs.zfsbootmenu.org/en/v3.1.x/general/remote-access.html
- https://docs.zfsbootmenu.org/en/v3.1.x/general/tailscale.html
- https://docs.zfsbootmenu.org/en/v3.1.x/general/container-building.html
- https://docs.zfsbootmenu.org/en/v3.1.x/general/container-building/example.html
-
Containerized build path on Debian. Reason: cleanly avoids distro packaging mismatches; upstream supports this path directly.
-
mkinitcpio hook snippets in
/etc/zfsbootmenu/mkinitcpio.conf.d/*.conf. Reason: cleaner than mutating the base mkinitcpio config and works with the builder container include logic. -
rclocalnetworking hook instead of mkinitcpionethook. Reason: Debian host path here did not have a practicalmkinitcpio-nfs-utilsnet module flow for this build;rclocal+dhclientis deterministic. -
Dropbear listens on TCP
2222. Reason: avoids accidental conflict with normal host SSH assumptions and keeps pre-boot access explicit. -
ZBM timeout set to
120seconds. Reason: gives a full two-minute window for remote attach during test boots. -
Upgrade workflow uses staging EFI and
BootNext. Reason: avoids changing primary ZBM entry until test boot is validated.
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"
VERSION_ID="13"
DEBIAN_VERSION_FULL=13.3ca-certificates 20250419
curl 8.14.1-2+deb13u2
efibootmgr 18-2
podman 5.4.2+ds1-2+b2
tailscale 1.94.2
dropbear-bin 2025.89-1~deb13u1Builder image currently present:
ghcr.io/zbm-dev/zbm-builder:latest (IMAGE ID 03d1950aa9bf)/etc/zfsbootmenu/config.yaml
/etc/zfsbootmenu/mkinitcpio.conf
/etc/zfsbootmenu/mkinitcpio.conf.d/10-network.conf
/etc/zfsbootmenu/mkinitcpio.conf.d/20-dropbear.conf
/etc/zfsbootmenu/mkinitcpio.conf.d/30-tailscale.conf
/etc/zfsbootmenu/initcpio/hooks/rclocal
/etc/zfsbootmenu/initcpio/install/rclocal
/etc/zfsbootmenu/initcpio/hooks/dropbear
/etc/zfsbootmenu/initcpio/install/dropbear
/etc/zfsbootmenu/initcpio/rc.local
/etc/zfsbootmenu/rc.d/dropbear
/etc/zfsbootmenu/rc.d/tailscale
/etc/zfsbootmenu/dropbear/dropbear.conf
/etc/zfsbootmenu/dropbear/root_key
/etc/zfsbootmenu/tailscale/tailscaled.state
/etc/zfsbootmenu/zbm-builder.sh
/etc/zfsbootmenu/zbm-builder.conf
/usr/local/sbin/zbm-upgrade-staged.sh
zfsbootmenu ro quiet loglevel=0 nomodeset zbm.timeout=120
EFI bundles:
/boot/efi/EFI/zfsbootmenu-ts/zfsbootmenu.EFI
/boot/efi/EFI/zfsbootmenu-staging/zfsbootmenu.EFI
/boot/efi/EFI/ZBM/VMLINUZ.EFI
Current EFI entries observed:
Boot0001* ZFSBootMenu (Tailscale test) \EFI\zfsbootmenu-ts\zfsbootmenu.EFI
Boot0002* ZFSBootMenu (Staging) \EFI\zfsbootmenu-staging\zfsbootmenu.EFI
Boot0004* ZFSBootMenu \EFI\ZBM\VMLINUZ.EFI
Boot0003* ZFSBootMenu (Backup) \EFI\ZBM\VMLINUZ-BACKUP.EFI
All commands in this section are intended to run on <HOST_OS>.
sudo apt update
sudo apt install -y podman efibootmgr curl ca-certificates tailscale dropbear-binVerify:
command -v podman efibootmgr curl tailscale dropbearkeysudo mkdir -p /etc/zfsbootmenuCreate /etc/zfsbootmenu/config.yaml:
Global:
ManageImages: true
InitCPIO: true
InitCPIOHookDirs:
- /build/initcpio
- /usr/lib/initcpio
Components:
Enabled: false
EFI:
Enabled: true
Versions: false
Kernel:
Prefix: zfsbootmenu
CommandLine: zfsbootmenu ro quiet loglevel=0 nomodeset zbm.timeout=120Install builder helper:
sudo curl -fsSL -o /etc/zfsbootmenu/zbm-builder.sh \
https://raw.githubusercontent.com/zbm-dev/zfsbootmenu/v3.1.0/zbm-builder.sh
sudo chmod 755 /etc/zfsbootmenu/zbm-builder.shInstall container-specialized mkinitcpio config:
sudo curl -fsSL -o /etc/zfsbootmenu/mkinitcpio.conf \
https://raw.githubusercontent.com/zbm-dev/zfsbootmenu/v3.1.0/etc/zbm-builder/mkinitcpio.confSet builder package additions in /etc/zfsbootmenu/zbm-builder.conf:
BUILD_ARGS+=( -p dropbear -p psmisc )
BUILD_ARGS+=( -p tailscale -p mkinitcpio-tailscale )sudo bash -eu <<'EOF'
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
mkdir -p /etc/zfsbootmenu/initcpio/{hooks,install}
curl -fsSL https://github.com/ahesford/mkinitcpio-rclocal/archive/master.tar.gz \
| tar -zxf - -C "$tmp"
install -m 0644 "$tmp/mkinitcpio-rclocal-master/rclocal_hook" \
/etc/zfsbootmenu/initcpio/hooks/rclocal
install -m 0644 "$tmp/mkinitcpio-rclocal-master/rclocal_install" \
/etc/zfsbootmenu/initcpio/install/rclocal
curl -fsSL https://github.com/ahesford/mkinitcpio-dropbear/archive/master.tar.gz \
| tar -zxf - -C "$tmp"
install -m 0644 "$tmp/mkinitcpio-dropbear-master/dropbear_hook" \
/etc/zfsbootmenu/initcpio/hooks/dropbear
install -m 0644 "$tmp/mkinitcpio-dropbear-master/dropbear_install" \
/etc/zfsbootmenu/initcpio/install/dropbear
EOFCreate /etc/zfsbootmenu/initcpio/rc.local:
#!/bin/sh
set -eu
iface=""
for cand in enp1s0 eth0; do
if ip link show dev "$cand" >/dev/null 2>&1; then
iface="$cand"
break
fi
done
if [ -z "$iface" ]; then
iface="$(ip -o link show | awk -F': ' '$2 != "lo" {print $2; exit}')"
fi
[ -n "$iface" ] || exit 0
ip link set dev "$iface" up
dhclient "$iface"sudo chmod 0755 /etc/zfsbootmenu/initcpio/rc.localsudo mkdir -p /etc/zfsbootmenu/mkinitcpio.conf.d/etc/zfsbootmenu/mkinitcpio.conf.d/10-network.conf:
BINARIES+=(ip dhclient dhclient-script)
HOOKS+=(rclocal)
rclocal_hook="/build/initcpio/rc.local"/etc/zfsbootmenu/mkinitcpio.conf.d/20-dropbear.conf:
HOOKS+=(dropbear)/etc/zfsbootmenu/mkinitcpio.conf.d/30-tailscale.conf:
HOOKS+=(tailscale)Create dedicated dropbear host keys:
sudo mkdir -p /etc/zfsbootmenu/dropbear
for keytype in rsa ecdsa ed25519; do
sudo dropbearkey -t "$keytype" \
-f "/etc/zfsbootmenu/dropbear/dropbear_${keytype}_host_key"
doneSet authorized key for pre-boot root login (/etc/dropbear/root_key inside initramfs):
sudo install -m 600 ~/.ssh/id_ed25519.pub /etc/zfsbootmenu/dropbear/root_keySet dropbear listen port:
echo 'dropbear_listen=2222' | sudo tee /etc/zfsbootmenu/dropbear/dropbear.conf >/dev/nullsudo mkdir -p /etc/zfsbootmenu/rc.dCreate /etc/zfsbootmenu/rc.d/dropbear:
#!/bin/sh
[ -d /build/dropbear ] || exit 0
mkdir -p /etc/dropbear
cp -R /build/dropbear/* /etc/dropbear/Create /etc/zfsbootmenu/rc.d/tailscale:
#!/bin/sh
[ -d /build/tailscale ] || exit 0
mkdir -p /etc/tailscale
cp -R /build/tailscale/* /etc/tailscale/sudo chmod 0755 /etc/zfsbootmenu/rc.d/dropbear /etc/zfsbootmenu/rc.d/tailscaleDo not print the auth key. Keep it in a file and pass by path only.
Place the fresh auth key file at a local path, example:
/etc/zfsbootmenu/tailscale/zbm-ts-authkey
Permissions:
sudo mkdir -p /etc/zfsbootmenu/tailscale
sudo chown root:root /etc/zfsbootmenu/tailscale/zbm-ts-authkey
sudo chmod 600 /etc/zfsbootmenu/tailscale/zbm-ts-authkeyGenerate state with the builder image environment:
sudo podman run --rm \
--entrypoint /bin/sh \
-v /etc/zfsbootmenu/tailscale:/var/lib/tailscale \
-v /etc/zfsbootmenu/tailscale/zbm-ts-authkey:/run/zbm-ts-authkey:ro \
ghcr.io/zbm-dev/zbm-builder:latest \
-lc '
set -eu
xbps-install -Suy xbps >/dev/null
xbps-install -Sy tailscale mkinitcpio-tailscale >/dev/null
mkinitcpio-tailscale-setup -f \
-H <INITRAMFS_NODE_NAME> \
-k /run/zbm-ts-authkey \
-t "--advertise-tags=tag:zfsbootmenu"
'Validate expected output files:
sudo ls -l /etc/zfsbootmenu/tailscale
sudo test -s /etc/zfsbootmenu/tailscale/tailscaled.stateOptional cleanup:
sudo rm -f /etc/zfsbootmenu/tailscale/zbm-ts-authkeysudo mkdir -p /boot/efi/EFI/zfsbootmenu-ts
cd /etc/zfsbootmenu
sudo ./zbm-builder.sh \
-O "--volume=/boot/efi/EFI/zfsbootmenu-ts:/output" \
-- -o /output \
-e '.Global.InitCPIOFlags=["-v"]' \
-- -dValidate image:
sudo file /boot/efi/EFI/zfsbootmenu-ts/zfsbootmenu.EFI
sudo zbm-kcl /boot/efi/EFI/zfsbootmenu-ts/zfsbootmenu.EFICreate EFI boot entry (idempotent pattern):
ESP_DEV="$(findmnt -no SOURCE /boot/efi)"
PKNAME="$(lsblk -no PKNAME "$ESP_DEV")"
PARTN="$(lsblk -no PARTN "$ESP_DEV")"
sudo efibootmgr -c \
-d "/dev/$PKNAME" \
-p "$PARTN" \
-L "ZFSBootMenu (Tailscale test)" \
-l '\EFI\zfsbootmenu-ts\zfsbootmenu.EFI'Find entry number:
sudo efibootmgr -vSet BootNext to test entry (example 0001):
sudo efibootmgr -n 0001
sudo rebootLAN path:
ssh -p 2222 root@<HOST_LAN_IP>Tailnet path (if MagicDNS is reachable):
ssh -p 2222 root@<INITRAMFS_TAILNODE_FQDN>Tailnet fallback (no direct MagicDNS routing from client shell):
ssh -p 2222 \
-o ProxyCommand='tailscale nc %h %p' \
root@<INITRAMFS_TAILNODE_FQDN>Observed peer metadata on 2026-03-02:
HostName: <INITRAMFS_NODE_NAME>
DNSName: <INITRAMFS_TAILNODE_FQDN>.
Tag: tag:zfsbootmenu
Note: DNS suffixes like -1 can change when node keys/state are regenerated.
zfsbootmenuCheck current KCL:
sudo zbm-kcl /boot/efi/EFI/zfsbootmenu-ts/zfsbootmenu.EFIChange timeout (example 30 -> 120) in-place:
sudo zbm-kcl \
-r zbm.timeout=30 \
-a zbm.timeout=120 \
/boot/efi/EFI/zfsbootmenu-ts/zfsbootmenu.EFIRepeat for staging image if needed:
sudo zbm-kcl \
-r zbm.timeout=30 \
-a zbm.timeout=120 \
/boot/efi/EFI/zfsbootmenu-staging/zfsbootmenu.EFIVerify:
sudo zbm-kcl /boot/efi/EFI/zfsbootmenu-ts/zfsbootmenu.EFI
sudo zbm-kcl /boot/efi/EFI/zfsbootmenu-staging/zfsbootmenu.EFIInstalled utility:
/usr/local/sbin/zbm-upgrade-staged.sh
- Builds new ZBM EFI into
/boot/efi/EFI/zfsbootmenu-staging. - Verifies EFI size and embedded KCL.
- Verifies build log evidence for
rclocal,dropbear, andtailscalehooks. - Ensures EFI boot entry
ZFSBootMenu (Staging)exists. - Optionally sets
BootNextto staging entry (--arm-next).
Pin a specific upstream tag and arm next boot:
sudo /usr/local/sbin/zbm-upgrade-staged.sh -t v3.1.0 --arm-nextBuild with builder-image default tag, do not arm boot:
sudo /usr/local/sbin/zbm-upgrade-staged.shImportant detail from builder internals:
zbm-builder.shdefaults to imageghcr.io/zbm-dev/zbm-builder:latest.- Inside that image,
/build-init.shuses/etc/zbm-commit-hashif present. - On current image this file contains
v3.1.0. - Build source fetch URL is
https://github.com/zbm-dev/zfsbootmenu/archive/${ZBMTAG}.tar.gz.
Practical implication:
- Without
-t, you build whatever tag the builder image currently pins. - With
-t vX.Y.Z, you explicitly fetch that tag from GitHub.
Recommended upgrade cadence:
sudo podman pull ghcr.io/zbm-dev/zbm-builder:latest
sudo /usr/local/sbin/zbm-upgrade-staged.sh -t vX.Y.Z --arm-next
sudo rebootAfter successful staged boot validation, promote by replacing primary EFI path/entry according to your site policy.
Before rebooting into a new image:
sudo test -s /etc/zfsbootmenu/dropbear/root_keysudo test -s /etc/zfsbootmenu/tailscale/tailscaled.statesudo zbm-kcl /boot/efi/EFI/zfsbootmenu-ts/zfsbootmenu.EFI | grep -q "zbm.timeout=120"sudo efibootmgr -v | grep -E "zfsbootmenu-ts|zfsbootmenu-staging"
During initramfs test boot:
- LAN SSH works on
:2222. - Tailnet peer appears with
tag:zfsbootmenu. zfsbootmenucommand opens UI.
After reboot back to normal OS:
efibootmgrno longer showsBootNextset.- Host comes back as normal
<HOST_OS>.
-
No network in initramfs. Check
rc.localinterface detection and ensuredhclientbinaries were included in10-network.conf. -
Dropbear auth fails. Confirm
/etc/zfsbootmenu/dropbear/root_keyexists, mode600, and contains the intended public key. -
Tailnet node never appears. Regenerate state with fresh auth key and verify ACL permits
tag:zfsbootmenu. -
Builder succeeds but remote hooks missing. Run staged script and inspect its build log (
/var/log/zbm-upgrade-staged-*.log) for hook evidence checks. -
Cannot resolve tailnet hostname from client. Use
ProxyCommand='tailscale nc %h %p'or connect via LAN fallback.
- Do not store reusable auth keys in shell history.
- Keep
/etc/zfsbootmenubacked up before major edits. - Test every upgrade with one-time
BootNextbefore changing persistent boot order. - Keep a known-good fallback entry (
/EFI/ZBM/VMLINUZ-BACKUP.EFI) in boot order.
Current script as deployed on <HOST_OS> at /usr/local/sbin/zbm-upgrade-staged.sh:
#!/usr/bin/env bash
set -euo pipefail
CONFIG_DIR="/etc/zfsbootmenu"
STAGE_DIR="/boot/efi/EFI/zfsbootmenu-staging"
ENTRY_LABEL="ZFSBootMenu (Staging)"
TAG=""
ARM_NEXT=0
usage() {
cat <<'EOF'
Usage: sudo zbm-upgrade-staged.sh [options]
Build and verify a staged ZFSBootMenu EFI image, ensure a staging EFI entry
exists, and optionally arm one-time BootNext for test boot.
Options:
-t, --tag <zbm-tag> Build specific ZFSBootMenu tag (e.g. v3.1.0)
-a, --arm-next Set BootNext to staging EFI entry
-s, --stage-dir <dir> Staging EFI directory (default: /boot/efi/EFI/zfsbootmenu-staging)
-c, --config-dir <dir> ZBM config/build dir (default: /etc/zfsbootmenu)
-l, --label <label> EFI boot entry label (default: ZFSBootMenu (Staging))
-h, --help Show this help
Examples:
sudo zbm-upgrade-staged.sh -t v3.1.0
sudo zbm-upgrade-staged.sh --tag v3.1.0 --arm-next
EOF
}
log() { printf '[INFO] %s\n' "$*"; }
pass() { printf '[PASS] %s\n' "$*"; }
warn() { printf '[WARN] %s\n' "$*"; }
fail() { printf '[FAIL] %s\n' "$*" >&2; exit 1; }
need_cmd() { command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1"; }
while [ "$#" -gt 0 ]; do
case "$1" in
-t|--tag)
[ "$#" -ge 2 ] || fail "missing value for $1"
TAG="$2"
shift 2
;;
-a|--arm-next)
ARM_NEXT=1
shift
;;
-s|--stage-dir)
[ "$#" -ge 2 ] || fail "missing value for $1"
STAGE_DIR="$2"
shift 2
;;
-c|--config-dir)
[ "$#" -ge 2 ] || fail "missing value for $1"
CONFIG_DIR="$2"
shift 2
;;
-l|--label)
[ "$#" -ge 2 ] || fail "missing value for $1"
ENTRY_LABEL="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
fail "unknown option: $1"
;;
esac
done
[ "${EUID}" -eq 0 ] || fail "run as root (sudo)"
need_cmd efibootmgr
need_cmd findmnt
need_cmd lsblk
need_cmd file
need_cmd zbm-kcl
[ -x "${CONFIG_DIR}/zbm-builder.sh" ] || fail "missing ${CONFIG_DIR}/zbm-builder.sh"
[ -f "${CONFIG_DIR}/config.yaml" ] || fail "missing ${CONFIG_DIR}/config.yaml"
HAVE_DROPBEAR=0
HAVE_TAILSCALE=0
if [ -f "${CONFIG_DIR}/dropbear/root_key" ]; then
pass "dropbear root_key present"
HAVE_DROPBEAR=1
else
warn "dropbear root_key missing (${CONFIG_DIR}/dropbear/root_key)"
fi
if [ -s "${CONFIG_DIR}/tailscale/tailscaled.state" ]; then
pass "tailscale state present"
HAVE_TAILSCALE=1
else
warn "tailscale state missing (${CONFIG_DIR}/tailscale/tailscaled.state)"
fi
mkdir -p "${STAGE_DIR}"
LOG_FILE="/var/log/zbm-upgrade-staged-$(date +%F-%H%M%S).log"
log "build log: ${LOG_FILE}"
pushd "${CONFIG_DIR}" >/dev/null
if [ -n "${TAG}" ]; then
log "building staged EFI from tag ${TAG}"
if ! ./zbm-builder.sh -O "--volume=${STAGE_DIR}:/output" -- -t "${TAG}" -o /output -e '.Global.InitCPIOFlags=["-v"]' -- -d >"${LOG_FILE}" 2>&1; then
tail -n 120 "${LOG_FILE}" >&2 || true
fail "zbm-builder failed"
fi
else
log "building staged EFI from default tag"
if ! ./zbm-builder.sh -O "--volume=${STAGE_DIR}:/output" -- -o /output -e '.Global.InitCPIOFlags=["-v"]' -- -d >"${LOG_FILE}" 2>&1; then
tail -n 120 "${LOG_FILE}" >&2 || true
fail "zbm-builder failed"
fi
fi
popd >/dev/null
STAGE_EFI="${STAGE_DIR}/zfsbootmenu.EFI"
[ -s "${STAGE_EFI}" ] || fail "missing staged EFI: ${STAGE_EFI}"
SIZE_BYTES="$(stat -c '%s' "${STAGE_EFI}")"
if [ "${SIZE_BYTES}" -lt $((20 * 1024 * 1024)) ]; then
fail "staged EFI too small (${SIZE_BYTES} bytes): ${STAGE_EFI}"
fi
pass "staged EFI exists (${SIZE_BYTES} bytes)"
file "${STAGE_EFI}" | sed 's/^/[INFO] /'
CMDLINE="$(zbm-kcl "${STAGE_EFI}")"
printf '[INFO] staged cmdline: %s\n' "${CMDLINE}"
# Evidence from verbose mkinitcpio + generate-zbm debug log
if grep -q '/build/initcpio/install/rclocal' "${LOG_FILE}"; then
pass "log evidence: rclocal hook executed"
else
warn "log evidence missing: rclocal hook"
fi
if [ "${HAVE_DROPBEAR}" -eq 1 ]; then
grep -q '/build/initcpio/install/dropbear' "${LOG_FILE}" || fail "dropbear hook not executed"
grep -q '/etc/dropbear/root_key' "${LOG_FILE}" || fail "dropbear root_key not embedded"
pass "log evidence: dropbear hook + root_key embedded"
fi
if [ "${HAVE_TAILSCALE}" -eq 1 ]; then
grep -q '/usr/lib/initcpio/install/tailscale' "${LOG_FILE}" || fail "tailscale hook not executed"
grep -q '/etc/tailscale/tailscaled.state' "${LOG_FILE}" || fail "tailscaled.state not embedded"
pass "log evidence: tailscale hook + state embedded"
fi
REL_PATH="${STAGE_DIR#/boot/efi/}"
EFI_PATH="\\${REL_PATH//\//\\}\\zfsbootmenu.EFI"
PATTERN="$(printf '%s' "${EFI_PATH}" | tr '[:upper:]' '[:lower:]')"
find_bootnum() {
efibootmgr -v | awk -v pat="${PATTERN}" '
{
line=tolower($0)
if (index(line, pat) > 0) {
b=$1
sub(/^Boot/, "", b)
sub(/\*.*/, "", b)
print b
exit
}
}
'
}
BOOTNUM="$(find_bootnum || true)"
if [ -z "${BOOTNUM}" ]; then
ESP_DEV="$(findmnt -no SOURCE /boot/efi)"
PKNAME="$(lsblk -no PKNAME "${ESP_DEV}")"
PARTN="$(lsblk -no PARTN "${ESP_DEV}")"
[ -n "${PKNAME}" ] || fail "unable to determine ESP parent disk"
[ -n "${PARTN}" ] || fail "unable to determine ESP partition number"
log "creating staging EFI entry: ${ENTRY_LABEL} -> ${EFI_PATH}"
efibootmgr -c -d "/dev/${PKNAME}" -p "${PARTN}" -L "${ENTRY_LABEL}" -l "${EFI_PATH}" >/dev/null
BOOTNUM="$(find_bootnum || true)"
[ -n "${BOOTNUM}" ] || fail "failed to locate staging EFI entry after creation"
pass "created staging EFI entry Boot${BOOTNUM}"
else
pass "staging EFI entry already exists as Boot${BOOTNUM}"
fi
if [ "${ARM_NEXT}" -eq 1 ]; then
efibootmgr -n "${BOOTNUM}" >/dev/null
NEXT="$(efibootmgr | awk -F': ' '/^BootNext:/ {print $2}')"
[ "${NEXT}" = "${BOOTNUM}" ] || fail "failed to arm BootNext=Boot${BOOTNUM}"
pass "armed one-time BootNext=Boot${BOOTNUM}"
else
log "BootNext not changed (use --arm-next to arm Boot${BOOTNUM})"
fi
printf '[INFO] staging EFI: %s\n' "${STAGE_EFI}"
printf '[INFO] staging entry: Boot%s (%s)\n' "${BOOTNUM}" "${ENTRY_LABEL}"
printf '[INFO] build log: %s\n' "${LOG_FILE}"