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"

Reply via email to