diff --git a/README.md b/README.md index e66102c..c8a072c 100644 --- a/README.md +++ b/README.md @@ -135,14 +135,15 @@ $ iclg extract -s acpi,pmt:crashlog0 ``` - **List** all available Crash Log sources in the platform. Each source -supports different capabilities like `extract`, `trigger`, or `enable/disable`. +supports different capabilities like `extract`, `trigger`, `enable/disable`, +or `rearm`. ```console $ iclg list Source Description Capabilities -------------- ---------------------- --------------------------------- +------------- ---------------------- --------------------------------------- acpi ACPI BERT extract -pmt:crashlog0 PMT endpoint crashlog0 extract, trigger, enable/disable +pmt:crashlog0 PMT endpoint crashlog0 extract, trigger, enable/disable, rearm ``` - **Trigger** a Crash Log collection on-demand. Like the `extract` command, @@ -153,6 +154,16 @@ command is only supported on Linux. $ iclg trigger ``` +- **Rearm** a Crash Log trigger. A source can trigger a Crash Log collection +only once per reset cycle; after a collection has been captured, the source +must be reset and rearmed before it will trigger again. Like the `trigger` +command, you can specify individual sources or rearm all sources by default. +This command is only supported on Linux. + +```console +$ iclg rearm +``` + - **Enable** or **Disable** the Crash Log collection in the platform. Individual sources can be specified in the CLI as well. These commands are only supported on Linux. @@ -189,18 +200,19 @@ $ iclg decode sample.crashlog $ iclg --help Extract and decode Intel Crash Log records. -Usage: iclg [OPTIONS] [COMMAND] +Usage: iclg [OPTIONS] Commands: - enable Enable the Crash Log collection in the platform + enable Enable Crash Log collection in the platform extract Extract the Crash Log records from the platform decode Decode Crash Log records into JSON - disable Disable the Crash Log collection in the platform + disable Disable Crash Log collection in the platform info List the Crash Log records stored in the input file - list List the Crash Log sources that are present in the platform + list List the Crash Log sources that are available in the platform + rearm Rearm a Crash Log trigger in the platform + trigger Trigger an on-demand Crash Log collection in the platform unpack Unpack the Crash Log records stored in the input file triage Triage the Crash Log records stored in the input files - trigger Trigger an on-demand collection of Crash Log in the platform help Print this message or the help of the given subcommand(s) Options: diff --git a/app/src/control.rs b/app/src/control.rs index b092fae..0967408 100644 --- a/app/src/control.rs +++ b/app/src/control.rs @@ -3,6 +3,10 @@ use intel_crashlog::prelude::*; +pub fn rearm(sources: Vec) -> Result<(), Error> { + control_command(sources, CrashLogSource::rearm) +} + pub fn trigger(sources: Vec) -> Result<(), Error> { control_command(sources, CrashLogSource::trigger) } diff --git a/app/src/main.rs b/app/src/main.rs index 1d732f4..a5be611 100644 --- a/app/src/main.rs +++ b/app/src/main.rs @@ -67,6 +67,11 @@ enum Command { }, /// List the Crash Log sources that are available in the platform with their capabilities List, + /// Rearm a Crash Log trigger in the platform + Rearm { + #[arg(short, long, value_delimiter = ',')] + sources: Vec, + }, /// Trigger an on-demand Crash Log collection in the platform Trigger { #[arg(short, long, value_delimiter = ',')] @@ -100,6 +105,7 @@ impl Command { format, } => info::info(&cm, input_files, *format), Command::List => list::list(), + Command::Rearm { sources } => control::rearm(sources.clone())?, Command::Trigger { sources } => control::trigger(sources.clone())?, Command::Clear { sources } => control::clear(sources.clone())?, Command::Unpack { input_files } => { diff --git a/lib/src/source.rs b/lib/src/source.rs index d2b1bf0..ab1c9f9 100644 --- a/lib/src/source.rs +++ b/lib/src/source.rs @@ -182,6 +182,15 @@ impl CrashLogSource { } } + /// Rearms a Crash Log trigger on this source + #[cfg(feature = "control_commands")] + pub fn rearm(&self) -> Result<(), Error> { + match self { + Self::PmtDevice(dev) => Pmt::default().rearm(dev), + _ => Err(Error::Unsupported), + } + } + /// Clears the Crash Log storage on this source #[cfg(feature = "control_commands")] pub fn clear(&self) -> Result<(), Error> { diff --git a/lib/src/source/capability.rs b/lib/src/source/capability.rs index 3423644..4bc95d0 100644 --- a/lib/src/source/capability.rs +++ b/lib/src/source/capability.rs @@ -17,6 +17,8 @@ pub enum Capability { EnableDisable, /// Clearing of the Crash Log storage Clear, + /// Rearming of the Crash Log trigger + Rearm, } impl fmt::Display for Capability { @@ -26,6 +28,7 @@ impl fmt::Display for Capability { Self::Trigger => write!(f, "trigger"), Self::EnableDisable => write!(f, "enable/disable"), Self::Clear => write!(f, "clear"), + Self::Rearm => write!(f, "rearm"), } } } diff --git a/lib/src/source/pmt.rs b/lib/src/source/pmt.rs index f25c623..cc4ea9f 100644 --- a/lib/src/source/pmt.rs +++ b/lib/src/source/pmt.rs @@ -111,6 +111,19 @@ impl Pmt { Err(Error::Unsupported) } + #[cfg(all(target_os = "linux", feature = "control_commands"))] + pub fn rearm(&self, dev: &PmtDeviceId) -> Result<(), Error> { + for endpoint in self.sysfs.get_endpoints(dev) { + endpoint.rearm()?; + } + Ok(()) + } + + #[cfg(all(not(target_os = "linux"), feature = "control_commands"))] + pub fn rearm(&self, _dev: &PmtDeviceId) -> Result<(), Error> { + Err(Error::Unsupported) + } + #[cfg(all(target_os = "linux", feature = "control_commands"))] pub fn trigger(&self, dev: &PmtDeviceId) -> Result<(), Error> { for endpoint in self.sysfs.get_endpoints(dev) { diff --git a/lib/src/source/pmt/sysfs.rs b/lib/src/source/pmt/sysfs.rs index 96111b8..3dceff7 100644 --- a/lib/src/source/pmt/sysfs.rs +++ b/lib/src/source/pmt/sysfs.rs @@ -248,6 +248,11 @@ impl PmtSysFsEndpoint { self.write_command("trigger", b"1") } + #[cfg(feature = "control_commands")] + pub fn rearm(&self) -> Result<(), Error> { + self.write_command("rearm", b"1") + } + #[cfg(feature = "control_commands")] pub fn clear(&self) -> Result<(), Error> { self.write_command("clear", b"1") @@ -295,6 +300,10 @@ impl PmtSysFsEndpoint { capabilities.insert(Capability::Clear); } + if self.path.join("rearm").exists() { + capabilities.insert(Capability::Rearm); + } + capabilities } @@ -435,6 +444,21 @@ mod tests { assert_eq!(&std::fs::read_to_string(&path).unwrap(), "1"); } + #[test] + fn rearm() { + let root = tempfile::tempdir().unwrap(); + + let dev = PmtSysFsEndpoint::new(root.path()).unwrap(); + assert!(matches!(dev.rearm(), Err(Error::IOError(_)))); + + let mut path = root.path().to_owned(); + path.push("rearm"); + std::fs::write(&path, b"0").unwrap(); + + dev.rearm().unwrap(); + assert_eq!(&std::fs::read_to_string(&path).unwrap(), "1"); + } + #[test] fn enable_disable() { let root = tempfile::tempdir().unwrap(); @@ -475,13 +499,18 @@ mod tests { trigger_path.push("trigger"); std::fs::create_dir(&trigger_path).unwrap(); + let mut rearm_path = dev_path.to_owned(); + rearm_path.push("rearm"); + std::fs::create_dir(&rearm_path).unwrap(); + let devices = sysfs.discover(); let dev = sysfs.get_endpoints(&devices[0]); let dev_capabilities = dev[0].capabilities(); - assert_eq!(dev_capabilities.len(), 2); + assert_eq!(dev_capabilities.len(), 3); assert!(dev_capabilities.contains(&Capability::Extract)); assert!(dev_capabilities.contains(&Capability::Trigger)); + assert!(dev_capabilities.contains(&Capability::Rearm)); } #[test]