use posish::fs::{getfd, setfd, FdFlags};
use std::{fs, io};
pub(crate) fn ensure_cloexec(file: &fs::File) -> io::Result<()> {
use std::sync::atomic::{AtomicUsize, Ordering};
const OPEN_CLOEXEC_UNKNOWN: usize = 0;
const OPEN_CLOEXEC_SUPPORTED: usize = 1;
const OPEN_CLOEXEC_NOTSUPPORTED: usize = 2;
static OPEN_CLOEXEC: AtomicUsize = AtomicUsize::new(OPEN_CLOEXEC_UNKNOWN);
let need_to_set;
match OPEN_CLOEXEC.load(Ordering::Relaxed) {
OPEN_CLOEXEC_UNKNOWN => {
need_to_set = !get_cloexec(file)?;
OPEN_CLOEXEC.store(
if need_to_set {
OPEN_CLOEXEC_NOTSUPPORTED
} else {
OPEN_CLOEXEC_SUPPORTED
},
Ordering::Relaxed,
);
}
OPEN_CLOEXEC_SUPPORTED => need_to_set = false,
OPEN_CLOEXEC_NOTSUPPORTED => need_to_set = true,
_ => unreachable!(),
}
if need_to_set {
set_cloexec(file)?;
}
Ok(())
}
fn get_cloexec(file: &fs::File) -> io::Result<bool> {
Ok(getfd(file)?.contains(FdFlags::CLOEXEC))
}
fn set_cloexec(file: &fs::File) -> io::Result<()> {
let previous = getfd(file)?;
let new = previous | FdFlags::CLOEXEC;
if new != previous {
setfd(file, new)?;
}
Ok(())
}