#![cfg(target_os = "linux")]
#![allow(unsafe_code)]
use std::ffi::CString;
use std::io;
use crate::probes::now_monotonic_ns;
use crate::{probe_source, ProbeEvent};
pub struct InotifyProbe {
fd: libc::c_int,
self_comm: String,
}
impl InotifyProbe {
pub fn open(path: &str, self_comm: impl Into<String>) -> io::Result<Self> {
let fd = unsafe { libc::inotify_init1(libc::IN_NONBLOCK | libc::IN_CLOEXEC) };
if fd < 0 {
return Err(io::Error::last_os_error());
}
let cpath =
CString::new(path).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
let mask = libc::IN_MODIFY | libc::IN_CREATE | libc::IN_DELETE | libc::IN_ATTRIB;
let wd = unsafe { libc::inotify_add_watch(fd, cpath.as_ptr(), mask as u32) };
if wd < 0 {
let err = io::Error::last_os_error();
unsafe { libc::close(fd) };
return Err(err);
}
Ok(Self {
fd,
self_comm: self_comm.into(),
})
}
pub fn poll(&mut self) -> Vec<ProbeEvent> {
let mut out = Vec::new();
let mut buf = [0u8; 4096];
loop {
let n =
unsafe { libc::read(self.fd, buf.as_mut_ptr() as *mut libc::c_void, buf.len()) };
if n <= 0 {
break;
}
out.push(ProbeEvent {
probe_source: probe_source::FS_INOTIFY_FIRED,
guest_pid: std::process::id(),
guest_comm: self.self_comm.clone(),
guest_monotonic_ns: now_monotonic_ns(),
});
}
out
}
}
impl Drop for InotifyProbe {
fn drop(&mut self) {
if self.fd >= 0 {
unsafe {
libc::close(self.fd);
}
}
}
}