feat(boot-medium): build_customer_iso.sh ans neue Struktur anpassen (Phase 3) + vier echte Deployment-Bugs behoben
Phase 3: Personalisierung (Aktivierungscode/WLAN) funktioniert jetzt ohne
Xorriso-Extraktion der ganzen ISO / Casper-Hook-Injection. /opt/tuxflotte/
liegt innerhalb von /live/filesystem.squashfs (read-only) - ein direktes
xorriso -update auf eine Datei darin traf live getestet ins Leere.
Stattdessen: Squashfs entpacken (unsquashfs), installer.conf ersetzen, neu
packen (mksquashfs -comp xz, ~1 Minute reine Kompression, kein
debootstrap/apt), als Ganzes per xorriso -update einspielen. Muss als root
laufen (Datei-Eigentuemer im Squashfs sonst falsch).
Beim ersten echten End-to-End-Testlauf mit dem vollen Golden-Image-Archiv
(vorher nie bis zum Ende gekommen - immer am Ubiquity-Bug oder an einem
Commit-Gate gestoppt) vier echte, bisher unentdeckte Bugs gefunden und
behoben:
1. Golden-Image-Download landete in /run/tuxflotte/backend/ (RAM-Tmpfs,
hier 392 MB) statt auf echtem Speicher - "curl: (23) Failure writing
output to destination" bei 2,3 GB Archiv, unabhaengig von RAM-Groesse.
Fix: image_deploy_extract_image_from_url() streamt Download direkt in
die Extraktion (curl | tar), kein Zwischenspeichern mehr noetig.
backend_launch() partitioniert/formatiert/mountet jetzt VOR dem
Download-Versuch statt danach.
2. /etc/resolv.conf im Zielbaum ist bei der echten Referenz-VM ein von
NetworkManager verwalteter Symlink - "cp" verweigerte das Schreiben
"through a dangling symlink". Fix: Ziel vor dem Kopieren explizit
entfernen.
3. mount --bind auf /dev, /proc, /sys schlug fehl, weil diese Verzeichnisse
nach dem Entpacken gar nicht existierten (package_golden_image.sh
schliesst sie bewusst aus) - und zwar SILENT, weil das bisherige
"cmd && stack_ref+=(...)"-Muster einen Fehlschlag unter "set -e" nicht
als Statement-Fehler wertet. Fiel dadurch erst beim naechsten
chroot-Aufruf auf ("ssh-keygen -A: Couldn't open /dev/null"), weit weg
von der eigentlichen Ursache. Fix: neue image_deploy_restore_excluded_dirs()
legt alle sechs von package_golden_image.sh ausgeschlossenen
Verzeichnisse (proc/sys/dev/run/tmp/var-tmp) direkt nach der Extraktion
wieder an; jeder Mount wird jetzt einzeln explizit geprueft statt auf
&&-Verkettung zu vertrauen.
4. package_golden_image.sh: "--exclude=dev" (ohne "./"-Praefix) matcht bei
GNU tar gegen JEDEN Verzeichnis-Basisnamen im ganzen Baum, nicht nur
den Top-Level-Eintrag - hat dadurch auch kernel/drivers/net/can/dev/
(ein zufaellig gleichnamiger, voellig unverwandter Kernelmodul-Ordner)
aus dem Archiv gerissen, update-initramfs scheiterte an fehlenden
can-dev.ko.zst-Abhaengigkeiten. Lokal mit einem Wegwerf-Testbaum
verifiziert (wie beim "run"-Fund vom selben Tag): "./"-Praefix
verankert das Muster auf den exakten Top-Level-Pfad, gleichnamige
verschachtelte Ordner bleiben erhalten. Betrifft das AKTUELL AUF ANODE
GEHOSTETE Archiv - muss mit dem korrigierten Skript auf der
Referenz-VM neu gepackt und hochgeladen werden (steht noch aus,
Nutzer verschlankt die Referenz-VM gerade zusaetzlich).
Live-Fortschritt in der enterprise-QEMU-VM: nach Fix 1-3 kam der
Deployment-Versuch bis kurz vor update-initramfs durch (Partitionierung,
Formatierung, Mounten, Download+Extraktion, chroot-Fixup bis machine-id +
SSH-Hostkeys liefen alle sauber) - Fund 4 (das defekte Archiv) ist der
letzte noch offene Blocker fuer einen vollstaendig erfolgreichen
End-to-End-Durchlauf.
This commit is contained in:
parent
95447f7486
commit
27d6fa0f47
@ -28,7 +28,6 @@ HARDWARE_FILE="/run/tuxflotte/hardware/hardware.json"
|
|||||||
|
|
||||||
RUNTIME_DIR="/run/tuxflotte/backend"
|
RUNTIME_DIR="/run/tuxflotte/backend"
|
||||||
CONFIG_FILE="${RUNTIME_DIR}/config.json"
|
CONFIG_FILE="${RUNTIME_DIR}/config.json"
|
||||||
GOLDEN_IMAGE_FILE="${RUNTIME_DIR}/golden-image.tar.zst"
|
|
||||||
|
|
||||||
# Ziel-Mountpunkt fuer die Deployment-Mechanik - global, da backend_launch()
|
# Ziel-Mountpunkt fuer die Deployment-Mechanik - global, da backend_launch()
|
||||||
# und backend_postinstall() (separate Funktionsaufrufe, aber dieselbe
|
# und backend_postinstall() (separate Funktionsaufrufe, aber dieselbe
|
||||||
@ -100,7 +99,7 @@ backend_init() {
|
|||||||
--group=root \
|
--group=root \
|
||||||
"${RUNTIME_DIR}"
|
"${RUNTIME_DIR}"
|
||||||
|
|
||||||
rm -f -- "${CONFIG_FILE}" "${GOLDEN_IMAGE_FILE}"
|
rm -f -- "${CONFIG_FILE}"
|
||||||
|
|
||||||
backend_log "Initialisiert."
|
backend_log "Initialisiert."
|
||||||
}
|
}
|
||||||
@ -203,11 +202,6 @@ backend_launch() {
|
|||||||
|
|
||||||
root_fs="$(jq --raw-output '.root_filesystem' "${CONFIG_FILE}")"
|
root_fs="$(jq --raw-output '.root_filesystem' "${CONFIG_FILE}")"
|
||||||
|
|
||||||
backend_log "Lade Golden Image von ${GOLDEN_IMAGE_URL}"
|
|
||||||
curl --silent --show-error --fail --location \
|
|
||||||
--output "${GOLDEN_IMAGE_FILE}" "${GOLDEN_IMAGE_URL}" ||
|
|
||||||
{ backend_fatal "Golden Image konnte nicht geladen werden: ${GOLDEN_IMAGE_URL}"; return 1; }
|
|
||||||
|
|
||||||
backend_log "Partitioniere ${disk}"
|
backend_log "Partitioniere ${disk}"
|
||||||
read -r boot_part root_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
|
read -r boot_part root_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
|
||||||
return 1
|
return 1
|
||||||
@ -218,9 +212,15 @@ backend_launch() {
|
|||||||
backend_log "Mounte unter ${TARGET_DIR}"
|
backend_log "Mounte unter ${TARGET_DIR}"
|
||||||
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
|
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
|
||||||
|
|
||||||
backend_log "Entpacke Golden Image"
|
# Live gefunden (31.08.2026, erster echter End-to-End-Lauf mit dem vollen
|
||||||
image_deploy_extract_image "${GOLDEN_IMAGE_FILE}" "${TARGET_DIR}" || return 1
|
# Referenz-VM-Archiv): "erst nach /run/tuxflotte/... herunterladen, dann
|
||||||
rm -f "${GOLDEN_IMAGE_FILE}"
|
# entpacken" scheiterte an /run (RAM-Tmpfs, viel kleiner als das
|
||||||
|
# 2,3-GB-Archiv - "curl: (23) Failure writing output to destination").
|
||||||
|
# Direktes Streamen in die Extraktion braucht nur ein paar MB Puffer,
|
||||||
|
# unabhaengig von der Archivgroesse - deshalb erst ab hier (nach
|
||||||
|
# Partitionieren/Formatieren/Mounten), kein Zwischenspeichern mehr.
|
||||||
|
backend_log "Lade und entpacke Golden Image von ${GOLDEN_IMAGE_URL}"
|
||||||
|
image_deploy_extract_image_from_url "${GOLDEN_IMAGE_URL}" "${TARGET_DIR}" || return 1
|
||||||
|
|
||||||
backend_log "Schreibe fstab"
|
backend_log "Schreibe fstab"
|
||||||
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
|
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
|
||||||
|
|||||||
@ -28,7 +28,6 @@ HARDWARE_FILE="/run/tuxflotte/hardware/hardware.json"
|
|||||||
|
|
||||||
RUNTIME_DIR="/run/tuxflotte/backend"
|
RUNTIME_DIR="/run/tuxflotte/backend"
|
||||||
CONFIG_FILE="${RUNTIME_DIR}/config.json"
|
CONFIG_FILE="${RUNTIME_DIR}/config.json"
|
||||||
GOLDEN_IMAGE_FILE="${RUNTIME_DIR}/golden-image.tar.zst"
|
|
||||||
|
|
||||||
# Ziel-Mountpunkt fuer die Deployment-Mechanik - global, da backend_launch()
|
# Ziel-Mountpunkt fuer die Deployment-Mechanik - global, da backend_launch()
|
||||||
# und backend_postinstall() (separate Funktionsaufrufe, aber dieselbe
|
# und backend_postinstall() (separate Funktionsaufrufe, aber dieselbe
|
||||||
@ -100,7 +99,7 @@ backend_init() {
|
|||||||
--group=root \
|
--group=root \
|
||||||
"${RUNTIME_DIR}"
|
"${RUNTIME_DIR}"
|
||||||
|
|
||||||
rm -f -- "${CONFIG_FILE}" "${GOLDEN_IMAGE_FILE}"
|
rm -f -- "${CONFIG_FILE}"
|
||||||
|
|
||||||
backend_log "Initialisiert."
|
backend_log "Initialisiert."
|
||||||
}
|
}
|
||||||
@ -203,11 +202,6 @@ backend_launch() {
|
|||||||
|
|
||||||
root_fs="$(jq --raw-output '.root_filesystem' "${CONFIG_FILE}")"
|
root_fs="$(jq --raw-output '.root_filesystem' "${CONFIG_FILE}")"
|
||||||
|
|
||||||
backend_log "Lade Golden Image von ${GOLDEN_IMAGE_URL}"
|
|
||||||
curl --silent --show-error --fail --location \
|
|
||||||
--output "${GOLDEN_IMAGE_FILE}" "${GOLDEN_IMAGE_URL}" ||
|
|
||||||
{ backend_fatal "Golden Image konnte nicht geladen werden: ${GOLDEN_IMAGE_URL}"; return 1; }
|
|
||||||
|
|
||||||
backend_log "Partitioniere ${disk}"
|
backend_log "Partitioniere ${disk}"
|
||||||
read -r boot_part root_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
|
read -r boot_part root_part <<<"$(image_deploy_partition "${disk}" "${is_efi}")" ||
|
||||||
return 1
|
return 1
|
||||||
@ -218,9 +212,15 @@ backend_launch() {
|
|||||||
backend_log "Mounte unter ${TARGET_DIR}"
|
backend_log "Mounte unter ${TARGET_DIR}"
|
||||||
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
|
image_deploy_mount "${TARGET_DIR}" "${boot_part}" "${root_part}" || return 1
|
||||||
|
|
||||||
backend_log "Entpacke Golden Image"
|
# Live gefunden (31.08.2026, erster echter End-to-End-Lauf mit dem vollen
|
||||||
image_deploy_extract_image "${GOLDEN_IMAGE_FILE}" "${TARGET_DIR}" || return 1
|
# Referenz-VM-Archiv): "erst nach /run/tuxflotte/... herunterladen, dann
|
||||||
rm -f "${GOLDEN_IMAGE_FILE}"
|
# entpacken" scheiterte an /run (RAM-Tmpfs, viel kleiner als das
|
||||||
|
# 2,3-GB-Archiv - "curl: (23) Failure writing output to destination").
|
||||||
|
# Direktes Streamen in die Extraktion braucht nur ein paar MB Puffer,
|
||||||
|
# unabhaengig von der Archivgroesse - deshalb erst ab hier (nach
|
||||||
|
# Partitionieren/Formatieren/Mounten), kein Zwischenspeichern mehr.
|
||||||
|
backend_log "Lade und entpacke Golden Image von ${GOLDEN_IMAGE_URL}"
|
||||||
|
image_deploy_extract_image_from_url "${GOLDEN_IMAGE_URL}" "${TARGET_DIR}" || return 1
|
||||||
|
|
||||||
backend_log "Schreibe fstab"
|
backend_log "Schreibe fstab"
|
||||||
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
|
image_deploy_write_fstab "${TARGET_DIR}" "${boot_part}" "${root_part}" "${root_fs}" || return 1
|
||||||
|
|||||||
@ -115,6 +115,25 @@ image_deploy_mount() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# package_golden_image.sh schliesst /proc, /sys, /dev, /run, /tmp, /var/tmp
|
||||||
|
# bewusst aus dem Archiv aus (Laufzeit-Zustand der Referenz-VM, nicht Teil
|
||||||
|
# eines portablen Images). Nach dem Entpacken fehlen diese Verzeichnisse
|
||||||
|
# deshalb komplett - live gefunden (31.08.2026, erster echter Lauf mit dem
|
||||||
|
# echten Referenz-VM-Archiv): erst "mount --bind /dev" ("mount point does
|
||||||
|
# not exist"), dann - nach Behebung dessen - "mktemp: failed to create
|
||||||
|
# directory via template '/var/tmp/mkinitramfs_XXXXXX'" bei
|
||||||
|
# update-initramfs. Statt jedes Fehlen einzeln zu jagen: alle sechs
|
||||||
|
# ausgeschlossenen Verzeichnisse direkt nach dem Entpacken einmalig mit
|
||||||
|
# sinnvollen Rechten wiederherstellen. /dev, /proc, /sys werden gleich
|
||||||
|
# danach ohnehin ueberbindmounted (image_deploy_bind_mounts) - schadet
|
||||||
|
# aber nicht, sie schon hier als leere Verzeichnisse anzulegen.
|
||||||
|
image_deploy_restore_excluded_dirs() {
|
||||||
|
local target="$1"
|
||||||
|
|
||||||
|
mkdir -p "${target}"/{proc,sys,dev,run,tmp,var/tmp}
|
||||||
|
chmod 1777 "${target}/tmp" "${target}/var/tmp"
|
||||||
|
}
|
||||||
|
|
||||||
# Entpackt das per build_golden_image.sh gebaute Golden Image direkt in
|
# Entpackt das per build_golden_image.sh gebaute Golden Image direkt in
|
||||||
# den gemounteten Zielbaum. -p erhaelt Rechte/Eigentuemer, --zstd deckt
|
# den gemounteten Zielbaum. -p erhaelt Rechte/Eigentuemer, --zstd deckt
|
||||||
# sowohl .tar.zst als auch (falls spaeter gewechselt) andere
|
# sowohl .tar.zst als auch (falls spaeter gewechselt) andere
|
||||||
@ -128,6 +147,40 @@ image_deploy_extract_image() {
|
|||||||
|
|
||||||
tar --zstd -xpf "${image_path}" -C "${target}" ||
|
tar --zstd -xpf "${image_path}" -C "${target}" ||
|
||||||
{ image_deploy_fatal "Golden Image konnte nicht nach ${target} entpackt werden"; return 1; }
|
{ image_deploy_fatal "Golden Image konnte nicht nach ${target} entpackt werden"; return 1; }
|
||||||
|
|
||||||
|
image_deploy_restore_excluded_dirs "${target}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Streamt das Golden Image direkt vom Server in die Extraktion, ohne es
|
||||||
|
# jemals als Ganzes zwischenzuspeichern - live gefunden (31.08.2026,
|
||||||
|
# erster echter End-to-End-Lauf mit dem vollen 2,3-GB-Referenz-VM-Archiv
|
||||||
|
# ueber das neue Boot-Medium): das bisherige "erst nach /run/tuxflotte/...
|
||||||
|
# herunterladen, dann entpacken" scheiterte an /run (RAM-Tmpfs, oft nur
|
||||||
|
# ein paar hundert MB gross, unabhaengig von der Geraete-RAM-Groesse) -
|
||||||
|
# "curl: (23) Failure writing output to destination". Direktes
|
||||||
|
# Zusammenrohren braucht dagegen nur ein paar MB Puffer, unabhaengig von
|
||||||
|
# der Archivgroesse. PIPESTATUS wird explizit geprueft statt sich auf
|
||||||
|
# "pipefail"-Semantik (rechteste fehlgeschlagene Stufe gewinnt) zu
|
||||||
|
# verlassen, damit die Fehlermeldung eindeutig zwischen Download- und
|
||||||
|
# Entpack-Fehler unterscheidet.
|
||||||
|
image_deploy_extract_image_from_url() {
|
||||||
|
local url="$1"
|
||||||
|
local target="$2"
|
||||||
|
local pipe_status
|
||||||
|
|
||||||
|
# "|| true" verhindert, dass "set -e" hier sofort abbricht - der
|
||||||
|
# eigentliche Fehlerfall wird gleich anhand von PIPESTATUS gezielt
|
||||||
|
# ausgewertet, statt die Pipeline roh durchschlagen zu lassen.
|
||||||
|
curl --silent --show-error --fail --location "${url}" |
|
||||||
|
tar --zstd -xpf - -C "${target}" || true
|
||||||
|
pipe_status=("${PIPESTATUS[@]}")
|
||||||
|
|
||||||
|
[[ "${pipe_status[0]}" -eq 0 ]] ||
|
||||||
|
{ image_deploy_fatal "Golden Image konnte nicht geladen werden: ${url}"; return 1; }
|
||||||
|
[[ "${pipe_status[1]}" -eq 0 ]] ||
|
||||||
|
{ image_deploy_fatal "Golden Image konnte nicht nach ${target} entpackt werden"; return 1; }
|
||||||
|
|
||||||
|
image_deploy_restore_excluded_dirs "${target}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# /etc/fstab aus den tatsaechlichen Partitions-UUIDs neu erzeugen - kein
|
# /etc/fstab aus den tatsaechlichen Partitions-UUIDs neu erzeugen - kein
|
||||||
@ -166,11 +219,48 @@ image_deploy_bind_mounts() {
|
|||||||
local target="$1"
|
local target="$1"
|
||||||
local -n stack_ref="$2"
|
local -n stack_ref="$2"
|
||||||
|
|
||||||
mount --bind /dev "${target}/dev" && stack_ref+=("${target}/dev")
|
# Golden Image schliesst /dev, /proc, /sys bewusst aus
|
||||||
mount -t proc proc "${target}/proc" && stack_ref+=("${target}/proc")
|
# (package_golden_image.sh --exclude=dev/sys/proc) - die Zielverzeichnisse
|
||||||
mount -t sysfs sysfs "${target}/sys" && stack_ref+=("${target}/sys")
|
# existieren nach dem Entpacken deshalb noch nicht und muessen vor dem
|
||||||
mount -t devpts devpts "${target}/dev/pts" && stack_ref+=("${target}/dev/pts")
|
# Bind-Mount erst angelegt werden. Live gefunden (31.08.2026, erster
|
||||||
cp /etc/resolv.conf "${target}/etc/resolv.conf"
|
# echter Lauf mit der echten Mint-Referenz-VM): ohne das schlaegt
|
||||||
|
# "mount --bind" mit "mount point does not exist" fehl - und zwar
|
||||||
|
# SILENT, weil das bisherige "cmd && stack_ref+=(...)"-Muster einen
|
||||||
|
# Fehlschlag von "cmd" unter "set -e" nicht als Statement-Fehler wertet
|
||||||
|
# (wohlbekannte Bash-Ausnahme fuer &&/||-Ketten) - der fehlende
|
||||||
|
# /dev-Bind-Mount fiel dann erst beim naechsten chroot-Aufruf auf
|
||||||
|
# ("ssh-keygen -A: Couldn't open /dev/null"), weit weg von der
|
||||||
|
# eigentlichen Ursache. Jetzt: Zielverzeichnisse anlegen, jeden
|
||||||
|
# Mount-Fehler explizit und einzeln pruefen statt auf &&-Verkettung
|
||||||
|
# zu vertrauen.
|
||||||
|
mkdir -p "${target}/dev" "${target}/proc" "${target}/sys" "${target}/dev/pts"
|
||||||
|
|
||||||
|
mount --bind /dev "${target}/dev" ||
|
||||||
|
{ image_deploy_fatal "/dev konnte nicht eingebunden werden"; return 1; }
|
||||||
|
stack_ref+=("${target}/dev")
|
||||||
|
|
||||||
|
mount -t proc proc "${target}/proc" ||
|
||||||
|
{ image_deploy_fatal "/proc konnte nicht eingebunden werden"; return 1; }
|
||||||
|
stack_ref+=("${target}/proc")
|
||||||
|
|
||||||
|
mount -t sysfs sysfs "${target}/sys" ||
|
||||||
|
{ image_deploy_fatal "/sys konnte nicht eingebunden werden"; return 1; }
|
||||||
|
stack_ref+=("${target}/sys")
|
||||||
|
|
||||||
|
mount -t devpts devpts "${target}/dev/pts" ||
|
||||||
|
{ image_deploy_fatal "/dev/pts konnte nicht eingebunden werden"; return 1; }
|
||||||
|
stack_ref+=("${target}/dev/pts")
|
||||||
|
|
||||||
|
# Live gefunden (31.08.2026, erster echter Lauf mit der echten
|
||||||
|
# Mint-Referenz-VM statt eines debootstrap-Test-Images): dort ist
|
||||||
|
# /etc/resolv.conf ein von NetworkManager verwalteter Symlink (z.B. auf
|
||||||
|
# /run/NetworkManager/resolv.conf) - im gerade erst entpackten,
|
||||||
|
# ungebooteten Zielbaum zeigt der ins Leere, "cp" verweigert dann das
|
||||||
|
# Schreiben "through a dangling symlink". Ziel deshalb vorher entfernen
|
||||||
|
# (Symlink oder Datei, beides abgedeckt), erst dann kopieren.
|
||||||
|
rm -f "${target}/etc/resolv.conf"
|
||||||
|
cp /etc/resolv.conf "${target}/etc/resolv.conf" ||
|
||||||
|
{ image_deploy_fatal "resolv.conf konnte nicht nach ${target} kopiert werden"; return 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
image_deploy_unbind_mounts() {
|
image_deploy_unbind_mounts() {
|
||||||
|
|||||||
@ -1,16 +1,34 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# Baut eine personalisierte Kunden-ISO fuer den Self-Service-Flow (Phase 4).
|
# Personalisiert das eigenstaendige Boot-Medium (scripts/build_boot_medium.sh)
|
||||||
# Anders als build.sh (das fuer Testzwecke einen statischen Preseed mit
|
# fuer eine bestimmte Kundenorganisation - befuellt config/installer.conf mit
|
||||||
# Fake-Geraete-ID einbrennt, siehe bake_test_preseed()) wird hier nur
|
# Aktivierungscode + WLAN-Zugangsdaten. Hostname/Geraete-ID/Partitionierung
|
||||||
# config/installer.conf mit den echten, organisationsspezifischen Werten
|
# werden weiterhin erst live auf dem Zielgeraet erzeugt (siehe
|
||||||
# befuellt - Hostname/Geraete-ID/Partitionierung werden weiterhin erst live
|
# backend_generate_config() in backends/mint-image/backend.sh).
|
||||||
# auf dem Zielgeraet erzeugt (siehe backend_generate_config() in
|
#
|
||||||
# backends/mint/backend.sh). Hier geht es nur um WLAN-Zugangsdaten +
|
# Anders als das alte, Casper-basierte Verfahren (Xorriso-Extraktion der
|
||||||
# Enrollment-Session-Code als Boot-Konfiguration, die start-kiosk.sh dazu
|
# ganzen ISO + Initrd-Hook-Injection, siehe scripts/lib/initrd.sh) kann hier
|
||||||
# bringt, den Installer beim Hochfahren automatisch zu starten statt der
|
# NICHT einfach eine einzelne Datei direkt auf der ISO9660-Ebene ersetzt
|
||||||
# interaktiven Kiosk-Startseite.
|
# 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() {
|
usage() {
|
||||||
echo "Usage: $0 <source.iso> <output.iso> <activation_code> [wifi_ssid] [wifi_psk] [volid]" >&2
|
echo "Usage: $0 <source.iso> <output.iso> <activation_code> [wifi_ssid] [wifi_psk] [volid]" >&2
|
||||||
@ -28,20 +46,6 @@ WIFI_PSK="${5:-}"
|
|||||||
# Aufrufe ohne sechsten Parameter (z.B. manuelle Tests).
|
# Aufrufe ohne sechsten Parameter (z.B. manuelle Tests).
|
||||||
VOLID="${6:-TUXFLOTTE}"
|
VOLID="${6:-TUXFLOTTE}"
|
||||||
|
|
||||||
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
||||||
WORK_DIR="$(mktemp -d)"
|
|
||||||
|
|
||||||
# shellcheck source=lib/initrd.sh
|
|
||||||
source "$REPO_DIR/scripts/lib/initrd.sh"
|
|
||||||
|
|
||||||
cleanup() {
|
|
||||||
# xorriso extrahiert Verzeichnisse teils mit den Original-ISO-Rechten
|
|
||||||
# (z.B. 555, kein 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
|
|
||||||
|
|
||||||
if [[ -z "${SOURCE_ISO}" || -z "${OUTPUT_ISO}" || -z "${ACTIVATION_CODE}" ]]; then
|
if [[ -z "${SOURCE_ISO}" || -z "${OUTPUT_ISO}" || -z "${ACTIVATION_CODE}" ]]; then
|
||||||
usage
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
@ -50,51 +54,47 @@ fi
|
|||||||
[[ -f "${SOURCE_ISO}" ]] ||
|
[[ -f "${SOURCE_ISO}" ]] ||
|
||||||
{ echo "Error: Quell-ISO nicht gefunden: ${SOURCE_ISO}" >&2; exit 1; }
|
{ echo "Error: Quell-ISO nicht gefunden: ${SOURCE_ISO}" >&2; exit 1; }
|
||||||
|
|
||||||
for cmd in xorriso cpio; do
|
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 ||
|
command -v "${cmd}" >/dev/null 2>&1 ||
|
||||||
{ echo "Error: fehlendes Werkzeug: ${cmd}" >&2; exit 1; }
|
{ echo "Error: fehlendes Werkzeug: ${cmd}" >&2; exit 1; }
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "Extrahiere Quell-ISO..."
|
WORK_DIR="$(mktemp -d)"
|
||||||
xorriso -indev "${SOURCE_ISO}" -osirrox on -extract / "${WORK_DIR}" >/dev/null
|
|
||||||
# xorriso uebernimmt die Original-ISO-Rechte (haeufig 555 auf
|
|
||||||
# Verzeichnissen, 444 auf Dateien) - ohne Write-Bit koennen weder
|
|
||||||
# spaetere Schritte noch der Cleanup-Trap Dateien darin ersetzen/entfernen.
|
|
||||||
chmod -R u+w "${WORK_DIR}"
|
|
||||||
|
|
||||||
echo "Installiere Tuxflotte-GRUB-Konfiguration..."
|
cleanup() {
|
||||||
# -f: xorriso extrahiert ISO-Dateien mit deren Original-Rechten, die auf
|
# unsquashfs uebernimmt Original-Rechte (teils ohne Write-Bit) - ohne
|
||||||
# Live-Medien haeufig read-only (444) sind - ohne -f schlaegt cp beim
|
# chmod schlaegt rm -rf darauf fehl.
|
||||||
# Ueberschreiben mit "Keine Berechtigung" fehl.
|
chmod -R u+w "${WORK_DIR}" 2>/dev/null || true
|
||||||
cp -f "${REPO_DIR}/grub/mint-boot-grub.cfg" "${WORK_DIR}/boot/grub/grub.cfg"
|
rm -rf "${WORK_DIR}"
|
||||||
cp -f "${REPO_DIR}/grub/mint-isolinux-live.cfg" "${WORK_DIR}/isolinux/live.cfg"
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
grep -q "Tuxflotte" "${WORK_DIR}/boot/grub/grub.cfg"
|
echo "Extrahiere Squashfs aus Quell-ISO..."
|
||||||
grep -q "Tuxflotte" "${WORK_DIR}/isolinux/live.cfg"
|
xorriso -indev "${SOURCE_ISO}" -osirrox on -extract /live/filesystem.squashfs \
|
||||||
|
"${WORK_DIR}/orig.squashfs" >/dev/null
|
||||||
|
|
||||||
echo "Baue personalisierte Boot-Konfiguration..."
|
echo "Entpacke Squashfs..."
|
||||||
updates_dir="${WORK_DIR}/updates"
|
unsquashfs -d "${WORK_DIR}/root" "${WORK_DIR}/orig.squashfs" >/dev/null
|
||||||
rm -rf "${updates_dir}"
|
|
||||||
mkdir -p "${updates_dir}"
|
|
||||||
cp -a "${REPO_DIR}/live-updates/." "${updates_dir}/"
|
|
||||||
cp -a "${REPO_DIR}/scripts" "${updates_dir}/opt/tuxflotte/"
|
|
||||||
cp -a "${REPO_DIR}/backends" "${updates_dir}/opt/tuxflotte/"
|
|
||||||
mkdir -p "${updates_dir}/opt/tuxflotte/config"
|
|
||||||
|
|
||||||
|
echo "Schreibe personalisierte installer.conf..."
|
||||||
|
mkdir -p "${WORK_DIR}/root/opt/tuxflotte/config"
|
||||||
{
|
{
|
||||||
echo "export TUXFLOTTE_AUTO_MODE=true"
|
echo "export TUXFLOTTE_AUTO_MODE=true"
|
||||||
printf 'export TUXFLOTTE_ACTIVATION_CODE=%q\n' "${ACTIVATION_CODE}"
|
printf 'export TUXFLOTTE_ACTIVATION_CODE=%q\n' "${ACTIVATION_CODE}"
|
||||||
[[ -n "${WIFI_SSID}" ]] && printf 'export TUXFLOTTE_WIFI_SSID=%q\n' "${WIFI_SSID}"
|
[[ -n "${WIFI_SSID}" ]] && printf 'export TUXFLOTTE_WIFI_SSID=%q\n' "${WIFI_SSID}"
|
||||||
[[ -n "${WIFI_PSK}" ]] && printf 'export TUXFLOTTE_WIFI_PSK=%q\n' "${WIFI_PSK}"
|
[[ -n "${WIFI_PSK}" ]] && printf 'export TUXFLOTTE_WIFI_PSK=%q\n' "${WIFI_PSK}"
|
||||||
} >"${updates_dir}/opt/tuxflotte/config/installer.conf"
|
} >"${WORK_DIR}/root/opt/tuxflotte/config/installer.conf"
|
||||||
|
|
||||||
chmod 0440 "${updates_dir}/etc/sudoers.d/90-tuxflotte"
|
echo "Packe Squashfs neu (nur Kompression, kein apt/debootstrap)..."
|
||||||
|
mksquashfs "${WORK_DIR}/root" "${WORK_DIR}/new.squashfs" -comp xz -no-progress >/dev/null
|
||||||
echo "Injiziere casper-bottom Updates-Hook in die Initrd..."
|
chmod 444 "${WORK_DIR}/new.squashfs"
|
||||||
custom_initrd="${WORK_DIR}/casper/initrd-tuxflotte.lz"
|
|
||||||
inject_casper_bottom_hooks "${REPO_DIR}" \
|
|
||||||
"${WORK_DIR}/casper/initrd.lz" \
|
|
||||||
"${custom_initrd}"
|
|
||||||
|
|
||||||
echo "Erzeuge Kunden-ISO..."
|
echo "Erzeuge Kunden-ISO..."
|
||||||
rm -f "${OUTPUT_ISO}"
|
rm -f "${OUTPUT_ISO}"
|
||||||
@ -102,14 +102,8 @@ rm -f "${OUTPUT_ISO}"
|
|||||||
xorriso \
|
xorriso \
|
||||||
-indev "${SOURCE_ISO}" \
|
-indev "${SOURCE_ISO}" \
|
||||||
-outdev "${OUTPUT_ISO}" \
|
-outdev "${OUTPUT_ISO}" \
|
||||||
-compliance no_emul_toc \
|
|
||||||
-volid "${VOLID}" \
|
-volid "${VOLID}" \
|
||||||
-map "${REPO_DIR}/grub/mint-boot-grub.cfg" /boot/grub/grub.cfg \
|
-update "${WORK_DIR}/new.squashfs" /live/filesystem.squashfs \
|
||||||
-map "${REPO_DIR}/grub/mint-isolinux-live.cfg" /isolinux/live.cfg \
|
|
||||||
-map "${custom_initrd}" /casper/initrd.lz \
|
|
||||||
-map "${updates_dir}" /updates \
|
|
||||||
-chown_r 0 /updates -- \
|
|
||||||
-chgrp_r 0 /updates -- \
|
|
||||||
-boot_image any replay
|
-boot_image any replay
|
||||||
|
|
||||||
echo "Kunden-ISO erstellt: ${OUTPUT_ISO}"
|
echo "Kunden-ISO erstellt: ${OUTPUT_ISO}"
|
||||||
|
|||||||
@ -115,6 +115,25 @@ image_deploy_mount() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# package_golden_image.sh schliesst /proc, /sys, /dev, /run, /tmp, /var/tmp
|
||||||
|
# bewusst aus dem Archiv aus (Laufzeit-Zustand der Referenz-VM, nicht Teil
|
||||||
|
# eines portablen Images). Nach dem Entpacken fehlen diese Verzeichnisse
|
||||||
|
# deshalb komplett - live gefunden (31.08.2026, erster echter Lauf mit dem
|
||||||
|
# echten Referenz-VM-Archiv): erst "mount --bind /dev" ("mount point does
|
||||||
|
# not exist"), dann - nach Behebung dessen - "mktemp: failed to create
|
||||||
|
# directory via template '/var/tmp/mkinitramfs_XXXXXX'" bei
|
||||||
|
# update-initramfs. Statt jedes Fehlen einzeln zu jagen: alle sechs
|
||||||
|
# ausgeschlossenen Verzeichnisse direkt nach dem Entpacken einmalig mit
|
||||||
|
# sinnvollen Rechten wiederherstellen. /dev, /proc, /sys werden gleich
|
||||||
|
# danach ohnehin ueberbindmounted (image_deploy_bind_mounts) - schadet
|
||||||
|
# aber nicht, sie schon hier als leere Verzeichnisse anzulegen.
|
||||||
|
image_deploy_restore_excluded_dirs() {
|
||||||
|
local target="$1"
|
||||||
|
|
||||||
|
mkdir -p "${target}"/{proc,sys,dev,run,tmp,var/tmp}
|
||||||
|
chmod 1777 "${target}/tmp" "${target}/var/tmp"
|
||||||
|
}
|
||||||
|
|
||||||
# Entpackt das per build_golden_image.sh gebaute Golden Image direkt in
|
# Entpackt das per build_golden_image.sh gebaute Golden Image direkt in
|
||||||
# den gemounteten Zielbaum. -p erhaelt Rechte/Eigentuemer, --zstd deckt
|
# den gemounteten Zielbaum. -p erhaelt Rechte/Eigentuemer, --zstd deckt
|
||||||
# sowohl .tar.zst als auch (falls spaeter gewechselt) andere
|
# sowohl .tar.zst als auch (falls spaeter gewechselt) andere
|
||||||
@ -128,6 +147,40 @@ image_deploy_extract_image() {
|
|||||||
|
|
||||||
tar --zstd -xpf "${image_path}" -C "${target}" ||
|
tar --zstd -xpf "${image_path}" -C "${target}" ||
|
||||||
{ image_deploy_fatal "Golden Image konnte nicht nach ${target} entpackt werden"; return 1; }
|
{ image_deploy_fatal "Golden Image konnte nicht nach ${target} entpackt werden"; return 1; }
|
||||||
|
|
||||||
|
image_deploy_restore_excluded_dirs "${target}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Streamt das Golden Image direkt vom Server in die Extraktion, ohne es
|
||||||
|
# jemals als Ganzes zwischenzuspeichern - live gefunden (31.08.2026,
|
||||||
|
# erster echter End-to-End-Lauf mit dem vollen 2,3-GB-Referenz-VM-Archiv
|
||||||
|
# ueber das neue Boot-Medium): das bisherige "erst nach /run/tuxflotte/...
|
||||||
|
# herunterladen, dann entpacken" scheiterte an /run (RAM-Tmpfs, oft nur
|
||||||
|
# ein paar hundert MB gross, unabhaengig von der Geraete-RAM-Groesse) -
|
||||||
|
# "curl: (23) Failure writing output to destination". Direktes
|
||||||
|
# Zusammenrohren braucht dagegen nur ein paar MB Puffer, unabhaengig von
|
||||||
|
# der Archivgroesse. PIPESTATUS wird explizit geprueft statt sich auf
|
||||||
|
# "pipefail"-Semantik (rechteste fehlgeschlagene Stufe gewinnt) zu
|
||||||
|
# verlassen, damit die Fehlermeldung eindeutig zwischen Download- und
|
||||||
|
# Entpack-Fehler unterscheidet.
|
||||||
|
image_deploy_extract_image_from_url() {
|
||||||
|
local url="$1"
|
||||||
|
local target="$2"
|
||||||
|
local pipe_status
|
||||||
|
|
||||||
|
# "|| true" verhindert, dass "set -e" hier sofort abbricht - der
|
||||||
|
# eigentliche Fehlerfall wird gleich anhand von PIPESTATUS gezielt
|
||||||
|
# ausgewertet, statt die Pipeline roh durchschlagen zu lassen.
|
||||||
|
curl --silent --show-error --fail --location "${url}" |
|
||||||
|
tar --zstd -xpf - -C "${target}" || true
|
||||||
|
pipe_status=("${PIPESTATUS[@]}")
|
||||||
|
|
||||||
|
[[ "${pipe_status[0]}" -eq 0 ]] ||
|
||||||
|
{ image_deploy_fatal "Golden Image konnte nicht geladen werden: ${url}"; return 1; }
|
||||||
|
[[ "${pipe_status[1]}" -eq 0 ]] ||
|
||||||
|
{ image_deploy_fatal "Golden Image konnte nicht nach ${target} entpackt werden"; return 1; }
|
||||||
|
|
||||||
|
image_deploy_restore_excluded_dirs "${target}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# /etc/fstab aus den tatsaechlichen Partitions-UUIDs neu erzeugen - kein
|
# /etc/fstab aus den tatsaechlichen Partitions-UUIDs neu erzeugen - kein
|
||||||
@ -166,11 +219,48 @@ image_deploy_bind_mounts() {
|
|||||||
local target="$1"
|
local target="$1"
|
||||||
local -n stack_ref="$2"
|
local -n stack_ref="$2"
|
||||||
|
|
||||||
mount --bind /dev "${target}/dev" && stack_ref+=("${target}/dev")
|
# Golden Image schliesst /dev, /proc, /sys bewusst aus
|
||||||
mount -t proc proc "${target}/proc" && stack_ref+=("${target}/proc")
|
# (package_golden_image.sh --exclude=dev/sys/proc) - die Zielverzeichnisse
|
||||||
mount -t sysfs sysfs "${target}/sys" && stack_ref+=("${target}/sys")
|
# existieren nach dem Entpacken deshalb noch nicht und muessen vor dem
|
||||||
mount -t devpts devpts "${target}/dev/pts" && stack_ref+=("${target}/dev/pts")
|
# Bind-Mount erst angelegt werden. Live gefunden (31.08.2026, erster
|
||||||
cp /etc/resolv.conf "${target}/etc/resolv.conf"
|
# echter Lauf mit der echten Mint-Referenz-VM): ohne das schlaegt
|
||||||
|
# "mount --bind" mit "mount point does not exist" fehl - und zwar
|
||||||
|
# SILENT, weil das bisherige "cmd && stack_ref+=(...)"-Muster einen
|
||||||
|
# Fehlschlag von "cmd" unter "set -e" nicht als Statement-Fehler wertet
|
||||||
|
# (wohlbekannte Bash-Ausnahme fuer &&/||-Ketten) - der fehlende
|
||||||
|
# /dev-Bind-Mount fiel dann erst beim naechsten chroot-Aufruf auf
|
||||||
|
# ("ssh-keygen -A: Couldn't open /dev/null"), weit weg von der
|
||||||
|
# eigentlichen Ursache. Jetzt: Zielverzeichnisse anlegen, jeden
|
||||||
|
# Mount-Fehler explizit und einzeln pruefen statt auf &&-Verkettung
|
||||||
|
# zu vertrauen.
|
||||||
|
mkdir -p "${target}/dev" "${target}/proc" "${target}/sys" "${target}/dev/pts"
|
||||||
|
|
||||||
|
mount --bind /dev "${target}/dev" ||
|
||||||
|
{ image_deploy_fatal "/dev konnte nicht eingebunden werden"; return 1; }
|
||||||
|
stack_ref+=("${target}/dev")
|
||||||
|
|
||||||
|
mount -t proc proc "${target}/proc" ||
|
||||||
|
{ image_deploy_fatal "/proc konnte nicht eingebunden werden"; return 1; }
|
||||||
|
stack_ref+=("${target}/proc")
|
||||||
|
|
||||||
|
mount -t sysfs sysfs "${target}/sys" ||
|
||||||
|
{ image_deploy_fatal "/sys konnte nicht eingebunden werden"; return 1; }
|
||||||
|
stack_ref+=("${target}/sys")
|
||||||
|
|
||||||
|
mount -t devpts devpts "${target}/dev/pts" ||
|
||||||
|
{ image_deploy_fatal "/dev/pts konnte nicht eingebunden werden"; return 1; }
|
||||||
|
stack_ref+=("${target}/dev/pts")
|
||||||
|
|
||||||
|
# Live gefunden (31.08.2026, erster echter Lauf mit der echten
|
||||||
|
# Mint-Referenz-VM statt eines debootstrap-Test-Images): dort ist
|
||||||
|
# /etc/resolv.conf ein von NetworkManager verwalteter Symlink (z.B. auf
|
||||||
|
# /run/NetworkManager/resolv.conf) - im gerade erst entpackten,
|
||||||
|
# ungebooteten Zielbaum zeigt der ins Leere, "cp" verweigert dann das
|
||||||
|
# Schreiben "through a dangling symlink". Ziel deshalb vorher entfernen
|
||||||
|
# (Symlink oder Datei, beides abgedeckt), erst dann kopieren.
|
||||||
|
rm -f "${target}/etc/resolv.conf"
|
||||||
|
cp /etc/resolv.conf "${target}/etc/resolv.conf" ||
|
||||||
|
{ image_deploy_fatal "resolv.conf konnte nicht nach ${target} kopiert werden"; return 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
image_deploy_unbind_mounts() {
|
image_deploy_unbind_mounts() {
|
||||||
|
|||||||
@ -73,11 +73,26 @@ echo "==> Packe nach ${OUTPUT_FILE}"
|
|||||||
# nicht absolute (/proc/...) - ein --exclude mit fuehrendem Slash matcht
|
# nicht absolute (/proc/...) - ein --exclude mit fuehrendem Slash matcht
|
||||||
# dagegen NICHT (live am 31.08.2026 entdeckt: das lief zunaechst
|
# dagegen NICHT (live am 31.08.2026 entdeckt: das lief zunaechst
|
||||||
# unbemerkt gegen die echte Referenz-VM und haette u.a. /proc/kcore mit
|
# unbemerkt gegen die echte Referenz-VM und haette u.a. /proc/kcore mit
|
||||||
# eingepackt). Ausschluesse deshalb ohne fuehrenden Slash angeben.
|
# eingepackt).
|
||||||
|
#
|
||||||
|
# ZWEITER FUND (31.08.2026, spaeter am selben Tag): ein --exclude OHNE
|
||||||
|
# fuehrenden Slash UND ohne "./" matcht bei GNU tar gegen den Basisnamen
|
||||||
|
# JEDER Datei/jedes Verzeichnisses im ganzen Baum, nicht nur den
|
||||||
|
# Top-Level-Eintrag - "--exclude=dev" hat dadurch auch
|
||||||
|
# kernel/drivers/net/can/dev/ (ein voellig unverwandter, aber zufaellig
|
||||||
|
# gleichnamiger Kernelmodul-Ordner) mit ausgeschlossen und damit das
|
||||||
|
# gesamte CAN-Bus-Treibermodul aus dem Archiv gerissen - live erst beim
|
||||||
|
# tatsaechlichen Deployment aufgefallen (update-initramfs scheiterte an
|
||||||
|
# fehlenden can-dev.ko.zst-Abhaengigkeiten). Ein Praefix "./" verankert
|
||||||
|
# das Muster auf den exakten Top-Level-Pfad (ein "/" im Muster laesst tar
|
||||||
|
# gegen den vollen Namen matchen statt nur den Basisnamen) - lokal mit
|
||||||
|
# einem Wegwerf-Testbaum verifiziert: ./dev/./proc/./run schliessen nur
|
||||||
|
# die Top-Level-Eintraege aus, kernel/drivers/net/can/dev/ und
|
||||||
|
# nested/proc/... bleiben erhalten.
|
||||||
tar --numeric-owner --xattrs \
|
tar --numeric-owner --xattrs \
|
||||||
--exclude=proc --exclude=sys --exclude=dev \
|
--exclude=./proc --exclude=./sys --exclude=./dev \
|
||||||
--exclude=run --exclude=tmp --exclude=var/tmp \
|
--exclude=./run --exclude=./tmp --exclude=./var/tmp \
|
||||||
--exclude="${OUTPUT_FILE#/}" \
|
--exclude="./${OUTPUT_FILE#/}" \
|
||||||
-C / -cf - . | zstd -f -T0 -19 -o "${OUTPUT_FILE}"
|
-C / -cf - . | zstd -f -T0 -19 -o "${OUTPUT_FILE}"
|
||||||
|
|
||||||
echo "==> Fertig: ${OUTPUT_FILE} ($(du -h "${OUTPUT_FILE}" | cut -f1))"
|
echo "==> Fertig: ${OUTPUT_FILE} ($(du -h "${OUTPUT_FILE}" | cut -f1))"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user