diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-05 18:39:31 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-05 18:39:31 +0000 |
commit | 559691a3bfcb66ccf1cb59060d62d042e0265c00 (patch) | |
tree | a876b9f84c307dd1e0e02a193bdd390c580884ae | |
parent | 93d0776a96919a94fca51fe2cfd9530d8c9dcbb9 (diff) | |
download | busybox-w32-559691a3bfcb66ccf1cb59060d62d042e0265c00.tar.gz busybox-w32-559691a3bfcb66ccf1cb59060d62d042e0265c00.tar.bz2 busybox-w32-559691a3bfcb66ccf1cb59060d62d042e0265c00.zip |
ash: implement ">&file" bashism. ~100 bytes.
-rw-r--r-- | shell/ash.c | 158 |
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 */ |
249 | static 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 | ||
530 | union node; | 540 | union 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 | */ | ||
591 | struct nfile { | 605 | struct 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 | ||
599 | struct ndup { | 614 | struct 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 | ||
607 | struct nhere { | 623 | struct 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; |