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>