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 /shell | |
| 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>
Diffstat (limited to 'shell')
| -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:$? | ||
