bug-gnulib
[Top][All Lists]
Advanced

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

Re: posix_spawn[p]: Don't execute scripts without '#!' marker through /b


From: Bruno Haible
Subject: Re: posix_spawn[p]: Don't execute scripts without '#!' marker through /bin/sh
Date: Thu, 24 Dec 2020 13:38:26 +0100
User-agent: KMail/5.1.3 (Linux/4.4.0-197-generic; KDE/5.18.0; x86_64; ; )

The new tests/test-spawn-pipe-script.c test reveals that create_pipe_in
returns an odd errno value when the program is an executable script without
'#!' marker. This patch fixes it.


2020-12-24  Bruno Haible  <bruno@clisp.org>

        findprog-in: Improve errno upon failure on native Windows.
        * lib/findprog-in.c (find_in_given_path): If the file basename has no
        dot and the search with a suffix returned no result, do also a search
        without a suffix, and set errno = ENOEXEC if we find a file in this way.
        * tests/test-spawn-pipe-script.c (main): Update expected errno.

diff --git a/lib/findprog-in.c b/lib/findprog-in.c
index 63b8419..d0505fb 100644
--- a/lib/findprog-in.c
+++ b/lib/findprog-in.c
@@ -118,6 +118,8 @@ find_in_given_path (const char *progname, const char *path,
                 if (ISSLASH (*p))
                   progbasename = p + 1;
             }
+
+            bool progbasename_has_dot = (strchr (progbasename, '.') != NULL);
             #endif
 
             /* Try all platform-dependent suffixes.  */
@@ -129,7 +131,7 @@ find_in_given_path (const char *progname, const char *path,
                 #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */
                 /* File names without a '.' are not considered executable, and
                    for file names with a '.' no additional suffix is tried.  */
-                if ((*suffix != '\0') != (strchr (progbasename, '.') != NULL))
+                if ((*suffix != '\0') != progbasename_has_dot)
                 #endif
                   {
                     /* Concatenate directory_as_prefix, progname, suffix.  */
@@ -174,6 +176,36 @@ find_in_given_path (const char *progname, const char *path,
                     free (progpathname);
                   }
               }
+            #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */
+            if (failure_errno == ENOENT && !progbasename_has_dot)
+              {
+                /* In the loop above, we skipped suffix = "".  Do this loop
+                   round now, merely to provide a better errno than ENOENT.  */
+
+                char *progpathname =
+                  concatenated_filename (directory_as_prefix, progname, "");
+
+                if (progpathname == NULL)
+                  return NULL; /* errno is set here */
+
+                if (eaccess (progpathname, X_OK) == 0)
+                  {
+                    struct stat statbuf;
+
+                    if (stat (progpathname, &statbuf) >= 0)
+                      {
+                        if (! S_ISDIR (statbuf.st_mode))
+                          errno = ENOEXEC;
+                        else
+                          errno = EACCES;
+                      }
+                  }
+
+                failure_errno = errno;
+
+                free (progpathname);
+              }
+            #endif
 
             errno = failure_errno;
             return NULL;
@@ -196,6 +228,10 @@ find_in_given_path (const char *progname, const char *path,
     char *path_rest;
     char *cp;
 
+    #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */
+    bool progname_has_dot = (strchr (progname, '.') != NULL);
+    #endif
+
     failure_errno = ENOENT;
     for (path_rest = path_copy; ; path_rest = cp + 1)
       {
@@ -243,7 +279,7 @@ find_in_given_path (const char *progname, const char *path,
             #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */
             /* File names without a '.' are not considered executable, and
                for file names with a '.' no additional suffix is tried.  */
-            if ((*suffix != '\0') != (strchr (progname, '.') != NULL))
+            if ((*suffix != '\0') != progname_has_dot)
             #endif
               {
                 /* Concatenate dir_as_prefix, progname, and suffix.  */
@@ -311,6 +347,41 @@ find_in_given_path (const char *progname, const char *path,
                 free (progpathname);
               }
           }
+        #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */
+        if (failure_errno == ENOENT && !progname_has_dot)
+          {
+            /* In the loop above, we skipped suffix = "".  Do this loop
+               round now, merely to provide a better errno than ENOENT.  */
+
+            char *progpathname =
+              concatenated_filename (dir_as_prefix, progname, "");
+
+            if (progpathname == NULL)
+              {
+                /* errno is set here.  */
+                failure_errno = errno;
+                free (dir_as_prefix_to_free);
+                goto failed;
+              }
+
+            if (eaccess (progpathname, X_OK) == 0)
+              {
+                struct stat statbuf;
+
+                if (stat (progpathname, &statbuf) >= 0)
+                  {
+                    if (! S_ISDIR (statbuf.st_mode))
+                      errno = ENOEXEC;
+                    else
+                      errno = EACCES;
+                  }
+              }
+
+            failure_errno = errno;
+
+            free (progpathname);
+          }
+        #endif
 
         free (dir_as_prefix_to_free);
 
diff --git a/tests/test-spawn-pipe-script.c b/tests/test-spawn-pipe-script.c
index 44f9d2c..dbd28ed 100644
--- a/tests/test-spawn-pipe-script.c
+++ b/tests/test-spawn-pipe-script.c
@@ -56,11 +56,7 @@ main ()
     else
       {
         ASSERT (pid == -1);
-#if defined _WIN32 && !defined __CYGWIN__
-        ASSERT (errno == ENOENT);
-#else
         ASSERT (errno == ENOEXEC);
-#endif
       }
   }
 




reply via email to

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