patch from oksh (except manpage, I'll merge that later):
pass "xerrok" status across the execution call stack to more closely match what both POSIX and [18]ksh.1 already describe in regards to set -e/errexit's behavior in determining when to exit from nonzero return values. specifically, the truth values tested as operands to &&' and ||', as well as the resulting compound expression itself, along with the truth value resulting from a negated command (i.e. a pipeline prefixed !'), should not make the shell exit when -e is in effect. issue reported by matthieu. testing matthieu, naddy. ok miod (earlier version), otto. man page ok jmc.
This commit is contained in:
77
exec.c
77
exec.c
@ -1,11 +1,11 @@
|
||||
/* $OpenBSD: exec.c,v 1.48 2007/09/05 19:02:01 otto Exp $ */
|
||||
/* $OpenBSD: exec.c,v 1.49 2009/01/29 23:27:26 jaredy Exp $ */
|
||||
|
||||
#include "sh.h"
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.50 2009/03/16 15:50:12 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.51 2009/03/22 17:47:36 tg Exp $");
|
||||
|
||||
static int comexec(struct op *, struct tbl *volatile, const char **,
|
||||
int volatile);
|
||||
int volatile, volatile int *);
|
||||
static void scriptexec(struct op *, const char **)
|
||||
__attribute__((noreturn));
|
||||
static int call_builtin(struct tbl *, const char **);
|
||||
@ -21,7 +21,8 @@ static void dbteste_error(Test_env *, int, const char *);
|
||||
*/
|
||||
int
|
||||
execute(struct op *volatile t,
|
||||
volatile int flags) /* if XEXEC don't fork */
|
||||
volatile int flags, /* if XEXEC don't fork */
|
||||
volatile int *xerrok)
|
||||
{
|
||||
int i;
|
||||
volatile int rv = 0;
|
||||
@ -36,7 +37,8 @@ execute(struct op *volatile t,
|
||||
return 0;
|
||||
|
||||
if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
|
||||
return exchild(t, flags & ~XTIME, -1); /* run in sub-process */
|
||||
/* run in sub-process */
|
||||
return exchild(t, flags & ~XTIME, xerrok, -1);
|
||||
|
||||
newenv(E_EXEC);
|
||||
if (trap)
|
||||
@ -95,11 +97,11 @@ execute(struct op *volatile t,
|
||||
|
||||
switch (t->type) {
|
||||
case TCOM:
|
||||
rv = comexec(t, tp, (const char **)ap, flags);
|
||||
rv = comexec(t, tp, (const char **)ap, flags, xerrok);
|
||||
break;
|
||||
|
||||
case TPAREN:
|
||||
rv = execute(t->left, flags|XFORK);
|
||||
rv = execute(t->left, flags | XFORK, xerrok);
|
||||
break;
|
||||
|
||||
case TPIPE:
|
||||
@ -115,7 +117,8 @@ execute(struct op *volatile t,
|
||||
* (: ; cat /etc/termcap) | sleep 1
|
||||
* will hang forever).
|
||||
*/
|
||||
exchild(t->left, flags|XPIPEO|XCCLOSE, pv[0]);
|
||||
exchild(t->left, flags | XPIPEO | XCCLOSE,
|
||||
NULL, pv[0]);
|
||||
ksh_dup2(pv[0], 0, false); /* stdin of next */
|
||||
closepipe(pv);
|
||||
flags |= XPIPEI;
|
||||
@ -124,17 +127,17 @@ execute(struct op *volatile t,
|
||||
restfd(1, e->savefd[1]); /* stdout of last */
|
||||
e->savefd[1] = 0; /* no need to re-restore this */
|
||||
/* Let exchild() close 0 in parent, after fork, before wait */
|
||||
i = exchild(t, flags|XPCLOSE, 0);
|
||||
i = exchild(t, flags | XPCLOSE, xerrok, 0);
|
||||
if (!(flags&XBGND) && !(flags&XXCOM))
|
||||
rv = i;
|
||||
break;
|
||||
|
||||
case TLIST:
|
||||
while (t->type == TLIST) {
|
||||
execute(t->left, flags & XERROK);
|
||||
execute(t->left, flags & XERROK, NULL);
|
||||
t = t->right;
|
||||
}
|
||||
rv = execute(t, flags & XERROK);
|
||||
rv = execute(t, flags & XERROK, xerrok);
|
||||
break;
|
||||
|
||||
case TCOPROC:
|
||||
@ -191,8 +194,8 @@ execute(struct op *volatile t,
|
||||
* job is actually created.
|
||||
*/
|
||||
flags &= ~XEXEC;
|
||||
exchild(t->left, flags|XBGND|XFORK|XCOPROC|XCCLOSE,
|
||||
coproc.readw);
|
||||
exchild(t->left, flags | XBGND | XFORK | XCOPROC | XCCLOSE,
|
||||
NULL, coproc.readw);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -201,20 +204,24 @@ execute(struct op *volatile t,
|
||||
* forks again for async... parent should optimise
|
||||
* this to "foo &"...
|
||||
*/
|
||||
rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK);
|
||||
rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK, xerrok);
|
||||
break;
|
||||
|
||||
case TOR:
|
||||
case TAND:
|
||||
rv = execute(t->left, XERROK);
|
||||
if (t->right != NULL && (rv == 0) == (t->type == TAND))
|
||||
rv = execute(t->right, flags & XERROK);
|
||||
else
|
||||
flags |= XERROK;
|
||||
rv = execute(t->left, XERROK, xerrok);
|
||||
if ((rv == 0) == (t->type == TAND))
|
||||
rv = execute(t->right, XERROK, xerrok);
|
||||
flags |= XERROK;
|
||||
if (xerrok)
|
||||
*xerrok = 1;
|
||||
break;
|
||||
|
||||
case TBANG:
|
||||
rv = !execute(t->right, XERROK);
|
||||
rv = !execute(t->right, XERROK, xerrok);
|
||||
flags |= XERROK;
|
||||
if (xerrok)
|
||||
*xerrok = 1;
|
||||
break;
|
||||
|
||||
case TDBRACKET:
|
||||
@ -257,7 +264,7 @@ execute(struct op *volatile t,
|
||||
if (t->type == TFOR) {
|
||||
while (*ap != NULL) {
|
||||
setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);
|
||||
rv = execute(t->left, flags & XERROK);
|
||||
rv = execute(t->left, flags & XERROK, xerrok);
|
||||
}
|
||||
} else { /* TSELECT */
|
||||
for (;;) {
|
||||
@ -267,7 +274,7 @@ execute(struct op *volatile t,
|
||||
}
|
||||
is_first = false;
|
||||
setstr(global(t->str), cp, KSH_UNWIND_ERROR);
|
||||
rv = execute(t->left, flags & XERROK);
|
||||
rv = execute(t->left, flags & XERROK, xerrok);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -290,17 +297,18 @@ execute(struct op *volatile t,
|
||||
}
|
||||
}
|
||||
rv = 0; /* in case of a continue */
|
||||
while ((execute(t->left, XERROK) == 0) == (t->type == TWHILE))
|
||||
rv = execute(t->right, flags & XERROK);
|
||||
while ((execute(t->left, XERROK, NULL) == 0) ==
|
||||
(t->type == TWHILE))
|
||||
rv = execute(t->right, flags & XERROK, xerrok);
|
||||
break;
|
||||
|
||||
case TIF:
|
||||
case TELIF:
|
||||
if (t->right == NULL)
|
||||
break; /* should be error */
|
||||
rv = execute(t->left, XERROK) == 0 ?
|
||||
execute(t->right->left, flags & XERROK) :
|
||||
execute(t->right->right, flags & XERROK);
|
||||
rv = execute(t->left, XERROK, NULL) == 0 ?
|
||||
execute(t->right->left, flags & XERROK, xerrok) :
|
||||
execute(t->right->right, flags & XERROK, xerrok);
|
||||
break;
|
||||
|
||||
case TCASE:
|
||||
@ -312,11 +320,11 @@ execute(struct op *volatile t,
|
||||
goto Found;
|
||||
break;
|
||||
Found:
|
||||
rv = execute(t->left, flags & XERROK);
|
||||
rv = execute(t->left, flags & XERROK, xerrok);
|
||||
break;
|
||||
|
||||
case TBRACE:
|
||||
rv = execute(t->left, flags & XERROK);
|
||||
rv = execute(t->left, flags & XERROK, xerrok);
|
||||
break;
|
||||
|
||||
case TFUNCT:
|
||||
@ -327,7 +335,7 @@ execute(struct op *volatile t,
|
||||
/* Clear XEXEC so nested execute() call doesn't exit
|
||||
* (allows "ls -l | time grep foo").
|
||||
*/
|
||||
rv = timex(t, flags & ~XEXEC);
|
||||
rv = timex(t, flags & ~XEXEC, xerrok);
|
||||
break;
|
||||
|
||||
case TEXEC: /* an eval'd TCOM */
|
||||
@ -353,7 +361,8 @@ execute(struct op *volatile t,
|
||||
quitenv(NULL); /* restores IO */
|
||||
if ((flags&XEXEC))
|
||||
unwind(LEXIT); /* exit child */
|
||||
if (rv != 0 && !(flags & XERROK)) {
|
||||
if (rv != 0 && !(flags & XERROK) &&
|
||||
(xerrok == NULL || !*xerrok)) {
|
||||
trapsig(SIGERR_);
|
||||
if (Flag(FERREXIT))
|
||||
unwind(LERROR);
|
||||
@ -367,7 +376,7 @@ execute(struct op *volatile t,
|
||||
|
||||
static int
|
||||
comexec(struct op *t, struct tbl *volatile tp, const char **ap,
|
||||
volatile int flags)
|
||||
volatile int flags, volatile int *xerrok)
|
||||
{
|
||||
int i;
|
||||
volatile int rv = 0;
|
||||
@ -579,7 +588,7 @@ comexec(struct op *t, struct tbl *volatile tp, const char **ap,
|
||||
i = sigsetjmp(e->jbuf, 0);
|
||||
if (i == 0) {
|
||||
/* seems odd to pass XERROK here, but at&t ksh does */
|
||||
exstat = execute(tp->val.t, flags & XERROK);
|
||||
exstat = execute(tp->val.t, flags & XERROK, xerrok);
|
||||
i = LRETURN;
|
||||
}
|
||||
kshname = old_kshname;
|
||||
@ -652,7 +661,7 @@ comexec(struct op *t, struct tbl *volatile tp, const char **ap,
|
||||
texec.left = t; /* for tprint */
|
||||
texec.str = tp->val.s;
|
||||
texec.args = ap;
|
||||
rv = exchild(&texec, flags, -1);
|
||||
rv = exchild(&texec, flags, xerrok, -1);
|
||||
break;
|
||||
}
|
||||
Leave:
|
||||
|
Reference in New Issue
Block a user