aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-10-05 18:39:31 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-10-05 18:39:31 +0000
commit559691a3bfcb66ccf1cb59060d62d042e0265c00 (patch)
treea876b9f84c307dd1e0e02a193bdd390c580884ae
parent93d0776a96919a94fca51fe2cfd9530d8c9dcbb9 (diff)
downloadbusybox-w32-559691a3bfcb66ccf1cb59060d62d042e0265c00.tar.gz
busybox-w32-559691a3bfcb66ccf1cb59060d62d042e0265c00.tar.bz2
busybox-w32-559691a3bfcb66ccf1cb59060d62d042e0265c00.zip
ash: implement ">&file" bashism. ~100 bytes.
-rw-r--r--shell/ash.c158
1 files changed, 111 insertions, 47 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 0878237bf..9ccb1c9ee 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -8,7 +8,6 @@
8 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au> 8 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
9 * was re-ported from NetBSD and debianized. 9 * was re-ported from NetBSD and debianized.
10 * 10 *
11 *
12 * This code is derived from software contributed to Berkeley by 11 * This code is derived from software contributed to Berkeley by
13 * Kenneth Almquist. 12 * Kenneth Almquist.
14 * 13 *
@@ -28,7 +27,6 @@
28 * used in busybox and size optimizations, 27 * used in busybox and size optimizations,
29 * rewrote arith (see notes to this), added locale support, 28 * rewrote arith (see notes to this), added locale support,
30 * rewrote dynamic variables. 29 * rewrote dynamic variables.
31 *
32 */ 30 */
33 31
34/* 32/*
@@ -247,8 +245,17 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
247} while (0) 245} while (0)
248 246
249 247
250/* ============ Interrupts / exceptions */ 248/* ============ Utility functions */
249static int isdigit_str9(const char *str)
250{
251 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
252 while (--maxlen && isdigit(*str))
253 str++;
254 return (*str == '\0');
255}
256
251 257
258/* ============ Interrupts / exceptions */
252/* 259/*
253 * These macros allow the user to suspend the handling of interrupt signals 260 * These macros allow the user to suspend the handling of interrupt signals
254 * over a period of time. This is similar to SIGHOLD or to sigblock, but 261 * over a period of time. This is similar to SIGHOLD or to sigblock, but
@@ -500,32 +507,35 @@ static const char dolatstr[] ALIGN1 = {
500 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' 507 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
501}; 508};
502 509
503#define NCMD 0 510#define NCMD 0
504#define NPIPE 1 511#define NPIPE 1
505#define NREDIR 2 512#define NREDIR 2
506#define NBACKGND 3 513#define NBACKGND 3
507#define NSUBSHELL 4 514#define NSUBSHELL 4
508#define NAND 5 515#define NAND 5
509#define NOR 6 516#define NOR 6
510#define NSEMI 7 517#define NSEMI 7
511#define NIF 8 518#define NIF 8
512#define NWHILE 9 519#define NWHILE 9
513#define NUNTIL 10 520#define NUNTIL 10
514#define NFOR 11 521#define NFOR 11
515#define NCASE 12 522#define NCASE 12
516#define NCLIST 13 523#define NCLIST 13
517#define NDEFUN 14 524#define NDEFUN 14
518#define NARG 15 525#define NARG 15
519#define NTO 16 526#define NTO 16
520#define NCLOBBER 17 527#if ENABLE_ASH_BASH_COMPAT
521#define NFROM 18 528#define NTO2 17
522#define NFROMTO 19 529#endif
523#define NAPPEND 20 530#define NCLOBBER 18
524#define NTOFD 21 531#define NFROM 19
525#define NFROMFD 22 532#define NFROMTO 20
526#define NHERE 23 533#define NAPPEND 21
527#define NXHERE 24 534#define NTOFD 22
528#define NNOT 25 535#define NFROMFD 23
536#define NHERE 24
537#define NXHERE 25
538#define NNOT 26
529 539
530union node; 540union node;
531 541
@@ -588,20 +598,26 @@ struct narg {
588 struct nodelist *backquote; 598 struct nodelist *backquote;
589}; 599};
590 600
601/* nfile and ndup layout must match!
602 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
603 * that it is actually NTO2 (>&file), and change its type.
604 */
591struct nfile { 605struct nfile {
592 smallint type; 606 smallint type;
593 union node *next; 607 union node *next;
594 int fd; 608 int fd;
609 int _unused_dupfd;
595 union node *fname; 610 union node *fname;
596 char *expfname; 611 char *expfname;
597}; 612};
598 613
599struct ndup { 614struct ndup {
600 smallint type; 615 smallint type;
601 union node *next; /* must match nfile's layout */ 616 union node *next;
602 int fd; /* must match nfile's layout */ 617 int fd;
603 int dupfd; 618 int dupfd;
604 union node *vname; 619 union node *vname;
620 char *_unused_expfname;
605}; 621};
606 622
607struct nhere { 623struct nhere {
@@ -904,8 +920,11 @@ shcmd(union node *cmd, FILE *fp)
904 case NTO: s = ">>"+1; dftfd = 1; break; 920 case NTO: s = ">>"+1; dftfd = 1; break;
905 case NCLOBBER: s = ">|"; dftfd = 1; break; 921 case NCLOBBER: s = ">|"; dftfd = 1; break;
906 case NAPPEND: s = ">>"; dftfd = 1; break; 922 case NAPPEND: s = ">>"; dftfd = 1; break;
923#if ENABLE_ASH_BASH_COMPAT
924 case NTO2:
925#endif
907 case NTOFD: s = ">&"; dftfd = 1; break; 926 case NTOFD: s = ">&"; dftfd = 1; break;
908 case NFROM: s = "<"; break; 927 case NFROM: s = "<"; break;
909 case NFROMFD: s = "<&"; break; 928 case NFROMFD: s = "<&"; break;
910 case NFROMTO: s = "<>"; break; 929 case NFROMTO: s = "<>"; break;
911 default: s = "*error*"; break; 930 default: s = "*error*"; break;
@@ -4408,6 +4427,9 @@ cmdtxt(union node *n)
4408 case NAPPEND: 4427 case NAPPEND:
4409 p = ">>"; 4428 p = ">>";
4410 goto redir; 4429 goto redir;
4430#if ENABLE_ASH_BASH_COMPAT
4431 case NTO2:
4432#endif
4411 case NTOFD: 4433 case NTOFD:
4412 p = ">&"; 4434 p = ">&";
4413 goto redir; 4435 goto redir;
@@ -4797,6 +4819,9 @@ openredirect(union node *redir)
4797 goto ecreate; 4819 goto ecreate;
4798 break; 4820 break;
4799 case NTO: 4821 case NTO:
4822#if ENABLE_ASH_BASH_COMPAT
4823 case NTO2:
4824#endif
4800 /* Take care of noclobber mode. */ 4825 /* Take care of noclobber mode. */
4801 if (Cflag) { 4826 if (Cflag) {
4802 fname = redir->nfile.expfname; 4827 fname = redir->nfile.expfname;
@@ -4959,6 +4984,10 @@ redirect(union node *redir, int flags)
4959 union node *tmp = redir; 4984 union node *tmp = redir;
4960 do { 4985 do {
4961 sv_pos++; 4986 sv_pos++;
4987#if ENABLE_ASH_BASH_COMPAT
4988 if (redir->nfile.type == NTO2)
4989 sv_pos++;
4990#endif
4962 tmp = tmp->nfile.next; 4991 tmp = tmp->nfile.next;
4963 } while (tmp); 4992 } while (tmp);
4964 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0])); 4993 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
@@ -4997,6 +5026,9 @@ redirect(union node *redir, int flags)
4997 continue; 5026 continue;
4998 } 5027 }
4999 } 5028 }
5029#if ENABLE_ASH_BASH_COMPAT
5030 redirect_more:
5031#endif
5000 if (need_to_remember(sv, fd)) { 5032 if (need_to_remember(sv, fd)) {
5001 /* Copy old descriptor */ 5033 /* Copy old descriptor */
5002 i = fcntl(fd, F_DUPFD, 10); 5034 i = fcntl(fd, F_DUPFD, 10);
@@ -5039,8 +5071,19 @@ redirect(union node *redir, int flags)
5039 } 5071 }
5040 } else if (fd != newfd) { /* move newfd to fd */ 5072 } else if (fd != newfd) { /* move newfd to fd */
5041 copyfd(newfd, fd | COPYFD_EXACT); 5073 copyfd(newfd, fd | COPYFD_EXACT);
5042 close(newfd); 5074#if ENABLE_ASH_BASH_COMPAT
5075 if (!(redir->nfile.type == NTO2 && fd == 2))
5076#endif
5077 close(newfd);
5078 }
5079#if ENABLE_ASH_BASH_COMPAT
5080 if (redir->nfile.type == NTO2 && fd == 1) {
5081 /* We already redirected it to fd 1, now copy it to 2 */
5082 newfd = 1;
5083 fd = 2;
5084 goto redirect_more;
5043 } 5085 }
5086#endif
5044 } while ((redir = redir->nfile.next) != NULL); 5087 } while ((redir = redir->nfile.next) != NULL);
5045 5088
5046 INT_ON; 5089 INT_ON;
@@ -7641,6 +7684,9 @@ calcsize(union node *n)
7641 calcsize(n->narg.next); 7684 calcsize(n->narg.next);
7642 break; 7685 break;
7643 case NTO: 7686 case NTO:
7687#if ENABLE_ASH_BASH_COMPAT
7688 case NTO2:
7689#endif
7644 case NCLOBBER: 7690 case NCLOBBER:
7645 case NFROM: 7691 case NFROM:
7646 case NFROMTO: 7692 case NFROMTO:
@@ -7754,6 +7800,9 @@ copynode(union node *n)
7754 new->narg.next = copynode(n->narg.next); 7800 new->narg.next = copynode(n->narg.next);
7755 break; 7801 break;
7756 case NTO: 7802 case NTO:
7803#if ENABLE_ASH_BASH_COMPAT
7804 case NTO2:
7805#endif
7757 case NCLOBBER: 7806 case NCLOBBER:
7758 case NFROM: 7807 case NFROM:
7759 case NFROMTO: 7808 case NFROMTO:
@@ -8175,17 +8224,33 @@ expredir(union node *n)
8175 case NFROMTO: 8224 case NFROMTO:
8176 case NFROM: 8225 case NFROM:
8177 case NTO: 8226 case NTO:
8227#if ENABLE_ASH_BASH_COMPAT
8228 case NTO2:
8229#endif
8178 case NCLOBBER: 8230 case NCLOBBER:
8179 case NAPPEND: 8231 case NAPPEND:
8180 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 8232 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
8233#if ENABLE_ASH_BASH_COMPAT
8234 store_expfname:
8235#endif
8181 redir->nfile.expfname = fn.list->text; 8236 redir->nfile.expfname = fn.list->text;
8182 break; 8237 break;
8183 case NFROMFD: 8238 case NFROMFD:
8184 case NTOFD: 8239 case NTOFD: /* >& */
8185 if (redir->ndup.vname) { 8240 if (redir->ndup.vname) {
8186 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 8241 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
8187 if (fn.list == NULL) 8242 if (fn.list == NULL)
8188 ash_msg_and_raise_error("redir error"); 8243 ash_msg_and_raise_error("redir error");
8244#if ENABLE_ASH_BASH_COMPAT
8245//FIXME: we used expandarg with different args!
8246 if (!isdigit_str9(fn.list->text)) {
8247 /* >&file, not >&fd */
8248 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8249 ash_msg_and_raise_error("redir error");
8250 redir->type = NTO2;
8251 goto store_expfname;
8252 }
8253#endif
8189 fixredir(redir, fn.list->text, 1); 8254 fixredir(redir, fn.list->text, 1);
8190 } 8255 }
8191 break; 8256 break;
@@ -10126,7 +10191,7 @@ fixredir(union node *n, const char *text, int err)
10126 n->ndup.dupfd = -1; 10191 n->ndup.dupfd = -1;
10127 else { 10192 else {
10128 if (err) 10193 if (err)
10129 raise_error_syntax("Bad fd number"); 10194 raise_error_syntax("bad fd number");
10130 n->ndup.vname = makename(); 10195 n->ndup.vname = makename();
10131 } 10196 }
10132} 10197}
@@ -10169,7 +10234,7 @@ parsefname(void)
10169 n->type = NXHERE; 10234 n->type = NXHERE;
10170 TRACE(("Here document %d\n", n->type)); 10235 TRACE(("Here document %d\n", n->type));
10171 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 10236 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10172 raise_error_syntax("Illegal eof marker for << redirection"); 10237 raise_error_syntax("illegal eof marker for << redirection");
10173 rmescapes(wordtext); 10238 rmescapes(wordtext);
10174 here->eofmark = wordtext; 10239 here->eofmark = wordtext;
10175 here->next = NULL; 10240 here->next = NULL;
@@ -10261,7 +10326,7 @@ simplecmd(void)
10261 if (!goodname(name) 10326 if (!goodname(name)
10262 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd)) 10327 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10263 ) { 10328 ) {
10264 raise_error_syntax("Bad function name"); 10329 raise_error_syntax("bad function name");
10265 } 10330 }
10266 n->type = NDEFUN; 10331 n->type = NDEFUN;
10267 checkkwd = CHKNL | CHKKWD | CHKALIAS; 10332 checkkwd = CHKNL | CHKKWD | CHKALIAS;
@@ -10346,7 +10411,7 @@ parse_command(void)
10346 } 10411 }
10347 case TFOR: 10412 case TFOR:
10348 if (readtoken() != TWORD || quoteflag || !goodname(wordtext)) 10413 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
10349 raise_error_syntax("Bad for loop variable"); 10414 raise_error_syntax("bad for loop variable");
10350 n1 = stzalloc(sizeof(struct nfor)); 10415 n1 = stzalloc(sizeof(struct nfor));
10351 n1->type = NFOR; 10416 n1->type = NFOR;
10352 n1->nfor.var = wordtext; 10417 n1->nfor.var = wordtext;
@@ -10748,25 +10813,21 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10748 endword: 10813 endword:
10749#if ENABLE_ASH_MATH_SUPPORT 10814#if ENABLE_ASH_MATH_SUPPORT
10750 if (syntax == ARISYNTAX) 10815 if (syntax == ARISYNTAX)
10751 raise_error_syntax("Missing '))'"); 10816 raise_error_syntax("missing '))'");
10752#endif 10817#endif
10753 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL) 10818 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
10754 raise_error_syntax("Unterminated quoted string"); 10819 raise_error_syntax("unterminated quoted string");
10755 if (varnest != 0) { 10820 if (varnest != 0) {
10756 startlinno = plinno; 10821 startlinno = plinno;
10757 /* { */ 10822 /* { */
10758 raise_error_syntax("Missing '}'"); 10823 raise_error_syntax("missing '}'");
10759 } 10824 }
10760 USTPUTC('\0', out); 10825 USTPUTC('\0', out);
10761 len = out - (char *)stackblock(); 10826 len = out - (char *)stackblock();
10762 out = stackblock(); 10827 out = stackblock();
10763 if (eofmark == NULL) { 10828 if (eofmark == NULL) {
10764 if ((c == '>' || c == '<') && quotef == 0) { 10829 if ((c == '>' || c == '<') && quotef == 0) {
10765 int maxlen = 9 + 1; /* max 9 digit fd#: 999999999 */ 10830 if (isdigit_str9(out)) {
10766 char *np = out;
10767 while (--maxlen && isdigit(*np))
10768 np++;
10769 if (*np == '\0') {
10770 PARSEREDIR(); /* passed as params: out, c */ 10831 PARSEREDIR(); /* passed as params: out, c */
10771 lasttoken = TREDIR; 10832 lasttoken = TREDIR;
10772 return lasttoken; 10833 return lasttoken;
@@ -10841,6 +10902,7 @@ parseredir: {
10841 np->type = NCLOBBER; 10902 np->type = NCLOBBER;
10842 else if (c == '&') 10903 else if (c == '&')
10843 np->type = NTOFD; 10904 np->type = NTOFD;
10905 /* it also can be NTO2 (>&file), but we can't figure it out yet */
10844 else { 10906 else {
10845 np->type = NTO; 10907 np->type = NTO;
10846 pungetc(); 10908 pungetc();
@@ -10954,8 +11016,10 @@ parsesub: {
10954 } else if (is_special(c)) { 11016 } else if (is_special(c)) {
10955 USTPUTC(c, out); 11017 USTPUTC(c, out);
10956 c = pgetc(); 11018 c = pgetc();
10957 } else 11019 } else {
10958 badsub: raise_error_syntax("Bad substitution"); 11020 badsub:
11021 raise_error_syntax("bad substitution");
11022 }
10959 11023
10960 STPUTC('=', out); 11024 STPUTC('=', out);
10961 flags = 0; 11025 flags = 0;