diff --git a/app/igneum-app/src/bootcheck.rs b/app/igneum-app/src/bootcheck.rs new file mode 100644 index 000000000..0f289b181 --- /dev/null +++ b/app/igneum-app/src/bootcheck.rs @@ -0,0 +1,73 @@ +//! Did this PC come up from a power loss or a hard reset? (MF-11, 7 October 2026: PC 2 dropped twice in one day with +//! Kernel-Power 41 and EventLog 6008 at the next boot, no bugcheck, no dump, and nothing said so until a person read +//! the event log.) Windows: the System log's event 41 (Kernel-Power, critical) or 6008 (EventLog, "the previous +//! shutdown was unexpected") inside the last 15 minutes, read once at the engine's start through wevtutil; the engine +//! logs one `FAULT pc-restart:` line to the intake. Other platforms: nothing (a Mac's power log is not this class). + +use std::process::Command; +use std::time::Duration; + +/// How far back the start-up check looks: an engine starts at login, inside a minute or two of the boot. +pub const WINDOW_MS: u64 = 15 * 60 * 1000; + +/// One line naming the event, or None when the boot was clean, the query failed, or this is not Windows. +pub fn unexpected_restart() -> Option { + if !cfg!(windows) { + return None; + } + let query = format!("*[System[(EventID=41 or EventID=6008) and TimeCreated[timediff(@SystemTime) <= {WINDOW_MS}]]]"); + let mut c = Command::new(crate::platform::tool("wevtutil")); + c.args(["qe", "System", &format!("/q:{query}"), "/f:text", "/c:2", "/rd:true"]); + let out = crate::detect::run_timeout(&mut c, None, Duration::from_secs(20))?; + parse_events(&out) +} + +/// The reading of wevtutil's text output: the newest 41 or 6008 as "event 41 (Kernel-Power) at