diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2019-11-01 14:16:07 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2019-11-01 14:16:07 +0100 |
commit | 21806562ca6350c78a14a89c22f985900ce96ade (patch) | |
tree | 8f6aa1ce178688c9668102c888b851e25490118e | |
parent | ea096d6c1389c93bdb6c6c45a04aff9062c7d8cf (diff) | |
download | busybox-w32-21806562ca6350c78a14a89c22f985900ce96ade.tar.gz busybox-w32-21806562ca6350c78a14a89c22f985900ce96ade.tar.bz2 busybox-w32-21806562ca6350c78a14a89c22f985900ce96ade.zip |
hush: restore redirected stdin
function old new delta
restore_redirects 52 95 +43
save_fd_on_redirect 243 253 +10
hfopen 90 99 +9
fgetc_interactive 259 261 +2
builtin_type 117 115 -2
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 4/1 up/down: 64/-2) Total: 62 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/ash_test/ash-redir/redir_stdin1.right | 3 | ||||
-rwxr-xr-x | shell/ash_test/ash-redir/redir_stdin1.tests | 7 | ||||
-rw-r--r-- | shell/hush.c | 29 | ||||
-rw-r--r-- | shell/hush_test/hush-redir/redir_stdin1.right | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-redir/redir_stdin1.tests | 7 |
5 files changed, 42 insertions, 7 deletions
diff --git a/shell/ash_test/ash-redir/redir_stdin1.right b/shell/ash_test/ash-redir/redir_stdin1.right new file mode 100644 index 000000000..1c6217e92 --- /dev/null +++ b/shell/ash_test/ash-redir/redir_stdin1.right | |||
@@ -0,0 +1,3 @@ | |||
1 | #Testing that stdin redirect is restored | ||
2 | read2 | ||
3 | Ok:0 | ||
diff --git a/shell/ash_test/ash-redir/redir_stdin1.tests b/shell/ash_test/ash-redir/redir_stdin1.tests new file mode 100755 index 000000000..f72253f9d --- /dev/null +++ b/shell/ash_test/ash-redir/redir_stdin1.tests | |||
@@ -0,0 +1,7 @@ | |||
1 | #Testing that stdin redirect is restored | ||
2 | echo read2 | $THIS_SH -c 'read r <redir_stdin1.tests | ||
3 | echo $r | ||
4 | read r | ||
5 | echo $r | ||
6 | ' | ||
7 | echo Ok:$? | ||
diff --git a/shell/hush.c b/shell/hush.c index 96a935875..25e5fb906 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -573,7 +573,6 @@ typedef struct HFILE { | |||
573 | char *cur; | 573 | char *cur; |
574 | char *end; | 574 | char *end; |
575 | struct HFILE *next_hfile; | 575 | struct HFILE *next_hfile; |
576 | int is_stdin; | ||
577 | int fd; | 576 | int fd; |
578 | char buf[1024]; | 577 | char buf[1024]; |
579 | } HFILE; | 578 | } HFILE; |
@@ -973,6 +972,7 @@ struct globals { | |||
973 | unsigned execute_lineno; | 972 | unsigned execute_lineno; |
974 | #endif | 973 | #endif |
975 | HFILE *HFILE_list; | 974 | HFILE *HFILE_list; |
975 | HFILE *HFILE_stdin; | ||
976 | /* Which signals have non-DFL handler (even with no traps set)? | 976 | /* Which signals have non-DFL handler (even with no traps set)? |
977 | * Set at the start to: | 977 | * Set at the start to: |
978 | * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS) | 978 | * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS) |
@@ -1603,7 +1603,8 @@ static HFILE *hfopen(const char *name) | |||
1603 | } | 1603 | } |
1604 | 1604 | ||
1605 | fp = xmalloc(sizeof(*fp)); | 1605 | fp = xmalloc(sizeof(*fp)); |
1606 | fp->is_stdin = (name == NULL); | 1606 | if (name == NULL) |
1607 | G.HFILE_stdin = fp; | ||
1607 | fp->fd = fd; | 1608 | fp->fd = fd; |
1608 | fp->cur = fp->end = fp->buf; | 1609 | fp->cur = fp->end = fp->buf; |
1609 | fp->next_hfile = G.HFILE_list; | 1610 | fp->next_hfile = G.HFILE_list; |
@@ -2666,7 +2667,7 @@ static int fgetc_interactive(struct in_str *i) | |||
2666 | { | 2667 | { |
2667 | int ch; | 2668 | int ch; |
2668 | /* If it's interactive stdin, get new line. */ | 2669 | /* If it's interactive stdin, get new line. */ |
2669 | if (G_interactive_fd && i->file->is_stdin) { | 2670 | if (G_interactive_fd && i->file == G.HFILE_stdin) { |
2670 | /* Returns first char (or EOF), the rest is in i->p[] */ | 2671 | /* Returns first char (or EOF), the rest is in i->p[] */ |
2671 | ch = get_user_input(i); | 2672 | ch = get_user_input(i); |
2672 | G.promptmode = 1; /* PS2 */ | 2673 | G.promptmode = 1; /* PS2 */ |
@@ -7605,7 +7606,9 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) | |||
7605 | avoid_fd = 9; | 7606 | avoid_fd = 9; |
7606 | 7607 | ||
7607 | #if ENABLE_HUSH_INTERACTIVE | 7608 | #if ENABLE_HUSH_INTERACTIVE |
7608 | if (fd == G_interactive_fd) { | 7609 | if (fd != 0 /* don't trigger for G_interactive_fd == 0 (that's "not interactive" flag) */ |
7610 | && fd == G_interactive_fd | ||
7611 | ) { | ||
7609 | /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */ | 7612 | /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */ |
7610 | G_interactive_fd = xdup_CLOEXEC_and_close(G_interactive_fd, avoid_fd); | 7613 | G_interactive_fd = xdup_CLOEXEC_and_close(G_interactive_fd, avoid_fd); |
7611 | debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G_interactive_fd); | 7614 | debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G_interactive_fd); |
@@ -7619,7 +7622,7 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) | |||
7619 | /* No need to move script fds. | 7622 | /* No need to move script fds. |
7620 | * For NOMMU case, it's actively wrong: we'd change ->fd | 7623 | * For NOMMU case, it's actively wrong: we'd change ->fd |
7621 | * fields in memory for the parent, but parent's fds | 7624 | * fields in memory for the parent, but parent's fds |
7622 | * aren't be moved, it would use wrong fd! | 7625 | * aren't moved, it would use wrong fd! |
7623 | * Reproducer: "cmd 3>FILE" in script. | 7626 | * Reproducer: "cmd 3>FILE" in script. |
7624 | * If we would call move_HFILEs_on_redirect(), child would: | 7627 | * If we would call move_HFILEs_on_redirect(), child would: |
7625 | * fcntl64(3, F_DUPFD_CLOEXEC, 10) = 10 | 7628 | * fcntl64(3, F_DUPFD_CLOEXEC, 10) = 10 |
@@ -7683,6 +7686,20 @@ static void restore_redirects(struct squirrel *sq) | |||
7683 | } | 7686 | } |
7684 | free(sq); | 7687 | free(sq); |
7685 | } | 7688 | } |
7689 | if (G.HFILE_stdin | ||
7690 | && G.HFILE_stdin->fd != STDIN_FILENO | ||
7691 | ) { | ||
7692 | /* Testcase: interactive "read r <FILE; echo $r; read r; echo $r". | ||
7693 | * Redirect moves ->fd to e.g. 10, | ||
7694 | * and it is not restored above (we do not restore script fds | ||
7695 | * after redirects, we just use new, "moved" fds). | ||
7696 | * However for stdin, get_user_input() -> read_line_input(), | ||
7697 | * and read builtin, depend on fd == STDIN_FILENO. | ||
7698 | */ | ||
7699 | debug_printf_redir("restoring %d to stdin\n", G.HFILE_stdin->fd); | ||
7700 | xmove_fd(G.HFILE_stdin->fd, STDIN_FILENO); | ||
7701 | G.HFILE_stdin->fd = STDIN_FILENO; | ||
7702 | } | ||
7686 | 7703 | ||
7687 | /* If moved, G_interactive_fd stays on new fd, not restoring it */ | 7704 | /* If moved, G_interactive_fd stays on new fd, not restoring it */ |
7688 | } | 7705 | } |
@@ -10214,8 +10231,6 @@ int hush_main(int argc, char **argv) | |||
10214 | G_saved_tty_pgrp = 0; | 10231 | G_saved_tty_pgrp = 0; |
10215 | } | 10232 | } |
10216 | } | 10233 | } |
10217 | // TODO: track & disallow any attempts of user | ||
10218 | // to (inadvertently) close/redirect G_interactive_fd | ||
10219 | } | 10234 | } |
10220 | debug_printf("interactive_fd:%d\n", G_interactive_fd); | 10235 | debug_printf("interactive_fd:%d\n", G_interactive_fd); |
10221 | if (G_interactive_fd) { | 10236 | if (G_interactive_fd) { |
diff --git a/shell/hush_test/hush-redir/redir_stdin1.right b/shell/hush_test/hush-redir/redir_stdin1.right new file mode 100644 index 000000000..1c6217e92 --- /dev/null +++ b/shell/hush_test/hush-redir/redir_stdin1.right | |||
@@ -0,0 +1,3 @@ | |||
1 | #Testing that stdin redirect is restored | ||
2 | read2 | ||
3 | Ok:0 | ||
diff --git a/shell/hush_test/hush-redir/redir_stdin1.tests b/shell/hush_test/hush-redir/redir_stdin1.tests new file mode 100755 index 000000000..f72253f9d --- /dev/null +++ b/shell/hush_test/hush-redir/redir_stdin1.tests | |||
@@ -0,0 +1,7 @@ | |||
1 | #Testing that stdin redirect is restored | ||
2 | echo read2 | $THIS_SH -c 'read r <redir_stdin1.tests | ||
3 | echo $r | ||
4 | read r | ||
5 | echo $r | ||
6 | ' | ||
7 | echo Ok:$? | ||