From: Bruno Haible Date: Mon, 14 Dec 2020 19:56:04 +0000 (+0100) Subject: findprog-in: Allow overriding the current directory. X-Git-Tag: v1.0~3367 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=0299e540e47d71207081f87de6ec7aa2ceed5d25;p=gnulib.git findprog-in: Allow overriding the current directory. * lib/findprog.h (find_in_given_path): Add directory argument. * lib/findprog-in.c (find_in_given_path): Likewise. * lib/execute.c (execute): Update caller. * lib/spawn-pipe.c (create_pipe): Likewise. * lib/windows-spawn.c (spawnpvech): Likewise. * NEWS: Mention the change. --- diff --git a/ChangeLog b/ChangeLog index f909f61222..1a8e1a1c49 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2020-12-14 Bruno Haible + + findprog-in: Allow overriding the current directory. + * lib/findprog.h (find_in_given_path): Add directory argument. + * lib/findprog-in.c (find_in_given_path): Likewise. + * lib/execute.c (execute): Update caller. + * lib/spawn-pipe.c (create_pipe): Likewise. + * lib/windows-spawn.c (spawnpvech): Likewise. + * NEWS: Mention the change. + 2020-12-14 Bruno Haible posix_spawn-internal: Make better use of 'const'. diff --git a/NEWS b/NEWS index f484881ecb..09d1987fb6 100644 --- a/NEWS +++ b/NEWS @@ -60,6 +60,11 @@ User visible incompatible changes Date Modules Changes +2020-12-14 findprog-in The function 'find_in_given_path' now takes a 3rd + argument 'const char *directory'. To maintain the + previous behaviour, insert NULL as additional 3rd + argument. + 2020-12-11 sh-quote The argv argument of the 'shell_quote_argv' function is now of type 'const char * const *'. You no longer need to cast read-only strings to 'char *' diff --git a/lib/execute.c b/lib/execute.c index bdc0c0c016..41a2239c8d 100644 --- a/lib/execute.c +++ b/lib/execute.c @@ -126,7 +126,7 @@ execute (const char *progname, if (! IS_ABSOLUTE_FILE_NAME (prog_path)) { const char *resolved_prog = - find_in_given_path (prog_path, getenv ("PATH"), false); + find_in_given_path (prog_path, getenv ("PATH"), NULL, false); if (resolved_prog == NULL) goto fail_with_errno; if (resolved_prog != prog_path) diff --git a/lib/findprog-in.c b/lib/findprog-in.c index 863f67e13f..63b8419630 100644 --- a/lib/findprog-in.c +++ b/lib/findprog-in.c @@ -73,7 +73,7 @@ static const char * const suffixes[] = const char * find_in_given_path (const char *progname, const char *path, - bool optimize_for_exec) + const char *directory, bool optimize_for_exec) { { bool has_slash = false; @@ -101,6 +101,12 @@ find_in_given_path (const char *progname, const char *path, with such a suffix is actually executable. */ int failure_errno; size_t i; + + const char *directory_as_prefix = + (directory != NULL && IS_RELATIVE_FILE_NAME (progname) + ? directory + : ""); + #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */ const char *progbasename; @@ -126,9 +132,10 @@ find_in_given_path (const char *progname, const char *path, if ((*suffix != '\0') != (strchr (progbasename, '.') != NULL)) #endif { - /* Concatenate progname and suffix. */ + /* Concatenate directory_as_prefix, progname, suffix. */ char *progpathname = - concatenated_filename ("", progname, suffix); + concatenated_filename (directory_as_prefix, progname, + suffix); if (progpathname == NULL) return NULL; /* errno is set here */ @@ -194,6 +201,8 @@ find_in_given_path (const char *progname, const char *path, { const char *dir; bool last; + char *dir_as_prefix_to_free; + const char *dir_as_prefix; size_t i; /* Extract next directory in PATH. */ @@ -207,6 +216,25 @@ find_in_given_path (const char *progname, const char *path, if (dir == cp) dir = "."; + /* Concatenate directory and dir. */ + if (directory != NULL && IS_RELATIVE_FILE_NAME (dir)) + { + dir_as_prefix_to_free = + concatenated_filename (directory, dir, NULL); + if (dir_as_prefix_to_free == NULL) + { + /* errno is set here. */ + failure_errno = errno; + goto failed; + } + dir_as_prefix = dir_as_prefix_to_free; + } + else + { + dir_as_prefix_to_free = NULL; + dir_as_prefix = dir; + } + /* Try all platform-dependent suffixes. */ for (i = 0; i < sizeof (suffixes) / sizeof (suffixes[0]); i++) { @@ -218,14 +246,15 @@ find_in_given_path (const char *progname, const char *path, if ((*suffix != '\0') != (strchr (progname, '.') != NULL)) #endif { - /* Concatenate dir, progname, and suffix. */ + /* Concatenate dir_as_prefix, progname, and suffix. */ char *progpathname = - concatenated_filename (dir, progname, suffix); + concatenated_filename (dir_as_prefix, progname, suffix); if (progpathname == NULL) { /* errno is set here. */ failure_errno = errno; + free (dir_as_prefix_to_free); goto failed; } @@ -249,7 +278,7 @@ find_in_given_path (const char *progname, const char *path, free (progpathname); /* Add the "./" prefix for real, that - xconcatenated_filename() optimized away. + concatenated_filename() optimized away. This avoids a second PATH search when the caller uses execl/execv/execlp/execvp. */ progpathname = @@ -258,6 +287,7 @@ find_in_given_path (const char *progname, const char *path, { /* errno is set here. */ failure_errno = errno; + free (dir_as_prefix_to_free); goto failed; } progpathname[0] = '.'; @@ -266,6 +296,7 @@ find_in_given_path (const char *progname, const char *path, strlen (progname) + 1); } + free (dir_as_prefix_to_free); free (path_copy); return progpathname; } @@ -281,6 +312,8 @@ find_in_given_path (const char *progname, const char *path, } } + free (dir_as_prefix_to_free); + if (last) break; } diff --git a/lib/findprog.h b/lib/findprog.h index c020290d87..6e21aa2a83 100644 --- a/lib/findprog.h +++ b/lib/findprog.h @@ -42,6 +42,10 @@ extern const char *find_in_path (const char *progname); directory. A null PATH is equivalent to an empty PATH, that is, to the singleton list that contains only the current directory. + If DIRECTORY is not NULL, all relative filenames (i.e. PROGNAME when it + contains a slash, and the PATH elements) are considered relative to + DIRECTORY instead of relative to the current directory of this process. + Determines the pathname that would be called by execlp/execvp of PROGNAME. - If successful, it returns a pathname containing a slash (either absolute or relative to the current directory). The returned string can be used @@ -62,6 +66,7 @@ extern const char *find_in_path (const char *progname); - On POSIX systems excluding Cygwin: a '/', - On Windows, OS/2, DOS platforms: a '/' or '\'. */ extern const char *find_in_given_path (const char *progname, const char *path, + const char *directory, bool optimize_for_exec); diff --git a/lib/spawn-pipe.c b/lib/spawn-pipe.c index bd34959d50..d48352097b 100644 --- a/lib/spawn-pipe.c +++ b/lib/spawn-pipe.c @@ -154,7 +154,7 @@ create_pipe (const char *progname, if (! IS_ABSOLUTE_FILE_NAME (prog_path)) { const char *resolved_prog = - find_in_given_path (prog_path, getenv ("PATH"), false); + find_in_given_path (prog_path, getenv ("PATH"), NULL, false); if (resolved_prog == NULL) goto fail_with_errno; if (resolved_prog != prog_path) diff --git a/lib/windows-spawn.c b/lib/windows-spawn.c index 509727c74e..19251aea97 100644 --- a/lib/windows-spawn.c +++ b/lib/windows-spawn.c @@ -223,7 +223,7 @@ spawnpvech (int mode, /* Implement the 'p' letter: search for PROGNAME in getenv ("PATH"). */ const char *resolved_progname = - find_in_given_path (progname, getenv ("PATH"), false); + find_in_given_path (progname, getenv ("PATH"), NULL, false); if (resolved_progname == NULL) return -1;