diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-07-24 19:44:41 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-07-24 19:44:41 +0000 |
commit | 6fbb43bc3c14fc30030cae77db51c322bece30ab (patch) | |
tree | 7a2263457ac46946263439d08ee0307f8eadb586 | |
parent | 6514c5e35c31624d5e92400a7ce261c9e93774fe (diff) | |
download | busybox-w32-6fbb43bc3c14fc30030cae77db51c322bece30ab.tar.gz busybox-w32-6fbb43bc3c14fc30030cae77db51c322bece30ab.tar.bz2 busybox-w32-6fbb43bc3c14fc30030cae77db51c322bece30ab.zip |
ash: teach ash about 123>file. It could take only 0..9 before
function old new delta
redirect 1052 1139 +87
need_to_remember - 36 +36
popredir 132 148 +16
fixredir 86 101 +15
readtoken1 3130 3143 +13
evalvar 1374 1376 +2
popstring 140 134 -6
cmdtxt 592 561 -31
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 5/2 up/down: 169/-37) Total: 132 bytes
-rw-r--r-- | shell/ash.c | 142 |
1 files changed, 97 insertions, 45 deletions
diff --git a/shell/ash.c b/shell/ash.c index 6de71f6d7..22575ffbc 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -62,6 +62,10 @@ | |||
62 | #include <termios.h> | 62 | #include <termios.h> |
63 | #endif | 63 | #endif |
64 | 64 | ||
65 | #ifndef PIPE_BUF | ||
66 | #define PIPE_BUF 4096 /* amount of buffering in a pipe */ | ||
67 | #endif | ||
68 | |||
65 | #if defined(__uClinux__) | 69 | #if defined(__uClinux__) |
66 | #error "Do not even bother, ash will not run on uClinux" | 70 | #error "Do not even bother, ash will not run on uClinux" |
67 | #endif | 71 | #endif |
@@ -4285,7 +4289,6 @@ cmdtxt(union node *n) | |||
4285 | union node *np; | 4289 | union node *np; |
4286 | struct nodelist *lp; | 4290 | struct nodelist *lp; |
4287 | const char *p; | 4291 | const char *p; |
4288 | char s[2]; | ||
4289 | 4292 | ||
4290 | if (!n) | 4293 | if (!n) |
4291 | return; | 4294 | return; |
@@ -4417,14 +4420,11 @@ cmdtxt(union node *n) | |||
4417 | case NFROMTO: | 4420 | case NFROMTO: |
4418 | p = "<>"; | 4421 | p = "<>"; |
4419 | redir: | 4422 | redir: |
4420 | s[0] = n->nfile.fd + '0'; | 4423 | cmdputs(utoa(n->nfile.fd)); |
4421 | s[1] = '\0'; | ||
4422 | cmdputs(s); | ||
4423 | cmdputs(p); | 4424 | cmdputs(p); |
4424 | if (n->type == NTOFD || n->type == NFROMFD) { | 4425 | if (n->type == NTOFD || n->type == NFROMFD) { |
4425 | s[0] = n->ndup.dupfd + '0'; | 4426 | cmdputs(utoa(n->ndup.dupfd)); |
4426 | p = s; | 4427 | break; |
4427 | goto dotail2; | ||
4428 | } | 4428 | } |
4429 | n = n->nfile.fname; | 4429 | n = n->nfile.fname; |
4430 | goto donode; | 4430 | goto donode; |
@@ -4675,11 +4675,6 @@ stoppedjobs(void) | |||
4675 | 4675 | ||
4676 | #define EMPTY -2 /* marks an unused slot in redirtab */ | 4676 | #define EMPTY -2 /* marks an unused slot in redirtab */ |
4677 | #define CLOSED -3 /* marks a slot of previously-closed fd */ | 4677 | #define CLOSED -3 /* marks a slot of previously-closed fd */ |
4678 | #ifndef PIPE_BUF | ||
4679 | # define PIPESIZE 4096 /* amount of buffering in a pipe */ | ||
4680 | #else | ||
4681 | # define PIPESIZE PIPE_BUF | ||
4682 | #endif | ||
4683 | 4678 | ||
4684 | /* | 4679 | /* |
4685 | * Open a file in noclobber mode. | 4680 | * Open a file in noclobber mode. |
@@ -4756,7 +4751,7 @@ openhere(union node *redir) | |||
4756 | ash_msg_and_raise_error("pipe call failed"); | 4751 | ash_msg_and_raise_error("pipe call failed"); |
4757 | if (redir->type == NHERE) { | 4752 | if (redir->type == NHERE) { |
4758 | len = strlen(redir->nhere.doc->narg.text); | 4753 | len = strlen(redir->nhere.doc->narg.text); |
4759 | if (len <= PIPESIZE) { | 4754 | if (len <= PIPE_BUF) { |
4760 | full_write(pip[1], redir->nhere.doc->narg.text, len); | 4755 | full_write(pip[1], redir->nhere.doc->narg.text, len); |
4761 | goto out; | 4756 | goto out; |
4762 | } | 4757 | } |
@@ -4860,19 +4855,40 @@ copyfd(int from, int to) | |||
4860 | if (newfd < 0) { | 4855 | if (newfd < 0) { |
4861 | if (errno == EMFILE) | 4856 | if (errno == EMFILE) |
4862 | return EMPTY; | 4857 | return EMPTY; |
4858 | /* Happens when source fd is not open: try "echo >&99" */ | ||
4863 | ash_msg_and_raise_error("%d: %m", from); | 4859 | ash_msg_and_raise_error("%d: %m", from); |
4864 | } | 4860 | } |
4865 | return newfd; | 4861 | return newfd; |
4866 | } | 4862 | } |
4867 | 4863 | ||
4868 | /* Struct def and variable are moved down to the first usage site */ | 4864 | /* Struct def and variable are moved down to the first usage site */ |
4865 | struct two_fd_t { | ||
4866 | int orig, copy; | ||
4867 | }; | ||
4869 | struct redirtab { | 4868 | struct redirtab { |
4870 | struct redirtab *next; | 4869 | struct redirtab *next; |
4871 | int renamed[10]; | ||
4872 | int nullredirs; | 4870 | int nullredirs; |
4871 | int pair_count; | ||
4872 | struct two_fd_t two_fd[0]; | ||
4873 | }; | 4873 | }; |
4874 | #define redirlist (G_var.redirlist) | 4874 | #define redirlist (G_var.redirlist) |
4875 | 4875 | ||
4876 | static int need_to_remember(struct redirtab *rp, int fd) | ||
4877 | { | ||
4878 | int i; | ||
4879 | |||
4880 | if (!rp) /* remebering was not requested */ | ||
4881 | return 0; | ||
4882 | |||
4883 | for (i = 0; i < rp->pair_count; i++) { | ||
4884 | if (rp->two_fd[i].orig == fd) { | ||
4885 | /* already remembered */ | ||
4886 | return 0; | ||
4887 | } | ||
4888 | } | ||
4889 | return 1; | ||
4890 | } | ||
4891 | |||
4876 | /* | 4892 | /* |
4877 | * Process a list of redirection commands. If the REDIR_PUSH flag is set, | 4893 | * Process a list of redirection commands. If the REDIR_PUSH flag is set, |
4878 | * old file descriptors are stashed away so that the redirection can be | 4894 | * old file descriptors are stashed away so that the redirection can be |
@@ -4887,24 +4903,36 @@ static void | |||
4887 | redirect(union node *redir, int flags) | 4903 | redirect(union node *redir, int flags) |
4888 | { | 4904 | { |
4889 | struct redirtab *sv; | 4905 | struct redirtab *sv; |
4906 | int sv_pos; | ||
4890 | int i; | 4907 | int i; |
4891 | int fd; | 4908 | int fd; |
4892 | int newfd; | 4909 | int newfd; |
4910 | int copied_fd2 = -1; | ||
4893 | 4911 | ||
4894 | g_nullredirs++; | 4912 | g_nullredirs++; |
4895 | if (!redir) { | 4913 | if (!redir) { |
4896 | return; | 4914 | return; |
4897 | } | 4915 | } |
4916 | |||
4898 | sv = NULL; | 4917 | sv = NULL; |
4918 | sv_pos = 0; | ||
4899 | INT_OFF; | 4919 | INT_OFF; |
4900 | if (flags & REDIR_PUSH) { | 4920 | if (flags & REDIR_PUSH) { |
4901 | sv = ckmalloc(sizeof(*sv)); | 4921 | union node *tmp = redir; |
4922 | do { | ||
4923 | sv_pos++; | ||
4924 | tmp = tmp->nfile.next; | ||
4925 | } while (tmp); | ||
4926 | sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0])); | ||
4902 | sv->next = redirlist; | 4927 | sv->next = redirlist; |
4928 | sv->pair_count = sv_pos; | ||
4903 | redirlist = sv; | 4929 | redirlist = sv; |
4904 | sv->nullredirs = g_nullredirs - 1; | 4930 | sv->nullredirs = g_nullredirs - 1; |
4905 | g_nullredirs = 0; | 4931 | g_nullredirs = 0; |
4906 | for (i = 0; i < 10; i++) | 4932 | while (sv_pos > 0) { |
4907 | sv->renamed[i] = EMPTY; | 4933 | sv_pos--; |
4934 | sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY; | ||
4935 | } | ||
4908 | } | 4936 | } |
4909 | 4937 | ||
4910 | do { | 4938 | do { |
@@ -4918,19 +4946,25 @@ redirect(union node *redir, int flags) | |||
4918 | if (fd == newfd) { | 4946 | if (fd == newfd) { |
4919 | /* Descriptor wasn't open before redirect. | 4947 | /* Descriptor wasn't open before redirect. |
4920 | * Mark it for close in the future */ | 4948 | * Mark it for close in the future */ |
4921 | if (sv && sv->renamed[fd] == EMPTY) | 4949 | if (need_to_remember(sv, fd)) { |
4922 | sv->renamed[fd] = CLOSED; | 4950 | if (fd == 2) |
4951 | copied_fd2 = CLOSED; /// do we need this? | ||
4952 | sv->two_fd[sv_pos].orig = fd; | ||
4953 | sv->two_fd[sv_pos].copy = CLOSED; | ||
4954 | sv_pos++; | ||
4955 | } | ||
4923 | continue; | 4956 | continue; |
4924 | } | 4957 | } |
4925 | } | 4958 | } |
4926 | if (sv && sv->renamed[fd] == EMPTY) { | 4959 | if (need_to_remember(sv, fd)) { |
4927 | /* Copy old descriptor */ | 4960 | /* Copy old descriptor */ |
4928 | i = fcntl(fd, F_DUPFD, 10); | 4961 | i = fcntl(fd, F_DUPFD, 10); |
4929 | if (i == -1) { | 4962 | if (i == -1) { |
4930 | i = errno; | 4963 | i = errno; |
4931 | if (i != EBADF) { | 4964 | if (i != EBADF) { |
4932 | /* Strange error (e.g. "too many files" EMFILE?) */ | 4965 | /* Strange error (e.g. "too many files" EMFILE?) */ |
4933 | /*if (newfd >= 0)*/ close(newfd); | 4966 | if (newfd >= 0) |
4967 | close(newfd); | ||
4934 | errno = i; | 4968 | errno = i; |
4935 | ash_msg_and_raise_error("%d: %m", fd); | 4969 | ash_msg_and_raise_error("%d: %m", fd); |
4936 | /* NOTREACHED */ | 4970 | /* NOTREACHED */ |
@@ -4938,10 +4972,15 @@ redirect(union node *redir, int flags) | |||
4938 | /* EBADF: it is not open - ok */ | 4972 | /* EBADF: it is not open - ok */ |
4939 | } else { | 4973 | } else { |
4940 | /* fd is open, save its copy */ | 4974 | /* fd is open, save its copy */ |
4941 | //TODO: CLOEXEC the copy? currently these extra "saved" fds are closed | 4975 | /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds |
4942 | // in popredir() in the child, preventing them from leaking into child. | 4976 | * are closed in popredir() in the child, preventing them from leaking |
4943 | // (popredir() also cleans up the mess in case of failures) | 4977 | * into child. (popredir() also cleans up the mess in case of failures) |
4944 | sv->renamed[fd] = i; | 4978 | */ |
4979 | if (fd == 2) | ||
4980 | copied_fd2 = i; | ||
4981 | sv->two_fd[sv_pos].orig = fd; | ||
4982 | sv->two_fd[sv_pos].copy = i; | ||
4983 | sv_pos++; | ||
4945 | close(fd); | 4984 | close(fd); |
4946 | } | 4985 | } |
4947 | } else { | 4986 | } else { |
@@ -4960,8 +4999,8 @@ redirect(union node *redir, int flags) | |||
4960 | } while ((redir = redir->nfile.next) != NULL); | 4999 | } while ((redir = redir->nfile.next) != NULL); |
4961 | 5000 | ||
4962 | INT_ON; | 5001 | INT_ON; |
4963 | if ((flags & REDIR_SAVEFD2) && sv && sv->renamed[2] >= 0) | 5002 | if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0) |
4964 | preverrout_fd = sv->renamed[2]; | 5003 | preverrout_fd = copied_fd2; |
4965 | } | 5004 | } |
4966 | 5005 | ||
4967 | /* | 5006 | /* |
@@ -4977,18 +5016,19 @@ popredir(int drop) | |||
4977 | return; | 5016 | return; |
4978 | INT_OFF; | 5017 | INT_OFF; |
4979 | rp = redirlist; | 5018 | rp = redirlist; |
4980 | for (i = 0; i < 10; i++) { | 5019 | for (i = 0; i < rp->pair_count; i++) { |
4981 | if (rp->renamed[i] == CLOSED) { | 5020 | int fd = rp->two_fd[i].orig; |
5021 | if (rp->two_fd[i].copy == CLOSED) { | ||
4982 | if (!drop) | 5022 | if (!drop) |
4983 | close(i); | 5023 | close(fd); |
4984 | continue; | 5024 | continue; |
4985 | } | 5025 | } |
4986 | if (rp->renamed[i] != EMPTY) { | 5026 | if (rp->two_fd[i].copy != EMPTY) { |
4987 | if (!drop) { | 5027 | if (!drop) { |
4988 | close(i); | 5028 | close(fd); |
4989 | copyfd(rp->renamed[i], i); | 5029 | copyfd(rp->two_fd[i].copy, fd); |
4990 | } | 5030 | } |
4991 | close(rp->renamed[i]); | 5031 | close(rp->two_fd[i].copy); |
4992 | } | 5032 | } |
4993 | } | 5033 | } |
4994 | redirlist = rp->next; | 5034 | redirlist = rp->next; |
@@ -10003,12 +10043,15 @@ makename(void) | |||
10003 | static void | 10043 | static void |
10004 | fixredir(union node *n, const char *text, int err) | 10044 | fixredir(union node *n, const char *text, int err) |
10005 | { | 10045 | { |
10046 | int fd; | ||
10047 | |||
10006 | TRACE(("Fix redir %s %d\n", text, err)); | 10048 | TRACE(("Fix redir %s %d\n", text, err)); |
10007 | if (!err) | 10049 | if (!err) |
10008 | n->ndup.vname = NULL; | 10050 | n->ndup.vname = NULL; |
10009 | 10051 | ||
10010 | if (isdigit(text[0]) && text[1] == '\0') | 10052 | fd = bb_strtou(text, NULL, 10); |
10011 | n->ndup.dupfd = text[0] - '0'; | 10053 | if (!errno && fd >= 0) |
10054 | n->ndup.dupfd = fd; | ||
10012 | else if (LONE_DASH(text)) | 10055 | else if (LONE_DASH(text)) |
10013 | n->ndup.dupfd = -1; | 10056 | n->ndup.dupfd = -1; |
10014 | else { | 10057 | else { |
@@ -10630,7 +10673,7 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) | |||
10630 | 10673 | ||
10631 | } | 10674 | } |
10632 | c = pgetc_macro(); | 10675 | c = pgetc_macro(); |
10633 | } /* for(;;) */ | 10676 | } /* for (;;) */ |
10634 | } | 10677 | } |
10635 | endword: | 10678 | endword: |
10636 | #if ENABLE_ASH_MATH_SUPPORT | 10679 | #if ENABLE_ASH_MATH_SUPPORT |
@@ -10650,12 +10693,20 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs) | |||
10650 | if (eofmark == NULL) { | 10693 | if (eofmark == NULL) { |
10651 | if ((c == '>' || c == '<') | 10694 | if ((c == '>' || c == '<') |
10652 | && quotef == 0 | 10695 | && quotef == 0 |
10653 | && len <= 2 // THIS LIMITS fd to 1 char: N>file, but no NN>file! | 10696 | // && len <= 2 // THIS LIMITS fd to 1 char: N>file, but no NN>file! |
10654 | && (*out == '\0' || isdigit(*out)) | 10697 | // && (*out == '\0' || isdigit(*out)) |
10655 | ) { | 10698 | ) { |
10656 | PARSEREDIR(); | 10699 | int maxlen = 9 + 1; /* max 9 digit fd#: 999999999 */ |
10657 | lasttoken = TREDIR; | 10700 | char *np = out; |
10658 | return lasttoken; | 10701 | while (--maxlen && isdigit(*np)) |
10702 | np++; | ||
10703 | if (*np == '\0') { | ||
10704 | PARSEREDIR(); /* passed as params: out, c */ | ||
10705 | lasttoken = TREDIR; | ||
10706 | return lasttoken; | ||
10707 | } | ||
10708 | /* else: non-number X seen, interpret it | ||
10709 | * as "NNNX>file" = "NNNX >file" */ | ||
10659 | } | 10710 | } |
10660 | pungetc(); | 10711 | pungetc(); |
10661 | } | 10712 | } |
@@ -10710,7 +10761,8 @@ checkend: { | |||
10710 | * first character of the redirection operator. | 10761 | * first character of the redirection operator. |
10711 | */ | 10762 | */ |
10712 | parseredir: { | 10763 | parseredir: { |
10713 | char fd = *out; | 10764 | /* out is already checked to be a valid number or "" */ |
10765 | int fd = (*out == '\0' ? -1 : atoi(out)); | ||
10714 | union node *np; | 10766 | union node *np; |
10715 | 10767 | ||
10716 | np = stzalloc(sizeof(struct nfile)); | 10768 | np = stzalloc(sizeof(struct nfile)); |
@@ -10762,8 +10814,8 @@ parseredir: { | |||
10762 | break; | 10814 | break; |
10763 | } | 10815 | } |
10764 | } | 10816 | } |
10765 | if (fd != '\0') | 10817 | if (fd >= 0) |
10766 | np->nfile.fd = fd - '0'; | 10818 | np->nfile.fd = fd; |
10767 | redirnode = np; | 10819 | redirnode = np; |
10768 | goto parseredir_return; | 10820 | goto parseredir_return; |
10769 | } | 10821 | } |