diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-08-19 20:15:26 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-08-19 20:15:26 +0200 |
commit | e9abe75fda82a986b0b40969ebdd4aa92bcb52e3 (patch) | |
tree | f500368056e7f414998beb28cee6336d6f9de031 /shell | |
parent | 215b0ca6e4fe466c6942d21a1bba62d97f2d5e5d (diff) | |
download | busybox-w32-e9abe75fda82a986b0b40969ebdd4aa92bcb52e3.tar.gz busybox-w32-e9abe75fda82a986b0b40969ebdd4aa92bcb52e3.tar.bz2 busybox-w32-e9abe75fda82a986b0b40969ebdd4aa92bcb52e3.zip |
hush: `cmd` and arithmetic also need the fix for FILE rewind
Discovered by running testsuite with a newest glibc
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 71 |
1 files changed, 39 insertions, 32 deletions
diff --git a/shell/hush.c b/shell/hush.c index be5c98a20..b41d9d04b 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -1477,19 +1477,50 @@ static sighandler_t install_sighandler(int sig, sighandler_t handler) | |||
1477 | return old_sa.sa_handler; | 1477 | return old_sa.sa_handler; |
1478 | } | 1478 | } |
1479 | 1479 | ||
1480 | static void hush_exit(int exitcode) NORETURN; | ||
1481 | static void fflush_and__exit(void) NORETURN; | ||
1482 | static void restore_ttypgrp_and__exit(void) NORETURN; | ||
1483 | |||
1484 | static void restore_ttypgrp_and__exit(void) | ||
1485 | { | ||
1486 | /* xfunc has failed! die die die */ | ||
1487 | /* no EXIT traps, this is an escape hatch! */ | ||
1488 | G.exiting = 1; | ||
1489 | hush_exit(xfunc_error_retval); | ||
1490 | } | ||
1491 | |||
1492 | /* Needed only on some libc: | ||
1493 | * It was observed that on exit(), fgetc'ed buffered data | ||
1494 | * gets "unwound" via lseek(fd, -NUM, SEEK_CUR). | ||
1495 | * With the net effect that even after fork(), not vfork(), | ||
1496 | * exit() in NOEXECed applet in "sh SCRIPT": | ||
1497 | * noexec_applet_here | ||
1498 | * echo END_OF_SCRIPT | ||
1499 | * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT". | ||
1500 | * This makes "echo END_OF_SCRIPT" executed twice. | ||
1501 | * Similar problems can be seen with die_if_script() -> xfunc_die() | ||
1502 | * and in `cmd` handling. | ||
1503 | * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit(): | ||
1504 | */ | ||
1505 | static void fflush_and__exit(void) | ||
1506 | { | ||
1507 | fflush_all(); | ||
1508 | _exit(xfunc_error_retval); | ||
1509 | } | ||
1510 | |||
1480 | #if ENABLE_HUSH_JOB | 1511 | #if ENABLE_HUSH_JOB |
1481 | 1512 | ||
1482 | static void xfunc_has_died(void); | ||
1483 | /* After [v]fork, in child: do not restore tty pgrp on xfunc death */ | 1513 | /* After [v]fork, in child: do not restore tty pgrp on xfunc death */ |
1484 | # define disable_restore_tty_pgrp_on_exit() (die_func = NULL) | 1514 | # define disable_restore_tty_pgrp_on_exit() (die_func = fflush_and__exit) |
1485 | /* After [v]fork, in parent: restore tty pgrp on xfunc death */ | 1515 | /* After [v]fork, in parent: restore tty pgrp on xfunc death */ |
1486 | # define enable_restore_tty_pgrp_on_exit() (die_func = xfunc_has_died) | 1516 | # define enable_restore_tty_pgrp_on_exit() (die_func = restore_ttypgrp_and__exit) |
1487 | 1517 | ||
1488 | /* Restores tty foreground process group, and exits. | 1518 | /* Restores tty foreground process group, and exits. |
1489 | * May be called as signal handler for fatal signal | 1519 | * May be called as signal handler for fatal signal |
1490 | * (will resend signal to itself, producing correct exit state) | 1520 | * (will resend signal to itself, producing correct exit state) |
1491 | * or called directly with -EXITCODE. | 1521 | * or called directly with -EXITCODE. |
1492 | * We also call it if xfunc is exiting. */ | 1522 | * We also call it if xfunc is exiting. |
1523 | */ | ||
1493 | static void sigexit(int sig) NORETURN; | 1524 | static void sigexit(int sig) NORETURN; |
1494 | static void sigexit(int sig) | 1525 | static void sigexit(int sig) |
1495 | { | 1526 | { |
@@ -1544,7 +1575,6 @@ static sighandler_t pick_sighandler(unsigned sig) | |||
1544 | } | 1575 | } |
1545 | 1576 | ||
1546 | /* Restores tty foreground process group, and exits. */ | 1577 | /* Restores tty foreground process group, and exits. */ |
1547 | static void hush_exit(int exitcode) NORETURN; | ||
1548 | static void hush_exit(int exitcode) | 1578 | static void hush_exit(int exitcode) |
1549 | { | 1579 | { |
1550 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 1580 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
@@ -1588,15 +1618,6 @@ static void hush_exit(int exitcode) | |||
1588 | #endif | 1618 | #endif |
1589 | } | 1619 | } |
1590 | 1620 | ||
1591 | static void xfunc_has_died(void) NORETURN; | ||
1592 | static void xfunc_has_died(void) | ||
1593 | { | ||
1594 | /* xfunc has failed! die die die */ | ||
1595 | /* no EXIT traps, this is an escape hatch! */ | ||
1596 | G.exiting = 1; | ||
1597 | hush_exit(xfunc_error_retval); | ||
1598 | } | ||
1599 | |||
1600 | 1621 | ||
1601 | //TODO: return a mask of ALL handled sigs? | 1622 | //TODO: return a mask of ALL handled sigs? |
1602 | static int check_and_run_traps(void) | 1623 | static int check_and_run_traps(void) |
@@ -5913,7 +5934,8 @@ static FILE *generate_stream_from_string(const char *s, pid_t *pid_p) | |||
5913 | ) { | 5934 | ) { |
5914 | static const char *const argv[] = { NULL, NULL }; | 5935 | static const char *const argv[] = { NULL, NULL }; |
5915 | builtin_trap((char**)argv); | 5936 | builtin_trap((char**)argv); |
5916 | exit(0); /* not _exit() - we need to fflush */ | 5937 | fflush_all(); /* important */ |
5938 | _exit(0); | ||
5917 | } | 5939 | } |
5918 | # if BB_MMU | 5940 | # if BB_MMU |
5919 | reset_traps_to_defaults(); | 5941 | reset_traps_to_defaults(); |
@@ -6467,22 +6489,7 @@ static void dump_cmd_in_x_mode(char **argv) | |||
6467 | * Don't exit() here. If you don't exec, use _exit instead. | 6489 | * Don't exit() here. If you don't exec, use _exit instead. |
6468 | * The at_exit handlers apparently confuse the calling process, | 6490 | * The at_exit handlers apparently confuse the calling process, |
6469 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) | 6491 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) |
6470 | * Also, it was observed that on exit(), fgetc'ed buffered data | ||
6471 | * gets "unwound" by some libcs, via lseek(fd, -NUM, SEEK_CUR). | ||
6472 | * With the net effect that even after fork(), not vfork(), | ||
6473 | * exit() in NOEXECed applet in "sh SCRIPT": | ||
6474 | * noexec_applet_here | ||
6475 | * echo END_OF_SCRIPT | ||
6476 | * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT". | ||
6477 | * This makes "echo END_OF_SCRIPT" executed twice. exexit() is the fix. | ||
6478 | */ | 6492 | */ |
6479 | #if ENABLE_FEATURE_SH_STANDALONE | ||
6480 | static void exexit(void) | ||
6481 | { | ||
6482 | fflush_all(); | ||
6483 | _exit(xfunc_error_retval); | ||
6484 | } | ||
6485 | #endif | ||
6486 | static void pseudo_exec_argv(nommu_save_t *nommu_save, | 6493 | static void pseudo_exec_argv(nommu_save_t *nommu_save, |
6487 | char **argv, int assignment_cnt, | 6494 | char **argv, int assignment_cnt, |
6488 | char **argv_expanded) NORETURN; | 6495 | char **argv_expanded) NORETURN; |
@@ -6563,7 +6570,6 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
6563 | # if BB_MMU /* see above why on NOMMU it is not allowed */ | 6570 | # if BB_MMU /* see above why on NOMMU it is not allowed */ |
6564 | if (APPLET_IS_NOEXEC(a)) { | 6571 | if (APPLET_IS_NOEXEC(a)) { |
6565 | debug_printf_exec("running applet '%s'\n", argv[0]); | 6572 | debug_printf_exec("running applet '%s'\n", argv[0]); |
6566 | die_func = exexit; | ||
6567 | run_applet_no_and_exit(a, argv); | 6573 | run_applet_no_and_exit(a, argv); |
6568 | } | 6574 | } |
6569 | # endif | 6575 | # endif |
@@ -7804,6 +7810,7 @@ int hush_main(int argc, char **argv) | |||
7804 | INIT_G(); | 7810 | INIT_G(); |
7805 | if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ | 7811 | if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ |
7806 | G.last_exitcode = EXIT_SUCCESS; | 7812 | G.last_exitcode = EXIT_SUCCESS; |
7813 | |||
7807 | #if ENABLE_HUSH_FAST | 7814 | #if ENABLE_HUSH_FAST |
7808 | G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ | 7815 | G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ |
7809 | #endif | 7816 | #endif |
@@ -7893,7 +7900,7 @@ int hush_main(int argc, char **argv) | |||
7893 | /* Initialize some more globals to non-zero values */ | 7900 | /* Initialize some more globals to non-zero values */ |
7894 | cmdedit_update_prompt(); | 7901 | cmdedit_update_prompt(); |
7895 | 7902 | ||
7896 | die_func = xfunc_has_died; | 7903 | die_func = restore_ttypgrp_and__exit; |
7897 | 7904 | ||
7898 | /* Shell is non-interactive at first. We need to call | 7905 | /* Shell is non-interactive at first. We need to call |
7899 | * install_special_sighandlers() if we are going to execute "sh <script>", | 7906 | * install_special_sighandlers() if we are going to execute "sh <script>", |