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:
parent
91836baf85
commit
844f990926
55
shell/ash.c
55
shell/ash.c
@ -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));
|
||||||
}
|
}
|
||||||
|
3
shell/ash_test/ash-signals/savetrap.right
Normal file
3
shell/ash_test/ash-signals/savetrap.right
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
trap -- 'echo WINCH!' SIGWINCH
|
||||||
|
trap -- 'echo WINCH!' SIGWINCH
|
||||||
|
Done
|
6
shell/ash_test/ash-signals/savetrap.tests
Executable file
6
shell/ash_test/ash-signals/savetrap.tests
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
trap 'echo WINCH!' SIGWINCH
|
||||||
|
v=` trap `
|
||||||
|
echo $v
|
||||||
|
v=`trap`
|
||||||
|
echo $v
|
||||||
|
echo Done
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user