diff options
author | Ron Yorston <rmy@pobox.com> | 2022-05-01 10:20:16 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2022-05-01 11:03:10 +0100 |
commit | 6d87be4d760ceda18d354c6d4c523a9adf50c04b (patch) | |
tree | ca286c74b3d0689591ce7bee6a9b98af93e15e21 | |
parent | ae61e126ee8e8200e87f285d9c410eb377505578 (diff) | |
download | busybox-w32-6d87be4d760ceda18d354c6d4c523a9adf50c04b.tar.gz busybox-w32-6d87be4d760ceda18d354c6d4c523a9adf50c04b.tar.bz2 busybox-w32-6d87be4d760ceda18d354c6d4c523a9adf50c04b.zip |
which,ash: changes to which/command/type
Change how 'which' detects if it was run from a standalone shell:
the shell passes the undocumented '-s' option. This is stricter
and more reliable than the previous method of checking the name
of the binary.
Add a function to determine the binary associated with a given
applet name. This makes it possible for 'which' and 'command -v'
to list the correct binary even for applets other than 'busybox'.
For example, when the binary is called 'sh.exe' 'which sh' will
report its path.
In standalone shell mode 'command -V' and 'type' now report "xxx
is a builtin applet" rather than "xxx is xxx", which is true but
not very illuminating.
(GitHub issue #248)
-rw-r--r-- | debianutils/which.c | 50 | ||||
-rw-r--r-- | include/mingw.h | 1 | ||||
-rw-r--r-- | shell/ash.c | 18 | ||||
-rw-r--r-- | win32/mingw.c | 21 |
4 files changed, 67 insertions, 23 deletions
diff --git a/debianutils/which.c b/debianutils/which.c index 815ac71da..d00b92e0b 100644 --- a/debianutils/which.c +++ b/debianutils/which.c | |||
@@ -12,7 +12,12 @@ | |||
12 | //config: which is used to find programs in your PATH and | 12 | //config: which is used to find programs in your PATH and |
13 | //config: print out their pathnames. | 13 | //config: print out their pathnames. |
14 | 14 | ||
15 | //applet:IF_WHICH(APPLET_NOFORK(which, which, BB_DIR_USR_BIN, BB_SUID_DROP, which)) | 15 | // NOTE: For WIN32 this applet is NOEXEC as alloc_system_drive() and |
16 | // find_executable() both allocate memory. And find_executable() | ||
17 | // calls alloc_system_drive(). | ||
18 | |||
19 | //applet:IF_PLATFORM_MINGW32(IF_WHICH(APPLET_NOEXEC(which, which, BB_DIR_USR_BIN, BB_SUID_DROP, which))) | ||
20 | //applet:IF_PLATFORM_POSIX(IF_WHICH(APPLET_NOFORK(which, which, BB_DIR_USR_BIN, BB_SUID_DROP, which))) | ||
16 | 21 | ||
17 | //kbuild:lib-$(CONFIG_WHICH) += which.o | 22 | //kbuild:lib-$(CONFIG_WHICH) += which.o |
18 | 23 | ||
@@ -28,6 +33,13 @@ | |||
28 | 33 | ||
29 | #include "libbb.h" | 34 | #include "libbb.h" |
30 | 35 | ||
36 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
37 | enum { | ||
38 | OPT_a = (1 << 0), | ||
39 | OPT_s = (1 << 1) | ||
40 | }; | ||
41 | #endif | ||
42 | |||
31 | int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 43 | int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
32 | int which_main(int argc UNUSED_PARAM, char **argv) | 44 | int which_main(int argc UNUSED_PARAM, char **argv) |
33 | { | 45 | { |
@@ -36,9 +48,7 @@ int which_main(int argc UNUSED_PARAM, char **argv) | |||
36 | /* This sizeof(): bb_default_root_path is shorter than BB_PATH_ROOT_PATH */ | 48 | /* This sizeof(): bb_default_root_path is shorter than BB_PATH_ROOT_PATH */ |
37 | char buf[sizeof(BB_PATH_ROOT_PATH)]; | 49 | char buf[sizeof(BB_PATH_ROOT_PATH)]; |
38 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | 50 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE |
39 | /* If we were run as 'which.exe' skip standalone shell behaviour */ | 51 | int sh_standalone; |
40 | int sh_standalone = | ||
41 | is_suffixed_with_case(bb_busybox_exec_path, "which.exe") == NULL; | ||
42 | #endif | 52 | #endif |
43 | 53 | ||
44 | env_path = getenv("PATH"); | 54 | env_path = getenv("PATH"); |
@@ -46,28 +56,25 @@ int which_main(int argc UNUSED_PARAM, char **argv) | |||
46 | /* env_path must be writable, and must not alloc, so... */ | 56 | /* env_path must be writable, and must not alloc, so... */ |
47 | env_path = strcpy(buf, bb_default_root_path); | 57 | env_path = strcpy(buf, bb_default_root_path); |
48 | 58 | ||
59 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | ||
60 | /* '-s' option indicates we were run from a standalone shell */ | ||
61 | getopt32(argv, "^" "as" "\0" "-1"/*at least one arg*/); | ||
62 | sh_standalone = option_mask32 & OPT_s; | ||
63 | option_mask32 &= ~OPT_s; | ||
64 | #else | ||
49 | getopt32(argv, "^" "a" "\0" "-1"/*at least one arg*/); | 65 | getopt32(argv, "^" "a" "\0" "-1"/*at least one arg*/); |
66 | #endif | ||
50 | argv += optind; | 67 | argv += optind; |
51 | 68 | ||
52 | do { | 69 | do { |
53 | int missing = 1; | 70 | int missing = 1; |
54 | 71 | ||
55 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | 72 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE |
56 | if (sh_standalone) { | 73 | if (sh_standalone && find_applet_by_name(*argv) >= 0) { |
57 | if (strcmp(*argv, "busybox") == 0 && | 74 | missing = 0; |
58 | is_prefixed_with_case(bb_basename(bb_busybox_exec_path), | 75 | puts(applet_to_exe(*argv)); |
59 | "busybox")) { | 76 | if (!option_mask32) /* -a not set */ |
60 | missing = 0; | 77 | break; |
61 | puts(bb_busybox_exec_path); | ||
62 | if (!option_mask32) /* -a not set */ | ||
63 | break; | ||
64 | } | ||
65 | else if (find_applet_by_name(*argv) >= 0) { | ||
66 | missing = 0; | ||
67 | puts(*argv); | ||
68 | if (!option_mask32) /* -a not set */ | ||
69 | break; | ||
70 | } | ||
71 | } | 78 | } |
72 | #endif | 79 | #endif |
73 | 80 | ||
@@ -87,15 +94,16 @@ int which_main(int argc UNUSED_PARAM, char **argv) | |||
87 | puts(bs_to_slash(path)); | 94 | puts(bs_to_slash(path)); |
88 | } | 95 | } |
89 | # if ENABLE_FEATURE_SH_STANDALONE | 96 | # if ENABLE_FEATURE_SH_STANDALONE |
90 | else if (sh_standalone) { | 97 | else if (sh_standalone && unix_path(*argv)) { |
91 | const char *name = bb_basename(*argv); | 98 | const char *name = bb_basename(*argv); |
92 | 99 | ||
93 | if (unix_path(*argv) && find_applet_by_name(name) >= 0) { | 100 | if (find_applet_by_name(name) >= 0) { |
94 | missing = 0; | 101 | missing = 0; |
95 | puts(name); | 102 | puts(name); |
96 | } | 103 | } |
97 | } | 104 | } |
98 | # endif | 105 | # endif |
106 | free(path); | ||
99 | #endif | 107 | #endif |
100 | } else { | 108 | } else { |
101 | char *path; | 109 | char *path; |
diff --git a/include/mingw.h b/include/mingw.h index 8a9610898..5e01b874e 100644 --- a/include/mingw.h +++ b/include/mingw.h | |||
@@ -584,3 +584,4 @@ int unix_path(const char *path); | |||
584 | int has_path(const char *file); | 584 | int has_path(const char *file); |
585 | int is_relative_path(const char *path); | 585 | int is_relative_path(const char *path); |
586 | char *get_last_slash(const char *path); | 586 | char *get_last_slash(const char *path); |
587 | const char *applet_to_exe(const char *name); | ||
diff --git a/shell/ash.c b/shell/ash.c index afb865146..97075ed5f 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -8904,6 +8904,16 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
8904 | (fs && fs->fpid == FS_SHELLEXEC)) { | 8904 | (fs && fs->fpid == FS_SHELLEXEC)) { |
8905 | /* mingw-w64's getopt() uses __argv[0] as the program name */ | 8905 | /* mingw-w64's getopt() uses __argv[0] as the program name */ |
8906 | __argv[0] = (char *)cmd; | 8906 | __argv[0] = (char *)cmd; |
8907 | /* 'which' wants to know if it was invoked from a standalone | ||
8908 | * shell. Use the spare element of argv to add a flag, but | ||
8909 | * not if the first argument is '--help', that's a special | ||
8910 | * case. */ | ||
8911 | if (strcmp(argv[0], "which") == 0 && | ||
8912 | (argv[1] == NULL || strcmp(argv[1], "--help") != 0)) { | ||
8913 | --argv; | ||
8914 | argv[0] = argv[1]; | ||
8915 | argv[1] = (char *)"-s"; | ||
8916 | } | ||
8907 | # else | 8917 | # else |
8908 | if (APPLET_IS_NOEXEC(applet_no)) { | 8918 | if (APPLET_IS_NOEXEC(applet_no)) { |
8909 | # endif | 8919 | # endif |
@@ -9456,7 +9466,12 @@ describe_command(char *command, const char *path, int describe_command_verbose) | |||
9456 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE | 9466 | #if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE |
9457 | if (j < -1) { | 9467 | if (j < -1) { |
9458 | p = (char *)bb_basename(command); | 9468 | p = (char *)bb_basename(command); |
9459 | goto describe; | 9469 | if (describe_command_verbose) { |
9470 | out1fmt(" is a builtin applet"); | ||
9471 | } else { | ||
9472 | out1str(applet_to_exe(p)); | ||
9473 | } | ||
9474 | break; | ||
9460 | } | 9475 | } |
9461 | #endif | 9476 | #endif |
9462 | if (j < 0) { | 9477 | if (j < 0) { |
@@ -9474,7 +9489,6 @@ describe_command(char *command, const char *path, int describe_command_verbose) | |||
9474 | #if ENABLE_PLATFORM_MINGW32 | 9489 | #if ENABLE_PLATFORM_MINGW32 |
9475 | add_win32_extension(p); | 9490 | add_win32_extension(p); |
9476 | bs_to_slash(p); | 9491 | bs_to_slash(p); |
9477 | IF_FEATURE_SH_STANDALONE(describe:) | ||
9478 | #endif | 9492 | #endif |
9479 | if (describe_command_verbose) { | 9493 | if (describe_command_verbose) { |
9480 | out1fmt(" is %s", p); | 9494 | out1fmt(" is %s", p); |
diff --git a/win32/mingw.c b/win32/mingw.c index 063a0c546..0fa2a1b8f 100644 --- a/win32/mingw.c +++ b/win32/mingw.c | |||
@@ -2130,3 +2130,24 @@ int is_relative_path(const char *path) | |||
2130 | { | 2130 | { |
2131 | return !is_dir_sep(path[0]) && !has_dos_drive_prefix(path); | 2131 | return !is_dir_sep(path[0]) && !has_dos_drive_prefix(path); |
2132 | } | 2132 | } |
2133 | |||
2134 | #if ENABLE_FEATURE_SH_STANDALONE | ||
2135 | /* | ||
2136 | * In standalone shell mode it's possible there's no binary file | ||
2137 | * corresponding to an applet name. There's one case where it's | ||
2138 | * easy to determine the corresponding binary: if the applet name | ||
2139 | * matches the file name from bb_busybox_exec_path (with appropriate | ||
2140 | * allowance for 'busybox*.exe'). | ||
2141 | */ | ||
2142 | const char *applet_to_exe(const char *name) | ||
2143 | { | ||
2144 | const char *exefile = bb_basename(bb_busybox_exec_path); | ||
2145 | const char *exesuff = is_prefixed_with_case(exefile, name); | ||
2146 | |||
2147 | if (exesuff && (strcmp(name, "busybox") == 0 || | ||
2148 | strcasecmp(exesuff, ".exe") == 0)) { | ||
2149 | return bb_busybox_exec_path; | ||
2150 | } | ||
2151 | return name; | ||
2152 | } | ||
2153 | #endif | ||