#!/usr/bin/env bash # diagnose-phase0-boot-evidence.sh — Phase 0 boot evidence collector # # Checks a mounted/extracted Red Bear root tree, or the running root when no # --root is supplied, for the boot-critical evidence needed to diagnose modern # hardware bring-up: PCI driver config locations, init service wiring, driver # binary presence, and optional driver-manager boot-timeline evidence. set -euo pipefail ROOT="/" BOOT_LOG="" usage() { cat <<'USAGE' Usage: local/scripts/diagnose-phase0-boot-evidence.sh [--root ] [--boot-log ] Examples: local/scripts/diagnose-phase0-boot-evidence.sh --root /mnt/redbear-root local/scripts/diagnose-phase0-boot-evidence.sh --boot-log serial.log Exit codes: 0 — evidence complete enough for Phase 0 diagnostics 1 — missing boot-critical evidence found 2 — usage or input path error USAGE } while [ $# -gt 0 ]; do case "$1" in --root) [ $# -ge 2 ] || { usage >&2; exit 2; } ROOT="$2" shift 2 ;; --boot-log) [ $# -ge 2 ] || { usage >&2; exit 2; } BOOT_LOG="$2" shift 2 ;; -h|--help) usage exit 0 ;; *) echo "ERROR: unknown argument: $1" >&2 usage >&2 exit 2 ;; esac done if [ ! -d "$ROOT" ]; then echo "ERROR: root path is not a directory: $ROOT" >&2 exit 2 fi if [ -n "$BOOT_LOG" ] && [ ! -f "$BOOT_LOG" ]; then echo "ERROR: boot log not found: $BOOT_LOG" >&2 exit 2 fi failures=0 warnings=0 join_root() { local path="$1" if [ "$ROOT" = "/" ]; then printf '/%s' "${path#/}" else printf '%s/%s' "${ROOT%/}" "${path#/}" fi } section() { echo "" echo "=== $* ===" } ok() { echo " OK: $*"; } warn() { echo " WARN: $*"; warnings=$((warnings + 1)); } fail() { echo " FAIL: $*"; failures=$((failures + 1)); } file_exists() { [ -f "$(join_root "$1")" ]; } dir_exists() { [ -d "$(join_root "$1")" ]; } executable_exists() { [ -x "$(join_root "$1")" ]; } count_files() { local dir="$1" if dir_exists "$dir"; then find "$(join_root "$dir")" -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' ' else printf '0' fi } config_contains_driver() { local driver="$1" shift local dir path for dir in "$@"; do path="$(join_root "$dir")" [ -d "$path" ] || continue if grep -Rqs "\b${driver}\b" "$path"; then return 0 fi done return 1 } service_cmd() { local service="$1" local path for path in "/etc/init.d/$service" "/usr/lib/init.d/$service" "/lib/init.d/$service"; do if file_exists "$path"; then grep -E '^[[:space:]]*cmd[[:space:]]*=' "$(join_root "$path")" 2>/dev/null | head -n 1 || true return 0 fi done return 1 } section "Phase 0 root" echo " root: $ROOT" [ -n "$BOOT_LOG" ] && echo " boot_log: $BOOT_LOG" section "PCI config directories" pcid_count=0 for dir in /usr/lib/pcid.d /lib/pcid.d /etc/pcid.d; do count="$(count_files "$dir")" echo " $dir: $count files" pcid_count=$((pcid_count + count)) done driversd_count=0 for dir in /usr/lib/drivers.d /lib/drivers.d /etc/drivers.d; do count="$(count_files "$dir")" echo " $dir: $count files" driversd_count=$((driversd_count + count)) done if [ "$pcid_count" -eq 0 ] && [ "$driversd_count" -eq 0 ]; then fail "no pcid.d or drivers.d config files found; driver-manager cannot match devices" elif [ "$driversd_count" -gt 0 ]; then ok "drivers.d config files present" elif [ "$pcid_count" -gt 0 ]; then ok "pcid.d config files present" else warn "unexpected PCI config directory state" fi section "Boot-critical driver config coverage" check_driver_config() { local driver="$1" local description="$2" if config_contains_driver "$driver" /usr/lib/pcid.d /lib/pcid.d /etc/pcid.d /usr/lib/drivers.d /lib/drivers.d /etc/drivers.d; then ok "$description has config entry containing '$driver'" else fail "$description has no config entry containing '$driver'" fi } check_driver_config xhcid "xHCI USB" check_driver_config nvmed "NVMe storage" check_driver_config ihdad "Intel HDA audio" check_driver_config redox-drm "DRM/KMS graphics" section "Boot-critical binary coverage" check_binary_anywhere() { local description="$1" shift local candidate for candidate in "$@"; do if executable_exists "$candidate"; then ok "$description binary exists at $candidate" return 0 fi done fail "$description binary missing; checked: $*" } check_binary_anywhere "pcid" /usr/bin/pcid /usr/lib/drivers/pcid check_binary_anywhere "driver-manager" /usr/bin/driver-manager /usr/lib/drivers/driver-manager if executable_exists /usr/bin/pcid-spawner || executable_exists /usr/lib/drivers/pcid-spawner; then ok "pcid-spawner compatibility binary exists" else warn "pcid-spawner compatibility binary missing; this is acceptable when driver-manager owns spawning" fi check_binary_anywhere "xHCI" /usr/lib/drivers/xhcid /usr/bin/xhcid check_binary_anywhere "NVMe" /usr/lib/drivers/nvmed /usr/bin/nvmed check_binary_anywhere "Intel HDA" /usr/lib/drivers/ihdad /usr/bin/ihdad check_binary_anywhere "DRM/KMS" /usr/bin/redox-drm /usr/lib/drivers/redox-drm section "Init service wiring" if cmd_line="$(service_cmd 00_driver-manager.service)" && [ -n "$cmd_line" ]; then ok "00_driver-manager.service present: $cmd_line" else fail "00_driver-manager.service missing from init service directories" fi if cmd_line="$(service_cmd 00_pcid-spawner.service)" && [ -n "$cmd_line" ]; then ok "00_pcid-spawner.service compatibility alias present: $cmd_line" else warn "00_pcid-spawner.service compatibility alias not present" fi if [ "$driversd_count" -gt 0 ] && service_cmd 00_driver-manager.service >/dev/null 2>&1; then cmd_line="$(service_cmd 00_driver-manager.service)" if echo "$cmd_line" | grep -q 'pcid-spawner'; then warn "00_driver-manager.service still runs pcid-spawner while drivers.d files exist" fi fi section "Optional boot log evidence" if [ -z "$BOOT_LOG" ]; then warn "no --boot-log supplied; skipping runtime evidence checks" else if grep -q '"event":"bus_enumerated"' "$BOOT_LOG"; then ok "driver-manager bus enumeration timeline evidence found" grep '"event":"bus_enumerated"' "$BOOT_LOG" | sed 's/^/ /' elif grep -q 'pcid-spawner: phase0 summary' "$BOOT_LOG"; then ok "legacy pcid-spawner phase0 summary found" grep 'pcid-spawner: phase0 summary' "$BOOT_LOG" | sed 's/^/ /' else fail "driver-manager bus enumeration evidence not found in boot log" fi if grep -q '"event":"probe".*"status":"bound"' "$BOOT_LOG"; then ok "driver-manager bound-probe evidence found" elif grep -q 'pcid-spawner: matched PCI' "$BOOT_LOG"; then ok "legacy matched PCI driver evidence found" else warn "no bound PCI driver evidence found" fi if grep -q '"event":"bus_enumeration_failed"' "$BOOT_LOG"; then warn "driver-manager bus enumeration failures found" grep '"event":"bus_enumeration_failed"' "$BOOT_LOG" | sed 's/^/ /' elif grep -q '"event":"probe".*"status":"failed"' "$BOOT_LOG"; then warn "driver-manager failed-probe evidence found" grep '"event":"probe".*"status":"failed"' "$BOOT_LOG" | sed 's/^/ /' elif grep -q 'pcid-spawner: unmatched PCI' "$BOOT_LOG"; then warn "legacy unmatched PCI devices found; inspect detailed pcid-spawner logs" grep 'pcid-spawner: unmatched PCI' "$BOOT_LOG" | sed 's/^/ /' else ok "no bus enumeration failure or failed-probe evidence in supplied boot log" fi fi section "Summary" echo " failures: $failures" echo " warnings: $warnings" if [ "$failures" -gt 0 ]; then echo "FAILED: Phase 0 boot evidence is incomplete." >&2 exit 1 fi echo "OK: Phase 0 boot evidence checks passed." exit 0