diff options
author | Ron Yorston <rmy@pobox.com> | 2024-10-08 11:54:51 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2024-10-08 12:09:30 +0100 |
commit | ded78ca2656fd41f130d65345b0eb4d39b1fcbdf (patch) | |
tree | ec6a2dfab77f2a49a9629d29df371a3d93256929 | |
parent | 054f494916093715bc1d2d25a7a452a036d41add (diff) | |
parent | 75ca8d074bacb6896d770993b93161c40aa31b9f (diff) | |
download | busybox-w32-ded78ca2656fd41f130d65345b0eb4d39b1fcbdf.tar.gz busybox-w32-ded78ca2656fd41f130d65345b0eb4d39b1fcbdf.tar.bz2 busybox-w32-ded78ca2656fd41f130d65345b0eb4d39b1fcbdf.zip |
Merge branch 'busybox' into merge
-rw-r--r-- | debianutils/which.c | 9 | ||||
-rw-r--r-- | include/libbb.h | 2 | ||||
-rw-r--r-- | libbb/appletlib.c | 6 | ||||
-rw-r--r-- | libbb/executable.c | 52 | ||||
-rw-r--r-- | shell/hush.c | 86 | ||||
-rw-r--r-- | util-linux/hexdump.c | 11 | ||||
-rw-r--r-- | win32/process.c | 2 |
7 files changed, 102 insertions, 66 deletions
diff --git a/debianutils/which.c b/debianutils/which.c index fd3f53d3e..5d564e01d 100644 --- a/debianutils/which.c +++ b/debianutils/which.c | |||
@@ -35,10 +35,8 @@ | |||
35 | int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 35 | int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
36 | int which_main(int argc UNUSED_PARAM, char **argv) | 36 | int which_main(int argc UNUSED_PARAM, char **argv) |
37 | { | 37 | { |
38 | char *env_path; | 38 | const char *env_path; |
39 | int status = 0; | 39 | int status = 0; |
40 | /* This sizeof(): bb_default_root_path is shorter than BB_PATH_ROOT_PATH */ | ||
41 | char buf[sizeof(BB_PATH_ROOT_PATH)]; | ||
42 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | 40 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE |
43 | /* 'Which' in argv[0] indicates we were run from a standalone shell */ | 41 | /* 'Which' in argv[0] indicates we were run from a standalone shell */ |
44 | int sh_standalone = argv[0][0] == 'W'; | 42 | int sh_standalone = argv[0][0] == 'W'; |
@@ -46,8 +44,7 @@ int which_main(int argc UNUSED_PARAM, char **argv) | |||
46 | 44 | ||
47 | env_path = getenv("PATH"); | 45 | env_path = getenv("PATH"); |
48 | if (!env_path) | 46 | if (!env_path) |
49 | /* env_path must be writable, and must not alloc, so... */ | 47 | env_path = bb_default_root_path; |
50 | env_path = strcpy(buf, bb_default_root_path); | ||
51 | 48 | ||
52 | getopt32(argv, "^" "a" "\0" "-1"/*at least one arg*/); | 49 | getopt32(argv, "^" "a" "\0" "-1"/*at least one arg*/); |
53 | argv += optind; | 50 | argv += optind; |
@@ -94,7 +91,7 @@ int which_main(int argc UNUSED_PARAM, char **argv) | |||
94 | } | 91 | } |
95 | #endif | 92 | #endif |
96 | } else { | 93 | } else { |
97 | char *path; | 94 | const char *path; |
98 | char *p; | 95 | char *p; |
99 | 96 | ||
100 | #if ENABLE_PLATFORM_MINGW32 | 97 | #if ENABLE_PLATFORM_MINGW32 |
diff --git a/include/libbb.h b/include/libbb.h index 11d52c08c..ed8892562 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -1291,7 +1291,7 @@ void FAST_FUNC update_utmp_DEAD_PROCESS(pid_t pid); | |||
1291 | 1291 | ||
1292 | 1292 | ||
1293 | int file_is_executable(const char *name) FAST_FUNC; | 1293 | int file_is_executable(const char *name) FAST_FUNC; |
1294 | char *find_executable(const char *filename, char **PATHp) FAST_FUNC; | 1294 | char *find_executable(const char *filename, const char **PATHp) FAST_FUNC; |
1295 | int executable_exists(const char *filename) FAST_FUNC; | 1295 | int executable_exists(const char *filename) FAST_FUNC; |
1296 | 1296 | ||
1297 | /* BB_EXECxx always execs (it's not doing NOFORK/NOEXEC stuff), | 1297 | /* BB_EXECxx always execs (it's not doing NOFORK/NOEXEC stuff), |
diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 27ce8a6e8..d6e042775 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c | |||
@@ -284,12 +284,12 @@ int FAST_FUNC find_applet_by_name(const char *name) | |||
284 | # if ENABLE_FEATURE_SH_STANDALONE || ENABLE_FEATURE_PREFER_APPLETS | 284 | # if ENABLE_FEATURE_SH_STANDALONE || ENABLE_FEATURE_PREFER_APPLETS |
285 | static int external_exists(const char *name, const char *path) | 285 | static int external_exists(const char *name, const char *path) |
286 | { | 286 | { |
287 | char *path0, *path1, *ret; | 287 | const char *path0, *path1, *ret; |
288 | 288 | ||
289 | path0 = path1 = xstrdup(path ?: getenv("PATH")); | 289 | path0 = path1 = xstrdup(path ?: getenv("PATH")); |
290 | ret = find_executable(name, &path1); | 290 | ret = find_executable(name, &path1); |
291 | free(ret); | 291 | free((void *)ret); |
292 | free(path0); | 292 | free((void *)path0); |
293 | return ret != NULL; | 293 | return ret != NULL; |
294 | } | 294 | } |
295 | 295 | ||
diff --git a/libbb/executable.c b/libbb/executable.c index 606bec986..263141912 100644 --- a/libbb/executable.c +++ b/libbb/executable.c | |||
@@ -26,14 +26,11 @@ int FAST_FUNC file_is_executable(const char *name) | |||
26 | /* search (*PATHp) for an executable file; | 26 | /* search (*PATHp) for an executable file; |
27 | * return allocated string containing full path if found; | 27 | * return allocated string containing full path if found; |
28 | * PATHp points to the component after the one where it was found | 28 | * PATHp points to the component after the one where it was found |
29 | * (or NULL), | 29 | * (or NULL if found in last component), |
30 | * you may call find_executable again with this PATHp to continue | 30 | * you may call find_executable again with this PATHp to continue |
31 | * (if it's not NULL). | 31 | * return NULL otherwise (PATHp is undefined) |
32 | * return NULL otherwise; (PATHp is undefined) | ||
33 | * in all cases (*PATHp) contents are temporarily modified | ||
34 | * but are restored on return (s/:/NUL/ and back). | ||
35 | */ | 32 | */ |
36 | char* FAST_FUNC find_executable(const char *filename, char **PATHp) | 33 | char* FAST_FUNC find_executable(const char *name, const char **PATHp) |
37 | { | 34 | { |
38 | /* About empty components in $PATH: | 35 | /* About empty components in $PATH: |
39 | * http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html | 36 | * http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html |
@@ -43,18 +40,27 @@ char* FAST_FUNC find_executable(const char *filename, char **PATHp) | |||
43 | * initial colon preceding the rest of the list, or as a trailing colon | 40 | * initial colon preceding the rest of the list, or as a trailing colon |
44 | * following the rest of the list. | 41 | * following the rest of the list. |
45 | */ | 42 | */ |
46 | char *p, *n; | 43 | char *p = (char*) *PATHp; |
47 | 44 | ||
48 | p = *PATHp; | 45 | if (!p) |
49 | while (p) { | 46 | return NULL; |
47 | while (1) { | ||
48 | const char *end = strchrnul(p, PATH_SEP); | ||
49 | int sz = end - p; | ||
50 | int ex; | 50 | int ex; |
51 | 51 | ||
52 | n = strchr(p, PATH_SEP); | 52 | if (sz != 0) { |
53 | if (n) *n = '\0'; | 53 | p = xasprintf("%.*s/%s", sz, p, name); |
54 | p = concat_path_file( | 54 | } else { |
55 | p[0] ? p : ".", /* handle "::" case */ | 55 | /* We have xxx::yyy in $PATH, |
56 | filename | 56 | * it means "use current dir" */ |
57 | ); | 57 | p = xstrdup(name); |
58 | // A bit of discrepancy wrt the path used if file is found here. | ||
59 | // bash 5.2.15 "type" returns "./NAME". | ||
60 | // GNU which v2.21 returns "/CUR/DIR/NAME". | ||
61 | // With -a, both skip over all colons: xxx::::yyy is the same as xxx::yyy, | ||
62 | // current dir is not tried the second time. | ||
63 | } | ||
58 | #if ENABLE_PLATFORM_MINGW32 | 64 | #if ENABLE_PLATFORM_MINGW32 |
59 | { | 65 | { |
60 | char *w = file_is_win32_exe(p); | 66 | char *w = file_is_win32_exe(p); |
@@ -67,25 +73,25 @@ char* FAST_FUNC find_executable(const char *filename, char **PATHp) | |||
67 | #else | 73 | #else |
68 | ex = file_is_executable(p); | 74 | ex = file_is_executable(p); |
69 | #endif | 75 | #endif |
70 | if (n) *n++ = PATH_SEP; | ||
71 | if (ex) { | 76 | if (ex) { |
72 | *PATHp = n; | 77 | *PATHp = (*end ? end+1 : NULL); |
73 | return p; | 78 | return p; |
74 | } | 79 | } |
75 | free(p); | 80 | free(p); |
76 | p = n; | 81 | if (*end == '\0') |
77 | } /* on loop exit p == NULL */ | 82 | return NULL; |
78 | return p; | 83 | p = (char *) end + 1; |
84 | } | ||
79 | } | 85 | } |
80 | 86 | ||
81 | /* search $PATH for an executable file; | 87 | /* search $PATH for an executable file; |
82 | * return 1 if found; | 88 | * return 1 if found; |
83 | * return 0 otherwise; | 89 | * return 0 otherwise; |
84 | */ | 90 | */ |
85 | int FAST_FUNC executable_exists(const char *filename) | 91 | int FAST_FUNC executable_exists(const char *name) |
86 | { | 92 | { |
87 | char *path = getenv("PATH"); | 93 | const char *path = getenv("PATH"); |
88 | char *ret = find_executable(filename, &path); | 94 | char *ret = find_executable(name, &path); |
89 | free(ret); | 95 | free(ret); |
90 | return ret != NULL; | 96 | return ret != NULL; |
91 | } | 97 | } |
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) { |
diff --git a/util-linux/hexdump.c b/util-linux/hexdump.c index c46ffeca7..5a938e783 100644 --- a/util-linux/hexdump.c +++ b/util-linux/hexdump.c | |||
@@ -127,15 +127,20 @@ int hexdump_main(int argc, char **argv) | |||
127 | if (ch == 'f') { | 127 | if (ch == 'f') { |
128 | bb_dump_addfile(dumper, optarg); | 128 | bb_dump_addfile(dumper, optarg); |
129 | } /* else */ | 129 | } /* else */ |
130 | if (ch == 'n') { | 130 | if (ch == 'n') { /* compat: -n accepts hex numbers too */ |
131 | dumper->dump_length = xatoi_positive(optarg); | 131 | dumper->dump_length = xstrtou_range_sfx( |
132 | optarg, | ||
133 | /*base:*/ 0, | ||
134 | /*lo:*/ 0, /*hi:*/ INT_MAX, | ||
135 | kmg_i_suffixes | ||
136 | ); | ||
132 | } /* else */ | 137 | } /* else */ |
133 | if (ch == 's') { /* compat: -s accepts hex numbers too */ | 138 | if (ch == 's') { /* compat: -s accepts hex numbers too */ |
134 | dumper->dump_skip = xstrtoull_range_sfx( | 139 | dumper->dump_skip = xstrtoull_range_sfx( |
135 | optarg, | 140 | optarg, |
136 | /*base:*/ 0, | 141 | /*base:*/ 0, |
137 | /*lo:*/ 0, /*hi:*/ OFF_T_MAX, | 142 | /*lo:*/ 0, /*hi:*/ OFF_T_MAX, |
138 | bkm_suffixes | 143 | kmg_i_suffixes |
139 | ); | 144 | ); |
140 | } /* else */ | 145 | } /* else */ |
141 | if (ch == 'v') { | 146 | if (ch == 'v') { |
diff --git a/win32/process.c b/win32/process.c index e3ce95ca0..9a5ab417a 100644 --- a/win32/process.c +++ b/win32/process.c | |||
@@ -146,7 +146,7 @@ quote_arg(const char *arg) | |||
146 | char * FAST_FUNC | 146 | char * FAST_FUNC |
147 | find_first_executable(const char *name) | 147 | find_first_executable(const char *name) |
148 | { | 148 | { |
149 | char *path = getenv("PATH"); | 149 | const char *path = getenv("PATH"); |
150 | return find_executable(name, &path); | 150 | return find_executable(name, &path); |
151 | } | 151 | } |
152 | 152 | ||