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
8 //! This is a pseudo-filesystem which is available on most every linux system and provides an
9 //! interface to kernel data structures.
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.
18 //! This crate aims to support all 2.6 kernels (and newer). WSL2 is also supported.
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.
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.
37 //! The following cargo features are available:
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.
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.
48 use bitflags::bitflags;
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()))
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))
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()))
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)
109 /// Extension traits useful for importing wholesale.
111 pub use super::{FromBufRead, FromBufReadSI, FromRead, FromReadSI};
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> {
125 impl<T, R> IntoOption<T> for Result<T, R> {
126 fn into_option(t: Result<T, R>) -> Option<T> {
132 pub trait IntoResult<T, E> {
133 fn into(t: Self) -> Result<T, E>;
138 macro_rules! build_internal_error {
140 crate::ProcError::InternalError(crate::InternalError {
141 msg: format!("Internal Unwrap Error: {}", $err),
144 #[cfg(feature = "backtrace")]
145 backtrace: backtrace::Backtrace::new(),
148 ($err: expr, $msg: expr) => {
149 crate::ProcError::InternalError(crate::InternalError {
150 msg: format!("Internal Unwrap Error: {}: {}", $msg, $err),
153 #[cfg(feature = "backtrace")]
154 backtrace: backtrace::Backtrace::new(),
159 // custom NoneError, since std::option::NoneError is nightly-only
160 // See https://github.com/rust-lang/rust/issues/42327
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")
170 impl<T> IntoResult<T, NoneError> for Option<T> {
171 fn into(t: Option<T>) -> Result<T, NoneError> {
176 impl<T, E> IntoResult<T, E> for Result<T, E> {
177 fn into(t: Result<T, E>) -> Result<T, E> {
182 #[allow(unused_macros)]
185 macro_rules! proc_panic {
187 crate::IntoOption::into_option($e).unwrap_or_else(|| {
189 "Failed to unwrap {}. Please report this as a procfs bug.",
194 ($e:expr, $msg:expr) => {
195 crate::IntoOption::into_option($e).unwrap_or_else(|| {
197 "Failed to unwrap {} ({}). Please report this as a procfs bug.",
207 macro_rules! expect {
209 match crate::IntoResult::into($e) {
211 Err(e) => return Err(crate::build_internal_error!(e)),
214 ($e:expr, $msg:expr) => {
215 match crate::IntoResult::into($e) {
217 Err(e) => return Err(crate::build_internal_error!(e, $msg)),
224 macro_rules! from_str {
225 ($t:tt, $e:expr) => {{
228 $t::from_str_radix(e, 10),
229 format!("Failed to parse {} ({:?}) as a {}", stringify!($e), e, stringify!($t),)
232 ($t:tt, $e:expr, $radix:expr) => {{
235 $t::from_str_radix(e, $radix),
236 format!("Failed to parse {} ({:?}) as a {}", stringify!($e), e, stringify!($t))
239 ($t:tt, $e:expr, $radix:expr, pid:$pid:expr) => {{
242 $t::from_str_radix(e, $radix),
244 "Failed to parse {} ({:?}) as a {} (pid {})",
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());
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,
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)
288 fn ticks_per_second(&self) -> u64 {
289 self.ticks_per_second
292 fn page_size(&self) -> u64 {
296 fn is_little_endian(&self) -> bool {
297 self.is_little_endian
301 /// Values which can provide an output given the [SystemInfo].
302 pub trait WithSystemInfo<'a>: '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
311 F: FnOnce(&SystemInfo) -> R,
315 fn with_system_info(self, info: &SystemInfo) -> Self::Output {
321 pub fn from_iter<'a, I, U>(i: I) -> ProcResult<U>
323 I: IntoIterator<Item = &'a str>,
326 let mut iter = i.into_iter();
327 let val = expect!(iter.next());
328 match FromStr::from_str(val) {
330 Err(..) => Err(build_internal_error!("Failed to convert")),
334 fn from_iter_optional<'a, I, U>(i: I) -> ProcResult<Option<U>>
336 I: IntoIterator<Item = &'a str>,
339 let mut iter = i.into_iter();
340 let Some(val) = iter.next() else {
343 match FromStr::from_str(val) {
344 Ok(u) => Ok(Some(u)),
345 Err(..) => Err(build_internal_error!("Failed to convert")),
356 pub use diskstats::*;
380 pub use sys::kernel::Version as KernelVersion;
383 pub use sysvipc_shm::*;
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)
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)
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));
411 /// This is used to hold both an IO error as well as the path of the file that originated the error
414 pub struct IoErrorWrapper {
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)
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.
437 /// A standard permission denied error.
439 /// This will be a common error, since some files in the procfs filesystem are only readable by
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.
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).
453 /// This error indicates that some unexpected error occurred. This is a bug. The inner
454 /// [InternalError] struct will contain some more info.
456 /// If you ever encounter this error, consider it a bug in the procfs crate and please report
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 {
471 PermissionDenied(p) | NotFound(p) | Incomplete(p) | Io(_, p) if p.is_none() => {
472 *p = Some(path.to_owned());
480 impl<T> ProcErrorExt for ProcResult<T> {
481 fn error_path(self, path: &Path) -> Self {
482 self.map_err(|e| e.error_path(path))
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 {
496 pub file: &'static str,
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 {
507 "bug at {}:{} (please report this procfs bug)\n{}",
508 self.file, self.line, self.msg
513 impl std::fmt::Display for InternalError {
514 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
517 "bug at {}:{} (please report this procfs bug)\n{}",
518 self.file, self.line, self.msg
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
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>() {
535 let path = wrapper.path;
537 ErrorKind::PermissionDenied => ProcError::PermissionDenied(Some(path)),
538 ErrorKind::NotFound => ProcError::NotFound(Some(path)),
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));
547 ProcError::Io(wrapper.inner, Some(path))
553 // reconstruct the original error
554 ProcError::Io(std::io::Error::new(kind, io), None)
559 ErrorKind::PermissionDenied => ProcError::PermissionDenied(None),
560 ErrorKind::NotFound => ProcError::NotFound(None),
561 _other => ProcError::Io(io, None),
567 impl From<&'static str> for ProcError {
568 fn from(val: &'static str) -> Self {
569 ProcError::Other(val.to_owned())
573 impl From<std::num::ParseIntError> for ProcError {
574 fn from(val: std::num::ParseIntError) -> Self {
575 ProcError::Other(format!("ParseIntError: {}", val))
579 impl From<std::string::ParseError> for ProcError {
580 fn from(e: std::string::ParseError) -> Self {
585 impl std::fmt::Display for ProcError {
586 fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
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)
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),
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
618 /// The five-minute load average
620 /// The fifteen-minute load average
622 /// The number of currently runnable kernel scheduling entities (processes, threads).
624 /// The number of kernel scheduling entities that currently exist on the system.
626 /// The fifth field is the PID of the process that was most recently created on the system.
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())));
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 {
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() {
678 if line.starts_with('#') {
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()),
689 map.insert(name, value);
693 Ok(KernelConfig(map))
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))]
707 /// Ticks spent in user mode
709 /// Ticks spent in user mode with low priority (nice)
711 /// Ticks spent in system mode
713 /// Ticks spent in the idle state
715 /// Ticks waiting for I/O to complete
717 /// This value is not reliable, for the following reasons:
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.
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.
726 /// 3. The value in this field may *decrease* in certain conditions.
728 /// (Since Linux 2.5.41)
729 pub iowait: Option<u64>,
730 /// Ticks servicing interrupts
732 /// (Since Linux 2.6.0)
733 pub irq: Option<u64>,
734 /// Ticks servicing softirqs
736 /// (Since Linux 2.6.0)
737 pub softirq: Option<u64>,
738 /// Ticks of stolen time.
740 /// Stolen time is the time spent in other operating systems when running in
741 /// a virtualized environment.
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
748 /// (Since Linux 2.6.24)
749 pub guest: Option<u64>,
750 /// Ticks spent running a niced guest
752 /// (Since Linux 2.6.33)
753 pub guest_nice: Option<u64>,
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;
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()?;
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
800 /// Time spent in user mode
801 pub fn user_duration(&self) -> Duration {
802 Duration::from_millis(self.user_ms())
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
811 /// Time spent in user mode with low priority (nice)
812 pub fn nice_duration(&self) -> Duration {
813 Duration::from_millis(self.nice_ms())
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
822 /// Time spent in system mode
823 pub fn system_duration(&self) -> Duration {
824 Duration::from_millis(self.system_ms())
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
833 /// Time spent in the idle state
834 pub fn idle_duration(&self) -> Duration {
835 Duration::from_millis(self.idle_ms())
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)
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)
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)
855 /// Time spent servicing interrupts
856 pub fn irq_duration(&self) -> Option<Duration> {
857 self.irq_ms().map(Duration::from_millis)
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)
866 /// Time spent servicing softirqs
867 pub fn softirq_duration(&self) -> Option<Duration> {
868 self.softirq_ms().map(Duration::from_millis)
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)
877 /// Amount of stolen time
878 pub fn steal_duration(&self) -> Option<Duration> {
879 self.steal_ms().map(Duration::from_millis)
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)
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)
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)
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)
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
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
917 /// Boot time, in number of seconds since the Epoch
920 /// Number of forks since boot
923 /// Number of processes in runnable state
925 /// (Since Linux 2.5.45)
926 pub procs_running: Option<u32>,
928 /// Number of processes blocked waiting for I/O
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();
941 let mut btime = None;
942 let mut processes = None;
943 let mut procs_running = None;
944 let mut procs_blocked = None;
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));
966 total: expect!(total_cpu),
969 btime: expect!(btime),
970 processes: expect!(processes),
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() {
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);
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
1011 /// The size of the module
1014 /// The number of references in the kernel to this module. This can be -1 if the module is unloading
1017 /// A list of modules that depend on this module.
1018 pub used_by: Vec<String>,
1020 /// The module state
1022 /// This will probably always be "Live", but it could also be either "Unloading" or "Loading"
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());
1048 name: name.to_string(),
1051 used_by: if used_by == "-" {
1056 .filter(|s| !s.is_empty())
1057 .map(|s| s.to_string())
1060 state: state.to_string(),
1065 Ok(KernelModules(map))
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)?;
1081 .filter_map(|s| if !s.is_empty() { Some(s.to_string()) } else { None })
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);
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();
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);
1140 fn test_from_str() -> ProcResult<()> {
1141 assert_eq!(from_str!(u8, "12"), 12);
1142 assert_eq!(from_str!(u8, "A", 16), 10);
1147 fn test_from_str_fail() {
1148 fn inner() -> ProcResult<()> {
1154 assert!(inner().is_err())
1159 fn _inner() -> ProcResult<bool> {
1160 let x: Option<bool> = None;
1161 let y: bool = expect!(x);
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"));
1175 println!("{:?}", r);
1176 assert!(r.is_err());
1179 #[cfg(feature = "backtrace")]
1181 fn test_backtrace() {
1182 fn _inner() -> ProcResult<bool> {
1183 let _f: std::fs::File = expect!(std::fs::File::open("/doesnotexist"));
1188 println!("{:?}", r);