1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::{NetworkData, Networks, NetworksExt, UserExt};
4
5use std::convert::{From, TryFrom};
6use std::fmt;
7use 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/// ```
17pub 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
37macro_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
76cfg_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
95macro_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```
103use sysinfo::", stringify!($ty_name), ";
104
105let r = ", stringify!($ty_name), "::new();
106assert_eq!(r.", stringify!($name), "(), false);
107
108let r = r.with_", stringify!($name), "();
109assert_eq!(r.", stringify!($name), "(), true);
110
111let r = r.without_", stringify!($name), "();
112assert_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```
121use sysinfo::", stringify!($ty_name), ";
122
123let r = ", stringify!($ty_name), "::new();
124assert_eq!(r.", stringify!($name), "(), false);
125
126let r = r.with_", stringify!($name), "();
127assert_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```
138use sysinfo::", stringify!($ty_name), ";
139
140let r = ", stringify!($ty_name), "::everything();
141assert_eq!(r.", stringify!($name), "(), true);
142
143let r = r.without_", stringify!($name), "();
144assert_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```
157use sysinfo::{", stringify!($ty_name), ", ", stringify!($typ), "};
158
159let r = ", stringify!($ty_name), "::new();
160assert_eq!(r.", stringify!($name), "().is_some(), false);
161
162let r = r.with_", stringify!($name), "(", stringify!($typ), "::everything());
163assert_eq!(r.", stringify!($name), "().is_some(), true);
164
165let r = r.without_", stringify!($name), "();
166assert_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```
175use sysinfo::{", stringify!($ty_name), ", ", stringify!($typ), "};
176
177let r = ", stringify!($ty_name), "::new();
178assert_eq!(r.", stringify!($name), "().is_some(), false);
179
180let r = r.with_", stringify!($name), "(", stringify!($typ), "::everything());
181assert_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```
192use sysinfo::", stringify!($ty_name), ";
193
194let r = ", stringify!($ty_name), "::everything();
195assert_eq!(r.", stringify!($name), "().is_some(), true);
196
197let r = r.without_", stringify!($name), "();
198assert_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)]
230pub struct ProcessRefreshKind {
231 cpu: bool,
232 disk_usage: bool,
233 user: bool,
234}
235
236impl 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
282on 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)]
307pub struct CpuRefreshKind {
308 cpu_usage: bool,
309 frequency: bool,
310}
311
312impl 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)]
366pub 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
379impl 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/// ```
473pub struct NetworksIter<'a> {
474 inner: std::collections::hash_map::Iter<'a, String, NetworkData>,
475}
476
477impl<'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
483impl<'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
491impl<'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)]
513pub 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)]
530pub 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
599impl 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)]
657pub 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
666macro_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
701macro_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
712macro_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
724cfg_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)]
765pub 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
772impl 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)]
813pub 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)]
826pub 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)]
958pub 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)]
993pub struct MacAddr(pub [u8; 6]);
994
995impl 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
1005impl 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)]
1017mod 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