use linux_kernel_panic_parser::{LineKind, parse};
use std::{
env,
error::Error,
fs,
io::{self, Read},
};
fn main() -> Result<(), Box<dyn Error>> {
let mut debug = false;
let mut path = None;
let mut positional_only = false;
for argument in env::args_os().skip(1) {
if !positional_only && argument == "--debug" {
debug = true;
} else if !positional_only && argument == "--" {
positional_only = true;
} else if !positional_only && (argument == "--help" || argument == "-h") {
println!(
"Usage: parse [--debug] [--] [path/to/panic.log]\nReads stdin when no path is supplied.\n--debug prints the parsed Rust structure to stdout."
);
return Ok(());
} else if (!positional_only && argument.to_string_lossy().starts_with('-'))
|| path.is_some()
{
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Usage: parse [--debug] [--] [path/to/panic.log]",
)
.into());
} else {
path = Some(argument);
}
}
let text = if let Some(path) = path {
fs::read_to_string(path)?
} else {
let mut text = String::new();
io::stdin().read_to_string(&mut text)?;
text
};
let log = parse(text);
if debug {
println!("{log:#?}");
return Ok(());
}
for line in log.lines() {
match line.kind() {
LineKind::Panic { message } => eprintln!("panic: {message}"),
LineKind::Cpu {
cpu,
uid,
pid,
details,
} => {
eprintln!("cpu: {cpu}, uid: {uid:?}, pid: {pid}, {details}");
if let Some(time) = line.timestamp() {
eprintln!("wall time: {time}");
}
if let Some(uptime) = line.uptime() {
eprintln!("uptime: {uptime}");
}
}
LineKind::Symbol {
label,
segment,
frame,
} => {
eprintln!(
"{label}: segment {segment:?}, {}+{}/{}",
frame.symbol, frame.offset, frame.size
);
}
LineKind::Diagnostic { label, details }
if matches!(label.as_str(), "Oops" | "BUG" | "#PF") =>
{
eprintln!("{label}: {details}");
}
LineKind::Frame(frame) => {
eprintln!("frame: {}+{}/{}", frame.symbol, frame.offset, frame.size)
}
_ => {}
}
}
print!("{log}");
Ok(())
}