#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
#![allow(dead_code)]
use core::any::Any;
use std::ffi::CString;
use std::os::raw::{c_char, c_int, c_long, c_void};
use crate::ported::machine::Machine;
use crate::ported::object::Object;
use crate::ported::process::{
Process, ProcessState, Process_fillStarttimeBuffer, Process_setParent, 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::solaris::solarismachine::{kstat_ctl_t, kstat_lookup_wrapper, SolarisMachine};
use crate::ported::solaris::solarisprocess::{SolarisProcess, SolarisProcess_new};
use crate::ported::table::{Table, TableClass};
const GZONE: &str = "global ";
const UZONE: &str = "unknown ";
const PATH_MAX: usize = 1024;
const NZERO: i32 = 20;
const PRNODEV: libc::dev_t = -1i64 as libc::dev_t;
#[repr(C)]
#[derive(Clone, Copy)]
struct timestruc_t {
tv_sec: libc::time_t,
tv_nsec: c_long,
}
const PRCLSZ: usize = 8;
const PRFNSZ: usize = 16;
const PRARGSZ: usize = 80;
#[repr(C)]
#[derive(Clone, Copy)]
struct lwpsinfo_t {
pr_flag: c_int,
pr_lwpid: i32,
pr_addr: usize,
pr_wchan: usize,
pr_stype: c_char,
pr_state: c_char,
pr_sname: c_char,
pr_nice: c_char,
pr_syscall: i16,
pr_oldpri: c_char,
pr_cpu: c_char,
pr_pri: c_int,
pr_pctcpu: u16,
pr_pad: u16,
pr_start: timestruc_t,
pr_time: timestruc_t,
pr_clname: [c_char; PRCLSZ],
pr_name: [c_char; PRFNSZ],
pr_onpro: i32,
pr_bindpro: i32,
pr_bindpset: i32,
pr_lgrp: i32,
pr_last_onproc: u64,
pr_filler: [c_int; 4],
}
#[repr(C)]
struct psinfo_t {
pr_flag: c_int,
pr_nlwp: c_int,
pr_pid: libc::pid_t,
pr_ppid: libc::pid_t,
pr_pgid: libc::pid_t,
pr_sid: libc::pid_t,
pr_uid: libc::uid_t,
pr_euid: libc::uid_t,
pr_gid: libc::gid_t,
pr_egid: libc::gid_t,
pr_addr: usize,
pr_size: usize,
pr_rssize: usize,
pr_pad1: usize,
pr_ttydev: libc::dev_t,
pr_pctcpu: u16,
pr_pctmem: u16,
pr_start: timestruc_t,
pr_time: timestruc_t,
pr_ctime: timestruc_t,
pr_fname: [c_char; PRFNSZ],
pr_psargs: [c_char; PRARGSZ],
pr_wstat: c_int,
pr_argc: c_int,
pr_argv: usize,
pr_envp: usize,
pr_dmodel: c_char,
pr_pad2: [c_char; 3],
pr_taskid: i32,
pr_projid: i32,
pr_nzomb: c_int,
pr_poolid: i32,
pr_zoneid: i32,
pr_contract: i32,
pr_filler: [c_int; 1],
pr_lwp: lwpsinfo_t,
}
type proc_walk_f = extern "C" fn(*mut psinfo_t, *mut lwpsinfo_t, *mut c_void) -> c_int;
const PR_WALK_LWP: c_int = 1;
#[link(name = "proc")]
extern "C" {
fn proc_walk(func: proc_walk_f, arg: *mut c_void, flags: c_int) -> c_int;
}
#[repr(C)]
pub struct SolarisProcessTable {
pub super_: ProcessTable,
}
pub fn SolarisProcessTable_readZoneName(kd: *mut kstat_ctl_t, sproc: &SolarisProcess) -> String {
if sproc.zoneid == 0 {
GZONE.to_string()
} else if kd.is_null() {
UZONE.to_string()
} else {
let ks = unsafe { kstat_lookup_wrapper(kd, "zones", sproc.zoneid, None) };
if ks.is_null() {
UZONE.to_string()
} else {
let name = unsafe { &(*ks).ks_name };
let bytes =
unsafe { core::slice::from_raw_parts(name.as_ptr() as *const u8, name.len()) };
let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
String::from_utf8_lossy(&bytes[..end]).into_owned()
}
}
}
impl SolarisProcessTable {
fn scan_prepare(super_: *mut Table) {
let this = super_ as *mut SolarisProcessTable;
ProcessTable_prepareEntries(unsafe { &mut (*this).super_ });
}
fn scan_iterate(super_: *mut Table) {
let this = super_ as *mut SolarisProcessTable;
ProcessTable_goThroughEntries(unsafe { &mut *this });
}
fn scan_cleanup(super_: *mut Table) {
let this = super_ as *mut SolarisProcessTable;
ProcessTable_cleanupEntries(unsafe { &mut (*this).super_ });
}
}
pub static SolarisProcessTable_class: TableClass = TableClass {
prepare: Some(SolarisProcessTable::scan_prepare),
iterate: Some(SolarisProcessTable::scan_iterate),
cleanup: Some(SolarisProcessTable::scan_cleanup),
};
pub fn ProcessTable_new(
host: *const Machine,
pidMatchList: Option<usize>,
) -> Box<SolarisProcessTable> {
let mut this = Box::new(SolarisProcessTable {
super_: ProcessTable::empty(),
});
ProcessTable_init(&mut this.super_, host, pidMatchList);
this.super_.super_.klass = &SolarisProcessTable_class as *const TableClass;
this
}
pub fn ProcessTable_delete() {
todo!("port of SolarisProcessTable.c:59 — pure free() teardown; Rust Drop handles it")
}
pub fn SolarisProcessTable_updateExe(pid: libc::pid_t, proc: &mut Process) {
let path = CString::new(format!("/proc/{}/path/a.out", pid)).unwrap();
let mut target = [0u8; PATH_MAX];
let ret = unsafe {
libc::readlink(
path.as_ptr(),
target.as_mut_ptr() as *mut c_char,
target.len() - 1,
)
};
if ret <= 0 {
return;
}
let s = String::from_utf8_lossy(&target[..ret as usize]).into_owned();
Process_updateExe(proc, Some(&s));
}
pub fn SolarisProcessTable_updateCwd(pid: libc::pid_t, proc: &mut Process) {
let path = CString::new(format!("/proc/{}/cwd", pid)).unwrap();
let mut target = [0u8; PATH_MAX];
let ret = unsafe {
libc::readlink(
path.as_ptr(),
target.as_mut_ptr() as *mut c_char,
target.len() - 1,
)
};
if ret <= 0 {
return;
}
proc.procCwd = Some(String::from_utf8_lossy(&target[..ret as usize]).into_owned());
}
pub fn SolarisProcessTable_getProcessState(state: c_char) -> ProcessState {
match state as u8 as char {
'S' => ProcessState::SLEEPING,
'R' => ProcessState::RUNNABLE,
'O' => ProcessState::RUNNING,
'Z' => ProcessState::ZOMBIE,
'T' => ProcessState::STOPPED,
'I' => ProcessState::IDLE,
_ => ProcessState::UNKNOWN,
}
}
pub extern "C" fn SolarisProcessTable_walkproc(
_psinfo: *mut psinfo_t,
_lwpsinfo: *mut lwpsinfo_t,
listptr: *mut c_void,
) -> c_int {
let ps = unsafe { &*_psinfo };
let lwp = unsafe { &*_lwpsinfo };
let field_str = |buf: &[c_char]| -> String {
let bytes = unsafe { core::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 pt = unsafe { &mut *(listptr as *mut ProcessTable) };
let host = pt.super_.host; let shost = host as *const SolarisMachine;
let lwpid_real = lwp.pr_lwpid;
if lwpid_real > 1023 {
return 0;
}
let lwpid = ps.pr_pid * 1024 + lwpid_real;
let onMasterLWP = lwp.pr_lwpid == ps.pr_lwp.pr_lwpid;
let getpid = if onMasterLWP { ps.pr_pid * 1024 } else { lwpid };
let (flags, hideKernelThreads, hideUserlandThreads) = unsafe {
(*host).settings.as_ref().map_or((0u32, false, false), |s| {
(
s.screens.get(s.ssIndex as usize).map_or(0, |ss| ss.flags),
s.hideKernelThreads,
s.hideUserlandThreads,
)
})
};
let (preExisting, idx) =
ProcessTable_getProcess(pt, getpid, |h| SolarisProcess_new(h) as Box<dyn Object>);
let pt_ptr = pt as *mut ProcessTable;
let sproc: *mut SolarisProcess = {
let obj: &mut dyn Object = pt.super_.rows[idx].as_mut().unwrap().as_mut();
let any: &mut dyn Any = obj;
any.downcast_mut::<SolarisProcess>().unwrap()
};
let sp = unsafe { &mut *sproc };
sp.super_.super_.show = false;
sp.taskid = ps.pr_taskid;
sp.projid = ps.pr_projid;
sp.poolid = ps.pr_poolid;
sp.contid = ps.pr_contract;
sp.super_.priority = lwp.pr_pri as i64;
sp.super_.nice = lwp.pr_nice as i32 - NZERO;
sp.super_.processor = lwp.pr_onpro;
sp.super_.state = SolarisProcessTable_getProcessState(lwp.pr_sname);
sp.super_.percent_mem = (ps.pr_pctmem as f64 / 32768.0 * 100.0) as f32;
sp.super_.pgrp = ps.pr_pgid;
sp.super_.nlwp = ps.pr_nlwp as i64;
sp.super_.session = ps.pr_sid;
sp.super_.tty_nr = ps.pr_ttydev;
let name = if ps.pr_ttydev != PRNODEV {
unsafe { libc::ttyname(ps.pr_ttydev as c_int) }
} else {
core::ptr::null_mut()
};
if name.is_null() {
sp.super_.tty_name = None;
} else {
sp.super_.tty_name = Some(
unsafe { std::ffi::CStr::from_ptr(name) }
.to_string_lossy()
.into_owned(),
);
}
sp.super_.m_resident = ps.pr_rssize as i64; sp.super_.m_virt = ps.pr_size as i64;
if sp.super_.st_uid != ps.pr_euid {
sp.super_.st_uid = ps.pr_euid;
}
if !preExisting {
sp.realpid = ps.pr_pid;
sp.lwpid = lwpid_real;
sp.zoneid = ps.pr_zoneid;
sp.zname = Some(SolarisProcessTable_readZoneName(unsafe { (*shost).kd }, sp));
SolarisProcessTable_updateExe(ps.pr_pid, &mut sp.super_);
Process_updateComm(&mut sp.super_, Some(&field_str(&ps.pr_fname)));
Process_updateCmdline(&mut sp.super_, Some(&field_str(&ps.pr_psargs)), 0, 0);
if flags & PROCESS_FLAG_CWD != 0 {
SolarisProcessTable_updateCwd(ps.pr_pid, &mut sp.super_);
}
}
if onMasterLWP {
Process_setParent(&mut sp.super_, ps.pr_ppid * 1024);
Process_setThreadGroup(&mut sp.super_, ps.pr_ppid * 1024);
sp.realppid = ps.pr_ppid;
sp.realtgid = ps.pr_ppid;
sp.super_.percent_cpu = (ps.pr_pctcpu as f64 / 32768.0 * 100.0) as f32;
Process_updateCPUFieldWidths(sp.super_.percent_cpu);
sp.super_.time =
(ps.pr_time.tv_sec * 100 + ps.pr_time.tv_nsec / 10_000_000) as u64;
if !preExisting {
sp.super_.isUserlandThread = false;
sp.super_.starttime_ctime = ps.pr_start.tv_sec;
}
if sp.super_.isKernelThread && !hideKernelThreads {
unsafe {
(*pt_ptr).kernelThreads += sp.super_.nlwp as u32;
(*pt_ptr).totalTasks += sp.super_.nlwp as u32 + 1;
if sp.super_.state == ProcessState::RUNNING {
(*pt_ptr).runningTasks += 1;
}
}
} else if !sp.super_.isKernelThread {
unsafe {
if sp.super_.state == ProcessState::RUNNING {
(*pt_ptr).runningTasks += 1;
}
if hideUserlandThreads {
(*pt_ptr).totalTasks += 1;
} else {
(*pt_ptr).userlandThreads += sp.super_.nlwp as u32;
(*pt_ptr).totalTasks += sp.super_.nlwp as u32 + 1;
}
}
}
sp.super_.super_.show = !(hideKernelThreads && sp.super_.isKernelThread);
} else {
sp.super_.percent_cpu = (lwp.pr_pctcpu as f64 / 32768.0 * 100.0) as f32;
Process_updateCPUFieldWidths(sp.super_.percent_cpu);
sp.super_.time =
(lwp.pr_time.tv_sec * 100 + lwp.pr_time.tv_nsec / 10_000_000) as u64;
if !preExisting {
sp.super_.isUserlandThread = true;
Process_setParent(&mut sp.super_, ps.pr_pid * 1024);
Process_setThreadGroup(&mut sp.super_, ps.pr_pid * 1024);
sp.realppid = ps.pr_pid;
sp.realtgid = ps.pr_pid;
sp.super_.starttime_ctime = lwp.pr_start.tv_sec;
}
if sp.super_.isKernelThread && !hideKernelThreads {
sp.super_.super_.show = true;
}
if !sp.super_.isKernelThread && !hideUserlandThreads {
sp.super_.super_.show = true;
}
}
if !preExisting {
if sp.realppid <= 0 && !(sp.realpid <= 1) {
sp.super_.isKernelThread = true;
} else {
sp.super_.isKernelThread = false;
}
Process_fillStarttimeBuffer(&mut sp.super_);
}
sp.super_.super_.updated = true;
0
}
pub fn ProcessTable_goThroughEntries(this: &mut SolarisProcessTable) {
this.super_.kernelThreads = 1;
unsafe {
proc_walk(
SolarisProcessTable_walkproc,
&mut this.super_ as *mut ProcessTable as *mut c_void,
PR_WALK_LWP,
);
}
}