summaryrefslogtreecommitdiffstats
path: root/common/hush.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2012-04-29 14:11:38 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2012-04-30 13:08:54 +0200
commit1aad6d033a83c025a6e3b279ac5b145c7a2efffd (patch)
tree887bc81a8a1b420c6f543cb7bb1d22841c35ca36 /common/hush.c
parent37e77d3cfec63f46e4c04847c6181dae2c1b7ea0 (diff)
downloadbarebox-1aad6d033a83c025a6e3b279ac5b145c7a2efffd.tar.gz
barebox-1aad6d033a83c025a6e3b279ac5b145c7a2efffd.tar.xz
hush: remove quotes at end of processing
hush removes the quotes from strings too early. This leads to some bugs. When hush executes echo "hello sascha" it correctly results in: argv[0] = "echo" argv[1] = "hello sascha" However, the following behaves incorrect: a="hello sascha" echo "$a" results in: argv[0] = "echo" argv[1] = "hello" argv[2] = "sascha" This is because hush removes the quotes and inserts variable values in a single loop, so echo "$a" becomes: echo hello sascha after the loop. Instead, keep the quotes until all variables are inserted and remove them at the end. This also fixes that echo \" resulted in \" instead of ". Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'common/hush.c')
-rw-r--r--common/hush.c89
1 files changed, 66 insertions, 23 deletions
diff --git a/common/hush.c b/common/hush.c
index cd2afef479..e32e884f4a 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -270,7 +270,6 @@ static void syntax_err(void) {
static int b_check_space(o_string *o, int len);
static int b_addchr(o_string *o, int ch);
static void b_reset(o_string *o);
-static int b_addqchr(o_string *o, int ch, int quote);
/* in_str manipulations: */
static int static_get(struct in_str *i);
static int static_peek(struct in_str *i);
@@ -356,22 +355,6 @@ static void b_free(o_string *o)
o->maxlen = 0;
}
-/* My analysis of quoting semantics tells me that state information
- * is associated with a destination, not a source.
- */
-static int b_addqchr(o_string *o, int ch, int quote)
-{
- if (quote && strchr("*?[",ch)) {
- int rc;
-
- rc = b_addchr(o, '\\');
- if (rc)
- return rc;
- }
-
- return b_addchr(o, ch);
-}
-
static int b_adduint(o_string *o, unsigned int i)
{
int r;
@@ -565,6 +548,59 @@ out:
BAREBOX_MAGICVAR(OPTARG, "optarg for hush builtin getopt");
#endif
+static void remove_quotes_in_str(char *src)
+{
+ char *trg = src;
+
+ while (*src) {
+ if (*src == '\'') {
+ src++;
+ while (*src != '\'')
+ *trg++ = *src++;
+ src++;
+ continue;
+ }
+
+ /* drop quotes */
+ if (*src == '"') {
+ src++;
+ continue;
+ }
+
+ /* replace \" with " */
+ if (*src == '\\' && *(src + 1) == '"') {
+ *trg++ = '"';
+ src += 2;
+ continue;
+ }
+
+ /* replace \' with ' */
+ if (*src == '\\' && *(src + 1) == '\'') {
+ *trg++ = '\'';
+ src += 2;
+ continue;
+ }
+
+ /* replace \\ with \ */
+ if (*src == '\\' && *(src + 1) == '\\') {
+ *trg++ = '\\';
+ src += 2;
+ continue;
+ }
+
+ *trg++ = *src++;
+ }
+ *trg = 0;
+}
+
+static void remove_quotes(int argc, char *argv[])
+{
+ int i;
+
+ for (i = 0; i < argc; i++)
+ remove_quotes_in_str(argv[i]);
+}
+
/* run_pipe_real() starts all the jobs, but doesn't wait for anything
* to finish. See checkjobs().
*
@@ -670,6 +706,8 @@ static int run_pipe_real(struct p_context *ctx, struct pipe *pi)
return last_return_code;
}
+ remove_quotes(child->argc - i, &child->argv[i]);
+
#ifdef CONFIG_HUSH_GETOPT
if (!strcmp(child->argv[i], "getopt"))
return builtin_getopt(ctx, child);
@@ -1007,6 +1045,8 @@ static int set_local_var(const char *s, int flg_export)
}
*value++ = 0;
+ remove_quotes_in_str(value);
+
ret = setenv(name, value);
free(name);
@@ -1347,7 +1387,7 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
b_addchr(dest, SPECIAL_VAR_SYMBOL);
break;
default:
- b_addqchr(dest,'$',dest->quote);
+ b_addchr(dest, '$');
}
}
/* Eat the character if the flag was set. If the compiler
@@ -1387,7 +1427,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
dest->quote, ctx->stack == NULL ? '*' : '.');
if (m == 0 || ((m == 1 || m == 2) && dest->quote)) {
- b_addqchr(dest, ch, dest->quote);
+ b_addchr(dest, ch);
continue;
}
@@ -1416,7 +1456,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
b_getch(input);
}
} else {
- b_addqchr(dest, ch, dest->quote);
+ b_addchr(dest, ch);
}
break;
case '\\':
@@ -1424,8 +1464,8 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
syntax();
return 1;
}
- b_addqchr(dest, '\\', dest->quote);
- b_addqchr(dest, b_getch(input), dest->quote);
+ b_addchr(dest, '\\');
+ b_addchr(dest, b_getch(input));
break;
case '$':
if (handle_dollar(dest, ctx, input)!=0)
@@ -1433,11 +1473,13 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
break;
case '\'':
dest->nonnull = 1;
- while (ch = b_getch(input), ch!=EOF && ch != '\'') {
+ b_addchr(dest, '\'');
+ while (ch = b_getch(input), ch != EOF && ch != '\'') {
if (input->__promptme == 0)
return 1;
b_addchr(dest,ch);
}
+ b_addchr(dest, '\'');
if (ch == EOF) {
syntax();
return 1;
@@ -1445,6 +1487,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
break;
case '"':
dest->nonnull = 1;
+ b_addchr(dest, '"');
dest->quote = !dest->quote;
break;
case ';':