1extern crate libc;
9
10use std::ffi;
11use std::fmt;
12use std::io::{self, Read};
13use std::fs::File;
14#[cfg(any(target_os = "windows", target_vendor = "apple", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
15use std::os::raw::c_char;
16#[cfg(not(any(target_os = "windows", target_os = "linux")))]
17use std::os::raw::{c_int, c_double};
18
19#[cfg(any(target_vendor = "apple", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
20use libc::sysctl;
21#[cfg(any(target_vendor = "apple", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
22use std::mem::size_of_val;
23#[cfg(any(target_vendor = "apple", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
24use std::ptr::null_mut;
25#[cfg(not(target_os = "windows"))]
26use libc::timeval;
27#[cfg(any(target_os = "solaris", target_os = "illumos"))]
28use std::time::SystemTime;
29#[cfg(target_os = "linux")]
30use std::collections::HashMap;
31
32#[cfg(any(target_os = "solaris", target_os = "illumos"))]
33mod kstat;
34
35#[cfg(any(target_vendor = "apple", target_os="freebsd", target_os = "openbsd", target_os = "netbsd"))]
36static OS_CTL_KERN: libc::c_int = 1;
37#[cfg(any(target_vendor = "apple", target_os="freebsd", target_os = "openbsd", target_os = "netbsd"))]
38static OS_KERN_BOOTTIME: libc::c_int = 21;
39
40#[repr(C)]
42#[derive(Debug)]
43pub struct LoadAvg {
44 pub one: f64,
46 pub five: f64,
48 pub fifteen: f64,
50}
51
52#[repr(C)]
54#[derive(Debug)]
55pub struct MemInfo {
56 pub total: u64,
58 pub free: u64,
59 pub avail: u64,
60
61 pub buffers: u64,
62 pub cached: u64,
63
64 pub swap_total: u64,
66 pub swap_free: u64,
67}
68
69#[derive(Debug)]
73#[derive(Default)]
74pub struct LinuxOSReleaseInfo {
75 pub id: Option<String>,
86
87 pub id_like: Option<String>,
103
104 pub name: Option<String>,
111
112 pub pretty_name: Option<String>,
119
120 pub version: Option<String>,
127
128 pub version_id: Option<String>,
137
138 pub version_codename: Option<String>,
146
147 pub ansi_color: Option<String>,
155
156 pub logo: Option<String>,
164
165 pub cpe_name: Option<String>,
172
173 pub build_id: Option<String>,
183
184 pub variant: Option<String>,
196
197 pub variant_id: Option<String>,
205
206 pub home_url: Option<String>,
218
219 pub documentation_url: Option<String>,
223
224 pub support_url: Option<String>,
229
230 pub bug_report_url: Option<String>,
237
238 pub privacy_policy_url: Option<String>,
244}
245
246macro_rules! os_release_defaults {
247 (
248 $(
249 $(#[$meta:meta])*
250 $vis:vis fn $field:ident => $default:literal
251 )*
252 ) => {
253 $(
254 $(#[$meta])*
255 $vis fn $field(&self) -> &str {
256 match self.$field.as_ref() {
257 Some(value) => value,
258 None => $default,
259 }
260 }
261 )*
262 }
263}
264
265impl LinuxOSReleaseInfo {
266 os_release_defaults!(
267 pub fn id => "linux"
269 pub fn name => "Linux"
271 pub fn pretty_name => "Linux"
273 );
274}
275
276#[repr(C)]
278#[derive(Debug)]
279pub struct DiskInfo {
280 pub total: u64,
281 pub free: u64,
282}
283
284#[derive(Debug)]
286pub enum Error {
287 UnsupportedSystem,
288 ExecFailed(io::Error),
289 IO(io::Error),
290 SystemTime(std::time::SystemTimeError),
291 General(String),
292 Unknown,
293}
294
295impl fmt::Display for Error {
296 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
297 use self::Error::*;
298 match *self {
299 UnsupportedSystem => write!(fmt, "System is not supported"),
300 ExecFailed(ref e) => write!(fmt, "Execution failed: {}", e),
301 IO(ref e) => write!(fmt, "IO error: {}", e),
302 SystemTime(ref e) => write!(fmt, "System time error: {}", e),
303 General(ref e) => write!(fmt, "Error: {}", e),
304 Unknown => write!(fmt, "An unknown error occurred"),
305 }
306 }
307}
308
309impl std::error::Error for Error {
310 fn description(&self) -> &str {
311 use self::Error::*;
312 match *self {
313 UnsupportedSystem => "unsupported system",
314 ExecFailed(_) => "execution failed",
315 IO(_) => "io error",
316 SystemTime(_) => "system time",
317 General(_) => "general error",
318 Unknown => "unknown error",
319 }
320 }
321
322 fn cause(&self) -> Option<&dyn std::error::Error> {
323 use self::Error::*;
324 match *self {
325 UnsupportedSystem => None,
326 ExecFailed(ref e) => Some(e),
327 IO(ref e) => Some(e),
328 SystemTime(ref e) => Some(e),
329 General(_) => None,
330 Unknown => None,
331 }
332 }
333}
334
335impl From<io::Error> for Error {
336 fn from(e: io::Error) -> Error {
337 Error::IO(e)
338 }
339}
340
341impl From<std::time::SystemTimeError> for Error {
342 fn from(e: std::time::SystemTimeError) -> Error {
343 Error::SystemTime(e)
344 }
345}
346
347impl From<Box<dyn std::error::Error>> for Error {
348 fn from(e: Box<dyn std::error::Error>) -> Error {
349 Error::General(e.to_string())
350 }
351}
352
353extern "C" {
354 #[cfg(any(target_vendor = "apple", target_os = "windows"))]
355 fn get_os_type() -> *const i8;
356 #[cfg(any(target_vendor = "apple", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
357 fn get_os_release() -> *const i8;
358
359 #[cfg(all(not(any(target_os = "solaris", target_os = "illumos", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")), any(unix, windows)))]
360 fn get_cpu_num() -> u32;
361 #[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"))]
362 fn get_cpu_speed() -> u64;
363
364 #[cfg(target_os = "windows")]
365 fn get_loadavg() -> LoadAvg;
366 #[cfg(any(target_vendor = "apple", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
367 fn get_proc_total() -> u64;
368
369 #[cfg(any(target_vendor = "apple", target_os = "windows"))]
370 fn get_mem_info() -> MemInfo;
371 #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
372 fn get_mem_info_bsd(mi: &mut MemInfo) ->i32;
373
374 #[cfg(any(target_os = "linux", target_vendor = "apple", target_os = "windows"))]
375 fn get_disk_info() -> DiskInfo;
376 #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
377 fn get_disk_info_bsd(di: &mut DiskInfo) -> i32;
378}
379
380
381pub fn os_type() -> Result<String, Error> {
385 #[cfg(target_os = "linux")]
386 {
387 let mut s = String::new();
388 File::open("/proc/sys/kernel/ostype")?.read_to_string(&mut s)?;
389 s.pop(); Ok(s)
391 }
392 #[cfg(any(target_vendor = "apple", target_os = "windows"))]
393 {
394 let typ = unsafe { ffi::CStr::from_ptr(get_os_type() as *const c_char).to_bytes() };
395 Ok(String::from_utf8_lossy(typ).into_owned())
396 }
397 #[cfg(target_os = "solaris")]
398 {
399 Ok("solaris".to_string())
400 }
401 #[cfg(target_os = "illumos")]
402 {
403 Ok("illumos".to_string())
404 }
405 #[cfg(target_os = "freebsd")]
406 {
407 Ok("freebsd".to_string())
408 }
409 #[cfg(target_os = "openbsd")]
410 {
411 Ok("openbsd".to_string())
412 }
413 #[cfg(target_os = "netbsd")]
414 {
415 Ok("netbsd".to_string())
416 }
417 #[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")))]
418 {
419 Err(Error::UnsupportedSystem)
420 }
421}
422
423pub fn os_release() -> Result<String, Error> {
427 #[cfg(target_os = "linux")]
428 {
429 let mut s = String::new();
430 File::open("/proc/sys/kernel/osrelease")?.read_to_string(&mut s)?;
431 s.pop(); Ok(s)
433 }
434 #[cfg(any(target_vendor = "apple", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
435 {
436 unsafe {
437 let rp = get_os_release() as *const c_char;
438 if rp == std::ptr::null() {
439 Err(Error::Unknown)
440 } else {
441 let typ = ffi::CStr::from_ptr(rp).to_bytes();
442 Ok(String::from_utf8_lossy(typ).into_owned())
443 }
444 }
445 }
446 #[cfg(any(target_os = "solaris", target_os = "illumos"))]
447 {
448 let release: Option<String> = unsafe {
449 let mut name: libc::utsname = std::mem::zeroed();
450 if libc::uname(&mut name) < 0 {
451 None
452 } else {
453 let cstr = std::ffi::CStr::from_ptr(name.release.as_mut_ptr());
454 Some(cstr.to_string_lossy().to_string())
455 }
456 };
457 match release {
458 None => Err(Error::Unknown),
459 Some(release) => Ok(release),
460 }
461 }
462 #[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")))]
463 {
464 Err(Error::UnsupportedSystem)
465 }
466}
467
468pub fn linux_os_release() -> Result<LinuxOSReleaseInfo, Error> {
474 if !cfg!(target_os = "linux") {
475 return Err(Error::UnsupportedSystem);
476 }
477
478 let mut s = String::new();
479 File::open("/etc/os-release")?.read_to_string(&mut s)?;
480
481 let mut info: LinuxOSReleaseInfo = Default::default();
482 for l in s.split('\n') {
483 match parse_line_for_linux_os_release(l.trim().to_string()) {
484 Some((key, value)) =>
485 match (key.as_ref(), value) {
486 ("ID", val) => info.id = Some(val),
487 ("ID_LIKE", val) => info.id_like = Some(val),
488 ("NAME", val) => info.name = Some(val),
489 ("PRETTY_NAME", val) => info.pretty_name = Some(val),
490
491 ("VERSION", val) => info.version = Some(val),
492 ("VERSION_ID", val) => info.version_id = Some(val),
493 ("VERSION_CODENAME", val) => info.version_codename = Some(val),
494
495 ("ANSI_COLOR", val) => info.ansi_color = Some(val),
496 ("LOGO", val) => info.logo = Some(val),
497
498 ("CPE_NAME", val) => info.cpe_name = Some(val),
499 ("BUILD_ID", val) => info.build_id = Some(val),
500 ("VARIANT", val) => info.variant = Some(val),
501 ("VARIANT_ID", val) => info.variant_id = Some(val),
502
503 ("HOME_URL", val) => info.home_url = Some(val),
504 ("BUG_REPORT_URL", val) => info.bug_report_url = Some(val),
505 ("SUPPORT_URL", val) => info.support_url = Some(val),
506 ("DOCUMENTATION_URL", val) => info.documentation_url = Some(val),
507 ("PRIVACY_POLICY_URL", val) => info.privacy_policy_url = Some(val),
508 _ => {}
509 }
510 None => {}
511 }
512 }
513
514 Ok(info)
515}
516
517fn parse_line_for_linux_os_release(l: String) -> Option<(String, String)> {
518 let words: Vec<&str> = l.splitn(2, '=').collect();
519 if words.len() < 2 {
520 return None
521 }
522 let mut trim_value = String::from(words[1]);
523
524 if trim_value.starts_with('"') {
525 trim_value.remove(0);
526 }
527 if trim_value.ends_with('"') {
528 let len = trim_value.len();
529 trim_value.remove(len - 1);
530 }
531
532 return Some((String::from(words[0]), trim_value))
533}
534
535pub fn cpu_num() -> Result<u32, Error> {
539 #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
540 {
541 let ret = unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) };
542 if ret < 1 || ret as i64 > std::u32::MAX as i64 {
543 Err(Error::IO(io::Error::last_os_error()))
544 } else {
545 Ok(ret as u32)
546 }
547 }
548 #[cfg(all(not(any(target_os = "solaris", target_os = "illumos", target_os="freebsd", target_os = "openbsd", target_os = "netbsd")), any(unix, windows)))]
549 {
550 unsafe { Ok(get_cpu_num()) }
551 }
552 #[cfg(not(any(target_os = "solaris", target_os = "illumos", unix, windows)))]
553 {
554 Err(Error::UnsupportedSystem)
555 }
556}
557
558pub fn cpu_speed() -> Result<u64, Error> {
562 #[cfg(any(target_os = "solaris", target_os = "illumos"))]
563 {
564 Ok(kstat::cpu_mhz()?)
565 }
566 #[cfg(target_os = "linux")]
567 {
568 let mut s = String::new();
570 File::open("/proc/cpuinfo")?.read_to_string(&mut s)?;
571
572 let find_cpu_mhz = s.split('\n').find(|line|
573 line.starts_with("cpu MHz\t") ||
574 line.starts_with("BogoMIPS") ||
575 line.starts_with("clock\t") ||
576 line.starts_with("bogomips per cpu")
577 );
578
579 find_cpu_mhz.and_then(|line| line.split(':').last())
580 .and_then(|val| val.replace("MHz", "").trim().parse::<f64>().ok())
581 .map(|speed| speed as u64)
582 .ok_or(Error::Unknown)
583 }
584 #[cfg(any(all(target_vendor = "apple", not(any(target_arch = "aarch64", target_arch = "arm"))), target_os = "windows"))]
585 {
586 unsafe { Ok(get_cpu_speed()) }
587 }
588 #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
589 {
590 let res: u64 = unsafe { get_cpu_speed() };
591 match res {
592 0 => Err(Error::IO(io::Error::last_os_error())),
593 _ => Ok(res),
594 }
595 }
596 #[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")))]
597 {
598 Err(Error::UnsupportedSystem)
599 }
600}
601
602pub fn loadavg() -> Result<LoadAvg, Error> {
606 #[cfg(target_os = "linux")]
607 {
608 let mut s = String::new();
609 File::open("/proc/loadavg")?.read_to_string(&mut s)?;
610 let loads = s.trim().split(' ')
611 .take(3)
612 .map(|val| val.parse::<f64>().unwrap())
613 .collect::<Vec<f64>>();
614 Ok(LoadAvg {
615 one: loads[0],
616 five: loads[1],
617 fifteen: loads[2],
618 })
619 }
620 #[cfg(any(target_os = "solaris", target_os = "illumos", target_vendor = "apple", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
621 {
622 let mut l: [c_double; 3] = [0f64; 3];
623 if unsafe { libc::getloadavg(l.as_mut_ptr(), l.len() as c_int) } < 3 {
624 Err(Error::Unknown)
625 } else {
626 Ok(LoadAvg {
627 one: l[0],
628 five: l[1],
629 fifteen: l[2],
630 })
631 }
632 }
633 #[cfg(any(target_os = "windows"))]
634 {
635 Ok(unsafe { get_loadavg() })
636 }
637 #[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")))]
638 {
639 Err(Error::UnsupportedSystem)
640 }
641}
642
643pub fn proc_total() -> Result<u64, Error> {
645 #[cfg(any(target_os = "solaris", target_os = "illumos"))]
646 {
647 Ok(kstat::nproc()?)
648 }
649 #[cfg(target_os = "linux")]
650 {
651 let mut s = String::new();
652 File::open("/proc/loadavg")?.read_to_string(&mut s)?;
653 s.split(' ')
654 .nth(3)
655 .and_then(|val| val.split('/').last())
656 .and_then(|val| val.parse::<u64>().ok())
657 .ok_or(Error::Unknown)
658 }
659 #[cfg(any(target_vendor = "apple", target_os = "windows"))]
660 {
661 Ok(unsafe { get_proc_total() })
662 }
663 #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
664 {
665 let res: u64 = unsafe { get_proc_total() };
666 match res {
667 0 => Err(Error::IO(io::Error::last_os_error())),
668 _ => Ok(res),
669 }
670 }
671 #[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")))]
672 {
673 Err(Error::UnsupportedSystem)
674 }
675}
676
677#[cfg(any(target_os = "solaris", target_os = "illumos"))]
678fn pagesize() -> Result<u32, Error> {
679 let ret = unsafe { libc::sysconf(libc::_SC_PAGESIZE) };
680 if ret < 1 || ret > std::u32::MAX as i64 {
681 Err(Error::Unknown)
682 } else {
683 Ok(ret as u32)
684 }
685}
686
687pub fn mem_info() -> Result<MemInfo, Error> {
691 #[cfg(target_os = "linux")]
692 {
693 let mut s = String::new();
694 File::open("/proc/meminfo")?.read_to_string(&mut s)?;
695 let mut meminfo_hashmap = HashMap::new();
696 for line in s.lines() {
697 let mut split_line = line.split_whitespace();
698 let label = split_line.next();
699 let value = split_line.next();
700 if value.is_some() && label.is_some() {
701 let label = label.unwrap().split(':').nth(0).ok_or(Error::Unknown)?;
702 let value = value.unwrap().parse::<u64>().ok().ok_or(Error::Unknown)?;
703 meminfo_hashmap.insert(label, value);
704 }
705 }
706 let total = *meminfo_hashmap.get("MemTotal").ok_or(Error::Unknown)?;
707 let free = *meminfo_hashmap.get("MemFree").ok_or(Error::Unknown)?;
708 let buffers = *meminfo_hashmap.get("Buffers").ok_or(Error::Unknown)?;
709 let cached = *meminfo_hashmap.get("Cached").ok_or(Error::Unknown)?;
710 let avail = meminfo_hashmap.get("MemAvailable").map(|v| v.clone()).or_else(|| {
711 let sreclaimable = *meminfo_hashmap.get("SReclaimable")?;
712 let shmem = *meminfo_hashmap.get("Shmem")?;
713 Some(free + buffers + cached + sreclaimable - shmem)
714 }).ok_or(Error::Unknown)?;
715 let swap_total = *meminfo_hashmap.get("SwapTotal").ok_or(Error::Unknown)?;
716 let swap_free = *meminfo_hashmap.get("SwapFree").ok_or(Error::Unknown)?;
717 Ok(MemInfo {
718 total,
719 free,
720 avail,
721 buffers,
722 cached,
723 swap_total,
724 swap_free,
725 })
726 }
727 #[cfg(any(target_os = "solaris", target_os = "illumos"))]
728 {
729 let pagesize = pagesize()? as u64;
730 let pages = kstat::pages()?;
731 return Ok(MemInfo {
732 total: pages.physmem * pagesize / 1024,
733 avail: 0,
734 free: pages.freemem * pagesize / 1024,
735 cached: 0,
736 buffers: 0,
737 swap_total: 0,
738 swap_free: 0,
739 });
740 }
741 #[cfg(any(target_vendor = "apple", target_os = "windows"))]
742 {
743 Ok(unsafe { get_mem_info() })
744 }
745 #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
746 {
747 let mut mi:MemInfo = MemInfo{total: 0, free: 0, avail: 0, buffers: 0,
748 cached: 0, swap_total: 0, swap_free: 0};
749 let res: i32 = unsafe { get_mem_info_bsd(&mut mi) };
750 match res {
751 -1 => Err(Error::IO(io::Error::last_os_error())),
752 0 => Ok(mi),
753 _ => Err(Error::Unknown),
754 }
755 }
756 #[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")))]
757 {
758 Err(Error::UnsupportedSystem)
759 }
760}
761
762pub fn disk_info() -> Result<DiskInfo, Error> {
766 #[cfg(any(target_os = "linux", target_vendor = "apple", target_os = "windows"))]
767 {
768 Ok(unsafe { get_disk_info() })
769 }
770 #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
771 {
772 let mut di:DiskInfo = DiskInfo{total: 0, free: 0};
773 let res: i32 = unsafe { get_disk_info_bsd(&mut di) };
774 match res {
775 -1 => Err(Error::IO(io::Error::last_os_error())),
776 0 => Ok(di),
777 _ => Err(Error::Unknown),
778 }
779 }
780 #[cfg(not(any(target_os = "linux", target_vendor = "apple", target_os = "windows", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))]
781 {
782 Err(Error::UnsupportedSystem)
783 }
784}
785
786#[cfg(target_family = "unix")]
788pub fn hostname() -> Result<String, Error> {
789 unsafe {
790 let buf_size = libc::sysconf(libc::_SC_HOST_NAME_MAX) as usize;
791 let mut buf = Vec::<u8>::with_capacity(buf_size + 1);
792 if libc::gethostname(buf.as_mut_ptr() as *mut libc::c_char, buf_size) < 0 {
793 return Err(Error::IO(io::Error::last_os_error()));
794 }
795 let hostname_len = libc::strnlen(buf.as_ptr() as *const libc::c_char, buf_size);
796 buf.set_len(hostname_len);
797 Ok(ffi::CString::new(buf).unwrap().into_string().unwrap())
798 }
799}
800
801#[cfg(target_family = "windows")]
802pub fn hostname() -> Result<String, Error> {
803 use std::process::Command;
804 Command::new("hostname")
805 .output()
806 .map_err(Error::ExecFailed)
807 .map(|output| String::from_utf8(output.stdout).unwrap().trim().to_string())
808}
809
810#[cfg(not(windows))]
812pub fn boottime() -> Result<timeval, Error> {
813 let mut bt = timeval {
814 tv_sec: 0,
815 tv_usec: 0
816 };
817
818 #[cfg(any(target_os = "linux", target_os="android"))]
819 {
820 let mut s = String::new();
821 File::open("/proc/uptime")?.read_to_string(&mut s)?;
822 let secs = s.trim().split(' ')
823 .take(2)
824 .map(|val| val.parse::<f64>().unwrap())
825 .collect::<Vec<f64>>();
826 bt.tv_sec = secs[0] as libc::time_t;
827 bt.tv_usec = secs[1] as libc::suseconds_t;
828 return Ok(bt);
829 }
830 #[cfg(any(target_vendor = "apple", target_os="freebsd", target_os = "openbsd", target_os = "netbsd"))]
831 {
832 let mut mib = [OS_CTL_KERN, OS_KERN_BOOTTIME];
833 let mut size: libc::size_t = size_of_val(&bt) as libc::size_t;
834 unsafe {
835 if sysctl(&mut mib[0], 2,
836 &mut bt as *mut timeval as *mut libc::c_void,
837 &mut size, null_mut(), 0) == -1 {
838 return Err(Error::IO(io::Error::last_os_error()));
839 } else {
840 return Ok(bt);
841 }
842 }
843 }
844 #[cfg(any(target_os = "solaris", target_os = "illumos"))]
845 {
846 let start = kstat::boot_time()?;
847 let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
848 let now = now.as_secs();
849 if now < start {
850 return Err(Error::General("time went backwards".into()));
851 }
852 bt.tv_sec = (now - start) as i64;
853 return Ok(bt);
854 }
855
856 #[warn(unreachable_code)]
857 Err(Error::UnsupportedSystem)
858}
859
860#[cfg(test)]
861mod test {
862 use super::*;
863
864 #[test]
865 pub fn test_os_type() {
866 let typ = os_type().unwrap();
867 assert!(typ.len() > 0);
868 println!("os_type(): {}", typ);
869 }
870
871 #[test]
872 pub fn test_os_release() {
873 let release = os_release().unwrap();
874 assert!(release.len() > 0);
875 println!("os_release(): {}", release);
876 }
877
878 #[test]
879 pub fn test_cpu_num() {
880 let num = cpu_num().unwrap();
881 assert!(num > 0);
882 println!("cpu_num(): {}", num);
883 }
884
885 #[test]
886 #[cfg(not(all(target_vendor = "apple", target_arch = "aarch64")))]
887 pub fn test_cpu_speed() {
888 let speed = cpu_speed().unwrap();
889 assert!(speed > 0);
890 println!("cpu_speed(): {}", speed);
891 }
892
893 #[test]
894 pub fn test_loadavg() {
895 let load = loadavg().unwrap();
896 println!("loadavg(): {:?}", load);
897 }
898
899 #[test]
900 pub fn test_proc_total() {
901 let procs = proc_total().unwrap();
902 assert!(procs > 0);
903 println!("proc_total(): {}", procs);
904 }
905
906 #[test]
907 pub fn test_mem_info() {
908 let mem = mem_info().unwrap();
909 assert!(mem.total > 0);
910 println!("mem_info(): {:?}", mem);
911 }
912
913 #[test]
914 #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
915 pub fn test_disk_info() {
916 let info = disk_info().unwrap();
917 println!("disk_info(): {:?}", info);
918 }
919
920 #[test]
921 pub fn test_hostname() {
922 let host = hostname().unwrap();
923 assert!(host.len() > 0);
924 println!("hostname(): {}", host);
925 }
926
927 #[test]
928 #[cfg(not(windows))]
929 pub fn test_boottime() {
930 let bt = boottime().unwrap();
931 println!("boottime(): {} {}", bt.tv_sec, bt.tv_usec);
932 assert!(bt.tv_sec > 0 || bt.tv_usec > 0);
933 }
934
935 #[test]
936 #[cfg(target_os = "linux")]
937 pub fn test_linux_os_release() {
938 let os_release = linux_os_release().unwrap();
939 println!("linux_os_release(): {:?}", os_release.name)
940 }
941}