Skip to content

Commit

Permalink
Adds support for NetBSD platform. (#91)
Browse files Browse the repository at this point in the history
* Adds support for NetBSD platform.

* Minor refactor of the variable name for consistency.

* Update the README to include NetBSD in the list of supported OSes.
  • Loading branch information
fraggerfox authored Apr 9, 2021
1 parent b1eb2e4 commit 11a4dad
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 29 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
140 changes: 140 additions & 0 deletions c/netbsd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <sys/swap.h>
#include <sys/sysctl.h>
#include <sys/utsname.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <kvm.h>

#include <uvm/uvm_extern.h>

#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);
}
60 changes: 32 additions & 28 deletions lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
Expand Down Expand Up @@ -353,27 +353,27 @@ impl From<Box<dyn std::error::Error>> 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;
}

Expand Down Expand Up @@ -410,7 +410,11 @@ pub fn os_type() -> Result<String, Error> {
{
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)
}
Expand All @@ -427,7 +431,7 @@ pub fn os_release() -> Result<String, Error> {
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;
Expand Down Expand Up @@ -455,7 +459,7 @@ pub fn os_release() -> Result<String, Error> {
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)
}
Expand Down Expand Up @@ -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<u32, Error> {
#[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 {
Expand All @@ -541,7 +545,7 @@ pub fn cpu_num() -> Result<u32, Error> {
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()) }
}
Expand Down Expand Up @@ -581,15 +585,15 @@ pub fn cpu_speed() -> Result<u64, Error> {
{
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 {
0 => Err(Error::IO(io::Error::last_os_error())),
_ => 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)
}
Expand All @@ -613,7 +617,7 @@ pub fn loadavg() -> Result<LoadAvg, Error> {
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 {
Expand All @@ -630,7 +634,7 @@ pub fn loadavg() -> Result<LoadAvg, Error> {
{
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)
}
Expand All @@ -656,15 +660,15 @@ pub fn proc_total() -> Result<u64, Error> {
{
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 {
0 => Err(Error::IO(io::Error::last_os_error())),
_ => 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)
}
Expand Down Expand Up @@ -738,7 +742,7 @@ pub fn mem_info() -> Result<MemInfo, Error> {
{
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};
Expand All @@ -749,7 +753,7 @@ pub fn mem_info() -> Result<MemInfo, Error> {
_ => 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)
}
Expand All @@ -763,7 +767,7 @@ pub fn disk_info() -> Result<DiskInfo, Error> {
{
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) };
Expand All @@ -773,7 +777,7 @@ pub fn disk_info() -> Result<DiskInfo, Error> {
_ => 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)
}
Expand Down Expand Up @@ -823,7 +827,7 @@ pub fn boottime() -> Result<timeval, Error> {
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;
Expand Down

0 comments on commit 11a4dad

Please sign in to comment.