fix: update phase0 boot evidence diagnostics
This commit is contained in:
+261
@@ -0,0 +1,261 @@
|
||||
#!/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 <mounted-root>] [--boot-log <log-file>]
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user