procfs_core/process/
stat.rs

1use super::ProcState;
2use super::StatFlags;
3use crate::{from_iter, from_iter_optional, ProcResult};
4#[cfg(feature = "serde1")]
5use serde::{Deserialize, Serialize};
6
7use std::io::Read;
8use std::str::FromStr;
9
10/// Status information about the process, based on the `/proc/<pid>/stat` file.
11///
12/// Not all fields are available in every kernel.  These fields have `Option<T>` types.
13///
14/// New fields to this struct may be added at any time (even without a major or minor semver bump).
15#[derive(Debug, Clone)]
16#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
17#[non_exhaustive]
18pub struct Stat {
19    /// The process ID.
20    pub pid: i32,
21    /// The filename of the executable, without the parentheses.
22    ///
23    /// This is visible whether or not the executable is swapped out.
24    ///
25    /// Note that if the actual comm field contains invalid UTF-8 characters, they will be replaced
26    /// here by the U+FFFD replacement character.
27    pub comm: String,
28    /// Process State.
29    ///
30    /// See [state()](#method.state) to get the process state as an enum.
31    pub state: char,
32    /// The PID of the parent of this process.
33    pub ppid: i32,
34    /// The process group ID of the process.
35    pub pgrp: i32,
36    /// The session ID of the process.
37    pub session: i32,
38    /// The controlling terminal of the process.
39    ///
40    /// The minor device number is contained in the combination of bits 31 to 20 and  7  to  0;
41    /// the major device number is in bits 15 to 8.
42    ///
43    /// See [tty_nr()](#method.tty_nr) to get this value decoded into a (major, minor) tuple
44    pub tty_nr: i32,
45    /// The ID of the foreground process group of the controlling terminal of the process.
46    pub tpgid: i32,
47    /// The kernel flags  word of the process.
48    ///
49    /// For bit meanings, see the PF_* defines in  the  Linux  kernel  source  file
50    /// [`include/linux/sched.h`](https://github.com/torvalds/linux/blob/master/include/linux/sched.h).
51    ///
52    /// See [flags()](#method.flags) to get a [`StatFlags`](struct.StatFlags.html) bitfield object.
53    pub flags: u32,
54    /// The number of minor faults the process has made which have not required loading a memory
55    /// page from disk.
56    pub minflt: u64,
57    /// The number of minor faults that the process's waited-for children have made.
58    pub cminflt: u64,
59    /// The number of major faults the process has made which have required loading a memory page
60    /// from disk.
61    pub majflt: u64,
62    /// The number of major faults that the process's waited-for children have made.
63    pub cmajflt: u64,
64    /// Amount of time that this process has been scheduled in user mode, measured in clock ticks
65    /// (divide by `ticks_per_second()`).
66    ///
67    /// This includes guest time, guest_time (time spent running a virtual CPU, see below), so that
68    /// applications that are not aware of the guest time field  do not lose that time from their
69    /// calculations.
70    pub utime: u64,
71    /// Amount of time that this process has been scheduled in kernel mode, measured in clock ticks
72    /// (divide by `ticks_per_second()`).
73    pub stime: u64,
74
75    /// Amount  of  time  that  this  process's  waited-for  children  have  been  scheduled  in
76    /// user  mode,  measured  in clock ticks (divide by `ticks_per_second()`).
77    ///
78    /// This includes guest time, cguest_time (time spent running a virtual CPU, see below).
79    pub cutime: i64,
80
81    /// Amount of time that this process's waited-for  children  have  been  scheduled  in  kernel
82    /// mode,  measured  in  clock  ticks  (divide  by `ticks_per_second()`).
83    pub cstime: i64,
84    /// For processes running a real-time scheduling policy (policy below; see sched_setscheduler(2)),
85    /// this is the negated scheduling priority, minus one;
86    ///
87    /// That is, a number in the range -2 to -100,
88    /// corresponding to real-time priority 1 to 99.  For processes running under a non-real-time
89    /// scheduling policy, this is the raw nice value (setpriority(2)) as represented in the kernel.
90    /// The kernel stores nice values as numbers in the range 0 (high) to 39  (low),  corresponding
91    /// to the user-visible nice range of -20 to 19.
92    /// (This explanation is for Linux 2.6)
93    ///
94    /// Before Linux 2.6, this was a scaled value based on the scheduler weighting given to this process.
95    pub priority: i64,
96    /// The nice value (see `setpriority(2)`), a value in the range 19 (low priority) to -20 (high priority).
97    pub nice: i64,
98    /// Number  of  threads in this process (since Linux 2.6).  Before kernel 2.6, this field was
99    /// hard coded to 0 as a placeholder for an earlier removed field.
100    pub num_threads: i64,
101    /// The time in jiffies before the next SIGALRM is sent to the process due to an interval
102    /// timer.
103    ///
104    /// Since kernel 2.6.17, this  field is no longer maintained, and is hard coded as 0.
105    pub itrealvalue: i64,
106    /// The time the process started after system boot.
107    ///
108    /// In kernels before Linux 2.6, this value was expressed in  jiffies.  Since  Linux 2.6, the
109    /// value is expressed in clock ticks (divide by `sysconf(_SC_CLK_TCK)`).
110    ///
111    #[cfg_attr(
112        feature = "chrono",
113        doc = "See also the [Stat::starttime()] method to get the starttime as a `DateTime` object"
114    )]
115    #[cfg_attr(
116        not(feature = "chrono"),
117        doc = "If you compile with the optional `chrono` feature, you can use the `starttime()` method to get the starttime as a `DateTime` object"
118    )]
119    pub starttime: u64,
120    /// Virtual memory size in bytes.
121    pub vsize: u64,
122    /// Resident Set Size: number of pages the process has in real memory.
123    ///
124    /// This is just the pages which count toward text,  data,  or stack space.
125    /// This does not include pages which have not been demand-loaded in, or which are swapped out.
126    pub rss: u64,
127    /// Current soft limit in bytes on the rss of the process; see the description of RLIMIT_RSS in
128    /// getrlimit(2).
129    pub rsslim: u64,
130    /// The address above which program text can run.
131    pub startcode: u64,
132    /// The address below which program text can run.
133    pub endcode: u64,
134    /// The address of the start (i.e., bottom) of the stack.
135    pub startstack: u64,
136    /// The current value of ESP (stack pointer), as found in the kernel stack page for the
137    /// process.
138    pub kstkesp: u64,
139    /// The current EIP (instruction pointer).
140    pub kstkeip: u64,
141    /// The  bitmap of pending signals, displayed as a decimal number.  Obsolete, because it does
142    /// not provide information on real-time signals; use `/proc/<pid>/status` instead.
143    pub signal: u64,
144    /// The bitmap of blocked signals, displayed as a decimal number.  Obsolete, because it does
145    /// not provide information on  real-time signals; use `/proc/<pid>/status` instead.
146    pub blocked: u64,
147    /// The  bitmap of ignored signals, displayed as a decimal number.  Obsolete, because it does
148    /// not provide information on real-time signals; use `/proc/<pid>/status` instead.
149    pub sigignore: u64,
150    /// The bitmap of caught signals, displayed as a decimal number.  Obsolete, because it does not
151    /// provide information  on  real-time signals; use `/proc/<pid>/status` instead.
152    pub sigcatch: u64,
153    /// This  is  the  "channel"  in which the process is waiting.  It is the address of a location
154    /// in the kernel where the process is sleeping.  The corresponding symbolic name can be found in
155    /// `/proc/<pid>/wchan`.
156    pub wchan: u64,
157    /// Number of pages swapped **(not maintained)**.
158    pub nswap: u64,
159    /// Cumulative nswap for child processes **(not maintained)**.
160    pub cnswap: u64,
161    /// Signal to be sent to parent when we die.
162    ///
163    /// (since Linux 2.1.22)
164    pub exit_signal: Option<i32>,
165    /// CPU number last executed on.
166    ///
167    /// (since Linux 2.2.8)
168    pub processor: Option<i32>,
169    /// Real-time scheduling priority
170    ///
171    ///  Real-time scheduling priority, a number in the range 1 to 99 for processes scheduled under a real-time policy, or 0, for non-real-time processes
172    ///
173    /// (since Linux 2.5.19)
174    pub rt_priority: Option<u32>,
175    /// Scheduling policy (see sched_setscheduler(2)).
176    ///
177    /// Decode using the `SCHED_*` constants in `linux/sched.h`.
178    ///
179    /// (since Linux 2.5.19)
180    pub policy: Option<u32>,
181    /// Aggregated block I/O delays, measured in clock ticks (centiseconds).
182    ///
183    /// (since Linux 2.6.18)
184    pub delayacct_blkio_ticks: Option<u64>,
185    /// Guest time of the process (time spent running a virtual CPU for a guest operating system),
186    /// measured in clock ticks (divide by `ticks_per_second()`)
187    ///
188    /// (since Linux 2.6.24)
189    pub guest_time: Option<u64>,
190    /// Guest time of the process's children, measured in clock ticks (divide by
191    /// `ticks_per_second()`).
192    ///
193    /// (since Linux 2.6.24)
194    pub cguest_time: Option<i64>,
195    /// Address above which program initialized and uninitialized (BSS) data are placed.
196    ///
197    /// (since Linux 3.3)
198    pub start_data: Option<u64>,
199    /// Address below which program initialized and uninitialized (BSS) data are placed.
200    ///
201    /// (since Linux 3.3)
202    pub end_data: Option<u64>,
203    /// Address above which program heap can be expanded with brk(2).
204    ///
205    /// (since Linux 3.3)
206    pub start_brk: Option<u64>,
207    /// Address above which program command-line arguments (argv) are placed.
208    ///
209    /// (since Linux 3.5)
210    pub arg_start: Option<u64>,
211    /// Address below program command-line arguments (argv) are placed.
212    ///
213    /// (since Linux 3.5)
214    pub arg_end: Option<u64>,
215    /// Address above which program environment is placed.
216    ///
217    /// (since Linux 3.5)
218    pub env_start: Option<u64>,
219    /// Address below which program environment is placed.
220    ///
221    /// (since Linux 3.5)
222    pub env_end: Option<u64>,
223    /// The thread's exit status in the form reported by waitpid(2).
224    ///
225    /// (since Linux 3.5)
226    pub exit_code: Option<i32>,
227}
228
229impl crate::FromRead for Stat {
230    #[allow(clippy::cognitive_complexity)]
231    fn from_read<R: Read>(mut r: R) -> ProcResult<Self> {
232        // read in entire thing, this is only going to be 1 line
233        let mut buf = Vec::with_capacity(512);
234        r.read_to_end(&mut buf)?;
235
236        let line = String::from_utf8_lossy(&buf);
237        let buf = line.trim();
238
239        // find the first opening paren, and split off the first part (pid)
240        let start_paren = expect!(buf.find('('));
241        let end_paren = expect!(buf.rfind(')'));
242        let pid_s = &buf[..start_paren - 1];
243        let comm = buf[start_paren + 1..end_paren].to_string();
244        let rest = &buf[end_paren + 2..];
245
246        let pid = expect!(FromStr::from_str(pid_s));
247
248        let mut rest = rest.split(' ');
249        let state = expect!(expect!(rest.next()).chars().next());
250
251        let ppid = expect!(from_iter(&mut rest));
252        let pgrp = expect!(from_iter(&mut rest));
253        let session = expect!(from_iter(&mut rest));
254        let tty_nr = expect!(from_iter(&mut rest));
255        let tpgid = expect!(from_iter(&mut rest));
256        let flags = expect!(from_iter(&mut rest));
257        let minflt = expect!(from_iter(&mut rest));
258        let cminflt = expect!(from_iter(&mut rest));
259        let majflt = expect!(from_iter(&mut rest));
260        let cmajflt = expect!(from_iter(&mut rest));
261        let utime = expect!(from_iter(&mut rest));
262        let stime = expect!(from_iter(&mut rest));
263        let cutime = expect!(from_iter(&mut rest));
264        let cstime = expect!(from_iter(&mut rest));
265        let priority = expect!(from_iter(&mut rest));
266        let nice = expect!(from_iter(&mut rest));
267        let num_threads = expect!(from_iter(&mut rest));
268        let itrealvalue = expect!(from_iter(&mut rest));
269        let starttime = expect!(from_iter(&mut rest));
270        let vsize = expect!(from_iter(&mut rest));
271        let rss = expect!(from_iter(&mut rest));
272        let rsslim = expect!(from_iter(&mut rest));
273        let startcode = expect!(from_iter(&mut rest));
274        let endcode = expect!(from_iter(&mut rest));
275        let startstack = expect!(from_iter(&mut rest));
276        let kstkesp = expect!(from_iter(&mut rest));
277        let kstkeip = expect!(from_iter(&mut rest));
278        let signal = expect!(from_iter(&mut rest));
279        let blocked = expect!(from_iter(&mut rest));
280        let sigignore = expect!(from_iter(&mut rest));
281        let sigcatch = expect!(from_iter(&mut rest));
282        let wchan = expect!(from_iter(&mut rest));
283        let nswap = expect!(from_iter(&mut rest));
284        let cnswap = expect!(from_iter(&mut rest));
285
286        // Since 2.1.22
287        let exit_signal = expect!(from_iter_optional(&mut rest));
288        // Since 2.2.8
289        let processor = expect!(from_iter_optional(&mut rest));
290        // Since 2.5.19
291        let rt_priority = expect!(from_iter_optional(&mut rest));
292        let policy = expect!(from_iter_optional(&mut rest));
293        // Since 2.6.18
294        let delayacct_blkio_ticks = expect!(from_iter_optional(&mut rest));
295        // Since 2.6.24
296        let guest_time = expect!(from_iter_optional(&mut rest));
297        let cguest_time = expect!(from_iter_optional(&mut rest));
298        // Since 3.3.0
299        let start_data = expect!(from_iter_optional(&mut rest));
300        let end_data = expect!(from_iter_optional(&mut rest));
301        let start_brk = expect!(from_iter_optional(&mut rest));
302        // Since 3.5.0
303        let arg_start = expect!(from_iter_optional(&mut rest));
304        let arg_end = expect!(from_iter_optional(&mut rest));
305        let env_start = expect!(from_iter_optional(&mut rest));
306        let env_end = expect!(from_iter_optional(&mut rest));
307        let exit_code = expect!(from_iter_optional(&mut rest));
308
309        Ok(Stat {
310            pid,
311            comm,
312            state,
313            ppid,
314            pgrp,
315            session,
316            tty_nr,
317            tpgid,
318            flags,
319            minflt,
320            cminflt,
321            majflt,
322            cmajflt,
323            utime,
324            stime,
325            cutime,
326            cstime,
327            priority,
328            nice,
329            num_threads,
330            itrealvalue,
331            starttime,
332            vsize,
333            rss,
334            rsslim,
335            startcode,
336            endcode,
337            startstack,
338            kstkesp,
339            kstkeip,
340            signal,
341            blocked,
342            sigignore,
343            sigcatch,
344            wchan,
345            nswap,
346            cnswap,
347            exit_signal,
348            processor,
349            rt_priority,
350            policy,
351            delayacct_blkio_ticks,
352            guest_time,
353            cguest_time,
354            start_data,
355            end_data,
356            start_brk,
357            arg_start,
358            arg_end,
359            env_start,
360            env_end,
361            exit_code,
362        })
363    }
364}
365
366impl Stat {
367    pub fn state(&self) -> ProcResult<ProcState> {
368        ProcState::from_char(self.state)
369            .ok_or_else(|| build_internal_error!(format!("{:?} is not a recognized process state", self.state)))
370    }
371
372    pub fn tty_nr(&self) -> (i32, i32) {
373        // minor is bits 31-20 and 7-0
374        // major is 15-8
375
376        // mmmmmmmmmmmm____MMMMMMMMmmmmmmmm
377        // 11111111111100000000000000000000
378        let major = (self.tty_nr & 0xfff00) >> 8;
379        let minor = (self.tty_nr & 0x000ff) | ((self.tty_nr >> 12) & 0xfff00);
380        (major, minor)
381    }
382
383    /// The kernel flags word of the process, as a bitfield
384    ///
385    /// See also the [Stat::flags](struct.Stat.html#structfield.flags) field.
386    pub fn flags(&self) -> ProcResult<StatFlags> {
387        StatFlags::from_bits(self.flags)
388            .ok_or_else(|| build_internal_error!(format!("Can't construct flags bitfield from {:?}", self.flags)))
389    }
390
391    /// Get the starttime of the process as a `DateTime` object.
392    ///
393    /// See also the [`starttime`](struct.Stat.html#structfield.starttime) field.
394    ///
395    /// This function requires the "chrono" features to be enabled (which it is by default).
396    ///
397    /// Since computing the absolute start time requires knowing the current boot time, this function returns
398    /// a type that needs info about the current machine.
399    ///
400    /// # Example
401    ///
402    /// ```rust,ignore
403    /// use procfs::WithCurrentSystemInfo;
404    ///
405    /// let me = procfs::process::Process::myself().unwrap();
406    /// let stat = me.stat().unwrap();
407    /// let start = stat.starttime().get().unwrap();
408    /// ```
409    #[cfg(feature = "chrono")]
410    pub fn starttime(&self) -> impl crate::WithSystemInfo<Output = ProcResult<chrono::DateTime<chrono::Local>>> {
411        move |si: &crate::SystemInfo| {
412            let seconds_since_boot = self.starttime as f32 / si.ticks_per_second() as f32;
413
414            Ok(si.boot_time()? + chrono::Duration::milliseconds((seconds_since_boot * 1000.0) as i64))
415        }
416    }
417
418    /// Gets the Resident Set Size (in bytes)
419    ///
420    /// The `rss` field will return the same value in pages
421    ///
422    /// # Example
423    ///
424    /// Calculating the rss value in bytes requires knowing the page size, so a `SystemInfo` is needed.
425    /// ```rust,ignore
426    /// use procfs::WithCurrentSystemInfo;
427    ///
428    /// let me = procfs::process::Process::myself().unwrap();
429    /// let stat = me.stat().unwrap();
430    /// let bytes = stat.rss_bytes().get();
431    /// ```
432    pub fn rss_bytes(&self) -> impl crate::WithSystemInfo<Output = u64> {
433        move |si: &crate::SystemInfo| self.rss * si.page_size()
434    }
435}