hush: make "exit" in trap use pre-trap exitcode
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 21 Feb 2020 01:18:06 +0000 (02:18 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 21 Feb 2020 01:18:06 +0000 (02:18 +0100)
function                                             old     new   delta
check_and_run_traps                                  259     276     +17
builtin_exit                                          42      53     +11
hush_main                                           1086    1096     +10
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/0 up/down: 38/0)               Total: 38 bytes

Fixes exitcode_trap2.tests.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/hush.c

index 6172f228599b81585a860772106e072cf855df6e..b881b001abe3956eb8502cf1f28414af06044a3b 100644 (file)
@@ -988,6 +988,7 @@ struct globals {
 # define G_fatal_sig_mask 0
 #endif
 #if ENABLE_HUSH_TRAP
+       int pre_trap_exitcode;
 # if ENABLE_HUSH_FUNCTIONS
        int return_exitcode;
 # endif
@@ -2111,10 +2112,11 @@ static int check_and_run_traps(void)
                                argv[1] = xstrdup(G_traps[sig]);
                                /* why strdup? trap can modify itself: trap 'trap "echo oops" INT' INT */
                                argv[2] = NULL;
-                               save_rcode = G.last_exitcode;
+                               G.pre_trap_exitcode = save_rcode = G.last_exitcode;
                                builtin_eval(argv);
                                free(argv[1]);
                                G.last_exitcode = save_rcode;
+                               G.pre_trap_exitcode = -1;
 # if ENABLE_HUSH_FUNCTIONS
                                if (G.return_exitcode >= 0) {
                                        debug_printf_exec("trap exitcode:%d\n", G.return_exitcode);
@@ -9927,8 +9929,11 @@ int hush_main(int argc, char **argv)
        INIT_G();
        if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */
                G.last_exitcode = EXIT_SUCCESS;
-#if ENABLE_HUSH_TRAP && ENABLE_HUSH_FUNCTIONS
+#if ENABLE_HUSH_TRAP
+# if ENABLE_HUSH_FUNCTIONS
        G.return_exitcode = -1;
+# endif
+       G.pre_trap_exitcode = -1;
 #endif
 
 #if ENABLE_HUSH_FAST
@@ -10575,8 +10580,13 @@ static int FAST_FUNC builtin_exit(char **argv)
 
        /* note: EXIT trap is run by hush_exit */
        argv = skip_dash_dash(argv);
-       if (argv[0] == NULL)
+       if (argv[0] == NULL) {
+#if ENABLE_HUSH_TRAP
+               if (G.pre_trap_exitcode >= 0) /* "exit" in trap uses $? from before the trap */
+                       hush_exit(G.pre_trap_exitcode);
+#endif
                hush_exit(G.last_exitcode);
+       }
        /* mimic bash: exit 123abc == exit 255 + error msg */
        xfunc_error_retval = 255;
        /* bash: exit -2 == exit 254, no error msg */