diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-17 11:55:42 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-17 11:55:42 +0000 |
commit | f8c1f02d2f7733619437581c2264828d3d160089 (patch) | |
tree | aca561482419d64a6d36d649fc1f4f67d1ba9123 /shell | |
parent | 5ff9629b8fe7578dd0cefb31764365c89ca6328c (diff) | |
download | busybox-w32-f8c1f02d2f7733619437581c2264828d3d160089.tar.gz busybox-w32-f8c1f02d2f7733619437581c2264828d3d160089.tar.bz2 busybox-w32-f8c1f02d2f7733619437581c2264828d3d160089.zip |
hush: disallow "{echo hi; }" (require whitespace)
and "{ echo hi }" (require semicolon or &)
function old new delta
parse_stream 2098 2176 +78
done_command 98 84 -14
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 78/-14) Total: 64 bytes
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 55 |
1 files changed, 35 insertions, 20 deletions
diff --git a/shell/hush.c b/shell/hush.c index 61b6a7925..8dda988ee 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -319,6 +319,10 @@ struct command { | |||
319 | */ | 319 | */ |
320 | struct redir_struct *redirects; /* I/O redirections */ | 320 | struct redir_struct *redirects; /* I/O redirections */ |
321 | }; | 321 | }; |
322 | /* Is there anything in this command at all? */ | ||
323 | #define IS_NULL_CMD(cmd) \ | ||
324 | (!(cmd)->group && !(cmd)->argv && !(cmd)->redirects) | ||
325 | |||
322 | 326 | ||
323 | struct pipe { | 327 | struct pipe { |
324 | struct pipe *next; | 328 | struct pipe *next; |
@@ -341,6 +345,9 @@ typedef enum pipe_style { | |||
341 | PIPE_OR = 3, | 345 | PIPE_OR = 3, |
342 | PIPE_BG = 4, | 346 | PIPE_BG = 4, |
343 | } pipe_style; | 347 | } pipe_style; |
348 | /* Is there anything in this pipe at all? */ | ||
349 | #define IS_NULL_PIPE(pi) \ | ||
350 | ((pi)->num_cmds == 0 IF_HAS_KEYWORDS( && (pi)->res_word == RES_NONE)) | ||
344 | 351 | ||
345 | /* This holds pointers to the various results of parsing */ | 352 | /* This holds pointers to the various results of parsing */ |
346 | struct parse_context { | 353 | struct parse_context { |
@@ -3971,8 +3978,10 @@ static struct pipe *new_pipe(void) | |||
3971 | return pi; | 3978 | return pi; |
3972 | } | 3979 | } |
3973 | 3980 | ||
3974 | /* Command (member of a pipe) is complete. The only possible error here | 3981 | /* Command (member of a pipe) is complete, or we start a new pipe |
3975 | * is out of memory, in which case xmalloc exits. */ | 3982 | * if ctx->command is NULL. |
3983 | * No errors possible here. | ||
3984 | */ | ||
3976 | static int done_command(struct parse_context *ctx) | 3985 | static int done_command(struct parse_context *ctx) |
3977 | { | 3986 | { |
3978 | /* The command is really already in the pipe structure, so | 3987 | /* The command is really already in the pipe structure, so |
@@ -3981,13 +3990,9 @@ static int done_command(struct parse_context *ctx) | |||
3981 | struct command *command = ctx->command; | 3990 | struct command *command = ctx->command; |
3982 | 3991 | ||
3983 | if (command) { | 3992 | if (command) { |
3984 | if (command->group == NULL | 3993 | if (IS_NULL_CMD(command)) { |
3985 | && command->argv == NULL | ||
3986 | && command->redirects == NULL | ||
3987 | ) { | ||
3988 | debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds); | 3994 | debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds); |
3989 | memset(command, 0, sizeof(*command)); /* paranoia */ | 3995 | goto clear_and_ret; |
3990 | return pi->num_cmds; | ||
3991 | } | 3996 | } |
3992 | pi->num_cmds++; | 3997 | pi->num_cmds++; |
3993 | debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds); | 3998 | debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds); |
@@ -3999,12 +4004,9 @@ static int done_command(struct parse_context *ctx) | |||
3999 | /* Only real trickiness here is that the uncommitted | 4004 | /* Only real trickiness here is that the uncommitted |
4000 | * command structure is not counted in pi->num_cmds. */ | 4005 | * command structure is not counted in pi->num_cmds. */ |
4001 | pi->cmds = xrealloc(pi->cmds, sizeof(*pi->cmds) * (pi->num_cmds+1)); | 4006 | pi->cmds = xrealloc(pi->cmds, sizeof(*pi->cmds) * (pi->num_cmds+1)); |
4002 | command = &pi->cmds[pi->num_cmds]; | 4007 | ctx->command = command = &pi->cmds[pi->num_cmds]; |
4008 | clear_and_ret: | ||
4003 | memset(command, 0, sizeof(*command)); | 4009 | memset(command, 0, sizeof(*command)); |
4004 | |||
4005 | ctx->command = command; | ||
4006 | /* but ctx->pipe and ctx->list_head remain unchanged */ | ||
4007 | |||
4008 | return pi->num_cmds; /* used only for 0/nonzero check */ | 4010 | return pi->num_cmds; /* used only for 0/nonzero check */ |
4009 | } | 4011 | } |
4010 | 4012 | ||
@@ -4024,9 +4026,7 @@ static void done_pipe(struct parse_context *ctx, pipe_style type) | |||
4024 | 4026 | ||
4025 | /* Without this check, even just <enter> on command line generates | 4027 | /* Without this check, even just <enter> on command line generates |
4026 | * tree of three NOPs (!). Which is harmless but annoying. | 4028 | * tree of three NOPs (!). Which is harmless but annoying. |
4027 | * IOW: it is safe to do it unconditionally. | 4029 | * IOW: it is safe to do it unconditionally. */ |
4028 | * RES_NONE case is for "for a in; do ..." (empty IN set) | ||
4029 | * and other cases to work. */ | ||
4030 | if (not_null | 4030 | if (not_null |
4031 | #if ENABLE_HUSH_IF | 4031 | #if ENABLE_HUSH_IF |
4032 | || ctx->ctx_res_w == RES_FI | 4032 | || ctx->ctx_res_w == RES_FI |
@@ -4048,7 +4048,7 @@ static void done_pipe(struct parse_context *ctx, pipe_style type) | |||
4048 | ctx->pipe->next = new_p; | 4048 | ctx->pipe->next = new_p; |
4049 | ctx->pipe = new_p; | 4049 | ctx->pipe = new_p; |
4050 | /* RES_THEN, RES_DO etc are "sticky" - | 4050 | /* RES_THEN, RES_DO etc are "sticky" - |
4051 | * they remain set for commands inside if/while. | 4051 | * they remain set for pipes inside if/while. |
4052 | * This is used to control execution. | 4052 | * This is used to control execution. |
4053 | * RES_FOR and RES_IN are NOT sticky (needed to support | 4053 | * RES_FOR and RES_IN are NOT sticky (needed to support |
4054 | * cases where variable or value happens to match a keyword): | 4054 | * cases where variable or value happens to match a keyword): |
@@ -4304,7 +4304,7 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
4304 | && ctx->ctx_res_w != RES_IN | 4304 | && ctx->ctx_res_w != RES_IN |
4305 | # endif | 4305 | # endif |
4306 | ) { | 4306 | ) { |
4307 | debug_printf_parse(": checking '%s' for reserved-ness\n", word->data); | 4307 | debug_printf_parse("checking '%s' for reserved-ness\n", word->data); |
4308 | if (reserved_word(word, ctx)) { | 4308 | if (reserved_word(word, ctx)) { |
4309 | o_reset_to_empty_unquoted(word); | 4309 | o_reset_to_empty_unquoted(word); |
4310 | debug_printf_parse("done_word return %d\n", | 4310 | debug_printf_parse("done_word return %d\n", |
@@ -4775,6 +4775,14 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
4775 | if (ch == '(') { | 4775 | if (ch == '(') { |
4776 | endch = ')'; | 4776 | endch = ')'; |
4777 | command->grp_type = GRP_SUBSHELL; | 4777 | command->grp_type = GRP_SUBSHELL; |
4778 | } else { | ||
4779 | /* bash does not allow "{echo...", requires whitespace */ | ||
4780 | ch = i_getch(input); | ||
4781 | if (ch != ' ' && ch != '\t' && ch != '\n') { | ||
4782 | syntax_error_unexpected_ch(ch); | ||
4783 | return 1; | ||
4784 | } | ||
4785 | nommu_addchr(&ctx->as_string, ch); | ||
4778 | } | 4786 | } |
4779 | 4787 | ||
4780 | { | 4788 | { |
@@ -5352,13 +5360,11 @@ static struct pipe *parse_stream(char **pstring, | |||
5352 | if (end_trigger && end_trigger == ch | 5360 | if (end_trigger && end_trigger == ch |
5353 | && (heredoc_cnt == 0 || end_trigger != ';') | 5361 | && (heredoc_cnt == 0 || end_trigger != ';') |
5354 | ) { | 5362 | ) { |
5355 | //TODO: disallow "{ cmd }" without semicolon | ||
5356 | if (heredoc_cnt) { | 5363 | if (heredoc_cnt) { |
5357 | /* This is technically valid: | 5364 | /* This is technically valid: |
5358 | * { cat <<HERE; }; echo Ok | 5365 | * { cat <<HERE; }; echo Ok |
5359 | * heredoc | 5366 | * heredoc |
5360 | * heredoc | 5367 | * heredoc |
5361 | * heredoc | ||
5362 | * HERE | 5368 | * HERE |
5363 | * but we don't support this. | 5369 | * but we don't support this. |
5364 | * We require heredoc to be in enclosing {}/(), | 5370 | * We require heredoc to be in enclosing {}/(), |
@@ -5370,6 +5376,15 @@ static struct pipe *parse_stream(char **pstring, | |||
5370 | if (done_word(&dest, &ctx)) { | 5376 | if (done_word(&dest, &ctx)) { |
5371 | goto parse_error; | 5377 | goto parse_error; |
5372 | } | 5378 | } |
5379 | /* Disallow "{ cmd }" without semicolon or & */ | ||
5380 | //debug_printf_parse("null pi %d\n", IS_NULL_PIPE(ctx.pipe)) | ||
5381 | //debug_printf_parse("null cmd %d\n", IS_NULL_CMD(ctx.command)) | ||
5382 | if (ch == '}' | ||
5383 | && !(IS_NULL_PIPE(ctx.pipe) && IS_NULL_CMD(ctx.command)) | ||
5384 | ) { | ||
5385 | syntax_error_unexpected_ch(ch); | ||
5386 | goto parse_error; | ||
5387 | } | ||
5373 | done_pipe(&ctx, PIPE_SEQ); | 5388 | done_pipe(&ctx, PIPE_SEQ); |
5374 | dest.o_assignment = MAYBE_ASSIGNMENT; | 5389 | dest.o_assignment = MAYBE_ASSIGNMENT; |
5375 | /* Do we sit outside of any if's, loops or case's? */ | 5390 | /* Do we sit outside of any if's, loops or case's? */ |