bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] findprog: Support searching in a specified path string


From: Bruno Haible
Subject: Re: [PATCH] findprog: Support searching in a specified path string
Date: Mon, 09 Sep 2019 20:54:22 +0200
User-agent: KMail/5.1.3 (Linux/4.4.0-159-generic; KDE/5.18.0; x86_64; ; )

Paul Smith wrote:
> Having PATH= be equivalent to PATH=., and even
> moreso "unset PATH" be equivalent to PATH=., is quite odd IMO.

It is just as odd as the fact that
  PATH=:/bin is equivalent to PATH=.:/bin
and
  PATH=/bin: is equivalent to PATH=/bin:.

> > > My personal opinion is that it's not difficult to come up with ways
> > > findprog can be useful _in addition_ to simply being a precursor to
> > > exec
> > 
> > In this case we should probably add a flag argument that tells the
> > function to do the complete lookup also when the progname contains a
> > slash. For now, until someone claims that this functionality would
> > be actually useful, I'll leave it as is.
> 
> I think this will not be needed.  In the event that someone does need
> this they can simply use the findprog-in module instead.

That's not what I meant. Hope it's clearer with this patch (which I'll
push once savannah is working again).


2019-09-09  Bruno Haible  <address@hidden>

        findprog-in: Make exec optimization optional.
        * lib/findprog.h: Add double-inclusion guard. Include <stdbool.h>.
        (find_in_given_path): Add optimize_for_exec parameter.
        * lib/findprog-in.c (find_in_given_path): Likewise.

diff --git a/lib/findprog.h b/lib/findprog.h
index 9bc8a60..f7b4407 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 <https://www.gnu.org/licenses/>.  */
 
+#ifndef _FINDPROG_H
+#define _FINDPROG_H
+
+#include <stdbool.h>
 
 #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 */
diff --git a/lib/findprog-in.c b/lib/findprog-in.c
index 3d70b7b..99b3c31 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!  */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]