sys-info-0.9.1/.cargo_vcs_info.json0000644000000001120000000000100126040ustar { "git": { "sha1": "1c119b37ac0737466cd450f1fa7fb03af28024c8" } } sys-info-0.9.1/.gitattributes000064400000000000000000000000260072674642500143230ustar 00000000000000c/* linguist-vendored sys-info-0.9.1/.gitignore000064400000000000000000000002000072674642500134120ustar 00000000000000# Compiled files *.o *.so *.rlib *.dll # Executables *.out *.exe # Generated by Cargo target/ *.lock .idea/ *.code-workspace sys-info-0.9.1/.travis.yml000064400000000000000000000021740072674642500135470ustar 00000000000000os: - linux - osx - windows language: rust rust: - stable - beta - nightly # Apparently (according to VSCode), # `cache: rust` is invalid # Should be `cache: cargo`, # but this seems to hang the build on windows # Uncomment the below line and comment out the current line to enable cargo caching: # cache: cargo cache: rust matrix: allow_failures: - rust: nightly # Use the msvc toolchain of rust on windows # The Travis default is _-x86_64-pc-windows-gnu # But since we need windows libraries for this crate, # _-x86_64-pc-windows-msvc needs to be used instead. # See https://github.com/rust-lang/rustup/blob/master/README.md#working-with-rust-on-windows before_script: - if [ "$TRAVIS_OS_NAME" = "windows" ]; then rustup toolchain add $TRAVIS_RUST_VERSION-x86_64-pc-windows-msvc && rustup default $TRAVIS_RUST_VERSION-x86_64-pc-windows-msvc ; fi script: - cargo test --all --verbose # Note: Whilst Travis says to install these in the before_script, # on nightly the install command fails # so the install happens after tests so nightly tests are still ran - rustup component add clippy rustfmt - cargo clippy sys-info-0.9.1/CHANGELOG.md000064400000000000000000000021170072674642500132440ustar 00000000000000# ChangeLog ## 0.9.1 - Fix iOS Support and CPU speed doesn't work on ARM64 Macs either. - Rust Nightly fix - Add a cast to allow building on ILP32 systems - Prevent free swap from getting larger than total swap - Fix compiler errors/warnings for NetBSD/arm ## 0.9.0 - Typo fixes & test fixup - macOS: On failure copy the unknown value and null-terminate it correctly - Fix windows-gnu build - Support for NetBSD platform ## 0.8.0 - Fix build for target android - add OpenBSD support - Make get_cpu_speed arch-independent on windows - improve get_mem_info on macos - Make Disk Info Thread-Safe on Linux - Loop to find max CPU speed in Windows get_cpu_speed ## 0.7.0 - FreeBSD port. ## 0.6.1 - Restore `Send` trait to `Error` for wrapping with `error-chain` - Use cfg attribute instead of cfg! macro, which fixes Windows build errors in v0.6.0 ## 0.6.0 - Support illumos and Solaris systems ## 0.5.10 - Cast gethostname() arguments to a proper type. ## 0.5.9 - Optimize getHostname for hostname command might not be installed. ## 0.5.8 - Support get os-release information for Linux #38 sys-info-0.9.1/Cargo.toml0000644000000021220000000000100106050ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "sys-info" version = "0.9.1" authors = ["Siyu Wang "] build = "build.rs" links = "info" description = "Get system information in Rust.\n\nFor now it supports Linux, Mac OS X, illumos, Solaris, FreeBSD, OpenBSD, and Windows.\n" documentation = "https://docs.rs/sys-info" readme = "README.md" keywords = ["system", "cpu", "disk", "memory", "information"] license = "MIT" repository = "https://github.com/FillZpp/sys-info-rs" [lib] name = "sys_info" path = "lib.rs" [dependencies.libc] version = "0.2.29" [build-dependencies.cc] version = "1" sys-info-0.9.1/Cargo.toml.orig0000644000000010730000000000100115500ustar [package] name = "sys-info" version = "0.9.1" authors = ["Siyu Wang "] license = "MIT" readme = "README.md" keywords = ["system", "cpu", "disk", "memory", "information"] repository = "https://github.com/FillZpp/sys-info-rs" documentation = "https://docs.rs/sys-info" description = """ Get system information in Rust. For now it supports Linux, Mac OS X, illumos, Solaris, FreeBSD, OpenBSD, and Windows. """ links = "info" build = "build.rs" [lib] name = "sys_info" path = "lib.rs" [build-dependencies] cc = "1" [dependencies] libc = "0.2.29" sys-info-0.9.1/Cargo.toml.orig000064400000000000000000000010730072674642500143220ustar 00000000000000[package] name = "sys-info" version = "0.9.1" authors = ["Siyu Wang "] license = "MIT" readme = "README.md" keywords = ["system", "cpu", "disk", "memory", "information"] repository = "https://github.com/FillZpp/sys-info-rs" documentation = "https://docs.rs/sys-info" description = """ Get system information in Rust. For now it supports Linux, Mac OS X, illumos, Solaris, FreeBSD, OpenBSD, and Windows. """ links = "info" build = "build.rs" [lib] name = "sys_info" path = "lib.rs" [build-dependencies] cc = "1" [dependencies] libc = "0.2.29" sys-info-0.9.1/LICENSE000064400000000000000000000020650072674642500124420ustar 00000000000000The MIT License (MIT) Copyright (c) 2015 Siyu Wang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sys-info-0.9.1/README.md000064400000000000000000000010210072674642500127030ustar 00000000000000# sys-info-rs [![Build Status](https://travis-ci.org/FillZpp/sys-info-rs.svg?branch=master)](https://travis-ci.org/FillZpp/sys-info-rs) Get system information in Rust. 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) ### Usage Add this to `Cargo.toml`: ``` [dependencies] sys-info = "0.9" ``` and add this to crate root: ``` extern crate sys_info; ``` sys-info-0.9.1/build.rs000064400000000000000000000024450072674642500131040ustar 00000000000000extern crate cc; use std::env; fn main() { let target = env::var("TARGET").unwrap(); let target_os = target.split('-').nth(2).unwrap(); let mut builder = cc::Build::new(); match target_os { "linux" | "android" | "androideabi" => builder.file("c/linux.c"), "illumos" | "solaris" => { println!("cargo:rustc-link-lib=kstat"); return; } "darwin" | "ios" => builder.file("c/darwin.c"), "windows" => { // GCC linker (ld.exe) wants system libs specified after the source file. // MSVC linker (link.exe) doesn't seem to care. builder.file("c/windows.c") .compile("info"); println!("cargo:rustc-flags=-l psapi"); println!("cargo:rustc-flags=-l powrprof"); return; }, "freebsd" => { println!("cargo:rustc-flags=-l pthread"); builder.file("c/freebsd.c") }, "openbsd" => { 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"); } sys-info-0.9.1/c/info.h000064400000000000000000000014340072674642500127620ustar 00000000000000#ifndef INFO_H_ #define INFO_H_ typedef struct LoadAvg { double one; double five; double fifteen; } LoadAvg; typedef struct MemInfo { unsigned long long total; unsigned long long free; unsigned long long avail; unsigned long long buffers; unsigned long long cached; unsigned long long swap_total; unsigned long long swap_free; } MemInfo; typedef struct DiskInfo { unsigned long long total; unsigned long long free; } DiskInfo; const char *get_os_type(void); const char *get_os_release(void); unsigned int get_cpu_num(void); unsigned long get_cpu_speed(void); LoadAvg get_loadavg(void); unsigned long get_proc_total(void); MemInfo get_mem_info(void); DiskInfo get_disk_info(void); #endif sys-info-0.9.1/c/linux.c000064400000000000000000000107650072674642500131700ustar 00000000000000#include #include #include #include #include #include "info.h" #define DFHASHSIZE 101 #define MOUNTS "/proc/mounts" static const char *os_type = "Linux"; /* Internal Declarations */ struct nlist { struct nlist *next; char *name; }; unsigned int DFhash(const char*); struct nlist *seen_before(struct nlist**, const char*); void DFcleanup(struct nlist**); int remote_mount(const char*, const char*); float device_space(struct nlist**, char*, char*, double*, double*); /* Get information */ /* get_os_type & get_os_release /proc/sys/kernel */ const char *get_os_type(void) { return os_type; } const char *get_os_release(void) { return ""; } unsigned int get_cpu_num(void) { return get_nprocs(); } /* get_cpu_speed /sys/devices/system/cpu/cpu0 */ unsigned long get_cpu_speed(void) { return 0; } /* get_loadavg & get_proc_total /proc/loadavg */ LoadAvg get_loadavg(void) { static LoadAvg avg; return avg; } unsigned long get_proc_total(void) { return 0; } /* get_mem_info /proc/meminfo */ MemInfo get_mem_info(void) { static MemInfo info; return info; } DiskInfo get_disk_info(void) { FILE *mounts; char procline[1024]; struct nlist *DFhashvector[DFHASHSIZE] = {0}; char *mount, *device, *type, *mode, *other; float thispct, max=0.0; double dtotal=0.0, dfree=0.0; DiskInfo di; di.total = 0; di.free = 0; mounts = fopen(MOUNTS,"r"); if (!mounts) { return di; } while ( fgets(procline, sizeof(procline), mounts) ) { device = procline; mount = index(procline, ' '); if (mount == NULL) continue; *mount++ = '\0'; type = index(mount, ' '); if (type == NULL) continue; *type++ = '\0'; mode = index(type, ' '); if (mode == NULL) continue; *mode++ = '\0'; other = index(mode, ' '); if (other != NULL) *other = '\0'; if (!strncmp(mode, "ro", 2)) continue; if (remote_mount(device, type)) continue; if (strncmp(device, "/dev/", 5) != 0 && strncmp(device, "/dev2/", 6) != 0) continue; thispct = device_space(DFhashvector, mount, device, &dtotal, &dfree); if (!max || maxnext) { if (!strcmp(name,np->name)) { found=np; break; } } if (!found) { /* not found */ np = (struct nlist *) malloc(sizeof(*np)); if (!np || !(np->name = (char *) strdup(name))) return NULL; np->next = DFhashvector[hashval]; DFhashvector[hashval] = np; return NULL; } else /* found name */ return found; } void DFcleanup(struct nlist **DFhashvector) { struct nlist *np, *next; int i; for (i=0; inext; free(np->name); free(np); } DFhashvector[i] = 0; } } int remote_mount(const char *device, const char *type) { /* From ME_REMOTE macro in mountlist.h: A file system is `remote' if its Fs_name contains a `:' or if (it is of type smbfs and its Fs_name starts with `//'). */ return ((strchr(device,':') != 0) || (!strcmp(type, "smbfs") && device[0]=='/' && device[1]=='/') || (!strncmp(type, "nfs", 3)) || (!strcmp(type, "autofs")) || (!strcmp(type,"gfs")) || (!strcmp(type,"none")) ); } float device_space(struct nlist **DFhashvector, char *mount, char *device, double *total_size, double *total_free) { struct statvfs svfs; double blocksize; double free; double size; /* The percent used: used/total * 100 */ float pct=0.0; /* Avoid multiply-mounted disks - not done in df. */ if (seen_before(DFhashvector, device)) return pct; if (statvfs(mount, &svfs)) { /* Ignore funky devices... */ return pct; } free = svfs.f_bavail; size = svfs.f_blocks; blocksize = svfs.f_bsize; /* Keep running sum of total used, free local disk space. */ *total_size += size * blocksize; *total_free += free * blocksize; /* The percentage of space used on this partition. */ pct = size ? ((size - free) / (float) size) * 100 : 0.0; return pct; } sys-info-0.9.1/kstat.rs000064400000000000000000000213100072674642500131230ustar 00000000000000#![cfg(any(target_os = "solaris", target_os = "illumos"))] type Result = std::result::Result>; // There is presently no static CStr constructor, so use these constants with // the c() wrapper below: const MODULE_CPU_INFO: &[u8] = b"cpu_info\0"; const STAT_CLOCK_MHZ: &[u8] = b"clock_MHz\0"; const MODULE_UNIX: &[u8] = b"unix\0"; const NAME_SYSTEM_MISC: &[u8] = b"system_misc\0"; const STAT_BOOT_TIME: &[u8] = b"boot_time\0"; const STAT_NPROC: &[u8] = b"nproc\0"; const NAME_SYSTEM_PAGES: &[u8] = b"system_pages\0"; const STAT_FREEMEM: &[u8] = b"freemem\0"; const STAT_PHYSMEM: &[u8] = b"physmem\0"; fn c(buf: &[u8]) -> &std::ffi::CStr { std::ffi::CStr::from_bytes_with_nul(buf).expect("invalid string constant") } mod wrapper { use std::os::raw::c_int; use std::os::raw::c_uint; use std::os::raw::c_char; use std::os::raw::c_uchar; use std::os::raw::c_void; use std::os::raw::c_long; use std::os::raw::c_ulong; use std::os::raw::c_longlong; use std::ptr::{null, null_mut, NonNull}; use std::ffi::CStr; const KSTAT_TYPE_NAMED: c_uchar = 1; const KSTAT_STRLEN: usize = 31; #[repr(C)] struct Kstat { ks_crtime: c_longlong, ks_next: *mut Kstat, ks_kid: c_uint, ks_module: [c_char; KSTAT_STRLEN], ks_resv: c_uchar, ks_instance: c_int, ks_name: [c_char; KSTAT_STRLEN], ks_type: c_uchar, ks_class: [c_char; KSTAT_STRLEN], ks_flags: c_uchar, ks_data: *mut c_void, ks_ndata: c_uint, ks_data_size: usize, ks_snaptime: c_longlong, } impl Kstat { fn name(&self) -> &CStr { unsafe { CStr::from_ptr(self.ks_name.as_ptr()) } } fn module(&self) -> &CStr { unsafe { CStr::from_ptr(self.ks_module.as_ptr()) } } } #[repr(C)] struct KstatCtl { kc_chain_id: c_uint, kc_chain: *mut Kstat, kc_kd: c_int, } #[repr(C)] #[derive(Copy, Clone)] union KstatValue { c: [c_char; 16], l: c_long, ul: c_ulong, ui32: u32, } #[repr(C)] struct KstatNamed { name: [c_char; KSTAT_STRLEN], data_type: c_uchar, value: KstatValue, } extern "C" { fn kstat_open() -> *mut KstatCtl; fn kstat_close(kc: *mut KstatCtl) -> c_int; fn kstat_lookup(kc: *mut KstatCtl, module: *const c_char, instance: c_int, name: *const c_char) -> *mut Kstat; fn kstat_read(kc: *mut KstatCtl, ksp: *mut Kstat, buf: *mut c_void) -> c_int; fn kstat_data_lookup(ksp: *mut Kstat, name: *const c_char) -> *mut c_void; } /// Minimal wrapper around libkstat(3LIB) on illumos and Solaris systems. pub struct KstatWrapper { kc: NonNull, ks: Option>, stepping: bool, } /// Turn an optional CStr into a (const char *) for Some, or NULL for None. fn cp(p: &Option<&CStr>) -> *const c_char { p.map_or_else(|| null(), |p| p.as_ptr()) } impl KstatWrapper { pub fn open() -> super::Result { let kc = NonNull::new(unsafe { kstat_open() }); if let Some(kc) = kc { Ok(KstatWrapper { kc: kc, ks: None, stepping: false, }) } else { let e = std::io::Error::last_os_error(); Err(format!("kstat_open(3KSTAT) failed: {}", e).into()) } } /// Call kstat_lookup(3KSTAT) and store the result, if there is a match. pub fn lookup(&mut self, module: Option<&CStr>, name: Option<&CStr>) { self.ks = NonNull::new(unsafe { kstat_lookup(self.kc.as_ptr(), cp(&module), -1, cp(&name)) }); self.stepping = false; } /// Call once to start iterating, and then repeatedly for each /// additional kstat in the chain. Returns false once there are no more /// kstat entries. pub fn step(&mut self) -> bool { if !self.stepping { self.stepping = true; } else { self.ks = self.ks.map_or(None, |ks| NonNull::new(unsafe { ks.as_ref() }.ks_next)); } if self.ks.is_none() { self.stepping = false; false } else { true } } /// Return the module name of the current kstat. This routine will /// panic if step() has not returned true. pub fn module(&self) -> &CStr { let ks = self.ks.as_ref().expect("step() must return true first"); unsafe { ks.as_ref() }.module() } /// Return the name of the current kstat. This routine will panic if /// step() has not returned true. pub fn name(&self) -> &CStr { let ks = self.ks.as_ref().expect("step() must return true first"); unsafe { ks.as_ref() }.name() } /// Look up a named kstat value. For internal use by typed accessors. fn data_value(&self, statistic: &CStr) -> Option> { let (ks, ksp) = if let Some(ks) = &self.ks { (unsafe { ks.as_ref() }, ks.as_ptr()) } else { return None; }; if unsafe { kstat_read(self.kc.as_ptr(), ksp, null_mut()) } == -1 { return None; } if ks.ks_type != KSTAT_TYPE_NAMED || ks.ks_ndata < 1 { // This is not a named kstat, or it has no data payload. return None; } NonNull::new(unsafe { kstat_data_lookup(ksp, cp(&Some(statistic))) }).map(|voidp| voidp.cast()) } /// Look up a named kstat value and interpret it as a "long_t". pub fn data_long(&self, statistic: &CStr) -> Option { self.data_value(statistic).map(|kn| unsafe { kn.as_ref().value.l } as i64) } /// Look up a named kstat value and interpret it as a "ulong_t". pub fn data_ulong(&self, statistic: &CStr) -> Option { self.data_value(statistic).map(|kn| unsafe { kn.as_ref().value.ul } as u64) } /// Look up a named kstat value and interpret it as a "uint32_t". pub fn data_u32(&self, statistic: &CStr) -> Option { self.data_value(statistic).map(|kn| unsafe { kn.as_ref().value.ui32 }) } } impl Drop for KstatWrapper { fn drop(&mut self) { unsafe { kstat_close(self.kc.as_ptr()) }; } } } pub fn cpu_mhz() -> Result { let mut k = wrapper::KstatWrapper::open()?; k.lookup(Some(c(MODULE_CPU_INFO)), None); while k.step() { if k.module() != c(MODULE_CPU_INFO) { continue; } if let Some(mhz) = k.data_long(c(STAT_CLOCK_MHZ)) { return Ok(mhz as u64); } } return Err("cpu speed kstat not found".into()); } pub fn boot_time() -> Result { let mut k = wrapper::KstatWrapper::open()?; k.lookup(Some(c(MODULE_UNIX)), Some(c(NAME_SYSTEM_MISC))); while k.step() { if k.module() != c(MODULE_UNIX) || k.name() != c(NAME_SYSTEM_MISC) { continue; } if let Some(boot_time) = k.data_u32(c(STAT_BOOT_TIME)) { return Ok(boot_time as u64); } } return Err("boot time kstat not found".into()); } pub fn nproc() -> Result { let mut k = wrapper::KstatWrapper::open()?; k.lookup(Some(c(MODULE_UNIX)), Some(c(NAME_SYSTEM_MISC))); while k.step() { if k.module() != c(MODULE_UNIX) || k.name() != c(NAME_SYSTEM_MISC) { continue; } if let Some(nproc) = k.data_u32(c(STAT_NPROC)) { return Ok(nproc as u64); } } return Err("process count kstat not found".into()); } pub struct Pages { pub freemem: u64, pub physmem: u64, } pub fn pages() -> Result { let mut k = wrapper::KstatWrapper::open()?; k.lookup(Some(c(MODULE_UNIX)), Some(c(NAME_SYSTEM_PAGES))); while k.step() { if k.module() != c(MODULE_UNIX) || k.name() != c(NAME_SYSTEM_PAGES) { continue; } let freemem = k.data_ulong(c(STAT_FREEMEM)); let physmem = k.data_ulong(c(STAT_PHYSMEM)); if freemem.is_some() && physmem.is_some() { return Ok(Pages { freemem: freemem.unwrap(), physmem: physmem.unwrap(), }); } } return Err("system pages kstat not available".into()); } sys-info-0.9.1/lib.rs000064400000000000000000001015460072674642500125550ustar 00000000000000//! #Introduction //! This crate focuses on geting system information. //! //! For now it supports Linux, Mac OS X and Windows. //! And now it can get information of kernel/cpu/memory/disk/load/hostname and so on. //! extern crate libc; use std::ffi; use std::fmt; use std::io::{self, Read}; use std::fs::File; #[cfg(any(target_os = "windows", target_vendor = "apple", 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_vendor = "apple", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] use libc::sysctl; #[cfg(any(target_vendor = "apple", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] use std::mem::size_of_val; #[cfg(any(target_vendor = "apple", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] use std::ptr::null_mut; #[cfg(not(target_os = "windows"))] use libc::timeval; #[cfg(any(target_os = "solaris", target_os = "illumos"))] use std::time::SystemTime; #[cfg(target_os = "linux")] use std::collections::HashMap; #[cfg(any(target_os = "solaris", target_os = "illumos"))] mod kstat; #[cfg(any(target_vendor = "apple", target_os="freebsd", target_os = "openbsd", target_os = "netbsd"))] static OS_CTL_KERN: libc::c_int = 1; #[cfg(any(target_vendor = "apple", target_os="freebsd", target_os = "openbsd", target_os = "netbsd"))] static OS_KERN_BOOTTIME: libc::c_int = 21; /// System load average value. #[repr(C)] #[derive(Debug)] pub struct LoadAvg { /// Average load within one minutes. pub one: f64, /// Average load within five minutes. pub five: f64, /// Average load within fifteen minutes. pub fifteen: f64, } /// System memory information. #[repr(C)] #[derive(Debug)] pub struct MemInfo { /// Total physical memory. pub total: u64, pub free: u64, pub avail: u64, pub buffers: u64, pub cached: u64, /// Total swap memory. pub swap_total: u64, pub swap_free: u64, } /// The os release info of Linux. /// /// See [man os-release](https://www.freedesktop.org/software/systemd/man/os-release.html). #[derive(Debug)] #[derive(Default)] pub struct LinuxOSReleaseInfo { /// A lower-case string (no spaces or other characters outside of 0–9, a–z, ".", "_" and "-") /// identifying the operating system, excluding any version information and suitable for /// processing by scripts or usage in generated filenames. /// /// Note that we don't verify that the string is lower-case and can be used in file-names. If /// the /etc/os-release file has an invalid value, you will get this value. /// /// If not set, defaults to "ID=linux". Use `self.id()` to fallback to the default. /// /// Example: "fedora" or "debian". pub id: Option, /// A space-separated list of operating system identifiers in the same syntax as the ID= /// setting. It should list identifiers of operating systems that are closely related to the /// local operating system in regards to packaging and programming interfaces, for example /// listing one or more OS identifiers the local OS is a derivative from. An OS should /// generally only list other OS identifiers it itself is a derivative of, and not any OSes /// that are derived from it, though symmetric relationships are possible. Build scripts and /// similar should check this variable if they need to identify the local operating system and /// the value of ID= is not recognized. Operating systems should be listed in order of how /// closely the local operating system relates to the listed ones, starting with the closest. /// /// This field is optional. /// /// Example: for an operating system with `ID=centos`, an assignment of `ID_LIKE="rhel fedora"` /// would be appropriate. For an operating system with `ID=ubuntu`, an assignment of /// `ID_LIKE=debian` is appropriate. pub id_like: Option, /// A string identifying the operating system, without a version component, and suitable for /// presentation to the user. /// /// If not set, defaults to "NAME=Linux".Use `self.id()` to fallback to the default. /// /// Example: "Fedora" or "Debian GNU/Linux". pub name: Option, /// A pretty operating system name in a format suitable for presentation to the user. May or /// may not contain a release code name or OS version of some kind, as suitable. /// /// If not set, defaults to "Linux". Use `self.id()` to fallback to the default. /// /// Example: "Fedora 17 (Beefy Miracle)". pub pretty_name: Option, /// A string identifying the operating system version, excluding any OS name information, /// possibly including a release code name, and suitable for presentation to the user. /// /// This field is optional. /// /// Example: "17" or "17 (Beefy Miracle)" pub version: Option, /// A lower-case string (mostly numeric, no spaces or other characters outside of 0–9, a–z, /// ".", "_" and "-") identifying the operating system version, excluding any OS name /// information or release code name, and suitable for processing by scripts or usage in /// generated filenames. /// /// This field is optional. /// /// Example: "17" or "11.04". pub version_id: Option, /// A lower-case string (no spaces or other characters outside of 0–9, a–z, ".", "_" and "-") /// identifying the operating system release code name, excluding any OS name information or /// release version, and suitable for processing by scripts or usage in generated filenames. /// /// This field is optional and may not be implemented on all systems. /// /// Examples: "buster", "xenial". pub version_codename: Option, /// A suggested presentation color when showing the OS name on the console. This should be /// specified as string suitable for inclusion in the ESC [ m ANSI/ECMA-48 escape code for /// setting graphical rendition. /// /// This field is optional. /// /// Example: "0;31" for red, "1;34" for light blue, or "0;38;2;60;110;180" for Fedora blue. pub ansi_color: Option, /// A string, specifying the name of an icon as defined by freedesktop.org Icon Theme /// Specification. This can be used by graphical applications to display an operating /// system's or distributor's logo. /// /// This field is optional and may not necessarily be implemented on all systems. /// /// Examples: "LOGO=fedora-logo", "LOGO=distributor-logo-opensuse". pub logo: Option, /// A CPE name for the operating system, in URI binding syntax, following the Common Platform /// Enumeration Specification as proposed by the NIST. /// /// This field is optional. /// /// Example: "cpe:/o:fedoraproject:fedora:17". pub cpe_name: Option, /// A string uniquely identifying the system image used as the origin for a distribution (it is /// not updated with system updates). The field can be identical between different VERSION_IDs /// as BUILD_ID is an only a unique identifier to a specific version. Distributions that /// release each update as a new version would only need to use VERSION_ID as each build is /// already distinct based on the VERSION_ID. /// /// This field is optional. /// /// Example: "2013-03-20.3" or "BUILD_ID=201303203". pub build_id: Option, /// A string identifying a specific variant or edition of the operating system suitable for /// presentation to the user. This field may be used to inform the user that the configuration /// of this system is subject to a specific divergent set of rules or default configuration /// settings. /// /// This field is optional and may not be implemented on all systems. /// /// Examples: "Server Edition", "Smart Refrigerator Edition". /// /// Note: this field is for display purposes only. The VARIANT_ID field should be used for /// making programmatic decisions. pub variant: Option, /// A lower-case string (no spaces or other characters outside of 0–9, a–z, ".", "_" and "-"), /// identifying a specific variant or edition of the operating system. This may be interpreted /// by other packages in order to determine a divergent default configuration. /// /// This field is optional and may not be implemented on all systems. /// /// Examples: "server", "embedded". pub variant_id: Option, /// HOME_URL= should refer to the homepage of the operating system, or alternatively some homepage of /// the specific version of the operating system. /// /// These URLs are intended to be exposed in "About this system" UIs behind links with captions /// such as "About this Operating System", "Obtain Support", "Report a Bug", or "Privacy /// Policy". The values should be in RFC3986 format, and should be "http:" or "https:" URLs, /// and possibly "mailto:" or "tel:". Only one URL shall be listed in each setting. If multiple /// resources need to be referenced, it is recommended to provide an online landing page /// linking all available resources. /// /// Example: "https://fedoraproject.org/". pub home_url: Option, /// DOCUMENTATION_URL= should refer to the main documentation page for this operating system. /// /// See also `home_url`. pub documentation_url: Option, /// SUPPORT_URL= should refer to the main support page for the operating system, if there is /// any. This is primarily intended for operating systems which vendors provide support for. /// /// See also `home_url`. pub support_url: Option, /// BUG_REPORT_URL= should refer to the main bug reporting page for the operating system, if /// there is any. This is primarily intended for operating systems that rely on community QA. /// /// Example: "https://bugzilla.redhat.com/". /// /// See also `home_url`. pub bug_report_url: Option, /// PRIVACY_POLICY_URL= should refer to the main privacy policy page for the operating system, /// if there is any. These settings are optional, and providing only some of these settings is /// common. /// /// See also `home_url`. pub privacy_policy_url: Option, } macro_rules! os_release_defaults { ( $( $(#[$meta:meta])* $vis:vis fn $field:ident => $default:literal )* ) => { $( $(#[$meta])* $vis fn $field(&self) -> &str { match self.$field.as_ref() { Some(value) => value, None => $default, } } )* } } impl LinuxOSReleaseInfo { os_release_defaults!( /// Returns the value of `self.id` or, if `None`, "linux" (the default value). pub fn id => "linux" /// Returns the value of `self.name` or, if `None`, "Linux" (the default value). pub fn name => "Linux" /// Returns the value of `self.pretty_name` or, if `None`, "Linux" (the default value). pub fn pretty_name => "Linux" ); } /// Disk information. #[repr(C)] #[derive(Debug)] pub struct DiskInfo { pub total: u64, pub free: u64, } /// Error types #[derive(Debug)] pub enum Error { UnsupportedSystem, ExecFailed(io::Error), IO(io::Error), SystemTime(std::time::SystemTimeError), General(String), Unknown, } impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { use self::Error::*; match *self { UnsupportedSystem => write!(fmt, "System is not supported"), ExecFailed(ref e) => write!(fmt, "Execution failed: {}", e), IO(ref e) => write!(fmt, "IO error: {}", e), SystemTime(ref e) => write!(fmt, "System time error: {}", e), General(ref e) => write!(fmt, "Error: {}", e), Unknown => write!(fmt, "An unknown error occurred"), } } } impl std::error::Error for Error { fn description(&self) -> &str { use self::Error::*; match *self { UnsupportedSystem => "unsupported system", ExecFailed(_) => "execution failed", IO(_) => "io error", SystemTime(_) => "system time", General(_) => "general error", Unknown => "unknown error", } } fn cause(&self) -> Option<&dyn std::error::Error> { use self::Error::*; match *self { UnsupportedSystem => None, ExecFailed(ref e) => Some(e), IO(ref e) => Some(e), SystemTime(ref e) => Some(e), General(_) => None, Unknown => None, } } } impl From for Error { fn from(e: io::Error) -> Error { Error::IO(e) } } impl From for Error { fn from(e: std::time::SystemTimeError) -> Error { Error::SystemTime(e) } } impl From> for Error { fn from(e: Box) -> Error { Error::General(e.to_string()) } } extern "C" { #[cfg(any(target_vendor = "apple", target_os = "windows"))] fn get_os_type() -> *const i8; #[cfg(any(target_vendor = "apple", 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", target_os = "netbsd")), any(unix, windows)))] fn get_cpu_num() -> u32; #[cfg(any(all(target_vendor = "apple", not(any(target_arch = "aarch64", target_arch = "arm"))), 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_vendor = "apple", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] fn get_proc_total() -> u64; #[cfg(any(target_vendor = "apple", target_os = "windows"))] fn get_mem_info() -> MemInfo; #[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_vendor = "apple", target_os = "windows"))] fn get_disk_info() -> DiskInfo; #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] fn get_disk_info_bsd(di: &mut DiskInfo) -> i32; } /// Get operation system type. /// /// Such as "Linux", "Darwin", "Windows". pub fn os_type() -> Result { #[cfg(target_os = "linux")] { let mut s = String::new(); File::open("/proc/sys/kernel/ostype")?.read_to_string(&mut s)?; s.pop(); // pop '\n' Ok(s) } #[cfg(any(target_vendor = "apple", target_os = "windows"))] { let typ = unsafe { ffi::CStr::from_ptr(get_os_type() as *const c_char).to_bytes() }; Ok(String::from_utf8_lossy(typ).into_owned()) } #[cfg(target_os = "solaris")] { Ok("solaris".to_string()) } #[cfg(target_os = "illumos")] { Ok("illumos".to_string()) } #[cfg(target_os = "freebsd")] { Ok("freebsd".to_string()) } #[cfg(target_os = "openbsd")] { Ok("openbsd".to_string()) } #[cfg(target_os = "netbsd")] { Ok("netbsd".to_string()) } #[cfg(not(any(target_os = "linux", target_vendor = "apple", target_os = "windows", target_os = "solaris", target_os = "illumos", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] { Err(Error::UnsupportedSystem) } } /// Get operation system release version. /// /// Such as "3.19.0-gentoo" pub fn os_release() -> Result { #[cfg(target_os = "linux")] { let mut s = String::new(); File::open("/proc/sys/kernel/osrelease")?.read_to_string(&mut s)?; s.pop(); // pop '\n' Ok(s) } #[cfg(any(target_vendor = "apple", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))] { unsafe { let rp = get_os_release() as *const c_char; if rp == std::ptr::null() { Err(Error::Unknown) } else { let typ = ffi::CStr::from_ptr(rp).to_bytes(); Ok(String::from_utf8_lossy(typ).into_owned()) } } } #[cfg(any(target_os = "solaris", target_os = "illumos"))] { let release: Option = unsafe { let mut name: libc::utsname = std::mem::zeroed(); if libc::uname(&mut name) < 0 { None } else { let cstr = std::ffi::CStr::from_ptr(name.release.as_mut_ptr()); Some(cstr.to_string_lossy().to_string()) } }; match release { None => Err(Error::Unknown), Some(release) => Ok(release), } } #[cfg(not(any(target_os = "linux", target_vendor = "apple", target_os = "windows", target_os = "solaris", target_os = "illumos", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] { Err(Error::UnsupportedSystem) } } /// Get the os release note of Linux /// /// Information in /etc/os-release, such as name and version of distribution. /// /// See `LinuxOSReleaseInfo` for more documentation. pub fn linux_os_release() -> Result { if !cfg!(target_os = "linux") { return Err(Error::UnsupportedSystem); } let mut s = String::new(); File::open("/etc/os-release")?.read_to_string(&mut s)?; let mut info: LinuxOSReleaseInfo = Default::default(); for l in s.split('\n') { match parse_line_for_linux_os_release(l.trim().to_string()) { Some((key, value)) => match (key.as_ref(), value) { ("ID", val) => info.id = Some(val), ("ID_LIKE", val) => info.id_like = Some(val), ("NAME", val) => info.name = Some(val), ("PRETTY_NAME", val) => info.pretty_name = Some(val), ("VERSION", val) => info.version = Some(val), ("VERSION_ID", val) => info.version_id = Some(val), ("VERSION_CODENAME", val) => info.version_codename = Some(val), ("ANSI_COLOR", val) => info.ansi_color = Some(val), ("LOGO", val) => info.logo = Some(val), ("CPE_NAME", val) => info.cpe_name = Some(val), ("BUILD_ID", val) => info.build_id = Some(val), ("VARIANT", val) => info.variant = Some(val), ("VARIANT_ID", val) => info.variant_id = Some(val), ("HOME_URL", val) => info.home_url = Some(val), ("BUG_REPORT_URL", val) => info.bug_report_url = Some(val), ("SUPPORT_URL", val) => info.support_url = Some(val), ("DOCUMENTATION_URL", val) => info.documentation_url = Some(val), ("PRIVACY_POLICY_URL", val) => info.privacy_policy_url = Some(val), _ => {} } None => {} } } Ok(info) } fn parse_line_for_linux_os_release(l: String) -> Option<(String, String)> { let words: Vec<&str> = l.splitn(2, '=').collect(); if words.len() < 2 { return None } let mut trim_value = String::from(words[1]); if trim_value.starts_with('"') { trim_value.remove(0); } if trim_value.ends_with('"') { let len = trim_value.len(); trim_value.remove(len - 1); } return Some((String::from(words[0]), trim_value)) } /// Get cpu num quantity. /// /// 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", target_os = "netbsd"))] { let ret = unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) }; if ret < 1 || ret as i64 > std::u32::MAX as i64 { Err(Error::IO(io::Error::last_os_error())) } else { Ok(ret as u32) } } #[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()) } } #[cfg(not(any(target_os = "solaris", target_os = "illumos", unix, windows)))] { Err(Error::UnsupportedSystem) } } /// Get cpu speed. /// /// Such as 2500, that is 2500 MHz. pub fn cpu_speed() -> Result { #[cfg(any(target_os = "solaris", target_os = "illumos"))] { Ok(kstat::cpu_mhz()?) } #[cfg(target_os = "linux")] { // /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq let mut s = String::new(); File::open("/proc/cpuinfo")?.read_to_string(&mut s)?; let find_cpu_mhz = s.split('\n').find(|line| line.starts_with("cpu MHz\t") || line.starts_with("BogoMIPS") || line.starts_with("clock\t") || line.starts_with("bogomips per cpu") ); find_cpu_mhz.and_then(|line| line.split(':').last()) .and_then(|val| val.replace("MHz", "").trim().parse::().ok()) .map(|speed| speed as u64) .ok_or(Error::Unknown) } #[cfg(any(all(target_vendor = "apple", not(any(target_arch = "aarch64", target_arch = "arm"))), target_os = "windows"))] { unsafe { Ok(get_cpu_speed()) } } #[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", all(target_vendor = "apple", not(any(target_arch = "aarch64", target_arch = "arm"))), target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] { Err(Error::UnsupportedSystem) } } /// Get system load average value. /// /// Notice, on windows, one/five/fifteen of the LoadAvg returned are the current load. pub fn loadavg() -> Result { #[cfg(target_os = "linux")] { let mut s = String::new(); File::open("/proc/loadavg")?.read_to_string(&mut s)?; let loads = s.trim().split(' ') .take(3) .map(|val| val.parse::().unwrap()) .collect::>(); Ok(LoadAvg { one: loads[0], five: loads[1], fifteen: loads[2], }) } #[cfg(any(target_os = "solaris", target_os = "illumos", target_vendor = "apple", 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 { Err(Error::Unknown) } else { Ok(LoadAvg { one: l[0], five: l[1], fifteen: l[2], }) } } #[cfg(any(target_os = "windows"))] { Ok(unsafe { get_loadavg() }) } #[cfg(not(any(target_os = "linux", target_os = "solaris", target_os = "illumos", target_vendor = "apple", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] { Err(Error::UnsupportedSystem) } } /// Get current processes quantity. pub fn proc_total() -> Result { #[cfg(any(target_os = "solaris", target_os = "illumos"))] { Ok(kstat::nproc()?) } #[cfg(target_os = "linux")] { let mut s = String::new(); File::open("/proc/loadavg")?.read_to_string(&mut s)?; s.split(' ') .nth(3) .and_then(|val| val.split('/').last()) .and_then(|val| val.parse::().ok()) .ok_or(Error::Unknown) } #[cfg(any(target_vendor = "apple", target_os = "windows"))] { Ok(unsafe { get_proc_total() }) } #[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_vendor = "apple", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] { Err(Error::UnsupportedSystem) } } #[cfg(any(target_os = "solaris", target_os = "illumos"))] fn pagesize() -> Result { let ret = unsafe { libc::sysconf(libc::_SC_PAGESIZE) }; if ret < 1 || ret > std::u32::MAX as i64 { Err(Error::Unknown) } else { Ok(ret as u32) } } /// Get memory information. /// /// On Mac OS X and Windows, the buffers and cached variables of the MemInfo returned are zero. pub fn mem_info() -> Result { #[cfg(target_os = "linux")] { let mut s = String::new(); File::open("/proc/meminfo")?.read_to_string(&mut s)?; let mut meminfo_hashmap = HashMap::new(); for line in s.lines() { let mut split_line = line.split_whitespace(); let label = split_line.next(); let value = split_line.next(); if value.is_some() && label.is_some() { let label = label.unwrap().split(':').nth(0).ok_or(Error::Unknown)?; let value = value.unwrap().parse::().ok().ok_or(Error::Unknown)?; meminfo_hashmap.insert(label, value); } } let total = *meminfo_hashmap.get("MemTotal").ok_or(Error::Unknown)?; let free = *meminfo_hashmap.get("MemFree").ok_or(Error::Unknown)?; let buffers = *meminfo_hashmap.get("Buffers").ok_or(Error::Unknown)?; let cached = *meminfo_hashmap.get("Cached").ok_or(Error::Unknown)?; let avail = meminfo_hashmap.get("MemAvailable").map(|v| v.clone()).or_else(|| { let sreclaimable = *meminfo_hashmap.get("SReclaimable")?; let shmem = *meminfo_hashmap.get("Shmem")?; Some(free + buffers + cached + sreclaimable - shmem) }).ok_or(Error::Unknown)?; let swap_total = *meminfo_hashmap.get("SwapTotal").ok_or(Error::Unknown)?; let swap_free = *meminfo_hashmap.get("SwapFree").ok_or(Error::Unknown)?; Ok(MemInfo { total, free, avail, buffers, cached, swap_total, swap_free, }) } #[cfg(any(target_os = "solaris", target_os = "illumos"))] { let pagesize = pagesize()? as u64; let pages = kstat::pages()?; return Ok(MemInfo { total: pages.physmem * pagesize / 1024, avail: 0, free: pages.freemem * pagesize / 1024, cached: 0, buffers: 0, swap_total: 0, swap_free: 0, }); } #[cfg(any(target_vendor = "apple", target_os = "windows"))] { Ok(unsafe { get_mem_info() }) } #[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}; let res: i32 = unsafe { get_mem_info_bsd(&mut mi) }; match res { -1 => Err(Error::IO(io::Error::last_os_error())), 0 => Ok(mi), _ => Err(Error::Unknown), } } #[cfg(not(any(target_os = "linux", target_os = "solaris", target_os = "illumos", target_vendor = "apple", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] { Err(Error::UnsupportedSystem) } } /// Get disk information. /// /// Notice, it just calculate current disk on Windows. pub fn disk_info() -> Result { #[cfg(any(target_os = "linux", target_vendor = "apple", target_os = "windows"))] { Ok(unsafe { get_disk_info() }) } #[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) }; match res { -1 => Err(Error::IO(io::Error::last_os_error())), 0 => Ok(di), _ => Err(Error::Unknown), } } #[cfg(not(any(target_os = "linux", target_vendor = "apple", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] { Err(Error::UnsupportedSystem) } } /// Get hostname. #[cfg(target_family = "unix")] pub fn hostname() -> Result { unsafe { let buf_size = libc::sysconf(libc::_SC_HOST_NAME_MAX) as usize; let mut buf = Vec::::with_capacity(buf_size + 1); if libc::gethostname(buf.as_mut_ptr() as *mut libc::c_char, buf_size) < 0 { return Err(Error::IO(io::Error::last_os_error())); } let hostname_len = libc::strnlen(buf.as_ptr() as *const libc::c_char, buf_size); buf.set_len(hostname_len); Ok(ffi::CString::new(buf).unwrap().into_string().unwrap()) } } #[cfg(target_family = "windows")] pub fn hostname() -> Result { use std::process::Command; Command::new("hostname") .output() .map_err(Error::ExecFailed) .map(|output| String::from_utf8(output.stdout).unwrap().trim().to_string()) } /// Get system boottime #[cfg(not(windows))] pub fn boottime() -> Result { let mut bt = timeval { tv_sec: 0, tv_usec: 0 }; #[cfg(any(target_os = "linux", target_os="android"))] { let mut s = String::new(); File::open("/proc/uptime")?.read_to_string(&mut s)?; let secs = s.trim().split(' ') .take(2) .map(|val| val.parse::().unwrap()) .collect::>(); bt.tv_sec = secs[0] as libc::time_t; bt.tv_usec = secs[1] as libc::suseconds_t; return Ok(bt); } #[cfg(any(target_vendor = "apple", 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; unsafe { if sysctl(&mut mib[0], 2, &mut bt as *mut timeval as *mut libc::c_void, &mut size, null_mut(), 0) == -1 { return Err(Error::IO(io::Error::last_os_error())); } else { return Ok(bt); } } } #[cfg(any(target_os = "solaris", target_os = "illumos"))] { let start = kstat::boot_time()?; let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?; let now = now.as_secs(); if now < start { return Err(Error::General("time went backwards".into())); } bt.tv_sec = (now - start) as i64; return Ok(bt); } #[warn(unreachable_code)] Err(Error::UnsupportedSystem) } #[cfg(test)] mod test { use super::*; #[test] pub fn test_os_type() { let typ = os_type().unwrap(); assert!(typ.len() > 0); println!("os_type(): {}", typ); } #[test] pub fn test_os_release() { let release = os_release().unwrap(); assert!(release.len() > 0); println!("os_release(): {}", release); } #[test] pub fn test_cpu_num() { let num = cpu_num().unwrap(); assert!(num > 0); println!("cpu_num(): {}", num); } #[test] #[cfg(not(all(target_vendor = "apple", target_arch = "aarch64")))] pub fn test_cpu_speed() { let speed = cpu_speed().unwrap(); assert!(speed > 0); println!("cpu_speed(): {}", speed); } #[test] pub fn test_loadavg() { let load = loadavg().unwrap(); println!("loadavg(): {:?}", load); } #[test] pub fn test_proc_total() { let procs = proc_total().unwrap(); assert!(procs > 0); println!("proc_total(): {}", procs); } #[test] pub fn test_mem_info() { let mem = mem_info().unwrap(); assert!(mem.total > 0); println!("mem_info(): {:?}", mem); } #[test] #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] pub fn test_disk_info() { let info = disk_info().unwrap(); println!("disk_info(): {:?}", info); } #[test] pub fn test_hostname() { let host = hostname().unwrap(); assert!(host.len() > 0); println!("hostname(): {}", host); } #[test] #[cfg(not(windows))] pub fn test_boottime() { let bt = boottime().unwrap(); println!("boottime(): {} {}", bt.tv_sec, bt.tv_usec); assert!(bt.tv_sec > 0 || bt.tv_usec > 0); } #[test] #[cfg(target_os = "linux")] pub fn test_linux_os_release() { let os_release = linux_os_release().unwrap(); println!("linux_os_release(): {:?}", os_release.name) } }