diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 175 |
1 files changed, 101 insertions, 74 deletions
diff --git a/shell/ash.c b/shell/ash.c index 866c7de05..02545f565 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -145,15 +145,10 @@ //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o /* - * The following should be set to reflect the type of system you have: - * JOBS -> 1 if you have Berkeley job control, 0 otherwise. - * define SYSV if you are running under System V. - * define DEBUG=1 to compile in debugging ('set -o debug' to turn on) - * define DEBUG=2 to compile in and turn on debugging. - * - * When debugging is on (DEBUG is 1 and "set -o debug" was executed), - * debugging info will be written to ./trace and a quit signal - * will generate a core dump. + * DEBUG=1 to compile in debugging ('set -o debug' turns on) + * DEBUG=2 to compile in and turn on debugging. + * When debugging is on ("set -o debug" was executed, or DEBUG=2), + * debugging info is written to ./trace, quit signal generates core dump. */ #define DEBUG 0 /* Tweak debug output verbosity here */ @@ -170,9 +165,30 @@ #include <fnmatch.h> #include <sys/times.h> #include <sys/utsname.h> /* for setting $HOSTNAME */ - #include "busybox.h" /* for applet_names */ +/* So far, all bash compat is controlled by one config option */ +/* Separate defines document which part of code implements what */ +/* function keyword */ +#define BASH_FUNCTION ENABLE_ASH_BASH_COMPAT +#define IF_BASH_FUNCTION IF_ASH_BASH_COMPAT +/* &>file */ +#define BASH_REDIR_OUTPUT ENABLE_ASH_BASH_COMPAT +#define IF_BASH_REDIR_OUTPUT IF_ASH_BASH_COMPAT +/* $'...' */ +#define BASH_DOLLAR_SQUOTE ENABLE_ASH_BASH_COMPAT +#define IF_BASH_DOLLAR_SQUOTE IF_ASH_BASH_COMPAT +#define BASH_PATTERN_SUBST ENABLE_ASH_BASH_COMPAT +#define IF_BASH_PATTERN_SUBST IF_ASH_BASH_COMPAT +#define BASH_SUBSTR ENABLE_ASH_BASH_COMPAT +#define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT +/* [[ EXPR ]] */ +#define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST) +#define BASH_SOURCE ENABLE_ASH_BASH_COMPAT +#define BASH_PIPEFAIL ENABLE_ASH_BASH_COMPAT +#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT +#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT + #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 /* Bionic at least up to version 24 has no glob() */ # undef ENABLE_ASH_INTERNAL_GLOB @@ -250,7 +266,7 @@ static const char *const optletters_optnames[] = { "b" "notify", "u" "nounset", "\0" "vi" -#if ENABLE_ASH_BASH_COMPAT +#if BASH_PIPEFAIL ,"\0" "pipefail" #endif #if DEBUG @@ -327,14 +343,14 @@ struct globals_misc { #define bflag optlist[11] #define uflag optlist[12] #define viflag optlist[13] -#if ENABLE_ASH_BASH_COMPAT +#if BASH_PIPEFAIL # define pipefail optlist[14] #else # define pipefail 0 #endif #if DEBUG -# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] -# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] +# define nolog optlist[14 + BASH_PIPEFAIL] +# define debug optlist[15 + BASH_PIPEFAIL] #endif /* trap handler commands */ @@ -655,8 +671,10 @@ out2str(const char *p) #define VSTRIMLEFT 0x8 /* ${var#pattern} */ #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */ #define VSLENGTH 0xa /* ${#var} */ -#if ENABLE_ASH_BASH_COMPAT +#if BASH_SUBSTR #define VSSUBSTR 0xc /* ${var:position:length} */ +#endif +#if BASH_PATTERN_SUBST #define VSREPLACE 0xd /* ${var/pattern/replacement} */ #define VSREPLACEALL 0xe /* ${var//pattern/replacement} */ #endif @@ -683,7 +701,7 @@ static const char dolatstr[] ALIGN1 = { #define NDEFUN 14 #define NARG 15 #define NTO 16 -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT #define NTO2 17 #endif #define NCLOBBER 18 @@ -1093,7 +1111,7 @@ shcmd(union node *cmd, FILE *fp) case NTO: s = ">>"+1; dftfd = 1; break; case NCLOBBER: s = ">|"; dftfd = 1; break; case NAPPEND: s = ">>"; dftfd = 1; break; -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT case NTO2: #endif case NTOFD: s = ">&"; dftfd = 1; break; @@ -4455,7 +4473,8 @@ cmdputs(const char *s) static const char vstype[VSTYPE + 1][3] = { "", "}", "-", "+", "?", "=", "%", "%%", "#", "##" - IF_ASH_BASH_COMPAT(, ":", "/", "//") + IF_BASH_SUBSTR(, ":") + IF_BASH_PATTERN_SUBST(, "/", "//") }; const char *p, *str; @@ -4682,7 +4701,7 @@ cmdtxt(union node *n) case NAPPEND: p = ">>"; goto redir; -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT case NTO2: #endif case NTOFD: @@ -5209,7 +5228,7 @@ openredirect(union node *redir) goto ecreate; break; case NTO: -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT case NTO2: #endif /* Take care of noclobber mode. */ @@ -5370,7 +5389,7 @@ redirect(union node *redir, int flags) union node *tmp = redir; do { sv_pos++; -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT if (tmp->nfile.type == NTO2) sv_pos++; #endif @@ -5412,7 +5431,7 @@ redirect(union node *redir, int flags) continue; } } -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT redirect_more: #endif if (need_to_remember(sv, fd)) { @@ -5465,12 +5484,12 @@ redirect(union node *redir, int flags) } } else if (fd != newfd) { /* move newfd to fd */ dup2_or_raise(newfd, fd); -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT if (!(redir->nfile.type == NTO2 && fd == 2)) #endif close(newfd); } -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT if (redir->nfile.type == NTO2 && fd == 1) { /* We already redirected it to fd 1, now copy it to 2 */ newfd = 1; @@ -5787,15 +5806,15 @@ static char * rmescapes(char *str, int flag) { static const char qchars[] ALIGN1 = { - IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' }; + IF_BASH_PATTERN_SUBST('/',) CTLESC, CTLQUOTEMARK, '\0' }; char *p, *q, *r; unsigned inquotes; unsigned protect_against_glob; unsigned globbing; - IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;) + IF_BASH_PATTERN_SUBST(unsigned slash = flag & RMESCAPE_SLASH;) - p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash)); + p = strpbrk(str, qchars IF_BASH_PATTERN_SUBST(+ !slash)); if (!p) return str; @@ -5847,7 +5866,7 @@ rmescapes(char *str, int flag) protect_against_glob = 0; goto copy; } -#if ENABLE_ASH_BASH_COMPAT +#if BASH_PATTERN_SUBST else if (*p == '/' && slash) { /* stop handling globbing and mark location of slash */ globbing = slash = 0; @@ -6494,10 +6513,10 @@ subevalvar(char *p, char *varname, int strloc, int subtype, char *loc; char *rmesc, *rmescend; char *str; - IF_ASH_BASH_COMPAT(char *repl = NULL;) - IF_ASH_BASH_COMPAT(int pos, len, orig_len;) + IF_BASH_SUBSTR(int pos, len, orig_len;) int amount, resetloc; - IF_ASH_BASH_COMPAT(int workloc;) + IF_BASH_PATTERN_SUBST(int workloc;) + IF_BASH_PATTERN_SUBST(char *repl = NULL;) int zero; char *(*scan)(char*, char*, char*, char*, int, int); @@ -6522,7 +6541,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, varunset(p, varname, startp, varflags); /* NOTREACHED */ -#if ENABLE_ASH_BASH_COMPAT +#if BASH_SUBSTR case VSSUBSTR: //TODO: support more general format ${v:EXPR:EXPR}, // where EXPR follows $(()) rules @@ -6591,17 +6610,19 @@ subevalvar(char *p, char *varname, int strloc, int subtype, amount = loc - expdest; STADJUST(amount, expdest); return loc; -#endif +#endif /* BASH_SUBSTR */ } resetloc = expdest - (char *)stackblock(); +#if BASH_PATTERN_SUBST /* We'll comeback here if we grow the stack while handling * a VSREPLACE or VSREPLACEALL, since our pointers into the * stack will need rebasing, and we'll need to remove our work * areas each time */ - IF_ASH_BASH_COMPAT(restart:) + restart: +#endif amount = expdest - ((char *)stackblock() + resetloc); STADJUST(-amount, expdest); @@ -6626,11 +6647,11 @@ subevalvar(char *p, char *varname, int strloc, int subtype, * RMESCAPE_SLASH causes preglob to work differently on the pattern * and string. It's only used on the first call. */ - preglob(str, IF_ASH_BASH_COMPAT( + preglob(str, IF_BASH_PATTERN_SUBST( (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ? - RMESCAPE_SLASH :) 0); + RMESCAPE_SLASH : ) 0); -#if ENABLE_ASH_BASH_COMPAT +#if BASH_PATTERN_SUBST workloc = expdest - (char *)stackblock(); if (subtype == VSREPLACE || subtype == VSREPLACEALL) { char *idx, *end; @@ -6731,7 +6752,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, STADJUST(-amount, expdest); return startp; } -#endif /* ENABLE_ASH_BASH_COMPAT */ +#endif /* BASH_PATTERN_SUBST */ subtype -= VSTRIMRIGHT; #if DEBUG @@ -6999,8 +7020,10 @@ evalvar(char *p, int flag, struct strlist *var_str_list) case VSTRIMLEFTMAX: case VSTRIMRIGHT: case VSTRIMRIGHTMAX: -#if ENABLE_ASH_BASH_COMPAT +#if BASH_SUBSTR case VSSUBSTR: +#endif +#if BASH_PATTERN_SUBST case VSREPLACE: case VSREPLACEALL: #endif @@ -7924,7 +7947,7 @@ enum { TESAC, TFI, TFOR, -#if ENABLE_ASH_BASH_COMPAT +#if BASH_FUNCTION TFUNCTION, #endif TIF, @@ -7962,7 +7985,7 @@ enum { /* 19 */ | (1u << TESAC) /* 20 */ | (1u << TFI) /* 21 */ | (0u << TFOR) -#if ENABLE_ASH_BASH_COMPAT +#if BASH_FUNCTION /* 22 */ | (0u << TFUNCTION) #endif /* 23 */ | (0u << TIF) @@ -8000,7 +8023,7 @@ static const char *const tokname_array[] = { "esac", "fi", "for", -#if ENABLE_ASH_BASH_COMPAT +#if BASH_FUNCTION "function", #endif "if", @@ -8244,7 +8267,7 @@ static const uint8_t nodesize[N_NUMBER] ALIGN1 = { [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)), [NARG ] = SHELL_ALIGN(sizeof(struct narg)), [NTO ] = SHELL_ALIGN(sizeof(struct nfile)), -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)), #endif [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)), @@ -8326,7 +8349,7 @@ calcsize(int funcblocksize, union node *n) funcblocksize = calcsize(funcblocksize, n->narg.next); break; case NTO: -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT case NTO2: #endif case NCLOBBER: @@ -8440,7 +8463,7 @@ copynode(union node *n) new->narg.next = copynode(n->narg.next); break; case NTO: -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT case NTO2: #endif case NCLOBBER: @@ -8873,14 +8896,14 @@ expredir(union node *n) case NFROMTO: case NFROM: case NTO: -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT case NTO2: #endif case NCLOBBER: case NAPPEND: expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); TRACE(("expredir expanded to '%s'\n", fn.list->text)); -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT store_expfname: #endif #if 0 @@ -8902,7 +8925,7 @@ expredir(union node *n) expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); if (fn.list == NULL) ash_msg_and_raise_error("redir error"); -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT //FIXME: we used expandarg with different args! if (!isdigit_str9(fn.list->text)) { /* >&file, not >&fd */ @@ -9298,7 +9321,7 @@ static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, a #if ENABLE_ASH_PRINTF static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); } #endif -#if ENABLE_ASH_TEST +#if ENABLE_ASH_TEST || BASH_TEST2 static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); } #endif @@ -9308,9 +9331,9 @@ static const struct builtincmd builtintab[] = { { BUILTIN_SPEC_REG ":" , truecmd }, #if ENABLE_ASH_TEST { BUILTIN_REGULAR "[" , testcmd }, -# if ENABLE_ASH_BASH_COMPAT +#endif +#if BASH_TEST2 { BUILTIN_REGULAR "[[" , testcmd }, -# endif #endif #if ENABLE_ASH_ALIAS { BUILTIN_REG_ASSG "alias" , aliascmd }, @@ -9363,7 +9386,7 @@ static const struct builtincmd builtintab[] = { { BUILTIN_SPEC_REG "return" , returncmd }, { BUILTIN_SPEC_REG "set" , setcmd }, { BUILTIN_SPEC_REG "shift" , shiftcmd }, -#if ENABLE_ASH_BASH_COMPAT +#if BASH_SOURCE { BUILTIN_SPEC_REG "source" , dotcmd }, #endif #if ENABLE_ASH_TEST @@ -9386,7 +9409,7 @@ static const struct builtincmd builtintab[] = { #define COMMANDCMD (builtintab + \ /* . : */ 2 + \ /* [ */ 1 * ENABLE_ASH_TEST + \ - /* [[ */ 1 * ENABLE_ASH_TEST * ENABLE_ASH_BASH_COMPAT + \ + /* [[ */ 1 * BASH_TEST2 + \ /* alias */ 1 * ENABLE_ASH_ALIAS + \ /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \ /* break cd cddir */ 3) @@ -11008,10 +11031,10 @@ simplecmd(void) union node *vars, **vpp; union node **rpp, *redir; int savecheckkwd; -#if ENABLE_ASH_BASH_COMPAT +#if BASH_TEST2 smallint double_brackets_flag = 0; - smallint function_flag = 0; #endif + IF_BASH_FUNCTION(smallint function_flag = 0;) args = NULL; app = &args; @@ -11026,12 +11049,14 @@ simplecmd(void) checkkwd = savecheckkwd; t = readtoken(); switch (t) { -#if ENABLE_ASH_BASH_COMPAT +#if BASH_FUNCTION case TFUNCTION: if (peektoken() != TWORD) raise_error_unexpected_syntax(TWORD); function_flag = 1; break; +#endif +#if BASH_TEST2 case TAND: /* "&&" */ case TOR: /* "||" */ if (!double_brackets_flag) { @@ -11045,7 +11070,7 @@ simplecmd(void) n->type = NARG; /*n->narg.next = NULL; - stzalloc did it */ n->narg.text = wordtext; -#if ENABLE_ASH_BASH_COMPAT +#if BASH_TEST2 if (strcmp("[[", wordtext) == 0) double_brackets_flag = 1; else if (strcmp("]]", wordtext) == 0) @@ -11060,7 +11085,7 @@ simplecmd(void) app = &n->narg.next; savecheckkwd = 0; } -#if ENABLE_ASH_BASH_COMPAT +#if BASH_FUNCTION if (function_flag) { checkkwd = CHKNL | CHKKWD; switch (peektoken()) { @@ -11090,7 +11115,7 @@ simplecmd(void) parsefname(); /* read name of redirection file */ break; case TLP: - IF_ASH_BASH_COMPAT(do_func:) + IF_BASH_FUNCTION(do_func:) if (args && app == &args->narg.next && !vars && !redir ) { @@ -11098,7 +11123,7 @@ simplecmd(void) const char *name; /* We have a function */ - if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP) + if (IF_BASH_FUNCTION(!function_flag &&) readtoken() != TRP) raise_error_unexpected_syntax(TRP); name = n->narg.text; if (!goodname(name) @@ -11111,7 +11136,7 @@ simplecmd(void) n->narg.next = parse_command(); return n; } - IF_ASH_BASH_COMPAT(function_flag = 0;) + IF_BASH_FUNCTION(function_flag = 0;) /* fall through */ default: tokpushback = 1; @@ -11292,7 +11317,7 @@ parse_command(void) n1 = list(0); t = TEND; break; - IF_ASH_BASH_COMPAT(case TFUNCTION:) + IF_BASH_FUNCTION(case TFUNCTION:) case TWORD: case TREDIR: tokpushback = 1; @@ -11325,7 +11350,7 @@ parse_command(void) return n1; } -#if ENABLE_ASH_BASH_COMPAT +#if BASH_DOLLAR_SQUOTE static int decode_dollar_squote(void) { @@ -11410,7 +11435,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */ int dqvarnest; /* levels of variables expansion within double quotes */ - IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;) + IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;) startlinno = g_parsefile->linno; bqlist = NULL; @@ -11445,7 +11470,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) USTPUTC(c, out); break; case CCTL: -#if ENABLE_ASH_BASH_COMPAT +#if BASH_DOLLAR_SQUOTE if (c == '\\' && bash_dollar_squote) { c = decode_dollar_squote(); if (c == '\0') { @@ -11506,7 +11531,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) dblquote = 1; goto quotemark; case CENDQUOTE: - IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) + IF_BASH_DOLLAR_SQUOTE(bash_dollar_squote = 0;) if (eofmark != NULL && varnest == 0) { USTPUTC(c, out); } else { @@ -11565,7 +11590,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) break; default: if (varnest == 0) { -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT if (c == '&') { //Can't call pgetc_eatbnl() here, this requires three-deep pungetc() if (pgetc() == '>') @@ -11597,7 +11622,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) len = out - (char *)stackblock(); out = stackblock(); if (eofmark == NULL) { - if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>')) + if ((c == '>' || c == '<' IF_BASH_REDIR_OUTPUT( || c == 0x100 + '>')) && quotef == 0 ) { if (isdigit_str9(out)) { @@ -11685,7 +11710,7 @@ parseredir: { pungetc(); } } -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT else if (c == 0x100 + '>') { /* this flags &> redirection */ np->nfile.fd = 1; pgetc(); /* this is '>', no need to check */ @@ -11751,7 +11776,7 @@ parsesub: { if (c > 255 /* PEOA or PEOF */ || (c != '(' && c != '{' && !is_name(c) && !is_special(c)) ) { -#if ENABLE_ASH_BASH_COMPAT +#if BASH_DOLLAR_SQUOTE if (syntax != DQSYNTAX && c == '\'') bash_dollar_squote = 1; else @@ -11827,7 +11852,7 @@ parsesub: { switch (c) { case ':': c = pgetc_eatbnl(); -#if ENABLE_ASH_BASH_COMPAT +#if BASH_SUBSTR /* This check is only needed to not misinterpret * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD} * constructs. @@ -11857,7 +11882,7 @@ parsesub: { subtype++; break; } -#if ENABLE_ASH_BASH_COMPAT +#if BASH_PATTERN_SUBST case '/': /* ${v/[/]pattern/repl} */ //TODO: encode pattern and repl separately. @@ -12112,7 +12137,7 @@ xxreadtoken(void) p += xxreadtoken_doubles + 1; } else { pungetc(); -#if ENABLE_ASH_BASH_COMPAT +#if BASH_REDIR_OUTPUT if (c == '&' && cc == '>') /* &> */ break; /* return readtoken1(...) */ #endif @@ -13274,9 +13299,11 @@ init(void) setvareq((char*)defoptindvar, VTEXTFIXED); setvar0("PPID", utoa(getppid())); -#if ENABLE_ASH_BASH_COMPAT +#if BASH_SHLVL_VAR p = lookupvar("SHLVL"); setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT); +#endif +#if BASH_HOSTNAME_VAR if (!lookupvar("HOSTNAME")) { struct utsname uts; uname(&uts); |