These few patches are preparations for the posix_spawn implementation for
native Windows.

Note the NEWS entry:

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.

Paul Smith: To accommodate for this change, a 1-liner patch is needed in
GNU make.


2020-12-14  Bruno Haible  <br...@clisp.org>

        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  <br...@clisp.org>

        posix_spawn-internal: Make better use of 'const'.
        * lib/spawn_int.h (__spawni): Does not need write access to the elements
        of argv and envp.
        * lib/spawni.c (__spawni, script_execute): Likewise.
        * lib/spawn.c (posix_spawn): Update caller.
        * lib/spawnp.c (posix_spawnp): Likewise.

2020-12-14  Bruno Haible  <br...@clisp.org>

        spawn: Make it compile on native Windows.
        * modules/spawn (Depends-on): Add signal-h.

2020-12-14  Bruno Haible  <br...@clisp.org>

        windows-spawn: Avoid shadowing a variable.
        * lib/windows-spawn.c (spawnpvech): Rename local variable 'flags'.

>From 62514110dafb876059c4c3654fd200a022ad892c Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Mon, 14 Dec 2020 18:05:38 +0100
Subject: [PATCH 1/4] windows-spawn: Avoid shadowing a variable.

* lib/windows-spawn.c (spawnpvech): Rename local variable 'flags'.
---
 ChangeLog           | 5 +++++
 lib/windows-spawn.c | 5 +++--
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9f9a021..865cc91 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2020-12-14  Bruno Haible  <br...@clisp.org>
+
+	windows-spawn: Avoid shadowing a variable.
+	* lib/windows-spawn.c (spawnpvech): Rename local variable 'flags'.
+
 2020-12-13  Paul Eggert  <egg...@cs.ucla.edu>
 
 	string: port memchr macro to AIX 7.2 XLC
diff --git a/lib/windows-spawn.c b/lib/windows-spawn.c
index 88a6b4d..509727c 100644
--- a/lib/windows-spawn.c
+++ b/lib/windows-spawn.c
@@ -308,7 +308,7 @@ spawnpvech (int mode,
   /* Regarding handle inheritance, see
      <https://docs.microsoft.com/en-us/windows/win32/sysinfo/handle-inheritance>  */
   /* <https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags>  */
-  DWORD flags = (mode == P_DETACH ? DETACHED_PROCESS : 0);
+  DWORD process_creation_flags = (mode == P_DETACH ? DETACHED_PROCESS : 0);
   /* STARTUPINFO
      <https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa>  */
   STARTUPINFO sinfo;
@@ -443,7 +443,8 @@ spawnpvech (int mode,
 
   PROCESS_INFORMATION pinfo;
   if (!CreateProcess (resolved_progname, command, NULL, NULL, TRUE,
-                      flags, envblock, currdir, &sinfo, &pinfo))
+                      process_creation_flags, envblock, currdir, &sinfo,
+                      &pinfo))
     {
       DWORD error = GetLastError ();
 
-- 
2.7.4

>From 12c8567fcbe7e7baf89ba9fadc157e0a336705dc Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Mon, 14 Dec 2020 18:07:28 +0100
Subject: [PATCH 2/4] spawn: Make it compile on native Windows.

* modules/spawn (Depends-on): Add signal-h.
---
 ChangeLog     | 5 +++++
 modules/spawn | 1 +
 2 files changed, 6 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 865cc91..21cc216 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2020-12-14  Bruno Haible  <br...@clisp.org>
 
+	spawn: Make it compile on native Windows.
+	* modules/spawn (Depends-on): Add signal-h.
+
+2020-12-14  Bruno Haible  <br...@clisp.org>
+
 	windows-spawn: Avoid shadowing a variable.
 	* lib/windows-spawn.c (spawnpvech): Rename local variable 'flags'.
 
diff --git a/modules/spawn b/modules/spawn
index f1b99ca..1828d37 100644
--- a/modules/spawn
+++ b/modules/spawn
@@ -9,6 +9,7 @@ m4/pid_t.m4
 Depends-on:
 include_next
 sched
+signal-h
 snippet/arg-nonnull
 snippet/c++defs
 snippet/warn-on-use
-- 
2.7.4

>From 29d55bf8c7d0c5a4a3b4aa2d93d897ff8463eb4c Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Mon, 14 Dec 2020 19:22:14 +0100
Subject: [PATCH 3/4] posix_spawn-internal: Make better use of 'const'.

* lib/spawn_int.h (__spawni): Does not need write access to the elements
of argv and envp.
* lib/spawni.c (__spawni, script_execute): Likewise.
* lib/spawn.c (posix_spawn): Update caller.
* lib/spawnp.c (posix_spawnp): Likewise.
---
 ChangeLog       |  9 +++++++++
 lib/spawn.c     |  3 ++-
 lib/spawn_int.h |  4 ++--
 lib/spawni.c    | 20 +++++++++++---------
 lib/spawnp.c    |  3 ++-
 5 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 21cc216..f909f61 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2020-12-14  Bruno Haible  <br...@clisp.org>
 
+	posix_spawn-internal: Make better use of 'const'.
+	* lib/spawn_int.h (__spawni): Does not need write access to the elements
+	of argv and envp.
+	* lib/spawni.c (__spawni, script_execute): Likewise.
+	* lib/spawn.c (posix_spawn): Update caller.
+	* lib/spawnp.c (posix_spawnp): Likewise.
+
+2020-12-14  Bruno Haible  <br...@clisp.org>
+
 	spawn: Make it compile on native Windows.
 	* modules/spawn (Depends-on): Add signal-h.
 
diff --git a/lib/spawn.c b/lib/spawn.c
index c139b71..b658453 100644
--- a/lib/spawn.c
+++ b/lib/spawn.c
@@ -29,5 +29,6 @@ posix_spawn (pid_t *pid, const char *path,
              const posix_spawnattr_t *attrp, char *const argv[],
              char *const envp[])
 {
-  return __spawni (pid, path, file_actions, attrp, argv, envp, 0);
+  return __spawni (pid, path, file_actions, attrp,
+                   (const char * const *) argv, (const char * const *) envp, 0);
 }
diff --git a/lib/spawn_int.h b/lib/spawn_int.h
index 7c063b6..60a94dd 100644
--- a/lib/spawn_int.h
+++ b/lib/spawn_int.h
@@ -68,5 +68,5 @@ extern int __posix_spawn_file_actions_realloc (posix_spawn_file_actions_t *
 #endif
 extern int __spawni (pid_t *pid, const char *path,
                      const posix_spawn_file_actions_t *file_actions,
-                     const posix_spawnattr_t *attrp, char *const argv[],
-                     char *const envp[], int use_path);
+                     const posix_spawnattr_t *attrp, const char *const argv[],
+                     const char *const envp[], int use_path);
diff --git a/lib/spawni.c b/lib/spawni.c
index 07bbec7..1e20a97 100644
--- a/lib/spawni.c
+++ b/lib/spawni.c
@@ -109,7 +109,8 @@ __spawni (pid_t *pid, const char *file,
    the shell to interpret it as a script.  */
 static void
 internal_function
-script_execute (const char *file, char *const argv[], char *const envp[])
+script_execute (const char *file, const char *const argv[],
+                const char *const envp[])
 {
   /* Count the arguments.  */
   int argc = 0;
@@ -118,9 +119,10 @@ script_execute (const char *file, char *const argv[], char *const envp[])
 
   /* Construct an argument list for the shell.  */
   {
-    char **new_argv = (char **) alloca ((argc + 1) * sizeof (char *));
-    new_argv[0] = (char *) _PATH_BSHELL;
-    new_argv[1] = (char *) file;
+    const char **new_argv =
+      (const char **) alloca ((argc + 1) * sizeof (const char *));
+    new_argv[0] = _PATH_BSHELL;
+    new_argv[1] = file;
     while (argc > 1)
       {
         new_argv[argc] = argv[argc - 1];
@@ -128,7 +130,7 @@ script_execute (const char *file, char *const argv[], char *const envp[])
       }
 
     /* Execute the shell.  */
-    execve (new_argv[0], new_argv, envp);
+    execve (new_argv[0], (char * const *) new_argv, (char * const *) envp);
   }
 }
 
@@ -138,8 +140,8 @@ script_execute (const char *file, char *const argv[], char *const envp[])
 int
 __spawni (pid_t *pid, const char *file,
           const posix_spawn_file_actions_t *file_actions,
-          const posix_spawnattr_t *attrp, char *const argv[],
-          char *const envp[], int use_path)
+          const posix_spawnattr_t *attrp, const char *const argv[],
+          const char *const envp[], int use_path)
 {
   pid_t new_pid;
   char *path, *p, *name;
@@ -303,7 +305,7 @@ __spawni (pid_t *pid, const char *file,
   if (! use_path || strchr (file, '/') != NULL)
     {
       /* The FILE parameter is actually a path.  */
-      execve (file, argv, envp);
+      execve (file, (char * const *) argv, (char * const *) envp);
 
       if (errno == ENOEXEC)
         script_execute (file, argv, envp);
@@ -354,7 +356,7 @@ __spawni (pid_t *pid, const char *file,
         startp = (char *) memcpy (name - (p - path), path, p - path);
 
       /* Try to execute this name.  If it works, execv will not return.  */
-      execve (startp, argv, envp);
+      execve (startp, (char * const *) argv, (char * const *) envp);
 
       if (errno == ENOEXEC)
         script_execute (startp, argv, envp);
diff --git a/lib/spawnp.c b/lib/spawnp.c
index 0f03e79..91c54a1 100644
--- a/lib/spawnp.c
+++ b/lib/spawnp.c
@@ -29,5 +29,6 @@ posix_spawnp (pid_t *pid, const char *file,
               const posix_spawnattr_t *attrp, char *const argv[],
               char *const envp[])
 {
-  return __spawni (pid, file, file_actions, attrp, argv, envp, 1);
+  return __spawni (pid, file, file_actions, attrp,
+                   (const char * const *) argv, (const char * const *) envp, 1);
 }
-- 
2.7.4

>From 0299e540e47d71207081f87de6ec7aa2ceed5d25 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Mon, 14 Dec 2020 20:56:04 +0100
Subject: [PATCH 4/4] 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.
---
 ChangeLog           | 10 ++++++++++
 NEWS                |  5 +++++
 lib/execute.c       |  2 +-
 lib/findprog-in.c   | 45 +++++++++++++++++++++++++++++++++++++++------
 lib/findprog.h      |  5 +++++
 lib/spawn-pipe.c    |  2 +-
 lib/windows-spawn.c |  2 +-
 7 files changed, 62 insertions(+), 9 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index f909f61..1a8e1a1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2020-12-14  Bruno Haible  <br...@clisp.org>
 
+	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  <br...@clisp.org>
+
 	posix_spawn-internal: Make better use of 'const'.
 	* lib/spawn_int.h (__spawni): Does not need write access to the elements
 	of argv and envp.
diff --git a/NEWS b/NEWS
index f484881..09d1987 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 bdc0c0c..41a2239 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 863f67e..63b8419 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 c020290..6e21aa2 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 bd34959..d483520 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 509727c..19251ae 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;
 
-- 
2.7.4

Reply via email to