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:
parent
6514c5e35c
commit
6fbb43bc3c
142
shell/ash.c
142
shell/ash.c
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user