svn commit: r201366 - in head: bin/sh
tools/regression/bin/sh/expansion
Jilles Tjoelker
jilles at FreeBSD.org
Fri Jan 1 18:17:47 UTC 2010
Author: jilles
Date: Fri Jan 1 18:17:46 2010
New Revision: 201366
URL: http://svn.freebsd.org/changeset/base/201366
Log:
sh: Fix some bugs with backquoted builtins:
- correctly handle error output in $(builtin 2>&1), clarify out1/out2 vs
output/errout in the code
- treat all builtins as regular builtins so errors do not abort the shell
and variable assignments do not persist
- respect the caller's INTOFF
Some bugs still exist:
- expansion errors may still abort the shell
- some side effects of expansions and builtins persist
Added:
head/tools/regression/bin/sh/expansion/cmdsubst1.0 (contents, props changed)
Modified:
head/bin/sh/error.c
head/bin/sh/eval.c
head/bin/sh/exec.c
head/bin/sh/expand.c
head/bin/sh/output.h
head/bin/sh/parser.c
Modified: head/bin/sh/error.c
==============================================================================
--- head/bin/sh/error.c Fri Jan 1 17:30:58 2010 (r201365)
+++ head/bin/sh/error.c Fri Jan 1 18:17:46 2010 (r201366)
@@ -160,8 +160,8 @@ exverror(int cond, const char *msg, va_l
#endif
if (msg) {
if (commandname)
- outfmt(&errout, "%s: ", commandname);
- doformat(&errout, msg, ap);
+ outfmt(out2, "%s: ", commandname);
+ doformat(out2, msg, ap);
out2c('\n');
}
flushall();
Modified: head/bin/sh/eval.c
==============================================================================
--- head/bin/sh/eval.c Fri Jan 1 17:30:58 2010 (r201365)
+++ head/bin/sh/eval.c Fri Jan 1 18:17:46 2010 (r201366)
@@ -646,7 +646,7 @@ evalcommand(union node *cmd, int flags,
out2str(ps4val());
for (sp = varlist.list ; sp ; sp = sp->next) {
if (sep != 0)
- outc(' ', &errout);
+ out2c(' ');
p = sp->text;
while (*p != '=' && *p != '\0')
out2c(*p++);
@@ -658,7 +658,7 @@ evalcommand(union node *cmd, int flags,
}
for (sp = arglist.list ; sp ; sp = sp->next) {
if (sep != 0)
- outc(' ', &errout);
+ out2c(' ');
/* Disambiguate command looking like assignment. */
if (sp == arglist.list &&
strchr(sp->text, '=') != NULL &&
@@ -670,7 +670,7 @@ evalcommand(union node *cmd, int flags,
out2qstr(sp->text);
sep = ' ';
}
- outc('\n', &errout);
+ out2c('\n');
flushout(&errout);
}
@@ -722,9 +722,8 @@ evalcommand(union node *cmd, int flags,
break;
if ((cmdentry.u.index = find_builtin(*argv,
&cmdentry.special)) < 0) {
- outfmt(&errout, "%s: not found\n", *argv);
+ out2fmt_flush("%s: not found\n", *argv);
exitstatus = 127;
- flushout(&errout);
return;
}
if (cmdentry.u.index != BLTINCMD)
@@ -832,6 +831,7 @@ evalcommand(union node *cmd, int flags,
memout.nextc = memout.buf;
memout.bufsize = 64;
mode |= REDIR_BACKQ;
+ cmdentry.special = 0;
}
savecmdname = commandname;
savetopfile = getcurrentfile();
@@ -865,20 +865,21 @@ cmddone:
}
}
handler = savehandler;
+ if (flags == EV_BACKCMD) {
+ backcmd->buf = memout.buf;
+ backcmd->nleft = memout.nextc - memout.buf;
+ memout.buf = NULL;
+ }
if (e != -1) {
if ((e != EXERROR && e != EXEXEC)
|| cmdentry.special)
exraise(e);
popfilesupto(savetopfile);
- FORCEINTON;
+ if (flags != EV_BACKCMD)
+ FORCEINTON;
}
if (cmdentry.u.index != EXECCMD)
popredir();
- if (flags == EV_BACKCMD) {
- backcmd->buf = memout.buf;
- backcmd->nleft = memout.nextc - memout.buf;
- memout.buf = NULL;
- }
} else {
#ifdef DEBUG
trputs("normal command: "); trargs(argv);
Modified: head/bin/sh/exec.c
==============================================================================
--- head/bin/sh/exec.c Fri Jan 1 17:30:58 2010 (r201365)
+++ head/bin/sh/exec.c Fri Jan 1 18:17:46 2010 (r201366)
@@ -255,7 +255,7 @@ hashcmd(int argc __unused, char **argv _
if (cmdp != NULL)
printentry(cmdp, verbose);
else
- outfmt(&errout, "%s: not found\n", name);
+ outfmt(out2, "%s: not found\n", name);
}
flushall();
}
Modified: head/bin/sh/expand.c
==============================================================================
--- head/bin/sh/expand.c Fri Jan 1 17:30:58 2010 (r201365)
+++ head/bin/sh/expand.c Fri Jan 1 18:17:46 2010 (r201366)
@@ -526,7 +526,7 @@ subevalvar(char *p, char *str, int strlo
case VSQUESTION:
if (*p != CTLENDVAR) {
- outfmt(&errout, "%s\n", startp);
+ outfmt(out2, "%s\n", startp);
error((char *)NULL);
}
error("%.*s: parameter %snot set", (int)(p - str - 1),
Modified: head/bin/sh/output.h
==============================================================================
--- head/bin/sh/output.h Fri Jan 1 17:30:58 2010 (r201365)
+++ head/bin/sh/output.h Fri Jan 1 18:17:46 2010 (r201366)
@@ -46,11 +46,12 @@ struct output {
short flags;
};
-extern struct output output;
-extern struct output errout;
+extern struct output output; /* to fd 1 */
+extern struct output errout; /* to fd 2 */
extern struct output memout;
-extern struct output *out1;
-extern struct output *out2;
+extern struct output *out1; /* &memout if backquote, otherwise &output */
+extern struct output *out2; /* &memout if backquote with 2>&1, otherwise
+ &errout */
void out1str(const char *);
void out1qstr(const char *);
Modified: head/bin/sh/parser.c
==============================================================================
--- head/bin/sh/parser.c Fri Jan 1 17:30:58 2010 (r201365)
+++ head/bin/sh/parser.c Fri Jan 1 18:17:46 2010 (r201366)
@@ -1560,8 +1560,8 @@ STATIC void
synerror(const char *msg)
{
if (commandname)
- outfmt(&errout, "%s: %d: ", commandname, startlinno);
- outfmt(&errout, "Syntax error: %s\n", msg);
+ outfmt(out2, "%s: %d: ", commandname, startlinno);
+ outfmt(out2, "Syntax error: %s\n", msg);
error((char *)NULL);
}
Added: head/tools/regression/bin/sh/expansion/cmdsubst1.0
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/tools/regression/bin/sh/expansion/cmdsubst1.0 Fri Jan 1 18:17:46 2010 (r201366)
@@ -0,0 +1,48 @@
+# $FreeBSD$
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$(echo abcde)" = "abcde"'
+check '"$(echo abcde; :)" = "abcde"'
+
+check '"$(printf abcde)" = "abcde"'
+check '"$(printf abcde; :)" = "abcde"'
+
+# regular
+check '-n "$(umask)"'
+check '-n "$(umask; :)"'
+check '-n "$(umask 2>&1)"'
+check '-n "$(umask 2>&1; :)"'
+
+# special
+check '-n "$(times)"'
+check '-n "$(times; :)"'
+check '-n "$(times 2>&1)"'
+check '-n "$(times 2>&1; :)"'
+
+# regular
+check '".$(umask -@ 2>&1)." = ".umask: Illegal option - at ."'
+check '".$(umask -@ 2>&1; :)." = ".umask: Illegal option - at ."'
+check '".$({ umask -@; } 2>&1)." = ".umask: Illegal option - at ."'
+
+# special
+check '".$(shift xyz 2>&1)." = ".shift: Illegal number: xyz."'
+check '".$(shift xyz 2>&1; :)." = ".shift: Illegal number: xyz."'
+check '".$({ shift xyz; } 2>&1)." = ".shift: Illegal number: xyz."'
+
+v=1
+check '-z "$(v=2 :)"'
+check '"$v" = 1'
+check '-z "$(v=3)"'
+check '"$v" = 1'
+check '"$(v=4 eval echo \$v)" = 4'
+check '"$v" = 1'
+
+exit $((failures > 0))
More information about the svn-src-head
mailing list