intel_crashlog/source/acpi/
sysfs.rs1use crate::CrashLog;
5use crate::bert::Berr;
6use crate::error::Error;
7use crate::metadata::Time;
8use std::path::{Path, PathBuf};
9
10pub(super) struct AcpiSysFs {
11 root: PathBuf,
12}
13
14impl Default for AcpiSysFs {
15 fn default() -> Self {
16 Self::new(Path::new("/"))
17 }
18}
19
20impl AcpiSysFs {
21 pub fn new(path: &Path) -> Self {
22 Self {
23 root: path.to_owned(),
24 }
25 }
26
27 fn tables_path(&self) -> PathBuf {
28 let mut path = self.root.clone();
29 path.push("sys");
30 path.push("firmware");
31 path.push("acpi");
32 path.push("tables");
33 path
34 }
35
36 fn berr_path(&self) -> PathBuf {
37 let mut path = self.tables_path();
38 path.push("data");
39 path.push("BERT");
40 path
41 }
42
43 pub fn extract(&self) -> Result<CrashLog, Error> {
44 let path = self.berr_path();
45 let berr = std::fs::read(&path)
46 .map_err(|err| {
47 log::warn!("Cannot read {}: {err}", path.display());
48 match err.kind() {
49 std::io::ErrorKind::NotFound => Error::NoCrashLogFound,
50 _ => Error::from(err),
51 }
52 })
53 .and_then(|berr| {
54 log::info!("Found ACPI boot error record in sysfs");
55 Berr::from_slice(&berr).ok_or(Error::InvalidBootErrorRecordRegion)
56 })?;
57
58 let mut crashlog = CrashLog::from_berr(berr)?;
59 crashlog.metadata.time = Time::now();
60 Ok(crashlog)
61 }
62}
63
64impl CrashLog {
65 pub fn from_acpi_sysfs() -> Result<Self, Error> {
67 AcpiSysFs::default().extract()
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use tempfile;
75
76 #[test]
77 fn extract() {
78 let root = tempfile::tempdir().unwrap();
79
80 let acpi = AcpiSysFs::new(root.path());
81
82 let mut berr_path = root.path().to_owned();
83 berr_path.push("sys");
84 berr_path.push("firmware");
85 berr_path.push("acpi");
86 berr_path.push("tables");
87 berr_path.push("data");
88 std::fs::create_dir_all(&berr_path).unwrap();
89
90 berr_path.push("BERT");
91
92 let bert = std::fs::read("tests/samples/dummy.bert").unwrap();
93 let crashlog = CrashLog::from_slice(&bert).unwrap();
94
95 let berr = Berr::from_crashlog(&crashlog);
96 std::fs::write(berr_path, berr.to_bytes()).unwrap();
97
98 let mut extracted_crashlog = acpi.extract().unwrap();
99 assert!(extracted_crashlog.metadata.time.is_some());
100
101 extracted_crashlog.metadata.time = None;
102
103 assert_eq!(crashlog.to_bytes(), extracted_crashlog.to_bytes());
104 }
105}