diff --git a/src/uu/pkill/src/pkill.rs b/src/uu/pkill/src/pkill.rs index d4c96a75..8659433b 100644 --- a/src/uu/pkill/src/pkill.rs +++ b/src/uu/pkill/src/pkill.rs @@ -4,7 +4,7 @@ // file that was distributed with this source code. // Pid utils -use clap::{arg, crate_version, Command}; +use clap::{arg, crate_version, value_parser, Command}; #[cfg(unix)] use nix::{ sys::signal::{self, Signal}, @@ -48,7 +48,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } else { let sig = (settings.signal as i32) .try_into() - .map_err(|e| std::io::Error::from_raw_os_error(e as i32))?; + .map_err(|e| Error::from_raw_os_error(e as i32))?; Some(sig) }; @@ -56,11 +56,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let pids = process_matcher::find_matching_pids(&settings)?; // Send signal - // TODO: Implement -q #[cfg(unix)] - let echo = matches.get_flag("echo"); - #[cfg(unix)] - kill(&pids, sig, echo); + { + let echo = matches.get_flag("echo"); + let queue = matches.get_one::("queue").cloned(); + + kill(&pids, sig, queue, echo); + } if matches.get_flag("count") { println!("{}", pids.len()); @@ -71,25 +73,50 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { #[cfg(unix)] fn handle_obsolete(args: &mut [String]) { - // Sanity check - if args.len() > 2 { - // Old signal can only be in the first argument position - let slice = args[1].as_str(); - if let Some(signal) = slice.strip_prefix('-') { + for arg in &mut args[1..] { + if let Some(signal) = arg.strip_prefix('-') { // Check if it is a valid signal let opt_signal = signal_by_name_or_value(signal); if opt_signal.is_some() { // Replace with long option that clap can parse - args[1] = format!("--signal={signal}"); + *arg = format!("--signal={signal}"); } } } } +// Not contains in libc +#[cfg(target_os = "linux")] +extern "C" { + fn sigqueue( + pid: uucore::libc::pid_t, + sig: uucore::libc::c_int, + val: uucore::libc::sigval, + ) -> uucore::libc::c_int; +} + #[cfg(unix)] -fn kill(pids: &Vec, sig: Option, echo: bool) { +#[allow(unused_variables)] +fn kill(pids: &Vec, sig: Option, queue: Option, echo: bool) { for pid in pids { - if let Err(e) = signal::kill(Pid::from_raw(pid.pid as i32), sig) { + #[cfg(target_os = "linux")] + let result = if let Some(queue) = queue { + let v = unsafe { + sigqueue( + pid.pid as i32, + sig.map_or(0, |s| s as uucore::libc::c_int), + uucore::libc::sigval { + sival_ptr: queue as usize as *mut uucore::libc::c_void, + }, + ) + }; + nix::errno::Errno::result(v).map(drop) + } else { + signal::kill(Pid::from_raw(pid.pid as i32), sig) + }; + #[cfg(not(target_os = "linux"))] + let result = signal::kill(Pid::from_raw(pid.pid as i32), sig); + if let Err(e) = result { show!(Error::from_raw_os_error(e as i32) .map_err_context(|| format!("killing pid {} failed", pid.pid))); } else if echo { @@ -111,7 +138,8 @@ pub fn uu_app() -> Command { .args_override_self(true) .args([ // arg!(- "signal to send (either number or name)"), - // arg!(-q --queue "integer value to be sent with the signal"), + arg!(-q --queue "integer value to be sent with the signal") + .value_parser(value_parser!(u32)), arg!(-e --echo "display what is killed"), ]) .args(process_matcher::clap_args( diff --git a/tests/by-util/test_pkill.rs b/tests/by-util/test_pkill.rs index 4828e907..54a4c178 100644 --- a/tests/by-util/test_pkill.rs +++ b/tests/by-util/test_pkill.rs @@ -74,3 +74,9 @@ fn test_too_long_pattern() { .code_is(1) .stderr_contains("pattern that searches for process name longer than 15 characters will result in zero matches"); } + +#[test] +#[cfg(target_os = "linux")] +fn test_invalid_queue() { + new_ucmd!().args(&["-q"]).fails().code_is(1); +}