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>", |
