use std::ffi::OsStr;
use std::ptr::NonNull;
#[cfg(feature = "macos_10_15_4")]
use std::time::Duration;
use std::time::{Instant, SystemTime};
use endpoint_sec_sys::*;
use crate::{utils, Action, ActionResult, AuditToken, Event};
#[doc(alias = "es_message_t")]
#[repr(transparent)]
pub struct Message(NonNull<es_message_t>);
impl Message {
#[cfg_attr(
feature = "macos_11_0_0",
doc = "[`es_retain_message()`], which is basically an `Arc::clone()`."
)]
#[cfg_attr(
not(feature = "macos_11_0_0"),
doc = "`es_retain_message()`, which is basically an `Arc::clone()`."
)]
#[inline(always)]
pub unsafe fn from_raw(msg: NonNull<es_message_t>) -> Self {
let msg = versioned_call!(if cfg!(feature = "macos_11_0_0") && version >= (11, 0, 0) {
unsafe { es_retain_message(msg.as_ref()) };
msg
} else {
let msg = unsafe { es_copy_message(msg.as_ref()) };
NonNull::new(msg).expect("es_copy_message returned NULL")
});
Self(msg)
}
#[inline(always)]
pub(crate) fn get_raw_ref(&self) -> &es_message_t {
unsafe { self.0.as_ref() }
}
#[inline(always)]
pub fn version(&self) -> u32 {
self.get_raw_ref().version
}
#[inline(always)]
pub fn raw_time(&self) -> endpoint_sec_sys::timespec {
self.get_raw_ref().time
}
#[inline(always)]
pub fn time(&self) -> SystemTime {
let dur = utils::convert_timespec_to_duration(self.raw_time());
SystemTime::UNIX_EPOCH + dur
}
#[inline(always)]
pub fn raw_mach_time(&self) -> u64 {
self.get_raw_ref().mach_time
}
#[inline(always)]
pub fn mach_time(&self) -> Result<Instant, TimeError> {
utils::convert_mach_time_to_instant(self.raw_mach_time())
}
#[inline(always)]
pub fn raw_deadline(&self) -> u64 {
self.get_raw_ref().deadline
}
#[inline(always)]
pub fn deadline(&self) -> Result<Instant, TimeError> {
utils::convert_mach_time_to_instant(self.raw_deadline())
}
#[inline(always)]
pub fn process(&self) -> Process<'_> {
Process::new(
unsafe { self.get_raw_ref().process() },
self.version(),
)
}
#[cfg(feature = "macos_10_15_4")]
#[inline(always)]
pub fn seq_num(&self) -> Option<u64> {
if self.version() >= 2 {
Some(self.get_raw_ref().seq_num)
} else {
None
}
}
#[inline(always)]
pub fn action_type(&self) -> es_action_type_t {
self.get_raw_ref().action_type
}
#[inline(always)]
pub fn action(&self) -> Option<Action> {
match self.action_type() {
es_action_type_t::ES_ACTION_TYPE_AUTH => Some(Action::Auth(unsafe { self.get_raw_ref().action.auth })),
es_action_type_t::ES_ACTION_TYPE_NOTIFY => Some(Action::Notify(ActionResult::from_raw(unsafe {
self.get_raw_ref().action.notify
})?)),
_ => None,
}
}
#[inline(always)]
pub fn event_type(&self) -> es_event_type_t {
self.get_raw_ref().event_type
}
#[inline(always)]
pub fn event(&self) -> Option<Event<'_>> {
unsafe { Event::from_raw_parts(self.event_type(), &self.get_raw_ref().event, self.version()) }
}
#[cfg(feature = "macos_11_0_0")]
#[inline(always)]
pub fn thread(&self) -> Option<Thread<'_>> {
if self.version() >= 4 {
let thread_res = unsafe { self.get_raw_ref().thread.as_ref() };
thread_res.map(Thread::new)
} else {
None
}
}
#[cfg(feature = "macos_11_0_0")]
#[inline(always)]
pub fn global_seq_num(&self) -> Option<u64> {
if self.version() >= 4 {
Some(self.get_raw_ref().global_seq_num)
} else {
None
}
}
}
impl Clone for Message {
#[inline(always)]
fn clone(&self) -> Self {
unsafe { Self::from_raw(self.0) }
}
}
impl Drop for Message {
#[inline(always)]
fn drop(&mut self) {
versioned_call!(if cfg!(feature = "macos_11_0_0") && version >= (11, 0, 0) {
unsafe { es_release_message(self.0.as_ref()) };
} else {
unsafe { es_free_message(self.0.as_ref()) };
})
}
}
unsafe impl Send for Message {}
unsafe impl Sync for Message {}
impl_debug_eq_hash_with_functions!(
Message;
action_type,
action,
deadline,
event,
event_type,
#[cfg(feature = "macos_11_0_0")]
global_seq_num,
mach_time,
process,
#[cfg(feature = "macos_10_15_4")]
seq_num,
#[cfg(feature = "macos_11_0_0")]
thread,
time,
version,
);
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TimeError {
Overflow,
}
impl std::error::Error for TimeError {}
impl std::fmt::Display for TimeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Overflow => "Computing deadline overflowed",
})
}
}
#[cfg(feature = "macos_11_0_0")]
pub struct Thread<'a>(&'a es_thread_t);
#[cfg(feature = "macos_11_0_0")]
impl<'a> Thread<'a> {
#[inline(always)]
pub const fn new(raw: &'a es_thread_t) -> Self {
Thread(raw)
}
#[inline(always)]
pub fn thread_id(&self) -> u64 {
self.0.thread_id
}
}
#[cfg(feature = "macos_11_0_0")]
unsafe impl Send for Thread<'_> {}
#[cfg(feature = "macos_11_0_0")]
impl_debug_eq_hash_with_functions!(Thread<'a>; thread_id);
pub struct File<'a>(&'a es_file_t);
impl<'a> File<'a> {
#[inline(always)]
pub const fn new(raw: &'a es_file_t) -> Self {
File(raw)
}
#[inline(always)]
pub fn path(&self) -> &'a OsStr {
unsafe { self.0.path.as_os_str() }
}
#[inline(always)]
pub fn path_truncated(&self) -> bool {
self.0.path_truncated
}
#[inline(always)]
pub fn stat(&self) -> &'a stat {
&self.0.stat
}
}
unsafe impl Send for File<'_> {}
impl_debug_eq_hash_with_functions!(File<'a>; path, path_truncated, stat);
pub struct Process<'a> {
raw: &'a es_process_t,
version: u32,
}
impl<'a> Process<'a> {
#[inline(always)]
pub const fn new(raw: &'a es_process_t, version: u32) -> Self {
Process { raw, version }
}
#[inline(always)]
pub fn audit_token(&self) -> AuditToken {
AuditToken::new(self.raw.audit_token)
}
#[cfg_attr(
feature = "macos_11_0_0",
doc = "**Warning**: It is recommended to instead use [`Self::parent_audit_token()`] when available."
)]
#[cfg_attr(
not(feature = "macos_11_0_0"),
doc = "**Warning**: It is recommended to instead use `Self::parent_audit_token()` when available."
)]
#[inline(always)]
pub fn ppid(&self) -> pid_t {
self.raw.ppid
}
#[inline(always)]
pub fn original_ppid(&self) -> pid_t {
self.raw.original_ppid
}
#[inline(always)]
pub fn group_id(&self) -> pid_t {
self.raw.group_id
}
#[inline(always)]
pub fn session_id(&self) -> pid_t {
self.raw.session_id
}
#[inline(always)]
pub fn codesigning_flags(&self) -> u32 {
self.raw.codesigning_flags
}
#[inline(always)]
pub fn is_platform_binary(&self) -> bool {
self.raw.is_platform_binary
}
#[inline(always)]
pub fn is_es_client(&self) -> bool {
self.raw.is_es_client
}
#[inline(always)]
pub fn cdhash(&self) -> [u8; 20] {
self.raw.cdhash
}
#[inline(always)]
pub fn signing_id(&self) -> &'a OsStr {
unsafe { self.raw.signing_id.as_os_str() }
}
#[inline(always)]
pub fn team_id(&self) -> &'a OsStr {
unsafe { self.raw.team_id.as_os_str() }
}
#[inline(always)]
pub fn executable(&self) -> File<'a> {
File::new(unsafe { self.raw.executable() })
}
#[cfg(feature = "macos_10_15_1")]
#[inline(always)]
pub fn tty(&self) -> Option<File<'a>> {
if self.version >= 2 {
unsafe { self.raw.tty.as_ref() }.map(File::new)
} else {
None
}
}
#[cfg(feature = "macos_10_15_4")]
#[inline(always)]
pub fn start_time(&self) -> Option<SystemTime> {
if self.version >= 3 {
let timestamp = Duration::from_secs(self.raw.start_time.tv_sec as u64)
+ Duration::from_micros(self.raw.start_time.tv_usec as u64);
if let Some(system_time) = SystemTime::UNIX_EPOCH.checked_add(timestamp) {
Some(system_time)
} else {
Some(SystemTime::UNIX_EPOCH)
}
} else {
None
}
}
#[cfg(feature = "macos_11_0_0")]
#[inline(always)]
pub fn responsible_audit_token(&self) -> Option<AuditToken> {
if self.version >= 4 {
Some(AuditToken::new(self.raw.responsible_audit_token))
} else {
None
}
}
#[cfg(feature = "macos_11_0_0")]
#[inline(always)]
pub fn parent_audit_token(&self) -> Option<AuditToken> {
if self.version >= 4 {
Some(AuditToken::new(self.raw.parent_audit_token))
} else {
None
}
}
}
unsafe impl Send for Process<'_> {}
impl_debug_eq_hash_with_functions!(
Process<'a> with version;
audit_token,
cdhash,
codesigning_flags,
executable,
group_id,
is_es_client,
is_platform_binary,
original_ppid,
#[cfg(feature = "macos_11_0_0")]
parent_audit_token,
ppid,
#[cfg(feature = "macos_11_0_0")]
responsible_audit_token,
session_id,
signing_id,
#[cfg(feature = "macos_10_15_4")]
start_time,
team_id,
#[cfg(feature = "macos_10_15_1")]
tty,
);
#[cfg(feature = "macos_11_0_0")]
pub struct ThreadState<'a>(&'a es_thread_state_t);
#[cfg(feature = "macos_11_0_0")]
impl<'a> ThreadState<'a> {
#[inline(always)]
pub const fn new(raw: &'a es_thread_state_t) -> Self {
ThreadState(raw)
}
#[inline(always)]
pub fn flavor(&self) -> i32 {
self.0.flavor
}
#[inline(always)]
pub fn state(&self) -> &'a [u8] {
unsafe { self.0.state.as_slice() }
}
}
#[cfg(feature = "macos_11_0_0")]
unsafe impl Send for ThreadState<'_> {}
#[cfg(feature = "macos_11_0_0")]
impl_debug_eq_hash_with_functions!(ThreadState<'a>; flavor, state);