ash: [BUILTIN] Exit without arguments in a trap should use status outside traps

Upstream commit:

    Date:   Mon Oct 6 10:39:47 2014 +0800
    [BUILTIN] Exit without arguments in a trap should use status outside traps

    POSIX now requires that exit without arguments in a trap should
    return the last command status prior to executing traps.  This
    patch implements this behaviour.

    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2020-02-14 17:27:18 +01:00
parent f7eea8c235
commit 4ccddc8fb3
3 changed files with 38 additions and 13 deletions

View File

@ -384,6 +384,7 @@ struct globals_misc {
uint8_t exitstatus; /* exit status of last command */ uint8_t exitstatus; /* exit status of last command */
uint8_t back_exitstatus;/* exit status of backquoted command */ uint8_t back_exitstatus;/* exit status of backquoted command */
smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
int savestatus; /* exit status of last command outside traps */
int rootpid; /* pid of main shell */ int rootpid; /* pid of main shell */
/* shell level: 0 for the main shell, 1 for its children, and so on */ /* shell level: 0 for the main shell, 1 for its children, and so on */
int shlvl; int shlvl;
@ -466,6 +467,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
#define exitstatus (G_misc.exitstatus ) #define exitstatus (G_misc.exitstatus )
#define back_exitstatus (G_misc.back_exitstatus ) #define back_exitstatus (G_misc.back_exitstatus )
#define job_warning (G_misc.job_warning) #define job_warning (G_misc.job_warning)
#define savestatus (G_misc.savestatus )
#define rootpid (G_misc.rootpid ) #define rootpid (G_misc.rootpid )
#define shlvl (G_misc.shlvl ) #define shlvl (G_misc.shlvl )
#define errlinno (G_misc.errlinno ) #define errlinno (G_misc.errlinno )
@ -491,6 +493,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
#define INIT_G_misc() do { \ #define INIT_G_misc() do { \
(*(struct globals_misc**)not_const_pp(&ash_ptr_to_globals_misc)) = xzalloc(sizeof(G_misc)); \ (*(struct globals_misc**)not_const_pp(&ash_ptr_to_globals_misc)) = xzalloc(sizeof(G_misc)); \
barrier(); \ barrier(); \
savestatus = -1; \
curdir = nullstr; \ curdir = nullstr; \
physdir = nullstr; \ physdir = nullstr; \
trap_ptr = trap; \ trap_ptr = trap; \
@ -9055,12 +9058,17 @@ dotrap(void)
{ {
uint8_t *g; uint8_t *g;
int sig; int sig;
uint8_t last_status; int status, last_status;
if (!pending_sig) if (!pending_sig)
return; return;
last_status = exitstatus; status = savestatus;
last_status = status;
if (status < 0) {
status = exitstatus;
savestatus = status;
}
pending_sig = 0; pending_sig = 0;
barrier(); barrier();
@ -9087,8 +9095,10 @@ dotrap(void)
if (!p) if (!p)
continue; continue;
evalstring(p, 0); evalstring(p, 0);
exitstatus = status;
} }
exitstatus = last_status;
savestatus = last_status;
TRACE(("dotrap returns\n")); TRACE(("dotrap returns\n"));
} }
@ -13416,8 +13426,15 @@ exitcmd(int argc UNUSED_PARAM, char **argv)
{ {
if (stoppedjobs()) if (stoppedjobs())
return 0; return 0;
if (argv[1])
exitstatus = number(argv[1]); if (argv[1]) {
int status = number(argv[1]);
exitstatus = status;
if (savestatus >= 0)
savestatus = status;
}
raise_exception(EXEXIT); raise_exception(EXEXIT);
/* NOTREACHED */ /* NOTREACHED */
} }
@ -14077,19 +14094,15 @@ exitshell(void)
{ {
struct jmploc loc; struct jmploc loc;
char *p; char *p;
int status;
#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
if (line_input_state) if (line_input_state)
save_history(line_input_state); save_history(line_input_state);
#endif #endif
status = exitstatus; savestatus = exitstatus;
TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus));
if (setjmp(loc.loc)) { if (setjmp(loc.loc))
if (exception_type == EXEXIT)
status = exitstatus;
goto out; goto out;
}
exception_handler = &loc; exception_handler = &loc;
p = trap[0]; p = trap[0];
if (p) { if (p) {
@ -14104,7 +14117,7 @@ exitshell(void)
*/ */
setjobctl(0); setjobctl(0);
flush_stdout_stderr(); flush_stdout_stderr();
_exit(status); _exit(savestatus);
/* NOTREACHED */ /* NOTREACHED */
} }
@ -14280,6 +14293,10 @@ reset(void)
/* from eval.c: */ /* from eval.c: */
evalskip = 0; evalskip = 0;
loopnest = 0; loopnest = 0;
if (savestatus >= 0) {
exitstatus = savestatus;
savestatus = -1;
}
/* from expand.c: */ /* from expand.c: */
ifsfree(); ifsfree();

View File

@ -0,0 +1,2 @@
Trapped
One:1

View File

@ -0,0 +1,6 @@
# "exit" in trap should not use last command's exitcode,
# but exitcode on entering the trap.
(trap "echo Trapped; exit" EXIT
(exit 1)
)
echo One:$?