summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/hush.c31
-rw-r--r--test/command_ut.c17
2 files changed, 42 insertions, 6 deletions
diff --git a/common/hush.c b/common/hush.c
index 3f3a79c..df10267 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -221,6 +221,8 @@ struct child_prog {
pid_t pid; /* 0 if exited */
#endif
char **argv; /* program name and arguments */
+ /* was quoted when parsed; copy of struct o_string.nonnull field */
+ int *argv_nonnull;
#ifdef __U_BOOT__
int argc; /* number of program arguments */
#endif
@@ -467,7 +469,7 @@ static int process_command_subs(o_string *dest, struct p_context *ctx, struct in
static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch);
#endif
static char *lookup_param(char *src);
-static char *make_string(char **inp);
+static char *make_string(char **inp, int *nonnull);
static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
#ifndef __U_BOOT__
static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
@@ -1613,7 +1615,8 @@ static int run_pipe_real(struct pipe *pi)
if (child->sp) {
char * str = NULL;
- str = make_string((child->argv + i));
+ str = make_string(child->argv + i,
+ child->argv_nonnull + i);
parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING);
free(str);
return last_return_code;
@@ -1940,7 +1943,8 @@ static int free_pipe(struct pipe *pi, int indent)
for (a = 0; a < child->argc; a++) {
free(child->argv[a]);
}
- free(child->argv);
+ free(child->argv);
+ free(child->argv_nonnull);
child->argc = 0;
#endif
child->argv=NULL;
@@ -2470,8 +2474,14 @@ static int done_word(o_string *dest, struct p_context *ctx)
argc = ++child->argc;
child->argv = realloc(child->argv, (argc+1)*sizeof(*child->argv));
if (child->argv == NULL) return 1;
+ child->argv_nonnull = realloc(child->argv_nonnull,
+ (argc+1)*sizeof(*child->argv_nonnull));
+ if (child->argv_nonnull == NULL)
+ return 1;
child->argv[argc-1]=str;
+ child->argv_nonnull[argc-1] = dest->nonnull;
child->argv[argc]=NULL;
+ child->argv_nonnull[argc] = 0;
for (s = dest->data; s && *s; s++,str++) {
if (*s == '\\') s++;
*str = *s;
@@ -2537,6 +2547,7 @@ static int done_command(struct p_context *ctx)
prog->redirects = NULL;
#endif
prog->argv = NULL;
+ prog->argv_nonnull = NULL;
#ifndef __U_BOOT__
prog->is_stopped = 0;
#endif
@@ -3585,8 +3596,12 @@ static char **make_list_in(char **inp, char *name)
return list;
}
-/* Make new string for parser */
-static char * make_string(char ** inp)
+/*
+ * Make new string for parser
+ * inp - array of argument strings to flatten
+ * nonnull - indicates argument was quoted when originally parsed
+ */
+static char *make_string(char **inp, int *nonnull)
{
char *p;
char *str = NULL;
@@ -3600,13 +3615,17 @@ static char * make_string(char ** inp)
noeval = 1;
for (n = 0; inp[n]; n++) {
p = insert_var_value_sub(inp[n], noeval);
- str = xrealloc(str, (len + strlen(p)));
+ str = xrealloc(str, (len + strlen(p) + (2 * nonnull[n])));
if (n) {
strcat(str, " ");
} else {
*str = '\0';
}
+ if (nonnull[n])
+ strcat(str, "'");
strcat(str, p);
+ if (nonnull[n])
+ strcat(str, "'");
len = strlen(str) + 3;
if (p != inp[n]) free(p);
}
diff --git a/test/command_ut.c b/test/command_ut.c
index 4f42056..b6b6976 100644
--- a/test/command_ut.c
+++ b/test/command_ut.c
@@ -138,6 +138,23 @@ static int do_ut_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
HUSH_TEST(or_1_0_inv_inv, "! ! aaa = aaa -o ! ! bbb != bbb", y);
HUSH_TEST(or_1_1_inv_inv, "! ! aaa = aaa -o ! ! bbb = bbb", y);
+ setenv("ut_var_nonexistent", NULL);
+ setenv("ut_var_exists", "1");
+ HUSH_TEST(z_varexp_quoted, "-z \"$ut_var_nonexistent\"", y);
+ HUSH_TEST(z_varexp_quoted, "-z \"$ut_var_exists\"", n);
+ setenv("ut_var_exists", NULL);
+
+ run_command("setenv ut_var_space \" \"", 0);
+ assert(!strcmp(getenv("ut_var_space"), " "));
+ run_command("setenv ut_var_test $ut_var_space", 0);
+ assert(!getenv("ut_var_test"));
+ run_command("setenv ut_var_test \"$ut_var_space\"", 0);
+ assert(!strcmp(getenv("ut_var_test"), " "));
+ run_command("setenv ut_var_test \" 1${ut_var_space}${ut_var_space} 2 \"", 0);
+ assert(!strcmp(getenv("ut_var_test"), " 1 2 "));
+ setenv("ut_var_space", NULL);
+ setenv("ut_var_test", NULL);
+
#ifdef CONFIG_SANDBOX
/*
* File existence