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 ***
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to