diff options
-rw-r--r-- | shell/hush.c | 43 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/empty_args.right | 6 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/empty_args.tests | 9 | ||||
-rw-r--r-- | shell/hush_test/hush-psubst/emptytick.right | 7 | ||||
-rwxr-xr-x | shell/hush_test/hush-psubst/emptytick.tests | 8 |
5 files changed, 58 insertions, 15 deletions
diff --git a/shell/hush.c b/shell/hush.c index 1d2826d9a..46bb7e9a2 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -2185,7 +2185,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
2185 | 2185 | ||
2186 | ored_ch = 0; | 2186 | ored_ch = 0; |
2187 | 2187 | ||
2188 | debug_printf_expand("expand_vars_to_list: arg '%s'\n", arg); | 2188 | debug_printf_expand("expand_vars_to_list: arg:'%s' or_mask:%x\n", arg, or_mask); |
2189 | debug_print_list("expand_vars_to_list", output, n); | 2189 | debug_print_list("expand_vars_to_list", output, n); |
2190 | n = o_save_ptr(output, n); | 2190 | n = o_save_ptr(output, n); |
2191 | debug_print_list("expand_vars_to_list[0]", output, n); | 2191 | debug_print_list("expand_vars_to_list[0]", output, n); |
@@ -3425,7 +3425,7 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
3425 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); | 3425 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); |
3426 | execvp(argv[0], argv); | 3426 | execvp(argv[0], argv); |
3427 | bb_perror_msg("can't execute '%s'", argv[0]); | 3427 | bb_perror_msg("can't execute '%s'", argv[0]); |
3428 | _exit(EXIT_FAILURE); | 3428 | _exit(127); /* bash compat */ |
3429 | } | 3429 | } |
3430 | 3430 | ||
3431 | /* Called after [v]fork() in run_pipe | 3431 | /* Called after [v]fork() in run_pipe |
@@ -3895,7 +3895,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
3895 | argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); | 3895 | argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); |
3896 | } | 3896 | } |
3897 | 3897 | ||
3898 | /* if someone gives us an empty string: ``, $(), ... */ | 3898 | /* if someone gives us an empty string: `cmd with empty output` */ |
3899 | if (!argv_expanded[0]) { | 3899 | if (!argv_expanded[0]) { |
3900 | debug_leave(); | 3900 | debug_leave(); |
3901 | return 0; | 3901 | return 0; |
@@ -5802,7 +5802,7 @@ static int parse_stream_dquoted(o_string *as_string, | |||
5802 | if (ch != '\n') { | 5802 | if (ch != '\n') { |
5803 | next = i_peek(input); | 5803 | next = i_peek(input); |
5804 | } | 5804 | } |
5805 | debug_printf_parse(": ch=%c (%d) escape=%d\n", | 5805 | debug_printf_parse("\" ch=%c (%d) escape=%d\n", |
5806 | ch, ch, dest->o_escape); | 5806 | ch, ch, dest->o_escape); |
5807 | if (ch == '\\') { | 5807 | if (ch == '\\') { |
5808 | if (next == EOF) { | 5808 | if (next == EOF) { |
@@ -5882,6 +5882,11 @@ static struct pipe *parse_stream(char **pstring, | |||
5882 | end_trigger ? end_trigger : 'X'); | 5882 | end_trigger ? end_trigger : 'X'); |
5883 | debug_enter(); | 5883 | debug_enter(); |
5884 | 5884 | ||
5885 | /* If very first arg is "" or '', dest.data may end up NULL. | ||
5886 | * Preventing this: */ | ||
5887 | o_addchr(&dest, '\0'); | ||
5888 | dest.length = 0; | ||
5889 | |||
5885 | G.ifs = get_local_var_value("IFS"); | 5890 | G.ifs = get_local_var_value("IFS"); |
5886 | if (G.ifs == NULL) | 5891 | if (G.ifs == NULL) |
5887 | G.ifs = " \t\n"; | 5892 | G.ifs = " \t\n"; |
@@ -6979,16 +6984,32 @@ static int FAST_FUNC builtin_cd(char **argv) | |||
6979 | 6984 | ||
6980 | static int FAST_FUNC builtin_exec(char **argv) | 6985 | static int FAST_FUNC builtin_exec(char **argv) |
6981 | { | 6986 | { |
6982 | if (*++argv == NULL) | 6987 | static const char pseudo_null_str[] = { SPECIAL_VAR_SYMBOL, SPECIAL_VAR_SYMBOL, '\0' }; |
6983 | return EXIT_SUCCESS; /* bash does this */ | 6988 | char **pp = argv; |
6984 | { | ||
6985 | #if !BB_MMU | 6989 | #if !BB_MMU |
6986 | nommu_save_t dummy; | 6990 | nommu_save_t dummy; |
6987 | #endif | 6991 | #endif |
6988 | /* TODO: if exec fails, bash does NOT exit! We do... */ | 6992 | |
6989 | pseudo_exec_argv(&dummy, argv, 0, NULL); | 6993 | if (*++argv == NULL) |
6990 | /* never returns */ | 6994 | return EXIT_SUCCESS; /* bash does this */ |
6995 | |||
6996 | /* Make sure empty arguments aren't ignored */ | ||
6997 | /* Example: exec ls '' */ | ||
6998 | pp = argv; | ||
6999 | while (*pp) { | ||
7000 | if ((*pp)[0] == '\0') | ||
7001 | *pp = (char*)pseudo_null_str; | ||
7002 | pp++; | ||
6991 | } | 7003 | } |
7004 | |||
7005 | /* Careful: we can end up here after [v]fork. Do not restore | ||
7006 | * tty pgrp then, only top-level shell process does that */ | ||
7007 | if (G_saved_tty_pgrp && getpid() == G.root_pid) | ||
7008 | tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp); | ||
7009 | |||
7010 | /* TODO: if exec fails, bash does NOT exit! We do... */ | ||
7011 | pseudo_exec_argv(&dummy, argv, 0, NULL); | ||
7012 | /* never returns */ | ||
6992 | } | 7013 | } |
6993 | 7014 | ||
6994 | static int FAST_FUNC builtin_exit(char **argv) | 7015 | static int FAST_FUNC builtin_exit(char **argv) |
diff --git a/shell/hush_test/hush-misc/empty_args.right b/shell/hush_test/hush-misc/empty_args.right new file mode 100644 index 000000000..38ed8b8be --- /dev/null +++ b/shell/hush_test/hush-misc/empty_args.right | |||
@@ -0,0 +1,6 @@ | |||
1 | Null 0th arg: | ||
2 | hush: can't execute '': No such file or directory | ||
3 | 127 | ||
4 | Null 1st arg: | ||
5 | 0 | ||
6 | Null arg in exec: | ||
diff --git a/shell/hush_test/hush-misc/empty_args.tests b/shell/hush_test/hush-misc/empty_args.tests new file mode 100755 index 000000000..efce5494a --- /dev/null +++ b/shell/hush_test/hush-misc/empty_args.tests | |||
@@ -0,0 +1,9 @@ | |||
1 | echo Null 0th arg: | ||
2 | "" | ||
3 | echo $? | ||
4 | echo Null 1st arg: | ||
5 | # printf without args would print usage info | ||
6 | printf "" | ||
7 | echo $? | ||
8 | echo Null arg in exec: | ||
9 | exec printf "" | ||
diff --git a/shell/hush_test/hush-psubst/emptytick.right b/shell/hush_test/hush-psubst/emptytick.right index d4b70c58a..1f60ecfda 100644 --- a/shell/hush_test/hush-psubst/emptytick.right +++ b/shell/hush_test/hush-psubst/emptytick.right | |||
@@ -1,14 +1,17 @@ | |||
1 | 0 | 1 | 0 |
2 | 0 | 2 | 0 |
3 | hush: can't execute '': No such file or directory | ||
3 | 0 | 4 | 0 |
5 | hush: can't execute '': No such file or directory | ||
4 | 0 | 6 | 0 |
5 | 0 | 7 | 0 |
6 | 0 | 8 | 0 |
7 | 0 | 9 | 0 |
8 | 0 | 10 | 0 |
11 | hush: can't execute '': No such file or directory | ||
9 | 0 | 12 | 0 |
13 | hush: can't execute '': No such file or directory | ||
10 | 0 | 14 | 0 |
11 | 0 | 15 | 0 |
12 | 0 | 16 | 0 |
13 | 0 | 17 | hush: can't execute '': No such file or directory |
14 | 0 | ||
diff --git a/shell/hush_test/hush-psubst/emptytick.tests b/shell/hush_test/hush-psubst/emptytick.tests index af3a1836c..a269f025a 100755 --- a/shell/hush_test/hush-psubst/emptytick.tests +++ b/shell/hush_test/hush-psubst/emptytick.tests | |||
@@ -1,16 +1,20 @@ | |||
1 | true; ``; echo $? | 1 | true; ``; echo $? |
2 | false; ``; echo $? | 2 | false; ``; echo $? |
3 | # UNFIXED BUG. bash sets $? to 127: | ||
3 | true; `""`; echo $? | 4 | true; `""`; echo $? |
5 | # bash sets $? to 127: | ||
4 | false; `""`; echo $? | 6 | false; `""`; echo $? |
5 | true; ` `; echo $? | 7 | true; ` `; echo $? |
6 | false; ` `; echo $? | 8 | false; ` `; echo $? |
7 | 9 | ||
8 | true; $(); echo $? | 10 | true; $(); echo $? |
9 | false; $(); echo $? | 11 | false; $(); echo $? |
12 | # bash sets $? to 127: | ||
10 | true; $(""); echo $? | 13 | true; $(""); echo $? |
14 | # bash sets $? to 127: | ||
11 | false; $(""); echo $? | 15 | false; $(""); echo $? |
12 | true; $( ); echo $? | 16 | true; $( ); echo $? |
13 | false; $( ); echo $? | 17 | false; $( ); echo $? |
14 | 18 | ||
15 | true; exec ''; echo $? | 19 | exec ''; echo $? |
16 | false; exec ''; echo $? | 20 | echo Not reached |