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
This commit is contained in:
Denis Vlasenko 2008-07-24 19:44:41 +00:00
parent 6514c5e35c
commit 6fbb43bc3c

View File

@ -62,6 +62,10 @@
#include <termios.h> #include <termios.h>
#endif #endif
#ifndef PIPE_BUF
#define PIPE_BUF 4096 /* amount of buffering in a pipe */
#endif
#if defined(__uClinux__) #if defined(__uClinux__)
#error "Do not even bother, ash will not run on uClinux" #error "Do not even bother, ash will not run on uClinux"
#endif #endif
@ -4285,7 +4289,6 @@ cmdtxt(union node *n)
union node *np; union node *np;
struct nodelist *lp; struct nodelist *lp;
const char *p; const char *p;
char s[2];
if (!n) if (!n)
return; return;
@ -4417,14 +4420,11 @@ cmdtxt(union node *n)
case NFROMTO: case NFROMTO:
p = "<>"; p = "<>";
redir: redir:
s[0] = n->nfile.fd + '0'; cmdputs(utoa(n->nfile.fd));
s[1] = '\0';
cmdputs(s);
cmdputs(p); cmdputs(p);
if (n->type == NTOFD || n->type == NFROMFD) { if (n->type == NTOFD || n->type == NFROMFD) {
s[0] = n->ndup.dupfd + '0'; cmdputs(utoa(n->ndup.dupfd));
p = s; break;
goto dotail2;
} }
n = n->nfile.fname; n = n->nfile.fname;
goto donode; goto donode;
@ -4675,11 +4675,6 @@ stoppedjobs(void)
#define EMPTY -2 /* marks an unused slot in redirtab */ #define EMPTY -2 /* marks an unused slot in redirtab */
#define CLOSED -3 /* marks a slot of previously-closed fd */ #define CLOSED -3 /* marks a slot of previously-closed fd */
#ifndef PIPE_BUF
# define PIPESIZE 4096 /* amount of buffering in a pipe */
#else
# define PIPESIZE PIPE_BUF
#endif
/* /*
* Open a file in noclobber mode. * Open a file in noclobber mode.
@ -4756,7 +4751,7 @@ openhere(union node *redir)
ash_msg_and_raise_error("pipe call failed"); ash_msg_and_raise_error("pipe call failed");
if (redir->type == NHERE) { if (redir->type == NHERE) {
len = strlen(redir->nhere.doc->narg.text); len = strlen(redir->nhere.doc->narg.text);
if (len <= PIPESIZE) { if (len <= PIPE_BUF) {
full_write(pip[1], redir->nhere.doc->narg.text, len); full_write(pip[1], redir->nhere.doc->narg.text, len);
goto out; goto out;
} }
@ -4860,19 +4855,40 @@ copyfd(int from, int to)
if (newfd < 0) { if (newfd < 0) {
if (errno == EMFILE) if (errno == EMFILE)
return EMPTY; return EMPTY;
/* Happens when source fd is not open: try "echo >&99" */
ash_msg_and_raise_error("%d: %m", from); ash_msg_and_raise_error("%d: %m", from);
} }
return newfd; return newfd;
} }
/* Struct def and variable are moved down to the first usage site */ /* Struct def and variable are moved down to the first usage site */
struct two_fd_t {
int orig, copy;
};
struct redirtab { struct redirtab {
struct redirtab *next; struct redirtab *next;
int renamed[10];
int nullredirs; int nullredirs;
int pair_count;
struct two_fd_t two_fd[0];
}; };
#define redirlist (G_var.redirlist) #define redirlist (G_var.redirlist)
static int need_to_remember(struct redirtab *rp, int fd)
{
int i;
if (!rp) /* remebering was not requested */
return 0;
for (i = 0; i < rp->pair_count; i++) {
if (rp->two_fd[i].orig == fd) {
/* already remembered */
return 0;
}
}
return 1;
}
/* /*
* Process a list of redirection commands. If the REDIR_PUSH flag is set, * Process a list of redirection commands. If the REDIR_PUSH flag is set,
* old file descriptors are stashed away so that the redirection can be * old file descriptors are stashed away so that the redirection can be
@ -4887,24 +4903,36 @@ static void
redirect(union node *redir, int flags) redirect(union node *redir, int flags)
{ {
struct redirtab *sv; struct redirtab *sv;
int sv_pos;
int i; int i;
int fd; int fd;
int newfd; int newfd;
int copied_fd2 = -1;
g_nullredirs++; g_nullredirs++;
if (!redir) { if (!redir) {
return; return;
} }
sv = NULL; sv = NULL;
sv_pos = 0;
INT_OFF; INT_OFF;
if (flags & REDIR_PUSH) { if (flags & REDIR_PUSH) {
sv = ckmalloc(sizeof(*sv)); union node *tmp = redir;
do {
sv_pos++;
tmp = tmp->nfile.next;
} while (tmp);
sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
sv->next = redirlist; sv->next = redirlist;
sv->pair_count = sv_pos;
redirlist = sv; redirlist = sv;
sv->nullredirs = g_nullredirs - 1; sv->nullredirs = g_nullredirs - 1;
g_nullredirs = 0; g_nullredirs = 0;
for (i = 0; i < 10; i++) while (sv_pos > 0) {
sv->renamed[i] = EMPTY; sv_pos--;
sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
}
} }
do { do {
@ -4918,19 +4946,25 @@ redirect(union node *redir, int flags)
if (fd == newfd) { if (fd == newfd) {
/* Descriptor wasn't open before redirect. /* Descriptor wasn't open before redirect.
* Mark it for close in the future */ * Mark it for close in the future */
if (sv && sv->renamed[fd] == EMPTY) if (need_to_remember(sv, fd)) {
sv->renamed[fd] = CLOSED; if (fd == 2)
copied_fd2 = CLOSED; /// do we need this?
sv->two_fd[sv_pos].orig = fd;
sv->two_fd[sv_pos].copy = CLOSED;
sv_pos++;
}
continue; continue;
} }
} }
if (sv && sv->renamed[fd] == EMPTY) { if (need_to_remember(sv, fd)) {
/* Copy old descriptor */ /* Copy old descriptor */
i = fcntl(fd, F_DUPFD, 10); i = fcntl(fd, F_DUPFD, 10);
if (i == -1) { if (i == -1) {
i = errno; i = errno;
if (i != EBADF) { if (i != EBADF) {
/* Strange error (e.g. "too many files" EMFILE?) */ /* Strange error (e.g. "too many files" EMFILE?) */
/*if (newfd >= 0)*/ close(newfd); if (newfd >= 0)
close(newfd);
errno = i; errno = i;
ash_msg_and_raise_error("%d: %m", fd); ash_msg_and_raise_error("%d: %m", fd);
/* NOTREACHED */ /* NOTREACHED */
@ -4938,10 +4972,15 @@ redirect(union node *redir, int flags)
/* EBADF: it is not open - ok */ /* EBADF: it is not open - ok */
} else { } else {
/* fd is open, save its copy */ /* fd is open, save its copy */
//TODO: CLOEXEC the copy? currently these extra "saved" fds are closed /* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
// in popredir() in the child, preventing them from leaking into child. * are closed in popredir() in the child, preventing them from leaking
// (popredir() also cleans up the mess in case of failures) * into child. (popredir() also cleans up the mess in case of failures)
sv->renamed[fd] = i; */
if (fd == 2)
copied_fd2 = i;
sv->two_fd[sv_pos].orig = fd;
sv->two_fd[sv_pos].copy = i;
sv_pos++;
close(fd); close(fd);
} }
} else { } else {
@ -4960,8 +4999,8 @@ redirect(union node *redir, int flags)
} while ((redir = redir->nfile.next) != NULL); } while ((redir = redir->nfile.next) != NULL);
INT_ON; INT_ON;
if ((flags & REDIR_SAVEFD2) && sv && sv->renamed[2] >= 0) if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
preverrout_fd = sv->renamed[2]; preverrout_fd = copied_fd2;
} }
/* /*
@ -4977,18 +5016,19 @@ popredir(int drop)
return; return;
INT_OFF; INT_OFF;
rp = redirlist; rp = redirlist;
for (i = 0; i < 10; i++) { for (i = 0; i < rp->pair_count; i++) {
if (rp->renamed[i] == CLOSED) { int fd = rp->two_fd[i].orig;
if (rp->two_fd[i].copy == CLOSED) {
if (!drop) if (!drop)
close(i); close(fd);
continue; continue;
} }
if (rp->renamed[i] != EMPTY) { if (rp->two_fd[i].copy != EMPTY) {
if (!drop) { if (!drop) {
close(i); close(fd);
copyfd(rp->renamed[i], i); copyfd(rp->two_fd[i].copy, fd);
} }
close(rp->renamed[i]); close(rp->two_fd[i].copy);
} }
} }
redirlist = rp->next; redirlist = rp->next;
@ -10003,12 +10043,15 @@ makename(void)
static void static void
fixredir(union node *n, const char *text, int err) fixredir(union node *n, const char *text, int err)
{ {
int fd;
TRACE(("Fix redir %s %d\n", text, err)); TRACE(("Fix redir %s %d\n", text, err));
if (!err) if (!err)
n->ndup.vname = NULL; n->ndup.vname = NULL;
if (isdigit(text[0]) && text[1] == '\0') fd = bb_strtou(text, NULL, 10);
n->ndup.dupfd = text[0] - '0'; if (!errno && fd >= 0)
n->ndup.dupfd = fd;
else if (LONE_DASH(text)) else if (LONE_DASH(text))
n->ndup.dupfd = -1; n->ndup.dupfd = -1;
else { else {
@ -10630,7 +10673,7 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
} }
c = pgetc_macro(); c = pgetc_macro();
} /* for(;;) */ } /* for (;;) */
} }
endword: endword:
#if ENABLE_ASH_MATH_SUPPORT #if ENABLE_ASH_MATH_SUPPORT
@ -10650,12 +10693,20 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
if (eofmark == NULL) { if (eofmark == NULL) {
if ((c == '>' || c == '<') if ((c == '>' || c == '<')
&& quotef == 0 && quotef == 0
&& len <= 2 // THIS LIMITS fd to 1 char: N>file, but no NN>file! // && len <= 2 // THIS LIMITS fd to 1 char: N>file, but no NN>file!
&& (*out == '\0' || isdigit(*out)) // && (*out == '\0' || isdigit(*out))
) { ) {
PARSEREDIR(); int maxlen = 9 + 1; /* max 9 digit fd#: 999999999 */
lasttoken = TREDIR; char *np = out;
return lasttoken; while (--maxlen && isdigit(*np))
np++;
if (*np == '\0') {
PARSEREDIR(); /* passed as params: out, c */
lasttoken = TREDIR;
return lasttoken;
}
/* else: non-number X seen, interpret it
* as "NNNX>file" = "NNNX >file" */
} }
pungetc(); pungetc();
} }
@ -10710,7 +10761,8 @@ checkend: {
* first character of the redirection operator. * first character of the redirection operator.
*/ */
parseredir: { parseredir: {
char fd = *out; /* out is already checked to be a valid number or "" */
int fd = (*out == '\0' ? -1 : atoi(out));
union node *np; union node *np;
np = stzalloc(sizeof(struct nfile)); np = stzalloc(sizeof(struct nfile));
@ -10762,8 +10814,8 @@ parseredir: {
break; break;
} }
} }
if (fd != '\0') if (fd >= 0)
np->nfile.fd = fd - '0'; np->nfile.fd = fd;
redirnode = np; redirnode = np;
goto parseredir_return; goto parseredir_return;
} }