aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorRoberto A. Foglietta <roberto.foglietta@gmail.com>2021-09-07 01:19:31 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2021-09-07 01:28:50 +0200
commite0bf3df0205d5ccef52df67b1760b8b54f15ec6e (patch)
tree3195ba74f0b9c3a93e36743a8693c8cd880f78af /shell
parent4b032a4d6c4a9e24e66c262d6350e6499d0facb3 (diff)
downloadbusybox-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.c86
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};
2170extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var; 2178extern 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)
10912static void 10959static void
10913nlprompt(void) 10960nlprompt(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}
10918static void 10966static void
10919nlnoprompt(void) 10967nlnoprompt(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 }