From 27fbde2a765b4e9ceb364438af16b8bd02864e6d Mon Sep 17 00:00:00 2001 From: "info@data-pro.nu" Date: Tue, 8 Sep 2026 17:59:24 +0200 Subject: [PATCH] Working in bootmenu --- build-kiosk-iso-v10.sh | 1300 ++++++++++++++++++++++++++++++++++++++++ build-kiosk-iso-v9.sh | 1300 ++++++++++++++++++++++++++++++++++++++++ preseed.cfg | 169 ++++-- 3 files changed, 2726 insertions(+), 43 deletions(-) create mode 100755 build-kiosk-iso-v10.sh create mode 100755 build-kiosk-iso-v9.sh diff --git a/build-kiosk-iso-v10.sh b/build-kiosk-iso-v10.sh new file mode 100755 index 0000000..4855f91 --- /dev/null +++ b/build-kiosk-iso-v10.sh @@ -0,0 +1,1300 @@ +#!/usr/bin/env bash +set -euo pipefail +set -o pipefail + +############################################################################### +# Linux Mint 22.3 Aamsveen Audio Kiosk ISO builder +# +# VERSION: v10 +# +# Host: +# NixOS 26.11 unstable +# +# Guest: +# Linux Mint 22.3 Cinnamon 64-bit +# +# BOOT DESIGN +# +# BIOS: +# ISO +# -> ISOLINUX +# -> /isolinux/live.cfg +# -> /casper/vmlinuz +# -> casper +# -> Ubiquity +# +# UEFI: +# ISO +# -> /boot/grub/efi.img +# -> ORIGINAL Mint EFI GRUB loader +# -> ISO /boot/grub/grub.cfg +# -> /casper/vmlinuz +# -> casper +# -> Ubiquity +# +# CRITICAL: +# +# boot/grub/efi.img is NEVER modified. +# +# The custom UEFI menu exists ONLY in: +# +# /boot/grub/grub.cfg +# +# The custom BIOS menu exists in: +# +# /isolinux/live.cfg +# +# xorriso creates the hybrid ISO directly. +# isohybrid is NOT run afterwards. +############################################################################### + +############################################################################### +# Configuration +############################################################################### + +BASE_ISO_FILENAME="linuxmint-22.3-cinnamon-64bit.iso" + +NEW_ISO_FILENAME="non-aamsveen-audio-kiosk_v10.iso" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +ISO_PATH="$SCRIPT_DIR/$BASE_ISO_FILENAME" +SCRIPT_PATH="$SCRIPT_DIR/install-kiosk-nl.sh" +PRESEED_PATH="$SCRIPT_DIR/preseed.cfg" + +WORK_DIR="$SCRIPT_DIR/build-aamsveen" + +ISO_ROOT="$WORK_DIR/iso" +SQUASHFS_DIR="$WORK_DIR/squashfs-root" + +NEW_ISO_PATH="$SCRIPT_DIR/$NEW_ISO_FILENAME" + +############################################################################### +# Helpers +############################################################################### + +die() { + echo + echo "ERROR: $*" >&2 + exit 1 +} + +log() { + echo + echo "============================================================" + echo "$*" + echo "============================================================" +} + +require_command() { + command -v "$1" >/dev/null 2>&1 \ + || die "Required command not found: $1" +} + +############################################################################### +# Mount cleanup +# +# Previous builds can leave efi.img loop mounts behind. +# +# IMPORTANT: +# +# We unmount deepest paths first, then remove the build directory. +############################################################################### + +cleanup_work_mounts() { + if [[ ! -d "$WORK_DIR" ]]; then + return 0 + fi + + while read -r MOUNTPOINT; do + [[ -n "$MOUNTPOINT" ]] || continue + + echo "Unmount: $MOUNTPOINT" + + sudo umount "$MOUNTPOINT" 2>/dev/null || \ + sudo umount -l "$MOUNTPOINT" 2>/dev/null || true + + done < <( + findmnt -rn -o TARGET 2>/dev/null | + grep -F "$WORK_DIR/" | + awk '{ print length($0), $0 }' | + sort -rn | + cut -d' ' -f2- + ) +} + +############################################################################### +# Dependency check +# +# NixOS: +# +# nix shell nixpkgs#xorriso nixpkgs#squashfsTools +############################################################################### + +log "Controleer benodigde programma's" + +for cmd in \ + xorriso \ + unsquashfs \ + mksquashfs \ + find \ + sed \ + awk \ + stat \ + mount \ + umount \ + dd \ + cmp \ + grep \ + sudo \ + mountpoint \ + sort \ + cut +do + require_command "$cmd" +done + +############################################################################### +# Input validation +############################################################################### + +log "Controleer invoerbestanden" + +[[ -f "$ISO_PATH" ]] \ + || die "Basis-ISO niet gevonden: $ISO_PATH" + +[[ -f "$SCRIPT_PATH" ]] \ + || die "Installatiescript niet gevonden: $SCRIPT_PATH" + +[[ -f "$PRESEED_PATH" ]] \ + || die "Preseed niet gevonden: $PRESEED_PATH" + +echo "Basis ISO : $ISO_PATH" +echo "Preseed : $PRESEED_PATH" +echo "Installer : $SCRIPT_PATH" +echo "Output : $NEW_ISO_PATH" + +############################################################################### +# Basic file information +############################################################################### + +log "Controleer basis-ISO" + +ORIGINAL_ISO_SIZE="$(stat -c%s "$ISO_PATH")" + +echo "Originele ISO:" +echo " $ISO_PATH" + +echo +echo "Grootte:" +echo " $ORIGINAL_ISO_SIZE bytes" + +############################################################################### +# Remove old build directory safely +############################################################################### + +log "Verwijder oude werkmap" + +cleanup_work_mounts + +rm -rf "$WORK_DIR" + +mkdir -p "$WORK_DIR" + +############################################################################### +# Remove old output ISO +############################################################################### + +if [[ -f "$NEW_ISO_PATH" ]]; then + log "Verwijder oude output ISO" + rm -f "$NEW_ISO_PATH" +fi + +############################################################################### +# Preserve ORIGINAL Mint MBR boot code +# +# Only the first 432 bytes are reused. +# +# xorriso generates the partition structures. +############################################################################### + +log "Bewaar originele Mint MBR bootcode" + +ORIGINAL_MBR="$WORK_DIR/mint-isohybrid-mbr.bin" + +dd \ + if="$ISO_PATH" \ + of="$ORIGINAL_MBR" \ + bs=432 \ + count=1 \ + status=none + +[[ "$(stat -c%s "$ORIGINAL_MBR")" -eq 432 ]] \ + || die "Originele MBR bootcode heeft geen 432 bytes." + +############################################################################### +# Inspect original ISO boot structure +############################################################################### + +log "Controleer originele El Torito bootinformatie" + +xorriso \ + -indev "$ISO_PATH" \ + -report_el_torito plain + +log "Controleer originele system area" + +xorriso \ + -indev "$ISO_PATH" \ + -report_system_area plain + +############################################################################### +# Extract ISO +############################################################################### + +log "Pak Linux Mint ISO uit" + +mkdir -p "$ISO_ROOT" + +xorriso \ + -osirrox on \ + -indev "$ISO_PATH" \ + -extract / "$ISO_ROOT" + +############################################################################### +# Verify required ISO structure +############################################################################### + +log "Controleer ISO-structuur" + +[[ -d "$ISO_ROOT/casper" ]] \ + || die "casper directory ontbreekt." + +[[ -f "$ISO_ROOT/casper/vmlinuz" ]] \ + || die "casper/vmlinuz ontbreekt." + +[[ -d "$ISO_ROOT/isolinux" ]] \ + || die "isolinux directory ontbreekt." + +[[ -f "$ISO_ROOT/isolinux/isolinux.bin" ]] \ + || die "isolinux/isolinux.bin ontbreekt." + +[[ -f "$ISO_ROOT/isolinux/boot.cat" ]] \ + || die "isolinux/boot.cat ontbreekt." + +[[ -f "$ISO_ROOT/isolinux/live.cfg" ]] \ + || die "isolinux/live.cfg ontbreekt." + +[[ -d "$ISO_ROOT/boot/grub" ]] \ + || die "boot/grub ontbreekt." + +[[ -f "$ISO_ROOT/boot/grub/efi.img" ]] \ + || die "boot/grub/efi.img ontbreekt." + +[[ -f "$ISO_ROOT/boot/grub/grub.cfg" ]] \ + || die "boot/grub/grub.cfg ontbreekt." + +############################################################################### +# Preserve original efi.img for byte-for-byte verification +############################################################################### + +log "Bewaar originele EFI image" + +ORIGINAL_EFI_IMG="$WORK_DIR/original-efi.img" + +cp \ + "$ISO_ROOT/boot/grub/efi.img" \ + "$ORIGINAL_EFI_IMG" + +############################################################################### +# Locate filesystem.squashfs +############################################################################### + +log "Zoek filesystem.squashfs" + +SQUASHFS_FILE="$( + find "$ISO_ROOT" \ + -type f \ + -name "filesystem.squashfs" \ + -print \ + -quit +)" + +[[ -n "$SQUASHFS_FILE" ]] \ + || die "filesystem.squashfs niet gevonden." + +echo "Squashfs:" +echo " $SQUASHFS_FILE" + +############################################################################### +# Detect initrd +############################################################################### + +log "Detecteer initrd" + +INITRD_FILE="$( + find "$ISO_ROOT/casper" \ + -maxdepth 1 \ + -type f \ + -iname "initrd*" \ + -print \ + -quit +)" + +[[ -n "$INITRD_FILE" ]] \ + || die "Geen initrd gevonden." + +ACTUAL_INITRD_NAME="$(basename "$INITRD_FILE")" + +echo "Initrd:" +echo " $ACTUAL_INITRD_NAME" + +############################################################################### +# Unpack squashfs +############################################################################### + +log "Pak squashfs uit" + +mkdir -p "$SQUASHFS_DIR" + +unsquashfs \ + -f \ + -d "$SQUASHFS_DIR" \ + "$SQUASHFS_FILE" + +############################################################################### +# Install preseed into ISO +############################################################################### + +log "Plaats preseed op ISO" + +PRESEED_ISO_DIR="$ISO_ROOT/preseed" +PRESEED_ISO_PATH="$PRESEED_ISO_DIR/preseed.cfg" + +mkdir -p "$PRESEED_ISO_DIR" + +cp \ + "$PRESEED_PATH" \ + "$PRESEED_ISO_PATH" + +chmod 644 \ + "$PRESEED_ISO_PATH" + +############################################################################### +# Install preseed into live filesystem +############################################################################### + +log "Plaats preseed in live filesystem" + +cp \ + "$PRESEED_PATH" \ + "$SQUASHFS_DIR/preseed.cfg" + +chmod 644 \ + "$SQUASHFS_DIR/preseed.cfg" + +############################################################################### +# Copy installer script into live filesystem +############################################################################### + +log "Plaats install-kiosk-nl.sh in live filesystem" + +INSTALL_SCRIPT_DEST="$SQUASHFS_DIR/usr/local/bin/install-kiosk-nl.sh" + +mkdir -p \ + "$(dirname "$INSTALL_SCRIPT_DEST")" + +cp \ + "$SCRIPT_PATH" \ + "$INSTALL_SCRIPT_DEST" + +chmod +x \ + "$INSTALL_SCRIPT_DEST" + +############################################################################### +# Keep installer script in /home/av-admin +############################################################################### + +log "Plaats install-kiosk-nl.sh in /home/av-admin" + +ADMIN_HOME="$SQUASHFS_DIR/home/av-admin" + +mkdir -p "$ADMIN_HOME" + +cp \ + "$SCRIPT_PATH" \ + "$ADMIN_HOME/install-kiosk-nl.sh" + +chmod +x \ + "$ADMIN_HOME/install-kiosk-nl.sh" + +############################################################################### +# Create dedicated Ubiquity launcher wrapper +# +# This avoids fragile nested quoting in Exec=. +############################################################################### + +log "Maak Ubiquity installer wrapper" + +INSTALLER_WRAPPER="$SQUASHFS_DIR/usr/local/bin/aamsveen-start-installer.sh" + +mkdir -p \ + "$(dirname "$INSTALLER_WRAPPER")" + +cat > "$INSTALLER_WRAPPER" << 'EOF' +#!/bin/sh +set -e + +sudo debconf-set-selections /preseed.cfg + +exec sudo env \ + DEBIAN_FRONTEND=noninteractive \ + ubiquity \ + --automatic +EOF + +chmod 755 \ + "$INSTALLER_WRAPPER" + +############################################################################### +# Disable Mint Welcome +############################################################################### + +log "Schakel mintwelcome uit" + +MINT_WELCOME="$SQUASHFS_DIR/etc/xdg/autostart/mintwelcome.desktop" + +if [[ -f "$MINT_WELCOME" ]]; then + mv \ + "$MINT_WELCOME" \ + "$MINT_WELCOME.bak" +fi + +############################################################################### +# Remove normal Ubiquity launcher +############################################################################### + +log "Verwijder standaard Ubiquity launcher" + +UBIQUITY_DESKTOP="$SQUASHFS_DIR/usr/share/applications/ubiquity.desktop" + +if [[ -f "$UBIQUITY_DESKTOP" ]]; then + rm -f "$UBIQUITY_DESKTOP" +fi + +############################################################################### +# Create custom desktop installer launcher +############################################################################### + +log "Maak aangepaste Ubiquity desktop launcher" + +CUSTOM_DESKTOP_ENTRY="$SQUASHFS_DIR/usr/share/applications/install-kiosk.desktop" + +mkdir -p \ + "$(dirname "$CUSTOM_DESKTOP_ENTRY")" + +cat > "$CUSTOM_DESKTOP_ENTRY" << 'EOF' +[Desktop Entry] +Name=Installeer Audio Kiosk voor Aamsveen +Comment=Installeer Linux Mint met Audio Kiosk voor Aamsveen +Exec=/usr/local/bin/aamsveen-start-installer.sh +Icon=mintubiquity +Terminal=false +Type=Application +Categories=System; +EOF + +chmod 644 \ + "$CUSTOM_DESKTOP_ENTRY" + +############################################################################### +# Replace Mint desktop installer shortcut +############################################################################### + +log "Maak aangepaste desktop installer shortcut" + +MINT_DESKTOP_DIR="$SQUASHFS_DIR/home/mint/Desktop" +MINT_DESKTOP_ENTRY="$MINT_DESKTOP_DIR/install.desktop" + +mkdir -p "$MINT_DESKTOP_DIR" + +rm -f "$MINT_DESKTOP_ENTRY" + +cp \ + "$CUSTOM_DESKTOP_ENTRY" \ + "$MINT_DESKTOP_ENTRY" + +chmod +x \ + "$MINT_DESKTOP_ENTRY" + +############################################################################### +# Desktop database +############################################################################### + +if command -v update-desktop-database >/dev/null 2>&1; then + update-desktop-database \ + "$SQUASHFS_DIR/usr/share/applications/" \ + 2>/dev/null || true +fi + +############################################################################### +# UEFI GRUB +# +# DO NOT MODIFY efi.img. +# +# Verified original Mint EFI loader: +# +# search --set=root --file /.disk/info +# set prefix=($root)/boot/grub +# configfile ($root)/boot/grub/grub.cfg +# +# Therefore the actual UEFI menu is the ISO-level: +# +# /boot/grub/grub.cfg +############################################################################### + +log "Maak UEFI GRUB bootmenu" + +GRUB_CFG="$ISO_ROOT/boot/grub/grub.cfg" + +cat > "$GRUB_CFG" << EOF +loadfont unicode + +set color_normal=dark-green/light-gray +set color_highlight=light-gray/dark-green + +set default=1 +set timeout=5 + +menuentry "Start Linux Mint 22.3 Cinnamon 64-bit" --class linuxmint { + set gfxpayload=keep + linux /casper/vmlinuz boot=casper uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint iso-scan/filename=\${iso_path} quiet splash -- + initrd /casper/${ACTUAL_INITRD_NAME} +} + +menuentry "Unattended Install Aamsveen Kiosk" --class linuxmint { + set gfxpayload=keep + linux /casper/vmlinuz boot=casper uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint iso-scan/filename=\${iso_path} automatic-ubiquity noprompt file=/cdrom/preseed/preseed.cfg priority=critical quiet splash -- + initrd /casper/${ACTUAL_INITRD_NAME} +} + +menuentry "Start Linux Mint 22.3 Cinnamon 64-bit (compatibility mode)" { + set gfxpayload=keep + linux /casper/vmlinuz boot=casper uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint iso-scan/filename=\${iso_path} noapic noacpi nosplash irqpoll nomodeset -- + initrd /casper/${ACTUAL_INITRD_NAME} +} + +menuentry "OEM install (for manufacturers)" { + set gfxpayload=keep + linux /casper/vmlinuz oem-config/enable=true only-ubiquity boot=casper uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint iso-scan/filename=\${iso_path} quiet splash -- + initrd /casper/${ACTUAL_INITRD_NAME} +} + +if [ "\$grub_platform" = "efi" ]; then + + menuentry "Boot from next volume" { + exit 1 + } + + menuentry "UEFI Firmware Settings" { + fwsetup + } + + if [ -f /boot/memtest.efi ]; then + menuentry "Memory test" { + linux /boot/memtest.efi + } + fi + +fi +EOF + +############################################################################### +# Verify UEFI GRUB source configuration +############################################################################### + +log "Controleer UEFI GRUB" + +grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + "$GRUB_CFG" \ + || die "UEFI unattended entry ontbreekt." + +grep -q \ + 'automatic-ubiquity' \ + "$GRUB_CFG" \ + || die "UEFI automatic-ubiquity ontbreekt." + +grep -q \ + 'noprompt' \ + "$GRUB_CFG" \ + || die "UEFI noprompt ontbreekt." + +grep -q \ + 'file=/cdrom/preseed/preseed.cfg' \ + "$GRUB_CFG" \ + || die "UEFI preseed path ontbreekt." + +grep -q \ + 'iso-scan/filename=${iso_path}' \ + "$GRUB_CFG" \ + || die "UEFI iso-scan/filename ontbreekt." + +grep -q \ + 'set default=1' \ + "$GRUB_CFG" \ + || die "UEFI unattended entry is niet default." + +grep -q \ + 'set timeout=5' \ + "$GRUB_CFG" \ + || die "UEFI timeout=5 ontbreekt." + +############################################################################### +# Verify original EFI image BEFORE ISO creation +############################################################################### + +log "Controleer originele EFI loader" + +EFI_IMG="$ISO_ROOT/boot/grub/efi.img" + +EFI_MOUNT="$WORK_DIR/efi_mount" + +mkdir -p "$EFI_MOUNT" + +EFI_MOUNTED=0 + +cleanup_efi() { + if [[ "$EFI_MOUNTED" -eq 1 ]]; then + sudo umount "$EFI_MOUNT" 2>/dev/null || \ + sudo umount -l "$EFI_MOUNT" 2>/dev/null || true + + EFI_MOUNTED=0 + fi +} + +trap cleanup_efi EXIT + +sudo mount \ + -o loop,ro \ + "$EFI_IMG" \ + "$EFI_MOUNT" + +EFI_MOUNTED=1 + +EFI_GRUB_CFG="$( + sudo find "$EFI_MOUNT" \ + -type f \ + -name "grub.cfg" \ + -print \ + -quit +)" + +[[ -n "$EFI_GRUB_CFG" ]] \ + || die "Geen grub.cfg gevonden in efi.img." + +EFI_GRUB_CONTENT="$( + sudo cat "$EFI_GRUB_CFG" +)" + +echo "$EFI_GRUB_CONTENT" + +grep -q \ + 'search --set=root --file /.disk/info' \ + <<< "$EFI_GRUB_CONTENT" \ + || die "Originele EFI loader mist /.disk/info search." + +grep -q \ + 'set prefix=($root)/boot/grub' \ + <<< "$EFI_GRUB_CONTENT" \ + || die "Originele EFI loader mist GRUB prefix." + +grep -q \ + 'configfile ($root)/boot/grub/grub.cfg' \ + <<< "$EFI_GRUB_CONTENT" \ + || die "Originele EFI loader mist configfile." + +if grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + <<< "$EFI_GRUB_CONTENT" +then + die "Aamsveen menu staat ten onrechte in efi.img." +fi + +cleanup_efi + +trap - EXIT + +############################################################################### +# BIOS / ISOLINUX +# +# The original Mint ISO uses /isolinux/live.cfg as its visible BIOS menu. +############################################################################### + +log "Maak BIOS/ISOLINUX bootmenu" + +LIVE_CFG_PATH="$ISO_ROOT/isolinux/live.cfg" + +[[ -f "$LIVE_CFG_PATH" ]] \ + || die "isolinux/live.cfg ontbreekt." + +############################################################################### +# Remove any previous Aamsveen unattended block +# +# This removes: +# +# label unattended-install +# ... +# +# until the next "label" or EOF. +############################################################################### + +TMP_LIVE_CFG="$WORK_DIR/live.cfg.tmp" + +awk ' +BEGIN { + skip = 0 +} + +/^[[:space:]]*label[[:space:]]+unattended-install[[:space:]]*$/ { + skip = 1 + next +} + +skip == 1 && /^[[:space:]]*label[[:space:]]+/ { + skip = 0 +} + +skip == 1 { + next +} + +{ + print +} +' "$LIVE_CFG_PATH" > "$TMP_LIVE_CFG" + +mv \ + "$TMP_LIVE_CFG" \ + "$LIVE_CFG_PATH" + +############################################################################### +# Remove old timeout directives +############################################################################### + +sed -i \ + '/^[[:space:]]*timeout[[:space:]]\+[0-9]\+[[:space:]]*$/d' \ + "$LIVE_CFG_PATH" + +############################################################################### +# Make unattended entry the BIOS default +# +# ISOLINUX uses "menu default" in the label block. +############################################################################### + +sed -i \ + '/^[[:space:]]*menu default[[:space:]]*$/d' \ + "$LIVE_CFG_PATH" + +############################################################################### +# Add unattended BIOS entry +############################################################################### + +cat >> "$LIVE_CFG_PATH" << EOF + +# --------------------------------------------------------------------------- +# Aamsveen custom unattended installer +# --------------------------------------------------------------------------- + +label unattended-install + menu label ^Unattended Install Aamsveen Kiosk + menu default + kernel /casper/vmlinuz + append boot=casper automatic-ubiquity noprompt file=/cdrom/preseed/preseed.cfg priority=critical quiet splash -- + initrd /casper/${ACTUAL_INITRD_NAME} + +# Wait indefinitely for user input. +timeout 0 +EOF + +############################################################################### +# Verify BIOS configuration +############################################################################### + +log "Controleer BIOS/ISOLINUX configuratie" + +grep -q \ + '^label unattended-install$' \ + "$LIVE_CFG_PATH" \ + || die "BIOS unattended entry ontbreekt." + +grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + "$LIVE_CFG_PATH" \ + || die "BIOS Aamsveen menu-entry ontbreekt." + +grep -q \ + 'automatic-ubiquity' \ + "$LIVE_CFG_PATH" \ + || die "BIOS automatic-ubiquity ontbreekt." + +grep -q \ + 'noprompt' \ + "$LIVE_CFG_PATH" \ + || die "BIOS noprompt ontbreekt." + +grep -q \ + 'file=/cdrom/preseed/preseed.cfg' \ + "$LIVE_CFG_PATH" \ + || die "BIOS preseed path ontbreekt." + +grep -q \ + '^timeout 0$' \ + "$LIVE_CFG_PATH" \ + || die "BIOS timeout 0 ontbreekt." + +grep -q \ + '^[[:space:]]*menu default[[:space:]]*$' \ + "$LIVE_CFG_PATH" \ + || die "BIOS unattended entry is niet default." + +############################################################################### +# Display boot configurations +############################################################################### + +echo +echo "================ UEFI grub.cfg ================" +cat "$GRUB_CFG" + +echo +echo "================ BIOS live.cfg ================" +cat "$LIVE_CFG_PATH" + +############################################################################### +# Rebuild squashfs +############################################################################### + +log "Verwijder oude filesystem.squashfs" + +rm -f \ + "$SQUASHFS_FILE" + +log "Bouw filesystem.squashfs opnieuw" + +mksquashfs \ + "$SQUASHFS_DIR" \ + "$ISO_ROOT/casper/filesystem.squashfs" \ + -b 256K \ + -comp xz \ + -Xdict-size 100% \ + -no-duplicates \ + -no-xattrs \ + -noappend + +[[ -f "$ISO_ROOT/casper/filesystem.squashfs" ]] \ + || die "Nieuw filesystem.squashfs ontbreekt." + +############################################################################### +# Build ISO +############################################################################### + +log "Bouw nieuwe ISO met xorriso-native hybrid layout" + +cd "$ISO_ROOT" + +xorriso -as mkisofs \ + -r \ + -V "NonAamsveenAudioKiosk" \ + -J \ + -l \ + -isohybrid-mbr "$ORIGINAL_MBR" \ + -partition_cyl_align on \ + -partition_offset 16 \ + -partition_hd_cyl 185 \ + -partition_sec_hd 32 \ + --mbr-force-bootable \ + -apm-block-size 2048 \ + -iso_mbr_part_type 0x00 \ + -c isolinux/boot.cat \ + -b isolinux/isolinux.bin \ + -no-emul-boot \ + -boot-load-size 4 \ + -boot-info-table \ + -eltorito-alt-boot \ + -e boot/grub/efi.img \ + -no-emul-boot \ + -isohybrid-gpt-basdat \ + -isohybrid-apm-hfsplus \ + -o "$NEW_ISO_PATH" \ + . + +############################################################################### +# Verify ISO exists +############################################################################### + +log "Controleer gemaakte ISO" + +[[ -f "$NEW_ISO_PATH" ]] \ + || die "Nieuwe ISO is niet gemaakt." + +NEW_ISO_SIZE="$(stat -c%s "$NEW_ISO_PATH")" + +echo "Originele ISO : $ORIGINAL_ISO_SIZE bytes" +echo "Nieuwe ISO : $NEW_ISO_SIZE bytes" + +if [[ "$NEW_ISO_SIZE" -lt "$((ORIGINAL_ISO_SIZE * 90 / 100))" ]]; then + die "Nieuwe ISO is verdacht klein." +fi + +############################################################################### +# Verify El Torito +############################################################################### + +log "Controleer El Torito" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -report_el_torito plain + +############################################################################### +# Verify hybrid system area +############################################################################### + +log "Controleer hybrid system area" + +SYSTEM_AREA_REPORT="$WORK_DIR/system-area-report.txt" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -report_system_area plain \ + > "$SYSTEM_AREA_REPORT" + +cat "$SYSTEM_AREA_REPORT" + +grep -Eq \ + 'System area summary:.*MBR.*GPT.*APM' \ + "$SYSTEM_AREA_REPORT" \ + || die "MBR/GPT/APM hybrid layout ontbreekt." + +############################################################################### +# Create final ISO verification directory +############################################################################### + +TMP_CHECK_DIR="$WORK_DIR/iso-check" + +mkdir -p "$TMP_CHECK_DIR" + +############################################################################### +# Verify boot files +############################################################################### + +log "Controleer bootbestanden" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -ls \ + /casper/vmlinuz \ + /casper/"$ACTUAL_INITRD_NAME" \ + /boot/grub/efi.img \ + /boot/grub/grub.cfg \ + /isolinux/live.cfg + +############################################################################### +# Verify BIOS config inside FINAL ISO +############################################################################### + +log "Controleer BIOS configuratie in eind-ISO" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /isolinux/live.cfg "$TMP_CHECK_DIR/" + +FINAL_LIVE_CFG="$TMP_CHECK_DIR/live.cfg" + +grep -q \ + '^label unattended-install$' \ + "$FINAL_LIVE_CFG" \ + || die "Finale ISO mist BIOS unattended entry." + +grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + "$FINAL_LIVE_CFG" \ + || die "Finale ISO mist BIOS Aamsveen entry." + +grep -q \ + 'automatic-ubiquity' \ + "$FINAL_LIVE_CFG" \ + || die "Finale ISO mist BIOS automatic-ubiquity." + +grep -q \ + 'noprompt' \ + "$FINAL_LIVE_CFG" \ + || die "Finale ISO mist BIOS noprompt." + +grep -q \ + 'file=/cdrom/preseed/preseed.cfg' \ + "$FINAL_LIVE_CFG" \ + || die "Finale ISO mist BIOS preseed." + +grep -q \ + '^[[:space:]]*menu default[[:space:]]*$' \ + "$FINAL_LIVE_CFG" \ + || die "Finale BIOS unattended entry is niet default." + +############################################################################### +# Verify UEFI config inside FINAL ISO +############################################################################### + +log "Controleer UEFI configuratie in eind-ISO" + +TMP_GRUB_CHECK="$TMP_CHECK_DIR/grub.cfg" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /boot/grub/grub.cfg "$TMP_GRUB_CHECK" + +grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + "$TMP_GRUB_CHECK" \ + || die "Finale ISO mist UEFI unattended entry." + +grep -q \ + 'automatic-ubiquity' \ + "$TMP_GRUB_CHECK" \ + || die "Finale ISO mist UEFI automatic-ubiquity." + +grep -q \ + 'noprompt' \ + "$TMP_GRUB_CHECK" \ + || die "Finale ISO mist UEFI noprompt." + +grep -q \ + 'file=/cdrom/preseed/preseed.cfg' \ + "$TMP_GRUB_CHECK" \ + || die "Finale ISO mist UEFI preseed path." + +grep -q \ + 'iso-scan/filename=${iso_path}' \ + "$TMP_GRUB_CHECK" \ + || die "Finale ISO mist UEFI iso-scan/filename." + +grep -q \ + 'set default=1' \ + "$TMP_GRUB_CHECK" \ + || die "Finale UEFI unattended entry is niet default." + +############################################################################### +# Verify ORIGINAL efi.img remains byte-for-byte identical +############################################################################### + +log "Controleer dat efi.img byte-for-byte origineel is" + +EFI_VERIFY_DIR="$TMP_CHECK_DIR/efi-verify" + +mkdir -p "$EFI_VERIFY_DIR" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /boot/grub/efi.img "$EFI_VERIFY_DIR/" + +FINAL_EFI_IMG="$EFI_VERIFY_DIR/efi.img" + +[[ -f "$FINAL_EFI_IMG" ]] \ + || die "Finale efi.img kon niet uit ISO worden gehaald." + +cmp \ + "$ORIGINAL_EFI_IMG" \ + "$FINAL_EFI_IMG" \ + || die "Finale efi.img verschilt van de originele Mint efi.img." + +echo "efi.img: BYTE-FOR-BYTE IDENTIEK AAN ORIGINEEL" + +############################################################################### +# Mount final efi.img and verify chainloader +############################################################################### + +log "Controleer EFI chainloader in eind-ISO" + +FINAL_EFI_MOUNT="$EFI_VERIFY_DIR/mount" + +mkdir -p "$FINAL_EFI_MOUNT" + +FINAL_EFI_MOUNTED=0 + +cleanup_final_efi() { + if [[ "$FINAL_EFI_MOUNTED" -eq 1 ]]; then + sudo umount "$FINAL_EFI_MOUNT" 2>/dev/null || \ + sudo umount -l "$FINAL_EFI_MOUNT" 2>/dev/null || true + + FINAL_EFI_MOUNTED=0 + fi +} + +trap cleanup_final_efi EXIT + +sudo mount \ + -o loop,ro \ + "$FINAL_EFI_IMG" \ + "$FINAL_EFI_MOUNT" + +FINAL_EFI_MOUNTED=1 + +FINAL_EFI_GRUB_CFG="$( + sudo find "$FINAL_EFI_MOUNT" \ + -type f \ + -name "grub.cfg" \ + -print \ + -quit +)" + +[[ -n "$FINAL_EFI_GRUB_CFG" ]] \ + || die "Geen grub.cfg in finale efi.img." + +FINAL_EFI_CONTENT="$( + sudo cat "$FINAL_EFI_GRUB_CFG" +)" + +echo +echo "================ FINAL EFI grub.cfg ================" +echo "$FINAL_EFI_CONTENT" + +grep -q \ + 'search --set=root --file /.disk/info' \ + <<< "$FINAL_EFI_CONTENT" \ + || die "Finale EFI loader mist Mint search." + +grep -q \ + 'set prefix=($root)/boot/grub' \ + <<< "$FINAL_EFI_CONTENT" \ + || die "Finale EFI loader mist GRUB prefix." + +grep -q \ + 'configfile ($root)/boot/grub/grub.cfg' \ + <<< "$FINAL_EFI_CONTENT" \ + || die "Finale EFI loader mist ISO-level configfile." + +if grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + <<< "$FINAL_EFI_CONTENT" +then + die "Finale efi.img bevat ten onrechte custom Aamsveen menu." +fi + +cleanup_final_efi + +trap - EXIT + +############################################################################### +# Verify preseed in FINAL ISO +############################################################################### + +log "Controleer preseed in eind-ISO" + +TMP_PRESEED_CHECK="$TMP_CHECK_DIR/preseed.cfg" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /preseed/preseed.cfg "$TMP_PRESEED_CHECK" + +[[ -s "$TMP_PRESEED_CHECK" ]] \ + || die "Finale ISO bevat geen geldige preseed." + +############################################################################### +# Verify installer wrapper in rebuilt squashfs +############################################################################### + +[[ -f "$SQUASHFS_DIR/usr/local/bin/aamsveen-start-installer.sh" ]] \ + || die "Installer wrapper ontbreekt." + +[[ -x "$SQUASHFS_DIR/usr/local/bin/aamsveen-start-installer.sh" ]] \ + || die "Installer wrapper is niet executable." + +[[ -f "$SQUASHFS_DIR/usr/local/bin/install-kiosk-nl.sh" ]] \ + || die "install-kiosk-nl.sh ontbreekt." + +[[ -x "$SQUASHFS_DIR/usr/local/bin/install-kiosk-nl.sh" ]] \ + || die "install-kiosk-nl.sh is niet executable." + +############################################################################### +# Final report +############################################################################### + +log "BUILD VOLTOOID" + +echo +echo "ISO:" +echo " $NEW_ISO_PATH" + +echo +echo "UEFI:" +echo " Start Linux Mint" +echo " Unattended Install Aamsveen Kiosk <-- DEFAULT" +echo " Compatibility mode" +echo " OEM" +echo " UEFI Firmware Settings" + +echo +echo "UEFI colors:" +echo " normal = dark-green / light-gray" +echo " highlight = light-gray / dark-green" + +echo +echo "UEFI timeout:" +echo " 5 seconden" + +echo +echo "BIOS:" +echo " Start Linux Mint" +echo " Compatibility mode" +echo " OEM" +echo " Hardware Detection" +echo " Boot from local drive" +echo " Memory test" +echo " Unattended Install Aamsveen Kiosk <-- DEFAULT" + +echo +echo "BIOS timeout:" +echo " 0 = oneindig" + +echo +echo "Installer:" +echo " automatic-ubiquity" +echo " noprompt" +echo " file=/cdrom/preseed/preseed.cfg" +echo " priority=critical" + +echo +echo "EFI image:" +echo " ORIGINAL" +echo " byte-for-byte verified" + +echo +echo "Hybrid ISO:" +echo " MBR + GPT + APM" +echo " xorriso native" +echo " GEEN isohybrid post-processing" + +############################################################################### +# Cleanup +############################################################################### + +log "Ruim werkmap op" + +cd "$SCRIPT_DIR" + +cleanup_work_mounts + +rm -rf "$WORK_DIR" + +echo +echo "============================================================" +echo "KLAAR" +echo "============================================================" +echo +echo "ISO:" +echo " $NEW_ISO_PATH" +echo diff --git a/build-kiosk-iso-v9.sh b/build-kiosk-iso-v9.sh new file mode 100755 index 0000000..8010697 --- /dev/null +++ b/build-kiosk-iso-v9.sh @@ -0,0 +1,1300 @@ +#!/usr/bin/env bash +set -euo pipefail +set -o pipefail + +############################################################################### +# Linux Mint 22.3 Aamsveen Audio Kiosk ISO builder +# +# VERSION: v9 +# +# Host: +# NixOS 26.11 unstable +# +# Guest: +# Linux Mint 22.3 Cinnamon 64-bit +# +# BOOT DESIGN +# +# BIOS: +# ISO +# -> ISOLINUX +# -> /isolinux/live.cfg +# -> /casper/vmlinuz +# -> casper +# -> Ubiquity +# +# UEFI: +# ISO +# -> /boot/grub/efi.img +# -> ORIGINAL Mint EFI GRUB loader +# -> ISO /boot/grub/grub.cfg +# -> /casper/vmlinuz +# -> casper +# -> Ubiquity +# +# CRITICAL: +# +# boot/grub/efi.img is NEVER modified. +# +# The custom UEFI menu exists ONLY in: +# +# /boot/grub/grub.cfg +# +# The custom BIOS menu exists in: +# +# /isolinux/live.cfg +# +# xorriso creates the hybrid ISO directly. +# isohybrid is NOT run afterwards. +############################################################################### + +############################################################################### +# Configuration +############################################################################### + +BASE_ISO_FILENAME="linuxmint-22.3-cinnamon-64bit.iso" + +NEW_ISO_FILENAME="non-aamsveen-audio-kiosk_v10.iso" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +ISO_PATH="$SCRIPT_DIR/$BASE_ISO_FILENAME" +SCRIPT_PATH="$SCRIPT_DIR/install-kiosk-nl.sh" +PRESEED_PATH="$SCRIPT_DIR/preseed.cfg" + +WORK_DIR="$SCRIPT_DIR/build-aamsveen" + +ISO_ROOT="$WORK_DIR/iso" +SQUASHFS_DIR="$WORK_DIR/squashfs-root" + +NEW_ISO_PATH="$SCRIPT_DIR/$NEW_ISO_FILENAME" + +############################################################################### +# Helpers +############################################################################### + +die() { + echo + echo "ERROR: $*" >&2 + exit 1 +} + +log() { + echo + echo "============================================================" + echo "$*" + echo "============================================================" +} + +require_command() { + command -v "$1" >/dev/null 2>&1 \ + || die "Required command not found: $1" +} + +############################################################################### +# Mount cleanup +# +# Previous builds can leave efi.img loop mounts behind. +# +# IMPORTANT: +# +# We unmount deepest paths first, then remove the build directory. +############################################################################### + +cleanup_work_mounts() { + if [[ ! -d "$WORK_DIR" ]]; then + return 0 + fi + + while read -r MOUNTPOINT; do + [[ -n "$MOUNTPOINT" ]] || continue + + echo "Unmount: $MOUNTPOINT" + + sudo umount "$MOUNTPOINT" 2>/dev/null || \ + sudo umount -l "$MOUNTPOINT" 2>/dev/null || true + + done < <( + findmnt -rn -o TARGET 2>/dev/null | + grep -F "$WORK_DIR/" | + awk '{ print length($0), $0 }' | + sort -rn | + cut -d' ' -f2- + ) +} + +############################################################################### +# Dependency check +# +# NixOS: +# +# nix shell nixpkgs#xorriso nixpkgs#squashfsTools +############################################################################### + +log "Controleer benodigde programma's" + +for cmd in \ + xorriso \ + unsquashfs \ + mksquashfs \ + find \ + sed \ + awk \ + stat \ + mount \ + umount \ + dd \ + cmp \ + grep \ + sudo \ + mountpoint \ + sort \ + cut +do + require_command "$cmd" +done + +############################################################################### +# Input validation +############################################################################### + +log "Controleer invoerbestanden" + +[[ -f "$ISO_PATH" ]] \ + || die "Basis-ISO niet gevonden: $ISO_PATH" + +[[ -f "$SCRIPT_PATH" ]] \ + || die "Installatiescript niet gevonden: $SCRIPT_PATH" + +[[ -f "$PRESEED_PATH" ]] \ + || die "Preseed niet gevonden: $PRESEED_PATH" + +echo "Basis ISO : $ISO_PATH" +echo "Preseed : $PRESEED_PATH" +echo "Installer : $SCRIPT_PATH" +echo "Output : $NEW_ISO_PATH" + +############################################################################### +# Basic file information +############################################################################### + +log "Controleer basis-ISO" + +ORIGINAL_ISO_SIZE="$(stat -c%s "$ISO_PATH")" + +echo "Originele ISO:" +echo " $ISO_PATH" + +echo +echo "Grootte:" +echo " $ORIGINAL_ISO_SIZE bytes" + +############################################################################### +# Remove old build directory safely +############################################################################### + +log "Verwijder oude werkmap" + +cleanup_work_mounts + +rm -rf "$WORK_DIR" + +mkdir -p "$WORK_DIR" + +############################################################################### +# Remove old output ISO +############################################################################### + +if [[ -f "$NEW_ISO_PATH" ]]; then + log "Verwijder oude output ISO" + rm -f "$NEW_ISO_PATH" +fi + +############################################################################### +# Preserve ORIGINAL Mint MBR boot code +# +# Only the first 432 bytes are reused. +# +# xorriso generates the partition structures. +############################################################################### + +log "Bewaar originele Mint MBR bootcode" + +ORIGINAL_MBR="$WORK_DIR/mint-isohybrid-mbr.bin" + +dd \ + if="$ISO_PATH" \ + of="$ORIGINAL_MBR" \ + bs=432 \ + count=1 \ + status=none + +[[ "$(stat -c%s "$ORIGINAL_MBR")" -eq 432 ]] \ + || die "Originele MBR bootcode heeft geen 432 bytes." + +############################################################################### +# Inspect original ISO boot structure +############################################################################### + +log "Controleer originele El Torito bootinformatie" + +xorriso \ + -indev "$ISO_PATH" \ + -report_el_torito plain + +log "Controleer originele system area" + +xorriso \ + -indev "$ISO_PATH" \ + -report_system_area plain + +############################################################################### +# Extract ISO +############################################################################### + +log "Pak Linux Mint ISO uit" + +mkdir -p "$ISO_ROOT" + +xorriso \ + -osirrox on \ + -indev "$ISO_PATH" \ + -extract / "$ISO_ROOT" + +############################################################################### +# Verify required ISO structure +############################################################################### + +log "Controleer ISO-structuur" + +[[ -d "$ISO_ROOT/casper" ]] \ + || die "casper directory ontbreekt." + +[[ -f "$ISO_ROOT/casper/vmlinuz" ]] \ + || die "casper/vmlinuz ontbreekt." + +[[ -d "$ISO_ROOT/isolinux" ]] \ + || die "isolinux directory ontbreekt." + +[[ -f "$ISO_ROOT/isolinux/isolinux.bin" ]] \ + || die "isolinux/isolinux.bin ontbreekt." + +[[ -f "$ISO_ROOT/isolinux/boot.cat" ]] \ + || die "isolinux/boot.cat ontbreekt." + +[[ -f "$ISO_ROOT/isolinux/live.cfg" ]] \ + || die "isolinux/live.cfg ontbreekt." + +[[ -d "$ISO_ROOT/boot/grub" ]] \ + || die "boot/grub ontbreekt." + +[[ -f "$ISO_ROOT/boot/grub/efi.img" ]] \ + || die "boot/grub/efi.img ontbreekt." + +[[ -f "$ISO_ROOT/boot/grub/grub.cfg" ]] \ + || die "boot/grub/grub.cfg ontbreekt." + +############################################################################### +# Preserve original efi.img for byte-for-byte verification +############################################################################### + +log "Bewaar originele EFI image" + +ORIGINAL_EFI_IMG="$WORK_DIR/original-efi.img" + +cp \ + "$ISO_ROOT/boot/grub/efi.img" \ + "$ORIGINAL_EFI_IMG" + +############################################################################### +# Locate filesystem.squashfs +############################################################################### + +log "Zoek filesystem.squashfs" + +SQUASHFS_FILE="$( + find "$ISO_ROOT" \ + -type f \ + -name "filesystem.squashfs" \ + -print \ + -quit +)" + +[[ -n "$SQUASHFS_FILE" ]] \ + || die "filesystem.squashfs niet gevonden." + +echo "Squashfs:" +echo " $SQUASHFS_FILE" + +############################################################################### +# Detect initrd +############################################################################### + +log "Detecteer initrd" + +INITRD_FILE="$( + find "$ISO_ROOT/casper" \ + -maxdepth 1 \ + -type f \ + -iname "initrd*" \ + -print \ + -quit +)" + +[[ -n "$INITRD_FILE" ]] \ + || die "Geen initrd gevonden." + +ACTUAL_INITRD_NAME="$(basename "$INITRD_FILE")" + +echo "Initrd:" +echo " $ACTUAL_INITRD_NAME" + +############################################################################### +# Unpack squashfs +############################################################################### + +log "Pak squashfs uit" + +mkdir -p "$SQUASHFS_DIR" + +unsquashfs \ + -f \ + -d "$SQUASHFS_DIR" \ + "$SQUASHFS_FILE" + +############################################################################### +# Install preseed into ISO +############################################################################### + +log "Plaats preseed op ISO" + +PRESEED_ISO_DIR="$ISO_ROOT/preseed" +PRESEED_ISO_PATH="$PRESEED_ISO_DIR/preseed.cfg" + +mkdir -p "$PRESEED_ISO_DIR" + +cp \ + "$PRESEED_PATH" \ + "$PRESEED_ISO_PATH" + +chmod 644 \ + "$PRESEED_ISO_PATH" + +############################################################################### +# Install preseed into live filesystem +############################################################################### + +log "Plaats preseed in live filesystem" + +cp \ + "$PRESEED_PATH" \ + "$SQUASHFS_DIR/preseed.cfg" + +chmod 644 \ + "$SQUASHFS_DIR/preseed.cfg" + +############################################################################### +# Copy installer script into live filesystem +############################################################################### + +log "Plaats install-kiosk-nl.sh in live filesystem" + +INSTALL_SCRIPT_DEST="$SQUASHFS_DIR/usr/local/bin/install-kiosk-nl.sh" + +mkdir -p \ + "$(dirname "$INSTALL_SCRIPT_DEST")" + +cp \ + "$SCRIPT_PATH" \ + "$INSTALL_SCRIPT_DEST" + +chmod +x \ + "$INSTALL_SCRIPT_DEST" + +############################################################################### +# Keep installer script in /home/av-admin +############################################################################### + +log "Plaats install-kiosk-nl.sh in /home/av-admin" + +ADMIN_HOME="$SQUASHFS_DIR/home/av-admin" + +mkdir -p "$ADMIN_HOME" + +cp \ + "$SCRIPT_PATH" \ + "$ADMIN_HOME/install-kiosk-nl.sh" + +chmod +x \ + "$ADMIN_HOME/install-kiosk-nl.sh" + +############################################################################### +# Create dedicated Ubiquity launcher wrapper +# +# This avoids fragile nested quoting in Exec=. +############################################################################### + +log "Maak Ubiquity installer wrapper" + +INSTALLER_WRAPPER="$SQUASHFS_DIR/usr/local/bin/aamsveen-start-installer.sh" + +mkdir -p \ + "$(dirname "$INSTALLER_WRAPPER")" + +cat > "$INSTALLER_WRAPPER" << 'EOF' +#!/bin/sh +set -e + +sudo debconf-set-selections /preseed.cfg + +exec sudo env \ + DEBIAN_FRONTEND=noninteractive \ + ubiquity \ + --automatic +EOF + +chmod 755 \ + "$INSTALLER_WRAPPER" + +############################################################################### +# Disable Mint Welcome +############################################################################### + +log "Schakel mintwelcome uit" + +MINT_WELCOME="$SQUASHFS_DIR/etc/xdg/autostart/mintwelcome.desktop" + +if [[ -f "$MINT_WELCOME" ]]; then + mv \ + "$MINT_WELCOME" \ + "$MINT_WELCOME.bak" +fi + +############################################################################### +# Remove normal Ubiquity launcher +############################################################################### + +log "Verwijder standaard Ubiquity launcher" + +UBIQUITY_DESKTOP="$SQUASHFS_DIR/usr/share/applications/ubiquity.desktop" + +if [[ -f "$UBIQUITY_DESKTOP" ]]; then + rm -f "$UBIQUITY_DESKTOP" +fi + +############################################################################### +# Create custom desktop installer launcher +############################################################################### + +log "Maak aangepaste Ubiquity desktop launcher" + +CUSTOM_DESKTOP_ENTRY="$SQUASHFS_DIR/usr/share/applications/install-kiosk.desktop" + +mkdir -p \ + "$(dirname "$CUSTOM_DESKTOP_ENTRY")" + +cat > "$CUSTOM_DESKTOP_ENTRY" << 'EOF' +[Desktop Entry] +Name=Installeer Audio Kiosk voor Aamsveen +Comment=Installeer Linux Mint met Audio Kiosk voor Aamsveen +Exec=/usr/local/bin/aamsveen-start-installer.sh +Icon=mintubiquity +Terminal=false +Type=Application +Categories=System; +EOF + +chmod 644 \ + "$CUSTOM_DESKTOP_ENTRY" + +############################################################################### +# Replace Mint desktop installer shortcut +############################################################################### + +log "Maak aangepaste desktop installer shortcut" + +MINT_DESKTOP_DIR="$SQUASHFS_DIR/home/mint/Desktop" +MINT_DESKTOP_ENTRY="$MINT_DESKTOP_DIR/install.desktop" + +mkdir -p "$MINT_DESKTOP_DIR" + +rm -f "$MINT_DESKTOP_ENTRY" + +cp \ + "$CUSTOM_DESKTOP_ENTRY" \ + "$MINT_DESKTOP_ENTRY" + +chmod +x \ + "$MINT_DESKTOP_ENTRY" + +############################################################################### +# Desktop database +############################################################################### + +if command -v update-desktop-database >/dev/null 2>&1; then + update-desktop-database \ + "$SQUASHFS_DIR/usr/share/applications/" \ + 2>/dev/null || true +fi + +############################################################################### +# UEFI GRUB +# +# DO NOT MODIFY efi.img. +# +# Verified original Mint EFI loader: +# +# search --set=root --file /.disk/info +# set prefix=($root)/boot/grub +# configfile ($root)/boot/grub/grub.cfg +# +# Therefore the actual UEFI menu is the ISO-level: +# +# /boot/grub/grub.cfg +############################################################################### + +log "Maak UEFI GRUB bootmenu" + +GRUB_CFG="$ISO_ROOT/boot/grub/grub.cfg" + +cat > "$GRUB_CFG" << EOF +loadfont unicode + +set color_normal=dark-green/light-gray +set color_highlight=light-gray/dark-green + +set default=1 +set timeout=5 + +menuentry "Start Linux Mint 22.3 Cinnamon 64-bit" --class linuxmint { + set gfxpayload=keep + linux /casper/vmlinuz boot=casper uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint iso-scan/filename=\${iso_path} quiet splash -- + initrd /casper/${ACTUAL_INITRD_NAME} +} + +menuentry "Unattended Install Aamsveen Kiosk" --class linuxmint { + set gfxpayload=keep + linux /casper/vmlinuz boot=casper uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint iso-scan/filename=\${iso_path} automatic-ubiquity noprompt file=/cdrom/preseed/preseed.cfg priority=critical quiet splash -- + initrd /casper/${ACTUAL_INITRD_NAME} +} + +menuentry "Start Linux Mint 22.3 Cinnamon 64-bit (compatibility mode)" { + set gfxpayload=keep + linux /casper/vmlinuz boot=casper uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint iso-scan/filename=\${iso_path} noapic noacpi nosplash irqpoll nomodeset -- + initrd /casper/${ACTUAL_INITRD_NAME} +} + +menuentry "OEM install (for manufacturers)" { + set gfxpayload=keep + linux /casper/vmlinuz oem-config/enable=true only-ubiquity boot=casper uuid=6e72f523-dc09-4880-8910-93ffa64401c5 username=mint hostname=mint iso-scan/filename=\${iso_path} quiet splash -- + initrd /casper/${ACTUAL_INITRD_NAME} +} + +if [ "\$grub_platform" = "efi" ]; then + + menuentry "Boot from next volume" { + exit 1 + } + + menuentry "UEFI Firmware Settings" { + fwsetup + } + + if [ -f /boot/memtest.efi ]; then + menuentry "Memory test" { + linux /boot/memtest.efi + } + fi + +fi +EOF + +############################################################################### +# Verify UEFI GRUB source configuration +############################################################################### + +log "Controleer UEFI GRUB" + +grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + "$GRUB_CFG" \ + || die "UEFI unattended entry ontbreekt." + +grep -q \ + 'automatic-ubiquity' \ + "$GRUB_CFG" \ + || die "UEFI automatic-ubiquity ontbreekt." + +grep -q \ + 'noprompt' \ + "$GRUB_CFG" \ + || die "UEFI noprompt ontbreekt." + +grep -q \ + 'file=/cdrom/preseed/preseed.cfg' \ + "$GRUB_CFG" \ + || die "UEFI preseed path ontbreekt." + +grep -q \ + 'iso-scan/filename=${iso_path}' \ + "$GRUB_CFG" \ + || die "UEFI iso-scan/filename ontbreekt." + +grep -q \ + 'set default=1' \ + "$GRUB_CFG" \ + || die "UEFI unattended entry is niet default." + +grep -q \ + 'set timeout=5' \ + "$GRUB_CFG" \ + || die "UEFI timeout=5 ontbreekt." + +############################################################################### +# Verify original EFI image BEFORE ISO creation +############################################################################### + +log "Controleer originele EFI loader" + +EFI_IMG="$ISO_ROOT/boot/grub/efi.img" + +EFI_MOUNT="$WORK_DIR/efi_mount" + +mkdir -p "$EFI_MOUNT" + +EFI_MOUNTED=0 + +cleanup_efi() { + if [[ "$EFI_MOUNTED" -eq 1 ]]; then + sudo umount "$EFI_MOUNT" 2>/dev/null || \ + sudo umount -l "$EFI_MOUNT" 2>/dev/null || true + + EFI_MOUNTED=0 + fi +} + +trap cleanup_efi EXIT + +sudo mount \ + -o loop,ro \ + "$EFI_IMG" \ + "$EFI_MOUNT" + +EFI_MOUNTED=1 + +EFI_GRUB_CFG="$( + sudo find "$EFI_MOUNT" \ + -type f \ + -name "grub.cfg" \ + -print \ + -quit +)" + +[[ -n "$EFI_GRUB_CFG" ]] \ + || die "Geen grub.cfg gevonden in efi.img." + +EFI_GRUB_CONTENT="$( + sudo cat "$EFI_GRUB_CFG" +)" + +echo "$EFI_GRUB_CONTENT" + +grep -q \ + 'search --set=root --file /.disk/info' \ + <<< "$EFI_GRUB_CONTENT" \ + || die "Originele EFI loader mist /.disk/info search." + +grep -q \ + 'set prefix=($root)/boot/grub' \ + <<< "$EFI_GRUB_CONTENT" \ + || die "Originele EFI loader mist GRUB prefix." + +grep -q \ + 'configfile ($root)/boot/grub/grub.cfg' \ + <<< "$EFI_GRUB_CONTENT" \ + || die "Originele EFI loader mist configfile." + +if grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + <<< "$EFI_GRUB_CONTENT" +then + die "Aamsveen menu staat ten onrechte in efi.img." +fi + +cleanup_efi + +trap - EXIT + +############################################################################### +# BIOS / ISOLINUX +# +# The original Mint ISO uses /isolinux/live.cfg as its visible BIOS menu. +############################################################################### + +log "Maak BIOS/ISOLINUX bootmenu" + +LIVE_CFG_PATH="$ISO_ROOT/isolinux/live.cfg" + +[[ -f "$LIVE_CFG_PATH" ]] \ + || die "isolinux/live.cfg ontbreekt." + +############################################################################### +# Remove any previous Aamsveen unattended block +# +# This removes: +# +# label unattended-install +# ... +# +# until the next "label" or EOF. +############################################################################### + +TMP_LIVE_CFG="$WORK_DIR/live.cfg.tmp" + +awk ' +BEGIN { + skip = 0 +} + +/^[[:space:]]*label[[:space:]]+unattended-install[[:space:]]*$/ { + skip = 1 + next +} + +skip == 1 && /^[[:space:]]*label[[:space:]]+/ { + skip = 0 +} + +skip == 1 { + next +} + +{ + print +} +' "$LIVE_CFG_PATH" > "$TMP_LIVE_CFG" + +mv \ + "$TMP_LIVE_CFG" \ + "$LIVE_CFG_PATH" + +############################################################################### +# Remove old timeout directives +############################################################################### + +sed -i \ + '/^[[:space:]]*timeout[[:space:]]\+[0-9]\+[[:space:]]*$/d' \ + "$LIVE_CFG_PATH" + +############################################################################### +# Make unattended entry the BIOS default +# +# ISOLINUX uses "menu default" in the label block. +############################################################################### + +sed -i \ + '/^[[:space:]]*menu default[[:space:]]*$/d' \ + "$LIVE_CFG_PATH" + +############################################################################### +# Add unattended BIOS entry +############################################################################### + +cat >> "$LIVE_CFG_PATH" << EOF + +# --------------------------------------------------------------------------- +# Aamsveen custom unattended installer +# --------------------------------------------------------------------------- + +label unattended-install + menu label ^Unattended Install Aamsveen Kiosk + menu default + kernel /casper/vmlinuz + append boot=casper automatic-ubiquity noprompt file=/cdrom/preseed/preseed.cfg priority=critical quiet splash -- + initrd /casper/${ACTUAL_INITRD_NAME} + +# Wait indefinitely for user input. +timeout 0 +EOF + +############################################################################### +# Verify BIOS configuration +############################################################################### + +log "Controleer BIOS/ISOLINUX configuratie" + +grep -q \ + '^label unattended-install$' \ + "$LIVE_CFG_PATH" \ + || die "BIOS unattended entry ontbreekt." + +grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + "$LIVE_CFG_PATH" \ + || die "BIOS Aamsveen menu-entry ontbreekt." + +grep -q \ + 'automatic-ubiquity' \ + "$LIVE_CFG_PATH" \ + || die "BIOS automatic-ubiquity ontbreekt." + +grep -q \ + 'noprompt' \ + "$LIVE_CFG_PATH" \ + || die "BIOS noprompt ontbreekt." + +grep -q \ + 'file=/cdrom/preseed/preseed.cfg' \ + "$LIVE_CFG_PATH" \ + || die "BIOS preseed path ontbreekt." + +grep -q \ + '^timeout 0$' \ + "$LIVE_CFG_PATH" \ + || die "BIOS timeout 0 ontbreekt." + +grep -q \ + '^[[:space:]]*menu default[[:space:]]*$' \ + "$LIVE_CFG_PATH" \ + || die "BIOS unattended entry is niet default." + +############################################################################### +# Display boot configurations +############################################################################### + +echo +echo "================ UEFI grub.cfg ================" +cat "$GRUB_CFG" + +echo +echo "================ BIOS live.cfg ================" +cat "$LIVE_CFG_PATH" + +############################################################################### +# Rebuild squashfs +############################################################################### + +log "Verwijder oude filesystem.squashfs" + +rm -f \ + "$SQUASHFS_FILE" + +log "Bouw filesystem.squashfs opnieuw" + +mksquashfs \ + "$SQUASHFS_DIR" \ + "$ISO_ROOT/casper/filesystem.squashfs" \ + -b 256K \ + -comp xz \ + -Xdict-size 100% \ + -no-duplicates \ + -no-xattrs \ + -noappend + +[[ -f "$ISO_ROOT/casper/filesystem.squashfs" ]] \ + || die "Nieuw filesystem.squashfs ontbreekt." + +############################################################################### +# Build ISO +############################################################################### + +log "Bouw nieuwe ISO met xorriso-native hybrid layout" + +cd "$ISO_ROOT" + +xorriso -as mkisofs \ + -r \ + -V "NonAamsveenAudioKiosk" \ + -J \ + -l \ + -isohybrid-mbr "$ORIGINAL_MBR" \ + -partition_cyl_align on \ + -partition_offset 16 \ + -partition_hd_cyl 185 \ + -partition_sec_hd 32 \ + --mbr-force-bootable \ + -apm-block-size 2048 \ + -iso_mbr_part_type 0x00 \ + -c isolinux/boot.cat \ + -b isolinux/isolinux.bin \ + -no-emul-boot \ + -boot-load-size 4 \ + -boot-info-table \ + -eltorito-alt-boot \ + -e boot/grub/efi.img \ + -no-emul-boot \ + -isohybrid-gpt-basdat \ + -isohybrid-apm-hfsplus \ + -o "$NEW_ISO_PATH" \ + . + +############################################################################### +# Verify ISO exists +############################################################################### + +log "Controleer gemaakte ISO" + +[[ -f "$NEW_ISO_PATH" ]] \ + || die "Nieuwe ISO is niet gemaakt." + +NEW_ISO_SIZE="$(stat -c%s "$NEW_ISO_PATH")" + +echo "Originele ISO : $ORIGINAL_ISO_SIZE bytes" +echo "Nieuwe ISO : $NEW_ISO_SIZE bytes" + +if [[ "$NEW_ISO_SIZE" -lt "$((ORIGINAL_ISO_SIZE * 90 / 100))" ]]; then + die "Nieuwe ISO is verdacht klein." +fi + +############################################################################### +# Verify El Torito +############################################################################### + +log "Controleer El Torito" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -report_el_torito plain + +############################################################################### +# Verify hybrid system area +############################################################################### + +log "Controleer hybrid system area" + +SYSTEM_AREA_REPORT="$WORK_DIR/system-area-report.txt" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -report_system_area plain \ + > "$SYSTEM_AREA_REPORT" + +cat "$SYSTEM_AREA_REPORT" + +grep -Eq \ + 'System area summary:.*MBR.*GPT.*APM' \ + "$SYSTEM_AREA_REPORT" \ + || die "MBR/GPT/APM hybrid layout ontbreekt." + +############################################################################### +# Create final ISO verification directory +############################################################################### + +TMP_CHECK_DIR="$WORK_DIR/iso-check" + +mkdir -p "$TMP_CHECK_DIR" + +############################################################################### +# Verify boot files +############################################################################### + +log "Controleer bootbestanden" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -ls \ + /casper/vmlinuz \ + /casper/"$ACTUAL_INITRD_NAME" \ + /boot/grub/efi.img \ + /boot/grub/grub.cfg \ + /isolinux/live.cfg + +############################################################################### +# Verify BIOS config inside FINAL ISO +############################################################################### + +log "Controleer BIOS configuratie in eind-ISO" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /isolinux/live.cfg "$TMP_CHECK_DIR/" + +FINAL_LIVE_CFG="$TMP_CHECK_DIR/live.cfg" + +grep -q \ + '^label unattended-install$' \ + "$FINAL_LIVE_CFG" \ + || die "Finale ISO mist BIOS unattended entry." + +grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + "$FINAL_LIVE_CFG" \ + || die "Finale ISO mist BIOS Aamsveen entry." + +grep -q \ + 'automatic-ubiquity' \ + "$FINAL_LIVE_CFG" \ + || die "Finale ISO mist BIOS automatic-ubiquity." + +grep -q \ + 'noprompt' \ + "$FINAL_LIVE_CFG" \ + || die "Finale ISO mist BIOS noprompt." + +grep -q \ + 'file=/cdrom/preseed/preseed.cfg' \ + "$FINAL_LIVE_CFG" \ + || die "Finale ISO mist BIOS preseed." + +grep -q \ + '^[[:space:]]*menu default[[:space:]]*$' \ + "$FINAL_LIVE_CFG" \ + || die "Finale BIOS unattended entry is niet default." + +############################################################################### +# Verify UEFI config inside FINAL ISO +############################################################################### + +log "Controleer UEFI configuratie in eind-ISO" + +TMP_GRUB_CHECK="$TMP_CHECK_DIR/grub.cfg" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /boot/grub/grub.cfg "$TMP_GRUB_CHECK" + +grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + "$TMP_GRUB_CHECK" \ + || die "Finale ISO mist UEFI unattended entry." + +grep -q \ + 'automatic-ubiquity' \ + "$TMP_GRUB_CHECK" \ + || die "Finale ISO mist UEFI automatic-ubiquity." + +grep -q \ + 'noprompt' \ + "$TMP_GRUB_CHECK" \ + || die "Finale ISO mist UEFI noprompt." + +grep -q \ + 'file=/cdrom/preseed/preseed.cfg' \ + "$TMP_GRUB_CHECK" \ + || die "Finale ISO mist UEFI preseed path." + +grep -q \ + 'iso-scan/filename=${iso_path}' \ + "$TMP_GRUB_CHECK" \ + || die "Finale ISO mist UEFI iso-scan/filename." + +grep -q \ + 'set default=1' \ + "$TMP_GRUB_CHECK" \ + || die "Finale UEFI unattended entry is niet default." + +############################################################################### +# Verify ORIGINAL efi.img remains byte-for-byte identical +############################################################################### + +log "Controleer dat efi.img byte-for-byte origineel is" + +EFI_VERIFY_DIR="$TMP_CHECK_DIR/efi-verify" + +mkdir -p "$EFI_VERIFY_DIR" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /boot/grub/efi.img "$EFI_VERIFY_DIR/" + +FINAL_EFI_IMG="$EFI_VERIFY_DIR/efi.img" + +[[ -f "$FINAL_EFI_IMG" ]] \ + || die "Finale efi.img kon niet uit ISO worden gehaald." + +cmp \ + "$ORIGINAL_EFI_IMG" \ + "$FINAL_EFI_IMG" \ + || die "Finale efi.img verschilt van de originele Mint efi.img." + +echo "efi.img: BYTE-FOR-BYTE IDENTIEK AAN ORIGINEEL" + +############################################################################### +# Mount final efi.img and verify chainloader +############################################################################### + +log "Controleer EFI chainloader in eind-ISO" + +FINAL_EFI_MOUNT="$EFI_VERIFY_DIR/mount" + +mkdir -p "$FINAL_EFI_MOUNT" + +FINAL_EFI_MOUNTED=0 + +cleanup_final_efi() { + if [[ "$FINAL_EFI_MOUNTED" -eq 1 ]]; then + sudo umount "$FINAL_EFI_MOUNT" 2>/dev/null || \ + sudo umount -l "$FINAL_EFI_MOUNT" 2>/dev/null || true + + FINAL_EFI_MOUNTED=0 + fi +} + +trap cleanup_final_efi EXIT + +sudo mount \ + -o loop,ro \ + "$FINAL_EFI_IMG" \ + "$FINAL_EFI_MOUNT" + +FINAL_EFI_MOUNTED=1 + +FINAL_EFI_GRUB_CFG="$( + sudo find "$FINAL_EFI_MOUNT" \ + -type f \ + -name "grub.cfg" \ + -print \ + -quit +)" + +[[ -n "$FINAL_EFI_GRUB_CFG" ]] \ + || die "Geen grub.cfg in finale efi.img." + +FINAL_EFI_CONTENT="$( + sudo cat "$FINAL_EFI_GRUB_CFG" +)" + +echo +echo "================ FINAL EFI grub.cfg ================" +echo "$FINAL_EFI_CONTENT" + +grep -q \ + 'search --set=root --file /.disk/info' \ + <<< "$FINAL_EFI_CONTENT" \ + || die "Finale EFI loader mist Mint search." + +grep -q \ + 'set prefix=($root)/boot/grub' \ + <<< "$FINAL_EFI_CONTENT" \ + || die "Finale EFI loader mist GRUB prefix." + +grep -q \ + 'configfile ($root)/boot/grub/grub.cfg' \ + <<< "$FINAL_EFI_CONTENT" \ + || die "Finale EFI loader mist ISO-level configfile." + +if grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + <<< "$FINAL_EFI_CONTENT" +then + die "Finale efi.img bevat ten onrechte custom Aamsveen menu." +fi + +cleanup_final_efi + +trap - EXIT + +############################################################################### +# Verify preseed in FINAL ISO +############################################################################### + +log "Controleer preseed in eind-ISO" + +TMP_PRESEED_CHECK="$TMP_CHECK_DIR/preseed.cfg" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /preseed/preseed.cfg "$TMP_PRESEED_CHECK" + +[[ -s "$TMP_PRESEED_CHECK" ]] \ + || die "Finale ISO bevat geen geldige preseed." + +############################################################################### +# Verify installer wrapper in rebuilt squashfs +############################################################################### + +[[ -f "$SQUASHFS_DIR/usr/local/bin/aamsveen-start-installer.sh" ]] \ + || die "Installer wrapper ontbreekt." + +[[ -x "$SQUASHFS_DIR/usr/local/bin/aamsveen-start-installer.sh" ]] \ + || die "Installer wrapper is niet executable." + +[[ -f "$SQUASHFS_DIR/usr/local/bin/install-kiosk-nl.sh" ]] \ + || die "install-kiosk-nl.sh ontbreekt." + +[[ -x "$SQUASHFS_DIR/usr/local/bin/install-kiosk-nl.sh" ]] \ + || die "install-kiosk-nl.sh is niet executable." + +############################################################################### +# Final report +############################################################################### + +log "BUILD VOLTOOID" + +echo +echo "ISO:" +echo " $NEW_ISO_PATH" + +echo +echo "UEFI:" +echo " Start Linux Mint" +echo " Unattended Install Aamsveen Kiosk <-- DEFAULT" +echo " Compatibility mode" +echo " OEM" +echo " UEFI Firmware Settings" + +echo +echo "UEFI colors:" +echo " normal = dark-green / light-gray" +echo " highlight = light-gray / dark-green" + +echo +echo "UEFI timeout:" +echo " 5 seconden" + +echo +echo "BIOS:" +echo " Start Linux Mint" +echo " Compatibility mode" +echo " OEM" +echo " Hardware Detection" +echo " Boot from local drive" +echo " Memory test" +echo " Unattended Install Aamsveen Kiosk <-- DEFAULT" + +echo +echo "BIOS timeout:" +echo " 0 = oneindig" + +echo +echo "Installer:" +echo " automatic-ubiquity" +echo " noprompt" +echo " file=/cdrom/preseed/preseed.cfg" +echo " priority=critical" + +echo +echo "EFI image:" +echo " ORIGINAL" +echo " byte-for-byte verified" + +echo +echo "Hybrid ISO:" +echo " MBR + GPT + APM" +echo " xorriso native" +echo " GEEN isohybrid post-processing" + +############################################################################### +# Cleanup +############################################################################### + +log "Ruim werkmap op" + +cd "$SCRIPT_DIR" + +cleanup_work_mounts + +rm -rf "$WORK_DIR" + +echo +echo "============================================================" +echo "KLAAR" +echo "============================================================" +echo +echo "ISO:" +echo " $NEW_ISO_PATH" +echo diff --git a/preseed.cfg b/preseed.cfg index 67e9489..729ebb7 100644 --- a/preseed.cfg +++ b/preseed.cfg @@ -6,20 +6,35 @@ # The selected target disk is COMPLETELY ERASED. # # The installer deliberately excludes the USB installer media. +# +# The target disk is partitioned as GPT and contains: +# +# 1 MiB BIOS Boot partition +# 538 MiB EFI System Partition +# ~remaining Linux root filesystem +# 2 GiB swap +# +# The BIOS Boot partition allows GRUB to install when the installer itself +# is booted in legacy BIOS mode. +# +# The EFI System Partition allows GRUB to install when booted in UEFI mode. ############################################################################### + ############################################################################### # Debconf ############################################################################### d-i debconf/priority string critical + ############################################################################### # Locale ############################################################################### d-i debian-installer/locale string nl_NL + ############################################################################### # Keyboard ############################################################################### @@ -29,12 +44,14 @@ d-i keyboard-configuration/layoutcode string us d-i keyboard-configuration/variantcode string euro d-i keyboard-configuration/ask_detect boolean false + ############################################################################### # Network ############################################################################### d-i netcfg/choose_interface select auto + ############################################################################### # Time zone ############################################################################### @@ -42,6 +59,7 @@ d-i netcfg/choose_interface select auto d-i clock-setup/utc boolean true d-i time/zone string Europe/Amsterdam + ############################################################################### # User ############################################################################### @@ -51,6 +69,7 @@ d-i passwd/username string av-admin d-i passwd/user-password password @)av-admin@^ d-i passwd/user-password-again password @)av-admin@^ + ############################################################################### # Hostname ############################################################################### @@ -58,33 +77,60 @@ d-i passwd/user-password-again password @)av-admin@^ d-i netcfg/get_hostname string audio-kiosk d-i netcfg/get_domain string + ############################################################################### -# Partitioning +# Partitioning method ############################################################################### d-i partman-auto/method string regular + ############################################################################### -# Dynamically determine the installation disk. +# Dynamic installation-disk selection # -# list-devices usb-partition identifies partitions belonging to USB devices. -# Their parent disks are excluded. +# This runs immediately before partman starts. # -# We then select the first non-removable disk. +# The installer USB media is deliberately excluded. # -# IMPORTANT: +# We: # -# There is deliberately NO hard-coded /dev/sda fallback. -# If no safe target can be identified, installation stops instead of -# accidentally overwriting the USB installer. +# 1. Ask the installer for all disks. +# 2. Find USB partitions. +# 3. Determine their parent disks using sysfs. +# 4. Exclude those disks. +# 5. Exclude disks marked removable. +# 6. Select the first remaining disk. +# +# No /dev/sda or /dev/vda is hard-coded. +# +# If no safe target exists, installation stops. ############################################################################### d-i partman/early_command string \ + LOG="/var/log/aamsveen-partition.log"; \ + echo "==================================================" > "$LOG"; \ + echo "Aamsveen Audio Kiosk - disk detection" >> "$LOG"; \ + echo "==================================================" >> "$LOG"; \ + echo "" >> "$LOG"; \ + echo "Disks reported by list-devices disk:" >> "$LOG"; \ + list-devices disk >> "$LOG" 2>&1; \ + echo "" >> "$LOG"; \ USB_DISKS=""; \ for USB_PART in $(list-devices usb-partition 2>/dev/null || true); do \ - USB_PARENT="$(lsblk -ndo PKNAME "$USB_PART" 2>/dev/null || true)"; \ - if [ -n "$USB_PARENT" ]; then \ - USB_DISKS="$USB_DISKS /dev/$USB_PARENT"; \ + PART_NAME="$(basename "$USB_PART")"; \ + PART_SYS="/sys/class/block/$PART_NAME"; \ + if [ -e "$PART_SYS" ]; then \ + PARENT="$(readlink -f "$PART_SYS" 2>/dev/null || true)"; \ + while [ -n "$PARENT" ] && [ "$(basename "$PARENT")" != "block" ]; do \ + PARENT_NAME="$(basename "$PARENT")"; \ + if [ -r "/sys/class/block/$PARENT_NAME/removable" ]; then \ + USB_DISKS="$USB_DISKS /dev/$PARENT_NAME"; \ + break; \ + fi; \ + NEXT="$(dirname "$PARENT")"; \ + [ "$NEXT" = "$PARENT" ] && break; \ + PARENT="$NEXT"; \ + done; \ fi; \ done; \ TARGET_DISK=""; \ @@ -106,48 +152,74 @@ d-i partman/early_command string \ TARGET_DISK="$DISK"; \ break; \ done; \ + echo "USB disks excluded: $USB_DISKS" >> "$LOG"; \ + echo "Selected target disk: $TARGET_DISK" >> "$LOG"; \ + echo "" >> "$LOG"; \ if [ -z "$TARGET_DISK" ]; then \ - echo "Aamsveen installer ERROR: no safe internal target disk found" \ - > /var/log/aamsveen-partition.log; \ + echo "ERROR: No safe internal target disk found." >> "$LOG"; \ exit 1; \ fi; \ debconf-set partman-auto/disk "$TARGET_DISK"; \ debconf-set grub-installer/bootdev "$TARGET_DISK"; \ - echo "Aamsveen installer: USB disks = $USB_DISKS" \ - > /var/log/aamsveen-partition.log; \ - echo "Aamsveen installer: TARGET disk = $TARGET_DISK" \ - >> /var/log/aamsveen-partition.log; \ - lsblk -e7 -o NAME,PATH,TYPE,SIZE,RM,RO,TRAN,FSTYPE,MOUNTPOINTS \ - >> /var/log/aamsveen-partition.log 2>&1 + echo "partman-auto/disk = $TARGET_DISK" >> "$LOG"; \ + echo "grub-installer/bootdev = $TARGET_DISK" >> "$LOG" + ############################################################################### -# GPT +# GPT partition table ############################################################################### d-i partman-partitioning/default_label string gpt d-i partman-partitioning/choose_label select gpt + ############################################################################### -# Explicit UEFI partition recipe +# Partition recipe # -# 512 MiB EFI System Partition -# remainder root filesystem -# 2 GiB swap +# BIOS BOOT: # -# No separate /boot partition is created. -# This deliberately keeps the partition layout simple. +# 1 MiB, no filesystem +# +# Required when GRUB is installed in legacy BIOS mode on GPT. +# +# EFI: +# +# 538 MiB FAT32 EFI System Partition +# +# ROOT: +# +# minimum 12 GiB +# priority 30 GiB +# maximum = remaining disk space +# +# SWAP: +# +# 2 GiB +# +# Example on a 32 GiB disk: +# +# BIOS Boot 1 MiB +# EFI 538 MiB +# swap 2 GiB +# / ~29 GiB ############################################################################### d-i partman-auto/expert_recipe string \ aamsveen-uefi :: \ + 1 1 1 biosgrub \ + $iflabel{ gpt } \ + $primary{ } \ + method{ biosgrub } \ + . \ 538 538 538 fat32 \ $iflabel{ gpt } \ $primary{ } \ - $reusemethod{ } \ + $bootable{ } \ method{ efi } \ format{ } \ + mountpoint{ /boot/efi } \ . \ - 8192 8192 -1 ext4 \ + 12288 30000 -1 ext4 \ $primary{ } \ method{ format } \ format{ } \ @@ -157,22 +229,28 @@ d-i partman-auto/expert_recipe string \ . \ 2048 2048 2048 linux-swap \ $primary{ } \ - $reusemethod{ } \ method{ swap } \ format{ } \ . -d-i partman-auto/choose_recipe select aamsveen-uefi ############################################################################### -# Remove existing storage configuration +# Select recipe +############################################################################### + +d-i partman-auto/choose_recipe select aamsveen-uefi + + +############################################################################### +# Remove existing LVM / RAID configuration ############################################################################### d-i partman-lvm/device_remove_lvm boolean true d-i partman-md/device_remove_md boolean true + ############################################################################### -# Do not preserve old partitions +# Completely replace existing partition table ############################################################################### d-i partman-partitioning/confirm_write_new_label boolean true @@ -180,42 +258,47 @@ d-i partman/choose_partition select finish d-i partman/confirm boolean true d-i partman/confirm_nooverwrite boolean true -############################################################################### -# UEFI -############################################################################### - -d-i partman-efi/non_efi_system boolean true ############################################################################### -# Filesystem +# Filesystem mounting ############################################################################### d-i partman/mount_style select uuid + ############################################################################### # Bootloader +# +# The actual target disk is supplied dynamically by partman/early_command. ############################################################################### d-i grub-installer/only_debian boolean true d-i grub-installer/with_other_os boolean false - -# The exact disk is supplied dynamically by partman/early_command. d-i grub-installer/bootdev string default +############################################################################### +# Third-party software / codecs +############################################################################### + +d-i ubiquity/use_nonfree boolean true + + ############################################################################### # Ubiquity ############################################################################### -ubiquity ubiquity/summary string +ubiquity ubiquity/summary note ubiquity ubiquity/confirm-partitioning boolean true ubiquity ubiquity/reboot boolean true + ############################################################################### -# Installation behaviour +# Installation media ############################################################################### d-i cdrom-detect/eject boolean false + ############################################################################### # Finish ###############################################################################