1b8a62b91Sopenharmony_ci//! Bindings for the FreeBSD `procctl` system call. 2b8a62b91Sopenharmony_ci//! 3b8a62b91Sopenharmony_ci//! There are similarities (but also differences) with Linux's `prctl` system call, whose interface 4b8a62b91Sopenharmony_ci//! is located in the `prctl.rs` file. 5b8a62b91Sopenharmony_ci 6b8a62b91Sopenharmony_ci#![allow(unsafe_code)] 7b8a62b91Sopenharmony_ci 8b8a62b91Sopenharmony_ciuse core::mem::MaybeUninit; 9b8a62b91Sopenharmony_ci 10b8a62b91Sopenharmony_ciuse crate::backend::c::{c_int, c_uint, c_void}; 11b8a62b91Sopenharmony_ciuse crate::backend::process::syscalls; 12b8a62b91Sopenharmony_ciuse crate::backend::process::types::{RawId, Signal}; 13b8a62b91Sopenharmony_ciuse crate::io; 14b8a62b91Sopenharmony_ciuse crate::process::{Pid, RawPid}; 15b8a62b91Sopenharmony_ci 16b8a62b91Sopenharmony_ci// 17b8a62b91Sopenharmony_ci// Helper functions. 18b8a62b91Sopenharmony_ci// 19b8a62b91Sopenharmony_ci 20b8a62b91Sopenharmony_ci/// Subset of `idtype_t` C enum, with only the values allowed by `procctl`. 21b8a62b91Sopenharmony_ci#[repr(i32)] 22b8a62b91Sopenharmony_cipub enum IdType { 23b8a62b91Sopenharmony_ci /// Process id. 24b8a62b91Sopenharmony_ci Pid = 0, 25b8a62b91Sopenharmony_ci /// Process group id. 26b8a62b91Sopenharmony_ci Pgid = 2, 27b8a62b91Sopenharmony_ci} 28b8a62b91Sopenharmony_ci 29b8a62b91Sopenharmony_ci/// A process selector for use with the `procctl` interface. 30b8a62b91Sopenharmony_ci/// 31b8a62b91Sopenharmony_ci/// `None` represents the current process. `Some((IdType::Pid, pid))` represents the process 32b8a62b91Sopenharmony_ci/// with pid `pid`. `Some((IdType::Pgid, pgid))` represents the control processes belonging to 33b8a62b91Sopenharmony_ci/// the process group with id `pgid`. 34b8a62b91Sopenharmony_cipub type ProcSelector = Option<(IdType, Pid)>; 35b8a62b91Sopenharmony_cifn proc_selector_to_raw(selector: ProcSelector) -> (IdType, RawPid) { 36b8a62b91Sopenharmony_ci match selector { 37b8a62b91Sopenharmony_ci Some((idtype, id)) => (idtype, id.as_raw_nonzero().get()), 38b8a62b91Sopenharmony_ci None => (IdType::Pid, 0), 39b8a62b91Sopenharmony_ci } 40b8a62b91Sopenharmony_ci} 41b8a62b91Sopenharmony_ci 42b8a62b91Sopenharmony_ci#[inline] 43b8a62b91Sopenharmony_cipub(crate) unsafe fn procctl( 44b8a62b91Sopenharmony_ci option: c_int, 45b8a62b91Sopenharmony_ci process: ProcSelector, 46b8a62b91Sopenharmony_ci data: *mut c_void, 47b8a62b91Sopenharmony_ci) -> io::Result<()> { 48b8a62b91Sopenharmony_ci let (idtype, id) = proc_selector_to_raw(process); 49b8a62b91Sopenharmony_ci syscalls::procctl(idtype as c_uint, id as RawId, option, data) 50b8a62b91Sopenharmony_ci} 51b8a62b91Sopenharmony_ci 52b8a62b91Sopenharmony_ci#[inline] 53b8a62b91Sopenharmony_cipub(crate) unsafe fn procctl_set<P>( 54b8a62b91Sopenharmony_ci option: c_int, 55b8a62b91Sopenharmony_ci process: ProcSelector, 56b8a62b91Sopenharmony_ci data: &P, 57b8a62b91Sopenharmony_ci) -> io::Result<()> { 58b8a62b91Sopenharmony_ci procctl(option, process, (data as *const P as *mut P).cast()) 59b8a62b91Sopenharmony_ci} 60b8a62b91Sopenharmony_ci 61b8a62b91Sopenharmony_ci#[inline] 62b8a62b91Sopenharmony_cipub(crate) unsafe fn procctl_get_optional<P>( 63b8a62b91Sopenharmony_ci option: c_int, 64b8a62b91Sopenharmony_ci process: ProcSelector, 65b8a62b91Sopenharmony_ci) -> io::Result<P> { 66b8a62b91Sopenharmony_ci let mut value: MaybeUninit<P> = MaybeUninit::uninit(); 67b8a62b91Sopenharmony_ci procctl(option, process, value.as_mut_ptr().cast())?; 68b8a62b91Sopenharmony_ci Ok(value.assume_init()) 69b8a62b91Sopenharmony_ci} 70b8a62b91Sopenharmony_ci 71b8a62b91Sopenharmony_ci// 72b8a62b91Sopenharmony_ci// PROC_PDEATHSIG_STATUS/PROC_PDEATHSIG_CTL 73b8a62b91Sopenharmony_ci// 74b8a62b91Sopenharmony_ci 75b8a62b91Sopenharmony_ciconst PROC_PDEATHSIG_STATUS: c_int = 12; 76b8a62b91Sopenharmony_ci 77b8a62b91Sopenharmony_ci/// Get the current value of the parent process death signal. 78b8a62b91Sopenharmony_ci/// 79b8a62b91Sopenharmony_ci/// # References 80b8a62b91Sopenharmony_ci/// - [Linux: `prctl(PR_GET_PDEATHSIG,...)`] 81b8a62b91Sopenharmony_ci/// - [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`] 82b8a62b91Sopenharmony_ci/// 83b8a62b91Sopenharmony_ci/// [Linux: `prctl(PR_GET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html 84b8a62b91Sopenharmony_ci/// [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 85b8a62b91Sopenharmony_ci#[inline] 86b8a62b91Sopenharmony_cipub fn parent_process_death_signal() -> io::Result<Option<Signal>> { 87b8a62b91Sopenharmony_ci unsafe { procctl_get_optional::<c_int>(PROC_PDEATHSIG_STATUS, None) }.map(Signal::from_raw) 88b8a62b91Sopenharmony_ci} 89b8a62b91Sopenharmony_ci 90b8a62b91Sopenharmony_ciconst PROC_PDEATHSIG_CTL: c_int = 11; 91b8a62b91Sopenharmony_ci 92b8a62b91Sopenharmony_ci/// Set the parent-death signal of the calling process. 93b8a62b91Sopenharmony_ci/// 94b8a62b91Sopenharmony_ci/// # References 95b8a62b91Sopenharmony_ci/// - [Linux: `prctl(PR_SET_PDEATHSIG,...)`] 96b8a62b91Sopenharmony_ci/// - [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`] 97b8a62b91Sopenharmony_ci/// 98b8a62b91Sopenharmony_ci/// [Linux: `prctl(PR_SET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html 99b8a62b91Sopenharmony_ci/// [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 100b8a62b91Sopenharmony_ci#[inline] 101b8a62b91Sopenharmony_cipub fn set_parent_process_death_signal(signal: Option<Signal>) -> io::Result<()> { 102b8a62b91Sopenharmony_ci let signal = signal.map_or(0, |signal| signal as c_int); 103b8a62b91Sopenharmony_ci unsafe { procctl_set::<c_int>(PROC_PDEATHSIG_CTL, None, &signal) } 104b8a62b91Sopenharmony_ci} 105b8a62b91Sopenharmony_ci 106b8a62b91Sopenharmony_ci// 107b8a62b91Sopenharmony_ci// PROC_TRACE_CTL 108b8a62b91Sopenharmony_ci// 109b8a62b91Sopenharmony_ci 110b8a62b91Sopenharmony_ciconst PROC_TRACE_CTL: c_int = 7; 111b8a62b91Sopenharmony_ci 112b8a62b91Sopenharmony_ciconst PROC_TRACE_CTL_ENABLE: i32 = 1; 113b8a62b91Sopenharmony_ciconst PROC_TRACE_CTL_DISABLE: i32 = 2; 114b8a62b91Sopenharmony_ciconst PROC_TRACE_CTL_DISABLE_EXEC: i32 = 3; 115b8a62b91Sopenharmony_ci 116b8a62b91Sopenharmony_ci/// `PROC_TRACE_CTL_*`. 117b8a62b91Sopenharmony_ci#[derive(Copy, Clone, Debug, Eq, PartialEq)] 118b8a62b91Sopenharmony_ci#[repr(i32)] 119b8a62b91Sopenharmony_cipub enum DumpableBehavior { 120b8a62b91Sopenharmony_ci /// Not dumpable. 121b8a62b91Sopenharmony_ci NotDumpable = PROC_TRACE_CTL_DISABLE, 122b8a62b91Sopenharmony_ci /// Dumpable. 123b8a62b91Sopenharmony_ci Dumpable = PROC_TRACE_CTL_ENABLE, 124b8a62b91Sopenharmony_ci /// Not dumpable, and this behaviour is preserved across `execve` calls. 125b8a62b91Sopenharmony_ci NotDumpableExecPreserved = PROC_TRACE_CTL_DISABLE_EXEC, 126b8a62b91Sopenharmony_ci} 127b8a62b91Sopenharmony_ci 128b8a62b91Sopenharmony_ci/// Set the state of the `dumpable` attribute for the process indicated by `idtype` and `id`. 129b8a62b91Sopenharmony_ci/// This determines whether the process can be traced and whether core dumps are produced for 130b8a62b91Sopenharmony_ci/// the process upon delivery of a signal whose default behavior is to produce a core dump. 131b8a62b91Sopenharmony_ci/// 132b8a62b91Sopenharmony_ci/// This is similar to `set_dumpable_behavior` on Linux, with the exception that on FreeBSD 133b8a62b91Sopenharmony_ci/// there is an extra argument `process`. When `process` is set to `None`, the operation is 134b8a62b91Sopenharmony_ci/// performed for the current process, like on Linux. 135b8a62b91Sopenharmony_ci/// 136b8a62b91Sopenharmony_ci/// # References 137b8a62b91Sopenharmony_ci/// - [`procctl(PROC_TRACE_CTL,...)`] 138b8a62b91Sopenharmony_ci/// 139b8a62b91Sopenharmony_ci/// [`procctl(PROC_TRACE_CTL,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 140b8a62b91Sopenharmony_ci#[inline] 141b8a62b91Sopenharmony_cipub fn set_dumpable_behavior(process: ProcSelector, config: DumpableBehavior) -> io::Result<()> { 142b8a62b91Sopenharmony_ci unsafe { procctl(PROC_TRACE_CTL, process, config as usize as *mut _) } 143b8a62b91Sopenharmony_ci} 144b8a62b91Sopenharmony_ci 145b8a62b91Sopenharmony_ci// 146b8a62b91Sopenharmony_ci// PROC_TRACE_STATUS 147b8a62b91Sopenharmony_ci// 148b8a62b91Sopenharmony_ci 149b8a62b91Sopenharmony_ciconst PROC_TRACE_STATUS: c_int = 8; 150b8a62b91Sopenharmony_ci 151b8a62b91Sopenharmony_ci/// Tracing status as returned by [`trace_status`]. 152b8a62b91Sopenharmony_ci#[derive(Copy, Clone, Debug, Eq, PartialEq)] 153b8a62b91Sopenharmony_cipub enum TracingStatus { 154b8a62b91Sopenharmony_ci /// Tracing is disabled for the process. 155b8a62b91Sopenharmony_ci NotTraceble, 156b8a62b91Sopenharmony_ci /// Tracing is not disabled for the process, but not debugger/tracer is attached. 157b8a62b91Sopenharmony_ci Tracable, 158b8a62b91Sopenharmony_ci /// The process is being traced by the process whose pid is stored in the first 159b8a62b91Sopenharmony_ci /// component of this variant. 160b8a62b91Sopenharmony_ci BeingTraced(Pid), 161b8a62b91Sopenharmony_ci} 162b8a62b91Sopenharmony_ci 163b8a62b91Sopenharmony_ci/// Get the tracing status of the process indicated by `idtype` and `id`. 164b8a62b91Sopenharmony_ci/// 165b8a62b91Sopenharmony_ci/// # References 166b8a62b91Sopenharmony_ci/// - [`procctl(PROC_TRACE_STATUS,...)`] 167b8a62b91Sopenharmony_ci/// 168b8a62b91Sopenharmony_ci/// [`procctl(PROC_TRACE_STATUS,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 169b8a62b91Sopenharmony_ci#[inline] 170b8a62b91Sopenharmony_cipub fn trace_status(process: ProcSelector) -> io::Result<TracingStatus> { 171b8a62b91Sopenharmony_ci let val = unsafe { procctl_get_optional::<c_int>(PROC_TRACE_STATUS, process) }?; 172b8a62b91Sopenharmony_ci match val { 173b8a62b91Sopenharmony_ci -1 => Ok(TracingStatus::NotTraceble), 174b8a62b91Sopenharmony_ci 0 => Ok(TracingStatus::Tracable), 175b8a62b91Sopenharmony_ci pid => { 176b8a62b91Sopenharmony_ci let pid = unsafe { Pid::from_raw(pid as RawPid) }.ok_or(io::Errno::RANGE)?; 177b8a62b91Sopenharmony_ci Ok(TracingStatus::BeingTraced(pid)) 178b8a62b91Sopenharmony_ci } 179b8a62b91Sopenharmony_ci } 180b8a62b91Sopenharmony_ci} 181