1#![doc = include_str!("../README.md")]
4#![cfg_attr(feature = "serde", doc = include_str!("../md_doc/serde.md"))]
5#![allow(unknown_lints)]
6#![deny(missing_docs)]
7#![deny(rustdoc::broken_intra_doc_links)]
8#![allow(clippy::upper_case_acronyms)]
9#![allow(clippy::non_send_fields_in_send_ty)]
10#![allow(renamed_and_removed_lints)]
11#![allow(clippy::assertions_on_constants)]
12
13#[macro_use]
14mod macros;
15
16cfg_if::cfg_if! {
17 if #[cfg(feature = "unknown-ci")] {
18 mod unknown;
20 use crate::unknown as sys;
21
22 #[cfg(test)]
23 pub(crate) const MIN_USERS: usize = 0;
24 } else if #[cfg(any(
25 target_os = "macos", target_os = "ios",
26 target_os = "linux", target_os = "android",
27 target_os = "freebsd"))]
28 {
29 mod unix;
30 mod network;
31 use crate::unix::sys as sys;
32 use crate::unix::network_helper;
33
34 #[cfg(test)]
35 pub(crate) const MIN_USERS: usize = 1;
36 } else if #[cfg(windows)] {
37 mod windows;
38 use crate::windows as sys;
39 use crate::windows::network_helper;
40 mod network;
41
42 #[cfg(test)]
43 pub(crate) const MIN_USERS: usize = 1;
44 } else {
45 mod unknown;
46 use crate::unknown as sys;
47
48 #[cfg(test)]
49 pub(crate) const MIN_USERS: usize = 0;
50 }
51}
52
53pub use crate::common::{
54 get_current_pid, CGroupLimits, Component, Components, Cpu, CpuRefreshKind, Disk, DiskKind,
55 DiskUsage, Disks, Gid, Group, Groups, LoadAvg, MacAddr, MemoryRefreshKind, NetworkData,
56 Networks, Pid, Process, ProcessRefreshKind, ProcessStatus, RefreshKind, Signal, System,
57 ThreadKind, Uid, UpdateKind, User, Users,
58};
59
60pub(crate) use crate::common::GroupInner;
61pub(crate) use crate::sys::{
62 ComponentInner, ComponentsInner, CpuInner, DiskInner, DisksInner, NetworkDataInner,
63 NetworksInner, ProcessInner, SystemInner, UserInner,
64};
65pub use crate::sys::{IS_SUPPORTED_SYSTEM, MINIMUM_CPU_UPDATE_INTERVAL, SUPPORTED_SIGNALS};
66
67#[cfg(feature = "c-interface")]
68pub use crate::c_interface::*;
69
70#[cfg(feature = "c-interface")]
71mod c_interface;
72mod common;
73mod debug;
74#[cfg(feature = "serde")]
75mod serde;
76pub(crate) mod utils;
77
78pub fn set_open_files_limit(mut _new_limit: isize) -> bool {
102 cfg_if::cfg_if! {
103 if #[cfg(all(not(feature = "unknown-ci"), any(target_os = "linux", target_os = "android")))]
104 {
105 use crate::sys::system::REMAINING_FILES;
106 use std::sync::atomic::Ordering;
107
108 if _new_limit < 0 {
109 _new_limit = 0;
110 }
111 let max = sys::system::get_max_nb_fds();
112 if _new_limit > max {
113 _new_limit = max;
114 }
115
116 REMAINING_FILES.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |remaining| {
120 let diff = max.saturating_sub(remaining);
121 Some(_new_limit.saturating_sub(diff))
122 }).unwrap();
123
124 true
125
126 } else {
127 false
128 }
129 }
130}
131
132#[cfg(doctest)]
134mod doctest {
135 mod process_clone {}
156
157 mod system_clone {}
176}
177
178#[cfg(test)]
179mod test {
180 use crate::*;
181
182 #[cfg(feature = "unknown-ci")]
183 #[test]
184 fn check_unknown_ci_feature() {
185 assert!(!IS_SUPPORTED_SYSTEM);
186 }
187
188 #[test]
190 fn check_macro_types() {
191 fn check_is_supported(_: bool) {}
192 fn check_supported_signals(_: &'static [Signal]) {}
193 fn check_minimum_cpu_update_interval(_: std::time::Duration) {}
194
195 check_is_supported(IS_SUPPORTED_SYSTEM);
196 check_supported_signals(SUPPORTED_SIGNALS);
197 check_minimum_cpu_update_interval(MINIMUM_CPU_UPDATE_INTERVAL);
198 }
199
200 #[test]
201 fn check_process_memory_usage() {
202 let mut s = System::new();
203 s.refresh_specifics(RefreshKind::everything());
204
205 if IS_SUPPORTED_SYSTEM {
206 #[cfg(not(feature = "apple-sandbox"))]
208 assert!(!s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
209 } else {
210 assert!(s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
212 }
213 }
214
215 #[test]
216 fn check_system_implemented_traits() {
217 fn check<T: Sized + std::fmt::Debug + Default + Send + Sync>(_: T) {}
218
219 check(System::new());
220 }
221
222 #[test]
223 fn check_memory_usage() {
224 let mut s = System::new();
225
226 assert_eq!(s.total_memory(), 0);
227 assert_eq!(s.free_memory(), 0);
228 assert_eq!(s.available_memory(), 0);
229 assert_eq!(s.used_memory(), 0);
230 assert_eq!(s.total_swap(), 0);
231 assert_eq!(s.free_swap(), 0);
232 assert_eq!(s.used_swap(), 0);
233
234 s.refresh_memory();
235 if IS_SUPPORTED_SYSTEM {
236 assert!(s.total_memory() > 0);
237 assert!(s.used_memory() > 0);
238 if s.total_swap() > 0 {
239 assert!(s.free_swap() > 0);
241 }
242 } else {
243 assert_eq!(s.total_memory(), 0);
244 assert_eq!(s.used_memory(), 0);
245 assert_eq!(s.total_swap(), 0);
246 assert_eq!(s.free_swap(), 0);
247 }
248 }
249
250 #[cfg(target_os = "linux")]
251 #[test]
252 fn check_processes_cpu_usage() {
253 if !IS_SUPPORTED_SYSTEM {
254 return;
255 }
256 let mut s = System::new();
257
258 s.refresh_processes();
259 assert!(s
261 .processes()
262 .iter()
263 .all(|(_, proc_)| proc_.cpu_usage() == 0.0));
264
265 std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL);
267 s.refresh_processes();
268 assert!(s
269 .processes()
270 .iter()
271 .all(|(_, proc_)| proc_.cpu_usage() >= 0.0
272 && proc_.cpu_usage() <= (s.cpus().len() as f32) * 100.0));
273 assert!(s
274 .processes()
275 .iter()
276 .any(|(_, proc_)| proc_.cpu_usage() > 0.0));
277 }
278
279 #[test]
280 fn check_cpu_usage() {
281 if !IS_SUPPORTED_SYSTEM {
282 return;
283 }
284 let mut s = System::new();
285 for _ in 0..10 {
286 s.refresh_cpu_usage();
287 std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL);
289 if s.cpus().iter().any(|c| c.cpu_usage() > 0.0) {
290 return;
292 }
293 }
294 panic!("CPU usage is always zero...");
295 }
296
297 #[test]
298 fn check_list() {
299 let mut users = Users::new();
300 assert!(users.list().is_empty());
301 users.refresh_list();
302 assert!(users.list().len() >= MIN_USERS);
303 }
304
305 #[test]
306 fn check_uid_gid() {
307 let mut users = Users::new();
308 assert!(users.list().is_empty());
309 users.refresh_list();
310 let user_list = users.list();
311 assert!(user_list.len() >= MIN_USERS);
312
313 if IS_SUPPORTED_SYSTEM {
314 #[cfg(not(target_os = "windows"))]
315 {
316 let user = user_list
317 .iter()
318 .find(|u| u.name() == "root")
319 .expect("no root user");
320 assert_eq!(**user.id(), 0);
321 assert_eq!(*user.group_id(), 0);
322 if let Some(user) = users.iter().find(|u| *u.group_id() > 0) {
323 assert!(**user.id() > 0);
324 assert!(*user.group_id() > 0);
325 }
326 assert!(user_list.iter().filter(|u| **u.id() > 0).count() > 0);
327 }
328
329 let s = System::new_with_specifics(
331 RefreshKind::new()
332 .with_processes(ProcessRefreshKind::new().with_user(UpdateKind::Always)),
333 );
334 assert!(s
335 .processes()
336 .iter()
337 .filter_map(|(_, p)| p.user_id())
338 .any(|uid| users.get_user_by_id(uid).is_some()));
339 }
340 }
341
342 #[test]
343 fn check_all_process_uids_resolvable() {
344 if IS_SUPPORTED_SYSTEM && cfg!(not(target_os = "linux")) {
347 let s = System::new_with_specifics(
348 RefreshKind::new()
349 .with_processes(ProcessRefreshKind::new().with_user(UpdateKind::Always)),
350 );
351 let users = Users::new_with_refreshed_list();
352
353 for process in s.processes().values() {
356 if let Some(uid) = process.user_id() {
357 assert!(
358 users.get_user_by_id(uid).is_some(),
359 "No UID {:?} found",
360 uid
361 );
362 }
363 }
364 }
365 }
366
367 #[test]
368 fn check_system_info() {
369 if IS_SUPPORTED_SYSTEM {
371 assert!(!System::name()
372 .expect("Failed to get system name")
373 .is_empty());
374
375 assert!(!System::kernel_version()
376 .expect("Failed to get kernel version")
377 .is_empty());
378
379 assert!(!System::os_version()
380 .expect("Failed to get os version")
381 .is_empty());
382
383 assert!(!System::long_os_version()
384 .expect("Failed to get long OS version")
385 .is_empty());
386 }
387
388 assert!(!System::distribution_id().is_empty());
389 }
390
391 #[test]
392 fn check_host_name() {
393 if IS_SUPPORTED_SYSTEM {
395 assert!(System::host_name().is_some());
396 }
397 }
398
399 #[test]
400 fn check_refresh_process_return_value() {
401 if IS_SUPPORTED_SYSTEM {
403 let _pid = get_current_pid().expect("Failed to get current PID");
404
405 #[cfg(not(feature = "apple-sandbox"))]
406 {
407 let mut s = System::new();
408 assert!(s.refresh_process(_pid));
410 assert!(s.refresh_process(_pid));
412 }
413 }
414 }
415
416 #[test]
417 fn ensure_is_supported_is_set_correctly() {
418 if MIN_USERS > 0 {
419 assert!(IS_SUPPORTED_SYSTEM);
420 } else {
421 assert!(!IS_SUPPORTED_SYSTEM);
422 }
423 }
424
425 #[test]
426 fn check_cpus_number() {
427 let mut s = System::new();
428
429 assert!(s.cpus().is_empty());
431 if IS_SUPPORTED_SYSTEM {
432 let physical_cores_count = s
435 .physical_core_count()
436 .expect("failed to get number of physical cores");
437
438 s.refresh_cpu_usage();
439 assert!(!s.cpus().is_empty());
441
442 let physical_cores_count2 = s
445 .physical_core_count()
446 .expect("failed to get number of physical cores");
447 assert!(physical_cores_count2 <= s.cpus().len());
448 assert_eq!(physical_cores_count, physical_cores_count2);
449 } else {
450 assert_eq!(s.physical_core_count(), None);
451 }
452 assert!(s.physical_core_count().unwrap_or(0) <= s.cpus().len());
453 }
454
455 #[test]
456 #[allow(clippy::const_is_empty)]
457 fn check_nb_supported_signals() {
458 if IS_SUPPORTED_SYSTEM {
459 assert!(
460 !SUPPORTED_SIGNALS.is_empty(),
461 "SUPPORTED_SIGNALS shouldn't be empty on supported systems!"
462 );
463 } else {
464 assert!(
465 SUPPORTED_SIGNALS.is_empty(),
466 "SUPPORTED_SIGNALS should be empty on not support systems!"
467 );
468 }
469 }
470
471 #[test]
473 fn check_cpu_frequency() {
474 if !IS_SUPPORTED_SYSTEM {
475 return;
476 }
477 let mut s = System::new();
478 s.refresh_processes();
479 for proc_ in s.cpus() {
480 assert_eq!(proc_.frequency(), 0);
481 }
482 s.refresh_cpu_usage();
483 for proc_ in s.cpus() {
484 assert_eq!(proc_.frequency(), 0);
485 }
486 if std::env::var("APPLE_CI").is_err() && std::env::var("FREEBSD_CI").is_err() {
488 s.refresh_cpu_specifics(CpuRefreshKind::everything());
489 for proc_ in s.cpus() {
490 assert_ne!(proc_.frequency(), 0);
491 }
492 }
493 }
494
495 #[test]
498 fn check_refresh_process_update() {
499 if !IS_SUPPORTED_SYSTEM {
500 return;
501 }
502 let mut s = System::new_all();
503 let total = s.processes().len() as isize;
504 s.refresh_processes();
505 let new_total = s.processes().len() as isize;
506 assert!(
508 (new_total - total).abs() <= 5,
509 "{} <= 5",
510 (new_total - total).abs()
511 );
512 }
513
514 #[test]
515 fn check_cpu_arch() {
516 assert_eq!(System::cpu_arch().is_some(), IS_SUPPORTED_SYSTEM);
517 }
518
519 #[test]
522 fn check_display_impl_process_status() {
523 println!("{} {:?}", ProcessStatus::Parked, ProcessStatus::Idle);
524 }
525
526 #[test]
528 fn check_display_impl_mac_address() {
529 println!(
530 "{} {:?}",
531 MacAddr([0x1, 0x2, 0x3, 0x4, 0x5, 0x6]),
532 MacAddr([0xa, 0xb, 0xc, 0xd, 0xe, 0xf])
533 );
534 }
535
536 #[test]
537 fn check_mac_address_is_unspecified_true() {
538 assert!(MacAddr::UNSPECIFIED.is_unspecified());
539 assert!(MacAddr([0; 6]).is_unspecified());
540 }
541
542 #[test]
543 fn check_mac_address_is_unspecified_false() {
544 assert!(!MacAddr([1, 2, 3, 4, 5, 6]).is_unspecified());
545 }
546
547 #[allow(clippy::unnecessary_fallible_conversions)]
550 #[test]
551 fn check_uid_gid_from_impls() {
552 use std::convert::TryFrom;
553 use std::str::FromStr;
554
555 #[cfg(not(windows))]
556 {
557 assert!(crate::Uid::try_from(0usize).is_ok());
558 assert!(crate::Uid::from_str("0").is_ok());
559 }
560 #[cfg(windows)]
561 {
562 assert!(crate::Uid::from_str("S-1-5-18").is_ok()); assert!(crate::Uid::from_str("0").is_err());
564 }
565
566 assert!(crate::Gid::try_from(0usize).is_ok());
567 assert!(crate::Gid::from_str("0").is_ok());
568
569 assert!(crate::Pid::try_from(0usize).is_ok());
570 let _ = crate::Pid::from(0);
572 assert!(crate::Pid::from_str("0").is_ok());
573 }
574
575 #[test]
576 fn check_groups() {
577 if !crate::IS_SUPPORTED_SYSTEM {
578 return;
579 }
580 assert!(!Groups::new_with_refreshed_list().is_empty());
581 }
582}