hush: fix handling of backslashes in variable assignment

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
This commit is contained in:
Denys Vlasenko 2010-09-04 19:52:44 +02:00
parent 8ae6e9be5c
commit e298ce69ba
5 changed files with 74 additions and 41 deletions

View File

@ -1,5 +1,5 @@
# This testcase checks whether slashes in ${v/a/b} are parsed before or after expansions # This testcase checks whether slashes in ${v/a/b} are parsed before
# in a part # or after expansions
v='a/b/c' v='a/b/c'
s='b/c' s='b/c'

View File

@ -390,6 +390,7 @@ typedef struct o_string {
smallint o_glob; smallint o_glob;
/* At least some part of the string was inside '' or "", /* At least some part of the string was inside '' or "",
* possibly empty one: word"", wo''rd etc. */ * possibly empty one: word"", wo''rd etc. */
//TODO: rename to no_empty_expansion?
smallint o_quoted; smallint o_quoted;
smallint has_empty_slot; smallint has_empty_slot;
smallint o_assignment; /* 0:maybe, 1:yes, 2:no */ smallint o_assignment; /* 0:maybe, 1:yes, 2:no */
@ -2018,11 +2019,10 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len
{ {
while (len) { while (len) {
o_addchr(o, *str); o_addchr(o, *str);
if (*str++ == '\\' if (*str == '\\') {
&& (*str != '*' && *str != '?' && *str != '[')
) {
o_addchr(o, '\\'); o_addchr(o, '\\');
} }
str++;
len--; len--;
} }
} }
@ -2128,8 +2128,8 @@ static void debug_print_list(const char *prefix, o_string *o, int n)
int i = 0; int i = 0;
indent(); indent();
fprintf(stderr, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d\n", fprintf(stderr, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d glob:%d quoted:%d escape:%d\n",
prefix, list, n, string_start, o->length, o->maxlen); prefix, list, n, string_start, o->length, o->maxlen, o->o_glob, o->o_quoted, o->o_escape);
while (i < n) { while (i < n) {
indent(); indent();
fprintf(stderr, " list[%d]=%d '%s' %p\n", i, (int)list[i], fprintf(stderr, " list[%d]=%d '%s' %p\n", i, (int)list[i],
@ -2563,9 +2563,9 @@ static char *expand_pseudo_dquoted(const char *str)
struct in_str input; struct in_str input;
o_string dest = NULL_O_STRING; o_string dest = NULL_O_STRING;
if (strchr(str, '$') == NULL if (!strchr(str, '$')
#if ENABLE_HUSH_TICK #if ENABLE_HUSH_TICK
&& strchr(str, '`') == NULL && !strchr(str, '`')
#endif #endif
) { ) {
return NULL; return NULL;
@ -2740,6 +2740,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char
} }
#endif #endif
default: { /* <SPECIAL_VAR_SYMBOL>varname<SPECIAL_VAR_SYMBOL> */ default: { /* <SPECIAL_VAR_SYMBOL>varname<SPECIAL_VAR_SYMBOL> */
//TODO: move to a subroutine?
char *var; char *var;
char first_char; char first_char;
char exp_op; char exp_op;
@ -3000,18 +3001,22 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char
return n; return n;
} }
static char **expand_variables(char **argv, int or_mask) enum {
EXPVAR_FLAG_GLOB = 0x200,
EXPVAR_FLAG_ESCAPE_VARS = 0x100,
EXPVAR_FLAG_SINGLEWORD = 0x80, /* must be 0x80 */
};
static char **expand_variables(char **argv, unsigned or_mask)
{ {
int n; int n;
char **list; char **list;
char **v; char **v;
o_string output = NULL_O_STRING; o_string output = NULL_O_STRING;
if (or_mask & 0x100) { /* protect against globbing for "$var"? */
output.o_escape = 1; /* protect against globbing for "$var" */ /* (unquoted $var will temporarily switch it off) */
/* (unquoted $var will temporarily switch it off) */ output.o_escape = 1 & (or_mask / EXPVAR_FLAG_ESCAPE_VARS);
output.o_glob = 1; output.o_glob = 1 & (or_mask / EXPVAR_FLAG_GLOB);
}
n = 0; n = 0;
v = argv; v = argv;
@ -3029,13 +3034,13 @@ static char **expand_variables(char **argv, int or_mask)
static char **expand_strvec_to_strvec(char **argv) static char **expand_strvec_to_strvec(char **argv)
{ {
return expand_variables(argv, 0x100); return expand_variables(argv, EXPVAR_FLAG_GLOB | EXPVAR_FLAG_ESCAPE_VARS);
} }
#if ENABLE_HUSH_BASH_COMPAT #if ENABLE_HUSH_BASH_COMPAT
static char **expand_strvec_to_strvec_singleword_noglob(char **argv) static char **expand_strvec_to_strvec_singleword_noglob(char **argv)
{ {
return expand_variables(argv, 0x80); return expand_variables(argv, EXPVAR_FLAG_SINGLEWORD);
} }
#endif #endif
@ -3075,15 +3080,15 @@ static char **expand_strvec_to_strvec_singleword_noglob_cond(char **argv)
#endif #endif
/* Used for expansion of right hand of assignments */ /* Used for expansion of right hand of assignments */
/* NB: should NOT do globbing! "export v=/bin/c*; env | grep ^v=" outputs /* NB: should NOT do globbing!
* "v=/bin/c*" */ * "export v=/bin/c*; env | grep ^v=" outputs "v=/bin/c*" */
static char *expand_string_to_string(const char *str) static char *expand_string_to_string(const char *str)
{ {
char *argv[2], **list; char *argv[2], **list;
argv[0] = (char*)str; argv[0] = (char*)str;
argv[1] = NULL; argv[1] = NULL;
list = expand_variables(argv, 0x80); /* 0x80: singleword expansion */ list = expand_variables(argv, EXPVAR_FLAG_ESCAPE_VARS | EXPVAR_FLAG_SINGLEWORD);
if (HUSH_DEBUG) if (HUSH_DEBUG)
if (!list[0] || list[1]) if (!list[0] || list[1])
bb_error_msg_and_die("BUG in varexp2"); bb_error_msg_and_die("BUG in varexp2");
@ -3099,7 +3104,7 @@ static char* expand_strvec_to_string(char **argv)
{ {
char **list; char **list;
list = expand_variables(argv, 0x80); list = expand_variables(argv, EXPVAR_FLAG_SINGLEWORD);
/* Convert all NULs to spaces */ /* Convert all NULs to spaces */
if (list[0]) { if (list[0]) {
int n = 1; int n = 1;

View File

@ -0,0 +1,11 @@
b1=-qwerty-t-\-"---z-*-?-
b1=-qwerty-t-\-"---z-*-?-
b2=-qwerty-\t-\-"-\--\z-\*-\?-
b2=-qwerty-\t-\-"-\--\z-\*-\?-
b3=-$a-\t-\\-\"-\--\z-\*-\?-
b3=-$a-\t-\\-\"-\--\z-\*-\?-
c=-$a-\t-\\-\"-\--\z-\*-\?-
c=-$a-\t-\\-\"-\--\z-\*-\?-
c=-$a-\t-\\-\"-\--\z-\*-\?-
c=-$a-\t-\\-\"-\--\z-\*-\?-
Done: 0

View File

@ -0,0 +1,23 @@
# Test for correct handling of backslashes
a=qwerty
b=-$a-\t-\\-\"-\--\z-\*-\?-
echo b1=$b
echo "b1=$b"
b="-$a-\t-\\-\"-\--\z-\*-\?-"
echo b2=$b
echo "b2=$b"
b='-$a-\t-\\-\"-\--\z-\*-\?-'
echo b3=$b
echo "b3=$b"
c=$b
echo "c=$c"
c=${b}
echo "c=$c"
c="$b"
echo "c=$c"
c="${b}"
echo "c=$c"
echo "Done: $?"

View File

@ -31,26 +31,23 @@ char *scanleft(char *string, char *pattern, bool match_at_left)
char c; char c;
char *loc = string; char *loc = string;
do { while (1) {
int match; int match;
const char *s;
c = *loc; c = *loc;
if (match_at_left) { if (match_at_left) {
*loc = '\0'; *loc = '\0';
s = string; match = pmatch(pattern, string);
} else *loc = c;
s = loc; } else {
match = pmatch(pattern, s); match = pmatch(pattern, loc);
*loc = c; }
if (match) if (match)
return loc; return loc;
if (!c)
return NULL;
loc++; loc++;
} while (c); }
return NULL;
} }
char *scanright(char *string, char *pattern, bool match_at_left) char *scanright(char *string, char *pattern, bool match_at_left)
@ -60,20 +57,17 @@ char *scanright(char *string, char *pattern, bool match_at_left)
while (loc >= string) { while (loc >= string) {
int match; int match;
const char *s;
c = *loc; c = *loc;
if (match_at_left) { if (match_at_left) {
*loc = '\0'; *loc = '\0';
s = string; match = pmatch(pattern, string);
} else *loc = c;
s = loc; } else {
match = pmatch(pattern, s); match = pmatch(pattern, loc);
*loc = c; }
if (match) if (match)
return loc; return loc;
loc--; loc--;
} }