Merge pull request #373 from dezgeg/pidof-x

pidof: Implement '-x' flag
This commit is contained in:
Daniel Hofstetter
2025-04-02 15:20:48 +02:00
committed by GitHub
2 changed files with 64 additions and 10 deletions
+27 -10
View File
@@ -49,18 +49,33 @@ fn match_process_name(
process: &mut ProcessInformation,
name_to_match: &str,
with_workers: bool,
match_scripts: bool,
) -> bool {
let binding = process.cmdline.split(' ').collect::<Vec<_>>();
let mut path = binding.first().unwrap().to_string();
let path = binding.first().unwrap().to_string();
if path.is_empty() {
if !with_workers {
return false;
}
path.clone_from(&process.status()["Name"]);
return process.name().unwrap() == name_to_match;
};
PathBuf::from(path).file_name().unwrap().to_str().unwrap() == name_to_match
if PathBuf::from(path).file_name().unwrap().to_str().unwrap() == name_to_match {
return true;
}
// When a script (ie. file starting with e.g. #!/bin/sh) is run like `./script.sh`, then
// its cmdline will look like `/bin/sh ./script.sh` but its .name() will be `script.sh`.
// As name() gets truncated to 15 characters, the original pidof seems to always do a prefix match.
if match_scripts && binding.len() > 1 {
return PathBuf::from(binding[1])
.file_name()
.map(|f| f.to_str().unwrap())
.is_some_and(|f| f == name_to_match && f.starts_with(&process.name().unwrap()));
}
false
}
fn collect_matched_pids(matches: &ArgMatches) -> Vec<usize> {
@@ -70,6 +85,7 @@ fn collect_matched_pids(matches: &ArgMatches) -> Vec<usize> {
.cloned()
.collect();
let with_workers = matches.get_flag("with-workers");
let match_scripts = matches.get_flag("x");
let collected = walk_process().collect::<Vec<_>>();
let arg_omit_pid = matches
@@ -83,7 +99,8 @@ fn collect_matched_pids(matches: &ArgMatches) -> Vec<usize> {
.flat_map(|program| {
let mut processed = Vec::new();
for mut process in collected.clone() {
let contains = match_process_name(&mut process, &program, with_workers);
let contains =
match_process_name(&mut process, &program, with_workers, match_scripts);
let should_omit = arg_omit_pid.contains(&process.pid);
if contains && !should_omit {
@@ -184,10 +201,10 @@ pub fn uu_app() -> Command {
.help("Show kernel worker threads as well")
.action(ArgAction::SetTrue),
)
// .arg(
// Arg::new("x")
// .short('x')
// .help("Return PIDs of shells running scripts with a matching name")
// .action(ArgAction::SetTrue),
// )
.arg(
Arg::new("x")
.short('x')
.help("Return PIDs of shells running scripts with a matching name")
.action(ArgAction::SetTrue),
)
}
+37
View File
@@ -111,3 +111,40 @@ fn test_threads() {
.join()
.unwrap();
}
#[test]
#[cfg(target_os = "linux")]
fn test_script() {
use std::os::unix::fs::PermissionsExt;
let temp_dir = tempfile::tempdir().unwrap();
let script_path = temp_dir
.path()
.join("dummy_test_script_with_very_long_name");
std::fs::write(&script_path, "#!/bin/sh\nsleep 2").unwrap();
std::fs::set_permissions(&script_path, std::fs::Permissions::from_mode(0o755)).unwrap();
let mut directly_executed_child = std::process::Command::new(&script_path).spawn().unwrap();
new_ucmd!()
.arg("dummy_test_script_with_very_long_name")
.fails();
new_ucmd!()
.args(&["-x", "dummy_test_script_with_very_long_name"])
.succeeds()
.stdout_contains(directly_executed_child.id().to_string());
directly_executed_child.kill().unwrap();
directly_executed_child.wait().unwrap();
let mut executed_via_sh_child = std::process::Command::new("/bin/sh")
.arg(&script_path)
.spawn()
.unwrap();
new_ucmd!()
.arg("dummy_test_script_with_very_long_name")
.fails();
new_ucmd!()
.args(&["-x", "dummy_test_script_with_very_long_name"])
.fails();
executed_via_sh_child.kill().unwrap();
executed_via_sh_child.wait().unwrap();
}