262 lines
8.0 KiB
Bash
Executable File
262 lines
8.0 KiB
Bash
Executable File
#!/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
|