aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2022-05-06 08:26:55 +0100
committerRon Yorston <rmy@pobox.com>2022-05-06 09:30:43 +0100
commit26ba73098e714459e3294679228a1d54eed14799 (patch)
tree5e5dda2adbf6577276baf372626465213fd2f1b9
parent3b5042430fc4b82d44e0430f9ecc21a9228d1651 (diff)
downloadbusybox-w32-26ba73098e714459e3294679228a1d54eed14799.tar.gz
busybox-w32-26ba73098e714459e3294679228a1d54eed14799.tar.bz2
busybox-w32-26ba73098e714459e3294679228a1d54eed14799.zip
win32: search PATH for missing Unix-style executables
Commit 41ef232fc5 (win32: use built-in applets for non-existent binaries with Unix-style paths) alters what happens when trying to find an executable. If all of the following apply: - the pathname starts with one of the standard directories for Unix executables (/bin, /usr/bin, /sbin, /usr/sbin); - the file isn't found relative to the system root; - the basename matches an applet then the applet is run. Further extend the procedure so that if the first two conditions are met and either: - the PREFER_APPLETS and SH_STANDALONE features are enabled and the basename *doesn't* match an applet or - the PREFER_APPLETS and SH_STANDALONE features are disabled then PATH is searched for the basename. This affects: - how interpreters and binaries are spawned by mingw_spawn_interpreter() and mingw_spawnvp(); - how 'which' and the shell search for binaries. Special steps need to be taken in the shell to avoid treating shell built-ins and functions as applets. As a consequence of this change: - An executable that isn't an applet, say curl.exe, can be run as /usr/bin/curl so long as it's in a directory in PATH. It doesn't have to be in C:/usr/bin. - If the PREFER_APPLETS and SH_STANDALONE features are disabled binaries can be run using paths referring to standard Unix directories even if they're installed elsewhere in PATH.
-rw-r--r--debianutils/which.c17
-rw-r--r--shell/ash.c46
-rw-r--r--win32/mingw.c2
-rw-r--r--win32/process.c68
4 files changed, 74 insertions, 59 deletions
diff --git a/debianutils/which.c b/debianutils/which.c
index d00b92e0b..4590653b3 100644
--- a/debianutils/which.c
+++ b/debianutils/which.c
@@ -93,22 +93,29 @@ int which_main(int argc UNUSED_PARAM, char **argv)
93 missing = 0; 93 missing = 0;
94 puts(bs_to_slash(path)); 94 puts(bs_to_slash(path));
95 } 95 }
96# if ENABLE_FEATURE_SH_STANDALONE 96 else if (unix_path(*argv)) {
97 else if (sh_standalone && unix_path(*argv)) {
98 const char *name = bb_basename(*argv); 97 const char *name = bb_basename(*argv);
99 98# if ENABLE_FEATURE_SH_STANDALONE
100 if (find_applet_by_name(name) >= 0) { 99 if (sh_standalone && find_applet_by_name(name) >= 0) {
101 missing = 0; 100 missing = 0;
102 puts(name); 101 puts(name);
102 } else
103# endif
104 {
105 argv[0] = (char *)name;
106 free(path);
107 goto try_PATH;
103 } 108 }
104 } 109 }
105# endif
106 free(path); 110 free(path);
107#endif 111#endif
108 } else { 112 } else {
109 char *path; 113 char *path;
110 char *p; 114 char *p;
111 115
116#if ENABLE_PLATFORM_MINGW32
117 try_PATH:
118#endif
112 path = env_path; 119 path = env_path;
113 /* NOFORK NB: xmalloc inside find_executable(), must have no allocs above! */ 120 /* NOFORK NB: xmalloc inside find_executable(), must have no allocs above! */
114 while ((p = find_executable(*argv, &path)) != NULL) { 121 while ((p = find_executable(*argv, &path)) != NULL) {
diff --git a/shell/ash.c b/shell/ash.c
index 97075ed5f..6c1e58d6f 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -8983,6 +8983,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c
8983 * have to change the find_command routine as well. 8983 * have to change the find_command routine as well.
8984 * argv[-1] must exist and be writable! See tryexec() for why. 8984 * argv[-1] must exist and be writable! See tryexec() for why.
8985 */ 8985 */
8986static struct builtincmd *find_builtin(const char *name);
8986static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN; 8987static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN;
8987static void shellexec(char *prog, char **argv, const char *path, int idx) 8988static void shellexec(char *prog, char **argv, const char *path, int idx)
8988{ 8989{
@@ -9011,9 +9012,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
9011#endif 9012#endif
9012 ) { 9013 ) {
9013#if ENABLE_PLATFORM_MINGW32 9014#if ENABLE_PLATFORM_MINGW32
9014# if ENABLE_FEATURE_SH_STANDALONE
9015 char *oldprog = prog; 9015 char *oldprog = prog;
9016# endif
9017 prog = stack_add_system_drive(prog); 9016 prog = stack_add_system_drive(prog);
9018#endif 9017#endif
9019 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp); 9018 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) prog, argv, envp);
@@ -9025,16 +9024,17 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
9025 goto try_PATH; 9024 goto try_PATH;
9026 } 9025 }
9027 e = errno; 9026 e = errno;
9028#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE 9027#if ENABLE_PLATFORM_MINGW32
9029 if (unix_path(oldprog)) { 9028 if (unix_path(oldprog) && !find_builtin(bb_basename(oldprog))) {
9029# if ENABLE_FEATURE_SH_STANDALONE
9030 const char *name = bb_basename(oldprog); 9030 const char *name = bb_basename(oldprog);
9031 if ((applet_no = find_applet_by_name(name)) >= 0) { 9031 if ((applet_no = find_applet_by_name(name)) >= 0) {
9032 tryexec(applet_no, name, argv, envp); 9032 tryexec(applet_no, name, argv, envp);
9033 e = errno; 9033 e = errno;
9034 } 9034 }
9035 else { 9035# endif
9036 e = ENOENT; 9036 argv[0] = (char *)bb_basename(oldprog);
9037 } 9037 goto try_PATH;
9038 } 9038 }
9039#endif 9039#endif
9040 } else { 9040 } else {
@@ -9481,6 +9481,10 @@ describe_command(char *command, const char *path, int describe_command_verbose)
9481 p = command; 9481 p = command;
9482#endif 9482#endif
9483 } else { 9483 } else {
9484#if ENABLE_PLATFORM_MINGW32
9485 if (unix_path(command))
9486 command = (char *)bb_basename(command);
9487#endif
9484 do { 9488 do {
9485 padvance(&path, command); 9489 padvance(&path, command);
9486 } while (--j >= 0); 9490 } while (--j >= 0);
@@ -14658,24 +14662,20 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
14658#else /* ENABLE_PLATFORM_MINGW32 */ 14662#else /* ENABLE_PLATFORM_MINGW32 */
14659 /* If name contains a slash or drive prefix, don't use PATH or hash table */ 14663 /* If name contains a slash or drive prefix, don't use PATH or hash table */
14660 if (has_path(name)) { 14664 if (has_path(name)) {
14661 fullname = stack_add_system_drive(name);
14662 entry->u.index = -1; 14665 entry->u.index = -1;
14663 if (act & DO_ABS) {
14664 if (!add_win32_extension(fullname) && stat(fullname, &statb) < 0) {
14665# if ENABLE_FEATURE_SH_STANDALONE
14666 if (unix_path(name) &&
14667 find_applet_by_name(bb_basename(name)) >= 0) {
14668 entry->cmdtype = CMDNORMAL;
14669 entry->u.index = INT_MIN;
14670 return;
14671 }
14672# endif
14673 entry->cmdtype = CMDUNKNOWN;
14674 return;
14675 }
14676 }
14677 entry->cmdtype = CMDNORMAL; 14666 entry->cmdtype = CMDNORMAL;
14678 return; 14667 fullname = stack_add_system_drive(name);
14668 if (add_win32_extension(fullname) || file_is_executable(fullname)) {
14669 return;
14670 } else if (unix_path(name) && !find_builtin(bb_basename(name))) {
14671 name = (char *)bb_basename(name);
14672 act |= DO_NOFUNC;
14673 } else if (act & DO_ABS) {
14674 entry->cmdtype = CMDUNKNOWN;
14675 return;
14676 } else {
14677 return;
14678 }
14679 } 14679 }
14680#endif /* ENABLE_PLATFORM_MINGW32 */ 14680#endif /* ENABLE_PLATFORM_MINGW32 */
14681 14681
diff --git a/win32/mingw.c b/win32/mingw.c
index 0fa2a1b8f..d6b725e17 100644
--- a/win32/mingw.c
+++ b/win32/mingw.c
@@ -2096,7 +2096,6 @@ void *get_proc_addr(const char *dll, const char *function,
2096 return proc->pfunction; 2096 return proc->pfunction;
2097} 2097}
2098 2098
2099#if ENABLE_FEATURE_SH_STANDALONE || ENABLE_FEATURE_PREFER_APPLETS
2100int unix_path(const char *path) 2099int unix_path(const char *path)
2101{ 2100{
2102 int i; 2101 int i;
@@ -2107,7 +2106,6 @@ int unix_path(const char *path)
2107 free(p); 2106 free(p);
2108 return i >= 0; 2107 return i >= 0;
2109} 2108}
2110#endif
2111 2109
2112/* Return true if file is referenced using a path. This means a path 2110/* Return true if file is referenced using a path. This means a path
2113 * look-up isn't required. */ 2111 * look-up isn't required. */
diff --git a/win32/process.c b/win32/process.c
index d4ab07ad8..6ab0d8735 100644
--- a/win32/process.c
+++ b/win32/process.c
@@ -297,12 +297,12 @@ static intptr_t
297mingw_spawn_interpreter(int mode, const char *prog, char *const *argv, 297mingw_spawn_interpreter(int mode, const char *prog, char *const *argv,
298 char *const *envp, int level) 298 char *const *envp, int level)
299{ 299{
300 intptr_t ret; 300 intptr_t ret = -1;
301 int nopts; 301 int nopts;
302 interp_t interp; 302 interp_t interp;
303 char **new_argv; 303 char **new_argv;
304 int argc; 304 int argc;
305 char *fullpath = NULL; 305 char *path = NULL;
306 306
307 if (!parse_interpreter(prog, &interp)) 307 if (!parse_interpreter(prog, &interp))
308 return spawnveq(mode, prog, argv, envp); 308 return spawnveq(mode, prog, argv, envp);
@@ -320,22 +320,33 @@ mingw_spawn_interpreter(int mode, const char *prog, char *const *argv,
320 memcpy(new_argv+nopts+2, argv+1, sizeof(*argv)*argc); 320 memcpy(new_argv+nopts+2, argv+1, sizeof(*argv)*argc);
321 321
322#if ENABLE_FEATURE_PREFER_APPLETS && NUM_APPLETS > 1 322#if ENABLE_FEATURE_PREFER_APPLETS && NUM_APPLETS > 1
323 if (find_applet_by_name(interp.name) >= 0) { 323 if (unix_path(interp.path) && find_applet_by_name(interp.name) >= 0) {
324 /* the fake path indicates the index of the script */ 324 /* the fake path indicates the index of the script */
325 new_argv[0] = fullpath = xasprintf("%d:/%s", nopts+1, interp.name); 325 new_argv[0] = path = xasprintf("%d:/%s", nopts+1, interp.name);
326 ret = mingw_spawn_applet(mode, new_argv, envp); 326 ret = mingw_spawn_applet(mode, new_argv, envp);
327 } else 327 goto done;
328 }
328#endif 329#endif
329 if ((fullpath = alloc_system_drive(interp.path)) && 330
330 (add_win32_extension(fullpath) || file_is_executable(fullpath))) { 331 path = alloc_system_drive(interp.path);
331 new_argv[0] = fullpath; 332 if ((add_win32_extension(path) || file_is_executable(path))) {
332 ret = mingw_spawn_interpreter(mode, new_argv[0], new_argv, envp, level); 333 new_argv[0] = path;
333 } else { 334 ret = mingw_spawn_interpreter(mode, path, new_argv, envp, level);
334 errno = ENOENT; 335 goto done;
335 ret = -1;
336 } 336 }
337 free(path);
338 path = NULL;
337 339
338 free(fullpath); 340 if (unix_path(interp.path)) {
341 if ((path = find_first_executable(interp.name)) != NULL) {
342 new_argv[0] = path;
343 ret = mingw_spawn_interpreter(mode, path, new_argv, envp, level);
344 goto done;
345 }
346 }
347 errno = ENOENT;
348 done:
349 free(path);
339 free(new_argv); 350 free(new_argv);
340 return ret; 351 return ret;
341} 352}
@@ -343,30 +354,29 @@ mingw_spawn_interpreter(int mode, const char *prog, char *const *argv,
343static intptr_t 354static intptr_t
344mingw_spawnvp(int mode, const char *cmd, char *const *argv) 355mingw_spawnvp(int mode, const char *cmd, char *const *argv)
345{ 356{
346 char *prog; 357 char *path;
347 intptr_t ret; 358 intptr_t ret;
348 359
349#if ENABLE_FEATURE_PREFER_APPLETS && NUM_APPLETS > 1 360#if ENABLE_FEATURE_PREFER_APPLETS && NUM_APPLETS > 1
350 if (find_applet_by_name(cmd) >= 0) 361 if ((!has_path(cmd) || unix_path(cmd)) &&
362 find_applet_by_name(bb_basename(cmd)) >= 0)
351 return mingw_spawn_applet(mode, argv, NULL); 363 return mingw_spawn_applet(mode, argv, NULL);
352 else
353#endif 364#endif
354 if (has_path(cmd)) { 365 if (has_path(cmd)) {
355 char *path = alloc_system_drive(cmd); 366 path = alloc_system_drive(cmd);
356 add_win32_extension(path); 367 if (add_win32_extension(path) || file_is_executable(path)) {
357 ret = mingw_spawn_interpreter(mode, path, argv, NULL, 0); 368 ret = mingw_spawn_interpreter(mode, path, argv, NULL, 0);
358 free(path); 369 free(path);
359#if ENABLE_FEATURE_PREFER_APPLETS && NUM_APPLETS > 1 370 return ret;
360 if (ret == -1 && unix_path(cmd) &&
361 find_applet_by_name(bb_basename(cmd)) >= 0) {
362 return mingw_spawn_applet(mode, argv, NULL);
363 } 371 }
364#endif 372 free(path);
365 return ret; 373 if (unix_path(cmd))
374 cmd = bb_basename(cmd);
366 } 375 }
367 else if ((prog=find_first_executable(cmd)) != NULL) { 376
368 ret = mingw_spawn_interpreter(mode, prog, argv, NULL, 0); 377 if ((path = find_first_executable(cmd)) != NULL) {
369 free(prog); 378 ret = mingw_spawn_interpreter(mode, path, argv, NULL, 0);
379 free(path);
370 return ret; 380 return ret;
371 } 381 }
372 382