diff options
Diffstat (limited to 'common/hush.c')
-rw-r--r-- | common/hush.c | 73 |
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; } |