Monorepo for Aesthetic.Computer
aesthetic.computer
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."