1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use crate::{NetworkData, Networks, NetworksExt, UserExt}; |
4 | |
5 | use std::convert::{From, TryFrom}; |
6 | use std::fmt; |
7 | use std::str::FromStr; |
8 | |
9 | /// Trait to have a common conversions for the [`Pid`][crate::Pid] type. |
10 | /// |
11 | /// ``` |
12 | /// use sysinfo::{Pid, PidExt}; |
13 | /// |
14 | /// let p = Pid::from_u32(0); |
15 | /// let value: u32 = p.as_u32(); |
16 | /// ``` |
17 | pub trait PidExt: Copy + From<usize> + FromStr + fmt::Display { |
18 | /// Allows to convert [`Pid`][crate::Pid] into [`u32`]. |
19 | /// |
20 | /// ``` |
21 | /// use sysinfo::{Pid, PidExt}; |
22 | /// |
23 | /// let p = Pid::from_u32(0); |
24 | /// let value: u32 = p.as_u32(); |
25 | /// ``` |
26 | fn as_u32(self) -> u32; |
27 | /// Allows to convert a [`u32`] into [`Pid`][crate::Pid]. |
28 | /// |
29 | /// ``` |
30 | /// use sysinfo::{Pid, PidExt}; |
31 | /// |
32 | /// let p = Pid::from_u32(0); |
33 | /// ``` |
34 | fn from_u32(v: u32) -> Self; |
35 | } |
36 | |
37 | macro_rules! pid_decl { |
38 | ($typ:ty) => { |
39 | #[doc = include_str!("../md_doc/pid.md" )] |
40 | #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] |
41 | #[repr(transparent)] |
42 | pub struct Pid(pub(crate) $typ); |
43 | |
44 | impl From<usize> for Pid { |
45 | fn from(v: usize) -> Self { |
46 | Self(v as _) |
47 | } |
48 | } |
49 | impl From<Pid> for usize { |
50 | fn from(v: Pid) -> Self { |
51 | v.0 as _ |
52 | } |
53 | } |
54 | impl PidExt for Pid { |
55 | fn as_u32(self) -> u32 { |
56 | self.0 as _ |
57 | } |
58 | fn from_u32(v: u32) -> Self { |
59 | Self(v as _) |
60 | } |
61 | } |
62 | impl FromStr for Pid { |
63 | type Err = <$typ as FromStr>::Err; |
64 | fn from_str(s: &str) -> Result<Self, Self::Err> { |
65 | Ok(Self(<$typ>::from_str(s)?)) |
66 | } |
67 | } |
68 | impl fmt::Display for Pid { |
69 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
70 | write!(f, "{}" , self.0) |
71 | } |
72 | } |
73 | }; |
74 | } |
75 | |
76 | cfg_if::cfg_if! { |
77 | if #[cfg(all( |
78 | not(feature = "unknown-ci" ), |
79 | any( |
80 | target_os = "freebsd" , |
81 | target_os = "linux" , |
82 | target_os = "android" , |
83 | target_os = "macos" , |
84 | target_os = "ios" , |
85 | ) |
86 | ))] { |
87 | use libc::pid_t; |
88 | |
89 | pid_decl!(pid_t); |
90 | } else { |
91 | pid_decl!(usize); |
92 | } |
93 | } |
94 | |
95 | macro_rules! impl_get_set { |
96 | ($ty_name:ident, $name:ident, $with:ident, $without:ident $(, $extra_doc:literal)? $(,)?) => { |
97 | #[doc = concat!("Returns the value of the \"" , stringify!($name), " \" refresh kind." )] |
98 | $(#[doc = concat!(" |
99 | " , $extra_doc, " |
100 | " )])? |
101 | #[doc = concat!(" |
102 | ``` |
103 | use sysinfo::" , stringify!($ty_name), "; |
104 | |
105 | let r = " , stringify!($ty_name), "::new(); |
106 | assert_eq!(r." , stringify!($name), "(), false); |
107 | |
108 | let r = r.with_" , stringify!($name), "(); |
109 | assert_eq!(r." , stringify!($name), "(), true); |
110 | |
111 | let r = r.without_" , stringify!($name), "(); |
112 | assert_eq!(r." , stringify!($name), "(), false); |
113 | ```" )] |
114 | pub fn $name(&self) -> bool { |
115 | self.$name |
116 | } |
117 | |
118 | #[doc = concat!("Sets the value of the \"" , stringify!($name), " \" refresh kind to `true`. |
119 | |
120 | ``` |
121 | use sysinfo::" , stringify!($ty_name), "; |
122 | |
123 | let r = " , stringify!($ty_name), "::new(); |
124 | assert_eq!(r." , stringify!($name), "(), false); |
125 | |
126 | let r = r.with_" , stringify!($name), "(); |
127 | assert_eq!(r." , stringify!($name), "(), true); |
128 | ```" )] |
129 | #[must_use] |
130 | pub fn $with(mut self) -> Self { |
131 | self.$name = true; |
132 | self |
133 | } |
134 | |
135 | #[doc = concat!("Sets the value of the \"" , stringify!($name), " \" refresh kind to `false`. |
136 | |
137 | ``` |
138 | use sysinfo::" , stringify!($ty_name), "; |
139 | |
140 | let r = " , stringify!($ty_name), "::everything(); |
141 | assert_eq!(r." , stringify!($name), "(), true); |
142 | |
143 | let r = r.without_" , stringify!($name), "(); |
144 | assert_eq!(r." , stringify!($name), "(), false); |
145 | ```" )] |
146 | #[must_use] |
147 | pub fn $without(mut self) -> Self { |
148 | self.$name = false; |
149 | self |
150 | } |
151 | }; |
152 | |
153 | ($ty_name:ident, $name:ident, $with:ident, $without:ident, $typ:ty $(,)?) => { |
154 | #[doc = concat!("Returns the value of the \"" , stringify!($name), " \" refresh kind. |
155 | |
156 | ``` |
157 | use sysinfo::{" , stringify!($ty_name), ", " , stringify!($typ), "}; |
158 | |
159 | let r = " , stringify!($ty_name), "::new(); |
160 | assert_eq!(r." , stringify!($name), "().is_some(), false); |
161 | |
162 | let r = r.with_" , stringify!($name), "(" , stringify!($typ), "::everything()); |
163 | assert_eq!(r." , stringify!($name), "().is_some(), true); |
164 | |
165 | let r = r.without_" , stringify!($name), "(); |
166 | assert_eq!(r." , stringify!($name), "().is_some(), false); |
167 | ```" )] |
168 | pub fn $name(&self) -> Option<$typ> { |
169 | self.$name |
170 | } |
171 | |
172 | #[doc = concat!("Sets the value of the \"" , stringify!($name), " \" refresh kind to `true`. |
173 | |
174 | ``` |
175 | use sysinfo::{" , stringify!($ty_name), ", " , stringify!($typ), "}; |
176 | |
177 | let r = " , stringify!($ty_name), "::new(); |
178 | assert_eq!(r." , stringify!($name), "().is_some(), false); |
179 | |
180 | let r = r.with_" , stringify!($name), "(" , stringify!($typ), "::everything()); |
181 | assert_eq!(r." , stringify!($name), "().is_some(), true); |
182 | ```" )] |
183 | #[must_use] |
184 | pub fn $with(mut self, kind: $typ) -> Self { |
185 | self.$name = Some(kind); |
186 | self |
187 | } |
188 | |
189 | #[doc = concat!("Sets the value of the \"" , stringify!($name), " \" refresh kind to `false`. |
190 | |
191 | ``` |
192 | use sysinfo::" , stringify!($ty_name), "; |
193 | |
194 | let r = " , stringify!($ty_name), "::everything(); |
195 | assert_eq!(r." , stringify!($name), "().is_some(), true); |
196 | |
197 | let r = r.without_" , stringify!($name), "(); |
198 | assert_eq!(r." , stringify!($name), "().is_some(), false); |
199 | ```" )] |
200 | #[must_use] |
201 | pub fn $without(mut self) -> Self { |
202 | self.$name = None; |
203 | self |
204 | } |
205 | }; |
206 | } |
207 | |
208 | /// Used to determine what you want to refresh specifically on the [`Process`] type. |
209 | /// |
210 | /// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that |
211 | /// the information won't be retrieved if the information is accessible without needing |
212 | /// extra computation. |
213 | /// |
214 | /// ``` |
215 | /// use sysinfo::{ProcessExt, ProcessRefreshKind, System, SystemExt}; |
216 | /// |
217 | /// let mut system = System::new(); |
218 | /// |
219 | /// // We don't want to update the CPU information. |
220 | /// system.refresh_processes_specifics(ProcessRefreshKind::everything().without_cpu()); |
221 | /// |
222 | /// for (_, proc_) in system.processes() { |
223 | /// // We use a `==` comparison on float only because we know it's set to 0 here. |
224 | /// assert_eq!(proc_.cpu_usage(), 0.); |
225 | /// } |
226 | /// ``` |
227 | /// |
228 | /// [`Process`]: crate::Process |
229 | #[derive (Clone, Copy, Debug, Default, PartialEq, Eq)] |
230 | pub struct ProcessRefreshKind { |
231 | cpu: bool, |
232 | disk_usage: bool, |
233 | user: bool, |
234 | } |
235 | |
236 | impl ProcessRefreshKind { |
237 | /// Creates a new `ProcessRefreshKind` with every refresh set to `false`. |
238 | /// |
239 | /// ``` |
240 | /// use sysinfo::ProcessRefreshKind; |
241 | /// |
242 | /// let r = ProcessRefreshKind::new(); |
243 | /// |
244 | /// assert_eq!(r.cpu(), false); |
245 | /// assert_eq!(r.disk_usage(), false); |
246 | /// ``` |
247 | pub fn new() -> Self { |
248 | Self::default() |
249 | } |
250 | |
251 | /// Creates a new `ProcessRefreshKind` with every refresh set to `true`. |
252 | /// |
253 | /// ``` |
254 | /// use sysinfo::ProcessRefreshKind; |
255 | /// |
256 | /// let r = ProcessRefreshKind::everything(); |
257 | /// |
258 | /// assert_eq!(r.cpu(), true); |
259 | /// assert_eq!(r.disk_usage(), true); |
260 | /// ``` |
261 | pub fn everything() -> Self { |
262 | Self { |
263 | cpu: true, |
264 | disk_usage: true, |
265 | user: true, |
266 | } |
267 | } |
268 | |
269 | impl_get_set!(ProcessRefreshKind, cpu, with_cpu, without_cpu); |
270 | impl_get_set!( |
271 | ProcessRefreshKind, |
272 | disk_usage, |
273 | with_disk_usage, |
274 | without_disk_usage |
275 | ); |
276 | impl_get_set!( |
277 | ProcessRefreshKind, |
278 | user, |
279 | with_user, |
280 | without_user, |
281 | r#"This refresh is about `user_id` and `group_id`. Please note that it has an effect mostly |
282 | on Windows as other platforms get this information alongside the Process information directly."# , |
283 | ); |
284 | } |
285 | |
286 | /// Used to determine what you want to refresh specifically on the [`Cpu`] type. |
287 | /// |
288 | /// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that |
289 | /// the information won't be retrieved if the information is accessible without needing |
290 | /// extra computation. |
291 | /// |
292 | /// ``` |
293 | /// use sysinfo::{CpuExt, CpuRefreshKind, System, SystemExt}; |
294 | /// |
295 | /// let mut system = System::new(); |
296 | /// |
297 | /// // We don't want to update all the CPU information. |
298 | /// system.refresh_cpu_specifics(CpuRefreshKind::everything().without_frequency()); |
299 | /// |
300 | /// for cpu in system.cpus() { |
301 | /// assert_eq!(cpu.frequency(), 0); |
302 | /// } |
303 | /// ``` |
304 | /// |
305 | /// [`Cpu`]: crate::Cpu |
306 | #[derive (Clone, Copy, Debug, Default, PartialEq, Eq)] |
307 | pub struct CpuRefreshKind { |
308 | cpu_usage: bool, |
309 | frequency: bool, |
310 | } |
311 | |
312 | impl CpuRefreshKind { |
313 | /// Creates a new `CpuRefreshKind` with every refresh set to `false`. |
314 | /// |
315 | /// ``` |
316 | /// use sysinfo::CpuRefreshKind; |
317 | /// |
318 | /// let r = CpuRefreshKind::new(); |
319 | /// |
320 | /// assert_eq!(r.frequency(), false); |
321 | /// ``` |
322 | pub fn new() -> Self { |
323 | Self::default() |
324 | } |
325 | |
326 | /// Creates a new `CpuRefreshKind` with every refresh set to `true`. |
327 | /// |
328 | /// ``` |
329 | /// use sysinfo::CpuRefreshKind; |
330 | /// |
331 | /// let r = CpuRefreshKind::everything(); |
332 | /// |
333 | /// assert_eq!(r.frequency(), true); |
334 | /// ``` |
335 | pub fn everything() -> Self { |
336 | Self { |
337 | cpu_usage: true, |
338 | frequency: true, |
339 | } |
340 | } |
341 | |
342 | impl_get_set!(CpuRefreshKind, cpu_usage, with_cpu_usage, without_cpu_usage); |
343 | impl_get_set!(CpuRefreshKind, frequency, with_frequency, without_frequency); |
344 | } |
345 | |
346 | /// Used to determine what you want to refresh specifically on the [`System`] type. |
347 | /// |
348 | /// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that |
349 | /// the information won't be retrieved if the information is accessible without needing |
350 | /// extra computation. |
351 | /// |
352 | /// ``` |
353 | /// use sysinfo::{RefreshKind, System, SystemExt}; |
354 | /// |
355 | /// // We want everything except disks. |
356 | /// let mut system = System::new_with_specifics(RefreshKind::everything().without_disks_list()); |
357 | /// |
358 | /// assert_eq!(system.disks().len(), 0); |
359 | /// # if System::IS_SUPPORTED && !cfg!(feature = "apple-sandbox" ) { |
360 | /// assert!(system.processes().len() > 0); |
361 | /// # } |
362 | /// ``` |
363 | /// |
364 | /// [`System`]: crate::System |
365 | #[derive (Clone, Copy, Debug, Default, PartialEq, Eq)] |
366 | pub struct RefreshKind { |
367 | networks: bool, |
368 | networks_list: bool, |
369 | processes: Option<ProcessRefreshKind>, |
370 | disks_list: bool, |
371 | disks: bool, |
372 | memory: bool, |
373 | cpu: Option<CpuRefreshKind>, |
374 | components: bool, |
375 | components_list: bool, |
376 | users_list: bool, |
377 | } |
378 | |
379 | impl RefreshKind { |
380 | /// Creates a new `RefreshKind` with every refresh set to `false`/`None`. |
381 | /// |
382 | /// ``` |
383 | /// use sysinfo::RefreshKind; |
384 | /// |
385 | /// let r = RefreshKind::new(); |
386 | /// |
387 | /// assert_eq!(r.networks(), false); |
388 | /// assert_eq!(r.networks_list(), false); |
389 | /// assert_eq!(r.processes().is_some(), false); |
390 | /// assert_eq!(r.disks_list(), false); |
391 | /// assert_eq!(r.disks(), false); |
392 | /// assert_eq!(r.memory(), false); |
393 | /// assert_eq!(r.cpu().is_some(), false); |
394 | /// assert_eq!(r.components(), false); |
395 | /// assert_eq!(r.components_list(), false); |
396 | /// assert_eq!(r.users_list(), false); |
397 | /// ``` |
398 | pub fn new() -> Self { |
399 | Self::default() |
400 | } |
401 | |
402 | /// Creates a new `RefreshKind` with every refresh set to `true`/`Some(...)`. |
403 | /// |
404 | /// ``` |
405 | /// use sysinfo::RefreshKind; |
406 | /// |
407 | /// let r = RefreshKind::everything(); |
408 | /// |
409 | /// assert_eq!(r.networks(), true); |
410 | /// assert_eq!(r.networks_list(), true); |
411 | /// assert_eq!(r.processes().is_some(), true); |
412 | /// assert_eq!(r.disks_list(), true); |
413 | /// assert_eq!(r.disks(), true); |
414 | /// assert_eq!(r.memory(), true); |
415 | /// assert_eq!(r.cpu().is_some(), true); |
416 | /// assert_eq!(r.components(), true); |
417 | /// assert_eq!(r.components_list(), true); |
418 | /// assert_eq!(r.users_list(), true); |
419 | /// ``` |
420 | pub fn everything() -> Self { |
421 | Self { |
422 | networks: true, |
423 | networks_list: true, |
424 | processes: Some(ProcessRefreshKind::everything()), |
425 | disks: true, |
426 | disks_list: true, |
427 | memory: true, |
428 | cpu: Some(CpuRefreshKind::everything()), |
429 | components: true, |
430 | components_list: true, |
431 | users_list: true, |
432 | } |
433 | } |
434 | |
435 | impl_get_set!( |
436 | RefreshKind, |
437 | processes, |
438 | with_processes, |
439 | without_processes, |
440 | ProcessRefreshKind |
441 | ); |
442 | impl_get_set!(RefreshKind, networks, with_networks, without_networks); |
443 | impl_get_set!( |
444 | RefreshKind, |
445 | networks_list, |
446 | with_networks_list, |
447 | without_networks_list |
448 | ); |
449 | impl_get_set!(RefreshKind, disks, with_disks, without_disks); |
450 | impl_get_set!(RefreshKind, disks_list, with_disks_list, without_disks_list); |
451 | impl_get_set!(RefreshKind, memory, with_memory, without_memory); |
452 | impl_get_set!(RefreshKind, cpu, with_cpu, without_cpu, CpuRefreshKind); |
453 | impl_get_set!(RefreshKind, components, with_components, without_components); |
454 | impl_get_set!( |
455 | RefreshKind, |
456 | components_list, |
457 | with_components_list, |
458 | without_components_list |
459 | ); |
460 | impl_get_set!(RefreshKind, users_list, with_users_list, without_users_list); |
461 | } |
462 | |
463 | /// Iterator over network interfaces. |
464 | /// |
465 | /// It is returned by [`Networks::iter`][crate::Networks#method.iter]. |
466 | /// |
467 | /// ```no_run |
468 | /// use sysinfo::{System, SystemExt, NetworksExt}; |
469 | /// |
470 | /// let system = System::new_all(); |
471 | /// let networks_iter = system.networks().iter(); |
472 | /// ``` |
473 | pub struct NetworksIter<'a> { |
474 | inner: std::collections::hash_map::Iter<'a, String, NetworkData>, |
475 | } |
476 | |
477 | impl<'a> NetworksIter<'a> { |
478 | pub(crate) fn new(v: std::collections::hash_map::Iter<'a, String, NetworkData>) -> Self { |
479 | NetworksIter { inner: v } |
480 | } |
481 | } |
482 | |
483 | impl<'a> Iterator for NetworksIter<'a> { |
484 | type Item = (&'a String, &'a NetworkData); |
485 | |
486 | fn next(&mut self) -> Option<Self::Item> { |
487 | self.inner.next() |
488 | } |
489 | } |
490 | |
491 | impl<'a> IntoIterator for &'a Networks { |
492 | type Item = (&'a String, &'a NetworkData); |
493 | type IntoIter = NetworksIter<'a>; |
494 | |
495 | fn into_iter(self) -> Self::IntoIter { |
496 | self.iter() |
497 | } |
498 | } |
499 | |
500 | /// Enum containing the different supported kinds of disks. |
501 | /// |
502 | /// This type is returned by [`DiskExt::kind`](`crate::DiskExt::kind`). |
503 | /// |
504 | /// ```no_run |
505 | /// use sysinfo::{System, SystemExt, DiskExt}; |
506 | /// |
507 | /// let system = System::new_all(); |
508 | /// for disk in system.disks() { |
509 | /// println!("{:?}: {:?}" , disk.name(), disk.kind()); |
510 | /// } |
511 | /// ``` |
512 | #[derive (Debug, PartialEq, Eq, Clone, Copy)] |
513 | pub enum DiskKind { |
514 | /// HDD type. |
515 | HDD, |
516 | /// SSD type. |
517 | SSD, |
518 | /// Unknown type. |
519 | Unknown(isize), |
520 | } |
521 | |
522 | /// An enum representing signals on UNIX-like systems. |
523 | /// |
524 | /// On non-unix systems, this enum is mostly useless and is only there to keep coherency between |
525 | /// the different OSes. |
526 | /// |
527 | /// If you want the list of the supported signals on the current system, use |
528 | /// [`SystemExt::SUPPORTED_SIGNALS`][crate::SystemExt::SUPPORTED_SIGNALS]. |
529 | #[derive (Clone, Copy, PartialEq, Eq, PartialOrd, Debug)] |
530 | pub enum Signal { |
531 | /// Hangup detected on controlling terminal or death of controlling process. |
532 | Hangup, |
533 | /// Interrupt from keyboard. |
534 | Interrupt, |
535 | /// Quit from keyboard. |
536 | Quit, |
537 | /// Illegal instruction. |
538 | Illegal, |
539 | /// Trace/breakpoint trap. |
540 | Trap, |
541 | /// Abort signal from C abort function. |
542 | Abort, |
543 | /// IOT trap. A synonym for SIGABRT. |
544 | IOT, |
545 | /// Bus error (bad memory access). |
546 | Bus, |
547 | /// Floating point exception. |
548 | FloatingPointException, |
549 | /// Kill signal. |
550 | Kill, |
551 | /// User-defined signal 1. |
552 | User1, |
553 | /// Invalid memory reference. |
554 | Segv, |
555 | /// User-defined signal 2. |
556 | User2, |
557 | /// Broken pipe: write to pipe with no readers. |
558 | Pipe, |
559 | /// Timer signal from C alarm function. |
560 | Alarm, |
561 | /// Termination signal. |
562 | Term, |
563 | /// Child stopped or terminated. |
564 | Child, |
565 | /// Continue if stopped. |
566 | Continue, |
567 | /// Stop process. |
568 | Stop, |
569 | /// Stop typed at terminal. |
570 | TSTP, |
571 | /// Terminal input for background process. |
572 | TTIN, |
573 | /// Terminal output for background process. |
574 | TTOU, |
575 | /// Urgent condition on socket. |
576 | Urgent, |
577 | /// CPU time limit exceeded. |
578 | XCPU, |
579 | /// File size limit exceeded. |
580 | XFSZ, |
581 | /// Virtual alarm clock. |
582 | VirtualAlarm, |
583 | /// Profiling time expired. |
584 | Profiling, |
585 | /// Windows resize signal. |
586 | Winch, |
587 | /// I/O now possible. |
588 | IO, |
589 | /// Pollable event (Sys V). Synonym for IO |
590 | Poll, |
591 | /// Power failure (System V). |
592 | /// |
593 | /// Doesn't exist on apple systems so will be ignored. |
594 | Power, |
595 | /// Bad argument to routine (SVr4). |
596 | Sys, |
597 | } |
598 | |
599 | impl std::fmt::Display for Signal { |
600 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
601 | let s = match *self { |
602 | Self::Hangup => "Hangup" , |
603 | Self::Interrupt => "Interrupt" , |
604 | Self::Quit => "Quit" , |
605 | Self::Illegal => "Illegal" , |
606 | Self::Trap => "Trap" , |
607 | Self::Abort => "Abort" , |
608 | Self::IOT => "IOT" , |
609 | Self::Bus => "Bus" , |
610 | Self::FloatingPointException => "FloatingPointException" , |
611 | Self::Kill => "Kill" , |
612 | Self::User1 => "User1" , |
613 | Self::Segv => "Segv" , |
614 | Self::User2 => "User2" , |
615 | Self::Pipe => "Pipe" , |
616 | Self::Alarm => "Alarm" , |
617 | Self::Term => "Term" , |
618 | Self::Child => "Child" , |
619 | Self::Continue => "Continue" , |
620 | Self::Stop => "Stop" , |
621 | Self::TSTP => "TSTP" , |
622 | Self::TTIN => "TTIN" , |
623 | Self::TTOU => "TTOU" , |
624 | Self::Urgent => "Urgent" , |
625 | Self::XCPU => "XCPU" , |
626 | Self::XFSZ => "XFSZ" , |
627 | Self::VirtualAlarm => "VirtualAlarm" , |
628 | Self::Profiling => "Profiling" , |
629 | Self::Winch => "Winch" , |
630 | Self::IO => "IO" , |
631 | Self::Poll => "Poll" , |
632 | Self::Power => "Power" , |
633 | Self::Sys => "Sys" , |
634 | }; |
635 | f.write_str(s) |
636 | } |
637 | } |
638 | |
639 | /// A struct representing system load average value. |
640 | /// |
641 | /// It is returned by [`SystemExt::load_average`][crate::SystemExt::load_average]. |
642 | /// |
643 | /// ```no_run |
644 | /// use sysinfo::{System, SystemExt}; |
645 | /// |
646 | /// let s = System::new_all(); |
647 | /// let load_avg = s.load_average(); |
648 | /// println!( |
649 | /// "one minute: {}%, five minutes: {}%, fifteen minutes: {}%" , |
650 | /// load_avg.one, |
651 | /// load_avg.five, |
652 | /// load_avg.fifteen, |
653 | /// ); |
654 | /// ``` |
655 | #[repr (C)] |
656 | #[derive (Default, Debug, Clone)] |
657 | pub struct LoadAvg { |
658 | /// Average load within one minute. |
659 | pub one: f64, |
660 | /// Average load within five minutes. |
661 | pub five: f64, |
662 | /// Average load within fifteen minutes. |
663 | pub fifteen: f64, |
664 | } |
665 | |
666 | macro_rules! xid { |
667 | ($(#[$outer:meta])+ $name:ident, $type:ty $(, $trait:ty)?) => { |
668 | $(#[$outer])+ |
669 | #[repr(transparent)] |
670 | #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] |
671 | pub struct $name(pub(crate) $type); |
672 | |
673 | impl std::ops::Deref for $name { |
674 | type Target = $type; |
675 | |
676 | fn deref(&self) -> &Self::Target { |
677 | &self.0 |
678 | } |
679 | } |
680 | |
681 | $( |
682 | impl TryFrom<usize> for $name { |
683 | type Error = <$type as TryFrom<usize>>::Error; |
684 | |
685 | fn try_from(t: usize) -> Result<Self, <$type as TryFrom<usize>>::Error> { |
686 | Ok(Self(<$type>::try_from(t)?)) |
687 | } |
688 | } |
689 | |
690 | impl $trait for $name { |
691 | type Err = <$type as FromStr>::Err; |
692 | |
693 | fn from_str(t: &str) -> Result<Self, <$type as FromStr>::Err> { |
694 | Ok(Self(<$type>::from_str(t)?)) |
695 | } |
696 | } |
697 | )? |
698 | }; |
699 | } |
700 | |
701 | macro_rules! uid { |
702 | ($type:ty$(, $trait:ty)?) => { |
703 | xid!( |
704 | /// A user id wrapping a platform specific type. |
705 | Uid, |
706 | $type |
707 | $(, $trait)? |
708 | ); |
709 | }; |
710 | } |
711 | |
712 | macro_rules! gid { |
713 | ($type:ty) => { |
714 | xid!( |
715 | /// A group id wrapping a platform specific type. |
716 | #[derive(Copy)] |
717 | Gid, |
718 | $type, |
719 | FromStr |
720 | ); |
721 | }; |
722 | } |
723 | |
724 | cfg_if::cfg_if! { |
725 | if #[cfg(all( |
726 | not(feature = "unknown-ci" ), |
727 | any( |
728 | target_os = "freebsd" , |
729 | target_os = "linux" , |
730 | target_os = "android" , |
731 | target_os = "macos" , |
732 | target_os = "ios" , |
733 | ) |
734 | ))] { |
735 | uid!(libc::uid_t, FromStr); |
736 | gid!(libc::gid_t); |
737 | } else if #[cfg(windows)] { |
738 | uid!(crate::windows::Sid); |
739 | gid!(u32); |
740 | // Manual implementation outside of the macro... |
741 | impl FromStr for Uid { |
742 | type Err = <crate::windows::Sid as FromStr>::Err; |
743 | |
744 | fn from_str(t: &str) -> Result<Self, Self::Err> { |
745 | Ok(Self(t.parse()?)) |
746 | } |
747 | } |
748 | } else { |
749 | uid!(u32, FromStr); |
750 | gid!(u32); |
751 | } |
752 | } |
753 | |
754 | /// Type containing user information. |
755 | /// |
756 | /// It is returned by [`SystemExt::users`][crate::SystemExt::users]. |
757 | /// |
758 | /// ```no_run |
759 | /// use sysinfo::{System, SystemExt}; |
760 | /// |
761 | /// let s = System::new_all(); |
762 | /// println!("users: {:?}" , s.users()); |
763 | /// ``` |
764 | #[derive (PartialEq, Eq, PartialOrd, Ord, Debug)] |
765 | pub struct User { |
766 | pub(crate) uid: Uid, |
767 | pub(crate) gid: Gid, |
768 | pub(crate) name: String, |
769 | pub(crate) groups: Vec<String>, |
770 | } |
771 | |
772 | impl UserExt for User { |
773 | fn id(&self) -> &Uid { |
774 | &self.uid |
775 | } |
776 | |
777 | fn group_id(&self) -> Gid { |
778 | self.gid |
779 | } |
780 | |
781 | fn name(&self) -> &str { |
782 | &self.name |
783 | } |
784 | |
785 | fn groups(&self) -> &[String] { |
786 | &self.groups |
787 | } |
788 | } |
789 | |
790 | /// Type containing read and written bytes. |
791 | /// |
792 | /// It is returned by [`ProcessExt::disk_usage`][crate::ProcessExt::disk_usage]. |
793 | /// |
794 | /// ```no_run |
795 | /// use sysinfo::{ProcessExt, System, SystemExt}; |
796 | /// |
797 | /// let s = System::new_all(); |
798 | /// for (pid, process) in s.processes() { |
799 | /// let disk_usage = process.disk_usage(); |
800 | /// println!("[{}] read bytes : new/total => {}/{} B" , |
801 | /// pid, |
802 | /// disk_usage.read_bytes, |
803 | /// disk_usage.total_read_bytes, |
804 | /// ); |
805 | /// println!("[{}] written bytes: new/total => {}/{} B" , |
806 | /// pid, |
807 | /// disk_usage.written_bytes, |
808 | /// disk_usage.total_written_bytes, |
809 | /// ); |
810 | /// } |
811 | /// ``` |
812 | #[derive (Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd)] |
813 | pub struct DiskUsage { |
814 | /// Total number of written bytes. |
815 | pub total_written_bytes: u64, |
816 | /// Number of written bytes since the last refresh. |
817 | pub written_bytes: u64, |
818 | /// Total number of read bytes. |
819 | pub total_read_bytes: u64, |
820 | /// Number of read bytes since the last refresh. |
821 | pub read_bytes: u64, |
822 | } |
823 | |
824 | /// Enum describing the different status of a process. |
825 | #[derive (Clone, Copy, Debug, PartialEq, Eq)] |
826 | pub enum ProcessStatus { |
827 | /// ## Linux |
828 | /// |
829 | /// Idle kernel thread. |
830 | /// |
831 | /// ## macOs/FreeBSD |
832 | /// |
833 | /// Process being created by fork. |
834 | /// |
835 | /// ## Other OS |
836 | /// |
837 | /// Not available. |
838 | Idle, |
839 | /// Running. |
840 | Run, |
841 | /// ## Linux |
842 | /// |
843 | /// Sleeping in an interruptible waiting. |
844 | /// |
845 | /// ## macOS/FreeBSD |
846 | /// |
847 | /// Sleeping on an address. |
848 | /// |
849 | /// ## Other OS |
850 | /// |
851 | /// Not available. |
852 | Sleep, |
853 | /// ## Linux |
854 | /// |
855 | /// Stopped (on a signal) or (before Linux 2.6.33) trace stopped. |
856 | /// |
857 | /// ## macOS/FreeBSD |
858 | /// |
859 | /// Process debugging or suspension. |
860 | /// |
861 | /// ## Other OS |
862 | /// |
863 | /// Not available. |
864 | Stop, |
865 | /// ## Linux/FreeBSD/macOS |
866 | /// |
867 | /// Zombie process. Terminated but not reaped by its parent. |
868 | /// |
869 | /// ## Other OS |
870 | /// |
871 | /// Not available. |
872 | Zombie, |
873 | /// ## Linux |
874 | /// |
875 | /// Tracing stop (Linux 2.6.33 onward). Stopped by debugger during the tracing. |
876 | /// |
877 | /// ## Other OS |
878 | /// |
879 | /// Not available. |
880 | Tracing, |
881 | /// ## Linux |
882 | /// |
883 | /// Dead/uninterruptible sleep (usually IO). |
884 | /// |
885 | /// ## FreeBSD |
886 | /// |
887 | /// A process should never end up in this state. |
888 | /// |
889 | /// ## Other OS |
890 | /// |
891 | /// Not available. |
892 | Dead, |
893 | /// ## Linux |
894 | /// |
895 | /// Wakekill (Linux 2.6.33 to 3.13 only). |
896 | /// |
897 | /// ## Other OS |
898 | /// |
899 | /// Not available. |
900 | Wakekill, |
901 | /// ## Linux |
902 | /// |
903 | /// Waking (Linux 2.6.33 to 3.13 only). |
904 | /// |
905 | /// ## Other OS |
906 | /// |
907 | /// Not available. |
908 | Waking, |
909 | /// ## Linux |
910 | /// |
911 | /// Parked (Linux 3.9 to 3.13 only). |
912 | /// |
913 | /// ## macOS |
914 | /// |
915 | /// Halted at a clean point. |
916 | /// |
917 | /// ## Other OS |
918 | /// |
919 | /// Not available. |
920 | Parked, |
921 | /// ## FreeBSD |
922 | /// |
923 | /// Blocked on a lock. |
924 | /// |
925 | /// ## Other OS |
926 | /// |
927 | /// Not available. |
928 | LockBlocked, |
929 | /// ## Linux |
930 | /// |
931 | /// Waiting in uninterruptible disk sleep. |
932 | /// |
933 | /// ## Other OS |
934 | /// |
935 | /// Not available. |
936 | UninterruptibleDiskSleep, |
937 | /// Unknown. |
938 | Unknown(u32), |
939 | } |
940 | |
941 | /// Returns the pid for the current process. |
942 | /// |
943 | /// `Err` is returned in case the platform isn't supported. |
944 | /// |
945 | /// ```no_run |
946 | /// use sysinfo::get_current_pid; |
947 | /// |
948 | /// match get_current_pid() { |
949 | /// Ok(pid) => { |
950 | /// println!("current pid: {}" , pid); |
951 | /// } |
952 | /// Err(e) => { |
953 | /// eprintln!("failed to get current pid: {}" , e); |
954 | /// } |
955 | /// } |
956 | /// ``` |
957 | #[allow (clippy::unnecessary_wraps)] |
958 | pub fn get_current_pid() -> Result<Pid, &'static str> { |
959 | cfg_if::cfg_if! { |
960 | if #[cfg(feature = "unknown-ci" )] { |
961 | fn inner() -> Result<Pid, &'static str> { |
962 | Err("Unknown platform (CI)" ) |
963 | } |
964 | } else if #[cfg(any( |
965 | target_os = "freebsd" , |
966 | target_os = "linux" , |
967 | target_os = "android" , |
968 | target_os = "macos" , |
969 | target_os = "ios" , |
970 | ))] { |
971 | fn inner() -> Result<Pid, &'static str> { |
972 | unsafe { Ok(Pid(libc::getpid())) } |
973 | } |
974 | } else if #[cfg(windows)] { |
975 | fn inner() -> Result<Pid, &'static str> { |
976 | use winapi::um::processthreadsapi::GetCurrentProcessId; |
977 | |
978 | unsafe { Ok(Pid(GetCurrentProcessId() as _)) } |
979 | } |
980 | } else { |
981 | fn inner() -> Result<Pid, &'static str> { |
982 | Err("Unknown platform" ) |
983 | } |
984 | } |
985 | } |
986 | inner() |
987 | } |
988 | |
989 | /// MAC address for network interface. |
990 | /// |
991 | /// It is returned by [`NetworkExt::mac_address`][crate::NetworkExt::mac_address]. |
992 | #[derive (PartialEq, Eq, Copy, Clone, Debug)] |
993 | pub struct MacAddr(pub [u8; 6]); |
994 | |
995 | impl MacAddr { |
996 | /// A `MacAddr` with all bytes set to `0`. |
997 | pub const UNSPECIFIED: Self = MacAddr([0; 6]); |
998 | |
999 | /// Checks if this `MacAddr` has all bytes equal to `0`. |
1000 | pub fn is_unspecified(&self) -> bool { |
1001 | self == &MacAddr::UNSPECIFIED |
1002 | } |
1003 | } |
1004 | |
1005 | impl fmt::Display for MacAddr { |
1006 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
1007 | let data: &[u8; 6] = &self.0; |
1008 | write!( |
1009 | f, |
1010 | " {:02x}: {:02x}: {:02x}: {:02x}: {:02x}: {:02x}" , |
1011 | data[0], data[1], data[2], data[3], data[4], data[5], |
1012 | ) |
1013 | } |
1014 | } |
1015 | |
1016 | #[cfg (test)] |
1017 | mod tests { |
1018 | use super::{MacAddr, ProcessStatus}; |
1019 | |
1020 | // This test only exists to ensure that the `Display` and `Debug` traits are implemented on the |
1021 | // `ProcessStatus` enum on all targets. |
1022 | #[test ] |
1023 | fn check_display_impl_process_status() { |
1024 | println!(" {} {:?}" , ProcessStatus::Parked, ProcessStatus::Idle); |
1025 | } |
1026 | |
1027 | // Ensure that the `Display` and `Debug` traits are implemented on the `MacAddr` struct |
1028 | #[test ] |
1029 | fn check_display_impl_mac_address() { |
1030 | println!( |
1031 | " {} {:?}" , |
1032 | MacAddr([0x1, 0x2, 0x3, 0x4, 0x5, 0x6]), |
1033 | MacAddr([0xa, 0xb, 0xc, 0xd, 0xe, 0xf]) |
1034 | ); |
1035 | } |
1036 | |
1037 | #[test ] |
1038 | fn check_mac_address_is_unspecified_true() { |
1039 | assert!(MacAddr::UNSPECIFIED.is_unspecified()); |
1040 | assert!(MacAddr([0; 6]).is_unspecified()); |
1041 | } |
1042 | |
1043 | #[test ] |
1044 | fn check_mac_address_is_unspecified_false() { |
1045 | assert!(!MacAddr([1, 2, 3, 4, 5, 6]).is_unspecified()); |
1046 | } |
1047 | |
1048 | // This test exists to ensure that the `TryFrom<usize>` and `FromStr` traits are implemented |
1049 | // on `Uid`, `Gid` and `Pid`. |
1050 | #[test ] |
1051 | fn check_uid_gid_from_impls() { |
1052 | use std::convert::TryFrom; |
1053 | use std::str::FromStr; |
1054 | |
1055 | #[cfg (not(windows))] |
1056 | { |
1057 | assert!(crate::Uid::try_from(0usize).is_ok()); |
1058 | assert!(crate::Uid::from_str("0" ).is_ok()); |
1059 | } |
1060 | #[cfg (windows)] |
1061 | { |
1062 | assert!(crate::Uid::from_str("S-1-5-18" ).is_ok()); // SECURITY_LOCAL_SYSTEM_RID |
1063 | assert!(crate::Uid::from_str("0" ).is_err()); |
1064 | } |
1065 | |
1066 | assert!(crate::Gid::try_from(0usize).is_ok()); |
1067 | assert!(crate::Gid::from_str("0" ).is_ok()); |
1068 | |
1069 | assert!(crate::Pid::try_from(0usize).is_ok()); |
1070 | // If it doesn't panic, it's fine. |
1071 | let _ = crate::Pid::from(0); |
1072 | assert!(crate::Pid::from_str("0" ).is_ok()); |
1073 | } |
1074 | } |
1075 | |