From f5783ef14f9ad96ae483f16e639953d0212ca7d0 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Wed, 28 Feb 2018 19:57:02 +0000 Subject: win32: additional improvements to handling of executables Consistent processing of file extensions, as described in the previous commit, has been applied to the 'which' applet and the functions find_executable and mingw_spawn_interpreter. In spawnveq check that the file to be executed exists and is executable, and ensure that it won't have any extensions added by spawnve. It's intended that all files passed to spawnve should have their names fully specified. If this isn't the case the tests here will cause errors which will need to be fixed. --- debianutils/which.c | 11 ++++++----- libbb/executable.c | 12 ++++++------ win32/process.c | 34 ++++++++++++++++++++++++---------- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/debianutils/which.c b/debianutils/which.c index 9060a5b47..0b0a6a645 100644 --- a/debianutils/which.c +++ b/debianutils/which.c @@ -66,17 +66,18 @@ int which_main(int argc UNUSED_PARAM, char **argv) /* If file contains a slash don't use PATH */ if (strchr(*argv, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(*argv, '\\'))) { - if (file_is_executable(*argv)) { - missing = 0; - puts(*argv); - } #if ENABLE_PLATFORM_MINGW32 - else if ((p=add_win32_extension(*argv)) != NULL) { + if ((p=add_win32_extension(*argv)) != NULL) { missing = 0; puts(p); free(p); } + else #endif + if (file_is_executable(*argv)) { + missing = 0; + puts(*argv); + } } else { char *path; diff --git a/libbb/executable.c b/libbb/executable.c index 76b10f790..aec829945 100644 --- a/libbb/executable.c +++ b/libbb/executable.c @@ -66,23 +66,23 @@ char* FAST_FUNC find_executable(const char *filename, char **PATHp) p[0] ? p : ".", /* handle "::" case */ filename ); - ex = file_is_executable(p); #if ENABLE_PLATFORM_MINGW32 if (n) *n++ = sep; #else if (n) *n++ = ':'; #endif - if (ex) { - *PATHp = n; - return p; - } #if ENABLE_PLATFORM_MINGW32 - else if ((w=add_win32_extension(p))) { + if ((w=add_win32_extension(p))) { *PATHp = n; free(p); return w; } #endif + ex = file_is_executable(p); + if (ex) { + *PATHp = n; + return p; + } free(p); p = n; } /* on loop exit p == NULL */ diff --git a/win32/process.c b/win32/process.c index eda143e0e..96561c482 100644 --- a/win32/process.c +++ b/win32/process.c @@ -195,6 +195,23 @@ spawnveq(int mode, const char *path, char *const *argv, char *const *env) char *new_path = NULL; int i, argc = -1; intptr_t ret; + struct stat st; + + /* + * Require that the file exists, is a regular file and is executable. + * It may still contain garbage but we let spawnve deal with that. + */ + if (stat(path, &st) == 0) { + if (!S_ISREG(st.st_mode) || !(st.st_mode&S_IXUSR)) { + errno = EACCES; + fprintf(stderr, "spawnveq: %s: %s\n", path, strerror(errno)); + return -1; + } + } + else { + fprintf(stderr, "spawnveq: %s: %s\n", path, strerror(errno)); + return -1; + } while (argv[++argc]) ; @@ -233,15 +250,12 @@ spawnveq(int mode, const char *path, char *const *argv, char *const *env) } /* - * Another special case: if a binary executable doesn't have an - * extension spawnve will only run it if the filename ends with a '.'. + * Another special case: if a file doesn't have an extension add + * a '.' at the end. This forces spawnve to use precisely the + * file specified without trying to add an extension. */ - if (!has_exe_suffix(path)) { - int len = strlen(path); - - if (path[len-1] != '.' && has_exec_format(path)) { - new_path = xasprintf("%s.", path); - } + if (!strchr(bb_basename(path), '.')) { + new_path = xasprintf("%s.", path); } ret = spawnve(mode, new_path ? new_path : path, new_argv, env); @@ -288,8 +302,8 @@ mingw_spawn_interpreter(int mode, const char *prog, char *const *argv, char *con new_argv[nopts+1] = (char *)prog; /* pass absolute path */ memcpy(new_argv+nopts+2, argv+1, sizeof(*argv)*argc); - if (file_is_executable(int_path) || - (fullpath=add_win32_extension(int_path)) != NULL) { + if ((fullpath=add_win32_extension(int_path)) != NULL || + file_is_executable(int_path)) { new_argv[0] = fullpath ? fullpath : int_path; ret = spawnveq(mode, new_argv[0], new_argv, envp); } else -- cgit v1.2.3-55-g6feb