aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2024-07-12 21:58:04 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2024-07-12 22:10:50 +0200
commit0829fce079dae45737330114c27886cb8af85043 (patch)
tree4c15302da692098b3cfa13c045b7818377c99c10
parent1ad2f5cd9fe5de0f19212924e100c6d87229c950 (diff)
downloadbusybox-w32-0829fce079dae45737330114c27886cb8af85043.tar.gz
busybox-w32-0829fce079dae45737330114c27886cb8af85043.tar.bz2
busybox-w32-0829fce079dae45737330114c27886cb8af85043.zip
ash: do not abort interactive mode on >&9999 redirect
With very large fd#, the error code path is different from one for closed but small fd#. Make it not abort if we are interactive: $ echo text >&99 # this wasn't buggy ash: dup2(9,1): Bad file descriptor $ echo text >&9999 # this was ash: fcntl(1,F_DUPFD,10000): Invalid argument function old new delta .rodata 105637 105661 +24 dup2_or_raise 35 38 +3 redirect 1084 1044 -40 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 27/-40) Total: -13 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/ash.c20
1 files changed, 16 insertions, 4 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 094a87390..39455c7c5 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -5621,10 +5621,13 @@ dup2_or_raise(int from, int to)
5621 newfd = (from != to) ? dup2(from, to) : to; 5621 newfd = (from != to) ? dup2(from, to) : to;
5622 if (newfd < 0) { 5622 if (newfd < 0) {
5623 /* Happens when source fd is not open: try "echo >&99" */ 5623 /* Happens when source fd is not open: try "echo >&99" */
5624 ash_msg_and_raise_perror("%d", from); 5624 ash_msg_and_raise_perror("dup2(%d,%d)", from, to);
5625 } 5625 }
5626 return newfd; 5626 return newfd;
5627} 5627}
5628/* The only possible error return is EBADF (fd wasn't open).
5629 * Transient errors retry, other errors raise exception.
5630 */
5628static int 5631static int
5629dup_CLOEXEC(int fd, int avoid_fd) 5632dup_CLOEXEC(int fd, int avoid_fd)
5630{ 5633{
@@ -5639,6 +5642,16 @@ dup_CLOEXEC(int fd, int avoid_fd)
5639 goto repeat; 5642 goto repeat;
5640 if (errno == EINTR) 5643 if (errno == EINTR)
5641 goto repeat; 5644 goto repeat;
5645 if (errno != EBADF) {
5646 /* "echo >&9999" gets EINVAL trying to save fd 1 to above 9999.
5647 * We could try saving it _below_ 9999 instead (how?), but
5648 * this probably means that dup2(9999,1) to effectuate >&9999
5649 * would also not work: fd 9999 can't exist. Gracefully bail out.
5650 * (This differs from "echo >&99" where saving works, but
5651 * subsequent dup2(99,1) fails if fd 99 is not open).
5652 */
5653 ash_msg_and_raise_perror("fcntl(%d,F_DUPFD,%d)", fd, avoid_fd + 1);
5654 }
5642 } 5655 }
5643 return newfd; 5656 return newfd;
5644} 5657}
@@ -5754,7 +5767,7 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
5754 new_fd = dup_CLOEXEC(fd, avoid_fd); 5767 new_fd = dup_CLOEXEC(fd, avoid_fd);
5755 sq->two_fd[i].moved_to = new_fd; 5768 sq->two_fd[i].moved_to = new_fd;
5756 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd)); 5769 TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd));
5757 if (new_fd < 0) /* what? */ 5770 if (new_fd < 0) /* EBADF? what? */
5758 xfunc_die(); 5771 xfunc_die();
5759 return 0; /* "we did not close fd" */ 5772 return 0; /* "we did not close fd" */
5760 } 5773 }
@@ -5769,8 +5782,7 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq)
5769 new_fd = dup_CLOEXEC(fd, avoid_fd); 5782 new_fd = dup_CLOEXEC(fd, avoid_fd);
5770 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd)); 5783 TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd));
5771 if (new_fd < 0) { 5784 if (new_fd < 0) {
5772 if (errno != EBADF) 5785 /* EBADF (fd is not open) */
5773 xfunc_die();
5774 /* new_fd = CLOSED; - already is -1 */ 5786 /* new_fd = CLOSED; - already is -1 */
5775 } 5787 }
5776 sq->two_fd[i].moved_to = new_fd; 5788 sq->two_fd[i].moved_to = new_fd;