diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d853714 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.iso +*.cow +*.img +*.qcow2 +*.vmdk +*.vdi +build-aamsveen +work +squashfs diff --git a/build-kiosk-iso-v6.sh b/build-kiosk-iso-v6.sh new file mode 100755 index 0000000..60e170c --- /dev/null +++ b/build-kiosk-iso-v6.sh @@ -0,0 +1,927 @@ +#!/usr/bin/env bash +set -euo pipefail + +############################################################################### +# Linux Mint 22.3 Aamsveen Audio Kiosk ISO builder +# +# Purpose: +# Build a customized Linux Mint 22.3 Cinnamon ISO with: +# +# 1. Normal "Start Linux Mint" live boot +# 2. "Unattended Install Aamsveen Kiosk" boot option +# 3. Boot menu waits indefinitely for user input +# 4. UEFI + legacy BIOS boot support +# 5. USB-hybrid layout generated DIRECTLY by xorriso +# +# IMPORTANT: +# +# We deliberately DO NOT run "isohybrid" after xorriso. +# +# The previous build did: +# +# xorriso ... -o output.iso . +# isohybrid output.iso +# +# That produced an MBR partition of type 0x17 on the resulting USB. +# The Acer TravelMate P614 firmware appears to dislike the resulting +# disk representation. +# +# Instead we let xorriso create the hybrid layout itself: +# +# -isohybrid-mbr +# -isohybrid-gpt-basdat +# +# The original Linux Mint ISO is used as the source for the isohybrid MBR +# boot code. xorriso then creates the MBR/GPT/APM structures itself. +# This reproduces the important hybrid layout of the known-good Mint ISO. +############################################################################### + +set -o pipefail + +############################################################################### +# Configuration +############################################################################### + +BASE_ISO_FILENAME="linuxmint-22.3-cinnamon-64bit.iso" + +NEW_ISO_FILENAME="non-aamsveen-audio-kiosk_v6.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" +NEW_ISO_PATH="$SCRIPT_DIR/$NEW_ISO_FILENAME" + +############################################################################### +# Helper functions +############################################################################### + +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" +} + +############################################################################### +# Check dependencies +############################################################################### + +log "Controleer benodigde programma's" + +for cmd in \ + xorriso \ + unsquashfs \ + mksquashfs \ + find \ + sed \ + awk \ + stat \ + mount \ + umount \ + dd \ + cmp \ + sudo +do + require_command "$cmd" +done + +############################################################################### +# Check input files +############################################################################### + +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" + +############################################################################### +# Check xorriso +############################################################################### + +log "Controleer xorriso" + +XORRISO_VERSION="$(xorriso -version | head -n 1 || true)" + +echo "$XORRISO_VERSION" + +############################################################################### +# Remove previous build directory +############################################################################### + +log "Verwijder oude werkmap" + +if [[ -d "$WORK_DIR" ]]; then + rm -rf "$WORK_DIR" +fi + +mkdir -p "$WORK_DIR" + +############################################################################### +# Remove previous output ISO +############################################################################### + +if [[ -f "$NEW_ISO_PATH" ]]; then + log "Verwijder oude output ISO" + rm -f "$NEW_ISO_PATH" +fi + +############################################################################### +# Extract the ORIGINAL ISO MBR boot code +# +# The official Linux Mint ISO uses xorriso's own hybrid layout: +# +# MBR + GPT + APM +# MBR partition 1 type 0x00 +# MBR partition 2 type 0xEF for /boot/grub/efi.img +# +# We reuse the original Mint MBR boot code, but DO NOT copy its partition table. +# xorriso generates the new partition metadata from the rebuilt ISO. +############################################################################### + +log "Bewaar MBR bootcode van originele Linux Mint ISO" + +ORIGINAL_MBR="$WORK_DIR/mint-isohybrid-mbr.bin" + +dd \ + if="$ISO_PATH" \ + of="$ORIGINAL_MBR" \ + bs=432 \ + count=1 \ + status=none + +[[ -s "$ORIGINAL_MBR" ]] \ + || die "Kon MBR bootcode niet uit originele ISO halen." + +MBR_SIZE="$(stat -c%s "$ORIGINAL_MBR")" + +[[ "$MBR_SIZE" -eq 432 ]] \ + || die "MBR bootcode heeft onverwachte grootte: ${MBR_SIZE} bytes." + +echo "Originele Mint MBR bootcode: $MBR_SIZE bytes" + +############################################################################### +# Inspect ORIGINAL ISO boot structure +############################################################################### + +log "Controleer originele Linux Mint bootinformatie" + +xorriso \ + -indev "$ISO_PATH" \ + -report_el_torito plain \ + -report_system_area plain + +############################################################################### +# Extract ISO filesystem +############################################################################### + +log "Pak Linux Mint ISO uit" + +xorriso \ + -osirrox on \ + -indev "$ISO_PATH" \ + -extract / "$WORK_DIR" + +############################################################################### +# Locate filesystem.squashfs +############################################################################### + +log "Zoek filesystem.squashfs" + +SQUASHFS_FILE="$( + find "$WORK_DIR" \ + -type f \ + -name "filesystem.squashfs" \ + -print \ + -quit +)" + +[[ -n "$SQUASHFS_FILE" ]] \ + || die "filesystem.squashfs niet gevonden in de ISO." + +echo "Gevonden:" +echo " $SQUASHFS_FILE" + +############################################################################### +# Check required ISO structure +############################################################################### + +log "Controleer ISO-structuur" + +[[ -d "$WORK_DIR/casper" ]] \ + || die "casper directory ontbreekt." + +[[ -f "$WORK_DIR/casper/vmlinuz" ]] \ + || die "casper/vmlinuz ontbreekt." + +[[ -d "$WORK_DIR/isolinux" ]] \ + || die "isolinux directory ontbreekt." + +[[ -f "$WORK_DIR/isolinux/isolinux.bin" ]] \ + || die "isolinux/isolinux.bin ontbreekt." + +[[ -f "$WORK_DIR/isolinux/boot.cat" ]] \ + || die "isolinux/boot.cat ontbreekt." + +[[ -d "$WORK_DIR/boot/grub" ]] \ + || die "boot/grub directory ontbreekt." + +[[ -f "$WORK_DIR/boot/grub/efi.img" ]] \ + || die "boot/grub/efi.img ontbreekt." + +############################################################################### +# Detect initrd +############################################################################### + +log "Detecteer initrd" + +INITRD_FILE="$( + find "$WORK_DIR/casper" \ + -maxdepth 1 \ + -type f \ + -iname "initrd*" \ + -print \ + -quit +)" + +[[ -n "$INITRD_FILE" ]] \ + || die "Geen initrd gevonden in $WORK_DIR/casper." + +ACTUAL_INITRD_NAME="$(basename "$INITRD_FILE")" + +echo "Initrd gevonden:" +echo " $ACTUAL_INITRD_NAME" + +############################################################################### +# Unpack squashfs +############################################################################### + +log "Pak squashfs uit" + +SQUASHFS_DIR="$WORK_DIR/squashfs" + +mkdir -p "$SQUASHFS_DIR" + +unsquashfs \ + -f \ + -d "$SQUASHFS_DIR" \ + "$SQUASHFS_FILE" + +############################################################################### +# Do NOT install automatic systemd installer +# +# The boot menu is the trigger. +# +# We deliberately do NOT create: +# +# /etc/systemd/system/install-kiosk.service +# +# or its multi-user.target symlink. +############################################################################### + +log "Geen automatische systemd-installer installeren" + +############################################################################### +# Copy preseed to ISO +############################################################################### + +log "Plaats preseed op de ISO" + +PRESEED_ISO_DIR="$WORK_DIR/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" + +echo "Preseed:" +echo " $PRESEED_ISO_PATH" + +############################################################################### +# Copy preseed into live filesystem +# +# This is used by the desktop fallback installer. +############################################################################### + +log "Plaats preseed ook in live filesystem" + +cp \ + "$PRESEED_PATH" \ + "$SQUASHFS_DIR/preseed.cfg" + +chmod 644 \ + "$SQUASHFS_DIR/preseed.cfg" + +############################################################################### +# Copy installer script into live system +############################################################################### + +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" + +############################################################################### +# 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 standard Ubiquity application entry +############################################################################### + +log "Verwijder standaard Ubiquity application entry" + +UBIQUITY_DESKTOP="$SQUASHFS_DIR/usr/share/applications/ubiquity.desktop" + +if [[ -f "$UBIQUITY_DESKTOP" ]]; then + rm -f "$UBIQUITY_DESKTOP" +fi + +############################################################################### +# Create custom installer launcher +# +# This is only the fallback when the user has already booted the live desktop. +############################################################################### + +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=bash -c 'sudo debconf-set-selections /preseed.cfg && sudo DEBIAN_FRONTEND=noninteractive ubiquity --automatic' +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" + +############################################################################### +# Update application database if available +############################################################################### + +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 configuration +# +# IMPORTANT: +# +# We keep the normal Mint live environment as one option and the unattended +# installer as the second option. +# +# timeout=-1 means the UEFI menu waits forever. +############################################################################### + +log "Maak UEFI GRUB bootmenu" + +GRUB_CFG="$WORK_DIR/boot/grub/grub.cfg" + +cat > "$GRUB_CFG" << EOF +set default=0 +set timeout=-1 + +menuentry "Start Linux Mint" { + set gfxpayload=keep + linux /casper/vmlinuz boot=casper quiet splash --- + initrd /casper/${ACTUAL_INITRD_NAME} +} + +menuentry "Unattended Install Aamsveen Kiosk" { + set gfxpayload=keep + linux /casper/vmlinuz boot=casper automatic-ubiquity file=/cdrom/preseed/preseed.cfg priority=critical quiet splash --- + initrd /casper/${ACTUAL_INITRD_NAME} +} +EOF + +############################################################################### +# Display GRUB configuration +############################################################################### + +log "Controleer UEFI GRUB configuratie" + +cat "$GRUB_CFG" + +############################################################################### +# Patch grub.cfg inside EFI image +############################################################################### + +log "Controleer GRUB-configuratie in efi.img" + +EFI_IMG="$WORK_DIR/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 || true + EFI_MOUNTED=0 + fi +} + +trap cleanup_efi EXIT + +sudo mount \ + -o loop \ + "$EFI_IMG" \ + "$EFI_MOUNT" + +EFI_MOUNTED=1 + +EFI_GRUB_CFG="$( + sudo find "$EFI_MOUNT" \ + -type f \ + -name "grub.cfg" \ + -print \ + -quit +)" + +if [[ -n "$EFI_GRUB_CFG" ]]; then + + echo + echo "EFI grub.cfg gevonden:" + echo " $EFI_GRUB_CFG" + + sudo cp \ + "$GRUB_CFG" \ + "$EFI_GRUB_CFG" + + echo + echo "Nieuwe EFI grub.cfg:" + + sudo cat \ + "$EFI_GRUB_CFG" + +else + + echo + echo "WAARSCHUWING:" + echo "Geen grub.cfg gevonden in efi.img." + echo + echo "De ISO-level boot/grub/grub.cfg blijft wel aanwezig." + +fi + +cleanup_efi +trap - EXIT + +############################################################################### +# BIOS / ISOLINUX menu +# +# Mint 22.3 uses the ISOLINUX configuration hierarchy. +# +# We modify live.cfg instead of replacing the entire ISOLINUX configuration +# tree. This keeps Mint's existing BIOS menu machinery intact. +############################################################################### + +log "Maak BIOS/ISOLINUX bootmenu" + +LIVE_CFG_PATH="$WORK_DIR/isolinux/live.cfg" + +[[ -f "$LIVE_CFG_PATH" ]] \ + || die "isolinux/live.cfg ontbreekt." + +############################################################################### +# Remove an existing unattended entry if this script is run against a tree +# which already contains one. +############################################################################### + +sed -i \ + '/^[[:space:]]*label[[:space:]]\+unattended-install[[:space:]]*$/,/^[[:space:]]*$/d' \ + "$LIVE_CFG_PATH" \ + || true + +############################################################################### +# Add custom unattended installer +############################################################################### + +cat >> "$LIVE_CFG_PATH" << EOF + +# --------------------------------------------------------------------------- +# Aamsveen custom unattended installer +# --------------------------------------------------------------------------- + +label unattended-install + menu label ^Unattended Install Aamsveen Kiosk + kernel /casper/vmlinuz + append boot=casper automatic-ubiquity file=/cdrom/preseed/preseed.cfg priority=critical quiet splash --- + initrd /casper/${ACTUAL_INITRD_NAME} +EOF + +############################################################################### +# Make BIOS menu wait indefinitely +############################################################################### + +sed -i \ + '/^[[:space:]]*timeout[[:space:]]\+[0-9]\+[[:space:]]*$/d' \ + "$LIVE_CFG_PATH" + +cat >> "$LIVE_CFG_PATH" << 'EOF' + +# Wait indefinitely for the user to select a boot option. +timeout 0 +EOF + +############################################################################### +# Display BIOS configuration +############################################################################### + +log "Controleer BIOS/ISOLINUX configuratie" + +cat "$LIVE_CFG_PATH" + +############################################################################### +# Remove old squashfs +############################################################################### + +log "Verwijder oude filesystem.squashfs" + +rm -f \ + "$SQUASHFS_FILE" + +############################################################################### +# Rebuild squashfs +############################################################################### + +log "Bouw filesystem.squashfs opnieuw" + +mksquashfs \ + "$SQUASHFS_DIR" \ + "$WORK_DIR/casper/filesystem.squashfs" \ + -b 256K \ + -comp xz \ + -Xdict-size 100% \ + -no-duplicates \ + -no-xattrs \ + -noappend + +############################################################################### +# Verify squashfs +############################################################################### + +[[ -f "$WORK_DIR/casper/filesystem.squashfs" ]] \ + || die "Nieuw filesystem.squashfs is niet aangemaakt." + +############################################################################### +# Do not repack initrd +############################################################################### + +log "Initrd blijft ongewijzigd" + +echo "Initrd:" +echo " $INITRD_FILE" + +############################################################################### +# Build ISO +# +# THIS IS THE IMPORTANT CHANGE. +# +# We do NOT call isohybrid afterwards. +# +# Instead xorriso itself creates the hybrid system area. +# +# -isohybrid-mbr +# Supplies the original Mint isohybrid boot code. +# +# -isohybrid-gpt-basdat +# Creates the hybrid GPT/MBR representation directly. +# +# This is intended to avoid the 0x17 Hidden HPFS/NTFS partition generated by +# the separate isohybrid post-processing step. +############################################################################### + +log "Bouw nieuwe ISO met xorriso-native hybride bootlayout" + +cd "$WORK_DIR" + +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 \ + -x "./squashfs" \ + -x "./temp_initrd" \ + -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")" +ORIGINAL_ISO_SIZE="$(stat -c%s "$ISO_PATH")" + +echo +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: minder dan 90% van originele ISO." +fi + +############################################################################### +# Verify El Torito +############################################################################### + +log "Controleer El Torito bootinformatie" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -report_el_torito plain + +############################################################################### +# Verify system area +############################################################################### + +log "Controleer nieuw ISO system area" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -report_system_area plain + +############################################################################### +# Verify the resulting hybrid layout +############################################################################### + +log "Controleer hybride partitie-indeling" + +SYSTEM_AREA_REPORT="$WORK_DIR/system-area-report.txt" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -report_system_area plain \ + > "$SYSTEM_AREA_REPORT" + +if ! grep -q 'System area summary: MBR isohybrid cyl-align-on GPT APM' "$SYSTEM_AREA_REPORT"; then + die "Nieuwe ISO heeft niet de verwachte Mint-achtige MBR/GPT/APM hybrid layout." +fi + +if ! grep -Eq 'MBR partition[[:space:]]*:.*0x80[[:space:]]+0x00' "$SYSTEM_AREA_REPORT"; then + die "MBR partition 1 heeft niet het verwachte type 0x00." +fi + +if ! grep -Eq 'MBR partition[[:space:]]*:.*0x00[[:space:]]+0xef' "$SYSTEM_AREA_REPORT"; then + die "MBR EFI partition 2 (0xEF) ontbreekt." +fi + +echo "Hybride layout lijkt correct:" +echo " MBR + GPT + APM" +echo " MBR partition 1 type 0x00" +echo " MBR EFI partition 2 type 0xEF" + +############################################################################### +# Verify ISO boot image files +############################################################################### + +log "Controleer bootbestanden" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -find /isolinux -type f -exec lsdl -- + +############################################################################### +# Verify custom BIOS configuration +############################################################################### + +log "Controleer aangepaste BIOS-configuratie" + +TMP_CHECK_DIR="$WORK_DIR/iso-check" + +mkdir -p "$TMP_CHECK_DIR" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /isolinux/live.cfg "$TMP_CHECK_DIR/" + +echo +echo "================ /isolinux/live.cfg ================" + +cat "$TMP_CHECK_DIR/live.cfg" + +############################################################################### +# Verify custom UEFI configuration +############################################################################### + +log "Controleer aangepaste UEFI-configuratie" + +TMP_GRUB_CHECK="$TMP_CHECK_DIR/grub.cfg" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /boot/grub/grub.cfg "$TMP_GRUB_CHECK" + +echo +echo "================ /boot/grub/grub.cfg ================" + +cat "$TMP_GRUB_CHECK" + +############################################################################### +# Verify that the separate isohybrid utility was NOT used +############################################################################### + +log "Hybride bootlayout" + +echo +echo "De ISO is rechtstreeks door xorriso als hybride image gebouwd." +echo +echo "Er wordt GEEN 'isohybrid' post-processing uitgevoerd." +echo +echo "Gebruikte opties:" +echo +echo " -isohybrid-mbr" +echo " -partition_cyl_align on" +echo " -partition_offset 16" +echo " -partition_hd_cyl 185" +echo " -partition_sec_hd 32" +echo " --mbr-force-bootable" +echo " -apm-block-size 2048" +echo " -iso_mbr_part_type 0x00" +echo " -isohybrid-gpt-basdat" +echo " -isohybrid-apm-hfsplus" +echo + +############################################################################### +# Final output +############################################################################### + +echo +echo "============================================================" +echo "KLAAR" +echo "============================================================" +echo + +echo "Nieuwe ISO:" +echo +echo " $NEW_ISO_PATH" +echo + +echo "Bootmenu:" +echo +echo " Start Linux Mint" +echo " Unattended Install Aamsveen Kiosk" +echo + +echo "Het bootmenu wacht op invoer." +echo + +echo "Unattended installatie gebruikt:" +echo +echo " automatic-ubiquity" +echo " file=/cdrom/preseed/preseed.cfg" +echo " priority=critical" +echo + +echo "BELANGRIJK:" +echo +echo " Schrijf deze ISO rechtstreeks naar USB met dd." +echo +echo " sudo dd if=\"$NEW_ISO_PATH\" of=/dev/sdX bs=4M conv=fsync status=progress" +echo +echo " Gebruik NIET /dev/sdX1." +echo + +############################################################################### +# Cleanup +############################################################################### + +log "Ruim werkmap op" + +cd "$SCRIPT_DIR" + +rm -rf "$WORK_DIR" + +echo +echo "============================================================" +echo "BUILD VOLTOOID" +echo "============================================================" +echo +echo "ISO:" +echo " $NEW_ISO_PATH" +echo diff --git a/build-kiosk-iso-v7.sh b/build-kiosk-iso-v7.sh new file mode 100755 index 0000000..97e29d4 --- /dev/null +++ b/build-kiosk-iso-v7.sh @@ -0,0 +1,1148 @@ +#!/usr/bin/env bash +set -euo pipefail + +############################################################################### +# Linux Mint 22.3 Aamsveen Audio Kiosk ISO builder +# +# Version: v7 +# +# Purpose: +# +# Build a customized Linux Mint 22.3 Cinnamon ISO with: +# +# 1. Normal "Start Linux Mint" live boot +# 2. "Unattended Install Aamsveen Kiosk" boot option +# 3. Boot menu waits indefinitely for user input +# 4. UEFI + legacy BIOS boot support +# 5. USB-hybrid layout generated DIRECTLY by xorriso +# +# IMPORTANT: +# +# We deliberately DO NOT run "isohybrid" after xorriso. +# +# xorriso itself creates the hybrid MBR/GPT/APM layout. +# +# CRITICAL UEFI DESIGN: +# +# The original Linux Mint EFI image contains: +# +# boot/grub/grub.cfg +# +# containing: +# +# search --set=root --file /.disk/info +# set prefix=($root)/boot/grub +# configfile ($root)/boot/grub/grub.cfg +# +# THIS FILE MUST NOT BE REPLACED. +# +# The EFI loader first finds the ISO filesystem using /.disk/info and then +# loads the REAL ISO-level: +# +# /boot/grub/grub.cfg +# +# Therefore: +# +# /boot/grub/grub.cfg +# = our custom UEFI menu +# +# /boot/grub/efi.img +# = original Mint EFI image, untouched +# +# This fixes: +# +# error: file /casper/vmlinuz not found +# +# which occurred when the custom menu was incorrectly placed inside +# efi.img/grub.cfg. +############################################################################### + +set -o pipefail + +############################################################################### +# Configuration +############################################################################### + +BASE_ISO_FILENAME="linuxmint-22.3-cinnamon-64bit.iso" + +NEW_ISO_FILENAME="non-aamsveen-audio-kiosk_v7.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" +NEW_ISO_PATH="$SCRIPT_DIR/$NEW_ISO_FILENAME" + +############################################################################### +# Helper functions +############################################################################### + +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" +} + +############################################################################### +# Check dependencies +############################################################################### + +log "Controleer benodigde programma's" + +for cmd in \ + xorriso \ + unsquashfs \ + mksquashfs \ + find \ + sed \ + awk \ + stat \ + mount \ + umount \ + dd \ + cmp \ + sudo +do + require_command "$cmd" +done + +############################################################################### +# Check input files +############################################################################### + +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" + +############################################################################### +# Check xorriso +############################################################################### + +log "Controleer xorriso" + +XORRISO_VERSION="$(xorriso -version | head -n 1 || true)" + +echo "$XORRISO_VERSION" + +############################################################################### +# Remove previous build directory +############################################################################### + +log "Verwijder oude werkmap" + +if [[ -d "$WORK_DIR" ]]; then + rm -rf "$WORK_DIR" +fi + +mkdir -p "$WORK_DIR" + +############################################################################### +# Remove previous output ISO +############################################################################### + +if [[ -f "$NEW_ISO_PATH" ]]; then + log "Verwijder oude output ISO" + rm -f "$NEW_ISO_PATH" +fi + +############################################################################### +# Extract ORIGINAL ISO MBR boot code +# +# The original Linux Mint ISO contains the hybrid boot code in the first +# 432 bytes of the MBR. +# +# We reuse ONLY the boot code. +# +# We do NOT copy the original partition table. +# xorriso creates the new hybrid partition metadata itself. +############################################################################### + +log "Bewaar MBR bootcode van originele Linux Mint ISO" + +ORIGINAL_MBR="$WORK_DIR/mint-isohybrid-mbr.bin" + +dd \ + if="$ISO_PATH" \ + of="$ORIGINAL_MBR" \ + bs=432 \ + count=1 \ + status=none + +[[ -s "$ORIGINAL_MBR" ]] \ + || die "Kon MBR bootcode niet uit originele ISO halen." + +MBR_SIZE="$(stat -c%s "$ORIGINAL_MBR")" + +[[ "$MBR_SIZE" -eq 432 ]] \ + || die "MBR bootcode heeft onverwachte grootte: ${MBR_SIZE} bytes." + +echo "Originele Mint MBR bootcode: $MBR_SIZE bytes" + +############################################################################### +# Inspect ORIGINAL ISO boot structure +############################################################################### + +log "Controleer originele Linux Mint bootinformatie" + +xorriso \ + -indev "$ISO_PATH" \ + -report_el_torito plain \ + -report_system_area plain + +############################################################################### +# Extract ISO filesystem +############################################################################### + +log "Pak Linux Mint ISO uit" + +xorriso \ + -osirrox on \ + -indev "$ISO_PATH" \ + -extract / "$WORK_DIR" + +############################################################################### +# Locate filesystem.squashfs +############################################################################### + +log "Zoek filesystem.squashfs" + +SQUASHFS_FILE="$( + find "$WORK_DIR" \ + -type f \ + -name "filesystem.squashfs" \ + -print \ + -quit +)" + +[[ -n "$SQUASHFS_FILE" ]] \ + || die "filesystem.squashfs niet gevonden in de ISO." + +echo "Gevonden:" +echo " $SQUASHFS_FILE" + +############################################################################### +# Check required ISO structure +############################################################################### + +log "Controleer ISO-structuur" + +[[ -d "$WORK_DIR/casper" ]] \ + || die "casper directory ontbreekt." + +[[ -f "$WORK_DIR/casper/vmlinuz" ]] \ + || die "casper/vmlinuz ontbreekt." + +[[ -d "$WORK_DIR/isolinux" ]] \ + || die "isolinux directory ontbreekt." + +[[ -f "$WORK_DIR/isolinux/isolinux.bin" ]] \ + || die "isolinux/isolinux.bin ontbreekt." + +[[ -f "$WORK_DIR/isolinux/boot.cat" ]] \ + || die "isolinux/boot.cat ontbreekt." + +[[ -d "$WORK_DIR/boot/grub" ]] \ + || die "boot/grub directory ontbreekt." + +[[ -f "$WORK_DIR/boot/grub/efi.img" ]] \ + || die "boot/grub/efi.img ontbreekt." + +[[ -f "$WORK_DIR/boot/grub/grub.cfg" ]] \ + || die "boot/grub/grub.cfg ontbreekt." + +############################################################################### +# Detect initrd +############################################################################### + +log "Detecteer initrd" + +INITRD_FILE="$( + find "$WORK_DIR/casper" \ + -maxdepth 1 \ + -type f \ + -iname "initrd*" \ + -print \ + -quit +)" + +[[ -n "$INITRD_FILE" ]] \ + || die "Geen initrd gevonden in $WORK_DIR/casper." + +ACTUAL_INITRD_NAME="$(basename "$INITRD_FILE")" + +echo "Initrd gevonden:" +echo " $ACTUAL_INITRD_NAME" + +############################################################################### +# Unpack squashfs +############################################################################### + +log "Pak squashfs uit" + +SQUASHFS_DIR="$WORK_DIR/squashfs" + +mkdir -p "$SQUASHFS_DIR" + +unsquashfs \ + -f \ + -d "$SQUASHFS_DIR" \ + "$SQUASHFS_FILE" + +############################################################################### +# Do NOT install automatic systemd installer +############################################################################### + +log "Geen automatische systemd-installer installeren" + +############################################################################### +# Copy preseed to ISO +############################################################################### + +log "Plaats preseed op de ISO" + +PRESEED_ISO_DIR="$WORK_DIR/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" + +echo "Preseed:" +echo " $PRESEED_ISO_PATH" + +############################################################################### +# Copy preseed into live filesystem +############################################################################### + +log "Plaats preseed ook in live filesystem" + +cp \ + "$PRESEED_PATH" \ + "$SQUASHFS_DIR/preseed.cfg" + +chmod 644 \ + "$SQUASHFS_DIR/preseed.cfg" + +############################################################################### +# Copy installer script into live system +############################################################################### + +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" + +############################################################################### +# 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 standard Ubiquity application entry +############################################################################### + +log "Verwijder standaard Ubiquity application entry" + +UBIQUITY_DESKTOP="$SQUASHFS_DIR/usr/share/applications/ubiquity.desktop" + +if [[ -f "$UBIQUITY_DESKTOP" ]]; then + rm -f "$UBIQUITY_DESKTOP" +fi + +############################################################################### +# Create custom installer launcher +# +# This is the fallback when the live desktop has already booted. +############################################################################### + +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=bash -c 'sudo debconf-set-selections /preseed.cfg && sudo DEBIAN_FRONTEND=noninteractive ubiquity --automatic' +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" + +############################################################################### +# Update application database if available +############################################################################### + +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 configuration +# +# CRITICAL: +# +# This modifies ONLY: +# +# $WORK_DIR/boot/grub/grub.cfg +# +# It does NOT modify: +# +# $WORK_DIR/boot/grub/efi.img +# +# The original efi.img contains a loader which searches for /.disk/info and +# then loads this ISO-level grub.cfg. +############################################################################### + +log "Maak UEFI GRUB bootmenu" + +GRUB_CFG="$WORK_DIR/boot/grub/grub.cfg" + +cat > "$GRUB_CFG" << EOF +loadfont unicode + +set color_normal=white/black +set color_highlight=black/light-gray + +set default=0 +set timeout=-1 + +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 automatic-ubiquity 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)" { + 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 + } + + menuentry 'Memory test' { + linux /boot/memtest.efi + } + +fi +EOF + +############################################################################### +# Verify ISO-level GRUB configuration +############################################################################### + +log "Controleer ISO-level UEFI GRUB configuratie" + +cat "$GRUB_CFG" + +############################################################################### +# IMPORTANT: +# +# DO NOT MODIFY efi.img +# +# We verify that its original loader is still present. +############################################################################### + +log "Controleer originele EFI GRUB loader" + +EFI_IMG="$WORK_DIR/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 || 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." + +echo +echo "EFI grub.cfg gevonden:" +echo " $EFI_GRUB_CFG" + +echo +echo "================ originele EFI grub.cfg ================" + +sudo cat "$EFI_GRUB_CFG" + +echo + +############################################################################### +# Verify that the EFI loader contains the expected Mint loader commands. +############################################################################### + +grep -q \ + 'search --set=root --file /.disk/info' \ + <(sudo cat "$EFI_GRUB_CFG") \ + || die "EFI grub.cfg mist de originele Mint 'search --set=root --file /.disk/info'." + +grep -q \ + 'set prefix=(\$root)/boot/grub' \ + <(sudo cat "$EFI_GRUB_CFG") \ + || die "EFI grub.cfg mist de originele Mint GRUB prefix." + +grep -q \ + 'configfile (\$root)/boot/grub/grub.cfg' \ + <(sudo cat "$EFI_GRUB_CFG") \ + || die "EFI grub.cfg mist de originele Mint configfile loader." + +echo +echo "OK: originele EFI GRUB loader is intact." + +cleanup_efi +trap - EXIT + +############################################################################### +# BIOS / ISOLINUX menu +# +# Mint uses isolinux/live.cfg for the visible BIOS boot menu. +# +# We preserve the original Mint entries and append our custom unattended +# installer. +############################################################################### + +log "Maak BIOS/ISOLINUX bootmenu" + +LIVE_CFG_PATH="$WORK_DIR/isolinux/live.cfg" + +[[ -f "$LIVE_CFG_PATH" ]] \ + || die "isolinux/live.cfg ontbreekt." + +############################################################################### +# Remove an existing unattended entry if present. +# +# This handles rebuilding from an already modified tree. +############################################################################### + +sed -i \ + '/^[[:space:]]*label[[:space:]]\+unattended-install[[:space:]]*$/,/^[[:space:]]*$/d' \ + "$LIVE_CFG_PATH" \ + || true + +############################################################################### +# Remove existing timeout directives. +############################################################################### + +sed -i \ + '/^[[:space:]]*timeout[[:space:]]\+[0-9]\+[[:space:]]*$/d' \ + "$LIVE_CFG_PATH" + +############################################################################### +# Add custom unattended installer. +############################################################################### + +cat >> "$LIVE_CFG_PATH" << EOF + +# --------------------------------------------------------------------------- +# Aamsveen custom unattended installer +# --------------------------------------------------------------------------- + +label unattended-install + menu label ^Unattended Install Aamsveen Kiosk + kernel /casper/vmlinuz + append boot=casper automatic-ubiquity file=/cdrom/preseed/preseed.cfg priority=critical quiet splash -- + initrd /casper/${ACTUAL_INITRD_NAME} + +# Wait indefinitely for user input. +timeout 0 +EOF + +############################################################################### +# Display BIOS configuration +############################################################################### + +log "Controleer BIOS/ISOLINUX configuratie" + +cat "$LIVE_CFG_PATH" + +############################################################################### +# Remove old squashfs +############################################################################### + +log "Verwijder oude filesystem.squashfs" + +rm -f \ + "$SQUASHFS_FILE" + +############################################################################### +# Rebuild squashfs +############################################################################### + +log "Bouw filesystem.squashfs opnieuw" + +mksquashfs \ + "$SQUASHFS_DIR" \ + "$WORK_DIR/casper/filesystem.squashfs" \ + -b 256K \ + -comp xz \ + -Xdict-size 100% \ + -no-duplicates \ + -no-xattrs \ + -noappend + +############################################################################### +# Verify squashfs +############################################################################### + +[[ -f "$WORK_DIR/casper/filesystem.squashfs" ]] \ + || die "Nieuw filesystem.squashfs is niet aangemaakt." + +############################################################################### +# Do not repack initrd +############################################################################### + +log "Initrd blijft ongewijzigd" + +echo "Initrd:" +echo " $INITRD_FILE" + +############################################################################### +# Build ISO +# +# xorriso creates the hybrid image directly. +# +# There is NO isohybrid post-processing. +############################################################################### + +log "Bouw nieuwe ISO met xorriso-native hybride bootlayout" + +cd "$WORK_DIR" + +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 \ + -x "./squashfs" \ + -x "./temp_initrd" \ + -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")" +ORIGINAL_ISO_SIZE="$(stat -c%s "$ISO_PATH")" + +echo +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: minder dan 90% van originele ISO." +fi + +############################################################################### +# Verify El Torito +############################################################################### + +log "Controleer El Torito bootinformatie" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -report_el_torito plain + +############################################################################### +# Verify system area +############################################################################### + +log "Controleer nieuw ISO system area" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -report_system_area plain + +############################################################################### +# Verify resulting hybrid layout +############################################################################### + +log "Controleer hybride partitie-indeling" + +SYSTEM_AREA_REPORT="$WORK_DIR/system-area-report.txt" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -report_system_area plain \ + > "$SYSTEM_AREA_REPORT" + +if ! grep -q \ + 'System area summary: MBR isohybrid cyl-align-on GPT APM' \ + "$SYSTEM_AREA_REPORT" +then + die "Nieuwe ISO heeft niet de verwachte Mint-achtige MBR/GPT/APM hybrid layout." +fi + +if ! grep -Eq \ + 'MBR partition[[:space:]]*:.*0x80[[:space:]]+0x00' \ + "$SYSTEM_AREA_REPORT" +then + die "MBR partition 1 heeft niet het verwachte type 0x00." +fi + +if ! grep -Eq \ + 'MBR partition[[:space:]]*:.*0x00[[:space:]]+0xef' \ + "$SYSTEM_AREA_REPORT" +then + die "MBR EFI partition 2 (0xEF) ontbreekt." +fi + +echo +echo "Hybride layout lijkt correct:" +echo " MBR + GPT + APM" +echo " MBR partition 1 type 0x00" +echo " MBR EFI partition 2 type 0xEF" + +############################################################################### +# Verify boot files +############################################################################### + +log "Controleer bootbestanden" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -find /isolinux -type f -exec lsdl -- + +############################################################################### +# Create ISO verification directory +############################################################################### + +TMP_CHECK_DIR="$WORK_DIR/iso-check" + +mkdir -p "$TMP_CHECK_DIR" + +############################################################################### +# Verify custom BIOS configuration +############################################################################### + +log "Controleer aangepaste BIOS-configuratie" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /isolinux/live.cfg "$TMP_CHECK_DIR/" + +echo +echo "================ /isolinux/live.cfg ================" + +cat "$TMP_CHECK_DIR/live.cfg" + +grep -q \ + 'label unattended-install' \ + "$TMP_CHECK_DIR/live.cfg" \ + || die "BIOS unattended-install entry ontbreekt." + +grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + "$TMP_CHECK_DIR/live.cfg" \ + || die "BIOS Aamsveen menu-entry ontbreekt." + +############################################################################### +# Verify custom UEFI configuration +############################################################################### + +log "Controleer aangepaste UEFI-configuratie" + +TMP_GRUB_CHECK="$TMP_CHECK_DIR/grub.cfg" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /boot/grub/grub.cfg "$TMP_GRUB_CHECK" + +echo +echo "================ /boot/grub/grub.cfg ================" + +cat "$TMP_GRUB_CHECK" + +grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + "$TMP_GRUB_CHECK" \ + || die "UEFI Aamsveen menu-entry ontbreekt." + +grep -q \ + 'automatic-ubiquity' \ + "$TMP_GRUB_CHECK" \ + || die "UEFI automatic-ubiquity ontbreekt." + +grep -q \ + 'file=/cdrom/preseed/preseed.cfg' \ + "$TMP_GRUB_CHECK" \ + || die "UEFI preseed path ontbreekt." + +grep -q \ + 'set timeout=-1' \ + "$TMP_GRUB_CHECK" \ + || die "UEFI timeout=-1 ontbreekt." + +############################################################################### +# Verify EFI image was NOT replaced by our custom menu +############################################################################### + +log "Controleer dat efi.img origineel is gebleven" + +EFI_VERIFY_DIR="$TMP_CHECK_DIR/efi-verify" + +mkdir -p "$EFI_VERIFY_DIR/mount" + +EFI_VERIFY_MOUNTED=0 + +cleanup_verify_efi() { + if [[ "$EFI_VERIFY_MOUNTED" -eq 1 ]]; then + sudo umount "$EFI_VERIFY_DIR" 2>/dev/null || true + EFI_VERIFY_MOUNTED=0 + fi +} + +trap cleanup_verify_efi EXIT + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /boot/grub/efi.img "$EFI_VERIFY_DIR/" + +sudo mount \ + -o loop,ro \ + "$EFI_VERIFY_DIR/efi.img" \ + "$EFI_VERIFY_DIR/mount" + +EFI_VERIFY_MOUNTED=1 + +FINAL_EFI_GRUB_CFG="$( + sudo find "$EFI_VERIFY_DIR/mount" \ + -type f \ + -name "grub.cfg" \ + -print \ + -quit +)" + +[[ -n "$FINAL_EFI_GRUB_CFG" ]] \ + || die "Geen grub.cfg gevonden in de EFI image van de nieuwe ISO." + +echo +echo "================ efi.img grub.cfg ================" + +sudo cat "$FINAL_EFI_GRUB_CFG" + +grep -q \ + 'search --set=root --file /.disk/info' \ + <(sudo cat "$FINAL_EFI_GRUB_CFG") \ + || die "Nieuwe ISO EFI loader mist Mint search command." + +grep -q \ + 'configfile (\$root)/boot/grub/grub.cfg' \ + <(sudo cat "$FINAL_EFI_GRUB_CFG") \ + || die "Nieuwe ISO EFI loader mist configfile command." + +if grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + <(sudo cat "$FINAL_EFI_GRUB_CFG") +then + die "FOUT: custom Aamsveen menu is ten onrechte in efi.img terechtgekomen." +fi + +echo +echo "OK: efi.img bevat alleen de originele Mint GRUB loader." + +cleanup_verify_efi +trap - EXIT + +############################################################################### +# Verify the kernel and initrd are actually present in the finished ISO +############################################################################### + +log "Controleer kernel en initrd in eind-ISO" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -ls \ + /casper/vmlinuz \ + /casper/"$ACTUAL_INITRD_NAME" + +############################################################################### +# Verify preseed is present +############################################################################### + +log "Controleer preseed in eind-ISO" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -ls \ + /preseed/preseed.cfg + +############################################################################### +# Verify installer script is present inside squashfs +############################################################################### + +log "Controleer installer script in squashfs" + +[[ -f "$SQUASHFS_DIR/usr/local/bin/install-kiosk-nl.sh" ]] \ + || die "install-kiosk-nl.sh ontbreekt in live filesystem." + +[[ -x "$SQUASHFS_DIR/usr/local/bin/install-kiosk-nl.sh" ]] \ + || die "install-kiosk-nl.sh is niet executable." + +############################################################################### +# Verify that the separate isohybrid utility was NOT used +############################################################################### + +log "Hybride bootlayout" + +echo +echo "De ISO is rechtstreeks door xorriso als hybride image gebouwd." +echo +echo "Er wordt GEEN 'isohybrid' post-processing uitgevoerd." +echo +echo "Gebruikte opties:" +echo +echo " -isohybrid-mbr" +echo " -partition_cyl_align on" +echo " -partition_offset 16" +echo " -partition_hd_cyl 185" +echo " -partition_sec_hd 32" +echo " --mbr-force-bootable" +echo " -apm-block-size 2048" +echo " -iso_mbr_part_type 0x00" +echo " -isohybrid-gpt-basdat" +echo " -isohybrid-apm-hfsplus" +echo + +############################################################################### +# Final output +############################################################################### + +echo +echo "============================================================" +echo "KLAAR" +echo "============================================================" +echo + +echo "Nieuwe ISO:" +echo +echo " $NEW_ISO_PATH" +echo + +echo "UEFI bootmenu:" +echo +echo " Start Linux Mint 22.3 Cinnamon 64-bit" +echo " Unattended Install Aamsveen Kiosk" +echo " Start Linux Mint 22.3 Cinnamon 64-bit (compatibility mode)" +echo " OEM install (for manufacturers)" +echo + +echo "BIOS bootmenu:" +echo +echo " Start Linux Mint" +echo " Start Linux Mint in compatibility mode" +echo " OEM install" +echo " Hardware Detection" +echo " Boot from local drive" +echo " Memory test" +echo " Unattended Install Aamsveen Kiosk" +echo + +echo "UEFI menu timeout:" +echo " -1 (wacht oneindig)" +echo + +echo "BIOS menu timeout:" +echo " 0 (wacht oneindig)" +echo + +echo "Unattended installatie gebruikt:" +echo +echo " automatic-ubiquity" +echo " file=/cdrom/preseed/preseed.cfg" +echo " priority=critical" +echo + +echo "BELANGRIJK:" +echo +echo " Schrijf deze ISO rechtstreeks naar USB met dd." +echo +echo " sudo dd if=\"$NEW_ISO_PATH\" of=/dev/sdX bs=4M conv=fsync status=progress" +echo +echo " Gebruik NIET /dev/sdX1." +echo + +############################################################################### +# Cleanup +############################################################################### + +log "Ruim werkmap op" + +cd "$SCRIPT_DIR" + +rm -rf "$WORK_DIR" + +echo +echo "============================================================" +echo "BUILD VOLTOOID" +echo "============================================================" +echo +echo "ISO:" +echo " $NEW_ISO_PATH" diff --git a/build-kiosk-iso-v8.sh b/build-kiosk-iso-v8.sh new file mode 100755 index 0000000..510bbe1 --- /dev/null +++ b/build-kiosk-iso-v8.sh @@ -0,0 +1,1089 @@ +#!/usr/bin/env bash +set -euo pipefail + +############################################################################### +# Linux Mint 22.3 Aamsveen Audio Kiosk ISO builder +# +# VERSION: v8 +# +# Host: +# NixOS 26.11 unstable +# +# Guest: +# Linux Mint 22.3 Cinnamon 64-bit +# +# Design: +# +# BIOS: +# ISO +# -> ISOLINUX +# -> /isolinux/live.cfg +# -> Linux kernel +# -> casper +# -> Ubiquity +# +# UEFI: +# ISO +# -> /boot/grub/efi.img +# -> ORIGINAL Mint EFI GRUB loader +# -> /boot/grub/grub.cfg +# -> Linux kernel +# -> casper +# -> Ubiquity +# +# CRITICAL: +# +# boot/grub/efi.img is NEVER modified. +# +# The custom UEFI menu lives ONLY in: +# +# /boot/grub/grub.cfg +# +# The custom BIOS menu lives in: +# +# /isolinux/live.cfg +# +# xorriso creates the hybrid ISO directly. +# isohybrid is NOT run afterwards. +############################################################################### + +set -o pipefail + +############################################################################### +# Configuration +############################################################################### + +BASE_ISO_FILENAME="linuxmint-22.3-cinnamon-64bit.iso" +NEW_ISO_FILENAME="non-aamsveen-audio-kiosk_v8.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" +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" +} + +############################################################################### +# Dependency check +# +# NixOS note: +# +# This script intentionally does NOT assume Debian/Ubuntu package paths. +# xorriso, squashfs-tools, etc. must simply be available in PATH. +# +# On NixOS, if necessary: +# +# 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 +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 +############################################################################### + +log "Verwijder oude werkmap" + +if mountpoint -q "$WORK_DIR/iso-check/efi-verify/mount"; then + sudo umount "$WORK_DIR/iso-check/efi-verify/mount" +fi + +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. +# The partition tables themselves are generated by xorriso. +############################################################################### + +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" + +xorriso \ + -osirrox on \ + -indev "$ISO_PATH" \ + -extract / "$WORK_DIR" + +############################################################################### +# Verify required ISO structure +############################################################################### + +log "Controleer ISO-structuur" + +[[ -d "$WORK_DIR/casper" ]] \ + || die "casper directory ontbreekt." + +[[ -f "$WORK_DIR/casper/vmlinuz" ]] \ + || die "casper/vmlinuz ontbreekt." + +[[ -d "$WORK_DIR/isolinux" ]] \ + || die "isolinux directory ontbreekt." + +[[ -f "$WORK_DIR/isolinux/isolinux.bin" ]] \ + || die "isolinux/isolinux.bin ontbreekt." + +[[ -f "$WORK_DIR/isolinux/boot.cat" ]] \ + || die "isolinux/boot.cat ontbreekt." + +[[ -f "$WORK_DIR/isolinux/live.cfg" ]] \ + || die "isolinux/live.cfg ontbreekt." + +[[ -d "$WORK_DIR/boot/grub" ]] \ + || die "boot/grub ontbreekt." + +[[ -f "$WORK_DIR/boot/grub/efi.img" ]] \ + || die "boot/grub/efi.img ontbreekt." + +[[ -f "$WORK_DIR/boot/grub/grub.cfg" ]] \ + || die "boot/grub/grub.cfg ontbreekt." + +############################################################################### +# Locate filesystem.squashfs +############################################################################### + +log "Zoek filesystem.squashfs" + +SQUASHFS_FILE="$( + find "$WORK_DIR" \ + -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 "$WORK_DIR/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" + +SQUASHFS_DIR="$WORK_DIR/squashfs" + +mkdir -p "$SQUASHFS_DIR" + +unsquashfs \ + -f \ + -d "$SQUASHFS_DIR" \ + "$SQUASHFS_FILE" + +############################################################################### +# Install preseed into ISO +############################################################################### + +log "Plaats preseed op ISO" + +PRESEED_ISO_DIR="$WORK_DIR/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 +# +# /preseed.cfg is deliberately retained because the desktop fallback uses it. +############################################################################### + +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" + +############################################################################### +# 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 +# +# IMPORTANT: +# +# This is a real shell command executed after the live desktop is running. +# Therefore shell syntax IS valid here. +############################################################################### + +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=bash -c 'sudo debconf-set-selections /preseed.cfg && sudo DEBIAN_FRONTEND=noninteractive ubiquity --automatic' +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" + +############################################################################### +# Update desktop database if available +############################################################################### + +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. +# +# The original Mint EFI loader is expected to contain: +# +# search --set=root --file /.disk/info +# set prefix=($root)/boot/grub +# configfile ($root)/boot/grub/grub.cfg +# +# Therefore the ISO-level grub.cfg is the real menu. +############################################################################### + +log "Maak UEFI GRUB bootmenu" + +GRUB_CFG="$WORK_DIR/boot/grub/grub.cfg" + +cat > "$GRUB_CFG" << EOF +loadfont unicode + +set color_normal=white/black +set color_highlight=black/light-gray + +set default=0 +set timeout=-1 + +menuentry "Start Linux Mint 22.3 Cinnamon 64-bit" --class linuxmint { + set gfxpayload=keep + linux /casper/vmlinuz boot=casper username=mint hostname=mint quiet splash -- + initrd /casper/${ACTUAL_INITRD_NAME} +} + +menuentry "Unattended Install Aamsveen Kiosk" --class linuxmint { + set gfxpayload=keep + linux /casper/vmlinuz boot=casper 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)" --class linuxmint { + set gfxpayload=keep + linux /casper/vmlinuz boot=casper username=mint hostname=mint 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 username=mint hostname=mint 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 +############################################################################### + +log "Controleer UEFI GRUB" + +grep -q \ + 'Unattended Install Aamsveen Kiosk' \ + "$GRUB_CFG" \ + || die "UEFI unattended entry ontbreekt." + +grep -q \ + 'automatic-ubiquity' \ + "$GRUB_CFG" \ + || die "automatic-ubiquity ontbreekt." + +grep -q \ + 'noprompt' \ + "$GRUB_CFG" \ + || die "noprompt ontbreekt." + +grep -q \ + 'file=/cdrom/preseed/preseed.cfg' \ + "$GRUB_CFG" \ + || die "UEFI preseed path ontbreekt." + +grep -q \ + 'set timeout=-1' \ + "$GRUB_CFG" \ + || die "UEFI timeout=-1 ontbreekt." + +############################################################################### +# Verify original EFI image BEFORE ISO creation +############################################################################### + +log "Controleer originele EFI loader" + +EFI_IMG="$WORK_DIR/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 || 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 +# +# We know from the original Mint ISO inspection that live.cfg is the visible +# menu configuration. +############################################################################### + +log "Maak BIOS/ISOLINUX bootmenu" + +LIVE_CFG_PATH="$WORK_DIR/isolinux/live.cfg" + +[[ -f "$LIVE_CFG_PATH" ]] \ + || die "isolinux/live.cfg ontbreekt." + +############################################################################### +# Remove previous Aamsveen entry if rebuilding +############################################################################### + +TMP_LIVE_CFG="$WORK_DIR/isolinux/live.cfg.tmp" + +awk ' +BEGIN { skip=0 } + +/^[[:space:]]*# ---------------------------------------------------------------------------$/ { + if (skip == 1) { + skip=0 + } +} + +/^[[:space:]]*label[[:space:]]+unattended-install[[:space:]]*$/ { + skip=1 + next +} + +skip == 1 { + if ($0 ~ /^[[:space:]]*$/) { + skip=0 + } + next +} + +{ + print +} +' "$LIVE_CFG_PATH" > "$TMP_LIVE_CFG" + +mv \ + "$TMP_LIVE_CFG" \ + "$LIVE_CFG_PATH" + +############################################################################### +# Remove existing timeout directives. +# +# We want the BIOS menu to wait indefinitely. +############################################################################### + +sed -i \ + '/^[[:space:]]*timeout[[:space:]]\+[0-9]\+[[:space:]]*$/d' \ + "$LIVE_CFG_PATH" + +############################################################################### +# Add unattended entry +############################################################################### + +cat >> "$LIVE_CFG_PATH" << EOF + +# --------------------------------------------------------------------------- +# Aamsveen custom unattended installer +# --------------------------------------------------------------------------- + +label unattended-install + menu label ^Unattended Install Aamsveen Kiosk + 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 \ + '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." + +############################################################################### +# 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" \ + "$WORK_DIR/casper/filesystem.squashfs" \ + -b 256K \ + -comp xz \ + -Xdict-size 100% \ + -no-duplicates \ + -no-xattrs \ + -noappend + +[[ -f "$WORK_DIR/casper/filesystem.squashfs" ]] \ + || die "Nieuw filesystem.squashfs ontbreekt." + +############################################################################### +# Build ISO +############################################################################### + +log "Bouw nieuwe ISO met xorriso-native hybrid layout" + +cd "$WORK_DIR" + +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 \ + -x "./squashfs" \ + -x "./temp_initrd" \ + -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 -q \ + 'System area summary: MBR isohybrid cyl-align-on GPT APM' \ + "$SYSTEM_AREA_REPORT" \ + || die "MBR/GPT/APM hybrid layout ontbreekt." + +############################################################################### +# Verify boot files +############################################################################### + +log "Controleer bootbestanden" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -find /isolinux -type f -exec lsdl -- + +############################################################################### +# Verify BIOS config inside final ISO +############################################################################### + +log "Controleer BIOS configuratie in eind-ISO" + +TMP_CHECK_DIR="$WORK_DIR/iso-check" + +mkdir -p "$TMP_CHECK_DIR" + +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 \ + 'automatic-ubiquity' \ + "$FINAL_LIVE_CFG" \ + || die "Finale ISO mist BIOS automatic-ubiquity." + +############################################################################### +# 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 \ + 'file=/cdrom/preseed/preseed.cfg' \ + "$TMP_GRUB_CHECK" \ + || die "Finale ISO mist UEFI preseed path." + +############################################################################### +# Verify EFI image remains original +############################################################################### + +log "Controleer dat efi.img niet is aangepast" + +EFI_VERIFY_DIR="$TMP_CHECK_DIR/efi-verify" + +mkdir -p "$EFI_VERIFY_DIR/mount" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /boot/grub/efi.img "$EFI_VERIFY_DIR/" + +sudo mount \ + -o loop,ro \ + "$EFI_VERIFY_DIR/efi.img" \ + "$EFI_VERIFY_DIR/mount" + +FINAL_EFI_GRUB_CFG="$( + sudo find "$EFI_VERIFY_DIR/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" +)" + +sudo umount \ + "$EFI_VERIFY_DIR/mount" + +grep -q \ + 'search --set=root --file /.disk/info' \ + <<< "$FINAL_EFI_CONTENT" \ + || die "Finale EFI loader mist Mint search." + +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 + +############################################################################### +# Verify kernel/initrd +############################################################################### + +log "Controleer kernel en initrd" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -ls \ + /casper/vmlinuz \ + /casper/"$ACTUAL_INITRD_NAME" + +############################################################################### +# Verify preseed +############################################################################### + +log "Controleer preseed" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -ls \ + /preseed/preseed.cfg + +############################################################################### +# Verify installer script in squashfs +############################################################################### + +[[ -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" +echo " Compatibility mode" +echo " OEM" +echo " UEFI Firmware Settings" +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" +echo +echo "UEFI timeout:" +echo " -1 = oneindig" +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 "Hybrid ISO:" +echo " MBR + GPT + APM" +echo " xorriso native" +echo " GEEN isohybrid post-processing" +echo + +############################################################################### +# Cleanup +############################################################################### + +log "Ruim werkmap op" + +cd "$SCRIPT_DIR" + +rm -rf "$WORK_DIR" + +echo +echo "============================================================" +echo "KLAAR" +echo "============================================================" +echo +echo "ISO:" +echo " $NEW_ISO_PATH" +echo diff --git a/build-kiosk-iso.sh b/build-kiosk-iso.sh new file mode 100755 index 0000000..cf36dfa --- /dev/null +++ b/build-kiosk-iso.sh @@ -0,0 +1,882 @@ +#!/usr/bin/env bash +set -euo pipefail + +############################################################################### +# Linux Mint 22.3 Aamsveen Audio Kiosk ISO builder +# +# Purpose: +# Build a customized Linux Mint 22.3 Cinnamon ISO with: +# +# 1. Normal "Start Linux Mint" live boot +# 2. "Unattended Install Aamsveen Kiosk" boot option +# 3. Boot menu waits indefinitely for user input +# 4. UEFI + legacy BIOS boot support +# 5. USB-hybrid layout generated DIRECTLY by xorriso +# +# IMPORTANT: +# +# We deliberately DO NOT run "isohybrid" after xorriso. +# +# The previous build did: +# +# xorriso ... -o output.iso . +# isohybrid output.iso +# +# That produced an MBR partition of type 0x17 on the resulting USB. +# The Acer TravelMate P614 firmware appears to dislike the resulting +# disk representation. +# +# Instead we let xorriso create the hybrid layout itself: +# +# -isohybrid-mbr +# -isohybrid-gpt-basdat +# +# The first 432 bytes of the ORIGINAL Linux Mint ISO are used as the +# isohybrid MBR boot code. This keeps the boot-system-area as close as +# possible to the known-good Mint ISO. +############################################################################### + +set -o pipefail + +############################################################################### +# Configuration +############################################################################### + +BASE_ISO_FILENAME="linuxmint-22.3-cinnamon-64bit.iso" + +NEW_ISO_FILENAME="non-aamsveen-audio-kiosk_v5.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" +NEW_ISO_PATH="$SCRIPT_DIR/$NEW_ISO_FILENAME" + +############################################################################### +# Helper functions +############################################################################### + +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" +} + +############################################################################### +# Check dependencies +############################################################################### + +log "Controleer benodigde programma's" + +for cmd in \ + xorriso \ + unsquashfs \ + mksquashfs \ + find \ + sed \ + awk \ + stat \ + mount \ + umount \ + dd \ + cmp \ + sudo +do + require_command "$cmd" +done + +############################################################################### +# Check input files +############################################################################### + +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" + +############################################################################### +# Check xorriso +############################################################################### + +log "Controleer xorriso" + +XORRISO_VERSION="$(xorriso -version | head -n 1 || true)" + +echo "$XORRISO_VERSION" + +############################################################################### +# Remove previous build directory +############################################################################### + +log "Verwijder oude werkmap" + +if [[ -d "$WORK_DIR" ]]; then + rm -rf "$WORK_DIR" +fi + +mkdir -p "$WORK_DIR" + +############################################################################### +# Remove previous output ISO +############################################################################### + +if [[ -f "$NEW_ISO_PATH" ]]; then + log "Verwijder oude output ISO" + rm -f "$NEW_ISO_PATH" +fi + +############################################################################### +# Extract the ORIGINAL ISO MBR boot code +# +# Linux Mint's ISO already contains the boot-system-area that was known to +# work with the Mint ISO. +# +# We preserve the first 432 bytes and give them to xorriso with: +# +# -isohybrid-mbr +# +# The partition table itself is NOT copied. xorriso creates the new partition +# metadata appropriate for the rebuilt ISO. +############################################################################### + +log "Bewaar MBR bootcode van originele Linux Mint ISO" + +ORIGINAL_MBR="$WORK_DIR/mint-isohybrid-mbr.bin" + +dd \ + if="$ISO_PATH" \ + of="$ORIGINAL_MBR" \ + bs=432 \ + count=1 \ + status=none + +[[ -s "$ORIGINAL_MBR" ]] \ + || die "Kon MBR bootcode niet uit originele ISO halen." + +MBR_SIZE="$(stat -c%s "$ORIGINAL_MBR")" + +[[ "$MBR_SIZE" -eq 432 ]] \ + || die "MBR bootcode heeft onverwachte grootte: ${MBR_SIZE} bytes." + +echo "Originele Mint MBR bootcode: $MBR_SIZE bytes" + +############################################################################### +# Inspect ORIGINAL ISO boot structure +############################################################################### + +log "Controleer originele Linux Mint bootinformatie" + +xorriso \ + -indev "$ISO_PATH" \ + -report_el_torito plain \ + -report_system_area plain + +############################################################################### +# Extract ISO filesystem +############################################################################### + +log "Pak Linux Mint ISO uit" + +xorriso \ + -osirrox on \ + -indev "$ISO_PATH" \ + -extract / "$WORK_DIR" + +############################################################################### +# Locate filesystem.squashfs +############################################################################### + +log "Zoek filesystem.squashfs" + +SQUASHFS_FILE="$( + find "$WORK_DIR" \ + -type f \ + -name "filesystem.squashfs" \ + -print \ + -quit +)" + +[[ -n "$SQUASHFS_FILE" ]] \ + || die "filesystem.squashfs niet gevonden in de ISO." + +echo "Gevonden:" +echo " $SQUASHFS_FILE" + +############################################################################### +# Check required ISO structure +############################################################################### + +log "Controleer ISO-structuur" + +[[ -d "$WORK_DIR/casper" ]] \ + || die "casper directory ontbreekt." + +[[ -f "$WORK_DIR/casper/vmlinuz" ]] \ + || die "casper/vmlinuz ontbreekt." + +[[ -d "$WORK_DIR/isolinux" ]] \ + || die "isolinux directory ontbreekt." + +[[ -f "$WORK_DIR/isolinux/isolinux.bin" ]] \ + || die "isolinux/isolinux.bin ontbreekt." + +[[ -f "$WORK_DIR/isolinux/boot.cat" ]] \ + || die "isolinux/boot.cat ontbreekt." + +[[ -d "$WORK_DIR/boot/grub" ]] \ + || die "boot/grub directory ontbreekt." + +[[ -f "$WORK_DIR/boot/grub/efi.img" ]] \ + || die "boot/grub/efi.img ontbreekt." + +############################################################################### +# Detect initrd +############################################################################### + +log "Detecteer initrd" + +INITRD_FILE="$( + find "$WORK_DIR/casper" \ + -maxdepth 1 \ + -type f \ + -iname "initrd*" \ + -print \ + -quit +)" + +[[ -n "$INITRD_FILE" ]] \ + || die "Geen initrd gevonden in $WORK_DIR/casper." + +ACTUAL_INITRD_NAME="$(basename "$INITRD_FILE")" + +echo "Initrd gevonden:" +echo " $ACTUAL_INITRD_NAME" + +############################################################################### +# Unpack squashfs +############################################################################### + +log "Pak squashfs uit" + +SQUASHFS_DIR="$WORK_DIR/squashfs" + +mkdir -p "$SQUASHFS_DIR" + +unsquashfs \ + -f \ + -d "$SQUASHFS_DIR" \ + "$SQUASHFS_FILE" + +############################################################################### +# Do NOT install automatic systemd installer +# +# The boot menu is the trigger. +# +# We deliberately do NOT create: +# +# /etc/systemd/system/install-kiosk.service +# +# or its multi-user.target symlink. +############################################################################### + +log "Geen automatische systemd-installer installeren" + +############################################################################### +# Copy preseed to ISO +############################################################################### + +log "Plaats preseed op de ISO" + +PRESEED_ISO_DIR="$WORK_DIR/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" + +echo "Preseed:" +echo " $PRESEED_ISO_PATH" + +############################################################################### +# Copy preseed into live filesystem +# +# This is used by the desktop fallback installer. +############################################################################### + +log "Plaats preseed ook in live filesystem" + +cp \ + "$PRESEED_PATH" \ + "$SQUASHFS_DIR/preseed.cfg" + +chmod 644 \ + "$SQUASHFS_DIR/preseed.cfg" + +############################################################################### +# Copy installer script into live system +############################################################################### + +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" + +############################################################################### +# 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 standard Ubiquity application entry +############################################################################### + +log "Verwijder standaard Ubiquity application entry" + +UBIQUITY_DESKTOP="$SQUASHFS_DIR/usr/share/applications/ubiquity.desktop" + +if [[ -f "$UBIQUITY_DESKTOP" ]]; then + rm -f "$UBIQUITY_DESKTOP" +fi + +############################################################################### +# Create custom installer launcher +# +# This is only the fallback when the user has already booted the live desktop. +############################################################################### + +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=bash -c 'sudo debconf-set-selections /preseed.cfg && sudo DEBIAN_FRONTEND=noninteractive ubiquity --automatic' +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" + +############################################################################### +# Update application database if available +############################################################################### + +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 configuration +# +# IMPORTANT: +# +# We keep the normal Mint live environment as one option and the unattended +# installer as the second option. +# +# timeout=-1 means the UEFI menu waits forever. +############################################################################### + +log "Maak UEFI GRUB bootmenu" + +GRUB_CFG="$WORK_DIR/boot/grub/grub.cfg" + +cat > "$GRUB_CFG" << EOF +set default=0 +set timeout=-1 + +menuentry "Start Linux Mint" { + set gfxpayload=keep + linux /casper/vmlinuz boot=casper quiet splash --- + initrd /casper/${ACTUAL_INITRD_NAME} +} + +menuentry "Unattended Install Aamsveen Kiosk" { + set gfxpayload=keep + linux /casper/vmlinuz boot=casper automatic-ubiquity file=/cdrom/preseed/preseed.cfg priority=critical quiet splash --- + initrd /casper/${ACTUAL_INITRD_NAME} +} +EOF + +############################################################################### +# Display GRUB configuration +############################################################################### + +log "Controleer UEFI GRUB configuratie" + +cat "$GRUB_CFG" + +############################################################################### +# Patch grub.cfg inside EFI image +############################################################################### + +log "Controleer GRUB-configuratie in efi.img" + +EFI_IMG="$WORK_DIR/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 || true + EFI_MOUNTED=0 + fi +} + +trap cleanup_efi EXIT + +sudo mount \ + -o loop \ + "$EFI_IMG" \ + "$EFI_MOUNT" + +EFI_MOUNTED=1 + +EFI_GRUB_CFG="$( + sudo find "$EFI_MOUNT" \ + -type f \ + -name "grub.cfg" \ + -print \ + -quit +)" + +if [[ -n "$EFI_GRUB_CFG" ]]; then + + echo + echo "EFI grub.cfg gevonden:" + echo " $EFI_GRUB_CFG" + + sudo cp \ + "$GRUB_CFG" \ + "$EFI_GRUB_CFG" + + echo + echo "Nieuwe EFI grub.cfg:" + + sudo cat \ + "$EFI_GRUB_CFG" + +else + + echo + echo "WAARSCHUWING:" + echo "Geen grub.cfg gevonden in efi.img." + echo + echo "De ISO-level boot/grub/grub.cfg blijft wel aanwezig." + +fi + +cleanup_efi +trap - EXIT + +############################################################################### +# BIOS / ISOLINUX menu +# +# Mint 22.3 uses the ISOLINUX configuration hierarchy. +# +# We modify live.cfg instead of replacing the entire ISOLINUX configuration +# tree. This keeps Mint's existing BIOS menu machinery intact. +############################################################################### + +log "Maak BIOS/ISOLINUX bootmenu" + +LIVE_CFG_PATH="$WORK_DIR/isolinux/live.cfg" + +[[ -f "$LIVE_CFG_PATH" ]] \ + || die "isolinux/live.cfg ontbreekt." + +############################################################################### +# Remove an existing unattended entry if this script is run against a tree +# which already contains one. +############################################################################### + +sed -i \ + '/^[[:space:]]*label[[:space:]]\+unattended-install[[:space:]]*$/,/^[[:space:]]*$/d' \ + "$LIVE_CFG_PATH" \ + || true + +############################################################################### +# Add custom unattended installer +############################################################################### + +cat >> "$LIVE_CFG_PATH" << EOF + +# --------------------------------------------------------------------------- +# Aamsveen custom unattended installer +# --------------------------------------------------------------------------- + +label unattended-install + menu label ^Unattended Install Aamsveen Kiosk + kernel /casper/vmlinuz + append boot=casper automatic-ubiquity file=/cdrom/preseed/preseed.cfg priority=critical quiet splash --- + initrd /casper/${ACTUAL_INITRD_NAME} +EOF + +############################################################################### +# Make BIOS menu wait indefinitely +############################################################################### + +sed -i \ + '/^[[:space:]]*timeout[[:space:]]\+[0-9]\+[[:space:]]*$/d' \ + "$LIVE_CFG_PATH" + +cat >> "$LIVE_CFG_PATH" << 'EOF' + +# Wait indefinitely for the user to select a boot option. +timeout 0 +EOF + +############################################################################### +# Display BIOS configuration +############################################################################### + +log "Controleer BIOS/ISOLINUX configuratie" + +cat "$LIVE_CFG_PATH" + +############################################################################### +# Remove old squashfs +############################################################################### + +log "Verwijder oude filesystem.squashfs" + +rm -f \ + "$SQUASHFS_FILE" + +############################################################################### +# Rebuild squashfs +############################################################################### + +log "Bouw filesystem.squashfs opnieuw" + +mksquashfs \ + "$SQUASHFS_DIR" \ + "$WORK_DIR/casper/filesystem.squashfs" \ + -b 256K \ + -comp xz \ + -Xdict-size 100% \ + -no-duplicates \ + -no-xattrs \ + -noappend + +############################################################################### +# Verify squashfs +############################################################################### + +[[ -f "$WORK_DIR/casper/filesystem.squashfs" ]] \ + || die "Nieuw filesystem.squashfs is niet aangemaakt." + +############################################################################### +# Do not repack initrd +############################################################################### + +log "Initrd blijft ongewijzigd" + +echo "Initrd:" +echo " $INITRD_FILE" + +############################################################################### +# Build ISO +# +# THIS IS THE IMPORTANT CHANGE. +# +# We do NOT call isohybrid afterwards. +# +# Instead xorriso itself creates the hybrid system area. +# +# -isohybrid-mbr +# Supplies the original Mint isohybrid boot code. +# +# -isohybrid-gpt-basdat +# Creates the hybrid GPT/MBR representation directly. +# +# This is intended to avoid the 0x17 Hidden HPFS/NTFS partition generated by +# the separate isohybrid post-processing step. +############################################################################### + +log "Bouw nieuwe ISO met xorriso-native hybride bootlayout" + +cd "$WORK_DIR" + +xorriso -as mkisofs \ + -r \ + -V "NonAamsveenAudioKiosk" \ + -J \ + -l \ + -b isolinux/isolinux.bin \ + -c isolinux/boot.cat \ + -no-emul-boot \ + -boot-load-size 4 \ + -boot-info-table \ + -eltorito-alt-boot \ + -e boot/grub/efi.img \ + -no-emul-boot \ + -isohybrid-mbr "$ORIGINAL_MBR" \ + -isohybrid-gpt-basdat \ + -x "./squashfs" \ + -x "./temp_initrd" \ + -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")" +ORIGINAL_ISO_SIZE="$(stat -c%s "$ISO_PATH")" + +echo +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: minder dan 90% van originele ISO." +fi + +############################################################################### +# Verify El Torito +############################################################################### + +log "Controleer El Torito bootinformatie" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -report_el_torito plain + +############################################################################### +# Verify system area +############################################################################### + +log "Controleer nieuw ISO system area" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -report_system_area plain + +############################################################################### +# Verify ISO boot image files +############################################################################### + +log "Controleer bootbestanden" + +xorriso \ + -indev "$NEW_ISO_PATH" \ + -find /isolinux -type f -exec lsdl -- + +############################################################################### +# Verify custom BIOS configuration +############################################################################### + +log "Controleer aangepaste BIOS-configuratie" + +TMP_CHECK_DIR="$WORK_DIR/iso-check" + +mkdir -p "$TMP_CHECK_DIR" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /isolinux/live.cfg "$TMP_CHECK_DIR/" + +echo +echo "================ /isolinux/live.cfg ================" + +cat "$TMP_CHECK_DIR/live.cfg" + +############################################################################### +# Verify custom UEFI configuration +############################################################################### + +log "Controleer aangepaste UEFI-configuratie" + +TMP_GRUB_CHECK="$TMP_CHECK_DIR/grub.cfg" + +xorriso \ + -osirrox on \ + -indev "$NEW_ISO_PATH" \ + -cpx /boot/grub/grub.cfg "$TMP_GRUB_CHECK" + +echo +echo "================ /boot/grub/grub.cfg ================" + +cat "$TMP_GRUB_CHECK" + +############################################################################### +# Verify that the separate isohybrid utility was NOT used +############################################################################### + +log "Hybride bootlayout" + +echo +echo "De ISO is rechtstreeks door xorriso als hybride image gebouwd." +echo +echo "Er wordt GEEN 'isohybrid' post-processing uitgevoerd." +echo +echo "Gebruikte opties:" +echo +echo " -isohybrid-mbr" +echo " -isohybrid-gpt-basdat" +echo + +############################################################################### +# Final output +############################################################################### + +echo +echo "============================================================" +echo "KLAAR" +echo "============================================================" +echo + +echo "Nieuwe ISO:" +echo +echo " $NEW_ISO_PATH" +echo + +echo "Bootmenu:" +echo +echo " Start Linux Mint" +echo " Unattended Install Aamsveen Kiosk" +echo + +echo "Het bootmenu wacht op invoer." +echo + +echo "Unattended installatie gebruikt:" +echo +echo " automatic-ubiquity" +echo " file=/cdrom/preseed/preseed.cfg" +echo " priority=critical" +echo + +echo "BELANGRIJK:" +echo +echo " Schrijf deze ISO rechtstreeks naar USB met dd." +echo +echo " sudo dd if=\"$NEW_ISO_PATH\" of=/dev/sdX bs=4M conv=fsync status=progress" +echo +echo " Gebruik NIET /dev/sdX1." +echo + +############################################################################### +# Cleanup +############################################################################### + +log "Ruim werkmap op" + +cd "$SCRIPT_DIR" + +rm -rf "$WORK_DIR" + +echo +echo "============================================================" +echo "BUILD VOLTOOID" +echo "============================================================" +echo +echo "ISO:" +echo " $NEW_ISO_PATH" +echo diff --git a/install-kiosk-nl.sh b/install-kiosk-nl.sh new file mode 100755 index 0000000..584941e --- /dev/null +++ b/install-kiosk-nl.sh @@ -0,0 +1,497 @@ +#!/bin/bash +# +# install-kiosk.sh +# +# Installatiescript voor de kiosk-laptop (geluidssysteem gemeenschapshal). +# Voert stap 2 t/m 9 uit van de "Kiosk Laptop Setup Guide". +# Voer dit script uit NA installatie van Linux Mint Cinnamon, ingelogd +# op het av-admin-account (stap 1 van de handleiding). +# +# Gebruik: +# 1. Pas hieronder de INSTELLINGEN aan (goedgekeurde URL's en pop-upbeleid) +# 2. chmod +x install-kiosk.sh +# 3. sudo ./install-kiosk.sh (vraagt bevestiging) +# of: sudo ./install-kiosk.sh --yes (slaat bevestiging over) +# +# Het script kan in principe veilig opnieuw worden uitgevoerd, maar +# controleer telkens de uitvoer. + +set -euo pipefail + +# ============================================================================= +# INSTELLINGEN — pas dit gedeelte aan naar wens vóórdat je het script draait +# ============================================================================= + +# --- 1. Lijst van goedgekeurde URL's ----------------------------------------- +# Dit zijn de tabbladen die automatisch geopend worden wanneer de kiosk +# opstart. Voeg zoveel regels toe als nodig. +APPROVED_URLS=( + "http://vida-24q-a9f0.local/#/panels" + "https://www.radiozenders.fm" + "https://www.spotify.com" + ) + +# --- 2. Pop-upbeleid ---------------------------------------------------------- +# Kies één van de volgende waarden voor POPUP_MODE: +# "alle" -> alle pop-ups worden toegestaan (niet aanbevolen) +# "geen" -> alle pop-ups worden geblokkeerd (standaard, veiligst) +# "sommige" -> pop-ups worden standaard geblokkeerd, behalve voor de +# sites die genoemd worden in POPUP_ALLOWED_URLS hieronder +POPUP_MODE="sommige" + +# Alleen relevant wanneer POPUP_MODE="sommige". Gebruik het formaat +# "https://voorbeeld.nl/*" (met wildcard) zodat alle pagina's binnen dat +# domein zijn toegestaan. +POPUP_ALLOWED_URLS=( + "https://open.spotify.com/*" + "https://accounts.google.com/*" + "https://www.facebook.com/*" + "https://m.facebook.com/*" +) + +# ============================================================================= +# Vanaf hier hoeft er normaal gesproken niets aangepast te worden. +# ============================================================================= + +# Kleine helperfunctie: zet een bash-array om in een JSON-array (string). +json_array() { + local arr=("$@") + local out="[" + local first=true + for item in "${arr[@]}"; do + if $first; then + first=false + else + out+=", " + fi + out+="\"${item}\"" + done + out+="]" + echo "$out" +} + +# Zet een volledige URL om naar een "bare origin" (schema://host, zonder pad). +# LET OP: Chromium's URLBlocklist/URLAllowlist-filtersyntax werkt NIET zoals +# extensie-matchpatterns — een expliciet toegevoegd "/*" pad wordt daar +# gelezen als "pad moet letterlijk beginnen met het teken *", wat nooit +# matcht met echte URL's. Een kale origin (zonder pad) matcht in die syntax +# juist automatisch elk pad binnen dat domein. Voeg hier dus GEEN "/*" toe. +url_to_origin_wildcard() { + local url="$1" + if [[ "$url" =~ ^([a-zA-Z]+://[^/]+) ]]; then + echo "${BASH_REMATCH[1]}" + else + echo "$url" + fi +} + +# Bepaal de Chromium-instellingen op basis van POPUP_MODE. +case "$POPUP_MODE" in + alle) + POPUP_SETTING_VALUE=1 + POPUP_ALLOWED_JSON="[]" + ;; + geen) + POPUP_SETTING_VALUE=2 + POPUP_ALLOWED_JSON="[]" + ;; + sommige) + POPUP_SETTING_VALUE=2 + POPUP_ALLOWED_JSON="$(json_array "${POPUP_ALLOWED_URLS[@]}")" + ;; + *) + echo "FOUT: POPUP_MODE moet 'alle', 'geen' of 'sommige' zijn (huidige waarde: '$POPUP_MODE')." >&2 + exit 1 + ;; +esac + +if [ "${#APPROVED_URLS[@]}" -eq 0 ]; then + echo "FOUT: APPROVED_URLS mag niet leeg zijn — voeg minstens één URL toe." >&2 + exit 1 +fi + +# Navigatie-toegestane lijst (URLAllowlist): het domein van elke goedgekeurde +# starttab, plus de domeinen die nodig zijn voor pop-ups (bv. inloggen bij +# Google/Facebook, of de Spotify-webspeler). Zonder deze lijst kan de kiosk +# naar willekeurige sites navigeren, ook al staan die niet in APPROVED_URLS. +# POPUP_ALLOWED_URLS bevat een "/*"-suffix (nodig voor PopupsAllowedForUrls, +# dat WEL matchpattern-syntax gebruikt) — die wordt hier gestript, omdat +# URLAllowlist die syntax juist niet gebruikt (zie url_to_origin_wildcard). +ALLOWLIST_URLS=() +for u in "${APPROVED_URLS[@]}"; do + ALLOWLIST_URLS+=("$(url_to_origin_wildcard "$u")") +done +for u in "${POPUP_ALLOWED_URLS[@]}"; do + ALLOWLIST_URLS+=("${u%/\*}") +done +ALLOWLIST_JSON="$(json_array "${ALLOWLIST_URLS[@]}")" + +# ----------------------------------------------------------------------------- +# 0. Voorafgaande controles +# ----------------------------------------------------------------------------- + +if [ "$(id -u)" -ne 0 ]; then + echo "Voer dit script uit met sudo: sudo ./install-kiosk.sh" >&2 + exit 1 +fi + +echo "==============================================" +echo " Installatie kiosk-laptop" +echo "==============================================" +echo +echo "Goedgekeurde URL's die geopend worden:" +for u in "${APPROVED_URLS[@]}"; do + echo " - $u" +done +echo +echo "Pop-upbeleid: $POPUP_MODE" +if [ "$POPUP_MODE" = "sommige" ]; then + echo " Toegestaan voor:" + for u in "${POPUP_ALLOWED_URLS[@]}"; do + echo " - $u" + done +fi +echo +echo "Navigatie is beperkt tot de volgende domeinen (URLAllowlist):" +for u in "${ALLOWLIST_URLS[@]}"; do + echo " - $u" +done +echo + +# Zet AUTO_YES=1 (of geef -y/--yes mee) om de bevestigingsvraag over te slaan +AUTO_YES="${AUTO_YES:-0}" +for arg in "$@"; do + case "$arg" in + -y|--yes) AUTO_YES=1 ;; + esac +done + +if [ "$AUTO_YES" -ne 1 ]; then + read -rp "Dit script maakt een 'kiosk'-gebruiker aan en past LightDM/X11 op deze machine aan. Doorgaan? [j/N] " CONFIRM + if [[ ! "$CONFIRM" =~ ^[jJ]$ ]]; then + echo "Afgebroken." + exit 0 + fi +else + echo "Bevestiging overgeslagen (--yes)." +fi + +# ----------------------------------------------------------------------------- +# 1. Systeem bijwerken (onderdeel van handleidingstap 1) +# ----------------------------------------------------------------------------- + +echo +echo "--> Systeempakketten bijwerken..." +apt update +apt full-upgrade -y + +# ----------------------------------------------------------------------------- +# 2. Kiosk-gebruiker aanmaken (vóór het instellen van het wachtwoord — zie +# hieronder waarom dit die volgorde moet hebben) +# ----------------------------------------------------------------------------- + +echo +echo "--> Gebruiker 'kiosk' aanmaken..." +if id "kiosk" &>/dev/null; then + echo " Gebruiker 'kiosk' bestaat al, aanmaken wordt overgeslagen." +else + adduser --disabled-password --gecos "" kiosk +fi + +usermod -aG audio,video,netdev,plugdev kiosk + +# Wachtwoord voor het 'kiosk'-account is vastgesteld op 'kiosk'. +# We schrijven de hash direct weg met usermod -p in plaats van chpasswd, +# omdat chpasswd via PAM loopt en de wachtwoordkwaliteitscontrole +# (bv. wachtwoord == gebruikersnaam) ook voor root kan blokkeren, +# wat dit script niet-interactief zou laten vastlopen. +echo +echo "--> Wachtwoord voor 'kiosk' instellen..." +KIOSK_PASSWORD="kiosk" +KIOSK_HASH="$(openssl passwd -6 "${KIOSK_PASSWORD}")" +usermod -p "${KIOSK_HASH}" kiosk +unset KIOSK_PASSWORD KIOSK_HASH + +# ----------------------------------------------------------------------------- +# 3. Openbox en Chromium installeren +# ----------------------------------------------------------------------------- + +echo +echo "--> Openbox, LightDM GTK-greeter en hulpprogramma's installeren..." +apt install -y openbox lightdm-gtk-greeter unclutter xdotool + +echo +echo "--> Chromium installeren (deb-pakket, geen snap)..." +# Verwijder de snap-versie van Chromium indien aanwezig: deze leest +# /etc/chromium/policies/ niet betrouwbaar uit. +if snap list chromium &>/dev/null; then + echo " Snap-versie van Chromium wordt verwijderd..." + snap remove chromium +fi + +apt install -y chromium || apt install -y chromium-browser + +BROWSER_BIN="$(command -v chromium || command -v chromium-browser || true)" +if [ -z "$BROWSER_BIN" ]; then + echo "FOUT: geen chromium-programma gevonden na installatie." >&2 + exit 1 +fi +echo " Gebruikte browser: $BROWSER_BIN" + +# ----------------------------------------------------------------------------- +# 4. Chromium-beleid (extensies, pop-ups, incognito etc. blokkeren) +# ----------------------------------------------------------------------------- +# Let op: de sleutelnamen in dit JSON-bestand (bv. "ExtensionInstallBlocklist") +# zijn vaste namen die Chromium herkent en kunnen niet vertaald worden zonder +# de werking te breken. JSON ondersteunt bovendien geen commentaarregels. + +echo +echo "--> Chromium-beheerbeleid wegschrijven..." +mkdir -p /etc/chromium/policies/managed + +cat > /etc/chromium/policies/managed/kiosk_policy.json < /etc/kiosk/urls.txt aanmaken op basis van APPROVED_URLS..." +mkdir -p /etc/kiosk + +{ + echo "# Goedgekeurde kiosk-tabbladen — één URL per regel." + echo "# Regels die beginnen met # zijn commentaar en worden genegeerd." + for u in "${APPROVED_URLS[@]}"; do + echo "$u" + done +} > /etc/kiosk/urls.txt + +AV_ADMIN_HOME="/home/av-admin" +ADMIN_KIOSK_DIR="${AV_ADMIN_HOME}/kiosk" +mkdir -p "$ADMIN_KIOSK_DIR" + +usermod -aG kiosk av-admin +chown root:kiosk /etc/kiosk/urls.txt +chmod 664 /etc/kiosk/urls.txt + +ln -sf /etc/kiosk/urls.txt "${AV_ADMIN_HOME}/urls.txt" +chown -h av-admin:av-admin "${AV_ADMIN_HOME}/urls.txt" + +SCRIPT_PATH="$(readlink -f "$0")" +cp "$SCRIPT_PATH" "${AV_ADMIN_HOME}/re-install-kiosk.sh" +chmod +x "${AV_ADMIN_HOME}/re-install-kiosk.sh" + +rm -rf "${AV_ADMIN_HOME}/install-kiosk.sh" + +chown -R av-admin:admin "$AV_ADMIN_HOME" 2>/dev/null || true + +# ----------------------------------------------------------------------------- +# 6. Opstartscript voor de browser +# ----------------------------------------------------------------------------- + +echo +echo "--> /usr/local/bin/kiosk-launch.sh wegschrijven..." +cat > /usr/local/bin/kiosk-launch.sh <<'EOF' +#!/bin/bash +# Start Chromium gemaximaliseerd (niet fullscreen) met de goedgekeurde tabbladen. + +URL_LIST="/etc/kiosk/urls.txt" +BROWSER_BIN="$(command -v chromium || command -v chromium-browser)" + +if [ -z "$BROWSER_BIN" ]; then + echo "Geen chromium-programma gevonden." >&2 + exit 1 +fi + +# Lees alle regels die geen commentaar of leeg zijn in een array +mapfile -t URLS < <(grep -vE '^\s*#' "$URL_LIST" | grep -vE '^\s*$') + +if [ ${#URLS[@]} -eq 0 ]; then + URLS=("http://localhost/kiosk-home") +fi + +exec "$BROWSER_BIN" \ + --start-maximized \ + --noerrdialogs \ + --disable-infobars \ + --disable-session-crashed-bubble \ + --disable-translate \ + --no-first-run \ + --fast \ + --fast-start \ + --disable-pinch \ + --overscroll-history-navigation=0 \ + --password-store=basic \ + "${URLS[@]}" +EOF + +chmod +x /usr/local/bin/kiosk-launch.sh + +# ----------------------------------------------------------------------------- +# 7. Openbox-sessie voor de kiosk-gebruiker +# ----------------------------------------------------------------------------- + +echo +echo "--> Openbox configureren voor 'kiosk'..." +sudo -u kiosk mkdir -p /home/kiosk/.config/openbox + +cat > /home/kiosk/.config/openbox/autostart <<'EOF' +# Schermbeveiliging/energiebeheer uitschakelen — deze laptop mag nooit slapen +xset s off +xset -dpms +xset s noblank + +# Muisaanwijzer verbergen bij inactiviteit +unclutter -idle 2 & + +# Bewakingslus: herstart de browser als deze ooit gesloten wordt of vastloopt +( + while true; do + /usr/local/bin/kiosk-launch.sh + sleep 2 + done +) & +EOF + +cat > /home/kiosk/.config/openbox/rc.xml <<'EOF' + + + + + + + dm-tool switch-to-greeter + + + + + + + +EOF + +chown -R kiosk:kiosk /home/kiosk/.config + +# ----------------------------------------------------------------------------- +# 8. LightDM: automatisch inloggen + av-admin-account verbergen +# ----------------------------------------------------------------------------- +# Let op: de sleutelnamen hieronder (bv. "autologin-user") zijn vaste +# LightDM-configuratienamen en kunnen niet vertaald worden. + +echo +echo "--> LightDM automatisch inloggen configureren..." +mkdir -p /etc/lightdm/lightdm.conf.d + +cat > /etc/lightdm/lightdm.conf.d/50-kiosk.conf <<'EOF' +[Seat:*] +autologin-user=kiosk +autologin-user-timeout=0 +autologin-session=openbox +greeter-hide-users=true +allow-guest=false +EOF + +# ----------------------------------------------------------------------------- +# 9. Extra beveiliging — virtuele-terminalwissel uitschakelen +# ----------------------------------------------------------------------------- + +echo +echo "--> Virtuele-terminalwissel (Ctrl+Alt+F1-F7) en Zap uitschakelen..." +mkdir -p /etc/X11/xorg.conf.d + +cat > /etc/X11/xorg.conf.d/10-no-vtswitch.conf <<'EOF' +Section "ServerFlags" + Option "DontVTSwitch" "true" + Option "DontZap" "true" +EndSection +EOF + +# ----------------------------------------------------------------------------- +# 10. Script maken waarmee av-admin het Chromium-beleid kan verversen na het +# aanpassen van /etc/kiosk/urls.txt, zonder het hele installatiescript +# opnieuw te hoeven draaien. +# ----------------------------------------------------------------------------- + +echo +echo "--> /etc/kiosk/refresh_policies.sh wegschrijven..." + +cat > "/etc/kiosk/refresh_policies.sh" <<'REFRESH_EOF' +#!/bin/bash +# Herstart Chromium op de kiosk zodat gewijzigde /etc/kiosk/urls.txt en +# beleidsinstellingen opnieuw ingelezen worden. Voer uit met: sudo ./refresh_policies.sh +set -euo pipefail + +if [ "$(id -u)" -ne 0 ]; then + echo "Voer dit script uit met sudo: sudo ./refresh_policies.sh" >&2 + exit 1 +fi + +echo "--> Chromium op de kiosk wordt herstart om wijzigingen door te voeren..." +pkill -u kiosk chromium 2>/dev/null || pkill -u kiosk chromium-browser 2>/dev/null || true +echo " Klaar. De bewakingslus in de kiosk-sessie start de browser automatisch opnieuw." +REFRESH_EOF + +chmod +x "/etc/kiosk/refresh_policies.sh" +chown av-admin:av-admin "/etc/kiosk/refresh_policies.sh" + +ln -sf /etc/kiosk/refresh_policies.sh "${ADMIN_KIOSK_DIR}/refresh_policies.sh" +chown -h av-admin:av-admin "${ADMIN_KIOSK_DIR}/refresh_policies.sh" + +# ----------------------------------------------------------------------------- +# Klaar +# ----------------------------------------------------------------------------- + +echo +echo "==============================================" +echo " Installatie voltooid." +echo "==============================================" +echo +echo "Resterende handmatige stappen:" +echo " 1. Controleer /etc/kiosk/urls.txt (of pas APPROVED_URLS hierboven aan" +echo " en voer het commando 'sudo ${ADMIN_KIOSK_DIR}/refresh_policies.sh' uit om wijzigingen door te voeren)." +echo " 2. Herstart om te testen: sudo reboot" +echo " -> zou automatisch moeten inloggen op de schermvullende kiosk-browser." +echo " 3. Druk op Ctrl+Alt+L op het kiosk-scherm om het inlogscherm te" +echo " bereiken en log in als beheerder om te controleren of het gewone" +echo " bureaublad nog werkt." +echo +echo "LightDM is NIET automatisch herstart, omdat dit je huidige grafische" +echo "sessie zou beëindigen. Herstart wanneer je klaar bent:" +echo " sudo reboot" diff --git a/preseed.cfg b/preseed.cfg new file mode 100644 index 0000000..67e9489 --- /dev/null +++ b/preseed.cfg @@ -0,0 +1,223 @@ +############################################################################### +# Aamsveen Audio Kiosk - Linux Mint 22.3 / Ubiquity +# +# WARNING: +# +# The selected target disk is COMPLETELY ERASED. +# +# The installer deliberately excludes the USB installer media. +############################################################################### + +############################################################################### +# Debconf +############################################################################### + +d-i debconf/priority string critical + +############################################################################### +# Locale +############################################################################### + +d-i debian-installer/locale string nl_NL + +############################################################################### +# Keyboard +############################################################################### + +d-i keyboard-configuration/xkb-keymap select us(euro) +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 +############################################################################### + +d-i clock-setup/utc boolean true +d-i time/zone string Europe/Amsterdam + +############################################################################### +# User +############################################################################### + +d-i passwd/user-fullname string AV Admin +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 +############################################################################### + +d-i netcfg/get_hostname string audio-kiosk +d-i netcfg/get_domain string + +############################################################################### +# Partitioning +############################################################################### + +d-i partman-auto/method string regular + +############################################################################### +# Dynamically determine the installation disk. +# +# list-devices usb-partition identifies partitions belonging to USB devices. +# Their parent disks are excluded. +# +# We then select the first non-removable disk. +# +# IMPORTANT: +# +# 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. +############################################################################### + +d-i partman/early_command string \ + 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"; \ + fi; \ + done; \ + TARGET_DISK=""; \ + for DISK in $(list-devices disk); do \ + SKIP=0; \ + for USB_DISK in $USB_DISKS; do \ + if [ "$DISK" = "$USB_DISK" ]; then \ + SKIP=1; \ + break; \ + fi; \ + done; \ + [ "$SKIP" -eq 1 ] && continue; \ + BASENAME="$(basename "$DISK")"; \ + if [ -r "/sys/class/block/$BASENAME/removable" ]; then \ + if [ "$(cat "/sys/class/block/$BASENAME/removable")" = "1" ]; then \ + continue; \ + fi; \ + fi; \ + TARGET_DISK="$DISK"; \ + break; \ + done; \ + if [ -z "$TARGET_DISK" ]; then \ + echo "Aamsveen installer ERROR: no safe internal target disk found" \ + > /var/log/aamsveen-partition.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 + +############################################################################### +# GPT +############################################################################### + +d-i partman-partitioning/default_label string gpt +d-i partman-partitioning/choose_label select gpt + +############################################################################### +# Explicit UEFI partition recipe +# +# 512 MiB EFI System Partition +# remainder root filesystem +# 2 GiB swap +# +# No separate /boot partition is created. +# This deliberately keeps the partition layout simple. +############################################################################### + +d-i partman-auto/expert_recipe string \ + aamsveen-uefi :: \ + 538 538 538 fat32 \ + $iflabel{ gpt } \ + $primary{ } \ + $reusemethod{ } \ + method{ efi } \ + format{ } \ + . \ + 8192 8192 -1 ext4 \ + $primary{ } \ + method{ format } \ + format{ } \ + use_filesystem{ } \ + filesystem{ ext4 } \ + mountpoint{ / } \ + . \ + 2048 2048 2048 linux-swap \ + $primary{ } \ + $reusemethod{ } \ + method{ swap } \ + format{ } \ + . + +d-i partman-auto/choose_recipe select aamsveen-uefi + +############################################################################### +# Remove existing storage configuration +############################################################################### + +d-i partman-lvm/device_remove_lvm boolean true +d-i partman-md/device_remove_md boolean true + +############################################################################### +# Do not preserve old partitions +############################################################################### + +d-i partman-partitioning/confirm_write_new_label boolean true +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 +############################################################################### + +d-i partman/mount_style select uuid + +############################################################################### +# Bootloader +############################################################################### + +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 + +############################################################################### +# Ubiquity +############################################################################### + +ubiquity ubiquity/summary string +ubiquity ubiquity/confirm-partitioning boolean true +ubiquity ubiquity/reboot boolean true + +############################################################################### +# Installation behaviour +############################################################################### + +d-i cdrom-detect/eject boolean false + +############################################################################### +# Finish +############################################################################### + +d-i finish-install/reboot_in_progress note