#[cfg(unix)]
use std::time::Duration;
use std::time::Instant;
#[cfg(unix)]
use std::os::fd::{AsRawFd, OwnedFd};
#[cfg(unix)]
pub fn drain_with_deadline(fd: &OwnedFd, deadline: Instant) -> (Vec<u8>, bool) {
let raw = fd.as_raw_fd();
let orig = unsafe { libc::fcntl(raw, libc::F_GETFL) };
unsafe {
libc::fcntl(raw, libc::F_SETFL, orig | libc::O_NONBLOCK);
}
struct Restore {
fd: i32,
flags: i32,
}
impl Drop for Restore {
fn drop(&mut self) {
unsafe {
libc::fcntl(self.fd, libc::F_SETFL, self.flags);
}
}
}
let _restore = Restore {
fd: raw,
flags: orig,
};
let mut out = Vec::new();
let mut buf = [0u8; 8192];
loop {
let n = unsafe { libc::read(raw, buf.as_mut_ptr().cast(), buf.len()) };
if n > 0 {
out.extend_from_slice(&buf[..n as usize]);
continue;
}
if n == 0 {
return (out, true);
}
let err = std::io::Error::last_os_error();
if let Some(code) = err.raw_os_error() {
if code == libc::EAGAIN || code == libc::EWOULDBLOCK {
if Instant::now() >= deadline {
return (out, false);
}
std::thread::sleep(Duration::from_millis(10));
continue;
}
if code == libc::EINTR {
continue;
}
}
return (out, false);
}
}
#[cfg(not(unix))]
pub fn drain_with_deadline(
_fd: &std::os::windows::io::OwnedHandle,
_deadline: Instant,
) -> (Vec<u8>, bool) {
(Vec::new(), false)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PostMortem {
Absent,
Present,
}
impl PostMortem {
pub fn stat(path: &std::path::Path, expect_empty_file: bool) -> Self {
match std::fs::metadata(path) {
Err(_) => PostMortem::Absent,
Ok(meta) => {
if expect_empty_file || meta.len() == 0 {
PostMortem::Absent
} else {
PostMortem::Present
}
}
}
}
}
#[cfg(test)]
mod collector_tests {
use super::*;
#[test]
fn postmortem_absent_for_missing() {
let p = std::env::temp_dir().join("vetto-vng-no-such-file-xyz");
assert_eq!(PostMortem::stat(&p, false), PostMortem::Absent);
}
#[test]
fn postmortem_present_for_content() {
let p = std::env::temp_dir().join(format!("vetto-vng-pm-{}", std::process::id()));
std::fs::write(&p, b"leak").expect("write");
assert_eq!(PostMortem::stat(&p, false), PostMortem::Present);
let _ = std::fs::remove_file(&p);
}
}