[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
}
}