Subject: bin/236: ash(1) parser is broken w.r.t. backgnd commands
To: None <gnats-admin>
From: Mark Weaver <mhw@cs.brown.edu>
List: netbsd-bugs
Date: 04/27/1994 20:20:02
>Number: 236
>Category: bin
>Synopsis: ash(1) parser is broken w.r.t. backgnd commands
>Confidential: no
>Severity: critical
>Priority: high
>Responsible: gnats-admin (Utility Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: mhw
>Arrival-Date: Wed Apr 27 20:20:02 1994
>Originator: Mark Weaver
>Organization:
--------------------------------------------------------------------
Email: Mark_Weaver@brown.edu | Brown University
PGP Key: finger mhw@cs.brown.edu | Dept of Computer Science
>Release: current-940427
>Environment:
System: NetBSD cis-ts3-slip4.cis.brown.edu 0.9a EXCELSIOR#2 i386
>Description:
Typing "sleep 1; sleep 10 &" executes the equivalent (roughly)
of "{ sleep 1; sleep 10; } &". This is because the parser is
broken w.r.t. lists. When a "&" is encountered in a list, all
the prior commands are grouped together and backgrounded, instead
of only the previous and-or construct being backgrounded.
This bug was reported earlier as well, claiming that the problem
occured within if statements only. Actually, it happens in any
list. However, in the outer body of the shell script, a list is
terminated at each newline (as a memory optimization), so the
problem went unnoticed.
>How-To-Repeat:
$ sleep 1; sleep 10 &
$ jobs
[1] 321 sleep 1; sleep 10
$
(first command above returns immediately)
mhw ~ % cat t
#!/bin/sh
(
sleep 2
echo 1
echo 2 &
echo 3
wait
)
mhw ~ % sh t
3
1
2
(with a 2 second pause after the 3 is printed)
>Fix:
*** parser.c.mhw1 Fri Dec 17 00:48:39 1993
--- parser.c Wed Apr 27 22:50:51 1994
***************
*** 144,174 ****
STATIC union node *
list(nlflag) {
union node *n1, *n2, *n3;
checkkwd = 2;
if (nlflag == 0 && tokendlist[peektoken()])
return NULL;
! n1 = andor();
for (;;) {
! switch (readtoken()) {
! case TBACKGND:
! if (n1->type == NCMD || n1->type == NPIPE) {
! n1->ncmd.backgnd = 1;
! } else if (n1->type == NREDIR) {
! n1->type = NBACKGND;
} else {
n3 = (union node *)stalloc(sizeof (struct nredir));
n3->type = NBACKGND;
! n3->nredir.n = n1;
n3->nredir.redirect = NULL;
! n1 = n3;
}
! goto tsemi;
! case TNL:
! tokpushback++;
/* fall through */
! tsemi: case TSEMI:
! if (readtoken() == TNL) {
parseheredoc();
if (nlflag)
return n1;
--- 144,188 ----
STATIC union node *
list(nlflag) {
union node *n1, *n2, *n3;
+ int tok;
checkkwd = 2;
if (nlflag == 0 && tokendlist[peektoken()])
return NULL;
! n1 = NULL;
for (;;) {
! n2 = andor();
! tok = readtoken();
! if (tok == TBACKGND) {
! if (n2->type == NCMD || n2->type == NPIPE) {
! n2->ncmd.backgnd = 1;
! } else if (n2->type == NREDIR) {
! n2->type = NBACKGND;
} else {
n3 = (union node *)stalloc(sizeof (struct nredir));
n3->type = NBACKGND;
! n3->nredir.n = n2;
n3->nredir.redirect = NULL;
! n2 = n3;
}
! }
! if (n1 == NULL) {
! n1 = n2;
! }
! else {
! n3 = (union node *)stalloc(sizeof (struct nbinary));
! n3->type = NSEMI;
! n3->nbinary.ch1 = n1;
! n3->nbinary.ch2 = n2;
! n1 = n3;
! }
! switch (tok) {
! case TBACKGND:
! case TSEMI:
! tok = readtoken();
/* fall through */
! case TNL:
! if (tok == TNL) {
parseheredoc();
if (nlflag)
return n1;
***************
*** 178,189 ****
checkkwd = 2;
if (tokendlist[peektoken()])
return n1;
- n2 = andor();
- n3 = (union node *)stalloc(sizeof (struct nbinary));
- n3->type = NSEMI;
- n3->nbinary.ch1 = n1;
- n3->nbinary.ch2 = n2;
- n1 = n3;
break;
case TEOF:
if (heredoclist)
--- 192,197 ----
>Audit-Trail:
>Unformatted:
------------------------------------------------------------------------------