From patchwork Tue Apr 16 21:27:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 162386 Delivered-To: patch@linaro.org Received: by 2002:a02:c6d8:0:0:0:0:0 with SMTP id r24csp4715606jan; Tue, 16 Apr 2019 14:27:34 -0700 (PDT) X-Google-Smtp-Source: APXvYqw7fqOdPDQJDch1CJBkp6AmG/PgGz8P3tVZodN7w3Z95j59MMqwJ/QLboaffqA8DX3rVR7d X-Received: by 2002:a62:5206:: with SMTP id g6mr84736068pfb.227.1555450054121; Tue, 16 Apr 2019 14:27:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1555450054; cv=none; d=google.com; s=arc-20160816; b=TeiULG5Jlg5+2yywBuZXF7bg2v05LMLW+pmZ6YYJJU/3O3hb3A5zHp8Ws7QLrSiCln vCdqqLlU49FfIDCe5Nu9XKl0/tVTuqsbuTLoWYYSf+9eHm5Wi65/qN08j9h79/2pjPfK CH143v36+6v4IIzkArOcNJv/eY53Ybs0L6pix/JorQ6DSnYLEc5Gg+gD3MrNPSTBDmXp tYqdsrgPATbhHzGZVEusg3q/0lAKXYQKka3lNOvpp+61CxrNjUQ2inY3fIAdef2F+Jiw xGL5ETX6f9xH7L4lJkzSxL0cSp61nMp/svImVnMKjdNL9XCs61y3hKgcF0sWUQgcxnXf RfMw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=message-id:date:subject:cc:to:from:dkim-signature:delivered-to :sender:list-help:list-post:list-archive:list-subscribe :list-unsubscribe:list-id:precedence:mailing-list:dkim-signature :domainkey-signature; bh=5C/F3w6pVZpB4JrocHgMhWvJHCmPzaYUtAw753PSTpQ=; b=KCM+7o6+KqHLJhhSr6H+T1IzZ2NU3TV4fE1rD7jwv1DRZn/1S3JAEwFJK8e7hmWEvy 7BzofoA+6+e6jiBaMXOQo/vBpBYik2nIwJeAOlQYm4ka0XwoD17PwBPWRrmeZSPZrqua ElzFBiw+kmP7/O7BU0LCA8PM811KUwr6Xws+OqV7Saj/ZlyvLdTNr3rztOqOjA+vEg8P w8mSqzV7+laDOEuC40NuX7mgIOLCIOhB+iM2DQvFBcY6Mfu3nrHVd7pIffDTkLYsdpR0 ZIjn9/mNPmoNQ3cOMLabFIxFmL/en3IW/5FAQINQJTizSPRKlJLONYz/Ellh4BzmZrir UKTw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=M3KH3w3r; dkim=pass header.i=@linaro.org header.s=google header.b=qXbf1yPx; spf=pass (google.com: domain of libc-alpha-return-101446-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-101446-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id g77si2330862pfd.221.2019.04.16.14.27.33 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 16 Apr 2019 14:27:34 -0700 (PDT) Received-SPF: pass (google.com: domain of libc-alpha-return-101446-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=M3KH3w3r; dkim=pass header.i=@linaro.org header.s=google header.b=qXbf1yPx; spf=pass (google.com: domain of libc-alpha-return-101446-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-101446-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id; q=dns; s= default; b=a182I2Uzj/1CdqAkwibvHwsW2nGs0c9NZFQX35fcFWCvW0ImCH4KO EV5DNIUtgi8OoZqpOeOO1ezBW6Wt8AnvRNnzfHZNhSwlbOuFGkUdrRAz8+AlJPUe MAMnDTpI2jq6p2gPyRaGZLEPt8gBQtZyRvaYrrRn2+c1cW2NvjK/KI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id; s=default; bh=Q2OPfBTpb828qmGdUkmNPnq6IJM=; b=M3KH3w3rwVHoFXkS0UynyIKEND2o L2opmKybZY6/FSqX+L3dIx+p7SixxkxohR42t1BkJI19GV2F7rk0l3Z5TSm51sah lI32SJeSJhyGUyUBZKpS/m95m8pgMtpIFIJFK1WBX67d/xnHjgAc/pPFcQTykTNK 5sN75W6uMEPZWuQ= Received: (qmail 71778 invoked by alias); 16 Apr 2019 21:27:24 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 71767 invoked by uid 89); 16 Apr 2019 21:27:24 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.5 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy= X-HELO: mail-vs1-f65.google.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=5C/F3w6pVZpB4JrocHgMhWvJHCmPzaYUtAw753PSTpQ=; b=qXbf1yPxtxVGJtrCGWBpOOZNomjRijYHcP4BQxzbUc+UPFkLDzoq+Wwi1ka+NkgDCv /QJ176eU6qp04pWBpJHfLQe2oqiFeww+tGXAhbKMqBp7mjGBc19Zx5Q2IRUak4OSAYkb q2aBFzK0ZAc+lNgEX6wrKiEF+wuL0Xs8Zm/LoWyOESSHzqeDEidViwZEledKya25Ai6e vFpaPnJqBYQu3TkAsj1jh6K0IMvqLmoeHu3akWNdmiUsVi7mZi5zWD8wziKfHtgM8zct LBk49aNmP/C6KzTnbagixdMNq6GKdnl3GyXywPlJTuph4Am6GkvNXBmo5evKMTJC3rqV mjiQ== Return-Path: From: Adhemerval Zanella To: libc-alpha@sourceware.org Cc: Carlos O'Donell Subject: [PATCH 1/2] support: Add support_capture_subprogram Date: Tue, 16 Apr 2019 18:27:12 -0300 Message-Id: <20190416212713.24659-1-adhemerval.zanella@linaro.org> Its API is similar to support_capture_subprogram, 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. --- support/Makefile | 8 +- support/capture_subprocess.h | 6 + support/subprocess.h | 49 ++++++ support/support_capture_subprocess.c | 80 ++++----- support/support_subprocess.c | 152 ++++++++++++++++ support/tst-support_capture_subprocess.c | 175 ++++++++++++++++++- support/xposix_spawn.c | 32 ++++ support/xposix_spawn_file_actions_addclose.c | 29 +++ support/xposix_spawn_file_actions_adddup2.c | 30 ++++ support/xspawn.h | 34 ++++ 10 files changed, 544 insertions(+), 51 deletions(-) create mode 100644 support/subprocess.h create mode 100644 support/support_subprocess.c create mode 100644 support/xposix_spawn.c create mode 100644 support/xposix_spawn_file_actions_addclose.c create mode 100644 support/xposix_spawn_file_actions_adddup2.c create mode 100644 support/xspawn.h -- 2.17.1 Reviewed-by: Carlos O'Donell diff --git a/support/Makefile b/support/Makefile index f173565202..4daf3f46fb 100644 --- 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 \ @@ -151,6 +152,9 @@ libsupport-routines = \ xsignal \ xsigstack \ xsocket \ + xposix_spawn \ + xposix_spawn_file_actions_addclose \ + xposix_spawn_file_actions_adddup2 \ xstrdup \ xstrndup \ xsymlink \ @@ -210,7 +214,7 @@ tests = \ tst-test_compare_blob \ tst-test_compare_string \ tst-xreadlink \ - tst-xsigstack \ + tst-xsigstack ifeq ($(run-built-tests),yes) tests-special = \ @@ -226,4 +230,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 --git a/support/capture_subprocess.h b/support/capture_subprocess.h index 2dce42e3a3..2832cfc635 100644 --- 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 --git a/support/subprocess.h b/support/subprocess.h new file mode 100644 index 0000000000..002319cbad --- /dev/null +++ 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 + . */ + +#ifndef SUPPORT_SUBPROCESS_H +#define SUPPORT_SUBPROCESS_H + +#include + +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 --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c index 167514faf1..0d7a9baa85 100644 --- 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 . */ +#include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include static void transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream) @@ -50,59 +52,53 @@ transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream) } } -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); - xwaitpid (pid, &result.status, 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); + + support_capture_poll (&result, &proc); return result; } diff --git a/support/support_subprocess.c b/support/support_subprocess.c new file mode 100644 index 0000000000..f847fa5e89 --- /dev/null +++ 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 already running, terminate it. */ + if (!support_process_kill (proc->pid, SIGTERM, &status) ) + support_process_kill (proc->pid, SIGKILL, &status); + + return status; +} diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c index d8ba42ea8b..0f04dc541c 100644 --- a/support/tst-support_capture_subprocess.c +++ b/support/tst-support_capture_subprocess.c @@ -23,8 +23,20 @@ #include #include #include +#include #include #include +#include +#include +#include +#include +#include + +/* 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 fd) 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,51 @@ check_stream (const char *what, const struct xmemstream *stream, } } +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) +{ + 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; + char *args[11]; + + 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; + + 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 +271,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); @@ -199,4 +308,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 diff --git a/support/xposix_spawn.c b/support/xposix_spawn.c new file mode 100644 index 0000000000..e846017632 --- /dev/null +++ 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 + . */ + +#include +#include + +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 --git a/support/xposix_spawn_file_actions_addclose.c b/support/xposix_spawn_file_actions_addclose.c new file mode 100644 index 0000000000..eed54a6514 --- /dev/null +++ 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 + . */ + +#include +#include + +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 --git a/support/xposix_spawn_file_actions_adddup2.c b/support/xposix_spawn_file_actions_adddup2.c new file mode 100644 index 0000000000..a43b6490be --- /dev/null +++ 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 + . */ + +#include +#include + +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 --git a/support/xspawn.h b/support/xspawn.h new file mode 100644 index 0000000000..bbf89132e4 --- /dev/null +++ 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 + . */ + +#ifndef SUPPORT_XSPAWN_H +#define SUPPORT_XSPAWN_H + +#include + +__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