mirror of
https://sourceware.org/git/glibc.git
synced 2025-01-03 08:11:08 +00:00
resolv: Tests for various versions of res_init
This commit is contained in:
parent
673cb072a4
commit
2714c5f3c9
32
ChangeLog
32
ChangeLog
@ -1,3 +1,35 @@
|
||||
2017-06-02 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
Test res_init with several configuration files.
|
||||
* resolv/Makefile [build-shared] (tests-internal): Add
|
||||
tst-resolv-res_init, tst-resolv-res_init-thread.
|
||||
(tst-resolv-res_init): Link against libdl, libresolv.
|
||||
(tst-resolv-res_init-thread): Link against libdl, libresolv,
|
||||
libpthread.
|
||||
* resolv/tst-resolv-res_init.c: New file.
|
||||
* resolv/tst-resolv-res_init-skeleton.c: Likewise.
|
||||
* resolv/tst-resolv-res_init-thread.c: Likewise.
|
||||
* support/Makefile (libsupport-routines): Add support-xstat,
|
||||
support_can_chroot, support_capture_subprocess_check,
|
||||
support_isolate_in_subprocess, support_shared_allocate,
|
||||
support_write_file_string, xchroot, xmkdir, xopen.
|
||||
* support/capture_subprocess.h (enum support_capture_allow): Define.
|
||||
(support_capture_subprocess_check): Declare.
|
||||
* support/namespace.h (support_can_chroot)
|
||||
(support_isolate_in_subprocess): Declare.
|
||||
* support/support-xstat.c: New file.
|
||||
* support/support.h (support_shared_allocate, support_shared_free)
|
||||
(support_write_file_string): Declare.
|
||||
* support/support_can_chroot.c: New file.
|
||||
* support/support_capture_subprocess_check.c: Likewise.
|
||||
* support/support_isolate_in_subprocess.c: Likewise.
|
||||
* support/support_shared_allocate.c: Likewise.
|
||||
* support/support_write_file_string.c: Likewise.
|
||||
* support/xchroot.c: Likwise.
|
||||
* support/xmkdir.c: Likwise.
|
||||
* support/xopen.c: Likwise.
|
||||
* support/xunistd.h (xopen, xstat, xmkdir, xchroot): Declare.
|
||||
|
||||
2017-06-02 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* sysdeps/posix/getaddrinfo.c (getcanonname): New function.
|
||||
|
@ -57,6 +57,11 @@ ifeq (yes,$(build-shared))
|
||||
tests += \
|
||||
tst-resolv-canonname \
|
||||
|
||||
# uses DEPRECATED_RES_USE_INET6 from <resolv-internal.h>.
|
||||
tests-internal += \
|
||||
tst-resolv-res_init \
|
||||
tst-resolv-res_init-thread \
|
||||
|
||||
endif
|
||||
|
||||
# This test sends millions of packets and is rather slow.
|
||||
@ -136,6 +141,9 @@ $(objpfx)tst-res_use_inet6: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-res_init: $(libdl) $(objpfx)libresolv.so
|
||||
$(objpfx)tst-resolv-res_init-thread: $(libdl) $(objpfx)libresolv.so \
|
||||
$(shared-thread-library)
|
||||
$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
|
||||
$(objpfx)tst-resolv-canonname: \
|
||||
|
601
resolv/tst-resolv-res_init-skeleton.c
Normal file
601
resolv/tst-resolv-res_init-skeleton.c
Normal file
@ -0,0 +1,601 @@
|
||||
/* Test parsing of /etc/resolv.conf. Genric version.
|
||||
Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Before including this file, TEST_THREAD has to be defined to 0 or
|
||||
1, depending on whether the threading tests should be compiled
|
||||
in. */
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <gnu/lib-names.h>
|
||||
#include <netdb.h>
|
||||
#include <resolv/resolv-internal.h> /* For DEPRECATED_RES_USE_INET6. */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <support/capture_subprocess.h>
|
||||
#include <support/check.h>
|
||||
#include <support/namespace.h>
|
||||
#include <support/run_diff.h>
|
||||
#include <support/support.h>
|
||||
#include <support/temp_file.h>
|
||||
#include <support/test-driver.h>
|
||||
#include <support/xstdio.h>
|
||||
#include <support/xunistd.h>
|
||||
|
||||
#if TEST_THREAD
|
||||
# include <support/xthread.h>
|
||||
#endif
|
||||
|
||||
/* This is the host name used to ensure predictable behavior of
|
||||
res_init. */
|
||||
static const char *const test_hostname = "www.example.com";
|
||||
|
||||
/* Path to the test root directory. */
|
||||
static char *path_chroot;
|
||||
|
||||
/* Path to resolv.conf under path_chroot (outside the chroot). */
|
||||
static char *path_resolv_conf;
|
||||
|
||||
static void
|
||||
prepare (int argc, char **argv)
|
||||
{
|
||||
path_chroot = xasprintf ("%s/tst-resolv-res_init-XXXXXX", test_dir);
|
||||
if (mkdtemp (path_chroot) == NULL)
|
||||
FAIL_EXIT1 ("mkdtemp (\"%s\"): %m", path_chroot);
|
||||
add_temp_file (path_chroot);
|
||||
|
||||
/* Create the /etc directory in the chroot environment. */
|
||||
char *path_etc = xasprintf ("%s/etc", path_chroot);
|
||||
xmkdir (path_etc, 0777);
|
||||
add_temp_file (path_etc);
|
||||
|
||||
/* Create an empty resolv.conf file. */
|
||||
path_resolv_conf = xasprintf ("%s/resolv.conf", path_etc);
|
||||
add_temp_file (path_resolv_conf);
|
||||
support_write_file_string (path_resolv_conf, "");
|
||||
|
||||
free (path_etc);
|
||||
|
||||
/* valgrind needs a temporary directory in the chroot. */
|
||||
{
|
||||
char *path_tmp = xasprintf ("%s/tmp", path_chroot);
|
||||
xmkdir (path_tmp, 0777);
|
||||
add_temp_file (path_tmp);
|
||||
free (path_tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify that the chroot environment has been set up. */
|
||||
static void
|
||||
check_chroot_working (void *closure)
|
||||
{
|
||||
xchroot (path_chroot);
|
||||
FILE *fp = xfopen (_PATH_RESCONF, "r");
|
||||
xfclose (fp);
|
||||
|
||||
TEST_VERIFY_EXIT (res_init () == 0);
|
||||
TEST_VERIFY (_res.options & RES_INIT);
|
||||
|
||||
char buf[100];
|
||||
if (gethostname (buf, sizeof (buf)) < 0)
|
||||
FAIL_EXIT1 ("gethostname: %m");
|
||||
if (strcmp (buf, test_hostname) != 0)
|
||||
FAIL_EXIT1 ("unexpected host name: %s", buf);
|
||||
}
|
||||
|
||||
/* If FLAG is set in *OPTIONS, write NAME to FP, and clear it in
|
||||
*OPTIONS. */
|
||||
static void
|
||||
print_option_flag (FILE *fp, int *options, int flag, const char *name)
|
||||
{
|
||||
if (*options & flag)
|
||||
{
|
||||
fprintf (fp, " %s", name);
|
||||
*options &= ~flag;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write a decoded version of the resolver configuration *RESP to the
|
||||
stream FP. */
|
||||
static void
|
||||
print_resp (FILE *fp, res_state resp)
|
||||
{
|
||||
/* The options directive. */
|
||||
{
|
||||
/* RES_INIT is used internally for tracking initialization. */
|
||||
TEST_VERIFY (resp->options & RES_INIT);
|
||||
/* Also mask out other default flags which cannot be set through
|
||||
the options directive. */
|
||||
int options
|
||||
= resp->options & ~(RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH);
|
||||
if (options != 0
|
||||
|| resp->ndots != 1
|
||||
|| resp->retrans != RES_TIMEOUT
|
||||
|| resp->retry != RES_DFLRETRY)
|
||||
{
|
||||
fputs ("options", fp);
|
||||
if (resp->ndots != 1)
|
||||
fprintf (fp, " ndots:%d", resp->ndots);
|
||||
if (resp->retrans != RES_TIMEOUT)
|
||||
fprintf (fp, " timeout:%d", resp->retrans);
|
||||
if (resp->retry != RES_DFLRETRY)
|
||||
fprintf (fp, " attempts:%d", resp->retry);
|
||||
print_option_flag (fp, &options, RES_USEVC, "use-vc");
|
||||
print_option_flag (fp, &options, DEPRECATED_RES_USE_INET6, "inet6");
|
||||
print_option_flag (fp, &options, RES_ROTATE, "rotate");
|
||||
print_option_flag (fp, &options, RES_USE_EDNS0, "edns0");
|
||||
print_option_flag (fp, &options, RES_SNGLKUP,
|
||||
"single-request");
|
||||
print_option_flag (fp, &options, RES_SNGLKUPREOP,
|
||||
"single-request-reopen");
|
||||
print_option_flag (fp, &options, RES_NOTLDQUERY, "no-tld-query");
|
||||
fputc ('\n', fp);
|
||||
if (options != 0)
|
||||
fprintf (fp, "; error: unresolved option bits: 0x%x\n", options);
|
||||
}
|
||||
}
|
||||
|
||||
/* The search and domain directives. */
|
||||
if (resp->dnsrch[0] != NULL)
|
||||
{
|
||||
fputs ("search", fp);
|
||||
for (int i = 0; i < MAXDNSRCH && resp->dnsrch[i] != NULL; ++i)
|
||||
{
|
||||
fputc (' ', fp);
|
||||
fputs (resp->dnsrch[i], fp);
|
||||
}
|
||||
fputc ('\n', fp);
|
||||
}
|
||||
else if (resp->defdname[0] != '\0')
|
||||
fprintf (fp, "domain %s\n", resp->defdname);
|
||||
|
||||
/* The sortlist directive. */
|
||||
if (resp->nsort > 0)
|
||||
{
|
||||
fputs ("sortlist", fp);
|
||||
for (int i = 0; i < resp->nsort && i < MAXRESOLVSORT; ++i)
|
||||
{
|
||||
char net[20];
|
||||
if (inet_ntop (AF_INET, &resp->sort_list[i].addr,
|
||||
net, sizeof (net)) == NULL)
|
||||
FAIL_EXIT1 ("inet_ntop: %m\n");
|
||||
char mask[20];
|
||||
if (inet_ntop (AF_INET, &resp->sort_list[i].mask,
|
||||
mask, sizeof (mask)) == NULL)
|
||||
FAIL_EXIT1 ("inet_ntop: %m\n");
|
||||
fprintf (fp, " %s/%s", net, mask);
|
||||
}
|
||||
fputc ('\n', fp);
|
||||
}
|
||||
|
||||
/* The nameserver directives. */
|
||||
for (size_t i = 0; i < resp->nscount; ++i)
|
||||
{
|
||||
char host[NI_MAXHOST];
|
||||
char service[NI_MAXSERV];
|
||||
|
||||
/* See get_nsaddr in res_send.c. */
|
||||
void *addr;
|
||||
size_t addrlen;
|
||||
if (resp->nsaddr_list[i].sin_family == 0
|
||||
&& resp->_u._ext.nsaddrs[i] != NULL)
|
||||
{
|
||||
addr = resp->_u._ext.nsaddrs[i];
|
||||
addrlen = sizeof (*resp->_u._ext.nsaddrs[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = &resp->nsaddr_list[i];
|
||||
addrlen = sizeof (resp->nsaddr_list[i]);
|
||||
}
|
||||
|
||||
int ret = getnameinfo (addr, addrlen,
|
||||
host, sizeof (host), service, sizeof (service),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
if (ret != 0)
|
||||
{
|
||||
if (ret == EAI_SYSTEM)
|
||||
fprintf (fp, "; error: getnameinfo: %m\n");
|
||||
else
|
||||
fprintf (fp, "; error: getnameinfo: %s\n", gai_strerror (ret));
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (fp, "nameserver %s\n", host);
|
||||
if (strcmp (service, "53") != 0)
|
||||
fprintf (fp, "; unrepresentable port number %s\n\n", service);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_VERIFY (!ferror (fp));
|
||||
}
|
||||
|
||||
/* Parameters of one test case. */
|
||||
struct test_case
|
||||
{
|
||||
/* A short, descriptive name of the test. */
|
||||
const char *name;
|
||||
|
||||
/* The contents of the /etc/resolv.conf file. */
|
||||
const char *conf;
|
||||
|
||||
/* The expected output from print_resp. */
|
||||
const char *expected;
|
||||
|
||||
/* Setting for the LOCALDOMAIN environment variable. NULL if the
|
||||
variable is not to be set. */
|
||||
const char *localdomain;
|
||||
|
||||
/* Setting for the RES_OPTIONS environment variable. NULL if the
|
||||
variable is not to be set. */
|
||||
const char *res_options;
|
||||
};
|
||||
|
||||
enum test_init
|
||||
{
|
||||
test_init,
|
||||
test_ninit,
|
||||
test_mkquery,
|
||||
test_gethostbyname,
|
||||
test_getaddrinfo,
|
||||
test_init_method_last = test_getaddrinfo
|
||||
};
|
||||
|
||||
/* Closure argument for run_res_init. */
|
||||
struct test_context
|
||||
{
|
||||
enum test_init init;
|
||||
const struct test_case *t;
|
||||
};
|
||||
|
||||
static void
|
||||
setup_nss_dns_and_chroot (void)
|
||||
{
|
||||
/* Load nss_dns outside of the chroot. */
|
||||
if (dlopen (LIBNSS_DNS_SO, RTLD_LAZY) == NULL)
|
||||
FAIL_EXIT1 ("could not load " LIBNSS_DNS_SO ": %s", dlerror ());
|
||||
xchroot (path_chroot);
|
||||
/* Force the use of nss_dns. */
|
||||
__nss_configure_lookup ("hosts", "dns");
|
||||
}
|
||||
|
||||
/* Run res_ninit or res_init in a subprocess and dump the parsed
|
||||
resolver state to standard output. */
|
||||
static void
|
||||
run_res_init (void *closure)
|
||||
{
|
||||
struct test_context *ctx = closure;
|
||||
TEST_VERIFY (getenv ("LOCALDOMAIN") == NULL);
|
||||
TEST_VERIFY (getenv ("RES_OPTIONS") == NULL);
|
||||
if (ctx->t->localdomain != NULL)
|
||||
setenv ("LOCALDOMAIN", ctx->t->localdomain, 1);
|
||||
if (ctx->t->res_options != NULL)
|
||||
setenv ("RES_OPTIONS", ctx->t->res_options, 1);
|
||||
|
||||
switch (ctx->init)
|
||||
{
|
||||
case test_init:
|
||||
xchroot (path_chroot);
|
||||
TEST_VERIFY (res_init () == 0);
|
||||
print_resp (stdout, &_res);
|
||||
return;
|
||||
|
||||
case test_ninit:
|
||||
xchroot (path_chroot);
|
||||
res_state resp = xmalloc (sizeof (*resp));
|
||||
memset (resp, 0, sizeof (*resp));
|
||||
TEST_VERIFY (res_ninit (resp) == 0);
|
||||
print_resp (stdout, resp);
|
||||
res_nclose (resp);
|
||||
free (resp);
|
||||
return;
|
||||
|
||||
case test_mkquery:
|
||||
xchroot (path_chroot);
|
||||
unsigned char buf[512];
|
||||
TEST_VERIFY (res_mkquery (QUERY, "www.example",
|
||||
C_IN, ns_t_a, NULL, 0,
|
||||
NULL, buf, sizeof (buf)) > 0);
|
||||
print_resp (stdout, &_res);
|
||||
return;
|
||||
|
||||
case test_gethostbyname:
|
||||
setup_nss_dns_and_chroot ();
|
||||
/* Trigger implicit initialization of the _res structure. The
|
||||
actual lookup result is immaterial. */
|
||||
(void )gethostbyname ("www.example");
|
||||
print_resp (stdout, &_res);
|
||||
return;
|
||||
|
||||
case test_getaddrinfo:
|
||||
setup_nss_dns_and_chroot ();
|
||||
/* Trigger implicit initialization of the _res structure. The
|
||||
actual lookup result is immaterial. */
|
||||
struct addrinfo *ai;
|
||||
(void) getaddrinfo ("www.example", NULL, NULL, &ai);
|
||||
print_resp (stdout, &_res);
|
||||
return;
|
||||
}
|
||||
|
||||
FAIL_EXIT1 ("invalid init method %d", ctx->init);
|
||||
}
|
||||
|
||||
#if TEST_THREAD
|
||||
/* Helper function which calls run_res_init from a thread. */
|
||||
static void *
|
||||
run_res_init_thread_func (void *closure)
|
||||
{
|
||||
run_res_init (closure);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Variant of res_run_init which runs the function on a non-main
|
||||
thread. */
|
||||
static void
|
||||
run_res_init_on_thread (void *closure)
|
||||
{
|
||||
xpthread_join (xpthread_create (NULL, run_res_init_thread_func, closure));
|
||||
}
|
||||
#endif /* TEST_THREAD */
|
||||
|
||||
struct test_case test_cases[] =
|
||||
{
|
||||
{.name = "empty file",
|
||||
.conf = "",
|
||||
.expected = "search example.com\n"
|
||||
"nameserver 127.0.0.1\n"
|
||||
},
|
||||
{.name = "empty file with LOCALDOMAIN",
|
||||
.conf = "",
|
||||
.expected = "search example.net\n"
|
||||
"nameserver 127.0.0.1\n",
|
||||
.localdomain = "example.net",
|
||||
},
|
||||
{.name = "empty file with RES_OPTIONS",
|
||||
.conf = "",
|
||||
.expected = "options attempts:5 edns0\n"
|
||||
"search example.com\n"
|
||||
"nameserver 127.0.0.1\n",
|
||||
.res_options = "edns0 attempts:5",
|
||||
},
|
||||
{.name = "empty file with RES_OPTIONS and LOCALDOMAIN",
|
||||
.conf = "",
|
||||
.expected = "options attempts:5 edns0\n"
|
||||
"search example.org\n"
|
||||
"nameserver 127.0.0.1\n",
|
||||
.localdomain = "example.org",
|
||||
.res_options = "edns0 attempts:5",
|
||||
},
|
||||
{.name = "basic",
|
||||
.conf = "domain example.net\n"
|
||||
"search corp.example.com example.com\n"
|
||||
"nameserver 192.0.2.1\n",
|
||||
.expected = "search corp.example.com example.com\n"
|
||||
"nameserver 192.0.2.1\n"
|
||||
},
|
||||
{.name = "whitespace",
|
||||
.conf = "# This test covers comment and whitespace processing "
|
||||
" (trailing whitespace,\n"
|
||||
"# missing newline at end of file).\n"
|
||||
"\n"
|
||||
"domain example.net\n"
|
||||
";search commented out\n"
|
||||
"search corp.example.com\texample.com\n"
|
||||
"#nameserver 192.0.2.3\n"
|
||||
"nameserver 192.0.2.1 \n"
|
||||
"nameserver 192.0.2.2", /* No \n at end of file. */
|
||||
.expected = "search corp.example.com example.com\n"
|
||||
"nameserver 192.0.2.1\n"
|
||||
"nameserver 192.0.2.2\n"
|
||||
},
|
||||
{.name = "option values, multiple servers",
|
||||
.conf = "options\tinet6\tndots:3 edns0\tattempts:5\ttimeout:19\n"
|
||||
"domain example.net\n"
|
||||
";domain comment\n"
|
||||
"search corp.example.com\texample.com\n"
|
||||
"nameserver 192.0.2.1\n"
|
||||
"nameserver ::1\n"
|
||||
"nameserver 192.0.2.2\n",
|
||||
.expected = "options ndots:3 timeout:19 attempts:5 inet6 edns0\n"
|
||||
"search corp.example.com example.com\n"
|
||||
"nameserver 192.0.2.1\n"
|
||||
"nameserver ::1\n"
|
||||
"nameserver 192.0.2.2\n"
|
||||
},
|
||||
{.name = "out-of-range option vales",
|
||||
.conf = "options use-vc timeout:999 attempts:999 ndots:99\n"
|
||||
"search example.com\n",
|
||||
.expected = "options ndots:15 timeout:30 attempts:5 use-vc\n"
|
||||
"search example.com\n"
|
||||
"nameserver 127.0.0.1\n"
|
||||
},
|
||||
{.name = "repeated directives",
|
||||
.conf = "options ndots:3 use-vc\n"
|
||||
"options edns0 ndots:2\n"
|
||||
"domain corp.example\n"
|
||||
"search example.net corp.example.com example.com\n"
|
||||
"search example.org\n"
|
||||
"search\n",
|
||||
.expected = "options ndots:2 use-vc edns0\n"
|
||||
"search example.org\n"
|
||||
"nameserver 127.0.0.1\n"
|
||||
},
|
||||
{.name = "many name servers, sortlist",
|
||||
.conf = "options single-request\n"
|
||||
"search example.org example.com example.net corp.example.com\n"
|
||||
"sortlist 192.0.2.0/255.255.255.0\n"
|
||||
"nameserver 192.0.2.1\n"
|
||||
"nameserver 192.0.2.2\n"
|
||||
"nameserver 192.0.2.3\n"
|
||||
"nameserver 192.0.2.4\n"
|
||||
"nameserver 192.0.2.5\n"
|
||||
"nameserver 192.0.2.6\n"
|
||||
"nameserver 192.0.2.7\n"
|
||||
"nameserver 192.0.2.8\n",
|
||||
.expected = "options single-request\n"
|
||||
"search example.org example.com example.net corp.example.com\n"
|
||||
"sortlist 192.0.2.0/255.255.255.0\n"
|
||||
"nameserver 192.0.2.1\n"
|
||||
"nameserver 192.0.2.2\n"
|
||||
"nameserver 192.0.2.3\n"
|
||||
},
|
||||
{.name = "IPv4 and IPv6 nameservers",
|
||||
.conf = "options single-request\n"
|
||||
"search example.org example.com example.net corp.example.com"
|
||||
" legacy.example.com\n"
|
||||
"sortlist 192.0.2.0\n"
|
||||
"nameserver 192.0.2.1\n"
|
||||
"nameserver 2001:db8::2\n"
|
||||
"nameserver 192.0.2.3\n"
|
||||
"nameserver 2001:db8::4\n"
|
||||
"nameserver 192.0.2.5\n"
|
||||
"nameserver 2001:db8::6\n"
|
||||
"nameserver 192.0.2.7\n"
|
||||
"nameserver 2001:db8::8\n",
|
||||
.expected = "options single-request\n"
|
||||
"search example.org example.com example.net corp.example.com"
|
||||
" legacy.example.com\n"
|
||||
"sortlist 192.0.2.0/255.255.255.0\n"
|
||||
"nameserver 192.0.2.1\n"
|
||||
"nameserver 2001:db8::2\n"
|
||||
"nameserver 192.0.2.3\n"
|
||||
},
|
||||
{.name = "garbage after nameserver",
|
||||
.conf = "nameserver 192.0.2.1 garbage\n"
|
||||
"nameserver 192.0.2.2:5353\n"
|
||||
"nameserver 192.0.2.3 5353\n",
|
||||
.expected = "search example.com\n"
|
||||
"nameserver 192.0.2.1\n"
|
||||
"nameserver 192.0.2.3\n"
|
||||
},
|
||||
{.name = "RES_OPTIONS is cummulative",
|
||||
.conf = "options timeout:7 ndots:2 use-vc\n"
|
||||
"nameserver 192.0.2.1\n",
|
||||
.expected = "options ndots:3 timeout:7 attempts:5 use-vc edns0\n"
|
||||
"search example.com\n"
|
||||
"nameserver 192.0.2.1\n",
|
||||
.res_options = "attempts:5 ndots:3 edns0 ",
|
||||
},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* Run the indicated test case. This function assumes that the chroot
|
||||
contents has already been set up. */
|
||||
static void
|
||||
test_file_contents (const struct test_case *t)
|
||||
{
|
||||
#if TEST_THREAD
|
||||
for (int do_thread = 0; do_thread < 2; ++do_thread)
|
||||
#endif
|
||||
for (int init_method = 0; init_method <= test_init_method_last;
|
||||
++init_method)
|
||||
{
|
||||
if (test_verbose > 0)
|
||||
printf ("info: testing init method %d\n", init_method);
|
||||
struct test_context ctx = { .init = init_method, .t = t };
|
||||
void (*func) (void *) = run_res_init;
|
||||
#if TEST_THREAD
|
||||
if (do_thread)
|
||||
func = run_res_init_on_thread;
|
||||
#endif
|
||||
struct support_capture_subprocess proc
|
||||
= support_capture_subprocess (func, &ctx);
|
||||
if (strcmp (proc.out.buffer, t->expected) != 0)
|
||||
{
|
||||
support_record_failure ();
|
||||
printf ("error: output mismatch for %s\n", t->name);
|
||||
support_run_diff ("expected", t->expected,
|
||||
"actual", proc.out.buffer);
|
||||
}
|
||||
support_capture_subprocess_check (&proc, t->name, 0,
|
||||
sc_allow_stdout);
|
||||
support_capture_subprocess_free (&proc);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
support_become_root ();
|
||||
support_enter_network_namespace ();
|
||||
if (!support_in_uts_namespace () || !support_can_chroot ())
|
||||
return EXIT_UNSUPPORTED;
|
||||
|
||||
/* We are in an UTS namespace, so we can set the host name without
|
||||
altering the state of the entire system. */
|
||||
if (sethostname (test_hostname, strlen (test_hostname)) != 0)
|
||||
FAIL_EXIT1 ("sethostname: %m");
|
||||
|
||||
/* These environment variables affect resolv.conf parsing. */
|
||||
unsetenv ("LOCALDOMAIN");
|
||||
unsetenv ("RES_OPTIONS");
|
||||
|
||||
/* Ensure that the chroot setup worked. */
|
||||
{
|
||||
struct support_capture_subprocess proc
|
||||
= support_capture_subprocess (check_chroot_working, NULL);
|
||||
support_capture_subprocess_check (&proc, "chroot", 0, sc_allow_none);
|
||||
support_capture_subprocess_free (&proc);
|
||||
}
|
||||
|
||||
for (size_t i = 0; test_cases[i].name != NULL; ++i)
|
||||
{
|
||||
if (test_verbose > 0)
|
||||
printf ("info: running test: %s\n", test_cases[i].name);
|
||||
TEST_VERIFY (test_cases[i].conf != NULL);
|
||||
TEST_VERIFY (test_cases[i].expected != NULL);
|
||||
|
||||
support_write_file_string (path_resolv_conf, test_cases[i].conf);
|
||||
|
||||
test_file_contents (&test_cases[i]);
|
||||
|
||||
/* The expected output from the empty file test is used for
|
||||
further tests. */
|
||||
if (test_cases[i].conf[0] == '\0')
|
||||
{
|
||||
if (test_verbose > 0)
|
||||
printf ("info: special test: missing file\n");
|
||||
TEST_VERIFY (unlink (path_resolv_conf) == 0);
|
||||
test_file_contents (&test_cases[i]);
|
||||
|
||||
if (test_verbose > 0)
|
||||
printf ("info: special test: dangling symbolic link\n");
|
||||
TEST_VERIFY (symlink ("does-not-exist", path_resolv_conf) == 0);
|
||||
test_file_contents (&test_cases[i]);
|
||||
TEST_VERIFY (unlink (path_resolv_conf) == 0);
|
||||
|
||||
if (test_verbose > 0)
|
||||
printf ("info: special test: unreadable file\n");
|
||||
support_write_file_string (path_resolv_conf, "");
|
||||
TEST_VERIFY (chmod (path_resolv_conf, 0) == 0);
|
||||
test_file_contents (&test_cases[i]);
|
||||
|
||||
/* Restore the empty file. */
|
||||
TEST_VERIFY (unlink (path_resolv_conf) == 0);
|
||||
support_write_file_string (path_resolv_conf, "");
|
||||
}
|
||||
}
|
||||
|
||||
free (path_chroot);
|
||||
path_chroot = NULL;
|
||||
free (path_resolv_conf);
|
||||
path_resolv_conf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PREPARE prepare
|
||||
#include <support/test-driver.c>
|
20
resolv/tst-resolv-res_init-thread.c
Normal file
20
resolv/tst-resolv-res_init-thread.c
Normal file
@ -0,0 +1,20 @@
|
||||
/* Test parsing of /etc/resolv.conf, threading version.
|
||||
Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#define TEST_THREAD 1
|
||||
#include "tst-resolv-res_init-skeleton.c"
|
20
resolv/tst-resolv-res_init.c
Normal file
20
resolv/tst-resolv-res_init.c
Normal file
@ -0,0 +1,20 @@
|
||||
/* Test parsing of /etc/resolv.conf, non-threading version.
|
||||
Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#define TEST_THREAD 0
|
||||
#include "tst-resolv-res_init-skeleton.c"
|
@ -35,8 +35,11 @@ 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_enter_network_namespace \
|
||||
support_format_address_family \
|
||||
support_format_addrinfo \
|
||||
@ -44,8 +47,11 @@ 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 \
|
||||
@ -55,6 +61,7 @@ libsupport-routines = \
|
||||
xasprintf \
|
||||
xbind \
|
||||
xcalloc \
|
||||
xchroot \
|
||||
xclose \
|
||||
xconnect \
|
||||
xdup2 \
|
||||
@ -65,8 +72,10 @@ libsupport-routines = \
|
||||
xlisten \
|
||||
xmalloc \
|
||||
xmemstream \
|
||||
xmkdir \
|
||||
xmmap \
|
||||
xmunmap \
|
||||
xopen \
|
||||
xpipe \
|
||||
xpoll \
|
||||
xpthread_attr_destroy \
|
||||
|
@ -39,4 +39,23 @@ struct support_capture_subprocess support_capture_subprocess
|
||||
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 */
|
||||
|
@ -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,11 @@ 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);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
|
30
support/support-xstat.c
Normal file
30
support/support-xstat.c
Normal 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);
|
||||
}
|
@ -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. */
|
||||
|
||||
|
65
support/support_can_chroot.c
Normal file
65
support/support_can_chroot.c
Normal 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;
|
||||
}
|
67
support/support_capture_subprocess_check.c
Normal file
67
support/support_capture_subprocess_check.c
Normal 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", 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");
|
||||
}
|
||||
}
|
38
support/support_isolate_in_subprocess.c
Normal file
38
support/support_isolate_in_subprocess.c
Normal 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);
|
||||
}
|
57
support/support_shared_allocate.c
Normal file
57
support/support_shared_allocate.c
Normal 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);
|
||||
}
|
39
support/support_write_file_string.c
Normal file
39
support/support_write_file_string.c
Normal 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);
|
||||
}
|
28
support/xchroot.c
Normal file
28
support/xchroot.c
Normal 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/xmkdir.c
Normal file
28
support/xmkdir.c
Normal 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);
|
||||
}
|
30
support/xopen.c
Normal file
30
support/xopen.c
Normal 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;
|
||||
}
|
@ -22,15 +22,22 @@
|
||||
#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. */
|
||||
|
Loading…
Reference in New Issue
Block a user