#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)] #![allow(dead_code)]
use core::slice;
use std::ffi::CStr;
use std::mem::size_of;
use std::os::raw::{c_char, c_int, c_ulong, c_void};
use std::ptr;
use crate::ported::machine::Machine;
use crate::ported::netbsd::netbsdmachine::NetBSDMachine;
use crate::ported::netbsd::netbsdprocess::NetBSDProcess_new;
use crate::ported::object::Object;
use crate::ported::process::{
Process, ProcessState, Process_fillStarttimeBuffer, Process_getPid, Process_getThreadGroup,
Process_isKernelThread, Process_isUserlandThread, Process_setParent, Process_setPid,
Process_setThreadGroup, Process_updateCPUFieldWidths, Process_updateCmdline, Process_updateComm,
Process_updateExe, PROCESS_FLAG_CWD,
};
use crate::ported::processtable::{
ProcessTable, ProcessTable_cleanupEntries, ProcessTable_getProcess, ProcessTable_init,
ProcessTable_prepareEntries,
};
use crate::ported::table::{Table, TableClass};
const KI_NGROUPS: usize = 16;
const KI_MAXCOMLEN: usize = 24;
const KI_WMESGLEN: usize = 8;
const KI_MAXLOGNAME: usize = 24;
const KI_MAXEMULLEN: usize = 16;
const KI_LNAMELEN: usize = 20;
const KERN_PROC_CWD: c_int = 6;
const PZERO: i64 = 22;
const P_SYSTEM: i32 = 0x0000_0002;
const SIDL: u64 = 1;
const SACTIVE: u64 = 2;
const SSTOP: u64 = 4;
const SZOMB: u64 = 5;
const SDEAD: u64 = 6;
#[repr(C)]
#[derive(Clone, Copy)]
pub struct ki_sigset_t {
pub __bits: [u32; 4],
}
extern "C" {
fn kvm_getproc2(
kd: *mut c_void,
op: c_int,
arg: c_int,
elemsize: usize,
cnt: *mut c_int,
) -> *const kinfo_proc2;
fn kvm_getlwps(
kd: *mut c_void,
pid: c_int,
paddr: c_ulong,
elemsize: usize,
cnt: *mut c_int,
) -> *const kinfo_lwp;
fn kvm_getargv2(kd: *mut c_void, p: *const kinfo_proc2, nchr: c_int) -> *const *const c_char;
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct kinfo_proc2 {
pub p_forw: u64,
pub p_back: u64,
pub p_paddr: u64,
pub p_addr: u64,
pub p_fd: u64,
pub p_cwdi: u64,
pub p_stats: u64,
pub p_limit: u64,
pub p_vmspace: u64,
pub p_sigacts: u64,
pub p_sess: u64,
pub p_tsess: u64,
pub p_ru: u64,
pub p_eflag: i32,
pub p_exitsig: i32,
pub p_flag: i32,
pub p_pid: i32,
pub p_ppid: i32,
pub p_sid: i32,
pub p__pgid: i32,
pub p_tpgid: i32,
pub p_uid: u32,
pub p_ruid: u32,
pub p_gid: u32,
pub p_rgid: u32,
pub p_groups: [u32; KI_NGROUPS],
pub p_ngroups: i16,
pub p_jobc: i16,
pub p_tdev: u32,
pub p_estcpu: u32,
pub p_rtime_sec: u32,
pub p_rtime_usec: u32,
pub p_cpticks: i32,
pub p_pctcpu: u32,
pub p_swtime: u32,
pub p_slptime: u32,
pub p_schedflags: i32,
pub p_uticks: u64,
pub p_sticks: u64,
pub p_iticks: u64,
pub p_tracep: u64,
pub p_traceflag: i32,
pub p_holdcnt: i32,
pub p_siglist: ki_sigset_t,
pub p_sigmask: ki_sigset_t,
pub p_sigignore: ki_sigset_t,
pub p_sigcatch: ki_sigset_t,
pub p_stat: i8,
pub p_priority: u8,
pub p_usrpri: u8,
pub p_nice: u8,
pub p_xstat: u16,
pub p_acflag: u16,
pub p_comm: [c_char; KI_MAXCOMLEN],
pub p_wmesg: [c_char; KI_WMESGLEN],
pub p_wchan: u64,
pub p_login: [c_char; KI_MAXLOGNAME],
pub p_vm_rssize: i32,
pub p_vm_tsize: i32,
pub p_vm_dsize: i32,
pub p_vm_ssize: i32,
pub p_uvalid: i64,
pub p_ustart_sec: u32,
pub p_ustart_usec: u32,
pub p_uutime_sec: u32,
pub p_uutime_usec: u32,
pub p_ustime_sec: u32,
pub p_ustime_usec: u32,
pub p_uru_maxrss: u64,
pub p_uru_ixrss: u64,
pub p_uru_idrss: u64,
pub p_uru_isrss: u64,
pub p_uru_minflt: u64,
pub p_uru_majflt: u64,
pub p_uru_nswap: u64,
pub p_uru_inblock: u64,
pub p_uru_oublock: u64,
pub p_uru_msgsnd: u64,
pub p_uru_msgrcv: u64,
pub p_uru_nsignals: u64,
pub p_uru_nvcsw: u64,
pub p_uru_nivcsw: u64,
pub p_uctime_sec: u32,
pub p_uctime_usec: u32,
pub p_cpuid: u64,
pub p_realflag: u64,
pub p_nlwps: u64,
pub p_nrlwps: u64,
pub p_realstat: u64,
pub p_svuid: u32,
pub p_svgid: u32,
pub p_ename: [c_char; KI_MAXEMULLEN],
pub p_vm_vsize: i64,
pub p_vm_msize: i64,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct kinfo_lwp {
pub l_forw: u64,
pub l_back: u64,
pub l_laddr: u64,
pub l_addr: u64,
pub l_lid: i32,
pub l_flag: i32,
pub l_swtime: u32,
pub l_slptime: u32,
pub l_schedflags: i32,
pub l_holdcnt: i32,
pub l_priority: u8,
pub l_usrpri: u8,
pub l_stat: i8,
pub l_pad1: i8,
pub l_pad2: i32,
pub l_wmesg: [c_char; KI_WMESGLEN],
pub l_wchan: u64,
pub l_cpuid: u64,
pub l_rtime_sec: u32,
pub l_rtime_usec: u32,
pub l_cpticks: u32,
pub l_pctcpu: u32,
pub l_pid: u32,
pub l_name: [c_char; KI_LNAMELEN],
}
#[repr(C)]
pub struct NetBSDProcessTable {
pub super_: ProcessTable,
}
pub fn NetBSDProcessTable_updateExe(kproc: &kinfo_proc2, proc: &mut Process) {
let mib: [c_int; 4] = [
libc::CTL_KERN,
libc::KERN_PROC_ARGS,
kproc.p_pid,
libc::KERN_PROC_PATHNAME,
];
let mut buffer = [0u8; 2048];
let mut size = buffer.len();
if unsafe {
libc::sysctl(
mib.as_ptr(),
4,
buffer.as_mut_ptr() as *mut c_void,
&mut size,
ptr::null(),
0,
)
} != 0
{
Process_updateExe(proc, None);
return;
}
if buffer[0] == 0 {
Process_updateExe(proc, None);
return;
}
let end = buffer.iter().position(|&b| b == 0).unwrap_or(buffer.len());
let exe = String::from_utf8_lossy(&buffer[..end]);
Process_updateExe(proc, Some(&exe));
}
pub fn NetBSDProcessTable_updateCwd(kproc: &kinfo_proc2, proc: &mut Process) {
let mib: [c_int; 4] = [
libc::CTL_KERN,
libc::KERN_PROC_ARGS,
kproc.p_pid,
KERN_PROC_CWD,
];
let mut buffer = [0u8; 2048];
let mut size = buffer.len();
if unsafe {
libc::sysctl(
mib.as_ptr(),
4,
buffer.as_mut_ptr() as *mut c_void,
&mut size,
ptr::null(),
0,
)
} != 0
{
proc.procCwd = None;
return;
}
if buffer[0] == 0 {
proc.procCwd = None;
return;
}
let end = buffer.iter().position(|&b| b == 0).unwrap_or(buffer.len());
proc.procCwd = Some(String::from_utf8_lossy(&buffer[..end]).into_owned());
}
pub fn NetBSDProcessTable_updateProcessName(
kd: *mut c_void,
kproc: &kinfo_proc2,
proc: &mut Process,
) {
fn c_field_to_string(buf: &[c_char]) -> String {
let bytes: &[u8] = unsafe { slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len()) };
let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
String::from_utf8_lossy(&bytes[..end]).into_owned()
}
let comm = c_field_to_string(&kproc.p_comm);
Process_updateComm(proc, Some(&comm));
let arg = unsafe { kvm_getargv2(kd, kproc as *const kinfo_proc2, 500) };
if arg.is_null() || unsafe { (*arg).is_null() } {
Process_updateCmdline(proc, Some(&comm), 0, comm.len());
return;
}
let mut args: Vec<&[u8]> = Vec::new();
let mut i = 0isize;
loop {
let p = unsafe { *arg.offset(i) };
if p.is_null() {
break;
}
args.push(unsafe { CStr::from_ptr(p) }.to_bytes());
i += 1;
}
let mut s = String::new();
let mut end = 0usize;
for (idx, a) in args.iter().enumerate() {
s.push_str(&String::from_utf8_lossy(a));
if idx == 0 {
end = a.len();
let byte_at = |j: usize| -> u8 {
if j < a.len() {
a[j]
} else {
0
}
};
let mut j = end;
while j > 0 {
if byte_at(j) == b' ' && byte_at(j - 1) != b'\\' {
end = if byte_at(j - 1) == b':' { j - 1 } else { j };
}
j -= 1;
}
}
s.push(' ');
}
Process_updateCmdline(proc, Some(&s), 0, end);
}
pub fn getpcpu(nhost: &NetBSDMachine, kp: &kinfo_proc2) -> f64 {
if nhost.fscale == 0 {
return 0.0;
}
100.0 * kp.p_pctcpu as f64 / nhost.fscale as f64
}
pub fn get_active_status(nhost: &NetBSDMachine, kproc: &kinfo_proc2) -> ProcessState {
let mut nlwps: c_int = 0;
let klwps = unsafe {
kvm_getlwps(
nhost.kd,
kproc.p_pid,
kproc.p_paddr as c_ulong,
size_of::<kinfo_lwp>(),
&mut nlwps,
)
};
if klwps.is_null() {
return ProcessState::UNKNOWN;
}
let lwps = unsafe { slice::from_raw_parts(klwps, nlwps.max(0) as usize) };
for lwp in lwps {
match lwp.l_stat as c_int {
libc::LSONPROC => return ProcessState::RUNNING,
libc::LSRUN => return ProcessState::RUNNABLE,
libc::LSSLEEP => return ProcessState::SLEEPING,
libc::LSSTOP => return ProcessState::STOPPED,
_ => {}
}
}
ProcessState::UNKNOWN
}
pub fn ProcessTable_goThroughEntries(this: &mut NetBSDProcessTable) {
let host = this.super_.super_.host;
let nhost = host as *const NetBSDMachine;
let (host_total_mem, host_active_cpus) = unsafe { ((*host).totalMem, (*host).activeCPUs) };
let (hide_kernel, hide_userland, update_names, cwd_flag) = unsafe {
let settings = (*host).settings.as_ref().expect("host settings unset");
let ss_flags = settings.screens[settings.ssIndex as usize].flags;
(
settings.hideKernelThreads,
settings.hideUserlandThreads,
settings.updateProcessNames,
ss_flags & PROCESS_FLAG_CWD != 0,
)
};
let (nhost_kd, nhost_page_kb) = unsafe { ((*nhost).kd, (*nhost).pageSizeKB) };
let mut count: c_int = 0;
let kprocs = unsafe {
kvm_getproc2(
nhost_kd,
libc::KERN_PROC_ALL,
0,
size_of::<kinfo_proc2>(),
&mut count,
)
};
if kprocs.is_null() {
return;
}
let kprocs = unsafe { slice::from_raw_parts(kprocs, count.max(0) as usize) };
for kproc in kprocs {
let (pre_existing, idx) =
ProcessTable_getProcess(&mut this.super_, kproc.p_pid, |h| {
NetBSDProcess_new(h) as Box<dyn Object>
});
let proc_ptr: *mut Process = {
let obj: &mut dyn Object = this.super_.super_.rows[idx].as_mut().unwrap().as_mut();
obj.as_process_mut().unwrap() as *mut Process
};
let this_ptr = this as *mut NetBSDProcessTable;
unsafe {
let proc = &mut *proc_ptr;
proc.super_.show = !((hide_kernel && Process_isKernelThread(proc))
|| (hide_userland && Process_isUserlandThread(proc)));
if !pre_existing {
Process_setPid(proc, kproc.p_pid);
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 = (kproc.p_flag & P_SYSTEM) != 0;
proc.isUserlandThread = Process_getPid(proc) != Process_getThreadGroup(proc);
proc.starttime_ctime = kproc.p_ustart_sec as i64;
Process_fillStarttimeBuffer(proc);
proc.tty_nr = kproc.p_tdev as u64;
let name: *mut c_char = if kproc.p_tdev != u32::MAX {
libc::devname(kproc.p_tdev as libc::dev_t, libc::S_IFCHR)
} else {
ptr::null_mut()
};
if name.is_null() {
proc.tty_name = None;
} else {
proc.tty_name =
Some(CStr::from_ptr(name).to_string_lossy().into_owned());
}
NetBSDProcessTable_updateExe(kproc, proc);
NetBSDProcessTable_updateProcessName(nhost_kd, kproc, proc);
} else if update_names {
NetBSDProcessTable_updateProcessName(nhost_kd, kproc, proc);
}
if cwd_flag {
NetBSDProcessTable_updateCwd(kproc, proc);
}
if proc.st_uid != kproc.p_uid {
proc.st_uid = kproc.p_uid;
}
proc.m_virt = kproc.p_vm_vsize;
proc.m_resident = kproc.p_vm_rssize as i64;
proc.percent_mem = ((proc.m_resident as f64 * nhost_page_kb as f64)
/ host_total_mem as f64
* 100.0) as f32;
proc.percent_cpu = getpcpu(&*nhost, kproc)
.clamp(0.0, host_active_cpus as f64 * 100.0) as f32;
Process_updateCPUFieldWidths(proc.percent_cpu);
proc.nlwp = kproc.p_nlwps as i64;
proc.nice = kproc.p_nice as i32 - 20;
proc.time = 100
* (kproc.p_rtime_sec as u64
+ ((kproc.p_rtime_usec as u64 + 500_000) / 1_000_000));
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.state = match kproc.p_realstat {
SIDL => ProcessState::IDLE,
SACTIVE => get_active_status(&*nhost, kproc),
SSTOP => ProcessState::STOPPED,
SZOMB => ProcessState::ZOMBIE,
SDEAD => ProcessState::DEFUNCT,
_ => ProcessState::UNKNOWN,
};
if Process_isKernelThread(proc) {
(*this_ptr).super_.kernelThreads += 1;
} else if Process_isUserlandThread(proc) {
(*this_ptr).super_.userlandThreads += 1;
}
(*this_ptr).super_.totalTasks += 1;
if proc.state == ProcessState::RUNNING {
(*this_ptr).super_.runningTasks += 1;
}
proc.super_.updated = true;
}
}
}
impl NetBSDProcessTable {
fn scan_prepare(super_: *mut Table) {
let this = super_ as *mut NetBSDProcessTable;
ProcessTable_prepareEntries(unsafe { &mut (*this).super_ });
}
fn scan_iterate(super_: *mut Table) {
let this = super_ as *mut NetBSDProcessTable;
ProcessTable_goThroughEntries(unsafe { &mut *this });
}
fn scan_cleanup(super_: *mut Table) {
let this = super_ as *mut NetBSDProcessTable;
ProcessTable_cleanupEntries(unsafe { &mut (*this).super_ });
}
}
pub static NetBSDProcessTable_class: TableClass = TableClass {
prepare: Some(NetBSDProcessTable::scan_prepare),
iterate: Some(NetBSDProcessTable::scan_iterate),
cleanup: Some(NetBSDProcessTable::scan_cleanup),
};
pub fn ProcessTable_new(host: *const Machine, pidMatchList: Option<usize>) -> Box<NetBSDProcessTable> {
let mut this = Box::new(NetBSDProcessTable {
super_: ProcessTable::empty(),
});
ProcessTable_init(&mut this.super_, host, pidMatchList);
this.super_.super_.klass = &NetBSDProcessTable_class as *const TableClass;
this
}
pub fn ProcessTable_delete() {
todo!("port of NetBSDProcessTable.c:50 — pure free() teardown; Rust Drop handles it")
}