From c296e2626e925ff077bb35febca116e4008da545 Mon Sep 17 00:00:00 2001 From: Michael Sauer Date: Tue, 15 Sep 2026 03:44:50 +0200 Subject: [PATCH] fix(station): nmcli-Werte unmaskiert lesen, Doppelpunkt im Profilnamen nmcli -t maskiert Doppelpunkte in Werten als \: und cut -d: -f2 schneidet ohnehin am ersten Doppelpunkt ab. Ein Profilname mit Doppelpunkt lieferte der Nachpruefung in ap_switch() damit einen abgeschnittenen Wert - und der Fehler zeigte in die unsichere Richtung: "Station aus" gemeldet, waehrend der Zugangspunkt weitersendet. Jetzt --escape no plus cut -f2-, auch bei den beiden Profilabfragen und in der Statusausgabe. Der nmcli-Stub in test_cli.sh maskiert jetzt wie das echte nmcli, sonst waere der neue Zusatzfall M1 mit und ohne Fix gruen. --- tools/station/ninlight-station | 19 ++++++--- tools/station/tests/test_cli.sh | 69 +++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 8 deletions(-) diff --git a/tools/station/ninlight-station b/tools/station/ninlight-station index 490a5ea..1273c02 100755 --- a/tools/station/ninlight-station +++ b/tools/station/ninlight-station @@ -124,7 +124,7 @@ need_profile() { # $1 = NetworkManager-Profilname, der existieren muss. # -F: der Profilname ist ein Konfigurationswert, kein BRE-Muster - ein Name mit # "." oder "[" wuerde mit "grep -x" sonst falsch (oder gar nicht) treffen. - nmcli -t -f NAME con show | grep -Fqx "$1" || { + nmcli -t --escape no -f NAME con show | grep -Fqx "$1" || { echo "Fehler: NetworkManager-Profil '$1' fehlt - tools/station/setup_pi.sh ausfuehren" >&2 exit 1 } @@ -266,7 +266,15 @@ ap_switch() { # zeigt, und erst dann Erfolg melden (Fixrunde 1, I2) - sonst kann z.B. der # Migrations-AP mit oeffentlich bekanntem Passwort weitersenden, waehrend # das CLI "Station aus" behauptet. - _active=$(nmcli -t -f GENERAL.CONNECTION device show wlan0 2>/dev/null | cut -d: -f2) + # --escape no und "-f2-" gehoeren zusammen (Abschlussreview, M1): "nmcli -t" + # maskiert Doppelpunkte IN WERTEN als "\:", und "cut -f2" schneidet ohnehin am + # ersten Doppelpunkt ab. Ein Profilname mit Doppelpunkt ergaebe so einen + # abgeschnittenen Wert, der Vergleich unten schluege fehl - und zwar in die + # UNSICHERE Richtung: "Station aus" gemeldet, waehrend der Zugangspunkt + # weitersendet. --escape no liefert den Rohwert, -f2- nimmt den ganzen Rest der + # Zeile (die Ausgabe hat genau ein Feld, alles nach dem ersten Doppelpunkt + # gehoert zum Wert). + _active=$(nmcli -t --escape no -f GENERAL.CONNECTION device show wlan0 2>/dev/null | cut -d: -f2-) if [ "$_active" = "$AP_CONNECTION" ] || [ "$_active" = "$MIGRATE_AP_CONNECTION" ]; then echo "Fehler: wlan0 zeigt nach dem Ausschalten immer noch '$_active' aktiv - NetworkManager pruefen (Zugangspunkt bleibt an)" >&2 return 1 @@ -274,7 +282,8 @@ ap_switch() { return 0 fi sudo nmcli con up "$_target" >/dev/null - _active=$(nmcli -t -f GENERAL.CONNECTION device show wlan0 2>/dev/null | cut -d: -f2) + # --escape no / -f2- aus demselben Grund wie oben. + _active=$(nmcli -t --escape no -f GENERAL.CONNECTION device show wlan0 2>/dev/null | cut -d: -f2-) if [ "$_active" != "$_target" ]; then sudo nmcli con down "$AP_CONNECTION" >/dev/null 2>&1 || true sudo nmcli con down "$MIGRATE_AP_CONNECTION" >/dev/null 2>&1 || true @@ -835,7 +844,7 @@ full_off() { # macht "off" unabhaengig vom Anzeigedienst - ob der installiert, aktiv oder gerade # gescheitert ist, hat auf das Abschalten der Station keinen Einfluss. ap_switch "" - if nmcli -t -f NAME con show | grep -Fqx "$HOME_CONNECTION"; then + if nmcli -t --escape no -f NAME con show | grep -Fqx "$HOME_CONNECTION"; then if sudo nmcli con up "$HOME_CONNECTION" >/dev/null; then echo "Station aus, wlan0 zurueck im Heim-WLAN ($HOME_CONNECTION)" else @@ -1041,7 +1050,7 @@ PY printf 'Erkannt: %s\n' "$_erkannt" printf 'Dienst : %s\n' "$(systemctl is-active ninlight-station 2>/dev/null || true)" autooff_status_line - printf 'wlan0 : %s\n' "$(nmcli -t -f GENERAL.CONNECTION device show wlan0 2>/dev/null | cut -d: -f2)" + printf 'wlan0 : %s\n' "$(nmcli -t --escape no -f GENERAL.CONNECTION device show wlan0 2>/dev/null | cut -d: -f2-)" printf 'Adresse: %s\n' "$(ip -4 -br addr show wlan0 2>/dev/null | awk '{print $3}')" echo "Images :" images | while read -r f; do diff --git a/tools/station/tests/test_cli.sh b/tools/station/tests/test_cli.sh index b7c9977..437f14e 100755 --- a/tools/station/tests/test_cli.sh +++ b/tools/station/tests/test_cli.sh @@ -75,8 +75,38 @@ setup_stubbin() { echo "STUB nmcli \$*" >>"$log" NMSTATE="$nmstate" +# "--escape no" abtrennen, BEVOR die Stellungen geprueft werden - sonst verschoebe der +# Schalter alle Positionen. Und der Stub maskiert wie das echte nmcli: OHNE den Schalter +# wird in den Werten von "-t" jeder Doppelpunkt zu "\\:" (Abschlussreview, M1). Nur so +# prueft der Test das Skript und nicht die Attrappe - ein Stub, der nie maskiert, waere +# mit und ohne den Fix gruen. +ESCAPE=yes +_args=() +while [ \$# -gt 0 ]; do + case "\$1" in + --escape) ESCAPE=\$2; shift 2 ;; + *) _args+=("\$1"); shift ;; + esac +done +set -- "\${_args[@]}" + +emit() { + # \$1 = Feldname, \$2 = Rohwert + if [ "\$ESCAPE" = "no" ]; then + echo "\$1:\$2" + else + echo "\$1:\${2//:/\\\\:}" + fi +} + if [ "\$1" = "-t" ] && [ "\$2" = "-f" ] && [ "\$3" = "NAME" ] && [ "\$4" = "con" ] && [ "\$5" = "show" ]; then - cat "\$NMSTATE/profiles" 2>/dev/null + while IFS= read -r _profile; do + if [ "\$ESCAPE" = "no" ]; then + echo "\$_profile" + else + echo "\${_profile//:/\\\\:}" + fi + done <"\$NMSTATE/profiles" 2>/dev/null exit 0 fi @@ -84,11 +114,11 @@ if [ "\$1" = "-t" ] && [ "\$2" = "-f" ] && [ "\$3" = "GENERAL.CONNECTION" ] && [ # Testschalter fuer Fall I3 (Fixrunde 1): erzwingt eine Antwort, die nicht zum # zuletzt hochgefahrenen Profil passt, um ap_switch()'s Fehlerzweig zu pruefen. if [ -n "\${FAKE_NMCLI_DEVSHOW:-}" ]; then - echo "GENERAL.CONNECTION:\${FAKE_NMCLI_DEVSHOW}" + emit GENERAL.CONNECTION "\${FAKE_NMCLI_DEVSHOW}" exit 0 fi last=\$(tail -n1 "\$NMSTATE/active" 2>/dev/null) - echo "GENERAL.CONNECTION:\${last:---}" + emit GENERAL.CONNECTION "\${last:---}" exit 0 fi @@ -621,6 +651,39 @@ echo "$ERR" | grep -qi "fehler" && pass "Fehlermeldung auf stderr vorhanden" || ACTIVE_AFTER=$(cat "$SBX/nmstate/active") [ "$ACTIVE_AFTER" = "ninlight-recovery" ] && pass "ninlight-recovery ist (wie vom Stub simuliert) tatsaechlich noch aktiv" || fail "unerwarteter nmcli-Zustand: $ACTIVE_AFTER" +echo +echo "=== Zusatzfall M1 (Abschlussreview): ein Profilname MIT Doppelpunkt wird beim Nachpruefen richtig gelesen ===" +# "nmcli -t" maskiert Doppelpunkte in Werten als "\:", und "cut -d: -f2" schneidet am +# ersten Doppelpunkt ab. Ohne "--escape no" UND "-f2-" liest ap_switch() aus einem +# Profil "ninlight:recovery" nur "ninlight\" bzw. "ninlight" - der Vergleich schluege +# fehl, und zwar in die UNSICHERE Richtung: "Station aus" gemeldet, waehrend der +# Zugangspunkt weitersendet. Aufbau wie Zusatzfall I2, nur mit Doppelpunkt im Namen. +SBX="$TMPROOT/tM1" +setup_sandbox "$SBX" +sed -i.bak "s/^AP_CONNECTION=.*/AP_CONNECTION='ninlight:recovery'/" "$SBX/station.conf" +rm -f "$SBX/station.conf.bak" +printf 'ninlight:recovery\nqconnex-firmware\nhome-wifi\n' >"$SBX/nmstate/profiles" +set +e +OUT=$(run_cli "$SBX" on 2>"$SBX/stderr.log") +RC=$? +set -e +[ "$RC" -eq 0 ] && pass "'on' kommt mit einem Doppelpunkt im Profilnamen zurecht" \ + || fail "'on' scheiterte an einem Doppelpunkt im Profilnamen (rc=$RC): $OUT $(cat "$SBX/stderr.log")" +[ "$(cat "$SBX/nmstate/active")" = "ninlight:recovery" ] \ + && pass "das Profil mit Doppelpunkt ist aktiv" || fail "unerwarteter nmcli-Zustand: $(cat "$SBX/nmstate/active")" +set +e +OUT=$(FAKE_NMCLI_STUCK=1 run_cli "$SBX" off 2>"$SBX/stderr.log") +RC=$? +set -e +ERR=$(cat "$SBX/stderr.log") +[ "$RC" -ne 0 ] \ + && pass "Exit-Code != 0 - der haengende Zugangspunkt wird trotz Doppelpunkt im Namen erkannt" \ + || fail "Exit-Code war 0, obwohl 'ninlight:recovery' weiterhin aktiv war: $OUT" +echo "$OUT" | grep -q "Station aus" && fail "CLI behauptete faelschlich 'Station aus'" \ + || pass "keine falsche 'Station aus'-Meldung" +echo "$ERR" | grep -q "ninlight:recovery" \ + && pass "die Fehlermeldung nennt den vollstaendigen Profilnamen, nicht den abgeschnittenen" \ + || fail "Fehlermeldung nennt den Profilnamen nicht vollstaendig: $ERR" echo echo "=== Zusatzfall I3: ap_switch bricht ab und faehrt beide Profile herunter, wenn 'device show wlan0' nach dem Umschalten nicht passt ===" SBX="$TMPROOT/tI3"