use std::env; use std::fs; use std::io::Read; use std::path::PathBuf; use std::process; use std::time::{SystemTime, UNIX_EPOCH}; use redox_driver_sys::pci::{InterruptSupport, parse_device_info_from_config_space}; use redox_driver_sys::quirks::{PciQuirkFlags, lookup_pci_quirks}; use serde_json::Value as JsonValue; use toml::Value; #[cfg(test)] use std::path::Path; #[cfg(feature = "tui")] mod tui; const RESET: &str = "\x1b[0m"; const GREEN: &str = "\x1b[32m"; const YELLOW: &str = "\x1b[33m"; const RED: &str = "\x1b[31m"; const BLUE: &str = "\x1b[34m"; const DIVIDER: &str = "═══════════════════════════════════════════════════════════════════"; const RTL8125_VENDOR_ID: u16 = 0x10ec; const RTL8125_DEVICE_ID: u16 = 0x8125; const VIRTIO_NET_VENDOR_ID: u16 = 0x1af4; const VIRTIO_NET_DEVICE_ID: u16 = 0x1000; const BLUETOOTH_STATUS_FRESHNESS_SECS: u64 = 90; const BOOT_TIMELINE_PATH: &str = "/tmp/redbear-boot-timeline.json"; const DRIVER_PARAMS_ROOT: &str = "/tmp/redbear-driver-params"; #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum OutputMode { Table, Json, Test, Quirks, Probe, Boot, Device, Health, Help, Tui, } struct Options { mode: OutputMode, verbose: bool, device: Option, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum ProbeState { Absent, Present, Active, Functional, Unobservable, } struct Runtime { root: Option, } struct IdentityReport { pretty_name: Option, version_id: Option, hostname: Option, } struct NetworkReport { state: ProbeState, connected: bool, interface: Option, mac: Option, address: Option, dns: Option, default_route: Option, active_profile: Option, network_schemes: Vec, wifi_control_state: ProbeState, wifi_interfaces: Vec, wifi_firmware_status: Option, wifi_transport_status: Option, wifi_transport_init_status: Option, wifi_activation_status: Option, wifi_connect_result: Option, wifi_disconnect_result: Option, wifi_scan_results: Vec, claim_limit: &'static str, bluetooth_transport_state: ProbeState, bluetooth_control_state: ProbeState, bluetooth_adapters: Vec, bluetooth_transport_status: Option, bluetooth_adapter_status: Option, bluetooth_scan_results: Vec, bluetooth_connection_state: Option, bluetooth_connect_result: Option, bluetooth_disconnect_result: Option, bluetooth_read_char_result: Option, bluetooth_bond_store_path: Option, bluetooth_bond_count: Option, bluetooth_claim_limit: &'static str, } struct HardwareReport { pci_devices: usize, pci_irq_none: usize, pci_irq_legacy: usize, pci_irq_msi: usize, pci_irq_msix: usize, pci_irq_forced_legacy: usize, pci_irq_msix_disabled_by_quirk: usize, pci_irq_msi_disabled_by_quirk: usize, runtime_irq_reports: Vec, usb_controllers: usize, drm_cards: usize, acpi_power_surface_present: bool, rtl8125_present: bool, virtio_net_present: bool, } struct IrqRuntimeReport { driver: String, pid: u32, device: String, mode: String, reason: String, } struct QuirkFile { name: String, pci_quirks: Vec, usb_quirks: Vec, dmi_quirk_count: usize, } struct QuirkEntry { vendor: String, device: Option, class: Option, flags: Vec, description: Option, } struct UsbQuirkEntry { vendor: String, product: Option, flags: Vec, } struct QuirksReport { files_loaded: Vec, load_errors: Vec, } struct IntegrationCheck { name: &'static str, category: &'static str, description: &'static str, artifact_path: Option<&'static str>, control_path: Option<&'static str>, test_hint: &'static str, note: &'static str, functional_probe: Option Option>, } struct IntegrationStatus<'a> { check: &'a IntegrationCheck, state: ProbeState, artifact_present: Option, control_present: Option, evidence: Vec, claim_limit: &'static str, } struct Report<'a> { identity: IdentityReport, network: NetworkReport, hardware: HardwareReport, integrations: Vec>, } #[derive(Clone, Debug, PartialEq, Eq)] struct BootTimelineEntry { ts: u128, event: BootTimelineEvent, } #[derive(Clone, Debug, PartialEq, Eq)] enum BootTimelineEvent { BusEnumerated { bus: String, count: usize, }, Probe { device: String, driver: String, status: BootProbeStatus, }, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum BootProbeStatus { Bound, Deferred, Failed, Skipped, } struct DeviceStatusReport { selector: String, status: Option, vendor_id: u16, device_id: u16, class_code: u8, class_name: &'static str, irq_mode: String, driver: Option, parameters: Vec<(String, String)>, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum HealthState { Healthy, Warning, Critical, } struct HealthItem { label: &'static str, state: HealthState, detail: String, } const INTEGRATIONS: &[IntegrationCheck] = &[ IntegrationCheck { name: "redbear-info", category: "Tool", description: "Runtime integration status utility", artifact_path: Some("/usr/bin/redbear-info"), control_path: None, test_hint: "redbear-info --json", note: "Binary presence proves the tool is installed, not that every integration is healthy.", functional_probe: None, }, IntegrationCheck { name: "lspci", category: "Tool", description: "Native PCI inventory command", artifact_path: Some("/usr/bin/lspci"), control_path: Some("/scheme/pci"), test_hint: "lspci", note: "Functional when the PCI scheme is enumerable.", functional_probe: Some(probe_directory_readable), }, IntegrationCheck { name: "lsusb", category: "Tool", description: "Native USB inventory command", artifact_path: Some("/usr/bin/lsusb"), control_path: Some("/scheme"), test_hint: "lsusb", note: "Functional when at least one usb.* controller scheme is readable.", functional_probe: Some(probe_usb_surface), }, IntegrationCheck { name: "netctl", category: "Tool", description: "Redox-native network profile manager", artifact_path: Some("/usr/bin/netctl"), control_path: Some("/etc/netctl"), test_hint: "netctl status", note: "Profiles and active profile tracking are readable; profile application remains a separate runtime action.", functional_probe: Some(probe_netctl_surface), }, IntegrationCheck { name: "redbear-wifictl", category: "Networking", description: "Wi-Fi control daemon and scheme", artifact_path: Some("/usr/bin/redbear-wifictl"), control_path: Some("/scheme/wifictl"), test_hint: "ls /scheme/wifictl/ && redbear-wifictl --connect wlan0 demo open && netctl start wifi-dhcp", note: "Functional when the wifictl scheme is enumerable, reports interface state, and exposes the bounded connect path; this still does not prove real radio association or working Wi-Fi connectivity.", functional_probe: Some(probe_wifictl_surface), }, IntegrationCheck { name: "redbear-btusb", category: "Bluetooth", description: "Bounded USB Bluetooth transport daemon", artifact_path: Some("/usr/bin/redbear-btusb"), control_path: Some("/var/run/redbear-btusb/status"), test_hint: "redbear-btusb --probe && redbear-btusb --status", note: "Active when the explicit-startup btusb status file is visible; this does not prove controller initialization, USB-class autospawn, or a real BLE workload.", functional_probe: Some(probe_btusb_surface), }, IntegrationCheck { name: "redbear-btctl", category: "Bluetooth", description: "Bounded Bluetooth host/control daemon and scheme", artifact_path: Some("/usr/bin/redbear-btctl"), control_path: Some("/scheme/btctl"), test_hint: "redbear-btctl --probe && redbear-btctl --status && redbear-btctl --scan && redbear-btctl --connect hci0 && redbear-btctl --read-char hci0 0000180f-0000-1000-8000-00805f9b34fb 00002a19-0000-1000-8000-00805f9b34fb", note: "Functional when the btctl scheme is enumerable and reports adapter state plus one experimental battery-sensor Battery Level read result; this still does not prove general device traffic, generic GATT, write/notify support, classic Bluetooth, or desktop integration.", functional_probe: Some(probe_btctl_surface), }, IntegrationCheck { name: "redbear-iwlwifi", category: "Drivers", description: "Bounded Intel Wi-Fi driver-side package", artifact_path: Some("/usr/lib/drivers/redbear-iwlwifi"), control_path: Some("/scheme/pci"), test_hint: "redbear-iwlwifi --probe && redbear-iwlwifi --connect demo open", note: "Functional when the Intel Wi-Fi driver package is installed and PCI inventory is accessible; bounded scan/connect actions may succeed, but this still does not prove real radio association or working connectivity.", functional_probe: Some(probe_pci_surface), }, IntegrationCheck { name: "redbear-netstat", category: "Tool", description: "Native Red Bear network status reporter", artifact_path: Some("/usr/bin/redbear-netstat"), control_path: Some("/scheme/netcfg"), test_hint: "redbear-netstat", note: "Functional when the netcfg scheme answers read-only interface, route, and resolver queries.", functional_probe: Some(probe_smolnetd_surface), }, IntegrationCheck { name: "redbear-traceroute", category: "Tool", description: "Native UDP-based path tracing utility", artifact_path: Some("/usr/bin/redbear-traceroute"), control_path: Some("/scheme/icmp"), test_hint: "redbear-traceroute 1.1.1.1", note: "Binary presence proves installation; successful hop tracing still depends on the live ICMP and UDP path in the current runtime.", functional_probe: Some(probe_icmp_surface), }, IntegrationCheck { name: "redbear-mtr", category: "Tool", description: "Native path measurement tool built on traceroute probes", artifact_path: Some("/usr/bin/redbear-mtr"), control_path: Some("/scheme/icmp"), test_hint: "redbear-mtr 1.1.1.1", note: "Binary presence proves installation; useful measurements still depend on the same live ICMP and UDP probe substrate as traceroute.", functional_probe: Some(probe_icmp_surface), }, IntegrationCheck { name: "redbear-nmap", category: "Tool", description: "Bounded TCP connect-scan utility", artifact_path: Some("/usr/bin/redbear-nmap"), control_path: Some("/scheme/netcfg"), test_hint: "redbear-nmap 127.0.0.1 22,80,443", note: "Binary presence proves the scanner is installed; successful scans still depend on live networking and reachable targets.", functional_probe: Some(probe_smolnetd_surface), }, IntegrationCheck { name: "pcid-spawner", category: "Core", description: "PCI driver autoload daemon", artifact_path: Some("/usr/bin/pcid-spawner"), control_path: Some("/scheme/pci"), test_hint: "lspci", note: "The PCI scheme proves discovery is live, but not which driver handled each device.", functional_probe: Some(probe_directory_readable), }, IntegrationCheck { name: "smolnetd", category: "Networking", description: "Native TCP/IP stack daemon", artifact_path: Some("/usr/bin/smolnetd"), control_path: Some("/scheme/netcfg"), test_hint: "redbear-info --verbose", note: "Functional when the netcfg scheme answers read-only queries.", functional_probe: Some(probe_smolnetd_surface), }, IntegrationCheck { name: "xhcid", category: "USB", description: "xHCI host-controller daemon", artifact_path: Some("/usr/lib/drivers/xhcid"), control_path: Some("/scheme"), test_hint: "lsusb", note: "Functional when at least one usb.* controller scheme is registered.", functional_probe: Some(probe_usb_surface), }, IntegrationCheck { name: "dhcpd", category: "Networking", description: "DHCP client daemon", artifact_path: Some("/usr/bin/dhcpd"), control_path: None, test_hint: "netctl start ", note: "Binary presence is observable; passive probing cannot prove the DHCP client is currently driving configuration.", functional_probe: None, }, IntegrationCheck { name: "ext4d", category: "Filesystem", description: "ext4 scheme daemon", artifact_path: Some("/usr/bin/ext4d"), control_path: Some("/scheme/ext4d"), test_hint: "ls /scheme/ext4d/", note: "Functional when the ext4 scheme directory can be enumerated.", functional_probe: Some(probe_directory_readable), }, IntegrationCheck { name: "firmware-loader", category: "System", description: "Firmware indexing and serving daemon", artifact_path: Some("/usr/bin/firmware-loader"), control_path: Some("/scheme"), test_hint: "ls /scheme/firmware/", note: "Functional when the firmware scheme is enumerable.", functional_probe: Some(probe_firmware_scheme), }, IntegrationCheck { name: "redbear-upower", category: "Power", description: "Bounded UPower-compatible power reporting daemon", artifact_path: Some("/usr/bin/redbear-upower"), control_path: Some("/scheme/acpi/power"), test_hint: "redbear-phase5-network-check", note: "Binary presence proves the daemon is installed; a live /scheme/acpi/power surface proves bounded ACPI-backed power reporting is actually available.", functional_probe: Some(probe_acpi_power_surface), }, IntegrationCheck { name: "iommu", category: "System", description: "IOMMU DMA-remapping daemon", artifact_path: Some("/usr/bin/iommu"), control_path: Some("/scheme/iommu"), test_hint: "redbear-phase-iommu-check", note: "Functional when the iommu scheme is registered in /scheme.", functional_probe: Some(probe_iommu_scheme), }, IntegrationCheck { name: "redbear-phase-ps2-check", category: "Validation", description: "Bounded PS/2 + serio runtime proof helper", artifact_path: Some("/usr/bin/redbear-phase-ps2-check"), control_path: Some("/scheme/serio/0"), test_hint: "redbear-phase-ps2-check", note: "Functional when the PS/2 proof helper is installed and both serio keyboard/mouse nodes are visible.", functional_probe: Some(probe_serio_surface), }, IntegrationCheck { name: "redbear-phase-timer-check", category: "Validation", description: "Bounded monotonic timer runtime proof helper", artifact_path: Some("/usr/bin/redbear-phase-timer-check"), control_path: Some("/scheme/time/4"), test_hint: "redbear-phase-timer-check", note: "Functional when the monotonic time scheme node is visible for bounded runtime timer proof.", functional_probe: Some(probe_time_surface), }, IntegrationCheck { name: "udev-shim", category: "System", description: "udev-compatible device enumeration shim", artifact_path: Some("/usr/bin/udev-shim"), control_path: Some("/scheme"), test_hint: "ls /scheme/udev/", note: "Functional when the udev scheme can be listed.", functional_probe: Some(probe_udev_scheme), }, IntegrationCheck { name: "evdevd", category: "Input", description: "Event-device translation daemon", artifact_path: Some("/usr/bin/evdevd"), control_path: Some("/scheme"), test_hint: "ls /scheme/evdev/", note: "Functional when event nodes are enumerable through the evdev scheme.", functional_probe: Some(probe_evdev_scheme), }, IntegrationCheck { name: "redox-drm", category: "GPU", description: "DRM/KMS scheme daemon", artifact_path: None, control_path: Some("/scheme/drm"), test_hint: "ls /scheme/drm/", note: "A live DRM scheme proves the daemon is running, not that hardware display is fully validated.", functional_probe: Some(probe_directory_readable), }, IntegrationCheck { name: "amdgpu", category: "GPU", description: "AMD GPU userspace driver library", artifact_path: Some("/usr/lib/redox/drivers/libamdgpu_dc_redox.so"), control_path: None, test_hint: "redbear-info --verbose", note: "Library presence proves packaging; runtime GPU validation still depends on actual hardware and redox-drm activity.", functional_probe: None, }, IntegrationCheck { name: "rtl8125-native-path", category: "Networking", description: "Native Realtek RTL8125 support through the rtl8168d autoload path", artifact_path: Some("/usr/lib/drivers/rtl8168d"), control_path: Some("/scheme/pci"), test_hint: "redbear-info --verbose", note: "This only becomes functional when 10ec:8125 hardware is present and a network.* scheme is live.", functional_probe: Some(probe_rtl8125_path), }, IntegrationCheck { name: "virtio-net-vm-path", category: "Networking", description: "VirtIO network support for QEMU and other virtualized baselines", artifact_path: Some("/usr/lib/drivers/virtio-netd"), control_path: Some("/scheme/pci"), test_hint: "redbear-info --verbose", note: "This becomes functional when a VirtIO NIC (1af4:1000) is present and a network.* scheme is live.", functional_probe: Some(probe_virtio_net_path), }, ]; fn main() { if let Err(err) = run() { eprintln!("redbear-info: {err}"); process::exit(1); } } fn run() -> Result<(), String> { let options = parse_args(env::args())?; if options.mode == OutputMode::Tui { #[cfg(feature = "tui")] { let runtime = Runtime::from_env(); return tui::run(&runtime).map_err(|e| format!("TUI error: {e}")); } #[cfg(not(feature = "tui"))] return Err("TUI support not compiled (enable 'tui' feature)".to_string()); } if options.mode == OutputMode::Help { print_help(); return Ok(()); } let runtime = Runtime::from_env(); if options.mode == OutputMode::Quirks { let quirks = collect_quirks(&runtime); print_quirks(&quirks, options.verbose); return Ok(()); } if options.mode == OutputMode::Probe { let result = Phase1ProbeResult { evdev_active: probe_evdev_active(), udev_active: probe_udev_active(), firmware_active: probe_firmware_active(), drm_active: probe_drm_active(), time_active: probe_time_active(), }; print_probe(&result); let all_present = result.evdev_active && result.udev_active && result.firmware_active && result.drm_active && result.time_active; if all_present { return Ok(()); } return Err("some Phase 1 services are not present".to_string()); } if options.mode == OutputMode::Boot { let timeline = collect_boot_timeline(&runtime)?; print_boot_timeline(&timeline); return Ok(()); } if options.mode == OutputMode::Device { let requested = options .device .as_deref() .ok_or_else(|| "missing device selector".to_string())?; let report = collect_device_status(&runtime, requested)?; print_device_status(&report); return Ok(()); } let report = collect_report(&runtime); if options.mode == OutputMode::Health { let health = collect_health_items(&runtime, &report); print_health_dashboard(&health); return Ok(()); } match options.mode { OutputMode::Table => print_table(&report, options.verbose), OutputMode::Json => print_json(&report), OutputMode::Test => print_tests(&report, options.verbose), OutputMode::Quirks => {} OutputMode::Probe => {} OutputMode::Boot => {} OutputMode::Device => {} OutputMode::Health => {} OutputMode::Help => {} } Ok(()) } impl Runtime { fn from_env() -> Self { Self { root: env::var_os("REDBEAR_INFO_ROOT").map(PathBuf::from), } } #[cfg(test)] fn from_root(root: PathBuf) -> Self { Self { root: Some(root) } } fn resolve(&self, absolute: &str) -> PathBuf { let trimmed = absolute.trim_start_matches('/'); match &self.root { Some(root) => root.join(trimmed), None => PathBuf::from(absolute), } } fn exists(&self, absolute: &str) -> bool { self.resolve(absolute).exists() } fn is_dir(&self, absolute: &str) -> bool { self.resolve(absolute).is_dir() } fn read_to_string(&self, absolute: &str) -> Option { fs::read_to_string(self.resolve(absolute)).ok() } fn read_dir_names(&self, absolute: &str) -> Option> { let mut names = Vec::new(); for entry in fs::read_dir(self.resolve(absolute)).ok()? { let entry = entry.ok()?; let name = entry.file_name(); let name = name.to_str()?.to_string(); names.push(name); } names.sort(); Some(names) } } fn collect_report<'a>(runtime: &Runtime) -> Report<'a> { let identity = collect_identity(runtime); let network = collect_network(runtime); let hardware = collect_hardware(runtime, &network); let integrations = INTEGRATIONS .iter() .map(|check| inspect_integration(runtime, &network, &hardware, check)) .collect(); Report { identity, network, hardware, integrations, } } fn collect_identity(runtime: &Runtime) -> IdentityReport { let os_release = runtime.read_to_string("/usr/lib/os-release"); IdentityReport { pretty_name: os_release .as_deref() .and_then(|content| parse_os_release_value(content, "PRETTY_NAME")), version_id: os_release .as_deref() .and_then(|content| parse_os_release_value(content, "VERSION_ID")), hostname: runtime .read_to_string("/etc/hostname") .map(|value| value.trim().to_string()) .filter(|value| !value.is_empty()), } } fn collect_network(runtime: &Runtime) -> NetworkReport { let network_schemes = runtime .read_dir_names("/scheme") .unwrap_or_default() .into_iter() .filter(|name| name.starts_with("network.")) .collect::>(); let dns = read_trimmed(runtime, "/scheme/netcfg/resolv/nameserver") .or_else(|| read_trimmed(runtime, "/etc/net/dns")) .filter(|value| !value.is_empty()); let default_route = read_trimmed(runtime, "/scheme/netcfg/route/list") .and_then(|routes| parse_default_route(&routes)); let active_profile = read_trimmed(runtime, "/etc/netctl/active").filter(|value| !value.is_empty()); let active_interface = active_profile .as_deref() .and_then(|profile| active_profile_interface(runtime, profile)); let preferred_interface = active_interface.clone().or_else(|| { runtime .exists("/scheme/netcfg/ifaces/eth0/mac") .then_some("eth0".to_string()) }); let mac = preferred_interface.as_ref().and_then(|iface| { read_trimmed(runtime, &format!("/scheme/netcfg/ifaces/{iface}/mac")) .filter(|value| !matches!(value.as_str(), "Not configured" | "Device not found")) }); let address = preferred_interface.as_ref().and_then(|iface| { read_trimmed(runtime, &format!("/scheme/netcfg/ifaces/{iface}/addr/list")) .filter(|value| !matches!(value.as_str(), "Not configured" | "Device not found")) }); let wifi_interfaces = runtime .read_dir_names("/scheme/wifictl/ifaces") .or_else(|| { runtime .read_to_string("/scheme/wifictl/ifaces") .map(|value| { value .lines() .map(str::trim) .filter(|line| !line.is_empty()) .map(str::to_string) .collect::>() }) }) .unwrap_or_default(); let wifi_control_state = if runtime.exists("/scheme/wifictl") { if wifi_interfaces.is_empty() { ProbeState::Active } else { ProbeState::Functional } } else if runtime.exists("/usr/bin/redbear-wifictl") { ProbeState::Present } else { ProbeState::Absent }; let wifi_primary = wifi_interfaces.first().cloned(); let wifi_firmware_status = wifi_primary.as_ref().and_then(|iface| { read_trimmed( runtime, &format!("/scheme/wifictl/ifaces/{iface}/firmware-status"), ) }); let wifi_transport_status = wifi_primary.as_ref().and_then(|iface| { read_trimmed( runtime, &format!("/scheme/wifictl/ifaces/{iface}/transport-status"), ) }); let wifi_transport_init_status = wifi_primary.as_ref().and_then(|iface| { read_trimmed( runtime, &format!("/scheme/wifictl/ifaces/{iface}/transport-init-status"), ) }); let wifi_activation_status = wifi_primary.as_ref().and_then(|iface| { read_trimmed( runtime, &format!("/scheme/wifictl/ifaces/{iface}/activation-status"), ) }); let wifi_connect_result = wifi_primary.as_ref().and_then(|iface| { read_trimmed( runtime, &format!("/scheme/wifictl/ifaces/{iface}/connect-result"), ) }); let wifi_disconnect_result = wifi_primary.as_ref().and_then(|iface| { read_trimmed( runtime, &format!("/scheme/wifictl/ifaces/{iface}/disconnect-result"), ) }); let wifi_scan_results = wifi_primary .as_ref() .and_then(|iface| { runtime .read_to_string(&format!("/scheme/wifictl/ifaces/{iface}/scan-results")) .map(|value| { value .lines() .map(str::trim) .filter(|line| !line.is_empty()) .map(str::to_string) .collect::>() }) }) .unwrap_or_default(); let bluetooth_adapters = runtime .read_dir_names("/scheme/btctl/adapters") .or_else(|| { runtime .read_to_string("/scheme/btctl/adapters") .map(|value| { value .lines() .map(str::trim) .filter(|line| !line.is_empty()) .map(str::to_string) .collect::>() }) }) .unwrap_or_default(); let bluetooth_transport_runtime_visible = read_trimmed(runtime, "/var/run/redbear-btusb/status") .map(|_| bluetooth_status_is_fresh(runtime, "/var/run/redbear-btusb/status")) .unwrap_or(false); let bluetooth_transport_state = if bluetooth_transport_runtime_visible { ProbeState::Active } else if runtime.exists("/usr/bin/redbear-btusb") { ProbeState::Present } else { ProbeState::Absent }; let bluetooth_control_state = if runtime.exists("/scheme/btctl") { if bluetooth_adapters.is_empty() { ProbeState::Active } else { ProbeState::Functional } } else if runtime.exists("/usr/bin/redbear-btctl") { ProbeState::Present } else { ProbeState::Absent }; let bluetooth_primary = bluetooth_adapters.first().cloned(); let bluetooth_transport_status = if bluetooth_transport_runtime_visible { read_compact(runtime, "/var/run/redbear-btusb/status") } else { bluetooth_primary .as_ref() .and_then(|adapter| { read_compact( runtime, &format!("/scheme/btctl/adapters/{adapter}/transport-status"), ) }) .or_else(|| { runtime.exists("/usr/bin/redbear-btusb").then_some( "transport=usb startup=explicit runtime_visibility=installed-only".to_string(), ) }) }; let bluetooth_adapter_status = bluetooth_primary.as_ref().and_then(|adapter| { read_compact(runtime, &format!("/scheme/btctl/adapters/{adapter}/status")) }); let bluetooth_scan_results = bluetooth_primary .as_ref() .and_then(|adapter| { runtime .read_to_string(&format!("/scheme/btctl/adapters/{adapter}/scan-results")) .map(|value| { value .lines() .map(str::trim) .filter(|line| !line.is_empty()) .map(str::to_string) .collect::>() }) }) .unwrap_or_default(); let bluetooth_connection_state = bluetooth_primary.as_ref().and_then(|adapter| { read_compact( runtime, &format!("/scheme/btctl/adapters/{adapter}/connection-state"), ) }); let bluetooth_connect_result = bluetooth_primary.as_ref().and_then(|adapter| { read_trimmed( runtime, &format!("/scheme/btctl/adapters/{adapter}/connect-result"), ) }); let bluetooth_disconnect_result = bluetooth_primary.as_ref().and_then(|adapter| { read_trimmed( runtime, &format!("/scheme/btctl/adapters/{adapter}/disconnect-result"), ) }); let bluetooth_read_char_result = bluetooth_primary.as_ref().and_then(|adapter| { read_trimmed( runtime, &format!("/scheme/btctl/adapters/{adapter}/read-char-result"), ) }); let bluetooth_bond_store_path = bluetooth_primary.as_ref().and_then(|adapter| { read_trimmed( runtime, &format!("/scheme/btctl/adapters/{adapter}/bond-store-path"), ) .or_else(|| { let path = format!("/var/lib/bluetooth/{adapter}/bonds"); runtime.exists(&path).then_some(path) }) }); let bluetooth_bond_count = bluetooth_primary.as_ref().and_then(|adapter| { read_compact( runtime, &format!("/scheme/btctl/adapters/{adapter}/bond-count"), ) .and_then(|content| parse_compact_key_value(&content, "bond_count")) .and_then(|value| value.parse::().ok()) .or_else(|| { let path = format!("/var/lib/bluetooth/{adapter}/bonds"); runtime.read_dir_names(&path).map(|entries| entries.len()) }) }); let state = if runtime.exists("/scheme/netcfg") { if address.is_some() { ProbeState::Functional } else { ProbeState::Active } } else if runtime.exists("/usr/bin/smolnetd") { ProbeState::Present } else { ProbeState::Absent }; NetworkReport { state, connected: address.is_some(), interface: preferred_interface, mac, address, dns, default_route, active_profile, network_schemes, wifi_control_state, wifi_interfaces, wifi_firmware_status, wifi_transport_status, wifi_transport_init_status, wifi_activation_status, wifi_connect_result, wifi_disconnect_result, wifi_scan_results, claim_limit: "Connected means the local stack exposes a configured address; this does not prove external reachability.", bluetooth_transport_state, bluetooth_control_state, bluetooth_adapters, bluetooth_transport_status, bluetooth_adapter_status, bluetooth_scan_results, bluetooth_connection_state, bluetooth_connect_result, bluetooth_disconnect_result, bluetooth_read_char_result, bluetooth_bond_store_path, bluetooth_bond_count, bluetooth_claim_limit: "Runtime-visible Bluetooth control evidence means the explicit-startup btusb/btctl surfaces, stub bond files, bounded connect/disconnect metadata, and one experimental battery-sensor Battery Level read result can be observed; this does not prove controller bring-up, general device traffic, generic GATT, real pairing, validated reconnect semantics, write support, or notify support beyond the experimental battery-sensor read-only workload.", } } fn active_profile_interface(runtime: &Runtime, profile: &str) -> Option { let content = runtime.read_to_string(&format!("/etc/netctl/{profile}"))?; content.lines().find_map(|line| { let line = line.trim(); let (key, value) = line.split_once('=')?; (key.trim() == "Interface").then(|| parse_profile_scalar(value.trim())) }) } fn parse_profile_scalar(value: &str) -> String { value .trim() .trim_start_matches('(') .trim_end_matches(')') .trim() .trim_matches('"') .trim_matches('\'') .to_string() } fn collect_hardware(runtime: &Runtime, network: &NetworkReport) -> HardwareReport { let pci_entries = runtime.read_dir_names("/scheme/pci").unwrap_or_default(); let pci_devices = pci_entries .iter() .filter(|entry| entry.contains("--") && entry.contains('.')) .count(); let mut pci_irq_none = 0; let mut pci_irq_legacy = 0; let mut pci_irq_msi = 0; let mut pci_irq_msix = 0; let mut pci_irq_forced_legacy = 0; let mut pci_irq_msix_disabled_by_quirk = 0; let mut pci_irq_msi_disabled_by_quirk = 0; let mut rtl8125_present_from_pci = false; let usb_controllers = runtime .read_dir_names("/scheme") .unwrap_or_default() .into_iter() .filter(|name| name.starts_with("usb.")) .count(); let drm_cards = runtime .read_dir_names("/scheme/drm") .unwrap_or_default() .into_iter() .filter(|name| name.starts_with("card")) .count(); let runtime_irq_reports = collect_irq_runtime_reports(runtime); let acpi_power_surface_present = runtime.exists("/scheme/acpi/power"); for entry in &pci_entries { let config_path = format!("/scheme/pci/{entry}/config"); let Some(bytes) = read_prefix_bytes(runtime, &config_path, 64) else { continue; }; if bytes.len() < 64 { continue; } if let Some(location) = parse_scheme_pci_location(entry) { if let Some(info) = parse_device_info_from_config_space(location, &bytes) { match info.interrupt_support() { InterruptSupport::None => pci_irq_none += 1, InterruptSupport::LegacyOnly => pci_irq_legacy += 1, InterruptSupport::Msi => pci_irq_msi += 1, InterruptSupport::MsiX => pci_irq_msix += 1, } let quirk_flags = lookup_pci_quirks(&info); if quirk_flags.contains(PciQuirkFlags::FORCE_LEGACY_IRQ) { pci_irq_forced_legacy += 1; } if quirk_flags.contains(PciQuirkFlags::NO_MSIX) { pci_irq_msix_disabled_by_quirk += 1; } if quirk_flags.contains(PciQuirkFlags::NO_MSI) { pci_irq_msi_disabled_by_quirk += 1; } rtl8125_present_from_pci |= info.vendor_id == RTL8125_VENDOR_ID && info.device_id == RTL8125_DEVICE_ID; } } } let rtl8125_present = rtl8125_present_from_pci || network .network_schemes .iter() .any(|name| name.contains("rtl8125")); let virtio_net_present = runtime .read_dir_names("/scheme/pci") .unwrap_or_default() .into_iter() .any(|entry| { let config_path = format!("/scheme/pci/{entry}/config"); let Some(bytes) = read_prefix_bytes(runtime, &config_path, 4) else { return false; }; if bytes.len() < 4 { return false; } let vendor = u16::from_le_bytes([bytes[0], bytes[1]]); let device = u16::from_le_bytes([bytes[2], bytes[3]]); vendor == VIRTIO_NET_VENDOR_ID && device == VIRTIO_NET_DEVICE_ID }) || network .network_schemes .iter() .any(|name| name.contains("virtio") || name.contains("eth0")); HardwareReport { pci_devices, pci_irq_none, pci_irq_legacy, pci_irq_msi, pci_irq_msix, pci_irq_forced_legacy, pci_irq_msix_disabled_by_quirk, pci_irq_msi_disabled_by_quirk, runtime_irq_reports, usb_controllers, drm_cards, acpi_power_surface_present, rtl8125_present, virtio_net_present, } } fn parse_scheme_pci_location(entry: &str) -> Option { let (segment, rest) = entry.split_once("--")?; let (bus, rest) = rest.split_once("--")?; let (device, function) = rest.split_once('.')?; Some(redox_driver_sys::pci::PciLocation { segment: u16::from_str_radix(segment, 16).ok()?, bus: u8::from_str_radix(bus, 16).ok()?, device: u8::from_str_radix(device, 16).ok()?, function: function.parse().ok()?, }) } fn collect_irq_runtime_reports(runtime: &Runtime) -> Vec { let mut reports = Vec::new(); let mut seen = std::collections::BTreeSet::new(); for dir in [ "/tmp/redbear-irq-report", "/tmp/run/redbear-irq-report", "/run/redbear-irq-report", "/var/run/redbear-irq-report", "/scheme/initfs/tmp/redbear-irq-report", "/scheme/initfs/tmp/run/redbear-irq-report", "/scheme/initfs/run/redbear-irq-report", "/scheme/initfs/var/run/redbear-irq-report", ] { let entries = runtime.read_dir_names(dir).unwrap_or_default(); for name in entries.into_iter().filter(|name| name.ends_with(".env")) { let path = format!("{dir}/{name}"); if !seen.insert(path.clone()) { continue; } let Some(content) = runtime.read_to_string(&path) else { continue; }; let mut driver = None; let mut pid = None; let mut device = None; let mut mode = None; let mut reason = None; for line in content.lines() { let Some((key, value)) = line.split_once('=') else { continue; }; match key.trim() { "driver" => driver = Some(value.trim().to_string()), "pid" => pid = value.trim().parse::().ok(), "device" => device = Some(value.trim().to_string()), "mode" => mode = Some(value.trim().to_string()), "reason" => reason = Some(value.trim().to_string()), _ => {} } } if let (Some(driver), Some(pid), Some(device), Some(mode), Some(reason)) = (driver, pid, device, mode, reason) { if !runtime.exists(&format!("/proc/{pid}")) { continue; } reports.push(IrqRuntimeReport { driver, pid, device, mode, reason, }); } } } reports.sort_by(|left, right| { left.driver .cmp(&right.driver) .then(left.device.cmp(&right.device)) }); reports } fn collect_quirks(runtime: &Runtime) -> QuirksReport { let mut files_loaded = Vec::new(); let mut load_errors = Vec::new(); let entries = match runtime.read_dir_names("/etc/quirks.d") { Some(entries) => entries, None => { return QuirksReport { files_loaded, load_errors: vec!["quirks directory not found".to_string()], }; } }; for name in entries.into_iter().filter(|name| name.ends_with(".toml")) { let path = format!("/etc/quirks.d/{name}"); match runtime.read_to_string(&path) { Some(content) => match parse_quirk_toml(&name, &content) { Ok(file_quirks) => files_loaded.push(file_quirks), Err(err) => load_errors.push(format!("{name}: {err}")), }, None => load_errors.push(format!("{name}: read error")), } } QuirksReport { files_loaded, load_errors, } } #[derive(Debug)] struct Phase1ProbeResult { evdev_active: bool, udev_active: bool, firmware_active: bool, drm_active: bool, time_active: bool, } #[cfg(target_os = "redox")] fn probe_evdev_active() -> bool { std::fs::read_dir("/scheme/") .map(|mut entries| { entries.any(|entry| { entry.map_or(false, |entry| { entry.file_name().to_string_lossy().starts_with("evdev") }) }) }) .unwrap_or(false) } #[cfg(not(target_os = "redox"))] fn probe_evdev_active() -> bool { false } #[cfg(target_os = "redox")] fn probe_udev_active() -> bool { std::fs::read_dir("/scheme/") .map(|mut entries| { entries.any(|entry| { entry.map_or(false, |entry| entry.file_name().to_string_lossy() == "udev") }) }) .unwrap_or(false) } #[cfg(not(target_os = "redox"))] fn probe_udev_active() -> bool { false } #[cfg(target_os = "redox")] fn probe_firmware_active() -> bool { std::fs::read_dir("/scheme/") .map(|mut entries| { entries.any(|entry| { entry.map_or(false, |entry| { entry.file_name().to_string_lossy() == "firmware" }) }) }) .unwrap_or(false) } #[cfg(not(target_os = "redox"))] fn probe_firmware_active() -> bool { false } #[cfg(target_os = "redox")] fn probe_drm_active() -> bool { std::fs::read_dir("/scheme/") .map(|mut entries| { entries.any(|entry| { entry.map_or(false, |entry| entry.file_name().to_string_lossy() == "drm") }) }) .unwrap_or(false) } #[cfg(not(target_os = "redox"))] fn probe_drm_active() -> bool { false } #[cfg(target_os = "redox")] fn probe_time_active() -> bool { std::path::Path::new("/scheme/time").exists() } #[cfg(not(target_os = "redox"))] fn probe_time_active() -> bool { false } fn print_probe(result: &Phase1ProbeResult) { let mark = |present: bool| if present { "✓ PRESENT" } else { "✗ ABSENT" }; println!("Phase 1 Service Probes:"); println!(" evdevd {}", mark(result.evdev_active)); println!(" udev-shim {}", mark(result.udev_active)); println!(" firmware {}", mark(result.firmware_active)); println!(" drm {}", mark(result.drm_active)); println!(" time {}", mark(result.time_active)); let all = result.evdev_active && result.udev_active && result.firmware_active && result.drm_active && result.time_active; let most = result.evdev_active as u8 + result.udev_active as u8 + result.firmware_active as u8 + result.drm_active as u8 + result.time_active as u8; println!(); if all { println!("ALL PHASE 1 SERVICES PRESENT"); } else if most >= 3 { println!("MOSTLY PRESENT, SOME GAPS ({}/5)", most); } else { println!("SIGNIFICANT GAPS REMAIN ({}/5)", most); } } fn parse_quirk_toml(name: &str, content: &str) -> Result { let document: Value = content .parse() .map_err(|err| format!("parse error: {err}"))?; let table = document .as_table() .ok_or_else(|| "top-level document is not a table".to_string())?; let mut file_quirks = QuirkFile { name: name.to_string(), pci_quirks: Vec::new(), usb_quirks: Vec::new(), dmi_quirk_count: 0, }; if let Some(entries) = table.get("pci_quirk").and_then(Value::as_array) { for entry in entries { if let Some(quirk) = parse_pci_quirk(entry) { file_quirks.pci_quirks.push(quirk); } } } if let Some(entries) = table.get("usb_quirk").and_then(Value::as_array) { for entry in entries { if let Some(quirk) = parse_usb_quirk(entry) { file_quirks.usb_quirks.push(quirk); } } } if let Some(entries) = table.get("dmi_system_quirk").and_then(Value::as_array) { file_quirks.dmi_quirk_count = entries.len(); } Ok(file_quirks) } fn parse_pci_quirk(entry: &Value) -> Option { let table = entry.as_table()?; let vendor = table.get("vendor").and_then(|value| format_hex(value, 4))?; let device = table.get("device").and_then(|value| format_hex(value, 4)); let class = table.get("class").and_then(|value| format_hex(value, 6)); let flags = table.get("flags").and_then(parse_string_array)?; let description = table .get("description") .and_then(Value::as_str) .map(str::to_string); Some(QuirkEntry { vendor, device, class, flags, description, }) } fn parse_usb_quirk(entry: &Value) -> Option { let table = entry.as_table()?; let vendor = table.get("vendor").and_then(|value| format_hex(value, 4))?; let product = table.get("product").and_then(|value| format_hex(value, 4)); let flags = table.get("flags").and_then(parse_string_array)?; Some(UsbQuirkEntry { vendor, product, flags, }) } fn format_hex(value: &Value, width: usize) -> Option { let raw = u64::try_from(value.as_integer()?).ok()?; Some(format!("0x{raw:0width$X}", width = width)) } fn parse_string_array(value: &Value) -> Option> { value.as_array().map(|items| { items .iter() .filter_map(Value::as_str) .map(str::to_string) .collect() }) } fn inspect_integration<'a>( runtime: &Runtime, network: &NetworkReport, hardware: &HardwareReport, check: &'a IntegrationCheck, ) -> IntegrationStatus<'a> { let artifact_present = check.artifact_path.map(|path| runtime.exists(path)); let control_present = check .control_path .map(|path| control_surface_present(runtime, check, path)); let mut evidence = Vec::new(); if let Some(path) = check.artifact_path { evidence.push(format!( "artifact {} {}", path, if artifact_present == Some(true) { "present" } else { "missing" } )); } if let Some(path) = check.control_path { evidence.push(format!( "control {} {}", path, if control_present == Some(true) { "present" } else { "missing" } )); } let state = if let Some(probe) = check.functional_probe { match probe(runtime, network, hardware, check) { Some(message) => { evidence.push(message); if artifact_present == Some(false) { ProbeState::Active } else { ProbeState::Functional } } None => { if check.name == "redbear-btctl" && control_present == Some(true) { ProbeState::Active } else { derive_state(artifact_present, control_present) } } } } else { derive_state(artifact_present, control_present) }; IntegrationStatus { check, state, artifact_present, control_present, evidence, claim_limit: check.note, } } fn derive_state(artifact_present: Option, control_present: Option) -> ProbeState { if control_present == Some(true) && artifact_present != Some(false) { ProbeState::Active } else if artifact_present == Some(true) { ProbeState::Present } else if artifact_present.is_none() && control_present.is_none() { ProbeState::Unobservable } else { ProbeState::Absent } } fn control_surface_present(runtime: &Runtime, check: &IntegrationCheck, path: &str) -> bool { if check.name == "redbear-btusb" { runtime.exists(path) && bluetooth_status_is_fresh(runtime, path) } else { runtime.exists(path) } } fn output_mode_flag(mode: OutputMode) -> &'static str { match mode { OutputMode::Table => "table output", OutputMode::Json => "--json", OutputMode::Test => "--test", OutputMode::Quirks => "--quirks", OutputMode::Probe => "--probe", OutputMode::Boot => "--boot", OutputMode::Device => "--device", OutputMode::Health => "--health", OutputMode::Help => "--help", } } fn set_output_mode( mode: &mut OutputMode, next_mode: OutputMode, next_flag: &str, ) -> Result<(), String> { if matches!(*mode, OutputMode::Table | OutputMode::Help) { *mode = next_mode; Ok(()) } else { Err(format!( "cannot combine {next_flag} with {}", output_mode_flag(*mode) )) } } fn parse_args(args: I) -> Result where I: IntoIterator, { let mut mode = OutputMode::Table; let mut verbose = false; let mut device = None; let mut args = args.into_iter().skip(1).peekable(); while let Some(arg) = args.next() { match arg.as_str() { "-v" | "--verbose" => verbose = true, "-i" | "--interactive" => set_output_mode(&mut mode, OutputMode::Tui, "-i")?, "--json" => set_output_mode(&mut mode, OutputMode::Json, "--json")?, "--test" => set_output_mode(&mut mode, OutputMode::Test, "--test")?, "--quirks" => set_output_mode(&mut mode, OutputMode::Quirks, "--quirks")?, "--probe" => set_output_mode(&mut mode, OutputMode::Probe, "--probe")?, "--boot" => set_output_mode(&mut mode, OutputMode::Boot, "--boot")?, "--health" => set_output_mode(&mut mode, OutputMode::Health, "--health")?, "--device" => { set_output_mode(&mut mode, OutputMode::Device, "--device")?; let Some(value) = args.next() else { return Err("--device requires a PCI address".to_string()); }; if value.starts_with('-') { return Err("--device requires a PCI address".to_string()); } device = Some(value); } "-h" | "--help" => mode = OutputMode::Help, _ => return Err(format!("unknown argument: {arg}")), } } Ok(Options { mode, verbose, device, }) } fn print_table(report: &Report<'_>, verbose: bool) { println!("Red Bear OS Runtime Integration Report"); println!("{DIVIDER}"); println!(); print_section_header("Identity"); println!( " OS: {}", display_or_unknown(report.identity.pretty_name.as_deref()) ); println!( " Version: {}", display_or_unknown(report.identity.version_id.as_deref()) ); println!( " Hostname: {}", display_or_unknown(report.identity.hostname.as_deref()) ); println!(); print_section_header("Networking"); println!( " Stack: {} {}", colorize( state_marker(report.network.state), state_color(report.network.state) ), state_label(report.network.state) ); println!( " Connected: {}", if report.network.connected { "yes" } else { "no" } ); println!( " Interface: {}", display_or_unknown(report.network.interface.as_deref()) ); println!( " MAC: {}", display_or_unknown(report.network.mac.as_deref()) ); println!( " Address: {}", display_or_unknown(report.network.address.as_deref()) ); println!( " DNS: {}", display_or_unknown(report.network.dns.as_deref()) ); println!( " Default route: {}", display_or_unknown(report.network.default_route.as_deref()) ); println!( " Active profile: {}", display_or_unknown(report.network.active_profile.as_deref()) ); println!( " Network schemes: {}", if report.network.network_schemes.is_empty() { "none".to_string() } else { report.network.network_schemes.join(", ") } ); println!( " Wi-Fi control: {}{}{}", state_marker(report.network.wifi_control_state), state_color(report.network.wifi_control_state), state_label(report.network.wifi_control_state) ); println!( " Wi-Fi interfaces: {}", if report.network.wifi_interfaces.is_empty() { "none".to_string() } else { report.network.wifi_interfaces.join(", ") } ); println!( " Wi-Fi firmware: {}", display_or_unknown(report.network.wifi_firmware_status.as_deref()) ); println!( " Wi-Fi transport: {}", display_or_unknown(report.network.wifi_transport_status.as_deref()) ); println!( " Wi-Fi transport init: {}", display_or_unknown(report.network.wifi_transport_init_status.as_deref()) ); println!( " Wi-Fi activation: {}", display_or_unknown(report.network.wifi_activation_status.as_deref()) ); println!( " Wi-Fi connect result: {}", display_or_unknown(report.network.wifi_connect_result.as_deref()) ); println!( " Wi-Fi disconnect result: {}", display_or_unknown(report.network.wifi_disconnect_result.as_deref()) ); println!( " Wi-Fi scan results: {}", if report.network.wifi_scan_results.is_empty() { "none".to_string() } else { report.network.wifi_scan_results.join(", ") } ); println!( " Bluetooth transport: {}{}{}", state_marker(report.network.bluetooth_transport_state), state_color(report.network.bluetooth_transport_state), state_label(report.network.bluetooth_transport_state) ); println!( " Bluetooth control: {}{}{}", state_marker(report.network.bluetooth_control_state), state_color(report.network.bluetooth_control_state), state_label(report.network.bluetooth_control_state) ); println!( " Bluetooth adapters: {}", if report.network.bluetooth_adapters.is_empty() { "none".to_string() } else { report.network.bluetooth_adapters.join(", ") } ); println!( " Bluetooth status: {}", display_or_unknown(report.network.bluetooth_adapter_status.as_deref()) ); println!( " Bluetooth transport status: {}", display_or_unknown(report.network.bluetooth_transport_status.as_deref()) ); println!( " Bluetooth scan results: {}", if report.network.bluetooth_scan_results.is_empty() { "none".to_string() } else { report.network.bluetooth_scan_results.join(", ") } ); println!( " Bluetooth connection state: {}", display_or_unknown(report.network.bluetooth_connection_state.as_deref()) ); println!( " Bluetooth connect result: {}", display_or_unknown(report.network.bluetooth_connect_result.as_deref()) ); println!( " Bluetooth disconnect result: {}", display_or_unknown(report.network.bluetooth_disconnect_result.as_deref()) ); println!( " Bluetooth experimental BLE read: {}", display_or_unknown(report.network.bluetooth_read_char_result.as_deref()) ); println!( " Bluetooth bond store: {}", report .network .bluetooth_bond_store_path .as_deref() .unwrap_or("none") ); println!( " Bluetooth bond count: {}", report .network .bluetooth_bond_count .map(|count| count.to_string()) .unwrap_or_else(|| "unknown".to_string()) ); if verbose { println!(" Network note: {}", report.network.claim_limit); println!(" Bluetooth note: {}", report.network.bluetooth_claim_limit); } println!(); print_section_header("Hardware"); println!(" PCI devices: {}", report.hardware.pci_devices); println!( " PCI IRQ support: none={} legacy={} msi={} msix={}", report.hardware.pci_irq_none, report.hardware.pci_irq_legacy, report.hardware.pci_irq_msi, report.hardware.pci_irq_msix, ); println!( " PCI IRQ quirk pressure: force_legacy={} no_msix={} no_msi={}", report.hardware.pci_irq_forced_legacy, report.hardware.pci_irq_msix_disabled_by_quirk, report.hardware.pci_irq_msi_disabled_by_quirk, ); if !report.hardware.runtime_irq_reports.is_empty() { println!(" PCI IRQ runtime modes:"); for item in &report.hardware.runtime_irq_reports { println!( " {} pid={} {} mode={} reason={}", item.driver, item.pid, item.device, item.mode, item.reason ); } } println!(" USB controllers: {}", report.hardware.usb_controllers); println!(" DRM cards: {}", report.hardware.drm_cards); println!( " ACPI power surface: {}", if report.hardware.acpi_power_surface_present { "present" } else { "unavailable" } ); println!( " RTL8125 device seen: {}", if report.hardware.rtl8125_present { "yes" } else { "no" } ); println!( " VirtIO NIC seen: {}", if report.hardware.virtio_net_present { "yes" } else { "no" } ); println!(); print_section_header("Integrations"); for integration in &report.integrations { println!( " {} {:<18} [{}] {}", colorize( state_marker(integration.state), state_color(integration.state) ), integration.check.name, integration.check.category, state_label(integration.state) ); println!(" {}", integration.check.description); println!(" Test: {}", integration.check.test_hint); if verbose { for line in &integration.evidence { println!(" Evidence: {line}"); } println!(" Claim limit: {}", integration.claim_limit); } println!(); } println!("{DIVIDER}"); println!( "functional={} active={} present={} absent={} total={}", count_state(&report.integrations, ProbeState::Functional), count_state(&report.integrations, ProbeState::Active), count_state(&report.integrations, ProbeState::Present), count_state(&report.integrations, ProbeState::Absent), report.integrations.len() ); } fn print_quirks(report: &QuirksReport, verbose: bool) { println!("Red Bear OS Hardware Quirks Configuration"); println!("{DIVIDER}"); println!(); if report.files_loaded.is_empty() && report .load_errors .iter() .any(|error| error.contains("quirks directory not found")) { println!(" Quirks directory: {}not found{}", YELLOW, RESET); return; } println!(" Files loaded: {}", report.files_loaded.len()); for file in &report.files_loaded { println!(); print_section_header(&format!("Quirks: {}", file.name)); if file.pci_quirks.is_empty() && file.usb_quirks.is_empty() && file.dmi_quirk_count == 0 { println!(" (no entries)"); continue; } println!( " {:<4} {:<8} {:<18} {}", "Type", "Vendor", "Match", "Flags" ); for quirk in &file.pci_quirks { let selector = quirk .device .as_deref() .map(|device| format!("device={device}")) .or_else(|| quirk.class.as_deref().map(|class| format!("class={class}"))) .unwrap_or_else(|| "match=unknown".to_string()); println!( " {:<4} {:<8} {:<18} {}", "PCI", quirk.vendor, selector, quirk.flags.join(", ") ); if verbose && let Some(description) = &quirk.description { println!(" Description: {description}"); } } for quirk in &file.usb_quirks { let selector = quirk .product .as_deref() .map(|p| format!("product={p}")) .unwrap_or_else(|| "match=any".to_string()); println!( " {:<4} {:<8} {:<18} {}", "USB", quirk.vendor, selector, quirk.flags.join(", ") ); } if file.dmi_quirk_count > 0 { println!( " DMI: {} system rule(s) configured (runtime application uses acpid /scheme/acpi/dmi)", file.dmi_quirk_count ); } } for error in &report.load_errors { println!(" {}Error: {}{}", RED, error, RESET); } } fn print_tests(report: &Report<'_>, verbose: bool) { println!("Red Bear OS Runtime Test Hints"); println!("{DIVIDER}"); println!(); println!(" redbear-info --json"); println!(" redbear-info --verbose"); println!(" redbear-info --boot"); println!(" redbear-info --health"); println!(" netctl status"); println!(" lspci"); println!(" lsusb"); println!(); for integration in report .integrations .iter() .filter(|integration| integration.state != ProbeState::Absent) { println!( " {:<18} {}", integration.check.name, integration.check.test_hint ); if verbose { println!(" {}", integration.claim_limit); } } println!(); println!("Network interpretation: {}", report.network.claim_limit); } fn print_json(report: &Report<'_>) { let mut out = String::new(); out.push_str("{\n"); out.push_str(" \"identity\": {\n"); push_json_field( &mut out, "pretty_name", report.identity.pretty_name.as_deref(), true, 4, ); push_json_field( &mut out, "version_id", report.identity.version_id.as_deref(), true, 4, ); push_json_field( &mut out, "hostname", report.identity.hostname.as_deref(), false, 4, ); out.push_str(" },\n"); out.push_str(" \"network\": {\n"); push_json_string_field( &mut out, "state", state_label(report.network.state), true, 4, ); push_json_bool_field(&mut out, "connected", report.network.connected, true, 4); push_json_field( &mut out, "interface", report.network.interface.as_deref(), true, 4, ); push_json_field(&mut out, "mac", report.network.mac.as_deref(), true, 4); push_json_field( &mut out, "address", report.network.address.as_deref(), true, 4, ); push_json_field(&mut out, "dns", report.network.dns.as_deref(), true, 4); push_json_field( &mut out, "default_route", report.network.default_route.as_deref(), true, 4, ); push_json_field( &mut out, "active_profile", report.network.active_profile.as_deref(), true, 4, ); push_json_string_array_field( &mut out, "network_schemes", &report.network.network_schemes, true, 4, ); push_json_string_field( &mut out, "wifi_control_state", state_label(report.network.wifi_control_state), true, 4, ); push_json_string_array_field( &mut out, "wifi_interfaces", &report.network.wifi_interfaces, true, 4, ); push_json_field( &mut out, "wifi_firmware_status", report.network.wifi_firmware_status.as_deref(), true, 4, ); push_json_field( &mut out, "wifi_transport_status", report.network.wifi_transport_status.as_deref(), true, 4, ); push_json_field( &mut out, "wifi_transport_init_status", report.network.wifi_transport_init_status.as_deref(), true, 4, ); push_json_field( &mut out, "wifi_activation_status", report.network.wifi_activation_status.as_deref(), true, 4, ); push_json_field( &mut out, "wifi_connect_result", report.network.wifi_connect_result.as_deref(), true, 4, ); push_json_field( &mut out, "wifi_disconnect_result", report.network.wifi_disconnect_result.as_deref(), true, 4, ); push_json_string_array_field( &mut out, "wifi_scan_results", &report.network.wifi_scan_results, true, 4, ); push_json_string_field(&mut out, "claim_limit", report.network.claim_limit, true, 4); push_json_string_field( &mut out, "bluetooth_transport_state", state_label(report.network.bluetooth_transport_state), true, 4, ); push_json_string_field( &mut out, "bluetooth_control_state", state_label(report.network.bluetooth_control_state), true, 4, ); push_json_string_array_field( &mut out, "bluetooth_adapters", &report.network.bluetooth_adapters, true, 4, ); push_json_field( &mut out, "bluetooth_transport_status", report.network.bluetooth_transport_status.as_deref(), true, 4, ); push_json_field( &mut out, "bluetooth_adapter_status", report.network.bluetooth_adapter_status.as_deref(), true, 4, ); push_json_string_array_field( &mut out, "bluetooth_scan_results", &report.network.bluetooth_scan_results, true, 4, ); push_json_field( &mut out, "bluetooth_connection_state", report.network.bluetooth_connection_state.as_deref(), true, 4, ); push_json_field( &mut out, "bluetooth_connect_result", report.network.bluetooth_connect_result.as_deref(), true, 4, ); push_json_field( &mut out, "bluetooth_disconnect_result", report.network.bluetooth_disconnect_result.as_deref(), true, 4, ); push_json_field( &mut out, "bluetooth_read_char_result", report.network.bluetooth_read_char_result.as_deref(), true, 4, ); push_json_field( &mut out, "bluetooth_bond_store_path", report.network.bluetooth_bond_store_path.as_deref(), true, 4, ); push_json_optional_number_field( &mut out, "bluetooth_bond_count", report.network.bluetooth_bond_count, true, 4, ); push_json_string_field( &mut out, "bluetooth_claim_limit", report.network.bluetooth_claim_limit, false, 4, ); out.push_str(" },\n"); out.push_str(" \"hardware\": {\n"); push_json_number_field( &mut out, "pci_devices", report.hardware.pci_devices, true, 4, ); push_json_number_field( &mut out, "pci_irq_none", report.hardware.pci_irq_none, true, 4, ); push_json_number_field( &mut out, "pci_irq_legacy", report.hardware.pci_irq_legacy, true, 4, ); push_json_number_field( &mut out, "pci_irq_msi", report.hardware.pci_irq_msi, true, 4, ); push_json_number_field( &mut out, "pci_irq_msix", report.hardware.pci_irq_msix, true, 4, ); push_json_number_field( &mut out, "pci_irq_forced_legacy", report.hardware.pci_irq_forced_legacy, true, 4, ); push_json_number_field( &mut out, "pci_irq_msix_disabled_by_quirk", report.hardware.pci_irq_msix_disabled_by_quirk, true, 4, ); push_json_number_field( &mut out, "pci_irq_msi_disabled_by_quirk", report.hardware.pci_irq_msi_disabled_by_quirk, true, 4, ); out.push_str(" \"runtime_irq_reports\": [\n"); for (index, item) in report.hardware.runtime_irq_reports.iter().enumerate() { out.push_str(" {\n"); push_json_string_field(&mut out, "driver", &item.driver, true, 8); push_json_number_field(&mut out, "pid", item.pid as usize, true, 8); push_json_string_field(&mut out, "device", &item.device, true, 8); push_json_string_field(&mut out, "mode", &item.mode, true, 8); push_json_string_field(&mut out, "reason", &item.reason, false, 8); out.push_str(" }"); if index + 1 != report.hardware.runtime_irq_reports.len() { out.push(','); } out.push('\n'); } out.push_str(" ],\n"); push_json_number_field( &mut out, "usb_controllers", report.hardware.usb_controllers, true, 4, ); push_json_number_field(&mut out, "drm_cards", report.hardware.drm_cards, true, 4); push_json_bool_field( &mut out, "acpi_power_surface_present", report.hardware.acpi_power_surface_present, true, 4, ); push_json_bool_field( &mut out, "rtl8125_present", report.hardware.rtl8125_present, true, 4, ); push_json_bool_field( &mut out, "virtio_net_present", report.hardware.virtio_net_present, false, 4, ); out.push_str(" },\n"); out.push_str(" \"integrations\": [\n"); for (index, integration) in report.integrations.iter().enumerate() { out.push_str(" {\n"); push_json_string_field(&mut out, "name", integration.check.name, true, 6); push_json_string_field(&mut out, "category", integration.check.category, true, 6); push_json_string_field( &mut out, "description", integration.check.description, true, 6, ); push_json_string_field(&mut out, "state", state_label(integration.state), true, 6); push_json_optional_bool_field( &mut out, "artifact_present", integration.artifact_present, true, 6, ); push_json_optional_bool_field( &mut out, "control_present", integration.control_present, true, 6, ); push_json_string_field(&mut out, "test_hint", integration.check.test_hint, true, 6); push_json_string_array_field(&mut out, "evidence", &integration.evidence, true, 6); push_json_string_field(&mut out, "claim_limit", integration.claim_limit, false, 6); out.push_str(" }"); if index + 1 != report.integrations.len() { out.push(','); } out.push('\n'); } out.push_str(" ]\n"); out.push('}'); println!("{out}"); } fn print_help() { println!( "Usage: redbear-info [--verbose|-v] [--json|--test|--quirks|--probe|--boot|--device |--health]" ); println!(); println!("Passive runtime integration report for Red Bear OS."); println!(); println!("This tool distinguishes:"); println!(" present artifact or config exists"); println!(" active live runtime surface exists"); println!( " functional read-only runtime probe succeeded (table/test output; --probe mode uses PRESENT/ABSENT)" ); println!(); println!("Connected means the local networking stack has a configured address."); println!("It does not prove internet reachability."); println!(); println!("Options:"); println!(" -v, --verbose Show evidence and claim limits"); println!(" --json Print structured JSON"); println!(" --test Print suggested diagnostic commands"); println!(" --quirks Print configured hardware quirk data"); println!( " --probe Probe Phase 1 service liveness (evdevd, udev-shim, firmware-loader, drm, time)" ); println!(" --boot Show device-init boot timeline"); println!(" --device Show per-device runtime status (example: pci/00:02:0)"); println!(" --health Show subsystem health dashboard"); println!(" -h, --help Show this help message"); } fn print_section_header(title: &str) { println!("{}", colorize(title, BLUE)); } fn state_marker(state: ProbeState) -> &'static str { match state { ProbeState::Functional => "●", ProbeState::Active => "◉", ProbeState::Present => "◌", ProbeState::Absent => "○", ProbeState::Unobservable => "?", } } fn state_label(state: ProbeState) -> &'static str { match state { ProbeState::Functional => "functional", ProbeState::Active => "active", ProbeState::Present => "present", ProbeState::Absent => "absent", ProbeState::Unobservable => "unobservable", } } fn state_color(state: ProbeState) -> &'static str { match state { ProbeState::Functional => GREEN, ProbeState::Active => YELLOW, ProbeState::Present => BLUE, ProbeState::Absent => RED, ProbeState::Unobservable => YELLOW, } } fn colorize(text: &str, color: &str) -> String { format!("{color}{text}{RESET}") } fn count_state(items: &[IntegrationStatus<'_>], state: ProbeState) -> usize { items.iter().filter(|item| item.state == state).count() } fn display_or_unknown(value: Option<&str>) -> &str { value.unwrap_or("unknown") } fn parse_os_release_value(contents: &str, key: &str) -> Option { contents.lines().find_map(|line| { let (found_key, raw) = line.split_once('=')?; if found_key == key { Some(raw.trim().trim_matches('"').to_string()) } else { None } }) } fn read_trimmed(runtime: &Runtime, path: &str) -> Option { runtime .read_to_string(path) .map(|value| value.trim().to_string()) .filter(|value| !value.is_empty()) } fn read_compact(runtime: &Runtime, path: &str) -> Option { runtime .read_to_string(path) .map(|value| { value .lines() .map(str::trim) .filter(|line| !line.is_empty()) .collect::>() .join(" ") }) .filter(|value| !value.is_empty()) } fn parse_compact_key_value(content: &str, key: &str) -> Option { let prefix = format!("{key}="); content .split_whitespace() .find_map(|token| token.strip_prefix(&prefix).map(str::to_string)) } fn current_epoch_seconds() -> u64 { SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap_or_default() .as_secs() } fn bluetooth_status_is_fresh(runtime: &Runtime, path: &str) -> bool { runtime .read_to_string(path) .and_then(|value| { value.lines().find_map(|line| { line.trim() .strip_prefix("updated_at_epoch=") .and_then(|raw| raw.parse::().ok()) }) }) .map(|timestamp| { current_epoch_seconds().saturating_sub(timestamp) <= BLUETOOTH_STATUS_FRESHNESS_SECS }) .unwrap_or(false) } fn read_prefix_bytes(runtime: &Runtime, path: &str, max_len: usize) -> Option> { let mut file = fs::File::open(runtime.resolve(path)).ok()?; let mut bytes = vec![0_u8; max_len]; let read = file.read(&mut bytes).ok()?; bytes.truncate(read); Some(bytes) } fn read_all_bytes(runtime: &Runtime, path: &str) -> Option> { fs::read(runtime.resolve(path)).ok() } impl BootProbeStatus { fn from_str(value: &str) -> Option { match value { "bound" => Some(Self::Bound), "deferred" => Some(Self::Deferred), "failed" => Some(Self::Failed), "skipped" => Some(Self::Skipped), _ => None, } } fn as_str(self) -> &'static str { match self { Self::Bound => "bound", Self::Deferred => "deferred", Self::Failed => "failed", Self::Skipped => "skipped", } } } fn collect_boot_timeline(runtime: &Runtime) -> Result, String> { let content = runtime .read_to_string(BOOT_TIMELINE_PATH) .ok_or_else(|| format!("boot timeline not found at {BOOT_TIMELINE_PATH}"))?; let mut entries = Vec::new(); for (index, line) in content.lines().enumerate() { let line = line.trim(); if line.is_empty() { continue; } let value: JsonValue = serde_json::from_str(line) .map_err(|err| format!("invalid boot timeline entry {}: {err}", index + 1))?; let ts = value .get("ts") .and_then(JsonValue::as_u64) .map(u128::from) .ok_or_else(|| format!("boot timeline entry {} is missing ts", index + 1))?; let event_name = value .get("event") .and_then(JsonValue::as_str) .ok_or_else(|| format!("boot timeline entry {} is missing event", index + 1))?; let event = match event_name { "bus_enumerated" => BootTimelineEvent::BusEnumerated { bus: value .get("bus") .and_then(JsonValue::as_str) .ok_or_else(|| format!("boot timeline entry {} is missing bus", index + 1))? .to_string(), count: value .get("count") .and_then(JsonValue::as_u64) .map(|value| value as usize) .ok_or_else(|| format!("boot timeline entry {} is missing count", index + 1))?, }, "probe" => BootTimelineEvent::Probe { device: value .get("device") .and_then(JsonValue::as_str) .ok_or_else(|| format!("boot timeline entry {} is missing device", index + 1))? .to_string(), driver: value .get("driver") .and_then(JsonValue::as_str) .ok_or_else(|| format!("boot timeline entry {} is missing driver", index + 1))? .to_string(), status: value .get("status") .and_then(JsonValue::as_str) .and_then(BootProbeStatus::from_str) .ok_or_else(|| { format!("boot timeline entry {} is missing status", index + 1) })?, }, _ => continue, }; entries.push(BootTimelineEntry { ts, event }); } entries.sort_by_key(|entry| entry.ts); Ok(entries) } fn print_boot_timeline(entries: &[BootTimelineEntry]) { println!("Boot Timeline:"); if entries.is_empty() { println!(" no timeline data recorded"); return; } let first_ts = entries.first().map(|entry| entry.ts).unwrap_or(0); let mut bound = 0usize; let mut deferred = 0usize; let mut failed = 0usize; for entry in entries { let delta = entry.ts.saturating_sub(first_ts); match &entry.event { BootTimelineEvent::BusEnumerated { bus, count } => { println!("[{delta:>4}ms] bus {bus} enumerated {count} device(s)"); } BootTimelineEvent::Probe { device, driver, status, } => { match status { BootProbeStatus::Bound => bound += 1, BootProbeStatus::Deferred => deferred += 1, BootProbeStatus::Failed => failed += 1, BootProbeStatus::Skipped => {} } println!( "[{delta:>4}ms] probed {} -> {} ({})", format_timeline_device(device), driver, status.as_str() ); } } } println!("Total: {bound} bound, {deferred} deferred, {failed} failed"); } fn collect_device_status(runtime: &Runtime, requested: &str) -> Result { let location = parse_requested_pci_location(requested) .ok_or_else(|| format!("invalid PCI device selector: {requested}"))?; let scheme_entry = format_scheme_pci_entry(&location); let config_path = format!("/scheme/pci/{scheme_entry}/config"); let bytes = read_all_bytes(runtime, &config_path) .ok_or_else(|| format!("device config not found at {config_path}"))?; if bytes.len() < 64 { return Err(format!("device config at {config_path} is too short")); } let info = parse_device_info_from_config_space(location, &bytes) .ok_or_else(|| format!("failed to parse PCI config at {config_path}"))?; let params = collect_driver_params(runtime, &scheme_entry); let driver = params .iter() .find_map(|(key, value)| (key == "driver" && !value.is_empty()).then(|| value.clone())); let parameters = params .into_iter() .filter(|(key, _)| key != "driver") .collect::>(); let runtime_device = format_runtime_pci_location(&location); let irq_mode = collect_irq_runtime_reports(runtime) .into_iter() .find(|report| report.device == runtime_device) .map(|report| format_irq_mode(&report.mode)) .unwrap_or_else(|| format_irq_mode(info.interrupt_support().as_str())); let status = latest_boot_status_for_device(runtime, &location); Ok(DeviceStatusReport { selector: format_device_selector(&location), status, vendor_id: info.vendor_id, device_id: info.device_id, class_code: info.class_code, class_name: pci_class_name(info.class_code), irq_mode, driver, parameters, }) } fn print_device_status(report: &DeviceStatusReport) { println!("Device: {}", report.selector); println!( " Status: {}", report .status .map(BootProbeStatus::as_str) .unwrap_or("unknown") ); println!( " Vendor: 0x{:04x} Device: 0x{:04x}", report.vendor_id, report.device_id ); println!( " Class: 0x{:02x} ({})", report.class_code, report.class_name ); println!(" IRQ mode: {}", report.irq_mode); println!( " Driver: {}", report.driver.as_deref().unwrap_or("unknown") ); println!( " Parameters: {}", if report.parameters.is_empty() { "none".to_string() } else { report .parameters .iter() .map(|(key, value)| format!("{key}={value}")) .collect::>() .join(" ") } ); } fn collect_health_items(runtime: &Runtime, report: &Report<'_>) -> Vec { let mut items = Vec::new(); items.push(HealthItem { label: "PCI scheme", state: if runtime.is_dir("/scheme/pci") { HealthState::Healthy } else { HealthState::Critical }, detail: "/scheme/pci".to_string(), }); let usb_scheme_present = runtime.is_dir("/scheme/usb") || report.hardware.usb_controllers > 0; items.push(HealthItem { label: "USB scheme", state: if usb_scheme_present { HealthState::Healthy } else if runtime.exists("/usr/lib/drivers/xhcid") { HealthState::Warning } else { HealthState::Critical }, detail: if runtime.is_dir("/scheme/usb") { "/scheme/usb".to_string() } else if report.hardware.usb_controllers > 0 { format!( "{} usb.* controller scheme(s)", report.hardware.usb_controllers ) } else { "no USB runtime surface".to_string() }, }); items.push(HealthItem { label: "ACPI scheme", state: if runtime.is_dir("/scheme/acpi") { HealthState::Healthy } else { HealthState::Critical }, detail: "/scheme/acpi".to_string(), }); items.push(HealthItem { label: "DRM scheme", state: if runtime.is_dir("/scheme/drm") && report.hardware.drm_cards > 0 { HealthState::Healthy } else if runtime.is_dir("/scheme/drm") { HealthState::Warning } else { HealthState::Critical }, detail: if report.hardware.drm_cards > 0 { format!("/scheme/drm ({} card(s))", report.hardware.drm_cards) } else { "/scheme/drm".to_string() }, }); items.push(HealthItem { label: "Network", state: if report.network.connected { HealthState::Healthy } else if matches!( report.network.state, ProbeState::Active | ProbeState::Functional ) { HealthState::Warning } else { HealthState::Critical }, detail: if report.network.connected { match report.network.interface.as_deref() { Some(interface) => format!("configured address on {interface}"), None => "configured address present".to_string(), } } else if runtime.exists("/scheme/netcfg") { "network stack visible, not configured".to_string() } else { "dhcpd/netcfg not active".to_string() }, }); items.push(HealthItem { label: "Wi-Fi", state: if !report.network.wifi_interfaces.is_empty() { HealthState::Healthy } else if report.network.wifi_control_state != ProbeState::Absent { HealthState::Warning } else { HealthState::Critical }, detail: if !report.network.wifi_interfaces.is_empty() { report.network.wifi_interfaces.join(", ") } else if report.network.wifi_control_state != ProbeState::Absent { "no adapter".to_string() } else { "not running".to_string() }, }); items.push(HealthItem { label: "Bluetooth", state: if !report.network.bluetooth_adapters.is_empty() { HealthState::Healthy } else if report.network.bluetooth_transport_state != ProbeState::Absent || report.network.bluetooth_control_state != ProbeState::Absent { HealthState::Warning } else { HealthState::Critical }, detail: if !report.network.bluetooth_adapters.is_empty() { report.network.bluetooth_adapters.join(", ") } else if report.network.bluetooth_transport_state != ProbeState::Absent || report.network.bluetooth_control_state != ProbeState::Absent { "no adapter".to_string() } else { "not running".to_string() }, }); items } fn print_health_dashboard(items: &[HealthItem]) { println!("Health Dashboard:"); for item in items { println!( "[{}] {:<12} ({})", health_marker(item.state), item.label, item.detail ); } } fn health_marker(state: HealthState) -> &'static str { match state { HealthState::Healthy => "✓", HealthState::Warning => "⚠", HealthState::Critical => "✗", } } fn format_timeline_device(device: &str) -> String { parse_requested_pci_location(device) .map(|location| { format!( "{:02x}.{:02x}.{}", location.bus, location.device, location.function ) }) .unwrap_or_else(|| { device .trim_start_matches("pci/") .replace(':', ".") .replace("..", ".") }) } fn latest_boot_status_for_device( runtime: &Runtime, location: &redox_driver_sys::pci::PciLocation, ) -> Option { collect_boot_timeline(runtime) .ok()? .iter() .rev() .find_map(|entry| match &entry.event { BootTimelineEvent::Probe { device, status, .. } if parse_requested_pci_location(device).as_ref() == Some(location) => { Some(*status) } _ => None, }) } fn parse_requested_pci_location(value: &str) -> Option { let raw = value.trim().trim_start_matches("pci/"); if raw.contains("--") { return parse_scheme_pci_location(raw); } if raw.matches(':').count() == 2 && raw.contains('.') { let (segment, rest) = raw.split_once(':')?; let (bus, rest) = rest.split_once(':')?; let (device, function) = rest.split_once('.')?; return Some(redox_driver_sys::pci::PciLocation { segment: u16::from_str_radix(segment, 16).ok()?, bus: u8::from_str_radix(bus, 16).ok()?, device: u8::from_str_radix(device, 16).ok()?, function: u8::from_str_radix(function, 16).ok()?, }); } let normalized = raw.replace('.', ":"); let mut parts = normalized.split(':'); let bus = u8::from_str_radix(parts.next()?, 16).ok()?; let device = u8::from_str_radix(parts.next()?, 16).ok()?; let function = u8::from_str_radix(parts.next()?, 16).ok()?; if parts.next().is_some() { return None; } Some(redox_driver_sys::pci::PciLocation { segment: 0, bus, device, function, }) } fn format_scheme_pci_entry(location: &redox_driver_sys::pci::PciLocation) -> String { format!( "{:04x}--{:02x}--{:02x}.{}", location.segment, location.bus, location.device, location.function ) } fn format_runtime_pci_location(location: &redox_driver_sys::pci::PciLocation) -> String { format!( "{:04x}:{:02x}:{:02x}.{}", location.segment, location.bus, location.device, location.function ) } fn format_device_selector(location: &redox_driver_sys::pci::PciLocation) -> String { format!( "pci/{:02x}:{:02x}:{}", location.bus, location.device, location.function ) } fn collect_driver_params(runtime: &Runtime, scheme_entry: &str) -> Vec<(String, String)> { let dir = format!("{DRIVER_PARAMS_ROOT}/{scheme_entry}"); runtime .read_dir_names(&dir) .unwrap_or_default() .into_iter() .filter_map(|name| { read_trimmed(runtime, &format!("{dir}/{name}")).map(|value| (name, value)) }) .collect() } fn format_irq_mode(value: &str) -> String { match value { "msix" => "msi-x".to_string(), "msi_or_msix" => "msi/msi-x".to_string(), other => other.to_string(), } } fn pci_class_name(class_code: u8) -> &'static str { match class_code { 0x00 => "Unclassified", 0x01 => "Mass storage controller", 0x02 => "Network controller", 0x03 => "Display controller", 0x04 => "Multimedia controller", 0x05 => "Memory controller", 0x06 => "Bridge device", 0x07 => "Communication controller", 0x08 => "System peripheral", 0x09 => "Input device controller", 0x0a => "Docking station", 0x0b => "Processor", 0x0c => "Serial bus controller", 0x0d => "Wireless controller", 0x0e => "Intelligent controller", 0x0f => "Satellite communication controller", 0x10 => "Encryption controller", 0x11 => "Signal processing controller", 0x12 => "Processing accelerator", 0x13 => "Non-essential instrumentation", _ => "Unknown class", } } fn parse_default_route(routes: &str) -> Option { routes.lines().find_map(|line| { let trimmed = line.trim(); if trimmed.starts_with("default via ") || trimmed.starts_with("0.0.0.0/0 via ") { Some(trimmed.to_string()) } else { None } }) } fn probe_directory_readable( runtime: &Runtime, _network: &NetworkReport, _hardware: &HardwareReport, check: &IntegrationCheck, ) -> Option { let path = check.control_path?; let entries = runtime.read_dir_names(path)?; Some(format!( "read-only probe succeeded on {path} ({} entrie(s))", entries.len() )) } fn probe_usb_surface( runtime: &Runtime, _network: &NetworkReport, hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { (hardware.usb_controllers > 0 || runtime.is_dir("/scheme")).then(|| { format!( "usb scheme scan sees {} controller(s)", hardware.usb_controllers ) }) } fn probe_icmp_surface( runtime: &Runtime, _network: &NetworkReport, _hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { runtime .read_dir_names("/scheme") .filter(|entries| entries.iter().any(|name| name == "icmp")) .map(|_| "icmp scheme is present for probe/error reporting".to_string()) } fn probe_netctl_surface( runtime: &Runtime, network: &NetworkReport, _hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { let profiles = runtime.read_dir_names("/etc/netctl")?; let profile_count = profiles .iter() .filter(|name| *name != "active" && !name.starts_with('.')) .count(); Some(match &network.active_profile { Some(active) => format!( "{} profile(s) visible, active profile {}", profile_count, active ), None => format!( "{} profile(s) visible, no active profile recorded", profile_count ), }) } fn probe_smolnetd_surface( runtime: &Runtime, network: &NetworkReport, _hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { let _ = runtime.read_dir_names("/scheme/netcfg")?; Some(match &network.address { Some(address) => format!("netcfg readable, active address {address}"), None => "netcfg readable, no configured address".to_string(), }) } fn probe_named_scheme(runtime: &Runtime, scheme_name: &str) -> Option { let names = runtime.read_dir_names("/scheme")?; names .into_iter() .any(|name| name == scheme_name) .then(|| format!("scheme {scheme_name} is registered in /scheme")) } fn probe_firmware_scheme( runtime: &Runtime, _network: &NetworkReport, _hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { probe_named_scheme(runtime, "firmware") } fn probe_udev_scheme( runtime: &Runtime, _network: &NetworkReport, _hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { probe_named_scheme(runtime, "udev") } fn probe_evdev_scheme( runtime: &Runtime, _network: &NetworkReport, _hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { probe_named_scheme(runtime, "evdev") } fn probe_wifictl_surface( runtime: &Runtime, _network: &NetworkReport, _hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { let ifaces = runtime .read_to_string("/scheme/wifictl/ifaces") .or_else(|| { runtime .read_dir_names("/scheme/wifictl/ifaces") .map(|entries| entries.join("\n")) })?; Some(format!( "wifictl interface surface visible ({})", ifaces.trim() )) } fn probe_btctl_surface( runtime: &Runtime, _network: &NetworkReport, _hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { let adapters = runtime .read_to_string("/scheme/btctl/adapters") .or_else(|| { runtime .read_dir_names("/scheme/btctl/adapters") .map(|entries| entries.join("\n")) })?; let primary_adapter = adapters .lines() .map(str::trim) .find(|line| !line.is_empty())?; let read_result = read_trimmed( runtime, &format!("/scheme/btctl/adapters/{primary_adapter}/read-char-result"), )?; read_result.starts_with("read_char_result=").then(|| { format!( "btctl adapter surface visible ({}) with bounded read result", primary_adapter ) }) } fn probe_btusb_surface( runtime: &Runtime, _network: &NetworkReport, _hardware: &HardwareReport, check: &IntegrationCheck, ) -> Option { let path = check.control_path?; bluetooth_status_is_fresh(runtime, path) .then(|| format!("btusb status file is fresh at {path}")) } fn probe_pci_surface( runtime: &Runtime, _network: &NetworkReport, _hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { let entries = runtime.read_dir_names("/scheme/pci")?; Some(format!("pci surface visible ({} entries)", entries.len())) } fn probe_iommu_scheme( runtime: &Runtime, _network: &NetworkReport, _hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { probe_named_scheme(runtime, "iommu") } fn probe_acpi_power_surface( runtime: &Runtime, _network: &NetworkReport, _hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { let adapters = runtime.read_dir_names("/scheme/acpi/power/adapters"); let batteries = runtime.read_dir_names("/scheme/acpi/power/batteries"); runtime.exists("/scheme/acpi/power").then(|| { format!( "acpi power surface visible (adapters={}, batteries={})", adapters.as_ref().map(|items| items.len()).unwrap_or(0), batteries.as_ref().map(|items| items.len()).unwrap_or(0) ) }) } fn probe_serio_surface( runtime: &Runtime, _network: &NetworkReport, _hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { (runtime.exists("/scheme/serio/0") && runtime.exists("/scheme/serio/1")) .then(|| "serio keyboard and mouse nodes are visible for PS/2 proof".to_string()) } fn probe_time_surface( runtime: &Runtime, _network: &NetworkReport, _hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { runtime .exists("/scheme/time/4") .then(|| "monotonic time scheme node is visible for runtime proof".to_string()) } fn probe_rtl8125_path( _runtime: &Runtime, network: &NetworkReport, hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { if !hardware.rtl8125_present { return None; } Some( if network .network_schemes .iter() .any(|name| name.contains("rtl8125")) { "RTL8125 PCI device seen and network.rtl8125 scheme visible".to_string() } else if network.connected { "RTL8125 PCI device seen and native network stack reports a configured address" .to_string() } else { "RTL8125 PCI device seen through /scheme/pci".to_string() }, ) } fn probe_virtio_net_path( _runtime: &Runtime, network: &NetworkReport, hardware: &HardwareReport, _check: &IntegrationCheck, ) -> Option { if !hardware.virtio_net_present { return None; } Some( if network .network_schemes .iter() .any(|name| name.contains("virtio") || name.contains("eth0")) { "VirtIO NIC seen and network scheme surface is visible".to_string() } else if network.connected { "VirtIO NIC seen and native network stack reports a configured address".to_string() } else { "VirtIO NIC seen through /scheme/pci".to_string() }, ) } fn push_json_string(output: &mut String, value: &str) { output.push('"'); for ch in value.chars() { match ch { '"' => output.push_str("\\\""), '\\' => output.push_str("\\\\"), '\n' => output.push_str("\\n"), '\r' => output.push_str("\\r"), '\t' => output.push_str("\\t"), _ => output.push(ch), } } output.push('"'); } fn push_json_indent(output: &mut String, indent: usize) { for _ in 0..indent { output.push(' '); } } fn push_json_string_field( output: &mut String, key: &str, value: &str, trailing_comma: bool, indent: usize, ) { push_json_indent(output, indent); push_json_string(output, key); output.push_str(": "); push_json_string(output, value); if trailing_comma { output.push(','); } output.push('\n'); } fn push_json_field( output: &mut String, key: &str, value: Option<&str>, trailing_comma: bool, indent: usize, ) { push_json_indent(output, indent); push_json_string(output, key); output.push_str(": "); match value { Some(value) => push_json_string(output, value), None => output.push_str("null"), } if trailing_comma { output.push(','); } output.push('\n'); } fn push_json_bool_field( output: &mut String, key: &str, value: bool, trailing_comma: bool, indent: usize, ) { push_json_indent(output, indent); push_json_string(output, key); output.push_str(": "); output.push_str(if value { "true" } else { "false" }); if trailing_comma { output.push(','); } output.push('\n'); } fn push_json_optional_bool_field( output: &mut String, key: &str, value: Option, trailing_comma: bool, indent: usize, ) { push_json_indent(output, indent); push_json_string(output, key); output.push_str(": "); match value { Some(value) => output.push_str(if value { "true" } else { "false" }), None => output.push_str("null"), } if trailing_comma { output.push(','); } output.push('\n'); } fn push_json_number_field( output: &mut String, key: &str, value: usize, trailing_comma: bool, indent: usize, ) { push_json_indent(output, indent); push_json_string(output, key); output.push_str(": "); output.push_str(&value.to_string()); if trailing_comma { output.push(','); } output.push('\n'); } fn push_json_optional_number_field( output: &mut String, key: &str, value: Option, trailing_comma: bool, indent: usize, ) { push_json_indent(output, indent); push_json_string(output, key); output.push_str(": "); match value { Some(value) => output.push_str(&value.to_string()), None => output.push_str("null"), } if trailing_comma { output.push(','); } output.push('\n'); } fn push_json_string_array_field( output: &mut String, key: &str, values: &[String], trailing_comma: bool, indent: usize, ) { push_json_indent(output, indent); push_json_string(output, key); output.push_str(": ["); for (index, value) in values.iter().enumerate() { if index > 0 { output.push_str(", "); } push_json_string(output, value); } output.push(']'); if trailing_comma { output.push(','); } output.push('\n'); } #[cfg(test)] mod tests { use super::*; fn temp_root() -> PathBuf { let unique = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() .as_nanos(); let path = env::temp_dir().join(format!("redbear-info-test-{}-{}", process::id(), unique)); fs::create_dir_all(&path).unwrap(); path } fn write_file(root: &Path, path: &str, content: &str) { let full = root.join(path.trim_start_matches('/')); if let Some(parent) = full.parent() { fs::create_dir_all(parent).unwrap(); } fs::write(full, content).unwrap(); } fn create_dir(root: &Path, path: &str) { fs::create_dir_all(root.join(path.trim_start_matches('/'))).unwrap(); } fn integration_state<'a>(report: &'a Report<'a>, name: &str) -> ProbeState { report .integrations .iter() .find(|integration| integration.check.name == name) .map(|integration| integration.state) .unwrap() } #[test] fn network_report_uses_live_netcfg_surfaces() { let root = temp_root(); write_file( &root, "/usr/lib/os-release", "PRETTY_NAME=\"Red Bear OS\"\nVERSION_ID=\"0.1.0\"\n", ); write_file(&root, "/etc/hostname", "redbear\n"); create_dir(&root, "/scheme/netcfg/ifaces/eth0/addr"); write_file( &root, "/scheme/netcfg/ifaces/eth0/addr/list", "192.168.10.20/24\n", ); write_file( &root, "/scheme/netcfg/ifaces/eth0/mac", "02:00:00:00:00:01\n", ); write_file(&root, "/scheme/netcfg/resolv/nameserver", "1.1.1.1\n"); write_file( &root, "/scheme/netcfg/route/list", "default via 192.168.10.1\n", ); create_dir(&root, "/scheme/network.eth0_rtl8125"); create_dir(&root, "/scheme/wifictl/ifaces/wlan0"); write_file( &root, "/scheme/wifictl/ifaces/wlan0/firmware-status", "firmware=present family=intel-bz-arrow-lake prepared=yes\n", ); write_file( &root, "/scheme/wifictl/ifaces/wlan0/transport-status", "transport=pci memory_enabled=yes bus_master=yes bar0_present=yes irq_pin_present=yes\n", ); write_file( &root, "/scheme/wifictl/ifaces/wlan0/transport-init-status", "transport_init=stub\n", ); write_file( &root, "/scheme/wifictl/ifaces/wlan0/activation-status", "activation=stub\n", ); write_file( &root, "/scheme/wifictl/ifaces/wlan0/scan-results", "demo-ssid\ndemo-open\n", ); create_dir(&root, "/scheme/btctl/adapters/hci0"); create_dir(&root, "/var/run/redbear-btusb"); write_file( &root, "/var/run/redbear-btusb/status", &format!( "transport=usb\nstartup=explicit\nupdated_at_epoch={}\nruntime_visibility=runtime-visible\n", current_epoch_seconds() ), ); write_file( &root, "/scheme/btctl/adapters/hci0/status", "status=adapter-visible\ntransport_status=transport=usb startup=explicit runtime_visibility=runtime-visible\nscan_results_count=2\nconnected_bond_count=1\nbond_count=1\nbond_store_path=/var/lib/bluetooth/hci0/bonds\n", ); write_file( &root, "/scheme/btctl/adapters/hci0/transport-status", "transport=usb startup=explicit runtime_visibility=runtime-visible\n", ); write_file( &root, "/scheme/btctl/adapters/hci0/bond-store-path", "/var/lib/bluetooth/hci0/bonds\n", ); write_file( &root, "/scheme/btctl/adapters/hci0/bond-count", "bond_count=1\nbond_store_path=/var/lib/bluetooth/hci0/bonds\n", ); write_file( &root, "/scheme/btctl/adapters/hci0/scan-results", "demo-beacon\ndemo-sensor\n", ); write_file( &root, "/scheme/btctl/adapters/hci0/connection-state", "connection_state=stub-connected\nconnected_bond_count=1\nconnected_bond_ids=AA:BB:CC:DD:EE:FF\nnote=stub-control-only-no-real-link-layer-beyond-experimental-battery-sensor-battery-level-read\n", ); write_file( &root, "/scheme/btctl/adapters/hci0/connect-result", "connect_result=stub-connected bond_id=AA:BB:CC:DD:EE:FF state=connected\n", ); write_file( &root, "/scheme/btctl/adapters/hci0/disconnect-result", "disconnect_result=stub-disconnected bond_id=AA:BB:CC:DD:EE:FF state=disconnected\n", ); write_file( &root, "/scheme/btctl/adapters/hci0/read-char-result", "read_char_result=stub-value workload=battery-sensor-battery-level-read peripheral_class=ble-battery-sensor characteristic=battery-level bond_id=AA:BB:CC:DD:EE:FF service_uuid=0000180f-0000-1000-8000-00805f9b34fb char_uuid=00002a19-0000-1000-8000-00805f9b34fb access=read-only value_hex=57 value_percent=87\n", ); create_dir(&root, "/var/lib/bluetooth/hci0/bonds"); write_file( &root, "/var/lib/bluetooth/hci0/bonds/aabbccddeeff.bond", "bond_id=AA:BB:CC:DD:EE:FF\nalias=demo-sensor\ncreated_at_epoch=123\nsource=stub-cli\n", ); create_dir(&root, "/etc/netctl"); write_file(&root, "/etc/netctl/active", "wired-static\n"); let report = collect_report(&Runtime::from_root(root.clone())); assert_eq!(report.network.state, ProbeState::Functional); assert!(report.network.connected); assert_eq!(report.network.address.as_deref(), Some("192.168.10.20/24")); assert_eq!(report.network.dns.as_deref(), Some("1.1.1.1")); assert_eq!( report.network.default_route.as_deref(), Some("default via 192.168.10.1") ); assert_eq!( report.network.active_profile.as_deref(), Some("wired-static") ); assert!( report .network .network_schemes .iter() .any(|name| name.contains("rtl8125")) ); assert_eq!(report.network.wifi_control_state, ProbeState::Functional); assert_eq!(report.network.wifi_interfaces, vec!["wlan0".to_string()]); assert!( report .network .wifi_firmware_status .as_deref() .unwrap() .contains("intel-bz-arrow-lake") ); assert!( report .network .wifi_transport_status .as_deref() .unwrap() .contains("memory_enabled=yes") ); assert_eq!( report.network.wifi_transport_init_status.as_deref(), Some("transport_init=stub") ); assert_eq!( report.network.wifi_activation_status.as_deref(), Some("activation=stub") ); assert_eq!( report.network.wifi_scan_results, vec!["demo-ssid".to_string(), "demo-open".to_string()] ); assert_eq!(report.network.bluetooth_transport_state, ProbeState::Active); assert_eq!( report.network.bluetooth_control_state, ProbeState::Functional ); assert_eq!(report.network.bluetooth_adapters, vec!["hci0".to_string()]); assert!( report .network .bluetooth_transport_status .as_deref() .unwrap() .contains("runtime_visibility=runtime-visible") ); assert!( report .network .bluetooth_adapter_status .as_deref() .unwrap() .contains("status=adapter-visible") ); assert_eq!( report.network.bluetooth_scan_results, vec!["demo-beacon".to_string(), "demo-sensor".to_string()] ); assert!( report .network .bluetooth_connection_state .as_deref() .unwrap() .contains("connected_bond_ids=AA:BB:CC:DD:EE:FF") ); assert_eq!( report.network.bluetooth_connect_result.as_deref(), Some("connect_result=stub-connected bond_id=AA:BB:CC:DD:EE:FF state=connected") ); assert_eq!( report.network.bluetooth_disconnect_result.as_deref(), Some( "disconnect_result=stub-disconnected bond_id=AA:BB:CC:DD:EE:FF state=disconnected" ) ); assert!( report .network .bluetooth_read_char_result .as_deref() .unwrap() .contains("read_char_result=stub-value") ); assert!( report .network .bluetooth_read_char_result .as_deref() .unwrap() .contains("workload=battery-sensor-battery-level-read") ); assert_eq!( report.network.bluetooth_bond_store_path.as_deref(), Some("/var/lib/bluetooth/hci0/bonds") ); assert_eq!(report.network.bluetooth_bond_count, Some(1)); assert!( report .network .bluetooth_claim_limit .contains("real pairing") ); assert!( report .network .bluetooth_claim_limit .contains("general device traffic") ); assert!( report .network .bluetooth_claim_limit .contains("generic GATT") ); assert!( report .network .bluetooth_claim_limit .contains("write support") ); fs::remove_dir_all(root).unwrap(); } #[test] fn network_report_prefers_active_wifi_profile_interface() { let root = temp_root(); create_dir(&root, "/scheme/netcfg/ifaces/wlan0/addr"); write_file( &root, "/scheme/netcfg/ifaces/wlan0/addr/list", "10.0.0.44/24\n", ); write_file( &root, "/scheme/netcfg/ifaces/wlan0/mac", "02:00:00:00:00:44\n", ); write_file(&root, "/scheme/netcfg/resolv/nameserver", "9.9.9.9\n"); write_file(&root, "/scheme/netcfg/route/list", "default via 10.0.0.1\n"); create_dir(&root, "/scheme/wifictl/ifaces/wlan0"); write_file( &root, "/scheme/wifictl/ifaces/wlan0/firmware-status", "firmware=present\n", ); write_file( &root, "/scheme/wifictl/ifaces/wlan0/transport-status", "transport=active\n", ); write_file( &root, "/scheme/wifictl/ifaces/wlan0/transport-init-status", "transport_init=ok\n", ); write_file( &root, "/scheme/wifictl/ifaces/wlan0/activation-status", "activation=ok\n", ); write_file( &root, "/scheme/wifictl/ifaces/wlan0/connect-result", "connect_result=bounded-associated ssid=demo security=wpa2-psk\n", ); write_file( &root, "/scheme/wifictl/ifaces/wlan0/disconnect-result", "disconnect_result=bounded-disconnected\n", ); create_dir(&root, "/etc/netctl"); write_file(&root, "/etc/netctl/active", "wifi-dhcp\n"); write_file( &root, "/etc/netctl/wifi-dhcp", "Description='Wi-Fi'\nInterface=wlan0\nConnection=wifi\nSSID='demo'\nSecurity=wpa2-psk\nKey='secret'\nIP=dhcp\n", ); let report = collect_report(&Runtime::from_root(root.clone())); assert_eq!(report.network.active_profile.as_deref(), Some("wifi-dhcp")); assert_eq!(report.network.interface.as_deref(), Some("wlan0")); assert_eq!(report.network.address.as_deref(), Some("10.0.0.44/24")); assert_eq!(report.network.mac.as_deref(), Some("02:00:00:00:00:44")); assert_eq!(report.network.dns.as_deref(), Some("9.9.9.9")); assert_eq!( report.network.wifi_connect_result.as_deref(), Some("connect_result=bounded-associated ssid=demo security=wpa2-psk") ); assert_eq!( report.network.wifi_disconnect_result.as_deref(), Some("disconnect_result=bounded-disconnected") ); } #[test] fn bluetooth_reporting_distinguishes_installed_from_runtime_visible() { let root = temp_root(); write_file(&root, "/usr/bin/redbear-btusb", ""); write_file(&root, "/usr/bin/redbear-btctl", ""); let report = collect_report(&Runtime::from_root(root.clone())); assert_eq!( report.network.bluetooth_transport_state, ProbeState::Present ); assert_eq!(report.network.bluetooth_control_state, ProbeState::Present); assert_eq!(report.network.bluetooth_connection_state, None); assert_eq!(report.network.bluetooth_connect_result, None); assert_eq!(report.network.bluetooth_disconnect_result, None); assert_eq!(report.network.bluetooth_read_char_result, None); assert_eq!(report.network.bluetooth_bond_store_path, None); assert_eq!(report.network.bluetooth_bond_count, None); assert_eq!( integration_state(&report, "redbear-btusb"), ProbeState::Present ); assert_eq!( integration_state(&report, "redbear-btctl"), ProbeState::Present ); fs::remove_dir_all(root).unwrap(); } #[test] fn bluetooth_bond_store_reporting_falls_back_to_filesystem_evidence() { let root = temp_root(); write_file(&root, "/usr/bin/redbear-btctl", ""); create_dir(&root, "/scheme/btctl/adapters/hci0"); create_dir(&root, "/var/lib/bluetooth/hci0/bonds"); write_file( &root, "/var/lib/bluetooth/hci0/bonds/112233445566.bond", "bond_id=11:22:33:44:55:66\ncreated_at_epoch=42\nsource=stub-cli\n", ); let report = collect_report(&Runtime::from_root(root.clone())); assert_eq!( report.network.bluetooth_bond_store_path.as_deref(), Some("/var/lib/bluetooth/hci0/bonds") ); assert_eq!(report.network.bluetooth_bond_count, Some(1)); assert!( report .network .bluetooth_claim_limit .contains("stub bond files") ); fs::remove_dir_all(root).unwrap(); } #[test] fn bluetooth_connection_reporting_reads_bounded_control_surfaces() { let root = temp_root(); write_file(&root, "/usr/bin/redbear-btctl", ""); create_dir(&root, "/scheme/btctl/adapters/hci0"); write_file( &root, "/scheme/btctl/adapters/hci0/connection-state", "connection_state=stub-connected\nconnected_bond_count=1\nconnected_bond_ids=AA:BB:CC:DD:EE:FF\nnote=stub-control-only-no-real-link-layer-beyond-experimental-battery-sensor-battery-level-read\n", ); write_file( &root, "/scheme/btctl/adapters/hci0/connect-result", "connect_result=stub-connected bond_id=AA:BB:CC:DD:EE:FF state=connected\n", ); write_file( &root, "/scheme/btctl/adapters/hci0/disconnect-result", "disconnect_result=stub-disconnected bond_id=AA:BB:CC:DD:EE:FF state=disconnected\n", ); write_file( &root, "/scheme/btctl/adapters/hci0/read-char-result", "read_char_result=stub-value workload=battery-sensor-battery-level-read peripheral_class=ble-battery-sensor characteristic=battery-level bond_id=AA:BB:CC:DD:EE:FF service_uuid=0000180f-0000-1000-8000-00805f9b34fb char_uuid=00002a19-0000-1000-8000-00805f9b34fb access=read-only value_hex=57 value_percent=87\n", ); let report = collect_report(&Runtime::from_root(root.clone())); assert!( report .network .bluetooth_connection_state .as_deref() .unwrap() .contains("connected_bond_ids=AA:BB:CC:DD:EE:FF") ); assert_eq!( report.network.bluetooth_connect_result.as_deref(), Some("connect_result=stub-connected bond_id=AA:BB:CC:DD:EE:FF state=connected") ); assert_eq!( report.network.bluetooth_disconnect_result.as_deref(), Some( "disconnect_result=stub-disconnected bond_id=AA:BB:CC:DD:EE:FF state=disconnected" ) ); assert!( report .network .bluetooth_read_char_result .as_deref() .unwrap() .contains("read_char_result=stub-value") ); assert!( report .network .bluetooth_read_char_result .as_deref() .unwrap() .contains("peripheral_class=ble-battery-sensor") ); assert_eq!( integration_state(&report, "redbear-btctl"), ProbeState::Functional ); fs::remove_dir_all(root).unwrap(); } #[test] fn btctl_integration_requires_bounded_read_result_for_functional_state() { let root = temp_root(); write_file(&root, "/usr/bin/redbear-btctl", ""); create_dir(&root, "/scheme/btctl/adapters/hci0"); let report = collect_report(&Runtime::from_root(root.clone())); assert_eq!( report.network.bluetooth_control_state, ProbeState::Functional ); assert_eq!( integration_state(&report, "redbear-btctl"), ProbeState::Active ); fs::remove_dir_all(root).unwrap(); } #[test] fn stale_btusb_status_does_not_report_active_in_integrations() { let root = temp_root(); write_file(&root, "/usr/bin/redbear-btusb", ""); write_file( &root, "/var/run/redbear-btusb/status", "transport=usb\nstartup=explicit\nupdated_at_epoch=1\nruntime_visibility=runtime-visible\n", ); let report = collect_report(&Runtime::from_root(root.clone())); assert_eq!( report.network.bluetooth_transport_state, ProbeState::Present ); assert_eq!( integration_state(&report, "redbear-btusb"), ProbeState::Present ); fs::remove_dir_all(root).unwrap(); } #[test] fn rtl8125_hardware_detection_parses_pci_config() { let root = temp_root(); create_dir(&root, "/scheme/pci/0000--02--00.0"); let mut config = [0u8; 68]; config[0x00] = (RTL8125_VENDOR_ID & 0xff) as u8; config[0x01] = (RTL8125_VENDOR_ID >> 8) as u8; config[0x02] = (RTL8125_DEVICE_ID & 0xff) as u8; config[0x03] = (RTL8125_DEVICE_ID >> 8) as u8; config[0x0e] = 0x00; let path = root.join("scheme/pci/0000--02--00.0/config"); if let Some(parent) = path.parent() { fs::create_dir_all(parent).unwrap(); } fs::write(&path, config).unwrap(); let network = collect_network(&Runtime::from_root(root.clone())); let hardware = collect_hardware(&Runtime::from_root(root.clone()), &network); assert!(hardware.rtl8125_present); fs::remove_dir_all(root).unwrap(); } #[test] fn virtio_net_hardware_detection_parses_pci_config() { let root = temp_root(); create_dir(&root, "/scheme/pci/0000--00--03.0"); let mut config = [0u8; 68]; config[0x00] = (VIRTIO_NET_VENDOR_ID & 0xff) as u8; config[0x01] = (VIRTIO_NET_VENDOR_ID >> 8) as u8; config[0x02] = (VIRTIO_NET_DEVICE_ID & 0xff) as u8; config[0x03] = (VIRTIO_NET_DEVICE_ID >> 8) as u8; config[0x0e] = 0x00; let path = root.join("scheme/pci/0000--00--03.0/config"); if let Some(parent) = path.parent() { fs::create_dir_all(parent).unwrap(); } fs::write(&path, config).unwrap(); let network = collect_network(&Runtime::from_root(root.clone())); let hardware = collect_hardware(&Runtime::from_root(root.clone()), &network); assert!(hardware.virtio_net_present); fs::remove_dir_all(root).unwrap(); } #[test] fn hardware_report_counts_pci_interrupt_support_modes() { let root = temp_root(); create_dir(&root, "/scheme/pci/0000--00--01.0"); create_dir(&root, "/scheme/pci/0000--00--02.0"); create_dir(&root, "/scheme/pci/0000--00--03.0"); let mut legacy = [0u8; 68]; legacy[0x00] = 0x34; legacy[0x01] = 0x12; legacy[0x02] = 0x78; legacy[0x03] = 0x56; legacy[0x06] = 0x10; // capabilities present legacy[0x0e] = 0x00; legacy[0x34] = 0x40; legacy[0x3c] = 11; legacy[0x40] = 0x01; // power capability only legacy[0x41] = 0x00; let mut msi = legacy; msi[0x02] = 0x79; msi[0x40] = 0x05; // MSI capability let mut msix = legacy; msix[0x02] = 0x7a; msix[0x40] = 0x11; // MSI-X capability fs::write(root.join("scheme/pci/0000--00--01.0/config"), legacy).unwrap(); fs::write(root.join("scheme/pci/0000--00--02.0/config"), msi).unwrap(); fs::write(root.join("scheme/pci/0000--00--03.0/config"), msix).unwrap(); let network = collect_network(&Runtime::from_root(root.clone())); let hardware = collect_hardware(&Runtime::from_root(root.clone()), &network); assert_eq!(hardware.pci_devices, 3); assert_eq!(hardware.pci_irq_none, 0); assert!(hardware.pci_irq_legacy >= 1); assert_eq!( hardware.pci_irq_legacy + hardware.pci_irq_msi + hardware.pci_irq_msix, hardware.pci_devices ); assert_eq!( hardware.pci_irq_forced_legacy + hardware.pci_irq_msix_disabled_by_quirk + hardware.pci_irq_msi_disabled_by_quirk, 0 ); fs::remove_dir_all(root).unwrap(); } #[test] fn hardware_report_detects_acpi_power_surface() { let root = temp_root(); create_dir(&root, "/scheme/acpi/power"); let network = collect_network(&Runtime::from_root(root.clone())); let hardware = collect_hardware(&Runtime::from_root(root.clone()), &network); assert!(hardware.acpi_power_surface_present); fs::remove_dir_all(root).unwrap(); } #[test] fn collect_irq_runtime_reports_reads_driver_mode_files() { let root = temp_root(); create_dir(&root, "/proc/123"); write_file( &root, "/tmp/redbear-irq-report/xhcid.env", "driver=xhcid\npid=123\ndevice=0000:00:14.0\nmode=msi_or_msix\nreason=driver_selected_interrupt_delivery\n", ); let reports = collect_irq_runtime_reports(&Runtime::from_root(root.clone())); assert_eq!(reports.len(), 1); assert_eq!(reports[0].driver, "xhcid"); assert_eq!(reports[0].pid, 123); assert_eq!(reports[0].mode, "msi_or_msix"); assert_eq!(reports[0].reason, "driver_selected_interrupt_delivery"); fs::remove_dir_all(root).unwrap(); } #[test] fn collect_irq_runtime_reports_ignores_stale_pid_entries() { let root = temp_root(); write_file( &root, "/tmp/redbear-irq-report/xhcid.env", "driver=xhcid\npid=999\ndevice=0000:00:14.0\nmode=msi_or_msix\nreason=driver_selected_interrupt_delivery\n", ); let reports = collect_irq_runtime_reports(&Runtime::from_root(root.clone())); assert!(reports.is_empty()); fs::remove_dir_all(root).unwrap(); } #[test] fn redbear_upower_integration_is_present_without_live_power_surface() { let root = temp_root(); write_file(&root, "/usr/bin/redbear-upower", ""); let report = collect_report(&Runtime::from_root(root.clone())); assert_eq!( integration_state(&report, "redbear-upower"), ProbeState::Present ); fs::remove_dir_all(root).unwrap(); } #[test] fn redbear_upower_integration_is_functional_with_live_power_surface() { let root = temp_root(); write_file(&root, "/usr/bin/redbear-upower", ""); create_dir(&root, "/scheme/acpi/power/adapters/AC"); create_dir(&root, "/scheme/acpi/power/batteries"); let report = collect_report(&Runtime::from_root(root.clone())); assert_eq!( integration_state(&report, "redbear-upower"), ProbeState::Functional ); fs::remove_dir_all(root).unwrap(); } #[test] fn json_output_contains_network_and_integration_state() { let root = temp_root(); write_file( &root, "/usr/lib/os-release", "PRETTY_NAME=\"Red Bear OS\"\nVERSION_ID=\"0.1.0\"\n", ); write_file(&root, "/usr/bin/redbear-info", ""); write_file(&root, "/usr/bin/redbear-netstat", ""); write_file(&root, "/usr/bin/redbear-nmap", ""); create_dir(&root, "/scheme/netcfg"); write_file( &root, "/scheme/netcfg/ifaces/eth0/addr/list", "Not configured\n", ); let report = collect_report(&Runtime::from_root(root.clone())); assert!(!report.hardware.virtio_net_present); assert!(!report.hardware.acpi_power_surface_present); let mut output = String::new(); output.push_str("{"); push_json_string_field( &mut output, "state", state_label(report.network.state), false, 0, ); assert!(output.contains("state")); assert!( report .integrations .iter() .any(|item| item.check.name == "redbear-info") ); assert!( report .integrations .iter() .any(|item| item.check.name == "redbear-netstat") ); assert!( report .integrations .iter() .any(|item| item.check.name == "redbear-btusb") ); assert!( report .integrations .iter() .any(|item| item.check.name == "redbear-btctl") ); assert!( report .integrations .iter() .any(|item| item.check.name == "redbear-upower") ); assert!( report .integrations .iter() .any(|item| item.check.name == "redbear-nmap") ); fs::remove_dir_all(root).unwrap(); } #[test] fn collect_boot_timeline_reads_probe_events() { let root = temp_root(); write_file( &root, BOOT_TIMELINE_PATH, concat!( "{\"ts\":1000,\"event\":\"bus_enumerated\",\"bus\":\"pci\",\"count\":5}\n", "{\"ts\":1120,\"event\":\"probe\",\"device\":\"pci/00:02:0\",\"driver\":\"redox-drm\",\"status\":\"bound\"}\n", "{\"ts\":1750,\"event\":\"probe\",\"device\":\"pci/00:19:0\",\"driver\":\"e1000d\",\"status\":\"deferred\"}\n" ), ); let timeline = collect_boot_timeline(&Runtime::from_root(root.clone())).unwrap(); assert_eq!(timeline.len(), 3); assert!(matches!( timeline[0].event, BootTimelineEvent::BusEnumerated { ref bus, count } if bus == "pci" && count == 5 )); assert!(matches!( timeline[1].event, BootTimelineEvent::Probe { ref driver, status: BootProbeStatus::Bound, .. } if driver == "redox-drm" )); assert_eq!(format_timeline_device("pci/00:02:0"), "00.02.0"); fs::remove_dir_all(root).unwrap(); } #[test] fn collect_device_status_reads_config_params_and_irq_mode() { let root = temp_root(); create_dir(&root, "/scheme/pci/0000--00--02.0"); create_dir(&root, "/proc/123"); let mut config = [0u8; 68]; config[0x00] = 0x86; config[0x01] = 0x80; config[0x02] = 0x34; config[0x03] = 0x12; config[0x0b] = 0x03; config[0x0a] = 0x00; config[0x09] = 0x00; config[0x0e] = 0x00; config[0x06] = 0x10; config[0x34] = 0x40; config[0x40] = 0x11; fs::write(root.join("scheme/pci/0000--00--02.0/config"), config).unwrap(); write_file( &root, "/tmp/redbear-driver-params/0000--00--02.0/driver", "redox-drm\n", ); write_file( &root, "/tmp/redbear-driver-params/0000--00--02.0/enabled", "true\n", ); write_file( &root, "/tmp/redbear-driver-params/0000--00--02.0/priority", "60\n", ); write_file( &root, "/tmp/redbear-irq-report/redox-drm.env", "driver=redox-drm\npid=123\ndevice=0000:00:02.0\nmode=msix\nreason=driver_selected_interrupt_delivery\n", ); write_file( &root, BOOT_TIMELINE_PATH, concat!( "{\"ts\":1000,\"event\":\"probe\",\"device\":\"pci/00:02:0\",\"driver\":\"redox-drm\",\"status\":\"deferred\"}\n", "{\"ts\":1200,\"event\":\"probe\",\"device\":\"0000:00:02.0\",\"driver\":\"redox-drm\",\"status\":\"bound\"}\n" ), ); let report = collect_device_status(&Runtime::from_root(root.clone()), "pci/00:02:0").unwrap(); assert_eq!(report.selector, "pci/00:02:0"); assert_eq!(report.status, Some(BootProbeStatus::Bound)); assert_eq!(report.vendor_id, 0x8086); assert_eq!(report.device_id, 0x1234); assert_eq!(report.class_name, "Display controller"); assert_eq!(report.irq_mode, "msi-x"); assert_eq!(report.driver.as_deref(), Some("redox-drm")); assert_eq!( report.parameters, vec![ ("enabled".to_string(), "true".to_string()), ("priority".to_string(), "60".to_string()) ] ); fs::remove_dir_all(root).unwrap(); } #[test] fn collect_device_status_falls_back_to_config_irq_mode_without_runtime_report() { let root = temp_root(); create_dir(&root, "/scheme/pci/0000--00--02.0"); let mut config = [0u8; 68]; config[0x00] = 0x86; config[0x01] = 0x80; config[0x02] = 0x34; config[0x03] = 0x12; config[0x0b] = 0x03; config[0x0a] = 0x00; config[0x09] = 0x00; config[0x0e] = 0x00; config[0x06] = 0x10; config[0x34] = 0x40; config[0x40] = 0x11; fs::write(root.join("scheme/pci/0000--00--02.0/config"), config).unwrap(); let report = collect_device_status(&Runtime::from_root(root.clone()), "pci/00:02:0").unwrap(); assert_eq!(report.irq_mode, "msi-x"); fs::remove_dir_all(root).unwrap(); } #[test] fn collect_health_items_reports_scheme_and_adapter_gaps() { let root = temp_root(); create_dir(&root, "/scheme/pci"); create_dir(&root, "/scheme/acpi"); create_dir(&root, "/scheme/drm/card0"); create_dir(&root, "/scheme/usb"); create_dir(&root, "/scheme/netcfg"); create_dir(&root, "/scheme/wifictl"); let runtime = Runtime::from_root(root.clone()); let report = collect_report(&runtime); let health = collect_health_items(&runtime, &report); assert!( health .iter() .any(|item| { item.label == "PCI scheme" && item.state == HealthState::Healthy }) ); assert!(health.iter().any(|item| { item.label == "Wi-Fi" && item.state == HealthState::Warning && item.detail == "no adapter" })); assert!(health.iter().any(|item| { item.label == "Bluetooth" && item.state == HealthState::Critical && item.detail == "not running" })); fs::remove_dir_all(root).unwrap(); } #[test] fn parse_args_accepts_boot_health_and_device_modes() { let boot = parse_args(["redbear-info".to_string(), "--boot".to_string()]).unwrap(); assert!(matches!(boot.mode, OutputMode::Boot)); let health = parse_args(["redbear-info".to_string(), "--health".to_string()]).unwrap(); assert!(matches!(health.mode, OutputMode::Health)); let device = parse_args([ "redbear-info".to_string(), "--device".to_string(), "pci/00:02:0".to_string(), ]) .unwrap(); assert!(matches!(device.mode, OutputMode::Device)); assert_eq!(device.device.as_deref(), Some("pci/00:02:0")); } #[test] fn parse_args_rejects_device_without_value_and_with_other_modes() { assert_eq!( parse_args(["redbear-info".to_string(), "--device".to_string()]).err(), Some("--device requires a PCI address".to_string()) ); assert_eq!( parse_args([ "redbear-info".to_string(), "--json".to_string(), "--device".to_string(), "pci/00:02:0".to_string(), ]) .err(), Some("cannot combine --device with --json".to_string()) ); } #[test] fn parse_args_accepts_probe_mode() { let options = parse_args(["redbear-info".to_string(), "--probe".to_string()]).unwrap(); assert!(matches!(options.mode, OutputMode::Probe)); } #[test] fn parse_args_rejects_probe_with_other_output_modes() { // probe first, then --json: --json is the current arg, error puts current arg first assert_eq!( parse_args([ "redbear-info".to_string(), "--probe".to_string(), "--json".to_string(), ]) .err(), Some("cannot combine --json with --probe".to_string()) ); // --test first, then --probe: --probe is the current arg assert_eq!( parse_args([ "redbear-info".to_string(), "--test".to_string(), "--probe".to_string(), ]) .err(), Some("cannot combine --probe with --test".to_string()) ); // --quirks first, then --probe: --probe is the current arg assert_eq!( parse_args([ "redbear-info".to_string(), "--quirks".to_string(), "--probe".to_string(), ]) .err(), Some("cannot combine --probe with --quirks".to_string()) ); // Reverse direction: --json/--test/--quirks after --probe assert_eq!( parse_args([ "redbear-info".to_string(), "--json".to_string(), "--probe".to_string(), ]) .err(), Some("cannot combine --probe with --json".to_string()) ); assert_eq!( parse_args([ "redbear-info".to_string(), "--probe".to_string(), "--test".to_string(), ]) .err(), Some("cannot combine --test with --probe".to_string()) ); } #[test] fn probe_functions_return_false_on_host() { assert!(!probe_evdev_active()); assert!(!probe_udev_active()); assert!(!probe_firmware_active()); assert!(!probe_drm_active()); assert!(!probe_time_active()); } #[test] fn print_probe_outputs_all_present() { let result = Phase1ProbeResult { evdev_active: true, udev_active: true, firmware_active: true, drm_active: true, time_active: true, }; assert!(result.evdev_active); assert!(result.udev_active); assert!(result.firmware_active); assert!(result.drm_active); assert!(result.time_active); let all = result.evdev_active && result.udev_active && result.firmware_active && result.drm_active && result.time_active; assert!(all, "all five services should be present"); } #[test] fn print_probe_reports_gaps_count() { let result = Phase1ProbeResult { evdev_active: true, udev_active: true, firmware_active: false, drm_active: true, time_active: false, }; let count = result.evdev_active as u8 + result.udev_active as u8 + result.firmware_active as u8 + result.drm_active as u8 + result.time_active as u8; assert_eq!(count, 3); assert!(!result.firmware_active); assert!(!result.time_active); } #[test] fn parse_args_accepts_quirks_mode() { let options = parse_args([ "redbear-info".to_string(), "--quirks".to_string(), "--verbose".to_string(), ]) .unwrap(); assert!(matches!(options.mode, OutputMode::Quirks)); assert!(options.verbose); } #[test] fn parse_args_rejects_quirks_with_other_output_modes() { assert_eq!( parse_args([ "redbear-info".to_string(), "--quirks".to_string(), "--json".to_string(), ]) .err(), Some("cannot combine --json with --quirks".to_string()) ); assert_eq!( parse_args([ "redbear-info".to_string(), "--test".to_string(), "--quirks".to_string(), ]) .err(), Some("cannot combine --quirks with --test".to_string()) ); } #[test] fn collect_quirks_reads_pci_class_and_usb_entries() { let root = temp_root(); write_file( &root, "/etc/quirks.d/10-gpu.toml", "[[pci_quirk]]\nvendor = 0x1002\nclass = 0x030000\nflags = [\"no_d3cold\", \"need_firmware\"]\ndescription = \"GPU class quirk\"\n\n[[pci_quirk]]\nvendor = 0x1002\ndevice = 0x744c\nflags = [\"need_iommu\"]\n\n[[usb_quirk]]\nvendor = 0x0bda\nproduct = 0x8153\nflags = [\"no_string_fetch\"]\n", ); let report = collect_quirks(&Runtime::from_root(root.clone())); assert!(report.load_errors.is_empty()); assert_eq!(report.files_loaded.len(), 1); let file = &report.files_loaded[0]; assert_eq!(file.name, "10-gpu.toml"); assert_eq!(file.pci_quirks.len(), 2); assert_eq!(file.usb_quirks.len(), 1); assert_eq!(file.pci_quirks[0].vendor, "0x1002"); assert_eq!(file.pci_quirks[0].class.as_deref(), Some("0x030000")); assert_eq!( file.pci_quirks[0].description.as_deref(), Some("GPU class quirk") ); assert_eq!(file.pci_quirks[1].device.as_deref(), Some("0x744C")); assert_eq!(file.usb_quirks[0].vendor, "0x0BDA"); assert_eq!(file.usb_quirks[0].product.as_deref(), Some("0x8153")); fs::remove_dir_all(root).unwrap(); } #[test] fn collect_quirks_reports_missing_directory() { let root = temp_root(); let report = collect_quirks(&Runtime::from_root(root.clone())); assert!(report.files_loaded.is_empty()); assert_eq!(report.load_errors, vec!["quirks directory not found"]); fs::remove_dir_all(root).unwrap(); } }