[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[glibc] 01/02: debian/patches/git-updates.diff: update from upstream stable branch.



This is an automated email from the git hooks/post-receive script.

aurel32 pushed a commit to branch glibc-2.26
in repository glibc.

commit d52a330c4cea79690233af54f8f65929abbc3ae5
Author: Aurelien Jarno <aurelien@aurel32.net>
Date:   Sun Dec 31 19:11:21 2017 +0100

    debian/patches/git-updates.diff: update from upstream stable branch.
---
 debian/changelog                |    1 +
 debian/patches/git-updates.diff | 3281 +++++++++++++++++++++++++++++++++------
 2 files changed, 2848 insertions(+), 434 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index 3158f20..1c30857 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -10,6 +10,7 @@ glibc (2.26-0experimental3) UNRELEASED; urgency=medium
   * debian/sysdeps/hppa.mk: set TIMEOUTFACTOR to 100 on HPPA.
   * debian/testsuite-xfail-debian.mk: remove tst-create-detached from XFAIL
     on HPPA.
+  * debian/patches/git-updates.diff: update from upstream stable branch.
 
  -- Aurelien Jarno <aurel32@debian.org>  Sun, 17 Dec 2017 20:13:55 +0100
 
diff --git a/debian/patches/git-updates.diff b/debian/patches/git-updates.diff
index e112efc..753fa61 100644
--- a/debian/patches/git-updates.diff
+++ b/debian/patches/git-updates.diff
@@ -1,10 +1,70 @@
-GIT update of git://sourceware.org/git/glibc.git/release/2.26/master from glibc-2.26
+GIT update of https://sourceware.org/git/glibc.git/release/2.26/master from glibc-2.26
 
 diff --git a/ChangeLog b/ChangeLog
-index 8dbfc7eaff..55a17414ab 100644
+index 8dbfc7eaff..414e931aa5 100644
 --- a/ChangeLog
 +++ b/ChangeLog
-@@ -1,3 +1,1057 @@
+@@ -1,3 +1,1117 @@
++2017-12-30  Aurelien Jarno  <aurelien@aurel32.net>
++	    Dmitry V. Levin  <ldv@altlinux.org>
++
++	[BZ #22625]
++	* elf/dl-load.c (fillin_rpath): Check for empty tokens before dynamic
++	string token expansion. Check for NULL pointer or empty string possibly
++	returned by expand_dynamic_string_token.
++	(decompose_rpath): Check for empty path after dynamic string
++	token expansion.
++
++2017-12-18  Dmitry V. Levin  <ldv@altlinux.org>
++
++	[BZ #22627]
++	* elf/dl-load.c (_dl_init_paths): Remove _dl_dst_substitute preparatory
++	code and invocation.
++
++2017-11-18  Florian Weimer  <fweimer@redhat.com>
++
++	* sysdeps/unix/sysv/linux/tst-ttyname.c
++	(become_root_in_mount_ns): Remove.
++	(do_in_chroot_1): Call support_enter_mount_namespace.
++	(do_in_chroot_2): Likewise.
++	(do_test): Call support_become_root early.
++
++2017-11-15  Luke Shumaker  <lukeshu@parabola.nu>
++
++	[BZ #22145]
++	* sysdeps/unix/sysv/linux/tst-ttyname.c: New file.
++	* sysdeps/unix/sysv/linux/Makefile: Add tst-ttyname to tests.
++
++2017-11-15  Luke Shumaker  <lukeshu@parabola.nu>
++
++	[BZ #22145]
++	* sysdeps/unix/sysv/linux/ttyname.c (ttyname):
++	Defer is_pty check until end of the function.
++	* sysdeps/unix/sysv/linux/ttyname_r.c (__ttyname_r): Likewise.
++
++2017-11-15  Luke Shumaker  <lukeshu@parabola.nu>
++
++	[BZ #22145]
++	* sysdeps/unix/sysv/linux/ttyname.h (is_mytty): New function.
++	* sysdeps/unix/sysv/linux/ttyname.c (getttyname): Call is_mytty.
++	(ttyname): Likewise.
++	* sysdeps/unix/sysv/linux/ttyname_r.c (getttyname_r): Likewise.
++	(__ttyname_r): Likewise.
++
++2017-11-15  Luke Shumaker  <lukeshu@parabola.nu>
++
++	* sysdeps/unix/sysv/linux/ttyname.h (is_pty): Change return type from
++	int to bool.
++
++2017-11-15  Luke Shumaker  <lukeshu@parabola.nu>
++
++	* sysdeps/unix/sysv/linux/ttyname.h (is_pty): Update doc reference.
++
++2017-11-15  Luke Shumaker  <lukeshu@parabola.nu>
++
++	* manual/terminal.texi (Is It a Terminal):
++	Mention ENODEV for ttyname and ttyname_r.
++
 +2017-12-14  Florian Weimer  <fweimer@redhat.com>
 +
 +	[BZ #22607]
@@ -1086,10 +1146,10 @@ index 9bb707c168..828a445f24 100644
  # Don't try to use -lc when making libc.so itself.
  # Also omits crti.o and crtn.o, which we do not want
 diff --git a/NEWS b/NEWS
-index 8295f20c0a..2c49212cb5 100644
+index 8295f20c0a..f04b3ed4e8 100644
 --- a/NEWS
 +++ b/NEWS
-@@ -5,6 +5,92 @@ See the end for copying conditions.
+@@ -5,6 +5,98 @@ See the end for copying conditions.
  Please send GNU C library bug reports via <http://sourceware.org/bugzilla/>
  using `glibc' in the "product" field.
  
@@ -1143,6 +1203,10 @@ index 8295f20c0a..2c49212cb5 100644
 +  CVE-2017-1000366 has been applied, but it is mentioned here only because
 +  of the CVE assignment.)  Reported by Qualys.
 +
++  CVE-2017-16997: Incorrect handling of RPATH or RUNPATH containing $ORIGIN
++  for AT_SECURE or SUID binaries could be used to load libraries from the
++  current directory.
++
 +The following bugs are resolved with this release:
 +
 +  [16750] ldd: Never run file directly.
@@ -1168,6 +1232,7 @@ index 8295f20c0a..2c49212cb5 100644
 +  [22095] resolv: Fix memory leak with OOM during resolv.conf parsing
 +  [22096] resolv: __resolv_conf_attach must not free passed conf object
 +  [22111] malloc: per thread cache is not returned when thread exits
++  [22145] ttyname gives up too early in the face of namespaces
 +  [22146] Let fpclassify use the builtin when optimizing for size in C++ mode
 +  [22225] math: nearbyint arithmetic moved before feholdexcept
 +  [22235] Add C++ versions of iscanonical for ldbl-96 and ldbl-128ibm
@@ -1178,6 +1243,7 @@ index 8295f20c0a..2c49212cb5 100644
 +  [22322] libc: [mips64] wrong bits/long-double.h installed
 +  [22325] glibc: Memory leak in glob with GLOB_TILDE (CVE-2017-15671)
 +  [22375] malloc returns pointer from tcache instead of NULL (CVE-2017-17426)
++  [22627] $ORIGIN in $LD_LIBRARY_PATH is substituted twice
 +
  Version 2.26
  
@@ -1414,7 +1480,7 @@ index 0280fba8a7..8bbbf2a121 100644
  else
  libcrypt-routines += md5 sha256 sha512
 diff --git a/elf/dl-load.c b/elf/dl-load.c
-index c1b6d4ba0f..621403c05f 100644
+index c1b6d4ba0f..7397c1882c 100644
 --- a/elf/dl-load.c
 +++ b/elf/dl-load.c
 @@ -37,6 +37,7 @@
@@ -1447,7 +1513,79 @@ index c1b6d4ba0f..621403c05f 100644
  
  static bool
  is_trusted_path (const char *path, size_t len)
-@@ -688,9 +689,8 @@ _dl_init_paths (const char *llp)
+@@ -433,31 +434,40 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
+ {
+   char *cp;
+   size_t nelems = 0;
+-  char *to_free;
+ 
+   while ((cp = __strsep (&rpath, sep)) != NULL)
+     {
+       struct r_search_path_elem *dirp;
++      char *to_free = NULL;
++      size_t len = 0;
+ 
+-      to_free = cp = expand_dynamic_string_token (l, cp, 1);
++      /* `strsep' can pass an empty string.  */
++      if (*cp != '\0')
++	{
++	  to_free = cp = expand_dynamic_string_token (l, cp, 1);
+ 
+-      size_t len = strlen (cp);
++	  /* expand_dynamic_string_token can return NULL in case of empty
++	     path or memory allocation failure.  */
++	  if (cp == NULL)
++	    continue;
+ 
+-      /* `strsep' can pass an empty string.  This has to be
+-	 interpreted as `use the current directory'. */
+-      if (len == 0)
+-	{
+-	  static const char curwd[] = "./";
+-	  cp = (char *) curwd;
+-	}
++	  /* Compute the length after dynamic string token expansion and
++	     ignore empty paths.  */
++	  len = strlen (cp);
++	  if (len == 0)
++	    {
++	      free (to_free);
++	      continue;
++	    }
+ 
+-      /* Remove trailing slashes (except for "/").  */
+-      while (len > 1 && cp[len - 1] == '/')
+-	--len;
++	  /* Remove trailing slashes (except for "/").  */
++	  while (len > 1 && cp[len - 1] == '/')
++	    --len;
+ 
+-      /* Now add one if there is none so far.  */
+-      if (len > 0 && cp[len - 1] != '/')
+-	cp[len++] = '/';
++	  /* Now add one if there is none so far.  */
++	  if (len > 0 && cp[len - 1] != '/')
++	    cp[len++] = '/';
++	}
+ 
+       /* Make sure we don't use untrusted directories if we run SUID.  */
+       if (__glibc_unlikely (check_trusted) && !is_trusted_path (cp, len))
+@@ -621,6 +631,14 @@ decompose_rpath (struct r_search_path_struct *sps,
+      necessary.  */
+   free (copy);
+ 
++  /* There is no path after expansion.  */
++  if (result[0] == NULL)
++    {
++      free (result);
++      sps->dirs = (struct r_search_path_elem **) -1;
++      return false;
++    }
++
+   sps->dirs = result;
+   /* The caller will change this value if we haven't used a real malloc.  */
+   sps->malloced = 1;
+@@ -688,9 +706,8 @@ _dl_init_paths (const char *llp)
  		 + ncapstr * sizeof (enum r_dir_status))
  		/ sizeof (struct r_search_path_elem));
  
@@ -1459,16 +1597,32 @@ index c1b6d4ba0f..621403c05f 100644
    if (rtld_search_dirs.dirs[0] == NULL)
      {
        errstring = N_("cannot create cache for search path");
-@@ -776,8 +776,6 @@ _dl_init_paths (const char *llp)
+@@ -776,37 +793,14 @@ _dl_init_paths (const char *llp)
  
    if (llp != NULL && *llp != '\0')
      {
 -      size_t nllp;
 -      const char *cp = llp;
-       char *llp_tmp;
- 
- #ifdef SHARED
-@@ -800,13 +798,10 @@ _dl_init_paths (const char *llp)
+-      char *llp_tmp;
+-
+-#ifdef SHARED
+-      /* Expand DSTs.  */
+-      size_t cnt = DL_DST_COUNT (llp, 1);
+-      if (__glibc_likely (cnt == 0))
+-	llp_tmp = strdupa (llp);
+-      else
+-	{
+-	  /* Determine the length of the substituted string.  */
+-	  size_t total = DL_DST_REQUIRED (l, llp, strlen (llp), cnt);
+-
+-	  /* Allocate the necessary memory.  */
+-	  llp_tmp = (char *) alloca (total + 1);
+-	  llp_tmp = _dl_dst_substitute (l, llp, llp_tmp, 1);
+-	}
+-#else
+-      llp_tmp = strdupa (llp);
+-#endif
++      char *llp_tmp = strdupa (llp);
  
        /* Decompose the LD_LIBRARY_PATH contents.  First determine how many
  	 elements it has.  */
@@ -10985,11 +11139,237 @@ index e28b0c5058..4320336c9a 100644
  #endif
      }
  
+diff --git a/support/Makefile b/support/Makefile
+index 2ace3fa8cc..8458840cd8 100644
+--- a/support/Makefile
++++ b/support/Makefile
+@@ -32,15 +32,18 @@ libsupport-routines = \
+   check_netent \
+   delayed_exit \
+   ignore_stderr \
++  next_to_fault \
+   oom_error \
+   resolv_test \
+   set_fortify_handler \
++  support-xfstat \
+   support-xstat \
+   support_become_root \
+   support_can_chroot \
+   support_capture_subprocess \
+   support_capture_subprocess_check \
+   support_chroot \
++  support_enter_mount_namespace \
+   support_enter_network_namespace \
+   support_format_address_family \
+   support_format_addrinfo \
+@@ -52,6 +55,7 @@ libsupport-routines = \
+   support_record_failure \
+   support_run_diff \
+   support_shared_allocate \
++  support_test_compare_failure \
+   support_write_file_string \
+   support_test_main \
+   support_test_verify_impl \
+@@ -65,12 +69,15 @@ libsupport-routines = \
+   xchroot \
+   xclose \
+   xconnect \
++  xdlfcn \
+   xdup2 \
+   xfclose \
+   xfopen \
+   xfork \
++  xftruncate \
+   xgetsockname \
+   xlisten \
++  xlseek \
+   xmalloc \
+   xmemstream \
+   xmkdir \
+@@ -83,8 +90,8 @@ libsupport-routines = \
+   xpthread_attr_destroy \
+   xpthread_attr_init \
+   xpthread_attr_setdetachstate \
+-  xpthread_attr_setstacksize \
+   xpthread_attr_setguardsize \
++  xpthread_attr_setstacksize \
+   xpthread_barrier_destroy \
+   xpthread_barrier_init \
+   xpthread_barrier_wait \
+@@ -108,19 +115,26 @@ libsupport-routines = \
+   xpthread_once \
+   xpthread_rwlock_init \
+   xpthread_rwlock_rdlock \
+-  xpthread_rwlock_wrlock \
+   xpthread_rwlock_unlock \
++  xpthread_rwlock_wrlock \
+   xpthread_rwlockattr_init \
+   xpthread_rwlockattr_setkind_np \
+   xpthread_sigmask \
+   xpthread_spin_lock \
+   xpthread_spin_unlock \
++  xraise \
++  xreadlink \
+   xrealloc \
+   xrecvfrom \
+   xsendto \
+   xsetsockopt \
++  xsigaction \
++  xsignal \
+   xsocket \
+   xstrdup \
++  xstrndup \
++  xsysconf \
++  xunlink \
+   xwaitpid \
+   xwrite \
+ 
+@@ -137,6 +151,8 @@ tests = \
+   tst-support_capture_subprocess \
+   tst-support_format_dns_packet \
+   tst-support_record_failure \
++  tst-test_compare \
++  tst-xreadlink \
+ 
+ ifeq ($(run-built-tests),yes)
+ tests-special = \
+diff --git a/support/check.h b/support/check.h
+index bdcd12952a..55a6f09f42 100644
+--- a/support/check.h
++++ b/support/check.h
+@@ -86,6 +86,67 @@ void support_test_verify_exit_impl (int status, const char *file, int line,
+    does not support reporting failures from a DSO.  */
+ void support_record_failure (void);
+ 
++/* Compare the two integers LEFT and RIGHT and report failure if they
++   are different.  */
++#define TEST_COMPARE(left, right)                                       \
++  ({                                                                    \
++    /* + applies the integer promotions, for bitfield support.   */     \
++    typedef __typeof__ (+ (left)) __left_type;                          \
++    typedef __typeof__ (+ (right)) __right_type;                        \
++    __left_type __left_value = (left);                                  \
++    __right_type __right_value = (right);                               \
++    /* Prevent use with floating-point and boolean types.  */           \
++    _Static_assert ((__left_type) 1.0 == (__left_type) 1.5,             \
++                    "left value has floating-point type");              \
++    _Static_assert ((__right_type) 1.0 == (__right_type) 1.5,           \
++                    "right value has floating-point type");             \
++    /* Prevent accidental use with larger-than-long long types.  */     \
++    _Static_assert (sizeof (__left_value) <= sizeof (long long),        \
++                    "left value fits into long long");                  \
++    _Static_assert (sizeof (__right_value) <= sizeof (long long),       \
++                    "right value fits into long long");                 \
++    /* Make sure that integer conversions does not alter the sign.   */ \
++    enum                                                                \
++    {                                                                   \
++      __left_is_unsigned = (__left_type) -1 > 0,                        \
++      __right_is_unsigned = (__right_type) -1 > 0,                      \
++      __unsigned_left_converts_to_wider = (__left_is_unsigned           \
++                                           && (sizeof (__left_value)    \
++                                               < sizeof (__right_value))), \
++      __unsigned_right_converts_to_wider = (__right_is_unsigned         \
++                                            && (sizeof (__right_value)  \
++                                                < sizeof (__left_value))) \
++    };                                                                  \
++    _Static_assert (__left_is_unsigned == __right_is_unsigned           \
++                    || __unsigned_left_converts_to_wider                \
++                    || __unsigned_right_converts_to_wider,              \
++                    "integer conversions may alter sign of operands");  \
++    /* Compare the value.  */                                           \
++    if (__left_value != __right_value)                                  \
++      /* Pass the sign for printing the correct value.  */              \
++      support_test_compare_failure                                      \
++        (__FILE__, __LINE__,                                            \
++         #left, __left_value, __left_value < 0, sizeof (__left_type),   \
++         #right, __right_value, __right_value < 0, sizeof (__right_type)); \
++  })
++
++/* Internal implementation of TEST_COMPARE.  LEFT_NEGATIVE and
++   RIGHT_NEGATIVE are used to store the sign separately, so that both
++   unsigned long long and long long arguments fit into LEFT_VALUE and
++   RIGHT_VALUE, and the function can still print the original value.
++   LEFT_SIZE and RIGHT_SIZE specify the size of the argument in bytes,
++   for hexadecimal formatting.  */
++void support_test_compare_failure (const char *file, int line,
++                                   const char *left_expr,
++                                   long long left_value,
++                                   int left_negative,
++                                   int left_size,
++                                   const char *right_expr,
++                                   long long right_value,
++                                   int right_negative,
++                                   int right_size);
++
++
+ /* Internal function called by the test driver.  */
+ int support_report_failure (int status)
+   __attribute__ ((weak, warn_unused_result));
+diff --git a/support/check_addrinfo.c b/support/check_addrinfo.c
+index 55895ace3c..c47f105ce6 100644
+--- a/support/check_addrinfo.c
++++ b/support/check_addrinfo.c
+@@ -20,6 +20,7 @@
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
++#include <string.h>
+ #include <support/check.h>
+ #include <support/format_nss.h>
+ #include <support/run_diff.h>
+diff --git a/support/check_dns_packet.c b/support/check_dns_packet.c
+index d2a31bed7b..6d14bd90c0 100644
+--- a/support/check_dns_packet.c
++++ b/support/check_dns_packet.c
+@@ -20,6 +20,7 @@
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
++#include <string.h>
+ #include <support/check.h>
+ #include <support/format_nss.h>
+ #include <support/run_diff.h>
+diff --git a/support/check_hostent.c b/support/check_hostent.c
+index 890d672d50..47fb8bc332 100644
+--- a/support/check_hostent.c
++++ b/support/check_hostent.c
+@@ -20,6 +20,7 @@
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
++#include <string.h>
+ #include <support/check.h>
+ #include <support/format_nss.h>
+ #include <support/run_diff.h>
+diff --git a/support/check_netent.c b/support/check_netent.c
+index daa3083fd1..80b69309b4 100644
+--- a/support/check_netent.c
++++ b/support/check_netent.c
+@@ -20,6 +20,7 @@
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
++#include <string.h>
+ #include <support/check.h>
+ #include <support/format_nss.h>
+ #include <support/run_diff.h>
 diff --git a/support/namespace.h b/support/namespace.h
-index 859c2fda3f..9eddb1a0e9 100644
+index 859c2fda3f..b5e2d1474a 100644
 --- a/support/namespace.h
 +++ b/support/namespace.h
-@@ -66,7 +66,9 @@ struct support_chroot_configuration
+@@ -51,6 +51,11 @@ bool support_can_chroot (void);
+    has sufficient privileges.  */
+ bool support_enter_network_namespace (void);
+ 
++/* Enter a mount namespace and mark / as private (not shared).  If
++   this function returns true, mount operations in this process will
++   not affect the host system afterwards.  */
++bool support_enter_mount_namespace (void);
++
+ /* Return true if support_enter_network_namespace managed to enter a
+    UTS namespace.  */
+ bool support_in_uts_namespace (void);
+@@ -66,7 +71,9 @@ struct support_chroot_configuration
  {
    /* File contents.  The files are not created if the field is
       NULL.  */
@@ -11000,7 +11380,7 @@ index 859c2fda3f..9eddb1a0e9 100644
  };
  
  /* The result of the creation of a chroot.  */
-@@ -78,8 +80,11 @@ struct support_chroot
+@@ -78,8 +85,11 @@ struct support_chroot
    /* Path to the chroot directory.  */
    char *path_chroot;
  
@@ -11014,11 +11394,272 @@ index 859c2fda3f..9eddb1a0e9 100644
  };
  
  /* Create a chroot environment.  The returned data should be freed
+diff --git a/support/next_to_fault.c b/support/next_to_fault.c
+new file mode 100644
+index 0000000000..7c6b077898
+--- /dev/null
++++ b/support/next_to_fault.c
+@@ -0,0 +1,52 @@
++/* Memory allocation next to an unmapped page.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/next_to_fault.h>
++#include <support/xunistd.h>
++#include <sys/mman.h>
++#include <sys/param.h>
++
++struct support_next_to_fault
++support_next_to_fault_allocate (size_t size)
++{
++  long page_size = sysconf (_SC_PAGE_SIZE);
++  TEST_VERIFY_EXIT (page_size > 0);
++  struct support_next_to_fault result;
++  result.region_size = roundup (size, page_size) + page_size;
++  if (size + page_size <= size || result.region_size <= size)
++    FAIL_EXIT1 ("support_next_to_fault_allocate (%zu): overflow", size);
++  result.region_start
++    = xmmap (NULL, result.region_size, PROT_READ | PROT_WRITE,
++             MAP_PRIVATE | MAP_ANONYMOUS, -1);
++  /* Unmap the page after the allocation.  */
++  xmprotect (result.region_start + (result.region_size - page_size),
++             page_size, PROT_NONE);
++  /* Align the allocation within the region so that it ends just
++     before the PROT_NONE page.  */
++  result.buffer = result.region_start + result.region_size - page_size - size;
++  result.length = size;
++  return result;
++}
++
++void
++support_next_to_fault_free (struct support_next_to_fault *ntf)
++{
++  xmunmap (ntf->region_start, ntf->region_size);
++  *ntf = (struct support_next_to_fault) { NULL, };
++}
+diff --git a/support/next_to_fault.h b/support/next_to_fault.h
+new file mode 100644
+index 0000000000..dd71c28ac0
+--- /dev/null
++++ b/support/next_to_fault.h
+@@ -0,0 +1,48 @@
++/* Memory allocation next to an unmapped page.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#ifndef SUPPORT_NEXT_TO_FAULT_H
++#define SUPPORT_NEXT_TO_FAULT_H
++
++#include <sys/cdefs.h>
++#include <sys/types.h>
++
++__BEGIN_DECLS
++
++/* The memory region created by next_to_fault_allocate.  */
++struct support_next_to_fault
++{
++  /* The user data.  */
++  char *buffer;
++  size_t length;
++
++  /* The entire allocated region.  */
++  void *region_start;
++  size_t region_size;
++};
++
++/* Allocate a buffer of SIZE bytes just before a page which is mapped
++   with PROT_NONE (so that overrunning the buffer will cause a
++   fault).  */
++struct support_next_to_fault support_next_to_fault_allocate (size_t size);
++
++/* Deallocate the memory region allocated by
++   next_to_fault_allocate.  */
++void support_next_to_fault_free (struct support_next_to_fault *);
++
++#endif /* SUPPORT_NEXT_TO_FAULT_H */
+diff --git a/support/support-xfstat.c b/support/support-xfstat.c
+new file mode 100644
+index 0000000000..4c8ee9142b
+--- /dev/null
++++ b/support/support-xfstat.c
+@@ -0,0 +1,28 @@
++/* fstat64 with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/xunistd.h>
++#include <sys/stat.h>
++
++void
++xfstat (int fd, struct stat64 *result)
++{
++  if (fstat64 (fd, result) != 0)
++    FAIL_EXIT1 ("fstat64 (%d): %m", fd);
++}
+diff --git a/support/support.h b/support/support.h
+index 4b5f04c2cc..bbba803ba1 100644
+--- a/support/support.h
++++ b/support/support.h
+@@ -68,6 +68,7 @@ void *xrealloc (void *p, size_t n);
+ char *xasprintf (const char *format, ...)
+   __attribute__ ((format (printf, 1, 2), malloc));
+ char *xstrdup (const char *);
++char *xstrndup (const char *, size_t);
+ 
+ __END_DECLS
+ 
+diff --git a/support/support_become_root.c b/support/support_become_root.c
+index 3fa0bd4ac0..933138f99f 100644
+--- a/support/support_become_root.c
++++ b/support/support_become_root.c
+@@ -18,18 +18,80 @@
+ 
+ #include <support/namespace.h>
+ 
++#include <errno.h>
++#include <fcntl.h>
+ #include <sched.h>
+ #include <stdio.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/xunistd.h>
+ #include <unistd.h>
+ 
++#ifdef CLONE_NEWUSER
++/* The necessary steps to allow file creation in user namespaces.  */
++static void
++setup_uid_gid_mapping (uid_t original_uid, gid_t original_gid)
++{
++  int fd = open64 ("/proc/self/uid_map", O_WRONLY);
++  if (fd < 0)
++    {
++      printf ("warning: could not open /proc/self/uid_map: %m\n"
++              "warning: file creation may not be possible\n");
++      return;
++    }
++
++  /* We map our original UID to the same UID in the container so we
++     own our own files normally.  Without that, file creation could
++     fail with EOVERFLOW (sic!).  */
++  char buf[100];
++  int ret = snprintf (buf, sizeof (buf), "%llu %llu 1\n",
++                      (unsigned long long) original_uid,
++                      (unsigned long long) original_uid);
++  TEST_VERIFY_EXIT (ret < sizeof (buf));
++  xwrite (fd, buf, ret);
++  xclose (fd);
++
++  /* Linux 3.19 introduced the setgroups file.  We need write "deny" to this
++     file otherwise writing to gid_map will fail with EPERM.  */
++  fd = open64 ("/proc/self/setgroups", O_WRONLY, 0);
++  if (fd < 0)
++    {
++      if (errno != ENOENT)
++        FAIL_EXIT1 ("open64 (\"/proc/self/setgroups\", 0x%x, 0%o): %m",
++                    O_WRONLY, 0);
++      /* This kernel doesn't expose the setgroups file so simply move on.  */
++    }
++  else
++    {
++      xwrite (fd, "deny\n", strlen ("deny\n"));
++      xclose (fd);
++    }
++
++  /* Now map our own GID, like we did for the user ID.  */
++  fd = xopen ("/proc/self/gid_map", O_WRONLY, 0);
++  ret = snprintf (buf, sizeof (buf), "%llu %llu 1\n",
++                  (unsigned long long) original_gid,
++                  (unsigned long long) original_gid);
++  TEST_VERIFY_EXIT (ret < sizeof (buf));
++  xwrite (fd, buf, ret);
++  xclose (fd);
++}
++#endif /* CLONE_NEWUSER */
++
+ bool
+ support_become_root (void)
+ {
+ #ifdef CLONE_NEWUSER
++  uid_t original_uid = getuid ();
++  gid_t original_gid = getgid ();
++
+   if (unshare (CLONE_NEWUSER | CLONE_NEWNS) == 0)
+-    /* Even if we do not have UID zero, we have extended privileges at
+-       this point.  */
+-    return true;
++    {
++      setup_uid_gid_mapping (original_uid, original_gid);
++      /* Even if we do not have UID zero, we have extended privileges at
++         this point.  */
++      return true;
++    }
+ #endif
+   if (setuid (0) != 0)
+     {
+diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c
+index 0dfd2deb54..a462753f76 100644
+--- a/support/support_can_chroot.c
++++ b/support/support_can_chroot.c
+@@ -21,9 +21,9 @@
+ #include <support/check.h>
+ #include <support/namespace.h>
+ #include <support/support.h>
++#include <support/xunistd.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
+-#include <xunistd.h>
+ 
+ static void
+ callback (void *closure)
 diff --git a/support/support_chroot.c b/support/support_chroot.c
-index c0807b313a..f3ef551b05 100644
+index c0807b313a..693813f694 100644
 --- a/support/support_chroot.c
 +++ b/support/support_chroot.c
-@@ -24,6 +24,23 @@
+@@ -24,30 +24,38 @@
  #include <support/test-driver.h>
  #include <support/xunistd.h>
  
@@ -11042,7 +11683,16 @@ index c0807b313a..f3ef551b05 100644
  struct support_chroot *
  support_chroot_create (struct support_chroot_configuration conf)
  {
-@@ -39,15 +56,10 @@ support_chroot_create (struct support_chroot_configuration conf)
+   struct support_chroot *chroot = xmalloc (sizeof (*chroot));
+-
+-  chroot->path_chroot = xasprintf ("%s/tst-resolv-res_init-XXXXXX", test_dir);
+-  if (mkdtemp (chroot->path_chroot) == NULL)
+-    FAIL_EXIT1 ("mkdtemp (\"%s\"): %m", chroot->path_chroot);
+-  add_temp_file (chroot->path_chroot);
++  chroot->path_chroot = support_create_temp_directory ("tst-resolv-res_init-");
+ 
+   /* Create the /etc directory in the chroot environment.  */
+   char *path_etc = xasprintf ("%s/etc", chroot->path_chroot);
    xmkdir (path_etc, 0777);
    add_temp_file (path_etc);
  
@@ -11062,7 +11712,7 @@ index c0807b313a..f3ef551b05 100644
  
    free (path_etc);
  
-@@ -67,5 +79,7 @@ support_chroot_free (struct support_chroot *chroot)
+@@ -67,5 +75,7 @@ support_chroot_free (struct support_chroot *chroot)
  {
    free (chroot->path_chroot);
    free (chroot->path_resolv_conf);
@@ -11070,70 +11720,14 @@ index c0807b313a..f3ef551b05 100644
 +  free (chroot->path_host_conf);
    free (chroot);
  }
-diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile
-index 78d52c717d..9aa1e79a80 100644
---- a/sysdeps/aarch64/multiarch/Makefile
-+++ b/sysdeps/aarch64/multiarch/Makefile
-@@ -1,3 +1,4 @@
- ifeq ($(subdir),string)
--sysdep_routines += memcpy_generic memcpy_thunderx
-+sysdep_routines += memcpy_generic memcpy_thunderx memcpy_falkor \
-+		   memmove_falkor
- endif
-diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c
-index 32056bcec3..2cb74d5b43 100644
---- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c
-+++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c
-@@ -25,7 +25,7 @@
- #include <stdio.h>
- 
- /* Maximum number of IFUNC implementations.  */
--#define MAX_IFUNC	2
-+#define MAX_IFUNC	3
- 
- size_t
- __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
-@@ -40,9 +40,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
-   /* Support sysdeps/aarch64/multiarch/memcpy.c and memmove.c.  */
-   IFUNC_IMPL (i, name, memcpy,
- 	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx)
-+	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_falkor)
- 	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic))
-   IFUNC_IMPL (i, name, memmove,
- 	      IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_thunderx)
-+	      IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_falkor)
- 	      IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic))
- 
-   return i;
-diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c
-index 9f73efbba7..b395df1c63 100644
---- a/sysdeps/aarch64/multiarch/memcpy.c
-+++ b/sysdeps/aarch64/multiarch/memcpy.c
-@@ -30,9 +30,14 @@ extern __typeof (__redirect_memcpy) __libc_memcpy;
- 
- extern __typeof (__redirect_memcpy) __memcpy_generic attribute_hidden;
- extern __typeof (__redirect_memcpy) __memcpy_thunderx attribute_hidden;
-+extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden;
- 
- libc_ifunc (__libc_memcpy,
--            IS_THUNDERX (midr) ? __memcpy_thunderx : __memcpy_generic);
-+            (IS_THUNDERX (midr)
-+	     ? __memcpy_thunderx
-+	     : (IS_FALKOR (midr)
-+		? __memcpy_falkor
-+		: __memcpy_generic)));
- 
- # undef memcpy
- strong_alias (__libc_memcpy, memcpy);
-diff --git a/sysdeps/aarch64/multiarch/memcpy_falkor.S b/sysdeps/aarch64/multiarch/memcpy_falkor.S
+diff --git a/support/support_enter_mount_namespace.c b/support/support_enter_mount_namespace.c
 new file mode 100644
-index 0000000000..dea4f225ee
+index 0000000000..6140692075
 --- /dev/null
-+++ b/sysdeps/aarch64/multiarch/memcpy_falkor.S
-@@ -0,0 +1,184 @@
-+/* Optimized memcpy for Qualcomm Falkor processor.
++++ b/support/support_enter_mount_namespace.c
+@@ -0,0 +1,45 @@
++/* Enter a mount namespace.
 +   Copyright (C) 2017 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
@@ -11147,202 +11741,228 @@ index 0000000000..dea4f225ee
 +   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
++   License along with the GNU C Library; if not, see
 +   <http://www.gnu.org/licenses/>.  */
 +
-+#include <sysdep.h>
-+
-+/* Assumptions:
++#include <support/namespace.h>
 +
-+   ARMv8-a, AArch64, falkor, unaligned accesses.  */
++#include <sched.h>
++#include <stdio.h>
++#include <sys/mount.h>
 +
-+#define dstin	x0
-+#define src	x1
-+#define count	x2
-+#define dst	x3
-+#define srcend	x4
-+#define dstend	x5
-+#define A_l	x6
-+#define A_lw	w6
-+#define A_h	x7
-+#define A_hw	w7
-+#define tmp1	x14
-+
-+/* Copies are split into 3 main cases:
-+
-+   1. Small copies of up to 32 bytes
-+   2. Medium copies of 33..128 bytes which are fully unrolled
-+   3. Large copies of more than 128 bytes.
-+
-+   Large copies align the sourceto a quad word and use an unrolled loop
-+   processing 64 bytes per iteration.
-+
-+   FALKOR-SPECIFIC DESIGN:
-+
-+   The smallest copies (32 bytes or less) focus on optimal pipeline usage,
-+   which is why the redundant copies of 0-3 bytes have been replaced with
-+   conditionals, since the former would unnecessarily break across multiple
-+   issue groups.  The medium copy group has been enlarged to 128 bytes since
-+   bumping up the small copies up to 32 bytes allows us to do that without
-+   cost and also allows us to reduce the size of the prep code before loop64.
-+
-+   All copies are done only via two registers r6 and r7.  This is to ensure
-+   that all loads hit a single hardware prefetcher which can get correctly
-+   trained to prefetch a single stream.
-+
-+   The non-temporal stores help optimize cache utilization.  */
-+
-+#if IS_IN (libc)
-+ENTRY_ALIGN (__memcpy_falkor, 6)
-+
-+	cmp	count, 32
-+	add	srcend, src, count
-+	add	dstend, dstin, count
-+	b.ls	L(copy32)
-+	ldp	A_l, A_h, [src]
-+	cmp	count, 128
-+	stp	A_l, A_h, [dstin]
-+	b.hi	L(copy_long)
++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_format_addrinfo.c b/support/support_format_addrinfo.c
+index eedb030591..daf335f775 100644
+--- a/support/support_format_addrinfo.c
++++ b/support/support_format_addrinfo.c
+@@ -21,6 +21,7 @@
+ #include <arpa/inet.h>
+ #include <errno.h>
+ #include <stdio.h>
++#include <stdlib.h>
+ #include <support/support.h>
+ #include <support/xmemstream.h>
+ 
+diff --git a/support/support_format_dns_packet.c b/support/support_format_dns_packet.c
+index 2992c57971..e5ef1aa4b3 100644
+--- a/support/support_format_dns_packet.c
++++ b/support/support_format_dns_packet.c
+@@ -20,6 +20,7 @@
+ 
+ #include <arpa/inet.h>
+ #include <resolv.h>
++#include <stdbool.h>
+ #include <support/check.h>
+ #include <support/support.h>
+ #include <support/xmemstream.h>
+diff --git a/support/support_format_hostent.c b/support/support_format_hostent.c
+index 5b5f26082e..0aac17972b 100644
+--- a/support/support_format_hostent.c
++++ b/support/support_format_hostent.c
+@@ -19,7 +19,9 @@
+ #include <support/format_nss.h>
+ 
+ #include <arpa/inet.h>
++#include <errno.h>
+ #include <stdio.h>
++#include <stdlib.h>
+ #include <support/support.h>
+ #include <support/xmemstream.h>
+ 
+@@ -41,10 +43,15 @@ support_format_hostent (struct hostent *h)
+ {
+   if (h == NULL)
+     {
+-      char *value = support_format_herrno (h_errno);
+-      char *result = xasprintf ("error: %s\n", value);
+-      free (value);
+-      return result;
++      if (h_errno == NETDB_INTERNAL)
++        return xasprintf ("error: NETDB_INTERNAL (errno %d, %m)\n", errno);
++      else
++        {
++          char *value = support_format_herrno (h_errno);
++          char *result = xasprintf ("error: %s\n", value);
++          free (value);
++          return result;
++        }
+     }
+ 
+   struct xmemstream mem;
+diff --git a/support/support_format_netent.c b/support/support_format_netent.c
+index 020f5720d9..be8f1720a2 100644
+--- a/support/support_format_netent.c
++++ b/support/support_format_netent.c
+@@ -20,6 +20,7 @@
+ 
+ #include <arpa/inet.h>
+ #include <stdio.h>
++#include <stdlib.h>
+ #include <support/support.h>
+ #include <support/xmemstream.h>
+ 
+diff --git a/support/support_test_compare_failure.c b/support/support_test_compare_failure.c
+new file mode 100644
+index 0000000000..894145b56d
+--- /dev/null
++++ b/support/support_test_compare_failure.c
+@@ -0,0 +1,55 @@
++/* Reporting a numeric comparison failure.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
 +
-+	/* Medium copies: 33..128 bytes.  */
-+	sub	tmp1, count, 1
-+	ldp	A_l, A_h, [src, 16]
-+	stp	A_l, A_h, [dstin, 16]
-+	tbz	tmp1, 6, 1f
-+	ldp	A_l, A_h, [src, 32]
-+	stp	A_l, A_h, [dstin, 32]
-+	ldp	A_l, A_h, [src, 48]
-+	stp	A_l, A_h, [dstin, 48]
-+	ldp	A_l, A_h, [srcend, -64]
-+	stp	A_l, A_h, [dstend, -64]
-+	ldp	A_l, A_h, [srcend, -48]
-+	stp	A_l, A_h, [dstend, -48]
-+1:
-+	ldp	A_l, A_h, [srcend, -32]
-+	stp	A_l, A_h, [dstend, -32]
-+	ldp	A_l, A_h, [srcend, -16]
-+	stp	A_l, A_h, [dstend, -16]
-+	ret
++   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.
 +
-+	.p2align 4
-+	/* Small copies: 0..32 bytes.  */
-+L(copy32):
-+	/* 16-32 */
-+	cmp	count, 16
-+	b.lo	1f
-+	ldp	A_l, A_h, [src]
-+	stp	A_l, A_h, [dstin]
-+	ldp	A_l, A_h, [srcend, -16]
-+	stp	A_l, A_h, [dstend, -16]
-+	ret
-+	.p2align 4
-+1:
-+	/* 8-15 */
-+	tbz	count, 3, 1f
-+	ldr	A_l, [src]
-+	str	A_l, [dstin]
-+	ldr	A_l, [srcend, -8]
-+	str	A_l, [dstend, -8]
-+	ret
-+	.p2align 4
-+1:
-+	/* 4-7 */
-+	tbz	count, 2, 1f
-+	ldr	A_lw, [src]
-+	str	A_lw, [dstin]
-+	ldr	A_lw, [srcend, -4]
-+	str	A_lw, [dstend, -4]
-+	ret
-+	.p2align 4
-+1:
-+	/* 2-3 */
-+	tbz	count, 1, 1f
-+	ldrh	A_lw, [src]
-+	strh	A_lw, [dstin]
-+	ldrh	A_lw, [srcend, -2]
-+	strh	A_lw, [dstend, -2]
-+	ret
-+	.p2align 4
-+1:
-+	/* 0-1 */
-+	tbz	count, 0, 1f
-+	ldrb	A_lw, [src]
-+	strb	A_lw, [dstin]
-+1:
-+	ret
++   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.
 +
-+	/* Align SRC to 16 bytes and copy; that way at least one of the
-+	   accesses is aligned throughout the copy sequence.
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
 +
-+	   The count is off by 0 to 15 bytes, but this is OK because we trim
-+	   off the last 64 bytes to copy off from the end.  Due to this the
-+	   loop never runs out of bounds.  */
-+	.p2align 6
-+L(copy_long):
-+	sub	count, count, 64 + 16
-+	and	tmp1, src, 15
-+	bic	src, src, 15
-+	sub	dst, dstin, tmp1
-+	add	count, count, tmp1
++#include <stdio.h>
++#include <support/check.h>
 +
-+L(loop64):
-+	ldp	A_l, A_h, [src, 16]!
-+	stnp	A_l, A_h, [dst, 16]
-+	ldp	A_l, A_h, [src, 16]!
-+	subs	count, count, 64
-+	stnp	A_l, A_h, [dst, 32]
-+	ldp	A_l, A_h, [src, 16]!
-+	stnp	A_l, A_h, [dst, 48]
-+	ldp	A_l, A_h, [src, 16]!
-+	stnp	A_l, A_h, [dst, 64]
-+	add	dst, dst, 64
-+	b.hi	L(loop64)
++static void
++report (const char *which, const char *expr, long long value, int negative,
++        int size)
++{
++  printf ("  %s: ", which);
++  if (negative)
++    printf ("%lld", value);
++  else
++    printf ("%llu", (unsigned long long) value);
++  unsigned long long mask
++    = (~0ULL) >> (8 * (sizeof (unsigned long long) - size));
++  printf (" (0x%llx); from: %s\n", (unsigned long long) value & mask, expr);
++}
 +
-+	/* Write the last full set of 64 bytes.  The remainder is at most 64
-+	   bytes, so it is safe to always copy 64 bytes from the end even if
-+	   there is just 1 byte left.  */
-+L(last64):
-+	ldp	A_l, A_h, [srcend, -64]
-+	stnp	A_l, A_h, [dstend, -64]
-+	ldp	A_l, A_h, [srcend, -48]
-+	stnp	A_l, A_h, [dstend, -48]
-+	ldp	A_l, A_h, [srcend, -32]
-+	stnp	A_l, A_h, [dstend, -32]
-+	ldp	A_l, A_h, [srcend, -16]
-+	stnp	A_l, A_h, [dstend, -16]
-+	ret
++void
++support_test_compare_failure (const char *file, int line,
++                              const char *left_expr,
++                              long long left_value,
++                              int left_negative,
++                              int left_size,
++                              const char *right_expr,
++                              long long right_value,
++                              int right_negative,
++                              int right_size)
++{
++  support_record_failure ();
++  if (left_size != right_size)
++    printf ("%s:%d: numeric comparison failure (widths %d and %d)\n",
++            file, line, left_size * 8, right_size * 8);
++  else
++    printf ("%s:%d: numeric comparison failure\n", file, line);
++  report (" left", left_expr, left_value, left_negative, left_size);
++  report ("right", right_expr, right_value, right_negative, right_size);
++}
+diff --git a/support/support_write_file_string.c b/support/support_write_file_string.c
+index 48e89597f3..48736530bf 100644
+--- a/support/support_write_file_string.c
++++ b/support/support_write_file_string.c
+@@ -19,7 +19,7 @@
+ #include <fcntl.h>
+ #include <string.h>
+ #include <support/check.h>
+-#include <xunistd.h>
++#include <support/xunistd.h>
+ 
+ void
+ support_write_file_string (const char *path, const char *contents)
+diff --git a/support/temp_file.c b/support/temp_file.c
+index fdb2477ab9..547263a3e4 100644
+--- a/support/temp_file.c
++++ b/support/temp_file.c
+@@ -86,6 +86,19 @@ create_temp_file (const char *base, char **filename)
+   return fd;
+ }
+ 
++char *
++support_create_temp_directory (const char *base)
++{
++  char *path = xasprintf ("%s/%sXXXXXX", test_dir, base);
++  if (mkdtemp (path) == NULL)
++    {
++      printf ("error: mkdtemp (\"%s\"): %m", path);
++      exit (1);
++    }
++  add_temp_file (path);
++  return path;
++}
 +
-+END (__memcpy_falkor)
-+libc_hidden_builtin_def (__memcpy_falkor)
-+#endif
-diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c
-index 34c6b29bd5..016f03ee50 100644
---- a/sysdeps/aarch64/multiarch/memmove.c
-+++ b/sysdeps/aarch64/multiarch/memmove.c
-@@ -30,9 +30,14 @@ extern __typeof (__redirect_memmove) __libc_memmove;
+ /* Helper functions called by the test skeleton follow.  */
  
- extern __typeof (__redirect_memmove) __memmove_generic attribute_hidden;
- extern __typeof (__redirect_memmove) __memmove_thunderx attribute_hidden;
-+extern __typeof (__redirect_memmove) __memmove_falkor attribute_hidden;
+ void
+diff --git a/support/temp_file.h b/support/temp_file.h
+index 6fed8df1ea..3b8563e115 100644
+--- a/support/temp_file.h
++++ b/support/temp_file.h
+@@ -32,6 +32,11 @@ void add_temp_file (const char *name);
+    *FILENAME.  */
+ int create_temp_file (const char *base, char **filename);
  
- libc_ifunc (__libc_memmove,
--            IS_THUNDERX (midr) ? __memmove_thunderx : __memmove_generic);
-+            (IS_THUNDERX (midr)
-+	     ? __memmove_thunderx
-+	     : (IS_FALKOR (midr)
-+		? __memmove_falkor
-+		: __memmove_generic)));
++/* 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
  
- # undef memmove
- strong_alias (__libc_memmove, memmove);
-diff --git a/sysdeps/aarch64/multiarch/memmove_falkor.S b/sysdeps/aarch64/multiarch/memmove_falkor.S
+ #endif /* SUPPORT_TEMP_FILE_H */
+diff --git a/support/tst-test_compare.c b/support/tst-test_compare.c
 new file mode 100644
-index 0000000000..3a4e6a2a8e
+index 0000000000..de138d4f8a
 --- /dev/null
-+++ b/sysdeps/aarch64/multiarch/memmove_falkor.S
-@@ -0,0 +1,232 @@
-+/* Copyright (C) 2017 Free Software Foundation, Inc.
-+
++++ b/support/tst-test_compare.c
+@@ -0,0 +1,98 @@
++/* Basic test for the TEST_COMPARE macro.
++   Copyright (C) 2017 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
@@ -11356,21 +11976,944 @@ index 0000000000..3a4e6a2a8e
 +   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
++   License along with the GNU C Library; if not, see
 +   <http://www.gnu.org/licenses/>.  */
 +
-+#include <sysdep.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/capture_subprocess.h>
 +
-+/* Assumptions: ARMv8-a, AArch64, falkor, unaligned accesses.  */
++static void
++subprocess (void *closure)
++{
++  char ch = 1;
++  /* These tests should fail.  */
++  TEST_COMPARE (ch, -1);         /* Line 28.  */
++  TEST_COMPARE (2LL, -2LL);      /* Line 29.  */
++  TEST_COMPARE (3LL, (short) -3); /* Line 30.  */
++}
 +
-+#define dstin	x0
-+#define src	x1
-+#define count	x2
-+#define dstlen	x3
-+#define dst	x3
-+#define srcend	x4
-+#define dstend	x5
-+#define A_l	x6
++struct bitfield
++{
++  int i2 : 2;
++  int i3 : 3;
++  unsigned int u2 : 2;
++  unsigned int u3 : 3;
++  int i31 : 31;
++  unsigned int u31 : 31 ;
++  long long int i63 : 63;
++  unsigned long long int u63 : 63;
++};
++
++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);
++  }
++
++  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 <support/test-driver.c>
+diff --git a/support/tst-xreadlink.c b/support/tst-xreadlink.c
+new file mode 100644
+index 0000000000..a4a22812c1
+--- /dev/null
++++ b/support/tst-xreadlink.c
+@@ -0,0 +1,72 @@
++/* Test the xreadlink function.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <errno.h>
++#include <fcntl.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/support.h>
++#include <support/temp_file.h>
++#include <support/xunistd.h>
++
++static int
++do_test (void)
++{
++  char *dir = support_create_temp_directory ("tst-xreadlink-");
++  char *symlink_name = xasprintf ("%s/symlink", dir);
++  add_temp_file (symlink_name);
++
++  /* The limit 10000 is arbitrary and simply there to prevent an
++     attempt to exhaust all available disk space.  */
++  for (int size = 1; size < 10000; ++size)
++    {
++      char *contents = xmalloc (size + 1);
++      for (int i = 0; i < size; ++i)
++        contents[i] = 'a' + (rand () % 26);
++      contents[size] = '\0';
++      if (symlink (contents, symlink_name) != 0)
++        {
++          if (errno == ENAMETOOLONG)
++            {
++              printf ("info: ENAMETOOLONG failure at %d bytes\n", size);
++              free (contents);
++              break;
++            }
++          FAIL_EXIT1 ("symlink (%d bytes): %m", size);
++        }
++
++      char *readlink_result = xreadlink (symlink_name);
++      TEST_VERIFY (strcmp (readlink_result, contents) == 0);
++      free (readlink_result);
++      xunlink (symlink_name);
++      free (contents);
++    }
++
++  /* Create an empty file to suppress the temporary file deletion
++     warning.  */
++  xclose (xopen (symlink_name, O_WRONLY | O_CREAT, 0));
++
++  free (symlink_name);
++  free (dir);
++
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/support/xdlfcn.c b/support/xdlfcn.c
+new file mode 100644
+index 0000000000..05966c41ef
+--- /dev/null
++++ b/support/xdlfcn.c
+@@ -0,0 +1,59 @@
++/* Support functionality for using dlopen/dlclose/dlsym.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <stddef.h>
++#include <support/check.h>
++#include <support/xdlfcn.h>
++
++void *
++xdlopen (const char *filename, int flags)
++{
++  void *dso = dlopen (filename, flags);
++
++  if (dso == NULL)
++    FAIL_EXIT1 ("error: dlopen: %s\n", dlerror ());
++
++  /* Clear any errors.  */
++  dlerror ();
++
++  return dso;
++}
++
++void *
++xdlsym (void *handle, const char *symbol)
++{
++  void *sym = dlsym (handle, symbol);
++
++  if (sym == NULL)
++    FAIL_EXIT1 ("error: dlsym: %s\n", dlerror ());
++
++  /* Clear any errors.  */
++  dlerror ();
++
++  return sym;
++}
++
++void
++xdlclose (void *handle)
++{
++  if (dlclose (handle) != 0)
++    FAIL_EXIT1 ("error: dlclose: %s\n", dlerror ());
++
++  /* Clear any errors.  */
++  dlerror ();
++}
+diff --git a/support/xdlfcn.h b/support/xdlfcn.h
+new file mode 100644
+index 0000000000..9bdcb38d3e
+--- /dev/null
++++ b/support/xdlfcn.h
+@@ -0,0 +1,34 @@
++/* Support functionality for using dlopen/dlclose/dlsym.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#ifndef SUPPORT_DLOPEN_H
++#define SUPPORT_DLOPEN_H
++
++#include <dlfcn.h>
++
++__BEGIN_DECLS
++
++/* Each of these terminates process on failure with relevant error message.  */
++void *xdlopen (const char *filename, int flags);
++void *xdlsym (void *handle, const char *symbol);
++void xdlclose (void *handle);
++
++
++__END_DECLS
++
++#endif /* SUPPORT_DLOPEN_H */
+diff --git a/support/xftruncate.c b/support/xftruncate.c
+new file mode 100644
+index 0000000000..9c4e9e3050
+--- /dev/null
++++ b/support/xftruncate.c
+@@ -0,0 +1,27 @@
++/* ftruncate with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/xunistd.h>
++
++void
++xftruncate (int fd, long long length)
++{
++  if (ftruncate64 (fd, length) != 0)
++    FAIL_EXIT1 ("ftruncate64 (%d, %lld): %m", fd, length);
++}
+diff --git a/support/xlseek.c b/support/xlseek.c
+new file mode 100644
+index 0000000000..0a75a9f2e6
+--- /dev/null
++++ b/support/xlseek.c
+@@ -0,0 +1,29 @@
++/* lseek with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/xunistd.h>
++
++long long
++xlseek (int fd, long long offset, int whence)
++{
++  long long result = lseek64 (fd, offset, whence);
++  if (result < 0)
++    FAIL_EXIT1 ("lseek64 (%d, %lld, %d): %m", fd, offset, whence);
++  return result;
++}
+diff --git a/support/xraise.c b/support/xraise.c
+new file mode 100644
+index 0000000000..9126c6c3ea
+--- /dev/null
++++ b/support/xraise.c
+@@ -0,0 +1,27 @@
++/* Error-checking wrapper for raise.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/xsignal.h>
++
++void
++xraise (int sig)
++{
++  if (raise (sig) != 0)
++    FAIL_EXIT1 ("raise (%d): %m" , sig);
++}
+diff --git a/support/xreadlink.c b/support/xreadlink.c
+new file mode 100644
+index 0000000000..aec58a2aa6
+--- /dev/null
++++ b/support/xreadlink.c
+@@ -0,0 +1,44 @@
++/* Error-checking, allocating wrapper for readlink.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <scratch_buffer.h>
++#include <support/check.h>
++#include <support/support.h>
++#include <xunistd.h>
++
++char *
++xreadlink (const char *path)
++{
++  struct scratch_buffer buf;
++  scratch_buffer_init (&buf);
++
++  while (true)
++    {
++      ssize_t count = readlink (path, buf.data, buf.length);
++      if (count < 0)
++        FAIL_EXIT1 ("readlink (\"%s\"): %m", path);
++      if (count < buf.length)
++        {
++          char *result = xstrndup (buf.data, count);
++          scratch_buffer_free (&buf);
++          return result;
++        }
++      if (!scratch_buffer_grow (&buf))
++        FAIL_EXIT1 ("scratch_buffer_grow in xreadlink");
++    }
++}
+diff --git a/support/xsigaction.c b/support/xsigaction.c
+new file mode 100644
+index 0000000000..b74c69afae
+--- /dev/null
++++ b/support/xsigaction.c
+@@ -0,0 +1,27 @@
++/* Error-checking wrapper for sigaction.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/xsignal.h>
++
++void
++xsigaction (int sig, const struct sigaction *newact, struct sigaction *oldact)
++{
++  if (sigaction (sig, newact, oldact))
++    FAIL_EXIT1 ("sigaction (%d): %m" , sig);
++}
+diff --git a/support/xsignal.c b/support/xsignal.c
+new file mode 100644
+index 0000000000..22a1dd74a7
+--- /dev/null
++++ b/support/xsignal.c
+@@ -0,0 +1,29 @@
++/* Error-checking wrapper for signal.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/xsignal.h>
++
++sighandler_t
++xsignal (int sig, sighandler_t handler)
++{
++  sighandler_t result = signal (sig, handler);
++  if (result == SIG_ERR)
++    FAIL_EXIT1 ("signal (%d, %p): %m", sig, handler);
++  return result;
++}
+diff --git a/support/xsignal.h b/support/xsignal.h
+index 3dc0d9d5ce..3087ed0082 100644
+--- a/support/xsignal.h
++++ b/support/xsignal.h
+@@ -24,6 +24,14 @@
+ 
+ __BEGIN_DECLS
+ 
++/* The following functions call the corresponding libc functions and
++   terminate the process on error.  */
++
++void xraise (int sig);
++sighandler_t xsignal (int sig, sighandler_t handler);
++void xsigaction (int sig, const struct sigaction *newact,
++                 struct sigaction *oldact);
++
+ /* The following functions call the corresponding libpthread functions
+    and terminate the process on error.  */
+ 
+diff --git a/support/xstrndup.c b/support/xstrndup.c
+new file mode 100644
+index 0000000000..d59a283d25
+--- /dev/null
++++ b/support/xstrndup.c
+@@ -0,0 +1,30 @@
++/* strndup with error checking.
++   Copyright (C) 2016-2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/support.h>
++
++#include <string.h>
++
++char *
++xstrndup (const char *s, size_t length)
++{
++  char *p = strndup (s, length);
++  if (p == NULL)
++    oom_error ("strndup", length);
++  return p;
++}
+diff --git a/support/xsysconf.c b/support/xsysconf.c
+new file mode 100644
+index 0000000000..15ab1e26c4
+--- /dev/null
++++ b/support/xsysconf.c
+@@ -0,0 +1,36 @@
++/* Error-checking wrapper for sysconf.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <errno.h>
++#include <support/check.h>
++#include <support/xunistd.h>
++
++long
++xsysconf (int name)
++{
++  /* Detect errors by a changed errno value, in case -1 is a valid
++     value.  Make sure that the caller does not see the zero value for
++     errno.  */
++  int old_errno = errno;
++  errno = 0;
++  long result = sysconf (name);
++  if (errno != 0)
++    FAIL_EXIT1 ("sysconf (%d): %m", name);
++  errno = old_errno;
++  return result;
++}
+diff --git a/support/xunistd.h b/support/xunistd.h
+index c947bfd8fb..29da063c15 100644
+--- a/support/xunistd.h
++++ b/support/xunistd.h
+@@ -36,8 +36,17 @@ void xpipe (int[2]);
+ void xdup2 (int, int);
+ int xopen (const char *path, int flags, mode_t);
+ void xstat (const char *path, struct stat64 *);
++void xfstat (int fd, struct stat64 *);
+ void xmkdir (const char *path, mode_t);
+ void xchroot (const char *path);
++void xunlink (const char *path);
++long xsysconf (int name);
++long long xlseek (int fd, long long offset, int whence);
++void xftruncate (int fd, long long length);
++
++/* Read the link at PATH.  The caller should free the returned string
++   with free.  */
++char *xreadlink (const char *path);
+ 
+ /* Close the file descriptor.  Ignore EINTR errors, but terminate the
+    process on other errors.  */
+diff --git a/support/xunlink.c b/support/xunlink.c
+new file mode 100644
+index 0000000000..f94ee118cf
+--- /dev/null
++++ b/support/xunlink.c
+@@ -0,0 +1,27 @@
++/* Error-checking wrapper for unlink.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/xunistd.h>
++
++void
++xunlink (const char *path)
++{
++  if (unlink (path) != 0)
++    FAIL_EXIT1 ("unlink (\"%s\"): %m", path);
++}
+diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile
+index 78d52c717d..9aa1e79a80 100644
+--- a/sysdeps/aarch64/multiarch/Makefile
++++ b/sysdeps/aarch64/multiarch/Makefile
+@@ -1,3 +1,4 @@
+ ifeq ($(subdir),string)
+-sysdep_routines += memcpy_generic memcpy_thunderx
++sysdep_routines += memcpy_generic memcpy_thunderx memcpy_falkor \
++		   memmove_falkor
+ endif
+diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c
+index 32056bcec3..2cb74d5b43 100644
+--- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c
++++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c
+@@ -25,7 +25,7 @@
+ #include <stdio.h>
+ 
+ /* Maximum number of IFUNC implementations.  */
+-#define MAX_IFUNC	2
++#define MAX_IFUNC	3
+ 
+ size_t
+ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -40,9 +40,11 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+   /* Support sysdeps/aarch64/multiarch/memcpy.c and memmove.c.  */
+   IFUNC_IMPL (i, name, memcpy,
+ 	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx)
++	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_falkor)
+ 	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic))
+   IFUNC_IMPL (i, name, memmove,
+ 	      IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_thunderx)
++	      IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_falkor)
+ 	      IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic))
+ 
+   return i;
+diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c
+index 9f73efbba7..b395df1c63 100644
+--- a/sysdeps/aarch64/multiarch/memcpy.c
++++ b/sysdeps/aarch64/multiarch/memcpy.c
+@@ -30,9 +30,14 @@ extern __typeof (__redirect_memcpy) __libc_memcpy;
+ 
+ extern __typeof (__redirect_memcpy) __memcpy_generic attribute_hidden;
+ extern __typeof (__redirect_memcpy) __memcpy_thunderx attribute_hidden;
++extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden;
+ 
+ libc_ifunc (__libc_memcpy,
+-            IS_THUNDERX (midr) ? __memcpy_thunderx : __memcpy_generic);
++            (IS_THUNDERX (midr)
++	     ? __memcpy_thunderx
++	     : (IS_FALKOR (midr)
++		? __memcpy_falkor
++		: __memcpy_generic)));
+ 
+ # undef memcpy
+ strong_alias (__libc_memcpy, memcpy);
+diff --git a/sysdeps/aarch64/multiarch/memcpy_falkor.S b/sysdeps/aarch64/multiarch/memcpy_falkor.S
+new file mode 100644
+index 0000000000..dea4f225ee
+--- /dev/null
++++ b/sysdeps/aarch64/multiarch/memcpy_falkor.S
+@@ -0,0 +1,184 @@
++/* Optimized memcpy for Qualcomm Falkor processor.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library.  If not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <sysdep.h>
++
++/* Assumptions:
++
++   ARMv8-a, AArch64, falkor, unaligned accesses.  */
++
++#define dstin	x0
++#define src	x1
++#define count	x2
++#define dst	x3
++#define srcend	x4
++#define dstend	x5
++#define A_l	x6
++#define A_lw	w6
++#define A_h	x7
++#define A_hw	w7
++#define tmp1	x14
++
++/* Copies are split into 3 main cases:
++
++   1. Small copies of up to 32 bytes
++   2. Medium copies of 33..128 bytes which are fully unrolled
++   3. Large copies of more than 128 bytes.
++
++   Large copies align the sourceto a quad word and use an unrolled loop
++   processing 64 bytes per iteration.
++
++   FALKOR-SPECIFIC DESIGN:
++
++   The smallest copies (32 bytes or less) focus on optimal pipeline usage,
++   which is why the redundant copies of 0-3 bytes have been replaced with
++   conditionals, since the former would unnecessarily break across multiple
++   issue groups.  The medium copy group has been enlarged to 128 bytes since
++   bumping up the small copies up to 32 bytes allows us to do that without
++   cost and also allows us to reduce the size of the prep code before loop64.
++
++   All copies are done only via two registers r6 and r7.  This is to ensure
++   that all loads hit a single hardware prefetcher which can get correctly
++   trained to prefetch a single stream.
++
++   The non-temporal stores help optimize cache utilization.  */
++
++#if IS_IN (libc)
++ENTRY_ALIGN (__memcpy_falkor, 6)
++
++	cmp	count, 32
++	add	srcend, src, count
++	add	dstend, dstin, count
++	b.ls	L(copy32)
++	ldp	A_l, A_h, [src]
++	cmp	count, 128
++	stp	A_l, A_h, [dstin]
++	b.hi	L(copy_long)
++
++	/* Medium copies: 33..128 bytes.  */
++	sub	tmp1, count, 1
++	ldp	A_l, A_h, [src, 16]
++	stp	A_l, A_h, [dstin, 16]
++	tbz	tmp1, 6, 1f
++	ldp	A_l, A_h, [src, 32]
++	stp	A_l, A_h, [dstin, 32]
++	ldp	A_l, A_h, [src, 48]
++	stp	A_l, A_h, [dstin, 48]
++	ldp	A_l, A_h, [srcend, -64]
++	stp	A_l, A_h, [dstend, -64]
++	ldp	A_l, A_h, [srcend, -48]
++	stp	A_l, A_h, [dstend, -48]
++1:
++	ldp	A_l, A_h, [srcend, -32]
++	stp	A_l, A_h, [dstend, -32]
++	ldp	A_l, A_h, [srcend, -16]
++	stp	A_l, A_h, [dstend, -16]
++	ret
++
++	.p2align 4
++	/* Small copies: 0..32 bytes.  */
++L(copy32):
++	/* 16-32 */
++	cmp	count, 16
++	b.lo	1f
++	ldp	A_l, A_h, [src]
++	stp	A_l, A_h, [dstin]
++	ldp	A_l, A_h, [srcend, -16]
++	stp	A_l, A_h, [dstend, -16]
++	ret
++	.p2align 4
++1:
++	/* 8-15 */
++	tbz	count, 3, 1f
++	ldr	A_l, [src]
++	str	A_l, [dstin]
++	ldr	A_l, [srcend, -8]
++	str	A_l, [dstend, -8]
++	ret
++	.p2align 4
++1:
++	/* 4-7 */
++	tbz	count, 2, 1f
++	ldr	A_lw, [src]
++	str	A_lw, [dstin]
++	ldr	A_lw, [srcend, -4]
++	str	A_lw, [dstend, -4]
++	ret
++	.p2align 4
++1:
++	/* 2-3 */
++	tbz	count, 1, 1f
++	ldrh	A_lw, [src]
++	strh	A_lw, [dstin]
++	ldrh	A_lw, [srcend, -2]
++	strh	A_lw, [dstend, -2]
++	ret
++	.p2align 4
++1:
++	/* 0-1 */
++	tbz	count, 0, 1f
++	ldrb	A_lw, [src]
++	strb	A_lw, [dstin]
++1:
++	ret
++
++	/* Align SRC to 16 bytes and copy; that way at least one of the
++	   accesses is aligned throughout the copy sequence.
++
++	   The count is off by 0 to 15 bytes, but this is OK because we trim
++	   off the last 64 bytes to copy off from the end.  Due to this the
++	   loop never runs out of bounds.  */
++	.p2align 6
++L(copy_long):
++	sub	count, count, 64 + 16
++	and	tmp1, src, 15
++	bic	src, src, 15
++	sub	dst, dstin, tmp1
++	add	count, count, tmp1
++
++L(loop64):
++	ldp	A_l, A_h, [src, 16]!
++	stnp	A_l, A_h, [dst, 16]
++	ldp	A_l, A_h, [src, 16]!
++	subs	count, count, 64
++	stnp	A_l, A_h, [dst, 32]
++	ldp	A_l, A_h, [src, 16]!
++	stnp	A_l, A_h, [dst, 48]
++	ldp	A_l, A_h, [src, 16]!
++	stnp	A_l, A_h, [dst, 64]
++	add	dst, dst, 64
++	b.hi	L(loop64)
++
++	/* Write the last full set of 64 bytes.  The remainder is at most 64
++	   bytes, so it is safe to always copy 64 bytes from the end even if
++	   there is just 1 byte left.  */
++L(last64):
++	ldp	A_l, A_h, [srcend, -64]
++	stnp	A_l, A_h, [dstend, -64]
++	ldp	A_l, A_h, [srcend, -48]
++	stnp	A_l, A_h, [dstend, -48]
++	ldp	A_l, A_h, [srcend, -32]
++	stnp	A_l, A_h, [dstend, -32]
++	ldp	A_l, A_h, [srcend, -16]
++	stnp	A_l, A_h, [dstend, -16]
++	ret
++
++END (__memcpy_falkor)
++libc_hidden_builtin_def (__memcpy_falkor)
++#endif
+diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c
+index 34c6b29bd5..016f03ee50 100644
+--- a/sysdeps/aarch64/multiarch/memmove.c
++++ b/sysdeps/aarch64/multiarch/memmove.c
+@@ -30,9 +30,14 @@ extern __typeof (__redirect_memmove) __libc_memmove;
+ 
+ extern __typeof (__redirect_memmove) __memmove_generic attribute_hidden;
+ extern __typeof (__redirect_memmove) __memmove_thunderx attribute_hidden;
++extern __typeof (__redirect_memmove) __memmove_falkor attribute_hidden;
+ 
+ libc_ifunc (__libc_memmove,
+-            IS_THUNDERX (midr) ? __memmove_thunderx : __memmove_generic);
++            (IS_THUNDERX (midr)
++	     ? __memmove_thunderx
++	     : (IS_FALKOR (midr)
++		? __memmove_falkor
++		: __memmove_generic)));
+ 
+ # undef memmove
+ strong_alias (__libc_memmove, memmove);
+diff --git a/sysdeps/aarch64/multiarch/memmove_falkor.S b/sysdeps/aarch64/multiarch/memmove_falkor.S
+new file mode 100644
+index 0000000000..3a4e6a2a8e
+--- /dev/null
++++ b/sysdeps/aarch64/multiarch/memmove_falkor.S
+@@ -0,0 +1,232 @@
++/* Copyright (C) 2017 Free Software Foundation, Inc.
++
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library.  If not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <sysdep.h>
++
++/* Assumptions: ARMv8-a, AArch64, falkor, unaligned accesses.  */
++
++#define dstin	x0
++#define src	x1
++#define count	x2
++#define dstlen	x3
++#define dst	x3
++#define srcend	x4
++#define dstend	x5
++#define A_l	x6
 +#define A_lw	w6
 +#define A_h	x7
 +#define A_hw	w7
@@ -19811,19 +21354,20 @@ index 0000000000..bdda1f197e
 +# define __PTHREAD_MUTEX_LIST_OFFSET     20
 +#endif
 diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
-index 9d6a2de870..dbe6a36c57 100644
+index 9d6a2de870..b1fe960d00 100644
 --- a/sysdeps/unix/sysv/linux/Makefile
 +++ b/sysdeps/unix/sysv/linux/Makefile
-@@ -50,7 +50,7 @@ sysdep_headers += sys/mount.h sys/acct.h sys/sysctl.h \
+@@ -50,7 +50,8 @@ sysdep_headers += sys/mount.h sys/acct.h sys/sysctl.h \
  		  bits/siginfo-arch.h bits/siginfo-consts-arch.h
  
  tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \
 -	 tst-quota tst-sync_file_range test-errno-linux
-+	 tst-quota tst-sync_file_range test-errno-linux tst-sysconf-iov_max
++	 tst-quota tst-sync_file_range tst-sysconf-iov_max tst-ttyname \
++	 test-errno-linux
  
  # Generate the list of SYS_* macros for the system calls (__NR_* macros).
  
-@@ -120,7 +120,11 @@ ifndef no_deps
+@@ -120,7 +121,11 @@ ifndef no_deps
  -include $(objpfx)bits/syscall.d
  endif
  generated += bits/syscall.h bits/syscall.d
@@ -19836,7 +21380,7 @@ index 9d6a2de870..dbe6a36c57 100644
  
  ifeq ($(subdir),time)
  sysdep_headers += sys/timex.h bits/timex.h
-@@ -162,7 +166,7 @@ endif
+@@ -162,7 +167,7 @@ endif
  ifeq ($(subdir),posix)
  sysdep_headers += bits/initspin.h
  
@@ -20707,17 +22251,147 @@ index 094e05124b..0000000000
 -#endif
 diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h
 new file mode 100644
-index 0000000000..094e05124b
+index 0000000000..094e05124b
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h
+@@ -0,0 +1,26 @@
++/* Properties of long double type.  SPARC version.
++   Copyright (C) 2016-2017 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  published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <bits/wordsize.h>
++
++#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32
++# define __LONG_DOUBLE_MATH_OPTIONAL   1
++# ifndef __LONG_DOUBLE_128__
++#  define __NO_LONG_DOUBLE_MATH        1
++# endif
++#endif
+diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/glob64.c b/sysdeps/unix/sysv/linux/sparc/sparc32/glob64.c
+deleted file mode 100644
+index 82a9a296a7..0000000000
+--- a/sysdeps/unix/sysv/linux/sparc/sparc32/glob64.c
++++ /dev/null
+@@ -1 +0,0 @@
+-#include <sysdeps/unix/sysv/linux/i386/glob64.c>
+diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h
+new file mode 100644
+index 0000000000..094e05124b
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h
+@@ -0,0 +1,26 @@
++/* Properties of long double type.  SPARC version.
++   Copyright (C) 2016-2017 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  published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <bits/wordsize.h>
++
++#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32
++# define __LONG_DOUBLE_MATH_OPTIONAL   1
++# ifndef __LONG_DOUBLE_128__
++#  define __NO_LONG_DOUBLE_MATH        1
++# endif
++#endif
+diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
+index c56f894a82..7d23df84d2 100644
+--- a/sysdeps/unix/sysv/linux/spawni.c
++++ b/sysdeps/unix/sysv/linux/spawni.c
+@@ -17,7 +17,6 @@
+    <http://www.gnu.org/licenses/>.  */
+ 
+ #include <spawn.h>
+-#include <assert.h>
+ #include <fcntl.h>
+ #include <paths.h>
+ #include <string.h>
+@@ -268,7 +267,6 @@ __spawni_child (void *arguments)
+   __sigprocmask (SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK)
+ 		 ? &attr->__ss : &args->oldmask, 0);
+ 
+-  args->err = 0;
+   args->exec (args->file, args->argv, args->envp);
+ 
+   /* This is compatibility function required to enable posix_spawn run
+@@ -339,7 +337,7 @@ __spawnix (pid_t * pid, const char *file,
+ 
+   /* Child must set args.err to something non-negative - we rely on
+      the parent and child sharing VM.  */
+-  args.err = -1;
++  args.err = 0;
+   args.file = file;
+   args.exec = exec;
+   args.fa = file_actions;
+@@ -362,12 +360,26 @@ __spawnix (pid_t * pid, const char *file,
+   new_pid = CLONE (__spawni_child, STACK (stack, stack_size), stack_size,
+ 		   CLONE_VM | CLONE_VFORK | SIGCHLD, &args);
+ 
++  /* It needs to collect the case where the auxiliary process was created
++     but failed to execute the file (due either any preparation step or
++     for execve itself).  */
+   if (new_pid > 0)
+     {
++      /* Also, it handles the unlikely case where the auxiliary process was
++	 terminated before calling execve as if it was successfully.  The
++	 args.err is set to 0 as default and changed to a positive value
++	 only in case of failure, so in case of premature termination
++	 due a signal args.err will remain zeroed and it will be up to
++	 caller to actually collect it.  */
+       ec = args.err;
+-      assert (ec >= 0);
+-      if (ec != 0)
+-	  __waitpid (new_pid, NULL, 0);
++      if (ec > 0)
++	/* There still an unlikely case where the child is cancelled after
++	   setting args.err, due to a positive error value.  Also there is
++	   possible pid reuse race (where the kernel allocated the same pid
++	   to an unrelated process).  Unfortunately due synchronization
++	   issues where the kernel might not have the process collected
++	   the waitpid below can not use WNOHANG.  */
++	__waitpid (new_pid, NULL, 0);
+     }
+   else
+     ec = -new_pid;
+diff --git a/sysdeps/unix/sysv/linux/tst-sysconf-iov_max-uapi.c b/sysdeps/unix/sysv/linux/tst-sysconf-iov_max-uapi.c
+new file mode 100644
+index 0000000000..1240b846e6
 --- /dev/null
-+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h
-@@ -0,0 +1,26 @@
-+/* Properties of long double type.  SPARC version.
-+   Copyright (C) 2016-2017 Free Software Foundation, Inc.
++++ b/sysdeps/unix/sysv/linux/tst-sysconf-iov_max-uapi.c
+@@ -0,0 +1,27 @@
++/* Check IOV_MAX definition: Helper function to capture UAPI header value.
++   Copyright (C) 2017 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  published by the Free Software Foundation; either
++   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,
@@ -20729,191 +22403,930 @@ index 0000000000..094e05124b
 +   License along with the GNU C Library; if not, see
 +   <http://www.gnu.org/licenses/>.  */
 +
-+#include <bits/wordsize.h>
++/* Use a separate function to avoid header compatibility issues.  */
 +
-+#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32
-+# define __LONG_DOUBLE_MATH_OPTIONAL   1
-+# ifndef __LONG_DOUBLE_128__
-+#  define __NO_LONG_DOUBLE_MATH        1
-+# endif
-+#endif
-diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/glob64.c b/sysdeps/unix/sysv/linux/sparc/sparc32/glob64.c
-deleted file mode 100644
-index 82a9a296a7..0000000000
---- a/sysdeps/unix/sysv/linux/sparc/sparc32/glob64.c
-+++ /dev/null
-@@ -1 +0,0 @@
--#include <sysdeps/unix/sysv/linux/i386/glob64.c>
-diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h
++#include <linux/uio.h>
++
++long
++uio_maxiov_value (void)
++{
++  return UIO_MAXIOV;
++}
+diff --git a/sysdeps/unix/sysv/linux/tst-sysconf-iov_max.c b/sysdeps/unix/sysv/linux/tst-sysconf-iov_max.c
 new file mode 100644
-index 0000000000..094e05124b
+index 0000000000..dfdf3da484
 --- /dev/null
-+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h
-@@ -0,0 +1,26 @@
-+/* Properties of long double type.  SPARC version.
-+   Copyright (C) 2016-2017 Free Software Foundation, Inc.
++++ b/sysdeps/unix/sysv/linux/tst-sysconf-iov_max.c
+@@ -0,0 +1,40 @@
++/* Check IOV_MAX definition for consistency (bug 22321).
++   Copyright (C) 2017 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  published by the Free Software Foundation; either
++   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.
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++/* Defined in tst-sysconf-iov_max-uapi.c.  */
++long uio_maxiov_value (void);
++
++
++#include <limits.h>
++#include <support/check.h>
++#include <sys/uio.h>
++#include <unistd.h>
++
++static int
++do_test (void)
++{
++  TEST_VERIFY (_XOPEN_IOV_MAX == 16); /* Value required by POSIX.  */
++  TEST_VERIFY (uio_maxiov_value () >= _XOPEN_IOV_MAX);
++  TEST_VERIFY (IOV_MAX == uio_maxiov_value ());
++  TEST_VERIFY (UIO_MAXIOV == uio_maxiov_value ());
++  TEST_VERIFY (sysconf (_SC_UIO_MAXIOV) == uio_maxiov_value ());
++  TEST_VERIFY (sysconf (_SC_IOV_MAX) == uio_maxiov_value ());
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/sysdeps/unix/sysv/linux/tst-ttyname.c b/sysdeps/unix/sysv/linux/tst-ttyname.c
+new file mode 100644
+index 0000000000..0fdf1a8ccb
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/tst-ttyname.c
+@@ -0,0 +1,570 @@
++/* Copyright (C) 2017 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; see the file COPYING.LIB.  If
++   not, see <http://www.gnu.org/licenses/>.  */
++
++#include <dirent.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <limits.h>
++#include <sched.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/mount.h>
++#include <sys/prctl.h>
++#include <sys/stat.h>
++#include <sys/wait.h>
++#include <unistd.h>
++
++#include <support/check.h>
++#include <support/namespace.h>
++#include <support/support.h>
++#include <support/temp_file.h>
++#include <support/test-driver.h>
++#include <support/xunistd.h>
++
++/* generic utilities */
++
++#define VERIFY(expr)                                                    \
++  do {                                                                  \
++    if (!(expr))                                                        \
++      {                                                                 \
++        printf ("error: %s:%d: %s: %m\n",                               \
++                __FILE__, __LINE__, #expr);                             \
++        exit (1);                                                       \
++      }                                                                 \
++  } while (0)
++
++static void
++touch (const char *path, mode_t mode)
++{
++  xclose (xopen (path, O_WRONLY|O_CREAT|O_NOCTTY, mode));
++}
++
++static size_t
++trim_prefix (char *str, size_t str_len, const char *prefix)
++{
++  size_t prefix_len = strlen (prefix);
++  if (str_len > prefix_len && memcmp (str, prefix, prefix_len) == 0)
++    {
++      memmove (str, str + prefix_len, str_len - prefix_len);
++      return str_len - prefix_len;
++    }
++  return str_len;
++}
++
++/* returns a pointer to static storage */
++static char *
++proc_fd_readlink (const char *linkname)
++{
++  static char target[PATH_MAX+1];
++  ssize_t target_len = readlink (linkname, target, PATH_MAX);
++  VERIFY (target_len > 0);
++  target_len = trim_prefix (target, target_len, "(unreachable)");
++  target[target_len] = '\0';
++  return target;
++}
++
++/* plain ttyname runner */
++
++struct result
++{
++  const char *name;
++  int err;
++};
++
++/* strings in result structure are in static storage */
++static struct result
++run_ttyname (int fd)
++{
++  struct result ret;
++  errno = 0;
++  ret.name = ttyname (fd);
++  ret.err = errno;
++  return ret;
++}
++
++static bool
++eq_ttyname (struct result actual, struct result expected)
++{
++  char *actual_name, *expected_name;
++
++  if ((actual.err == expected.err) &&
++      (!actual.name == !expected.name) &&
++      (actual.name ? strcmp (actual.name, expected.name) == 0 : true))
++    {
++      if (expected.name)
++        expected_name = xasprintf ("\"%s\"", expected.name);
++      else
++	expected_name = xstrdup ("NULL");
++
++      printf ("info:      ttyname: PASS {name=%s, errno=%d}\n",
++	      expected_name, expected.err);
++
++      free (expected_name);
++      return true;
++    }
++
++  if (actual.name)
++    actual_name = xasprintf ("\"%s\"", actual.name);
++  else
++    actual_name = xstrdup ("NULL");
++
++  if (expected.name)
++    expected_name = xasprintf ("\"%s\"", expected.name);
++  else
++    expected_name = xstrdup ("NULL");
++
++  printf ("error:     ttyname: actual {name=%s, errno=%d} != expected {name=%s, errno=%d}\n",
++	  actual_name, actual.err,
++	  expected_name, expected.err);
++
++  free (actual_name);
++  free (expected_name);
++  return false;
++}
++
++/* ttyname_r runner */
++
++struct result_r
++{
++  const char *name;
++  int ret;
++  int err;
++};
++
++/* strings in result structure are in static storage */
++static struct result_r
++run_ttyname_r (int fd)
++{
++  static char buf[TTY_NAME_MAX];
++
++  struct result_r ret;
++  errno = 0;
++  ret.ret = ttyname_r (fd, buf, TTY_NAME_MAX);
++  ret.err = errno;
++  if (ret.ret == 0)
++    ret.name = buf;
++  else
++    ret.name = NULL;
++  return ret;
++}
++
++static bool
++eq_ttyname_r (struct result_r actual, struct result_r expected)
++{
++  char *actual_name, *expected_name;
++
++  if ((actual.err == expected.err) &&
++      (actual.ret == expected.ret) &&
++      (!actual.name == !expected.name) &&
++      (actual.name ? strcmp (actual.name, expected.name) == 0 : true))
++    {
++      if (expected.name)
++        expected_name = xasprintf ("\"%s\"", expected.name);
++      else
++        expected_name = xstrdup ("NULL");
++
++      printf ("info:      ttyname_r: PASS {name=%s, ret=%d, errno=%d}\n",
++              expected_name, expected.ret, expected.err);
++
++      free (expected_name);
++      return true;
++    }
++
++  if (actual.name)
++    actual_name = xasprintf ("\"%s\"", actual.name);
++  else
++    actual_name = xstrdup ("NULL");
++
++  if (expected.name)
++    expected_name = xasprintf ("\"%s\"", expected.name);
++  else
++    expected_name = xstrdup ("NULL");
++
++  printf ("error:     ttyname_r: actual {name=%s, ret=%d, errno=%d} != expected {name=%s, ret=%d, errno=%d}\n",
++	  actual_name, actual.ret, actual.err,
++	  expected_name, expected.ret, expected.err);
++
++  free (actual_name);
++  free (expected_name);
++  return false;
++}
++
++/* combined runner */
++
++static bool
++doit (int fd, const char *testname, struct result_r expected_r)
++{
++  struct result expected = {.name=expected_r.name, .err=expected_r.ret};
++  bool ret = true;
++
++  printf ("info:    testcase: %s\n", testname);
++
++  if (!eq_ttyname (run_ttyname (fd), expected))
++    ret = false;
++  if (!eq_ttyname_r (run_ttyname_r (fd), expected_r))
++    ret = false;
++
++  if (!ret)
++    support_record_failure ();
++
++  return ret;
++}
++
++/* chroot setup */
++
++static char *chrootdir;
++
++static void
++prepare (int argc, char **argv)
++{
++  chrootdir = xasprintf ("%s/tst-ttyname-XXXXXX", test_dir);
++  if (mkdtemp (chrootdir) == NULL)
++    FAIL_EXIT1 ("mkdtemp (\"%s\"): %m", chrootdir);
++  add_temp_file (chrootdir);
++}
++#define PREPARE prepare
++
++/* These chroot setup functions put the TTY at at "/console" (where it
++   won't be found by ttyname), and create "/dev/console" as an
++   ordinary file.  This way, it's easier to write test-cases that
++   expect ttyname to fail; test-cases that expect it to succeed need
++   to explicitly remount it at "/dev/console".  */
++
++static int
++do_in_chroot_1 (int (*cb)(const char *, int))
++{
++  printf ("info:  entering chroot 1\n");
++
++  /* Open the PTS that we'll be testing on.  */
++  int master;
++  char *slavename;
++  VERIFY ((master = posix_openpt (O_RDWR|O_NOCTTY|O_NONBLOCK)) >= 0);
++  VERIFY ((slavename = ptsname (master)));
++  VERIFY (unlockpt (master) == 0);
++  if (strncmp (slavename, "/dev/pts/", 9) != 0)
++    FAIL_UNSUPPORTED ("slave pseudo-terminal is not under /dev/pts/: %s",
++                      slavename);
++  int slave = xopen (slavename, O_RDWR, 0);
++  if (!doit (slave, "basic smoketest",
++             (struct result_r){.name=slavename, .ret=0, .err=0}))
++    return 1;
++
++  pid_t pid = xfork ();
++  if (pid == 0)
++    {
++      xclose (master);
 +
-+   You should have received a copy of the GNU Lesser General Public
-+   License along with the GNU C Library; if not, see
-+   <http://www.gnu.org/licenses/>.  */
++      if (!support_enter_mount_namespace ())
++	FAIL_UNSUPPORTED ("could not enter new mount namespace");
 +
-+#include <bits/wordsize.h>
++      VERIFY (mount ("tmpfs", chrootdir, "tmpfs", 0, "mode=755") == 0);
++      VERIFY (chdir (chrootdir) == 0);
 +
-+#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32
-+# define __LONG_DOUBLE_MATH_OPTIONAL   1
-+# ifndef __LONG_DOUBLE_128__
-+#  define __NO_LONG_DOUBLE_MATH        1
-+# endif
-+#endif
-diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
-index c56f894a82..7d23df84d2 100644
---- a/sysdeps/unix/sysv/linux/spawni.c
-+++ b/sysdeps/unix/sysv/linux/spawni.c
-@@ -17,7 +17,6 @@
-    <http://www.gnu.org/licenses/>.  */
- 
- #include <spawn.h>
--#include <assert.h>
- #include <fcntl.h>
- #include <paths.h>
- #include <string.h>
-@@ -268,7 +267,6 @@ __spawni_child (void *arguments)
-   __sigprocmask (SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK)
- 		 ? &attr->__ss : &args->oldmask, 0);
- 
--  args->err = 0;
-   args->exec (args->file, args->argv, args->envp);
- 
-   /* This is compatibility function required to enable posix_spawn run
-@@ -339,7 +337,7 @@ __spawnix (pid_t * pid, const char *file,
- 
-   /* Child must set args.err to something non-negative - we rely on
-      the parent and child sharing VM.  */
--  args.err = -1;
-+  args.err = 0;
-   args.file = file;
-   args.exec = exec;
-   args.fa = file_actions;
-@@ -362,12 +360,26 @@ __spawnix (pid_t * pid, const char *file,
-   new_pid = CLONE (__spawni_child, STACK (stack, stack_size), stack_size,
- 		   CLONE_VM | CLONE_VFORK | SIGCHLD, &args);
- 
-+  /* It needs to collect the case where the auxiliary process was created
-+     but failed to execute the file (due either any preparation step or
-+     for execve itself).  */
-   if (new_pid > 0)
-     {
-+      /* Also, it handles the unlikely case where the auxiliary process was
-+	 terminated before calling execve as if it was successfully.  The
-+	 args.err is set to 0 as default and changed to a positive value
-+	 only in case of failure, so in case of premature termination
-+	 due a signal args.err will remain zeroed and it will be up to
-+	 caller to actually collect it.  */
-       ec = args.err;
--      assert (ec >= 0);
--      if (ec != 0)
--	  __waitpid (new_pid, NULL, 0);
-+      if (ec > 0)
-+	/* There still an unlikely case where the child is cancelled after
-+	   setting args.err, due to a positive error value.  Also there is
-+	   possible pid reuse race (where the kernel allocated the same pid
-+	   to an unrelated process).  Unfortunately due synchronization
-+	   issues where the kernel might not have the process collected
-+	   the waitpid below can not use WNOHANG.  */
-+	__waitpid (new_pid, NULL, 0);
-     }
-   else
-     ec = -new_pid;
-diff --git a/sysdeps/unix/sysv/linux/tst-sysconf-iov_max-uapi.c b/sysdeps/unix/sysv/linux/tst-sysconf-iov_max-uapi.c
-new file mode 100644
-index 0000000000..1240b846e6
---- /dev/null
-+++ b/sysdeps/unix/sysv/linux/tst-sysconf-iov_max-uapi.c
-@@ -0,0 +1,27 @@
-+/* Check IOV_MAX definition: Helper function to capture UAPI header value.
-+   Copyright (C) 2017 Free Software Foundation, Inc.
-+   This file is part of the GNU C Library.
++      xmkdir ("proc", 0755);
++      xmkdir ("dev", 0755);
++      xmkdir ("dev/pts", 0755);
 +
-+   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.
++      VERIFY (mount ("/proc", "proc", NULL, MS_BIND|MS_REC, NULL) == 0);
++      VERIFY (mount ("devpts", "dev/pts", "devpts",
++                     MS_NOSUID|MS_NOEXEC,
++                     "newinstance,ptmxmode=0666,mode=620") == 0);
++      VERIFY (symlink ("pts/ptmx", "dev/ptmx") == 0);
 +
-+   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.
++      touch ("console", 0);
++      touch ("dev/console", 0);
++      VERIFY (mount (slavename, "console", NULL, MS_BIND, NULL) == 0);
 +
-+   You should have received a copy of the GNU Lesser General Public
-+   License along with the GNU C Library; if not, see
-+   <http://www.gnu.org/licenses/>.  */
++      xchroot (".");
 +
-+/* Use a separate function to avoid header compatibility issues.  */
++      char *linkname = xasprintf ("/proc/self/fd/%d", slave);
++      char *target = proc_fd_readlink (linkname);
++      VERIFY (strcmp (target, slavename) == 0);
++      free (linkname);
 +
-+#include <linux/uio.h>
++      _exit (cb (slavename, slave));
++    }
++  int status;
++  xwaitpid (pid, &status, 0);
++  VERIFY (WIFEXITED (status));
++  xclose (master);
++  xclose (slave);
++  return WEXITSTATUS (status);
++}
 +
-+long
-+uio_maxiov_value (void)
++static int
++do_in_chroot_2 (int (*cb)(const char *, int))
 +{
-+  return UIO_MAXIOV;
++  printf ("info:  entering chroot 2\n");
++
++  int pid_pipe[2];
++  xpipe (pid_pipe);
++  int exit_pipe[2];
++  xpipe (exit_pipe);
++
++  /* Open the PTS that we'll be testing on.  */
++  int master;
++  char *slavename;
++  VERIFY ((master = posix_openpt (O_RDWR|O_NOCTTY|O_NONBLOCK)) >= 0);
++  VERIFY ((slavename = ptsname (master)));
++  VERIFY (unlockpt (master) == 0);
++  if (strncmp (slavename, "/dev/pts/", 9) != 0)
++    FAIL_UNSUPPORTED ("slave pseudo-terminal is not under /dev/pts/: %s",
++                      slavename);
++  /* wait until in a new mount ns to open the slave */
++
++  /* enable `wait`ing on grandchildren */
++  VERIFY (prctl (PR_SET_CHILD_SUBREAPER, 1) == 0);
++
++  pid_t pid = xfork (); /* outer child */
++  if (pid == 0)
++    {
++      xclose (master);
++      xclose (pid_pipe[0]);
++      xclose (exit_pipe[1]);
++
++      if (!support_enter_mount_namespace ())
++	FAIL_UNSUPPORTED ("could not enter new mount namespace");
++
++      int slave = xopen (slavename, O_RDWR, 0);
++      if (!doit (slave, "basic smoketest",
++                 (struct result_r){.name=slavename, .ret=0, .err=0}))
++        _exit (1);
++
++      VERIFY (mount ("tmpfs", chrootdir, "tmpfs", 0, "mode=755") == 0);
++      VERIFY (chdir (chrootdir) == 0);
++
++      xmkdir ("proc", 0755);
++      xmkdir ("dev", 0755);
++      xmkdir ("dev/pts", 0755);
++
++      VERIFY (mount ("devpts", "dev/pts", "devpts",
++                     MS_NOSUID|MS_NOEXEC,
++                     "newinstance,ptmxmode=0666,mode=620") == 0);
++      VERIFY (symlink ("pts/ptmx", "dev/ptmx") == 0);
++
++      touch ("console", 0);
++      touch ("dev/console", 0);
++      VERIFY (mount (slavename, "console", NULL, MS_BIND, NULL) == 0);
++
++      xchroot (".");
++
++      if (unshare (CLONE_NEWNS | CLONE_NEWPID) < 0)
++        FAIL_UNSUPPORTED ("could not enter new PID namespace");
++      pid = xfork (); /* inner child */
++      if (pid == 0)
++        {
++          xclose (pid_pipe[1]);
++
++          /* wait until the outer child has exited */
++          char c;
++          VERIFY (read (exit_pipe[0], &c, 1) == 0);
++          xclose (exit_pipe[0]);
++
++          VERIFY (mount ("proc", "/proc", "proc",
++                         MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) == 0);
++
++          char *linkname = xasprintf ("/proc/self/fd/%d", slave);
++          char *target = proc_fd_readlink (linkname);
++          VERIFY (strcmp (target, strrchr (slavename, '/')) == 0);
++          free (linkname);
++
++          _exit (cb (slavename, slave));
++        }
++      xwrite (pid_pipe[1], &pid, sizeof pid);
++      _exit (0);
++    }
++  xclose (pid_pipe[1]);
++  xclose (exit_pipe[0]);
++  xclose (exit_pipe[1]);
++
++  /* wait for the outer child */
++  int status;
++  xwaitpid (pid, &status, 0);
++  VERIFY (WIFEXITED (status));
++  int ret = WEXITSTATUS (status);
++  if (ret != 0)
++    return ret;
++
++  /* set 'pid' to the inner child */
++  VERIFY (read (pid_pipe[0], &pid, sizeof pid) == sizeof pid);
++  xclose (pid_pipe[0]);
++
++  /* wait for the inner child */
++  xwaitpid (pid, &status, 0);
++  VERIFY (WIFEXITED (status));
++  xclose (master);
++  return WEXITSTATUS (status);
 +}
-diff --git a/sysdeps/unix/sysv/linux/tst-sysconf-iov_max.c b/sysdeps/unix/sysv/linux/tst-sysconf-iov_max.c
-new file mode 100644
-index 0000000000..dfdf3da484
---- /dev/null
-+++ b/sysdeps/unix/sysv/linux/tst-sysconf-iov_max.c
-@@ -0,0 +1,40 @@
-+/* Check IOV_MAX definition for consistency (bug 22321).
-+   Copyright (C) 2017 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.
++/* main test */
 +
-+   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.
++static int
++run_chroot_tests (const char *slavename, int slave)
++{
++  struct stat st;
++  bool ok = true;
 +
-+   You should have received a copy of the GNU Lesser General Public
-+   License along with the GNU C Library; if not, see
-+   <http://www.gnu.org/licenses/>.  */
++  /* There are 3 groups of tests here.  The first group fairly
++     generically does things known to mess up ttyname, and verifies
++     that ttyname copes correctly.  The remaining groups are
++     increasingly convoluted, as we target specific parts of ttyname
++     to try to confuse.  */
 +
-+/* Defined in tst-sysconf-iov_max-uapi.c.  */
-+long uio_maxiov_value (void);
++  /* Basic tests that it doesn't get confused by multiple devpts
++     instances.  */
++  {
++    VERIFY (stat (slavename, &st) < 0); /* sanity check */
++    if (!doit (slave, "no conflict, no match",
++               (struct result_r){.name=NULL, .ret=ENODEV, .err=ENODEV}))
++      ok = false;
++    VERIFY (mount ("/console", "/dev/console", NULL, MS_BIND, NULL) == 0);
++    if (!doit (slave, "no conflict, console",
++               (struct result_r){.name="/dev/console", .ret=0, .err=0}))
++      ok = false;
++    VERIFY (umount ("/dev/console") == 0);
++
++    /* keep creating PTYs until we we get a name collision */
++    while (stat (slavename, &st) < 0)
++      posix_openpt (O_RDWR|O_NOCTTY|O_NONBLOCK);
++    VERIFY (stat (slavename, &st) == 0);
++
++    if (!doit (slave, "conflict, no match",
++               (struct result_r){.name=NULL, .ret=ENODEV, .err=ENODEV}))
++      ok = false;
++    VERIFY (mount ("/console", "/dev/console", NULL, MS_BIND, NULL) == 0);
++    if (!doit (slave, "conflict, console",
++               (struct result_r){.name="/dev/console", .ret=0, .err=0}))
++      ok = false;
++    VERIFY (umount ("/dev/console") == 0);
++  }
 +
++  /* The first tests kinda assumed that they hit certain code-paths
++     based on assuming that the readlink target is 'slavename', but
++     that's not quite always true.  They're still a good preliminary
++     sanity check, so keep them, but let's add tests that make sure
++     that those code-paths are hit by doing a readlink ourself.  */
++  {
++    char *linkname = xasprintf ("/proc/self/fd/%d", slave);
++    char *target = proc_fd_readlink (linkname);
++    free (linkname);
++    /* Depeding on how we set up the chroot, the kernel may or may not
++       trim the leading path to the target (it may give us "/6",
++       instead of "/dev/pts/6").  We test it both ways (do_in_chroot_1
++       and do_in_chroot_2).  This test group relies on the target
++       existing, so guarantee that it does exist by creating it if
++       necessary.  */
++    if (stat (target, &st) < 0)
++      {
++        VERIFY (errno == ENOENT);
++        touch (target, 0);
++      }
 +
-+#include <limits.h>
-+#include <support/check.h>
-+#include <sys/uio.h>
-+#include <unistd.h>
++    VERIFY (mount ("/console", "/dev/console", NULL, MS_BIND, NULL) == 0);
++    VERIFY (mount ("/console", target, NULL, MS_BIND, NULL) == 0);
++    if (!doit (slave, "with readlink target",
++               (struct result_r){.name=target, .ret=0, .err=0}))
++      ok = false;
++    VERIFY (umount (target) == 0);
++    VERIFY (umount ("/dev/console") == 0);
++
++    VERIFY (mount ("/console", "/dev/console", NULL, MS_BIND, NULL) == 0);
++    VERIFY (mount (slavename, target, NULL, MS_BIND, NULL) == 0);
++    if (!doit (slave, "with readlink trap; fallback",
++               (struct result_r){.name="/dev/console", .ret=0, .err=0}))
++      ok = false;
++    VERIFY (umount (target) == 0);
++    VERIFY (umount ("/dev/console") == 0);
++
++    VERIFY (mount (slavename, target, NULL, MS_BIND, NULL) == 0);
++    if (!doit (slave, "with readlink trap; no fallback",
++               (struct result_r){.name=NULL, .ret=ENODEV, .err=ENODEV}))
++      ok = false;
++    VERIFY (umount (target) == 0);
++  }
++
++  /* This test makes sure that everything still works OK if readdir
++     finds a pseudo-match before and/or after the actual match.  Now,
++     to do that, we need to control that readdir finds the
++     pseudo-matches before and after the actual match; and there's no
++     good way to control that order in absence of whitebox testing.
++     So, just create 3 files, then use opendir/readdir to see what
++     order they are in, and assign meaning based on that order, not by
++     name; assigning the first to be a pseudo-match, the second to be
++     the actual match, and the third to be a pseudo-match.  This
++     assumes that (on tmpfs) ordering within the directory is stable
++     in the absence of modification, which seems reasonably safe.  */
++  {
++    /* since we're testing the fallback search, disable the readlink
++       happy-path */
++    VERIFY (umount2 ("/proc", MNT_DETACH) == 0);
++
++    touch ("/dev/console1", 0);
++    touch ("/dev/console2", 0);
++    touch ("/dev/console3", 0);
++
++    char *c[3];
++    int ci = 0;
++    DIR *dirstream = opendir ("/dev");
++    VERIFY (dirstream != NULL);
++    struct dirent *d;
++    while ((d = readdir (dirstream)) != NULL && ci < 3)
++      {
++        if (strcmp (d->d_name, "console1") &&
++            strcmp (d->d_name, "console2") &&
++            strcmp (d->d_name, "console3") )
++          continue;
++        c[ci++] = xasprintf ("/dev/%s", d->d_name);
++      }
++    VERIFY (ci == 3);
++    VERIFY (closedir (dirstream) == 0);
++
++    VERIFY (mount (slavename, c[0], NULL, MS_BIND, NULL) == 0);
++    VERIFY (mount ("/console", c[1], NULL, MS_BIND, NULL) == 0);
++    VERIFY (mount (slavename, c[2], NULL, MS_BIND, NULL) == 0);
++    VERIFY (umount2 ("/dev/pts", MNT_DETACH) == 0);
++    if (!doit (slave, "with search-path trap",
++               (struct result_r){.name=c[1], .ret=0, .err=0}))
++      ok = false;
++    for (int i = 0; i < 3; i++)
++      {
++        VERIFY (umount (c[i]) == 0);
++        VERIFY (unlink (c[i]) == 0);
++        free (c[i]);
++      }
++  }
++
++  return ok ? 0 : 1;
++}
 +
 +static int
 +do_test (void)
 +{
-+  TEST_VERIFY (_XOPEN_IOV_MAX == 16); /* Value required by POSIX.  */
-+  TEST_VERIFY (uio_maxiov_value () >= _XOPEN_IOV_MAX);
-+  TEST_VERIFY (IOV_MAX == uio_maxiov_value ());
-+  TEST_VERIFY (UIO_MAXIOV == uio_maxiov_value ());
-+  TEST_VERIFY (sysconf (_SC_UIO_MAXIOV) == uio_maxiov_value ());
-+  TEST_VERIFY (sysconf (_SC_IOV_MAX) == uio_maxiov_value ());
-+  return 0;
++  support_become_root ();
++
++  int ret1 = do_in_chroot_1 (run_chroot_tests);
++  if (ret1 == EXIT_UNSUPPORTED)
++    return ret1;
++
++  int ret2 = do_in_chroot_2 (run_chroot_tests);
++  if (ret2 == EXIT_UNSUPPORTED)
++    return ret2;
++
++  return  ret1 | ret2;
 +}
 +
 +#include <support/test-driver.c>
+diff --git a/sysdeps/unix/sysv/linux/ttyname.c b/sysdeps/unix/sysv/linux/ttyname.c
+index 5909cb765f..f4c955f25b 100644
+--- a/sysdeps/unix/sysv/linux/ttyname.c
++++ b/sysdeps/unix/sysv/linux/ttyname.c
+@@ -35,16 +35,14 @@
+ char *__ttyname;
+ #endif
+ 
+-static char *getttyname (const char *dev, dev_t mydev,
+-			 ino64_t myino, int save, int *dostat)
+-     internal_function;
+-
++static char *getttyname (const char *dev, const struct stat64 *mytty,
++			 int save, int *dostat);
+ 
+ libc_freeres_ptr (static char *getttyname_name);
+ 
+ static char *
+-internal_function attribute_compat_text_section
+-getttyname (const char *dev, dev_t mydev, ino64_t myino, int save, int *dostat)
++attribute_compat_text_section
++getttyname (const char *dev, const struct stat64 *mytty, int save, int *dostat)
+ {
+   static size_t namelen;
+   struct stat64 st;
+@@ -65,7 +63,7 @@ getttyname (const char *dev, dev_t mydev, ino64_t myino, int save, int *dostat)
+     *((char *) __mempcpy (getttyname_name, dev, devlen - 1)) = '/';
+ 
+   while ((d = __readdir64 (dirstream)) != NULL)
+-    if ((d->d_fileno == myino || *dostat)
++    if ((d->d_fileno == mytty->st_ino || *dostat)
+ 	&& strcmp (d->d_name, "stdin")
+ 	&& strcmp (d->d_name, "stdout")
+ 	&& strcmp (d->d_name, "stderr"))
+@@ -87,12 +85,7 @@ getttyname (const char *dev, dev_t mydev, ino64_t myino, int save, int *dostat)
+ 	  }
+ 	memcpy (&getttyname_name[devlen], d->d_name, dlen);
+ 	if (__xstat64 (_STAT_VER, getttyname_name, &st) == 0
+-#ifdef _STATBUF_ST_RDEV
+-	    && S_ISCHR (st.st_mode) && st.st_rdev == mydev
+-#else
+-	    && d->d_fileno == myino && st.st_dev == mydev
+-#endif
+-	   )
++	    && is_mytty (mytty, &st))
+ 	  {
+ 	    (void) __closedir (dirstream);
+ #if 0
+@@ -122,6 +115,7 @@ ttyname (int fd)
+   char procname[30];
+   struct stat64 st, st1;
+   int dostat = 0;
++  int doispty = 0;
+   char *name;
+   int save = errno;
+   struct termios term;
+@@ -169,30 +163,15 @@ ttyname (int fd)
+       /* Verify readlink result, fall back on iterating through devices.  */
+       if (ttyname_buf[0] == '/'
+ 	  && __xstat64 (_STAT_VER, ttyname_buf, &st1) == 0
+-#ifdef _STATBUF_ST_RDEV
+-	  && S_ISCHR (st1.st_mode)
+-	  && st1.st_rdev == st.st_rdev
+-#endif
+-	  && st1.st_ino == st.st_ino
+-	  && st1.st_dev == st.st_dev)
++	  && is_mytty (&st, &st1))
+ 	return ttyname_buf;
+ 
+-      /* If the link doesn't exist, then it points to a device in another
+-	 namespace. */
+-      if (is_pty (&st))
+-	{
+-	  __set_errno (ENODEV);
+-	  return NULL;
+-	}
++      doispty = 1;
+     }
+ 
+   if (__xstat64 (_STAT_VER, "/dev/pts", &st1) == 0 && S_ISDIR (st1.st_mode))
+     {
+-#ifdef _STATBUF_ST_RDEV
+-      name = getttyname ("/dev/pts", st.st_rdev, st.st_ino, save, &dostat);
+-#else
+-      name = getttyname ("/dev/pts", st.st_dev, st.st_ino, save, &dostat);
+-#endif
++      name = getttyname ("/dev/pts", &st, save, &dostat);
+     }
+   else
+     {
+@@ -202,21 +181,23 @@ ttyname (int fd)
+ 
+   if (!name && dostat != -1)
+     {
+-#ifdef _STATBUF_ST_RDEV
+-      name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat);
+-#else
+-      name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat);
+-#endif
++      name = getttyname ("/dev", &st, save, &dostat);
+     }
+ 
+   if (!name && dostat != -1)
+     {
+       dostat = 1;
+-#ifdef _STATBUF_ST_RDEV
+-      name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat);
+-#else
+-      name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat);
+-#endif
++      name = getttyname ("/dev", &st, save, &dostat);
++    }
++
++  if (!name && doispty && is_pty (&st))
++    {
++      /* We failed to figure out the TTY's name, but we can at least
++         signal that we did verify that it really is a PTY slave.
++         This happens when we have inherited the file descriptor from
++         a different mount namespace.  */
++      __set_errno (ENODEV);
++      return NULL;
+     }
+ 
+   return name;
+diff --git a/sysdeps/unix/sysv/linux/ttyname.h b/sysdeps/unix/sysv/linux/ttyname.h
+index 2e415e4e9c..48181330a9 100644
+--- a/sysdeps/unix/sysv/linux/ttyname.h
++++ b/sysdeps/unix/sysv/linux/ttyname.h
+@@ -16,13 +16,15 @@
+    not, see <http://www.gnu.org/licenses/>.  */
+ 
+ #include <unistd.h>
++#include <stdbool.h>
+ #include <sys/sysmacros.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ 
+ /* Return true if this is a UNIX98 pty device, as defined in
+-   linux/Documentation/devices.txt.  */
+-static inline int
++   linux/Documentation/devices.txt (on linux < 4.10) or
++   linux/Documentation/admin-guide/devices.txt (on linux >= 4.10).  */
++static inline bool
+ is_pty (struct stat64 *sb)
+ {
+ #ifdef _STATBUF_ST_RDEV
+@@ -32,3 +34,15 @@ is_pty (struct stat64 *sb)
+   return false;
+ #endif
+ }
++
++static inline bool
++is_mytty (const struct stat64 *mytty, const struct stat64 *maybe)
++{
++  return (maybe->st_ino == mytty->st_ino
++	  && maybe->st_dev == mytty->st_dev
++#ifdef _STATBUF_ST_RDEV
++	  && S_ISCHR (maybe->st_mode)
++	  && maybe->st_rdev == mytty->st_rdev
++#endif
++	  );
++}
+diff --git a/sysdeps/unix/sysv/linux/ttyname_r.c b/sysdeps/unix/sysv/linux/ttyname_r.c
+index dc863526ba..00eefc2c5c 100644
+--- a/sysdeps/unix/sysv/linux/ttyname_r.c
++++ b/sysdeps/unix/sysv/linux/ttyname_r.c
+@@ -31,12 +31,12 @@
+ #include "ttyname.h"
+ 
+ static int getttyname_r (char *buf, size_t buflen,
+-			 dev_t mydev, ino64_t myino, int save,
+-			 int *dostat) internal_function;
++			 const struct stat64 *mytty, int save,
++			 int *dostat);
+ 
+ static int
+-internal_function attribute_compat_text_section
+-getttyname_r (char *buf, size_t buflen, dev_t mydev, ino64_t myino,
++attribute_compat_text_section
++getttyname_r (char *buf, size_t buflen, const struct stat64 *mytty,
+ 	      int save, int *dostat)
+ {
+   struct stat64 st;
+@@ -52,7 +52,7 @@ getttyname_r (char *buf, size_t buflen, dev_t mydev, ino64_t myino,
+     }
+ 
+   while ((d = __readdir64 (dirstream)) != NULL)
+-    if ((d->d_fileno == myino || *dostat)
++    if ((d->d_fileno == mytty->st_ino || *dostat)
+ 	&& strcmp (d->d_name, "stdin")
+ 	&& strcmp (d->d_name, "stdout")
+ 	&& strcmp (d->d_name, "stderr"))
+@@ -72,12 +72,7 @@ getttyname_r (char *buf, size_t buflen, dev_t mydev, ino64_t myino,
+ 	cp[0] = '\0';
+ 
+ 	if (__xstat64 (_STAT_VER, buf, &st) == 0
+-#ifdef _STATBUF_ST_RDEV
+-	    && S_ISCHR (st.st_mode) && st.st_rdev == mydev
+-#else
+-	    && d->d_fileno == myino && st.st_dev == mydev
+-#endif
+-	   )
++	    && is_mytty (mytty, &st))
+ 	  {
+ 	    (void) __closedir (dirstream);
+ 	    __set_errno (save);
+@@ -100,6 +95,7 @@ __ttyname_r (int fd, char *buf, size_t buflen)
+   char procname[30];
+   struct stat64 st, st1;
+   int dostat = 0;
++  int doispty = 0;
+   int save = errno;
+ 
+   /* Test for the absolute minimal size.  This makes life easier inside
+@@ -151,22 +147,10 @@ __ttyname_r (int fd, char *buf, size_t buflen)
+       /* Verify readlink result, fall back on iterating through devices.  */
+       if (buf[0] == '/'
+ 	  && __xstat64 (_STAT_VER, buf, &st1) == 0
+-#ifdef _STATBUF_ST_RDEV
+-	  && S_ISCHR (st1.st_mode)
+-	  && st1.st_rdev == st.st_rdev
+-#endif
+-	  && st1.st_ino == st.st_ino
+-	  && st1.st_dev == st.st_dev)
++	  && is_mytty (&st, &st1))
+ 	return 0;
+ 
+-      /* If the link doesn't exist, then it points to a device in another
+-       * namespace.
+-       */
+-      if (is_pty (&st))
+-	{
+-	  __set_errno (ENODEV);
+-	  return ENODEV;
+-	}
++      doispty = 1;
+     }
+ 
+   /* Prepare the result buffer.  */
+@@ -175,13 +159,8 @@ __ttyname_r (int fd, char *buf, size_t buflen)
+ 
+   if (__xstat64 (_STAT_VER, buf, &st1) == 0 && S_ISDIR (st1.st_mode))
+     {
+-#ifdef _STATBUF_ST_RDEV
+-      ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save,
++      ret = getttyname_r (buf, buflen, &st, save,
+ 			  &dostat);
+-#else
+-      ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save,
+-			  &dostat);
+-#endif
+     }
+   else
+     {
+@@ -193,26 +172,26 @@ __ttyname_r (int fd, char *buf, size_t buflen)
+     {
+       buf[sizeof ("/dev/") - 1] = '\0';
+       buflen += sizeof ("pts/") - 1;
+-#ifdef _STATBUF_ST_RDEV
+-      ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save,
+-			  &dostat);
+-#else
+-      ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save,
++      ret = getttyname_r (buf, buflen, &st, save,
+ 			  &dostat);
+-#endif
+     }
+ 
+   if (ret && dostat != -1)
+     {
+       buf[sizeof ("/dev/") - 1] = '\0';
+       dostat = 1;
+-#ifdef _STATBUF_ST_RDEV
+-      ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino,
++      ret = getttyname_r (buf, buflen, &st,
+ 			  save, &dostat);
+-#else
+-      ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino,
+-			  save, &dostat);
+-#endif
++    }
++
++  if (ret && doispty && is_pty (&st))
++    {
++      /* We failed to figure out the TTY's name, but we can at least
++         signal that we did verify that it really is a PTY slave.
++         This happens when we have inherited the file descriptor from
++         a different mount namespace.  */
++      __set_errno (ENODEV);
++      return ENODEV;
+     }
+ 
+   return ret;
 diff --git a/sysdeps/unix/sysv/linux/wordsize-64/glob64.c b/sysdeps/unix/sysv/linux/wordsize-64/glob64.c
 deleted file mode 100644
 index eab7703d5c..0000000000

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-glibc/glibc.git


Reply to: