diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-11-15 19:58:19 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-11-15 19:58:19 +0100 |
commit | 647553a4fcbbc169b4390d9ef8e4657f0ffe1a5f (patch) | |
tree | 974dde9bc45566319f8b9750b6397fbafe94ad43 | |
parent | ff1822aed159e1c1b5a92dc5c1fd1648b026f8f4 (diff) | |
download | busybox-w32-647553a4fcbbc169b4390d9ef8e4657f0ffe1a5f.tar.gz busybox-w32-647553a4fcbbc169b4390d9ef8e4657f0ffe1a5f.tar.bz2 busybox-w32-647553a4fcbbc169b4390d9ef8e4657f0ffe1a5f.zip |
hush: wait for `cmd` to complete, and immediately store its exitcode in $?
function old new delta
expand_vars_to_list 2129 2197 +68
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/brace.txt | 50 | ||||
-rw-r--r-- | shell/hush.c | 36 | ||||
-rw-r--r-- | shell/hush_test/hush-psubst/tick5.right | 1 | ||||
-rwxr-xr-x | shell/hush_test/hush-psubst/tick5.tests | 1 |
4 files changed, 70 insertions, 18 deletions
diff --git a/shell/brace.txt b/shell/brace.txt new file mode 100644 index 000000000..664861b08 --- /dev/null +++ b/shell/brace.txt | |||
@@ -0,0 +1,50 @@ | |||
1 | Brace Expansion | ||
2 | |||
3 | Brace expansion is a mechanism by which arbitrary strings may be gener- | ||
4 | ated. This mechanism is similar to pathname expansion, but the file- | ||
5 | names generated need not exist. Patterns to be brace expanded take the | ||
6 | form of an optional preamble, followed by either a series of comma-sep- | ||
7 | arated strings or a sequence expression between a pair of braces, fol- | ||
8 | lowed by an optional postscript. The preamble is prefixed to each | ||
9 | string contained within the braces, and the postscript is then appended | ||
10 | to each resulting string, expanding left to right. | ||
11 | |||
12 | Brace expansions may be nested. The results of each expanded string | ||
13 | are not sorted; left to right order is preserved. For example, | ||
14 | a{d,c,b}e expands into `ade ace abe'. | ||
15 | |||
16 | A sequence expression takes the form {x..y}, where x and y are either | ||
17 | integers or single characters. When integers are supplied, the expres- | ||
18 | sion expands to each number between x and y, inclusive. When charac- | ||
19 | ters are supplied, the expression expands to each character lexico- | ||
20 | graphically between x and y, inclusive. Note that both x and y must be | ||
21 | of the same type. | ||
22 | |||
23 | Brace expansion is performed before any other expansions, and any char- | ||
24 | acters special to other expansions are preserved in the result. It is | ||
25 | strictly textual. Bash does not apply any syntactic interpretation to | ||
26 | the context of the expansion or the text between the braces. | ||
27 | |||
28 | A correctly-formed brace expansion must contain unquoted opening and | ||
29 | closing braces, and at least one unquoted comma or a valid sequence | ||
30 | expression. Any incorrectly formed brace expansion is left unchanged. | ||
31 | A { or , may be quoted with a backslash to prevent its being considered | ||
32 | part of a brace expression. To avoid conflicts with parameter expan- | ||
33 | sion, the string ${ is not considered eligible for brace expansion. | ||
34 | |||
35 | This construct is typically used as shorthand when the common prefix of | ||
36 | the strings to be generated is longer than in the above example: | ||
37 | |||
38 | mkdir /usr/local/src/bash/{old,new,dist,bugs} | ||
39 | or | ||
40 | chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}} | ||
41 | |||
42 | Brace expansion introduces a slight incompatibility with historical | ||
43 | versions of sh. sh does not treat opening or closing braces specially | ||
44 | when they appear as part of a word, and preserves them in the output. | ||
45 | Bash removes braces from words as a consequence of brace expansion. | ||
46 | For example, a word entered to sh as file{1,2} appears identically in | ||
47 | the output. The same word is output as file1 file2 after expansion by | ||
48 | bash. If strict compatibility with sh is desired, start bash with the | ||
49 | +B option or disable brace expansion with the +B option to the set com- | ||
50 | mand | ||
diff --git a/shell/hush.c b/shell/hush.c index 891d87be7..6f394d1d5 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -2287,7 +2287,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
2287 | * expanded result may need to be globbed | 2287 | * expanded result may need to be globbed |
2288 | * and $IFS-splitted */ | 2288 | * and $IFS-splitted */ |
2289 | debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch); | 2289 | debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch); |
2290 | process_command_subs(&subst_result, arg); | 2290 | G.last_exitcode = process_command_subs(&subst_result, arg); |
2291 | debug_printf_subst("SUBST RES '%s'\n", subst_result.data); | 2291 | debug_printf_subst("SUBST RES '%s'\n", subst_result.data); |
2292 | val = subst_result.data; | 2292 | val = subst_result.data; |
2293 | goto store_val; | 2293 | goto store_val; |
@@ -3904,7 +3904,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
3904 | /* if someone gives us an empty string: `cmd with empty output` */ | 3904 | /* if someone gives us an empty string: `cmd with empty output` */ |
3905 | if (!argv_expanded[0]) { | 3905 | if (!argv_expanded[0]) { |
3906 | debug_leave(); | 3906 | debug_leave(); |
3907 | return 0; | 3907 | return 0; // or G.last_exitcode? see emptytick.tests |
3908 | } | 3908 | } |
3909 | 3909 | ||
3910 | x = find_builtin(argv_expanded[0]); | 3910 | x = find_builtin(argv_expanded[0]); |
@@ -5202,10 +5202,10 @@ static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_ | |||
5202 | 5202 | ||
5203 | 5203 | ||
5204 | #if ENABLE_HUSH_TICK | 5204 | #if ENABLE_HUSH_TICK |
5205 | static FILE *generate_stream_from_string(const char *s) | 5205 | static FILE *generate_stream_from_string(const char *s, pid_t *pid_p) |
5206 | { | 5206 | { |
5207 | FILE *pf; | 5207 | pid_t pid; |
5208 | int pid, channel[2]; | 5208 | int channel[2]; |
5209 | # if !BB_MMU | 5209 | # if !BB_MMU |
5210 | char **to_free; | 5210 | char **to_free; |
5211 | # endif | 5211 | # endif |
@@ -5291,6 +5291,7 @@ static FILE *generate_stream_from_string(const char *s) | |||
5291 | } | 5291 | } |
5292 | 5292 | ||
5293 | /* parent */ | 5293 | /* parent */ |
5294 | *pid_p = pid; | ||
5294 | # if ENABLE_HUSH_FAST | 5295 | # if ENABLE_HUSH_FAST |
5295 | G.count_SIGCHLD++; | 5296 | G.count_SIGCHLD++; |
5296 | //bb_error_msg("[%d] fork in generate_stream_from_string: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); | 5297 | //bb_error_msg("[%d] fork in generate_stream_from_string: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); |
@@ -5300,8 +5301,8 @@ static FILE *generate_stream_from_string(const char *s) | |||
5300 | free(to_free); | 5301 | free(to_free); |
5301 | # endif | 5302 | # endif |
5302 | close(channel[1]); | 5303 | close(channel[1]); |
5303 | pf = fdopen(channel[0], "r"); | 5304 | //TODO: libbb: fdopen_or_die? |
5304 | return pf; | 5305 | return fdopen(channel[0], "r"); |
5305 | } | 5306 | } |
5306 | 5307 | ||
5307 | /* Return code is exit status of the process that is run. */ | 5308 | /* Return code is exit status of the process that is run. */ |
@@ -5309,9 +5310,10 @@ static int process_command_subs(o_string *dest, const char *s) | |||
5309 | { | 5310 | { |
5310 | FILE *pf; | 5311 | FILE *pf; |
5311 | struct in_str pipe_str; | 5312 | struct in_str pipe_str; |
5312 | int ch, eol_cnt; | 5313 | pid_t pid; |
5314 | int status, ch, eol_cnt; | ||
5313 | 5315 | ||
5314 | pf = generate_stream_from_string(s); | 5316 | pf = generate_stream_from_string(s, &pid); |
5315 | if (pf == NULL) | 5317 | if (pf == NULL) |
5316 | return 1; | 5318 | return 1; |
5317 | close_on_exec_on(fileno(pf)); | 5319 | close_on_exec_on(fileno(pf)); |
@@ -5331,16 +5333,14 @@ static int process_command_subs(o_string *dest, const char *s) | |||
5331 | o_addQchr(dest, ch); | 5333 | o_addQchr(dest, ch); |
5332 | } | 5334 | } |
5333 | 5335 | ||
5334 | debug_printf("done reading from pipe, pclose()ing\n"); | 5336 | debug_printf("done reading from `cmd` pipe, closing it\n"); |
5335 | /* Note: we got EOF, and we just close the read end of the pipe. | ||
5336 | * We do not wait for the `cmd` child to terminate. bash and ash do. | ||
5337 | * Try these: | ||
5338 | * echo `echo Hi; exec 1>&-; sleep 2` - bash waits 2 sec | ||
5339 | * `false`; echo $? - bash outputs "1" | ||
5340 | */ | ||
5341 | fclose(pf); | 5337 | fclose(pf); |
5342 | debug_printf("closed FILE from child. return 0\n"); | 5338 | /* We need to extract exitcode. Test case |
5343 | return 0; | 5339 | * "true; echo `sleep 1; false` $?" |
5340 | * should print 1 */ | ||
5341 | safe_waitpid(pid, &status, 0); | ||
5342 | debug_printf("child exited. returning its exitcode:%d\n", WEXITSTATUS(status)); | ||
5343 | return WEXITSTATUS(status); | ||
5344 | } | 5344 | } |
5345 | #endif /* ENABLE_HUSH_TICK */ | 5345 | #endif /* ENABLE_HUSH_TICK */ |
5346 | 5346 | ||
diff --git a/shell/hush_test/hush-psubst/tick5.right b/shell/hush_test/hush-psubst/tick5.right new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/shell/hush_test/hush-psubst/tick5.right | |||
@@ -0,0 +1 @@ | |||
1 | |||
diff --git a/shell/hush_test/hush-psubst/tick5.tests b/shell/hush_test/hush-psubst/tick5.tests new file mode 100755 index 000000000..bd160c9fc --- /dev/null +++ b/shell/hush_test/hush-psubst/tick5.tests | |||
@@ -0,0 +1 @@ | |||
true; echo `false` $? | |||