hush: fix all testsuite failures on NOMMU except memory leak.
known TODOs: we do not pass traps and positional args yet.
This commit is contained in:
parent
609f2ab434
commit
0bb4a23506
125
shell/hush.c
125
shell/hush.c
@ -1055,13 +1055,18 @@ static const char *get_local_var_value(const char *src)
|
|||||||
|
|
||||||
/* str holds "NAME=VAL" and is expected to be malloced.
|
/* str holds "NAME=VAL" and is expected to be malloced.
|
||||||
* We take ownership of it.
|
* We take ownership of it.
|
||||||
* flg_export is used by:
|
* flg_export:
|
||||||
* 0: do not export
|
* 0: do not export
|
||||||
* 1: export
|
* 1: export
|
||||||
* -1: if NAME is set, leave export status alone
|
* -1: if NAME is set, leave export status alone
|
||||||
* if NAME is not set, do not export
|
* if NAME is not set, do not export
|
||||||
|
* flg_read_only is set only when we handle -R var=val
|
||||||
*/
|
*/
|
||||||
static int set_local_var(char *str, int flg_export)
|
#if BB_MMU
|
||||||
|
#define set_local_var(str, flg_export, flg_read_only) \
|
||||||
|
set_local_var(str, flg_export)
|
||||||
|
#endif
|
||||||
|
static int set_local_var(char *str, int flg_export, int flg_read_only)
|
||||||
{
|
{
|
||||||
struct variable *cur;
|
struct variable *cur;
|
||||||
char *value;
|
char *value;
|
||||||
@ -1088,7 +1093,10 @@ static int set_local_var(char *str, int flg_export)
|
|||||||
/* We found an existing var with this name */
|
/* We found an existing var with this name */
|
||||||
*value = '\0';
|
*value = '\0';
|
||||||
if (cur->flg_read_only) {
|
if (cur->flg_read_only) {
|
||||||
bb_error_msg("%s: readonly variable", str);
|
#if !BB_MMU
|
||||||
|
if (!flg_read_only)
|
||||||
|
#endif
|
||||||
|
bb_error_msg("%s: readonly variable", str);
|
||||||
free(str);
|
free(str);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1119,6 +1127,7 @@ static int set_local_var(char *str, int flg_export)
|
|||||||
|
|
||||||
set_str_and_exp:
|
set_str_and_exp:
|
||||||
cur->varstr = str;
|
cur->varstr = str;
|
||||||
|
cur->flg_read_only = flg_read_only;
|
||||||
exp:
|
exp:
|
||||||
if (flg_export == 1)
|
if (flg_export == 1)
|
||||||
cur->flg_export = 1;
|
cur->flg_export = 1;
|
||||||
@ -1182,7 +1191,7 @@ static void arith_set_local_var(const char *name, const char *val, int flags)
|
|||||||
{
|
{
|
||||||
/* arith code doesnt malloc space, so do it for it */
|
/* arith code doesnt malloc space, so do it for it */
|
||||||
char *var = xasprintf("%s=%s", name, val);
|
char *var = xasprintf("%s=%s", name, val);
|
||||||
set_local_var(var, flags);
|
set_local_var(var, flags, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1948,7 +1957,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
|
|||||||
} else {
|
} else {
|
||||||
char *new_var = xmalloc(strlen(var) + strlen(val) + 2);
|
char *new_var = xmalloc(strlen(var) + strlen(val) + 2);
|
||||||
sprintf(new_var, "%s=%s", var, val);
|
sprintf(new_var, "%s=%s", var, val);
|
||||||
set_local_var(new_var, -1);
|
set_local_var(new_var, -1, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2332,9 +2341,40 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save,
|
|||||||
static void re_execute_shell(const char *s) NORETURN;
|
static void re_execute_shell(const char *s) NORETURN;
|
||||||
static void re_execute_shell(const char *s)
|
static void re_execute_shell(const char *s)
|
||||||
{
|
{
|
||||||
//TODO: pass non-exported variables, traps, and functions
|
struct variable *cur;
|
||||||
debug_printf_exec("re_execute_shell pid:%d cmd:'%s'", getpid(), s);
|
char **argv, **pp;
|
||||||
execl(bb_busybox_exec_path, "hush", "-c", s, NULL);
|
unsigned cnt;
|
||||||
|
|
||||||
|
/* hush -$<pid> -?<exitcode> ... -c <cmd> NULL */
|
||||||
|
cnt = 6;
|
||||||
|
for (cur = G.top_var; cur; cur = cur->next) {
|
||||||
|
if (!cur->flg_export || cur->flg_read_only)
|
||||||
|
cnt += 2;
|
||||||
|
}
|
||||||
|
//TODO: need to free these strings in parent!
|
||||||
|
argv = pp = xmalloc(sizeof(argv[0]) * cnt);
|
||||||
|
*pp++ = (char *) applet_name;
|
||||||
|
*pp++ = xasprintf("-$%u", G.root_pid);
|
||||||
|
*pp++ = xasprintf("-?%u", G.last_return_code);
|
||||||
|
for (cur = G.top_var; cur; cur = cur->next) {
|
||||||
|
if (cur->varstr == hush_version_str)
|
||||||
|
continue;
|
||||||
|
if (cur->flg_read_only) {
|
||||||
|
*pp++ = (char *) "-R";
|
||||||
|
*pp++ = cur->varstr;
|
||||||
|
} else if (!cur->flg_export) {
|
||||||
|
*pp++ = (char *) "-V";
|
||||||
|
*pp++ = cur->varstr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*pp++ = (char *) "-c";
|
||||||
|
*pp++ = (char *) s;
|
||||||
|
//TODO: pass $N
|
||||||
|
*pp = NULL;
|
||||||
|
//TODO: pass traps and functions
|
||||||
|
|
||||||
|
debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s);
|
||||||
|
execv(bb_busybox_exec_path, argv);
|
||||||
//TODO: fallback for init=/bin/hush?
|
//TODO: fallback for init=/bin/hush?
|
||||||
_exit(127);
|
_exit(127);
|
||||||
}
|
}
|
||||||
@ -2720,7 +2760,7 @@ static int run_pipe(struct pipe *pi)
|
|||||||
p = expand_string_to_string(*argv);
|
p = expand_string_to_string(*argv);
|
||||||
debug_printf_exec("set shell var:'%s'->'%s'\n",
|
debug_printf_exec("set shell var:'%s'->'%s'\n",
|
||||||
*argv, p);
|
*argv, p);
|
||||||
set_local_var(p, 0);
|
set_local_var(p, 0, 0);
|
||||||
argv++;
|
argv++;
|
||||||
}
|
}
|
||||||
/* Do we need to flag set_local_var() errors?
|
/* Do we need to flag set_local_var() errors?
|
||||||
@ -4094,7 +4134,7 @@ static int handle_dollar(struct parse_context *ctx,
|
|||||||
if (isalpha(ch)) {
|
if (isalpha(ch)) {
|
||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
#if !BB_MMU
|
#if !BB_MMU
|
||||||
o_addchr(&ctx->as_string, ch);
|
if (ctx) o_addchr(&ctx->as_string, ch);
|
||||||
#endif
|
#endif
|
||||||
make_var:
|
make_var:
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
@ -4107,7 +4147,7 @@ static int handle_dollar(struct parse_context *ctx,
|
|||||||
break;
|
break;
|
||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
#if !BB_MMU
|
#if !BB_MMU
|
||||||
o_addchr(&ctx->as_string, ch);
|
if (ctx) o_addchr(&ctx->as_string, ch);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
@ -4115,7 +4155,7 @@ static int handle_dollar(struct parse_context *ctx,
|
|||||||
make_one_char_var:
|
make_one_char_var:
|
||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
#if !BB_MMU
|
#if !BB_MMU
|
||||||
o_addchr(&ctx->as_string, ch);
|
if (ctx) o_addchr(&ctx->as_string, ch);
|
||||||
#endif
|
#endif
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
debug_printf_parse(": '%c'\n", ch);
|
debug_printf_parse(": '%c'\n", ch);
|
||||||
@ -4135,7 +4175,7 @@ static int handle_dollar(struct parse_context *ctx,
|
|||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
#if !BB_MMU
|
#if !BB_MMU
|
||||||
o_addchr(&ctx->as_string, ch);
|
if (ctx) o_addchr(&ctx->as_string, ch);
|
||||||
#endif
|
#endif
|
||||||
/* XXX maybe someone will try to escape the '}' */
|
/* XXX maybe someone will try to escape the '}' */
|
||||||
expansion = 0;
|
expansion = 0;
|
||||||
@ -4144,7 +4184,7 @@ static int handle_dollar(struct parse_context *ctx,
|
|||||||
while (1) {
|
while (1) {
|
||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
#if !BB_MMU
|
#if !BB_MMU
|
||||||
o_addchr(&ctx->as_string, ch);
|
if (ctx) o_addchr(&ctx->as_string, ch);
|
||||||
#endif
|
#endif
|
||||||
if (ch == '}')
|
if (ch == '}')
|
||||||
break;
|
break;
|
||||||
@ -4211,19 +4251,32 @@ static int handle_dollar(struct parse_context *ctx,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case '(': {
|
case '(': {
|
||||||
|
#if !BB_MMU
|
||||||
|
int pos;
|
||||||
|
#endif
|
||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
#if !BB_MMU
|
#if !BB_MMU
|
||||||
o_addchr(&ctx->as_string, ch);
|
if (ctx) o_addchr(&ctx->as_string, ch);
|
||||||
#endif
|
#endif
|
||||||
#if ENABLE_SH_MATH_SUPPORT
|
#if ENABLE_SH_MATH_SUPPORT
|
||||||
if (i_peek(input) == '(') {
|
if (i_peek(input) == '(') {
|
||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
#if !BB_MMU
|
#if !BB_MMU
|
||||||
o_addchr(&ctx->as_string, ch);
|
if (ctx) o_addchr(&ctx->as_string, ch);
|
||||||
#endif
|
#endif
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
o_addchr(dest, /*quote_mask |*/ '+');
|
o_addchr(dest, /*quote_mask |*/ '+');
|
||||||
|
#if !BB_MMU
|
||||||
|
pos = dest->length;
|
||||||
|
#endif
|
||||||
add_till_closing_paren(dest, input, true);
|
add_till_closing_paren(dest, input, true);
|
||||||
|
#if !BB_MMU
|
||||||
|
if (ctx) {
|
||||||
|
o_addstr(&ctx->as_string, dest->data + pos);
|
||||||
|
o_addchr(&ctx->as_string, ')');
|
||||||
|
o_addchr(&ctx->as_string, ')');
|
||||||
|
}
|
||||||
|
#endif
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -4232,7 +4285,16 @@ static int handle_dollar(struct parse_context *ctx,
|
|||||||
//int pos = dest->length;
|
//int pos = dest->length;
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
o_addchr(dest, quote_mask | '`');
|
o_addchr(dest, quote_mask | '`');
|
||||||
|
#if !BB_MMU
|
||||||
|
pos = dest->length;
|
||||||
|
#endif
|
||||||
add_till_closing_paren(dest, input, false);
|
add_till_closing_paren(dest, input, false);
|
||||||
|
#if !BB_MMU
|
||||||
|
if (ctx) {
|
||||||
|
o_addstr(&ctx->as_string, dest->data + pos);
|
||||||
|
o_addchr(&ctx->as_string, '`');
|
||||||
|
}
|
||||||
|
#endif
|
||||||
//debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos);
|
//debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos);
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
#endif
|
#endif
|
||||||
@ -4241,7 +4303,7 @@ static int handle_dollar(struct parse_context *ctx,
|
|||||||
case '_':
|
case '_':
|
||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
#if !BB_MMU
|
#if !BB_MMU
|
||||||
o_addchr(&ctx->as_string, ch);
|
if (ctx) o_addchr(&ctx->as_string, ch);
|
||||||
#endif
|
#endif
|
||||||
ch = i_peek(input);
|
ch = i_peek(input);
|
||||||
if (isalnum(ch)) { /* it's $_name or $_123 */
|
if (isalnum(ch)) { /* it's $_name or $_123 */
|
||||||
@ -4293,8 +4355,8 @@ static int parse_stream_dquoted(struct parse_context *ctx,
|
|||||||
if (ch != '\n') {
|
if (ch != '\n') {
|
||||||
next = i_peek(input);
|
next = i_peek(input);
|
||||||
}
|
}
|
||||||
debug_printf_parse(": ch=%c (%d) m=%d escape=%d\n",
|
debug_printf_parse(": ch=%c (%d) escape=%d\n",
|
||||||
ch, ch, m, dest->o_escape);
|
ch, ch, dest->o_escape);
|
||||||
if (ch == '\\') {
|
if (ch == '\\') {
|
||||||
if (next == EOF) {
|
if (next == EOF) {
|
||||||
syntax("\\<eof>");
|
syntax("\\<eof>");
|
||||||
@ -4944,7 +5006,14 @@ int hush_main(int argc, char **argv)
|
|||||||
input = stdin;
|
input = stdin;
|
||||||
|
|
||||||
/* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */
|
/* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */
|
||||||
while ((opt = getopt(argc, argv, "c:xins")) > 0) {
|
while (1) {
|
||||||
|
opt = getopt(argc, argv, "c:xins"
|
||||||
|
#if !BB_MMU
|
||||||
|
"$:?:R:V:"
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
if (opt <= 0)
|
||||||
|
break;
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'c':
|
case 'c':
|
||||||
G.global_argv = argv + optind;
|
G.global_argv = argv + optind;
|
||||||
@ -4965,6 +5034,18 @@ int hush_main(int argc, char **argv)
|
|||||||
/* "-s" means "read from stdin", but this is how we always
|
/* "-s" means "read from stdin", but this is how we always
|
||||||
* operate, so simply do nothing here. */
|
* operate, so simply do nothing here. */
|
||||||
break;
|
break;
|
||||||
|
#if !BB_MMU
|
||||||
|
case '$':
|
||||||
|
G.root_pid = xatoi_u(optarg);
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
G.last_return_code = xatoi_u(optarg);
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
case 'V':
|
||||||
|
set_local_var(xstrdup(optarg), 0, opt == 'R');
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case 'n':
|
case 'n':
|
||||||
case 'x':
|
case 'x':
|
||||||
if (!set_mode('-', opt))
|
if (!set_mode('-', opt))
|
||||||
@ -5293,7 +5374,7 @@ static int builtin_export(char **argv)
|
|||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_local_var(xstrdup(name), 1);
|
set_local_var(xstrdup(name), 1, 0);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5406,7 +5487,7 @@ static int builtin_read(char **argv)
|
|||||||
const char *name = argv[1] ? argv[1] : "REPLY";
|
const char *name = argv[1] ? argv[1] : "REPLY";
|
||||||
|
|
||||||
string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name), NULL);
|
string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name), NULL);
|
||||||
return set_local_var(string, 0);
|
return set_local_var(string, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set
|
/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set
|
||||||
|
Loading…
Reference in New Issue
Block a user