diff options
author | Ron Yorston <rmy@pobox.com> | 2019-05-27 11:56:52 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2019-05-27 11:56:52 +0100 |
commit | a61949401890cbb33a9d6c4571b51c53460ad438 (patch) | |
tree | 64dedaddb89896d5b1670a421af123670ca2120b /shell/hush.c | |
parent | 03a7b173605a890e1db5177ecd5b8dd591081c41 (diff) | |
parent | bcb1fc3e6ca6fe902610f507eaf9b0b58a5c583a (diff) | |
download | busybox-w32-a61949401890cbb33a9d6c4571b51c53460ad438.tar.gz busybox-w32-a61949401890cbb33a9d6c4571b51c53460ad438.tar.bz2 busybox-w32-a61949401890cbb33a9d6c4571b51c53460ad438.zip |
Merge branch 'busybox' into merge
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 241 |
1 files changed, 123 insertions, 118 deletions
diff --git a/shell/hush.c b/shell/hush.c index b3ae73b9b..4b08232a4 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -466,9 +466,9 @@ | |||
466 | 466 | ||
467 | #define JOB_STATUS_FORMAT "[%u] %-22s %.40s\n" | 467 | #define JOB_STATUS_FORMAT "[%u] %-22s %.40s\n" |
468 | 468 | ||
469 | #define _SPECIAL_VARS_STR "_*@$!?#" | 469 | #define _SPECIAL_VARS_STR "_*@$!?#-" |
470 | #define SPECIAL_VARS_STR ("_*@$!?#" + 1) | 470 | #define SPECIAL_VARS_STR ("_*@$!?#-" + 1) |
471 | #define NUMERIC_SPECVARS_STR ("_*@$!?#" + 3) | 471 | #define NUMERIC_SPECVARS_STR ("_*@$!?#-" + 3) |
472 | #if BASH_PATTERN_SUBST | 472 | #if BASH_PATTERN_SUBST |
473 | /* Support / and // replace ops */ | 473 | /* Support / and // replace ops */ |
474 | /* Note that // is stored as \ in "encoded" string representation */ | 474 | /* Note that // is stored as \ in "encoded" string representation */ |
@@ -854,8 +854,7 @@ struct globals { | |||
854 | /* 'interactive_fd' is a fd# open to ctty, if we have one | 854 | /* 'interactive_fd' is a fd# open to ctty, if we have one |
855 | * _AND_ if we decided to act interactively */ | 855 | * _AND_ if we decided to act interactively */ |
856 | int interactive_fd; | 856 | int interactive_fd; |
857 | const char *PS1; | 857 | IF_NOT_FEATURE_EDITING_FANCY_PROMPT(char *PS1;) |
858 | IF_FEATURE_EDITING_FANCY_PROMPT(const char *PS2;) | ||
859 | # define G_interactive_fd (G.interactive_fd) | 858 | # define G_interactive_fd (G.interactive_fd) |
860 | #else | 859 | #else |
861 | # define G_interactive_fd 0 | 860 | # define G_interactive_fd 0 |
@@ -903,6 +902,7 @@ struct globals { | |||
903 | #else | 902 | #else |
904 | # define G_x_mode 0 | 903 | # define G_x_mode 0 |
905 | #endif | 904 | #endif |
905 | char opt_s; | ||
906 | #if ENABLE_HUSH_INTERACTIVE | 906 | #if ENABLE_HUSH_INTERACTIVE |
907 | smallint promptmode; /* 0: PS1, 1: PS2 */ | 907 | smallint promptmode; /* 0: PS1, 1: PS2 */ |
908 | #endif | 908 | #endif |
@@ -968,8 +968,8 @@ struct globals { | |||
968 | smallint we_have_children; | 968 | smallint we_have_children; |
969 | #endif | 969 | #endif |
970 | #if ENABLE_HUSH_LINENO_VAR | 970 | #if ENABLE_HUSH_LINENO_VAR |
971 | unsigned lineno; | 971 | unsigned parse_lineno; |
972 | char *lineno_var; | 972 | unsigned execute_lineno; |
973 | #endif | 973 | #endif |
974 | HFILE *HFILE_list; | 974 | HFILE *HFILE_list; |
975 | /* Which signals have non-DFL handler (even with no traps set)? | 975 | /* Which signals have non-DFL handler (even with no traps set)? |
@@ -1009,6 +1009,7 @@ struct globals { | |||
1009 | int debug_indent; | 1009 | int debug_indent; |
1010 | #endif | 1010 | #endif |
1011 | struct sigaction sa; | 1011 | struct sigaction sa; |
1012 | char optstring_buf[sizeof("eixs")]; | ||
1012 | #if BASH_EPOCH_VARS | 1013 | #if BASH_EPOCH_VARS |
1013 | char epoch_buf[sizeof("%lu.nnnnnn") + sizeof(long)*3]; | 1014 | char epoch_buf[sizeof("%lu.nnnnnn") + sizeof(long)*3]; |
1014 | #endif | 1015 | #endif |
@@ -1448,13 +1449,6 @@ static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch) | |||
1448 | #endif | 1449 | #endif |
1449 | 1450 | ||
1450 | 1451 | ||
1451 | #if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT | ||
1452 | static void cmdedit_update_prompt(void); | ||
1453 | #else | ||
1454 | # define cmdedit_update_prompt() ((void)0) | ||
1455 | #endif | ||
1456 | |||
1457 | |||
1458 | /* Utility functions | 1452 | /* Utility functions |
1459 | */ | 1453 | */ |
1460 | /* Replace each \x with x in place, return ptr past NUL. */ | 1454 | /* Replace each \x with x in place, return ptr past NUL. */ |
@@ -2039,7 +2033,8 @@ static sighandler_t pick_sighandler(unsigned sig) | |||
2039 | static void hush_exit(int exitcode) | 2033 | static void hush_exit(int exitcode) |
2040 | { | 2034 | { |
2041 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 2035 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
2042 | save_history(G.line_input_state); | 2036 | if (G.line_input_state) |
2037 | save_history(G.line_input_state); | ||
2043 | #endif | 2038 | #endif |
2044 | 2039 | ||
2045 | fflush_all(); | 2040 | fflush_all(); |
@@ -2229,6 +2224,10 @@ static const char* FAST_FUNC get_local_var_value(const char *name) | |||
2229 | if (strcmp(name, "RANDOM") == 0) | 2224 | if (strcmp(name, "RANDOM") == 0) |
2230 | return utoa(next_random(&G.random_gen)); | 2225 | return utoa(next_random(&G.random_gen)); |
2231 | #endif | 2226 | #endif |
2227 | #if ENABLE_HUSH_LINENO_VAR | ||
2228 | if (strcmp(name, "LINENO") == 0) | ||
2229 | return utoa(G.execute_lineno); | ||
2230 | #endif | ||
2232 | #if BASH_EPOCH_VARS | 2231 | #if BASH_EPOCH_VARS |
2233 | { | 2232 | { |
2234 | const char *fmt = NULL; | 2233 | const char *fmt = NULL; |
@@ -2248,32 +2247,20 @@ static const char* FAST_FUNC get_local_var_value(const char *name) | |||
2248 | return NULL; | 2247 | return NULL; |
2249 | } | 2248 | } |
2250 | 2249 | ||
2250 | #if ENABLE_HUSH_GETOPTS | ||
2251 | static void handle_changed_special_names(const char *name, unsigned name_len) | 2251 | static void handle_changed_special_names(const char *name, unsigned name_len) |
2252 | { | 2252 | { |
2253 | if (ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT | 2253 | if (name_len == 6) { |
2254 | && name_len == 3 && name[0] == 'P' && name[1] == 'S' | ||
2255 | ) { | ||
2256 | cmdedit_update_prompt(); | ||
2257 | return; | ||
2258 | } | ||
2259 | |||
2260 | if ((ENABLE_HUSH_LINENO_VAR || ENABLE_HUSH_GETOPTS) | ||
2261 | && name_len == 6 | ||
2262 | ) { | ||
2263 | #if ENABLE_HUSH_LINENO_VAR | ||
2264 | if (strncmp(name, "LINENO", 6) == 0) { | ||
2265 | G.lineno_var = NULL; | ||
2266 | return; | ||
2267 | } | ||
2268 | #endif | ||
2269 | #if ENABLE_HUSH_GETOPTS | ||
2270 | if (strncmp(name, "OPTIND", 6) == 0) { | 2254 | if (strncmp(name, "OPTIND", 6) == 0) { |
2271 | G.getopt_count = 0; | 2255 | G.getopt_count = 0; |
2272 | return; | 2256 | return; |
2273 | } | 2257 | } |
2274 | #endif | ||
2275 | } | 2258 | } |
2276 | } | 2259 | } |
2260 | #else | ||
2261 | /* Do not even bother evaluating arguments */ | ||
2262 | # define handle_changed_special_names(...) ((void)0) | ||
2263 | #endif | ||
2277 | 2264 | ||
2278 | /* str holds "NAME=VAL" and is expected to be malloced. | 2265 | /* str holds "NAME=VAL" and is expected to be malloced. |
2279 | * We take ownership of it. | 2266 | * We take ownership of it. |
@@ -2289,6 +2276,7 @@ static int set_local_var(char *str, unsigned flags) | |||
2289 | char *free_me = NULL; | 2276 | char *free_me = NULL; |
2290 | char *eq_sign; | 2277 | char *eq_sign; |
2291 | int name_len; | 2278 | int name_len; |
2279 | int retval; | ||
2292 | unsigned local_lvl = (flags >> SETFLAG_VARLVL_SHIFT); | 2280 | unsigned local_lvl = (flags >> SETFLAG_VARLVL_SHIFT); |
2293 | 2281 | ||
2294 | eq_sign = strchr(str, '='); | 2282 | eq_sign = strchr(str, '='); |
@@ -2402,24 +2390,24 @@ static int set_local_var(char *str, unsigned flags) | |||
2402 | #endif | 2390 | #endif |
2403 | if (flags & SETFLAG_EXPORT) | 2391 | if (flags & SETFLAG_EXPORT) |
2404 | cur->flg_export = 1; | 2392 | cur->flg_export = 1; |
2393 | retval = 0; | ||
2405 | if (cur->flg_export) { | 2394 | if (cur->flg_export) { |
2406 | if (flags & SETFLAG_UNEXPORT) { | 2395 | if (flags & SETFLAG_UNEXPORT) { |
2407 | cur->flg_export = 0; | 2396 | cur->flg_export = 0; |
2408 | /* unsetenv was already done */ | 2397 | /* unsetenv was already done */ |
2409 | } else { | 2398 | } else { |
2410 | int i; | ||
2411 | debug_printf_env("%s: putenv '%s'/%u\n", __func__, cur->varstr, cur->var_nest_level); | 2399 | debug_printf_env("%s: putenv '%s'/%u\n", __func__, cur->varstr, cur->var_nest_level); |
2412 | i = putenv(cur->varstr); | 2400 | retval = putenv(cur->varstr); |
2413 | /* only now we can free old exported malloced string */ | 2401 | /* fall through to "free(free_me)" - |
2414 | free(free_me); | 2402 | * only now we can free old exported malloced string |
2415 | return i; | 2403 | */ |
2416 | } | 2404 | } |
2417 | } | 2405 | } |
2418 | free(free_me); | 2406 | free(free_me); |
2419 | 2407 | ||
2420 | handle_changed_special_names(cur->varstr, name_len - 1); | 2408 | handle_changed_special_names(cur->varstr, name_len - 1); |
2421 | 2409 | ||
2422 | return 0; | 2410 | return retval; |
2423 | } | 2411 | } |
2424 | 2412 | ||
2425 | static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) | 2413 | static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) |
@@ -2462,7 +2450,7 @@ static int unset_local_var_len(const char *name, int name_len) | |||
2462 | cur_pp = &cur->next; | 2450 | cur_pp = &cur->next; |
2463 | } | 2451 | } |
2464 | 2452 | ||
2465 | /* Handle "unset PS1" et al even if did not find the variable to unset */ | 2453 | /* Handle "unset LINENO" et al even if did not find the variable to unset */ |
2466 | handle_changed_special_names(name, name_len); | 2454 | handle_changed_special_names(name, name_len); |
2467 | 2455 | ||
2468 | return EXIT_SUCCESS; | 2456 | return EXIT_SUCCESS; |
@@ -2581,36 +2569,27 @@ static void reinit_unicode_for_hush(void) | |||
2581 | * \ | 2569 | * \ |
2582 | * It exercises a lot of corner cases. | 2570 | * It exercises a lot of corner cases. |
2583 | */ | 2571 | */ |
2584 | # if ENABLE_FEATURE_EDITING_FANCY_PROMPT | ||
2585 | static void cmdedit_update_prompt(void) | ||
2586 | { | ||
2587 | G.PS1 = get_local_var_value("PS1"); | ||
2588 | if (G.PS1 == NULL) | ||
2589 | G.PS1 = ""; | ||
2590 | G.PS2 = get_local_var_value("PS2"); | ||
2591 | if (G.PS2 == NULL) | ||
2592 | G.PS2 = ""; | ||
2593 | } | ||
2594 | # endif | ||
2595 | static const char *setup_prompt_string(void) | 2572 | static const char *setup_prompt_string(void) |
2596 | { | 2573 | { |
2597 | const char *prompt_str; | 2574 | const char *prompt_str; |
2598 | 2575 | ||
2599 | debug_printf_prompt("%s promptmode:%d\n", __func__, G.promptmode); | 2576 | debug_printf_prompt("%s promptmode:%d\n", __func__, G.promptmode); |
2600 | 2577 | ||
2601 | IF_FEATURE_EDITING_FANCY_PROMPT( prompt_str = G.PS2;) | 2578 | # if ENABLE_FEATURE_EDITING_FANCY_PROMPT |
2602 | IF_NOT_FEATURE_EDITING_FANCY_PROMPT(prompt_str = "> ";) | 2579 | prompt_str = get_local_var_value(G.promptmode == 0 ? "PS1" : "PS2"); |
2580 | if (!prompt_str) | ||
2581 | prompt_str = ""; | ||
2582 | # else | ||
2583 | prompt_str = "> "; /* if PS2, else... */ | ||
2603 | if (G.promptmode == 0) { /* PS1 */ | 2584 | if (G.promptmode == 0) { /* PS1 */ |
2604 | if (!ENABLE_FEATURE_EDITING_FANCY_PROMPT) { | 2585 | /* No fancy prompts supported, (re)generate "CURDIR $ " by hand */ |
2605 | /* No fancy prompts supported, (re)generate "CURDIR $ " by hand */ | 2586 | free(G.PS1); |
2606 | free((char*)G.PS1); | 2587 | /* bash uses $PWD value, even if it is set by user. |
2607 | /* bash uses $PWD value, even if it is set by user. | 2588 | * It uses current dir only if PWD is unset. |
2608 | * It uses current dir only if PWD is unset. | 2589 | * We always use current dir. */ |
2609 | * We always use current dir. */ | 2590 | G.PS1 = xasprintf("%s %c ", get_cwd(0), (geteuid() != 0) ? '$' : '#'); |
2610 | G.PS1 = xasprintf("%s %c ", get_cwd(0), (geteuid() != 0) ? '$' : '#'); | ||
2611 | } | ||
2612 | prompt_str = G.PS1; | ||
2613 | } | 2591 | } |
2592 | # endif | ||
2614 | debug_printf("prompt_str '%s'\n", prompt_str); | 2593 | debug_printf("prompt_str '%s'\n", prompt_str); |
2615 | return prompt_str; | 2594 | return prompt_str; |
2616 | } | 2595 | } |
@@ -2747,8 +2726,8 @@ static int i_getch(struct in_str *i) | |||
2747 | i->last_char = ch; | 2726 | i->last_char = ch; |
2748 | #if ENABLE_HUSH_LINENO_VAR | 2727 | #if ENABLE_HUSH_LINENO_VAR |
2749 | if (ch == '\n') { | 2728 | if (ch == '\n') { |
2750 | G.lineno++; | 2729 | G.parse_lineno++; |
2751 | debug_printf_parse("G.lineno++ = %u\n", G.lineno); | 2730 | debug_printf_parse("G.parse_lineno++ = %u\n", G.parse_lineno); |
2752 | } | 2731 | } |
2753 | #endif | 2732 | #endif |
2754 | return ch; | 2733 | return ch; |
@@ -3750,8 +3729,8 @@ static int done_command(struct parse_context *ctx) | |||
3750 | clear_and_ret: | 3729 | clear_and_ret: |
3751 | memset(command, 0, sizeof(*command)); | 3730 | memset(command, 0, sizeof(*command)); |
3752 | #if ENABLE_HUSH_LINENO_VAR | 3731 | #if ENABLE_HUSH_LINENO_VAR |
3753 | command->lineno = G.lineno; | 3732 | command->lineno = G.parse_lineno; |
3754 | debug_printf_parse("command->lineno = G.lineno (%u)\n", G.lineno); | 3733 | debug_printf_parse("command->lineno = G.parse_lineno (%u)\n", G.parse_lineno); |
3755 | #endif | 3734 | #endif |
3756 | return pi->num_cmds; /* used only for 0/nonzero check */ | 3735 | return pi->num_cmds; /* used only for 0/nonzero check */ |
3757 | } | 3736 | } |
@@ -4198,7 +4177,7 @@ static int done_word(struct parse_context *ctx) | |||
4198 | #if ENABLE_HUSH_LOOPS | 4177 | #if ENABLE_HUSH_LOOPS |
4199 | if (ctx->ctx_res_w == RES_FOR) { | 4178 | if (ctx->ctx_res_w == RES_FOR) { |
4200 | if (ctx->word.has_quoted_part | 4179 | if (ctx->word.has_quoted_part |
4201 | || !is_well_formed_var_name(command->argv[0], '\0') | 4180 | || endofname(command->argv[0])[0] != '\0' |
4202 | ) { | 4181 | ) { |
4203 | /* bash says just "not a valid identifier" */ | 4182 | /* bash says just "not a valid identifier" */ |
4204 | syntax_error("not a valid identifier in for"); | 4183 | syntax_error("not a valid identifier in for"); |
@@ -4912,6 +4891,7 @@ static int parse_dollar(o_string *as_string, | |||
4912 | case '#': /* number of args */ | 4891 | case '#': /* number of args */ |
4913 | case '*': /* args */ | 4892 | case '*': /* args */ |
4914 | case '@': /* args */ | 4893 | case '@': /* args */ |
4894 | case '-': /* $- option flags set by set builtin or shell options (-i etc) */ | ||
4915 | goto make_one_char_var; | 4895 | goto make_one_char_var; |
4916 | case '{': { | 4896 | case '{': { |
4917 | char len_single_ch; | 4897 | char len_single_ch; |
@@ -5086,11 +5066,10 @@ static int parse_dollar(o_string *as_string, | |||
5086 | case '_': | 5066 | case '_': |
5087 | goto make_var; | 5067 | goto make_var; |
5088 | #if 0 | 5068 | #if 0 |
5089 | /* TODO: $_ and $-: */ | 5069 | /* TODO: $_: */ |
5090 | /* $_ Shell or shell script name; or last argument of last command | 5070 | /* $_ Shell or shell script name; or last argument of last command |
5091 | * (if last command wasn't a pipe; if it was, bash sets $_ to ""); | 5071 | * (if last command wasn't a pipe; if it was, bash sets $_ to ""); |
5092 | * but in command's env, set to full pathname used to invoke it */ | 5072 | * but in command's env, set to full pathname used to invoke it */ |
5093 | /* $- Option flags set by set builtin or shell options (-i etc) */ | ||
5094 | ch = i_getch(input); | 5073 | ch = i_getch(input); |
5095 | nommu_addchr(as_string, ch); | 5074 | nommu_addchr(as_string, ch); |
5096 | ch = i_peek_and_eat_bkslash_nl(input); | 5075 | ch = i_peek_and_eat_bkslash_nl(input); |
@@ -5372,7 +5351,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5372 | if ((ctx.is_assignment == MAYBE_ASSIGNMENT | 5351 | if ((ctx.is_assignment == MAYBE_ASSIGNMENT |
5373 | || ctx.is_assignment == WORD_IS_KEYWORD) | 5352 | || ctx.is_assignment == WORD_IS_KEYWORD) |
5374 | && ch == '=' | 5353 | && ch == '=' |
5375 | && is_well_formed_var_name(ctx.word.data, '=') | 5354 | && endofname(ctx.word.data)[0] == '=' |
5376 | ) { | 5355 | ) { |
5377 | ctx.is_assignment = DEFINITELY_ASSIGNMENT; | 5356 | ctx.is_assignment = DEFINITELY_ASSIGNMENT; |
5378 | debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); | 5357 | debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); |
@@ -6119,6 +6098,12 @@ static int encode_then_append_var_plusminus(o_string *output, int n, | |||
6119 | /* string has no special chars | 6098 | /* string has no special chars |
6120 | * && string has no $IFS chars | 6099 | * && string has no $IFS chars |
6121 | */ | 6100 | */ |
6101 | if (dquoted) { | ||
6102 | /* Prints 1 (quoted expansion is a "" word, not nothing): | ||
6103 | * set -- "${notexist-}"; echo $# | ||
6104 | */ | ||
6105 | output->has_quoted_part = 1; | ||
6106 | } | ||
6122 | return expand_vars_to_list(output, n, str); | 6107 | return expand_vars_to_list(output, n, str); |
6123 | } | 6108 | } |
6124 | 6109 | ||
@@ -6415,6 +6400,26 @@ static NOINLINE int expand_one_var(o_string *output, int n, | |||
6415 | case '#': /* argc */ | 6400 | case '#': /* argc */ |
6416 | val = utoa(G.global_argc ? G.global_argc-1 : 0); | 6401 | val = utoa(G.global_argc ? G.global_argc-1 : 0); |
6417 | break; | 6402 | break; |
6403 | case '-': { /* active options */ | ||
6404 | /* Check set_mode() to see what option chars we support */ | ||
6405 | char *cp; | ||
6406 | val = cp = G.optstring_buf; | ||
6407 | if (G.o_opt[OPT_O_ERREXIT]) | ||
6408 | *cp++ = 'e'; | ||
6409 | if (G_interactive_fd) | ||
6410 | *cp++ = 'i'; | ||
6411 | if (G_x_mode) | ||
6412 | *cp++ = 'x'; | ||
6413 | /* If G.o_opt[OPT_O_NOEXEC] is true, | ||
6414 | * commands read but are not executed, | ||
6415 | * so $- can not execute too, 'n' is never seen in $-. | ||
6416 | */ | ||
6417 | if (G.opt_s) | ||
6418 | *cp++ = 's'; | ||
6419 | //TODO: show 'c' if executed via "hush -c 'CMDS'" (bash only, not ash) | ||
6420 | *cp = '\0'; | ||
6421 | break; | ||
6422 | } | ||
6418 | default: | 6423 | default: |
6419 | val = get_local_var_value(var); | 6424 | val = get_local_var_value(var); |
6420 | } | 6425 | } |
@@ -7275,22 +7280,22 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger) | |||
7275 | static void parse_and_run_string(const char *s) | 7280 | static void parse_and_run_string(const char *s) |
7276 | { | 7281 | { |
7277 | struct in_str input; | 7282 | struct in_str input; |
7278 | //IF_HUSH_LINENO_VAR(unsigned sv = G.lineno;) | 7283 | //IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;) |
7279 | 7284 | ||
7280 | setup_string_in_str(&input, s); | 7285 | setup_string_in_str(&input, s); |
7281 | parse_and_run_stream(&input, '\0'); | 7286 | parse_and_run_stream(&input, '\0'); |
7282 | //IF_HUSH_LINENO_VAR(G.lineno = sv;) | 7287 | //IF_HUSH_LINENO_VAR(G.parse_lineno = sv;) |
7283 | } | 7288 | } |
7284 | 7289 | ||
7285 | static void parse_and_run_file(HFILE *fp) | 7290 | static void parse_and_run_file(HFILE *fp) |
7286 | { | 7291 | { |
7287 | struct in_str input; | 7292 | struct in_str input; |
7288 | IF_HUSH_LINENO_VAR(unsigned sv = G.lineno;) | 7293 | IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;) |
7289 | 7294 | ||
7290 | IF_HUSH_LINENO_VAR(G.lineno = 1;) | 7295 | IF_HUSH_LINENO_VAR(G.parse_lineno = 1;) |
7291 | setup_file_in_str(&input, fp); | 7296 | setup_file_in_str(&input, fp); |
7292 | parse_and_run_stream(&input, ';'); | 7297 | parse_and_run_stream(&input, ';'); |
7293 | IF_HUSH_LINENO_VAR(G.lineno = sv;) | 7298 | IF_HUSH_LINENO_VAR(G.parse_lineno = sv;) |
7294 | } | 7299 | } |
7295 | 7300 | ||
7296 | #if ENABLE_HUSH_TICK | 7301 | #if ENABLE_HUSH_TICK |
@@ -7598,10 +7603,10 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) | |||
7598 | avoid_fd = 9; | 7603 | avoid_fd = 9; |
7599 | 7604 | ||
7600 | #if ENABLE_HUSH_INTERACTIVE | 7605 | #if ENABLE_HUSH_INTERACTIVE |
7601 | if (fd == G.interactive_fd) { | 7606 | if (fd == G_interactive_fd) { |
7602 | /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */ | 7607 | /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */ |
7603 | G.interactive_fd = xdup_CLOEXEC_and_close(G.interactive_fd, avoid_fd); | 7608 | G_interactive_fd = xdup_CLOEXEC_and_close(G_interactive_fd, avoid_fd); |
7604 | debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G.interactive_fd); | 7609 | debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G_interactive_fd); |
7605 | return 1; /* "we closed fd" */ | 7610 | return 1; /* "we closed fd" */ |
7606 | } | 7611 | } |
7607 | #endif | 7612 | #endif |
@@ -7677,7 +7682,7 @@ static void restore_redirects(struct squirrel *sq) | |||
7677 | free(sq); | 7682 | free(sq); |
7678 | } | 7683 | } |
7679 | 7684 | ||
7680 | /* If moved, G.interactive_fd stays on new fd, not restoring it */ | 7685 | /* If moved, G_interactive_fd stays on new fd, not restoring it */ |
7681 | } | 7686 | } |
7682 | 7687 | ||
7683 | #if ENABLE_FEATURE_SH_STANDALONE && BB_MMU | 7688 | #if ENABLE_FEATURE_SH_STANDALONE && BB_MMU |
@@ -7694,7 +7699,7 @@ static int internally_opened_fd(int fd, struct squirrel *sq) | |||
7694 | int i; | 7699 | int i; |
7695 | 7700 | ||
7696 | #if ENABLE_HUSH_INTERACTIVE | 7701 | #if ENABLE_HUSH_INTERACTIVE |
7697 | if (fd == G.interactive_fd) | 7702 | if (fd == G_interactive_fd) |
7698 | return 1; | 7703 | return 1; |
7699 | #endif | 7704 | #endif |
7700 | /* If this one of script's fds? */ | 7705 | /* If this one of script's fds? */ |
@@ -8989,8 +8994,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
8989 | struct variable *old_vars; | 8994 | struct variable *old_vars; |
8990 | 8995 | ||
8991 | #if ENABLE_HUSH_LINENO_VAR | 8996 | #if ENABLE_HUSH_LINENO_VAR |
8992 | if (G.lineno_var) | 8997 | G.execute_lineno = command->lineno; |
8993 | strcpy(G.lineno_var + sizeof("LINENO=")-1, utoa(command->lineno)); | ||
8994 | #endif | 8998 | #endif |
8995 | 8999 | ||
8996 | if (argv[command->assignment_cnt] == NULL) { | 9000 | if (argv[command->assignment_cnt] == NULL) { |
@@ -9223,8 +9227,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
9223 | xpiped_pair(pipefds); | 9227 | xpiped_pair(pipefds); |
9224 | 9228 | ||
9225 | #if ENABLE_HUSH_LINENO_VAR | 9229 | #if ENABLE_HUSH_LINENO_VAR |
9226 | if (G.lineno_var) | 9230 | G.execute_lineno = command->lineno; |
9227 | strcpy(G.lineno_var + sizeof("LINENO=")-1, utoa(command->lineno)); | ||
9228 | #endif | 9231 | #endif |
9229 | 9232 | ||
9230 | command->pid = BB_MMU ? fork() : vfork(); | 9233 | command->pid = BB_MMU ? fork() : vfork(); |
@@ -9908,14 +9911,6 @@ int hush_main(int argc, char **argv) | |||
9908 | /* Export PWD */ | 9911 | /* Export PWD */ |
9909 | set_pwd_var(SETFLAG_EXPORT); | 9912 | set_pwd_var(SETFLAG_EXPORT); |
9910 | 9913 | ||
9911 | #if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT | ||
9912 | /* Set (but not export) PS1/2 unless already set */ | ||
9913 | if (!get_local_var_value("PS1")) | ||
9914 | set_local_var_from_halves("PS1", "\\w \\$ "); | ||
9915 | if (!get_local_var_value("PS2")) | ||
9916 | set_local_var_from_halves("PS2", "> "); | ||
9917 | #endif | ||
9918 | |||
9919 | #if BASH_HOSTNAME_VAR | 9914 | #if BASH_HOSTNAME_VAR |
9920 | /* Set (but not export) HOSTNAME unless already set */ | 9915 | /* Set (but not export) HOSTNAME unless already set */ |
9921 | if (!get_local_var_value("HOSTNAME")) { | 9916 | if (!get_local_var_value("HOSTNAME")) { |
@@ -9927,6 +9922,11 @@ int hush_main(int argc, char **argv) | |||
9927 | /* IFS is not inherited from the parent environment */ | 9922 | /* IFS is not inherited from the parent environment */ |
9928 | set_local_var_from_halves("IFS", defifs); | 9923 | set_local_var_from_halves("IFS", defifs); |
9929 | 9924 | ||
9925 | if (!get_local_var_value("PATH")) | ||
9926 | set_local_var_from_halves("PATH", bb_default_root_path); | ||
9927 | |||
9928 | /* PS1/PS2 are set later, if we determine that we are interactive */ | ||
9929 | |||
9930 | /* bash also exports SHLVL and _, | 9930 | /* bash also exports SHLVL and _, |
9931 | * and sets (but doesn't export) the following variables: | 9931 | * and sets (but doesn't export) the following variables: |
9932 | * BASH=/bin/bash | 9932 | * BASH=/bin/bash |
@@ -9960,21 +9960,7 @@ int hush_main(int argc, char **argv) | |||
9960 | * PS4='+ ' | 9960 | * PS4='+ ' |
9961 | */ | 9961 | */ |
9962 | 9962 | ||
9963 | #if ENABLE_HUSH_LINENO_VAR | ||
9964 | if (ENABLE_HUSH_LINENO_VAR) { | ||
9965 | char *p = xasprintf("LINENO=%*s", (int)(sizeof(int)*3), ""); | ||
9966 | set_local_var(p, /*flags*/ 0); | ||
9967 | G.lineno_var = p; /* can't assign before set_local_var("LINENO=...") */ | ||
9968 | } | ||
9969 | #endif | ||
9970 | |||
9971 | #if ENABLE_FEATURE_EDITING | ||
9972 | G.line_input_state = new_line_input_t(FOR_SHELL); | ||
9973 | #endif | ||
9974 | |||
9975 | /* Initialize some more globals to non-zero values */ | 9963 | /* Initialize some more globals to non-zero values */ |
9976 | cmdedit_update_prompt(); | ||
9977 | |||
9978 | die_func = restore_ttypgrp_and__exit; | 9964 | die_func = restore_ttypgrp_and__exit; |
9979 | 9965 | ||
9980 | /* Shell is non-interactive at first. We need to call | 9966 | /* Shell is non-interactive at first. We need to call |
@@ -10192,6 +10178,7 @@ int hush_main(int argc, char **argv) | |||
10192 | #endif | 10178 | #endif |
10193 | goto final_return; | 10179 | goto final_return; |
10194 | } | 10180 | } |
10181 | G.opt_s = 1; | ||
10195 | 10182 | ||
10196 | /* Up to here, shell was non-interactive. Now it may become one. | 10183 | /* Up to here, shell was non-interactive. Now it may become one. |
10197 | * NB: don't forget to (re)run install_special_sighandlers() as needed. | 10184 | * NB: don't forget to (re)run install_special_sighandlers() as needed. |
@@ -10260,6 +10247,9 @@ int hush_main(int argc, char **argv) | |||
10260 | } | 10247 | } |
10261 | enable_restore_tty_pgrp_on_exit(); | 10248 | enable_restore_tty_pgrp_on_exit(); |
10262 | 10249 | ||
10250 | # if ENABLE_FEATURE_EDITING | ||
10251 | G.line_input_state = new_line_input_t(FOR_SHELL); | ||
10252 | # endif | ||
10263 | # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 | 10253 | # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 |
10264 | { | 10254 | { |
10265 | const char *hp = get_local_var_value("HISTFILE"); | 10255 | const char *hp = get_local_var_value("HISTFILE"); |
@@ -10308,14 +10298,23 @@ int hush_main(int argc, char **argv) | |||
10308 | * (--norc turns this off, --rcfile <file> overrides) | 10298 | * (--norc turns this off, --rcfile <file> overrides) |
10309 | */ | 10299 | */ |
10310 | 10300 | ||
10311 | if (!ENABLE_FEATURE_SH_EXTRA_QUIET && G_interactive_fd) { | 10301 | if (G_interactive_fd) { |
10312 | /* note: ash and hush share this string */ | 10302 | #if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT |
10313 | printf("\n\n%s %s\n" | 10303 | /* Set (but not export) PS1/2 unless already set */ |
10314 | IF_HUSH_HELP("Enter 'help' for a list of built-in commands.\n") | 10304 | if (!get_local_var_value("PS1")) |
10315 | "\n", | 10305 | set_local_var_from_halves("PS1", "\\w \\$ "); |
10316 | bb_banner, | 10306 | if (!get_local_var_value("PS2")) |
10317 | "hush - the humble shell" | 10307 | set_local_var_from_halves("PS2", "> "); |
10318 | ); | 10308 | #endif |
10309 | if (!ENABLE_FEATURE_SH_EXTRA_QUIET) { | ||
10310 | /* note: ash and hush share this string */ | ||
10311 | printf("\n\n%s %s\n" | ||
10312 | IF_HUSH_HELP("Enter 'help' for a list of built-in commands.\n") | ||
10313 | "\n", | ||
10314 | bb_banner, | ||
10315 | "hush - the humble shell" | ||
10316 | ); | ||
10317 | } | ||
10319 | } | 10318 | } |
10320 | 10319 | ||
10321 | parse_and_run_file(hfopen(NULL)); /* stdin */ | 10320 | parse_and_run_file(hfopen(NULL)); /* stdin */ |
@@ -10378,7 +10377,8 @@ static int FAST_FUNC builtin_help(char **argv UNUSED_PARAM) | |||
10378 | #if MAX_HISTORY && ENABLE_FEATURE_EDITING | 10377 | #if MAX_HISTORY && ENABLE_FEATURE_EDITING |
10379 | static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM) | 10378 | static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM) |
10380 | { | 10379 | { |
10381 | show_history(G.line_input_state); | 10380 | if (G.line_input_state) |
10381 | show_history(G.line_input_state); | ||
10382 | return EXIT_SUCCESS; | 10382 | return EXIT_SUCCESS; |
10383 | } | 10383 | } |
10384 | #endif | 10384 | #endif |
@@ -10687,9 +10687,7 @@ static int helper_export_local(char **argv, unsigned flags) | |||
10687 | { | 10687 | { |
10688 | do { | 10688 | do { |
10689 | char *name = *argv; | 10689 | char *name = *argv; |
10690 | char *name_end = strchrnul(name, '='); | 10690 | const char *name_end = endofname(name); |
10691 | |||
10692 | /* So far we do not check that name is valid (TODO?) */ | ||
10693 | 10691 | ||
10694 | if (*name_end == '\0') { | 10692 | if (*name_end == '\0') { |
10695 | struct variable *var, **vpp; | 10693 | struct variable *var, **vpp; |
@@ -10747,8 +10745,15 @@ static int helper_export_local(char **argv, unsigned flags) | |||
10747 | */ | 10745 | */ |
10748 | name = xasprintf("%s=", name); | 10746 | name = xasprintf("%s=", name); |
10749 | } else { | 10747 | } else { |
10748 | if (*name_end != '=') { | ||
10749 | bb_error_msg("'%s': bad variable name", name); | ||
10750 | /* do not parse following argv[]s: */ | ||
10751 | return 1; | ||
10752 | } | ||
10750 | /* (Un)exporting/making local NAME=VALUE */ | 10753 | /* (Un)exporting/making local NAME=VALUE */ |
10751 | name = xstrdup(name); | 10754 | name = xstrdup(name); |
10755 | /* Testcase: export PS1='\w \$ ' */ | ||
10756 | unbackslash(name); | ||
10752 | } | 10757 | } |
10753 | debug_printf_env("%s: set_local_var('%s')\n", __func__, name); | 10758 | debug_printf_env("%s: set_local_var('%s')\n", __func__, name); |
10754 | if (set_local_var(name, flags)) | 10759 | if (set_local_var(name, flags)) |