Bug 1689358 - Generate minidumps for child process crashes using the minidump-writer...
[gecko.git] / third_party / rust / procfs-core / src / lib.rs
blob352b62ffd942a1a64edd398feadae017dd0d2a95
1 #![allow(unknown_lints)]
2 // The suggested fix with `str::parse` removes support for Rust 1.48
3 #![allow(clippy::from_str_radix_10)]
4 #![deny(broken_intra_doc_links, invalid_html_tags)]
5 //! This crate provides to an interface into the linux `procfs` filesystem, usually mounted at
6 //! `/proc`.
7 //!
8 //! This is a pseudo-filesystem which is available on most every linux system and provides an
9 //! interface to kernel data structures.
10 //!
11 //!
12 //! # Kernel support
13 //!
14 //! Not all fields/data are available in each kernel.  Some fields were added in specific kernel
15 //! releases, and other fields are only present in certain kernel configuration options are
16 //! enabled.  These are represented as `Option` fields in this crate.
17 //!
18 //! This crate aims to support all 2.6 kernels (and newer).  WSL2 is also supported.
19 //!
20 //! # Documentation
21 //!
22 //! In almost all cases, the documentation is taken from the
23 //! [`proc.5`](http://man7.org/linux/man-pages/man5/proc.5.html) manual page.  This means that
24 //! sometimes the style of writing is not very "rusty", or may do things like reference related files
25 //! (instead of referencing related structs).  Contributions to improve this are welcome.
26 //!
27 //! # Panicing
28 //!
29 //! While previous versions of the library could panic, this current version aims to be panic-free
30 //! in a many situations as possible.  Whenever the procfs crate encounters a bug in its own
31 //! parsing code, it will return an [`InternalError`](enum.ProcError.html#variant.InternalError) error.  This should be considered a
32 //! bug and should be [reported](https://github.com/eminence/procfs).  If you encounter a panic,
33 //! please report that as well.
34 //!
35 //! # Cargo features
36 //!
37 //! The following cargo features are available:
38 //!
39 //! * `chrono` -- Default.  Optional.  This feature enables a few methods that return values as `DateTime` objects.
40 //! * `backtrace` -- Optional.  This feature lets you get a stack trace whenever an `InternalError` is raised.
41 //!
42 //! # Examples
43 //!
44 //! Examples can be found in the various modules shown below, or in the
45 //! [examples](https://github.com/eminence/procfs/tree/master/examples) folder of the code repository.
46 //!
48 use bitflags::bitflags;
50 use std::fmt;
51 use std::io::{BufRead, BufReader, Read};
52 use std::path::{Path, PathBuf};
53 use std::str::FromStr;
54 use std::{collections::HashMap, time::Duration};
56 #[cfg(feature = "serde1")]
57 use serde::{Deserialize, Serialize};
59 /// Types which can be parsed from a Read implementation.
60 pub trait FromRead: Sized {
61     /// Read the type from a Read.
62     fn from_read<R: Read>(r: R) -> ProcResult<Self>;
64     /// Read the type from a file.
65     fn from_file<P: AsRef<Path>>(path: P) -> ProcResult<Self> {
66         std::fs::File::open(path.as_ref())
67             .map_err(|e| e.into())
68             .and_then(|f| Self::from_read(f))
69             .map_err(|e| e.error_path(path.as_ref()))
70     }
73 /// Types which can be parsed from a BufRead implementation.
74 pub trait FromBufRead: Sized {
75     fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self>;
78 impl<T: FromBufRead> FromRead for T {
79     fn from_read<R: Read>(r: R) -> ProcResult<Self> {
80         Self::from_buf_read(BufReader::new(r))
81     }
84 /// Types which can be parsed from a Read implementation and system info.
85 pub trait FromReadSI: Sized {
86     /// Parse the type from a Read and system info.
87     fn from_read<R: Read>(r: R, system_info: &SystemInfo) -> ProcResult<Self>;
89     /// Parse the type from a file.
90     fn from_file<P: AsRef<Path>>(path: P, system_info: &SystemInfo) -> ProcResult<Self> {
91         std::fs::File::open(path.as_ref())
92             .map_err(|e| e.into())
93             .and_then(|f| Self::from_read(f, system_info))
94             .map_err(|e| e.error_path(path.as_ref()))
95     }
98 /// Types which can be parsed from a BufRead implementation and system info.
99 pub trait FromBufReadSI: Sized {
100     fn from_buf_read<R: BufRead>(r: R, system_info: &SystemInfo) -> ProcResult<Self>;
103 impl<T: FromBufReadSI> FromReadSI for T {
104     fn from_read<R: Read>(r: R, system_info: &SystemInfo) -> ProcResult<Self> {
105         Self::from_buf_read(BufReader::new(r), system_info)
106     }
109 /// Extension traits useful for importing wholesale.
110 pub mod prelude {
111     pub use super::{FromBufRead, FromBufReadSI, FromRead, FromReadSI};
114 #[doc(hidden)]
115 pub trait IntoOption<T> {
116     fn into_option(t: Self) -> Option<T>;
119 impl<T> IntoOption<T> for Option<T> {
120     fn into_option(t: Option<T>) -> Option<T> {
121         t
122     }
125 impl<T, R> IntoOption<T> for Result<T, R> {
126     fn into_option(t: Result<T, R>) -> Option<T> {
127         t.ok()
128     }
131 #[doc(hidden)]
132 pub trait IntoResult<T, E> {
133     fn into(t: Self) -> Result<T, E>;
136 #[macro_export]
137 #[doc(hidden)]
138 macro_rules! build_internal_error {
139     ($err: expr) => {
140         crate::ProcError::InternalError(crate::InternalError {
141             msg: format!("Internal Unwrap Error: {}", $err),
142             file: file!(),
143             line: line!(),
144             #[cfg(feature = "backtrace")]
145             backtrace: backtrace::Backtrace::new(),
146         })
147     };
148     ($err: expr, $msg: expr) => {
149         crate::ProcError::InternalError(crate::InternalError {
150             msg: format!("Internal Unwrap Error: {}: {}", $msg, $err),
151             file: file!(),
152             line: line!(),
153             #[cfg(feature = "backtrace")]
154             backtrace: backtrace::Backtrace::new(),
155         })
156     };
159 // custom NoneError, since std::option::NoneError is nightly-only
160 // See https://github.com/rust-lang/rust/issues/42327
161 #[doc(hidden)]
162 pub struct NoneError;
164 impl std::fmt::Display for NoneError {
165     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166         write!(f, "NoneError")
167     }
170 impl<T> IntoResult<T, NoneError> for Option<T> {
171     fn into(t: Option<T>) -> Result<T, NoneError> {
172         t.ok_or(NoneError)
173     }
176 impl<T, E> IntoResult<T, E> for Result<T, E> {
177     fn into(t: Result<T, E>) -> Result<T, E> {
178         t
179     }
182 #[allow(unused_macros)]
183 #[macro_export]
184 #[doc(hidden)]
185 macro_rules! proc_panic {
186     ($e:expr) => {
187         crate::IntoOption::into_option($e).unwrap_or_else(|| {
188             panic!(
189                 "Failed to unwrap {}. Please report this as a procfs bug.",
190                 stringify!($e)
191             )
192         })
193     };
194     ($e:expr, $msg:expr) => {
195         crate::IntoOption::into_option($e).unwrap_or_else(|| {
196             panic!(
197                 "Failed to unwrap {} ({}). Please report this as a procfs bug.",
198                 stringify!($e),
199                 $msg
200             )
201         })
202     };
205 #[macro_export]
206 #[doc(hidden)]
207 macro_rules! expect {
208     ($e:expr) => {
209         match crate::IntoResult::into($e) {
210             Ok(v) => v,
211             Err(e) => return Err(crate::build_internal_error!(e)),
212         }
213     };
214     ($e:expr, $msg:expr) => {
215         match crate::IntoResult::into($e) {
216             Ok(v) => v,
217             Err(e) => return Err(crate::build_internal_error!(e, $msg)),
218         }
219     };
222 #[macro_export]
223 #[doc(hidden)]
224 macro_rules! from_str {
225     ($t:tt, $e:expr) => {{
226         let e = $e;
227         crate::expect!(
228             $t::from_str_radix(e, 10),
229             format!("Failed to parse {} ({:?}) as a {}", stringify!($e), e, stringify!($t),)
230         )
231     }};
232     ($t:tt, $e:expr, $radix:expr) => {{
233         let e = $e;
234         crate::expect!(
235             $t::from_str_radix(e, $radix),
236             format!("Failed to parse {} ({:?}) as a {}", stringify!($e), e, stringify!($t))
237         )
238     }};
239     ($t:tt, $e:expr, $radix:expr, pid:$pid:expr) => {{
240         let e = $e;
241         crate::expect!(
242             $t::from_str_radix(e, $radix),
243             format!(
244                 "Failed to parse {} ({:?}) as a {} (pid {})",
245                 stringify!($e),
246                 e,
247                 stringify!($t),
248                 $pid
249             )
250         )
251     }};
254 /// Auxiliary system information interface.
255 pub trait SystemInfoInterface {
256     fn boot_time_secs(&self) -> ProcResult<u64>;
257     fn ticks_per_second(&self) -> u64;
258     fn page_size(&self) -> u64;
259     /// Whether the system is little endian (true) or big endian (false).
260     fn is_little_endian(&self) -> bool;
262     #[cfg(feature = "chrono")]
263     fn boot_time(&self) -> ProcResult<chrono::DateTime<chrono::Local>> {
264         use chrono::TimeZone;
265         let date_time = expect!(chrono::Local.timestamp_opt(self.boot_time_secs()? as i64, 0).single());
266         Ok(date_time)
267     }
270 /// Auxiliary system information.
271 pub type SystemInfo = dyn SystemInfoInterface;
273 /// A convenience stuct implementing [SystemInfoInterface] with explicitly-specified values.
274 #[derive(Debug, Clone, Copy)]
275 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
276 pub struct ExplicitSystemInfo {
277     pub boot_time_secs: u64,
278     pub ticks_per_second: u64,
279     pub page_size: u64,
280     pub is_little_endian: bool,
283 impl SystemInfoInterface for ExplicitSystemInfo {
284     fn boot_time_secs(&self) -> ProcResult<u64> {
285         Ok(self.boot_time_secs)
286     }
288     fn ticks_per_second(&self) -> u64 {
289         self.ticks_per_second
290     }
292     fn page_size(&self) -> u64 {
293         self.page_size
294     }
296     fn is_little_endian(&self) -> bool {
297         self.is_little_endian
298     }
301 /// Values which can provide an output given the [SystemInfo].
302 pub trait WithSystemInfo<'a>: 'a {
303     type Output: 'a;
305     /// Get the output derived from the given [SystemInfo].
306     fn with_system_info(self, info: &SystemInfo) -> Self::Output;
309 impl<'a, F: 'a, R: 'a> WithSystemInfo<'a> for F
310 where
311     F: FnOnce(&SystemInfo) -> R,
313     type Output = R;
315     fn with_system_info(self, info: &SystemInfo) -> Self::Output {
316         self(info)
317     }
320 #[doc(hidden)]
321 pub fn from_iter<'a, I, U>(i: I) -> ProcResult<U>
322 where
323     I: IntoIterator<Item = &'a str>,
324     U: FromStr,
326     let mut iter = i.into_iter();
327     let val = expect!(iter.next());
328     match FromStr::from_str(val) {
329         Ok(u) => Ok(u),
330         Err(..) => Err(build_internal_error!("Failed to convert")),
331     }
334 fn from_iter_optional<'a, I, U>(i: I) -> ProcResult<Option<U>>
335 where
336     I: IntoIterator<Item = &'a str>,
337     U: FromStr,
339     let mut iter = i.into_iter();
340     let Some(val) = iter.next() else {
341         return Ok(None);
342     };
343     match FromStr::from_str(val) {
344         Ok(u) => Ok(Some(u)),
345         Err(..) => Err(build_internal_error!("Failed to convert")),
346     }
349 mod cgroups;
350 pub use cgroups::*;
352 mod cpuinfo;
353 pub use cpuinfo::*;
355 mod diskstats;
356 pub use diskstats::*;
358 mod iomem;
359 pub use iomem::*;
361 pub mod keyring;
363 mod locks;
364 pub use locks::*;
366 mod mounts;
367 pub use mounts::*;
369 mod meminfo;
370 pub use meminfo::*;
372 pub mod net;
374 mod pressure;
375 pub use pressure::*;
377 pub mod process;
379 pub mod sys;
380 pub use sys::kernel::Version as KernelVersion;
382 mod sysvipc_shm;
383 pub use sysvipc_shm::*;
385 mod uptime;
386 pub use uptime::*;
388 // TODO temporary, only for procfs
389 pub trait FromStrRadix: Sized {
390     fn from_str_radix(t: &str, radix: u32) -> Result<Self, std::num::ParseIntError>;
393 impl FromStrRadix for u64 {
394     fn from_str_radix(s: &str, radix: u32) -> Result<u64, std::num::ParseIntError> {
395         u64::from_str_radix(s, radix)
396     }
398 impl FromStrRadix for i32 {
399     fn from_str_radix(s: &str, radix: u32) -> Result<i32, std::num::ParseIntError> {
400         i32::from_str_radix(s, radix)
401     }
404 fn split_into_num<T: FromStrRadix>(s: &str, sep: char, radix: u32) -> ProcResult<(T, T)> {
405     let mut s = s.split(sep);
406     let a = expect!(FromStrRadix::from_str_radix(expect!(s.next()), radix));
407     let b = expect!(FromStrRadix::from_str_radix(expect!(s.next()), radix));
408     Ok((a, b))
411 /// This is used to hold both an IO error as well as the path of the file that originated the error
412 #[derive(Debug)]
413 #[doc(hidden)]
414 pub struct IoErrorWrapper {
415     pub path: PathBuf,
416     pub inner: std::io::Error,
419 impl std::error::Error for IoErrorWrapper {}
420 impl fmt::Display for IoErrorWrapper {
421     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
422         write!(f, "IoErrorWrapper({}): {}", self.path.display(), self.inner)
423     }
426 /// The main error type for the procfs crate.
428 /// For more info, see the [ProcError] type.
429 pub type ProcResult<T> = Result<T, ProcError>;
431 /// The various error conditions in the procfs crate.
433 /// Most of the variants have an `Option<PathBuf>` component.  If the error root cause was related
434 /// to some operation on a file, the path of this file will be stored in this component.
435 #[derive(Debug)]
436 pub enum ProcError {
437     /// A standard permission denied error.
438     ///
439     /// This will be a common error, since some files in the procfs filesystem are only readable by
440     /// the root user.
441     PermissionDenied(Option<PathBuf>),
442     /// This might mean that the process no longer exists, or that your kernel doesn't support the
443     /// feature you are trying to use.
444     NotFound(Option<PathBuf>),
445     /// This might mean that a procfs file has incomplete contents.
446     ///
447     /// If you encounter this error, consider retrying the operation.
448     Incomplete(Option<PathBuf>),
449     /// Any other IO error (rare).
450     Io(std::io::Error, Option<PathBuf>),
451     /// Any other non-IO error (very rare).
452     Other(String),
453     /// This error indicates that some unexpected error occurred.  This is a bug.  The inner
454     /// [InternalError] struct will contain some more info.
455     ///
456     /// If you ever encounter this error, consider it a bug in the procfs crate and please report
457     /// it on github.
458     InternalError(InternalError),
461 /// Extensions for dealing with ProcErrors.
462 pub trait ProcErrorExt {
463     /// Add path information to the error.
464     fn error_path(self, path: &Path) -> Self;
467 impl ProcErrorExt for ProcError {
468     fn error_path(mut self, path: &Path) -> Self {
469         use ProcError::*;
470         match &mut self {
471             PermissionDenied(p) | NotFound(p) | Incomplete(p) | Io(_, p) if p.is_none() => {
472                 *p = Some(path.to_owned());
473             }
474             _ => (),
475         }
476         self
477     }
480 impl<T> ProcErrorExt for ProcResult<T> {
481     fn error_path(self, path: &Path) -> Self {
482         self.map_err(|e| e.error_path(path))
483     }
486 /// An internal error in the procfs crate
488 /// If you encounter this error, consider it a bug and please report it on
489 /// [github](https://github.com/eminence/procfs).
491 /// If you compile with the optional `backtrace` feature (disabled by default),
492 /// you can gain access to a stack trace of where the error happened.
493 #[cfg_attr(feature = "serde1", derive(Serialize))]
494 pub struct InternalError {
495     pub msg: String,
496     pub file: &'static str,
497     pub line: u32,
498     #[cfg(feature = "backtrace")]
499     #[cfg_attr(feature = "serde1", serde(skip))]
500     pub backtrace: backtrace::Backtrace,
503 impl std::fmt::Debug for InternalError {
504     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
505         write!(
506             f,
507             "bug at {}:{} (please report this procfs bug)\n{}",
508             self.file, self.line, self.msg
509         )
510     }
513 impl std::fmt::Display for InternalError {
514     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
515         write!(
516             f,
517             "bug at {}:{} (please report this procfs bug)\n{}",
518             self.file, self.line, self.msg
519         )
520     }
523 impl From<std::io::Error> for ProcError {
524     fn from(io: std::io::Error) -> Self {
525         use std::io::ErrorKind;
526         let kind = io.kind();
527         // the only way we'll have a path for the IO error is if this IO error
528         // has a inner type
529         if io.get_ref().is_some() {
530             let inner = io.into_inner().unwrap();
532             // is this inner type a IoErrorWrapper?
533             match inner.downcast::<IoErrorWrapper>() {
534                 Ok(wrapper) => {
535                     let path = wrapper.path;
536                     match kind {
537                         ErrorKind::PermissionDenied => ProcError::PermissionDenied(Some(path)),
538                         ErrorKind::NotFound => ProcError::NotFound(Some(path)),
539                         _other => {
540                             // All platforms happen to have ESRCH=3, and windows actually
541                             // translates it to a `NotFound` anyway.
542                             const ESRCH: i32 = 3;
543                             if matches!(wrapper.inner.raw_os_error(), Some(raw) if raw == ESRCH) {
544                                 // This "No such process" error gets mapped into a NotFound error
545                                 return ProcError::NotFound(Some(path));
546                             } else {
547                                 ProcError::Io(wrapper.inner, Some(path))
548                             }
549                         }
550                     }
551                 }
552                 Err(io) => {
553                     // reconstruct the original error
554                     ProcError::Io(std::io::Error::new(kind, io), None)
555                 }
556             }
557         } else {
558             match kind {
559                 ErrorKind::PermissionDenied => ProcError::PermissionDenied(None),
560                 ErrorKind::NotFound => ProcError::NotFound(None),
561                 _other => ProcError::Io(io, None),
562             }
563         }
564     }
567 impl From<&'static str> for ProcError {
568     fn from(val: &'static str) -> Self {
569         ProcError::Other(val.to_owned())
570     }
573 impl From<std::num::ParseIntError> for ProcError {
574     fn from(val: std::num::ParseIntError) -> Self {
575         ProcError::Other(format!("ParseIntError: {}", val))
576     }
579 impl From<std::string::ParseError> for ProcError {
580     fn from(e: std::string::ParseError) -> Self {
581         match e {}
582     }
585 impl std::fmt::Display for ProcError {
586     fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
587         match self {
588             // Variants with paths:
589             ProcError::PermissionDenied(Some(p)) => write!(f, "Permission Denied: {}", p.display()),
590             ProcError::NotFound(Some(p)) => write!(f, "File not found: {}", p.display()),
591             ProcError::Incomplete(Some(p)) => write!(f, "Data incomplete: {}", p.display()),
592             ProcError::Io(inner, Some(p)) => {
593                 write!(f, "Unexpected IO error({}): {}", p.display(), inner)
594             }
595             // Variants without paths:
596             ProcError::PermissionDenied(None) => write!(f, "Permission Denied"),
597             ProcError::NotFound(None) => write!(f, "File not found"),
598             ProcError::Incomplete(None) => write!(f, "Data incomplete"),
599             ProcError::Io(inner, None) => write!(f, "Unexpected IO error: {}", inner),
601             ProcError::Other(s) => write!(f, "Unknown error {}", s),
602             ProcError::InternalError(e) => write!(f, "Internal error: {}", e),
603         }
604     }
607 impl std::error::Error for ProcError {}
609 /// Load average figures.
611 /// Load averages are calculated as the number of jobs in the run queue (state R) or waiting for
612 /// disk I/O (state D) averaged over 1, 5, and 15 minutes.
613 #[derive(Debug, Clone)]
614 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
615 pub struct LoadAverage {
616     /// The one-minute load average
617     pub one: f32,
618     /// The five-minute load average
619     pub five: f32,
620     /// The fifteen-minute load average
621     pub fifteen: f32,
622     /// The number of currently runnable kernel scheduling  entities  (processes,  threads).
623     pub cur: u32,
624     /// The number of kernel scheduling entities that currently exist on the system.
625     pub max: u32,
626     /// The fifth field is the PID of the process that was most recently created on the system.
627     pub latest_pid: u32,
630 impl FromRead for LoadAverage {
631     fn from_read<R: Read>(mut reader: R) -> ProcResult<Self> {
632         let mut line = String::new();
634         reader.read_to_string(&mut line)?;
635         let mut s = line.split_whitespace();
637         let one = expect!(f32::from_str(expect!(s.next())));
638         let five = expect!(f32::from_str(expect!(s.next())));
639         let fifteen = expect!(f32::from_str(expect!(s.next())));
640         let curmax = expect!(s.next());
641         let latest_pid = expect!(u32::from_str(expect!(s.next())));
643         let mut s = curmax.split('/');
644         let cur = expect!(u32::from_str(expect!(s.next())));
645         let max = expect!(u32::from_str(expect!(s.next())));
647         Ok(LoadAverage {
648             one,
649             five,
650             fifteen,
651             cur,
652             max,
653             latest_pid,
654         })
655     }
658 /// Possible values for a kernel config option
659 #[derive(Debug, Clone, PartialEq, Eq)]
660 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
661 pub enum ConfigSetting {
662     Yes,
663     Module,
664     Value(String),
667 /// The kernel configuration.
668 #[derive(Debug, Clone)]
669 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
670 pub struct KernelConfig(pub HashMap<String, ConfigSetting>);
672 impl FromBufRead for KernelConfig {
673     fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
674         let mut map = HashMap::new();
676         for line in r.lines() {
677             let line = line?;
678             if line.starts_with('#') {
679                 continue;
680             }
681             if line.contains('=') {
682                 let mut s = line.splitn(2, '=');
683                 let name = expect!(s.next()).to_owned();
684                 let value = match expect!(s.next()) {
685                     "y" => ConfigSetting::Yes,
686                     "m" => ConfigSetting::Module,
687                     s => ConfigSetting::Value(s.to_owned()),
688                 };
689                 map.insert(name, value);
690             }
691         }
693         Ok(KernelConfig(map))
694     }
697 /// The amount of time, measured in ticks, the CPU has been in specific states
699 /// These fields are measured in ticks because the underlying data from the kernel is measured in ticks.
700 /// The number of ticks per second is generally 100 on most systems.
702 /// To convert this value to seconds, you can divide by the tps.  There are also convenience methods
703 /// that you can use too.
704 #[derive(Debug, Clone)]
705 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
706 pub struct CpuTime {
707     /// Ticks spent in user mode
708     pub user: u64,
709     /// Ticks spent in user mode with low priority (nice)
710     pub nice: u64,
711     /// Ticks spent in system mode
712     pub system: u64,
713     /// Ticks spent in the idle state
714     pub idle: u64,
715     /// Ticks waiting for I/O to complete
716     ///
717     /// This value is not reliable, for the following reasons:
718     ///
719     /// 1. The CPU will not wait for I/O to complete; iowait is the time that a
720     ///    task is waiting for I/O to complete.  When a CPU goes into idle state
721     ///    for outstanding task I/O, another task will be scheduled on this CPU.
722     ///
723     /// 2. On a multi-core CPU, this task waiting for I/O to complete is not running
724     ///    on any CPU, so the iowait for each CPU is difficult to calculate.
725     ///
726     /// 3. The value in this field may *decrease* in certain conditions.
727     ///
728     /// (Since Linux 2.5.41)
729     pub iowait: Option<u64>,
730     /// Ticks servicing interrupts
731     ///
732     /// (Since Linux 2.6.0)
733     pub irq: Option<u64>,
734     /// Ticks servicing softirqs
735     ///
736     /// (Since Linux 2.6.0)
737     pub softirq: Option<u64>,
738     /// Ticks of stolen time.
739     ///
740     /// Stolen time is the time spent in other operating systems when running in
741     /// a virtualized environment.
742     ///
743     /// (Since Linux 2.6.11)
744     pub steal: Option<u64>,
745     /// Ticks spent running a virtual CPU for guest operating systems under control
746     /// of the linux kernel
747     ///
748     /// (Since Linux 2.6.24)
749     pub guest: Option<u64>,
750     /// Ticks spent running a niced guest
751     ///
752     /// (Since Linux 2.6.33)
753     pub guest_nice: Option<u64>,
755     tps: u64,
758 impl CpuTime {
759     fn from_str(s: &str, ticks_per_second: u64) -> ProcResult<CpuTime> {
760         let mut s = s.split_whitespace();
762         // Store this field in the struct so we don't have to attempt to unwrap ticks_per_second() when we convert
763         // from ticks into other time units
764         let tps = ticks_per_second;
766         s.next();
767         let user = from_str!(u64, expect!(s.next()));
768         let nice = from_str!(u64, expect!(s.next()));
769         let system = from_str!(u64, expect!(s.next()));
770         let idle = from_str!(u64, expect!(s.next()));
772         let iowait = s.next().map(|s| Ok(from_str!(u64, s))).transpose()?;
773         let irq = s.next().map(|s| Ok(from_str!(u64, s))).transpose()?;
774         let softirq = s.next().map(|s| Ok(from_str!(u64, s))).transpose()?;
775         let steal = s.next().map(|s| Ok(from_str!(u64, s))).transpose()?;
776         let guest = s.next().map(|s| Ok(from_str!(u64, s))).transpose()?;
777         let guest_nice = s.next().map(|s| Ok(from_str!(u64, s))).transpose()?;
779         Ok(CpuTime {
780             user,
781             nice,
782             system,
783             idle,
784             iowait,
785             irq,
786             softirq,
787             steal,
788             guest,
789             guest_nice,
790             tps,
791         })
792     }
794     /// Milliseconds spent in user mode
795     pub fn user_ms(&self) -> u64 {
796         let ms_per_tick = 1000 / self.tps;
797         self.user * ms_per_tick
798     }
800     /// Time spent in user mode
801     pub fn user_duration(&self) -> Duration {
802         Duration::from_millis(self.user_ms())
803     }
805     /// Milliseconds spent in user mode with low priority (nice)
806     pub fn nice_ms(&self) -> u64 {
807         let ms_per_tick = 1000 / self.tps;
808         self.nice * ms_per_tick
809     }
811     /// Time spent in user mode with low priority (nice)
812     pub fn nice_duration(&self) -> Duration {
813         Duration::from_millis(self.nice_ms())
814     }
816     /// Milliseconds spent in system mode
817     pub fn system_ms(&self) -> u64 {
818         let ms_per_tick = 1000 / self.tps;
819         self.system * ms_per_tick
820     }
822     /// Time spent in system mode
823     pub fn system_duration(&self) -> Duration {
824         Duration::from_millis(self.system_ms())
825     }
827     /// Milliseconds spent in the idle state
828     pub fn idle_ms(&self) -> u64 {
829         let ms_per_tick = 1000 / self.tps;
830         self.idle * ms_per_tick
831     }
833     /// Time spent in the idle state
834     pub fn idle_duration(&self) -> Duration {
835         Duration::from_millis(self.idle_ms())
836     }
838     /// Milliseconds spent waiting for I/O to complete
839     pub fn iowait_ms(&self) -> Option<u64> {
840         let ms_per_tick = 1000 / self.tps;
841         self.iowait.map(|io| io * ms_per_tick)
842     }
844     /// Time spent waiting for I/O to complete
845     pub fn iowait_duration(&self) -> Option<Duration> {
846         self.iowait_ms().map(Duration::from_millis)
847     }
849     /// Milliseconds spent servicing interrupts
850     pub fn irq_ms(&self) -> Option<u64> {
851         let ms_per_tick = 1000 / self.tps;
852         self.irq.map(|ms| ms * ms_per_tick)
853     }
855     /// Time spent servicing interrupts
856     pub fn irq_duration(&self) -> Option<Duration> {
857         self.irq_ms().map(Duration::from_millis)
858     }
860     /// Milliseconds spent servicing softirqs
861     pub fn softirq_ms(&self) -> Option<u64> {
862         let ms_per_tick = 1000 / self.tps;
863         self.softirq.map(|ms| ms * ms_per_tick)
864     }
866     /// Time spent servicing softirqs
867     pub fn softirq_duration(&self) -> Option<Duration> {
868         self.softirq_ms().map(Duration::from_millis)
869     }
871     /// Milliseconds of stolen time
872     pub fn steal_ms(&self) -> Option<u64> {
873         let ms_per_tick = 1000 / self.tps;
874         self.steal.map(|ms| ms * ms_per_tick)
875     }
877     /// Amount of stolen time
878     pub fn steal_duration(&self) -> Option<Duration> {
879         self.steal_ms().map(Duration::from_millis)
880     }
882     /// Milliseconds spent running a virtual CPU for guest operating systems under control of the linux kernel
883     pub fn guest_ms(&self) -> Option<u64> {
884         let ms_per_tick = 1000 / self.tps;
885         self.guest.map(|ms| ms * ms_per_tick)
886     }
888     /// Time spent running a virtual CPU for guest operating systems under control of the linux kernel
889     pub fn guest_duration(&self) -> Option<Duration> {
890         self.guest_ms().map(Duration::from_millis)
891     }
893     /// Milliseconds spent running a niced guest
894     pub fn guest_nice_ms(&self) -> Option<u64> {
895         let ms_per_tick = 1000 / self.tps;
896         self.guest_nice.map(|ms| ms * ms_per_tick)
897     }
899     /// Time spent running a niced guest
900     pub fn guest_nice_duration(&self) -> Option<Duration> {
901         self.guest_nice_ms().map(Duration::from_millis)
902     }
905 /// Kernel/system statistics, from `/proc/stat`
906 #[derive(Debug, Clone)]
907 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
908 pub struct KernelStats {
909     /// The amount of time the system spent in various states
910     pub total: CpuTime,
911     /// The amount of time that specific CPUs spent in various states
912     pub cpu_time: Vec<CpuTime>,
914     /// The number of context switches that the system underwent
915     pub ctxt: u64,
917     /// Boot time, in number of seconds since the Epoch
918     pub btime: u64,
920     /// Number of forks since boot
921     pub processes: u64,
923     /// Number of processes in runnable state
924     ///
925     /// (Since Linux 2.5.45)
926     pub procs_running: Option<u32>,
928     /// Number of processes blocked waiting for I/O
929     ///
930     /// (Since Linux 2.5.45)
931     pub procs_blocked: Option<u32>,
934 impl FromBufReadSI for KernelStats {
935     fn from_buf_read<R: BufRead>(r: R, system_info: &SystemInfo) -> ProcResult<Self> {
936         let lines = r.lines();
938         let mut total_cpu = None;
939         let mut cpus = Vec::new();
940         let mut ctxt = None;
941         let mut btime = None;
942         let mut processes = None;
943         let mut procs_running = None;
944         let mut procs_blocked = None;
946         for line in lines {
947             let line = line?;
948             if line.starts_with("cpu ") {
949                 total_cpu = Some(CpuTime::from_str(&line, system_info.ticks_per_second())?);
950             } else if line.starts_with("cpu") {
951                 cpus.push(CpuTime::from_str(&line, system_info.ticks_per_second())?);
952             } else if let Some(stripped) = line.strip_prefix("ctxt ") {
953                 ctxt = Some(from_str!(u64, stripped));
954             } else if let Some(stripped) = line.strip_prefix("btime ") {
955                 btime = Some(from_str!(u64, stripped));
956             } else if let Some(stripped) = line.strip_prefix("processes ") {
957                 processes = Some(from_str!(u64, stripped));
958             } else if let Some(stripped) = line.strip_prefix("procs_running ") {
959                 procs_running = Some(from_str!(u32, stripped));
960             } else if let Some(stripped) = line.strip_prefix("procs_blocked ") {
961                 procs_blocked = Some(from_str!(u32, stripped));
962             }
963         }
965         Ok(KernelStats {
966             total: expect!(total_cpu),
967             cpu_time: cpus,
968             ctxt: expect!(ctxt),
969             btime: expect!(btime),
970             processes: expect!(processes),
971             procs_running,
972             procs_blocked,
973         })
974     }
977 /// Various virtual memory statistics
979 /// Since the exact set of statistics will vary from kernel to kernel, and because most of them are
980 /// not well documented, this struct contains a HashMap instead of specific members. Consult the
981 /// kernel source code for more details of this data.
982 #[derive(Debug, Clone)]
983 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
984 pub struct VmStat(pub HashMap<String, i64>);
986 impl FromBufRead for VmStat {
987     fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
988         let mut map = HashMap::new();
989         for line in r.lines() {
990             let line = line?;
991             let mut split = line.split_whitespace();
992             let name = expect!(split.next());
993             let val = from_str!(i64, expect!(split.next()));
994             map.insert(name.to_owned(), val);
995         }
997         Ok(VmStat(map))
998     }
1001 /// Details about a loaded kernel module
1003 /// For an example, see the [lsmod.rs](https://github.com/eminence/procfs/tree/master/examples)
1004 /// example in the source repo.
1005 #[derive(Debug, Clone)]
1006 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
1007 pub struct KernelModule {
1008     /// The name of the module
1009     pub name: String,
1011     /// The size of the module
1012     pub size: u32,
1014     /// The number of references in the kernel to this module.  This can be -1 if the module is unloading
1015     pub refcount: i32,
1017     /// A list of modules that depend on this module.
1018     pub used_by: Vec<String>,
1020     /// The module state
1021     ///
1022     /// This will probably always be "Live", but it could also be either "Unloading" or "Loading"
1023     pub state: String,
1026 /// A set of loaded kernel modules
1027 #[derive(Debug, Clone)]
1028 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
1029 pub struct KernelModules(pub HashMap<String, KernelModule>);
1031 impl FromBufRead for KernelModules {
1032     /// This should correspond to the data in `/proc/modules`.
1033     fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
1034         // kernel reference: kernel/module.c m_show()
1035         let mut map = HashMap::new();
1036         for line in r.lines() {
1037             let line: String = line?;
1038             let mut s = line.split_whitespace();
1039             let name = expect!(s.next());
1040             let size = from_str!(u32, expect!(s.next()));
1041             let refcount = from_str!(i32, expect!(s.next()));
1042             let used_by: &str = expect!(s.next());
1043             let state = expect!(s.next());
1045             map.insert(
1046                 name.to_string(),
1047                 KernelModule {
1048                     name: name.to_string(),
1049                     size,
1050                     refcount,
1051                     used_by: if used_by == "-" {
1052                         Vec::new()
1053                     } else {
1054                         used_by
1055                             .split(',')
1056                             .filter(|s| !s.is_empty())
1057                             .map(|s| s.to_string())
1058                             .collect()
1059                     },
1060                     state: state.to_string(),
1061                 },
1062             );
1063         }
1065         Ok(KernelModules(map))
1066     }
1069 /// A list of the arguments passed to the Linux kernel at boot time.
1070 #[derive(Debug, Clone)]
1071 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
1072 pub struct KernelCmdline(pub Vec<String>);
1074 impl FromRead for KernelCmdline {
1075     /// This should correspond to the data in `/proc/cmdline`.
1076     fn from_read<R: Read>(mut r: R) -> ProcResult<Self> {
1077         let mut buf = String::new();
1078         r.read_to_string(&mut buf)?;
1079         Ok(KernelCmdline(
1080             buf.split(' ')
1081                 .filter_map(|s| if !s.is_empty() { Some(s.to_string()) } else { None })
1082                 .collect(),
1083         ))
1084     }
1087 #[cfg(test)]
1088 mod tests {
1089     use super::*;
1091     #[test]
1092     fn test_kernel_from_str() {
1093         let k = KernelVersion::from_str("1.2.3").unwrap();
1094         assert_eq!(k.major, 1);
1095         assert_eq!(k.minor, 2);
1096         assert_eq!(k.patch, 3);
1098         let k = KernelVersion::from_str("4.9.16-gentoo").unwrap();
1099         assert_eq!(k.major, 4);
1100         assert_eq!(k.minor, 9);
1101         assert_eq!(k.patch, 16);
1103         let k = KernelVersion::from_str("4.9.266-0.1.ac.225.84.332.metal1.x86_64").unwrap();
1104         assert_eq!(k.major, 4);
1105         assert_eq!(k.minor, 9);
1106         assert_eq!(k.patch, 266);
1107     }
1109     #[test]
1110     fn test_kernel_cmp() {
1111         let a = KernelVersion::from_str("1.2.3").unwrap();
1112         let b = KernelVersion::from_str("1.2.3").unwrap();
1113         let c = KernelVersion::from_str("1.2.4").unwrap();
1114         let d = KernelVersion::from_str("1.5.4").unwrap();
1115         let e = KernelVersion::from_str("2.5.4").unwrap();
1117         assert_eq!(a, b);
1118         assert!(a < c);
1119         assert!(a < d);
1120         assert!(a < e);
1121         assert!(e > d);
1122         assert!(e > c);
1123         assert!(e > b);
1124     }
1126     #[test]
1127     fn test_loadavg_from_reader() -> ProcResult<()> {
1128         let load_average = LoadAverage::from_read("2.63 1.00 1.42 3/4280 2496732".as_bytes())?;
1130         assert_eq!(load_average.one, 2.63);
1131         assert_eq!(load_average.five, 1.00);
1132         assert_eq!(load_average.fifteen, 1.42);
1133         assert_eq!(load_average.max, 4280);
1134         assert_eq!(load_average.cur, 3);
1135         assert_eq!(load_average.latest_pid, 2496732);
1136         Ok(())
1137     }
1139     #[test]
1140     fn test_from_str() -> ProcResult<()> {
1141         assert_eq!(from_str!(u8, "12"), 12);
1142         assert_eq!(from_str!(u8, "A", 16), 10);
1143         Ok(())
1144     }
1146     #[test]
1147     fn test_from_str_fail() {
1148         fn inner() -> ProcResult<()> {
1149             let s = "four";
1150             from_str!(u8, s);
1151             unreachable!()
1152         }
1154         assert!(inner().is_err())
1155     }
1157     #[test]
1158     fn test_nopanic() {
1159         fn _inner() -> ProcResult<bool> {
1160             let x: Option<bool> = None;
1161             let y: bool = expect!(x);
1162             Ok(y)
1163         }
1165         let r = _inner();
1166         println!("{:?}", r);
1167         assert!(r.is_err());
1169         fn _inner2() -> ProcResult<bool> {
1170             let _f: std::fs::File = expect!(std::fs::File::open("/doesnotexist"));
1171             Ok(true)
1172         }
1174         let r = _inner2();
1175         println!("{:?}", r);
1176         assert!(r.is_err());
1177     }
1179     #[cfg(feature = "backtrace")]
1180     #[test]
1181     fn test_backtrace() {
1182         fn _inner() -> ProcResult<bool> {
1183             let _f: std::fs::File = expect!(std::fs::File::open("/doesnotexist"));
1184             Ok(true)
1185         }
1187         let r = _inner();
1188         println!("{:?}", r);
1189     }