diff options
author | Roberto A. Foglietta <roberto.foglietta@gmail.com> | 2021-09-07 01:19:31 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2021-09-07 01:28:50 +0200 |
commit | e0bf3df0205d5ccef52df67b1760b8b54f15ec6e (patch) | |
tree | 3195ba74f0b9c3a93e36743a8693c8cd880f78af /shell | |
parent | 4b032a4d6c4a9e24e66c262d6350e6499d0facb3 (diff) | |
download | busybox-w32-e0bf3df0205d5ccef52df67b1760b8b54f15ec6e.tar.gz busybox-w32-e0bf3df0205d5ccef52df67b1760b8b54f15ec6e.tar.bz2 busybox-w32-e0bf3df0205d5ccef52df67b1760b8b54f15ec6e.zip |
ash: add bash-like ERR trap and set -E
While at it, stop incrementing LINENO inside traps
function old new delta
evaltree 567 762 +195
evalfun 268 348 +80
trapcmd 286 333 +47
dotrap 129 157 +28
exitshell 120 139 +19
readtoken1 3096 3110 +14
nlprompt 25 39 +14
nlnoprompt 19 33 +14
.rodata 104245 104255 +10
forkchild 610 617 +7
optletters_optnames 64 68 +4
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 11/0 up/down: 432/0) Total: 432 bytes
Signed-off-by: Roberto A. Foglietta <roberto.foglietta@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 86 |
1 files changed, 69 insertions, 17 deletions
diff --git a/shell/ash.c b/shell/ash.c index 53c140930..cfe0433a8 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -348,6 +348,7 @@ static const char *const optletters_optnames[] = { | |||
348 | "a" "allexport", | 348 | "a" "allexport", |
349 | "b" "notify", | 349 | "b" "notify", |
350 | "u" "nounset", | 350 | "u" "nounset", |
351 | "E" "errtrace", | ||
351 | "\0" "vi" | 352 | "\0" "vi" |
352 | #if BASH_PIPEFAIL | 353 | #if BASH_PIPEFAIL |
353 | ,"\0" "pipefail" | 354 | ,"\0" "pipefail" |
@@ -442,15 +443,16 @@ struct globals_misc { | |||
442 | #define aflag optlist[11] | 443 | #define aflag optlist[11] |
443 | #define bflag optlist[12] | 444 | #define bflag optlist[12] |
444 | #define uflag optlist[13] | 445 | #define uflag optlist[13] |
445 | #define viflag optlist[14] | 446 | #define Eflag optlist[14] |
447 | #define viflag optlist[15] | ||
446 | #if BASH_PIPEFAIL | 448 | #if BASH_PIPEFAIL |
447 | # define pipefail optlist[15] | 449 | # define pipefail optlist[16] |
448 | #else | 450 | #else |
449 | # define pipefail 0 | 451 | # define pipefail 0 |
450 | #endif | 452 | #endif |
451 | #if DEBUG | 453 | #if DEBUG |
452 | # define nolog optlist[15 + BASH_PIPEFAIL] | 454 | # define nolog optlist[16 + BASH_PIPEFAIL] |
453 | # define debug optlist[16 + BASH_PIPEFAIL] | 455 | # define debug optlist[17 + BASH_PIPEFAIL] |
454 | #endif | 456 | #endif |
455 | 457 | ||
456 | /* trap handler commands */ | 458 | /* trap handler commands */ |
@@ -468,7 +470,11 @@ struct globals_misc { | |||
468 | /* indicates specified signal received */ | 470 | /* indicates specified signal received */ |
469 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ | 471 | uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */ |
470 | uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ | 472 | uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */ |
471 | char *trap[NSIG]; | 473 | char *trap[NSIG + 1]; |
474 | /* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */ | ||
475 | #define NTRAP_ERR NSIG | ||
476 | #define NTRAP_LAST NSIG | ||
477 | |||
472 | char **trap_ptr; /* used only by "trap hack" */ | 478 | char **trap_ptr; /* used only by "trap hack" */ |
473 | 479 | ||
474 | /* Rarely referenced stuff */ | 480 | /* Rarely referenced stuff */ |
@@ -2166,6 +2172,8 @@ struct globals_var { | |||
2166 | struct var varinit[ARRAY_SIZE(varinit_data)]; | 2172 | struct var varinit[ARRAY_SIZE(varinit_data)]; |
2167 | int lineno; | 2173 | int lineno; |
2168 | char linenovar[sizeof("LINENO=") + sizeof(int)*3]; | 2174 | char linenovar[sizeof("LINENO=") + sizeof(int)*3]; |
2175 | unsigned trap_depth; | ||
2176 | bool in_trap_ERR; /* ERR cannot recurse, no need to be a counter */ | ||
2169 | }; | 2177 | }; |
2170 | extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var; | 2178 | extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var; |
2171 | #define G_var (*ash_ptr_to_globals_var) | 2179 | #define G_var (*ash_ptr_to_globals_var) |
@@ -2176,6 +2184,8 @@ extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var; | |||
2176 | #define varinit (G_var.varinit ) | 2184 | #define varinit (G_var.varinit ) |
2177 | #define lineno (G_var.lineno ) | 2185 | #define lineno (G_var.lineno ) |
2178 | #define linenovar (G_var.linenovar ) | 2186 | #define linenovar (G_var.linenovar ) |
2187 | #define trap_depth (G_var.trap_depth ) | ||
2188 | #define in_trap_ERR (G_var.in_trap_ERR ) | ||
2179 | #define vifs varinit[0] | 2189 | #define vifs varinit[0] |
2180 | #if ENABLE_ASH_MAIL | 2190 | #if ENABLE_ASH_MAIL |
2181 | # define vmail varinit[1] | 2191 | # define vmail varinit[1] |
@@ -5163,13 +5173,13 @@ clear_traps(void) | |||
5163 | char **tp; | 5173 | char **tp; |
5164 | 5174 | ||
5165 | INT_OFF; | 5175 | INT_OFF; |
5166 | for (tp = trap; tp < &trap[NSIG]; tp++) { | 5176 | for (tp = trap; tp <= &trap[NTRAP_LAST]; tp++) { |
5167 | if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */ | 5177 | if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */ |
5168 | if (trap_ptr == trap) | 5178 | if (trap_ptr == trap) |
5169 | free(*tp); | 5179 | free(*tp); |
5170 | /* else: it "belongs" to trap_ptr vector, don't free */ | 5180 | /* else: it "belongs" to trap_ptr vector, don't free */ |
5171 | *tp = NULL; | 5181 | *tp = NULL; |
5172 | if ((tp - trap) != 0) | 5182 | if ((tp - trap) != 0 && (tp - trap) < NSIG) |
5173 | setsignal(tp - trap); | 5183 | setsignal(tp - trap); |
5174 | } | 5184 | } |
5175 | } | 5185 | } |
@@ -9253,7 +9263,9 @@ dotrap(void) | |||
9253 | *g = 0; | 9263 | *g = 0; |
9254 | if (!p) | 9264 | if (!p) |
9255 | continue; | 9265 | continue; |
9266 | trap_depth++; | ||
9256 | evalstring(p, 0); | 9267 | evalstring(p, 0); |
9268 | trap_depth--; | ||
9257 | if (evalskip != SKIPFUNC) | 9269 | if (evalskip != SKIPFUNC) |
9258 | exitstatus = status; | 9270 | exitstatus = status; |
9259 | } | 9271 | } |
@@ -9321,7 +9333,7 @@ evaltree(union node *n, int flags) | |||
9321 | case NCMD: | 9333 | case NCMD: |
9322 | evalfn = evalcommand; | 9334 | evalfn = evalcommand; |
9323 | checkexit: | 9335 | checkexit: |
9324 | if (eflag && !(flags & EV_TESTED)) | 9336 | if (!(flags & EV_TESTED)) |
9325 | checkexit = ~0; | 9337 | checkexit = ~0; |
9326 | goto calleval; | 9338 | goto calleval; |
9327 | case NFOR: | 9339 | case NFOR: |
@@ -9395,8 +9407,32 @@ evaltree(union node *n, int flags) | |||
9395 | */ | 9407 | */ |
9396 | dotrap(); | 9408 | dotrap(); |
9397 | 9409 | ||
9398 | if (checkexit & status) | 9410 | if (checkexit & status) { |
9399 | raise_exception(EXEND); | 9411 | if (trap[NTRAP_ERR] && !in_trap_ERR) { |
9412 | int err; | ||
9413 | struct jmploc *volatile savehandler = exception_handler; | ||
9414 | struct jmploc jmploc; | ||
9415 | |||
9416 | in_trap_ERR = 1; | ||
9417 | trap_depth++; | ||
9418 | err = setjmp(jmploc.loc); | ||
9419 | if (!err) { | ||
9420 | exception_handler = &jmploc; | ||
9421 | savestatus = exitstatus; | ||
9422 | evalstring(trap[NTRAP_ERR], 0); | ||
9423 | } | ||
9424 | trap_depth--; | ||
9425 | in_trap_ERR = 0; | ||
9426 | |||
9427 | exception_handler = savehandler; | ||
9428 | if (err && exception_type != EXERROR) | ||
9429 | longjmp(exception_handler->loc, 1); | ||
9430 | |||
9431 | exitstatus = savestatus; | ||
9432 | } | ||
9433 | if (eflag) | ||
9434 | raise_exception(EXEND); | ||
9435 | } | ||
9400 | if (flags & EV_EXIT) | 9436 | if (flags & EV_EXIT) |
9401 | raise_exception(EXEND); | 9437 | raise_exception(EXEND); |
9402 | 9438 | ||
@@ -9861,7 +9897,12 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | |||
9861 | struct jmploc jmploc; | 9897 | struct jmploc jmploc; |
9862 | int e; | 9898 | int e; |
9863 | int savefuncline; | 9899 | int savefuncline; |
9900 | char *savetrap = NULL; | ||
9864 | 9901 | ||
9902 | if (!Eflag) { | ||
9903 | savetrap = trap[NTRAP_ERR]; | ||
9904 | trap[NTRAP_ERR] = NULL; | ||
9905 | } | ||
9865 | saveparam = shellparam; | 9906 | saveparam = shellparam; |
9866 | savefuncline = funcline; | 9907 | savefuncline = funcline; |
9867 | savehandler = exception_handler; | 9908 | savehandler = exception_handler; |
@@ -9884,6 +9925,12 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | |||
9884 | evaltree(func->n.ndefun.body, flags & EV_TESTED); | 9925 | evaltree(func->n.ndefun.body, flags & EV_TESTED); |
9885 | funcdone: | 9926 | funcdone: |
9886 | INT_OFF; | 9927 | INT_OFF; |
9928 | if (savetrap) { | ||
9929 | if (!trap[NTRAP_ERR]) | ||
9930 | trap[NTRAP_ERR] = savetrap; | ||
9931 | else | ||
9932 | free(savetrap); | ||
9933 | } | ||
9887 | funcline = savefuncline; | 9934 | funcline = savefuncline; |
9888 | freefunc(func); | 9935 | freefunc(func); |
9889 | freeparam(&shellparam); | 9936 | freeparam(&shellparam); |
@@ -10912,13 +10959,15 @@ preadbuffer(void) | |||
10912 | static void | 10959 | static void |
10913 | nlprompt(void) | 10960 | nlprompt(void) |
10914 | { | 10961 | { |
10915 | g_parsefile->linno++; | 10962 | if (trap_depth == 0) |
10963 | g_parsefile->linno++; | ||
10916 | setprompt_if(doprompt, 2); | 10964 | setprompt_if(doprompt, 2); |
10917 | } | 10965 | } |
10918 | static void | 10966 | static void |
10919 | nlnoprompt(void) | 10967 | nlnoprompt(void) |
10920 | { | 10968 | { |
10921 | g_parsefile->linno++; | 10969 | if (trap_depth == 0) |
10970 | g_parsefile->linno++; | ||
10922 | needprompt = doprompt; | 10971 | needprompt = doprompt; |
10923 | } | 10972 | } |
10924 | 10973 | ||
@@ -12620,7 +12669,8 @@ checkend: { | |||
12620 | 12669 | ||
12621 | if (c == '\n' || c == PEOF) { | 12670 | if (c == '\n' || c == PEOF) { |
12622 | c = PEOF; | 12671 | c = PEOF; |
12623 | g_parsefile->linno++; | 12672 | if (trap_depth == 0) |
12673 | g_parsefile->linno++; | ||
12624 | needprompt = doprompt; | 12674 | needprompt = doprompt; |
12625 | } else { | 12675 | } else { |
12626 | int len_here; | 12676 | int len_here; |
@@ -13869,7 +13919,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
13869 | nextopt(nullstr); | 13919 | nextopt(nullstr); |
13870 | ap = argptr; | 13920 | ap = argptr; |
13871 | if (!*ap) { | 13921 | if (!*ap) { |
13872 | for (signo = 0; signo < NSIG; signo++) { | 13922 | for (signo = 0; signo <= NTRAP_LAST; signo++) { |
13873 | char *tr = trap_ptr[signo]; | 13923 | char *tr = trap_ptr[signo]; |
13874 | if (tr) { | 13924 | if (tr) { |
13875 | /* note: bash adds "SIG", but only if invoked | 13925 | /* note: bash adds "SIG", but only if invoked |
@@ -13878,7 +13928,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
13878 | * We are printing short names: */ | 13928 | * We are printing short names: */ |
13879 | out1fmt("trap -- %s %s\n", | 13929 | out1fmt("trap -- %s %s\n", |
13880 | single_quote(tr), | 13930 | single_quote(tr), |
13881 | get_signame(signo)); | 13931 | (signo == NTRAP_ERR) ? "ERR" : get_signame(signo)); |
13882 | /* trap_ptr != trap only if we are in special-cased `trap` code. | 13932 | /* trap_ptr != trap only if we are in special-cased `trap` code. |
13883 | * In this case, we will exit very soon, no need to free(). */ | 13933 | * In this case, we will exit very soon, no need to free(). */ |
13884 | /* if (trap_ptr != trap && tp[0]) */ | 13934 | /* if (trap_ptr != trap && tp[0]) */ |
@@ -13904,7 +13954,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
13904 | 13954 | ||
13905 | exitcode = 0; | 13955 | exitcode = 0; |
13906 | while (*ap) { | 13956 | while (*ap) { |
13907 | signo = get_signum(*ap); | 13957 | signo = strcmp(*ap, "ERR") == 0 ? NTRAP_ERR : get_signum(*ap); |
13908 | if (signo < 0) { | 13958 | if (signo < 0) { |
13909 | /* Mimic bash message exactly */ | 13959 | /* Mimic bash message exactly */ |
13910 | ash_msg("%s: invalid signal specification", *ap); | 13960 | ash_msg("%s: invalid signal specification", *ap); |
@@ -13923,7 +13973,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
13923 | } | 13973 | } |
13924 | free(trap[signo]); | 13974 | free(trap[signo]); |
13925 | trap[signo] = action; | 13975 | trap[signo] = action; |
13926 | if (signo != 0) | 13976 | if (signo != 0 && signo < NSIG) |
13927 | setsignal(signo); | 13977 | setsignal(signo); |
13928 | INT_ON; | 13978 | INT_ON; |
13929 | next: | 13979 | next: |
@@ -14348,7 +14398,9 @@ exitshell(void) | |||
14348 | if (p) { | 14398 | if (p) { |
14349 | trap[0] = NULL; | 14399 | trap[0] = NULL; |
14350 | evalskip = 0; | 14400 | evalskip = 0; |
14401 | trap_depth++; | ||
14351 | evalstring(p, 0); | 14402 | evalstring(p, 0); |
14403 | trap_depth--; | ||
14352 | evalskip = SKIPFUNCDEF; | 14404 | evalskip = SKIPFUNCDEF; |
14353 | /*free(p); - we'll exit soon */ | 14405 | /*free(p); - we'll exit soon */ |
14354 | } | 14406 | } |