Monorepo for Aesthetic.Computer aesthetic.computer
at main 315 lines 9.5 kB view raw
1#!/bin/bash 2# make-usb.sh — One-step FedAC USB creator 3# 4# Downloads Fedora, flashes to USB, patches GRUB with FedAC branding + kickstart. 5# One command, done. 6# 7# Usage: 8# sudo bash fedac/scripts/make-usb.sh /dev/sdX 9# 10# Options: 11# --iso <path> Use a local ISO instead of downloading 12# --no-eject Don't eject when done 13# --yes Skip confirmation prompts 14 15set -euo pipefail 16 17RED='\033[0;31m' 18GREEN='\033[0;32m' 19YELLOW='\033[1;33m' 20CYAN='\033[0;36m' 21PURPLE='\033[0;35m' 22NC='\033[0m' 23 24SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" 25FEDAC_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" 26 27# Fedora 43 Workstation 28FEDORA_VERSION="43" 29FEDORA_RELEASE="43-1.6" 30FEDORA_ISO_NAME="Fedora-Workstation-Live-${FEDORA_RELEASE}.x86_64.iso" 31FEDORA_URL="https://dl.fedoraproject.org/pub/fedora/linux/releases/${FEDORA_VERSION}/Workstation/x86_64/iso/${FEDORA_ISO_NAME}" 32FEDORA_SHA256="2a4a16c009244eb5ab2198700eb04103793b62407e8596f30a3e0cc8ac294d77" 33CACHE_DIR="${HOME}/Downloads" 34 35usage() { 36 echo -e "${PURPLE}FedAC USB Creator${NC}" 37 echo "" 38 echo "Usage: sudo $0 <device> [options]" 39 echo "" 40 echo " <device> USB block device (e.g., /dev/sdb)" 41 echo "" 42 echo "Options:" 43 echo " --iso <path> Use existing ISO instead of downloading" 44 echo " --no-eject Don't eject the USB when done" 45 echo " --yes Skip confirmation prompts" 46 echo " --help Show this help" 47 exit 1 48} 49 50# ── Parse args ── 51DEVICE="" 52ISO_PATH="" 53DO_EJECT=true 54SKIP_CONFIRM=false 55 56while [ $# -gt 0 ]; do 57 case "$1" in 58 --iso) ISO_PATH="$2"; shift 2 ;; 59 --no-eject) DO_EJECT=false; shift ;; 60 --yes) SKIP_CONFIRM=true; shift ;; 61 --help|-h) usage ;; 62 /dev/*) DEVICE="$1"; shift ;; 63 *) echo -e "${RED}Unknown arg: $1${NC}"; usage ;; 64 esac 65done 66 67[ -n "$DEVICE" ] || { echo -e "${RED}Error: No device specified${NC}"; usage; } 68[ -b "$DEVICE" ] || { echo -e "${RED}Error: $DEVICE is not a block device${NC}"; exit 1; } 69 70# Must be root 71if [ "$(id -u)" -ne 0 ]; then 72 echo -e "${RED}Error: Must run as root (sudo)${NC}" 73 exit 1 74fi 75 76# Safety: refuse system disks 77case "$DEVICE" in 78 /dev/sda|/dev/nvme0n1|/dev/vda|/dev/xvda) 79 echo -e "${RED}REFUSED: $DEVICE is likely your system disk.${NC}" 80 exit 1 81 ;; 82esac 83 84echo -e "${PURPLE}╔══════════════════════════════════════╗${NC}" 85echo -e "${PURPLE}║ FedAC USB Creator ║${NC}" 86echo -e "${PURPLE}╚══════════════════════════════════════╝${NC}" 87echo "" 88 89# ── Step 1: Get the ISO ── 90echo -e "${CYAN}[1/5] Getting Fedora ${FEDORA_VERSION} ISO...${NC}" 91 92if [ -n "$ISO_PATH" ]; then 93 # User provided an ISO 94 if [ ! -f "$ISO_PATH" ]; then 95 echo -e "${RED}ISO not found: $ISO_PATH${NC}" 96 exit 1 97 fi 98 echo -e " Using: ${GREEN}$ISO_PATH${NC}" 99else 100 ISO_PATH="${CACHE_DIR}/${FEDORA_ISO_NAME}" 101 102 if [ -f "$ISO_PATH" ]; then 103 echo -e " Found cached: ${GREEN}$ISO_PATH${NC}" 104 else 105 echo -e " Downloading ${FEDORA_ISO_NAME} (~2.6 GB)..." 106 mkdir -p "$CACHE_DIR" 107 curl -L --progress-bar -o "$ISO_PATH" "$FEDORA_URL" 108 echo -e " ${GREEN}Downloaded${NC}" 109 fi 110fi 111 112# ── Step 2: Verify checksum ── 113echo -e "${CYAN}[2/5] Verifying checksum...${NC}" 114ACTUAL_SHA=$(sha256sum "$ISO_PATH" | cut -d' ' -f1) 115if [ "$ACTUAL_SHA" = "$FEDORA_SHA256" ]; then 116 echo -e " ${GREEN}SHA256 OK${NC}" 117else 118 echo -e " ${YELLOW}WARNING: Checksum mismatch${NC}" 119 echo " Expected: $FEDORA_SHA256" 120 echo " Got: $ACTUAL_SHA" 121 echo " (Continuing — may be a different Fedora build)" 122fi 123 124# ── Confirm ── 125echo "" 126echo -e "Target: ${YELLOW}$DEVICE${NC}" 127lsblk "$DEVICE" 2>/dev/null || true 128echo "" 129 130if [ "$SKIP_CONFIRM" = false ]; then 131 echo -e "${RED}ALL DATA ON $DEVICE WILL BE DESTROYED${NC}" 132 read -p "Continue? [y/N] " confirm 133 if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then 134 echo "Aborted." 135 exit 0 136 fi 137fi 138 139# ── Step 3: Flash ISO ── 140echo -e "${CYAN}[3/5] Flashing ISO to $DEVICE...${NC}" 141 142# Unmount any mounted partitions 143for part in "${DEVICE}"*; do 144 umount "$part" 2>/dev/null || true 145done 146 147dd if="$ISO_PATH" of="$DEVICE" bs=4M status=progress oflag=sync 2>&1 148sync 149echo -e " ${GREEN}Flash complete${NC}" 150 151# Wait for kernel to re-read partition table 152echo -e " Waiting for partitions..." 153sleep 2 154partprobe "$DEVICE" 2>/dev/null || true 155sleep 2 156 157# ── Step 4: Patch EFI partition ── 158echo -e "${CYAN}[4/5] Patching EFI partition with FedAC boot...${NC}" 159 160# Find EFI partition 161EFI_PART="" 162for part in "${DEVICE}2" "${DEVICE}p2"; do 163 if [ -b "$part" ]; then 164 EFI_PART="$part" 165 break 166 fi 167done 168 169if [ -z "$EFI_PART" ]; then 170 echo -e "${YELLOW}Could not find EFI partition — skipping GRUB patch${NC}" 171 echo "You'll see the default Fedora boot menu." 172 echo "At GRUB, press 'e' and add: inst.ks=https://..." 173else 174 MOUNT_DIR=$(mktemp -d /tmp/fedac-efi-XXXX) 175 mount "$EFI_PART" "$MOUNT_DIR" 176 177 # Copy kickstart 178 KS_SRC="$FEDAC_DIR/kickstart/fedac-thinkpad.ks" 179 if [ -f "$KS_SRC" ]; then 180 cp "$KS_SRC" "$MOUNT_DIR/fedac.ks" 181 echo -e " Kickstart copied to EFI partition" 182 else 183 echo -e " ${YELLOW}Warning: $KS_SRC not found — kickstart not included${NC}" 184 fi 185 186 # ── Install GRUB theme ── 187 THEME_SRC="$FEDAC_DIR/grub-theme" 188 THEME_DST="$MOUNT_DIR/EFI/BOOT/fedac-theme" 189 mkdir -p "$THEME_DST" 190 191 # Copy theme assets 192 NEED_GENERATE=false 193 for asset in theme.txt background.png DejaVuSansBold36.pf2 DejaVuSans18.pf2 DejaVuSans10.pf2 select_c.png menu_c.png; do 194 if [ -f "$THEME_SRC/$asset" ]; then 195 cp "$THEME_SRC/$asset" "$THEME_DST/" 196 elif [ "$asset" != "theme.txt" ]; then 197 NEED_GENERATE=true 198 fi 199 done 200 201 if [ "$NEED_GENERATE" = true ] && [ -x "$THEME_SRC/prepare-theme.sh" ]; then 202 echo -e " Generating theme assets..." 203 bash "$THEME_SRC/prepare-theme.sh" 2>/dev/null || echo -e " ${YELLOW}Theme generation had warnings${NC}" 204 for asset in background.png DejaVuSansBold36.pf2 DejaVuSans18.pf2 DejaVuSans10.pf2 select_c.png menu_c.png; do 205 [ -f "$THEME_SRC/$asset" ] && cp "$THEME_SRC/$asset" "$THEME_DST/" 206 done 207 fi 208 echo -e " ${GREEN}Theme installed${NC}" 209 210 # ── Patch GRUB config ── 211 GRUB_CFG="" 212 for candidate in \ 213 "$MOUNT_DIR/EFI/BOOT/grub.cfg" \ 214 "$MOUNT_DIR/EFI/fedora/grub.cfg" \ 215 "$MOUNT_DIR/boot/grub2/grub.cfg"; do 216 if [ -f "$candidate" ]; then 217 GRUB_CFG="$candidate" 218 break 219 fi 220 done 221 222 if [ -n "$GRUB_CFG" ]; then 223 cp "$GRUB_CFG" "${GRUB_CFG}.orig" 224 CDLABEL="Fedora-WS-Live-${FEDORA_VERSION}" 225 226 cat > "$GRUB_CFG" << 'GRUBEOF' 227# FedAC — Fedora Boot-to-Aesthetic-Computer 228# Auto-generated by fedac/scripts/make-usb.sh 229 230set default=0 231set timeout=5 232 233# ── Graphics modules ── 234if [ "$grub_platform" == "efi" ]; then 235 insmod efi_gop 236 insmod efi_uga 237fi 238insmod all_video 239insmod gzio 240insmod part_gpt 241insmod ext2 242insmod png 243insmod font 244 245# ── Save EFI partition root before search changes it ── 246set efi_root=$root 247 248# ── Load fonts from EFI partition (before $root changes) ── 249loadfont ($efi_root)/EFI/BOOT/fedac-theme/DejaVuSansBold36.pf2 250loadfont ($efi_root)/EFI/BOOT/fedac-theme/DejaVuSans18.pf2 251loadfont ($efi_root)/EFI/BOOT/fedac-theme/DejaVuSans10.pf2 252 253# ── Switch to graphical terminal ── 254set gfxmode=auto 255set gfxpayload=keep 256terminal_input console 257terminal_output gfxterm 258 259# ── Load theme from EFI partition ── 260if [ -f ($efi_root)/EFI/BOOT/fedac-theme/theme.txt ]; then 261 set theme=($efi_root)/EFI/BOOT/fedac-theme/theme.txt 262else 263 set color_normal=magenta/black 264 set color_highlight=white/magenta 265fi 266 267# ── Find Fedora live partition (changes $root) ── 268search --file --set=root /boot/0x4da30161 269 270menuentry " FedAC — Install Aesthetic Computer" --class fedora { 271 linux ($root)/boot/x86_64/loader/linux quiet rhgb root=live:CDLABEL=FEDAC_CDLABEL rd.live.image inst.ks=https://raw.githubusercontent.com/whistlegraph/aesthetic-computer/main/fedac/kickstart/fedac-thinkpad.ks 272 initrd ($root)/boot/x86_64/loader/initrd 273} 274 275menuentry " FedAC — Live Desktop (no install)" --class fedora { 276 linux ($root)/boot/x86_64/loader/linux quiet rhgb root=live:CDLABEL=FEDAC_CDLABEL rd.live.image 277 initrd ($root)/boot/x86_64/loader/initrd 278} 279 280menuentry " Boot from local drive" { 281 exit 282} 283GRUBEOF 284 285 sed -i "s/FEDAC_CDLABEL/${CDLABEL}/g" "$GRUB_CFG" 286 echo -e " ${GREEN}GRUB patched — FedAC graphical boot menu installed${NC}" 287 else 288 echo -e " ${YELLOW}No grub.cfg found on EFI — skipping GRUB patch${NC}" 289 fi 290 291 sync 292 umount "$MOUNT_DIR" 293 rmdir "$MOUNT_DIR" 294fi 295 296# ── Step 5: Done ── 297echo -e "${CYAN}[5/5] Finalizing...${NC}" 298sync 299 300if [ "$DO_EJECT" = true ]; then 301 eject "$DEVICE" 2>/dev/null || true 302 echo -e " ${GREEN}Ejected${NC}" 303fi 304 305echo "" 306echo -e "${GREEN}╔══════════════════════════════════════╗${NC}" 307echo -e "${GREEN}║ FedAC USB Ready ║${NC}" 308echo -e "${GREEN}╚══════════════════════════════════════╝${NC}" 309echo "" 310echo -e "Boot menu (pals logo + large text, auto-starts in 5s):" 311echo -e " ${PURPLE}1. FedAC — Install Aesthetic Computer${NC}" 312echo -e " 2. FedAC — Live Desktop (no install)" 313echo -e " 3. Boot from local drive" 314echo "" 315echo "Plug into target machine → boot from USB → done."