diff --git a/src/uucore/src/lib/features/signals.rs b/src/uucore/src/lib/features/signals.rs index 6b89704fcad..38e7be06037 100644 --- a/src/uucore/src/lib/features/signals.rs +++ b/src/uucore/src/lib/features/signals.rs @@ -400,7 +400,50 @@ pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option { } let signal_name = signal_name_upcase.trim_start_matches("SIG"); - ALL_SIGNALS.iter().position(|&s| s == signal_name) + #[cfg(any(target_os = "linux", target_os = "freebsd"))] + return try_parse_sigrt(signal_name_or_value) + .or_else(|| ALL_SIGNALS.iter().position(|&s| s == signal_name)); + #[cfg(not(any(target_os = "linux", target_os = "freebsd")))] + return ALL_SIGNALS.iter().position(|&s| s == signal_name); +} + +#[cfg(any(target_os = "linux", target_os = "freebsd"))] +/// Parses signals of the form RTMIN(+[0-9]\+)?|RTMAX(-[0-9]\+)? +fn try_parse_sigrt(signal_name: &str) -> Option { + realtime_signal_bounds()?; + if let Some(rest) = signal_name.strip_prefix("RTMIN") { + if rest.is_empty() { + Some(libc::SIGRTMIN() as usize) + } else if let Some(rest) = rest.strip_prefix("+") + && let Ok(offset) = rest.parse::() + { + let value = libc::SIGRTMIN() as usize + offset; + if value <= libc::SIGRTMAX() as usize { + Some(value) + } else { + None + } + } else { + None + } + } else if let Some(rest) = signal_name.strip_prefix("RTMAX") { + if rest.is_empty() { + Some(libc::SIGRTMAX() as usize) + } else if let Some(rest) = rest.strip_prefix("-") + && let Ok(offset) = rest.parse::() + { + let value = libc::SIGRTMAX() as usize - offset; + if value >= libc::SIGRTMIN() as usize { + Some(value) + } else { + None + } + } else { + None + } + } else { + None + } } /// Returns true if the given number is a valid signal number. @@ -414,7 +457,7 @@ pub fn signal_name_by_value(signal_value: usize) -> Option<&'static str> { } #[cfg(any(target_os = "linux", target_os = "android"))] -fn realtime_signal_bounds() -> Option<(usize, usize)> { +pub fn realtime_signal_bounds() -> Option<(usize, usize)> { let rtmin = libc::SIGRTMIN(); let rtmax = libc::SIGRTMAX(); @@ -422,7 +465,7 @@ fn realtime_signal_bounds() -> Option<(usize, usize)> { } #[cfg(not(any(target_os = "linux", target_os = "android")))] -fn realtime_signal_bounds() -> Option<(usize, usize)> { +pub fn realtime_signal_bounds() -> Option<(usize, usize)> { None } diff --git a/tests/by-util/test_kill.rs b/tests/by-util/test_kill.rs index c666db3714d..4aa9f8bcfed 100644 --- a/tests/by-util/test_kill.rs +++ b/tests/by-util/test_kill.rs @@ -2,7 +2,7 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore IAMNOTASIGNAL RTMAX RTMIN SIGRTMAX +// spell-checker:ignore IAMNOTASIGNAL RTMAX RTMIN SIGRTMAX SIGRT SIGRTMIN SIGRTMAX use regex::Regex; use std::os::unix::process::ExitStatusExt; use std::process::{Child, Command}; @@ -493,3 +493,18 @@ fn test_kill_signal_only_no_pid() { .fails() .stderr_contains("no process ID specified"); } + +#[test] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] +fn test_kill_with_signal_sigrt() { + if !uucore::os::is_wsl() && uucore::signals::realtime_signal_bounds().is_some() { + for signal in &["SIGRTMIN", "SIGRTMIN+1", "SIGRTMAX", "SIGRTMAX-1"] { + let target = Target::new(); + new_ucmd!() + .arg("-s") + .arg(signal) + .arg(format!("{}", target.pid())) + .succeeds(); + } + } +} diff --git a/tests/by-util/test_timeout.rs b/tests/by-util/test_timeout.rs index 4bbc532e9cc..4668a289feb 100644 --- a/tests/by-util/test_timeout.rs +++ b/tests/by-util/test_timeout.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore dont +// spell-checker:ignore dont sigrt sigrtmin sigrtmax use rstest::rstest; use std::time::Duration; @@ -286,3 +286,22 @@ fn test_foreground_signal0_kill_after() { .args(&["--foreground", "-s0", "-k.1", ".1", "sleep", "10"]) .fails_with_code(137); } + +#[test] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] +fn test_timeout_sigrt() { + if !uucore::os::is_wsl() && uucore::signals::realtime_signal_bounds().is_some() { + new_ucmd!() + .args(&["-s", "SIGRTMIN", "0.1", "sleep", "2"]) + .succeeds(); + new_ucmd!() + .args(&["-s", "SIGRTMIN+1", "0.1", "sleep", "2"]) + .succeeds(); + new_ucmd!() + .args(&["-s", "SIGRTMAX", "0.1", "sleep", "2"]) + .succeeds(); + new_ucmd!() + .args(&["-s", "SIGRTMAX-1", "0.1", "sleep", "2"]) + .succeeds(); + } +}