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 | |
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
-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 | ||