hush: fix `trap`
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 22 Sep 2009 23:46:19 +0000 (01:46 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 22 Sep 2009 23:46:19 +0000 (01:46 +0200)
function                                             old     new   delta
expand_variables                                    2217    2280     +63
static.argv                                            -       8      +8

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/hush.c
shell/hush_test/hush-trap/savetrap.right [new file with mode: 0644]
shell/hush_test/hush-trap/savetrap.tests [new file with mode: 0755]

index 6b176c3880668e73ab14427098c536a74967b348..eaf911458e6dd513a385f5ad04e11877cf929d6c 100644 (file)
@@ -5180,6 +5180,47 @@ static FILE *generate_stream_from_string(const char *s)
                xmove_fd(channel[1], 1);
                /* Prevent it from trying to handle ctrl-z etc */
                IF_HUSH_JOB(G.run_list_level = 1;)
+               /* 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.
+                */
+               s = skip_whitespace(s);
+               if (strncmp(s, "trap", 4) == 0 && (*skip_whitespace(s + 4) == '\0'))
+               {
+                       static const char *const argv[] = { NULL, NULL };
+                       builtin_trap((char**)argv);
+                       exit(0); /* not _exit() - we need to fflush */
+               }
 #if BB_MMU
                reset_traps_to_defaults();
                parse_and_run_string(s);
@@ -7057,7 +7098,8 @@ static int FAST_FUNC builtin_trap(char **argv)
                        if (G.traps[i]) {
                                printf("trap -- ");
                                print_escaped(G.traps[i]);
-                               printf(" %s\n", get_signame(i));
+                               /* bash compat: it says SIGxxx, not just xxx */
+                               printf(" SIG%s\n", get_signame(i));
                        }
                }
                /*fflush(stdout); - done after each builtin anyway */
diff --git a/shell/hush_test/hush-trap/savetrap.right b/shell/hush_test/hush-trap/savetrap.right
new file mode 100644 (file)
index 0000000..2d33427
--- /dev/null
@@ -0,0 +1,3 @@
+trap -- 'echo WINCH!' SIGWINCH
+trap -- 'echo WINCH!' SIGWINCH
+Done
diff --git a/shell/hush_test/hush-trap/savetrap.tests b/shell/hush_test/hush-trap/savetrap.tests
new file mode 100755 (executable)
index 0000000..6492e86
--- /dev/null
@@ -0,0 +1,6 @@
+trap 'echo WINCH!' SIGWINCH
+v=` trap   `
+echo $v
+v=`trap`
+echo $v
+echo Done