#!/usr/bin/env bash # Bootstrap a one-shot GRUB entry for BGP.Exchange automated reinstall. # Usage: curl -fsSL https://install.bgp.exchange/ | sudo bash # # Bare-metal / VM from ISO (Debian 13): https://repo.bgp.exchange/iso/bgpe-debian13-amd64-netinst.iso # See https://repo.bgp.exchange/iso/debian13/README.md set -euo pipefail if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then echo "Run as root (e.g. curl -fsSL https://install.bgp.exchange/ | sudo bash)" >&2 exit 1 fi if ! command -v wget >/dev/null 2>&1; then echo "wget is required" >&2 exit 1 fi detect_deb_release() { local id codename ver if [[ -r /etc/os-release ]]; then # shellcheck disable=SC1091 source /etc/os-release case "${VERSION_ID:-}" in 12|12.*) echo deb12; return ;; 13|13.*) echo deb13; return ;; esac codename="${VERSION_CODENAME:-}" fi if [[ -z "${codename:-}" && -r /etc/debian_version ]]; then ver="$(sed 's/\/.*//' /etc/debian_version)" case "$ver" in 12|12.*) echo deb12; return ;; 13|13.*) echo deb13; return ;; bookworm) echo deb12; return ;; trixie) echo deb13; return ;; esac fi case "${codename:-}" in bookworm) echo deb12 ;; trixie) echo deb13 ;; *) echo "ERROR: unsupported Debian release (need 12/bookworm or 13/trixie)" >&2 exit 1 ;; esac } is_efi() { [[ -d /sys/firmware/efi ]] } # stdin is the script when piped from curl; read prompts from the terminal. read_tty() { if [[ -r /dev/tty ]]; then read -r -p "$1" "$2" &2 exit 1 fi done deb_release="$(detect_deb_release)" repo_base="https://repo.bgp.exchange/${deb_release}" preseed_base="https://repo.bgp.exchange/preseed" if is_efi; then preseed_file="${hostname}.efi.txt" else preseed_file="${hostname}.txt" fi preseed_url="${preseed_base}/${preseed_file}" echo "Debian netboot: ${repo_base}/" echo "Preseed: ${preseed_url}" boot_dir="/boot/bgpe" mkdir -p "$boot_dir" cd "$boot_dir" rm -f initrd.gz vmlinuz initrd.gz.* vmlinuz.* wget -q --show-progress -O initrd.gz "${repo_base}/initrd.gz" wget -q --show-progress -O vmlinuz "${repo_base}/vmlinuz" for f in initrd.gz vmlinuz; do if [[ ! -s "${boot_dir}/${f}" ]]; then echo "ERROR: ${boot_dir}/${f} missing or empty after download" >&2 exit 1 fi done # GRUB paths are relative to the partition containing /boot. When /boot is its own # filesystem, that partition's root is /boot — use /bgpe/..., not /boot/bgpe/... if mountpoint -q /boot && [[ "$(stat -c '%d' /)" -ne "$(stat -c '%d' /boot)" ]]; then grub_kernel="/bgpe/vmlinuz" grub_initrd="/bgpe/initrd.gz" else grub_kernel="/boot/bgpe/vmlinuz" grub_initrd="/boot/bgpe/initrd.gz" fi echo "GRUB paths: ${grub_kernel}, ${grub_initrd}" cat > /etc/grub.d/50_bgpe <