Austin Group Defect Tracker

Aardvark Mark IV


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0001212 [1003.1(2016/18)/Issue7+TC2] Shell and Utilities Objection Enhancement Request 2018-09-28 02:56 2020-04-27 11:18
Reporter kre View Status public  
Assigned To
Priority normal Resolution Accepted As Marked  
Status Applied  
Name Robert Elz
Organization
User Reference
Section XCU 2.14 -- trap special builtin
Page Number 2420 - 2423
Line Number 77484-5 (and more)
Interp Status ---
Final Accepted Text Note: 0004358
Summary 0001212: Enhance trap command
Description The trap command, as it stands, is missing two useful functions

1) the ability to discover the current action for a particular condition
2) the ability to save the current state of all conditions (see issue 1211)

Several shells have implemented a solution to (1) using a new -p option
to trap (unfortunately, the output format, and so how it should be used,
varies - but at least the mechanism is there).

The NetBSD shell has a solution to (2) based upon that for (1), but as
far as I know, no other shell has a solution to this, and the NetBSD shell
is not in widespread enough use to standardise its mechanism yet.

Hence, I am requesting that this issue be marked as "for the future" and
retained (along with any notes it attracts, and possible different solutions)
until we do have something that is ready to be included in the standard.

And implementers - please do *something*...

Also note, that for shells that have "trap -p" already, but treat it
used with no conditions as identical to "trap" with no operands, that
is not a useful feature (two ways to do the same thing) and changing the
implementation of "trap -p" as suggested below will do no harm.
Desired Action In the SYNOPSIS, between lines 77484 and 77485 add a new form for the command

      trap -p [condition...]

Then somewhere in the DESCRIPTION (probably after the paragraph about
trap with no operands, starting on line 77514) add a new paragraph

     When the -p option is given the trap command shall write,
     in the same format used when no operands are given, a list
     of commands for each condition specified as an operand, or if
     no operands, other than the -p flag, are given, then for all
     possible conditions for which actions can be set in the shell,
     whether currently at their default values,or not. It is unspecified
     whether the values for SIGKILL and SIGSTOP can be obtained this way,
     but if those are included in trap -p output, the shell shall not
     object to them used as input provided that the action specified
     is the same as was, or would be, output by trap -p, and in this case
     no undefined results shall occur.

Then change the example at line 77524 from
     save_traps=$(trap)
to
     save_traps=$(trap -p)
Tags issue8
Attached Files

- Relationships
related to 0001211Applied "trap" (with no args) specification does not match reality 

-  Notes
(0004356)
shware_systems (reporter)
2019-04-04 17:35

Does it need to be a special case that the output for a trap whose default interpretation as a sigaction is to be ignored, such as SIGCHLD and SIGURG, shall be reported as if they were explicitly set to this if a handler action is not assigned, i.e.:
>echo `trap -p CHLD`
trap -- "" CHLD

and not:
trap -- - CHLD

or is the first form reported only when an actual
trap "" CHLD

command has been entered?
(0004357)
kre (reporter)
2019-04-06 07:54

Re Note: 0004356

No, certainly nothing is needed as a special case for signals
which default to ignored - those are not the same state in any
case - explicitly ignoring a signal is a different state from
simply doing nothing, which results in the signal being ignored
(perhaps a subtle difference, but a difference nevertheless).

I wouldn't use SIGCHLD as an example of that however, as while the
effect on signal delivery of an ignored (SIG_IGN) SIGCHLD is the
same as for SIGCHLD in its default state (SIG_DFL) being ignored
can have other ramifications for the application.

This does however raise two other interesting questions. First should
the trap command (some enhanced trap command as proposed here) report
a signal that was ignored upon entry to the shell as being ignored, or
simply as being in its default state? I have no particular insightful
answer to that one, and either would be reasonable. My gut tells me that
the purpose of the command is to discover what earlier manipulations have
been made in the script, so a function (or dot script, or whatever) can
return the world to its entry state before finishing. If that's the case
the signals ignored on entry (which the shell cannot manipulate anyway) would
be irrelevant. However having those signals explicitly listed as ignored
would not harm that usage, and would allow the script to discover that no
matter how much it wants to receive a SIGxxx it cannot, because its parent
invoked it with that signal ignored, and hence the script needs to either
fail, or use some other method to handle whatever it needed the signal for
(if it was just for synchronisation between its sub-shells, then it might
simply pick a different signal to use).

My implementation of this currently lists signals that were ignored on
entry as being in the default state (or actually, whatever state the
script attempted to set the signal into - whether or not that was actually
effective) - but that could easily be changed if the overall opinion is
that that would be better.

This also raises an additional sub-issue of whether or not there should be
some method to allow a script to trap a signal that was ignored on entry
if it really needs to do that. C programs can do it, I see no particular
reason why scripts should not have the option .. the only reason that I can
see that it isn't done now, is that typical program behaviour used to be

     if (signal(SIGxxx, SIG_IGN) != SIG_IGN)
         signal(SIGxxx, xxx_trap);

so that a signal which was ignored would stay that way (that's usually what
is wanted) and as sh provided no method to do the test explicitly, so only
provided that mechanism. But as it was always OK to restore the signal to
its entry state (no test like above is done then) sh always explicitly tests
the invocation signal state, as it has no other way to know whether a trap
command is establishing a new trap or resetting to the earlier state.

If we had the testing method, and an option to not do the test, but simply
override an existing SIG_IGN (not previously set by the script) I don't see
that it would do any harm - the current trap command would need to continue
acting the way it always has of course.

The second new issue mentioned above is more specific to SIGCHLD (though
could also apply to other signals). If a script does
      trap '' SIGCHLD
and the shell from that actually does signal(SIGCHLD, SIG_IGN) then the
shell is not likely to work very well (certainly on some systems).

So, the question is, is the shell obliged to actually do what the script
instructs, or can it merely act as if it had done that (in this case, by
not delivering any SIGCHLD traps to the script). Or on systems where it
works this way, is it required that "trap '' SIGCHLD" cause the shell to
lose the ability to wait() on any of its children, thus making $? useless
for anything not built in?

And a corollary to that, if a script does do "trap '' SIGCHLD" the
shell then invoke sub-processes (other commands) with SIGCHLD ignored
(which most do not expect, and sometimes cannot handle) and in particular
if that invoked sub-process is a subshell - either a subshell environment
of the current shell, or more relevantly here, "/bin/sh -c 'command || other'" -
that sub-process would be invoked with SIGCHLD ignored, and if it is a shell,
is it permitted to either set SIGCHLD back to SIG_DFL, or catch the signal
(depending upon its needs) or must it comply with the restriction that
signals ignored upon entry remain ignored throughout the script?

FWIW: the NetBSD shell silently ignores attempts by scripts to manipulate
SIGCHLD (or should, but I don't remember if I actually committed that change).

Everything appears to the script as if SIGCHLD were trapped/ignored, but
no signal() sys call is ever made to affect the kernel when the script does
that. It is my intention (not yet implemented) to copy the bash mechanism
for this (maybe itself copied from elsewhere) to a degree - and implement
script level SIGCHLD traps independent of (and more reliably than) kernel
delivered SIGCHLD signals - so that one SIGCHLD trap (in the script) is taken
for every asynchronous pipeline (command) that completes (not for every
command that completes the way bash implements this - that does not seem to
be very useful). In the trap handler $! would be redefined to be the pid
of the async job that caused this invocation of the trap handler (so, for
example:
    "wait $!"
in the trap handler would clean up the job, and set $? to its status).

I believe this is safe, as the trap could fire anywhere in the script, so its
handler cannot reasonably be depending upon $! being the pid of any particular
last async job started ... unless of course there was only one, in which case,
it would be).

None of this mechanism is relevant to the standard (certainly not yet) but
the question of exactly what the shell is permitted/required to do with
signals when implementing the trap command is.
(0004358)
geoffclare (manager)
2019-04-09 11:07
edited on: 2019-04-11 15:33

Suggested changes ...

In the SYNOPSIS, between lines 77484 and 77485 add a new form for the command
trap -p [condition...]

On page 2420 line 77487 change:
If the first operand is an unsigned decimal integer, the shell shall treat all operands as conditions, and shall reset each condition to the default value. Otherwise, if there are operands, the first is treated as an action and the remaining as conditions.
to:
If the -p option is not specified and the first operand is an unsigned decimal integer, the shell shall treat all operands as conditions, and shall reset each condition to the default value. Otherwise, if the -p option is not specified and there are operands, the first operand shall be treated as an action and the remaining as conditions.

On page 2420 line 77514 after applying bug 1211 change:
The trap command with no operands shall write to standard output a list of commands associated with each condition which is not in its default state.
to:
The trap command with no operands shall write to standard output a list of commands associated with each of a set of conditions; if the -p option is not specified, this set shall contain only the conditions that are not in the default state (including signals that were ignored on entry to a non-interactive shell); if the -p option is specified, the set shall contain all conditions, except that it is unspecified whether conditions corresponding to the SIGKILL and SIGSTOP signals are included in the set.

On page 2420 line 77522 after applying bug 1211 change:
The shell shall format the output, including the proper use of quoting, so that it is suitable for reinput to the shell as commands that achieve the same trapping results for those traps that had previously been altered.
to:
The shell shall format the output, including the proper use of quoting, so that it is suitable for reinput to the shell as commands that achieve the same trapping results for the set of conditions included in the output, except for signals that were ignored on entry to the shell as described above. If this set includes conditions corresponding to the SIGKILL and SIGSTOP signals, the shell shall accept them when the output is reinput to the shell (where accepting them means they do not cause a non-zero exit status, a diagnostic message, or undefined behavior).

On page 2420 line 77524 after applying bug 1211 change:
save_traps=$(trap)
trap "some command" INT QUIT
save_traps="trap - INT QUIT; $save_traps"

...

eval "$save_traps"
to:
save_traps=$(trap -p)

...

eval "$save_traps"
or:
save_traps=$(trap -p INT QUIT)
trap "some command" INT QUIT

...

eval "$save_traps"

On page 2421 line 77538 change the OPTIONS section from:
None.
to:
The following option shall be supported:

-p
Write to standard output a list of commands associated with each condition operand. The behavior when there are no operands is specified in the DESCRIPTION section.

The shell shall format the output, including the proper use of quoting, so that it is suitable for reinput to the shell as commands that achieve the same trapping results for the specified set of conditions. If a condition operand is a condition corresponding to the SIGKILL or SIGSTOP signal, and trap -p without any operands would not include it in the set of conditions for which it writes output, the behavior is undefined if the output is reinput to the shell.

On page 2422 line 77564 after applying bug 1211 change APPLICATION USAGE to:
When the -p option is not used, since trap with no operands does not output commands to restore traps that are currently set to default, these need to be restored separately. The RATIONALE section shows examples and describes their drawbacks.

On page 2423 line 77604 add some new paragraphs to RATIONALE:
The -p option was added because without it the method used to restore traps needs to include special handling of traps that are set to default when trap with no operands is used to save the current traps. One example is:
save_traps=$(trap)
trap "some command" INT QUIT
save_traps="trap - INT QUIT; $save_traps"

...

eval "$save_traps"
but this method relies on hard-coding the commands to reset the traps that are being set. It also has a race condition if INT or QUIT was not set to default when saved, since it first sets them to default and then restores the saved traps. A more general approach would be:
save_traps=$(trap)
...
for sig in EXIT $( kill -l )
do
    case "$sig" in
    SIGKILL | KILL | sigkill | kill | SIGSTOP | STOP | sigstop | stop)
    ;;
    *) trap - $sig
    ;;
    esac
done
eval "$save_traps"
This has the same race condition since it first sets all traps (that can be set) to default and then restores those that were not previously set to default.

Historically, some shells behaved the same with and without -p when there are no operands. This standard requires that the set of conditions differs between the two cases: with -p it is all conditions (except possibly SIGKILL and SIGSTOP); without -p it is only the conditions that are not in the default state.

On page 2423 line 77606 revert the bug 1211 change, so that FUTURE DIRECTIONS is:
None.


(0004359)
joerg (reporter)
2019-04-09 13:32
edited on: 2019-04-09 13:35

Hi Geoff, your text does not include an explanation on what should
happen with e.g.

   trap -p INT ....

The easy way to implement -p results in -p being ignored in such
a case and the SIGINT trap restored to it's default. If you like
to require that "trap -p INT" lists the trap state for SIGINT,
I would need to restructure the trap implementation in the Bourne
Shell.

Also: The requirement to print the state of "ignored since startup"
traps without -p is a change compared to the historic behavior and
I tend not to change this behavior.

(0004360)
nick (manager)
2019-04-09 14:27

In the proposed change on page 2420 line 77522 after applying bug 1211 change:

The shell shall format the output, including the proper use of quoting, so that it is suitable for reinput to the shell as commands that achieve the same trapping results for the set of conditions included in the output. If this set includes conditions corresponding to the SIGKILL and SIGSTOP signals, the shell shall silently ignore them when the output is reinput to the shell.


I believe it is incorrect to say "shall silently ignore" here. Many shells permit a trap of these signals, even though they cannot be caught or ignored. When you request a list of currently set traps, that (meaningless) action is listed. So the shell does not ignore the setting ... it is doing something with it. It is ignoring the error that occurs should it call signal() or sigaction() on these signals.

The important thing is that the list produced by trap -p can be re-input without an error being reported, so you don't need to filter out those uncatchable signals from the list.

So I believe it would be better to replace "the shell shall silently ignore them" with "the shell shall not produce any diagnostic message with respect to these signals", leaving it unspecified as to what else it might or might not do.
(0004361)
chet_ramey (reporter)
2019-04-15 14:23

Re: 4359

Doesn't `trap -p INT' fall under the first sentence of the -p description?

"Write to standard output a list of commands associated with each condition operand"

- Issue History
Date Modified Username Field Change
2018-09-28 02:56 kre New Issue
2018-09-28 02:56 kre Name => Robert Elz
2018-09-28 02:56 kre Section => XCU 2.14 -- trap special builtin
2018-09-28 02:56 kre Page Number => 2420 - 2423
2018-09-28 02:56 kre Line Number => 77484-5 (and more)
2019-04-04 17:35 shware_systems Note Added: 0004356
2019-04-06 07:54 kre Note Added: 0004357
2019-04-09 11:07 geoffclare Note Added: 0004358
2019-04-09 11:09 geoffclare Note Edited: 0004358
2019-04-09 11:11 geoffclare Note Edited: 0004358
2019-04-09 11:13 geoffclare Note Edited: 0004358
2019-04-09 11:19 geoffclare Relationship added related to 0001211
2019-04-09 13:32 joerg Note Added: 0004359
2019-04-09 13:35 joerg Note Edited: 0004359
2019-04-09 13:52 geoffclare Note Edited: 0004358
2019-04-09 14:27 nick Note Added: 0004360
2019-04-10 08:33 geoffclare Note Edited: 0004358
2019-04-11 15:33 geoffclare Note Edited: 0004358
2019-04-11 15:48 geoffclare Interp Status => ---
2019-04-11 15:48 geoffclare Final Accepted Text => Note: 0004358
2019-04-11 15:48 geoffclare Status New => Resolved
2019-04-11 15:48 geoffclare Resolution Open => Accepted As Marked
2019-04-11 15:48 geoffclare Tag Attached: issue8
2019-04-15 14:23 chet_ramey Note Added: 0004361
2020-04-27 11:18 geoffclare Status Resolved => Applied


Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker