Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss
Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

/bin/sh (aka ash) patches for C-news, etc)

26 views
Skip to first unread message

jim Wilson

unread,
Apr 19, 1993, 3:06:52 AM4/19/93
to

I have been fixing /bin/sh (aka ash) bugs. If you know of shell bugs that
aren't fixed by this patch, or have problems with this patch, send me
a bug report and I will try to fix it.

This patch fixes 7 bugs:
1) correct handling of \ within backquotes
2) don't require \n or ; before do in `for var do'
3) accept redir before (non-simple) command
4) don't expand regexps as case pattern if inside string
5) for a background command, don't redirect stdin to /dev/null if stdin has
been previously redirected
6) set exitstatus for backquoted commands
7) correctly expand $n inside quotes

This patch should fix all problems with C-news.
It also fixes some problems with the SPEC benchmark suite, groff 1.07, etc.

I have test cases for each of these patches for anyone who is interested
in seeing them.

Jim Wilson
wil...@moria.cygnus.com

diff -pr /usr/src/bin/sh/expand.c sh/expand.c
*** /usr/src/bin/sh/expand.c Sun Oct 25 00:07:38 1992
--- sh/expand.c Sun Apr 18 23:34:55 1993
*************** expbackq(cmd, quoted, full)
*** 300,306 ****
if (in.buf)
ckfree(in.buf);
if (in.jp)
! waitforjob(in.jp);
if (quoted == 0)
recordregion(startloc, dest - stackblock(), 0);
TRACE(("evalbackq: size=%d: \"%.*s\"\n",
--- 300,306 ----
if (in.buf)
ckfree(in.buf);
if (in.jp)
! exitstatus = waitforjob(in.jp);
if (quoted == 0)
recordregion(startloc, dest - stackblock(), 0);
TRACE(("evalbackq: size=%d: \"%.*s\"\n",
*************** numvar:
*** 499,505 ****
case '*':
sep = ' ';
allargs:
! syntax = quoted? DQSYNTAX : BASESYNTAX;
for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
/* should insert CTLESC characters */
while (*p) {
--- 499,507 ----
case '*':
sep = ' ';
allargs:
! /* Only emit CTLESC if we will do further processing,
! i.e. if allow_split is set. */
! syntax = quoted && allow_split ? DQSYNTAX : BASESYNTAX;
for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
/* should insert CTLESC characters */
while (*p) {
*************** allargs:
*** 514,520 ****
case '0':
p = arg0;
string:
! syntax = quoted? DQSYNTAX : BASESYNTAX;
while (*p) {
if (syntax[*p] == CCTL)
STPUTC(CTLESC, expdest);
--- 516,524 ----
case '0':
p = arg0;
string:
! /* Only emit CTLESC if we will do further processing,
! i.e. if allow_split is set. */
! syntax = quoted && allow_split ? DQSYNTAX : BASESYNTAX;
while (*p) {
if (syntax[*p] == CCTL)
STPUTC(CTLESC, expdest);
*************** casematch(pattern, val)
*** 1095,1101 ****
argbackq = pattern->narg.backquote;
STARTSTACKSTR(expdest);
ifslastp = NULL;
! argstr(pattern->narg.text, 0);
STPUTC('\0', expdest);
p = grabstackstr(expdest);
result = patmatch(p, val);
--- 1099,1107 ----
argbackq = pattern->narg.backquote;
STARTSTACKSTR(expdest);
ifslastp = NULL;
! /* Preserve any CTLESC characters inserted previously, so that
! we won't expand reg exps which are inside strings. */
! argstr(pattern->narg.text, 1);
STPUTC('\0', expdest);
p = grabstackstr(expdest);
result = patmatch(p, val);
diff -pr /usr/src/bin/sh/jobs.c sh/jobs.c
*** /usr/src/bin/sh/jobs.c Mon Apr 15 17:23:08 1991
--- sh/jobs.c Sat Apr 17 16:16:35 1993
*************** static char sccsid[] = "@(#)jobs.c 5.1 (
*** 56,61 ****
--- 56,62 ----
#include "memalloc.h"
#include "error.h"
#include "mystring.h"
+ #include "redir.h"
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
*************** forkshell(jp, n, mode)
*** 550,556 ****
} else if (mode == FORK_BG) {
ignoresig(SIGINT);
ignoresig(SIGQUIT);
! if (jp == NULL || jp->nprocs == 0) {
close(0);
if (open("/dev/null", O_RDONLY) != 0)
error("Can't open /dev/null");
--- 551,558 ----
} else if (mode == FORK_BG) {
ignoresig(SIGINT);
ignoresig(SIGQUIT);
! if ((jp == NULL || jp->nprocs == 0)
! && ! fd0_redirected_p ()) {
close(0);
if (open("/dev/null", O_RDONLY) != 0)
error("Can't open /dev/null");
*************** forkshell(jp, n, mode)
*** 560,566 ****
if (mode == FORK_BG) {
ignoresig(SIGINT);
ignoresig(SIGQUIT);
! if (jp == NULL || jp->nprocs == 0) {
close(0);
if (open("/dev/null", O_RDONLY) != 0)
error("Can't open /dev/null");
--- 562,569 ----
if (mode == FORK_BG) {
ignoresig(SIGINT);
ignoresig(SIGQUIT);
! if ((jp == NULL || jp->nprocs == 0)
! && ! fd0_redirected_p ()) {
close(0);
if (open("/dev/null", O_RDONLY) != 0)
error("Can't open /dev/null");
diff -pr /usr/src/bin/sh/parser.c sh/parser.c
*** /usr/src/bin/sh/parser.c Mon Apr 15 17:23:22 1991
--- sh/parser.c Sat Apr 17 14:58:56 1993
*************** STATIC union node *list __P((int));
*** 99,105 ****
STATIC union node *andor __P((void));
STATIC union node *pipeline __P((void));
STATIC union node *command __P((void));
! STATIC union node *simplecmd __P((void));
STATIC void parsefname __P((void));
STATIC void parseheredoc __P((void));
STATIC int readtoken __P((void));
--- 99,105 ----
STATIC union node *andor __P((void));
STATIC union node *pipeline __P((void));
STATIC union node *command __P((void));
! STATIC union node *simplecmd __P((union node **, union node *));
STATIC void parsefname __P((void));
STATIC void parseheredoc __P((void));
STATIC int readtoken __P((void));
*************** command() {
*** 264,269 ****
--- 264,279 ----
int t;

checkkwd = 2;
+ redir = 0;
+ rpp = &redir;
+ /* Check for redirection which may precede command */
+ while (readtoken() == TREDIR) {
+ *rpp = n2 = redirnode;
+ rpp = &n2->nfile.next;
+ parsefname();
+ }
+ tokpushback++;
+
switch (readtoken()) {
case TIF:
n1 = (union node *)stalloc(sizeof (struct nif));
*************** TRACE(("expecting DO got %s %s\n", tokna
*** 326,331 ****
--- 336,345 ----
}
*app = NULL;
n1->nfor.args = ap;
+ /* A newline or semicolon is required here to end
+ the list. */
+ if (lasttoken != TNL && lasttoken != TSEMI)
+ synexpect(-1);
} else {
#ifndef GDB_HACK
static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
*************** TRACE(("expecting DO got %s %s\n", tokna
*** 337,345 ****
n2->narg.backquote = NULL;
n2->narg.next = NULL;
n1->nfor.args = n2;
}
- if (lasttoken != TNL && lasttoken != TSEMI)
- synexpect(-1);
checkkwd = 2;
if ((t = readtoken()) == TDO)
t = TDONE;
--- 351,361 ----
n2->narg.backquote = NULL;
n2->narg.next = NULL;
n1->nfor.args = n2;
+ /* A newline or semicolon is optional here. Anything
+ else gets pushed back so we can read it again. */
+ if (lasttoken != TNL && lasttoken != TSEMI)
+ tokpushback++;
}
checkkwd = 2;
if ((t = readtoken()) == TDO)
t = TDONE;
*************** TRACE(("expecting DO got %s %s\n", tokna
*** 411,426 ****
synexpect(TEND);
checkkwd = 1;
break;
case TWORD:
- case TREDIR:
tokpushback++;
! return simplecmd();
default:
synexpect(-1);
}

/* Now check for redirection which may follow command */
- rpp = &redir;
while (readtoken() == TREDIR) {
*rpp = n2 = redirnode;
rpp = &n2->nfile.next;
--- 427,442 ----
synexpect(TEND);
checkkwd = 1;
break;
+ /* Handle an empty command like other simple commands. */
+ case TNL:
case TWORD:
tokpushback++;
! return simplecmd(rpp, redir);
default:
synexpect(-1);
}

/* Now check for redirection which may follow command */
while (readtoken() == TREDIR) {
*rpp = n2 = redirnode;
rpp = &n2->nfile.next;
*************** TRACE(("expecting DO got %s %s\n", tokna
*** 442,455 ****


STATIC union node *
! simplecmd() {
union node *args, **app;
! union node *redir, **rpp;
union node *n;

args = NULL;
app = &args;
! rpp = &redir;
for (;;) {
if (readtoken() == TWORD) {
n = (union node *)stalloc(sizeof (struct narg));
--- 458,481 ----


STATIC union node *
! simplecmd(rpp, redir)
! union node **rpp, *redir;
! {
union node *args, **app;
! union node **orig_rpp = rpp;
union node *n;

+ /* If we don't have any redirections already, then we must reset
+ rpp to be the address of the local redir variable. */
+ if (redir == 0)
+ rpp = &redir;
+
args = NULL;
app = &args;
! /* We save the incoming value, because we need this for shell
! functions. There can not be a redirect or an argument between
! the function name and the open parenthesis. */
! orig_rpp = rpp;
for (;;) {
if (readtoken() == TWORD) {
n = (union node *)stalloc(sizeof (struct narg));
*************** simplecmd() {
*** 463,469 ****
rpp = &n->nfile.next;
parsefname(); /* read name of redirection file */
} else if (lasttoken == TLP && app == &args->narg.next
! && rpp == &redir) {
/* We have a function */
if (readtoken() != TRP)
synexpect(TRP);
--- 489,495 ----
rpp = &n->nfile.next;
parsefname(); /* read name of redirection file */
} else if (lasttoken == TLP && app == &args->narg.next
! && rpp == orig_rpp) {
/* We have a function */
if (readtoken() != TRP)
synexpect(TRP);
*************** readtoken1(firstc, syntax, eofmark, stri
*** 836,847 ****
}
break;
case CBQUOTE: /* '`' */
- if (parsebackquote && syntax == BASESYNTAX) {
- if (out == stackblock())
- return lasttoken = TENDBQUOTE;
- else
- goto endword; /* exit outer loop */
- }
PARSEBACKQOLD();
break;
case CEOF:
--- 862,867 ----
*************** readtoken1(firstc, syntax, eofmark, stri
*** 855,861 ****
}
}
endword:
! if (syntax != BASESYNTAX && eofmark == NULL)
synerror("Unterminated quoted string");
if (varnest != 0) {
startlinno = plinno;
--- 875,881 ----
}
}
endword:
! if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
synerror("Unterminated quoted string");
if (varnest != 0) {
startlinno = plinno;
*************** parsebackq: {
*** 1048,1054 ****
struct jmploc jmploc;
struct jmploc *volatile savehandler;
int savelen;
- int t;

savepbq = parsebackquote;
if (setjmp(jmploc.loc)) {
--- 1068,1073 ----
*************** parsebackq: {
*** 1068,1073 ****
--- 1087,1119 ----
savehandler = handler;
handler = &jmploc;
INTON;
+ if (oldstyle) {
+ /* We must read until the closing backquote, giving special
+ treatment to some slashes, and then push the string and
+ reread it as input, interpreting it normally. */
+ register char *out;
+ register c;
+ int savelen;
+ char *str;
+
+ STARTSTACKSTR(out);
+ while ((c = pgetc ()) != '`') {
+ if (c == '\\') {
+ c = pgetc ();
+ if (c != '\\' && c != '`' && c != '$'
+ && (!dblquote || c != '"'))
+ STPUTC('\\', out);
+ }
+ STPUTC(c, out);
+ }
+ STPUTC('\0', out);
+ savelen = out - stackblock();
+ if (savelen > 0) {
+ str = ckmalloc(savelen);
+ bcopy(stackblock(), str, savelen);
+ }
+ setinputstring(str, 1);
+ }
nlpp = &bqlist;
while (*nlpp)
nlpp = &(*nlpp)->next;
*************** parsebackq: {
*** 1075,1084 ****
(*nlpp)->next = NULL;
parsebackquote = oldstyle;
n = list(0);
! t = oldstyle? TENDBQUOTE : TRP;
! if (readtoken() != t)
! synexpect(t);
(*nlpp)->n = n;
while (stackblocksize() <= savelen)
growstackblock();
STARTSTACKSTR(out);
--- 1121,1132 ----
(*nlpp)->next = NULL;
parsebackquote = oldstyle;
n = list(0);
! if (!oldstyle && (readtoken() != TRP))
! synexpect(TRP);
(*nlpp)->n = n;
+ /* Start reading from old file again. */
+ if (oldstyle)
+ popfile();
while (stackblocksize() <= savelen)
growstackblock();
STARTSTACKSTR(out);
diff -pr /usr/src/bin/sh/redir.c sh/redir.c
*** /usr/src/bin/sh/redir.c Mon Apr 15 17:23:23 1991
--- sh/redir.c Sat Apr 17 16:15:10 1993
*************** struct redirtab {
*** 68,73 ****
--- 68,77 ----

MKINIT struct redirtab *redirlist;

+ /* We keep track of whether or not fd0 has been redirected. This is for
+ background commands, where we want to redirect fd0 to /dev/null only
+ if it hasn't already been redirected. */
+ int fd0_redirected = 0;

#ifdef __STDC__
STATIC void openredirect(union node *, char *);
*************** redirect(redir, flags)
*** 122,127 ****
--- 126,133 ----
} else {
close(fd);
}
+ if (fd == 0)
+ fd0_redirected++;
openredirect(n, memory);
}
if (memory[1])
*************** popredir() {
*** 255,260 ****
--- 261,268 ----

for (i = 0 ; i < 10 ; i++) {
if (rp->renamed[i] != EMPTY) {
+ if (i == 0)
+ fd0_redirected--;
close(i);
if (rp->renamed[i] >= 0) {
copyfd(rp->renamed[i], i);
*************** copyfd(from, to) {
*** 347,350 ****
--- 355,364 ----
return EMPTY;
return newfd;
#endif
+ }
+
+ /* Return true if fd 0 has already been redirected at least once. */
+ int
+ fd0_redirected_p () {
+ return fd0_redirected != 0;
}
diff -pr /usr/src/bin/sh/redir.h sh/redir.h
*** /usr/src/bin/sh/redir.h Mon Apr 15 17:23:24 1991
--- sh/redir.h Sat Apr 17 16:15:09 1993
*************** void redirect(union node *, int);
*** 46,54 ****
--- 46,56 ----
void popredir(void);
void clearredir(void);
int copyfd(int, int);
+ int fd0_redirected_p(void);
#else
void redirect();
void popredir();
void clearredir();
int copyfd();
+ int fd0_redirected_p();
#endif

0 new messages