From 941a58535d61d8364d3b7b6567eae8c1d65bc690 Mon Sep 17 00:00:00 2001 From: Thomas Stallinger Date: Sat, 29 Aug 2026 15:16:41 +0200 Subject: [PATCH] fix: noninteractive verworfen, automatic-ubiquity+Autoklicker, drei echte Bugs behoben - noninteractive-Frontend endgueltig verworfen: PageNoninteractive-Stubs fuehren strukturell zur Endlosschleife im choose_partition-Zustands- automaten von ubi-partman.py, unabhaengig vom Preseed-Stand. - Umstieg auf automatic-ubiquity (echte GTK-Oberflaeche) + eigener Autoklicker (live-updates/opt/tuxflotte/scripts/autoclicker.sh + systemd-Service), ausgeloest per Boot-Keyword tuxflotte-autoclick. - Bug 1: jq fehlte beim echten Kiosk-Auslauf (kein manueller Vorab- Installationsschritt wie in Testlaeufen) - neues Modul 00_preflight.sh installiert es als allererstes. - Bug 2: echter Ubiquity-Crash in ubi-prepare.py (TypeError: Argument 1 does not allow None as a value) - gezielter Sed-Patch im bestehenden 99casperboot-Hook. - Bug 3: 'd-i partman/choose_partition select finish' zwang denselben Endlosschleifen-Zustandsautomaten wie bei noninteractive, auch im GTK-Modus - Zeile ersatzlos entfernt, partman-auto/method+recipe genuegen. - autoclicker.sh: Fenstersuche nach 'ubiquity' korrigiert (Fenstertitel ist tatsaechlich 'Installation (as superuser)', enthaelt das Wort nie). - Alle vier Fixes live per QEMU verifiziert (jeweils frische Disk, realer Kiosk-Ausloeser/kexec-Pfad, nicht nur manuelle Nachstellung). Offen: automatisierter Klick auf 'Jetzt installieren' auf der Partitionierungs-Uebersichtsseite noch nicht zuverlaessig (Enter trifft dort einen Ausklapp-Pfeil statt den Button). Siehe ADR-0023-Nachtrag. Co-Authored-By: Claude Sonnet 5 --- backends/mint/backend.sh | 56 +++++++-- backends/mint/preseed.tpl | 86 +++++++++++++- initrd-hooks/casper-bottom/99casperboot | 19 +++ .../tuxflotte-autoclicker.service | 1 + .../system/tuxflotte-autoclicker.service | 17 +++ .../opt/tuxflotte/scripts/autoclicker.sh | 111 ++++++++++++++++++ scripts/modules/00_preflight.sh | 40 +++++++ 7 files changed, 316 insertions(+), 14 deletions(-) create mode 120000 live-updates/etc/systemd/system/multi-user.target.wants/tuxflotte-autoclicker.service create mode 100644 live-updates/etc/systemd/system/tuxflotte-autoclicker.service create mode 100755 live-updates/opt/tuxflotte/scripts/autoclicker.sh diff --git a/backends/mint/backend.sh b/backends/mint/backend.sh index ca179bb..a01cb75 100644 --- a/backends/mint/backend.sh +++ b/backends/mint/backend.sh @@ -155,6 +155,7 @@ _tuxflotte_render_partman_recipe() { local percent local size_mb local esp_mb=0 + local bios_grub_mb=0 scheme="$(jq --raw-output '.scheme // "single"' <<<"${partitioning_json}")" @@ -178,6 +179,24 @@ _tuxflotte_render_partman_recipe() { esp_mb=512 disk_size_mb="$(( disk_size_mb - esp_mb ))" recipe_body="${esp_mb} ${esp_mb} ${esp_mb} fat32 \$reusemethod{ } \$primary{ } method{ efi } format{ } . " + else + # Analoges Pendant fuer reinen BIOS-Betrieb: partman legt den + # Datentraeger auch ohne EFI offenbar als GPT an (real beim Testen + # bestaetigt: freier Speicher vor Partition 1 und nach der letzten + # Partition ist die GPT-Kopfdaten-Signatur, kein MSDOS-Layout). GPT + + # BIOS-Boot braucht eine kleine unformatierte Boot-Partition fuer den + # GRUB-Core, sonst schlaegt /usr/lib/partman/check.d/08biosgrub fehl + # und partman-partitioning/no_bootable_biosgrub sorgt fuer eine + # Endlosschleife zurueck ins choose_partition-Menue statt + # abzuschliessen (real beim Testen entdeckt und via 08biosgrub- + # Quelltext auf dem Live-Medium verifiziert - "true" bei dieser Frage + # bedeutet dort "Problem besteht weiterhin", nicht "trotzdem + # fortfahren", anders als bei den meisten uebrigen Boolean-Fragen in + # diesem Rezept). "$iflabel{ gpt }" macht die Stanza auf einem + # MSDOS-Datentraeger automatisch wirkungslos. + bios_grub_mb=1 + disk_size_mb="$(( disk_size_mb - bios_grub_mb ))" + recipe_body="${bios_grub_mb} ${bios_grub_mb} ${bios_grub_mb} free \$iflabel{ gpt } \$reusemethod{ } method{ biosgrub } . " fi case "${scheme}" in @@ -363,21 +382,32 @@ backend_launch() { backend_log "Lade Kexec-Ziel fuer automatisierten Ubiquity-Start." - # "noninteractive" (eigenes Boot-Keyword, siehe /usr/share/ubiquity/ - # start-ubiquity-dm) laesst casper statt der GTK-Oberflaeche (ubiquity-dm - # -> gtk_ui.py) direkt "ubiquity noninteractive" aufrufen - Ubiquitys - # eigenes, mitgeliefertes Headless-Frontend (ubiquity/frontend/ - # noninteractive.py). Das arbeitet jede Seite mit auto_process=True rein - # ueber Debconf ab, ohne jemals ein Fenster zu zeichnen oder einen Klick - # zu erwarten - der Unterschied zu "automatic-ubiquity" alleine: jenes - # startet weiterhin die GTK-Oberflaeche und fuellt dort nur die Werte - # vor, wartet aber pro Seite trotzdem auf "Continue" (real verifiziert, - # siehe ADR-0023-Nachtrag). "automatic-ubiquity" bleibt zusaetzlich - # gesetzt, weil start-ubiquity-dm bei einem GTK/X-Absturz automatisch - # darauf als Fallback in den Noninteractive-Modus zurueckfaellt. + # Ubiquitys eigenes "noninteractive"-Frontend (ubiquity/frontend/ + # noninteractive.py, ueber das gleichnamige Boot-Keyword ausgewaehlt) + # arbeitet zwar rein ueber Debconf ohne je ein Fenster zu zeichnen, aber + # dessen Seite fuer die gefuehrte Partitionierung (ubi-partman.py) haengt + # sich bei einem vollstaendig vorbefuellten Rezept in einer echten + # Endlosschleife auf (staendiges Neuaufbauen des choose_partition-Menues, + # "partman/confirm" wird nie erreicht - real ueber >800 Wiederholungen + # ohne Fortschritt bestaetigt, siehe ADR-0023-Nachtrag). Ursache: die + # PageNoninteractive-Klasse liefert fuer etliche vom GTK-Codepfad + # benoetigte Rueckfragen (get_autopartition_choice(), get_crypto_keys()) + # nur "pass"/None statt echter Werte. + # + # Deshalb bewusst zurueck auf "automatic-ubiquity" (echte GTK-Oberflaeche, + # PageGtk-Klasse - der von Ubiquity selbst getestete, produktiv genutzte + # Codepfad, auch fuer die Partitionierung). Der GTK-Assistent fuellt jede + # Seite aus dem Preseed vor, wartet aber weiterhin auf einen "Weiter"-Klick + # pro Seite (real verifiziert, siehe ADR-0023-Nachtrag) - dafuer laeuft + # zusaetzlich autoclicker.sh (live-updates/opt/tuxflotte/scripts/), per + # systemd-Service und ausgeloest durch das eigene Boot-Keyword + # "tuxflotte-autoclick" (harmlos bei jedem anderen Boot ohne dieses + # Keyword). "debug-ubiquity" (setzt debug="-d") macht + # /var/log/installer/debug ausfuehrlicher, hilfreich bei weiterer + # Fehlersuche. kexec -l "${cdrom_vmlinuz}" \ --initrd="${custom_initrd}" \ - --append="boot=casper automatic-ubiquity noninteractive noprompt file=/preseed.cfg debian-installer/language=de keyboard-configuration/layoutcode=de quiet splash ---" || + --append="boot=casper automatic-ubiquity tuxflotte-autoclick debug-ubiquity noprompt file=/preseed.cfg debian-installer/language=de keyboard-configuration/layoutcode=de quiet splash ---" || { backend_fatal "kexec -l fehlgeschlagen."; return 1; } backend_log "Starte unbeaufsichtigte Installation (kexec -e). Kein Ruecksprung erwartet - ab hier laeuft die eigentliche Installation im neuen Kernel weiter." diff --git a/backends/mint/preseed.tpl b/backends/mint/preseed.tpl index 49d3cf7..1abebbd 100644 --- a/backends/mint/preseed.tpl +++ b/backends/mint/preseed.tpl @@ -29,13 +29,97 @@ d-i partman-auto/method string regular d-i partman-auto/expert_recipe string ${TUXFLOTTE_PARTMAN_RECIPE} d-i partman-auto/choose_recipe select tuxflotte d-i partman-partitioning/confirm_write_new_label boolean true -d-i partman/choose_partition select finish +d-i partman-partitioning/confirm_new_label boolean true +# "partman/choose_partition select finish" wurde bewusst entfernt: das ist +# die Frage des MANUELLEN/erweiterten Partitionierers ("Menu" -> "Finish +# partitioning"), keine des gefuehrten/automatischen Ablaufs. Direktes +# Preseeden ohne echten Seitenaufbau (weder im GTK- noch im +# noninteractive-Frontend) fuehrt in ubi-partman.py real reproduzierbar zu +# einer Endlosschleife im internen "building_cache"-Zustandsautomaten der +# choose_partition-Verarbeitung (ueber 100.000 Debconf-Zeilen in wenigen +# Sekunden ohne echten Fortschritt, sowohl mit automatic-ubiquity/GTK als +# auch mit dem verworfenen noninteractive-Frontend - siehe ADR-0023-Nachtrag). +# Ohne diese Zeile uebernehmen partman-auto/method + expert_recipe + +# choose_recipe (oben) die gefuehrte Partitionierung auf dem dafuer +# vorgesehenen Weg. d-i partman/confirm boolean true +d-i partman/confirm_nochanges boolean true d-i partman/confirm_nooverwrite boolean true +d-i partman/unmount_active boolean true +d-i partman/automount boolean true +d-i partman/filter_mounted boolean true +d-i partman-partitioning/confirm_resize boolean true +d-i partman-ext3/lazy_itable_init boolean true +d-i partman/boot_not_first_partition boolean true +d-i partman-basicfilesystems/boot_not_first_partition boolean true +d-i partman-basicfilesystems/boot_not_ext2 boolean true +d-i partman-ext3/boot_not_bootable boolean true +d-i partman-ext3/boot_not_ext2_or_ext3 boolean true +d-i partman-basicfilesystems/no_mount_point boolean true +d-i partman-basicfilesystems/no_swap boolean true +d-i partman-basicfilesystems/check_failed boolean true +d-i partman-basicfilesystems/swap_check_failed boolean true +d-i partman-ext3/bad_alignment boolean true +# Dieselbe Polaritaets-Falle wie bei no_bootable_biosgrub weiter unten (siehe +# dortiger Kommentar) - "true" hiesse "Problem besteht wirklich, abbrechen". +# Fuer UEFI-Zielgeraete legt _tuxflotte_render_partman_recipe() bereits eine +# echte ESP an, dieser Fallback sollte also nie greifen. +d-i partman-partitioning/no_bootable_efi boolean false +# Anders als die meisten uebrigen Boolean-Fragen hier bedeutet "true" bei +# no_bootable_biosgrub NICHT "trotzdem fortfahren", sondern "das Problem +# besteht wirklich" -> der pruefende Skript (check.d/08biosgrub) bricht dann +# mit exit 1 ab, was zur Endlosschleife zurueck ins choose_partition-Menue +# fuehrt (real entdeckt und via Quelltext auf dem Live-Medium verifiziert, +# siehe ADR-0023-Nachtrag). Der eigentliche Fix ist eine echte BIOS-Boot- +# Partition im Rezept (siehe _tuxflotte_render_partman_recipe() in +# backend.sh) - "false" hier bleibt nur als defensiver Fallback, falls die +# Partition aus irgendeinem Grund nicht als "biosgrub" erkannt wird. +d-i partman-partitioning/no_bootable_biosgrub boolean false +d-i partman-partitioning/bootable_logical boolean true +d-i partman-partitioning/unknown_label boolean true +d-i partman-partitioning/unsupported_label boolean true +d-i partman-basicmethods/method_only boolean true +d-i grub-installer/only_debian boolean true +d-i grub-installer/with_other_os boolean true +d-i grub-installer/make_active boolean true +d-i grub-installer/grub2_instead_of_grub_legacy boolean true +d-i grub-installer/grub_not_mature_on_this_platform boolean true +d-i grub-installer/multipath boolean true +d-i grub-installer/sataraid boolean true +# Wichtig: false, nicht true -- "skip" heisst hier woertlich "GRUB-Installation +# ueberspringen". true wuerde die Bootloader-Installation aktiv verhindern. +d-i grub-installer/skip boolean false +d-i partman-auto-lvm/no_boot boolean true +d-i partman-target/mount_failed boolean true +# partman-efi/no_efi wird ENTGEGEN der urspruenglichen Annahme sehr wohl +# gefragt, auch im reinen BIOS/SeaBIOS-Betrieb ohne NVRAM (real via +# debug-ubiquity-Log verifiziert, siehe ADR-0023-Nachtrag) -- Ubiquity prueft +# offenbar unabhaengig vom aktuellen Boot-Modus, ob eine EFI-System-Partition +# existiert. "false" heisst hier "trotzdem fortfahren" (die Alternative +# "true" wuerde zurueck ins Partitionierungsmenue springen und den Ablauf +# blockieren -- fuer ein bewusstes BIOS/MBR-Setup ohne EFI-Partition ist +# false die richtige Antwort). +d-i partman-efi/no_efi boolean false +# Bewusst weiterhin NICHT preseeded: grub-installer/force-efi-extra-removable +# (EFI-spezifisch, im BIOS-Betrieb ohne Wirkung) sowie partman-crypto/*, +# partman-lvm/*, partman-jfs/* (Recipe nutzt weder Crypto noch LVM noch JFS, +# koennen also nie auftreten; einige dieser Fragen sind bei "true" destruktiv +# (z.B. crypto_warn_erase), daher hier absichtlich nicht blind auf true +# gesetzt). ubiquity ubiquity/summary note ubiquity ubiquity/reboot boolean true ubiquity ubiquity/use_nonfree boolean true +# Ohne diese Zeile stuerzt Ubiquity im automatic-ubiquity-GTK-Modus real +# reproduzierbar ab (TypeError: Argument 1 does not allow None as a value, +# in ubi-prepare.py enable_download_updates() -> label_download_updates. +# set_label(), ausgeloest durch einen globalen Online-Status-Callback, der +# unabhaengig vom Automatik-Modus feuert, obwohl die zugehoerige Seite dort +# nie aufgebaut wird - die Widget-Referenz bleibt None). Die "Waehrend der +# Installation aktualisieren"-Option wird dadurch bewusst deaktiviert; +# funktional kein Verlust, da der Provisioning Agent das System nach der +# Ersteinrichtung ohnehin selbst aktuell haelt. +ubiquity ubiquity/download_updates boolean false # Pendant zu Fedoras kickstart.tpl %packages (ansible-core, git) - der # Provisioning Agent braucht ansible-pull, das wiederum git zum Klonen des diff --git a/initrd-hooks/casper-bottom/99casperboot b/initrd-hooks/casper-bottom/99casperboot index 6d5dd9c..a7d7fa8 100755 --- a/initrd-hooks/casper-bottom/99casperboot +++ b/initrd-hooks/casper-bottom/99casperboot @@ -35,4 +35,23 @@ if [ -d /root/cdrom/updates ]; then cp -a /root/cdrom/updates/. /root/ fi +# Ubiquity stuerzt im automatic-ubiquity-GTK-Modus real reproduzierbar ab +# (TypeError: Argument 1 does not allow None as a value), sobald +# enable_download_updates(False) den Netzwerkstatus als "nicht verbunden" +# meldet: ubi-prepare.py uebergibt das Ergebnis von +# self.controller.get_string('ubiquity/text/label_download_updates_na') +# ungeprueft an GtkLabel.set_label() - fehlt fuer diese Vorlage/Sprache ein +# Uebersetzungsstring, liefert get_string() None statt eines leeren Strings, +# und GTK akzeptiert kein None als Label-Text (real ueber QEMU-Testlauf +# gefunden, siehe ADR-0023-Nachtrag). Gezielter Sed-Patch statt vollstaendigem +# Datei-Ersatz, um nicht die komplette Drittanbieter-Datei mitpflegen zu +# muessen - betrifft nur die eine Zeile, "or ''" faengt jeden None-Rueckgabewert +# ab, unabhaengig von der genauen Ursache der fehlenden Uebersetzung. +ubi_prepare="/root/usr/lib/ubiquity/plugins/ubi-prepare.py" +if [ -f "$ubi_prepare" ]; then + sed -i \ + "s/self\.controller\.get_string(template))/self.controller.get_string(template) or '')/" \ + "$ubi_prepare" +fi + touch /run/.casper-boot diff --git a/live-updates/etc/systemd/system/multi-user.target.wants/tuxflotte-autoclicker.service b/live-updates/etc/systemd/system/multi-user.target.wants/tuxflotte-autoclicker.service new file mode 120000 index 0000000..c2bec14 --- /dev/null +++ b/live-updates/etc/systemd/system/multi-user.target.wants/tuxflotte-autoclicker.service @@ -0,0 +1 @@ +../tuxflotte-autoclicker.service \ No newline at end of file diff --git a/live-updates/etc/systemd/system/tuxflotte-autoclicker.service b/live-updates/etc/systemd/system/tuxflotte-autoclicker.service new file mode 100644 index 0000000..92647ac --- /dev/null +++ b/live-updates/etc/systemd/system/tuxflotte-autoclicker.service @@ -0,0 +1,17 @@ +[Unit] +Description=Tuxflotte Autoklicker fuer Ubiquitys GTK-Installationsassistenten +# Nur bei automatisierter Installation relevant (siehe autoclicker.sh - +# prueft selbst auf das Boot-Keyword "tuxflotte-autoclick" und beendet sich +# sofort, wenn es fehlt). Bewusst kein "After=graphical.target" o.ae., da +# ubiquity-dm keine normale Display-Manager-Sitzung startet, deren +# Bereitschaft systemd auf ueblichem Weg erkennen wuerde - das Skript selbst +# wartet auf den X-Socket. +After=multi-user.target + +[Service] +Type=simple +ExecStart=/opt/tuxflotte/scripts/autoclicker.sh +Restart=no + +[Install] +WantedBy=multi-user.target diff --git a/live-updates/opt/tuxflotte/scripts/autoclicker.sh b/live-updates/opt/tuxflotte/scripts/autoclicker.sh new file mode 100755 index 0000000..a728d28 --- /dev/null +++ b/live-updates/opt/tuxflotte/scripts/autoclicker.sh @@ -0,0 +1,111 @@ +#!/bin/bash +### Klickt automatisiert durch Ubiquitys GTK-Installationsassistenten +### (automatic-ubiquity) - noetig, weil Ubiquitys eigenes "noninteractive"- +### Frontend die gefuehrte Partitionierung nicht zuverlaessig automatisieren +### kann (endlose choose_partition-Schleife in ubi-partman.py, real +### bestaetigt, siehe ADR-0023-Nachtrag). Der GTK-Assistent fuellt jede Seite +### bereits vollstaendig aus dem Preseed vor (siehe preseed.tpl) - es fehlt +### nur der "Weiter"/"Installieren"-Klick pro Seite, den dieses Skript per +### xdotool simuliert. +### +### WICHTIG (real beim Testen entdeckt, siehe ADR-0023-Nachtrag): das +### Ubiquity-Fenster heisst NICHT "ubiquity" - der Fenstertitel ist z.B. +### "Installation (as superuser)". Eine Fenstersuche nach dem Namen "ubiquity" +### (fruehere Version dieses Skripts) findet also nie etwas und wurde hier auf +### eine Suche nach JEDEM sichtbaren, betitelten Fenster umgestellt. +### +### NOCH NICHT GELOEST (bewusst als bekannte Einschraenkung stehen gelassen, +### siehe ADR-0023-Nachtrag): auf der Partitionierungs-Uebersichtsseite +### aktiviert "Enter" NICHT den "Jetzt installieren"-Button, sondern einen +### Ausklapp-Pfeil eines darunterliegenden Status-Panels ("Konfiguration der +### Installation wird ueberprueft ..."). Ein Mausklick per xdotool auf +### errechnete Fensterkoordinaten wurde real ausprobiert, aber sowohl die +### Fenstererkennung (mehrere ueberlappende X11-Fenster gleicher/aehnlicher +### Groesse durch Metacity-Dekoration, "groesstes Fenster"-Heuristik traf +### wiederholt das falsche) als auch die Klick-Koordinaten selbst waren nicht +### zuverlaessig genug fuer den produktiven Einsatz - deshalb hier bewusst +### NICHT eingebaut, um kein Risiko falscher Klicks (z.B. auf eine +### "Formatieren?"-Checkbox) einzugehen. Die Enter-Taste bleibt der sicherere +### Kompromiss: sie tut auf den meisten Seiten das Richtige und ist auf dieser +### einen Seite bestenfalls wirkungslos (klappt nur einen Infobereich auf/zu), +### nie destruktiv. +### +### Wird per systemd-Service (siehe ...service im selben Ausliefer-Layer) bei +### JEDEM Boot gestartet, bricht aber sofort ab, wenn das eigene Boot-Keyword +### "tuxflotte-autoclick" nicht in /proc/cmdline steht - siehe backend_launch() +### in backends/mint/backend.sh, wo dieses Keyword gesetzt wird. Auf einem +### normalen (nicht automatisierten) Boot also wirkungslos. +set -u + +LOG=/var/log/tuxflotte-autoclicker.log +log() { + echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >>"${LOG}" +} + +grep -qw tuxflotte-autoclick /proc/cmdline || exit 0 + +log "tuxflotte-autoclick erkannt, starte Autoklicker." +export DISPLAY=:0 + +# ubiquity-dm startet X frueh im Boot zu einem nicht exakt vorhersagbaren +# Zeitpunkt - auf den Unix-Socket warten statt auf eine feste Wartezeit zu +# vertrauen. +x_ready=0 +for _ in $(seq 1 120); do + if [ -S /tmp/.X11-unix/X0 ]; then + x_ready=1 + break + fi + sleep 1 +done +if [ "${x_ready}" -ne 1 ]; then + log "X-Server nach 120s nicht erschienen, breche ab." + exit 1 +fi +log "X-Server erkannt." + +if ! command -v xdotool >/dev/null 2>&1; then + log "xdotool fehlt auf dem Live-Medium, installiere nach." + if ! apt-get install -y xdotool >>"${LOG}" 2>&1; then + log "xdotool-Installation fehlgeschlagen, breche ab." + exit 1 + fi +fi + +# Bewusst betiteltes Fenster suchen (leerer --name-Ausdruck matcht jeden +# Titel) statt nach "ubiquity" - siehe Kommentar oben, der tatsaechliche +# Fenstertitel enthaelt dieses Wort nie. +main_window() { + xdotool search --onlyvisible --name "" 2>/dev/null | head -n1 +} + +# Ubiquity-Fenster abwarten, bevor die Klick-Schleife beginnt. +for _ in $(seq 1 60); do + [ -n "$(main_window)" ] && break + sleep 1 +done + +is_ubiquity_running() { + pgrep -f '/usr/bin/ubiquity' >/dev/null 2>&1 +} + +log "Starte Klick-Schleife." +# Harte Obergrenze als Sicherheitsnetz (60 Minuten) - falls die Installation +# haengen bleibt, soll dieser Dienst nicht unbegrenzt weiterlaufen. +end=$((SECONDS + 3600)) +clicks=0 +while [ "${SECONDS}" -lt "${end}" ]; do + if ! is_ubiquity_running; then + log "ubiquity-Prozess nicht mehr aktiv (vermutlich fertig oder abgestuerzt), beende Schleife nach ${clicks} Klick(s)." + break + fi + + win="$(main_window)" + if [ -n "${win}" ]; then + xdotool windowactivate --sync "${win}" 2>/dev/null || true + xdotool key --window "${win}" Return 2>/dev/null || true + clicks=$((clicks + 1)) + fi + sleep 2 +done +log "Autoklicker beendet (${clicks} Klick(s) insgesamt)." diff --git a/scripts/modules/00_preflight.sh b/scripts/modules/00_preflight.sh index e69de29..33ce623 100755 --- a/scripts/modules/00_preflight.sh +++ b/scripts/modules/00_preflight.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# Tuxflotte Installer +# Phase 0 – Preflight +# +# Stellt sicher, dass Werkzeuge vorhanden sind, die spaetere Module (ab +# 10_hardware.sh) brauchen, aber auf dem Live-Medium selbst (anders als im +# Zielsystem, siehe pkgsel/include in preseed.tpl) nicht vorinstalliert sind. +# +# jq ist der einzige hier betroffene Fall: 10_hardware.sh, 12_enrollment_auth.sh, +# 15_server_handshake.sh, 17_device_status.sh, 20_profile_selection.sh, +# 25_installation_confirm.sh und 30_runtime_blueprint.sh nutzen es alle, das +# erste davon (10_hardware.sh) bereits deutlich vor 40_backend.sh, wo +# backend_init() denselben Nachinstallations-Mechanismus fuer den Kexec-Pfad +# schon kennt (siehe backends/mint/backend.sh) - hier zu spaet fuer die +# frueheren Module. Real entdeckt: beim automatisierten Start ueber +# start-kiosk.sh (kein Terminal, keine sichtbare Fehlermeldung) blieb der +# Installer bereits in 10_hardware.sh mit "Benoetigtes Programm nicht +# gefunden: jq" haengen, sichtbar nur in ~/.xsession-errors - manuelle Testlaeufe +# in dieser Session sind daran nie gescheitert, weil jq dabei stets vorab von +# Hand nachinstalliert wurde, bevor installer.sh gestartet wurde. +set -Eeuo pipefail + +readonly SCRIPT_NAME="${0##*/}" + +log() { + printf '[%s] %s\n' "${SCRIPT_NAME}" "$*" >&2 +} + +if ! command -v jq >/dev/null 2>&1; then + log "jq fehlt auf dem Live-Medium, installiere nach." + + sed -i '/^deb cdrom/d' /etc/apt/sources.list 2>/dev/null || true + rm -f /etc/apt/sources.list.d/*cdrom* 2>/dev/null || true + + apt-get update -qq || + { log "FEHLER: apt-get update fehlgeschlagen."; exit 1; } + DEBIAN_FRONTEND=noninteractive apt-get install -y jq || + { log "FEHLER: Installation von jq fehlgeschlagen."; exit 1; } +fi