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 = "windows")]
30pub fn get_os_uptime() -> Result<u64, Box<dyn Error>> {
31 use winapi::um::errhandlingapi::GetLastError;
32 use winapi::um::sysinfoapi::GetTickCount64;
33
34 unsafe {
35 let uptime_ms = GetTickCount64();
36 if uptime_ms == 0 {
37 let error_code = GetLastError();
38 if error_code != 0 {
39 return Err(format!("Windows API error: {}", error_code).into());
40 }
41 }
42 Ok(uptime_ms)
43 }
44}
45#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
46pub fn get_os_uptime() -> Result<u64, Box<dyn Error>> {
47 use libc::{sysctl, timeval};
48 use std::io;
49 use std::mem;
50
51 let mut mib = [libc::CTL_KERN, libc::KERN_BOOTTIME];
52 let mut boot_time = timeval {
53 tv_sec: 0,
54 tv_usec: 0,
55 };
56 let mut size = mem::size_of_val(&boot_time);
57
58 unsafe {
59 if sysctl(
60 mib.as_mut_ptr(),
61 2,
62 &mut boot_time as *mut _ as *mut _,
63 &mut size,
64 std::ptr::null_mut(),
65 0,
66 ) != 0
67 {
68 return Err(io::Error::last_os_error().into());
69 }
70
71 let now = libc::time(std::ptr::null_mut());
72 let uptime_seconds = now - boot_time.tv_sec;
73 Ok(uptime_seconds as u64 * 1000)
74 }
75}
76#[cfg(not(any(
77 target_os = "windows",
78 target_os = "linux",
79 target_os = "android",
80 target_os = "macos",
81 target_os = "ios",
82 target_os = "freebsd"
83)))]
84pub fn get_os_uptime() -> Result<u64, Box<dyn Error>> {
85 Err("Unsupported operating system".into())
86}
87
88pub fn get_os_uptime_duration() -> Result<Duration, Box<dyn Error>> {
90 let ms = get_os_uptime()?;
91 Ok(Duration::from_millis(ms))
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn it_os_uptime() {
100 let uptime = get_os_uptime();
101 assert!(
102 uptime.is_ok(),
103 "Failed to get os uptime: {:?}",
104 uptime.err()
105 );
106
107 let uptime_ms = uptime.unwrap();
108 assert!(uptime_ms > 0, "Uptime should be greater than 0");
109
110 let duration = get_os_uptime_duration().unwrap();
111 assert_eq!(duration.as_millis() as u64, uptime_ms);
112 }
113}