summaryrefslogtreecommitdiffstats
path: root/common/hush.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/hush.c')
-rw-r--r--common/hush.c73
1 files changed, 44 insertions, 29 deletions
diff --git a/common/hush.c b/common/hush.c
index 68c3eccdfc..608c0e4937 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/* vi: set sw=8 ts=8: */
/*
* hush.c -- a prototype Bourne shell grammar parser
@@ -94,19 +95,6 @@
*
*/
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- */
-
#define pr_fmt(fmt) "hush: " fmt
#include <malloc.h> /* malloc, free, realloc*/
@@ -121,9 +109,9 @@
#include <libbb.h>
#include <password.h>
#include <glob.h>
+#include <slice.h>
#include <getopt.h>
#include <libfile.h>
-#include <libbb.h>
#include <magicvar.h>
#include <linux/list.h>
#include <binfmt.h>
@@ -460,7 +448,12 @@ static void get_user_input(struct in_str *i)
else
prompt = CONFIG_PROMPT_HUSH_PS2;
- n = readline(prompt, console_buffer, CONFIG_CBSIZE);
+ command_slice_release();
+
+ n = readline(prompt, console_buffer, CONFIG_CBSIZE - 1);
+
+ command_slice_acquire();
+
if (n == -1 ) {
i->interrupt = 1;
n = 0;
@@ -624,6 +617,7 @@ static int builtin_exit(struct p_context *ctx, struct child_prog *child,
static void remove_quotes_in_str(char *src)
{
char *trg = src;
+ bool in_double_quotes = false;
while (*src) {
if (*src == '\'') {
@@ -636,6 +630,7 @@ static void remove_quotes_in_str(char *src)
/* drop quotes */
if (*src == '"') {
+ in_double_quotes = !in_double_quotes;
src++;
continue;
}
@@ -661,6 +656,13 @@ static void remove_quotes_in_str(char *src)
continue;
}
+ /* replace '\ ' with ' ' */
+ if (!in_double_quotes && *src == '\\' && *(src + 1) == ' ') {
+ *trg++ = ' ';
+ src += 2;
+ continue;
+ }
+
*trg++ = *src++;
}
*trg = 0;
@@ -761,7 +763,7 @@ static int run_pipe_real(struct p_context *ctx, struct pipe *pi)
/*
* We do not support pipes in barebox, so pi->num_progs can't
- * be bigger than 1. pi->num_progs == 0 is already catched in
+ * be bigger than 1. pi->num_progs == 0 is already caught in
* the caller, so everything else than 1 is a bug.
*/
BUG_ON(pi->num_progs != 1);
@@ -792,16 +794,9 @@ static int run_pipe_real(struct p_context *ctx, struct pipe *pi)
* This junk is all to decide whether or not to export this
* variable. */
int export_me = 0;
- char *name, *value;
- name = xstrdup(child->argv[i]);
- hush_debug("Local environment set: %s\n", name);
- value = strchr(name, '=');
+ hush_debug("Local environment set: %s\n", child->argv[i]);
- if (value)
- *value = 0;
-
- free(name);
p = insert_var_value(child->argv[i]);
rcode = set_local_var(p, export_me);
if (rcode)
@@ -867,7 +862,7 @@ static int run_list_real(struct p_context *ctx, struct pipe *pi)
struct pipe *rpipe;
int flag_rep = 0;
int rcode=0, flag_skip=1;
- int flag_restore = 0;
+ int flag_restore = 0, flag_conditional = 0;
int if_code=0, next_if_code=0; /* need double-buffer to handle elif */
reserved_style rmode, skip_more_in_this_rmode = RES_XXXX;
@@ -979,6 +974,20 @@ static int run_list_real(struct p_context *ctx, struct pipe *pi)
return rcode; /* exit */
}
+ /* Conditional statements like "if", "elif", "while" and "until"
+ * return 1 if conditional is not met. This is standard behavior.
+ * However this does not mean that this value (1) should be
+ * returned as exit code, as it suggests generic error code.
+ * Catch this by raising a flag and check it later on.
+ */
+ if (rcode == 1) {
+ if (rmode == RES_IF || rmode == RES_ELIF ||
+ rmode == RES_WHILE || rmode == RES_UNTIL)
+ flag_conditional = 1;
+ else
+ flag_conditional = 0;
+ }
+
last_return_code = rcode;
if (rmode == RES_IF || rmode == RES_ELIF )
@@ -994,6 +1003,13 @@ static int run_list_real(struct p_context *ctx, struct pipe *pi)
(rcode != EXIT_SUCCESS && pi->followup == PIPE_AND) )
skip_more_in_this_rmode = rmode;
}
+
+ /* Substitute exit code in case flag_conditional is set. */
+ if (flag_conditional == 1 && last_return_code == 1) {
+ last_return_code = 0;
+ rcode = 0;
+ }
+
return rcode;
}
@@ -1118,12 +1134,11 @@ static int set_local_var(const char *s, int flg_export)
/* Assume when we enter this function that we are already in
* NAME=VALUE format. So the first order of business is to
* split 's' on the '=' into 'name' and 'value' */
- value = strchr(name, '=');
+ value = parse_assignment(name);
if (!value) {
free(name);
return -1;
}
- *value++ = 0;
remove_quotes_in_str(value);
@@ -1689,7 +1704,7 @@ char *shell_expand(char *str)
return res;
}
-/* most recursion does not come through here, the exeception is
+/* most recursion does not come through here, the exception is
* from builtin_source() */
static int parse_stream_outer(struct p_context *ctx, struct in_str *inp, int flag)
{
@@ -1822,7 +1837,7 @@ static char **make_list_in(char **inp, char *name)
p3 = insert_var_value(inp[i]);
p1 = p3;
while (*p1) {
- if ((*p1 == ' ')) {
+ if (*p1 == ' ') {
p1++;
continue;
}