aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-07-24 19:46:38 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-07-24 19:46:38 +0000
commit5a867317bb1cbf36d396d9cdb552212607dcc2b1 (patch)
treee8c01f8c4f8242694db730eed60a3616e86f3a48
parent6fbb43bc3c14fc30030cae77db51c322bece30ab (diff)
downloadbusybox-w32-5a867317bb1cbf36d396d9cdb552212607dcc2b1.tar.gz
busybox-w32-5a867317bb1cbf36d396d9cdb552212607dcc2b1.tar.bz2
busybox-w32-5a867317bb1cbf36d396d9cdb552212607dcc2b1.zip
ash: fix a bug where redirection fds were not closed afterwards.
optimize close+fcntl(DUPFD) into dup2. add testsuites. function old new delta copyfd 47 68 +21 argstr 1311 1298 -13 popredir 148 131 -17 redirect 1139 1107 -32 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/3 up/down: 21/-62) Total: -41 bytes
-rw-r--r--shell/ash.c74
-rw-r--r--shell/ash_test/ash-redir/redir2.right1
-rwxr-xr-xshell/ash_test/ash-redir/redir2.tests5
-rw-r--r--shell/ash_test/ash-redir/redir3.right3
-rwxr-xr-xshell/ash_test/ash-redir/redir3.tests5
-rwxr-xr-xshell/ash_test/run-all4
6 files changed, 53 insertions, 39 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 22575ffbc..ec3bd0927 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -4846,12 +4846,21 @@ openredirect(union node *redir)
4846 * if the source file descriptor is closed, EMPTY if there are no unused 4846 * if the source file descriptor is closed, EMPTY if there are no unused
4847 * file descriptors left. 4847 * file descriptors left.
4848 */ 4848 */
4849/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
4850 * old code was doing close(to) prior to copyfd() to achieve the same */
4851#define COPYFD_EXACT ((int)~INT_MAX)
4849static int 4852static int
4850copyfd(int from, int to) 4853copyfd(int from, int to)
4851{ 4854{
4852 int newfd; 4855 int newfd;
4853 4856
4854 newfd = fcntl(from, F_DUPFD, to); 4857 if (to & COPYFD_EXACT) {
4858 to &= ~COPYFD_EXACT;
4859 /*if (from != to)*/
4860 newfd = dup2(from, to);
4861 } else {
4862 newfd = fcntl(from, F_DUPFD, to);
4863 }
4855 if (newfd < 0) { 4864 if (newfd < 0) {
4856 if (errno == EMFILE) 4865 if (errno == EMFILE)
4857 return EMPTY; 4866 return EMPTY;
@@ -4947,11 +4956,7 @@ redirect(union node *redir, int flags)
4947 /* Descriptor wasn't open before redirect. 4956 /* Descriptor wasn't open before redirect.
4948 * Mark it for close in the future */ 4957 * Mark it for close in the future */
4949 if (need_to_remember(sv, fd)) { 4958 if (need_to_remember(sv, fd)) {
4950 if (fd == 2) 4959 goto remember_to_close;
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 } 4960 }
4956 continue; 4961 continue;
4957 } 4962 }
@@ -4959,6 +4964,10 @@ redirect(union node *redir, int flags)
4959 if (need_to_remember(sv, fd)) { 4964 if (need_to_remember(sv, fd)) {
4960 /* Copy old descriptor */ 4965 /* Copy old descriptor */
4961 i = fcntl(fd, F_DUPFD, 10); 4966 i = fcntl(fd, F_DUPFD, 10);
4967/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
4968 * are closed in popredir() in the child, preventing them from leaking
4969 * into child. (popredir() also cleans up the mess in case of failures)
4970 */
4962 if (i == -1) { 4971 if (i == -1) {
4963 i = errno; 4972 i = errno;
4964 if (i != EBADF) { 4973 if (i != EBADF) {
@@ -4969,31 +4978,25 @@ redirect(union node *redir, int flags)
4969 ash_msg_and_raise_error("%d: %m", fd); 4978 ash_msg_and_raise_error("%d: %m", fd);
4970 /* NOTREACHED */ 4979 /* NOTREACHED */
4971 } 4980 }
4972 /* EBADF: it is not open - ok */ 4981 /* EBADF: it is not open - good, remember to close it */
4973 } else { 4982 remember_to_close:
4974 /* fd is open, save its copy */ 4983 i = CLOSED;
4975/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds 4984 } /* else: fd is open, save its copy */
4976 * are closed in popredir() in the child, preventing them from leaking 4985 if (fd == 2)
4977 * into child. (popredir() also cleans up the mess in case of failures) 4986 copied_fd2 = i;
4978 */ 4987 sv->two_fd[sv_pos].orig = fd;
4979 if (fd == 2) 4988 sv->two_fd[sv_pos].copy = i;
4980 copied_fd2 = i; 4989 sv_pos++;
4981 sv->two_fd[sv_pos].orig = fd;
4982 sv->two_fd[sv_pos].copy = i;
4983 sv_pos++;
4984 close(fd);
4985 }
4986 } else {
4987 close(fd);
4988 } 4990 }
4989 /* At this point fd is closed */
4990 if (newfd < 0) { 4991 if (newfd < 0) {
4991 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */ 4992 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
4992 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ 4993 if (redir->ndup.dupfd < 0) { /* "NN>&-" */
4993 copyfd(redir->ndup.dupfd, fd); 4994 close(fd);
4995 } else {
4996 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
4994 } 4997 }
4995 } else { /* move newfd to fd */ 4998 } else if (fd != newfd) { /* move newfd to fd */
4996 copyfd(newfd, fd); 4999 copyfd(newfd, fd | COPYFD_EXACT);
4997 close(newfd); 5000 close(newfd);
4998 } 5001 }
4999 } while ((redir = redir->nfile.next) != NULL); 5002 } while ((redir = redir->nfile.next) != NULL);
@@ -5025,8 +5028,8 @@ popredir(int drop)
5025 } 5028 }
5026 if (rp->two_fd[i].copy != EMPTY) { 5029 if (rp->two_fd[i].copy != EMPTY) {
5027 if (!drop) { 5030 if (!drop) {
5028 close(fd); 5031 /*close(fd);*/
5029 copyfd(rp->two_fd[i].copy, fd); 5032 copyfd(rp->two_fd[i].copy, fd | COPYFD_EXACT);
5030 } 5033 }
5031 close(rp->two_fd[i].copy); 5034 close(rp->two_fd[i].copy);
5032 } 5035 }
@@ -5064,7 +5067,8 @@ redirectsafe(union node *redir, int flags)
5064 struct jmploc jmploc; 5067 struct jmploc jmploc;
5065 5068
5066 SAVE_INT(saveint); 5069 SAVE_INT(saveint);
5067 err = setjmp(jmploc.loc) * 2; 5070 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5071 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
5068 if (!err) { 5072 if (!err) {
5069 exception_handler = &jmploc; 5073 exception_handler = &jmploc;
5070 redirect(redir, flags); 5074 redirect(redir, flags);
@@ -5443,8 +5447,8 @@ evalbackcmd(union node *n, struct backcmd *result)
5443 FORCE_INT_ON; 5447 FORCE_INT_ON;
5444 close(pip[0]); 5448 close(pip[0]);
5445 if (pip[1] != 1) { 5449 if (pip[1] != 1) {
5446 close(1); 5450 /*close(1);*/
5447 copyfd(pip[1], 1); 5451 copyfd(pip[1], 1 | COPYFD_EXACT);
5448 close(pip[1]); 5452 close(pip[1]);
5449 } 5453 }
5450 eflag = 0; 5454 eflag = 0;
@@ -10691,11 +10695,7 @@ readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10691 len = out - (char *)stackblock(); 10695 len = out - (char *)stackblock();
10692 out = stackblock(); 10696 out = stackblock();
10693 if (eofmark == NULL) { 10697 if (eofmark == NULL) {
10694 if ((c == '>' || c == '<') 10698 if ((c == '>' || c == '<') && quotef == 0) {
10695 && quotef == 0
10696 // && len <= 2 // THIS LIMITS fd to 1 char: N>file, but no NN>file!
10697 // && (*out == '\0' || isdigit(*out))
10698 ) {
10699 int maxlen = 9 + 1; /* max 9 digit fd#: 999999999 */ 10699 int maxlen = 9 + 1; /* max 9 digit fd#: 999999999 */
10700 char *np = out; 10700 char *np = out;
10701 while (--maxlen && isdigit(*np)) 10701 while (--maxlen && isdigit(*np))
diff --git a/shell/ash_test/ash-redir/redir2.right b/shell/ash_test/ash-redir/redir2.right
new file mode 100644
index 000000000..d86bac9de
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir2.right
@@ -0,0 +1 @@
OK
diff --git a/shell/ash_test/ash-redir/redir2.tests b/shell/ash_test/ash-redir/redir2.tests
new file mode 100755
index 000000000..61ccea30c
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir2.tests
@@ -0,0 +1,5 @@
1# ash once couldn't redirect above fd#9
2exec 1>/dev/null
3(echo LOST1 >&22) 22>&1
4(echo LOST2 >&22) 22>&1
5(echo OK >&22) 22>&2
diff --git a/shell/ash_test/ash-redir/redir3.right b/shell/ash_test/ash-redir/redir3.right
new file mode 100644
index 000000000..fd641a8ea
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir3.right
@@ -0,0 +1,3 @@
1TEST
2./redir3.tests: line 4: 9: Bad file descriptor
3Output to fd#9: 1
diff --git a/shell/ash_test/ash-redir/redir3.tests b/shell/ash_test/ash-redir/redir3.tests
new file mode 100755
index 000000000..f50a7674c
--- /dev/null
+++ b/shell/ash_test/ash-redir/redir3.tests
@@ -0,0 +1,5 @@
1# redirects to closed descriptors should not leave these descriptors"
2# open afterwards
3echo TEST 9>/dev/null
4echo MUST ERROR OUT >&9
5echo "Output to fd#9: $?"
diff --git a/shell/ash_test/run-all b/shell/ash_test/run-all
index b0a6d1088..4d0f39a41 100755
--- a/shell/ash_test/run-all
+++ b/shell/ash_test/run-all
@@ -3,8 +3,8 @@
3TOPDIR=$PWD 3TOPDIR=$PWD
4 4
5test -x ash || { 5test -x ash || {
6 echo "No ./ash?! Perhaps you want to run 'ln -s ../../busybox ash'" 6 echo "No ./ash - creating a link to ../../busybox"
7 exit 7 ln -s ../../busybox ash
8} 8}
9test -x printenv || gcc -O2 -o printenv printenv.c || exit $? 9test -x printenv || gcc -O2 -o printenv printenv.c || exit $?
10test -x recho || gcc -O2 -o recho recho.c || exit $? 10test -x recho || gcc -O2 -o recho recho.c || exit $?