diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-03-24 05:25:59 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-03-24 05:25:59 +0100 |
commit | 3eab24e64a65746ed9fcc5bed3e9a19a489b0573 (patch) | |
tree | d22ebcecadb99fcb4ec94f1b461b39e3910a014c /shell | |
parent | 68d5cb5dacbc80347119ac9cff365e5f04105ef1 (diff) | |
download | busybox-w32-3eab24e64a65746ed9fcc5bed3e9a19a489b0573.tar.gz busybox-w32-3eab24e64a65746ed9fcc5bed3e9a19a489b0573.tar.bz2 busybox-w32-3eab24e64a65746ed9fcc5bed3e9a19a489b0573.zip |
hush: make parse errors in sourced file non-fatal in interactive script
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 97 |
1 files changed, 52 insertions, 45 deletions
diff --git a/shell/hush.c b/shell/hush.c index 8154ac47b..e4c3a7d77 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -1095,17 +1095,10 @@ static void syntax_error_unterm_str(unsigned lineno, const char *s) | |||
1095 | die_if_script(lineno, "syntax error: unterminated %s", s); | 1095 | die_if_script(lineno, "syntax error: unterminated %s", s); |
1096 | } | 1096 | } |
1097 | 1097 | ||
1098 | /* It so happens that all such cases are totally fatal | ||
1099 | * even if shell is interactive: EOF while looking for closing | ||
1100 | * delimiter. There is nowhere to read stuff from after that, | ||
1101 | * it's EOF! The only choice is to terminate. | ||
1102 | */ | ||
1103 | static void syntax_error_unterm_ch(unsigned lineno, char ch) NORETURN; | ||
1104 | static void syntax_error_unterm_ch(unsigned lineno, char ch) | 1098 | static void syntax_error_unterm_ch(unsigned lineno, char ch) |
1105 | { | 1099 | { |
1106 | char msg[2] = { ch, '\0' }; | 1100 | char msg[2] = { ch, '\0' }; |
1107 | syntax_error_unterm_str(lineno, msg); | 1101 | syntax_error_unterm_str(lineno, msg); |
1108 | xfunc_die(); | ||
1109 | } | 1102 | } |
1110 | 1103 | ||
1111 | static void syntax_error_unexpected_ch(unsigned lineno, int ch) | 1104 | static void syntax_error_unexpected_ch(unsigned lineno, int ch) |
@@ -3539,39 +3532,40 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
3539 | 3532 | ||
3540 | #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS | 3533 | #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS |
3541 | /* Subroutines for copying $(...) and `...` things */ | 3534 | /* Subroutines for copying $(...) and `...` things */ |
3542 | static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); | 3535 | static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); |
3543 | /* '...' */ | 3536 | /* '...' */ |
3544 | static void add_till_single_quote(o_string *dest, struct in_str *input) | 3537 | static int add_till_single_quote(o_string *dest, struct in_str *input) |
3545 | { | 3538 | { |
3546 | while (1) { | 3539 | while (1) { |
3547 | int ch = i_getch(input); | 3540 | int ch = i_getch(input); |
3548 | if (ch == EOF) { | 3541 | if (ch == EOF) { |
3549 | syntax_error_unterm_ch('\''); | 3542 | syntax_error_unterm_ch('\''); |
3550 | /*xfunc_die(); - redundant */ | 3543 | return 0; |
3551 | } | 3544 | } |
3552 | if (ch == '\'') | 3545 | if (ch == '\'') |
3553 | return; | 3546 | return 1; |
3554 | o_addchr(dest, ch); | 3547 | o_addchr(dest, ch); |
3555 | } | 3548 | } |
3556 | } | 3549 | } |
3557 | /* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ | 3550 | /* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ |
3558 | static void add_till_double_quote(o_string *dest, struct in_str *input) | 3551 | static int add_till_double_quote(o_string *dest, struct in_str *input) |
3559 | { | 3552 | { |
3560 | while (1) { | 3553 | while (1) { |
3561 | int ch = i_getch(input); | 3554 | int ch = i_getch(input); |
3562 | if (ch == EOF) { | 3555 | if (ch == EOF) { |
3563 | syntax_error_unterm_ch('"'); | 3556 | syntax_error_unterm_ch('"'); |
3564 | /*xfunc_die(); - redundant */ | 3557 | return 0; |
3565 | } | 3558 | } |
3566 | if (ch == '"') | 3559 | if (ch == '"') |
3567 | return; | 3560 | return 1; |
3568 | if (ch == '\\') { /* \x. Copy both chars. */ | 3561 | if (ch == '\\') { /* \x. Copy both chars. */ |
3569 | o_addchr(dest, ch); | 3562 | o_addchr(dest, ch); |
3570 | ch = i_getch(input); | 3563 | ch = i_getch(input); |
3571 | } | 3564 | } |
3572 | o_addchr(dest, ch); | 3565 | o_addchr(dest, ch); |
3573 | if (ch == '`') { | 3566 | if (ch == '`') { |
3574 | add_till_backquote(dest, input, /*in_dquote:*/ 1); | 3567 | if (!add_till_backquote(dest, input, /*in_dquote:*/ 1)) |
3568 | return 0; | ||
3575 | o_addchr(dest, ch); | 3569 | o_addchr(dest, ch); |
3576 | continue; | 3570 | continue; |
3577 | } | 3571 | } |
@@ -3592,12 +3586,12 @@ static void add_till_double_quote(o_string *dest, struct in_str *input) | |||
3592 | * Example Output | 3586 | * Example Output |
3593 | * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST | 3587 | * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST |
3594 | */ | 3588 | */ |
3595 | static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquote) | 3589 | static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote) |
3596 | { | 3590 | { |
3597 | while (1) { | 3591 | while (1) { |
3598 | int ch = i_getch(input); | 3592 | int ch = i_getch(input); |
3599 | if (ch == '`') | 3593 | if (ch == '`') |
3600 | return; | 3594 | return 1; |
3601 | if (ch == '\\') { | 3595 | if (ch == '\\') { |
3602 | /* \x. Copy both unless it is \`, \$, \\ and maybe \" */ | 3596 | /* \x. Copy both unless it is \`, \$, \\ and maybe \" */ |
3603 | ch = i_getch(input); | 3597 | ch = i_getch(input); |
@@ -3611,7 +3605,7 @@ static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquo | |||
3611 | } | 3605 | } |
3612 | if (ch == EOF) { | 3606 | if (ch == EOF) { |
3613 | syntax_error_unterm_ch('`'); | 3607 | syntax_error_unterm_ch('`'); |
3614 | /*xfunc_die(); - redundant */ | 3608 | return 0; |
3615 | } | 3609 | } |
3616 | o_addchr(dest, ch); | 3610 | o_addchr(dest, ch); |
3617 | } | 3611 | } |
@@ -3647,7 +3641,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign | |||
3647 | ch = i_getch(input); | 3641 | ch = i_getch(input); |
3648 | if (ch == EOF) { | 3642 | if (ch == EOF) { |
3649 | syntax_error_unterm_ch(end_ch); | 3643 | syntax_error_unterm_ch(end_ch); |
3650 | /*xfunc_die(); - redundant */ | 3644 | return 0; |
3651 | } | 3645 | } |
3652 | if (ch == end_ch IF_HUSH_BASH_COMPAT( || ch == end_char2)) { | 3646 | if (ch == end_ch IF_HUSH_BASH_COMPAT( || ch == end_char2)) { |
3653 | if (!dbl) | 3647 | if (!dbl) |
@@ -3661,22 +3655,26 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign | |||
3661 | o_addchr(dest, ch); | 3655 | o_addchr(dest, ch); |
3662 | if (ch == '(' || ch == '{') { | 3656 | if (ch == '(' || ch == '{') { |
3663 | ch = (ch == '(' ? ')' : '}'); | 3657 | ch = (ch == '(' ? ')' : '}'); |
3664 | add_till_closing_bracket(dest, input, ch); | 3658 | if (!add_till_closing_bracket(dest, input, ch)) |
3659 | return 0; | ||
3665 | o_addchr(dest, ch); | 3660 | o_addchr(dest, ch); |
3666 | continue; | 3661 | continue; |
3667 | } | 3662 | } |
3668 | if (ch == '\'') { | 3663 | if (ch == '\'') { |
3669 | add_till_single_quote(dest, input); | 3664 | if (!add_till_single_quote(dest, input)) |
3665 | return 0; | ||
3670 | o_addchr(dest, ch); | 3666 | o_addchr(dest, ch); |
3671 | continue; | 3667 | continue; |
3672 | } | 3668 | } |
3673 | if (ch == '"') { | 3669 | if (ch == '"') { |
3674 | add_till_double_quote(dest, input); | 3670 | if (!add_till_double_quote(dest, input)) |
3671 | return 0; | ||
3675 | o_addchr(dest, ch); | 3672 | o_addchr(dest, ch); |
3676 | continue; | 3673 | continue; |
3677 | } | 3674 | } |
3678 | if (ch == '`') { | 3675 | if (ch == '`') { |
3679 | add_till_backquote(dest, input, /*in_dquote:*/ 0); | 3676 | if (!add_till_backquote(dest, input, /*in_dquote:*/ 0)) |
3677 | return 0; | ||
3680 | o_addchr(dest, ch); | 3678 | o_addchr(dest, ch); |
3681 | continue; | 3679 | continue; |
3682 | } | 3680 | } |
@@ -3685,7 +3683,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign | |||
3685 | ch = i_getch(input); | 3683 | ch = i_getch(input); |
3686 | if (ch == EOF) { | 3684 | if (ch == EOF) { |
3687 | syntax_error_unterm_ch(')'); | 3685 | syntax_error_unterm_ch(')'); |
3688 | /*xfunc_die(); - redundant */ | 3686 | return 0; |
3689 | } | 3687 | } |
3690 | o_addchr(dest, ch); | 3688 | o_addchr(dest, ch); |
3691 | continue; | 3689 | continue; |
@@ -3756,8 +3754,8 @@ static int parse_dollar(o_string *as_string, | |||
3756 | ) { | 3754 | ) { |
3757 | bad_dollar_syntax: | 3755 | bad_dollar_syntax: |
3758 | syntax_error_unterm_str("${name}"); | 3756 | syntax_error_unterm_str("${name}"); |
3759 | debug_printf_parse("parse_dollar return 1: unterminated ${name}\n"); | 3757 | debug_printf_parse("parse_dollar return 0: unterminated ${name}\n"); |
3760 | return 1; | 3758 | return 0; |
3761 | } | 3759 | } |
3762 | nommu_addchr(as_string, ch); | 3760 | nommu_addchr(as_string, ch); |
3763 | ch |= quote_mask; | 3761 | ch |= quote_mask; |
@@ -3813,6 +3811,8 @@ static int parse_dollar(o_string *as_string, | |||
3813 | pos = dest->length; | 3811 | pos = dest->length; |
3814 | #if ENABLE_HUSH_DOLLAR_OPS | 3812 | #if ENABLE_HUSH_DOLLAR_OPS |
3815 | last_ch = add_till_closing_bracket(dest, input, end_ch); | 3813 | last_ch = add_till_closing_bracket(dest, input, end_ch); |
3814 | if (last_ch == 0) /* error? */ | ||
3815 | return 0; | ||
3816 | #else | 3816 | #else |
3817 | #error Simple code to only allow ${var} is not implemented | 3817 | #error Simple code to only allow ${var} is not implemented |
3818 | #endif | 3818 | #endif |
@@ -3857,7 +3857,8 @@ static int parse_dollar(o_string *as_string, | |||
3857 | o_addchr(dest, /*quote_mask |*/ '+'); | 3857 | o_addchr(dest, /*quote_mask |*/ '+'); |
3858 | if (!BB_MMU) | 3858 | if (!BB_MMU) |
3859 | pos = dest->length; | 3859 | pos = dest->length; |
3860 | add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG); | 3860 | if (!add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG)) |
3861 | return 0; /* error */ | ||
3861 | if (as_string) { | 3862 | if (as_string) { |
3862 | o_addstr(as_string, dest->data + pos); | 3863 | o_addstr(as_string, dest->data + pos); |
3863 | o_addchr(as_string, ')'); | 3864 | o_addchr(as_string, ')'); |
@@ -3872,7 +3873,8 @@ static int parse_dollar(o_string *as_string, | |||
3872 | o_addchr(dest, quote_mask | '`'); | 3873 | o_addchr(dest, quote_mask | '`'); |
3873 | if (!BB_MMU) | 3874 | if (!BB_MMU) |
3874 | pos = dest->length; | 3875 | pos = dest->length; |
3875 | add_till_closing_bracket(dest, input, ')'); | 3876 | if (!add_till_closing_bracket(dest, input, ')')) |
3877 | return 0; /* error */ | ||
3876 | if (as_string) { | 3878 | if (as_string) { |
3877 | o_addstr(as_string, dest->data + pos); | 3879 | o_addstr(as_string, dest->data + pos); |
3878 | o_addchr(as_string, ')'); | 3880 | o_addchr(as_string, ')'); |
@@ -3899,8 +3901,8 @@ static int parse_dollar(o_string *as_string, | |||
3899 | default: | 3901 | default: |
3900 | o_addQchr(dest, '$'); | 3902 | o_addQchr(dest, '$'); |
3901 | } | 3903 | } |
3902 | debug_printf_parse("parse_dollar return 0\n"); | 3904 | debug_printf_parse("parse_dollar return 1 (ok)\n"); |
3903 | return 0; | 3905 | return 1; |
3904 | #undef as_string | 3906 | #undef as_string |
3905 | } | 3907 | } |
3906 | 3908 | ||
@@ -3941,13 +3943,13 @@ static int encode_string(o_string *as_string, | |||
3941 | if (ch != EOF) | 3943 | if (ch != EOF) |
3942 | nommu_addchr(as_string, ch); | 3944 | nommu_addchr(as_string, ch); |
3943 | if (ch == dquote_end) { /* may be only '"' or EOF */ | 3945 | if (ch == dquote_end) { /* may be only '"' or EOF */ |
3944 | debug_printf_parse("encode_string return 0\n"); | 3946 | debug_printf_parse("encode_string return 1 (ok)\n"); |
3945 | return 0; | 3947 | return 1; |
3946 | } | 3948 | } |
3947 | /* note: can't move it above ch == dquote_end check! */ | 3949 | /* note: can't move it above ch == dquote_end check! */ |
3948 | if (ch == EOF) { | 3950 | if (ch == EOF) { |
3949 | syntax_error_unterm_ch('"'); | 3951 | syntax_error_unterm_ch('"'); |
3950 | /*xfunc_die(); - redundant */ | 3952 | return 0; /* error */ |
3951 | } | 3953 | } |
3952 | next = '\0'; | 3954 | next = '\0'; |
3953 | if (ch != '\n') { | 3955 | if (ch != '\n') { |
@@ -3978,10 +3980,10 @@ static int encode_string(o_string *as_string, | |||
3978 | goto again; | 3980 | goto again; |
3979 | } | 3981 | } |
3980 | if (ch == '$') { | 3982 | if (ch == '$') { |
3981 | if (parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80) != 0) { | 3983 | if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) { |
3982 | debug_printf_parse("encode_string return 1: " | 3984 | debug_printf_parse("encode_string return 0: " |
3983 | "parse_dollar returned non-0\n"); | 3985 | "parse_dollar returned 0 (error)\n"); |
3984 | return 1; | 3986 | return 0; |
3985 | } | 3987 | } |
3986 | goto again; | 3988 | goto again; |
3987 | } | 3989 | } |
@@ -3990,7 +3992,8 @@ static int encode_string(o_string *as_string, | |||
3990 | //unsigned pos = dest->length; | 3992 | //unsigned pos = dest->length; |
3991 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 3993 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
3992 | o_addchr(dest, 0x80 | '`'); | 3994 | o_addchr(dest, 0x80 | '`'); |
3993 | add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"'); | 3995 | if (!add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"')) |
3996 | return 0; /* error */ | ||
3994 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 3997 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
3995 | //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); | 3998 | //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); |
3996 | goto again; | 3999 | goto again; |
@@ -4061,8 +4064,8 @@ static struct pipe *parse_stream(char **pstring, | |||
4061 | /* end_trigger == '}' case errors out earlier, | 4064 | /* end_trigger == '}' case errors out earlier, |
4062 | * checking only ')' */ | 4065 | * checking only ')' */ |
4063 | if (end_trigger == ')') { | 4066 | if (end_trigger == ')') { |
4064 | syntax_error_unterm_ch('('); /* exits */ | 4067 | syntax_error_unterm_ch('('); |
4065 | /* goto parse_error; */ | 4068 | goto parse_error; |
4066 | } | 4069 | } |
4067 | 4070 | ||
4068 | if (done_word(&dest, &ctx)) { | 4071 | if (done_word(&dest, &ctx)) { |
@@ -4353,9 +4356,9 @@ static struct pipe *parse_stream(char **pstring, | |||
4353 | dest.has_quoted_part = 1; | 4356 | dest.has_quoted_part = 1; |
4354 | break; | 4357 | break; |
4355 | case '$': | 4358 | case '$': |
4356 | if (parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0) != 0) { | 4359 | if (!parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0)) { |
4357 | debug_printf_parse("parse_stream parse error: " | 4360 | debug_printf_parse("parse_stream parse error: " |
4358 | "parse_dollar returned non-0\n"); | 4361 | "parse_dollar returned 0 (error)\n"); |
4359 | goto parse_error; | 4362 | goto parse_error; |
4360 | } | 4363 | } |
4361 | break; | 4364 | break; |
@@ -4365,7 +4368,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4365 | ch = i_getch(input); | 4368 | ch = i_getch(input); |
4366 | if (ch == EOF) { | 4369 | if (ch == EOF) { |
4367 | syntax_error_unterm_ch('\''); | 4370 | syntax_error_unterm_ch('\''); |
4368 | /*xfunc_die(); - redundant */ | 4371 | goto parse_error; |
4369 | } | 4372 | } |
4370 | nommu_addchr(&ctx.as_string, ch); | 4373 | nommu_addchr(&ctx.as_string, ch); |
4371 | if (ch == '\'') | 4374 | if (ch == '\'') |
@@ -4377,7 +4380,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4377 | dest.has_quoted_part = 1; | 4380 | dest.has_quoted_part = 1; |
4378 | if (dest.o_assignment == NOT_ASSIGNMENT) | 4381 | if (dest.o_assignment == NOT_ASSIGNMENT) |
4379 | dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; | 4382 | dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; |
4380 | if (encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) | 4383 | if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) |
4381 | goto parse_error; | 4384 | goto parse_error; |
4382 | dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; | 4385 | dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; |
4383 | break; | 4386 | break; |
@@ -4388,7 +4391,8 @@ static struct pipe *parse_stream(char **pstring, | |||
4388 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); | 4391 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); |
4389 | o_addchr(&dest, '`'); | 4392 | o_addchr(&dest, '`'); |
4390 | pos = dest.length; | 4393 | pos = dest.length; |
4391 | add_till_backquote(&dest, input, /*in_dquote:*/ 0); | 4394 | if (!add_till_backquote(&dest, input, /*in_dquote:*/ 0)) |
4395 | goto parse_error; | ||
4392 | # if !BB_MMU | 4396 | # if !BB_MMU |
4393 | o_addstr(&ctx.as_string, dest.data + pos); | 4397 | o_addstr(&ctx.as_string, dest.data + pos); |
4394 | o_addchr(&ctx.as_string, '`'); | 4398 | o_addchr(&ctx.as_string, '`'); |
@@ -4664,6 +4668,7 @@ static char *encode_then_expand_string(const char *str, int process_bkslash, int | |||
4664 | */ | 4668 | */ |
4665 | setup_string_in_str(&input, str); | 4669 | setup_string_in_str(&input, str); |
4666 | encode_string(NULL, &dest, &input, EOF, process_bkslash); | 4670 | encode_string(NULL, &dest, &input, EOF, process_bkslash); |
4671 | //TODO: error check (encode_string returns 0 on error)? | ||
4667 | //bb_error_msg("'%s' -> '%s'", str, dest.data); | 4672 | //bb_error_msg("'%s' -> '%s'", str, dest.data); |
4668 | exp_str = expand_string_to_string(dest.data, /*unbackslash:*/ do_unbackslash); | 4673 | exp_str = expand_string_to_string(dest.data, /*unbackslash:*/ do_unbackslash); |
4669 | //bb_error_msg("'%s' -> '%s'", dest.data, exp_str); | 4674 | //bb_error_msg("'%s' -> '%s'", dest.data, exp_str); |
@@ -8625,6 +8630,8 @@ static int FAST_FUNC builtin_source(char **argv) | |||
8625 | #endif | 8630 | #endif |
8626 | save_and_replace_G_args(&sv, argv); | 8631 | save_and_replace_G_args(&sv, argv); |
8627 | 8632 | ||
8633 | //TODO: syntax errors in sourced file should never abort the "calling" script. | ||
8634 | //Try: bash -c '. ./bad_file; echo YES' | ||
8628 | parse_and_run_file(input); | 8635 | parse_and_run_file(input); |
8629 | fclose(input); | 8636 | fclose(input); |
8630 | 8637 | ||