feat(m1): kmsg watcher — reads /dev/kmsg kernel ring buffer

This commit is contained in:
pyr0ball 2026-05-18 17:13:36 -07:00
parent e48536dfbe
commit db7d30d4c1

View file

@ -1,6 +1,65 @@
use super::SystemEvent;
use super::{EventSource, SystemEvent, now_unix};
use tokio::fs::File;
use tokio::io::{AsyncBufReadExt, BufReader};
use tokio::sync::mpsc;
pub async fn watch(_tx: mpsc::Sender<SystemEvent>) {
// implemented in Task 7
pub async fn watch(tx: mpsc::Sender<SystemEvent>) {
let file = match File::open("/dev/kmsg").await {
Ok(f) => f,
Err(e) => {
log::warn!("kmsg watcher: cannot open /dev/kmsg: {e}");
return;
}
};
let mut lines = BufReader::new(file).lines();
while let Ok(Some(line)) = lines.next_line().await {
if let Some(msg) = parse_kmsg(&line) {
let _ = tx
.send(SystemEvent {
source: EventSource::Kmsg,
raw_line: msg,
timestamp: now_unix(),
})
.await;
}
}
}
fn parse_kmsg(line: &str) -> Option<String> {
let msg = if let Some(pos) = line.find(';') {
&line[pos + 1..]
} else {
line
};
if msg.is_empty() {
return None;
}
Some(msg.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_kmsg_line_with_semicolon() {
let line = "6,1234,56789,-;usb 1-1: new full-speed USB device number 2";
assert_eq!(
parse_kmsg(line),
Some("usb 1-1: new full-speed USB device number 2".to_string())
);
}
#[test]
fn parses_kmsg_line_without_semicolon() {
let line = "plain message without header";
assert_eq!(parse_kmsg(line), Some("plain message without header".to_string()));
}
#[test]
fn skips_empty_message_after_semicolon() {
let line = "6,1234,56789,-;";
assert_eq!(parse_kmsg(line), None);
}
}