linux_audit_parser/
event_id.rs

1#[cfg(feature = "serde")]
2use serde_with::{DeserializeFromStr, SerializeDisplay};
3
4use std::fmt::{self, Display};
5use std::str::FromStr;
6
7use thiserror::Error;
8
9/// The identifier of an audit event, corresponding to the
10/// `msg=audit(…)` part of every Linux Audit log line.
11///
12/// The event ID can reasonably be expected to be unique per system.
13#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
14#[cfg_attr(feature = "serde", derive(DeserializeFromStr, SerializeDisplay))]
15pub struct EventID {
16    /// Unix epoch-based timestamp, with mullisecond-precision
17    pub timestamp: u64,
18    /// Sequence number
19    pub sequence: u32,
20}
21
22impl Display for EventID {
23    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24        let sec = self.timestamp / 1000;
25        let msec = self.timestamp % 1000;
26        let seq = self.sequence;
27        write!(f, "{sec}.{msec:03}:{seq}")
28    }
29}
30
31/// The error type returned by [EventID::from_str]
32#[derive(Debug, Error)]
33pub enum ParseEventIDError {
34    #[error("wrong format (character '{0}' not found)")]
35    Format(char),
36    #[error("cannot parse number: {0}")]
37    Number(std::num::ParseIntError),
38}
39
40impl FromStr for EventID {
41    type Err = ParseEventIDError;
42    fn from_str(s: &str) -> Result<Self, Self::Err> {
43        let (sec, rest) = s.split_once(".").ok_or(ParseEventIDError::Format('.'))?;
44        let (msec, seq) = rest.split_once(":").ok_or(ParseEventIDError::Format(':'))?;
45        Ok(EventID {
46            timestamp: u64::from_str(sec).map_err(ParseEventIDError::Number)? * 1000
47                + u64::from_str(msec).map_err(ParseEventIDError::Number)?,
48            sequence: u32::from_str(seq).map_err(ParseEventIDError::Number)?,
49        })
50    }
51}
52
53impl PartialEq<str> for EventID {
54    fn eq(&self, other: &str) -> bool {
55        format!("{self}") == other
56    }
57}