X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=shell%2Fash.c;h=6f03ac1c69b07aa35306a8fd8e1a05513729f4fc;hb=642e71a789156a96bcb18e6c5a0f52416c49d3b5;hp=067feb13d058cda4c3526cac2366cf75fd92d69a;hpb=08d8b3cee1329d390f91bce419e2b4dadf484952;p=oweals%2Fbusybox.git diff --git a/shell/ash.c b/shell/ash.c index 067feb13d..6f03ac1c6 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -13,7 +13,7 @@ * Copyright (c) 1997-2005 Herbert Xu * was re-ported from NetBSD and debianized. * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* @@ -36,28 +36,23 @@ #define JOBS ENABLE_ASH_JOB_CONTROL -#if DEBUG -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# endif -#endif - #include "busybox.h" /* for applet_names */ #include #include #include +#include #include "shell_common.h" -#include "math.h" +#if ENABLE_SH_MATH_SUPPORT +# include "math.h" +#endif #if ENABLE_ASH_RANDOM_SUPPORT # include "random.h" #else # define CLEAR_RANDOM_T(rnd) ((void)0) #endif -#define SKIP_definitions 1 -#include "applet_tables.h" -#undef SKIP_definitions +#include "NUM_APPLETS.h" #if NUM_APPLETS == 1 /* STANDALONE does not make sense, and won't compile */ # undef CONFIG_FEATURE_SH_STANDALONE @@ -77,6 +72,124 @@ # error "Do not even bother, ash will not run on NOMMU machine" #endif +//applet:IF_ASH(APPLET(ash, _BB_DIR_BIN, _BB_SUID_DROP)) +//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh)) +//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash)) + +//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o +//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o + +//config:config ASH +//config: bool "ash" +//config: default y +//config: depends on !NOMMU +//config: help +//config: Tha 'ash' shell adds about 60k in the default configuration and is +//config: the most complete and most pedantically correct shell included with +//config: busybox. This shell is actually a derivative of the Debian 'dash' +//config: shell (by Herbert Xu), which was created by porting the 'ash' shell +//config: (written by Kenneth Almquist) from NetBSD. +//config: +//config:config ASH_BASH_COMPAT +//config: bool "bash-compatible extensions" +//config: default y +//config: depends on ASH +//config: help +//config: Enable bash-compatible extensions. +//config: +//config:config ASH_JOB_CONTROL +//config: bool "Job control" +//config: default y +//config: depends on ASH +//config: help +//config: Enable job control in the ash shell. +//config: +//config:config ASH_ALIAS +//config: bool "alias support" +//config: default y +//config: depends on ASH +//config: help +//config: Enable alias support in the ash shell. +//config: +//config:config ASH_GETOPTS +//config: bool "Builtin getopt to parse positional parameters" +//config: default y +//config: depends on ASH +//config: help +//config: Enable getopts builtin in the ash shell. +//config: +//config:config ASH_BUILTIN_ECHO +//config: bool "Builtin version of 'echo'" +//config: default y +//config: depends on ASH +//config: help +//config: Enable support for echo, builtin to ash. +//config: +//config:config ASH_BUILTIN_PRINTF +//config: bool "Builtin version of 'printf'" +//config: default y +//config: depends on ASH +//config: help +//config: Enable support for printf, builtin to ash. +//config: +//config:config ASH_BUILTIN_TEST +//config: bool "Builtin version of 'test'" +//config: default y +//config: depends on ASH +//config: help +//config: Enable support for test, builtin to ash. +//config: +//config:config ASH_CMDCMD +//config: bool "'command' command to override shell builtins" +//config: default y +//config: depends on ASH +//config: help +//config: Enable support for the ash 'command' builtin, which allows +//config: you to run the specified command with the specified arguments, +//config: even when there is an ash builtin command with the same name. +//config: +//config:config ASH_MAIL +//config: bool "Check for new mail on interactive shells" +//config: default n +//config: depends on ASH +//config: help +//config: Enable "check for new mail" in the ash shell. +//config: +//config:config ASH_OPTIMIZE_FOR_SIZE +//config: bool "Optimize for size instead of speed" +//config: default y +//config: depends on ASH +//config: help +//config: Compile ash for reduced size at the price of speed. +//config: +//config:config ASH_RANDOM_SUPPORT +//config: bool "Pseudorandom generator and $RANDOM variable" +//config: default y +//config: depends on ASH +//config: help +//config: Enable pseudorandom generator and dynamic variable "$RANDOM". +//config: Each read of "$RANDOM" will generate a new pseudorandom value. +//config: You can reset the generator by using a specified start value. +//config: After "unset RANDOM" the generator will switch off and this +//config: variable will no longer have special treatment. +//config: +//config:config ASH_EXPAND_PRMT +//config: bool "Expand prompt string" +//config: default y +//config: depends on ASH +//config: help +//config: "PS#" may contain volatile content, such as backquote commands. +//config: This option recreates the prompt string from the environment +//config: variable each time it is displayed. +//config: + +//usage:#define ash_trivial_usage NOUSAGE_STR +//usage:#define ash_full_usage "" +//usage:#define sh_trivial_usage NOUSAGE_STR +//usage:#define sh_full_usage "" +//usage:#define bash_trivial_usage NOUSAGE_STR +//usage:#define bash_full_usage "" + /* ============ Hash table sizes. Configurable. */ @@ -842,7 +955,8 @@ sharg(union node *arg, FILE *fp) for (p = arg->narg.text; *p; p++) { switch ((unsigned char)*p) { case CTLESC: - putc(*++p, fp); + p++; + putc(*p, fp); break; case CTLVAR: putc('$', fp); @@ -851,8 +965,10 @@ sharg(union node *arg, FILE *fp) if (subtype == VSLENGTH) putc('#', fp); - while (*p != '=') - putc(*p++, fp); + while (*p != '=') { + putc(*p, fp); + p++; + } if (subtype & VSNUL) putc(':', fp); @@ -1044,7 +1160,7 @@ struct strpush { struct parsefile { struct parsefile *prev; /* preceding file on stack */ int linno; /* current line */ - int fd; /* file descriptor (or -1 if string) */ + int pf_fd; /* file descriptor (or -1 if string) */ int left_in_line; /* number of chars left in this line */ int left_in_buffer; /* number of chars left in this buffer past the line */ char *next_to_pgetc; /* next char in buffer */ @@ -1070,7 +1186,7 @@ ash_vmsg(const char *msg, va_list ap) if (commandname) { if (strcmp(arg0, commandname)) fprintf(stderr, "%s: ", commandname); - if (!iflag || g_parsefile->fd > 0) + if (!iflag || g_parsefile->pf_fd > 0) fprintf(stderr, "line %d: ", startlinno); } vfprintf(stderr, msg, ap); @@ -1871,10 +1987,6 @@ extern struct globals_var *const ash_ptr_to_globals_var; # define optindval() (voptind.var_text + 7) #endif - -#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) -#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) - #if ENABLE_ASH_GETOPTS static void FAST_FUNC getoptsreset(const char *value) @@ -1884,24 +1996,26 @@ getoptsreset(const char *value) } #endif +/* math.h has these, otherwise define our private copies */ +#if !ENABLE_SH_MATH_SUPPORT +#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) +#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) /* - * Return of a legal variable name (a letter or underscore followed by zero or - * more letters, underscores, and digits). + * Return the pointer to the first char which is not part of a legal variable name + * (a letter or underscore followed by letters, underscores, and digits). */ -static char* FAST_FUNC +static const char* endofname(const char *name) { - char *p; - - p = (char *) name; - if (!is_name(*p)) - return p; - while (*++p) { - if (!is_in_name(*p)) + if (!is_name(*name)) + return name; + while (*++name) { + if (!is_in_name(*name)) break; } - return p; + return name; } +#endif /* * Compares two strings up to the first = or '\0'. The first @@ -2084,9 +2198,10 @@ setvareq(char *s, int flags) static void setvar(const char *name, const char *val, int flags) { - char *p, *q; - size_t namelen; + const char *q; + char *p; char *nameeq; + size_t namelen; size_t vallen; q = endofname(name); @@ -2100,12 +2215,13 @@ setvar(const char *name, const char *val, int flags) } else { vallen = strlen(val); } + INT_OFF; nameeq = ckmalloc(namelen + vallen + 2); - p = (char *)memcpy(nameeq, name, namelen) + namelen; + p = memcpy(nameeq, name, namelen) + namelen; if (val) { *p++ = '='; - p = (char *)memcpy(p, val, vallen) + vallen; + p = memcpy(p, val, vallen) + vallen; } *p = '\0'; setvareq(nameeq, flags | VNOSAVE); @@ -2319,12 +2435,13 @@ static const char *expandstr(const char *ps); #endif static void -setprompt(int whichprompt) +setprompt_if(smallint do_set, int whichprompt) { const char *prompt; -#if ENABLE_ASH_EXPAND_PRMT - struct stackmark smark; -#endif + IF_ASH_EXPAND_PRMT(struct stackmark smark;) + + if (!do_set) + return; needprompt = 0; @@ -4522,6 +4639,7 @@ clear_traps(void) INT_ON; } } + may_have_traps = 0; } /* Lives far away from here, needed for forkchild */ @@ -4877,9 +4995,13 @@ noclobberopen(const char *fname) * revealed that it was a regular file, and the file has not been * replaced, return the file descriptor. */ - if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) - && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) + if (fstat(fd, &finfo2) == 0 + && !S_ISREG(finfo2.st_mode) + && finfo.st_dev == finfo2.st_dev + && finfo.st_ino == finfo2.st_ino + ) { return fd; + } /* The file has been replaced. badness. */ close(fd); @@ -4943,7 +5065,7 @@ openredirect(union node *redir) break; case NFROMTO: fname = redir->nfile.expfname; - f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666); + f = open(fname, O_RDWR|O_CREAT, 0666); if (f < 0) goto ecreate; break; @@ -5066,15 +5188,15 @@ static int is_hidden_fd(struct redirtab *rp, int fd) /* Check open scripts' fds */ pf = g_parsefile; while (pf) { - /* We skip fd == 0 case because of the following case: + /* We skip pf_fd == 0 case because of the following case: * $ ash # running ash interactively * $ . ./script.sh * and in script.sh: "exec 9>&0". - * Even though top-level fd _is_ 0, + * Even though top-level pf_fd _is_ 0, * it's still ok to use it: "read" builtin uses it, * why should we cripple "exec" builtin? */ - if (pf->fd > 0 && fd == pf->fd) { + if (pf->pf_fd > 0 && fd == pf->pf_fd) { return 1; } pf = pf->prev; @@ -5322,25 +5444,17 @@ redirectsafe(union node *redir, int flags) static arith_t ash_arith(const char *s) { - arith_eval_hooks_t math_hooks; + arith_state_t math_state; arith_t result; - int errcode = 0; - math_hooks.lookupvar = lookupvar; - math_hooks.setvar = setvar2; - math_hooks.endofname = endofname; + math_state.lookupvar = lookupvar; + math_state.setvar = setvar2; + //math_state.endofname = endofname; INT_OFF; - result = arith(s, &errcode, &math_hooks); - if (errcode < 0) { - if (errcode == -3) - ash_msg_and_raise_error("exponent less than 0"); - if (errcode == -2) - ash_msg_and_raise_error("divide by zero"); - if (errcode == -5) - ash_msg_and_raise_error("expression recursion loop detected"); - raise_error_syntax(s); - } + result = arith(&math_state, s); + if (math_state.errmsg) + ash_msg_and_raise_error(math_state.errmsg); INT_ON; return result; @@ -5398,13 +5512,18 @@ static struct arglist exparg; /* * Our own itoa(). */ +#if !ENABLE_SH_MATH_SUPPORT +/* cvtnum() is used even if math support is off (to prepare $? values and such) */ +typedef long arith_t; +# define ARITH_FMT "%ld" +#endif static int cvtnum(arith_t num) { int len; expdest = makestrspace(32, expdest); - len = fmtstr(expdest, 32, arith_t_fmt, num); + len = fmtstr(expdest, 32, ARITH_FMT, num); STADJUST(len, expdest); return len; } @@ -5575,7 +5694,7 @@ removerecordregions(int endoff) return; if (ifsfirst.endoff > endoff) { - while (ifsfirst.next != NULL) { + while (ifsfirst.next) { struct ifsregion *ifsp; INT_OFF; ifsp = ifsfirst.next->next; @@ -5583,9 +5702,9 @@ removerecordregions(int endoff) ifsfirst.next = ifsp; INT_ON; } - if (ifsfirst.begoff > endoff) + if (ifsfirst.begoff > endoff) { ifslastp = NULL; - else { + } else { ifslastp = &ifsfirst; ifsfirst.endoff = endoff; } @@ -5594,8 +5713,8 @@ removerecordregions(int endoff) ifslastp = &ifsfirst; while (ifslastp->next && ifslastp->next->begoff < endoff) - ifslastp=ifslastp->next; - while (ifslastp->next != NULL) { + ifslastp = ifslastp->next; + while (ifslastp->next) { struct ifsregion *ifsp; INT_OFF; ifsp = ifslastp->next->next; @@ -5772,9 +5891,9 @@ expbackq(union node *cmd, int quoted, int quotes) if (quoted == 0) recordregion(startloc, dest - (char *)stackblock(), 0); - TRACE(("evalbackq: size=%d: \"%.*s\"\n", - (dest - (char *)stackblock()) - startloc, - (dest - (char *)stackblock()) - startloc, + TRACE(("evalbackq: size:%d:'%.*s'\n", + (int)((dest - (char *)stackblock()) - startloc), + (int)((dest - (char *)stackblock()) - startloc), stackblock() + startloc)); } @@ -5889,7 +6008,7 @@ argstr(char *p, int flags, struct strlist *var_str_list) flags &= ~EXP_TILDE; tilde: q = p; - if (*q == CTLESC && (flags & EXP_QWORD)) + if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD)) q++; if (*q == '~') p = exptilde(p, q, flags); @@ -5903,9 +6022,7 @@ argstr(char *p, int flags, struct strlist *var_str_list) c = p[length]; if (c) { if (!(c & 0x80) -#if ENABLE_SH_MATH_SUPPORT - || c == CTLENDARI -#endif + IF_SH_MATH_SUPPORT(|| c == CTLENDARI) ) { /* c == '=' || c == ':' || c == CTLENDARI */ length++; @@ -5952,8 +6069,8 @@ argstr(char *p, int flags, struct strlist *var_str_list) /* "$@" syntax adherence hack */ if (!inquotes && memcmp(p, dolatstr, 4) == 0 - && ( p[4] == CTLQUOTEMARK - || (p[4] == CTLENDVAR && p[5] == CTLQUOTEMARK) + && ( p[4] == (char)CTLQUOTEMARK + || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK) ) ) { p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1; @@ -5988,47 +6105,20 @@ argstr(char *p, int flags, struct strlist *var_str_list) #endif } } - breakloop: - ; + breakloop: ; } static char * -scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int quotes, - int zero) -{ -// This commented out code was added by James Simmons -// as part of a larger change when he added support for ${var/a/b}. -// However, it broke # and % operators: -// -//var=ababcdcd -// ok bad -//echo ${var#ab} abcdcd abcdcd -//echo ${var##ab} abcdcd abcdcd -//echo ${var#a*b} abcdcd ababcdcd (!) -//echo ${var##a*b} cdcd cdcd -//echo ${var#?} babcdcd ababcdcd (!) -//echo ${var##?} babcdcd babcdcd -//echo ${var#*} ababcdcd babcdcd (!) -//echo ${var##*} -//echo ${var%cd} ababcd ababcd -//echo ${var%%cd} ababcd abab (!) -//echo ${var%c*d} ababcd ababcd -//echo ${var%%c*d} abab ababcdcd (!) -//echo ${var%?} ababcdc ababcdc -//echo ${var%%?} ababcdc ababcdcd (!) -//echo ${var%*} ababcdcd ababcdcd -//echo ${var%%*} -// -// Commenting it back out helped. Remove it completely if it really -// is not needed. - - char *loc, *loc2; //, *full; +scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, + char *pattern, int quotes, int zero) +{ + char *loc, *loc2; char c; loc = startp; loc2 = rmesc; do { - int match; // = strlen(str); + int match; const char *s = loc2; c = *loc2; @@ -6036,35 +6126,22 @@ scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int *loc2 = '\0'; s = rmesc; } - match = pmatch(str, s); // this line was deleted - -// // chop off end if its '*' -// full = strrchr(str, '*'); -// if (full && full != str) -// match--; -// -// // If str starts with '*' replace with s. -// if ((*str == '*') && strlen(s) >= match) { -// full = xstrdup(s); -// strncpy(full+strlen(s)-match+1, str+1, match-1); -// } else -// full = xstrndup(str, match); -// match = strncmp(s, full, strlen(full)); -// free(full); -// + match = pmatch(pattern, s); + *loc2 = c; - if (match) // if (!match) + if (match) return loc; if (quotes && (unsigned char)*loc == CTLESC) loc++; loc++; loc2++; } while (c); - return 0; + return NULL; } static char * -scanright(char *startp, char *rmesc, char *rmescend, char *pattern, int quotes, int match_at_start) +scanright(char *startp, char *rmesc, char *rmescend, + char *pattern, int quotes, int match_at_start) { #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE int try2optimize = match_at_start; @@ -6130,7 +6207,7 @@ scanright(char *startp, char *rmesc, char *rmescend, char *pattern, int quotes, } } } - return 0; + return NULL; } static void varunset(const char *, const char *, const char *, int) NORETURN; @@ -6150,16 +6227,18 @@ varunset(const char *end, const char *var, const char *umsg, int varflags) msg = umsg; } } - ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail); + ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); } #if ENABLE_ASH_BASH_COMPAT static char * -parse_sub_pattern(char *arg, int inquotes) +parse_sub_pattern(char *arg, int varflags) { char *idx, *repl = NULL; unsigned char c; + //char *org_arg = arg; + //bb_error_msg("arg:'%s' varflags:%x", arg, varflags); idx = arg; while (1) { c = *arg; @@ -6173,32 +6252,47 @@ parse_sub_pattern(char *arg, int inquotes) } } *idx++ = c; - if (!inquotes && c == '\\' && arg[1] == '\\') - arg++; /* skip both \\, not just first one */ arg++; + /* + * Example: v='ab\c'; echo ${v/\\b/_\\_\z_} + * The result is a_\_z_c (not a\_\_z_c)! + * + * Enable debug prints in this function and you'll see: + * ash: arg:'\\b/_\\_z_' varflags:d + * ash: pattern:'\\b' repl:'_\_z_' + * That is, \\b is interpreted as \\b, but \\_ as \_! + * IOW: search pattern and replace string treat backslashes + * differently! That is the reason why we check repl below: + */ + if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE)) + arg++; /* skip both '\', not just first one */ } *idx = c; /* NUL */ + //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl); return repl; } #endif /* ENABLE_ASH_BASH_COMPAT */ static const char * -subevalvar(char *p, char *str, int strloc, int subtype, +subevalvar(char *p, char *varname, int strloc, int subtype, int startloc, int varflags, int quotes, struct strlist *var_str_list) { struct nodelist *saveargbackq = argbackq; char *startp; char *loc; char *rmesc, *rmescend; - IF_ASH_BASH_COMPAT(char *repl = NULL;) - IF_ASH_BASH_COMPAT(char null = '\0';) + char *str; + IF_ASH_BASH_COMPAT(const char *repl = NULL;) IF_ASH_BASH_COMPAT(int pos, len, orig_len;) int saveherefd = herefd; int amount, workloc, resetloc; int zero; char *(*scan)(char*, char*, char*, char*, int, int); + //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)", + // p, varname, strloc, subtype, startloc, varflags, quotes); + herefd = -1; argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0, var_str_list); @@ -6209,11 +6303,15 @@ subevalvar(char *p, char *str, int strloc, int subtype, switch (subtype) { case VSASSIGN: - setvar(str, startp, 0); + setvar(varname, startp, 0); amount = startp - expdest; STADJUST(amount, expdest); return startp; + case VSQUESTION: + varunset(p, varname, startp, varflags); + /* NOTREACHED */ + #if ENABLE_ASH_BASH_COMPAT case VSSUBSTR: loc = str = stackblock() + strloc; @@ -6274,11 +6372,8 @@ subevalvar(char *p, char *str, int strloc, int subtype, STADJUST(amount, expdest); return loc; #endif - - case VSQUESTION: - varunset(p, str, startp, varflags); - /* NOTREACHED */ } + resetloc = expdest - (char *)stackblock(); /* We'll comeback here if we grow the stack while handling @@ -6311,14 +6406,15 @@ subevalvar(char *p, char *str, int strloc, int subtype, char *idx, *end; if (!repl) { - repl = parse_sub_pattern(str, varflags & VSQUOTE); + repl = parse_sub_pattern(str, varflags); + //bb_error_msg("repl:'%s'", repl); if (!repl) - repl = &null; + repl = nullstr; } /* If there's no pattern to match, return the expansion unmolested */ if (str[0] == '\0') - return 0; + return NULL; len = 0; idx = startp; @@ -6326,6 +6422,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, while (idx < end) { try_to_match: loc = scanright(idx, rmesc, rmescend, str, quotes, 1); + //bb_error_msg("scanright('%s'):'%s'", str, loc); if (!loc) { /* No match, advance */ char *restart_detect = stackblock(); @@ -6364,8 +6461,13 @@ subevalvar(char *p, char *str, int strloc, int subtype, idx = loc; } - for (loc = repl; *loc; loc++) { + //bb_error_msg("repl:'%s'", repl); + for (loc = (char*)repl; *loc; loc++) { char *restart_detect = stackblock(); + if (quotes && *loc == '\\') { + STPUTC(CTLESC, expdest); + len++; + } STPUTC(*loc, expdest); if (stackblock() != restart_detect) goto restart; @@ -6373,6 +6475,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, } if (subtype == VSREPLACE) { + //bb_error_msg("tail:'%s', quotes:%x", idx, quotes); while (*idx) { char *restart_detect = stackblock(); STPUTC(*idx, expdest); @@ -6388,11 +6491,11 @@ subevalvar(char *p, char *str, int strloc, int subtype, /* We've put the replaced text into a buffer at workloc, now * move it to the right place and adjust the stack. */ - startp = stackblock() + startloc; STPUTC('\0', expdest); - memmove(startp, stackblock() + workloc, len); - startp[len++] = '\0'; - amount = expdest - ((char *)stackblock() + startloc + len - 1); + startp = (char *)stackblock() + startloc; + memmove(startp, (char *)stackblock() + workloc, len + 1); + //bb_error_msg("startp:'%s'", startp); + amount = expdest - (startp + len); STADJUST(-amount, expdest); return startp; } @@ -6621,8 +6724,8 @@ evalvar(char *p, int flags, struct strlist *var_str_list) vsplus: if (varlen < 0) { argstr( - p, flags | EXP_TILDE | - (quoted ? EXP_QWORD : EXP_WORD), + p, + flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD), var_str_list ); goto end; @@ -6692,7 +6795,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) */ STPUTC('\0', expdest); patloc = expdest - (char *)stackblock(); - if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype, + if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, startloc, varflags, //TODO: | EXP_REDIR too? All other such places do it too /* quotes: */ flags & (EXP_FULL | EXP_CASE), @@ -6855,13 +6958,11 @@ addfname(const char *name) exparg.lastp = &sp->next; } -static char *expdir; - /* * Do metacharacter (i.e. *, ?, [...]) expansion. */ static void -expmeta(char *enddir, char *name) +expmeta(char *expdir, char *enddir, char *name) { char *p; const char *cp; @@ -6960,7 +7061,7 @@ expmeta(char *enddir, char *name) for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';) continue; p[-1] = '/'; - expmeta(p, endname); + expmeta(expdir, p, endname); } } } @@ -7042,6 +7143,7 @@ expandmeta(struct strlist *str /*, int flag*/) /* TODO - EXP_REDIR */ while (str) { + char *expdir; struct strlist **savelastp; struct strlist *sp; char *p; @@ -7058,8 +7160,7 @@ expandmeta(struct strlist *str /*, int flag*/) int i = strlen(str->text); expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ } - - expmeta(expdir, p); + expmeta(expdir, expdir, p); free(expdir); if (p != str->text) free(p); @@ -7251,6 +7352,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** #if ENABLE_FEATURE_SH_STANDALONE if (applet_no >= 0) { if (APPLET_IS_NOEXEC(applet_no)) { + clearenv(); while (*envp) putenv(*envp++); run_applet_no_and_exit(applet_no, argv); @@ -7310,7 +7412,7 @@ shellexec(char **argv, const char *path, int idx) #endif clearredir(/*drop:*/ 1); - envp = listvars(VEXPORT, VUNSET, 0); + envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); if (strchr(argv[0], '/') != NULL #if ENABLE_FEATURE_SH_STANDALONE || (applet_no = find_applet_by_name(argv[0])) >= 0 @@ -7528,7 +7630,7 @@ hashcd(void) for (cmdp = *pp; cmdp; cmdp = cmdp->next) { if (cmdp->cmdtype == CMDNORMAL || (cmdp->cmdtype == CMDBUILTIN - && !IS_BUILTIN_REGULAR(cmdp->param.cmd) + && !IS_BUILTIN_REGULAR(cmdp->param.cmd) && builtinloc > 0) ) { cmdp->rehash = 1; @@ -8119,7 +8221,7 @@ static int evalstring(char *s, int mask); /* Called to execute a trap. * Single callsite - at the end of evaltree(). - * If we return non-zero, exaltree raises EXEXIT exception. + * If we return non-zero, evaltree raises EXEXIT exception. * * Perhaps we should avoid entering new trap handlers * while we are executing a trap handler. [is it a TODO?] @@ -8309,11 +8411,15 @@ evaltree(union node *n, int flags) out: exception_handler = savehandler; + out1: + /* Order of checks below is important: + * signal handlers trigger before exit caused by "set -e". + */ + if (pending_sig && dotrap()) + goto exexit; if (checkexit & exitstatus) evalskip |= SKIPEVAL; - else if (pending_sig && dotrap()) - goto exexit; if (flags & EV_EXIT) { exexit: @@ -8645,7 +8751,7 @@ poplocalvars(void) while ((lvp = localvars) != NULL) { localvars = lvp->next; vp = lvp->vp; - TRACE(("poplocalvar %s\n", vp ? vp->text : "-")); + TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-")); if (vp == NULL) { /* $- saved */ memcpy(optlist, lvp->text, sizeof(optlist)); free((char*)lvp->text); @@ -9107,19 +9213,15 @@ evalcommand(union node *cmd, int flags) /* Print the command if xflag is set. */ if (xflag) { int n; - const char *p = " %s"; + const char *p = " %s" + 1; - p++; fdprintf(preverrout_fd, p, expandstr(ps4val())); - sp = varlist.list; for (n = 0; n < 2; n++) { while (sp) { fdprintf(preverrout_fd, p, sp->text); sp = sp->next; - if (*p == '%') { - p--; - } + p = " %s"; } sp = arglist.list; } @@ -9307,7 +9409,7 @@ evalbltin(const struct builtincmd *cmd, int argc, char **argv) static int goodname(const char *p) { - return !*endofname(p); + return endofname(p)[0] == '\0'; } @@ -9456,8 +9558,8 @@ preadfd(void) g_parsefile->next_to_pgetc = buf; #if ENABLE_FEATURE_EDITING retry: - if (!iflag || g_parsefile->fd != STDIN_FILENO) - nr = nonblock_safe_read(g_parsefile->fd, buf, IBUFSIZ - 1); + if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) + nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); else { #if ENABLE_FEATURE_TAB_COMPLETION line_input_state->path_lookup = pathval(); @@ -9479,7 +9581,7 @@ preadfd(void) } } #else - nr = nonblock_safe_read(g_parsefile->fd, buf, IBUFSIZ - 1); + nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); #endif #if 0 @@ -9706,7 +9808,7 @@ pushfile(void) pf = ckzalloc(sizeof(*pf)); pf->prev = g_parsefile; - pf->fd = -1; + pf->pf_fd = -1; /*pf->strpush = NULL; - ckzalloc did it */ /*pf->basestrpush.prev = NULL;*/ g_parsefile = pf; @@ -9718,8 +9820,8 @@ popfile(void) struct parsefile *pf = g_parsefile; INT_OFF; - if (pf->fd >= 0) - close(pf->fd); + if (pf->pf_fd >= 0) + close(pf->pf_fd); free(pf->buf); while (pf->strpush) popstring(); @@ -9746,9 +9848,9 @@ static void closescript(void) { popallfiles(); - if (g_parsefile->fd > 0) { - close(g_parsefile->fd); - g_parsefile->fd = 0; + if (g_parsefile->pf_fd > 0) { + close(g_parsefile->pf_fd); + g_parsefile->pf_fd = 0; } } @@ -9764,7 +9866,7 @@ setinputfd(int fd, int push) pushfile(); g_parsefile->buf = NULL; } - g_parsefile->fd = fd; + g_parsefile->pf_fd = fd; if (g_parsefile->buf == NULL) g_parsefile->buf = ckmalloc(IBUFSIZ); g_parsefile->left_in_buffer = 0; @@ -10938,7 +11040,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) startlinno = g_parsefile->linno; bqlist = NULL; quotef = 0; - oldstyle = 0; prevsyntax = 0; #if ENABLE_ASH_EXPAND_PRMT pssyntax = (syntax == PSSYNTAX); @@ -10954,160 +11055,156 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) STARTSTACKSTR(out); loop: /* For each line, until end of word */ - { - CHECKEND(); /* set c to PEOF if at end of here document */ - for (;;) { /* until end of line or end of word */ - CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ - switch (SIT(c, syntax)) { - case CNL: /* '\n' */ - if (syntax == BASESYNTAX) - goto endword; /* exit outer loop */ - USTPUTC(c, out); - g_parsefile->linno++; - if (doprompt) - setprompt(2); - c = pgetc(); - goto loop; /* continue outer loop */ - case CWORD: - USTPUTC(c, out); - break; - case CCTL: - if (eofmark == NULL || dblquote) - USTPUTC(CTLESC, out); + CHECKEND(); /* set c to PEOF if at end of here document */ + for (;;) { /* until end of line or end of word */ + CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ + switch (SIT(c, syntax)) { + case CNL: /* '\n' */ + if (syntax == BASESYNTAX) + goto endword; /* exit outer loop */ + USTPUTC(c, out); + g_parsefile->linno++; + setprompt_if(doprompt, 2); + c = pgetc(); + goto loop; /* continue outer loop */ + case CWORD: + USTPUTC(c, out); + break; + case CCTL: + if (eofmark == NULL || dblquote) + USTPUTC(CTLESC, out); #if ENABLE_ASH_BASH_COMPAT - if (c == '\\' && bash_dollar_squote) { - c = decode_dollar_squote(); - if (c & 0x100) { - USTPUTC('\\', out); - c = (unsigned char)c; - } + if (c == '\\' && bash_dollar_squote) { + c = decode_dollar_squote(); + if (c & 0x100) { + USTPUTC('\\', out); + c = (unsigned char)c; } + } #endif - USTPUTC(c, out); - break; - case CBACK: /* backslash */ - c = pgetc_without_PEOA(); - if (c == PEOF) { + USTPUTC(c, out); + break; + case CBACK: /* backslash */ + c = pgetc_without_PEOA(); + if (c == PEOF) { + USTPUTC(CTLESC, out); + USTPUTC('\\', out); + pungetc(); + } else if (c == '\n') { + setprompt_if(doprompt, 2); + } else { +#if ENABLE_ASH_EXPAND_PRMT + if (c == '$' && pssyntax) { USTPUTC(CTLESC, out); USTPUTC('\\', out); - pungetc(); - } else if (c == '\n') { - if (doprompt) - setprompt(2); - } else { -#if ENABLE_ASH_EXPAND_PRMT - if (c == '$' && pssyntax) { - USTPUTC(CTLESC, out); - USTPUTC('\\', out); - } + } #endif - if (dblquote && c != '\\' - && c != '`' && c != '$' - && (c != '"' || eofmark != NULL) - ) { - USTPUTC(CTLESC, out); - USTPUTC('\\', out); - } - if (SIT(c, SQSYNTAX) == CCTL) - USTPUTC(CTLESC, out); - USTPUTC(c, out); - quotef = 1; + /* Backslash is retained if we are in "str" and next char isn't special */ + if (dblquote + && c != '\\' + && c != '`' + && c != '$' + && (c != '"' || eofmark != NULL) + ) { + USTPUTC(CTLESC, out); + USTPUTC('\\', out); } - break; - case CSQUOTE: - syntax = SQSYNTAX; + if (SIT(c, SQSYNTAX) == CCTL) + USTPUTC(CTLESC, out); + USTPUTC(c, out); + quotef = 1; + } + break; + case CSQUOTE: + syntax = SQSYNTAX; quotemark: - if (eofmark == NULL) { - USTPUTC(CTLQUOTEMARK, out); + if (eofmark == NULL) { + USTPUTC(CTLQUOTEMARK, out); + } + break; + case CDQUOTE: + syntax = DQSYNTAX; + dblquote = 1; + goto quotemark; + case CENDQUOTE: + IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) + if (eofmark != NULL && arinest == 0 + && varnest == 0 + ) { + USTPUTC(c, out); + } else { + if (dqvarnest == 0) { + syntax = BASESYNTAX; + dblquote = 0; } - break; - case CDQUOTE: - syntax = DQSYNTAX; - dblquote = 1; + quotef = 1; goto quotemark; - case CENDQUOTE: - IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) - if (eofmark != NULL && arinest == 0 - && varnest == 0 - ) { - USTPUTC(c, out); - } else { - if (dqvarnest == 0) { - syntax = BASESYNTAX; - dblquote = 0; - } - quotef = 1; - goto quotemark; - } - break; - case CVAR: /* '$' */ - PARSESUB(); /* parse substitution */ - break; - case CENDVAR: /* '}' */ - if (varnest > 0) { - varnest--; - if (dqvarnest > 0) { - dqvarnest--; - } - USTPUTC(CTLENDVAR, out); - } else { - USTPUTC(c, out); + } + break; + case CVAR: /* '$' */ + PARSESUB(); /* parse substitution */ + break; + case CENDVAR: /* '}' */ + if (varnest > 0) { + varnest--; + if (dqvarnest > 0) { + dqvarnest--; } - break; + c = CTLENDVAR; + } + USTPUTC(c, out); + break; #if ENABLE_SH_MATH_SUPPORT - case CLP: /* '(' in arithmetic */ - parenlevel++; - USTPUTC(c, out); - break; - case CRP: /* ')' in arithmetic */ - if (parenlevel > 0) { - USTPUTC(c, out); - --parenlevel; - } else { - if (pgetc() == ')') { - if (--arinest == 0) { - USTPUTC(CTLENDARI, out); - syntax = prevsyntax; - dblquote = (syntax == DQSYNTAX); - } else - USTPUTC(')', out); - } else { - /* - * unbalanced parens - * (don't 2nd guess - no error) - */ - pungetc(); - USTPUTC(')', out); + case CLP: /* '(' in arithmetic */ + parenlevel++; + USTPUTC(c, out); + break; + case CRP: /* ')' in arithmetic */ + if (parenlevel > 0) { + parenlevel--; + } else { + if (pgetc() == ')') { + if (--arinest == 0) { + syntax = prevsyntax; + dblquote = (syntax == DQSYNTAX); + c = CTLENDARI; } + } else { + /* + * unbalanced parens + * (don't 2nd guess - no error) + */ + pungetc(); } - break; + } + USTPUTC(c, out); + break; #endif - case CBQUOTE: /* '`' */ - PARSEBACKQOLD(); - break; - case CENDFILE: - goto endword; /* exit outer loop */ - case CIGN: - break; - default: - if (varnest == 0) { + case CBQUOTE: /* '`' */ + PARSEBACKQOLD(); + break; + case CENDFILE: + goto endword; /* exit outer loop */ + case CIGN: + break; + default: + if (varnest == 0) { #if ENABLE_ASH_BASH_COMPAT - if (c == '&') { - if (pgetc() == '>') - c = 0x100 + '>'; /* flag &> */ - pungetc(); - } -#endif - goto endword; /* exit outer loop */ + if (c == '&') { + if (pgetc() == '>') + c = 0x100 + '>'; /* flag &> */ + pungetc(); } - IF_ASH_ALIAS(if (c != PEOA)) - USTPUTC(c, out); - +#endif + goto endword; /* exit outer loop */ } - c = pgetc_fast(); - } /* for (;;) */ - } + IF_ASH_ALIAS(if (c != PEOA)) + USTPUTC(c, out); + } + c = pgetc_fast(); + } /* for (;;) */ endword: + #if ENABLE_SH_MATH_SUPPORT if (syntax == ARISYNTAX) raise_error_syntax("missing '))'"); @@ -11268,8 +11365,6 @@ parsesub: { unsigned char subtype; int typeloc; int flags; - char *p; - static const char types[] ALIGN1 = "}-+?="; c = pgetc(); if (c > 255 /* PEOA or PEOF */ @@ -11282,7 +11377,8 @@ parsesub: { #endif USTPUTC('$', out); pungetc(); - } else if (c == '(') { /* $(command) or $((arith)) */ + } else if (c == '(') { + /* $(command) or $((arith)) */ if (pgetc() == '(') { #if ENABLE_SH_MATH_SUPPORT PARSEARITH(); @@ -11294,6 +11390,7 @@ parsesub: { PARSEBACKQNEW(); } } else { + /* $VAR, $, ${...}, or PEOA/PEOF */ USTPUTC(CTLVAR, out); typeloc = out - (char *)stackblock(); USTPUTC(VSNORMAL, out); @@ -11303,76 +11400,90 @@ parsesub: { if (c == '#') { c = pgetc(); if (c == '}') - c = '#'; + c = '#'; /* ${#} - same as $# */ else - subtype = VSLENGTH; - } else + subtype = VSLENGTH; /* ${#VAR} */ + } else { subtype = 0; + } } if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) { + /* $[{[#]]NAME[}] */ do { STPUTC(c, out); c = pgetc(); } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c)); } else if (isdigit(c)) { + /* $[{[#]]NUM[}] */ do { STPUTC(c, out); c = pgetc(); } while (isdigit(c)); } else if (is_special(c)) { + /* $[{[#]][}] */ USTPUTC(c, out); c = pgetc(); } else { badsub: raise_error_syntax("bad substitution"); } - if (c != '}' && subtype == VSLENGTH) + if (c != '}' && subtype == VSLENGTH) { + /* ${#VAR didn't end with } */ goto badsub; + } STPUTC('=', out); flags = 0; if (subtype == 0) { + /* ${VAR...} but not $VAR or ${#VAR} */ + /* c == first char after VAR */ switch (c) { case ':': c = pgetc(); #if ENABLE_ASH_BASH_COMPAT if (c == ':' || c == '$' || isdigit(c)) { - pungetc(); +//TODO: support more general format ${v:EXPR:EXPR}, +// where EXPR follows $(()) rules subtype = VSSUBSTR; - break; + pungetc(); + break; /* "goto do_pungetc" is bigger (!) */ } #endif flags = VSNUL; /*FALLTHROUGH*/ - default: - p = strchr(types, c); + default: { + static const char types[] ALIGN1 = "}-+?="; + const char *p = strchr(types, c); if (p == NULL) goto badsub; subtype = p - types + VSNORMAL; break; + } case '%': case '#': { int cc = c; - subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT; + subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT); c = pgetc(); - if (c == cc) - subtype++; - else - pungetc(); + if (c != cc) + goto do_pungetc; + subtype++; break; } #if ENABLE_ASH_BASH_COMPAT case '/': + /* ${v/[/]pattern/repl} */ +//TODO: encode pattern and repl separately. +// Currently ${v/$var_with_slash/repl} is horribly broken subtype = VSREPLACE; c = pgetc(); - if (c == '/') - subtype++; /* VSREPLACEALL */ - else - pungetc(); + if (c != '/') + goto do_pungetc; + subtype++; /* VSREPLACEALL */ break; #endif } } else { + do_pungetc: pungetc(); } if (dblquote || arinest) @@ -11429,16 +11540,14 @@ parsebackq: { treatment to some slashes, and then push the string and reread it as input, interpreting it normally. */ char *pout; - int pc; size_t psavelen; char *pstr; - STARTSTACKSTR(pout); for (;;) { - if (needprompt) { - setprompt(2); - } + int pc; + + setprompt_if(needprompt, 2); pc = pgetc(); switch (pc) { case '`': @@ -11448,8 +11557,7 @@ parsebackq: { pc = pgetc(); if (pc == '\n') { g_parsefile->linno++; - if (doprompt) - setprompt(2); + setprompt_if(doprompt, 2); /* * If eating a newline, avoid putting * the newline into the new character @@ -11612,9 +11720,7 @@ xxreadtoken(void) tokpushback = 0; return lasttoken; } - if (needprompt) { - setprompt(2); - } + setprompt_if(needprompt, 2); startlinno = g_parsefile->linno; for (;;) { /* until token or start of word found */ c = pgetc_fast(); @@ -11631,8 +11737,7 @@ xxreadtoken(void) break; /* return readtoken1(...) */ } startlinno = ++g_parsefile->linno; - if (doprompt) - setprompt(2); + setprompt_if(doprompt, 2); } else { const char *p; @@ -11678,9 +11783,7 @@ xxreadtoken(void) tokpushback = 0; return lasttoken; } - if (needprompt) { - setprompt(2); - } + setprompt_if(needprompt, 2); startlinno = g_parsefile->linno; for (;;) { /* until token or start of word found */ c = pgetc_fast(); @@ -11696,8 +11799,7 @@ xxreadtoken(void) case '\\': if (pgetc() == '\n') { startlinno = ++g_parsefile->linno; - if (doprompt) - setprompt(2); + setprompt_if(doprompt, 2); continue; } pungetc(); @@ -11823,8 +11925,7 @@ parsecmd(int interact) tokpushback = 0; doprompt = interact; - if (doprompt) - setprompt(doprompt); + setprompt_if(doprompt, doprompt); needprompt = 0; t = readtoken(); if (t == TEOF) @@ -11848,10 +11949,8 @@ parseheredoc(void) heredoclist = NULL; while (here) { - if (needprompt) { - setprompt(2); - } - readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, + setprompt_if(needprompt, 2); + readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX, here->eofmark, here->striptabs); n = stzalloc(sizeof(struct narg)); n->narg.type = NARG; @@ -11942,7 +12041,6 @@ evalcmd(int argc UNUSED_PARAM, char **argv) p = grabstackstr(concat); } evalstring(p, ~SKIPEVAL); - } return exitstatus; } @@ -12234,7 +12332,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) } if ((act & DO_NOFUNC) || !prefix(pathopt, "func") - ) { /* ignore unimplemented options */ + ) { /* ignore unimplemented options */ continue; } } @@ -12468,7 +12566,7 @@ unsetfunc(const char *name) struct tblentry *cmdp; cmdp = cmdlookup(name, 0); - if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION) + if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION) delete_cmd_entry(); } @@ -12485,7 +12583,7 @@ unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) int flag = 0; int ret = 0; - while ((i = nextopt("vf")) != '\0') { + while ((i = nextopt("vf")) != 0) { flag = i; } @@ -12502,11 +12600,6 @@ unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) return ret & 1; } - -/* setmode.c */ - -#include - static const unsigned char timescmd_str[] ALIGN1 = { ' ', offsetof(struct tms, tms_utime), '\n', offsetof(struct tms, tms_stime), @@ -12514,11 +12607,10 @@ static const unsigned char timescmd_str[] ALIGN1 = { '\n', offsetof(struct tms, tms_cstime), 0 }; - static int FAST_FUNC timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) { - long clk_tck, s, t; + unsigned long clk_tck, s, t; const unsigned char *p; struct tms buf; @@ -12529,18 +12621,20 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) do { t = *(clock_t *)(((char *) &buf) + p[1]); s = t / clk_tck; - out1fmt("%ldm%ld.%.3lds%c", - s/60, s%60, - ((t - s * clk_tck) * 1000) / clk_tck, + t = t % clk_tck; + out1fmt("%lum%lu.%03lus%c", + s / 60, s % 60, + (t * 1000) / clk_tck, p[0]); - } while (*(p += 2)); + p += 2; + } while (*p); return 0; } #if ENABLE_SH_MATH_SUPPORT /* - * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell. + * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell. * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. * * Copyright (C) 2003 Vladimir Oleynik @@ -12559,18 +12653,6 @@ letcmd(int argc UNUSED_PARAM, char **argv) return !i; } -#endif /* SH_MATH_SUPPORT */ - - -/* ============ miscbltin.c - * - * Miscellaneous builtins. - */ - -#undef rflag - -#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 -typedef enum __rlimit_resource rlim_t; #endif /* @@ -12765,7 +12847,7 @@ init(void) /* bash re-enables SIGHUP which is SIG_IGNed on entry. * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" */ - signal(SIGHUP, SIG_DFL); + signal(SIGHUP, SIG_DFL); /* from var.c: */ { @@ -12938,10 +13020,12 @@ int ash_main(int argc UNUSED_PARAM, char **argv) if (e == EXERROR) exitstatus = 2; s = state; - if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) + if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) { exitshell(); - if (e == EXINT) + } + if (e == EXINT) { outcslow('\n', stderr); + } popstackmark(&smark); FORCE_INT_ON; /* enable interrupts */ @@ -12979,7 +13063,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) } } #endif - if (/* argv[0] && */ argv[0][0] == '-') + if (argv[0] && argv[0][0] == '-') isloginsh = 1; if (isloginsh) { state = 1; @@ -13008,7 +13092,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) * Ensure we don't falsely claim that 0 (stdin) * is one of stacked source fds. * Testcase: ash -c 'exec 1>&0' must not complain. */ - // if (!sflag) g_parsefile->fd = -1; + // if (!sflag) g_parsefile->pf_fd = -1; // ^^ not necessary since now we special-case fd 0 // in is_hidden_fd() to not be considered "hidden fd" evalstring(minusc, 0); @@ -13034,6 +13118,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) _mcleanup(); } #endif + TRACE(("End of main reached\n")); exitshell(); /* NOTREACHED */ }