diff --git a/SOURCES/glibc-rh1418978-1.patch b/SOURCES/glibc-rh1418978-1.patch index c57c6528..466a62e6 100644 --- a/SOURCES/glibc-rh1418978-1.patch +++ b/SOURCES/glibc-rh1418978-1.patch @@ -1,19 +1,25 @@ This patch creates the contents of the support/ directory up to this upstream commit on the master branch: -commit 401311cfba71b61d93d23aa17e5c9ac5fb047d48 -Author: Florian Weimer -Date: Mon Jan 8 14:33:17 2018 +0100 +commit 00c86a37d1b63044e3169d1f2ebec23447c73f79 +Author: Adhemerval Zanella +Date: Wed Nov 7 11:09:02 2018 -0200 - resolv: Support binary labels in test framework + support: Fix printf format for TEST_COMPARE_STRING - The old implementation based on hsearch_r used an ad-hoc C string - encoding and produced an incorrect format on the wire for domain - names which contained bytes which needed escaping when printed. + Fix the following on 32 bits targets: - This commit switches to ns_name_pton for the wire format conversion - (now that we have separate tests for it) and uses a tsearch tree - with a suitable comparison function to locate compression targets. + support_test_compare_string.c: In function ‘support_test_compare_string’: + support_test_compare_string.c:80:37: error: format ‘%lu’ expects argument of + type ‘long unsigned int’, but argument 2 has type ‘size_t’ {aka ‘unsigned int’} + [-Werror=format=] + printf (" string length: %lu bytes\n", left_length); + ~~^ ~~~~~~~~~~~ + %u + Checked on arm-linux-gnueabihf. + + * support/support_test_compare_string.c + (support_test_compare_string): Fix printf format. diff --git a/scripts/backport-support.sh b/scripts/backport-support.sh new file mode 100644 @@ -133,10 +139,10 @@ index 0000000000..4057e42d3c +command_$command diff --git a/support/Makefile b/support/Makefile new file mode 100644 -index 0000000000..1bda81e55e +index 0000000000..2b663fbbfa --- /dev/null +++ b/support/Makefile -@@ -0,0 +1,171 @@ +@@ -0,0 +1,219 @@ +# Makefile for support library, used only at build and test time +# Copyright (C) 2016-2018 Free Software Foundation, Inc. +# This file is part of the GNU C Library. @@ -164,6 +170,7 @@ index 0000000000..1bda81e55e +extra-libs-noinstall := $(extra-libs) + +libsupport-routines = \ ++ blob_repeat \ + check \ + check_addrinfo \ + check_dns_packet \ @@ -182,6 +189,8 @@ index 0000000000..1bda81e55e + support_capture_subprocess \ + support_capture_subprocess_check \ + support_chroot \ ++ support_copy_file_range \ ++ support_descriptor_supports_holes \ + support_enter_mount_namespace \ + support_enter_network_namespace \ + support_format_address_family \ @@ -191,10 +200,15 @@ index 0000000000..1bda81e55e + support_format_hostent \ + support_format_netent \ + support_isolate_in_subprocess \ ++ support_openpty \ ++ support_paths \ ++ support_quote_blob \ + support_record_failure \ + support_run_diff \ + support_shared_allocate \ ++ support_test_compare_blob \ + support_test_compare_failure \ ++ support_test_compare_string \ + support_write_file_string \ + support_test_main \ + support_test_verify_impl \ @@ -208,6 +222,7 @@ index 0000000000..1bda81e55e + xchroot \ + xclose \ + xconnect \ ++ xcopy_file_range \ + xdlfcn \ + xdup2 \ + xfclose \ @@ -220,6 +235,7 @@ index 0000000000..1bda81e55e + xmalloc \ + xmemstream \ + xmkdir \ ++ xmkdirp \ + xmmap \ + xmprotect \ + xmunmap \ @@ -234,6 +250,9 @@ index 0000000000..1bda81e55e + xpthread_barrier_destroy \ + xpthread_barrier_init \ + xpthread_barrier_wait \ ++ xpthread_barrierattr_destroy \ ++ xpthread_barrierattr_init \ ++ xpthread_barrierattr_setpshared \ + xpthread_cancel \ + xpthread_check_return \ + xpthread_cond_wait \ @@ -272,6 +291,7 @@ index 0000000000..1bda81e55e + xsocket \ + xstrdup \ + xstrndup \ ++ xsymlink \ + xsysconf \ + xunlink \ + xwaitpid \ @@ -284,13 +304,47 @@ index 0000000000..1bda81e55e +libsupport-inhibit-o += .o +endif + ++CFLAGS-support_paths.c = \ ++ -DSRCDIR_PATH=\"`cd .. ; pwd`\" \ ++ -DOBJDIR_PATH=\"`cd $(objpfx)/..; pwd`\" \ ++ -DOBJDIR_ELF_LDSO_PATH=\"`cd $(objpfx)/..; pwd`/elf/$(rtld-installed-name)\" \ ++ -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 -lgcc_s $(libunwind) ++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 \ ++ tst-support_blob_repeat \ + tst-support_capture_subprocess \ + tst-support_format_dns_packet \ ++ tst-support_quote_blob \ + tst-support_record_failure \ + tst-test_compare \ ++ tst-test_compare_blob \ ++ tst-test_compare_string \ + tst-xreadlink \ + +ifeq ($(run-built-tests),yes) @@ -368,6 +422,344 @@ index 0000000000..9d289c3020 +/* This file references do_test above and contains the definition of + the main function. */ +#include +diff --git a/support/blob_repeat.c b/support/blob_repeat.c +new file mode 100644 +index 0000000000..16c1e448b9 +--- /dev/null ++++ b/support/blob_repeat.c +@@ -0,0 +1,282 @@ ++/* Repeating a memory blob, with alias mapping optimization. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Small allocations should use malloc directly instead of the mmap ++ optimization because mappings carry a lot of overhead. */ ++static const size_t maximum_small_size = 4 * 1024 * 1024; ++ ++/* Internal helper for fill. */ ++static void ++fill0 (char *target, const char *element, size_t element_size, ++ size_t count) ++{ ++ while (count > 0) ++ { ++ memcpy (target, element, element_size); ++ target += element_size; ++ --count; ++ } ++} ++ ++/* Fill the buffer at TARGET with COUNT copies of the ELEMENT_SIZE ++ bytes starting at ELEMENT. */ ++static void ++fill (char *target, const char *element, size_t element_size, ++ size_t count) ++{ ++ if (element_size == 0 || count == 0) ++ return; ++ else if (element_size == 1) ++ memset (target, element[0], count); ++ else if (element_size == sizeof (wchar_t)) ++ { ++ wchar_t wc; ++ memcpy (&wc, element, sizeof (wc)); ++ wmemset ((wchar_t *) target, wc, count); ++ } ++ else if (element_size < 1024 && count > 4096) ++ { ++ /* Use larger copies for really small element sizes. */ ++ char buffer[8192]; ++ size_t buffer_count = sizeof (buffer) / element_size; ++ fill0 (buffer, element, element_size, buffer_count); ++ while (count > 0) ++ { ++ size_t copy_count = buffer_count; ++ if (copy_count > count) ++ copy_count = count; ++ size_t copy_bytes = copy_count * element_size; ++ memcpy (target, buffer, copy_bytes); ++ target += copy_bytes; ++ count -= copy_count; ++ } ++ } ++ else ++ fill0 (target, element, element_size, count); ++} ++ ++/* Use malloc instead of mmap for small allocations and unusual size ++ combinations. */ ++static struct support_blob_repeat ++allocate_malloc (size_t total_size, const void *element, size_t element_size, ++ size_t count) ++{ ++ void *buffer = malloc (total_size); ++ if (buffer == NULL) ++ return (struct support_blob_repeat) { 0 }; ++ fill (buffer, element, element_size, count); ++ return (struct support_blob_repeat) ++ { ++ .start = buffer, ++ .size = total_size, ++ .use_malloc = true ++ }; ++} ++ ++/* Return the least common multiple of PAGE_SIZE and ELEMENT_SIZE, ++ avoiding overflow. This assumes that PAGE_SIZE is a power of ++ two. */ ++static size_t ++minimum_stride_size (size_t page_size, size_t element_size) ++{ ++ TEST_VERIFY_EXIT (page_size > 0); ++ TEST_VERIFY_EXIT (element_size > 0); ++ ++ /* Compute the number of trailing zeros common to both sizes. */ ++ unsigned int common_zeros = __builtin_ctzll (page_size | element_size); ++ ++ /* In the product, this power of two appears twice, but in the least ++ common multiple, it appears only once. Therefore, shift one ++ factor. */ ++ size_t multiple; ++ if (__builtin_mul_overflow (page_size >> common_zeros, element_size, ++ &multiple)) ++ return 0; ++ return multiple; ++} ++ ++/* Allocations larger than maximum_small_size potentially use mmap ++ with alias mappings. */ ++static struct support_blob_repeat ++allocate_big (size_t total_size, const void *element, size_t element_size, ++ size_t count) ++{ ++ unsigned long page_size = xsysconf (_SC_PAGESIZE); ++ size_t stride_size = minimum_stride_size (page_size, element_size); ++ if (stride_size == 0) ++ { ++ errno = EOVERFLOW; ++ return (struct support_blob_repeat) { 0 }; ++ } ++ ++ /* Ensure that the stride size is at least maximum_small_size. This ++ is necessary to reduce the number of distinct mappings. */ ++ if (stride_size < maximum_small_size) ++ stride_size ++ = ((maximum_small_size + stride_size - 1) / stride_size) * stride_size; ++ ++ if (stride_size > total_size) ++ /* The mmap optimization would not save anything. */ ++ return allocate_malloc (total_size, element, element_size, count); ++ ++ /* Reserve the memory region. If we cannot create the mapping, ++ there is no reason to set up the backing file. */ ++ void *target = mmap (NULL, total_size, PROT_NONE, ++ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); ++ if (target == MAP_FAILED) ++ return (struct support_blob_repeat) { 0 }; ++ ++ /* Create the backing file for the repeated mapping. Call mkstemp ++ directly to remove the resources backing the temporary file ++ immediately, once support_blob_repeat_free is called. Using ++ create_temp_file would result in a warning during post-test ++ cleanup. */ ++ int fd; ++ { ++ char *temppath = xasprintf ("%s/support_blob_repeat-XXXXXX", test_dir); ++ fd = mkstemp (temppath); ++ if (fd < 0) ++ FAIL_EXIT1 ("mkstemp (\"%s\"): %m", temppath); ++ xunlink (temppath); ++ free (temppath); ++ } ++ ++ /* Make sure that there is backing storage, so that the fill ++ operation will not fault. */ ++ if (posix_fallocate (fd, 0, stride_size) != 0) ++ FAIL_EXIT1 ("posix_fallocate (%zu): %m", stride_size); ++ ++ /* The stride size must still be a multiple of the page size and ++ element size. */ ++ TEST_VERIFY_EXIT ((stride_size % page_size) == 0); ++ TEST_VERIFY_EXIT ((stride_size % element_size) == 0); ++ ++ /* Fill the backing store. */ ++ { ++ void *ptr = mmap (target, stride_size, PROT_READ | PROT_WRITE, ++ MAP_FIXED | MAP_FILE | MAP_SHARED, fd, 0); ++ if (ptr == MAP_FAILED) ++ { ++ int saved_errno = errno; ++ xmunmap (target, total_size); ++ xclose (fd); ++ errno = saved_errno; ++ return (struct support_blob_repeat) { 0 }; ++ } ++ if (ptr != target) ++ FAIL_EXIT1 ("mapping of %zu bytes moved from %p to %p", ++ stride_size, target, ptr); ++ ++ /* Write the repeating data. */ ++ fill (target, element, element_size, stride_size / element_size); ++ ++ /* Return to a PROT_NONE mapping, just to be on the safe side. */ ++ ptr = mmap (target, stride_size, PROT_NONE, ++ MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); ++ if (ptr == MAP_FAILED) ++ FAIL_EXIT1 ("Failed to reinstate PROT_NONE mapping: %m"); ++ if (ptr != target) ++ FAIL_EXIT1 ("PROT_NONE mapping of %zu bytes moved from %p to %p", ++ stride_size, target, ptr); ++ } ++ ++ /* Create the alias mappings. */ ++ { ++ size_t remaining_size = total_size; ++ char *current = target; ++ int flags = MAP_FIXED | MAP_FILE | MAP_PRIVATE; ++#ifdef MAP_NORESERVE ++ flags |= MAP_NORESERVE; ++#endif ++ while (remaining_size > 0) ++ { ++ size_t to_map = stride_size; ++ if (to_map > remaining_size) ++ to_map = remaining_size; ++ void *ptr = mmap (current, to_map, PROT_READ | PROT_WRITE, ++ flags, fd, 0); ++ if (ptr == MAP_FAILED) ++ { ++ int saved_errno = errno; ++ xmunmap (target, total_size); ++ xclose (fd); ++ errno = saved_errno; ++ return (struct support_blob_repeat) { 0 }; ++ } ++ if (ptr != current) ++ FAIL_EXIT1 ("MAP_PRIVATE mapping of %zu bytes moved from %p to %p", ++ to_map, target, ptr); ++ remaining_size -= to_map; ++ current += to_map; ++ } ++ } ++ ++ xclose (fd); ++ ++ return (struct support_blob_repeat) ++ { ++ .start = target, ++ .size = total_size, ++ .use_malloc = false ++ }; ++} ++ ++struct support_blob_repeat ++support_blob_repeat_allocate (const void *element, size_t element_size, ++ size_t count) ++{ ++ size_t total_size; ++ if (__builtin_mul_overflow (element_size, count, &total_size)) ++ { ++ errno = EOVERFLOW; ++ return (struct support_blob_repeat) { 0 }; ++ } ++ if (total_size <= maximum_small_size) ++ return allocate_malloc (total_size, element, element_size, count); ++ else ++ return allocate_big (total_size, element, element_size, count); ++} ++ ++void ++support_blob_repeat_free (struct support_blob_repeat *blob) ++{ ++ if (blob->size > 0) ++ { ++ int saved_errno = errno; ++ if (blob->use_malloc) ++ free (blob->start); ++ else ++ xmunmap (blob->start, blob->size); ++ errno = saved_errno; ++ } ++ *blob = (struct support_blob_repeat) { 0 }; ++} +diff --git a/support/blob_repeat.h b/support/blob_repeat.h +new file mode 100644 +index 0000000000..8e9d7ff5f1 +--- /dev/null ++++ b/support/blob_repeat.h +@@ -0,0 +1,44 @@ ++/* Repeating a memory blob, with alias mapping optimization. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_BLOB_REPEAT_H ++#define SUPPORT_BLOB_REPEAT_H ++ ++#include ++#include ++ ++struct support_blob_repeat ++{ ++ void *start; ++ size_t size; ++ bool use_malloc; ++}; ++ ++/* Return an allocation of COUNT elements, each of ELEMENT_SIZE bytes, ++ initialized with the bytes starting at ELEMENT. The memory is ++ writable (and thus counts towards the commit charge). In case of ++ on error, all members of the return struct are zero-initialized, ++ and errno is set accordingly. */ ++struct support_blob_repeat support_blob_repeat_allocate (const void *element, ++ size_t element_size, ++ size_t count); ++ ++/* Deallocate the blob created by support_blob_repeat_allocate. */ ++void support_blob_repeat_free (struct support_blob_repeat *); ++ ++#endif /* SUPPORT_BLOB_REPEAT_H */ diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h new file mode 100644 index 0000000000..b0886ba1d1 @@ -437,10 +829,10 @@ index 0000000000..b0886ba1d1 +#endif /* SUPPORT_CAPTURE_SUBPROCESS_H */ diff --git a/support/check.c b/support/check.c new file mode 100644 -index 0000000000..688ed569ac +index 0000000000..78f2b3cde1 --- /dev/null +++ b/support/check.c -@@ -0,0 +1,57 @@ +@@ -0,0 +1,60 @@ +/* Support code for reporting test results. + Copyright (C) 2016-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. @@ -461,6 +853,7 @@ index 0000000000..688ed569ac + +#include + ++#include +#include +#include +#include @@ -469,9 +862,11 @@ index 0000000000..688ed569ac +static void +print_failure (const char *file, int line, const char *format, va_list ap) +{ ++ int saved_errno = errno; + printf ("error: %s:%d: ", file, line); + vprintf (format, ap); + puts (""); ++ errno = saved_errno; +} + +int @@ -500,10 +895,10 @@ index 0000000000..688ed569ac +} diff --git a/support/check.h b/support/check.h new file mode 100644 -index 0000000000..2192f38941 +index 0000000000..e6765289f2 --- /dev/null +++ b/support/check.h -@@ -0,0 +1,153 @@ +@@ -0,0 +1,188 @@ +/* Functionality for reporting test results. + Copyright (C) 2016-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. @@ -570,6 +965,8 @@ index 0000000000..2192f38941 + (1, __FILE__, __LINE__, #expr); \ + }) + ++ ++ +int support_print_failure_impl (const char *file, int line, + const char *format, ...) + __attribute__ ((nonnull (1), format (printf, 3, 4))); @@ -647,6 +1044,39 @@ index 0000000000..2192f38941 + int right_size); + + ++/* Compare [LEFT, LEFT + LEFT_LENGTH) with [RIGHT, RIGHT + ++ RIGHT_LENGTH) and report a test failure if the arrays are ++ different. LEFT_LENGTH and RIGHT_LENGTH are measured in bytes. If ++ the length is null, the corresponding pointer is ignored (i.e., it ++ can be NULL). The blobs should be reasonably short because on ++ mismatch, both are printed. */ ++#define TEST_COMPARE_BLOB(left, left_length, right, right_length) \ ++ (support_test_compare_blob (left, left_length, right, right_length, \ ++ __FILE__, __LINE__, \ ++ #left, #left_length, #right, #right_length)) ++ ++void support_test_compare_blob (const void *left, ++ unsigned long int left_length, ++ const void *right, ++ unsigned long int right_length, ++ const char *file, int line, ++ const char *left_exp, const char *left_len_exp, ++ const char *right_exp, ++ const char *right_len_exp); ++ ++/* Compare the strings LEFT and RIGHT and report a test failure if ++ they are different. Also report failure if one of the arguments is ++ a null pointer and the other is not. The strings should be ++ reasonably short because on mismatch, both are printed. */ ++#define TEST_COMPARE_STRING(left, right) \ ++ (support_test_compare_string (left, right, __FILE__, __LINE__, \ ++ #left, #right)) ++ ++void support_test_compare_string (const char *left, const char *right, ++ const char *file, int line, ++ const char *left_expr, ++ const char *right_expr); ++ +/* Internal function called by the test driver. */ +int support_report_failure (int status) + __attribute__ ((weak, warn_unused_result)); @@ -962,6 +1392,46 @@ index 0000000000..2780d9a6fe + /* Restore the original signal mask. */ + xpthread_sigmask (SIG_SETMASK, &old_set, NULL); +} +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 ++ . */ ++ ++#include ++ ++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/format_nss.h b/support/format_nss.h new file mode 100644 index 0000000000..e55354e788 @@ -1053,6 +1523,38 @@ index 0000000000..450333ad38 + } + setenv ("LIBC_FATAL_STDERR_", "1", 1); +} +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 ++ ++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 ++ ++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/namespace.h b/support/namespace.h new file mode 100644 index 0000000000..3c3842a49b @@ -2855,14 +3357,14 @@ index 0000000000..c2dacbb179 + sigaction (SIGABRT, &sa, NULL); + ignore_stderr (); +} -diff --git a/support/support-xfstat.c b/support/support-xfstat.c +diff --git a/support/shell-container.c b/support/shell-container.c new file mode 100644 -index 0000000000..f69253af09 +index 0000000000..9bd90d3f60 --- /dev/null -+++ b/support/support-xfstat.c -@@ -0,0 +1,28 @@ -+/* fstat64 with error checking. -+ Copyright (C) 2017-2018 Free Software Foundation, Inc. ++++ 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 @@ -2879,58 +3381,459 @@ index 0000000000..f69253af09 + License along with the GNU C Library; if not, see + . */ + -+#include -+#include ++#define _FILE_OFFSET_BITS 64 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include +#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+void -+xfstat (int fd, struct stat64 *result) -+{ -+ if (fstat64 (fd, result) != 0) -+ FAIL_EXIT1 ("fstat64 (%d): %m", fd); -+} -diff --git a/support/support-xstat.c b/support/support-xstat.c -new file mode 100644 -index 0000000000..fc10c6dcb7 ---- /dev/null -+++ b/support/support-xstat.c -@@ -0,0 +1,30 @@ -+/* stat64 with error checking. -+ Copyright (C) 2017-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. ++#include + -+ 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. ++/* Design considerations + -+ 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. ++ General rule: optimize for developer time, not run time. + -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ ++ Specifically: + -+/* NB: Non-standard file name to avoid sysdeps override for xstat. */ ++ * 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. + -+#include -+#include -+#include ++*/ + -+void -+xstat (const char *path, struct stat64 *result) ++#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) +{ -+ if (stat64 (path, result) != 0) -+ FAIL_EXIT1 ("stat64 (\"%s\"): %m", path); ++ 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 (support_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-xfstat.c b/support/support-xfstat.c +new file mode 100644 +index 0000000000..f69253af09 +--- /dev/null ++++ b/support/support-xfstat.c +@@ -0,0 +1,28 @@ ++/* fstat64 with error checking. ++ Copyright (C) 2017-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 ++ . */ ++ ++#include ++#include ++#include ++ ++void ++xfstat (int fd, struct stat64 *result) ++{ ++ if (fstat64 (fd, result) != 0) ++ FAIL_EXIT1 ("fstat64 (%d): %m", fd); ++} +diff --git a/support/support-xstat.c b/support/support-xstat.c +new file mode 100644 +index 0000000000..fc10c6dcb7 +--- /dev/null ++++ b/support/support-xstat.c +@@ -0,0 +1,30 @@ ++/* stat64 with error checking. ++ Copyright (C) 2017-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 ++ . */ ++ ++/* NB: Non-standard file name to avoid sysdeps override for xstat. */ ++ ++#include ++#include ++#include ++ ++void ++xstat (const char *path, struct stat64 *result) ++{ ++ if (stat64 (path, result) != 0) ++ FAIL_EXIT1 ("stat64 (\"%s\"): %m", path); +} diff --git a/support/support.h b/support/support.h new file mode 100644 -index 0000000000..bc5827ed87 +index 0000000000..9418cd11ef --- /dev/null +++ b/support/support.h -@@ -0,0 +1,75 @@ +@@ -0,0 +1,108 @@ +/* Common extra functions. + Copyright (C) 2016-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. @@ -2958,6 +3861,10 @@ index 0000000000..bc5827ed87 + +#include +#include ++/* For mode_t. */ ++#include ++/* For ssize_t and off64_t. */ ++#include + +__BEGIN_DECLS + @@ -2992,6 +3899,18 @@ index 0000000000..bc5827ed87 + process on error. */ +void support_write_file_string (const char *path, const char *contents); + ++/* Quote the contents of the byte array starting at BLOB, of LENGTH ++ bytes, in such a way that the result string can be included in a C ++ literal (in single/double quotes, without putting the quotes into ++ the result). */ ++char *support_quote_blob (const void *blob, size_t length); ++ ++/* Returns non-zero if the file descriptor is a regular file on a file ++ system which supports holes (that is, seeking and writing does not ++ allocate storage for the range of zeros). FD must refer to a ++ regular file open for writing, and initially empty. */ ++int support_descriptor_supports_holes (int fd); ++ +/* Error-checking wrapper functions which terminate the process on + error. */ + @@ -3003,6 +3922,23 @@ index 0000000000..bc5827ed87 +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 path to the runtime linker used by the testsuite, ++ e.g. OBJDIR_PATH/elf/ld-linux-x86-64.so.2 */ ++extern const char support_objdir_elf_ldso[]; ++ ++/* 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[]; ++ ++extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *, ++ size_t, unsigned int); ++ +__END_DECLS + +#endif /* SUPPORT_H */ @@ -3459,14 +4395,14 @@ index 0000000000..6356b1af6c + free (chroot->path_host_conf); + free (chroot); +} -diff --git a/support/support_enter_mount_namespace.c b/support/support_enter_mount_namespace.c +diff --git a/support/support_copy_file_range.c b/support/support_copy_file_range.c new file mode 100644 -index 0000000000..ba68e990f2 +index 0000000000..9a1e39773e --- /dev/null -+++ b/support/support_enter_mount_namespace.c -@@ -0,0 +1,47 @@ -+/* Enter a mount namespace. -+ Copyright (C) 2017-2018 Free Software Foundation, Inc. ++++ b/support/support_copy_file_range.c +@@ -0,0 +1,143 @@ ++/* Simplified copy_file_range with cross-device copy. ++ 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 @@ -3483,39 +4419,281 @@ index 0000000000..ba68e990f2 + License along with the GNU C Library; if not, see + . */ + -+#include -+ -+#include -+#include -+#ifdef CLONE_NEWNS -+# include -+#endif /* CLONE_NEWNS */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+bool -+support_enter_mount_namespace (void) ++ssize_t ++support_copy_file_range (int infd, __off64_t *pinoff, ++ int outfd, __off64_t *poutoff, ++ size_t length, unsigned int flags) +{ -+#ifdef CLONE_NEWNS -+ if (unshare (CLONE_NEWNS) == 0) ++ if (flags != 0) + { -+ /* On some systems, / is marked as MS_SHARED, which means that -+ mounts within the namespace leak to the rest of the system, -+ which is not what we want. */ -+ if (mount ("none", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0) -+ { -+ printf ("warning: making the mount namespace private failed: %m\n"); -+ return false; -+ } -+ return true; ++ errno = EINVAL; ++ return -1; + } -+ else -+ printf ("warning: unshare (CLONE_NEWNS) failed: %m\n"); -+#endif /* CLONE_NEWNS */ -+ return false; -+} -diff --git a/support/support_enter_network_namespace.c b/support/support_enter_network_namespace.c -new file mode 100644 -index 0000000000..1d874df885 ---- /dev/null ++ ++ struct stat64 instat; ++ struct stat64 outstat; ++ if (fstat64 (infd, &instat) != 0 || fstat64 (outfd, &outstat) != 0) ++ return -1; ++ if (S_ISDIR (instat.st_mode) || S_ISDIR (outstat.st_mode)) ++ { ++ errno = EISDIR; ++ return -1; ++ } ++ if (!S_ISREG (instat.st_mode) || !S_ISREG (outstat.st_mode)) ++ { ++ /* We need a regular input file so that the we can seek ++ backwards in case of a write failure. */ ++ errno = EINVAL; ++ return -1; ++ } ++ ++ /* The output descriptor must not have O_APPEND set. */ ++ if (fcntl (outfd, F_GETFL) & O_APPEND) ++ { ++ errno = EBADF; ++ return -1; ++ } ++ ++ /* Avoid an overflow in the result. */ ++ if (length > SSIZE_MAX) ++ length = SSIZE_MAX; ++ ++ /* Main copying loop. The buffer size is arbitrary and is a ++ trade-off between stack size consumption, cache usage, and ++ amortization of system call overhead. */ ++ size_t copied = 0; ++ char buf[8192]; ++ while (length > 0) ++ { ++ size_t to_read = length; ++ if (to_read > sizeof (buf)) ++ to_read = sizeof (buf); ++ ++ /* Fill the buffer. */ ++ ssize_t read_count; ++ if (pinoff == NULL) ++ read_count = read (infd, buf, to_read); ++ else ++ read_count = pread64 (infd, buf, to_read, *pinoff); ++ if (read_count == 0) ++ /* End of file reached prematurely. */ ++ return copied; ++ if (read_count < 0) ++ { ++ if (copied > 0) ++ /* Report the number of bytes copied so far. */ ++ return copied; ++ return -1; ++ } ++ if (pinoff != NULL) ++ *pinoff += read_count; ++ ++ /* Write the buffer part which was read to the destination. */ ++ char *end = buf + read_count; ++ for (char *p = buf; p < end; ) ++ { ++ ssize_t write_count; ++ if (poutoff == NULL) ++ write_count = write (outfd, p, end - p); ++ else ++ write_count = pwrite64 (outfd, p, end - p, *poutoff); ++ if (write_count < 0) ++ { ++ /* Adjust the input read position to match what we have ++ written, so that the caller can pick up after the ++ error. */ ++ size_t written = p - buf; ++ /* NB: This needs to be signed so that we can form the ++ negative value below. */ ++ ssize_t overread = read_count - written; ++ if (pinoff == NULL) ++ { ++ if (overread > 0) ++ { ++ /* We are on an error recovery path, so we ++ cannot deal with failure here. */ ++ int save_errno = errno; ++ (void) lseek64 (infd, -overread, SEEK_CUR); ++ errno = save_errno; ++ } ++ } ++ else /* pinoff != NULL */ ++ *pinoff -= overread; ++ ++ if (copied + written > 0) ++ /* Report the number of bytes copied so far. */ ++ return copied + written; ++ return -1; ++ } ++ p += write_count; ++ if (poutoff != NULL) ++ *poutoff += write_count; ++ } /* Write loop. */ ++ ++ copied += read_count; ++ length -= read_count; ++ } ++ return copied; ++} +diff --git a/support/support_descriptor_supports_holes.c b/support/support_descriptor_supports_holes.c +new file mode 100644 +index 0000000000..c7099ca67c +--- /dev/null ++++ b/support/support_descriptor_supports_holes.c +@@ -0,0 +1,87 @@ ++/* Test for file system hole support. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++int ++support_descriptor_supports_holes (int fd) ++{ ++ enum ++ { ++ /* Write offset for the enlarged file. This value is arbitrary ++ and hopefully large enough to trigger the creation of holes. ++ We cannot use the file system block size as a reference here ++ because it is incorrect for network file systems. */ ++ write_offset = 16 * 1024 * 1024, ++ ++ /* Our write may add this number of additional blocks (see ++ block_limit below). */ ++ block_headroom = 8, ++ }; ++ ++ struct stat64 st; ++ xfstat (fd, &st); ++ if (!S_ISREG (st.st_mode)) ++ FAIL_EXIT1 ("descriptor %d does not refer to a regular file", fd); ++ if (st.st_size != 0) ++ FAIL_EXIT1 ("descriptor %d does not refer to an empty file", fd); ++ if (st.st_blocks > block_headroom) ++ FAIL_EXIT1 ("descriptor %d refers to a pre-allocated file (%lld blocks)", ++ fd, (long long int) st.st_blocks); ++ ++ /* Write a single byte at the start of the file to compute the block ++ usage for a single byte. */ ++ xlseek (fd, 0, SEEK_SET); ++ char b = '@'; ++ xwrite (fd, &b, 1); ++ /* Attempt to bypass delayed allocation. */ ++ TEST_COMPARE (fsync (fd), 0); ++ xfstat (fd, &st); ++ ++ /* This limit is arbitrary. The file system needs to store ++ somewhere that data exists at the write offset, and this may ++ moderately increase the number of blocks used by the file, in ++ proportion to the initial block count, but not in proportion to ++ the write offset. */ ++ unsigned long long int block_limit = 2 * st.st_blocks + block_headroom; ++ ++ /* Write a single byte at 16 megabytes. */ ++ xlseek (fd, write_offset, SEEK_SET); ++ xwrite (fd, &b, 1); ++ /* Attempt to bypass delayed allocation. */ ++ TEST_COMPARE (fsync (fd), 0); ++ xfstat (fd, &st); ++ bool supports_holes = st.st_blocks <= block_limit; ++ ++ /* Also check that extending the file does not fill up holes. */ ++ xftruncate (fd, 2 * write_offset); ++ /* Attempt to bypass delayed allocation. */ ++ TEST_COMPARE (fsync (fd), 0); ++ xfstat (fd, &st); ++ supports_holes = supports_holes && st.st_blocks <= block_limit; ++ ++ /* Return to a zero-length file. */ ++ xftruncate (fd, 0); ++ xlseek (fd, 0, SEEK_SET); ++ ++ return supports_holes; ++} +diff --git a/support/support_enter_mount_namespace.c b/support/support_enter_mount_namespace.c +new file mode 100644 +index 0000000000..ba68e990f2 +--- /dev/null ++++ b/support/support_enter_mount_namespace.c +@@ -0,0 +1,47 @@ ++/* Enter a mount namespace. ++ Copyright (C) 2017-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 ++ . */ ++ ++#include ++ ++#include ++#include ++#ifdef CLONE_NEWNS ++# include ++#endif /* CLONE_NEWNS */ ++ ++bool ++support_enter_mount_namespace (void) ++{ ++#ifdef CLONE_NEWNS ++ if (unshare (CLONE_NEWNS) == 0) ++ { ++ /* On some systems, / is marked as MS_SHARED, which means that ++ mounts within the namespace leak to the rest of the system, ++ which is not what we want. */ ++ if (mount ("none", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0) ++ { ++ printf ("warning: making the mount namespace private failed: %m\n"); ++ return false; ++ } ++ return true; ++ } ++ else ++ printf ("warning: unshare (CLONE_NEWNS) failed: %m\n"); ++#endif /* CLONE_NEWNS */ ++ return false; ++} +diff --git a/support/support_enter_network_namespace.c b/support/support_enter_network_namespace.c +new file mode 100644 +index 0000000000..1d874df885 +--- /dev/null +++ b/support/support_enter_network_namespace.c @@ -0,0 +1,75 @@ +/* Enter a network namespace. @@ -3636,10 +4814,10 @@ index 0000000000..2acb9afffd +} diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c new file mode 100644 -index 0000000000..c5e00e516a +index 0000000000..60d2cc40f6 --- /dev/null +++ b/support/support_format_addrinfo.c -@@ -0,0 +1,240 @@ +@@ -0,0 +1,242 @@ +/* Convert struct addrinfo values to a string. + Copyright (C) 2016-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. @@ -3709,8 +4887,6 @@ index 0000000000..c5e00e516a + FLAG (AI_ADDRCONFIG); + FLAG (AI_IDN); + FLAG (AI_CANONIDN); -+ FLAG (AI_IDN_ALLOW_UNASSIGNED); -+ FLAG (AI_IDN_USE_STD3_ASCII_RULES); + FLAG (AI_NUMERICSERV); +#undef FLAG + int remaining = ai->ai_flags & ~flags_printed; @@ -3862,7 +5038,11 @@ index 0000000000..c5e00e516a + xopen_memstream (&mem); + if (ret != 0) + { -+ fprintf (mem.out, "error: %s\n", gai_strerror (ret)); ++ const char *errmsg = gai_strerror (ret); ++ if (strcmp (errmsg, "Unknown error") == 0) ++ fprintf (mem.out, "error: Unknown error %d\n", ret); ++ else ++ fprintf (mem.out, "error: %s\n", errmsg); + if (ret == EAI_SYSTEM) + { + errno = errno_copy; @@ -4351,6 +5531,275 @@ index 0000000000..25edc00385 + if (status != 0) + FAIL_EXIT1 ("child process exited with status %d", status); +} +diff --git a/support/support_openpty.c b/support/support_openpty.c +new file mode 100644 +index 0000000000..ac779ab91e +--- /dev/null ++++ b/support/support_openpty.c +@@ -0,0 +1,109 @@ ++/* Open a pseudoterminal. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* As ptsname, but allocates space for an appropriately-sized string ++ using malloc. */ ++static char * ++xptsname (int fd) ++{ ++ int rv; ++ size_t buf_len = 128; ++ char *buf = xmalloc (buf_len); ++ for (;;) ++ { ++ rv = ptsname_r (fd, buf, buf_len); ++ if (rv) ++ FAIL_EXIT1 ("ptsname_r: %s", strerror (errno)); ++ ++ if (memchr (buf, '\0', buf_len)) ++ return buf; /* ptsname succeeded and the buffer was not truncated */ ++ ++ buf_len *= 2; ++ buf = xrealloc (buf, buf_len); ++ } ++} ++ ++void ++support_openpty (int *a_outer, int *a_inner, char **a_name, ++ const struct termios *termp, ++ const struct winsize *winp) ++{ ++ int outer = -1, inner = -1; ++ char *namebuf = 0; ++ ++ outer = posix_openpt (O_RDWR | O_NOCTTY); ++ if (outer == -1) ++ FAIL_EXIT1 ("posix_openpt: %s", strerror (errno)); ++ ++ if (grantpt (outer)) ++ FAIL_EXIT1 ("grantpt: %s", strerror (errno)); ++ ++ if (unlockpt (outer)) ++ FAIL_EXIT1 ("unlockpt: %s", strerror (errno)); ++ ++ ++#ifdef TIOCGPTPEER ++ inner = ioctl (outer, TIOCGPTPEER, O_RDWR | O_NOCTTY); ++#endif ++ if (inner == -1) ++ { ++ /* The kernel might not support TIOCGPTPEER, fall back to open ++ by name. */ ++ namebuf = xptsname (outer); ++ inner = open (namebuf, O_RDWR | O_NOCTTY); ++ if (inner == -1) ++ FAIL_EXIT1 ("%s: %s", namebuf, strerror (errno)); ++ } ++ ++ if (termp) ++ { ++ if (tcsetattr (inner, TCSAFLUSH, termp)) ++ FAIL_EXIT1 ("tcsetattr: %s", strerror (errno)); ++ } ++#ifdef TIOCSWINSZ ++ if (winp) ++ { ++ if (ioctl (inner, TIOCSWINSZ, winp)) ++ FAIL_EXIT1 ("TIOCSWINSZ: %s", strerror (errno)); ++ } ++#endif ++ ++ if (a_name) ++ { ++ if (!namebuf) ++ namebuf = xptsname (outer); ++ *a_name = namebuf; ++ } ++ else ++ free (namebuf); ++ *a_outer = outer; ++ *a_inner = inner; ++} +diff --git a/support/support_paths.c b/support/support_paths.c +new file mode 100644 +index 0000000000..6d0beb102c +--- /dev/null ++++ b/support/support_paths.c +@@ -0,0 +1,59 @@ ++/* 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 ++ . */ ++ ++#include ++#include ++ ++/* 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 OBJDIR_ELF_LDSO_PATH ++/* Corresponds to the path to the runtime linker used by the testsuite, ++ e.g. OBJDIR_PATH/elf/ld-linux-x86-64.so.2 */ ++const char support_objdir_elf_ldso[] = OBJDIR_ELF_LDSO_PATH; ++#else ++# error please -DOBJDIR_ELF_LDSO_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/support_quote_blob.c b/support/support_quote_blob.c +new file mode 100644 +index 0000000000..d6a678d8d6 +--- /dev/null ++++ b/support/support_quote_blob.c +@@ -0,0 +1,83 @@ ++/* Quote a blob so that it can be used in C literals. ++ 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 ++ . */ ++ ++#include ++#include ++ ++char * ++support_quote_blob (const void *blob, size_t length) ++{ ++ struct xmemstream out; ++ xopen_memstream (&out); ++ ++ const unsigned char *p = blob; ++ for (size_t i = 0; i < length; ++i) ++ { ++ unsigned char ch = p[i]; ++ ++ /* Use C backslash escapes for those control characters for ++ which they are defined. */ ++ switch (ch) ++ { ++ case '\a': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('a', out.out); ++ break; ++ case '\b': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('b', out.out); ++ break; ++ case '\f': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('f', out.out); ++ break; ++ case '\n': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('n', out.out); ++ break; ++ case '\r': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('r', out.out); ++ break; ++ case '\t': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('t', out.out); ++ break; ++ case '\v': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('v', out.out); ++ break; ++ case '\\': ++ case '\'': ++ case '\"': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked (ch, out.out); ++ break; ++ default: ++ if (ch < ' ' || ch > '~') ++ /* Use octal sequences because they are fixed width, ++ unlike hexadecimal sequences. */ ++ fprintf (out.out, "\\%03o", ch); ++ else ++ putc_unlocked (ch, out.out); ++ } ++ } ++ ++ xfclose_memstream (&out); ++ return out.buffer; ++} diff --git a/support/support_record_failure.c b/support/support_record_failure.c new file mode 100644 index 0000000000..356798f556 @@ -4608,14 +6057,14 @@ index 0000000000..8ab43c4b38 + struct header *header = data - offsetof (struct header, data); + xmunmap (header, header->total_size); +} -diff --git a/support/support_test_compare_failure.c b/support/support_test_compare_failure.c +diff --git a/support/support_test_compare_blob.c b/support/support_test_compare_blob.c new file mode 100644 -index 0000000000..e5596fd121 +index 0000000000..c5e63d1b93 --- /dev/null -+++ b/support/support_test_compare_failure.c -@@ -0,0 +1,55 @@ -+/* Reporting a numeric comparison failure. -+ Copyright (C) 2017-2018 Free Software Foundation, Inc. ++++ b/support/support_test_compare_blob.c +@@ -0,0 +1,76 @@ ++/* Check two binary blobs for equality. ++ 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 @@ -4633,18 +6082,101 @@ index 0000000000..e5596fd121 + . */ + +#include ++#include ++#include +#include ++#include ++#include + +static void -+report (const char *which, const char *expr, long long value, int positive, -+ int size) ++report_length (const char *what, unsigned long int length, const char *expr) +{ -+ printf (" %s: ", which); -+ if (positive) -+ printf ("%llu", (unsigned long long) value); -+ else -+ printf ("%lld", value); -+ unsigned long long mask ++ printf (" %s %lu bytes (from %s)\n", what, length, expr); ++} ++ ++static void ++report_blob (const char *what, const unsigned char *blob, ++ unsigned long int length, const char *expr) ++{ ++ if (length > 0) ++ { ++ printf (" %s (evaluated from %s):\n", what, expr); ++ char *quoted = support_quote_blob (blob, length); ++ printf (" \"%s\"\n", quoted); ++ free (quoted); ++ ++ fputs (" ", stdout); ++ for (unsigned long i = 0; i < length; ++i) ++ printf (" %02X", blob[i]); ++ putc ('\n', stdout); ++ } ++} ++ ++void ++support_test_compare_blob (const void *left, unsigned long int left_length, ++ const void *right, unsigned long int right_length, ++ const char *file, int line, ++ const char *left_expr, const char *left_len_expr, ++ const char *right_expr, const char *right_len_expr) ++{ ++ /* No differences are possible if both lengths are null. */ ++ if (left_length == 0 && right_length == 0) ++ return; ++ ++ if (left_length != right_length || left == NULL || right == NULL ++ || memcmp (left, right, left_length) != 0) ++ { ++ support_record_failure (); ++ printf ("%s:%d: error: blob comparison failed\n", file, line); ++ if (left_length == right_length) ++ printf (" blob length: %lu bytes\n", left_length); ++ else ++ { ++ report_length ("left length: ", left_length, left_len_expr); ++ report_length ("right length:", right_length, right_len_expr); ++ } ++ report_blob ("left", left, left_length, left_expr); ++ report_blob ("right", right, right_length, right_expr); ++ } ++} +diff --git a/support/support_test_compare_failure.c b/support/support_test_compare_failure.c +new file mode 100644 +index 0000000000..8eb51c439d +--- /dev/null ++++ b/support/support_test_compare_failure.c +@@ -0,0 +1,58 @@ ++/* Reporting a numeric comparison failure. ++ Copyright (C) 2017-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 ++ . */ ++ ++#include ++#include ++#include ++ ++static void ++report (const char *which, const char *expr, long long value, int positive, ++ int size) ++{ ++ printf (" %s: ", which); ++ if (positive) ++ printf ("%llu", (unsigned long long) value); ++ else ++ printf ("%lld", value); ++ unsigned long long mask + = (~0ULL) >> (8 * (sizeof (unsigned long long) - size)); + printf (" (0x%llx); from: %s\n", (unsigned long long) value & mask, expr); +} @@ -4660,6 +6192,7 @@ index 0000000000..e5596fd121 + int right_positive, + int right_size) +{ ++ int saved_errno = errno; + support_record_failure (); + if (left_size != right_size) + printf ("%s:%d: numeric comparison failure (widths %d and %d)\n", @@ -4668,13 +6201,111 @@ index 0000000000..e5596fd121 + printf ("%s:%d: numeric comparison failure\n", file, line); + report (" left", left_expr, left_value, left_positive, left_size); + report ("right", right_expr, right_value, right_positive, right_size); ++ errno = saved_errno; ++} +diff --git a/support/support_test_compare_string.c b/support/support_test_compare_string.c +new file mode 100644 +index 0000000000..a76ba8eda7 +--- /dev/null ++++ b/support/support_test_compare_string.c +@@ -0,0 +1,91 @@ ++/* Check two strings for equality. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++report_length (const char *what, const char *str, size_t length) ++{ ++ if (str == NULL) ++ printf (" %s string: NULL\n", what); ++ else ++ printf (" %s string: %zu bytes\n", what, length); ++} ++ ++static void ++report_string (const char *what, const unsigned char *blob, ++ size_t length, const char *expr) ++{ ++ if (length > 0) ++ { ++ printf (" %s (evaluated from %s):\n", what, expr); ++ char *quoted = support_quote_blob (blob, length); ++ printf (" \"%s\"\n", quoted); ++ free (quoted); ++ ++ fputs (" ", stdout); ++ for (size_t i = 0; i < length; ++i) ++ printf (" %02X", blob[i]); ++ putc ('\n', stdout); ++ } ++} ++ ++static size_t ++string_length_or_zero (const char *str) ++{ ++ if (str == NULL) ++ return 0; ++ else ++ return strlen (str); ++} ++ ++void ++support_test_compare_string (const char *left, const char *right, ++ const char *file, int line, ++ const char *left_expr, const char *right_expr) ++{ ++ /* Two null pointers are accepted. */ ++ if (left == NULL && right == NULL) ++ return; ++ ++ size_t left_length = string_length_or_zero (left); ++ size_t right_length = string_length_or_zero (right); ++ ++ if (left_length != right_length || left == NULL || right == NULL ++ || memcmp (left, right, left_length) != 0) ++ { ++ support_record_failure (); ++ printf ("%s:%d: error: blob comparison failed\n", file, line); ++ if (left_length == right_length && right != NULL && left != NULL) ++ printf (" string length: %zu bytes\n", left_length); ++ else ++ { ++ report_length ("left", left, left_length); ++ report_length ("right", right, right_length); ++ } ++ report_string ("left", (const unsigned char *) left, ++ left_length, left_expr); ++ report_string ("right", (const unsigned char *) right, ++ right_length, right_expr); ++ } +} diff --git a/support/support_test_main.c b/support/support_test_main.c new file mode 100644 -index 0000000000..396385729b +index 0000000000..23429779ac --- /dev/null +++ b/support/support_test_main.c -@@ -0,0 +1,424 @@ +@@ -0,0 +1,425 @@ +/* Main worker function for the test driver. + Copyright (C) 1998-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. @@ -4947,7 +6578,8 @@ index 0000000000..396385729b + timeout = DEFAULT_TIMEOUT; + + /* Make sure we see all message, even those on stdout. */ -+ setvbuf (stdout, NULL, _IONBF, 0); ++ if (!config->no_setvbuf) ++ setvbuf (stdout, NULL, _IONBF, 0); + + /* Make sure temporary files are deleted. */ + if (support_delete_temp_files != NULL) @@ -5101,10 +6733,10 @@ index 0000000000..396385729b +} diff --git a/support/support_test_verify_impl.c b/support/support_test_verify_impl.c new file mode 100644 -index 0000000000..80311a8265 +index 0000000000..5ff5555a6a --- /dev/null +++ b/support/support_test_verify_impl.c -@@ -0,0 +1,37 @@ +@@ -0,0 +1,40 @@ +/* Implementation of the TEST_VERIFY and TEST_VERIFY_EXIT macros. + Copyright (C) 2016-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. @@ -5125,14 +6757,17 @@ index 0000000000..80311a8265 + +#include + ++#include +#include +#include + +void +support_test_verify_impl (const char *file, int line, const char *expr) +{ ++ int saved_errno = errno; + support_record_failure (); + printf ("error: %s:%d: not true: %s\n", file, line, expr); ++ errno = saved_errno; +} + +void @@ -5406,29 +7041,1023 @@ index 0000000000..c7795cc577 + +__BEGIN_DECLS + -+/* Schedule a temporary file for deletion on exit. */ -+void add_temp_file (const char *name); ++/* Schedule a temporary file for deletion on exit. */ ++void add_temp_file (const char *name); ++ ++/* Create a temporary file. Return the opened file descriptor on ++ success, or -1 on failure. Write the file name to *FILENAME if ++ FILENAME is not NULL. In this case, the caller is expected to free ++ *FILENAME. */ ++int create_temp_file (const char *base, char **filename); ++ ++/* Create a temporary directory and schedule it for deletion. BASE is ++ used as a prefix for the unique directory name, which the function ++ returns. The caller should free this string. */ ++char *support_create_temp_directory (const char *base); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_TEMP_FILE_H */ +diff --git a/support/test-container.c b/support/test-container.c +new file mode 100644 +index 0000000000..b58f0f7b3d +--- /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 ++ . */ ++ ++#define _FILE_OFFSET_BITS 64 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef __linux__ ++#include ++#endif ++ ++#include ++#include ++#include "check.h" ++#include "test-driver.h" ++ ++#ifndef __linux__ ++#define mount(s,t,fs,f,d) no_mount() ++int no_mount (void) ++{ ++ FAIL_UNSUPPORTED("mount not supported; port needed"); ++} ++#endif ++ ++int verbose = 0; ++ ++/* Running a test in a container is tricky. There are two main ++ categories of things to do: ++ ++ 1. "Once" actions, like setting up the container and doing an ++ install into it. ++ ++ 2. "Per-test" actions, like copying in support files and ++ configuring the container. ++ ++ ++ "Once" actions: ++ ++ * mkdir $buildroot/testroot.pristine/ ++ * install into it ++ * rsync to $buildroot/testroot.root/ ++ ++ "Per-test" actions: ++ * maybe rsync to $buildroot/testroot.root/ ++ * copy support files and test binary ++ * chroot/unshare ++ * set up any mounts (like /proc) ++ ++ Magic files: ++ ++ For test $srcdir/foo/mytest.c we look for $srcdir/foo/mytest.root ++ and, if found... ++ ++ * mytest.root/ is rsync'd into container ++ * mytest.root/preclean.req causes fresh rsync (with delete) before ++ test if present ++ * mytest.root/mytset.script has a list of "commands" to run: ++ syntax: ++ # comment ++ mv FILE FILE ++ cp FILE FILE ++ rm FILE ++ FILE must start with $B/, $S/, $I/, $L/, or / ++ (expands to build dir, source dir, install dir, library dir ++ (in container), or container's root) ++ * mytest.root/postclean.req causes fresh rsync (with delete) after ++ test if present ++ ++ Note that $srcdir/foo/mytest.script may be used instead of a ++ $srcdir/foo/mytest.root/mytest.script in the sysroot template, if ++ there is no other reason for a sysroot. ++ ++ Design goals: ++ ++ * independent of other packages which may not be installed (like ++ rsync or Docker, or even "cp") ++ ++ * Simple, easy to review code (i.e. prefer simple naive code over ++ complex efficient code) ++ ++ * The current implementation ist parallel-make-safe, but only in ++ that it uses a lock to prevent parallel access to the testroot. */ ++ ++ ++/* Utility Functions */ ++ ++/* Like xunlink, but it's OK if the file already doesn't exist. */ ++void ++maybe_xunlink (const char *path) ++{ ++ int rv = unlink (path); ++ if (rv < 0 && errno != ENOENT) ++ FAIL_EXIT1 ("unlink (\"%s\"): %m", path); ++} ++ ++/* Like xmkdir, but it's OK if the directory already exists. */ ++void ++maybe_xmkdir (const char *path, mode_t mode) ++{ ++ struct stat st; ++ ++ if (stat (path, &st) == 0 ++ && S_ISDIR (st.st_mode)) ++ return; ++ xmkdir (path, mode); ++} ++ ++/* Temporarily concatenate multiple strings into one. Allows up to 10 ++ temporary results; use strdup () if you need them to be ++ permanent. */ ++static char * ++concat (const char *str, ...) ++{ ++ /* Assume initialized to NULL/zero. */ ++ static char *bufs[10]; ++ static size_t buflens[10]; ++ static int bufn = 0; ++ int n; ++ size_t len; ++ va_list ap, ap2; ++ char *cp; ++ char *next; ++ ++ va_start (ap, str); ++ va_copy (ap2, ap); ++ ++ n = bufn; ++ bufn = (bufn + 1) % 10; ++ len = strlen (str); ++ ++ while ((next = va_arg (ap, char *)) != NULL) ++ len = len + strlen (next); ++ ++ va_end (ap); ++ ++ if (bufs[n] == NULL) ++ { ++ bufs[n] = xmalloc (len + 1); /* NUL */ ++ buflens[n] = len + 1; ++ } ++ else if (buflens[n] < len + 1) ++ { ++ bufs[n] = xrealloc (bufs[n], len + 1); /* NUL */ ++ buflens[n] = len + 1; ++ } ++ ++ strcpy (bufs[n], str); ++ cp = strchr (bufs[n], '\0'); ++ while ((next = va_arg (ap2, char *)) != NULL) ++ { ++ strcpy (cp, next); ++ cp = strchr (cp, '\0'); ++ } ++ *cp = 0; ++ va_end (ap2); ++ ++ return bufs[n]; ++} ++ ++/* Try to mount SRC onto DEST. */ ++static void ++trymount (const char *src, const char *dest) ++{ ++ if (mount (src, dest, "", MS_BIND, NULL) < 0) ++ FAIL_EXIT1 ("can't mount %s onto %s\n", src, dest); ++} ++ ++/* Special case of above for devices like /dev/zero where we have to ++ mount a device over a device, not a directory over a directory. */ ++static void ++devmount (const char *new_root_path, const char *which) ++{ ++ int fd; ++ fd = open (concat (new_root_path, "/dev/", which, NULL), ++ O_CREAT | O_TRUNC | O_RDWR, 0777); ++ xclose (fd); ++ ++ trymount (concat ("/dev/", which, NULL), ++ concat (new_root_path, "/dev/", which, NULL)); ++} ++ ++/* Returns true if the string "looks like" an environement variable ++ being set. */ ++static int ++is_env_setting (const char *a) ++{ ++ int count_name = 0; ++ ++ while (*a) ++ { ++ if (isalnum (*a) || *a == '_') ++ ++count_name; ++ else if (*a == '=' && count_name > 0) ++ return 1; ++ else ++ return 0; ++ ++a; ++ } ++ return 0; ++} ++ ++/* Break the_line into words and store in the_words. Max nwords, ++ returns actual count. */ ++static int ++tokenize (char *the_line, char **the_words, int nwords) ++{ ++ int rv = 0; ++ ++ while (nwords > 0) ++ { ++ /* Skip leading whitespace, if any. */ ++ while (*the_line && isspace (*the_line)) ++ ++the_line; ++ ++ /* End of line? */ ++ if (*the_line == 0) ++ return rv; ++ ++ /* THE_LINE points to a non-whitespace character, so we have a ++ word. */ ++ *the_words = the_line; ++ ++the_words; ++ nwords--; ++ ++rv; ++ ++ /* Skip leading whitespace, if any. */ ++ while (*the_line && ! isspace (*the_line)) ++ ++the_line; ++ ++ /* We now point at the trailing NUL *or* some whitespace. */ ++ if (*the_line == 0) ++ return rv; ++ ++ /* It was whitespace, skip and keep tokenizing. */ ++ *the_line++ = 0; ++ } ++ ++ /* We get here if we filled the words buffer. */ ++ return rv; ++} ++ ++ ++/* Mini-RSYNC implementation. Optimize later. */ ++ ++/* A few routines for an "rsync buffer" which stores the paths we're ++ working on. We continuously grow and shrink the paths in each ++ buffer so there's lot of re-use. */ ++ ++/* We rely on "initialized to zero" to set these up. */ ++typedef struct ++{ ++ char *buf; ++ size_t len; ++ size_t size; ++} path_buf; ++ ++static path_buf spath, dpath; ++ ++static void ++r_setup (char *path, path_buf * pb) ++{ ++ size_t len = strlen (path); ++ if (pb->buf == NULL || pb->size < len + 1) ++ { ++ /* Round up. This is an arbitrary number, just to keep from ++ reallocing too often. */ ++ size_t sz = ALIGN_UP (len + 1, 512); ++ if (pb->buf == NULL) ++ pb->buf = (char *) xmalloc (sz); ++ else ++ pb->buf = (char *) xrealloc (pb->buf, sz); ++ if (pb->buf == NULL) ++ FAIL_EXIT1 ("Out of memory while rsyncing\n"); ++ ++ pb->size = sz; ++ } ++ strcpy (pb->buf, path); ++ pb->len = len; ++} ++ ++static void ++r_append (const char *path, path_buf * pb) ++{ ++ size_t len = strlen (path) + pb->len; ++ if (pb->size < len + 1) ++ { ++ /* Round up */ ++ size_t sz = ALIGN_UP (len + 1, 512); ++ pb->buf = (char *) xrealloc (pb->buf, sz); ++ if (pb->buf == NULL) ++ FAIL_EXIT1 ("Out of memory while rsyncing\n"); ++ ++ pb->size = sz; ++ } ++ strcpy (pb->buf + pb->len, path); ++ pb->len = len; ++} ++ ++static int ++file_exists (char *path) ++{ ++ struct stat st; ++ if (lstat (path, &st) == 0) ++ return 1; ++ return 0; ++} ++ ++static void ++recursive_remove (char *path) ++{ ++ pid_t child; ++ int status; ++ ++ child = fork (); ++ ++ switch (child) { ++ case -1: ++ FAIL_EXIT1 ("Unable to fork"); ++ case 0: ++ /* Child. */ ++ execlp ("rm", "rm", "-rf", path, NULL); ++ default: ++ /* Parent. */ ++ waitpid (child, &status, 0); ++ /* "rm" would have already printed a suitable error message. */ ++ if (! WIFEXITED (status) ++ || WEXITSTATUS (status) != 0) ++ exit (1); ++ ++ break; ++ } ++} ++ ++/* Used for both rsync and the mytest.script "cp" command. */ ++static void ++copy_one_file (const char *sname, const char *dname) ++{ ++ int sfd, dfd; ++ struct stat st; ++ struct utimbuf times; ++ ++ sfd = open (sname, O_RDONLY); ++ if (sfd < 0) ++ FAIL_EXIT1 ("unable to open %s for reading\n", sname); ++ ++ if (fstat (sfd, &st) < 0) ++ FAIL_EXIT1 ("unable to fstat %s\n", sname); ++ ++ dfd = open (dname, O_WRONLY | O_TRUNC | O_CREAT, 0600); ++ if (dfd < 0) ++ FAIL_EXIT1 ("unable to open %s for writing\n", dname); ++ ++ xcopy_file_range (sfd, 0, dfd, 0, st.st_size, 0); ++ ++ xclose (sfd); ++ xclose (dfd); ++ ++ if (chmod (dname, st.st_mode & 0777) < 0) ++ FAIL_EXIT1 ("chmod %s: %s\n", dname, strerror (errno)); ++ ++ times.actime = st.st_atime; ++ times.modtime = st.st_mtime; ++ if (utime (dname, ×) < 0) ++ FAIL_EXIT1 ("utime %s: %s\n", dname, strerror (errno)); ++} ++ ++/* We don't check *everything* about the two files to see if a copy is ++ needed, just the minimum to make sure we get the latest copy. */ ++static int ++need_sync (char *ap, char *bp, struct stat *a, struct stat *b) ++{ ++ if ((a->st_mode & S_IFMT) != (b->st_mode & S_IFMT)) ++ return 1; ++ ++ if (S_ISLNK (a->st_mode)) ++ { ++ int rv; ++ char *al, *bl; ++ ++ if (a->st_size != b->st_size) ++ return 1; ++ ++ al = xreadlink (ap); ++ bl = xreadlink (bp); ++ rv = strcmp (al, bl); ++ free (al); ++ free (bl); ++ if (rv == 0) ++ return 0; /* links are same */ ++ return 1; /* links differ */ ++ } ++ ++ if (verbose) ++ { ++ if (a->st_size != b->st_size) ++ printf ("SIZE\n"); ++ if ((a->st_mode & 0777) != (b->st_mode & 0777)) ++ printf ("MODE\n"); ++ if (a->st_mtime != b->st_mtime) ++ printf ("TIME\n"); ++ } ++ ++ if (a->st_size == b->st_size ++ && ((a->st_mode & 0777) == (b->st_mode & 0777)) ++ && a->st_mtime == b->st_mtime) ++ return 0; ++ ++ return 1; ++} ++ ++static void ++rsync_1 (path_buf * src, path_buf * dest, int and_delete) ++{ ++ DIR *dir; ++ struct dirent *de; ++ struct stat s, d; ++ ++ r_append ("/", src); ++ r_append ("/", dest); ++ ++ if (verbose) ++ printf ("sync %s to %s %s\n", src->buf, dest->buf, ++ and_delete ? "and delete" : ""); ++ ++ size_t staillen = src->len; ++ ++ size_t dtaillen = dest->len; ++ ++ dir = opendir (src->buf); ++ ++ while ((de = readdir (dir)) != NULL) ++ { ++ if (strcmp (de->d_name, ".") == 0 ++ || strcmp (de->d_name, "..") == 0) ++ continue; ++ ++ src->len = staillen; ++ r_append (de->d_name, src); ++ dest->len = dtaillen; ++ r_append (de->d_name, dest); ++ ++ s.st_mode = ~0; ++ d.st_mode = ~0; ++ ++ if (lstat (src->buf, &s) != 0) ++ FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", src->buf); ++ ++ /* It's OK if this one fails, since we know the file might be ++ missing. */ ++ lstat (dest->buf, &d); ++ ++ if (! need_sync (src->buf, dest->buf, &s, &d)) ++ { ++ if (S_ISDIR (s.st_mode)) ++ rsync_1 (src, dest, and_delete); ++ continue; ++ } ++ ++ if (d.st_mode != ~0) ++ switch (d.st_mode & S_IFMT) ++ { ++ case S_IFDIR: ++ if (!S_ISDIR (s.st_mode)) ++ { ++ if (verbose) ++ printf ("-D %s\n", dest->buf); ++ recursive_remove (dest->buf); ++ } ++ break; ++ ++ default: ++ if (verbose) ++ printf ("-F %s\n", dest->buf); ++ maybe_xunlink (dest->buf); ++ break; ++ } ++ ++ switch (s.st_mode & S_IFMT) ++ { ++ case S_IFREG: ++ if (verbose) ++ printf ("+F %s\n", dest->buf); ++ copy_one_file (src->buf, dest->buf); ++ break; ++ ++ case S_IFDIR: ++ if (verbose) ++ printf ("+D %s\n", dest->buf); ++ maybe_xmkdir (dest->buf, (s.st_mode & 0777) | 0700); ++ rsync_1 (src, dest, and_delete); ++ break; ++ ++ case S_IFLNK: ++ { ++ char *lp; ++ if (verbose) ++ printf ("+L %s\n", dest->buf); ++ lp = xreadlink (src->buf); ++ xsymlink (lp, dest->buf); ++ free (lp); ++ break; ++ } ++ ++ default: ++ break; ++ } ++ } ++ ++ closedir (dir); ++ src->len = staillen; ++ src->buf[staillen] = 0; ++ dest->len = dtaillen; ++ dest->buf[dtaillen] = 0; ++ ++ if (!and_delete) ++ return; ++ ++ /* The rest of this function removes any files/directories in DEST ++ that do not exist in SRC. This is triggered as part of a ++ preclean or postsclean step. */ ++ ++ dir = opendir (dest->buf); ++ ++ while ((de = readdir (dir)) != NULL) ++ { ++ if (strcmp (de->d_name, ".") == 0 ++ || strcmp (de->d_name, "..") == 0) ++ continue; ++ ++ src->len = staillen; ++ r_append (de->d_name, src); ++ dest->len = dtaillen; ++ r_append (de->d_name, dest); ++ ++ s.st_mode = ~0; ++ d.st_mode = ~0; ++ ++ lstat (src->buf, &s); ++ ++ if (lstat (dest->buf, &d) != 0) ++ FAIL_EXIT1 ("%s obtained by readdir, but stat failed.\n", dest->buf); ++ ++ if (s.st_mode == ~0) ++ { ++ /* dest exists and src doesn't, clean it. */ ++ switch (d.st_mode & S_IFMT) ++ { ++ case S_IFDIR: ++ if (!S_ISDIR (s.st_mode)) ++ { ++ if (verbose) ++ printf ("-D %s\n", dest->buf); ++ recursive_remove (dest->buf); ++ } ++ break; ++ ++ default: ++ if (verbose) ++ printf ("-F %s\n", dest->buf); ++ maybe_xunlink (dest->buf); ++ break; ++ } ++ } ++ } ++ ++ closedir (dir); ++} ++ ++static void ++rsync (char *src, char *dest, int and_delete) ++{ ++ r_setup (src, &spath); ++ r_setup (dest, &dpath); ++ ++ rsync_1 (&spath, &dpath, and_delete); ++} ++ ++ ++int ++main (int argc, char **argv) ++{ ++ pid_t child; ++ char *pristine_root_path; ++ char *new_root_path; ++ char *new_cwd_path; ++ char *new_objdir_path; ++ char *new_srcdir_path; ++ char **new_child_proc; ++ char *command_root; ++ char *command_base; ++ char *command_basename; ++ char *so_base; ++ int do_postclean = 0; ++ ++ uid_t original_uid; ++ gid_t original_gid; ++ int UMAP; ++ int GMAP; ++ /* Used for "%lld %lld 1" so need not be large. */ ++ char tmp[100]; ++ struct stat st; ++ int lock_fd; ++ ++ setbuf (stdout, NULL); ++ ++ /* The command line we're expecting looks like this: ++ env ld.so test-binary ++ ++ We need to peel off any "env" or "ld.so" portion of the command ++ line, and keep track of which env vars we should preserve and ++ which we drop. */ ++ ++ if (argc < 2) ++ { ++ fprintf (stderr, "Usage: containerize \n"); ++ exit (1); ++ } ++ ++ if (strcmp (argv[1], "-v") == 0) ++ { ++ verbose = 1; ++ ++argv; ++ --argc; ++ } ++ ++ if (strcmp (argv[1], "env") == 0) ++ { ++ ++argv; ++ --argc; ++ while (is_env_setting (argv[1])) ++ { ++ /* If there are variables we do NOT want to propogate, this ++ is where the test for them goes. */ ++ { ++ /* Need to keep these. Note that putenv stores a ++ pointer to our argv. */ ++ putenv (argv[1]); ++ } ++ ++argv; ++ --argc; ++ } ++ } ++ ++ if (strcmp (argv[1], support_objdir_elf_ldso) == 0) ++ { ++ ++argv; ++ --argc; ++ while (argv[1][0] == '-') ++ { ++ if (strcmp (argv[1], "--library-path") == 0) ++ { ++ ++argv; ++ --argc; ++ } ++ ++argv; ++ --argc; ++ } ++ } ++ ++ pristine_root_path = strdup (concat (support_objdir_root, ++ "/testroot.pristine", NULL)); ++ new_root_path = strdup (concat (support_objdir_root, ++ "/testroot.root", NULL)); ++ new_cwd_path = get_current_dir_name (); ++ new_child_proc = argv + 1; ++ ++ lock_fd = open (concat (pristine_root_path, "/lock.fd", NULL), ++ O_CREAT | O_TRUNC | O_RDWR, 0666); ++ if (lock_fd < 0) ++ FAIL_EXIT1 ("Cannot create testroot lock.\n"); ++ ++ while (flock (lock_fd, LOCK_EX) != 0) ++ { ++ if (errno != EINTR) ++ FAIL_EXIT1 ("Cannot lock testroot.\n"); ++ } ++ ++ xmkdirp (new_root_path, 0755); ++ ++ /* We look for extra setup info in a subdir in the same spot as the ++ test, with the same name but a ".root" extension. This is that ++ directory. We try to look in the source tree if the path we're ++ given refers to the build tree, but we rely on the path to be ++ absolute. This is what the glibc makefiles do. */ ++ command_root = concat (argv[1], ".root", NULL); ++ if (strncmp (command_root, support_objdir_root, ++ strlen (support_objdir_root)) == 0 ++ && command_root[strlen (support_objdir_root)] == '/') ++ command_root = concat (support_srcdir_root, ++ argv[1] + strlen (support_objdir_root), ++ ".root", NULL); ++ command_root = strdup (command_root); ++ ++ /* This cuts off the ".root" we appended above. */ ++ command_base = strdup (command_root); ++ command_base[strlen (command_base) - 5] = 0; ++ ++ /* This is the basename of the test we're running. */ ++ command_basename = strrchr (command_base, '/'); ++ if (command_basename == NULL) ++ command_basename = command_base; ++ else ++ ++command_basename; ++ ++ /* Shared object base directory. */ ++ so_base = strdup (argv[1]); ++ if (strrchr (so_base, '/') != NULL) ++ strrchr (so_base, '/')[1] = 0; ++ ++ if (file_exists (concat (command_root, "/postclean.req", NULL))) ++ do_postclean = 1; ++ ++ rsync (pristine_root_path, new_root_path, ++ file_exists (concat (command_root, "/preclean.req", NULL))); ++ ++ if (stat (command_root, &st) >= 0 ++ && S_ISDIR (st.st_mode)) ++ rsync (command_root, new_root_path, 0); ++ ++ new_objdir_path = strdup (concat (new_root_path, ++ support_objdir_root, NULL)); ++ new_srcdir_path = strdup (concat (new_root_path, ++ support_srcdir_root, NULL)); ++ ++ /* new_cwd_path starts with '/' so no "/" needed between the two. */ ++ xmkdirp (concat (new_root_path, new_cwd_path, NULL), 0755); ++ xmkdirp (new_srcdir_path, 0755); ++ xmkdirp (new_objdir_path, 0755); ++ ++ original_uid = getuid (); ++ original_gid = getgid (); ++ ++ /* Handle the cp/mv/rm "script" here. */ ++ { ++ char *the_line = NULL; ++ size_t line_len = 0; ++ char *fname = concat (command_root, "/", ++ command_basename, ".script", NULL); ++ char *the_words[3]; ++ FILE *f = fopen (fname, "r"); ++ ++ if (verbose && f) ++ fprintf (stderr, "running %s\n", fname); ++ ++ if (f == NULL) ++ { ++ /* Try foo.script instead of foo.root/foo.script, as a shortcut. */ ++ fname = concat (command_base, ".script", NULL); ++ f = fopen (fname, "r"); ++ if (verbose && f) ++ fprintf (stderr, "running %s\n", fname); ++ } ++ ++ /* Note that we do NOT look for a Makefile-generated foo.script in ++ the build directory. If that is ever needed, this is the place ++ to add it. */ ++ ++ /* This is where we "interpret" the mini-script which is .script. */ ++ if (f != NULL) ++ { ++ while (getline (&the_line, &line_len, f) > 0) ++ { ++ int nt = tokenize (the_line, the_words, 3); ++ int i; ++ ++ for (i = 1; i < nt; ++i) ++ { ++ if (memcmp (the_words[i], "$B/", 3) == 0) ++ the_words[i] = concat (support_objdir_root, ++ the_words[i] + 2, NULL); ++ else if (memcmp (the_words[i], "$S/", 3) == 0) ++ the_words[i] = concat (support_srcdir_root, ++ the_words[i] + 2, NULL); ++ else if (memcmp (the_words[i], "$I/", 3) == 0) ++ the_words[i] = concat (new_root_path, ++ support_install_prefix, ++ the_words[i] + 2, NULL); ++ else if (memcmp (the_words[i], "$L/", 3) == 0) ++ the_words[i] = concat (new_root_path, ++ support_libdir_prefix, ++ the_words[i] + 2, NULL); ++ else if (the_words[i][0] == '/') ++ the_words[i] = concat (new_root_path, ++ the_words[i], NULL); ++ } ++ ++ if (nt == 3 && the_words[2][strlen (the_words[2]) - 1] == '/') ++ { ++ char *r = strrchr (the_words[1], '/'); ++ if (r) ++ the_words[2] = concat (the_words[2], r + 1, NULL); ++ else ++ the_words[2] = concat (the_words[2], the_words[1], NULL); ++ } ++ ++ if (nt == 2 && strcmp (the_words[0], "so") == 0) ++ { ++ the_words[2] = concat (new_root_path, support_libdir_prefix, ++ "/", the_words[1], NULL); ++ the_words[1] = concat (so_base, the_words[1], NULL); ++ copy_one_file (the_words[1], the_words[2]); ++ } ++ else if (nt == 3 && strcmp (the_words[0], "cp") == 0) ++ { ++ copy_one_file (the_words[1], the_words[2]); ++ } ++ else if (nt == 3 && strcmp (the_words[0], "mv") == 0) ++ { ++ if (rename (the_words[1], the_words[2]) < 0) ++ FAIL_EXIT1 ("rename %s -> %s: %s", the_words[1], ++ the_words[2], strerror (errno)); ++ } ++ else if (nt == 3 && strcmp (the_words[0], "chmod") == 0) ++ { ++ long int m; ++ m = strtol (the_words[1], NULL, 0); ++ if (chmod (the_words[2], m) < 0) ++ FAIL_EXIT1 ("chmod %s: %s\n", ++ the_words[2], strerror (errno)); ++ ++ } ++ else if (nt == 2 && strcmp (the_words[0], "rm") == 0) ++ { ++ maybe_xunlink (the_words[1]); ++ } ++ else if (nt > 0 && the_words[0][0] != '#') ++ { ++ printf ("\033[31minvalid [%s]\033[0m\n", the_words[0]); ++ } ++ } ++ fclose (f); ++ } ++ } ++ ++#ifdef CLONE_NEWNS ++ /* The unshare here gives us our own spaces and capabilities. */ ++ if (unshare (CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS) < 0) ++ { ++ /* Older kernels may not support all the options, or security ++ policy may block this call. */ ++ if (errno == EINVAL || errno == EPERM) ++ FAIL_UNSUPPORTED ("unable to unshare user/fs: %s", strerror (errno)); ++ else ++ FAIL_EXIT1 ("unable to unshare user/fs: %s", strerror (errno)); ++ } ++#else ++ /* Some targets may not support unshare at all. */ ++ FAIL_UNSUPPORTED ("unshare support missing"); ++#endif ++ ++ /* Some systems, by default, all mounts leak out of the namespace. */ ++ if (mount ("none", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0) ++ FAIL_EXIT1 ("could not create a private mount namespace\n"); ++ ++ trymount (support_srcdir_root, new_srcdir_path); ++ trymount (support_objdir_root, new_objdir_path); ++ ++ xmkdirp (concat (new_root_path, "/dev", NULL), 0755); ++ devmount (new_root_path, "null"); ++ devmount (new_root_path, "zero"); ++ devmount (new_root_path, "urandom"); ++ ++ /* We're done with the "old" root, switch to the new one. */ ++ if (chroot (new_root_path) < 0) ++ FAIL_EXIT1 ("Can't chroot to %s - ", new_root_path); ++ ++ if (chdir (new_cwd_path) < 0) ++ FAIL_EXIT1 ("Can't cd to new %s - ", new_cwd_path); ++ ++ /* To complete the containerization, we need to fork () at least ++ once. We can't exec, nor can we somehow link the new child to ++ our parent. So we run the child and propogate it's exit status ++ up. */ ++ child = fork (); ++ if (child < 0) ++ FAIL_EXIT1 ("Unable to fork"); ++ else if (child > 0) ++ { ++ /* Parent. */ ++ int status; ++ waitpid (child, &status, 0); ++ ++ /* There's a bit of magic here, since the buildroot is mounted ++ in our space, the paths are still valid, and since the mounts ++ aren't recursive, it sees *only* the built root, not anything ++ we would normally se if we rsync'd to "/" like mounted /dev ++ files. */ ++ if (do_postclean) ++ rsync (pristine_root_path, new_root_path, 1); ++ ++ if (WIFEXITED (status)) ++ exit (WEXITSTATUS (status)); ++ ++ if (WIFSIGNALED (status)) ++ { ++ printf ("%%SIGNALLED%%\n"); ++ exit (77); ++ } ++ ++ printf ("%%EXITERROR%%\n"); ++ exit (78); ++ } ++ ++ /* The rest is the child process, which is now PID 1 and "in" the ++ new root. */ ++ ++ maybe_xmkdir ("/tmp", 0755); ++ ++ /* Now that we're pid 1 (effectively "root") we can mount /proc */ ++ maybe_xmkdir ("/proc", 0777); ++ if (mount ("proc", "/proc", "proc", 0, NULL) < 0) ++ FAIL_EXIT1 ("Unable to mount /proc: "); ++ ++ /* We map our original UID to the same UID in the container so we ++ can own our own files normally. */ ++ UMAP = open ("/proc/self/uid_map", O_WRONLY); ++ if (UMAP < 0) ++ FAIL_EXIT1 ("can't write to /proc/self/uid_map\n"); ++ ++ sprintf (tmp, "%lld %lld 1\n", ++ (long long) original_uid, (long long) original_uid); ++ write (UMAP, tmp, strlen (tmp)); ++ xclose (UMAP); ++ ++ /* We must disable setgroups () before we can map our groups, else we ++ get EPERM. */ ++ GMAP = open ("/proc/self/setgroups", O_WRONLY); ++ if (GMAP >= 0) ++ { ++ /* We support kernels old enough to not have this. */ ++ write (GMAP, "deny\n", 5); ++ xclose (GMAP); ++ } ++ ++ /* We map our original GID to the same GID in the container so we ++ can own our own files normally. */ ++ GMAP = open ("/proc/self/gid_map", O_WRONLY); ++ if (GMAP < 0) ++ FAIL_EXIT1 ("can't write to /proc/self/gid_map\n"); + -+/* Create a temporary file. Return the opened file descriptor on -+ success, or -1 on failure. Write the file name to *FILENAME if -+ FILENAME is not NULL. In this case, the caller is expected to free -+ *FILENAME. */ -+int create_temp_file (const char *base, char **filename); ++ sprintf (tmp, "%lld %lld 1\n", ++ (long long) original_gid, (long long) original_gid); ++ write (GMAP, tmp, strlen (tmp)); ++ xclose (GMAP); + -+/* Create a temporary directory and schedule it for deletion. BASE is -+ used as a prefix for the unique directory name, which the function -+ returns. The caller should free this string. */ -+char *support_create_temp_directory (const char *base); ++ /* Now run the child. */ ++ execvp (new_child_proc[0], new_child_proc); + -+__END_DECLS ++ /* Or don't run the child? */ ++ FAIL_EXIT1 ("Unable to exec %s\n", new_child_proc[0]); + -+#endif /* SUPPORT_TEMP_FILE_H */ ++ /* Because gcc won't know error () never returns... */ ++ exit (EXIT_UNSUPPORTED); ++} diff --git a/support/test-driver.c b/support/test-driver.c new file mode 100644 -index 0000000000..09c8783e4f +index 0000000000..9798f16227 --- /dev/null +++ b/support/test-driver.c -@@ -0,0 +1,165 @@ +@@ -0,0 +1,169 @@ +/* Main function for test programs. + Copyright (C) 2016-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. @@ -5571,6 +8200,10 @@ index 0000000000..09c8783e4f + test_config.no_mallopt = 1; +#endif + ++#ifdef TEST_NO_SETVBUF ++ test_config.no_setvbuf = 1; ++#endif ++ +#ifdef TIMEOUT + test_config.timeout = TIMEOUT; +#endif @@ -5596,10 +8229,10 @@ index 0000000000..09c8783e4f +} diff --git a/support/test-driver.h b/support/test-driver.h new file mode 100644 -index 0000000000..1708d68d60 +index 0000000000..549179b254 --- /dev/null +++ b/support/test-driver.h -@@ -0,0 +1,75 @@ +@@ -0,0 +1,76 @@ +/* Interfaces for the test driver. + Copyright (C) 2016-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. @@ -5637,6 +8270,7 @@ index 0000000000..1708d68d60 + int expected_status; /* Expected exit status. */ + int expected_signal; /* If non-zero, expect termination by signal. */ + char no_mallopt; /* Boolean flag to disable mallopt. */ ++ char no_setvbuf; /* Boolean flag to disable setvbuf. */ + const char *optstring; /* Short command line options. */ +}; + @@ -5675,6 +8309,38 @@ index 0000000000..1708d68d60 +__END_DECLS + +#endif /* SUPPORT_TEST_DRIVER_H */ +diff --git a/support/true-container.c b/support/true-container.c +new file mode 100644 +index 0000000000..57dc57e252 +--- /dev/null ++++ b/support/true-container.c +@@ -0,0 +1,26 @@ ++/* Minimal /bin/true 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 ++ . */ ++ ++/* Implements the in-container /bin/true, which always returns true ++ (0). */ ++ ++int ++main (void) ++{ ++ return 0; ++} diff --git a/support/tst-support-namespace.c b/support/tst-support-namespace.c new file mode 100644 index 0000000000..e20423c4a3 @@ -5795,6 +8461,97 @@ index 0000000000..e20423c4a3 +} + +#include +diff --git a/support/tst-support_blob_repeat.c b/support/tst-support_blob_repeat.c +new file mode 100644 +index 0000000000..1978c14488 +--- /dev/null ++++ b/support/tst-support_blob_repeat.c +@@ -0,0 +1,85 @@ ++/* Tests for ++ 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 ++ . */ ++ ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ struct support_blob_repeat repeat ++ = support_blob_repeat_allocate ("5", 1, 5); ++ TEST_COMPARE_BLOB (repeat.start, repeat.size, "55555", 5); ++ support_blob_repeat_free (&repeat); ++ ++ repeat = support_blob_repeat_allocate ("ABC", 3, 3); ++ TEST_COMPARE_BLOB (repeat.start, repeat.size, "ABCABCABC", 9); ++ support_blob_repeat_free (&repeat); ++ ++ repeat = support_blob_repeat_allocate ("abc", 4, 3); ++ TEST_COMPARE_BLOB (repeat.start, repeat.size, "abc\0abc\0abc", 12); ++ support_blob_repeat_free (&repeat); ++ ++ size_t gigabyte = 1U << 30; ++ repeat = support_blob_repeat_allocate ("X", 1, gigabyte + 1); ++ if (repeat.start == NULL) ++ puts ("warning: not enough memory for 1 GiB mapping"); ++ else ++ { ++ TEST_COMPARE (repeat.size, gigabyte + 1); ++ { ++ unsigned char *p = repeat.start; ++ for (size_t i = 0; i < gigabyte + 1; ++i) ++ if (p[i] != 'X') ++ FAIL_EXIT1 ("invalid byte 0x%02x at %zu", p[i], i); ++ ++ /* Check that there is no sharing across the mapping. */ ++ p[0] = 'Y'; ++ p[1U << 24] = 'Z'; ++ for (size_t i = 0; i < gigabyte + 1; ++i) ++ if (i == 0) ++ TEST_COMPARE (p[i], 'Y'); ++ else if (i == 1U << 24) ++ TEST_COMPARE (p[i], 'Z'); ++ else if (p[i] != 'X') ++ FAIL_EXIT1 ("invalid byte 0x%02x at %zu", p[i], i); ++ } ++ } ++ support_blob_repeat_free (&repeat); ++ ++ repeat = support_blob_repeat_allocate ("012345678", 9, 10 * 1000 * 1000); ++ if (repeat.start == NULL) ++ puts ("warning: not enough memory for large mapping"); ++ else ++ { ++ unsigned char *p = repeat.start; ++ for (int i = 0; i < 10 * 1000 * 1000; ++i) ++ for (int j = 0; j <= 8; ++j) ++ if (p[i * 9 + j] != '0' + j) ++ { ++ printf ("error: element %d index %d\n", i, j); ++ TEST_COMPARE (p[i * 9 + j], '0' + j); ++ } ++ } ++ support_blob_repeat_free (&repeat); ++ ++ return 0; ++} ++ ++#include diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c new file mode 100644 index 0000000000..a685256091 @@ -6096,6 +8853,73 @@ index 0000000000..b1135eebc6 +} + +#include +diff --git a/support/tst-support_quote_blob.c b/support/tst-support_quote_blob.c +new file mode 100644 +index 0000000000..5467a190a6 +--- /dev/null ++++ b/support/tst-support_quote_blob.c +@@ -0,0 +1,61 @@ ++/* Test the support_quote_blob function. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* Check handling of the empty blob, both with and without trailing ++ NUL byte. */ ++ char *p = support_quote_blob ("", 0); ++ TEST_COMPARE (strlen (p), 0); ++ free (p); ++ p = support_quote_blob ("X", 0); ++ TEST_COMPARE (strlen (p), 0); ++ free (p); ++ ++ /* Check escaping of backslash-escaped characters, and lack of ++ escaping for other shell meta-characters. */ ++ p = support_quote_blob ("$()*?`@[]{}~\'\"X", 14); ++ TEST_COMPARE (strcmp (p, "$()*?`@[]{}~\\'\\\""), 0); ++ free (p); ++ ++ /* Check lack of escaping for letters and digits. */ ++#define LETTERS_AND_DIGTS \ ++ "abcdefghijklmnopqrstuvwxyz" \ ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ ++ "0123456789" ++ p = support_quote_blob (LETTERS_AND_DIGTS "@", 2 * 26 + 10); ++ TEST_COMPARE (strcmp (p, LETTERS_AND_DIGTS), 0); ++ free (p); ++ ++ /* Check escaping of control characters and other non-printable ++ characters. */ ++ p = support_quote_blob ("\r\n\t\a\b\f\v\1\177\200\377\0@", 14); ++ TEST_COMPARE (strcmp (p, "\\r\\n\\t\\a\\b\\f\\v\\001" ++ "\\177\\200\\377\\000@\\000"), 0); ++ free (p); ++ ++ return 0; ++} ++ ++#include diff --git a/support/tst-support_record_failure-2.sh b/support/tst-support_record_failure-2.sh new file mode 100644 index 0000000000..09cd96290a @@ -6380,47 +9204,264 @@ index 0000000000..123ba1bc3c + unsigned long long int u63 : 63; +}; + -+/* Functions which return signed sizes are common, so test that these -+ results can readily checked using TEST_COMPARE. */ ++/* Functions which return signed sizes are common, so test that these ++ results can readily checked using TEST_COMPARE. */ ++ ++static int ++return_ssize_t (void) ++{ ++ return 4; ++} ++ ++static int ++return_int (void) ++{ ++ return 4; ++} ++ ++ ++static int ++do_test (void) ++{ ++ /* This should succeed. */ ++ TEST_COMPARE (1, 1); ++ TEST_COMPARE (2LL, 2U); ++ { ++ char i8 = 3; ++ unsigned short u16 = 3; ++ TEST_COMPARE (i8, u16); ++ } ++ TEST_COMPARE (return_ssize_t (), sizeof (char[4])); ++ TEST_COMPARE (return_int (), sizeof (char[4])); ++ ++ struct bitfield bitfield = { 0 }; ++ TEST_COMPARE (bitfield.i2, bitfield.i3); ++ TEST_COMPARE (bitfield.u2, bitfield.u3); ++ TEST_COMPARE (bitfield.u2, bitfield.i3); ++ TEST_COMPARE (bitfield.u3, bitfield.i3); ++ TEST_COMPARE (bitfield.i2, bitfield.u3); ++ TEST_COMPARE (bitfield.i3, bitfield.u2); ++ TEST_COMPARE (bitfield.i63, bitfield.i63); ++ TEST_COMPARE (bitfield.u63, bitfield.u63); ++ TEST_COMPARE (bitfield.i31, bitfield.i63); ++ TEST_COMPARE (bitfield.i63, bitfield.i31); ++ ++ struct support_capture_subprocess proc = support_capture_subprocess ++ (&subprocess, NULL); ++ ++ /* Discard the reported error. */ ++ support_record_failure_reset (); ++ ++ puts ("info: *** subprocess output starts ***"); ++ fputs (proc.out.buffer, stdout); ++ puts ("info: *** subprocess output ends ***"); ++ ++ TEST_VERIFY ++ (strcmp (proc.out.buffer, ++ "tst-test_compare.c:28: numeric comparison failure\n" ++ " left: 1 (0x1); from: ch\n" ++ " right: -1 (0xffffffff); from: -1\n" ++ "tst-test_compare.c:29: numeric comparison failure\n" ++ " left: 2 (0x2); from: 2LL\n" ++ " right: -2 (0xfffffffffffffffe); from: -2LL\n" ++ "tst-test_compare.c:30: numeric comparison failure" ++ " (widths 64 and 32)\n" ++ " left: 3 (0x3); from: 3LL\n" ++ " right: -3 (0xfffffffd); from: (short) -3\n") == 0); ++ ++ /* Check that there is no output on standard error. */ ++ support_capture_subprocess_check (&proc, "TEST_COMPARE", 0, sc_allow_stdout); ++ ++ return 0; ++} ++ ++#include +diff --git a/support/tst-test_compare_blob.c b/support/tst-test_compare_blob.c +new file mode 100644 +index 0000000000..aa8643e182 +--- /dev/null ++++ b/support/tst-test_compare_blob.c +@@ -0,0 +1,125 @@ ++/* Basic test for the TEST_COMPARE_BLOB macro. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++ ++static void ++subprocess (void *closure) ++{ ++ /* These tests should fail. They were chosen to cover differences ++ in length (with the same contents), single-bit mismatches, and ++ mismatching null pointers. */ ++ TEST_COMPARE_BLOB ("", 0, "", 1); /* Line 29. */ ++ TEST_COMPARE_BLOB ("X", 1, "", 1); /* Line 30. */ ++ TEST_COMPARE_BLOB ("abcd", 3, "abcd", 4); /* Line 31. */ ++ TEST_COMPARE_BLOB ("abcd", 4, "abcD", 4); /* Line 32. */ ++ TEST_COMPARE_BLOB ("abcd", 4, NULL, 0); /* Line 33. */ ++ TEST_COMPARE_BLOB (NULL, 0, "abcd", 4); /* Line 34. */ ++} ++ ++/* Same contents, different addresses. */ ++char buffer_abc_1[] = "abc"; ++char buffer_abc_2[] = "abc"; ++ ++static int ++do_test (void) ++{ ++ /* This should succeed. Even if the pointers and array contents are ++ different, zero-length inputs are not different. */ ++ TEST_COMPARE_BLOB ("", 0, "", 0); ++ TEST_COMPARE_BLOB ("", 0, buffer_abc_1, 0); ++ TEST_COMPARE_BLOB (buffer_abc_1, 0, "", 0); ++ TEST_COMPARE_BLOB (NULL, 0, "", 0); ++ TEST_COMPARE_BLOB ("", 0, NULL, 0); ++ TEST_COMPARE_BLOB (NULL, 0, NULL, 0); ++ ++ /* Check equality of blobs containing a single NUL byte. */ ++ TEST_COMPARE_BLOB ("", 1, "", 1); ++ TEST_COMPARE_BLOB ("", 1, &buffer_abc_1[3], 1); ++ ++ /* Check equality of blobs of varying lengths. */ ++ for (size_t i = 0; i <= sizeof (buffer_abc_1); ++i) ++ TEST_COMPARE_BLOB (buffer_abc_1, i, buffer_abc_2, i); ++ ++ struct support_capture_subprocess proc = support_capture_subprocess ++ (&subprocess, NULL); ++ ++ /* Discard the reported error. */ ++ support_record_failure_reset (); ++ ++ puts ("info: *** subprocess output starts ***"); ++ fputs (proc.out.buffer, stdout); ++ puts ("info: *** subprocess output ends ***"); ++ ++ TEST_VERIFY ++ (strcmp (proc.out.buffer, ++"tst-test_compare_blob.c:29: error: blob comparison failed\n" ++" left length: 0 bytes (from 0)\n" ++" right length: 1 bytes (from 1)\n" ++" right (evaluated from \"\"):\n" ++" \"\\000\"\n" ++" 00\n" ++"tst-test_compare_blob.c:30: error: blob comparison failed\n" ++" blob length: 1 bytes\n" ++" left (evaluated from \"X\"):\n" ++" \"X\"\n" ++" 58\n" ++" right (evaluated from \"\"):\n" ++" \"\\000\"\n" ++" 00\n" ++"tst-test_compare_blob.c:31: error: blob comparison failed\n" ++" left length: 3 bytes (from 3)\n" ++" right length: 4 bytes (from 4)\n" ++" left (evaluated from \"abcd\"):\n" ++" \"abc\"\n" ++" 61 62 63\n" ++" right (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++"tst-test_compare_blob.c:32: error: blob comparison failed\n" ++" blob length: 4 bytes\n" ++" left (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++" right (evaluated from \"abcD\"):\n" ++" \"abcD\"\n" ++" 61 62 63 44\n" ++"tst-test_compare_blob.c:33: error: blob comparison failed\n" ++" left length: 4 bytes (from 4)\n" ++" right length: 0 bytes (from 0)\n" ++" left (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++"tst-test_compare_blob.c:34: error: blob comparison failed\n" ++" left length: 0 bytes (from 0)\n" ++" right length: 4 bytes (from 4)\n" ++" right (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++ ) == 0); ++ ++ /* Check that there is no output on standard error. */ ++ support_capture_subprocess_check (&proc, "TEST_COMPARE_BLOB", ++ 0, sc_allow_stdout); ++ ++ return 0; ++} ++ ++#include +diff --git a/support/tst-test_compare_string.c b/support/tst-test_compare_string.c +new file mode 100644 +index 0000000000..2a4b258587 +--- /dev/null ++++ b/support/tst-test_compare_string.c +@@ -0,0 +1,107 @@ ++/* Basic test for the TEST_COMPARE_STRING macro. ++ 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 ++ . */ + -+static int -+return_ssize_t (void) -+{ -+ return 4; -+} ++#include ++#include ++#include + -+static int -+return_int (void) ++static void ++subprocess (void *closure) +{ -+ return 4; ++ /* These tests should fail. They were chosen to cover differences ++ in length (with the same contents), single-bit mismatches, and ++ mismatching null pointers. */ ++ TEST_COMPARE_STRING ("", NULL); /* Line 29. */ ++ TEST_COMPARE_STRING ("X", ""); /* Line 30. */ ++ TEST_COMPARE_STRING (NULL, "X"); /* Line 31. */ ++ TEST_COMPARE_STRING ("abcd", "abcD"); /* Line 32. */ ++ TEST_COMPARE_STRING ("abcd", NULL); /* Line 33. */ ++ TEST_COMPARE_STRING (NULL, "abcd"); /* Line 34. */ +} + ++/* Same contents, different addresses. */ ++char buffer_abc_1[] = "abc"; ++char buffer_abc_2[] = "abc"; + +static int +do_test (void) +{ -+ /* This should succeed. */ -+ TEST_COMPARE (1, 1); -+ TEST_COMPARE (2LL, 2U); -+ { -+ char i8 = 3; -+ unsigned short u16 = 3; -+ TEST_COMPARE (i8, u16); -+ } -+ TEST_COMPARE (return_ssize_t (), sizeof (char[4])); -+ TEST_COMPARE (return_int (), sizeof (char[4])); -+ -+ struct bitfield bitfield = { 0 }; -+ TEST_COMPARE (bitfield.i2, bitfield.i3); -+ TEST_COMPARE (bitfield.u2, bitfield.u3); -+ TEST_COMPARE (bitfield.u2, bitfield.i3); -+ TEST_COMPARE (bitfield.u3, bitfield.i3); -+ TEST_COMPARE (bitfield.i2, bitfield.u3); -+ TEST_COMPARE (bitfield.i3, bitfield.u2); -+ TEST_COMPARE (bitfield.i63, bitfield.i63); -+ TEST_COMPARE (bitfield.u63, bitfield.u63); -+ TEST_COMPARE (bitfield.i31, bitfield.i63); -+ TEST_COMPARE (bitfield.i63, bitfield.i31); ++ /* This should succeed. Even if the pointers and array contents are ++ different, zero-length inputs are not different. */ ++ TEST_COMPARE_STRING (NULL, NULL); ++ TEST_COMPARE_STRING ("", ""); ++ TEST_COMPARE_STRING (buffer_abc_1, buffer_abc_2); ++ TEST_COMPARE_STRING (buffer_abc_1, "abc"); + + struct support_capture_subprocess proc = support_capture_subprocess + (&subprocess, NULL); @@ -6434,19 +9475,46 @@ index 0000000000..123ba1bc3c + + TEST_VERIFY + (strcmp (proc.out.buffer, -+ "tst-test_compare.c:28: numeric comparison failure\n" -+ " left: 1 (0x1); from: ch\n" -+ " right: -1 (0xffffffff); from: -1\n" -+ "tst-test_compare.c:29: numeric comparison failure\n" -+ " left: 2 (0x2); from: 2LL\n" -+ " right: -2 (0xfffffffffffffffe); from: -2LL\n" -+ "tst-test_compare.c:30: numeric comparison failure" -+ " (widths 64 and 32)\n" -+ " left: 3 (0x3); from: 3LL\n" -+ " right: -3 (0xfffffffd); from: (short) -3\n") == 0); ++"tst-test_compare_string.c:29: error: blob comparison failed\n" ++" left string: 0 bytes\n" ++" right string: NULL\n" ++"tst-test_compare_string.c:30: error: blob comparison failed\n" ++" left string: 1 bytes\n" ++" right string: 0 bytes\n" ++" left (evaluated from \"X\"):\n" ++" \"X\"\n" ++" 58\n" ++"tst-test_compare_string.c:31: error: blob comparison failed\n" ++" left string: NULL\n" ++" right string: 1 bytes\n" ++" right (evaluated from \"X\"):\n" ++" \"X\"\n" ++" 58\n" ++"tst-test_compare_string.c:32: error: blob comparison failed\n" ++" string length: 4 bytes\n" ++" left (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++" right (evaluated from \"abcD\"):\n" ++" \"abcD\"\n" ++" 61 62 63 44\n" ++"tst-test_compare_string.c:33: error: blob comparison failed\n" ++" left string: 4 bytes\n" ++" right string: NULL\n" ++" left (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++"tst-test_compare_string.c:34: error: blob comparison failed\n" ++" left string: NULL\n" ++" right string: 4 bytes\n" ++" right (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++ ) == 0); + + /* Check that there is no output on standard error. */ -+ support_capture_subprocess_check (&proc, "TEST_COMPARE", 0, sc_allow_stdout); ++ support_capture_subprocess_check (&proc, "TEST_COMPARE_STRING", ++ 0, sc_allow_stdout); + + return 0; +} @@ -6530,12 +9598,63 @@ index 0000000000..b142207228 +} + +#include +diff --git a/support/tty.h b/support/tty.h +new file mode 100644 +index 0000000000..1d37c42279 +--- /dev/null ++++ b/support/tty.h +@@ -0,0 +1,45 @@ ++/* Support functions related to (pseudo)terminals. ++ 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 ++ . */ ++ ++#ifndef _SUPPORT_TTY_H ++#define _SUPPORT_TTY_H 1 ++ ++struct termios; ++struct winsize; ++ ++/** Open a pseudoterminal pair. The outer fd is written to the address ++ A_OUTER and the inner fd to A_INNER. ++ ++ If A_NAME is not NULL, it will be set to point to a string naming ++ the /dev/pts/NNN device corresponding to the inner fd; space for ++ this string is allocated with malloc and should be freed by the ++ caller when no longer needed. (This is different from the libutil ++ function 'openpty'.) ++ ++ If TERMP is not NULL, the terminal parameters will be initialized ++ according to the termios structure it points to. ++ ++ If WINP is not NULL, the terminal window size will be set ++ accordingly. ++ ++ Terminates the process on failure (like xmalloc). */ ++extern void support_openpty (int *a_outer, int *a_inner, char **a_name, ++ const struct termios *termp, ++ const struct winsize *winp); ++ ++#endif diff --git a/support/write_message.c b/support/write_message.c new file mode 100644 -index 0000000000..9d0f267a2f +index 0000000000..a3e2f90535 --- /dev/null +++ b/support/write_message.c -@@ -0,0 +1,29 @@ +@@ -0,0 +1,32 @@ +/* Write a message to standard output. + Copyright (C) 2016-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. @@ -6556,14 +9675,17 @@ index 0000000000..9d0f267a2f + +#include + ++#include +#include +#include + +void +write_message (const char *message) +{ ++ int saved_errno = errno; + ssize_t unused __attribute__ ((unused)); + unused = write (STDOUT_FILENO, message, strlen (message)); ++ errno = saved_errno; +} diff --git a/support/xaccept.c b/support/xaccept.c new file mode 100644 @@ -6863,6 +9985,44 @@ index 0000000000..341805d80d + if (connect (fd, sa, sa_len) != 0) + FAIL_EXIT1 ("connect (%d), family %d: %m", fd, sa->sa_family); +} +diff --git a/support/xcopy_file_range.c b/support/xcopy_file_range.c +new file mode 100644 +index 0000000000..b3501a4d5e +--- /dev/null ++++ b/support/xcopy_file_range.c +@@ -0,0 +1,32 @@ ++/* copy_file_range with error checking. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++ ++ssize_t ++xcopy_file_range (int infd, off64_t *pinoff, int outfd, off64_t *poutoff, ++ size_t length, unsigned int flags) ++{ ++ ssize_t status = support_copy_file_range (infd, pinoff, outfd, ++ poutoff, length, flags); ++ if (status == -1) ++ FAIL_EXIT1 ("cannot copy file: %m\n"); ++ return status; ++} diff --git a/support/xdlfcn.c b/support/xdlfcn.c new file mode 100644 index 0000000000..f34bb059c0 @@ -7433,6 +10593,78 @@ index 0000000000..7e67f783de + if (mkdir (path, mode) != 0) + FAIL_EXIT1 ("mkdir (\"%s\", 0%o): %m", path, mode); +} +diff --git a/support/xmkdirp.c b/support/xmkdirp.c +new file mode 100644 +index 0000000000..fada0452ea +--- /dev/null ++++ b/support/xmkdirp.c +@@ -0,0 +1,66 @@ ++/* Error-checking replacement for "mkdir -p". ++ 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 ++ . */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* Equivalent of "mkdir -p". Any failures cause FAIL_EXIT1 so no ++ return code is needed. */ ++ ++void ++xmkdirp (const char *path, mode_t mode) ++{ ++ struct stat s; ++ const char *slash_p; ++ int rv; ++ ++ if (path[0] == 0) ++ return; ++ ++ if (stat (path, &s) == 0) ++ { ++ if (S_ISDIR (s.st_mode)) ++ return; ++ errno = EEXIST; ++ FAIL_EXIT1 ("mkdir_p (\"%s\", 0%o): %m", path, mode); ++ } ++ ++ slash_p = strrchr (path, '/'); ++ if (slash_p != NULL) ++ { ++ while (slash_p > path && slash_p[-1] == '/') ++ --slash_p; ++ if (slash_p > path) ++ { ++ char *parent = xstrndup (path, slash_p - path); ++ xmkdirp (parent, mode); ++ free (parent); ++ } ++ } ++ ++ rv = mkdir (path, mode); ++ if (rv != 0) ++ FAIL_EXIT1 ("mkdir_p (\"%s\", 0%o): %m", path, mode); ++ ++ return; ++} diff --git a/support/xmmap.c b/support/xmmap.c new file mode 100644 index 0000000000..d580c07013 @@ -7905,6 +11137,102 @@ index 0000000000..61690c5e7c + xpthread_check_return ("pthread_barrier_wait", ret); + return ret == PTHREAD_BARRIER_SERIAL_THREAD; +} +diff --git a/support/xpthread_barrierattr_destroy.c b/support/xpthread_barrierattr_destroy.c +new file mode 100644 +index 0000000000..3e471f9a81 +--- /dev/null ++++ b/support/xpthread_barrierattr_destroy.c +@@ -0,0 +1,26 @@ ++/* pthread_barrierattr_destroy with error checking. ++ 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 ++ . */ ++ ++#include ++ ++void ++xpthread_barrierattr_destroy (pthread_barrierattr_t *attr) ++{ ++ xpthread_check_return ("pthread_barrierattr_destroy", ++ pthread_barrierattr_destroy (attr)); ++} +diff --git a/support/xpthread_barrierattr_init.c b/support/xpthread_barrierattr_init.c +new file mode 100644 +index 0000000000..4ee14e78f3 +--- /dev/null ++++ b/support/xpthread_barrierattr_init.c +@@ -0,0 +1,26 @@ ++/* pthread_barrierattr_init with error checking. ++ 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 ++ . */ ++ ++#include ++ ++void ++xpthread_barrierattr_init (pthread_barrierattr_t *attr) ++{ ++ xpthread_check_return ("pthread_barrierattr_init", ++ pthread_barrierattr_init (attr)); ++} +diff --git a/support/xpthread_barrierattr_setpshared.c b/support/xpthread_barrierattr_setpshared.c +new file mode 100644 +index 0000000000..90b2c5bec6 +--- /dev/null ++++ b/support/xpthread_barrierattr_setpshared.c +@@ -0,0 +1,26 @@ ++/* pthread_barrierattr_setpshared with error checking. ++ 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 ++ . */ ++ ++#include ++ ++void ++xpthread_barrierattr_setpshared (pthread_barrierattr_t *attr, int pshared) ++{ ++ xpthread_check_return ("pthread_barrierattr_setpshared", ++ pthread_barrierattr_setpshared (attr, pshared)); ++} diff --git a/support/xpthread_cancel.c b/support/xpthread_cancel.c new file mode 100644 index 0000000000..26e864ea3e @@ -9330,6 +12658,41 @@ index 0000000000..e85fddd439 + oom_error ("strndup", length); + return p; +} +diff --git a/support/xsymlink.c b/support/xsymlink.c +new file mode 100644 +index 0000000000..0f3edf640a +--- /dev/null ++++ b/support/xsymlink.c +@@ -0,0 +1,29 @@ ++/* Error-checking replacement for "symlink". ++ 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 ++ . */ ++ ++#include ++#include ++ ++#include ++ ++void ++xsymlink (const char *target, const char *linkpath) ++{ ++ if (symlink (target, linkpath) < 0) ++ FAIL_EXIT1 ("symlink (\"%s\", \"%s\")", target, linkpath); ++} diff --git a/support/xsysconf.c b/support/xsysconf.c new file mode 100644 index 0000000000..afefc2d098 @@ -9374,10 +12737,10 @@ index 0000000000..afefc2d098 +} diff --git a/support/xthread.h b/support/xthread.h new file mode 100644 -index 0000000000..79358e7c99 +index 0000000000..623f5ad0ac --- /dev/null +++ b/support/xthread.h -@@ -0,0 +1,87 @@ +@@ -0,0 +1,90 @@ +/* Support functionality for using threads. + Copyright (C) 2016-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. @@ -9421,6 +12784,9 @@ index 0000000000..79358e7c99 +void xpthread_barrier_init (pthread_barrier_t *barrier, + pthread_barrierattr_t *attr, unsigned int count); +void xpthread_barrier_destroy (pthread_barrier_t *barrier); ++void xpthread_barrierattr_destroy (pthread_barrierattr_t *); ++void xpthread_barrierattr_init (pthread_barrierattr_t *); ++void xpthread_barrierattr_setpshared (pthread_barrierattr_t *, int pshared); +void xpthread_mutexattr_destroy (pthread_mutexattr_t *); +void xpthread_mutexattr_init (pthread_mutexattr_t *); +void xpthread_mutexattr_setprotocol (pthread_mutexattr_t *, int); @@ -9467,10 +12833,10 @@ index 0000000000..79358e7c99 +#endif /* SUPPORT_THREAD_H */ diff --git a/support/xunistd.h b/support/xunistd.h new file mode 100644 -index 0000000000..5fe5dae818 +index 0000000000..f99f362cb4 --- /dev/null +++ b/support/xunistd.h -@@ -0,0 +1,65 @@ +@@ -0,0 +1,72 @@ +/* POSIX-specific extra functions. + Copyright (C) 2016-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. @@ -9516,6 +12882,10 @@ index 0000000000..5fe5dae818 +long xsysconf (int name); +long long xlseek (int fd, long long offset, int whence); +void xftruncate (int fd, long long length); ++void xsymlink (const char *target, const char *linkpath); ++ ++/* Equivalent of "mkdir -p". */ ++void xmkdirp (const char *, mode_t); + +/* Read the link at PATH. The caller should free the returned string + with free. */ @@ -9533,6 +12903,9 @@ index 0000000000..5fe5dae818 +void xmprotect (void *addr, size_t length, int prot); +void xmunmap (void *addr, size_t length); + ++ssize_t xcopy_file_range(int fd_in, loff_t *off_in, int fd_out, ++ loff_t *off_out, size_t len, unsigned int flags); ++ +__END_DECLS + +#endif /* SUPPORT_XUNISTD_H */ diff --git a/SOURCES/glibc-rh1439165-syscall-names.patch b/SOURCES/glibc-rh1439165-syscall-names.patch index 247e3f26..6bc2372a 100644 --- a/SOURCES/glibc-rh1439165-syscall-names.patch +++ b/SOURCES/glibc-rh1439165-syscall-names.patch @@ -1,5 +1,6 @@ This patch contains the sysdeps/unix/sysv/linux/syscall-names.list file -from upstream and is continuously updated for new kernel versions. +from upstream for Linux 4.13, and forms the baseline, subsequent changes +are cherry picked from upstream. diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list new file mode 100644 diff --git a/SOURCES/glibc-rh1439165.patch b/SOURCES/glibc-rh1439165.patch index bb2ee651..624d4483 100644 --- a/SOURCES/glibc-rh1439165.patch +++ b/SOURCES/glibc-rh1439165.patch @@ -3,8 +3,8 @@ Posted upstream at: https://sourceware.org/ml/libc-alpha/2017-04/msg00082.html sysdeps/unix/sysv/linux/syscall-names.list is stored as a separate patch -(glibc-rh1439165-syscall-names.patch) in the source RPM for easier -updates. +(glibc-rh1439165-syscall-names.patch) in the source RPM, and is the +baseline for subsequent changes. Author: Florian Weimer diff --git a/SOURCES/glibc-rh1457479-3.patch b/SOURCES/glibc-rh1457479-3.patch index bb86e24e..e8710fd7 100644 --- a/SOURCES/glibc-rh1457479-3.patch +++ b/SOURCES/glibc-rh1457479-3.patch @@ -1,3 +1,7 @@ +Note; the test is known to fail on the RHEL 7.7 kernel - the patch +fixes PT_GETREGS (which we want) but adds PTRACE_SINGLEBLOCK (which we +don't support yet). So, the test case was not included. - DJ + commit b08a6a0dea63742313ed3d9577c1e2d83436b196 Author: Stefan Liebler Date: Mon Jun 19 16:27:25 2017 +0200 diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec index f2ad1044..608aae61 100644 --- a/SPECS/glibc.spec +++ b/SPECS/glibc.spec @@ -1,6 +1,6 @@ %define glibcsrcdir glibc-2.17-c758a686 %define glibcversion 2.17 -%define glibcrelease 260%{?dist} +%define glibcrelease 317%{?dist} ############################################################################## # We support the following options: # --with/--without, @@ -264,6 +264,10 @@ Patch0069: glibc-rh1448107.patch # ############################################################################## +# Armhfp build issue +Patch9998: glibc-armhfp-ELF_MACHINE_NO_REL-undefined.patch +Patch9999: glibc-rh1256317-armhfp-build-issue.patch + Patch1000: glibc-rh905877.patch Patch1001: glibc-rh958652.patch Patch1002: glibc-rh977870.patch @@ -937,6 +941,7 @@ Patch1757: glibc-rh1337242.patch Patch17580: glibc-rh1418978-max_align_t.patch Patch1758: glibc-rh1418978-0.patch Patch1759: glibc-rh1418978-1.patch +Patch2752: glibc-rh1418978-1a.patch Patch1760: glibc-rh1418978-2-1.patch Patch1761: glibc-rh1418978-2-2.patch Patch1762: glibc-rh1418978-2-3.patch @@ -1154,11 +1159,14 @@ Patch1899: glibc-rh1527904-4.patch # RHBZ #1534635: CVE-2018-1000001 glibc: realpath() buffer underflow. Patch1900: glibc-rh1534635.patch - # RHBZ #1529982: recompile glibc to fix incorrect CFI information on i386. Patch1901: glibc-rh1529982.patch - Patch1902: glibc-rh1523119-compat-symbols.patch +# RHBZ #1609067: Backfort of upstream [#15804] - fix race condition in pldd +Patch1903: glibc-rh1609067.patch +# RHBZ #1672771: +Patch1904: glibc-rh1672771.patch + Patch2500: glibc-rh1505492-nscd_stat.patch Patch2501: glibc-rh1564638.patch Patch2502: glibc-rh1566623.patch @@ -1418,6 +1426,108 @@ Patch2749: glibc-rh1401665-3.patch Patch2750: glibc-rh1401665-4.patch Patch2751: glibc-rh1401665-5.patch +Patch2753: glibc-rh1595191-1.patch +Patch2754: glibc-rh1595191-2.patch +Patch2755: glibc-rh1595191-3.patch +Patch2756: glibc-rh1595191-4.patch +Patch2757: glibc-rh1647490-1.patch +Patch2758: glibc-rh1647490-2.patch +Patch2759: glibc-rh1647490-3.patch +Patch2760: glibc-rh1647490-4.patch +Patch2761: glibc-rh1647490-5.patch +Patch2762: glibc-rh1639524.patch +Patch2763: glibc-rh1647490-6.patch +Patch2764: glibc-rh1579730-1.patch +Patch2765: glibc-rh1579730-2.patch +Patch2766: glibc-rh1579730-3.patch +Patch2767: glibc-rh1630440-1.patch +Patch2768: glibc-rh1630440-2.patch +Patch2769: glibc-rh1646373.patch +Patch2770: glibc-rh1591268.patch +Patch2771: glibc-rh1592475-1.patch +Patch2772: glibc-rh1592475-2.patch +Patch2773: glibc-rh1592475-3.patch +Patch2774: glibc-rh1657015-1.patch +Patch2775: glibc-rh1657015-2.patch +Patch2776: glibc-rh1657015-3.patch +Patch2777: glibc-rh1657015-4.patch +Patch2778: glibc-rh1673465-1.patch +Patch2779: glibc-rh1673465-2.patch +Patch2780: glibc-rh1673465-3.patch +Patch2781: glibc-rh1673465-4.patch +Patch2782: glibc-rh1673465-5.patch +Patch2783: glibc-rh1673465-6.patch +Patch2784: glibc-rh1673465-7.patch +Patch2785: glibc-rh1039304-1.patch +Patch2786: glibc-rh1039304-2.patch +Patch2787: glibc-rh1039304-3.patch +Patch2788: glibc-rh1039304-4.patch +Patch2789: glibc-rh1443872.patch +Patch2790: glibc-rh1472832.patch +Patch2791: glibc-rh1673465-8.patch +Patch2792: glibc-rh1443872-2.patch +Patch2793: glibc-rh1579354.patch +Patch2794: glibc-rh1579739.patch +Patch2795: glibc-rh1641981.patch +Patch2796: glibc-rh1579739-2.patch +Patch2797: glibc-rh1684874-1.patch +Patch2798: glibc-rh1684874-2.patch +Patch2799: glibc-rh1488370.patch +Patch2800: glibc-rh1662842.patch +Patch2801: glibc-rh1163509-1.patch +Patch2802: glibc-rh1163509-2.patch +Patch2803: glibc-rh1163509-3.patch +Patch2804: glibc-rh1163509-4.patch +Patch2805: glibc-rh1163509-5.patch +Patch2806: glibc-rh1555189-1.patch +Patch2807: glibc-rh1555189-2.patch +Patch2808: glibc-rh1427734-1.patch +Patch2809: glibc-rh1427734-2.patch +Patch2810: glibc-rh1414263.patch +Patch2811: glibc-rh1406732-1.patch +Patch2812: glibc-rh1406732-2.patch +Patch2813: glibc-rh1406732-3.patch +Patch2814: glibc-rh1406732-4.patch +Patch2815: glibc-rh1406732-5.patch +Patch2816: glibc-rh1670041.patch +Patch2817: glibc-rh1451308.patch +Patch2818: glibc-rh1636229-1.patch +Patch2819: glibc-rh1636229-2.patch +Patch2820: glibc-rh1636229-3.patch +Patch2821: glibc-rh1636229-4.patch +Patch2822: glibc-rh1579451.patch +Patch2823: glibc-rh1634021.patch +Patch2824: glibc-rh1691534-1.patch +Patch2825: glibc-rh1691534-2.patch +Patch2826: glibc-rh1698015.patch +Patch2827: glibc-rh1065574-1.patch +Patch2828: glibc-rh1065574-2.patch +Patch2829: glibc-rh1065574-3.patch +Patch2830: glibc-rh1065574-4.patch +Patch2831: glibc-rh1065574-5.patch +Patch2832: glibc-rh1065574-6.patch +Patch2833: glibc-rh1065574-7.patch +Patch2834: glibc-rh1484832.patch +Patch2835: glibc-rh1740039-1.patch +Patch2836: glibc-rh1740039-2.patch +Patch2837: glibc-rh1775599.patch +Patch2838: glibc-rh1235112.patch +Patch2839: glibc-rh1728915-1.patch +Patch2840: glibc-rh1728915-2.patch +Patch2841: glibc-rh1772307.patch +Patch2842: glibc-rh1747465-1.patch +Patch2843: glibc-rh1747465-2.patch +Patch2844: glibc-rh1747465-3.patch +Patch2845: glibc-rh1747465-4.patch +Patch2846: glibc-rh1747465-5.patch +Patch2847: glibc-rh1747465-6.patch +Patch2848: glibc-rh1747465-7.patch +Patch2849: glibc-rh1747465-8.patch +Patch2850: glibc-rh1775816.patch +Patch2851: glibc-rh1763325.patch +Patch2852: glibc-rh1406732-6.patch +Patch2853: glibc-rh1834816.patch + ############################################################################## # # Patches submitted, but not yet approved upstream. @@ -1617,6 +1727,9 @@ BuildRequires: systemd # the required semantics. BuildRequires: gcc >= 4.8.5-25 +# This RPM version introduced --g-libs. +BuildRequires: rpm-build >= 4.11.3-38.el7 + %define enablekernel 2.6.32 Conflicts: kernel < %{enablekernel} %define target %{_target_cpu}-powerel-linux @@ -2384,6 +2497,7 @@ package or when debugging this package. %patch17580 -p1 %patch1758 -p1 %patch1759 -p1 +%patch2752 -p1 %patch1760 -p1 %patch1761 -p1 %patch1762 -p1 @@ -2564,6 +2678,8 @@ package or when debugging this package. %patch1900 -p1 %patch1901 -p1 %patch1902 -p1 +%patch1903 -p1 +%patch1904 -p1 %patch2500 -p1 %patch2501 -p1 %patch2502 -p1 @@ -2820,6 +2936,112 @@ package or when debugging this package. %patch2749 -p1 %patch2750 -p1 %patch2751 -p1 +%patch2753 -p1 +%patch2754 -p1 +%patch2755 -p1 +%patch2756 -p1 +%patch2757 -p1 +%patch2758 -p1 +%patch2759 -p1 +%patch2760 -p1 +%patch2761 -p1 +%patch2762 -p1 +%patch2763 -p1 +%patch2764 -p1 +%patch2765 -p1 +%patch2766 -p1 +%patch2767 -p1 +%patch2768 -p1 +%patch2769 -p1 +%patch2770 -p1 +%patch2771 -p1 +%patch2772 -p1 +%patch2773 -p1 +%patch2774 -p1 +%patch2775 -p1 +%patch2776 -p1 +%patch2777 -p1 +%patch2778 -p1 +%patch2779 -p1 +%patch2780 -p1 +%patch2781 -p1 +%patch2782 -p1 +%patch2783 -p1 +%patch2784 -p1 +%patch2785 -p1 +%patch2786 -p1 +%patch2787 -p1 +%patch2788 -p1 +%patch2789 -p1 +%patch2790 -p1 +%patch2791 -p1 +%patch2792 -p1 +%patch2793 -p1 +%patch2794 -p1 +%patch2795 -p1 +%patch2796 -p1 +%patch2797 -p1 +%patch2798 -p1 +%patch2799 -p1 +%patch2800 -p1 +%patch2801 -p1 +%patch2802 -p1 +%patch2803 -p1 +%patch2804 -p1 +%patch2805 -p1 +%patch2806 -p1 +%patch2807 -p1 +%patch2808 -p1 +%patch2809 -p1 +%patch2810 -p1 +%patch2811 -p1 +%patch2812 -p1 +%patch2813 -p1 +%patch2814 -p1 +%patch2815 -p1 +%patch2816 -p1 +%patch2817 -p1 +%patch2818 -p1 +%patch2819 -p1 +%patch2820 -p1 +%patch2821 -p1 +%patch2822 -p1 +%patch2823 -p1 +%patch2824 -p1 +%patch2825 -p1 +%patch2826 -p1 +%patch2827 -p1 +%patch2828 -p1 +%patch2829 -p1 +%patch2830 -p1 +%patch2831 -p1 +%patch2832 -p1 +%patch2833 -p1 +%patch2834 -p1 +%patch2835 -p1 +%patch2836 -p1 +%patch2837 -p1 +%patch2838 -p1 +%patch2839 -p1 +%patch2840 -p1 +%patch2841 -p1 +%patch2842 -p1 +%patch2843 -p1 +%patch2844 -p1 +%patch2845 -p1 +%patch2846 -p1 +%patch2847 -p1 +%patch2848 -p1 +%patch2849 -p1 +%patch2850 -p1 +%patch2851 -p1 +%patch2852 -p1 +%patch2853 -p1 + +%ifarch %{arm} +%patch9998 -p1 +%patch9999 -p1 +%endif ############################################################################## # %%prep - Additional prep required... @@ -2860,6 +3082,9 @@ touch `find . -name configure` # Ensure *-kw.h files are current to prevent regenerating them. touch locale/programs/*-kw.h +# RHBZ #1640764: Ensure plural.c is current to prevent regenerating it (bison) +touch intl/plural.c + ############################################################################## # Build glibc... ############################################################################## @@ -3317,7 +3542,7 @@ $olddir/build-%{target}/elf/ld.so \ --prefix ${RPM_BUILD_ROOT} --add-to-archive \ *_* rm -rf *_* -mv locale-archive{,.tmpl} +cp locale-archive{,.tmpl} popd %endif @@ -3696,7 +3921,7 @@ ls -l $RPM_BUILD_ROOT/usr/bin/getconf ls -l $RPM_BUILD_ROOT/usr/libexec/getconf eu-readelf -hS $RPM_BUILD_ROOT/usr/bin/getconf $RPM_BUILD_ROOT/usr/libexec/getconf/* -find_debuginfo_args='--strict-build-id -g' +find_debuginfo_args='--strict-build-id --g-libs' %ifarch %{debuginfocommonarches} find_debuginfo_args="$find_debuginfo_args \ -l common.filelist -l utils.filelist -l nscd.filelist \ @@ -3933,7 +4158,7 @@ rm -f *.filelist* %files -f common.filelist common %defattr(-,root,root) %attr(0644,root,root) %verify(not md5 size mtime) %{_prefix}/lib/locale/locale-archive.tmpl -%attr(0644,root,root) %verify(not md5 size mtime mode) %ghost %config(missingok,noreplace) %{_prefix}/lib/locale/locale-archive +%attr(0644,root,root) %verify(not md5 size mtime mode) %ghost %{_prefix}/lib/locale/locale-archive %dir %attr(755,root,root) /etc/default %verify(not md5 size mtime) %config(noreplace) /etc/default/nss %doc documentation/*