Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
Shell
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490#!/bin/bash# make-kiosk-usb.sh — Create a FedAC live kiosk USB## Boots Fedora 43 straight into Firefox kiosk mode at kidlisp.com.# No install, no GRUB menu, no desktop access. Plug in, boot, see kidlisp.com fullscreen.## How it works:# 1. Flash Fedora Workstation Live ISO to USB# 2. Extract squashfs rootfs from live partition# 3. Inject kiosk autostart + dconf settings into rootfs# 4. Repack squashfs, replace on USB# 5. Patch EFI partition: instant-boot GRUB + theme## Usage:# sudo bash fedac/scripts/make-kiosk-usb.sh /dev/sdX## Options:# --iso <path> Use a local ISO instead of downloading# --no-eject Don't eject when done# --yes Skip confirmation prompts## Requirements:# squashfs-tools (unsquashfs, mksquashfs)# ~5GB free temp space
set -euo pipefail
RED='\033[0;31m'GREEN='\033[0;32m'YELLOW='\033[1;33m'CYAN='\033[0;36m'PURPLE='\033[0;35m'NC='\033[0m'
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"FEDAC_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"OVERLAY_DIR="$FEDAC_DIR/overlays/kiosk"
# Fedora 43 WorkstationFEDORA_VERSION="43"FEDORA_RELEASE="43-1.6"FEDORA_ISO_NAME="Fedora-Workstation-Live-${FEDORA_RELEASE}.x86_64.iso"FEDORA_URL="https://dl.fedoraproject.org/pub/fedora/linux/releases/${FEDORA_VERSION}/Workstation/x86_64/iso/${FEDORA_ISO_NAME}"FEDORA_SHA256="2a4a16c009244eb5ab2198700eb04103793b62407e8596f30a3e0cc8ac294d77"CDLABEL="Fedora-WS-Live-${FEDORA_VERSION}"CACHE_DIR="${HOME}/Downloads"
usage() { echo -e "${PURPLE}FedAC Kiosk USB Creator${NC}" echo "" echo "Creates a live-only USB that boots straight into Firefox kiosk at kidlisp.com." echo "" echo "Usage: sudo $0 <device> [options]" echo "" echo " <device> USB block device (e.g., /dev/sdb)" echo "" echo "Options:" echo " --iso <path> Use existing ISO instead of downloading" echo " --no-eject Don't eject the USB when done" echo " --yes Skip confirmation prompts" echo " --help Show this help" exit 1}
cleanup() { echo -e "\n${YELLOW}Cleaning up...${NC}" # Unmount anything we mounted [ -n "${LIVE_MOUNT:-}" ] && mountpoint -q "$LIVE_MOUNT" 2>/dev/null && umount "$LIVE_MOUNT" 2>/dev/null || true [ -n "${EFI_MOUNT:-}" ] && mountpoint -q "$EFI_MOUNT" 2>/dev/null && umount "$EFI_MOUNT" 2>/dev/null || true # Remove temp dirs (but not the squashfs work dir — it's huge, leave for manual cleanup on error) [ -n "${LIVE_MOUNT:-}" ] && [ -d "$LIVE_MOUNT" ] && rmdir "$LIVE_MOUNT" 2>/dev/null || true [ -n "${EFI_MOUNT:-}" ] && [ -d "$EFI_MOUNT" ] && rmdir "$EFI_MOUNT" 2>/dev/null || true}trap cleanup EXIT
# ── Parse args ──DEVICE=""ISO_PATH=""DO_EJECT=trueSKIP_CONFIRM=false
while [ $# -gt 0 ]; do case "$1" in --iso) ISO_PATH="$2"; shift 2 ;; --no-eject) DO_EJECT=false; shift ;; --yes) SKIP_CONFIRM=true; shift ;; --help|-h) usage ;; /dev/*) DEVICE="$1"; shift ;; *) echo -e "${RED}Unknown arg: $1${NC}"; usage ;; esacdone
[ -n "$DEVICE" ] || { echo -e "${RED}Error: No device specified${NC}"; usage; }[ -b "$DEVICE" ] || { echo -e "${RED}Error: $DEVICE is not a block device${NC}"; exit 1; }
# Must be rootif [ "$(id -u)" -ne 0 ]; then echo -e "${RED}Error: Must run as root (sudo)${NC}" exit 1fi
# Safety: refuse system diskscase "$DEVICE" in /dev/nvme0n1|/dev/vda|/dev/xvda) echo -e "${RED}REFUSED: $DEVICE is likely your system disk.${NC}" exit 1 ;;esac
# Check for squashfs-toolsif ! command -v unsquashfs &>/dev/null || ! command -v mksquashfs &>/dev/null; then echo -e "${RED}Error: squashfs-tools not installed${NC}" echo "Install with: sudo dnf install squashfs-tools" exit 1fi
echo -e "${PURPLE}╔══════════════════════════════════════════╗${NC}"echo -e "${PURPLE}║ FedAC Kiosk USB Creator ║${NC}"echo -e "${PURPLE}║ Live boot → Firefox → kidlisp.com ║${NC}"echo -e "${PURPLE}╚══════════════════════════════════════════╝${NC}"echo ""
# ══════════════════════════════════════════# Step 1: Get the ISO# ══════════════════════════════════════════echo -e "${CYAN}[1/7] Getting Fedora ${FEDORA_VERSION} ISO...${NC}"
if [ -n "$ISO_PATH" ]; then if [ ! -f "$ISO_PATH" ]; then echo -e "${RED}ISO not found: $ISO_PATH${NC}" exit 1 fi echo -e " Using: ${GREEN}$ISO_PATH${NC}"else ISO_PATH="${CACHE_DIR}/${FEDORA_ISO_NAME}" if [ -f "$ISO_PATH" ]; then echo -e " Found cached: ${GREEN}$ISO_PATH${NC}" else echo -e " Downloading ${FEDORA_ISO_NAME} (~2.6 GB)..." mkdir -p "$CACHE_DIR" curl -L --progress-bar -o "$ISO_PATH" "$FEDORA_URL" echo -e " ${GREEN}Downloaded${NC}" fifi
# ══════════════════════════════════════════# Step 2: Verify checksum# ══════════════════════════════════════════echo -e "${CYAN}[2/7] Verifying checksum...${NC}"ACTUAL_SHA=$(sha256sum "$ISO_PATH" | cut -d' ' -f1)if [ "$ACTUAL_SHA" = "$FEDORA_SHA256" ]; then echo -e " ${GREEN}SHA256 OK${NC}"else echo -e " ${YELLOW}WARNING: Checksum mismatch${NC}" echo " Expected: $FEDORA_SHA256" echo " Got: $ACTUAL_SHA" echo " (Continuing — may be a different Fedora build)"fi
# ── Confirm ──echo ""echo -e "Target: ${YELLOW}$DEVICE${NC}"lsblk "$DEVICE" 2>/dev/null || trueecho ""
if [ "$SKIP_CONFIRM" = false ]; then echo -e "${RED}ALL DATA ON $DEVICE WILL BE DESTROYED${NC}" read -p "Continue? [y/N] " confirm if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then echo "Aborted." exit 0 fifi
# ══════════════════════════════════════════# Step 3: Flash ISO to USB# ══════════════════════════════════════════echo -e "${CYAN}[3/7] Flashing ISO to $DEVICE...${NC}"
# Unmount any mounted partitionsfor part in "${DEVICE}"*; do umount "$part" 2>/dev/null || truedone
dd if="$ISO_PATH" of="$DEVICE" bs=4M status=progress oflag=sync 2>&1syncecho -e " ${GREEN}Flash complete${NC}"
# Wait for kernel to re-read partition tableecho -e " Waiting for partitions..."sleep 2partprobe "$DEVICE" 2>/dev/null || truesleep 2
# ══════════════════════════════════════════# Step 4: Inject kiosk config into squashfs# ══════════════════════════════════════════echo -e "${CYAN}[4/7] Injecting kiosk config into squashfs rootfs...${NC}"
# Find and mount the live partition (partition 3 on Fedora live USB — the large ISO9660/ext4)LIVE_PART=""for part in "${DEVICE}3" "${DEVICE}p3" "${DEVICE}1" "${DEVICE}p1"; do if [ -b "$part" ]; then # Check if this partition has LiveOS/squashfs.img LIVE_MOUNT=$(mktemp -d /tmp/fedac-live-XXXX) if mount -o ro "$part" "$LIVE_MOUNT" 2>/dev/null; then if [ -f "$LIVE_MOUNT/LiveOS/squashfs.img" ]; then LIVE_PART="$part" echo -e " Found squashfs on ${GREEN}$part${NC}" break fi umount "$LIVE_MOUNT" fi rmdir "$LIVE_MOUNT" 2>/dev/null || true LIVE_MOUNT="" fidone
if [ -z "$LIVE_PART" ]; then echo -e "${RED}Could not find LiveOS/squashfs.img on any partition${NC}" echo "Partitions on $DEVICE:" lsblk "$DEVICE" exit 1fi
# Set up work directory for squashfs manipulationWORK_DIR=$(mktemp -d /tmp/fedac-squash-XXXX)echo -e " Work dir: $WORK_DIR"
# Copy squashfs.img to work dir (need to modify it)echo -e " Copying squashfs.img to work dir..."cp "$LIVE_MOUNT/LiveOS/squashfs.img" "$WORK_DIR/squashfs.img"
# Unmount live partition (we'll remount rw later)umount "$LIVE_MOUNT"
# Extract squashfsecho -e " Extracting squashfs (this takes a minute)..."cd "$WORK_DIR"unsquashfs -d squashfs-root squashfs.img
# The squashfs contains LiveOS/rootfs.img (an ext4 image)ROOTFS_IMG="$WORK_DIR/squashfs-root/LiveOS/rootfs.img"if [ ! -f "$ROOTFS_IMG" ]; then echo -e "${RED}No LiveOS/rootfs.img inside squashfs${NC}" ls -la "$WORK_DIR/squashfs-root/" "$WORK_DIR/squashfs-root/LiveOS/" 2>/dev/null || true exit 1fi
# Mount rootfs.img (ext4) read-writeROOTFS_MOUNT=$(mktemp -d /tmp/fedac-rootfs-XXXX)mount -o loop "$ROOTFS_IMG" "$ROOTFS_MOUNT"echo -e " ${GREEN}Rootfs mounted${NC}"
# ── Inject kiosk files ──
# 1. Firefox kiosk autostart for liveuserAUTOSTART_DIR="$ROOTFS_MOUNT/home/liveuser/.config/autostart"mkdir -p "$AUTOSTART_DIR"cp "$OVERLAY_DIR/firefox-kiosk.desktop" "$AUTOSTART_DIR/"# Set ownership (liveuser is UID 1000 on Fedora live)chown -R 1000:1000 "$ROOTFS_MOUNT/home/liveuser/.config"echo -e " ${GREEN}Injected firefox-kiosk.desktop${NC}"
# 2. dconf settings (disable idle, screensaver, lock, notifications)mkdir -p "$ROOTFS_MOUNT/etc/dconf/db/local.d"mkdir -p "$ROOTFS_MOUNT/etc/dconf/profile"cp "$OVERLAY_DIR/00-kiosk" "$ROOTFS_MOUNT/etc/dconf/db/local.d/00-kiosk"cp "$OVERLAY_DIR/dconf-profile-user" "$ROOTFS_MOUNT/etc/dconf/profile/user"echo -e " ${GREEN}Injected dconf kiosk settings${NC}"
# 3. Compile dconf database (run dconf update inside the rootfs via chroot)# We need to compile the local dconf db so GNOME picks it upif [ -x "$ROOTFS_MOUNT/usr/bin/dconf" ]; then # Use a minimal chroot to run dconf compile chroot "$ROOTFS_MOUNT" /usr/bin/dconf compile /etc/dconf/db/local /etc/dconf/db/local.d 2>/dev/null || true echo -e " ${GREEN}Compiled dconf database${NC}"else # Fallback: just place the keyfiles, GNOME will compile at runtime echo -e " ${YELLOW}dconf binary not in rootfs, will compile at boot${NC}"fi
# 4. Disable GNOME initial setup (it would block kiosk boot)mkdir -p "$ROOTFS_MOUNT/home/liveuser/.config"echo "yes" > "$ROOTFS_MOUNT/home/liveuser/.config/gnome-initial-setup-done"chown 1000:1000 "$ROOTFS_MOUNT/home/liveuser/.config/gnome-initial-setup-done"echo -e " ${GREEN}Disabled GNOME initial setup${NC}"
# 5. Create a systemd service to disable screen blanking at runtimecat > "$ROOTFS_MOUNT/etc/systemd/system/disable-blanking.service" << 'SVCEOF'[Unit]Description=Disable screen blanking for kioskAfter=graphical.target
[Service]Type=oneshotExecStart=/usr/bin/bash -c 'DISPLAY=:0 xset s off; DISPLAY=:0 xset -dpms; DISPLAY=:0 xset s noblank'ExecStart=/usr/bin/bash -c 'dbus-send --system --print-reply --dest=org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager.SetWallMessage string:"" boolean:false 2>/dev/null || true'
[Install]WantedBy=graphical.targetSVCEOF
# Enable it via symlinkmkdir -p "$ROOTFS_MOUNT/etc/systemd/system/graphical.target.wants"ln -sf /etc/systemd/system/disable-blanking.service "$ROOTFS_MOUNT/etc/systemd/system/graphical.target.wants/disable-blanking.service"echo -e " ${GREEN}Created disable-blanking service${NC}"
# ── Unmount rootfs and repack squashfs ──echo -e " Unmounting rootfs..."umount "$ROOTFS_MOUNT"rmdir "$ROOTFS_MOUNT"
echo -e " Repacking squashfs (this takes a few minutes)..."rm -f "$WORK_DIR/squashfs-new.img"mksquashfs "$WORK_DIR/squashfs-root" "$WORK_DIR/squashfs-new.img" -comp xz -b 1M -Xdict-size 100%echo -e " ${GREEN}Squashfs repacked${NC}"
# ══════════════════════════════════════════# Step 5: Replace squashfs on USB# ══════════════════════════════════════════echo -e "${CYAN}[5/7] Replacing squashfs on USB...${NC}"
# Remount live partition read-writeLIVE_MOUNT=$(mktemp -d /tmp/fedac-live-XXXX)mount "$LIVE_PART" "$LIVE_MOUNT"
# Check spaceNEW_SIZE=$(stat -c%s "$WORK_DIR/squashfs-new.img")OLD_SIZE=$(stat -c%s "$LIVE_MOUNT/LiveOS/squashfs.img")echo -e " Old squashfs: $(numfmt --to=iec $OLD_SIZE)"echo -e " New squashfs: $(numfmt --to=iec $NEW_SIZE)"
# Replacecp "$WORK_DIR/squashfs-new.img" "$LIVE_MOUNT/LiveOS/squashfs.img"syncecho -e " ${GREEN}Squashfs replaced on USB${NC}"
umount "$LIVE_MOUNT"rmdir "$LIVE_MOUNT"LIVE_MOUNT=""
# Clean up work direcho -e " Cleaning up work dir..."rm -rf "$WORK_DIR"
# ══════════════════════════════════════════# Step 6: Patch EFI partition# ══════════════════════════════════════════echo -e "${CYAN}[6/7] Patching EFI partition...${NC}"
EFI_PART=""for part in "${DEVICE}2" "${DEVICE}p2"; do if [ -b "$part" ]; then EFI_PART="$part" break fidone
if [ -z "$EFI_PART" ]; then echo -e "${YELLOW}Could not find EFI partition — skipping GRUB patch${NC}"else EFI_MOUNT=$(mktemp -d /tmp/fedac-efi-XXXX) mount "$EFI_PART" "$EFI_MOUNT"
# Install GRUB theme THEME_SRC="$FEDAC_DIR/grub-theme" THEME_DST="$EFI_MOUNT/EFI/BOOT/fedac-theme" mkdir -p "$THEME_DST"
for asset in theme.txt background.png DejaVuSansBold36.pf2 DejaVuSans18.pf2 DejaVuSans10.pf2 select_c.png menu_c.png; do if [ -f "$THEME_SRC/$asset" ]; then cp "$THEME_SRC/$asset" "$THEME_DST/" fi done
# Generate theme assets if missing NEED_GENERATE=false for asset in background.png DejaVuSansBold36.pf2 DejaVuSans18.pf2 DejaVuSans10.pf2; do [ ! -f "$THEME_DST/$asset" ] && NEED_GENERATE=true done
if [ "$NEED_GENERATE" = true ] && [ -x "$THEME_SRC/prepare-theme.sh" ]; then echo -e " Generating theme assets..." bash "$THEME_SRC/prepare-theme.sh" 2>/dev/null || true for asset in background.png DejaVuSansBold36.pf2 DejaVuSans18.pf2 DejaVuSans10.pf2 select_c.png menu_c.png; do [ -f "$THEME_SRC/$asset" ] && cp "$THEME_SRC/$asset" "$THEME_DST/" done fi echo -e " ${GREEN}Theme installed${NC}"
# Write kiosk GRUB config — instant boot, no menu choices GRUB_CFG="" for candidate in \ "$EFI_MOUNT/EFI/BOOT/grub.cfg" \ "$EFI_MOUNT/EFI/fedora/grub.cfg" \ "$EFI_MOUNT/boot/grub2/grub.cfg"; do if [ -f "$candidate" ]; then GRUB_CFG="$candidate" break fi done
if [ -n "$GRUB_CFG" ]; then cp "$GRUB_CFG" "${GRUB_CFG}.orig"
cat > "$GRUB_CFG" << 'GRUBEOF'# FedAC Kiosk — Live boot to Firefox fullscreen# Auto-generated by fedac/scripts/make-kiosk-usb.sh
set default=0set timeout=0
# ── Graphics modules ──if [ "$grub_platform" == "efi" ]; then insmod efi_gop insmod efi_ugafiinsmod all_videoinsmod gzioinsmod part_gptinsmod ext2insmod pnginsmod font
# ── Save EFI partition root before search changes it ──set efi_root=$root
# ── Load fonts from EFI partition ──loadfont ($efi_root)/EFI/BOOT/fedac-theme/DejaVuSansBold36.pf2loadfont ($efi_root)/EFI/BOOT/fedac-theme/DejaVuSans18.pf2loadfont ($efi_root)/EFI/BOOT/fedac-theme/DejaVuSans10.pf2
# ── Switch to graphical terminal ──set gfxmode=autoset gfxpayload=keepterminal_input consoleterminal_output gfxterm
# ── Load theme from EFI partition ──if [ -f ($efi_root)/EFI/BOOT/fedac-theme/theme.txt ]; then set theme=($efi_root)/EFI/BOOT/fedac-theme/theme.txtelse set color_normal=magenta/black set color_highlight=white/magentafi
# ── Find Fedora live partition (changes $root) ──search --file --set=root /boot/0x4da30161
menuentry "FedAC Kiosk" --class fedora { linux ($root)/boot/x86_64/loader/linux quiet rhgb root=live:CDLABEL=FEDAC_CDLABEL rd.live.image initrd ($root)/boot/x86_64/loader/initrd}GRUBEOF
sed -i "s/FEDAC_CDLABEL/${CDLABEL}/g" "$GRUB_CFG" echo -e " ${GREEN}GRUB patched — instant kiosk boot (0s timeout)${NC}" else echo -e " ${YELLOW}No grub.cfg found on EFI — skipping${NC}" fi
sync umount "$EFI_MOUNT" rmdir "$EFI_MOUNT" EFI_MOUNT=""fi
# ══════════════════════════════════════════# Step 7: Finalize# ══════════════════════════════════════════echo -e "${CYAN}[7/7] Finalizing...${NC}"sync
if [ "$DO_EJECT" = true ]; then eject "$DEVICE" 2>/dev/null || true echo -e " ${GREEN}Ejected${NC}"fi
echo ""echo -e "${GREEN}╔══════════════════════════════════════════╗${NC}"echo -e "${GREEN}║ FedAC Kiosk USB Ready ║${NC}"echo -e "${GREEN}╚══════════════════════════════════════════╝${NC}"echo ""echo -e "Boot flow:"echo -e " Power on → GRUB (instant) → Fedora live → GNOME auto-login"echo -e " → ${PURPLE}Firefox fullscreen → kidlisp.com${NC}"echo ""echo "Plug into target machine → boot from USB → done."