#!/usr/bin/env bash load_config() { local config_file="$1" if [[ -f "$config_file" ]]; then # shellcheck disable=SC1090 source "$config_file" log_info "Konfiguration geladen: $config_file" else log_warn "Keine Konfiguration gefunden: $config_file" fi } # Module mit einem eigenen Modus (weder die generische Kreisel/Haken- # Kompaktdarstellung noch voll verbose): 40_backend.sh ist der mit Abstand # langlaeufigste Schritt (Minuten statt Sekunden) - Partitionieren/ # Formatieren/chroot-Fixup/Bootloader/Postinstall sind fuer den Kunden # ebenso uninteressant wie bei jedem anderen Modul, ABER der Download- # Fortschrittsbalken (image_deploy_extract_image_from_url()) soll trotzdem # sichtbar bleiben - siehe run_module_backend(). declare -a TUXFLOTTE_BACKEND_MODULES=(40_backend.sh) _tuxflotte_module_is_backend() { local module_name="$1" local candidate for candidate in "${TUXFLOTTE_BACKEND_MODULES[@]}"; do [[ "${candidate}" == "${module_name}" ]] && return 0 done return 1 } # Kompakte Modul-Ausfuehrung fuer den unbeaufsichtigten Auto-Modus (siehe # log_module_title()/log_module_ok()/log_module_failed() in logging.sh): # Modul laeuft im Hintergrund, waehrenddessen ein Kreisel auf derselben # Zeile, am Ende entweder ein gruener Haken (Erfolg, Detailausgabe nur ins # Logfile) oder ein rotes Kreuz + die volle mitgeschnittene Ausgabe auf der # Konsole (Fehlschlag - Fehlersuche darf nie schlechter werden als vorher). run_module_quiet() { local module="$1" local module_name module_name="$(basename "${module}")" log_module_title "${module_name}" local title="${TUXFLOTTE_CURRENT_TITLE}" local output_file output_file="$(mktemp)" # shellcheck disable=SC1090 "${module}" >"${output_file}" 2>&1 & local pid=$! if _tuxflotte_console_is_live; then printf '%s ' "${title}" local frame_index=0 local frame_count="${#_TUXFLOTTE_SPINNER_FRAMES[@]}" while kill -0 "${pid}" 2>/dev/null; do printf '\r%s %s' "${title}" "${_TUXFLOTTE_SPINNER_FRAMES[$((frame_index % frame_count))]}" frame_index=$((frame_index + 1)) sleep 0.1 done fi # "wait || status=$?" statt eines nackten "wait"-Aufrufs - genau das # bekannte &&/||-Gegenstueck zu "set -e" (siehe die mount-Bind-Lehre in # image_deploy.sh), hier bewusst genutzt, um den echten Exit-Code sauber # auszuwerten statt das ganze Skript sofort abzubrechen. local status=0 wait "${pid}" || status=$? if [[ "${status}" -eq 0 ]]; then log_module_ok "${title}" else log_module_failed "${title}" echo cat "${output_file}" echo fi [[ -n "${TUXFLOTTE_LOG_FILE:-}" ]] && cat "${output_file}" >>"${TUXFLOTTE_LOG_FILE}" 2>/dev/null rm -f "${output_file}" return "${status}" } # Wie run_module_quiet(), aber ohne animierten Kreisel: der Titel wird # einmalig mit Zeilenumbruch ausgegeben (nicht per "\r" ueberschrieben) und # das Modul laeuft im Vordergrund (kein Hintergrundprozess noetig, da kein # Kreisel dagegen ankaempft). Grund: image_deploy_extract_image_from_url() # schreibt den Download-Fortschrittsbalken bei aktivem TUXFLOTTE_TTY_LIVE # direkt auf /dev/tty1 (siehe dort) - das umgeht die stdout/stderr- # Umleitung dieser Funktion bewusst, landet also auf einer eigenen, # unbenutzten Zeile direkt unter dem Titel, statt mit einem "\r"-Kreisel # um dieselbe Zeile zu konkurrieren. # # Nutzer-Feedback (01.09.2026, zweiter echter Hardware-Test): "Das # backend40-Script/Partitionierung zeigt viele Zeilen Ausgaben... Der # Fortschrittsbalken ist super! Nach dem Entpacken kommen wieder sehr # viele Zeilen Ausgaben" - Partitionieren/Formatieren/chroot-Fixup/ # Bootloader/Postinstall sollen wie jedes andere Modul verborgen bleiben, # nur der Fortschrittsbalken bleibt sichtbar. run_module_backend() { local module="$1" local module_name module_name="$(basename "${module}")" log_module_title "${module_name}" local title="${TUXFLOTTE_CURRENT_TITLE}" printf '%s ...\n' "${title}" local output_file output_file="$(mktemp)" local status=0 # shellcheck disable=SC1090 "${module}" >"${output_file}" 2>&1 || status=$? if [[ "${status}" -eq 0 ]]; then printf '%s \033[1;32m[OK]\033[0m\n' "${title}" else printf '%s \033[1;31m[FEHLER]\033[0m\n' "${title}" echo cat "${output_file}" echo fi [[ -n "${TUXFLOTTE_LOG_FILE:-}" ]] && cat "${output_file}" >>"${TUXFLOTTE_LOG_FILE}" 2>/dev/null rm -f "${output_file}" return "${status}" } run_module() { local module="$1" local mode="${2:-normal}" local module_name module_name="$(basename "$module")" [[ -f "$module" ]] || error_exit "Modul nicht gefunden: $module" if [[ "${DRY_RUN:-false}" == true && "$mode" != "always" ]]; then log_step "${module_name}" log_warn "Dry-Run: Modul übersprungen: $module" return 0 fi # Kompakte Kreisel/Haken-Darstellung nur im echten Auto-Modus: nur dort # ist sichergestellt, dass kein Modul interaktiv nach Eingaben fragt # (12_enrollment_auth.sh/20_profile_selection.sh/25_installation_confirm.sh # pruefen TUXFLOTTE_AUTO_MODE selbst und ueberspringen ihre Prompts) - # ein Prompt-Text waere sonst zusammen mit der restlichen Ausgabe in # output_file gefangen und fuer die Person vor dem Geraet unsichtbar. if [[ "${TUXFLOTTE_AUTO_MODE:-false}" == "true" ]]; then if _tuxflotte_module_is_backend "${module_name}"; then run_module_backend "$module" else run_module_quiet "$module" fi return "$?" fi log_step "${module_name}" log_info "Starte Modul: ${module_name}" # shellcheck disable=SC1090 "$module" log_success "Modul abgeschlossen: ${module_name}" } require_root() { [[ "$EUID" -eq 0 ]] || error_exit "Installer muss als root ausgeführt werden." } command_exists() { command -v "$1" >/dev/null 2>&1 }