Cygwin's execlp() does not work with an empty $PATH element
Takashi Yano
takashi.yano@nifty.ne.jp
Mon Jun 27 11:16:36 GMT 2022
On Sun, 26 Jun 2022 15:09:34 +0000
"Lavrentiev, Anton \(NIH/NLM/NCBI\) \[C\] wrote:
> An empty PATH element (":xxx" or "xxx::xxx" or "xxx:") is to be considered as the current directory (from the very first days of Unix).
>
> However, Cygwin does not seem to obey the rule.
>
> Consider the following simple C program:
>
> $ cat hello.c
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
>
> int main(int argc, const char* argv[])
> {
> if (argc < 2) {
> const char* prog = strrchr(argv[0], '/');
> if (!prog++)
> prog = argv[0];
> execlp(prog, prog, "Hello", NULL); // execute just by the program name
> perror("exec");
> return 1;
> }
> printf("%s\n", argv[1]);
> return 0;
> }
>
> Now compare the execution on Linux and Cygwin:
>
> Linux:
>
> $ gcc -Wall -o hello hello.c
> $ hello
> bash: hello: command not found
> $ ./hello
> exec: No such file or directory
> $ PATH=".:$PATH" ./hello
> Hello
> $ PATH=":$PATH" ./hello
> Hello
> $ PATH="${PATH}:" ./hello
> Hello
>
> Cygwin:
>
> $ gcc -Wall -o hello hello.c
> $ hello
> -bash: hello: command not found
> $ ./hello
> exec: No such file or directory
> $ PATH=".:$PATH" ./hello
> Hello
> $ PATH=":$PATH" ./hello
> exec: No such file or directory
> $ PATH="${PATH}:" ./hello
> exec: No such file or directory
>
> As you can see, the execution failed when an empty PATH element was added on Cygwin
> (yet it was perfectly fine on Linux).
How about the following patch?
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index e0f1247e1..8fe9d089f 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -118,8 +118,10 @@ find_exec (const char *name, path_conv& buf, const char *search,
the name of an environment variable. */
if (strchr (search, '/'))
*stpncpy (tmp, search, NT_MAX_PATH - 1) = '\0';
- else if (has_slash || isdrive (name) || !(path = getenv (search)) || !*path)
+ else if (has_slash || isdrive (name))
goto errout;
+ else if (!(path = getenv (search)) || !*path)
+ strcpy (tmp, "."); /* Search the current directory when PATH is absent */
else
*stpncpy (tmp, path, NT_MAX_PATH - 1) = '\0';
@@ -134,7 +136,9 @@ find_exec (const char *name, path_conv& buf, const char *search,
already tried that. */
if ((opt & FE_CWD) && (tmp_path[0] == '\0'
|| (tmp_path[0] == '.' && tmp_path[1] == '\0')))
- continue;
+ goto next;
+ else if (tmp_path[0] == '\0') /* An empty path means the current dir. */
+ eotmp = stpcpy (tmp_path, ".");
*eotmp++ = '/';
stpcpy (eotmp, name);
@@ -146,7 +150,7 @@ find_exec (const char *name, path_conv& buf, const char *search,
if ((suffix = perhaps_suffix (tmp_path, buf, err1, opt)) != NULL)
{
if (buf.has_acls () && check_file_access (buf, X_OK, true))
- continue;
+ goto next;
/* Overwrite potential symlink target with original path.
See comment preceeding this method. */
buf.set_posix (tmp_path);
@@ -154,8 +158,13 @@ find_exec (const char *name, path_conv& buf, const char *search,
goto out;
}
+next:
+ if (*path == '\0')
+ break;
+ if (*path == ':')
+ path++;
}
- while (*path && *++path);
+ while (true);
errout:
/* Couldn't find anything in the given path.
--
Takashi Yano <takashi.yano@nifty.ne.jp>
More information about the Cygwin
mailing list