Skip to content

Commit 6e18efb

Browse files
kevinburkesegmentclaude
authored andcommitted
uucore: support realtime signals (RTMIN/RTMAX) in signal_by_name_or_value
`signal_by_name_or_value()` only looked up signals from the static ALL_SIGNALS array, which doesn't include realtime signals. This caused `timeout -s RTMAX`, `kill -s RTMIN`, and `env --default-signal=RTMAX` to reject valid signal names. Extend the function to fall back to realtime_signal_bounds() for both name lookups and numeric values in the realtime range, matching the behavior already present in signal_list_value_by_name_or_number(). Also fix timeout's report_if_verbose() to use signal_list_name_by_value instead of signal_name_by_value, so verbose output doesn't panic for realtime signal numbers. Fixes GNU test: tests/env/env-signal-handler.sh Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f6451c7 commit 6e18efb

4 files changed

Lines changed: 55 additions & 4 deletions

File tree

.vscode/cspell.dictionaries/workspace.wordlist.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,13 @@ LINESIZE
185185
NAMESIZE
186186
RTLD_NEXT
187187
RTLD
188+
RTMAX
189+
RTMIN
188190
SIGABRT
189191
SIGINT
190192
SIGKILL
193+
SIGRTMAX
194+
SIGRTMIN
191195
SIGSTOP
192196
SIGTERM
193197
SYS_fdatasync

src/uu/timeout/src/timeout.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use uucore::translate;
2222

2323
use uucore::{
2424
format_usage,
25-
signals::{signal_by_name_or_value, signal_name_by_value},
25+
signals::{signal_by_name_or_value, signal_list_name_by_value},
2626
};
2727

2828
use nix::sys::signal::{SigHandler, Signal, kill};
@@ -227,7 +227,7 @@ fn report_if_verbose(signal: usize, cmd: &str, verbose: bool) {
227227
let s = if signal == 0 {
228228
"0".to_string()
229229
} else {
230-
signal_name_by_value(signal).unwrap().to_string()
230+
signal_list_name_by_value(signal).unwrap()
231231
};
232232
let mut stderr = std::io::stderr();
233233
let _ = writeln!(

src/uucore/src/lib/features/signals.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,11 +396,24 @@ pub static ALL_SIGNALS: [&str; 32] = [
396396
pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option<usize> {
397397
let signal_name_upcase = signal_name_or_value.to_uppercase();
398398
if let Ok(value) = signal_name_upcase.parse() {
399-
return if is_signal(value) { Some(value) } else { None };
399+
if is_signal(value) {
400+
return Some(value);
401+
}
402+
return realtime_signal_bounds()
403+
.filter(|&(rtmin, rtmax)| value >= rtmin && value <= rtmax)
404+
.map(|_| value);
400405
}
401406
let signal_name = signal_name_upcase.trim_start_matches("SIG");
402407

403-
ALL_SIGNALS.iter().position(|&s| s == signal_name)
408+
if let Some(pos) = ALL_SIGNALS.iter().position(|&s| s == signal_name) {
409+
return Some(pos);
410+
}
411+
412+
realtime_signal_bounds().and_then(|(rtmin, rtmax)| match signal_name {
413+
"RTMIN" => Some(rtmin),
414+
"RTMAX" => Some(rtmax),
415+
_ => None,
416+
})
404417
}
405418

406419
/// Returns true if the given number is a valid signal number.
@@ -754,3 +767,19 @@ fn linux_unnamed_signal_numbers_are_valid_for_lists() {
754767
assert_eq!(signal_list_value_by_name_or_number("32"), Some(32));
755768
assert_eq!(signal_list_value_by_name_or_number("33"), Some(33));
756769
}
770+
771+
#[cfg(any(target_os = "linux", target_os = "android"))]
772+
#[test]
773+
fn linux_realtime_signals_resolve_by_name_or_value() {
774+
let (rtmin, rtmax) = realtime_signal_bounds().unwrap();
775+
776+
// By name
777+
assert_eq!(signal_by_name_or_value("RTMIN"), Some(rtmin));
778+
assert_eq!(signal_by_name_or_value("RTMAX"), Some(rtmax));
779+
assert_eq!(signal_by_name_or_value("SIGRTMIN"), Some(rtmin));
780+
assert_eq!(signal_by_name_or_value("SIGRTMAX"), Some(rtmax));
781+
782+
// By numeric value
783+
assert_eq!(signal_by_name_or_value(&rtmin.to_string()), Some(rtmin));
784+
assert_eq!(signal_by_name_or_value(&rtmax.to_string()), Some(rtmax));
785+
}

tests/by-util/test_timeout.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,21 @@ fn test_foreground_signal0_kill_after() {
286286
.args(&["--foreground", "-s0", "-k.1", ".1", "sleep", "10"])
287287
.fails_with_code(137);
288288
}
289+
290+
#[test]
291+
#[cfg(any(target_os = "linux", target_os = "android"))]
292+
fn test_realtime_signal_names() {
293+
// timeout should accept RTMIN and RTMAX as valid signal names
294+
new_ucmd!()
295+
.args(&["-v", "-s", "RTMAX", ".1", "sleep", "1"])
296+
.fails()
297+
.stderr_contains("sending signal RTMAX to command");
298+
new_ucmd!()
299+
.args(&["-v", "-s", "RTMIN", ".1", "sleep", "1"])
300+
.fails()
301+
.stderr_contains("sending signal RTMIN to command");
302+
new_ucmd!()
303+
.args(&["-v", "-s", "SIGRTMAX", ".1", "sleep", "1"])
304+
.fails()
305+
.stderr_contains("sending signal RTMAX to command");
306+
}

0 commit comments

Comments
 (0)