Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 41 additions & 0 deletions lib/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ serialize = [
"dep:serde_json",
]
std = [
"serde/std"
"serde/std",
"dep:jiff",
]

[dev-dependencies]
Expand All @@ -64,6 +65,16 @@ log = "0.4"
version = "5"
default-features = false

[dependencies.jiff]
version = "0.2"
default-features = false
features = [
"std",
"tz-system",
"tzdb-zoneinfo",
]
optional = true

[dependencies.serde]
version = "1"
optional = true
Expand Down
56 changes: 24 additions & 32 deletions lib/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

//! Information extracted alongside the Crash Log records.

mod time;

#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[cfg(not(feature = "std"))]
Expand All @@ -13,6 +15,8 @@ use std::fmt;
use crate::cper::CperSectionBody;
use crate::source::CrashLogSource;

pub use time::Time;

/// Crash Log Metadata
#[derive(Default, Clone)]
pub struct Metadata {
Expand All @@ -27,41 +31,29 @@ pub struct Metadata {
pub extra_cper_sections: Vec<CperSectionBody>,
}

/// Crash Log Extraction Time
#[derive(Clone)]
pub struct Time {
pub year: u16,
pub month: u8,
pub day: u8,
pub hour: u8,
pub minute: u8,
}

impl fmt::Display for Metadata {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match (
self.computer.as_ref(),
self.source.as_ref(),
self.time.as_ref(),
) {
(Some(computer), Some(source), Some(time)) => write!(f, "{computer}-{source}-{time}"),
(Some(computer), None, Some(time)) => write!(f, "{computer}-{time}"),
(None, None, Some(time)) => write!(f, "{time}"),
(None, Some(source), Some(time)) => write!(f, "{source}-{time}"),
(Some(computer), None, None) => write!(f, "{computer}"),
(Some(computer), Some(source), None) => write!(f, "{computer}-{source}"),
(None, Some(source), None) => write!(f, "{source}"),
(None, None, None) => write!(f, "unnamed"),
let mut sep = "";

if let Some(computer) = &self.computer {
write!(f, "{computer}")?;
sep = "-";
}
}
}

impl fmt::Display for Time {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{:04}-{:02}-{:02}-{:02}-{:02}",
self.year, self.month, self.day, self.hour, self.minute
)
if let Some(source) = &self.source {
write!(f, "{sep}{source}")?;
sep = "-";
}

if let Some(time) = &self.time {
write!(f, "{sep}{time}")?;
sep = "-";
}

if sep.is_empty() {
write!(f, "unnamed")?;
}

Ok(())
}
}
80 changes: 80 additions & 0 deletions lib/src/metadata/time.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (C) 2026 Intel Corporation
// SPDX-License-Identifier: MIT

#[cfg(not(feature = "std"))]
use alloc::fmt;
#[cfg(feature = "std")]
use std::fmt;

/// Crash Log Extraction Time, expressed in the local time of the system
#[derive(Clone)]
pub struct Time {
pub year: u16,
pub month: u8,
pub day: u8,
pub hour: u8,
pub minute: u8,
pub second: u8,
pub millisecond: u16,
}

impl fmt::Display for Time {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{:04}{:02}{:02}T{:02}{:02}{:02}.{:03}",
self.year, self.month, self.day, self.hour, self.minute, self.second, self.millisecond,
)
}
}

impl Time {
/// Returns the current [Time], or [None] if it cannot be determined
///
/// The time is read from the operating system
#[cfg(feature = "std")]
pub fn now() -> Option<Self> {
use jiff::{Timestamp, tz};

let now = Timestamp::try_from(std::time::SystemTime::now())
.inspect_err(|err| log::info!("Cannot get the current time: {err}"))
.ok()?;

let tz = tz::TimeZone::system();

if tz == tz::TimeZone::unknown() {
log::warn!("Cannot determine the system time zone");
}

let local = now.to_zoned(tz).datetime();
Some(Time {
year: local.year() as u16,
month: local.month() as u8,
day: local.day() as u8,
hour: local.hour() as u8,
minute: local.minute() as u8,
second: local.second() as u8,
millisecond: local.millisecond() as u16,
})
}

/// Returns the current [Time], or [None] if it cannot be determined
///
/// The time is read from the UEFI runtime services
#[cfg(all(not(feature = "std"), target_os = "uefi"))]
pub fn now() -> Option<Self> {
let time = uefi::runtime::get_time()
.inspect_err(|err| log::info!("Cannot get RTC time: {err}"))
.ok()?;

Some(Time {
year: time.year(),
month: time.month(),
day: time.day(),
hour: time.hour(),
minute: time.minute(),
second: time.second(),
millisecond: (time.nanosecond() / 1_000_000) as u16,
})
}
}
1 change: 0 additions & 1 deletion lib/src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ impl CrashLogSource {
crashlog.metadata.source = Some(self.clone());
}
}

crashlogs
}

Expand Down
2 changes: 1 addition & 1 deletion lib/src/source/acpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl Acpi {
#[cfg(target_os = "linux")]
{
match self.sysfs.extract() {
Ok(crashlogs) => return Ok(crashlogs),
Ok(crashlog) => return Ok(crashlog),
Err(err) => log::error!("Cannot extract Crash Log from ACPI sysfs: {err}"),
}
}
Expand Down
11 changes: 1 addition & 10 deletions lib/src/source/acpi/efi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,7 @@ pub(super) fn extract_crashlog() -> Result<CrashLog, Error> {

crashlog.metadata = metadata::Metadata {
computer: Some("efi".to_string()),
time: uefi::runtime::get_time()
.map(|time| metadata::Time {
year: time.year(),
month: time.month(),
day: time.day(),
hour: time.hour(),
minute: time.minute(),
})
.inspect_err(|err| log::warn!("Cannot get time: {err}"))
.ok(),
time: metadata::Time::now(),
..Default::default()
};

Expand Down
10 changes: 8 additions & 2 deletions lib/src/source/acpi/sysfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use crate::CrashLog;
use crate::bert::Berr;
use crate::error::Error;
use crate::metadata::Time;
use std::path::{Path, PathBuf};

pub(super) struct AcpiSysFs {
Expand Down Expand Up @@ -54,7 +55,9 @@ impl AcpiSysFs {
Berr::from_slice(&berr).ok_or(Error::InvalidBootErrorRecordRegion)
})?;

CrashLog::from_berr(berr)
let mut crashlog = CrashLog::from_berr(berr)?;
crashlog.metadata.time = Time::now();
Ok(crashlog)
}
}

Expand Down Expand Up @@ -92,7 +95,10 @@ mod tests {
let berr = Berr::from_crashlog(&crashlog);
std::fs::write(berr_path, berr.to_bytes()).unwrap();

let extracted_crashlog = acpi.extract().unwrap();
let mut extracted_crashlog = acpi.extract().unwrap();
assert!(extracted_crashlog.metadata.time.is_some());

extracted_crashlog.metadata.time = None;

assert_eq!(crashlog.to_bytes(), extracted_crashlog.to_bytes());
}
Expand Down
2 changes: 2 additions & 0 deletions lib/src/source/event_log/win.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ impl EvtRecord {
day: time.wDay as u8,
hour: time.wHour as u8,
minute: time.wMinute as u8,
second: time.wSecond as u8,
millisecond: time.wMilliseconds,
});
}

Expand Down
10 changes: 8 additions & 2 deletions lib/src/source/pmt/sysfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::PmtDeviceId;
use super::bdf::PciBdf;
use crate::CrashLog;
use crate::error::Error;
use crate::metadata::Time;
use crate::region::Region;
use crate::source::{Capabilities, Capability};
use std::collections::BTreeSet;
Expand Down Expand Up @@ -212,7 +213,10 @@ impl PmtSysFs {

for endpoint in self.get_endpoints(dev) {
match endpoint.extract() {
Ok(crashlog) => crashlogs.push(crashlog),
Ok(mut crashlog) => {
crashlog.metadata.time = Time::now();
crashlogs.push(crashlog);
}
Err(Error::EmptyRegion) => (),
Err(err) => return Err(err),
}
Expand Down Expand Up @@ -340,7 +344,9 @@ impl CrashLog {
.flat_map(|crashlog| crashlog.regions)
.collect();

CrashLog::from_regions(regions)
let mut crashlog = CrashLog::from_regions(regions)?;
crashlog.metadata.time = Time::now();
Ok(crashlog)
}
}

Expand Down
Loading