sh: Allow EV_EXIT through function calls, make {...} <redir more consistent.
If EV_EXIT causes an exit, use the exception mechanism to unwind redirections and local variables. This way, if the final command is a redirected command, an EXIT trap now executes without the redirections. Because of these changes, EV_EXIT can now be inherited by the body of a function, so do so. This means that a function no longer prevents a fork before an exec being skipped, such as in f() { head -1 /etc/passwd; }; echo $(f) Wrapping a single builtin in a function may still cause an otherwise unnecessary fork with command substitution, however. An exit command or -e failure still invokes the EXIT trap with the original redirections and local variables in place. Note: this depends on SHELLPROC being gone. A SHELLPROC depended on keeping the redirections and local variables and only cleaning up the state to restore them.
This commit is contained in:
parent
86769ac0a4
commit
45496405c6
@ -57,6 +57,7 @@ extern volatile sig_atomic_t exception;
|
||||
#define EXINT 0 /* SIGINT received */
|
||||
#define EXERROR 1 /* a generic error */
|
||||
#define EXEXEC 2 /* command execution failed */
|
||||
#define EXEXIT 3 /* call exitshell(exitstatus) */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -179,7 +179,7 @@ evalstring(char *s, int flags)
|
||||
if (!any)
|
||||
exitstatus = 0;
|
||||
if (flags_exit)
|
||||
exitshell(exitstatus);
|
||||
exraise(EXEXIT);
|
||||
}
|
||||
|
||||
|
||||
@ -285,8 +285,10 @@ evaltree(union node *n, int flags)
|
||||
out:
|
||||
if (pendingsigs)
|
||||
dotrap();
|
||||
if ((flags & EV_EXIT) || (eflag && exitstatus != 0 && do_etest))
|
||||
if (eflag && exitstatus != 0 && do_etest)
|
||||
exitshell(exitstatus);
|
||||
if (flags & EV_EXIT)
|
||||
exraise(EXEXIT);
|
||||
}
|
||||
|
||||
|
||||
@ -440,8 +442,8 @@ evalredir(union node *n, int flags)
|
||||
|
||||
handler = savehandler;
|
||||
e = exception;
|
||||
popredir();
|
||||
if (e == EXERROR || e == EXEXEC) {
|
||||
popredir();
|
||||
if (in_redirect) {
|
||||
exitstatus = 2;
|
||||
return;
|
||||
@ -927,8 +929,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
if (setjmp(jmploc.loc)) {
|
||||
freeparam(&shellparam);
|
||||
shellparam = saveparam;
|
||||
if (exception == EXERROR || exception == EXEXEC)
|
||||
popredir();
|
||||
popredir();
|
||||
unreffunc(cmdentry.u.func);
|
||||
poplocalvars();
|
||||
localvars = savelocalvars;
|
||||
@ -943,10 +944,8 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
for (sp = varlist.list ; sp ; sp = sp->next)
|
||||
mklocal(sp->text);
|
||||
exitstatus = oexitstatus;
|
||||
if (flags & EV_TESTED)
|
||||
evaltree(getfuncnode(cmdentry.u.func), EV_TESTED);
|
||||
else
|
||||
evaltree(getfuncnode(cmdentry.u.func), 0);
|
||||
evaltree(getfuncnode(cmdentry.u.func),
|
||||
flags & (EV_TESTED | EV_EXIT));
|
||||
INTOFF;
|
||||
unreffunc(cmdentry.u.func);
|
||||
poplocalvars();
|
||||
@ -982,7 +981,10 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
savehandler = handler;
|
||||
if (setjmp(jmploc.loc)) {
|
||||
e = exception;
|
||||
exitstatus = (e == EXINT)? SIGINT+128 : 2;
|
||||
if (e == EXINT)
|
||||
exitstatus = SIGINT+128;
|
||||
else if (e != EXEXIT)
|
||||
exitstatus = 2;
|
||||
goto cmddone;
|
||||
}
|
||||
handler = &jmploc;
|
||||
@ -1018,8 +1020,7 @@ cmddone:
|
||||
backcmd->nleft = memout.nextc - memout.buf;
|
||||
memout.buf = NULL;
|
||||
}
|
||||
if (cmdentry.u.index != EXECCMD &&
|
||||
(e == -1 || e == EXERROR || e == EXEXEC))
|
||||
if (cmdentry.u.index != EXECCMD)
|
||||
popredir();
|
||||
if (e != -1) {
|
||||
if ((e != EXERROR && e != EXEXEC)
|
||||
|
@ -111,7 +111,8 @@ main(int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
|
||||
if (state == 0 || iflag == 0 || ! rootshell)
|
||||
if (state == 0 || iflag == 0 || ! rootshell ||
|
||||
exception == EXEXIT)
|
||||
exitshell(exitstatus);
|
||||
reset();
|
||||
if (exception == EXINT)
|
||||
|
4
tools/regression/bin/sh/execution/fork3.0
Normal file
4
tools/regression/bin/sh/execution/fork3.0
Normal file
@ -0,0 +1,4 @@
|
||||
# $FreeBSD$
|
||||
|
||||
result=$(${SH} -c 'f() { ps -p $$ -o comm=; }; f')
|
||||
test "$result" = "ps"
|
21
tools/regression/bin/sh/execution/redir6.0
Normal file
21
tools/regression/bin/sh/execution/redir6.0
Normal file
@ -0,0 +1,21 @@
|
||||
# $FreeBSD$
|
||||
|
||||
failures=0
|
||||
|
||||
check() {
|
||||
if [ "$2" != "$3" ]; then
|
||||
echo "Failure at $1" >&2
|
||||
failures=$((failures + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
check $LINENO "$(trap "echo bye" EXIT; : >/dev/null)" bye
|
||||
check $LINENO "$(trap "echo bye" EXIT; { :; } >/dev/null)" bye
|
||||
check $LINENO "$(trap "echo bye" EXIT; (:) >/dev/null)" bye
|
||||
check $LINENO "$(trap "echo bye" EXIT; (: >/dev/null))" bye
|
||||
check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; : >/dev/null')" bye
|
||||
check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; { :; } >/dev/null')" bye
|
||||
check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; (:) >/dev/null')" bye
|
||||
check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; (: >/dev/null)')" bye
|
||||
|
||||
exit $((failures > 0))
|
21
tools/regression/bin/sh/execution/redir7.0
Normal file
21
tools/regression/bin/sh/execution/redir7.0
Normal file
@ -0,0 +1,21 @@
|
||||
# $FreeBSD$
|
||||
|
||||
failures=0
|
||||
|
||||
check() {
|
||||
if [ "$2" != "$3" ]; then
|
||||
echo "Failure at $1" >&2
|
||||
failures=$((failures + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
check $LINENO "$(trap "echo bye" EXIT; f() { :; }; f >/dev/null)" bye
|
||||
check $LINENO "$(trap "echo bye" EXIT; f() { :; }; { f; } >/dev/null)" bye
|
||||
check $LINENO "$(trap "echo bye" EXIT; f() { :; }; (f) >/dev/null)" bye
|
||||
check $LINENO "$(trap "echo bye" EXIT; f() { :; }; (f >/dev/null))" bye
|
||||
check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; f() { :; }; f >/dev/null')" bye
|
||||
check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; f() { :; }; { f; } >/dev/null')" bye
|
||||
check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; f() { :; }; (f) >/dev/null')" bye
|
||||
check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; f() { :; }; (f >/dev/null)')" bye
|
||||
|
||||
exit $((failures > 0))
|
Loading…
x
Reference in New Issue
Block a user