heim_process/sys/macos/bindings/
process.rs1use std::convert::TryFrom;
2use std::mem;
3use std::ptr;
4
5use mach::{boolean, vm_types};
6
7use heim_common::prelude::Error;
8
9use crate::{Pid, ProcessError, Status};
10
11pub const SIDL: libc::c_char = 1;
17pub const SRUN: libc::c_char = 2;
19pub const SSLEEP: libc::c_char = 3;
21pub const SSTOP: libc::c_char = 4;
23pub const SZOMB: libc::c_char = 5;
25
26impl TryFrom<libc::c_char> for Status {
27 type Error = Error;
28
29 fn try_from(value: libc::c_char) -> Result<Status, Self::Error> {
30 match value {
31 SIDL => Ok(Status::Idle),
32 SRUN => Ok(Status::Running),
33 SSLEEP => Ok(Status::Sleeping),
34 SSTOP => Ok(Status::Stopped),
35 SZOMB => Ok(Status::Zombie),
36 other => Err(Error::incompatible(format!(
37 "Unnknown process p_stat {:?}",
38 other
39 ))),
40 }
41 }
42}
43
44#[allow(non_camel_case_types)]
45type caddr_t = *const libc::c_char;
46#[allow(non_camel_case_types)]
47type segsz_t = i32;
48
49#[repr(C)]
50#[derive(Debug, Copy, Clone)]
51pub struct vmspace {
52 pub dummy: i32,
53 pub dummy2: caddr_t,
54 pub dummy3: [i32; 5],
55 pub dummy4: [caddr_t; 3],
56}
57
58#[repr(C)]
59#[derive(Copy, Clone)]
60pub struct pcred {
61 pub pc_lock: [libc::c_char; 72],
62 pub pc_ucred: *mut libc::xucred,
63 pub p_ruid: libc::uid_t,
64 pub p_svuid: libc::uid_t,
65 pub p_rgid: libc::gid_t,
66 pub p_svgid: libc::gid_t,
67 pub p_refcnt: libc::c_int,
68}
69
70#[repr(C)]
71#[derive(Copy, Clone)]
72pub struct kinfo_proc {
73 pub kp_proc: extern_proc,
74 pub kp_eproc: kinfo_proc_eproc,
75}
76
77#[repr(C)]
78#[derive(Copy, Clone)]
79pub struct run_sleep_queue {
80 p_forw: vm_types::user_addr_t,
81 p_back: vm_types::user_addr_t,
82}
83
84#[repr(C)]
85#[derive(Copy, Clone)]
86pub union p_un {
87 pub p_st1: run_sleep_queue,
88 pub p_starttime: libc::timeval,
89}
90
91#[repr(C)]
92#[derive(Copy, Clone)]
93pub struct extern_proc {
94 pub p_un: p_un,
95 pub p_vmspace: vm_types::user_addr_t,
96 pub p_sigacts: vm_types::user_addr_t,
97
98 pub p_flag: libc::c_int,
99 pub p_stat: libc::c_char,
100 pub p_pid: libc::pid_t,
101 pub p_oppid: libc::pid_t,
102 pub p_dupfd: libc::c_int,
103 pub user_stack: caddr_t,
104 pub exit_thread: *mut libc::c_void,
105 pub p_debugger: libc::c_int,
106 pub sigwait: boolean::boolean_t,
107 pub p_estcpu: libc::c_uint,
108 pub p_cpticks: libc::c_int,
109 pub p_pctcpu: u32,
110 pub p_wchan: *mut libc::c_void,
111 pub p_wmesg: *mut libc::c_char,
112 pub p_swtime: libc::c_uint,
113 pub p_slptime: libc::c_uint,
114 pub p_realtimer: libc::itimerval,
115 pub p_rtime: libc::timeval,
116 pub p_uticks: u64,
117 pub p_sticks: u64,
118 pub p_iticks: u64,
119 pub p_traceflag: libc::c_int,
120 pub p_tracep: *mut libc::c_void,
121 pub p_siglist: libc::c_int,
122 pub p_textvp: *mut libc::c_void,
124 pub p_holdcnt: libc::c_int,
125 pub p_sigmask: libc::sigset_t,
126 pub p_sigignore: libc::sigset_t,
127 pub p_sigcatch: libc::sigset_t,
128 pub p_priority: libc::c_uchar,
129 pub p_usrpri: libc::c_uchar,
130 pub p_nice: libc::c_char,
131 pub p_comm: [libc::c_char; 17],
132 pub p_pgrp: *mut libc::c_void,
134 pub p_addr: *mut libc::c_void,
137 pub p_xstat: libc::c_ushort,
138 pub p_acflag: libc::c_ushort,
139 pub p_ru: *mut libc::rusage,
140}
141
142#[repr(C)]
143#[derive(Copy, Clone)]
144pub struct kinfo_proc_eproc {
145 pub e_paddr: *mut libc::c_void,
147 pub e_sess: *mut libc::c_void,
151 pub e_pcred: pcred,
152 pub e_ucred: libc::xucred,
153 pub e_vm: vmspace,
154 pub e_ppid: libc::pid_t,
155 pub e_pgid: libc::pid_t,
156 pub e_jobc: libc::c_short,
157 pub e_tdev: libc::dev_t,
158 pub e_tpgid: libc::pid_t,
159 pub e_tsess: *mut libc::c_void, pub e_wmesg: [libc::c_char; 8],
161 pub e_xsize: segsz_t,
162 pub e_xrssize: libc::c_short,
163 pub e_xccount: libc::c_short,
164 pub e_xswrss: libc::c_short,
165 pub e_flag: i32,
166 pub e_login: [libc::c_char; 12],
167 pub e_spare: [i32; 4],
168}
169
170pub fn processes() -> Result<Vec<kinfo_proc>, Error> {
171 let mut name: [i32; 3] = [libc::CTL_KERN, libc::KERN_PROC, libc::KERN_PROC_ALL];
172 let mut size: libc::size_t = 0;
173 let mut processes: Vec<kinfo_proc> = vec![];
174
175 loop {
176 let result = unsafe {
177 libc::sysctl(
178 name.as_mut_ptr(),
179 3,
180 ptr::null_mut(),
181 &mut size,
182 ptr::null_mut(),
183 0,
184 )
185 };
186 if result < 0 {
187 return Err(Error::last_os_error());
188 }
189
190 processes.reserve(size);
191
192 let result = unsafe {
193 libc::sysctl(
194 name.as_mut_ptr(),
195 3,
196 processes.as_mut_ptr() as *mut libc::c_void,
197 &mut size,
198 ptr::null_mut(),
199 0,
200 )
201 };
202 match result {
203 libc::ENOMEM => continue,
204 code if code < 0 => return Err(Error::last_os_error()),
205 _ => {
206 let length = size / mem::size_of::<kinfo_proc>();
207 unsafe {
208 processes.set_len(length);
209 }
210 debug_assert!(!processes.is_empty());
211
212 return Ok(processes);
213 }
214 }
215 }
216}
217
218pub fn process(pid: Pid) -> Result<kinfo_proc, ProcessError> {
219 let mut name: [i32; 4] = [libc::CTL_KERN, libc::KERN_PROC, libc::KERN_PROC_PID, pid];
220 let mut size: libc::size_t = mem::size_of::<kinfo_proc>();
221 let mut info = mem::MaybeUninit::<kinfo_proc>::uninit();
222
223 let result = unsafe {
224 libc::sysctl(
225 name.as_mut_ptr(),
226 4,
227 info.as_mut_ptr() as *mut libc::c_void,
228 &mut size,
229 ptr::null_mut(),
230 0,
231 )
232 };
233
234 if result < 0 {
235 return Err(Error::last_os_error().into());
236 }
237
238 if size == 0 {
240 return Err(ProcessError::NoSuchProcess(pid));
241 }
242
243 unsafe { Ok(info.assume_init()) }
244}
245
246#[cfg(test)]
247mod tests {
248 use std::mem;
249
250 use super::{kinfo_proc, kinfo_proc_eproc, pcred, vmspace};
251
252 #[test]
253 fn test_layout() {
254 assert_eq!(mem::size_of::<vmspace>(), 64);
255 assert_eq!(mem::align_of::<vmspace>(), 8);
256
257 assert_eq!(mem::size_of::<pcred>(), 104);
258 assert_eq!(mem::align_of::<pcred>(), 8);
259
260 assert_eq!(mem::size_of::<kinfo_proc>(), 648);
261 assert_eq!(mem::align_of::<kinfo_proc>(), 8);
262
263 assert_eq!(mem::size_of::<kinfo_proc_eproc>(), 352);
264 assert_eq!(mem::align_of::<kinfo_proc_eproc>(), 8);
265 }
266}