Aus dem Gerätelauf: S2 lief bis Stufe 1 durch und scheiterte dann an 'proot-distro: cannot execute: required file not found'. Danach meldete die Auswertung folgerichtig 'S2 gescheitert' — was den Beweis inhaltlich belastet, obwohl nur die Grundlage fehlte. Genau diese Verwechslung soll der Spike nicht produzieren. Alle Beweise prüfen jetzt vorab, ob proot-distro ausführbar ist und das Rootfs steht, und brechen sonst mit klarer Ansage ab statt mitten im Test aufzulaufen. Die Meldung selbst ist irreführend: 'required file not found' heißt nicht, dass proot-distro fehlt — bash hat es gefunden und nennt den vollen Pfad. Es fehlt der Interpreter aus dessen Shebang-Zeile. Die Prüfung sagt das ausdrücklich und nennt Datei und Shebang, statt den Suchenden an der falschen Stelle graben zu lassen. 00-bootstrap versucht in dem Fall selbsttätig eine Neuinstallation. Dazu die Berechtigungsprüfung entschärft: dumpsys verlangt die DUMP-Berechtigung, die eine gewöhnliche App nicht hat. Das Fehlschlagen ist erwartbar und kein Warnsignal; die Meldung nennt jetzt den Weg über adb statt Ratlosigkeit zu säen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
153 lines
5.2 KiB
Bash
Executable File
153 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# Gemeinsame Hilfsfunktionen für die Phase-0-Spike-Skripte.
|
||
# Wird von den 0x-Skripten eingebunden, nicht direkt ausgeführt.
|
||
|
||
# Farben nur wenn wir auf einem Terminal landen — sonst verschmutzen sie das Protokoll.
|
||
if [ -t 1 ]; then
|
||
C_OK=$'\033[32m'; C_WARN=$'\033[33m'; C_ERR=$'\033[31m'
|
||
C_HEAD=$'\033[1;36m'; C_DIM=$'\033[2m'; C_OFF=$'\033[0m'
|
||
else
|
||
C_OK=""; C_WARN=""; C_ERR=""; C_HEAD=""; C_DIM=""; C_OFF=""
|
||
fi
|
||
|
||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||
OUT_DIR="$REPO_ROOT/spike/out"
|
||
mkdir -p "$OUT_DIR"
|
||
|
||
# Jeder Lauf bekommt sein eigenes Protokoll. Die Sammlung ist später die halbe
|
||
# Auswertung — deshalb wird alles mitgeschrieben, auch was funktioniert hat.
|
||
LOG="${LOG:-$OUT_DIR/$(basename "${0%.sh}").log}"
|
||
|
||
log() { printf '%s\n' "$*" | tee -a "$LOG"; }
|
||
section() { log ""; log "${C_HEAD}══ $* ══${C_OFF}"; }
|
||
ok() { log "${C_OK} ✓${C_OFF} $*"; }
|
||
warn() { log "${C_WARN} !${C_OFF} $*"; }
|
||
fail() { log "${C_ERR} ✗${C_OFF} $*"; }
|
||
hint() { log "${C_DIM} $*${C_OFF}"; }
|
||
|
||
# Befehl ausführen, Ausgabe ins Protokoll, Fehler nicht tödlich.
|
||
# Für alles, was scheitern DARF, ohne den Spike abzubrechen.
|
||
try() {
|
||
log "${C_DIM} \$ $*${C_OFF}"
|
||
if "$@" >>"$LOG" 2>&1; then
|
||
return 0
|
||
else
|
||
local rc=$?
|
||
warn "fehlgeschlagen (Code $rc): $*"
|
||
return $rc
|
||
fi
|
||
}
|
||
|
||
# Wie try(), aber ein Fehlschlag beendet den Spike. Für echte Voraussetzungen.
|
||
need() {
|
||
log "${C_DIM} \$ $*${C_OFF}"
|
||
if ! "$@" >>"$LOG" 2>&1; then
|
||
fail "Abbruch — notwendiger Schritt fehlgeschlagen: $*"
|
||
log ""
|
||
log "Vollständiges Protokoll: $LOG"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
have() { command -v "$1" >/dev/null 2>&1; }
|
||
|
||
in_termux() {
|
||
case "${PREFIX:-}" in
|
||
*com.termux*) [ -d "$PREFIX/bin" ] ;;
|
||
*) return 1 ;;
|
||
esac
|
||
}
|
||
|
||
require_termux() {
|
||
if ! in_termux; then
|
||
fail "Dieses Skript läuft in Termux auf dem Telefon, nicht auf dem PC."
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# Prüft, ob die Grundlage steht, BEVOR ein Beweis losläuft. Ohne das scheitert ein
|
||
# Test mitten im Ablauf und sieht aus wie ein inhaltlicher Fehlschlag, obwohl nur
|
||
# die Vorbereitung fehlt — die irreführendste Sorte Fehler.
|
||
voraussetzungen_pruefen() {
|
||
local distro="${1:-debian}" fehlt=0
|
||
|
||
section "Voraussetzungen"
|
||
|
||
if ! have proot-distro; then
|
||
fail "proot-distro ist nicht installiert"
|
||
hint "Nachholen mit: bash spike/00-bootstrap-termux.sh"
|
||
return 1
|
||
fi
|
||
|
||
# 'cannot execute: required file not found' heißt NICHT, dass das Skript fehlt.
|
||
# Es heißt, dass der Interpreter aus seiner Shebang-Zeile fehlt. Der Unterschied
|
||
# kostet sonst eine halbe Stunde Suche an der falschen Stelle.
|
||
local pfad interpreter
|
||
pfad="$(command -v proot-distro)"
|
||
if ! proot-distro list >/dev/null 2>&1; then
|
||
fail "proot-distro lässt sich nicht ausführen"
|
||
interpreter="$(head -1 "$pfad" 2>/dev/null | sed 's|^#!||; s| .*||')"
|
||
log " Datei: $pfad"
|
||
log " Shebang: ${interpreter:-(keine)}"
|
||
if [ -n "$interpreter" ] && [ ! -x "$interpreter" ]; then
|
||
fail "Der Interpreter $interpreter fehlt oder ist nicht ausführbar."
|
||
hint "Das ist die Ursache, nicht proot-distro selbst."
|
||
hint "Reparieren mit: pkg install -y bash coreutils proot proot-distro"
|
||
else
|
||
hint "Reparieren mit: pkg reinstall -y proot-distro"
|
||
fi
|
||
return 1
|
||
fi
|
||
ok "proot-distro ausführbar"
|
||
|
||
if proot-distro list --installed 2>/dev/null | grep -q "^$distro\b" \
|
||
|| [ -d "$PREFIX/var/lib/proot-distro/installed-rootfs/$distro" ]; then
|
||
ok "$distro-Rootfs vorhanden"
|
||
else
|
||
fail "$distro-Rootfs fehlt"
|
||
hint "Nachholen mit: bash spike/00-bootstrap-termux.sh"
|
||
fehlt=1
|
||
fi
|
||
|
||
return $fehlt
|
||
}
|
||
|
||
# Fragt am Ende jedes Beweises nach dem, was nur ein Mensch beurteilen kann:
|
||
# ob es tatsächlich funktioniert hat. Das Ergebnis geht ins Protokoll.
|
||
verdict() {
|
||
local beweis="$1" frage="$2"
|
||
log ""
|
||
log "${C_HEAD}── Beurteilung $beweis ──${C_OFF}"
|
||
log "$frage"
|
||
printf ' [j] ja [n] nein [t] teilweise > '
|
||
read -r antwort </dev/tty || antwort="?"
|
||
local text
|
||
case "$antwort" in
|
||
j|J) text="BESTANDEN" ;;
|
||
n|N) text="GESCHEITERT" ;;
|
||
t|T) text="TEILWEISE" ;;
|
||
*) text="UNKLAR" ;;
|
||
esac
|
||
printf ' Anmerkung (eine Zeile, Enter für nichts) > '
|
||
read -r notiz </dev/tty || notiz=""
|
||
log " Ergebnis $beweis: $text ${notiz:+— $notiz}"
|
||
printf '%s\t%s\t%s\n' "$beweis" "$text" "$notiz" >>"$OUT_DIR/ergebnisse.tsv"
|
||
log ""
|
||
log "Ins Protokoll übertragen: docs/spike-protokoll.md"
|
||
log "Rohdaten: $LOG"
|
||
}
|
||
|
||
# Gerätesteckbrief — landet in jedem Protokoll, damit Meldungen vergleichbar sind.
|
||
geraete_steckbrief() {
|
||
section "Gerät"
|
||
local p
|
||
for p in ro.product.manufacturer ro.product.model ro.product.device \
|
||
ro.build.version.release ro.build.version.sdk ro.board.platform \
|
||
ro.hardware ro.soc.model; do
|
||
log " $p = $(getprop "$p" 2>/dev/null || echo '?')"
|
||
done
|
||
log " Arch = $(uname -m)"
|
||
log " Kernel = $(uname -r)"
|
||
if have free; then log " RAM = $(free -h 2>/dev/null | awk '/Mem:/{print $2}')"; fi
|
||
}
|