procfs_core/
lib.rs

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