From a083035983bc2966fb9da0cdc34a96e564cdd0d2 Mon Sep 17 00:00:00 2001 From: Jay Hemnani <193022578+jayhemnani9910@users.noreply.github.com> Date: Mon, 26 Oct 2026 01:17:56 +0530 Subject: [PATCH 1/2] pidof: accept %PPID in -o procps-ng pidof takes the special value %PPID for the parent of pidof, so a script can check whether another copy of it is running with 'pidof -o %PPID -x name'. It was rejected as an invalid PID. --- src/uu/pidof/src/pidof.rs | 12 +++++++++++- tests/by-util/test_pidof.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/uu/pidof/src/pidof.rs b/src/uu/pidof/src/pidof.rs index 00069481..e47563ff 100644 --- a/src/uu/pidof/src/pidof.rs +++ b/src/uu/pidof/src/pidof.rs @@ -185,7 +185,7 @@ pub fn uu_app() -> Command { .help("Omit results with a given PID") .value_delimiter(',') .action(ArgAction::Append) - .value_parser(clap::value_parser!(usize)) + .value_parser(parse_omit_pid) .value_name("PID"), ) .arg( @@ -222,3 +222,13 @@ pub fn uu_app() -> Command { .action(ArgAction::SetTrue), ) } + +/// Parse an `-o` value: a PID, or `%PPID` for the parent of pidof (the +/// calling shell or script). +fn parse_omit_pid(value: &str) -> Result { + #[cfg(unix)] + if value == "%PPID" { + return Ok(std::os::unix::process::parent_id() as usize); + } + value.parse::().map_err(|e| e.to_string()) +} diff --git a/tests/by-util/test_pidof.rs b/tests/by-util/test_pidof.rs index 3dc7059d..8570693e 100644 --- a/tests/by-util/test_pidof.rs +++ b/tests/by-util/test_pidof.rs @@ -83,6 +83,35 @@ fn test_omit_pid() { } } +#[test] +#[cfg(target_os = "linux")] +fn test_omit_pid_ppid() { + // pidof runs as a child of this test, so %PPID names this process. + let argv0 = std::env::args().next().unwrap(); + let our_name = std::path::Path::new(argv0.as_str()) + .file_name() + .unwrap() + .to_str() + .unwrap() + .to_owned(); + let our_pid = std::process::id().to_string(); + + new_ucmd!() + .arg(&our_name) + .succeeds() + .stdout_contains(&our_pid); + let result = new_ucmd!().args(&["-o", "%PPID", &our_name]).run(); + result.no_stderr(); + assert!( + !result + .stdout_str() + .split_whitespace() + .any(|pid| pid == our_pid), + "{} contains {our_pid}", + result.stdout_str() + ); +} + #[test] #[cfg(target_os = "linux")] fn test_separator() { From 4f1424e1558a3fa7510b5fb2763dcd0b5b6e75d6 Mon Sep 17 00:00:00 2001 From: Jay Hemnani <193022578+jayhemnani9910@users.noreply.github.com> Date: Tue, 27 Oct 2026 12:28:06 +0530 Subject: [PATCH 2/2] pidof: test %PPID in a list and find the test binary with current_exe --- tests/by-util/test_pidof.rs | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/tests/by-util/test_pidof.rs b/tests/by-util/test_pidof.rs index 8570693e..f48cc0b0 100644 --- a/tests/by-util/test_pidof.rs +++ b/tests/by-util/test_pidof.rs @@ -87,29 +87,26 @@ fn test_omit_pid() { #[cfg(target_os = "linux")] fn test_omit_pid_ppid() { // pidof runs as a child of this test, so %PPID names this process. - let argv0 = std::env::args().next().unwrap(); - let our_name = std::path::Path::new(argv0.as_str()) - .file_name() - .unwrap() - .to_str() - .unwrap() - .to_owned(); + let exe = std::env::current_exe().unwrap(); + let our_name = exe.file_name().unwrap().to_str().unwrap(); let our_pid = std::process::id().to_string(); new_ucmd!() - .arg(&our_name) + .arg(our_name) .succeeds() .stdout_contains(&our_pid); - let result = new_ucmd!().args(&["-o", "%PPID", &our_name]).run(); - result.no_stderr(); - assert!( - !result - .stdout_str() - .split_whitespace() - .any(|pid| pid == our_pid), - "{} contains {our_pid}", - result.stdout_str() - ); + for omit in ["%PPID", "1,%PPID"] { + let result = new_ucmd!().args(&["-o", omit, our_name]).run(); + result.no_stderr(); + assert!( + !result + .stdout_str() + .split_whitespace() + .any(|pid| pid == our_pid), + "-o {omit}: {} contains {our_pid}", + result.stdout_str() + ); + } } #[test]