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

Denys Vlasenko vda.linux at googlemail.com
Sun Feb 16 18:14:45 UTC 2020


commit: https://git.busybox.net/busybox/commit/?id=4ccddc8fb37b7f585c2d62f6e61ad17295399aff
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

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 at gondor.apana.org.au>

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 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(-)

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:$?


More information about the busybox-cvs mailing list