diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-11-22 08:16:57 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-11-22 08:16:57 +0000 |
commit | 7d75a96b15327050a294b1f54981781ce6e551e2 (patch) | |
tree | df8a1fcb74b6bd7869fe60af461c11f0684df043 /shell | |
parent | 705eaf8b403555741cf6313a76da8597ae54d324 (diff) | |
download | busybox-7d75a96b15327050a294b1f54981781ce6e551e2.tar.gz |
ash: fix bug where redirection of closed fd was leaving it open afterwards.
redirect 983 1024 +41
bb_echo 276 301 +25
popredir 118 132 +14
evalcommand 1163 1176 +13
bbunpack 358 366 +8
echocmd 13 5 -8
echo_main 13 5 -8
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/2 up/down: 101/-16) Total: 85 bytes
text data bss dec hex filename
774999 962 9236 785197 bfb2d busybox_old
775084 962 9236 785282 bfb82 busybox_unstripped
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 35 | ||||
-rw-r--r-- | shell/ash_test/ash-redir/redir.right | 1 | ||||
-rw-r--r-- | shell/ash_test/ash-redir/redir.tests | 6 |
3 files changed, 29 insertions, 13 deletions
diff --git a/shell/ash.c b/shell/ash.c index bb930f55f..4113ce8e2 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -4567,6 +4567,7 @@ stoppedjobs(void) */ #define EMPTY -2 /* marks an unused slot in redirtab */ +#define CLOSED -3 /* marks a slot of previously-closed fd */ #ifndef PIPE_BUF # define PIPESIZE 4096 /* amount of buffering in a pipe */ #else @@ -4791,7 +4792,7 @@ redirect(union node *redir, int flags) int i; int fd; int newfd; - int *p; + nullredirs++; if (!redir) { return; @@ -4799,15 +4800,13 @@ redirect(union node *redir, int flags) sv = NULL; INT_OFF; if (flags & REDIR_PUSH) { - struct redirtab *q; - q = ckmalloc(sizeof(struct redirtab)); - q->next = redirlist; - redirlist = q; - q->nullredirs = nullredirs - 1; + sv = ckmalloc(sizeof(*sv)); + sv->next = redirlist; + redirlist = sv; + sv->nullredirs = nullredirs - 1; for (i = 0; i < 10; i++) - q->renamed[i] = EMPTY; + sv->renamed[i] = EMPTY; nullredirs = 0; - sv = q; } n = redir; do { @@ -4817,9 +4816,14 @@ redirect(union node *redir, int flags) continue; /* redirect from/to same file descriptor */ newfd = openredirect(n); - if (fd == newfd) + if (fd == newfd) { + /* Descriptor wasn't open before redirect. + * Mark it for close in the future */ + if (sv && sv->renamed[fd] == EMPTY) + sv->renamed[fd] = CLOSED; continue; - if (sv && *(p = &sv->renamed[fd]) == EMPTY) { + } + if (sv && sv->renamed[fd] == EMPTY) { i = fcntl(fd, F_DUPFD, 10); if (i == -1) { @@ -4831,7 +4835,7 @@ redirect(union node *redir, int flags) /* NOTREACHED */ } } else { - *p = i; + sv->renamed[fd] = i; close(fd); } } else { @@ -4840,7 +4844,7 @@ redirect(union node *redir, int flags) dupredirect(n, newfd); } while ((n = n->nfile.next)); INT_ON; - if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0) + if ((flags & REDIR_SAVEFD2) && sv && sv->renamed[2] >= 0) preverrout_fd = sv->renamed[2]; } @@ -4858,6 +4862,11 @@ popredir(int drop) INT_OFF; rp = redirlist; for (i = 0; i < 10; i++) { + if (rp->renamed[i] == CLOSED) { + if (!drop) + close(i); + continue; + } if (rp->renamed[i] != EMPTY) { if (!drop) { close(i); @@ -10994,7 +11003,7 @@ exitcmd(int argc, char **argv) static int echocmd(int argc, char **argv) { - return bb_echo(argv); + return bb_echo(argc, argv); } #endif diff --git a/shell/ash_test/ash-redir/redir.right b/shell/ash_test/ash-redir/redir.right new file mode 100644 index 000000000..2a02d41ce --- /dev/null +++ b/shell/ash_test/ash-redir/redir.right @@ -0,0 +1 @@ +TEST diff --git a/shell/ash_test/ash-redir/redir.tests b/shell/ash_test/ash-redir/redir.tests new file mode 100644 index 000000000..7a1a66806 --- /dev/null +++ b/shell/ash_test/ash-redir/redir.tests @@ -0,0 +1,6 @@ +# test: closed fds should stay closed +exec 1>&- +echo TEST >TEST +echo JUNK # lost: stdout is closed +cat TEST >&2 +rm TEST |