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..f48cc0b0 100644 --- a/tests/by-util/test_pidof.rs +++ b/tests/by-util/test_pidof.rs @@ -83,6 +83,32 @@ 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 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) + .succeeds() + .stdout_contains(&our_pid); + 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] #[cfg(target_os = "linux")] fn test_separator() {