Home | History | Annotate | Download | only in sh
History log of /src/bin/sh/trap.c
RevisionDateAuthorComments
 1.58  09-Oct-2024  kre PR bin/58687 -- implement suspend as a builtin in sh

Requested by uwe@ in PR bin/58687 without objections from
anyone except me, here is an implementation of a suspend
builtin command for /bin/sh

The sh.1 man page is updated, naturally, to describe it.

This new builtin does not exist in SMALL shells -- as used
on (some) boot media, etc.

If this turns out not to be useful, it can easily be removed.
 1.57  13-Jul-2024  kre Implement the HISTFILE and HISTAPPEND variables.

See the (newly updated) sh(1) for details.
Also add the -z option to fc (clear history).

None of this exists in SMALL shells.
 1.56  10-Nov-2021  kre branches: 1.56.4;

DEBUG mode changes only. NFC (NC) for any normally compiled shell.

Mostly adding DEBUG mode tracing (when appropriate verbose tracing
is enabled generally) whenever a shell (including sushell) process
exits, so shells that the tracing should indicate why ehslls that
vanish did that.

Note for future investigators: if the relevant tracing is enabled,
and a (sub-)shell still simply seems to have vanished without trace,
the likely cause is that it was killed by a signal - and of those,
the most common that occurs is SIGPIPE.
 1.55  20-Aug-2020  kre Be less conservative about when we do clear_traps() when we have
traps_invalid (that is, when we actually nuke the parent shell's
caught traps in a subshell). This allows more reasonable use of
"trap -p" (and similar) in subshells than existed before (and in
particular, that command can be in a function now - there can also
be several related commands like
traps=$(trap -p INT; trap -p QUIT; trap -p HUP)
A side effect of all of this is that
(eval "$(trap -p)"; ...)
now allows copying caught traps into a subshell environment, if desired.

Also att the ksh93 variant (the one not picked by POSIX as it isn't
generally as useful) of "trap -p" (but call it "trap -P" which extracts
just the trap action for named signals (giving more than one is usually
undesirable). This allows
eval "$(trap -P INT)"
to run the action for SIGINT traps, without needing to attempt to parse
the "trap -p" output.
 1.54  20-Aug-2020  kre Whitespace. NFCI.
 1.53  09-Dec-2019  kre PR bin/54743

If a builtin command or function is the final command intended to be
executed, and is interrupted by a caught signal, the trap handler for
that signal was not executed - the shell simply exited (an exit trap
handler would still have been run - if there was one the handler
for the signal may have been invoked during the execution of the
exit trap handler, which, if it happened, is incorrect sequencing).

Now, if we're exiting, and there are pending signals, run their handlers
just before running the EXIT trap handler, if any.

There are almost certainly plenty more issues with traps that need
solving. Later,

XXX pullup -9

(-8 is too different in this area, and this problem suitably obscure,
that we won't bother) (the -7 sh is simply obsolete).
 1.52  25-Apr-2019  kre branches: 1.52.2;
Better interactive SIGINT handling (when a trap is set), and other
cleanups to the trap code. No longer silently ignore attempts to
do anything other than set SIGKILL or SIGSTOP to the default ('-")
state. Don't include those in trap or trap -p output (the former
because they cannot be other than in default state, so simply aren't
included, the latter because it is pointless) but do list them
when requested with trap -p SIG.

Interactive mode SIGINT traps are now run ASAP, rather than after
a command has been entered (so the sequence ^C \n is no longer needed
to generate one). Further, when trapped, in interactive mode,
while waiting for a user command, a SIGINT acts (aside from the
trap being run) just like when not trapped, aborts the command being
entered (rather than leaving it, which it did when libedit was in use)
prints a new prompt, and starts again (which is what should happen.)

Traps other than SIGINT (which has always been handled special in
interactive mode) are unaffected by this change, as are SIGINT traps
in non-interactive shells. Or that is the intent anyway.

Fix an in_dotrap ref count bug (was never being decremented... that
was inserted in a place never executed) (relatively harmless) and
add/improve some trap/signal related DEBUG mode tracing.
 1.51  18-Jan-2019  kre Finish (hopefully) the second half of 1.47 ... make sure
that when traps are marked as invalid, we never use them
for anything except output from the trap command.

Fixes issues where sub-shells of shells which use traps
(eg: to trap SIGPIPE) can end up looping forever if the
signal occurs in a sub-shell (where the trap is supposed
to be reset to its default). Reported, and mostly
analyzed by Martijn Dekker.
 1.50  12-Dec-2018  kre Reverse a decision made when the printsignals() routines from
kill and sh were merged so that the shell (for trap -l) and
kill (for kill -l) can use the same routine, and site that function
in the shell, rather than in kill (use the code that is in kill as
the basis for that routine). This allows access to sh internals,
and in particular to the posix option, so the builtin kill can
operate in posix mode where the standard requires just a single
character (space of newline) between successive signal names (and
we prefer nicely aligned columns instead)..

In a SMALL shell, use the ancient sh printsignals routine instead,
it is smaller (and very much dumber).

/bin/kill still uses the routine that is in its source, and is
not posix compliant. A task for some other day...
 1.49  05-Dec-2018  kre evert previous, linux build problem confirmed fixed by
update to mkinit.sh (to 1.10).

Or more correctly, revert & fix - turns out that there was an off by one
(failure to adjust for other changes -- in a value printed by debug mode
trace output).

NFC.
 1.48  05-Dec-2018  kre NFC (except that it should, I am guessing, fix compilation on
some versions of liux) - DEBUG mode change: Delete a (relatively new)
trace point (temporarily anyway) which mkinit (a script run using the
host's /bin/sh) apparently cannot handle correctly on (some release of)
linux (it is fine with the NetBSD shell).

I don't know which linux version has a shell with this problem
(or whether it is a mkinit issue that only works by fluke on NetBSD)

Problem reported by gson@
 1.47  03-Dec-2018  kre Cleanup traps a bit - attempt to handle weird uses in traps, such
as traps that issue break/continue/return to cause the loop/function
executing when the trap occurred to break/continue/return, and
generating the correct exit code from the shell including when a
signal is caught, but the trap handler for it exits.

All that from FreeBSD.

Also make
T=$(trap)
work as it is supposed to (also trap -p).

For now this is handled by the same technique as $(jobs) - rather
than clearing the traps in subshells, just mark them invalid, and
then whenever they're invalid, clear them before executing anything
other than the special blessed "trap" command. Eventually we will
handle these using non-subshell command substitution instead (not
creating a subshell environ when the commands in a command-sub alter
nothing in the environment).
 1.46  28-Oct-2018  kre Switch from using two printsignals() functions, one in trap.c
and one in (the included from bin/kill) kill.c and use just
the one in kill.c (which is amended slightly so it can work
the way that trap.c needs it to work). This one is chosen as
it was a much nicer implementation, and because while kill is
always built into the shell, kill also exists without the shell.

Leave the old implementation #if 0'd in trap.c (but updated to
match the calling convention of the one in kill.c) - for now.

Delete references of sys_signame[] from sh/trap.c and along with
that several uses of NSIG (unfortunately, there are still more)
and replace them with the newer libc functional interfaces.
 1.45  19-Aug-2018  kre PR bin/48875 (is related, and ameliorated, but not exactly "fixed")

Import a whole set of tree evaluation enhancements from FreeBSD.

With these, before forking, the shell predicts (often) when all it will
have to do after forking (in the parent) is wait for the child and then
exit with the status from the child, and in such a case simply does not
fork, but rather allows the child to take over the parent's role.

This turns out to handle the particular test case from PR bin/48875 in
such a way that it works as hoped, rather than as it did (the delay there
was caused by an extra copy of the shell hanging around waiting for the
background child to complete ... and keeping the command substitution
stdout open, so the "real" parent had to wait in case more output appeared).

As part of doing this, redirection processing for compound commands gets
moved out of evalsubshell() and into a new evalredir(), which allows us
to properly handle errors occurring while performing those redirects,
and not mishandle (as in simply forget) fd's which had been moved out
of the way temporarily.

evaltree() has its degree of recursion reduced by making it loop to
handle the subsequent operation: that is instead of (for any binop
like ';' '&&' (etc)) where it used to
evaltree(node->left);
evaltree(node->right);
return;
it now does (kind of)
next = node;
while ((node = next) != NULL) {
next = NULL;

if (node is a binary op) {
evaltree(node->left);
if appropriate /* if && test for success, etc */
next = node->right;
continue;
}
/* similar for loops, etc */
}
which can be a good saving, as while the left side (now) tends to be
(usually) a simple (or simpleish) command, the right side can be many
commands (in a command sequence like a; b; c; d; ... the node at the
top of the tree will now have "a" as its left node, and the tree for
b; c; d; ... as its right node - until now everything was evaluated
recursively so it made no difference, and the tree was constructed
the other way).

if/while/... statements are done similarly, recurse to evaluate the
condition, then if the (or one of the) body parts is to be evaluated,
set next to that, and loop (previously it recursed).

There is more to do in this area (particularly in the way that case
statements are processed - we can avoid recursion there as well) but
that can wait for another day.

While doing all of this we keep much better track of when the shell is
just going to exit once the current tree is evaluated (with a new
predicate at_eof() to tell us that we have, for sure, reached the end
of the input stream, that is, this shell will, for certain, not be reading
more command input) and use that info to avoid unneeded forks. For that
we also need another new predicate (have_traps()) to determine of there
are any caught traps which might occur - if there are, we need to remain
to (potentially) handle them, so these optimisations will not occur (to
make the issue in PR 48875 appear again, run the same code, but with a
trap set to execute some code when a signal (or EXIT) occurs - note that
the trap must be set in the appropriate level of sub-shell to have this
effect, any caught traps are cleared in a subshell whenever one is created).

There is still work to be done to handle traps properly, whatever
weirdness they do (some of which is related to some of this.)

These changes do not need man page updates, but 48875 does - an update
to sh.1 will be forthcoming once it is decided what it should say...

Once again, all the heavy lifting for this set of changes comes directly
(with thanks) from the FreeBSD shell.

XXX pullup-8 (but not very soon)
 1.44  22-Jul-2018  kre PR bin/36532 (perhaps)

This is more or less the same patch as provided in the PR
(just 11 years later, so changed a bit) by woods@...

Since there is no known way to actually cause the reported crash,
we may never know if this change actually fixes anything. But
even if it doesn't it certainly cannot hurt.

There is a potential race which could possibly explain the issue
(see commentary in the PR) which is not easy to avoid - if that is
the actual cause, this should provide a defence, if not really a fix.
 1.43  22-Jul-2018  kre Revert previous, change has nothing to do with DEBUG mode.
COming again (correctly) in a few seconds.
 1.42  22-Jul-2018  kre DEBUG mode only change (ie: no effect to any normal shell).

Add tracing of pattern matching (aid in debugging various issues.)
 1.41  05-Jul-2017  kre branches: 1.41.4; 1.41.6;

DEBUG and white space changes only. Convert TRACE() calls for DEBUg mode
to the new style. NFC (when not debugging sh).
 1.40  07-May-2017  kre branches: 1.40.2;

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?]
 1.39  29-Apr-2017  kre Fix several problems with the implementation of the "trap" command
(that is, with the command itself, not with the traps that are
executed, if any).

- "trap -- -l" is not rational, permit the (non-std) -l option only
when given as the sole arg (ie: "trap -l").
- "trap --" is the same as just "trap" (and -- is ignored for below)
- "trap action" generates a usage message (there must be at least one condition)
- "trap N [condition...]" (the old form with a numeric first arg, to reset
traps to default, instead of "trap - condition...") is properly detected.
In particular while "trap 1 2 3" resets sighup sigint and siquit handlers
to default, "trap hup int quit" runs the "hup" command on sigint or sigquit
and does nothing to sighup at all.
- actions can start with "-" (as can commands in general) - it may be unusual
or even unwise, but it is not prohibited, and should work
- bad conditions (signal names/numbers) are just a usage error (resulting in
non-zero "exit status" (and a diagnostic on stderr)) they do not cause
the script to abort (as a syntax error in a special builtin would.)
(so says posix, very explicitly.)
- when outputting the trap list ("trap") properly quote null actions
(ignored conditions). This has the side effect of also generating an
explicit null string ('') in other cases where null values are output,
such as when reporting var values ("set") but that's OK, and might be
better (VAR= and VAR='' mean the same, but the latter is more obvious.)

We still do not properly handle traps=$(trap) (ie: it does not work at all,
and should) but that's a different problem that needs fixing in another place.
 1.38  26-Apr-2017  kre Deal with traps that reset the (same) trap in the trap handler
(avoid referrencing memory that might have been freed).
From FreeBSD (ages ago, just not committed until now...)
 1.37  22-Aug-2015  christos branches: 1.37.6;
report the signal that wait was interrupted by, which is not always SIGINT
anymore.
 1.36  22-Aug-2015  christos Process pending signals while waiting for a job:
$ cat << EOF > hup.sh
#!/bin/sh
trap 'echo SIGHUP; exit 1' 1
sleep 10000 &
wait
EOF
$ chmod +x ./hup.sh
$ ./hup.sh &
$ kill -HUP %1
 1.35  18-Jun-2011  christos branches: 1.35.4; 1.35.22;
PR/45069: Henning Petersen: Use prototypes from builtins.h .
 1.34  15-Feb-2008  matt branches: 1.34.24;
Fix inconsistent definitions
 1.33  15-Jul-2005  christos branches: 1.33.10;
Allow trap to work on ignored signals when the shell is interactive.
 1.32  11-Jul-2005  christos Don't hard ignore signals that were ignored by our environment, because
when we try to set a trap on them it will not work. Also while I am here:
1. don't change the action status if the signal system call failed.
2. don't try to sigignore it if signal failed.
3. clear the signal mask in case our parent blocked it for us.
 1.31  11-Jan-2005  christos PR/28940: David Laight: /bin/sh doesn't quote the output of trap.
 1.30  26-Aug-2003  jmmv Use '\0' instead of NULL in two checks (we are not checking for a pointer
value). While here, add a missing whitespace.
 1.29  07-Aug-2003  agc Move UCB-licensed code from 4-clause to 3-clause licence.

Patches provided by Joel Baker in PR 22249, verified by myself.
 1.28  24-Nov-2002  christos Fixes from David Laight:
- ansification
- format of output of jobs command (etc)
- job identiers %+, %- etc
- $? and $(...)
- correct quoting of output of set, export -p and readonly -p
- differentiation between nornal and 'posix special' builtins
- correct behaviour (posix) for errors on builtins and special builtins
- builtin printf and kill
- set -o debug (if compiled with DEBUG)
- cd src obj (as ksh - too useful to do without)
- unset -e name, remove non-readonly variable from export list.
(so I could unset -e PS1 before running the test shell...)
 1.27  27-Sep-2002  christos VFork()ing shell: From elric@netbsd.org:
Plus my changes:
- walking process group fix in foregrounding a job.
- reset of process group in parent shell if interrupted before the wait.
- move INTON lower in the dowait so that the job structure is
consistent.
- error check all setpgid(), tcsetpgrp() calls.
- eliminate unneeded strpgid() call.
- check that we don't belong in the process group before we try to
set it.
 1.26  18-Mar-2001  wulf branches: 1.26.2;
Extended functionality of the trap builtin, which now closely follows
POSIX recommendations.

- trap now accepts signal names and signal numbers
e.g. INT, SIGINT, 2
- added option -l that outputs a list of valid signals
- added signal EXIT to list of valid signals
- a `-' in the action part will reset specified signal to their
default behaviour
- changed standard output format to make it suitable as an input
to another shell that achieves the same trapping results
 1.25  04-Feb-2001  christos remove redundant declarations and nexted externs.
 1.24  22-May-2000  elric branches: 1.24.4;
Back out previous vfork changes.
 1.23  13-May-2000  elric Now we use vfork(2) instead of fork(2) when we can.
 1.22  27-Jan-2000  christos Fix bin/9184, bin/9194, bin/9265, bin/9266
Exitcode and negation problems (From Martin Husemann)
 1.21  27-Mar-1999  christos When we execute commands from a shell script, make sure that the signals
are being caught (reported by Alexis Rosen), similar to the -c case.

#!/bin/sh
vi "$@"

^C when the script is running...
 1.20  05-Feb-1999  christos Fix the -c problem differently. We cannot just ignore SIGINT etc, otherwise
we cannot interrupt sh -c <command>
 1.19  18-Jan-1999  christos PR/6213: Urban Boquist: /bin/sh does not handle a trapped signal correctly
The problem was that system calls got restarted after a signal,
instead of returning EINTR. Thus the read builtin, had no way to
know that a signal occured that could change the course of execution.
Since the code has sprinkled checks for EINTR all over the place,
it is supposed to work properly with non restartable syscalls.
The fix is to use siginterrupt(signo, 1), before setting a signal
handler, to make sure that system calls don't get restarted.
 1.18  28-Jul-1998  mycroft Delint.
 1.17  04-Jul-1997  christos Fix compiler warnings.
 1.16  16-Oct-1996  christos PR/2808: Remove trailing whitespace (from FreeBSD)
 1.15  07-Jun-1995  christos branches: 1.15.6;
Ignore result of sigaction when setting traps. Traps will succeed even
on SIGKILL or SIGSTOP. This is what other bourne shells do. (suggested
by mycroft)
 1.14  05-Jun-1995  christos Avoid trapping SIGKILL. Pretend that we did, so that we will not keep
failing trying to trap it later. This is what the other bourne shells do.
 1.13  11-May-1995  christos Merge in my changes from vangogh, and fix the x=`false`; echo $? == 0
bug.
 1.12  21-Mar-1995  cgd convert to new RCS id conventions.
 1.11  23-Dec-1994  cgd be more careful with casts.
 1.10  05-Dec-1994  cgd clean up further. more patches from Jim Jegers
 1.9  11-Jun-1994  mycroft Add RCS ids.
 1.8  12-May-1994  jtc last sys_signame[] changes; shell can now be built from scratch
 1.7  12-May-1994  jtc Include appropriate header files to bring function prototypes into scope.
 1.6  11-May-1994  jtc sync with 4.4lite
 1.5  06-Aug-1993  mycroft Use sys_signame[].
 1.4  01-Aug-1993  mycroft Add RCS identifiers.
 1.3  23-Mar-1993  cgd changed "Id" to "Header" for rcsids
 1.2  22-Mar-1993  cgd added rcs ids to all files
 1.1  21-Mar-1993  cgd branches: 1.1.1;
Initial revision
 1.1.1.2  11-May-1994  jtc 44lite code
 1.1.1.1  21-Mar-1993  cgd initial import of 386bsd-0.1 sources
 1.15.6.1  26-Jan-1997  rat Update /bin/sh from trunk per request of Christos Zoulas. Fixes
many bugs.
 1.24.4.3  23-Feb-2002  he Pull up revisions 1.25-1.26 (requested by jonb):
Extend functionality of the trap builtin, which now more closely
follows POSIX recommendations:
o accept signal names as well as signal numbers
o add ``-l'' option which outputs list of valid signals
o add signal EXIT to list of valid signals
o an ``-'' in the action part will reset signal to default behaviour
o changed standard output of ``trap'' to make it suitable as
subsequent input
Also various cleanups of redundant declarations and nested externs.
 1.24.4.2  18-Mar-2001  wulf Reversed submission of trap.c and sh.1 to wrong branch
 1.24.4.1  17-Mar-2001  wulf Extended functionality of the trap builtin, which now closely follows
POSIX recommendations.

- trap now accepts signal names and signal numbers
e.g. INT, SIGINT, 2
- added option -l that outputs a list of valid signals
- added signal EXIT to list of valid signals
- a `-' in the action part will reset specified signal to their
default behaviour
- changed standard output format to make it suitable as an input
to another shell that achieves the same trapping results
 1.26.2.1  27-Mar-2002  elric Doing the vfork work on ash on a branch to try to shake out the
problems before I expose everyone to them. This checkin represents
a merge of the prior work, which I backed out a while ago, to the
HEAD only and does not incorporate any additional bugfixes. The
additional bugfixes and code-cleanup will occur in later checkins.

For reference the patches that were used are:
cvs diff -kk -r1.51 -r1.55 eval.c | patch
cvs diff -kk -r1.27 -r1.28 exec.c | patch
cvs diff -kk -r1.15 -r1.16 exec.h | patch
cvs diff -kk -r1.32 -r1.33 input.c | patch
cvs diff -kk -r1.10 -r1.11 input.h | patch
cvs diff -kk -r1.32 -r1.35 jobs.c | patch
cvs diff -kk -r1.9 -r1.11 jobs.h | patch
cvs diff -kk -r1.36 -r1.37 main.c | patch
cvs diff -kk -r1.20 -r1.21 redir.c | patch
cvs diff -kk -r1.10 -r1.11 redir.h | patch
cvs diff -kk -r1.10 -r1.12 shell.h | patch
cvs diff -kk -r1.22 -r1.23 trap.c | patch
cvs diff -kk -r1.12 -r1.13 trap.h | patch
cvs diff -kk -r1.23 -r1.24 var.c | patch
cvs diff -kk -r1.16 -r1.17 var.h | patch

All other changes were simply the resolution of the resulting
conflicts, which occured only in the merge of jobs.c.

Begins to address PR: bin/5475
 1.33.10.1  23-Mar-2008  matt sync with HEAD
 1.34.24.1  23-Jun-2011  cherry Catchup with rmind-uvmplock merge.
 1.35.22.1  04-Nov-2015  riz Pull up following revision(s) (requested by christos in ticket #964):
bin/sh/jobs.c: revision 1.74
bin/sh/jobs.c: revision 1.75
bin/sh/trap.c: revision 1.36
bin/sh/trap.c: revision 1.37
bin/sh/trap.h: revision 1.21
bin/sh/trap.h: revision 1.22
Process pending signals while waiting for a job:
$ cat << EOF > hup.sh
#!/bin/sh
trap 'echo SIGHUP; exit 1' 1
sleep 10000 &
wait
EOF
$ chmod +x ./hup.sh
$ ./hup.sh &
$ kill -HUP %1
report the signal that wait was interrupted by, which is not always SIGINT
anymore.
 1.35.4.1  15-Nov-2015  bouyer Pull up following revision(s) (requested by christos in ticket #1323):
bin/sh/jobs.c: revision 1.74
bin/sh/jobs.c: revision 1.75
bin/sh/trap.c: revision 1.36
bin/sh/trap.c: revision 1.37
bin/sh/trap.h: revision 1.21
bin/sh/trap.h: revision 1.22
Process pending signals while waiting for a job:
$ cat << EOF > hup.sh
#!/bin/sh
trap 'echo SIGHUP; exit 1' 1
sleep 10000 &
wait
EOF
$ chmod +x ./hup.sh
$ ./hup.sh &
$ kill -HUP %1
report the signal that wait was interrupted by, which is not always SIGINT
anymore.
 1.37.6.2  11-May-2017  pgoyette Sync with HEAD
 1.37.6.1  02-May-2017  pgoyette Sync with HEAD - tag prg-localcount2-base1
 1.40.2.2  25-Aug-2018  martin Pull up following revision(s) (requested by kre in ticket #987):

bin/sh/trap.c: revision 1.44

PR bin/36532 (perhaps)

This is more or less the same patch as provided in the PR
(just 11 years later, so changed a bit) by woods@...

Since there is no known way to actually cause the reported crash,
we may never know if this change actually fixes anything. But
even if it doesn't it certainly cannot hurt.

There is a potential race which could possibly explain the issue
(see commentary in the PR) which is not easy to avoid - if that is
the actual cause, this should provide a defence, if not really a fix.
 1.40.2.1  23-Jul-2017  snj Pull up following revision(s) (requested by kre in ticket #103):
bin/kill/kill.c: 1.28
bin/sh/Makefile: 1.111-1.113
bin/sh/arith_token.c: 1.5
bin/sh/arith_tokens.h: 1.2
bin/sh/arithmetic.c: 1.3
bin/sh/arithmetic.h: 1.2
bin/sh/bltin/bltin.h: 1.15
bin/sh/cd.c: 1.49-1.50
bin/sh/error.c: 1.40
bin/sh/eval.c: 1.142-1.151
bin/sh/exec.c: 1.49-1.51
bin/sh/exec.h: 1.26
bin/sh/expand.c: 1.113-1.119
bin/sh/expand.h: 1.23
bin/sh/histedit.c: 1.49-1.52
bin/sh/input.c: 1.57-1.60
bin/sh/input.h: 1.19-1.20
bin/sh/jobs.c: 1.86-1.87
bin/sh/main.c: 1.71-1.72
bin/sh/memalloc.c: 1.30
bin/sh/memalloc.h: 1.17
bin/sh/mknodenames.sh: 1.4
bin/sh/mkoptions.sh: 1.3-1.4
bin/sh/myhistedit.h: 1.12-1.13
bin/sh/nodetypes: 1.16-1.18
bin/sh/option.list: 1.3-1.5
bin/sh/parser.c: 1.133-1.141
bin/sh/parser.h: 1.22-1.23
bin/sh/redir.c: 1.58
bin/sh/redir.h: 1.24
bin/sh/sh.1: 1.149-1.159
bin/sh/shell.h: 1.24
bin/sh/show.c: 1.43-1.47
bin/sh/show.h: 1.11
bin/sh/syntax.c: 1.4
bin/sh/syntax.h: 1.8
bin/sh/trap.c: 1.41
bin/sh/var.c: 1.56-1.65
bin/sh/var.h: 1.29-1.35
An initial attempt at implementing LINENO to meet the specs.
Aside from one problem (not too hard to fix if it was ever needed) this version
does about as well as most other shell implementations when expanding
$((LINENO)) and better for ${LINENO} as it retains the "LINENO hack" for the
latter, and that is very accurate.
Unfortunately that means that ${LINENO} and $((LINENO)) do not always produce
the same value when used on the same line (a defect that other shells do not
share - aside from the FreeBSD sh as it is today, where only the LINENO hack
exists and so (like for us before this commit) $((LINENO)) is always either
0, or at least whatever value was last set, perhaps by
LINENO=${LINENO}
which does actually work ... for that one line...)
This could be corrected by simply removing the LINENO hack (look for the string
LINENO in parser.c) in which case ${LINENO} and $((LINENO)) would give the
same (not perfectly accurate) values, as do most other shells.
POSIX requires that LINENO be set before each command, and this implementation
does that fairly literally - except that we only bother before the commands
which actually expand words (for, case and simple commands). Unfortunately
this forgot that expansions also occur in redirects, and the other compound
commands can also have redirects, so if a redirect on one of the other compound
commands wants to use the value of $((LINENO)) as a part of a generated file
name, then it will get an incorrect value. This is the "one problem" above.
(Because the LINENO hack is still enabled, using ${LINENO} works.)
This could be fixed, but as this version of the LINENO implementation is just
for reference purposes (it will be superseded within minutes by a better one)
I won't bother. However should anyone else decide that this is a better choice
(it is probably a smaller implementation, in terms of code & data space then
the replacement, but also I would expect, slower, and definitely less accurate)
this defect is something to bear in mind, and fix.
This version retains the *BSD historical practice that line numbers in functions
(all functions) count from 1 from the start of the function, and elsewhere,
start from 1 from where the shell started reading the input file/stream in
question. In an "eval" expression the line number starts at the line of the
"eval" (and then increases if the input is a multi-line string).
Note: this version is not documented (beyond as much as LINENO was before)
hence this slightly longer than usual commit message.
A better LINENO implementation. This version deletes (well, #if 0's out)
the LINENO hack, and uses the LINENO var for both ${LINENO} and $((LINENO)).
(Code to invert the LINENO hack when required, like when de-compiling the
execution tree to provide the "jobs" command strings, is still included,
that can be deleted when the LINENO hack is completely removed - look for
refs to VSLINENO throughout the code. The var funclinno in parser.c can
also be removed, it is used only for the LINENO hack.)
This version produces accurate results: $((LINENO)) was made as accurate
as the LINENO hack made ${LINENO} which is very good. That's why the
LINENO hack is not yet completely removed, so it can be easily re-enabled.
If you can tell the difference when it is in use, or not in use, then
something has broken (or I managed to miss a case somewhere.)
The way that LINENO works is documented in its own (new) section in the
man page, so nothing more about that, or the new options, etc, here.
This version introduces the possibility of having a "reference" function
associated with a variable, which gets called whenever the value of the
variable is required (that's what implements LINENO). There is just
one function pointer however, so any particular variable gets at most
one of the set function (as used for PATH, etc) or the reference function.
The VFUNCREF bit in the var flags indicates which func the variable in
question uses (if any - the func ptr, as before, can be NULL).
I would not call the results of this perfect yet, but it is close.
Unbreak (at least) i386 build .... I have no idea why this built for me on
amd64 (problem was missing prototype for snprintf witout <stdio.h>)
While here, add some (DEBUG mode only) tracing that proved useful in
solving another problem.
Set the line number before expanding args, not after. As the line_number
would have usually been set earlier, this change is mostly an effective
no-op, but it is better this way (just in case) - not observed to have
caused any problems.
Undo some over agressive fixes for a (pre-commit) bug that did not
need these changes to be fixed - and these cause problems in another
absurd use case. Either of these issues is unlikely to be seen by
anyone who isn't an idiot masochist...
PR bin/52280
removescapes_nl in expari() even when not quoted,
CRTNONL's appear regardless of quoting (unlike CTLESC).
New sentence, new line. Whitespace.
Improve the (new) LINENO section, markup changes (with thanks to wiz@ for
assistace) and some better wording in a few placed.
I am an idiot... revert the previous unintended commit.
Remove some left over baggage from the LINENO v1 implementation that
didn't get removed with v2, and should have. This would have had
(I think, without having tested it) one very minor effect on the way
LINENO worked in the v2 implementation, but my guess is it would have
taken a long time before anyone noticed...
Correct spelling in comments of DEBUG only code...
(Perhaps) temporary fix to pkgtools (cwrappers) build (configure).
Expanding `` containing \ \n sequences looks to have been giving
problems. I don't think this is the correct fix, but it will do
no worse harm than (perhaps) incorrectly calculating LINENO in this
kind of (rare) circumstance. I'll look and see if there should be
a better fix later.
s/volatile/const/ -- wonderful how opposites attract like this.
NFC (normal use) - DEBUG only change, when showing empty arg list don't
omit terminating \n.
Free stack memory in a couple of obscure cases where it wasn't
being done (one in probably dead code that is never compiled, the other
in a very rare error case.) Since it is stack memory it wasn't lost
in any case, just held longer than needed.
Many internal memory management type fixes.
PR bin/52302 (core dump with interactive shell, here doc and error
on same line) is fixed. (An old bug.)
echo "$( echo x; for a in $( seq 1000 ); do printf '%s\n'; done; echo y )"
consistently prints 1002 lines (x, 1000 empty ones, then y) as it should
(And you don't want to know what it did before, or why.) (Another old one.)
(Recently added) Problems with ~ expansion fixed (mem management related).
Proper fix for the cwrappers configure problem (which includes the quick
fix that was done earlier, but extends upon that to be correct). (This was
another newly added problem.)
And the really devious (and rare) old bug - if STACKSTRNUL() needs to
allocate a new buffer in which to store the \0, calculate the size of
the string space remaining correctly, unlike when SPUTC() grows the
buffer, there is no actual data being stored in the STACKSTRNUL()
case - the string space remaining was calculated as one byte too few.
That would be harmless, unless the next buffer also filled, in which
case it was assumed that it was really full, not one byte less, meaning
one junk char (a nul, or anything) was being copied into the next (even
bigger buffer) corrupting the data.
Consistent use of stalloc() to allocate a new block of (stack) memory,
and grabstackstr() to claim a block of (stack) memory that had already
been occupied but not claimed as in use. Since grabstackstr is implemented
as just a call to stalloc() this is a no-op change in practice, but makes
it much easier to comprehend what is really happening. Previous code
sometimes used stalloc() when the use case was really for grabstackstr().
Change grabstackstr() to actually use the arg passed to it, instead of
(not much better than) guessing how much space to claim,
More care when using unstalloc()/ungrabstackstr() to return space, and in
particular when the stack must be returned to its previous state, rather than
just returning no-longer needed space, neither of those work. They also don't
work properly if there have been (really, even might have been) any stack mem
allocations since the last stalloc()/grabstackstr(). (If we know there
cannot have been then the alloc/release sequence is kind of pointless.)
To work correctly in general we must use setstackmark()/popstackmark() so
do that when needed. Have those also save/restore the top of stack string
space remaining.
[Aside: for those reading this, the "stack" mentioned is not
in any way related to the thing used for maintaining the C
function call state, ie: the "stack segment" of the program,
but the shell's internal memory management strategy.]
More comments to better explain what is happening in some cases.
Also cleaned up some hopelessly broken DEBUG mode data that were
recently added (no effect on anyone but the poor semi-human attempting
to make sense of it...).
User visible changes:
Proper counting of line numbers when a here document is delimited
by a multi-line end-delimiter, as in
cat << 'REALLY
END'
here doc line 1
here doc line 2
REALLY
END
(which is an obscure case, but nothing says should not work.) The \n
in the end-delimiter of the here doc (the last one) was not incrementing
the line number, which from that point on in the script would be 1 too
low (or more, for end-delimiters with more than one \n in them.)
With tilde expansion:
unset HOME; echo ~
changed to return getpwuid(getuid())->pw_home instead of failing (returning ~)
POSIX says this is unspecified, which makes it difficult for a script to
compensate for being run without HOME set (as in env -i sh script), so
while not able to be used portably, this seems like a useful extension
(and is implemented the same way by some other shells).
Further, with
HOME=; printf %s ~
we now write nothing (which is required by POSIX - which requires ~ to
expand to the value of $HOME if it is set) previously if $HOME (in this
case) or a user's directory in the passwd file (for ~user) were a null
STRING, We failed the ~ expansion and left behind '~' or '~user'.
Changed the long name for the -L option from lineno_fn_relative
to local_lineno as the latter seemed to be marginally more popular,
and perhaps more importantly, is the same length as the peviously
existing quietprofile option, which means the man page indentation
for the list of options can return to (about) what it was before...
(That is, less indented, which means more data/line, which means less
lines of man page - a good thing!)
Cosmetic changes to variable flags - make their values more suited
to my delicate sensibilities... (NFC).
Arrange not to barf (ever) if some turkey makes _ readonly. Do this
by adding a VNOERROR flag that causes errors in var setting to be
ignored (intended use is only for internal shell var setting, like of "_").
(nb: invalid var name errors ignore this flag, but those should never
occur on a var set by the shell itself.)
From FreeBSD: don't simply discard memory if a variable is not set for
any reason (including because it is readonly) if the var's value had
been malloc'd. Free it instead...
NFC - DEBUG changes, update this to new TRACE method.
KNF - white space and comment formatting.
NFC - DEBUG mode only change - convert this to the new TRACE() format.
NFC - DEBUG mode only change - complete a change made earlier (marking
the line number when included in the trace line tag to show whether it
comes from the parser, or the elsewhere as they tend to be quite different).
Initially only one case was changed, while I pondered whether I liked it
or not. Now it is all done... Also when there is a line tag at all,
always include the root/sub-shell indicator character, not only when the
pid is included.
NFC: DEBUG related comment change - catch up with reality.
NFC: DEBUG mode only change. Fix botched cleanup of one TRACE().
"b" more forgiving when sorting options to allow reasonable (and intended)
flexibility in option.list format. Changes nothing for current option.list.
Now that excessive use of STACKSTRNUL has served its purpose (well, accidental
purpose) in exposing the bug in its implementation, go back to not using
it when not needed for DEBUG TRACE purposes. This change should have no
practical effect on either a DEBUG shell (where the STACKSTRNUL() calls
remain) or a non DEBUG shell where they are not needed.
Correct the initial line number used for processing -c arg strings.
(It was inheriting the value from end of profile file processing) - I didn't
notice before as I usually test with empty or no profile files to avoid
complications. Trivial change which should have very limited impact.
Fix from FreeBSD (applied there in July 2008...)
Don't dump core with input like sh -c 'x=; echo >&$x' - that is where
the word after a >& or <& redirect expands to nothing at all.
Another fix from FreeBSD (this one from April 2009).
When processing a string (as in eval, trap, or sh -c) don't allow
trailing \n's to destroy the exit status of the last command executed.
That is:
sh -c 'false
'
echo $?
should produce 1, not 0.
It is amazing what nonsense appears to work sometimes... (all my nonsense too!)
Two bugs here, one benign because of the way the script is used.
The other hidden by NetBSD's sort being stable, and the data not really
requiring sorting at all...
So as it happens these fixes change nothing, but they are needed anyway.
(The contents of the generated file are only used in DEBUG shells, so
this is really even less important than it seems.)
Another ancient (highly improbable) bug bites the dust. This one
caused by incorrect macro usage (ie: using the wrong one) which has
been in the sources since version 1.1 (ie: forever).
Like the previous (STACKSTRNUL) bug, the probability of this one
actually occurring has been infinitesimal but the LINENO code increases
that to infinitesimal and a smidgen... (or a few, depending upon usage).
Still, apparently that was enough, Kamil Rytarowski discovered that the
zsh configure script (damn competition!) managed to trigger this problem.
source .editrc after we initialize so that commands persist!
Make arg parsing in kill POSIX compatible with POSIX (XBD 2.12) by
parsing the way getopt(3) would, if only it could handle the (required)
-signumber and -signame options. This adds two "features" to kill,
-ssigname and -lstatus now work (ie: one word with all of the '-', the
option letter, and its value) and "--" also now works (kill -- -pid1 pid2
will not attempt to send the pid1 signal to pid2, but rather SIGTERM
to the pid1 process group and pid2). It is still the case that (apart
from --) at most 1 option is permitted (-l, -s, -signame, or -signumber.)
Note that we now have an ambiguity, -sname might mean "-s name" or
send the signal "sname" - if one of those turns out to be valid, that
will be accepted, otherwise the error message will indicate that "sname"
is not a valid signal name, not that "name" is not. Keeping the "-s"
and signal name as separate words avoids this issue.
Also caution: should someone be weird enough to define a new signal
name (as in the part after SIG) which is almost the same name as an
existing name that starts with 'S' by adding an extra 'S' prepended
(eg: adding a SIGSSYS) then the ambiguity problem becomes much worse.
In that case "kill -ssys" will be resolved in favour of the "-s"
flag being used (the more modern syntax) and would send a SIGSYS, rather
that a SIGSSYS. So don't do that.
While here, switch to using signalname(3) (bye bye NSIG, et. al.), add
some constipation, and show a little pride in formatting the signal names
for "kill -l" (and in the usage when appropriate -- same routine.) Respect
COLUMNS (POSIX XBD 8.3) as primary specification of the width (terminal width,
not number of columns to print) for kill -l, a very small value for COLUMNS
will cause kill -l output to list signals one per line, a very large
value will cause them all to be listed on one line.) (eg: "COLUMNS=1 kill -l")
TODO: the signal printing for "trap -l" and that for "kill -l"
should be switched to use a common routine (for the sh builtin versions.)
All changes of relevance here are to bin/kill - the (minor) changes to bin/sh
are only to properly expose the builtin version of getenv(3) so the builtin
version of kill can use it (ie: make its prototype available.)
Properly support EDITRC - use it as (naming) the file when setting
up libedit, and re-do the config whenever EDITRC is set.
Get rid of workarounds for ancient groff html backend.
Simplify macro usage.
Make one example more like a real world possibility (it still isn't, but
is closer) - though the actual content is irrelevant to the point being made.
Add literal prompt support this allows one to do:
CA="$(printf '\1')"
PS1="${CA}$(tput bold)${CA}\$${CA}$(tput sgr0)${CA} "
Now libedit supports embedded mode switch sequence, improve sh
support for them (adds PSlit variable to set the magic character).
NFC: DEBUG only change - provide an externally visible (to the DEBUG sh
internals) interface to one of the internal (private to trace code) functions
Include redirections in trace output from "set -x"
Implement PS1, PS2 and PS4 expansions (variable expansions, arithmetic
expansions, and if enabled by the promptcmds option, command substitutions.)
Implement a bunch of new shell environment variables. many mostly useful
in prompts when expanded at prompt time, but all available for general use.
Many of the new ones are not available in SMALL shells (they work as normal
if assigned, but the shell does not set or use them - and there is no magic
in a SMALL shell (usually for install media.))
Omnibus manual update for prompt expansions and new variables. Throw in
some random cleanups as a bonus.
Correct a markup typo (why did I not see this before the prev commit??)
Sort options (our default is 0..9AaBbZz).
Fix markup problems and a typo.
Make $- list flags in the same order they appear in sh(1)
Do a better job of detecting the error in pkgsrc/devel/libbson-1.6.3's
configure script, ie: $(( which is intended to be a sub-shell in a
command substitution, but is an arith subst instead, it needs to be
written $( ( to do as intended. Instead of just blindly carrying on to
find the missing )) somewhere, anywhere, give up as soon as we have seen
an unbalanced ')' that isn't immediately followed by another ')' which
in a valid arith subst it always would be.
While here, there has been a comment in the code for quite a while noting a
difference in the standard between the text descr & grammar when it comes to
the syntax of case statements. Add more comments to explain why parsing it
as we do is in fact definitely the correct way (ie: the grammar wins arguments
like this...).
DEBUG and white space changes only. Convert TRACE() calls for DEBUg mode
to the new style. NFC (when not debugging sh).
Mostly DEBUG and white space changes. Convert DEEBUG TRACE() calls to
the new format. Also #if 0 a function definition that is used nowhere.
While here, change the function of pushfile() slightly - it now sets
the buf pointer in the top (new) input descriptor to NULL, instead of
simply leaving it - code that needs a buffer always (before and after)
must malloc() one and assign it after the call. But code which does not
(which will be reading from a string or similar) now does not have to
explicitly set it to NULL (cleaner interface.) NFC intended (or observed.)
DEBUG changes: convert DEBUG TRACE() calls to new format.
ALso, cause exec failures to always cause the shell to exit with
status 126 or 127, whatever the cause. 127 is intended for lookup
failures (and is used that way), 126 is used for anything else that
goes wrong (as in several other shells.) We no longer use 2 (more easily
confused with an exit status of the command exec'd) for shell exec failures.
DEBUG only changes. Convert the TRACE() calls in the remaining files
that still used it to the new format. NFC.
Fix a reference after free (and consequent nonsense diagnostic for
attempts to set readonly variables) I added in 1.60 by incompletely
copying the FreeBSD fix for the lost memory issue.
 1.41.6.4  21-Apr-2020  martin Ooops, restore accidently removed files from merge mishap
 1.41.6.3  21-Apr-2020  martin Sync with HEAD
 1.41.6.2  08-Apr-2020  martin Merge changes from current as of 20200406
 1.41.6.1  10-Jun-2019  christos Sync with HEAD
 1.41.4.5  18-Jan-2019  pgoyette Synch with HEAD
 1.41.4.4  26-Dec-2018  pgoyette Sync with HEAD, resolve a few conflicts
 1.41.4.3  26-Nov-2018  pgoyette Sync with HEAD, resolve a couple of conflicts
 1.41.4.2  06-Sep-2018  pgoyette Sync with HEAD

Resolve a couple of conflicts (result of the uimin/uimax changes)
 1.41.4.1  28-Jul-2018  pgoyette Sync with HEAD
 1.52.2.1  11-Dec-2019  martin Pull up following revision(s) (requested by kre in ticket #542):

bin/sh/eval.c: revision 1.176
bin/sh/trap.c: revision 1.53

PR bin/54743

Having traps set should not enforce a fork for the next command,
whatever that command happens to be, only for commands which would
normally fork if they weren't the last command expected to be
executed (ie: builtins and functions shouldn't be exexuted in a
sub-shell merely because a trap is set).

As it was (for example)
trap 'whatever' SIGANY; wait $anypid
was guaranteed to fail the wait, as the subshell it was executed
in could not have any children.

XXX pullup -9

PR bin/54743

If a builtin command or function is the final command intended to be
executed, and is interrupted by a caught signal, the trap handler for
that signal was not executed - the shell simply exited (an exit trap
handler would still have been run - if there was one the handler
for the signal may have been invoked during the execution of the
exit trap handler, which, if it happened, is incorrect sequencing).

Now, if we're exiting, and there are pending signals, run their handlers
just before running the EXIT trap handler, if any.
There are almost certainly plenty more issues with traps that need
solving. Later,

XXX pullup -9
(-8 is too different in this area, and this problem suitably obscure,
that we won't bother) (the -7 sh is simply obsolete).
 1.56.4.1  02-Aug-2025  perseant Sync with HEAD

RSS XML Feed