procfs_core/
lib.rs

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