aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2024-07-13 01:47:49 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2024-07-13 02:13:28 +0200
commit23da5c4b716b92524240c6f81c2e2474c1825cfc (patch)
tree1acec3d32a91a45d2e182d0b7ffa643367935ffe /shell
parent14e28c18ca1a0fb87b6c73d5cb7487e80bc6713a (diff)
downloadbusybox-w32-23da5c4b716b92524240c6f81c2e2474c1825cfc.tar.gz
busybox-w32-23da5c4b716b92524240c6f81c2e2474c1825cfc.tar.bz2
busybox-w32-23da5c4b716b92524240c6f81c2e2474c1825cfc.zip
hush: do not exit interactive shell on some redirection errors
$ echo >&99 hush: dup2(99,1): Bad file descriptor $ echo >&9999 hush: fcntl(1,F_DUPFD,10000): Invalid argument $ echo 2>/dev/tty 10>&9999 hush: fcntl(10,F_DUPFD,10000): Invalid argument $ still alive!_ function old new delta static.setup_redirects 334 394 +60 .rodata 105661 105712 +51 dup_CLOEXEC 49 79 +30 save_fd_on_redirect 263 277 +14 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/0 up/down: 155/0) Total: 155 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rwxr-xr-xshell/ash_test/ash-redir/redir_exec2.tests1
-rw-r--r--shell/hush.c51
-rw-r--r--shell/hush_test/hush-redir/redir3.right3
-rwxr-xr-xshell/hush_test/hush-redir/redir_exec2.tests1
-rw-r--r--shell/hush_test/hush-redir/redir_to_bad_fd.right3
-rw-r--r--shell/hush_test/hush-redir/redir_to_bad_fd255.right3
-rw-r--r--shell/hush_test/hush-redir/redir_to_bad_fd3.right3
7 files changed, 47 insertions, 18 deletions
diff --git a/shell/ash_test/ash-redir/redir_exec2.tests b/shell/ash_test/ash-redir/redir_exec2.tests
index 700a51786..0af767592 100755
--- a/shell/ash_test/ash-redir/redir_exec2.tests
+++ b/shell/ash_test/ash-redir/redir_exec2.tests
@@ -8,4 +8,3 @@ ls -1 fd/3
8exec 5>&- 8exec 5>&-
9test -e fd/5 && echo BUG 9test -e fd/5 && echo BUG
10echo One:$? 10echo One:$?
11
diff --git a/shell/hush.c b/shell/hush.c
index 1d5642260..707b77c9c 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1581,6 +1581,16 @@ static int dup_CLOEXEC(int fd, int avoid_fd)
1581 goto repeat; 1581 goto repeat;
1582 if (errno == EINTR) 1582 if (errno == EINTR)
1583 goto repeat; 1583 goto repeat;
1584 if (errno != EBADF) {
1585 /* "echo >&9999" gets EINVAL trying to save fd 1 to above 9999.
1586 * We could try saving it _below_ 9999 instead (how?), but
1587 * this probably means that dup2(9999,1) to effectuate >&9999
1588 * would also not work: fd 9999 can't exist.
1589 * (This differs from "echo >&99" where saving works, but
1590 * subsequent dup2(99,1) fails if fd 99 is not open).
1591 */
1592 bb_perror_msg("fcntl(%d,F_DUPFD,%d)", fd, avoid_fd + 1);
1593 }
1584 } 1594 }
1585 return newfd; 1595 return newfd;
1586} 1596}
@@ -7893,10 +7903,16 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
7893 if (sq) for (; sq[i].orig_fd >= 0; i++) { 7903 if (sq) for (; sq[i].orig_fd >= 0; i++) {
7894 /* If we collide with an already moved fd... */ 7904 /* If we collide with an already moved fd... */
7895 if (fd == sq[i].moved_to) { 7905 if (fd == sq[i].moved_to) {
7896 sq[i].moved_to = dup_CLOEXEC(sq[i].moved_to, avoid_fd); 7906 moved_to = dup_CLOEXEC(sq[i].moved_to, avoid_fd);
7897 debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, sq[i].moved_to); 7907 debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, moved_to);
7898 if (sq[i].moved_to < 0) /* what? */ 7908 if (moved_to < 0) {
7899 xfunc_die(); 7909 /* "echo 2>/dev/tty 10>&9999" testcase:
7910 * We move fd 2 to 10, then discover we need to move fd 10
7911 * (and not hit 9999) and the latter fails.
7912 */
7913 return NULL; /* fcntl failed */
7914 }
7915 sq[i].moved_to = moved_to;
7900 return sq; 7916 return sq;
7901 } 7917 }
7902 if (fd == sq[i].orig_fd) { 7918 if (fd == sq[i].orig_fd) {
@@ -7910,7 +7926,7 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
7910 moved_to = dup_CLOEXEC(fd, avoid_fd); 7926 moved_to = dup_CLOEXEC(fd, avoid_fd);
7911 debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to); 7927 debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to);
7912 if (moved_to < 0 && errno != EBADF) 7928 if (moved_to < 0 && errno != EBADF)
7913 xfunc_die(); 7929 return NULL; /* fcntl failed (not because fd is closed) */
7914 return append_squirrel(sq, i, fd, moved_to); 7930 return append_squirrel(sq, i, fd, moved_to);
7915} 7931}
7916 7932
@@ -7943,6 +7959,8 @@ static struct squirrel *add_squirrel_closed(struct squirrel *sq, int fd)
7943 */ 7959 */
7944static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) 7960static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
7945{ 7961{
7962 struct squirrel *new_squirrel;
7963
7946 if (avoid_fd < 9) /* the important case here is that it can be -1 */ 7964 if (avoid_fd < 9) /* the important case here is that it can be -1 */
7947 avoid_fd = 9; 7965 avoid_fd = 9;
7948 7966
@@ -8006,7 +8024,10 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
8006 } 8024 }
8007 8025
8008 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */ 8026 /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */
8009 *sqp = add_squirrel(*sqp, fd, avoid_fd); 8027 new_squirrel = add_squirrel(*sqp, fd, avoid_fd);
8028 if (!new_squirrel)
8029 return -1; /* redirect error */
8030 *sqp = new_squirrel;
8010 return 0; /* "we did not close fd" */ 8031 return 0; /* "we did not close fd" */
8011} 8032}
8012 8033
@@ -8092,7 +8113,8 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
8092 8113
8093 if (redir->rd_type == REDIRECT_HEREDOC2) { 8114 if (redir->rd_type == REDIRECT_HEREDOC2) {
8094 /* "rd_fd<<HERE" case */ 8115 /* "rd_fd<<HERE" case */
8095 save_fd_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp); 8116 if (save_fd_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp) < 0)
8117 return 1;
8096 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_ 8118 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_
8097 * of the heredoc */ 8119 * of the heredoc */
8098 debug_printf_redir("set heredoc '%s'\n", 8120 debug_printf_redir("set heredoc '%s'\n",
@@ -8151,6 +8173,8 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
8151 /* if "N>&-": close redir->rd_fd (newfd is REDIRFD_CLOSE) */ 8173 /* if "N>&-": close redir->rd_fd (newfd is REDIRFD_CLOSE) */
8152 8174
8153 closed = save_fd_on_redirect(redir->rd_fd, /*avoid:*/ newfd, sqp); 8175 closed = save_fd_on_redirect(redir->rd_fd, /*avoid:*/ newfd, sqp);
8176 if (closed < 0)
8177 return 1; /* error */
8154 if (newfd == REDIRFD_CLOSE) { 8178 if (newfd == REDIRFD_CLOSE) {
8155 /* "N>&-" means "close me" */ 8179 /* "N>&-" means "close me" */
8156 if (!closed) { 8180 if (!closed) {
@@ -8164,13 +8188,16 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
8164 * and second redirect closes 3! Restore code then closes 3 again. 8188 * and second redirect closes 3! Restore code then closes 3 again.
8165 */ 8189 */
8166 } else { 8190 } else {
8167 /* if newfd is a script fd or saved fd, simulate EBADF */ 8191 /* if newfd is a script fd or saved fd, do not allow to use it */
8168 if (internally_opened_fd(newfd, sqp && sqp != ERR_PTR ? *sqp : NULL)) { 8192 if (internally_opened_fd(newfd, sqp && sqp != ERR_PTR ? *sqp : NULL)) {
8169 //errno = EBADF; 8193 bb_error_msg("fd#%d is not open", newfd);
8170 //bb_perror_msg_and_die("can't duplicate file descriptor"); 8194 return 1;
8171 newfd = -1; /* same effect as code above */ 8195 }
8196 if (dup2(newfd, redir->rd_fd) < 0) {
8197 /* "echo >&99" testcase */
8198 bb_perror_msg("dup2(%d,%d)", newfd, redir->rd_fd);
8199 return 1;
8172 } 8200 }
8173 xdup2(newfd, redir->rd_fd);
8174 if (redir->rd_dup == REDIRFD_TO_FILE) 8201 if (redir->rd_dup == REDIRFD_TO_FILE)
8175 /* "rd_fd > FILE" */ 8202 /* "rd_fd > FILE" */
8176 close(newfd); 8203 close(newfd);
diff --git a/shell/hush_test/hush-redir/redir3.right b/shell/hush_test/hush-redir/redir3.right
index e3c878b7d..d49237c42 100644
--- a/shell/hush_test/hush-redir/redir3.right
+++ b/shell/hush_test/hush-redir/redir3.right
@@ -1,2 +1,3 @@
1TEST 1TEST
2hush: can't duplicate file descriptor: Bad file descriptor 2hush: dup2(9,1): Bad file descriptor
3Output to fd#9: 1
diff --git a/shell/hush_test/hush-redir/redir_exec2.tests b/shell/hush_test/hush-redir/redir_exec2.tests
index 700a51786..0af767592 100755
--- a/shell/hush_test/hush-redir/redir_exec2.tests
+++ b/shell/hush_test/hush-redir/redir_exec2.tests
@@ -8,4 +8,3 @@ ls -1 fd/3
8exec 5>&- 8exec 5>&-
9test -e fd/5 && echo BUG 9test -e fd/5 && echo BUG
10echo One:$? 10echo One:$?
11
diff --git a/shell/hush_test/hush-redir/redir_to_bad_fd.right b/shell/hush_test/hush-redir/redir_to_bad_fd.right
index 936911ce5..4fc51cc93 100644
--- a/shell/hush_test/hush-redir/redir_to_bad_fd.right
+++ b/shell/hush_test/hush-redir/redir_to_bad_fd.right
@@ -1 +1,2 @@
1hush: can't duplicate file descriptor: Bad file descriptor 1hush: dup2(10,1): Bad file descriptor
2OK
diff --git a/shell/hush_test/hush-redir/redir_to_bad_fd255.right b/shell/hush_test/hush-redir/redir_to_bad_fd255.right
index 936911ce5..baa2959ca 100644
--- a/shell/hush_test/hush-redir/redir_to_bad_fd255.right
+++ b/shell/hush_test/hush-redir/redir_to_bad_fd255.right
@@ -1 +1,2 @@
1hush: can't duplicate file descriptor: Bad file descriptor 1hush: dup2(255,1): Bad file descriptor
2OK
diff --git a/shell/hush_test/hush-redir/redir_to_bad_fd3.right b/shell/hush_test/hush-redir/redir_to_bad_fd3.right
index 936911ce5..5e54abc0a 100644
--- a/shell/hush_test/hush-redir/redir_to_bad_fd3.right
+++ b/shell/hush_test/hush-redir/redir_to_bad_fd3.right
@@ -1 +1,2 @@
1hush: can't duplicate file descriptor: Bad file descriptor 1hush: fd#3 is not open
2OK