From 4ccddc8fb37b7f585c2d62f6e61ad17295399aff Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 14 Feb 2020 17:27:18 +0100 Subject: 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 Signed-off-by: Denys Vlasenko --- shell/ash.c | 43 +++++++++++++++++++--------- shell/ash_test/ash-misc/exitcode_trap1.right | 2 ++ shell/ash_test/ash-misc/exitcode_trap1.tests | 6 ++++ 3 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 shell/ash_test/ash-misc/exitcode_trap1.right create mode 100755 shell/ash_test/ash-misc/exitcode_trap1.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index a300061a2..270a338d9 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -384,6 +384,7 @@ struct globals_misc { uint8_t exitstatus; /* exit status of last 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). */ + int savestatus; /* exit status of last command outside traps */ int rootpid; /* pid of main shell */ /* shell level: 0 for the main shell, 1 for its children, and so on */ int shlvl; @@ -466,6 +467,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; #define exitstatus (G_misc.exitstatus ) #define back_exitstatus (G_misc.back_exitstatus ) #define job_warning (G_misc.job_warning) +#define savestatus (G_misc.savestatus ) #define rootpid (G_misc.rootpid ) #define shlvl (G_misc.shlvl ) #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 { \ (*(struct globals_misc**)not_const_pp(&ash_ptr_to_globals_misc)) = xzalloc(sizeof(G_misc)); \ barrier(); \ + savestatus = -1; \ curdir = nullstr; \ physdir = nullstr; \ trap_ptr = trap; \ @@ -9055,12 +9058,17 @@ dotrap(void) { uint8_t *g; int sig; - uint8_t last_status; + int status, last_status; if (!pending_sig) return; - last_status = exitstatus; + status = savestatus; + last_status = status; + if (status < 0) { + status = exitstatus; + savestatus = status; + } pending_sig = 0; barrier(); @@ -9087,8 +9095,10 @@ dotrap(void) if (!p) continue; evalstring(p, 0); + exitstatus = status; } - exitstatus = last_status; + + savestatus = last_status; TRACE(("dotrap returns\n")); } @@ -13416,8 +13426,15 @@ exitcmd(int argc UNUSED_PARAM, char **argv) { if (stoppedjobs()) 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); /* NOTREACHED */ } @@ -14077,19 +14094,15 @@ exitshell(void) { struct jmploc loc; char *p; - int status; #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT if (line_input_state) save_history(line_input_state); #endif - status = exitstatus; - TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); - if (setjmp(loc.loc)) { - if (exception_type == EXEXIT) - status = exitstatus; + savestatus = exitstatus; + TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus)); + if (setjmp(loc.loc)) goto out; - } exception_handler = &loc; p = trap[0]; if (p) { @@ -14104,7 +14117,7 @@ exitshell(void) */ setjobctl(0); flush_stdout_stderr(); - _exit(status); + _exit(savestatus); /* NOTREACHED */ } @@ -14280,6 +14293,10 @@ reset(void) /* from eval.c: */ evalskip = 0; loopnest = 0; + if (savestatus >= 0) { + exitstatus = savestatus; + savestatus = -1; + } /* from expand.c: */ ifsfree(); diff --git a/shell/ash_test/ash-misc/exitcode_trap1.right b/shell/ash_test/ash-misc/exitcode_trap1.right new file mode 100644 index 000000000..5f76f68da --- /dev/null +++ b/shell/ash_test/ash-misc/exitcode_trap1.right @@ -0,0 +1,2 @@ +Trapped +One:1 diff --git a/shell/ash_test/ash-misc/exitcode_trap1.tests b/shell/ash_test/ash-misc/exitcode_trap1.tests new file mode 100755 index 000000000..c35b6b391 --- /dev/null +++ b/shell/ash_test/ash-misc/exitcode_trap1.tests @@ -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:$? -- cgit v1.2.3