Source-Changes archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

CVS commit: src/bin/sh



Module Name:    src
Committed By:   kre
Date:           Sun May  7 15:01:18 UTC 2017

Modified Files:
        src/bin/sh: sh.1 trap.c

Log Message:
Enhance the trap command to make it possible to do what POSIX wants
(even if no shell in existence, that I am aware of, does that).

That is, POSIX says ... [of the trap command with no args]

        The shell shall format the output, including the proper use of
        quoting, so that it is suitable for re-input to the shell as commands
        that achieve the same trapping results. For example:

        save_traps=$(trap)

        ...

        eval "$save_traps"

It is obvious what the intent is there.  But no shell makes it work.

An example using bash (as the NetBSD shell, still does not do the save_traps=
stuff correctly - but that is a problem for a different time and place...)

Given this script

        printf 'At start: '; trap
        printf '\n'

        traps=$(trap)
        trap 'echo hello' INT
        printf 'inside  : '; trap
        printf '\n'
        eval "${traps}"

        printf 'At end  : '; trap
        printf '\n'

One would expect that (assuming no traps are set at the start, and
there aren't) that the first trap will print nothing, then the inside
trap will show the trap that was set, and then when we get to the
end everything will be back to nothing again.

But:

At start:
inside  : trap -- 'echo hello' SIGINT

At end  : trap -- 'echo hello' SIGINT

And of course. when you think about it, it is obvious why this happens.
The first "trap" command prints nothing ... nothing has changed when we
get to the "traps=$(trap)" command ... that trap command also prints
nothing.  So this does traps=''.  When we do eval "${traps}" we are
doing eval "", and it is hardly surprising that this accomplishes nothing!

Now we cannot rationally change the "trap" command without args to
behave in a way that would make it useful for the posix purpose (and
here, what they're aiming for is good, it should be possible to
accomplish that objective) so is there some other way?

I think I have seen some shell (but I do not remember which one) that
actually has "trap -" that resets all traps to the default, so with that,
if we changed the 'eval "${traps}"' line to 'trap -; eval "${traps}"'
then things would actually work - kind of - that version has race conditions,
so is not really safe to use (it will work, most of the time...)

But, both ksh93 and bash have a -p arg to "trap" that allows information
about the current trap status of named signals to be reported.  Unfortunately
they don't do quite the same thing, but that's not important right now,
either would be usable, and they are, but it is a lot of effort, not
nearly as simple as the posix example.

First, while "trap -p" (with no signals specified) works, it works just
the same (in both bash and ksh93, aside from output format) as "trap".
That is, that is useless.   But we can to

        trap_int=$(trap -p int)
        trap_hup=$(trap -p hup)
        ...

and then reset them all, one by one, later...

(bash syntax)
        test -n "${trap_int}" && eval "${trap_int}" || trap - int
        test -n "${trap_hup}" && eval "${trap_hup}" || trap - hup
(ksh93 syntax)
        trap "${trap_int:-}" int
        trap "${trap_hup:-}" hup

the test (for bash) and  variable with default for ksh93, is needed
because they both still print nothing if the signal action is the default.

So, this modification attempts to fix all of that...

1) we add trap -p, but make it always output something for every signal
   listed (all of the signals if none are given) even if the signal
   action is the default.

2) choose the bash output format for trap -p, over the ksh93 format,
   even though the simpler usage just above makes the ksh93 form seem
   better.   But it isn't.  Consider:

        ksh93$ trap -p int hup
        echo hello

   One of the two traps has "echo hello" as its action, the other is
   still at the default, but which?

   From bash...
        bash$ trap -p int hup
        trap -- 'echo hello' SIGINT

   And now we know!  Given the bash 'trap -p' format, the following function
   produces ksh93 format output (for use with named signals only) instead...

        ksh93_trap_p() {
                for _ARG_ do
                        _TRAP_=$(trap -p "${_ARG_}") || return 1
                        eval set -- "${_TRAP_}"
                        printf '%s' "$3${3:+
        }"
                done
                return 0
        }

  [ It needs to be entered without the indentation, that '}"' line has to be
    at the margin.   If the shell running that has local vars (bash does) then
    _ARG_ and _TRAP_ should be made local. ]

  So the bash format was chosen (except we do not include the "SIG" on the
  signal names.  That's irrelevant.)

  If no traps are set, "trap -p" will say (on NetBSD of course)...

trap -- - EXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS
trap -- - PIPE ALRM TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ
trap -- - VTALRM PROF WINCH INFO USR1 USR2 PWR RT0 RT1 RT2 RT3 RT4 RT5
trap -- - RT6 RT7 RT8 RT9 RT10 RT11 RT12 RT13 RT14 RT15 RT16 RT17 RT18
trap -- - RT19 RT20 RT21 RT22 RT23 RT24 RT25 RT26 RT27 RT28 RT29 RT30

  Obviously if traps are set, the relevant signal names will be removed from
  that list, and additional lines added for the trapped signals.

  With args, the signals names are listed, one line each, whatever
  the status of the trap for that signal is:

$ trap -p HUP INT QUIT
trap -- - HUP
trap -- 'echo interrupted' INT
trap -- - QUIT

3) we add "trap -" to reset all traps to default.   (It is easy, and seems
   useful.)

4) While here, lots of generic cleanup.   In particular, get rid of the
   NSIG+1 nonsense, and anything that ever believes a signo == NSIG
   is in any way rational.   Before there was a bunch of confusion,
   as we need all the signals for traps, plus one more for the EXIT
   trap, which looks like we then need NSIG+1.  But EXIT is 0, NSIG
   includes signals from 0..NSIG-1 but there is no signal 0, EXIT
   uses that slot, so we do not need to add and extra one, NSIG is
   enough.   (To see the effect of this, use a /bin/sh from before
   this fix, and compare the output from

        trap '' 64
   and  trap '' 65

   both invalid signal numbers.

   Then try just "trap" and watch your shell drop core...)

   Eventually NSIG needs to go away completely (from user apps), it
   is not POSIX, it isn't really useful (unless we make lots of
   assumptions about how signals are numbered, which are not guaranteed,
   so even if apps, like this sh, work on NetBSD, they're not portable,)
   and it isn't necessary (or will not be, soon.)

   But that is for another day...

5) As is kind of obvious above, when listing "all" traps, list all the
   ones still at their defaults, and all the ignored signals, on as
   few lines as possible (it could all be on one line - technically it
   would work as well, but it would have made this cvs log message
   really ugly...)   Signals with a non-null action still get listed
   one to a line (even if several do have the exact same action.)

6) Man page updates as well.

After this change, the following script:

        printf 'At start: '; trap
        printf '\n'

        trap -p >/tmp/out.$$
        trap 'echo hello' INT
        printf 'inside  : '; trap
        printf '\n'
        . /tmp/out.$$; rm /tmp/out.$$

        printf 'At end  : '; trap
        printf '\n'

which is just the example from above,
using "trap -p" instead of just "trap" to save the traps,
and modified to a form that will work with the NetBSD shell today
produces:

At start:
inside  : trap -- 'echo hello' INT

At end  :

[Do I get a prize for longest commit log message of the year?]


To generate a diff of this commit:
cvs rdiff -u -r1.135 -r1.136 src/bin/sh/sh.1
cvs rdiff -u -r1.39 -r1.40 src/bin/sh/trap.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.




Home | Main Index | Thread Index | Old Index