aboutsummaryrefslogtreecommitdiff
path: root/support/tst-support_capture_subprocess.c
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2019-04-12 17:39:53 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2019-04-17 11:35:59 -0300
commit0e169691290a6d2187a4ff41495fc5678cbfdcdc (patch)
tree22a279438012ed4e10b4477fe8a9d0a03a2630e6 /support/tst-support_capture_subprocess.c
parentbae8cf0e930d82133e96c4e2547548ed53938de1 (diff)
downloadglibc-0e169691290a6d2187a4ff41495fc5678cbfdcdc.tar
glibc-0e169691290a6d2187a4ff41495fc5678cbfdcdc.tar.gz
glibc-0e169691290a6d2187a4ff41495fc5678cbfdcdc.tar.bz2
glibc-0e169691290a6d2187a4ff41495fc5678cbfdcdc.zip
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>
Diffstat (limited to 'support/tst-support_capture_subprocess.c')
-rw-r--r--support/tst-support_capture_subprocess.c183
1 files changed, 175 insertions, 8 deletions
diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c
index d8ba42ea8b..ab363e41ac 100644
--- 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 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,59 @@ 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)
+{
+ /* 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);
@@ -199,4 +316,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>