#![allow(non_snake_case)]
#![allow(non_upper_case_globals)] #![allow(dead_code)]
use core::any::Any;
use std::mem::size_of;
use std::os::raw::{c_char, c_int, c_void};
use std::ptr;
use crate::ported::machine::Machine;
use crate::ported::object::Object;
use crate::ported::openbsd::openbsdmachine::{kvm_getargv, kvm_getprocs, kvm_t, OpenBSDMachine};
use crate::ported::openbsd::openbsdprocess::{OpenBSDProcess, OpenBSDProcess_new};
use crate::ported::process::{
Process, ProcessState, Process_fillStarttimeBuffer, Process_isKernelThread,
Process_isUserlandThread, Process_setParent, Process_setThreadGroup,
Process_updateCPUFieldWidths, Process_updateCmdline, Process_updateComm, PROCESS_FLAG_CWD,
};
use crate::ported::processtable::{
ProcessTable, ProcessTable_cleanupEntries, ProcessTable_getProcess, ProcessTable_init,
ProcessTable_prepareEntries,
};
use crate::ported::table::{Table, TableClass};
const PZERO: i64 = 22;
const NODEV: libc::dev_t = -1;
const SIDL: i32 = 1;
const SRUN: i32 = 2;
const SSLEEP: i32 = 3;
const SSTOP: i32 = 4;
const SZOMB: i32 = 5;
const SDEAD: i32 = 6;
const SONPROC: i32 = 7;
#[repr(C)]
pub struct OpenBSDProcessTable {
pub super_: ProcessTable,
}
impl OpenBSDProcessTable {
fn scan_prepare(super_: *mut Table) {
let this = super_ as *mut OpenBSDProcessTable;
ProcessTable_prepareEntries(unsafe { &mut (*this).super_ });
}
fn scan_iterate(super_: *mut Table) {
let this = super_ as *mut OpenBSDProcessTable;
ProcessTable_goThroughEntries(unsafe { &mut *this });
}
fn scan_cleanup(super_: *mut Table) {
let this = super_ as *mut OpenBSDProcessTable;
ProcessTable_cleanupEntries(unsafe { &mut (*this).super_ });
}
}
pub static OpenBSDProcessTable_class: TableClass = TableClass {
prepare: Some(OpenBSDProcessTable::scan_prepare),
iterate: Some(OpenBSDProcessTable::scan_iterate),
cleanup: Some(OpenBSDProcessTable::scan_cleanup),
};
pub fn ProcessTable_new(
host: *const Machine,
pidMatchList: Option<usize>,
) -> Box<OpenBSDProcessTable> {
let mut this = Box::new(OpenBSDProcessTable {
super_: ProcessTable::empty(),
});
ProcessTable_init(&mut this.super_, host, pidMatchList);
this.super_.super_.klass = &OpenBSDProcessTable_class as *const TableClass;
this
}
pub fn ProcessTable_delete() {
todo!("port of OpenBSDProcessTable.c:48 — pure free() teardown; Rust Drop handles it")
}
pub fn OpenBSDProcessTable_updateCwd(kproc: &libc::kinfo_proc, proc: &mut Process) {
let mib: [c_int; 3] = [libc::CTL_KERN, libc::KERN_PROC_CWD, kproc.p_pid];
let mut buffer = [0u8; 2048];
let mut size = buffer.len();
if unsafe {
libc::sysctl(
mib.as_ptr(),
3,
buffer.as_mut_ptr() as *mut c_void,
&mut size,
ptr::null_mut(),
0,
)
} != 0
{
proc.procCwd = None;
return;
}
if buffer[0] == 0 {
proc.procCwd = None;
return;
}
let n = buffer.iter().position(|&b| b == 0).unwrap_or(buffer.len());
proc.procCwd = Some(String::from_utf8_lossy(&buffer[..n]).into_owned());
}
pub fn OpenBSDProcessTable_updateProcessName(
kd: *mut kvm_t,
kproc: &libc::kinfo_proc,
proc: &mut Process,
) {
fn cstr_field(buf: &[c_char]) -> String {
let bytes: &[u8] =
unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len()) };
let n = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
String::from_utf8_lossy(&bytes[..n]).into_owned()
}
fn updateCmdlineFromComm(proc: &mut Process, comm: &str) {
let end = comm.len();
let arg = if comm.is_empty() { None } else { Some(comm) };
Process_updateCmdline(proc, arg, 0, end);
}
let comm = cstr_field(&kproc.p_comm);
Process_updateComm(proc, Some(&comm));
let argv = unsafe { kvm_getargv(kd, kproc, 500) };
if argv.is_null() {
updateCmdlineFromComm(proc, &comm);
return;
}
let mut args: Vec<&[u8]> = Vec::new();
unsafe {
let mut i: isize = 0;
loop {
let p = *argv.offset(i);
if p.is_null() {
break;
}
args.push(std::ffi::CStr::from_ptr(p).to_bytes());
i += 1;
}
}
if args.is_empty() {
updateCmdlineFromComm(proc, &comm);
return;
}
let arg0 = args[0];
let byte_at = |b: &[u8], j: usize| -> u8 {
if j < b.len() {
b[j]
} else {
0 }
};
let mut end = arg0.len();
let mut j = end;
while j > 0 {
if byte_at(arg0, j) == b' ' && byte_at(arg0, j - 1) != b'\\' {
end = if byte_at(arg0, j - 1) == b':' { j - 1 } else { j };
}
j -= 1;
}
let mut s = String::new();
for a in &args {
s.push_str(&String::from_utf8_lossy(a));
s.push(' ');
}
let end = end.min(s.len());
Process_updateCmdline(proc, Some(&s), 0, end);
}
pub fn getpcpu(ohost: &OpenBSDMachine, kp: &libc::kinfo_proc) -> f64 {
if ohost.fscale == 0 {
return 0.0;
}
100.0 * kp.p_pctcpu as f64 / ohost.fscale as f64
}
pub fn OpenBSDProcessTable_scanProcs(this: &mut OpenBSDProcessTable) {
let host = this.super_.super_.host;
let ohost = host as *const OpenBSDMachine;
let (hideKernelThreads, hideUserlandThreads, updateProcessNames, cwdFlag) = unsafe {
let settings = (*host)
.settings
.as_ref()
.expect("OpenBSDProcessTable_scanProcs: settings unset");
let ss = &settings.screens[settings.ssIndex as usize];
(
settings.hideKernelThreads,
settings.hideUserlandThreads,
settings.updateProcessNames,
(ss.flags & PROCESS_FLAG_CWD) != 0,
)
};
let kd = unsafe { (*ohost).kd };
let pageSizeKB = unsafe { (*ohost).pageSizeKB } as i64;
let totalMem = unsafe { (*host).totalMem };
let activeCPUs = unsafe { (*host).activeCPUs };
let mut count: c_int = 0;
let kprocs = unsafe {
kvm_getprocs(
kd,
libc::KERN_PROC_KTHREAD | libc::KERN_PROC_SHOW_THREADS,
0,
size_of::<libc::kinfo_proc>(),
&mut count,
)
};
if kprocs.is_null() {
return;
}
for i in 0..count as isize {
let kproc: &libc::kinfo_proc = unsafe { &*kprocs.offset(i) };
if kproc.p_tid != -1 {
if let Some(&idx) = this.super_.super_.table.get(&kproc.p_pid) {
let cont: &mut dyn Object =
this.super_.super_.rows[idx].as_mut().unwrap().as_mut();
let cont_any: &mut dyn Any = cont;
let cont_op = cont_any
.downcast_mut::<OpenBSDProcess>()
.expect("scanProcs: containing row is not an OpenBSDProcess");
if cont_op.addr == kproc.p_addr {
continue;
}
cont_op.super_.nlwp += 1;
}
}
let pid = if kproc.p_tid == -1 {
kproc.p_pid
} else {
kproc.p_tid
};
let (preExisting, idx) = ProcessTable_getProcess(&mut this.super_, pid, |h| {
OpenBSDProcess_new(h) as Box<dyn Object>
});
let op: *mut OpenBSDProcess = {
let obj: &mut dyn Object = this.super_.super_.rows[idx].as_mut().unwrap().as_mut();
let any: &mut dyn Any = obj;
any.downcast_mut::<OpenBSDProcess>().unwrap()
};
let this_ptr = this as *mut OpenBSDProcessTable;
unsafe {
if !preExisting {
let proc = &mut (*op).super_;
Process_setParent(proc, kproc.p_ppid);
Process_setThreadGroup(proc, kproc.p_pid);
proc.tpgid = kproc.p_tpgid;
proc.session = kproc.p_sid;
proc.pgrp = kproc.p__pgid;
proc.isKernelThread = proc.pgrp == 0;
proc.isUserlandThread = kproc.p_tid != -1;
proc.starttime_ctime = kproc.p_ustart_sec as i64;
Process_fillStarttimeBuffer(proc);
OpenBSDProcessTable_updateProcessName(kd, kproc, proc);
if cwdFlag {
OpenBSDProcessTable_updateCwd(kproc, proc);
}
proc.tty_nr = kproc.p_tdev as u64;
let name_ptr = if (kproc.p_tdev as libc::dev_t) != NODEV {
libc::devname(kproc.p_tdev as libc::dev_t, libc::S_IFCHR)
} else {
ptr::null_mut()
};
if name_ptr.is_null() {
proc.tty_name = None;
} else {
let name = std::ffi::CStr::from_ptr(name_ptr).to_string_lossy().into_owned();
if name == "??" {
proc.tty_name = None;
} else {
proc.tty_name = Some(name);
}
}
} else if updateProcessNames {
OpenBSDProcessTable_updateProcessName(kd, kproc, &mut (*op).super_);
}
(*op).addr = kproc.p_addr;
let proc = &mut (*op).super_;
proc.m_virt = kproc.p_vm_dsize as i64 * pageSizeKB;
proc.m_resident = kproc.p_vm_rssize as i64 * pageSizeKB;
proc.percent_mem = proc.m_resident as f32 / totalMem as f32 * 100.0;
let pcpu = getpcpu(&*ohost, kproc) as f32;
proc.percent_cpu = pcpu.clamp(0.0, activeCPUs as f32 * 100.0);
Process_updateCPUFieldWidths(proc.percent_cpu);
proc.nice = kproc.p_nice as i32 - 20;
proc.time = 100
* (kproc.p_rtime_sec as u64
+ ((kproc.p_rtime_usec as u64 + 500000) / 1000000));
proc.priority = kproc.p_priority as i64 - PZERO;
proc.processor = kproc.p_cpuid as i32;
proc.minflt = kproc.p_uru_minflt;
proc.majflt = kproc.p_uru_majflt;
proc.nlwp = 1;
if proc.st_uid != kproc.p_uid {
proc.st_uid = kproc.p_uid;
}
proc.state = match kproc.p_stat as i32 {
SIDL => ProcessState::IDLE,
SRUN => ProcessState::RUNNABLE,
SSLEEP => ProcessState::SLEEPING,
SSTOP => ProcessState::STOPPED,
SZOMB => ProcessState::ZOMBIE,
SDEAD => ProcessState::DEFUNCT,
SONPROC => ProcessState::RUNNING,
_ => ProcessState::UNKNOWN,
};
let isKernel = Process_isKernelThread(proc);
let isUser = Process_isUserlandThread(proc);
if isKernel {
(*this_ptr).super_.kernelThreads += 1;
} else if isUser {
(*this_ptr).super_.userlandThreads += 1;
}
(*this_ptr).super_.totalTasks += 1;
if proc.state == ProcessState::RUNNING {
(*this_ptr).super_.runningTasks += 1;
}
proc.super_.show =
!((hideKernelThreads && isKernel) || (hideUserlandThreads && isUser));
proc.super_.updated = true;
}
}
}
pub fn ProcessTable_goThroughEntries(this: &mut OpenBSDProcessTable) {
OpenBSDProcessTable_scanProcs(this);
}