diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-07 22:07:28 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-07 22:07:28 +0200 |
commit | 2db74610cdf8ffb4f9ed99b62c755377d3cc48ea (patch) | |
tree | 6835b5b3e84d3d9c5b511053df692db8bfab8792 /shell | |
parent | 69a5ec9dccfd183cdf6bee7b994336670755cd47 (diff) | |
download | busybox-w32-2db74610cdf8ffb4f9ed99b62c755377d3cc48ea.tar.gz busybox-w32-2db74610cdf8ffb4f9ed99b62c755377d3cc48ea.tar.bz2 busybox-w32-2db74610cdf8ffb4f9ed99b62c755377d3cc48ea.zip |
hush: fix two redirection testcase failures
function old new delta
save_fds_on_redirect 183 256 +73
fcntl_F_DUPFD - 46 +46
restore_redirects 74 96 +22
xdup_and_close 51 72 +21
setup_redirects 196 200 +4
hush_main 988 983 -5
static.C 12 - -12
run_pipe 1595 1551 -44
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 4/2 up/down: 166/-61) Total: 105 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 179 | ||||
-rw-r--r-- | shell/hush_test/hush-redir/redir3.right | 3 | ||||
-rw-r--r-- | shell/hush_test/hush-redir/redir_to_bad_fd.right | 3 |
3 files changed, 117 insertions, 68 deletions
diff --git a/shell/hush.c b/shell/hush.c index cf6d8cd9f..59bddbfff 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -402,6 +402,7 @@ | |||
402 | #define debug_printf_expand(...) do {} while (0) | 402 | #define debug_printf_expand(...) do {} while (0) |
403 | #define debug_printf_varexp(...) do {} while (0) | 403 | #define debug_printf_varexp(...) do {} while (0) |
404 | #define debug_printf_glob(...) do {} while (0) | 404 | #define debug_printf_glob(...) do {} while (0) |
405 | #define debug_printf_redir(...) do {} while (0) | ||
405 | #define debug_printf_list(...) do {} while (0) | 406 | #define debug_printf_list(...) do {} while (0) |
406 | #define debug_printf_subst(...) do {} while (0) | 407 | #define debug_printf_subst(...) do {} while (0) |
407 | #define debug_printf_clean(...) do {} while (0) | 408 | #define debug_printf_clean(...) do {} while (0) |
@@ -1146,6 +1147,10 @@ static const struct built_in_command bltins2[] = { | |||
1146 | # define DEBUG_GLOB 0 | 1147 | # define DEBUG_GLOB 0 |
1147 | #endif | 1148 | #endif |
1148 | 1149 | ||
1150 | #ifndef debug_printf_redir | ||
1151 | # define debug_printf_redir(...) (indent(), fdprintf(2, __VA_ARGS__)) | ||
1152 | #endif | ||
1153 | |||
1149 | #ifndef debug_printf_list | 1154 | #ifndef debug_printf_list |
1150 | # define debug_printf_list(...) (indent(), fdprintf(2, __VA_ARGS__)) | 1155 | # define debug_printf_list(...) (indent(), fdprintf(2, __VA_ARGS__)) |
1151 | #endif | 1156 | #endif |
@@ -1381,12 +1386,30 @@ static void free_strings(char **strings) | |||
1381 | free(strings); | 1386 | free(strings); |
1382 | } | 1387 | } |
1383 | 1388 | ||
1389 | static int fcntl_F_DUPFD(int fd, int avoid_fd) | ||
1390 | { | ||
1391 | int newfd; | ||
1392 | repeat: | ||
1393 | newfd = fcntl(fd, F_DUPFD, avoid_fd + 1); | ||
1394 | if (newfd < 0) { | ||
1395 | if (errno == EBUSY) | ||
1396 | goto repeat; | ||
1397 | if (errno == EINTR) | ||
1398 | goto repeat; | ||
1399 | } | ||
1400 | return newfd; | ||
1401 | } | ||
1384 | 1402 | ||
1385 | static int xdup_and_close(int fd, int F_DUPFD_maybe_CLOEXEC) | 1403 | static int xdup_and_close(int fd, int F_DUPFD_maybe_CLOEXEC, int avoid_fd) |
1386 | { | 1404 | { |
1387 | /* We avoid taking stdio fds. Mimicking ash: use fds above 9 */ | 1405 | int newfd; |
1388 | int newfd = fcntl(fd, F_DUPFD_maybe_CLOEXEC, 10); | 1406 | repeat: |
1407 | newfd = fcntl(fd, F_DUPFD_maybe_CLOEXEC, avoid_fd + 1); | ||
1389 | if (newfd < 0) { | 1408 | if (newfd < 0) { |
1409 | if (errno == EBUSY) | ||
1410 | goto repeat; | ||
1411 | if (errno == EINTR) | ||
1412 | goto repeat; | ||
1390 | /* fd was not open? */ | 1413 | /* fd was not open? */ |
1391 | if (errno == EBADF) | 1414 | if (errno == EBADF) |
1392 | return fd; | 1415 | return fd; |
@@ -1424,13 +1447,14 @@ static void fclose_and_forget(FILE *fp) | |||
1424 | } | 1447 | } |
1425 | fclose(fp); | 1448 | fclose(fp); |
1426 | } | 1449 | } |
1427 | static int save_FILEs_on_redirect(int fd) | 1450 | static int save_FILEs_on_redirect(int fd, int avoid_fd) |
1428 | { | 1451 | { |
1429 | struct FILE_list *fl = G.FILE_list; | 1452 | struct FILE_list *fl = G.FILE_list; |
1430 | while (fl) { | 1453 | while (fl) { |
1431 | if (fd == fl->fd) { | 1454 | if (fd == fl->fd) { |
1432 | /* We use it only on script files, they are all CLOEXEC */ | 1455 | /* We use it only on script files, they are all CLOEXEC */ |
1433 | fl->fd = xdup_and_close(fd, F_DUPFD_CLOEXEC); | 1456 | fl->fd = xdup_and_close(fd, F_DUPFD_CLOEXEC, avoid_fd); |
1457 | debug_printf_redir("redirect_fd %d: matches a script fd, moving it to %d\n", fd, fl->fd); | ||
1434 | return 1; | 1458 | return 1; |
1435 | } | 1459 | } |
1436 | fl = fl->next; | 1460 | fl = fl->next; |
@@ -1443,6 +1467,7 @@ static void restore_redirected_FILEs(void) | |||
1443 | while (fl) { | 1467 | while (fl) { |
1444 | int should_be = fileno(fl->fp); | 1468 | int should_be = fileno(fl->fp); |
1445 | if (fl->fd != should_be) { | 1469 | if (fl->fd != should_be) { |
1470 | debug_printf_redir("restoring script fd from %d to %d\n", fl->fd, should_be); | ||
1446 | xmove_fd(fl->fd, should_be); | 1471 | xmove_fd(fl->fd, should_be); |
1447 | fl->fd = should_be; | 1472 | fl->fd = should_be; |
1448 | } | 1473 | } |
@@ -6518,77 +6543,108 @@ static void setup_heredoc(struct redir_struct *redir) | |||
6518 | wait(NULL); /* wait till child has died */ | 6543 | wait(NULL); /* wait till child has died */ |
6519 | } | 6544 | } |
6520 | 6545 | ||
6521 | /* fd: redirect wants this fd to be used (e.g. 3>file). | 6546 | struct squirrel { |
6522 | * Move all conflicting internally used fds, | 6547 | int orig_fd; |
6523 | * and remember them so that we can restore them later. | 6548 | int moved_to; |
6524 | */ | 6549 | /* moved_to = n: fd was moved to n; restore back to orig_fd after redir */ |
6525 | static int save_fds_on_redirect(int fd, int squirrel[3]) | 6550 | /* moved_to = -1: fd was opened by redirect; close orig_fd after redir */ |
6551 | }; | ||
6552 | |||
6553 | static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) | ||
6526 | { | 6554 | { |
6527 | if (squirrel) { | 6555 | int i = 0; |
6528 | /* Handle redirects of fds 0,1,2 */ | ||
6529 | 6556 | ||
6530 | /* If we collide with an already moved stdio fd... */ | 6557 | if (sq) while (sq[i].orig_fd >= 0) { |
6531 | if (fd == squirrel[0]) { | 6558 | /* If we collide with an already moved fd... */ |
6532 | squirrel[0] = xdup_and_close(squirrel[0], F_DUPFD); | 6559 | if (fd == sq[i].moved_to) { |
6533 | return 1; | 6560 | sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd); |
6534 | } | 6561 | debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, sq[i].moved_to); |
6535 | if (fd == squirrel[1]) { | 6562 | if (sq[i].moved_to < 0) /* what? */ |
6536 | squirrel[1] = xdup_and_close(squirrel[1], F_DUPFD); | ||
6537 | return 1; | ||
6538 | } | ||
6539 | if (fd == squirrel[2]) { | ||
6540 | squirrel[2] = xdup_and_close(squirrel[2], F_DUPFD); | ||
6541 | return 1; | ||
6542 | } | ||
6543 | /* If we are about to redirect stdio fd, and did not yet move it... */ | ||
6544 | if (fd <= 2 && squirrel[fd] < 0) { | ||
6545 | /* We avoid taking stdio fds */ | ||
6546 | squirrel[fd] = fcntl(fd, F_DUPFD, 10); | ||
6547 | if (squirrel[fd] < 0 && errno != EBADF) | ||
6548 | xfunc_die(); | 6563 | xfunc_die(); |
6549 | return 0; /* "we did not close fd" */ | 6564 | return sq; |
6565 | } | ||
6566 | if (fd == sq[i].orig_fd) { | ||
6567 | /* Example: echo Hello >/dev/null 1>&2 */ | ||
6568 | debug_printf_redir("redirect_fd %d: already moved\n", fd); | ||
6569 | return sq; | ||
6550 | } | 6570 | } |
6571 | i++; | ||
6551 | } | 6572 | } |
6552 | 6573 | ||
6574 | sq = xrealloc(sq, (i + 2) * sizeof(sq[0])); | ||
6575 | sq[i].orig_fd = fd; | ||
6576 | /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */ | ||
6577 | sq[i].moved_to = fcntl_F_DUPFD(fd, avoid_fd); | ||
6578 | debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, sq[i].moved_to); | ||
6579 | if (sq[i].moved_to < 0 && errno != EBADF) | ||
6580 | xfunc_die(); | ||
6581 | sq[i+1].orig_fd = -1; /* end marker */ | ||
6582 | return sq; | ||
6583 | } | ||
6584 | |||
6585 | /* fd: redirect wants this fd to be used (e.g. 3>file). | ||
6586 | * Move all conflicting internally used fds, | ||
6587 | * and remember them so that we can restore them later. | ||
6588 | */ | ||
6589 | static int save_fds_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) | ||
6590 | { | ||
6591 | if (avoid_fd < 9) /* the important case here is that it can be -1 */ | ||
6592 | avoid_fd = 9; | ||
6593 | |||
6553 | #if ENABLE_HUSH_INTERACTIVE | 6594 | #if ENABLE_HUSH_INTERACTIVE |
6554 | if (fd != 0 && fd == G.interactive_fd) { | 6595 | if (fd != 0 && fd == G.interactive_fd) { |
6555 | G.interactive_fd = xdup_and_close(G.interactive_fd, F_DUPFD_CLOEXEC); | 6596 | G.interactive_fd = xdup_and_close(G.interactive_fd, F_DUPFD_CLOEXEC, avoid_fd); |
6556 | return 1; | 6597 | debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G.interactive_fd); |
6598 | return 1; /* "we closed fd" */ | ||
6557 | } | 6599 | } |
6558 | #endif | 6600 | #endif |
6559 | |||
6560 | /* Are we called from setup_redirects(squirrel==NULL)? Two cases: | 6601 | /* Are we called from setup_redirects(squirrel==NULL)? Two cases: |
6561 | * (1) Redirect in a forked child. No need to save FILEs' fds, | 6602 | * (1) Redirect in a forked child. No need to save FILEs' fds, |
6562 | * we aren't going to use them anymore, ok to trash. | 6603 | * we aren't going to use them anymore, ok to trash. |
6563 | * (2) "exec 3>FILE". Bummer. We can save FILEs' fds, | 6604 | * (2) "exec 3>FILE". Bummer. We can save script FILEs' fds, |
6564 | * but how are we doing to use them? | 6605 | * but how are we doing to restore them? |
6565 | * "fileno(fd) = new_fd" can't be done. | 6606 | * "fileno(fd) = new_fd" can't be done. |
6566 | */ | 6607 | */ |
6567 | if (!squirrel) | 6608 | if (!sqp) |
6568 | return 0; | 6609 | return 0; |
6569 | 6610 | ||
6570 | return save_FILEs_on_redirect(fd); | 6611 | /* If this one of script's fds? */ |
6612 | if (save_FILEs_on_redirect(fd, avoid_fd)) | ||
6613 | return 1; /* yes. "we closed fd" */ | ||
6614 | |||
6615 | /* Check whether it collides with any open fds (e.g. stdio), save fds as needed */ | ||
6616 | *sqp = add_squirrel(*sqp, fd, avoid_fd); | ||
6617 | return 0; /* "we did not close fd" */ | ||
6571 | } | 6618 | } |
6572 | 6619 | ||
6573 | static void restore_redirects(int squirrel[3]) | 6620 | static void restore_redirects(struct squirrel *sq) |
6574 | { | 6621 | { |
6575 | int i, fd; | 6622 | |
6576 | for (i = 0; i <= 2; i++) { | 6623 | if (sq) { |
6577 | fd = squirrel[i]; | 6624 | int i = 0; |
6578 | if (fd != -1) { | 6625 | while (sq[i].orig_fd >= 0) { |
6579 | /* We simply die on error */ | 6626 | if (sq[i].moved_to >= 0) { |
6580 | xmove_fd(fd, i); | 6627 | /* We simply die on error */ |
6628 | debug_printf_redir("restoring redirected fd from %d to %d\n", sq[i].moved_to, sq[i].orig_fd); | ||
6629 | xmove_fd(sq[i].moved_to, sq[i].orig_fd); | ||
6630 | } else { | ||
6631 | /* cmd1 9>FILE; cmd2_should_see_fd9_closed */ | ||
6632 | debug_printf_redir("restoring redirected fd %d: closing it\n", sq[i].orig_fd); | ||
6633 | close(sq[i].orig_fd); | ||
6634 | } | ||
6635 | i++; | ||
6581 | } | 6636 | } |
6637 | free(sq); | ||
6582 | } | 6638 | } |
6583 | 6639 | ||
6584 | /* Moved G.interactive_fd stays on new fd, not doing anything for it */ | 6640 | /* If moved, G.interactive_fd stays on new fd, not restoring it */ |
6585 | 6641 | ||
6586 | restore_redirected_FILEs(); | 6642 | restore_redirected_FILEs(); |
6587 | } | 6643 | } |
6588 | 6644 | ||
6589 | /* squirrel != NULL means we squirrel away copies of stdin, stdout, | 6645 | /* squirrel != NULL means we squirrel away copies of stdin, stdout, |
6590 | * and stderr if they are redirected. */ | 6646 | * and stderr if they are redirected. */ |
6591 | static int setup_redirects(struct command *prog, int squirrel[]) | 6647 | static int setup_redirects(struct command *prog, struct squirrel **sqp) |
6592 | { | 6648 | { |
6593 | int openfd, mode; | 6649 | int openfd, mode; |
6594 | struct redir_struct *redir; | 6650 | struct redir_struct *redir; |
@@ -6596,7 +6652,7 @@ static int setup_redirects(struct command *prog, int squirrel[]) | |||
6596 | for (redir = prog->redirects; redir; redir = redir->next) { | 6652 | for (redir = prog->redirects; redir; redir = redir->next) { |
6597 | if (redir->rd_type == REDIRECT_HEREDOC2) { | 6653 | if (redir->rd_type == REDIRECT_HEREDOC2) { |
6598 | /* "rd_fd<<HERE" case */ | 6654 | /* "rd_fd<<HERE" case */ |
6599 | save_fds_on_redirect(redir->rd_fd, squirrel); | 6655 | save_fds_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp); |
6600 | /* for REDIRECT_HEREDOC2, rd_filename holds _contents_ | 6656 | /* for REDIRECT_HEREDOC2, rd_filename holds _contents_ |
6601 | * of the heredoc */ | 6657 | * of the heredoc */ |
6602 | debug_printf_parse("set heredoc '%s'\n", | 6658 | debug_printf_parse("set heredoc '%s'\n", |
@@ -6635,7 +6691,7 @@ static int setup_redirects(struct command *prog, int squirrel[]) | |||
6635 | } | 6691 | } |
6636 | 6692 | ||
6637 | if (openfd != redir->rd_fd) { | 6693 | if (openfd != redir->rd_fd) { |
6638 | int closed = save_fds_on_redirect(redir->rd_fd, squirrel); | 6694 | int closed = save_fds_on_redirect(redir->rd_fd, /*avoid:*/ openfd, sqp); |
6639 | if (openfd == REDIRFD_CLOSE) { | 6695 | if (openfd == REDIRFD_CLOSE) { |
6640 | /* "rd_fd >&-" means "close me" */ | 6696 | /* "rd_fd >&-" means "close me" */ |
6641 | if (!closed) { | 6697 | if (!closed) { |
@@ -7497,14 +7553,14 @@ static int checkjobs_and_fg_shell(struct pipe *fg_pipe) | |||
7497 | static int redirect_and_varexp_helper(char ***new_env_p, | 7553 | static int redirect_and_varexp_helper(char ***new_env_p, |
7498 | struct variable **old_vars_p, | 7554 | struct variable **old_vars_p, |
7499 | struct command *command, | 7555 | struct command *command, |
7500 | int squirrel[3], | 7556 | struct squirrel **sqp, |
7501 | char **argv_expanded) | 7557 | char **argv_expanded) |
7502 | { | 7558 | { |
7503 | /* setup_redirects acts on file descriptors, not FILEs. | 7559 | /* setup_redirects acts on file descriptors, not FILEs. |
7504 | * This is perfect for work that comes after exec(). | 7560 | * This is perfect for work that comes after exec(). |
7505 | * Is it really safe for inline use? Experimentally, | 7561 | * Is it really safe for inline use? Experimentally, |
7506 | * things seem to work. */ | 7562 | * things seem to work. */ |
7507 | int rcode = setup_redirects(command, squirrel); | 7563 | int rcode = setup_redirects(command, sqp); |
7508 | if (rcode == 0) { | 7564 | if (rcode == 0) { |
7509 | char **new_env = expand_assignments(command->argv, command->assignment_cnt); | 7565 | char **new_env = expand_assignments(command->argv, command->assignment_cnt); |
7510 | *new_env_p = new_env; | 7566 | *new_env_p = new_env; |
@@ -7524,8 +7580,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
7524 | struct command *command; | 7580 | struct command *command; |
7525 | char **argv_expanded; | 7581 | char **argv_expanded; |
7526 | char **argv; | 7582 | char **argv; |
7527 | /* it is not always needed, but we aim to smaller code */ | 7583 | struct squirrel *squirrel = NULL; |
7528 | int squirrel[] = { -1, -1, -1 }; | ||
7529 | int rcode; | 7584 | int rcode; |
7530 | 7585 | ||
7531 | debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds); | 7586 | debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds); |
@@ -7582,7 +7637,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
7582 | /* { list } */ | 7637 | /* { list } */ |
7583 | debug_printf("non-subshell group\n"); | 7638 | debug_printf("non-subshell group\n"); |
7584 | rcode = 1; /* exitcode if redir failed */ | 7639 | rcode = 1; /* exitcode if redir failed */ |
7585 | if (setup_redirects(command, squirrel) == 0) { | 7640 | if (setup_redirects(command, &squirrel) == 0) { |
7586 | debug_printf_exec(": run_list\n"); | 7641 | debug_printf_exec(": run_list\n"); |
7587 | rcode = run_list(command->group) & 0xff; | 7642 | rcode = run_list(command->group) & 0xff; |
7588 | } | 7643 | } |
@@ -7609,7 +7664,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
7609 | /* Ensure redirects take effect (that is, create files). | 7664 | /* Ensure redirects take effect (that is, create files). |
7610 | * Try "a=t >file" */ | 7665 | * Try "a=t >file" */ |
7611 | #if 0 /* A few cases in testsuite fail with this code. FIXME */ | 7666 | #if 0 /* A few cases in testsuite fail with this code. FIXME */ |
7612 | rcode = redirect_and_varexp_helper(&new_env, /*old_vars:*/ NULL, command, squirrel, /*argv_expanded:*/ NULL); | 7667 | rcode = redirect_and_varexp_helper(&new_env, /*old_vars:*/ NULL, command, &squirrel, /*argv_expanded:*/ NULL); |
7613 | /* Set shell variables */ | 7668 | /* Set shell variables */ |
7614 | if (new_env) { | 7669 | if (new_env) { |
7615 | argv = new_env; | 7670 | argv = new_env; |
@@ -7631,7 +7686,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
7631 | 7686 | ||
7632 | #else /* Older, bigger, but more correct code */ | 7687 | #else /* Older, bigger, but more correct code */ |
7633 | 7688 | ||
7634 | rcode = setup_redirects(command, squirrel); | 7689 | rcode = setup_redirects(command, &squirrel); |
7635 | restore_redirects(squirrel); | 7690 | restore_redirects(squirrel); |
7636 | /* Set shell variables */ | 7691 | /* Set shell variables */ |
7637 | if (G_x_mode) | 7692 | if (G_x_mode) |
@@ -7694,7 +7749,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
7694 | goto clean_up_and_ret1; | 7749 | goto clean_up_and_ret1; |
7695 | } | 7750 | } |
7696 | } | 7751 | } |
7697 | rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); | 7752 | rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, &squirrel, argv_expanded); |
7698 | if (rcode == 0) { | 7753 | if (rcode == 0) { |
7699 | if (!funcp) { | 7754 | if (!funcp) { |
7700 | debug_printf_exec(": builtin '%s' '%s'...\n", | 7755 | debug_printf_exec(": builtin '%s' '%s'...\n", |
@@ -7723,10 +7778,6 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
7723 | unset_vars(new_env); | 7778 | unset_vars(new_env); |
7724 | add_vars(old_vars); | 7779 | add_vars(old_vars); |
7725 | /* clean_up_and_ret0: */ | 7780 | /* clean_up_and_ret0: */ |
7726 | |||
7727 | //FIXME: this restores stdio fds, but does not close other redirects! | ||
7728 | //Example: after "echo TEST 9>/dev/null" fd#9 is not closed! | ||
7729 | //The squirreling code needs rework to remember all fds, not just 0,1,2. | ||
7730 | restore_redirects(squirrel); | 7781 | restore_redirects(squirrel); |
7731 | clean_up_and_ret1: | 7782 | clean_up_and_ret1: |
7732 | free(argv_expanded); | 7783 | free(argv_expanded); |
@@ -7739,7 +7790,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
7739 | if (ENABLE_FEATURE_SH_NOFORK) { | 7790 | if (ENABLE_FEATURE_SH_NOFORK) { |
7740 | int n = find_applet_by_name(argv_expanded[0]); | 7791 | int n = find_applet_by_name(argv_expanded[0]); |
7741 | if (n >= 0 && APPLET_IS_NOFORK(n)) { | 7792 | if (n >= 0 && APPLET_IS_NOFORK(n)) { |
7742 | rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); | 7793 | rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, &squirrel, argv_expanded); |
7743 | if (rcode == 0) { | 7794 | if (rcode == 0) { |
7744 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", | 7795 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", |
7745 | argv_expanded[0], argv_expanded[1]); | 7796 | argv_expanded[0], argv_expanded[1]); |
@@ -8694,7 +8745,7 @@ int hush_main(int argc, char **argv) | |||
8694 | G_saved_tty_pgrp = 0; | 8745 | G_saved_tty_pgrp = 0; |
8695 | 8746 | ||
8696 | /* try to dup stdin to high fd#, >= 255 */ | 8747 | /* try to dup stdin to high fd#, >= 255 */ |
8697 | G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); | 8748 | G_interactive_fd = fcntl_F_DUPFD(STDIN_FILENO, 254); |
8698 | if (G_interactive_fd < 0) { | 8749 | if (G_interactive_fd < 0) { |
8699 | /* try to dup to any fd */ | 8750 | /* try to dup to any fd */ |
8700 | G_interactive_fd = dup(STDIN_FILENO); | 8751 | G_interactive_fd = dup(STDIN_FILENO); |
@@ -8767,7 +8818,7 @@ int hush_main(int argc, char **argv) | |||
8767 | #elif ENABLE_HUSH_INTERACTIVE | 8818 | #elif ENABLE_HUSH_INTERACTIVE |
8768 | /* No job control compiled in, only prompt/line editing */ | 8819 | /* No job control compiled in, only prompt/line editing */ |
8769 | if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { | 8820 | if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { |
8770 | G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255); | 8821 | G_interactive_fd = fcntl_F_DUPFD(STDIN_FILENO, 254); |
8771 | if (G_interactive_fd < 0) { | 8822 | if (G_interactive_fd < 0) { |
8772 | /* try to dup to any fd */ | 8823 | /* try to dup to any fd */ |
8773 | G_interactive_fd = dup(STDIN_FILENO); | 8824 | G_interactive_fd = dup(STDIN_FILENO); |
diff --git a/shell/hush_test/hush-redir/redir3.right b/shell/hush_test/hush-redir/redir3.right index fd641a8ea..e3c878b7d 100644 --- a/shell/hush_test/hush-redir/redir3.right +++ b/shell/hush_test/hush-redir/redir3.right | |||
@@ -1,3 +1,2 @@ | |||
1 | TEST | 1 | TEST |
2 | ./redir3.tests: line 4: 9: Bad file descriptor | 2 | hush: can't duplicate file descriptor: Bad file descriptor |
3 | Output to fd#9: 1 | ||
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 43b8af293..936911ce5 100644 --- a/shell/hush_test/hush-redir/redir_to_bad_fd.right +++ b/shell/hush_test/hush-redir/redir_to_bad_fd.right | |||
@@ -1,2 +1 @@ | |||
1 | ./redir_to_bad_fd.tests: line 2: 10: Bad file descriptor | hush: can't duplicate file descriptor: Bad file descriptor | |
2 | OK | ||