hush: fix handling of backslashes in variable assignment
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
This commit is contained in:
parent
8ae6e9be5c
commit
e298ce69ba
@ -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'
|
||||||
|
43
shell/hush.c
43
shell/hush.c
@ -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;
|
||||||
|
11
shell/hush_test/hush-vars/var_unbackslash.right
Normal file
11
shell/hush_test/hush-vars/var_unbackslash.right
Normal 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
|
23
shell/hush_test/hush-vars/var_unbackslash.tests
Executable file
23
shell/hush_test/hush-vars/var_unbackslash.tests
Executable 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: $?"
|
@ -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--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user