summaryrefslogtreecommitdiffstats
path: root/bin
diff options
context:
space:
mode:
Diffstat (limited to 'bin')
-rw-r--r--bin/rm/rm.121
-rw-r--r--bin/sh/eval.c155
-rw-r--r--bin/sh/expand.c64
-rw-r--r--bin/sh/expand.h2
-rw-r--r--bin/sh/histedit.c4
-rw-r--r--bin/sh/mksyntax.c1
-rw-r--r--bin/sh/parser.c98
-rw-r--r--bin/sh/parser.h1
-rw-r--r--bin/sh/sh.128
-rw-r--r--bin/sh/var.c2
10 files changed, 225 insertions, 151 deletions
diff --git a/bin/rm/rm.1 b/bin/rm/rm.1
index 11bc77d..ad81066 100644
--- a/bin/rm/rm.1
+++ b/bin/rm/rm.1
@@ -32,7 +32,7 @@
.\" @(#)rm.1 8.5 (Berkeley) 12/5/94
.\" $FreeBSD$
.\"
-.Dd October 8, 2010
+.Dd October 31, 2010
.Dt RM 1
.Os
.Sh NAME
@@ -100,6 +100,11 @@ Specifying this flag for a read only file will cause
.Nm
to generate an error message and exit.
The file will not be removed or overwritten.
+.Pp
+N.B.: The
+.Fl P
+flag is not considered a security feature
+.Pq see Sx BUGS .
.It Fl R
Attempt to remove the file hierarchy rooted in each
.Ar file
@@ -229,8 +234,12 @@ command appeared in
.Sh BUGS
The
.Fl P
-option assumes that the underlying file system updates existing blocks
-in-place and does not store new data in a new location.
-This is true for UFS but not for ZFS, which is using a Copy-On-Write strategy.
-In addition, only regular files are overwritten, other types of files
-are not.
+option assumes that the underlying storage overwrites file blocks
+when data is written to an existing offset.
+Several factors including the file system and its backing store could defeat
+this assumption.
+This includes, but is not limited to file systems that use a
+Copy-On-Write strategy (e.g. ZFS or UFS when snapshots are being used), Flash
+media that are using a wear leveling algorithm, or when the backing datastore
+does journaling, etc.
+In addition, only regular files are overwritten, other types of files are not.
diff --git a/bin/sh/eval.c b/bin/sh/eval.c
index 499751d..415b9eb 100644
--- a/bin/sh/eval.c
+++ b/bin/sh/eval.c
@@ -196,6 +196,7 @@ void
evaltree(union node *n, int flags)
{
int do_etest;
+ union node *next;
do_etest = 0;
if (n == NULL) {
@@ -203,84 +204,88 @@ evaltree(union node *n, int flags)
exitstatus = 0;
goto out;
}
+ do {
+ next = NULL;
#ifndef NO_HISTORY
- displayhist = 1; /* show history substitutions done with fc */
+ displayhist = 1; /* show history substitutions done with fc */
#endif
- TRACE(("evaltree(%p: %d) called\n", (void *)n, n->type));
- switch (n->type) {
- case NSEMI:
- evaltree(n->nbinary.ch1, flags & ~EV_EXIT);
- if (evalskip)
- goto out;
- evaltree(n->nbinary.ch2, flags);
- break;
- case NAND:
- evaltree(n->nbinary.ch1, EV_TESTED);
- if (evalskip || exitstatus != 0) {
- goto out;
+ TRACE(("evaltree(%p: %d) called\n", (void *)n, n->type));
+ switch (n->type) {
+ case NSEMI:
+ evaltree(n->nbinary.ch1, flags & ~EV_EXIT);
+ if (evalskip)
+ goto out;
+ next = n->nbinary.ch2;
+ break;
+ case NAND:
+ evaltree(n->nbinary.ch1, EV_TESTED);
+ if (evalskip || exitstatus != 0) {
+ goto out;
+ }
+ next = n->nbinary.ch2;
+ break;
+ case NOR:
+ evaltree(n->nbinary.ch1, EV_TESTED);
+ if (evalskip || exitstatus == 0)
+ goto out;
+ next = n->nbinary.ch2;
+ break;
+ case NREDIR:
+ evalredir(n, flags);
+ break;
+ case NSUBSHELL:
+ evalsubshell(n, flags);
+ do_etest = !(flags & EV_TESTED);
+ break;
+ case NBACKGND:
+ evalsubshell(n, flags);
+ break;
+ case NIF: {
+ evaltree(n->nif.test, EV_TESTED);
+ if (evalskip)
+ goto out;
+ if (exitstatus == 0)
+ next = n->nif.ifpart;
+ else if (n->nif.elsepart)
+ next = n->nif.elsepart;
+ else
+ exitstatus = 0;
+ break;
}
- evaltree(n->nbinary.ch2, flags);
- break;
- case NOR:
- evaltree(n->nbinary.ch1, EV_TESTED);
- if (evalskip || exitstatus == 0)
- goto out;
- evaltree(n->nbinary.ch2, flags);
- break;
- case NREDIR:
- evalredir(n, flags);
- break;
- case NSUBSHELL:
- evalsubshell(n, flags);
- do_etest = !(flags & EV_TESTED);
- break;
- case NBACKGND:
- evalsubshell(n, flags);
- break;
- case NIF: {
- evaltree(n->nif.test, EV_TESTED);
- if (evalskip)
- goto out;
- if (exitstatus == 0)
- evaltree(n->nif.ifpart, flags);
- else if (n->nif.elsepart)
- evaltree(n->nif.elsepart, flags);
- else
+ case NWHILE:
+ case NUNTIL:
+ evalloop(n, flags & ~EV_EXIT);
+ break;
+ case NFOR:
+ evalfor(n, flags & ~EV_EXIT);
+ break;
+ case NCASE:
+ evalcase(n, flags);
+ break;
+ case NDEFUN:
+ defun(n->narg.text, n->narg.next);
exitstatus = 0;
- break;
- }
- case NWHILE:
- case NUNTIL:
- evalloop(n, flags & ~EV_EXIT);
- break;
- case NFOR:
- evalfor(n, flags & ~EV_EXIT);
- break;
- case NCASE:
- evalcase(n, flags);
- break;
- case NDEFUN:
- defun(n->narg.text, n->narg.next);
- exitstatus = 0;
- break;
- case NNOT:
- evaltree(n->nnot.com, EV_TESTED);
- exitstatus = !exitstatus;
- break;
-
- case NPIPE:
- evalpipe(n);
- do_etest = !(flags & EV_TESTED);
- break;
- case NCMD:
- evalcommand(n, flags, (struct backcmd *)NULL);
- do_etest = !(flags & EV_TESTED);
- break;
- default:
- out1fmt("Node type = %d\n", n->type);
- flushout(&output);
- break;
- }
+ break;
+ case NNOT:
+ evaltree(n->nnot.com, EV_TESTED);
+ exitstatus = !exitstatus;
+ break;
+
+ case NPIPE:
+ evalpipe(n);
+ do_etest = !(flags & EV_TESTED);
+ break;
+ case NCMD:
+ evalcommand(n, flags, (struct backcmd *)NULL);
+ do_etest = !(flags & EV_TESTED);
+ break;
+ default:
+ out1fmt("Node type = %d\n", n->type);
+ flushout(&output);
+ break;
+ }
+ n = next;
+ } while (n != NULL);
out:
if (pendingsigs)
dotrap();
@@ -1130,7 +1135,7 @@ commandcmd(int argc, char **argv)
return typecmd_impl(2, argv - 1, cmd, path);
}
if (argc != 0)
- error("commandcmd() called while it should not be");
+ error("commandcmd bad call");
/*
* Do nothing successfully if no command was specified;
diff --git a/bin/sh/expand.c b/bin/sh/expand.c
index d33f0ac..200da3f 100644
--- a/bin/sh/expand.c
+++ b/bin/sh/expand.c
@@ -98,7 +98,7 @@ static struct arglist exparg; /* holds expanded arg list */
static void argstr(char *, int);
static char *exptilde(char *, int);
static void expbackq(union node *, int, int);
-static int subevalvar(char *, char *, int, int, int, int);
+static int subevalvar(char *, char *, int, int, int, int, int);
static char *evalvar(char *, int);
static int varisset(char *, int);
static void varvalue(char *, int, int, int);
@@ -216,7 +216,12 @@ argstr(char *p, int flag)
char c;
int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
int firsteq = 1;
+ int split_lit;
+ int lit_quoted;
+ split_lit = flag & EXP_SPLIT_LIT;
+ lit_quoted = flag & EXP_LIT_QUOTED;
+ flag &= ~(EXP_SPLIT_LIT | EXP_LIT_QUOTED);
if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
p = exptilde(p, flag);
for (;;) {
@@ -225,17 +230,25 @@ argstr(char *p, int flag)
case CTLENDVAR:
goto breakloop;
case CTLQUOTEMARK:
+ lit_quoted = 1;
/* "$@" syntax adherence hack */
if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
break;
if ((flag & EXP_FULL) != 0)
STPUTC(c, expdest);
break;
+ case CTLQUOTEEND:
+ lit_quoted = 0;
+ break;
case CTLESC:
if (quotes)
STPUTC(c, expdest);
c = *p++;
STPUTC(c, expdest);
+ if (split_lit && !lit_quoted)
+ recordregion(expdest - stackblock() -
+ (quotes ? 2 : 1),
+ expdest - stackblock(), 0);
break;
case CTLVAR:
p = evalvar(p, flag);
@@ -255,18 +268,21 @@ argstr(char *p, int flag)
* assignments (after the first '=' and after ':'s).
*/
STPUTC(c, expdest);
- if (flag & EXP_VARTILDE && *p == '~') {
- if (c == '=') {
- if (firsteq)
- firsteq = 0;
- else
- break;
- }
+ if (split_lit && !lit_quoted)
+ recordregion(expdest - stackblock() - 1,
+ expdest - stackblock(), 0);
+ if (flag & EXP_VARTILDE && *p == '~' &&
+ (c != '=' || firsteq)) {
+ if (c == '=')
+ firsteq = 0;
p = exptilde(p, flag);
}
break;
default:
STPUTC(c, expdest);
+ if (split_lit && !lit_quoted)
+ recordregion(expdest - stackblock() - 1,
+ expdest - stackblock(), 0);
}
}
breakloop:;
@@ -510,7 +526,7 @@ expbackq(union node *cmd, int quoted, int flag)
static int
subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
- int varflags)
+ int varflags, int quotes)
{
char *startp;
char *loc = NULL;
@@ -555,12 +571,12 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
for (loc = startp; loc < str; loc++) {
c = *loc;
*loc = '\0';
- if (patmatch(str, startp, varflags & VSQUOTE)) {
+ if (patmatch(str, startp, quotes)) {
*loc = c;
goto recordleft;
}
*loc = c;
- if ((varflags & VSQUOTE) && *loc == CTLESC)
+ if (quotes && *loc == CTLESC)
loc++;
}
return 0;
@@ -569,14 +585,13 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
for (loc = str - 1; loc >= startp;) {
c = *loc;
*loc = '\0';
- if (patmatch(str, startp, varflags & VSQUOTE)) {
+ if (patmatch(str, startp, quotes)) {
*loc = c;
goto recordleft;
}
*loc = c;
loc--;
- if ((varflags & VSQUOTE) && loc > startp &&
- *(loc - 1) == CTLESC) {
+ if (quotes && loc > startp && *(loc - 1) == CTLESC) {
for (q = startp; q < loc; q++)
if (*q == CTLESC)
q++;
@@ -588,14 +603,13 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
case VSTRIMRIGHT:
for (loc = str - 1; loc >= startp;) {
- if (patmatch(str, loc, varflags & VSQUOTE)) {
+ if (patmatch(str, loc, quotes)) {
amount = loc - expdest;
STADJUST(amount, expdest);
return 1;
}
loc--;
- if ((varflags & VSQUOTE) && loc > startp &&
- *(loc - 1) == CTLESC) {
+ if (quotes && loc > startp && *(loc - 1) == CTLESC) {
for (q = startp; q < loc; q++)
if (*q == CTLESC)
q++;
@@ -607,12 +621,12 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
case VSTRIMRIGHTMAX:
for (loc = startp; loc < str - 1; loc++) {
- if (patmatch(str, loc, varflags & VSQUOTE)) {
+ if (patmatch(str, loc, quotes)) {
amount = loc - expdest;
STADJUST(amount, expdest);
return 1;
}
- if ((varflags & VSQUOTE) && *loc == CTLESC)
+ if (quotes && *loc == CTLESC)
loc++;
}
return 0;
@@ -742,7 +756,8 @@ record:
case VSPLUS:
case VSMINUS:
if (!set) {
- argstr(p, flag);
+ argstr(p, flag | (flag & EXP_FULL ? EXP_SPLIT_LIT : 0) |
+ (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0));
break;
}
if (easy)
@@ -762,7 +777,7 @@ record:
STPUTC('\0', expdest);
patloc = expdest - stackblock();
if (subevalvar(p, NULL, patloc, subtype,
- startloc, varflags) == 0) {
+ startloc, varflags, quotes) == 0) {
int amount = (expdest - stackblock() - patloc) + 1;
STADJUST(-amount, expdest);
}
@@ -773,7 +788,8 @@ record:
case VSASSIGN:
case VSQUESTION:
if (!set) {
- if (subevalvar(p, var, 0, subtype, startloc, varflags)) {
+ if (subevalvar(p, var, 0, subtype, startloc, varflags,
+ quotes)) {
varflags &= ~VSNUL;
/*
* Remove any recorded regions beyond
@@ -1495,13 +1511,13 @@ rmescapes(char *str)
char *p, *q;
p = str;
- while (*p != CTLESC && *p != CTLQUOTEMARK) {
+ while (*p != CTLESC && *p != CTLQUOTEMARK && *p != CTLQUOTEEND) {
if (*p++ == '\0')
return;
}
q = p;
while (*p) {
- if (*p == CTLQUOTEMARK) {
+ if (*p == CTLQUOTEMARK || *p == CTLQUOTEEND) {
p++;
continue;
}
diff --git a/bin/sh/expand.h b/bin/sh/expand.h
index a3e079a..a4bb198 100644
--- a/bin/sh/expand.h
+++ b/bin/sh/expand.h
@@ -52,6 +52,8 @@ struct arglist {
#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
+#define EXP_SPLIT_LIT 0x20 /* IFS split literal text ${v+-a b c} */
+#define EXP_LIT_QUOTED 0x40 /* for EXP_SPLIT_LIT, start off quoted */
union node;
diff --git a/bin/sh/histedit.c b/bin/sh/histedit.c
index dab69f1..3fc1782 100644
--- a/bin/sh/histedit.c
+++ b/bin/sh/histedit.c
@@ -297,7 +297,7 @@ histcmd(int argc, char **argv)
laststr = argv[1];
break;
default:
- error("too many args");
+ error("too many arguments");
}
/*
* Turn into event numbers.
@@ -329,7 +329,7 @@ histcmd(int argc, char **argv)
editfile = editfilestr;
if ((efp = fdopen(fd, "w")) == NULL) {
close(fd);
- error("can't allocate stdio buffer for temp");
+ error("Out of space");
}
}
diff --git a/bin/sh/mksyntax.c b/bin/sh/mksyntax.c
index e4c4d14..07e8eb7 100644
--- a/bin/sh/mksyntax.c
+++ b/bin/sh/mksyntax.c
@@ -285,6 +285,7 @@ init(void)
syntax[base + CTLARI] = "CCTL";
syntax[base + CTLENDARI] = "CCTL";
syntax[base + CTLQUOTEMARK] = "CCTL";
+ syntax[base + CTLQUOTEEND] = "CCTL";
}
diff --git a/bin/sh/parser.c b/bin/sh/parser.c
index 9500d91..23db5e7 100644
--- a/bin/sh/parser.c
+++ b/bin/sh/parser.c
@@ -106,7 +106,7 @@ static struct parser_temp *parser_temp;
static int noaliases = 0;
-static union node *list(int);
+static union node *list(int, int);
static union node *andor(void);
static union node *pipeline(void);
static union node *command(void);
@@ -220,20 +220,20 @@ parsecmd(int interact)
if (t == TNL)
return NULL;
tokpushback++;
- return list(1);
+ return list(1, 1);
}
static union node *
-list(int nlflag)
+list(int nlflag, int erflag)
{
- union node *n1, *n2, *n3;
+ union node *ntop, *n1, *n2, *n3;
int tok;
checkkwd = 2;
- if (nlflag == 0 && tokendlist[peektoken()])
+ if (!nlflag && !erflag && tokendlist[peektoken()])
return NULL;
- n1 = NULL;
+ ntop = n1 = NULL;
for (;;) {
n2 = andor();
tok = readtoken();
@@ -250,14 +250,21 @@ list(int nlflag)
n2 = n3;
}
}
- if (n1 == NULL) {
- n1 = n2;
+ if (ntop == NULL)
+ ntop = n2;
+ else if (n1 == NULL) {
+ n1 = (union node *)stalloc(sizeof (struct nbinary));
+ n1->type = NSEMI;
+ n1->nbinary.ch1 = ntop;
+ n1->nbinary.ch2 = n2;
+ ntop = n1;
}
else {
n3 = (union node *)stalloc(sizeof (struct nbinary));
n3->type = NSEMI;
- n3->nbinary.ch1 = n1;
+ n3->nbinary.ch1 = n1->nbinary.ch2;
n3->nbinary.ch2 = n2;
+ n1->nbinary.ch2 = n3;
n1 = n3;
}
switch (tok) {
@@ -269,28 +276,28 @@ list(int nlflag)
if (tok == TNL) {
parseheredoc();
if (nlflag)
- return n1;
+ return ntop;
} else if (tok == TEOF && nlflag) {
parseheredoc();
- return n1;
+ return ntop;
} else {
tokpushback++;
}
checkkwd = 2;
- if (tokendlist[peektoken()])
- return n1;
+ if (!nlflag && !erflag && tokendlist[peektoken()])
+ return ntop;
break;
case TEOF:
if (heredoclist)
parseheredoc();
else
pungetc(); /* push back EOF on input */
- return n1;
+ return ntop;
default:
- if (nlflag)
+ if (nlflag || erflag)
synexpect(-1);
tokpushback++;
- return n1;
+ return ntop;
}
}
}
@@ -398,24 +405,24 @@ command(void)
case TIF:
n1 = (union node *)stalloc(sizeof (struct nif));
n1->type = NIF;
- if ((n1->nif.test = list(0)) == NULL)
+ if ((n1->nif.test = list(0, 0)) == NULL)
synexpect(-1);
if (readtoken() != TTHEN)
synexpect(TTHEN);
- n1->nif.ifpart = list(0);
+ n1->nif.ifpart = list(0, 0);
n2 = n1;
while (readtoken() == TELIF) {
n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
n2 = n2->nif.elsepart;
n2->type = NIF;
- if ((n2->nif.test = list(0)) == NULL)
+ if ((n2->nif.test = list(0, 0)) == NULL)
synexpect(-1);
if (readtoken() != TTHEN)
synexpect(TTHEN);
- n2->nif.ifpart = list(0);
+ n2->nif.ifpart = list(0, 0);
}
if (lasttoken == TELSE)
- n2->nif.elsepart = list(0);
+ n2->nif.elsepart = list(0, 0);
else {
n2->nif.elsepart = NULL;
tokpushback++;
@@ -429,13 +436,13 @@ command(void)
int got;
n1 = (union node *)stalloc(sizeof (struct nbinary));
n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
- if ((n1->nbinary.ch1 = list(0)) == NULL)
+ if ((n1->nbinary.ch1 = list(0, 0)) == NULL)
synexpect(-1);
if ((got=readtoken()) != TDO) {
TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
synexpect(TDO);
}
- n1->nbinary.ch2 = list(0);
+ n1->nbinary.ch2 = list(0, 0);
if (readtoken() != TDONE)
synexpect(TDONE);
checkkwd = 1;
@@ -487,7 +494,7 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
t = TEND;
else
synexpect(-1);
- n1->nfor.body = list(0);
+ n1->nfor.body = list(0, 0);
if (readtoken() != t)
synexpect(t);
checkkwd = 1;
@@ -527,7 +534,7 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
ap->narg.next = NULL;
if (lasttoken != TRP)
noaliases = 0, synexpect(TRP);
- cp->nclist.body = list(0);
+ cp->nclist.body = list(0, 0);
checkkwd = 2;
if ((t = readtoken()) != TESAC) {
@@ -545,14 +552,14 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
case TLP:
n1 = (union node *)stalloc(sizeof (struct nredir));
n1->type = NSUBSHELL;
- n1->nredir.n = list(0);
+ n1->nredir.n = list(0, 0);
n1->nredir.redirect = NULL;
if (readtoken() != TRP)
synexpect(TRP);
checkkwd = 1;
break;
case TBEGIN:
- n1 = list(0);
+ n1 = list(0, 0);
if (readtoken() != TEND)
synexpect(TEND);
checkkwd = 1;
@@ -644,9 +651,13 @@ simplecmd(union node **rpp, union node *redir)
/*
* - Require plain text.
* - Functions with '/' cannot be called.
+ * - Reject name=().
+ * - Reject ksh extended glob patterns.
*/
if (!noexpand(n->narg.text) || quoteflag ||
- strchr(n->narg.text, '/'))
+ strchr(n->narg.text, '/') ||
+ strchr("!%*+-=?@}~",
+ n->narg.text[strlen(n->narg.text) - 1]))
synerror("Bad function name");
rmescapes(n->narg.text);
if (find_builtin(n->narg.text, &special) >= 0 &&
@@ -1066,7 +1077,7 @@ done:
doprompt = 0;
}
- n = list(0);
+ n = list(0, oldstyle);
if (oldstyle)
doprompt = saveprompt;
@@ -1161,7 +1172,7 @@ readtoken1(int firstc, char const *initialsyntax, char *eofmark, int striptabs)
loop: { /* for each line, until end of word */
CHECKEND(); /* set c to PEOF if at end of here document */
for (;;) { /* until end of line or end of word */
- CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
+ CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
synentry = state[level].syntax[c];
@@ -1203,12 +1214,18 @@ readtoken1(int firstc, char const *initialsyntax, char *eofmark, int striptabs)
newvarnest == 0)) &&
(c != '}' || state[level].category != TSTATE_VAR_OLD))
USTPUTC('\\', out);
+ if ((eofmark == NULL ||
+ newvarnest > 0) &&
+ state[level].syntax == BASESYNTAX)
+ USTPUTC(CTLQUOTEMARK, out);
if (SQSYNTAX[c] == CCTL)
USTPUTC(CTLESC, out);
- else if (eofmark == NULL ||
- newvarnest > 0)
- USTPUTC(CTLQUOTEMARK, out);
USTPUTC(c, out);
+ if ((eofmark == NULL ||
+ newvarnest > 0) &&
+ state[level].syntax == BASESYNTAX &&
+ state[level].category == TSTATE_VAR_OLD)
+ USTPUTC(CTLQUOTEEND, out);
quotef++;
}
break;
@@ -1224,6 +1241,8 @@ readtoken1(int firstc, char const *initialsyntax, char *eofmark, int striptabs)
if (eofmark != NULL && newvarnest == 0)
USTPUTC(c, out);
else {
+ if (state[level].category == TSTATE_VAR_OLD)
+ USTPUTC(CTLQUOTEEND, out);
state[level].syntax = BASESYNTAX;
quotef++;
}
@@ -1233,11 +1252,12 @@ readtoken1(int firstc, char const *initialsyntax, char *eofmark, int striptabs)
break;
case CENDVAR: /* '}' */
if (level > 0 &&
- (state[level].category == TSTATE_VAR_OLD ||
- state[level].category == TSTATE_VAR_NEW)) {
- if (state[level].category == TSTATE_VAR_OLD)
- state[level - 1].syntax = state[level].syntax;
- else
+ ((state[level].category == TSTATE_VAR_OLD &&
+ state[level].syntax ==
+ state[level - 1].syntax) ||
+ (state[level].category == TSTATE_VAR_NEW &&
+ state[level].syntax == BASESYNTAX))) {
+ if (state[level].category == TSTATE_VAR_NEW)
newvarnest--;
level--;
USTPUTC(CTLENDVAR, out);
@@ -1725,7 +1745,7 @@ getprompt(void *unused __unused)
char *fmt;
const char *pwd;
int i, trim;
- static char internal_error[] = "<internal prompt error>";
+ static char internal_error[] = "??";
/*
* Select prompt format.
diff --git a/bin/sh/parser.h b/bin/sh/parser.h
index 453711f..64ec97f 100644
--- a/bin/sh/parser.h
+++ b/bin/sh/parser.h
@@ -43,6 +43,7 @@
#define CTLARI '\206'
#define CTLENDARI '\207'
#define CTLQUOTEMARK '\210'
+#define CTLQUOTEEND '\211' /* only for ${v+-...} */
/* variable substitution byte (follows CTLVAR) */
#define VSTYPE 0x0f /* type of variable substitution */
diff --git a/bin/sh/sh.1 b/bin/sh/sh.1
index 3499969..d529692 100644
--- a/bin/sh/sh.1
+++ b/bin/sh/sh.1
@@ -32,7 +32,7 @@
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
.\" $FreeBSD$
.\"
-.Dd October 16, 2010
+.Dd October 31, 2010
.Dt SH 1
.Os
.Sh NAME
@@ -40,9 +40,24 @@
.Nd command interpreter (shell)
.Sh SYNOPSIS
.Nm
-.Op Fl /+abCEefIimnPpsTuVvx
+.Op Fl /+abCEefIimnPpTuVvx
.Op Fl /+o Ar longname
-.Op Fl c Ar string
+.Oo
+.Ar script
+.Op Ar arg ...
+.Oc
+.Nm
+.Op Fl /+abCEefIimnPpTuVvx
+.Op Fl /+o Ar longname
+.Fl c Ar string
+.Oo
+.Ar name
+.Op Ar arg ...
+.Oc
+.Nm
+.Op Fl /+abCEefIimnPpTuVvx
+.Op Fl /+o Ar longname
+.Fl s
.Op Ar arg ...
.Sh DESCRIPTION
The
@@ -1109,7 +1124,12 @@ the process ID and its exit status until the
.Ic wait
built-in command reports completion of the process.
.It Li $0
-(zero) Expands to the name of the shell or shell script.
+(zero) Expands to the name of the shell script if passed on the command line,
+the
+.Ar name
+operand if given (with
+.Fl c )
+or otherwise argument 0 passed to the shell.
.El
.Ss Special Variables
The following variables are set by the shell or
diff --git a/bin/sh/var.c b/bin/sh/var.c
index 27bbf50..f5ea775 100644
--- a/bin/sh/var.c
+++ b/bin/sh/var.c
@@ -826,7 +826,7 @@ setvarcmd(int argc, char **argv)
else if (argc == 3)
setvar(argv[1], argv[2], 0);
else
- error("List assignment not implemented");
+ error("too many arguments");
return 0;
}
OpenPOWER on IntegriCloud