diff options
author | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2019-04-12 17:39:53 -0300 |
---|---|---|
committer | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2019-04-17 11:35:59 -0300 |
commit | 0e169691290a6d2187a4ff41495fc5678cbfdcdc (patch) | |
tree | 22a279438012ed4e10b4477fe8a9d0a03a2630e6 /support/tst-support_capture_subprocess.c | |
parent | bae8cf0e930d82133e96c4e2547548ed53938de1 (diff) | |
download | glibc-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.c | 183 |
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> |