diff options
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 70 |
1 files changed, 36 insertions, 34 deletions
diff --git a/shell/hush.c b/shell/hush.c index cdaa67a3b..8e632e0af 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -91,7 +91,7 @@ | |||
91 | * in word = GLOB, quoting should be significant on char-by-char basis: a*cd"*" | 91 | * in word = GLOB, quoting should be significant on char-by-char basis: a*cd"*" |
92 | */ | 92 | */ |
93 | //config:config HUSH | 93 | //config:config HUSH |
94 | //config: bool "hush (68 kb)" | 94 | //config: bool "hush (70 kb)" |
95 | //config: default y | 95 | //config: default y |
96 | //config: select SHELL_HUSH | 96 | //config: select SHELL_HUSH |
97 | //config: help | 97 | //config: help |
@@ -2255,14 +2255,14 @@ static const char *get_cwd(int force) | |||
2255 | /* | 2255 | /* |
2256 | * Shell and environment variable support | 2256 | * Shell and environment variable support |
2257 | */ | 2257 | */ |
2258 | static struct variable **get_ptr_to_local_var(const char *name, unsigned len) | 2258 | static struct variable **get_ptr_to_local_var(const char *name) |
2259 | { | 2259 | { |
2260 | struct variable **pp; | 2260 | struct variable **pp; |
2261 | struct variable *cur; | 2261 | struct variable *cur; |
2262 | 2262 | ||
2263 | pp = &G.top_var; | 2263 | pp = &G.top_var; |
2264 | while ((cur = *pp) != NULL) { | 2264 | while ((cur = *pp) != NULL) { |
2265 | if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=') | 2265 | if (varcmp(cur->varstr, name) == 0) |
2266 | return pp; | 2266 | return pp; |
2267 | pp = &cur->next; | 2267 | pp = &cur->next; |
2268 | } | 2268 | } |
@@ -2272,21 +2272,20 @@ static struct variable **get_ptr_to_local_var(const char *name, unsigned len) | |||
2272 | static const char* FAST_FUNC get_local_var_value(const char *name) | 2272 | static const char* FAST_FUNC get_local_var_value(const char *name) |
2273 | { | 2273 | { |
2274 | struct variable **vpp; | 2274 | struct variable **vpp; |
2275 | unsigned len = strlen(name); | ||
2276 | 2275 | ||
2277 | if (G.expanded_assignments) { | 2276 | if (G.expanded_assignments) { |
2278 | char **cpp = G.expanded_assignments; | 2277 | char **cpp = G.expanded_assignments; |
2279 | while (*cpp) { | 2278 | while (*cpp) { |
2280 | char *cp = *cpp; | 2279 | char *cp = *cpp; |
2281 | if (strncmp(cp, name, len) == 0 && cp[len] == '=') | 2280 | if (varcmp(cp, name) == 0) |
2282 | return cp + len + 1; | 2281 | return strchr(cp, '=') + 1; |
2283 | cpp++; | 2282 | cpp++; |
2284 | } | 2283 | } |
2285 | } | 2284 | } |
2286 | 2285 | ||
2287 | vpp = get_ptr_to_local_var(name, len); | 2286 | vpp = get_ptr_to_local_var(name); |
2288 | if (vpp) | 2287 | if (vpp) |
2289 | return (*vpp)->varstr + len + 1; | 2288 | return strchr((*vpp)->varstr, '=') + 1; |
2290 | 2289 | ||
2291 | if (strcmp(name, "PPID") == 0) | 2290 | if (strcmp(name, "PPID") == 0) |
2292 | return utoa(G.root_ppid); | 2291 | return utoa(G.root_ppid); |
@@ -2319,13 +2318,11 @@ static const char* FAST_FUNC get_local_var_value(const char *name) | |||
2319 | } | 2318 | } |
2320 | 2319 | ||
2321 | #if ENABLE_HUSH_GETOPTS | 2320 | #if ENABLE_HUSH_GETOPTS |
2322 | static void handle_changed_special_names(const char *name, unsigned name_len) | 2321 | static void handle_changed_special_names(const char *name) |
2323 | { | 2322 | { |
2324 | if (name_len == 6) { | 2323 | if (varcmp(name, "OPTIND") == 0) { |
2325 | if (strncmp(name, "OPTIND", 6) == 0) { | 2324 | G.getopt_count = 0; |
2326 | G.getopt_count = 0; | 2325 | return; |
2327 | return; | ||
2328 | } | ||
2329 | } | 2326 | } |
2330 | } | 2327 | } |
2331 | #else | 2328 | #else |
@@ -2476,7 +2473,7 @@ static int set_local_var(char *str, unsigned flags) | |||
2476 | } | 2473 | } |
2477 | free(free_me); | 2474 | free(free_me); |
2478 | 2475 | ||
2479 | handle_changed_special_names(cur->varstr, name_len - 1); | 2476 | handle_changed_special_names(cur->varstr); |
2480 | 2477 | ||
2481 | return retval; | 2478 | return retval; |
2482 | } | 2479 | } |
@@ -2499,16 +2496,14 @@ static void set_pwd_var(unsigned flag) | |||
2499 | } | 2496 | } |
2500 | 2497 | ||
2501 | #if ENABLE_HUSH_UNSET || ENABLE_HUSH_GETOPTS | 2498 | #if ENABLE_HUSH_UNSET || ENABLE_HUSH_GETOPTS |
2502 | static int unset_local_var_len(const char *name, int name_len) | 2499 | static int unset_local_var(const char *name) |
2503 | { | 2500 | { |
2504 | struct variable *cur; | 2501 | struct variable *cur; |
2505 | struct variable **cur_pp; | 2502 | struct variable **cur_pp; |
2506 | 2503 | ||
2507 | cur_pp = &G.top_var; | 2504 | cur_pp = &G.top_var; |
2508 | while ((cur = *cur_pp) != NULL) { | 2505 | while ((cur = *cur_pp) != NULL) { |
2509 | if (strncmp(cur->varstr, name, name_len) == 0 | 2506 | if (varcmp(cur->varstr, name) == 0) { |
2510 | && cur->varstr[name_len] == '=' | ||
2511 | ) { | ||
2512 | if (cur->flg_read_only) { | 2507 | if (cur->flg_read_only) { |
2513 | bb_error_msg("%s: readonly variable", name); | 2508 | bb_error_msg("%s: readonly variable", name); |
2514 | return EXIT_FAILURE; | 2509 | return EXIT_FAILURE; |
@@ -2527,15 +2522,10 @@ static int unset_local_var_len(const char *name, int name_len) | |||
2527 | } | 2522 | } |
2528 | 2523 | ||
2529 | /* Handle "unset LINENO" et al even if did not find the variable to unset */ | 2524 | /* Handle "unset LINENO" et al even if did not find the variable to unset */ |
2530 | handle_changed_special_names(name, name_len); | 2525 | handle_changed_special_names(name); |
2531 | 2526 | ||
2532 | return EXIT_SUCCESS; | 2527 | return EXIT_SUCCESS; |
2533 | } | 2528 | } |
2534 | |||
2535 | static int unset_local_var(const char *name) | ||
2536 | { | ||
2537 | return unset_local_var_len(name, strlen(name)); | ||
2538 | } | ||
2539 | #endif | 2529 | #endif |
2540 | 2530 | ||
2541 | 2531 | ||
@@ -2581,7 +2571,7 @@ static void set_vars_and_save_old(char **strings) | |||
2581 | eq = strchr(*s, '='); | 2571 | eq = strchr(*s, '='); |
2582 | if (HUSH_DEBUG && !eq) | 2572 | if (HUSH_DEBUG && !eq) |
2583 | bb_simple_error_msg_and_die("BUG in varexp4"); | 2573 | bb_simple_error_msg_and_die("BUG in varexp4"); |
2584 | var_pp = get_ptr_to_local_var(*s, eq - *s); | 2574 | var_pp = get_ptr_to_local_var(*s); |
2585 | if (var_pp) { | 2575 | if (var_pp) { |
2586 | var_p = *var_pp; | 2576 | var_p = *var_pp; |
2587 | if (var_p->flg_read_only) { | 2577 | if (var_p->flg_read_only) { |
@@ -4316,7 +4306,7 @@ static int done_word(struct parse_context *ctx) | |||
4316 | || endofname(command->argv[0])[0] != '\0' | 4306 | || endofname(command->argv[0])[0] != '\0' |
4317 | ) { | 4307 | ) { |
4318 | /* bash says just "not a valid identifier" */ | 4308 | /* bash says just "not a valid identifier" */ |
4319 | syntax_error("bad variable name in for"); | 4309 | syntax_error("bad for loop variable"); |
4320 | return 1; | 4310 | return 1; |
4321 | } | 4311 | } |
4322 | /* Force FOR to have just one word (variable name) */ | 4312 | /* Force FOR to have just one word (variable name) */ |
@@ -4693,6 +4683,11 @@ static int parse_group(struct parse_context *ctx, | |||
4693 | syntax_error_unexpected_ch(ch); | 4683 | syntax_error_unexpected_ch(ch); |
4694 | return -1; | 4684 | return -1; |
4695 | } | 4685 | } |
4686 | //bash allows functions named "123", "..", "return"! | ||
4687 | // if (endofname(command->argv[0])[0] != '\0') { | ||
4688 | // syntax_error("bad function name"); | ||
4689 | // return -1; | ||
4690 | // } | ||
4696 | nommu_addchr(&ctx->as_string, ch); | 4691 | nommu_addchr(&ctx->as_string, ch); |
4697 | command->cmd_type = CMD_FUNCDEF; | 4692 | command->cmd_type = CMD_FUNCDEF; |
4698 | goto skip; | 4693 | goto skip; |
@@ -6398,7 +6393,7 @@ static NOINLINE int encode_then_append_var_plusminus(o_string *output, int n, | |||
6398 | if (!dest.o_expflags) { | 6393 | if (!dest.o_expflags) { |
6399 | if (ch == EOF) | 6394 | if (ch == EOF) |
6400 | break; | 6395 | break; |
6401 | if (!dquoted && strchr(G.ifs, ch)) { | 6396 | if (!dquoted && !(output->o_expflags & EXP_FLAG_SINGLEWORD) && strchr(G.ifs, ch)) { |
6402 | /* PREFIX${x:d${e}f ...} and we met space: expand "d${e}f" and start new word. | 6397 | /* PREFIX${x:d${e}f ...} and we met space: expand "d${e}f" and start new word. |
6403 | * do not assume we are at the start of the word (PREFIX above). | 6398 | * do not assume we are at the start of the word (PREFIX above). |
6404 | */ | 6399 | */ |
@@ -11178,7 +11173,7 @@ static int FAST_FUNC builtin_umask(char **argv) | |||
11178 | } | 11173 | } |
11179 | #endif | 11174 | #endif |
11180 | 11175 | ||
11181 | #if ENABLE_HUSH_EXPORT || ENABLE_HUSH_TRAP | 11176 | #if ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY || ENABLE_HUSH_SET || ENABLE_HUSH_TRAP |
11182 | static void print_escaped(const char *s) | 11177 | static void print_escaped(const char *s) |
11183 | { | 11178 | { |
11184 | //TODO? bash "set" does not quote variables which contain only alnums and "%+,-./:=@_~", | 11179 | //TODO? bash "set" does not quote variables which contain only alnums and "%+,-./:=@_~", |
@@ -11215,7 +11210,7 @@ static int helper_export_local(char **argv, unsigned flags) | |||
11215 | if (*name_end == '\0') { | 11210 | if (*name_end == '\0') { |
11216 | struct variable *var, **vpp; | 11211 | struct variable *var, **vpp; |
11217 | 11212 | ||
11218 | vpp = get_ptr_to_local_var(name, name_end - name); | 11213 | vpp = get_ptr_to_local_var(name); |
11219 | var = vpp ? *vpp : NULL; | 11214 | var = vpp ? *vpp : NULL; |
11220 | 11215 | ||
11221 | if (flags & SETFLAG_UNEXPORT) { | 11216 | if (flags & SETFLAG_UNEXPORT) { |
@@ -11317,8 +11312,8 @@ static int FAST_FUNC builtin_export(char **argv) | |||
11317 | 11312 | ||
11318 | if (!p) /* wtf? take next variable */ | 11313 | if (!p) /* wtf? take next variable */ |
11319 | continue; | 11314 | continue; |
11320 | /* export var= */ | 11315 | /* "export VAR=" */ |
11321 | printf("export %.*s", (int)(p - s) + 1, s); | 11316 | printf("%s %.*s", "export", (int)(p - s) + 1, s); |
11322 | print_escaped(p + 1); | 11317 | print_escaped(p + 1); |
11323 | putchar('\n'); | 11318 | putchar('\n'); |
11324 | # endif | 11319 | # endif |
@@ -11362,8 +11357,15 @@ static int FAST_FUNC builtin_readonly(char **argv) | |||
11362 | struct variable *e; | 11357 | struct variable *e; |
11363 | for (e = G.top_var; e; e = e->next) { | 11358 | for (e = G.top_var; e; e = e->next) { |
11364 | if (e->flg_read_only) { | 11359 | if (e->flg_read_only) { |
11365 | //TODO: quote value: readonly VAR='VAL' | 11360 | const char *s = e->varstr; |
11366 | printf("readonly %s\n", e->varstr); | 11361 | const char *p = strchr(s, '='); |
11362 | |||
11363 | if (!p) /* wtf? take next variable */ | ||
11364 | continue; | ||
11365 | /* "readonly VAR=" */ | ||
11366 | printf("%s %.*s", "readonly", (int)(p - s) + 1, s); | ||
11367 | print_escaped(p + 1); | ||
11368 | putchar('\n'); | ||
11367 | } | 11369 | } |
11368 | } | 11370 | } |
11369 | return EXIT_SUCCESS; | 11371 | return EXIT_SUCCESS; |