diff options
author | Ron Yorston <rmy@pobox.com> | 2022-05-06 08:26:55 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2022-05-06 09:30:43 +0100 |
commit | 26ba73098e714459e3294679228a1d54eed14799 (patch) | |
tree | 5e5dda2adbf6577276baf372626465213fd2f1b9 | |
parent | 3b5042430fc4b82d44e0430f9ecc21a9228d1651 (diff) | |
download | busybox-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.c | 17 | ||||
-rw-r--r-- | shell/ash.c | 46 | ||||
-rw-r--r-- | win32/mingw.c | 2 | ||||
-rw-r--r-- | win32/process.c | 68 |
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 | */ |
8986 | static struct builtincmd *find_builtin(const char *name); | ||
8986 | static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN; | 8987 | static void shellexec(char *prog, char **argv, const char *path, int idx) NORETURN; |
8987 | static void shellexec(char *prog, char **argv, const char *path, int idx) | 8988 | static 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 | ||
2100 | int unix_path(const char *path) | 2099 | int 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 | |||
297 | mingw_spawn_interpreter(int mode, const char *prog, char *const *argv, | 297 | mingw_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, | |||
343 | static intptr_t | 354 | static intptr_t |
344 | mingw_spawnvp(int mode, const char *cmd, char *const *argv) | 355 | mingw_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 | ||