diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2020-02-14 17:27:18 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2020-02-16 19:14:45 +0100 |
| commit | 4ccddc8fb37b7f585c2d62f6e61ad17295399aff (patch) | |
| tree | 5a7b60334c1be7f7d32ca7d589b4171fc1eea28a /shell | |
| parent | f7eea8c235dea6699a21c7b26c218e6c0dc1bf95 (diff) | |
| download | busybox-w32-4ccddc8fb37b7f585c2d62f6e61ad17295399aff.tar.gz busybox-w32-4ccddc8fb37b7f585c2d62f6e61ad17295399aff.tar.bz2 busybox-w32-4ccddc8fb37b7f585c2d62f6e61ad17295399aff.zip | |
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>
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/ash.c | 43 | ||||
| -rw-r--r-- | shell/ash_test/ash-misc/exitcode_trap1.right | 2 | ||||
| -rwxr-xr-x | 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 { | |||
| 384 | uint8_t exitstatus; /* exit status of last command */ | 384 | uint8_t exitstatus; /* exit status of last command */ |
| 385 | uint8_t back_exitstatus;/* exit status of backquoted command */ | 385 | uint8_t back_exitstatus;/* exit status of backquoted command */ |
| 386 | smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ | 386 | smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ |
| 387 | int savestatus; /* exit status of last command outside traps */ | ||
| 387 | int rootpid; /* pid of main shell */ | 388 | int rootpid; /* pid of main shell */ |
| 388 | /* shell level: 0 for the main shell, 1 for its children, and so on */ | 389 | /* shell level: 0 for the main shell, 1 for its children, and so on */ |
| 389 | int shlvl; | 390 | int shlvl; |
| @@ -466,6 +467,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
| 466 | #define exitstatus (G_misc.exitstatus ) | 467 | #define exitstatus (G_misc.exitstatus ) |
| 467 | #define back_exitstatus (G_misc.back_exitstatus ) | 468 | #define back_exitstatus (G_misc.back_exitstatus ) |
| 468 | #define job_warning (G_misc.job_warning) | 469 | #define job_warning (G_misc.job_warning) |
| 470 | #define savestatus (G_misc.savestatus ) | ||
| 469 | #define rootpid (G_misc.rootpid ) | 471 | #define rootpid (G_misc.rootpid ) |
| 470 | #define shlvl (G_misc.shlvl ) | 472 | #define shlvl (G_misc.shlvl ) |
| 471 | #define errlinno (G_misc.errlinno ) | 473 | #define errlinno (G_misc.errlinno ) |
| @@ -491,6 +493,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
| 491 | #define INIT_G_misc() do { \ | 493 | #define INIT_G_misc() do { \ |
| 492 | (*(struct globals_misc**)not_const_pp(&ash_ptr_to_globals_misc)) = xzalloc(sizeof(G_misc)); \ | 494 | (*(struct globals_misc**)not_const_pp(&ash_ptr_to_globals_misc)) = xzalloc(sizeof(G_misc)); \ |
| 493 | barrier(); \ | 495 | barrier(); \ |
| 496 | savestatus = -1; \ | ||
| 494 | curdir = nullstr; \ | 497 | curdir = nullstr; \ |
| 495 | physdir = nullstr; \ | 498 | physdir = nullstr; \ |
| 496 | trap_ptr = trap; \ | 499 | trap_ptr = trap; \ |
| @@ -9055,12 +9058,17 @@ dotrap(void) | |||
| 9055 | { | 9058 | { |
| 9056 | uint8_t *g; | 9059 | uint8_t *g; |
| 9057 | int sig; | 9060 | int sig; |
| 9058 | uint8_t last_status; | 9061 | int status, last_status; |
| 9059 | 9062 | ||
| 9060 | if (!pending_sig) | 9063 | if (!pending_sig) |
| 9061 | return; | 9064 | return; |
| 9062 | 9065 | ||
| 9063 | last_status = exitstatus; | 9066 | status = savestatus; |
| 9067 | last_status = status; | ||
| 9068 | if (status < 0) { | ||
| 9069 | status = exitstatus; | ||
| 9070 | savestatus = status; | ||
| 9071 | } | ||
| 9064 | pending_sig = 0; | 9072 | pending_sig = 0; |
| 9065 | barrier(); | 9073 | barrier(); |
| 9066 | 9074 | ||
| @@ -9087,8 +9095,10 @@ dotrap(void) | |||
| 9087 | if (!p) | 9095 | if (!p) |
| 9088 | continue; | 9096 | continue; |
| 9089 | evalstring(p, 0); | 9097 | evalstring(p, 0); |
| 9098 | exitstatus = status; | ||
| 9090 | } | 9099 | } |
| 9091 | exitstatus = last_status; | 9100 | |
| 9101 | savestatus = last_status; | ||
| 9092 | TRACE(("dotrap returns\n")); | 9102 | TRACE(("dotrap returns\n")); |
| 9093 | } | 9103 | } |
| 9094 | 9104 | ||
| @@ -13416,8 +13426,15 @@ exitcmd(int argc UNUSED_PARAM, char **argv) | |||
| 13416 | { | 13426 | { |
| 13417 | if (stoppedjobs()) | 13427 | if (stoppedjobs()) |
| 13418 | return 0; | 13428 | return 0; |
| 13419 | if (argv[1]) | 13429 | |
| 13420 | exitstatus = number(argv[1]); | 13430 | if (argv[1]) { |
| 13431 | int status = number(argv[1]); | ||
| 13432 | |||
| 13433 | exitstatus = status; | ||
| 13434 | if (savestatus >= 0) | ||
| 13435 | savestatus = status; | ||
| 13436 | } | ||
| 13437 | |||
| 13421 | raise_exception(EXEXIT); | 13438 | raise_exception(EXEXIT); |
| 13422 | /* NOTREACHED */ | 13439 | /* NOTREACHED */ |
| 13423 | } | 13440 | } |
| @@ -14077,19 +14094,15 @@ exitshell(void) | |||
| 14077 | { | 14094 | { |
| 14078 | struct jmploc loc; | 14095 | struct jmploc loc; |
| 14079 | char *p; | 14096 | char *p; |
| 14080 | int status; | ||
| 14081 | 14097 | ||
| 14082 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 14098 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
| 14083 | if (line_input_state) | 14099 | if (line_input_state) |
| 14084 | save_history(line_input_state); | 14100 | save_history(line_input_state); |
| 14085 | #endif | 14101 | #endif |
| 14086 | status = exitstatus; | 14102 | savestatus = exitstatus; |
| 14087 | TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); | 14103 | TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus)); |
| 14088 | if (setjmp(loc.loc)) { | 14104 | if (setjmp(loc.loc)) |
| 14089 | if (exception_type == EXEXIT) | ||
| 14090 | status = exitstatus; | ||
| 14091 | goto out; | 14105 | goto out; |
| 14092 | } | ||
| 14093 | exception_handler = &loc; | 14106 | exception_handler = &loc; |
| 14094 | p = trap[0]; | 14107 | p = trap[0]; |
| 14095 | if (p) { | 14108 | if (p) { |
| @@ -14104,7 +14117,7 @@ exitshell(void) | |||
| 14104 | */ | 14117 | */ |
| 14105 | setjobctl(0); | 14118 | setjobctl(0); |
| 14106 | flush_stdout_stderr(); | 14119 | flush_stdout_stderr(); |
| 14107 | _exit(status); | 14120 | _exit(savestatus); |
| 14108 | /* NOTREACHED */ | 14121 | /* NOTREACHED */ |
| 14109 | } | 14122 | } |
| 14110 | 14123 | ||
| @@ -14280,6 +14293,10 @@ reset(void) | |||
| 14280 | /* from eval.c: */ | 14293 | /* from eval.c: */ |
| 14281 | evalskip = 0; | 14294 | evalskip = 0; |
| 14282 | loopnest = 0; | 14295 | loopnest = 0; |
| 14296 | if (savestatus >= 0) { | ||
| 14297 | exitstatus = savestatus; | ||
| 14298 | savestatus = -1; | ||
| 14299 | } | ||
| 14283 | 14300 | ||
| 14284 | /* from expand.c: */ | 14301 | /* from expand.c: */ |
| 14285 | ifsfree(); | 14302 | 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 @@ | |||
| 1 | Trapped | ||
| 2 | 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 @@ | |||
| 1 | # "exit" in trap should not use last command's exitcode, | ||
| 2 | # but exitcode on entering the trap. | ||
| 3 | (trap "echo Trapped; exit" EXIT | ||
| 4 | (exit 1) | ||
| 5 | ) | ||
| 6 | echo One:$? | ||
