LIBCx, which is a kLIBC extension library, provides spawn2() to support
this feature. If LIBCx is available, then support a directory argument
using spawn2() of LIBCx.

* lib/spawn-pipe.c (create_pipe) [kLIBC]: Use spawn2() of LIBCx to support
a directory argument if available.
* m4/spawn-pipe.m4 (gl_SPAWN_PIPE): Check the availability of
libcx/spawn2.h.
* modules/spawn-pipe (Depends-on): Add wait, waitid and waitpid if
libcx/spawn2.h exists.
---
 lib/spawn-pipe.c   | 45 ++++++++++++++++++++++++++++++++++++++++-----
 m4/spawn-pipe.m4   |  8 ++++++++
 modules/spawn-pipe |  3 +++
 3 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/lib/spawn-pipe.c b/lib/spawn-pipe.c
index 0f03926e9f..a4e4bc2581 100644
--- a/lib/spawn-pipe.c
+++ b/lib/spawn-pipe.c
@@ -72,6 +72,10 @@
 
 /* OS/2 kLIBC API.  */
 # include <process.h>
+# include <dlfcn.h>
+# if HAVE_LIBCX_SPAWN2_H
+#  include <libcx/spawn2.h>
+# endif
 # include "os2-spawn.h"
 
 #else
@@ -356,11 +360,34 @@ create_pipe (const char *progname,
     }
 
 # else /* __KLIBC__ */
+#  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;
+#  endif
+
   if (!(directory == NULL || strcmp (directory, ".") == 0))
     {
-      /* A directory argument is not supported in this implementation.  */
-      saved_errno = EINVAL;
-      goto fail_with_saved_errno;
+#  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;
+        }
+
+      if (!libcx_spawn2_loaded)
+#  endif
+        {
+          /* A directory argument is not supported in this implementation.  */
+          saved_errno = EINVAL;
+          goto fail_with_saved_errno;
+        }
     }
 
   int orig_stdin;
@@ -402,8 +429,16 @@ create_pipe (const char *progname,
        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);
+#  if HAVE_LIBCX_SPAWN2_H
+      if (directory == NULL || strcmp (directory, ".") == 0)
+#  endif
+        child = _spawnvpe (P_NOWAIT, prog_path, argv + 1,
+                           (const char **) environ);
+#  if HAVE_LIBCX_SPAWN2_H
+      else
+        child = libcx_spawn2 (P_NOWAIT | P_2_THREADSAFE, prog_path, argv + 1,
+                              directory, (const char **) environ, NULL);
+#  endif
 #  if 0 /* Executing arbitrary files as shell scripts is unsecure.  */
       if (child == -1 && errno == ENOEXEC)
         {
diff --git a/m4/spawn-pipe.m4 b/m4/spawn-pipe.m4
index 6539bdbb95..cb7e5dc8eb 100644
--- a/m4/spawn-pipe.m4
+++ b/m4/spawn-pipe.m4
@@ -9,4 +9,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)
 ])
diff --git a/modules/spawn-pipe b/modules/spawn-pipe
index b2b343c093..d94dee1ad6 100644
--- a/modules/spawn-pipe
+++ b/modules/spawn-pipe
@@ -43,6 +43,9 @@ unistd-safer
 wait-process
 windows-spawn
 xalloc-die
+wait                                [test $HAVE_LIBCX_SPAWN2_H = 1]
+waitid                              [test $HAVE_LIBCX_SPAWN2_H = 1]
+waitpid                             [test $HAVE_LIBCX_SPAWN2_H = 1]
 
 configure.ac:
 gl_SPAWN_PIPE
-- 
2.42.0


Reply via email to