c_scape/process/
wait.rs

1use core::mem::zeroed;
2use errno::{set_errno, Errno};
3use libc::{c_int, id_t, idtype_t, pid_t, siginfo_t};
4use rustix::fd::BorrowedFd;
5use rustix::process::{Pid, WaitId, WaitIdOptions, WaitOptions};
6
7use crate::convert_res;
8
9#[no_mangle]
10unsafe extern "C" fn waitpid(pid: c_int, status: *mut c_int, options: c_int) -> c_int {
11    libc!(libc::waitpid(pid, status, options));
12    let options = WaitOptions::from_bits(options as _).unwrap();
13    let ret_pid;
14    let ret_status;
15    match pid {
16        -1 => match convert_res(rustix::process::wait(options)) {
17            Some(Some((new_pid, new_status))) => {
18                ret_pid = new_pid.as_raw_nonzero().get() as c_int;
19                ret_status = new_status.as_raw() as c_int;
20            }
21            Some(None) => return 0,
22            None => return -1,
23        },
24        pid if pid == pid_t::MIN => {
25            set_errno(Errno(libc::ESRCH));
26            return -1;
27        }
28        pid if pid < 0 => match convert_res(rustix::process::waitpgid(
29            Pid::from_raw_unchecked(pid.wrapping_neg()),
30            options,
31        )) {
32            Some(Some(new_status)) => {
33                ret_pid = if pid == 0 {
34                    rustix::process::getpid().as_raw_nonzero().get() as c_int
35                } else {
36                    pid
37                };
38                ret_status = new_status.1.as_raw() as c_int;
39            }
40            Some(None) => return 0,
41            None => return -1,
42        },
43        pid => match convert_res(rustix::process::waitpid(Pid::from_raw(pid as _), options)) {
44            Some(Some(new_status)) => {
45                ret_pid = if pid == 0 {
46                    rustix::process::getpid().as_raw_nonzero().get() as c_int
47                } else {
48                    pid
49                };
50                ret_status = new_status.1.as_raw() as c_int;
51            }
52            Some(None) => return 0,
53            None => return -1,
54        },
55    }
56    if !status.is_null() {
57        status.write(ret_status);
58    }
59    ret_pid
60}
61
62#[no_mangle]
63unsafe extern "C" fn wait(status: *mut c_int) -> pid_t {
64    libc!(libc::wait(status));
65    waitpid(-1, status, 0)
66}
67
68#[no_mangle]
69unsafe extern "C" fn waitid(
70    idtype: idtype_t,
71    id: id_t,
72    infop: *mut siginfo_t,
73    options: c_int,
74) -> c_int {
75    libc!(libc::waitid(idtype, id, infop, options));
76
77    let id = match idtype {
78        libc::P_PID => {
79            if let Some(pid) = Pid::from_raw(id as _) {
80                WaitId::Pid(pid)
81            } else {
82                set_errno(Errno(libc::EINVAL));
83                return -1;
84            }
85        }
86        libc::P_PIDFD => WaitId::PidFd(BorrowedFd::borrow_raw(id as _)),
87        libc::P_PGID => WaitId::Pgid(Pid::from_raw(id as _)),
88        libc::P_ALL => WaitId::All,
89        _ => {
90            set_errno(Errno(libc::EINVAL));
91            return -1;
92        }
93    };
94
95    let options = WaitIdOptions::from_bits(options as _).unwrap();
96
97    match convert_res(rustix::process::waitid(id, options)) {
98        Some(Some(new_info)) => {
99            *infop = zeroed();
100            (*infop).si_signo = new_info.raw_signo();
101            (*infop).si_errno = new_info.raw_errno();
102            (*infop).si_code = new_info.raw_code();
103            0
104        }
105        Some(None) => 0,
106        None => -1,
107    }
108}