diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-09-23 03:25:52 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-09-23 03:25:52 +0200 |
commit | 844f9909264b7f46620e06b7116facba0a940667 (patch) | |
tree | c0a21470c20f3dcab9c61abbd2e2137172741f09 | |
parent | 91836baf85ce6980a33c6ce38730928a4edc3c5a (diff) | |
download | busybox-w32-844f9909264b7f46620e06b7116facba0a940667.tar.gz busybox-w32-844f9909264b7f46620e06b7116facba0a940667.tar.bz2 busybox-w32-844f9909264b7f46620e06b7116facba0a940667.zip |
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>
-rw-r--r-- | shell/ash.c | 57 | ||||
-rw-r--r-- | shell/ash_test/ash-signals/savetrap.right | 3 | ||||
-rwxr-xr-x | shell/ash_test/ash-signals/savetrap.tests | 6 | ||||
-rw-r--r-- | shell/ash_test/ash-signals/signal1.right | 10 |
4 files changed, 68 insertions, 8 deletions
diff --git a/shell/ash.c b/shell/ash.c index 4360770d4..68aa675e5 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -4553,7 +4553,52 @@ forkchild(struct job *jp, union node *n, int mode) | |||
4553 | * Do we do it correctly? */ | 4553 | * Do we do it correctly? */ |
4554 | 4554 | ||
4555 | closescript(); | 4555 | closescript(); |
4556 | clear_traps(); | 4556 | |
4557 | if (mode == FORK_NOJOB /* is it `xxx` ? */ | ||
4558 | && n && n->type == NCMD /* is it single cmd? */ | ||
4559 | /* && n->ncmd.args->type == NARG - always true? */ | ||
4560 | && strcmp(n->ncmd.args->narg.text, "trap") == 0 | ||
4561 | && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */ | ||
4562 | /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */ | ||
4563 | ) { | ||
4564 | TRACE(("Trap hack\n")); | ||
4565 | /* Awful hack for `trap` or $(trap). | ||
4566 | * | ||
4567 | * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html | ||
4568 | * contains an example where "trap" is executed in a subshell: | ||
4569 | * | ||
4570 | * save_traps=$(trap) | ||
4571 | * ... | ||
4572 | * eval "$save_traps" | ||
4573 | * | ||
4574 | * Standard does not say that "trap" in subshell shall print | ||
4575 | * parent shell's traps. It only says that its output | ||
4576 | * must have suitable form, but then, in the above example | ||
4577 | * (which is not supposed to be normative), it implies that. | ||
4578 | * | ||
4579 | * bash (and probably other shell) does implement it | ||
4580 | * (traps are reset to defaults, but "trap" still shows them), | ||
4581 | * but as a result, "trap" logic is hopelessly messed up: | ||
4582 | * | ||
4583 | * # trap | ||
4584 | * trap -- 'echo Ho' SIGWINCH <--- we have a handler | ||
4585 | * # (trap) <--- trap is in subshell - no output (correct, traps are reset) | ||
4586 | * # true | trap <--- trap is in subshell - no output (ditto) | ||
4587 | * # echo `true | trap` <--- in subshell - output (but traps are reset!) | ||
4588 | * trap -- 'echo Ho' SIGWINCH | ||
4589 | * # echo `(trap)` <--- in subshell in subshell - output | ||
4590 | * trap -- 'echo Ho' SIGWINCH | ||
4591 | * # echo `true | (trap)` <--- in subshell in subshell in subshell - output! | ||
4592 | * trap -- 'echo Ho' SIGWINCH | ||
4593 | * | ||
4594 | * The rules when to forget and when to not forget traps | ||
4595 | * get really complex and nonsensical. | ||
4596 | * | ||
4597 | * Our solution: ONLY bare $(trap) or `trap` is special. | ||
4598 | */ | ||
4599 | } else { | ||
4600 | clear_traps(); | ||
4601 | } | ||
4557 | #if JOBS | 4602 | #if JOBS |
4558 | /* do job control only in root shell */ | 4603 | /* do job control only in root shell */ |
4559 | doing_jobctl = 0; | 4604 | doing_jobctl = 0; |
@@ -4597,8 +4642,14 @@ forkchild(struct job *jp, union node *n, int mode) | |||
4597 | setsignal(SIGQUIT); | 4642 | setsignal(SIGQUIT); |
4598 | } | 4643 | } |
4599 | #if JOBS | 4644 | #if JOBS |
4600 | if (n && n->type == NCMD && strcmp(n->ncmd.args->narg.text, "jobs") == 0) { | 4645 | if (n && n->type == NCMD |
4646 | && strcmp(n->ncmd.args->narg.text, "jobs") == 0 | ||
4647 | ) { | ||
4601 | TRACE(("Job hack\n")); | 4648 | TRACE(("Job hack\n")); |
4649 | /* "jobs": we do not want to clear job list for it, | ||
4650 | * instead we remove only _its_ own_ job from job list. | ||
4651 | * This makes "jobs .... | cat" more useful. | ||
4652 | */ | ||
4602 | freejob(curjob); | 4653 | freejob(curjob); |
4603 | return; | 4654 | return; |
4604 | } | 4655 | } |
@@ -12208,7 +12259,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
12208 | if (!*ap) { | 12259 | if (!*ap) { |
12209 | for (signo = 0; signo < NSIG; signo++) { | 12260 | for (signo = 0; signo < NSIG; signo++) { |
12210 | if (trap[signo] != NULL) { | 12261 | if (trap[signo] != NULL) { |
12211 | out1fmt("trap -- %s %s\n", | 12262 | out1fmt("trap -- %s SIG%s\n", |
12212 | single_quote(trap[signo]), | 12263 | single_quote(trap[signo]), |
12213 | get_signame(signo)); | 12264 | get_signame(signo)); |
12214 | } | 12265 | } |
diff --git a/shell/ash_test/ash-signals/savetrap.right b/shell/ash_test/ash-signals/savetrap.right new file mode 100644 index 000000000..2d33427aa --- /dev/null +++ b/shell/ash_test/ash-signals/savetrap.right | |||
@@ -0,0 +1,3 @@ | |||
1 | trap -- 'echo WINCH!' SIGWINCH | ||
2 | trap -- 'echo WINCH!' SIGWINCH | ||
3 | Done | ||
diff --git a/shell/ash_test/ash-signals/savetrap.tests b/shell/ash_test/ash-signals/savetrap.tests new file mode 100755 index 000000000..6492e86a2 --- /dev/null +++ b/shell/ash_test/ash-signals/savetrap.tests | |||
@@ -0,0 +1,6 @@ | |||
1 | trap 'echo WINCH!' SIGWINCH | ||
2 | v=` trap ` | ||
3 | echo $v | ||
4 | v=`trap` | ||
5 | echo $v | ||
6 | echo Done | ||
diff --git a/shell/ash_test/ash-signals/signal1.right b/shell/ash_test/ash-signals/signal1.right index cf403ac62..beb0a988e 100644 --- a/shell/ash_test/ash-signals/signal1.right +++ b/shell/ash_test/ash-signals/signal1.right | |||
@@ -1,20 +1,20 @@ | |||
1 | got signal | 1 | got signal |
2 | trap -- 'echo got signal' USR1 | 2 | trap -- 'echo got signal' SIGUSR1 |
3 | sent 1 signal | 3 | sent 1 signal |
4 | got signal | 4 | got signal |
5 | wait interrupted | 5 | wait interrupted |
6 | trap -- 'echo got signal' USR1 | 6 | trap -- 'echo got signal' SIGUSR1 |
7 | sent 2 signal | 7 | sent 2 signal |
8 | got signal | 8 | got signal |
9 | wait interrupted | 9 | wait interrupted |
10 | trap -- 'echo got signal' USR1 | 10 | trap -- 'echo got signal' SIGUSR1 |
11 | sent 3 signal | 11 | sent 3 signal |
12 | got signal | 12 | got signal |
13 | wait interrupted | 13 | wait interrupted |
14 | trap -- 'echo got signal' USR1 | 14 | trap -- 'echo got signal' SIGUSR1 |
15 | sent 4 signal | 15 | sent 4 signal |
16 | got signal | 16 | got signal |
17 | wait interrupted | 17 | wait interrupted |
18 | trap -- 'echo got signal' USR1 | 18 | trap -- 'echo got signal' SIGUSR1 |
19 | sent 5 signal | 19 | sent 5 signal |
20 | sleep completed | 20 | sleep completed |