diff --git a/src/system/mod.rs b/src/system/mod.rs index f838b93da..ff7cabcd5 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -600,7 +600,7 @@ impl Process { /// attached to the given process pub fn tty_device_id(pid: WithProcess) -> std::io::Result> { // device id of tty is displayed as a signed integer of 32 bits - let data: i32 = read_proc_stat(pid, 7 /* tty_nr */)?; + let data: i32 = read_proc_stat(pid, 6 /* tty_nr */)?; if data == 0 { Ok(None) } else { @@ -615,7 +615,7 @@ impl Process { /// Get the process starting time of a specific process pub fn starting_time(pid: WithProcess) -> io::Result { - let process_start: u64 = read_proc_stat(pid, 22 /* start_time */)?; + let process_start: u64 = read_proc_stat(pid, 21 /* start_time */)?; // the startime field is stored in ticks since the system start, so we need to know how many // ticks go into a second @@ -634,13 +634,19 @@ impl Process { } } -/// Read the n-th field (with 1-based indexing) from `/proc//self`. +/// Read the n-th field (with 0-based indexing) from `/proc//self`. /// /// See ["Table 1-4: Contents of the stat fields" of "The /proc /// Filesystem"][proc_stat_fields] in the Linux docs for all available fields. /// +/// IMPORTANT: the first two fields are not accessible with this routine. +/// /// [proc_stat_fields]: https://www.kernel.org/doc/html/latest/filesystems/proc.html#id10 fn read_proc_stat(pid: WithProcess, field_idx: isize) -> io::Result { + // the first two fields are skipped by the code below, and we never need them, + // so no point in implementing code for it in this private function. + debug_assert!(field_idx >= 2); + // read from a specific pid file, or use `self` to refer to our own process let pidref = pid.to_proc_string(); @@ -661,7 +667,7 @@ fn read_proc_stat(pid: WithProcess, field_idx: isize) -> io::Result< // we've now passed the first two fields, so we are at index 1, now we skip over // fields until we arrive at the field we are searching for let mut curr_field = 1; - while curr_field <= field_idx && !stat.is_empty() { + while curr_field < field_idx && !stat.is_empty() { if stat[0] == b' ' { curr_field += 1; } @@ -960,4 +966,17 @@ mod tests { let (_, status) = child_pid.wait(WaitOptions::new()).unwrap(); assert_eq!(status.exit_status(), Some(0)); } + + #[cfg(target_os = "linux")] + #[test] + fn proc_stat_test() { + use super::{read_proc_stat, Process, WithProcess::Current}; + // the process is 'sleeping' (apparently) + assert_eq!("S", read_proc_stat::(Current, 2).unwrap()); + let parent = Process::parent_id().unwrap(); + // field 3 is always the parent process + assert_eq!(parent, read_proc_stat::(Current, 3).unwrap()); + // this next field should always be 0 (which precedes an important bit of info for us!) + assert_eq!(0, read_proc_stat::(Current, 20).unwrap()); + } }