View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0001954 | 1003.1(2024)/Issue8 | Shell and Utilities | public | 2025-11-07 20:40 | 2025-11-12 10:35 |
| Reporter | stephane | Assigned To | |||
| Priority | normal | Severity | Objection | Type | Enhancement Request |
| Status | New | Resolution | Open | ||
| Name | Stephane Chazelas | ||||
| Organization | |||||
| User Reference | |||||
| Section | trap utility | ||||
| Page Number | 2565 | ||||
| Line Number | 83714-83716 | ||||
| Interp Status | |||||
| Final Accepted Text | |||||
| Summary | 0001954: please allow shells to unignore signals | ||||
| Description | The specification of the trap utility has: <<< Signals that were ignored on entry to a non-interactive shell cannot be trapped or reset, although no error need be reported when attempting to do so. An interactive shell may reset or catch signals ignored on entry. >>> In this day and age, that requirement is unhelpful and annoying. That means one has to resort to things like perl or shells that ignore that requirement to work around it. For example, to make sure SIGPIPE is not ignored: #! /bin/sh -
if [ -n "$RESTORED_SIGPIPE" ]; then
unset -v RESTORED_SIGPIPE
else
RESTORED_SIGPIPE=1 exec perl -e '$SIG{PIPE} = "DEFAULT"; exec @ARGV' -- "$0" "$@"
fiI guess POSIX introduced that requirement because that's what the Bourne shell or ksh88 did back then, and they likely did it because they were written before BSD job control was invented in the 80s, so handling of "background" jobs was done by ignoring SIGINT/SIGQUIT, and restoring their disposition in those jobs would defeat that. Nowadays, we should no longer need that. In any case, even back then that requirement would not make sense in an interactive shell which likely explains why POSIX doesn't mandate it there. So unless there's another good reason that still holds today (but I doubt so, zsh has been ignoring that for 35 years and I don't think anyone ever complained), I'd suggest dropping it. That comes back regularly in usenet or stackexchange discussions, with one of the work arounds being to switch shell to zsh. | ||||
| Desired Action | Change that paragraph to something like: <<< Requests to change the disposition of signals that were ignored on entry of the shell may be silently ignored by the trap utility. Traps shall remain in place for a given shell until explicitly changed with another trap command. >>> And maybe add a rationale section with historical information as to why some shells may still be doing it. | ||||
| Tags | No tags attached. | ||||
|
|
Sorry, I removed the "Traps shall remain in place for a given shell until explicitly changed with another trap command" part from the quoting text as it was not relevant to this issue but forgot to remove it from the proposed resolution. It should just be: <<< Requests to change the disposition of signals that were ignored on entry of the shell may be silently ignored by the trap utility. >>> Note it's related to and extends 0000751. The behaviour Geoff objected to there in historical shell implementations was likely there for the same reason they refused un-ignoring signals ignored on startup. |
|
|
For the record, I have spent a few hours looking for a rationale for that requirement. The only thing I found was that it was what the Bourne shell did (and the Korn shell inherited it). ChatGPT made a somewhat compelling argument: <<< 1. Fundamental Principle: Child Should Respect Parent’s Signal Policy The main rationale comes from the long-standing UNIX convention that a process must not silently override its inherited signal dispositions unless there’s a compelling reason. When a process is launched, the parent’s signal dispositions reflect deliberate decisions about how that process and its descendants should behave in response to asynchronous events (interrupts, termination requests, etc.). For instance: A parent program that sets SIGINT (Ctrl-C) to SIG_IGN is saying “don’t let Ctrl-C interrupt me or anything I spawn.” A system daemon, or a pipeline component, might ignore SIGPIPE to prevent cascaded terminations. If a shell script could re-enable those signals, it would be violating a fundamental contract: Children should inherit and honour their parent’s signal ignore state. >>> Though all the references to that "long-standing UNIX convention" it gave me were all made-up and it admitted not being able to give me a verifiable one. One of my issues here is the shell deciding it knows better than the user if a signal disposition should be changed. No other programming language does AFAIK. |
|
|
(ChatGPT transcript at https://chatgpt.com/share/690f033f-1878-800a-9714-5008c7597fa6 in case anyone cares and would like to follow-up there) |
|
|
> Though all the references to that "long-standing UNIX convention" it gave me were all made-up Well it certainly is long-standing UNIX convention and the way it was implemented historically in C code was something like: if (signal(signum, SIG_IGN) != SIG_IGN)
signal(signum, handler);These days it would be done with two sigaction() calls, the first of which only queries the disposition (which signal() could not do). It's also required behaviour for all standard utilities where ASYNCHRONOUS EVENTS says "Default" or specifies "the standard action" for a given signal. (See XCU 1.4 Utility Description Defaults). I always assumed the reason the shell disallows trapping (or resetting) a signal inherited as ignored is so that shell programmers don't need to bother to code some equivalent of the above C code in shell scripts. And given that large numbers of shell scripts rely on this, removing the requirement now would be a bad idea. |
|
|
If you want to get a way to override this feature of trap into the standard, you'll need to persuade at least one shell maintainer to implement it first so that there is existing practice. The obvious way to provide it would be to add a -f ("force") option to trap. |
|
|
Re: 0001954:0007312 As mentioned above, zsh already does not forbid changing the disposition of signals ignored upon start (and never had AFAIK since the first version from 1990). Even in sh mode, which makes it non-conformant, but also more usable than conformant ones. zsh, when interactive, from testing, appears to restore most if not all signal dispositions to their default, avoiding the common pathological issues with ignored SIGPIPE or SIGCHILD. fish does it even when non-interactive (I don't think that's a good idea when non-interactive though). fish is not (even remotely) POSIX compliant and doesn't claim nor intend to be. I'm not trying to introduce a new feature, just relax or remove a harmful requirement. > And given that large numbers of shell scripts rely on this, removing the requirement now would be a bad idea. Can you please give one example of a real-life shell script that relies on this? I've seen many cases where that gets in the way. I can't think of one where it would be relied upon (except maybe for pre-job control systems from the 80s maybe). I can give references to some examples on unix.stackexchange.com. The latest occurrence and which prompted me to raise that was https://unix.stackexchange.com/a/801140 Do you have a reference to some modern software that does the equivalent of if (signal(signum, SIG_IGN) != SIG_IGN)
signal(signum, handler);I'm trying to figure out if there's any other reason than to cover the pre-job control handling. |
|
|
Re: 0001954:0007311 > It's also required behaviour for all standard utilities where ASYNCHRONOUS EVENTS says "Default" or specifies "the standard action" for a given signal. (See XCU 1.4 Utility Description Defaults). Looks like none of GNU grep, GNU awk, or procps ps (among the handful I tried) are compliant then: $ sh -c 'trap "" SEGV FPE BUS; </proc/self/status exec gawk /Sig...:/' SigPnd: 0000000000000000 SigBlk: 0000000000000000 SigIgn: 0000000000001000 SigCgt: 00000000000004c0 It installed handlers on SEGV FPE BUS even though they were ignored on entry. $ sh -c 'trap "" SEGV; </proc/self/status exec grep Sig...:' SigPnd: 0000000000000000 SigBlk: 0000000000000000 SigIgn: 0000000000000000 SigCgt: 0000000000000400 $ sh -c 'trap "" HUP INT ILL TRAP BUS; exec ps --signames -o ignored,caught,comm' IGNORED CAUGHT COMMAND QUIT,SEGV,USR2,PIPE,TERM+ HUP,INT,ILL,BUS,FPE,SEGV+ zsh INT HUP,INT,QUIT,ILL,TRAP,BUS+ ps |
|
|
Re: 0001954:0007316 GNU grep (I didn't check but most likely GNU awk as well) installs a SIGSEGV handler so it can exit gracefully on a stack overflow error. I think it's a good excuse to break POSIX conformance. I don't see a good reason to completely remove the "signals ignored on entry can't be trapped" rule in either of your links though. |
|
|
> Can you please give one example of a real-life shell script that relies on this? Every script that installs a trap handler for SIGHUP. If the handler was unilaterally installed, it would break nohup. > Do you have a reference to some modern software that does the equivalent of ... xz compression utility in the signals_init() function in signals.c: for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i) {
// If the parent process has left some signals ignored,
// we don't unignore them.
if (sigaction(sigs[i], NULL, &old) == 0
&& old.sa_handler == SIG_IGN)
continue;
// Establish the signal handler.
if (sigaction(sigs[i], &my_sa, NULL))
message_signal_handler();
}gnupg in init_one_signal() in signal.c: if (check_ign)
{
/* we don't want to change an IGN handler */
sigaction (sig, NULL, &oact );
if (oact.sa_handler == SIG_IGN )
return;
}Libreoffice in set_signal() in dotlockfile.c: if (sigaction(sig, NULL, &sa) < 0)
return -1;
if (sa.sa_handler == SIG_IGN)
return 0;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
return sigaction(sig, &sa, NULL); |
|
|
> Looks like none of GNU grep, GNU awk, or procps ps (among the handful I tried) are compliant Wouldn't surprise me. However, the fact that a signal handler is installed doesn't necessarily mean the utility is non-compliant. For example, catching SIGSEGV to detect a stack overflow error could be done in a conforming way if the signal handler behaves as per the inherited disposition if si_code is not SEGV_MAPERR. The required behaviour is tested by the UNIX conformance test suite, but the tests were added relatively recently so the only systems that have certified with those tests are macOS and AIX. |
|
|
Thanks. "not breaking nohup" sounds indeed like one of those "good reasons that still holds today". I still don't like the fact that the shell (as opposed to other programming language) doesn't honour what I ask it to do, but given there's no standard CLI interface at the moment to retrieve inherited dispositions, the current behaviour makes sense and I agree a trap -f would be a better approach. Happy to retract this bug, or can we change it to a request to add a rationale for that requirement (and the one for utilities not to change disposition of ignored signals)? |
|
|
re: 0001954:0007315 > As mentioned above, zsh already does not forbid changing the disposition of signals ignored upon start (and never had AFAIK since the first version from 1990) Looking for other stackexchange Q&As about this "annoying" requirement, I found https://unix.stackexchange.com/a/515169 (by me) which shows in some older versions of zsh, for SIGINT and SIGQUIT at least, you could set a handler on those if ignored on start, but not reset the disposition to default unless you first installed a handler. I'll try and dig the rationales for the related changes when I have some time. |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2025-11-07 20:40 | stephane | New Issue | |
| 2025-11-08 08:27 | stephane | Note Added: 0007302 | |
| 2025-11-08 08:37 | stephane | Note Added: 0007303 | |
| 2025-11-08 11:13 | stephane | Note Added: 0007304 | |
| 2025-11-11 10:25 | geoffclare | Note Added: 0007311 | |
| 2025-11-11 10:50 | geoffclare | Note Added: 0007312 | |
| 2025-11-11 18:06 | stephane | Note Added: 0007315 | |
| 2025-11-11 21:33 | stephane | Note Added: 0007316 | |
| 2025-11-12 04:36 | oguzismailuysal | Note Added: 0007317 | |
| 2025-11-12 09:58 | geoffclare | Note Added: 0007318 | |
| 2025-11-12 09:59 | geoffclare | Note Edited: 0007318 | |
| 2025-11-12 10:11 | geoffclare | Note Added: 0007319 | |
| 2025-11-12 10:28 | stephane | Note Added: 0007320 | |
| 2025-11-12 10:35 | stephane | Note Added: 0007321 |