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.
Obtained-from: FreeBSD SVN rev 220978
* SUCH DAMAGE.
*
* @(#)error.h 8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/error.h,v 1.21 2011/02/04 22:47:55 jilles Exp $
+ * $FreeBSD: src/bin/sh/error.h,v 1.22 2011/04/23 22:28:56 jilles Exp $
*/
/*
#define EXINT 0 /* SIGINT received */
#define EXERROR 1 /* a generic error */
#define EXEXEC 2 /* command execution failed */
+#define EXEXIT 3 /* call exitshell(exitstatus) */
/*
* SUCH DAMAGE.
*
* @(#)eval.c 8.9 (Berkeley) 6/8/95
- * $FreeBSD: src/bin/sh/eval.c,v 1.101 2011/02/05 14:08:51 jilles Exp $
+ * $FreeBSD: src/bin/sh/eval.c,v 1.102 2011/04/23 22:28:56 jilles Exp $
*/
#include <sys/time.h>
if (!any)
exitstatus = 0;
if (flags_exit)
- exitshell(exitstatus);
+ exraise(EXEXIT);
}
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);
}
handler = savehandler;
e = exception;
+ popredir();
if (e == EXERROR || e == EXEXEC) {
- popredir();
if (in_redirect) {
exitstatus = 2;
return;
if (setjmp(jmploc.loc)) {
freeparam(&shellparam);
shellparam = saveparam;
- if (exception == EXERROR || exception == EXEXEC)
- popredir();
+ popredir();
unreffunc(cmdentry.u.func);
poplocalvars();
localvars = savelocalvars;
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();
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;
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)
*
* @(#) Copyright (c) 1991, 1993 The Regents of the University of California. All rights reserved.
* @(#)main.c 8.6 (Berkeley) 5/28/95
- * $FreeBSD: src/bin/sh/main.c,v 1.44 2011/02/04 22:47:55 jilles Exp $
+ * $FreeBSD: src/bin/sh/main.c,v 1.45 2011/04/23 22:28:56 jilles Exp $
*/
#include <stdio.h>
break;
}
- if (state == 0 || iflag == 0 || ! rootshell)
+ if (state == 0 || iflag == 0 || ! rootshell ||
+ exception == EXEXIT)
exitshell(exitstatus);
reset();
if (exception == EXINT)
--- /dev/null
+# $FreeBSD: src/tools/regression/bin/sh/execution/fork3.0,v 1.1 2011/04/23 22:28:56 jilles Exp $
+
+result=$(${SH} -c 'f() { ps -p $$ -o comm=; }; f')
+test "$result" = "ps"
--- /dev/null
+# $FreeBSD: src/tools/regression/bin/sh/execution/redir6.0,v 1.1 2011/04/23 22:28:56 jilles Exp $
+
+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))
--- /dev/null
+# $FreeBSD: src/tools/regression/bin/sh/execution/redir7.0,v 1.1 2011/04/23 22:28:56 jilles Exp $
+
+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))