diff options
| author | DJ Delorie <dj@redhat.com> | 2018-07-06 01:10:41 -0400 |
|---|---|---|
| committer | DJ Delorie <dj@redhat.com> | 2018-08-22 21:20:37 -0400 |
| commit | 561b0bec4448f0302cb4915bf67c919bde4a1c57 (patch) | |
| tree | a05c836bfe23e523ec7d357203e7b6599b287f98 /support | |
| parent | b35d3509caee04b2e196bb832138e4e4042347db (diff) | |
| download | glibc-561b0bec4448f0302cb4915bf67c919bde4a1c57.tar.xz glibc-561b0bec4448f0302cb4915bf67c919bde4a1c57.zip | |
Add test-in-container infrastructure.
* Makefile (testroot.pristine): New rules to initialize the
test-in-container "testroot".
* Makerules (all-testsuite): Add tests-container.
* Rules (tests-expected): Add tests-container.
(binaries-all-tests): Likewise.
(tests-container): New, run these tests in the testroot container.
* support/Makefile (others): Add *-container, support_paths.c,
xmkdirp, and links-dso-program.
* support/links-dso-program-c.c: New.
* support/links-dso-program.cc: New.
* support/test-container.c: New.
* support/shell-container.c: New.
* support/echo-container.c: New.
* support/true-container.c: New.
* support/xmkdirp.c: New.
* support/xsymlink.c: New.
* support/support_paths.c: New.
* support/support.h: Add support paths prototypes.
* support/xunistd.h: Add xmkdirp () and xsymlink ().
* nss/tst-nss-test3.c: Convert to test-in-container.
* nss/tst-nss-test3.root/: New.
Diffstat (limited to 'support')
| -rw-r--r-- | support/Makefile | 42 | ||||
| -rw-r--r-- | support/echo-container.c | 34 | ||||
| -rw-r--r-- | support/links-dso-program-c.c | 9 | ||||
| -rw-r--r-- | support/links-dso-program.cc | 11 | ||||
| -rw-r--r-- | support/shell-container.c | 395 | ||||
| -rw-r--r-- | support/support.h | 12 | ||||
| -rw-r--r-- | support/support_paths.c | 51 | ||||
| -rw-r--r-- | support/test-container.c | 988 | ||||
| -rw-r--r-- | support/true-container.c | 26 | ||||
| -rw-r--r-- | support/xmkdirp.c | 66 | ||||
| -rw-r--r-- | support/xsymlink.c | 29 | ||||
| -rw-r--r-- | support/xunistd.h | 4 |
12 files changed, 1667 insertions, 0 deletions
diff --git a/support/Makefile b/support/Makefile index 9063046c23..b5fcb6ed86 100644 --- a/support/Makefile +++ b/support/Makefile @@ -54,6 +54,7 @@ libsupport-routines = \ support_format_netent \ support_isolate_in_subprocess \ support_openpty \ + support_paths \ support_quote_blob \ support_record_failure \ support_run_diff \ @@ -85,6 +86,7 @@ libsupport-routines = \ xmalloc \ xmemstream \ xmkdir \ + xmkdirp \ xmmap \ xmprotect \ xmunmap \ @@ -140,6 +142,7 @@ libsupport-routines = \ xsocket \ xstrdup \ xstrndup \ + xsymlink \ xsysconf \ xunlink \ xwaitpid \ @@ -152,6 +155,45 @@ ifeq ($(build-shared),yes) libsupport-inhibit-o += .o endif +CFLAGS-support_paths.c = \ + -DSRCDIR_PATH=\"`cd .. ; pwd`\" \ + -DOBJDIR_PATH=\"`cd $(objpfx)/..; pwd`\" \ + -DINSTDIR_PATH=\"$(prefix)\" \ + -DLIBDIR_PATH=\"$(libdir)\" + +ifeq (,$(CXX)) +LINKS_DSO_PROGRAM = links-dso-program-c +else +LINKS_DSO_PROGRAM = links-dso-program +LDLIBS-links-dso-program = -lstdc++ -lgcc_s +endif + +others: \ + $(objpfx)test-container \ + $(objpfx)shell-container \ + $(objpfx)echo-container \ + $(objpfx)true-container \ + $(objpfx)$(LINKS_DSO_PROGRAM) + +ifeq ($(build-programs),yes) +endif + +LDLIBS-test-container = $(libsupport) + +others += test-container +others-noinstall += test-container + +others += shell-container echo-container true-container +others-noinstall += shell-container echo-container true-container + +others += $(LINKS_DSO_PROGRAM) +others-noinstall += $(LINKS_DSO_PROGRAM) + +$(objpfx)test-container : $(libsupport) +$(objpfx)shell-container : $(libsupport) +$(objpfx)echo-container : $(libsupport) +$(objpfx)true-container : $(libsupport) + tests = \ README-testing \ tst-support-namespace \ diff --git a/support/echo-container.c b/support/echo-container.c new file mode 100644 index 0000000000..e4d48df957 --- /dev/null +++ b/support/echo-container.c @@ -0,0 +1,34 @@ +/* Minimal /bin/echo for in-container use. + Copyright (C) 2018 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> + +int +main (int argc, const char **argv) +{ + int i; + + for (i = 1; i < argc; i++) + { + if (i > 1) + putchar (' '); + fputs (argv[i], stdout); + } + putchar ('\n'); + return 0; +} diff --git a/support/links-dso-program-c.c b/support/links-dso-program-c.c new file mode 100644 index 0000000000..d28a28a0d0 --- /dev/null +++ b/support/links-dso-program-c.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int +main (int argc, char **argv) +{ + /* Complexity to keep gcc from optimizing this away. */ + printf ("This is a test %s.\n", argc > 1 ? argv[1] : "null"); + return 0; +} diff --git a/support/links-dso-program.cc b/support/links-dso-program.cc new file mode 100644 index 0000000000..dba6976c06 --- /dev/null +++ b/support/links-dso-program.cc @@ -0,0 +1,11 @@ +#include <iostream> + +using namespace std; + +int +main (int argc, char **argv) +{ + /* Complexity to keep gcc from optimizing this away. */ + cout << (argc > 1 ? argv[1] : "null"); + return 0; +} diff --git a/support/shell-container.c b/support/shell-container.c new file mode 100644 index 0000000000..d303131daf --- /dev/null +++ b/support/shell-container.c @@ -0,0 +1,395 @@ +/* Minimal /bin/sh for in-container use. + Copyright (C) 2018 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/>. */ + +#define _FILE_OFFSET_BITS 64 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sched.h> +#include <sys/syscall.h> +#include <unistd.h> +#include <sys/types.h> +#include <dirent.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/fcntl.h> +#include <sys/file.h> +#include <sys/wait.h> +#include <stdarg.h> +#include <sys/sysmacros.h> +#include <ctype.h> +#include <utime.h> +#include <errno.h> +#include <error.h> + +#include <support/support.h> + +/* Design considerations + + General rule: optimize for developer time, not run time. + + Specifically: + + * Don't worry about slow algorithms + * Don't worry about free'ing memory + * Don't implement anything the testsuite doesn't need. + * Line and argument counts are limited, see below. + +*/ + +#define MAX_ARG_COUNT 100 +#define MAX_LINE_LENGTH 1000 + +/* Debugging is enabled via --debug, which must be the first argument. */ +static int debug_mode = 0; +#define dprintf if (debug_mode) fprintf + +/* Emulate the "/bin/true" command. Arguments are ignored. */ +static int +true_func (char **argv) +{ + return 0; +} + +/* Emulate the "/bin/echo" command. Options are ignored, arguments + are printed to stdout. */ +static int +echo_func (char **argv) +{ + int i; + + for (i = 0; argv[i]; i++) + { + if (i > 0) + putchar (' '); + fputs (argv[i], stdout); + } + putchar ('\n'); + + return 0; +} + +/* Emulate the "/bin/cp" command. Options are ignored. Only copies + one source file to one destination file. Directory destinations + are not supported. */ +static int +copy_func (char **argv) +{ + char *sname = argv[0]; + char *dname = argv[1]; + int sfd, dfd; + struct stat st; + + sfd = open (sname, O_RDONLY); + if (sfd < 0) + { + fprintf (stderr, "cp: unable to open %s for reading: %s\n", + sname, strerror (errno)); + return 1; + } + + if (fstat (sfd, &st) < 0) + { + fprintf (stderr, "cp: unable to fstat %s: %s\n", + sname, strerror (errno)); + return 1; + } + + dfd = open (dname, O_WRONLY | O_TRUNC | O_CREAT, 0600); + if (dfd < 0) + { + fprintf (stderr, "cp: unable to open %s for writing: %s\n", + dname, strerror (errno)); + return 1; + } + + if (copy_file_range (sfd, 0, dfd, 0, st.st_size, 0) != st.st_size) + { + fprintf (stderr, "cp: cannot copy file %s to %s: %s\n", + sname, dname, strerror (errno)); + return 1; + } + + close (sfd); + close (dfd); + + chmod (dname, st.st_mode & 0777); + + return 0; + +} + +/* This is a list of all the built-in commands we understand. */ +static struct { + const char *name; + int (*func) (char **argv); +} builtin_funcs[] = { + { "true", true_func }, + { "echo", echo_func }, + { "cp", copy_func }, + { NULL, NULL } +}; + +/* Run one tokenized command. argv[0] is the command. argv is + NULL-terminated. */ +static void +run_command_array (char **argv) +{ + int i, j; + pid_t pid; + int status; + int (*builtin_func) (char **args); + + if (argv[0] == NULL) + return; + + builtin_func = NULL; + + int new_stdin = 0; + int new_stdout = 1; + int new_stderr = 2; + + dprintf (stderr, "run_command_array starting\n"); + for (i = 0; argv[i]; i++) + dprintf (stderr, " argv [%d] `%s'\n", i, argv[i]); + + for (j = i = 0; argv[i]; i++) + { + if (strcmp (argv[i], "<") == 0 && argv[i + 1]) + { + new_stdin = open (argv[i + 1], O_WRONLY|O_CREAT|O_TRUNC, 0777); + ++i; + continue; + } + if (strcmp (argv[i], ">") == 0 && argv[i + 1]) + { + new_stdout = open (argv[i + 1], O_WRONLY|O_CREAT|O_TRUNC, 0777); + ++i; + continue; + } + if (strcmp (argv[i], ">>") == 0 && argv[i + 1]) + { + new_stdout = open (argv[i + 1], O_WRONLY|O_CREAT|O_APPEND, 0777); + ++i; + continue; + } + if (strcmp (argv[i], "2>") == 0 && argv[i + 1]) + { + new_stderr = open (argv[i + 1], O_WRONLY|O_CREAT|O_TRUNC, 0777); + ++i; + continue; + } + argv[j++] = argv[i]; + } + argv[j] = NULL; + + + for (i = 0; builtin_funcs[i].name != NULL; i++) + if (strcmp (argv[0], builtin_funcs[i].name) == 0) + builtin_func = builtin_funcs[i].func; + + dprintf (stderr, "builtin %p argv0 `%s'\n", builtin_func, argv[0]); + + pid = fork (); + if (pid < 0) + { + fprintf (stderr, "sh: fork failed\n"); + exit (1); + } + + if (pid == 0) + { + if (new_stdin != 0) + { + dup2 (new_stdin, 0); + close (new_stdin); + } + if (new_stdout != 1) + { + dup2 (new_stdout, 1); + close (new_stdout); + } + if (new_stderr != 2) + { + dup2 (new_stderr, 2); + close (new_stdout); + } + + if (builtin_func != NULL) + exit (builtin_func (argv + 1)); + + execvp (argv[0], argv); + + fprintf (stderr, "sh: execing %s failed: %s", + argv[0], strerror (errno)); + exit (1); + } + + waitpid (pid, &status, 0); + + dprintf (stderr, "exiting run_command_array\n"); + + if (WIFEXITED (status)) + { + int rv = WEXITSTATUS (status); + if (rv) + exit (rv); + } + else + exit (1); +} + +/* Run one command-as-a-string, by tokenizing it. Limited to + MAX_ARG_COUNT arguments. Simple substitution is done of $1 to $9 + (as whole separate tokens) from iargs[]. Quoted strings work if + the quotes wrap whole tokens; i.e. "foo bar" but not foo" bar". */ +static void +run_command_string (const char *cmdline, const char **iargs) +{ + char *args[MAX_ARG_COUNT+1]; + int ap = 0; + const char *start, *end; + int nargs; + + for (nargs = 0; iargs[nargs] != NULL; ++nargs) + ; + + dprintf (stderr, "run_command_string starting: '%s'\n", cmdline); + + while (ap < MAX_ARG_COUNT) + { + /* If the argument is quoted, this is the quote character, else NUL. */ + int in_quote = 0; + + /* Skip whitespace up to the next token. */ + while (*cmdline && isspace (*cmdline)) + cmdline ++; + if (*cmdline == 0) + break; + + start = cmdline; + /* Check for quoted argument. */ + in_quote = (*cmdline == '\'' || *cmdline == '"') ? *cmdline : 0; + + /* Skip to end of token; either by whitespace or matching quote. */ + dprintf (stderr, "in_quote %d\n", in_quote); + while (*cmdline + && (!isspace (*cmdline) || in_quote)) + { + if (*cmdline == in_quote + && cmdline != start) + in_quote = 0; + dprintf (stderr, "[%c]%d ", *cmdline, in_quote); + cmdline ++; + } + dprintf (stderr, "\n"); + + /* Allocate space for this token and store it in args[]. */ + end = cmdline; + dprintf (stderr, "start<%s> end<%s>\n", start, end); + args[ap] = (char *) xmalloc (end - start + 1); + memcpy (args[ap], start, end - start); + args[ap][end - start] = 0; + + /* Strip off quotes, if found. */ + dprintf (stderr, "args[%d] = <%s>\n", ap, args[ap]); + if (args[ap][0] == '\'' + && args[ap][strlen (args[ap])-1] == '\'') + { + args[ap][strlen (args[ap])-1] = 0; + args[ap] ++; + } + + else if (args[ap][0] == '"' + && args[ap][strlen (args[ap])-1] == '"') + { + args[ap][strlen (args[ap])-1] = 0; + args[ap] ++; + } + + /* Replace positional parameters like $4. */ + else if (args[ap][0] == '$' + && isdigit (args[ap][1]) + && args[ap][2] == 0) + { + int a = args[ap][1] - '1'; + if (0 <= a && a < nargs) + args[ap] = strdup (iargs[a]); + } + + ap ++; + + if (*cmdline == 0) + break; + } + + /* Lastly, NULL terminate the array and run it. */ + args[ap] = NULL; + run_command_array (args); +} + +/* Run a script by reading lines and passing them to the above + function. */ +static void +run_script (const char *filename, const char **args) +{ + char line[MAX_LINE_LENGTH + 1]; + dprintf (stderr, "run_script starting: '%s'\n", filename); + FILE *f = fopen (filename, "r"); + if (f == NULL) + { + fprintf (stderr, "sh: %s: %s\n", filename, strerror (errno)); + exit (1); + } + while (fgets (line, sizeof (line), f) != NULL) + { + if (line[0] == '#') + { + dprintf (stderr, "comment: %s\n", line); + continue; + } + run_command_string (line, args); + } + fclose (f); +} + +int +main (int argc, const char **argv) +{ + int i; + + if (strcmp (argv[1], "--debug") == 0) + { + debug_mode = 1; + --argc; + ++argv; + } + + dprintf (stderr, "container-sh starting:\n"); + for (i = 0; i < argc; i++) + dprintf (stderr, " argv[%d] is `%s'\n", i, argv[i]); + + if (strcmp (argv[1], "-c") == 0) + run_command_string (argv[2], argv+3); + else + run_script (argv[1], argv+2); + + dprintf (stderr, "normal exit 0\n"); + return 0; +} diff --git a/support/support.h b/support/support.h index 34ae6e10cd..c6ff4bafb4 100644 --- a/support/support.h +++ b/support/support.h @@ -25,6 +25,8 @@ #include <stddef.h> #include <sys/cdefs.h> +/* For mode_t. */ +#include <sys/stat.h> __BEGIN_DECLS @@ -82,6 +84,16 @@ char *xasprintf (const char *format, ...) char *xstrdup (const char *); char *xstrndup (const char *, size_t); +/* These point to the TOP of the source/build tree, not your (or + support's) subdirectory. */ +extern const char support_srcdir_root[]; +extern const char support_objdir_root[]; + +/* Corresponds to the --prefix= passed to configure. */ +extern const char support_install_prefix[]; +/* Corresponds to the install's lib/ or lib64/ directory. */ +extern const char support_libdir_prefix[]; + __END_DECLS #endif /* SUPPORT_H */ diff --git a/support/support_paths.c b/support/support_paths.c new file mode 100644 index 0000000000..a1c22315bd --- /dev/null +++ b/support/support_paths.c @@ -0,0 +1,51 @@ +/* Various paths that might be needed. + Copyright (C) 2018 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/support.h> +#include <support/check.h> + +/* The idea here is to make various makefile-level paths available to + support programs, as canonicalized absolute paths. */ + +/* These point to the TOP of the source/build tree, not your (or + support's) subdirectory. */ +#ifdef SRCDIR_PATH +const char support_srcdir_root[] = SRCDIR_PATH; +#else +# error please -DSRCDIR_PATH=something in the Makefile +#endif + +#ifdef OBJDIR_PATH +const char support_objdir_root[] = OBJDIR_PATH; +#else +# error please -DOBJDIR_PATH=something in the Makefile +#endif + +#ifdef INSTDIR_PATH +/* Corresponds to the --prefix= passed to configure. */ +const char support_install_prefix[] = INSTDIR_PATH; +#else +# error please -DINSTDIR_PATH=something in the Makefile +#endif + +#ifdef LIBDIR_PATH +/* Corresponds to the install's lib/ or lib64/ directory. */ +const char support_libdir_prefix[] = LIBDIR_PATH; +#else +# error please -DLIBDIR_PATH=something in the Makefile +#endif diff --git a/support/test-container.c b/support/test-container.c new file mode 100644 index 0000000000..ce16e061e7 --- /dev/null +++ b/support/test-container.c @@ -0,0 +1,988 @@ +/* Run a test case in an isolated namespace. + Copyright (C) 2018 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/>. */ + +#define _FILE_OFFSET_BITS 64 + +#include &l |
