sysinfo/
common.rs

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 = &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}