mirror of
https://github.com/uutils/procps.git
synced 2026-06-10 16:14:00 -07:00
pgrep: Support -w option
Unlike pidof's similar option, the pgrep version will run the match predicates against every thread of the system and printing matching tids (unlike pidof which will run match predicates on every process of the system and then list every thread of every matched process).
This commit is contained in:
@@ -28,7 +28,8 @@ const USAGE: &str = help_usage!("pgrep.md");
|
||||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let matches = uu_app().try_get_matches_from(args)?;
|
||||
let settings = process_matcher::get_match_settings(&matches)?;
|
||||
let mut settings = process_matcher::get_match_settings(&matches)?;
|
||||
settings.threads = matches.get_flag("lightweight");
|
||||
|
||||
// Collect pids
|
||||
let pids = process_matcher::find_matching_pids(&settings);
|
||||
@@ -82,7 +83,7 @@ pub fn uu_app() -> Command {
|
||||
.hide_default_value(true),
|
||||
arg!(-l --"list-name" "list PID and process name"),
|
||||
arg!(-a --"list-full" "list PID and full command line"),
|
||||
// arg!(-w --lightweight "list all TID"),
|
||||
arg!(-w --lightweight "list all TID"),
|
||||
])
|
||||
.args(process_matcher::clap_args(
|
||||
"Name of the program to find the PID of",
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use regex::Regex;
|
||||
use std::hash::Hash;
|
||||
use std::sync::LazyLock;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::{self, Display, Formatter},
|
||||
@@ -460,6 +462,22 @@ pub fn walk_process() -> impl Iterator<Item = ProcessInformation> {
|
||||
.flat_map(ProcessInformation::try_from)
|
||||
}
|
||||
|
||||
static THREAD_REGEX: LazyLock<Regex> = LazyLock::new(|| {
|
||||
Regex::new(r"^/proc/[0-9]+$|^/proc/[0-9]+/task$|^/proc/[0-9]+/task/[0-9]+$").unwrap()
|
||||
});
|
||||
|
||||
pub fn walk_threads() -> impl Iterator<Item = ProcessInformation> {
|
||||
WalkDir::new("/proc/")
|
||||
.min_depth(1)
|
||||
.max_depth(3)
|
||||
.follow_links(false)
|
||||
.into_iter()
|
||||
.filter_entry(|e| THREAD_REGEX.is_match(e.path().as_os_str().to_string_lossy().as_ref()))
|
||||
.flatten()
|
||||
.filter(|it| it.path().as_os_str().to_string_lossy().contains("/task/"))
|
||||
.flat_map(ProcessInformation::try_from)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -21,7 +21,7 @@ use uucore::{
|
||||
|
||||
use uucore::error::{UResult, USimpleError};
|
||||
|
||||
use crate::process::{walk_process, ProcessInformation, Teletype};
|
||||
use crate::process::{walk_process, walk_threads, ProcessInformation, Teletype};
|
||||
|
||||
pub struct Settings {
|
||||
pub regex: Regex,
|
||||
@@ -44,6 +44,7 @@ pub struct Settings {
|
||||
pub gid: Option<HashSet<u32>>,
|
||||
pub pgroup: Option<HashSet<u64>>,
|
||||
pub session: Option<HashSet<u64>>,
|
||||
pub threads: bool,
|
||||
}
|
||||
|
||||
pub fn get_match_settings(matches: &ArgMatches) -> UResult<Settings> {
|
||||
@@ -100,6 +101,7 @@ pub fn get_match_settings(matches: &ArgMatches) -> UResult<Settings> {
|
||||
})
|
||||
.collect()
|
||||
}),
|
||||
threads: false,
|
||||
};
|
||||
|
||||
if !settings.newest
|
||||
@@ -194,8 +196,14 @@ fn collect_matched_pids(settings: &Settings) -> Vec<ProcessInformation> {
|
||||
let filtered: Vec<ProcessInformation> = {
|
||||
let mut tmp_vec = Vec::new();
|
||||
|
||||
let pids = if settings.threads {
|
||||
walk_threads().collect::<Vec<_>>()
|
||||
} else {
|
||||
walk_process().collect::<Vec<_>>()
|
||||
};
|
||||
let our_pid = std::process::id() as usize;
|
||||
for mut pid in walk_process().collect::<Vec<_>>() {
|
||||
|
||||
for mut pid in pids {
|
||||
if pid.pid == our_pid {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -478,3 +478,21 @@ fn test_session() {
|
||||
fn test_nonexisting_session() {
|
||||
new_ucmd!().arg("--session=9999999999").fails();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_threads() {
|
||||
std::thread::Builder::new()
|
||||
.name("PgrepTest".to_owned())
|
||||
.spawn(|| {
|
||||
let thread_tid = unsafe { uucore::libc::gettid() };
|
||||
new_ucmd!()
|
||||
.arg("-w")
|
||||
.arg("PgrepTest")
|
||||
.succeeds()
|
||||
.stdout_contains(thread_tid.to_string());
|
||||
})
|
||||
.unwrap()
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user