Skip to main content

intel_crashlog/extract/
sysfs.rs

1// Copyright (C) 2025 Intel Corporation
2// SPDX-License-Identifier: MIT
3
4use 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    /// Reads the Crash Log reported through ACPI from the linux sysfs
14    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    /// Reads the Crash Log reported through Intel PMT from the linux sysfs
32    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(&region))
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}