From 5dc219344fa8b3b42ec369260bc10d32e0e99184 Mon Sep 17 00:00:00 2001 From: "Rivas Paz, Jose L" Date: Fri, 28 Aug 2026 08:38:33 +0200 Subject: [PATCH 1/2] lib: introduce method to discover non-repeated Crash Log sources This patch includes `discover_distinct` method in the CrashLogSource API. This is a discovery method but as a difference with `discover` this one is avoiding the return of repeated sources, which is the case of the PMT sys class and PMT BDF sources. The usage of this method is for the automatic discovery when executing a control command or extracting and avoiding extracting data twice or sending the control command twice Signed-off-by: Rivas Paz, Jose L --- lib/src/source.rs | 22 ++++++++++++++++++++++ lib/src/source/pmt.rs | 10 ++++++++++ lib/src/source/pmt/sysfs.rs | 8 ++++++++ 3 files changed, 40 insertions(+) diff --git a/lib/src/source.rs b/lib/src/source.rs index ab1c9f9..b68c9e8 100644 --- a/lib/src/source.rs +++ b/lib/src/source.rs @@ -134,6 +134,18 @@ impl FromStr for CrashLogSource { impl CrashLogSource { /// Returns all the Crash Log sources that are available in the platform pub fn discover() -> Vec { + Self::discover_sources() + } + + /// Returns all the Crash Log sources that are available in the platform without duplicates + pub fn discover_distinct() -> Vec { + Self::discover_sources() + .into_iter() + .filter(|src| src.is_distinct()) + .collect() + } + + fn discover_sources() -> Vec { let mut sources = Vec::new(); if Acpi::default().is_available() { @@ -155,6 +167,16 @@ impl CrashLogSource { sources } + /// Returns `true` if the Crash log source is distinct, e. g. it is not mirrored by another + /// Crash Log source in the system + pub fn is_distinct(&self) -> bool { + match self { + Self::Acpi => true, + Self::EventLog => true, + Self::PmtDevice(dev) => Pmt::default().is_distinct(dev), + } + } + /// Returns the Crash Log extracted from the platform using the current Crash Log source #[cfg(feature = "extraction")] pub fn extract(&self) -> Result, Error> { diff --git a/lib/src/source/pmt.rs b/lib/src/source/pmt.rs index 8b9ecff..742517e 100644 --- a/lib/src/source/pmt.rs +++ b/lib/src/source/pmt.rs @@ -170,4 +170,14 @@ impl Pmt { PmtDeviceId::Bdf(bdf) => format!("PMT endpoints for PCI device {bdf}"), } } + + #[cfg(target_os = "linux")] + pub fn is_distinct(&self, dev: &PmtDeviceId) -> bool { + self.sysfs.is_distinct(dev) + } + + #[cfg(not(target_os = "linux"))] + pub fn is_distinct(&self, _dev: &PmtDeviceId) -> bool { + true + } } diff --git a/lib/src/source/pmt/sysfs.rs b/lib/src/source/pmt/sysfs.rs index 3c77372..62d19aa 100644 --- a/lib/src/source/pmt/sysfs.rs +++ b/lib/src/source/pmt/sysfs.rs @@ -129,9 +129,17 @@ impl PmtSysFs { devices } + pub(super) fn is_distinct(&self, dev: &PmtDeviceId) -> bool { + match dev { + PmtDeviceId::Name(_name) => true, + PmtDeviceId::Bdf(_bdf) => false, + } + } + pub fn get_all_endpoints(&self) -> Vec { self.discover() .into_iter() + .filter(|dev| self.is_distinct(dev)) .flat_map(|devid| self.get_endpoints(&devid)) .collect() } From e291a7f1c4c98eeba30f516d5f21e6043b635cd8 Mon Sep 17 00:00:00 2001 From: "Rivas Paz, Jose L" Date: Fri, 28 Aug 2026 08:29:14 +0200 Subject: [PATCH 2/2] app: enable control commands to trigger on all sources by default This patch enables the CLI to execute a control command on all the discoverable endpoints when no parameter was indicated with "-s" There is another change in the extraction flow as well, where the extracted data from PMT devices will be done only for the sys class PMT devices and not from the BDF devices. Signed-off-by: Rivas Paz, Jose L --- app/src/control.rs | 49 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/app/src/control.rs b/app/src/control.rs index 0967408..8bf2621 100644 --- a/app/src/control.rs +++ b/app/src/control.rs @@ -2,33 +2,66 @@ // SPDX-License-Identifier: MIT use intel_crashlog::prelude::*; +use intel_crashlog::source::Capability; pub fn rearm(sources: Vec) -> Result<(), Error> { - control_command(sources, CrashLogSource::rearm) + control_command(sources, Capability::Rearm, CrashLogSource::rearm) } pub fn trigger(sources: Vec) -> Result<(), Error> { - control_command(sources, CrashLogSource::trigger) + control_command(sources, Capability::Trigger, CrashLogSource::trigger) } pub fn clear(sources: Vec) -> Result<(), Error> { - control_command(sources, CrashLogSource::clear) + control_command(sources, Capability::Clear, CrashLogSource::clear) } pub fn enable(sources: Vec) -> Result<(), Error> { - control_command(sources, CrashLogSource::enable) + control_command(sources, Capability::EnableDisable, CrashLogSource::enable) } pub fn disable(sources: Vec) -> Result<(), Error> { - control_command(sources, CrashLogSource::disable) + control_command(sources, Capability::EnableDisable, CrashLogSource::disable) } -fn control_command(sources: Vec, control: F) -> Result<(), Error> +fn control_command( + sources: Vec, + capability: Capability, + control: F, +) -> Result<(), Error> where F: Fn(&CrashLogSource) -> Result<(), Error>, { - for source in sources { - control(&source)?; + let mut cmd_success = false; + let mut first_error = None; + + let control_sources = if sources.is_empty() { + CrashLogSource::discover_distinct() + .into_iter() + .filter(|src| src.capabilities().contains(&capability)) + .collect() + } else { + sources + }; + + if control_sources.is_empty() { + return Err(Error::NoCrashLogSourceFound); + } + + for source in control_sources { + match control(&source) { + Ok(()) => cmd_success = true, + Err(err) => { + log::warn!("Error while running {capability} command on {source}: {err}"); + if first_error.is_none() { + first_error = Some(err); + } + } + } + } + + if !cmd_success { + return Err(first_error.unwrap_or(Error::InternalError)); } Ok(())