#!/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