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