diff options
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 404 |
1 files changed, 241 insertions, 163 deletions
diff --git a/shell/hush.c b/shell/hush.c index ab7263381..77f90f82f 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -596,10 +596,10 @@ typedef struct in_str { | |||
596 | /* The descrip member of this structure is only used to make | 596 | /* The descrip member of this structure is only used to make |
597 | * debugging output pretty */ | 597 | * debugging output pretty */ |
598 | static const struct { | 598 | static const struct { |
599 | int mode; | 599 | int32_t mode; |
600 | signed char default_fd; | 600 | signed char default_fd; |
601 | char descrip[3]; | 601 | char descrip[3]; |
602 | } redir_table[] = { | 602 | } redir_table[] ALIGN4 = { |
603 | { O_RDONLY, 0, "<" }, | 603 | { O_RDONLY, 0, "<" }, |
604 | { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" }, | 604 | { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" }, |
605 | { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" }, | 605 | { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" }, |
@@ -653,7 +653,7 @@ struct command { | |||
653 | /* used for "[[ EXPR ]]" */ | 653 | /* used for "[[ EXPR ]]" */ |
654 | # define CMD_TEST2_SINGLEWORD_NOGLOB 2 | 654 | # define CMD_TEST2_SINGLEWORD_NOGLOB 2 |
655 | #endif | 655 | #endif |
656 | #if ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY | 656 | #if BASH_TEST2 || ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY |
657 | /* used to prevent word splitting and globbing in "export v=t*" */ | 657 | /* used to prevent word splitting and globbing in "export v=t*" */ |
658 | # define CMD_SINGLEWORD_NOGLOB 3 | 658 | # define CMD_SINGLEWORD_NOGLOB 3 |
659 | #endif | 659 | #endif |
@@ -1027,7 +1027,7 @@ struct globals { | |||
1027 | struct sigaction sa; | 1027 | struct sigaction sa; |
1028 | char optstring_buf[sizeof("eixcs")]; | 1028 | char optstring_buf[sizeof("eixcs")]; |
1029 | #if BASH_EPOCH_VARS | 1029 | #if BASH_EPOCH_VARS |
1030 | char epoch_buf[sizeof("%lu.nnnnnn") + sizeof(long)*3]; | 1030 | char epoch_buf[sizeof("%llu.nnnnnn") + sizeof(long long)*3]; |
1031 | #endif | 1031 | #endif |
1032 | #if ENABLE_FEATURE_EDITING | 1032 | #if ENABLE_FEATURE_EDITING |
1033 | char user_input_buf[CONFIG_FEATURE_EDITING_MAX_LEN]; | 1033 | char user_input_buf[CONFIG_FEATURE_EDITING_MAX_LEN]; |
@@ -1140,7 +1140,7 @@ struct built_in_command { | |||
1140 | #endif | 1140 | #endif |
1141 | }; | 1141 | }; |
1142 | 1142 | ||
1143 | static const struct built_in_command bltins1[] = { | 1143 | static const struct built_in_command bltins1[] ALIGN_PTR = { |
1144 | BLTIN("." , builtin_source , "Run commands in file"), | 1144 | BLTIN("." , builtin_source , "Run commands in file"), |
1145 | BLTIN(":" , builtin_true , NULL), | 1145 | BLTIN(":" , builtin_true , NULL), |
1146 | #if ENABLE_HUSH_JOB | 1146 | #if ENABLE_HUSH_JOB |
@@ -1225,7 +1225,7 @@ static const struct built_in_command bltins1[] = { | |||
1225 | /* These builtins won't be used if we are on NOMMU and need to re-exec | 1225 | /* These builtins won't be used if we are on NOMMU and need to re-exec |
1226 | * (it's cheaper to run an external program in this case): | 1226 | * (it's cheaper to run an external program in this case): |
1227 | */ | 1227 | */ |
1228 | static const struct built_in_command bltins2[] = { | 1228 | static const struct built_in_command bltins2[] ALIGN_PTR = { |
1229 | #if ENABLE_HUSH_TEST | 1229 | #if ENABLE_HUSH_TEST |
1230 | BLTIN("[" , builtin_test , NULL), | 1230 | BLTIN("[" , builtin_test , NULL), |
1231 | #endif | 1231 | #endif |
@@ -1649,13 +1649,33 @@ static int refill_HFILE_and_getc(HFILE *fp) | |||
1649 | /* Already saw EOF */ | 1649 | /* Already saw EOF */ |
1650 | return EOF; | 1650 | return EOF; |
1651 | } | 1651 | } |
1652 | #if ENABLE_HUSH_INTERACTIVE && !ENABLE_FEATURE_EDITING | ||
1653 | /* If user presses ^C, read() restarts after SIGINT (we use SA_RESTART). | ||
1654 | * IOW: ^C will not immediately stop line input. | ||
1655 | * But poll() is different: it does NOT restart after signals. | ||
1656 | */ | ||
1657 | if (fp == G.HFILE_stdin) { | ||
1658 | struct pollfd pfd[1]; | ||
1659 | pfd[0].fd = fp->fd; | ||
1660 | pfd[0].events = POLLIN; | ||
1661 | n = poll(pfd, 1, -1); | ||
1662 | if (n < 0 | ||
1663 | /*&& errno == EINTR - assumed true */ | ||
1664 | && sigismember(&G.pending_set, SIGINT) | ||
1665 | ) { | ||
1666 | return '\0'; | ||
1667 | } | ||
1668 | } | ||
1669 | #else | ||
1670 | /* if FEATURE_EDITING=y, we do not use this routine for interactive input */ | ||
1671 | #endif | ||
1652 | /* Try to buffer more input */ | 1672 | /* Try to buffer more input */ |
1653 | fp->cur = fp->buf; | ||
1654 | n = safe_read(fp->fd, fp->buf, sizeof(fp->buf)); | 1673 | n = safe_read(fp->fd, fp->buf, sizeof(fp->buf)); |
1655 | if (n < 0) { | 1674 | if (n < 0) { |
1656 | bb_simple_perror_msg("read error"); | 1675 | bb_simple_perror_msg("read error"); |
1657 | n = 0; | 1676 | n = 0; |
1658 | } | 1677 | } |
1678 | fp->cur = fp->buf; | ||
1659 | fp->end = fp->buf + n; | 1679 | fp->end = fp->buf + n; |
1660 | if (n == 0) { | 1680 | if (n == 0) { |
1661 | /* EOF/error */ | 1681 | /* EOF/error */ |
@@ -2050,8 +2070,7 @@ static sighandler_t pick_sighandler(unsigned sig) | |||
2050 | static void hush_exit(int exitcode) | 2070 | static void hush_exit(int exitcode) |
2051 | { | 2071 | { |
2052 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT | 2072 | #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT |
2053 | if (G.line_input_state) | 2073 | save_history(G.line_input_state); /* may be NULL */ |
2054 | save_history(G.line_input_state); | ||
2055 | #endif | 2074 | #endif |
2056 | 2075 | ||
2057 | fflush_all(); | 2076 | fflush_all(); |
@@ -2091,7 +2110,6 @@ static void hush_exit(int exitcode) | |||
2091 | #endif | 2110 | #endif |
2092 | } | 2111 | } |
2093 | 2112 | ||
2094 | |||
2095 | //TODO: return a mask of ALL handled sigs? | 2113 | //TODO: return a mask of ALL handled sigs? |
2096 | static int check_and_run_traps(void) | 2114 | static int check_and_run_traps(void) |
2097 | { | 2115 | { |
@@ -2259,13 +2277,13 @@ static const char* FAST_FUNC get_local_var_value(const char *name) | |||
2259 | { | 2277 | { |
2260 | const char *fmt = NULL; | 2278 | const char *fmt = NULL; |
2261 | if (strcmp(name, "EPOCHSECONDS") == 0) | 2279 | if (strcmp(name, "EPOCHSECONDS") == 0) |
2262 | fmt = "%lu"; | 2280 | fmt = "%llu"; |
2263 | else if (strcmp(name, "EPOCHREALTIME") == 0) | 2281 | else if (strcmp(name, "EPOCHREALTIME") == 0) |
2264 | fmt = "%lu.%06u"; | 2282 | fmt = "%llu.%06u"; |
2265 | if (fmt) { | 2283 | if (fmt) { |
2266 | struct timeval tv; | 2284 | struct timeval tv; |
2267 | gettimeofday(&tv, NULL); | 2285 | xgettimeofday(&tv); |
2268 | sprintf(G.epoch_buf, fmt, (unsigned long)tv.tv_sec, | 2286 | sprintf(G.epoch_buf, fmt, (unsigned long long)tv.tv_sec, |
2269 | (unsigned)tv.tv_usec); | 2287 | (unsigned)tv.tv_usec); |
2270 | return G.epoch_buf; | 2288 | return G.epoch_buf; |
2271 | } | 2289 | } |
@@ -2614,7 +2632,7 @@ static const char *setup_prompt_string(void) | |||
2614 | /* bash uses $PWD value, even if it is set by user. | 2632 | /* bash uses $PWD value, even if it is set by user. |
2615 | * It uses current dir only if PWD is unset. | 2633 | * It uses current dir only if PWD is unset. |
2616 | * We always use current dir. */ | 2634 | * We always use current dir. */ |
2617 | G.PS1 = xasprintf("%s %c ", get_cwd(0), (geteuid() != 0) ? '$' : '#'); | 2635 | prompt_str = G.PS1 = xasprintf("%s %c ", get_cwd(0), (geteuid() != 0) ? '$' : '#'); |
2618 | } | 2636 | } |
2619 | # endif | 2637 | # endif |
2620 | debug_printf("prompt_str '%s'\n", prompt_str); | 2638 | debug_printf("prompt_str '%s'\n", prompt_str); |
@@ -2622,33 +2640,33 @@ static const char *setup_prompt_string(void) | |||
2622 | } | 2640 | } |
2623 | static int get_user_input(struct in_str *i) | 2641 | static int get_user_input(struct in_str *i) |
2624 | { | 2642 | { |
2643 | # if ENABLE_FEATURE_EDITING | ||
2644 | /* In EDITING case, this function reads next input line, | ||
2645 | * saves it in i->p, then returns 1st char of it. | ||
2646 | */ | ||
2625 | int r; | 2647 | int r; |
2626 | const char *prompt_str; | 2648 | const char *prompt_str; |
2627 | 2649 | ||
2628 | prompt_str = setup_prompt_string(); | 2650 | prompt_str = setup_prompt_string(); |
2629 | # if ENABLE_FEATURE_EDITING | ||
2630 | for (;;) { | 2651 | for (;;) { |
2631 | reinit_unicode_for_hush(); | 2652 | reinit_unicode_for_hush(); |
2632 | if (G.flag_SIGINT) { | 2653 | G.flag_SIGINT = 0; |
2633 | /* There was ^C'ed, make it look prettier: */ | ||
2634 | bb_putchar('\n'); | ||
2635 | G.flag_SIGINT = 0; | ||
2636 | } | ||
2637 | /* buglet: SIGINT will not make new prompt to appear _at once_, | 2654 | /* buglet: SIGINT will not make new prompt to appear _at once_, |
2638 | * only after <Enter>. (^C works immediately) */ | 2655 | * only after <Enter>. (^C works immediately) */ |
2639 | r = read_line_input(G.line_input_state, prompt_str, | 2656 | r = read_line_input(G.line_input_state, prompt_str, |
2640 | G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1 | 2657 | G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1 |
2641 | ); | 2658 | ); |
2642 | /* read_line_input intercepts ^C, "convert" it to SIGINT */ | 2659 | /* read_line_input intercepts ^C, "convert" it to SIGINT */ |
2643 | if (r == 0) | 2660 | if (r == 0) { |
2644 | raise(SIGINT); | 2661 | raise(SIGINT); |
2662 | } | ||
2645 | check_and_run_traps(); | 2663 | check_and_run_traps(); |
2646 | if (r != 0 && !G.flag_SIGINT) | 2664 | if (r != 0 && !G.flag_SIGINT) |
2647 | break; | 2665 | break; |
2648 | /* ^C or SIGINT: repeat */ | 2666 | /* ^C or SIGINT: repeat */ |
2649 | /* bash prints ^C even on real SIGINT (non-kbd generated) */ | 2667 | /* bash prints ^C even on real SIGINT (non-kbd generated) */ |
2650 | write(STDOUT_FILENO, "^C", 2); | 2668 | write(STDOUT_FILENO, "^C\n", 3); |
2651 | G.last_exitcode = 128 + SIGINT; | 2669 | G.last_exitcode = 128 | SIGINT; |
2652 | } | 2670 | } |
2653 | if (r < 0) { | 2671 | if (r < 0) { |
2654 | /* EOF/error detected */ | 2672 | /* EOF/error detected */ |
@@ -2659,9 +2677,15 @@ static int get_user_input(struct in_str *i) | |||
2659 | i->p = G.user_input_buf; | 2677 | i->p = G.user_input_buf; |
2660 | return (unsigned char)*i->p++; | 2678 | return (unsigned char)*i->p++; |
2661 | # else | 2679 | # else |
2680 | /* In !EDITING case, this function gets called for every char. | ||
2681 | * Buffering happens deeper in the call chain, in hfgetc(i->file). | ||
2682 | */ | ||
2683 | int r; | ||
2684 | |||
2662 | for (;;) { | 2685 | for (;;) { |
2663 | G.flag_SIGINT = 0; | 2686 | G.flag_SIGINT = 0; |
2664 | if (i->last_char == '\0' || i->last_char == '\n') { | 2687 | if (i->last_char == '\0' || i->last_char == '\n') { |
2688 | const char *prompt_str = setup_prompt_string(); | ||
2665 | /* Why check_and_run_traps here? Try this interactively: | 2689 | /* Why check_and_run_traps here? Try this interactively: |
2666 | * $ trap 'echo INT' INT; (sleep 2; kill -INT $$) & | 2690 | * $ trap 'echo INT' INT; (sleep 2; kill -INT $$) & |
2667 | * $ <[enter], repeatedly...> | 2691 | * $ <[enter], repeatedly...> |
@@ -2669,19 +2693,23 @@ static int get_user_input(struct in_str *i) | |||
2669 | */ | 2693 | */ |
2670 | check_and_run_traps(); | 2694 | check_and_run_traps(); |
2671 | fputs(prompt_str, stdout); | 2695 | fputs(prompt_str, stdout); |
2696 | fflush_all(); | ||
2672 | } | 2697 | } |
2673 | fflush_all(); | ||
2674 | //FIXME: here ^C or SIGINT will have effect only after <Enter> | ||
2675 | r = hfgetc(i->file); | 2698 | r = hfgetc(i->file); |
2676 | /* In !ENABLE_FEATURE_EDITING we don't use read_line_input, | 2699 | /* In !ENABLE_FEATURE_EDITING we don't use read_line_input, |
2677 | * no ^C masking happens during fgetc, no special code for ^C: | 2700 | * no ^C masking happens during fgetc, no special code for ^C: |
2678 | * it generates SIGINT as usual. | 2701 | * it generates SIGINT as usual. |
2679 | */ | 2702 | */ |
2680 | check_and_run_traps(); | 2703 | check_and_run_traps(); |
2681 | if (G.flag_SIGINT) | 2704 | if (r != '\0' && !G.flag_SIGINT) |
2682 | G.last_exitcode = 128 + SIGINT; | ||
2683 | if (r != '\0') | ||
2684 | break; | 2705 | break; |
2706 | if (G.flag_SIGINT) { | ||
2707 | /* ^C or SIGINT: repeat */ | ||
2708 | /* bash prints ^C even on real SIGINT (non-kbd generated) */ | ||
2709 | /* kernel prints "^C" itself, just print newline: */ | ||
2710 | write(STDOUT_FILENO, "\n", 1); | ||
2711 | G.last_exitcode = 128 | SIGINT; | ||
2712 | } | ||
2685 | } | 2713 | } |
2686 | return r; | 2714 | return r; |
2687 | # endif | 2715 | # endif |
@@ -2703,14 +2731,14 @@ static int fgetc_interactive(struct in_str *i) | |||
2703 | } | 2731 | } |
2704 | return ch; | 2732 | return ch; |
2705 | } | 2733 | } |
2706 | #else | 2734 | #else /* !INTERACTIVE */ |
2707 | static ALWAYS_INLINE int fgetc_interactive(struct in_str *i) | 2735 | static ALWAYS_INLINE int fgetc_interactive(struct in_str *i) |
2708 | { | 2736 | { |
2709 | int ch; | 2737 | int ch; |
2710 | do ch = hfgetc(i->file); while (ch == '\0'); | 2738 | do ch = hfgetc(i->file); while (ch == '\0'); |
2711 | return ch; | 2739 | return ch; |
2712 | } | 2740 | } |
2713 | #endif /* INTERACTIVE */ | 2741 | #endif /* !INTERACTIVE */ |
2714 | 2742 | ||
2715 | static int i_getch(struct in_str *i) | 2743 | static int i_getch(struct in_str *i) |
2716 | { | 2744 | { |
@@ -3888,7 +3916,7 @@ struct reserved_combo { | |||
3888 | char literal[6]; | 3916 | char literal[6]; |
3889 | unsigned char res; | 3917 | unsigned char res; |
3890 | unsigned char assignment_flag; | 3918 | unsigned char assignment_flag; |
3891 | int flag; | 3919 | uint32_t flag; |
3892 | }; | 3920 | }; |
3893 | enum { | 3921 | enum { |
3894 | FLAG_END = (1 << RES_NONE ), | 3922 | FLAG_END = (1 << RES_NONE ), |
@@ -3921,7 +3949,7 @@ static const struct reserved_combo* match_reserved_word(o_string *word) | |||
3921 | * to turn the compound list into a command. | 3949 | * to turn the compound list into a command. |
3922 | * FLAG_START means the word must start a new compound list. | 3950 | * FLAG_START means the word must start a new compound list. |
3923 | */ | 3951 | */ |
3924 | static const struct reserved_combo reserved_list[] = { | 3952 | static const struct reserved_combo reserved_list[] ALIGN4 = { |
3925 | # if ENABLE_HUSH_IF | 3953 | # if ENABLE_HUSH_IF |
3926 | { "!", RES_NONE, NOT_ASSIGNMENT , 0 }, | 3954 | { "!", RES_NONE, NOT_ASSIGNMENT , 0 }, |
3927 | { "if", RES_IF, MAYBE_ASSIGNMENT, FLAG_THEN | FLAG_START }, | 3955 | { "if", RES_IF, MAYBE_ASSIGNMENT, FLAG_THEN | FLAG_START }, |
@@ -5263,19 +5291,19 @@ static struct pipe *parse_stream(char **pstring, | |||
5263 | 5291 | ||
5264 | if (heredoc_cnt) { | 5292 | if (heredoc_cnt) { |
5265 | syntax_error_unterm_str("here document"); | 5293 | syntax_error_unterm_str("here document"); |
5266 | goto parse_error; | 5294 | goto parse_error_exitcode1; |
5267 | } | 5295 | } |
5268 | if (end_trigger == ')') { | 5296 | if (end_trigger == ')') { |
5269 | syntax_error_unterm_ch('('); | 5297 | syntax_error_unterm_ch('('); |
5270 | goto parse_error; | 5298 | goto parse_error_exitcode1; |
5271 | } | 5299 | } |
5272 | if (end_trigger == '}') { | 5300 | if (end_trigger == '}') { |
5273 | syntax_error_unterm_ch('{'); | 5301 | syntax_error_unterm_ch('{'); |
5274 | goto parse_error; | 5302 | goto parse_error_exitcode1; |
5275 | } | 5303 | } |
5276 | 5304 | ||
5277 | if (done_word(&ctx)) { | 5305 | if (done_word(&ctx)) { |
5278 | goto parse_error; | 5306 | goto parse_error_exitcode1; |
5279 | } | 5307 | } |
5280 | o_free_and_set_NULL(&ctx.word); | 5308 | o_free_and_set_NULL(&ctx.word); |
5281 | done_pipe(&ctx, PIPE_SEQ); | 5309 | done_pipe(&ctx, PIPE_SEQ); |
@@ -5345,7 +5373,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5345 | while (1) { | 5373 | while (1) { |
5346 | if (ch == EOF) { | 5374 | if (ch == EOF) { |
5347 | syntax_error_unterm_ch('\''); | 5375 | syntax_error_unterm_ch('\''); |
5348 | goto parse_error; | 5376 | goto parse_error_exitcode1; |
5349 | } | 5377 | } |
5350 | nommu_addchr(&ctx.as_string, ch); | 5378 | nommu_addchr(&ctx.as_string, ch); |
5351 | if (ch == '\'') | 5379 | if (ch == '\'') |
@@ -5424,7 +5452,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5424 | /* ch == last eaten whitespace char */ | 5452 | /* ch == last eaten whitespace char */ |
5425 | #endif | 5453 | #endif |
5426 | if (done_word(&ctx)) { | 5454 | if (done_word(&ctx)) { |
5427 | goto parse_error; | 5455 | goto parse_error_exitcode1; |
5428 | } | 5456 | } |
5429 | if (ch == '\n') { | 5457 | if (ch == '\n') { |
5430 | /* Is this a case when newline is simply ignored? | 5458 | /* Is this a case when newline is simply ignored? |
@@ -5467,7 +5495,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5467 | if (heredoc_cnt) { | 5495 | if (heredoc_cnt) { |
5468 | heredoc_cnt = fetch_heredocs(&ctx.as_string, ctx.list_head, heredoc_cnt, input); | 5496 | heredoc_cnt = fetch_heredocs(&ctx.as_string, ctx.list_head, heredoc_cnt, input); |
5469 | if (heredoc_cnt != 0) | 5497 | if (heredoc_cnt != 0) |
5470 | goto parse_error; | 5498 | goto parse_error_exitcode1; |
5471 | } | 5499 | } |
5472 | ctx.is_assignment = MAYBE_ASSIGNMENT; | 5500 | ctx.is_assignment = MAYBE_ASSIGNMENT; |
5473 | debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); | 5501 | debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); |
@@ -5517,7 +5545,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5517 | #endif | 5545 | #endif |
5518 | ) { | 5546 | ) { |
5519 | if (done_word(&ctx)) { | 5547 | if (done_word(&ctx)) { |
5520 | goto parse_error; | 5548 | goto parse_error_exitcode1; |
5521 | } | 5549 | } |
5522 | done_pipe(&ctx, PIPE_SEQ); | 5550 | done_pipe(&ctx, PIPE_SEQ); |
5523 | ctx.is_assignment = MAYBE_ASSIGNMENT; | 5551 | ctx.is_assignment = MAYBE_ASSIGNMENT; |
@@ -5538,7 +5566,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5538 | /* Example: bare "{ }", "()" */ | 5566 | /* Example: bare "{ }", "()" */ |
5539 | G.last_exitcode = 2; /* bash compat */ | 5567 | G.last_exitcode = 2; /* bash compat */ |
5540 | syntax_error_unexpected_ch(ch); | 5568 | syntax_error_unexpected_ch(ch); |
5541 | goto parse_error2; | 5569 | goto parse_error; |
5542 | } | 5570 | } |
5543 | if (heredoc_cnt_ptr) | 5571 | if (heredoc_cnt_ptr) |
5544 | *heredoc_cnt_ptr = heredoc_cnt; | 5572 | *heredoc_cnt_ptr = heredoc_cnt; |
@@ -5560,7 +5588,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5560 | case '>': | 5588 | case '>': |
5561 | redir_fd = redirect_opt_num(&ctx.word); | 5589 | redir_fd = redirect_opt_num(&ctx.word); |
5562 | if (done_word(&ctx)) { | 5590 | if (done_word(&ctx)) { |
5563 | goto parse_error; | 5591 | goto parse_error_exitcode1; |
5564 | } | 5592 | } |
5565 | redir_style = REDIRECT_OVERWRITE; | 5593 | redir_style = REDIRECT_OVERWRITE; |
5566 | if (next == '>') { | 5594 | if (next == '>') { |
@@ -5571,16 +5599,16 @@ static struct pipe *parse_stream(char **pstring, | |||
5571 | #if 0 | 5599 | #if 0 |
5572 | else if (next == '(') { | 5600 | else if (next == '(') { |
5573 | syntax_error(">(process) not supported"); | 5601 | syntax_error(">(process) not supported"); |
5574 | goto parse_error; | 5602 | goto parse_error_exitcode1; |
5575 | } | 5603 | } |
5576 | #endif | 5604 | #endif |
5577 | if (parse_redirect(&ctx, redir_fd, redir_style, input)) | 5605 | if (parse_redirect(&ctx, redir_fd, redir_style, input)) |
5578 | goto parse_error; | 5606 | goto parse_error_exitcode1; |
5579 | continue; /* get next char */ | 5607 | continue; /* get next char */ |
5580 | case '<': | 5608 | case '<': |
5581 | redir_fd = redirect_opt_num(&ctx.word); | 5609 | redir_fd = redirect_opt_num(&ctx.word); |
5582 | if (done_word(&ctx)) { | 5610 | if (done_word(&ctx)) { |
5583 | goto parse_error; | 5611 | goto parse_error_exitcode1; |
5584 | } | 5612 | } |
5585 | redir_style = REDIRECT_INPUT; | 5613 | redir_style = REDIRECT_INPUT; |
5586 | if (next == '<') { | 5614 | if (next == '<') { |
@@ -5597,11 +5625,11 @@ static struct pipe *parse_stream(char **pstring, | |||
5597 | #if 0 | 5625 | #if 0 |
5598 | else if (next == '(') { | 5626 | else if (next == '(') { |
5599 | syntax_error("<(process) not supported"); | 5627 | syntax_error("<(process) not supported"); |
5600 | goto parse_error; | 5628 | goto parse_error_exitcode1; |
5601 | } | 5629 | } |
5602 | #endif | 5630 | #endif |
5603 | if (parse_redirect(&ctx, redir_fd, redir_style, input)) | 5631 | if (parse_redirect(&ctx, redir_fd, redir_style, input)) |
5604 | goto parse_error; | 5632 | goto parse_error_exitcode1; |
5605 | continue; /* get next char */ | 5633 | continue; /* get next char */ |
5606 | case '#': | 5634 | case '#': |
5607 | if (ctx.word.length == 0 && !ctx.word.has_quoted_part) { | 5635 | if (ctx.word.length == 0 && !ctx.word.has_quoted_part) { |
@@ -5655,7 +5683,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5655 | if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) { | 5683 | if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) { |
5656 | debug_printf_parse("parse_stream parse error: " | 5684 | debug_printf_parse("parse_stream parse error: " |
5657 | "parse_dollar returned 0 (error)\n"); | 5685 | "parse_dollar returned 0 (error)\n"); |
5658 | goto parse_error; | 5686 | goto parse_error_exitcode1; |
5659 | } | 5687 | } |
5660 | continue; /* get next char */ | 5688 | continue; /* get next char */ |
5661 | case '"': | 5689 | case '"': |
@@ -5671,7 +5699,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5671 | if (ctx.is_assignment == NOT_ASSIGNMENT) | 5699 | if (ctx.is_assignment == NOT_ASSIGNMENT) |
5672 | ctx.word.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; | 5700 | ctx.word.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; |
5673 | if (!encode_string(&ctx.as_string, &ctx.word, input, '"')) | 5701 | if (!encode_string(&ctx.as_string, &ctx.word, input, '"')) |
5674 | goto parse_error; | 5702 | goto parse_error_exitcode1; |
5675 | ctx.word.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; | 5703 | ctx.word.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; |
5676 | continue; /* get next char */ | 5704 | continue; /* get next char */ |
5677 | #if ENABLE_HUSH_TICK | 5705 | #if ENABLE_HUSH_TICK |
@@ -5682,7 +5710,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5682 | o_addchr(&ctx.word, '`'); | 5710 | o_addchr(&ctx.word, '`'); |
5683 | USE_FOR_NOMMU(pos = ctx.word.length;) | 5711 | USE_FOR_NOMMU(pos = ctx.word.length;) |
5684 | if (!add_till_backquote(&ctx.word, input, /*in_dquote:*/ 0)) | 5712 | if (!add_till_backquote(&ctx.word, input, /*in_dquote:*/ 0)) |
5685 | goto parse_error; | 5713 | goto parse_error_exitcode1; |
5686 | # if !BB_MMU | 5714 | # if !BB_MMU |
5687 | o_addstr(&ctx.as_string, ctx.word.data + pos); | 5715 | o_addstr(&ctx.as_string, ctx.word.data + pos); |
5688 | o_addchr(&ctx.as_string, '`'); | 5716 | o_addchr(&ctx.as_string, '`'); |
@@ -5697,7 +5725,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5697 | case_semi: | 5725 | case_semi: |
5698 | #endif | 5726 | #endif |
5699 | if (done_word(&ctx)) { | 5727 | if (done_word(&ctx)) { |
5700 | goto parse_error; | 5728 | goto parse_error_exitcode1; |
5701 | } | 5729 | } |
5702 | done_pipe(&ctx, PIPE_SEQ); | 5730 | done_pipe(&ctx, PIPE_SEQ); |
5703 | #if ENABLE_HUSH_CASE | 5731 | #if ENABLE_HUSH_CASE |
@@ -5724,7 +5752,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5724 | continue; /* get next char */ | 5752 | continue; /* get next char */ |
5725 | case '&': | 5753 | case '&': |
5726 | if (done_word(&ctx)) { | 5754 | if (done_word(&ctx)) { |
5727 | goto parse_error; | 5755 | goto parse_error_exitcode1; |
5728 | } | 5756 | } |
5729 | if (next == '&') { | 5757 | if (next == '&') { |
5730 | ch = i_getch(input); | 5758 | ch = i_getch(input); |
@@ -5736,7 +5764,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5736 | goto new_cmd; | 5764 | goto new_cmd; |
5737 | case '|': | 5765 | case '|': |
5738 | if (done_word(&ctx)) { | 5766 | if (done_word(&ctx)) { |
5739 | goto parse_error; | 5767 | goto parse_error_exitcode1; |
5740 | } | 5768 | } |
5741 | #if ENABLE_HUSH_CASE | 5769 | #if ENABLE_HUSH_CASE |
5742 | if (ctx.ctx_res_w == RES_MATCH) | 5770 | if (ctx.ctx_res_w == RES_MATCH) |
@@ -5768,7 +5796,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5768 | case '{': { | 5796 | case '{': { |
5769 | int n = parse_group(&ctx, input, ch); | 5797 | int n = parse_group(&ctx, input, ch); |
5770 | if (n < 0) { | 5798 | if (n < 0) { |
5771 | goto parse_error; | 5799 | goto parse_error_exitcode1; |
5772 | } | 5800 | } |
5773 | debug_printf_heredoc("parse_group done, needs heredocs:%d\n", n); | 5801 | debug_printf_heredoc("parse_group done, needs heredocs:%d\n", n); |
5774 | heredoc_cnt += n; | 5802 | heredoc_cnt += n; |
@@ -5786,16 +5814,16 @@ static struct pipe *parse_stream(char **pstring, | |||
5786 | * and it will match } earlier (not here). */ | 5814 | * and it will match } earlier (not here). */ |
5787 | G.last_exitcode = 2; | 5815 | G.last_exitcode = 2; |
5788 | syntax_error_unexpected_ch(ch); | 5816 | syntax_error_unexpected_ch(ch); |
5789 | goto parse_error2; | 5817 | goto parse_error; |
5790 | default: | 5818 | default: |
5791 | if (HUSH_DEBUG) | 5819 | if (HUSH_DEBUG) |
5792 | bb_error_msg_and_die("BUG: unexpected %c", ch); | 5820 | bb_error_msg_and_die("BUG: unexpected %c", ch); |
5793 | } | 5821 | } |
5794 | } /* while (1) */ | 5822 | } /* while (1) */ |
5795 | 5823 | ||
5796 | parse_error: | 5824 | parse_error_exitcode1: |
5797 | G.last_exitcode = 1; | 5825 | G.last_exitcode = 1; |
5798 | parse_error2: | 5826 | parse_error: |
5799 | { | 5827 | { |
5800 | struct parse_context *pctx; | 5828 | struct parse_context *pctx; |
5801 | IF_HAS_KEYWORDS(struct parse_context *p2;) | 5829 | IF_HAS_KEYWORDS(struct parse_context *p2;) |
@@ -6490,9 +6518,11 @@ static NOINLINE int expand_one_var(o_string *output, int n, | |||
6490 | * Word is expanded to produce a glob pattern. | 6518 | * Word is expanded to produce a glob pattern. |
6491 | * Then var's value is matched to it and matching part removed. | 6519 | * Then var's value is matched to it and matching part removed. |
6492 | */ | 6520 | */ |
6493 | //FIXME: ${x#...${...}...} | 6521 | /* bash compat: if x is "" and no shrinking of it is possible, |
6494 | //should evaluate inner ${...} even if x is "" and no shrinking of it is possible - | 6522 | * inner ${...} is not evaluated. Example: |
6495 | //inner ${...} may have side effects! | 6523 | * unset b; : ${a%${b=B}}; echo $b |
6524 | * assignment b=B only happens if $a is not "". | ||
6525 | */ | ||
6496 | if (val && val[0]) { | 6526 | if (val && val[0]) { |
6497 | char *t; | 6527 | char *t; |
6498 | char *exp_exp_word; | 6528 | char *exp_exp_word; |
@@ -6531,7 +6561,12 @@ static NOINLINE int expand_one_var(o_string *output, int n, | |||
6531 | * and if // is used, it is encoded as \: | 6561 | * and if // is used, it is encoded as \: |
6532 | * var\pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL> | 6562 | * var\pattern<SPECIAL_VAR_SYMBOL>repl<SPECIAL_VAR_SYMBOL> |
6533 | */ | 6563 | */ |
6534 | if (val && val[0]) { | 6564 | /* bash compat: if var is "", both pattern and repl |
6565 | * are still evaluated, if it is unset, then not: | ||
6566 | * unset b; a=; : ${a/z/${b=3}}; echo $b # b=3 | ||
6567 | * unset b; unset a; : ${a/z/${b=3}}; echo $b # b not set | ||
6568 | */ | ||
6569 | if (val /*&& val[0]*/) { | ||
6535 | /* pattern uses non-standard expansion. | 6570 | /* pattern uses non-standard expansion. |
6536 | * repl should be unbackslashed and globbed | 6571 | * repl should be unbackslashed and globbed |
6537 | * by the usual expansion rules: | 6572 | * by the usual expansion rules: |
@@ -6567,8 +6602,9 @@ static NOINLINE int expand_one_var(o_string *output, int n, | |||
6567 | free(pattern); | 6602 | free(pattern); |
6568 | free(repl); | 6603 | free(repl); |
6569 | } else { | 6604 | } else { |
6570 | /* Empty variable always gives nothing */ | 6605 | /* Unset variable always gives nothing */ |
6571 | // "v=''; echo ${v/*/w}" prints "", not "w" | 6606 | // a=; echo ${a/*/w} # "w" |
6607 | // unset a; echo ${a/*/w} # "" | ||
6572 | /* Just skip "replace" part */ | 6608 | /* Just skip "replace" part */ |
6573 | *p++ = SPECIAL_VAR_SYMBOL; | 6609 | *p++ = SPECIAL_VAR_SYMBOL; |
6574 | p = strchr(p, SPECIAL_VAR_SYMBOL); | 6610 | p = strchr(p, SPECIAL_VAR_SYMBOL); |
@@ -6583,40 +6619,48 @@ static NOINLINE int expand_one_var(o_string *output, int n, | |||
6583 | * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL> | 6619 | * var:N<SPECIAL_VAR_SYMBOL>M<SPECIAL_VAR_SYMBOL> |
6584 | */ | 6620 | */ |
6585 | arith_t beg, len; | 6621 | arith_t beg, len; |
6622 | unsigned vallen; | ||
6586 | const char *errmsg; | 6623 | const char *errmsg; |
6587 | 6624 | ||
6588 | beg = expand_and_evaluate_arith(exp_word, &errmsg); | 6625 | beg = expand_and_evaluate_arith(exp_word, &errmsg); |
6589 | if (errmsg) | 6626 | if (errmsg) |
6590 | goto arith_err; | 6627 | goto empty_result; |
6591 | debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg); | 6628 | debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg); |
6592 | *p++ = SPECIAL_VAR_SYMBOL; | 6629 | *p++ = SPECIAL_VAR_SYMBOL; |
6593 | exp_word = p; | 6630 | exp_word = p; |
6594 | p = strchr(p, SPECIAL_VAR_SYMBOL); | 6631 | p = strchr(p, SPECIAL_VAR_SYMBOL); |
6595 | *p = '\0'; | 6632 | *p = '\0'; |
6596 | len = expand_and_evaluate_arith(exp_word, &errmsg); | 6633 | vallen = val ? strlen(val) : 0; |
6597 | if (errmsg) | ||
6598 | goto arith_err; | ||
6599 | debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len); | ||
6600 | if (beg < 0) { | 6634 | if (beg < 0) { |
6601 | /* negative beg counts from the end */ | 6635 | /* negative beg counts from the end */ |
6602 | beg = (arith_t)strlen(val) + beg; | 6636 | beg = (arith_t)vallen + beg; |
6603 | if (beg < 0) /* ${v: -999999} is "" */ | 6637 | } |
6604 | beg = len = 0; | 6638 | /* If expansion will be empty, do not even evaluate len */ |
6639 | if (!val || beg < 0 || beg > vallen) { | ||
6640 | /* Why > vallen, not >=? bash: | ||
6641 | * unset b; a=ab; : ${a:2:${b=3}}; echo $b # "", b=3 (!!!) | ||
6642 | * unset b; a=a; : ${a:2:${b=3}}; echo $b # "", b not set | ||
6643 | */ | ||
6644 | goto empty_result; | ||
6605 | } | 6645 | } |
6646 | len = expand_and_evaluate_arith(exp_word, &errmsg); | ||
6647 | if (errmsg) | ||
6648 | goto empty_result; | ||
6649 | debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len); | ||
6606 | debug_printf_varexp("from val:'%s'\n", val); | 6650 | debug_printf_varexp("from val:'%s'\n", val); |
6607 | if (len < 0) { | 6651 | if (len < 0) { |
6608 | /* in bash, len=-n means strlen()-n */ | 6652 | /* in bash, len=-n means strlen()-n */ |
6609 | len = (arith_t)strlen(val) - beg + len; | 6653 | len = (arith_t)vallen - beg + len; |
6610 | if (len < 0) /* bash compat */ | 6654 | if (len < 0) /* bash compat */ |
6611 | msg_and_die_if_script("%s: substring expression < 0", var); | 6655 | msg_and_die_if_script("%s: substring expression < 0", var); |
6612 | } | 6656 | } |
6613 | if (len <= 0 || !val || beg >= strlen(val)) { | 6657 | if (len <= 0 || !val /*|| beg >= vallen*/) { |
6614 | arith_err: | 6658 | empty_result: |
6615 | val = NULL; | 6659 | val = NULL; |
6616 | } else { | 6660 | } else { |
6617 | /* Paranoia. What if user entered 9999999999999 | 6661 | /* Paranoia. What if user entered 9999999999999 |
6618 | * which fits in arith_t but not int? */ | 6662 | * which fits in arith_t but not int? */ |
6619 | if (len >= INT_MAX) | 6663 | if (len > INT_MAX) |
6620 | len = INT_MAX; | 6664 | len = INT_MAX; |
6621 | val = to_be_freed = xstrndup(val + beg, len); | 6665 | val = to_be_freed = xstrndup(val + beg, len); |
6622 | } | 6666 | } |
@@ -6650,12 +6694,13 @@ static NOINLINE int expand_one_var(o_string *output, int n, | |||
6650 | * | 6694 | * |
6651 | * Word-splitting and single quote behavior: | 6695 | * Word-splitting and single quote behavior: |
6652 | * | 6696 | * |
6653 | * $ f() { for i; do echo "|$i|"; done; }; | 6697 | * $ f() { for i; do echo "|$i|"; done; } |
6654 | * | 6698 | * |
6655 | * $ x=; f ${x:?'x y' z} | 6699 | * $ x=; f ${x:?'x y' z}; echo $? |
6656 | * bash: x: x y z #BUG: does not abort, ${} results in empty expansion | 6700 | * bash: x: x y z # neither f nor "echo $?" executes |
6701 | * (if interactive, bash does not exit, but merely aborts to prompt. $? is set to 1) | ||
6657 | * $ x=; f "${x:?'x y' z}" | 6702 | * $ x=; f "${x:?'x y' z}" |
6658 | * bash: x: x y z # dash prints: dash: x: 'x y' z #BUG: does not abort, ${} results in "" | 6703 | * bash: x: x y z # dash prints: dash: x: 'x y' z |
6659 | * | 6704 | * |
6660 | * $ x=; f ${x:='x y' z} | 6705 | * $ x=; f ${x:='x y' z} |
6661 | * |x| | 6706 | * |x| |
@@ -7743,7 +7788,11 @@ static void restore_redirects(struct squirrel *sq) | |||
7743 | free(sq); | 7788 | free(sq); |
7744 | } | 7789 | } |
7745 | if (G.HFILE_stdin | 7790 | if (G.HFILE_stdin |
7746 | && G.HFILE_stdin->fd != STDIN_FILENO | 7791 | && G.HFILE_stdin->fd > STDIN_FILENO |
7792 | /* we compare > STDIN, not == STDIN, since hfgetc() | ||
7793 | * closes fd and sets ->fd to -1 if EOF is reached. | ||
7794 | * Testcase: echo 'pwd' | hush | ||
7795 | */ | ||
7747 | ) { | 7796 | ) { |
7748 | /* Testcase: interactive "read r <FILE; echo $r; read r; echo $r". | 7797 | /* Testcase: interactive "read r <FILE; echo $r; read r; echo $r". |
7749 | * Redirect moves ->fd to e.g. 10, | 7798 | * Redirect moves ->fd to e.g. 10, |
@@ -8136,7 +8185,6 @@ static void exec_function(char ***to_free, | |||
8136 | 8185 | ||
8137 | /* On MMU, funcp->body is always non-NULL */ | 8186 | /* On MMU, funcp->body is always non-NULL */ |
8138 | n = run_list(funcp->body); | 8187 | n = run_list(funcp->body); |
8139 | fflush_all(); | ||
8140 | _exit(n); | 8188 | _exit(n); |
8141 | # else | 8189 | # else |
8142 | //? close_saved_fds_and_FILE_fds(); | 8190 | //? close_saved_fds_and_FILE_fds(); |
@@ -8211,7 +8259,6 @@ static void exec_builtin(char ***to_free, | |||
8211 | { | 8259 | { |
8212 | #if BB_MMU | 8260 | #if BB_MMU |
8213 | int rcode; | 8261 | int rcode; |
8214 | fflush_all(); | ||
8215 | //? close_saved_fds_and_FILE_fds(); | 8262 | //? close_saved_fds_and_FILE_fds(); |
8216 | rcode = x->b_function(argv); | 8263 | rcode = x->b_function(argv); |
8217 | fflush_all(); | 8264 | fflush_all(); |
@@ -8715,6 +8762,7 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status) | |||
8715 | */ | 8762 | */ |
8716 | if (WIFSIGNALED(status)) { | 8763 | if (WIFSIGNALED(status)) { |
8717 | int sig = WTERMSIG(status); | 8764 | int sig = WTERMSIG(status); |
8765 | #if ENABLE_HUSH_JOB | ||
8718 | if (G.run_list_level == 1 | 8766 | if (G.run_list_level == 1 |
8719 | /* ^^^^^ Do not print in nested contexts, example: | 8767 | /* ^^^^^ Do not print in nested contexts, example: |
8720 | * echo `sleep 1; sh -c 'kill -9 $$'` - prints "137", NOT "Killed 137" | 8768 | * echo `sleep 1; sh -c 'kill -9 $$'` - prints "137", NOT "Killed 137" |
@@ -8724,10 +8772,12 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status) | |||
8724 | /* strsignal() is for bash compat. ~600 bloat versus bbox's get_signame() */ | 8772 | /* strsignal() is for bash compat. ~600 bloat versus bbox's get_signame() */ |
8725 | puts(sig == SIGINT || sig == SIGPIPE ? "" : strsignal(sig)); | 8773 | puts(sig == SIGINT || sig == SIGPIPE ? "" : strsignal(sig)); |
8726 | } | 8774 | } |
8775 | #endif | ||
8727 | /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ | 8776 | /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ |
8728 | /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? | 8777 | /* MIPS has 128 sigs (1..128), if sig==128, |
8729 | * Maybe we need to use sig | 128? */ | 8778 | * 128 + sig would result in exitcode 256 -> 0! |
8730 | ex = sig + 128; | 8779 | */ |
8780 | ex = 128 | sig; | ||
8731 | } | 8781 | } |
8732 | fg_pipe->cmds[i].cmd_exitcode = ex; | 8782 | fg_pipe->cmds[i].cmd_exitcode = ex; |
8733 | } else { | 8783 | } else { |
@@ -8774,7 +8824,8 @@ static int process_wait_result(struct pipe *fg_pipe, pid_t childpid, int status) | |||
8774 | /* child exited */ | 8824 | /* child exited */ |
8775 | int rcode = WEXITSTATUS(status); | 8825 | int rcode = WEXITSTATUS(status); |
8776 | if (WIFSIGNALED(status)) | 8826 | if (WIFSIGNALED(status)) |
8777 | rcode = 128 + WTERMSIG(status); | 8827 | /* NB: not 128 + sig, MIPS has sig 128 */ |
8828 | rcode = 128 | WTERMSIG(status); | ||
8778 | pi->cmds[i].cmd_exitcode = rcode; | 8829 | pi->cmds[i].cmd_exitcode = rcode; |
8779 | if (G.last_bg_pid == pi->cmds[i].pid) | 8830 | if (G.last_bg_pid == pi->cmds[i].pid) |
8780 | G.last_bg_pid_exitcode = rcode; | 8831 | G.last_bg_pid_exitcode = rcode; |
@@ -8894,10 +8945,10 @@ static int checkjobs(struct pipe *fg_pipe, pid_t waitfor_pid) | |||
8894 | debug_printf_exec("childpid==waitfor_pid:%d status:0x%08x\n", childpid, status); | 8945 | debug_printf_exec("childpid==waitfor_pid:%d status:0x%08x\n", childpid, status); |
8895 | rcode = WEXITSTATUS(status); | 8946 | rcode = WEXITSTATUS(status); |
8896 | if (WIFSIGNALED(status)) | 8947 | if (WIFSIGNALED(status)) |
8897 | rcode = 128 + WTERMSIG(status); | 8948 | rcode = 128 | WTERMSIG(status); |
8898 | if (WIFSTOPPED(status)) | 8949 | if (WIFSTOPPED(status)) |
8899 | /* bash: "cmd & wait $!" and cmd stops: $? = 128 + stopsig */ | 8950 | /* bash: "cmd & wait $!" and cmd stops: $? = 128 | stopsig */ |
8900 | rcode = 128 + WSTOPSIG(status); | 8951 | rcode = 128 | WSTOPSIG(status); |
8901 | rcode++; | 8952 | rcode++; |
8902 | break; /* "wait PID" called us, give it exitcode+1 */ | 8953 | break; /* "wait PID" called us, give it exitcode+1 */ |
8903 | } | 8954 | } |
@@ -9287,7 +9338,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
9287 | * during builtin/nofork. | 9338 | * during builtin/nofork. |
9288 | */ | 9339 | */ |
9289 | if (sigismember(&G.pending_set, SIGINT)) | 9340 | if (sigismember(&G.pending_set, SIGINT)) |
9290 | rcode = 128 + SIGINT; | 9341 | rcode = 128 | SIGINT; |
9291 | } | 9342 | } |
9292 | free(argv_expanded); | 9343 | free(argv_expanded); |
9293 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) | 9344 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) |
@@ -9972,11 +10023,14 @@ static int set_mode(int state, char mode, const char *o_opt) | |||
9972 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 10023 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
9973 | int hush_main(int argc, char **argv) | 10024 | int hush_main(int argc, char **argv) |
9974 | { | 10025 | { |
10026 | pid_t cached_getpid; | ||
9975 | enum { | 10027 | enum { |
9976 | OPT_login = (1 << 0), | 10028 | OPT_login = (1 << 0), |
9977 | }; | 10029 | }; |
9978 | unsigned flags; | 10030 | unsigned flags; |
9979 | unsigned builtin_argc; | 10031 | #if !BB_MMU |
10032 | unsigned builtin_argc = 0; | ||
10033 | #endif | ||
9980 | char **e; | 10034 | char **e; |
9981 | struct variable *cur_var; | 10035 | struct variable *cur_var; |
9982 | struct variable *shell_ver; | 10036 | struct variable *shell_ver; |
@@ -9998,6 +10052,10 @@ int hush_main(int argc, char **argv) | |||
9998 | G.argv0_for_re_execing = argv[0]; | 10052 | G.argv0_for_re_execing = argv[0]; |
9999 | #endif | 10053 | #endif |
10000 | 10054 | ||
10055 | cached_getpid = getpid(); /* for tcsetpgrp() during init */ | ||
10056 | G.root_pid = cached_getpid; /* for $PID (NOMMU can override via -$HEXPID:HEXPPID:...) */ | ||
10057 | G.root_ppid = getppid(); /* for $PPID (NOMMU can override) */ | ||
10058 | |||
10001 | /* Deal with HUSH_VERSION */ | 10059 | /* Deal with HUSH_VERSION */ |
10002 | debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); | 10060 | debug_printf_env("unsetenv '%s'\n", "HUSH_VERSION"); |
10003 | unsetenv("HUSH_VERSION"); /* in case it exists in initial env */ | 10061 | unsetenv("HUSH_VERSION"); /* in case it exists in initial env */ |
@@ -10080,6 +10138,17 @@ int hush_main(int argc, char **argv) | |||
10080 | * PS4='+ ' | 10138 | * PS4='+ ' |
10081 | */ | 10139 | */ |
10082 | 10140 | ||
10141 | #if NUM_SCRIPTS > 0 | ||
10142 | if (argc < 0) { | ||
10143 | char *script = get_script_content(-argc - 1); | ||
10144 | G.global_argv = argv; | ||
10145 | G.global_argc = string_array_len(argv); | ||
10146 | //install_special_sighandlers(); - needed? | ||
10147 | parse_and_run_string(script); | ||
10148 | goto final_return; | ||
10149 | } | ||
10150 | #endif | ||
10151 | |||
10083 | /* Initialize some more globals to non-zero values */ | 10152 | /* Initialize some more globals to non-zero values */ |
10084 | die_func = restore_ttypgrp_and__exit; | 10153 | die_func = restore_ttypgrp_and__exit; |
10085 | 10154 | ||
@@ -10093,17 +10162,9 @@ int hush_main(int argc, char **argv) | |||
10093 | /* Parse options */ | 10162 | /* Parse options */ |
10094 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ | 10163 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/sh.html */ |
10095 | flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; | 10164 | flags = (argv[0] && argv[0][0] == '-') ? OPT_login : 0; |
10096 | builtin_argc = 0; | ||
10097 | #if NUM_SCRIPTS > 0 | ||
10098 | if (argc < 0) { | ||
10099 | optarg = get_script_content(-argc - 1); | ||
10100 | optind = 0; | ||
10101 | argc = string_array_len(argv); | ||
10102 | goto run_script; | ||
10103 | } | ||
10104 | #endif | ||
10105 | while (1) { | 10165 | while (1) { |
10106 | int opt = getopt(argc, argv, "+c:exinsl" | 10166 | int opt = getopt(argc, argv, "+" /* stop at 1st non-option */ |
10167 | "cexinsl" | ||
10107 | #if !BB_MMU | 10168 | #if !BB_MMU |
10108 | "<:$:R:V:" | 10169 | "<:$:R:V:" |
10109 | # if ENABLE_HUSH_FUNCTIONS | 10170 | # if ENABLE_HUSH_FUNCTIONS |
@@ -10115,50 +10176,11 @@ int hush_main(int argc, char **argv) | |||
10115 | break; | 10176 | break; |
10116 | switch (opt) { | 10177 | switch (opt) { |
10117 | case 'c': | 10178 | case 'c': |
10118 | /* Possibilities: | 10179 | /* Note: -c is not an option with param! |
10119 | * sh ... -c 'script' | 10180 | * "hush -c -l SCRIPT" is valid. "hush -cSCRIPT" is not. |
10120 | * sh ... -c 'script' ARG0 [ARG1...] | ||
10121 | * On NOMMU, if builtin_argc != 0, | ||
10122 | * sh ... -c 'builtin' BARGV... "" ARG0 [ARG1...] | ||
10123 | * "" needs to be replaced with NULL | ||
10124 | * and BARGV vector fed to builtin function. | ||
10125 | * Note: the form without ARG0 never happens: | ||
10126 | * sh ... -c 'builtin' BARGV... "" | ||
10127 | */ | 10181 | */ |
10128 | #if NUM_SCRIPTS > 0 | ||
10129 | run_script: | ||
10130 | #endif | ||
10131 | if (!G.root_pid) { | ||
10132 | G.root_pid = getpid(); | ||
10133 | G.root_ppid = getppid(); | ||
10134 | } | ||
10135 | G.global_argv = argv + optind; | ||
10136 | G.global_argc = argc - optind; | ||
10137 | if (builtin_argc) { | ||
10138 | /* -c 'builtin' [BARGV...] "" ARG0 [ARG1...] */ | ||
10139 | const struct built_in_command *x; | ||
10140 | |||
10141 | install_special_sighandlers(); | ||
10142 | x = find_builtin(optarg); | ||
10143 | if (x) { /* paranoia */ | ||
10144 | G.global_argc -= builtin_argc; /* skip [BARGV...] "" */ | ||
10145 | G.global_argv += builtin_argc; | ||
10146 | G.global_argv[-1] = NULL; /* replace "" */ | ||
10147 | fflush_all(); | ||
10148 | G.last_exitcode = x->b_function(argv + optind - 1); | ||
10149 | } | ||
10150 | goto final_return; | ||
10151 | } | ||
10152 | G.opt_c = 1; | 10182 | G.opt_c = 1; |
10153 | if (!G.global_argv[0]) { | 10183 | break; |
10154 | /* -c 'script' (no params): prevent empty $0 */ | ||
10155 | G.global_argv--; /* points to argv[i] of 'script' */ | ||
10156 | G.global_argv[0] = argv[0]; | ||
10157 | G.global_argc++; | ||
10158 | } /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */ | ||
10159 | install_special_sighandlers(); | ||
10160 | parse_and_run_string(optarg); | ||
10161 | goto final_return; | ||
10162 | case 'i': | 10184 | case 'i': |
10163 | /* Well, we cannot just declare interactiveness, | 10185 | /* Well, we cannot just declare interactiveness, |
10164 | * we have to have some stuff (ctty, etc) */ | 10186 | * we have to have some stuff (ctty, etc) */ |
@@ -10205,6 +10227,11 @@ int hush_main(int argc, char **argv) | |||
10205 | optarg++; | 10227 | optarg++; |
10206 | G.depth_of_loop = bb_strtou(optarg, &optarg, 16); | 10228 | G.depth_of_loop = bb_strtou(optarg, &optarg, 16); |
10207 | # endif | 10229 | # endif |
10230 | /* Suppress "killed by signal" message, -$ hack is used | ||
10231 | * for subshells: echo `sh -c 'kill -9 $$'` | ||
10232 | * should be silent. | ||
10233 | */ | ||
10234 | IF_HUSH_JOB(G.run_list_level = 1;) | ||
10208 | # if ENABLE_HUSH_FUNCTIONS | 10235 | # if ENABLE_HUSH_FUNCTIONS |
10209 | /* nommu uses re-exec trick for "... | func | ...", | 10236 | /* nommu uses re-exec trick for "... | func | ...", |
10210 | * should allow "return". | 10237 | * should allow "return". |
@@ -10229,19 +10256,14 @@ int hush_main(int argc, char **argv) | |||
10229 | } | 10256 | } |
10230 | # endif | 10257 | # endif |
10231 | #endif | 10258 | #endif |
10232 | case 'n': | 10259 | /*case '?': invalid option encountered (set_mode('?') will fail) */ |
10233 | case 'x': | 10260 | /*case 'n':*/ |
10234 | case 'e': | 10261 | /*case 'x':*/ |
10262 | /*case 'e':*/ | ||
10263 | default: | ||
10235 | if (set_mode(1, opt, NULL) == 0) /* no error */ | 10264 | if (set_mode(1, opt, NULL) == 0) /* no error */ |
10236 | break; | 10265 | break; |
10237 | default: | ||
10238 | #ifndef BB_VER | ||
10239 | fprintf(stderr, "Usage: sh [FILE]...\n" | ||
10240 | " or: sh -c command [args]...\n\n"); | ||
10241 | exit(EXIT_FAILURE); | ||
10242 | #else | ||
10243 | bb_show_usage(); | 10266 | bb_show_usage(); |
10244 | #endif | ||
10245 | } | 10267 | } |
10246 | } /* option parsing loop */ | 10268 | } /* option parsing loop */ |
10247 | 10269 | ||
@@ -10250,16 +10272,14 @@ int hush_main(int argc, char **argv) | |||
10250 | G.global_argv = argv + (optind - 1); | 10272 | G.global_argv = argv + (optind - 1); |
10251 | G.global_argv[0] = argv[0]; | 10273 | G.global_argv[0] = argv[0]; |
10252 | 10274 | ||
10253 | if (!G.root_pid) { | ||
10254 | G.root_pid = getpid(); | ||
10255 | G.root_ppid = getppid(); | ||
10256 | } | ||
10257 | |||
10258 | /* If we are login shell... */ | 10275 | /* If we are login shell... */ |
10259 | if (flags & OPT_login) { | 10276 | if (flags & OPT_login) { |
10277 | const char *hp = NULL; | ||
10260 | HFILE *input; | 10278 | HFILE *input; |
10279 | |||
10261 | debug_printf("sourcing /etc/profile\n"); | 10280 | debug_printf("sourcing /etc/profile\n"); |
10262 | input = hfopen("/etc/profile"); | 10281 | input = hfopen("/etc/profile"); |
10282 | run_profile: | ||
10263 | if (input != NULL) { | 10283 | if (input != NULL) { |
10264 | install_special_sighandlers(); | 10284 | install_special_sighandlers(); |
10265 | parse_and_run_file(input); | 10285 | parse_and_run_file(input); |
@@ -10272,6 +10292,64 @@ int hush_main(int argc, char **argv) | |||
10272 | * bash also sources ~/.bash_logout on exit. | 10292 | * bash also sources ~/.bash_logout on exit. |
10273 | * If called as sh, skips .bash_XXX files. | 10293 | * If called as sh, skips .bash_XXX files. |
10274 | */ | 10294 | */ |
10295 | if (!hp) { /* unless we looped on the "goto" already */ | ||
10296 | hp = get_local_var_value("HOME"); | ||
10297 | if (hp && hp[0]) { | ||
10298 | debug_printf("sourcing ~/.profile\n"); | ||
10299 | hp = concat_path_file(hp, ".profile"); | ||
10300 | input = hfopen(hp); | ||
10301 | free((char*)hp); | ||
10302 | goto run_profile; | ||
10303 | } | ||
10304 | } | ||
10305 | } | ||
10306 | |||
10307 | /* -c takes effect *after* -l */ | ||
10308 | if (G.opt_c) { | ||
10309 | /* Possibilities: | ||
10310 | * sh ... -c 'script' | ||
10311 | * sh ... -c 'script' ARG0 [ARG1...] | ||
10312 | * On NOMMU, if builtin_argc != 0, | ||
10313 | * sh ... -c 'builtin' BARGV... "" ARG0 [ARG1...] | ||
10314 | * "" needs to be replaced with NULL | ||
10315 | * and BARGV vector fed to builtin function. | ||
10316 | * Note: the form without ARG0 never happens: | ||
10317 | * sh ... -c 'builtin' BARGV... "" | ||
10318 | */ | ||
10319 | char *script; | ||
10320 | |||
10321 | install_special_sighandlers(); | ||
10322 | |||
10323 | G.global_argc--; | ||
10324 | G.global_argv++; | ||
10325 | #if !BB_MMU | ||
10326 | if (builtin_argc) { | ||
10327 | /* -c 'builtin' [BARGV...] "" ARG0 [ARG1...] */ | ||
10328 | const struct built_in_command *x; | ||
10329 | x = find_builtin(G.global_argv[0]); | ||
10330 | if (x) { /* paranoia */ | ||
10331 | argv = G.global_argv; | ||
10332 | G.global_argc -= builtin_argc + 1; /* skip [BARGV...] "" */ | ||
10333 | G.global_argv += builtin_argc + 1; | ||
10334 | G.global_argv[-1] = NULL; /* replace "" */ | ||
10335 | G.last_exitcode = x->b_function(argv); | ||
10336 | } | ||
10337 | goto final_return; | ||
10338 | } | ||
10339 | #endif | ||
10340 | |||
10341 | script = G.global_argv[0]; | ||
10342 | if (!script) | ||
10343 | bb_error_msg_and_die(bb_msg_requires_arg, "-c"); | ||
10344 | if (!G.global_argv[1]) { | ||
10345 | /* -c 'script' (no params): prevent empty $0 */ | ||
10346 | G.global_argv[0] = argv[0]; | ||
10347 | } else { /* else -c 'script' ARG0 [ARG1...]: $0 is ARG0 */ | ||
10348 | G.global_argc--; | ||
10349 | G.global_argv++; | ||
10350 | } | ||
10351 | parse_and_run_string(script); | ||
10352 | goto final_return; | ||
10275 | } | 10353 | } |
10276 | 10354 | ||
10277 | /* -s is: hush -s ARGV1 ARGV2 (no SCRIPT) */ | 10355 | /* -s is: hush -s ARGV1 ARGV2 (no SCRIPT) */ |
@@ -10363,7 +10441,7 @@ int hush_main(int argc, char **argv) | |||
10363 | * (bash, too, does this only if ctty is available) */ | 10441 | * (bash, too, does this only if ctty is available) */ |
10364 | bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ | 10442 | bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */ |
10365 | /* Grab control of the terminal */ | 10443 | /* Grab control of the terminal */ |
10366 | tcsetpgrp(G_interactive_fd, getpid()); | 10444 | tcsetpgrp(G_interactive_fd, cached_getpid); |
10367 | } | 10445 | } |
10368 | enable_restore_tty_pgrp_on_exit(); | 10446 | enable_restore_tty_pgrp_on_exit(); |
10369 | 10447 | ||
@@ -10456,7 +10534,7 @@ static int FAST_FUNC builtin_true(char **argv UNUSED_PARAM) | |||
10456 | } | 10534 | } |
10457 | 10535 | ||
10458 | #if ENABLE_HUSH_TEST || ENABLE_HUSH_ECHO || ENABLE_HUSH_PRINTF || ENABLE_HUSH_KILL | 10536 | #if ENABLE_HUSH_TEST || ENABLE_HUSH_ECHO || ENABLE_HUSH_PRINTF || ENABLE_HUSH_KILL |
10459 | static int run_applet_main(char **argv, int (*applet_main_func)(int argc, char **argv)) | 10537 | static NOINLINE int run_applet_main(char **argv, int (*applet_main_func)(int argc, char **argv)) |
10460 | { | 10538 | { |
10461 | int argc = string_array_len(argv); | 10539 | int argc = string_array_len(argv); |
10462 | return applet_main_func(argc, argv); | 10540 | return applet_main_func(argc, argv); |
@@ -11662,7 +11740,7 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid | |||
11662 | sig = check_and_run_traps(); | 11740 | sig = check_and_run_traps(); |
11663 | if (sig /*&& sig != SIGCHLD - always true */) { | 11741 | if (sig /*&& sig != SIGCHLD - always true */) { |
11664 | /* Do this for any (non-ignored) signal, not only for ^C */ | 11742 | /* Do this for any (non-ignored) signal, not only for ^C */ |
11665 | ret = 128 + sig; | 11743 | ret = 128 | sig; |
11666 | break; | 11744 | break; |
11667 | } | 11745 | } |
11668 | /* SIGCHLD, or no signal, or ignored one, such as SIGQUIT. Repeat */ | 11746 | /* SIGCHLD, or no signal, or ignored one, such as SIGQUIT. Repeat */ |
@@ -11762,7 +11840,7 @@ static int FAST_FUNC builtin_wait(char **argv) | |||
11762 | process_wait_result(NULL, pid, status); | 11840 | process_wait_result(NULL, pid, status); |
11763 | ret = WEXITSTATUS(status); | 11841 | ret = WEXITSTATUS(status); |
11764 | if (WIFSIGNALED(status)) | 11842 | if (WIFSIGNALED(status)) |
11765 | ret = 128 + WTERMSIG(status); | 11843 | ret = 128 | WTERMSIG(status); |
11766 | } | 11844 | } |
11767 | } while (*++argv); | 11845 | } while (*++argv); |
11768 | 11846 | ||