]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Synchronize support/ infrastructure with master
authorFlorian Weimer <fweimer@redhat.com>
Mon, 28 Aug 2017 12:38:52 +0000 (14:38 +0200)
committerFlorian Weimer <fweimer@redhat.com>
Mon, 28 Aug 2017 12:38:52 +0000 (14:38 +0200)
This commit updates the support/ subdirectory to
commit faf8c066df0d6bccb54bd74dd696eeb65e1b3bbc
on the master branch.

48 files changed:
scripts/backport-support.sh [new file with mode: 0644]
support/Makefile
support/capture_subprocess.h [new file with mode: 0644]
support/check.h
support/namespace.h
support/resolv_test.c
support/resolv_test.h
support/support-xstat.c [new file with mode: 0644]
support/support.h
support/support_can_chroot.c [new file with mode: 0644]
support/support_capture_subprocess.c [new file with mode: 0644]
support/support_capture_subprocess_check.c [new file with mode: 0644]
support/support_chroot.c [new file with mode: 0644]
support/support_enter_network_namespace.c
support/support_format_addrinfo.c
support/support_format_dns_packet.c
support/support_isolate_in_subprocess.c [new file with mode: 0644]
support/support_run_diff.c
support/support_shared_allocate.c [new file with mode: 0644]
support/support_test_main.c
support/support_test_verify_impl.c
support/support_write_file_string.c [new file with mode: 0644]
support/temp_file.c
support/test-driver.c
support/test-driver.h
support/tst-support-namespace.c
support/tst-support_capture_subprocess.c [new file with mode: 0644]
support/tst-support_format_dns_packet.c [new file with mode: 0644]
support/tst-support_record_failure-2.sh
support/tst-support_record_failure.c
support/xaccept4.c [new file with mode: 0644]
support/xchroot.c [new file with mode: 0644]
support/xclose.c [new file with mode: 0644]
support/xdup2.c [new file with mode: 0644]
support/xmkdir.c [new file with mode: 0644]
support/xmprotect.c [new file with mode: 0644]
support/xopen.c [new file with mode: 0644]
support/xpipe.c [new file with mode: 0644]
support/xpthread_attr_setguardsize.c [new file with mode: 0644]
support/xpthread_rwlock_init.c [new file with mode: 0644]
support/xpthread_rwlock_rdlock.c [new file with mode: 0644]
support/xpthread_rwlock_unlock.c [new file with mode: 0644]
support/xpthread_rwlock_wrlock.c [new file with mode: 0644]
support/xpthread_rwlockattr_init.c [new file with mode: 0644]
support/xpthread_rwlockattr_setkind_np.c [new file with mode: 0644]
support/xsocket.h
support/xthread.h
support/xunistd.h

diff --git a/scripts/backport-support.sh b/scripts/backport-support.sh
new file mode 100644 (file)
index 0000000..2ece7ce
--- /dev/null
@@ -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
index 2ace559ae0afc05d814f177dcbc2286c1e63c436..2ace3fa8cc50c6038e830d968cac43d50651c05a 100644 (file)
@@ -35,7 +35,12 @@ libsupport-routines = \
   oom_error \
   resolv_test \
   set_fortify_handler \
+  support-xstat \
   support_become_root \
+  support_can_chroot \
+  support_capture_subprocess \
+  support_capture_subprocess_check \
+  support_chroot \
   support_enter_network_namespace \
   support_format_address_family \
   support_format_addrinfo \
@@ -43,17 +48,24 @@ libsupport-routines = \
   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 \
@@ -61,13 +73,18 @@ libsupport-routines = \
   xlisten \
   xmalloc \
   xmemstream \
+  xmkdir \
   xmmap \
+  xmprotect \
   xmunmap \
+  xopen \
+  xpipe \
   xpoll \
   xpthread_attr_destroy \
   xpthread_attr_init \
   xpthread_attr_setdetachstate \
   xpthread_attr_setstacksize \
+  xpthread_attr_setguardsize \
   xpthread_barrier_destroy \
   xpthread_barrier_init \
   xpthread_barrier_wait \
@@ -89,6 +106,12 @@ libsupport-routines = \
   xpthread_mutexattr_setrobust \
   xpthread_mutexattr_settype \
   xpthread_once \
+  xpthread_rwlock_init \
+  xpthread_rwlock_rdlock \
+  xpthread_rwlock_wrlock \
+  xpthread_rwlock_unlock \
+  xpthread_rwlockattr_init \
+  xpthread_rwlockattr_setkind_np \
   xpthread_sigmask \
   xpthread_spin_lock \
   xpthread_spin_unlock \
@@ -111,6 +134,8 @@ 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)
@@ -125,4 +150,6 @@ $(objpfx)tst-support_record_failure-2.out: tst-support_record_failure-2.sh \
        $(evaluate-test)
 endif
 
+$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so
+
 include ../Rules
diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
new file mode 100644 (file)
index 0000000..43caf9b
--- /dev/null
@@ -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 */
index 1d244a35576a2e65f3f8e6ae372a4e59c5a341dd..bdcd12952af6c286cebc9ec0916abedff71b77ed 100644 (file)
@@ -51,7 +51,7 @@ __BEGIN_DECLS
     if (expr)                                                   \
       ;                                                         \
     else                                                        \
-      support_test_verify_impl (-1, __FILE__, __LINE__, #expr); \
+      support_test_verify_impl (__FILE__, __LINE__, #expr);     \
   })
 
 /* Record a test failure and exit if EXPR evaluates to false.  */
@@ -60,7 +60,8 @@ __BEGIN_DECLS
     if (expr)                                                   \
       ;                                                         \
     else                                                        \
-      support_test_verify_impl (1, __FILE__, __LINE__, #expr);  \
+      support_test_verify_exit_impl                             \
+        (1, __FILE__, __LINE__, #expr);                         \
   })
 
 int support_print_failure_impl (const char *file, int line,
@@ -70,8 +71,11 @@ 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,
+void support_test_verify_impl (const char *file, int line,
                                const char *expr);
+void support_test_verify_exit_impl (int status, const char *file, int line,
+                                    const char *expr)
+  __attribute__ ((noreturn));
 
 /* Record a test failure.  This function returns and does not
    terminate the process.  The failure counter is stored in a shared
index 6bc82d619b9f8478e422cee40b33e3faf0bd63a0..859c2fda3ffd499cfbb62656826f00d002c25f7b 100644 (file)
@@ -35,6 +35,13 @@ __BEGIN_DECLS
    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.
@@ -48,6 +55,43 @@ bool support_enter_network_namespace (void);
    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);
+
+/* Describe the setup of a chroot environment, for
+   support_chroot_create below.  */
+struct support_chroot_configuration
+{
+  /* File contents.  The files are not created if the field is
+     NULL.  */
+  const char *resolv_conf;
+};
+
+/* The result of the creation of a chroot.  */
+struct support_chroot
+{
+  /* Path information.  All these paths are relative to the parent
+     chroot.  */
+
+  /* Path to the chroot directory.  */
+  char *path_chroot;
+
+  /* Path to the /etc/resolv.conf file.  */
+  char *path_resolv_conf;
+};
+
+/* Create a chroot environment.  The returned data should be freed
+   using support_chroot_free below.  The files will be deleted when
+   the process exits.  This function does not enter the chroot.  */
+struct support_chroot *support_chroot_create
+  (struct support_chroot_configuration);
+
+/* Deallocate the chroot information created by
+   support_chroot_create.  */
+void support_chroot_free (struct support_chroot *);
+
 __END_DECLS
 
 #endif
index 6b3554f1ce2351f6eaa8b2726233d542124852e7..1625dcf43a204434d395a6fbf8524d06c5f403fc 100644 (file)
 #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. */
+/* Response builder.  */
 
 enum
   {
@@ -910,7 +912,7 @@ server_thread_tcp_client (void *arg)
         break;
     }
 
-  close (closure->client_socket);
+  xclose (closure->client_socket);
   free (closure);
   return NULL;
 }
@@ -931,7 +933,7 @@ server_thread_tcp (struct resolv_test *obj, int server_index)
       if (obj->termination_requested)
         {
           xpthread_mutex_unlock (&obj->lock);
-          close (client_socket);
+          xclose (client_socket);
           break;
         }
       xpthread_mutex_unlock (&obj->lock);
@@ -991,8 +993,8 @@ make_server_sockets (struct resolv_test_server *server)
              next local UDP address randomly.  */
           if (errno == EADDRINUSE)
             {
-              close (server->socket_udp);
-              close (server->socket_tcp);
+              xclose (server->socket_udp);
+              xclose (server->socket_tcp);
               continue;
             }
           FAIL_EXIT1 ("TCP bind: %m");
@@ -1002,6 +1004,29 @@ make_server_sockets (struct resolv_test_server *server)
     }
 }
 
+/* Like make_server_sockets, but the caller supplies the address to
+   use.  */
+static void
+make_server_sockets_for_address (struct resolv_test_server *server,
+                                 const struct sockaddr *addr)
+{
+  server->socket_udp = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  server->socket_tcp = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+  if (addr->sa_family == AF_INET)
+    server->address = *(const struct sockaddr_in *) addr;
+  else
+    /* We cannot store the server address in the socket.  This should
+       not matter if disable_redirect is used.  */
+    server->address = (struct sockaddr_in) { .sin_family = 0, };
+
+  xbind (server->socket_udp,
+         (struct sockaddr *)&server->address, sizeof (server->address));
+  xbind (server->socket_tcp,
+         (struct sockaddr *)&server->address, sizeof (server->address));
+  xlisten (server->socket_tcp, 5);
+}
+
 /* One-time initialization of NSS.  */
 static void
 resolv_redirect_once (void)
@@ -1062,11 +1087,17 @@ resolv_test_start (struct resolv_redirect_config config)
     .lock = PTHREAD_MUTEX_INITIALIZER,
   };
 
-  resolv_test_init ();
+  if (!config.disable_redirect)
+    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);
+    if (config.disable_redirect && config.server_address_overrides != NULL)
+      make_server_sockets_for_address
+        (obj->servers + server_index,
+         config.server_address_overrides[server_index]);
+    else
+      make_server_sockets (obj->servers + server_index);
 
   /* Start server threads.  Disable the server ports, as
      requested.  */
@@ -1075,7 +1106,7 @@ resolv_test_start (struct resolv_redirect_config config)
       struct resolv_test_server *server = obj->servers + server_index;
       if (config.servers[server_index].disable_udp)
         {
-          close (server->socket_udp);
+          xclose (server->socket_udp);
           server->socket_udp = -1;
         }
       else if (!config.single_thread_udp)
@@ -1083,7 +1114,7 @@ resolv_test_start (struct resolv_redirect_config config)
                                                   server_thread_udp);
       if (config.servers[server_index].disable_tcp)
         {
-          close (server->socket_tcp);
+          xclose (server->socket_tcp);
           server->socket_tcp = -1;
         }
       else
@@ -1093,6 +1124,9 @@ resolv_test_start (struct resolv_redirect_config config)
   if (config.single_thread_udp)
     start_server_thread_udp_single (obj);
 
+  if (config.disable_redirect)
+    return obj;
+
   int timeout = 1;
 
   /* Initialize libresolv.  */
@@ -1127,6 +1161,7 @@ resolv_test_start (struct resolv_redirect_config config)
     }
   for (int server_index = 0; server_index < config.nscount; ++server_index)
     {
+      TEST_VERIFY_EXIT (obj->servers[server_index].address.sin_port != 0);
       _res.nsaddr_list[server_index] = obj->servers[server_index].address;
       if (test_verbose)
         {
@@ -1164,7 +1199,7 @@ resolv_test_end (struct resolv_test *obj)
           xsendto (sock, "", 1, 0,
                    (struct sockaddr *) &obj->servers[server_index].address,
                    sizeof (obj->servers[server_index].address));
-          close (sock);
+          xclose (sock);
         }
       if (!obj->config.servers[server_index].disable_tcp)
         {
@@ -1172,7 +1207,7 @@ resolv_test_end (struct resolv_test *obj)
           xconnect (sock,
                     (struct sockaddr *) &obj->servers[server_index].address,
                     sizeof (obj->servers[server_index].address));
-          close (sock);
+          xclose (sock);
         }
     }
 
@@ -1187,12 +1222,12 @@ resolv_test_end (struct resolv_test *obj)
         {
           if (!obj->config.single_thread_udp)
             xpthread_join (obj->servers[server_index].thread_udp);
-          close (obj->servers[server_index].socket_udp);
+          xclose (obj->servers[server_index].socket_udp);
         }
       if (!obj->config.servers[server_index].disable_tcp)
         {
           xpthread_join (obj->servers[server_index].thread_tcp);
-          close (obj->servers[server_index].socket_tcp);
+          xclose (obj->servers[server_index].socket_tcp);
         }
     }
 
index 6498751569f22319050705477a67f604652d8882..b953dc12000742465b75a2092f95c92718318ab5 100644 (file)
@@ -93,6 +93,16 @@ struct resolv_redirect_config
      may results in more predictable ordering of queries and
      responses.  */
   bool single_thread_udp;
+
+  /* Do not rewrite the _res variable or change NSS defaults.  Use
+     server_address_overrides below to tell the testing framework on
+     which addresses to create the servers.  */
+  bool disable_redirect;
+
+  /* Use these addresses for creating the DNS servers.  The array must
+     have ns_count (or resolv_max_test_servers) sockaddr * elements if
+     not NULL.  */
+  const struct sockaddr *const *server_address_overrides;
 };
 
 /* Configure NSS to use, nss_dns only for aplicable databases, and try
diff --git a/support/support-xstat.c b/support/support-xstat.c
new file mode 100644 (file)
index 0000000..86a81ec
--- /dev/null
@@ -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);
+}
index 7292e2a5645c66295be5c0bc3b5c56a7c753143b..4b5f04c2ccc2c419d5f77d685c5a6a24dc30c674 100644 (file)
@@ -44,6 +44,21 @@ void set_fortify_handler (void (*handler) (int sig));
 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.  */
 
diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c
new file mode 100644 (file)
index 0000000..0dfd2de
--- /dev/null
@@ -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 (file)
index 0000000..030f124
--- /dev/null
@@ -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 (file)
index 0000000..e1cf73b
--- /dev/null
@@ -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", proc->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_chroot.c b/support/support_chroot.c
new file mode 100644 (file)
index 0000000..c0807b3
--- /dev/null
@@ -0,0 +1,71 @@
+/* Setup a chroot environment for use within tests.
+   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 <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>
+
+struct support_chroot *
+support_chroot_create (struct support_chroot_configuration conf)
+{
+  struct support_chroot *chroot = xmalloc (sizeof (*chroot));
+
+  chroot->path_chroot = xasprintf ("%s/tst-resolv-res_init-XXXXXX", test_dir);
+  if (mkdtemp (chroot->path_chroot) == NULL)
+    FAIL_EXIT1 ("mkdtemp (\"%s\"): %m", chroot->path_chroot);
+  add_temp_file (chroot->path_chroot);
+
+  /* Create the /etc directory in the chroot environment.  */
+  char *path_etc = xasprintf ("%s/etc", chroot->path_chroot);
+  xmkdir (path_etc, 0777);
+  add_temp_file (path_etc);
+
+  if (conf.resolv_conf != NULL)
+    {
+      /* Create an empty resolv.conf file.  */
+      chroot->path_resolv_conf = xasprintf ("%s/resolv.conf", path_etc);
+      add_temp_file (chroot->path_resolv_conf);
+      support_write_file_string (chroot->path_resolv_conf, conf.resolv_conf);
+    }
+  else
+    chroot->path_resolv_conf = NULL;
+
+  free (path_etc);
+
+  /* valgrind needs a temporary directory in the chroot.  */
+  {
+    char *path_tmp = xasprintf ("%s/tmp", chroot->path_chroot);
+    xmkdir (path_tmp, 0777);
+    add_temp_file (path_tmp);
+    free (path_tmp);
+  }
+
+  return chroot;
+}
+
+void
+support_chroot_free (struct support_chroot *chroot)
+{
+  free (chroot->path_chroot);
+  free (chroot->path_resolv_conf);
+  free (chroot);
+}
index d2e78fe56083358d0f38e9f25f9bed0b27bb7b02..28b0ee29cffe00e44ba09ff57f65f2f3ed253c78 100644 (file)
 #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>
-#include <xsocket.h>
 
 static bool in_uts_namespace;
 
@@ -58,7 +59,7 @@ support_enter_network_namespace (void)
           req.ifr_flags |= IFF_UP | IFF_RUNNING;
           TEST_VERIFY_EXIT (ioctl (fd, SIOCSIFFLAGS, &req) == 0);
         }
-      close (fd);
+      xclose (fd);
 
       return !already_up;
     }
index 262e0df7379024afe8523615f77b1633ad121388..eedb0305911a46afbe5183fc7f82e83987e2fb2a 100644 (file)
@@ -39,8 +39,8 @@ socket_address_length (int family)
 }
 
 static void
-format_ai_flags (FILE *out, struct addrinfo *ai, int flag, const char *name,
-                 int * flags_printed)
+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);
@@ -48,14 +48,16 @@ format_ai_flags (FILE *out, struct addrinfo *ai, int flag, const char *name,
 }
 
 static void
-format_ai_one (FILE *out, struct addrinfo *ai, int *flags)
+format_ai_flags (FILE *out, struct addrinfo *ai)
 {
-  /* ai_flags */
-  if (ai->ai_flags != *flags)
+  if (ai == NULL)
+    return;
+
+  if (ai->ai_flags != 0)
     {
       fprintf (out, "flags:");
       int flags_printed = 0;
-#define FLAG(flag) format_ai_flags (out, ai, flag, #flag, &flags_printed)
+#define FLAG(flag) format_ai_flags_1 (out, ai, flag, #flag, &flags_printed)
       FLAG (AI_PASSIVE);
       FLAG (AI_CANONNAME);
       FLAG (AI_NUMERICHOST);
@@ -72,9 +74,47 @@ format_ai_one (FILE *out, struct addrinfo *ai, int *flags)
       if (remaining != 0)
         fprintf (out, " %08x", remaining);
       fprintf (out, "\n");
-      *flags = ai->ai_flags;
     }
 
+  /* 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;
@@ -156,20 +196,16 @@ format_ai_one (FILE *out, struct addrinfo *ai, int *flags)
     else
       fprintf (out, " %s %u\n", buf, ntohs (port));
   }
-
-  /* ai_canonname */
-  if (ai->ai_canonname != NULL)
-    fprintf (out, "canonname: %s\n", ai->ai_canonname);
 }
 
 /* Format all the addresses in one address family.  */
 static void
-format_ai_family (FILE *out, struct addrinfo *ai, int family, int *flags)
+format_ai_family (FILE *out, struct addrinfo *ai, int family)
 {
   while (ai)
     {
       if (ai->ai_family == family)
-        format_ai_one (out, ai, flags);
+        format_ai_one (out, ai);
       ai = ai->ai_next;
     }
 }
@@ -192,9 +228,10 @@ support_format_addrinfo (struct addrinfo *ai, int ret)
     }
   else
     {
-      int flags = 0;
-      format_ai_family (mem.out, ai, AF_INET, &flags);
-      format_ai_family (mem.out, ai, AF_INET6, &flags);
+      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);
index 21fe7e5c8df70a4aee8e103328e179e2ed6f6085..2992c579717e19da3ce24055b6d5de131c10e3c0 100644 (file)
@@ -174,7 +174,7 @@ support_format_dns_packet (const unsigned char *buffer, size_t length)
           goto out;
         }
       /* Skip non-matching record types.  */
-      if (rtype != qtype || rclass != qclass)
+      if ((rtype != qtype && rtype != T_CNAME) || rclass != qclass)
         continue;
       switch (rtype)
         {
@@ -186,22 +186,29 @@ support_format_dns_packet (const unsigned char *buffer, size_t length)
                        rdata.data[2],
                        rdata.data[3]);
           else
-            fprintf (mem.out, "error: A record of size %d: %s\n", rdlen, rname.name);
+            fprintf (mem.out, "error: A record of size %d: %s\n",
+                     rdlen, rname.name);
           break;
         case T_AAAA:
           {
-            char buf[100];
-            if (inet_ntop (AF_INET6, rdata.data, buf, sizeof (buf)) == NULL)
-              fprintf (mem.out, "error: AAAA record decoding failed: %m\n");
+            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, "address: %s\n", buf);
+              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, &in, &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");
diff --git a/support/support_isolate_in_subprocess.c b/support/support_isolate_in_subprocess.c
new file mode 100644 (file)
index 0000000..cf48614
--- /dev/null
@@ -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);
+}
index 3085037a69612010ce3edf0f82a656aa2d03615c..f5155de72749cacd89e780ab0c654a37f5dffa6a 100644 (file)
@@ -24,8 +24,8 @@
 #include <support/check.h>
 #include <support/support.h>
 #include <support/temp_file.h>
+#include <support/xunistd.h>
 #include <sys/wait.h>
-#include <xunistd.h>
 
 static char *
 write_to_temp_file (const char *prefix, const char *str)
@@ -36,7 +36,7 @@ write_to_temp_file (const char *prefix, const char *str)
   TEST_VERIFY_EXIT (fd >= 0);
   free (template);
   xwrite (fd, str, strlen (str));
-  TEST_VERIFY_EXIT (close (fd) == 0);
+  xclose (fd);
   return name;
 }
 
diff --git a/support/support_shared_allocate.c b/support/support_shared_allocate.c
new file mode 100644 (file)
index 0000000..61d088e
--- /dev/null
@@ -0,0 +1,57 @@
+/* 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>
+
+/* 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);
+}
index 914d64f6036aa152beaa84357433d85c3aacefb2..3c411a467b04f4dec279ddb84841d1d2f6d56e70 100644 (file)
@@ -211,7 +211,8 @@ support_test_main (int argc, char **argv, const struct test_config *config)
         mallopt (M_PERTURB, 42);
     }
 
-  while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1)
+  while ((opt = getopt_long (argc, argv, config->optstring, options, NULL))
+        != -1)
     switch (opt)
       {
       case '?':
index 5bae38f8b1b04e93a01b253d7ea64eedbc0b4126..55ab2111b3d0d7dcb032f8483d18cb1d45b12513 100644 (file)
 #include <stdlib.h>
 
 void
-support_test_verify_impl (int status, const char *file, int line,
-                          const char *expr)
+support_test_verify_impl (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);
+}
 
+void
+support_test_verify_exit_impl (int status, const char *file, int line,
+                               const char *expr)
+{
+  support_test_verify_impl (file, line, expr);
+  exit (status);
 }
diff --git a/support/support_write_file_string.c b/support/support_write_file_string.c
new file mode 100644 (file)
index 0000000..48e8959
--- /dev/null
@@ -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);
+}
index f06647a467fbf39809a25acb28c78a61d02c29be..fdb2477ab9e7dd3fe8851a2968a36ea75ec96c75 100644 (file)
 #include <support/support.h>
 
 #include <paths.h>
-#include <search.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 /* List of temporary files.  */
 static struct temp_name_list
 {
-  struct qelem q;
+  struct temp_name_list *next;
   char *name;
+  pid_t owner;
 } *temp_name_list;
 
 /* Location of the temporary files.  Set by the test skeleton via
@@ -50,10 +51,9 @@ add_temp_file (const char *name)
   if (newname != NULL)
     {
       newp->name = newname;
-      if (temp_name_list == NULL)
-       temp_name_list = (struct temp_name_list *) &newp->q;
-      else
-       insque (newp, temp_name_list);
+      newp->next = temp_name_list;
+      newp->owner = getpid ();
+      temp_name_list = newp;
     }
   else
     free (newp);
@@ -97,13 +97,22 @@ support_set_test_dir (const char *path)
 void
 support_delete_temp_files (void)
 {
+  pid_t pid = getpid ();
   while (temp_name_list != NULL)
     {
-      remove (temp_name_list->name);
+      /* 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
-       = (struct temp_name_list *) temp_name_list->q.q_forw;
+      struct temp_name_list *next = temp_name_list->next;
       free (temp_name_list);
       temp_name_list = next;
     }
@@ -116,9 +125,7 @@ support_print_temp_files (FILE *f)
     {
       struct temp_name_list *n;
       fprintf (f, "temp_files=(\n");
-      for (n = temp_name_list;
-           n != NULL;
-           n = (struct temp_name_list *) n->q.q_forw)
+      for (n = temp_name_list; n != NULL; n = n->next)
         fprintf (f, "  '%s'\n", n->name);
       fprintf (f, ")\n");
     }
index 482066dbeb326bb2b6518649128017e8be3b36e9..47c387c2b485bc8415a17b1ce56fb6f49769a58d 100644 (file)
    has this type:
 
      void CMDLINE_PROCESS (int);
+
+   If the program also to process custom default short command line
+   argument (similar to getopt) it must define CMDLINE_OPTSTRING
+   with the expected options (for instance "vb").
 */
 
 #include <support/test-driver.h>
@@ -151,6 +155,11 @@ main (int argc, char **argv)
 #ifdef CMDLINE_PROCESS
   test_config.cmdline_function = CMDLINE_PROCESS;
 #endif
+#ifdef CMDLINE_OPTSTRING
+  test_config.optstring = "+" CMDLINE_OPTSTRING;
+#else
+  test_config.optstring = "+";
+#endif
 
   return support_test_main (argc, argv, &test_config);
 }
index af1971a9ca10acaf235b86e0cc3d68b07eba64af..a8fe9c3565cddbe3b4fe054202742acafbc43179 100644 (file)
@@ -35,6 +35,7 @@ struct test_config
   int expected_status;   /* Expected exit status.  */
   int expected_signal;   /* If non-zero, expect termination by signal.  */
   char no_mallopt;       /* Boolean flag to disable mallopt.  */
+  const char *optstring; /* Short command line options.  */
 };
 
 enum
index a50b074f5e8e884bcc722c40c6cac0a7019c1435..dbe7cc07c8f8aaa4eb4701362468c5754cffaa7a 100644 (file)
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <errno.h>
+#include <netdb.h>
 #include <stdio.h>
+#include <support/check.h>
 #include <support/namespace.h>
+#include <support/xsocket.h>
+#include <support/xunistd.h>
+
+/* Check that the loopback interface provides multiple addresses which
+   can be used to run independent servers.  */
+static void
+test_localhost_bind (void)
+{
+  printf ("info: testing loopback interface with multiple addresses\n");
+
+  /* Create the two server addresses.  */
+  static const struct addrinfo hints =
+    {
+      .ai_family = AF_INET,
+      .ai_socktype = SOCK_DGRAM,
+      .ai_protocol = IPPROTO_UDP,
+    };
+  struct addrinfo *ai[3];
+  TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.1", "53", &hints, ai + 0) == 0);
+  TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.2", "53", &hints, ai + 1) == 0);
+  TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.3", "53", &hints, ai + 2) == 0);
+
+  /* Create the server scokets and bind them to these addresses.  */
+  int sockets[3];
+  for (int i = 0; i < 3; ++i)
+    {
+      sockets[i] = xsocket
+        (ai[i]->ai_family, ai[i]->ai_socktype, ai[i]->ai_protocol);
+      xbind (sockets[i], ai[i]->ai_addr, ai[i]->ai_addrlen);
+    }
+
+  /* Send two packets to each server.  */
+  int client = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  for (int i = 0; i < 3; ++i)
+    {
+      TEST_VERIFY (sendto (client, &i, sizeof (i), 0,
+                           ai[i]->ai_addr, ai[i]->ai_addrlen) == sizeof (i));
+      int j = i + 256;
+      TEST_VERIFY (sendto (client, &j, sizeof (j), 0,
+                           ai[i]->ai_addr, ai[i]->ai_addrlen) == sizeof (j));
+    }
+
+  /* Check that the packets can be received with the expected
+     contents.  Note that the receive calls interleave differently,
+     which hopefully proves that the sockets are, indeed,
+     independent.  */
+  for (int i = 0; i < 3; ++i)
+    {
+      int buf;
+      TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), 0) == sizeof (buf));
+      TEST_VERIFY (buf == i);
+    }
+  for (int i = 0; i < 3; ++i)
+    {
+      int buf;
+      TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), 0) == sizeof (buf));
+      TEST_VERIFY (buf == i + 256);
+      /* Check that there is no more data to receive.  */
+      TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), MSG_DONTWAIT) == -1);
+      TEST_VERIFY (errno == EWOULDBLOCK || errno == EAGAIN);
+    }
+
+  /* Close all sockets and free the addresses.  */
+  for (int i = 0; i < 3; ++i)
+    {
+      freeaddrinfo (ai[i]);
+      xclose (sockets[i]);
+    }
+  xclose (client);
+}
+
 
 static int
 do_test (void)
 {
-  if (support_become_root ())
+  bool root = support_become_root ();
+  if (root)
     printf ("info: acquired root-like privileges\n");
-  if (support_enter_network_namespace ())
+  bool netns = support_enter_network_namespace ();
+  if (netns)
     printf ("info: entered network namespace\n");
   if (support_in_uts_namespace ())
     printf ("info: also entered UTS namespace\n");
+
+  if (root && netns)
+    test_localhost_bind ();
+
   return 0;
 }
 
diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c
new file mode 100644 (file)
index 0000000..5672fba
--- /dev/null
@@ -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 (file)
index 0000000..9c8589c
--- /dev/null
@@ -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>
index 175137780a96e83cbef9f1839c740adfe02991f5..2c9372cc2916220e963baba0cc3e09105648e2c6 100644 (file)
@@ -37,7 +37,7 @@ run_test () {
     set -e
     echo "  exit status: $status"
     if test "$output" != "$expected_output" ; then
-       echo "error: unexpected ouput: $output"
+       echo "error: unexpected output: $output"
        exit 1
     fi
     if test "$status" -ne "$expected_status" ; then
@@ -52,9 +52,9 @@ different_status () {
     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:108: not true: false
+    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:108: not true: false
+    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
 }
@@ -62,8 +62,8 @@ error: 1 test failures" $direct --test-verify --verbose
 different_status
 different_status --direct
 
-run_test 1 "error: tst-support_record_failure.c:115: not true: false
+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:115: not true: false" \
+run_test 1 "error: tst-support_record_failure.c:116: not true: false" \
         --direct --test-verify-exit
index 62d8e1f0572da0abe5f3a86d864cb0b776e7a2b4..e739e739c399cb94449449bd14a465f23b4becc3 100644 (file)
@@ -25,6 +25,7 @@
 #include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
 
 static int exit_status_with_failure = -1;
 static bool test_verify;
diff --git a/support/xaccept4.c b/support/xaccept4.c
new file mode 100644 (file)
index 0000000..67dd95e
--- /dev/null
@@ -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/xchroot.c b/support/xchroot.c
new file mode 100644 (file)
index 0000000..abcc299
--- /dev/null
@@ -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 (file)
index 0000000..c931e08
--- /dev/null
@@ -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/xdup2.c b/support/xdup2.c
new file mode 100644 (file)
index 0000000..dc08c94
--- /dev/null
@@ -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/xmkdir.c b/support/xmkdir.c
new file mode 100644 (file)
index 0000000..ea17d49
--- /dev/null
@@ -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/xmprotect.c b/support/xmprotect.c
new file mode 100644 (file)
index 0000000..9410251
--- /dev/null
@@ -0,0 +1,28 @@
+/* mprotect 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/mman.h>
+
+void
+xmprotect (void *addr, size_t length, int prot)
+{
+  if (mprotect (addr, length, prot) != 0)
+    FAIL_EXIT1 ("mprotect (%p, %zu, 0x%x): %m", addr, length, prot);
+}
diff --git a/support/xopen.c b/support/xopen.c
new file mode 100644 (file)
index 0000000..7f033a0
--- /dev/null
@@ -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 (file)
index 0000000..89a64a5
--- /dev/null
@@ -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/xpthread_attr_setguardsize.c b/support/xpthread_attr_setguardsize.c
new file mode 100644 (file)
index 0000000..35fed5d
--- /dev/null
@@ -0,0 +1,26 @@
+/* pthread_attr_setguardsize 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_setguardsize (pthread_attr_t *attr, size_t guardsize)
+{
+  xpthread_check_return ("pthread_attr_setguardize",
+                        pthread_attr_setguardsize (attr, guardsize));
+}
diff --git a/support/xpthread_rwlock_init.c b/support/xpthread_rwlock_init.c
new file mode 100644 (file)
index 0000000..824288c
--- /dev/null
@@ -0,0 +1,27 @@
+/* pthread_rwlock_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_rwlock_init (pthread_rwlock_t *rwlock,
+                     const pthread_rwlockattr_t *attr)
+{
+  xpthread_check_return ("pthread_rwlock_init",
+                         pthread_rwlock_init (rwlock, attr));
+}
diff --git a/support/xpthread_rwlock_rdlock.c b/support/xpthread_rwlock_rdlock.c
new file mode 100644 (file)
index 0000000..96330a5
--- /dev/null
@@ -0,0 +1,26 @@
+/* pthread_rwlock_rdlock 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_rwlock_rdlock (pthread_rwlock_t *rwlock)
+{
+  xpthread_check_return ("pthread_rwlock_rdlock",
+                        pthread_rwlock_rdlock (rwlock));
+}
diff --git a/support/xpthread_rwlock_unlock.c b/support/xpthread_rwlock_unlock.c
new file mode 100644 (file)
index 0000000..eaa136b
--- /dev/null
@@ -0,0 +1,26 @@
+/* pthread_rwlock_unlock 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_rwlock_unlock (pthread_rwlock_t *rwlock)
+{
+  xpthread_check_return ("pthread_rwlock_unlock",
+                        pthread_rwlock_unlock (rwlock));
+}
diff --git a/support/xpthread_rwlock_wrlock.c b/support/xpthread_rwlock_wrlock.c
new file mode 100644 (file)
index 0000000..8d25d5b
--- /dev/null
@@ -0,0 +1,26 @@
+/* pthread_rwlock_wrlock 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_rwlock_wrlock (pthread_rwlock_t *rwlock)
+{
+  xpthread_check_return ("pthread_rwlock_wrlock",
+                        pthread_rwlock_wrlock (rwlock));
+}
diff --git a/support/xpthread_rwlockattr_init.c b/support/xpthread_rwlockattr_init.c
new file mode 100644 (file)
index 0000000..48baf24
--- /dev/null
@@ -0,0 +1,26 @@
+/* pthread_rwlockattr_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_rwlockattr_init (pthread_rwlockattr_t *attr)
+{
+  xpthread_check_return ("pthread_rwlockattr_init",
+                         pthread_rwlockattr_init (attr));
+}
diff --git a/support/xpthread_rwlockattr_setkind_np.c b/support/xpthread_rwlockattr_setkind_np.c
new file mode 100644 (file)
index 0000000..958aace
--- /dev/null
@@ -0,0 +1,27 @@
+/* pthread_rwlockattr_setkind_np 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_rwlockattr_setkind_np (pthread_rwlockattr_t *attr,
+                               int pref)
+{
+  xpthread_check_return ("pthread_rwlockattr_setkind_np",
+                         pthread_rwlockattr_setkind_np (attr, pref));
+}
index 0dbf13ace9d1b3f6b79318bffe35761a8f877d6d..d6724948d8a1f58a4c61c95162bc005d744ee722 100644 (file)
@@ -30,6 +30,7 @@ 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 *);
index 6dd7e709bec14eef86dbed2085e99aada1757ef1..472763ebe86cfef5e60738b24b915a0188ca4337 100644 (file)
@@ -67,11 +67,21 @@ void xpthread_attr_setdetachstate (pthread_attr_t *attr,
                                   int detachstate);
 void xpthread_attr_setstacksize (pthread_attr_t *attr,
                                 size_t stacksize);
+void xpthread_attr_setguardsize (pthread_attr_t *attr,
+                                size_t guardsize);
 
 /* This function returns non-zero if pthread_barrier_wait returned
    PTHREAD_BARRIER_SERIAL_THREAD.  */
 int xpthread_barrier_wait (pthread_barrier_t *barrier);
 
+void xpthread_rwlock_init (pthread_rwlock_t *rwlock,
+                         const pthread_rwlockattr_t *attr);
+void xpthread_rwlockattr_init (pthread_rwlockattr_t *attr);
+void xpthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref);
+void xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock);
+void xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock);
+void xpthread_rwlock_unlock (pthread_rwlock_t *rwlock);
+
 __END_DECLS
 
 #endif /* SUPPORT_THREAD_H */
index a83b1f4541fc3eec79d0148ceab66a45843fd0c7..c947bfd8fb8f443a49cac37945b29789db4ec539 100644 (file)
 #ifndef SUPPORT_XUNISTD_H
 #define SUPPORT_XUNISTD_H
 
-#include <unistd.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 xmprotect (void *addr, size_t length, int prot);
 void xmunmap (void *addr, size_t length);
 
 __END_DECLS