]> Savannah Git Hosting - gnulib.git/commitdiff
spawn-pipe: Support a directory argument of create_pipe() on OS/2 kLIBC.
authorKO Myung-Hun <komh78@gmail.com>
Thu, 19 Sep 2024 13:58:01 +0000 (22:58 +0900)
committerBruno Haible <bruno@clisp.org>
Tue, 1 Oct 2024 21:00:10 +0000 (23:00 +0200)
* lib/os2-spawn.h (spawnpvech): New declaration.
* lib/os2-spawn.c (spawnpvech): New function.
* lib/spawn-pipe.c (create_pipe) [kLIBC]: Reimplement with spawnpvech().
* m4/spawn-pipe.m4 (gl_SPAWN_PIPE) [HAVE_LIBCX_SPAWN2_H]: Check if
libcx/spawn2.h is available.

ChangeLog
lib/os2-spawn.c
lib/os2-spawn.h
lib/spawn-pipe.c
m4/spawn-pipe.m4

index cf0829d772e5ef39431b9764c354439dc30ec0b0..0c4b6472d128c24a44324e4e6b8b8b1998af6ad4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2024-09-19  KO Myung-Hun  <komh78@gmail.com>
+
+       spawn-pipe: Support a directory argument of create_pipe() on OS/2 kLIBC.
+       * lib/os2-spawn.h (spawnpvech): New declaration.
+       * lib/os2-spawn.c (spawnpvech): New function.
+       * lib/spawn-pipe.c (create_pipe) [kLIBC]: Reimplement with spawnpvech().
+       * m4/spawn-pipe.m4 (gl_SPAWN_PIPE) [HAVE_LIBCX_SPAWN2_H]: Check if
+       libcx/spawn2.h is available.
+
 2024-09-16  Bruno Haible  <bruno@clisp.org>
 
        stdlib: Fix compilation error with Sun C++.
index 05bcd1ee07671d7a14436b21b23d4dbe7c709d73..42b245490822c7895757c39542c9f7ccd5065370 100644 (file)
 #include <unistd.h>
 #include <errno.h>
 
+#include <process.h>
+#include <dlfcn.h>
+#if HAVE_LIBCX_SPAWN2_H
+# include <libcx/spawn2.h>
+#endif
+
 #include "cloexec.h"
 #include <error.h>
 #include "gettext.h"
@@ -152,3 +158,86 @@ prepare_spawn (const char * const *argv, char **mem_to_free)
 
   return new_argv;
 }
+
+int
+spawnpvech (int mode,
+            const char *progname, const char * const *argv,
+            const char * const *envp,
+            const char *currdir,
+            int new_stdin, int new_stdout, int new_stderr)
+{
+#if HAVE_LIBCX_SPAWN2_H
+  static int (*libcx_spawn2) (int mode,
+                              const char *name, const char * const argv[],
+                              const char *cwd, const char * const envp[],
+                              const int stdfds[]) = NULL;
+  static int libcx_spawn2_loaded = -1;
+#else
+  static int libcx_spawn2_loaded = 0;
+#endif
+
+  int saved_stdin = STDIN_FILENO;
+  int saved_stdout = STDOUT_FILENO;
+  int saved_stderr = STDERR_FILENO;
+  int ret = -1;
+
+#if HAVE_LIBCX_SPAWN2_H
+  if (libcx_spawn2_loaded == -1)
+    {
+      void *libcx_handle;
+
+      libcx_handle = dlopen ("libcx0", RTLD_LAZY);
+      if (libcx_handle != NULL)
+        libcx_spawn2 = dlsym (libcx_handle, "_spawn2");
+
+      libcx_spawn2_loaded = libcx_handle != NULL && libcx_spawn2 != NULL;
+    }
+#endif
+
+  if (!(libcx_spawn2_loaded
+        || (currdir == NULL || strcmp (currdir, ".") == 0)))
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  /* Save standard file handles.  */
+  /* 0 means no changes. This is a behavior of spawn2().  */
+  if (new_stdin != 0)
+    saved_stdin = dup_safer_noinherit (STDIN_FILENO);
+
+  if (!(new_stdout == 0 || new_stdout == 1))
+    saved_stdout = dup_safer_noinherit (STDOUT_FILENO);
+
+  if (!(new_stderr == 0 || new_stderr == 2))
+    saved_stderr = dup_safer_noinherit (STDERR_FILENO);
+
+  if ((saved_stdin == STDIN_FILENO || dup2 (new_stdin, STDIN_FILENO) >= 0)
+      && (saved_stdout == STDOUT_FILENO
+          || dup2 (new_stdout, STDOUT_FILENO) >= 0)
+      && (saved_stderr == STDERR_FILENO
+          || dup2 (new_stderr, STDERR_FILENO) >= 0))
+    {
+      if (!libcx_spawn2_loaded
+          || (currdir == NULL || strcmp (currdir, ".") == 0))
+        ret = spawnvpe (mode, progname, (char * const *) argv,
+                        (char * const *) envp);
+#if HAVE_LIBCX_SPAWN2_H
+      else
+        ret = libcx_spawn2 (mode | P_2_THREADSAFE, progname, argv, currdir,
+                            envp, NULL);
+#endif
+    }
+
+  /* Restores standard file handles.  */
+  if (saved_stderr > STDERR_FILENO)
+    undup_safer_noinherit (saved_stderr, STDERR_FILENO);
+
+  if (saved_stdout > STDOUT_FILENO)
+    undup_safer_noinherit (saved_stdout, STDOUT_FILENO);
+
+  if (saved_stdin > STDIN_FILENO)
+    undup_safer_noinherit (saved_stdin, STDIN_FILENO);
+
+  return ret;
+}
index c8b8e335051c4c214a3659cd63204289803cb4c8..e71791f52c807feec0a59888ed0a30d60970ade3 100644 (file)
@@ -30,4 +30,10 @@ extern void undup_safer_noinherit (int tempfd, int origfd);
 extern const char ** prepare_spawn (const char * const *argv,
                                     char **mem_to_free);
 
+/* Creates a subprocess.  */
+extern int spawnpvech (int mode, const char *progname,
+                       const char * const *argv, const char * const *envp,
+                       const char *currdir,
+                       int stdin_fd, int stdout_fd, int stderr_fd);
+
 #endif /* _OS2_SPAWN_H */
index 0f03926e9fa2e7e151f63c784d90762bc2fe9515..28e15a117ae3f00c2ef3a376d4101b36800cda27 100644 (file)
@@ -356,62 +356,43 @@ create_pipe (const char *progname,
     }
 
 # else /* __KLIBC__ */
-  if (!(directory == NULL || strcmp (directory, ".") == 0))
-    {
-      /* A directory argument is not supported in this implementation.  */
-      saved_errno = EINVAL;
-      goto fail_with_saved_errno;
-    }
-
-  int orig_stdin;
-  int orig_stdout;
-  int orig_stderr;
-
-  /* Save standard file handles of parent process.  */
-  if (pipe_stdin || prog_stdin != NULL)
-    orig_stdin = dup_safer_noinherit (STDIN_FILENO);
-  if (pipe_stdout || prog_stdout != NULL)
-    orig_stdout = dup_safer_noinherit (STDOUT_FILENO);
-  if (null_stderr)
-    orig_stderr = dup_safer_noinherit (STDERR_FILENO);
+  int new_stdin = STDIN_FILENO;
+  int new_stdout = STDOUT_FILENO;
+  int new_stderr = STDERR_FILENO;
 
   /* Create standard file handles of child process.  */
   nulloutfd = -1;
   stdinfd = -1;
   stdoutfd = -1;
-  if ((!pipe_stdin || dup2 (ofd[0], STDIN_FILENO) >= 0)
-      && (!pipe_stdout || dup2 (ifd[1], STDOUT_FILENO) >= 0)
+  if ((!pipe_stdin || (new_stdin = ofd[0]) >= 0)
+      && (!pipe_stdout || (new_stdout = ifd[1]) >= 0)
       && (!null_stderr
-          || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0
-              && (nulloutfd == STDERR_FILENO
-                  || (dup2 (nulloutfd, STDERR_FILENO) >= 0
-                      && close (nulloutfd) >= 0))))
+          || ((nulloutfd = open ("NUL", O_RDWR | O_CLOEXEC, 0)) >= 0
+              && (new_stderr = nulloutfd) >= 0))
       && (pipe_stdin
           || prog_stdin == NULL
-          || ((stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0
-              && (stdinfd == STDIN_FILENO
-                  || (dup2 (stdinfd, STDIN_FILENO) >= 0
-                      && close (stdinfd) >= 0))))
+          || ((stdinfd = open (prog_stdin, O_RDONLY | O_CLOEXEC, 0)) >= 0
+              && (new_stdin = stdinfd) >= 0))
       && (pipe_stdout
           || prog_stdout == NULL
-          || ((stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0
-              && (stdoutfd == STDOUT_FILENO
-                  || (dup2 (stdoutfd, STDOUT_FILENO) >= 0
-                      && close (stdoutfd) >= 0)))))
+          || ((stdoutfd = open (prog_stdout, O_WRONLY | O_CLOEXEC, 0)) >= 0
+              && (new_stdout = stdoutfd) >= 0)))
     /* The child process doesn't inherit ifd[0], ifd[1], ofd[0], ofd[1],
        but it inherits all open()ed or dup2()ed file handles (which is what
        we want in the case of STD*_FILENO).  */
     {
-      child = _spawnvpe (P_NOWAIT, prog_path, argv + 1,
-                         (const char **) environ);
+      child = spawnpvech (P_NOWAIT, prog_path, argv + 1,
+                          (const char **) environ, directory,
+                          new_stdin, new_stdout, new_stderr);
 #  if 0 /* Executing arbitrary files as shell scripts is unsecure.  */
       if (child == -1 && errno == ENOEXEC)
         {
           /* prog is not a native executable.  Try to execute it as a
              shell script.  Note that prepare_spawn() has already prepended
              a hidden element "sh.exe" to argv.  */
-          child = _spawnvpe (P_NOWAIT, argv[0], argv,
-                             (const char **) environ);
+          child = spawnpvech (P_NOWAIT, argv[0], argv,
+                              (const char **) environ, directory,
+                              new_stdin, new_stdout, new_stderr);
         }
 #  endif
     }
@@ -424,14 +405,6 @@ create_pipe (const char *progname,
   if (nulloutfd >= 0)
     close (nulloutfd);
 
-  /* Restore standard file handles of parent process.  */
-  if (null_stderr)
-    undup_safer_noinherit (orig_stderr, STDERR_FILENO);
-  if (pipe_stdout || prog_stdout != NULL)
-    undup_safer_noinherit (orig_stdout, STDOUT_FILENO);
-  if (pipe_stdin || prog_stdin != NULL)
-    undup_safer_noinherit (orig_stdin, STDIN_FILENO);
-
   if (pipe_stdin)
     close (ofd[0]);
   if (pipe_stdout)
index 54706ce17f9a5e210d0c94c11c64826aa1c348e6..180b9443174dc6c476e301b75881b7732b36badc 100644 (file)
@@ -1,4 +1,4 @@
-# spawn-pipe.m4 serial 2
+# spawn-pipe.m4 serial 3
 dnl Copyright (C) 2004, 2008-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -8,4 +8,12 @@ AC_DEFUN([gl_SPAWN_PIPE],
 [
   dnl Prerequisites of lib/spawn-pipe.c.
   AC_REQUIRE([AC_TYPE_MODE_T])
+
+  AC_CHECK_HEADERS_ONCE([libcx/spawn2.h])
+  if test $ac_cv_header_libcx_spawn2_h = yes; then
+    HAVE_LIBCX_SPAWN2_H=1
+  else
+    HAVE_LIBCX_SPAWN2_H=0
+  fi
+  AC_SUBST(HAVE_LIBCX_SPAWN2_H)
 ])