use std::{ffi::CStr, mem, os::fd::RawFd};
#[cfg(any(feature = "fs", feature = "term"))]
use crate::fcntl::OFlag;
#[cfg(feature = "signal")]
use crate::sys::signal::SigSet;
#[cfg(feature = "fs")]
use crate::sys::stat::Mode;
use crate::{errno::Errno, unistd::Pid, NixPath, Result};
#[repr(transparent)]
#[derive(Debug)]
pub struct PosixSpawnAttr {
attr: libc::posix_spawnattr_t,
}
impl PosixSpawnAttr {
#[doc(alias("posix_spawnattr_init"))]
pub fn init() -> Result<PosixSpawnAttr> {
let mut attr = mem::MaybeUninit::uninit();
let res = unsafe { libc::posix_spawnattr_init(attr.as_mut_ptr()) };
Errno::result(res)?;
let attr = unsafe { attr.assume_init() };
Ok(PosixSpawnAttr { attr })
}
#[doc(alias("posix_spawnattr_destroy"))]
pub fn reinit(mut self) -> Result<PosixSpawnAttr> {
let res = unsafe {
libc::posix_spawnattr_destroy(
&mut self.attr as *mut libc::posix_spawnattr_t,
)
};
Errno::result(res)?;
let res = unsafe {
libc::posix_spawnattr_init(
&mut self.attr as *mut libc::posix_spawnattr_t,
)
};
Errno::result(res)?;
Ok(self)
}
#[doc(alias("posix_spawnattr_setflags"))]
pub fn set_flags(&mut self, flags: PosixSpawnFlags) -> Result<()> {
let res = unsafe {
libc::posix_spawnattr_setflags(
&mut self.attr as *mut libc::posix_spawnattr_t,
flags.bits() as libc::c_short,
)
};
Errno::result(res)?;
Ok(())
}
#[doc(alias("posix_spawnattr_getflags"))]
pub fn flags(&self) -> Result<PosixSpawnFlags> {
let mut flags: libc::c_short = 0;
let res = unsafe {
libc::posix_spawnattr_getflags(
&self.attr as *const libc::posix_spawnattr_t,
&mut flags,
)
};
Errno::result(res)?;
Ok(PosixSpawnFlags::from_bits_truncate(flags.into()))
}
#[doc(alias("posix_spawnattr_setpgroup"))]
pub fn set_pgroup(&mut self, pgroup: Pid) -> Result<()> {
let res = unsafe {
libc::posix_spawnattr_setpgroup(
&mut self.attr as *mut libc::posix_spawnattr_t,
pgroup.as_raw(),
)
};
Errno::result(res)?;
Ok(())
}
#[doc(alias("posix_spawnattr_getpgroup"))]
pub fn pgroup(&self) -> Result<Pid> {
let mut pid: libc::pid_t = 0;
let res = unsafe {
libc::posix_spawnattr_getpgroup(
&self.attr as *const libc::posix_spawnattr_t,
&mut pid,
)
};
Errno::result(res)?;
Ok(Pid::from_raw(pid))
}
feature! {
#![feature = "signal"]
#[doc(alias("posix_spawnattr_setsigdefault"))]
pub fn set_sigdefault(&mut self, sigdefault: &SigSet) -> Result<()> {
let res = unsafe {
libc::posix_spawnattr_setsigdefault(
&mut self.attr as *mut libc::posix_spawnattr_t,
sigdefault.as_ref(),
)
};
Errno::result(res)?;
Ok(())
}
#[doc(alias("posix_spawnattr_getsigdefault"))]
pub fn sigdefault(&self) -> Result<SigSet> {
let mut sigset = mem::MaybeUninit::uninit();
let res = unsafe {
libc::posix_spawnattr_getsigdefault(
&self.attr as *const libc::posix_spawnattr_t,
sigset.as_mut_ptr(),
)
};
Errno::result(res)?;
let sigdefault =
unsafe { SigSet::from_sigset_t_unchecked(sigset.assume_init()) };
Ok(sigdefault)
}
#[doc(alias("posix_spawnattr_setsigmask"))]
pub fn set_sigmask(&mut self, sigdefault: &SigSet) -> Result<()> {
let res = unsafe {
libc::posix_spawnattr_setsigmask(
&mut self.attr as *mut libc::posix_spawnattr_t,
sigdefault.as_ref(),
)
};
Errno::result(res)?;
Ok(())
}
#[doc(alias("posix_spawnattr_getsigmask"))]
pub fn sigmask(&self) -> Result<SigSet> {
let mut sigset = mem::MaybeUninit::uninit();
let res = unsafe {
libc::posix_spawnattr_getsigmask(
&self.attr as *const libc::posix_spawnattr_t,
sigset.as_mut_ptr(),
)
};
Errno::result(res)?;
let sigdefault =
unsafe { SigSet::from_sigset_t_unchecked(sigset.assume_init()) };
Ok(sigdefault)
}
}
}
impl Drop for PosixSpawnAttr {
fn drop(&mut self) {
unsafe {
libc::posix_spawnattr_destroy(
&mut self.attr as *mut libc::posix_spawnattr_t,
);
}
}
}
libc_bitflags!(
pub struct PosixSpawnFlags: libc::c_int {
POSIX_SPAWN_RESETIDS;
POSIX_SPAWN_SETPGROUP;
#[cfg(feature = "signal")]
POSIX_SPAWN_SETSIGDEF;
#[cfg(feature = "signal")]
POSIX_SPAWN_SETSIGMASK;
}
);
#[repr(transparent)]
#[derive(Debug)]
pub struct PosixSpawnFileActions {
fa: libc::posix_spawn_file_actions_t,
}
impl PosixSpawnFileActions {
#[doc(alias("posix_spawn_file_actions_init"))]
pub fn init() -> Result<PosixSpawnFileActions> {
let mut actions = mem::MaybeUninit::uninit();
let res = unsafe {
libc::posix_spawn_file_actions_init(actions.as_mut_ptr())
};
Errno::result(res)?;
Ok(unsafe {
PosixSpawnFileActions {
fa: actions.assume_init(),
}
})
}
#[doc(alias("posix_spawn_file_actions_destroy"))]
pub fn reinit(mut self) -> Result<PosixSpawnFileActions> {
let res = unsafe {
libc::posix_spawn_file_actions_destroy(
&mut self.fa as *mut libc::posix_spawn_file_actions_t,
)
};
Errno::result(res)?;
let res = unsafe {
libc::posix_spawn_file_actions_init(
&mut self.fa as *mut libc::posix_spawn_file_actions_t,
)
};
Errno::result(res)?;
Ok(self)
}
#[doc(alias("posix_spawn_file_actions_adddup2"))]
pub fn add_dup2(&mut self, fd: RawFd, newfd: RawFd) -> Result<()> {
let res = unsafe {
libc::posix_spawn_file_actions_adddup2(
&mut self.fa as *mut libc::posix_spawn_file_actions_t,
fd,
newfd,
)
};
Errno::result(res)?;
Ok(())
}
feature! {
#![all(feature = "fs", feature = "term")]
#[doc(alias("posix_spawn_file_actions_addopen"))]
pub fn add_open<P: ?Sized + NixPath>(
&mut self,
fd: RawFd,
path: &P,
oflag: OFlag,
mode: Mode,
) -> Result<()> {
let res = path.with_nix_path(|cstr| unsafe {
libc::posix_spawn_file_actions_addopen(
&mut self.fa as *mut libc::posix_spawn_file_actions_t,
fd,
cstr.as_ptr(),
oflag.bits(),
mode.bits(),
)
})?;
Errno::result(res)?;
Ok(())
}
}
#[doc(alias("posix_spawn_file_actions_addclose"))]
pub fn add_close(&mut self, fd: RawFd) -> Result<()> {
let res = unsafe {
libc::posix_spawn_file_actions_addclose(
&mut self.fa as *mut libc::posix_spawn_file_actions_t,
fd,
)
};
Errno::result(res)?;
Ok(())
}
}
impl Drop for PosixSpawnFileActions {
fn drop(&mut self) {
unsafe {
libc::posix_spawn_file_actions_destroy(
&mut self.fa as *mut libc::posix_spawn_file_actions_t,
);
}
}
}
unsafe fn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*mut libc::c_char> {
let mut v: Vec<*mut libc::c_char> = args
.iter()
.map(|s| s.as_ref().as_ptr().cast_mut())
.collect();
v.push(std::ptr::null_mut());
v
}
pub fn posix_spawn<P, SA, SE>(
path: &P,
file_actions: &PosixSpawnFileActions,
attr: &PosixSpawnAttr,
args: &[SA],
envp: &[SE],
) -> Result<Pid>
where
P: NixPath + ?Sized,
SA: AsRef<CStr>,
SE: AsRef<CStr>,
{
let mut pid = 0;
let ret = unsafe {
let args_p = to_exec_array(args);
let env_p = to_exec_array(envp);
path.with_nix_path(|c_str| {
libc::posix_spawn(
&mut pid as *mut libc::pid_t,
c_str.as_ptr(),
&file_actions.fa as *const libc::posix_spawn_file_actions_t,
&attr.attr as *const libc::posix_spawnattr_t,
args_p.as_ptr(),
env_p.as_ptr(),
)
})?
};
if ret != 0 {
return Err(Errno::from_raw(ret));
}
Ok(Pid::from_raw(pid))
}
pub fn posix_spawnp<SA: AsRef<CStr>, SE: AsRef<CStr>>(
path: &CStr,
file_actions: &PosixSpawnFileActions,
attr: &PosixSpawnAttr,
args: &[SA],
envp: &[SE],
) -> Result<Pid> {
let mut pid = 0;
let ret = unsafe {
let args_p = to_exec_array(args);
let env_p = to_exec_array(envp);
libc::posix_spawnp(
&mut pid as *mut libc::pid_t,
path.as_ptr(),
&file_actions.fa as *const libc::posix_spawn_file_actions_t,
&attr.attr as *const libc::posix_spawnattr_t,
args_p.as_ptr(),
env_p.as_ptr(),
)
};
if ret != 0 {
return Err(Errno::from_raw(ret));
}
Ok(Pid::from_raw(pid))
}