X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=shell%2Fash.c;h=83cac3fb0a5eb315bacc52a6930829a717a298ba;hb=9a1a659707a18c29166c3e2977523102866d7aed;hp=a6f777800d1d9049b31c2385e09fafb4bbd18b9d;hpb=d5bfe26c457a97a8b525b6c27f5498525a5829bf;p=oweals%2Fbusybox.git diff --git a/shell/ash.c b/shell/ash.c index a6f777800..83cac3fb0 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -404,11 +404,11 @@ struct globals_misc { volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */ volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */ - smallint exception_type; /* kind of exception (0..5) */ - /* exceptions */ + smallint exception_type; /* kind of exception: */ #define EXINT 0 /* SIGINT received */ #define EXERROR 1 /* a generic error */ -#define EXEXIT 4 /* exit the shell */ +#define EXEND 3 /* exit the shell */ +#define EXEXIT 4 /* exit the shell via exitcmd */ char nullstr[1]; /* zero length string */ @@ -1678,15 +1678,16 @@ popstackmark(struct stackmark *mark) * part of the block that has been used. */ static void -growstackblock(void) +growstackblock(size_t min) { size_t newlen; newlen = g_stacknleft * 2; if (newlen < g_stacknleft) ash_msg_and_raise_error(bb_msg_memory_exhausted); - if (newlen < 128) - newlen += 128; + min = SHELL_ALIGN(min | 128); + if (newlen < min) + newlen += min; if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) { struct stack_block *sp; @@ -1736,16 +1737,15 @@ static void * growstackstr(void) { size_t len = stackblocksize(); - growstackblock(); + growstackblock(0); return (char *)stackblock() + len; } static char * growstackto(size_t len) { - while (stackblocksize() < len) - growstackblock(); - + if (stackblocksize() < len) + growstackblock(len); return stackblock(); } @@ -6070,26 +6070,6 @@ static struct ifsregion *ifslastp; /* holds expanded arg list */ static struct arglist exparg; -/* - * Our own itoa(). - * cvtnum() is used even if math support is off (to prepare $? values and such). - */ -static int -cvtnum(arith_t num) -{ - int len; - - /* 32-bit and wider ints require buffer size of bytes*3 (or less) */ - len = sizeof(arith_t) * 3; - /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127" */ - if (sizeof(arith_t) < 4) len += 2; - - expdest = makestrspace(len, expdest); - len = fmtstr(expdest, len, ARITH_FMT, num); - STADJUST(len, expdest); - return len; -} - /* * Break the argument string into pieces based upon IFS and add the * strings to the argument list. The regions of the string to be @@ -6347,16 +6327,18 @@ preglob(const char *pattern, int flag) /* * Put a string on the stack. */ -static void +static size_t memtodest(const char *p, size_t len, int flags) { int syntax = flags & EXP_QUOTED ? DQSYNTAX : BASESYNTAX; char *q; + char *s; if (!len) - return; + return 0; q = makestrspace(len * 2, expdest); + s = q; do { unsigned char c = *p++; @@ -6375,6 +6357,7 @@ memtodest(const char *p, size_t len, int flags) } while (--len); expdest = q; + return q - s; } static size_t @@ -6385,6 +6368,22 @@ strtodest(const char *p, int flags) return len; } +/* + * Our own itoa(). + * cvtnum() is used even if math support is off (to prepare $? values and such). + */ +static int +cvtnum(arith_t num, int flags) +{ + /* 32-bit and wider ints require buffer size of bytes*3 (or less) */ + /* If narrower: worst case, 1-byte ints: need 5 bytes: "-127" */ + int len = (sizeof(arith_t) >= 4) ? sizeof(arith_t) * 3 : sizeof(arith_t) * 3 + 2; + char buf[len]; + + len = fmtstr(buf, len, ARITH_FMT, num); + return memtodest(buf, len, flags); +} + /* * Record the fact that we have to scan this region of the * string for IFS characters. @@ -6683,7 +6682,7 @@ expari(int flag) if (flag & QUOTES_ESC) rmescapes(p + 1, 0, NULL); - len = cvtnum(ash_arith(p + 1)); + len = cvtnum(ash_arith(p + 1), flag); if (!(flag & EXP_QUOTED)) recordregion(begoff, begoff + len, 0); @@ -7328,7 +7327,7 @@ varvalue(char *name, int varflags, int flags, int quoted) if (num == 0) return -1; numvar: - len = cvtnum(num); + len = cvtnum(num, flags); goto check_1char_name; case '-': expdest = makestrspace(NOPTS, expdest); @@ -7494,7 +7493,7 @@ evalvar(char *p, int flag) varunset(p, var, 0, 0); if (subtype == VSLENGTH) { - cvtnum(varlen > 0 ? varlen : 0); + cvtnum(varlen > 0 ? varlen : 0, flag); goto record; } @@ -8237,7 +8236,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx) exitstatus = exerrno; TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n", prog, e, suppress_int)); - ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found")); + ash_msg_and_raise(EXEND, "%s: %s", prog, errmsg(e, "not found")); /* NOTREACHED */ } @@ -9091,6 +9090,7 @@ defun(union node *func) #define SKIPBREAK (1 << 0) #define SKIPCONT (1 << 1) #define SKIPFUNC (1 << 2) +#define SKIPFUNCDEF (1 << 3) 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 */ @@ -9148,7 +9148,8 @@ dotrap(void) if (!p) continue; evalstring(p, 0); - exitstatus = status; + if (evalskip != SKIPFUNC) + exitstatus = status; } savestatus = last_status; @@ -9289,9 +9290,9 @@ evaltree(union node *n, int flags) dotrap(); if (checkexit & status) - raise_exception(EXEXIT); + raise_exception(EXEND); if (flags & EV_EXIT) - raise_exception(EXEXIT); + raise_exception(EXEND); popstackmark(&smark); TRACE(("leaving evaltree (no interrupts)\n")); @@ -9783,7 +9784,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) shellparam = saveparam; exception_handler = savehandler; INT_ON; - evalskip &= ~SKIPFUNC; + evalskip &= ~(SKIPFUNC | SKIPFUNCDEF); return e; } @@ -9928,12 +9929,23 @@ execcmd(int argc UNUSED_PARAM, char **argv) static int FAST_FUNC returncmd(int argc UNUSED_PARAM, char **argv) { + int skip; + int status; + /* * If called outside a function, do what ksh does; * skip the rest of the file. */ - evalskip = SKIPFUNC; - return argv[1] ? number(argv[1]) : exitstatus; + if (argv[1]) { + skip = SKIPFUNC; + status = number(argv[1]); + } else { + skip = SKIPFUNCDEF; + status = exitstatus; + } + evalskip = skip; + + return status; } /* Forward declarations for builtintab[] */ @@ -12865,9 +12877,9 @@ parsebackq: { if (readtoken() != TRP) raise_error_unexpected_syntax(TRP); setinputstring(nullstr); - parseheredoc(); } + parseheredoc(); heredoclist = saveheredoclist; (*nlpp)->n = n; @@ -13372,7 +13384,7 @@ cmdloop(int top) skip = evalskip; if (skip) { - evalskip &= ~SKIPFUNC; + evalskip &= ~(SKIPFUNC | SKIPFUNCDEF); break; } } @@ -14133,6 +14145,47 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv) /* ============ main() and helpers */ +/* + * This routine is called when an error or an interrupt occurs in an + * interactive shell and control is returned to the main command loop + * but prior to exitshell. + */ +static void +exitreset(void) +{ + /* from eval.c: */ + if (savestatus >= 0) { + if (exception_type == EXEXIT || evalskip == SKIPFUNCDEF) + exitstatus = savestatus; + savestatus = -1; + } + evalskip = 0; + loopnest = 0; + + /* from expand.c: */ + ifsfree(); + + /* from redir.c: */ + unwindredir(NULL); +} + +/* + * This routine is called when an error or an interrupt occurs in an + * interactive shell and control is returned to the main command loop. + * (In dash, this function is auto-generated by build machinery). + */ +static void +reset(void) +{ + /* from input.c: */ + g_parsefile->left_in_buffer = 0; + g_parsefile->left_in_line = 0; /* clear input buffer */ + popallfiles(); + + /* from var.c: */ + unwindlocalvars(NULL); +} + /* * Called to exit the shell. */ @@ -14156,15 +14209,17 @@ exitshell(void) trap[0] = NULL; evalskip = 0; evalstring(p, 0); + evalskip = SKIPFUNCDEF; /*free(p); - we'll exit soon */ } out: + exitreset(); /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". * our setjobctl(0) does not panic if tcsetpgrp fails inside it. */ setjobctl(0); flush_stdout_stderr(); - _exit(savestatus); + _exit(exitstatus); /* NOTREACHED */ } @@ -14324,46 +14379,6 @@ read_profile(const char *name) popfile(); } -/* - * This routine is called when an error or an interrupt occurs in an - * interactive shell and control is returned to the main command loop - * but prior to exitshell. - */ -static void -exitreset(void) -{ - /* from eval.c: */ - evalskip = 0; - loopnest = 0; - if (savestatus >= 0) { - exitstatus = savestatus; - savestatus = -1; - } - - /* from expand.c: */ - ifsfree(); - - /* from redir.c: */ - unwindredir(NULL); -} - -/* - * This routine is called when an error or an interrupt occurs in an - * interactive shell and control is returned to the main command loop. - * (In dash, this function is auto-generated by build machinery). - */ -static void -reset(void) -{ - /* from input.c: */ - g_parsefile->left_in_buffer = 0; - g_parsefile->left_in_line = 0; /* clear input buffer */ - popallfiles(); - - /* from var.c: */ - unwindlocalvars(NULL); -} - #if PROFILE static short profile_buf[16384]; extern int etext(); @@ -14411,7 +14426,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) e = exception_type; s = state; - if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) { + if (e == EXEND || e == EXEXIT || s == 0 || iflag == 0 || shlvl) { exitshell(); }