Skip to main content

Commands

cli

cli öffnet die eigentliche Switch-CLI, also die FastPath-/Switching-Ebene.

Dort arbeitest du mit Dingen wie:

show vlan
show running-config
configure
interface 0/1
switchport mode access
vlan database
write memory

Das ist die Cisco-ähnliche Oberfläche für:

  • VLANs
  • Ports
  • Trunks
  • Layer-2/teilweise Layer-3
  • laufende Switch-Konfiguration

Das Problem: Diese CLI verwaltet hauptsächlich den laufenden FastPath-Zustand. write memory meldet zwar Erfolg, aber die UniFi-Firmware baut FastPath beim Start wieder aus /tmp/system.cfg beziehungsweise der von ubntconf erzeugten Startup-Konfiguration auf. Deshalb verschwinden die Änderungen nach einem Reboot.




mca-cli-op

mca-cli-op gehört zur UniFi-Management-Ebene.

Auf deinem Switch ist es nur ein Symlink:

/usr/bin/mca-cli-op -> mcad

Es startet also das Programm mcad in einem speziellen Betriebsmodus.

mcad kümmert sich um Dinge wie:

  • Adoption
  • Controller-Kommunikation
  • Inform-Nachrichten
  • Provisionierung
  • Managementstatus
  • Werksreset
  • Speichern und Laden von UniFi-Konfiguration
  • mgmt.is_default
  • mgmt.is_setup_completed

Mit Argumenten wird es normalerweise als interner Einzelbefehl verwendet, zum Beispiel:

mca-cli-op inform
mca-cli-op set-inform http://controller:8080/inform
mca-cli-op set-default

Der Firmware-Wrapper ruft solche Befehle selbst auf. set-inform wird beispielsweise direkt an mca-cli-op weitergereicht, während set-default einen Werksreset einleitet.

Ohne Argument:

mca-cli-op

öffnet es die interaktive Management-CLI:

UniFi#

Das ist keine Linux-Shell und auch nicht dieselbe CLI wie cli. Deshalb kennt sie kein echo, awk, find oder Shell-Pipes.

Vereinfacht dargestellt

SSH-Shell
│
├── cli
│   └── FastPath-Switch-CLI
│       ├── VLANs
│       ├── Ports
│       ├── Trunks
│       └── running-config
│
└── mca-cli-op / mcad
    └── UniFi-Management-Stack
        ├── Adoption
        ├── Provisionierung
        ├── Controller/Inform
        ├── mgmt-Konfiguration
        └── Default-/Setup-Status


USW-Pro-48-US.7.5.6# mca-cli-op help 2>&1
UniFi Command Line Interface - Ubiquiti Networks

   info                      display device information
   set-default               restore to factory default
   set-inform <inform_url>   attempt inform URL (e.g. set-inform http://192.168.0.8:8080/inform)
   upgrade <firmware_url>    upgrade firmware (e.g. upgrade http://192.168.0.8/unifi_fw.bin)
   fwupdate --url <firmware_url|firmware_name> [--dl-only] [--md5sum <sum_of_fw>]
            [--keep-firmware] [--keep-running] [--reboot-sys] 
                                   new firmware update command
   reboot                    reboot the device

USW-Pro-48-US.7.5.6# printf 'Rückgabecode: %s\n' "$?"
Rückgabecode: 0
USW-Pro-48-US.7.5.6# mca-cli-op info

Model:       USW-Pro-48
Version:     7.5.6.17090
MAC Address: f4:e2:c6:c0:ec:22
IP Address:  172.16.1.22
Hostname:    USW-Pro-48
Uptime:      3893 seconds
NTP:         Not synchronized

Status:      Unable to resolve (http://unifi:8080/inform)
USW-Pro-48-US.7.5.6# echo '=== Managementwerte ==='
=== Managementwerte ===
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# for datei in \
>     /tmp/system.cfg \
>     /tmp/default.cfg \
>     /etc/persistent/cfg/mgmt
> do
>     if [ -r "$datei" ]; then
>         echo
>         echo "--- $datei ---"
> 
>         awk -F= '
>             $1 == "mgmt.is_default" ||
>             $1 == "mgmt.is_setup_completed" ||
>             $1 == "mgmt.cfgversion" ||
>             $1 == "mgmt.selfrun" ||
>             $1 ~ /^mgmt\.servers\.[0-9]+\.url$/ ||
>             $1 ~ /^mgmt\.led_/ {
>                 printf "%d: %s\n", NR, $0
>             }
>         ' "$datei"
>     else
>         echo
>         echo "--- $datei fehlt oder ist nicht lesbar ---"
>     fi
> done

--- /tmp/system.cfg ---
2: mgmt.is_default=true

--- /tmp/default.cfg ---
2: mgmt.is_default=true

--- /etc/persistent/cfg/mgmt fehlt oder ist nicht lesbar ---
USW-Pro-48-US.7.5.6# 

USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# awk '
> {
>     text[NR] = $0
> }
> 
> /set_cfg_save/ {
>     for (nummer = NR - 15; nummer <= NR + 20; nummer++) {
>         if (nummer > 0) {
>             zeigen[nummer] = 1
>         }
>     }
> }
> 
> END {
>     for (nummer = 1; nummer <= NR; nummer++) {
>         if (zeigen[nummer]) {
>             printf "%5d: %s\n", nummer, text[nummer]
>         }
>     }
> }
> ' /usr/etc/syswrapper.sh
 1030:          export SSH_CLIENT=""
 1031:          export UI_SSH_SAFE_CONTEXT="$LOG $TAIL_PID"
 1032:          setsid "$SCRIPT" "$cmd" "$@" >>$LOG 2>&1 </dev/null 3<&- &
 1033:          wait $TAIL_PID
 1034:          cat <&3 # Dump anything that tail might have missed
 1035:          exit 0
 1036:  fi
 1037: 
 1038:  set -- $UI_SSH_SAFE_CONTEXT
 1039:  [ $# -eq 2 ] || return
 1040:  local LOG=$1
 1041:  local TAIL_PID=$2
 1042:  local CLEAN_UP="kill $TAIL_PID 2>/dev/null; rm -f $LOG"
 1043:  trap "$CLEAN_UP; exit 0" HUP INT QUIT TERM EXIT
 1044: }
 1045: set_cfg_save() {
 1046:  if [ ! -e "$NEED_CFG_SAVE_FILE" ]; then
 1047:          log "Creating $NEED_CFG_SAVE_FILE"
 1048:          touch "$NEED_CFG_SAVE_FILE"
 1049:  fi
 1050: 
 1051:  pidof $SYSMON || syswrapper.sh cfg_save_check
 1052: 
 1053:  state_reload
 1054: }
 1055: 
 1056: # mac2serial <mac>
 1057: mac2serial() {
 1058:  echo $1 | sed -e 's/://g' -e 'y/ABCDEF/abcdef/'
 1059: }
 1060: 
 1061: # pkill_generic <process_name> [signal] [args]
 1062: pkill_generic() {
 1063:  local process=$1
 1064:  local signal=$2
 1065:  shift; shift;
 2975:  if type 'is_support_stacking' 2> /dev/null | grep -q 'function' && is_support_stacking ; then
 2976:          role="$(swctrl mgmt stack-info | sed -n 's/role=\([a-z]*\),.*/\1/p')"
 2977: 
 2978:          if [ "$role" = "controller" ]; then
 2979:                  log "[Stack] $cmd remote unit $unit_number"
 2980:                  swctrl mgmt stack-run -b "$unit_number" "syswrapper.sh $cmd"
 2981:          fi
 2982:  fi
 2983:  ;;
 2984: set-etherlight-mode)
 2985:  exit_if_busy $cmd $*
 2986:  exit_if_state_lock_failed $cmd $*
 2987:  _set_etherlight_mode "$1"
 2988:  rc=$?
 2989:  if [ $rc -eq 1 ]; then
 2990:          set_cfg_save
 2991:  fi
 2992:  state_unlock
 2993:  ;;
 2994: set-stack-unit-etherlight-mode)
 2995:  exit_if_busy $cmd $*
 2996:  exit_if_state_lock_failed $cmd $*
 2997:  _set_etherlight_mode "$1"
 2998:  rc=$?
 2999:  if [ $rc -eq 1 ]; then
 3000:          set_cfg_save
 3001:  fi
 3002:  state_unlock
 3003:  ;;
 3004: set-etherlight-device-type)
 3005:  exit_if_busy $cmd $*
 3006:  exit_if_state_lock_failed $cmd $*
 3007:  pkill_generic led_locate.sh -f
 3008: 
 3009:  led_device_type_mode=3
 3010:  _set_etherlight_mode $led_device_type_mode
 3011:  _set_port_bitmap_color $led_device_type_mode $@
 3012: 
 3013:  state_unlock
 3014:  ;;
 3015: set-port-locate)
 3016:  exit_if_busy $cmd $*
 3017:  exit_if_state_lock_failed $cmd $*
 3018:  pkill_generic led_locate.sh -f
 3019: 
 3020:  led_port_locate_mode=4
 3136:  if [ "$2" = "nopersist" ]; then
 3137:          persist=0
 3138:          log "[apply-config] persist=false - config will not be saved to flash"
 3139:  fi
 3140:  state_lock
 3141:  before=$(sed "s/\..*//" /proc/uptime)
 3142:  before_mca_pid=$(cat_file /var/run/mcad.0.pid)
 3143:  full_provision=0
 3144:  if ! do_fast_apply; then
 3145:          lockfile_retry 60 "$NEED_CFG_SAVE_LOCK_FILE" || exit 1
 3146:          full_provision=1
 3147:          /usr/etc/rc.d/rc restart
 3148:          unlockfile "$NEED_CFG_SAVE_LOCK_FILE"
 3149:  fi
 3150:  if [ "$persist" = 1 ]; then
 3151:          pidof $SYSMON && set_cfg_save
 3152:  fi
 3153:  state_reload
 3154:  now=$(sed "s/\..*//" /proc/uptime)
 3155:  delta=$((now - before))
 3156:  log "Provision took $delta sec, full=$full_provision, persist=$persist"
 3157:  # Remove deltas that may be due to time syncs, etc.
 3158:  if [ "$delta" -ge 0 -a "$delta" -lt 300 ]; then
 3159:          if [ "$full_provision" = 1 ]; then
 3160:                  add_stat /var/run/provision_time.total $delta
 3161:                  add_stat /var/run/provision_time.count 1
 3162:          else
 3163:                  add_stat /var/run/fast_apply_time.total $delta
 3164:                  add_stat /var/run/fast_apply_time.count 1
 3165:          fi
 3166:  fi
 3167:  # Update fw auto-rollback flag based on controller config
 3168:  # Default is enabled — only disable when explicitly set to "disabled"
 3169:  if [ "$(get_config_value /tmp/system.cfg switch.fw_auto_rollback.status)" = "disabled" ]; then
 3170:          touch /var/run/fw_auto_rollback_disabled
 3171:  else
 3195:  if [ ! -f /tmp/previous.cfg ]; then
 3196:          log "[apply-previous-config] previous.cfg not found, skipping rollback"
 3197:          state_unlock
 3198:          exit 1
 3199:  fi
 3200:  log "[apply-previous-config] reverting to previous configuration"
 3201:  cp -f /tmp/previous.cfg /tmp/system.cfg
 3202:  before=$(sed "s/\..*//" /proc/uptime)
 3203:  full_provision=0
 3204:  if ! do_fast_apply; then
 3205:          lockfile_retry 60 "$NEED_CFG_SAVE_LOCK_FILE" || exit 1
 3206:          full_provision=1
 3207:          /usr/etc/rc.d/rc restart
 3208:          unlockfile "$NEED_CFG_SAVE_LOCK_FILE"
 3209:  fi
 3210:  pidof $SYSMON && set_cfg_save
 3211:  state_reload
 3212:  now=$(sed "s/\..*//" /proc/uptime)
 3213:  delta=$((now - before))
 3214:  log "[apply-previous-config] Rollback took $delta sec, full=$full_provision"
 3215:  state_unlock
 3216:  ;;
 3217: apply-stack-unit-config)
 3218:  run_ssh_safe "$@"
 3219:  if type 'is_support_stacking' 2> /dev/null | grep -q 'function' && is_support_stacking ; then
 3220:          unit="$1"
 3221:          systemcfg_path="$2"
 3222:          role="$(swctrl mgmt stack-info | sed -n 's/role=\([a-z]*\),.*/\1/p')"
 3223:          before=$(sed "s/\..*//" /proc/uptime)
 3224:          STACKING_PATH="/tmp/stacking"
 3225: 
 3226:          if [ ! -f "$systemcfg_path" ]; then
 3227:                  log "[error] Configuration file not found: $systemcfg_path."
 3228:                  exit 1
 3229:          fi
 3230: 
 3269:          /bin/sh /var/run/if_up_hook.$ifname
 3270:  fi
 3271:  ;;
 3272: soft-restart)
 3273:  exit_if_busy $cmd $*
 3274:  run_ssh_safe "$@"
 3275:  state_lock
 3276:  lockfile_retry 30 "$NEED_CFG_SAVE_LOCK_FILE" || exit 1
 3277:  /usr/etc/rc.d/rc restart
 3278:  unlockfile "$NEED_CFG_SAVE_LOCK_FILE"
 3279:  state_reload
 3280:  state_unlock
 3281:  ;;
 3282: save-config)
 3283:  state_lock
 3284:  set_cfg_save
 3285:  state_unlock
 3286:  ;;
 3287: reload)
 3288:  exit_if_busy $cmd $*
 3289:  exit_if_state_lock_failed $cmd $*
 3290:  state_reload
 3291:  state_unlock
 3292:  ;;
 3293: set-ready)
 3294:  # called by mcagent
 3295:  state_lock
 3296:  set_state_ready
 3297:  state_unlock
 3298:  # Mark boot as successful for auto-rollback (once per boot)
 3299:  if [ ! -f /var/run/boot_success_marked ] && [ -x /sbin/ubntbox ] && \
 3300:     grep -q "ubnt_active_slot=" /proc/cmdline 2>/dev/null; then
 3301:          ubntbox bootsel mark-success && touch /var/run/boot_success_marked
 3302:  fi
 3303:  # Update fw auto-rollback flag based on controller config
 3304:  # Default is enabled — only disable when explicitly set to "disabled"
 3656:  ble_stp $@
 3657:  ;;
 3658: ble-check)
 3659:  ble_check $@
 3660:  ;;
 3661: kick-sta)
 3662:  kick_sta $1
 3663:  ;;
 3664: kick-sta-on)
 3665:  kick_sta_on $2 $1 $3
 3666:  ;;
 3667: block-sta)
 3668:  driver_kick_block_sta $1
 3669:  add_mac /etc/persistent/cfg/blocked_sta "$1"
 3670:  state_lock
 3671:  set_cfg_save
 3672:  state_unlock
 3673:  ;;
 3674: unblock-sta)
 3675:  del_mac /etc/persistent/cfg/blocked_sta "$1"
 3676:  driver_unblock_sta $1
 3677:  state_lock
 3678:  set_cfg_save
 3679:  state_unlock
 3680:  ;;
 3681: apply-blocked-sta)
 3682:  driver_apply_blocklist
 3683:  ;;
 3684: apply-blocked-sta-ifup)
 3685:  driver_apply_blocklist_ifup $1
 3686:  ;;
 3687: redirector-init)
 3688:  guest_redirector_init_iptables "$@"
 3689:  ;;
 3690: redirector-deinit)
 3691:  guest_redirector_deinit_iptables "$@"
 3692:  ;;
 3693: authorize-guest)
 3694:  guest_authorize "$@"
 3695:  ;;
 3696: unauthorize-guest)
 3697:  guest_unauthorize "$@"
 3698:  kick_sta $1
USW-Pro-48-US.7.5.6#

Das ist der bisher wichtigste Fund. Die Firmware besitzt tatsächlich einen vorgesehenen internen Speicherweg:

syswrapper.sh save-config
        ↓
set_cfg_save
        ↓
/var/run/need_cfg_save
        ↓
sysmon
        ↓
syswrapper.sh cfg_save_check
        ↓
sanitize_cfg
        ↓
cfgmtd -w -p /etc /tmp/system.cfg

save-config ist also etwas anderes als FastPaths write memory. Es speichert die UniFi-Systemkonfiguration, aus der beim Boot anschließend /tmp/.startup-config für den Switch erzeugt wird. Genau diese Bootkette wurde in deinen bisherigen Tests sichtbar.

Der Haken bleibt: cfg_save_check schreibt nur, wenn nach sanitize_cfg eine nichtleere Datei /etc/persistent/cfg/mgmt existiert. Ohne sie versucht es lediglich, eine alte Managementdatei aus dem Flash wiederherzustellen.

USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# rm -rf /tmp/usw-flash-read
USW-Pro-48-US.7.5.6# mkdir -p /tmp/usw-flash-read
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# cfgmtd -r \
>     -p /tmp/usw-flash-read \
>     -f /tmp/usw-flash-read/system.cfg

USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# printf 'cfgmtd Rückgabecode: %s\n' "$?"
cfgmtd Rückgabecode: 0
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# echo

USW-Pro-48-US.7.5.6# echo '=== Gelesene Dateien ==='
=== Gelesene Dateien ===
USW-Pro-48-US.7.5.6# find /tmp/usw-flash-read \
>     -maxdepth 4 \
>     -type f \
>     -exec ls -l {} \;
-rw-------    1 ui       admin         1018 Jun 22 10:03 /tmp/usw-flash-read/system.cfg
-rw-------    1 ui       admin           83 Jan  1  1970 /tmp/usw-flash-read/persistent/dropbear_ed25519_host_key
-rw-------    1 ui       admin           89 Jan  1  1970 /tmp/usw-flash-read/persistent/dropbear_ed25519_host_key.pub
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# echo

USW-Pro-48-US.7.5.6# echo '=== Managementdatei ==='
=== Managementdatei ===
USW-Pro-48-US.7.5.6# if [ -r /tmp/usw-flash-read/persistent/cfg/mgmt ]; then
>     awk -F= '
>         $1 == "mgmt.is_default" ||
>         $1 == "mgmt.is_setup_completed" ||
>         $1 == "mgmt.cfgversion" ||
>         $1 == "mgmt.selfrun" ||
>         $1 ~ /^mgmt\.servers\.[0-9]+\.url$/ ||
>         $1 ~ /^mgmt\.led_/ {
>             printf "%d: %s\n", NR, $0
>         }
>     ' /tmp/usw-flash-read/persistent/cfg/mgmt
> else
>     echo 'Keine persistente Managementdatei im gelesenen Flash-Stand'
> fi
Keine persistente Managementdatei im gelesenen Flash-Stand
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# echo

USW-Pro-48-US.7.5.6# echo '=== Managementwerte aus system.cfg ==='
=== Managementwerte aus system.cfg ===
USW-Pro-48-US.7.5.6# if [ -r /tmp/usw-flash-read/system.cfg ]; then
>     awk -F= '
>         $1 == "mgmt.is_default" ||
>         $1 == "mgmt.is_setup_completed" ||
>         $1 == "mgmt.cfgversion" ||
>         $1 == "mgmt.selfrun" ||
>         $1 ~ /^mgmt\.servers\.[0-9]+\.url$/ ||
>         $1 ~ /^mgmt\.led_/ {
>             printf "%d: %s\n", NR, $0
>         }
>     ' /tmp/usw-flash-read/system.cfg
> else
>     echo 'Keine system.cfg gelesen'
> fi
2: mgmt.is_default=true
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# rm -rf /tmp/usw-mgmt-runtime-test
USW-Pro-48-US.7.5.6# mkdir -p /tmp/usw-mgmt-runtime-test
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# if [ -d /etc/persistent/cfg ]; then
>     cp -a /etc/persistent/cfg /tmp/usw-mgmt-runtime-test/cfg.before
> else
>     echo 'cfg war nicht vorhanden' > /tmp/usw-mgmt-runtime-test/cfg-was-missing
> fi
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# mkdir -p /etc/persistent/cfg
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# cat > /etc/persistent/cfg/mgmt <<'EOF'
> mgmt.is_default=false
> mgmt.is_setup_completed=true
> EOF
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# chmod 600 /etc/persistent/cfg/mgmt
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# echo '=== Angelegte Laufzeitdatei ==='
=== Angelegte Laufzeitdatei ===
USW-Pro-48-US.7.5.6# cat /etc/persistent/cfg/mgmt
mgmt.is_default=false
mgmt.is_setup_completed=true
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# echo

USW-Pro-48-US.7.5.6# echo '=== Interner Adoptionstest ==='
=== Interner Adoptionstest ===
USW-Pro-48-US.7.5.6# /sbin/syswrapper.sh check-is-adopted
sh: false: unknown operand
USW-Pro-48-US.7.5.6# printf 'Rückgabecode: %s\n' "$?"
Rückgabecode: 2
USW-Pro-48-US.7.5.6# 
USW-Pro-48-US.7.5.6# echo

USW-Pro-48-US.7.5.6# echo '=== Laufzeitstatus ==='
=== Laufzeitstatus ===
USW-Pro-48-US.7.5.6# printf 'IsDefault='
IsDefault=USW-Pro-48-US.7.5.6# cat /proc/ubnthal/status/IsDefault
true
USW-Pro-48-US.7.5.6# printf 'LED-Pattern='
LED-Pattern=USW-Pro-48-US.7.5.6# cat /proc/gpio/led_pattern
2
USW-Pro-48-US.7.5.6#

Der Fehler kommt nicht von deiner mgmt-Datei. Der Firmware-Code ist schlicht schlampig geschrieben:


[ $(get_fw_env is_default) = false -o $(get_mgmt_cfg mgmt.is_default) = false ]

Da get_fw_env is_default auf diesem Switch leer zurückkommt, entsteht sinngemäß:


[ = false -o false = false ]

BusyBox antwortet darauf mit:


sh: false: unknown operand

Die Funktion check-is-adopted ist auf diesem Modell also kaputt, weil Ubiquiti Variablen nicht in Anführungszeichen gesetzt hat. Ein Klassiker: Milliardenunternehmen, Shellcode wie aus einem Freitagnachmittag.

IsDefault=true und LED-Muster 2 bleiben zunächst unverändert, weil das Anlegen der Datei den laufenden mcad-Status nicht automatisch neu lädt.

Die Ausgabe zeigt etwas Wichtiges: state_reload() liest nur /proc/ubnthal/status/IsDefault. Unsere neue mgmt-Datei wird dabei gar nicht beachtet. Deshalb bleiben LED-Muster 2 und IsDefault=true unverändert.

Offiziell ist für UniFi-Switches nur die Adoption über UniFi Network dokumentiert; einen unterstützten Standalone-Modus beschreibt Ubiquiti nur für bestimmte andere Geräteklassen. Wir arbeiten hier also bewusst unterhalb der offiziell vorgesehenen Verwaltungsschicht.

Jetzt machen wir einen automatisch rückgängig gemachten Laufzeittest. Er schreibt nichts in den Flash und stellt IsDefault nach 45 Sekunden wieder auf den bisherigen Wert zurück:

NODE=/proc/ubnthal/status/IsDefault

cat "$NODE" > /tmp/isdefault.before

setsid /bin/sh -c '
    sleep 45
    BEFORE="$(cat /tmp/isdefault.before 2>/dev/null)"
    [ -n "$BEFORE" ] || BEFORE=true
    printf "%s\n" "$BEFORE" > /proc/ubnthal/status/IsDefault
    /sbin/syswrapper.sh reload
' >/tmp/isdefault-restore.log 2>&1 </dev/null &

printf 'false\n' > "$NODE" || {
    echo 'IsDefault konnte nicht geschrieben werden'
    exit 1
}

/sbin/syswrapper.sh reload

echo '=== Testzustand ==='
printf 'IsDefault='
cat "$NODE"

printf 'LED-Pattern='
cat /proc/gpio/led_pattern

printf 'System-State='
cat /var/run/system.state 2>/dev/null || echo 'nicht vorhanden'

printf 'Uplink='
cat /var/run/system.uplink 2>/dev/null || echo 'nicht vorhanden'