diff --git a/README.md b/README.md index 76ba9ce..a6c4b9a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Get system information in Rust. -For now it supports Linux, Mac OS X, illumos, Solaris, FreeBSD, OpenBSD, and Windows. +For now it supports Linux, Mac OS X, illumos, Solaris, FreeBSD, OpenBSD, NetBSD and Windows. And now it can get information of kernel/cpu/memory/disk/load/hostname and so on. [Documentation](https://docs.rs/sys-info) diff --git a/build.rs b/build.rs index 9e0f2fa..58c72b6 100644 --- a/build.rs +++ b/build.rs @@ -27,6 +27,10 @@ fn main() { println!("cargo:rustc-flags=-l pthread"); builder.file("c/openbsd.c") }, + "netbsd" => { + println!("cargo:rustc-flags=-l pthread"); + builder.file("c/netbsd.c") + }, _ => panic!("unsupported system: {}", target_os) }; builder.compile("info"); diff --git a/c/netbsd.c b/c/netbsd.c new file mode 100644 index 0000000..0dccdbd --- /dev/null +++ b/c/netbsd.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "info.h" + +#define ONE_K 1024L +#define ONE_DECIMAL_K 1000L + +#ifndef PAGE_SIZE +#define PAGE_SIZE ( sysconf(_SC_PAGESIZE) ) +#endif +#define PAGE_SIZE_KB ( PAGE_SIZE / ONE_K ) + +static const char *os_release; + +static pthread_once_t once_init_netbsd; +static void init_netbsd(void) { + struct utsname un; + + if (uname(&un) == -1) + return; + os_release = strdup(un.release); +} + +const char *get_os_release(void) { + pthread_once(&once_init_netbsd, init_netbsd); + return (os_release); +} + +uint64_t get_cpu_speed(void) { + uint64_t tsc_freq; + size_t len; + int error; + +#if defined(__i386__) || defined(__amd64__) + len = sizeof(tsc_freq); + error = sysctlbyname("machdep.tsc_freq", &tsc_freq, &len, NULL, 0); + if (error == -1) + return (0); +#else + tsc_freq = ONE_DECIMAL_K * ONE_DECIMAL_K * ONE_DECIMAL_K; +#endif + return (tsc_freq / ONE_DECIMAL_K / ONE_DECIMAL_K); +} + +unsigned long get_proc_total(void) { + char errbuf[_POSIX2_LINE_MAX]; + int count; + kvm_t *kd; + struct kinfo_proc *kp; + + if ((kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL) + return (0); + + if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &count)) == NULL) { + (void) kvm_close(kd); + return(0); + } + + kvm_close(kd); + free(kp); + return (unsigned long) (count); +} + +int32_t get_mem_info_bsd(struct MemInfo *mi) { + static int uvmexp_mib[] = {CTL_VM, VM_UVMEXP2}; + struct uvmexp_sysctl uvmexp; + size_t size_uvmexp = sizeof(uvmexp); + int error; + + error = sysctl(uvmexp_mib, 2, &uvmexp, &size_uvmexp, NULL, 0); + if (error == -1) + goto fail; + + // These calculations have been taken from sys/miscfs/procfs + // They need review for testing the correctness + mi->total = (uint64_t)uvmexp.npages * PAGE_SIZE_KB / ONE_K; + mi->avail = 0; + mi->free = (uint64_t)uvmexp.free * PAGE_SIZE_KB / ONE_K; + mi->cached = (uvmexp.anonpages + uvmexp.filepages + uvmexp.execpages) * PAGE_SIZE_KB / ONE_K; + mi->buffers = uvmexp.filepages * PAGE_SIZE_KB / ONE_K; + mi->swap_total = uvmexp.swpages * PAGE_SIZE_KB / ONE_K; + mi->swap_free = (uvmexp.swpages - uvmexp.swpginuse) * PAGE_SIZE_KB / ONE_K; + return (0); + +fail: + return (-1); +} + +int32_t get_disk_info_bsd(DiskInfo *di) { + struct statvfs *svfs, *svf; + int i, nmounts; + uint64_t dtotal, dfree; + int32_t res = 0; + + dtotal = 0; + dfree = 0; + svfs = NULL; + res = -1; + + nmounts = getvfsstat(NULL, 0, MNT_WAIT); + if (nmounts == -1) + goto fail; + svfs = calloc(nmounts, sizeof(*svfs)); + if (svfs == NULL) + goto fail; + nmounts = getvfsstat(svfs, nmounts * sizeof(*svfs), MNT_WAIT); + if (nmounts == -1) + goto fail; + + for (i = 0; i < nmounts; i++) { + svf = &svfs[i]; + if ((svf->f_flag & MNT_LOCAL) != MNT_LOCAL) + continue; + dtotal += svf->f_blocks * svf->f_bsize; + dfree += svf->f_bfree * svf->f_bsize; + } + + di->total = dtotal / 1000; + di->free = dfree / 1000; + res = 0; + +fail: + free(svfs); + return (res); +} diff --git a/lib.rs b/lib.rs index eb871e2..9d616c1 100644 --- a/lib.rs +++ b/lib.rs @@ -11,16 +11,16 @@ use std::ffi; use std::fmt; use std::io::{self, Read}; use std::fs::File; -#[cfg(any(target_os = "windows", target_os = "macos", target_os = "freebsd", target_os = "openbsd"))] +#[cfg(any(target_os = "windows", target_os = "macos", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] use std::os::raw::c_char; #[cfg(not(any(target_os = "windows", target_os = "linux")))] use std::os::raw::{c_int, c_double}; -#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))] +#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] use libc::sysctl; -#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))] +#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] use std::mem::size_of_val; -#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))] +#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] use std::ptr::null_mut; #[cfg(not(target_os = "windows"))] use libc::timeval; @@ -32,9 +32,9 @@ use std::collections::HashMap; #[cfg(any(target_os = "solaris", target_os = "illumos"))] mod kstat; -#[cfg(any(target_os = "macos", target_os="freebsd", target_os = "openbsd"))] +#[cfg(any(target_os = "macos", target_os="freebsd", target_os = "openbsd", target_os = "netbsd"))] static OS_CTL_KERN: libc::c_int = 1; -#[cfg(any(target_os = "macos", target_os="freebsd", target_os = "openbsd"))] +#[cfg(any(target_os = "macos", target_os="freebsd", target_os = "openbsd", target_os = "netbsd"))] static OS_KERN_BOOTTIME: libc::c_int = 21; /// System load average value. @@ -353,27 +353,27 @@ impl From> for Error { extern "C" { #[cfg(any(target_os = "macos", target_os = "windows"))] fn get_os_type() -> *const i8; - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd"))] + #[cfg(any(target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] fn get_os_release() -> *const i8; - #[cfg(all(not(any(target_os = "solaris", target_os = "illumos", target_os = "freebsd", target_os = "openbsd")), any(unix, windows)))] + #[cfg(all(not(any(target_os = "solaris", target_os = "illumos", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")), any(unix, windows)))] fn get_cpu_num() -> u32; - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd"))] + #[cfg(any(target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] fn get_cpu_speed() -> u64; #[cfg(target_os = "windows")] fn get_loadavg() -> LoadAvg; - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd"))] + #[cfg(any(target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] fn get_proc_total() -> u64; #[cfg(any(target_os = "macos", target_os = "windows"))] fn get_mem_info() -> MemInfo; - #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] + #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] fn get_mem_info_bsd(mi: &mut MemInfo) ->i32; #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] fn get_disk_info() -> DiskInfo; - #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] + #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] fn get_disk_info_bsd(di: &mut DiskInfo) -> i32; } @@ -410,7 +410,11 @@ pub fn os_type() -> Result { { Ok("openbsd".to_string()) } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "solaris", target_os = "illumos", target_os = "freebsd", target_os = "openbsd")))] + #[cfg(target_os = "netbsd")] + { + Ok("netbsd".to_string()) + } + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "solaris", target_os = "illumos", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] { Err(Error::UnsupportedSystem) } @@ -427,7 +431,7 @@ pub fn os_release() -> Result { s.pop(); // pop '\n' Ok(s) } - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd"))] + #[cfg(any(target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] { unsafe { let rp = get_os_release() as *const c_char; @@ -455,7 +459,7 @@ pub fn os_release() -> Result { Some(release) => Ok(release), } } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "solaris", target_os = "illumos", target_os = "freebsd", target_os = "openbsd")))] + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "solaris", target_os = "illumos", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] { Err(Error::UnsupportedSystem) } @@ -532,7 +536,7 @@ fn parse_line_for_linux_os_release(l: String) -> Option<(String, String)> { /// /// Notice, it returns the logical cpu quantity. pub fn cpu_num() -> Result { - #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "freebsd", target_os = "openbsd"))] + #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] { let ret = unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) }; if ret < 1 || ret > std::u32::MAX as i64 { @@ -541,7 +545,7 @@ pub fn cpu_num() -> Result { Ok(ret as u32) } } - #[cfg(all(not(any(target_os = "solaris", target_os = "illumos", target_os="freebsd", target_os = "openbsd")), any(unix, windows)))] + #[cfg(all(not(any(target_os = "solaris", target_os = "illumos", target_os="freebsd", target_os = "openbsd", target_os = "netbsd")), any(unix, windows)))] { unsafe { Ok(get_cpu_num()) } } @@ -581,7 +585,7 @@ pub fn cpu_speed() -> Result { { unsafe { Ok(get_cpu_speed()) } } - #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] + #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] { let res: u64 = unsafe { get_cpu_speed() }; match res { @@ -589,7 +593,7 @@ pub fn cpu_speed() -> Result { _ => Ok(res), } } - #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "linux", target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd")))] + #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "linux", target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] { Err(Error::UnsupportedSystem) } @@ -613,7 +617,7 @@ pub fn loadavg() -> Result { fifteen: loads[2], }) } - #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "macos", target_os = "freebsd", target_os = "openbsd"))] + #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "macos", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] { let mut l: [c_double; 3] = [0f64; 3]; if unsafe { libc::getloadavg(l.as_mut_ptr(), l.len() as c_int) } < 3 { @@ -630,7 +634,7 @@ pub fn loadavg() -> Result { { Ok(unsafe { get_loadavg() }) } - #[cfg(not(any(target_os = "linux", target_os = "solaris", target_os = "illumos", target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd")))] + #[cfg(not(any(target_os = "linux", target_os = "solaris", target_os = "illumos", target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] { Err(Error::UnsupportedSystem) } @@ -656,7 +660,7 @@ pub fn proc_total() -> Result { { Ok(unsafe { get_proc_total() }) } - #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] + #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] { let res: u64 = unsafe { get_proc_total() }; match res { @@ -664,7 +668,7 @@ pub fn proc_total() -> Result { _ => Ok(res), } } - #[cfg(not(any(target_os = "linux", target_os = "solaris", target_os = "illumos", target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd")))] + #[cfg(not(any(target_os = "linux", target_os = "solaris", target_os = "illumos", target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] { Err(Error::UnsupportedSystem) } @@ -738,7 +742,7 @@ pub fn mem_info() -> Result { { Ok(unsafe { get_mem_info() }) } - #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] + #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] { let mut mi:MemInfo = MemInfo{total: 0, free: 0, avail: 0, buffers: 0, cached: 0, swap_total: 0, swap_free: 0}; @@ -749,7 +753,7 @@ pub fn mem_info() -> Result { _ => Err(Error::Unknown), } } - #[cfg(not(any(target_os = "linux", target_os = "solaris", target_os = "illumos", target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd")))] + #[cfg(not(any(target_os = "linux", target_os = "solaris", target_os = "illumos", target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] { Err(Error::UnsupportedSystem) } @@ -763,7 +767,7 @@ pub fn disk_info() -> Result { { Ok(unsafe { get_disk_info() }) } - #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] + #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] { let mut di:DiskInfo = DiskInfo{total: 0, free: 0}; let res: i32 = unsafe { get_disk_info_bsd(&mut di) }; @@ -773,7 +777,7 @@ pub fn disk_info() -> Result { _ => Err(Error::Unknown), } } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd")))] + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] { Err(Error::UnsupportedSystem) } @@ -823,7 +827,7 @@ pub fn boottime() -> Result { bt.tv_usec = secs[1] as libc::suseconds_t; Ok(bt) } - #[cfg(any(target_os = "macos", target_os="freebsd", target_os = "openbsd"))] + #[cfg(any(target_os = "macos", target_os="freebsd", target_os = "openbsd", target_os = "netbsd"))] { let mut mib = [OS_CTL_KERN, OS_KERN_BOOTTIME]; let mut size: libc::size_t = size_of_val(&bt) as libc::size_t;