golden-image: Trimming-Mounts fixen (Incident 11.09.2026), Trimming-Feature committen

Zwei Bugs behoben, die den Mount-Incident vom 11.09.2026 verursacht haben
(rm -rf gegen einen noch teilweise gemounteten Pfad hat echte
Geraetedateien auf dem Build-Host geloescht, u.a. /dev/null):

1. mount --rbind /dev -> normaler --bind + eigene, frische devpts-Instanz
   nur fuer dev/pts. --rbind hat die STAGING_DIR-Devpts-Instanz 1:1 mit der
   des eigenen Terminals geteilt - beim Aufraeumen war der Sub-Mount
   dadurch 'busy', was zu einem manuellen Lazy-Unmount (umount -l)
   verleitet hat.

2. unmount_chroot_binds() nutzt jetzt nirgends mehr umount -l/-R (Lazy-
   /rekursiver Unmount) - stattdessen normaler umount mit begrenztem Retry
   je Mount. cleanup() prueft zusaetzlich UNABHAENGIG per mountpoint -q
   nach, bevor rm -rf auf STAGING_DIR laeuft, und verweigert das Loeschen,
   falls doch noch etwas eingehaengt ist, statt stillschweigend
   weiterzumachen.

Gleichzeitig wird damit das inhaltlich bereits fertige, bisher nur
uncommitted auf controller liegende Trimming-Feature (echter Testlauf
11.09.2026, 37 Pakete/910MB) mit committed - siehe Kommentar im Skript fuer
die vollstaendige Paketauswahl-Analyse.

Noch offen: naechster echter Testlauf des reparierten Mount-/Unmount-
Zyklus gegen golden-linux-mint/103 (bisher nur syntaktisch/statisch
geprueft, nicht real gegen chroot+apt getestet).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011HDFX6o1ZMxKVFLYiMjERR
This commit is contained in:
adminandClaude Sonnet 5 committed 2026-09-12 13:38:23 +02:00
1 parent 7c52e5fb90
commit 8196166c90
1 file changed
+147 -8
+147 -8
View File
@@ -68,6 +68,21 @@ mkdir -p "${STAGING_BASE_DIR}"
STAGING_DIR="$(mktemp -d -p "${STAGING_BASE_DIR}")"
cleanup() {
# Schutzmassnahme nach dem Mount-Incident vom 11.09.2026 (siehe
# unmount_chroot_binds() weiter unten): "rm -rf" darf NIEMALS gegen
# einen Pfad laufen, unter dem noch ein Bind-/devpts-Mount haengt - genau
# das ist damals passiert (ein manueller Lazy-Unmount war noch nicht
# fertig, als "rm -rf" schon lief) und hat dabei echte Geraetedateien
# (u.a. /dev/null) auf dem Build-Host geloescht. Deshalb hier
# UNABHAENGIG von unmount_chroot_binds() ein zweites, autoritatives
# Nachpruefen: nur loeschen, wenn WIRKLICH nichts mehr eingehaengt ist.
local mnt
for mnt in "${STAGING_DIR}/dev/pts" "${STAGING_DIR}/dev" "${STAGING_DIR}/sys" "${STAGING_DIR}/proc"; do
if mountpoint -q "${mnt}" 2>/dev/null; then
echo "FEHLER: ${mnt} ist noch eingehaengt - rm -rf auf ${STAGING_DIR} wird NICHT ausgefuehrt. Manuell aushaengen (umount ${mnt}) und ${STAGING_DIR} danach von Hand loeschen." >&2
return 1
fi
done
chmod -R u+w "${STAGING_DIR}" 2>/dev/null || true
rm -rf "${STAGING_DIR}"
}
@@ -141,14 +156,138 @@ rm -rf "${STAGING_DIR}"/tmp/* "${STAGING_DIR}"/var/tmp/*
rm -f "${STAGING_DIR}/root/.bash_history"
rm -f "${STAGING_DIR}"/home/*/.bash_history 2>/dev/null || true
# Paketauswahl eindampfen (Browser, Office-Pakete o.Ä.) bewusst NICHT im
# ersten Lauf - siehe Plan ("erster Durchlauf zeigt, wie groß das Archiv
# real wird, dann gezielt nachschärfen"). Blindes Purgen ohne die
# tatsächliche Paketliste gesehen zu haben, riskiert eher kaputte
# Abhängigkeiten als sinnvolle Einsparung. Nach diesem Lauf:
# `chroot "${STAGING_DIR}" dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -rn | head -30`
# auf der Staging-Kopie zeigt die groessten Kandidaten fuer einen gezielten
# zweiten Durchlauf.
# Paketauswahl eindampfen (11.09.2026, zweiter Durchlauf nach dem oben
# beschriebenen ersten Lauf - echte Groessenanalyse auf golden-linux-mint/103
# per `dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -rn`, jeder
# Kandidat einzeln per `apt-cache rdepends --installed` gegen versteckte
# Abhaengigkeiten geprueft, nicht blind uebernommen):
# - ansible: eigenes Provisionierungswerkzeug, Testueberbleibsel auf der
# Referenz-VM - gehoert nie auf ein Kundengeraet.
# - gcc-13/g++-13/cpp-13 + linux-headers-*/linux-hwe-*-headers-*: kein
# lokales Entwickeln vorgesehen ([[project_no_local_install_capability]],
# ADR-0026), `dkms status` auf der Referenz-VM leer - kein Kernel-Modul
# braucht sie zum Neubauen.
# - mint-l-icons/yaru-theme-icon/mint-l-theme: ungenutzte Alternativ-Themes
# - NICHT in der Inherits-Kette des aktiven Icon-Themes (Mint-Y-Sand ->
# Mint-Y,Adwaita,gnome,hicolor) und nicht das aktive GTK-Theme
# (Mint-Y-Aqua, liefert mint-themes - bleibt). mint-x-icons war
# URSPRUENGLICH auch auf der Liste, aber nach echtem Testlauf (11.09.2026)
# WIEDER RAUSGENOMMEN: einziger Trigger einer eigenen Kaskade
# (mint-meta-cinnamon/mint-meta-core/mint-artwork/mint-themes selbst!) -
# vermutlich ueber folder-color-switcher, das Mint-X-Ordnerfarbvarianten
# braucht. Bisektion (jedes Paket einzeln simuliert) hat das eindeutig
# auf mint-x-icons zurueckgefuehrt, die anderen drei sind einzeln UND
# zusammen sauber.
# - mintinstall + app-install-data: URSPRUENGLICH auf der Liste (ADR-0026 -
# kein sudo/pkexec fuer den interaktiven Nutzer, damit funktionslos), aber
# nach echtem Testlauf (11.09.2026) WIEDER RAUSGENOMMEN: mintinstall
# haengt an mint-meta-core/mint-meta-cinnamon, deren Entfernung eine
# Kaskade aus (apt autoremove reisst alles mit, was NUR ueber dieses
# Meta-Paket als "automatisch installiert" markiert war) - hat im
# Testlauf mint-themes (!), mint-artwork, xorg und lightdm-settings mit
# zur Entfernung markiert. Das Risiko (kaputter Desktop) steht in keinem
# Verhaeltnis zur Ersparnis (~45MB) - bewusst NICHT entfernt.
# - libreoffice* + mythes-*: der Katalog installiert LibreOffice separat per
# Flatpak (roles/libreoffice in ansible-content) - die apt-Variante hier
# ist reine Redundanz.
# - kolibri: der Katalog installiert es identisch per apt (roles/kolibri) -
# ebenfalls redundant.
#
# NICHT entfernt (geprueft, echte Abhaengigkeiten): mint-cursor-themes (liefert
# das aktive Cursor-Theme Bibata-Modern-Classic), mint-y-icons/mint-themes
# (aktive Themes), mint-x-icons (siehe oben), libwebkit2gtk*/libwebkitgtk*
# (braucht yelp/Xreader), mesa-vulkan-drivers (Xorg-Basis).
#
# Nebeneffekt der gcc-Entfernung, bewusst akzeptiert (11.09.2026 geprueft):
# das "xorg"-META-Paket (SDK/Bundle, NICHT der laufende X-Server selbst -
# xserver-xorg-core haengt unabhaengig an den echten Treiber-Paketen) geht
# ueber dpkg-dev->build-essential->gcc mit, dabei auch x11-xserver-utils
# (xrandr/xset & Co.) und lightdm-settings (GUI-Konfig fuer den Login-
# Manager) - im eigenen Code (ansible-content/provisioning-server) nirgends
# referenziert, unproblematisch.
#
# Bewusst als PATTERN-LISTE + dpkg-query-Auflösung statt direkt an
# `apt-get purge` durchgereicht - macht explizit sichtbar/loggbar, welche
# tatsaechlichen Paketnamen getroffen werden, statt sich auf apt-eigenes
# Wildcard-Matching zu verlassen. Patterns, die auf dieser Distro nichts
# treffen (z.B. "mintinstall" auf Debian/Ubuntu), werden einfach
# uebersprungen - kein Fehler.
#
# `apt-get purge`/`autoremove` brauchen ein funktionierendes /proc im
# chroot (u.a. fuer update-initramfs/Trigger-Skripte) - deshalb kurz
# bind-mounten, aber VOR jedem Skript-Ende (auch bei Fehlern) wieder
# aushaengen, sonst wuerde der cleanup()-Trap (`rm -rf STAGING_DIR`) gegen
# das ECHTE /proc/etc. des Build-Hosts durchschlagen.
TRIM_PATTERNS=(
ansible
gcc-13-x86-64-linux-gnu g++-13-x86-64-linux-gnu cpp-13-x86-64-linux-gnu
'linux-headers-*' 'linux-hwe-*-headers-*'
mint-l-icons yaru-theme-icon mint-l-theme
'libreoffice*' mythes-de mythes-en-us
kolibri
)
mkdir -p "${STAGING_DIR}/proc" "${STAGING_DIR}/sys" "${STAGING_DIR}/dev" "${STAGING_DIR}/dev/pts"
mount --bind /proc "${STAGING_DIR}/proc"
mount --bind /sys "${STAGING_DIR}/sys"
# NICHT --rbind fuer /dev (Bugfix 12.09.2026, nach dem Incident vom
# 11.09.2026 - siehe unmount_chroot_binds() unten): --rbind ist rekursiv und
# haette /dev/pts der STAGING_DIR 1:1 an dieselbe devpts-INSTANZ gebunden,
# die auch das eigene Terminal dieses Skripts nutzt. Damit ist der
# Sub-Mount beim Aufraeumen "busy" (normaler umount schlaegt fehl), was
# beim Incident zu einem manuellen Lazy-Unmount (umount -l) verleitet hat -
# der dann noch lief, als bereits "rm -rf" auf die STAGING_DIR losging, und
# dabei ECHTE Geraetedateien (u.a. /dev/null) auf dem Build-Host geloescht
# hat. Stattdessen: normaler (nicht-rekursiver) --bind fuer /dev selbst
# (bringt alle Geraetedateien mit, u.a. /dev/null/zero/ptmx), plus eine
# FRISCHE, eigenstaendige devpts-Instanz NUR fuer dev/pts - dpkg/apt
# brauchen die zum Oeffnen eines Pseudo-Terminals ("posix_openpt"), aber sie
# teilt sich dann nichts mehr mit dem Host-Terminal und laesst sich darum
# immer sauber mit einem normalen (nicht-lazy) umount aushaengen.
mount --bind /dev "${STAGING_DIR}/dev"
mount -t devpts devpts "${STAGING_DIR}/dev/pts"
unmount_chroot_binds() {
# Zweiter Teil des Bugfixes vom 12.09.2026: kein Lazy-Unmount (umount
# -l/-R) mehr an irgendeiner Stelle - das war der eigentliche Ausloeser
# des Incidents (rm -rf lief los, bevor der Lazy-Unmount fertig war).
# Stattdessen ein normaler umount mit begrenztem Retry, und danach eine
# ECHTE Verifikation per mountpoint -q statt stillschweigend
# weiterzumachen. dev/pts zuerst (Blattmount), erst danach dev selbst -
# sonst waere dev noch "busy" durch die eigene devpts-Einhaengung
# darunter. sys/proc sind voneinander unabhaengig.
local mnt tries
for mnt in "${STAGING_DIR}/dev/pts" "${STAGING_DIR}/dev" "${STAGING_DIR}/sys" "${STAGING_DIR}/proc"; do
tries=0
while mountpoint -q "${mnt}" 2>/dev/null && [[ "${tries}" -lt 10 ]]; do
umount "${mnt}" 2>/dev/null || true
tries=$((tries + 1))
mountpoint -q "${mnt}" 2>/dev/null && sleep 0.5
done
if mountpoint -q "${mnt}" 2>/dev/null; then
echo "WARNUNG: ${mnt} laesst sich nach ${tries} Versuchen nicht aushaengen - bleibt eingehaengt (bewusst KEIN Lazy-Unmount hier, siehe Incident 11.09.2026). cleanup() weigert sich weiter unten, die STAGING_DIR zu loeschen, solange das so bleibt - manuelle Nachschau noetig." >&2
fi
done
}
trap 'unmount_chroot_binds; cleanup' EXIT
mapfile -t TRIM_PACKAGES < <(
for pattern in "${TRIM_PATTERNS[@]}"; do
chroot "${STAGING_DIR}" dpkg-query -Wf '${Package}\n' "${pattern}" 2>/dev/null || true
done | sort -u
)
if [[ "${#TRIM_PACKAGES[@]}" -gt 0 ]]; then
echo "==> Entferne redundante/unnötige Basis-Pakete: ${TRIM_PACKAGES[*]}"
chroot "${STAGING_DIR}" env DEBIAN_FRONTEND=noninteractive \
apt-get purge -y "${TRIM_PACKAGES[@]}"
chroot "${STAGING_DIR}" env DEBIAN_FRONTEND=noninteractive apt-get autoremove -y
chroot "${STAGING_DIR}" apt-get clean
else
echo "==> Keines der Trimming-Pakete auf dieser Referenz-VM gefunden, nichts zu tun."
fi
unmount_chroot_binds
trap cleanup EXIT
echo "==> Packe nach ${OUTPUT_FILE}"
# WICHTIG: tar -C STAGING_DIR erzeugt relative Elementnamen (./proc/...,