aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-07-24 19:44:41 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-07-24 19:44:41 +0000
commit6fbb43bc3c14fc30030cae77db51c322bece30ab (patch)
tree7a2263457ac46946263439d08ee0307f8eadb586
parent6514c5e35c31624d5e92400a7ce261c9e93774fe (diff)
downloadbusybox-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.c142
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 */
4865struct two_fd_t {
4866 int orig, copy;
4867};
4869struct redirtab { 4868struct 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
4876static 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
4887redirect(union node *redir, int flags) 4903redirect(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)
10003static void 10043static void
10004fixredir(union node *n, const char *text, int err) 10044fixredir(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 */
10712parseredir: { 10763parseredir: {
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}