diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-24 12:42:17 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-24 12:42:17 +0200 |
commit | 621fc50e83f7446a060f0b9689dc8dc59ee0743a (patch) | |
tree | 7b40c2368fe3f7387ab44a1f0758d850cbd29929 | |
parent | b72f1ef17b97802d33f0ac522f64bea0f65442c5 (diff) | |
download | busybox-w32-621fc50e83f7446a060f0b9689dc8dc59ee0743a.tar.gz busybox-w32-621fc50e83f7446a060f0b9689dc8dc59ee0743a.tar.bz2 busybox-w32-621fc50e83f7446a060f0b9689dc8dc59ee0743a.zip |
hush: fix a case when redirect to a closed fd #1 is not restoring (closing) it
function old new delta
setup_redirects 200 245 +45
append_squirrel - 41 +41
save_fds_on_redirect 256 221 -35
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/1 up/down: 86/-35) Total: 51 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/hush.c | 34 | ||||
-rw-r--r-- | shell/hush_test/hush-redir/redir.right | 2 | ||||
-rwxr-xr-x | shell/hush_test/hush-redir/redir.tests | 6 |
3 files changed, 35 insertions, 7 deletions
diff --git a/shell/hush.c b/shell/hush.c index 309ed2139..20b092398 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -6643,8 +6643,18 @@ struct squirrel { | |||
6643 | /* moved_to = -1: fd was opened by redirect; close orig_fd after redir */ | 6643 | /* moved_to = -1: fd was opened by redirect; close orig_fd after redir */ |
6644 | }; | 6644 | }; |
6645 | 6645 | ||
6646 | static struct squirrel *append_squirrel(struct squirrel *sq, int i, int orig, int moved) | ||
6647 | { | ||
6648 | sq = xrealloc(sq, (i + 2) * sizeof(sq[0])); | ||
6649 | sq[i].orig_fd = orig; | ||
6650 | sq[i].moved_to = moved; | ||
6651 | sq[i+1].orig_fd = -1; /* end marker */ | ||
6652 | return sq; | ||
6653 | } | ||
6654 | |||
6646 | static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) | 6655 | static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) |
6647 | { | 6656 | { |
6657 | int moved_to; | ||
6648 | int i = 0; | 6658 | int i = 0; |
6649 | 6659 | ||
6650 | if (sq) while (sq[i].orig_fd >= 0) { | 6660 | if (sq) while (sq[i].orig_fd >= 0) { |
@@ -6664,15 +6674,12 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) | |||
6664 | i++; | 6674 | i++; |
6665 | } | 6675 | } |
6666 | 6676 | ||
6667 | sq = xrealloc(sq, (i + 2) * sizeof(sq[0])); | ||
6668 | sq[i].orig_fd = fd; | ||
6669 | /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */ | 6677 | /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */ |
6670 | sq[i].moved_to = fcntl_F_DUPFD(fd, avoid_fd); | 6678 | moved_to = fcntl_F_DUPFD(fd, avoid_fd); |
6671 | debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, sq[i].moved_to); | 6679 | debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to); |
6672 | if (sq[i].moved_to < 0 && errno != EBADF) | 6680 | if (moved_to < 0 && errno != EBADF) |
6673 | xfunc_die(); | 6681 | xfunc_die(); |
6674 | sq[i+1].orig_fd = -1; /* end marker */ | 6682 | return append_squirrel(sq, i, fd, moved_to); |
6675 | return sq; | ||
6676 | } | 6683 | } |
6677 | 6684 | ||
6678 | /* fd: redirect wants this fd to be used (e.g. 3>file). | 6685 | /* fd: redirect wants this fd to be used (e.g. 3>file). |
@@ -6778,6 +6785,19 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp) | |||
6778 | */ | 6785 | */ |
6779 | return 1; | 6786 | return 1; |
6780 | } | 6787 | } |
6788 | if (openfd == redir->rd_fd && sqp) { | ||
6789 | /* open() gave us precisely the fd we wanted. | ||
6790 | * This means that this fd was not busy | ||
6791 | * (not opened to anywhere). | ||
6792 | * Remember to close it on restore: | ||
6793 | */ | ||
6794 | struct squirrel *sq = *sqp; | ||
6795 | int i = 0; | ||
6796 | if (sq) while (sq[i].orig_fd >= 0) | ||
6797 | i++; | ||
6798 | *sqp = append_squirrel(sq, i, openfd, -1); /* -1 = "it was closed" */ | ||
6799 | debug_printf_redir("redir to previously closed fd %d\n", openfd); | ||
6800 | } | ||
6781 | } else { | 6801 | } else { |
6782 | /* "rd_fd<*>rd_dup" or "rd_fd<*>-" cases */ | 6802 | /* "rd_fd<*>rd_dup" or "rd_fd<*>-" cases */ |
6783 | openfd = redir->rd_dup; | 6803 | openfd = redir->rd_dup; |
diff --git a/shell/hush_test/hush-redir/redir.right b/shell/hush_test/hush-redir/redir.right new file mode 100644 index 000000000..4de5ec701 --- /dev/null +++ b/shell/hush_test/hush-redir/redir.right | |||
@@ -0,0 +1,2 @@ | |||
1 | hush: write error: Bad file descriptor | ||
2 | TEST | ||
diff --git a/shell/hush_test/hush-redir/redir.tests b/shell/hush_test/hush-redir/redir.tests new file mode 100755 index 000000000..7a1a66806 --- /dev/null +++ b/shell/hush_test/hush-redir/redir.tests | |||
@@ -0,0 +1,6 @@ | |||
1 | # test: closed fds should stay closed | ||
2 | exec 1>&- | ||
3 | echo TEST >TEST | ||
4 | echo JUNK # lost: stdout is closed | ||
5 | cat TEST >&2 | ||
6 | rm TEST | ||