Skip to main content

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 = "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
97/// Returns OS uptime in useful Duration format
98pub 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}