diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 86 |
1 files changed, 57 insertions, 29 deletions
diff --git a/shell/hush.c b/shell/hush.c index 6b6ec7c6b..04dda0734 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -1022,6 +1022,13 @@ struct globals { | |||
1022 | #if HUSH_DEBUG >= 2 | 1022 | #if HUSH_DEBUG >= 2 |
1023 | int debug_indent; | 1023 | int debug_indent; |
1024 | #endif | 1024 | #endif |
1025 | #if ENABLE_HUSH_TEST || BASH_TEST2 | ||
1026 | /* Cached supplementary group array (for testing executable'ity of files) */ | ||
1027 | struct cached_groupinfo groupinfo; | ||
1028 | # define GROUPINFO_INIT { G.groupinfo.euid = -1; G.groupinfo.egid = -1; } | ||
1029 | #else | ||
1030 | # define GROUPINFO_INIT /* nothing */ | ||
1031 | #endif | ||
1025 | struct sigaction sa; | 1032 | struct sigaction sa; |
1026 | char optstring_buf[sizeof("eixcs")]; | 1033 | char optstring_buf[sizeof("eixcs")]; |
1027 | #if BASH_EPOCH_VARS | 1034 | #if BASH_EPOCH_VARS |
@@ -1040,6 +1047,7 @@ struct globals { | |||
1040 | /* memset(&G.sa, 0, sizeof(G.sa)); */ \ | 1047 | /* memset(&G.sa, 0, sizeof(G.sa)); */ \ |
1041 | sigfillset(&G.sa.sa_mask); \ | 1048 | sigfillset(&G.sa.sa_mask); \ |
1042 | G.sa.sa_flags = SA_RESTART; \ | 1049 | G.sa.sa_flags = SA_RESTART; \ |
1050 | GROUPINFO_INIT; \ | ||
1043 | } while (0) | 1051 | } while (0) |
1044 | 1052 | ||
1045 | /* Function prototypes for builtins */ | 1053 | /* Function prototypes for builtins */ |
@@ -8193,38 +8201,53 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp) | |||
8193 | return 0; | 8201 | return 0; |
8194 | } | 8202 | } |
8195 | 8203 | ||
8196 | static char *find_in_path(const char *arg) | 8204 | /* Find a file in PATH, not necessarily executable |
8205 | * Name is known to not contain '/'. | ||
8206 | */ | ||
8207 | //TODO: shares code with find_executable() in libbb, factor out? | ||
8208 | static char *find_in_PATH(const char *name) | ||
8197 | { | 8209 | { |
8198 | char *ret = NULL; | 8210 | char *p = (char*) get_local_var_value("PATH"); |
8199 | const char *PATH = get_local_var_value("PATH"); | ||
8200 | 8211 | ||
8201 | if (!PATH) | 8212 | if (!p) |
8202 | return NULL; | 8213 | return NULL; |
8203 | |||
8204 | while (1) { | 8214 | while (1) { |
8205 | const char *end = strchrnul(PATH, ':'); | 8215 | const char *end = strchrnul(p, ':'); |
8206 | int sz = end - PATH; /* must be int! */ | 8216 | int sz = end - p; /* must be int! */ |
8207 | 8217 | ||
8208 | free(ret); | ||
8209 | if (sz != 0) { | 8218 | if (sz != 0) { |
8210 | ret = xasprintf("%.*s/%s", sz, PATH, arg); | 8219 | p = xasprintf("%.*s/%s", sz, p, name); |
8211 | } else { | 8220 | } else { |
8212 | /* We have xxx::yyyy in $PATH, | 8221 | /* We have xxx::yyy in $PATH, |
8213 | * it means "use current dir" */ | 8222 | * it means "use current dir" */ |
8214 | ret = xstrdup(arg); | 8223 | p = xstrdup(name); |
8215 | } | 8224 | } |
8216 | if (access(ret, F_OK) == 0) | 8225 | if (access(p, F_OK) == 0) |
8217 | break; | 8226 | return p; |
8218 | 8227 | free(p); | |
8219 | if (*end == '\0') { | 8228 | if (*end == '\0') |
8220 | free(ret); | ||
8221 | return NULL; | 8229 | return NULL; |
8222 | } | 8230 | p = (char *) end + 1; |
8223 | PATH = end + 1; | ||
8224 | } | 8231 | } |
8232 | } | ||
8225 | 8233 | ||
8226 | return ret; | 8234 | #if ENABLE_HUSH_TYPE || ENABLE_HUSH_COMMAND |
8235 | static char *find_executable_in_PATH(const char *name) | ||
8236 | { | ||
8237 | const char *PATH; | ||
8238 | if (strchr(name, '/')) { | ||
8239 | /* Name with '/' is tested verbatim, with no PATH traversal: | ||
8240 | * "cd /bin; type ./cat" should print "./cat is ./cat", | ||
8241 | * NOT "./cat is /bin/./cat" | ||
8242 | */ | ||
8243 | if (file_is_executable(name)) | ||
8244 | return xstrdup(name); | ||
8245 | return NULL; | ||
8246 | } | ||
8247 | PATH = get_local_var_value("PATH"); | ||
8248 | return find_executable(name, &PATH); /* path == NULL is ok */ | ||
8227 | } | 8249 | } |
8250 | #endif | ||
8228 | 8251 | ||
8229 | static const struct built_in_command *find_builtin_helper(const char *name, | 8252 | static const struct built_in_command *find_builtin_helper(const char *name, |
8230 | const struct built_in_command *x, | 8253 | const struct built_in_command *x, |
@@ -8635,10 +8658,11 @@ static void if_command_vV_print_and_exit(char opt_vV, char *cmd, const char *exp | |||
8635 | 8658 | ||
8636 | to_free = NULL; | 8659 | to_free = NULL; |
8637 | if (!explanation) { | 8660 | if (!explanation) { |
8638 | char *path = getenv("PATH"); | 8661 | explanation = to_free = find_executable_in_PATH(cmd); |
8639 | explanation = to_free = find_executable(cmd, &path); /* path == NULL is ok */ | 8662 | if (!explanation) { |
8640 | if (!explanation) | 8663 | bb_error_msg("%s: %s: not found", "command", cmd); |
8641 | _exit(1); /* PROG was not found */ | 8664 | _exit(1); /* PROG was not found */ |
8665 | } | ||
8642 | if (opt_vV != 'V') | 8666 | if (opt_vV != 'V') |
8643 | cmd = to_free; /* -v PROG prints "/path/to/PROG" */ | 8667 | cmd = to_free; /* -v PROG prints "/path/to/PROG" */ |
8644 | } | 8668 | } |
@@ -10870,7 +10894,8 @@ static NOINLINE int run_applet_main(char **argv, int (*applet_main_func)(int arg | |||
10870 | #if ENABLE_HUSH_TEST || BASH_TEST2 | 10894 | #if ENABLE_HUSH_TEST || BASH_TEST2 |
10871 | static int FAST_FUNC builtin_test(char **argv) | 10895 | static int FAST_FUNC builtin_test(char **argv) |
10872 | { | 10896 | { |
10873 | return run_applet_main(argv, test_main); | 10897 | int argc = string_array_len(argv); |
10898 | return test_main2(&G.groupinfo, argc, argv); | ||
10874 | } | 10899 | } |
10875 | #endif | 10900 | #endif |
10876 | #if ENABLE_HUSH_ECHO | 10901 | #if ENABLE_HUSH_ECHO |
@@ -11063,12 +11088,15 @@ static int FAST_FUNC builtin_type(char **argv) | |||
11063 | # endif | 11088 | # endif |
11064 | else if (find_builtin(*argv)) | 11089 | else if (find_builtin(*argv)) |
11065 | type = "a shell builtin"; | 11090 | type = "a shell builtin"; |
11066 | else if ((path = find_in_path(*argv)) != NULL) | ||
11067 | type = path; | ||
11068 | else { | 11091 | else { |
11069 | bb_error_msg("type: %s: not found", *argv); | 11092 | path = find_executable_in_PATH(*argv); |
11070 | ret = EXIT_FAILURE; | 11093 | if (path) |
11071 | continue; | 11094 | type = path; |
11095 | else { | ||
11096 | bb_error_msg("%s: %s: not found", "type", *argv); | ||
11097 | ret = EXIT_FAILURE; | ||
11098 | continue; | ||
11099 | } | ||
11072 | } | 11100 | } |
11073 | 11101 | ||
11074 | printf("%s is %s\n", *argv, type); | 11102 | printf("%s is %s\n", *argv, type); |
@@ -11695,7 +11723,7 @@ static int FAST_FUNC builtin_source(char **argv) | |||
11695 | } | 11723 | } |
11696 | arg_path = NULL; | 11724 | arg_path = NULL; |
11697 | if (!strchr(filename, '/')) { | 11725 | if (!strchr(filename, '/')) { |
11698 | arg_path = find_in_path(filename); | 11726 | arg_path = find_in_PATH(filename); |
11699 | if (arg_path) | 11727 | if (arg_path) |
11700 | filename = arg_path; | 11728 | filename = arg_path; |
11701 | else if (!ENABLE_HUSH_BASH_SOURCE_CURDIR) { | 11729 | else if (!ENABLE_HUSH_BASH_SOURCE_CURDIR) { |