aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2015-05-18 09:57:51 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2015-05-18 09:57:51 +0200
commit549deab5abd59c1ab752754170f69aa2248e72c9 (patch)
tree91bfe638bd0a5e158c098f9f064559c533596c66 /shell
parentad88bdee0c382b9f1cbbb2d76cc739afb2790a60 (diff)
downloadbusybox-w32-549deab5abd59c1ab752754170f69aa2248e72c9.tar.gz
busybox-w32-549deab5abd59c1ab752754170f69aa2248e72c9.tar.bz2
busybox-w32-549deab5abd59c1ab752754170f69aa2248e72c9.zip
ash: move parse-time quote flag detection to run-time
Because the parser does not recursively parse parameter expansion with respect to quotes, we can't accurately determine quote status at parse time. This patch works around this by moving the quote detection to run-time where we do interpret it recursively. Test case: foo=\\ echo "<${foo#[\\]}>" Old result: <\> New result: <> Do not quote back slashes in parameter expansions outside quotes. Test case: a=/b/c/* b=\\ echo ${a%$b*} Old result: /b/c/* New result: /b/c/ Based on commits 880d952, 7cfd8be, 0d7d660 and a7c21a6 from git://git.kernel.org/pub/scm/utils/dash/dash.git by Herbert Xu function old new delta argstr 1164 1193 +29 memtodest 147 174 +27 subevalvar 1153 1177 +24 redirect 1279 1282 +3 dolatstr 5 7 +2 static.spclchars 10 9 -1 expandarg 962 960 -2 evalcase 273 271 -2 evalcommand 1204 1197 -7 rmescapes 236 227 -9 preglob 27 8 -19 evalvar 604 582 -22 cmdputs 389 334 -55 readtoken1 3163 3061 -102 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 5/9 up/down: 85/-219) Total: -134 bytes Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c164
-rw-r--r--shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right1
-rwxr-xr-xshell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests3
-rw-r--r--shell/ash_test/ash-vars/var-runtime-quote-detection.right1
-rwxr-xr-xshell/ash_test/ash-vars/var-runtime-quote-detection.tests1
5 files changed, 72 insertions, 98 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 33a477d80..e7e70817f 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -598,8 +598,6 @@ out2str(const char *p)
598#define CTLVAR ((unsigned char)'\202') /* variable defn */ 598#define CTLVAR ((unsigned char)'\202') /* variable defn */
599#define CTLENDVAR ((unsigned char)'\203') 599#define CTLENDVAR ((unsigned char)'\203')
600#define CTLBACKQ ((unsigned char)'\204') 600#define CTLBACKQ ((unsigned char)'\204')
601#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
602/* CTLBACKQ | CTLQUOTE == '\205' */
603#define CTLARI ((unsigned char)'\206') /* arithmetic expression */ 601#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
604#define CTLENDARI ((unsigned char)'\207') 602#define CTLENDARI ((unsigned char)'\207')
605#define CTLQUOTEMARK ((unsigned char)'\210') 603#define CTLQUOTEMARK ((unsigned char)'\210')
@@ -608,7 +606,6 @@ out2str(const char *p)
608/* variable substitution byte (follows CTLVAR) */ 606/* variable substitution byte (follows CTLVAR) */
609#define VSTYPE 0x0f /* type of variable substitution */ 607#define VSTYPE 0x0f /* type of variable substitution */
610#define VSNUL 0x10 /* colon--treat the empty string as unset */ 608#define VSNUL 0x10 /* colon--treat the empty string as unset */
611#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
612 609
613/* values of VSTYPE field */ 610/* values of VSTYPE field */
614#define VSNORMAL 0x1 /* normal variable: $var or ${var} */ 611#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
@@ -628,8 +625,9 @@ out2str(const char *p)
628#endif 625#endif
629 626
630static const char dolatstr[] ALIGN1 = { 627static const char dolatstr[] ALIGN1 = {
631 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' 628 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
632}; 629};
630#define DOLATSTRLEN 6
633 631
634#define NCMD 0 632#define NCMD 0
635#define NPIPE 1 633#define NPIPE 1
@@ -865,9 +863,7 @@ trace_puts_quoted(char *s)
865 case '\\': c = '\\'; goto backslash; 863 case '\\': c = '\\'; goto backslash;
866 case CTLESC: c = 'e'; goto backslash; 864 case CTLESC: c = 'e'; goto backslash;
867 case CTLVAR: c = 'v'; goto backslash; 865 case CTLVAR: c = 'v'; goto backslash;
868 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
869 case CTLBACKQ: c = 'q'; goto backslash; 866 case CTLBACKQ: c = 'q'; goto backslash;
870 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
871 backslash: 867 backslash:
872 putc('\\', tracefile); 868 putc('\\', tracefile);
873 putc(c, tracefile); 869 putc(c, tracefile);
@@ -1030,7 +1026,6 @@ sharg(union node *arg, FILE *fp)
1030 putc('}', fp); 1026 putc('}', fp);
1031 break; 1027 break;
1032 case CTLBACKQ: 1028 case CTLBACKQ:
1033 case CTLBACKQ|CTLQUOTE:
1034 putc('$', fp); 1029 putc('$', fp);
1035 putc('(', fp); 1030 putc('(', fp);
1036 shtree(bqlist->n, -1, NULL, fp); 1031 shtree(bqlist->n, -1, NULL, fp);
@@ -4413,11 +4408,7 @@ cmdputs(const char *s)
4413 str = "${#"; 4408 str = "${#";
4414 else 4409 else
4415 str = "${"; 4410 str = "${";
4416 if (!(subtype & VSQUOTE) == !(quoted & 1)) 4411 goto dostr;
4417 goto dostr;
4418 quoted ^= 1;
4419 c = '"';
4420 break;
4421 case CTLENDVAR: 4412 case CTLENDVAR:
4422 str = "\"}" + !(quoted & 1); 4413 str = "\"}" + !(quoted & 1);
4423 quoted >>= 1; 4414 quoted >>= 1;
@@ -4426,9 +4417,6 @@ cmdputs(const char *s)
4426 case CTLBACKQ: 4417 case CTLBACKQ:
4427 str = "$(...)"; 4418 str = "$(...)";
4428 goto dostr; 4419 goto dostr;
4429 case CTLBACKQ+CTLQUOTE:
4430 str = "\"$(...)\"";
4431 goto dostr;
4432#if ENABLE_SH_MATH_SUPPORT 4420#if ENABLE_SH_MATH_SUPPORT
4433 case CTLARI: 4421 case CTLARI:
4434 str = "$(("; 4422 str = "$((";
@@ -5526,7 +5514,7 @@ ash_arith(const char *s)
5526#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ 5514#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5527#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ 5515#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5528#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ 5516#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5529#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ 5517#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
5530#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ 5518#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5531#define EXP_WORD 0x80 /* expand word in parameter expansion */ 5519#define EXP_WORD 0x80 /* expand word in parameter expansion */
5532#define EXP_QUOTED 0x100 /* expand word in double quotes */ 5520#define EXP_QUOTED 0x100 /* expand word in double quotes */
@@ -5535,12 +5523,11 @@ ash_arith(const char *s)
5535 */ 5523 */
5536#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ 5524#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5537#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ 5525#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5538#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5539#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ 5526#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5540#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ 5527#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5541 5528
5542/* Add CTLESC when necessary. */ 5529/* Add CTLESC when necessary. */
5543#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_REDIR) 5530#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
5544/* Do not skip NUL characters. */ 5531/* Do not skip NUL characters. */
5545#define QUOTES_KEEPNUL EXP_TILDE 5532#define QUOTES_KEEPNUL EXP_TILDE
5546 5533
@@ -5641,13 +5628,11 @@ rmescapes(char *str, int flag)
5641 } 5628 }
5642 } 5629 }
5643 5630
5644 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; 5631 inquotes = 0;
5645 globbing = flag & RMESCAPE_GLOB; 5632 globbing = flag & RMESCAPE_GLOB;
5646 protect_against_glob = globbing; 5633 protect_against_glob = globbing;
5647 while (*p) { 5634 while (*p) {
5648 if ((unsigned char)*p == CTLQUOTEMARK) { 5635 if ((unsigned char)*p == CTLQUOTEMARK) {
5649// TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0
5650// (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok?
5651// Note: both inquotes and protect_against_glob only affect whether 5636// Note: both inquotes and protect_against_glob only affect whether
5652// CTLESC,<ch> gets converted to <ch> or to \<ch> 5637// CTLESC,<ch> gets converted to <ch> or to \<ch>
5653 inquotes = ~inquotes; 5638 inquotes = ~inquotes;
@@ -5655,16 +5640,15 @@ rmescapes(char *str, int flag)
5655 protect_against_glob = globbing; 5640 protect_against_glob = globbing;
5656 continue; 5641 continue;
5657 } 5642 }
5658 if (*p == '\\') {
5659 /* naked back slash */
5660 protect_against_glob = 0;
5661 goto copy;
5662 }
5663 if ((unsigned char)*p == CTLESC) { 5643 if ((unsigned char)*p == CTLESC) {
5664 p++; 5644 p++;
5665 if (protect_against_glob && inquotes && *p != '/') { 5645 if (protect_against_glob) {
5666 *q++ = '\\'; 5646 *q++ = '\\';
5667 } 5647 }
5648 } else if (*p == '\\' && !inquotes) {
5649 /* naked back slash */
5650 protect_against_glob = 0;
5651 goto copy;
5668 } 5652 }
5669 protect_against_glob = globbing; 5653 protect_against_glob = globbing;
5670 copy: 5654 copy:
@@ -5685,13 +5669,9 @@ rmescapes(char *str, int flag)
5685 * Returns an stalloced string. 5669 * Returns an stalloced string.
5686 */ 5670 */
5687static char * 5671static char *
5688preglob(const char *pattern, int quoted, int flag) 5672preglob(const char *pattern, int flag)
5689{ 5673{
5690 flag |= RMESCAPE_GLOB; 5674 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
5691 if (quoted) {
5692 flag |= RMESCAPE_QUOTED;
5693 }
5694 return rmescapes((char *)pattern, flag);
5695} 5675}
5696 5676
5697/* 5677/*
@@ -5712,7 +5692,9 @@ memtodest(const char *p, size_t len, int syntax, int quotes)
5712 if (c) { 5692 if (c) {
5713 int n = SIT(c, syntax); 5693 int n = SIT(c, syntax);
5714 if ((quotes & QUOTES_ESC) && 5694 if ((quotes & QUOTES_ESC) &&
5715 (n == CCTL || n == CBACK)) 5695 ((n == CCTL) ||
5696 (((quotes & EXP_FULL) || syntax != BASESYNTAX) &&
5697 n == CBACK)))
5716 USTPUTC(CTLESC, q); 5698 USTPUTC(CTLESC, q);
5717 } else if (!(quotes & QUOTES_KEEPNUL)) 5699 } else if (!(quotes & QUOTES_KEEPNUL))
5718 continue; 5700 continue;
@@ -5905,7 +5887,7 @@ evalbackcmd(union node *n, struct backcmd *result)
5905 * Expand stuff in backwards quotes. 5887 * Expand stuff in backwards quotes.
5906 */ 5888 */
5907static void 5889static void
5908expbackq(union node *cmd, int quoted, int quotes) 5890expbackq(union node *cmd, int flag)
5909{ 5891{
5910 struct backcmd in; 5892 struct backcmd in;
5911 int i; 5893 int i;
@@ -5913,7 +5895,7 @@ expbackq(union node *cmd, int quoted, int quotes)
5913 char *p; 5895 char *p;
5914 char *dest; 5896 char *dest;
5915 int startloc; 5897 int startloc;
5916 int syntax = quoted ? DQSYNTAX : BASESYNTAX; 5898 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
5917 struct stackmark smark; 5899 struct stackmark smark;
5918 5900
5919 INT_OFF; 5901 INT_OFF;
@@ -5929,7 +5911,7 @@ expbackq(union node *cmd, int quoted, int quotes)
5929 if (i == 0) 5911 if (i == 0)
5930 goto read; 5912 goto read;
5931 for (;;) { 5913 for (;;) {
5932 memtodest(p, i, syntax, quotes); 5914 memtodest(p, i, syntax, flag & QUOTES_ESC);
5933 read: 5915 read:
5934 if (in.fd < 0) 5916 if (in.fd < 0)
5935 break; 5917 break;
@@ -5953,7 +5935,7 @@ expbackq(union node *cmd, int quoted, int quotes)
5953 STUNPUTC(dest); 5935 STUNPUTC(dest);
5954 expdest = dest; 5936 expdest = dest;
5955 5937
5956 if (quoted == 0) 5938 if (!(flag & EXP_QUOTED))
5957 recordregion(startloc, dest - (char *)stackblock(), 0); 5939 recordregion(startloc, dest - (char *)stackblock(), 0);
5958 TRACE(("evalbackq: size:%d:'%.*s'\n", 5940 TRACE(("evalbackq: size:%d:'%.*s'\n",
5959 (int)((dest - (char *)stackblock()) - startloc), 5941 (int)((dest - (char *)stackblock()) - startloc),
@@ -5967,11 +5949,10 @@ expbackq(union node *cmd, int quoted, int quotes)
5967 * evaluate, place result in (backed up) result, adjust string position. 5949 * evaluate, place result in (backed up) result, adjust string position.
5968 */ 5950 */
5969static void 5951static void
5970expari(int quotes) 5952expari(int flag)
5971{ 5953{
5972 char *p, *start; 5954 char *p, *start;
5973 int begoff; 5955 int begoff;
5974 int flag;
5975 int len; 5956 int len;
5976 5957
5977 /* ifsfree(); */ 5958 /* ifsfree(); */
@@ -6009,16 +5990,14 @@ expari(int quotes)
6009 5990
6010 removerecordregions(begoff); 5991 removerecordregions(begoff);
6011 5992
6012 flag = p[1];
6013
6014 expdest = p; 5993 expdest = p;
6015 5994
6016 if (quotes) 5995 if (flag & QUOTES_ESC)
6017 rmescapes(p + 2, 0); 5996 rmescapes(p + 1, 0);
6018 5997
6019 len = cvtnum(ash_arith(p + 2)); 5998 len = cvtnum(ash_arith(p + 1));
6020 5999
6021 if (flag != '"') 6000 if (!(flag & EXP_QUOTED))
6022 recordregion(begoff, begoff + len, 0); 6001 recordregion(begoff, begoff + len, 0);
6023} 6002}
6024#endif 6003#endif
@@ -6046,14 +6025,12 @@ argstr(char *p, int flags, struct strlist *var_str_list)
6046 CTLESC, 6025 CTLESC,
6047 CTLVAR, 6026 CTLVAR,
6048 CTLBACKQ, 6027 CTLBACKQ,
6049 CTLBACKQ | CTLQUOTE,
6050#if ENABLE_SH_MATH_SUPPORT 6028#if ENABLE_SH_MATH_SUPPORT
6051 CTLENDARI, 6029 CTLENDARI,
6052#endif 6030#endif
6053 '\0' 6031 '\0'
6054 }; 6032 };
6055 const char *reject = spclchars; 6033 const char *reject = spclchars;
6056 int quotes = flags & QUOTES_ESC;
6057 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD; 6034 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
6058 int inquotes; 6035 int inquotes;
6059 size_t length; 6036 size_t length;
@@ -6128,19 +6105,14 @@ argstr(char *p, int flags, struct strlist *var_str_list)
6128 case CTLENDVAR: /* ??? */ 6105 case CTLENDVAR: /* ??? */
6129 goto breakloop; 6106 goto breakloop;
6130 case CTLQUOTEMARK: 6107 case CTLQUOTEMARK:
6108 inquotes ^= EXP_QUOTED;
6131 /* "$@" syntax adherence hack */ 6109 /* "$@" syntax adherence hack */
6132 if (!inquotes 6110 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6133 && memcmp(p, dolatstr, 4) == 0 6111 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
6134 && ( p[4] == (char)CTLQUOTEMARK
6135 || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK)
6136 )
6137 ) {
6138 p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1;
6139 goto start; 6112 goto start;
6140 } 6113 }
6141 inquotes = !inquotes;
6142 addquote: 6114 addquote:
6143 if (quotes) { 6115 if (flags & QUOTES_ESC) {
6144 p--; 6116 p--;
6145 length++; 6117 length++;
6146 startloc++; 6118 startloc++;
@@ -6149,22 +6121,30 @@ argstr(char *p, int flags, struct strlist *var_str_list)
6149 case CTLESC: 6121 case CTLESC:
6150 startloc++; 6122 startloc++;
6151 length++; 6123 length++;
6124
6125 /*
6126 * Quoted parameter expansion pattern: remove quote
6127 * unless inside inner quotes or we have a literal
6128 * backslash.
6129 */
6130 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6131 EXP_QPAT && *p != '\\')
6132 break;
6133
6152 goto addquote; 6134 goto addquote;
6153 case CTLVAR: 6135 case CTLVAR:
6154 TRACE(("argstr: evalvar('%s')\n", p)); 6136 TRACE(("argstr: evalvar('%s')\n", p));
6155 p = evalvar(p, flags, var_str_list); 6137 p = evalvar(p, flags | inquotes, var_str_list);
6156 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); 6138 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
6157 goto start; 6139 goto start;
6158 case CTLBACKQ: 6140 case CTLBACKQ:
6159 c = '\0'; 6141 expbackq(argbackq->n, flags | inquotes);
6160 case CTLBACKQ|CTLQUOTE:
6161 expbackq(argbackq->n, c, quotes);
6162 argbackq = argbackq->next; 6142 argbackq = argbackq->next;
6163 goto start; 6143 goto start;
6164#if ENABLE_SH_MATH_SUPPORT 6144#if ENABLE_SH_MATH_SUPPORT
6165 case CTLENDARI: 6145 case CTLENDARI:
6166 p--; 6146 p--;
6167 expari(quotes); 6147 expari(flags | inquotes);
6168 goto start; 6148 goto start;
6169#endif 6149#endif
6170 } 6150 }
@@ -6296,13 +6276,13 @@ varunset(const char *end, const char *var, const char *umsg, int varflags)
6296 6276
6297#if ENABLE_ASH_BASH_COMPAT 6277#if ENABLE_ASH_BASH_COMPAT
6298static char * 6278static char *
6299parse_sub_pattern(char *arg, int varflags) 6279parse_sub_pattern(char *arg, int quoted)
6300{ 6280{
6301 char *idx, *repl = NULL; 6281 char *idx, *repl = NULL;
6302 unsigned char c; 6282 unsigned char c;
6303 6283
6304 //char *org_arg = arg; 6284 //char *org_arg = arg;
6305 //bb_error_msg("arg:'%s' varflags:%x", arg, varflags); 6285 //bb_error_msg("arg:'%s' quoted:%x", arg, quoted);
6306 idx = arg; 6286 idx = arg;
6307 while (1) { 6287 while (1) {
6308 c = *arg; 6288 c = *arg;
@@ -6318,7 +6298,7 @@ parse_sub_pattern(char *arg, int varflags)
6318 *idx++ = c; 6298 *idx++ = c;
6319 arg++; 6299 arg++;
6320 /* 6300 /*
6321 * Example: v='ab\c'; echo ${v/\\b/_\\_\z_} 6301 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6322 * The result is a_\_z_c (not a\_\_z_c)! 6302 * The result is a_\_z_c (not a\_\_z_c)!
6323 * 6303 *
6324 * Enable debug prints in this function and you'll see: 6304 * Enable debug prints in this function and you'll see:
@@ -6328,7 +6308,7 @@ parse_sub_pattern(char *arg, int varflags)
6328 * IOW: search pattern and replace string treat backslashes 6308 * IOW: search pattern and replace string treat backslashes
6329 * differently! That is the reason why we check repl below: 6309 * differently! That is the reason why we check repl below:
6330 */ 6310 */
6331 if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE)) 6311 if (c == '\\' && *arg == '\\' && repl && !quoted)
6332 arg++; /* skip both '\', not just first one */ 6312 arg++; /* skip both '\', not just first one */
6333 } 6313 }
6334 *idx = c; /* NUL */ 6314 *idx = c; /* NUL */
@@ -6340,9 +6320,10 @@ parse_sub_pattern(char *arg, int varflags)
6340 6320
6341static const char * 6321static const char *
6342subevalvar(char *p, char *varname, int strloc, int subtype, 6322subevalvar(char *p, char *varname, int strloc, int subtype,
6343 int startloc, int varflags, int quotes, struct strlist *var_str_list) 6323 int startloc, int varflags, int flag, struct strlist *var_str_list)
6344{ 6324{
6345 struct nodelist *saveargbackq = argbackq; 6325 struct nodelist *saveargbackq = argbackq;
6326 int quotes = flag & QUOTES_ESC;
6346 char *startp; 6327 char *startp;
6347 char *loc; 6328 char *loc;
6348 char *rmesc, *rmescend; 6329 char *rmesc, *rmescend;
@@ -6360,7 +6341,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6360 6341
6361 herefd = -1; 6342 herefd = -1;
6362 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? 6343 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
6363 EXP_CASE : 0), var_str_list); 6344 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6345 var_str_list);
6364 STPUTC('\0', expdest); 6346 STPUTC('\0', expdest);
6365 herefd = saveherefd; 6347 herefd = saveherefd;
6366 argbackq = saveargbackq; 6348 argbackq = saveargbackq;
@@ -6471,7 +6453,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6471 } 6453 }
6472 rmescend--; 6454 rmescend--;
6473 str = (char *)stackblock() + strloc; 6455 str = (char *)stackblock() + strloc;
6474 preglob(str, varflags & VSQUOTE, 0); 6456 preglob(str, 0);
6475 6457
6476#if ENABLE_ASH_BASH_COMPAT 6458#if ENABLE_ASH_BASH_COMPAT
6477 workloc = expdest - (char *)stackblock(); 6459 workloc = expdest - (char *)stackblock();
@@ -6479,7 +6461,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
6479 char *idx, *end; 6461 char *idx, *end;
6480 6462
6481 if (!repl) { 6463 if (!repl) {
6482 repl = parse_sub_pattern(str, varflags); 6464 repl = parse_sub_pattern(str, flag & EXP_QUOTED);
6483 //bb_error_msg("repl:'%s'", repl); 6465 //bb_error_msg("repl:'%s'", repl);
6484 if (!repl) 6466 if (!repl)
6485 repl = nullstr; 6467 repl = nullstr;
@@ -6618,7 +6600,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
6618 int i; 6600 int i;
6619 ssize_t len = 0; 6601 ssize_t len = 0;
6620 int sep; 6602 int sep;
6621 int quoted = varflags & VSQUOTE; 6603 int quoted = flags & EXP_QUOTED;
6622 int subtype = varflags & VSTYPE; 6604 int subtype = varflags & VSTYPE;
6623 int discard = subtype == VSPLUS || subtype == VSLENGTH; 6605 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6624 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; 6606 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
@@ -6758,7 +6740,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
6758{ 6740{
6759 char varflags; 6741 char varflags;
6760 char subtype; 6742 char subtype;
6761 char quoted; 6743 int quoted;
6762 char easy; 6744 char easy;
6763 char *var; 6745 char *var;
6764 int patloc; 6746 int patloc;
@@ -6767,7 +6749,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
6767 6749
6768 varflags = (unsigned char) *p++; 6750 varflags = (unsigned char) *p++;
6769 subtype = varflags & VSTYPE; 6751 subtype = varflags & VSTYPE;
6770 quoted = varflags & VSQUOTE; 6752 quoted = flags & EXP_QUOTED;
6771 var = p; 6753 var = p;
6772 easy = (!quoted || (*var == '@' && shellparam.nparam)); 6754 easy = (!quoted || (*var == '@' && shellparam.nparam));
6773 startloc = expdest - (char *)stackblock(); 6755 startloc = expdest - (char *)stackblock();
@@ -6788,7 +6770,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
6788 if (varlen < 0) { 6770 if (varlen < 0) {
6789 argstr( 6771 argstr(
6790 p, 6772 p,
6791 flags | EXP_TILDE | EXP_WORD | (quoted ? EXP_QUOTED : 0), 6773 flags | EXP_TILDE | EXP_WORD,
6792 var_str_list 6774 var_str_list
6793 ); 6775 );
6794 goto end; 6776 goto end;
@@ -6802,7 +6784,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
6802 if (varlen < 0) { 6784 if (varlen < 0) {
6803 if (subevalvar(p, var, /* strloc: */ 0, 6785 if (subevalvar(p, var, /* strloc: */ 0,
6804 subtype, startloc, varflags, 6786 subtype, startloc, varflags,
6805 /* quotes: */ 0, 6787 /* quotes: */ flags & ~QUOTES_ESC,
6806 var_str_list) 6788 var_str_list)
6807 ) { 6789 ) {
6808 varflags &= ~VSNUL; 6790 varflags &= ~VSNUL;
@@ -6859,10 +6841,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
6859 STPUTC('\0', expdest); 6841 STPUTC('\0', expdest);
6860 patloc = expdest - (char *)stackblock(); 6842 patloc = expdest - (char *)stackblock();
6861 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, 6843 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
6862 startloc, varflags, 6844 startloc, varflags, flags, var_str_list)) {
6863 /* quotes: */ flags & QUOTES_ESC,
6864 var_str_list)
6865 ) {
6866 int amount = expdest - ( 6845 int amount = expdest - (
6867 (char *)stackblock() + patloc - 1 6846 (char *)stackblock() + patloc - 1
6868 ); 6847 );
@@ -6881,7 +6860,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
6881 unsigned char c = *p++; 6860 unsigned char c = *p++;
6882 if (c == CTLESC) 6861 if (c == CTLESC)
6883 p++; 6862 p++;
6884 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 6863 else if (c == CTLBACKQ) {
6885 if (varlen >= 0) 6864 if (varlen >= 0)
6886 argbackq = argbackq->next; 6865 argbackq = argbackq->next;
6887 } else if (c == CTLVAR) { 6866 } else if (c == CTLVAR) {
@@ -7217,7 +7196,7 @@ expandmeta(struct strlist *str /*, int flag*/)
7217 savelastp = exparg.lastp; 7196 savelastp = exparg.lastp;
7218 7197
7219 INT_OFF; 7198 INT_OFF;
7220 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); 7199 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7221 { 7200 {
7222 int i = strlen(str->text); 7201 int i = strlen(str->text);
7223 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ 7202 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
@@ -7307,7 +7286,7 @@ static void
7307expandhere(union node *arg, int fd) 7286expandhere(union node *arg, int fd)
7308{ 7287{
7309 herefd = fd; 7288 herefd = fd;
7310 expandarg(arg, (struct arglist *)NULL, 0); 7289 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
7311 full_write(fd, stackblock(), expdest - (char *)stackblock()); 7290 full_write(fd, stackblock(), expdest - (char *)stackblock());
7312} 7291}
7313 7292
@@ -7317,7 +7296,7 @@ expandhere(union node *arg, int fd)
7317static int 7296static int
7318patmatch(char *pattern, const char *string) 7297patmatch(char *pattern, const char *string)
7319{ 7298{
7320 return pmatch(preglob(pattern, 0, 0), string); 7299 return pmatch(preglob(pattern, 0), string);
7321} 7300}
7322 7301
7323/* 7302/*
@@ -8570,7 +8549,7 @@ evalfor(union node *n, int flags)
8570 arglist.list = NULL; 8549 arglist.list = NULL;
8571 arglist.lastp = &arglist.list; 8550 arglist.lastp = &arglist.list;
8572 for (argp = n->nfor.args; argp; argp = argp->narg.next) { 8551 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
8573 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); 8552 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
8574 /* XXX */ 8553 /* XXX */
8575 if (evalskip) 8554 if (evalskip)
8576 goto out; 8555 goto out;
@@ -11260,11 +11239,9 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11260 && c != '$' 11239 && c != '$'
11261 && (c != '"' || eofmark != NULL) 11240 && (c != '"' || eofmark != NULL)
11262 ) { 11241 ) {
11263 USTPUTC(CTLESC, out);
11264 USTPUTC('\\', out); 11242 USTPUTC('\\', out);
11265 } 11243 }
11266 if (SIT(c, SQSYNTAX) == CCTL) 11244 USTPUTC(CTLESC, out);
11267 USTPUTC(CTLESC, out);
11268 USTPUTC(c, out); 11245 USTPUTC(c, out);
11269 quotef = 1; 11246 quotef = 1;
11270 } 11247 }
@@ -11637,8 +11614,6 @@ parsesub: {
11637 do_pungetc: 11614 do_pungetc:
11638 pungetc(); 11615 pungetc();
11639 } 11616 }
11640 if (dblquote || arinest)
11641 flags |= VSQUOTE;
11642 ((unsigned char *)stackblock())[typeloc] = subtype | flags; 11617 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
11643 if (subtype != VSNORMAL) { 11618 if (subtype != VSNORMAL) {
11644 varnest++; 11619 varnest++;
@@ -11792,10 +11767,7 @@ parsebackq: {
11792 } 11767 }
11793 parsebackquote = savepbq; 11768 parsebackquote = savepbq;
11794 exception_handler = savehandler; 11769 exception_handler = savehandler;
11795 if (arinest || dblquote) 11770 USTPUTC(CTLBACKQ, out);
11796 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11797 else
11798 USTPUTC(CTLBACKQ, out);
11799 if (oldstyle) 11771 if (oldstyle)
11800 goto parsebackq_oldreturn; 11772 goto parsebackq_oldreturn;
11801 goto parsebackq_newreturn; 11773 goto parsebackq_newreturn;
@@ -11811,10 +11783,6 @@ parsearith: {
11811 syntax = ARISYNTAX; 11783 syntax = ARISYNTAX;
11812 } 11784 }
11813 USTPUTC(CTLARI, out); 11785 USTPUTC(CTLARI, out);
11814 if (dblquote)
11815 USTPUTC('"', out);
11816 else
11817 USTPUTC(' ', out);
11818 goto parsearith_return; 11786 goto parsearith_return;
11819} 11787}
11820#endif 11788#endif
@@ -12129,7 +12097,7 @@ expandstr(const char *ps)
12129 n.narg.text = wordtext; 12097 n.narg.text = wordtext;
12130 n.narg.backquote = backquotelist; 12098 n.narg.backquote = backquotelist;
12131 12099
12132 expandarg(&n, NULL, 0); 12100 expandarg(&n, NULL, EXP_QUOTED);
12133 return stackblock(); 12101 return stackblock();
12134} 12102}
12135#endif 12103#endif
diff --git a/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right
new file mode 100644
index 000000000..030ebdeb6
--- /dev/null
+++ b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right
@@ -0,0 +1 @@
/b/c/
diff --git a/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests
new file mode 100755
index 000000000..fb9371467
--- /dev/null
+++ b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests
@@ -0,0 +1,3 @@
1a=/b/c/*
2b=\\
3echo ${a%$b*}
diff --git a/shell/ash_test/ash-vars/var-runtime-quote-detection.right b/shell/ash_test/ash-vars/var-runtime-quote-detection.right
new file mode 100644
index 000000000..b554d9e46
--- /dev/null
+++ b/shell/ash_test/ash-vars/var-runtime-quote-detection.right
@@ -0,0 +1 @@
<>
diff --git a/shell/ash_test/ash-vars/var-runtime-quote-detection.tests b/shell/ash_test/ash-vars/var-runtime-quote-detection.tests
new file mode 100755
index 000000000..e570631fd
--- /dev/null
+++ b/shell/ash_test/ash-vars/var-runtime-quote-detection.tests
@@ -0,0 +1 @@
foo=\\ echo "<${foo#[\\]}>"