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