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>
This commit is contained in:
parent
4b032a4d6c
commit
e0bf3df020
78
shell/ash.c
78
shell/ash.c
@ -348,6 +348,7 @@ static const char *const optletters_optnames[] = {
|
|||||||
"a" "allexport",
|
"a" "allexport",
|
||||||
"b" "notify",
|
"b" "notify",
|
||||||
"u" "nounset",
|
"u" "nounset",
|
||||||
|
"E" "errtrace",
|
||||||
"\0" "vi"
|
"\0" "vi"
|
||||||
#if BASH_PIPEFAIL
|
#if BASH_PIPEFAIL
|
||||||
,"\0" "pipefail"
|
,"\0" "pipefail"
|
||||||
@ -442,15 +443,16 @@ struct globals_misc {
|
|||||||
#define aflag optlist[11]
|
#define aflag optlist[11]
|
||||||
#define bflag optlist[12]
|
#define bflag optlist[12]
|
||||||
#define uflag optlist[13]
|
#define uflag optlist[13]
|
||||||
#define viflag optlist[14]
|
#define Eflag optlist[14]
|
||||||
|
#define viflag optlist[15]
|
||||||
#if BASH_PIPEFAIL
|
#if BASH_PIPEFAIL
|
||||||
# define pipefail optlist[15]
|
# define pipefail optlist[16]
|
||||||
#else
|
#else
|
||||||
# define pipefail 0
|
# define pipefail 0
|
||||||
#endif
|
#endif
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
# define nolog optlist[15 + BASH_PIPEFAIL]
|
# define nolog optlist[16 + BASH_PIPEFAIL]
|
||||||
# define debug optlist[16 + BASH_PIPEFAIL]
|
# define debug optlist[17 + BASH_PIPEFAIL]
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* trap handler commands */
|
/* trap handler commands */
|
||||||
@ -468,7 +470,11 @@ struct globals_misc {
|
|||||||
/* indicates specified signal received */
|
/* indicates specified signal received */
|
||||||
uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
|
uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
|
||||||
uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
|
uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
|
||||||
char *trap[NSIG];
|
char *trap[NSIG + 1];
|
||||||
|
/* trap[0] is EXIT trap, trap[NTRAP_ERR] is ERR trap, other trap[i] are signal traps */
|
||||||
|
#define NTRAP_ERR NSIG
|
||||||
|
#define NTRAP_LAST NSIG
|
||||||
|
|
||||||
char **trap_ptr; /* used only by "trap hack" */
|
char **trap_ptr; /* used only by "trap hack" */
|
||||||
|
|
||||||
/* Rarely referenced stuff */
|
/* Rarely referenced stuff */
|
||||||
@ -2166,6 +2172,8 @@ struct globals_var {
|
|||||||
struct var varinit[ARRAY_SIZE(varinit_data)];
|
struct var varinit[ARRAY_SIZE(varinit_data)];
|
||||||
int lineno;
|
int lineno;
|
||||||
char linenovar[sizeof("LINENO=") + sizeof(int)*3];
|
char linenovar[sizeof("LINENO=") + sizeof(int)*3];
|
||||||
|
unsigned trap_depth;
|
||||||
|
bool in_trap_ERR; /* ERR cannot recurse, no need to be a counter */
|
||||||
};
|
};
|
||||||
extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
|
extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
|
||||||
#define G_var (*ash_ptr_to_globals_var)
|
#define G_var (*ash_ptr_to_globals_var)
|
||||||
@ -2176,6 +2184,8 @@ extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
|
|||||||
#define varinit (G_var.varinit )
|
#define varinit (G_var.varinit )
|
||||||
#define lineno (G_var.lineno )
|
#define lineno (G_var.lineno )
|
||||||
#define linenovar (G_var.linenovar )
|
#define linenovar (G_var.linenovar )
|
||||||
|
#define trap_depth (G_var.trap_depth )
|
||||||
|
#define in_trap_ERR (G_var.in_trap_ERR )
|
||||||
#define vifs varinit[0]
|
#define vifs varinit[0]
|
||||||
#if ENABLE_ASH_MAIL
|
#if ENABLE_ASH_MAIL
|
||||||
# define vmail varinit[1]
|
# define vmail varinit[1]
|
||||||
@ -5163,13 +5173,13 @@ clear_traps(void)
|
|||||||
char **tp;
|
char **tp;
|
||||||
|
|
||||||
INT_OFF;
|
INT_OFF;
|
||||||
for (tp = trap; tp < &trap[NSIG]; tp++) {
|
for (tp = trap; tp <= &trap[NTRAP_LAST]; tp++) {
|
||||||
if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
|
if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
|
||||||
if (trap_ptr == trap)
|
if (trap_ptr == trap)
|
||||||
free(*tp);
|
free(*tp);
|
||||||
/* else: it "belongs" to trap_ptr vector, don't free */
|
/* else: it "belongs" to trap_ptr vector, don't free */
|
||||||
*tp = NULL;
|
*tp = NULL;
|
||||||
if ((tp - trap) != 0)
|
if ((tp - trap) != 0 && (tp - trap) < NSIG)
|
||||||
setsignal(tp - trap);
|
setsignal(tp - trap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9253,7 +9263,9 @@ dotrap(void)
|
|||||||
*g = 0;
|
*g = 0;
|
||||||
if (!p)
|
if (!p)
|
||||||
continue;
|
continue;
|
||||||
|
trap_depth++;
|
||||||
evalstring(p, 0);
|
evalstring(p, 0);
|
||||||
|
trap_depth--;
|
||||||
if (evalskip != SKIPFUNC)
|
if (evalskip != SKIPFUNC)
|
||||||
exitstatus = status;
|
exitstatus = status;
|
||||||
}
|
}
|
||||||
@ -9321,7 +9333,7 @@ evaltree(union node *n, int flags)
|
|||||||
case NCMD:
|
case NCMD:
|
||||||
evalfn = evalcommand;
|
evalfn = evalcommand;
|
||||||
checkexit:
|
checkexit:
|
||||||
if (eflag && !(flags & EV_TESTED))
|
if (!(flags & EV_TESTED))
|
||||||
checkexit = ~0;
|
checkexit = ~0;
|
||||||
goto calleval;
|
goto calleval;
|
||||||
case NFOR:
|
case NFOR:
|
||||||
@ -9395,8 +9407,32 @@ evaltree(union node *n, int flags)
|
|||||||
*/
|
*/
|
||||||
dotrap();
|
dotrap();
|
||||||
|
|
||||||
if (checkexit & status)
|
if (checkexit & status) {
|
||||||
|
if (trap[NTRAP_ERR] && !in_trap_ERR) {
|
||||||
|
int err;
|
||||||
|
struct jmploc *volatile savehandler = exception_handler;
|
||||||
|
struct jmploc jmploc;
|
||||||
|
|
||||||
|
in_trap_ERR = 1;
|
||||||
|
trap_depth++;
|
||||||
|
err = setjmp(jmploc.loc);
|
||||||
|
if (!err) {
|
||||||
|
exception_handler = &jmploc;
|
||||||
|
savestatus = exitstatus;
|
||||||
|
evalstring(trap[NTRAP_ERR], 0);
|
||||||
|
}
|
||||||
|
trap_depth--;
|
||||||
|
in_trap_ERR = 0;
|
||||||
|
|
||||||
|
exception_handler = savehandler;
|
||||||
|
if (err && exception_type != EXERROR)
|
||||||
|
longjmp(exception_handler->loc, 1);
|
||||||
|
|
||||||
|
exitstatus = savestatus;
|
||||||
|
}
|
||||||
|
if (eflag)
|
||||||
raise_exception(EXEND);
|
raise_exception(EXEND);
|
||||||
|
}
|
||||||
if (flags & EV_EXIT)
|
if (flags & EV_EXIT)
|
||||||
raise_exception(EXEND);
|
raise_exception(EXEND);
|
||||||
|
|
||||||
@ -9861,7 +9897,12 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
|
|||||||
struct jmploc jmploc;
|
struct jmploc jmploc;
|
||||||
int e;
|
int e;
|
||||||
int savefuncline;
|
int savefuncline;
|
||||||
|
char *savetrap = NULL;
|
||||||
|
|
||||||
|
if (!Eflag) {
|
||||||
|
savetrap = trap[NTRAP_ERR];
|
||||||
|
trap[NTRAP_ERR] = NULL;
|
||||||
|
}
|
||||||
saveparam = shellparam;
|
saveparam = shellparam;
|
||||||
savefuncline = funcline;
|
savefuncline = funcline;
|
||||||
savehandler = exception_handler;
|
savehandler = exception_handler;
|
||||||
@ -9884,6 +9925,12 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
|
|||||||
evaltree(func->n.ndefun.body, flags & EV_TESTED);
|
evaltree(func->n.ndefun.body, flags & EV_TESTED);
|
||||||
funcdone:
|
funcdone:
|
||||||
INT_OFF;
|
INT_OFF;
|
||||||
|
if (savetrap) {
|
||||||
|
if (!trap[NTRAP_ERR])
|
||||||
|
trap[NTRAP_ERR] = savetrap;
|
||||||
|
else
|
||||||
|
free(savetrap);
|
||||||
|
}
|
||||||
funcline = savefuncline;
|
funcline = savefuncline;
|
||||||
freefunc(func);
|
freefunc(func);
|
||||||
freeparam(&shellparam);
|
freeparam(&shellparam);
|
||||||
@ -10912,12 +10959,14 @@ preadbuffer(void)
|
|||||||
static void
|
static void
|
||||||
nlprompt(void)
|
nlprompt(void)
|
||||||
{
|
{
|
||||||
|
if (trap_depth == 0)
|
||||||
g_parsefile->linno++;
|
g_parsefile->linno++;
|
||||||
setprompt_if(doprompt, 2);
|
setprompt_if(doprompt, 2);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
nlnoprompt(void)
|
nlnoprompt(void)
|
||||||
{
|
{
|
||||||
|
if (trap_depth == 0)
|
||||||
g_parsefile->linno++;
|
g_parsefile->linno++;
|
||||||
needprompt = doprompt;
|
needprompt = doprompt;
|
||||||
}
|
}
|
||||||
@ -12620,6 +12669,7 @@ checkend: {
|
|||||||
|
|
||||||
if (c == '\n' || c == PEOF) {
|
if (c == '\n' || c == PEOF) {
|
||||||
c = PEOF;
|
c = PEOF;
|
||||||
|
if (trap_depth == 0)
|
||||||
g_parsefile->linno++;
|
g_parsefile->linno++;
|
||||||
needprompt = doprompt;
|
needprompt = doprompt;
|
||||||
} else {
|
} else {
|
||||||
@ -13869,7 +13919,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
|
|||||||
nextopt(nullstr);
|
nextopt(nullstr);
|
||||||
ap = argptr;
|
ap = argptr;
|
||||||
if (!*ap) {
|
if (!*ap) {
|
||||||
for (signo = 0; signo < NSIG; signo++) {
|
for (signo = 0; signo <= NTRAP_LAST; signo++) {
|
||||||
char *tr = trap_ptr[signo];
|
char *tr = trap_ptr[signo];
|
||||||
if (tr) {
|
if (tr) {
|
||||||
/* note: bash adds "SIG", but only if invoked
|
/* note: bash adds "SIG", but only if invoked
|
||||||
@ -13878,7 +13928,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
|
|||||||
* We are printing short names: */
|
* We are printing short names: */
|
||||||
out1fmt("trap -- %s %s\n",
|
out1fmt("trap -- %s %s\n",
|
||||||
single_quote(tr),
|
single_quote(tr),
|
||||||
get_signame(signo));
|
(signo == NTRAP_ERR) ? "ERR" : get_signame(signo));
|
||||||
/* trap_ptr != trap only if we are in special-cased `trap` code.
|
/* trap_ptr != trap only if we are in special-cased `trap` code.
|
||||||
* In this case, we will exit very soon, no need to free(). */
|
* In this case, we will exit very soon, no need to free(). */
|
||||||
/* if (trap_ptr != trap && tp[0]) */
|
/* if (trap_ptr != trap && tp[0]) */
|
||||||
@ -13904,7 +13954,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
|
|||||||
|
|
||||||
exitcode = 0;
|
exitcode = 0;
|
||||||
while (*ap) {
|
while (*ap) {
|
||||||
signo = get_signum(*ap);
|
signo = strcmp(*ap, "ERR") == 0 ? NTRAP_ERR : get_signum(*ap);
|
||||||
if (signo < 0) {
|
if (signo < 0) {
|
||||||
/* Mimic bash message exactly */
|
/* Mimic bash message exactly */
|
||||||
ash_msg("%s: invalid signal specification", *ap);
|
ash_msg("%s: invalid signal specification", *ap);
|
||||||
@ -13923,7 +13973,7 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
|
|||||||
}
|
}
|
||||||
free(trap[signo]);
|
free(trap[signo]);
|
||||||
trap[signo] = action;
|
trap[signo] = action;
|
||||||
if (signo != 0)
|
if (signo != 0 && signo < NSIG)
|
||||||
setsignal(signo);
|
setsignal(signo);
|
||||||
INT_ON;
|
INT_ON;
|
||||||
next:
|
next:
|
||||||
@ -14348,7 +14398,9 @@ exitshell(void)
|
|||||||
if (p) {
|
if (p) {
|
||||||
trap[0] = NULL;
|
trap[0] = NULL;
|
||||||
evalskip = 0;
|
evalskip = 0;
|
||||||
|
trap_depth++;
|
||||||
evalstring(p, 0);
|
evalstring(p, 0);
|
||||||
|
trap_depth--;
|
||||||
evalskip = SKIPFUNCDEF;
|
evalskip = SKIPFUNCDEF;
|
||||||
/*free(p); - we'll exit soon */
|
/*free(p); - we'll exit soon */
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user