Das Gerät läuft proot-distro 5.5.0. Dort gibt es '--installed' nicht mehr, und die Meldung lautet "container 'debian' already exists" statt 'already installed' — mein Mustervergleich hätte sie nicht erkannt und wäre in den Fehlerzweig gelaufen, obwohl alles in Ordnung ist. Beide Formulierungen werden jetzt abgedeckt. Gegen die tatsächliche Meldung vom Gerät geprüft. Die Hinweise zum Nachbessern nennen zusätzlich 'proot-distro reset', das in 5.5.0 der vorgesehene Weg zum Neuaufsetzen ist — mit dem ausdrücklichen Vermerk, dass dabei die Daten verloren gehen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
332 lines
16 KiB
Bash
Executable File
332 lines
16 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# Phase 0 — Grundinstallation in Termux.
|
||
#
|
||
# Richtet Termux-X11, den GPU-Pfad und ein Debian-13-Rootfs ein, damit die Beweise
|
||
# S1 bis S4 danach laufen können. Idempotent: mehrfaches Ausführen ist unschädlich.
|
||
#
|
||
# Ausführen IN TERMUX auf dem Telefon: bash spike/00-bootstrap-termux.sh
|
||
set -uo pipefail
|
||
source "$(dirname "$0")/lib.sh"
|
||
require_termux
|
||
|
||
DISTRO=debian
|
||
BIND_ROOT="$REPO_ROOT"
|
||
|
||
log "HPOS Phase 0 — Bootstrap"
|
||
log "Protokoll: $LOG"
|
||
geraete_steckbrief
|
||
|
||
# ── Repositories ─────────────────────────────────────────────────────────────
|
||
# x11-repo bringt Termux-X11 und virglrenderer, tur-repo die Mesa-/Turnip-Pakete.
|
||
section "Paketquellen"
|
||
try pkg update -y
|
||
try pkg install -y x11-repo tur-repo
|
||
try pkg update -y
|
||
|
||
# Vollupgrade vor allen Einzelinstallationen. Termux verträgt keine Teilupgrades:
|
||
# die Pakete werden gegeneinander gebaut, und ein einzeln nachinstalliertes trifft
|
||
# sonst auf veraltete Abhängigkeiten. Genau daran ist proot-distro gescheitert.
|
||
# init-phone.sh macht das schon; wer direkt hier einsteigt, bekommt es hier.
|
||
section "Termux auf einen Stand bringen"
|
||
if [ "${HPOS_OHNE_UPGRADE:-0}" = 1 ]; then
|
||
warn "Übersprungen (HPOS_OHNE_UPGRADE=1)"
|
||
else
|
||
export DEBIAN_FRONTEND=noninteractive
|
||
# --force-confold: vorhandene Konfiguration behalten, statt mitten im Lauf
|
||
# eine Rückfrage zu stellen, die niemand beantwortet.
|
||
if try pkg upgrade -y -o Dpkg::Options::=--force-confold; then
|
||
ok "Termux ist aktuell"
|
||
else
|
||
warn "Upgrade brach ab — versuche zu reparieren."
|
||
# Dateikonflikt gezielt behandeln: entsteht, wenn ein Paket aufgeteilt
|
||
# wurde und beide Teile kurzzeitig dieselbe Datei mitbringen — bei Termux
|
||
# etwa libmagic, herausgelöst aus file. --force-overwrite wird bewusst nur
|
||
# dann gesetzt, wenn der Konflikt im Protokoll nachgewiesen ist; pauschal
|
||
# hieße es, jede künftige Dateikollision stillschweigend zu übergehen.
|
||
if grep -q 'which is also in package' "$LOG" 2>/dev/null; then
|
||
warn "Dateikonflikt zwischen zwei Paketen erkannt:"
|
||
grep 'trying to overwrite' "$LOG" | tail -3 | sed 's/^/ /' | tee -a "$LOG"
|
||
hint "Typisch bei einer Paketaufteilung. Wiederhole mit --force-overwrite."
|
||
try pkg upgrade -y -o Dpkg::Options::=--force-confold \
|
||
-o Dpkg::Options::=--force-overwrite
|
||
fi
|
||
# Meist scheitert ein einzelnes Paket beim Auspacken, danach steckt dpkg
|
||
# halb fertig fest und blockiert jede weitere Installation.
|
||
try dpkg --configure -a
|
||
try apt-get -f install -y
|
||
if try pkg upgrade -y -o Dpkg::Options::=--force-confold \
|
||
-o Dpkg::Options::=--force-overwrite; then
|
||
ok "Nach der Reparatur durchgelaufen"
|
||
else
|
||
warn "Bleibt unvollständig."
|
||
hint "Speicherplatz: df -h \$PREFIX"
|
||
hint "Freier Platz unter etwa 1 GB ist die häufigste Ursache."
|
||
hint "Fehler ohne Rauschen: pkg upgrade -y 2>&1 | grep -viE 'unable to delete' | tail -20"
|
||
hint "Die vielen 'unable to delete old directory' sind Warnungen, keine Fehler."
|
||
fi
|
||
fi
|
||
# Platz prüfen, solange es noch nicht weh tut: das Debian-Rootfs samt Plasma
|
||
# Mobile braucht mehrere GB, und ein Abbruch mitten im Entpacken ist ärgerlicher
|
||
# als eine Warnung vorher.
|
||
FREI_KB=$(df -Pk "$PREFIX" 2>/dev/null | awk 'NR==2 {print $4}')
|
||
if [ -n "$FREI_KB" ]; then
|
||
log " Freier Speicher: $((FREI_KB / 1024)) MB"
|
||
[ "$FREI_KB" -lt 2000000 ] && warn "Unter 2 GB frei — für Debian plus Plasma Mobile knapp."
|
||
fi
|
||
fi
|
||
|
||
# ── Basispakete ──────────────────────────────────────────────────────────────
|
||
# Einzeln installiert und einzeln protokolliert: Paketnamen wandern in Termux
|
||
# gelegentlich, und wir wollen wissen, WELCHES Paket fehlt, statt nur dass etwas fehlt.
|
||
section "Basispakete"
|
||
BASIS=(termux-x11-nightly pulseaudio proot-distro termux-api git python openssl termux-tools)
|
||
for p in "${BASIS[@]}"; do
|
||
if try pkg install -y "$p"; then ok "$p"; else fail "$p — fehlt, betroffene Beweise siehe unten"; fi
|
||
done
|
||
|
||
# ── GPU-Pfad ─────────────────────────────────────────────────────────────────
|
||
# Adreno 6xx/7xx → Turnip greift direkt auf KGSL zu, das ist der schnellste Weg.
|
||
# Mali und alles andere → virgl/ANGLE. Wir installieren beides und entscheiden
|
||
# zur Laufzeit; das Ergebnis landet im GPU-Profil.
|
||
section "GPU-Pakete"
|
||
GPU_PKGS=(virglrenderer-android vulkan-loader-android vulkan-tools angle-android
|
||
mesa-zink virglrenderer-mesa-zink)
|
||
for p in "${GPU_PKGS[@]}"; do
|
||
if try pkg install -y "$p"; then ok "$p"; else warn "$p nicht verfügbar — kein Beinbruch"; fi
|
||
done
|
||
|
||
# Der Vulkan-Treiber ist der einzige GPU-Teil, der wirklich zählt: ohne ihn bleibt
|
||
# nur Software-Rendering. Die Paketnamen haben sich in Termux mehrfach geändert,
|
||
# deshalb werden mehrere Kandidaten probiert, bis einer greift.
|
||
section "Vulkan-Treiber (Turnip)"
|
||
ICD_KANDIDATEN=(mesa-vulkan-icd-freedreno mesa-vulkan-icd-wrapper
|
||
mesa-vulkan-icd-wrapper-android mesa-vulkan-icd-swrast)
|
||
ICD_GEFUNDEN=""
|
||
for p in "${ICD_KANDIDATEN[@]}"; do
|
||
if pkg install -y "$p" >>"$LOG" 2>&1; then
|
||
ICD_GEFUNDEN="$p"
|
||
ok "$p installiert"
|
||
break
|
||
fi
|
||
hint "$p — nicht verfügbar"
|
||
done
|
||
if [ -z "$ICD_GEFUNDEN" ]; then
|
||
warn "Kein Vulkan-Treiber installierbar."
|
||
hint "Ohne ihn läuft der Desktop im Software-Rendering — S1 wird träge,"
|
||
hint "sagt aber trotzdem etwas über die Machbarkeit aus."
|
||
hint "Verfügbare Kandidaten prüfen: pkg search mesa-vulkan"
|
||
fi
|
||
|
||
section "GPU erkennen"
|
||
PLATFORM="$(getprop ro.board.platform 2>/dev/null)"
|
||
HARDWARE="$(getprop ro.hardware 2>/dev/null)"
|
||
GPU_PROFIL="virgl" # konservative Vorgabe
|
||
if have vulkaninfo; then
|
||
vulkaninfo --summary >>"$LOG" 2>&1 || true
|
||
GPU_NAME="$(vulkaninfo --summary 2>/dev/null | grep -m1 -i 'deviceName' | cut -d= -f2- | xargs)"
|
||
else
|
||
GPU_NAME=""
|
||
fi
|
||
log " Plattform = ${PLATFORM:-?}"
|
||
log " Hardware = ${HARDWARE:-?}"
|
||
log " GPU = ${GPU_NAME:-unbekannt}"
|
||
|
||
case "${GPU_NAME}${PLATFORM}" in
|
||
*[Aa]dreno*|*qcom*|*sm[0-9]*|*msm*)
|
||
GPU_PROFIL="turnip"
|
||
ok "Adreno erkannt → Turnip-Profil (direkter KGSL-Zugriff, schnellster Weg)"
|
||
;;
|
||
*[Mm]ali*)
|
||
GPU_PROFIL="virgl"
|
||
warn "Mali erkannt → virgl/ANGLE-Profil. Spürbar langsamer als Turnip."
|
||
;;
|
||
*)
|
||
warn "GPU nicht eindeutig erkannt → virgl als Vorgabe."
|
||
hint "Bitte im Spike-Protokoll vermerken, welcher Pfad tatsächlich getragen hat."
|
||
;;
|
||
esac
|
||
|
||
# Das Profil ist eine Datei, kein Sonderfall im Code — so bleibt es später
|
||
# erweiterbar, ohne dass jemand Skripte anfassen muss.
|
||
mkdir -p "$REPO_ROOT/rootfs/profiles"
|
||
PROFIL_DATEI="$OUT_DIR/gpu-profil.env"
|
||
{
|
||
echo "# Automatisch erkannt von 00-bootstrap-termux.sh"
|
||
echo "HPOS_GPU_PROFIL=$GPU_PROFIL"
|
||
echo "HPOS_GPU_NAME=\"${GPU_NAME:-unbekannt}\""
|
||
echo "HPOS_PLATFORM=\"${PLATFORM:-unbekannt}\""
|
||
} >"$PROFIL_DATEI"
|
||
ok "GPU-Profil geschrieben: $PROFIL_DATEI ($GPU_PROFIL)"
|
||
|
||
# ── Termux-Eigenschaften ─────────────────────────────────────────────────────
|
||
# allow-external-apps ist die Voraussetzung dafür, dass die Bridge-APK später
|
||
# Kommandos in Termux anstoßen darf. Hier gesetzt, damit Phase 2 es vorfindet.
|
||
section "Termux-Eigenschaften"
|
||
TP="$HOME/.termux/termux.properties"
|
||
mkdir -p "$(dirname "$TP")"
|
||
touch "$TP"
|
||
if grep -q '^allow-external-apps' "$TP" 2>/dev/null; then
|
||
ok "allow-external-apps bereits gesetzt"
|
||
else
|
||
echo 'allow-external-apps = true' >>"$TP"
|
||
ok "allow-external-apps = true gesetzt"
|
||
hint "Wird erst nach 'termux-reload-settings' oder Neustart von Termux wirksam."
|
||
fi
|
||
try termux-reload-settings
|
||
|
||
section "Speicherzugriff"
|
||
if [ -d "$HOME/storage" ]; then
|
||
ok "Speicherzugriff bereits eingerichtet"
|
||
else
|
||
warn "termux-setup-storage wird gleich einen Berechtigungsdialog zeigen — bitte erlauben."
|
||
try termux-setup-storage
|
||
sleep 2
|
||
[ -d "$HOME/storage" ] && ok "Speicherzugriff eingerichtet" || fail "Speicherzugriff fehlt — Backup nach /sdcard geht später nicht"
|
||
fi
|
||
|
||
# ── Wachhalten ───────────────────────────────────────────────────────────────
|
||
# Ohne Wake-Lock schläft der Stack weg, sobald der Bildschirm aus geht.
|
||
# Die herstellerseitigen Maßnahmen kommen zusätzlich, siehe provision/.
|
||
section "Wake-Lock"
|
||
try termux-wake-lock && ok "Wake-Lock aktiv" || warn "Wake-Lock nicht gesetzt"
|
||
|
||
# ── Debian-Rootfs ────────────────────────────────────────────────────────────
|
||
section "Debian-Rootfs"
|
||
# Erst prüfen, ob proot-distro überhaupt LÄUFT. Ein installiertes Paket, dessen
|
||
# Shebang-Interpreter fehlt, meldet sich mit "cannot execute: required file not
|
||
# found" — eine Meldung, die aussieht als fehle das Programm, obwohl es da ist.
|
||
if ! proot-distro list >/dev/null 2>&1; then
|
||
fail "proot-distro ist installiert, lässt sich aber nicht ausführen"
|
||
PD="$(command -v proot-distro)"
|
||
SHEBANG="$(head -1 "$PD" 2>/dev/null)"
|
||
INTERPRETER="$(printf '%s' "$SHEBANG" | sed 's|^#!||; s| .*||')"
|
||
log " Datei: $PD"
|
||
log " Shebang: $SHEBANG"
|
||
log " Interpreter: ${INTERPRETER:-(keiner)}"
|
||
|
||
if [ -n "$INTERPRETER" ] && [ ! -x "$INTERPRETER" ]; then
|
||
fail "Der Interpreter fehlt — nicht proot-distro selbst."
|
||
log ""
|
||
log " Das ist der klassische Termux-Teilupgrade-Fehler: das Paket wurde gegen"
|
||
log " eine Fassung gebaut, installiert ist eine andere. Termux verträgt keine"
|
||
log " Teilupgrades — hier hilft nur, alles auf denselben Stand zu bringen."
|
||
|
||
# Schritt 1: fehlendes Paket nachziehen. Bei python3.x heißt es schlicht python.
|
||
case "$(basename "$INTERPRETER")" in
|
||
python3*|python) try pkg install -y python ;;
|
||
bash) try pkg install -y bash ;;
|
||
*) try pkg install -y "$(basename "$INTERPRETER")" ;;
|
||
esac
|
||
|
||
# Schritt 2: Vollupgrade. Das ist die eigentliche Reparatur.
|
||
if [ ! -x "$INTERPRETER" ]; then
|
||
log ""
|
||
warn "Reicht nicht — jetzt das Vollupgrade. Das dauert und lädt einiges."
|
||
try pkg update -y
|
||
try pkg upgrade -y
|
||
try pkg install -y proot proot-distro
|
||
fi
|
||
|
||
# Schritt 3: Notnagel. Nur für Python, und nur weil proot-distro reines
|
||
# Python ohne kompilierte Erweiterungen ist — sonst wäre eine Version
|
||
# überzustülpen grob fahrlässig.
|
||
if [ ! -x "$INTERPRETER" ]; then
|
||
case "$(basename "$INTERPRETER")" in
|
||
python3.*)
|
||
VORHANDEN="$(ls "$PREFIX/bin"/python3.* 2>/dev/null | grep -v config | head -1)"
|
||
if [ -n "$VORHANDEN" ]; then
|
||
log ""
|
||
warn "Notnagel: verweise $(basename "$INTERPRETER") auf $(basename "$VORHANDEN")"
|
||
hint "Vertretbar, weil proot-distro reines Python ist."
|
||
hint "Sauber wird es erst mit einem vollständigen 'pkg upgrade'."
|
||
ln -sf "$VORHANDEN" "$INTERPRETER" && ok "Verweis angelegt"
|
||
fi
|
||
;;
|
||
esac
|
||
fi
|
||
else
|
||
try pkg install -y bash coreutils proot proot-distro
|
||
fi
|
||
|
||
if ! proot-distro list >/dev/null 2>&1; then
|
||
fail "Bleibt defekt — ohne proot-distro geht es nicht weiter."
|
||
log ""
|
||
log " Von Hand versuchen, in dieser Reihenfolge:"
|
||
log " pkg update && pkg upgrade -y # Vollupgrade, keine Teilschritte"
|
||
log " pkg install -y python proot proot-distro"
|
||
log " termux-change-repo # falls der Spiegel unstimmig ist"
|
||
exit 1
|
||
fi
|
||
ok "proot-distro läuft wieder"
|
||
fi
|
||
|
||
# Ob ein Rootfs da ist, wird nicht mehr an Pfaden oder Ausgabeformaten festgemacht:
|
||
# proot-distro hat sein Ablageformat gewechselt (erkennbar an der Meldung
|
||
# "Migrating legacy container"), und danach lag das Rootfs woanders als erwartet.
|
||
# Ein Anmeldeversuch ist die einzige Prüfung, die das nicht betrifft — sie fragt
|
||
# nicht, wo etwas liegt, sondern ob es funktioniert.
|
||
rootfs_laeuft() { proot-distro login "$DISTRO" -- true >/dev/null 2>&1; }
|
||
|
||
if rootfs_laeuft; then
|
||
ok "$DISTRO bereits installiert und lauffähig"
|
||
else
|
||
log " Installiere $DISTRO — das dauert einige Minuten."
|
||
if proot-distro install "$DISTRO" >>"$LOG" 2>&1; then
|
||
ok "$DISTRO installiert"
|
||
else
|
||
# 'already exists' bzw. 'already installed' ist kein Fehler, sondern ein
|
||
# Wettlauf zwischen meiner Prüfung und der Wirklichkeit. Die Wortwahl hat
|
||
# sich über die Fassungen geändert (5.5.0 spricht von Containern), deshalb
|
||
# werden beide Formulierungen abgedeckt. Entscheidend ist ohnehin allein,
|
||
# ob sich danach anmelden lässt.
|
||
if grep -qiE 'already (installed|exists)' "$LOG"; then
|
||
warn "proot-distro meldet: gibt es bereits"
|
||
else
|
||
warn "Installation meldete einen Fehler:"
|
||
tail -n 12 "$LOG" | sed 's/^/ /'
|
||
fi
|
||
if rootfs_laeuft; then
|
||
ok "Anmeldung funktioniert trotzdem — weiter."
|
||
else
|
||
fail "Kein lauffähiges $DISTRO-Rootfs."
|
||
log ""
|
||
log " Von Hand versuchen:"
|
||
log " proot-distro list # was ist da?"
|
||
log " proot-distro reset $DISTRO # neu aufsetzen, Daten weg"
|
||
log " proot-distro remove $DISTRO && proot-distro install $DISTRO"
|
||
exit 1
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
section "Debian-Grundausstattung"
|
||
# Der Bind macht das Repo im Rootfs unter /hpos sichtbar, damit die inneren
|
||
# Skripte dieselben Dateien benutzen und Ergebnisse am selben Ort landen.
|
||
proot-distro login "$DISTRO" --bind "$BIND_ROOT:/hpos" -- bash -lc '
|
||
set -uo pipefail
|
||
export DEBIAN_FRONTEND=noninteractive
|
||
apt-get update -qq
|
||
apt-get install -y --no-install-recommends \
|
||
ca-certificates locales dbus-x11 sudo nano less procps \
|
||
mesa-utils vulkan-tools pulseaudio-utils
|
||
# Deutsche und englische Locale, sonst meckert die halbe Desktop-Software.
|
||
sed -i "s/^# *\(de_DE.UTF-8\|en_US.UTF-8\)/\1/" /etc/locale.gen
|
||
locale-gen >/dev/null 2>&1
|
||
echo "--- Debian-Version ---"; cat /etc/debian_version
|
||
' 2>&1 | tee -a "$LOG"
|
||
|
||
# ── Abschluss ────────────────────────────────────────────────────────────────
|
||
section "Bereit"
|
||
log "GPU-Profil : $GPU_PROFIL"
|
||
log "Rootfs : $DISTRO"
|
||
log "Repo im Rootfs sichtbar unter /hpos"
|
||
log ""
|
||
log "Nächste Schritte, in dieser Reihenfolge:"
|
||
log " bash spike/01-s1-plasma-mobile.sh # der wackligste Beweis, deshalb zuerst"
|
||
log " bash spike/02-s2-mikrofon.sh"
|
||
log " bash spike/03-s3-pipewire-kamera.sh"
|
||
log " bash spike/04-s4-intent-handoff.sh"
|
||
log ""
|
||
log "Vor dem Übernacht-Test bitte provision/provision.sh vom PC laufen lassen"
|
||
log "und die herstellerseitigen Handgriffe aus docs/machbarkeit.md erledigen."
|