feat: generic user, dynamic paths, simplified ISO build pipeline

This commit is contained in:
2026-05-23 14:26:25 +00:00
parent 312db58775
commit cb5bf7ff94
5 changed files with 319 additions and 260 deletions
+109 -104
View File
@@ -1,119 +1,124 @@
#!/bin/bash
set -e
# Build SeniorNet Kiosk ISO
# Run on workstation: ./build-iso.sh
# Requires: debian-live-build, sudo
echo "==> SeniorNet Kiosk ISO Builder"
echo
# SeniorNet Kiosk ISO Builder
# Takes the official Debian Trixie netinstall ISO and repacks it with:
# - preseed.cfg embedded for silent auto-install
# - GRUB + isolinux configured for auto-boot (UEFI + BIOS)
#
# The kiosk app itself is NOT bundled — it's downloaded from Gitea at
# first-boot time. Rebuild the ISO only when changing Debian base or preseed.
#
# Run: sudo ./build-iso.sh
# Output: iso-output/seniornet-kiosk.iso
if [ "$EUID" -ne 0 ]; then
echo "ERROR: Run as root (sudo ./build-iso.sh)"
exit 1
echo "ERROR: Run as root: sudo ./build-iso.sh"; exit 1
fi
# Check dependencies
if ! command -v lb &>/dev/null; then
echo "==> Installing debian-live-build..."
apt-get update
apt-get install -y debian-live-build
fi
BUILD_DIR="/tmp/kiosk-build-$$"
OUTPUT_DIR="$(pwd)/iso-output"
REPO_DIR="$(cd "$(dirname "$0")" && pwd)"
OUTPUT_DIR="$REPO_DIR/iso-output"
WORK_DIR="$(mktemp -d /tmp/kiosk-iso-XXXX)"
trap 'rm -rf "$WORK_DIR"' EXIT
mkdir -p "$BUILD_DIR" "$OUTPUT_DIR"
cd "$BUILD_DIR"
DEBIAN_ISO_URL="https://cdimage.debian.org/cdimage/daily-builds/daily/arch-latest/amd64/iso-cd/debian-testing-amd64-netinst.iso"
ISO_CACHE="$OUTPUT_DIR/debian-netinst.iso"
OUTPUT_ISO="$OUTPUT_DIR/seniornet-kiosk.iso"
echo "==> Initializing live-build..."
lb config \
--distribution trixie \
--architectures amd64 \
--image-type iso-hybrid \
--bootappend-live "boot=live components autologin username=root quiet splash" \
--bootappend-install "preseed/file=/preseed.cfg auto=true priority=critical" \
--linux-packages "linux-image-amd64" \
--parent-mirror-bootstrap "https://deb.debian.org/debian" \
--parent-mirror-binary "https://deb.debian.org/debian" \
--parent-mirror-binary-security "https://security.debian.org/debian-security" \
--parent-distribution-binary-security trixie-security
mkdir -p "$OUTPUT_DIR"
echo "==> Adding packages..."
mkdir -p config/package-lists
cat > config/package-lists/kiosk.list.chroot << 'PKGLIST'
# Base system
openssh-server
build-essential
git
curl
wget
sudo
# Display and window manager
xserver-xorg
xserver-xorg-video-dummy
xinit
openbox
xvfb
xdotool
xprop
# Chromium browser
chromium
# Python and kiosk app
python3
python3-pip
sqlite3
PKGLIST
echo "==> Adding preseed file..."
mkdir -p config/includes.installer
cp "$REPO_DIR/preseed.cfg" config/includes.installer/
echo "==> Adding hook script..."
mkdir -p config/hooks/normal
cat > config/hooks/normal/9999-kiosk-postinstall.chroot << 'HOOK'
#!/bin/bash
set -e
echo "==> Running kiosk post-install hook..."
# Install Python packages
pip3 install --break-system-packages PyQt5 websocket-client
# Clone repo
if [ ! -d /home/jgitta/kiosk-browser ]; then
git clone https://gitea.jgitta.com/jgitta/senior-kiosk.git /home/jgitta/kiosk-browser
cd /home/jgitta/kiosk-browser
bash install-kiosk.sh
# ── Dependencies ───────────────────────────────────────────────────
echo "==> Checking dependencies..."
MISSING=""
for pkg in xorriso isolinux curl; do
dpkg -l "$pkg" &>/dev/null || MISSING="$MISSING $pkg"
done
if [ -n "$MISSING" ]; then
apt-get install -y $MISSING
fi
echo "==> Kiosk post-install complete"
HOOK
chmod +x config/hooks/normal/9999-kiosk-postinstall.chroot
echo "==> Building ISO (this may take 5-10 minutes)..."
lb build 2>&1 | tail -20
ISO_FILE="live-image-amd64.hybrid.iso"
if [ -f "$ISO_FILE" ]; then
cp "$ISO_FILE" "$OUTPUT_DIR/seniornet-kiosk.iso"
echo
echo "==> ✓ ISO build complete!"
echo " Output: $OUTPUT_DIR/seniornet-kiosk.iso"
echo
echo "Next steps:"
echo " 1. Write to USB:"
echo " sudo dd if=$OUTPUT_DIR/seniornet-kiosk.iso of=/dev/sdX bs=4M status=progress && sync"
echo
echo " 2. Boot from USB and wait ~10 minutes for silent installation"
echo
echo " 3. Machine will reboot into kiosk mode automatically"
echo
# ── Download Debian netinstall ISO (cached) ────────────────────────
if [ -f "$ISO_CACHE" ]; then
echo "==> Using cached Debian ISO: $ISO_CACHE"
else
echo "ERROR: ISO build failed"
exit 1
echo "==> Downloading Debian Trixie netinstall (~700 MB)..."
curl -L --progress-bar "$DEBIAN_ISO_URL" -o "$ISO_CACHE"
fi
# ── Extract ISO ────────────────────────────────────────────────────
echo "==> Extracting ISO..."
mkdir -p "$WORK_DIR/iso"
xorriso -osirrox on -indev "$ISO_CACHE" -extract / "$WORK_DIR/iso" 2>/dev/null
chmod -R u+w "$WORK_DIR/iso"
# ── Add preseed to ISO root ────────────────────────────────────────
# Accessible during install as /cdrom/preseed.cfg
cp "$REPO_DIR/preseed.cfg" "$WORK_DIR/iso/preseed.cfg"
# ── Auto-boot: GRUB (UEFI) ────────────────────────────────────────
echo "==> Configuring auto-boot..."
cat > "$WORK_DIR/iso/boot/grub/grub.cfg" << 'GRUBEOF'
set default=0
set timeout=5
menuentry "SeniorNet Kiosk — Automatic Install" {
linux /install.amd/vmlinuz preseed/file=/cdrom/preseed.cfg auto=true priority=critical quiet ---
initrd /install.amd/initrd.gz
}
menuentry "SeniorNet Kiosk — Install (verbose)" {
linux /install.amd/vmlinuz preseed/file=/cdrom/preseed.cfg auto=true priority=critical ---
initrd /install.amd/initrd.gz
}
GRUBEOF
# ── Auto-boot: isolinux (BIOS legacy) ─────────────────────────────
if [ -f "$WORK_DIR/iso/isolinux/isolinux.cfg" ]; then
cat > "$WORK_DIR/iso/isolinux/isolinux.cfg" << 'ISOEOF'
default install
timeout 50
label install
menu label SeniorNet Kiosk - Automatic Install
kernel /install.amd/vmlinuz
append initrd=/install.amd/initrd.gz preseed/file=/cdrom/preseed.cfg auto=true priority=critical quiet ---
label verbose
menu label SeniorNet Kiosk - Install (verbose)
kernel /install.amd/vmlinuz
append initrd=/install.amd/initrd.gz preseed/file=/cdrom/preseed.cfg auto=true priority=critical ---
ISOEOF
fi
# ── Repack ISO (UEFI + BIOS hybrid) ───────────────────────────────
echo "==> Building final ISO..."
cd "$WORK_DIR/iso"
xorriso -as mkisofs \
-r -J -joliet-long \
-V "SeniorNet Kiosk" \
--grub2-mbr boot/grub/i386-pc/boot_hybrid.img \
-partition_offset 16 \
--mbr-force-bootable \
-append_partition 2 28732ac11ff8d211ba4b00a0c93ec93b boot/grub/efi.img \
-appended_part_as_gpt \
-iso_mbr_part_type a2a0d0ebe5b9334487c068b6b72699c7 \
-c '/boot/boot.cat' \
-b '/boot/grub/i386-pc/eltorito.img' \
-no-emul-boot -boot-load-size 4 -boot-info-table --grub2-boot-info \
-eltorito-alt-boot \
-e '--interval:appended_partition_2:::' \
-no-emul-boot \
-o "$OUTPUT_ISO" \
. 2>&1 | tail -5
echo
SIZE=$(du -sh "$OUTPUT_ISO" | cut -f1)
echo "==> ✓ ISO complete: $OUTPUT_ISO ($SIZE)"
echo
echo "Write to USB:"
echo " sudo dd if=\"$OUTPUT_ISO\" of=/dev/sdX bs=4M status=progress && sync"
echo
echo "Boot from USB — Debian installs silently (~10 min) then reboots."
echo "On first reboot: setup wizard prompts for username and senior's name."
echo "Second reboot: kiosk is running."