sh: Do not abort on a redirection error on a compound command.

Redirection errors on subshells already did not abort the shell because
the redirection is executed in the subshell.

Other shells seem to agree that these redirection errors should not abort
the shell.

Also ensure that the redirections will be cleaned up properly in cases like
  command eval '{ shift x; } 2>/dev/null'

Example:
  { echo bad; } </var/empty/x; echo good
This commit is contained in:
jilles 2010-03-14 14:24:35 +00:00
parent b9152e6b95
commit d88c6b2784
3 changed files with 68 additions and 4 deletions

View File

@ -91,6 +91,7 @@ STATIC void evalloop(union node *, int);
STATIC void evalfor(union node *, int);
STATIC void evalcase(union node *, int);
STATIC void evalsubshell(union node *, int);
STATIC void evalredir(union node *, int);
STATIC void expredir(union node *);
STATIC void evalpipe(union node *);
STATIC void evalcommand(union node *, int, struct backcmd *);
@ -221,10 +222,7 @@ evaltree(union node *n, int flags)
evaltree(n->nbinary.ch2, flags);
break;
case NREDIR:
expredir(n->nredir.redirect);
redirect(n->nredir.redirect, REDIR_PUSH);
evaltree(n->nredir.n, flags);
popredir();
evalredir(n, flags);
break;
case NSUBSHELL:
evalsubshell(n, flags);
@ -415,6 +413,46 @@ evalsubshell(union node *n, int flags)
}
/*
* Evaluate a redirected compound command.
*/
STATIC void
evalredir(union node *n, int flags)
{
struct jmploc jmploc;
struct jmploc *savehandler;
volatile int in_redirect = 1;
expredir(n->nredir.redirect);
savehandler = handler;
if (setjmp(jmploc.loc)) {
int e;
handler = savehandler;
e = exception;
if (e == EXERROR || e == EXEXEC) {
popredir();
if (in_redirect) {
exitstatus = 2;
return;
}
}
longjmp(handler->loc, 1);
} else {
INTOFF;
handler = &jmploc;
redirect(n->nredir.redirect, REDIR_PUSH);
in_redirect = 0;
INTON;
evaltree(n->nredir.n, flags);
}
INTOFF;
handler = savehandler;
popredir();
INTON;
}
/*
* Compute the names of the files in a redirection list.

View File

@ -0,0 +1,14 @@
# $FreeBSD$
failures=0
check() {
if ! eval "[ $* ]"; then
echo "Failed: $*"
: $((failures += 1))
fi
}
check '"$({ command eval \{ shift x\; \} 2\>/dev/null; } >/dev/null; echo hi)" = hi'
exit $((failures > 0))

View File

@ -0,0 +1,12 @@
# $FreeBSD$
# A redirection error on a compound command should not abort the shell.
exec 2>/dev/null
{ echo bad; } </var/empty/x
if :; then echo bad; fi </var/empty/x
for i in 1; do echo bad; done </var/empty/x
i=0
while [ $i = 0 ]; do echo bad; i=1; done </var/empty/x
i=0
until [ $i != 0 ]; do echo bad; i=1; done </var/empty/x
case i in *) echo bad ;; esac </var/empty/x
exit 0