Here we go again... One more time to redo how here docs are
processed (it has been a few years since the last time!)
This is actually a relatively minor change, mostly to timimg
(to just when things happen). Now here docs are expanded at the
same time the "filename" word in a redirect is expanded, rather than
later when the heredoc was being sent to its process. This actually
makes things more consistent - but does break one of the ATF tests
which was testing that we were (effectively) internally inconsistent
in this area.
Not all shells agree on the context in which redirection expansions
should happen, some make any side effects visible to the parent shell
(the majority do) others do the redirection expansions in a subshell
so any side effcts are lost. We used to have a foot in each camp,
with the majority for everything but here docs, and the minority for
here docs. Now we're all the way with LBJ ... (or something like that).
all the sh options, also used with "set", are listed) in response to
a discussion on icb conveyed to me by Darrin B. Jewell.
A few improvements to the description of the "set" built-in as well.
Bump Dd to cover all of this month's changes (so far).
Make "hash" exit(!=0) (ie: exit(1)) if it writes an error message to
stderr as required by POSIX (it was writing "not found" errors, yet
still doing exit(0)).
Whether, when doing "hash foobar", and "foobar" is not found as a command
(not a built-in, not a function, and not found via a PATH search), that
should be considered an error differs between shells. All of the ksh
descendant shells say "no", write no error message in this case, and
exit(0) if no other errors occur. Other shells (essentially all) do
consider it an error, write a message to stderr, and exit(1) when this happens.
POSIX isn't clear, the bug report:
https://austingroupbugs.net/view.php?id=1460
which is not yet resolved, suggests that the outcome will be that
this is to be unspecified. Given the diversity, there might be no
other choice.
Have a foot in both camps - default to the "other shell" behaviour,
but add a -e option (no errors ... applies only to these "not found"
errors) to generate the ksh behaviour. Without other errors (like an
unknown option, etc) "hash -e anyname" will always exit(0).
See the PR for details on how it all works now, or read the updated man page.
While here, when hash is in its other mode (reporting what is in the
table) check for I/O errors on stdout, and exit(1) (with an error
message!) if any occurred. This does not apply to output generated
by the -v option when command names are given (that output is incidental).
In sh.1 document all of this. Also add documentation for a bunch of
other options the hash command has had for years, but which were never
documented. And while there, clean up some other sections I noticed
needed improving (either formatting or content or both).
This affects (as best I can tell) only uses of ${LINENO} in PS4
when -x is enabled (and perhaps only when the list contains no
expansions). "for" like "case" (which was already handled) is
special in that it generates trace output before actually executing
any kind of simple command.
identified with the -u flag (that is, I hope I identified all
the ones that were missing it).
This change is a no-op (NFC) as the -u flag does nothing.
Still, just in case we find a use for it one day, and just as a
matter of general principle, we should get this correct.
echo.c: In function 'main':
echo.c:74:1: warning: control reaches end of non-void function
This raises 2 issues.
First, why with WARNS set to 6, which should include just about
everything, was this not causing problems with everyday builds?
Surely falling off the end of a non-void function without returning
a specific value is one of the more basic errors that should be fixed.
(Whatever the name of the function). Is there a missing -Wxxx option?
And second, does C99 really promise:
Remove unnecessary call to exit(0); returning from main is equivalent
since C99.
in the sense that simply falling out of main() is exit(0)? Or is it
simply saying that the return value of main() is the exit status (which
has been true for much longer than since c99)?
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.
Be explicit about what happens to PWD after a successful cd command.
Also be very clear that "cd" and "cd -P" are the same thing, and
the only cd variant implemented.
Also, when it is appropriate to print the new directory after a cd
command, note that it happens if interactive (as it always has here)
and also if the posix option is set (for POSIX compat, where "interactive"
is irrelevant). Mention that "cd -" is a case where the new directory
is printed (along with paths relative to a non-empty CDPATH entry,
and where the "cd old new" (string replacement in curdir) is used.
While here document the new -e option to cd.
XXX pullup -9
In the pwd builtin, verify that curdir names '.' before
simply printing it. Never alter PWD or OLDPWD in the
pwd command.
Also while here, implement the (new: coming in POSIX, but has existed
for a while in several other shells) -e option to cd (with -e, cd -P
will exit(1) if the chdir() succeeds, but PWD cannot be discovered).
cd now prints the directory name used (if different from that given,
or cdprint is on) if interactive or (the new bit)in posix mode.
Some additional/changed comments added, and a DEBUG mode trace call
that was accidentally put inside an #if 0 block moved to where it
can do some good.
XXX pullup -9
for a function with unknown number & types of args, the compiler isn't
able to automatically convert to the correct type. Issue pointed out
in off list e-mail by Rolland Illig ... Thanks.
The first arg (pointer to where to put length of result) is of a known
type, so doesn't have the same issue - we can keep using NULL for that
one when the length isn't needed.
Also, make sure to return a correctly null terminated null string in
the (absurd) case that there are no non-null args to strstrcat() (though
there are much better ways to generate "" on the stack). Since there is
currently just one call in the code, and it has real string args, this
isn't an issue for now, but who knows, some day.
NFCI - if there is any real change, then it is a change that is required.
XXX pullup -9 (together with the previous changes)
After almost 30 years, finally do the right thing and read $HOME/.profile
rather than .profile in the initial directory (it was that way in version
1.1 ...) All other ash descendants seem to have fixed this long ago.
While here, copy a feature from FreeBSD which allows "set +p" (if a
shell run by a setuid process with the -p flag is privileged) to reset
the privileges. Once done (the set +p) it cannot be undone (a later
set -p sets the 'p' flag, but that's all it does) - that just becomes a
one bit storage location.
We do this, as (also copying from FreeBSD, and because it is the right
thing to do) we don't run .profile in a privileged shell - FreeBSD run
/etc/suid_profile in that case (not a good name, it also applies to setgid
shells) but I see no real need for that, we run /etc/profile in any case,
anything that would go in /etc/suid_profile can just go in /etc/profile
instead (with suitable guards so the commands only run in priv'd shells).
One or two minor DEBUG mode changes (notably having priv'd shells identify
themselves in the DEBUG trace) and sh.1 changes with doc of the "set +p"
change, the effect that has on $PSc and a few other wording tweaks.
XXX pullup -9 (not -8, this isn't worth it for the short lifetime
that has left - if it took 28+ years for anyone to notice this, it
cannot be having all that much effect).
Lint can handle __COPYRIGHT and __RCSID, so there is no need to hide
them anymore.
Use proper type 'bool' for nflag, ensure correct types via lint's strict
bool mode.
Remove unnecessary call to exit(0); returning from main is equivalent
since C99.
No functional change.
28 years was more than enough for the useless 'continue' statement in
this do-while-0 "loop". Without the 'continue' statement, there is no
need for the "loop" anymore. The comment at its top was confusing since
the word 'while' suggested a loop, but there was none, so remove that as
well.
Pointed out by Tom Ivar Helbekkmo on source-changes-d.
No change to the resulting binary.
Lint complained about the do-while-0 loop that contained a continue. It
didn't state the reason for it, but indeed the code looked complicated.
Rewrite the code to be less verbose and to use common coding patterns.
No functional change.
exec.c(575): error: continue in 'do ... while (0)' loop [323]
jobs.c(203): error: continue in 'do ... while (0)' loop [323]
It is certainly a rarely used feature, I saw it the first time today and
had to look up its meaning in the C standard. But after that, I don't
see why a 'continue' statement in a 'do while' loop should be an error.
Maybe a warning since up to now I thought that 'continue' would jump
back to the top of the loop, while it really jumps to the bottom of the
loop body, for all 3 kinds of loops.
No change to the resulting binary. The 'return' statements are necessary
for GCC to generate the exact same object code, even though they can be
removed without affecting the functionality, as seen before the 'else'.
a way, but made more serious with the recent changes).
The n>&n operation (more or less a no-op, except it clears CLOEXEC)
should precede almost everything else - and simply be made to fail if
an attempt is made to apply it to a sh internal fd.
We were renumbering the internal fd (the n> part considered first)
which was dumb, but OK, before, but now rejecting the operation
(the >&n) part when n should not be visible to the script. That
made something of a mess (and could lead to the shell believing its
job control tty was at a fd it never got moved to).
Do things in the correct order, and simply fail that case for internal
fds (for every other n>xxx for any xxx sh simply renumbers its internal fd
n to some other fd before attempting the operation, even n>&- ... those are
all fine).
[In all the above the '>' is used in place of any redirect operator].
and keep the rest of the shell aware of any changes.
While here, modify 'ulimit -aSH' to print both the soft and hard limits
for the resources, rather than just (in this case, as H comes last) the
hard limit. In any other case when both S and H are present, and we're
examining a limit, use the soft limit (just as if neither were given).
No change for setting limits (both are set, unless exactly one of -H
or -S is given). However, we now check for overflow when converting
the value to be assigned, rather than just truncating the value however
it happens to work out...
be available ("13") issue reported by Jan Schaumann on netbsd-users.
This fixes a bug in the earlier fix (a day or so ago) which could allow the
shell's idea of which fd range was in use by the script to get wildly
incorrect, but now also actually looks to see which fd's are in use as
renamed other user fd's during the lifetime of a redirection which needs
to be able to be undone (most redirections occur after a fork and are
permanent in the child process). Attempting to access such a fd (as with
attempts to access a fd in use by the shell for its own purposes) is treated
as an attempt to access a closed fd (EBADF). Attempting to reuse the fd
for some other purpose (which should be rare, even for scripts attempting
to cause problems, since the shell generally knows which fds the script
wants to use, and avoids them) will cause the renamed (renumbered) fd
to be renamed again (moved aside to some other available fd), just as
happens with the shell's private fds.
Also, when a generic fd is required, don't give up because of EMFILE
or similar unless there are no available fds at all (we might prefer >10
or bigger, but if there are none there, use anything). This avoids
redirection errors when ulimit -n has been set small, and all the fds >10
that are available have been used, but we need somewhere to park the old
user of a fd while we reuse that fd for the redirection.
by the shell were available for manipulation by scripts (or the user).
These issues were reported by Jan Schaumann on netbsd-users.
The first allows the user to reference sh internal fds, and is
a simple fix - any sh internal fd is simply treated as if it were closed
when referenced by the script. These fds can be discovered by
examining /proc/N/fd so it is not difficult for a script to discover
which fd it should attempt to access.
The second allows the user to reference a user level fd which is
one that is normally available to it, but at a point where it should
no longer be visible (when that fd has been redirected, for a built
in command, so the original fd needs to be saved so it can be restored,
the saving fd should not be accessible). It is not as easy for the
script to determine which fd to attempt here, as the relevant one
exists only during the lifetime of a built-in command (and similar),
but there are ways in some cases (aside from looking at /proc from
another process).
Fix this one by watching which fds the user script is attempting
to use, and avoid using those as temporary fds. This is possible in
this case as we know what command is being run, before we need to
save the fds it uses. That's different from the earlier case where
when the shell allocates its fds we have no idea what it might
reference later.
Also clean up a couple of other minor code issues (NFC intended) that
I noticed while here...
commands with multiple synopsis lines (eg: trap).
But there really must be a better way to achieve this effect than
the way it is accomplished here, and I'm hoping some wizard who
understands mdoc much better than I do will revert this change and
do it using some inspired magic incantation instead.
do setproctitle(NULL) (which is not the same thing at all). Do the
same with jobs -Z '' as setting the title to "sh: " isn't useful.
Improve the way this is documented, and note that it is only done
this way because zsh did it first (ie: pass on the balme, doing this
in the jobs command is simply absurd.)
by oguzismailuysal@gmail.com (2021-09-08) (applies to all ash descendant
shells).
There were places in the parser where newline tokens were handled
without reading any pending here documents (leaving those until a
later newline token).
Eg: in
: << do | for x in xxx
do
do echo $x
done
The here doc text (<<do) should start immediately after the next newline
(which is after xxx). But it wasn't happening until after the following
newline (after the line containing only "do").
Bizarrely, this
: << do | for x in xxx
do echo $x
do
done
"worked" because of that.
For other cases that also failed, see the hard_cases test case in
src/tests/bin/sh/t_here.sh Note that there's nothing magic about
the particular end delimiter word chosen here, any will do, using
the ones selected for the tests (and shown here) simply makes it
all more mysterious! The one here is the exact case reported.
Fix this by reading the here docs when processing newline tokens
when they are encountered in other than the "normal" way. Whether
this catches every possibility is unknown currently - may never be
known for certain, but there are no more I can currently think of.
No pullups needed, this isn't a significant enough bug (ie: no one
actually writes code like this) to warrant that.
Oguz <oguzismailuysal@gmail.com>
If echo detects an I/O error, it does exit(1) (that's fine) but then
the next echo also does exit(1) even without any errors of its own,
and every following echo writing to stdout does the same thing.
eg:
echo foo >&- ; echo $?; echo $?; ( echo $( echo $?; echo $?) ; echo $? )
1
1
1 1
1
The first echo writes nothing (stdout is closed) but does exit(1).
The second echo writes "1" (correct, the exit status of the previous
echo) and should exit(0) - but doesn't. This pattern continues...
While here, conform to the POSIX requirement on echo (and many other
standard utilities, but definitely not all) that when the utility
does exit(>0) a message must be written to stderr (and vice versa
in many cases). Our echo (as shown above) did the exit(1) part
when it detected the I/O error, but no message is sent to stderr.
Fix that while we're here.
Similar changes are required for /bin/echo (coming soon), and
/usr/bin/printf (which is also the sh builtin printf) - except
currently that one kind of conforms, as it ignores errors writing
to stdout (as do large numbers of other utilities). For many
programs that's kind of acceptable, but where the sole purpose of
the program is to write to stdout, it really isn't. Also to be
fixed soon.
Correct an issue found by Oguz <oguzismailuysal@gmail.com> and reported
in e-mail (on the bug-bash list initially!) with the code changed to deal
with PR bin/48875
With:
sh -c 'echo start at $SECONDS;
(sleep 3 & (sleep 1& wait) );
echo end at $SECONDS'
The shell should say "start at 0\nend at 1\n", but instead (before
this fix, in -9 and HEAD, but not -8) does "start at 0\nend at 3\n"
(Not in -8 as the 48875 changes were never pulled up)>
There was an old problem, fixed years ago, which cause the same symptom,
related to the way the jobs table was cleared (or not) in subshells, and
it seemed like that might have resurfaced.
But not so, the issue here is the sub-shell elimination, which was part
of the 48875 "fix" (not really, it wasn't really a bug, just sub-optimal
and unexpected behaviour).
What the shell actually has been running in this case is:
sh -c 'echo start at $SECONDS;
(sleep 3 & sleep 1& wait );
echo end at $SECONDS'
as the inner subshell was deemed unnecessary - all its parent would
do is wait for its exit status, and then exit with that status - we
may as well simply replace the current sub-shell with the new one,
let it do its thing, and we're done...
But not here, the running "sleep 3" will remain a child of that merged
sub-shell, and the "wait" will thus wait for it, along with the sleep 1
which is all it should be seeing.
For now, fix this by not eliminating a sub-shell if there are existing
unwaited upon children in the current one. It might be possible to
simply disregard the old child for the purposes of wait (and "jobs", etc,
all cmds which look at the jobs table) but the bookkeeping required to
make that work reliably is likely to take some time to get correct...
Along with this fix comes a fix to DEBUG mode shells, which, in situations
like this, could dump core in the debug code if the relevant tracing was
enabled, and add a new trace for when the jobs table is cleared (which was
added predating the discovery of the actual cause of this issue, but seems
worth keeping.) Neither of these changes have any effect on shells
compiled normally.
XXX pullup -9
Correctly handle (ie: ignore completely) \0 chars (nuls) in the
shell command input stream (script, dot file, or stdin).
Previously nul chars were ignored correctly in the line in which
they occurred, but would cause trailing chars of that line to reappear
as the start of the following line. If there was just one \0 skipped,
this would generally result in an extra \n in the sh input, which in
most cases has no effect. With multiple \0's in a single line, more
of the end of that line was duplicated into the following one. This
usually manifested as a weird "command not found" error.
Note that any \0 chars in the sh input make the script non-conforming,
so fixing this is not crucial (no \0's should really ever be seen) but
it was an obvious bug in the code, which was attempting to ignore nul
chars (as do many other shells), so let it be fixed.
XXX pullup -9
This fixes the MSAN detected reference to an unitialised variable
(an unitialised field in a struct) which happens when a command is
not found after a PATH search.
Aside from skipping some known to be going to fail exec*() calls
in some cases, the setting of the relevant field is irrelevant,
so this problem makes no practical difference to the shell, or any
shell script.
XXX (maybe) pullup -9
the "local" built-in command description (pointed out by mrg@ via uwe@ in
private e-mail).
Add a description to the export command of why this quoting is required,
and then refer to it from local and readonly (explained in export as that
one comes first).
Note that some shells parse export/local/readonly (and often more) as
"declarative" commands, and this quoting isn't needed (provided the
command name is literal and not the result of an expansion) making
X=$Y type args not require quoting, as they often don't in a regular
variable assignment (preceding, or not part of, another command).
POSIX is going to allow, but not require, that behaviour. We do not
implement it.
instead of simply assuming that the pid of the first (leftmost) process
in a pipeline is the pgrp - someday we may switch things around and
create pipelines right to left instead, which has several advantages,
but which would invalidate the assumption which was being made here.
abs(pid)) and indicate that -- is (strictly) needed if the first pid arg
(there often is only one) is negative - though this implementation works
without it if a signal to send has been explicitly given, but whereas
'kill 1234" is valid (send SIGTERM to pid 1234) "kill -1234" will generate
a usage error from the attempt to send signal 1234 to nothing, to send
SIGTERM to pgrp 1234 it needs to be "kill -- -1234" (or "kill -s term -1234").
While here do a couple of markup improvements, and allow for the
possibility that users might be running the builtin kill from some
shell other than csh or sh.
That means we cannot use (pid_t)-1 as an error indicator, as that's a
valid pid to use (described as working in kill(1) - yet it wasn't working
in /bin/kill (nor sh's builtin kill, which is essentially the same code).
This is even required to work by POSIX.
So change processnum() (the parser/validator for the pid args) to take
a pointer to a pid_t and return the pid that way, leaving the return value
of the (now int) function to indicate just ok/error. While here, fix
the validation a little ('' is no longer an accepted alias for 0) and in
case of an error from kill(2) have the error message indicate whether the
kill was targeted at a pid of a pgrp.
environment, rather than the nicer layout that is normally used.
Note this applies to /bin/kill only, the builtin kill in sh uses its
"posix" option for the same purpose, the one in csh only ever uses
POSIX format.
Better describe the command search procedure.
Document "trap -P"
Describe what works as a function name.
More accurate description of reserved word recognition.
Be more accurate about when field splittng happens after
expansions (and in particular note that tilde expansions are
not subject to field splitting). Be clear that "$@" is
not field split, it simply produces multiple fields as part
of its expansion (hence IFS is irrelevant to this), but if
used as $@ (unquoted) each field produced is potentially subject
to field splitting. Other minor wording changes.
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.
Also enhance some of the DEBUG mode trace output (nothing visible
in a normal shell build).
A couple of very minor code changes that no-one should ever notice
(eg: one less wait() call in the case that there is nothing pending).
functions being defined (they can still be included if quoted).
If we parsed the way POSIX specifies (leaving the exact input text of
$ and ` expansions unaltered, until required to be expanded) this would
not be needed, as the name of a function being defined does not underbo
parameter, command, or arith expansions, so xxx$3() { : ; } would just
work. But for many reasons we don't do that (and are unlikely to ever,
though maintaing both forms might be an option someday) - which led to
very obscure behaviour (if sh were compiled in DEBUG mode, even an abort())
and certainly nothing useful. So just prohibit these uses for now.
(A portable function name must be a "name" so this makes no difference
at all to posix compat applications/scripts).
A doc update is pending (the updated sh.1 also contains updates in other
areas not yet appropriate to commit).
When allocating for a Char **, it should use sizeof(Char *), not
sizeof(Char **). This doesn't actually affect the results except
on DS9000 though :-)
(part 2, the instance in this file was as far as I can tell
inexplicably missed by CVS on the first go...)
extra && or || or something ... forgotten now) as part a failed attempt
to fix an earlier bug (later fixed a better way) - when the extra
test (never committed) was removed, the now-redundant parentheses got
forgotten...
NFC.
Fix a bug that has existed since the "command" command was added in
2003. "command foo" would cause the definition of a function "foo"
to be lost (not freed, simply discarded) if "foo" is (in addition to
being a function) a filesystem command. The case where "foo" is
a builtin was handled.
For now, when a function exists with the same name as a filesystem
command, the latter can never appear in the command hash table, and
when used (which can only be via "command foo", just "foo" finds
the function) will always result in a full PATH search.
XXX pullup everything (from NetBSD 2.0 onwards). (really -8 and -9)
It is not enough to avoid displaying the contents of the directory,
we need to set FTS_SKIP to avoid descending into any subdirs too.
Otherwise, if a ".foo" directory has a subdirectory "bar", ls will
descend into bar and display its contents. From Todd Miller
`mv -h source target' just issues rename(source, target) without
discriminating on whether target resolves to a directory; this way
you can atomically replace a symlink to a directory.
would lead to a desynchronization of the protocol and further files or
directories to be ignored or corrupted.
Reported by Daniel Goujot, Georges-Axel Jaloyan, Ryan Lahfa, and David Naccache.
The other BSDs all have a note reminding that many shells have their
own internal echo implementations which may vary from this utility, so
add one. (Much of the wording is borrowed from FreeBSD's man page.)
(The other BSDs also have notes about the -n option not really being
portable, and printf[1] being preferable, we might want to add
something about that, too.)
the output will not be further processed (at all) so there is no need
to escape magic chars in the output, and doing so leaves stray CTLESC
chars in the here doc text. Not good. So don't do that...
To save a strlen() of the result, to determine the size of the here doc,
make rmescapes() return the length of the resulting string (this isn't
needed for other uses, so didn't happen previously).
Reported on current-users@ (2020-02-06) by Jun Ebihara
XXX pullup -9
children happens to exit while we are waiting for another child
to exit.
This can happen with code like
sh -c '
sleep 5 &
exec sh -c "sleep 10 & wait !$"
'
when the inner "sh" is waiting for the 10 second sleep to be
done, the 5 second sleep started earlier terminates. It is
a child of our process, as the inner shell is the same process
as the outer one, but not a known child (the inner shell has no
idea what the outer one did before it started).
This was observed in the wild by Martijn Dekker (where the outer
shell was bash but that's irrelevant).
XXX pullup -9
that we can always wait(2) for our children, and an ignored SIGCHLD
prevents that. Recent versions of bash can be convinced (due to a
bug most likely) to invoke us that way. Always return SIGCHLD to
SIG_DFL during init - we already prevent scripts from fiddling it.
All ash derived shells apparently have this problem (observed by
Martijn Dekker, and notified on the bash-bug list). Actual issue
diagnosed by Harald van Dijk (same list).
Mark the variable as volatile as it can be clobbered when a vfork occurs.
Error was reported when build.sh was run with MKLIBCSANITIZER=yes flag.
Reviewed by: kamil@
https://austingroupbugs.net/view.php?id=252
the Austin Group decided to require processing of "--" by the "."
and "exec" commands to solve a problem where some shells did
option processing for those commands (permitted) and others did
not (also permitted) which left no safe way to process a file
with a name beginning with "-".
This has finally made its way into what will be the next version of
the POSIX standard.
Since this shell did no option processing at all for those commands,
we need to update. This is that update.
The sole effect is that a "--" 'option' (to "." or "exec") is ignored.
This means that if you want to use "--" as the arg to one of those
commands, it needs to be given twice ". -- --". Apart from that there
should be no difference at all (though the "--" can now be used in other
situations, where we did not require it before, and still do not).
process with redirects. If we use vfork() and a redirect hangs
(eg: opening a fifo) which the parent was intended to unhang,
then the parent never gets to continue to unhang the child.
eg: mkfifo f; cat <f &; echo foo>f
The parent should not be waiting for a background process, even
just for its exec() to complete. if there are no redirects there
is (should be) nothing left that might be done that will cause any
noticeable delay, so vfork() should be safe in all other cases.
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).
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