Synchronize support/ infrastructure with master

This commit updates the support/ subdirectory to
commit faf8c066df
on the master branch.
This commit is contained in:
Florian Weimer 2017-08-28 14:38:52 +02:00
parent 02aaa3c749
commit 92a0e0c617
48 changed files with 1726 additions and 70 deletions

110
scripts/backport-support.sh Normal file
View File

@ -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

View 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

View File

@ -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 */

View 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

View 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

View File

@ -32,9 +32,11 @@
#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);
}
}

View 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

30
support/support-xstat.c Normal file
View File

@ -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);
}

View 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. */

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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");
}
}

71
support/support_chroot.c Normal file
View File

@ -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);
}

View File

@ -23,9 +23,10 @@
#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;
}

View 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);

View 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");

View File

@ -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);
}

View 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;
}

View File

@ -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);
}

View 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 '?':

View File

@ -22,12 +22,16 @@
#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);
}

View File

@ -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);
}

View File

@ -25,16 +25,17 @@
#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");
}

View File

@ -93,6 +93,10 @@
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);
}

View 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

View File

@ -16,18 +16,98 @@
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;
}

View File

@ -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>

View File

@ -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>

View 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

View 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;

32
support/xaccept4.c Normal file
View File

@ -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;
}

28
support/xchroot.c Normal file
View File

@ -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);
}

28
support/xclose.c Normal file
View File

@ -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);
}

28
support/xdup2.c Normal file
View File

@ -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);
}

28
support/xmkdir.c Normal file
View File

@ -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);
}

28
support/xmprotect.c Normal file
View File

@ -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);
}

30
support/xopen.c Normal file
View File

@ -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;
}

28
support/xpipe.c Normal file
View File

@ -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");
}

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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));
}

View 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 *);

View 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 */

View File

@ -22,20 +22,33 @@
#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