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>
195 lines
6 KiB
Bash
Executable file
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"
|