Skip to content

Commit e427ebd

Browse files
authored
Merge pull request #422 from dezgeg/ignore-ancestors
pgrep/pkill/pidwait: Implement --ignore-ancestors
2 parents d53660d + 725ed3e commit e427ebd

File tree

2 files changed

+36
-3
lines changed

2 files changed

+36
-3
lines changed

src/uu/pgrep/src/process_matcher.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ pub struct Settings {
5151

5252
pub pidfile: Option<String>,
5353
pub logpidfile: bool,
54+
pub ignore_ancestors: bool,
5455
}
5556

5657
pub fn get_match_settings(matches: &ArgMatches) -> UResult<Settings> {
@@ -113,6 +114,7 @@ pub fn get_match_settings(matches: &ArgMatches) -> UResult<Settings> {
113114
threads: false,
114115
pidfile: matches.get_one::<String>("pidfile").cloned(),
115116
logpidfile: matches.get_flag("logpidfile"),
117+
ignore_ancestors: matches.get_flag("ignore-ancestors"),
116118
};
117119

118120
if !settings.newest
@@ -196,26 +198,45 @@ fn any_matches<T: Eq + Hash>(optional_ids: &Option<HashSet<T>>, id: T) -> bool {
196198
optional_ids.as_ref().is_none_or(|ids| ids.contains(&id))
197199
}
198200

201+
fn get_ancestors(process_infos: &mut [ProcessInformation], mut pid: usize) -> HashSet<usize> {
202+
let mut ret = HashSet::from([pid]);
203+
while pid != 1 {
204+
if let Some(process) = process_infos.iter_mut().find(|p| p.pid == pid) {
205+
pid = process.ppid().unwrap() as usize;
206+
ret.insert(pid);
207+
} else {
208+
break;
209+
}
210+
}
211+
ret
212+
}
213+
199214
/// Collect pids with filter construct from command line arguments
200215
fn collect_matched_pids(settings: &Settings) -> UResult<Vec<ProcessInformation>> {
201216
// Filtration general parameters
202217
let filtered: Vec<ProcessInformation> = {
203218
let mut tmp_vec = Vec::new();
204219

205-
let pids = if settings.threads {
220+
let mut pids = if settings.threads {
206221
walk_threads().collect::<Vec<_>>()
207222
} else {
208223
walk_process().collect::<Vec<_>>()
209224
};
210225
let our_pid = std::process::id() as usize;
226+
let ignored_pids = if settings.ignore_ancestors {
227+
get_ancestors(&mut pids, our_pid)
228+
} else {
229+
HashSet::from([our_pid])
230+
};
231+
211232
let pid_from_pidfile = settings
212233
.pidfile
213234
.as_ref()
214235
.map(|filename| read_pidfile(filename, settings.logpidfile))
215236
.transpose()?;
216237

217238
for mut pid in pids {
218-
if pid.pid == our_pid {
239+
if ignored_pids.contains(&pid.pid) {
219240
continue;
220241
}
221242

@@ -507,7 +528,7 @@ pub fn clap_args(pattern_help: &'static str, enable_v_flag: bool) -> Vec<Arg> {
507528
arg!(-F --pidfile <file> "read PIDs from file"),
508529
arg!(-L --logpidfile "fail if PID file is not locked"),
509530
arg!(-r --runstates <state> "match runstates [D,S,Z,...]"),
510-
// arg!(-A --"ignore-ancestors" "exclude our ancestors from results"),
531+
arg!(-A --"ignore-ancestors" "exclude our ancestors from results"),
511532
arg!(--cgroup <grp> "match by cgroup v2 names").value_delimiter(','),
512533
// arg!(--ns <PID> "match the processes that belong to the same namespace as <pid>"),
513534
// arg!(--nslist <ns> "list which namespaces will be considered for the --ns option.")

tests/by-util/test_pgrep.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,3 +673,15 @@ fn test_pidfile_fcntl_locked() {
673673
flock_process.kill().unwrap();
674674
flock_process.wait().unwrap();
675675
}
676+
677+
#[test]
678+
#[cfg(target_os = "linux")]
679+
fn test_ignore_ancestors() {
680+
let our_pid = std::process::id();
681+
new_ucmd!()
682+
.arg("--ignore-ancestors")
683+
.arg(".*")
684+
.succeeds()
685+
.stdout_does_not_match(&Regex::new(&format!("(?m)^{our_pid}$")).unwrap())
686+
.stdout_does_not_match(&Regex::new("(?m)^1$").unwrap());
687+
}

0 commit comments

Comments
 (0)