|
|
d8307d |
This patch is a rework of the following upstream patch:
|
|
|
d8307d |
|
|
|
d8307d |
commit 0e169691290a6d2187a4ff41495fc5678cbfdcdc
|
|
|
d8307d |
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
|
|
d8307d |
Date: Fri Apr 12 17:39:53 2019 -0300
|
|
|
d8307d |
|
|
|
d8307d |
support: Add support_capture_subprogram
|
|
|
d8307d |
|
|
|
d8307d |
Its API is similar to support_capture_subprocess, but rather creates a
|
|
|
d8307d |
new process based on the input path and arguments. Under the hoods it
|
|
|
d8307d |
uses posix_spawn to create the new process.
|
|
|
d8307d |
|
|
|
d8307d |
It also allows the use of other support_capture_* functions to check
|
|
|
d8307d |
for expected results and free the resources.
|
|
|
d8307d |
|
|
|
d8307d |
Checked on x86_64-linux-gnu.
|
|
|
d8307d |
|
|
|
d8307d |
* support/Makefile (libsupport-routines): Add support_subprocess,
|
|
|
d8307d |
xposix_spawn, xposix_spawn_file_actions_addclose, and
|
|
|
d8307d |
xposix_spawn_file_actions_adddup2.
|
|
|
d8307d |
(tst-support_capture_subprocess-ARGS): New rule.
|
|
|
d8307d |
* support/capture_subprocess.h (support_capture_subprogram): New
|
|
|
d8307d |
prototype.
|
|
|
d8307d |
* support/support_capture_subprocess.c (support_capture_subprocess):
|
|
|
d8307d |
Refactor to use support_subprocess and support_capture_poll.
|
|
|
d8307d |
(support_capture_subprogram): New function.
|
|
|
d8307d |
* support/tst-support_capture_subprocess.c (write_mode_to_str,
|
|
|
d8307d |
str_to_write_mode, test_common, parse_int, handle_restart,
|
|
|
d8307d |
do_subprocess, do_subprogram, do_multiple_tests): New functions.
|
|
|
d8307d |
(do_test): Add support_capture_subprogram tests.
|
|
|
d8307d |
* support/subprocess.h: New file.
|
|
|
d8307d |
* support/support_subprocess.c: Likewise.
|
|
|
d8307d |
* support/xposix_spawn.c: Likewise.
|
|
|
d8307d |
* support/xposix_spawn_file_actions_addclose.c: Likewise.
|
|
|
d8307d |
* support/xposix_spawn_file_actions_adddup2.c: Likewise.
|
|
|
d8307d |
* support/xspawn.h: Likewise.
|
|
|
d8307d |
|
|
|
d8307d |
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
|
|
d8307d |
|
|
|
d8307d |
|
|
|
d8307d |
|
|
|
d8307d |
diff -Nrup a/support/capture_subprocess.h b/support/capture_subprocess.h
|
|
|
d8307d |
--- a/support/capture_subprocess.h 2018-08-01 01:10:47.000000000 -0400
|
|
|
d8307d |
+++ b/support/capture_subprocess.h 2019-05-16 23:37:19.903845257 -0400
|
|
|
d8307d |
@@ -35,6 +35,12 @@ struct support_capture_subprocess
|
|
|
d8307d |
struct support_capture_subprocess support_capture_subprocess
|
|
|
d8307d |
(void (*callback) (void *), void *closure);
|
|
|
d8307d |
|
|
|
d8307d |
+/* Issue FILE with ARGV arguments by using posix_spawn and capture standard
|
|
|
d8307d |
+ output, standard error, and the exit status. The out.buffer and err.buffer
|
|
|
d8307d |
+ are handle as support_capture_subprocess. */
|
|
|
d8307d |
+struct support_capture_subprocess support_capture_subprogram
|
|
|
d8307d |
+ (const char *file, char *const argv[]);
|
|
|
d8307d |
+
|
|
|
d8307d |
/* Deallocate the subprocess data captured by
|
|
|
d8307d |
support_capture_subprocess. */
|
|
|
d8307d |
void support_capture_subprocess_free (struct support_capture_subprocess *);
|
|
|
d8307d |
diff -Nrup a/support/Makefile b/support/Makefile
|
|
|
d8307d |
--- a/support/Makefile 2019-05-16 23:36:51.066665814 -0400
|
|
|
d8307d |
+++ b/support/Makefile 2019-05-17 10:31:24.268313761 -0400
|
|
|
d8307d |
@@ -63,6 +63,7 @@ libsupport-routines = \
|
|
|
d8307d |
support_record_failure \
|
|
|
d8307d |
support_run_diff \
|
|
|
d8307d |
support_shared_allocate \
|
|
|
d8307d |
+ support_subprocess \
|
|
|
d8307d |
support_test_compare_blob \
|
|
|
d8307d |
support_test_compare_failure \
|
|
|
d8307d |
support_test_compare_string \
|
|
|
d8307d |
@@ -147,6 +148,9 @@ libsupport-routines = \
|
|
|
d8307d |
xsigaction \
|
|
|
d8307d |
xsignal \
|
|
|
d8307d |
xsocket \
|
|
|
d8307d |
+ xposix_spawn \
|
|
|
d8307d |
+ xposix_spawn_file_actions_addclose \
|
|
|
d8307d |
+ xposix_spawn_file_actions_adddup2 \
|
|
|
d8307d |
xstrdup \
|
|
|
d8307d |
xstrndup \
|
|
|
d8307d |
xsymlink \
|
|
|
d8307d |
@@ -221,4 +225,6 @@ endif
|
|
|
d8307d |
|
|
|
d8307d |
$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so
|
|
|
d8307d |
|
|
|
d8307d |
+tst-support_capture_subprocess-ARGS = -- $(host-test-program-cmd)
|
|
|
d8307d |
+
|
|
|
d8307d |
include ../Rules
|
|
|
d8307d |
diff -Nrup a/support/subprocess.h b/support/subprocess.h
|
|
|
d8307d |
--- a/support/subprocess.h 1969-12-31 19:00:00.000000000 -0500
|
|
|
d8307d |
+++ b/support/subprocess.h 2019-05-16 23:37:19.903845257 -0400
|
|
|
d8307d |
@@ -0,0 +1,49 @@
|
|
|
d8307d |
+/* Create a subprocess.
|
|
|
d8307d |
+ Copyright (C) 2019 Free Software Foundation, Inc.
|
|
|
d8307d |
+ This file is part of the GNU C Library.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ The GNU C Library is free software; you can redistribute it and/or
|
|
|
d8307d |
+ modify it under the terms of the GNU Lesser General Public
|
|
|
d8307d |
+ License as published by the Free Software Foundation; either
|
|
|
d8307d |
+ version 2.1 of the License, or (at your option) any later version.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
|
d8307d |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
d8307d |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
d8307d |
+ Lesser General Public License for more details.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ You should have received a copy of the GNU Lesser General Public
|
|
|
d8307d |
+ License along with the GNU C Library; if not, see
|
|
|
d8307d |
+ <http://www.gnu.org/licenses/>. */
|
|
|
d8307d |
+
|
|
|
d8307d |
+#ifndef SUPPORT_SUBPROCESS_H
|
|
|
d8307d |
+#define SUPPORT_SUBPROCESS_H
|
|
|
d8307d |
+
|
|
|
d8307d |
+#include <sys/types.h>
|
|
|
d8307d |
+
|
|
|
d8307d |
+struct support_subprocess
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ int stdout_pipe[2];
|
|
|
d8307d |
+ int stderr_pipe[2];
|
|
|
d8307d |
+ pid_t pid;
|
|
|
d8307d |
+};
|
|
|
d8307d |
+
|
|
|
d8307d |
+/* Invoke CALLBACK (CLOSURE) in a subprocess created with fork and return
|
|
|
d8307d |
+ its PID, a pipe redirected to STDOUT, and a pipe redirected to STDERR. */
|
|
|
d8307d |
+struct support_subprocess support_subprocess
|
|
|
d8307d |
+ (void (*callback) (void *), void *closure);
|
|
|
d8307d |
+
|
|
|
d8307d |
+/* Issue FILE with ARGV arguments by using posix_spawn and return is PID, a
|
|
|
d8307d |
+ pipe redirected to STDOUT, and a pipe redirected to STDERR. */
|
|
|
d8307d |
+struct support_subprocess support_subprogram
|
|
|
d8307d |
+ (const char *file, char *const argv[]);
|
|
|
d8307d |
+
|
|
|
d8307d |
+/* Wait for the subprocess indicated by PROC::PID. Return the status
|
|
|
d8307d |
+ indicate by waitpid call. */
|
|
|
d8307d |
+int support_process_wait (struct support_subprocess *proc);
|
|
|
d8307d |
+
|
|
|
d8307d |
+/* Terminate the subprocess indicated by PROC::PID, first with a SIGTERM and
|
|
|
d8307d |
+ then with a SIGKILL. Return the status as for waitpid call. */
|
|
|
d8307d |
+int support_process_terminate (struct support_subprocess *proc);
|
|
|
d8307d |
+
|
|
|
d8307d |
+#endif
|
|
|
d8307d |
diff -Nrup a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
|
|
|
d8307d |
--- a/support/support_capture_subprocess.c 2019-05-16 23:36:50.672677025 -0400
|
|
|
d8307d |
+++ b/support/support_capture_subprocess.c 2019-05-16 23:38:34.298728367 -0400
|
|
|
d8307d |
@@ -16,6 +16,7 @@
|
|
|
d8307d |
License along with the GNU C Library; if not, see
|
|
|
d8307d |
<http://www.gnu.org/licenses/>. */
|
|
|
d8307d |
|
|
|
d8307d |
+#include <support/subprocess.h>
|
|
|
d8307d |
#include <support/capture_subprocess.h>
|
|
|
d8307d |
|
|
|
d8307d |
#include <errno.h>
|
|
|
d8307d |
@@ -23,6 +24,7 @@
|
|
|
d8307d |
#include <support/check.h>
|
|
|
d8307d |
#include <support/xunistd.h>
|
|
|
d8307d |
#include <support/xsocket.h>
|
|
|
d8307d |
+#include <support/xspawn.h>
|
|
|
d8307d |
|
|
|
d8307d |
static void
|
|
|
d8307d |
transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
|
|
|
d8307d |
@@ -50,59 +52,52 @@ transfer (const char *what, struct pollf
|
|
|
d8307d |
}
|
|
|
d8307d |
}
|
|
|
d8307d |
|
|
|
d8307d |
-struct support_capture_subprocess
|
|
|
d8307d |
-support_capture_subprocess (void (*callback) (void *), void *closure)
|
|
|
d8307d |
+static void
|
|
|
d8307d |
+support_capture_poll (struct support_capture_subprocess *result,
|
|
|
d8307d |
+ struct support_subprocess *proc)
|
|
|
d8307d |
{
|
|
|
d8307d |
- struct support_capture_subprocess result;
|
|
|
d8307d |
- xopen_memstream (&result.out);
|
|
|
d8307d |
- xopen_memstream (&result.err);
|
|
|
d8307d |
-
|
|
|
d8307d |
- int stdout_pipe[2];
|
|
|
d8307d |
- xpipe (stdout_pipe);
|
|
|
d8307d |
- TEST_VERIFY (stdout_pipe[0] > STDERR_FILENO);
|
|
|
d8307d |
- TEST_VERIFY (stdout_pipe[1] > STDERR_FILENO);
|
|
|
d8307d |
- int stderr_pipe[2];
|
|
|
d8307d |
- xpipe (stderr_pipe);
|
|
|
d8307d |
- TEST_VERIFY (stderr_pipe[0] > STDERR_FILENO);
|
|
|
d8307d |
- TEST_VERIFY (stderr_pipe[1] > STDERR_FILENO);
|
|
|
d8307d |
-
|
|
|
d8307d |
- TEST_VERIFY (fflush (stdout) == 0);
|
|
|
d8307d |
- TEST_VERIFY (fflush (stderr) == 0);
|
|
|
d8307d |
-
|
|
|
d8307d |
- pid_t pid = xfork ();
|
|
|
d8307d |
- if (pid == 0)
|
|
|
d8307d |
- {
|
|
|
d8307d |
- xclose (stdout_pipe[0]);
|
|
|
d8307d |
- xclose (stderr_pipe[0]);
|
|
|
d8307d |
- xdup2 (stdout_pipe[1], STDOUT_FILENO);
|
|
|
d8307d |
- xdup2 (stderr_pipe[1], STDERR_FILENO);
|
|
|
d8307d |
- xclose (stdout_pipe[1]);
|
|
|
d8307d |
- xclose (stderr_pipe[1]);
|
|
|
d8307d |
- callback (closure);
|
|
|
d8307d |
- _exit (0);
|
|
|
d8307d |
- }
|
|
|
d8307d |
- xclose (stdout_pipe[1]);
|
|
|
d8307d |
- xclose (stderr_pipe[1]);
|
|
|
d8307d |
-
|
|
|
d8307d |
struct pollfd fds[2] =
|
|
|
d8307d |
{
|
|
|
d8307d |
- { .fd = stdout_pipe[0], .events = POLLIN },
|
|
|
d8307d |
- { .fd = stderr_pipe[0], .events = POLLIN },
|
|
|
d8307d |
+ { .fd = proc->stdout_pipe[0], .events = POLLIN },
|
|
|
d8307d |
+ { .fd = proc->stderr_pipe[0], .events = POLLIN },
|
|
|
d8307d |
};
|
|
|
d8307d |
|
|
|
d8307d |
do
|
|
|
d8307d |
{
|
|
|
d8307d |
xpoll (fds, 2, -1);
|
|
|
d8307d |
- transfer ("stdout", &fds[0], &result.out);
|
|
|
d8307d |
- transfer ("stderr", &fds[1], &result.err);
|
|
|
d8307d |
+ transfer ("stdout", &fds[0], &result->out);
|
|
|
d8307d |
+ transfer ("stderr", &fds[1], &result->err);
|
|
|
d8307d |
}
|
|
|
d8307d |
while (fds[0].events != 0 || fds[1].events != 0);
|
|
|
d8307d |
- xclose (stdout_pipe[0]);
|
|
|
d8307d |
- xclose (stderr_pipe[0]);
|
|
|
d8307d |
+ xfclose_memstream (&result->out);
|
|
|
d8307d |
+ xfclose_memstream (&result->err);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ result->status = support_process_wait (proc);
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
+struct support_capture_subprocess
|
|
|
d8307d |
+support_capture_subprocess (void (*callback) (void *), void *closure)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ struct support_capture_subprocess result;
|
|
|
d8307d |
+ xopen_memstream (&result.out);
|
|
|
d8307d |
+ xopen_memstream (&result.err);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ struct support_subprocess proc = support_subprocess (callback, closure);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ support_capture_poll (&result, &proc;;
|
|
|
d8307d |
+ return result;
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
+struct support_capture_subprocess
|
|
|
d8307d |
+support_capture_subprogram (const char *file, char *const argv[])
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ struct support_capture_subprocess result;
|
|
|
d8307d |
+ xopen_memstream (&result.out);
|
|
|
d8307d |
+ xopen_memstream (&result.err);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ struct support_subprocess proc = support_subprogram (file, argv);
|
|
|
d8307d |
|
|
|
d8307d |
- xfclose_memstream (&result.out);
|
|
|
d8307d |
- xfclose_memstream (&result.err);
|
|
|
d8307d |
- xwaitpid (pid, &result.status, 0);
|
|
|
d8307d |
+ support_capture_poll (&result, &proc;;
|
|
|
d8307d |
return result;
|
|
|
d8307d |
}
|
|
|
d8307d |
|
|
|
d8307d |
diff -Nrup a/support/support_subprocess.c b/support/support_subprocess.c
|
|
|
d8307d |
--- a/support/support_subprocess.c 1969-12-31 19:00:00.000000000 -0500
|
|
|
d8307d |
+++ b/support/support_subprocess.c 2019-05-16 23:37:19.903845257 -0400
|
|
|
d8307d |
@@ -0,0 +1,152 @@
|
|
|
d8307d |
+/* Create subprocess.
|
|
|
d8307d |
+ Copyright (C) 2019 Free Software Foundation, Inc.
|
|
|
d8307d |
+ This file is part of the GNU C Library.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ The GNU C Library is free software; you can redistribute it and/or
|
|
|
d8307d |
+ modify it under the terms of the GNU Lesser General Public
|
|
|
d8307d |
+ License as published by the Free Software Foundation; either
|
|
|
d8307d |
+ version 2.1 of the License, or (at your option) any later version.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
|
d8307d |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
d8307d |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
d8307d |
+ Lesser General Public License for more details.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ You should have received a copy of the GNU Lesser General Public
|
|
|
d8307d |
+ License along with the GNU C Library; if not, see
|
|
|
d8307d |
+ <http://www.gnu.org/licenses/>. */
|
|
|
d8307d |
+
|
|
|
d8307d |
+#include <stdio.h>
|
|
|
d8307d |
+#include <signal.h>
|
|
|
d8307d |
+#include <time.h>
|
|
|
d8307d |
+#include <sys/wait.h>
|
|
|
d8307d |
+#include <stdbool.h>
|
|
|
d8307d |
+#include <support/xspawn.h>
|
|
|
d8307d |
+#include <support/check.h>
|
|
|
d8307d |
+#include <support/xunistd.h>
|
|
|
d8307d |
+#include <support/subprocess.h>
|
|
|
d8307d |
+
|
|
|
d8307d |
+static struct support_subprocess
|
|
|
d8307d |
+support_suprocess_init (void)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ struct support_subprocess result;
|
|
|
d8307d |
+
|
|
|
d8307d |
+ xpipe (result.stdout_pipe);
|
|
|
d8307d |
+ TEST_VERIFY (result.stdout_pipe[0] > STDERR_FILENO);
|
|
|
d8307d |
+ TEST_VERIFY (result.stdout_pipe[1] > STDERR_FILENO);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ xpipe (result.stderr_pipe);
|
|
|
d8307d |
+ TEST_VERIFY (result.stderr_pipe[0] > STDERR_FILENO);
|
|
|
d8307d |
+ TEST_VERIFY (result.stderr_pipe[1] > STDERR_FILENO);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ TEST_VERIFY (fflush (stdout) == 0);
|
|
|
d8307d |
+ TEST_VERIFY (fflush (stderr) == 0);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ return result;
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
+struct support_subprocess
|
|
|
d8307d |
+support_subprocess (void (*callback) (void *), void *closure)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ struct support_subprocess result = support_suprocess_init ();
|
|
|
d8307d |
+
|
|
|
d8307d |
+ result.pid = xfork ();
|
|
|
d8307d |
+ if (result.pid == 0)
|
|
|
d8307d |
+ {
|
|
|
d8307d |
+ xclose (result.stdout_pipe[0]);
|
|
|
d8307d |
+ xclose (result.stderr_pipe[0]);
|
|
|
d8307d |
+ xdup2 (result.stdout_pipe[1], STDOUT_FILENO);
|
|
|
d8307d |
+ xdup2 (result.stderr_pipe[1], STDERR_FILENO);
|
|
|
d8307d |
+ xclose (result.stdout_pipe[1]);
|
|
|
d8307d |
+ xclose (result.stderr_pipe[1]);
|
|
|
d8307d |
+ callback (closure);
|
|
|
d8307d |
+ _exit (0);
|
|
|
d8307d |
+ }
|
|
|
d8307d |
+ xclose (result.stdout_pipe[1]);
|
|
|
d8307d |
+ xclose (result.stderr_pipe[1]);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ return result;
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
+struct support_subprocess
|
|
|
d8307d |
+support_subprogram (const char *file, char *const argv[])
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ struct support_subprocess result = support_suprocess_init ();
|
|
|
d8307d |
+
|
|
|
d8307d |
+ posix_spawn_file_actions_t fa;
|
|
|
d8307d |
+ /* posix_spawn_file_actions_init does not fail. */
|
|
|
d8307d |
+ posix_spawn_file_actions_init (&fa);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[0]);
|
|
|
d8307d |
+ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[0]);
|
|
|
d8307d |
+ xposix_spawn_file_actions_adddup2 (&fa, result.stdout_pipe[1], STDOUT_FILENO);
|
|
|
d8307d |
+ xposix_spawn_file_actions_adddup2 (&fa, result.stderr_pipe[1], STDERR_FILENO);
|
|
|
d8307d |
+ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]);
|
|
|
d8307d |
+ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ result.pid = xposix_spawn (file, &fa, NULL, argv, NULL);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ xclose (result.stdout_pipe[1]);
|
|
|
d8307d |
+ xclose (result.stderr_pipe[1]);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ return result;
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
+int
|
|
|
d8307d |
+support_process_wait (struct support_subprocess *proc)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ xclose (proc->stdout_pipe[0]);
|
|
|
d8307d |
+ xclose (proc->stderr_pipe[0]);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ int status;
|
|
|
d8307d |
+ xwaitpid (proc->pid, &status, 0);
|
|
|
d8307d |
+ return status;
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
+
|
|
|
d8307d |
+static bool
|
|
|
d8307d |
+support_process_kill (int pid, int signo, int *status)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ /* Kill the whole process group. */
|
|
|
d8307d |
+ kill (-pid, signo);
|
|
|
d8307d |
+ /* In case setpgid failed in the child, kill it individually too. */
|
|
|
d8307d |
+ kill (pid, signo);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ /* Wait for it to terminate. */
|
|
|
d8307d |
+ pid_t killed;
|
|
|
d8307d |
+ for (int i = 0; i < 5; ++i)
|
|
|
d8307d |
+ {
|
|
|
d8307d |
+ int status;
|
|
|
d8307d |
+ killed = xwaitpid (pid, &status, WNOHANG|WUNTRACED);
|
|
|
d8307d |
+ if (killed != 0)
|
|
|
d8307d |
+ break;
|
|
|
d8307d |
+
|
|
|
d8307d |
+ /* Delay, give the system time to process the kill. If the
|
|
|
d8307d |
+ nanosleep() call return prematurely, all the better. We
|
|
|
d8307d |
+ won't restart it since this probably means the child process
|
|
|
d8307d |
+ finally died. */
|
|
|
d8307d |
+ nanosleep (&((struct timespec) { 0, 100000000 }), NULL);
|
|
|
d8307d |
+ }
|
|
|
d8307d |
+ if (killed != 0 && killed != pid)
|
|
|
d8307d |
+ return false;
|
|
|
d8307d |
+
|
|
|
d8307d |
+ return true;
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
+int
|
|
|
d8307d |
+support_process_terminate (struct support_subprocess *proc)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ xclose (proc->stdout_pipe[0]);
|
|
|
d8307d |
+ xclose (proc->stderr_pipe[0]);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ int status;
|
|
|
d8307d |
+ pid_t killed = xwaitpid (proc->pid, &status, WNOHANG|WUNTRACED);
|
|
|
d8307d |
+ if (killed != 0 && killed == proc->pid)
|
|
|
d8307d |
+ return status;
|
|
|
d8307d |
+
|
|
|
d8307d |
+ /* Subprocess is still running, terminate it. */
|
|
|
d8307d |
+ if (!support_process_kill (proc->pid, SIGTERM, &status) )
|
|
|
d8307d |
+ support_process_kill (proc->pid, SIGKILL, &status);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ return status;
|
|
|
d8307d |
+}
|
|
|
d8307d |
diff -Nrup a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c
|
|
|
d8307d |
--- a/support/tst-support_capture_subprocess.c 2018-08-01 01:10:47.000000000 -0400
|
|
|
d8307d |
+++ b/support/tst-support_capture_subprocess.c 2019-05-16 23:37:19.904845228 -0400
|
|
|
d8307d |
@@ -23,8 +23,20 @@
|
|
|
d8307d |
#include <support/capture_subprocess.h>
|
|
|
d8307d |
#include <support/check.h>
|
|
|
d8307d |
#include <support/support.h>
|
|
|
d8307d |
+#include <support/temp_file.h>
|
|
|
d8307d |
#include <sys/wait.h>
|
|
|
d8307d |
#include <unistd.h>
|
|
|
d8307d |
+#include <paths.h>
|
|
|
d8307d |
+#include <getopt.h>
|
|
|
d8307d |
+#include <limits.h>
|
|
|
d8307d |
+#include <errno.h>
|
|
|
d8307d |
+#include <array_length.h>
|
|
|
d8307d |
+
|
|
|
d8307d |
+/* Nonzero if the program gets called via 'exec'. */
|
|
|
d8307d |
+static int restart;
|
|
|
d8307d |
+
|
|
|
d8307d |
+/* Hold the four initial argument used to respawn the process. */
|
|
|
d8307d |
+static char *initial_argv[5];
|
|
|
d8307d |
|
|
|
d8307d |
/* Write one byte at *P to FD and advance *P. Do nothing if *P is
|
|
|
d8307d |
'\0'. */
|
|
|
d8307d |
@@ -42,6 +54,30 @@ transfer (const unsigned char **p, int f
|
|
|
d8307d |
enum write_mode { out_first, err_first, interleave,
|
|
|
d8307d |
write_mode_last = interleave };
|
|
|
d8307d |
|
|
|
d8307d |
+static const char *
|
|
|
d8307d |
+write_mode_to_str (enum write_mode mode)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ switch (mode)
|
|
|
d8307d |
+ {
|
|
|
d8307d |
+ case out_first: return "out_first";
|
|
|
d8307d |
+ case err_first: return "err_first";
|
|
|
d8307d |
+ case interleave: return "interleave";
|
|
|
d8307d |
+ default: return "write_mode_last";
|
|
|
d8307d |
+ }
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
+static enum write_mode
|
|
|
d8307d |
+str_to_write_mode (const char *mode)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ if (strcmp (mode, "out_first") == 0)
|
|
|
d8307d |
+ return out_first;
|
|
|
d8307d |
+ else if (strcmp (mode, "err_first") == 0)
|
|
|
d8307d |
+ return err_first;
|
|
|
d8307d |
+ else if (strcmp (mode, "interleave") == 0)
|
|
|
d8307d |
+ return interleave;
|
|
|
d8307d |
+ return write_mode_last;
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
/* Describe what to write in the subprocess. */
|
|
|
d8307d |
struct test
|
|
|
d8307d |
{
|
|
|
d8307d |
@@ -52,11 +88,9 @@ struct test
|
|
|
d8307d |
int status;
|
|
|
d8307d |
};
|
|
|
d8307d |
|
|
|
d8307d |
-/* For use with support_capture_subprocess. */
|
|
|
d8307d |
-static void
|
|
|
d8307d |
-callback (void *closure)
|
|
|
d8307d |
+_Noreturn static void
|
|
|
d8307d |
+test_common (const struct test *test)
|
|
|
d8307d |
{
|
|
|
d8307d |
- const struct test *test = closure;
|
|
|
d8307d |
bool mode_ok = false;
|
|
|
d8307d |
switch (test->write_mode)
|
|
|
d8307d |
{
|
|
|
d8307d |
@@ -95,6 +129,40 @@ callback (void *closure)
|
|
|
d8307d |
exit (test->status);
|
|
|
d8307d |
}
|
|
|
d8307d |
|
|
|
d8307d |
+static int
|
|
|
d8307d |
+parse_int (const char *str)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ char *endptr;
|
|
|
d8307d |
+ long int ret = strtol (str, &endptr, 10);
|
|
|
d8307d |
+ TEST_COMPARE (errno, 0);
|
|
|
d8307d |
+ TEST_VERIFY (ret >= 0 && ret <= INT_MAX);
|
|
|
d8307d |
+ return ret;
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
+/* For use with support_capture_subprogram. */
|
|
|
d8307d |
+_Noreturn static void
|
|
|
d8307d |
+handle_restart (char *out, char *err, const char *write_mode,
|
|
|
d8307d |
+ const char *signal, const char *status)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ struct test test =
|
|
|
d8307d |
+ {
|
|
|
d8307d |
+ out,
|
|
|
d8307d |
+ err,
|
|
|
d8307d |
+ str_to_write_mode (write_mode),
|
|
|
d8307d |
+ parse_int (signal),
|
|
|
d8307d |
+ parse_int (status)
|
|
|
d8307d |
+ };
|
|
|
d8307d |
+ test_common (&test);
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
+/* For use with support_capture_subprocess. */
|
|
|
d8307d |
+_Noreturn static void
|
|
|
d8307d |
+callback (void *closure)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ const struct test *test = closure;
|
|
|
d8307d |
+ test_common (test);
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
/* Create a heap-allocated random string of letters. */
|
|
|
d8307d |
static char *
|
|
|
d8307d |
random_string (size_t length)
|
|
|
d8307d |
@@ -130,12 +198,59 @@ check_stream (const char *what, const st
|
|
|
d8307d |
}
|
|
|
d8307d |
}
|
|
|
d8307d |
|
|
|
d8307d |
+static struct support_capture_subprocess
|
|
|
d8307d |
+do_subprocess (struct test *test)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ return support_capture_subprocess (callback, test);
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
+static struct support_capture_subprocess
|
|
|
d8307d |
+do_subprogram (const struct test *test)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ /* Three digits per byte plus null terminator. */
|
|
|
d8307d |
+ char signalstr[3 * sizeof(int) + 1];
|
|
|
d8307d |
+ snprintf (signalstr, sizeof (signalstr), "%d", test->signal);
|
|
|
d8307d |
+ char statusstr[3 * sizeof(int) + 1];
|
|
|
d8307d |
+ snprintf (statusstr, sizeof (statusstr), "%d", test->status);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ int argc = 0;
|
|
|
d8307d |
+ enum {
|
|
|
d8307d |
+ /* 4 elements from initial_argv (path to ld.so, '--library-path', the
|
|
|
d8307d |
+ path', and application name'), 2 for restart argument ('--direct',
|
|
|
d8307d |
+ '--restart'), 5 arguments plus NULL. */
|
|
|
d8307d |
+ argv_size = 12
|
|
|
d8307d |
+ };
|
|
|
d8307d |
+ char *args[argv_size];
|
|
|
d8307d |
+
|
|
|
d8307d |
+ for (char **arg = initial_argv; *arg != NULL; arg++)
|
|
|
d8307d |
+ args[argc++] = *arg;
|
|
|
d8307d |
+
|
|
|
d8307d |
+ args[argc++] = (char*) "--direct";
|
|
|
d8307d |
+ args[argc++] = (char*) "--restart";
|
|
|
d8307d |
+
|
|
|
d8307d |
+ args[argc++] = test->out;
|
|
|
d8307d |
+ args[argc++] = test->err;
|
|
|
d8307d |
+ args[argc++] = (char*) write_mode_to_str (test->write_mode);
|
|
|
d8307d |
+ args[argc++] = signalstr;
|
|
|
d8307d |
+ args[argc++] = statusstr;
|
|
|
d8307d |
+ args[argc] = NULL;
|
|
|
d8307d |
+ TEST_VERIFY (argc < argv_size);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ return support_capture_subprogram (args[0], args);
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
+enum test_type
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ subprocess,
|
|
|
d8307d |
+ subprogram,
|
|
|
d8307d |
+};
|
|
|
d8307d |
+
|
|
|
d8307d |
static int
|
|
|
d8307d |
-do_test (void)
|
|
|
d8307d |
+do_multiple_tests (enum test_type type)
|
|
|
d8307d |
{
|
|
|
d8307d |
const int lengths[] = {0, 1, 17, 512, 20000, -1};
|
|
|
d8307d |
|
|
|
d8307d |
- /* Test multiple combinations of support_capture_subprocess.
|
|
|
d8307d |
+ /* Test multiple combinations of support_capture_sub{process,program}.
|
|
|
d8307d |
|
|
|
d8307d |
length_idx_stdout: Index into the lengths array above,
|
|
|
d8307d |
controls how many bytes are written by the subprocess to
|
|
|
d8307d |
@@ -164,8 +279,10 @@ do_test (void)
|
|
|
d8307d |
TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]);
|
|
|
d8307d |
TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]);
|
|
|
d8307d |
|
|
|
d8307d |
- struct support_capture_subprocess result
|
|
|
d8307d |
- = support_capture_subprocess (callback, &test);
|
|
|
d8307d |
+ struct support_capture_subprocess result
|
|
|
d8307d |
+ = type == subprocess ? do_subprocess (&test)
|
|
|
d8307d |
+ : do_subprogram (&test);
|
|
|
d8307d |
+
|
|
|
d8307d |
check_stream ("stdout", &result.out, test.out);
|
|
|
d8307d |
check_stream ("stderr", &result.err, test.err);
|
|
|
d8307d |
if (test.signal != 0)
|
|
|
d8307d |
@@ -185,4 +302,54 @@ do_test (void)
|
|
|
d8307d |
return 0;
|
|
|
d8307d |
}
|
|
|
d8307d |
|
|
|
d8307d |
+static int
|
|
|
d8307d |
+do_test (int argc, char *argv[])
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ /* We must have either:
|
|
|
d8307d |
+
|
|
|
d8307d |
+ - one or four parameters if called initially:
|
|
|
d8307d |
+ + argv[1]: path for ld.so optional
|
|
|
d8307d |
+ + argv[2]: "--library-path" optional
|
|
|
d8307d |
+ + argv[3]: the library path optional
|
|
|
d8307d |
+ + argv[4]: the application name
|
|
|
d8307d |
+
|
|
|
d8307d |
+ - six parameters left if called through re-execution:
|
|
|
d8307d |
+ + argv[1]: the application name
|
|
|
d8307d |
+ + argv[2]: the stdout to print
|
|
|
d8307d |
+ + argv[3]: the stderr to print
|
|
|
d8307d |
+ + argv[4]: the write mode to use
|
|
|
d8307d |
+ + argv[5]: the signal to issue
|
|
|
d8307d |
+ + argv[6]: the exit status code to use
|
|
|
d8307d |
+
|
|
|
d8307d |
+ * When built with --enable-hardcoded-path-in-tests or issued without
|
|
|
d8307d |
+ using the loader directly.
|
|
|
d8307d |
+ */
|
|
|
d8307d |
+
|
|
|
d8307d |
+ if (argc != (restart ? 6 : 5) && argc != (restart ? 6 : 2))
|
|
|
d8307d |
+ FAIL_EXIT1 ("wrong number of arguments (%d)", argc);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ if (restart)
|
|
|
d8307d |
+ {
|
|
|
d8307d |
+ handle_restart (argv[1], /* stdout */
|
|
|
d8307d |
+ argv[2], /* stderr */
|
|
|
d8307d |
+ argv[3], /* write_mode */
|
|
|
d8307d |
+ argv[4], /* signal */
|
|
|
d8307d |
+ argv[5]); /* status */
|
|
|
d8307d |
+ }
|
|
|
d8307d |
+
|
|
|
d8307d |
+ initial_argv[0] = argv[1]; /* path for ld.so */
|
|
|
d8307d |
+ initial_argv[1] = argv[2]; /* "--library-path" */
|
|
|
d8307d |
+ initial_argv[2] = argv[3]; /* the library path */
|
|
|
d8307d |
+ initial_argv[3] = argv[4]; /* the application name */
|
|
|
d8307d |
+ initial_argv[4] = NULL;
|
|
|
d8307d |
+
|
|
|
d8307d |
+ do_multiple_tests (subprocess);
|
|
|
d8307d |
+ do_multiple_tests (subprogram);
|
|
|
d8307d |
+
|
|
|
d8307d |
+ return 0;
|
|
|
d8307d |
+}
|
|
|
d8307d |
+
|
|
|
d8307d |
+#define CMDLINE_OPTIONS \
|
|
|
d8307d |
+ { "restart", no_argument, &restart, 1 },
|
|
|
d8307d |
+#define TEST_FUNCTION_ARGV do_test
|
|
|
d8307d |
#include <support/test-driver.c>
|
|
|
d8307d |
diff -Nrup a/support/xposix_spawn.c b/support/xposix_spawn.c
|
|
|
d8307d |
--- a/support/xposix_spawn.c 1969-12-31 19:00:00.000000000 -0500
|
|
|
d8307d |
+++ b/support/xposix_spawn.c 2019-05-16 23:37:19.904845228 -0400
|
|
|
d8307d |
@@ -0,0 +1,32 @@
|
|
|
d8307d |
+/* xposix_spawn implementation.
|
|
|
d8307d |
+ Copyright (C) 2019 Free Software Foundation, Inc.
|
|
|
d8307d |
+ This file is part of the GNU C Library.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ The GNU C Library is free software; you can redistribute it and/or
|
|
|
d8307d |
+ modify it under the terms of the GNU Lesser General Public
|
|
|
d8307d |
+ License as published by the Free Software Foundation; either
|
|
|
d8307d |
+ version 2.1 of the License, or (at your option) any later version.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
|
d8307d |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
d8307d |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
d8307d |
+ Lesser General Public License for more details.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ You should have received a copy of the GNU Lesser General Public
|
|
|
d8307d |
+ License along with the GNU C Library; if not, see
|
|
|
d8307d |
+ <http://www.gnu.org/licenses/>. */
|
|
|
d8307d |
+
|
|
|
d8307d |
+#include <support/xspawn.h>
|
|
|
d8307d |
+#include <support/check.h>
|
|
|
d8307d |
+
|
|
|
d8307d |
+pid_t
|
|
|
d8307d |
+xposix_spawn (const char *file, const posix_spawn_file_actions_t *fa,
|
|
|
d8307d |
+ const posix_spawnattr_t *attr, char *const args[],
|
|
|
d8307d |
+ char *const envp[])
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ pid_t pid;
|
|
|
d8307d |
+ int status = posix_spawn (&pid, file, fa, attr, args, envp);
|
|
|
d8307d |
+ if (status != 0)
|
|
|
d8307d |
+ FAIL_EXIT1 ("posix_spawn to %s file failed: %m", file);
|
|
|
d8307d |
+ return pid;
|
|
|
d8307d |
+}
|
|
|
d8307d |
diff -Nrup a/support/xposix_spawn_file_actions_addclose.c b/support/xposix_spawn_file_actions_addclose.c
|
|
|
d8307d |
--- a/support/xposix_spawn_file_actions_addclose.c 1969-12-31 19:00:00.000000000 -0500
|
|
|
d8307d |
+++ b/support/xposix_spawn_file_actions_addclose.c 2019-05-16 23:37:19.904845228 -0400
|
|
|
d8307d |
@@ -0,0 +1,29 @@
|
|
|
d8307d |
+/* xposix_spawn_file_actions_addclose implementation.
|
|
|
d8307d |
+ Copyright (C) 2019 Free Software Foundation, Inc.
|
|
|
d8307d |
+ This file is part of the GNU C Library.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ The GNU C Library is free software; you can redistribute it and/or
|
|
|
d8307d |
+ modify it under the terms of the GNU Lesser General Public
|
|
|
d8307d |
+ License as published by the Free Software Foundation; either
|
|
|
d8307d |
+ version 2.1 of the License, or (at your option) any later version.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
|
d8307d |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
d8307d |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
d8307d |
+ Lesser General Public License for more details.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ You should have received a copy of the GNU Lesser General Public
|
|
|
d8307d |
+ License along with the GNU C Library; if not, see
|
|
|
d8307d |
+ <http://www.gnu.org/licenses/>. */
|
|
|
d8307d |
+
|
|
|
d8307d |
+#include <support/xspawn.h>
|
|
|
d8307d |
+#include <support/check.h>
|
|
|
d8307d |
+
|
|
|
d8307d |
+int
|
|
|
d8307d |
+xposix_spawn_file_actions_addclose (posix_spawn_file_actions_t *fa, int fd)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ int status = posix_spawn_file_actions_addclose (fa, fd);
|
|
|
d8307d |
+ if (status == -1)
|
|
|
d8307d |
+ FAIL_EXIT1 ("posix_spawn_file_actions_addclose failed: %m\n");
|
|
|
d8307d |
+ return status;
|
|
|
d8307d |
+}
|
|
|
d8307d |
diff -Nrup a/support/xposix_spawn_file_actions_adddup2.c b/support/xposix_spawn_file_actions_adddup2.c
|
|
|
d8307d |
--- a/support/xposix_spawn_file_actions_adddup2.c 1969-12-31 19:00:00.000000000 -0500
|
|
|
d8307d |
+++ b/support/xposix_spawn_file_actions_adddup2.c 2019-05-16 23:37:19.904845228 -0400
|
|
|
d8307d |
@@ -0,0 +1,30 @@
|
|
|
d8307d |
+/* xposix_spawn_file_actions_adddup2 implementation.
|
|
|
d8307d |
+ Copyright (C) 2019 Free Software Foundation, Inc.
|
|
|
d8307d |
+ This file is part of the GNU C Library.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ The GNU C Library is free software; you can redistribute it and/or
|
|
|
d8307d |
+ modify it under the terms of the GNU Lesser General Public
|
|
|
d8307d |
+ License as published by the Free Software Foundation; either
|
|
|
d8307d |
+ version 2.1 of the License, or (at your option) any later version.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
|
d8307d |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
d8307d |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
d8307d |
+ Lesser General Public License for more details.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ You should have received a copy of the GNU Lesser General Public
|
|
|
d8307d |
+ License along with the GNU C Library; if not, see
|
|
|
d8307d |
+ <http://www.gnu.org/licenses/>. */
|
|
|
d8307d |
+
|
|
|
d8307d |
+#include <support/xspawn.h>
|
|
|
d8307d |
+#include <support/check.h>
|
|
|
d8307d |
+
|
|
|
d8307d |
+int
|
|
|
d8307d |
+xposix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *fa, int fd,
|
|
|
d8307d |
+ int newfd)
|
|
|
d8307d |
+{
|
|
|
d8307d |
+ int status = posix_spawn_file_actions_adddup2 (fa, fd, newfd);
|
|
|
d8307d |
+ if (status == -1)
|
|
|
d8307d |
+ FAIL_EXIT1 ("posix_spawn_file_actions_adddup2 failed: %m\n");
|
|
|
d8307d |
+ return status;
|
|
|
d8307d |
+}
|
|
|
d8307d |
diff -Nrup a/support/xspawn.h b/support/xspawn.h
|
|
|
d8307d |
--- a/support/xspawn.h 1969-12-31 19:00:00.000000000 -0500
|
|
|
d8307d |
+++ b/support/xspawn.h 2019-05-16 23:37:19.904845228 -0400
|
|
|
d8307d |
@@ -0,0 +1,34 @@
|
|
|
d8307d |
+/* posix_spawn with support checks.
|
|
|
d8307d |
+ Copyright (C) 2019 Free Software Foundation, Inc.
|
|
|
d8307d |
+ This file is part of the GNU C Library.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ The GNU C Library is free software; you can redistribute it and/or
|
|
|
d8307d |
+ modify it under the terms of the GNU Lesser General Public
|
|
|
d8307d |
+ License as published by the Free Software Foundation; either
|
|
|
d8307d |
+ version 2.1 of the License, or (at your option) any later version.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
|
d8307d |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
d8307d |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
d8307d |
+ Lesser General Public License for more details.
|
|
|
d8307d |
+
|
|
|
d8307d |
+ You should have received a copy of the GNU Lesser General Public
|
|
|
d8307d |
+ License along with the GNU C Library; if not, see
|
|
|
d8307d |
+ <http://www.gnu.org/licenses/>. */
|
|
|
d8307d |
+
|
|
|
d8307d |
+#ifndef SUPPORT_XSPAWN_H
|
|
|
d8307d |
+#define SUPPORT_XSPAWN_H
|
|
|
d8307d |
+
|
|
|
d8307d |
+#include <spawn.h>
|
|
|
d8307d |
+
|
|
|
d8307d |
+__BEGIN_DECLS
|
|
|
d8307d |
+
|
|
|
d8307d |
+int xposix_spawn_file_actions_addclose (posix_spawn_file_actions_t *, int);
|
|
|
d8307d |
+int xposix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *, int, int);
|
|
|
d8307d |
+
|
|
|
d8307d |
+pid_t xposix_spawn (const char *, const posix_spawn_file_actions_t *,
|
|
|
d8307d |
+ const posix_spawnattr_t *, char *const [], char *const []);
|
|
|
d8307d |
+
|
|
|
d8307d |
+__END_DECLS
|
|
|
d8307d |
+
|
|
|
d8307d |
+#endif
|