On Sun, Oct 05, 2008 at 08:39:11PM +0200, Denys Vlasenko wrote:
>On Thursday 02 October 2008 04:25:45 pm Bernhard Reutner-Fischer wrote:
>> This one works reliably about everywhere:
>> $ (echo "out1" ; echo "err" >&2 ; echo "out2") > foo 2>&1
>> 
>> but ash rejects this:
>> $ (echo "out1" ; echo "err" >&2 ; echo "out2") 2>&1 >& foo
>> ash: syntax error: Bad fd number
>> 
>> It tries to use 'foo' as fd, which is not really appropriate as i think
>> a '>&' implies stdout, does it?
>
>No, it does not:

ok, it refers to the last "to" fd in the example above.
>
>[EMAIL PROTECTED] tmp]# bash
>[EMAIL PROTECTED] tmp]# echo HI >&
>bash: syntax error near unexpected token `newline'
>[EMAIL PROTECTED] tmp]#
>
>Looks like in ">&file" "file" is mandatory.

Ok, but only if there was not previously a target-fd of a redirection.

>
>The attached patch implements it for ash. Please test.

I'll test ASAP and report back, thanks.
>--
>vda

>diff -d -urpN busybox.2/shell/ash.c busybox.3/shell/ash.c
>--- busybox.2/shell/ash.c      2008-09-27 01:49:35.000000000 +0200
>+++ busybox.3/shell/ash.c      2008-10-05 16:27:51.000000000 +0200
>@@ -8,7 +8,6 @@
>  * Copyright (c) 1997-2005 Herbert Xu <[EMAIL PROTECTED]>
>  * was re-ported from NetBSD and debianized.
>  *
>- *
>  * This code is derived from software contributed to Berkeley by
>  * Kenneth Almquist.
>  *
>@@ -28,7 +27,6 @@
>  * used in busybox and size optimizations,
>  * rewrote arith (see notes to this), added locale support,
>  * rewrote dynamic variables.
>- *
>  */
> 
> /*
>@@ -247,8 +245,17 @@ extern struct globals_misc *const ash_pt
> } while (0)
> 
> 
>-/* ============ Interrupts / exceptions */
>+/* ============ Utility functions */
>+static int isdigit_str9(const char *str)
>+{
>+      int maxlen = 9 + 1; /* max 9 digits: 999999999 */
>+      while (--maxlen && isdigit(*str))
>+              str++;
>+      return (*str == '\0');
>+}
> 
>+
>+/* ============ Interrupts / exceptions */
> /*
>  * These macros allow the user to suspend the handling of interrupt signals
>  * over a period of time.  This is similar to SIGHOLD or to sigblock, but
>@@ -500,32 +507,33 @@ static const char dolatstr[] ALIGN1 = {
>       CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
> };
> 
>-#define NCMD 0
>-#define NPIPE 1
>-#define NREDIR 2
>-#define NBACKGND 3
>+#define NCMD      0
>+#define NPIPE     1
>+#define NREDIR    2
>+#define NBACKGND  3
> #define NSUBSHELL 4
>-#define NAND 5
>-#define NOR 6
>-#define NSEMI 7
>-#define NIF 8
>-#define NWHILE 9
>-#define NUNTIL 10
>-#define NFOR 11
>-#define NCASE 12
>-#define NCLIST 13
>-#define NDEFUN 14
>-#define NARG 15
>-#define NTO 16
>-#define NCLOBBER 17
>-#define NFROM 18
>-#define NFROMTO 19
>-#define NAPPEND 20
>-#define NTOFD 21
>-#define NFROMFD 22
>-#define NHERE 23
>-#define NXHERE 24
>-#define NNOT 25
>+#define NAND      5
>+#define NOR       6
>+#define NSEMI     7
>+#define NIF       8
>+#define NWHILE    9
>+#define NUNTIL   10
>+#define NFOR     11
>+#define NCASE    12
>+#define NCLIST   13
>+#define NDEFUN   14
>+#define NARG     15
>+#define NTO      16
>+#define NTO2     17
>+#define NCLOBBER 18
>+#define NFROM    19
>+#define NFROMTO  20
>+#define NAPPEND  21
>+#define NTOFD    22
>+#define NFROMFD  23
>+#define NHERE    24
>+#define NXHERE   25
>+#define NNOT     26
> 
> union node;
> 
>@@ -588,20 +596,26 @@ struct narg {
>       struct nodelist *backquote;
> };
> 
>+/* nfile and ndup layout must match!
>+ * NTOFD (>&) uses ndup structure, but we may discover mid-flight
>+ * that it is actually NTO2 (>&file), and change its type.
>+ */
> struct nfile {
>       smallint type;
>       union node *next;
>       int fd;
>+      int _unused_dupfd;
>       union node *fname;
>       char *expfname;
> };
> 
> struct ndup {
>       smallint type;
>-      union node *next; /* must match nfile's layout */
>-      int fd; /* must match nfile's layout */
>+      union node *next;
>+      int fd;
>       int dupfd;
>       union node *vname;
>+      char *_unused_expfname;
> };
> 
> struct nhere {
>@@ -904,8 +918,9 @@ shcmd(union node *cmd, FILE *fp)
>               case NTO:      s = ">>"+1; dftfd = 1; break;
>               case NCLOBBER: s = ">|"; dftfd = 1; break;
>               case NAPPEND:  s = ">>"; dftfd = 1; break;
>+              case NTO2:
>               case NTOFD:    s = ">&"; dftfd = 1; break;
>-              case NFROM:    s = "<";  break;
>+              case NFROM:    s = "<"; break;
>               case NFROMFD:  s = "<&"; break;
>               case NFROMTO:  s = "<>"; break;
>               default:       s = "*error*"; break;
>@@ -4408,6 +4423,7 @@ cmdtxt(union node *n)
>       case NAPPEND:
>               p = ">>";
>               goto redir;
>+      case NTO2:
>       case NTOFD:
>               p = ">&";
>               goto redir;
>@@ -4797,6 +4813,7 @@ openredirect(union node *redir)
>                       goto ecreate;
>               break;
>       case NTO:
>+      case NTO2:
>               /* Take care of noclobber mode. */
>               if (Cflag) {
>                       fname = redir->nfile.expfname;
>@@ -4959,6 +4976,8 @@ redirect(union node *redir, int flags)
>               union node *tmp = redir;
>               do {
>                       sv_pos++;
>+                      if (redir->nfile.type == NTO2)
>+                              sv_pos++;
>                       tmp = tmp->nfile.next;
>               } while (tmp);
>               sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
>@@ -4997,6 +5016,7 @@ redirect(union node *redir, int flags)
>                               continue;
>                       }
>               }
>+ redirect_more:
>               if (need_to_remember(sv, fd)) {
>                       /* Copy old descriptor */
>                       i = fcntl(fd, F_DUPFD, 10);
>@@ -5039,7 +5059,14 @@ redirect(union node *redir, int flags)
>                       }
>               } else if (fd != newfd) { /* move newfd to fd */
>                       copyfd(newfd, fd | COPYFD_EXACT);
>-                      close(newfd);
>+                      if (!(redir->nfile.type == NTO2 && fd == 2))
>+                              close(newfd);
>+              }
>+              if (redir->nfile.type == NTO2 && fd == 1) {
>+                      /* We already redirected it to fd 1, now copy it to 2 */
>+                      newfd = 1;
>+                      fd = 2;
>+                      goto redirect_more;
>               }
>       } while ((redir = redir->nfile.next) != NULL);
> 
>@@ -7641,6 +7668,7 @@ calcsize(union node *n)
>               calcsize(n->narg.next);
>               break;
>       case NTO:
>+      case NTO2:
>       case NCLOBBER:
>       case NFROM:
>       case NFROMTO:
>@@ -7754,6 +7782,7 @@ copynode(union node *n)
>               new->narg.next = copynode(n->narg.next);
>               break;
>       case NTO:
>+      case NTO2:
>       case NCLOBBER:
>       case NFROM:
>       case NFROMTO:
>@@ -8175,17 +8204,27 @@ expredir(union node *n)
>               case NFROMTO:
>               case NFROM:
>               case NTO:
>+              case NTO2:
>               case NCLOBBER:
>               case NAPPEND:
>                       expandarg(redir->nfile.fname, &fn, EXP_TILDE | 
> EXP_REDIR);
>+ store_expfname:
>                       redir->nfile.expfname = fn.list->text;
>                       break;
>               case NFROMFD:
>-              case NTOFD:
>+              case NTOFD: /* >& */
>                       if (redir->ndup.vname) {
>                               expandarg(redir->ndup.vname, &fn, EXP_FULL | 
> EXP_TILDE);
>                               if (fn.list == NULL)
>                                       ash_msg_and_raise_error("redir error");
>+//FIXME: we used expandarg with different args!
>+                              if (!isdigit_str9(fn.list->text)) {
>+                                      /* >&file, not >&fd */
>+                                      if (redir->nfile.fd != 1) /* 123>&file 
>- BAD */
>+                                              ash_msg_and_raise_error("redir 
>error");
>+                                      redir->type = NTO2;
>+                                      goto store_expfname;
>+                              }
>                               fixredir(redir, fn.list->text, 1);
>                       }
>                       break;
>@@ -10126,7 +10165,7 @@ fixredir(union node *n, const char *text
>               n->ndup.dupfd = -1;
>       else {
>               if (err)
>-                      raise_error_syntax("Bad fd number");
>+                      raise_error_syntax("bad fd number");
>               n->ndup.vname = makename();
>       }
> }
>@@ -10169,7 +10208,7 @@ parsefname(void)
>                       n->type = NXHERE;
>               TRACE(("Here document %d\n", n->type));
>               if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > 
> EOFMARKLEN)
>-                      raise_error_syntax("Illegal eof marker for << 
>redirection");
>+                      raise_error_syntax("illegal eof marker for << 
>redirection");
>               rmescapes(wordtext);
>               here->eofmark = wordtext;
>               here->next = NULL;
>@@ -10261,7 +10300,7 @@ simplecmd(void)
>                               if (!goodname(name)
>                                || ((bcmd = find_builtin(name)) && 
> IS_BUILTIN_SPECIAL(bcmd))
>                               ) {
>-                                      raise_error_syntax("Bad function name");
>+                                      raise_error_syntax("bad function name");
>                               }
>                               n->type = NDEFUN;
>                               checkkwd = CHKNL | CHKKWD | CHKALIAS;
>@@ -10346,7 +10385,7 @@ parse_command(void)
>       }
>       case TFOR:
>               if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
>-                      raise_error_syntax("Bad for loop variable");
>+                      raise_error_syntax("bad for loop variable");
>               n1 = stzalloc(sizeof(struct nfor));
>               n1->type = NFOR;
>               n1->nfor.var = wordtext;
>@@ -10748,25 +10787,21 @@ readtoken1(int firstc, int syntax, char 
>  endword:
> #if ENABLE_ASH_MATH_SUPPORT
>       if (syntax == ARISYNTAX)
>-              raise_error_syntax("Missing '))'");
>+              raise_error_syntax("missing '))'");
> #endif
>       if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
>-              raise_error_syntax("Unterminated quoted string");
>+              raise_error_syntax("unterminated quoted string");
>       if (varnest != 0) {
>               startlinno = plinno;
>               /* { */
>-              raise_error_syntax("Missing '}'");
>+              raise_error_syntax("missing '}'");
>       }
>       USTPUTC('\0', out);
>       len = out - (char *)stackblock();
>       out = stackblock();
>       if (eofmark == NULL) {
>               if ((c == '>' || c == '<') && quotef == 0) {
>-                      int maxlen = 9 + 1; /* max 9 digit fd#: 999999999 */
>-                      char *np = out;
>-                      while (--maxlen && isdigit(*np))
>-                              np++;
>-                      if (*np == '\0') {
>+                      if (isdigit_str9(out)) {
>                               PARSEREDIR(); /* passed as params: out, c */
>                               lasttoken = TREDIR;
>                               return lasttoken;
>@@ -10841,6 +10876,7 @@ parseredir: {
>                       np->type = NCLOBBER;
>               else if (c == '&')
>                       np->type = NTOFD;
>+                      /* it also can be NTO2 (>&file), but we can't figure it 
>out yet */
>               else {
>                       np->type = NTO;
>                       pungetc();
>@@ -10954,8 +10990,10 @@ parsesub: {
>               } else if (is_special(c)) {
>                       USTPUTC(c, out);
>                       c = pgetc();
>-              } else
>- badsub:              raise_error_syntax("Bad substitution");
>+              } else {
>+ badsub:
>+                      raise_error_syntax("bad substitution");
>+              }
> 
>               STPUTC('=', out);
>               flags = 0;

_______________________________________________
busybox mailing list
[email protected]
http://busybox.net/cgi-bin/mailman/listinfo/busybox

Reply via email to