Author: jilles Date: Sat Apr 23 22:28:56 2011 New Revision: 220978 URL: http://svn.freebsd.org/changeset/base/220978
Log: 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. Added: head/tools/regression/bin/sh/execution/fork3.0 (contents, props changed) head/tools/regression/bin/sh/execution/redir6.0 (contents, props changed) head/tools/regression/bin/sh/execution/redir7.0 (contents, props changed) Modified: head/bin/sh/error.h head/bin/sh/eval.c head/bin/sh/main.c Modified: head/bin/sh/error.h ============================================================================== --- head/bin/sh/error.h Sat Apr 23 21:38:21 2011 (r220977) +++ head/bin/sh/error.h Sat Apr 23 22:28:56 2011 (r220978) @@ -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) */ /* Modified: head/bin/sh/eval.c ============================================================================== --- head/bin/sh/eval.c Sat Apr 23 21:38:21 2011 (r220977) +++ head/bin/sh/eval.c Sat Apr 23 22:28:56 2011 (r220978) @@ -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, 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, 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, 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) Modified: head/bin/sh/main.c ============================================================================== --- head/bin/sh/main.c Sat Apr 23 21:38:21 2011 (r220977) +++ head/bin/sh/main.c Sat Apr 23 22:28:56 2011 (r220978) @@ -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) Added: head/tools/regression/bin/sh/execution/fork3.0 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/bin/sh/execution/fork3.0 Sat Apr 23 22:28:56 2011 (r220978) @@ -0,0 +1,4 @@ +# $FreeBSD$ + +result=$(${SH} -c 'f() { ps -p $$ -o comm=; }; f') +test "$result" = "ps" Added: head/tools/regression/bin/sh/execution/redir6.0 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/bin/sh/execution/redir6.0 Sat Apr 23 22:28:56 2011 (r220978) @@ -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)) Added: head/tools/regression/bin/sh/execution/redir7.0 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/bin/sh/execution/redir7.0 Sat Apr 23 22:28:56 2011 (r220978) @@ -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)) _______________________________________________ svn-src-head@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"