use std::io;
use nix::{
errno::{Errno, Errno::EINTR},
libc::pid_t,
sys::{
signal::{kill, Signal, SIGKILL},
wait::waitpid,
},
unistd::Pid,
};
use crate::unshare::{Child, ExitStatus};
impl Child {
#[expect(clippy::cast_sign_loss)]
pub fn id(&self) -> u32 {
self.pid as u32
}
pub fn pid(&self) -> pid_t {
self.pid
}
pub fn wait(&mut self) -> Result<ExitStatus, io::Error> {
if let Some(x) = self.status {
return Ok(x);
}
let status = self._wait()?;
self.status = Some(status);
Ok(status)
}
fn _wait(&mut self) -> Result<ExitStatus, io::Error> {
use nix::sys::wait::WaitStatus::*;
loop {
match waitpid(Some(Pid::from_raw(self.pid)), None) {
Ok(PtraceEvent(..)) => {}
Ok(PtraceSyscall(..)) => {}
Ok(Exited(x, status)) => {
assert!(i32::from(x) == self.pid);
#[expect(clippy::cast_possible_truncation)]
return Ok(ExitStatus::Exited(status as i8));
}
Ok(Signaled(x, sig, core)) => {
assert!(i32::from(x) == self.pid);
return Ok(ExitStatus::Signaled(sig, core));
}
Ok(Stopped(_, _)) => unreachable!(),
Ok(Continued(_)) => unreachable!(),
Ok(StillAlive) => unreachable!(),
Err(EINTR) => continue,
Err(errno) => return Err(io::Error::from_raw_os_error(errno as i32)),
}
}
}
pub fn signal(&self, signal: Signal) -> Result<(), Errno> {
if self.status.is_none() {
kill(Pid::from_raw(self.pid), signal)
} else {
Err(Errno::ESRCH)
}
}
pub fn kill(&self) -> Result<(), Errno> {
self.signal(SIGKILL)
}
}