//! Bindings for the FreeBSD `procctl` system call. //! //! There are similarities (but also differences) with Linux's `prctl` system call, whose interface //! is located in the `prctl.rs` file. #![allow(unsafe_code)] use core::mem::MaybeUninit; use crate::backend::c::{c_int, c_uint, c_void}; use crate::backend::process::syscalls; use crate::backend::process::types::{RawId, Signal}; use crate::io; use crate::process::{Pid, RawPid}; // // Helper functions. // /// Subset of `idtype_t` C enum, with only the values allowed by `procctl`. #[repr(i32)] pub enum IdType { /// Process id. Pid = 0, /// Process group id. Pgid = 2, } /// A process selector for use with the `procctl` interface. /// /// `None` represents the current process. `Some((IdType::Pid, pid))` represents the process /// with pid `pid`. `Some((IdType::Pgid, pgid))` represents the control processes belonging to /// the process group with id `pgid`. pub type ProcSelector = Option<(IdType, Pid)>; fn proc_selector_to_raw(selector: ProcSelector) -> (IdType, RawPid) { match selector { Some((idtype, id)) => (idtype, id.as_raw_nonzero().get()), None => (IdType::Pid, 0), } } #[inline] pub(crate) unsafe fn procctl( option: c_int, process: ProcSelector, data: *mut c_void, ) -> io::Result<()> { let (idtype, id) = proc_selector_to_raw(process); syscalls::procctl(idtype as c_uint, id as RawId, option, data) } #[inline] pub(crate) unsafe fn procctl_set

( option: c_int, process: ProcSelector, data: &P, ) -> io::Result<()> { procctl(option, process, (data as *const P as *mut P).cast()) } #[inline] pub(crate) unsafe fn procctl_get_optional

( option: c_int, process: ProcSelector, ) -> io::Result

{ let mut value: MaybeUninit

= MaybeUninit::uninit(); procctl(option, process, value.as_mut_ptr().cast())?; Ok(value.assume_init()) } // // PROC_PDEATHSIG_STATUS/PROC_PDEATHSIG_CTL // const PROC_PDEATHSIG_STATUS: c_int = 12; /// Get the current value of the parent process death signal. /// /// # References /// - [Linux: `prctl(PR_GET_PDEATHSIG,...)`] /// - [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`] /// /// [Linux: `prctl(PR_GET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html /// [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 #[inline] pub fn parent_process_death_signal() -> io::Result> { unsafe { procctl_get_optional::(PROC_PDEATHSIG_STATUS, None) }.map(Signal::from_raw) } const PROC_PDEATHSIG_CTL: c_int = 11; /// Set the parent-death signal of the calling process. /// /// # References /// - [Linux: `prctl(PR_SET_PDEATHSIG,...)`] /// - [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`] /// /// [Linux: `prctl(PR_SET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html /// [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 #[inline] pub fn set_parent_process_death_signal(signal: Option) -> io::Result<()> { let signal = signal.map_or(0, |signal| signal as c_int); unsafe { procctl_set::(PROC_PDEATHSIG_CTL, None, &signal) } } // // PROC_TRACE_CTL // const PROC_TRACE_CTL: c_int = 7; const PROC_TRACE_CTL_ENABLE: i32 = 1; const PROC_TRACE_CTL_DISABLE: i32 = 2; const PROC_TRACE_CTL_DISABLE_EXEC: i32 = 3; /// `PROC_TRACE_CTL_*`. #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[repr(i32)] pub enum DumpableBehavior { /// Not dumpable. NotDumpable = PROC_TRACE_CTL_DISABLE, /// Dumpable. Dumpable = PROC_TRACE_CTL_ENABLE, /// Not dumpable, and this behaviour is preserved across `execve` calls. NotDumpableExecPreserved = PROC_TRACE_CTL_DISABLE_EXEC, } /// Set the state of the `dumpable` attribute for the process indicated by `idtype` and `id`. /// This determines whether the process can be traced and whether core dumps are produced for /// the process upon delivery of a signal whose default behavior is to produce a core dump. /// /// This is similar to `set_dumpable_behavior` on Linux, with the exception that on FreeBSD /// there is an extra argument `process`. When `process` is set to `None`, the operation is /// performed for the current process, like on Linux. /// /// # References /// - [`procctl(PROC_TRACE_CTL,...)`] /// /// [`procctl(PROC_TRACE_CTL,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 #[inline] pub fn set_dumpable_behavior(process: ProcSelector, config: DumpableBehavior) -> io::Result<()> { unsafe { procctl(PROC_TRACE_CTL, process, config as usize as *mut _) } } // // PROC_TRACE_STATUS // const PROC_TRACE_STATUS: c_int = 8; /// Tracing status as returned by [`trace_status`]. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum TracingStatus { /// Tracing is disabled for the process. NotTraceble, /// Tracing is not disabled for the process, but not debugger/tracer is attached. Tracable, /// The process is being traced by the process whose pid is stored in the first /// component of this variant. BeingTraced(Pid), } /// Get the tracing status of the process indicated by `idtype` and `id`. /// /// # References /// - [`procctl(PROC_TRACE_STATUS,...)`] /// /// [`procctl(PROC_TRACE_STATUS,...)`]: https://www.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 #[inline] pub fn trace_status(process: ProcSelector) -> io::Result { let val = unsafe { procctl_get_optional::(PROC_TRACE_STATUS, process) }?; match val { -1 => Ok(TracingStatus::NotTraceble), 0 => Ok(TracingStatus::Tracable), pid => { let pid = unsafe { Pid::from_raw(pid as RawPid) }.ok_or(io::Errno::RANGE)?; Ok(TracingStatus::BeingTraced(pid)) } } }