Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 9 Mar 2014 17:04:32 +0000 (UTC)
From:      Julio Merino <jmmv@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r262951 - in stable/10: bin bin/date bin/date/tests bin/mv bin/mv/tests bin/pax bin/pax/tests bin/sh bin/sh/tests bin/sh/tests/builtins bin/sh/tests/parameters bin/sh/tests/parser bin/t...
Message-ID:  <201403091704.s29H4WZ5055299@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jmmv
Date: Sun Mar  9 17:04:31 2014
New Revision: 262951
URL: http://svnweb.freebsd.org/changeset/base/262951

Log:
  Sync sh(1) in stable/10 to head.
  
  This is a MFC of all the commits listed below.
  
  My original goal of this change was to only merge the move of the tests
  from tools/regression/bin/ into the new layout (which include tests for
  sh(1) and other tools as well).  However, doing so is tricky due to the
  ongoing work in sh(1) and, especially, the many changes to its tests
  since stable/10 was first branched.
  
  Merging everything is the simplest way to achieve this goal and, as a
  bonus point, we get various fixes and miscellaneous improvements into
  the branch.
  
  Per jilles' suggestion, I'm avoiding the merge of a couple of changes
  (r256850 and r257506) that required depending kernel changes.  I'm also
  avoiding very recent changes that have not had a long enough time to be
  validated in current.
  
  This is "make tinderbox" clean.
  
  r256735	sh: Remove one syscall when waiting for a foreground job.
  r257399	sh: Allow trapping SIGINT/SIGQUIT after ignore because of '&'.
  r257504	sh: Reorder union node to reduce its size on 64-bit platforms.
  r257920	sh: Add a test case for would-be assignments that are not due to quoting.
  r257929	sh: Properly quote alias output from command -v.
  r258489	sh: Add tests for the </dev/null implicit in a background command.
  r258533	sh: Add more tests for the </dev/null implicit in a background command.
  r258535	sh: Make <&0 disable the </dev/null implicit in a background command.
  r258776	sh: Prefer memcpy() to strcpy() in most cases. Remove the scopy macro.
  r259047	sh: Split set -x output into a separate function.
  r259210	Migrate tools/regression/bin/ tests to the new layout.
  r259844	sh: Remove an unused variable.
  r259846	sh: Initialize OPTIND=1 even if it came from the environment.
  r259874	sh: Simplify code related to PPID variable.
  r259946	sh: Don't check input for non-whitespace if history is disabled.
  r260246	sh(1): Discourage use of -e.
  r260506	Run the sh(1) and test(1) tests as unprivileged.
  r260586	Mark the bin/pax tests as requiring perl.
  r260634	Use TAP_TESTS_PERL to register the legacy_test in bin/pax.
  r260635	Replace hand-crafted Kyuafiles with automatic generation.
  r260654	sh: Remove SIGWINCH handler and just check for resize before every read.
  r261121	sh: Add test for nested alias.
  r261125	sh: Solve the alias recursion problem in a less hackish way.
  r261141	sh: Do not depend on parse/execute split in new alias test.
  r261160	sh: Add tests for alias names after another alias.
  r261192	sh: Allow aliases to force alias substitution on the following word.
  r262533	sh: Make expari() static.
  r262565	sh: Do not corrupt internal representation if LINENO inner expansion fails.
  r262697	sh: Simplify expari().
  
  Reviewed by:	jilles

Added:
  stable/10/bin/date/tests/
     - copied from r259210, head/bin/date/tests/
  stable/10/bin/mv/tests/
     - copied from r259210, head/bin/mv/tests/
  stable/10/bin/pax/tests/
     - copied from r259210, head/bin/pax/tests/
  stable/10/bin/pax/tests/legacy_test.pl
     - copied unchanged from r260634, head/bin/pax/tests/legacy_test.pl
  stable/10/bin/sh/tests/
     - copied from r259210, head/bin/sh/tests/
  stable/10/bin/sh/tests/builtins/lineno2.0
     - copied unchanged from r262565, head/bin/sh/tests/builtins/lineno2.0
  stable/10/bin/sh/tests/parameters/optind2.0
     - copied unchanged from r259846, head/bin/sh/tests/parameters/optind2.0
  stable/10/bin/sh/tests/parser/alias11.0
     - copied, changed from r261121, head/bin/sh/tests/parser/alias11.0
  stable/10/bin/sh/tests/parser/alias12.0
     - copied unchanged from r261160, head/bin/sh/tests/parser/alias12.0
  stable/10/bin/sh/tests/parser/alias13.0
     - copied unchanged from r261160, head/bin/sh/tests/parser/alias13.0
  stable/10/bin/sh/tests/parser/alias14.0
     - copied unchanged from r261192, head/bin/sh/tests/parser/alias14.0
  stable/10/bin/sh/tests/parser/alias15.0
     - copied unchanged from r261192, head/bin/sh/tests/parser/alias15.0
  stable/10/bin/sh/tests/parser/alias15.0.stdout
     - copied unchanged from r261192, head/bin/sh/tests/parser/alias15.0.stdout
  stable/10/bin/test/tests/
     - copied from r259210, head/bin/test/tests/
  stable/10/bin/tests/
     - copied from r259210, head/bin/tests/
Deleted:
  stable/10/bin/pax/tests/legacy_test.sh
  stable/10/tools/regression/bin/
Modified:
  stable/10/bin/Makefile
  stable/10/bin/date/Makefile
  stable/10/bin/mv/Makefile
  stable/10/bin/pax/Makefile
  stable/10/bin/pax/tests/Makefile
  stable/10/bin/sh/Makefile
  stable/10/bin/sh/alias.c
  stable/10/bin/sh/cd.c
  stable/10/bin/sh/eval.c
  stable/10/bin/sh/exec.c
  stable/10/bin/sh/expand.c
  stable/10/bin/sh/expand.h
  stable/10/bin/sh/input.c
  stable/10/bin/sh/jobs.c
  stable/10/bin/sh/memalloc.c
  stable/10/bin/sh/mystring.c
  stable/10/bin/sh/mystring.h
  stable/10/bin/sh/nodetypes
  stable/10/bin/sh/parser.c
  stable/10/bin/sh/parser.h
  stable/10/bin/sh/redir.c
  stable/10/bin/sh/sh.1
  stable/10/bin/sh/show.c
  stable/10/bin/sh/tests/Makefile
  stable/10/bin/sh/tests/builtins/Makefile
  stable/10/bin/sh/tests/builtins/command3.0.stdout
  stable/10/bin/sh/tests/builtins/command5.0.stdout
  stable/10/bin/sh/tests/builtins/command6.0.stdout
  stable/10/bin/sh/tests/parameters/Makefile
  stable/10/bin/sh/tests/parser/Makefile
  stable/10/bin/sh/trap.c
  stable/10/bin/sh/trap.h
  stable/10/bin/sh/var.c
  stable/10/bin/sh/var.h
  stable/10/bin/test/Makefile
  stable/10/bin/test/tests/Makefile
  stable/10/etc/mtree/BSD.tests.dist
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/bin/Makefile
==============================================================================
--- stable/10/bin/Makefile	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/Makefile	Sun Mar  9 17:04:31 2014	(r262951)
@@ -52,6 +52,10 @@ SUBDIR+=	rmail
 SUBDIR+=	csh
 .endif
 
+.if ${MK_TESTS} != "no"
+SUBDIR+=	tests
+.endif
+
 .include <bsd.arch.inc.mk>
 
 SUBDIR:=	${SUBDIR:O}

Modified: stable/10/bin/date/Makefile
==============================================================================
--- stable/10/bin/date/Makefile	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/date/Makefile	Sun Mar  9 17:04:31 2014	(r262951)
@@ -1,7 +1,13 @@
 #	@(#)Makefile	8.1 (Berkeley) 5/31/93
 # $FreeBSD$
 
+.include <bsd.own.mk>
+
 PROG=	date
 SRCS=	date.c netdate.c vary.c
 
+.if ${MK_TESTS} != "no"
+SUBDIR+=    tests
+.endif
+
 .include <bsd.prog.mk>

Modified: stable/10/bin/mv/Makefile
==============================================================================
--- stable/10/bin/mv/Makefile	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/mv/Makefile	Sun Mar  9 17:04:31 2014	(r262951)
@@ -1,6 +1,12 @@
 #	@(#)Makefile	8.2 (Berkeley) 4/2/94
 # $FreeBSD$
 
+.include <bsd.own.mk>
+
 PROG=	mv
 
+.if ${MK_TESTS} != "no"
+SUBDIR+=    tests
+.endif
+
 .include <bsd.prog.mk>

Modified: stable/10/bin/pax/Makefile
==============================================================================
--- stable/10/bin/pax/Makefile	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/pax/Makefile	Sun Mar  9 17:04:31 2014	(r262951)
@@ -1,6 +1,8 @@
 #       @(#)Makefile	8.1 (Berkeley) 5/31/93
 # $FreeBSD$
 
+.include <bsd.own.mk>
+
 # To install on versions prior to BSD 4.4 the following may have to be
 # defined with CFLAGS +=
 #
@@ -30,4 +32,8 @@ SRCS=	ar_io.c ar_subs.c buf_subs.c cache
 	gen_subs.c getoldopt.c options.c pat_rep.c pax.c sel_subs.c \
 	tables.c tar.c tty_subs.c
 
+.if ${MK_TESTS} != "no"
+SUBDIR+=    tests
+.endif
+
 .include <bsd.prog.mk>

Modified: stable/10/bin/pax/tests/Makefile
==============================================================================
--- head/bin/pax/tests/Makefile	Wed Dec 11 04:09:17 2013	(r259210)
+++ stable/10/bin/pax/tests/Makefile	Sun Mar  9 17:04:31 2014	(r262951)
@@ -4,6 +4,6 @@
 
 TESTSDIR=	${TESTSBASE}/bin/pax
 
-TAP_TESTS_SH=	legacy_test
+TAP_TESTS_PERL=	legacy_test
 
 .include <tap.test.mk>

Copied: stable/10/bin/pax/tests/legacy_test.pl (from r260634, head/bin/pax/tests/legacy_test.pl)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/10/bin/pax/tests/legacy_test.pl	Sun Mar  9 17:04:31 2014	(r262951, copy of r260634, head/bin/pax/tests/legacy_test.pl)
@@ -0,0 +1,89 @@
+# $FreeBSD$
+
+use strict;
+use warnings;
+
+use Test::More tests => 6;
+use File::Path qw(rmtree mkpath);
+use Cwd;
+
+my $n = 0;
+sub create_file {
+    my $fn = shift;
+
+    $n++;
+    (my $dir = $fn) =~ s,/[^/]+$,,;
+    mkpath $dir;
+    open my $fd, ">", $fn or die "$fn: $!";
+    print $fd "file $n\n";
+}
+
+
+ustar_pathnames: { SKIP: {
+    # Prove that pax breaks up ustar pathnames properly
+
+    my $top = getcwd . "/ustar-pathnames-1";
+    skip "Current path is too long", 6 if length $top > 92;
+    rmtree $top;
+    my $subdir = "x" . "x" x (92 - length $top);
+    my $work94 = "$top/$subdir";
+    mkpath $work94;		# $work is 94 characters long
+
+    my $x49 = "x" x 49;
+    my $x50 = "x" x 50;
+    my $x60 = "x" x 60;
+    my $x95 = "x" x 95;
+
+    my @paths = (
+	"$work94/x099",		# 99 chars
+	"$work94/xx100",		# 100 chars
+	"$work94/xxx101",		# 101 chars
+	"$work94/$x49/${x50}x199",	# 199 chars
+	"$work94/$x49/${x50}xx200",	# 200 chars
+	"$work94/$x49/${x50}xxx201",	# 201 chars
+	"$work94/$x60/${x95}254",	# 254 chars
+	"$work94/$x60/${x95}x255",	# 255 chars
+    );
+
+    my @l = map { length } @paths;
+
+    my $n = 0;
+    create_file $_ for @paths;
+    system "pax -wf ustar.ok $work94";
+    ok($? == 0, "Wrote 'ustar.ok' containing files with lengths @l");
+
+    (my $orig = $top) =~ s,1$,2,;
+    rmtree $orig;
+    rename $top, $orig;
+
+    system "pax -rf ustar.ok";
+    ok($? == 0, "Restored 'ustar.ok' containing files with lengths @l");
+
+    system "diff -ru $orig $top";
+    ok($? == 0, "Restored files are identical");
+
+    rmtree $top;
+    rename $orig, $top;
+
+    # 256 chars (with components < 100 chars) should not work
+    push @paths, "$work94/x$x60/${x95}x256";	# 256 chars
+    push @l, length $paths[-1];
+    create_file $paths[-1];
+    system "pax -wf ustar.fail1 $work94";
+    ok($?, "Failed to write 'ustar.fail1' containing files with lengths @l");
+
+    # Components with 100 chars shouldn't work
+    unlink $paths[-1];
+    $paths[-1] = "$work94/${x95}xc100";		# 100 char filename
+    $l[-1] = length $paths[-1];
+    create_file $paths[-1];
+    system "pax -wf ustar.fail2 $work94";
+    ok($?, "Failed to write 'ustar.fail2' with a 100 char filename");
+
+    unlink $paths[-1];
+    $paths[-1] = "$work94/${x95}xc100/x";	# 100 char component
+    $l[-1] = length $paths[-1];
+    create_file $paths[-1];
+    system "pax -wf ustar.fail3 $work94";
+    ok($?, "Failed to write 'ustar.fail3' with a 100 char component");
+}}

Modified: stable/10/bin/sh/Makefile
==============================================================================
--- stable/10/bin/sh/Makefile	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/Makefile	Sun Mar  9 17:04:31 2014	(r262951)
@@ -1,6 +1,8 @@
 #	@(#)Makefile	8.4 (Berkeley) 5/5/95
 # $FreeBSD$
 
+.include <bsd.own.mk>
+
 PROG=	sh
 INSTALLFLAGS= -S
 SHSRCS=	alias.c arith_yacc.c arith_yylex.c cd.c echo.c error.c eval.c \
@@ -59,7 +61,8 @@ syntax.c syntax.h: mksyntax
 token.h: mktokens
 	sh ${.CURDIR}/mktokens
 
-regress:
-	cd ${.CURDIR}/../../tools/regression/bin/sh && ${MAKE} SH=${.OBJDIR}/sh
+.if ${MK_TESTS} != "no"
+SUBDIR+=    tests
+.endif
 
 .include <bsd.prog.mk>

Modified: stable/10/bin/sh/alias.c
==============================================================================
--- stable/10/bin/sh/alias.c	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/alias.c	Sun Mar  9 17:04:31 2014	(r262951)
@@ -68,18 +68,7 @@ setalias(const char *name, const char *v
 		if (equal(name, ap->name)) {
 			INTOFF;
 			ckfree(ap->val);
-			/* See HACK below. */
-#ifdef notyet
 			ap->val	= savestr(val);
-#else
-			{
-			size_t len = strlen(val);
-			ap->val = ckmalloc(len + 2);
-			memcpy(ap->val, val, len);
-			ap->val[len] = ' ';
-			ap->val[len+1] = '\0';
-			}
-#endif
 			INTON;
 			return;
 		}
@@ -88,34 +77,7 @@ setalias(const char *name, const char *v
 	INTOFF;
 	ap = ckmalloc(sizeof (struct alias));
 	ap->name = savestr(name);
-	/*
-	 * XXX - HACK: in order that the parser will not finish reading the
-	 * alias value off the input before processing the next alias, we
-	 * dummy up an extra space at the end of the alias.  This is a crock
-	 * and should be re-thought.  The idea (if you feel inclined to help)
-	 * is to avoid alias recursions.  The mechanism used is: when
-	 * expanding an alias, the value of the alias is pushed back on the
-	 * input as a string and a pointer to the alias is stored with the
-	 * string.  The alias is marked as being in use.  When the input
-	 * routine finishes reading the string, it marks the alias not
-	 * in use.  The problem is synchronization with the parser.  Since
-	 * it reads ahead, the alias is marked not in use before the
-	 * resulting token(s) is next checked for further alias sub.  The
-	 * H A C K is that we add a little fluff after the alias value
-	 * so that the string will not be exhausted.  This is a good
-	 * idea ------- ***NOT***
-	 */
-#ifdef notyet
 	ap->val = savestr(val);
-#else /* hack */
-	{
-	size_t len = strlen(val);
-	ap->val = ckmalloc(len + 2);
-	memcpy(ap->val, val, len);
-	ap->val[len] = ' ';	/* fluff */
-	ap->val[len+1] = '\0';
-	}
-#endif
 	ap->flag = 0;
 	ap->next = *app;
 	*app = ap;
@@ -207,14 +169,8 @@ comparealiases(const void *p1, const voi
 static void
 printalias(const struct alias *a)
 {
-	char *p;
-
 	out1fmt("%s=", a->name);
-	/* Don't print the space added above. */
-	p = a->val + strlen(a->val) - 1;
-	*p = '\0';
 	out1qstr(a->val);
-	*p = ' ';
 	out1c('\n');
 }
 

Modified: stable/10/bin/sh/cd.c
==============================================================================
--- stable/10/bin/sh/cd.c	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/cd.c	Sun Mar  9 17:04:31 2014	(r262951)
@@ -182,6 +182,7 @@ cdlogical(char *dest)
 	struct stat statb;
 	int first;
 	int badstat;
+	size_t len;
 
 	/*
 	 *  Check each component of the path. If we find a symlink or
@@ -189,8 +190,9 @@ cdlogical(char *dest)
 	 *  next time we get the value of the current directory.
 	 */
 	badstat = 0;
-	cdcomppath = stalloc(strlen(dest) + 1);
-	scopy(dest, cdcomppath);
+	len = strlen(dest);
+	cdcomppath = stalloc(len + 1);
+	memcpy(cdcomppath, dest, len + 1);
 	STARTSTACKSTR(p);
 	if (*dest == '/') {
 		STPUTC('/', p);
@@ -275,6 +277,7 @@ findcwd(char *dir)
 {
 	char *new;
 	char *p;
+	size_t len;
 
 	/*
 	 * If our argument is NULL, we don't know the current directory
@@ -283,8 +286,9 @@ findcwd(char *dir)
 	 */
 	if (dir == NULL || curdir == NULL)
 		return getpwd2();
-	cdcomppath = stalloc(strlen(dir) + 1);
-	scopy(dir, cdcomppath);
+	len = strlen(dir);
+	cdcomppath = stalloc(len + 1);
+	memcpy(cdcomppath, dir, len + 1);
 	STARTSTACKSTR(new);
 	if (*dir != '/') {
 		STPUTS(curdir, new);

Modified: stable/10/bin/sh/eval.c
==============================================================================
--- stable/10/bin/sh/eval.c	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/eval.c	Sun Mar  9 17:04:31 2014	(r262951)
@@ -750,6 +750,45 @@ isdeclarationcmd(struct narg *arg)
 		(have_command || !isfunc("local"))));
 }
 
+static void
+xtracecommand(struct arglist *varlist, struct arglist *arglist)
+{
+	struct strlist *sp;
+	char sep = 0;
+	const char *p, *ps4;
+
+	ps4 = expandstr(ps4val());
+	out2str(ps4 != NULL ? ps4 : ps4val());
+	for (sp = varlist->list ; sp ; sp = sp->next) {
+		if (sep != 0)
+			out2c(' ');
+		p = strchr(sp->text, '=');
+		if (p != NULL) {
+			p++;
+			outbin(sp->text, p - sp->text, out2);
+			out2qstr(p);
+		} else
+			out2qstr(sp->text);
+		sep = ' ';
+	}
+	for (sp = arglist->list ; sp ; sp = sp->next) {
+		if (sep != 0)
+			out2c(' ');
+		/* Disambiguate command looking like assignment. */
+		if (sp == arglist->list &&
+				strchr(sp->text, '=') != NULL &&
+				strchr(sp->text, '\'') == NULL) {
+			out2c('\'');
+			out2str(sp->text);
+			out2c('\'');
+		} else
+			out2qstr(sp->text);
+		sep = ' ';
+	}
+	out2c('\n');
+	flushout(&errout);
+}
+
 /*
  * Check if a builtin can safely be executed in the same process,
  * even though it should be in a subshell (command substitution).
@@ -847,40 +886,8 @@ evalcommand(union node *cmd, int flags, 
 	argv -= argc;
 
 	/* Print the command if xflag is set. */
-	if (xflag) {
-		char sep = 0;
-		const char *p, *ps4;
-		ps4 = expandstr(ps4val());
-		out2str(ps4 != NULL ? ps4 : ps4val());
-		for (sp = varlist.list ; sp ; sp = sp->next) {
-			if (sep != 0)
-				out2c(' ');
-			p = strchr(sp->text, '=');
-			if (p != NULL) {
-				p++;
-				outbin(sp->text, p - sp->text, out2);
-				out2qstr(p);
-			} else
-				out2qstr(sp->text);
-			sep = ' ';
-		}
-		for (sp = arglist.list ; sp ; sp = sp->next) {
-			if (sep != 0)
-				out2c(' ');
-			/* Disambiguate command looking like assignment. */
-			if (sp == arglist.list &&
-					strchr(sp->text, '=') != NULL &&
-					strchr(sp->text, '\'') == NULL) {
-				out2c('\'');
-				out2str(sp->text);
-				out2c('\'');
-			} else
-				out2qstr(sp->text);
-			sep = ' ';
-		}
-		out2c('\n');
-		flushout(&errout);
-	}
+	if (xflag)
+		xtracecommand(&varlist, &arglist);
 
 	/* Now locate the command. */
 	if (argc == 0) {

Modified: stable/10/bin/sh/exec.c
==============================================================================
--- stable/10/bin/sh/exec.c	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/exec.c	Sun Mar  9 17:04:31 2014	(r262951)
@@ -187,14 +187,15 @@ padvance(const char **path, const char *
 {
 	const char *p, *start;
 	char *q;
-	size_t len;
+	size_t len, namelen;
 
 	if (*path == NULL)
 		return NULL;
 	start = *path;
 	for (p = start; *p && *p != ':' && *p != '%'; p++)
 		; /* nothing */
-	len = p - start + strlen(name) + 2;	/* "2" is for '/' and '\0' */
+	namelen = strlen(name);
+	len = p - start + namelen + 2;	/* "2" is for '/' and '\0' */
 	STARTSTACKSTR(q);
 	CHECKSTRSPACE(len, q);
 	if (p != start) {
@@ -202,7 +203,7 @@ padvance(const char **path, const char *
 		q += p - start;
 		*q++ = '/';
 	}
-	strcpy(q, name);
+	memcpy(q, name, namelen + 1);
 	pathopt = NULL;
 	if (*p == '%') {
 		pathopt = ++p;
@@ -527,6 +528,7 @@ cmdlookup(const char *name, int add)
 	const char *p;
 	struct tblentry *cmdp;
 	struct tblentry **pp;
+	size_t len;
 
 	p = name;
 	hashval = *p << 4;
@@ -541,11 +543,11 @@ cmdlookup(const char *name, int add)
 	}
 	if (add && cmdp == NULL) {
 		INTOFF;
-		cmdp = *pp = ckmalloc(sizeof (struct tblentry)
-					+ strlen(name) + 1);
+		len = strlen(name);
+		cmdp = *pp = ckmalloc(sizeof (struct tblentry) + len + 1);
 		cmdp->next = NULL;
 		cmdp->cmdtype = CMDUNKNOWN;
-		strcpy(cmdp->cmdname, name);
+		memcpy(cmdp->cmdname, name, len + 1);
 		INTON;
 	}
 	lastcmdentry = pp;
@@ -672,9 +674,11 @@ typecmd_impl(int argc, char **argv, int 
 
 		/* Then look at the aliases */
 		if ((ap = lookupalias(argv[i], 1)) != NULL) {
-			if (cmd == TYPECMD_SMALLV)
-				out1fmt("alias %s='%s'\n", argv[i], ap->val);
-			else
+			if (cmd == TYPECMD_SMALLV) {
+				out1fmt("alias %s=", argv[i]);
+				out1qstr(ap->val);
+				outcslow('\n', out1);
+			} else
 				out1fmt("%s is an alias for %s\n", argv[i],
 				    ap->val);
 			continue;

Modified: stable/10/bin/sh/expand.c
==============================================================================
--- stable/10/bin/sh/expand.c	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/expand.c	Sun Mar  9 17:04:31 2014	(r262951)
@@ -100,6 +100,7 @@ static struct arglist exparg;		/* holds 
 
 static void argstr(char *, int);
 static char *exptilde(char *, int);
+static char *expari(char *);
 static void expbackq(union node *, int, int);
 static int subevalvar(char *, char *, int, int, int, int, int);
 static char *evalvar(char *, int);
@@ -206,7 +207,7 @@ expandarg(union node *arg, struct arglis
 /*
  * Perform parameter expansion, command substitution and arithmetic
  * expansion, and tilde expansion if requested via EXP_TILDE/EXP_VARTILDE.
- * Processing ends at a CTLENDVAR character as well as '\0'.
+ * Processing ends at a CTLENDVAR or CTLENDARI character as well as '\0'.
  * This is used to expand word in ${var+word} etc.
  * If EXP_FULL, EXP_CASE or EXP_REDIR are set, keep and/or generate CTLESC
  * characters to allow for further processing.
@@ -231,6 +232,7 @@ argstr(char *p, int flag)
 		switch (c = *p++) {
 		case '\0':
 		case CTLENDVAR:
+		case CTLENDARI:
 			goto breakloop;
 		case CTLQUOTEMARK:
 			lit_quoted = 1;
@@ -261,8 +263,8 @@ argstr(char *p, int flag)
 			expbackq(argbackq->n, c & CTLQUOTE, flag);
 			argbackq = argbackq->next;
 			break;
-		case CTLENDARI:
-			expari(flag);
+		case CTLARI:
+			p = expari(p);
 			break;
 		case ':':
 		case '=':
@@ -387,59 +389,56 @@ removerecordregions(int endoff)
 }
 
 /*
- * Expand arithmetic expression.  Backup to start of expression,
- * evaluate, place result in (backed up) result, adjust string position.
+ * Expand arithmetic expression.
+ * Note that flag is not required as digits never require CTLESC characters.
  */
-void
-expari(int flag)
+static char *
+expari(char *p)
 {
-	char *p, *q, *start;
+	char *q, *start;
 	arith_t result;
 	int begoff;
-	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
 	int quoted;
+	int c;
+	int nesting;
+	int adj;
 
-	/*
-	 * This routine is slightly over-complicated for
-	 * efficiency.  First we make sure there is
-	 * enough space for the result, which may be bigger
-	 * than the expression.  Next we
-	 * scan backwards looking for the start of arithmetic.  If the
-	 * next previous character is a CTLESC character, then we
-	 * have to rescan starting from the beginning since CTLESC
-	 * characters have to be processed left to right.
-	 */
-	CHECKSTRSPACE(DIGITS(result) - 2, expdest);
-	USTPUTC('\0', expdest);
-	start = stackblock();
-	p = expdest - 2;
-	while (p >= start && *p != CTLARI)
-		--p;
-	if (p < start || *p != CTLARI)
-		error("missing CTLARI (shouldn't happen)");
-	if (p > start && *(p - 1) == CTLESC)
-		for (p = start; *p != CTLARI; p++)
-			if (*p == CTLESC)
-				p++;
-
-	if (p[1] == '"')
-		quoted=1;
-	else
-		quoted=0;
-	begoff = p - start;
+	quoted = *p++ == '"';
+	begoff = expdest - stackblock();
+	argstr(p, 0);
 	removerecordregions(begoff);
-	if (quotes)
-		rmescapes(p+2);
+	STPUTC('\0', expdest);
+	start = stackblock() + begoff;
+
 	q = grabstackstr(expdest);
-	result = arith(p+2);
+	result = arith(start);
 	ungrabstackstr(q, expdest);
-	fmtstr(p, DIGITS(result), ARITH_FORMAT_STR, result);
-	while (*p++)
-		;
-	if (quoted == 0)
-		recordregion(begoff, p - 1 - start, 0);
-	result = expdest - p + 1;
-	STADJUST(-result, expdest);
+
+	start = stackblock() + begoff;
+	adj = start - expdest;
+	STADJUST(adj, expdest);
+
+	CHECKSTRSPACE((int)(DIGITS(result) + 1), expdest);
+	fmtstr(expdest, DIGITS(result), ARITH_FORMAT_STR, result);
+	adj = strlen(expdest);
+	STADJUST(adj, expdest);
+	if (!quoted)
+		recordregion(begoff, expdest - stackblock(), 0);
+	nesting = 1;
+	while (nesting > 0) {
+		c = *p++;
+		if (c == CTLESC)
+			p++;
+		else if (c == CTLARI)
+			nesting++;
+		else if (c == CTLENDARI)
+			nesting--;
+		else if (c == CTLVAR)
+			p++; /* ignore variable substitution byte */
+		else if (c == '\0')
+			return p - 1;
+	}
+	return p;
 }
 
 
@@ -671,10 +670,8 @@ evalvar(char *p, int flag)
 again: /* jump here after setting a variable with ${var=text} */
 	if (varflags & VSLINENO) {
 		set = 1;
-		special = 0;
-		val = var;
-		p[-1] = '\0';	/* temporarily overwrite '=' to have \0
-				   terminated string */
+		special = 1;
+		val = NULL;
 	} else if (special) {
 		set = varisset(var, varflags & VSNUL);
 		val = NULL;
@@ -703,7 +700,10 @@ again: /* jump here after setting a vari
 	if (set && subtype != VSPLUS) {
 		/* insert the value of the variable */
 		if (special) {
-			varvalue(var, varflags & VSQUOTE, subtype, flag);
+			if (varflags & VSLINENO)
+				STPUTBIN(var, p - var - 1, expdest);
+			else
+				varvalue(var, varflags & VSQUOTE, subtype, flag);
 			if (subtype == VSLENGTH) {
 				varlenb = expdest - stackblock() - startloc;
 				varlen = varlenb;
@@ -815,7 +815,6 @@ record:
 	default:
 		abort();
 	}
-	p[-1] = '=';	/* recover overwritten '=' */
 
 	if (subtype != VSNORMAL) {	/* skip to end of alternative */
 		int nesting = 1;
@@ -1307,9 +1306,11 @@ addfname(char *name)
 {
 	char *p;
 	struct strlist *sp;
+	size_t len;
 
-	p = stalloc(strlen(name) + 1);
-	scopy(name, p);
+	len = strlen(name);
+	p = stalloc(len + 1);
+	memcpy(p, name, len + 1);
 	sp = (struct strlist *)stalloc(sizeof *sp);
 	sp->text = p;
 	*exparg.lastp = sp;

Modified: stable/10/bin/sh/expand.h
==============================================================================
--- stable/10/bin/sh/expand.h	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/expand.h	Sun Mar  9 17:04:31 2014	(r262951)
@@ -58,6 +58,5 @@ struct arglist {
 
 union node;
 void expandarg(union node *, struct arglist *, int);
-void expari(int);
 void rmescapes(char *);
 int casematch(union node *, const char *);

Modified: stable/10/bin/sh/input.c
==============================================================================
--- stable/10/bin/sh/input.c	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/input.c	Sun Mar  9 17:04:31 2014	(r262951)
@@ -162,20 +162,16 @@ preadfd(void)
 	int nr;
 	parsenextc = parsefile->buf;
 
-#ifndef NO_HISTORY
-	if (el != NULL && gotwinch) {
-		gotwinch = 0;
-		el_resize(el);
-	}
-#endif
 retry:
 #ifndef NO_HISTORY
 	if (parsefile->fd == 0 && el) {
 		static const char *rl_cp;
 		static int el_len;
 
-		if (rl_cp == NULL)
+		if (rl_cp == NULL) {
+			el_resize(el);
 			rl_cp = el_gets(el, &el_len);
+		}
 		if (rl_cp == NULL)
 			nr = el_len == 0 ? 0 : -1;
 		else {
@@ -228,10 +224,16 @@ preadbuffer(void)
 {
 	char *p, *q;
 	int more;
-	int something;
 	char savec;
 
-	if (parsefile->strpush) {
+	while (parsefile->strpush) {
+		/*
+		 * Add a space to the end of an alias to ensure that the
+		 * alias remains in use while parsing its last word.
+		 * This avoids alias recursions.
+		 */
+		if (parsenleft == -1 && parsefile->strpush->ap != NULL)
+			return ' ';
 		popstring();
 		if (--parsenleft >= 0)
 			return (*parsenextc++);
@@ -252,24 +254,18 @@ again:
 	q = p = parsefile->buf + (parsenextc - parsefile->buf);
 
 	/* delete nul characters */
-	something = 0;
 	for (more = 1; more;) {
 		switch (*p) {
 		case '\0':
 			p++;	/* Skip nul */
 			goto check;
 
-		case '\t':
-		case ' ':
-			break;
-
 		case '\n':
 			parsenleft = q - parsenextc;
 			more = 0; /* Stop processing here */
 			break;
 
 		default:
-			something = 1;
 			break;
 		}
 
@@ -288,7 +284,8 @@ check:
 	*q = '\0';
 
 #ifndef NO_HISTORY
-	if (parsefile->fd == 0 && hist && something) {
+	if (parsefile->fd == 0 && hist &&
+	    parsenextc[strspn(parsenextc, " \t\n")] != '\0') {
 		HistEvent he;
 		INTOFF;
 		history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
@@ -370,12 +367,16 @@ popstring(void)
 	struct strpush *sp = parsefile->strpush;
 
 	INTOFF;
+	if (sp->ap) {
+		if (parsenextc != sp->ap->val &&
+		    (parsenextc[-1] == ' ' || parsenextc[-1] == '\t'))
+			forcealias();
+		sp->ap->flag &= ~ALIASINUSE;
+	}
 	parsenextc = sp->prevstring;
 	parsenleft = sp->prevnleft;
 	parselleft = sp->prevlleft;
 /*out2fmt_flush("*** calling popstring: restoring to '%s'\n", parsenextc);*/
-	if (sp->ap)
-		sp->ap->flag &= ~ALIASINUSE;
 	parsefile->strpush = sp->prev;
 	if (sp != &(parsefile->basestrpush))
 		ckfree(sp);

Modified: stable/10/bin/sh/jobs.c
==============================================================================
--- stable/10/bin/sh/jobs.c	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/jobs.c	Sun Mar  9 17:04:31 2014	(r262951)
@@ -978,7 +978,6 @@ int
 waitforjob(struct job *jp, int *origstatus)
 {
 #if JOBS
-	pid_t mypgrp = getpgrp();
 	int propagate_int = jp->jobctl && jp->foreground;
 #endif
 	int status;
@@ -992,7 +991,7 @@ waitforjob(struct job *jp, int *origstat
 			dotrap();
 #if JOBS
 	if (jp->jobctl) {
-		if (tcsetpgrp(ttyfd, mypgrp) < 0)
+		if (tcsetpgrp(ttyfd, rootpid) < 0)
 			error("tcsetpgrp failed, errno=%d\n", errno);
 	}
 	if (jp->state == JOBSTOPPED)

Modified: stable/10/bin/sh/memalloc.c
==============================================================================
--- stable/10/bin/sh/memalloc.c	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/memalloc.c	Sun Mar  9 17:04:31 2014	(r262951)
@@ -98,9 +98,11 @@ char *
 savestr(const char *s)
 {
 	char *p;
+	size_t len;
 
-	p = ckmalloc(strlen(s) + 1);
-	scopy(s, p);
+	len = strlen(s);
+	p = ckmalloc(len + 1);
+	memcpy(p, s, len + 1);
 	return p;
 }
 

Modified: stable/10/bin/sh/mystring.c
==============================================================================
--- stable/10/bin/sh/mystring.c	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/mystring.c	Sun Mar  9 17:04:31 2014	(r262951)
@@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$");
  * String functions.
  *
  *	equal(s1, s2)		Return true if strings are equal.
- *	scopy(from, to)		Copy a string.
  *	number(s)		Convert a string of digits to an integer.
  *	is_number(s)		Return true if s is a string of digits.
  */
@@ -60,10 +59,6 @@ char nullstr[1];		/* zero length string 
  * equal - #defined in mystring.h
  */
 
-/*
- * scopy - #defined in mystring.h
- */
-
 
 /*
  * prefix -- see if pfx is a prefix of string.

Modified: stable/10/bin/sh/mystring.h
==============================================================================
--- stable/10/bin/sh/mystring.h	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/mystring.h	Sun Mar  9 17:04:31 2014	(r262951)
@@ -40,4 +40,3 @@ int number(const char *);
 int is_number(const char *);
 
 #define equal(s1, s2)	(strcmp(s1, s2) == 0)
-#define scopy(s1, s2)	((void)strcpy(s2, s1))

Modified: stable/10/bin/sh/nodetypes
==============================================================================
--- stable/10/bin/sh/nodetypes	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/nodetypes	Sun Mar  9 17:04:31 2014	(r262951)
@@ -118,16 +118,16 @@ NFROMTO nfile			# fd<> fname
 NAPPEND nfile			# fd>> fname
 NCLOBBER nfile			# fd>| fname
 	type	  int
-	next	  nodeptr		# next redirection in list
 	fd	  int			# file descriptor being redirected
+	next	  nodeptr		# next redirection in list
 	fname	  nodeptr		# file name, in a NARG node
 	expfname  temp	char *expfname	# actual file name
 
 NTOFD ndup			# fd<&dupfd
 NFROMFD ndup			# fd>&dupfd
 	type	  int
-	next	  nodeptr		# next redirection in list
 	fd	  int			# file descriptor being redirected
+	next	  nodeptr		# next redirection in list
 	dupfd	  int			# file descriptor to duplicate
 	vname	  nodeptr		# file name if fd>&$var
 
@@ -135,8 +135,8 @@ NFROMFD ndup			# fd>&dupfd
 NHERE nhere			# fd<<\!
 NXHERE nhere			# fd<<!
 	type	  int
-	next	  nodeptr		# next redirection in list
 	fd	  int			# file descriptor being redirected
+	next	  nodeptr		# next redirection in list
 	doc	  nodeptr		# input to command (NARG node)
 	expdoc    temp	char *expdoc	# actual document (for NXHERE)
 

Modified: stable/10/bin/sh/parser.c
==============================================================================
--- stable/10/bin/sh/parser.c	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/parser.c	Sun Mar  9 17:04:31 2014	(r262951)
@@ -683,6 +683,12 @@ makebinary(int type, union node *n1, uni
 }
 
 void
+forcealias(void)
+{
+	checkkwd |= CHKALIAS;
+}
+
+void
 fixredir(union node *n, const char *text, int err)
 {
 	TRACE(("Fix redir %s %d\n", text, err));

Modified: stable/10/bin/sh/parser.h
==============================================================================
--- stable/10/bin/sh/parser.h	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/parser.h	Sun Mar  9 17:04:31 2014	(r262951)
@@ -76,6 +76,7 @@ extern const char *const parsekwd[];
 
 
 union node *parsecmd(int);
+void forcealias(void);
 void fixredir(union node *, const char *, int);
 int goodname(const char *);
 int isassignment(const char *);

Modified: stable/10/bin/sh/redir.c
==============================================================================
--- stable/10/bin/sh/redir.c	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/redir.c	Sun Mar  9 17:04:31 2014	(r262951)
@@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$");
 struct redirtab {
 	struct redirtab *next;
 	int renamed[10];
+	int fd0_redirected;
 };
 
 
@@ -109,11 +110,14 @@ redirect(union node *redir, int flags)
 		sv = ckmalloc(sizeof (struct redirtab));
 		for (i = 0 ; i < 10 ; i++)
 			sv->renamed[i] = EMPTY;
+		sv->fd0_redirected = fd0_redirected;
 		sv->next = redirlist;
 		redirlist = sv;
 	}
 	for (n = redir ; n ; n = n->nfile.next) {
 		fd = n->nfile.fd;
+		if (fd == 0)
+			fd0_redirected = 1;
 		if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
 		    n->ndup.dupfd == fd)
 			continue; /* redirect from/to same file descriptor */
@@ -134,8 +138,6 @@ redirect(union node *redir, int flags)
 			sv->renamed[fd] = i;
 			INTON;
 		}
-		if (fd == 0)
-			fd0_redirected++;
 		openredirect(n, memory);
 	}
 	if (memory[1])
@@ -303,8 +305,6 @@ popredir(void)
 
 	for (i = 0 ; i < 10 ; i++) {
 		if (rp->renamed[i] != EMPTY) {
-                        if (i == 0)
-                                fd0_redirected--;
 			if (rp->renamed[i] >= 0) {
 				dup2(rp->renamed[i], i);
 				close(rp->renamed[i]);
@@ -314,6 +314,7 @@ popredir(void)
 		}
 	}
 	INTOFF;
+	fd0_redirected = rp->fd0_redirected;
 	redirlist = rp->next;
 	ckfree(rp);
 	INTON;

Modified: stable/10/bin/sh/sh.1
==============================================================================
--- stable/10/bin/sh/sh.1	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/sh.1	Sun Mar  9 17:04:31 2014	(r262951)
@@ -32,7 +32,7 @@
 .\"	from: @(#)sh.1	8.6 (Berkeley) 5/4/95
 .\" $FreeBSD$
 .\"
-.Dd June 14, 2013
+.Dd January 26, 2014
 .Dt SH 1
 .Os
 .Sh NAME
@@ -235,10 +235,16 @@ or
 .Dq Li ||
 operator; or if the command is a pipeline preceded by the
 .Ic !\&
-operator.
+keyword.
 If a shell function is executed and its exit status is explicitly
 tested, all commands of the function are considered to be tested as
 well.
+.Pp
+It is recommended to check for failures explicitly
+instead of relying on
+.Fl e
+because it tends to behave in unexpected ways,
+particularly in larger scripts.
 .It Fl f Li noglob
 Disable pathname expansion.
 .It Fl h Li trackall
@@ -527,6 +533,20 @@ would become
 .Pp
 .Dl "ls -F foobar"
 .Pp
+Aliases are also recognized after an alias
+whose value ends with a space or tab.
+For example, if there is also an alias called
+.Dq Li nohup
+with the value
+.Dq Li "nohup " ,
+then the input
+.Pp
+.Dl "nohup lf foobar"
+.Pp
+would become
+.Pp
+.Dl "nohup ls -F foobar"
+.Pp
 Aliases provide a convenient way for naive users to
 create shorthands for commands without having to learn how
 to create functions with arguments.

Modified: stable/10/bin/sh/show.c
==============================================================================
--- stable/10/bin/sh/show.c	Sun Mar  9 15:36:56 2014	(r262950)
+++ stable/10/bin/sh/show.c	Sun Mar  9 17:04:31 2014	(r262951)
@@ -390,11 +390,11 @@ opentrace(void)
 			else
 				p = "/tmp";
 		}
-		scopy(p, s);
+		strcpy(s, p);
 		strcat(s, "/trace");
 	}
 #else
-	scopy("./trace", s);
+	strcpy(s, "./trace");
 #endif /* not_this_way */
 	if ((tracefile = fopen(s, "a")) == NULL) {
 		fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));

Modified: stable/10/bin/sh/tests/Makefile
==============================================================================
--- head/bin/sh/tests/Makefile	Wed Dec 11 04:09:17 2013	(r259210)
+++ stable/10/bin/sh/tests/Makefile	Sun Mar  9 17:04:31 2014	(r262951)
@@ -6,6 +6,12 @@ TESTSDIR=	${TESTSBASE}/bin/sh
 
 TAP_TESTS_SH=	legacy_test
 TAP_TESTS_SH_SED_legacy_test=	-e 's,__SH__,/bin/sh,g'
+# Some tests in here are silently not run when the tests are executed as
+# root.  Explicitly tell Kyua to drop privileges.
+#
+# TODO(jmmv): Kyua needs to do this by default, not only when explicitly
+# requested.  See https://code.google.com/p/kyua/issues/detail?id=6

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



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