diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2024-07-13 01:47:49 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2024-07-13 02:13:28 +0200 |
commit | 23da5c4b716b92524240c6f81c2e2474c1825cfc (patch) | |
tree | 1acec3d32a91a45d2e182d0b7ffa643367935ffe /shell | |
parent | 14e28c18ca1a0fb87b6c73d5cb7487e80bc6713a (diff) | |
download | busybox-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-x | shell/ash_test/ash-redir/redir_exec2.tests | 1 | ||||
-rw-r--r-- | shell/hush.c | 51 | ||||
-rw-r--r-- | shell/hush_test/hush-redir/redir3.right | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-redir/redir_exec2.tests | 1 | ||||
-rw-r--r-- | shell/hush_test/hush-redir/redir_to_bad_fd.right | 3 | ||||
-rw-r--r-- | shell/hush_test/hush-redir/redir_to_bad_fd255.right | 3 | ||||
-rw-r--r-- | shell/hush_test/hush-redir/redir_to_bad_fd3.right | 3 |
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 | |||
8 | exec 5>&- | 8 | exec 5>&- |
9 | test -e fd/5 && echo BUG | 9 | test -e fd/5 && echo BUG |
10 | echo One:$? | 10 | echo 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 | */ |
7944 | static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) | 7960 | static 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 @@ | |||
1 | TEST | 1 | TEST |
2 | hush: can't duplicate file descriptor: Bad file descriptor | 2 | hush: dup2(9,1): Bad file descriptor |
3 | Output 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 | |||
8 | exec 5>&- | 8 | exec 5>&- |
9 | test -e fd/5 && echo BUG | 9 | test -e fd/5 && echo BUG |
10 | echo One:$? | 10 | echo 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 @@ | |||
1 | hush: can't duplicate file descriptor: Bad file descriptor | 1 | hush: dup2(10,1): Bad file descriptor |
2 | OK | ||
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 @@ | |||
1 | hush: can't duplicate file descriptor: Bad file descriptor | 1 | hush: dup2(255,1): Bad file descriptor |
2 | OK | ||
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 @@ | |||
1 | hush: can't duplicate file descriptor: Bad file descriptor | 1 | hush: fd#3 is not open |
2 | OK | ||