diff --git a/rpi/flash-pi.sh b/rpi/flash-pi.sh new file mode 100755 index 0000000..f376a6a --- /dev/null +++ b/rpi/flash-pi.sh @@ -0,0 +1,179 @@ +#!/bin/bash +# Flash Raspberry Pi image with headless config +# Usage: ./flash-pi.sh +# Reads settings from config.json in same directory + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_FILE="$SCRIPT_DIR/config.json" + +# ============================================================================ +# Load config +# ============================================================================ +if [ ! -f "$CONFIG_FILE" ]; then + echo "Error: config.json not found at $CONFIG_FILE" + exit 1 +fi + +PI_USER=$(jq -r '.username' "$CONFIG_FILE") +PI_PASS=$(jq -r '.password' "$CONFIG_FILE") +WIFI_SSID=$(jq -r '.wifiSSID' "$CONFIG_FILE") +WIFI_PASS=$(jq -r '.wifiPassword' "$CONFIG_FILE") +WIFI_COUNTRY=$(jq -r '.wifiCountry' "$CONFIG_FILE") +HOSTNAME=$(jq -r '.hostname' "$CONFIG_FILE") + +echo "Loaded config from $CONFIG_FILE" +echo " Hostname: $HOSTNAME" +echo " User: $PI_USER" +echo " WiFi: $WIFI_SSID" +echo + +# ============================================================================ +# Validate args +# ============================================================================ +if [ $# -ne 2 ]; then + echo "Usage: $0 " + echo "Example: $0 2025-12-04-raspios-trixie-arm64-lite.img.xz /dev/sdb" + exit 1 +fi + +IMAGE="$1" +DEVICE="$2" + +if [ ! -f "$IMAGE" ]; then + echo "Error: Image file not found: $IMAGE" + exit 1 +fi + +if [ ! -b "$DEVICE" ]; then + echo "Error: Device not found: $DEVICE" + exit 1 +fi + +# Safety check +echo "WARNING: This will ERASE all data on $DEVICE" +echo "Device info:" +lsblk "$DEVICE" +echo +read -p "Type 'yes' to continue: " confirm +if [ "$confirm" != "yes" ]; then + echo "Aborted." + exit 1 +fi + +# ============================================================================ +# Flash image +# ============================================================================ +echo "Flashing $IMAGE to $DEVICE..." +if [[ "$IMAGE" == *.xz ]]; then + xzcat "$IMAGE" | sudo dd of="$DEVICE" bs=4M status=progress conv=fsync +elif [[ "$IMAGE" == *.zst ]]; then + zstdcat "$IMAGE" | sudo dd of="$DEVICE" bs=4M status=progress conv=fsync +else + sudo dd if="$IMAGE" of="$DEVICE" bs=4M status=progress conv=fsync +fi + +echo "Syncing..." +sync + +# ============================================================================ +# Configure boot partition +# ============================================================================ +BOOT_MOUNT=$(mktemp -d) +echo "Mounting boot partition to $BOOT_MOUNT..." + +# Wait for partition to appear +sleep 2 +sudo partprobe "$DEVICE" 2>/dev/null || true +sleep 1 + +# Try both partition naming schemes +if [ -b "${DEVICE}1" ]; then + BOOT_PART="${DEVICE}1" +elif [ -b "${DEVICE}p1" ]; then + BOOT_PART="${DEVICE}p1" +else + echo "Error: Could not find boot partition" + exit 1 +fi + +sudo mount "$BOOT_PART" "$BOOT_MOUNT" + +# Enable SSH +echo "Enabling SSH..." +sudo touch "$BOOT_MOUNT/ssh" + +# Set user/password +echo "Setting user credentials..." +PASS_HASH=$(echo "$PI_PASS" | openssl passwd -6 -stdin) +echo "${PI_USER}:${PASS_HASH}" | sudo tee "$BOOT_MOUNT/userconf.txt" > /dev/null + +# Set hostname +echo "Setting hostname to $HOSTNAME..." +echo "$HOSTNAME" | sudo tee "$BOOT_MOUNT/hostname" > /dev/null + +# Cleanup boot partition +echo "Unmounting boot..." +sudo umount "$BOOT_MOUNT" + +# ============================================================================ +# Configure rootfs partition (for NetworkManager WiFi) +# ============================================================================ +if [ -n "$WIFI_SSID" ]; then + echo "Configuring WiFi on rootfs..." + + # Find rootfs partition + if [ -b "${DEVICE}2" ]; then + ROOT_PART="${DEVICE}2" + elif [ -b "${DEVICE}p2" ]; then + ROOT_PART="${DEVICE}p2" + else + echo "Warning: Could not find rootfs partition, skipping WiFi config" + rmdir "$BOOT_MOUNT" + exit 0 + fi + + sudo mount "$ROOT_PART" "$BOOT_MOUNT" + + # Create NetworkManager connection file + NM_DIR="$BOOT_MOUNT/etc/NetworkManager/system-connections" + sudo mkdir -p "$NM_DIR" + + sudo tee "$NM_DIR/$WIFI_SSID.nmconnection" > /dev/null << EOF +[connection] +id=$WIFI_SSID +type=wifi +autoconnect=true + +[wifi] +mode=infra +ssid=$WIFI_SSID + +[wifi-security] +key-mgmt=wpa-psk +psk=$WIFI_PASS + +[ipv4] +method=auto + +[ipv6] +method=auto +EOF + + sudo chmod 600 "$NM_DIR/$WIFI_SSID.nmconnection" + + echo "Unmounting rootfs..." + sudo umount "$BOOT_MOUNT" +fi + +rmdir "$BOOT_MOUNT" + +echo +echo "Done! SD card is ready." +echo " Hostname: $HOSTNAME" +echo " User: $PI_USER" +echo " SSH: enabled" +echo " WiFi: $WIFI_SSID" +echo +echo "Insert into Pi and boot. Find it with: ping $HOSTNAME.local"