From 5b586b1ef88b79afcc5e2d98ec50dc360a7fb2a4 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Mon, 9 Sep 2019 20:46:44 +0200 Subject: findprog-in: Make exec optimization optional. * lib/findprog.h: Add double-inclusion guard. Include . (find_in_given_path): Add optimize_for_exec parameter. * lib/findprog-in.c (find_in_given_path): Likewise. --- ChangeLog | 7 ++++ lib/findprog-in.c | 98 +++++++++++++++++++++++++++++++++++++++++++------------ lib/findprog.h | 14 ++++++-- 3 files changed, 97 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index b2d2b00448..8ca2a33052 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2019-09-09 Bruno Haible + + findprog-in: Make exec optimization optional. + * lib/findprog.h: Add double-inclusion guard. Include . + (find_in_given_path): Add optimize_for_exec parameter. + * lib/findprog-in.c (find_in_given_path): Likewise. + 2019-09-08 Bruno Haible Add option to assume the best, not the worst, when cross-compiling. diff --git a/lib/findprog-in.c b/lib/findprog-in.c index 3d70b7b393..99b3c314d9 100644 --- a/lib/findprog-in.c +++ b/lib/findprog-in.c @@ -71,26 +71,84 @@ static const char * const suffixes[] = }; const char * -find_in_given_path (const char *progname, const char *path) +find_in_given_path (const char *progname, const char *path, + bool optimize_for_exec) { { bool has_slash = false; - const char *p; + { + const char *p; - for (p = progname; *p != '\0'; p++) - if (ISSLASH (*p)) - { - has_slash = true; - break; - } + for (p = progname; *p != '\0'; p++) + if (ISSLASH (*p)) + { + has_slash = true; + break; + } + } if (has_slash) - /* If progname contains a slash, it is either absolute or relative to - the current directory. PATH is not used. - We could try the various suffixes and see whether one of the files - with such a suffix is actually executable. But this is not needed, - since the execl/execv/execlp/execvp functions will do these tests - anyway. */ - return progname; + { + /* If progname contains a slash, it is either absolute or relative to + the current directory. PATH is not used. */ + if (optimize_for_exec) + /* The execl/execv/execlp/execvp functions will try the various + suffixes anyway and fail if no executable is found. */ + return progname; + else + { + /* Try the various suffixes and see whether one of the files + with such a suffix is actually executable. */ + size_t i; + #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */ + const char *progbasename; + + { + const char *p; + + progbasename = progname; + for (p = progname; *p != '\0'; p++) + if (ISSLASH (*p)) + progbasename = p + 1; + } + #endif + + /* Try all platform-dependent suffixes. */ + for (i = 0; i < sizeof (suffixes) / sizeof (suffixes[0]); i++) + { + const char *suffix = suffixes[i]; + + #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */ + /* File names without a '.' are not considered executable. */ + if (*suffix != '\0' || strchr (progbasename, '.') != NULL) + #endif + { + /* Concatenate progname and suffix. */ + char *progpathname = + xconcatenated_filename ("", progname, suffix); + + /* On systems which have the eaccess() system call, let's + use it. On other systems, let's hope that this program + is not installed setuid or setgid, so that it is ok to + call access() despite its design flaw. */ + if (eaccess (progpathname, X_OK) == 0) + { + /* Found! */ + if (strcmp (progpathname, progname) == 0) + { + free (progpathname); + return progname; + } + else + return progpathname; + } + + free (progpathname); + } + } + + return NULL; + } + } } if (path == NULL) @@ -131,14 +189,14 @@ find_in_given_path (const char *progname, const char *path) if (*suffix != '\0' || strchr (progname, '.') != NULL) #endif { - /* Concatenate dir and progname. */ + /* Concatenate dir, progname, and suffix. */ char *progpathname = xconcatenated_filename (dir, progname, suffix); - /* On systems which have the eaccess() system call, let's use - it. On other systems, let's hope that this program is not - installed setuid or setgid, so that it is ok to call - access() despite its design flaw. */ + /* On systems which have the eaccess() system call, let's + use it. On other systems, let's hope that this program + is not installed setuid or setgid, so that it is ok to + call access() despite its design flaw. */ if (eaccess (progpathname, X_OK) == 0) { /* Found! */ diff --git a/lib/findprog.h b/lib/findprog.h index 9bc8a60da2..f7b44071fb 100644 --- a/lib/findprog.h +++ b/lib/findprog.h @@ -15,6 +15,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#ifndef _FINDPROG_H +#define _FINDPROG_H + +#include #ifdef __cplusplus extern "C" { @@ -41,10 +45,16 @@ extern const char *find_in_path (const char *progname); or relative to the current directory). The returned string can be used with either execl/execv or execlp/execvp. It is freshly malloc()ed if it is != PROGNAME. - - Otherwise, it returns NULL. */ -extern const char *find_in_given_path (const char *progname, const char *path); + - Otherwise, it returns NULL. + If OPTIMIZE_FOR_EXEC is true, the function saves some work, under the + assumption that the resulting pathname will not be accessed directly, + only through execl/execv or execlp/execvp. */ +extern const char *find_in_given_path (const char *progname, const char *path, + bool optimize_for_exec); #ifdef __cplusplus } #endif + +#endif /* _FINDPROG_H */ -- cgit v1.2.1