diff --git a/shell/ash.c b/shell/ash.c index 11174683e..5348e9572 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -203,7 +203,7 @@ struct globals_misc { #define S_RESET 5 /* temporary - to reset a hard ignored sig */ /* indicates specified signal received */ - char gotsig[NSIG - 1]; + char gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ char *trap[NSIG]; /* Rarely referenced stuff */ @@ -7846,12 +7846,12 @@ dotrap(void) pendingsig = 0; xbarrier(); - for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) { + for (i = 1, q = gotsig; i < NSIG; i++, q++) { if (!*q) continue; *q = '\0'; - p = trap[i + 1]; + p = trap[i]; if (!p) continue; skip = evalstring(p, SKIPEVAL); @@ -7881,16 +7881,33 @@ static void prehash(union node *); static void evaltree(union node *n, int flags) { + + struct jmploc *volatile savehandler = exception_handler; + struct jmploc jmploc; int checkexit = 0; void (*evalfn)(union node *, int); - unsigned isor; int status; + if (n == NULL) { TRACE(("evaltree(NULL) called\n")); - goto out; + goto out1; } TRACE(("pid %d, evaltree(%p: %d, %d) called\n", getpid(), n, n->type, flags)); + + exception_handler = &jmploc; + { + int err = setjmp(jmploc.loc); + if (err) { + /* if it was a signal, check for trap handlers */ + if (exception == EXSIG) + goto out; + /* continue on the way out */ + exception_handler = savehandler; + longjmp(exception_handler->loc, err); + } + } + switch (n->type) { default: #if DEBUG @@ -7936,19 +7953,20 @@ evaltree(union node *n, int flags) goto calleval; case NAND: case NOR: - case NSEMI: + case NSEMI: { + #if NAND + 1 != NOR #error NAND + 1 != NOR #endif #if NOR + 1 != NSEMI #error NOR + 1 != NSEMI #endif - isor = n->type - NAND; + unsigned is_or = is_or = n->type - NAND; evaltree( n->nbinary.ch1, - (flags | ((isor >> 1) - 1)) & EV_TESTED + (flags | ((is_or >> 1) - 1)) & EV_TESTED ); - if (!exitstatus == isor) + if (!exitstatus == is_or) break; if (!evalskip) { n = n->nbinary.ch2; @@ -7959,6 +7977,7 @@ evaltree(union node *n, int flags) break; } break; + } case NIF: evaltree(n->nif.test, EV_TESTED); if (evalskip) @@ -7979,8 +7998,11 @@ evaltree(union node *n, int flags) exitstatus = status; break; } + out: - if ((checkexit & exitstatus)) + exception_handler = savehandler; + out1: + if (checkexit & exitstatus) evalskip |= SKIPEVAL; else if (pendingsig && dotrap()) goto exexit; @@ -11907,18 +11929,15 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) if (!*ap) { for (signo = 0; signo < NSIG; signo++) { if (trap[signo] != NULL) { - const char *sn; - - sn = get_signame(signo); out1fmt("trap -- %s %s\n", - single_quote(trap[signo]), sn); + single_quote(trap[signo]), + get_signame(signo)); } } return 0; } - if (!ap[1]) - action = NULL; - else + action = NULL; + if (ap[1]) action = *ap++; while (*ap) { signo = get_signum(*ap); diff --git a/shell/ash_test/ash-signals/signal2.right b/shell/ash_test/ash-signals/signal2.right new file mode 100644 index 000000000..96d2d6ad3 --- /dev/null +++ b/shell/ash_test/ash-signals/signal2.right @@ -0,0 +1,3 @@ +sleeping +child exits as expected +parent exits diff --git a/shell/ash_test/ash-signals/signal2.tests b/shell/ash_test/ash-signals/signal2.tests new file mode 100755 index 000000000..04f981c2d --- /dev/null +++ b/shell/ash_test/ash-signals/signal2.tests @@ -0,0 +1,18 @@ +#!/bin/sh + +$THIS_SH -c ' +cleanup() { + echo "child exits as expected" + exit +} +trap cleanup HUP +echo "sleeping" +sleep 1 +echo "BAD exit from child!" +' & + +child=$! +sleep 0.1 # let child install handler first +kill -HUP $child +wait +echo "parent exits"