]> Savannah Git Hosting - gnulib.git/commitdiff
execute, spawn-pipe: Support DLL dependencies of Windows executables.
authorBruno Haible <bruno@clisp.org>
Tue, 22 Oct 2024 20:08:24 +0000 (22:08 +0200)
committerBruno Haible <bruno@clisp.org>
Tue, 22 Oct 2024 20:08:24 +0000 (22:08 +0200)
Reported by Michele Locati <michele@locati.it>.

* lib/windows-path.h: New file.
* lib/windows-path.c: New file.
* lib/windows-spawn.h (compose_envblock): Add new_PATH parameter.
(spawnpvech): Add dll_dirs parameter. Call extended_PATH.
* lib/windows-spawn.c: Include windows-path.h.
(compose_envblock): Add new_PATH parameter.
* modules/windows-spawn (Description): Now applies to Cygwin as well.
(Files): Add lib/windows-path.h, lib/windows-path.c.
(configure.ac): Define GL_COND_OBJ_WINDOWS_PATH.
(Makefile.am): Conditionally compile windows-path.c.
(Include): Add windows-path.h.
* lib/spawni.c (__spawni): Update compose_envblock call.
* lib/execute.h (execute): Add dll_dirs parameter.
* lib/execute.c: Include windows-path.h.
(execute): Add dll_dirs parameter. Pass it down to spawnpvech. Call
extended_environ.
* lib/spawn-pipe.h (create_pipe_out, create_pipe_in, create_pipe_bidi):
Add dll_dirs parameter.
* lib/spawn-pipe.c: Include windows-path.h.
(create_pipe): Add dll_dirs parameter. Pass it down to spawnpvech. Call
extended_environ.
(create_pipe_bidi, create_pipe_in, create_pipe_out): Add dll_dirs
parameter.
* lib/javaexec.c (execute_java_class): Update execute invocations.
* lib/cygpath.c (execute_and_read_line): Update create_pipe_in
invocation.
* lib/javaversion.c (execute_and_read_line): Likewise.
* lib/csharpcomp.c (compile_csharp_using_mono,
compile_csharp_using_dotnet, compile_csharp_using_sscli): Update
execute, create_pipe_in invocations.
* lib/csharpexec.c (execute_csharp_using_mono,
execute_csharp_using_dotnet, execute_csharp_using_sscli): Likewise.
* lib/javacomp.c (compile_using_envjavac, compile_using_javac,
execute_and_read_line, is_javac_present): Likewise.
* lib/pipe-filter-gi.c (pipe_filter_gi_create): Update create_pipe_bidi
invocation.
* lib/pipe-filter-ii.c (pipe_filter_ii_execute): Likewise.
* tests/test-execute-main.c (main): Update execute invocations.
* tests/test-execute-script.c (main): Likewise.
* tests/test-spawn-pipe-main.c (main): Update create_pipe_bidi
invocation.
* tests/test-spawn-pipe-script.c (main): Update create_pipe_in
invocations.
* NEWS: Mention the changes.

24 files changed:
ChangeLog
NEWS
lib/csharpcomp.c
lib/csharpexec.c
lib/cygpath.c
lib/execute.c
lib/execute.h
lib/javacomp.c
lib/javaexec.c
lib/javaversion.c
lib/pipe-filter-gi.c
lib/pipe-filter-ii.c
lib/spawn-pipe.c
lib/spawn-pipe.h
lib/spawni.c
lib/windows-path.c [new file with mode: 0644]
lib/windows-path.h [new file with mode: 0644]
lib/windows-spawn.c
lib/windows-spawn.h
modules/windows-spawn
tests/test-execute-main.c
tests/test-execute-script.c
tests/test-spawn-pipe-main.c
tests/test-spawn-pipe-script.c

index a9f4da95561779789402429fa859539dad8320d2..f87126240a24ccef7fa115242ed653ceaaff0084 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,52 @@
+2024-10-22  Bruno Haible  <bruno@clisp.org>
+
+       execute, spawn-pipe: Support DLL dependencies of Windows executables.
+       Reported by Michele Locati <michele@locati.it>.
+       * lib/windows-path.h: New file.
+       * lib/windows-path.c: New file.
+       * lib/windows-spawn.h (compose_envblock): Add new_PATH parameter.
+       (spawnpvech): Add dll_dirs parameter. Call extended_PATH.
+       * lib/windows-spawn.c: Include windows-path.h.
+       (compose_envblock): Add new_PATH parameter.
+       * modules/windows-spawn (Description): Now applies to Cygwin as well.
+       (Files): Add lib/windows-path.h, lib/windows-path.c.
+       (configure.ac): Define GL_COND_OBJ_WINDOWS_PATH.
+       (Makefile.am): Conditionally compile windows-path.c.
+       (Include): Add windows-path.h.
+       * lib/spawni.c (__spawni): Update compose_envblock call.
+       * lib/execute.h (execute): Add dll_dirs parameter.
+       * lib/execute.c: Include windows-path.h.
+       (execute): Add dll_dirs parameter. Pass it down to spawnpvech. Call
+       extended_environ.
+       * lib/spawn-pipe.h (create_pipe_out, create_pipe_in, create_pipe_bidi):
+       Add dll_dirs parameter.
+       * lib/spawn-pipe.c: Include windows-path.h.
+       (create_pipe): Add dll_dirs parameter. Pass it down to spawnpvech. Call
+       extended_environ.
+       (create_pipe_bidi, create_pipe_in, create_pipe_out): Add dll_dirs
+       parameter.
+       * lib/javaexec.c (execute_java_class): Update execute invocations.
+       * lib/cygpath.c (execute_and_read_line): Update create_pipe_in
+       invocation.
+       * lib/javaversion.c (execute_and_read_line): Likewise.
+       * lib/csharpcomp.c (compile_csharp_using_mono,
+       compile_csharp_using_dotnet, compile_csharp_using_sscli): Update
+       execute, create_pipe_in invocations.
+       * lib/csharpexec.c (execute_csharp_using_mono,
+       execute_csharp_using_dotnet, execute_csharp_using_sscli): Likewise.
+       * lib/javacomp.c (compile_using_envjavac, compile_using_javac,
+       execute_and_read_line, is_javac_present): Likewise.
+       * lib/pipe-filter-gi.c (pipe_filter_gi_create): Update create_pipe_bidi
+       invocation.
+       * lib/pipe-filter-ii.c (pipe_filter_ii_execute): Likewise.
+       * tests/test-execute-main.c (main): Update execute invocations.
+       * tests/test-execute-script.c (main): Likewise.
+       * tests/test-spawn-pipe-main.c (main): Update create_pipe_bidi
+       invocation.
+       * tests/test-spawn-pipe-script.c (main): Update create_pipe_in
+       invocations.
+       * NEWS: Mention the changes.
+
 2024-10-21  Bruno Haible  <bruno@clisp.org>
 
        reallocarray: Don't assume unportable behaviour of realloc.
diff --git a/NEWS b/NEWS
index bd120be0b3a436d61636067db82eedb6d04e09b4..7c48798dbffff0808dc62399c2ce1132a9640d43 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -74,6 +74,17 @@ User visible incompatible changes
 
 Date        Modules         Changes
 
+2024-10-22  spawn-pipe      The functions 'create_pipe_out', 'create_pipe_in',
+                            'create_pipe_bidi' now take a 4th argument
+                            'const char * const *dll_dirs'. To maintain the
+                            previous behaviour, insert NULL as additional 4th
+                            argument.
+
+2024-10-22  execute         The function 'execute' now takes a 4th argument
+                            'const char * const *dll_dirs'. To maintain the
+                            previous behaviour, insert NULL as additional 4th
+                            argument.
+
 2024-10-02  file-has-acl    The file_has_aclinfo function introduced 3 days ago
                             now has a different signature.
 
index 4874061e60061d3ff78107ceff94bb27df852ae1..f0a941fd26b73f94d7daffdbd1ec8fca9648c40a 100644 (file)
@@ -106,7 +106,7 @@ compile_csharp_using_mono (const char * const *sources,
       argv[0] = "mcs";
       argv[1] = "--version";
       argv[2] = NULL;
-      child = create_pipe_in ("mcs", "mcs", argv, NULL,
+      child = create_pipe_in ("mcs", "mcs", argv, NULL, NULL,
                               DEV_NULL, true, true, false, fd);
       mcs_present = false;
       if (child != -1)
@@ -215,7 +215,7 @@ compile_csharp_using_mono (const char * const *sources,
           free (command);
         }
 
-      child = create_pipe_in ("mcs", "mcs", argv, NULL,
+      child = create_pipe_in ("mcs", "mcs", argv, NULL, NULL,
                               NULL, false, true, true, fd);
 
       /* Read the subprocess output, copying it to stderr.  Drop the last
@@ -292,7 +292,7 @@ compile_csharp_using_dotnet (const char * const *sources,
         argv[0] = "dotnet";
         argv[1] = "--list-runtimes";
         argv[2] = NULL;
-        exitstatus = execute ("dotnet", "dotnet", argv, NULL,
+        exitstatus = execute ("dotnet", "dotnet", argv, NULL, NULL,
                               false, false, true, true,
                               true, false, NULL);
       }
@@ -305,7 +305,7 @@ compile_csharp_using_dotnet (const char * const *sources,
           argv[0] = "dotnet";
           argv[1] = "--list-sdks";
           argv[2] = NULL;
-          child = create_pipe_in ("dotnet", "dotnet", argv, NULL,
+          child = create_pipe_in ("dotnet", "dotnet", argv, NULL, NULL,
                                   DEV_NULL, true, true, false, fd);
           if (child != -1)
             {
@@ -353,7 +353,7 @@ compile_csharp_using_dotnet (const char * const *sources,
 
         /* Open a pipe to the program.  */
         int fd[1];
-        pid_t child = create_pipe_in ("dotnet", "dotnet", argv, NULL,
+        pid_t child = create_pipe_in ("dotnet", "dotnet", argv, NULL, NULL,
                                       DEV_NULL, false, true, false, fd);
         if (child == -1)
           {
@@ -445,7 +445,7 @@ compile_csharp_using_dotnet (const char * const *sources,
 
         /* Open a pipe to the program.  */
         int fd[1];
-        pid_t child = create_pipe_in ("dotnet", "dotnet", argv, NULL,
+        pid_t child = create_pipe_in ("dotnet", "dotnet", argv, NULL, NULL,
                                       DEV_NULL, false, true, false, fd);
         if (child == -1)
           {
@@ -651,7 +651,7 @@ compile_csharp_using_dotnet (const char * const *sources,
           free (command);
         }
 
-      exitstatus = execute ("dotnet", "dotnet", argv, NULL,
+      exitstatus = execute ("dotnet", "dotnet", argv, NULL, NULL,
                             false, false, false, false,
                             true, true, NULL);
 
@@ -691,7 +691,7 @@ compile_csharp_using_dotnet (const char * const *sources,
           argv[0] = "csc";
           argv[1] = "-help";
           argv[2] = NULL;
-          child = create_pipe_in ("csc", "csc", argv, NULL,
+          child = create_pipe_in ("csc", "csc", argv, NULL, NULL,
                                   DEV_NULL, true, true, false, fd);
           if (child != -1)
             {
@@ -825,7 +825,7 @@ compile_csharp_using_dotnet (const char * const *sources,
               free (command);
             }
 
-          exitstatus = execute ("csc", "csc", argv, NULL,
+          exitstatus = execute ("csc", "csc", argv, NULL, NULL,
                                 false, false, false, false,
                                 true, true, NULL);
 
@@ -870,7 +870,7 @@ compile_csharp_using_sscli (const char * const *sources,
       argv[0] = "csc";
       argv[1] = "-help";
       argv[2] = NULL;
-      child = create_pipe_in ("csc", "csc", argv, NULL,
+      child = create_pipe_in ("csc", "csc", argv, NULL, NULL,
                               DEV_NULL, true, true, false, fd);
       csc_present = false;
       if (child != -1)
@@ -997,7 +997,7 @@ compile_csharp_using_sscli (const char * const *sources,
           free (command);
         }
 
-      exitstatus = execute ("csc", "csc", argv, NULL,
+      exitstatus = execute ("csc", "csc", argv, NULL, NULL,
                             false, false, false, false,
                             true, true, NULL);
 
index 79f2a3fd9189ad06550f0f7fd2d46d5725f5aab9..c0658da5a8e47f498de9eec0db9322aa9aa5514b 100644 (file)
@@ -132,7 +132,7 @@ execute_csharp_using_mono (const char *assembly_path,
       argv[0] = "mono";
       argv[1] = "--version";
       argv[2] = NULL;
-      exitstatus = execute ("mono", "mono", argv, NULL,
+      exitstatus = execute ("mono", "mono", argv, NULL, NULL,
                             false, false, true, true,
                             true, false, NULL);
       mono_present = (exitstatus == 0);
@@ -196,7 +196,7 @@ execute_csharp_using_dotnet (const char *assembly_path,
       argv[0] = "dotnet";
       argv[1] = "--list-runtimes";
       argv[2] = NULL;
-      exitstatus = execute ("dotnet", "dotnet", argv, NULL,
+      exitstatus = execute ("dotnet", "dotnet", argv, NULL, NULL,
                             false, false, true, true,
                             true, false, NULL);
       dotnet_present = (exitstatus == 0);
@@ -382,7 +382,7 @@ execute_csharp_using_dotnet (const char *assembly_path,
 
             /* Open a pipe to the program.  */
             int fd[1];
-            pid_t child = create_pipe_in ("dotnet", "dotnet", argv, NULL,
+            pid_t child = create_pipe_in ("dotnet", "dotnet", argv, NULL, NULL,
                                           DEV_NULL, false, true, false, fd);
             if (child == -1)
               {
@@ -572,7 +572,7 @@ execute_csharp_using_sscli (const char *assembly_path,
 
       argv[0] = "clix";
       argv[1] = NULL;
-      exitstatus = execute ("clix", "clix", argv, NULL,
+      exitstatus = execute ("clix", "clix", argv, NULL, NULL,
                             false, false, true, true,
                             true, false, NULL);
       clix_present = (exitstatus == 0 || exitstatus == 1);
index 746170608961acd727236ac33024d35a6e5f4d9f..90caacde42db324f2cacfb0a364c925ac7a6eda5 100644 (file)
@@ -92,7 +92,7 @@ execute_and_read_line (const char *progname,
   size_t linelen;
 
   /* Open a pipe to the program.  */
-  child = create_pipe_in (progname, prog_path, prog_argv, NULL,
+  child = create_pipe_in (progname, prog_path, prog_argv, NULL, NULL,
                           DEV_NULL, false, true, false, fd);
 
   if (child == -1)
index 8bbba2be62417bd5b9ca88cbd7018cac015e011b..c5ebf29690de3cf08d44c9a5de07cfcc078faad0 100644 (file)
@@ -35,6 +35,7 @@
 #include "fatal-signal.h"
 #include "filename.h"
 #include "findprog.h"
+#include "windows-path.h"
 #include "wait-process.h"
 #include "xalloc.h"
 #include "gettext.h"
@@ -113,6 +114,7 @@ nonintr_open (const char *pathname, int oflag, mode_t mode)
 int
 execute (const char *progname,
          const char *prog_path, const char * const *prog_argv,
+         const char * const *dll_dirs,
          const char *directory,
          bool ignore_sigpipe,
          bool null_stdin, bool null_stdout, bool null_stderr,
@@ -203,7 +205,8 @@ execute (const char *progname,
         (HANDLE) _get_osfhandle (null_stderr ? nulloutfd : STDERR_FILENO);
 
       exitcode = spawnpvech (P_WAIT, prog_path, argv + 1,
-                             (const char * const *) environ, directory,
+                             (const char * const *) environ, dll_dirs,
+                             directory,
                              stdin_handle, stdout_handle, stderr_handle);
 # if 0 /* Executing arbitrary files as shell scripts is unsecure.  */
       if (exitcode == -1 && errno == ENOEXEC)
@@ -213,7 +216,8 @@ execute (const char *progname,
              a hidden element "sh.exe" to argv.  */
           argv[1] = prog_path;
           exitcode = spawnpvech (P_WAIT, argv[0], argv,
-                                 (const char * const *) environ, directory,
+                                 (const char * const *) environ, dll_dirs,
+                                 directory,
                                  stdin_handle, stdout_handle, stderr_handle);
         }
 # endif
@@ -254,6 +258,8 @@ execute (const char *progname,
      subprocess to exit with return code 127.  It is implementation
      dependent which error is reported which way.  We treat both cases as
      equivalent.  */
+  char **child_environ;
+  char **malloced_environ;
   sigset_t blocked_signals;
   posix_spawn_file_actions_t actions;
   bool actions_allocated;
@@ -262,6 +268,18 @@ execute (const char *progname,
   int err;
   pid_t child;
 
+  child_environ = environ;
+  malloced_environ = NULL;
+# if defined _WIN32 || defined __CYGWIN__
+  if (dll_dirs != NULL && dll_dirs[0] != NULL)
+    {
+      malloced_environ = extended_environ (dll_dirs);
+      if (malloced_environ == NULL)
+        goto fail_with_errno;
+      child_environ = malloced_environ;
+    }
+# endif
+
   if (slave_process)
     {
       sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
@@ -300,16 +318,18 @@ execute (const char *progname,
                                                          &blocked_signals))
                       != 0
                       || (err = posix_spawnattr_setflags (&attrs,
-                                                        POSIX_SPAWN_SETSIGMASK))
+                                                          POSIX_SPAWN_SETSIGMASK))
                          != 0)))
 # endif
           || (err = (directory != NULL
                      ? posix_spawn (&child, prog_path, &actions,
                                     attrs_allocated ? &attrs : NULL,
-                                    (char * const *) prog_argv, environ)
+                                    (char * const *) prog_argv,
+                                    child_environ)
                      : posix_spawnp (&child, prog_path, &actions,
                                      attrs_allocated ? &attrs : NULL,
-                                     (char * const *) prog_argv, environ)))
+                                     (char * const *) prog_argv,
+                                     child_environ)))
              != 0))
     {
       if (actions_allocated)
@@ -318,6 +338,11 @@ execute (const char *progname,
         posix_spawnattr_destroy (&attrs);
       if (slave_process)
         unblock_fatal_signals ();
+      if (malloced_environ != NULL)
+        {
+          free (malloced_environ[0]);
+          free (malloced_environ);
+        }
       free (prog_path_to_free);
       if (termsigp != NULL)
         *termsigp = 0;
@@ -332,6 +357,11 @@ execute (const char *progname,
       register_slave_subprocess (child);
       unblock_fatal_signals ();
     }
+  if (malloced_environ != NULL)
+    {
+      free (malloced_environ[0]);
+      free (malloced_environ);
+    }
   free (prog_path_to_free);
 
   return wait_subprocess (child, progname, ignore_sigpipe, null_stderr,
index 27ac081f5e02c6f6f50b9646ec314da53106eb75..cb43f21e1653f2846591188b613faac8d74f29cc 100644 (file)
@@ -27,6 +27,7 @@ extern "C" {
    descriptors to /dev/null.  Return its exit code.
    If it didn't terminate correctly, exit if exit_on_error is true, otherwise
    return 127.
+
    progname is the name of the program to be executed by the subprocess, used
    for error messages.
    prog_path is the file name of the program to be executed by the subprocess.
@@ -35,21 +36,31 @@ extern "C" {
    prog_argv is the array of strings that the subprocess shall receive in
    argv[].  It is a NULL-terminated array.  prog_argv[0] should normally be
    identical to prog_path.
+
+   dll_dirs is, on Windows platforms, a NULL-terminated list of directories
+   that contain DLLs needed to execute the program, or NULL if none is needed.
+   On other platforms, always pass NULL.
+
    If directory is not NULL, the command is executed in that directory.  If
    prog_path is a relative file name, it resolved before changing to that
    directory.  The current directory of the current process remains unchanged.
+
    If ignore_sigpipe is true, consider a subprocess termination due to SIGPIPE
    as equivalent to a success.  This is suitable for processes whose only
    purpose is to write to standard output.
+
    If slave_process is true, the child process will be terminated when its
    creator receives a catchable fatal signal.
+
    If termsigp is not NULL, *termsig will be set to the signal that terminated
    the subprocess (if supported by the platform: not on native Windows
    platforms), otherwise 0.
+
    It is recommended that no signal is blocked or ignored while execute()
    is called.  See spawn-pipe.h for the reason.  */
 extern int execute (const char *progname,
                     const char *prog_path, const char * const *prog_argv,
+                    const char * const *dll_dirs,
                     const char *directory,
                     bool ignore_sigpipe,
                     bool null_stdin, bool null_stdout, bool null_stderr,
index 107f373740ec7ed414a6edce2ddb04e3321cedac..c5b90147ca2a8c96b5e7795096bafe0f5ac0218e 100644 (file)
@@ -243,7 +243,7 @@ compile_using_envjavac (const char *javac,
   argv[1] = "-c";
   argv[2] = command;
   argv[3] = NULL;
-  exitstatus = execute (javac, BOURNE_SHELL, argv, NULL,
+  exitstatus = execute (javac, BOURNE_SHELL, argv, NULL, NULL,
                         false, false, false, null_stderr,
                         true, true, NULL);
   err = (exitstatus != 0);
@@ -315,7 +315,7 @@ compile_using_javac (const char * const *java_sources,
       free (command);
     }
 
-  exitstatus = execute ("javac", "javac", argv, NULL,
+  exitstatus = execute ("javac", "javac", argv, NULL, NULL,
                         false, false, false,
                         null_stderr, true, true, NULL);
   err = (exitstatus != 0);
@@ -343,7 +343,7 @@ execute_and_read_line (const char *progname,
   int exitstatus;
 
   /* Open a pipe to the program.  */
-  child = create_pipe_in (progname, prog_path, prog_argv, NULL,
+  child = create_pipe_in (progname, prog_path, prog_argv, NULL, NULL,
                           DEV_NULL, false, true, false, fd);
 
   if (child == -1)
@@ -762,7 +762,7 @@ is_javac_present (void)
 
       argv[0] = "javac";
       argv[1] = NULL;
-      exitstatus = execute ("javac", "javac", argv, NULL,
+      exitstatus = execute ("javac", "javac", argv, NULL, NULL,
                             false, false, true, true,
                             true, false, NULL);
       javac_present = (exitstatus == 0 || exitstatus == 1 || exitstatus == 2);
index 081c54eaaa39d2af35e8dc339beab58a4e52797e..7df0a28f76935cde6b20012c49d73fa35387116e 100644 (file)
@@ -205,7 +205,7 @@ execute_java_class (const char *class_name,
         argv[0] = "java";
         argv[1] = "-version";
         argv[2] = NULL;
-        exitstatus = execute ("java", "java", argv, NULL,
+        exitstatus = execute ("java", "java", argv, NULL, NULL,
                               false, false, true, true,
                               true, false, NULL);
         java_present = (exitstatus == 0);
@@ -261,7 +261,7 @@ execute_java_class (const char *class_name,
 
         argv[0] = "jre";
         argv[1] = NULL;
-        exitstatus = execute ("jre", "jre", argv, NULL,
+        exitstatus = execute ("jre", "jre", argv, NULL, NULL,
                               false, false, true, true,
                               true, false, NULL);
         jre_present = (exitstatus == 0 || exitstatus == 1);
index fefdfe560de03601d00da19026202ac828b274de..fb3ce70751e81dff46949b372f8c744d54756694 100644 (file)
@@ -63,7 +63,7 @@ execute_and_read_line (const char *progname,
   size_t linelen;
 
   /* Open a pipe to the JVM.  */
-  child = create_pipe_in (progname, prog_path, prog_argv, NULL,
+  child = create_pipe_in (progname, prog_path, prog_argv, NULL, NULL,
                           DEV_NULL, false, true, false, fd);
 
   if (child == -1)
index 6bbe4b4ff9cb537efc9a9963842a2f27a8050e9a..ab26fc4774f755dcbaba4f2197eb1159dab85aba 100644 (file)
@@ -496,7 +496,7 @@ pipe_filter_gi_create (const char *progname,
     (struct pipe_filter_gi *) xmalloc (sizeof (struct pipe_filter_gi));
 
   /* Open a bidirectional pipe to a subprocess.  */
-  filter->child = create_pipe_bidi (progname, prog_path, prog_argv,
+  filter->child = create_pipe_bidi (progname, prog_path, prog_argv, NULL,
                                     NULL, null_stderr, true, exit_on_error,
                                     filter->fd);
   filter->progname = progname;
index 1786ba267f7456b6a8e1c4150e959f7c61c203e5..00845288985f1ac915bce21273553592f5295627 100644 (file)
@@ -269,7 +269,7 @@ pipe_filter_ii_execute (const char *progname,
 #endif
 
   /* Open a bidirectional pipe to a subprocess.  */
-  child = create_pipe_bidi (progname, prog_path, prog_argv,
+  child = create_pipe_bidi (progname, prog_path, prog_argv, NULL,
                             NULL, null_stderr, true, exit_on_error,
                             fd);
   if (child == -1)
index 28e15a117ae3f00c2ef3a376d4101b36800cda27..fe60646c4341f790440653eb76235c836047bafb 100644 (file)
@@ -37,6 +37,7 @@
 #include "fatal-signal.h"
 #include "filename.h"
 #include "findprog.h"
+#include "windows-path.h"
 #include "unistd-safer.h"
 #include "wait-process.h"
 #include "xalloc.h"
@@ -138,6 +139,7 @@ static pid_t
 create_pipe (const char *progname,
              const char *prog_path,
              const char * const *prog_argv,
+             const char * const *dll_dirs,
              const char *directory,
              bool pipe_stdin, bool pipe_stdout,
              const char *prog_stdin, const char *prog_stdout,
@@ -313,7 +315,8 @@ create_pipe (const char *progname,
         (HANDLE) _get_osfhandle (null_stderr ? nulloutfd : STDERR_FILENO);
 
       child = spawnpvech (P_NOWAIT, prog_path, argv + 1,
-                          (const char * const *) environ, directory,
+                          (const char * const *) environ, dll_dirs,
+                          directory,
                           stdin_handle, stdout_handle, stderr_handle);
 #  if 0 /* Executing arbitrary files as shell scripts is unsecure.  */
       if (child == -1 && errno == ENOEXEC)
@@ -323,7 +326,8 @@ create_pipe (const char *progname,
              a hidden element "sh.exe" to argv.  */
           argv[1] = prog_path;
           child = spawnpvech (P_NOWAIT, argv[0], argv,
-                              (const char * const *) environ, directory,
+                              (const char * const *) environ, dll_dirs,
+                              directory,
                               stdin_handle, stdout_handle, stderr_handle);
         }
 #  endif
@@ -433,6 +437,8 @@ create_pipe (const char *progname,
 #else
 
   /* Unix API.  */
+  char **child_environ;
+  char **malloced_environ;
   sigset_t blocked_signals;
   posix_spawn_file_actions_t actions;
   bool actions_allocated;
@@ -441,6 +447,18 @@ create_pipe (const char *progname,
   int err;
   pid_t child;
 
+  child_environ = environ;
+  malloced_environ = NULL;
+# if defined _WIN32 || defined __CYGWIN__
+  if (dll_dirs != NULL && dll_dirs[0] != NULL)
+    {
+      malloced_environ = extended_environ (dll_dirs);
+      if (malloced_environ == NULL)
+        goto fail_with_errno;
+      child_environ = malloced_environ;
+    }
+# endif
+
   if (slave_process)
     {
       sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
@@ -499,24 +517,26 @@ create_pipe (const char *progname,
 # if defined _WIN32 && !defined __CYGWIN__
                       (err = posix_spawnattr_setpgroup (&attrs, 0)) != 0
                       || (err = posix_spawnattr_setflags (&attrs,
-                                                         POSIX_SPAWN_SETPGROUP))
+                                                          POSIX_SPAWN_SETPGROUP))
                          != 0
 # else
                       (err = posix_spawnattr_setsigmask (&attrs,
                                                          &blocked_signals))
                       != 0
                       || (err = posix_spawnattr_setflags (&attrs,
-                                                        POSIX_SPAWN_SETSIGMASK))
+                                                          POSIX_SPAWN_SETSIGMASK))
                          != 0
 # endif
              )   )   )
           || (err = (directory != NULL
                      ? posix_spawn (&child, prog_path, &actions,
                                     attrs_allocated ? &attrs : NULL,
-                                    (char * const *) prog_argv, environ)
+                                    (char * const *) prog_argv,
+                                    child_environ)
                      : posix_spawnp (&child, prog_path, &actions,
                                      attrs_allocated ? &attrs : NULL,
-                                     (char * const *) prog_argv, environ)))
+                                     (char * const *) prog_argv,
+                                     child_environ)))
              != 0))
     {
       if (actions_allocated)
@@ -525,6 +545,11 @@ create_pipe (const char *progname,
         posix_spawnattr_destroy (&attrs);
       if (slave_process)
         unblock_fatal_signals ();
+      if (malloced_environ != NULL)
+        {
+          free (malloced_environ[0]);
+          free (malloced_environ);
+        }
       if (pipe_stdout)
         {
           close (ifd[0]);
@@ -547,6 +572,11 @@ create_pipe (const char *progname,
       register_slave_subprocess (child);
       unblock_fatal_signals ();
     }
+  if (malloced_environ != NULL)
+    {
+      free (malloced_environ[0]);
+      free (malloced_environ);
+    }
   if (pipe_stdin)
     close (ofd[0]);
   if (pipe_stdout)
@@ -582,12 +612,14 @@ create_pipe (const char *progname,
 pid_t
 create_pipe_bidi (const char *progname,
                   const char *prog_path, const char * const *prog_argv,
+                  const char * const *dll_dirs,
                   const char *directory,
                   bool null_stderr,
                   bool slave_process, bool exit_on_error,
                   int fd[2])
 {
-  pid_t result = create_pipe (progname, prog_path, prog_argv, directory,
+  pid_t result = create_pipe (progname, prog_path, prog_argv, dll_dirs,
+                              directory,
                               true, true, NULL, NULL,
                               null_stderr, slave_process, exit_on_error,
                               fd);
@@ -604,13 +636,15 @@ create_pipe_bidi (const char *progname,
 pid_t
 create_pipe_in (const char *progname,
                 const char *prog_path, const char * const *prog_argv,
+                const char * const *dll_dirs,
                 const char *directory,
                 const char *prog_stdin, bool null_stderr,
                 bool slave_process, bool exit_on_error,
                 int fd[1])
 {
   int iofd[2];
-  pid_t result = create_pipe (progname, prog_path, prog_argv, directory,
+  pid_t result = create_pipe (progname, prog_path, prog_argv, dll_dirs,
+                              directory,
                               false, true, prog_stdin, NULL,
                               null_stderr, slave_process, exit_on_error,
                               iofd);
@@ -629,13 +663,15 @@ create_pipe_in (const char *progname,
 pid_t
 create_pipe_out (const char *progname,
                  const char *prog_path, const char * const *prog_argv,
+                 const char * const *dll_dirs,
                  const char *directory,
                  const char *prog_stdout, bool null_stderr,
                  bool slave_process, bool exit_on_error,
                  int fd[1])
 {
   int iofd[2];
-  pid_t result = create_pipe (progname, prog_path, prog_argv, directory,
+  pid_t result = create_pipe (progname, prog_path, prog_argv, dll_dirs,
+                              directory,
                               true, false, NULL, prog_stdout,
                               null_stderr, slave_process, exit_on_error,
                               iofd);
index 9f558ddf18a2e2fee7abb0f0f09f8d808d42a848..1fe07da1205d036b01086e2201ec7e18ce4ac1a5 100644 (file)
@@ -49,6 +49,10 @@ extern "C" {
    argv[].  It is a NULL-terminated array.  prog_argv[0] should normally be
    identical to prog_path.
 
+   dll_dirs is, on Windows platforms, a NULL-terminated list of directories
+   that contain DLLs needed to execute the program, or NULL if none is needed.
+   On other platforms, always pass NULL.
+
    If directory is not NULL, the subprocess is started in that directory.  If
    prog_path is a relative file name, it resolved before changing to that
    directory.  The current directory of the current process remains unchanged.
@@ -96,6 +100,7 @@ extern "C" {
 extern pid_t create_pipe_out (const char *progname,
                               const char *prog_path,
                               const char * const *prog_argv,
+                              const char * const *dll_dirs,
                               const char *directory,
                               const char *prog_stdout, bool null_stderr,
                               bool slave_process, bool exit_on_error,
@@ -111,6 +116,7 @@ extern pid_t create_pipe_out (const char *progname,
 extern pid_t create_pipe_in (const char *progname,
                              const char *prog_path,
                              const char * const *prog_argv,
+                             const char * const *dll_dirs,
                              const char *directory,
                              const char *prog_stdin, bool null_stderr,
                              bool slave_process, bool exit_on_error,
@@ -141,6 +147,7 @@ extern pid_t create_pipe_in (const char *progname,
 extern pid_t create_pipe_bidi (const char *progname,
                                const char *prog_path,
                                const char * const *prog_argv,
+                               const char * const *dll_dirs,
                                const char *directory,
                                bool null_stderr,
                                bool slave_process, bool exit_on_error,
index 8ddf9c599912173401eb69ee2c62250ea50e30ac..211394bb9f9b44be304bf261b098b1d68c42f900 100644 (file)
@@ -665,7 +665,7 @@ __spawni (pid_t *pid, const char *prog_filename,
     envblock = NULL;
   else
     {
-      envblock = compose_envblock (envp);
+      envblock = compose_envblock (envp, NULL);
       if (envblock == NULL)
         {
           free (command);
diff --git a/lib/windows-path.c b/lib/windows-path.c
new file mode 100644 (file)
index 0000000..d238653
--- /dev/null
@@ -0,0 +1,146 @@
+/* Auxiliary functions for the creation of subprocesses on Windows.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2024.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include "windows-path.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+char *
+extended_PATH (const char * const *dll_dirs)
+{
+  /* Create a string PATH=(dll_dirs[0];dll_dirs[1];...;)old_PATH  */
+  const char *old_PATH = getenv ("PATH");
+  if (old_PATH == NULL)
+    old_PATH = "";
+  size_t size;
+  {
+    size = 5;
+    {
+      size_t i;
+      for (i = 0; dll_dirs[i] != NULL; i++)
+        size += strlen (dll_dirs[i]) + 1;
+    }
+    size += strlen (old_PATH) + 1;
+  }
+  char *new_PATH = (char *) malloc (size);
+  if (new_PATH == NULL)
+    return NULL;
+  {
+    char *p = new_PATH;
+    {
+      memcpy (p, "PATH=", 5);
+      p += 5;
+    }
+    {
+      size_t i;
+      for (i = 0; dll_dirs[i] != NULL; i++)
+        {
+          size_t l = strlen (dll_dirs[i]);
+          memcpy (p, dll_dirs[i], l);
+          p += l;
+#if defined _WIN32 && !defined __CYGWIN__
+          *p++ = ';';
+#else
+          *p++ = ':';
+#endif
+        }
+    }
+    {
+      size_t l = strlen (old_PATH);
+      memcpy (p, old_PATH, l);
+      p += l;
+      *p = '\0';
+    }
+  }
+  return new_PATH;
+}
+
+char **
+extended_environ (const char * const *dll_dirs)
+{
+  char *child_PATH = extended_PATH (dll_dirs);
+  if (child_PATH == NULL)
+    return NULL;
+
+  /* Create a shallow copy of environ, adding the child_PATH and removing
+     the original "PATH=..." string.
+     This is a bit hairy, because we don't have a lock that would prevent
+     other threads from making modifications in ENVP.  So, just make sure
+     we don't crash; but if other threads are making modifications, part
+     of the result may be wrong.  */
+  char **envp;
+
+#if defined _WIN32 && !defined __CYGWIN__
+  envp = _environ;
+#else
+  envp = environ;
+#endif
+
+ retry:
+  {
+    /* Guess the size of the needed block of memory.
+       The guess will be exact if other threads don't make modifications.  */
+    size_t size = 0;
+    {
+      char **ep;
+      char *p;
+      for (ep = envp; (p = *ep) != NULL; ep++)
+        if (strncmp (p, "PATH=", 5) != 0)
+          size += 1;
+    }
+    char **new_environ = (char **) malloc ((1 + size + 1) * sizeof (char *));
+    if (new_environ == NULL)
+      {
+        free (child_PATH);
+        errno = ENOMEM;
+        return NULL;
+      }
+    char **nep = new_environ;
+    *nep++ = child_PATH;
+    {
+      size_t i = 0;
+      char **ep;
+      char *p;
+      for (ep = envp; (p = *ep) != NULL; ep++)
+        if (strncmp (p, "PATH=", 5) != 0)
+          {
+            if (i == size)
+              {
+                /* Other threads did modifications.  Restart.  */
+                free (new_environ);
+                goto retry;
+              }
+            *nep++ = p;
+            i += 1;
+          }
+      if (i < size)
+        {
+          /* Other threads did modifications.  Restart.  */
+          free (new_environ);
+          goto retry;
+        }
+    }
+    *nep = NULL;
+    return new_environ;
+  }
+}
diff --git a/lib/windows-path.h b/lib/windows-path.h
new file mode 100644 (file)
index 0000000..f4199db
--- /dev/null
@@ -0,0 +1,54 @@
+/* Auxiliary functions for the creation of subprocesses on Windows.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2024.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#ifndef _WINDOWS_PATH_H
+#define _WINDOWS_PATH_H
+
+/* This file uses _GL_ATTRIBUTE_MALLOC.  */
+#if !_GL_CONFIG_H_INCLUDED
+ #error "Please include config.h first."
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Returns an augmented "PATH=..." string for the environment of a child process.
+   dll_dirs is a NULL-terminated list of directories that contain DLLs needed to
+   execute the program, or NULL if none is needed.
+   Returns a freshly allocated string.  In case of memory allocation failure,
+   NULL is returned, with errno set.  */
+extern char * extended_PATH (const char * const *dll_dirs)
+  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE;
+
+/* Returns an augmented environment for a child process.
+   dll_dirs is a NULL-terminated list of directories that contain DLLs needed to
+   execute the program, or NULL if none is needed.
+   Returns a freshly allocated string array, with a freshly allocated first
+   string.  In case of memory allocation failure, NULL is returned, with errno
+   set.  */
+extern char ** extended_environ (const char * const *dll_dirs)
+  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _WINDOWS_PATH_H */
index e2222f4fc871a0f5e116fe227d7a7ed0f2b669f1..ac098b42623e96774626a05af5abda81d933672b 100644 (file)
@@ -38,6 +38,7 @@
 #include <process.h>
 
 #include "findprog.h"
+#include "windows-path.h"
 
 /* Don't assume that UNICODE is not defined.  */
 #undef STARTUPINFO
@@ -244,7 +245,7 @@ compose_command (const char * const *argv)
 }
 
 char *
-compose_envblock (const char * const *envp)
+compose_envblock (const char * const *envp, const char *new_PATH)
 {
   /* This is a bit hairy, because we don't have a lock that would prevent other
      threads from making modifications in ENVP.  So, just make sure we don't
@@ -257,8 +258,11 @@ compose_envblock (const char * const *envp)
     size_t total_size = 0;
     const char * const *ep;
     const char *p;
+    if (new_PATH != NULL)
+      total_size += strlen (new_PATH) + 1;
     for (ep = envp; (p = *ep) != NULL; ep++)
-      total_size += strlen (p) + 1;
+      if (!(new_PATH != NULL && strncmp (p, "PATH=", 5) == 0))
+        total_size += strlen (p) + 1;
     size_t envblock_size = total_size;
 
     /* Allocate the block of memory.  */
@@ -269,34 +273,42 @@ compose_envblock (const char * const *envp)
         return NULL;
       }
     size_t envblock_used = 0;
-    for (ep = envp; (p = *ep) != NULL; ep++)
+    if (new_PATH != NULL)
       {
-        size_t size = strlen (p) + 1;
-        if (envblock_used + size > envblock_size)
-          {
-            /* Other threads did modifications.  Need more memory.  */
-            envblock_size += envblock_size / 2;
-            if (envblock_used + size > envblock_size)
-              envblock_size = envblock_used + size;
-
-            char *new_envblock = (char *) realloc (envblock, envblock_size + 1);
-            if (new_envblock == NULL)
-              {
-                free (envblock);
-                errno = ENOMEM;
-                return NULL;
-              }
-            envblock = new_envblock;
-          }
-        memcpy (envblock + envblock_used, p, size);
+        size_t size = strlen (new_PATH) + 1;
+        memcpy (envblock + envblock_used, new_PATH, size);
         envblock_used += size;
-        if (envblock[envblock_used - 1] != '\0')
-          {
-            /* Other threads did modifications.  Restart.  */
-            free (envblock);
-            goto retry;
-          }
       }
+    for (ep = envp; (p = *ep) != NULL; ep++)
+      if (!(new_PATH != NULL && strncmp (p, "PATH=", 5) == 0))
+        {
+          size_t size = strlen (p) + 1;
+          if (envblock_used + size > envblock_size)
+            {
+              /* Other threads did modifications.  Need more memory.  */
+              envblock_size += envblock_size / 2;
+              if (envblock_used + size > envblock_size)
+                envblock_size = envblock_used + size;
+
+              char *new_envblock =
+                (char *) realloc (envblock, envblock_size + 1);
+              if (new_envblock == NULL)
+                {
+                  free (envblock);
+                  errno = ENOMEM;
+                  return NULL;
+                }
+              envblock = new_envblock;
+            }
+          memcpy (envblock + envblock_used, p, size);
+          envblock_used += size;
+          if (envblock[envblock_used - 1] != '\0')
+            {
+              /* Other threads did modifications.  Restart.  */
+              free (envblock);
+              goto retry;
+            }
+        }
     envblock[envblock_used] = '\0';
     return envblock;
   }
@@ -573,6 +585,7 @@ intptr_t
 spawnpvech (int mode,
             const char *progname, const char * const *argv,
             const char * const *envp,
+            const char * const *dll_dirs,
             const char *currdir,
             HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle)
 {
@@ -600,11 +613,23 @@ spawnpvech (int mode,
 
   /* Copy *ENVP into a contiguous block of memory.  */
   char *envblock;
-  if (envp == NULL)
+  if (envp == NULL && !(dll_dirs != NULL && dll_dirs[0] != NULL))
     envblock = NULL;
   else
     {
-      envblock = compose_envblock (envp);
+      if (envp == NULL)
+        /* Documentation:
+           <https://learn.microsoft.com/en-us/cpp/c-runtime-library/environ-wenviron>  */
+        envp = (const char **) _environ;
+      char *new_PATH = NULL;
+      if (dll_dirs != NULL && dll_dirs[0] != NULL)
+        {
+          new_PATH = extended_PATH (dll_dirs);
+          if (new_PATH == NULL)
+            goto out_of_memory_2;
+        }
+      envblock = compose_envblock (envp, new_PATH);
+      free (new_PATH);
       if (envblock == NULL)
         goto out_of_memory_2;
     }
index 9f18ab2a64e6ae65a5bea4c9d0ad377b8b681365..3a33016a5c5f653bd7281e099cb7a1b5e8aae54a 100644 (file)
@@ -88,9 +88,11 @@ extern char * compose_command (const char * const *argv)
 /* Composes the block of memory that contains the environment variables.
    ENVP must contain an environment (a NULL-terminated array of string of the
    form VARIABLE=VALUE).
+   NEW_PATH must be a string of the form PATH=VALUE, or NULL if the PATH
+   environment variable from this process is suitable for the child process.
    Returns a freshly allocated block of memory.  In case of memory allocation
    failure, NULL is returned, with errno set.  */
-extern char * compose_envblock (const char * const *envp)
+extern char * compose_envblock (const char * const *envp, const char *new_PATH)
   _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE;
 
 
@@ -176,6 +178,9 @@ extern int convert_CreateProcess_error (DWORD error);
    ENVP is the NULL-terminated set of environment variable assignments, or NULL
    to inherit the initial environ variable assignments from the caller and
    ignore all calls to putenv(), setenv(), unsetenv() done in the caller.
+   DLL_DIRS is, on Windows platforms, a NULL-terminated list of directories
+   that contain DLLs needed to execute the program, or NULL if none is needed.
+   On other platforms, always pass NULL.
    CURRDIR is the directory in which to start the program, or NULL to inherit
    the working directory from the caller.
    STDIN_HANDLE, STDOUT_HANDLE, STDERR_HANDLE are the handles to use for the
@@ -188,6 +193,7 @@ extern int convert_CreateProcess_error (DWORD error);
 extern intptr_t spawnpvech (int mode,
                             const char *progname, const char * const *argv,
                             const char * const *envp,
+                            const char * const *dll_dirs,
                             const char *currdir,
                             HANDLE stdin_handle, HANDLE stdout_handle,
                             HANDLE stderr_handle);
index 2b0c7ccf3cf9280e0b07f78180d479ab1f787ca5..29b89ec244445d696d042a4a8808f1a2a4d6b148 100644 (file)
@@ -1,11 +1,14 @@
 Description:
-Auxiliary functions for the creation of subprocesses on native Windows.
+Auxiliary functions for the creation of subprocesses on Windows.
 
 Files:
+lib/windows-path.h
+lib/windows-path.c
 lib/windows-spawn.h
 lib/windows-spawn.c
 
 Depends-on:
+environ
 findprog-in
 msvc-nothrow
 stdbool
@@ -17,15 +20,21 @@ malloc-posix
 
 configure.ac:
 AC_REQUIRE([AC_CANONICAL_HOST])
+gl_CONDITIONAL([GL_COND_OBJ_WINDOWS_PATH],
+               [case "$host_os" in cygwin* | mingw* | windows*) true;; *) false;; esac])
 gl_CONDITIONAL([GL_COND_OBJ_WINDOWS_SPAWN],
                [case "$host_os" in mingw* | windows*) true;; *) false;; esac])
 
 Makefile.am:
+if GL_COND_OBJ_WINDOWS_PATH
+lib_SOURCES += windows-path.c
+endif
 if GL_COND_OBJ_WINDOWS_SPAWN
 lib_SOURCES += windows-spawn.c
 endif
 
 Include:
+"windows-path.h"
 "windows-spawn.h"
 
 License:
index 4703941beae7410ff084257e3acef5d2cd3ccd3b..307b1f7cbfa0a89d915ca34d6996e245361cf9d6 100644 (file)
@@ -104,7 +104,7 @@ main (int argc, char *argv[])
       {
         /* Check an invocation without arguments.  Check the exit code.  */
         const char *prog_argv[2] = { prog_path, NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, NULL);
         ASSERT (ret == 40);
       }
@@ -113,7 +113,7 @@ main (int argc, char *argv[])
       {
         /* Check an invocation of a nonexistent program.  */
         const char *prog_argv[3] = { "./nonexistent", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, NULL);
         ASSERT (ret == 127);
       }
@@ -137,7 +137,7 @@ main (int argc, char *argv[])
             "",
             NULL
           };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, NULL);
         ASSERT (ret == 0);
       }
@@ -148,7 +148,7 @@ main (int argc, char *argv[])
         /* Check SIGPIPE handling with ignore_sigpipe = false.  */
         const char *prog_argv[3] = { prog_path, "3", NULL };
         int termsig = 0x7DEADBEE;
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, &termsig);
         ASSERT (ret == 127);
         ASSERT (termsig == SIGPIPE);
@@ -161,7 +161,7 @@ main (int argc, char *argv[])
         /* Check SIGPIPE handling with ignore_sigpipe = true.  */
         const char *prog_argv[3] = { prog_path, "4", NULL };
         int termsig = 0x7DEADBEE;
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            true, false, false, false, true, false, &termsig);
         ASSERT (ret == 0);
         ASSERT (termsig == SIGPIPE);
@@ -173,7 +173,7 @@ main (int argc, char *argv[])
         /* Check other signal.  */
         const char *prog_argv[3] = { prog_path, "5", NULL };
         int termsig = 0x7DEADBEE;
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, &termsig);
         ASSERT (ret == 127);
         #if defined _WIN32 && !defined __CYGWIN__
@@ -194,7 +194,7 @@ main (int argc, char *argv[])
         ASSERT (fp != NULL);
 
         const char *prog_argv[3] = { prog_path, "6", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, NULL);
         ASSERT (ret == 0);
 
@@ -213,7 +213,7 @@ main (int argc, char *argv[])
         ASSERT (fp != NULL);
 
         const char *prog_argv[3] = { prog_path, "7", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, true, false, false, true, false, NULL);
         ASSERT (ret == 0);
 
@@ -228,7 +228,7 @@ main (int argc, char *argv[])
         ASSERT (fp != NULL);
 
         const char *prog_argv[3] = { prog_path, "8", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, NULL);
         ASSERT (ret == 0);
 
@@ -248,7 +248,7 @@ main (int argc, char *argv[])
         ASSERT (fp != NULL);
 
         const char *prog_argv[3] = { prog_path, "9", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, NULL);
         ASSERT (ret == 0);
       }
@@ -260,7 +260,7 @@ main (int argc, char *argv[])
         ASSERT (fp != NULL);
 
         const char *prog_argv[3] = { prog_path, "10", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, true, false, true, false, NULL);
         ASSERT (ret == 0);
 
@@ -280,7 +280,7 @@ main (int argc, char *argv[])
         ASSERT (fp != NULL);
 
         const char *prog_argv[3] = { prog_path, "11", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, NULL);
         ASSERT (ret == 0);
 
@@ -300,7 +300,7 @@ main (int argc, char *argv[])
         ASSERT (fp != NULL);
 
         const char *prog_argv[3] = { prog_path, "12", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, NULL);
         ASSERT (ret == 0);
       }
@@ -312,7 +312,7 @@ main (int argc, char *argv[])
         ASSERT (fp != NULL);
 
         const char *prog_argv[3] = { prog_path, "13", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, true, true, false, NULL);
         ASSERT (ret == 0);
 
@@ -330,7 +330,7 @@ main (int argc, char *argv[])
         /* Check file descriptors >= 3 can be inherited.  */
         ASSERT (dup2 (STDOUT_FILENO, 10) >= 0);
         const char *prog_argv[3] = { prog_path, "14", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            true, false, false, false, true, false, NULL);
         ASSERT (ret == 0);
       }
@@ -340,7 +340,7 @@ main (int argc, char *argv[])
         /* Check file descriptors >= 3 can be inherited.  */
         ASSERT (fcntl (STDOUT_FILENO, F_DUPFD, 10) >= 0);
         const char *prog_argv[3] = { prog_path, "15", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            true, false, false, false, true, false, NULL);
         ASSERT (ret == 0);
       }
@@ -350,7 +350,7 @@ main (int argc, char *argv[])
         /* Check file descriptors >= 3 with O_CLOEXEC bit are not inherited.  */
         ASSERT (fcntl (STDOUT_FILENO, F_DUPFD_CLOEXEC, 10) >= 0);
         const char *prog_argv[3] = { prog_path, "16", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            true, false, false, false, true, false, NULL);
         ASSERT (ret == 0);
       }
@@ -375,7 +375,7 @@ main (int argc, char *argv[])
         /* The file position is now 2.  */
 
         const char *prog_argv[3] = { prog_path, "17", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, NULL);
         ASSERT (ret == 0);
 
@@ -399,7 +399,7 @@ main (int argc, char *argv[])
         /* The file position is now 3.  */
 
         const char *prog_argv[3] = { prog_path, "18", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, NULL);
         ASSERT (ret == 0);
 
@@ -435,7 +435,7 @@ main (int argc, char *argv[])
         fd_out = 16;
 
         const char *prog_argv[3] = { prog_path, "19", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, NULL);
         #if defined _WIN32 && ! defined __CYGWIN__
         ASSERT (ret == 4 + 2 * (_isatty (15) != 0) + (_isatty (16) != 0));
@@ -459,7 +459,7 @@ main (int argc, char *argv[])
         int fd_out = 16;
 
         const char *prog_argv[3] = { prog_path, "20", NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, NULL);
         #if defined _WIN32 && ! defined __CYGWIN__
         ASSERT (ret == 4 + 2 * (_isatty (15) != 0) + (_isatty (16) != 0));
@@ -485,7 +485,7 @@ main (int argc, char *argv[])
         #endif
 
         const char *prog_argv[4] = { prog_path, "21", cwd, NULL };
-        int ret = execute (progname, prog_argv[0], prog_argv, BASE ".sub",
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, BASE ".sub",
                            false, false, false, false, true, false, NULL);
         ASSERT (ret == 0);
 
index dfb9d8c259656a74493edec51ca4f820128ec26f..a5a271d838a440e055d589d2faadf3f5b2a55dd0 100644 (file)
@@ -57,7 +57,7 @@ main ()
           (i == 0 ? SRCDIR "executable-script" : SRCDIR "executable-script.sh");
         const char *prog_argv[2] = { prog_path, NULL };
 
-        int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+        int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                            false, false, false, false, true, false, NULL);
         ASSERT (ret == 127);
       }
@@ -78,7 +78,7 @@ main ()
     const char *prog_path = SRCDIR "executable-shell-script";
     const char *prog_argv[2] = { prog_path, NULL };
 
-    int ret = execute (progname, prog_argv[0], prog_argv, NULL,
+    int ret = execute (progname, prog_argv[0], prog_argv, NULL, NULL,
                        false, false, false, false, true, false, NULL);
     ASSERT (ret == 0);
 
index 612d47bed54bd3af479e88e44e7cf6a3d77cd813..98998ea9b88df59d9aea7acc79c61113ab51c8bf 100644 (file)
@@ -51,7 +51,7 @@ test_pipe (const char *prog, bool stderr_closed)
   argv[0] = prog;
   argv[1] = (stderr_closed ? "1" : "0");
   argv[2] = NULL;
-  pid = create_pipe_bidi (prog, prog, argv, NULL, false, true, true, fd);
+  pid = create_pipe_bidi (prog, prog, argv, NULL, NULL, false, true, true, fd);
   ASSERT (0 <= pid);
   ASSERT (STDERR_FILENO < fd[0]);
   ASSERT (STDERR_FILENO < fd[1]);
index 07b06c1b29f45a6d6ba5d6d2403a1262c3e605a6..ed43c2f18aa644648dbcbcedcbc62366d0f8704a 100644 (file)
@@ -50,7 +50,7 @@ main ()
           (i == 0 ? SRCDIR "executable-script" : SRCDIR "executable-script.sh");
         const char *prog_argv[2] = { prog_path, NULL };
 
-        pid = create_pipe_in (progname, prog_argv[0], prog_argv, NULL,
+        pid = create_pipe_in (progname, prog_argv[0], prog_argv, NULL, NULL,
                               NULL, false, true, false, fd);
         if (pid >= 0)
           {
@@ -80,7 +80,7 @@ main ()
     const char *prog_path = SRCDIR "executable-shell-script";
     const char *prog_argv[2] = { prog_path, NULL };
 
-    pid = create_pipe_in (progname, prog_argv[0], prog_argv, NULL,
+    pid = create_pipe_in (progname, prog_argv[0], prog_argv, NULL, NULL,
                           NULL, false, true, false, fd);
     ASSERT (pid >= 0);
     ASSERT (fd[0] > STDERR_FILENO);