4.4 KiB
Startup Environment Check + Self-Heal
Date: 2026-08-19
Problem
Rebooting the Pineapple left Mark VIII in a broken state: the boot-persistent procd service came back, but nothing reconciled pineapd/UCI/monitors, so the UI reported state that did not match the device (pool "off" while actually broadcasting), native recon scans failed, and scans only returned 5GHz results.
Three observed failures:
- native recon scan failed —
h_recon_startproxies/api/pineap/recon/new; it returns 502 when the daemon fails (typically pineapd down/crash-looping). Nothing verifies pineapd health before the user starts a scan. - scans only showed 5GHz — radio0's AP interfaces (wlan0open/wlan0wpa)
pin
wlan0monto one 2.4GHz channel (a phy's channel is held by its AP interface), so 2.4GHz results mostly vanish while 5GHzwlan1monhopping keeps producing results. The band UCI config itself is correct. - pool "on" while UI shows "off" — the UI's advertise state is derived
only from UCI
pineapd.@ssidpool[0].disable. Nothing syncs pineapd's runtime pool broadcast to match UCI. UCI can say disabled while pineapd is live-broadcasting.
Design decisions
- Keep boot auto-start; the service self-heals at every startup instead.
- The env check auto-fixes everything fixable, re-verifies, and only fails hard on core deps (daemon unreachable after fix, pineapd down after restart, recon DB unreadable).
- 5GHz-only scans are handled by verify + warn (no scan-time AP pausing).
Implementation
1. env_check() in server.py (single source of truth)
Runs in order and returns [{step, ok, detail, action}] where ok is one of
pass, fixed, warn, fail:
- Daemon reachable —
daemon_sock_call('GET', '/api/pineap/get_config'). Report-only. - pineapd alive —
pidof pineapd. If down: stabilize UCI, restart/etc/init.d/pineapd, re-verify. Core: if still down after restart -> fail. - Sane-off UCI defaults — reuse the
_stabilize_pineapdwanted-dict (pooldisable=1+ clear pool list,wlan2mon.disable=1/hop=0,wlan1mon.bands=5/hop=0,wlan0mon.bands=2). Write + commit when missing. Refactor so the health monitor and env check share the wanted-dict. - Runtime pool sync — when UCI says pool disabled, call
_pineap('SSIDPOOL', 'DISABLE')so pineapd's runtime broadcast matches the UI. Report the resulting runtime state aspool_runtime. - Monitors up —
_bring_monitors_up()for wlan0mon/wlan1mon. - Recon DB readable — read-only scan-count query against
RECON_DB. Report row count. Core: unreadable -> fail. - 2.4GHz sampling — report enabled radio0 APs (wlan0open/wlan0wpa). Warn: "2.4GHz under-sampled while an OpenAP/Evil WPA AP is up on radio0".
2. CLI mode server.py --env-check
if __name__ == '__main__' branch: run env_check(), print verbose
[PASS] step — detail / [FIXED] ... / [WARN] ... / [FAIL] ... lines to
stdout, exit 0 (all pass/warn) or 1 (any core fail).
3. Startup self-heal
serve() runs env_check() before binding, stores the report in module state,
and logs to /tmp/pagerwebui.log (covers boot + procd respawn).
4. API + UI
GET /api/healthgainsenv(last env-check report + timestamp + pass/fixed/warn/fail counts) andpool_runtime(actual runtime broadcast state after sync).GET /api/recon/statusgainswlan0_pinned(true when a radio0 AP is enabled); the recon scan bar shows a 2.4GHz under-sampling warning pill.h_recon_startfailure includesdetailin the user-facing error.
5. payload.sh
Before starting the service (both foreground and background paths), run
python3 "$SCRIPT_DIR/server.py" --env-check, show output verbosely on the
payload screen, and abort with a red message on exit 1. Bump header version to
match the current release.
6. Tests
tests/test_env_check.py— fakedevice_runUCI harness (pattern fromtest_health.py): defaults applied when missing / idempotent when set, pool list cleared, runtime SSIDPOOL disable invoked when UCI says disabled, monitors brought up, pineapd restarted when down, DB unreadable -> fail, CLI--env-checkprints and exits correctly.test_health.pyupdated for the shared stabilization refactor.
Out of scope
- No scan-time AP pausing / radio0 AP teardown.
- No changes to radio1 / evil-twin / enterprise config handling.