1#[cfg(target_family = "windows")]
3use std::sync::Once;
4
5type LoadAvg = (f64, f64, f64);
6const DEFAULT_LOADAVG: LoadAvg = (0.0, 0.0, 0.0);
7
8pub fn loadavg() -> LoadAvg {
9 #[cfg(any(target_os = "android", target_os = "linux"))]
10 {
11 use libc::SI_LOAD_SHIFT;
12
13 let mut info = std::mem::MaybeUninit::uninit();
14 let res = unsafe { libc::sysinfo(info.as_mut_ptr()) };
16 if res == 0 {
17 let info = unsafe { info.assume_init() };
19 (
20 info.loads[0] as f64 / (1 << SI_LOAD_SHIFT) as f64,
21 info.loads[1] as f64 / (1 << SI_LOAD_SHIFT) as f64,
22 info.loads[2] as f64 / (1 << SI_LOAD_SHIFT) as f64,
23 )
24 } else {
25 DEFAULT_LOADAVG
26 }
27 }
28 #[cfg(any(
29 target_vendor = "apple",
30 target_os = "freebsd",
31 target_os = "openbsd"
32 ))]
33 {
34 let mut l: [f64; 3] = [0.; 3];
35 if unsafe { libc::getloadavg(&mut l as *mut f64, l.len() as _) } < 3 {
37 DEFAULT_LOADAVG
38 } else {
39 (l[0], l[1], l[2])
40 }
41 }
42 #[cfg(target_os = "windows")]
43 {
44 DEFAULT_LOADAVG
45 }
46}
47
48pub fn os_release() -> String {
49 #[cfg(target_os = "linux")]
50 {
51 #[allow(clippy::disallowed_methods)]
52 match std::fs::read_to_string("/proc/sys/kernel/osrelease") {
53 Ok(mut s) => {
54 s.pop(); s
56 }
57 _ => String::from(""),
58 }
59 }
60 #[cfg(target_os = "android")]
61 {
62 let mut info = std::mem::MaybeUninit::uninit();
63 let res = unsafe { libc::uname(info.as_mut_ptr()) };
65 if res != 0 {
66 return String::from("");
67 }
68 let mut info = unsafe { info.assume_init() };
70 let len = info.release.len();
71 info.release[len - 1] = 0;
72 let c_str = unsafe { std::ffi::CStr::from_ptr(info.release.as_ptr()) };
74 c_str.to_string_lossy().into_owned()
75 }
76 #[cfg(any(
77 target_vendor = "apple",
78 target_os = "freebsd",
79 target_os = "openbsd"
80 ))]
81 {
82 let mut s = [0u8; 256];
83 let mut mib = [libc::CTL_KERN, libc::KERN_OSRELEASE];
84 let mut len = s.len();
86 if unsafe {
90 libc::sysctl(
91 mib.as_mut_ptr(),
92 mib.len() as _,
93 s.as_mut_ptr() as _,
94 &mut len,
95 std::ptr::null_mut(),
96 0,
97 )
98 } == -1
99 {
100 return String::from("Unknown");
101 }
102
103 return String::from_utf8_lossy(&s[..len - 1]).to_string();
105 }
106 #[cfg(target_family = "windows")]
107 {
108 use ntapi::ntrtl::RtlGetVersion;
109 use winapi::shared::ntdef::NT_SUCCESS;
110 use winapi::um::winnt::RTL_OSVERSIONINFOEXW;
111
112 let mut version_info =
113 std::mem::MaybeUninit::<RTL_OSVERSIONINFOEXW>::uninit();
114 unsafe {
116 (*version_info.as_mut_ptr()).dwOSVersionInfoSize =
117 std::mem::size_of::<RTL_OSVERSIONINFOEXW>() as u32;
118 }
119 if !NT_SUCCESS(unsafe {
122 RtlGetVersion(version_info.as_mut_ptr() as *mut _)
123 }) {
124 String::from("")
125 } else {
126 let version_info = unsafe { version_info.assume_init() };
128 format!(
129 "{}.{}.{}",
130 version_info.dwMajorVersion,
131 version_info.dwMinorVersion,
132 version_info.dwBuildNumber
133 )
134 }
135 }
136}
137
138#[cfg(target_family = "windows")]
139static WINSOCKET_INIT: Once = Once::new();
140
141pub fn hostname() -> String {
142 #[cfg(target_family = "unix")]
143 unsafe {
145 let buf_size = libc::sysconf(libc::_SC_HOST_NAME_MAX) as usize;
146 let mut buf = vec![0u8; buf_size + 1];
147 let len = buf.len();
148 if libc::gethostname(buf.as_mut_ptr() as *mut libc::c_char, len) < 0 {
149 return String::from("");
150 }
151 buf[len - 1] = 0;
153 std::ffi::CStr::from_ptr(buf.as_ptr() as *const libc::c_char)
154 .to_string_lossy()
155 .to_string()
156 }
157 #[cfg(target_family = "windows")]
158 {
159 use std::ffi::OsString;
160 use std::mem;
161 use std::os::windows::ffi::OsStringExt;
162 use winapi::shared::minwindef::MAKEWORD;
163 use winapi::um::winsock2::GetHostNameW;
164 use winapi::um::winsock2::WSAStartup;
165
166 let namelen = 256;
167 let mut name: Vec<u16> = vec![0u16; namelen];
168 WINSOCKET_INIT.call_once(|| unsafe {
172 let mut data = mem::zeroed();
173 let wsa_startup_result = WSAStartup(MAKEWORD(2, 2), &mut data);
174 if wsa_startup_result != 0 {
175 panic!("Failed to start winsocket");
176 }
177 });
178 let err =
179 unsafe { GetHostNameW(name.as_mut_ptr(), namelen as libc::c_int) };
182
183 if err == 0 {
184 let len = name.iter().take_while(|&&c| c != 0).count();
186 OsString::from_wide(&name[..len])
187 .to_string_lossy()
188 .into_owned()
189 } else {
190 String::from("")
191 }
192 }
193}
194
195#[derive(serde::Serialize)]
196#[serde(rename_all = "camelCase")]
197pub struct MemInfo {
198 pub total: u64,
199 pub free: u64,
200 pub available: u64,
201 pub buffers: u64,
202 pub cached: u64,
203 pub swap_total: u64,
204 pub swap_free: u64,
205}
206
207pub fn mem_info() -> Option<MemInfo> {
208 let mut mem_info = MemInfo {
209 total: 0,
210 free: 0,
211 available: 0,
212 buffers: 0,
213 cached: 0,
214 swap_total: 0,
215 swap_free: 0,
216 };
217 #[cfg(any(target_os = "android", target_os = "linux"))]
218 {
219 let mut info = std::mem::MaybeUninit::uninit();
220 let res = unsafe { libc::sysinfo(info.as_mut_ptr()) };
222 if res == 0 {
223 let info = unsafe { info.assume_init() };
225 let mem_unit = info.mem_unit as u64;
226 mem_info.swap_total = info.totalswap * mem_unit;
227 mem_info.swap_free = info.freeswap * mem_unit;
228 mem_info.total = info.totalram * mem_unit;
229 mem_info.free = info.freeram * mem_unit;
230 mem_info.available = mem_info.free;
231 mem_info.buffers = info.bufferram * mem_unit;
232 }
233
234 #[allow(clippy::disallowed_methods)]
236 if let Ok(meminfo) = std::fs::read_to_string("/proc/meminfo") {
237 let line = meminfo.lines().find(|l| l.starts_with("MemAvailable:"));
238 if let Some(line) = line {
239 let mem = line.split_whitespace().nth(1);
240 let mem = mem.and_then(|v| v.parse::<u64>().ok());
241 mem_info.available = mem.unwrap_or(0) * 1024;
242 }
243 }
244 }
245 #[cfg(target_vendor = "apple")]
246 {
247 let mut mib: [i32; 2] = [0, 0];
248 mib[0] = libc::CTL_HW;
249 mib[1] = libc::HW_MEMSIZE;
250 unsafe {
254 let mut size = std::mem::size_of::<u64>();
255 libc::sysctl(
256 mib.as_mut_ptr(),
257 mib.len() as _,
258 &mut mem_info.total as *mut _ as *mut libc::c_void,
259 &mut size,
260 std::ptr::null_mut(),
261 0,
262 );
263
264 let mut xs: libc::xsw_usage = std::mem::zeroed::<libc::xsw_usage>();
265 mib[0] = libc::CTL_VM;
266 mib[1] = libc::VM_SWAPUSAGE;
267
268 let mut size = std::mem::size_of::<libc::xsw_usage>();
269 libc::sysctl(
270 mib.as_mut_ptr(),
271 mib.len() as _,
272 &mut xs as *mut _ as *mut libc::c_void,
273 &mut size,
274 std::ptr::null_mut(),
275 0,
276 );
277
278 mem_info.swap_total = xs.xsu_total;
279 mem_info.swap_free = xs.xsu_avail;
280
281 let mut count: u32 = libc::HOST_VM_INFO64_COUNT as _;
282 let mut stat = std::mem::zeroed::<libc::vm_statistics64>();
283 if libc::host_statistics64(
284 libc::mach_host_self(),
286 libc::HOST_VM_INFO64,
287 &mut stat as *mut libc::vm_statistics64 as *mut _,
288 &mut count,
289 ) == libc::KERN_SUCCESS
290 {
291 let page_size = libc::sysconf(libc::_SC_PAGESIZE) as u64;
293 mem_info.available =
294 (stat.free_count as u64 + stat.inactive_count as u64) * page_size
295 / 1024;
296 mem_info.free =
297 (stat.free_count as u64 - stat.speculative_count as u64) * page_size
298 / 1024;
299 }
300 }
301 }
302 #[cfg(target_family = "windows")]
303 unsafe {
307 use std::mem;
308 use winapi::shared::minwindef;
309 use winapi::um::psapi::GetPerformanceInfo;
310 use winapi::um::psapi::PERFORMANCE_INFORMATION;
311 use winapi::um::sysinfoapi;
312
313 let mut mem_status =
314 mem::MaybeUninit::<sysinfoapi::MEMORYSTATUSEX>::uninit();
315 let length =
316 mem::size_of::<sysinfoapi::MEMORYSTATUSEX>() as minwindef::DWORD;
317 (*mem_status.as_mut_ptr()).dwLength = length;
318
319 let result = sysinfoapi::GlobalMemoryStatusEx(mem_status.as_mut_ptr());
320 if result != 0 {
321 let stat = mem_status.assume_init();
322 mem_info.total = stat.ullTotalPhys;
323 mem_info.available = 0;
324 mem_info.free = stat.ullAvailPhys;
325 mem_info.cached = 0;
326 mem_info.buffers = 0;
327
328 let mut perf_info = mem::MaybeUninit::<PERFORMANCE_INFORMATION>::uninit();
334 let result = GetPerformanceInfo(
335 perf_info.as_mut_ptr(),
336 mem::size_of::<PERFORMANCE_INFORMATION>() as minwindef::DWORD,
337 );
338 if result == minwindef::TRUE {
339 let perf_info = perf_info.assume_init();
340 let swap_total = perf_info.PageSize
341 * perf_info
342 .CommitLimit
343 .saturating_sub(perf_info.PhysicalTotal);
344 let swap_free = perf_info.PageSize
345 * perf_info
346 .CommitLimit
347 .saturating_sub(perf_info.PhysicalTotal)
348 .saturating_sub(perf_info.PhysicalAvailable);
349 mem_info.swap_total = (swap_total / 1000) as u64;
350 mem_info.swap_free = (swap_free / 1000) as u64;
351 }
352 }
353 }
354
355 Some(mem_info)
356}
357
358pub fn os_uptime() -> u64 {
359 let uptime: u64;
360
361 #[cfg(any(target_os = "android", target_os = "linux"))]
362 {
363 let mut info = std::mem::MaybeUninit::uninit();
364 let res = unsafe { libc::sysinfo(info.as_mut_ptr()) };
366 uptime = if res == 0 {
367 let info = unsafe { info.assume_init() };
369 info.uptime as u64
370 } else {
371 0
372 }
373 }
374
375 #[cfg(any(
376 target_vendor = "apple",
377 target_os = "freebsd",
378 target_os = "openbsd"
379 ))]
380 {
381 use std::mem;
382 use std::time::Duration;
383 use std::time::SystemTime;
384 let mut request = [libc::CTL_KERN, libc::KERN_BOOTTIME];
385 let mut boottime: libc::timeval = unsafe { mem::zeroed() };
388 let mut size: libc::size_t = mem::size_of_val(&boottime) as libc::size_t;
389 let res = unsafe {
391 libc::sysctl(
392 &mut request[0],
393 2,
394 &mut boottime as *mut libc::timeval as *mut libc::c_void,
395 &mut size,
396 std::ptr::null_mut(),
397 0,
398 )
399 };
400 uptime = if res == 0 {
401 SystemTime::now()
402 .duration_since(SystemTime::UNIX_EPOCH)
403 .map(|d| {
404 (d - Duration::new(
405 boottime.tv_sec as u64,
406 boottime.tv_usec as u32 * 1000,
407 ))
408 .as_secs()
409 })
410 .unwrap_or_default()
411 } else {
412 0
413 }
414 }
415
416 #[cfg(target_family = "windows")]
417 unsafe {
419 uptime = winapi::um::sysinfoapi::GetTickCount64() / 1000;
422 }
423
424 uptime
425}