diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-05 01:42:59 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-05 01:42:59 +0000 |
commit | 0bb4a23506c07c2b696a91661d38b86860e2e7be (patch) | |
tree | 2a69e566333a2b3f8c2988d7cce66d38f7a68ace | |
parent | 609f2ab4345e173ea944db774131e3615b3176a8 (diff) | |
download | busybox-w32-0bb4a23506c07c2b696a91661d38b86860e2e7be.tar.gz busybox-w32-0bb4a23506c07c2b696a91661d38b86860e2e7be.tar.bz2 busybox-w32-0bb4a23506c07c2b696a91661d38b86860e2e7be.zip |
hush: fix all testsuite failures on NOMMU except memory leak.
known TODOs: we do not pass traps and positional args yet.
-rw-r--r-- | shell/hush.c | 125 |
1 files changed, 103 insertions, 22 deletions
diff --git a/shell/hush.c b/shell/hush.c index 0313cfd78..13e962383 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -1055,13 +1055,18 @@ static const char *get_local_var_value(const char *src) | |||
1055 | 1055 | ||
1056 | /* str holds "NAME=VAL" and is expected to be malloced. | 1056 | /* str holds "NAME=VAL" and is expected to be malloced. |
1057 | * We take ownership of it. | 1057 | * We take ownership of it. |
1058 | * flg_export is used by: | 1058 | * flg_export: |
1059 | * 0: do not export | 1059 | * 0: do not export |
1060 | * 1: export | 1060 | * 1: export |
1061 | * -1: if NAME is set, leave export status alone | 1061 | * -1: if NAME is set, leave export status alone |
1062 | * if NAME is not set, do not export | 1062 | * if NAME is not set, do not export |
1063 | * flg_read_only is set only when we handle -R var=val | ||
1063 | */ | 1064 | */ |
1064 | static int set_local_var(char *str, int flg_export) | 1065 | #if BB_MMU |
1066 | #define set_local_var(str, flg_export, flg_read_only) \ | ||
1067 | set_local_var(str, flg_export) | ||
1068 | #endif | ||
1069 | static int set_local_var(char *str, int flg_export, int flg_read_only) | ||
1065 | { | 1070 | { |
1066 | struct variable *cur; | 1071 | struct variable *cur; |
1067 | char *value; | 1072 | char *value; |
@@ -1088,7 +1093,10 @@ static int set_local_var(char *str, int flg_export) | |||
1088 | /* We found an existing var with this name */ | 1093 | /* We found an existing var with this name */ |
1089 | *value = '\0'; | 1094 | *value = '\0'; |
1090 | if (cur->flg_read_only) { | 1095 | if (cur->flg_read_only) { |
1091 | bb_error_msg("%s: readonly variable", str); | 1096 | #if !BB_MMU |
1097 | if (!flg_read_only) | ||
1098 | #endif | ||
1099 | bb_error_msg("%s: readonly variable", str); | ||
1092 | free(str); | 1100 | free(str); |
1093 | return -1; | 1101 | return -1; |
1094 | } | 1102 | } |
@@ -1119,6 +1127,7 @@ static int set_local_var(char *str, int flg_export) | |||
1119 | 1127 | ||
1120 | set_str_and_exp: | 1128 | set_str_and_exp: |
1121 | cur->varstr = str; | 1129 | cur->varstr = str; |
1130 | cur->flg_read_only = flg_read_only; | ||
1122 | exp: | 1131 | exp: |
1123 | if (flg_export == 1) | 1132 | if (flg_export == 1) |
1124 | cur->flg_export = 1; | 1133 | cur->flg_export = 1; |
@@ -1182,7 +1191,7 @@ static void arith_set_local_var(const char *name, const char *val, int flags) | |||
1182 | { | 1191 | { |
1183 | /* arith code doesnt malloc space, so do it for it */ | 1192 | /* arith code doesnt malloc space, so do it for it */ |
1184 | char *var = xasprintf("%s=%s", name, val); | 1193 | char *var = xasprintf("%s=%s", name, val); |
1185 | set_local_var(var, flags); | 1194 | set_local_var(var, flags, 0); |
1186 | } | 1195 | } |
1187 | #endif | 1196 | #endif |
1188 | 1197 | ||
@@ -1948,7 +1957,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1948 | } else { | 1957 | } else { |
1949 | char *new_var = xmalloc(strlen(var) + strlen(val) + 2); | 1958 | char *new_var = xmalloc(strlen(var) + strlen(val) + 2); |
1950 | sprintf(new_var, "%s=%s", var, val); | 1959 | sprintf(new_var, "%s=%s", var, val); |
1951 | set_local_var(new_var, -1); | 1960 | set_local_var(new_var, -1, 0); |
1952 | } | 1961 | } |
1953 | } | 1962 | } |
1954 | } | 1963 | } |
@@ -2332,9 +2341,40 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
2332 | static void re_execute_shell(const char *s) NORETURN; | 2341 | static void re_execute_shell(const char *s) NORETURN; |
2333 | static void re_execute_shell(const char *s) | 2342 | static void re_execute_shell(const char *s) |
2334 | { | 2343 | { |
2335 | //TODO: pass non-exported variables, traps, and functions | 2344 | struct variable *cur; |
2336 | debug_printf_exec("re_execute_shell pid:%d cmd:'%s'", getpid(), s); | 2345 | char **argv, **pp; |
2337 | execl(bb_busybox_exec_path, "hush", "-c", s, NULL); | 2346 | unsigned cnt; |
2347 | |||
2348 | /* hush -$<pid> -?<exitcode> ... -c <cmd> NULL */ | ||
2349 | cnt = 6; | ||
2350 | for (cur = G.top_var; cur; cur = cur->next) { | ||
2351 | if (!cur->flg_export || cur->flg_read_only) | ||
2352 | cnt += 2; | ||
2353 | } | ||
2354 | //TODO: need to free these strings in parent! | ||
2355 | argv = pp = xmalloc(sizeof(argv[0]) * cnt); | ||
2356 | *pp++ = (char *) applet_name; | ||
2357 | *pp++ = xasprintf("-$%u", G.root_pid); | ||
2358 | *pp++ = xasprintf("-?%u", G.last_return_code); | ||
2359 | for (cur = G.top_var; cur; cur = cur->next) { | ||
2360 | if (cur->varstr == hush_version_str) | ||
2361 | continue; | ||
2362 | if (cur->flg_read_only) { | ||
2363 | *pp++ = (char *) "-R"; | ||
2364 | *pp++ = cur->varstr; | ||
2365 | } else if (!cur->flg_export) { | ||
2366 | *pp++ = (char *) "-V"; | ||
2367 | *pp++ = cur->varstr; | ||
2368 | } | ||
2369 | } | ||
2370 | *pp++ = (char *) "-c"; | ||
2371 | *pp++ = (char *) s; | ||
2372 | //TODO: pass $N | ||
2373 | *pp = NULL; | ||
2374 | //TODO: pass traps and functions | ||
2375 | |||
2376 | debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); | ||
2377 | execv(bb_busybox_exec_path, argv); | ||
2338 | //TODO: fallback for init=/bin/hush? | 2378 | //TODO: fallback for init=/bin/hush? |
2339 | _exit(127); | 2379 | _exit(127); |
2340 | } | 2380 | } |
@@ -2720,7 +2760,7 @@ static int run_pipe(struct pipe *pi) | |||
2720 | p = expand_string_to_string(*argv); | 2760 | p = expand_string_to_string(*argv); |
2721 | debug_printf_exec("set shell var:'%s'->'%s'\n", | 2761 | debug_printf_exec("set shell var:'%s'->'%s'\n", |
2722 | *argv, p); | 2762 | *argv, p); |
2723 | set_local_var(p, 0); | 2763 | set_local_var(p, 0, 0); |
2724 | argv++; | 2764 | argv++; |
2725 | } | 2765 | } |
2726 | /* Do we need to flag set_local_var() errors? | 2766 | /* Do we need to flag set_local_var() errors? |
@@ -4094,7 +4134,7 @@ static int handle_dollar(struct parse_context *ctx, | |||
4094 | if (isalpha(ch)) { | 4134 | if (isalpha(ch)) { |
4095 | ch = i_getch(input); | 4135 | ch = i_getch(input); |
4096 | #if !BB_MMU | 4136 | #if !BB_MMU |
4097 | o_addchr(&ctx->as_string, ch); | 4137 | if (ctx) o_addchr(&ctx->as_string, ch); |
4098 | #endif | 4138 | #endif |
4099 | make_var: | 4139 | make_var: |
4100 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4140 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
@@ -4107,7 +4147,7 @@ static int handle_dollar(struct parse_context *ctx, | |||
4107 | break; | 4147 | break; |
4108 | ch = i_getch(input); | 4148 | ch = i_getch(input); |
4109 | #if !BB_MMU | 4149 | #if !BB_MMU |
4110 | o_addchr(&ctx->as_string, ch); | 4150 | if (ctx) o_addchr(&ctx->as_string, ch); |
4111 | #endif | 4151 | #endif |
4112 | } | 4152 | } |
4113 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4153 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
@@ -4115,7 +4155,7 @@ static int handle_dollar(struct parse_context *ctx, | |||
4115 | make_one_char_var: | 4155 | make_one_char_var: |
4116 | ch = i_getch(input); | 4156 | ch = i_getch(input); |
4117 | #if !BB_MMU | 4157 | #if !BB_MMU |
4118 | o_addchr(&ctx->as_string, ch); | 4158 | if (ctx) o_addchr(&ctx->as_string, ch); |
4119 | #endif | 4159 | #endif |
4120 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4160 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4121 | debug_printf_parse(": '%c'\n", ch); | 4161 | debug_printf_parse(": '%c'\n", ch); |
@@ -4135,7 +4175,7 @@ static int handle_dollar(struct parse_context *ctx, | |||
4135 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4175 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4136 | ch = i_getch(input); | 4176 | ch = i_getch(input); |
4137 | #if !BB_MMU | 4177 | #if !BB_MMU |
4138 | o_addchr(&ctx->as_string, ch); | 4178 | if (ctx) o_addchr(&ctx->as_string, ch); |
4139 | #endif | 4179 | #endif |
4140 | /* XXX maybe someone will try to escape the '}' */ | 4180 | /* XXX maybe someone will try to escape the '}' */ |
4141 | expansion = 0; | 4181 | expansion = 0; |
@@ -4144,7 +4184,7 @@ static int handle_dollar(struct parse_context *ctx, | |||
4144 | while (1) { | 4184 | while (1) { |
4145 | ch = i_getch(input); | 4185 | ch = i_getch(input); |
4146 | #if !BB_MMU | 4186 | #if !BB_MMU |
4147 | o_addchr(&ctx->as_string, ch); | 4187 | if (ctx) o_addchr(&ctx->as_string, ch); |
4148 | #endif | 4188 | #endif |
4149 | if (ch == '}') | 4189 | if (ch == '}') |
4150 | break; | 4190 | break; |
@@ -4211,19 +4251,32 @@ static int handle_dollar(struct parse_context *ctx, | |||
4211 | break; | 4251 | break; |
4212 | } | 4252 | } |
4213 | case '(': { | 4253 | case '(': { |
4254 | #if !BB_MMU | ||
4255 | int pos; | ||
4256 | #endif | ||
4214 | ch = i_getch(input); | 4257 | ch = i_getch(input); |
4215 | #if !BB_MMU | 4258 | #if !BB_MMU |
4216 | o_addchr(&ctx->as_string, ch); | 4259 | if (ctx) o_addchr(&ctx->as_string, ch); |
4217 | #endif | 4260 | #endif |
4218 | #if ENABLE_SH_MATH_SUPPORT | 4261 | #if ENABLE_SH_MATH_SUPPORT |
4219 | if (i_peek(input) == '(') { | 4262 | if (i_peek(input) == '(') { |
4220 | ch = i_getch(input); | 4263 | ch = i_getch(input); |
4221 | #if !BB_MMU | 4264 | #if !BB_MMU |
4222 | o_addchr(&ctx->as_string, ch); | 4265 | if (ctx) o_addchr(&ctx->as_string, ch); |
4223 | #endif | 4266 | #endif |
4224 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4267 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4225 | o_addchr(dest, /*quote_mask |*/ '+'); | 4268 | o_addchr(dest, /*quote_mask |*/ '+'); |
4269 | #if !BB_MMU | ||
4270 | pos = dest->length; | ||
4271 | #endif | ||
4226 | add_till_closing_paren(dest, input, true); | 4272 | add_till_closing_paren(dest, input, true); |
4273 | #if !BB_MMU | ||
4274 | if (ctx) { | ||
4275 | o_addstr(&ctx->as_string, dest->data + pos); | ||
4276 | o_addchr(&ctx->as_string, ')'); | ||
4277 | o_addchr(&ctx->as_string, ')'); | ||
4278 | } | ||
4279 | #endif | ||
4227 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4280 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4228 | break; | 4281 | break; |
4229 | } | 4282 | } |
@@ -4232,7 +4285,16 @@ static int handle_dollar(struct parse_context *ctx, | |||
4232 | //int pos = dest->length; | 4285 | //int pos = dest->length; |
4233 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4286 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4234 | o_addchr(dest, quote_mask | '`'); | 4287 | o_addchr(dest, quote_mask | '`'); |
4288 | #if !BB_MMU | ||
4289 | pos = dest->length; | ||
4290 | #endif | ||
4235 | add_till_closing_paren(dest, input, false); | 4291 | add_till_closing_paren(dest, input, false); |
4292 | #if !BB_MMU | ||
4293 | if (ctx) { | ||
4294 | o_addstr(&ctx->as_string, dest->data + pos); | ||
4295 | o_addchr(&ctx->as_string, '`'); | ||
4296 | } | ||
4297 | #endif | ||
4236 | //debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos); | 4298 | //debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos); |
4237 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4299 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4238 | #endif | 4300 | #endif |
@@ -4241,7 +4303,7 @@ static int handle_dollar(struct parse_context *ctx, | |||
4241 | case '_': | 4303 | case '_': |
4242 | ch = i_getch(input); | 4304 | ch = i_getch(input); |
4243 | #if !BB_MMU | 4305 | #if !BB_MMU |
4244 | o_addchr(&ctx->as_string, ch); | 4306 | if (ctx) o_addchr(&ctx->as_string, ch); |
4245 | #endif | 4307 | #endif |
4246 | ch = i_peek(input); | 4308 | ch = i_peek(input); |
4247 | if (isalnum(ch)) { /* it's $_name or $_123 */ | 4309 | if (isalnum(ch)) { /* it's $_name or $_123 */ |
@@ -4293,8 +4355,8 @@ static int parse_stream_dquoted(struct parse_context *ctx, | |||
4293 | if (ch != '\n') { | 4355 | if (ch != '\n') { |
4294 | next = i_peek(input); | 4356 | next = i_peek(input); |
4295 | } | 4357 | } |
4296 | debug_printf_parse(": ch=%c (%d) m=%d escape=%d\n", | 4358 | debug_printf_parse(": ch=%c (%d) escape=%d\n", |
4297 | ch, ch, m, dest->o_escape); | 4359 | ch, ch, dest->o_escape); |
4298 | if (ch == '\\') { | 4360 | if (ch == '\\') { |
4299 | if (next == EOF) { | 4361 | if (next == EOF) { |
4300 | syntax("\\<eof>"); | 4362 | syntax("\\<eof>"); |
@@ -4944,7 +5006,14 @@ int hush_main(int argc, char **argv) | |||
4944 | input = stdin; | 5006 | input = stdin; |
4945 | 5007 | ||
4946 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ | 5008 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ |
4947 | while ((opt = getopt(argc, argv, "c:xins")) > 0) { | 5009 | while (1) { |
5010 | opt = getopt(argc, argv, "c:xins" | ||
5011 | #if !BB_MMU | ||
5012 | "$:?:R:V:" | ||
5013 | #endif | ||
5014 | ); | ||
5015 | if (opt <= 0) | ||
5016 | break; | ||
4948 | switch (opt) { | 5017 | switch (opt) { |
4949 | case 'c': | 5018 | case 'c': |
4950 | G.global_argv = argv + optind; | 5019 | G.global_argv = argv + optind; |
@@ -4965,6 +5034,18 @@ int hush_main(int argc, char **argv) | |||
4965 | /* "-s" means "read from stdin", but this is how we always | 5034 | /* "-s" means "read from stdin", but this is how we always |
4966 | * operate, so simply do nothing here. */ | 5035 | * operate, so simply do nothing here. */ |
4967 | break; | 5036 | break; |
5037 | #if !BB_MMU | ||
5038 | case '$': | ||
5039 | G.root_pid = xatoi_u(optarg); | ||
5040 | break; | ||
5041 | case '?': | ||
5042 | G.last_return_code = xatoi_u(optarg); | ||
5043 | break; | ||
5044 | case 'R': | ||
5045 | case 'V': | ||
5046 | set_local_var(xstrdup(optarg), 0, opt == 'R'); | ||
5047 | break; | ||
5048 | #endif | ||
4968 | case 'n': | 5049 | case 'n': |
4969 | case 'x': | 5050 | case 'x': |
4970 | if (!set_mode('-', opt)) | 5051 | if (!set_mode('-', opt)) |
@@ -5293,7 +5374,7 @@ static int builtin_export(char **argv) | |||
5293 | return EXIT_SUCCESS; | 5374 | return EXIT_SUCCESS; |
5294 | } | 5375 | } |
5295 | 5376 | ||
5296 | set_local_var(xstrdup(name), 1); | 5377 | set_local_var(xstrdup(name), 1, 0); |
5297 | return EXIT_SUCCESS; | 5378 | return EXIT_SUCCESS; |
5298 | } | 5379 | } |
5299 | 5380 | ||
@@ -5406,7 +5487,7 @@ static int builtin_read(char **argv) | |||
5406 | const char *name = argv[1] ? argv[1] : "REPLY"; | 5487 | const char *name = argv[1] ? argv[1] : "REPLY"; |
5407 | 5488 | ||
5408 | string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name), NULL); | 5489 | string = xmalloc_reads(STDIN_FILENO, xasprintf("%s=", name), NULL); |
5409 | return set_local_var(string, 0); | 5490 | return set_local_var(string, 0, 0); |
5410 | } | 5491 | } |
5411 | 5492 | ||
5412 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set | 5493 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set |