Skip to content

Commit

Permalink
Merge pull request #144 from cakebaker/pgrep_parent
Browse files Browse the repository at this point in the history
pgrep: implement -P/--parent
  • Loading branch information
Krysztal112233 committed Jul 26, 2024
2 parents 82dc7d2 + 66ede2a commit 7a928bb
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 3 deletions.
24 changes: 22 additions & 2 deletions src/uu/pgrep/src/pgrep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct Settings {
newest: bool,
oldest: bool,
older: Option<u64>,
parent: Option<Vec<u64>>,
runstates: Option<String>,
terminal: Option<HashSet<TerminalType>>,
}
Expand Down Expand Up @@ -60,6 +61,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
inverse: matches.get_flag("inverse"),
newest: matches.get_flag("newest"),
oldest: matches.get_flag("oldest"),
parent: matches
.get_many::<u64>("parent")
.map(|parents| parents.copied().collect()),
runstates: matches.get_one::<String>("runstates").cloned(),
older: matches.get_one::<u64>("older").copied(),
terminal: matches.get_many::<String>("terminal").map(|ttys| {
Expand All @@ -73,6 +77,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
&& !settings.oldest
&& settings.runstates.is_none()
&& settings.older.is_none()
&& settings.parent.is_none()
&& settings.terminal.is_none())
&& pattern.is_empty()
{
Expand Down Expand Up @@ -209,7 +214,20 @@ fn collect_matched_pids(settings: &Settings) -> Vec<ProcessInformation> {
let arg_older = settings.older.unwrap_or(0);
let older_matched = pid.start_time().unwrap() >= arg_older;

if (run_state_matched && pattern_matched && tty_matched && older_matched)
// the PPID is the fourth field in /proc/<PID>/stat
// (https://www.kernel.org/doc/html/latest/filesystems/proc.html#id10)
let stat = pid.stat();
let ppid = stat.get(3);
let parent_matched = match (&settings.parent, ppid) {
(Some(parents), Some(ppid)) => parents.contains(&ppid.parse::<u64>().unwrap()),
_ => true,
};

if (run_state_matched
&& pattern_matched
&& tty_matched
&& older_matched
&& parent_matched)
^ settings.inverse
{
tmp_vec.push(pid)
Expand Down Expand Up @@ -285,7 +303,9 @@ pub fn uu_app() -> Command {
arg!(-o --oldest "select least recently started"),
arg!(-O --older <seconds> "select where older than seconds")
.value_parser(clap::value_parser!(u64)),
// arg!(-P --parent <PPID> "match only child processes of the given parent"),
arg!(-P --parent <PPID> "match only child processes of the given parent")
.value_delimiter(',')
.value_parser(clap::value_parser!(u64)),
// arg!(-s --session <SID> "match session IDs"),
arg!(-t --terminal <tty> "match by controlling terminal")
.value_delimiter(','),
Expand Down
2 changes: 1 addition & 1 deletion src/uu/pgrep/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ impl ProcessInformation {
}

/// Collect information from `/proc/<pid>/stat` file
fn stat(&mut self) -> Rc<Vec<String>> {
pub fn stat(&mut self) -> Rc<Vec<String>> {
if let Some(c) = &self.cached_stat {
return Rc::clone(c);
}
Expand Down
31 changes: 31 additions & 0 deletions tests/by-util/test_pgrep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,3 +304,34 @@ fn test_runstates_invalid_runstate() {
.code_is(1)
.no_output();
}

#[test]
#[cfg(target_os = "linux")]
fn test_parent() {
for arg in ["-P", "--parent"] {
new_ucmd!()
.arg(arg)
.arg("0")
.succeeds()
.stdout_matches(&Regex::new(MULTIPLE_PIDS).unwrap());
}
}

#[test]
#[cfg(target_os = "linux")]
fn test_parent_multiple_parents() {
new_ucmd!()
.arg("--parent=0,1")
.succeeds()
.stdout_matches(&Regex::new(MULTIPLE_PIDS).unwrap());
}

#[test]
#[cfg(target_os = "linux")]
fn test_parent_non_matching_parent() {
new_ucmd!()
.arg("--parent=10000000")
.fails()
.code_is(1)
.no_output();
}

0 comments on commit 7a928bb

Please sign in to comment.