#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(dead_code)]
use std::mem::size_of;
use std::os::raw::{c_char, c_int, c_void};
use std::ptr;
use crate::ported::crt::CRT_fatalError;
use crate::ported::diskiometer::DiskIOData;
use crate::ported::meter::Meter;
use crate::ported::netbsd::netbsdmachine::NetBSDMachine;
use crate::ported::netbsd::netbsdprocesstable::kinfo_proc2;
use crate::ported::networkiometer::NetworkIOData;
const VM_LOADAVG: c_int = 2;
const CPU_METER_NICE: usize = 0;
const CPU_METER_NORMAL: usize = 1;
const CPU_METER_KERNEL: usize = 2;
const CPU_METER_IRQ: usize = 3;
const CPU_METER_SOFTIRQ: usize = 4;
const CPU_METER_STEAL: usize = 5;
const CPU_METER_GUEST: usize = 6;
const CPU_METER_IOWAIT: usize = 7;
const CPU_METER_FREQUENCY: usize = 8;
const CPU_METER_TEMPERATURE: usize = 9;
const SWAP_METER_USED: usize = 0;
const MEMORY_CLASS_WIRED: usize = 0;
const MEMORY_CLASS_ACTIVE: usize = 1;
const MEMORY_CLASS_PAGED: usize = 2;
const MEMORY_CLASS_INACTIVE: usize = 3;
const HW_IOSTATS: c_int = 9;
const IOSTAT_DISK: i32 = 0;
const IOSTATNAMELEN: usize = 16;
const KVM_NO_FILES: c_int = 0x8000_0000u32 as c_int;
const POSIX2_LINE_MAX: usize = 2048;
extern "C" {
fn kvm_openfiles(
execfile: *const c_char,
corefile: *const c_char,
swapfile: *const c_char,
flags: c_int,
errbuf: *mut c_char,
) -> *mut c_void;
fn kvm_close(kd: *mut c_void) -> c_int;
fn kvm_getproc2(
kd: *mut c_void,
op: c_int,
arg: c_int,
elemsize: usize,
cnt: *mut c_int,
) -> *const kinfo_proc2;
fn kvm_getenvv2(
kd: *mut c_void,
p: *const kinfo_proc2,
limit: c_int,
) -> *const *const c_char;
}
#[repr(C)]
#[derive(Clone, Copy)]
struct io_sysctl {
name: [c_char; IOSTATNAMELEN],
busy: i32,
r#type: i32,
xfer: u64,
seek: u64,
bytes: u64,
attachtime_sec: u32,
attachtime_usec: u32,
timestamp_sec: u32,
timestamp_usec: u32,
time_sec: u32,
time_usec: u32,
rxfer: u64,
rbytes: u64,
wxfer: u64,
wbytes: u64,
wait_sec: u32,
wait_usec: u32,
waitsum_sec: u32,
waitsum_usec: u32,
busysum_sec: u32,
busysum_usec: u32,
}
#[repr(C)]
struct loadavg {
ldavg: [u32; 3],
fscale: libc::c_long,
}
pub fn Platform_init() -> bool {
true
}
pub fn Platform_done() {
}
pub fn Platform_setBindings() {
}
pub fn Platform_getUptime() -> c_int {
let mut bootTime: libc::timeval = unsafe { std::mem::zeroed() };
let mib: [c_int; 2] = [libc::CTL_KERN, libc::KERN_BOOTTIME];
let mut size = size_of::<libc::timeval>();
let err = unsafe {
libc::sysctl(
mib.as_ptr(),
2,
&mut bootTime as *mut libc::timeval as *mut c_void,
&mut size,
ptr::null(),
0,
)
};
if err != 0 {
return -1;
}
let mut currTime: libc::timeval = unsafe { std::mem::zeroed() };
unsafe { libc::gettimeofday(&mut currTime, ptr::null_mut()) };
(currTime.tv_sec - bootTime.tv_sec) as c_int
}
pub fn Platform_getLoadAverage(one: &mut f64, five: &mut f64, fifteen: &mut f64) {
let mut loadAverage: loadavg = unsafe { std::mem::zeroed() };
let mib: [c_int; 2] = [libc::CTL_VM, VM_LOADAVG];
let mut size = size_of::<loadavg>();
let err = unsafe {
libc::sysctl(
mib.as_ptr(),
2,
&mut loadAverage as *mut loadavg as *mut c_void,
&mut size,
ptr::null(),
0,
)
};
if err != 0 {
*one = 0.0;
*five = 0.0;
*fifteen = 0.0;
return;
}
*one = loadAverage.ldavg[0] as f64 / loadAverage.fscale as f64;
*five = loadAverage.ldavg[1] as f64 / loadAverage.fscale as f64;
*fifteen = loadAverage.ldavg[2] as f64 / loadAverage.fscale as f64;
}
pub fn Platform_getMaxPid() -> libc::pid_t {
i32::MAX
}
pub fn Platform_setCPUValues(this: &mut Meter, cpu: c_int) -> f64 {
let host = this.host;
let nhost = host as *const NetBSDMachine;
let cpuData = unsafe {
let nh = &*nhost;
nh.cpuData[cpu as usize]
};
let total = if cpuData.totalPeriod == 0 {
1.0
} else {
cpuData.totalPeriod as f64
};
let detailed = unsafe {
(*host)
.settings
.as_ref()
.map(|s| s.detailedCPUTime)
.unwrap_or(false)
};
let v = &mut this.values;
v[CPU_METER_NICE] = cpuData.nicePeriod as f64 / total * 100.0;
v[CPU_METER_NORMAL] = cpuData.userPeriod as f64 / total * 100.0;
if detailed {
v[CPU_METER_KERNEL] = cpuData.sysPeriod as f64 / total * 100.0;
v[CPU_METER_IRQ] = cpuData.intrPeriod as f64 / total * 100.0;
v[CPU_METER_SOFTIRQ] = 0.0;
v[CPU_METER_STEAL] = 0.0;
v[CPU_METER_GUEST] = 0.0;
v[CPU_METER_IOWAIT] = 0.0;
v[CPU_METER_FREQUENCY] = f64::NAN;
this.curItems = 8;
} else {
v[CPU_METER_KERNEL] = cpuData.sysAllPeriod as f64 / total * 100.0;
v[CPU_METER_IRQ] = 0.0; this.curItems = 4;
}
let mut totalPercent = this.values[CPU_METER_NICE]
+ this.values[CPU_METER_NORMAL]
+ this.values[CPU_METER_KERNEL]
+ this.values[CPU_METER_IRQ];
totalPercent = totalPercent.clamp(0.0, 100.0);
this.values[CPU_METER_FREQUENCY] = cpuData.frequency;
this.values[CPU_METER_TEMPERATURE] = f64::NAN;
totalPercent
}
pub fn Platform_setMemoryValues(this: &mut Meter) {
let host = this.host;
let nhost = host as *const NetBSDMachine;
unsafe {
this.total = (*host).totalMem as f64;
this.values[MEMORY_CLASS_WIRED] = (*nhost).wiredMem as f64;
this.values[MEMORY_CLASS_ACTIVE] = (*nhost).activeMem as f64;
this.values[MEMORY_CLASS_PAGED] = (*nhost).pagedMem as f64;
this.values[MEMORY_CLASS_INACTIVE] = (*nhost).inactiveMem as f64;
}
}
pub fn Platform_setSwapValues(this: &mut Meter) {
let host = this.host;
unsafe {
this.total = (*host).totalSwap as f64;
this.values[SWAP_METER_USED] = (*host).usedSwap as f64;
}
}
pub fn Platform_getProcessEnv(pid: libc::pid_t) -> Option<String> {
let mut errbuf = [0 as c_char; POSIX2_LINE_MAX];
let kt = unsafe {
kvm_openfiles(
ptr::null(),
ptr::null(),
ptr::null(),
KVM_NO_FILES,
errbuf.as_mut_ptr(),
)
};
if kt.is_null() {
return None;
}
let mut count: c_int = 0;
let kproc = unsafe {
kvm_getproc2(
kt,
libc::KERN_PROC_PID,
pid,
size_of::<kinfo_proc2>(),
&mut count,
)
};
if kproc.is_null() {
unsafe { kvm_close(kt) };
return None;
}
let envv = unsafe { kvm_getenvv2(kt, kproc, 0) };
if envv.is_null() {
unsafe { kvm_close(kt) };
return None;
}
let mut env: Vec<u8> = Vec::with_capacity(4096);
let mut i = 0isize;
loop {
let p = unsafe { *envv.offset(i) };
if p.is_null() {
break;
}
let bytes = unsafe { std::ffi::CStr::from_ptr(p) }.to_bytes();
env.extend_from_slice(bytes);
env.push(0);
i += 1;
}
if env.len() < 2 || env[env.len() - 1] != 0 || env[env.len() - 2] != 0 {
env.push(0);
env.push(0);
}
unsafe { kvm_close(kt) };
Some(String::from_utf8_lossy(&env).into_owned())
}
pub fn Platform_getProcessLocks() {
todo!("port of Platform.c:360")
}
pub fn Platform_getFileDescriptors() {
todo!("port of Platform.c:365")
}
pub fn Platform_getDiskIO(data: &mut DiskIOData) -> bool {
let mib: [c_int; 3] = [libc::CTL_HW, HW_IOSTATS, size_of::<io_sysctl>() as c_int];
let mut buf: Vec<u8> = Vec::new();
let mut size: usize = 0;
let mut last_errno = 0;
for _retry in (1..=3).rev() {
if unsafe {
libc::sysctl(
mib.as_ptr(),
mib.len() as u32,
ptr::null_mut(),
&mut size,
ptr::null(),
0,
)
} < 0
{
CRT_fatalError("Unable to get size of io_sysctl");
}
if size == 0 {
return false;
}
buf.resize(size, 0);
let rc = unsafe {
libc::sysctl(
mib.as_ptr(),
mib.len() as u32,
buf.as_mut_ptr() as *mut c_void,
&mut size,
ptr::null(),
0,
)
};
if rc == 0 {
last_errno = 0;
break;
}
last_errno = std::io::Error::last_os_error().raw_os_error().unwrap_or(0);
if last_errno != libc::ENOMEM {
CRT_fatalError("Unable to get disk IO statistics");
}
}
if last_errno == libc::ENOMEM {
CRT_fatalError("Unable to get disk IO statistics");
}
let mut bytesReadSum: u64 = 0;
let mut bytesWriteSum: u64 = 0;
let mut busyTimeSum: u64 = 0;
let mut numDisks: u64 = 0;
let count = size / size_of::<io_sysctl>();
let entries =
unsafe { std::slice::from_raw_parts(buf.as_ptr() as *const io_sysctl, count) };
for io in entries {
if io.r#type != IOSTAT_DISK {
continue;
}
bytesReadSum += io.rbytes;
bytesWriteSum += io.wbytes;
busyTimeSum += io.busysum_usec as u64;
numDisks += 1;
}
data.totalBytesRead = bytesReadSum;
data.totalBytesWritten = bytesWriteSum;
data.totalMsTimeSpend = busyTimeSum / 1000;
data.numDisks = numDisks;
true
}
pub fn Platform_getNetworkIO(data: &mut NetworkIOData) -> bool {
let mut ifap: *mut libc::ifaddrs = ptr::null_mut();
if unsafe { libc::getifaddrs(&mut ifap) } != 0 {
return false;
}
let mut ifa = ifap;
while !ifa.is_null() {
let cur = unsafe { &*ifa };
ifa = cur.ifa_next;
if cur.ifa_addr.is_null() {
continue;
}
if unsafe { (*cur.ifa_addr).sa_family } as c_int != libc::AF_LINK {
continue;
}
if cur.ifa_flags & libc::IFF_LOOPBACK as libc::c_uint != 0 {
continue;
}
let ifd = cur.ifa_data as *const libc::if_data;
if ifd.is_null() {
continue;
}
let d = unsafe { &*ifd };
data.bytesReceived += d.ifi_ibytes;
data.packetsReceived += d.ifi_ipackets;
data.bytesTransmitted += d.ifi_obytes;
data.packetsTransmitted += d.ifi_opackets;
}
unsafe { libc::freeifaddrs(ifap) };
true
}
pub fn Platform_getBattery() {
todo!("port of Platform.c:449")
}