1use std::{error::Error, time::Duration};
2
3#[cfg(any(target_os = "linux", target_os = "android"))]
16pub fn get_os_uptime() -> Result<u64, Box<dyn Error>> {
17 use std::fs;
18
19 let uptime_content = fs::read_to_string("/proc/uptime")?;
20 let parts = uptime_content.split_whitespace().collect::<Vec<_>>();
21
22 if parts.is_empty() {
23 return Err("Invalid /proc/uptime format".into());
24 }
25
26 let uptime_seconds: f64 = parts[0].parse()?;
27 Ok((uptime_seconds * 1000.0) as u64)
28}
29#[cfg(target_os = "redox")]
30pub fn get_os_uptime() -> Result<u64, Box<dyn Error>> {
31 use libredox::{call, flag};
32
33 let ts = call::clock_gettime(flag::CLOCK_MONOTONIC)?;
34 let millisecs = (ts.tv_sec * 1_000 + ts.tv_nsec / 1_000_000) as u64;
35 Ok(millisecs)
36}
37#[cfg(target_os = "windows")]
38pub fn get_os_uptime() -> Result<u64, Box<dyn Error>> {
39 use winapi::um::errhandlingapi::GetLastError;
40 use winapi::um::sysinfoapi::GetTickCount64;
41
42 unsafe {
43 let uptime_ms = GetTickCount64();
44 if uptime_ms == 0 {
45 let error_code = GetLastError();
46 if error_code != 0 {
47 return Err(format!("Windows API error: {}", error_code).into());
48 }
49 }
50 Ok(uptime_ms)
51 }
52}
53#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
54pub fn get_os_uptime() -> Result<u64, Box<dyn Error>> {
55 use libc::{sysctl, timeval};
56 use std::io;
57 use std::mem;
58
59 let mut mib = [libc::CTL_KERN, libc::KERN_BOOTTIME];
60 let mut boot_time = timeval {
61 tv_sec: 0,
62 tv_usec: 0,
63 };
64 let mut size = mem::size_of_val(&boot_time);
65
66 unsafe {
67 if sysctl(
68 mib.as_mut_ptr(),
69 2,
70 &mut boot_time as *mut _ as *mut _,
71 &mut size,
72 std::ptr::null_mut(),
73 0,
74 ) != 0
75 {
76 return Err(io::Error::last_os_error().into());
77 }
78
79 let now = libc::time(std::ptr::null_mut());
80 let uptime_seconds = now - boot_time.tv_sec;
81 Ok(uptime_seconds as u64 * 1000)
82 }
83}
84#[cfg(not(any(
85 target_os = "windows",
86 target_os = "linux",
87 target_os = "android",
88 target_os = "macos",
89 target_os = "ios",
90 target_os = "freebsd",
91 target_os = "redox"
92)))]
93pub fn get_os_uptime() -> Result<u64, Box<dyn Error>> {
94 Err("Unsupported operating system".into())
95}
96
97pub fn get_os_uptime_duration() -> Result<Duration, Box<dyn Error>> {
99 let ms = get_os_uptime()?;
100 Ok(Duration::from_millis(ms))
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn it_os_uptime() {
109 let uptime = get_os_uptime();
110 assert!(
111 uptime.is_ok(),
112 "Failed to get os uptime: {:?}",
113 uptime.err()
114 );
115
116 let uptime_ms = uptime.unwrap();
117 assert!(uptime_ms > 0, "Uptime should be greater than 0");
118
119 let duration = get_os_uptime_duration().unwrap();
120 assert_eq!(duration.as_millis() as u64, uptime_ms);
121 }
122}