1use std::io;
2
3use nix::{
4 errno::{Errno, Errno::EINTR},
5 libc::pid_t,
6 sys::{
7 signal::{kill, Signal, SIGKILL},
8 wait::waitpid,
9 },
10 unistd::Pid,
11};
12
13use crate::unshare::{Child, ExitStatus};
14
15impl Child {
16 #[allow(clippy::cast_sign_loss)]
18 pub fn id(&self) -> u32 {
19 self.pid as u32
20 }
21
22 pub fn pid(&self) -> pid_t {
24 self.pid
25 }
26
27 pub fn wait(&mut self) -> Result<ExitStatus, io::Error> {
29 if let Some(x) = self.status {
30 return Ok(x);
31 }
32 let status = self._wait()?;
33 self.status = Some(status);
34 Ok(status)
35 }
36
37 fn _wait(&mut self) -> Result<ExitStatus, io::Error> {
38 use nix::sys::wait::WaitStatus::*;
39 loop {
40 match waitpid(Some(Pid::from_raw(self.pid)), None) {
41 Ok(PtraceEvent(..)) => {}
42 Ok(PtraceSyscall(..)) => {}
43 Ok(Exited(x, status)) => {
44 assert!(i32::from(x) == self.pid);
45 #[allow(clippy::cast_possible_truncation)]
46 return Ok(ExitStatus::Exited(status as i8));
47 }
48 Ok(Signaled(x, sig, core)) => {
49 assert!(i32::from(x) == self.pid);
50 return Ok(ExitStatus::Signaled(sig, core));
51 }
52 Ok(Stopped(_, _)) => unreachable!(),
53 Ok(Continued(_)) => unreachable!(),
54 Ok(StillAlive) => unreachable!(),
55 Err(EINTR) => continue,
56 Err(errno) => return Err(io::Error::from_raw_os_error(errno as i32)),
57 }
58 }
59 }
60
61 pub fn signal(&self, signal: Signal) -> Result<(), Errno> {
63 if self.status.is_none() {
66 kill(Pid::from_raw(self.pid), signal)
67 } else {
68 Err(Errno::ESRCH)
70 }
71 }
72
73 pub fn kill(&self) -> Result<(), Errno> {
75 self.signal(SIGKILL)
76 }
77}