diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-06-18 16:29:32 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-06-18 16:29:32 +0000 |
| commit | ab876cd107fe6ca274f58bae3264396745d8e5f9 (patch) | |
| tree | c94ecba9c7d10af007294333e9b4c80efe079cfb /shell | |
| parent | 985de15bf3f39b5e32e34cadaf6947708197f018 (diff) | |
| download | busybox-w32-ab876cd107fe6ca274f58bae3264396745d8e5f9.tar.gz busybox-w32-ab876cd107fe6ca274f58bae3264396745d8e5f9.tar.bz2 busybox-w32-ab876cd107fe6ca274f58bae3264396745d8e5f9.zip | |
hush: add testsuite for "no globbing in redirection" rule.
simplify redirection habdling
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/hush.c | 69 | ||||
| -rw-r--r-- | shell/hush_test/hush-glob/glob_redir.right | 2 | ||||
| -rwxr-xr-x | shell/hush_test/hush-glob/glob_redir.tests | 9 | ||||
| -rw-r--r-- | shell/hush_test/hush-parsing/escape3.right | 23 | ||||
| -rwxr-xr-x | shell/hush_test/hush-parsing/escape3.tests | 8 | ||||
| -rw-r--r-- | shell/hush_test/hush-parsing/redir_space.right | 3 | ||||
| -rwxr-xr-x | shell/hush_test/hush-parsing/redir_space.tests | 6 |
7 files changed, 75 insertions, 45 deletions
diff --git a/shell/hush.c b/shell/hush.c index cb289769e..f81203e2b 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -287,7 +287,7 @@ struct redir_struct { | |||
| 287 | redir_type type; /* type of redirection */ | 287 | redir_type type; /* type of redirection */ |
| 288 | int fd; /* file descriptor being redirected */ | 288 | int fd; /* file descriptor being redirected */ |
| 289 | int dup; /* -1, or file descriptor being duplicated */ | 289 | int dup; /* -1, or file descriptor being duplicated */ |
| 290 | char **glob_word; /* *word.gl_pathv is the filename */ | 290 | char *rd_filename; /* filename */ |
| 291 | }; | 291 | }; |
| 292 | 292 | ||
| 293 | struct child_prog { | 293 | struct child_prog { |
| @@ -1304,14 +1304,14 @@ static int setup_redirects(struct child_prog *prog, int squirrel[]) | |||
| 1304 | struct redir_struct *redir; | 1304 | struct redir_struct *redir; |
| 1305 | 1305 | ||
| 1306 | for (redir = prog->redirects; redir; redir = redir->next) { | 1306 | for (redir = prog->redirects; redir; redir = redir->next) { |
| 1307 | if (redir->dup == -1 && redir->glob_word == NULL) { | 1307 | if (redir->dup == -1 && redir->rd_filename == NULL) { |
| 1308 | /* something went wrong in the parse. Pretend it didn't happen */ | 1308 | /* something went wrong in the parse. Pretend it didn't happen */ |
| 1309 | continue; | 1309 | continue; |
| 1310 | } | 1310 | } |
| 1311 | if (redir->dup == -1) { | 1311 | if (redir->dup == -1) { |
| 1312 | char *p; | 1312 | char *p; |
| 1313 | mode = redir_table[redir->type].mode; | 1313 | mode = redir_table[redir->type].mode; |
| 1314 | p = expand_string_to_string(redir->glob_word[0]); | 1314 | p = expand_string_to_string(redir->rd_filename); |
| 1315 | openfd = open_or_warn(p, mode); | 1315 | openfd = open_or_warn(p, mode); |
| 1316 | free(p); | 1316 | free(p); |
| 1317 | if (openfd < 0) { | 1317 | if (openfd < 0) { |
| @@ -2227,10 +2227,10 @@ static int free_pipe(struct pipe *pi, int indent) | |||
| 2227 | debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->type].descrip); | 2227 | debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->type].descrip); |
| 2228 | if (r->dup == -1) { | 2228 | if (r->dup == -1) { |
| 2229 | /* guard against the case >$FOO, where foo is unset or blank */ | 2229 | /* guard against the case >$FOO, where foo is unset or blank */ |
| 2230 | if (r->glob_word) { | 2230 | if (r->rd_filename) { |
| 2231 | debug_printf_clean(" %s\n", r->glob_word[0]); | 2231 | debug_printf_clean(" %s\n", r->rd_filename); |
| 2232 | free_strings(r->glob_word); | 2232 | free(r->rd_filename); |
| 2233 | r->glob_word = NULL; | 2233 | r->rd_filename = NULL; |
| 2234 | } | 2234 | } |
| 2235 | } else { | 2235 | } else { |
| 2236 | debug_printf_clean("&%d\n", r->dup); | 2236 | debug_printf_clean("&%d\n", r->dup); |
| @@ -2680,7 +2680,7 @@ static int setup_redirect(struct p_context *ctx, int fd, redir_type style, | |||
| 2680 | } | 2680 | } |
| 2681 | redir = xzalloc(sizeof(struct redir_struct)); | 2681 | redir = xzalloc(sizeof(struct redir_struct)); |
| 2682 | /* redir->next = NULL; */ | 2682 | /* redir->next = NULL; */ |
| 2683 | /* redir->glob_word = NULL; */ | 2683 | /* redir->rd_filename = NULL; */ |
| 2684 | if (last_redir) { | 2684 | if (last_redir) { |
| 2685 | last_redir->next = redir; | 2685 | last_redir->next = redir; |
| 2686 | } else { | 2686 | } else { |
| @@ -2857,17 +2857,17 @@ static int reserved_word(const o_string *word, struct p_context *ctx) | |||
| 2857 | static int done_word(o_string *word, struct p_context *ctx) | 2857 | static int done_word(o_string *word, struct p_context *ctx) |
| 2858 | { | 2858 | { |
| 2859 | struct child_prog *child = ctx->child; | 2859 | struct child_prog *child = ctx->child; |
| 2860 | char ***glob_target; | ||
| 2861 | 2860 | ||
| 2862 | debug_printf_parse("done_word entered: '%s' %p\n", word->data, child); | 2861 | debug_printf_parse("done_word entered: '%s' %p\n", word->data, child); |
| 2863 | if (word->length == 0) { | 2862 | if (word->length == 0 && word->nonnull == 0) { |
| 2864 | if (!word->nonnull) { | 2863 | debug_printf_parse("done_word return 0: true null, ignored\n"); |
| 2865 | debug_printf_parse("done_word return 0: true null, ignored\n"); | 2864 | return 0; |
| 2866 | return 0; | ||
| 2867 | } | ||
| 2868 | } | 2865 | } |
| 2869 | if (ctx->pending_redirect) { | 2866 | if (ctx->pending_redirect) { |
| 2870 | glob_target = &ctx->pending_redirect->glob_word; | 2867 | /* We do not glob in e.g. >*.tmp case. bash seems to glob here |
| 2868 | * only if run as "bash", not "sh" */ | ||
| 2869 | ctx->pending_redirect->rd_filename = xstrdup(word->data); | ||
| 2870 | debug_printf("word stored in rd_filename: '%s'\n", word->data); | ||
| 2871 | } else { | 2871 | } else { |
| 2872 | if (child->group) { /* TODO: example how to trigger? */ | 2872 | if (child->group) { /* TODO: example how to trigger? */ |
| 2873 | syntax(NULL); | 2873 | syntax(NULL); |
| @@ -2882,46 +2882,25 @@ static int done_word(o_string *word, struct p_context *ctx) | |||
| 2882 | return (ctx->res_w == RES_SNTX); | 2882 | return (ctx->res_w == RES_SNTX); |
| 2883 | } | 2883 | } |
| 2884 | } | 2884 | } |
| 2885 | if (word->nonnull) { | 2885 | if (word->nonnull |
| 2886 | /* && word->data[0] != */ | ||
| 2887 | ) { | ||
| 2886 | /* Insert "empty variable" reference, this makes e.g. "", '', | 2888 | /* Insert "empty variable" reference, this makes e.g. "", '', |
| 2887 | * $empty"" etc to not disappear */ | 2889 | * $empty"" etc to not disappear */ |
| 2888 | o_addchr(word, SPECIAL_VAR_SYMBOL); | 2890 | o_addchr(word, SPECIAL_VAR_SYMBOL); |
| 2889 | o_addchr(word, SPECIAL_VAR_SYMBOL); | 2891 | o_addchr(word, SPECIAL_VAR_SYMBOL); |
| 2890 | } | 2892 | } |
| 2891 | glob_target = &child->argv; | 2893 | child->argv = add_malloced_string_to_strings(child->argv, xstrdup(word->data)); |
| 2892 | } | 2894 | debug_print_strings("word appended to argv", child->argv); |
| 2893 | |||
| 2894 | //FIXME: we had globbing here, but now it's moved! Do we glob in e.g. ">*.tmp" now!? | ||
| 2895 | |||
| 2896 | /*if (word->length || word->nonnull) - true */ { | ||
| 2897 | *glob_target = add_malloced_string_to_strings(*glob_target, xstrdup(word->data)); | ||
| 2898 | debug_print_strings("glob_target appended", *glob_target); | ||
| 2899 | } | 2895 | } |
| 2900 | 2896 | ||
| 2901 | o_reset(word); | 2897 | o_reset(word); |
| 2902 | if (ctx->pending_redirect) { | 2898 | ctx->pending_redirect = NULL; |
| 2903 | /* NB: don't free_strings(ctx->pending_redirect->glob_word) here */ | 2899 | |
| 2904 | if (ctx->pending_redirect->glob_word | ||
| 2905 | && ctx->pending_redirect->glob_word[0] | ||
| 2906 | && ctx->pending_redirect->glob_word[1] | ||
| 2907 | ) { | ||
| 2908 | /* more than one word resulted from globbing redir */ | ||
| 2909 | ctx->pending_redirect = NULL; | ||
| 2910 | bb_error_msg("ambiguous redirect"); | ||
| 2911 | debug_printf_parse("done_word return 1: ambiguous redirect\n"); | ||
| 2912 | return 1; | ||
| 2913 | } | ||
| 2914 | ctx->pending_redirect = NULL; | ||
| 2915 | } | ||
| 2916 | #if ENABLE_HUSH_LOOPS | 2900 | #if ENABLE_HUSH_LOOPS |
| 2917 | /* comment? is it forcing "for" to have just one word (variable name)? */ | 2901 | /* Force FOR to have just one word (variable name) */ |
| 2918 | if (ctx->res_w == RES_FOR) { | 2902 | if (ctx->res_w == RES_FOR) |
| 2919 | //TESTING | ||
| 2920 | //looks like (word->length == 0 && !word->nonnull) is true here, always | ||
| 2921 | //(due to o_reset). done_word would return at once. Why then? | ||
| 2922 | // done_word(word, ctx); | ||
| 2923 | done_pipe(ctx, PIPE_SEQ); | 2903 | done_pipe(ctx, PIPE_SEQ); |
| 2924 | } | ||
| 2925 | #endif | 2904 | #endif |
| 2926 | debug_printf_parse("done_word return 0\n"); | 2905 | debug_printf_parse("done_word return 0\n"); |
| 2927 | return 0; | 2906 | return 0; |
diff --git a/shell/hush_test/hush-glob/glob_redir.right b/shell/hush_test/hush-glob/glob_redir.right new file mode 100644 index 000000000..fbd0309b0 --- /dev/null +++ b/shell/hush_test/hush-glob/glob_redir.right | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | z.tmp: | ||
| 2 | ?.tmp: TEST | ||
diff --git a/shell/hush_test/hush-glob/glob_redir.tests b/shell/hush_test/hush-glob/glob_redir.tests new file mode 100755 index 000000000..621d12017 --- /dev/null +++ b/shell/hush_test/hush-glob/glob_redir.tests | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | # Redirections are not globbed. | ||
| 2 | # bash: | ||
| 3 | # if run as "sh", they are not globbed, but | ||
| 4 | # if run as "bash", they are! | ||
| 5 | >z.tmp | ||
| 6 | echo TEST >?.tmp | ||
| 7 | echo 'z.tmp:' `cat 'z.tmp'` | ||
| 8 | echo '?.tmp:' `cat '?.tmp'` | ||
| 9 | rm 'z.tmp' '?.tmp' | ||
diff --git a/shell/hush_test/hush-parsing/escape3.right b/shell/hush_test/hush-parsing/escape3.right new file mode 100644 index 000000000..da02a976a --- /dev/null +++ b/shell/hush_test/hush-parsing/escape3.right | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | v: a \ b \\ c \\\ d \\\\ e | ||
| 2 | v: a \ b \\ c \\\ d \\\\ e | ||
| 3 | Unquoted: | ||
| 4 | .a. | ||
| 5 | .\. | ||
| 6 | .b. | ||
| 7 | .\\. | ||
| 8 | .c. | ||
| 9 | .\\\. | ||
| 10 | .d. | ||
| 11 | .\\\\. | ||
| 12 | .e. | ||
| 13 | Quoted: | ||
| 14 | .a. | ||
| 15 | .\. | ||
| 16 | .b. | ||
| 17 | .\\. | ||
| 18 | .c. | ||
| 19 | .\\\. | ||
| 20 | .d. | ||
| 21 | .\\\\. | ||
| 22 | .e. | ||
| 23 | done | ||
diff --git a/shell/hush_test/hush-parsing/escape3.tests b/shell/hush_test/hush-parsing/escape3.tests new file mode 100755 index 000000000..111ed40a2 --- /dev/null +++ b/shell/hush_test/hush-parsing/escape3.tests | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | v='a \ b \\ c \\\ d \\\\ e' | ||
| 2 | echo v: $v | ||
| 3 | echo v: "$v" | ||
| 4 | echo Unquoted: | ||
| 5 | for a in $v; do echo .$a.; done | ||
| 6 | echo Quoted: | ||
| 7 | for a in $v; do echo ".$a."; done | ||
| 8 | echo done | ||
diff --git a/shell/hush_test/hush-parsing/redir_space.right b/shell/hush_test/hush-parsing/redir_space.right new file mode 100644 index 000000000..084295204 --- /dev/null +++ b/shell/hush_test/hush-parsing/redir_space.right | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | z1.tmp: 1 | ||
| 2 | z2.tmp: 1 | ||
| 3 | "z1.tmp z2.tmp": TEST 0 | ||
diff --git a/shell/hush_test/hush-parsing/redir_space.tests b/shell/hush_test/hush-parsing/redir_space.tests new file mode 100755 index 000000000..c0b543098 --- /dev/null +++ b/shell/hush_test/hush-parsing/redir_space.tests | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | v='z1.tmp z2.tmp' | ||
| 2 | echo TEST >$v | ||
| 3 | echo 'z1.tmp:' `cat 'z1.tmp' 2>/dev/null; echo $?` | ||
| 4 | echo 'z2.tmp:' `cat 'z2.tmp' 2>/dev/null; echo $?` | ||
| 5 | echo '"z1.tmp z2.tmp":' `cat 'z1.tmp z2.tmp' 2>/dev/null; echo $?` | ||
| 6 | rm z*.tmp | ||
