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