--- /dev/null
+#!/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
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 \
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 \
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 \
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 \
tests = \
README-testing \
tst-support-namespace \
+ tst-support_capture_subprocess \
+ tst-support_format_dns_packet \
tst-support_record_failure \
ifeq ($(run-built-tests),yes)
$(evaluate-test)
endif
+$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so
+
include ../Rules
--- /dev/null
+/* 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 */
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. */
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,
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
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.
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
#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
{
break;
}
- close (closure->client_socket);
+ xclose (closure->client_socket);
free (closure);
return NULL;
}
if (obj->termination_requested)
{
xpthread_mutex_unlock (&obj->lock);
- close (client_socket);
+ xclose (client_socket);
break;
}
xpthread_mutex_unlock (&obj->lock);
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");
}
}
+/* 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)
.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. */
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)
server_thread_udp);
if (config.servers[server_index].disable_tcp)
{
- close (server->socket_tcp);
+ xclose (server->socket_tcp);
server->socket_tcp = -1;
}
else
if (config.single_thread_udp)
start_server_thread_udp_single (obj);
+ if (config.disable_redirect)
+ return obj;
+
int timeout = 1;
/* Initialize libresolv. */
}
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)
{
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)
{
xconnect (sock,
(struct sockaddr *) &obj->servers[server_index].address,
sizeof (obj->servers[server_index].address));
- close (sock);
+ xclose (sock);
}
}
{
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);
}
}
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
--- /dev/null
+/* 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);
+}
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. */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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");
+ }
+}
--- /dev/null
+/* 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);
+}
#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;
req.ifr_flags |= IFF_UP | IFF_RUNNING;
TEST_VERIFY_EXIT (ioctl (fd, SIOCSIFFLAGS, &req) == 0);
}
- close (fd);
+ xclose (fd);
return !already_up;
}
}
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);
}
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);
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;
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;
}
}
}
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);
goto out;
}
/* Skip non-matching record types. */
- if (rtype != qtype || rclass != qclass)
+ if ((rtype != qtype && rtype != T_CNAME) || rclass != qclass)
continue;
switch (rtype)
{
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");
--- /dev/null
+/* 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);
+}
#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)
TEST_VERIFY_EXIT (fd >= 0);
free (template);
xwrite (fd, str, strlen (str));
- TEST_VERIFY_EXIT (close (fd) == 0);
+ xclose (fd);
return name;
}
--- /dev/null
+/* 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);
+}
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 '?':
#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);
}
--- /dev/null
+/* 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);
+}
#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
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);
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;
}
{
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");
}
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>
#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);
}
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
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;
}
--- /dev/null
+/* 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>
--- /dev/null
+/* 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>
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
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
}
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
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
static int exit_status_with_failure = -1;
static bool test_verify;
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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");
+}
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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));
+}
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 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 */
#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