From b563f62bbb1c9a6d931924f8fd7c3e52bb3d5875 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 25 Sep 2010 17:15:13 +0200 Subject: ash: fix signal and "set -e" interaction Signed-off-by: Denys Vlasenko --- shell/ash.c | 19 +++++++++++++------ shell/ash_test/ash-signals/signal8.right | 3 +++ shell/ash_test/ash-signals/signal8.tests | 18 ++++++++++++++++++ shell/ash_test/ash-signals/signal9.right | 3 +++ shell/ash_test/ash-signals/signal9.tests | 21 +++++++++++++++++++++ 5 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 shell/ash_test/ash-signals/signal8.right create mode 100755 shell/ash_test/ash-signals/signal8.tests create mode 100644 shell/ash_test/ash-signals/signal9.right create mode 100755 shell/ash_test/ash-signals/signal9.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 9089adc63..ea835527e 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -8214,7 +8214,7 @@ static int evalstring(char *s, int mask); /* Called to execute a trap. * Single callsite - at the end of evaltree(). - * If we return non-zero, exaltree raises EXEXIT exception. + * If we return non-zero, evaltree raises EXEXIT exception. * * Perhaps we should avoid entering new trap handlers * while we are executing a trap handler. [is it a TODO?] @@ -8404,11 +8404,15 @@ evaltree(union node *n, int flags) out: exception_handler = savehandler; + out1: + /* Order of checks below is important: + * signal handlers trigger before exit caused by "set -e". + */ + if (pending_sig && dotrap()) + goto exexit; if (checkexit & exitstatus) evalskip |= SKIPEVAL; - else if (pending_sig && dotrap()) - goto exexit; if (flags & EV_EXIT) { exexit: @@ -8740,7 +8744,7 @@ poplocalvars(void) while ((lvp = localvars) != NULL) { localvars = lvp->next; vp = lvp->vp; - TRACE(("poplocalvar %s\n", vp ? vp->text : "-")); + TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-")); if (vp == NULL) { /* $- saved */ memcpy(optlist, lvp->text, sizeof(optlist)); free((char*)lvp->text); @@ -13009,10 +13013,12 @@ int ash_main(int argc UNUSED_PARAM, char **argv) if (e == EXERROR) exitstatus = 2; s = state; - if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) + if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) { exitshell(); - if (e == EXINT) + } + if (e == EXINT) { outcslow('\n', stderr); + } popstackmark(&smark); FORCE_INT_ON; /* enable interrupts */ @@ -13105,6 +13111,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) _mcleanup(); } #endif + TRACE(("End of main reached\n")); exitshell(); /* NOTREACHED */ } diff --git a/shell/ash_test/ash-signals/signal8.right b/shell/ash_test/ash-signals/signal8.right new file mode 100644 index 000000000..39572f30e --- /dev/null +++ b/shell/ash_test/ash-signals/signal8.right @@ -0,0 +1,3 @@ +Removing traps +End of exit_func +Done: 0 diff --git a/shell/ash_test/ash-signals/signal8.tests b/shell/ash_test/ash-signals/signal8.tests new file mode 100755 index 000000000..731af7477 --- /dev/null +++ b/shell/ash_test/ash-signals/signal8.tests @@ -0,0 +1,18 @@ +"$THIS_SH" -c ' +exit_func() { + echo "Removing traps" + trap - EXIT TERM INT + echo "End of exit_func" +} +set -e +trap exit_func EXIT TERM INT +sleep 2 +exit 77 +' & + +sleep 1 +# BUG: ash kills -PGRP, but in non-interactive shell we do not create pgrps! +# In this case, bash kills by PID, not PGRP. +kill -TERM %1 +wait +echo Done: $? diff --git a/shell/ash_test/ash-signals/signal9.right b/shell/ash_test/ash-signals/signal9.right new file mode 100644 index 000000000..39572f30e --- /dev/null +++ b/shell/ash_test/ash-signals/signal9.right @@ -0,0 +1,3 @@ +Removing traps +End of exit_func +Done: 0 diff --git a/shell/ash_test/ash-signals/signal9.tests b/shell/ash_test/ash-signals/signal9.tests new file mode 100755 index 000000000..18e71012b --- /dev/null +++ b/shell/ash_test/ash-signals/signal9.tests @@ -0,0 +1,21 @@ +# Note: the inner script is a test which checks for a different bug +# (ordering between INT handler and exit on "set -e"), +# but so far I did not figure out how to simulate it non-interactively. + +"$THIS_SH" -c ' +exit_func() { + echo "Removing traps" + trap - EXIT TERM INT + echo "End of exit_func" +} +set -e +trap exit_func EXIT TERM INT +sleep 2 +exit 77 +' & + +child=$! +sleep 1 +kill -TERM $child +wait +echo Done: $? -- cgit v1.2.3