Files
Arch-R/scripts/first-boot.sh
Douglas Teles e4294ab47b Two-image build pipeline, clone support, initramfs splash
- Clone variant: mainline U-Boot v2025.10, boot.scr, clone DTS (type5)
- Initramfs splash: archr-init.c with embedded BMP, sub-second display
- Panel wizard: auto-detect with fsync persistence, evdev X-button reset
- Hotkeys: adc-keys volume for clone, HP jack detection, brightness persist
- Boot.ini: ASCII-only (no Unicode), GPIO check removed
- ES wrapper: removed framebuffer blanking (preserves splash)
- Build pipeline: both variants, splash generation, panel DTBOs
- .gitignore: exclude large bootloader trees and build artifacts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 22:38:47 -03:00

210 lines
7.5 KiB
Bash

#!/bin/bash
#==============================================================================
# Arch R - First Boot Setup Script
#==============================================================================
# Runs on first boot to:
# 1. Create ROMS partition (FAT32) with remaining SD card space
# 2. Generate SSH keys and machine-id
# 3. Configure RetroArch and EmulationStation
# 4. Create ROM directories
#==============================================================================
FIRST_BOOT_FLAG="/var/lib/archr/.first-boot-done"
LOG_FILE="/var/log/first-boot.log"
# Log all output for debugging
exec > >(tee -a "$LOG_FILE") 2>&1
if [ -f "$FIRST_BOOT_FLAG" ]; then
echo "First boot already completed, skipping"
exit 0
fi
echo "=== Arch R First Boot Setup === ($(date))"
#------------------------------------------------------------------------------
# Detect SD card device
#------------------------------------------------------------------------------
ROOT_SOURCE=$(findmnt -no SOURCE /)
ROOT_DISK=$(lsblk -no PKNAME "$ROOT_SOURCE" | head -1)
ROOT_DISK="/dev/${ROOT_DISK}"
echo "Root device: $ROOT_SOURCE"
echo "SD card: $ROOT_DISK"
#------------------------------------------------------------------------------
# Create ROMS partition (partition 3) if it doesn't exist
#------------------------------------------------------------------------------
ROMS_PART="${ROOT_DISK}p3"
ROMS_OK=false
if ! lsblk "$ROMS_PART" &>/dev/null; then
echo "Creating ROMS partition..."
# Parse partition info using sfdisk dump format (reliable, no column alignment issues)
LAST_INFO=$(sfdisk -d "$ROOT_DISK" 2>/dev/null | grep '^/dev' | tail -1)
PART_START=$(echo "$LAST_INFO" | grep -o 'start=[[:space:]]*[0-9]*' | grep -o '[0-9]*')
PART_SIZE=$(echo "$LAST_INFO" | grep -o 'size=[[:space:]]*[0-9]*' | grep -o '[0-9]*')
if [ -n "$PART_START" ] && [ -n "$PART_SIZE" ]; then
LAST_END=$((PART_START + PART_SIZE))
DISK_SECTORS=$(blockdev --getsz "$ROOT_DISK" 2>/dev/null)
echo " Last partition ends at sector $LAST_END, disk has $DISK_SECTORS sectors"
if [ -n "$DISK_SECTORS" ] && [ "$LAST_END" -lt "$DISK_SECTORS" ]; then
echo "${LAST_END},+,0c" | sfdisk --force --append "$ROOT_DISK" 2>&1 || \
echo ",,0c" | sfdisk --force --append "$ROOT_DISK" 2>&1 || \
echo " ERROR: sfdisk --append failed"
else
echo " ERROR: No free space on disk (last=$LAST_END, total=$DISK_SECTORS)"
fi
else
echo " WARNING: Could not parse partition table, trying generic append"
echo ",,0c" | sfdisk --force --append "$ROOT_DISK" 2>&1 || \
echo " ERROR: sfdisk --append failed"
fi
# Tell kernel about the new partition (try multiple methods)
partprobe "$ROOT_DISK" 2>/dev/null
sleep 2
if ! lsblk "$ROMS_PART" &>/dev/null; then
# partprobe failed — try partx (more reliable for adding single partitions)
partx -a "$ROOT_DISK" 2>/dev/null
sleep 2
fi
if ! lsblk "$ROMS_PART" &>/dev/null; then
# Last resort: blockdev re-read
blockdev --rereadpt "$ROOT_DISK" 2>/dev/null
sleep 3
fi
if lsblk "$ROMS_PART" &>/dev/null; then
echo " Formatting as FAT32..."
mkfs.vfat -F 32 -n ROMS "$ROMS_PART"
echo " ROMS partition created!"
else
echo " WARNING: Partition created in table but kernel can't see it yet"
echo " ROMS will be available after reboot"
fi
else
echo " ROMS partition already exists"
# Ensure it has a FAT32 filesystem with the ROMS label
if ! blkid "$ROMS_PART" | grep -q 'TYPE="vfat"'; then
echo " Formatting existing partition as FAT32..."
mkfs.vfat -F 32 -n ROMS "$ROMS_PART"
elif ! blkid "$ROMS_PART" | grep -q 'LABEL="ROMS"'; then
echo " Setting label to ROMS..."
fatlabel "$ROMS_PART" ROMS 2>/dev/null || true
fi
fi
#------------------------------------------------------------------------------
# Mount ROMS partition and create directories
#------------------------------------------------------------------------------
echo "Setting up ROM directories..."
mkdir -p /roms
if lsblk "$ROMS_PART" &>/dev/null; then
if ! mountpoint -q /roms; then
mount "$ROMS_PART" /roms 2>&1 || echo " WARNING: Could not mount $ROMS_PART"
fi
fi
if mountpoint -q /roms; then
ROMS_OK=true
SYSTEMS=(
"nes" "snes" "gb" "gbc" "gba" "nds"
"megadrive" "mastersystem" "gamegear" "genesis" "segacd" "sega32x"
"n64" "psx" "psp"
"dreamcast" "saturn"
"arcade" "mame" "fbneo" "neogeo"
"atari2600" "atari7800" "atarilynx"
"pcengine" "pcenginecd" "supergrafx"
"wonderswan" "wonderswancolor"
"ngp" "ngpc"
"virtualboy"
"scummvm" "dos"
"ports"
"bios"
)
for sys in "${SYSTEMS[@]}"; do
mkdir -p "/roms/$sys"
done
mkdir -p /roms/saves /roms/states
echo " ROM directories created"
else
echo " WARNING: /roms not mounted — directories will be created on next boot"
fi
#------------------------------------------------------------------------------
# Generate SSH host keys
#------------------------------------------------------------------------------
echo "Generating SSH host keys..."
ssh-keygen -A 2>/dev/null || true
#------------------------------------------------------------------------------
# Set random machine-id
#------------------------------------------------------------------------------
echo "Generating machine ID..."
rm -f /etc/machine-id
systemd-machine-id-setup
#------------------------------------------------------------------------------
# Enable services
#------------------------------------------------------------------------------
echo "Enabling services..."
systemctl enable NetworkManager 2>/dev/null || true
#------------------------------------------------------------------------------
# Configure RetroArch
#------------------------------------------------------------------------------
echo "Configuring RetroArch..."
RA_DIR="/home/archr/.config/retroarch"
mkdir -p "$RA_DIR/cores"
mkdir -p "$RA_DIR/saves"
mkdir -p "$RA_DIR/states"
mkdir -p "$RA_DIR/screenshots"
if [ ! -f "$RA_DIR/retroarch.cfg" ] && [ -f /etc/archr/retroarch.cfg ]; then
cp /etc/archr/retroarch.cfg "$RA_DIR/retroarch.cfg"
fi
# Set savefile/savestate directories to ROMS partition
sed -i "s|^savefile_directory =.*|savefile_directory = \"/roms/saves\"|" "$RA_DIR/retroarch.cfg" 2>/dev/null || true
sed -i "s|^savestate_directory =.*|savestate_directory = \"/roms/states\"|" "$RA_DIR/retroarch.cfg" 2>/dev/null || true
#------------------------------------------------------------------------------
# Configure EmulationStation
#------------------------------------------------------------------------------
echo "Configuring EmulationStation..."
ES_DIR="/home/archr/.emulationstation"
mkdir -p "$ES_DIR"
# Link system config
if [ ! -f "$ES_DIR/es_systems.cfg" ] && [ -f /etc/emulationstation/es_systems.cfg ]; then
ln -sf /etc/emulationstation/es_systems.cfg "$ES_DIR/es_systems.cfg"
fi
chown -R archr:archr /home/archr
#------------------------------------------------------------------------------
# Mark first boot complete (only if ROMS partition is working)
#------------------------------------------------------------------------------
if [ "$ROMS_OK" = true ]; then
mkdir -p "$(dirname "$FIRST_BOOT_FLAG")"
touch "$FIRST_BOOT_FLAG"
echo "=== First Boot Setup Complete ==="
else
echo "=== First Boot Setup Partial — ROMS partition will retry on next boot ==="
fi