[prev in list] [next in list] [prev in thread] [next in thread]
List: busybox
Subject: [PATCH] shell script error management in ash (ready for integration)
From: "Roberto A. Foglietta" <roberto.foglietta () gmail ! com>
Date: 2021-08-30 6:55:13
Message-ID: CAJGKYO4_WTFqggGVb8ptLirjOHNT6DCfTHd3NS64pXR6dMRKZQ () mail ! gmail ! com
[Download RAW message or body]
[Attachment #2 (multipart/alternative)]
Hi Denis,
supported by the experience of Harald, I developed this patch far enough
to be ready for integration. These are the features that will add to
busybox ash:
- trap ERR and set -E added
- global FUNCNAME added
- LINENO became global
The patch is in attachment with its test suite. Both could be also
retrieved at this link
https://github.com/robang74/tinycore-editor/tree/main/busybox/patches
busybox-1.33.1-error-management-extension-for-ash-v019.patch
https://github.com/robang74/tinycore-editor/tree/main/busybox/tests
Best regards,
--
Roberto A. Foglietta
+39.349.33.30.697
[Attachment #5 (text/html)]
<div dir="ltr">Hi Denis,<div><br></div><div> supported by the experience of Harald, \
I developed this patch far enough to be ready for integration. These are the features \
that will add to busybox ash:</div><div><br></div><div> - trap ERR and set -E \
added</div><div> - global FUNCNAME added<br></div><div> - LINENO became \
global</div><div> </div><div> The patch is in attachment with its test suite. Both \
could be also retrieved at this link</div><div><br></div><div> <a \
href="https://github.com/robang74/tinycore-editor/tree/main/busybox/patches">https://github.com/robang74/tinycore-editor/tree/main/busybox/patches</a></div><div> \
busybox-1.33.1-error-management-extension-for-ash-v019.patch</div><div><br></div><div> \
<a href="https://github.com/robang74/tinycore-editor/tree/main/busybox/tests">https://github.com/robang74/tinycore-editor/tree/main/busybox/tests</a><br \
clear="all"><div><br></div><div> Best regards,</div>-- <br><div dir="ltr" \
class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><div><div \
dir="ltr"><div>Roberto A. \
Foglietta</div><div>+39.349.33.30.697</div></div></div></div></div></div></div>
["busybox-1.33.1-error-management-extension-for-ash-v019.patch" (application/octet-stream)]
--- src.0/shell/ash.c 2021-05-03 20:06:49.000000000 +0200
+++ src.1/shell/ash.c 2021-08-30 08:34:03.971466553 +0200
@@ -336,7 +336,8 @@ static const char *const optletters_optn
"a" "allexport",
"b" "notify",
"u" "nounset",
- "\0" "vi"
+ "\0" "vi",
+ "E" "errtrace"
#if BASH_PIPEFAIL
,"\0" "pipefail"
#endif
@@ -431,14 +432,15 @@ struct globals_misc {
#define bflag optlist[12]
#define uflag optlist[13]
#define viflag optlist[14]
+#define Eflag optlist[15]
#if BASH_PIPEFAIL
-# define pipefail optlist[15]
+# define pipefail optlist[16]
#else
# define pipefail 0
#endif
#if DEBUG
-# define nolog optlist[15 + BASH_PIPEFAIL]
-# define debug optlist[16 + BASH_PIPEFAIL]
+# define nolog optlist[16 + BASH_PIPEFAIL]
+# define debug optlist[17 + BASH_PIPEFAIL]
#endif
/* trap handler commands */
@@ -456,7 +458,7 @@ struct globals_misc {
/* indicates specified signal received */
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 \
*/
- char *trap[NSIG];
+ char *trap[NSIG + 1]; /* increased by 1: trap ERR handler */
char **trap_ptr; /* used only by "trap hack" */
/* Rarely referenced stuff */
@@ -2109,6 +2111,7 @@ static const struct {
{ VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
#endif
{ VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL },
+ { VSTRFIXED|VTEXTFIXED , NULL /* inited to funcnamevar */, NULL },
#if ENABLE_ASH_RANDOM_SUPPORT
{ VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
#endif
@@ -2135,6 +2138,9 @@ struct globals_var {
struct var varinit[ARRAY_SIZE(varinit_data)];
int lineno;
char linenovar[sizeof("LINENO=") + sizeof(int)*3];
+ char funcnamevar[sizeof("FUNCNAME=") + 256];
+ char *funcname;
+ bool doingtrap;
};
extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var;
#define G_var (*ash_ptr_to_globals_var)
@@ -2145,6 +2151,9 @@ extern struct globals_var *BB_GLOBAL_CON
#define varinit (G_var.varinit )
#define lineno (G_var.lineno )
#define linenovar (G_var.linenovar )
+#define funcnamevar (G_var.funcnamevar )
+#define funcname (G_var.funcname )
+#define doingtrap (G_var.doingtrap )
#define vifs varinit[0]
#if ENABLE_ASH_MAIL
# define vmail varinit[1]
@@ -2160,13 +2169,14 @@ extern struct globals_var *BB_GLOBAL_CON
#endif
#define VAR_OFFSET2 (VAR_OFFSET1 + ENABLE_ASH_GETOPTS)
#define vlineno varinit[VAR_OFFSET2 + 5]
+#define vfuncname varinit[VAR_OFFSET2 + 6]
#if ENABLE_ASH_RANDOM_SUPPORT
-# define vrandom varinit[VAR_OFFSET2 + 6]
+# define vrandom varinit[VAR_OFFSET2 + 7]
#endif
#define VAR_OFFSET3 (VAR_OFFSET2 + ENABLE_ASH_RANDOM_SUPPORT)
#if BASH_EPOCH_VARS
-# define vepochs varinit[VAR_OFFSET3 + 6]
-# define vepochr varinit[VAR_OFFSET3 + 7]
+# define vepochs varinit[VAR_OFFSET3 + 7]
+# define vepochr varinit[VAR_OFFSET3 + 8]
#endif
#define INIT_G_var() do { \
unsigned i; \
@@ -2177,8 +2187,13 @@ extern struct globals_var *BB_GLOBAL_CON
varinit[i].var_text = varinit_data[i].var_text; \
varinit[i].var_func = varinit_data[i].var_func; \
} \
+ lineno = 0; \
strcpy(linenovar, "LINENO="); \
vlineno.var_text = linenovar; \
+ strcpy(funcnamevar, "FUNCNAME="); \
+ vfuncname.var_text = funcnamevar; \
+ funcname = NULL; \
+ doingtrap = 0; \
} while (0)
/*
@@ -2316,8 +2331,12 @@ lookupvar(const char *name)
v->var_func(NULL);
#endif
if (!(v->flags & VUNSET)) {
- if (v == &vlineno && v->var_text == linenovar) {
+ if (v->var_text == linenovar) {
fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
+ } else
+ if (v->var_text == funcnamevar) {
+ fmtstr(funcnamevar+9, sizeof(funcnamevar)-9, "%s",
+ funcname ? funcname : "");
}
return var_end(v->var_text);
}
@@ -5114,13 +5133,13 @@ clear_traps(void)
char **tp;
INT_OFF;
- for (tp = trap; tp < &trap[NSIG]; tp++) {
+ for (tp = trap; tp < &trap[NSIG+1]; tp++) { /* increased by 1: trap ERR handler */
if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
if (trap_ptr == trap)
free(*tp);
/* else: it "belongs" to trap_ptr vector, don't free */
*tp = NULL;
- if ((tp - trap) != 0)
+ if ((tp - trap) != 0 && tp < &trap[NSIG])
setsignal(tp - trap);
}
}
@@ -9069,7 +9088,7 @@ defun(union node *func)
static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
static int skipcount; /* number of levels to skip */
static int loopnest; /* current loop nesting level */
-static int funcline; /* starting line number of current function, or 0 if \
not in a function */ +static int funcline = 0; /* starting line number of \
current function, or 0 if not in a function */
/* Forward decl way out to parsing code - dotrap needs it */
static int evalstring(char *s, int flags);
@@ -9091,6 +9110,7 @@ dotrap(void)
if (!pending_sig)
return;
+ doingtrap = 1;
status = savestatus;
last_status = status;
if (status < 0) {
@@ -9127,6 +9147,7 @@ dotrap(void)
exitstatus = status;
}
+ doingtrap = 0;
savestatus = last_status;
TRACE(("dotrap returns\n"));
}
@@ -9176,8 +9197,6 @@ evaltree(union node *n, int flags)
goto setstatus;
case NREDIR:
errlinno = lineno = n->nredir.linno;
- if (funcline)
- lineno -= funcline - 1;
expredir(n->nredir.redirect);
pushredir(n->nredir.redirect);
status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
@@ -9190,7 +9209,7 @@ evaltree(union node *n, int flags)
case NCMD:
evalfn = evalcommand;
checkexit:
- if (eflag && !(flags & EV_TESTED))
+ if (!(flags & EV_TESTED))
checkexit = ~0;
goto calleval;
case NFOR:
@@ -9264,10 +9283,43 @@ evaltree(union node *n, int flags)
*/
dotrap();
- if (checkexit & status)
- raise_exception(EXEND);
+ if (checkexit & status) {
+ if (trap[NSIG]) {
+ static bool recursive = 0, savetrap;
+ static int savelineno;
+ if (!recursive) {
+ int err;
+ struct jmploc *volatile savehandler = exception_handler;
+ struct jmploc jmploc;
+
+ err = setjmp(jmploc.loc);
+ if (!err) {
+ exception_handler = &jmploc;
+
+ savestatus = exitstatus;
+ savetrap = doingtrap;
+ savelineno = lineno;
+ doingtrap = 1;
+ recursive = 1;
+
+ evalstring(trap[NSIG], 0);
+ }
+
+ exception_handler = savehandler;
+ if (err && exception_type != EXERROR)
+ longjmp(exception_handler->loc, 1);
+
+ recursive = 0;
+ lineno = savelineno;
+ doingtrap = savetrap;
+ exitstatus = savestatus;
+ }
+ }
+ if (eflag)
+ exitshell();
+ }
if (flags & EV_EXIT)
- raise_exception(EXEND);
+ exitshell();
popstackmark(&smark);
TRACE(("leaving evaltree (no interrupts)\n"));
@@ -9333,8 +9385,6 @@ evalfor(union node *n, int flags)
int status = 0;
errlinno = lineno = n->ncase.linno;
- if (funcline)
- lineno -= funcline - 1;
arglist.list = NULL;
arglist.lastp = &arglist.list;
@@ -9365,8 +9415,6 @@ evalcase(union node *n, int flags)
int status = 0;
errlinno = lineno = n->ncase.linno;
- if (funcline)
- lineno -= funcline - 1;
arglist.list = NULL;
arglist.lastp = &arglist.list;
@@ -9400,8 +9448,6 @@ evalsubshell(union node *n, int flags)
int status;
errlinno = lineno = n->nredir.linno;
- if (funcline)
- lineno -= funcline - 1;
expredir(n->nredir.redirect);
if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
@@ -9729,10 +9775,18 @@ evalfun(struct funcnode *func, int argc,
struct jmploc *volatile savehandler;
struct jmploc jmploc;
int e;
+ int savelineno;
int savefuncline;
+ char *savefuncname, *savetrap = NULL;
+ if (!Eflag) {
+ savetrap = trap[NSIG];
+ trap[NSIG] = NULL;
+ }
+ savelineno = lineno;
saveparam = shellparam;
savefuncline = funcline;
+ savefuncname = funcname;
savehandler = exception_handler;
e = setjmp(jmploc.loc);
if (e) {
@@ -9742,6 +9796,7 @@ evalfun(struct funcnode *func, int argc,
exception_handler = &jmploc;
shellparam.malloced = 0;
func->count++;
+ funcname = strdup(func->n.ndefun.text);
funcline = func->n.ndefun.linno;
INT_ON;
shellparam.nparam = argc - 1;
@@ -9753,7 +9808,21 @@ evalfun(struct funcnode *func, int argc,
evaltree(func->n.ndefun.body, flags & EV_TESTED);
funcdone:
INT_OFF;
+ if ((exitstatus && eflag) || (e)) {
+ /* we are exiting within the function */
+ if (savefuncname)
+ free(savefuncname);
+ if (savetrap)
+ free(savetrap);
+ } else {
+ if (funcname)
+ free(funcname);
+ funcname = savefuncname;
+ if (!trap[NSIG])
+ trap[NSIG] = savetrap;
+ }
funcline = savefuncline;
+ lineno = savelineno;
freefunc(func);
freeparam(&shellparam);
shellparam = saveparam;
@@ -10142,8 +10211,6 @@ evalcommand(union node *cmd, int flags)
int vlocal;
errlinno = lineno = cmd->ncmd.linno;
- if (funcline)
- lineno -= funcline - 1;
/* First expand the arguments. */
TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
@@ -10396,6 +10463,7 @@ evalcommand(union node *cmd, int flags)
FORCE_INT_ON;
out:
+
if (cmd->ncmd.redirect)
popredir(/*drop:*/ cmd_is_exec);
unwindredir(redir_stop);
@@ -10774,13 +10842,15 @@ preadbuffer(void)
static void
nlprompt(void)
{
- g_parsefile->linno++;
+ if (!doingtrap)
+ g_parsefile->linno++;
setprompt_if(doprompt, 2);
}
static void
nlnoprompt(void)
{
- g_parsefile->linno++;
+ if (!doingtrap)
+ g_parsefile->linno++;
needprompt = doprompt;
}
@@ -11012,7 +11082,7 @@ setinputstring(char *string)
g_parsefile->next_to_pgetc = string;
g_parsefile->left_in_line = strlen(string);
g_parsefile->buf = NULL;
- g_parsefile->linno = 1;
+ g_parsefile->linno = lineno;
INT_ON;
}
@@ -12470,7 +12540,8 @@ checkend: {
if (c == '\n' || c == PEOF) {
c = PEOF;
- g_parsefile->linno++;
+ if (!doingtrap)
+ g_parsefile->linno++;
needprompt = doprompt;
} else {
int len_here;
@@ -13713,7 +13784,7 @@ trapcmd(int argc UNUSED_PARAM, char **ar
nextopt(nullstr);
ap = argptr;
if (!*ap) {
- for (signo = 0; signo < NSIG; signo++) {
+ for (signo = 0; signo < NSIG + 1; signo++) { /* increased by 1: trap ERR handler \
*/ char *tr = trap_ptr[signo];
if (tr) {
/* note: bash adds "SIG", but only if invoked
@@ -13722,7 +13793,7 @@ trapcmd(int argc UNUSED_PARAM, char **ar
* We are printing short names: */
out1fmt("trap -- %s %s\n",
single_quote(tr),
- get_signame(signo));
+ (signo == NSIG) ? "ERR" : get_signame(signo));
/* trap_ptr != trap only if we are in special-cased `trap` code.
* In this case, we will exit very soon, no need to free(). */
/* if (trap_ptr != trap && tp[0]) */
@@ -13748,7 +13819,7 @@ trapcmd(int argc UNUSED_PARAM, char **ar
exitcode = 0;
while (*ap) {
- signo = get_signum(*ap);
+ signo = strstr(*ap, "ERR") ? NSIG : get_signum(*ap);
if (signo < 0) {
/* Mimic bash message exactly */
ash_msg("%s: invalid signal specification", *ap);
@@ -13767,7 +13838,7 @@ trapcmd(int argc UNUSED_PARAM, char **ar
}
free(trap[signo]);
trap[signo] = action;
- if (signo != 0)
+ if (signo != 0 && signo < NSIG)
setsignal(signo);
INT_ON;
next:
@@ -14188,7 +14259,9 @@ exitshell(void)
if (p) {
trap[0] = NULL;
evalskip = 0;
+ doingtrap = 1;
evalstring(p, 0);
+ doingtrap = 0;
evalskip = SKIPFUNCDEF;
/*free(p); - we'll exit soon */
}
@@ -14495,6 +14568,7 @@ int ash_main(int argc UNUSED_PARAM, char
// ash -sc 'echo $-'
// continue reading input from stdin after running 'echo'.
// bash does not do this: it prints "hBcs" and exits.
+ lineno = 0;
evalstring(minusc, EV_EXIT);
}
["testsuite.tgz" (application/x-compressed)]
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic