diff options
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 47 |
1 files changed, 44 insertions, 3 deletions
diff --git a/shell/hush.c b/shell/hush.c index bced388bf..357a354e2 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -988,6 +988,10 @@ struct globals { | |||
988 | # define G_fatal_sig_mask 0 | 988 | # define G_fatal_sig_mask 0 |
989 | #endif | 989 | #endif |
990 | #if ENABLE_HUSH_TRAP | 990 | #if ENABLE_HUSH_TRAP |
991 | int pre_trap_exitcode; | ||
992 | # if ENABLE_HUSH_FUNCTIONS | ||
993 | int return_exitcode; | ||
994 | # endif | ||
991 | char **traps; /* char *traps[NSIG] */ | 995 | char **traps; /* char *traps[NSIG] */ |
992 | # define G_traps G.traps | 996 | # define G_traps G.traps |
993 | #else | 997 | #else |
@@ -2097,25 +2101,35 @@ static int check_and_run_traps(void) | |||
2097 | } while (sig < NSIG); | 2101 | } while (sig < NSIG); |
2098 | break; | 2102 | break; |
2099 | got_sig: | 2103 | got_sig: |
2104 | #if ENABLE_HUSH_TRAP | ||
2100 | if (G_traps && G_traps[sig]) { | 2105 | if (G_traps && G_traps[sig]) { |
2101 | debug_printf_exec("%s: sig:%d handler:'%s'\n", __func__, sig, G.traps[sig]); | 2106 | debug_printf_exec("%s: sig:%d handler:'%s'\n", __func__, sig, G.traps[sig]); |
2102 | if (G_traps[sig][0]) { | 2107 | if (G_traps[sig][0]) { |
2103 | /* We have user-defined handler */ | 2108 | /* We have user-defined handler */ |
2104 | smalluint save_rcode; | 2109 | smalluint save_rcode; |
2110 | int save_pre; | ||
2105 | char *argv[3]; | 2111 | char *argv[3]; |
2106 | /* argv[0] is unused */ | 2112 | /* argv[0] is unused */ |
2107 | argv[1] = xstrdup(G_traps[sig]); | 2113 | argv[1] = xstrdup(G_traps[sig]); |
2108 | /* why strdup? trap can modify itself: trap 'trap "echo oops" INT' INT */ | 2114 | /* why strdup? trap can modify itself: trap 'trap "echo oops" INT' INT */ |
2109 | argv[2] = NULL; | 2115 | argv[2] = NULL; |
2110 | save_rcode = G.last_exitcode; | 2116 | save_pre = G.pre_trap_exitcode; |
2117 | G.pre_trap_exitcode = save_rcode = G.last_exitcode; | ||
2111 | builtin_eval(argv); | 2118 | builtin_eval(argv); |
2112 | free(argv[1]); | 2119 | free(argv[1]); |
2113 | //FIXME: shouldn't it be set to 128 + sig instead? | 2120 | G.pre_trap_exitcode = save_pre; |
2114 | G.last_exitcode = save_rcode; | 2121 | G.last_exitcode = save_rcode; |
2122 | # if ENABLE_HUSH_FUNCTIONS | ||
2123 | if (G.return_exitcode >= 0) { | ||
2124 | debug_printf_exec("trap exitcode:%d\n", G.return_exitcode); | ||
2125 | G.last_exitcode = G.return_exitcode; | ||
2126 | } | ||
2127 | # endif | ||
2115 | last_sig = sig; | 2128 | last_sig = sig; |
2116 | } /* else: "" trap, ignoring signal */ | 2129 | } /* else: "" trap, ignoring signal */ |
2117 | continue; | 2130 | continue; |
2118 | } | 2131 | } |
2132 | #endif | ||
2119 | /* not a trap: special action */ | 2133 | /* not a trap: special action */ |
2120 | switch (sig) { | 2134 | switch (sig) { |
2121 | case SIGINT: | 2135 | case SIGINT: |
@@ -8127,6 +8141,10 @@ static int run_function(const struct function *funcp, char **argv) | |||
8127 | IF_HUSH_LOCAL(leave_var_nest_level();) | 8141 | IF_HUSH_LOCAL(leave_var_nest_level();) |
8128 | 8142 | ||
8129 | G_flag_return_in_progress = sv_flg; | 8143 | G_flag_return_in_progress = sv_flg; |
8144 | # if ENABLE_HUSH_TRAP | ||
8145 | debug_printf_exec("G.return_exitcode=-1\n"); | ||
8146 | G.return_exitcode = -1; /* invalidate stashed return value */ | ||
8147 | # endif | ||
8130 | 8148 | ||
8131 | restore_G_args(&sv, argv); | 8149 | restore_G_args(&sv, argv); |
8132 | 8150 | ||
@@ -9628,6 +9646,9 @@ static int run_list(struct pipe *pi) | |||
9628 | debug_printf_exec(": builtin/func exitcode %d\n", rcode); | 9646 | debug_printf_exec(": builtin/func exitcode %d\n", rcode); |
9629 | G.last_exitcode = rcode; | 9647 | G.last_exitcode = rcode; |
9630 | check_and_run_traps(); | 9648 | check_and_run_traps(); |
9649 | #if ENABLE_HUSH_TRAP && ENABLE_HUSH_FUNCTIONS | ||
9650 | rcode = G.last_exitcode; /* "return" in trap can change it, read back */ | ||
9651 | #endif | ||
9631 | #if ENABLE_HUSH_LOOPS | 9652 | #if ENABLE_HUSH_LOOPS |
9632 | /* Was it "break" or "continue"? */ | 9653 | /* Was it "break" or "continue"? */ |
9633 | if (G.flag_break_continue) { | 9654 | if (G.flag_break_continue) { |
@@ -9684,6 +9705,9 @@ static int run_list(struct pipe *pi) | |||
9684 | check_traps: | 9705 | check_traps: |
9685 | G.last_exitcode = rcode; | 9706 | G.last_exitcode = rcode; |
9686 | check_and_run_traps(); | 9707 | check_and_run_traps(); |
9708 | #if ENABLE_HUSH_TRAP && ENABLE_HUSH_FUNCTIONS | ||
9709 | rcode = G.last_exitcode; /* "return" in trap can change it, read back */ | ||
9710 | #endif | ||
9687 | } | 9711 | } |
9688 | 9712 | ||
9689 | /* Handle "set -e" */ | 9713 | /* Handle "set -e" */ |
@@ -9907,6 +9931,12 @@ int hush_main(int argc, char **argv) | |||
9907 | INIT_G(); | 9931 | INIT_G(); |
9908 | if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ | 9932 | if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ |
9909 | G.last_exitcode = EXIT_SUCCESS; | 9933 | G.last_exitcode = EXIT_SUCCESS; |
9934 | #if ENABLE_HUSH_TRAP | ||
9935 | # if ENABLE_HUSH_FUNCTIONS | ||
9936 | G.return_exitcode = -1; | ||
9937 | # endif | ||
9938 | G.pre_trap_exitcode = -1; | ||
9939 | #endif | ||
9910 | 9940 | ||
9911 | #if ENABLE_HUSH_FAST | 9941 | #if ENABLE_HUSH_FAST |
9912 | G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ | 9942 | G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ |
@@ -10552,8 +10582,13 @@ static int FAST_FUNC builtin_exit(char **argv) | |||
10552 | 10582 | ||
10553 | /* note: EXIT trap is run by hush_exit */ | 10583 | /* note: EXIT trap is run by hush_exit */ |
10554 | argv = skip_dash_dash(argv); | 10584 | argv = skip_dash_dash(argv); |
10555 | if (argv[0] == NULL) | 10585 | if (argv[0] == NULL) { |
10586 | #if ENABLE_HUSH_TRAP | ||
10587 | if (G.pre_trap_exitcode >= 0) /* "exit" in trap uses $? from before the trap */ | ||
10588 | hush_exit(G.pre_trap_exitcode); | ||
10589 | #endif | ||
10556 | hush_exit(G.last_exitcode); | 10590 | hush_exit(G.last_exitcode); |
10591 | } | ||
10557 | /* mimic bash: exit 123abc == exit 255 + error msg */ | 10592 | /* mimic bash: exit 123abc == exit 255 + error msg */ |
10558 | xfunc_error_retval = 255; | 10593 | xfunc_error_retval = 255; |
10559 | /* bash: exit -2 == exit 254, no error msg */ | 10594 | /* bash: exit -2 == exit 254, no error msg */ |
@@ -11745,6 +11780,12 @@ static int FAST_FUNC builtin_return(char **argv) | |||
11745 | * 255 <== we also do this | 11780 | * 255 <== we also do this |
11746 | */ | 11781 | */ |
11747 | rc = parse_numeric_argv1(argv, G.last_exitcode, 0); | 11782 | rc = parse_numeric_argv1(argv, G.last_exitcode, 0); |
11783 | # if ENABLE_HUSH_TRAP | ||
11784 | if (argv[1]) { /* "return ARG" inside a running trap sets $? */ | ||
11785 | debug_printf_exec("G.return_exitcode=%d\n", rc); | ||
11786 | G.return_exitcode = rc; | ||
11787 | } | ||
11788 | # endif | ||
11748 | return rc; | 11789 | return rc; |
11749 | } | 11790 | } |
11750 | #endif | 11791 | #endif |