diff options
author | Ron Yorston <rmy@pobox.com> | 2018-02-28 17:00:43 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2018-02-28 17:00:43 +0000 |
commit | 92dbd3c0932abbfb6814554603abd38e3eb9d953 (patch) | |
tree | 11ec318924d65796538a776422ab130d81b56752 | |
parent | b0a565de930df8dc4fd8f00cbfe3a585391cb05a (diff) | |
download | busybox-w32-92dbd3c0932abbfb6814554603abd38e3eb9d953.tar.gz busybox-w32-92dbd3c0932abbfb6814554603abd38e3eb9d953.tar.bz2 busybox-w32-92dbd3c0932abbfb6814554603abd38e3eb9d953.zip |
ash: changes to command resolution, execution and display
ash separates searching for commands from running them. Searching
is performed in find_command(). The result of the search is stored
in a hash table but not as the full path: the path is reconstructed
in shellexec() by combining the directory and command name.
In Windows the command name is insufficient, as the executable name
may also include an extension. To resolve this we must ensure that
extensions are processed in the same order in find_command, shellexec
and any other places where command names are resolved into file names.
The order used matches that of spawnve: .com, .exe, .bat, .cmd.
Finally the bare filename with no additional extension
The order has been made consistent:
- in find_command for absolute paths and the Windows-specific path
search;
- in tryexec (which is called by shellexec) where an additional test
that the file is executable has been added;
- in the type and hash built-ins where the output has been modified to
include the extension.
Additionally, the code in tryexec to handle ENOEXEC errors from
execve has been excluded. The rationale for the exec functions
in POSIX [1] suggests the requirement to retry is a workaround
for the lack of '#!' support on some platforms.
[1] http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html
-rw-r--r-- | shell/ash.c | 78 |
1 files changed, 55 insertions, 23 deletions
diff --git a/shell/ash.c b/shell/ash.c index 7dec5dfc7..fa71bd84d 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -8318,6 +8318,10 @@ static int builtinloc = -1; /* index in path of %builtin, or -1 */ | |||
8318 | static void | 8318 | static void |
8319 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp) | 8319 | tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, char **envp) |
8320 | { | 8320 | { |
8321 | #if ENABLE_PLATFORM_MINGW32 | ||
8322 | char *new_cmd; | ||
8323 | #endif | ||
8324 | |||
8321 | #if ENABLE_FEATURE_SH_STANDALONE | 8325 | #if ENABLE_FEATURE_SH_STANDALONE |
8322 | if (applet_no >= 0) { | 8326 | if (applet_no >= 0) { |
8323 | if (APPLET_IS_NOEXEC(applet_no)) { | 8327 | if (APPLET_IS_NOEXEC(applet_no)) { |
@@ -8334,6 +8338,16 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
8334 | } | 8338 | } |
8335 | #endif | 8339 | #endif |
8336 | 8340 | ||
8341 | #if ENABLE_PLATFORM_MINGW32 | ||
8342 | /* ensure we have a path to a real, executable file */ | ||
8343 | if (!(new_cmd=add_win32_extension(cmd)) && !file_is_executable(cmd)) { | ||
8344 | errno = EACCES; | ||
8345 | return; | ||
8346 | } | ||
8347 | execve(new_cmd ? new_cmd : cmd, argv, envp); | ||
8348 | free(new_cmd); | ||
8349 | /* skip POSIX-mandated retry on ENOEXEC */ | ||
8350 | #else | ||
8337 | repeat: | 8351 | repeat: |
8338 | #ifdef SYSV | 8352 | #ifdef SYSV |
8339 | do { | 8353 | do { |
@@ -8368,6 +8382,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c | |||
8368 | argv[0] = (char*) "ash"; | 8382 | argv[0] = (char*) "ash"; |
8369 | goto repeat; | 8383 | goto repeat; |
8370 | } | 8384 | } |
8385 | #endif | ||
8371 | } | 8386 | } |
8372 | 8387 | ||
8373 | /* | 8388 | /* |
@@ -8437,6 +8452,9 @@ printentry(struct tblentry *cmdp) | |||
8437 | int idx; | 8452 | int idx; |
8438 | const char *path; | 8453 | const char *path; |
8439 | char *name; | 8454 | char *name; |
8455 | #if ENABLE_PLATFORM_MINGW32 | ||
8456 | char *n; | ||
8457 | #endif | ||
8440 | 8458 | ||
8441 | idx = cmdp->param.index; | 8459 | idx = cmdp->param.index; |
8442 | path = pathval(); | 8460 | path = pathval(); |
@@ -8444,7 +8462,14 @@ printentry(struct tblentry *cmdp) | |||
8444 | name = path_advance(&path, cmdp->cmdname); | 8462 | name = path_advance(&path, cmdp->cmdname); |
8445 | stunalloc(name); | 8463 | stunalloc(name); |
8446 | } while (--idx >= 0); | 8464 | } while (--idx >= 0); |
8465 | #if ENABLE_PLATFORM_MINGW32 | ||
8466 | if ((n=add_win32_extension(name)) != NULL) | ||
8467 | name = n; | ||
8468 | #endif | ||
8447 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); | 8469 | out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); |
8470 | #if ENABLE_PLATFORM_MINGW32 | ||
8471 | free(n); | ||
8472 | #endif | ||
8448 | } | 8473 | } |
8449 | 8474 | ||
8450 | /* | 8475 | /* |
@@ -8832,6 +8857,9 @@ describe_command(char *command, const char *path, int describe_command_verbose) | |||
8832 | case CMDNORMAL: { | 8857 | case CMDNORMAL: { |
8833 | int j = entry.u.index; | 8858 | int j = entry.u.index; |
8834 | char *p; | 8859 | char *p; |
8860 | #if ENABLE_PLATFORM_MINGW32 | ||
8861 | char *q; | ||
8862 | #endif | ||
8835 | if (j < 0) { | 8863 | if (j < 0) { |
8836 | p = command; | 8864 | p = command; |
8837 | } else { | 8865 | } else { |
@@ -8840,11 +8868,18 @@ describe_command(char *command, const char *path, int describe_command_verbose) | |||
8840 | stunalloc(p); | 8868 | stunalloc(p); |
8841 | } while (--j >= 0); | 8869 | } while (--j >= 0); |
8842 | } | 8870 | } |
8871 | #if ENABLE_PLATFORM_MINGW32 | ||
8872 | if ((q=add_win32_extension(p)) != NULL) | ||
8873 | p = q; | ||
8874 | #endif | ||
8843 | if (describe_command_verbose) { | 8875 | if (describe_command_verbose) { |
8844 | out1fmt(" is %s", p); | 8876 | out1fmt(" is %s", p); |
8845 | } else { | 8877 | } else { |
8846 | out1str(p); | 8878 | out1str(p); |
8847 | } | 8879 | } |
8880 | #if ENABLE_PLATFORM_MINGW32 | ||
8881 | free(q); | ||
8882 | #endif | ||
8848 | break; | 8883 | break; |
8849 | } | 8884 | } |
8850 | 8885 | ||
@@ -13647,16 +13682,21 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13647 | int e; | 13682 | int e; |
13648 | int updatetbl; | 13683 | int updatetbl; |
13649 | struct builtincmd *bcmd; | 13684 | struct builtincmd *bcmd; |
13685 | #if ENABLE_PLATFORM_MINGW32 | ||
13686 | extern const char win_suffix[4][4]; | ||
13687 | int i, len; | ||
13688 | #endif | ||
13650 | 13689 | ||
13651 | /* If name contains a slash, don't use PATH or hash table */ | 13690 | /* If name contains a slash, don't use PATH or hash table */ |
13652 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) { | 13691 | if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) { |
13653 | entry->u.index = -1; | 13692 | entry->u.index = -1; |
13654 | if (act & DO_ABS) { | 13693 | if (act & DO_ABS) { |
13655 | while (stat(name, &statb) < 0 | ||
13656 | #if ENABLE_PLATFORM_MINGW32 | 13694 | #if ENABLE_PLATFORM_MINGW32 |
13657 | && (fullname=add_win32_extension(name)) == NULL | 13695 | while ((fullname=add_win32_extension(name)) == NULL || |
13696 | stat(name, &statb) < 0 ) { | ||
13697 | #else | ||
13698 | while (stat(name, &statb) < 0) { | ||
13658 | #endif | 13699 | #endif |
13659 | ) { | ||
13660 | #ifdef SYSV | 13700 | #ifdef SYSV |
13661 | if (errno == EINTR) | 13701 | if (errno == EINTR) |
13662 | continue; | 13702 | continue; |
@@ -13770,34 +13810,26 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
13770 | goto success; | 13810 | goto success; |
13771 | } | 13811 | } |
13772 | #if ENABLE_PLATFORM_MINGW32 | 13812 | #if ENABLE_PLATFORM_MINGW32 |
13773 | if (has_exe_suffix(fullname)) { | 13813 | /* first try appending suffixes (unless there's one already) */ |
13774 | if (stat(fullname, &statb) < 0) { | 13814 | i = 4; |
13775 | if (errno != ENOENT && errno != ENOTDIR) | 13815 | len = strlen(fullname); |
13776 | e = errno; | 13816 | if (!has_exe_suffix_or_dot(fullname)) { |
13777 | goto loop; | ||
13778 | } | ||
13779 | } | ||
13780 | else { | ||
13781 | extern const char win_suffix[4][4]; | ||
13782 | int i, len; | ||
13783 | |||
13784 | /* path_advance() has reserved space for suffix */ | 13817 | /* path_advance() has reserved space for suffix */ |
13785 | len = strlen(fullname); | ||
13786 | fullname[len] = '.'; | 13818 | fullname[len] = '.'; |
13787 | for (i=0; i<4; ++i) { | 13819 | for (i=0; i<4; ++i) { |
13788 | memcpy(fullname+len+1, win_suffix[i], 4); | 13820 | memcpy(fullname+len+1, win_suffix[i], 4); |
13789 | if (stat(fullname, &statb) == 0) | 13821 | if (stat(fullname, &statb) == 0) |
13790 | break; | 13822 | break; |
13791 | } | 13823 | } |
13792 | fullname[len] = '\0'; | 13824 | } |
13793 | 13825 | ||
13794 | if (i == 4) { | 13826 | if (i == 4) { |
13795 | /* suffix didn't work, try without */ | 13827 | /* adding a suffix failed (or wasn't tried), try original */ |
13796 | if (stat(fullname, &statb) < 0) { | 13828 | fullname[len] = '\0'; |
13797 | if (errno != ENOENT && errno != ENOTDIR) | 13829 | if (stat(fullname, &statb) < 0) { |
13798 | e = errno; | 13830 | if (errno != ENOENT && errno != ENOTDIR) |
13799 | goto loop; | 13831 | e = errno; |
13800 | } | 13832 | goto loop; |
13801 | } | 13833 | } |
13802 | } | 13834 | } |
13803 | #else | 13835 | #else |