bitspire/deploy/nixos/flash-douro-usb.sh
Padreug 7c1011d382 chore(nix): bump nixpkgs 24.05 → 24.11
Three breakages handled:

- hardware.opengl → hardware.graphics (renamed in 24.11). Touches
  upboard.nix, douro.nix, batm3.nix, live.nix.
- vaapiIntel dropped — legacy pre-Broadwell driver, removed in
  nixpkgs. UP Board (Cherry Trail) and OptiPlex 9030 (Haswell) both
  use intel-media-driver, which stays.
- vaapiVdpau renamed → libva-vdpau-driver.

system.stateVersion stays 24.05 — convention is to never bump after
install. Existing Sintra and fresh flashes keep the 24.05 state
semantics; that's correct.

All 8 nixosConfigurations (4 models × {live,installed}) evaluate
clean with zero deprecation warnings on 24.11.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 19:12:11 +02:00

195 lines
6 KiB
Bash
Executable file

#!/usr/bin/env bash
# Flash a NixOS Live ISO to a USB stick with a proper GPT + FAT32 ESP layout.
#
# Bay Trail (Douro) UEFI firmware can't boot from raw dd'd ISOs because it
# doesn't parse the El Torito EFI boot catalog embedded in ISO9660. This script
# creates a standard GPT partition with a FAT32 filesystem containing the
# EFI bootloader, kernel, initrd, and NixOS squashfs — which Bay Trail
# firmware recognizes natively.
#
# Usage: sudo bash flash-usb.sh /dev/sdX [path/to/iso]
#
# If no ISO path is given, uses the most recent build in result/iso/.
set -euo pipefail
USB_DEV="${1:-}"
ISO_PATH="${2:-}"
if [ -z "$USB_DEV" ]; then
echo "Usage: sudo bash flash-usb.sh /dev/sdX [path/to/iso]"
echo ""
echo " /dev/sdX USB device (NOT a partition — e.g. /dev/sdc, not /dev/sdc1)"
echo " path/to/iso Optional ISO path (default: result/iso/*.iso)"
echo ""
echo "WARNING: This will erase ALL data on the target device!"
exit 1
fi
# Safety checks
if [ "$(id -u)" -ne 0 ]; then
echo "ERROR: Must run as root (sudo)"
exit 1
fi
if [ ! -b "$USB_DEV" ]; then
echo "ERROR: $USB_DEV is not a block device"
exit 1
fi
# Don't accidentally wipe a hard drive
if echo "$USB_DEV" | grep -qE '^/dev/(sda|nvme|vda)'; then
echo "ERROR: $USB_DEV looks like a system drive. Refusing to proceed."
echo " Use a removable USB device (e.g. /dev/sdb, /dev/sdc)."
exit 1
fi
# Find ISO
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ -z "$ISO_PATH" ]; then
ISO_PATH=$(ls "$SCRIPT_DIR"/result/iso/*.iso 2>/dev/null | head -1)
if [ -z "$ISO_PATH" ]; then
echo "ERROR: No ISO found in $SCRIPT_DIR/result/iso/"
echo " Build one first: bash build-iso.sh douro"
exit 1
fi
fi
if [ ! -f "$ISO_PATH" ]; then
echo "ERROR: ISO not found: $ISO_PATH"
exit 1
fi
ISO_SIZE=$(du -h "$ISO_PATH" | cut -f1)
USB_SIZE=$(lsblk -dno SIZE "$USB_DEV" 2>/dev/null || echo "unknown")
USB_MODEL=$(lsblk -dno MODEL "$USB_DEV" 2>/dev/null || echo "unknown")
echo "=== Flash NixOS Live USB ==="
echo "ISO: $ISO_PATH ($ISO_SIZE)"
echo "Target: $USB_DEV ($USB_SIZE, $USB_MODEL)"
echo ""
echo "WARNING: ALL data on $USB_DEV will be destroyed!"
read -p "Continue? (y/N) " -r
if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then
echo "Aborted."
exit 0
fi
# Unmount any mounted partitions on the USB
echo ""
echo "--- Unmounting existing partitions ---"
for part in "${USB_DEV}"*; do
if mountpoint -q "$part" 2>/dev/null || mount | grep -q "^$part "; then
umount "$part" 2>/dev/null || true
echo "Unmounted $part"
fi
done
# Step 1: Create GPT partition table with a single FAT32 partition
echo ""
echo "--- Step 1: Creating GPT partition table ---"
parted -s "$USB_DEV" mklabel gpt
parted -s "$USB_DEV" mkpart ESP fat32 1MiB 100%
parted -s "$USB_DEV" set 1 esp on
echo "OK: GPT with ESP partition"
# Wait for kernel to pick up new partition table
sleep 2
partprobe "$USB_DEV" 2>/dev/null || true
sleep 1
# Find the partition device (handles both /dev/sdc1 and /dev/nvme0n1p1 styles)
PART_DEV="${USB_DEV}1"
if [ ! -b "$PART_DEV" ]; then
PART_DEV="${USB_DEV}p1"
fi
if [ ! -b "$PART_DEV" ]; then
echo "ERROR: Partition device not found (tried ${USB_DEV}1 and ${USB_DEV}p1)"
exit 1
fi
# Step 2: Format as FAT32
# FAT32 volume labels are max 11 chars, so we use a short label.
# The kernel finds root by LABEL=nixos-24.11-x86_64 which is on the ISO9660.
# But since we're extracting the ISO, we set the label on the FAT32 partition.
# NixOS initrd also searches by /nix-store.squashfs file presence.
echo ""
echo "--- Step 2: Formatting FAT32 ---"
mkfs.fat -F32 -n 'NIXOS2411' "$PART_DEV"
echo "OK: FAT32 formatted"
# Step 3: Mount ISO and USB partition
echo ""
echo "--- Step 3: Mounting ISO and USB ---"
MNT_ISO=$(mktemp -d)
MNT_USB=$(mktemp -d)
mount -o loop,ro "$ISO_PATH" "$MNT_ISO"
mount "$PART_DEV" "$MNT_USB"
echo "ISO mounted at $MNT_ISO"
echo "USB mounted at $MNT_USB"
# Cleanup function
cleanup() {
echo ""
echo "--- Cleaning up ---"
umount "$MNT_USB" 2>/dev/null || true
umount "$MNT_ISO" 2>/dev/null || true
rmdir "$MNT_ISO" 2>/dev/null || true
rmdir "$MNT_USB" 2>/dev/null || true
}
trap cleanup EXIT
# Step 4: Copy EFI boot files (UPPERCASE paths for Bay Trail UEFI compatibility)
echo ""
echo "--- Step 4: Copying EFI boot files ---"
mkdir -p "$MNT_USB/EFI/BOOT"
cp "$MNT_ISO/EFI/boot/bootx64.efi" "$MNT_USB/EFI/BOOT/BOOTX64.EFI"
cp "$MNT_ISO/EFI/boot/grub.cfg" "$MNT_USB/EFI/BOOT/grub.cfg"
cp -r "$MNT_ISO/EFI/boot/grub-theme" "$MNT_USB/EFI/BOOT/grub-theme"
cp "$MNT_ISO/EFI/boot/unicode.pf2" "$MNT_USB/EFI/BOOT/unicode.pf2"
cp "$MNT_ISO/EFI/boot/efi-background.png" "$MNT_USB/EFI/BOOT/efi-background.png"
if [ -f "$MNT_ISO/EFI/boot/refind_x64.efi" ]; then
cp "$MNT_ISO/EFI/boot/refind_x64.efi" "$MNT_USB/EFI/BOOT/refind_x64.efi"
fi
# Create the marker file GRUB searches for (search --file /EFI/nixos-installer-image)
mkdir -p "$MNT_USB/EFI"
touch "$MNT_USB/EFI/nixos-installer-image"
echo "OK: EFI boot files copied"
# Step 5: Copy boot directory (kernel, initrd, grub modules)
echo ""
echo "--- Step 5: Copying kernel and initrd ---"
cp -r "$MNT_ISO/boot" "$MNT_USB/boot"
echo "OK: Kernel and initrd copied"
# Step 6: Fix GRUB config paths (lowercase -> uppercase for our layout)
echo ""
echo "--- Step 6: Fixing GRUB config paths ---"
sed -i 's|/EFI/boot/|/EFI/BOOT/|g' "$MNT_USB/EFI/BOOT/grub.cfg"
echo "OK: GRUB paths updated"
# Step 7: Copy NixOS root filesystem (this is the big one ~2GB)
echo ""
echo "--- Step 7: Copying NixOS squashfs (this takes a while) ---"
cp "$MNT_ISO/nix-store.squashfs" "$MNT_USB/nix-store.squashfs"
if [ -f "$MNT_ISO/version.txt" ]; then
cp "$MNT_ISO/version.txt" "$MNT_USB/version.txt"
fi
echo "OK: squashfs copied"
# Step 8: Sync
echo ""
echo "--- Step 8: Syncing to disk ---"
sync
echo "OK: All data written"
# Cleanup happens via trap
echo ""
echo "=== USB flash complete ==="
echo "Device: $USB_DEV"
echo ""
echo "Now plug it into the target machine and boot from USB."
echo "The GRUB menu should appear with NixOS installer options."
echo ""
echo "After booting, provision credentials with:"
echo " bash provision-atm.sh <atm-ip> 22"