Skip to content

Commit 4e2a13b

Browse files
author
aweinstock
committed
uucore: Support parsing real-time signals.
This allows `timeout -s`, `kill -s`, and `env --{block,default,ignore}-signal` to recognize and handle signals of the forms `RTMIN`, `RTMIN+n`, `RTMAX`, and `RTMAX-n`, consistent with the behaviour of GNU coreutils.
1 parent ff6dd99 commit 4e2a13b

File tree

3 files changed

+82
-3
lines changed

3 files changed

+82
-3
lines changed

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

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,52 @@ pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option<usize> {
400400
}
401401
let signal_name = signal_name_upcase.trim_start_matches("SIG");
402402

403-
ALL_SIGNALS.iter().position(|&s| s == signal_name)
403+
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
404+
return try_parse_sigrt(signal_name_or_value)
405+
.or_else(|| ALL_SIGNALS.iter().position(|&s| s == signal_name));
406+
#[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
407+
return ALL_SIGNALS.iter().position(|&s| s == signal_name);
408+
}
409+
410+
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
411+
/// Parses signals of the form RTMIN(+[0-9]\+)?|RTMAX(-[0-9]\+)?
412+
fn try_parse_sigrt(signal_name: &str) -> Option<usize> {
413+
if crate::os::is_wsl() {
414+
return None;
415+
}
416+
if let Some(rest) = signal_name.strip_prefix("RTMIN") {
417+
if rest.is_empty() {
418+
Some(libc::SIGRTMIN() as usize)
419+
} else if let Some(rest) = rest.strip_prefix("+")
420+
&& let Ok(offset) = rest.parse::<usize>()
421+
{
422+
let value = libc::SIGRTMIN() as usize + offset;
423+
if value <= libc::SIGRTMAX() as usize {
424+
Some(value)
425+
} else {
426+
None
427+
}
428+
} else {
429+
None
430+
}
431+
} else if let Some(rest) = signal_name.strip_prefix("RTMAX") {
432+
if rest.is_empty() {
433+
Some(libc::SIGRTMAX() as usize)
434+
} else if let Some(rest) = rest.strip_prefix("-")
435+
&& let Ok(offset) = rest.parse::<usize>()
436+
{
437+
let value = libc::SIGRTMAX() as usize - offset;
438+
if value >= libc::SIGRTMIN() as usize {
439+
Some(value)
440+
} else {
441+
None
442+
}
443+
} else {
444+
None
445+
}
446+
} else {
447+
None
448+
}
404449
}
405450

406451
/// Returns true if the given number is a valid signal number.

tests/by-util/test_kill.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
5-
// spell-checker:ignore IAMNOTASIGNAL RTMAX RTMIN SIGRTMAX
5+
// spell-checker:ignore IAMNOTASIGNAL RTMAX RTMIN SIGRTMAX SIGRT SIGRTMIN SIGRTMAX
66
use regex::Regex;
77
use std::os::unix::process::ExitStatusExt;
88
use std::process::{Child, Command};
@@ -493,3 +493,18 @@ fn test_kill_signal_only_no_pid() {
493493
.fails()
494494
.stderr_contains("no process ID specified");
495495
}
496+
497+
#[test]
498+
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
499+
fn test_kill_with_signal_sigrt() {
500+
if !uucore::os::is_wsl() {
501+
for signal in &["SIGRTMIN", "SIGRTMIN+1", "SIGRTMAX", "SIGRTMAX-1"] {
502+
let target = Target::new();
503+
new_ucmd!()
504+
.arg("-s")
505+
.arg(signal)
506+
.arg(format!("{}", target.pid()))
507+
.succeeds();
508+
}
509+
}
510+
}

tests/by-util/test_timeout.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
55

6-
// spell-checker:ignore dont
6+
// spell-checker:ignore dont sigrt sigrtmin sigrtmax
77

88
use rstest::rstest;
99
use std::time::Duration;
@@ -286,3 +286,22 @@ 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 = "freebsd"))]
292+
fn test_timeout_sigrt() {
293+
if !uucore::os::is_wsl() {
294+
new_ucmd!()
295+
.args(&["-s", "SIGRTMIN", "0.1", "sleep", "2"])
296+
.succeeds();
297+
new_ucmd!()
298+
.args(&["-s", "SIGRTMIN+1", "0.1", "sleep", "2"])
299+
.succeeds();
300+
new_ucmd!()
301+
.args(&["-s", "SIGRTMAX", "0.1", "sleep", "2"])
302+
.succeeds();
303+
new_ucmd!()
304+
.args(&["-s", "SIGRTMAX-1", "0.1", "sleep", "2"])
305+
.succeeds();
306+
}
307+
}

0 commit comments

Comments
 (0)