Index: bin/ksh/exec.c
===================================================================
RCS file: /cvs/src/bin/ksh/exec.c,v
retrieving revision 1.64
diff -u -p -r1.64 exec.c
--- bin/ksh/exec.c	30 Dec 2015 09:07:00 -0000	1.64
+++ bin/ksh/exec.c	10 Dec 2016 03:57:51 -0000
@@ -40,9 +40,12 @@ static void	dbteste_error(Test_env *, in
  */
 int
 execute(struct op *volatile t,
-    volatile int flags, volatile int *xerrok)		/* if XEXEC don't fork */
+    volatile int flags,		/* if XEXEC don't fork */
+    volatile int *xerrok)	/* inform recursive callers in -e mode that
+				 * short-circuit && or || shouldn't be treated
+				 * as an error */
 {
-	int i, dummy = 0;
+	int i, dummy = 0, save_xerrok = 0;
 	volatile int rv = 0;
 	int pv[2];
 	char ** volatile ap;
@@ -240,16 +243,14 @@ execute(struct op *volatile t,
 			rv = execute(t->right, flags & XERROK, xerrok);
 		else {
 			flags |= XERROK;
-			if (xerrok)
-				*xerrok = 1;
+			*xerrok = 1;
 		}
 		break;
 
 	case TBANG:
 		rv = !execute(t->right, XERROK, xerrok);
 		flags |= XERROK;
-		if (xerrok)
-			*xerrok = 1;
+		*xerrok = 1;
 		break;
 
 	case TDBRACKET:
@@ -289,10 +290,15 @@ execute(struct op *volatile t,
 		}
 		rv = 0; /* in case of a continue */
 		if (t->type == TFOR) {
+			save_xerrok = *xerrok;
 			while (*ap != NULL) {
 				setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);
+				/* undo xerrok in all iterations except the
+				 * last */
+				*xerrok = save_xerrok;
 				rv = execute(t->left, flags & XERROK, xerrok);
 			}
+			/* ripple xerrok set at final iteration */
 		} else { /* TSELECT */
 			for (;;) {
 				if (!(cp = do_selectargs(ap, is_first))) {
@@ -340,10 +346,10 @@ execute(struct op *volatile t,
 	case TCASE:
 		cp = evalstr(t->str, DOTILDE);
 		for (t = t->left; t != NULL && t->type == TPAT; t = t->right)
-		    for (ap = t->vars; *ap; ap++)
-			if ((s = evalstr(*ap, DOTILDE|DOPAT)) &&
-			    gmatch(cp, s, false))
-				goto Found;
+			for (ap = t->vars; *ap; ap++)
+				if ((s = evalstr(*ap, DOTILDE|DOPAT)) &&
+				    gmatch(cp, s, false))
+					goto Found;
 		break;
 	  Found:
 		rv = execute(t->left, flags & XERROK, xerrok);
@@ -381,8 +387,7 @@ execute(struct op *volatile t,
 	quitenv(NULL);		/* restores IO */
 	if ((flags&XEXEC))
 		unwind(LEXIT);	/* exit child */
-	if (rv != 0 && !(flags & XERROK) &&
-	    (xerrok == NULL || !*xerrok)) {
+	if (rv != 0 && !(flags & XERROK) && !*xerrok) {
 		trapsig(SIGERR_);
 		if (Flag(FERREXIT))
 			unwind(LERROR);
Index: regress/bin/ksh/obsd-regress.t
===================================================================
RCS file: /cvs/src/regress/bin/ksh/obsd-regress.t,v
retrieving revision 1.1
diff -u -p -r1.1 obsd-regress.t
--- regress/bin/ksh/obsd-regress.t	2 Dec 2013 20:39:44 -0000	1.1
+++ regress/bin/ksh/obsd-regress.t	10 Dec 2016 03:57:51 -0000
@@ -173,8 +173,8 @@ stdin:
 
 name: seterror-1
 description:
-	The -e flag should be ignored when executing a compound list
-	followed by an if statement.
+	The -e flag should be ignored on unsuccessful commands before && inside an
+	if statement.
 stdin:
 	if true; then false && false; fi
 	true
@@ -184,8 +184,8 @@ expected-exit: e == 0
 
 name: seterror-2
 description:
-	The -e flag should be ignored when executing a compound list
-	followed by an if statement.
+	The -e flag should be ignored on unsuccessful commands before && inside a
+	nested if statement.
 stdin:
 	if true; then if true; then false && false; fi; fi
 	true
@@ -205,8 +205,8 @@ expected-exit: e == 0
 
 name: seterror-4
 description:
-	The -e flag should be ignored when executing a pipeline
-	beginning with '!'
+	Inside a for statement, the -e flag should be ignored on successful commands
+	before ||, or unsuccessful commands before &&.
 stdin:
 	for i in 1 2 3
 	do
@@ -254,6 +254,110 @@ stdin:
 arguments: !-e!
 expected-stdout:
 	
+---
+
+name: seterror-8
+description:
+	The -e flag within an if statement should terminate && chains on
+	failure in rightmost command.
+stdin:
+	if true; then true && false; fi
+	true
+arguments: !-e!
+expected-exit: e != 0
+---
+
+name: seterror-9
+description:
+	The -e flag within a for statement should terminate && or || chains on
+	failure in rightmost command.
+stdin:
+	for f in 0; do true && false; done
+	true
+arguments: !-e!
+expected-exit: e != 0
+---
+
+name: seterror-10
+description:
+	The -e flag within a while statement should terminate && or || chains on
+	failure in rightmost command.
+stdin:
+	while true; do true && false; done
+	true
+arguments: !-e!
+expected-exit: e != 0
+---
+
+name: seterror-11
+description:
+	Putting it all together for -e mode, test an && chain behaving in different
+	ways in different iterations of a for loop.
+# file x is absent; xx is present
+file-setup: file 644 "xx"
+# file y is absent
+arguments: !-e!
+# first iteration of for loop errors at first branch of &&
+#   execution should continue in spite of -e mode
+# second iteration of for loop errors at second branch of &&
+#   -e mode should trigger exit
+stdin:
+	for f in x xx
+	do
+		test -f $f && test -f y  # final statement in loop
+	done
+	echo "should not print"
+expected-exit: e != 0
+---
+
+name: seterror-12
+description:
+	Putting it all together for -e mode, test an && chain behaving in different
+	ways in different iterations of a while loop.
+# file x is absent; xx is present
+file-setup: file 644 "x"
+# file y is absent
+arguments: !-e!
+# first iteration of for loop errors at first branch of &&
+#   execution should continue in spite of -e mode
+# second iteration of for loop errors at second branch of &&
+#   -e mode should trigger exit
+stdin:
+	x=''
+	y=''
+	while [ "$x" != xxx ]
+	do
+		x=x$x
+		y=y$y
+		test -f $x && test -f y  # final statement in loop
+	done
+	echo "should not print"
+expected-exit: e != 0
+---
+
+name: seterror-13
+description:
+	Putting it all together for -e mode, test an && chain behaving in different
+	ways in different iterations of a until loop.
+# file x is absent; xx is present
+file-setup: file 644 "x"
+# files y and yy are both absent
+arguments: !-e!
+# first iteration of for loop errors at first branch of &&
+#   execution should continue in spite of -e mode
+# second iteration of for loop errors at second branch of &&
+#   -e mode should trigger exit
+stdin:
+	x=''
+	y=''
+	until [ "$x" == xxx ]
+	do
+		x=x$x
+		y=y$y
+		test -f $x && test -f $y  # final statement in loop
+	done
+	echo "should not print"
+expected-exit: e != 0
 ---
 
 name: input-comsub
