]> git.proxmox.com Git - rustc.git/blob - vendor/sysinfo/src/lib.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / vendor / sysinfo / src / lib.rs
1 // Take a look at the license at the top of the repository in the LICENSE file.
2
3 #![doc = include_str!("../README.md")]
4 #![allow(unknown_lints)]
5 #![deny(missing_docs)]
6 #![deny(rustdoc::broken_intra_doc_links)]
7 #![allow(clippy::upper_case_acronyms)]
8 #![allow(clippy::non_send_fields_in_send_ty)]
9 #![allow(renamed_and_removed_lints)]
10 #![allow(unknown_lints)]
11
12 #[macro_use]
13 mod macros;
14
15 cfg_if::cfg_if! {
16 if #[cfg(feature = "unknown-ci")] {
17 // This is used in CI to check that the build for unknown targets is compiling fine.
18 mod unknown;
19 use unknown as sys;
20
21 #[cfg(test)]
22 pub(crate) const MIN_USERS: usize = 0;
23 } else if #[cfg(any(target_os = "macos", target_os = "ios"))] {
24 mod apple;
25 use apple as sys;
26 extern crate core_foundation_sys;
27
28 #[cfg(test)]
29 pub(crate) const MIN_USERS: usize = 1;
30 } else if #[cfg(windows)] {
31 mod windows;
32 use windows as sys;
33 extern crate winapi;
34 extern crate ntapi;
35
36 #[cfg(test)]
37 pub(crate) const MIN_USERS: usize = 1;
38 } else if #[cfg(any(target_os = "linux", target_os = "android"))] {
39 mod linux;
40 use linux as sys;
41 pub(crate) mod users;
42
43 #[cfg(test)]
44 pub(crate) const MIN_USERS: usize = 1;
45 } else if #[cfg(target_os = "freebsd")] {
46 mod freebsd;
47 use freebsd as sys;
48 pub(crate) mod users;
49
50 #[cfg(test)]
51 pub(crate) const MIN_USERS: usize = 1;
52 } else {
53 mod unknown;
54 use unknown as sys;
55
56 #[cfg(test)]
57 pub(crate) const MIN_USERS: usize = 0;
58 }
59 }
60
61 pub use common::{
62 get_current_pid, CpuRefreshKind, DiskType, DiskUsage, Gid, LoadAvg, NetworksIter, Pid, PidExt,
63 ProcessRefreshKind, ProcessStatus, RefreshKind, Signal, Uid, User,
64 };
65 pub use sys::{Component, Cpu, Disk, NetworkData, Networks, Process, System};
66 pub use traits::{
67 ComponentExt, CpuExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, SystemExt, UserExt,
68 };
69
70 #[cfg(feature = "c-interface")]
71 pub use c_interface::*;
72
73 #[cfg(feature = "c-interface")]
74 mod c_interface;
75 mod common;
76 mod debug;
77 mod system;
78 mod traits;
79 mod utils;
80
81 /// This function is only used on linux targets, on the other platforms it does nothing and returns
82 /// `false`.
83 ///
84 /// On linux, to improve performance, we keep a `/proc` file open for each process we index with
85 /// a maximum number of files open equivalent to half of the system limit.
86 ///
87 /// The problem is that some users might need all the available file descriptors so we need to
88 /// allow them to change this limit.
89 ///
90 /// Note that if you set a limit bigger than the system limit, the system limit will be set.
91 ///
92 /// Returns `true` if the new value has been set.
93 ///
94 /// ```no_run
95 /// use sysinfo::{System, SystemExt, set_open_files_limit};
96 ///
97 /// // We call the function before any call to the processes update.
98 /// if !set_open_files_limit(10) {
99 /// // It'll always return false on non-linux targets.
100 /// eprintln!("failed to update the open files limit...");
101 /// }
102 /// let s = System::new_all();
103 /// ```
104 pub fn set_open_files_limit(mut _new_limit: isize) -> bool {
105 cfg_if::cfg_if! {
106 if #[cfg(all(not(feature = "unknown-ci"), any(target_os = "linux", target_os = "android")))]
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 unsafe {
116 if let Ok(ref mut x) = sys::system::REMAINING_FILES.lock() {
117 // If files are already open, to be sure that the number won't be bigger when those
118 // files are closed, we subtract the current number of opened files to the new
119 // limit.
120 let diff = max.saturating_sub(**x);
121 **x = _new_limit.saturating_sub(diff);
122 true
123 } else {
124 false
125 }
126 }
127 } else {
128 false
129 }
130 }
131 }
132
133 // FIXME: Can be removed once negative trait bounds are supported.
134 #[cfg(doctest)]
135 mod doctest {
136 /// Check that `Process` doesn't implement `Clone`.
137 ///
138 /// First we check that the "basic" code works:
139 ///
140 /// ```no_run
141 /// use sysinfo::{Process, System, SystemExt};
142 ///
143 /// let mut s = System::new_all();
144 /// let p: &Process = s.processes().values().next().unwrap();
145 /// ```
146 ///
147 /// And now we check if it fails when we try to clone it:
148 ///
149 /// ```compile_fail
150 /// use sysinfo::{Process, System, SystemExt};
151 ///
152 /// let mut s = System::new_all();
153 /// let p: &Process = s.processes().values().next().unwrap();
154 /// let p = (*p).clone();
155 /// ```
156 mod process_clone {}
157
158 /// Check that `System` doesn't implement `Clone`.
159 ///
160 /// First we check that the "basic" code works:
161 ///
162 /// ```no_run
163 /// use sysinfo::{Process, System, SystemExt};
164 ///
165 /// let s = System::new();
166 /// ```
167 ///
168 /// And now we check if it fails when we try to clone it:
169 ///
170 /// ```compile_fail
171 /// use sysinfo::{Process, System, SystemExt};
172 ///
173 /// let s = System::new();
174 /// let s = s.clone();
175 /// ```
176 mod system_clone {}
177 }
178
179 #[cfg(test)]
180 mod test {
181 use crate::*;
182
183 #[cfg(feature = "unknown-ci")]
184 #[test]
185 fn check_unknown_ci_feature() {
186 assert!(!System::IS_SUPPORTED);
187 }
188
189 #[test]
190 fn check_process_memory_usage() {
191 let mut s = System::new();
192 s.refresh_all();
193
194 if System::IS_SUPPORTED {
195 // No process should have 0 as memory usage.
196 #[cfg(not(feature = "apple-sandbox"))]
197 assert!(!s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
198 } else {
199 // There should be no process, but if there is one, its memory usage should be 0.
200 assert!(s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
201 }
202 }
203
204 #[test]
205 fn check_memory_usage() {
206 let mut s = System::new();
207
208 assert_eq!(s.total_memory(), 0);
209 assert_eq!(s.free_memory(), 0);
210 assert_eq!(s.available_memory(), 0);
211 assert_eq!(s.used_memory(), 0);
212 assert_eq!(s.total_swap(), 0);
213 assert_eq!(s.free_swap(), 0);
214 assert_eq!(s.used_swap(), 0);
215
216 s.refresh_memory();
217 if System::IS_SUPPORTED {
218 assert!(s.total_memory() > 0);
219 assert!(s.used_memory() > 0);
220 if s.total_swap() > 0 {
221 // I think it's pretty safe to assume that there is still some swap left...
222 assert!(s.free_swap() > 0);
223 }
224 } else {
225 assert_eq!(s.total_memory(), 0);
226 assert_eq!(s.used_memory(), 0);
227 assert_eq!(s.total_swap(), 0);
228 assert_eq!(s.free_swap(), 0);
229 }
230 }
231
232 #[cfg(target_os = "linux")]
233 #[test]
234 fn check_processes_cpu_usage() {
235 if !System::IS_SUPPORTED {
236 return;
237 }
238 let mut s = System::new();
239
240 s.refresh_processes();
241 // All CPU usage will start at zero until the second refresh
242 assert!(s
243 .processes()
244 .iter()
245 .all(|(_, proc_)| proc_.cpu_usage() == 0.0));
246
247 // Wait a bit to update CPU usage values
248 std::thread::sleep(std::time::Duration::from_millis(100));
249 s.refresh_processes();
250 assert!(s
251 .processes()
252 .iter()
253 .all(|(_, proc_)| proc_.cpu_usage() >= 0.0
254 && proc_.cpu_usage() <= (s.cpus().len() as f32) * 100.0));
255 assert!(s
256 .processes()
257 .iter()
258 .any(|(_, proc_)| proc_.cpu_usage() > 0.0));
259 }
260
261 #[test]
262 fn check_cpu_usage() {
263 if !System::IS_SUPPORTED {
264 return;
265 }
266 let mut s = System::new();
267 for _ in 0..10 {
268 s.refresh_cpu();
269 // Wait a bit to update CPU usage values
270 std::thread::sleep(std::time::Duration::from_millis(100));
271 if s.cpus().iter().any(|c| c.cpu_usage() > 0.0) {
272 // All good!
273 return;
274 }
275 }
276 panic!("CPU usage is always zero...");
277 }
278
279 #[test]
280 fn check_users() {
281 let mut s = System::new();
282 assert!(s.users().is_empty());
283 s.refresh_users_list();
284 assert!(s.users().len() >= MIN_USERS);
285
286 let mut s = System::new();
287 assert!(s.users().is_empty());
288 s.refresh_all();
289 assert!(s.users().is_empty());
290
291 let s = System::new_all();
292 assert!(s.users().len() >= MIN_USERS);
293 }
294
295 #[test]
296 fn check_uid_gid() {
297 let mut s = System::new();
298 assert!(s.users().is_empty());
299 s.refresh_users_list();
300 let users = s.users();
301 assert!(users.len() >= MIN_USERS);
302
303 if System::IS_SUPPORTED {
304 #[cfg(not(target_os = "windows"))]
305 {
306 let user = users
307 .iter()
308 .find(|u| u.name() == "root")
309 .expect("no root user");
310 assert_eq!(**user.id(), 0);
311 assert_eq!(*user.group_id(), 0);
312 if let Some(user) = users.iter().find(|u| *u.group_id() > 0) {
313 assert!(**user.id() > 0);
314 assert!(*user.group_id() > 0);
315 }
316 assert!(users.iter().filter(|u| **u.id() > 0).count() > 0);
317 }
318
319 // And now check that our `get_user_by_id` method works.
320 s.refresh_processes();
321 assert!(s
322 .processes()
323 .iter()
324 .filter_map(|(_, p)| p.user_id())
325 .any(|uid| s.get_user_by_id(uid).is_some()));
326 }
327 }
328
329 #[test]
330 fn check_system_info() {
331 // We don't want to test on unsupported systems.
332 if System::IS_SUPPORTED {
333 let s = System::new();
334 assert!(!s.name().expect("Failed to get system name").is_empty());
335
336 assert!(!s
337 .kernel_version()
338 .expect("Failed to get kernel version")
339 .is_empty());
340
341 assert!(!s.os_version().expect("Failed to get os version").is_empty());
342
343 assert!(!s
344 .long_os_version()
345 .expect("Failed to get long OS version")
346 .is_empty());
347 }
348 }
349
350 #[test]
351 fn check_host_name() {
352 // We don't want to test on unsupported systems.
353 if System::IS_SUPPORTED {
354 let s = System::new();
355 assert!(s.host_name().is_some());
356 }
357 }
358
359 #[test]
360 fn check_refresh_process_return_value() {
361 // We don't want to test on unsupported systems.
362 if System::IS_SUPPORTED {
363 let _pid = get_current_pid().expect("Failed to get current PID");
364
365 #[cfg(not(feature = "apple-sandbox"))]
366 {
367 let mut s = System::new();
368 // First check what happens in case the process isn't already in our process list.
369 assert!(s.refresh_process(_pid));
370 // Then check that it still returns true if the process is already in our process list.
371 assert!(s.refresh_process(_pid));
372 }
373 }
374 }
375
376 #[test]
377 fn ensure_is_supported_is_set_correctly() {
378 if MIN_USERS > 0 {
379 assert!(System::IS_SUPPORTED);
380 } else {
381 assert!(!System::IS_SUPPORTED);
382 }
383 }
384
385 #[test]
386 fn check_cpus_number() {
387 let mut s = System::new();
388
389 // This information isn't retrieved by default.
390 assert!(s.cpus().is_empty());
391 if System::IS_SUPPORTED {
392 // The physical cores count is recomputed every time the function is called, so the
393 // information must be relevant even with nothing initialized.
394 let physical_cores_count = s
395 .physical_core_count()
396 .expect("failed to get number of physical cores");
397
398 s.refresh_cpu();
399 // The cpus shouldn't be empty anymore.
400 assert!(!s.cpus().is_empty());
401
402 // In case we are running inside a VM, it's possible to not have a physical core, only
403 // logical ones, which is why we don't test `physical_cores_count > 0`.
404 let physical_cores_count2 = s
405 .physical_core_count()
406 .expect("failed to get number of physical cores");
407 assert!(physical_cores_count2 <= s.cpus().len());
408 assert_eq!(physical_cores_count, physical_cores_count2);
409 } else {
410 assert_eq!(s.physical_core_count(), None);
411 }
412 assert!(s.physical_core_count().unwrap_or(0) <= s.cpus().len());
413 }
414
415 #[test]
416 fn check_nb_supported_signals() {
417 if System::IS_SUPPORTED {
418 assert!(
419 !System::SUPPORTED_SIGNALS.is_empty(),
420 "SUPPORTED_SIGNALS shoudn't be empty on supported systems!"
421 );
422 } else {
423 assert!(
424 System::SUPPORTED_SIGNALS.is_empty(),
425 "SUPPORTED_SIGNALS should be empty on not support systems!"
426 );
427 }
428 }
429
430 // Ensure that the CPUs frequency isn't retrieved until we ask for it.
431 #[test]
432 #[cfg(not(target_os = "freebsd"))] // In a VM, it'll fail.
433 fn check_cpu_frequency() {
434 if !System::IS_SUPPORTED {
435 return;
436 }
437 let mut s = System::new();
438 s.refresh_processes();
439 for proc_ in s.cpus() {
440 assert_eq!(proc_.frequency(), 0);
441 }
442 s.refresh_cpu();
443 for proc_ in s.cpus() {
444 assert_ne!(proc_.frequency(), 0);
445 }
446 }
447 }