diff options
author | dumbbell <dumbbell@FreeBSD.org> | 2012-01-16 11:07:46 +0000 |
---|---|---|
committer | dumbbell <dumbbell@FreeBSD.org> | 2012-01-16 11:07:46 +0000 |
commit | 8b387a2d35f960b0b880a2b1863250d6a9b4d692 (patch) | |
tree | 5791a3a058bf56e166a4607a77c3912f992892ea /bin | |
parent | 4e22d62dd60e215d56c8fe89a74171b4c90d3f2e (diff) | |
download | FreeBSD-src-8b387a2d35f960b0b880a2b1863250d6a9b4d692.zip FreeBSD-src-8b387a2d35f960b0b880a2b1863250d6a9b4d692.tar.gz |
sh: Fix execution of multiple statements in a trap when evalskip is set
Before this fix, only the first statement of the trap was executed if
evalskip was set. This is for example the case when:
o "-e" is set for this shell
o a trap is set on EXIT
o a function returns 1 and causes the script to abort
Reviewed by: jilles
MFC after: 2 weeks
Diffstat (limited to 'bin')
-rw-r--r-- | bin/sh/eval.c | 2 | ||||
-rw-r--r-- | bin/sh/eval.h | 1 | ||||
-rw-r--r-- | bin/sh/trap.c | 33 |
3 files changed, 34 insertions, 2 deletions
diff --git a/bin/sh/eval.c b/bin/sh/eval.c index ea23a9d..f4f69d9 100644 --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -75,7 +75,7 @@ __FBSDID("$FreeBSD$"); int evalskip; /* set if we are skipping commands */ -static int skipcount; /* number of levels to skip */ +int skipcount; /* number of levels to skip */ MKINIT int loopnest; /* current loop nesting level */ int funcnest; /* depth of function calls */ static int builtin_flags; /* evalcommand flags for builtins */ diff --git a/bin/sh/eval.h b/bin/sh/eval.h index fba6f9a..724e157 100644 --- a/bin/sh/eval.h +++ b/bin/sh/eval.h @@ -60,6 +60,7 @@ void evalbackcmd(union node *, struct backcmd *); #define in_function() funcnest extern int funcnest; extern int evalskip; +extern int skipcount; /* reasons for skipping commands (see comment on breakcmd routine) */ #define SKIPBREAK 1 diff --git a/bin/sh/trap.c b/bin/sh/trap.c index a6f929d..834992f 100644 --- a/bin/sh/trap.c +++ b/bin/sh/trap.c @@ -412,7 +412,7 @@ void dotrap(void) { int i; - int savestatus; + int savestatus, prev_evalskip, prev_skipcount; in_dotrap++; for (;;) { @@ -427,10 +427,36 @@ dotrap(void) */ if (i == SIGCHLD) ignore_sigchld++; + + /* + * Backup current evalskip + * state and reset it before + * executing a trap, so that the + * trap is not disturbed by an + * ongoing break/continue/return + * statement. + */ + prev_evalskip = evalskip; + prev_skipcount = skipcount; + evalskip = 0; + last_trapsig = i; savestatus = exitstatus; evalstring(trap[i], 0); exitstatus = savestatus; + + /* + * If such a command was not + * already in progress, allow a + * break/continue/return in the + * trap action to have an effect + * outside of it. + */ + if (prev_evalskip != 0) { + evalskip = prev_evalskip; + skipcount = prev_skipcount; + } + if (i == SIGCHLD) ignore_sigchld--; } @@ -501,6 +527,11 @@ exitshell_savedstatus(void) } handler = &loc1; if ((p = trap[0]) != NULL && *p != '\0') { + /* + * Reset evalskip, or the trap on EXIT could be + * interrupted if the last command was a "return". + */ + evalskip = 0; trap[0] = NULL; evalstring(p, 0); } |