ash: fix bug which causes signal6.tests to fail
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 18 May 2010 13:49:07 +0000 (15:49 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 18 May 2010 13:49:07 +0000 (15:49 +0200)
function                                             old     new   delta
trapcmd                                              271     277      +6
localcmd                                             277     275      -2

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/route.c
shell/ash.c
shell/ash_test/ash-signals/signal6.tests

index 241be8e09a3507e8d8bc93d90b34ea688783f6e4..a3199621a7bed122e6f011011af9175caa460987 100644 (file)
@@ -178,7 +178,7 @@ static NOINLINE void INET_setroute(int action, char **args)
                        int prefix_len;
 
                        prefix_len = xatoul_range(prefix+1, 0, 32);
-                       mask_in_addr(rt) = htonl( ~ (0xffffffffUL >> prefix_len));
+                       mask_in_addr(rt) = htonl( ~(0xffffffffUL >> prefix_len));
                        *prefix = '\0';
 #if HAVE_NEW_ADDRT
                        rt.rt_genmask.sa_family = AF_INET;
index 641a140356adee915677b8d93066e204db277611..4f2fa756bdafd3701f934166810bc667e8f77f09 100644 (file)
@@ -208,6 +208,7 @@ struct globals_misc {
 
        /* indicates specified signal received */
        uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
+       uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
        char *trap[NSIG];
        char **trap_ptr;        /* used only by "trap hack" */
 
@@ -236,6 +237,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
 #define optlist     (G_misc.optlist    )
 #define sigmode     (G_misc.sigmode    )
 #define gotsig      (G_misc.gotsig     )
+#define may_have_traps    (G_misc.may_have_traps   )
 #define trap        (G_misc.trap       )
 #define trap_ptr    (G_misc.trap_ptr   )
 #define random_gen  (G_misc.random_gen )
@@ -333,7 +335,7 @@ raise_interrupt(void)
        /* Signal is not automatically unmasked after it is raised,
         * do it ourself - unmask all signals */
        sigprocmask_allsigs(SIG_UNBLOCK);
-       /* pending_sig = 0; - now done in onsig() */
+       /* pending_sig = 0; - now done in signal_handler() */
 
        ex_type = EXSIG;
        if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
@@ -3268,10 +3270,10 @@ ignoresig(int signo)
 }
 
 /*
- * Signal handler. Only one usage site - in setsignal()
+ * Only one usage site - in setsignal()
  */
 static void
-onsig(int signo)
+signal_handler(int signo)
 {
        gotsig[signo - 1] = 1;
 
@@ -3366,7 +3368,7 @@ setsignal(int signo)
        act.sa_handler = SIG_DFL;
        switch (new_act) {
        case S_CATCH:
-               act.sa_handler = onsig;
+               act.sa_handler = signal_handler;
                act.sa_flags = 0; /* matters only if !DFL and !IGN */
                sigfillset(&act.sa_mask); /* ditto */
                break;
@@ -8443,15 +8445,16 @@ evalsubshell(union node *n, int flags)
        int status;
 
        expredir(n->nredir.redirect);
-       if (!backgnd && flags & EV_EXIT && !trap[0])
+       if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
                goto nofork;
        INT_OFF;
        jp = makejob(/*n,*/ 1);
        if (forkshell(jp, n, backgnd) == 0) {
+               /* child */
                INT_ON;
                flags |= EV_EXIT;
                if (backgnd)
-                       flags &=EV_TESTED;
+                       flags &= ~EV_TESTED;
  nofork:
                redirect(n->nredir.redirect, 0);
                evaltreenr(n->nredir.n, flags);
@@ -9193,16 +9196,19 @@ evalcommand(union node *cmd, int flags)
        }
 #endif
                /* Fork off a child process if necessary. */
-               if (!(flags & EV_EXIT) || trap[0]) {
+               if (!(flags & EV_EXIT) || may_have_traps) {
                        INT_OFF;
                        jp = makejob(/*cmd,*/ 1);
                        if (forkshell(jp, cmd, FORK_FG) != 0) {
+                               /* parent */
                                exitstatus = waitforjob(jp);
                                INT_ON;
                                TRACE(("forked child exited with %d\n", exitstatus));
                                break;
                        }
+                       /* child */
                        FORCE_INT_ON;
+                       /* fall through to exec'ing exeternal program */
                }
                listsetvar(varlist.list, VEXPORT|VSTACK);
                shellexec(argv, path, cmdentry.u.index);
@@ -12349,6 +12355,8 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
                                action = ckstrdup(action);
                }
                free(trap[signo]);
+               if (action)
+                       may_have_traps = 1;
                trap[signo] = action;
                if (signo != 0)
                        setsignal(signo);
index ffeded2a5bec38f8b2dd280ade3786962478ef83..3ce151060198f3250c21d3f7ae7cda1b3f2d1d40 100755 (executable)
@@ -1,3 +1,2 @@
-# Bug: TERM does not trigger in the child
 { trap "echo got TERM" TERM; sleep 3; }& sleep 1; kill $!; wait
 echo Done: $?