summaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenis Vlasenko2008-07-26 13:45:57 +0000
committerDenis Vlasenko2008-07-26 13:45:57 +0000
commit4e19a9c81a6e0b0608fcae1f1a5adbaa1893a17d (patch)
tree2121472f1df9153eec42f8da7e0517af443fdded /shell
parent2b2e267b434d197fdbce2b36181dfd422da7f9d2 (diff)
downloadbusybox-4e19a9c81a6e0b0608fcae1f1a5adbaa1893a17d.zip
busybox-4e19a9c81a6e0b0608fcae1f1a5adbaa1893a17d.tar.gz
ash: hopefully close bug 4324. With testcase.
function old new delta evaltree 621 869 +248 popstring 134 140 +6
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c53
-rw-r--r--shell/ash_test/ash-signals/signal2.right3
-rwxr-xr-xshell/ash_test/ash-signals/signal2.tests18
3 files changed, 57 insertions, 17 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 1117468..5348e95 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 0000000..96d2d6a
--- /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 0000000..04f981c
--- /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"