The 'trap action sig' form of the command is different from the kernel model, 
or signal() interface, because all shells have to implement a handler that 
references the action string and passes it to eval as a special built-in. 
Whether they use a single function with sigaction(), which has access to the 
signo field of a siginfo_t, to establish this or multiple entry points to one 
function body for use with signal() directly is not material. From this it's 
not unreasonable to expect that 'trap - sig' and 'trap "" sig' may use a 
different constant to represent SIG_DFLT and SIG_IGN that this eval handler 
recognizes, without calling signal() or sigaction() each time trap is called. 
It can just set all handlers at startup to this eval() function then, until a 
forked utility environment requires the startup state for exec() to match the 
SIG_IGN state trap doesn't inherit, and modifies the list of action strings 
directly to represent initial state and changes.

This is what I see as the "higher level abstraction" shell's are supposed to 
implement, anyways. The default for shells is this _trap_eval() function, not 
SIG_DFLT or SIG_IGN. It can be argued the <signal.h> header is missing SIG_EVAL 
to reflect this state, to be specific an asynch-signal safe version of system() 
is the portable means of handling a signal, not simply to kill it or the other 
default actions. An implementation-defined separate interface to establish the 
action string associated with each signal would be needed, as invention, to 
augment signal(); but this is fairly trivial to implement on systems where 
signal() is a wrapper of sigaction().
In a message dated 4/15/2019 1:08:51 PM Eastern Standard Time, 
k...@munnari.oz.au writes:
Replying to a bunch of messages in one...

    Date:        Mon, 15 Apr 2019 10:26:35 -0400
    From:        Chet Ramey <chet.ra...@case.edu>
    Message-ID:  <7e4691fd-95a8-5cc0-4521-513f1aca7...@case.edu>

  | I guess Geoff has the last word on the intent.

Sure, and that's fine.

  | It at least tells the user that the SIG_IGN isn't going to change,
  | regardless of how many trap commands he or she issues.

I will comment more on that lower down when I am replying to Geoff's message.

  | The devil's advocate position here is that there is variation between
  | implementations, so we shouldn't attempt to standardize anything.

When there are good reasons, and users of the variations, that's a good
argument.  Here we just have an unworkable mess, that no-one understands,
and where only the simplest usages are even attempted.  This is something
that warrants a cleanup.

  | I don't view blocking signals as changing the state of their disposition.
  | Blocking is a temporary condition;

Not necessarily.  If signals are blocked when the shell starts, and
the shell doesn't arbitrarily unblock them, then they will remain blocked
forever - there's no mechanism (at least no standard mechanism) for a
shell user to manipulate the blocking state.

chet.ra...@case.edu ikn a different message said:
  | It's not. It's about why there is a distinction between non-interactive and
  | interactive shells.

Yes, that's what I initially thought, that or something more along those
lines - but then everyone else seemed to go the other way.

  | My guess is that Korn wanted scripts to be able to change traps for signals
  | ignored at startup, too, but decided that it wasn't backwards-compatible
  | enough, and ended up just allowing interactive shells to do it.

Early versions of that shell had to work in systems with no job
control, and so no process groups.  In such an environment the
script cannot be allowed to alter an ignored signal - or not without
some method to find out the current state, and while ksh has trap -p
(for named conditions anyway) that's not really a convenient way, though
ksh's format for trap -p does make that much easier than everyone else's.

But the "ended up" is what the Bourne shell had always done, so unless
there's some other reason for believing there was an intended change,
I'm not sure I believe that hypothesis.

And:

chet.ra...@case.edu said in yet another message:
  | OK, then there must be some other reason that text appears in the 1992
  | edition. 

Back in 1992, job control, outside BSD systems, was still not
all that common (it was in SunOS, Digital Unix (both originally
BSD based) and probablu IRIX, but I think not in AIX or HPUX, etc).

Without job control, and without a reasonable way to test the existing
state of a signal, it was crucial that signals ignored on entry to a
non-interactive shell continue to be ignored.  For interactive shells
it makes no difference, as an interactive shell (more or less by
definition) cannot be run in the background, whereas a non-interactive
one can.  Since a shell cannot tell (in a non job control envoronment)
whether it is in foreground or background, the best that can be done is
whether it is interactive or not, and whether it has signals ignored or
not (those it can tell.)



g...@opengroup.org quoted me, and said:
  | > Huh?  What "trap - $sig" ?
  | The one three lines above that in my email.  (Which is now below, because of
  | your reordering.) 

Yes, that I assumed.  The point was more what that has to do with
anything.  The question is what "trap" should output.  That cannot
depend upon what other commands might perhaps be, or have been issued
earlier (except commands that have changed the state).

  | The output should be a command that sets signals X Y and Z to be ignored.

I see from later in your reply that you believe that has always what
has been required, and if that were true, there would be less of an
issue.  But I disagree.

  | I agree there's no point trying to do it in a non-interactive shell. But I
  | don't see that as justification for stopping the standard from specifying
  | the behaviour if a script did try to do it. 

No, that's fine - though there has to be a limit on how much useless
imaginary behaviour we explicitly specify the results of ... where
possible it is better to simply have a general principle stated, and
not try to call out (any) particular cases, except for exceptions.

  | The difference is that for a non-interactive shell, signals that were
  | ignored on entry to the shell are *always* reported by trap as ignored,
  | no matter what else has happened.  

I have never believed that to be true - but that may be because I've
never been a ksh user, and haven't ever attempted to follow all the random
stray changes it introduced.

However, I can believe that of ksh, as much of the aim of that (all the
way down to its model for local variables, declarations, ...) seems to
have been inspired by at attempt to make the shell programming language
a "good" language in the sense understood by programming language designers.
That was always doomed (a new language, like rc perhaps, could do that, but
the Bourne shell language and model can't be bent far enough to ever achieve
that.)

That also justifies the ksh "trap -p" format, which is completelty useless
for input to the shell to restore anything, but makes it much easier to
detect the current state of one particular trap.

Part of the division between views of this, I think, is that I (at least)
view traps and signals as different things (and I think the diffeence in
names supports that - the command could have been called sig or signal or
something after all).

Signals are simply the underlying kernel mechanism that allows traps to
be implemented.

My view of traps is that they allow a script to specify what should happen
if a particular (usually async) condition occurs.

That is, if I say

    trap 'command' INT

what I am doing is saying "if an interrupt occurs, execute command and
then continue".  This has nothing whatever to do with whether or not
it is possible for an interrupt to occur.

Then the (old) trap command in query mode (just trap) is intended to
save the actions, so that they can be restored sometime later (how much
later is never specified - but it could be that a script reaches some
point, writes state, and exits.  Then weeks or months later, the script
is restarted, reads its saved state, and continues.  The "trap" command
is part of that state saving.

In that, the first instance of the script might have been running (on a
non job control system - something from the early 80's) in the background,
and so have SIGINT (etc) ignored.  When it results, it might be running
in the foreground.

If the intent of the script is to do the above, and run command on an
interrupt, then if the trap command in the saved state output
    trap -- '' INT
then when it resumes, it would go back to that state, and even though
it can now be interrupted, rather than doing what the script author
wanted to happen, it instead just ignores the interrupt.

And no, it cannot just redo the original trap command, as the action
might very well vary during different parts of the script, we need to
recover the action that was current at the time the script was suspended.

So, in my view anyway, the traps are somethng that lives inside the
shell, and are set as instructed, always, even if the associated signal
cannot be caught.

The "reveal the state of the kernel interface model" is not really very
useful.  No-one wants to restore a trap to ignored, if it could be
trapped instead now, just because it could only (effectively) be ignored
earlier.  That's pointless.  And if now the signal can only be ignored
then what is in the saved trap command makes no difference at all.
That's one of the two uses of the trap command.

The other is to display to users the state of the traps (which is typically
only of any use in debugging).  For that, displaying the actual signal
disposition might be slightly better (only slightly - there are arguments
that users might want either way ... some users want to know why the trap
isn't being executed, others want to confirm that they trap that the code
was supposed to set is what actually was executed).

  | I disagree that it needs fixing.

Well, really, I think there is no doubt that it needs some kind
of fixing.  That's what started this thread.  I read the words
and could not work out what they meant.  Unless I have gone completely
senile, to me, that's evidence that the meaning is not clear.  Of
course, it is no surprise that the author of the words knows what they're
supposed to mean, but when someone else tells you that the words alone
are insufficient to reach that conclusion, then you should at least look
seriously at improving them.

Whether it is my suggested wording (or something like it) or not is less
important, but starting out with wording that is not clear is not a good
place to be.

And:

  | Your suggestion applies to both interactive and non-interactive shells,
  | and so doesn't highlight that the there is something special about the
  | non-interactive case

because for the purposes of the trap command, as long as it remains
the way you want it to be, there is nothing special.  What you want
is for it to write out the state of the kernel sigaction - if it is
SIG_DFL, then "trap" says nothing, if it is SIG_IGN, then "trap" says
the action is an empty string, and if it is something else, then we
report that action string that has been set.

Whether the shell is interactive or not, whether the signal is in SIG_IGN
state because of a previous trap command, or because it started out that
way, makes no difference whatever.  Don't complicate things.

(For this purpose we assume that a shell which is trapping a signal for
its own purpose makes it appear to act the way that it should if it were
not doing that.)

Those things only matter to an attempt to change the state.

  | The behaviour of these shells also doesn't conform to the requirements
  | of the current standard. 

I disagree.

Lines 77490-2
    If action is '-', the shell shall reset each condition to the
    default value. If action is null (""), the shell shall ignore
    each specified condition if it arises. Otherwise, the argument
    action shall be read and executed by the shell when one of the
    corresponding conditions arises.

Lines 77514-5
    The trap command with no operands shall write to standard output
    a list of commands associated with each condition.

To me that's clear.  The trap command (with args) sets an action for
when (if) a condition arises, and without args lt lists the commands for
each condition.  Nothing there about inventing different conditions
that what was set.  And certainly nothing about writing the "ignored"
output state for traps that will not be delivered to the shell.

I suspect that you're relying upon line 77504
    Signals that were ignored on entry to a non-interactive shell
    cannot be trapped or reset,

but (to me) that is just saying that the signal (not the trap) cannot be
altered in the circumstance.  Note "signals" not "conditions" used
elsewhere (though I know the latter is partly because of EXIT, which
is not a signal, and obviously cannot be ignored when the shell starts...)

I believe a perfectly valid interpretation of what has been there (before
this new wording in 1212) is that the traps can be set, and later displayed,
regardless of the state of the signals at entry, all that the latter affects
is which signals can be delivered to the shell to cause the trap action to
be invoked.

  | The standard clearly states that signals ignored on entry to a
  | non-interactive shell *cannot* be trapped or reset. 

Yes, it does.  It is just that you are interpreting what that means
differntly than I do.  If there really was such a prohibition as you
believe, it would make sense for that to generate an error, rather than
simply being silently ignored (the way *everyone* does it, the:

  | no error need be reported when attempting to do so.

really makes no sense in that case.  If an error was returned
(as an exit status at least) then scripts would have a way to
know what happened - but they don't (parsing the output of trap
is nearly impossible).

Further note "trapped or reset" that "or reset" suggests that
"trapped" does not mean "have the trap command executed" as the
reset case is simply an instance of that - but rather might just
be saying that we cannot set the signal to SIG_DFL or to some local
handler (it cannot be trapped, not the shell shall not allow the
trap to happen) - cannot is a statement of fact.  Nb: "cannot" is
not a term from XBD 1.5.  Don't misread the text as if it were.

  | If, after an attempt has been made to set a trap, the trap output
  | shows something other than that the signal is set to ignored,
  | then shell has not obeyed this requirement.

I disagree.  If the trap action were invoked in such a situation,
then the shell would have done the wrong thing.  What the output of
the trap command is is almost irrelevant.

Again, this largely comes down to whether you beloeve that the primary
purpose of the trap (no args) command is to display stuff for humans to
look at, or whether it is (was, not quite done properly, though in practice
it is sometimes good enough) to allow the trap conditions to be saved
and restored (as the example in the standard suggests).

For the latter, having the output be the actions in earlier trap commands
is a much more useful approach.  For the former, showing the state of the
signals can be better.  I think the latter is more important.

Then again, there's also the (unrelated right now) question of whether
the standard should continue saying

  | that signals ignored on entry to a non-interactive shell *cannot*
  | be trapped or reset. 

The reason for that is mostly long gone, and this is one more reason
why scripts cannot send signals to each other - as they have no way
to know which signals will be being ignored at startup (and especially
which are being ignored in the shell running the other script).

C programs have no such constraint, while there was once a need for
this in the shell, there really isn't any more.

  | There is certainly an issue with SIGCHLD, but it's a separate issue that
  | should be the subject of a separate bug. 

While the details of what should happen with that (and other similar cases,
though SIGCHLD is more special than most) the fact that there is this odd
case should tell us something about how we resolve all the above issues.

If we make the trap command be more like setting a variable (with side
effects, that sometimes do not happen in quite the most obvious way) then
many things become much simpler (including SIGCHLD) to specify.  But if
we persist in attempting to model the kernel interface, instead of useful
higher level behaviour, then it all gets very messy.

kre

Reply via email to