#!/usr/bin/env bash set -euo pipefail # Personalisiert das eigenstaendige Boot-Medium (scripts/build_boot_medium.sh) # fuer eine bestimmte Kundenorganisation - befuellt config/installer.conf mit # Aktivierungscode + WLAN-Zugangsdaten. Hostname/Geraete-ID/Partitionierung # werden weiterhin erst live auf dem Zielgeraet erzeugt (siehe # backend_generate_config() in backends/mint-image/backend.sh). # # Anders als das alte, Casper-basierte Verfahren (Xorriso-Extraktion der # ganzen ISO + Initrd-Hook-Injection, siehe scripts/lib/initrd.sh) kann hier # NICHT einfach eine einzelne Datei direkt auf der ISO9660-Ebene ersetzt # werden: /opt/tuxflotte/ liegt innerhalb von /live/filesystem.squashfs # (read-only, von live-boot gemountet). Ein direktes # `xorriso -update datei /opt/tuxflotte/config/installer.conf` traf live # getestet ins Leere - das gebootete System sah weiterhin die leere # Platzhalter-Konfiguration aus dem Basis-Image, weil dieser Pfad ausserhalb # des Squashfs liegt und live-boot ihn nie liest (31.08.2026, live in der # enterprise-QEMU-VM gefunden: Aktivierungscode-Prompt erschien trotz # TUXFLOTTE_AUTO_MODE=true in der vermeintlich aktualisierten ISO). # # Stattdessen: das Squashfs wird entpackt, installer.conf darin ersetzt, neu # gepackt (mksquashfs -no-progress braucht dafuer nur reine Kompressionszeit, # ~1 Minute - kein debootstrap/apt, kein Netzwerk) und als Ganzes per # `xorriso -update` ins Ziel-ISO eingespielt (Boot-Sektoren/GRUB-Branding # bleiben unangetastet, stecken schon im Basis-Image aus # scripts/build_boot_medium.sh). mksquashfs kann ein bestehendes Squashfs # zwar inkrementell erweitern, aber NICHT bereits vorhandene Dateien # ueberschreiben (live getestet: identischer Dateiinhalt trotz # augenscheinlich erfolgreichem Lauf) - deshalb der volle # unsquashfs/mksquashfs-Zyklus statt eines inkrementellen Appends. usage() { echo "Usage: $0 [wifi_ssid] [wifi_psk] [volid]" >&2 } SOURCE_ISO="${1:-}" OUTPUT_ISO="${2:-}" ACTIVATION_CODE="${3:-}" WIFI_SSID="${4:-}" WIFI_PSK="${5:-}" # Vom Aufrufer (provisioning-server, compute_iso_volid()) bereits # ISO9660-konform aufbereitet (Grossbuchstaben/Ziffern/Unterstrich, <=32 # Zeichen) - dieses Skript validiert/sanitisiert das bewusst nicht nochmal, # um die Sanitisierungslogik nicht doppelt zu pflegen. Fallback nur fuer # Aufrufe ohne sechsten Parameter (z.B. manuelle Tests). VOLID="${6:-TUXFLOTTE}" if [[ -z "${SOURCE_ISO}" || -z "${OUTPUT_ISO}" || -z "${ACTIVATION_CODE}" ]]; then usage exit 1 fi [[ -f "${SOURCE_ISO}" ]] || { echo "Error: Quell-ISO nicht gefunden: ${SOURCE_ISO}" >&2; exit 1; } if [[ "${EUID}" -ne 0 ]]; then echo "Error: muss als root laufen (unsquashfs/mksquashfs brauchen root, um" >&2 echo " Datei-Eigentuemer im Squashfs korrekt zu erhalten - ohne root" >&2 echo " gehen z.B. root:shadow-Zuordnungen verloren, live gefunden)." >&2 exit 1 fi for cmd in xorriso unsquashfs mksquashfs; do command -v "${cmd}" >/dev/null 2>&1 || { echo "Error: fehlendes Werkzeug: ${cmd}" >&2; exit 1; } done WORK_DIR="$(mktemp -d)" cleanup() { # unsquashfs uebernimmt Original-Rechte (teils ohne Write-Bit) - ohne # chmod schlaegt rm -rf darauf fehl. chmod -R u+w "${WORK_DIR}" 2>/dev/null || true rm -rf "${WORK_DIR}" } trap cleanup EXIT echo "Extrahiere Squashfs aus Quell-ISO..." xorriso -indev "${SOURCE_ISO}" -osirrox on -extract /live/filesystem.squashfs \ "${WORK_DIR}/orig.squashfs" >/dev/null echo "Entpacke Squashfs..." # "-excludes ... dev" schliesst /dev von der Extraktion aus - live auf anode # gefunden (01.09.2026): anode laeuft in einem LXC-Container, der CAP_MKNOD # grundsaetzlich blockiert (auch fuer root) - unsquashfs scheiterte beim # Wiederherstellen der paar Geraetedateien im Boot-Medium-Squashfs # (/dev/null, /dev/console, ...) mit "Operation not permitted". unsquashfs -excludes -d "${WORK_DIR}/root" "${WORK_DIR}/orig.squashfs" dev || { echo "Error: Squashfs konnte nicht entpackt werden." >&2; exit 1; } # ECHTER BUG, live auf echter Hardware gefunden (01.09.2026, direkt nach dem # vorigen Fix): "-excludes dev" entfernt nicht nur die Geraetedateien, # sondern das gesamte /dev-VERZEICHNIS - live-boots eigenes Initramfs- # Skript braucht /dev aber als reinen MOUNTPUNKT (bindet dort sein eigenes # Devtmpfs ein, kurz vor switch_root) und scheiterte deshalb sofort beim # Booten mit "mount: /root/dev: mount point does not exist" gefolgt von # einem Kernel-Panic. Anders als beim Golden Image (siehe # package_golden_image.sh/image_deploy_restore_excluded_dirs(), wo dasselbe # Muster schon einmal gefunden wurde) reicht hier ein leeres Verzeichnis - # devtmpfs bindet sich selbst darueber, die eigentlichen Geraetedateien # werden nie aus dem Squashfs gebraucht. mkdir -p "${WORK_DIR}/root/dev" echo "Schreibe personalisierte installer.conf..." mkdir -p "${WORK_DIR}/root/opt/tuxflotte/config" { echo "export TUXFLOTTE_AUTO_MODE=true" printf 'export TUXFLOTTE_ACTIVATION_CODE=%q\n' "${ACTIVATION_CODE}" [[ -n "${WIFI_SSID}" ]] && printf 'export TUXFLOTTE_WIFI_SSID=%q\n' "${WIFI_SSID}" [[ -n "${WIFI_PSK}" ]] && printf 'export TUXFLOTTE_WIFI_PSK=%q\n' "${WIFI_PSK}" } >"${WORK_DIR}/root/opt/tuxflotte/config/installer.conf" echo "Packe Squashfs neu (nur Kompression, kein apt/debootstrap)..." mksquashfs "${WORK_DIR}/root" "${WORK_DIR}/new.squashfs" -comp xz -no-progress >/dev/null chmod 444 "${WORK_DIR}/new.squashfs" echo "Erzeuge Kunden-ISO..." rm -f "${OUTPUT_ISO}" xorriso \ -indev "${SOURCE_ISO}" \ -outdev "${OUTPUT_ISO}" \ -volid "${VOLID}" \ -update "${WORK_DIR}/new.squashfs" /live/filesystem.squashfs \ -boot_image any replay echo "Kunden-ISO erstellt: ${OUTPUT_ISO}"