hush: make parse errors in sourced file non-fatal in interactive script
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
68d5cb5dac
commit
3eab24e64a
97
shell/hush.c
97
shell/hush.c
@ -1095,17 +1095,10 @@ static void syntax_error_unterm_str(unsigned lineno, const char *s)
|
|||||||
die_if_script(lineno, "syntax error: unterminated %s", s);
|
die_if_script(lineno, "syntax error: unterminated %s", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* It so happens that all such cases are totally fatal
|
|
||||||
* even if shell is interactive: EOF while looking for closing
|
|
||||||
* delimiter. There is nowhere to read stuff from after that,
|
|
||||||
* it's EOF! The only choice is to terminate.
|
|
||||||
*/
|
|
||||||
static void syntax_error_unterm_ch(unsigned lineno, char ch) NORETURN;
|
|
||||||
static void syntax_error_unterm_ch(unsigned lineno, char ch)
|
static void syntax_error_unterm_ch(unsigned lineno, char ch)
|
||||||
{
|
{
|
||||||
char msg[2] = { ch, '\0' };
|
char msg[2] = { ch, '\0' };
|
||||||
syntax_error_unterm_str(lineno, msg);
|
syntax_error_unterm_str(lineno, msg);
|
||||||
xfunc_die();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syntax_error_unexpected_ch(unsigned lineno, int ch)
|
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,
|
|||||||
|
|
||||||
#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS
|
#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS
|
||||||
/* Subroutines for copying $(...) and `...` things */
|
/* Subroutines for copying $(...) and `...` things */
|
||||||
static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
|
static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote);
|
||||||
/* '...' */
|
/* '...' */
|
||||||
static void add_till_single_quote(o_string *dest, struct in_str *input)
|
static int add_till_single_quote(o_string *dest, struct in_str *input)
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
int ch = i_getch(input);
|
int ch = i_getch(input);
|
||||||
if (ch == EOF) {
|
if (ch == EOF) {
|
||||||
syntax_error_unterm_ch('\'');
|
syntax_error_unterm_ch('\'');
|
||||||
/*xfunc_die(); - redundant */
|
return 0;
|
||||||
}
|
}
|
||||||
if (ch == '\'')
|
if (ch == '\'')
|
||||||
return;
|
return 1;
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */
|
/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */
|
||||||
static void add_till_double_quote(o_string *dest, struct in_str *input)
|
static int add_till_double_quote(o_string *dest, struct in_str *input)
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
int ch = i_getch(input);
|
int ch = i_getch(input);
|
||||||
if (ch == EOF) {
|
if (ch == EOF) {
|
||||||
syntax_error_unterm_ch('"');
|
syntax_error_unterm_ch('"');
|
||||||
/*xfunc_die(); - redundant */
|
return 0;
|
||||||
}
|
}
|
||||||
if (ch == '"')
|
if (ch == '"')
|
||||||
return;
|
return 1;
|
||||||
if (ch == '\\') { /* \x. Copy both chars. */
|
if (ch == '\\') { /* \x. Copy both chars. */
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
}
|
}
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
if (ch == '`') {
|
if (ch == '`') {
|
||||||
add_till_backquote(dest, input, /*in_dquote:*/ 1);
|
if (!add_till_backquote(dest, input, /*in_dquote:*/ 1))
|
||||||
|
return 0;
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -3592,12 +3586,12 @@ static void add_till_double_quote(o_string *dest, struct in_str *input)
|
|||||||
* Example Output
|
* Example Output
|
||||||
* echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST
|
* echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST
|
||||||
*/
|
*/
|
||||||
static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquote)
|
static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote)
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
int ch = i_getch(input);
|
int ch = i_getch(input);
|
||||||
if (ch == '`')
|
if (ch == '`')
|
||||||
return;
|
return 1;
|
||||||
if (ch == '\\') {
|
if (ch == '\\') {
|
||||||
/* \x. Copy both unless it is \`, \$, \\ and maybe \" */
|
/* \x. Copy both unless it is \`, \$, \\ and maybe \" */
|
||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
@ -3611,7 +3605,7 @@ static void add_till_backquote(o_string *dest, struct in_str *input, int in_dquo
|
|||||||
}
|
}
|
||||||
if (ch == EOF) {
|
if (ch == EOF) {
|
||||||
syntax_error_unterm_ch('`');
|
syntax_error_unterm_ch('`');
|
||||||
/*xfunc_die(); - redundant */
|
return 0;
|
||||||
}
|
}
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
}
|
}
|
||||||
@ -3647,7 +3641,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
|
|||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
if (ch == EOF) {
|
if (ch == EOF) {
|
||||||
syntax_error_unterm_ch(end_ch);
|
syntax_error_unterm_ch(end_ch);
|
||||||
/*xfunc_die(); - redundant */
|
return 0;
|
||||||
}
|
}
|
||||||
if (ch == end_ch IF_HUSH_BASH_COMPAT( || ch == end_char2)) {
|
if (ch == end_ch IF_HUSH_BASH_COMPAT( || ch == end_char2)) {
|
||||||
if (!dbl)
|
if (!dbl)
|
||||||
@ -3661,22 +3655,26 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
|
|||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
if (ch == '(' || ch == '{') {
|
if (ch == '(' || ch == '{') {
|
||||||
ch = (ch == '(' ? ')' : '}');
|
ch = (ch == '(' ? ')' : '}');
|
||||||
add_till_closing_bracket(dest, input, ch);
|
if (!add_till_closing_bracket(dest, input, ch))
|
||||||
|
return 0;
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ch == '\'') {
|
if (ch == '\'') {
|
||||||
add_till_single_quote(dest, input);
|
if (!add_till_single_quote(dest, input))
|
||||||
|
return 0;
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ch == '"') {
|
if (ch == '"') {
|
||||||
add_till_double_quote(dest, input);
|
if (!add_till_double_quote(dest, input))
|
||||||
|
return 0;
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ch == '`') {
|
if (ch == '`') {
|
||||||
add_till_backquote(dest, input, /*in_dquote:*/ 0);
|
if (!add_till_backquote(dest, input, /*in_dquote:*/ 0))
|
||||||
|
return 0;
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -3685,7 +3683,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
|
|||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
if (ch == EOF) {
|
if (ch == EOF) {
|
||||||
syntax_error_unterm_ch(')');
|
syntax_error_unterm_ch(')');
|
||||||
/*xfunc_die(); - redundant */
|
return 0;
|
||||||
}
|
}
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
continue;
|
continue;
|
||||||
@ -3756,8 +3754,8 @@ static int parse_dollar(o_string *as_string,
|
|||||||
) {
|
) {
|
||||||
bad_dollar_syntax:
|
bad_dollar_syntax:
|
||||||
syntax_error_unterm_str("${name}");
|
syntax_error_unterm_str("${name}");
|
||||||
debug_printf_parse("parse_dollar return 1: unterminated ${name}\n");
|
debug_printf_parse("parse_dollar return 0: unterminated ${name}\n");
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
nommu_addchr(as_string, ch);
|
nommu_addchr(as_string, ch);
|
||||||
ch |= quote_mask;
|
ch |= quote_mask;
|
||||||
@ -3813,6 +3811,8 @@ static int parse_dollar(o_string *as_string,
|
|||||||
pos = dest->length;
|
pos = dest->length;
|
||||||
#if ENABLE_HUSH_DOLLAR_OPS
|
#if ENABLE_HUSH_DOLLAR_OPS
|
||||||
last_ch = add_till_closing_bracket(dest, input, end_ch);
|
last_ch = add_till_closing_bracket(dest, input, end_ch);
|
||||||
|
if (last_ch == 0) /* error? */
|
||||||
|
return 0;
|
||||||
#else
|
#else
|
||||||
#error Simple code to only allow ${var} is not implemented
|
#error Simple code to only allow ${var} is not implemented
|
||||||
#endif
|
#endif
|
||||||
@ -3857,7 +3857,8 @@ static int parse_dollar(o_string *as_string,
|
|||||||
o_addchr(dest, /*quote_mask |*/ '+');
|
o_addchr(dest, /*quote_mask |*/ '+');
|
||||||
if (!BB_MMU)
|
if (!BB_MMU)
|
||||||
pos = dest->length;
|
pos = dest->length;
|
||||||
add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG);
|
if (!add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG))
|
||||||
|
return 0; /* error */
|
||||||
if (as_string) {
|
if (as_string) {
|
||||||
o_addstr(as_string, dest->data + pos);
|
o_addstr(as_string, dest->data + pos);
|
||||||
o_addchr(as_string, ')');
|
o_addchr(as_string, ')');
|
||||||
@ -3872,7 +3873,8 @@ static int parse_dollar(o_string *as_string,
|
|||||||
o_addchr(dest, quote_mask | '`');
|
o_addchr(dest, quote_mask | '`');
|
||||||
if (!BB_MMU)
|
if (!BB_MMU)
|
||||||
pos = dest->length;
|
pos = dest->length;
|
||||||
add_till_closing_bracket(dest, input, ')');
|
if (!add_till_closing_bracket(dest, input, ')'))
|
||||||
|
return 0; /* error */
|
||||||
if (as_string) {
|
if (as_string) {
|
||||||
o_addstr(as_string, dest->data + pos);
|
o_addstr(as_string, dest->data + pos);
|
||||||
o_addchr(as_string, ')');
|
o_addchr(as_string, ')');
|
||||||
@ -3899,8 +3901,8 @@ static int parse_dollar(o_string *as_string,
|
|||||||
default:
|
default:
|
||||||
o_addQchr(dest, '$');
|
o_addQchr(dest, '$');
|
||||||
}
|
}
|
||||||
debug_printf_parse("parse_dollar return 0\n");
|
debug_printf_parse("parse_dollar return 1 (ok)\n");
|
||||||
return 0;
|
return 1;
|
||||||
#undef as_string
|
#undef as_string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3941,13 +3943,13 @@ static int encode_string(o_string *as_string,
|
|||||||
if (ch != EOF)
|
if (ch != EOF)
|
||||||
nommu_addchr(as_string, ch);
|
nommu_addchr(as_string, ch);
|
||||||
if (ch == dquote_end) { /* may be only '"' or EOF */
|
if (ch == dquote_end) { /* may be only '"' or EOF */
|
||||||
debug_printf_parse("encode_string return 0\n");
|
debug_printf_parse("encode_string return 1 (ok)\n");
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
/* note: can't move it above ch == dquote_end check! */
|
/* note: can't move it above ch == dquote_end check! */
|
||||||
if (ch == EOF) {
|
if (ch == EOF) {
|
||||||
syntax_error_unterm_ch('"');
|
syntax_error_unterm_ch('"');
|
||||||
/*xfunc_die(); - redundant */
|
return 0; /* error */
|
||||||
}
|
}
|
||||||
next = '\0';
|
next = '\0';
|
||||||
if (ch != '\n') {
|
if (ch != '\n') {
|
||||||
@ -3978,10 +3980,10 @@ static int encode_string(o_string *as_string,
|
|||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
if (ch == '$') {
|
if (ch == '$') {
|
||||||
if (parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80) != 0) {
|
if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) {
|
||||||
debug_printf_parse("encode_string return 1: "
|
debug_printf_parse("encode_string return 0: "
|
||||||
"parse_dollar returned non-0\n");
|
"parse_dollar returned 0 (error)\n");
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
@ -3990,7 +3992,8 @@ static int encode_string(o_string *as_string,
|
|||||||
//unsigned pos = dest->length;
|
//unsigned pos = dest->length;
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
o_addchr(dest, 0x80 | '`');
|
o_addchr(dest, 0x80 | '`');
|
||||||
add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"');
|
if (!add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"'))
|
||||||
|
return 0; /* error */
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
//debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
|
//debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
|
||||||
goto again;
|
goto again;
|
||||||
@ -4061,8 +4064,8 @@ static struct pipe *parse_stream(char **pstring,
|
|||||||
/* end_trigger == '}' case errors out earlier,
|
/* end_trigger == '}' case errors out earlier,
|
||||||
* checking only ')' */
|
* checking only ')' */
|
||||||
if (end_trigger == ')') {
|
if (end_trigger == ')') {
|
||||||
syntax_error_unterm_ch('('); /* exits */
|
syntax_error_unterm_ch('(');
|
||||||
/* goto parse_error; */
|
goto parse_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (done_word(&dest, &ctx)) {
|
if (done_word(&dest, &ctx)) {
|
||||||
@ -4353,9 +4356,9 @@ static struct pipe *parse_stream(char **pstring,
|
|||||||
dest.has_quoted_part = 1;
|
dest.has_quoted_part = 1;
|
||||||
break;
|
break;
|
||||||
case '$':
|
case '$':
|
||||||
if (parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0) != 0) {
|
if (!parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0)) {
|
||||||
debug_printf_parse("parse_stream parse error: "
|
debug_printf_parse("parse_stream parse error: "
|
||||||
"parse_dollar returned non-0\n");
|
"parse_dollar returned 0 (error)\n");
|
||||||
goto parse_error;
|
goto parse_error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -4365,7 +4368,7 @@ static struct pipe *parse_stream(char **pstring,
|
|||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
if (ch == EOF) {
|
if (ch == EOF) {
|
||||||
syntax_error_unterm_ch('\'');
|
syntax_error_unterm_ch('\'');
|
||||||
/*xfunc_die(); - redundant */
|
goto parse_error;
|
||||||
}
|
}
|
||||||
nommu_addchr(&ctx.as_string, ch);
|
nommu_addchr(&ctx.as_string, ch);
|
||||||
if (ch == '\'')
|
if (ch == '\'')
|
||||||
@ -4377,7 +4380,7 @@ static struct pipe *parse_stream(char **pstring,
|
|||||||
dest.has_quoted_part = 1;
|
dest.has_quoted_part = 1;
|
||||||
if (dest.o_assignment == NOT_ASSIGNMENT)
|
if (dest.o_assignment == NOT_ASSIGNMENT)
|
||||||
dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS;
|
dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS;
|
||||||
if (encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1))
|
if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1))
|
||||||
goto parse_error;
|
goto parse_error;
|
||||||
dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS;
|
dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS;
|
||||||
break;
|
break;
|
||||||
@ -4388,7 +4391,8 @@ static struct pipe *parse_stream(char **pstring,
|
|||||||
o_addchr(&dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(&dest, SPECIAL_VAR_SYMBOL);
|
||||||
o_addchr(&dest, '`');
|
o_addchr(&dest, '`');
|
||||||
pos = dest.length;
|
pos = dest.length;
|
||||||
add_till_backquote(&dest, input, /*in_dquote:*/ 0);
|
if (!add_till_backquote(&dest, input, /*in_dquote:*/ 0))
|
||||||
|
goto parse_error;
|
||||||
# if !BB_MMU
|
# if !BB_MMU
|
||||||
o_addstr(&ctx.as_string, dest.data + pos);
|
o_addstr(&ctx.as_string, dest.data + pos);
|
||||||
o_addchr(&ctx.as_string, '`');
|
o_addchr(&ctx.as_string, '`');
|
||||||
@ -4664,6 +4668,7 @@ static char *encode_then_expand_string(const char *str, int process_bkslash, int
|
|||||||
*/
|
*/
|
||||||
setup_string_in_str(&input, str);
|
setup_string_in_str(&input, str);
|
||||||
encode_string(NULL, &dest, &input, EOF, process_bkslash);
|
encode_string(NULL, &dest, &input, EOF, process_bkslash);
|
||||||
|
//TODO: error check (encode_string returns 0 on error)?
|
||||||
//bb_error_msg("'%s' -> '%s'", str, dest.data);
|
//bb_error_msg("'%s' -> '%s'", str, dest.data);
|
||||||
exp_str = expand_string_to_string(dest.data, /*unbackslash:*/ do_unbackslash);
|
exp_str = expand_string_to_string(dest.data, /*unbackslash:*/ do_unbackslash);
|
||||||
//bb_error_msg("'%s' -> '%s'", dest.data, exp_str);
|
//bb_error_msg("'%s' -> '%s'", dest.data, exp_str);
|
||||||
@ -8625,6 +8630,8 @@ static int FAST_FUNC builtin_source(char **argv)
|
|||||||
#endif
|
#endif
|
||||||
save_and_replace_G_args(&sv, argv);
|
save_and_replace_G_args(&sv, argv);
|
||||||
|
|
||||||
|
//TODO: syntax errors in sourced file should never abort the "calling" script.
|
||||||
|
//Try: bash -c '. ./bad_file; echo YES'
|
||||||
parse_and_run_file(input);
|
parse_and_run_file(input);
|
||||||
fclose(input);
|
fclose(input);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user