public inbox for libc-stable@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 2.22 08/14] <array_length.h>: New array_length and array_end macros
  2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
@ 2018-01-01  0:00 ` Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 09/14] elf: Compute correct array size in _dl_init_paths [BZ #22606] Raphael Moreira Zinsly
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: libc-stable

From: Florian Weimer <fweimer@redhat.com>

(cherry picked from commit c94a5688fb1228a862b2d4a3f1239cdc0e3349e5)
---
 ChangeLog              |  5 +++++
 include/array_length.h | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+)
 create mode 100644 include/array_length.h

diff --git a/ChangeLog b/ChangeLog
index 40c0c60..48fc023 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2017-11-02  Florian Weimer  <fweimer@redhat.com>
+
+	Add array_length and array_end macros.
+	* include/array_length.h: New file.
+
 2017-12-14  Florian Weimer  <fweimer@redhat.com>
 
 	[BZ #22607]
diff --git a/include/array_length.h b/include/array_length.h
new file mode 100644
index 0000000..cb4a8b2
--- /dev/null
+++ b/include/array_length.h
@@ -0,0 +1,36 @@
+/* The array_length and array_end macros.
+   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 _ARRAY_LENGTH_H
+#define _ARRAY_LENGTH_H
+
+/* array_length (VAR) is the number of elements in the array VAR.  VAR
+   must evaluate to an array, not a pointer.  */
+#define array_length(var)                                               \
+  __extension__ ({                                                      \
+    _Static_assert (!__builtin_types_compatible_p                       \
+                    (__typeof (var), __typeof (&(var)[0])),             \
+                    "argument must be an array");                       \
+    sizeof (var) / sizeof ((var)[0]);                                   \
+  })
+
+/* array_end (VAR) is a pointer one past the end of the array VAR.
+   VAR must evaluate to an array, not a pointer.  */
+#define array_end(var) (&(var)[array_length (var)])
+
+#endif /* _ARRAY_LENGTH_H */
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22 13/14] Record CVE-2018-6485 in ChangeLog and NEWS [BZ #22343]
  2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
                   ` (12 preceding siblings ...)
  2018-01-01  0:00 ` [PATCH 2.22 04/14] sunrpc: Avoid use-after-free read access in clntudp_call [BZ #21115] Raphael Moreira Zinsly
@ 2018-01-01  0:00 ` Raphael Moreira Zinsly
  13 siblings, 0 replies; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: libc-stable

From: Florian Weimer <fweimer@redhat.com>

(cherry picked from commit 4590634fd65162568b9f52fb4beb60aa25da37f2)
---
 ChangeLog | 1 +
 NEWS      | 4 ++++
 2 files changed, 5 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 05ef3fd..162c5da 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,6 +10,7 @@
 2018-01-18  Arjun Shankar  <arjun@redhat.com>
 
 	[BZ #22343]
+	CVE-2018-6485
 	* malloc/malloc.c (checked_request2size): call REQUEST_OUT_OF_RANGE
 	after padding.
 	(_int_memalign): check for integer overflow before calling
diff --git a/NEWS b/NEWS
index 2d703f2..d151e13 100644
--- a/NEWS
+++ b/NEWS
@@ -100,6 +100,10 @@ Version 2.22.1
   vulnerability; only trusted binaries must be examined using the ldd
   script.)
 
+* CVE-2018-6485: The posix_memalign and memalign functions, when called with
+  an object size near the value of SIZE_MAX, would return a pointer to a
+  buffer which is too small, instead of NULL.  Reported by Jakub Wilk.
+
 \f
 Version 2.22
 
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2.22 01/14] ldd: never run file directly
  2018-01-01  0:00 ` [PATCH 2.22 01/14] ldd: never run file directly Carlos O'Donell
@ 2018-01-01  0:00   ` Tulio Magno Quites Machado Filho
  0 siblings, 0 replies; 26+ messages in thread
From: Tulio Magno Quites Machado Filho @ 2018-01-01  0:00 UTC (permalink / raw)
  To: Carlos O'Donell, Raphael Moreira Zinsly, libc-stable

Carlos O'Donell <carlos@redhat.com> writes:

> On 03/28/2018 03:43 PM, Raphael Moreira Zinsly wrote:
>> From: Andreas Schwab <schwab@suse.de>
>> 
>> (cherry picked from commit eedca9772e99c72ab4c3c34e43cc764250aa3e3c)
> Is the goal of this patchset to backport 14 patches from master to
> the stable 2.22 branch?

Yes.

> Note that by consensus you can just do the backport to 2.22, for what
> I assume is IBM Advance Toolchain 9.0 uses (which uses 2.22).

That information is right.

I'll wait until Monday for any objections and will push them.

Thanks!

-- 
Tulio Magno

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22 14/14] Record CVE-2018-6551 in NEWS and ChangeLog [BZ #22774]
  2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
                   ` (5 preceding siblings ...)
  2018-01-01  0:00 ` [PATCH 2.22 01/14] ldd: never run file directly Carlos O'Donell
@ 2018-01-01  0:00 ` Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 11/14] linux: make getcwd(3) fail if it cannot obtain an absolute path [BZ #22679] Raphael Moreira Zinsly
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: libc-stable

From: Florian Weimer <fweimer@redhat.com>

(cherry picked from commit 71aa429b029fdb6f9e65d44050388b51eca460d6)
---
 ChangeLog | 2 ++
 NEWS      | 4 ++++
 2 files changed, 6 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 162c5da..bbf02ac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,7 +10,9 @@
 2018-01-18  Arjun Shankar  <arjun@redhat.com>
 
 	[BZ #22343]
+	[BZ #22774]
 	CVE-2018-6485
+	CVE-2018-6551
 	* malloc/malloc.c (checked_request2size): call REQUEST_OUT_OF_RANGE
 	after padding.
 	(_int_memalign): check for integer overflow before calling
diff --git a/NEWS b/NEWS
index d151e13..a8f115f 100644
--- a/NEWS
+++ b/NEWS
@@ -104,6 +104,10 @@ Version 2.22.1
   an object size near the value of SIZE_MAX, would return a pointer to a
   buffer which is too small, instead of NULL.  Reported by Jakub Wilk.
 
+* CVE-2018-6551: The malloc function, when called with an object size near
+  the value of SIZE_MAX, would return a pointer to a buffer which is too
+  small, instead of NULL.
+
 \f
 Version 2.22
 
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22 04/14] sunrpc: Avoid use-after-free read access in clntudp_call [BZ #21115]
  2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
                   ` (11 preceding siblings ...)
  2018-01-01  0:00 ` [PATCH 2.22 07/14] elf: Count components of the expanded path in _dl_init_path [BZ #22607] Raphael Moreira Zinsly
@ 2018-01-01  0:00 ` Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 13/14] Record CVE-2018-6485 in ChangeLog and NEWS [BZ #22343] Raphael Moreira Zinsly
  13 siblings, 0 replies; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: libc-stable

From: Florian Weimer <fweimer@redhat.com>

After commit bc779a1a5b3035133024b21e2f339fe4219fb11c
(CVE-2016-4429: sunrpc: Do not use alloca in clntudp_call
[BZ #20112]), ancillary data is stored on the heap,
but it is accessed after it has been freed.

The test case must be run under a heap debugger such as valgrind
to observe the invalid access.  A malloc implementation which
immediately calls munmap on free would catch this bug as well.

(cherry picked from commit d42eed4a044e5e10dfb885cf9891c2518a72a491)
---
 ChangeLog              |  8 +++++++
 NEWS                   |  3 +++
 sunrpc/Makefile        |  3 ++-
 sunrpc/clnt_udp.c      |  2 +-
 sunrpc/tst-udp-error.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 76 insertions(+), 2 deletions(-)
 create mode 100644 sunrpc/tst-udp-error.c

diff --git a/ChangeLog b/ChangeLog
index 0e07eb2..7af97cd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2017-02-27  Florian Weimer  <fweimer@redhat.com>
+
+	[BZ #21115]
+	* sunrpc/clnt_udp.c (clntudp_call): Free ancillary data later.
+	* sunrpc/Makefile (tests): Add tst-udp-error.
+	(tst-udp-error): Link against libc.so explicitly.
+	* sunrpc/tst-udp-error: New file.
+
 2017-10-21  Florian Weimer  <fweimer@redhat.com>
 
 	* posix/Makefile (tests): Add tst-glob-tilde.
diff --git a/NEWS b/NEWS
index 069b3ea..ef34252 100644
--- a/NEWS
+++ b/NEWS
@@ -68,6 +68,9 @@ Version 2.22.1
   from a one-byte overflow during ~ operator processing (either on the stack
   or the heap, depending on the length of the user name).
 
+* A use-after-free vulnerability in clntudp_call in the Sun RPC system has been
+  fixed (CVE-2017-12133).
+
 \f
 Version 2.22
 
diff --git a/sunrpc/Makefile b/sunrpc/Makefile
index 60caa0a..4f74f27 100644
--- a/sunrpc/Makefile
+++ b/sunrpc/Makefile
@@ -96,7 +96,7 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \
 extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
 others += rpcgen
 
-tests = tst-xdrmem tst-xdrmem2 test-rpcent
+tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error
 xtests := tst-getmyaddr
 
 ifeq ($(have-thread-library),yes)
@@ -153,6 +153,7 @@ BUILD_CPPFLAGS += $(sunrpc-CPPFLAGS)
 $(objpfx)tst-getmyaddr: $(common-objpfx)linkobj/libc.so
 $(objpfx)tst-xdrmem: $(common-objpfx)linkobj/libc.so
 $(objpfx)tst-xdrmem2: $(common-objpfx)linkobj/libc.so
+$(objpfx)tst-udp-error: $(common-objpfx)linkobj/libc.so
 
 $(objpfx)rpcgen: $(addprefix $(objpfx),$(rpcgen-objs))
 
diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c
index c818caf..30613e3 100644
--- a/sunrpc/clnt_udp.c
+++ b/sunrpc/clnt_udp.c
@@ -453,9 +453,9 @@ send_again:
 		 cmsg = CMSG_NXTHDR (&msg, cmsg))
 	      if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
 		{
-		  free (cbuf);
 		  e = (struct sock_extended_err *) CMSG_DATA(cmsg);
 		  cu->cu_error.re_errno = e->ee_errno;
+		  free (cbuf);
 		  return (cu->cu_error.re_status = RPC_CANTRECV);
 		}
 	  free (cbuf);
diff --git a/sunrpc/tst-udp-error.c b/sunrpc/tst-udp-error.c
new file mode 100644
index 0000000..1efc02f
--- /dev/null
+++ b/sunrpc/tst-udp-error.c
@@ -0,0 +1,62 @@
+/* Check for use-after-free in clntudp_call (bug 21115).
+   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 <netinet/in.h>
+#include <rpc/clnt.h>
+#include <rpc/svc.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/xsocket.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+  support_become_root ();
+  support_enter_network_namespace ();
+
+  /* Obtain a likely-unused port number.  */
+  struct sockaddr_in sin =
+    {
+      .sin_family = AF_INET,
+      .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
+    };
+  {
+    int fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+    xbind (fd, (struct sockaddr *) &sin, sizeof (sin));
+    socklen_t sinlen = sizeof (sin);
+    xgetsockname (fd, (struct sockaddr *) &sin, &sinlen);
+    /* Close the socket, so that we will receive an error below.  */
+    close (fd);
+  }
+
+  int sock = RPC_ANYSOCK;
+  CLIENT *clnt = clntudp_create
+    (&sin, 1, 2, (struct timeval) { 1, 0 }, &sock);
+  TEST_VERIFY_EXIT (clnt != NULL);
+  TEST_VERIFY (clnt_call (clnt, 3,
+                          (xdrproc_t) xdr_void, NULL,
+                          (xdrproc_t) xdr_void, NULL,
+                          ((struct timeval) { 3, 0 }))
+               == RPC_CANTRECV);
+  clnt_destroy (clnt);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22 01/14] ldd: never run file directly
@ 2018-01-01  0:00 Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 08/14] <array_length.h>: New array_length and array_end macros Raphael Moreira Zinsly
                   ` (13 more replies)
  0 siblings, 14 replies; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: libc-stable

From: Andreas Schwab <schwab@suse.de>

(cherry picked from commit eedca9772e99c72ab4c3c34e43cc764250aa3e3c)
---
 ChangeLog       |  4 ++++
 elf/ldd.bash.in | 14 +-------------
 2 files changed, 5 insertions(+), 13 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index c5389fa..643aeb9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2017-08-16  Andreas Schwab  <schwab@suse.de>
+
+	* elf/ldd.bash.in: Never run file directly.
+
 2016-10-14  Carlos Eduardo Seo  <cseo@linux.vnet.ibm.com>
 
 	* sysdeps/powerpc/bits/hwcap.h: Add PPC_FEATURE2_HTM_NOSC.
diff --git a/elf/ldd.bash.in b/elf/ldd.bash.in
index 7fb6c15..9cb1636 100644
--- a/elf/ldd.bash.in
+++ b/elf/ldd.bash.in
@@ -164,18 +164,6 @@ warning: you do not have execution permission for" "\`$file'" >&2
       fi
     done
     case $ret in
-    0)
-      # If the program exits with exit code 5, it means the process has been
-      # invoked with __libc_enable_secure.  Fall back to running it through
-      # the dynamic linker.
-      try_trace "$file"
-      rc=$?
-      if [ $rc = 5 ]; then
-	try_trace "$RTLD" "$file"
-	rc=$?
-      fi
-      [ $rc = 0 ] || result=1
-      ;;
     1)
       # This can be a non-ELF binary or no binary at all.
       nonelf "$file" || {
@@ -183,7 +171,7 @@ warning: you do not have execution permission for" "\`$file'" >&2
 	result=1
       }
       ;;
-    2)
+    0|2)
       try_trace "$RTLD" "$file" || result=1
       ;;
     *)
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22 05/14] glob: Fix buffer overflow during GLOB_TILDE unescaping [BZ #22332]
  2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
                   ` (2 preceding siblings ...)
  2018-01-01  0:00 ` [PATCH 2.22 03/14] glob: Add new test tst-glob-tilde Raphael Moreira Zinsly
@ 2018-01-01  0:00 ` Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 10/14] Fix integer overflows in internal memalign and malloc functions [BZ #22343] Raphael Moreira Zinsly
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: libc-stable

From: Paul Eggert <eggert@cs.ucla.edu>

(cherry picked from commit a159b53fa059947cc2548e3b0d5bdcf7b9630ba8)
---
 ChangeLog    | 6 ++++++
 NEWS         | 4 ++++
 posix/glob.c | 4 ++--
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 7af97cd..4b87910 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2017-10-22  Paul Eggert <eggert@cs.ucla.edu>
+
+	[BZ #22332]
+	* posix/glob.c (__glob): Fix buffer overflow during GLOB_TILDE
+	unescaping.
+
 2017-02-27  Florian Weimer  <fweimer@redhat.com>
 
 	[BZ #21115]
diff --git a/NEWS b/NEWS
index ef34252..314a443 100644
--- a/NEWS
+++ b/NEWS
@@ -71,6 +71,10 @@ Version 2.22.1
 * A use-after-free vulnerability in clntudp_call in the Sun RPC system has been
   fixed (CVE-2017-12133).
 
+* CVE-2017-15804: The glob function, when invoked with GLOB_TILDE and without
+  GLOB_NOESCAPE, could write past the end of a buffer while
+  unescaping user names.  Reported by Tim Rühsen.
+
 \f
 Version 2.22
 
diff --git a/posix/glob.c b/posix/glob.c
index 40496a0..c4c0532 100644
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -839,11 +839,11 @@ glob (pattern, flags, errfunc, pglob)
 		  char *p = mempcpy (newp, dirname + 1,
 				     unescape - dirname - 1);
 		  char *q = unescape;
-		  while (*q != '\0')
+		  while (q != end_name)
 		    {
 		      if (*q == '\\')
 			{
-			  if (q[1] == '\0')
+			  if (q + 1 == end_name)
 			    {
 			      /* "~fo\\o\\" unescape to user_name "foo\\",
 				 but "~fo\\o\\/" unescape to user_name
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22 10/14] Fix integer overflows in internal memalign and malloc functions [BZ #22343]
  2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
                   ` (3 preceding siblings ...)
  2018-01-01  0:00 ` [PATCH 2.22 05/14] glob: Fix buffer overflow during GLOB_TILDE unescaping [BZ #22332] Raphael Moreira Zinsly
@ 2018-01-01  0:00 ` Raphael Moreira Zinsly
  2018-01-01  0:00   ` [PATCH 2.22 v2] " Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 01/14] ldd: never run file directly Carlos O'Donell
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: libc-stable

From: Arjun Shankar <arjun.is@lostca.se>

When posix_memalign is called with an alignment less than MALLOC_ALIGNMENT
and a requested size close to SIZE_MAX, it falls back to malloc code
(because the alignment of a block returned by malloc is sufficient to
satisfy the call).  In this case, an integer overflow in _int_malloc leads
to posix_memalign incorrectly returning successfully.

Upon fixing this and writing a somewhat thorough regression test, it was
discovered that when posix_memalign is called with an alignment larger than
MALLOC_ALIGNMENT (so it uses _int_memalign instead) and a requested size
close to SIZE_MAX, a different integer overflow in _int_memalign leads to
posix_memalign incorrectly returning successfully.

Both integer overflows affect other memory allocation functions that use
_int_malloc (one affected malloc in x86) or _int_memalign as well.

This commit fixes both integer overflows.  In addition to this, it adds a
regression test to guard against false successful allocations by the
following memory allocation functions when called with too-large allocation
sizes and, where relevant, various valid alignments:
malloc, realloc, calloc, reallocarray, memalign, posix_memalign,
aligned_alloc, valloc, and pvalloc.

(cherry picked from commit 8e448310d74b283c5cd02b9ed7fb997b47bf9b22)
---
 ChangeLog                     |  10 ++
 malloc/Makefile               |   3 +-
 malloc/malloc.c               |  30 +++--
 malloc/tst-malloc-too-large.c | 253 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 287 insertions(+), 9 deletions(-)
 create mode 100644 malloc/tst-malloc-too-large.c

diff --git a/ChangeLog b/ChangeLog
index 890b97d..92af495 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2018-01-18  Arjun Shankar  <arjun@redhat.com>
+
+	[BZ #22343]
+	* malloc/malloc.c (checked_request2size): call REQUEST_OUT_OF_RANGE
+	after padding.
+	(_int_memalign): check for integer overflow before calling
+	_int_malloc.
+	* malloc/tst-malloc-too-large.c: New test.
+	* malloc/Makefile: Add tst-malloc-too-large.
+
 2017-11-02  Florian Weimer  <fweimer@redhat.com>
 
 	Add array_length and array_end macros.
diff --git a/malloc/Makefile b/malloc/Makefile
index aa0579c..8445b9e 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -28,7 +28,8 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
 	 tst-mallocstate tst-mcheck tst-mallocfork tst-trim1 \
 	 tst-malloc-usable tst-realloc tst-posix_memalign \
 	 tst-pvalloc tst-memalign tst-mallopt tst-scratch_buffer \
-	 tst-malloc-backtrace tst-malloc-thread-exit
+	 tst-malloc-backtrace tst-malloc-thread-exit tst-malloc-too-large \
+
 test-srcs = tst-mtrace
 
 routines = malloc morecore mcheck mtrace obstack \
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 5c84e62..a5334e5 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1252,14 +1252,21 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    MINSIZE :                                                      \
    ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
 
-/*  Same, except also perform argument check */
-
-#define checked_request2size(req, sz)                             \
-  if (REQUEST_OUT_OF_RANGE (req)) {					      \
-      __set_errno (ENOMEM);						      \
-      return 0;								      \
-    }									      \
-  (sz) = request2size (req);
+/* Same, except also perform an argument and result check.  First, we check
+   that the padding done by request2size didn't result in an integer
+   overflow.  Then we check (using REQUEST_OUT_OF_RANGE) that the resulting
+   size isn't so large that a later alignment would lead to another integer
+   overflow.  */
+#define checked_request2size(req, sz) \
+({				    \
+  (sz) = request2size (req);	    \
+  if (((sz) < (req))		    \
+      || REQUEST_OUT_OF_RANGE (sz)) \
+    {				    \
+      __set_errno (ENOMEM);	    \
+      return 0;			    \
+    }				    \
+})
 
 /*
    --------------- Physical chunk operations ---------------
@@ -4417,6 +4424,13 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
    */
 
 
+  /* Check for overflow.  */
+  if (nb > SIZE_MAX - alignment - MINSIZE)
+    {
+      __set_errno (ENOMEM);
+      return 0;
+    }
+
   /* Call malloc with worst case padding to hit alignment. */
 
   m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
diff --git a/malloc/tst-malloc-too-large.c b/malloc/tst-malloc-too-large.c
new file mode 100644
index 0000000..10fb136
--- /dev/null
+++ b/malloc/tst-malloc-too-large.c
@@ -0,0 +1,253 @@
+/* Test and verify that too-large memory allocations fail with ENOMEM.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Bug 22375 reported a regression in malloc where if after malloc'ing then
+   free'ing a small block of memory, malloc is then called with a really
+   large size argument (close to SIZE_MAX): instead of returning NULL and
+   setting errno to ENOMEM, malloc incorrectly returns the previously
+   allocated block instead.  Bug 22343 reported a similar case where
+   posix_memalign incorrectly returns successfully when called with an with
+   a really large size argument.
+
+   Both of these were caused by integer overflows in the allocator when it
+   was trying to pad the requested size to allow for book-keeping or
+   alignment.  This test guards against such bugs by repeatedly allocating
+   and freeing small blocks of memory then trying to allocate various block
+   sizes larger than the memory bus width of 64-bit targets, or almost
+   as large as SIZE_MAX on 32-bit targets supported by glibc.  In each case,
+   it verifies that such impossibly large allocations correctly fail.  */
+
+
+#include <stdlib.h>
+#include <malloc.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/resource.h>
+#include <libc-diag.h>
+#include <support/check.h>
+#include <unistd.h>
+#include <sys/param.h>
+
+
+/* This function prepares for each 'too-large memory allocation' test by
+   performing a small successful malloc/free and resetting errno prior to
+   the actual test.  */
+static void
+test_setup (void)
+{
+  void *volatile ptr = malloc (16);
+  TEST_VERIFY_EXIT (ptr != NULL);
+  free (ptr);
+  errno = 0;
+}
+
+
+/* This function tests each of:
+   - malloc (SIZE)
+   - realloc (PTR_FOR_REALLOC, SIZE)
+   - for various values of NMEMB:
+    - calloc (NMEMB, SIZE/NMEMB)
+    - calloc (SIZE/NMEMB, NMEMB)
+    - reallocarray (PTR_FOR_REALLOC, NMEMB, SIZE/NMEMB)
+    - reallocarray (PTR_FOR_REALLOC, SIZE/NMEMB, NMEMB)
+   and precedes each of these tests with a small malloc/free before it.  */
+static void
+test_large_allocations (size_t size)
+{
+  void * ptr_to_realloc;
+
+  test_setup ();
+  TEST_VERIFY (malloc (size) == NULL);
+  TEST_VERIFY (errno == ENOMEM);
+
+  ptr_to_realloc = malloc (16);
+  TEST_VERIFY_EXIT (ptr_to_realloc != NULL);
+  test_setup ();
+  TEST_VERIFY (realloc (ptr_to_realloc, size) == NULL);
+  TEST_VERIFY (errno == ENOMEM);
+  free (ptr_to_realloc);
+
+  for (size_t nmemb = 1; nmemb <= 8; nmemb *= 2)
+    if ((size % nmemb) == 0)
+      {
+        test_setup ();
+        TEST_VERIFY (calloc (nmemb, size / nmemb) == NULL);
+        TEST_VERIFY (errno == ENOMEM);
+
+        test_setup ();
+        TEST_VERIFY (calloc (size / nmemb, nmemb) == NULL);
+        TEST_VERIFY (errno == ENOMEM);
+
+        ptr_to_realloc = malloc (16);
+        TEST_VERIFY_EXIT (ptr_to_realloc != NULL);
+        test_setup ();
+        TEST_VERIFY (reallocarray (ptr_to_realloc, nmemb, size / nmemb) == NULL);
+        TEST_VERIFY (errno == ENOMEM);
+        free (ptr_to_realloc);
+
+        ptr_to_realloc = malloc (16);
+        TEST_VERIFY_EXIT (ptr_to_realloc != NULL);
+        test_setup ();
+        TEST_VERIFY (reallocarray (ptr_to_realloc, size / nmemb, nmemb) == NULL);
+        TEST_VERIFY (errno == ENOMEM);
+        free (ptr_to_realloc);
+      }
+    else
+      break;
+}
+
+
+static long pagesize;
+
+/* This function tests the following aligned memory allocation functions
+   using several valid alignments and precedes each allocation test with a
+   small malloc/free before it:
+   memalign, posix_memalign, aligned_alloc, valloc, pvalloc.  */
+static void
+test_large_aligned_allocations (size_t size)
+{
+  /* ptr stores the result of posix_memalign but since all those calls
+     should fail, posix_memalign should never change ptr.  We set it to
+     NULL here and later on we check that it remains NULL after each
+     posix_memalign call.  */
+  void * ptr = NULL;
+
+  size_t align;
+
+  /* All aligned memory allocation functions expect an alignment that is a
+     power of 2.  Given this, we test each of them with every valid
+     alignment from 1 thru PAGESIZE.  */
+  for (align = 1; align <= pagesize; align *= 2)
+    {
+      test_setup ();
+      TEST_VERIFY (memalign (align, size) == NULL);
+      TEST_VERIFY (errno == ENOMEM);
+
+      /* posix_memalign expects an alignment that is a power of 2 *and* a
+         multiple of sizeof (void *).  */
+      if ((align % sizeof (void *)) == 0)
+        {
+          test_setup ();
+          TEST_VERIFY (posix_memalign (&ptr, align, size) == ENOMEM);
+          TEST_VERIFY (ptr == NULL);
+        }
+
+      /* aligned_alloc expects a size that is a multiple of alignment.  */
+      if ((size % align) == 0)
+        {
+          test_setup ();
+          TEST_VERIFY (aligned_alloc (align, size) == NULL);
+          TEST_VERIFY (errno == ENOMEM);
+        }
+    }
+
+  /* Both valloc and pvalloc return page-aligned memory.  */
+
+  test_setup ();
+  TEST_VERIFY (valloc (size) == NULL);
+  TEST_VERIFY (errno == ENOMEM);
+
+  test_setup ();
+  TEST_VERIFY (pvalloc (size) == NULL);
+  TEST_VERIFY (errno == ENOMEM);
+}
+
+
+#define FOURTEEN_ON_BITS ((1UL << 14) - 1)
+#define FIFTY_ON_BITS ((1UL << 50) - 1)
+
+
+static int
+do_test (void)
+{
+
+#if __WORDSIZE >= 64
+
+  /* This test assumes that none of the supported targets have an address
+     bus wider than 50 bits, and that therefore allocations for sizes wider
+     than 50 bits will fail.  Here, we ensure that the assumption continues
+     to be true in the future when we might have address buses wider than 50
+     bits.  */
+
+  struct rlimit alloc_size_limit
+    = {
+        .rlim_cur = FIFTY_ON_BITS,
+        .rlim_max = FIFTY_ON_BITS
+      };
+
+  setrlimit (RLIMIT_AS, &alloc_size_limit);
+
+#endif /* __WORDSIZE >= 64 */
+
+  DIAG_PUSH_NEEDS_COMMENT;
+#if __GNUC_PREREQ (7, 0)
+  /* GCC 7 warns about too-large allocations; here we want to test
+     that they fail.  */
+  DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
+#endif
+
+  /* Aligned memory allocation functions need to be tested up to alignment
+     size equivalent to page size, which should be a power of 2.  */
+  pagesize = sysconf (_SC_PAGESIZE);
+  TEST_VERIFY_EXIT (powerof2 (pagesize));
+
+  /* Loop 1: Ensure that all allocations with SIZE close to SIZE_MAX, i.e.
+     in the range (SIZE_MAX - 2^14, SIZE_MAX], fail.
+
+     We can expect that this range of allocation sizes will always lead to
+     an allocation failure on both 64 and 32 bit targets, because:
+
+     1. no currently supported 64-bit target has an address bus wider than
+     50 bits -- and (2^64 - 2^14) is much wider than that;
+
+     2. on 32-bit targets, even though 2^32 is only 4 GB and potentially
+     addressable, glibc itself is more than 2^14 bytes in size, and
+     therefore once glibc is loaded, less than (2^32 - 2^14) bytes remain
+     available.  */
+
+  for (size_t i = 0; i <= FOURTEEN_ON_BITS; i++)
+    {
+      test_large_allocations (SIZE_MAX - i);
+      test_large_aligned_allocations (SIZE_MAX - i);
+    }
+
+#if __WORDSIZE >= 64
+  /* On 64-bit targets, we need to test a much wider range of too-large
+     sizes, so we test at intervals of (1 << 50) that allocation sizes
+     ranging from SIZE_MAX down to (1 << 50) fail:
+     The 14 MSBs are decremented starting from "all ON" going down to 1,
+     the 50 LSBs are "all ON" and then "all OFF" during every iteration.  */
+  for (size_t msbs = FOURTEEN_ON_BITS; msbs >= 1; msbs--)
+    {
+      size_t size = (msbs << 50) | FIFTY_ON_BITS;
+      test_large_allocations (size);
+      test_large_aligned_allocations (size);
+
+      size = msbs << 50;
+      test_large_allocations (size);
+      test_large_aligned_allocations (size);
+    }
+#endif /* __WORDSIZE >= 64 */
+
+  DIAG_POP_NEEDS_COMMENT;
+
+  return 0;
+}
+
+
+#include <support/test-driver.c>
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22 12/14] Add ChangeLog reference to bug 16750/CVE-2009-5064
  2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
                   ` (8 preceding siblings ...)
  2018-01-01  0:00 ` [PATCH 2.22 06/14] elf: Check for empty tokens before dynamic string token expansion [BZ #22625] Raphael Moreira Zinsly
@ 2018-01-01  0:00 ` Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 02/14] CVE-2017-15670: glob: Fix one-byte overflow [BZ #22320] Raphael Moreira Zinsly
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: libc-stable

From: Florian Weimer <fweimer@redhat.com>

(cherry picked from commit 403143e1df85dadd374f304bd891be0cd7573e3b)
---
 ChangeLog | 2 ++
 NEWS      | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 91a9fb9..05ef3fd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -77,6 +77,8 @@
 
 2017-08-16  Andreas Schwab  <schwab@suse.de>
 
+	[BZ #16750]
+	CVE-2009-5064
 	* elf/ldd.bash.in: Never run file directly.
 
 2016-10-14  Carlos Eduardo Seo  <cseo@linux.vnet.ibm.com>
diff --git a/NEWS b/NEWS
index e061583..2d703f2 100644
--- a/NEWS
+++ b/NEWS
@@ -94,6 +94,12 @@ Version 2.22.1
   succeeds without returning an absolute path due to unexpected behaviour
   of the Linux kernel getcwd syscall.  Reported by halfdog.
 
+* CVE-2009-5064: The ldd script would sometimes run the program under
+  examination directly, without preventing code execution through the
+  dynamic linker.  (The glibc project disputes that this is a security
+  vulnerability; only trusted binaries must be examined using the ldd
+  script.)
+
 \f
 Version 2.22
 
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22 03/14] glob: Add new test tst-glob-tilde
  2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 08/14] <array_length.h>: New array_length and array_end macros Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 09/14] elf: Compute correct array size in _dl_init_paths [BZ #22606] Raphael Moreira Zinsly
@ 2018-01-01  0:00 ` Raphael Moreira Zinsly
  2018-01-01  0:00   ` Tulio Magno Quites Machado Filho
  2018-01-01  0:00 ` [PATCH 2.22 05/14] glob: Fix buffer overflow during GLOB_TILDE unescaping [BZ #22332] Raphael Moreira Zinsly
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: libc-stable

From: Florian Weimer <fweimer@redhat.com>

The new test checks for memory leaks (see bug 22325) and attempts
to trigger the buffer overflow in bug 22320.

(cherry picked from commit e80fc1fc98bf614eb01cf8325503df3a1451a99c)
---
 ChangeLog              |   8 +++
 posix/Makefile         |  12 ++++-
 posix/tst-glob-tilde.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 154 insertions(+), 2 deletions(-)
 create mode 100644 posix/tst-glob-tilde.c

diff --git a/ChangeLog b/ChangeLog
index 4c96691..0e07eb2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2017-10-21  Florian Weimer  <fweimer@redhat.com>
+
+	* posix/Makefile (tests): Add tst-glob-tilde.
+	(tests-special): Add tst-glob-tilde-mem.out
+	(tst-glob-tilde-ENV): Set MALLOC_TRACE.
+	(tst-glob-tilde-mem.out): Add mtrace check.
+	* posix/tst-glob-tilde.c: New file.
+
 2017-10-20  Paul Eggert <eggert@cs.ucla.edu>
 
 	[BZ #22320]
diff --git a/posix/Makefile b/posix/Makefile
index 15e8818..ec7c24e 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -87,7 +87,8 @@ tests		:= tstgetopt testfnm runtests runptests	     \
 		   bug-getopt1 bug-getopt2 bug-getopt3 bug-getopt4 \
 		   bug-getopt5 tst-getopt_long1 bug-regex34 bug-regex35 \
 		   tst-pathconf tst-getaddrinfo4 tst-rxspencer-no-utf8 \
-		   tst-fnmatch3 bug-regex36 tst-getaddrinfo5
+		   tst-fnmatch3 bug-regex36 tst-getaddrinfo5 \
+		   tst-glob-tilde
 xtests		:= bug-ga2
 ifeq (yes,$(build-shared))
 test-srcs	:= globtest
@@ -130,7 +131,8 @@ tests-special += $(objpfx)bug-regex2-mem.out $(objpfx)bug-regex14-mem.out \
 		 $(objpfx)tst-rxspencer-no-utf8-mem.out $(objpfx)tst-pcre-mem.out \
 		 $(objpfx)tst-boost-mem.out $(objpfx)tst-getconf.out \
 		 $(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \
-		 $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out
+		 $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out \
+		 $(objpfx)tst-glob-tilde-mem.out
 xtests-special += $(objpfx)bug-ga2-mem.out
 endif
 
@@ -307,6 +309,12 @@ $(objpfx)bug-glob2-mem.out: $(objpfx)bug-glob2.out
 	$(common-objpfx)malloc/mtrace $(objpfx)bug-glob2.mtrace > $@; \
 	$(evaluate-test)
 
+tst-glob-tilde-ENV = MALLOC_TRACE=$(objpfx)tst-glob-tilde.mtrace
+
+$(objpfx)tst-glob-tilde-mem.out: $(objpfx)tst-glob-tilde.out
+	$(common-objpfx)malloc/mtrace $(objpfx)tst-glob-tilde.mtrace > $@; \
+	$(evaluate-test)
+
 $(inst_libexecdir)/getconf: $(inst_bindir)/getconf \
 			    $(objpfx)getconf.speclist FORCE
 	$(addprefix $(..)./scripts/mkinstalldirs ,\
diff --git a/posix/tst-glob-tilde.c b/posix/tst-glob-tilde.c
new file mode 100644
index 0000000..9518b4a
--- /dev/null
+++ b/posix/tst-glob-tilde.c
@@ -0,0 +1,136 @@
+/* Check for GLOB_TIDLE heap allocation issues (bug 22320, bug 22325).
+   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 <glob.h>
+#include <mcheck.h>
+#include <nss.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+
+/* Flag which indicates whether to pass the GLOB_ONLYDIR flag.  */
+static int do_onlydir;
+
+/* Flag which indicates whether to pass the GLOB_NOCHECK flag.  */
+static int do_nocheck;
+
+/* Flag which indicates whether to pass the GLOB_MARK flag.  */
+static int do_mark;
+
+static void
+one_test (const char *prefix, const char *middle, const char *suffix)
+{
+  char *pattern = xasprintf ("%s%s%s", prefix, middle, suffix);
+  int flags = GLOB_TILDE;
+  if (do_onlydir)
+    flags |= GLOB_ONLYDIR;
+  if (do_nocheck)
+    flags |= GLOB_NOCHECK;
+  if (do_mark)
+    flags |= GLOB_MARK;
+  glob_t gl;
+  /* This glob call might result in crashes or memory leaks.  */
+  if (glob (pattern, flags, NULL, &gl) == 0)
+    globfree (&gl);
+  free (pattern);
+}
+
+enum
+  {
+    /* The largest base being tested.  */
+    largest_base_size = 500000,
+
+    /* The actual size is the base size plus a variable whose absolute
+       value is not greater than this.  This helps malloc to trigger
+       overflows.  */
+    max_size_skew = 16,
+
+    /* The maximum string length supported by repeating_string
+       below.  */
+    repeat_size = largest_base_size + max_size_skew,
+  };
+
+/* Used to construct strings which repeat a single character 'x'.  */
+static char *repeat;
+
+/* Return a string of SIZE characters.  */
+const char *
+repeating_string (int size)
+{
+  TEST_VERIFY (size >= 0);
+  TEST_VERIFY (size <= repeat_size);
+  const char *repeated_shifted = repeat + repeat_size - size;
+  TEST_VERIFY (strlen (repeated_shifted) == size);
+  return repeated_shifted;
+}
+
+static int
+do_test (void)
+{
+  /* Avoid network-based NSS modules and initialize nss_files with a
+     dummy lookup.  This has to come before mtrace because NSS does
+     not free all memory.  */
+  __nss_configure_lookup ("passwd", "files");
+  (void) getpwnam ("root");
+
+  mtrace ();
+
+  repeat = xmalloc (repeat_size + 1);
+  memset (repeat, 'x', repeat_size);
+  repeat[repeat_size] = '\0';
+
+  /* These numbers control the size of the user name.  The values
+     cover the minimum (0), a typical size (8), a large
+     stack-allocated size (100000), and a somewhat large
+     heap-allocated size (largest_base_size).  */
+  static const int base_sizes[] = { 0, 8, 100, 100000, largest_base_size, -1 };
+
+  for (do_onlydir = 0; do_onlydir < 2; ++do_onlydir)
+    for (do_nocheck = 0; do_nocheck < 2; ++do_nocheck)
+      for (do_mark = 0; do_mark < 2; ++do_mark)
+        for (int base_idx = 0; base_sizes[base_idx] >= 0; ++base_idx)
+          {
+            for (int size_skew = -max_size_skew; size_skew <= max_size_skew;
+                 ++size_skew)
+              {
+                int size = base_sizes[base_idx] + size_skew;
+                if (size < 0)
+                  continue;
+
+                const char *user_name = repeating_string (size);
+                one_test ("~", user_name, "/a/b");
+              }
+
+            const char *user_name = repeating_string (base_sizes[base_idx]);
+            one_test ("~", user_name, "");
+            one_test ("~", user_name, "/");
+            one_test ("~", user_name, "/a");
+            one_test ("~", user_name, "/*/*");
+            one_test ("~", user_name, "\\/");
+            one_test ("/~", user_name, "");
+            one_test ("*/~", user_name, "/a/b");
+          }
+
+  free (repeat);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22 07/14] elf: Count components of the expanded path in _dl_init_path [BZ #22607]
  2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
                   ` (10 preceding siblings ...)
  2018-01-01  0:00 ` [PATCH 2.22 02/14] CVE-2017-15670: glob: Fix one-byte overflow [BZ #22320] Raphael Moreira Zinsly
@ 2018-01-01  0:00 ` Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 04/14] sunrpc: Avoid use-after-free read access in clntudp_call [BZ #21115] Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 13/14] Record CVE-2018-6485 in ChangeLog and NEWS [BZ #22343] Raphael Moreira Zinsly
  13 siblings, 0 replies; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: libc-stable

From: Florian Weimer <fweimer@redhat.com>

(cherry picked from commit 3ff3dfa5af313a6ea33f3393916f30eece4f0171)
---
 ChangeLog     |  7 +++++++
 NEWS          |  6 ++++++
 elf/dl-load.c | 13 ++++---------
 3 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 6fb5e62..40c0c60 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2017-12-14  Florian Weimer  <fweimer@redhat.com>
+
+	[BZ #22607]
+	CVE-2017-1000409
+	* elf/dl-load.c (_dl_init_paths): Compute number of components in
+	the expanded path string.
+
 2017-12-30  Aurelien Jarno  <aurelien@aurel32.net>
 	    Dmitry V. Levin  <ldv@altlinux.org>
 
diff --git a/NEWS b/NEWS
index 73f2cfa..ea8e17c 100644
--- a/NEWS
+++ b/NEWS
@@ -79,6 +79,12 @@ Version 2.22.1
   for AT_SECURE or SUID binaries could be used to load libraries from the
   current directory.
 
+* CVE-2017-1000409: Buffer overflow in _dl_init_paths due to miscomputation
+  of the number of search path components.  (This is not a security
+  vulnerability per se because no trust boundary is crossed if the fix for
+  CVE-2017-1000366 has been applied, but it is mentioned here only because
+  of the CVE assignment.)  Reported by Qualys.
+
 \f
 Version 2.22
 
diff --git a/elf/dl-load.c b/elf/dl-load.c
index d0ac65e..f22fd0d 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -792,8 +792,6 @@ _dl_init_paths (const char *llp)
 
   if (llp != NULL && *llp != '\0')
     {
-      size_t nllp;
-      const char *cp = llp;
       char *llp_tmp;
 
 #ifdef SHARED
@@ -816,13 +814,10 @@ _dl_init_paths (const char *llp)
 
       /* Decompose the LD_LIBRARY_PATH contents.  First determine how many
 	 elements it has.  */
-      nllp = 1;
-      while (*cp)
-	{
-	  if (*cp == ':' || *cp == ';')
-	    ++nllp;
-	  ++cp;
-	}
+      size_t nllp = 1;
+      for (const char *cp = llp_tmp; *cp != '\0'; ++cp)
+	if (*cp == ':' || *cp == ';')
+	  ++nllp;
 
       env_path_list.dirs = (struct r_search_path_elem **)
 	malloc ((nllp + 1) * sizeof (struct r_search_path_elem *));
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22 02/14] CVE-2017-15670: glob: Fix one-byte overflow [BZ #22320]
  2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
                   ` (9 preceding siblings ...)
  2018-01-01  0:00 ` [PATCH 2.22 12/14] Add ChangeLog reference to bug 16750/CVE-2009-5064 Raphael Moreira Zinsly
@ 2018-01-01  0:00 ` Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 07/14] elf: Count components of the expanded path in _dl_init_path [BZ #22607] Raphael Moreira Zinsly
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: libc-stable

From: Paul Eggert <eggert@cs.ucla.edu>

(cherry picked from commit c369d66e5426a30e4725b100d5cd28e372754f90)
---
 ChangeLog    | 6 ++++++
 NEWS         | 5 +++++
 posix/glob.c | 2 +-
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index 643aeb9..4c96691 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2017-10-20  Paul Eggert <eggert@cs.ucla.edu>
+
+	[BZ #22320]
+	CVE-2017-15670
+	* posix/glob.c (__glob): Fix one-byte overflow.
+
 2017-08-16  Andreas Schwab  <schwab@suse.de>
 
 	* elf/ldd.bash.in: Never run file directly.
diff --git a/NEWS b/NEWS
index a19f656..069b3ea 100644
--- a/NEWS
+++ b/NEWS
@@ -63,6 +63,11 @@ Version 2.22.1
 * The Sun RPC UDP client could exhaust all available stack space when
   flooded with crafted ICMP and UDP messages.  Reported by Aldy Hernandez'
   alloca plugin for GCC.  (CVE-2016-4429)
+
+* CVE-2017-15670: The glob function, when invoked with GLOB_TILDE, suffered
+  from a one-byte overflow during ~ operator processing (either on the stack
+  or the heap, depending on the length of the user name).
+
 \f
 Version 2.22
 
diff --git a/posix/glob.c b/posix/glob.c
index 60fa6c5..40496a0 100644
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -859,7 +859,7 @@ glob (pattern, flags, errfunc, pglob)
 		  *p = '\0';
 		}
 	      else
-		*((char *) mempcpy (newp, dirname + 1, end_name - dirname))
+		*((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1))
 		  = '\0';
 	      user_name = newp;
 	    }
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22 09/14] elf: Compute correct array size in _dl_init_paths [BZ #22606]
  2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 08/14] <array_length.h>: New array_length and array_end macros Raphael Moreira Zinsly
@ 2018-01-01  0:00 ` Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 03/14] glob: Add new test tst-glob-tilde Raphael Moreira Zinsly
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: libc-stable

From: Florian Weimer <fweimer@redhat.com>

(cherry picked from commit 8a0b17e48b83e933960dfeb8fa08b259f03f310e)
---
 ChangeLog     |  8 ++++++++
 NEWS          |  5 +++++
 elf/dl-load.c | 14 +++++++-------
 3 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 48fc023..890b97d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,14 @@
 
 2017-12-14  Florian Weimer  <fweimer@redhat.com>
 
+	[BZ #22606]
+	CVE-2017-1000408
+	* elf/dl-load.c (system_dirs): Update comment.
+	(nsystem_dirs_len): Use array_length.
+	(_dl_init_paths): Use nsystem_dirs_len to compute the array size.
+
+2017-12-14  Florian Weimer  <fweimer@redhat.com>
+
 	[BZ #22607]
 	CVE-2017-1000409
 	* elf/dl-load.c (_dl_init_paths): Compute number of components in
diff --git a/NEWS b/NEWS
index ea8e17c..7c090fe 100644
--- a/NEWS
+++ b/NEWS
@@ -85,6 +85,11 @@ Version 2.22.1
   CVE-2017-1000366 has been applied, but it is mentioned here only because
   of the CVE assignment.)  Reported by Qualys.
 
+* CVE-2017-1000408: Incorrect array size computation in _dl_init_paths leads
+  to the allocation of too much memory.  (This is not a security bug per se,
+  it is mentioned here only because of the CVE assignment.)  Reported by
+  Qualys.
+
 \f
 Version 2.22
 
diff --git a/elf/dl-load.c b/elf/dl-load.c
index f22fd0d..32c3159 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -36,6 +36,7 @@
 #include <caller.h>
 #include <sysdep.h>
 #include <stap-probe.h>
+#include <array_length.h>
 
 #include <dl-dst.h>
 #include <dl-load.h>
@@ -102,7 +103,9 @@ static size_t ncapstr attribute_relro;
 static size_t max_capstrlen attribute_relro;
 
 
-/* Get the generated information about the trusted directories.  */
+/* Get the generated information about the trusted directories.  Use
+   an array of concatenated strings to avoid relocations.  See
+   gen-trusted-dirs.awk.  */
 #include "trusted-dirs.h"
 
 static const char system_dirs[] = SYSTEM_DIRS;
@@ -110,9 +113,7 @@ static const size_t system_dirs_len[] =
 {
   SYSTEM_DIRS_LEN
 };
-#define nsystem_dirs_len \
-  (sizeof (system_dirs_len) / sizeof (system_dirs_len[0]))
-
+#define nsystem_dirs_len array_length (system_dirs_len)
 
 static bool
 is_trusted_path (const char *path, size_t len)
@@ -704,9 +705,8 @@ _dl_init_paths (const char *llp)
 		 + ncapstr * sizeof (enum r_dir_status))
 		/ sizeof (struct r_search_path_elem));
 
-  rtld_search_dirs.dirs[0] = (struct r_search_path_elem *)
-    malloc ((sizeof (system_dirs) / sizeof (system_dirs[0]))
-	    * round_size * sizeof (struct r_search_path_elem));
+  rtld_search_dirs.dirs[0] = malloc (nsystem_dirs_len * round_size
+				     * sizeof (*rtld_search_dirs.dirs[0]));
   if (rtld_search_dirs.dirs[0] == NULL)
     {
       errstring = N_("cannot create cache for search path");
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22 06/14] elf: Check for empty tokens before dynamic string token expansion [BZ #22625]
  2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
                   ` (7 preceding siblings ...)
  2018-01-01  0:00 ` [PATCH 2.22 11/14] linux: make getcwd(3) fail if it cannot obtain an absolute path [BZ #22679] Raphael Moreira Zinsly
@ 2018-01-01  0:00 ` Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 12/14] Add ChangeLog reference to bug 16750/CVE-2009-5064 Raphael Moreira Zinsly
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: libc-stable

From: Aurelien Jarno <aurelien@aurel32.net>

The fillin_rpath function in elf/dl-load.c loops over each RPATH or
RUNPATH tokens and interprets empty tokens as the current directory
("./"). In practice the check for empty token is done *after* the
dynamic string token expansion. The expansion process can return an
empty string for the $ORIGIN token if __libc_enable_secure is set
or if the path of the binary can not be determined (/proc not mounted).

Fix that by moving the check for empty tokens before the dynamic string
token expansion. In addition, check for NULL pointer or empty strings
return by expand_dynamic_string_token.

The above changes highlighted a bug in decompose_rpath, an empty array
is represented by the first element being NULL at the fillin_rpath
level, but by using a -1 pointer in decompose_rpath and other functions.

Changelog:
	[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.

(cherry picked from commit 3e3c904daef69b8bf7d5cc07f793c9f07c3553ef)
---
 ChangeLog     | 10 ++++++++++
 NEWS          |  4 ++++
 elf/dl-load.c | 49 +++++++++++++++++++++++++++++++++----------------
 3 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 4b87910..6fb5e62 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+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-10-22  Paul Eggert <eggert@cs.ucla.edu>
 
 	[BZ #22332]
diff --git a/NEWS b/NEWS
index 314a443..73f2cfa 100644
--- a/NEWS
+++ b/NEWS
@@ -75,6 +75,10 @@ Version 2.22.1
   GLOB_NOESCAPE, could write past the end of a buffer while
   unescaping user names.  Reported by Tim Rühsen.
 
+* 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.
+
 \f
 Version 2.22
 
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 7e6f4c5..d0ac65e 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -432,31 +432,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))
@@ -620,6 +629,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;
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2.22 01/14] ldd: never run file directly
  2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
                   ` (4 preceding siblings ...)
  2018-01-01  0:00 ` [PATCH 2.22 10/14] Fix integer overflows in internal memalign and malloc functions [BZ #22343] Raphael Moreira Zinsly
@ 2018-01-01  0:00 ` Carlos O'Donell
  2018-01-01  0:00   ` Tulio Magno Quites Machado Filho
  2018-01-01  0:00 ` [PATCH 2.22 14/14] Record CVE-2018-6551 in NEWS and ChangeLog [BZ #22774] Raphael Moreira Zinsly
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 26+ messages in thread
From: Carlos O'Donell @ 2018-01-01  0:00 UTC (permalink / raw)
  To: Raphael Moreira Zinsly, libc-stable

On 03/28/2018 03:43 PM, Raphael Moreira Zinsly wrote:
> From: Andreas Schwab <schwab@suse.de>
> 
> (cherry picked from commit eedca9772e99c72ab4c3c34e43cc764250aa3e3c)
Is the goal of this patchset to backport 14 patches from master to
the stable 2.22 branch?

Note that by consensus you can just do the backport to 2.22, for what
I assume is IBM Advance Toolchain 9.0 uses (which uses 2.22).

If not, please update:
https://sourceware.org/glibc/wiki/Release/#Distribution_Branch_Mapping

-- 
Cheers,
Carlos.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22 11/14] linux: make getcwd(3) fail if it cannot obtain an absolute path [BZ #22679]
  2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
                   ` (6 preceding siblings ...)
  2018-01-01  0:00 ` [PATCH 2.22 14/14] Record CVE-2018-6551 in NEWS and ChangeLog [BZ #22774] Raphael Moreira Zinsly
@ 2018-01-01  0:00 ` Raphael Moreira Zinsly
  2018-01-01  0:00 ` [PATCH 2.22 06/14] elf: Check for empty tokens before dynamic string token expansion [BZ #22625] Raphael Moreira Zinsly
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: libc-stable

From: "Dmitry V. Levin" <ldv@altlinux.org>

Currently getcwd(3) can succeed without returning an absolute path
because the underlying getcwd syscall, starting with linux commit
v2.6.36-rc1~96^2~2, may succeed without returning an absolute path.

This is a conformance issue because "The getcwd() function shall
place an absolute pathname of the current working directory
in the array pointed to by buf, and return buf".

This is also a security issue because a non-absolute path returned
by getcwd(3) causes a buffer underflow in realpath(3).

Fix this by checking the path returned by getcwd syscall and falling
back to generic_getcwd if the path is not absolute, effectively making
getcwd(3) fail with ENOENT.  The error code is chosen for consistency
with the case when the current directory is unlinked.

[BZ #22679]
CVE-2018-1000001
* sysdeps/unix/sysv/linux/getcwd.c (__getcwd): Fall back to
generic_getcwd if the path returned by getcwd syscall is not absolute.
* io/tst-getcwd-abspath.c: New test.
* io/Makefile (tests): Add tst-getcwd-abspath.

(cherry picked from commit 52a713fdd0a30e1bd79818e2e3c4ab44ddca1a94)
---
 ChangeLog                        |  9 ++++++
 NEWS                             |  4 +++
 io/Makefile                      |  2 +-
 io/tst-getcwd-abspath.c          | 66 ++++++++++++++++++++++++++++++++++++++++
 sysdeps/unix/sysv/linux/getcwd.c |  8 ++---
 5 files changed, 84 insertions(+), 5 deletions(-)
 create mode 100644 io/tst-getcwd-abspath.c

diff --git a/ChangeLog b/ChangeLog
index 92af495..91a9fb9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2018-01-12  Dmitry V. Levin  <ldv@altlinux.org>
+
+	[BZ #22679]
+	CVE-2018-1000001
+	* sysdeps/unix/sysv/linux/getcwd.c (__getcwd): Fall back to
+	generic_getcwd if the path returned by getcwd syscall is not absolute.
+	* io/tst-getcwd-abspath.c: New test.
+	* io/Makefile (tests): Add tst-getcwd-abspath.
+
 2018-01-18  Arjun Shankar  <arjun@redhat.com>
 
 	[BZ #22343]
diff --git a/NEWS b/NEWS
index 7c090fe..e061583 100644
--- a/NEWS
+++ b/NEWS
@@ -90,6 +90,10 @@ Version 2.22.1
   it is mentioned here only because of the CVE assignment.)  Reported by
   Qualys.
 
+* CVE-2018-1000001: Buffer underflow in realpath function when getcwd function
+  succeeds without returning an absolute path due to unexpected behaviour
+  of the Linux kernel getcwd syscall.  Reported by halfdog.
+
 \f
 Version 2.22
 
diff --git a/io/Makefile b/io/Makefile
index 613dce0..c50be28 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -71,7 +71,7 @@ tests		:= test-utime test-stat test-stat2 test-lfs tst-getcwd \
 		   tst-renameat tst-fchownat tst-fchmodat tst-faccessat \
 		   tst-symlinkat tst-linkat tst-readlinkat tst-mkdirat \
 		   tst-mknodat tst-mkfifoat tst-ttyname_r bug-ftw5 \
-		   tst-posix_fallocate
+		   tst-posix_fallocate tst-getcwd-abspath
 
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)ftwtest.out
diff --git a/io/tst-getcwd-abspath.c b/io/tst-getcwd-abspath.c
new file mode 100644
index 0000000..3a3636f
--- /dev/null
+++ b/io/tst-getcwd-abspath.c
@@ -0,0 +1,66 @@
+/* BZ #22679 getcwd(3) should not succeed without returning an absolute path.
+
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.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>
+#include <unistd.h>
+
+static char *chroot_dir;
+
+/* The actual test.  Run it in a subprocess, so that the test harness
+   can remove the temporary directory in --direct mode.  */
+static void
+getcwd_callback (void *closure)
+{
+  xchroot (chroot_dir);
+
+  errno = 0;
+  char *cwd = getcwd (NULL, 0);
+  TEST_COMPARE (errno, ENOENT);
+  TEST_VERIFY (cwd == NULL);
+
+  errno = 0;
+  cwd = realpath (".", NULL);
+  TEST_COMPARE (errno, ENOENT);
+  TEST_VERIFY (cwd == NULL);
+
+  _exit (0);
+}
+
+static int
+do_test (void)
+{
+  support_become_root ();
+  if (!support_can_chroot ())
+    return EXIT_UNSUPPORTED;
+
+  chroot_dir = support_create_temp_directory ("tst-getcwd-abspath-");
+  support_isolate_in_subprocess (getcwd_callback, NULL);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/getcwd.c b/sysdeps/unix/sysv/linux/getcwd.c
index 5caee92..4a4c8f0 100644
--- a/sysdeps/unix/sysv/linux/getcwd.c
+++ b/sysdeps/unix/sysv/linux/getcwd.c
@@ -76,7 +76,7 @@ __getcwd (char *buf, size_t size)
   int retval;
 
   retval = INLINE_SYSCALL (getcwd, 2, path, alloc_size);
-  if (retval >= 0)
+  if (retval > 0 && path[0] == '/')
     {
 #ifndef NO_ALLOCATION
       if (buf == NULL && size == 0)
@@ -92,10 +92,10 @@ __getcwd (char *buf, size_t size)
       return buf;
     }
 
-  /* The system call cannot handle paths longer than a page.
-     Neither can the magic symlink in /proc/self.  Just use the
+  /* The system call either cannot handle paths longer than a page
+     or can succeed without returning an absolute path.  Just use the
      generic implementation right away.  */
-  if (errno == ENAMETOOLONG)
+  if (retval >= 0 || errno == ENAMETOOLONG)
     {
 #ifndef NO_ALLOCATION
       if (buf == NULL && size == 0)
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2.22] Synchronize support/ infrastructure with master
  2018-01-01  0:00     ` [PATCH 2.22] Synchronize support/ infrastructure with master Raphael Moreira Zinsly
@ 2018-01-01  0:00       ` Carlos O'Donell
  2018-01-01  0:00       ` Tulio Magno Quites Machado Filho
  1 sibling, 0 replies; 26+ messages in thread
From: Carlos O'Donell @ 2018-01-01  0:00 UTC (permalink / raw)
  To: Raphael Moreira Zinsly, tuliom; +Cc: libc-stable

On 04/04/2018 08:22 AM, Raphael Moreira Zinsly wrote:
> From: Arjun Shankar <arjun.is@lostca.se>
> 
> Sorry for that, with that backport the tests work fine.
> 
> -- >8 --
> 
> This commit updates the support/ subdirectory to
> commit 2714c5f3c95f90977167c1d21326d907fb76b419
> on the master branch and modifies Makeconfig,
> Rules, and extra-lib.mk accordingly.

Ah! I see now. This patch is dependent on the other later patch.

This looks fine. In the future please post a patch series so they
get reviewed together, or identify dependencies.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

> (cherry picked from commit 4c5785aa129a5d195fc1cd5c7fcd6f62c2b0ff0c)
> ---
>  Makeconfig                                 |   15 +-
>  Rules                                      |    3 +
>  extra-lib.mk                               |    5 +
>  scripts/backport-support.sh                |  110 +++
>  support/Makefile                           |  146 ++++
>  support/README                             |   29 +
>  support/README-testing.c                   |   19 +
>  support/capture_subprocess.h               |   61 ++
>  support/check.c                            |   57 ++
>  support/check.h                            |   94 +++
>  support/check_addrinfo.c                   |   42 +
>  support/check_dns_packet.c                 |   42 +
>  support/check_hostent.c                    |   42 +
>  support/check_netent.c                     |   42 +
>  support/check_nss.h                        |   42 +
>  support/delayed_exit.c                     |   55 ++
>  support/format_nss.h                       |   41 +
>  support/ignore_stderr.c                    |   38 +
>  support/namespace.h                        |   65 ++
>  support/oom_error.c                        |   29 +
>  support/resolv_test.c                      | 1202 ++++++++++++++++++++++++++++
>  support/resolv_test.h                      |  180 +++++
>  support/run_diff.h                         |   31 +
>  support/set_fortify_handler.c              |   34 +
>  support/support-xstat.c                    |   30 +
>  support/support.h                          |   74 ++
>  support/support_become_root.c              |   40 +
>  support/support_can_chroot.c               |   65 ++
>  support/support_capture_subprocess.c       |  108 +++
>  support/support_capture_subprocess_check.c |   67 ++
>  support/support_enter_network_namespace.c  |   75 ++
>  support/support_format_address_family.c    |   35 +
>  support/support_format_addrinfo.c          |  239 ++++++
>  support/support_format_dns_packet.c        |  222 +++++
>  support/support_format_herrno.c            |   45 ++
>  support/support_format_hostent.c           |   75 ++
>  support/support_format_netent.c            |   52 ++
>  support/support_isolate_in_subprocess.c    |   38 +
>  support/support_record_failure.c           |  106 +++
>  support/support_run_diff.c                 |   76 ++
>  support/support_shared_allocate.c          |   59 ++
>  support/support_test_main.c                |  423 ++++++++++
>  support/support_test_verify_impl.c         |   33 +
>  support/support_write_file_string.c        |   39 +
>  support/temp_file-internal.h               |   31 +
>  support/temp_file.c                        |  132 +++
>  support/temp_file.h                        |   37 +
>  support/test-driver.c                      |  156 ++++
>  support/test-driver.h                      |   74 ++
>  support/tst-support-namespace.c            |   34 +
>  support/tst-support_capture_subprocess.c   |  188 +++++
>  support/tst-support_format_dns_packet.c    |  101 +++
>  support/tst-support_record_failure-2.sh    |   69 ++
>  support/tst-support_record_failure.c       |  153 ++++
>  support/write_message.c                    |   29 +
>  support/xaccept.c                          |   32 +
>  support/xaccept4.c                         |   32 +
>  support/xasprintf.c                        |   36 +
>  support/xbind.c                            |   30 +
>  support/xcalloc.c                          |   34 +
>  support/xchroot.c                          |   28 +
>  support/xclose.c                           |   28 +
>  support/xconnect.c                         |   30 +
>  support/xdup2.c                            |   28 +
>  support/xfclose.c                          |   33 +
>  support/xfopen.c                           |   31 +
>  support/xfork.c                            |   32 +
>  support/xgetsockname.c                     |   30 +
>  support/xlisten.c                          |   30 +
>  support/xmalloc.c                          |   34 +
>  support/xmemstream.c                       |   42 +
>  support/xmemstream.h                       |   49 ++
>  support/xmkdir.c                           |   28 +
>  support/xmmap.c                            |   31 +
>  support/xmunmap.c                          |   28 +
>  support/xopen.c                            |   30 +
>  support/xpipe.c                            |   28 +
>  support/xpoll.c                            |   32 +
>  support/xpthread_attr_destroy.c            |   26 +
>  support/xpthread_attr_init.c               |   25 +
>  support/xpthread_attr_setdetachstate.c     |   27 +
>  support/xpthread_attr_setstacksize.c       |   26 +
>  support/xpthread_barrier_destroy.c         |   26 +
>  support/xpthread_barrier_init.c            |   27 +
>  support/xpthread_barrier_wait.c            |   28 +
>  support/xpthread_cancel.c                  |   25 +
>  support/xpthread_check_return.c            |   34 +
>  support/xpthread_cond_wait.c               |   26 +
>  support/xpthread_create.c                  |   29 +
>  support/xpthread_detach.c                  |   25 +
>  support/xpthread_join.c                    |   27 +
>  support/xpthread_mutex_consistent.c        |   26 +
>  support/xpthread_mutex_destroy.c           |   26 +
>  support/xpthread_mutex_init.c              |   26 +
>  support/xpthread_mutex_lock.c              |   25 +
>  support/xpthread_mutex_unlock.c            |   25 +
>  support/xpthread_mutexattr_destroy.c       |   26 +
>  support/xpthread_mutexattr_init.c          |   25 +
>  support/xpthread_mutexattr_setprotocol.c   |   26 +
>  support/xpthread_mutexattr_setpshared.c    |   26 +
>  support/xpthread_mutexattr_setrobust.c     |   26 +
>  support/xpthread_mutexattr_settype.c       |   26 +
>  support/xpthread_once.c                    |   25 +
>  support/xpthread_sigmask.c                 |   34 +
>  support/xpthread_spin_lock.c               |   25 +
>  support/xpthread_spin_unlock.c             |   25 +
>  support/xrealloc.c                         |   32 +
>  support/xrecvfrom.c                        |   33 +
>  support/xsendto.c                          |   35 +
>  support/xsetsockopt.c                      |   31 +
>  support/xsignal.h                          |   34 +
>  support/xsocket.c                          |   32 +
>  support/xsocket.h                          |   39 +
>  support/xstdio.h                           |   32 +
>  support/xstrdup.c                          |   30 +
>  support/xthread.h                          |   77 ++
>  support/xunistd.h                          |   56 ++
>  support/xwaitpid.c                         |   33 +
>  support/xwrite.c                           |   39 +
>  119 files changed, 7308 insertions(+), 3 deletions(-)
>  create mode 100644 scripts/backport-support.sh
>  create mode 100644 support/Makefile
>  create mode 100644 support/README
>  create mode 100644 support/README-testing.c
>  create mode 100644 support/capture_subprocess.h
>  create mode 100644 support/check.c
>  create mode 100644 support/check.h
>  create mode 100644 support/check_addrinfo.c
>  create mode 100644 support/check_dns_packet.c
>  create mode 100644 support/check_hostent.c
>  create mode 100644 support/check_netent.c
>  create mode 100644 support/check_nss.h
>  create mode 100644 support/delayed_exit.c
>  create mode 100644 support/format_nss.h
>  create mode 100644 support/ignore_stderr.c
>  create mode 100644 support/namespace.h
>  create mode 100644 support/oom_error.c
>  create mode 100644 support/resolv_test.c
>  create mode 100644 support/resolv_test.h
>  create mode 100644 support/run_diff.h
>  create mode 100644 support/set_fortify_handler.c
>  create mode 100644 support/support-xstat.c
>  create mode 100644 support/support.h
>  create mode 100644 support/support_become_root.c
>  create mode 100644 support/support_can_chroot.c
>  create mode 100644 support/support_capture_subprocess.c
>  create mode 100644 support/support_capture_subprocess_check.c
>  create mode 100644 support/support_enter_network_namespace.c
>  create mode 100644 support/support_format_address_family.c
>  create mode 100644 support/support_format_addrinfo.c
>  create mode 100644 support/support_format_dns_packet.c
>  create mode 100644 support/support_format_herrno.c
>  create mode 100644 support/support_format_hostent.c
>  create mode 100644 support/support_format_netent.c
>  create mode 100644 support/support_isolate_in_subprocess.c
>  create mode 100644 support/support_record_failure.c
>  create mode 100644 support/support_run_diff.c
>  create mode 100644 support/support_shared_allocate.c
>  create mode 100644 support/support_test_main.c
>  create mode 100644 support/support_test_verify_impl.c
>  create mode 100644 support/support_write_file_string.c
>  create mode 100644 support/temp_file-internal.h
>  create mode 100644 support/temp_file.c
>  create mode 100644 support/temp_file.h
>  create mode 100644 support/test-driver.c
>  create mode 100644 support/test-driver.h
>  create mode 100644 support/tst-support-namespace.c
>  create mode 100644 support/tst-support_capture_subprocess.c
>  create mode 100644 support/tst-support_format_dns_packet.c
>  create mode 100644 support/tst-support_record_failure-2.sh
>  create mode 100644 support/tst-support_record_failure.c
>  create mode 100644 support/write_message.c
>  create mode 100644 support/xaccept.c
>  create mode 100644 support/xaccept4.c
>  create mode 100644 support/xasprintf.c
>  create mode 100644 support/xbind.c
>  create mode 100644 support/xcalloc.c
>  create mode 100644 support/xchroot.c
>  create mode 100644 support/xclose.c
>  create mode 100644 support/xconnect.c
>  create mode 100644 support/xdup2.c
>  create mode 100644 support/xfclose.c
>  create mode 100644 support/xfopen.c
>  create mode 100644 support/xfork.c
>  create mode 100644 support/xgetsockname.c
>  create mode 100644 support/xlisten.c
>  create mode 100644 support/xmalloc.c
>  create mode 100644 support/xmemstream.c
>  create mode 100644 support/xmemstream.h
>  create mode 100644 support/xmkdir.c
>  create mode 100644 support/xmmap.c
>  create mode 100644 support/xmunmap.c
>  create mode 100644 support/xopen.c
>  create mode 100644 support/xpipe.c
>  create mode 100644 support/xpoll.c
>  create mode 100644 support/xpthread_attr_destroy.c
>  create mode 100644 support/xpthread_attr_init.c
>  create mode 100644 support/xpthread_attr_setdetachstate.c
>  create mode 100644 support/xpthread_attr_setstacksize.c
>  create mode 100644 support/xpthread_barrier_destroy.c
>  create mode 100644 support/xpthread_barrier_init.c
>  create mode 100644 support/xpthread_barrier_wait.c
>  create mode 100644 support/xpthread_cancel.c
>  create mode 100644 support/xpthread_check_return.c
>  create mode 100644 support/xpthread_cond_wait.c
>  create mode 100644 support/xpthread_create.c
>  create mode 100644 support/xpthread_detach.c
>  create mode 100644 support/xpthread_join.c
>  create mode 100644 support/xpthread_mutex_consistent.c
>  create mode 100644 support/xpthread_mutex_destroy.c
>  create mode 100644 support/xpthread_mutex_init.c
>  create mode 100644 support/xpthread_mutex_lock.c
>  create mode 100644 support/xpthread_mutex_unlock.c
>  create mode 100644 support/xpthread_mutexattr_destroy.c
>  create mode 100644 support/xpthread_mutexattr_init.c
>  create mode 100644 support/xpthread_mutexattr_setprotocol.c
>  create mode 100644 support/xpthread_mutexattr_setpshared.c
>  create mode 100644 support/xpthread_mutexattr_setrobust.c
>  create mode 100644 support/xpthread_mutexattr_settype.c
>  create mode 100644 support/xpthread_once.c
>  create mode 100644 support/xpthread_sigmask.c
>  create mode 100644 support/xpthread_spin_lock.c
>  create mode 100644 support/xpthread_spin_unlock.c
>  create mode 100644 support/xrealloc.c
>  create mode 100644 support/xrecvfrom.c
>  create mode 100644 support/xsendto.c
>  create mode 100644 support/xsetsockopt.c
>  create mode 100644 support/xsignal.h
>  create mode 100644 support/xsocket.c
>  create mode 100644 support/xsocket.h
>  create mode 100644 support/xstdio.h
>  create mode 100644 support/xstrdup.c
>  create mode 100644 support/xthread.h
>  create mode 100644 support/xunistd.h
>  create mode 100644 support/xwaitpid.c
>  create mode 100644 support/xwrite.c
> 
> diff --git a/Makeconfig b/Makeconfig
> index f136b88..b5d100b 100644
> --- a/Makeconfig
> +++ b/Makeconfig
> @@ -395,6 +395,9 @@ ifndef after-link
>  after-link =
>  endif
>  
> +# Additional libraries to link into every test.
> +link-extra-libs-tests = $(libsupport)
> +
>  # Command for linking PIE programs with the C library.
>  ifndef +link-pie
>  +link-pie-before-libc = $(CC) -pie -Wl,-O1 -nostdlib -nostartfiles -o $@ \
> @@ -504,7 +507,7 @@ link-libc = $(link-libc-rpath-link) $(link-libc-before-gnulib) $(gnulib)
>  link-libc-tests = $(link-libc-tests-rpath-link) \
>  		  $(link-libc-before-gnulib) $(gnulib-tests)
>  # This is how to find at build-time things that will be installed there.
> -rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec
> +rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec support
>  rpath-link = \
>  $(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%)))
>  else
> @@ -851,7 +854,7 @@ libio-include = -I$(..)libio
>  # List of non-library modules that we build.
>  built-modules = iconvprogs iconvdata ldconfig lddlibc4 libmemusage \
>  		libSegFault libpcprofile librpcsvc locale-programs \
> -		memusagestat nonlib nscd extramodules libnldbl
> +		memusagestat nonlib nscd extramodules libnldbl libsupport
>  
>  in-module = $(subst -,_,$(firstword $(libof-$(basename $(@F))) \
>  				    $(libof-$(<F)) \
> @@ -1089,6 +1092,12 @@ libm = $(common-objpfx)math/libm.a
>  libmvec = $(common-objpfx)mathvec/libmvec.a
>  endif
>  
> +ifeq ($(build-shared),yes)
> +libsupport = $(common-objpfx)support/libsupport_nonshared.a
> +else
> +libsupport = $(common-objpfx)support/libsupport.a
> +endif
> +
>  # These are the subdirectories containing the library source.  The order
>  # is more or less arbitrary.  The sorting step will take care of the
>  # dependencies.
> @@ -1096,7 +1105,7 @@ all-subdirs = csu assert ctype locale intl catgets math setjmp signal	    \
>  	      stdlib stdio-common libio malloc string wcsmbs time dirent    \
>  	      grp pwd posix io termios resource misc socket sysvipc gmon    \
>  	      gnulib iconv iconvdata wctype manual shadow gshadow po argp   \
> -	      crypt localedata timezone rt conform debug mathvec	    \
> +	      crypt localedata timezone rt conform debug mathvec support    \
>  	      $(add-on-subdirs) dlfcn elf
>  
>  ifndef avoid-generated
> diff --git a/Rules b/Rules
> index e237d03..7c5777c 100644
> --- a/Rules
> +++ b/Rules
> @@ -149,6 +149,7 @@ endif
>  
>  ifneq "$(strip $(binaries-shared-tests))" ""
>  $(addprefix $(objpfx),$(binaries-shared-tests)): %: %.o \
> +  $(link-extra-libs-tests) \
>    $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \
>    $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit)
>  	$(+link-tests)
> @@ -156,6 +157,7 @@ endif
>  
>  ifneq "$(strip $(binaries-pie-tests))" ""
>  $(addprefix $(objpfx),$(binaries-pie-tests)): %: %.o \
> +  $(link-extra-libs-tests) \
>    $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \
>    $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit)
>  	$(+link-pie-tests)
> @@ -177,6 +179,7 @@ endif
>  
>  ifneq "$(strip $(binaries-static-tests))" ""
>  $(addprefix $(objpfx),$(binaries-static-tests)): %: %.o \
> +  $(link-extra-libs-tests) \
>    $(sort $(filter $(common-objpfx)lib%,$(link-libc-static-tests))) \
>    $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit)
>  	$(+link-static-tests)
> diff --git a/extra-lib.mk b/extra-lib.mk
> index b10748d..2552049 100644
> --- a/extra-lib.mk
> +++ b/extra-lib.mk
> @@ -5,6 +5,9 @@
>  # The variable $($(lib)-routines) defines the list of modules
>  # to be included in that library.  A sysdep Makefile can add to
>  # $(lib)-sysdep_routines to include additional modules.
> +#
> +# Libraries listed in $(extra-libs-noinstall) are built, but not
> +# installed.
>  
>  lib := $(firstword $(extra-libs-left))
>  extra-libs-left := $(filter-out $(lib),$(extra-libs-left))
> @@ -28,7 +31,9 @@ extra-objs := $(extra-objs)
>  all-$(lib)-routines := $($(lib)-routines) $($(lib)-sysdep_routines)
>  
>  # Add each flavor of library to the lists of things to build and install.
> +ifeq (,$(filter $(lib), $(extra-libs-noinstall)))
>  install-lib += $(foreach o,$(object-suffixes-$(lib)),$(lib:lib%=$(libtype$o)))
> +endif
>  extra-objs += $(foreach o,$(filter-out .os .oS,$(object-suffixes-$(lib))),\
>  			$(patsubst %,%$o,$(filter-out \
>  					   $($(lib)-shared-only-routines),\
> diff --git a/scripts/backport-support.sh b/scripts/backport-support.sh
> new file mode 100644
> index 0000000..2ece7ce
> --- /dev/null
> +++ b/scripts/backport-support.sh
> @@ -0,0 +1,110 @@
> +#!/bin/bash
> +# Create a patch which backports the support/ subdirectory.
> +# 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/>.
> +
> +# This script does not backport the Makefile tweaks outside the
> +# support/ directory (which need to be backported separately), or the
> +# changes to test-skeleton.c (which should not be backported).
> +
> +set -e
> +
> +export LC_ALL=C
> +export GIT_CONFIG=/dev/null
> +export GTT_CONFIG_NOSYSTEM=0
> +export GIT_PAGER=
> +
> +usage () {
> +    cat >&2 <<EOF
> +usage: $0 {patch|commit}
> +EOF
> +    exit 1
> +}
> +
> +if test $# -ne 1 ; then
> +    usage
> +fi
> +
> +command="$1"
> +
> +case "$command" in
> +    patch|commit)
> +    ;;
> +    *)
> +	usage
> +	;;
> +esac
> +
> +# The upstream branch to work on.
> +branch=origin/master
> +
> +# The commit which added the support/ directory.
> +initial_commit=c23de0aacbeaa7a091609b35764bed931475a16d
> +
> +# We backport the support directory and this script.  Directories need
> +# to end in a /.
> +patch_targets="support/ scripts/backport-support.sh"
> +
> +latest_commit="$(git log --max-count=1 --pretty=format:%H "$branch" -- \
> +  $patch_targets)"
> +
> +# Simplify the branch name somewhat for reporting.
> +branch_name="$(echo "$branch" | sed s,^origin/,,)"
> +
> +command_patch () {
> +    cat <<EOF
> +This patch creates the contents of the support/ directory up to this
> +upstream commit on the $branch_name branch:
> +
> +EOF
> +    git log --max-count=1 "$latest_commit"
> +    echo
> +    git diff "$initial_commit"^.."$latest_commit" $patch_targets
> +    echo "# Before applying the patch, run this command:" >&2
> +    echo "# rm -rf $patch_targets" >&2
> +}
> +
> +command_commit () {
> +    git status --porcelain | while read line ; do
> +	echo "error: working copy is not clean, cannot commit" >&2
> +	exit 1
> +    done
> +    for path in $patch_targets; do
> +	echo "# Processing $path" >&2
> +	case "$path" in
> +	    [a-zA-Z0-9]*/)
> +		# Directory.
> +		git rm --cached --ignore-unmatch -r "$path"
> +		rm -rf "$path"
> +		git read-tree --prefix="$path" "$latest_commit":"$path"
> +		git checkout "$path"
> +		;;
> +	    *)
> +		# File.
> +		git show "$latest_commit":"$path" > "$path"
> +		git add "$path"
> +	esac
> +    done
> +    git commit -m "Synchronize support/ infrastructure with $branch_name
> +
> +This commit updates the support/ subdirectory to
> +commit $latest_commit
> +on the $branch_name branch.
> +"
> +}
> +
> +command_$command
> diff --git a/support/Makefile b/support/Makefile
> new file mode 100644
> index 0000000..20b0343
> --- /dev/null
> +++ b/support/Makefile
> @@ -0,0 +1,146 @@
> +# Makefile for support library, used only at build and test time
> +# 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/>.
> +
> +subdir := support
> +
> +include ../Makeconfig
> +
> +extra-libs := libsupport
> +extra-libs-others = $(extra-libs)
> +extra-libs-noinstall := $(extra-libs)
> +
> +libsupport-routines = \
> +  check \
> +  check_addrinfo \
> +  check_dns_packet \
> +  check_hostent \
> +  check_netent \
> +  delayed_exit \
> +  ignore_stderr \
> +  oom_error \
> +  resolv_test \
> +  set_fortify_handler \
> +  support-xstat \
> +  support_become_root \
> +  support_can_chroot \
> +  support_capture_subprocess \
> +  support_capture_subprocess_check \
> +  support_enter_network_namespace \
> +  support_format_address_family \
> +  support_format_addrinfo \
> +  support_format_dns_packet \
> +  support_format_herrno \
> +  support_format_hostent \
> +  support_format_netent \
> +  support_isolate_in_subprocess \
> +  support_record_failure \
> +  support_run_diff \
> +  support_shared_allocate \
> +  support_write_file_string \
> +  support_test_main \
> +  support_test_verify_impl \
> +  temp_file \
> +  write_message \
> +  xaccept \
> +  xaccept4 \
> +  xasprintf \
> +  xbind \
> +  xcalloc \
> +  xchroot \
> +  xclose \
> +  xconnect \
> +  xdup2 \
> +  xfclose \
> +  xfopen \
> +  xfork \
> +  xgetsockname \
> +  xlisten \
> +  xmalloc \
> +  xmemstream \
> +  xmkdir \
> +  xmmap \
> +  xmunmap \
> +  xopen \
> +  xpipe \
> +  xpoll \
> +  xpthread_attr_destroy \
> +  xpthread_attr_init \
> +  xpthread_attr_setdetachstate \
> +  xpthread_attr_setstacksize \
> +  xpthread_barrier_destroy \
> +  xpthread_barrier_init \
> +  xpthread_barrier_wait \
> +  xpthread_cancel \
> +  xpthread_check_return \
> +  xpthread_cond_wait \
> +  xpthread_create \
> +  xpthread_detach \
> +  xpthread_join \
> +  xpthread_mutex_consistent \
> +  xpthread_mutex_destroy \
> +  xpthread_mutex_init \
> +  xpthread_mutex_lock \
> +  xpthread_mutex_unlock \
> +  xpthread_mutexattr_destroy \
> +  xpthread_mutexattr_init \
> +  xpthread_mutexattr_setprotocol \
> +  xpthread_mutexattr_setpshared \
> +  xpthread_mutexattr_setrobust \
> +  xpthread_mutexattr_settype \
> +  xpthread_once \
> +  xpthread_sigmask \
> +  xpthread_spin_lock \
> +  xpthread_spin_unlock \
> +  xrealloc \
> +  xrecvfrom \
> +  xsendto \
> +  xsetsockopt \
> +  xsocket \
> +  xstrdup \
> +  xwaitpid \
> +  xwrite \
> +
> +libsupport-static-only-routines := $(libsupport-routines)
> +# Only build one variant of the library.
> +libsupport-inhibit-o := .os
> +ifeq ($(build-shared),yes)
> +libsupport-inhibit-o += .o
> +endif
> +
> +tests = \
> +  README-testing \
> +  tst-support-namespace \
> +  tst-support_capture_subprocess \
> +  tst-support_format_dns_packet \
> +  tst-support_record_failure \
> +
> +ifeq ($(run-built-tests),yes)
> +tests-special = \
> +  $(objpfx)tst-support_record_failure-2.out
> +
> +$(objpfx)tst-support_record_failure-2.out: tst-support_record_failure-2.sh \
> +  $(objpfx)tst-support_record_failure
> +	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
> +	  '$(run-program-env)' '$(test-program-prefix-after-env)' \
> +	  > $@; \
> +	$(evaluate-test)
> +endif
> +
> +$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so
> +
> +include ../Rules
> diff --git a/support/README b/support/README
> new file mode 100644
> index 0000000..476cfcd
> --- /dev/null
> +++ b/support/README
> @@ -0,0 +1,29 @@
> +This subdirectory contains infrastructure which is not put into
> +installed libraries, but may be linked into programs (installed or
> +not) and tests.
> +
> +# Error-checking wrappers
> +
> +These wrappers test for error return codes an terminate the process on
> +error.  They are declared in these header files:
> +
> +* support.h
> +* xsignal.h
> +* xthread.h
> +
> +In general, new wrappers should be added to support.h if possible.
> +However, support.h must remain fully compatible with C90 and therefore
> +cannot include headers which use identifers not reserved in C90.  If
> +the wrappers need additional types, additional headers such as
> +signal.h need to be introduced.
> +
> +# Test framework
> +
> +The test framework provides a main program for tests, including a
> +timeout for hanging tests.  See README-testing.c for a minimal
> +example, and test-driver.c for details how to use it.  The following
> +header files provide related declarations:
> +
> +* check.h
> +* temp_file.h
> +* test-driver.h
> diff --git a/support/README-testing.c b/support/README-testing.c
> new file mode 100644
> index 0000000..9d289c3
> --- /dev/null
> +++ b/support/README-testing.c
> @@ -0,0 +1,19 @@
> +/* This file contains an example test case which shows minimal use of
> +   the test framework.  Additional testing hooks are described in
> +   <support/test-driver.c>.  */
> +
> +/* This function will be called from the test driver.  */
> +static int
> +do_test (void)
> +{
> +  if (3 == 5)
> +    /* Indicate failure.  */
> +    return 1;
> +  else
> +    /* Indicate success.  */
> +    return 0;
> +}
> +
> +/* This file references do_test above and contains the definition of
> +   the main function.  */
> +#include <support/test-driver.c>
> diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
> new file mode 100644
> index 0000000..43caf9b
> --- /dev/null
> +++ b/support/capture_subprocess.h
> @@ -0,0 +1,61 @@
> +/* Capture output from a subprocess.
> +   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_CAPTURE_SUBPROCESS_H
> +#define SUPPORT_CAPTURE_SUBPROCESS_H
> +
> +#include <support/xmemstream.h>
> +
> +struct support_capture_subprocess
> +{
> +  struct xmemstream out;
> +  struct xmemstream err;
> +  int status;
> +};
> +
> +/* Invoke CALLBACK (CLOSURE) in a subprocess and capture standard
> +   output, standard error, and the exit status.  The out.buffer and
> +   err.buffer members in the result are null-terminated strings which
> +   can be examined by the caller (out.out and err.out are NULL).  */
> +struct support_capture_subprocess support_capture_subprocess
> +  (void (*callback) (void *), void *closure);
> +
> +/* Deallocate the subprocess data captured by
> +   support_capture_subprocess.  */
> +void support_capture_subprocess_free (struct support_capture_subprocess *);
> +
> +enum support_capture_allow
> +{
> +  /* No output is allowed.  */
> +  sc_allow_none = 0x01,
> +  /* Output to stdout is permitted.  */
> +  sc_allow_stdout = 0x02,
> +  /* Output to standard error is permitted.  */
> +  sc_allow_stderr = 0x04,
> +};
> +
> +/* Check that the subprocess exited with STATUS and that only the
> +   allowed outputs happened.  ALLOWED is a combination of
> +   support_capture_allow flags.  Report errors under the CONTEXT
> +   message.  */
> +void support_capture_subprocess_check (struct support_capture_subprocess *,
> +                                       const char *context, int status,
> +                                       int allowed)
> +  __attribute__ ((nonnull (1, 2)));
> +
> +#endif /* SUPPORT_CAPTURE_SUBPROCESS_H */
> diff --git a/support/check.c b/support/check.c
> new file mode 100644
> index 0000000..592f2bc
> --- /dev/null
> +++ b/support/check.c
> @@ -0,0 +1,57 @@
> +/* Support code for reporting test results.
> +   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/check.h>
> +
> +#include <stdarg.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/test-driver.h>
> +
> +static void
> +print_failure (const char *file, int line, const char *format, va_list ap)
> +{
> +  printf ("error: %s:%d: ", file, line);
> +  vprintf (format, ap);
> +  puts ("");
> +}
> +
> +int
> +support_print_failure_impl (const char *file, int line,
> +                            const char *format, ...)
> +{
> +  support_record_failure ();
> +  va_list ap;
> +  va_start (ap, format);
> +  print_failure (file, line, format, ap);
> +  va_end (ap);
> +  return 1;
> +}
> +
> +void
> +support_exit_failure_impl (int status, const char *file, int line,
> +                           const char *format, ...)
> +{
> +  if (status != EXIT_SUCCESS && status != EXIT_UNSUPPORTED)
> +    support_record_failure ();
> +  va_list ap;
> +  va_start (ap, format);
> +  print_failure (file, line, format, ap);
> +  va_end (ap);
> +  exit (status);
> +}
> diff --git a/support/check.h b/support/check.h
> new file mode 100644
> index 0000000..1d244a3
> --- /dev/null
> +++ b/support/check.h
> @@ -0,0 +1,94 @@
> +/* Functionality for reporting test results.
> +   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/>.  */
> +
> +#ifndef SUPPORT_CHECK_H
> +#define SUPPORT_CHECK_H
> +
> +#include <sys/cdefs.h>
> +
> +__BEGIN_DECLS
> +
> +/* Record a test failure, print the failure message to standard output
> +   and return 1.  */
> +#define FAIL_RET(...) \
> +  return support_print_failure_impl (__FILE__, __LINE__, __VA_ARGS__)
> +
> +/* Print the failure message and terminate the process with STATUS.
> +   Record a the process as failed if STATUS is neither EXIT_SUCCESS
> +   nor EXIT_UNSUPPORTED.  */
> +#define FAIL_EXIT(status, ...) \
> +  support_exit_failure_impl (status, __FILE__, __LINE__, __VA_ARGS__)
> +
> +/* Record a test failure, print the failure message and terminate with
> +   exit status 1.  */
> +#define FAIL_EXIT1(...) \
> +  support_exit_failure_impl (1, __FILE__, __LINE__, __VA_ARGS__)
> +
> +/* Print failure message and terminate with as unsupported test (exit
> +   status of 77).  */
> +#define FAIL_UNSUPPORTED(...) \
> +  support_exit_failure_impl (77, __FILE__, __LINE__, __VA_ARGS__)
> +
> +/* Record a test failure (but continue executing) if EXPR evaluates to
> +   false.  */
> +#define TEST_VERIFY(expr)                                       \
> +  ({                                                            \
> +    if (expr)                                                   \
> +      ;                                                         \
> +    else                                                        \
> +      support_test_verify_impl (-1, __FILE__, __LINE__, #expr); \
> +  })
> +
> +/* Record a test failure and exit if EXPR evaluates to false.  */
> +#define TEST_VERIFY_EXIT(expr)                                  \
> +  ({                                                            \
> +    if (expr)                                                   \
> +      ;                                                         \
> +    else                                                        \
> +      support_test_verify_impl (1, __FILE__, __LINE__, #expr);  \
> +  })
> +
> +int support_print_failure_impl (const char *file, int line,
> +                                const char *format, ...)
> +  __attribute__ ((nonnull (1), format (printf, 3, 4)));
> +void support_exit_failure_impl (int exit_status,
> +                                const char *file, int line,
> +                                const char *format, ...)
> +  __attribute__ ((noreturn, nonnull (2), format (printf, 4, 5)));
> +void support_test_verify_impl (int status, const char *file, int line,
> +                               const char *expr);
> +
> +/* Record a test failure.  This function returns and does not
> +   terminate the process.  The failure counter is stored in a shared
> +   memory mapping, so that failures reported in child processes are
> +   visible to the parent process and test driver.  This function
> +   depends on initialization by an ELF constructor, so it can only be
> +   invoked after the test driver has run.  Note that this function
> +   does not support reporting failures from a DSO.  */
> +void support_record_failure (void);
> +
> +/* Internal function called by the test driver.  */
> +int support_report_failure (int status)
> +  __attribute__ ((weak, warn_unused_result));
> +
> +/* Internal function used to test the failure recording framework.  */
> +void support_record_failure_reset (void);
> +
> +__END_DECLS
> +
> +#endif /* SUPPORT_CHECK_H */
> diff --git a/support/check_addrinfo.c b/support/check_addrinfo.c
> new file mode 100644
> index 0000000..55895ac
> --- /dev/null
> +++ b/support/check_addrinfo.c
> @@ -0,0 +1,42 @@
> +/* Compare struct addrinfo values against a formatted string.
> +   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/check_nss.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <support/format_nss.h>
> +#include <support/run_diff.h>
> +
> +void
> +check_addrinfo (const char *query_description, struct addrinfo *ai, int ret,
> +                const char *expected)
> +{
> +  char *formatted = support_format_addrinfo (ai, ret);
> +  if (strcmp (formatted, expected) != 0)
> +    {
> +      support_record_failure ();
> +      printf ("error: addrinfo comparison failure\n");
> +      if (query_description != NULL)
> +        printf ("query: %s\n", query_description);
> +      support_run_diff ("expected", expected,
> +                        "actual", formatted);
> +    }
> +  free (formatted);
> +}
> diff --git a/support/check_dns_packet.c b/support/check_dns_packet.c
> new file mode 100644
> index 0000000..d2a31be
> --- /dev/null
> +++ b/support/check_dns_packet.c
> @@ -0,0 +1,42 @@
> +/* Check that a DNS packet buffer has the expected contents.
> +   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/check_nss.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <support/format_nss.h>
> +#include <support/run_diff.h>
> +
> +void
> +check_dns_packet (const char *query_description,
> +                  const unsigned char *buffer, size_t length,
> +                  const char *expected)
> +{
> +  char *formatted = support_format_dns_packet (buffer, length);
> +  if (strcmp (formatted, expected) != 0)
> +    {
> +      support_record_failure ();
> +      printf ("error: packet comparison failure\n");
> +      if (query_description != NULL)
> +        printf ("query: %s\n", query_description);
> +      support_run_diff ("expected", expected, "actual", formatted);
> +    }
> +  free (formatted);
> +}
> diff --git a/support/check_hostent.c b/support/check_hostent.c
> new file mode 100644
> index 0000000..890d672
> --- /dev/null
> +++ b/support/check_hostent.c
> @@ -0,0 +1,42 @@
> +/* Compare struct hostent values against a formatted string.
> +   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/check_nss.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <support/format_nss.h>
> +#include <support/run_diff.h>
> +
> +void
> +check_hostent (const char *query_description, struct hostent *h,
> +               const char *expected)
> +{
> +  char *formatted = support_format_hostent (h);
> +  if (strcmp (formatted, expected) != 0)
> +    {
> +      support_record_failure ();
> +      printf ("error: hostent comparison failure\n");
> +      if (query_description != NULL)
> +        printf ("query: %s\n", query_description);
> +      support_run_diff ("expected", expected,
> +                        "actual", formatted);
> +    }
> +  free (formatted);
> +}
> diff --git a/support/check_netent.c b/support/check_netent.c
> new file mode 100644
> index 0000000..daa3083
> --- /dev/null
> +++ b/support/check_netent.c
> @@ -0,0 +1,42 @@
> +/* Compare struct netent values against a formatted string.
> +   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/check_nss.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <support/format_nss.h>
> +#include <support/run_diff.h>
> +
> +void
> +check_netent (const char *query_description, struct netent *e,
> +              const char *expected)
> +{
> +  char *formatted = support_format_netent (e);
> +  if (strcmp (formatted, expected) != 0)
> +    {
> +      support_record_failure ();
> +      printf ("error: netent comparison failure\n");
> +      if (query_description != NULL)
> +        printf ("query: %s\n", query_description);
> +      support_run_diff ("expected", expected,
> +                        "actual", formatted);
> +    }
> +  free (formatted);
> +}
> diff --git a/support/check_nss.h b/support/check_nss.h
> new file mode 100644
> index 0000000..2893f2c
> --- /dev/null
> +++ b/support/check_nss.h
> @@ -0,0 +1,42 @@
> +/* Test verification functions for NSS- and DNS-related data.
> +   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/>.  */
> +
> +#ifndef SUPPORT_CHECK_NSS_H
> +#define SUPPORT_CHECK_NSS_H
> +
> +#include <netdb.h>
> +#include <sys/cdefs.h>
> +
> +__BEGIN_DECLS
> +
> +/* Compare the data structures against the expected values (which have
> +   to be formatted according to the support_format_* functions in
> +   <support/format_nss.h>).  If there is a difference, a delayed test
> +   failure is recorded, and a diff is written to standard output.  */
> +void check_addrinfo (const char *query_description,
> +                     struct addrinfo *, int ret, const char *expected);
> +void check_dns_packet (const char *query_description,
> +                       const unsigned char *, size_t, const char *expected);
> +void check_hostent (const char *query_description,
> +                    struct hostent *, const char *expected);
> +void check_netent (const char *query_description,
> +                   struct netent *, const char *expected);
> +
> +__END_DECLS
> +
> +#endif  /* SUPPORT_CHECK_NSS_H */
> diff --git a/support/delayed_exit.c b/support/delayed_exit.c
> new file mode 100644
> index 0000000..67442f9
> --- /dev/null
> +++ b/support/delayed_exit.c
> @@ -0,0 +1,55 @@
> +/* Time-triggered process termination.
> +   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/xthread.h>
> +#include <support/xsignal.h>
> +
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <time.h>
> +
> +static void *
> +delayed_exit_thread (void *seconds_as_ptr)
> +{
> +  int seconds = (uintptr_t) seconds_as_ptr;
> +  struct timespec delay = { seconds, 0 };
> +  struct timespec remaining = { 0 };
> +  if (nanosleep (&delay, &remaining) != 0)
> +    FAIL_EXIT1 ("nanosleep: %m");
> +  /* Exit the process sucessfully.  */
> +  exit (0);
> +  return NULL;
> +}
> +
> +void
> +delayed_exit (int seconds)
> +{
> +  /* Create the new thread with all signals blocked.  */
> +  sigset_t all_blocked;
> +  sigfillset (&all_blocked);
> +  sigset_t old_set;
> +  xpthread_sigmask (SIG_SETMASK, &all_blocked, &old_set);
> +  /* Create a detached thread. */
> +  pthread_t thr = xpthread_create
> +    (NULL, delayed_exit_thread, (void *) (uintptr_t) seconds);
> +  xpthread_detach (thr);
> +  /* Restore the original signal mask.  */
> +  xpthread_sigmask (SIG_SETMASK, &old_set, NULL);
> +}
> diff --git a/support/format_nss.h b/support/format_nss.h
> new file mode 100644
> index 0000000..fb4597c
> --- /dev/null
> +++ b/support/format_nss.h
> @@ -0,0 +1,41 @@
> +/* String formatting functions for NSS- and DNS-related data.
> +   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/>.  */
> +
> +#ifndef SUPPORT_FORMAT_NSS_H
> +#define SUPPORT_FORMAT_NSS_H
> +
> +#include <netdb.h>
> +#include <sys/cdefs.h>
> +
> +__BEGIN_DECLS
> +
> +/* The following functions format their arguments as human-readable
> +   strings (which can span multiple lines).  The caller must free the
> +   returned buffer.  For NULL pointers or failure status arguments,
> +   error variables such as h_errno and errno are included in the
> +   result.  */
> +char *support_format_address_family (int);
> +char *support_format_addrinfo (struct addrinfo *, int ret);
> +char *support_format_dns_packet (const unsigned char *buffer, size_t length);
> +char *support_format_herrno (int);
> +char *support_format_hostent (struct hostent *);
> +char *support_format_netent (struct netent *);
> +
> +__END_DECLS
> +
> +#endif  /* SUPPORT_FORMAT_NSS_H */
> diff --git a/support/ignore_stderr.c b/support/ignore_stderr.c
> new file mode 100644
> index 0000000..7b77a2c
> --- /dev/null
> +++ b/support/ignore_stderr.c
> @@ -0,0 +1,38 @@
> +/* Avoid all the buffer overflow messages on stderr.
> +   Copyright (C) 2015-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 <fcntl.h>
> +#include <paths.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +
> +void
> +ignore_stderr (void)
> +{
> +  int fd = open (_PATH_DEVNULL, O_WRONLY);
> +  if (fd == -1)
> +    close (STDERR_FILENO);
> +  else
> +    {
> +      dup2 (fd, STDERR_FILENO);
> +      close (fd);
> +    }
> +  setenv ("LIBC_FATAL_STDERR_", "1", 1);
> +}
> diff --git a/support/namespace.h b/support/namespace.h
> new file mode 100644
> index 0000000..e1ccaa1
> --- /dev/null
> +++ b/support/namespace.h
> @@ -0,0 +1,65 @@
> +/* Entering namespaces for test case isolation.
> +   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/>.  */
> +
> +#ifndef SUPPORT_NAMESPACE_H
> +#define SUPPORT_NAMESPACE_H
> +
> +#include <stdbool.h>
> +#include <sys/cdefs.h>
> +
> +__BEGIN_DECLS
> +
> +/* Attempts to become root (or acquire root-like privileges), possibly
> +   with the help of user namespaces.  Return true if (restricted) root
> +   privileges could be attained in some way.  Print diagnostics to
> +   standard output.
> +
> +   Note that this function generally has to be called before a process
> +   becomes multi-threaded, otherwise it may fail with insufficient
> +   privileges on systems which would support this operation for
> +   single-threaded processes.  */
> +bool support_become_root (void);
> +
> +/* Return true if this process can perform a chroot operation.  In
> +   general, this is only possible if support_become_root has been
> +   called.  Note that the actual test is performed in a subprocess,
> +   after fork, so that the file system root of the original process is
> +   not changed.  */
> +bool support_can_chroot (void);
> +
> +/* Enter a network namespace (and a UTS namespace if possible) and
> +   configure the loopback interface.  Return true if a network
> +   namespace could be created.  Print diagnostics to standard output.
> +   If a network namespace could be created, but networking in it could
> +   not be configured, terminate the process.  It is recommended to
> +   call support_become_root before this function so that the process
> +   has sufficient privileges.  */
> +bool support_enter_network_namespace (void);
> +
> +/* Return true if support_enter_network_namespace managed to enter a
> +   UTS namespace.  */
> +bool support_in_uts_namespace (void);
> +
> +/* Invoke CALLBACK (CLOSURE) in a subprocess created using fork.
> +   Terminate the calling process if the subprocess exits with a
> +   non-zero exit status.  */
> +void support_isolate_in_subprocess (void (*callback) (void *), void *closure);
> +
> +__END_DECLS
> +
> +#endif
> diff --git a/support/oom_error.c b/support/oom_error.c
> new file mode 100644
> index 0000000..7816978
> --- /dev/null
> +++ b/support/oom_error.c
> @@ -0,0 +1,29 @@
> +/* Reporting out-of-memory errors.
> +   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 <stdio.h>
> +#include <stdlib.h>
> +
> +void
> +oom_error (const char *function, size_t size)
> +{
> +  printf ("%s: unable to allocate %zu bytes: %m\n", function, size);
> +  exit (1);
> +}
> diff --git a/support/resolv_test.c b/support/resolv_test.c
> new file mode 100644
> index 0000000..050cd71
> --- /dev/null
> +++ b/support/resolv_test.c
> @@ -0,0 +1,1202 @@
> +/* DNS test framework and libresolv redirection.
> +   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/resolv_test.h>
> +
> +#include <arpa/inet.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <nss.h>
> +#include <resolv.h>
> +#include <search.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <support/check.h>
> +#include <support/namespace.h>
> +#include <support/support.h>
> +#include <support/test-driver.h>
> +#include <support/xsocket.h>
> +#include <support/xthread.h>
> +#include <support/xunistd.h>
> +#include <sys/uio.h>
> +#include <unistd.h>
> +
> +/* Response builder.  */
> +
> +enum
> +  {
> +    max_response_length = 65536
> +  };
> +
> +/* List of pointers to be freed.  The hash table implementation
> +   (struct hsearch_data) does not provide a way to deallocate all
> +   objects, so this approach is used to avoid memory leaks.  */
> +struct to_be_freed
> +{
> +  struct to_be_freed *next;
> +  void *ptr;
> +};
> +
> +struct resolv_response_builder
> +{
> +  const unsigned char *query_buffer;
> +  size_t query_length;
> +
> +  size_t offset;                /* Bytes written so far in buffer.  */
> +  ns_sect section;              /* Current section in the DNS packet.  */
> +  unsigned int truncate_bytes;  /* Bytes to remove at end of response. */
> +  bool drop;                    /* Discard generated response.  */
> +  bool close;                   /* Close TCP client connection.  */
> +
> +  /* Offset of the two-byte RDATA length field in the currently
> +     written RDATA sub-structure.  0 if no RDATA is being written.  */
> +  size_t current_rdata_offset;
> +
> +  /* Hash table for locating targets for label compression.  */
> +  struct hsearch_data compression_offsets;
> +  /* List of pointers which need to be freed.  Used for domain names
> +     involved in label compression.  */
> +  struct to_be_freed *to_be_freed;
> +
> +  /* Must be last.  Not zeroed for performance reasons.  */
> +  unsigned char buffer[max_response_length];
> +};
> +
> +/* Response builder. */
> +
> +/* Add a pointer to the list of pointers to be freed when B is
> +   deallocated.  */
> +static void
> +response_push_pointer_to_free (struct resolv_response_builder *b, void *ptr)
> +{
> +  if (ptr == NULL)
> +    return;
> +  struct to_be_freed *e = xmalloc (sizeof (*e));
> +  *e = (struct to_be_freed) {b->to_be_freed, ptr};
> +  b->to_be_freed = e;
> +}
> +
> +void
> +resolv_response_init (struct resolv_response_builder *b,
> +                      struct resolv_response_flags flags)
> +{
> +  if (b->offset > 0)
> +    FAIL_EXIT1 ("response_init: called at offset %zu", b->offset);
> +  if (b->query_length < 12)
> +    FAIL_EXIT1 ("response_init called for a query of size %zu",
> +                b->query_length);
> +  if (flags.rcode > 15)
> +    FAIL_EXIT1 ("response_init: invalid RCODE %u", flags.rcode);
> +
> +  /* Copy the transaction ID.  */
> +  b->buffer[0] = b->query_buffer[0];
> +  b->buffer[1] = b->query_buffer[1];
> +
> +  /* Initialize the flags.  */
> +  b->buffer[2] = 0x80;                       /* Mark as response.   */
> +  b->buffer[2] |= b->query_buffer[2] & 0x01; /* Copy the RD bit.  */
> +  if (flags.tc)
> +    b->buffer[2] |= 0x02;
> +  b->buffer[3] = 0x80 | flags.rcode; /* Always set RA.  */
> +
> +  /* Fill in the initial section count values.  */
> +  b->buffer[4] = flags.qdcount >> 8;
> +  b->buffer[5] = flags.qdcount;
> +  b->buffer[6] = flags.ancount >> 8;
> +  b->buffer[7] = flags.ancount;
> +  b->buffer[8] = flags.nscount >> 8;
> +  b->buffer[9] = flags.nscount;
> +  b->buffer[10] = flags.adcount >> 8;
> +  b->buffer[11] = flags.adcount;
> +
> +  b->offset = 12;
> +}
> +
> +void
> +resolv_response_section (struct resolv_response_builder *b, ns_sect section)
> +{
> +  if (b->offset == 0)
> +    FAIL_EXIT1 ("resolv_response_section: response_init not called before");
> +  if (section < b->section)
> +    FAIL_EXIT1 ("resolv_response_section: cannot go back to previous section");
> +  b->section = section;
> +}
> +
> +/* Add a single byte to B.  */
> +static inline void
> +response_add_byte (struct resolv_response_builder *b, unsigned char ch)
> +{
> +  if (b->offset == max_response_length)
> +    FAIL_EXIT1 ("DNS response exceeds 64 KiB limit");
> +  b->buffer[b->offset] = ch;
> +  ++b->offset;
> +}
> +
> +/* Add a 16-bit word VAL to B, in big-endian format.  */
> +static void
> +response_add_16 (struct resolv_response_builder *b, uint16_t val)
> +{
> +  response_add_byte (b, val >> 8);
> +  response_add_byte (b, val);
> +}
> +
> +/* Increment the pers-section record counter in the packet header.  */
> +static void
> +response_count_increment (struct resolv_response_builder *b)
> +{
> +  unsigned int offset = b->section;
> +  offset = 4 + 2 * offset;
> +  ++b->buffer[offset + 1];
> +  if (b->buffer[offset + 1] == 0)
> +    {
> +      /* Carry.  */
> +      ++b->buffer[offset];
> +      if (b->buffer[offset] == 0)
> +        /* Overflow.  */
> +        FAIL_EXIT1 ("too many records in section");
> +    }
> +}
> +
> +void
> +resolv_response_add_question (struct resolv_response_builder *b,
> +                              const char *name, uint16_t class, uint16_t type)
> +{
> +  if (b->offset == 0)
> +    FAIL_EXIT1 ("resolv_response_add_question: "
> +                "resolv_response_init not called");
> +  if (b->section != ns_s_qd)
> +    FAIL_EXIT1 ("resolv_response_add_question: "
> +                "must be called in the question section");
> +
> +  resolv_response_add_name (b, name);
> +  response_add_16 (b, type);
> +  response_add_16 (b, class);
> +
> +  response_count_increment (b);
> +}
> +
> +void
> +resolv_response_add_name (struct resolv_response_builder *b,
> +                          const char *const origname)
> +{
> +  /* Normalized name.  */
> +  char *name;
> +  /* Normalized name with case preserved.  */
> +  char *name_case;
> +  {
> +    size_t namelen = strlen (origname);
> +    /* Remove trailing dots.  FIXME: Handle trailing quoted dots.  */
> +    while (namelen > 0 && origname[namelen - 1] == '.')
> +      --namelen;
> +    name = xmalloc (namelen + 1);
> +    name_case = xmalloc (namelen + 1);
> +    /* Copy and convert to lowercase.  FIXME: This needs to normalize
> +       escaping as well.  */
> +    for (size_t i = 0; i < namelen; ++i)
> +      {
> +        char ch = origname[i];
> +        name_case[i] = ch;
> +        if ('A' <= ch && ch <= 'Z')
> +          ch = ch - 'A' + 'a';
> +        name[i] = ch;
> +      }
> +    name[namelen] = 0;
> +    name_case[namelen] = 0;
> +  }
> +  char *name_start = name;
> +  char *name_case_start = name_case;
> +
> +  bool compression = false;
> +  while (*name)
> +    {
> +      /* Search for a previous name we can reference.  */
> +      ENTRY new_entry =
> +        {
> +          .key = name,
> +          .data = (void *) (uintptr_t) b->offset,
> +        };
> +
> +      /* If the label can be a compression target because it is at a
> +         reachable offset, add it to the hash table.  */
> +      ACTION action;
> +      if (b->offset < (1 << 12))
> +        action = ENTER;
> +      else
> +        action = FIND;
> +
> +      /* Search for known compression offsets in the hash table.  */
> +      ENTRY *e;
> +      if (hsearch_r (new_entry, action, &e, &b->compression_offsets) == 0)
> +        {
> +          if (action == FIND && errno == ESRCH)
> +            /* Fall through.  */
> +            e = NULL;
> +          else
> +            FAIL_EXIT1 ("hsearch_r failure in name compression: %m");
> +        }
> +
> +      /* The name is known.  Reference the previous location.  */
> +      if (e != NULL && e->data != new_entry.data)
> +        {
> +          size_t old_offset = (uintptr_t) e->data;
> +          response_add_byte (b, 0xC0 | (old_offset >> 8));
> +          response_add_byte (b, old_offset);
> +          compression = true;
> +          break;
> +        }
> +
> +      /* The name does not exist yet.  Write one label.  First, add
> +         room for the label length.  */
> +      size_t buffer_label_offset = b->offset;
> +      response_add_byte (b, 0);
> +
> +      /* Copy the label.  */
> +      while (true)
> +        {
> +          char ch = *name_case;
> +          if (ch == '\0')
> +            break;
> +          ++name;
> +          ++name_case;
> +          if (ch == '.')
> +            break;
> +          /* FIXME: Handle escaping.  */
> +          response_add_byte (b, ch);
> +        }
> +
> +      /* Patch in the label length.  */
> +      size_t label_length = b->offset - buffer_label_offset - 1;
> +      if (label_length == 0)
> +        FAIL_EXIT1 ("empty label in name compression: %s", origname);
> +      if (label_length > 63)
> +        FAIL_EXIT1 ("label too long in name compression: %s", origname);
> +      b->buffer[buffer_label_offset] = label_length;
> +
> +      /* Continue with the tail of the name and the next label.  */
> +    }
> +
> +  if (compression)
> +    {
> +      /* If we found an immediate match for the name, we have not put
> +         it into the hash table, and can free it immediately.  */
> +      if (name == name_start)
> +        free (name_start);
> +      else
> +        response_push_pointer_to_free (b, name_start);
> +    }
> +  else
> +    {
> +      /* Terminate the sequence of labels.  With compression, this is
> +         implicit in the compression reference.  */
> +      response_add_byte (b, 0);
> +      response_push_pointer_to_free (b, name_start);
> +    }
> +
> +  free (name_case_start);
> +}
> +
> +void
> +resolv_response_open_record (struct resolv_response_builder *b,
> +                             const char *name,
> +                             uint16_t class, uint16_t type, uint32_t ttl)
> +{
> +  if (b->section == ns_s_qd)
> +    FAIL_EXIT1 ("resolv_response_open_record called in question section");
> +  if (b->current_rdata_offset != 0)
> +    FAIL_EXIT1 ("resolv_response_open_record called with open record");
> +
> +  resolv_response_add_name (b, name);
> +  response_add_16 (b, type);
> +  response_add_16 (b, class);
> +  response_add_16 (b, ttl >> 16);
> +  response_add_16 (b, ttl);
> +
> +  b->current_rdata_offset = b->offset;
> +  /* Add room for the RDATA length.  */
> +  response_add_16 (b, 0);
> +}
> +
> +
> +void
> +resolv_response_close_record (struct resolv_response_builder *b)
> +{
> +  size_t rdata_offset = b->current_rdata_offset;
> +  if (rdata_offset == 0)
> +    FAIL_EXIT1 ("response_close_record called without open record");
> +  size_t rdata_length = b->offset - rdata_offset - 2;
> +  if (rdata_length > 65535)
> +    FAIL_EXIT1 ("RDATA length %zu exceeds limit", rdata_length);
> +  b->buffer[rdata_offset] = rdata_length >> 8;
> +  b->buffer[rdata_offset + 1] = rdata_length;
> +  response_count_increment (b);
> +  b->current_rdata_offset = 0;
> +}
> +
> +void
> +resolv_response_add_data (struct resolv_response_builder *b,
> +                          const void *data, size_t length)
> +{
> +  size_t remaining = max_response_length - b->offset;
> +  if (remaining < length)
> +    FAIL_EXIT1 ("resolv_response_add_data: not enough room for %zu bytes",
> +                length);
> +  memcpy (b->buffer + b->offset, data, length);
> +  b->offset += length;
> +}
> +
> +void
> +resolv_response_drop (struct resolv_response_builder *b)
> +{
> +  b->drop = true;
> +}
> +
> +void
> +resolv_response_close (struct resolv_response_builder *b)
> +{
> +  b->close = true;
> +}
> +
> +void
> +resolv_response_truncate_data (struct resolv_response_builder *b, size_t count)
> +{
> +  if (count > 65535)
> +    FAIL_EXIT1 ("resolv_response_truncate_data: argument too large: %zu",
> +                count);
> +  b->truncate_bytes = count;
> +}
> +
> +
> +size_t
> +resolv_response_length (const struct resolv_response_builder *b)
> +{
> +  return b->offset;
> +}
> +
> +unsigned char *
> +resolv_response_buffer (const struct resolv_response_builder *b)
> +{
> +  unsigned char *result = xmalloc (b->offset);
> +  memcpy (result, b->buffer, b->offset);
> +  return result;
> +}
> +
> +static struct resolv_response_builder *
> +response_builder_allocate
> +  (const unsigned char *query_buffer, size_t query_length)
> +{
> +  struct resolv_response_builder *b = xmalloc (sizeof (*b));
> +  memset (b, 0, offsetof (struct resolv_response_builder, buffer));
> +  b->query_buffer = query_buffer;
> +  b->query_length = query_length;
> +  TEST_VERIFY_EXIT (hcreate_r (10000, &b->compression_offsets) != 0);
> +  return b;
> +}
> +
> +static void
> +response_builder_free (struct resolv_response_builder *b)
> +{
> +  struct to_be_freed *current = b->to_be_freed;
> +  while (current != NULL)
> +    {
> +      struct to_be_freed *next = current->next;
> +      free (current->ptr);
> +      free (current);
> +      current = next;
> +    }
> +  hdestroy_r (&b->compression_offsets);
> +  free (b);
> +}
> +
> +/* DNS query processing. */
> +
> +/* Data extracted from the question section of a DNS packet.  */
> +struct query_info
> +{
> +  char qname[MAXDNAME];
> +  uint16_t qclass;
> +  uint16_t qtype;
> +  struct resolv_edns_info edns;
> +};
> +
> +/* Update *INFO from the specified DNS packet.  */
> +static void
> +parse_query (struct query_info *info,
> +             const unsigned char *buffer, size_t length)
> +{
> +  HEADER hd;
> +  _Static_assert (sizeof (hd) == 12, "DNS header size");
> +  if (length < sizeof (hd))
> +    FAIL_EXIT1 ("malformed DNS query: too short: %zu bytes", length);
> +  memcpy (&hd, buffer, sizeof (hd));
> +
> +  if (ntohs (hd.qdcount) != 1)
> +    FAIL_EXIT1 ("malformed DNS query: wrong question count: %d",
> +                (int) ntohs (hd.qdcount));
> +  if (ntohs (hd.ancount) != 0)
> +    FAIL_EXIT1 ("malformed DNS query: wrong answer count: %d",
> +                (int) ntohs (hd.ancount));
> +  if (ntohs (hd.nscount) != 0)
> +    FAIL_EXIT1 ("malformed DNS query: wrong authority count: %d",
> +                (int) ntohs (hd.nscount));
> +  if (ntohs (hd.arcount) > 1)
> +    FAIL_EXIT1 ("malformed DNS query: wrong additional count: %d",
> +                (int) ntohs (hd.arcount));
> +
> +  int ret = dn_expand (buffer, buffer + length, buffer + sizeof (hd),
> +                       info->qname, sizeof (info->qname));
> +  if (ret < 0)
> +    FAIL_EXIT1 ("malformed DNS query: cannot uncompress QNAME");
> +
> +  /* Obtain QTYPE and QCLASS.  */
> +  size_t remaining = length - (12 + ret);
> +  struct
> +  {
> +    uint16_t qtype;
> +    uint16_t qclass;
> +  } qtype_qclass;
> +  if (remaining < sizeof (qtype_qclass))
> +    FAIL_EXIT1 ("malformed DNS query: "
> +                "query lacks QCLASS/QTYPE, QNAME: %s", info->qname);
> +  memcpy (&qtype_qclass, buffer + 12 + ret, sizeof (qtype_qclass));
> +  info->qclass = ntohs (qtype_qclass.qclass);
> +  info->qtype = ntohs (qtype_qclass.qtype);
> +
> +  memset (&info->edns, 0, sizeof (info->edns));
> +  if (ntohs (hd.arcount) > 0)
> +    {
> +      /* Parse EDNS record.  */
> +      struct __attribute__ ((packed, aligned (1)))
> +      {
> +        uint8_t root;
> +        uint16_t rtype;
> +        uint16_t payload;
> +        uint8_t edns_extended_rcode;
> +        uint8_t edns_version;
> +        uint16_t flags;
> +        uint16_t rdatalen;
> +      } rr;
> +      _Static_assert (sizeof (rr) == 11, "EDNS record size");
> +
> +      if (remaining < 4 + sizeof (rr))
> +        FAIL_EXIT1 ("mailformed DNS query: no room for EDNS record");
> +      memcpy (&rr, buffer + 12 + ret + 4, sizeof (rr));
> +      if (rr.root != 0)
> +        FAIL_EXIT1 ("malformed DNS query: invalid OPT RNAME: %d\n", rr.root);
> +      if (rr.rtype != htons (41))
> +        FAIL_EXIT1 ("malformed DNS query: invalid OPT type: %d\n",
> +                    ntohs (rr.rtype));
> +      info->edns.active = true;
> +      info->edns.extended_rcode = rr.edns_extended_rcode;
> +      info->edns.version = rr.edns_version;
> +      info->edns.flags = ntohs (rr.flags);
> +      info->edns.payload_size = ntohs (rr.payload);
> +    }
> +}
> +
> +
> +/* Main testing framework.  */
> +
> +/* Per-server information.  One struct is allocated for each test
> +   server.  */
> +struct resolv_test_server
> +{
> +  /* Local address of the server.  UDP and TCP use the same port.  */
> +  struct sockaddr_in address;
> +
> +  /* File descriptor of the UDP server, or -1 if this server is
> +     disabled.  */
> +  int socket_udp;
> +
> +  /* File descriptor of the TCP server, or -1 if this server is
> +     disabled.  */
> +  int socket_tcp;
> +
> +  /* Counter of the number of responses processed so far.  */
> +  size_t response_number;
> +
> +  /* Thread handles for the server threads (if not disabled in the
> +     configuration).  */
> +  pthread_t thread_udp;
> +  pthread_t thread_tcp;
> +};
> +
> +/* Main struct for keeping track of libresolv redirection and
> +   testing.  */
> +struct resolv_test
> +{
> +  /* After initialization, any access to the struct must be performed
> +     while this lock is acquired.  */
> +  pthread_mutex_t lock;
> +
> +  /* Data for each test server. */
> +  struct resolv_test_server servers[resolv_max_test_servers];
> +
> +  /* Used if config.single_thread_udp is true.  */
> +  pthread_t thread_udp_single;
> +
> +  struct resolv_redirect_config config;
> +  bool termination_requested;
> +};
> +
> +/* Function implementing a server thread.  */
> +typedef void (*thread_callback) (struct resolv_test *, int server_index);
> +
> +/* Storage for thread-specific data, for passing to the
> +   thread_callback function.  */
> +struct thread_closure
> +{
> +  struct resolv_test *obj;      /* Current test object.  */
> +  thread_callback callback;     /* Function to call.  */
> +  int server_index;             /* Index of the implemented server.  */
> +};
> +
> +/* Wrap response_callback as a function which can be passed to
> +   pthread_create.  */
> +static void *
> +thread_callback_wrapper (void *arg)
> +{
> +  struct thread_closure *closure = arg;
> +  closure->callback (closure->obj, closure->server_index);
> +  free (closure);
> +  return NULL;
> +}
> +
> +/* Start a server thread for the specified SERVER_INDEX, implemented
> +   by CALLBACK.  */
> +static pthread_t
> +start_server_thread (struct resolv_test *obj, int server_index,
> +                     thread_callback callback)
> +{
> +  struct thread_closure *closure = xmalloc (sizeof (*closure));
> +  *closure = (struct thread_closure)
> +    {
> +      .obj = obj,
> +      .callback = callback,
> +      .server_index = server_index,
> +    };
> +  return xpthread_create (NULL, thread_callback_wrapper, closure);
> +}
> +
> +/* Process one UDP query.  Return false if a termination requested has
> +   been detected.  */
> +static bool
> +server_thread_udp_process_one (struct resolv_test *obj, int server_index)
> +{
> +  unsigned char query[512];
> +  struct sockaddr_storage peer;
> +  socklen_t peerlen = sizeof (peer);
> +  size_t length = xrecvfrom (obj->servers[server_index].socket_udp,
> +                             query, sizeof (query), 0,
> +                             (struct sockaddr *) &peer, &peerlen);
> +  /* Check for termination.  */
> +  {
> +    bool termination_requested;
> +    xpthread_mutex_lock (&obj->lock);
> +    termination_requested = obj->termination_requested;
> +    xpthread_mutex_unlock (&obj->lock);
> +    if (termination_requested)
> +      return false;
> +  }
> +
> +
> +  struct query_info qinfo;
> +  parse_query (&qinfo, query, length);
> +  if (test_verbose > 0)
> +    {
> +      if (test_verbose > 1)
> +        printf ("info: UDP server %d: incoming query:"
> +                " %zd bytes, %s/%u/%u, tnxid=0x%02x%02x\n",
> +                server_index, length, qinfo.qname, qinfo.qclass, qinfo.qtype,
> +                query[0], query[1]);
> +      else
> +        printf ("info: UDP server %d: incoming query:"
> +                " %zd bytes, %s/%u/%u\n",
> +                server_index, length, qinfo.qname, qinfo.qclass, qinfo.qtype);
> +    }
> +
> +  struct resolv_response_context ctx =
> +    {
> +      .query_buffer = query,
> +      .query_length = length,
> +      .server_index = server_index,
> +      .tcp = false,
> +      .edns = qinfo.edns,
> +    };
> +  struct resolv_response_builder *b = response_builder_allocate (query, length);
> +  obj->config.response_callback
> +    (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype);
> +
> +  if (b->drop)
> +    {
> +      if (test_verbose)
> +        printf ("info: UDP server %d: dropping response to %s/%u/%u\n",
> +                server_index, qinfo.qname, qinfo.qclass, qinfo.qtype);
> +    }
> +  else
> +    {
> +      if (test_verbose)
> +        {
> +          if (b->offset >= 12)
> +            printf ("info: UDP server %d: sending response:"
> +                    " %zu bytes, RCODE %d (for %s/%u/%u)\n",
> +                    server_index, b->offset, b->buffer[3] & 0x0f,
> +                    qinfo.qname, qinfo.qclass, qinfo.qtype);
> +          else
> +            printf ("info: UDP server %d: sending response: %zu bytes"
> +                    " (for %s/%u/%u)\n",
> +                    server_index, b->offset,
> +                    qinfo.qname, qinfo.qclass, qinfo.qtype);
> +          if (b->truncate_bytes > 0)
> +            printf ("info:    truncated by %u bytes\n", b->truncate_bytes);
> +        }
> +      size_t to_send = b->offset;
> +      if (to_send < b->truncate_bytes)
> +        to_send = 0;
> +      else
> +        to_send -= b->truncate_bytes;
> +
> +      /* Ignore most errors here because the other end may have closed
> +         the socket. */
> +      if (sendto (obj->servers[server_index].socket_udp,
> +                  b->buffer, to_send, 0,
> +                  (struct sockaddr *) &peer, peerlen) < 0)
> +        TEST_VERIFY_EXIT (errno != EBADF);
> +    }
> +  response_builder_free (b);
> +  return true;
> +}
> +
> +/* UDP thread_callback function.  Variant for one thread per
> +   server.  */
> +static void
> +server_thread_udp (struct resolv_test *obj, int server_index)
> +{
> +  while (server_thread_udp_process_one (obj, server_index))
> +    ;
> +}
> +
> +/* Single-threaded UDP processing function, for the single_thread_udp
> +   case.  */
> +static void *
> +server_thread_udp_single (void *closure)
> +{
> +  struct resolv_test *obj = closure;
> +
> +  struct pollfd fds[resolv_max_test_servers];
> +  for (int server_index = 0; server_index < resolv_max_test_servers;
> +       ++server_index)
> +    if (obj->config.servers[server_index].disable_udp)
> +      fds[server_index] = (struct pollfd) {.fd = -1};
> +    else
> +      {
> +        fds[server_index] = (struct pollfd)
> +          {
> +            .fd = obj->servers[server_index].socket_udp,
> +            .events = POLLIN
> +          };
> +
> +        /* Make the socket non-blocking.  */
> +        int flags = fcntl (obj->servers[server_index].socket_udp, F_GETFL, 0);
> +        if (flags < 0)
> +          FAIL_EXIT1 ("fcntl (F_GETFL): %m");
> +        flags |= O_NONBLOCK;
> +        if (fcntl (obj->servers[server_index].socket_udp, F_SETFL, flags) < 0)
> +          FAIL_EXIT1 ("fcntl (F_SETFL): %m");
> +      }
> +
> +  while (true)
> +    {
> +      xpoll (fds, resolv_max_test_servers, -1);
> +      for (int server_index = 0; server_index < resolv_max_test_servers;
> +           ++server_index)
> +        if (fds[server_index].revents != 0)
> +          {
> +            if (!server_thread_udp_process_one (obj, server_index))
> +              goto out;
> +            fds[server_index].revents = 0;
> +          }
> +    }
> +
> + out:
> +  return NULL;
> +}
> +
> +/* Start the single UDP handler thread (for the single_thread_udp
> +   case).  */
> +static void
> +start_server_thread_udp_single (struct resolv_test *obj)
> +{
> +  obj->thread_udp_single
> +    = xpthread_create (NULL, server_thread_udp_single, obj);
> +}
> +
> +/* Data describing a TCP client connect.  */
> +struct tcp_thread_closure
> +{
> +  struct resolv_test *obj;
> +  int server_index;
> +  int client_socket;
> +};
> +
> +/* Read a complete DNS query packet.  If EOF_OK, an immediate
> +   end-of-file condition is acceptable.  */
> +static bool
> +read_fully (int fd, void *buf, size_t len, bool eof_ok)
> +{
> +  const void *const end = buf + len;
> +  while (buf < end)
> +    {
> +      ssize_t ret = read (fd, buf, end - buf);
> +      if (ret == 0)
> +        {
> +          if (!eof_ok)
> +            {
> +              support_record_failure ();
> +              printf ("error: unexpected EOF on TCP connection\n");
> +            }
> +          return false;
> +        }
> +      else if (ret < 0)
> +        {
> +          if (!eof_ok || errno != ECONNRESET)
> +            {
> +              support_record_failure ();
> +              printf ("error: TCP read: %m\n");
> +            }
> +          return false;
> +        }
> +      buf += ret;
> +      eof_ok = false;
> +    }
> +  return true;
> +}
> +
> +/* Write an array of iovecs.  Terminate the process on failure.  */
> +static void
> +writev_fully (int fd, struct iovec *buffers, size_t count)
> +{
> +  while (count > 0)
> +    {
> +      /* Skip zero-length write requests.  */
> +      if (buffers->iov_len == 0)
> +        {
> +          ++buffers;
> +          --count;
> +          continue;
> +        }
> +      /* Try to rewrite the remaing buffers.  */
> +      ssize_t ret = writev (fd, buffers, count);
> +      if (ret < 0)
> +        FAIL_EXIT1 ("writev: %m");
> +      if (ret == 0)
> +        FAIL_EXIT1 ("writev: invalid return value zero");
> +      /* Find the buffers that were successfully written.  */
> +      while (ret > 0)
> +        {
> +          if (count == 0)
> +            FAIL_EXIT1 ("internal writev consistency failure");
> +          /* Current buffer was partially written.  */
> +          if (buffers->iov_len > (size_t) ret)
> +            {
> +              buffers->iov_base += ret;
> +              buffers->iov_len -= ret;
> +              ret = 0;
> +            }
> +          else
> +            {
> +              ret -= buffers->iov_len;
> +              buffers->iov_len = 0;
> +              ++buffers;
> +              --count;
> +            }
> +        }
> +    }
> +}
> +
> +/* Thread callback for handling a single established TCP connection to
> +   a client.  */
> +static void *
> +server_thread_tcp_client (void *arg)
> +{
> +  struct tcp_thread_closure *closure = arg;
> +
> +  while (true)
> +    {
> +      /* Read packet length.  */
> +      uint16_t query_length;
> +      if (!read_fully (closure->client_socket,
> +                       &query_length, sizeof (query_length), true))
> +        break;
> +      query_length = ntohs (query_length);
> +
> +      /* Read the packet.  */
> +      unsigned char *query_buffer = xmalloc (query_length);
> +      read_fully (closure->client_socket, query_buffer, query_length, false);
> +
> +      struct query_info qinfo;
> +      parse_query (&qinfo, query_buffer, query_length);
> +      if (test_verbose > 0)
> +        {
> +          if (test_verbose > 1)
> +            printf ("info: UDP server %d: incoming query:"
> +                    " %d bytes, %s/%u/%u, tnxid=0x%02x%02x\n",
> +                    closure->server_index, query_length,
> +                    qinfo.qname, qinfo.qclass, qinfo.qtype,
> +                    query_buffer[0], query_buffer[1]);
> +          else
> +            printf ("info: TCP server %d: incoming query:"
> +                    " %u bytes, %s/%u/%u\n",
> +                    closure->server_index, query_length,
> +                    qinfo.qname, qinfo.qclass, qinfo.qtype);
> +        }
> +
> +      struct resolv_response_context ctx =
> +        {
> +          .query_buffer = query_buffer,
> +          .query_length = query_length,
> +          .server_index = closure->server_index,
> +          .tcp = true,
> +          .edns = qinfo.edns,
> +        };
> +      struct resolv_response_builder *b = response_builder_allocate
> +        (query_buffer, query_length);
> +      closure->obj->config.response_callback
> +        (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype);
> +
> +      if (b->drop)
> +        {
> +          if (test_verbose)
> +            printf ("info: TCP server %d: dropping response to %s/%u/%u\n",
> +                    closure->server_index,
> +                    qinfo.qname, qinfo.qclass, qinfo.qtype);
> +        }
> +      else
> +        {
> +          if (test_verbose)
> +            printf ("info: TCP server %d: sending response: %zu bytes"
> +                    " (for %s/%u/%u)\n",
> +                    closure->server_index, b->offset,
> +                    qinfo.qname, qinfo.qclass, qinfo.qtype);
> +          uint16_t length = htons (b->offset);
> +          size_t to_send = b->offset;
> +          if (to_send < b->truncate_bytes)
> +            to_send = 0;
> +          else
> +            to_send -= b->truncate_bytes;
> +          struct iovec buffers[2] =
> +            {
> +              {&length, sizeof (length)},
> +              {b->buffer, to_send}
> +            };
> +          writev_fully (closure->client_socket, buffers, 2);
> +        }
> +      bool close_flag = b->close;
> +      response_builder_free (b);
> +      free (query_buffer);
> +      if (close_flag)
> +        break;
> +    }
> +
> +  xclose (closure->client_socket);
> +  free (closure);
> +  return NULL;
> +}
> +
> +/* thread_callback for the TCP case.  Accept connections and create a
> +   new thread for each client.  */
> +static void
> +server_thread_tcp (struct resolv_test *obj, int server_index)
> +{
> +  while (true)
> +    {
> +      /* Get the client conenction.  */
> +      int client_socket = xaccept
> +        (obj->servers[server_index].socket_tcp, NULL, NULL);
> +
> +      /* Check for termination.  */
> +      xpthread_mutex_lock (&obj->lock);
> +      if (obj->termination_requested)
> +        {
> +          xpthread_mutex_unlock (&obj->lock);
> +          xclose (client_socket);
> +          break;
> +        }
> +      xpthread_mutex_unlock (&obj->lock);
> +
> +      /* Spawn a new thread for handling this connection.  */
> +      struct tcp_thread_closure *closure = xmalloc (sizeof (*closure));
> +      *closure = (struct tcp_thread_closure)
> +        {
> +          .obj = obj,
> +          .server_index = server_index,
> +          .client_socket = client_socket,
> +        };
> +
> +      pthread_t thr
> +        = xpthread_create (NULL, server_thread_tcp_client, closure);
> +      /* TODO: We should keep track of this thread so that we can
> +         block in resolv_test_end until it has exited.  */
> +      xpthread_detach (thr);
> +    }
> +}
> +
> +/* Create UDP and TCP server sockets.  */
> +static void
> +make_server_sockets (struct resolv_test_server *server)
> +{
> +  while (true)
> +    {
> +      server->socket_udp = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
> +      server->socket_tcp = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
> +
> +      /* Pick the address for the UDP socket.  */
> +      server->address = (struct sockaddr_in)
> +        {
> +          .sin_family = AF_INET,
> +          .sin_addr = {.s_addr = htonl (INADDR_LOOPBACK)}
> +        };
> +      xbind (server->socket_udp,
> +             (struct sockaddr *)&server->address, sizeof (server->address));
> +
> +      /* Retrieve the address. */
> +      socklen_t addrlen = sizeof (server->address);
> +      xgetsockname (server->socket_udp,
> +                    (struct sockaddr *)&server->address, &addrlen);
> +
> +      /* Bind the TCP socket to the same address.  */
> +      {
> +        int on = 1;
> +        xsetsockopt (server->socket_tcp, SOL_SOCKET, SO_REUSEADDR,
> +                     &on, sizeof (on));
> +      }
> +      if (bind (server->socket_tcp,
> +                (struct sockaddr *)&server->address,
> +                sizeof (server->address)) != 0)
> +        {
> +          /* Port collision.  The UDP bind succeeded, but the TCP BIND
> +             failed.  We assume here that the kernel will pick the
> +             next local UDP address randomly.  */
> +          if (errno == EADDRINUSE)
> +            {
> +              xclose (server->socket_udp);
> +              xclose (server->socket_tcp);
> +              continue;
> +            }
> +          FAIL_EXIT1 ("TCP bind: %m");
> +        }
> +      xlisten (server->socket_tcp, 5);
> +      break;
> +    }
> +}
> +
> +/* One-time initialization of NSS.  */
> +static void
> +resolv_redirect_once (void)
> +{
> +  /* Only use nss_dns.  */
> +  __nss_configure_lookup ("hosts", "dns");
> +  __nss_configure_lookup ("networks", "dns");
> +  /* Enter a network namespace for isolation and firewall state
> +     cleanup.  The tests will still work if these steps fail, but they
> +     may be less reliable.  */
> +  support_become_root ();
> +  support_enter_network_namespace ();
> +}
> +pthread_once_t resolv_redirect_once_var = PTHREAD_ONCE_INIT;
> +
> +void
> +resolv_test_init (void)
> +{
> +  /* Perform one-time initialization of NSS.  */
> +  xpthread_once (&resolv_redirect_once_var, resolv_redirect_once);
> +}
> +
> +/* Copy the search path from CONFIG.search to the _res object.  */
> +static void
> +set_search_path (struct resolv_redirect_config config)
> +{
> +  memset (_res.defdname, 0, sizeof (_res.defdname));
> +  memset (_res.dnsrch, 0, sizeof (_res.dnsrch));
> +
> +  char *current = _res.defdname;
> +  char *end = current + sizeof (_res.defdname);
> +
> +  for (unsigned int i = 0;
> +       i < sizeof (config.search) / sizeof (config.search[0]); ++i)
> +    {
> +      if (config.search[i] == NULL)
> +        continue;
> +
> +      size_t length = strlen (config.search[i]) + 1;
> +      size_t remaining = end - current;
> +      TEST_VERIFY_EXIT (length <= remaining);
> +      memcpy (current, config.search[i], length);
> +      _res.dnsrch[i] = current;
> +      current += length;
> +    }
> +}
> +
> +struct resolv_test *
> +resolv_test_start (struct resolv_redirect_config config)
> +{
> +  /* Apply configuration defaults.  */
> +  if (config.nscount == 0)
> +    config.nscount = resolv_max_test_servers;
> +
> +  struct resolv_test *obj = xmalloc (sizeof (*obj));
> +  *obj = (struct resolv_test) {
> +    .config = config,
> +    .lock = PTHREAD_MUTEX_INITIALIZER,
> +  };
> +
> +  resolv_test_init ();
> +
> +  /* Create all the servers, to reserve the necessary ports.  */
> +  for (int server_index = 0; server_index < config.nscount; ++server_index)
> +    make_server_sockets (obj->servers + server_index);
> +
> +  /* Start server threads.  Disable the server ports, as
> +     requested.  */
> +  for (int server_index = 0; server_index < config.nscount; ++server_index)
> +    {
> +      struct resolv_test_server *server = obj->servers + server_index;
> +      if (config.servers[server_index].disable_udp)
> +        {
> +          xclose (server->socket_udp);
> +          server->socket_udp = -1;
> +        }
> +      else if (!config.single_thread_udp)
> +        server->thread_udp = start_server_thread (obj, server_index,
> +                                                  server_thread_udp);
> +      if (config.servers[server_index].disable_tcp)
> +        {
> +          xclose (server->socket_tcp);
> +          server->socket_tcp = -1;
> +        }
> +      else
> +        server->thread_tcp = start_server_thread (obj, server_index,
> +                                                  server_thread_tcp);
> +    }
> +  if (config.single_thread_udp)
> +    start_server_thread_udp_single (obj);
> +
> +  int timeout = 1;
> +
> +  /* Initialize libresolv.  */
> +  TEST_VERIFY_EXIT (res_init () == 0);
> +
> +  /* Disable IPv6 name server addresses.  The code below only
> +     overrides the IPv4 addresses.  */
> +  __res_iclose (&_res, true);
> +  _res._u._ext.nscount = 0;
> +
> +  /* Redirect queries to the server socket.  */
> +  if (test_verbose)
> +    {
> +      printf ("info: old timeout value: %d\n", _res.retrans);
> +      printf ("info: old retry attempt value: %d\n", _res.retry);
> +      printf ("info: old _res.options: 0x%lx\n", _res.options);
> +      printf ("info: old _res.nscount value: %d\n", _res.nscount);
> +      printf ("info: old _res.ndots value: %d\n", _res.ndots);
> +    }
> +  _res.retrans = timeout;
> +  _res.retry = 4;
> +  _res.nscount = config.nscount;
> +  _res.options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
> +  _res.ndots = 1;
> +  if (test_verbose)
> +    {
> +      printf ("info: new timeout value: %d\n", _res.retrans);
> +      printf ("info: new retry attempt value: %d\n", _res.retry);
> +      printf ("info: new _res.options: 0x%lx\n", _res.options);
> +      printf ("info: new _res.nscount value: %d\n", _res.nscount);
> +      printf ("info: new _res.ndots value: %d\n", _res.ndots);
> +    }
> +  for (int server_index = 0; server_index < config.nscount; ++server_index)
> +    {
> +      _res.nsaddr_list[server_index] = obj->servers[server_index].address;
> +      if (test_verbose)
> +        {
> +          char buf[256];
> +          TEST_VERIFY_EXIT
> +            (inet_ntop (AF_INET, &obj->servers[server_index].address.sin_addr,
> +                        buf, sizeof (buf)) != NULL);
> +          printf ("info: server %d: %s/%u\n",
> +                  server_index, buf,
> +                  htons (obj->servers[server_index].address.sin_port));
> +        }
> +    }
> +
> +  set_search_path (config);
> +
> +  return obj;
> +}
> +
> +void
> +resolv_test_end (struct resolv_test *obj)
> +{
> +  res_close ();
> +
> +  xpthread_mutex_lock (&obj->lock);
> +  obj->termination_requested = true;
> +  xpthread_mutex_unlock (&obj->lock);
> +
> +  /* Send trigger packets to unblock the server threads.  */
> +  for (int server_index = 0; server_index < obj->config.nscount;
> +       ++server_index)
> +    {
> +      if (!obj->config.servers[server_index].disable_udp)
> +        {
> +          int sock = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
> +          xsendto (sock, "", 1, 0,
> +                   (struct sockaddr *) &obj->servers[server_index].address,
> +                   sizeof (obj->servers[server_index].address));
> +          xclose (sock);
> +        }
> +      if (!obj->config.servers[server_index].disable_tcp)
> +        {
> +          int sock = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
> +          xconnect (sock,
> +                    (struct sockaddr *) &obj->servers[server_index].address,
> +                    sizeof (obj->servers[server_index].address));
> +          xclose (sock);
> +        }
> +    }
> +
> +  if (obj->config.single_thread_udp)
> +    xpthread_join (obj->thread_udp_single);
> +
> +  /* Wait for the server threads to terminate.  */
> +  for (int server_index = 0; server_index < obj->config.nscount;
> +       ++server_index)
> +    {
> +      if (!obj->config.servers[server_index].disable_udp)
> +        {
> +          if (!obj->config.single_thread_udp)
> +            xpthread_join (obj->servers[server_index].thread_udp);
> +          xclose (obj->servers[server_index].socket_udp);
> +        }
> +      if (!obj->config.servers[server_index].disable_tcp)
> +        {
> +          xpthread_join (obj->servers[server_index].thread_tcp);
> +          xclose (obj->servers[server_index].socket_tcp);
> +        }
> +    }
> +
> +  free (obj);
> +}
> diff --git a/support/resolv_test.h b/support/resolv_test.h
> new file mode 100644
> index 0000000..6498751
> --- /dev/null
> +++ b/support/resolv_test.h
> @@ -0,0 +1,180 @@
> +/* DNS test framework and libresolv redirection.
> +   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/>.  */
> +
> +#ifndef SUPPORT_RESOLV_TEST_H
> +#define SUPPORT_RESOLV_TEST_H
> +
> +#include <arpa/nameser.h>
> +#include <stdbool.h>
> +#include <sys/cdefs.h>
> +
> +__BEGIN_DECLS
> +
> +/* Information about EDNS properties of a DNS query.  */
> +struct resolv_edns_info
> +{
> +  bool active;
> +  uint8_t extended_rcode;
> +  uint8_t version;
> +  uint16_t flags;
> +  uint16_t payload_size;
> +};
> +
> +/* This struct provides context information when the response callback
> +   specified in struct resolv_redirect_config is invoked. */
> +struct resolv_response_context
> +{
> +  const unsigned char *query_buffer;
> +  size_t query_length;
> +  int server_index;
> +  bool tcp;
> +  struct resolv_edns_info edns;
> +};
> +
> +/* This opaque struct is used to construct responses from within the
> +   response callback function.  */
> +struct resolv_response_builder;
> +
> +/* This opaque struct collects information about the resolver testing
> +   currently in progress.  */
> +struct resolv_test;
> +
> +enum
> +  {
> +    /* Maximum number of test servers supported by the framework.  */
> +    resolv_max_test_servers = 3,
> +  };
> +
> +/* Configuration settings specific to individual test servers.  */
> +struct resolv_redirect_server_config
> +{
> +  bool disable_tcp;             /* If true, no TCP server is listening.  */
> +  bool disable_udp;             /* If true, no UDP server is listening.  */
> +};
> +
> +/* Instructions for setting up the libresolv redirection.  */
> +struct resolv_redirect_config
> +{
> +  /* The response_callback function is called for every incoming DNS
> +     packet, over UDP or TCP.  It must be specified, the other
> +     configuration settings are optional.  */
> +  void (*response_callback) (const struct resolv_response_context *,
> +                             struct resolv_response_builder *,
> +                             const char *qname,
> +                             uint16_t qclass, uint16_t qtype);
> +
> +  /* Per-server configuration.  */
> +  struct resolv_redirect_server_config servers[resolv_max_test_servers];
> +
> +  /* Search path entries.  The first entry serves as the default
> +     domain name as well.  */
> +  const char *search[7];
> +
> +  /* Number of servers to activate in resolv.  0 means the default,
> +     resolv_max_test_servers.  */
> +  int nscount;
> +
> +  /* If true, use a single thread to process all UDP queries.  This
> +     may results in more predictable ordering of queries and
> +     responses.  */
> +  bool single_thread_udp;
> +};
> +
> +/* Configure NSS to use, nss_dns only for aplicable databases, and try
> +   to put the process into a network namespace for better isolation.
> +   This may have to be called before resolv_test_start, before the
> +   process creates any threads.  Otherwise, initialization is
> +   performed by resolv_test_start implicitly.  */
> +void resolv_test_init (void);
> +
> +/* Initiate resolver testing.  This updates the _res variable as
> +   needed.  As a side effect, NSS is reconfigured to use nss_dns only
> +   for aplicable databases, and the process may enter a network
> +   namespace for better isolation.  */
> +struct resolv_test *resolv_test_start (struct resolv_redirect_config);
> +
> +/* Call this function at the end of resolver testing, to free
> +   resources and report pending errors (if any).  */
> +void resolv_test_end (struct resolv_test *);
> +
> +/* The remaining facilities in this file are used for constructing
> +   response packets from the response_callback function.  */
> +
> +/* Special settings for constructing responses from the callback.  */
> +struct resolv_response_flags
> +{
> +  /* 4-bit response code to incorporate into the response. */
> +  unsigned char rcode;
> +
> +  /* If true, the TC (truncation) flag will be set.  */
> +  bool tc;
> +
> +  /* Initial section count values.  Can be used to artificially
> +     increase the counts, for malformed packet testing.*/
> +  unsigned short qdcount;
> +  unsigned short ancount;
> +  unsigned short nscount;
> +  unsigned short adcount;
> +};
> +
> +/* Begin a new response with the requested flags.  Must be called
> +   first.  */
> +void resolv_response_init (struct resolv_response_builder *,
> +                           struct resolv_response_flags);
> +
> +/* Switches to the section in the response packet.  Only forward
> +   movement is supported.  */
> +void resolv_response_section (struct resolv_response_builder *, ns_sect);
> +
> +/* Add a question record to the question section.  */
> +void resolv_response_add_question (struct resolv_response_builder *,
> +                                   const char *name, uint16_t class,
> +                                   uint16_t type);
> +/* Starts a new resource record with the specified owner name, class,
> +   type, and TTL.  Data is supplied with resolv_response_add_data or
> +   resolv_response_add_name.  */
> +void resolv_response_open_record (struct resolv_response_builder *,
> +                                  const char *name, uint16_t class,
> +                                  uint16_t type, uint32_t ttl);
> +
> +/* Add unstructed bytes to the RDATA part of a resource record.  */
> +void resolv_response_add_data (struct resolv_response_builder *,
> +                               const void *, size_t);
> +
> +/* Add a compressed domain name to the RDATA part of a resource
> +   record.  */
> +void resolv_response_add_name (struct resolv_response_builder *,
> +                               const char *name);
> +
> +/* Mark the end of the constructed record.  Must be called last.  */
> +void resolv_response_close_record (struct resolv_response_builder *);
> +
> +/* Drop this query packet (that is, do not send a response, not even
> +   an empty packet).  */
> +void resolv_response_drop (struct resolv_response_builder *);
> +
> +/* In TCP mode, close the connection after this packet (if a response
> +   is sent).  */
> +void resolv_response_close (struct resolv_response_builder *);
> +
> +/* The size of the response packet built so far.  */
> +size_t resolv_response_length (const struct resolv_response_builder *);
> +
> +__END_DECLS
> +
> +#endif /* SUPPORT_RESOLV_TEST_H */
> diff --git a/support/run_diff.h b/support/run_diff.h
> new file mode 100644
> index 0000000..f65b5dd
> --- /dev/null
> +++ b/support/run_diff.h
> @@ -0,0 +1,31 @@
> +/* Invoke the system diff tool to compare two strings.
> +   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/>.  */
> +
> +#ifndef SUPPORT_RUN_DIFF_H
> +#define SUPPORT_RUN_DIFF_H
> +
> +/* Compare the two NUL-terminated strings LEFT and RIGHT using the
> +   diff tool.  Label the sides of the diff with LEFT_LABEL and
> +   RIGHT_LABEL, respectively.
> +
> +   This function assumes that LEFT and RIGHT are different
> +   strings.  */
> +void support_run_diff (const char *left_label, const char *left,
> +                       const char *right_label, const char *right);
> +
> +#endif /* SUPPORT_RUN_DIFF_H */
> diff --git a/support/set_fortify_handler.c b/support/set_fortify_handler.c
> new file mode 100644
> index 0000000..f434a80
> --- /dev/null
> +++ b/support/set_fortify_handler.c
> @@ -0,0 +1,34 @@
> +/* Set signal handler for use in fortify tests.
> +   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 <signal.h>
> +
> +void
> +set_fortify_handler (void (*handler) (int sig))
> +{
> +  struct sigaction sa;
> +
> +  sa.sa_handler = handler;
> +  sa.sa_flags = 0;
> +  sigemptyset (&sa.sa_mask);
> +
> +  sigaction (SIGABRT, &sa, NULL);
> +  ignore_stderr ();
> +}
> diff --git a/support/support-xstat.c b/support/support-xstat.c
> new file mode 100644
> index 0000000..86a81ec
> --- /dev/null
> +++ b/support/support-xstat.c
> @@ -0,0 +1,30 @@
> +/* stat64 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/>.  */
> +
> +/* NB: Non-standard file name to avoid sysdeps override for xstat.  */
> +
> +#include <support/check.h>
> +#include <support/xunistd.h>
> +#include <sys/stat.h>
> +
> +void
> +xstat (const char *path, struct stat64 *result)
> +{
> +  if (stat64 (path, result) != 0)
> +    FAIL_EXIT1 ("stat64 (\"%s\"): %m", path);
> +}
> diff --git a/support/support.h b/support/support.h
> new file mode 100644
> index 0000000..4b5f04c
> --- /dev/null
> +++ b/support/support.h
> @@ -0,0 +1,74 @@
> +/* Common extra functions.
> +   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/>.  */
> +
> +/* This header file should only contain definitions compatible with
> +   C90.  (Using __attribute__ is fine because <features.h> provides a
> +   fallback.)  */
> +
> +#ifndef SUPPORT_H
> +#define SUPPORT_H
> +
> +#include <stddef.h>
> +#include <sys/cdefs.h>
> +
> +__BEGIN_DECLS
> +
> +/* Write a message to standard output.  Can be used in signal
> +   handlers.  */
> +void write_message (const char *message) __attribute__ ((nonnull (1)));
> +
> +/* Avoid all the buffer overflow messages on stderr.  */
> +void ignore_stderr (void);
> +
> +/* Set fortification error handler.  Used when tests want to verify that bad
> +   code is caught by the library.  */
> +void set_fortify_handler (void (*handler) (int sig));
> +
> +/* Report an out-of-memory error for the allocation of SIZE bytes in
> +   FUNCTION, terminating the process.  */
> +void oom_error (const char *function, size_t size)
> +  __attribute__ ((nonnull (1)));
> +
> +/* Return a pointer to a memory region of SIZE bytes.  The memory is
> +   initialized to zero and will be shared with subprocesses (across
> +   fork).  The returned pointer must be freed using
> +   support_shared_free; it is not compatible with the malloc
> +   functions.  */
> +void *support_shared_allocate (size_t size);
> +
> +/* Deallocate a pointer returned by support_shared_allocate.  */
> +void support_shared_free (void *);
> +
> +/* Write CONTENTS to the file PATH.  Create or truncate the file as
> +   needed.  The file mode is 0666 masked by the umask.  Terminate the
> +   process on error.  */
> +void support_write_file_string (const char *path, const char *contents);
> +
> +/* Error-checking wrapper functions which terminate the process on
> +   error.  */
> +
> +void *xmalloc (size_t) __attribute__ ((malloc));
> +void *xcalloc (size_t n, size_t s) __attribute__ ((malloc));
> +void *xrealloc (void *p, size_t n);
> +char *xasprintf (const char *format, ...)
> +  __attribute__ ((format (printf, 1, 2), malloc));
> +char *xstrdup (const char *);
> +
> +__END_DECLS
> +
> +#endif /* SUPPORT_H */
> diff --git a/support/support_become_root.c b/support/support_become_root.c
> new file mode 100644
> index 0000000..3fa0bd4
> --- /dev/null
> +++ b/support/support_become_root.c
> @@ -0,0 +1,40 @@
> +/* Acquire root privileges.
> +   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/namespace.h>
> +
> +#include <sched.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +
> +bool
> +support_become_root (void)
> +{
> +#ifdef CLONE_NEWUSER
> +  if (unshare (CLONE_NEWUSER | CLONE_NEWNS) == 0)
> +    /* Even if we do not have UID zero, we have extended privileges at
> +       this point.  */
> +    return true;
> +#endif
> +  if (setuid (0) != 0)
> +    {
> +      printf ("warning: could not become root outside namespace (%m)\n");
> +      return false;
> +    }
> +  return true;
> +}
> diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c
> new file mode 100644
> index 0000000..0dfd2de
> --- /dev/null
> +++ b/support/support_can_chroot.c
> @@ -0,0 +1,65 @@
> +/* Return true if the process can perform a chroot operation.
> +   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 <stdio.h>
> +#include <support/check.h>
> +#include <support/namespace.h>
> +#include <support/support.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +#include <xunistd.h>
> +
> +static void
> +callback (void *closure)
> +{
> +  int *result = closure;
> +  struct stat64 before;
> +  xstat ("/dev", &before);
> +  if (chroot ("/dev") != 0)
> +    {
> +      *result = errno;
> +      return;
> +    }
> +  struct stat64 after;
> +  xstat ("/", &after);
> +  TEST_VERIFY (before.st_dev == after.st_dev);
> +  TEST_VERIFY (before.st_ino == after.st_ino);
> +  *result = 0;
> +}
> +
> +bool
> +support_can_chroot (void)
> +{
> +  int *result = support_shared_allocate (sizeof (*result));
> +  *result = 0;
> +  support_isolate_in_subprocess (callback, result);
> +  bool ok = *result == 0;
> +  if (!ok)
> +    {
> +      static bool already_warned;
> +      if (!already_warned)
> +        {
> +          already_warned = true;
> +          errno = *result;
> +          printf ("warning: this process does not support chroot: %m\n");
> +        }
> +    }
> +  support_shared_free (result);
> +  return ok;
> +}
> diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
> new file mode 100644
> index 0000000..030f124
> --- /dev/null
> +++ b/support/support_capture_subprocess.c
> @@ -0,0 +1,108 @@
> +/* Capture output from a subprocess.
> +   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/capture_subprocess.h>
> +
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <support/xunistd.h>
> +#include <support/xsocket.h>
> +
> +static void
> +transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
> +{
> +  if (pfd->revents != 0)
> +    {
> +      char buf[1024];
> +      ssize_t ret = TEMP_FAILURE_RETRY (read (pfd->fd, buf, sizeof (buf)));
> +      if (ret < 0)
> +        {
> +          support_record_failure ();
> +          printf ("error: reading from subprocess %s: %m", what);
> +          pfd->events = 0;
> +          pfd->revents = 0;
> +        }
> +      else if (ret == 0)
> +        {
> +          /* EOF reached.  Stop listening.  */
> +          pfd->events = 0;
> +          pfd->revents = 0;
> +        }
> +      else
> +        /* Store the data just read.   */
> +        TEST_VERIFY (fwrite (buf, ret, 1, stream->out) == 1);
> +    }
> +}
> +
> +struct support_capture_subprocess
> +support_capture_subprocess (void (*callback) (void *), void *closure)
> +{
> +  struct support_capture_subprocess result;
> +  xopen_memstream (&result.out);
> +  xopen_memstream (&result.err);
> +
> +  int stdout_pipe[2];
> +  xpipe (stdout_pipe);
> +  int stderr_pipe[2];
> +  xpipe (stderr_pipe);
> +
> +  TEST_VERIFY (fflush (stdout) == 0);
> +  TEST_VERIFY (fflush (stderr) == 0);
> +
> +  pid_t pid = xfork ();
> +  if (pid == 0)
> +    {
> +      xclose (stdout_pipe[0]);
> +      xclose (stderr_pipe[0]);
> +      xdup2 (stdout_pipe[1], STDOUT_FILENO);
> +      xdup2 (stderr_pipe[1], STDERR_FILENO);
> +      callback (closure);
> +      _exit (0);
> +    }
> +  xclose (stdout_pipe[1]);
> +  xclose (stderr_pipe[1]);
> +
> +  struct pollfd fds[2] =
> +    {
> +      { .fd = stdout_pipe[0], .events = POLLIN },
> +      { .fd = stderr_pipe[0], .events = POLLIN },
> +    };
> +
> +  do
> +    {
> +      xpoll (fds, 2, -1);
> +      transfer ("stdout", &fds[0], &result.out);
> +      transfer ("stderr", &fds[1], &result.err);
> +    }
> +  while (fds[0].events != 0 || fds[1].events != 0);
> +  xclose (stdout_pipe[0]);
> +  xclose (stderr_pipe[0]);
> +
> +  xfclose_memstream (&result.out);
> +  xfclose_memstream (&result.err);
> +  xwaitpid (pid, &result.status, 0);
> +  return result;
> +}
> +
> +void
> +support_capture_subprocess_free (struct support_capture_subprocess *p)
> +{
> +  free (p->out.buffer);
> +  free (p->err.buffer);
> +}
> diff --git a/support/support_capture_subprocess_check.c b/support/support_capture_subprocess_check.c
> new file mode 100644
> index 0000000..708c89f
> --- /dev/null
> +++ b/support/support_capture_subprocess_check.c
> @@ -0,0 +1,67 @@
> +/* Verify capture output from a subprocess.
> +   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 <stdbool.h>
> +#include <stdio.h>
> +#include <support/capture_subprocess.h>
> +#include <support/check.h>
> +
> +static void
> +print_context (const char *context, bool *failed)
> +{
> +  if (*failed)
> +    /* Do not duplicate message.  */
> +    return;
> +  support_record_failure ();
> +  printf ("error: subprocess failed: %s\n", context);
> +}
> +
> +void
> +support_capture_subprocess_check (struct support_capture_subprocess *proc,
> +                                  const char *context, int status,
> +                                  int allowed)
> +{
> +  TEST_VERIFY ((allowed & sc_allow_none)
> +               || (allowed & sc_allow_stdout)
> +               || (allowed & sc_allow_stderr));
> +  TEST_VERIFY (!((allowed & sc_allow_none)
> +                 && ((allowed & sc_allow_stdout)
> +                     || (allowed & sc_allow_stderr))));
> +
> +  bool failed = false;
> +  if (proc->status != status)
> +    {
> +      print_context (context, &failed);
> +      printf ("error:   expected exit status: %d\n", status);
> +      printf ("error:   actual exit status:   %d\n", status);
> +    }
> +  if (!(allowed & sc_allow_stdout) && proc->out.length != 0)
> +    {
> +      print_context (context, &failed);
> +      printf ("error:   unexpected output from subprocess\n");
> +      fwrite (proc->out.buffer, proc->out.length, 1, stdout);
> +      puts ("\n");
> +    }
> +  if (!(allowed & sc_allow_stderr) && proc->err.length != 0)
> +    {
> +      print_context (context, &failed);
> +      printf ("error:   unexpected error output from subprocess\n");
> +      fwrite (proc->err.buffer, proc->err.length, 1, stdout);
> +      puts ("\n");
> +    }
> +}
> diff --git a/support/support_enter_network_namespace.c b/support/support_enter_network_namespace.c
> new file mode 100644
> index 0000000..28b0ee2
> --- /dev/null
> +++ b/support/support_enter_network_namespace.c
> @@ -0,0 +1,75 @@
> +/* Enter a network namespace.
> +   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/namespace.h>
> +
> +#include <net/if.h>
> +#include <sched.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <support/check.h>
> +#include <support/xsocket.h>
> +#include <support/xunistd.h>
> +#include <sys/ioctl.h>
> +#include <unistd.h>
> +
> +static bool in_uts_namespace;
> +
> +bool
> +support_enter_network_namespace (void)
> +{
> +#ifdef CLONE_NEWUTS
> +  if (unshare (CLONE_NEWUTS) == 0)
> +    in_uts_namespace = true;
> +  else
> +    printf ("warning: unshare (CLONE_NEWUTS) failed: %m\n");
> +#endif
> +
> +#ifdef CLONE_NEWNET
> +  if (unshare (CLONE_NEWNET) == 0)
> +    {
> +      /* Bring up the loopback interface.  */
> +      int fd = xsocket (AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
> +      struct ifreq req;
> +      strcpy (req.ifr_name, "lo");
> +      TEST_VERIFY_EXIT (ioctl (fd, SIOCGIFFLAGS, &req) == 0);
> +      bool already_up = req.ifr_flags & IFF_UP;
> +      if (already_up)
> +        /* This means that we likely have not achieved isolation from
> +           the parent namespace.  */
> +        printf ("warning: loopback interface already exists"
> +                " in new network namespace\n");
> +      else
> +        {
> +          req.ifr_flags |= IFF_UP | IFF_RUNNING;
> +          TEST_VERIFY_EXIT (ioctl (fd, SIOCSIFFLAGS, &req) == 0);
> +        }
> +      xclose (fd);
> +
> +      return !already_up;
> +    }
> +#endif
> +  printf ("warning: could not enter network namespace\n");
> +  return false;
> +}
> +
> +bool
> +support_in_uts_namespace (void)
> +{
> +  return in_uts_namespace;
> +}
> diff --git a/support/support_format_address_family.c b/support/support_format_address_family.c
> new file mode 100644
> index 0000000..5d42c42
> --- /dev/null
> +++ b/support/support_format_address_family.c
> @@ -0,0 +1,35 @@
> +/* Convert an address family to a string.
> +   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/format_nss.h>
> +
> +#include <support/support.h>
> +
> +char *
> +support_format_address_family (int family)
> +{
> +  switch (family)
> +    {
> +    case AF_INET:
> +      return xstrdup ("INET");
> +    case AF_INET6:
> +      return xstrdup ("INET6");
> +    default:
> +      return xasprintf ("<unknown address family %d>", family);
> +    }
> +}
> diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c
> new file mode 100644
> index 0000000..eedb030
> --- /dev/null
> +++ b/support/support_format_addrinfo.c
> @@ -0,0 +1,239 @@
> +/* Convert struct addrinfo values to a string.
> +   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/format_nss.h>
> +
> +#include <arpa/inet.h>
> +#include <errno.h>
> +#include <stdio.h>
> +#include <support/support.h>
> +#include <support/xmemstream.h>
> +
> +static size_t
> +socket_address_length (int family)
> +{
> +  switch (family)
> +    {
> +    case AF_INET:
> +      return sizeof (struct sockaddr_in);
> +    case AF_INET6:
> +      return sizeof (struct sockaddr_in6);
> +    default:
> +      return -1;
> +    }
> +}
> +
> +static void
> +format_ai_flags_1 (FILE *out, struct addrinfo *ai, int flag, const char *name,
> +                   int * flags_printed)
> +{
> +  if ((ai->ai_flags & flag) != 0)
> +    fprintf (out, " %s", name);
> +  *flags_printed |= flag;
> +}
> +
> +static void
> +format_ai_flags (FILE *out, struct addrinfo *ai)
> +{
> +  if (ai == NULL)
> +    return;
> +
> +  if (ai->ai_flags != 0)
> +    {
> +      fprintf (out, "flags:");
> +      int flags_printed = 0;
> +#define FLAG(flag) format_ai_flags_1 (out, ai, flag, #flag, &flags_printed)
> +      FLAG (AI_PASSIVE);
> +      FLAG (AI_CANONNAME);
> +      FLAG (AI_NUMERICHOST);
> +      FLAG (AI_V4MAPPED);
> +      FLAG (AI_ALL);
> +      FLAG (AI_ADDRCONFIG);
> +      FLAG (AI_IDN);
> +      FLAG (AI_CANONIDN);
> +      FLAG (AI_IDN_ALLOW_UNASSIGNED);
> +      FLAG (AI_IDN_USE_STD3_ASCII_RULES);
> +      FLAG (AI_NUMERICSERV);
> +#undef FLAG
> +      int remaining = ai->ai_flags & ~flags_printed;
> +      if (remaining != 0)
> +        fprintf (out, " %08x", remaining);
> +      fprintf (out, "\n");
> +    }
> +
> +  /* Report flag mismatches within the list.  */
> +  int flags = ai->ai_flags;
> +  int index = 1;
> +  ai = ai->ai_next;
> +  while (ai != NULL)
> +    {
> +      if (ai->ai_flags != flags)
> +        fprintf (out, "error: flags at %d: 0x%x expected, 0x%x actual\n",
> +                 index, flags, ai->ai_flags);
> +      ai = ai->ai_next;
> +      ++index;
> +    }
> +}
> +
> +static void
> +format_ai_canonname (FILE *out, struct addrinfo *ai)
> +{
> +  if (ai == NULL)
> +    return;
> +  if (ai->ai_canonname != NULL)
> +    fprintf (out, "canonname: %s\n", ai->ai_canonname);
> +
> +  /* Report incorrectly set ai_canonname fields on subsequent list
> +     entries.  */
> +  int index = 1;
> +  ai = ai->ai_next;
> +  while (ai != NULL)
> +    {
> +      if (ai->ai_canonname != NULL)
> +        fprintf (out, "error: canonname set at %d: %s\n",
> +                 index, ai->ai_canonname);
> +      ai = ai->ai_next;
> +      ++index;
> +    }
> +}
> +
> +static void
> +format_ai_one (FILE *out, struct addrinfo *ai)
> +{
> +  {
> +    char type_buf[32];
> +    const char *type_str;
> +    char proto_buf[32];
> +    const char *proto_str;
> +
> +    /* ai_socktype */
> +    switch (ai->ai_socktype)
> +      {
> +      case SOCK_RAW:
> +        type_str = "RAW";
> +        break;
> +      case SOCK_DGRAM:
> +        type_str = "DGRAM";
> +        break;
> +      case SOCK_STREAM:
> +        type_str = "STREAM";
> +        break;
> +      default:
> +        snprintf (type_buf, sizeof (type_buf), "%d", ai->ai_socktype);
> +        type_str = type_buf;
> +      }
> +
> +    /* ai_protocol */
> +    switch (ai->ai_protocol)
> +      {
> +      case IPPROTO_IP:
> +        proto_str = "IP";
> +        break;
> +      case IPPROTO_UDP:
> +        proto_str = "UDP";
> +        break;
> +      case IPPROTO_TCP:
> +        proto_str = "TCP";
> +        break;
> +      default:
> +        snprintf (proto_buf, sizeof (proto_buf), "%d", ai->ai_protocol);
> +        proto_str = proto_buf;
> +      }
> +    fprintf (out, "address: %s/%s", type_str, proto_str);
> +  }
> +
> +  /* ai_addrlen */
> +  if (ai->ai_addrlen != socket_address_length (ai->ai_family))
> +    {
> +      char *family = support_format_address_family (ai->ai_family);
> +      fprintf (out, "error: invalid address length %d for %s\n",
> +               ai->ai_addrlen, family);
> +      free (family);
> +    }
> +
> +  /* ai_addr */
> +  {
> +    char buf[128];
> +    uint16_t port;
> +    const char *ret;
> +    switch (ai->ai_family)
> +      {
> +      case AF_INET:
> +        {
> +          struct sockaddr_in *sin = (struct sockaddr_in *) ai->ai_addr;
> +          ret = inet_ntop (AF_INET, &sin->sin_addr, buf, sizeof (buf));
> +          port = sin->sin_port;
> +        }
> +        break;
> +      case AF_INET6:
> +        {
> +          struct sockaddr_in6 *sin = (struct sockaddr_in6 *) ai->ai_addr;
> +          ret = inet_ntop (AF_INET6, &sin->sin6_addr, buf, sizeof (buf));
> +          port = sin->sin6_port;
> +        }
> +        break;
> +      default:
> +        errno = EAFNOSUPPORT;
> +        ret = NULL;
> +      }
> +    if (ret == NULL)
> +        fprintf (out, "error: inet_top failed: %m\n");
> +    else
> +      fprintf (out, " %s %u\n", buf, ntohs (port));
> +  }
> +}
> +
> +/* Format all the addresses in one address family.  */
> +static void
> +format_ai_family (FILE *out, struct addrinfo *ai, int family)
> +{
> +  while (ai)
> +    {
> +      if (ai->ai_family == family)
> +        format_ai_one (out, ai);
> +      ai = ai->ai_next;
> +    }
> +}
> +
> +char *
> +support_format_addrinfo (struct addrinfo *ai, int ret)
> +{
> +  int errno_copy = errno;
> +
> +  struct xmemstream mem;
> +  xopen_memstream (&mem);
> +  if (ret != 0)
> +    {
> +      fprintf (mem.out, "error: %s\n", gai_strerror (ret));
> +      if (ret == EAI_SYSTEM)
> +        {
> +          errno = errno_copy;
> +          fprintf (mem.out, "error: %m\n");
> +        }
> +    }
> +  else
> +    {
> +      format_ai_flags (mem.out, ai);
> +      format_ai_canonname (mem.out, ai);
> +      format_ai_family (mem.out, ai, AF_INET);
> +      format_ai_family (mem.out, ai, AF_INET6);
> +    }
> +
> +  xfclose_memstream (&mem);
> +  return mem.buffer;
> +}
> diff --git a/support/support_format_dns_packet.c b/support/support_format_dns_packet.c
> new file mode 100644
> index 0000000..2992c57
> --- /dev/null
> +++ b/support/support_format_dns_packet.c
> @@ -0,0 +1,222 @@
> +/* Convert a DNS packet to a human-readable representation.
> +   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/format_nss.h>
> +
> +#include <arpa/inet.h>
> +#include <resolv.h>
> +#include <support/check.h>
> +#include <support/support.h>
> +#include <support/xmemstream.h>
> +
> +struct in_buffer
> +{
> +  const unsigned char *data;
> +  size_t size;
> +};
> +
> +static inline bool
> +extract_8 (struct in_buffer *in, unsigned char *value)
> +{
> +  if (in->size == 0)
> +    return false;
> +  *value = in->data[0];
> +  ++in->data;
> +  --in->size;
> +  return true;
> +}
> +
> +static inline bool
> +extract_16 (struct in_buffer *in, unsigned short *value)
> +{
> +  if (in->size < 2)
> +    return false;
> +  *value = (in->data[0] << 8) | in->data[1];
> +  in->data += 2;
> +  in->size -= 2;
> +  return true;
> +}
> +
> +static inline bool
> +extract_32 (struct in_buffer *in, unsigned *value)
> +{
> +  if (in->size < 4)
> +    return false;
> +  unsigned a = in->data[0];
> +  unsigned b = in->data[1];
> +  unsigned c = in->data[2];
> +  unsigned d = in->data[3];
> +  *value = (a << 24) | (b << 16) | (c << 8) | d;
> +  in->data += 4;
> +  in->size -= 4;
> +  return true;
> +}
> +
> +static inline bool
> +extract_bytes (struct in_buffer *in, size_t length, struct in_buffer *value)
> +{
> +  if (in->size < length)
> +    return false;
> +  *value = (struct in_buffer) {in->data, length};
> +  in->data += length;
> +  in->size -= length;
> +  return true;
> +}
> +
> +struct dname
> +{
> +  char name[MAXDNAME + 1];
> +};
> +
> +static bool
> +extract_name (struct in_buffer full, struct in_buffer *in, struct dname *value)
> +{
> +  const unsigned char *full_end = full.data + full.size;
> +  /* Sanity checks; these indicate buffer misuse.  */
> +  TEST_VERIFY_EXIT
> +    (!(in->data < full.data || in->data > full_end
> +       || in->size > (size_t) (full_end - in->data)));
> +  int ret = dn_expand (full.data, full_end, in->data,
> +                       value->name, sizeof (value->name));
> +  if (ret < 0)
> +    return false;
> +  in->data += ret;
> +  in->size -= ret;
> +  return true;
> +}
> +
> +char *
> +support_format_dns_packet (const unsigned char *buffer, size_t length)
> +{
> +  struct in_buffer full = { buffer, length };
> +  struct in_buffer in = full;
> +  struct xmemstream mem;
> +  xopen_memstream (&mem);
> +
> +  unsigned short txnid;
> +  unsigned short flags;
> +  unsigned short qdcount;
> +  unsigned short ancount;
> +  unsigned short nscount;
> +  unsigned short adcount;
> +  if (!(extract_16 (&in, &txnid)
> +        && extract_16 (&in, &flags)
> +        && extract_16 (&in, &qdcount)
> +        && extract_16 (&in, &ancount)
> +        && extract_16 (&in, &nscount)
> +        && extract_16 (&in, &adcount)))
> +    {
> +      fprintf (mem.out, "error: could not parse DNS header\n");
> +      goto out;
> +    }
> +  if (qdcount != 1)
> +    {
> +      fprintf (mem.out, "error: question count is %d, not 1\n", qdcount);
> +      goto out;
> +    }
> +  struct dname qname;
> +  if (!extract_name (full, &in, &qname))
> +    {
> +      fprintf (mem.out, "error: malformed QNAME\n");
> +      goto out;
> +    }
> +  unsigned short qtype;
> +  unsigned short qclass;
> +  if (!(extract_16 (&in, &qtype)
> +        && extract_16 (&in, &qclass)))
> +    {
> +      fprintf (mem.out, "error: malformed question\n");
> +      goto out;
> +    }
> +  if (qtype != T_A && qtype != T_AAAA && qtype != T_PTR)
> +    {
> +      fprintf (mem.out, "error: unsupported QTYPE %d\n", qtype);
> +      goto out;
> +    }
> +
> +  fprintf (mem.out, "name: %s\n", qname.name);
> +
> +  for (int i = 0; i < ancount; ++i)
> +    {
> +      struct dname rname;
> +      if (!extract_name (full, &in, &rname))
> +        {
> +          fprintf (mem.out, "error: malformed record name\n");
> +          goto out;
> +        }
> +      unsigned short rtype;
> +      unsigned short rclass;
> +      unsigned ttl;
> +      unsigned short rdlen;
> +      struct in_buffer rdata;
> +      if (!(extract_16 (&in, &rtype)
> +            && extract_16 (&in, &rclass)
> +            && extract_32 (&in, &ttl)
> +            && extract_16 (&in, &rdlen)
> +            && extract_bytes (&in, rdlen, &rdata)))
> +        {
> +          fprintf (mem.out, "error: malformed record header\n");
> +          goto out;
> +        }
> +      /* Skip non-matching record types.  */
> +      if ((rtype != qtype && rtype != T_CNAME) || rclass != qclass)
> +        continue;
> +      switch (rtype)
> +        {
> +        case T_A:
> +          if (rdlen == 4)
> +              fprintf (mem.out, "address: %d.%d.%d.%d\n",
> +                       rdata.data[0],
> +                       rdata.data[1],
> +                       rdata.data[2],
> +                       rdata.data[3]);
> +          else
> +            fprintf (mem.out, "error: A record of size %d: %s\n",
> +                     rdlen, rname.name);
> +          break;
> +        case T_AAAA:
> +          {
> +            if (rdlen == 16)
> +              {
> +                char buf[100];
> +                if (inet_ntop (AF_INET6, rdata.data, buf, sizeof (buf)) == NULL)
> +                  fprintf (mem.out, "error: AAAA record decoding failed: %m\n");
> +                else
> +                  fprintf (mem.out, "address: %s\n", buf);
> +              }
> +            else
> +              fprintf (mem.out, "error: AAAA record of size %d: %s\n",
> +                       rdlen, rname.name);
> +          }
> +          break;
> +        case T_CNAME:
> +        case T_PTR:
> +          {
> +            struct dname name;
> +            if (extract_name (full, &rdata, &name))
> +              fprintf (mem.out, "name: %s\n", name.name);
> +            else
> +              fprintf (mem.out, "error: malformed CNAME/PTR record\n");
> +          }
> +        }
> +    }
> +
> + out:
> +  xfclose_memstream (&mem);
> +  return mem.buffer;
> +}
> diff --git a/support/support_format_herrno.c b/support/support_format_herrno.c
> new file mode 100644
> index 0000000..493d6ae
> --- /dev/null
> +++ b/support/support_format_herrno.c
> @@ -0,0 +1,45 @@
> +/* Convert a h_errno error code to a string.
> +   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/format_nss.h>
> +
> +#include <support/support.h>
> +
> +char *
> +support_format_herrno (int code)
> +{
> +  const char *errstr;
> +  switch (code)
> +    {
> +    case HOST_NOT_FOUND:
> +      errstr = "HOST_NOT_FOUND";
> +      break;
> +    case NO_ADDRESS:
> +      errstr = "NO_ADDRESS";
> +      break;
> +    case NO_RECOVERY:
> +      errstr = "NO_RECOVERY";
> +      break;
> +    case TRY_AGAIN:
> +      errstr = "TRY_AGAIN";
> +      break;
> +    default:
> +      return xasprintf ("<invalid h_errno value %d>\n", code);
> +    }
> +  return xstrdup (errstr);
> +}
> diff --git a/support/support_format_hostent.c b/support/support_format_hostent.c
> new file mode 100644
> index 0000000..5b5f260
> --- /dev/null
> +++ b/support/support_format_hostent.c
> @@ -0,0 +1,75 @@
> +/* Convert a struct hostent object to a string.
> +   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/format_nss.h>
> +
> +#include <arpa/inet.h>
> +#include <stdio.h>
> +#include <support/support.h>
> +#include <support/xmemstream.h>
> +
> +static int
> +address_length (int family)
> +{
> +  switch (family)
> +    {
> +    case AF_INET:
> +      return 4;
> +    case AF_INET6:
> +      return 16;
> +    }
> +  return -1;
> +}
> +
> +char *
> +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;
> +    }
> +
> +  struct xmemstream mem;
> +  xopen_memstream (&mem);
> +
> +  fprintf (mem.out, "name: %s\n", h->h_name);
> +  for (char **alias = h->h_aliases; *alias != NULL; ++alias)
> +    fprintf (mem.out, "alias: %s\n", *alias);
> +  for (unsigned i = 0; h->h_addr_list[i] != NULL; ++i)
> +    {
> +      char buf[128];
> +      if (inet_ntop (h->h_addrtype, h->h_addr_list[i],
> +                     buf, sizeof (buf)) == NULL)
> +        fprintf (mem.out, "error: inet_ntop failed: %m\n");
> +      else
> +        fprintf (mem.out, "address: %s\n", buf);
> +    }
> +  if (h->h_length != address_length (h->h_addrtype))
> +    {
> +      char *family = support_format_address_family (h->h_addrtype);
> +      fprintf (mem.out, "error: invalid address length %d for %s\n",
> +               h->h_length, family);
> +      free (family);
> +    }
> +
> +  xfclose_memstream (&mem);
> +  return mem.buffer;
> +}
> diff --git a/support/support_format_netent.c b/support/support_format_netent.c
> new file mode 100644
> index 0000000..020f572
> --- /dev/null
> +++ b/support/support_format_netent.c
> @@ -0,0 +1,52 @@
> +/* Convert a struct netent object to a string.
> +   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/format_nss.h>
> +
> +#include <arpa/inet.h>
> +#include <stdio.h>
> +#include <support/support.h>
> +#include <support/xmemstream.h>
> +
> +char *
> +support_format_netent (struct netent *e)
> +{
> +  if (e == NULL)
> +    {
> +      char *value = support_format_herrno (h_errno);
> +      char *result = xasprintf ("error: %s\n", value);
> +      free (value);
> +      return result;
> +    }
> +
> +  struct xmemstream mem;
> +  xopen_memstream (&mem);
> +
> +  if (e->n_name != NULL)
> +    fprintf (mem.out, "name: %s\n", e->n_name);
> +  for (char **ap = e->n_aliases; *ap != NULL; ++ap)
> +    fprintf (mem.out, "alias: %s\n", *ap);
> +  if (e->n_addrtype != AF_INET)
> +    fprintf (mem.out, "addrtype: %d\n", e->n_addrtype);
> +  /* On alpha, e->n_net is an unsigned long.  */
> +  unsigned int n_net = e->n_net;
> +  fprintf (mem.out, "net: 0x%08x\n", n_net);
> +
> +  xfclose_memstream (&mem);
> +  return mem.buffer;
> +}
> diff --git a/support/support_isolate_in_subprocess.c b/support/support_isolate_in_subprocess.c
> new file mode 100644
> index 0000000..cf48614
> --- /dev/null
> +++ b/support/support_isolate_in_subprocess.c
> @@ -0,0 +1,38 @@
> +/* Run a function in a subprocess.
> +   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
> +support_isolate_in_subprocess (void (*callback) (void *), void *closure)
> +{
> +  pid_t pid = xfork ();
> +  if (pid == 0)
> +    {
> +      /* Child process.  */
> +      callback (closure);
> +      _exit (0);
> +    }
> +
> +  /* Parent process.  */
> +  int status;
> +  xwaitpid (pid, &status, 0);
> +  if (status != 0)
> +    FAIL_EXIT1 ("child process exited with status %d", status);
> +}
> diff --git a/support/support_record_failure.c b/support/support_record_failure.c
> new file mode 100644
> index 0000000..684055c
> --- /dev/null
> +++ b/support/support_record_failure.c
> @@ -0,0 +1,106 @@
> +/* Global test failure counter.
> +   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/check.h>
> +#include <support/support.h>
> +#include <support/test-driver.h>
> +
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/mman.h>
> +#include <unistd.h>
> +
> +/* This structure keeps track of test failures.  The counter is
> +   incremented on each failure.  The failed member is set to true if a
> +   failure is detected, so that even if the counter wraps around to
> +   zero, the failure of a test can be detected.
> +
> +   The init constructor function below puts *state on a shared
> +   annonymous mapping, so that failure reports from subprocesses
> +   propagate to the parent process.  */
> +struct test_failures
> +{
> +  unsigned int counter;
> +  unsigned int failed;
> +};
> +static struct test_failures *state;
> +
> +static __attribute__ ((constructor)) void
> +init (void)
> +{
> +  void *ptr = mmap (NULL, sizeof (*state), PROT_READ | PROT_WRITE,
> +                    MAP_ANONYMOUS | MAP_SHARED, -1, 0);
> +  if (ptr == MAP_FAILED)
> +    {
> +      printf ("error: could not map %zu bytes: %m\n", sizeof (*state));
> +      exit (1);
> +    }
> +  /* Zero-initialization of the struct is sufficient.  */
> +  state = ptr;
> +}
> +
> +void
> +support_record_failure (void)
> +{
> +  if (state == NULL)
> +    {
> +      write_message
> +        ("error: support_record_failure called without initialization\n");
> +      _exit (1);
> +    }
> +  /* Relaxed MO is sufficient because we are only interested in the
> +     values themselves, in isolation.  */
> +  __atomic_store_n (&state->failed, 1, __ATOMIC_RELEASE);
> +  __atomic_add_fetch (&state->counter, 1, __ATOMIC_RELEASE);
> +}
> +
> +int
> +support_report_failure (int status)
> +{
> +  if (state == NULL)
> +    {
> +      write_message
> +        ("error: support_report_failure called without initialization\n");
> +      return 1;
> +    }
> +
> +  /* Relaxed MO is sufficient because acquire test result reporting
> +     assumes that exiting from the main thread happens before the
> +     error reporting via support_record_failure, which requires some
> +     form of external synchronization.  */
> +  bool failed = __atomic_load_n (&state->failed, __ATOMIC_RELAXED);
> +  if (failed)
> +    printf ("error: %u test failures\n",
> +            __atomic_load_n (&state->counter, __ATOMIC_RELAXED));
> +
> +  if ((status == 0 || status == EXIT_UNSUPPORTED) && failed)
> +    /* If we have a recorded failure, it overrides a non-failure
> +       report from the test function.  */
> +    status = 1;
> +  return status;
> +}
> +
> +void
> +support_record_failure_reset (void)
> +{
> +  /* Only used for testing the test framework, with external
> +     synchronization, but use release MO for consistency.  */
> +  __atomic_store_n (&state->failed, 0, __ATOMIC_RELAXED);
> +  __atomic_add_fetch (&state->counter, 0, __ATOMIC_RELAXED);
> +}
> diff --git a/support/support_run_diff.c b/support/support_run_diff.c
> new file mode 100644
> index 0000000..f5155de
> --- /dev/null
> +++ b/support/support_run_diff.c
> @@ -0,0 +1,76 @@
> +/* Invoke the system diff tool to compare two strings.
> +   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/run_diff.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>
> +#include <sys/wait.h>
> +
> +static char *
> +write_to_temp_file (const char *prefix, const char *str)
> +{
> +  char *template = xasprintf ("run_diff-%s", prefix);
> +  char *name = NULL;
> +  int fd = create_temp_file (template, &name);
> +  TEST_VERIFY_EXIT (fd >= 0);
> +  free (template);
> +  xwrite (fd, str, strlen (str));
> +  xclose (fd);
> +  return name;
> +}
> +
> +void
> +support_run_diff (const char *left_label, const char *left,
> +                  const char *right_label, const char *right)
> +{
> +  /* Ensure that the diff command output is ordered properly with
> +     standard output.  */
> +  TEST_VERIFY_EXIT (fflush (stdout) == 0);
> +
> +  char *left_path = write_to_temp_file ("left-diff", left);
> +  char *right_path = write_to_temp_file ("right-diff", right);
> +
> +  pid_t pid = xfork ();
> +  if (pid == 0)
> +    {
> +      execlp ("diff", "diff", "-u",
> +              "--label", left_label, "--label", right_label,
> +              "--", left_path, right_path,
> +              NULL);
> +      _exit (17);
> +    }
> +  else
> +    {
> +      int status;
> +      xwaitpid (pid, &status, 0);
> +      if (!WIFEXITED (status) || WEXITSTATUS (status) != 1)
> +        printf ("warning: could not run diff, exit status: %d\n"
> +                "*** %s ***\n%s\n"
> +                "*** %s ***\n%s\n",
> +                status, left_label, left, right_label, right);
> +    }
> +
> +  free (right_path);
> +  free (left_path);
> +}
> diff --git a/support/support_shared_allocate.c b/support/support_shared_allocate.c
> new file mode 100644
> index 0000000..c2ca7c2
> --- /dev/null
> +++ b/support/support_shared_allocate.c
> @@ -0,0 +1,59 @@
> +/* Allocate a memory region shared across processes.
> +   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 <stddef.h>
> +#include <support/support.h>
> +#include <support/xunistd.h>
> +#include <sys/mman.h>
> +
> +#if defined ISO11
> +/* Header for the allocation.  It contains the size of the allocation
> +   for subsequent unmapping.  */
> +struct header
> +{
> +  size_t total_size;
> +  char data[] __attribute__ ((aligned (__alignof__ (max_align_t))));
> +};
> +
> +void *
> +support_shared_allocate (size_t size)
> +{
> +  size_t total_size = size + offsetof (struct header, data);
> +  if (total_size < size)
> +    {
> +      errno = ENOMEM;
> +      oom_error (__func__, size);
> +      return NULL;
> +    }
> +  else
> +    {
> +      struct header *result = xmmap (NULL, total_size, PROT_READ | PROT_WRITE,
> +                                     MAP_ANONYMOUS | MAP_SHARED, -1);
> +      result->total_size = total_size;
> +      return &result->data;
> +    }
> +}
> +
> +void
> +support_shared_free (void *data)
> +{
> +  struct header *header = data - offsetof (struct header, data);
> +  xmunmap (header, header->total_size);
> +}
> +#endif
> diff --git a/support/support_test_main.c b/support/support_test_main.c
> new file mode 100644
> index 0000000..914d64f
> --- /dev/null
> +++ b/support/support_test_main.c
> @@ -0,0 +1,423 @@
> +/* Main worker function for the test driver.
> +   Copyright (C) 1998-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/test-driver.h>
> +#include <support/check.h>
> +#include <support/temp_file-internal.h>
> +
> +#include <assert.h>
> +#include <errno.h>
> +#include <getopt.h>
> +#include <malloc.h>
> +#include <signal.h>
> +#include <stdbool.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/param.h>
> +#include <sys/resource.h>
> +#include <sys/types.h>
> +#include <sys/wait.h>
> +#include <time.h>
> +#include <unistd.h>
> +
> +static const struct option default_options[] =
> +{
> +  TEST_DEFAULT_OPTIONS
> +  { NULL, 0, NULL, 0 }
> +};
> +
> +/* Show people how to run the program.  */
> +static void
> +usage (const struct option *options)
> +{
> +  size_t i;
> +
> +  printf ("Usage: %s [options]\n"
> +          "\n"
> +          "Environment Variables:\n"
> +          "  TIMEOUTFACTOR          An integer used to scale the timeout\n"
> +          "  TMPDIR                 Where to place temporary files\n"
> +          "  TEST_COREDUMPS         Do not disable coredumps if set\n"
> +          "\n",
> +          program_invocation_short_name);
> +  printf ("Options:\n");
> +  for (i = 0; options[i].name; ++i)
> +    {
> +      int indent;
> +
> +      indent = printf ("  --%s", options[i].name);
> +      if (options[i].has_arg == required_argument)
> +        indent += printf (" <arg>");
> +      printf ("%*s", 25 - indent, "");
> +      switch (options[i].val)
> +        {
> +        case 'v':
> +          printf ("Increase the output verbosity");
> +          break;
> +        case OPT_DIRECT:
> +          printf ("Run the test directly (instead of forking & monitoring)");
> +          break;
> +        case OPT_TESTDIR:
> +          printf ("Override the TMPDIR env var");
> +          break;
> +        }
> +      printf ("\n");
> +    }
> +}
> +
> +/* The PID of the test process.  */
> +static pid_t test_pid;
> +
> +/* The cleanup handler passed to test_main.  */
> +static void (*cleanup_function) (void);
> +
> +/* Timeout handler.  We kill the child and exit with an error.  */
> +static void
> +__attribute__ ((noreturn))
> +signal_handler (int sig)
> +{
> +  int killed;
> +  int status;
> +
> +  assert (test_pid > 1);
> +  /* Kill the whole process group.  */
> +  kill (-test_pid, SIGKILL);
> +  /* In case setpgid failed in the child, kill it individually too.  */
> +  kill (test_pid, SIGKILL);
> +
> +  /* Wait for it to terminate.  */
> +  int i;
> +  for (i = 0; i < 5; ++i)
> +    {
> +      killed = waitpid (test_pid, &status, WNOHANG|WUNTRACED);
> +      if (killed != 0)
> +        break;
> +
> +      /* Delay, give the system time to process the kill.  If the
> +         nanosleep() call return prematurely, all the better.  We
> +         won't restart it since this probably means the child process
> +         finally died.  */
> +      struct timespec ts;
> +      ts.tv_sec = 0;
> +      ts.tv_nsec = 100000000;
> +      nanosleep (&ts, NULL);
> +    }
> +  if (killed != 0 && killed != test_pid)
> +    {
> +      printf ("Failed to kill test process: %m\n");
> +      exit (1);
> +    }
> +
> +  if (cleanup_function != NULL)
> +    cleanup_function ();
> +
> +  if (sig == SIGINT)
> +    {
> +      signal (sig, SIG_DFL);
> +      raise (sig);
> +    }
> +
> +  if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL))
> +    puts ("Timed out: killed the child process");
> +  else if (WIFSTOPPED (status))
> +    printf ("Timed out: the child process was %s\n",
> +            strsignal (WSTOPSIG (status)));
> +  else if (WIFSIGNALED (status))
> +    printf ("Timed out: the child process got signal %s\n",
> +            strsignal (WTERMSIG (status)));
> +  else
> +    printf ("Timed out: killed the child process but it exited %d\n",
> +            WEXITSTATUS (status));
> +
> +  /* Exit with an error.  */
> +  exit (1);
> +}
> +
> +/* Run test_function or test_function_argv.  */
> +static int
> +run_test_function (int argc, char **argv, const struct test_config *config)
> +{
> +  if (config->test_function != NULL)
> +    return config->test_function ();
> +  else if (config->test_function_argv != NULL)
> +    return config->test_function_argv (argc, argv);
> +  else
> +    {
> +      printf ("error: no test function defined\n");
> +      exit (1);
> +    }
> +}
> +
> +static bool test_main_called;
> +
> +const char *test_dir = NULL;
> +unsigned int test_verbose = 0;
> +
> +/* If test failure reporting has been linked in, it may contribute
> +   additional test failures.  */
> +static int
> +adjust_exit_status (int status)
> +{
> +  if (support_report_failure != NULL)
> +    return support_report_failure (status);
> +  return status;
> +}
> +
> +int
> +support_test_main (int argc, char **argv, const struct test_config *config)
> +{
> +  if (test_main_called)
> +    {
> +      printf ("error: test_main called for a second time\n");
> +      exit (1);
> +    }
> +  test_main_called = true;
> +  const struct option *options;
> +  if (config->options != NULL)
> +    options = config->options;
> +  else
> +    options = default_options;
> +
> +  cleanup_function = config->cleanup_function;
> +
> +  int direct = 0;       /* Directly call the test function?  */
> +  int status;
> +  int opt;
> +  unsigned int timeoutfactor = 1;
> +  pid_t termpid;
> +
> +  if (!config->no_mallopt)
> +    {
> +      /* Make uses of freed and uninitialized memory known.  Do not
> +         pull in a definition for mallopt if it has not been defined
> +         already.  */
> +      extern __typeof__ (mallopt) mallopt __attribute__ ((weak));
> +      if (mallopt != NULL)
> +        mallopt (M_PERTURB, 42);
> +    }
> +
> +  while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1)
> +    switch (opt)
> +      {
> +      case '?':
> +        usage (options);
> +        exit (1);
> +      case 'v':
> +        ++test_verbose;
> +        break;
> +      case OPT_DIRECT:
> +        direct = 1;
> +        break;
> +      case OPT_TESTDIR:
> +        test_dir = optarg;
> +        break;
> +      default:
> +        if (config->cmdline_function != NULL)
> +          config->cmdline_function (opt);
> +      }
> +
> +  /* If set, read the test TIMEOUTFACTOR value from the environment.
> +     This value is used to scale the default test timeout values. */
> +  char *envstr_timeoutfactor = getenv ("TIMEOUTFACTOR");
> +  if (envstr_timeoutfactor != NULL)
> +    {
> +      char *envstr_conv = envstr_timeoutfactor;
> +      unsigned long int env_fact;
> +
> +      env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0);
> +      if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor)
> +        timeoutfactor = MAX (env_fact, 1);
> +    }
> +
> +  /* Set TMPDIR to specified test directory.  */
> +  if (test_dir != NULL)
> +    {
> +      setenv ("TMPDIR", test_dir, 1);
> +
> +      if (chdir (test_dir) < 0)
> +        {
> +          printf ("chdir: %m\n");
> +          exit (1);
> +        }
> +    }
> +  else
> +    {
> +      test_dir = getenv ("TMPDIR");
> +      if (test_dir == NULL || test_dir[0] == '\0')
> +        test_dir = "/tmp";
> +    }
> +  if (support_set_test_dir != NULL)
> +    support_set_test_dir (test_dir);
> +
> +  int timeout = config->timeout;
> +  if (timeout == 0)
> +    timeout =  DEFAULT_TIMEOUT;
> +
> +  /* Make sure we see all message, even those on stdout.  */
> +  setvbuf (stdout, NULL, _IONBF, 0);
> +
> +  /* Make sure temporary files are deleted.  */
> +  if (support_delete_temp_files != NULL)
> +      atexit (support_delete_temp_files);
> +
> +  /* Correct for the possible parameters.  */
> +  argv[optind - 1] = argv[0];
> +  argv += optind - 1;
> +  argc -= optind - 1;
> +
> +  /* Call the initializing function, if one is available.  */
> +  if (config->prepare_function != NULL)
> +    config->prepare_function (argc, argv);
> +
> +  const char *envstr_direct = getenv ("TEST_DIRECT");
> +  if (envstr_direct != NULL)
> +    {
> +      FILE *f = fopen (envstr_direct, "w");
> +      if (f == NULL)
> +        {
> +          printf ("cannot open TEST_DIRECT output file '%s': %m\n",
> +                  envstr_direct);
> +          exit (1);
> +        }
> +
> +      fprintf (f, "timeout=%u\ntimeoutfactor=%u\n",
> +               config->timeout, timeoutfactor);
> +      if (config->expected_status != 0)
> +        fprintf (f, "exit=%u\n", config->expected_status);
> +      if (config->expected_signal != 0)
> +        fprintf (f, "signal=%s\n", strsignal (config->expected_signal));
> +
> +      if (support_print_temp_files != NULL)
> +        support_print_temp_files (f);
> +
> +      fclose (f);
> +      direct = 1;
> +    }
> +
> +  bool disable_coredumps;
> +  {
> +    const char *coredumps = getenv ("TEST_COREDUMPS");
> +    disable_coredumps = coredumps == NULL || coredumps[0] == '\0';
> +  }
> +
> +  /* If we are not expected to fork run the function immediately.  */
> +  if (direct)
> +    return adjust_exit_status (run_test_function (argc, argv, config));
> +
> +  /* Set up the test environment:
> +     - prevent core dumps
> +     - set up the timer
> +     - fork and execute the function.  */
> +
> +  test_pid = fork ();
> +  if (test_pid == 0)
> +    {
> +      /* This is the child.  */
> +      if (disable_coredumps)
> +        {
> +          /* Try to avoid dumping core.  This is necessary because we
> +             run the test from the source tree, and the coredumps
> +             would end up there (and not in the build tree).  */
> +          struct rlimit core_limit;
> +          core_limit.rlim_cur = 0;
> +          core_limit.rlim_max = 0;
> +          setrlimit (RLIMIT_CORE, &core_limit);
> +        }
> +
> +      /* We put the test process in its own pgrp so that if it bogusly
> +         generates any job control signals, they won't hit the whole build.  */
> +      if (setpgid (0, 0) != 0)
> +        printf ("Failed to set the process group ID: %m\n");
> +
> +      /* Execute the test function and exit with the return value.   */
> +      exit (run_test_function (argc, argv, config));
> +    }
> +  else if (test_pid < 0)
> +    {
> +      printf ("Cannot fork test program: %m\n");
> +      exit (1);
> +    }
> +
> +  /* Set timeout.  */
> +  signal (SIGALRM, signal_handler);
> +  alarm (timeout * timeoutfactor);
> +
> +  /* Make sure we clean up if the wrapper gets interrupted.  */
> +  signal (SIGINT, signal_handler);
> +
> +  /* Wait for the regular termination.  */
> +  termpid = TEMP_FAILURE_RETRY (waitpid (test_pid, &status, 0));
> +  if (termpid == -1)
> +    {
> +      printf ("Waiting for test program failed: %m\n");
> +      exit (1);
> +    }
> +  if (termpid != test_pid)
> +    {
> +      printf ("Oops, wrong test program terminated: expected %ld, got %ld\n",
> +              (long int) test_pid, (long int) termpid);
> +      exit (1);
> +    }
> +
> +  /* Process terminated normaly without timeout etc.  */
> +  if (WIFEXITED (status))
> +    {
> +      if (config->expected_status == 0)
> +        {
> +          if (config->expected_signal == 0)
> +            /* Exit with the return value of the test.  */
> +            return adjust_exit_status (WEXITSTATUS (status));
> +          else
> +            {
> +              printf ("Expected signal '%s' from child, got none\n",
> +                      strsignal (config->expected_signal));
> +              exit (1);
> +            }
> +        }
> +      else
> +        {
> +          /* Non-zero exit status is expected */
> +          if (WEXITSTATUS (status) != config->expected_status)
> +            {
> +              printf ("Expected status %d, got %d\n",
> +                      config->expected_status, WEXITSTATUS (status));
> +              exit (1);
> +            }
> +        }
> +      return adjust_exit_status (0);
> +    }
> +  /* Process was killed by timer or other signal.  */
> +  else
> +    {
> +      if (config->expected_signal == 0)
> +        {
> +          printf ("Didn't expect signal from child: got `%s'\n",
> +                  strsignal (WTERMSIG (status)));
> +          exit (1);
> +        }
> +      else if (WTERMSIG (status) != config->expected_signal)
> +        {
> +          printf ("Incorrect signal from child: got `%s', need `%s'\n",
> +                  strsignal (WTERMSIG (status)),
> +                  strsignal (config->expected_signal));
> +          exit (1);
> +        }
> +
> +      return adjust_exit_status (0);
> +    }
> +}
> diff --git a/support/support_test_verify_impl.c b/support/support_test_verify_impl.c
> new file mode 100644
> index 0000000..5bae38f
> --- /dev/null
> +++ b/support/support_test_verify_impl.c
> @@ -0,0 +1,33 @@
> +/* Implementation of the TEST_VERIFY and TEST_VERIFY_EXIT macros.
> +   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/check.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +void
> +support_test_verify_impl (int status, const char *file, int line,
> +                          const char *expr)
> +{
> +  support_record_failure ();
> +  printf ("error: %s:%d: not true: %s\n", file, line, expr);
> +  if (status >= 0)
> +    exit (status);
> +
> +}
> diff --git a/support/support_write_file_string.c b/support/support_write_file_string.c
> new file mode 100644
> index 0000000..48e8959
> --- /dev/null
> +++ b/support/support_write_file_string.c
> @@ -0,0 +1,39 @@
> +/* Write a string to a file.
> +   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 <fcntl.h>
> +#include <string.h>
> +#include <support/check.h>
> +#include <xunistd.h>
> +
> +void
> +support_write_file_string (const char *path, const char *contents)
> +{
> +  int fd = xopen (path, O_CREAT | O_TRUNC | O_WRONLY, 0666);
> +  const char *end = contents + strlen (contents);
> +  for (const char *p = contents; p < end; )
> +    {
> +      ssize_t ret = write (fd, p, end - p);
> +      if (ret < 0)
> +        FAIL_EXIT1 ("cannot write to \"%s\": %m", path);
> +      if (ret == 0)
> +        FAIL_EXIT1 ("zero-length write to \"%s\"", path);
> +      p += ret;
> +    }
> +  xclose (fd);
> +}
> diff --git a/support/temp_file-internal.h b/support/temp_file-internal.h
> new file mode 100644
> index 0000000..fb6cceb
> --- /dev/null
> +++ b/support/temp_file-internal.h
> @@ -0,0 +1,31 @@
> +/* Internal weak declarations for temporary file handling.
> +   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/>.  */
> +
> +#ifndef SUPPORT_TEMP_FILE_INTERNAL_H
> +#define SUPPORT_TEMP_FILE_INTERNAL_H
> +
> +/* These functions are called by the test driver if they are
> +   defined.  Tests should not call them directly.  */
> +
> +#include <stdio.h>
> +
> +void support_set_test_dir (const char *name) __attribute__ ((weak));
> +void support_delete_temp_files (void) __attribute__ ((weak));
> +void support_print_temp_files (FILE *) __attribute__ ((weak));
> +
> +#endif /* SUPPORT_TEMP_FILE_INTERNAL_H */
> diff --git a/support/temp_file.c b/support/temp_file.c
> new file mode 100644
> index 0000000..fdb2477
> --- /dev/null
> +++ b/support/temp_file.c
> @@ -0,0 +1,132 @@
> +/* Temporary file handling for tests.
> +   Copyright (C) 1998-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/>.  */
> +
> +/* This is required to get an mkstemp which can create large files on
> +   some 32-bit platforms. */
> +#define _FILE_OFFSET_BITS 64
> +
> +#include <support/temp_file.h>
> +#include <support/temp_file-internal.h>
> +#include <support/support.h>
> +
> +#include <paths.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +/* List of temporary files.  */
> +static struct temp_name_list
> +{
> +  struct temp_name_list *next;
> +  char *name;
> +  pid_t owner;
> +} *temp_name_list;
> +
> +/* Location of the temporary files.  Set by the test skeleton via
> +   support_set_test_dir.  The string is not be freed.  */
> +static const char *test_dir = _PATH_TMP;
> +
> +void
> +add_temp_file (const char *name)
> +{
> +  struct temp_name_list *newp
> +    = (struct temp_name_list *) xcalloc (sizeof (*newp), 1);
> +  char *newname = strdup (name);
> +  if (newname != NULL)
> +    {
> +      newp->name = newname;
> +      newp->next = temp_name_list;
> +      newp->owner = getpid ();
> +      temp_name_list = newp;
> +    }
> +  else
> +    free (newp);
> +}
> +
> +int
> +create_temp_file (const char *base, char **filename)
> +{
> +  char *fname;
> +  int fd;
> +
> +  fname = (char *) xmalloc (strlen (test_dir) + 1 + strlen (base)
> +			    + sizeof ("XXXXXX"));
> +  strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX");
> +
> +  fd = mkstemp (fname);
> +  if (fd == -1)
> +    {
> +      printf ("cannot open temporary file '%s': %m\n", fname);
> +      free (fname);
> +      return -1;
> +    }
> +
> +  add_temp_file (fname);
> +  if (filename != NULL)
> +    *filename = fname;
> +  else
> +    free (fname);
> +
> +  return fd;
> +}
> +
> +/* Helper functions called by the test skeleton follow.  */
> +
> +void
> +support_set_test_dir (const char *path)
> +{
> +  test_dir = path;
> +}
> +
> +void
> +support_delete_temp_files (void)
> +{
> +  pid_t pid = getpid ();
> +  while (temp_name_list != NULL)
> +    {
> +      /* Only perform the removal if the path was registed in the same
> +	 process, as identified by the PID.  (This assumes that the
> +	 parent process which registered the temporary file sticks
> +	 around, to prevent PID reuse.)  */
> +      if (temp_name_list->owner == pid)
> +	{
> +	  if (remove (temp_name_list->name) != 0)
> +	    printf ("warning: could not remove temporary file: %s: %m\n",
> +		    temp_name_list->name);
> +	}
> +      free (temp_name_list->name);
> +
> +      struct temp_name_list *next = temp_name_list->next;
> +      free (temp_name_list);
> +      temp_name_list = next;
> +    }
> +}
> +
> +void
> +support_print_temp_files (FILE *f)
> +{
> +  if (temp_name_list != NULL)
> +    {
> +      struct temp_name_list *n;
> +      fprintf (f, "temp_files=(\n");
> +      for (n = temp_name_list; n != NULL; n = n->next)
> +        fprintf (f, "  '%s'\n", n->name);
> +      fprintf (f, ")\n");
> +    }
> +}
> diff --git a/support/temp_file.h b/support/temp_file.h
> new file mode 100644
> index 0000000..6fed8df
> --- /dev/null
> +++ b/support/temp_file.h
> @@ -0,0 +1,37 @@
> +/* Declarations for temporary file handling.
> +   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/>.  */
> +
> +#ifndef SUPPORT_TEMP_FILE_H
> +#define SUPPORT_TEMP_FILE_H
> +
> +#include <sys/cdefs.h>
> +
> +__BEGIN_DECLS
> +
> +/* Schedule a temporary file for deletion on exit.  */
> +void add_temp_file (const char *name);
> +
> +/* Create a temporary file.  Return the opened file descriptor on
> +   success, or -1 on failure.  Write the file name to *FILENAME if
> +   FILENAME is not NULL.  In this case, the caller is expected to free
> +   *FILENAME.  */
> +int create_temp_file (const char *base, char **filename);
> +
> +__END_DECLS
> +
> +#endif /* SUPPORT_TEMP_FILE_H */
> diff --git a/support/test-driver.c b/support/test-driver.c
> new file mode 100644
> index 0000000..482066d
> --- /dev/null
> +++ b/support/test-driver.c
> @@ -0,0 +1,156 @@
> +/* Main function for test programs.
> +   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/>.  */
> +
> +/* This file should be included from test cases.  It will define a
> +   main function which provides the test wrapper.
> +
> +   It assumes that the test case defines a function
> +
> +     int do_test (void);
> +
> +   and arranges for that function being called under the test wrapper.
> +   The do_test function should return 0 to indicate a passing test, 1
> +   to indicate a failing test, or 77 to indicate an unsupported test.
> +   Other result values could be used to indicate a failing test, but
> +   the result of the expression is passed to exit and exit only
> +   returns the lower 8 bits of its input.  A non-zero return with some
> +   values could cause a test to incorrectly be considered passing when
> +   it really failed.  For this reason, the function should always
> +   return 0 (EXIT_SUCCESS), 1 (EXIT_FAILURE), or 77
> +   (EXIT_UNSUPPORTED).
> +
> +   The test function may print out diagnostic or warning messages as well
> +   as messages about failures.  These messages should be printed to stdout
> +   and not stderr so that the output is properly ordered with respect to
> +   the rest of the glibc testsuite run output.
> +
> +   Several preprocessors macros can be defined before including this
> +   file.
> +
> +   The name of the do_test function can be changed with the
> +   TEST_FUNCTION macro.  It must expand to the desired function name.
> +
> +   If the test case needs access to command line parameters, it must
> +   define the TEST_FUNCTION_ARGV macro with the name of the test
> +   function.  It must have the following type:
> +
> +     int TEST_FUNCTION_ARGV (int argc, char **argv);
> +
> +   This overrides the do_test default function and is incompatible
> +   with the TEST_FUNCTION macro.
> +
> +   If PREPARE is defined, it must expand to the name of a function of
> +   the type
> +
> +     void PREPARE (int argc, char **);
> +
> +   This function will be called early, after parsing the command line,
> +   but before running the test, in the parent process which acts as
> +   the test supervisor.
> +
> +   If CLEANUP_HANDLER is defined, it must expand to the name of a
> +   function of the type
> +
> +     void CLEANUP_HANDLER (void);
> +
> +   This function will be called from the timeout (SIGALRM) signal
> +   handler.
> +
> +   If EXPECTED_SIGNAL is defined, it must expanded to a constant which
> +   denotes the expected signal number.
> +
> +   If EXPECTED_STATUS is defined, it must expand to the expected exit
> +   status.
> +
> +   If TIMEOUT is defined, it must be positive constant.  It overrides
> +   the default test timeout and is measured in seconds.
> +
> +   If TEST_NO_MALLOPT is defined, the test wrapper will not call
> +   mallopt.
> +
> +   Custom command line handling can be implemented by defining the
> +   CMDLINE_OPTION macro (after including the <getopt.h> header; this
> +   requires _GNU_SOURCE to be defined).  This macro must expand to a
> +   to a comma-separated list of braced initializers for struct option
> +   from <getopt.h>, with a trailing comma.  CMDLINE_PROCESS can be
> +   defined as the name of a function which is called to process these
> +   options.  The function is passed the option character/number and
> +   has this type:
> +
> +     void CMDLINE_PROCESS (int);
> +*/
> +
> +#include <support/test-driver.h>
> +
> +#include <string.h>
> +
> +int
> +main (int argc, char **argv)
> +{
> +  struct test_config test_config;
> +  memset (&test_config, 0, sizeof (test_config));
> +
> +#ifdef PREPARE
> +  test_config.prepare_function = (PREPARE);
> +#endif
> +
> +#if defined (TEST_FUNCTION) && defined (TEST_FUNCTON_ARGV)
> +# error TEST_FUNCTION and TEST_FUNCTION_ARGV cannot be defined at the same time
> +#endif
> +#if defined (TEST_FUNCTION)
> +  test_config.test_function = TEST_FUNCTION;
> +#elif defined (TEST_FUNCTION_ARGV)
> +  test_config.test_function_argv = TEST_FUNCTION_ARGV;
> +#else
> +  test_config.test_function = do_test;
> +#endif
> +
> +#ifdef CLEANUP_HANDLER
> +  test_config.cleanup_function = CLEANUP_HANDLER;
> +#endif
> +
> +#ifdef EXPECTED_SIGNAL
> +  test_config.expected_signal = (EXPECTED_SIGNAL);
> +#endif
> +
> +#ifdef EXPECTED_STATUS
> +  test_config.expected_status = (EXPECTED_STATUS);
> +#endif
> +
> +#ifdef TEST_NO_MALLOPT
> +  test_config.no_mallopt = 1;
> +#endif
> +
> +#ifdef TIMEOUT
> +  test_config.timeout = TIMEOUT;
> +#endif
> +
> +#ifdef CMDLINE_OPTIONS
> +  struct option options[] =
> +    {
> +      CMDLINE_OPTIONS
> +      TEST_DEFAULT_OPTIONS
> +    };
> +  test_config.options = &options;
> +#endif
> +#ifdef CMDLINE_PROCESS
> +  test_config.cmdline_function = CMDLINE_PROCESS;
> +#endif
> +
> +  return support_test_main (argc, argv, &test_config);
> +}
> diff --git a/support/test-driver.h b/support/test-driver.h
> new file mode 100644
> index 0000000..af1971a
> --- /dev/null
> +++ b/support/test-driver.h
> @@ -0,0 +1,74 @@
> +/* Interfaces for the test driver.
> +   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/>.  */
> +
> +#ifndef SUPPORT_TEST_DRIVER_H
> +#define SUPPORT_TEST_DRIVER_H
> +
> +#include <sys/cdefs.h>
> +
> +__BEGIN_DECLS
> +
> +struct test_config
> +{
> +  void (*prepare_function) (int argc, char **argv);
> +  int (*test_function) (void);
> +  int (*test_function_argv) (int argc, char **argv);
> +  void (*cleanup_function) (void);
> +  void (*cmdline_function) (int);
> +  const void *options;   /* Custom options if not NULL.  */
> +  int timeout;           /* Test timeout in seconds.  */
> +  int expected_status;   /* Expected exit status.  */
> +  int expected_signal;   /* If non-zero, expect termination by signal.  */
> +  char no_mallopt;       /* Boolean flag to disable mallopt.  */
> +};
> +
> +enum
> +  {
> +    /* Test exit status which indicates that the feature is
> +       unsupported. */
> +    EXIT_UNSUPPORTED = 77,
> +
> +    /* Default timeout is twenty seconds.  Tests should normally
> +       complete faster than this, but if they don't, that's abnormal
> +       (a bug) anyways.  */
> +    DEFAULT_TIMEOUT = 20,
> +
> +    /* Used for command line argument parsing.  */
> +    OPT_DIRECT = 1000,
> +    OPT_TESTDIR,
> +  };
> +
> +/* Options provided by the test driver.  */
> +#define TEST_DEFAULT_OPTIONS                            \
> +  { "verbose", no_argument, NULL, 'v' },                \
> +  { "direct", no_argument, NULL, OPT_DIRECT },          \
> +  { "test-dir", required_argument, NULL, OPT_TESTDIR }, \
> +
> +/* The directory the test should use for temporary files.  */
> +extern const char *test_dir;
> +
> +/* The number of --verbose arguments specified during program
> +   invocation.  This variable can be used to control the verbosity of
> +   tests.  */
> +extern unsigned int test_verbose;
> +
> +int support_test_main (int argc, char **argv, const struct test_config *);
> +
> +__END_DECLS
> +
> +#endif /* SUPPORT_TEST_DRIVER_H */
> diff --git a/support/tst-support-namespace.c b/support/tst-support-namespace.c
> new file mode 100644
> index 0000000..a50b074
> --- /dev/null
> +++ b/support/tst-support-namespace.c
> @@ -0,0 +1,34 @@
> +/* Test entering namespaces.
> +   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 <stdio.h>
> +#include <support/namespace.h>
> +
> +static int
> +do_test (void)
> +{
> +  if (support_become_root ())
> +    printf ("info: acquired root-like privileges\n");
> +  if (support_enter_network_namespace ())
> +    printf ("info: entered network namespace\n");
> +  if (support_in_uts_namespace ())
> +    printf ("info: also entered UTS namespace\n");
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c
> new file mode 100644
> index 0000000..5672fba
> --- /dev/null
> +++ b/support/tst-support_capture_subprocess.c
> @@ -0,0 +1,188 @@
> +/* Test capturing output from a subprocess.
> +   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 <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <support/capture_subprocess.h>
> +#include <support/check.h>
> +#include <support/support.h>
> +#include <sys/wait.h>
> +#include <unistd.h>
> +
> +/* Write one byte at *P to FD and advance *P.  Do nothing if *P is
> +   '\0'.  */
> +static void
> +transfer (const unsigned char **p, int fd)
> +{
> +  if (**p != '\0')
> +    {
> +      TEST_VERIFY (write (fd, *p, 1) == 1);
> +      ++*p;
> +    }
> +}
> +
> +/* Determine the order in which stdout and stderr are written.  */
> +enum write_mode { out_first, err_first, interleave,
> +                  write_mode_last =  interleave };
> +
> +/* Describe what to write in the subprocess.  */
> +struct test
> +{
> +  char *out;
> +  char *err;
> +  enum write_mode write_mode;
> +  int signal;
> +  int status;
> +};
> +
> +/* For use with support_capture_subprocess.  */
> +static void
> +callback (void *closure)
> +{
> +  const struct test *test = closure;
> +  bool mode_ok = false;
> +  switch (test->write_mode)
> +    {
> +    case out_first:
> +      TEST_VERIFY (fputs (test->out, stdout) >= 0);
> +      TEST_VERIFY (fflush (stdout) == 0);
> +      TEST_VERIFY (fputs (test->err, stderr) >= 0);
> +      TEST_VERIFY (fflush (stderr) == 0);
> +      mode_ok = true;
> +      break;
> +    case err_first:
> +      TEST_VERIFY (fputs (test->err, stderr) >= 0);
> +      TEST_VERIFY (fflush (stderr) == 0);
> +      TEST_VERIFY (fputs (test->out, stdout) >= 0);
> +      TEST_VERIFY (fflush (stdout) == 0);
> +      mode_ok = true;
> +      break;
> +    case interleave:
> +      {
> +        const unsigned char *pout = (const unsigned char *) test->out;
> +        const unsigned char *perr = (const unsigned char *) test->err;
> +        do
> +          {
> +            transfer (&pout, STDOUT_FILENO);
> +            transfer (&perr, STDERR_FILENO);
> +          }
> +        while (*pout != '\0' || *perr != '\0');
> +      }
> +      mode_ok = true;
> +      break;
> +    }
> +  TEST_VERIFY (mode_ok);
> +
> +  if (test->signal != 0)
> +    raise (test->signal);
> +  exit (test->status);
> +}
> +
> +/* Create a heap-allocated random string of letters.  */
> +static char *
> +random_string (size_t length)
> +{
> +  char *result = xmalloc (length + 1);
> +  for (size_t i = 0; i < length; ++i)
> +    result[i] = 'a' + (rand () % 26);
> +  result[length] = '\0';
> +  return result;
> +}
> +
> +/* Check that the specific stream from the captured subprocess matches
> +   expectations.  */
> +static void
> +check_stream (const char *what, const struct xmemstream *stream,
> +              const char *expected)
> +{
> +  if (strcmp (stream->buffer, expected) != 0)
> +    {
> +      support_record_failure ();
> +      printf ("error: captured %s data incorrect\n"
> +              "  expected: %s\n"
> +              "  actual:   %s\n",
> +              what, expected, stream->buffer);
> +    }
> +  if (stream->length != strlen (expected))
> +    {
> +      support_record_failure ();
> +      printf ("error: captured %s data length incorrect\n"
> +              "  expected: %zu\n"
> +              "  actual:   %zu\n",
> +              what, strlen (expected), stream->length);
> +    }
> +}
> +
> +static int
> +do_test (void)
> +{
> +  const int lengths[] = {0, 1, 17, 512, 20000, -1};
> +
> +  /* Test multiple combinations of support_capture_subprocess.
> +
> +     length_idx_stdout: Index into the lengths array above,
> +       controls how many bytes are written by the subprocess to
> +       standard output.
> +     length_idx_stderr: Same for standard error.
> +     write_mode: How standard output and standard error writes are
> +       ordered.
> +     signal: Exit with no signal if zero, with SIGTERM if one.
> +     status: Process exit status: 0 if zero, 3 if one.  */
> +  for (int length_idx_stdout = 0; lengths[length_idx_stdout] >= 0;
> +       ++length_idx_stdout)
> +    for (int length_idx_stderr = 0; lengths[length_idx_stderr] >= 0;
> +         ++length_idx_stderr)
> +      for (int write_mode = 0; write_mode < write_mode_last; ++write_mode)
> +        for (int signal = 0; signal < 2; ++signal)
> +          for (int status = 0; status < 2; ++status)
> +            {
> +              struct test test =
> +                {
> +                  .out = random_string (lengths[length_idx_stdout]),
> +                  .err = random_string (lengths[length_idx_stderr]),
> +                  .write_mode = write_mode,
> +                  .signal = signal * SIGTERM, /* 0 or SIGTERM.  */
> +                  .status = status * 3,       /* 0 or 3.  */
> +                };
> +              TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]);
> +              TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]);
> +
> +              struct support_capture_subprocess result
> +                = support_capture_subprocess (callback, &test);
> +              check_stream ("stdout", &result.out, test.out);
> +              check_stream ("stderr", &result.err, test.err);
> +              if (test.signal != 0)
> +                {
> +                  TEST_VERIFY (WIFSIGNALED (result.status));
> +                  TEST_VERIFY (WTERMSIG (result.status) == test.signal);
> +                }
> +              else
> +                {
> +                  TEST_VERIFY (WIFEXITED (result.status));
> +                  TEST_VERIFY (WEXITSTATUS (result.status) == test.status);
> +                }
> +              support_capture_subprocess_free (&result);
> +              free (test.out);
> +              free (test.err);
> +            }
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/support/tst-support_format_dns_packet.c b/support/tst-support_format_dns_packet.c
> new file mode 100644
> index 0000000..9c8589c
> --- /dev/null
> +++ b/support/tst-support_format_dns_packet.c
> @@ -0,0 +1,101 @@
> +/* Tests for the support_format_dns_packet function.
> +   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/check.h>
> +#include <support/format_nss.h>
> +#include <support/run_diff.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +static void
> +check_packet (const void *buffer, size_t length,
> +              const char *name, const char *expected)
> +{
> +  char *actual = support_format_dns_packet (buffer, length);
> +  if (strcmp (actual, expected) != 0)
> +    {
> +      support_record_failure ();
> +      printf ("error: formatted packet does not match: %s\n", name);
> +      support_run_diff ("expected", expected,
> +                        "actual", actual);
> +    }
> +  free (actual);
> +}
> +
> +static void
> +test_aaaa_length (void)
> +{
> +  static const char packet[] =
> +    /* Header: Response with two records.  */
> +    "\x12\x34\x80\x00\x00\x01\x00\x02\x00\x00\x00\x00"
> +    /* Question section.  www.example/IN/AAAA.  */
> +    "\x03www\x07""example\x00\x00\x1c\x00\x01"
> +    /* Answer section.  www.example AAAA [corrupted].  */
> +    "\xc0\x0c"
> +    "\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x10"
> +    "\x20\x01\x0d\xb8\x05\x06\x07\x08"
> +    "\x11\x12\x13\x14\x15\x16\x17\x18"
> +    /* www.example AAAA [corrupted].  */
> +    "\xc0\x0c"
> +    "\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x11"
> +    "\x01\x02\x03\x04\x05\x06\x07\x08"
> +    "\x11\x12\x13\x14\x15\x16\x17\x18" "\xff";
> +  check_packet (packet, sizeof (packet) - 1, __func__,
> +                "name: www.example\n"
> +                "address: 2001:db8:506:708:1112:1314:1516:1718\n"
> +                "error: AAAA record of size 17: www.example\n");
> +}
> +
> +static void
> +test_multiple_cnames (void)
> +{
> +  static const char packet[] =
> +    /* Header: Response with three records.  */
> +    "\x12\x34\x80\x00\x00\x01\x00\x03\x00\x00\x00\x00"
> +    /* Question section.  www.example/IN/A.  */
> +    "\x03www\x07""example\x00\x00\x01\x00\x01"
> +    /* Answer section.  www.example CNAME www1.example.  */
> +    "\xc0\x0c"
> +    "\x00\x05\x00\x01\x00\x00\x00\x00\x00\x07"
> +    "\x04www1\xc0\x10"
> +    /* www1 CNAME www2.  */
> +    "\x04www1\xc0\x10"
> +    "\x00\x05\x00\x01\x00\x00\x00\x00\x00\x07"
> +    "\x04www2\xc0\x10"
> +    /* www2 A 192.0.2.1.  */
> +    "\x04www2\xc0\x10"
> +    "\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04"
> +    "\xc0\x00\x02\x01";
> +  check_packet (packet, sizeof (packet) - 1, __func__,
> +                "name: www.example\n"
> +                "name: www1.example\n"
> +                "name: www2.example\n"
> +                "address: 192.0.2.1\n");
> +}
> +
> +static int
> +do_test (void)
> +{
> +  test_aaaa_length ();
> +  test_multiple_cnames ();
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/support/tst-support_record_failure-2.sh b/support/tst-support_record_failure-2.sh
> new file mode 100644
> index 0000000..2c9372c
> --- /dev/null
> +++ b/support/tst-support_record_failure-2.sh
> @@ -0,0 +1,69 @@
> +#!/bin/sh
> +# Test failure recording (with and without --direct).
> +# 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/>.  */
> +
> +set -e
> +
> +common_objpfx=$1; shift
> +test_program_prefix_before_env=$1; shift
> +run_program_env=$1; shift
> +test_program_prefix_after_env=$1; shift
> +
> +run_test () {
> +    expected_status="$1"
> +    expected_output="$2"
> +    shift 2
> +    args="${common_objpfx}support/tst-support_record_failure $*"
> +    echo "running: $args"
> +    set +e
> +    output="$(${test_program_prefix_before_env} \
> +		 ${run_program} ${test_program_prefix_after_env} $args)"
> +    status=$?
> +    set -e
> +    echo "  exit status: $status"
> +    if test "$output" != "$expected_output" ; then
> +	echo "error: unexpected output: $output"
> +	exit 1
> +    fi
> +    if test "$status" -ne "$expected_status" ; then
> +	echo "error: exit status $expected_status expected"
> +	exit 1
> +    fi
> +}
> +
> +different_status () {
> +    direct="$1"
> +    run_test 1 "error: 1 test failures" $direct --status=0
> +    run_test 1 "error: 1 test failures" $direct --status=1
> +    run_test 2 "error: 1 test failures" $direct --status=2
> +    run_test 1 "error: 1 test failures" $direct --status=77
> +    run_test 2 "error: tst-support_record_failure.c:109: not true: false
> +error: 1 test failures" $direct --test-verify
> +    run_test 2 "error: tst-support_record_failure.c:109: not true: false
> +info: execution passed failed TEST_VERIFY
> +error: 1 test failures" $direct --test-verify --verbose
> +}
> +
> +different_status
> +different_status --direct
> +
> +run_test 1 "error: tst-support_record_failure.c:116: not true: false
> +error: 1 test failures" --test-verify-exit
> +# --direct does not print the summary error message if exit is called.
> +run_test 1 "error: tst-support_record_failure.c:116: not true: false" \
> +	 --direct --test-verify-exit
> diff --git a/support/tst-support_record_failure.c b/support/tst-support_record_failure.c
> new file mode 100644
> index 0000000..e739e73
> --- /dev/null
> +++ b/support/tst-support_record_failure.c
> @@ -0,0 +1,153 @@
> +/* Test support_record_failure state sharing.
> +   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/check.h>
> +#include <support/support.h>
> +#include <support/test-driver.h>
> +#include <support/xunistd.h>
> +
> +#include <getopt.h>
> +#include <stdbool.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +
> +static int exit_status_with_failure = -1;
> +static bool test_verify;
> +static bool test_verify_exit;
> +enum
> +  {
> +    OPT_STATUS = 10001,
> +    OPT_TEST_VERIFY,
> +    OPT_TEST_VERIFY_EXIT,
> +  };
> +#define CMDLINE_OPTIONS                                                 \
> +  { "status", required_argument, NULL, OPT_STATUS },                    \
> +  { "test-verify", no_argument, NULL, OPT_TEST_VERIFY },                \
> +  { "test-verify-exit", no_argument, NULL, OPT_TEST_VERIFY_EXIT },
> +static void
> +cmdline_process (int c)
> +{
> +  switch (c)
> +    {
> +    case OPT_STATUS:
> +      exit_status_with_failure = atoi (optarg);
> +      break;
> +    case OPT_TEST_VERIFY:
> +      test_verify = true;
> +      break;
> +    case OPT_TEST_VERIFY_EXIT:
> +      test_verify_exit = true;
> +      break;
> +    }
> +}
> +#define CMDLINE_PROCESS cmdline_process
> +
> +static void
> +check_failure_reporting (int phase, int zero, int unsupported)
> +{
> +  int status = support_report_failure (0);
> +  if (status != zero)
> +    {
> +      printf ("real-error (phase %d): support_report_failure (0) == %d\n",
> +              phase, status);
> +      exit (1);
> +    }
> +  status = support_report_failure (1);
> +  if (status != 1)
> +    {
> +      printf ("real-error (phase %d): support_report_failure (1) == %d\n",
> +              phase, status);
> +      exit (1);
> +    }
> +  status = support_report_failure (2);
> +  if (status != 2)
> +    {
> +      printf ("real-error (phase %d): support_report_failure (2) == %d\n",
> +              phase, status);
> +      exit (1);
> +    }
> +  status = support_report_failure (EXIT_UNSUPPORTED);
> +  if (status != unsupported)
> +    {
> +      printf ("real-error (phase %d): "
> +              "support_report_failure (EXIT_UNSUPPORTED) == %d\n",
> +              phase, status);
> +      exit (1);
> +    }
> +}
> +
> +static int
> +do_test (void)
> +{
> +  if (exit_status_with_failure >= 0)
> +    {
> +      /* External invocation with requested error status.  Used by
> +         tst-support_report_failure-2.sh.  */
> +      support_record_failure ();
> +      return exit_status_with_failure;
> +    }
> +  TEST_VERIFY (true);
> +  TEST_VERIFY_EXIT (true);
> +  if (test_verify)
> +    {
> +      TEST_VERIFY (false);
> +      if (test_verbose)
> +        printf ("info: execution passed failed TEST_VERIFY\n");
> +      return 2; /* Expected exit status.  */
> +    }
> +  if (test_verify_exit)
> +    {
> +      TEST_VERIFY_EXIT (false);
> +      return 3; /* Not reached.  Expected exit status is 1.  */
> +    }
> +
> +  printf ("info: This test tests the test framework.\n"
> +          "info: It reports some expected errors on stdout.\n");
> +
> +  /* Check that the status is passed through unchanged.  */
> +  check_failure_reporting (1, 0, EXIT_UNSUPPORTED);
> +
> +  /* Check state propagation from a subprocess.  */
> +  pid_t pid = xfork ();
> +  if (pid == 0)
> +    {
> +      support_record_failure ();
> +      _exit (0);
> +    }
> +  int status;
> +  xwaitpid (pid, &status, 0);
> +  if (status != 0)
> +    {
> +      printf ("real-error: incorrect status from subprocess: %d\n", status);
> +      return 1;
> +    }
> +  check_failure_reporting (2, 1, 1);
> +
> +  /* Also test directly in the parent process.  */
> +  support_record_failure_reset ();
> +  check_failure_reporting (3, 0, EXIT_UNSUPPORTED);
> +  support_record_failure ();
> +  check_failure_reporting (4, 1, 1);
> +
> +  /* We need to mask the failure above.  */
> +  support_record_failure_reset ();
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/support/write_message.c b/support/write_message.c
> new file mode 100644
> index 0000000..f03ed93
> --- /dev/null
> +++ b/support/write_message.c
> @@ -0,0 +1,29 @@
> +/* Write a message to standard output.
> +   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>
> +#include <unistd.h>
> +
> +void
> +write_message (const char *message)
> +{
> +  ssize_t unused __attribute__ ((unused));
> +  unused = write (STDOUT_FILENO, message, strlen (message));
> +}
> diff --git a/support/xaccept.c b/support/xaccept.c
> new file mode 100644
> index 0000000..7b25af3
> --- /dev/null
> +++ b/support/xaccept.c
> @@ -0,0 +1,32 @@
> +/* accept 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/xsocket.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +
> +int
> +xaccept (int fd, struct sockaddr *sa, socklen_t *salen)
> +{
> +  int clientfd = accept (fd, sa, salen);
> +  if (clientfd < 0)
> +    FAIL_EXIT1 ("accept (%d): %m", fd);
> +  return clientfd;
> +}
> diff --git a/support/xaccept4.c b/support/xaccept4.c
> new file mode 100644
> index 0000000..67dd95e
> --- /dev/null
> +++ b/support/xaccept4.c
> @@ -0,0 +1,32 @@
> +/* accept4 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/xsocket.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +
> +int
> +xaccept4 (int fd, struct sockaddr *sa, socklen_t *salen, int flags)
> +{
> +  int clientfd = accept4 (fd, sa, salen, flags);
> +  if (clientfd < 0)
> +    FAIL_EXIT1 ("accept4 (%d, 0x%x): %m", fd, flags);
> +  return clientfd;
> +}
> diff --git a/support/xasprintf.c b/support/xasprintf.c
> new file mode 100644
> index 0000000..5157680
> --- /dev/null
> +++ b/support/xasprintf.c
> @@ -0,0 +1,36 @@
> +/* Error-checking wrapper for asprintf.
> +   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 <stdarg.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +
> +char *
> +xasprintf (const char *format, ...)
> +{
> +  va_list ap;
> +  va_start (ap, format);
> +  char *result;
> +  if (vasprintf (&result, format, ap) < 0)
> +    FAIL_EXIT1 ("asprintf: %m");
> +  va_end (ap);
> +  return result;
> +}
> diff --git a/support/xbind.c b/support/xbind.c
> new file mode 100644
> index 0000000..cfc6dd8
> --- /dev/null
> +++ b/support/xbind.c
> @@ -0,0 +1,30 @@
> +/* bind 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/xsocket.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +
> +void
> +xbind (int fd, const struct sockaddr *sa, socklen_t sa_len)
> +{
> +  if (bind (fd, sa, sa_len) != 0)
> +    FAIL_EXIT1 ("bind (%d), family %d: %m", fd, sa->sa_family);
> +}
> diff --git a/support/xcalloc.c b/support/xcalloc.c
> new file mode 100644
> index 0000000..135f42d
> --- /dev/null
> +++ b/support/xcalloc.c
> @@ -0,0 +1,34 @@
> +/* Error-checking wrapper for calloc.
> +   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 <stdarg.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +void *
> +xcalloc (size_t n, size_t s)
> +{
> +  void *p;
> +
> +  p = calloc (n, s);
> +  if (p == NULL)
> +    oom_error ("calloc", n * s);
> +  return p;
> +}
> diff --git a/support/xchroot.c b/support/xchroot.c
> new file mode 100644
> index 0000000..abcc299
> --- /dev/null
> +++ b/support/xchroot.c
> @@ -0,0 +1,28 @@
> +/* chroot 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
> +xchroot (const char *path)
> +{
> +  if (chroot (path) != 0)
> +    FAIL_EXIT1 ("chroot (\"%s\"): %m", path);
> +}
> diff --git a/support/xclose.c b/support/xclose.c
> new file mode 100644
> index 0000000..c931e08
> --- /dev/null
> +++ b/support/xclose.c
> @@ -0,0 +1,28 @@
> +/* close 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/xunistd.h>
> +#include <support/check.h>
> +#include <errno.h>
> +
> +void
> +xclose (int fd)
> +{
> +  if (close (fd) < 0 && errno != EINTR)
> +    FAIL_EXIT1 ("close of descriptor %d failed: %m", fd);
> +}
> diff --git a/support/xconnect.c b/support/xconnect.c
> new file mode 100644
> index 0000000..0266dbc
> --- /dev/null
> +++ b/support/xconnect.c
> @@ -0,0 +1,30 @@
> +/* connect 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/xsocket.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +
> +void
> +xconnect (int fd, const struct sockaddr *sa, socklen_t sa_len)
> +{
> +  if (connect (fd, sa, sa_len) != 0)
> +    FAIL_EXIT1 ("connect (%d), family %d: %m", fd, sa->sa_family);
> +}
> diff --git a/support/xdup2.c b/support/xdup2.c
> new file mode 100644
> index 0000000..dc08c94
> --- /dev/null
> +++ b/support/xdup2.c
> @@ -0,0 +1,28 @@
> +/* dup2 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/xunistd.h>
> +
> +#include <support/check.h>
> +
> +void
> +xdup2 (int from, int to)
> +{
> +  if (dup2 (from, to) < 0)
> +    FAIL_EXIT1 ("dup2 (%d, %d): %m", from, to);
> +}
> diff --git a/support/xfclose.c b/support/xfclose.c
> new file mode 100644
> index 0000000..2737f05
> --- /dev/null
> +++ b/support/xfclose.c
> @@ -0,0 +1,33 @@
> +/* fclose 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/xstdio.h>
> +
> +#include <support/check.h>
> +#include <stdlib.h>
> +
> +void
> +xfclose (FILE *fp)
> +{
> +  if (ferror (fp))
> +    FAIL_EXIT1 ("stdio stream closed with pending errors");
> +  if (fflush (fp) != 0)
> +    FAIL_EXIT1 ("fflush: %m");
> +  if (fclose (fp) != 0)
> +    FAIL_EXIT1 ("fclose: %m");
> +}
> diff --git a/support/xfopen.c b/support/xfopen.c
> new file mode 100644
> index 0000000..14532a0
> --- /dev/null
> +++ b/support/xfopen.c
> @@ -0,0 +1,31 @@
> +/* fopen 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/xstdio.h>
> +
> +#include <support/check.h>
> +#include <stdlib.h>
> +
> +FILE *
> +xfopen (const char *path, const char *mode)
> +{
> +  FILE *fp = fopen (path, mode);
> +  if (fp == NULL)
> +    FAIL_EXIT1 ("could not open %s (mode \"%s\"): %m", path, mode);
> +  return fp;
> +}
> diff --git a/support/xfork.c b/support/xfork.c
> new file mode 100644
> index 0000000..aa52ba6
> --- /dev/null
> +++ b/support/xfork.c
> @@ -0,0 +1,32 @@
> +/* fork 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/xunistd.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +
> +pid_t
> +xfork (void)
> +{
> +  pid_t result = fork ();
> +  if (result < 0)
> +    FAIL_EXIT1 ("fork: %m");
> +  return result;
> +}
> diff --git a/support/xgetsockname.c b/support/xgetsockname.c
> new file mode 100644
> index 0000000..c3bd884
> --- /dev/null
> +++ b/support/xgetsockname.c
> @@ -0,0 +1,30 @@
> +/* getsockname 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/xsocket.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +
> +void
> +xgetsockname (int fd, struct sockaddr *sa, socklen_t *plen)
> +{
> +  if (getsockname (fd, sa, plen) != 0)
> +    FAIL_EXIT1 ("setsockopt (%d): %m", fd);
> +}
> diff --git a/support/xlisten.c b/support/xlisten.c
> new file mode 100644
> index 0000000..1953e59
> --- /dev/null
> +++ b/support/xlisten.c
> @@ -0,0 +1,30 @@
> +/* listen 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/xsocket.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +
> +void
> +xlisten (int fd, int backlog)
> +{
> +  if (listen (fd, backlog) != 0)
> +    FAIL_EXIT1 ("listen (%d, %d): %m", fd, backlog);
> +}
> diff --git a/support/xmalloc.c b/support/xmalloc.c
> new file mode 100644
> index 0000000..450f699
> --- /dev/null
> +++ b/support/xmalloc.c
> @@ -0,0 +1,34 @@
> +/* Error-checking wrapper for malloc.
> +   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 <stdarg.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +void *
> +xmalloc (size_t n)
> +{
> +  void *p;
> +
> +  p = malloc (n);
> +  if (p == NULL)
> +    oom_error ("malloc", n);
> +  return p;
> +}
> diff --git a/support/xmemstream.c b/support/xmemstream.c
> new file mode 100644
> index 0000000..bce6dc9
> --- /dev/null
> +++ b/support/xmemstream.c
> @@ -0,0 +1,42 @@
> +/* Error-checking wrappers for memstream functions.
> +   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/xmemstream.h>
> +
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <support/xstdio.h>
> +
> +void
> +xopen_memstream (struct xmemstream *stream)
> +{
> +  int old_errno = errno;
> +  *stream = (struct xmemstream) {};
> +  stream->out = open_memstream (&stream->buffer, &stream->length);
> +  if (stream->out == NULL)
> +    FAIL_EXIT1 ("open_memstream: %m");
> +  errno = old_errno;
> +}
> +
> +void
> +xfclose_memstream (struct xmemstream *stream)
> +{
> +  xfclose (stream->out);
> +  stream->out = NULL;
> +}
> diff --git a/support/xmemstream.h b/support/xmemstream.h
> new file mode 100644
> index 0000000..e5ba231
> --- /dev/null
> +++ b/support/xmemstream.h
> @@ -0,0 +1,49 @@
> +/* Error-checking wrappers for memstream functions.
> +   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/>.  */
> +
> +#ifndef SUPPORT_XMEMSTREAM_H
> +#define SUPPORT_XMEMSTREAM_H
> +
> +#include <stdio.h>
> +#include <sys/cdefs.h>
> +
> +__BEGIN_DECLS
> +
> +/* Wrappers for other libc functions.  */
> +struct xmemstream
> +{
> +  FILE *out;
> +  char *buffer;
> +  size_t length;
> +};
> +
> +/* Create a new in-memory stream.  Initializes *STREAM.  After this
> +   function returns, STREAM->out is a file descriptor open for
> +   writing.  errno is preserved, so that the %m format specifier can
> +   be used for writing to STREAM->out.  */
> +void xopen_memstream (struct xmemstream *stream);
> +
> +/* Closes STREAM->OUT.  After this function returns, STREAM->buffer
> +   and STREAM->length denote a memory range which contains the bytes
> +   written to the output stream.  The caller should free
> +   STREAM->buffer.  */
> +void xfclose_memstream (struct xmemstream *stream);
> +
> +__END_DECLS
> +
> +#endif /* SUPPORT_XMEMSTREAM_H */
> diff --git a/support/xmkdir.c b/support/xmkdir.c
> new file mode 100644
> index 0000000..ea17d49
> --- /dev/null
> +++ b/support/xmkdir.c
> @@ -0,0 +1,28 @@
> +/* mkdir 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
> +xmkdir (const char *path, mode_t mode)
> +{
> +  if (mkdir (path, mode) != 0)
> +    FAIL_EXIT1 ("mkdir (\"%s\", 0%o): %m", path, mode);
> +}
> diff --git a/support/xmmap.c b/support/xmmap.c
> new file mode 100644
> index 0000000..435b1eb
> --- /dev/null
> +++ b/support/xmmap.c
> @@ -0,0 +1,31 @@
> +/* mmap 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/check.h>
> +#include <support/xunistd.h>
> +#include <sys/mman.h>
> +
> +void *
> +xmmap (void *addr, size_t length, int prot, int flags, int fd)
> +{
> +  void *result = mmap (addr, length, prot, flags, fd, 0);
> +  if (result == MAP_FAILED)
> +    FAIL_EXIT1 ("mmap of %zu bytes, prot=0x%x, flags=0x%x: %m",
> +                length, prot, flags);
> +  return result;
> +}
> diff --git a/support/xmunmap.c b/support/xmunmap.c
> new file mode 100644
> index 0000000..6ef5a4a
> --- /dev/null
> +++ b/support/xmunmap.c
> @@ -0,0 +1,28 @@
> +/* munmap 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/check.h>
> +#include <support/xunistd.h>
> +#include <sys/mman.h>
> +
> +void
> +xmunmap (void *addr, size_t length)
> +{
> +  if (munmap (addr, length) != 0)
> +    FAIL_EXIT1 ("munmap of %zu bytes: %m", length);
> +}
> diff --git a/support/xopen.c b/support/xopen.c
> new file mode 100644
> index 0000000..7f033a0
> --- /dev/null
> +++ b/support/xopen.c
> @@ -0,0 +1,30 @@
> +/* open64 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 <fcntl.h>
> +
> +int
> +xopen (const char *path, int flags, mode_t mode)
> +{
> +  int ret = open64 (path, flags, mode);
> +  if (ret < 0)
> +    FAIL_EXIT1 ("open64 (\"%s\", 0x%x, 0%o): %m", path, flags, mode);
> +  return ret;
> +}
> diff --git a/support/xpipe.c b/support/xpipe.c
> new file mode 100644
> index 0000000..89a64a5
> --- /dev/null
> +++ b/support/xpipe.c
> @@ -0,0 +1,28 @@
> +/* pipe 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/xunistd.h>
> +
> +#include <support/check.h>
> +
> +void
> +xpipe (int fds[2])
> +{
> +  if (pipe (fds) < 0)
> +    FAIL_EXIT1 ("pipe: %m");
> +}
> diff --git a/support/xpoll.c b/support/xpoll.c
> new file mode 100644
> index 0000000..bec2521
> --- /dev/null
> +++ b/support/xpoll.c
> @@ -0,0 +1,32 @@
> +/* poll 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/xsocket.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +
> +int
> +xpoll (struct pollfd *fds, nfds_t nfds, int timeout)
> +{
> +  int ret = poll (fds, nfds, timeout);
> +  if (ret < 0)
> +    FAIL_EXIT1 ("poll: %m");
> +  return ret;
> +}
> diff --git a/support/xpthread_attr_destroy.c b/support/xpthread_attr_destroy.c
> new file mode 100644
> index 0000000..664c809
> --- /dev/null
> +++ b/support/xpthread_attr_destroy.c
> @@ -0,0 +1,26 @@
> +/* pthread_attr_destroy 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/xthread.h>
> +
> +void
> +xpthread_attr_destroy (pthread_attr_t *attr)
> +{
> +  xpthread_check_return ("pthread_attr_destroy",
> +			 pthread_attr_destroy (attr));
> +}
> diff --git a/support/xpthread_attr_init.c b/support/xpthread_attr_init.c
> new file mode 100644
> index 0000000..2e30ade
> --- /dev/null
> +++ b/support/xpthread_attr_init.c
> @@ -0,0 +1,25 @@
> +/* pthread_attr_init 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/xthread.h>
> +
> +void
> +xpthread_attr_init (pthread_attr_t *attr)
> +{
> +  xpthread_check_return ("pthread_attr_init", pthread_attr_init (attr));
> +}
> diff --git a/support/xpthread_attr_setdetachstate.c b/support/xpthread_attr_setdetachstate.c
> new file mode 100644
> index 0000000..b544dba
> --- /dev/null
> +++ b/support/xpthread_attr_setdetachstate.c
> @@ -0,0 +1,27 @@
> +/* pthread_attr_setdetachstate 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/xthread.h>
> +
> +void
> +xpthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate)
> +{
> +  xpthread_check_return ("pthread_attr_setdetachstate",
> +			 pthread_attr_setdetachstate (attr,
> +						      detachstate));
> +}
> diff --git a/support/xpthread_attr_setstacksize.c b/support/xpthread_attr_setstacksize.c
> new file mode 100644
> index 0000000..02d0631
> --- /dev/null
> +++ b/support/xpthread_attr_setstacksize.c
> @@ -0,0 +1,26 @@
> +/* pthread_attr_setstacksize 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/xthread.h>
> +
> +void
> +xpthread_attr_setstacksize (pthread_attr_t *attr, size_t stacksize)
> +{
> +  xpthread_check_return ("pthread_attr_setstacksize",
> +			 pthread_attr_setstacksize (attr, stacksize));
> +}
> diff --git a/support/xpthread_barrier_destroy.c b/support/xpthread_barrier_destroy.c
> new file mode 100644
> index 0000000..efc0719
> --- /dev/null
> +++ b/support/xpthread_barrier_destroy.c
> @@ -0,0 +1,26 @@
> +/* pthread_barrier_destroy 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/xthread.h>
> +
> +void
> +xpthread_barrier_destroy (pthread_barrier_t *barrier)
> +{
> +  xpthread_check_return ("pthread_barrier_destroy",
> +                         pthread_barrier_destroy (barrier));
> +}
> diff --git a/support/xpthread_barrier_init.c b/support/xpthread_barrier_init.c
> new file mode 100644
> index 0000000..b32dad1
> --- /dev/null
> +++ b/support/xpthread_barrier_init.c
> @@ -0,0 +1,27 @@
> +/* pthread_barrier_init 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/xthread.h>
> +
> +void
> +xpthread_barrier_init (pthread_barrier_t *barrier,
> +                       pthread_barrierattr_t *attr, unsigned int count)
> +{
> +  xpthread_check_return ("pthread_barrier_init",
> +                         pthread_barrier_init (barrier, attr, count));
> +}
> diff --git a/support/xpthread_barrier_wait.c b/support/xpthread_barrier_wait.c
> new file mode 100644
> index 0000000..7cee44d
> --- /dev/null
> +++ b/support/xpthread_barrier_wait.c
> @@ -0,0 +1,28 @@
> +/* pthread_barrier_wait 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/xthread.h>
> +
> +int
> +xpthread_barrier_wait (pthread_barrier_t *barrier)
> +{
> +  int ret = pthread_barrier_wait (barrier);
> +  if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
> +    xpthread_check_return ("pthread_barrier_wait", ret);
> +  return ret == PTHREAD_BARRIER_SERIAL_THREAD;
> +}
> diff --git a/support/xpthread_cancel.c b/support/xpthread_cancel.c
> new file mode 100644
> index 0000000..3af16f9
> --- /dev/null
> +++ b/support/xpthread_cancel.c
> @@ -0,0 +1,25 @@
> +/* pthread_cancel 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/xthread.h>
> +
> +void
> +xpthread_cancel (pthread_t thr)
> +{
> +  xpthread_check_return ("pthread_cancel", pthread_cancel (thr));
> +}
> diff --git a/support/xpthread_check_return.c b/support/xpthread_check_return.c
> new file mode 100644
> index 0000000..3094d82
> --- /dev/null
> +++ b/support/xpthread_check_return.c
> @@ -0,0 +1,34 @@
> +/* Return value checking for pthread functions, exit variant.
> +   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/xthread.h>
> +
> +#include <errno.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +
> +void
> +xpthread_check_return (const char *function, int value)
> +{
> +  if (value != 0)
> +    {
> +      errno = value;
> +      FAIL_EXIT1 ("%s: %m", function);
> +    }
> +}
> diff --git a/support/xpthread_cond_wait.c b/support/xpthread_cond_wait.c
> new file mode 100644
> index 0000000..b0e9b2a
> --- /dev/null
> +++ b/support/xpthread_cond_wait.c
> @@ -0,0 +1,26 @@
> +/* pthread_cond_wait 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/xthread.h>
> +
> +void
> +xpthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
> +{
> +  xpthread_check_return
> +    ("pthread_cond_wait", pthread_cond_wait (cond, mutex));
> +}
> diff --git a/support/xpthread_create.c b/support/xpthread_create.c
> new file mode 100644
> index 0000000..98c63e5
> --- /dev/null
> +++ b/support/xpthread_create.c
> @@ -0,0 +1,29 @@
> +/* pthread_create 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/xthread.h>
> +
> +pthread_t
> +xpthread_create (pthread_attr_t *attr,
> +                 void *(*thread_func) (void *), void *closure)
> +{
> +  pthread_t thr;
> +  xpthread_check_return
> +    ("pthread_create", pthread_create (&thr, attr, thread_func, closure));
> +  return thr;
> +}
> diff --git a/support/xpthread_detach.c b/support/xpthread_detach.c
> new file mode 100644
> index 0000000..2088af2
> --- /dev/null
> +++ b/support/xpthread_detach.c
> @@ -0,0 +1,25 @@
> +/* pthread_detach 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/xthread.h>
> +
> +void
> +xpthread_detach (pthread_t thr)
> +{
> +  xpthread_check_return ("pthread_detach", pthread_detach (thr));
> +}
> diff --git a/support/xpthread_join.c b/support/xpthread_join.c
> new file mode 100644
> index 0000000..f23bb9a
> --- /dev/null
> +++ b/support/xpthread_join.c
> @@ -0,0 +1,27 @@
> +/* pthread_join 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/xthread.h>
> +
> +void *
> +xpthread_join (pthread_t thr)
> +{
> +  void *result;
> +  xpthread_check_return ("pthread_join", pthread_join (thr, &result));
> +  return result;
> +}
> diff --git a/support/xpthread_mutex_consistent.c b/support/xpthread_mutex_consistent.c
> new file mode 100644
> index 0000000..52364be
> --- /dev/null
> +++ b/support/xpthread_mutex_consistent.c
> @@ -0,0 +1,26 @@
> +/* pthread_mutex_consistent 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/xthread.h>
> +
> +void
> +xpthread_mutex_consistent (pthread_mutex_t *mutex)
> +{
> +  xpthread_check_return ("pthread_mutex_consistent",
> +                         pthread_mutex_consistent (mutex));
> +}
> diff --git a/support/xpthread_mutex_destroy.c b/support/xpthread_mutex_destroy.c
> new file mode 100644
> index 0000000..f11f8f0
> --- /dev/null
> +++ b/support/xpthread_mutex_destroy.c
> @@ -0,0 +1,26 @@
> +/* pthread_mutex_destroy 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/xthread.h>
> +
> +void
> +xpthread_mutex_destroy (pthread_mutex_t *mutex)
> +{
> +  xpthread_check_return ("pthread_mutex_destroy",
> +                         pthread_mutex_destroy (mutex));
> +}
> diff --git a/support/xpthread_mutex_init.c b/support/xpthread_mutex_init.c
> new file mode 100644
> index 0000000..2d16d1b
> --- /dev/null
> +++ b/support/xpthread_mutex_init.c
> @@ -0,0 +1,26 @@
> +/* pthread_mutex_init 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/xthread.h>
> +
> +void
> +xpthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
> +{
> +  xpthread_check_return ("pthread_mutex_init",
> +                         pthread_mutex_init (mutex, attr));
> +}
> diff --git a/support/xpthread_mutex_lock.c b/support/xpthread_mutex_lock.c
> new file mode 100644
> index 0000000..af727b4
> --- /dev/null
> +++ b/support/xpthread_mutex_lock.c
> @@ -0,0 +1,25 @@
> +/* pthread_mutex_lock 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/xthread.h>
> +
> +void
> +xpthread_mutex_lock (pthread_mutex_t *mutex)
> +{
> +  xpthread_check_return ("pthread_mutex_lock", pthread_mutex_lock (mutex));
> +}
> diff --git a/support/xpthread_mutex_unlock.c b/support/xpthread_mutex_unlock.c
> new file mode 100644
> index 0000000..161b41e
> --- /dev/null
> +++ b/support/xpthread_mutex_unlock.c
> @@ -0,0 +1,25 @@
> +/* pthread_mutex_unlock 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/xthread.h>
> +
> +void
> +xpthread_mutex_unlock (pthread_mutex_t *mutex)
> +{
> +  xpthread_check_return ("pthread_mutex_unlock", pthread_mutex_unlock (mutex));
> +}
> diff --git a/support/xpthread_mutexattr_destroy.c b/support/xpthread_mutexattr_destroy.c
> new file mode 100644
> index 0000000..c699e32
> --- /dev/null
> +++ b/support/xpthread_mutexattr_destroy.c
> @@ -0,0 +1,26 @@
> +/* pthread_mutexattr_destroy 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/xthread.h>
> +
> +void
> +xpthread_mutexattr_destroy (pthread_mutexattr_t *attr)
> +{
> +  xpthread_check_return ("pthread_mutexattr_destroy",
> +                         pthread_mutexattr_destroy (attr));
> +}
> diff --git a/support/xpthread_mutexattr_init.c b/support/xpthread_mutexattr_init.c
> new file mode 100644
> index 0000000..fa93fab
> --- /dev/null
> +++ b/support/xpthread_mutexattr_init.c
> @@ -0,0 +1,25 @@
> +/* pthread_mutexattr_init 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/xthread.h>
> +
> +void
> +xpthread_mutexattr_init (pthread_mutexattr_t *attr)
> +{
> +  xpthread_check_return ("pthread_mutexattr_init", pthread_mutexattr_init (attr));
> +}
> diff --git a/support/xpthread_mutexattr_setprotocol.c b/support/xpthread_mutexattr_setprotocol.c
> new file mode 100644
> index 0000000..353f75e
> --- /dev/null
> +++ b/support/xpthread_mutexattr_setprotocol.c
> @@ -0,0 +1,26 @@
> +/* pthread_mutexattr_setprotocol 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/xthread.h>
> +
> +void
> +xpthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int flag)
> +{
> +  xpthread_check_return ("pthread_mutexattr_setprotocol",
> +                         pthread_mutexattr_setprotocol (attr, flag));
> +}
> diff --git a/support/xpthread_mutexattr_setpshared.c b/support/xpthread_mutexattr_setpshared.c
> new file mode 100644
> index 0000000..242da1a
> --- /dev/null
> +++ b/support/xpthread_mutexattr_setpshared.c
> @@ -0,0 +1,26 @@
> +/* pthread_mutexattr_setpshared 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/xthread.h>
> +
> +void
> +xpthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int flag)
> +{
> +  xpthread_check_return ("pthread_mutexattr_setpshared",
> +                         pthread_mutexattr_setpshared (attr, flag));
> +}
> diff --git a/support/xpthread_mutexattr_setrobust.c b/support/xpthread_mutexattr_setrobust.c
> new file mode 100644
> index 0000000..d7d6fa8
> --- /dev/null
> +++ b/support/xpthread_mutexattr_setrobust.c
> @@ -0,0 +1,26 @@
> +/* pthread_mutexattr_setrobust 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/xthread.h>
> +
> +void
> +xpthread_mutexattr_setrobust (pthread_mutexattr_t *attr, int flag)
> +{
> +  xpthread_check_return ("pthread_mutexattr_setrobust",
> +                         pthread_mutexattr_setrobust (attr, flag));
> +}
> diff --git a/support/xpthread_mutexattr_settype.c b/support/xpthread_mutexattr_settype.c
> new file mode 100644
> index 0000000..cf22170
> --- /dev/null
> +++ b/support/xpthread_mutexattr_settype.c
> @@ -0,0 +1,26 @@
> +/* pthread_mutexattr_settype 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/xthread.h>
> +
> +void
> +xpthread_mutexattr_settype (pthread_mutexattr_t *attr, int flag)
> +{
> +  xpthread_check_return ("pthread_mutexattr_settype",
> +                         pthread_mutexattr_settype (attr, flag));
> +}
> diff --git a/support/xpthread_once.c b/support/xpthread_once.c
> new file mode 100644
> index 0000000..70d58db
> --- /dev/null
> +++ b/support/xpthread_once.c
> @@ -0,0 +1,25 @@
> +/* pthread_once 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/xthread.h>
> +
> +void
> +xpthread_once (pthread_once_t *guard, void (*func) (void))
> +{
> +  xpthread_check_return ("pthread_once", pthread_once (guard, func));
> +}
> diff --git a/support/xpthread_sigmask.c b/support/xpthread_sigmask.c
> new file mode 100644
> index 0000000..0ba9ca0
> --- /dev/null
> +++ b/support/xpthread_sigmask.c
> @@ -0,0 +1,34 @@
> +/* pthread_sigmask 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/xsignal.h>
> +#include <support/support.h>
> +
> +#include <unistd.h>
> +
> +void
> +xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset)
> +{
> +  if (pthread_sigmask (how, set, oldset) != 0)
> +    {
> +      write_message ("error: pthread_setmask failed\n");
> +      /* Do not use exit because pthread_sigmask can be called from a
> +         signal handler.  */
> +      _exit (1);
> +    }
> +}
> diff --git a/support/xpthread_spin_lock.c b/support/xpthread_spin_lock.c
> new file mode 100644
> index 0000000..6975215
> --- /dev/null
> +++ b/support/xpthread_spin_lock.c
> @@ -0,0 +1,25 @@
> +/* pthread_spin_lock 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/xthread.h>
> +
> +void
> +xpthread_spin_lock (pthread_spinlock_t *lock)
> +{
> +  xpthread_check_return ("pthread_spin_lock", pthread_spin_lock (lock));
> +}
> diff --git a/support/xpthread_spin_unlock.c b/support/xpthread_spin_unlock.c
> new file mode 100644
> index 0000000..4f19a44
> --- /dev/null
> +++ b/support/xpthread_spin_unlock.c
> @@ -0,0 +1,25 @@
> +/* pthread_spin_unlock 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/xthread.h>
> +
> +void
> +xpthread_spin_unlock (pthread_spinlock_t *lock)
> +{
> +  xpthread_check_return ("pthread_spin_unlock", pthread_spin_unlock (lock));
> +}
> diff --git a/support/xrealloc.c b/support/xrealloc.c
> new file mode 100644
> index 0000000..00c3138
> --- /dev/null
> +++ b/support/xrealloc.c
> @@ -0,0 +1,32 @@
> +/* Error-checking wrapper for realloc.
> +   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 <stdarg.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +void *
> +xrealloc (void *p, size_t n)
> +{
> +  void *result = realloc (p, n);
> +  if (result == NULL && (n > 0 || p == NULL))
> +    oom_error ("realloc", n);
> +  return result;
> +}
> diff --git a/support/xrecvfrom.c b/support/xrecvfrom.c
> new file mode 100644
> index 0000000..17809c4
> --- /dev/null
> +++ b/support/xrecvfrom.c
> @@ -0,0 +1,33 @@
> +/* recvfrom 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/xsocket.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +
> +size_t
> +xrecvfrom (int fd, void *buf, size_t buflen, int flags,
> +           struct sockaddr *sa, socklen_t *salen)
> +{
> +  ssize_t ret = recvfrom (fd, buf, buflen, flags, sa, salen);
> +  if (ret < 0)
> +    FAIL_EXIT1 ("error: recvfrom (%d), %zu bytes buffer: %m", fd, buflen);
> +  return ret;
> +}
> diff --git a/support/xsendto.c b/support/xsendto.c
> new file mode 100644
> index 0000000..20bddf6
> --- /dev/null
> +++ b/support/xsendto.c
> @@ -0,0 +1,35 @@
> +/* sendto 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/xsocket.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +
> +void
> +xsendto (int fd, const void *buf, size_t buflen, int flags,
> +         const struct sockaddr *sa, socklen_t salen)
> +{
> +  ssize_t ret = sendto (fd, buf, buflen, flags, sa, salen);
> +  if (ret < 0)
> +    FAIL_EXIT1 ("sendto (%d), %zu bytes, family %d: %m",
> +                fd, buflen, sa->sa_family);
> +  if (ret != buflen)
> +    FAIL_EXIT1 ("sendto (%d) sent %zd bytes instead of %zu", fd, ret, buflen);
> +}
> diff --git a/support/xsetsockopt.c b/support/xsetsockopt.c
> new file mode 100644
> index 0000000..9931882
> --- /dev/null
> +++ b/support/xsetsockopt.c
> @@ -0,0 +1,31 @@
> +/* setsockopt 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/xsocket.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +
> +void
> +xsetsockopt (int fd, int level, int name, const void *val, socklen_t vallen)
> +{
> +  if (setsockopt (fd, level, name, val, vallen) != 0)
> +    FAIL_EXIT1 ("setsockopt (%d, %d, %d), %zu bytes: %m",
> +                fd, level, name, (size_t) vallen);
> +}
> diff --git a/support/xsignal.h b/support/xsignal.h
> new file mode 100644
> index 0000000..3dc0d9d
> --- /dev/null
> +++ b/support/xsignal.h
> @@ -0,0 +1,34 @@
> +/* Support functionality for using signals.
> +   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/>.  */
> +
> +#ifndef SUPPORT_SIGNAL_H
> +#define SUPPORT_SIGNAL_H
> +
> +#include <signal.h>
> +#include <sys/cdefs.h>
> +
> +__BEGIN_DECLS
> +
> +/* The following functions call the corresponding libpthread functions
> +   and terminate the process on error.  */
> +
> +void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset);
> +
> +__END_DECLS
> +
> +#endif /* SUPPORT_SIGNAL_H */
> diff --git a/support/xsocket.c b/support/xsocket.c
> new file mode 100644
> index 0000000..c1deaee
> --- /dev/null
> +++ b/support/xsocket.c
> @@ -0,0 +1,32 @@
> +/* socket 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/xsocket.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +
> +int
> +xsocket (int domain, int type, int protocol)
> +{
> +  int fd = socket (domain, type, protocol);
> +  if (fd < 0)
> +    FAIL_EXIT1 ("socket (%d, %d, %d): %m\n", domain, type, protocol);
> +  return fd;
> +}
> diff --git a/support/xsocket.h b/support/xsocket.h
> new file mode 100644
> index 0000000..d672494
> --- /dev/null
> +++ b/support/xsocket.h
> @@ -0,0 +1,39 @@
> +/* Error-checking wrappers for socket functions.
> +   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/>.  */
> +
> +#ifndef SUPPORT_XSOCKET_H
> +#define SUPPORT_XSOCKET_H
> +
> +#include <poll.h>
> +#include <sys/socket.h>
> +#include <sys/types.h>
> +
> +int xsocket (int, int, int);
> +void xsetsockopt (int, int, int, const void *, socklen_t);
> +void xgetsockname (int, struct sockaddr *, socklen_t *);
> +void xconnect (int, const struct sockaddr *, socklen_t);
> +void xbind (int, const struct sockaddr *, socklen_t);
> +void xlisten (int, int);
> +int xaccept (int, struct sockaddr *, socklen_t *);
> +int xaccept4 (int, struct sockaddr *, socklen_t *, int);
> +void xsendto (int, const void *, size_t, int,
> +              const struct sockaddr *, socklen_t);
> +size_t xrecvfrom (int, void *, size_t, int, struct sockaddr *, socklen_t *);
> +int xpoll (struct pollfd *, nfds_t, int);
> +
> +#endif /* SUPPORT_XSOCKET_H */
> diff --git a/support/xstdio.h b/support/xstdio.h
> new file mode 100644
> index 0000000..bcc2e86
> --- /dev/null
> +++ b/support/xstdio.h
> @@ -0,0 +1,32 @@
> +/* Error-checking wrappers for stdio functions.
> +   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/>.  */
> +
> +#ifndef SUPPORT_XSTDIO_H
> +#define SUPPORT_XSTDIO_H
> +
> +#include <stdio.h>
> +#include <sys/cdefs.h>
> +
> +__BEGIN_DECLS
> +
> +FILE *xfopen (const char *path, const char *mode);
> +void xfclose (FILE *);
> +
> +__END_DECLS
> +
> +#endif /* SUPPORT_XSTDIO_H */
> diff --git a/support/xstrdup.c b/support/xstrdup.c
> new file mode 100644
> index 0000000..d6a8c04
> --- /dev/null
> +++ b/support/xstrdup.c
> @@ -0,0 +1,30 @@
> +/* strdup 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 *
> +xstrdup (const char *s)
> +{
> +  char *p = strdup (s);
> +  if (p == NULL)
> +    oom_error ("strdup", strlen (s));
> +  return p;
> +}
> diff --git a/support/xthread.h b/support/xthread.h
> new file mode 100644
> index 0000000..6dd7e70
> --- /dev/null
> +++ b/support/xthread.h
> @@ -0,0 +1,77 @@
> +/* Support functionality for using threads.
> +   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/>.  */
> +
> +#ifndef SUPPORT_THREAD_H
> +#define SUPPORT_THREAD_H
> +
> +#include <pthread.h>
> +#include <sys/cdefs.h>
> +
> +__BEGIN_DECLS
> +
> +/* Terminate the process (with exit status 0) after SECONDS have
> +   elapsed, from a helper thread.  The process is terminated with the
> +   exit function, so atexit handlers are executed.  */
> +void delayed_exit (int seconds);
> +
> +/* Terminate the process (with exit status 1) if VALUE is not zero.
> +   In that case, print a failure message to standard output mentioning
> +   FUNCTION.  The process is terminated with the exit function, so
> +   atexit handlers are executed.  */
> +void xpthread_check_return (const char *function, int value);
> +
> +/* The following functions call the corresponding libpthread functions
> +   and terminate the process on error.  */
> +
> +void xpthread_barrier_init (pthread_barrier_t *barrier,
> +                            pthread_barrierattr_t *attr, unsigned int count);
> +void xpthread_barrier_destroy (pthread_barrier_t *barrier);
> +void xpthread_mutexattr_destroy (pthread_mutexattr_t *);
> +void xpthread_mutexattr_init (pthread_mutexattr_t *);
> +void xpthread_mutexattr_setprotocol (pthread_mutexattr_t *, int);
> +void xpthread_mutexattr_setpshared (pthread_mutexattr_t *, int);
> +void xpthread_mutexattr_setrobust (pthread_mutexattr_t *, int);
> +void xpthread_mutexattr_settype (pthread_mutexattr_t *, int);
> +void xpthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *);
> +void xpthread_mutex_destroy (pthread_mutex_t *);
> +void xpthread_mutex_lock (pthread_mutex_t *mutex);
> +void xpthread_mutex_unlock (pthread_mutex_t *mutex);
> +void xpthread_mutex_consistent (pthread_mutex_t *);
> +void xpthread_spin_lock (pthread_spinlock_t *lock);
> +void xpthread_spin_unlock (pthread_spinlock_t *lock);
> +void xpthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex);
> +pthread_t xpthread_create (pthread_attr_t *attr,
> +                           void *(*thread_func) (void *), void *closure);
> +void xpthread_detach (pthread_t thr);
> +void xpthread_cancel (pthread_t thr);
> +void *xpthread_join (pthread_t thr);
> +void xpthread_once (pthread_once_t *guard, void (*func) (void));
> +void xpthread_attr_destroy (pthread_attr_t *attr);
> +void xpthread_attr_init (pthread_attr_t *attr);
> +void xpthread_attr_setdetachstate (pthread_attr_t *attr,
> +				   int detachstate);
> +void xpthread_attr_setstacksize (pthread_attr_t *attr,
> +				 size_t stacksize);
> +
> +/* This function returns non-zero if pthread_barrier_wait returned
> +   PTHREAD_BARRIER_SERIAL_THREAD.  */
> +int xpthread_barrier_wait (pthread_barrier_t *barrier);
> +
> +__END_DECLS
> +
> +#endif /* SUPPORT_THREAD_H */
> diff --git a/support/xunistd.h b/support/xunistd.h
> new file mode 100644
> index 0000000..151d743
> --- /dev/null
> +++ b/support/xunistd.h
> @@ -0,0 +1,56 @@
> +/* POSIX-specific extra functions.
> +   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/>.  */
> +
> +/* These wrapper functions use POSIX types and therefore cannot be
> +   declared in <support/support.h>.  */
> +
> +#ifndef SUPPORT_XUNISTD_H
> +#define SUPPORT_XUNISTD_H
> +
> +#include <sys/cdefs.h>
> +#include <sys/types.h>
> +#include <unistd.h>
> +
> +__BEGIN_DECLS
> +
> +struct stat64;
> +
> +pid_t xfork (void);
> +pid_t xwaitpid (pid_t, int *status, int flags);
> +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 xmkdir (const char *path, mode_t);
> +void xchroot (const char *path);
> +
> +/* Close the file descriptor.  Ignore EINTR errors, but terminate the
> +   process on other errors.  */
> +void xclose (int);
> +
> +/* Write the buffer.  Retry on short writes.  */
> +void xwrite (int, const void *, size_t);
> +
> +/* Invoke mmap with a zero file offset.  */
> +void *xmmap (void *addr, size_t length, int prot, int flags, int fd);
> +
> +void xmunmap (void *addr, size_t length);
> +
> +__END_DECLS
> +
> +#endif /* SUPPORT_XUNISTD_H */
> diff --git a/support/xwaitpid.c b/support/xwaitpid.c
> new file mode 100644
> index 0000000..204795e
> --- /dev/null
> +++ b/support/xwaitpid.c
> @@ -0,0 +1,33 @@
> +/* waitpid 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/xunistd.h>
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <sys/wait.h>
> +
> +int
> +xwaitpid (int pid, int *status, int flags)
> +{
> +  pid_t result = waitpid (pid, status, flags);
> +  if (result < 0)
> +    FAIL_EXIT1 ("waitpid: %m\n");
> +  return result;
> +}
> diff --git a/support/xwrite.c b/support/xwrite.c
> new file mode 100644
> index 0000000..134e8ee
> --- /dev/null
> +++ b/support/xwrite.c
> @@ -0,0 +1,39 @@
> +/* write with error checking and retries.
> +   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/xunistd.h>
> +
> +#include <support/check.h>
> +
> +void
> +xwrite (int fd, const void *buffer, size_t length)
> +{
> +  const char *p = buffer;
> +  const char *end = p + length;
> +  while (p < end)
> +    {
> +      ssize_t ret = write (fd, p, end - p);
> +      if (ret < 0)
> +        FAIL_EXIT1 ("write of %zu bytes failed after %td: %m",
> +                    length, p - (const char *) buffer);
> +      if (ret == 0)
> +        FAIL_EXIT1 ("write return 0 after writing %td bytes of %zu",
> +                    p - (const char *) buffer, length);
> +      p += ret;
> +    }
> +}
> 


-- 
Cheers,
Carlos.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2.22] Synchronize support/ infrastructure with master
  2018-01-01  0:00     ` [PATCH 2.22] Synchronize support/ infrastructure with master Raphael Moreira Zinsly
  2018-01-01  0:00       ` Carlos O'Donell
@ 2018-01-01  0:00       ` Tulio Magno Quites Machado Filho
  2018-01-01  0:00         ` [PATCH 2.22] posix: Sync glob with gnulib [BZ #1062] Raphael Moreira Zinsly
  1 sibling, 1 reply; 26+ messages in thread
From: Tulio Magno Quites Machado Filho @ 2018-01-01  0:00 UTC (permalink / raw)
  To: Raphael Moreira Zinsly; +Cc: libc-stable, arjun.is, Carlos O'Donell

Raphael Moreira Zinsly <rzinsly@linux.vnet.ibm.com> writes:

> This commit updates the support/ subdirectory to
> commit 2714c5f3c95f90977167c1d21326d907fb76b419
> on the master branch and modifies Makeconfig,
> Rules, and extra-lib.mk accordingly.
>
> (cherry picked from commit 4c5785aa129a5d195fc1cd5c7fcd6f62c2b0ff0c)

This patch does solve part of the issues, but it isn't enough to make
posix/tst-glob-tilde-mem and io/tst-getcwd-abspath to pass.

I removed the following patches and pushed the rest:
[PATCH 2.22 02/14] CVE-2017-15670: glob: Fix one-byte overflow [BZ #22320]
[PATCH 2.22 03/14] glob: Add new test tst-glob-tilde
[PATCH 2.22 05/14] glob: Fix buffer overflow during GLOB_TILDE unescaping [BZ #22332]
[PATCH 2.22 11/14] linux: make getcwd(3) fail if it cannot obtain an absolute path [BZ #22679]

We can continue to work on these patches after this.

-- 
Tulio Magno

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2.22 v2] Fix integer overflows in internal memalign and malloc functions [BZ #22343]
  2018-01-01  0:00         ` Carlos O'Donell
@ 2018-01-01  0:00           ` Tulio Magno Quites Machado Filho
  0 siblings, 0 replies; 26+ messages in thread
From: Tulio Magno Quites Machado Filho @ 2018-01-01  0:00 UTC (permalink / raw)
  To: Carlos O'Donell, Arjun Shankar, Raphael Moreira Zinsly; +Cc: libc-stable

Carlos O'Donell <carlos@redhat.com> writes:

> [ text/plain ]
> On 04/05/2018 02:49 PM, Arjun Shankar wrote:
>> On Wed, 2018-04-04 at 20:29 -0500, Carlos O'Donell wrote:
>> 
>>>> +#include <support/test-driver.c>
>>>  
>>> This can't possibly work for release/2.22/master, there was no support
>>> infrastructure?
>> 
>> I'm working on backporting *just* enough bits into 2.22 to:
>> 
>> 1. Include support/ infrastructure (Florian wrote a script that does this)

This is (at least partially) covered by this backport from Raphael:
https://sourceware.org/ml/libc-stable/2018-04/msg00001.html

>> 2. Have glibc-2.22 compile with a new-ish GCC (7.3) -
>>      This needs 8 additional commits

We aren't working on this and do not have plans to.  I can confirm it's
still failing.

>> 3. Include fix in question; i.e. BZ #22343

This is already covered by:
https://sourceware.org/ml/libc-stable/2018-04/msg00002.html

-- 
Tulio Magno

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22] Synchronize support/ infrastructure with master
  2018-01-01  0:00   ` Tulio Magno Quites Machado Filho
@ 2018-01-01  0:00     ` Raphael Moreira Zinsly
  2018-01-01  0:00       ` Carlos O'Donell
  2018-01-01  0:00       ` Tulio Magno Quites Machado Filho
  0 siblings, 2 replies; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: tuliom; +Cc: libc-stable

From: Arjun Shankar <arjun.is@lostca.se>

Sorry for that, with that backport the tests work fine.

-- >8 --

This commit updates the support/ subdirectory to
commit 2714c5f3c95f90977167c1d21326d907fb76b419
on the master branch and modifies Makeconfig,
Rules, and extra-lib.mk accordingly.

(cherry picked from commit 4c5785aa129a5d195fc1cd5c7fcd6f62c2b0ff0c)
---
 Makeconfig                                 |   15 +-
 Rules                                      |    3 +
 extra-lib.mk                               |    5 +
 scripts/backport-support.sh                |  110 +++
 support/Makefile                           |  146 ++++
 support/README                             |   29 +
 support/README-testing.c                   |   19 +
 support/capture_subprocess.h               |   61 ++
 support/check.c                            |   57 ++
 support/check.h                            |   94 +++
 support/check_addrinfo.c                   |   42 +
 support/check_dns_packet.c                 |   42 +
 support/check_hostent.c                    |   42 +
 support/check_netent.c                     |   42 +
 support/check_nss.h                        |   42 +
 support/delayed_exit.c                     |   55 ++
 support/format_nss.h                       |   41 +
 support/ignore_stderr.c                    |   38 +
 support/namespace.h                        |   65 ++
 support/oom_error.c                        |   29 +
 support/resolv_test.c                      | 1202 ++++++++++++++++++++++++++++
 support/resolv_test.h                      |  180 +++++
 support/run_diff.h                         |   31 +
 support/set_fortify_handler.c              |   34 +
 support/support-xstat.c                    |   30 +
 support/support.h                          |   74 ++
 support/support_become_root.c              |   40 +
 support/support_can_chroot.c               |   65 ++
 support/support_capture_subprocess.c       |  108 +++
 support/support_capture_subprocess_check.c |   67 ++
 support/support_enter_network_namespace.c  |   75 ++
 support/support_format_address_family.c    |   35 +
 support/support_format_addrinfo.c          |  239 ++++++
 support/support_format_dns_packet.c        |  222 +++++
 support/support_format_herrno.c            |   45 ++
 support/support_format_hostent.c           |   75 ++
 support/support_format_netent.c            |   52 ++
 support/support_isolate_in_subprocess.c    |   38 +
 support/support_record_failure.c           |  106 +++
 support/support_run_diff.c                 |   76 ++
 support/support_shared_allocate.c          |   59 ++
 support/support_test_main.c                |  423 ++++++++++
 support/support_test_verify_impl.c         |   33 +
 support/support_write_file_string.c        |   39 +
 support/temp_file-internal.h               |   31 +
 support/temp_file.c                        |  132 +++
 support/temp_file.h                        |   37 +
 support/test-driver.c                      |  156 ++++
 support/test-driver.h                      |   74 ++
 support/tst-support-namespace.c            |   34 +
 support/tst-support_capture_subprocess.c   |  188 +++++
 support/tst-support_format_dns_packet.c    |  101 +++
 support/tst-support_record_failure-2.sh    |   69 ++
 support/tst-support_record_failure.c       |  153 ++++
 support/write_message.c                    |   29 +
 support/xaccept.c                          |   32 +
 support/xaccept4.c                         |   32 +
 support/xasprintf.c                        |   36 +
 support/xbind.c                            |   30 +
 support/xcalloc.c                          |   34 +
 support/xchroot.c                          |   28 +
 support/xclose.c                           |   28 +
 support/xconnect.c                         |   30 +
 support/xdup2.c                            |   28 +
 support/xfclose.c                          |   33 +
 support/xfopen.c                           |   31 +
 support/xfork.c                            |   32 +
 support/xgetsockname.c                     |   30 +
 support/xlisten.c                          |   30 +
 support/xmalloc.c                          |   34 +
 support/xmemstream.c                       |   42 +
 support/xmemstream.h                       |   49 ++
 support/xmkdir.c                           |   28 +
 support/xmmap.c                            |   31 +
 support/xmunmap.c                          |   28 +
 support/xopen.c                            |   30 +
 support/xpipe.c                            |   28 +
 support/xpoll.c                            |   32 +
 support/xpthread_attr_destroy.c            |   26 +
 support/xpthread_attr_init.c               |   25 +
 support/xpthread_attr_setdetachstate.c     |   27 +
 support/xpthread_attr_setstacksize.c       |   26 +
 support/xpthread_barrier_destroy.c         |   26 +
 support/xpthread_barrier_init.c            |   27 +
 support/xpthread_barrier_wait.c            |   28 +
 support/xpthread_cancel.c                  |   25 +
 support/xpthread_check_return.c            |   34 +
 support/xpthread_cond_wait.c               |   26 +
 support/xpthread_create.c                  |   29 +
 support/xpthread_detach.c                  |   25 +
 support/xpthread_join.c                    |   27 +
 support/xpthread_mutex_consistent.c        |   26 +
 support/xpthread_mutex_destroy.c           |   26 +
 support/xpthread_mutex_init.c              |   26 +
 support/xpthread_mutex_lock.c              |   25 +
 support/xpthread_mutex_unlock.c            |   25 +
 support/xpthread_mutexattr_destroy.c       |   26 +
 support/xpthread_mutexattr_init.c          |   25 +
 support/xpthread_mutexattr_setprotocol.c   |   26 +
 support/xpthread_mutexattr_setpshared.c    |   26 +
 support/xpthread_mutexattr_setrobust.c     |   26 +
 support/xpthread_mutexattr_settype.c       |   26 +
 support/xpthread_once.c                    |   25 +
 support/xpthread_sigmask.c                 |   34 +
 support/xpthread_spin_lock.c               |   25 +
 support/xpthread_spin_unlock.c             |   25 +
 support/xrealloc.c                         |   32 +
 support/xrecvfrom.c                        |   33 +
 support/xsendto.c                          |   35 +
 support/xsetsockopt.c                      |   31 +
 support/xsignal.h                          |   34 +
 support/xsocket.c                          |   32 +
 support/xsocket.h                          |   39 +
 support/xstdio.h                           |   32 +
 support/xstrdup.c                          |   30 +
 support/xthread.h                          |   77 ++
 support/xunistd.h                          |   56 ++
 support/xwaitpid.c                         |   33 +
 support/xwrite.c                           |   39 +
 119 files changed, 7308 insertions(+), 3 deletions(-)
 create mode 100644 scripts/backport-support.sh
 create mode 100644 support/Makefile
 create mode 100644 support/README
 create mode 100644 support/README-testing.c
 create mode 100644 support/capture_subprocess.h
 create mode 100644 support/check.c
 create mode 100644 support/check.h
 create mode 100644 support/check_addrinfo.c
 create mode 100644 support/check_dns_packet.c
 create mode 100644 support/check_hostent.c
 create mode 100644 support/check_netent.c
 create mode 100644 support/check_nss.h
 create mode 100644 support/delayed_exit.c
 create mode 100644 support/format_nss.h
 create mode 100644 support/ignore_stderr.c
 create mode 100644 support/namespace.h
 create mode 100644 support/oom_error.c
 create mode 100644 support/resolv_test.c
 create mode 100644 support/resolv_test.h
 create mode 100644 support/run_diff.h
 create mode 100644 support/set_fortify_handler.c
 create mode 100644 support/support-xstat.c
 create mode 100644 support/support.h
 create mode 100644 support/support_become_root.c
 create mode 100644 support/support_can_chroot.c
 create mode 100644 support/support_capture_subprocess.c
 create mode 100644 support/support_capture_subprocess_check.c
 create mode 100644 support/support_enter_network_namespace.c
 create mode 100644 support/support_format_address_family.c
 create mode 100644 support/support_format_addrinfo.c
 create mode 100644 support/support_format_dns_packet.c
 create mode 100644 support/support_format_herrno.c
 create mode 100644 support/support_format_hostent.c
 create mode 100644 support/support_format_netent.c
 create mode 100644 support/support_isolate_in_subprocess.c
 create mode 100644 support/support_record_failure.c
 create mode 100644 support/support_run_diff.c
 create mode 100644 support/support_shared_allocate.c
 create mode 100644 support/support_test_main.c
 create mode 100644 support/support_test_verify_impl.c
 create mode 100644 support/support_write_file_string.c
 create mode 100644 support/temp_file-internal.h
 create mode 100644 support/temp_file.c
 create mode 100644 support/temp_file.h
 create mode 100644 support/test-driver.c
 create mode 100644 support/test-driver.h
 create mode 100644 support/tst-support-namespace.c
 create mode 100644 support/tst-support_capture_subprocess.c
 create mode 100644 support/tst-support_format_dns_packet.c
 create mode 100644 support/tst-support_record_failure-2.sh
 create mode 100644 support/tst-support_record_failure.c
 create mode 100644 support/write_message.c
 create mode 100644 support/xaccept.c
 create mode 100644 support/xaccept4.c
 create mode 100644 support/xasprintf.c
 create mode 100644 support/xbind.c
 create mode 100644 support/xcalloc.c
 create mode 100644 support/xchroot.c
 create mode 100644 support/xclose.c
 create mode 100644 support/xconnect.c
 create mode 100644 support/xdup2.c
 create mode 100644 support/xfclose.c
 create mode 100644 support/xfopen.c
 create mode 100644 support/xfork.c
 create mode 100644 support/xgetsockname.c
 create mode 100644 support/xlisten.c
 create mode 100644 support/xmalloc.c
 create mode 100644 support/xmemstream.c
 create mode 100644 support/xmemstream.h
 create mode 100644 support/xmkdir.c
 create mode 100644 support/xmmap.c
 create mode 100644 support/xmunmap.c
 create mode 100644 support/xopen.c
 create mode 100644 support/xpipe.c
 create mode 100644 support/xpoll.c
 create mode 100644 support/xpthread_attr_destroy.c
 create mode 100644 support/xpthread_attr_init.c
 create mode 100644 support/xpthread_attr_setdetachstate.c
 create mode 100644 support/xpthread_attr_setstacksize.c
 create mode 100644 support/xpthread_barrier_destroy.c
 create mode 100644 support/xpthread_barrier_init.c
 create mode 100644 support/xpthread_barrier_wait.c
 create mode 100644 support/xpthread_cancel.c
 create mode 100644 support/xpthread_check_return.c
 create mode 100644 support/xpthread_cond_wait.c
 create mode 100644 support/xpthread_create.c
 create mode 100644 support/xpthread_detach.c
 create mode 100644 support/xpthread_join.c
 create mode 100644 support/xpthread_mutex_consistent.c
 create mode 100644 support/xpthread_mutex_destroy.c
 create mode 100644 support/xpthread_mutex_init.c
 create mode 100644 support/xpthread_mutex_lock.c
 create mode 100644 support/xpthread_mutex_unlock.c
 create mode 100644 support/xpthread_mutexattr_destroy.c
 create mode 100644 support/xpthread_mutexattr_init.c
 create mode 100644 support/xpthread_mutexattr_setprotocol.c
 create mode 100644 support/xpthread_mutexattr_setpshared.c
 create mode 100644 support/xpthread_mutexattr_setrobust.c
 create mode 100644 support/xpthread_mutexattr_settype.c
 create mode 100644 support/xpthread_once.c
 create mode 100644 support/xpthread_sigmask.c
 create mode 100644 support/xpthread_spin_lock.c
 create mode 100644 support/xpthread_spin_unlock.c
 create mode 100644 support/xrealloc.c
 create mode 100644 support/xrecvfrom.c
 create mode 100644 support/xsendto.c
 create mode 100644 support/xsetsockopt.c
 create mode 100644 support/xsignal.h
 create mode 100644 support/xsocket.c
 create mode 100644 support/xsocket.h
 create mode 100644 support/xstdio.h
 create mode 100644 support/xstrdup.c
 create mode 100644 support/xthread.h
 create mode 100644 support/xunistd.h
 create mode 100644 support/xwaitpid.c
 create mode 100644 support/xwrite.c

diff --git a/Makeconfig b/Makeconfig
index f136b88..b5d100b 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -395,6 +395,9 @@ ifndef after-link
 after-link =
 endif
 
+# Additional libraries to link into every test.
+link-extra-libs-tests = $(libsupport)
+
 # Command for linking PIE programs with the C library.
 ifndef +link-pie
 +link-pie-before-libc = $(CC) -pie -Wl,-O1 -nostdlib -nostartfiles -o $@ \
@@ -504,7 +507,7 @@ link-libc = $(link-libc-rpath-link) $(link-libc-before-gnulib) $(gnulib)
 link-libc-tests = $(link-libc-tests-rpath-link) \
 		  $(link-libc-before-gnulib) $(gnulib-tests)
 # This is how to find at build-time things that will be installed there.
-rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec
+rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec support
 rpath-link = \
 $(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%)))
 else
@@ -851,7 +854,7 @@ libio-include = -I$(..)libio
 # List of non-library modules that we build.
 built-modules = iconvprogs iconvdata ldconfig lddlibc4 libmemusage \
 		libSegFault libpcprofile librpcsvc locale-programs \
-		memusagestat nonlib nscd extramodules libnldbl
+		memusagestat nonlib nscd extramodules libnldbl libsupport
 
 in-module = $(subst -,_,$(firstword $(libof-$(basename $(@F))) \
 				    $(libof-$(<F)) \
@@ -1089,6 +1092,12 @@ libm = $(common-objpfx)math/libm.a
 libmvec = $(common-objpfx)mathvec/libmvec.a
 endif
 
+ifeq ($(build-shared),yes)
+libsupport = $(common-objpfx)support/libsupport_nonshared.a
+else
+libsupport = $(common-objpfx)support/libsupport.a
+endif
+
 # These are the subdirectories containing the library source.  The order
 # is more or less arbitrary.  The sorting step will take care of the
 # dependencies.
@@ -1096,7 +1105,7 @@ all-subdirs = csu assert ctype locale intl catgets math setjmp signal	    \
 	      stdlib stdio-common libio malloc string wcsmbs time dirent    \
 	      grp pwd posix io termios resource misc socket sysvipc gmon    \
 	      gnulib iconv iconvdata wctype manual shadow gshadow po argp   \
-	      crypt localedata timezone rt conform debug mathvec	    \
+	      crypt localedata timezone rt conform debug mathvec support    \
 	      $(add-on-subdirs) dlfcn elf
 
 ifndef avoid-generated
diff --git a/Rules b/Rules
index e237d03..7c5777c 100644
--- a/Rules
+++ b/Rules
@@ -149,6 +149,7 @@ endif
 
 ifneq "$(strip $(binaries-shared-tests))" ""
 $(addprefix $(objpfx),$(binaries-shared-tests)): %: %.o \
+  $(link-extra-libs-tests) \
   $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \
   $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit)
 	$(+link-tests)
@@ -156,6 +157,7 @@ endif
 
 ifneq "$(strip $(binaries-pie-tests))" ""
 $(addprefix $(objpfx),$(binaries-pie-tests)): %: %.o \
+  $(link-extra-libs-tests) \
   $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \
   $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit)
 	$(+link-pie-tests)
@@ -177,6 +179,7 @@ endif
 
 ifneq "$(strip $(binaries-static-tests))" ""
 $(addprefix $(objpfx),$(binaries-static-tests)): %: %.o \
+  $(link-extra-libs-tests) \
   $(sort $(filter $(common-objpfx)lib%,$(link-libc-static-tests))) \
   $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit)
 	$(+link-static-tests)
diff --git a/extra-lib.mk b/extra-lib.mk
index b10748d..2552049 100644
--- a/extra-lib.mk
+++ b/extra-lib.mk
@@ -5,6 +5,9 @@
 # The variable $($(lib)-routines) defines the list of modules
 # to be included in that library.  A sysdep Makefile can add to
 # $(lib)-sysdep_routines to include additional modules.
+#
+# Libraries listed in $(extra-libs-noinstall) are built, but not
+# installed.
 
 lib := $(firstword $(extra-libs-left))
 extra-libs-left := $(filter-out $(lib),$(extra-libs-left))
@@ -28,7 +31,9 @@ extra-objs := $(extra-objs)
 all-$(lib)-routines := $($(lib)-routines) $($(lib)-sysdep_routines)
 
 # Add each flavor of library to the lists of things to build and install.
+ifeq (,$(filter $(lib), $(extra-libs-noinstall)))
 install-lib += $(foreach o,$(object-suffixes-$(lib)),$(lib:lib%=$(libtype$o)))
+endif
 extra-objs += $(foreach o,$(filter-out .os .oS,$(object-suffixes-$(lib))),\
 			$(patsubst %,%$o,$(filter-out \
 					   $($(lib)-shared-only-routines),\
diff --git a/scripts/backport-support.sh b/scripts/backport-support.sh
new file mode 100644
index 0000000..2ece7ce
--- /dev/null
+++ b/scripts/backport-support.sh
@@ -0,0 +1,110 @@
+#!/bin/bash
+# Create a patch which backports the support/ subdirectory.
+# 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/>.
+
+# This script does not backport the Makefile tweaks outside the
+# support/ directory (which need to be backported separately), or the
+# changes to test-skeleton.c (which should not be backported).
+
+set -e
+
+export LC_ALL=C
+export GIT_CONFIG=/dev/null
+export GTT_CONFIG_NOSYSTEM=0
+export GIT_PAGER=
+
+usage () {
+    cat >&2 <<EOF
+usage: $0 {patch|commit}
+EOF
+    exit 1
+}
+
+if test $# -ne 1 ; then
+    usage
+fi
+
+command="$1"
+
+case "$command" in
+    patch|commit)
+    ;;
+    *)
+	usage
+	;;
+esac
+
+# The upstream branch to work on.
+branch=origin/master
+
+# The commit which added the support/ directory.
+initial_commit=c23de0aacbeaa7a091609b35764bed931475a16d
+
+# We backport the support directory and this script.  Directories need
+# to end in a /.
+patch_targets="support/ scripts/backport-support.sh"
+
+latest_commit="$(git log --max-count=1 --pretty=format:%H "$branch" -- \
+  $patch_targets)"
+
+# Simplify the branch name somewhat for reporting.
+branch_name="$(echo "$branch" | sed s,^origin/,,)"
+
+command_patch () {
+    cat <<EOF
+This patch creates the contents of the support/ directory up to this
+upstream commit on the $branch_name branch:
+
+EOF
+    git log --max-count=1 "$latest_commit"
+    echo
+    git diff "$initial_commit"^.."$latest_commit" $patch_targets
+    echo "# Before applying the patch, run this command:" >&2
+    echo "# rm -rf $patch_targets" >&2
+}
+
+command_commit () {
+    git status --porcelain | while read line ; do
+	echo "error: working copy is not clean, cannot commit" >&2
+	exit 1
+    done
+    for path in $patch_targets; do
+	echo "# Processing $path" >&2
+	case "$path" in
+	    [a-zA-Z0-9]*/)
+		# Directory.
+		git rm --cached --ignore-unmatch -r "$path"
+		rm -rf "$path"
+		git read-tree --prefix="$path" "$latest_commit":"$path"
+		git checkout "$path"
+		;;
+	    *)
+		# File.
+		git show "$latest_commit":"$path" > "$path"
+		git add "$path"
+	esac
+    done
+    git commit -m "Synchronize support/ infrastructure with $branch_name
+
+This commit updates the support/ subdirectory to
+commit $latest_commit
+on the $branch_name branch.
+"
+}
+
+command_$command
diff --git a/support/Makefile b/support/Makefile
new file mode 100644
index 0000000..20b0343
--- /dev/null
+++ b/support/Makefile
@@ -0,0 +1,146 @@
+# Makefile for support library, used only at build and test time
+# 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/>.
+
+subdir := support
+
+include ../Makeconfig
+
+extra-libs := libsupport
+extra-libs-others = $(extra-libs)
+extra-libs-noinstall := $(extra-libs)
+
+libsupport-routines = \
+  check \
+  check_addrinfo \
+  check_dns_packet \
+  check_hostent \
+  check_netent \
+  delayed_exit \
+  ignore_stderr \
+  oom_error \
+  resolv_test \
+  set_fortify_handler \
+  support-xstat \
+  support_become_root \
+  support_can_chroot \
+  support_capture_subprocess \
+  support_capture_subprocess_check \
+  support_enter_network_namespace \
+  support_format_address_family \
+  support_format_addrinfo \
+  support_format_dns_packet \
+  support_format_herrno \
+  support_format_hostent \
+  support_format_netent \
+  support_isolate_in_subprocess \
+  support_record_failure \
+  support_run_diff \
+  support_shared_allocate \
+  support_write_file_string \
+  support_test_main \
+  support_test_verify_impl \
+  temp_file \
+  write_message \
+  xaccept \
+  xaccept4 \
+  xasprintf \
+  xbind \
+  xcalloc \
+  xchroot \
+  xclose \
+  xconnect \
+  xdup2 \
+  xfclose \
+  xfopen \
+  xfork \
+  xgetsockname \
+  xlisten \
+  xmalloc \
+  xmemstream \
+  xmkdir \
+  xmmap \
+  xmunmap \
+  xopen \
+  xpipe \
+  xpoll \
+  xpthread_attr_destroy \
+  xpthread_attr_init \
+  xpthread_attr_setdetachstate \
+  xpthread_attr_setstacksize \
+  xpthread_barrier_destroy \
+  xpthread_barrier_init \
+  xpthread_barrier_wait \
+  xpthread_cancel \
+  xpthread_check_return \
+  xpthread_cond_wait \
+  xpthread_create \
+  xpthread_detach \
+  xpthread_join \
+  xpthread_mutex_consistent \
+  xpthread_mutex_destroy \
+  xpthread_mutex_init \
+  xpthread_mutex_lock \
+  xpthread_mutex_unlock \
+  xpthread_mutexattr_destroy \
+  xpthread_mutexattr_init \
+  xpthread_mutexattr_setprotocol \
+  xpthread_mutexattr_setpshared \
+  xpthread_mutexattr_setrobust \
+  xpthread_mutexattr_settype \
+  xpthread_once \
+  xpthread_sigmask \
+  xpthread_spin_lock \
+  xpthread_spin_unlock \
+  xrealloc \
+  xrecvfrom \
+  xsendto \
+  xsetsockopt \
+  xsocket \
+  xstrdup \
+  xwaitpid \
+  xwrite \
+
+libsupport-static-only-routines := $(libsupport-routines)
+# Only build one variant of the library.
+libsupport-inhibit-o := .os
+ifeq ($(build-shared),yes)
+libsupport-inhibit-o += .o
+endif
+
+tests = \
+  README-testing \
+  tst-support-namespace \
+  tst-support_capture_subprocess \
+  tst-support_format_dns_packet \
+  tst-support_record_failure \
+
+ifeq ($(run-built-tests),yes)
+tests-special = \
+  $(objpfx)tst-support_record_failure-2.out
+
+$(objpfx)tst-support_record_failure-2.out: tst-support_record_failure-2.sh \
+  $(objpfx)tst-support_record_failure
+	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+	  '$(run-program-env)' '$(test-program-prefix-after-env)' \
+	  > $@; \
+	$(evaluate-test)
+endif
+
+$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so
+
+include ../Rules
diff --git a/support/README b/support/README
new file mode 100644
index 0000000..476cfcd
--- /dev/null
+++ b/support/README
@@ -0,0 +1,29 @@
+This subdirectory contains infrastructure which is not put into
+installed libraries, but may be linked into programs (installed or
+not) and tests.
+
+# Error-checking wrappers
+
+These wrappers test for error return codes an terminate the process on
+error.  They are declared in these header files:
+
+* support.h
+* xsignal.h
+* xthread.h
+
+In general, new wrappers should be added to support.h if possible.
+However, support.h must remain fully compatible with C90 and therefore
+cannot include headers which use identifers not reserved in C90.  If
+the wrappers need additional types, additional headers such as
+signal.h need to be introduced.
+
+# Test framework
+
+The test framework provides a main program for tests, including a
+timeout for hanging tests.  See README-testing.c for a minimal
+example, and test-driver.c for details how to use it.  The following
+header files provide related declarations:
+
+* check.h
+* temp_file.h
+* test-driver.h
diff --git a/support/README-testing.c b/support/README-testing.c
new file mode 100644
index 0000000..9d289c3
--- /dev/null
+++ b/support/README-testing.c
@@ -0,0 +1,19 @@
+/* This file contains an example test case which shows minimal use of
+   the test framework.  Additional testing hooks are described in
+   <support/test-driver.c>.  */
+
+/* This function will be called from the test driver.  */
+static int
+do_test (void)
+{
+  if (3 == 5)
+    /* Indicate failure.  */
+    return 1;
+  else
+    /* Indicate success.  */
+    return 0;
+}
+
+/* This file references do_test above and contains the definition of
+   the main function.  */
+#include <support/test-driver.c>
diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
new file mode 100644
index 0000000..43caf9b
--- /dev/null
+++ b/support/capture_subprocess.h
@@ -0,0 +1,61 @@
+/* Capture output from a subprocess.
+   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_CAPTURE_SUBPROCESS_H
+#define SUPPORT_CAPTURE_SUBPROCESS_H
+
+#include <support/xmemstream.h>
+
+struct support_capture_subprocess
+{
+  struct xmemstream out;
+  struct xmemstream err;
+  int status;
+};
+
+/* Invoke CALLBACK (CLOSURE) in a subprocess and capture standard
+   output, standard error, and the exit status.  The out.buffer and
+   err.buffer members in the result are null-terminated strings which
+   can be examined by the caller (out.out and err.out are NULL).  */
+struct support_capture_subprocess support_capture_subprocess
+  (void (*callback) (void *), void *closure);
+
+/* Deallocate the subprocess data captured by
+   support_capture_subprocess.  */
+void support_capture_subprocess_free (struct support_capture_subprocess *);
+
+enum support_capture_allow
+{
+  /* No output is allowed.  */
+  sc_allow_none = 0x01,
+  /* Output to stdout is permitted.  */
+  sc_allow_stdout = 0x02,
+  /* Output to standard error is permitted.  */
+  sc_allow_stderr = 0x04,
+};
+
+/* Check that the subprocess exited with STATUS and that only the
+   allowed outputs happened.  ALLOWED is a combination of
+   support_capture_allow flags.  Report errors under the CONTEXT
+   message.  */
+void support_capture_subprocess_check (struct support_capture_subprocess *,
+                                       const char *context, int status,
+                                       int allowed)
+  __attribute__ ((nonnull (1, 2)));
+
+#endif /* SUPPORT_CAPTURE_SUBPROCESS_H */
diff --git a/support/check.c b/support/check.c
new file mode 100644
index 0000000..592f2bc
--- /dev/null
+++ b/support/check.c
@@ -0,0 +1,57 @@
+/* Support code for reporting test results.
+   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/check.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/test-driver.h>
+
+static void
+print_failure (const char *file, int line, const char *format, va_list ap)
+{
+  printf ("error: %s:%d: ", file, line);
+  vprintf (format, ap);
+  puts ("");
+}
+
+int
+support_print_failure_impl (const char *file, int line,
+                            const char *format, ...)
+{
+  support_record_failure ();
+  va_list ap;
+  va_start (ap, format);
+  print_failure (file, line, format, ap);
+  va_end (ap);
+  return 1;
+}
+
+void
+support_exit_failure_impl (int status, const char *file, int line,
+                           const char *format, ...)
+{
+  if (status != EXIT_SUCCESS && status != EXIT_UNSUPPORTED)
+    support_record_failure ();
+  va_list ap;
+  va_start (ap, format);
+  print_failure (file, line, format, ap);
+  va_end (ap);
+  exit (status);
+}
diff --git a/support/check.h b/support/check.h
new file mode 100644
index 0000000..1d244a3
--- /dev/null
+++ b/support/check.h
@@ -0,0 +1,94 @@
+/* Functionality for reporting test results.
+   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/>.  */
+
+#ifndef SUPPORT_CHECK_H
+#define SUPPORT_CHECK_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Record a test failure, print the failure message to standard output
+   and return 1.  */
+#define FAIL_RET(...) \
+  return support_print_failure_impl (__FILE__, __LINE__, __VA_ARGS__)
+
+/* Print the failure message and terminate the process with STATUS.
+   Record a the process as failed if STATUS is neither EXIT_SUCCESS
+   nor EXIT_UNSUPPORTED.  */
+#define FAIL_EXIT(status, ...) \
+  support_exit_failure_impl (status, __FILE__, __LINE__, __VA_ARGS__)
+
+/* Record a test failure, print the failure message and terminate with
+   exit status 1.  */
+#define FAIL_EXIT1(...) \
+  support_exit_failure_impl (1, __FILE__, __LINE__, __VA_ARGS__)
+
+/* Print failure message and terminate with as unsupported test (exit
+   status of 77).  */
+#define FAIL_UNSUPPORTED(...) \
+  support_exit_failure_impl (77, __FILE__, __LINE__, __VA_ARGS__)
+
+/* Record a test failure (but continue executing) if EXPR evaluates to
+   false.  */
+#define TEST_VERIFY(expr)                                       \
+  ({                                                            \
+    if (expr)                                                   \
+      ;                                                         \
+    else                                                        \
+      support_test_verify_impl (-1, __FILE__, __LINE__, #expr); \
+  })
+
+/* Record a test failure and exit if EXPR evaluates to false.  */
+#define TEST_VERIFY_EXIT(expr)                                  \
+  ({                                                            \
+    if (expr)                                                   \
+      ;                                                         \
+    else                                                        \
+      support_test_verify_impl (1, __FILE__, __LINE__, #expr);  \
+  })
+
+int support_print_failure_impl (const char *file, int line,
+                                const char *format, ...)
+  __attribute__ ((nonnull (1), format (printf, 3, 4)));
+void support_exit_failure_impl (int exit_status,
+                                const char *file, int line,
+                                const char *format, ...)
+  __attribute__ ((noreturn, nonnull (2), format (printf, 4, 5)));
+void support_test_verify_impl (int status, const char *file, int line,
+                               const char *expr);
+
+/* Record a test failure.  This function returns and does not
+   terminate the process.  The failure counter is stored in a shared
+   memory mapping, so that failures reported in child processes are
+   visible to the parent process and test driver.  This function
+   depends on initialization by an ELF constructor, so it can only be
+   invoked after the test driver has run.  Note that this function
+   does not support reporting failures from a DSO.  */
+void support_record_failure (void);
+
+/* Internal function called by the test driver.  */
+int support_report_failure (int status)
+  __attribute__ ((weak, warn_unused_result));
+
+/* Internal function used to test the failure recording framework.  */
+void support_record_failure_reset (void);
+
+__END_DECLS
+
+#endif /* SUPPORT_CHECK_H */
diff --git a/support/check_addrinfo.c b/support/check_addrinfo.c
new file mode 100644
index 0000000..55895ac
--- /dev/null
+++ b/support/check_addrinfo.c
@@ -0,0 +1,42 @@
+/* Compare struct addrinfo values against a formatted string.
+   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/check_nss.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/format_nss.h>
+#include <support/run_diff.h>
+
+void
+check_addrinfo (const char *query_description, struct addrinfo *ai, int ret,
+                const char *expected)
+{
+  char *formatted = support_format_addrinfo (ai, ret);
+  if (strcmp (formatted, expected) != 0)
+    {
+      support_record_failure ();
+      printf ("error: addrinfo comparison failure\n");
+      if (query_description != NULL)
+        printf ("query: %s\n", query_description);
+      support_run_diff ("expected", expected,
+                        "actual", formatted);
+    }
+  free (formatted);
+}
diff --git a/support/check_dns_packet.c b/support/check_dns_packet.c
new file mode 100644
index 0000000..d2a31be
--- /dev/null
+++ b/support/check_dns_packet.c
@@ -0,0 +1,42 @@
+/* Check that a DNS packet buffer has the expected contents.
+   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/check_nss.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/format_nss.h>
+#include <support/run_diff.h>
+
+void
+check_dns_packet (const char *query_description,
+                  const unsigned char *buffer, size_t length,
+                  const char *expected)
+{
+  char *formatted = support_format_dns_packet (buffer, length);
+  if (strcmp (formatted, expected) != 0)
+    {
+      support_record_failure ();
+      printf ("error: packet comparison failure\n");
+      if (query_description != NULL)
+        printf ("query: %s\n", query_description);
+      support_run_diff ("expected", expected, "actual", formatted);
+    }
+  free (formatted);
+}
diff --git a/support/check_hostent.c b/support/check_hostent.c
new file mode 100644
index 0000000..890d672
--- /dev/null
+++ b/support/check_hostent.c
@@ -0,0 +1,42 @@
+/* Compare struct hostent values against a formatted string.
+   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/check_nss.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/format_nss.h>
+#include <support/run_diff.h>
+
+void
+check_hostent (const char *query_description, struct hostent *h,
+               const char *expected)
+{
+  char *formatted = support_format_hostent (h);
+  if (strcmp (formatted, expected) != 0)
+    {
+      support_record_failure ();
+      printf ("error: hostent comparison failure\n");
+      if (query_description != NULL)
+        printf ("query: %s\n", query_description);
+      support_run_diff ("expected", expected,
+                        "actual", formatted);
+    }
+  free (formatted);
+}
diff --git a/support/check_netent.c b/support/check_netent.c
new file mode 100644
index 0000000..daa3083
--- /dev/null
+++ b/support/check_netent.c
@@ -0,0 +1,42 @@
+/* Compare struct netent values against a formatted string.
+   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/check_nss.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/format_nss.h>
+#include <support/run_diff.h>
+
+void
+check_netent (const char *query_description, struct netent *e,
+              const char *expected)
+{
+  char *formatted = support_format_netent (e);
+  if (strcmp (formatted, expected) != 0)
+    {
+      support_record_failure ();
+      printf ("error: netent comparison failure\n");
+      if (query_description != NULL)
+        printf ("query: %s\n", query_description);
+      support_run_diff ("expected", expected,
+                        "actual", formatted);
+    }
+  free (formatted);
+}
diff --git a/support/check_nss.h b/support/check_nss.h
new file mode 100644
index 0000000..2893f2c
--- /dev/null
+++ b/support/check_nss.h
@@ -0,0 +1,42 @@
+/* Test verification functions for NSS- and DNS-related data.
+   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/>.  */
+
+#ifndef SUPPORT_CHECK_NSS_H
+#define SUPPORT_CHECK_NSS_H
+
+#include <netdb.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Compare the data structures against the expected values (which have
+   to be formatted according to the support_format_* functions in
+   <support/format_nss.h>).  If there is a difference, a delayed test
+   failure is recorded, and a diff is written to standard output.  */
+void check_addrinfo (const char *query_description,
+                     struct addrinfo *, int ret, const char *expected);
+void check_dns_packet (const char *query_description,
+                       const unsigned char *, size_t, const char *expected);
+void check_hostent (const char *query_description,
+                    struct hostent *, const char *expected);
+void check_netent (const char *query_description,
+                   struct netent *, const char *expected);
+
+__END_DECLS
+
+#endif  /* SUPPORT_CHECK_NSS_H */
diff --git a/support/delayed_exit.c b/support/delayed_exit.c
new file mode 100644
index 0000000..67442f9
--- /dev/null
+++ b/support/delayed_exit.c
@@ -0,0 +1,55 @@
+/* Time-triggered process termination.
+   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/xthread.h>
+#include <support/xsignal.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <time.h>
+
+static void *
+delayed_exit_thread (void *seconds_as_ptr)
+{
+  int seconds = (uintptr_t) seconds_as_ptr;
+  struct timespec delay = { seconds, 0 };
+  struct timespec remaining = { 0 };
+  if (nanosleep (&delay, &remaining) != 0)
+    FAIL_EXIT1 ("nanosleep: %m");
+  /* Exit the process sucessfully.  */
+  exit (0);
+  return NULL;
+}
+
+void
+delayed_exit (int seconds)
+{
+  /* Create the new thread with all signals blocked.  */
+  sigset_t all_blocked;
+  sigfillset (&all_blocked);
+  sigset_t old_set;
+  xpthread_sigmask (SIG_SETMASK, &all_blocked, &old_set);
+  /* Create a detached thread. */
+  pthread_t thr = xpthread_create
+    (NULL, delayed_exit_thread, (void *) (uintptr_t) seconds);
+  xpthread_detach (thr);
+  /* Restore the original signal mask.  */
+  xpthread_sigmask (SIG_SETMASK, &old_set, NULL);
+}
diff --git a/support/format_nss.h b/support/format_nss.h
new file mode 100644
index 0000000..fb4597c
--- /dev/null
+++ b/support/format_nss.h
@@ -0,0 +1,41 @@
+/* String formatting functions for NSS- and DNS-related data.
+   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/>.  */
+
+#ifndef SUPPORT_FORMAT_NSS_H
+#define SUPPORT_FORMAT_NSS_H
+
+#include <netdb.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* The following functions format their arguments as human-readable
+   strings (which can span multiple lines).  The caller must free the
+   returned buffer.  For NULL pointers or failure status arguments,
+   error variables such as h_errno and errno are included in the
+   result.  */
+char *support_format_address_family (int);
+char *support_format_addrinfo (struct addrinfo *, int ret);
+char *support_format_dns_packet (const unsigned char *buffer, size_t length);
+char *support_format_herrno (int);
+char *support_format_hostent (struct hostent *);
+char *support_format_netent (struct netent *);
+
+__END_DECLS
+
+#endif  /* SUPPORT_FORMAT_NSS_H */
diff --git a/support/ignore_stderr.c b/support/ignore_stderr.c
new file mode 100644
index 0000000..7b77a2c
--- /dev/null
+++ b/support/ignore_stderr.c
@@ -0,0 +1,38 @@
+/* Avoid all the buffer overflow messages on stderr.
+   Copyright (C) 2015-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 <fcntl.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void
+ignore_stderr (void)
+{
+  int fd = open (_PATH_DEVNULL, O_WRONLY);
+  if (fd == -1)
+    close (STDERR_FILENO);
+  else
+    {
+      dup2 (fd, STDERR_FILENO);
+      close (fd);
+    }
+  setenv ("LIBC_FATAL_STDERR_", "1", 1);
+}
diff --git a/support/namespace.h b/support/namespace.h
new file mode 100644
index 0000000..e1ccaa1
--- /dev/null
+++ b/support/namespace.h
@@ -0,0 +1,65 @@
+/* Entering namespaces for test case isolation.
+   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/>.  */
+
+#ifndef SUPPORT_NAMESPACE_H
+#define SUPPORT_NAMESPACE_H
+
+#include <stdbool.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Attempts to become root (or acquire root-like privileges), possibly
+   with the help of user namespaces.  Return true if (restricted) root
+   privileges could be attained in some way.  Print diagnostics to
+   standard output.
+
+   Note that this function generally has to be called before a process
+   becomes multi-threaded, otherwise it may fail with insufficient
+   privileges on systems which would support this operation for
+   single-threaded processes.  */
+bool support_become_root (void);
+
+/* Return true if this process can perform a chroot operation.  In
+   general, this is only possible if support_become_root has been
+   called.  Note that the actual test is performed in a subprocess,
+   after fork, so that the file system root of the original process is
+   not changed.  */
+bool support_can_chroot (void);
+
+/* Enter a network namespace (and a UTS namespace if possible) and
+   configure the loopback interface.  Return true if a network
+   namespace could be created.  Print diagnostics to standard output.
+   If a network namespace could be created, but networking in it could
+   not be configured, terminate the process.  It is recommended to
+   call support_become_root before this function so that the process
+   has sufficient privileges.  */
+bool support_enter_network_namespace (void);
+
+/* Return true if support_enter_network_namespace managed to enter a
+   UTS namespace.  */
+bool support_in_uts_namespace (void);
+
+/* Invoke CALLBACK (CLOSURE) in a subprocess created using fork.
+   Terminate the calling process if the subprocess exits with a
+   non-zero exit status.  */
+void support_isolate_in_subprocess (void (*callback) (void *), void *closure);
+
+__END_DECLS
+
+#endif
diff --git a/support/oom_error.c b/support/oom_error.c
new file mode 100644
index 0000000..7816978
--- /dev/null
+++ b/support/oom_error.c
@@ -0,0 +1,29 @@
+/* Reporting out-of-memory errors.
+   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 <stdio.h>
+#include <stdlib.h>
+
+void
+oom_error (const char *function, size_t size)
+{
+  printf ("%s: unable to allocate %zu bytes: %m\n", function, size);
+  exit (1);
+}
diff --git a/support/resolv_test.c b/support/resolv_test.c
new file mode 100644
index 0000000..050cd71
--- /dev/null
+++ b/support/resolv_test.c
@@ -0,0 +1,1202 @@
+/* DNS test framework and libresolv redirection.
+   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/resolv_test.h>
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <nss.h>
+#include <resolv.h>
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+#include <support/xsocket.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+/* Response builder.  */
+
+enum
+  {
+    max_response_length = 65536
+  };
+
+/* List of pointers to be freed.  The hash table implementation
+   (struct hsearch_data) does not provide a way to deallocate all
+   objects, so this approach is used to avoid memory leaks.  */
+struct to_be_freed
+{
+  struct to_be_freed *next;
+  void *ptr;
+};
+
+struct resolv_response_builder
+{
+  const unsigned char *query_buffer;
+  size_t query_length;
+
+  size_t offset;                /* Bytes written so far in buffer.  */
+  ns_sect section;              /* Current section in the DNS packet.  */
+  unsigned int truncate_bytes;  /* Bytes to remove at end of response. */
+  bool drop;                    /* Discard generated response.  */
+  bool close;                   /* Close TCP client connection.  */
+
+  /* Offset of the two-byte RDATA length field in the currently
+     written RDATA sub-structure.  0 if no RDATA is being written.  */
+  size_t current_rdata_offset;
+
+  /* Hash table for locating targets for label compression.  */
+  struct hsearch_data compression_offsets;
+  /* List of pointers which need to be freed.  Used for domain names
+     involved in label compression.  */
+  struct to_be_freed *to_be_freed;
+
+  /* Must be last.  Not zeroed for performance reasons.  */
+  unsigned char buffer[max_response_length];
+};
+
+/* Response builder. */
+
+/* Add a pointer to the list of pointers to be freed when B is
+   deallocated.  */
+static void
+response_push_pointer_to_free (struct resolv_response_builder *b, void *ptr)
+{
+  if (ptr == NULL)
+    return;
+  struct to_be_freed *e = xmalloc (sizeof (*e));
+  *e = (struct to_be_freed) {b->to_be_freed, ptr};
+  b->to_be_freed = e;
+}
+
+void
+resolv_response_init (struct resolv_response_builder *b,
+                      struct resolv_response_flags flags)
+{
+  if (b->offset > 0)
+    FAIL_EXIT1 ("response_init: called at offset %zu", b->offset);
+  if (b->query_length < 12)
+    FAIL_EXIT1 ("response_init called for a query of size %zu",
+                b->query_length);
+  if (flags.rcode > 15)
+    FAIL_EXIT1 ("response_init: invalid RCODE %u", flags.rcode);
+
+  /* Copy the transaction ID.  */
+  b->buffer[0] = b->query_buffer[0];
+  b->buffer[1] = b->query_buffer[1];
+
+  /* Initialize the flags.  */
+  b->buffer[2] = 0x80;                       /* Mark as response.   */
+  b->buffer[2] |= b->query_buffer[2] & 0x01; /* Copy the RD bit.  */
+  if (flags.tc)
+    b->buffer[2] |= 0x02;
+  b->buffer[3] = 0x80 | flags.rcode; /* Always set RA.  */
+
+  /* Fill in the initial section count values.  */
+  b->buffer[4] = flags.qdcount >> 8;
+  b->buffer[5] = flags.qdcount;
+  b->buffer[6] = flags.ancount >> 8;
+  b->buffer[7] = flags.ancount;
+  b->buffer[8] = flags.nscount >> 8;
+  b->buffer[9] = flags.nscount;
+  b->buffer[10] = flags.adcount >> 8;
+  b->buffer[11] = flags.adcount;
+
+  b->offset = 12;
+}
+
+void
+resolv_response_section (struct resolv_response_builder *b, ns_sect section)
+{
+  if (b->offset == 0)
+    FAIL_EXIT1 ("resolv_response_section: response_init not called before");
+  if (section < b->section)
+    FAIL_EXIT1 ("resolv_response_section: cannot go back to previous section");
+  b->section = section;
+}
+
+/* Add a single byte to B.  */
+static inline void
+response_add_byte (struct resolv_response_builder *b, unsigned char ch)
+{
+  if (b->offset == max_response_length)
+    FAIL_EXIT1 ("DNS response exceeds 64 KiB limit");
+  b->buffer[b->offset] = ch;
+  ++b->offset;
+}
+
+/* Add a 16-bit word VAL to B, in big-endian format.  */
+static void
+response_add_16 (struct resolv_response_builder *b, uint16_t val)
+{
+  response_add_byte (b, val >> 8);
+  response_add_byte (b, val);
+}
+
+/* Increment the pers-section record counter in the packet header.  */
+static void
+response_count_increment (struct resolv_response_builder *b)
+{
+  unsigned int offset = b->section;
+  offset = 4 + 2 * offset;
+  ++b->buffer[offset + 1];
+  if (b->buffer[offset + 1] == 0)
+    {
+      /* Carry.  */
+      ++b->buffer[offset];
+      if (b->buffer[offset] == 0)
+        /* Overflow.  */
+        FAIL_EXIT1 ("too many records in section");
+    }
+}
+
+void
+resolv_response_add_question (struct resolv_response_builder *b,
+                              const char *name, uint16_t class, uint16_t type)
+{
+  if (b->offset == 0)
+    FAIL_EXIT1 ("resolv_response_add_question: "
+                "resolv_response_init not called");
+  if (b->section != ns_s_qd)
+    FAIL_EXIT1 ("resolv_response_add_question: "
+                "must be called in the question section");
+
+  resolv_response_add_name (b, name);
+  response_add_16 (b, type);
+  response_add_16 (b, class);
+
+  response_count_increment (b);
+}
+
+void
+resolv_response_add_name (struct resolv_response_builder *b,
+                          const char *const origname)
+{
+  /* Normalized name.  */
+  char *name;
+  /* Normalized name with case preserved.  */
+  char *name_case;
+  {
+    size_t namelen = strlen (origname);
+    /* Remove trailing dots.  FIXME: Handle trailing quoted dots.  */
+    while (namelen > 0 && origname[namelen - 1] == '.')
+      --namelen;
+    name = xmalloc (namelen + 1);
+    name_case = xmalloc (namelen + 1);
+    /* Copy and convert to lowercase.  FIXME: This needs to normalize
+       escaping as well.  */
+    for (size_t i = 0; i < namelen; ++i)
+      {
+        char ch = origname[i];
+        name_case[i] = ch;
+        if ('A' <= ch && ch <= 'Z')
+          ch = ch - 'A' + 'a';
+        name[i] = ch;
+      }
+    name[namelen] = 0;
+    name_case[namelen] = 0;
+  }
+  char *name_start = name;
+  char *name_case_start = name_case;
+
+  bool compression = false;
+  while (*name)
+    {
+      /* Search for a previous name we can reference.  */
+      ENTRY new_entry =
+        {
+          .key = name,
+          .data = (void *) (uintptr_t) b->offset,
+        };
+
+      /* If the label can be a compression target because it is at a
+         reachable offset, add it to the hash table.  */
+      ACTION action;
+      if (b->offset < (1 << 12))
+        action = ENTER;
+      else
+        action = FIND;
+
+      /* Search for known compression offsets in the hash table.  */
+      ENTRY *e;
+      if (hsearch_r (new_entry, action, &e, &b->compression_offsets) == 0)
+        {
+          if (action == FIND && errno == ESRCH)
+            /* Fall through.  */
+            e = NULL;
+          else
+            FAIL_EXIT1 ("hsearch_r failure in name compression: %m");
+        }
+
+      /* The name is known.  Reference the previous location.  */
+      if (e != NULL && e->data != new_entry.data)
+        {
+          size_t old_offset = (uintptr_t) e->data;
+          response_add_byte (b, 0xC0 | (old_offset >> 8));
+          response_add_byte (b, old_offset);
+          compression = true;
+          break;
+        }
+
+      /* The name does not exist yet.  Write one label.  First, add
+         room for the label length.  */
+      size_t buffer_label_offset = b->offset;
+      response_add_byte (b, 0);
+
+      /* Copy the label.  */
+      while (true)
+        {
+          char ch = *name_case;
+          if (ch == '\0')
+            break;
+          ++name;
+          ++name_case;
+          if (ch == '.')
+            break;
+          /* FIXME: Handle escaping.  */
+          response_add_byte (b, ch);
+        }
+
+      /* Patch in the label length.  */
+      size_t label_length = b->offset - buffer_label_offset - 1;
+      if (label_length == 0)
+        FAIL_EXIT1 ("empty label in name compression: %s", origname);
+      if (label_length > 63)
+        FAIL_EXIT1 ("label too long in name compression: %s", origname);
+      b->buffer[buffer_label_offset] = label_length;
+
+      /* Continue with the tail of the name and the next label.  */
+    }
+
+  if (compression)
+    {
+      /* If we found an immediate match for the name, we have not put
+         it into the hash table, and can free it immediately.  */
+      if (name == name_start)
+        free (name_start);
+      else
+        response_push_pointer_to_free (b, name_start);
+    }
+  else
+    {
+      /* Terminate the sequence of labels.  With compression, this is
+         implicit in the compression reference.  */
+      response_add_byte (b, 0);
+      response_push_pointer_to_free (b, name_start);
+    }
+
+  free (name_case_start);
+}
+
+void
+resolv_response_open_record (struct resolv_response_builder *b,
+                             const char *name,
+                             uint16_t class, uint16_t type, uint32_t ttl)
+{
+  if (b->section == ns_s_qd)
+    FAIL_EXIT1 ("resolv_response_open_record called in question section");
+  if (b->current_rdata_offset != 0)
+    FAIL_EXIT1 ("resolv_response_open_record called with open record");
+
+  resolv_response_add_name (b, name);
+  response_add_16 (b, type);
+  response_add_16 (b, class);
+  response_add_16 (b, ttl >> 16);
+  response_add_16 (b, ttl);
+
+  b->current_rdata_offset = b->offset;
+  /* Add room for the RDATA length.  */
+  response_add_16 (b, 0);
+}
+
+
+void
+resolv_response_close_record (struct resolv_response_builder *b)
+{
+  size_t rdata_offset = b->current_rdata_offset;
+  if (rdata_offset == 0)
+    FAIL_EXIT1 ("response_close_record called without open record");
+  size_t rdata_length = b->offset - rdata_offset - 2;
+  if (rdata_length > 65535)
+    FAIL_EXIT1 ("RDATA length %zu exceeds limit", rdata_length);
+  b->buffer[rdata_offset] = rdata_length >> 8;
+  b->buffer[rdata_offset + 1] = rdata_length;
+  response_count_increment (b);
+  b->current_rdata_offset = 0;
+}
+
+void
+resolv_response_add_data (struct resolv_response_builder *b,
+                          const void *data, size_t length)
+{
+  size_t remaining = max_response_length - b->offset;
+  if (remaining < length)
+    FAIL_EXIT1 ("resolv_response_add_data: not enough room for %zu bytes",
+                length);
+  memcpy (b->buffer + b->offset, data, length);
+  b->offset += length;
+}
+
+void
+resolv_response_drop (struct resolv_response_builder *b)
+{
+  b->drop = true;
+}
+
+void
+resolv_response_close (struct resolv_response_builder *b)
+{
+  b->close = true;
+}
+
+void
+resolv_response_truncate_data (struct resolv_response_builder *b, size_t count)
+{
+  if (count > 65535)
+    FAIL_EXIT1 ("resolv_response_truncate_data: argument too large: %zu",
+                count);
+  b->truncate_bytes = count;
+}
+
+
+size_t
+resolv_response_length (const struct resolv_response_builder *b)
+{
+  return b->offset;
+}
+
+unsigned char *
+resolv_response_buffer (const struct resolv_response_builder *b)
+{
+  unsigned char *result = xmalloc (b->offset);
+  memcpy (result, b->buffer, b->offset);
+  return result;
+}
+
+static struct resolv_response_builder *
+response_builder_allocate
+  (const unsigned char *query_buffer, size_t query_length)
+{
+  struct resolv_response_builder *b = xmalloc (sizeof (*b));
+  memset (b, 0, offsetof (struct resolv_response_builder, buffer));
+  b->query_buffer = query_buffer;
+  b->query_length = query_length;
+  TEST_VERIFY_EXIT (hcreate_r (10000, &b->compression_offsets) != 0);
+  return b;
+}
+
+static void
+response_builder_free (struct resolv_response_builder *b)
+{
+  struct to_be_freed *current = b->to_be_freed;
+  while (current != NULL)
+    {
+      struct to_be_freed *next = current->next;
+      free (current->ptr);
+      free (current);
+      current = next;
+    }
+  hdestroy_r (&b->compression_offsets);
+  free (b);
+}
+
+/* DNS query processing. */
+
+/* Data extracted from the question section of a DNS packet.  */
+struct query_info
+{
+  char qname[MAXDNAME];
+  uint16_t qclass;
+  uint16_t qtype;
+  struct resolv_edns_info edns;
+};
+
+/* Update *INFO from the specified DNS packet.  */
+static void
+parse_query (struct query_info *info,
+             const unsigned char *buffer, size_t length)
+{
+  HEADER hd;
+  _Static_assert (sizeof (hd) == 12, "DNS header size");
+  if (length < sizeof (hd))
+    FAIL_EXIT1 ("malformed DNS query: too short: %zu bytes", length);
+  memcpy (&hd, buffer, sizeof (hd));
+
+  if (ntohs (hd.qdcount) != 1)
+    FAIL_EXIT1 ("malformed DNS query: wrong question count: %d",
+                (int) ntohs (hd.qdcount));
+  if (ntohs (hd.ancount) != 0)
+    FAIL_EXIT1 ("malformed DNS query: wrong answer count: %d",
+                (int) ntohs (hd.ancount));
+  if (ntohs (hd.nscount) != 0)
+    FAIL_EXIT1 ("malformed DNS query: wrong authority count: %d",
+                (int) ntohs (hd.nscount));
+  if (ntohs (hd.arcount) > 1)
+    FAIL_EXIT1 ("malformed DNS query: wrong additional count: %d",
+                (int) ntohs (hd.arcount));
+
+  int ret = dn_expand (buffer, buffer + length, buffer + sizeof (hd),
+                       info->qname, sizeof (info->qname));
+  if (ret < 0)
+    FAIL_EXIT1 ("malformed DNS query: cannot uncompress QNAME");
+
+  /* Obtain QTYPE and QCLASS.  */
+  size_t remaining = length - (12 + ret);
+  struct
+  {
+    uint16_t qtype;
+    uint16_t qclass;
+  } qtype_qclass;
+  if (remaining < sizeof (qtype_qclass))
+    FAIL_EXIT1 ("malformed DNS query: "
+                "query lacks QCLASS/QTYPE, QNAME: %s", info->qname);
+  memcpy (&qtype_qclass, buffer + 12 + ret, sizeof (qtype_qclass));
+  info->qclass = ntohs (qtype_qclass.qclass);
+  info->qtype = ntohs (qtype_qclass.qtype);
+
+  memset (&info->edns, 0, sizeof (info->edns));
+  if (ntohs (hd.arcount) > 0)
+    {
+      /* Parse EDNS record.  */
+      struct __attribute__ ((packed, aligned (1)))
+      {
+        uint8_t root;
+        uint16_t rtype;
+        uint16_t payload;
+        uint8_t edns_extended_rcode;
+        uint8_t edns_version;
+        uint16_t flags;
+        uint16_t rdatalen;
+      } rr;
+      _Static_assert (sizeof (rr) == 11, "EDNS record size");
+
+      if (remaining < 4 + sizeof (rr))
+        FAIL_EXIT1 ("mailformed DNS query: no room for EDNS record");
+      memcpy (&rr, buffer + 12 + ret + 4, sizeof (rr));
+      if (rr.root != 0)
+        FAIL_EXIT1 ("malformed DNS query: invalid OPT RNAME: %d\n", rr.root);
+      if (rr.rtype != htons (41))
+        FAIL_EXIT1 ("malformed DNS query: invalid OPT type: %d\n",
+                    ntohs (rr.rtype));
+      info->edns.active = true;
+      info->edns.extended_rcode = rr.edns_extended_rcode;
+      info->edns.version = rr.edns_version;
+      info->edns.flags = ntohs (rr.flags);
+      info->edns.payload_size = ntohs (rr.payload);
+    }
+}
+
+
+/* Main testing framework.  */
+
+/* Per-server information.  One struct is allocated for each test
+   server.  */
+struct resolv_test_server
+{
+  /* Local address of the server.  UDP and TCP use the same port.  */
+  struct sockaddr_in address;
+
+  /* File descriptor of the UDP server, or -1 if this server is
+     disabled.  */
+  int socket_udp;
+
+  /* File descriptor of the TCP server, or -1 if this server is
+     disabled.  */
+  int socket_tcp;
+
+  /* Counter of the number of responses processed so far.  */
+  size_t response_number;
+
+  /* Thread handles for the server threads (if not disabled in the
+     configuration).  */
+  pthread_t thread_udp;
+  pthread_t thread_tcp;
+};
+
+/* Main struct for keeping track of libresolv redirection and
+   testing.  */
+struct resolv_test
+{
+  /* After initialization, any access to the struct must be performed
+     while this lock is acquired.  */
+  pthread_mutex_t lock;
+
+  /* Data for each test server. */
+  struct resolv_test_server servers[resolv_max_test_servers];
+
+  /* Used if config.single_thread_udp is true.  */
+  pthread_t thread_udp_single;
+
+  struct resolv_redirect_config config;
+  bool termination_requested;
+};
+
+/* Function implementing a server thread.  */
+typedef void (*thread_callback) (struct resolv_test *, int server_index);
+
+/* Storage for thread-specific data, for passing to the
+   thread_callback function.  */
+struct thread_closure
+{
+  struct resolv_test *obj;      /* Current test object.  */
+  thread_callback callback;     /* Function to call.  */
+  int server_index;             /* Index of the implemented server.  */
+};
+
+/* Wrap response_callback as a function which can be passed to
+   pthread_create.  */
+static void *
+thread_callback_wrapper (void *arg)
+{
+  struct thread_closure *closure = arg;
+  closure->callback (closure->obj, closure->server_index);
+  free (closure);
+  return NULL;
+}
+
+/* Start a server thread for the specified SERVER_INDEX, implemented
+   by CALLBACK.  */
+static pthread_t
+start_server_thread (struct resolv_test *obj, int server_index,
+                     thread_callback callback)
+{
+  struct thread_closure *closure = xmalloc (sizeof (*closure));
+  *closure = (struct thread_closure)
+    {
+      .obj = obj,
+      .callback = callback,
+      .server_index = server_index,
+    };
+  return xpthread_create (NULL, thread_callback_wrapper, closure);
+}
+
+/* Process one UDP query.  Return false if a termination requested has
+   been detected.  */
+static bool
+server_thread_udp_process_one (struct resolv_test *obj, int server_index)
+{
+  unsigned char query[512];
+  struct sockaddr_storage peer;
+  socklen_t peerlen = sizeof (peer);
+  size_t length = xrecvfrom (obj->servers[server_index].socket_udp,
+                             query, sizeof (query), 0,
+                             (struct sockaddr *) &peer, &peerlen);
+  /* Check for termination.  */
+  {
+    bool termination_requested;
+    xpthread_mutex_lock (&obj->lock);
+    termination_requested = obj->termination_requested;
+    xpthread_mutex_unlock (&obj->lock);
+    if (termination_requested)
+      return false;
+  }
+
+
+  struct query_info qinfo;
+  parse_query (&qinfo, query, length);
+  if (test_verbose > 0)
+    {
+      if (test_verbose > 1)
+        printf ("info: UDP server %d: incoming query:"
+                " %zd bytes, %s/%u/%u, tnxid=0x%02x%02x\n",
+                server_index, length, qinfo.qname, qinfo.qclass, qinfo.qtype,
+                query[0], query[1]);
+      else
+        printf ("info: UDP server %d: incoming query:"
+                " %zd bytes, %s/%u/%u\n",
+                server_index, length, qinfo.qname, qinfo.qclass, qinfo.qtype);
+    }
+
+  struct resolv_response_context ctx =
+    {
+      .query_buffer = query,
+      .query_length = length,
+      .server_index = server_index,
+      .tcp = false,
+      .edns = qinfo.edns,
+    };
+  struct resolv_response_builder *b = response_builder_allocate (query, length);
+  obj->config.response_callback
+    (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype);
+
+  if (b->drop)
+    {
+      if (test_verbose)
+        printf ("info: UDP server %d: dropping response to %s/%u/%u\n",
+                server_index, qinfo.qname, qinfo.qclass, qinfo.qtype);
+    }
+  else
+    {
+      if (test_verbose)
+        {
+          if (b->offset >= 12)
+            printf ("info: UDP server %d: sending response:"
+                    " %zu bytes, RCODE %d (for %s/%u/%u)\n",
+                    server_index, b->offset, b->buffer[3] & 0x0f,
+                    qinfo.qname, qinfo.qclass, qinfo.qtype);
+          else
+            printf ("info: UDP server %d: sending response: %zu bytes"
+                    " (for %s/%u/%u)\n",
+                    server_index, b->offset,
+                    qinfo.qname, qinfo.qclass, qinfo.qtype);
+          if (b->truncate_bytes > 0)
+            printf ("info:    truncated by %u bytes\n", b->truncate_bytes);
+        }
+      size_t to_send = b->offset;
+      if (to_send < b->truncate_bytes)
+        to_send = 0;
+      else
+        to_send -= b->truncate_bytes;
+
+      /* Ignore most errors here because the other end may have closed
+         the socket. */
+      if (sendto (obj->servers[server_index].socket_udp,
+                  b->buffer, to_send, 0,
+                  (struct sockaddr *) &peer, peerlen) < 0)
+        TEST_VERIFY_EXIT (errno != EBADF);
+    }
+  response_builder_free (b);
+  return true;
+}
+
+/* UDP thread_callback function.  Variant for one thread per
+   server.  */
+static void
+server_thread_udp (struct resolv_test *obj, int server_index)
+{
+  while (server_thread_udp_process_one (obj, server_index))
+    ;
+}
+
+/* Single-threaded UDP processing function, for the single_thread_udp
+   case.  */
+static void *
+server_thread_udp_single (void *closure)
+{
+  struct resolv_test *obj = closure;
+
+  struct pollfd fds[resolv_max_test_servers];
+  for (int server_index = 0; server_index < resolv_max_test_servers;
+       ++server_index)
+    if (obj->config.servers[server_index].disable_udp)
+      fds[server_index] = (struct pollfd) {.fd = -1};
+    else
+      {
+        fds[server_index] = (struct pollfd)
+          {
+            .fd = obj->servers[server_index].socket_udp,
+            .events = POLLIN
+          };
+
+        /* Make the socket non-blocking.  */
+        int flags = fcntl (obj->servers[server_index].socket_udp, F_GETFL, 0);
+        if (flags < 0)
+          FAIL_EXIT1 ("fcntl (F_GETFL): %m");
+        flags |= O_NONBLOCK;
+        if (fcntl (obj->servers[server_index].socket_udp, F_SETFL, flags) < 0)
+          FAIL_EXIT1 ("fcntl (F_SETFL): %m");
+      }
+
+  while (true)
+    {
+      xpoll (fds, resolv_max_test_servers, -1);
+      for (int server_index = 0; server_index < resolv_max_test_servers;
+           ++server_index)
+        if (fds[server_index].revents != 0)
+          {
+            if (!server_thread_udp_process_one (obj, server_index))
+              goto out;
+            fds[server_index].revents = 0;
+          }
+    }
+
+ out:
+  return NULL;
+}
+
+/* Start the single UDP handler thread (for the single_thread_udp
+   case).  */
+static void
+start_server_thread_udp_single (struct resolv_test *obj)
+{
+  obj->thread_udp_single
+    = xpthread_create (NULL, server_thread_udp_single, obj);
+}
+
+/* Data describing a TCP client connect.  */
+struct tcp_thread_closure
+{
+  struct resolv_test *obj;
+  int server_index;
+  int client_socket;
+};
+
+/* Read a complete DNS query packet.  If EOF_OK, an immediate
+   end-of-file condition is acceptable.  */
+static bool
+read_fully (int fd, void *buf, size_t len, bool eof_ok)
+{
+  const void *const end = buf + len;
+  while (buf < end)
+    {
+      ssize_t ret = read (fd, buf, end - buf);
+      if (ret == 0)
+        {
+          if (!eof_ok)
+            {
+              support_record_failure ();
+              printf ("error: unexpected EOF on TCP connection\n");
+            }
+          return false;
+        }
+      else if (ret < 0)
+        {
+          if (!eof_ok || errno != ECONNRESET)
+            {
+              support_record_failure ();
+              printf ("error: TCP read: %m\n");
+            }
+          return false;
+        }
+      buf += ret;
+      eof_ok = false;
+    }
+  return true;
+}
+
+/* Write an array of iovecs.  Terminate the process on failure.  */
+static void
+writev_fully (int fd, struct iovec *buffers, size_t count)
+{
+  while (count > 0)
+    {
+      /* Skip zero-length write requests.  */
+      if (buffers->iov_len == 0)
+        {
+          ++buffers;
+          --count;
+          continue;
+        }
+      /* Try to rewrite the remaing buffers.  */
+      ssize_t ret = writev (fd, buffers, count);
+      if (ret < 0)
+        FAIL_EXIT1 ("writev: %m");
+      if (ret == 0)
+        FAIL_EXIT1 ("writev: invalid return value zero");
+      /* Find the buffers that were successfully written.  */
+      while (ret > 0)
+        {
+          if (count == 0)
+            FAIL_EXIT1 ("internal writev consistency failure");
+          /* Current buffer was partially written.  */
+          if (buffers->iov_len > (size_t) ret)
+            {
+              buffers->iov_base += ret;
+              buffers->iov_len -= ret;
+              ret = 0;
+            }
+          else
+            {
+              ret -= buffers->iov_len;
+              buffers->iov_len = 0;
+              ++buffers;
+              --count;
+            }
+        }
+    }
+}
+
+/* Thread callback for handling a single established TCP connection to
+   a client.  */
+static void *
+server_thread_tcp_client (void *arg)
+{
+  struct tcp_thread_closure *closure = arg;
+
+  while (true)
+    {
+      /* Read packet length.  */
+      uint16_t query_length;
+      if (!read_fully (closure->client_socket,
+                       &query_length, sizeof (query_length), true))
+        break;
+      query_length = ntohs (query_length);
+
+      /* Read the packet.  */
+      unsigned char *query_buffer = xmalloc (query_length);
+      read_fully (closure->client_socket, query_buffer, query_length, false);
+
+      struct query_info qinfo;
+      parse_query (&qinfo, query_buffer, query_length);
+      if (test_verbose > 0)
+        {
+          if (test_verbose > 1)
+            printf ("info: UDP server %d: incoming query:"
+                    " %d bytes, %s/%u/%u, tnxid=0x%02x%02x\n",
+                    closure->server_index, query_length,
+                    qinfo.qname, qinfo.qclass, qinfo.qtype,
+                    query_buffer[0], query_buffer[1]);
+          else
+            printf ("info: TCP server %d: incoming query:"
+                    " %u bytes, %s/%u/%u\n",
+                    closure->server_index, query_length,
+                    qinfo.qname, qinfo.qclass, qinfo.qtype);
+        }
+
+      struct resolv_response_context ctx =
+        {
+          .query_buffer = query_buffer,
+          .query_length = query_length,
+          .server_index = closure->server_index,
+          .tcp = true,
+          .edns = qinfo.edns,
+        };
+      struct resolv_response_builder *b = response_builder_allocate
+        (query_buffer, query_length);
+      closure->obj->config.response_callback
+        (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype);
+
+      if (b->drop)
+        {
+          if (test_verbose)
+            printf ("info: TCP server %d: dropping response to %s/%u/%u\n",
+                    closure->server_index,
+                    qinfo.qname, qinfo.qclass, qinfo.qtype);
+        }
+      else
+        {
+          if (test_verbose)
+            printf ("info: TCP server %d: sending response: %zu bytes"
+                    " (for %s/%u/%u)\n",
+                    closure->server_index, b->offset,
+                    qinfo.qname, qinfo.qclass, qinfo.qtype);
+          uint16_t length = htons (b->offset);
+          size_t to_send = b->offset;
+          if (to_send < b->truncate_bytes)
+            to_send = 0;
+          else
+            to_send -= b->truncate_bytes;
+          struct iovec buffers[2] =
+            {
+              {&length, sizeof (length)},
+              {b->buffer, to_send}
+            };
+          writev_fully (closure->client_socket, buffers, 2);
+        }
+      bool close_flag = b->close;
+      response_builder_free (b);
+      free (query_buffer);
+      if (close_flag)
+        break;
+    }
+
+  xclose (closure->client_socket);
+  free (closure);
+  return NULL;
+}
+
+/* thread_callback for the TCP case.  Accept connections and create a
+   new thread for each client.  */
+static void
+server_thread_tcp (struct resolv_test *obj, int server_index)
+{
+  while (true)
+    {
+      /* Get the client conenction.  */
+      int client_socket = xaccept
+        (obj->servers[server_index].socket_tcp, NULL, NULL);
+
+      /* Check for termination.  */
+      xpthread_mutex_lock (&obj->lock);
+      if (obj->termination_requested)
+        {
+          xpthread_mutex_unlock (&obj->lock);
+          xclose (client_socket);
+          break;
+        }
+      xpthread_mutex_unlock (&obj->lock);
+
+      /* Spawn a new thread for handling this connection.  */
+      struct tcp_thread_closure *closure = xmalloc (sizeof (*closure));
+      *closure = (struct tcp_thread_closure)
+        {
+          .obj = obj,
+          .server_index = server_index,
+          .client_socket = client_socket,
+        };
+
+      pthread_t thr
+        = xpthread_create (NULL, server_thread_tcp_client, closure);
+      /* TODO: We should keep track of this thread so that we can
+         block in resolv_test_end until it has exited.  */
+      xpthread_detach (thr);
+    }
+}
+
+/* Create UDP and TCP server sockets.  */
+static void
+make_server_sockets (struct resolv_test_server *server)
+{
+  while (true)
+    {
+      server->socket_udp = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+      server->socket_tcp = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+      /* Pick the address for the UDP socket.  */
+      server->address = (struct sockaddr_in)
+        {
+          .sin_family = AF_INET,
+          .sin_addr = {.s_addr = htonl (INADDR_LOOPBACK)}
+        };
+      xbind (server->socket_udp,
+             (struct sockaddr *)&server->address, sizeof (server->address));
+
+      /* Retrieve the address. */
+      socklen_t addrlen = sizeof (server->address);
+      xgetsockname (server->socket_udp,
+                    (struct sockaddr *)&server->address, &addrlen);
+
+      /* Bind the TCP socket to the same address.  */
+      {
+        int on = 1;
+        xsetsockopt (server->socket_tcp, SOL_SOCKET, SO_REUSEADDR,
+                     &on, sizeof (on));
+      }
+      if (bind (server->socket_tcp,
+                (struct sockaddr *)&server->address,
+                sizeof (server->address)) != 0)
+        {
+          /* Port collision.  The UDP bind succeeded, but the TCP BIND
+             failed.  We assume here that the kernel will pick the
+             next local UDP address randomly.  */
+          if (errno == EADDRINUSE)
+            {
+              xclose (server->socket_udp);
+              xclose (server->socket_tcp);
+              continue;
+            }
+          FAIL_EXIT1 ("TCP bind: %m");
+        }
+      xlisten (server->socket_tcp, 5);
+      break;
+    }
+}
+
+/* One-time initialization of NSS.  */
+static void
+resolv_redirect_once (void)
+{
+  /* Only use nss_dns.  */
+  __nss_configure_lookup ("hosts", "dns");
+  __nss_configure_lookup ("networks", "dns");
+  /* Enter a network namespace for isolation and firewall state
+     cleanup.  The tests will still work if these steps fail, but they
+     may be less reliable.  */
+  support_become_root ();
+  support_enter_network_namespace ();
+}
+pthread_once_t resolv_redirect_once_var = PTHREAD_ONCE_INIT;
+
+void
+resolv_test_init (void)
+{
+  /* Perform one-time initialization of NSS.  */
+  xpthread_once (&resolv_redirect_once_var, resolv_redirect_once);
+}
+
+/* Copy the search path from CONFIG.search to the _res object.  */
+static void
+set_search_path (struct resolv_redirect_config config)
+{
+  memset (_res.defdname, 0, sizeof (_res.defdname));
+  memset (_res.dnsrch, 0, sizeof (_res.dnsrch));
+
+  char *current = _res.defdname;
+  char *end = current + sizeof (_res.defdname);
+
+  for (unsigned int i = 0;
+       i < sizeof (config.search) / sizeof (config.search[0]); ++i)
+    {
+      if (config.search[i] == NULL)
+        continue;
+
+      size_t length = strlen (config.search[i]) + 1;
+      size_t remaining = end - current;
+      TEST_VERIFY_EXIT (length <= remaining);
+      memcpy (current, config.search[i], length);
+      _res.dnsrch[i] = current;
+      current += length;
+    }
+}
+
+struct resolv_test *
+resolv_test_start (struct resolv_redirect_config config)
+{
+  /* Apply configuration defaults.  */
+  if (config.nscount == 0)
+    config.nscount = resolv_max_test_servers;
+
+  struct resolv_test *obj = xmalloc (sizeof (*obj));
+  *obj = (struct resolv_test) {
+    .config = config,
+    .lock = PTHREAD_MUTEX_INITIALIZER,
+  };
+
+  resolv_test_init ();
+
+  /* Create all the servers, to reserve the necessary ports.  */
+  for (int server_index = 0; server_index < config.nscount; ++server_index)
+    make_server_sockets (obj->servers + server_index);
+
+  /* Start server threads.  Disable the server ports, as
+     requested.  */
+  for (int server_index = 0; server_index < config.nscount; ++server_index)
+    {
+      struct resolv_test_server *server = obj->servers + server_index;
+      if (config.servers[server_index].disable_udp)
+        {
+          xclose (server->socket_udp);
+          server->socket_udp = -1;
+        }
+      else if (!config.single_thread_udp)
+        server->thread_udp = start_server_thread (obj, server_index,
+                                                  server_thread_udp);
+      if (config.servers[server_index].disable_tcp)
+        {
+          xclose (server->socket_tcp);
+          server->socket_tcp = -1;
+        }
+      else
+        server->thread_tcp = start_server_thread (obj, server_index,
+                                                  server_thread_tcp);
+    }
+  if (config.single_thread_udp)
+    start_server_thread_udp_single (obj);
+
+  int timeout = 1;
+
+  /* Initialize libresolv.  */
+  TEST_VERIFY_EXIT (res_init () == 0);
+
+  /* Disable IPv6 name server addresses.  The code below only
+     overrides the IPv4 addresses.  */
+  __res_iclose (&_res, true);
+  _res._u._ext.nscount = 0;
+
+  /* Redirect queries to the server socket.  */
+  if (test_verbose)
+    {
+      printf ("info: old timeout value: %d\n", _res.retrans);
+      printf ("info: old retry attempt value: %d\n", _res.retry);
+      printf ("info: old _res.options: 0x%lx\n", _res.options);
+      printf ("info: old _res.nscount value: %d\n", _res.nscount);
+      printf ("info: old _res.ndots value: %d\n", _res.ndots);
+    }
+  _res.retrans = timeout;
+  _res.retry = 4;
+  _res.nscount = config.nscount;
+  _res.options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
+  _res.ndots = 1;
+  if (test_verbose)
+    {
+      printf ("info: new timeout value: %d\n", _res.retrans);
+      printf ("info: new retry attempt value: %d\n", _res.retry);
+      printf ("info: new _res.options: 0x%lx\n", _res.options);
+      printf ("info: new _res.nscount value: %d\n", _res.nscount);
+      printf ("info: new _res.ndots value: %d\n", _res.ndots);
+    }
+  for (int server_index = 0; server_index < config.nscount; ++server_index)
+    {
+      _res.nsaddr_list[server_index] = obj->servers[server_index].address;
+      if (test_verbose)
+        {
+          char buf[256];
+          TEST_VERIFY_EXIT
+            (inet_ntop (AF_INET, &obj->servers[server_index].address.sin_addr,
+                        buf, sizeof (buf)) != NULL);
+          printf ("info: server %d: %s/%u\n",
+                  server_index, buf,
+                  htons (obj->servers[server_index].address.sin_port));
+        }
+    }
+
+  set_search_path (config);
+
+  return obj;
+}
+
+void
+resolv_test_end (struct resolv_test *obj)
+{
+  res_close ();
+
+  xpthread_mutex_lock (&obj->lock);
+  obj->termination_requested = true;
+  xpthread_mutex_unlock (&obj->lock);
+
+  /* Send trigger packets to unblock the server threads.  */
+  for (int server_index = 0; server_index < obj->config.nscount;
+       ++server_index)
+    {
+      if (!obj->config.servers[server_index].disable_udp)
+        {
+          int sock = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+          xsendto (sock, "", 1, 0,
+                   (struct sockaddr *) &obj->servers[server_index].address,
+                   sizeof (obj->servers[server_index].address));
+          xclose (sock);
+        }
+      if (!obj->config.servers[server_index].disable_tcp)
+        {
+          int sock = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+          xconnect (sock,
+                    (struct sockaddr *) &obj->servers[server_index].address,
+                    sizeof (obj->servers[server_index].address));
+          xclose (sock);
+        }
+    }
+
+  if (obj->config.single_thread_udp)
+    xpthread_join (obj->thread_udp_single);
+
+  /* Wait for the server threads to terminate.  */
+  for (int server_index = 0; server_index < obj->config.nscount;
+       ++server_index)
+    {
+      if (!obj->config.servers[server_index].disable_udp)
+        {
+          if (!obj->config.single_thread_udp)
+            xpthread_join (obj->servers[server_index].thread_udp);
+          xclose (obj->servers[server_index].socket_udp);
+        }
+      if (!obj->config.servers[server_index].disable_tcp)
+        {
+          xpthread_join (obj->servers[server_index].thread_tcp);
+          xclose (obj->servers[server_index].socket_tcp);
+        }
+    }
+
+  free (obj);
+}
diff --git a/support/resolv_test.h b/support/resolv_test.h
new file mode 100644
index 0000000..6498751
--- /dev/null
+++ b/support/resolv_test.h
@@ -0,0 +1,180 @@
+/* DNS test framework and libresolv redirection.
+   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/>.  */
+
+#ifndef SUPPORT_RESOLV_TEST_H
+#define SUPPORT_RESOLV_TEST_H
+
+#include <arpa/nameser.h>
+#include <stdbool.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Information about EDNS properties of a DNS query.  */
+struct resolv_edns_info
+{
+  bool active;
+  uint8_t extended_rcode;
+  uint8_t version;
+  uint16_t flags;
+  uint16_t payload_size;
+};
+
+/* This struct provides context information when the response callback
+   specified in struct resolv_redirect_config is invoked. */
+struct resolv_response_context
+{
+  const unsigned char *query_buffer;
+  size_t query_length;
+  int server_index;
+  bool tcp;
+  struct resolv_edns_info edns;
+};
+
+/* This opaque struct is used to construct responses from within the
+   response callback function.  */
+struct resolv_response_builder;
+
+/* This opaque struct collects information about the resolver testing
+   currently in progress.  */
+struct resolv_test;
+
+enum
+  {
+    /* Maximum number of test servers supported by the framework.  */
+    resolv_max_test_servers = 3,
+  };
+
+/* Configuration settings specific to individual test servers.  */
+struct resolv_redirect_server_config
+{
+  bool disable_tcp;             /* If true, no TCP server is listening.  */
+  bool disable_udp;             /* If true, no UDP server is listening.  */
+};
+
+/* Instructions for setting up the libresolv redirection.  */
+struct resolv_redirect_config
+{
+  /* The response_callback function is called for every incoming DNS
+     packet, over UDP or TCP.  It must be specified, the other
+     configuration settings are optional.  */
+  void (*response_callback) (const struct resolv_response_context *,
+                             struct resolv_response_builder *,
+                             const char *qname,
+                             uint16_t qclass, uint16_t qtype);
+
+  /* Per-server configuration.  */
+  struct resolv_redirect_server_config servers[resolv_max_test_servers];
+
+  /* Search path entries.  The first entry serves as the default
+     domain name as well.  */
+  const char *search[7];
+
+  /* Number of servers to activate in resolv.  0 means the default,
+     resolv_max_test_servers.  */
+  int nscount;
+
+  /* If true, use a single thread to process all UDP queries.  This
+     may results in more predictable ordering of queries and
+     responses.  */
+  bool single_thread_udp;
+};
+
+/* Configure NSS to use, nss_dns only for aplicable databases, and try
+   to put the process into a network namespace for better isolation.
+   This may have to be called before resolv_test_start, before the
+   process creates any threads.  Otherwise, initialization is
+   performed by resolv_test_start implicitly.  */
+void resolv_test_init (void);
+
+/* Initiate resolver testing.  This updates the _res variable as
+   needed.  As a side effect, NSS is reconfigured to use nss_dns only
+   for aplicable databases, and the process may enter a network
+   namespace for better isolation.  */
+struct resolv_test *resolv_test_start (struct resolv_redirect_config);
+
+/* Call this function at the end of resolver testing, to free
+   resources and report pending errors (if any).  */
+void resolv_test_end (struct resolv_test *);
+
+/* The remaining facilities in this file are used for constructing
+   response packets from the response_callback function.  */
+
+/* Special settings for constructing responses from the callback.  */
+struct resolv_response_flags
+{
+  /* 4-bit response code to incorporate into the response. */
+  unsigned char rcode;
+
+  /* If true, the TC (truncation) flag will be set.  */
+  bool tc;
+
+  /* Initial section count values.  Can be used to artificially
+     increase the counts, for malformed packet testing.*/
+  unsigned short qdcount;
+  unsigned short ancount;
+  unsigned short nscount;
+  unsigned short adcount;
+};
+
+/* Begin a new response with the requested flags.  Must be called
+   first.  */
+void resolv_response_init (struct resolv_response_builder *,
+                           struct resolv_response_flags);
+
+/* Switches to the section in the response packet.  Only forward
+   movement is supported.  */
+void resolv_response_section (struct resolv_response_builder *, ns_sect);
+
+/* Add a question record to the question section.  */
+void resolv_response_add_question (struct resolv_response_builder *,
+                                   const char *name, uint16_t class,
+                                   uint16_t type);
+/* Starts a new resource record with the specified owner name, class,
+   type, and TTL.  Data is supplied with resolv_response_add_data or
+   resolv_response_add_name.  */
+void resolv_response_open_record (struct resolv_response_builder *,
+                                  const char *name, uint16_t class,
+                                  uint16_t type, uint32_t ttl);
+
+/* Add unstructed bytes to the RDATA part of a resource record.  */
+void resolv_response_add_data (struct resolv_response_builder *,
+                               const void *, size_t);
+
+/* Add a compressed domain name to the RDATA part of a resource
+   record.  */
+void resolv_response_add_name (struct resolv_response_builder *,
+                               const char *name);
+
+/* Mark the end of the constructed record.  Must be called last.  */
+void resolv_response_close_record (struct resolv_response_builder *);
+
+/* Drop this query packet (that is, do not send a response, not even
+   an empty packet).  */
+void resolv_response_drop (struct resolv_response_builder *);
+
+/* In TCP mode, close the connection after this packet (if a response
+   is sent).  */
+void resolv_response_close (struct resolv_response_builder *);
+
+/* The size of the response packet built so far.  */
+size_t resolv_response_length (const struct resolv_response_builder *);
+
+__END_DECLS
+
+#endif /* SUPPORT_RESOLV_TEST_H */
diff --git a/support/run_diff.h b/support/run_diff.h
new file mode 100644
index 0000000..f65b5dd
--- /dev/null
+++ b/support/run_diff.h
@@ -0,0 +1,31 @@
+/* Invoke the system diff tool to compare two strings.
+   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/>.  */
+
+#ifndef SUPPORT_RUN_DIFF_H
+#define SUPPORT_RUN_DIFF_H
+
+/* Compare the two NUL-terminated strings LEFT and RIGHT using the
+   diff tool.  Label the sides of the diff with LEFT_LABEL and
+   RIGHT_LABEL, respectively.
+
+   This function assumes that LEFT and RIGHT are different
+   strings.  */
+void support_run_diff (const char *left_label, const char *left,
+                       const char *right_label, const char *right);
+
+#endif /* SUPPORT_RUN_DIFF_H */
diff --git a/support/set_fortify_handler.c b/support/set_fortify_handler.c
new file mode 100644
index 0000000..f434a80
--- /dev/null
+++ b/support/set_fortify_handler.c
@@ -0,0 +1,34 @@
+/* Set signal handler for use in fortify tests.
+   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 <signal.h>
+
+void
+set_fortify_handler (void (*handler) (int sig))
+{
+  struct sigaction sa;
+
+  sa.sa_handler = handler;
+  sa.sa_flags = 0;
+  sigemptyset (&sa.sa_mask);
+
+  sigaction (SIGABRT, &sa, NULL);
+  ignore_stderr ();
+}
diff --git a/support/support-xstat.c b/support/support-xstat.c
new file mode 100644
index 0000000..86a81ec
--- /dev/null
+++ b/support/support-xstat.c
@@ -0,0 +1,30 @@
+/* stat64 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/>.  */
+
+/* NB: Non-standard file name to avoid sysdeps override for xstat.  */
+
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <sys/stat.h>
+
+void
+xstat (const char *path, struct stat64 *result)
+{
+  if (stat64 (path, result) != 0)
+    FAIL_EXIT1 ("stat64 (\"%s\"): %m", path);
+}
diff --git a/support/support.h b/support/support.h
new file mode 100644
index 0000000..4b5f04c
--- /dev/null
+++ b/support/support.h
@@ -0,0 +1,74 @@
+/* Common extra functions.
+   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/>.  */
+
+/* This header file should only contain definitions compatible with
+   C90.  (Using __attribute__ is fine because <features.h> provides a
+   fallback.)  */
+
+#ifndef SUPPORT_H
+#define SUPPORT_H
+
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Write a message to standard output.  Can be used in signal
+   handlers.  */
+void write_message (const char *message) __attribute__ ((nonnull (1)));
+
+/* Avoid all the buffer overflow messages on stderr.  */
+void ignore_stderr (void);
+
+/* Set fortification error handler.  Used when tests want to verify that bad
+   code is caught by the library.  */
+void set_fortify_handler (void (*handler) (int sig));
+
+/* Report an out-of-memory error for the allocation of SIZE bytes in
+   FUNCTION, terminating the process.  */
+void oom_error (const char *function, size_t size)
+  __attribute__ ((nonnull (1)));
+
+/* Return a pointer to a memory region of SIZE bytes.  The memory is
+   initialized to zero and will be shared with subprocesses (across
+   fork).  The returned pointer must be freed using
+   support_shared_free; it is not compatible with the malloc
+   functions.  */
+void *support_shared_allocate (size_t size);
+
+/* Deallocate a pointer returned by support_shared_allocate.  */
+void support_shared_free (void *);
+
+/* Write CONTENTS to the file PATH.  Create or truncate the file as
+   needed.  The file mode is 0666 masked by the umask.  Terminate the
+   process on error.  */
+void support_write_file_string (const char *path, const char *contents);
+
+/* Error-checking wrapper functions which terminate the process on
+   error.  */
+
+void *xmalloc (size_t) __attribute__ ((malloc));
+void *xcalloc (size_t n, size_t s) __attribute__ ((malloc));
+void *xrealloc (void *p, size_t n);
+char *xasprintf (const char *format, ...)
+  __attribute__ ((format (printf, 1, 2), malloc));
+char *xstrdup (const char *);
+
+__END_DECLS
+
+#endif /* SUPPORT_H */
diff --git a/support/support_become_root.c b/support/support_become_root.c
new file mode 100644
index 0000000..3fa0bd4
--- /dev/null
+++ b/support/support_become_root.c
@@ -0,0 +1,40 @@
+/* Acquire root privileges.
+   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/namespace.h>
+
+#include <sched.h>
+#include <stdio.h>
+#include <unistd.h>
+
+bool
+support_become_root (void)
+{
+#ifdef CLONE_NEWUSER
+  if (unshare (CLONE_NEWUSER | CLONE_NEWNS) == 0)
+    /* Even if we do not have UID zero, we have extended privileges at
+       this point.  */
+    return true;
+#endif
+  if (setuid (0) != 0)
+    {
+      printf ("warning: could not become root outside namespace (%m)\n");
+      return false;
+    }
+  return true;
+}
diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c
new file mode 100644
index 0000000..0dfd2de
--- /dev/null
+++ b/support/support_can_chroot.c
@@ -0,0 +1,65 @@
+/* Return true if the process can perform a chroot operation.
+   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 <stdio.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <xunistd.h>
+
+static void
+callback (void *closure)
+{
+  int *result = closure;
+  struct stat64 before;
+  xstat ("/dev", &before);
+  if (chroot ("/dev") != 0)
+    {
+      *result = errno;
+      return;
+    }
+  struct stat64 after;
+  xstat ("/", &after);
+  TEST_VERIFY (before.st_dev == after.st_dev);
+  TEST_VERIFY (before.st_ino == after.st_ino);
+  *result = 0;
+}
+
+bool
+support_can_chroot (void)
+{
+  int *result = support_shared_allocate (sizeof (*result));
+  *result = 0;
+  support_isolate_in_subprocess (callback, result);
+  bool ok = *result == 0;
+  if (!ok)
+    {
+      static bool already_warned;
+      if (!already_warned)
+        {
+          already_warned = true;
+          errno = *result;
+          printf ("warning: this process does not support chroot: %m\n");
+        }
+    }
+  support_shared_free (result);
+  return ok;
+}
diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
new file mode 100644
index 0000000..030f124
--- /dev/null
+++ b/support/support_capture_subprocess.c
@@ -0,0 +1,108 @@
+/* Capture output from a subprocess.
+   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/capture_subprocess.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <support/xsocket.h>
+
+static void
+transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
+{
+  if (pfd->revents != 0)
+    {
+      char buf[1024];
+      ssize_t ret = TEMP_FAILURE_RETRY (read (pfd->fd, buf, sizeof (buf)));
+      if (ret < 0)
+        {
+          support_record_failure ();
+          printf ("error: reading from subprocess %s: %m", what);
+          pfd->events = 0;
+          pfd->revents = 0;
+        }
+      else if (ret == 0)
+        {
+          /* EOF reached.  Stop listening.  */
+          pfd->events = 0;
+          pfd->revents = 0;
+        }
+      else
+        /* Store the data just read.   */
+        TEST_VERIFY (fwrite (buf, ret, 1, stream->out) == 1);
+    }
+}
+
+struct support_capture_subprocess
+support_capture_subprocess (void (*callback) (void *), void *closure)
+{
+  struct support_capture_subprocess result;
+  xopen_memstream (&result.out);
+  xopen_memstream (&result.err);
+
+  int stdout_pipe[2];
+  xpipe (stdout_pipe);
+  int stderr_pipe[2];
+  xpipe (stderr_pipe);
+
+  TEST_VERIFY (fflush (stdout) == 0);
+  TEST_VERIFY (fflush (stderr) == 0);
+
+  pid_t pid = xfork ();
+  if (pid == 0)
+    {
+      xclose (stdout_pipe[0]);
+      xclose (stderr_pipe[0]);
+      xdup2 (stdout_pipe[1], STDOUT_FILENO);
+      xdup2 (stderr_pipe[1], STDERR_FILENO);
+      callback (closure);
+      _exit (0);
+    }
+  xclose (stdout_pipe[1]);
+  xclose (stderr_pipe[1]);
+
+  struct pollfd fds[2] =
+    {
+      { .fd = stdout_pipe[0], .events = POLLIN },
+      { .fd = stderr_pipe[0], .events = POLLIN },
+    };
+
+  do
+    {
+      xpoll (fds, 2, -1);
+      transfer ("stdout", &fds[0], &result.out);
+      transfer ("stderr", &fds[1], &result.err);
+    }
+  while (fds[0].events != 0 || fds[1].events != 0);
+  xclose (stdout_pipe[0]);
+  xclose (stderr_pipe[0]);
+
+  xfclose_memstream (&result.out);
+  xfclose_memstream (&result.err);
+  xwaitpid (pid, &result.status, 0);
+  return result;
+}
+
+void
+support_capture_subprocess_free (struct support_capture_subprocess *p)
+{
+  free (p->out.buffer);
+  free (p->err.buffer);
+}
diff --git a/support/support_capture_subprocess_check.c b/support/support_capture_subprocess_check.c
new file mode 100644
index 0000000..708c89f
--- /dev/null
+++ b/support/support_capture_subprocess_check.c
@@ -0,0 +1,67 @@
+/* Verify capture output from a subprocess.
+   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 <stdbool.h>
+#include <stdio.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+
+static void
+print_context (const char *context, bool *failed)
+{
+  if (*failed)
+    /* Do not duplicate message.  */
+    return;
+  support_record_failure ();
+  printf ("error: subprocess failed: %s\n", context);
+}
+
+void
+support_capture_subprocess_check (struct support_capture_subprocess *proc,
+                                  const char *context, int status,
+                                  int allowed)
+{
+  TEST_VERIFY ((allowed & sc_allow_none)
+               || (allowed & sc_allow_stdout)
+               || (allowed & sc_allow_stderr));
+  TEST_VERIFY (!((allowed & sc_allow_none)
+                 && ((allowed & sc_allow_stdout)
+                     || (allowed & sc_allow_stderr))));
+
+  bool failed = false;
+  if (proc->status != status)
+    {
+      print_context (context, &failed);
+      printf ("error:   expected exit status: %d\n", status);
+      printf ("error:   actual exit status:   %d\n", status);
+    }
+  if (!(allowed & sc_allow_stdout) && proc->out.length != 0)
+    {
+      print_context (context, &failed);
+      printf ("error:   unexpected output from subprocess\n");
+      fwrite (proc->out.buffer, proc->out.length, 1, stdout);
+      puts ("\n");
+    }
+  if (!(allowed & sc_allow_stderr) && proc->err.length != 0)
+    {
+      print_context (context, &failed);
+      printf ("error:   unexpected error output from subprocess\n");
+      fwrite (proc->err.buffer, proc->err.length, 1, stdout);
+      puts ("\n");
+    }
+}
diff --git a/support/support_enter_network_namespace.c b/support/support_enter_network_namespace.c
new file mode 100644
index 0000000..28b0ee2
--- /dev/null
+++ b/support/support_enter_network_namespace.c
@@ -0,0 +1,75 @@
+/* Enter a network namespace.
+   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/namespace.h>
+
+#include <net/if.h>
+#include <sched.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/xsocket.h>
+#include <support/xunistd.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+static bool in_uts_namespace;
+
+bool
+support_enter_network_namespace (void)
+{
+#ifdef CLONE_NEWUTS
+  if (unshare (CLONE_NEWUTS) == 0)
+    in_uts_namespace = true;
+  else
+    printf ("warning: unshare (CLONE_NEWUTS) failed: %m\n");
+#endif
+
+#ifdef CLONE_NEWNET
+  if (unshare (CLONE_NEWNET) == 0)
+    {
+      /* Bring up the loopback interface.  */
+      int fd = xsocket (AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+      struct ifreq req;
+      strcpy (req.ifr_name, "lo");
+      TEST_VERIFY_EXIT (ioctl (fd, SIOCGIFFLAGS, &req) == 0);
+      bool already_up = req.ifr_flags & IFF_UP;
+      if (already_up)
+        /* This means that we likely have not achieved isolation from
+           the parent namespace.  */
+        printf ("warning: loopback interface already exists"
+                " in new network namespace\n");
+      else
+        {
+          req.ifr_flags |= IFF_UP | IFF_RUNNING;
+          TEST_VERIFY_EXIT (ioctl (fd, SIOCSIFFLAGS, &req) == 0);
+        }
+      xclose (fd);
+
+      return !already_up;
+    }
+#endif
+  printf ("warning: could not enter network namespace\n");
+  return false;
+}
+
+bool
+support_in_uts_namespace (void)
+{
+  return in_uts_namespace;
+}
diff --git a/support/support_format_address_family.c b/support/support_format_address_family.c
new file mode 100644
index 0000000..5d42c42
--- /dev/null
+++ b/support/support_format_address_family.c
@@ -0,0 +1,35 @@
+/* Convert an address family to a string.
+   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/format_nss.h>
+
+#include <support/support.h>
+
+char *
+support_format_address_family (int family)
+{
+  switch (family)
+    {
+    case AF_INET:
+      return xstrdup ("INET");
+    case AF_INET6:
+      return xstrdup ("INET6");
+    default:
+      return xasprintf ("<unknown address family %d>", family);
+    }
+}
diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c
new file mode 100644
index 0000000..eedb030
--- /dev/null
+++ b/support/support_format_addrinfo.c
@@ -0,0 +1,239 @@
+/* Convert struct addrinfo values to a string.
+   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/format_nss.h>
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdio.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+static size_t
+socket_address_length (int family)
+{
+  switch (family)
+    {
+    case AF_INET:
+      return sizeof (struct sockaddr_in);
+    case AF_INET6:
+      return sizeof (struct sockaddr_in6);
+    default:
+      return -1;
+    }
+}
+
+static void
+format_ai_flags_1 (FILE *out, struct addrinfo *ai, int flag, const char *name,
+                   int * flags_printed)
+{
+  if ((ai->ai_flags & flag) != 0)
+    fprintf (out, " %s", name);
+  *flags_printed |= flag;
+}
+
+static void
+format_ai_flags (FILE *out, struct addrinfo *ai)
+{
+  if (ai == NULL)
+    return;
+
+  if (ai->ai_flags != 0)
+    {
+      fprintf (out, "flags:");
+      int flags_printed = 0;
+#define FLAG(flag) format_ai_flags_1 (out, ai, flag, #flag, &flags_printed)
+      FLAG (AI_PASSIVE);
+      FLAG (AI_CANONNAME);
+      FLAG (AI_NUMERICHOST);
+      FLAG (AI_V4MAPPED);
+      FLAG (AI_ALL);
+      FLAG (AI_ADDRCONFIG);
+      FLAG (AI_IDN);
+      FLAG (AI_CANONIDN);
+      FLAG (AI_IDN_ALLOW_UNASSIGNED);
+      FLAG (AI_IDN_USE_STD3_ASCII_RULES);
+      FLAG (AI_NUMERICSERV);
+#undef FLAG
+      int remaining = ai->ai_flags & ~flags_printed;
+      if (remaining != 0)
+        fprintf (out, " %08x", remaining);
+      fprintf (out, "\n");
+    }
+
+  /* Report flag mismatches within the list.  */
+  int flags = ai->ai_flags;
+  int index = 1;
+  ai = ai->ai_next;
+  while (ai != NULL)
+    {
+      if (ai->ai_flags != flags)
+        fprintf (out, "error: flags at %d: 0x%x expected, 0x%x actual\n",
+                 index, flags, ai->ai_flags);
+      ai = ai->ai_next;
+      ++index;
+    }
+}
+
+static void
+format_ai_canonname (FILE *out, struct addrinfo *ai)
+{
+  if (ai == NULL)
+    return;
+  if (ai->ai_canonname != NULL)
+    fprintf (out, "canonname: %s\n", ai->ai_canonname);
+
+  /* Report incorrectly set ai_canonname fields on subsequent list
+     entries.  */
+  int index = 1;
+  ai = ai->ai_next;
+  while (ai != NULL)
+    {
+      if (ai->ai_canonname != NULL)
+        fprintf (out, "error: canonname set at %d: %s\n",
+                 index, ai->ai_canonname);
+      ai = ai->ai_next;
+      ++index;
+    }
+}
+
+static void
+format_ai_one (FILE *out, struct addrinfo *ai)
+{
+  {
+    char type_buf[32];
+    const char *type_str;
+    char proto_buf[32];
+    const char *proto_str;
+
+    /* ai_socktype */
+    switch (ai->ai_socktype)
+      {
+      case SOCK_RAW:
+        type_str = "RAW";
+        break;
+      case SOCK_DGRAM:
+        type_str = "DGRAM";
+        break;
+      case SOCK_STREAM:
+        type_str = "STREAM";
+        break;
+      default:
+        snprintf (type_buf, sizeof (type_buf), "%d", ai->ai_socktype);
+        type_str = type_buf;
+      }
+
+    /* ai_protocol */
+    switch (ai->ai_protocol)
+      {
+      case IPPROTO_IP:
+        proto_str = "IP";
+        break;
+      case IPPROTO_UDP:
+        proto_str = "UDP";
+        break;
+      case IPPROTO_TCP:
+        proto_str = "TCP";
+        break;
+      default:
+        snprintf (proto_buf, sizeof (proto_buf), "%d", ai->ai_protocol);
+        proto_str = proto_buf;
+      }
+    fprintf (out, "address: %s/%s", type_str, proto_str);
+  }
+
+  /* ai_addrlen */
+  if (ai->ai_addrlen != socket_address_length (ai->ai_family))
+    {
+      char *family = support_format_address_family (ai->ai_family);
+      fprintf (out, "error: invalid address length %d for %s\n",
+               ai->ai_addrlen, family);
+      free (family);
+    }
+
+  /* ai_addr */
+  {
+    char buf[128];
+    uint16_t port;
+    const char *ret;
+    switch (ai->ai_family)
+      {
+      case AF_INET:
+        {
+          struct sockaddr_in *sin = (struct sockaddr_in *) ai->ai_addr;
+          ret = inet_ntop (AF_INET, &sin->sin_addr, buf, sizeof (buf));
+          port = sin->sin_port;
+        }
+        break;
+      case AF_INET6:
+        {
+          struct sockaddr_in6 *sin = (struct sockaddr_in6 *) ai->ai_addr;
+          ret = inet_ntop (AF_INET6, &sin->sin6_addr, buf, sizeof (buf));
+          port = sin->sin6_port;
+        }
+        break;
+      default:
+        errno = EAFNOSUPPORT;
+        ret = NULL;
+      }
+    if (ret == NULL)
+        fprintf (out, "error: inet_top failed: %m\n");
+    else
+      fprintf (out, " %s %u\n", buf, ntohs (port));
+  }
+}
+
+/* Format all the addresses in one address family.  */
+static void
+format_ai_family (FILE *out, struct addrinfo *ai, int family)
+{
+  while (ai)
+    {
+      if (ai->ai_family == family)
+        format_ai_one (out, ai);
+      ai = ai->ai_next;
+    }
+}
+
+char *
+support_format_addrinfo (struct addrinfo *ai, int ret)
+{
+  int errno_copy = errno;
+
+  struct xmemstream mem;
+  xopen_memstream (&mem);
+  if (ret != 0)
+    {
+      fprintf (mem.out, "error: %s\n", gai_strerror (ret));
+      if (ret == EAI_SYSTEM)
+        {
+          errno = errno_copy;
+          fprintf (mem.out, "error: %m\n");
+        }
+    }
+  else
+    {
+      format_ai_flags (mem.out, ai);
+      format_ai_canonname (mem.out, ai);
+      format_ai_family (mem.out, ai, AF_INET);
+      format_ai_family (mem.out, ai, AF_INET6);
+    }
+
+  xfclose_memstream (&mem);
+  return mem.buffer;
+}
diff --git a/support/support_format_dns_packet.c b/support/support_format_dns_packet.c
new file mode 100644
index 0000000..2992c57
--- /dev/null
+++ b/support/support_format_dns_packet.c
@@ -0,0 +1,222 @@
+/* Convert a DNS packet to a human-readable representation.
+   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/format_nss.h>
+
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+struct in_buffer
+{
+  const unsigned char *data;
+  size_t size;
+};
+
+static inline bool
+extract_8 (struct in_buffer *in, unsigned char *value)
+{
+  if (in->size == 0)
+    return false;
+  *value = in->data[0];
+  ++in->data;
+  --in->size;
+  return true;
+}
+
+static inline bool
+extract_16 (struct in_buffer *in, unsigned short *value)
+{
+  if (in->size < 2)
+    return false;
+  *value = (in->data[0] << 8) | in->data[1];
+  in->data += 2;
+  in->size -= 2;
+  return true;
+}
+
+static inline bool
+extract_32 (struct in_buffer *in, unsigned *value)
+{
+  if (in->size < 4)
+    return false;
+  unsigned a = in->data[0];
+  unsigned b = in->data[1];
+  unsigned c = in->data[2];
+  unsigned d = in->data[3];
+  *value = (a << 24) | (b << 16) | (c << 8) | d;
+  in->data += 4;
+  in->size -= 4;
+  return true;
+}
+
+static inline bool
+extract_bytes (struct in_buffer *in, size_t length, struct in_buffer *value)
+{
+  if (in->size < length)
+    return false;
+  *value = (struct in_buffer) {in->data, length};
+  in->data += length;
+  in->size -= length;
+  return true;
+}
+
+struct dname
+{
+  char name[MAXDNAME + 1];
+};
+
+static bool
+extract_name (struct in_buffer full, struct in_buffer *in, struct dname *value)
+{
+  const unsigned char *full_end = full.data + full.size;
+  /* Sanity checks; these indicate buffer misuse.  */
+  TEST_VERIFY_EXIT
+    (!(in->data < full.data || in->data > full_end
+       || in->size > (size_t) (full_end - in->data)));
+  int ret = dn_expand (full.data, full_end, in->data,
+                       value->name, sizeof (value->name));
+  if (ret < 0)
+    return false;
+  in->data += ret;
+  in->size -= ret;
+  return true;
+}
+
+char *
+support_format_dns_packet (const unsigned char *buffer, size_t length)
+{
+  struct in_buffer full = { buffer, length };
+  struct in_buffer in = full;
+  struct xmemstream mem;
+  xopen_memstream (&mem);
+
+  unsigned short txnid;
+  unsigned short flags;
+  unsigned short qdcount;
+  unsigned short ancount;
+  unsigned short nscount;
+  unsigned short adcount;
+  if (!(extract_16 (&in, &txnid)
+        && extract_16 (&in, &flags)
+        && extract_16 (&in, &qdcount)
+        && extract_16 (&in, &ancount)
+        && extract_16 (&in, &nscount)
+        && extract_16 (&in, &adcount)))
+    {
+      fprintf (mem.out, "error: could not parse DNS header\n");
+      goto out;
+    }
+  if (qdcount != 1)
+    {
+      fprintf (mem.out, "error: question count is %d, not 1\n", qdcount);
+      goto out;
+    }
+  struct dname qname;
+  if (!extract_name (full, &in, &qname))
+    {
+      fprintf (mem.out, "error: malformed QNAME\n");
+      goto out;
+    }
+  unsigned short qtype;
+  unsigned short qclass;
+  if (!(extract_16 (&in, &qtype)
+        && extract_16 (&in, &qclass)))
+    {
+      fprintf (mem.out, "error: malformed question\n");
+      goto out;
+    }
+  if (qtype != T_A && qtype != T_AAAA && qtype != T_PTR)
+    {
+      fprintf (mem.out, "error: unsupported QTYPE %d\n", qtype);
+      goto out;
+    }
+
+  fprintf (mem.out, "name: %s\n", qname.name);
+
+  for (int i = 0; i < ancount; ++i)
+    {
+      struct dname rname;
+      if (!extract_name (full, &in, &rname))
+        {
+          fprintf (mem.out, "error: malformed record name\n");
+          goto out;
+        }
+      unsigned short rtype;
+      unsigned short rclass;
+      unsigned ttl;
+      unsigned short rdlen;
+      struct in_buffer rdata;
+      if (!(extract_16 (&in, &rtype)
+            && extract_16 (&in, &rclass)
+            && extract_32 (&in, &ttl)
+            && extract_16 (&in, &rdlen)
+            && extract_bytes (&in, rdlen, &rdata)))
+        {
+          fprintf (mem.out, "error: malformed record header\n");
+          goto out;
+        }
+      /* Skip non-matching record types.  */
+      if ((rtype != qtype && rtype != T_CNAME) || rclass != qclass)
+        continue;
+      switch (rtype)
+        {
+        case T_A:
+          if (rdlen == 4)
+              fprintf (mem.out, "address: %d.%d.%d.%d\n",
+                       rdata.data[0],
+                       rdata.data[1],
+                       rdata.data[2],
+                       rdata.data[3]);
+          else
+            fprintf (mem.out, "error: A record of size %d: %s\n",
+                     rdlen, rname.name);
+          break;
+        case T_AAAA:
+          {
+            if (rdlen == 16)
+              {
+                char buf[100];
+                if (inet_ntop (AF_INET6, rdata.data, buf, sizeof (buf)) == NULL)
+                  fprintf (mem.out, "error: AAAA record decoding failed: %m\n");
+                else
+                  fprintf (mem.out, "address: %s\n", buf);
+              }
+            else
+              fprintf (mem.out, "error: AAAA record of size %d: %s\n",
+                       rdlen, rname.name);
+          }
+          break;
+        case T_CNAME:
+        case T_PTR:
+          {
+            struct dname name;
+            if (extract_name (full, &rdata, &name))
+              fprintf (mem.out, "name: %s\n", name.name);
+            else
+              fprintf (mem.out, "error: malformed CNAME/PTR record\n");
+          }
+        }
+    }
+
+ out:
+  xfclose_memstream (&mem);
+  return mem.buffer;
+}
diff --git a/support/support_format_herrno.c b/support/support_format_herrno.c
new file mode 100644
index 0000000..493d6ae
--- /dev/null
+++ b/support/support_format_herrno.c
@@ -0,0 +1,45 @@
+/* Convert a h_errno error code to a string.
+   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/format_nss.h>
+
+#include <support/support.h>
+
+char *
+support_format_herrno (int code)
+{
+  const char *errstr;
+  switch (code)
+    {
+    case HOST_NOT_FOUND:
+      errstr = "HOST_NOT_FOUND";
+      break;
+    case NO_ADDRESS:
+      errstr = "NO_ADDRESS";
+      break;
+    case NO_RECOVERY:
+      errstr = "NO_RECOVERY";
+      break;
+    case TRY_AGAIN:
+      errstr = "TRY_AGAIN";
+      break;
+    default:
+      return xasprintf ("<invalid h_errno value %d>\n", code);
+    }
+  return xstrdup (errstr);
+}
diff --git a/support/support_format_hostent.c b/support/support_format_hostent.c
new file mode 100644
index 0000000..5b5f260
--- /dev/null
+++ b/support/support_format_hostent.c
@@ -0,0 +1,75 @@
+/* Convert a struct hostent object to a string.
+   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/format_nss.h>
+
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+static int
+address_length (int family)
+{
+  switch (family)
+    {
+    case AF_INET:
+      return 4;
+    case AF_INET6:
+      return 16;
+    }
+  return -1;
+}
+
+char *
+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;
+    }
+
+  struct xmemstream mem;
+  xopen_memstream (&mem);
+
+  fprintf (mem.out, "name: %s\n", h->h_name);
+  for (char **alias = h->h_aliases; *alias != NULL; ++alias)
+    fprintf (mem.out, "alias: %s\n", *alias);
+  for (unsigned i = 0; h->h_addr_list[i] != NULL; ++i)
+    {
+      char buf[128];
+      if (inet_ntop (h->h_addrtype, h->h_addr_list[i],
+                     buf, sizeof (buf)) == NULL)
+        fprintf (mem.out, "error: inet_ntop failed: %m\n");
+      else
+        fprintf (mem.out, "address: %s\n", buf);
+    }
+  if (h->h_length != address_length (h->h_addrtype))
+    {
+      char *family = support_format_address_family (h->h_addrtype);
+      fprintf (mem.out, "error: invalid address length %d for %s\n",
+               h->h_length, family);
+      free (family);
+    }
+
+  xfclose_memstream (&mem);
+  return mem.buffer;
+}
diff --git a/support/support_format_netent.c b/support/support_format_netent.c
new file mode 100644
index 0000000..020f572
--- /dev/null
+++ b/support/support_format_netent.c
@@ -0,0 +1,52 @@
+/* Convert a struct netent object to a string.
+   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/format_nss.h>
+
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+char *
+support_format_netent (struct netent *e)
+{
+  if (e == NULL)
+    {
+      char *value = support_format_herrno (h_errno);
+      char *result = xasprintf ("error: %s\n", value);
+      free (value);
+      return result;
+    }
+
+  struct xmemstream mem;
+  xopen_memstream (&mem);
+
+  if (e->n_name != NULL)
+    fprintf (mem.out, "name: %s\n", e->n_name);
+  for (char **ap = e->n_aliases; *ap != NULL; ++ap)
+    fprintf (mem.out, "alias: %s\n", *ap);
+  if (e->n_addrtype != AF_INET)
+    fprintf (mem.out, "addrtype: %d\n", e->n_addrtype);
+  /* On alpha, e->n_net is an unsigned long.  */
+  unsigned int n_net = e->n_net;
+  fprintf (mem.out, "net: 0x%08x\n", n_net);
+
+  xfclose_memstream (&mem);
+  return mem.buffer;
+}
diff --git a/support/support_isolate_in_subprocess.c b/support/support_isolate_in_subprocess.c
new file mode 100644
index 0000000..cf48614
--- /dev/null
+++ b/support/support_isolate_in_subprocess.c
@@ -0,0 +1,38 @@
+/* Run a function in a subprocess.
+   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
+support_isolate_in_subprocess (void (*callback) (void *), void *closure)
+{
+  pid_t pid = xfork ();
+  if (pid == 0)
+    {
+      /* Child process.  */
+      callback (closure);
+      _exit (0);
+    }
+
+  /* Parent process.  */
+  int status;
+  xwaitpid (pid, &status, 0);
+  if (status != 0)
+    FAIL_EXIT1 ("child process exited with status %d", status);
+}
diff --git a/support/support_record_failure.c b/support/support_record_failure.c
new file mode 100644
index 0000000..684055c
--- /dev/null
+++ b/support/support_record_failure.c
@@ -0,0 +1,106 @@
+/* Global test failure counter.
+   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/check.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+/* This structure keeps track of test failures.  The counter is
+   incremented on each failure.  The failed member is set to true if a
+   failure is detected, so that even if the counter wraps around to
+   zero, the failure of a test can be detected.
+
+   The init constructor function below puts *state on a shared
+   annonymous mapping, so that failure reports from subprocesses
+   propagate to the parent process.  */
+struct test_failures
+{
+  unsigned int counter;
+  unsigned int failed;
+};
+static struct test_failures *state;
+
+static __attribute__ ((constructor)) void
+init (void)
+{
+  void *ptr = mmap (NULL, sizeof (*state), PROT_READ | PROT_WRITE,
+                    MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+  if (ptr == MAP_FAILED)
+    {
+      printf ("error: could not map %zu bytes: %m\n", sizeof (*state));
+      exit (1);
+    }
+  /* Zero-initialization of the struct is sufficient.  */
+  state = ptr;
+}
+
+void
+support_record_failure (void)
+{
+  if (state == NULL)
+    {
+      write_message
+        ("error: support_record_failure called without initialization\n");
+      _exit (1);
+    }
+  /* Relaxed MO is sufficient because we are only interested in the
+     values themselves, in isolation.  */
+  __atomic_store_n (&state->failed, 1, __ATOMIC_RELEASE);
+  __atomic_add_fetch (&state->counter, 1, __ATOMIC_RELEASE);
+}
+
+int
+support_report_failure (int status)
+{
+  if (state == NULL)
+    {
+      write_message
+        ("error: support_report_failure called without initialization\n");
+      return 1;
+    }
+
+  /* Relaxed MO is sufficient because acquire test result reporting
+     assumes that exiting from the main thread happens before the
+     error reporting via support_record_failure, which requires some
+     form of external synchronization.  */
+  bool failed = __atomic_load_n (&state->failed, __ATOMIC_RELAXED);
+  if (failed)
+    printf ("error: %u test failures\n",
+            __atomic_load_n (&state->counter, __ATOMIC_RELAXED));
+
+  if ((status == 0 || status == EXIT_UNSUPPORTED) && failed)
+    /* If we have a recorded failure, it overrides a non-failure
+       report from the test function.  */
+    status = 1;
+  return status;
+}
+
+void
+support_record_failure_reset (void)
+{
+  /* Only used for testing the test framework, with external
+     synchronization, but use release MO for consistency.  */
+  __atomic_store_n (&state->failed, 0, __ATOMIC_RELAXED);
+  __atomic_add_fetch (&state->counter, 0, __ATOMIC_RELAXED);
+}
diff --git a/support/support_run_diff.c b/support/support_run_diff.c
new file mode 100644
index 0000000..f5155de
--- /dev/null
+++ b/support/support_run_diff.c
@@ -0,0 +1,76 @@
+/* Invoke the system diff tool to compare two strings.
+   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/run_diff.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>
+#include <sys/wait.h>
+
+static char *
+write_to_temp_file (const char *prefix, const char *str)
+{
+  char *template = xasprintf ("run_diff-%s", prefix);
+  char *name = NULL;
+  int fd = create_temp_file (template, &name);
+  TEST_VERIFY_EXIT (fd >= 0);
+  free (template);
+  xwrite (fd, str, strlen (str));
+  xclose (fd);
+  return name;
+}
+
+void
+support_run_diff (const char *left_label, const char *left,
+                  const char *right_label, const char *right)
+{
+  /* Ensure that the diff command output is ordered properly with
+     standard output.  */
+  TEST_VERIFY_EXIT (fflush (stdout) == 0);
+
+  char *left_path = write_to_temp_file ("left-diff", left);
+  char *right_path = write_to_temp_file ("right-diff", right);
+
+  pid_t pid = xfork ();
+  if (pid == 0)
+    {
+      execlp ("diff", "diff", "-u",
+              "--label", left_label, "--label", right_label,
+              "--", left_path, right_path,
+              NULL);
+      _exit (17);
+    }
+  else
+    {
+      int status;
+      xwaitpid (pid, &status, 0);
+      if (!WIFEXITED (status) || WEXITSTATUS (status) != 1)
+        printf ("warning: could not run diff, exit status: %d\n"
+                "*** %s ***\n%s\n"
+                "*** %s ***\n%s\n",
+                status, left_label, left, right_label, right);
+    }
+
+  free (right_path);
+  free (left_path);
+}
diff --git a/support/support_shared_allocate.c b/support/support_shared_allocate.c
new file mode 100644
index 0000000..c2ca7c2
--- /dev/null
+++ b/support/support_shared_allocate.c
@@ -0,0 +1,59 @@
+/* Allocate a memory region shared across processes.
+   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 <stddef.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+#include <sys/mman.h>
+
+#if defined ISO11
+/* Header for the allocation.  It contains the size of the allocation
+   for subsequent unmapping.  */
+struct header
+{
+  size_t total_size;
+  char data[] __attribute__ ((aligned (__alignof__ (max_align_t))));
+};
+
+void *
+support_shared_allocate (size_t size)
+{
+  size_t total_size = size + offsetof (struct header, data);
+  if (total_size < size)
+    {
+      errno = ENOMEM;
+      oom_error (__func__, size);
+      return NULL;
+    }
+  else
+    {
+      struct header *result = xmmap (NULL, total_size, PROT_READ | PROT_WRITE,
+                                     MAP_ANONYMOUS | MAP_SHARED, -1);
+      result->total_size = total_size;
+      return &result->data;
+    }
+}
+
+void
+support_shared_free (void *data)
+{
+  struct header *header = data - offsetof (struct header, data);
+  xmunmap (header, header->total_size);
+}
+#endif
diff --git a/support/support_test_main.c b/support/support_test_main.c
new file mode 100644
index 0000000..914d64f
--- /dev/null
+++ b/support/support_test_main.c
@@ -0,0 +1,423 @@
+/* Main worker function for the test driver.
+   Copyright (C) 1998-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/test-driver.h>
+#include <support/check.h>
+#include <support/temp_file-internal.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <getopt.h>
+#include <malloc.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static const struct option default_options[] =
+{
+  TEST_DEFAULT_OPTIONS
+  { NULL, 0, NULL, 0 }
+};
+
+/* Show people how to run the program.  */
+static void
+usage (const struct option *options)
+{
+  size_t i;
+
+  printf ("Usage: %s [options]\n"
+          "\n"
+          "Environment Variables:\n"
+          "  TIMEOUTFACTOR          An integer used to scale the timeout\n"
+          "  TMPDIR                 Where to place temporary files\n"
+          "  TEST_COREDUMPS         Do not disable coredumps if set\n"
+          "\n",
+          program_invocation_short_name);
+  printf ("Options:\n");
+  for (i = 0; options[i].name; ++i)
+    {
+      int indent;
+
+      indent = printf ("  --%s", options[i].name);
+      if (options[i].has_arg == required_argument)
+        indent += printf (" <arg>");
+      printf ("%*s", 25 - indent, "");
+      switch (options[i].val)
+        {
+        case 'v':
+          printf ("Increase the output verbosity");
+          break;
+        case OPT_DIRECT:
+          printf ("Run the test directly (instead of forking & monitoring)");
+          break;
+        case OPT_TESTDIR:
+          printf ("Override the TMPDIR env var");
+          break;
+        }
+      printf ("\n");
+    }
+}
+
+/* The PID of the test process.  */
+static pid_t test_pid;
+
+/* The cleanup handler passed to test_main.  */
+static void (*cleanup_function) (void);
+
+/* Timeout handler.  We kill the child and exit with an error.  */
+static void
+__attribute__ ((noreturn))
+signal_handler (int sig)
+{
+  int killed;
+  int status;
+
+  assert (test_pid > 1);
+  /* Kill the whole process group.  */
+  kill (-test_pid, SIGKILL);
+  /* In case setpgid failed in the child, kill it individually too.  */
+  kill (test_pid, SIGKILL);
+
+  /* Wait for it to terminate.  */
+  int i;
+  for (i = 0; i < 5; ++i)
+    {
+      killed = waitpid (test_pid, &status, WNOHANG|WUNTRACED);
+      if (killed != 0)
+        break;
+
+      /* Delay, give the system time to process the kill.  If the
+         nanosleep() call return prematurely, all the better.  We
+         won't restart it since this probably means the child process
+         finally died.  */
+      struct timespec ts;
+      ts.tv_sec = 0;
+      ts.tv_nsec = 100000000;
+      nanosleep (&ts, NULL);
+    }
+  if (killed != 0 && killed != test_pid)
+    {
+      printf ("Failed to kill test process: %m\n");
+      exit (1);
+    }
+
+  if (cleanup_function != NULL)
+    cleanup_function ();
+
+  if (sig == SIGINT)
+    {
+      signal (sig, SIG_DFL);
+      raise (sig);
+    }
+
+  if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL))
+    puts ("Timed out: killed the child process");
+  else if (WIFSTOPPED (status))
+    printf ("Timed out: the child process was %s\n",
+            strsignal (WSTOPSIG (status)));
+  else if (WIFSIGNALED (status))
+    printf ("Timed out: the child process got signal %s\n",
+            strsignal (WTERMSIG (status)));
+  else
+    printf ("Timed out: killed the child process but it exited %d\n",
+            WEXITSTATUS (status));
+
+  /* Exit with an error.  */
+  exit (1);
+}
+
+/* Run test_function or test_function_argv.  */
+static int
+run_test_function (int argc, char **argv, const struct test_config *config)
+{
+  if (config->test_function != NULL)
+    return config->test_function ();
+  else if (config->test_function_argv != NULL)
+    return config->test_function_argv (argc, argv);
+  else
+    {
+      printf ("error: no test function defined\n");
+      exit (1);
+    }
+}
+
+static bool test_main_called;
+
+const char *test_dir = NULL;
+unsigned int test_verbose = 0;
+
+/* If test failure reporting has been linked in, it may contribute
+   additional test failures.  */
+static int
+adjust_exit_status (int status)
+{
+  if (support_report_failure != NULL)
+    return support_report_failure (status);
+  return status;
+}
+
+int
+support_test_main (int argc, char **argv, const struct test_config *config)
+{
+  if (test_main_called)
+    {
+      printf ("error: test_main called for a second time\n");
+      exit (1);
+    }
+  test_main_called = true;
+  const struct option *options;
+  if (config->options != NULL)
+    options = config->options;
+  else
+    options = default_options;
+
+  cleanup_function = config->cleanup_function;
+
+  int direct = 0;       /* Directly call the test function?  */
+  int status;
+  int opt;
+  unsigned int timeoutfactor = 1;
+  pid_t termpid;
+
+  if (!config->no_mallopt)
+    {
+      /* Make uses of freed and uninitialized memory known.  Do not
+         pull in a definition for mallopt if it has not been defined
+         already.  */
+      extern __typeof__ (mallopt) mallopt __attribute__ ((weak));
+      if (mallopt != NULL)
+        mallopt (M_PERTURB, 42);
+    }
+
+  while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1)
+    switch (opt)
+      {
+      case '?':
+        usage (options);
+        exit (1);
+      case 'v':
+        ++test_verbose;
+        break;
+      case OPT_DIRECT:
+        direct = 1;
+        break;
+      case OPT_TESTDIR:
+        test_dir = optarg;
+        break;
+      default:
+        if (config->cmdline_function != NULL)
+          config->cmdline_function (opt);
+      }
+
+  /* If set, read the test TIMEOUTFACTOR value from the environment.
+     This value is used to scale the default test timeout values. */
+  char *envstr_timeoutfactor = getenv ("TIMEOUTFACTOR");
+  if (envstr_timeoutfactor != NULL)
+    {
+      char *envstr_conv = envstr_timeoutfactor;
+      unsigned long int env_fact;
+
+      env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0);
+      if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor)
+        timeoutfactor = MAX (env_fact, 1);
+    }
+
+  /* Set TMPDIR to specified test directory.  */
+  if (test_dir != NULL)
+    {
+      setenv ("TMPDIR", test_dir, 1);
+
+      if (chdir (test_dir) < 0)
+        {
+          printf ("chdir: %m\n");
+          exit (1);
+        }
+    }
+  else
+    {
+      test_dir = getenv ("TMPDIR");
+      if (test_dir == NULL || test_dir[0] == '\0')
+        test_dir = "/tmp";
+    }
+  if (support_set_test_dir != NULL)
+    support_set_test_dir (test_dir);
+
+  int timeout = config->timeout;
+  if (timeout == 0)
+    timeout =  DEFAULT_TIMEOUT;
+
+  /* Make sure we see all message, even those on stdout.  */
+  setvbuf (stdout, NULL, _IONBF, 0);
+
+  /* Make sure temporary files are deleted.  */
+  if (support_delete_temp_files != NULL)
+      atexit (support_delete_temp_files);
+
+  /* Correct for the possible parameters.  */
+  argv[optind - 1] = argv[0];
+  argv += optind - 1;
+  argc -= optind - 1;
+
+  /* Call the initializing function, if one is available.  */
+  if (config->prepare_function != NULL)
+    config->prepare_function (argc, argv);
+
+  const char *envstr_direct = getenv ("TEST_DIRECT");
+  if (envstr_direct != NULL)
+    {
+      FILE *f = fopen (envstr_direct, "w");
+      if (f == NULL)
+        {
+          printf ("cannot open TEST_DIRECT output file '%s': %m\n",
+                  envstr_direct);
+          exit (1);
+        }
+
+      fprintf (f, "timeout=%u\ntimeoutfactor=%u\n",
+               config->timeout, timeoutfactor);
+      if (config->expected_status != 0)
+        fprintf (f, "exit=%u\n", config->expected_status);
+      if (config->expected_signal != 0)
+        fprintf (f, "signal=%s\n", strsignal (config->expected_signal));
+
+      if (support_print_temp_files != NULL)
+        support_print_temp_files (f);
+
+      fclose (f);
+      direct = 1;
+    }
+
+  bool disable_coredumps;
+  {
+    const char *coredumps = getenv ("TEST_COREDUMPS");
+    disable_coredumps = coredumps == NULL || coredumps[0] == '\0';
+  }
+
+  /* If we are not expected to fork run the function immediately.  */
+  if (direct)
+    return adjust_exit_status (run_test_function (argc, argv, config));
+
+  /* Set up the test environment:
+     - prevent core dumps
+     - set up the timer
+     - fork and execute the function.  */
+
+  test_pid = fork ();
+  if (test_pid == 0)
+    {
+      /* This is the child.  */
+      if (disable_coredumps)
+        {
+          /* Try to avoid dumping core.  This is necessary because we
+             run the test from the source tree, and the coredumps
+             would end up there (and not in the build tree).  */
+          struct rlimit core_limit;
+          core_limit.rlim_cur = 0;
+          core_limit.rlim_max = 0;
+          setrlimit (RLIMIT_CORE, &core_limit);
+        }
+
+      /* We put the test process in its own pgrp so that if it bogusly
+         generates any job control signals, they won't hit the whole build.  */
+      if (setpgid (0, 0) != 0)
+        printf ("Failed to set the process group ID: %m\n");
+
+      /* Execute the test function and exit with the return value.   */
+      exit (run_test_function (argc, argv, config));
+    }
+  else if (test_pid < 0)
+    {
+      printf ("Cannot fork test program: %m\n");
+      exit (1);
+    }
+
+  /* Set timeout.  */
+  signal (SIGALRM, signal_handler);
+  alarm (timeout * timeoutfactor);
+
+  /* Make sure we clean up if the wrapper gets interrupted.  */
+  signal (SIGINT, signal_handler);
+
+  /* Wait for the regular termination.  */
+  termpid = TEMP_FAILURE_RETRY (waitpid (test_pid, &status, 0));
+  if (termpid == -1)
+    {
+      printf ("Waiting for test program failed: %m\n");
+      exit (1);
+    }
+  if (termpid != test_pid)
+    {
+      printf ("Oops, wrong test program terminated: expected %ld, got %ld\n",
+              (long int) test_pid, (long int) termpid);
+      exit (1);
+    }
+
+  /* Process terminated normaly without timeout etc.  */
+  if (WIFEXITED (status))
+    {
+      if (config->expected_status == 0)
+        {
+          if (config->expected_signal == 0)
+            /* Exit with the return value of the test.  */
+            return adjust_exit_status (WEXITSTATUS (status));
+          else
+            {
+              printf ("Expected signal '%s' from child, got none\n",
+                      strsignal (config->expected_signal));
+              exit (1);
+            }
+        }
+      else
+        {
+          /* Non-zero exit status is expected */
+          if (WEXITSTATUS (status) != config->expected_status)
+            {
+              printf ("Expected status %d, got %d\n",
+                      config->expected_status, WEXITSTATUS (status));
+              exit (1);
+            }
+        }
+      return adjust_exit_status (0);
+    }
+  /* Process was killed by timer or other signal.  */
+  else
+    {
+      if (config->expected_signal == 0)
+        {
+          printf ("Didn't expect signal from child: got `%s'\n",
+                  strsignal (WTERMSIG (status)));
+          exit (1);
+        }
+      else if (WTERMSIG (status) != config->expected_signal)
+        {
+          printf ("Incorrect signal from child: got `%s', need `%s'\n",
+                  strsignal (WTERMSIG (status)),
+                  strsignal (config->expected_signal));
+          exit (1);
+        }
+
+      return adjust_exit_status (0);
+    }
+}
diff --git a/support/support_test_verify_impl.c b/support/support_test_verify_impl.c
new file mode 100644
index 0000000..5bae38f
--- /dev/null
+++ b/support/support_test_verify_impl.c
@@ -0,0 +1,33 @@
+/* Implementation of the TEST_VERIFY and TEST_VERIFY_EXIT macros.
+   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/check.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+support_test_verify_impl (int status, const char *file, int line,
+                          const char *expr)
+{
+  support_record_failure ();
+  printf ("error: %s:%d: not true: %s\n", file, line, expr);
+  if (status >= 0)
+    exit (status);
+
+}
diff --git a/support/support_write_file_string.c b/support/support_write_file_string.c
new file mode 100644
index 0000000..48e8959
--- /dev/null
+++ b/support/support_write_file_string.c
@@ -0,0 +1,39 @@
+/* Write a string to a file.
+   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 <fcntl.h>
+#include <string.h>
+#include <support/check.h>
+#include <xunistd.h>
+
+void
+support_write_file_string (const char *path, const char *contents)
+{
+  int fd = xopen (path, O_CREAT | O_TRUNC | O_WRONLY, 0666);
+  const char *end = contents + strlen (contents);
+  for (const char *p = contents; p < end; )
+    {
+      ssize_t ret = write (fd, p, end - p);
+      if (ret < 0)
+        FAIL_EXIT1 ("cannot write to \"%s\": %m", path);
+      if (ret == 0)
+        FAIL_EXIT1 ("zero-length write to \"%s\"", path);
+      p += ret;
+    }
+  xclose (fd);
+}
diff --git a/support/temp_file-internal.h b/support/temp_file-internal.h
new file mode 100644
index 0000000..fb6cceb
--- /dev/null
+++ b/support/temp_file-internal.h
@@ -0,0 +1,31 @@
+/* Internal weak declarations for temporary file handling.
+   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/>.  */
+
+#ifndef SUPPORT_TEMP_FILE_INTERNAL_H
+#define SUPPORT_TEMP_FILE_INTERNAL_H
+
+/* These functions are called by the test driver if they are
+   defined.  Tests should not call them directly.  */
+
+#include <stdio.h>
+
+void support_set_test_dir (const char *name) __attribute__ ((weak));
+void support_delete_temp_files (void) __attribute__ ((weak));
+void support_print_temp_files (FILE *) __attribute__ ((weak));
+
+#endif /* SUPPORT_TEMP_FILE_INTERNAL_H */
diff --git a/support/temp_file.c b/support/temp_file.c
new file mode 100644
index 0000000..fdb2477
--- /dev/null
+++ b/support/temp_file.c
@@ -0,0 +1,132 @@
+/* Temporary file handling for tests.
+   Copyright (C) 1998-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/>.  */
+
+/* This is required to get an mkstemp which can create large files on
+   some 32-bit platforms. */
+#define _FILE_OFFSET_BITS 64
+
+#include <support/temp_file.h>
+#include <support/temp_file-internal.h>
+#include <support/support.h>
+
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* List of temporary files.  */
+static struct temp_name_list
+{
+  struct temp_name_list *next;
+  char *name;
+  pid_t owner;
+} *temp_name_list;
+
+/* Location of the temporary files.  Set by the test skeleton via
+   support_set_test_dir.  The string is not be freed.  */
+static const char *test_dir = _PATH_TMP;
+
+void
+add_temp_file (const char *name)
+{
+  struct temp_name_list *newp
+    = (struct temp_name_list *) xcalloc (sizeof (*newp), 1);
+  char *newname = strdup (name);
+  if (newname != NULL)
+    {
+      newp->name = newname;
+      newp->next = temp_name_list;
+      newp->owner = getpid ();
+      temp_name_list = newp;
+    }
+  else
+    free (newp);
+}
+
+int
+create_temp_file (const char *base, char **filename)
+{
+  char *fname;
+  int fd;
+
+  fname = (char *) xmalloc (strlen (test_dir) + 1 + strlen (base)
+			    + sizeof ("XXXXXX"));
+  strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX");
+
+  fd = mkstemp (fname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file '%s': %m\n", fname);
+      free (fname);
+      return -1;
+    }
+
+  add_temp_file (fname);
+  if (filename != NULL)
+    *filename = fname;
+  else
+    free (fname);
+
+  return fd;
+}
+
+/* Helper functions called by the test skeleton follow.  */
+
+void
+support_set_test_dir (const char *path)
+{
+  test_dir = path;
+}
+
+void
+support_delete_temp_files (void)
+{
+  pid_t pid = getpid ();
+  while (temp_name_list != NULL)
+    {
+      /* Only perform the removal if the path was registed in the same
+	 process, as identified by the PID.  (This assumes that the
+	 parent process which registered the temporary file sticks
+	 around, to prevent PID reuse.)  */
+      if (temp_name_list->owner == pid)
+	{
+	  if (remove (temp_name_list->name) != 0)
+	    printf ("warning: could not remove temporary file: %s: %m\n",
+		    temp_name_list->name);
+	}
+      free (temp_name_list->name);
+
+      struct temp_name_list *next = temp_name_list->next;
+      free (temp_name_list);
+      temp_name_list = next;
+    }
+}
+
+void
+support_print_temp_files (FILE *f)
+{
+  if (temp_name_list != NULL)
+    {
+      struct temp_name_list *n;
+      fprintf (f, "temp_files=(\n");
+      for (n = temp_name_list; n != NULL; n = n->next)
+        fprintf (f, "  '%s'\n", n->name);
+      fprintf (f, ")\n");
+    }
+}
diff --git a/support/temp_file.h b/support/temp_file.h
new file mode 100644
index 0000000..6fed8df
--- /dev/null
+++ b/support/temp_file.h
@@ -0,0 +1,37 @@
+/* Declarations for temporary file handling.
+   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/>.  */
+
+#ifndef SUPPORT_TEMP_FILE_H
+#define SUPPORT_TEMP_FILE_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Schedule a temporary file for deletion on exit.  */
+void add_temp_file (const char *name);
+
+/* Create a temporary file.  Return the opened file descriptor on
+   success, or -1 on failure.  Write the file name to *FILENAME if
+   FILENAME is not NULL.  In this case, the caller is expected to free
+   *FILENAME.  */
+int create_temp_file (const char *base, char **filename);
+
+__END_DECLS
+
+#endif /* SUPPORT_TEMP_FILE_H */
diff --git a/support/test-driver.c b/support/test-driver.c
new file mode 100644
index 0000000..482066d
--- /dev/null
+++ b/support/test-driver.c
@@ -0,0 +1,156 @@
+/* Main function for test programs.
+   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/>.  */
+
+/* This file should be included from test cases.  It will define a
+   main function which provides the test wrapper.
+
+   It assumes that the test case defines a function
+
+     int do_test (void);
+
+   and arranges for that function being called under the test wrapper.
+   The do_test function should return 0 to indicate a passing test, 1
+   to indicate a failing test, or 77 to indicate an unsupported test.
+   Other result values could be used to indicate a failing test, but
+   the result of the expression is passed to exit and exit only
+   returns the lower 8 bits of its input.  A non-zero return with some
+   values could cause a test to incorrectly be considered passing when
+   it really failed.  For this reason, the function should always
+   return 0 (EXIT_SUCCESS), 1 (EXIT_FAILURE), or 77
+   (EXIT_UNSUPPORTED).
+
+   The test function may print out diagnostic or warning messages as well
+   as messages about failures.  These messages should be printed to stdout
+   and not stderr so that the output is properly ordered with respect to
+   the rest of the glibc testsuite run output.
+
+   Several preprocessors macros can be defined before including this
+   file.
+
+   The name of the do_test function can be changed with the
+   TEST_FUNCTION macro.  It must expand to the desired function name.
+
+   If the test case needs access to command line parameters, it must
+   define the TEST_FUNCTION_ARGV macro with the name of the test
+   function.  It must have the following type:
+
+     int TEST_FUNCTION_ARGV (int argc, char **argv);
+
+   This overrides the do_test default function and is incompatible
+   with the TEST_FUNCTION macro.
+
+   If PREPARE is defined, it must expand to the name of a function of
+   the type
+
+     void PREPARE (int argc, char **);
+
+   This function will be called early, after parsing the command line,
+   but before running the test, in the parent process which acts as
+   the test supervisor.
+
+   If CLEANUP_HANDLER is defined, it must expand to the name of a
+   function of the type
+
+     void CLEANUP_HANDLER (void);
+
+   This function will be called from the timeout (SIGALRM) signal
+   handler.
+
+   If EXPECTED_SIGNAL is defined, it must expanded to a constant which
+   denotes the expected signal number.
+
+   If EXPECTED_STATUS is defined, it must expand to the expected exit
+   status.
+
+   If TIMEOUT is defined, it must be positive constant.  It overrides
+   the default test timeout and is measured in seconds.
+
+   If TEST_NO_MALLOPT is defined, the test wrapper will not call
+   mallopt.
+
+   Custom command line handling can be implemented by defining the
+   CMDLINE_OPTION macro (after including the <getopt.h> header; this
+   requires _GNU_SOURCE to be defined).  This macro must expand to a
+   to a comma-separated list of braced initializers for struct option
+   from <getopt.h>, with a trailing comma.  CMDLINE_PROCESS can be
+   defined as the name of a function which is called to process these
+   options.  The function is passed the option character/number and
+   has this type:
+
+     void CMDLINE_PROCESS (int);
+*/
+
+#include <support/test-driver.h>
+
+#include <string.h>
+
+int
+main (int argc, char **argv)
+{
+  struct test_config test_config;
+  memset (&test_config, 0, sizeof (test_config));
+
+#ifdef PREPARE
+  test_config.prepare_function = (PREPARE);
+#endif
+
+#if defined (TEST_FUNCTION) && defined (TEST_FUNCTON_ARGV)
+# error TEST_FUNCTION and TEST_FUNCTION_ARGV cannot be defined at the same time
+#endif
+#if defined (TEST_FUNCTION)
+  test_config.test_function = TEST_FUNCTION;
+#elif defined (TEST_FUNCTION_ARGV)
+  test_config.test_function_argv = TEST_FUNCTION_ARGV;
+#else
+  test_config.test_function = do_test;
+#endif
+
+#ifdef CLEANUP_HANDLER
+  test_config.cleanup_function = CLEANUP_HANDLER;
+#endif
+
+#ifdef EXPECTED_SIGNAL
+  test_config.expected_signal = (EXPECTED_SIGNAL);
+#endif
+
+#ifdef EXPECTED_STATUS
+  test_config.expected_status = (EXPECTED_STATUS);
+#endif
+
+#ifdef TEST_NO_MALLOPT
+  test_config.no_mallopt = 1;
+#endif
+
+#ifdef TIMEOUT
+  test_config.timeout = TIMEOUT;
+#endif
+
+#ifdef CMDLINE_OPTIONS
+  struct option options[] =
+    {
+      CMDLINE_OPTIONS
+      TEST_DEFAULT_OPTIONS
+    };
+  test_config.options = &options;
+#endif
+#ifdef CMDLINE_PROCESS
+  test_config.cmdline_function = CMDLINE_PROCESS;
+#endif
+
+  return support_test_main (argc, argv, &test_config);
+}
diff --git a/support/test-driver.h b/support/test-driver.h
new file mode 100644
index 0000000..af1971a
--- /dev/null
+++ b/support/test-driver.h
@@ -0,0 +1,74 @@
+/* Interfaces for the test driver.
+   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/>.  */
+
+#ifndef SUPPORT_TEST_DRIVER_H
+#define SUPPORT_TEST_DRIVER_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+struct test_config
+{
+  void (*prepare_function) (int argc, char **argv);
+  int (*test_function) (void);
+  int (*test_function_argv) (int argc, char **argv);
+  void (*cleanup_function) (void);
+  void (*cmdline_function) (int);
+  const void *options;   /* Custom options if not NULL.  */
+  int timeout;           /* Test timeout in seconds.  */
+  int expected_status;   /* Expected exit status.  */
+  int expected_signal;   /* If non-zero, expect termination by signal.  */
+  char no_mallopt;       /* Boolean flag to disable mallopt.  */
+};
+
+enum
+  {
+    /* Test exit status which indicates that the feature is
+       unsupported. */
+    EXIT_UNSUPPORTED = 77,
+
+    /* Default timeout is twenty seconds.  Tests should normally
+       complete faster than this, but if they don't, that's abnormal
+       (a bug) anyways.  */
+    DEFAULT_TIMEOUT = 20,
+
+    /* Used for command line argument parsing.  */
+    OPT_DIRECT = 1000,
+    OPT_TESTDIR,
+  };
+
+/* Options provided by the test driver.  */
+#define TEST_DEFAULT_OPTIONS                            \
+  { "verbose", no_argument, NULL, 'v' },                \
+  { "direct", no_argument, NULL, OPT_DIRECT },          \
+  { "test-dir", required_argument, NULL, OPT_TESTDIR }, \
+
+/* The directory the test should use for temporary files.  */
+extern const char *test_dir;
+
+/* The number of --verbose arguments specified during program
+   invocation.  This variable can be used to control the verbosity of
+   tests.  */
+extern unsigned int test_verbose;
+
+int support_test_main (int argc, char **argv, const struct test_config *);
+
+__END_DECLS
+
+#endif /* SUPPORT_TEST_DRIVER_H */
diff --git a/support/tst-support-namespace.c b/support/tst-support-namespace.c
new file mode 100644
index 0000000..a50b074
--- /dev/null
+++ b/support/tst-support-namespace.c
@@ -0,0 +1,34 @@
+/* Test entering namespaces.
+   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 <stdio.h>
+#include <support/namespace.h>
+
+static int
+do_test (void)
+{
+  if (support_become_root ())
+    printf ("info: acquired root-like privileges\n");
+  if (support_enter_network_namespace ())
+    printf ("info: entered network namespace\n");
+  if (support_in_uts_namespace ())
+    printf ("info: also entered UTS namespace\n");
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c
new file mode 100644
index 0000000..5672fba
--- /dev/null
+++ b/support/tst-support_capture_subprocess.c
@@ -0,0 +1,188 @@
+/* Test capturing output from a subprocess.
+   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 <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+/* Write one byte at *P to FD and advance *P.  Do nothing if *P is
+   '\0'.  */
+static void
+transfer (const unsigned char **p, int fd)
+{
+  if (**p != '\0')
+    {
+      TEST_VERIFY (write (fd, *p, 1) == 1);
+      ++*p;
+    }
+}
+
+/* Determine the order in which stdout and stderr are written.  */
+enum write_mode { out_first, err_first, interleave,
+                  write_mode_last =  interleave };
+
+/* Describe what to write in the subprocess.  */
+struct test
+{
+  char *out;
+  char *err;
+  enum write_mode write_mode;
+  int signal;
+  int status;
+};
+
+/* For use with support_capture_subprocess.  */
+static void
+callback (void *closure)
+{
+  const struct test *test = closure;
+  bool mode_ok = false;
+  switch (test->write_mode)
+    {
+    case out_first:
+      TEST_VERIFY (fputs (test->out, stdout) >= 0);
+      TEST_VERIFY (fflush (stdout) == 0);
+      TEST_VERIFY (fputs (test->err, stderr) >= 0);
+      TEST_VERIFY (fflush (stderr) == 0);
+      mode_ok = true;
+      break;
+    case err_first:
+      TEST_VERIFY (fputs (test->err, stderr) >= 0);
+      TEST_VERIFY (fflush (stderr) == 0);
+      TEST_VERIFY (fputs (test->out, stdout) >= 0);
+      TEST_VERIFY (fflush (stdout) == 0);
+      mode_ok = true;
+      break;
+    case interleave:
+      {
+        const unsigned char *pout = (const unsigned char *) test->out;
+        const unsigned char *perr = (const unsigned char *) test->err;
+        do
+          {
+            transfer (&pout, STDOUT_FILENO);
+            transfer (&perr, STDERR_FILENO);
+          }
+        while (*pout != '\0' || *perr != '\0');
+      }
+      mode_ok = true;
+      break;
+    }
+  TEST_VERIFY (mode_ok);
+
+  if (test->signal != 0)
+    raise (test->signal);
+  exit (test->status);
+}
+
+/* Create a heap-allocated random string of letters.  */
+static char *
+random_string (size_t length)
+{
+  char *result = xmalloc (length + 1);
+  for (size_t i = 0; i < length; ++i)
+    result[i] = 'a' + (rand () % 26);
+  result[length] = '\0';
+  return result;
+}
+
+/* Check that the specific stream from the captured subprocess matches
+   expectations.  */
+static void
+check_stream (const char *what, const struct xmemstream *stream,
+              const char *expected)
+{
+  if (strcmp (stream->buffer, expected) != 0)
+    {
+      support_record_failure ();
+      printf ("error: captured %s data incorrect\n"
+              "  expected: %s\n"
+              "  actual:   %s\n",
+              what, expected, stream->buffer);
+    }
+  if (stream->length != strlen (expected))
+    {
+      support_record_failure ();
+      printf ("error: captured %s data length incorrect\n"
+              "  expected: %zu\n"
+              "  actual:   %zu\n",
+              what, strlen (expected), stream->length);
+    }
+}
+
+static int
+do_test (void)
+{
+  const int lengths[] = {0, 1, 17, 512, 20000, -1};
+
+  /* Test multiple combinations of support_capture_subprocess.
+
+     length_idx_stdout: Index into the lengths array above,
+       controls how many bytes are written by the subprocess to
+       standard output.
+     length_idx_stderr: Same for standard error.
+     write_mode: How standard output and standard error writes are
+       ordered.
+     signal: Exit with no signal if zero, with SIGTERM if one.
+     status: Process exit status: 0 if zero, 3 if one.  */
+  for (int length_idx_stdout = 0; lengths[length_idx_stdout] >= 0;
+       ++length_idx_stdout)
+    for (int length_idx_stderr = 0; lengths[length_idx_stderr] >= 0;
+         ++length_idx_stderr)
+      for (int write_mode = 0; write_mode < write_mode_last; ++write_mode)
+        for (int signal = 0; signal < 2; ++signal)
+          for (int status = 0; status < 2; ++status)
+            {
+              struct test test =
+                {
+                  .out = random_string (lengths[length_idx_stdout]),
+                  .err = random_string (lengths[length_idx_stderr]),
+                  .write_mode = write_mode,
+                  .signal = signal * SIGTERM, /* 0 or SIGTERM.  */
+                  .status = status * 3,       /* 0 or 3.  */
+                };
+              TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]);
+              TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]);
+
+              struct support_capture_subprocess result
+                = support_capture_subprocess (callback, &test);
+              check_stream ("stdout", &result.out, test.out);
+              check_stream ("stderr", &result.err, test.err);
+              if (test.signal != 0)
+                {
+                  TEST_VERIFY (WIFSIGNALED (result.status));
+                  TEST_VERIFY (WTERMSIG (result.status) == test.signal);
+                }
+              else
+                {
+                  TEST_VERIFY (WIFEXITED (result.status));
+                  TEST_VERIFY (WEXITSTATUS (result.status) == test.status);
+                }
+              support_capture_subprocess_free (&result);
+              free (test.out);
+              free (test.err);
+            }
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/support/tst-support_format_dns_packet.c b/support/tst-support_format_dns_packet.c
new file mode 100644
index 0000000..9c8589c
--- /dev/null
+++ b/support/tst-support_format_dns_packet.c
@@ -0,0 +1,101 @@
+/* Tests for the support_format_dns_packet function.
+   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/check.h>
+#include <support/format_nss.h>
+#include <support/run_diff.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void
+check_packet (const void *buffer, size_t length,
+              const char *name, const char *expected)
+{
+  char *actual = support_format_dns_packet (buffer, length);
+  if (strcmp (actual, expected) != 0)
+    {
+      support_record_failure ();
+      printf ("error: formatted packet does not match: %s\n", name);
+      support_run_diff ("expected", expected,
+                        "actual", actual);
+    }
+  free (actual);
+}
+
+static void
+test_aaaa_length (void)
+{
+  static const char packet[] =
+    /* Header: Response with two records.  */
+    "\x12\x34\x80\x00\x00\x01\x00\x02\x00\x00\x00\x00"
+    /* Question section.  www.example/IN/AAAA.  */
+    "\x03www\x07""example\x00\x00\x1c\x00\x01"
+    /* Answer section.  www.example AAAA [corrupted].  */
+    "\xc0\x0c"
+    "\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x10"
+    "\x20\x01\x0d\xb8\x05\x06\x07\x08"
+    "\x11\x12\x13\x14\x15\x16\x17\x18"
+    /* www.example AAAA [corrupted].  */
+    "\xc0\x0c"
+    "\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x11"
+    "\x01\x02\x03\x04\x05\x06\x07\x08"
+    "\x11\x12\x13\x14\x15\x16\x17\x18" "\xff";
+  check_packet (packet, sizeof (packet) - 1, __func__,
+                "name: www.example\n"
+                "address: 2001:db8:506:708:1112:1314:1516:1718\n"
+                "error: AAAA record of size 17: www.example\n");
+}
+
+static void
+test_multiple_cnames (void)
+{
+  static const char packet[] =
+    /* Header: Response with three records.  */
+    "\x12\x34\x80\x00\x00\x01\x00\x03\x00\x00\x00\x00"
+    /* Question section.  www.example/IN/A.  */
+    "\x03www\x07""example\x00\x00\x01\x00\x01"
+    /* Answer section.  www.example CNAME www1.example.  */
+    "\xc0\x0c"
+    "\x00\x05\x00\x01\x00\x00\x00\x00\x00\x07"
+    "\x04www1\xc0\x10"
+    /* www1 CNAME www2.  */
+    "\x04www1\xc0\x10"
+    "\x00\x05\x00\x01\x00\x00\x00\x00\x00\x07"
+    "\x04www2\xc0\x10"
+    /* www2 A 192.0.2.1.  */
+    "\x04www2\xc0\x10"
+    "\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04"
+    "\xc0\x00\x02\x01";
+  check_packet (packet, sizeof (packet) - 1, __func__,
+                "name: www.example\n"
+                "name: www1.example\n"
+                "name: www2.example\n"
+                "address: 192.0.2.1\n");
+}
+
+static int
+do_test (void)
+{
+  test_aaaa_length ();
+  test_multiple_cnames ();
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/support/tst-support_record_failure-2.sh b/support/tst-support_record_failure-2.sh
new file mode 100644
index 0000000..2c9372c
--- /dev/null
+++ b/support/tst-support_record_failure-2.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+# Test failure recording (with and without --direct).
+# 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/>.  */
+
+set -e
+
+common_objpfx=$1; shift
+test_program_prefix_before_env=$1; shift
+run_program_env=$1; shift
+test_program_prefix_after_env=$1; shift
+
+run_test () {
+    expected_status="$1"
+    expected_output="$2"
+    shift 2
+    args="${common_objpfx}support/tst-support_record_failure $*"
+    echo "running: $args"
+    set +e
+    output="$(${test_program_prefix_before_env} \
+		 ${run_program} ${test_program_prefix_after_env} $args)"
+    status=$?
+    set -e
+    echo "  exit status: $status"
+    if test "$output" != "$expected_output" ; then
+	echo "error: unexpected output: $output"
+	exit 1
+    fi
+    if test "$status" -ne "$expected_status" ; then
+	echo "error: exit status $expected_status expected"
+	exit 1
+    fi
+}
+
+different_status () {
+    direct="$1"
+    run_test 1 "error: 1 test failures" $direct --status=0
+    run_test 1 "error: 1 test failures" $direct --status=1
+    run_test 2 "error: 1 test failures" $direct --status=2
+    run_test 1 "error: 1 test failures" $direct --status=77
+    run_test 2 "error: tst-support_record_failure.c:109: not true: false
+error: 1 test failures" $direct --test-verify
+    run_test 2 "error: tst-support_record_failure.c:109: not true: false
+info: execution passed failed TEST_VERIFY
+error: 1 test failures" $direct --test-verify --verbose
+}
+
+different_status
+different_status --direct
+
+run_test 1 "error: tst-support_record_failure.c:116: not true: false
+error: 1 test failures" --test-verify-exit
+# --direct does not print the summary error message if exit is called.
+run_test 1 "error: tst-support_record_failure.c:116: not true: false" \
+	 --direct --test-verify-exit
diff --git a/support/tst-support_record_failure.c b/support/tst-support_record_failure.c
new file mode 100644
index 0000000..e739e73
--- /dev/null
+++ b/support/tst-support_record_failure.c
@@ -0,0 +1,153 @@
+/* Test support_record_failure state sharing.
+   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/check.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+#include <support/xunistd.h>
+
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static int exit_status_with_failure = -1;
+static bool test_verify;
+static bool test_verify_exit;
+enum
+  {
+    OPT_STATUS = 10001,
+    OPT_TEST_VERIFY,
+    OPT_TEST_VERIFY_EXIT,
+  };
+#define CMDLINE_OPTIONS                                                 \
+  { "status", required_argument, NULL, OPT_STATUS },                    \
+  { "test-verify", no_argument, NULL, OPT_TEST_VERIFY },                \
+  { "test-verify-exit", no_argument, NULL, OPT_TEST_VERIFY_EXIT },
+static void
+cmdline_process (int c)
+{
+  switch (c)
+    {
+    case OPT_STATUS:
+      exit_status_with_failure = atoi (optarg);
+      break;
+    case OPT_TEST_VERIFY:
+      test_verify = true;
+      break;
+    case OPT_TEST_VERIFY_EXIT:
+      test_verify_exit = true;
+      break;
+    }
+}
+#define CMDLINE_PROCESS cmdline_process
+
+static void
+check_failure_reporting (int phase, int zero, int unsupported)
+{
+  int status = support_report_failure (0);
+  if (status != zero)
+    {
+      printf ("real-error (phase %d): support_report_failure (0) == %d\n",
+              phase, status);
+      exit (1);
+    }
+  status = support_report_failure (1);
+  if (status != 1)
+    {
+      printf ("real-error (phase %d): support_report_failure (1) == %d\n",
+              phase, status);
+      exit (1);
+    }
+  status = support_report_failure (2);
+  if (status != 2)
+    {
+      printf ("real-error (phase %d): support_report_failure (2) == %d\n",
+              phase, status);
+      exit (1);
+    }
+  status = support_report_failure (EXIT_UNSUPPORTED);
+  if (status != unsupported)
+    {
+      printf ("real-error (phase %d): "
+              "support_report_failure (EXIT_UNSUPPORTED) == %d\n",
+              phase, status);
+      exit (1);
+    }
+}
+
+static int
+do_test (void)
+{
+  if (exit_status_with_failure >= 0)
+    {
+      /* External invocation with requested error status.  Used by
+         tst-support_report_failure-2.sh.  */
+      support_record_failure ();
+      return exit_status_with_failure;
+    }
+  TEST_VERIFY (true);
+  TEST_VERIFY_EXIT (true);
+  if (test_verify)
+    {
+      TEST_VERIFY (false);
+      if (test_verbose)
+        printf ("info: execution passed failed TEST_VERIFY\n");
+      return 2; /* Expected exit status.  */
+    }
+  if (test_verify_exit)
+    {
+      TEST_VERIFY_EXIT (false);
+      return 3; /* Not reached.  Expected exit status is 1.  */
+    }
+
+  printf ("info: This test tests the test framework.\n"
+          "info: It reports some expected errors on stdout.\n");
+
+  /* Check that the status is passed through unchanged.  */
+  check_failure_reporting (1, 0, EXIT_UNSUPPORTED);
+
+  /* Check state propagation from a subprocess.  */
+  pid_t pid = xfork ();
+  if (pid == 0)
+    {
+      support_record_failure ();
+      _exit (0);
+    }
+  int status;
+  xwaitpid (pid, &status, 0);
+  if (status != 0)
+    {
+      printf ("real-error: incorrect status from subprocess: %d\n", status);
+      return 1;
+    }
+  check_failure_reporting (2, 1, 1);
+
+  /* Also test directly in the parent process.  */
+  support_record_failure_reset ();
+  check_failure_reporting (3, 0, EXIT_UNSUPPORTED);
+  support_record_failure ();
+  check_failure_reporting (4, 1, 1);
+
+  /* We need to mask the failure above.  */
+  support_record_failure_reset ();
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/support/write_message.c b/support/write_message.c
new file mode 100644
index 0000000..f03ed93
--- /dev/null
+++ b/support/write_message.c
@@ -0,0 +1,29 @@
+/* Write a message to standard output.
+   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>
+#include <unistd.h>
+
+void
+write_message (const char *message)
+{
+  ssize_t unused __attribute__ ((unused));
+  unused = write (STDOUT_FILENO, message, strlen (message));
+}
diff --git a/support/xaccept.c b/support/xaccept.c
new file mode 100644
index 0000000..7b25af3
--- /dev/null
+++ b/support/xaccept.c
@@ -0,0 +1,32 @@
+/* accept 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/xsocket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+int
+xaccept (int fd, struct sockaddr *sa, socklen_t *salen)
+{
+  int clientfd = accept (fd, sa, salen);
+  if (clientfd < 0)
+    FAIL_EXIT1 ("accept (%d): %m", fd);
+  return clientfd;
+}
diff --git a/support/xaccept4.c b/support/xaccept4.c
new file mode 100644
index 0000000..67dd95e
--- /dev/null
+++ b/support/xaccept4.c
@@ -0,0 +1,32 @@
+/* accept4 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/xsocket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+int
+xaccept4 (int fd, struct sockaddr *sa, socklen_t *salen, int flags)
+{
+  int clientfd = accept4 (fd, sa, salen, flags);
+  if (clientfd < 0)
+    FAIL_EXIT1 ("accept4 (%d, 0x%x): %m", fd, flags);
+  return clientfd;
+}
diff --git a/support/xasprintf.c b/support/xasprintf.c
new file mode 100644
index 0000000..5157680
--- /dev/null
+++ b/support/xasprintf.c
@@ -0,0 +1,36 @@
+/* Error-checking wrapper for asprintf.
+   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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+char *
+xasprintf (const char *format, ...)
+{
+  va_list ap;
+  va_start (ap, format);
+  char *result;
+  if (vasprintf (&result, format, ap) < 0)
+    FAIL_EXIT1 ("asprintf: %m");
+  va_end (ap);
+  return result;
+}
diff --git a/support/xbind.c b/support/xbind.c
new file mode 100644
index 0000000..cfc6dd8
--- /dev/null
+++ b/support/xbind.c
@@ -0,0 +1,30 @@
+/* bind 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/xsocket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+void
+xbind (int fd, const struct sockaddr *sa, socklen_t sa_len)
+{
+  if (bind (fd, sa, sa_len) != 0)
+    FAIL_EXIT1 ("bind (%d), family %d: %m", fd, sa->sa_family);
+}
diff --git a/support/xcalloc.c b/support/xcalloc.c
new file mode 100644
index 0000000..135f42d
--- /dev/null
+++ b/support/xcalloc.c
@@ -0,0 +1,34 @@
+/* Error-checking wrapper for calloc.
+   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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void *
+xcalloc (size_t n, size_t s)
+{
+  void *p;
+
+  p = calloc (n, s);
+  if (p == NULL)
+    oom_error ("calloc", n * s);
+  return p;
+}
diff --git a/support/xchroot.c b/support/xchroot.c
new file mode 100644
index 0000000..abcc299
--- /dev/null
+++ b/support/xchroot.c
@@ -0,0 +1,28 @@
+/* chroot 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
+xchroot (const char *path)
+{
+  if (chroot (path) != 0)
+    FAIL_EXIT1 ("chroot (\"%s\"): %m", path);
+}
diff --git a/support/xclose.c b/support/xclose.c
new file mode 100644
index 0000000..c931e08
--- /dev/null
+++ b/support/xclose.c
@@ -0,0 +1,28 @@
+/* close 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/xunistd.h>
+#include <support/check.h>
+#include <errno.h>
+
+void
+xclose (int fd)
+{
+  if (close (fd) < 0 && errno != EINTR)
+    FAIL_EXIT1 ("close of descriptor %d failed: %m", fd);
+}
diff --git a/support/xconnect.c b/support/xconnect.c
new file mode 100644
index 0000000..0266dbc
--- /dev/null
+++ b/support/xconnect.c
@@ -0,0 +1,30 @@
+/* connect 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/xsocket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+void
+xconnect (int fd, const struct sockaddr *sa, socklen_t sa_len)
+{
+  if (connect (fd, sa, sa_len) != 0)
+    FAIL_EXIT1 ("connect (%d), family %d: %m", fd, sa->sa_family);
+}
diff --git a/support/xdup2.c b/support/xdup2.c
new file mode 100644
index 0000000..dc08c94
--- /dev/null
+++ b/support/xdup2.c
@@ -0,0 +1,28 @@
+/* dup2 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/xunistd.h>
+
+#include <support/check.h>
+
+void
+xdup2 (int from, int to)
+{
+  if (dup2 (from, to) < 0)
+    FAIL_EXIT1 ("dup2 (%d, %d): %m", from, to);
+}
diff --git a/support/xfclose.c b/support/xfclose.c
new file mode 100644
index 0000000..2737f05
--- /dev/null
+++ b/support/xfclose.c
@@ -0,0 +1,33 @@
+/* fclose 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/xstdio.h>
+
+#include <support/check.h>
+#include <stdlib.h>
+
+void
+xfclose (FILE *fp)
+{
+  if (ferror (fp))
+    FAIL_EXIT1 ("stdio stream closed with pending errors");
+  if (fflush (fp) != 0)
+    FAIL_EXIT1 ("fflush: %m");
+  if (fclose (fp) != 0)
+    FAIL_EXIT1 ("fclose: %m");
+}
diff --git a/support/xfopen.c b/support/xfopen.c
new file mode 100644
index 0000000..14532a0
--- /dev/null
+++ b/support/xfopen.c
@@ -0,0 +1,31 @@
+/* fopen 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/xstdio.h>
+
+#include <support/check.h>
+#include <stdlib.h>
+
+FILE *
+xfopen (const char *path, const char *mode)
+{
+  FILE *fp = fopen (path, mode);
+  if (fp == NULL)
+    FAIL_EXIT1 ("could not open %s (mode \"%s\"): %m", path, mode);
+  return fp;
+}
diff --git a/support/xfork.c b/support/xfork.c
new file mode 100644
index 0000000..aa52ba6
--- /dev/null
+++ b/support/xfork.c
@@ -0,0 +1,32 @@
+/* fork 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/xunistd.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+pid_t
+xfork (void)
+{
+  pid_t result = fork ();
+  if (result < 0)
+    FAIL_EXIT1 ("fork: %m");
+  return result;
+}
diff --git a/support/xgetsockname.c b/support/xgetsockname.c
new file mode 100644
index 0000000..c3bd884
--- /dev/null
+++ b/support/xgetsockname.c
@@ -0,0 +1,30 @@
+/* getsockname 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/xsocket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+void
+xgetsockname (int fd, struct sockaddr *sa, socklen_t *plen)
+{
+  if (getsockname (fd, sa, plen) != 0)
+    FAIL_EXIT1 ("setsockopt (%d): %m", fd);
+}
diff --git a/support/xlisten.c b/support/xlisten.c
new file mode 100644
index 0000000..1953e59
--- /dev/null
+++ b/support/xlisten.c
@@ -0,0 +1,30 @@
+/* listen 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/xsocket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+void
+xlisten (int fd, int backlog)
+{
+  if (listen (fd, backlog) != 0)
+    FAIL_EXIT1 ("listen (%d, %d): %m", fd, backlog);
+}
diff --git a/support/xmalloc.c b/support/xmalloc.c
new file mode 100644
index 0000000..450f699
--- /dev/null
+++ b/support/xmalloc.c
@@ -0,0 +1,34 @@
+/* Error-checking wrapper for malloc.
+   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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void *
+xmalloc (size_t n)
+{
+  void *p;
+
+  p = malloc (n);
+  if (p == NULL)
+    oom_error ("malloc", n);
+  return p;
+}
diff --git a/support/xmemstream.c b/support/xmemstream.c
new file mode 100644
index 0000000..bce6dc9
--- /dev/null
+++ b/support/xmemstream.c
@@ -0,0 +1,42 @@
+/* Error-checking wrappers for memstream functions.
+   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/xmemstream.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+
+void
+xopen_memstream (struct xmemstream *stream)
+{
+  int old_errno = errno;
+  *stream = (struct xmemstream) {};
+  stream->out = open_memstream (&stream->buffer, &stream->length);
+  if (stream->out == NULL)
+    FAIL_EXIT1 ("open_memstream: %m");
+  errno = old_errno;
+}
+
+void
+xfclose_memstream (struct xmemstream *stream)
+{
+  xfclose (stream->out);
+  stream->out = NULL;
+}
diff --git a/support/xmemstream.h b/support/xmemstream.h
new file mode 100644
index 0000000..e5ba231
--- /dev/null
+++ b/support/xmemstream.h
@@ -0,0 +1,49 @@
+/* Error-checking wrappers for memstream functions.
+   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/>.  */
+
+#ifndef SUPPORT_XMEMSTREAM_H
+#define SUPPORT_XMEMSTREAM_H
+
+#include <stdio.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Wrappers for other libc functions.  */
+struct xmemstream
+{
+  FILE *out;
+  char *buffer;
+  size_t length;
+};
+
+/* Create a new in-memory stream.  Initializes *STREAM.  After this
+   function returns, STREAM->out is a file descriptor open for
+   writing.  errno is preserved, so that the %m format specifier can
+   be used for writing to STREAM->out.  */
+void xopen_memstream (struct xmemstream *stream);
+
+/* Closes STREAM->OUT.  After this function returns, STREAM->buffer
+   and STREAM->length denote a memory range which contains the bytes
+   written to the output stream.  The caller should free
+   STREAM->buffer.  */
+void xfclose_memstream (struct xmemstream *stream);
+
+__END_DECLS
+
+#endif /* SUPPORT_XMEMSTREAM_H */
diff --git a/support/xmkdir.c b/support/xmkdir.c
new file mode 100644
index 0000000..ea17d49
--- /dev/null
+++ b/support/xmkdir.c
@@ -0,0 +1,28 @@
+/* mkdir 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
+xmkdir (const char *path, mode_t mode)
+{
+  if (mkdir (path, mode) != 0)
+    FAIL_EXIT1 ("mkdir (\"%s\", 0%o): %m", path, mode);
+}
diff --git a/support/xmmap.c b/support/xmmap.c
new file mode 100644
index 0000000..435b1eb
--- /dev/null
+++ b/support/xmmap.c
@@ -0,0 +1,31 @@
+/* mmap 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/check.h>
+#include <support/xunistd.h>
+#include <sys/mman.h>
+
+void *
+xmmap (void *addr, size_t length, int prot, int flags, int fd)
+{
+  void *result = mmap (addr, length, prot, flags, fd, 0);
+  if (result == MAP_FAILED)
+    FAIL_EXIT1 ("mmap of %zu bytes, prot=0x%x, flags=0x%x: %m",
+                length, prot, flags);
+  return result;
+}
diff --git a/support/xmunmap.c b/support/xmunmap.c
new file mode 100644
index 0000000..6ef5a4a
--- /dev/null
+++ b/support/xmunmap.c
@@ -0,0 +1,28 @@
+/* munmap 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/check.h>
+#include <support/xunistd.h>
+#include <sys/mman.h>
+
+void
+xmunmap (void *addr, size_t length)
+{
+  if (munmap (addr, length) != 0)
+    FAIL_EXIT1 ("munmap of %zu bytes: %m", length);
+}
diff --git a/support/xopen.c b/support/xopen.c
new file mode 100644
index 0000000..7f033a0
--- /dev/null
+++ b/support/xopen.c
@@ -0,0 +1,30 @@
+/* open64 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 <fcntl.h>
+
+int
+xopen (const char *path, int flags, mode_t mode)
+{
+  int ret = open64 (path, flags, mode);
+  if (ret < 0)
+    FAIL_EXIT1 ("open64 (\"%s\", 0x%x, 0%o): %m", path, flags, mode);
+  return ret;
+}
diff --git a/support/xpipe.c b/support/xpipe.c
new file mode 100644
index 0000000..89a64a5
--- /dev/null
+++ b/support/xpipe.c
@@ -0,0 +1,28 @@
+/* pipe 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/xunistd.h>
+
+#include <support/check.h>
+
+void
+xpipe (int fds[2])
+{
+  if (pipe (fds) < 0)
+    FAIL_EXIT1 ("pipe: %m");
+}
diff --git a/support/xpoll.c b/support/xpoll.c
new file mode 100644
index 0000000..bec2521
--- /dev/null
+++ b/support/xpoll.c
@@ -0,0 +1,32 @@
+/* poll 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/xsocket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+int
+xpoll (struct pollfd *fds, nfds_t nfds, int timeout)
+{
+  int ret = poll (fds, nfds, timeout);
+  if (ret < 0)
+    FAIL_EXIT1 ("poll: %m");
+  return ret;
+}
diff --git a/support/xpthread_attr_destroy.c b/support/xpthread_attr_destroy.c
new file mode 100644
index 0000000..664c809
--- /dev/null
+++ b/support/xpthread_attr_destroy.c
@@ -0,0 +1,26 @@
+/* pthread_attr_destroy 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/xthread.h>
+
+void
+xpthread_attr_destroy (pthread_attr_t *attr)
+{
+  xpthread_check_return ("pthread_attr_destroy",
+			 pthread_attr_destroy (attr));
+}
diff --git a/support/xpthread_attr_init.c b/support/xpthread_attr_init.c
new file mode 100644
index 0000000..2e30ade
--- /dev/null
+++ b/support/xpthread_attr_init.c
@@ -0,0 +1,25 @@
+/* pthread_attr_init 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/xthread.h>
+
+void
+xpthread_attr_init (pthread_attr_t *attr)
+{
+  xpthread_check_return ("pthread_attr_init", pthread_attr_init (attr));
+}
diff --git a/support/xpthread_attr_setdetachstate.c b/support/xpthread_attr_setdetachstate.c
new file mode 100644
index 0000000..b544dba
--- /dev/null
+++ b/support/xpthread_attr_setdetachstate.c
@@ -0,0 +1,27 @@
+/* pthread_attr_setdetachstate 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/xthread.h>
+
+void
+xpthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate)
+{
+  xpthread_check_return ("pthread_attr_setdetachstate",
+			 pthread_attr_setdetachstate (attr,
+						      detachstate));
+}
diff --git a/support/xpthread_attr_setstacksize.c b/support/xpthread_attr_setstacksize.c
new file mode 100644
index 0000000..02d0631
--- /dev/null
+++ b/support/xpthread_attr_setstacksize.c
@@ -0,0 +1,26 @@
+/* pthread_attr_setstacksize 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/xthread.h>
+
+void
+xpthread_attr_setstacksize (pthread_attr_t *attr, size_t stacksize)
+{
+  xpthread_check_return ("pthread_attr_setstacksize",
+			 pthread_attr_setstacksize (attr, stacksize));
+}
diff --git a/support/xpthread_barrier_destroy.c b/support/xpthread_barrier_destroy.c
new file mode 100644
index 0000000..efc0719
--- /dev/null
+++ b/support/xpthread_barrier_destroy.c
@@ -0,0 +1,26 @@
+/* pthread_barrier_destroy 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/xthread.h>
+
+void
+xpthread_barrier_destroy (pthread_barrier_t *barrier)
+{
+  xpthread_check_return ("pthread_barrier_destroy",
+                         pthread_barrier_destroy (barrier));
+}
diff --git a/support/xpthread_barrier_init.c b/support/xpthread_barrier_init.c
new file mode 100644
index 0000000..b32dad1
--- /dev/null
+++ b/support/xpthread_barrier_init.c
@@ -0,0 +1,27 @@
+/* pthread_barrier_init 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/xthread.h>
+
+void
+xpthread_barrier_init (pthread_barrier_t *barrier,
+                       pthread_barrierattr_t *attr, unsigned int count)
+{
+  xpthread_check_return ("pthread_barrier_init",
+                         pthread_barrier_init (barrier, attr, count));
+}
diff --git a/support/xpthread_barrier_wait.c b/support/xpthread_barrier_wait.c
new file mode 100644
index 0000000..7cee44d
--- /dev/null
+++ b/support/xpthread_barrier_wait.c
@@ -0,0 +1,28 @@
+/* pthread_barrier_wait 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/xthread.h>
+
+int
+xpthread_barrier_wait (pthread_barrier_t *barrier)
+{
+  int ret = pthread_barrier_wait (barrier);
+  if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
+    xpthread_check_return ("pthread_barrier_wait", ret);
+  return ret == PTHREAD_BARRIER_SERIAL_THREAD;
+}
diff --git a/support/xpthread_cancel.c b/support/xpthread_cancel.c
new file mode 100644
index 0000000..3af16f9
--- /dev/null
+++ b/support/xpthread_cancel.c
@@ -0,0 +1,25 @@
+/* pthread_cancel 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/xthread.h>
+
+void
+xpthread_cancel (pthread_t thr)
+{
+  xpthread_check_return ("pthread_cancel", pthread_cancel (thr));
+}
diff --git a/support/xpthread_check_return.c b/support/xpthread_check_return.c
new file mode 100644
index 0000000..3094d82
--- /dev/null
+++ b/support/xpthread_check_return.c
@@ -0,0 +1,34 @@
+/* Return value checking for pthread functions, exit variant.
+   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/xthread.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+void
+xpthread_check_return (const char *function, int value)
+{
+  if (value != 0)
+    {
+      errno = value;
+      FAIL_EXIT1 ("%s: %m", function);
+    }
+}
diff --git a/support/xpthread_cond_wait.c b/support/xpthread_cond_wait.c
new file mode 100644
index 0000000..b0e9b2a
--- /dev/null
+++ b/support/xpthread_cond_wait.c
@@ -0,0 +1,26 @@
+/* pthread_cond_wait 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/xthread.h>
+
+void
+xpthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+  xpthread_check_return
+    ("pthread_cond_wait", pthread_cond_wait (cond, mutex));
+}
diff --git a/support/xpthread_create.c b/support/xpthread_create.c
new file mode 100644
index 0000000..98c63e5
--- /dev/null
+++ b/support/xpthread_create.c
@@ -0,0 +1,29 @@
+/* pthread_create 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/xthread.h>
+
+pthread_t
+xpthread_create (pthread_attr_t *attr,
+                 void *(*thread_func) (void *), void *closure)
+{
+  pthread_t thr;
+  xpthread_check_return
+    ("pthread_create", pthread_create (&thr, attr, thread_func, closure));
+  return thr;
+}
diff --git a/support/xpthread_detach.c b/support/xpthread_detach.c
new file mode 100644
index 0000000..2088af2
--- /dev/null
+++ b/support/xpthread_detach.c
@@ -0,0 +1,25 @@
+/* pthread_detach 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/xthread.h>
+
+void
+xpthread_detach (pthread_t thr)
+{
+  xpthread_check_return ("pthread_detach", pthread_detach (thr));
+}
diff --git a/support/xpthread_join.c b/support/xpthread_join.c
new file mode 100644
index 0000000..f23bb9a
--- /dev/null
+++ b/support/xpthread_join.c
@@ -0,0 +1,27 @@
+/* pthread_join 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/xthread.h>
+
+void *
+xpthread_join (pthread_t thr)
+{
+  void *result;
+  xpthread_check_return ("pthread_join", pthread_join (thr, &result));
+  return result;
+}
diff --git a/support/xpthread_mutex_consistent.c b/support/xpthread_mutex_consistent.c
new file mode 100644
index 0000000..52364be
--- /dev/null
+++ b/support/xpthread_mutex_consistent.c
@@ -0,0 +1,26 @@
+/* pthread_mutex_consistent 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/xthread.h>
+
+void
+xpthread_mutex_consistent (pthread_mutex_t *mutex)
+{
+  xpthread_check_return ("pthread_mutex_consistent",
+                         pthread_mutex_consistent (mutex));
+}
diff --git a/support/xpthread_mutex_destroy.c b/support/xpthread_mutex_destroy.c
new file mode 100644
index 0000000..f11f8f0
--- /dev/null
+++ b/support/xpthread_mutex_destroy.c
@@ -0,0 +1,26 @@
+/* pthread_mutex_destroy 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/xthread.h>
+
+void
+xpthread_mutex_destroy (pthread_mutex_t *mutex)
+{
+  xpthread_check_return ("pthread_mutex_destroy",
+                         pthread_mutex_destroy (mutex));
+}
diff --git a/support/xpthread_mutex_init.c b/support/xpthread_mutex_init.c
new file mode 100644
index 0000000..2d16d1b
--- /dev/null
+++ b/support/xpthread_mutex_init.c
@@ -0,0 +1,26 @@
+/* pthread_mutex_init 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/xthread.h>
+
+void
+xpthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
+{
+  xpthread_check_return ("pthread_mutex_init",
+                         pthread_mutex_init (mutex, attr));
+}
diff --git a/support/xpthread_mutex_lock.c b/support/xpthread_mutex_lock.c
new file mode 100644
index 0000000..af727b4
--- /dev/null
+++ b/support/xpthread_mutex_lock.c
@@ -0,0 +1,25 @@
+/* pthread_mutex_lock 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/xthread.h>
+
+void
+xpthread_mutex_lock (pthread_mutex_t *mutex)
+{
+  xpthread_check_return ("pthread_mutex_lock", pthread_mutex_lock (mutex));
+}
diff --git a/support/xpthread_mutex_unlock.c b/support/xpthread_mutex_unlock.c
new file mode 100644
index 0000000..161b41e
--- /dev/null
+++ b/support/xpthread_mutex_unlock.c
@@ -0,0 +1,25 @@
+/* pthread_mutex_unlock 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/xthread.h>
+
+void
+xpthread_mutex_unlock (pthread_mutex_t *mutex)
+{
+  xpthread_check_return ("pthread_mutex_unlock", pthread_mutex_unlock (mutex));
+}
diff --git a/support/xpthread_mutexattr_destroy.c b/support/xpthread_mutexattr_destroy.c
new file mode 100644
index 0000000..c699e32
--- /dev/null
+++ b/support/xpthread_mutexattr_destroy.c
@@ -0,0 +1,26 @@
+/* pthread_mutexattr_destroy 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/xthread.h>
+
+void
+xpthread_mutexattr_destroy (pthread_mutexattr_t *attr)
+{
+  xpthread_check_return ("pthread_mutexattr_destroy",
+                         pthread_mutexattr_destroy (attr));
+}
diff --git a/support/xpthread_mutexattr_init.c b/support/xpthread_mutexattr_init.c
new file mode 100644
index 0000000..fa93fab
--- /dev/null
+++ b/support/xpthread_mutexattr_init.c
@@ -0,0 +1,25 @@
+/* pthread_mutexattr_init 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/xthread.h>
+
+void
+xpthread_mutexattr_init (pthread_mutexattr_t *attr)
+{
+  xpthread_check_return ("pthread_mutexattr_init", pthread_mutexattr_init (attr));
+}
diff --git a/support/xpthread_mutexattr_setprotocol.c b/support/xpthread_mutexattr_setprotocol.c
new file mode 100644
index 0000000..353f75e
--- /dev/null
+++ b/support/xpthread_mutexattr_setprotocol.c
@@ -0,0 +1,26 @@
+/* pthread_mutexattr_setprotocol 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/xthread.h>
+
+void
+xpthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int flag)
+{
+  xpthread_check_return ("pthread_mutexattr_setprotocol",
+                         pthread_mutexattr_setprotocol (attr, flag));
+}
diff --git a/support/xpthread_mutexattr_setpshared.c b/support/xpthread_mutexattr_setpshared.c
new file mode 100644
index 0000000..242da1a
--- /dev/null
+++ b/support/xpthread_mutexattr_setpshared.c
@@ -0,0 +1,26 @@
+/* pthread_mutexattr_setpshared 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/xthread.h>
+
+void
+xpthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int flag)
+{
+  xpthread_check_return ("pthread_mutexattr_setpshared",
+                         pthread_mutexattr_setpshared (attr, flag));
+}
diff --git a/support/xpthread_mutexattr_setrobust.c b/support/xpthread_mutexattr_setrobust.c
new file mode 100644
index 0000000..d7d6fa8
--- /dev/null
+++ b/support/xpthread_mutexattr_setrobust.c
@@ -0,0 +1,26 @@
+/* pthread_mutexattr_setrobust 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/xthread.h>
+
+void
+xpthread_mutexattr_setrobust (pthread_mutexattr_t *attr, int flag)
+{
+  xpthread_check_return ("pthread_mutexattr_setrobust",
+                         pthread_mutexattr_setrobust (attr, flag));
+}
diff --git a/support/xpthread_mutexattr_settype.c b/support/xpthread_mutexattr_settype.c
new file mode 100644
index 0000000..cf22170
--- /dev/null
+++ b/support/xpthread_mutexattr_settype.c
@@ -0,0 +1,26 @@
+/* pthread_mutexattr_settype 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/xthread.h>
+
+void
+xpthread_mutexattr_settype (pthread_mutexattr_t *attr, int flag)
+{
+  xpthread_check_return ("pthread_mutexattr_settype",
+                         pthread_mutexattr_settype (attr, flag));
+}
diff --git a/support/xpthread_once.c b/support/xpthread_once.c
new file mode 100644
index 0000000..70d58db
--- /dev/null
+++ b/support/xpthread_once.c
@@ -0,0 +1,25 @@
+/* pthread_once 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/xthread.h>
+
+void
+xpthread_once (pthread_once_t *guard, void (*func) (void))
+{
+  xpthread_check_return ("pthread_once", pthread_once (guard, func));
+}
diff --git a/support/xpthread_sigmask.c b/support/xpthread_sigmask.c
new file mode 100644
index 0000000..0ba9ca0
--- /dev/null
+++ b/support/xpthread_sigmask.c
@@ -0,0 +1,34 @@
+/* pthread_sigmask 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/xsignal.h>
+#include <support/support.h>
+
+#include <unistd.h>
+
+void
+xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset)
+{
+  if (pthread_sigmask (how, set, oldset) != 0)
+    {
+      write_message ("error: pthread_setmask failed\n");
+      /* Do not use exit because pthread_sigmask can be called from a
+         signal handler.  */
+      _exit (1);
+    }
+}
diff --git a/support/xpthread_spin_lock.c b/support/xpthread_spin_lock.c
new file mode 100644
index 0000000..6975215
--- /dev/null
+++ b/support/xpthread_spin_lock.c
@@ -0,0 +1,25 @@
+/* pthread_spin_lock 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/xthread.h>
+
+void
+xpthread_spin_lock (pthread_spinlock_t *lock)
+{
+  xpthread_check_return ("pthread_spin_lock", pthread_spin_lock (lock));
+}
diff --git a/support/xpthread_spin_unlock.c b/support/xpthread_spin_unlock.c
new file mode 100644
index 0000000..4f19a44
--- /dev/null
+++ b/support/xpthread_spin_unlock.c
@@ -0,0 +1,25 @@
+/* pthread_spin_unlock 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/xthread.h>
+
+void
+xpthread_spin_unlock (pthread_spinlock_t *lock)
+{
+  xpthread_check_return ("pthread_spin_unlock", pthread_spin_unlock (lock));
+}
diff --git a/support/xrealloc.c b/support/xrealloc.c
new file mode 100644
index 0000000..00c3138
--- /dev/null
+++ b/support/xrealloc.c
@@ -0,0 +1,32 @@
+/* Error-checking wrapper for realloc.
+   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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void *
+xrealloc (void *p, size_t n)
+{
+  void *result = realloc (p, n);
+  if (result == NULL && (n > 0 || p == NULL))
+    oom_error ("realloc", n);
+  return result;
+}
diff --git a/support/xrecvfrom.c b/support/xrecvfrom.c
new file mode 100644
index 0000000..17809c4
--- /dev/null
+++ b/support/xrecvfrom.c
@@ -0,0 +1,33 @@
+/* recvfrom 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/xsocket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+size_t
+xrecvfrom (int fd, void *buf, size_t buflen, int flags,
+           struct sockaddr *sa, socklen_t *salen)
+{
+  ssize_t ret = recvfrom (fd, buf, buflen, flags, sa, salen);
+  if (ret < 0)
+    FAIL_EXIT1 ("error: recvfrom (%d), %zu bytes buffer: %m", fd, buflen);
+  return ret;
+}
diff --git a/support/xsendto.c b/support/xsendto.c
new file mode 100644
index 0000000..20bddf6
--- /dev/null
+++ b/support/xsendto.c
@@ -0,0 +1,35 @@
+/* sendto 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/xsocket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+void
+xsendto (int fd, const void *buf, size_t buflen, int flags,
+         const struct sockaddr *sa, socklen_t salen)
+{
+  ssize_t ret = sendto (fd, buf, buflen, flags, sa, salen);
+  if (ret < 0)
+    FAIL_EXIT1 ("sendto (%d), %zu bytes, family %d: %m",
+                fd, buflen, sa->sa_family);
+  if (ret != buflen)
+    FAIL_EXIT1 ("sendto (%d) sent %zd bytes instead of %zu", fd, ret, buflen);
+}
diff --git a/support/xsetsockopt.c b/support/xsetsockopt.c
new file mode 100644
index 0000000..9931882
--- /dev/null
+++ b/support/xsetsockopt.c
@@ -0,0 +1,31 @@
+/* setsockopt 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/xsocket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+void
+xsetsockopt (int fd, int level, int name, const void *val, socklen_t vallen)
+{
+  if (setsockopt (fd, level, name, val, vallen) != 0)
+    FAIL_EXIT1 ("setsockopt (%d, %d, %d), %zu bytes: %m",
+                fd, level, name, (size_t) vallen);
+}
diff --git a/support/xsignal.h b/support/xsignal.h
new file mode 100644
index 0000000..3dc0d9d
--- /dev/null
+++ b/support/xsignal.h
@@ -0,0 +1,34 @@
+/* Support functionality for using signals.
+   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/>.  */
+
+#ifndef SUPPORT_SIGNAL_H
+#define SUPPORT_SIGNAL_H
+
+#include <signal.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* The following functions call the corresponding libpthread functions
+   and terminate the process on error.  */
+
+void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset);
+
+__END_DECLS
+
+#endif /* SUPPORT_SIGNAL_H */
diff --git a/support/xsocket.c b/support/xsocket.c
new file mode 100644
index 0000000..c1deaee
--- /dev/null
+++ b/support/xsocket.c
@@ -0,0 +1,32 @@
+/* socket 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/xsocket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+int
+xsocket (int domain, int type, int protocol)
+{
+  int fd = socket (domain, type, protocol);
+  if (fd < 0)
+    FAIL_EXIT1 ("socket (%d, %d, %d): %m\n", domain, type, protocol);
+  return fd;
+}
diff --git a/support/xsocket.h b/support/xsocket.h
new file mode 100644
index 0000000..d672494
--- /dev/null
+++ b/support/xsocket.h
@@ -0,0 +1,39 @@
+/* Error-checking wrappers for socket functions.
+   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/>.  */
+
+#ifndef SUPPORT_XSOCKET_H
+#define SUPPORT_XSOCKET_H
+
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+int xsocket (int, int, int);
+void xsetsockopt (int, int, int, const void *, socklen_t);
+void xgetsockname (int, struct sockaddr *, socklen_t *);
+void xconnect (int, const struct sockaddr *, socklen_t);
+void xbind (int, const struct sockaddr *, socklen_t);
+void xlisten (int, int);
+int xaccept (int, struct sockaddr *, socklen_t *);
+int xaccept4 (int, struct sockaddr *, socklen_t *, int);
+void xsendto (int, const void *, size_t, int,
+              const struct sockaddr *, socklen_t);
+size_t xrecvfrom (int, void *, size_t, int, struct sockaddr *, socklen_t *);
+int xpoll (struct pollfd *, nfds_t, int);
+
+#endif /* SUPPORT_XSOCKET_H */
diff --git a/support/xstdio.h b/support/xstdio.h
new file mode 100644
index 0000000..bcc2e86
--- /dev/null
+++ b/support/xstdio.h
@@ -0,0 +1,32 @@
+/* Error-checking wrappers for stdio functions.
+   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/>.  */
+
+#ifndef SUPPORT_XSTDIO_H
+#define SUPPORT_XSTDIO_H
+
+#include <stdio.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+FILE *xfopen (const char *path, const char *mode);
+void xfclose (FILE *);
+
+__END_DECLS
+
+#endif /* SUPPORT_XSTDIO_H */
diff --git a/support/xstrdup.c b/support/xstrdup.c
new file mode 100644
index 0000000..d6a8c04
--- /dev/null
+++ b/support/xstrdup.c
@@ -0,0 +1,30 @@
+/* strdup 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 *
+xstrdup (const char *s)
+{
+  char *p = strdup (s);
+  if (p == NULL)
+    oom_error ("strdup", strlen (s));
+  return p;
+}
diff --git a/support/xthread.h b/support/xthread.h
new file mode 100644
index 0000000..6dd7e70
--- /dev/null
+++ b/support/xthread.h
@@ -0,0 +1,77 @@
+/* Support functionality for using threads.
+   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/>.  */
+
+#ifndef SUPPORT_THREAD_H
+#define SUPPORT_THREAD_H
+
+#include <pthread.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/* Terminate the process (with exit status 0) after SECONDS have
+   elapsed, from a helper thread.  The process is terminated with the
+   exit function, so atexit handlers are executed.  */
+void delayed_exit (int seconds);
+
+/* Terminate the process (with exit status 1) if VALUE is not zero.
+   In that case, print a failure message to standard output mentioning
+   FUNCTION.  The process is terminated with the exit function, so
+   atexit handlers are executed.  */
+void xpthread_check_return (const char *function, int value);
+
+/* The following functions call the corresponding libpthread functions
+   and terminate the process on error.  */
+
+void xpthread_barrier_init (pthread_barrier_t *barrier,
+                            pthread_barrierattr_t *attr, unsigned int count);
+void xpthread_barrier_destroy (pthread_barrier_t *barrier);
+void xpthread_mutexattr_destroy (pthread_mutexattr_t *);
+void xpthread_mutexattr_init (pthread_mutexattr_t *);
+void xpthread_mutexattr_setprotocol (pthread_mutexattr_t *, int);
+void xpthread_mutexattr_setpshared (pthread_mutexattr_t *, int);
+void xpthread_mutexattr_setrobust (pthread_mutexattr_t *, int);
+void xpthread_mutexattr_settype (pthread_mutexattr_t *, int);
+void xpthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *);
+void xpthread_mutex_destroy (pthread_mutex_t *);
+void xpthread_mutex_lock (pthread_mutex_t *mutex);
+void xpthread_mutex_unlock (pthread_mutex_t *mutex);
+void xpthread_mutex_consistent (pthread_mutex_t *);
+void xpthread_spin_lock (pthread_spinlock_t *lock);
+void xpthread_spin_unlock (pthread_spinlock_t *lock);
+void xpthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex);
+pthread_t xpthread_create (pthread_attr_t *attr,
+                           void *(*thread_func) (void *), void *closure);
+void xpthread_detach (pthread_t thr);
+void xpthread_cancel (pthread_t thr);
+void *xpthread_join (pthread_t thr);
+void xpthread_once (pthread_once_t *guard, void (*func) (void));
+void xpthread_attr_destroy (pthread_attr_t *attr);
+void xpthread_attr_init (pthread_attr_t *attr);
+void xpthread_attr_setdetachstate (pthread_attr_t *attr,
+				   int detachstate);
+void xpthread_attr_setstacksize (pthread_attr_t *attr,
+				 size_t stacksize);
+
+/* This function returns non-zero if pthread_barrier_wait returned
+   PTHREAD_BARRIER_SERIAL_THREAD.  */
+int xpthread_barrier_wait (pthread_barrier_t *barrier);
+
+__END_DECLS
+
+#endif /* SUPPORT_THREAD_H */
diff --git a/support/xunistd.h b/support/xunistd.h
new file mode 100644
index 0000000..151d743
--- /dev/null
+++ b/support/xunistd.h
@@ -0,0 +1,56 @@
+/* POSIX-specific extra functions.
+   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/>.  */
+
+/* These wrapper functions use POSIX types and therefore cannot be
+   declared in <support/support.h>.  */
+
+#ifndef SUPPORT_XUNISTD_H
+#define SUPPORT_XUNISTD_H
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+__BEGIN_DECLS
+
+struct stat64;
+
+pid_t xfork (void);
+pid_t xwaitpid (pid_t, int *status, int flags);
+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 xmkdir (const char *path, mode_t);
+void xchroot (const char *path);
+
+/* Close the file descriptor.  Ignore EINTR errors, but terminate the
+   process on other errors.  */
+void xclose (int);
+
+/* Write the buffer.  Retry on short writes.  */
+void xwrite (int, const void *, size_t);
+
+/* Invoke mmap with a zero file offset.  */
+void *xmmap (void *addr, size_t length, int prot, int flags, int fd);
+
+void xmunmap (void *addr, size_t length);
+
+__END_DECLS
+
+#endif /* SUPPORT_XUNISTD_H */
diff --git a/support/xwaitpid.c b/support/xwaitpid.c
new file mode 100644
index 0000000..204795e
--- /dev/null
+++ b/support/xwaitpid.c
@@ -0,0 +1,33 @@
+/* waitpid 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/xunistd.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <sys/wait.h>
+
+int
+xwaitpid (int pid, int *status, int flags)
+{
+  pid_t result = waitpid (pid, status, flags);
+  if (result < 0)
+    FAIL_EXIT1 ("waitpid: %m\n");
+  return result;
+}
diff --git a/support/xwrite.c b/support/xwrite.c
new file mode 100644
index 0000000..134e8ee
--- /dev/null
+++ b/support/xwrite.c
@@ -0,0 +1,39 @@
+/* write with error checking and retries.
+   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/xunistd.h>
+
+#include <support/check.h>
+
+void
+xwrite (int fd, const void *buffer, size_t length)
+{
+  const char *p = buffer;
+  const char *end = p + length;
+  while (p < end)
+    {
+      ssize_t ret = write (fd, p, end - p);
+      if (ret < 0)
+        FAIL_EXIT1 ("write of %zu bytes failed after %td: %m",
+                    length, p - (const char *) buffer);
+      if (ret == 0)
+        FAIL_EXIT1 ("write return 0 after writing %td bytes of %zu",
+                    p - (const char *) buffer, length);
+      p += ret;
+    }
+}
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2.22 v2] Fix integer overflows in internal memalign and malloc functions [BZ #22343]
  2018-01-01  0:00   ` [PATCH 2.22 v2] " Raphael Moreira Zinsly
@ 2018-01-01  0:00     ` Carlos O'Donell
       [not found]       ` <20180405194944.GA44061@aloka.lostca.se>
  0 siblings, 1 reply; 26+ messages in thread
From: Carlos O'Donell @ 2018-01-01  0:00 UTC (permalink / raw)
  To: Raphael Moreira Zinsly, rzinsly; +Cc: libc-stable

On 04/04/2018 09:50 AM, Raphael Moreira Zinsly wrote:
> +#include <support/test-driver.c>
 
This can't possibly work for release/2.22/master, there was no support infrastructure?

How are you testing these patches?

-- 
Cheers,
Carlos.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2.22] posix: Sync glob with gnulib [BZ #1062]
  2018-01-01  0:00         ` [PATCH 2.22] posix: Sync glob with gnulib [BZ #1062] Raphael Moreira Zinsly
@ 2018-01-01  0:00           ` Tulio Magno Quites Machado Filho
  0 siblings, 0 replies; 26+ messages in thread
From: Tulio Magno Quites Machado Filho @ 2018-01-01  0:00 UTC (permalink / raw)
  To: Raphael Moreira Zinsly; +Cc: libc-stable, carlos, arjun.is

Raphael Moreira Zinsly <rzinsly@linux.vnet.ibm.com> writes:

> This patch syncs posix/glob.c implementation with gnulib version
> b5ec983 (glob: simplify symlink detection).  The only difference
> to gnulib code is
>
>   * DT_UNKNOWN, DT_DIR, and DT_LNK definition in the case there
>     were not already defined.  Gnulib code which uses
>     HAVE_STRUCT_DIRENT_D_TYPE will redefine them wrongly because
>     GLIBC does not define HAVE_STRUCT_DIRENT_D_TYPE.  Instead
>     the patch check for each definition instead.
>
> Also, the patch requires additional globfree and globfree64 files
> for compatibility version on some architectures.  Also the code
> simplification leads to not macro simplification (not need for
> NO_GLOB_PATTERN_P anymore).
>
> Checked on x86_64-linux-gnu and on a build using build-many-glibcs.py
> for all major architectures.

LGTM.

With this patch, I could merge the following patches:
[PATCH 2.22 02/14] CVE-2017-15670: glob: Fix one-byte overflow [BZ #22320]
[PATCH 2.22 03/14] glob: Add new test tst-glob-tilde
[PATCH 2.22 05/14] glob: Fix buffer overflow during GLOB_TILDE unescaping [BZ #22332]

If there are any objections, I plan to merge it next Tuesday.

After merging these patches, the following patch would still be pending from
your initial submission:
[PATCH 2.22 11/14] linux: make getcwd(3) fail if it cannot obtain an absolute path [BZ #22679]

Thanks!

-- 
Tulio Magno

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22 v2]  Fix integer overflows in internal memalign and malloc functions [BZ #22343]
  2018-01-01  0:00 ` [PATCH 2.22 10/14] Fix integer overflows in internal memalign and malloc functions [BZ #22343] Raphael Moreira Zinsly
@ 2018-01-01  0:00   ` Raphael Moreira Zinsly
  2018-01-01  0:00     ` Carlos O'Donell
  0 siblings, 1 reply; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: rzinsly; +Cc: libc-stable

From: Arjun Shankar <arjun.is@lostca.se>

When posix_memalign is called with an alignment less than MALLOC_ALIGNMENT
and a requested size close to SIZE_MAX, it falls back to malloc code
(because the alignment of a block returned by malloc is sufficient to
satisfy the call).  In this case, an integer overflow in _int_malloc leads
to posix_memalign incorrectly returning successfully.

Upon fixing this and writing a somewhat thorough regression test, it was
discovered that when posix_memalign is called with an alignment larger than
MALLOC_ALIGNMENT (so it uses _int_memalign instead) and a requested size
close to SIZE_MAX, a different integer overflow in _int_memalign leads to
posix_memalign incorrectly returning successfully.

Both integer overflows affect other memory allocation functions that use
_int_malloc (one affected malloc in x86) or _int_memalign as well.

This commit fixes both integer overflows.  In addition to this, it adds a
regression test to guard against false successful allocations by the
following memory allocation functions when called with too-large allocation
sizes and, where relevant, various valid alignments:
malloc, realloc, calloc, reallocarray, memalign, posix_memalign,
aligned_alloc, valloc, and pvalloc.

(cherry picked from commit 8e448310d74b283c5cd02b9ed7fb997b47bf9b22)
---
 ChangeLog                     |  10 ++
 malloc/Makefile               |   3 +-
 malloc/malloc.c               |  30 ++++--
 malloc/tst-malloc-too-large.c | 237 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 271 insertions(+), 9 deletions(-)
 create mode 100644 malloc/tst-malloc-too-large.c

diff --git a/ChangeLog b/ChangeLog
index 890b97d..92af495 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2018-01-18  Arjun Shankar  <arjun@redhat.com>
+
+	[BZ #22343]
+	* malloc/malloc.c (checked_request2size): call REQUEST_OUT_OF_RANGE
+	after padding.
+	(_int_memalign): check for integer overflow before calling
+	_int_malloc.
+	* malloc/tst-malloc-too-large.c: New test.
+	* malloc/Makefile: Add tst-malloc-too-large.
+
 2017-11-02  Florian Weimer  <fweimer@redhat.com>
 
 	Add array_length and array_end macros.
diff --git a/malloc/Makefile b/malloc/Makefile
index aa0579c..8445b9e 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -28,7 +28,8 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
 	 tst-mallocstate tst-mcheck tst-mallocfork tst-trim1 \
 	 tst-malloc-usable tst-realloc tst-posix_memalign \
 	 tst-pvalloc tst-memalign tst-mallopt tst-scratch_buffer \
-	 tst-malloc-backtrace tst-malloc-thread-exit
+	 tst-malloc-backtrace tst-malloc-thread-exit tst-malloc-too-large \
+
 test-srcs = tst-mtrace
 
 routines = malloc morecore mcheck mtrace obstack \
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 5c84e62..a5334e5 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1252,14 +1252,21 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    MINSIZE :                                                      \
    ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
 
-/*  Same, except also perform argument check */
-
-#define checked_request2size(req, sz)                             \
-  if (REQUEST_OUT_OF_RANGE (req)) {					      \
-      __set_errno (ENOMEM);						      \
-      return 0;								      \
-    }									      \
-  (sz) = request2size (req);
+/* Same, except also perform an argument and result check.  First, we check
+   that the padding done by request2size didn't result in an integer
+   overflow.  Then we check (using REQUEST_OUT_OF_RANGE) that the resulting
+   size isn't so large that a later alignment would lead to another integer
+   overflow.  */
+#define checked_request2size(req, sz) \
+({				    \
+  (sz) = request2size (req);	    \
+  if (((sz) < (req))		    \
+      || REQUEST_OUT_OF_RANGE (sz)) \
+    {				    \
+      __set_errno (ENOMEM);	    \
+      return 0;			    \
+    }				    \
+})
 
 /*
    --------------- Physical chunk operations ---------------
@@ -4417,6 +4424,13 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
    */
 
 
+  /* Check for overflow.  */
+  if (nb > SIZE_MAX - alignment - MINSIZE)
+    {
+      __set_errno (ENOMEM);
+      return 0;
+    }
+
   /* Call malloc with worst case padding to hit alignment. */
 
   m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
diff --git a/malloc/tst-malloc-too-large.c b/malloc/tst-malloc-too-large.c
new file mode 100644
index 0000000..1f7bf29
--- /dev/null
+++ b/malloc/tst-malloc-too-large.c
@@ -0,0 +1,237 @@
+/* Test and verify that too-large memory allocations fail with ENOMEM.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Bug 22375 reported a regression in malloc where if after malloc'ing then
+   free'ing a small block of memory, malloc is then called with a really
+   large size argument (close to SIZE_MAX): instead of returning NULL and
+   setting errno to ENOMEM, malloc incorrectly returns the previously
+   allocated block instead.  Bug 22343 reported a similar case where
+   posix_memalign incorrectly returns successfully when called with an with
+   a really large size argument.
+
+   Both of these were caused by integer overflows in the allocator when it
+   was trying to pad the requested size to allow for book-keeping or
+   alignment.  This test guards against such bugs by repeatedly allocating
+   and freeing small blocks of memory then trying to allocate various block
+   sizes larger than the memory bus width of 64-bit targets, or almost
+   as large as SIZE_MAX on 32-bit targets supported by glibc.  In each case,
+   it verifies that such impossibly large allocations correctly fail.  */
+
+
+#include <stdlib.h>
+#include <malloc.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/resource.h>
+#include <libc-internal.h>
+#include <support/check.h>
+#include <unistd.h>
+#include <sys/param.h>
+
+
+/* This function prepares for each 'too-large memory allocation' test by
+   performing a small successful malloc/free and resetting errno prior to
+   the actual test.  */
+static void
+test_setup (void)
+{
+  void *volatile ptr = malloc (16);
+  TEST_VERIFY_EXIT (ptr != NULL);
+  free (ptr);
+  errno = 0;
+}
+
+
+/* This function tests each of:
+   - malloc (SIZE)
+   - realloc (PTR_FOR_REALLOC, SIZE)
+   - for various values of NMEMB:
+    - calloc (NMEMB, SIZE/NMEMB)
+    - calloc (SIZE/NMEMB, NMEMB)
+   and precedes each of these tests with a small malloc/free before it.  */
+static void
+test_large_allocations (size_t size)
+{
+  void * ptr_to_realloc;
+
+  test_setup ();
+  TEST_VERIFY (malloc (size) == NULL);
+  TEST_VERIFY (errno == ENOMEM);
+
+  ptr_to_realloc = malloc (16);
+  TEST_VERIFY_EXIT (ptr_to_realloc != NULL);
+  test_setup ();
+  TEST_VERIFY (realloc (ptr_to_realloc, size) == NULL);
+  TEST_VERIFY (errno == ENOMEM);
+  free (ptr_to_realloc);
+
+  for (size_t nmemb = 1; nmemb <= 8; nmemb *= 2)
+    if ((size % nmemb) == 0)
+      {
+        test_setup ();
+        TEST_VERIFY (calloc (nmemb, size / nmemb) == NULL);
+        TEST_VERIFY (errno == ENOMEM);
+
+        test_setup ();
+        TEST_VERIFY (calloc (size / nmemb, nmemb) == NULL);
+        TEST_VERIFY (errno == ENOMEM);
+      }
+    else
+      break;
+}
+
+
+static long pagesize;
+
+/* This function tests the following aligned memory allocation functions
+   using several valid alignments and precedes each allocation test with a
+   small malloc/free before it:
+   memalign, posix_memalign, aligned_alloc, valloc, pvalloc.  */
+static void
+test_large_aligned_allocations (size_t size)
+{
+  /* ptr stores the result of posix_memalign but since all those calls
+     should fail, posix_memalign should never change ptr.  We set it to
+     NULL here and later on we check that it remains NULL after each
+     posix_memalign call.  */
+  void * ptr = NULL;
+
+  size_t align;
+
+  /* All aligned memory allocation functions expect an alignment that is a
+     power of 2.  Given this, we test each of them with every valid
+     alignment from 1 thru PAGESIZE.  */
+  for (align = 1; align <= pagesize; align *= 2)
+    {
+      test_setup ();
+      TEST_VERIFY (memalign (align, size) == NULL);
+      TEST_VERIFY (errno == ENOMEM);
+
+      /* posix_memalign expects an alignment that is a power of 2 *and* a
+         multiple of sizeof (void *).  */
+      if ((align % sizeof (void *)) == 0)
+        {
+          test_setup ();
+          TEST_VERIFY (posix_memalign (&ptr, align, size) == ENOMEM);
+          TEST_VERIFY (ptr == NULL);
+        }
+
+      /* aligned_alloc expects a size that is a multiple of alignment.  */
+      if ((size % align) == 0)
+        {
+          test_setup ();
+          TEST_VERIFY (aligned_alloc (align, size) == NULL);
+          TEST_VERIFY (errno == ENOMEM);
+        }
+    }
+
+  /* Both valloc and pvalloc return page-aligned memory.  */
+
+  test_setup ();
+  TEST_VERIFY (valloc (size) == NULL);
+  TEST_VERIFY (errno == ENOMEM);
+
+  test_setup ();
+  TEST_VERIFY (pvalloc (size) == NULL);
+  TEST_VERIFY (errno == ENOMEM);
+}
+
+
+#define FOURTEEN_ON_BITS ((1UL << 14) - 1)
+#define FIFTY_ON_BITS ((1UL << 50) - 1)
+
+
+static int
+do_test (void)
+{
+
+#if __WORDSIZE >= 64
+
+  /* This test assumes that none of the supported targets have an address
+     bus wider than 50 bits, and that therefore allocations for sizes wider
+     than 50 bits will fail.  Here, we ensure that the assumption continues
+     to be true in the future when we might have address buses wider than 50
+     bits.  */
+
+  struct rlimit alloc_size_limit
+    = {
+        .rlim_cur = FIFTY_ON_BITS,
+        .rlim_max = FIFTY_ON_BITS
+      };
+
+  setrlimit (RLIMIT_AS, &alloc_size_limit);
+
+#endif /* __WORDSIZE >= 64 */
+
+  DIAG_PUSH_NEEDS_COMMENT;
+#if __GNUC_PREREQ (7, 0)
+  /* GCC 7 warns about too-large allocations; here we want to test
+     that they fail.  */
+  DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
+#endif
+
+  /* Aligned memory allocation functions need to be tested up to alignment
+     size equivalent to page size, which should be a power of 2.  */
+  pagesize = sysconf (_SC_PAGESIZE);
+  TEST_VERIFY_EXIT (powerof2 (pagesize));
+
+  /* Loop 1: Ensure that all allocations with SIZE close to SIZE_MAX, i.e.
+     in the range (SIZE_MAX - 2^14, SIZE_MAX], fail.
+
+     We can expect that this range of allocation sizes will always lead to
+     an allocation failure on both 64 and 32 bit targets, because:
+
+     1. no currently supported 64-bit target has an address bus wider than
+     50 bits -- and (2^64 - 2^14) is much wider than that;
+
+     2. on 32-bit targets, even though 2^32 is only 4 GB and potentially
+     addressable, glibc itself is more than 2^14 bytes in size, and
+     therefore once glibc is loaded, less than (2^32 - 2^14) bytes remain
+     available.  */
+
+  for (size_t i = 0; i <= FOURTEEN_ON_BITS; i++)
+    {
+      test_large_allocations (SIZE_MAX - i);
+      test_large_aligned_allocations (SIZE_MAX - i);
+    }
+
+#if __WORDSIZE >= 64
+  /* On 64-bit targets, we need to test a much wider range of too-large
+     sizes, so we test at intervals of (1 << 50) that allocation sizes
+     ranging from SIZE_MAX down to (1 << 50) fail:
+     The 14 MSBs are decremented starting from "all ON" going down to 1,
+     the 50 LSBs are "all ON" and then "all OFF" during every iteration.  */
+  for (size_t msbs = FOURTEEN_ON_BITS; msbs >= 1; msbs--)
+    {
+      size_t size = (msbs << 50) | FIFTY_ON_BITS;
+      test_large_allocations (size);
+      test_large_aligned_allocations (size);
+
+      size = msbs << 50;
+      test_large_allocations (size);
+      test_large_aligned_allocations (size);
+    }
+#endif /* __WORDSIZE >= 64 */
+
+  DIAG_POP_NEEDS_COMMENT;
+
+  return 0;
+}
+
+
+#include <support/test-driver.c>
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2.22] posix: Sync glob with gnulib [BZ #1062]
  2018-01-01  0:00       ` Tulio Magno Quites Machado Filho
@ 2018-01-01  0:00         ` Raphael Moreira Zinsly
  2018-01-01  0:00           ` Tulio Magno Quites Machado Filho
  0 siblings, 1 reply; 26+ messages in thread
From: Raphael Moreira Zinsly @ 2018-01-01  0:00 UTC (permalink / raw)
  To: tuliom; +Cc: libc-stable, carlos, arjun.is

From: Adhemerval Zanella <adhemerval.zanella@linaro.org>

On 04/06/2018 05:16 PM, Tulio Magno Quites Machado Filho wrote:
>This patch does solve part of the issues, but it isn't enough to make
>posix/tst-glob-tilde-mem and io/tst-getcwd-abspath to pass.

This patch was missing to fix the issues tested in
posix/tst-glob-tilde-mem.

-- >8 --

This patch syncs posix/glob.c implementation with gnulib version
b5ec983 (glob: simplify symlink detection).  The only difference
to gnulib code is

  * DT_UNKNOWN, DT_DIR, and DT_LNK definition in the case there
    were not already defined.  Gnulib code which uses
    HAVE_STRUCT_DIRENT_D_TYPE will redefine them wrongly because
    GLIBC does not define HAVE_STRUCT_DIRENT_D_TYPE.  Instead
    the patch check for each definition instead.

Also, the patch requires additional globfree and globfree64 files
for compatibility version on some architectures.  Also the code
simplification leads to not macro simplification (not need for
NO_GLOB_PATTERN_P anymore).

Checked on x86_64-linux-gnu and on a build using build-many-glibcs.py
for all major architectures.

	[BZ #1062]
	* posix/Makefile (routines): Add globfree, globfree64, and
	glob_pattern_p.
	* posix/flexmember.h: New file.
	* posix/glob_internal.h: Likewise.
	* posix/glob_pattern_p.c: Likewise.
	* posix/globfree.c: Likewise.
	* posix/globfree64.c: Likewise.
	* sysdeps/gnu/globfree64.c: Likewise.
	* sysdeps/unix/sysv/linux/alpha/globfree.c: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c: Likewise.
	* sysdeps/unix/sysv/linux/oldglob.c: Likewise.
	* sysdeps/unix/sysv/linux/wordsize-64/globfree64.c: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/globfree.c: Likewise.
	* sysdeps/wordsize-64/globfree.c: Likewise.
	* sysdeps/wordsize-64/globfree64.c: Likewise.
	* posix/glob.c (HAVE_CONFIG_H): Use !_LIBC instead.
	[NDEBUG): Remove comments.
	(GLOB_ONLY_P, _AMIGA, VMS): Remove define.
	(dirent_type): New type.  Use uint_fast8_t not
	uint8_t, as C99 does not require uint8_t.
	(DT_UNKNOWN, DT_DIR, DT_LNK): New macros.
	(struct readdir_result): Use dirent_type.  Do not define skip_entry
	unless it is needed; this saves a byte on platforms lacking d_ino.
	(readdir_result_type, readdir_result_skip_entry):
	New functions, replacing ...
	(readdir_result_might_be_symlink, readdir_result_might_be_dir):
	 these functions, which were removed.  This makes the callers
	easier to read.  All callers changed.
	(D_INO_TO_RESULT): Now empty if there is no d_ino.
	(size_add_wrapv, glob_use_alloca): New static functions.
	(glob, glob_in_dir): Check for size_t overflow in several places,
	and fix some size_t checks that were not quite right.
	Remove old code using SHELL since Bash no longer
	uses this.
	(glob, prefix_array): Separate MS code better.
	(glob_in_dir): Remove old Amiga and VMS code.
	(globfree, __glob_pattern_type, __glob_pattern_p): Move to
	separate files.
	(glob_in_dir): Do not rely on undefined behavior in accessing
	struct members beyond their bounds.  Use a flexible array member
	instead
	(link_stat): Rename from link_exists2_p and return -1/0 instead of
	0/1.  Caller changed.
	(glob): Fix memory leaks.
	* posix/glob64 (globfree64): Move to separate file.
	* sysdeps/gnu/glob64.c (NO_GLOB_PATTERN_P): Remove define.
	(globfree64): Remove hidden alias.
	* sysdeps/unix/sysv/linux/Makefile (sysdeps_routines): Add
	oldglob.
	* sysdeps/unix/sysv/linux/alpha/glob.c (__new_globfree): Move to
	separate file.
	* sysdeps/unix/sysv/linux/i386/glob64.c (NO_GLOB_PATTERN_P): Remove
	define.
	Move compat code to separate file.
	* sysdeps/wordsize-64/glob.c (globfree): Move definitions to
	separate file.

(cherry picked from commit c66c908230169c1bab1f83b071eb585baa214b9f)
---
 ChangeLog                                          |  60 ++
 posix/Makefile                                     |   2 +-
 posix/flexmember.h                                 |  45 ++
 posix/glob.c                                       | 779 ++++++++++-----------
 posix/glob64.c                                     |   6 -
 posix/glob_internal.h                              |  57 ++
 posix/glob_pattern_p.c                             |  33 +
 posix/globfree.c                                   |  41 ++
 posix/globfree64.c                                 |  31 +
 sysdeps/gnu/glob64.c                               |   3 -
 sysdeps/gnu/globfree64.c                           |  10 +
 sysdeps/unix/sysv/linux/Makefile                   |   2 +-
 sysdeps/unix/sysv/linux/alpha/glob.c               |   4 -
 sysdeps/unix/sysv/linux/alpha/globfree.c           |  37 +
 sysdeps/unix/sysv/linux/i386/glob64.c              |  36 +-
 .../unix/sysv/linux/mips/mips64/n64/globfree64.c   |   1 +
 sysdeps/unix/sysv/linux/oldglob.c                  |  42 ++
 sysdeps/unix/sysv/linux/wordsize-64/globfree64.c   |   2 +
 sysdeps/unix/sysv/linux/x86_64/x32/globfree.c      |   1 +
 sysdeps/wordsize-64/glob.c                         |   2 -
 sysdeps/wordsize-64/globfree.c                     |   5 +
 sysdeps/wordsize-64/globfree64.c                   |   1 +
 22 files changed, 739 insertions(+), 461 deletions(-)
 create mode 100644 posix/flexmember.h
 create mode 100644 posix/glob_internal.h
 create mode 100644 posix/glob_pattern_p.c
 create mode 100644 posix/globfree.c
 create mode 100644 posix/globfree64.c
 create mode 100644 sysdeps/gnu/globfree64.c
 create mode 100644 sysdeps/unix/sysv/linux/alpha/globfree.c
 create mode 100644 sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c
 create mode 100644 sysdeps/unix/sysv/linux/oldglob.c
 create mode 100644 sysdeps/unix/sysv/linux/wordsize-64/globfree64.c
 create mode 100644 sysdeps/unix/sysv/linux/x86_64/x32/globfree.c
 create mode 100644 sysdeps/wordsize-64/globfree.c
 create mode 100644 sysdeps/wordsize-64/globfree64.c

diff --git a/ChangeLog b/ChangeLog
index b0c33a3..276ab46 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,63 @@
+2017-09-08  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
+
+	[BZ #1062]
+	* posix/Makefile (routines): Add globfree, globfree64, and
+	glob_pattern_p.
+	* posix/flexmember.h: New file.
+	* posix/glob_internal.h: Likewise.
+	* posix/glob_pattern_p.c: Likewise.
+	* posix/globfree.c: Likewise.
+	* posix/globfree64.c: Likewise.
+	* sysdeps/gnu/globfree64.c: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/globfree.c: Likewise.
+	* sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c: Likewise.
+	* sysdeps/unix/sysv/linux/oldglob.c: Likewise.
+	* sysdeps/unix/sysv/linux/wordsize-64/globfree64.c: Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/x32/globfree.c: Likewise.
+	* sysdeps/wordsize-64/globfree.c: Likewise.
+	* sysdeps/wordsize-64/globfree64.c: Likewise.
+	* posix/glob.c (HAVE_CONFIG_H): Use !_LIBC instead.
+	[NDEBUG): Remove comments.
+	(GLOB_ONLY_P, _AMIGA, VMS): Remove define.
+	(dirent_type): New type.  Use uint_fast8_t not
+	uint8_t, as C99 does not require uint8_t.
+	(DT_UNKNOWN, DT_DIR, DT_LNK): New macros.
+	(struct readdir_result): Use dirent_type.  Do not define skip_entry
+	unless it is needed; this saves a byte on platforms lacking d_ino.
+	(readdir_result_type, readdir_result_skip_entry):
+	New functions, replacing ...
+	(readdir_result_might_be_symlink, readdir_result_might_be_dir):
+	 these functions, which were removed.  This makes the callers
+	easier to read.  All callers changed.
+	(D_INO_TO_RESULT): Now empty if there is no d_ino.
+	(size_add_wrapv, glob_use_alloca): New static functions.
+	(glob, glob_in_dir): Check for size_t overflow in several places,
+	and fix some size_t checks that were not quite right.
+	Remove old code using SHELL since Bash no longer
+	uses this.
+	(glob, prefix_array): Separate MS code better.
+	(glob_in_dir): Remove old Amiga and VMS code.
+	(globfree, __glob_pattern_type, __glob_pattern_p): Move to
+	separate files.
+	(glob_in_dir): Do not rely on undefined behavior in accessing
+	struct members beyond their bounds.  Use a flexible array member
+	instead
+	(link_stat): Rename from link_exists2_p and return -1/0 instead of
+	0/1.  Caller changed.
+	(glob): Fix memory leaks.
+	* posix/glob64 (globfree64): Move to separate file.
+	* sysdeps/gnu/glob64.c (NO_GLOB_PATTERN_P): Remove define.
+	(globfree64): Remove hidden alias.
+	* sysdeps/unix/sysv/linux/Makefile (sysdeps_routines): Add
+	oldglob.
+	* sysdeps/unix/sysv/linux/alpha/glob.c (__new_globfree): Move to
+	separate file.
+	* sysdeps/unix/sysv/linux/i386/glob64.c (NO_GLOB_PATTERN_P): Remove
+	define.
+	Move compat code to separate file.
+	* sysdeps/wordsize-64/glob.c (globfree): Move definitions to
+	separate file.
+
 2017-10-22  Paul Eggert <eggert@cs.ucla.edu>
 
 	[BZ #22332]
diff --git a/posix/Makefile b/posix/Makefile
index ec7c24e..29b44e5 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -43,7 +43,7 @@ routines :=								      \
 	getpgid setpgid getpgrp bsd-getpgrp setpgrp getsid setsid	      \
 	getresuid getresgid setresuid setresgid				      \
 	pathconf sysconf fpathconf					      \
-	glob glob64 fnmatch regex					      \
+	glob glob64 globfree globfree64 glob_pattern_p fnmatch regex	      \
 	confstr								      \
 	getopt getopt1 getopt_init					      \
 	sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax  \
diff --git a/posix/flexmember.h b/posix/flexmember.h
new file mode 100644
index 0000000..107c1f0
--- /dev/null
+++ b/posix/flexmember.h
@@ -0,0 +1,45 @@
+/* Sizes of structs with flexible array members.
+
+   Copyright 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/>.
+
+   Written by Paul Eggert.  */
+
+#include <stddef.h>
+
+/* Nonzero multiple of alignment of TYPE, suitable for FLEXSIZEOF below.
+   On older platforms without _Alignof, use a pessimistic bound that is
+   safe in practice even if FLEXIBLE_ARRAY_MEMBER is 1.
+   On newer platforms, use _Alignof to get a tighter bound.  */
+
+#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112
+# define FLEXALIGNOF(type) (sizeof (type) & ~ (sizeof (type) - 1))
+#else
+# define FLEXALIGNOF(type) _Alignof (type)
+#endif
+
+/* Upper bound on the size of a struct of type TYPE with a flexible
+   array member named MEMBER that is followed by N bytes of other data.
+   This is not simply sizeof (TYPE) + N, since it may require
+   alignment on unusually picky C11 platforms, and
+   FLEXIBLE_ARRAY_MEMBER may be 1 on pre-C11 platforms.
+   Yield a value less than N if and only if arithmetic overflow occurs.  */
+
+#define FLEXSIZEOF(type, member, n) \
+   ((offsetof (type, member) + FLEXALIGNOF (type) - 1 + (n)) \
+    & ~ (FLEXALIGNOF (type) - 1))
diff --git a/posix/glob.c b/posix/glob.c
index c4c0532..944b77b 100644
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -15,7 +15,7 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifdef	HAVE_CONFIG_H
+#ifndef _LIBC
 # include <config.h>
 #endif
 
@@ -27,29 +27,15 @@
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
-
-/* Outcomment the following line for production quality code.  */
-/* #define NDEBUG 1 */
 #include <assert.h>
+#include <unistd.h>
 
-#include <stdio.h>		/* Needed on stupid SunOS for assert.  */
-
-#if !defined _LIBC || !defined GLOB_ONLY_P
-#if defined HAVE_UNISTD_H || defined _LIBC
-# include <unistd.h>
-# ifndef POSIX
-#  ifdef _POSIX_VERSION
-#   define POSIX
-#  endif
-# endif
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# define WINDOWS32
 #endif
 
-#include <pwd.h>
-
-#if defined HAVE_STDINT_H || defined _LIBC
-# include <stdint.h>
-#elif !defined UINTPTR_MAX
-# define UINTPTR_MAX (~((size_t) 0))
+#ifndef WINDOWS32
+# include <pwd.h>
 #endif
 
 #include <errno.h>
@@ -57,24 +43,7 @@
 # define __set_errno(val) errno = (val)
 #endif
 
-#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
-# include <dirent.h>
-#else
-# define dirent direct
-# ifdef HAVE_SYS_NDIR_H
-#  include <sys/ndir.h>
-# endif
-# ifdef HAVE_SYS_DIR_H
-#  include <sys/dir.h>
-# endif
-# ifdef HAVE_NDIR_H
-#  include <ndir.h>
-# endif
-# ifdef HAVE_VMSDIR_H
-#  include "vmsdir.h"
-# endif /* HAVE_VMSDIR_H */
-#endif
-
+#include <dirent.h>
 #include <stdlib.h>
 #include <string.h>
 #include <alloca.h>
@@ -87,27 +56,29 @@
 # define opendir(name) __opendir (name)
 # define readdir(str) __readdir64 (str)
 # define getpwnam_r(name, bufp, buf, len, res) \
-   __getpwnam_r (name, bufp, buf, len, res)
+    __getpwnam_r (name, bufp, buf, len, res)
 # ifndef __stat64
 #  define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf)
 # endif
 # define struct_stat64		struct stat64
+# define FLEXIBLE_ARRAY_MEMBER
 #else /* !_LIBC */
-# include "getlogin_r.h"
-# include "mempcpy.h"
-# include "stat-macros.h"
-# include "strdup.h"
-# define __stat64(fname, buf)	stat (fname, buf)
-# define struct_stat64		struct stat
-# define __stat(fname, buf)	stat (fname, buf)
-# define __alloca		alloca
-# define __readdir		readdir
-# define __readdir64		readdir64
-# define __glob_pattern_p	glob_pattern_p
+# define __getlogin_r(buf, len) getlogin_r (buf, len)
+# define __stat64(fname, buf)   stat (fname, buf)
+# define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag)
+# define struct_stat64          struct stat
+# ifndef __MVS__
+#  define __alloca              alloca
+# endif
+# define __readdir              readdir
+# define COMPILE_GLOB64
 #endif /* _LIBC */
 
 #include <fnmatch.h>
 
+#include <flexmember.h>
+#include <glob_internal.h>
+
 #ifdef _SC_GETPW_R_SIZE_MAX
 # define GETPW_R_SIZE_MAX()	sysconf (_SC_GETPW_R_SIZE_MAX)
 #else
@@ -121,61 +92,59 @@
 \f
 static const char *next_brace_sub (const char *begin, int flags) __THROWNL;
 
+typedef uint_fast8_t dirent_type;
+
+#if !defined _LIBC && !defined HAVE_STRUCT_DIRENT_D_TYPE
+/* Any distinct values will do here.
+   Undef any existing macros out of the way.  */
+# undef DT_UNKNOWN
+# undef DT_DIR
+# undef DT_LNK
+# define DT_UNKNOWN 0
+# define DT_DIR 1
+# define DT_LNK 2
+#endif
+
 /* A representation of a directory entry which does not depend on the
    layout of struct dirent, or the size of ino_t.  */
 struct readdir_result
 {
   const char *name;
-# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
-  uint8_t type;
-# endif
+#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
+  dirent_type type;
+#endif
+#if defined _LIBC || defined D_INO_IN_DIRENT
   bool skip_entry;
+#endif
 };
 
-# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
-/* Initializer based on the d_type member of struct dirent.  */
-#  define D_TYPE_TO_RESULT(source) (source)->d_type,
-
-/* True if the directory entry D might be a symbolic link.  */
-static bool
-readdir_result_might_be_symlink (struct readdir_result d)
-{
-  return d.type == DT_UNKNOWN || d.type == DT_LNK;
-}
-
-/* True if the directory entry D might be a directory.  */
-static bool
-readdir_result_might_be_dir (struct readdir_result d)
+/* Initialize and return type member of struct readdir_result.  */
+static dirent_type
+readdir_result_type (struct readdir_result d)
 {
-  return d.type == DT_DIR || readdir_result_might_be_symlink (d);
-}
-# else /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
-#  define D_TYPE_TO_RESULT(source)
-
-/* If we do not have type information, symbolic links and directories
-   are always a possibility.  */
-
-static bool
-readdir_result_might_be_symlink (struct readdir_result d)
-{
-  return true;
+#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
+# define D_TYPE_TO_RESULT(source) (source)->d_type,
+  return d.type;
+#else
+# define D_TYPE_TO_RESULT(source)
+  return DT_UNKNOWN;
+#endif
 }
 
+/* Initialize and return skip_entry member of struct readdir_result.  */
 static bool
-readdir_result_might_be_dir (struct readdir_result d)
+readdir_result_skip_entry (struct readdir_result d)
 {
-  return true;
-}
-
-# endif /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
-
-# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
 /* Initializer for skip_entry.  POSIX does not require that the d_ino
    field be present, and some systems do not provide it. */
-#  define D_INO_TO_RESULT(source) false,
-# else
-#  define D_INO_TO_RESULT(source) (source)->d_ino == 0,
-# endif
+#if defined _LIBC || defined D_INO_IN_DIRENT
+# define D_INO_TO_RESULT(source) (source)->d_ino == 0,
+  return d.skip_entry;
+#else
+# define D_INO_TO_RESULT(source)
+  return false;
+#endif
+}
 
 /* Construct an initializer for a struct readdir_result object from a
    struct dirent *.  No copy of the name is made.  */
@@ -186,8 +155,6 @@ readdir_result_might_be_dir (struct readdir_result d)
     D_INO_TO_RESULT (source)		   \
   }
 
-#endif /* !defined _LIBC || !defined GLOB_ONLY_P */
-
 /* Call gl_readdir on STREAM.  This macro can be overridden to reduce
    type safety if an old interface version needs to be supported.  */
 #ifndef GL_READDIR
@@ -225,10 +192,48 @@ convert_dirent64 (const struct dirent64 *source)
 }
 #endif
 
+#ifndef _LIBC
+/* The results of opendir() in this file are not used with dirfd and fchdir,
+   and we do not leak fds to any single-threaded code that could use stdio,
+   therefore save some unnecessary recursion in fchdir.c and opendir_safer.c.
+   FIXME - if the kernel ever adds support for multi-thread safety for
+   avoiding standard fds, then we should use opendir_safer.  */
+# ifdef GNULIB_defined_opendir
+#  undef opendir
+# endif
+# ifdef GNULIB_defined_closedir
+#  undef closedir
+# endif
+
+/* Just use malloc.  */
+# define __libc_use_alloca(n) false
+# define alloca_account(len, avar) ((void) (len), (void) (avar), (void *) 0)
+# define extend_alloca_account(buf, len, newlen, avar) \
+    ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0)
+#endif
+
+/* Set *R = A + B.  Return true if the answer is mathematically
+   incorrect due to overflow; in this case, *R is the low order
+   bits of the correct answer.  */
 
-#ifndef attribute_hidden
-# define attribute_hidden
+static bool
+size_add_wrapv (size_t a, size_t b, size_t *r)
+{
+#if 5 <= __GNUC__ && !defined __ICC
+  return __builtin_add_overflow (a, b, r);
+#else
+  *r = a + b;
+  return *r < a;
 #endif
+}
+
+static bool
+glob_use_alloca (size_t alloca_used, size_t len)
+{
+  size_t size;
+  return (!size_add_wrapv (alloca_used, len, &size)
+          && __libc_use_alloca (size));
+}
 
 static int glob_in_dir (const char *pattern, const char *directory,
 			int flags, int (*errfunc) (const char *, int),
@@ -236,7 +241,6 @@ static int glob_in_dir (const char *pattern, const char *directory,
 extern int __glob_pattern_type (const char *pattern, int quote)
     attribute_hidden;
 
-#if !defined _LIBC || !defined GLOB_ONLY_P
 static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL;
 static int collated_compare (const void *, const void *) __THROWNL;
 
@@ -265,16 +269,15 @@ next_brace_sub (const char *cp, int flags)
   return *cp != '\0' ? cp : NULL;
 }
 
-#endif /* !defined _LIBC || !defined GLOB_ONLY_P */
 
 /* Do glob searching for PATTERN, placing results in PGLOB.
    The bits defined above may be set in FLAGS.
    If a directory cannot be opened or read and ERRFUNC is not nil,
    it is called with the pathname that caused the error, and the
-   `errno' value from the failing call; if it returns non-zero
-   `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
+   'errno' value from the failing call; if it returns non-zero
+   'glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
    If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
-   Otherwise, `glob' returns zero.  */
+   Otherwise, 'glob' returns zero.  */
 int
 #ifdef GLOB_ATTRIBUTE
 GLOB_ATTRIBUTE
@@ -295,9 +298,7 @@ glob (pattern, flags, errfunc, pglob)
   int malloc_dirname = 0;
   glob_t dirs;
   int retval = 0;
-#ifdef _LIBC
   size_t alloca_used = 0;
-#endif
 
   if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
     {
@@ -311,7 +312,7 @@ glob (pattern, flags, errfunc, pglob)
     flags |= GLOB_ONLYDIR;
 
   if (!(flags & GLOB_DOOFFS))
-    /* Have to do this so `globfree' knows where to start freeing.  It
+    /* Have to do this so 'globfree' knows where to start freeing.  It
        also makes all the code that uses gl_offs simpler. */
     pglob->gl_offs = 0;
 
@@ -353,14 +354,12 @@ glob (pattern, flags, errfunc, pglob)
 	  size_t rest_len;
 	  char *onealt;
 	  size_t pattern_len = strlen (pattern) - 1;
-#ifdef _LIBC
-	  int alloca_onealt = __libc_use_alloca (alloca_used + pattern_len);
+	  int alloca_onealt = glob_use_alloca (alloca_used, pattern_len);
 	  if (alloca_onealt)
 	    onealt = alloca_account (pattern_len, alloca_used);
 	  else
-#endif
 	    {
-	      onealt = (char *) malloc (pattern_len);
+	      onealt = malloc (pattern_len);
 	      if (onealt == NULL)
 		{
 		  if (!(flags & GLOB_APPEND))
@@ -380,11 +379,9 @@ glob (pattern, flags, errfunc, pglob)
 	  next = next_brace_sub (begin + 1, flags);
 	  if (next == NULL)
 	    {
-	      /* It is an illegal expression.  */
+	      /* It is an invalid expression.  */
 	    illegal_brace:
-#ifdef _LIBC
 	      if (__glibc_unlikely (!alloca_onealt))
-#endif
 		free (onealt);
 	      return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
 	    }
@@ -432,9 +429,7 @@ glob (pattern, flags, errfunc, pglob)
 	      /* If we got an error, return it.  */
 	      if (result && result != GLOB_NOMATCH)
 		{
-#ifdef _LIBC
 		  if (__glibc_unlikely (!alloca_onealt))
-#endif
 		    free (onealt);
 		  if (!(flags & GLOB_APPEND))
 		    {
@@ -453,9 +448,7 @@ glob (pattern, flags, errfunc, pglob)
 	      assert (next != NULL);
 	    }
 
-#ifdef _LIBC
 	  if (__glibc_unlikely (!alloca_onealt))
-#endif
 	    free (onealt);
 
 	  if (pglob->gl_pathc != firstc)
@@ -492,14 +485,16 @@ glob (pattern, flags, errfunc, pglob)
 
   /* Find the filename.  */
   filename = strrchr (pattern, '/');
+
 #if defined __MSDOS__ || defined WINDOWS32
-  /* The case of "d:pattern".  Since `:' is not allowed in
+  /* The case of "d:pattern".  Since ':' is not allowed in
      file names, we can safely assume that wherever it
      happens in pattern, it signals the filename part.  This
      is so we could some day support patterns like "[a-z]:foo".  */
   if (filename == NULL)
     filename = strchr (pattern, ':');
 #endif /* __MSDOS__ || WINDOWS32 */
+
   dirname_modified = 0;
   if (filename == NULL)
     {
@@ -524,11 +519,7 @@ glob (pattern, flags, errfunc, pglob)
 	    }
 
 	  filename = pattern;
-#ifdef _AMIGA
-	  dirname = (char *) "";
-#else
 	  dirname = (char *) ".";
-#endif
 	  dirlen = 0;
 	}
     }
@@ -552,22 +543,21 @@ glob (pattern, flags, errfunc, pglob)
 	  char *drive_spec;
 
 	  ++dirlen;
-	  drive_spec = (char *) __alloca (dirlen + 1);
+	  drive_spec = __alloca (dirlen + 1);
 	  *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
 	  /* For now, disallow wildcards in the drive spec, to
 	     prevent infinite recursion in glob.  */
 	  if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
 	    return GLOB_NOMATCH;
-	  /* If this is "d:pattern", we need to copy `:' to DIRNAME
+	  /* If this is "d:pattern", we need to copy ':' to DIRNAME
 	     as well.  If it's "d:/pattern", don't remove the slash
 	     from "d:/", since "d:" and "d:/" are not the same.*/
 	}
 #endif
-#ifdef _LIBC
-      if (__libc_use_alloca (alloca_used + dirlen + 1))
+
+      if (glob_use_alloca (alloca_used, dirlen + 1))
 	newp = alloca_account (dirlen + 1, alloca_used);
       else
-#endif
 	{
 	  newp = malloc (dirlen + 1);
 	  if (newp == NULL)
@@ -578,14 +568,17 @@ glob (pattern, flags, errfunc, pglob)
       dirname = newp;
       ++filename;
 
-      if (filename[0] == '\0'
 #if defined __MSDOS__ || defined WINDOWS32
-	  && dirname[dirlen - 1] != ':'
-	  && (dirlen < 3 || dirname[dirlen - 2] != ':'
-	      || dirname[dirlen - 1] != '/')
+      bool drive_root = (dirlen > 1
+                         && (dirname[dirlen - 1] == ':'
+                             || (dirlen > 2 && dirname[dirlen - 2] == ':'
+                                 && dirname[dirlen - 1] == '/')));
+#else
+      bool drive_root = false;
 #endif
-	  && dirlen > 1)
-	/* "pattern/".  Expand "pattern", appending slashes.  */
+
+      if (filename[0] == '\0' && dirlen > 1 && !drive_root)
+        /* "pattern/".  Expand "pattern", appending slashes.  */
 	{
 	  int orig_flags = flags;
 	  if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\')
@@ -618,7 +611,6 @@ glob (pattern, flags, errfunc, pglob)
 	}
     }
 
-#ifndef VMS
   if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
     {
       if (dirname[1] == '\0' || dirname[1] == '/'
@@ -628,100 +620,127 @@ glob (pattern, flags, errfunc, pglob)
 	  /* Look up home directory.  */
 	  char *home_dir = getenv ("HOME");
 	  int malloc_home_dir = 0;
-# ifdef _AMIGA
-	  if (home_dir == NULL || home_dir[0] == '\0')
-	    home_dir = "SYS:";
-# else
-#  ifdef WINDOWS32
-	  if (home_dir == NULL || home_dir[0] == '\0')
-	    home_dir = "c:/users/default"; /* poor default */
-#  else
 	  if (home_dir == NULL || home_dir[0] == '\0')
 	    {
+#ifdef WINDOWS32
+	      /* Windows NT defines HOMEDRIVE and HOMEPATH.  But give
+		 preference to HOME, because the user can change HOME.  */
+	      const char *home_drive = getenv ("HOMEDRIVE");
+	      const char *home_path = getenv ("HOMEPATH");
+
+	      if (home_drive != NULL && home_path != NULL)
+		{
+		  size_t home_drive_len = strlen (home_drive);
+		  size_t home_path_len = strlen (home_path);
+		  char *mem = alloca (home_drive_len + home_path_len + 1);
+
+		  memcpy (mem, home_drive, home_drive_len);
+		  memcpy (mem + home_drive_len, home_path, home_path_len + 1);
+		  home_dir = mem;
+		}
+	      else
+		home_dir = "c:/users/default"; /* poor default */
+#else
 	      int success;
 	      char *name;
+	      int malloc_name = 0;
 	      size_t buflen = GET_LOGIN_NAME_MAX () + 1;
 
 	      if (buflen == 0)
-		/* `sysconf' does not support _SC_LOGIN_NAME_MAX.  Try
+		/* 'sysconf' does not support _SC_LOGIN_NAME_MAX.  Try
 		   a moderate value.  */
 		buflen = 20;
-	      name = alloca_account (buflen, alloca_used);
+	      if (glob_use_alloca (alloca_used, buflen))
+		name = alloca_account (buflen, alloca_used);
+	      else
+		{
+		  name = malloc (buflen);
+		  if (name == NULL)
+		    {
+		      retval = GLOB_NOSPACE;
+		      goto out;
+		    }
+		  malloc_name = 1;
+		}
 
 	      success = __getlogin_r (name, buflen) == 0;
 	      if (success)
 		{
 		  struct passwd *p;
-#   if defined HAVE_GETPWNAM_R || defined _LIBC
-		  long int pwbuflen = GETPW_R_SIZE_MAX ();
+		  char *malloc_pwtmpbuf = NULL;
 		  char *pwtmpbuf;
+# if defined HAVE_GETPWNAM_R || defined _LIBC
+		  long int pwbuflenmax = GETPW_R_SIZE_MAX ();
+		  size_t pwbuflen = pwbuflenmax;
 		  struct passwd pwbuf;
-		  int malloc_pwtmpbuf = 0;
 		  int save = errno;
 
-#    ifndef _LIBC
-		  if (pwbuflen == -1)
-		    /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
+#  ifndef _LIBC
+		  if (! (0 < pwbuflenmax && pwbuflenmax <= SIZE_MAX))
+		    /* 'sysconf' does not support _SC_GETPW_R_SIZE_MAX.
 		       Try a moderate value.  */
 		    pwbuflen = 1024;
-#    endif
-		  if (__libc_use_alloca (alloca_used + pwbuflen))
+#  endif
+		  if (glob_use_alloca (alloca_used, pwbuflen))
 		    pwtmpbuf = alloca_account (pwbuflen, alloca_used);
 		  else
 		    {
 		      pwtmpbuf = malloc (pwbuflen);
 		      if (pwtmpbuf == NULL)
 			{
+			  if (__glibc_unlikely (malloc_name))
+			    free (name);
 			  retval = GLOB_NOSPACE;
 			  goto out;
 			}
-		      malloc_pwtmpbuf = 1;
+		      malloc_pwtmpbuf = pwtmpbuf;
 		    }
 
 		  while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
 			 != 0)
 		    {
+		      size_t newlen;
+		      bool v;
 		      if (errno != ERANGE)
 			{
 			  p = NULL;
 			  break;
 			}
-
-		      if (!malloc_pwtmpbuf
-			  && __libc_use_alloca (alloca_used
-						+ 2 * pwbuflen))
+		      v = size_add_wrapv (pwbuflen, pwbuflen, &newlen);
+		      if (!v && malloc_pwtmpbuf == NULL
+			  && glob_use_alloca (alloca_used, newlen))
 			pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen,
-							  2 * pwbuflen,
-							  alloca_used);
+							  newlen, alloca_used);
 		      else
 			{
-			  char *newp = realloc (malloc_pwtmpbuf
-						? pwtmpbuf : NULL,
-						2 * pwbuflen);
+			  char *newp = (v ? NULL
+					: realloc (malloc_pwtmpbuf, newlen));
 			  if (newp == NULL)
 			    {
-			      if (__glibc_unlikely (malloc_pwtmpbuf))
-				free (pwtmpbuf);
+			      free (malloc_pwtmpbuf);
+			      if (__glibc_unlikely (malloc_name))
+				free (name);
 			      retval = GLOB_NOSPACE;
 			      goto out;
 			    }
-			  pwtmpbuf = newp;
-			  pwbuflen = 2 * pwbuflen;
-			  malloc_pwtmpbuf = 1;
+			  malloc_pwtmpbuf = pwtmpbuf = newp;
 			}
+		      pwbuflen = newlen;
 		      __set_errno (save);
 		    }
-#   else
+# else
 		  p = getpwnam (name);
-#   endif
+# endif
+		  if (__glibc_unlikely (malloc_name))
+		    free (name);
 		  if (p != NULL)
 		    {
-		      if (!malloc_pwtmpbuf)
+		      if (malloc_pwtmpbuf == NULL)
 			home_dir = p->pw_dir;
 		      else
 			{
 			  size_t home_dir_len = strlen (p->pw_dir) + 1;
-			  if (__libc_use_alloca (alloca_used + home_dir_len))
+			  if (glob_use_alloca (alloca_used, home_dir_len))
 			    home_dir = alloca_account (home_dir_len,
 						       alloca_used);
 			  else
@@ -736,26 +755,32 @@ glob (pattern, flags, errfunc, pglob)
 			      malloc_home_dir = 1;
 			    }
 			  memcpy (home_dir, p->pw_dir, home_dir_len);
-
-			  free (pwtmpbuf);
 			}
 		    }
+		  free (malloc_pwtmpbuf);
 		}
+	      else
+		{
+		  if (__glibc_unlikely (malloc_name))
+		    free (name);
+		}
+#endif /* WINDOWS32 */
 	    }
 	  if (home_dir == NULL || home_dir[0] == '\0')
 	    {
+	      if (__glibc_unlikely (malloc_home_dir))
+		free (home_dir);
 	      if (flags & GLOB_TILDE_CHECK)
 		{
-		  if (__glibc_unlikely (malloc_home_dir))
-		    free (home_dir);
 		  retval = GLOB_NOMATCH;
 		  goto out;
 		}
 	      else
-		home_dir = (char *) "~"; /* No luck.  */
+		{
+		  home_dir = (char *) "~"; /* No luck.  */
+		  malloc_home_dir = 0;
+		}
 	    }
-#  endif /* WINDOWS32 */
-# endif
 	  /* Now construct the full directory.  */
 	  if (dirname[1] == '\0')
 	    {
@@ -770,8 +795,7 @@ glob (pattern, flags, errfunc, pglob)
 	    {
 	      char *newp;
 	      size_t home_len = strlen (home_dir);
-	      int use_alloca = __libc_use_alloca (alloca_used
-						  + home_len + dirlen);
+	      int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen);
 	      if (use_alloca)
 		newp = alloca_account (home_len + dirlen, alloca_used);
 	      else
@@ -795,12 +819,15 @@ glob (pattern, flags, errfunc, pglob)
 	      dirname = newp;
 	      dirlen += home_len - 1;
 	      malloc_dirname = !use_alloca;
+
+	      if (__glibc_unlikely (malloc_home_dir))
+		free (home_dir);
 	    }
 	  dirname_modified = 1;
 	}
-# if !defined _AMIGA && !defined WINDOWS32
       else
 	{
+#ifndef WINDOWS32
 	  char *end_name = strchr (dirname, '/');
 	  char *user_name;
 	  int malloc_user_name = 0;
@@ -822,7 +849,7 @@ glob (pattern, flags, errfunc, pglob)
 	  else
 	    {
 	      char *newp;
-	      if (__libc_use_alloca (alloca_used + (end_name - dirname)))
+	      if (glob_use_alloca (alloca_used, end_name - dirname))
 		newp = alloca_account (end_name - dirname, alloca_used);
 	      else
 		{
@@ -867,20 +894,21 @@ glob (pattern, flags, errfunc, pglob)
 	  /* Look up specific user's home directory.  */
 	  {
 	    struct passwd *p;
+	    char *malloc_pwtmpbuf = NULL;
 #  if defined HAVE_GETPWNAM_R || defined _LIBC
-	    long int buflen = GETPW_R_SIZE_MAX ();
+	    long int buflenmax = GETPW_R_SIZE_MAX ();
+	    size_t buflen = buflenmax;
 	    char *pwtmpbuf;
-	    int malloc_pwtmpbuf = 0;
 	    struct passwd pwbuf;
 	    int save = errno;
 
 #   ifndef _LIBC
-	    if (buflen == -1)
-	      /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.  Try a
+	    if (! (0 <= buflenmax && buflenmax <= SIZE_MAX))
+	      /* Perhaps 'sysconf' does not support _SC_GETPW_R_SIZE_MAX.  Try a
 		 moderate value.  */
 	      buflen = 1024;
 #   endif
-	    if (__libc_use_alloca (alloca_used + buflen))
+	    if (glob_use_alloca (alloca_used, buflen))
 	      pwtmpbuf = alloca_account (buflen, alloca_used);
 	    else
 	      {
@@ -893,32 +921,32 @@ glob (pattern, flags, errfunc, pglob)
 		    retval = GLOB_NOSPACE;
 		    goto out;
 		  }
-		malloc_pwtmpbuf = 1;
+		malloc_pwtmpbuf = pwtmpbuf;
 	      }
 
 	    while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
 	      {
+		size_t newlen;
+		bool v;
 		if (errno != ERANGE)
 		  {
 		    p = NULL;
 		    break;
 		  }
-		if (!malloc_pwtmpbuf
-		    && __libc_use_alloca (alloca_used + 2 * buflen))
+		v = size_add_wrapv (buflen, buflen, &newlen);
+		if (!v && malloc_pwtmpbuf == NULL
+		    && glob_use_alloca (alloca_used, newlen))
 		  pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen,
-						    2 * buflen, alloca_used);
+						    newlen, alloca_used);
 		else
 		  {
-		    char *newp = realloc (malloc_pwtmpbuf ? pwtmpbuf : NULL,
-					  2 * buflen);
+		    char *newp = v ? NULL : realloc (malloc_pwtmpbuf, newlen);
 		    if (newp == NULL)
 		      {
-			if (__glibc_unlikely (malloc_pwtmpbuf))
-			  free (pwtmpbuf);
+			free (malloc_pwtmpbuf);
 			goto nomem_getpw;
 		      }
-		    pwtmpbuf = newp;
-		    malloc_pwtmpbuf = 1;
+		    malloc_pwtmpbuf = pwtmpbuf = newp;
 		  }
 		__set_errno (save);
 	      }
@@ -939,7 +967,7 @@ glob (pattern, flags, errfunc, pglob)
 		  free (dirname);
 		malloc_dirname = 0;
 
-		if (__libc_use_alloca (alloca_used + home_len + rest_len + 1))
+		if (glob_use_alloca (alloca_used, home_len + rest_len + 1))
 		  dirname = alloca_account (home_len + rest_len + 1,
 					    alloca_used);
 		else
@@ -947,8 +975,7 @@ glob (pattern, flags, errfunc, pglob)
 		    dirname = malloc (home_len + rest_len + 1);
 		    if (dirname == NULL)
 		      {
-			if (__glibc_unlikely (malloc_pwtmpbuf))
-			  free (pwtmpbuf);
+			free (malloc_pwtmpbuf);
 			retval = GLOB_NOSPACE;
 			goto out;
 		      }
@@ -960,24 +987,24 @@ glob (pattern, flags, errfunc, pglob)
 		dirlen = home_len + rest_len;
 		dirname_modified = 1;
 
-		if (__glibc_unlikely (malloc_pwtmpbuf))
-		  free (pwtmpbuf);
+		free (malloc_pwtmpbuf);
 	      }
 	    else
 	      {
-		if (__glibc_unlikely (malloc_pwtmpbuf))
-		  free (pwtmpbuf);
+		free (malloc_pwtmpbuf);
 
 		if (flags & GLOB_TILDE_CHECK)
-		  /* We have to regard it as an error if we cannot find the
-		     home directory.  */
-		  return GLOB_NOMATCH;
+		  {
+		    /* We have to regard it as an error if we cannot find the
+		       home directory.  */
+		    retval = GLOB_NOMATCH;
+		    goto out;
+		  }
 	      }
 	  }
+#endif /* !WINDOWS32 */
 	}
-# endif	/* Not Amiga && not WINDOWS32.  */
     }
-#endif	/* Not VMS.  */
 
   /* Now test whether we looked for "~" or "~NAME".  In this case we
      can give the answer now.  */
@@ -996,19 +1023,18 @@ glob (pattern, flags, errfunc, pglob)
 	  size_t newcount = pglob->gl_pathc + pglob->gl_offs;
 	  char **new_gl_pathv;
 
-	  if (newcount > UINTPTR_MAX - (1 + 1)
-	      || newcount + 1 + 1 > ~((size_t) 0) / sizeof (char *))
+	  if (newcount > SIZE_MAX / sizeof (char *) - 2)
 	    {
 	    nospace:
 	      free (pglob->gl_pathv);
 	      pglob->gl_pathv = NULL;
 	      pglob->gl_pathc = 0;
-	      return GLOB_NOSPACE;
+	      retval = GLOB_NOSPACE;
+	      goto out;
 	    }
 
-	  new_gl_pathv
-	    = (char **) realloc (pglob->gl_pathv,
-				 (newcount + 1 + 1) * sizeof (char *));
+	  new_gl_pathv = realloc (pglob->gl_pathv,
+				  (newcount + 2) * sizeof (char *));
 	  if (new_gl_pathv == NULL)
 	    goto nospace;
 	  pglob->gl_pathv = new_gl_pathv;
@@ -1022,12 +1048,19 @@ glob (pattern, flags, errfunc, pglob)
 	      p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen);
 	      p[0] = '/';
 	      p[1] = '\0';
+	      if (__glibc_unlikely (malloc_dirname))
+		free (dirname);
 	    }
 	  else
 	    {
-	      pglob->gl_pathv[newcount] = strdup (dirname);
-	      if (pglob->gl_pathv[newcount] == NULL)
-		goto nospace;
+	      if (__glibc_unlikely (malloc_dirname))
+		pglob->gl_pathv[newcount] = dirname;
+	      else
+		{
+		  pglob->gl_pathv[newcount] = strdup (dirname);
+		  if (pglob->gl_pathv[newcount] == NULL)
+		    goto nospace;
+		}
 	    }
 	  pglob->gl_pathv[++newcount] = NULL;
 	  ++pglob->gl_pathc;
@@ -1037,7 +1070,8 @@ glob (pattern, flags, errfunc, pglob)
 	}
 
       /* Not found.  */
-      return GLOB_NOMATCH;
+      retval = GLOB_NOMATCH;
+      goto out;
     }
 
   meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE));
@@ -1083,7 +1117,10 @@ glob (pattern, flags, errfunc, pglob)
       if (status != 0)
 	{
 	  if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
-	    return status;
+	    {
+	      retval = status;
+	      goto out;
+	    }
 	  goto no_matches;
 	}
 
@@ -1094,19 +1131,6 @@ glob (pattern, flags, errfunc, pglob)
 	{
 	  size_t old_pathc;
 
-#ifdef	SHELL
-	  {
-	    /* Make globbing interruptible in the bash shell. */
-	    extern int interrupt_state;
-
-	    if (interrupt_state)
-	      {
-		globfree (&dirs);
-		return GLOB_ABORTED;
-	      }
-	  }
-#endif /* SHELL.  */
-
 	  old_pathc = pglob->gl_pathc;
 	  status = glob_in_dir (filename, dirs.gl_pathv[i],
 				((flags | GLOB_APPEND)
@@ -1121,7 +1145,8 @@ glob (pattern, flags, errfunc, pglob)
 	      globfree (&dirs);
 	      globfree (pglob);
 	      pglob->gl_pathc = 0;
-	      return status;
+	      retval = status;
+	      goto out;
 	    }
 
 	  /* Stick the directory on the front of each name.  */
@@ -1132,13 +1157,14 @@ glob (pattern, flags, errfunc, pglob)
 	      globfree (&dirs);
 	      globfree (pglob);
 	      pglob->gl_pathc = 0;
-	      return GLOB_NOSPACE;
+	      retval = GLOB_NOSPACE;
+	      goto out;
 	    }
 	}
 
       flags |= GLOB_MAGCHAR;
 
-      /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
+      /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls.
 	 But if we have not found any matching entry and the GLOB_NOCHECK
 	 flag was set we must return the input pattern itself.  */
       if (pglob->gl_pathc + pglob->gl_offs == oldcount)
@@ -1150,28 +1176,28 @@ glob (pattern, flags, errfunc, pglob)
 	      size_t newcount = pglob->gl_pathc + pglob->gl_offs;
 	      char **new_gl_pathv;
 
-	      if (newcount > UINTPTR_MAX - 2
-		  || newcount + 2 > ~((size_t) 0) / sizeof (char *))
+	      if (newcount > SIZE_MAX / sizeof (char *) - 2)
 		{
 		nospace2:
 		  globfree (&dirs);
-		  return GLOB_NOSPACE;
+		  retval = GLOB_NOSPACE;
+		  goto out;
 		}
 
-	      new_gl_pathv = (char **) realloc (pglob->gl_pathv,
-						(newcount + 2)
-						* sizeof (char *));
+	      new_gl_pathv = realloc (pglob->gl_pathv,
+				      (newcount + 2) * sizeof (char *));
 	      if (new_gl_pathv == NULL)
 		goto nospace2;
 	      pglob->gl_pathv = new_gl_pathv;
 
-	      pglob->gl_pathv[newcount] = __strdup (pattern);
+	      pglob->gl_pathv[newcount] = strdup (pattern);
 	      if (pglob->gl_pathv[newcount] == NULL)
 		{
 		  globfree (&dirs);
 		  globfree (pglob);
 		  pglob->gl_pathc = 0;
-		  return GLOB_NOSPACE;
+		  retval = GLOB_NOSPACE;
+		  goto out;
 		}
 
 	      ++pglob->gl_pathc;
@@ -1183,7 +1209,8 @@ glob (pattern, flags, errfunc, pglob)
 	  else
 	    {
 	      globfree (&dirs);
-	      return GLOB_NOMATCH;
+	      retval = GLOB_NOMATCH;
+	      goto out;
 	    }
 	}
 
@@ -1229,7 +1256,8 @@ glob (pattern, flags, errfunc, pglob)
 	      flags = orig_flags;
 	      goto no_matches;
 	    }
-	  return status;
+	  retval = status;
+	  goto out;
 	}
 
       if (dirlen > 0)
@@ -1241,7 +1269,8 @@ glob (pattern, flags, errfunc, pglob)
 	    {
 	      globfree (pglob);
 	      pglob->gl_pathc = 0;
-	      return GLOB_NOSPACE;
+	      retval = GLOB_NOSPACE;
+	      goto out;
 	    }
 	}
     }
@@ -1266,7 +1295,8 @@ glob (pattern, flags, errfunc, pglob)
 	      {
 		globfree (pglob);
 		pglob->gl_pathc = 0;
-		return GLOB_NOSPACE;
+		retval = GLOB_NOSPACE;
+		goto out;
 	      }
 	    strcpy (&new[len - 2], "/");
 	    pglob->gl_pathv[i] = new;
@@ -1292,33 +1322,12 @@ libc_hidden_def (glob)
 #endif
 
 
-#if !defined _LIBC || !defined GLOB_ONLY_P
-
-/* Free storage allocated in PGLOB by a previous `glob' call.  */
-void
-globfree (pglob)
-     glob_t *pglob;
-{
-  if (pglob->gl_pathv != NULL)
-    {
-      size_t i;
-      for (i = 0; i < pglob->gl_pathc; ++i)
-	free (pglob->gl_pathv[pglob->gl_offs + i]);
-      free (pglob->gl_pathv);
-      pglob->gl_pathv = NULL;
-    }
-}
-#if defined _LIBC && !defined globfree
-libc_hidden_def (globfree)
-#endif
-
-
 /* Do a collated comparison of A and B.  */
 static int
 collated_compare (const void *a, const void *b)
 {
-  const char *const s1 = *(const char *const * const) a;
-  const char *const s2 = *(const char *const * const) b;
+  char *const *ps1 = a; char *s1 = *ps1;
+  char *const *ps2 = b; char *s2 = *ps2;
 
   if (s1 == s2)
     return 0;
@@ -1339,28 +1348,24 @@ prefix_array (const char *dirname, char **array, size_t n)
 {
   size_t i;
   size_t dirlen = strlen (dirname);
-#if defined __MSDOS__ || defined WINDOWS32
-  int sep_char = '/';
-# define DIRSEP_CHAR sep_char
-#else
-# define DIRSEP_CHAR '/'
-#endif
+  char dirsep_char = '/';
 
   if (dirlen == 1 && dirname[0] == '/')
     /* DIRNAME is just "/", so normal prepending would get us "//foo".
        We want "/foo" instead, so don't prepend any chars from DIRNAME.  */
     dirlen = 0;
+
 #if defined __MSDOS__ || defined WINDOWS32
-  else if (dirlen > 1)
+  if (dirlen > 1)
     {
       if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
 	/* DIRNAME is "d:/".  Don't prepend the slash from DIRNAME.  */
 	--dirlen;
       else if (dirname[dirlen - 1] == ':')
 	{
-	  /* DIRNAME is "d:".  Use `:' instead of `/'.  */
+	  /* DIRNAME is "d:".  Use ':' instead of '/'.  */
 	  --dirlen;
-	  sep_char = ':';
+	  dirsep_char = ':';
 	}
     }
 #endif
@@ -1368,7 +1373,7 @@ prefix_array (const char *dirname, char **array, size_t n)
   for (i = 0; i < n; ++i)
     {
       size_t eltlen = strlen (array[i]) + 1;
-      char *new = (char *) malloc (dirlen + 1 + eltlen);
+      char *new = malloc (dirlen + 1 + eltlen);
       if (new == NULL)
 	{
 	  while (i > 0)
@@ -1378,7 +1383,7 @@ prefix_array (const char *dirname, char **array, size_t n)
 
       {
 	char *endp = mempcpy (new, dirname, dirlen);
-	*endp++ = DIRSEP_CHAR;
+	*endp++ = dirsep_char;
 	mempcpy (endp, array[i], eltlen);
       }
       free (array[i]);
@@ -1388,107 +1393,57 @@ prefix_array (const char *dirname, char **array, size_t n)
   return 0;
 }
 
-
-/* We must not compile this function twice.  */
-#if !defined _LIBC || !defined NO_GLOB_PATTERN_P
-int
-__glob_pattern_type (pattern, quote)
-     const char *pattern;
-     int quote;
-{
-  const char *p;
-  int ret = 0;
-
-  for (p = pattern; *p != '\0'; ++p)
-    switch (*p)
-      {
-      case '?':
-      case '*':
-	return 1;
-
-      case '\\':
-	if (quote)
-	  {
-	    if (p[1] != '\0')
-	      ++p;
-	    ret |= 2;
-	  }
-	break;
-
-      case '[':
-	ret |= 4;
-	break;
-
-      case ']':
-	if (ret & 4)
-	  return 1;
-	break;
-      }
-
-  return ret;
-}
-
-/* Return nonzero if PATTERN contains any metacharacters.
-   Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
-int
-__glob_pattern_p (pattern, quote)
-     const char *pattern;
-     int quote;
-{
-  return __glob_pattern_type (pattern, quote) == 1;
-}
-# ifdef _LIBC
-weak_alias (__glob_pattern_p, glob_pattern_p)
-# endif
-#endif
-
-#endif /* !GLOB_ONLY_P */
-
-
 /* We put this in a separate function mainly to allow the memory
    allocated with alloca to be recycled.  */
-#if !defined _LIBC || !defined GLOB_ONLY_P
 static int
 __attribute_noinline__
-link_exists2_p (const char *dir, size_t dirlen, const char *fname,
-	       glob_t *pglob
-# ifndef _LIBC
-		, int flags
+link_stat (const char *dir, size_t dirlen, const char *fname,
+	   glob_t *pglob
+# if !defined _LIBC && !HAVE_FSTATAT
+	   , int flags
 # endif
-		)
+	   )
 {
   size_t fnamelen = strlen (fname);
-  char *fullname = (char *) __alloca (dirlen + 1 + fnamelen + 1);
+  char *fullname = __alloca (dirlen + 1 + fnamelen + 1);
   struct stat st;
-# ifndef _LIBC
-  struct_stat64 st64;
-# endif
 
   mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1),
 	   fname, fnamelen + 1);
 
-# ifdef _LIBC
-  return (*pglob->gl_stat) (fullname, &st) == 0;
-# else
-  return ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
-	   ? (*pglob->gl_stat) (fullname, &st)
-	   : __stat64 (fullname, &st64)) == 0);
+# if !defined _LIBC && !HAVE_FSTATAT
+  if (__builtin_expect ((flags & GLOB_ALTDIRFUNC) == 0, 1))
+    {
+      struct_stat64 st64;
+      return __stat64 (fullname, &st64);
+    }
 # endif
+  return (*pglob->gl_stat) (fullname, &st);
 }
-# ifdef _LIBC
-#  define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \
-  (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)			      \
-   ? link_exists2_p (dirname, dirnamelen, fname, pglob)			      \
-   : ({ struct stat64 st64;						      \
-       __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0) == 0; }))
+
+/* Return true if DIR/FNAME exists.  */
+static int
+link_exists_p (int dfd, const char *dir, size_t dirlen, const char *fname,
+	       glob_t *pglob, int flags)
+{
+  int status;
+# if defined _LIBC || HAVE_FSTATAT
+  if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
+    status = link_stat (dir, dirlen, fname, pglob);
+  else
+    {
+      /* dfd cannot be -1 here, because dirfd never returns -1 on
+	 glibc, or on hosts that have fstatat.  */
+      struct_stat64 st64;
+      status = __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0);
+    }
 # else
-#  define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \
-  link_exists2_p (dirname, dirnamelen, fname, pglob, flags)
+  status = link_stat (dir, dirlen, fname, pglob, flags);
 # endif
-#endif
-
+  return status == 0 || errno == EOVERFLOW;
+}
 
-/* Like `glob', but PATTERN is a final pathname component,
+/* Like 'glob', but PATTERN is a final pathname component,
    and matches are searched for in DIRECTORY.
    The GLOB_NOSORT bit in FLAGS is ignored.  No sorting is ever done.
    The GLOB_APPEND flag is assumed to be set (always appends).  */
@@ -1499,25 +1454,25 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
 {
   size_t dirlen = strlen (directory);
   void *stream = NULL;
-  struct globnames
-    {
-      struct globnames *next;
-      size_t count;
-      char *name[64];
-    };
-#define INITIAL_COUNT sizeof (init_names.name) / sizeof (init_names.name[0])
-  struct globnames init_names;
-  struct globnames *names = &init_names;
-  struct globnames *names_alloca = &init_names;
+# define GLOBNAMES_MEMBERS(nnames) \
+    struct globnames *next; size_t count; char *name[nnames];
+  struct globnames { GLOBNAMES_MEMBERS (FLEXIBLE_ARRAY_MEMBER) };
+  struct { GLOBNAMES_MEMBERS (64) } init_names_buf;
+  struct globnames *init_names = (struct globnames *) &init_names_buf;
+  struct globnames *names = init_names;
+  struct globnames *names_alloca = init_names;
   size_t nfound = 0;
   size_t cur = 0;
   int meta;
   int save;
+  int result;
 
-  alloca_used += sizeof (init_names);
+  alloca_used += sizeof init_names_buf;
 
-  init_names.next = NULL;
-  init_names.count = INITIAL_COUNT;
+  init_names->next = NULL;
+  init_names->count = ((sizeof init_names_buf
+                        - offsetof (struct globnames, name))
+                       / sizeof init_names->name[0]);
 
   meta = __glob_pattern_type (pattern, !(flags & GLOB_NOESCAPE));
   if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
@@ -1537,14 +1492,16 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
 	struct_stat64 st64;
       } ust;
       size_t patlen = strlen (pattern);
-      int alloca_fullname = __libc_use_alloca (alloca_used
-					       + dirlen + 1 + patlen + 1);
+      size_t fullsize;
+      bool alloca_fullname
+        = (! size_add_wrapv (dirlen + 1, patlen + 1, &fullsize)
+           && glob_use_alloca (alloca_used, fullsize));
       char *fullname;
       if (alloca_fullname)
-	fullname = alloca_account (dirlen + 1 + patlen + 1, alloca_used);
+        fullname = alloca_account (fullsize, alloca_used);
       else
 	{
-	  fullname = malloc (dirlen + 1 + patlen + 1);
+	  fullname = malloc (fullsize);
 	  if (fullname == NULL)
 	    return GLOB_NOSPACE;
 	}
@@ -1552,9 +1509,11 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
       mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
 			"/", 1),
 	       pattern, patlen + 1);
-      if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+      if (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
 	   ? (*pglob->gl_stat) (fullname, &ust.st)
-	   : __stat64 (fullname, &ust.st64)) == 0)
+	    : __stat64 (fullname, &ust.st64))
+	   == 0)
+	  || errno == EOVERFLOW)
 	/* We found this file to be existing.  Now tell the rest
 	   of the function to copy this name into the result.  */
 	flags |= GLOB_NOCHECK;
@@ -1576,16 +1535,10 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
 	}
       else
 	{
-#ifdef _LIBC
 	  int dfd = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
 		     ? -1 : dirfd ((DIR *) stream));
-#endif
 	  int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
-			   | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
-#if defined _AMIGA || defined VMS
-			   | FNM_CASEFOLD
-#endif
-			   );
+			   | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0));
 	  flags |= GLOB_MAGCHAR;
 
 	  while (1)
@@ -1605,19 +1558,24 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
 	      }
 	      if (d.name == NULL)
 		break;
-	      if (d.skip_entry)
+	      if (readdir_result_skip_entry (d))
 		continue;
 
 	      /* If we shall match only directories use the information
 		 provided by the dirent call if possible.  */
-	      if ((flags & GLOB_ONLYDIR) && !readdir_result_might_be_dir (d))
-		continue;
+	      if (flags & GLOB_ONLYDIR)
+		switch (readdir_result_type (d))
+		  {
+		  case DT_DIR: case DT_LNK: case DT_UNKNOWN: break;
+		  default: continue;
+		  }
 
 	      if (fnmatch (pattern, d.name, fnm_flags) == 0)
 		{
 		  /* If the file we found is a symlink we have to
 		     make sure the target file exists.  */
-		  if (!readdir_result_might_be_symlink (d)
+		  dirent_type type = readdir_result_type (d);
+		  if (! (type == DT_LNK || type == DT_UNKNOWN)
 		      || link_exists_p (dfd, directory, dirlen, d.name,
 					pglob, flags))
 		    {
@@ -1625,10 +1583,13 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
 			{
 			  struct globnames *newnames;
 			  size_t count = names->count * 2;
-			  size_t size = (sizeof (struct globnames)
-					 + ((count - INITIAL_COUNT)
-					    * sizeof (char *)));
-			  if (__libc_use_alloca (alloca_used + size))
+			  size_t nameoff = offsetof (struct globnames, name);
+			  size_t size = FLEXSIZEOF (struct globnames, name,
+						    count * sizeof (char *));
+			  if ((SIZE_MAX - nameoff) / 2 / sizeof (char *)
+			      < names->count)
+			    goto memory_error;
+			  if (glob_use_alloca (alloca_used, size))
 			    newnames = names_alloca
 			      = alloca_account (size, alloca_used);
 			  else if ((newnames = malloc (size))
@@ -1644,6 +1605,8 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
 			goto memory_error;
 		      ++cur;
 		      ++nfound;
+		      if (SIZE_MAX - pglob->gl_offs <= nfound)
+			goto memory_error;
 		    }
 		}
 	    }
@@ -1654,29 +1617,27 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
     {
       size_t len = strlen (pattern);
       nfound = 1;
-      names->name[cur] = (char *) malloc (len + 1);
+      names->name[cur] = malloc (len + 1);
       if (names->name[cur] == NULL)
 	goto memory_error;
       *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0';
     }
 
-  int result = GLOB_NOMATCH;
+  result = GLOB_NOMATCH;
   if (nfound != 0)
     {
+      char **new_gl_pathv;
       result = 0;
 
-      if (pglob->gl_pathc > UINTPTR_MAX - pglob->gl_offs
-	  || pglob->gl_pathc + pglob->gl_offs > UINTPTR_MAX - nfound
-	  || pglob->gl_pathc + pglob->gl_offs + nfound > UINTPTR_MAX - 1
-	  || (pglob->gl_pathc + pglob->gl_offs + nfound + 1
-	      > UINTPTR_MAX / sizeof (char *)))
+      if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc
+	  < pglob->gl_offs + nfound + 1)
 	goto memory_error;
 
-      char **new_gl_pathv;
       new_gl_pathv
-	= (char **) realloc (pglob->gl_pathv,
-			     (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
-			     * sizeof (char *));
+	= realloc (pglob->gl_pathv,
+		   (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
+		    * sizeof (char *));
+
       if (new_gl_pathv == NULL)
 	{
 	memory_error:
@@ -1692,7 +1653,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
 		 and this is the block assigned to OLD here.  */
 	      if (names == NULL)
 		{
-		  assert (old == &init_names);
+		  assert (old == init_names);
 		  break;
 		}
 	      cur = names->count;
@@ -1718,7 +1679,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
 		 and this is the block assigned to OLD here.  */
 	      if (names == NULL)
 		{
-		  assert (old == &init_names);
+		  assert (old == init_names);
 		  break;
 		}
 	      cur = names->count;
diff --git a/posix/glob64.c b/posix/glob64.c
index 56ede77..96e58c3 100644
--- a/posix/glob64.c
+++ b/posix/glob64.c
@@ -43,10 +43,4 @@ glob64 (const char *pattern, int flags,
 }
 libc_hidden_def (glob64)
 
-void
-globfree64 (glob64_t *pglob)
-{
-}
-libc_hidden_def (globfree64)
-
 stub_warning (glob64)
diff --git a/posix/glob_internal.h b/posix/glob_internal.h
new file mode 100644
index 0000000..12c9366
--- /dev/null
+++ b/posix/glob_internal.h
@@ -0,0 +1,57 @@
+/* Shared definition for glob and glob_pattern_p.
+   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 GLOB_INTERNAL_H
+# define GLOB_INTERNAL_H
+
+static inline int
+__glob_pattern_type (const char *pattern, int quote)
+{
+  const char *p;
+  int ret = 0;
+
+  for (p = pattern; *p != '\0'; ++p)
+    switch (*p)
+      {
+      case '?':
+      case '*':
+        return 1;
+
+      case '\\':
+        if (quote)
+          {
+            if (p[1] != '\0')
+              ++p;
+            ret |= 2;
+          }
+        break;
+
+      case '[':
+        ret |= 4;
+        break;
+
+      case ']':
+        if (ret & 4)
+          return 1;
+        break;
+      }
+
+  return ret;
+}
+
+#endif /* GLOB_INTERNAL_H  */
diff --git a/posix/glob_pattern_p.c b/posix/glob_pattern_p.c
new file mode 100644
index 0000000..a17d337
--- /dev/null
+++ b/posix/glob_pattern_p.c
@@ -0,0 +1,33 @@
+/* Return nonzero if PATTERN contains any metacharacters.
+   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 _LIBC
+# include <config.h>
+#endif
+
+#include <glob.h>
+#include "glob_internal.h"
+
+/* Return nonzero if PATTERN contains any metacharacters.
+   Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
+int
+__glob_pattern_p (const char *pattern, int quote)
+{
+  return __glob_pattern_type (pattern, quote) == 1;
+}
+weak_alias (__glob_pattern_p, glob_pattern_p)
diff --git a/posix/globfree.c b/posix/globfree.c
new file mode 100644
index 0000000..042e29d
--- /dev/null
+++ b/posix/globfree.c
@@ -0,0 +1,41 @@
+/* Frees the dynamically allocated storage from an earlier call to glob.
+   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 _LIBC
+# include <config.h>
+#endif
+
+#include <glob.h>
+#include <stdlib.h>
+
+/* Free storage allocated in PGLOB by a previous `glob' call.  */
+void
+globfree (glob_t *pglob)
+{
+  if (pglob->gl_pathv != NULL)
+    {
+      size_t i;
+      for (i = 0; i < pglob->gl_pathc; ++i)
+        free (pglob->gl_pathv[pglob->gl_offs + i]);
+      free (pglob->gl_pathv);
+      pglob->gl_pathv = NULL;
+    }
+}
+#ifndef globfree
+libc_hidden_def (globfree)
+#endif
diff --git a/posix/globfree64.c b/posix/globfree64.c
new file mode 100644
index 0000000..c9f8908
--- /dev/null
+++ b/posix/globfree64.c
@@ -0,0 +1,31 @@
+/* Frees the dynamically allocated storage from an earlier call to glob.
+   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 _LIBC
+# include <config.h>
+#endif
+
+#include <glob.h>
+#include <stdlib.h>
+
+/* Free storage allocated in PGLOB by a previous `glob' call.  */
+void
+globfree64 (glob64_t *pglob)
+{
+}
+libc_hidden_def (globfree64)
diff --git a/sysdeps/gnu/glob64.c b/sysdeps/gnu/glob64.c
index d1e4e6f..52e97e2 100644
--- a/sysdeps/gnu/glob64.c
+++ b/sysdeps/gnu/glob64.c
@@ -15,11 +15,8 @@
 #undef __stat
 #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
 
-#define NO_GLOB_PATTERN_P 1
-
 #define COMPILE_GLOB64	1
 
 #include <posix/glob.c>
 
 libc_hidden_def (glob64)
-libc_hidden_def (globfree64)
diff --git a/sysdeps/gnu/globfree64.c b/sysdeps/gnu/globfree64.c
new file mode 100644
index 0000000..f092d0b
--- /dev/null
+++ b/sysdeps/gnu/globfree64.c
@@ -0,0 +1,10 @@
+#include <dirent.h>
+#include <glob.h>
+#include <sys/stat.h>
+
+#define glob_t glob64_t
+#define globfree(pglob) globfree64 (pglob)
+
+#include <posix/globfree.c>
+
+libc_hidden_def (globfree64)
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index bfbabd4..07cf9bf 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -137,7 +137,7 @@ endif
 ifeq ($(subdir),posix)
 sysdep_headers += bits/initspin.h
 
-sysdep_routines += sched_getcpu
+sysdep_routines += sched_getcpu oldglob
 
 tests += tst-getcpu
 
diff --git a/sysdeps/unix/sysv/linux/alpha/glob.c b/sysdeps/unix/sysv/linux/alpha/glob.c
index b0df24b..639e949 100644
--- a/sysdeps/unix/sysv/linux/alpha/glob.c
+++ b/sysdeps/unix/sysv/linux/alpha/glob.c
@@ -42,10 +42,6 @@ extern void __new_globfree (glob_t *__pglob);
 #undef globfree64
 
 versioned_symbol (libc, __new_glob, glob, GLIBC_2_1);
-versioned_symbol (libc, __new_globfree, globfree, GLIBC_2_1);
 libc_hidden_ver (__new_glob, glob)
-libc_hidden_ver (__new_globfree, globfree)
 
 weak_alias (__new_glob, glob64)
-weak_alias (__new_globfree, globfree64)
-libc_hidden_ver (__new_globfree, globfree64)
diff --git a/sysdeps/unix/sysv/linux/alpha/globfree.c b/sysdeps/unix/sysv/linux/alpha/globfree.c
new file mode 100644
index 0000000..98cf1c2
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/alpha/globfree.c
@@ -0,0 +1,37 @@
+/* Compat globfree.  Linux/alpha version.
+   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/>.  */
+
+#define globfree64 __no_globfree64_decl
+#include <sys/types.h>
+#include <glob.h>
+#include <shlib-compat.h>
+
+#define globfree(pglob) \
+  __new_globfree (pglob)
+
+extern void __new_globfree (glob_t *__pglob);
+
+#include <posix/globfree.c>
+
+#undef globfree64
+
+versioned_symbol (libc, __new_globfree, globfree, GLIBC_2_1);
+libc_hidden_ver (__new_globfree, globfree)
+
+weak_alias (__new_globfree, globfree64)
+libc_hidden_ver (__new_globfree, globfree64)
diff --git a/sysdeps/unix/sysv/linux/i386/glob64.c b/sysdeps/unix/sysv/linux/i386/glob64.c
index 802c957..c2cc857 100644
--- a/sysdeps/unix/sysv/linux/i386/glob64.c
+++ b/sysdeps/unix/sysv/linux/i386/glob64.c
@@ -19,6 +19,7 @@
 #include <dirent.h>
 #include <glob.h>
 #include <sys/stat.h>
+#include <shlib-compat.h>
 
 #define dirent dirent64
 #define __readdir(dirp) __readdir64 (dirp)
@@ -33,44 +34,9 @@
 #undef __stat
 #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
 
-#define NO_GLOB_PATTERN_P 1
-
 #define COMPILE_GLOB64	1
 
 #include <posix/glob.c>
 
-#include "shlib-compat.h"
-
-libc_hidden_def (globfree64)
-
 versioned_symbol (libc, __glob64, glob64, GLIBC_2_2);
 libc_hidden_ver (__glob64, glob64)
-
-#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
-
-#include <sysdeps/unix/sysv/linux/i386/olddirent.h>
-
-int __old_glob64 (const char *__pattern, int __flags,
-		  int (*__errfunc) (const char *, int),
-		  glob64_t *__pglob);
-
-#undef dirent
-#define dirent __old_dirent64
-#undef GL_READDIR
-# define GL_READDIR(pglob, stream) \
-  ((struct __old_dirent64 *) (pglob)->gl_readdir (stream))
-#undef __readdir
-#define __readdir(dirp) __old_readdir64 (dirp)
-#undef glob
-#define glob(pattern, flags, errfunc, pglob) \
-  __old_glob64 (pattern, flags, errfunc, pglob)
-#define convert_dirent __old_convert_dirent
-#define glob_in_dir __old_glob_in_dir
-#define GLOB_ATTRIBUTE attribute_compat_text_section
-
-#define GLOB_ONLY_P 1
-
-#include <posix/glob.c>
-
-compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1);
-#endif
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c
new file mode 100644
index 0000000..abc35fd
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c
@@ -0,0 +1 @@
+/* glob64 is in globfree64.c */
diff --git a/sysdeps/unix/sysv/linux/oldglob.c b/sysdeps/unix/sysv/linux/oldglob.c
new file mode 100644
index 0000000..8233e57
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/oldglob.c
@@ -0,0 +1,42 @@
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
+
+#include <dirent.h>
+#include <glob.h>
+#include <sys/stat.h>
+
+#include <sysdeps/unix/sysv/linux/i386/olddirent.h>
+
+int __old_glob64 (const char *__pattern, int __flags,
+		  int (*__errfunc) (const char *, int),
+		  glob64_t *__pglob);
+libc_hidden_proto (__old_glob64);
+
+#define dirent __old_dirent64
+#define GL_READDIR(pglob, stream) \
+  ((struct __old_dirent64 *) (pglob)->gl_readdir (stream))
+#undef __readdir
+#define __readdir(dirp) __old_readdir64 (dirp)
+
+#define glob_t glob64_t
+#define glob(pattern, flags, errfunc, pglob) \
+  __old_glob64 (pattern, flags, errfunc, pglob)
+#define globfree(pglob) globfree64(pglob)
+
+#define convert_dirent __old_convert_dirent
+#define glob_in_dir __old_glob_in_dir
+
+#undef stat
+#define stat stat64
+#undef __stat
+#define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
+
+#define GLOB_ATTRIBUTE attribute_compat_text_section
+
+#include <posix/glob.c>
+
+libc_hidden_def (__old_glob64);
+
+compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1);
+#endif
diff --git a/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c b/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c
new file mode 100644
index 0000000..af035e1
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c
@@ -0,0 +1,2 @@
+/* This file is here so sysdeps/gnu/glob64.c doesn't take precedence.  */
+#include <sysdeps/wordsize-64/globfree64.c>
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c b/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c
new file mode 100644
index 0000000..b76a761
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c
@@ -0,0 +1 @@
+#include <sysdeps/wordsize-64/globfree.c>
diff --git a/sysdeps/wordsize-64/glob.c b/sysdeps/wordsize-64/glob.c
index 082faf1..954e8d3 100644
--- a/sysdeps/wordsize-64/glob.c
+++ b/sysdeps/wordsize-64/glob.c
@@ -4,5 +4,3 @@
 #undef glob64
 #undef globfree64
 weak_alias (glob, glob64)
-weak_alias (globfree, globfree64)
-libc_hidden_ver (globfree, globfree64)
diff --git a/sysdeps/wordsize-64/globfree.c b/sysdeps/wordsize-64/globfree.c
new file mode 100644
index 0000000..ec8c35b
--- /dev/null
+++ b/sysdeps/wordsize-64/globfree.c
@@ -0,0 +1,5 @@
+#define globfree64 __no_globfree64_decl
+#include <posix/globfree.c>
+#undef globfree64
+weak_alias (globfree, globfree64)
+libc_hidden_ver (globfree, globfree64)
diff --git a/sysdeps/wordsize-64/globfree64.c b/sysdeps/wordsize-64/globfree64.c
new file mode 100644
index 0000000..a0f57ff
--- /dev/null
+++ b/sysdeps/wordsize-64/globfree64.c
@@ -0,0 +1 @@
+/* globfree64 is in globfree.c */
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2.22 03/14] glob: Add new test tst-glob-tilde
  2018-01-01  0:00 ` [PATCH 2.22 03/14] glob: Add new test tst-glob-tilde Raphael Moreira Zinsly
@ 2018-01-01  0:00   ` Tulio Magno Quites Machado Filho
  2018-01-01  0:00     ` [PATCH 2.22] Synchronize support/ infrastructure with master Raphael Moreira Zinsly
  0 siblings, 1 reply; 26+ messages in thread
From: Tulio Magno Quites Machado Filho @ 2018-01-01  0:00 UTC (permalink / raw)
  To: Raphael Moreira Zinsly, libc-stable

Raphael Moreira Zinsly <rzinsly@linux.vnet.ibm.com> writes:

> The new test checks for memory leaks (see bug 22325) and attempts
> to trigger the buffer overflow in bug 22320.
>
> (cherry picked from commit e80fc1fc98bf614eb01cf8325503df3a1451a99c)

This test depends on the support/ directory, which isn't available in glibc
2.22.

The same thing happens with the other 3 new tests.

-- 
Tulio Magno

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2.22 v2] Fix integer overflows in internal memalign and malloc functions [BZ #22343]
       [not found]       ` <20180405194944.GA44061@aloka.lostca.se>
@ 2018-01-01  0:00         ` Carlos O'Donell
  2018-01-01  0:00           ` Tulio Magno Quites Machado Filho
  0 siblings, 1 reply; 26+ messages in thread
From: Carlos O'Donell @ 2018-01-01  0:00 UTC (permalink / raw)
  To: Arjun Shankar, Raphael Moreira Zinsly, rzinsly; +Cc: libc-stable

On 04/05/2018 02:49 PM, Arjun Shankar wrote:
> On Wed, 2018-04-04 at 20:29 -0500, Carlos O'Donell wrote:
> 
>>> +#include <support/test-driver.c>
>>  
>> This can't possibly work for release/2.22/master, there was no support
>> infrastructure?
> 
> I'm working on backporting *just* enough bits into 2.22 to:
> 
> 1. Include support/ infrastructure (Florian wrote a script that does this)
> 
> 2. Have glibc-2.22 compile with a new-ish GCC (7.3) -
>      This needs 8 additional commits
> 
> 3. Include fix in question; i.e. BZ #22343

I missed that IBM already posted the support/ backport here:
https://sourceware.org/ml/libc-stable/2018-04/msg00004.html

Please coordinate with IBM :-)
 
> Cheers,
> Arjun
> 
> 
> 
> On Wed, 2018-04-04 at 20:29 -0500, Carlos O'Donell wrote:
> 
>>> > > +#include <support/test-driver.c>
>> > 
>> > This can't possibly work for release/2.22/master, there was no support
>> > infrastructure?
> 
> I'm working on backporting *just* enough bits into 2.22 to:
> 
> 1. Include support/ infrastructure (Florian wrote a script that does this)
> 
> 2. Have glibc-2.22 compile with a new-ish GCC (7.3) -
> This needs 8 additional commits
> 
> 3. Include fix in question; i.e. BZ #22343
> 
> Cheers,
> Arjun
> 


-- 
Cheers,
Carlos.

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2018-04-13 18:31 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-01  0:00 [PATCH 2.22 01/14] ldd: never run file directly Raphael Moreira Zinsly
2018-01-01  0:00 ` [PATCH 2.22 08/14] <array_length.h>: New array_length and array_end macros Raphael Moreira Zinsly
2018-01-01  0:00 ` [PATCH 2.22 09/14] elf: Compute correct array size in _dl_init_paths [BZ #22606] Raphael Moreira Zinsly
2018-01-01  0:00 ` [PATCH 2.22 03/14] glob: Add new test tst-glob-tilde Raphael Moreira Zinsly
2018-01-01  0:00   ` Tulio Magno Quites Machado Filho
2018-01-01  0:00     ` [PATCH 2.22] Synchronize support/ infrastructure with master Raphael Moreira Zinsly
2018-01-01  0:00       ` Carlos O'Donell
2018-01-01  0:00       ` Tulio Magno Quites Machado Filho
2018-01-01  0:00         ` [PATCH 2.22] posix: Sync glob with gnulib [BZ #1062] Raphael Moreira Zinsly
2018-01-01  0:00           ` Tulio Magno Quites Machado Filho
2018-01-01  0:00 ` [PATCH 2.22 05/14] glob: Fix buffer overflow during GLOB_TILDE unescaping [BZ #22332] Raphael Moreira Zinsly
2018-01-01  0:00 ` [PATCH 2.22 10/14] Fix integer overflows in internal memalign and malloc functions [BZ #22343] Raphael Moreira Zinsly
2018-01-01  0:00   ` [PATCH 2.22 v2] " Raphael Moreira Zinsly
2018-01-01  0:00     ` Carlos O'Donell
     [not found]       ` <20180405194944.GA44061@aloka.lostca.se>
2018-01-01  0:00         ` Carlos O'Donell
2018-01-01  0:00           ` Tulio Magno Quites Machado Filho
2018-01-01  0:00 ` [PATCH 2.22 01/14] ldd: never run file directly Carlos O'Donell
2018-01-01  0:00   ` Tulio Magno Quites Machado Filho
2018-01-01  0:00 ` [PATCH 2.22 14/14] Record CVE-2018-6551 in NEWS and ChangeLog [BZ #22774] Raphael Moreira Zinsly
2018-01-01  0:00 ` [PATCH 2.22 11/14] linux: make getcwd(3) fail if it cannot obtain an absolute path [BZ #22679] Raphael Moreira Zinsly
2018-01-01  0:00 ` [PATCH 2.22 06/14] elf: Check for empty tokens before dynamic string token expansion [BZ #22625] Raphael Moreira Zinsly
2018-01-01  0:00 ` [PATCH 2.22 12/14] Add ChangeLog reference to bug 16750/CVE-2009-5064 Raphael Moreira Zinsly
2018-01-01  0:00 ` [PATCH 2.22 02/14] CVE-2017-15670: glob: Fix one-byte overflow [BZ #22320] Raphael Moreira Zinsly
2018-01-01  0:00 ` [PATCH 2.22 07/14] elf: Count components of the expanded path in _dl_init_path [BZ #22607] Raphael Moreira Zinsly
2018-01-01  0:00 ` [PATCH 2.22 04/14] sunrpc: Avoid use-after-free read access in clntudp_call [BZ #21115] Raphael Moreira Zinsly
2018-01-01  0:00 ` [PATCH 2.22 13/14] Record CVE-2018-6485 in ChangeLog and NEWS [BZ #22343] Raphael Moreira Zinsly

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).