intel_crashlog/extract/
sysfs.rs1use crate::CrashLog;
5use crate::bert::Berr;
6use crate::error::Error;
7use crate::region::Region;
8
9const BERR_PATH: &str = "/sys/firmware/acpi/tables/data/BERT";
10const PMT_PATH: &str = "/sys/class/intel_pmt";
11
12impl CrashLog {
13 pub fn from_acpi_sysfs() -> Result<Self, Error> {
15 let berr = std::fs::read(BERR_PATH)
16 .map_err(|err| {
17 log::warn!("Cannot read {BERR_PATH}: {err}");
18 match err.kind() {
19 std::io::ErrorKind::NotFound => Error::NoCrashLogFound,
20 _ => Error::from(err),
21 }
22 })
23 .and_then(|berr| {
24 log::info!("Found ACPI boot error record in sysfs");
25 Berr::from_slice(&berr).ok_or(Error::InvalidBootErrorRecordRegion)
26 })?;
27
28 Self::from_berr(berr)
29 }
30
31 pub fn from_pmt_sysfs() -> Result<Self, Error> {
33 let regions: Vec<Region> = std::fs::read_dir(PMT_PATH)
34 .map_err(|err| {
35 log::warn!("Cannot read {PMT_PATH}: {err}");
36 match err.kind() {
37 std::io::ErrorKind::NotFound => Error::NoCrashLogFound,
38 _ => Error::from(err),
39 }
40 })?
41 .filter_map(|entry| {
42 entry
43 .inspect_err(|err| log::error!("Cannot access directory entry: {err}"))
44 .ok()
45 })
46 .filter(|entry| {
47 let is_dir = entry
48 .file_type()
49 .map(|file_type| file_type.is_dir())
50 .unwrap_or(false);
51 let is_crashlog_dir = entry
52 .file_name()
53 .to_str()
54 .map(|name| name.starts_with("crashlog"))
55 .unwrap_or(false);
56
57 is_dir && is_crashlog_dir
58 })
59 .filter_map(|entry| {
60 let mut path = entry.path();
61
62 log::info!("Found Crash Log entry in PMT sysfs: {}", path.display());
63 path.push("crashlog");
64
65 std::fs::read(&path)
66 .map_err(Error::IOError)
67 .and_then(|region| Region::from_slice(®ion))
68 .inspect(|_| log::info!("Extracted valid record from {}", path.display()))
69 .inspect_err(|err| log::error!("{}: {err}", path.display()))
70 .ok()
71 })
72 .collect();
73
74 Self::from_regions(regions)
75 }
76}