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.
This commit is contained in:
Michael Sauer
2026-09-15 03:44:50 +02:00
parent 4e1a965cbb
commit c296e2626e
2 changed files with 80 additions and 8 deletions
+14 -5
View File
@@ -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
+66 -3
View File
@@ -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"