diff --git a/src/uptime.rs b/src/uptime.rs index 095af7d..c6c4b26 100644 --- a/src/uptime.rs +++ b/src/uptime.rs @@ -17,14 +17,41 @@ fn itoa(mut n: u64, buf: &mut [u8]) -> &str { unsafe { std::str::from_utf8_unchecked(&buf[i..]) } } -/// Direct `sysinfo` syscall using inline assembly +/// Raw buffer for the `sysinfo(2)` syscall. +/// +/// In the Linux ABI `uptime` is a `long` at offset 0. The remaining fields are +/// not needed, but are declared to give the struct its correct size (112 bytes +/// on 64-bit Linux). +/// +/// The layout matches the kernel's `struct sysinfo` *exactly*: +/// `mem_unit` ends at offset 108, then 4 bytes of implicit padding to 112. +#[repr(C)] +struct SysInfo { + uptime: i64, + loads: [u64; 3], + totalram: u64, + freeram: u64, + sharedram: u64, + bufferram: u64, + totalswap: u64, + freeswap: u64, + procs: u16, + _pad: u16, + _pad2: u32, // alignment padding to reach 8-byte boundary for totalhigh + totalhigh: u64, + freehigh: u64, + mem_unit: u32, + // 4 bytes implicit trailing padding to reach 112 bytes total; no field + // needed +} + +/// Direct `sysinfo(2)` syscall using inline assembly /// /// # Safety /// -/// This function uses inline assembly to make a direct syscall. /// The caller must ensure the sysinfo pointer is valid. #[inline] -unsafe fn sys_sysinfo(info: *mut libc::sysinfo) -> i64 { +unsafe fn sys_sysinfo(info: *mut SysInfo) -> i64 { #[cfg(target_arch = "x86_64")] { let ret: i64; @@ -59,7 +86,7 @@ unsafe fn sys_sysinfo(info: *mut libc::sysinfo) -> i64 { #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))] { - unsafe { libc::sysinfo(info) as i64 } + compile_error!("Unsupported architecture for inline assembly syscalls"); } }