use mach::port::{mach_port_t, MACH_PORT_NULL};
use mach::kern_return::{kern_return_t, KERN_SUCCESS};
use mach::traps::{mach_task_self, task_for_pid};
use libproc::{processes};
use libproc::processes::ProcFilter;
pub struct Process {
pub pid: u32,
pub port: mach_port_t,
}
#[derive(Debug)]
pub enum ProcessErr {
ListFailed(String),
KernError(String),
}
impl std::fmt::Display for ProcessErr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
ProcessErr::ListFailed(s) => write!(f, "failed to list processes: {}", s),
ProcessErr::KernError(s) => write!(f, "kernel error: {}", s),
}
}
}
impl std::error::Error for ProcessErr {}
impl ProcessErr {
pub(crate) fn from_kern(kr: kern_return_t) -> Self {
unsafe extern "C" { fn mach_error_string(err: kern_return_t) -> *const std::ffi::c_char;}
let msg = unsafe { std::ffi::CStr::from_ptr(mach_error_string(kr)) }
.to_string_lossy()
.to_string();
ProcessErr::KernError(msg)
}
}
impl Process {
pub fn open(pid: u32) -> Result<Process, ProcessErr> {
let mut port:mach_port_t = MACH_PORT_NULL; let kern_ret:kern_return_t = unsafe {task_for_pid(mach_task_self(), pid as i32, &mut port)};
return if kern_ret != KERN_SUCCESS {
Err(ProcessErr::from_kern(kern_ret))
} else {
Ok(Process{pid, port})
}
}
pub fn open_by_name(name: &str) -> Result<Process, ProcessErr> {
let pids: Vec<u32> = processes::pids_by_type(ProcFilter::All).map_err(|e| ProcessErr::ListFailed(e.to_string()))?;
let pid = pids.iter()
.find(|pid| libproc::proc_pid::name(**pid as i32).ok().as_deref() == Some(name))
.ok_or(ProcessErr::KernError("no such process".to_string()))?;
Process::open(*pid)
}
}