Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 1 Jan 2010 18:17:46 +0000 (UTC)
From:      Jilles Tjoelker <jilles@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r201366 - in head: bin/sh tools/regression/bin/sh/expansion
Message-ID:  <201001011817.o01IHkU4089396@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 -@."'
+check '".$(umask -@ 2>&1; :)." = ".umask: Illegal option -@."'
+check '".$({ umask -@; } 2>&1)." = ".umask: Illegal option -@."'
+
+# 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))



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201001011817.o01IHkU4089396>