use std::{io, mem::MaybeUninit, ptr};
use super::AnchorCreation;
#[derive(Debug)]
pub(in crate::group_guard) struct PreparedAnchor {
attributes: libc::posix_spawnattr_t,
}
impl AnchorCreation for PreparedAnchor {
fn prepare() -> io::Result<Self> {
let mut attributes = MaybeUninit::<libc::posix_spawnattr_t>::uninit();
spawn_result(unsafe { libc::posix_spawnattr_init(attributes.as_mut_ptr()) })?;
let mut spawn = Self {
attributes: unsafe { attributes.assume_init() },
};
let mut defaults: libc::sigset_t = unsafe { std::mem::zeroed() };
let mut mask: libc::sigset_t = unsafe { std::mem::zeroed() };
if unsafe { libc::sigfillset(&raw mut defaults) } != 0
|| unsafe { libc::sigdelset(&raw mut defaults, libc::SIGKILL) } != 0
|| unsafe { libc::sigdelset(&raw mut defaults, libc::SIGSTOP) } != 0
|| unsafe { libc::sigemptyset(&raw mut mask) } != 0
{
return Err(io::Error::last_os_error());
}
let flags = libc::c_short::try_from(spawn_flags())
.map_err(|error| io::Error::new(io::ErrorKind::InvalidInput, error))?;
spawn_result(unsafe {
libc::posix_spawnattr_setsigdefault(&raw mut spawn.attributes, &raw const defaults)
})?;
spawn_result(unsafe {
libc::posix_spawnattr_setsigmask(&raw mut spawn.attributes, &raw const mask)
})?;
spawn_result(unsafe { libc::posix_spawnattr_setpgroup(&raw mut spawn.attributes, 0) })?;
spawn_result(unsafe { libc::posix_spawnattr_setflags(&raw mut spawn.attributes, flags) })?;
Ok(spawn)
}
fn child_create(&self) -> Result<libc::pid_t, libc::c_int> {
let mut anchor: libc::pid_t = 0;
let argv = [c"true".as_ptr().cast_mut(), ptr::null_mut()];
let envp = [ptr::null_mut::<libc::c_char>()];
let result = unsafe {
libc::posix_spawn(
&raw mut anchor,
c"/usr/bin/true".as_ptr(),
ptr::null(),
&raw const self.attributes,
argv.as_ptr(),
envp.as_ptr(),
)
};
match (result, anchor) {
(0, anchor) if anchor > 0 => Ok(anchor),
(0, _) => Err(libc::EIO),
(error, _) => Err(error),
}
}
}
impl Drop for PreparedAnchor {
fn drop(&mut self) {
let _ = unsafe { libc::posix_spawnattr_destroy(&raw mut self.attributes) };
}
}
#[cfg(target_vendor = "apple")]
const fn spawn_flags() -> libc::c_int {
libc::POSIX_SPAWN_SETPGROUP
| libc::POSIX_SPAWN_SETSIGDEF
| libc::POSIX_SPAWN_SETSIGMASK
| libc::POSIX_SPAWN_CLOEXEC_DEFAULT
}
#[cfg(not(target_vendor = "apple"))]
const fn spawn_flags() -> libc::c_int {
libc::POSIX_SPAWN_SETPGROUP | libc::POSIX_SPAWN_SETSIGDEF | libc::POSIX_SPAWN_SETSIGMASK
}
fn spawn_result(result: libc::c_int) -> io::Result<()> {
if result == 0 {
Ok(())
} else {
Err(io::Error::from_raw_os_error(result))
}
}