system_uptime/
lib.rs

1use std::{error::Error, time::Duration};
2
3/// Returns OS uptime in milliseconds
4///
5/// # Example
6///
7/// ```
8/// use system_uptime::get_os_uptime;
9///
10/// match get_os_uptime() {
11///     Ok(uptime_ms) => println!("OS uptime {} ms", uptime_ms),
12///     Err(e) => eprintln!("Error is {}", e),
13/// }
14/// ```
15#[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
88/// Returns OS uptime in useful Duration format
89pub 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}