aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2024-10-08 11:54:51 +0100
committerRon Yorston <rmy@pobox.com>2024-10-08 12:09:30 +0100
commitded78ca2656fd41f130d65345b0eb4d39b1fcbdf (patch)
treeec6a2dfab77f2a49a9629d29df371a3d93256929
parent054f494916093715bc1d2d25a7a452a036d41add (diff)
parent75ca8d074bacb6896d770993b93161c40aa31b9f (diff)
downloadbusybox-w32-ded78ca2656fd41f130d65345b0eb4d39b1fcbdf.tar.gz
busybox-w32-ded78ca2656fd41f130d65345b0eb4d39b1fcbdf.tar.bz2
busybox-w32-ded78ca2656fd41f130d65345b0eb4d39b1fcbdf.zip
Merge branch 'busybox' into merge
-rw-r--r--debianutils/which.c9
-rw-r--r--include/libbb.h2
-rw-r--r--libbb/appletlib.c6
-rw-r--r--libbb/executable.c52
-rw-r--r--shell/hush.c86
-rw-r--r--util-linux/hexdump.c11
-rw-r--r--win32/process.c2
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 @@
35int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 35int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
36int which_main(int argc UNUSED_PARAM, char **argv) 36int 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
1293int file_is_executable(const char *name) FAST_FUNC; 1293int file_is_executable(const char *name) FAST_FUNC;
1294char *find_executable(const char *filename, char **PATHp) FAST_FUNC; 1294char *find_executable(const char *filename, const char **PATHp) FAST_FUNC;
1295int executable_exists(const char *filename) FAST_FUNC; 1295int 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
285static int external_exists(const char *name, const char *path) 285static 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 */
36char* FAST_FUNC find_executable(const char *filename, char **PATHp) 33char* 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 */
85int FAST_FUNC executable_exists(const char *filename) 91int 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
8196static 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?
8208static 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
8235static 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
8229static const struct built_in_command *find_builtin_helper(const char *name, 8252static 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
10871static int FAST_FUNC builtin_test(char **argv) 10895static 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)
146char * FAST_FUNC 146char * FAST_FUNC
147find_first_executable(const char *name) 147find_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