ash: fix trap

function                                             old     new   delta
forkshell                                            738     810     +72
popstring                                            134     140      +6
parse_command                                       1460    1463      +3
evalvar                                             1373    1371      -2
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/1 up/down: 81/-2)              Total: 79 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2009-09-23 03:25:52 +02:00
parent 91836baf85
commit 844f990926
4 changed files with 68 additions and 8 deletions

View File

@ -4553,7 +4553,52 @@ forkchild(struct job *jp, union node *n, int mode)
* Do we do it correctly? */ * Do we do it correctly? */
closescript(); closescript();
if (mode == FORK_NOJOB /* is it `xxx` ? */
&& n && n->type == NCMD /* is it single cmd? */
/* && n->ncmd.args->type == NARG - always true? */
&& strcmp(n->ncmd.args->narg.text, "trap") == 0
&& n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
/* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
) {
TRACE(("Trap hack\n"));
/* Awful hack for `trap` or $(trap).
*
* http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
* contains an example where "trap" is executed in a subshell:
*
* save_traps=$(trap)
* ...
* eval "$save_traps"
*
* Standard does not say that "trap" in subshell shall print
* parent shell's traps. It only says that its output
* must have suitable form, but then, in the above example
* (which is not supposed to be normative), it implies that.
*
* bash (and probably other shell) does implement it
* (traps are reset to defaults, but "trap" still shows them),
* but as a result, "trap" logic is hopelessly messed up:
*
* # trap
* trap -- 'echo Ho' SIGWINCH <--- we have a handler
* # (trap) <--- trap is in subshell - no output (correct, traps are reset)
* # true | trap <--- trap is in subshell - no output (ditto)
* # echo `true | trap` <--- in subshell - output (but traps are reset!)
* trap -- 'echo Ho' SIGWINCH
* # echo `(trap)` <--- in subshell in subshell - output
* trap -- 'echo Ho' SIGWINCH
* # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
* trap -- 'echo Ho' SIGWINCH
*
* The rules when to forget and when to not forget traps
* get really complex and nonsensical.
*
* Our solution: ONLY bare $(trap) or `trap` is special.
*/
} else {
clear_traps(); clear_traps();
}
#if JOBS #if JOBS
/* do job control only in root shell */ /* do job control only in root shell */
doing_jobctl = 0; doing_jobctl = 0;
@ -4597,8 +4642,14 @@ forkchild(struct job *jp, union node *n, int mode)
setsignal(SIGQUIT); setsignal(SIGQUIT);
} }
#if JOBS #if JOBS
if (n && n->type == NCMD && strcmp(n->ncmd.args->narg.text, "jobs") == 0) { if (n && n->type == NCMD
&& strcmp(n->ncmd.args->narg.text, "jobs") == 0
) {
TRACE(("Job hack\n")); TRACE(("Job hack\n"));
/* "jobs": we do not want to clear job list for it,
* instead we remove only _its_ own_ job from job list.
* This makes "jobs .... | cat" more useful.
*/
freejob(curjob); freejob(curjob);
return; return;
} }
@ -12208,7 +12259,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
if (!*ap) { if (!*ap) {
for (signo = 0; signo < NSIG; signo++) { for (signo = 0; signo < NSIG; signo++) {
if (trap[signo] != NULL) { if (trap[signo] != NULL) {
out1fmt("trap -- %s %s\n", out1fmt("trap -- %s SIG%s\n",
single_quote(trap[signo]), single_quote(trap[signo]),
get_signame(signo)); get_signame(signo));
} }

View File

@ -0,0 +1,3 @@
trap -- 'echo WINCH!' SIGWINCH
trap -- 'echo WINCH!' SIGWINCH
Done

View File

@ -0,0 +1,6 @@
trap 'echo WINCH!' SIGWINCH
v=` trap `
echo $v
v=`trap`
echo $v
echo Done

View File

@ -1,20 +1,20 @@
got signal got signal
trap -- 'echo got signal' USR1 trap -- 'echo got signal' SIGUSR1
sent 1 signal sent 1 signal
got signal got signal
wait interrupted wait interrupted
trap -- 'echo got signal' USR1 trap -- 'echo got signal' SIGUSR1
sent 2 signal sent 2 signal
got signal got signal
wait interrupted wait interrupted
trap -- 'echo got signal' USR1 trap -- 'echo got signal' SIGUSR1
sent 3 signal sent 3 signal
got signal got signal
wait interrupted wait interrupted
trap -- 'echo got signal' USR1 trap -- 'echo got signal' SIGUSR1
sent 4 signal sent 4 signal
got signal got signal
wait interrupted wait interrupted
trap -- 'echo got signal' USR1 trap -- 'echo got signal' SIGUSR1
sent 5 signal sent 5 signal
sleep completed sleep completed