* 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-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++.
#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"
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;
+}
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 */
}
# 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
}
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)
-# 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,
[
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)
])