/* Test parsing of /etc/resolv.conf. Genric version.
- Copyright (C) 2017 Free Software Foundation, Inc.
+ Copyright (C) 2017-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
#include <errno.h>
#include <gnu/lib-names.h>
#include <netdb.h>
-#include <resolv/resolv-internal.h> /* For DEPRECATED_RES_USE_INET6. */
+#include <resolv/resolv_context.h>
#include <stdio.h>
#include <stdlib.h>
#include <support/capture_subprocess.h>
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;
+struct support_chroot *chroot_env;
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);
- }
+ chroot_env = support_chroot_create
+ ((struct support_chroot_configuration)
+ {
+ .resolv_conf = "",
+ });
}
/* Verify that the chroot environment has been set up. */
static void
check_chroot_working (void *closure)
{
- xchroot (path_chroot);
+ xchroot (chroot_env->path_chroot);
FILE *fp = xfopen (_PATH_RESCONF, "r");
xfclose (fp);
static void
print_resp (FILE *fp, res_state resp)
{
+ struct resolv_context *ctx = __resolv_context_get_override (resp);
+ TEST_VERIFY_EXIT (ctx != NULL);
+ if (ctx->conf == NULL)
+ fprintf (fp, "; extended resolver state missing\n");
+
/* The options directive. */
{
/* RES_INIT is used internally for tracking initialization. */
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,
print_option_flag (fp, &options, RES_SNGLKUPREOP,
"single-request-reopen");
print_option_flag (fp, &options, RES_NOTLDQUERY, "no-tld-query");
+ print_option_flag (fp, &options, RES_NORELOAD, "no-reload");
fputc ('\n', fp);
if (options != 0)
fprintf (fp, "; error: unresolved option bits: 0x%x\n", options);
else if (resp->defdname[0] != '\0')
fprintf (fp, "domain %s\n", resp->defdname);
+ /* The extended search path. */
+ {
+ size_t i = 0;
+ while (true)
+ {
+ const char *name = __resolv_context_search_list (ctx, i);
+ if (name == NULL)
+ break;
+ fprintf (fp, "; search[%zu]: %s\n", i, name);
+ ++i;
+ }
+ }
+
/* The sortlist directive. */
if (resp->nsort > 0)
{
}
}
+ /* The extended name server list. */
+ {
+ size_t i = 0;
+ while (true)
+ {
+ const struct sockaddr *addr = __resolv_context_nameserver (ctx, i);
+ if (addr == NULL)
+ break;
+ size_t addrlen;
+ switch (addr->sa_family)
+ {
+ case AF_INET:
+ addrlen = sizeof (struct sockaddr_in);
+ break;
+ case AF_INET6:
+ addrlen = sizeof (struct sockaddr_in6);
+ break;
+ default:
+ FAIL_EXIT1 ("invalid address family %d", addr->sa_family);
+ }
+
+ char host[NI_MAXHOST];
+ char service[NI_MAXSERV];
+ 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[%zu]: [%s]:%s\n", i, host, service);
+ ++i;
+ }
+ }
+
TEST_VERIFY (!ferror (fp));
+
+ __resolv_context_put (ctx);
}
/* Parameters of one test case. */
/* Setting for the RES_OPTIONS environment variable. NULL if the
variable is not to be set. */
const char *res_options;
+
+ /* Override the system host name. NULL means that no change is made
+ and the default is used (test_hostname). */
+ const char *hostname;
};
enum test_init
test_init_method_last = test_getaddrinfo
};
+static const char *const test_init_names[] =
+ {
+ [test_init] = "res_init",
+ [test_ninit] = "res_ninit",
+ [test_mkquery] = "res_mkquery",
+ [test_gethostbyname] = "gethostbyname",
+ [test_getaddrinfo] = "getaddrinfo",
+ };
+
/* Closure argument for run_res_init. */
struct test_context
{
/* 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);
+ xchroot (chroot_env->path_chroot);
/* Force the use of nss_dns. */
__nss_configure_lookup ("hosts", "dns");
}
setenv ("LOCALDOMAIN", ctx->t->localdomain, 1);
if (ctx->t->res_options != NULL)
setenv ("RES_OPTIONS", ctx->t->res_options, 1);
+ if (ctx->t->hostname != NULL)
+ {
+#ifdef CLONE_NEWUTS
+ /* This test needs its own namespace, to avoid changing the host
+ name for the parent, too. */
+ TEST_VERIFY_EXIT (unshare (CLONE_NEWUTS) == 0);
+ if (sethostname (ctx->t->hostname, strlen (ctx->t->hostname)) != 0)
+ FAIL_EXIT1 ("sethostname (\"%s\"): %m", ctx->t->hostname);
+#else
+ FAIL_UNSUPPORTED ("clone (CLONE_NEWUTS) not supported");
+#endif
+ }
switch (ctx->init)
{
case test_init:
- xchroot (path_chroot);
+ xchroot (chroot_env->path_chroot);
TEST_VERIFY (res_init () == 0);
print_resp (stdout, &_res);
return;
case test_ninit:
- xchroot (path_chroot);
+ xchroot (chroot_env->path_chroot);
res_state resp = xmalloc (sizeof (*resp));
memset (resp, 0, sizeof (*resp));
TEST_VERIFY (res_ninit (resp) == 0);
return;
case test_mkquery:
- xchroot (path_chroot);
+ xchroot (chroot_env->path_chroot);
unsigned char buf[512];
TEST_VERIFY (res_mkquery (QUERY, "www.example",
C_IN, ns_t_a, NULL, 0,
{.name = "empty file",
.conf = "",
.expected = "search example.com\n"
+ "; search[0]: example.com\n"
"nameserver 127.0.0.1\n"
+ "; nameserver[0]: [127.0.0.1]:53\n"
+ },
+ {.name = "empty file, no-dot hostname",
+ .conf = "",
+ .expected = "nameserver 127.0.0.1\n"
+ "; nameserver[0]: [127.0.0.1]:53\n",
+ .hostname = "example",
},
{.name = "empty file with LOCALDOMAIN",
.conf = "",
.expected = "search example.net\n"
- "nameserver 127.0.0.1\n",
+ "; search[0]: example.net\n"
+ "nameserver 127.0.0.1\n"
+ "; nameserver[0]: [127.0.0.1]:53\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",
+ "; search[0]: example.com\n"
+ "nameserver 127.0.0.1\n"
+ "; nameserver[0]: [127.0.0.1]:53\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",
+ "; search[0]: example.org\n"
+ "nameserver 127.0.0.1\n"
+ "; nameserver[0]: [127.0.0.1]:53\n",
.localdomain = "example.org",
.res_options = "edns0 attempts:5",
},
{.name = "basic",
- .conf = "domain example.net\n"
- "search corp.example.com example.com\n"
+ .conf = "search corp.example.com example.com\n"
+ "nameserver 192.0.2.1\n",
+ .expected = "search corp.example.com example.com\n"
+ "; search[0]: corp.example.com\n"
+ "; search[1]: example.com\n"
+ "nameserver 192.0.2.1\n"
+ "; nameserver[0]: [192.0.2.1]:53\n"
+ },
+ {.name = "basic with no-dot hostname",
+ .conf = "search corp.example.com example.com\n"
"nameserver 192.0.2.1\n",
.expected = "search corp.example.com example.com\n"
+ "; search[0]: corp.example.com\n"
+ "; search[1]: example.com\n"
+ "nameserver 192.0.2.1\n"
+ "; nameserver[0]: [192.0.2.1]:53\n",
+ .hostname = "example",
+ },
+ {.name = "basic no-reload",
+ .conf = "options no-reload\n"
+ "search corp.example.com example.com\n"
+ "nameserver 192.0.2.1\n",
+ .expected = "options no-reload\n"
+ "search corp.example.com example.com\n"
+ "; search[0]: corp.example.com\n"
+ "; search[1]: example.com\n"
"nameserver 192.0.2.1\n"
+ "; nameserver[0]: [192.0.2.1]:53\n"
+ },
+ {.name = "basic no-reload via RES_OPTIONS",
+ .conf = "search corp.example.com example.com\n"
+ "nameserver 192.0.2.1\n",
+ .expected = "options no-reload\n"
+ "search corp.example.com example.com\n"
+ "; search[0]: corp.example.com\n"
+ "; search[1]: example.com\n"
+ "nameserver 192.0.2.1\n"
+ "; nameserver[0]: [192.0.2.1]:53\n",
+ .res_options = "no-reload"
},
{.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"
+ "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"
+ "; search[0]: corp.example.com\n"
+ "; search[1]: example.com\n"
"nameserver 192.0.2.1\n"
"nameserver 192.0.2.2\n"
+ "; nameserver[0]: [192.0.2.1]:53\n"
+ "; nameserver[1]: [192.0.2.2]:53\n"
+ },
+ {.name = "domain",
+ .conf = "domain example.net\n"
+ "nameserver 192.0.2.1\n",
+ .expected = "search example.net\n"
+ "; search[0]: example.net\n"
+ "nameserver 192.0.2.1\n"
+ "; nameserver[0]: [192.0.2.1]:53\n"
+ },
+ {.name = "domain space",
+ .conf = "domain example.net \n"
+ "nameserver 192.0.2.1\n",
+ .expected = "search example.net\n"
+ "; search[0]: example.net\n"
+ "nameserver 192.0.2.1\n"
+ "; nameserver[0]: [192.0.2.1]:53\n"
+ },
+ {.name = "domain tab",
+ .conf = "domain example.net\t\n"
+ "nameserver 192.0.2.1\n",
+ .expected = "search example.net\n"
+ "; search[0]: example.net\n"
+ "nameserver 192.0.2.1\n"
+ "; nameserver[0]: [192.0.2.1]:53\n"
+ },
+ {.name = "domain override",
+ .conf = "search example.com example.org\n"
+ "nameserver 192.0.2.1\n"
+ "domain example.net", /* No \n at end of file. */
+ .expected = "search example.net\n"
+ "; search[0]: example.net\n"
+ "nameserver 192.0.2.1\n"
+ "; nameserver[0]: [192.0.2.1]:53\n"
},
{.name = "option values, multiple servers",
.conf = "options\tinet6\tndots:3 edns0\tattempts:5\ttimeout:19\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"
+ .expected = "options ndots:3 timeout:19 attempts:5 edns0\n"
"search corp.example.com example.com\n"
+ "; search[0]: corp.example.com\n"
+ "; search[1]: example.com\n"
"nameserver 192.0.2.1\n"
"nameserver ::1\n"
"nameserver 192.0.2.2\n"
+ "; nameserver[0]: [192.0.2.1]:53\n"
+ "; nameserver[1]: [::1]:53\n"
+ "; nameserver[2]: [192.0.2.2]:53\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"
+ "; search[0]: example.com\n"
"nameserver 127.0.0.1\n"
+ "; nameserver[0]: [127.0.0.1]:53\n"
},
{.name = "repeated directives",
.conf = "options ndots:3 use-vc\n"
"search\n",
.expected = "options ndots:2 use-vc edns0\n"
"search example.org\n"
+ "; search[0]: example.org\n"
"nameserver 127.0.0.1\n"
+ "; nameserver[0]: [127.0.0.1]:53\n"
},
{.name = "many name servers, sortlist",
.conf = "options single-request\n"
"nameserver 192.0.2.8\n",
.expected = "options single-request\n"
"search example.org example.com example.net corp.example.com\n"
+ "; search[0]: example.org\n"
+ "; search[1]: example.com\n"
+ "; search[2]: example.net\n"
+ "; search[3]: 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[0]: [192.0.2.1]:53\n"
+ "; nameserver[1]: [192.0.2.2]:53\n"
+ "; nameserver[2]: [192.0.2.3]:53\n"
+ "; nameserver[3]: [192.0.2.4]:53\n"
+ "; nameserver[4]: [192.0.2.5]:53\n"
+ "; nameserver[5]: [192.0.2.6]:53\n"
+ "; nameserver[6]: [192.0.2.7]:53\n"
+ "; nameserver[7]: [192.0.2.8]:53\n"
},
{.name = "IPv4 and IPv6 nameservers",
.conf = "options single-request\n"
.expected = "options single-request\n"
"search example.org example.com example.net corp.example.com"
" legacy.example.com\n"
+ "; search[0]: example.org\n"
+ "; search[1]: example.com\n"
+ "; search[2]: example.net\n"
+ "; search[3]: corp.example.com\n"
+ "; search[4]: 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"
+ "; nameserver[0]: [192.0.2.1]:53\n"
+ "; nameserver[1]: [2001:db8::2]:53\n"
+ "; nameserver[2]: [192.0.2.3]:53\n"
+ "; nameserver[3]: [2001:db8::4]:53\n"
+ "; nameserver[4]: [192.0.2.5]:53\n"
+ "; nameserver[5]: [2001:db8::6]:53\n"
+ "; nameserver[6]: [192.0.2.7]:53\n"
+ "; nameserver[7]: [2001:db8::8]:53\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"
+ "; search[0]: example.com\n"
"nameserver 192.0.2.1\n"
"nameserver 192.0.2.3\n"
+ "; nameserver[0]: [192.0.2.1]:53\n"
+ "; nameserver[1]: [192.0.2.3]:53\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",
+ "; search[0]: example.com\n"
+ "nameserver 192.0.2.1\n"
+ "; nameserver[0]: [192.0.2.1]:53\n",
.res_options = "attempts:5 ndots:3 edns0 ",
},
+ {.name = "many search list entries (bug 19569)",
+ .conf = "nameserver 192.0.2.1\n"
+ "search corp.example.com support.example.com"
+ " community.example.org wan.example.net vpn.example.net"
+ " example.com example.org example.net\n",
+ .expected = "search corp.example.com support.example.com"
+ " community.example.org wan.example.net vpn.example.net example.com\n"
+ "; search[0]: corp.example.com\n"
+ "; search[1]: support.example.com\n"
+ "; search[2]: community.example.org\n"
+ "; search[3]: wan.example.net\n"
+ "; search[4]: vpn.example.net\n"
+ "; search[5]: example.com\n"
+ "; search[6]: example.org\n"
+ "; search[7]: example.net\n"
+ "nameserver 192.0.2.1\n"
+ "; nameserver[0]: [192.0.2.1]:53\n"
+ },
+ {.name = "very long search list entries (bug 21475)",
+ .conf = "nameserver 192.0.2.1\n"
+ "search example.com "
+#define H63 "this-host-name-is-longer-than-yours-yes-I-really-really-mean-it"
+#define D63 "this-domain-name-is-as-long-as-the-previous-name--63-characters"
+ " " H63 "." D63 ".example.org"
+ " " H63 "." D63 ".example.net\n",
+ .expected = "search example.com " H63 "." D63 ".example.org\n"
+ "; search[0]: example.com\n"
+ "; search[1]: " H63 "." D63 ".example.org\n"
+ "; search[2]: " H63 "." D63 ".example.net\n"
+#undef H63
+#undef D63
+ "nameserver 192.0.2.1\n"
+ "; nameserver[0]: [192.0.2.1]:53\n"
+ },
{ NULL }
};
++init_method)
{
if (test_verbose > 0)
- printf ("info: testing init method %d\n", init_method);
+ printf ("info: testing init method %s\n",
+ test_init_names[init_method]);
struct test_context ctx = { .init = init_method, .t = t };
void (*func) (void *) = run_res_init;
#if TEST_THREAD
if (strcmp (proc.out.buffer, t->expected) != 0)
{
support_record_failure ();
- printf ("error: output mismatch for %s\n", t->name);
+ printf ("error: output mismatch for %s (init method %s)\n",
+ t->name, test_init_names[init_method]);
support_run_diff ("expected", t->expected,
"actual", proc.out.buffer);
}
}
}
+/* Special tests which do not follow the general pattern. */
+enum { special_tests_count = 11 };
+
+/* Implementation of special tests. */
+static void
+special_test_callback (void *closure)
+{
+ unsigned int *test_indexp = closure;
+ unsigned test_index = *test_indexp;
+ TEST_VERIFY (test_index < special_tests_count);
+ if (test_verbose > 0)
+ printf ("info: special test %u\n", test_index);
+ xchroot (chroot_env->path_chroot);
+
+ switch (test_index)
+ {
+ case 0:
+ case 1:
+ /* Second res_init with missing or empty file preserves
+ flags. */
+ if (test_index == 1)
+ TEST_VERIFY (unlink (_PATH_RESCONF) == 0);
+ _res.options = RES_USE_EDNS0;
+ TEST_VERIFY (res_init () == 0);
+ /* First res_init clears flag. */
+ TEST_VERIFY (!(_res.options & RES_USE_EDNS0));
+ _res.options |= RES_USE_EDNS0;
+ TEST_VERIFY (res_init () == 0);
+ /* Second res_init preserves flag. */
+ TEST_VERIFY (_res.options & RES_USE_EDNS0);
+ if (test_index == 1)
+ /* Restore empty file. */
+ support_write_file_string (_PATH_RESCONF, "");
+ break;
+
+ case 2:
+ /* Second res_init is cumulative. */
+ support_write_file_string (_PATH_RESCONF,
+ "options rotate\n"
+ "nameserver 192.0.2.1\n");
+ _res.options = RES_USE_EDNS0;
+ TEST_VERIFY (res_init () == 0);
+ /* First res_init clears flag. */
+ TEST_VERIFY (!(_res.options & RES_USE_EDNS0));
+ /* And sets RES_ROTATE. */
+ TEST_VERIFY (_res.options & RES_ROTATE);
+ _res.options |= RES_USE_EDNS0;
+ TEST_VERIFY (res_init () == 0);
+ /* Second res_init preserves flag. */
+ TEST_VERIFY (_res.options & RES_USE_EDNS0);
+ TEST_VERIFY (_res.options & RES_ROTATE);
+ /* Reloading the configuration does not clear the explicitly set
+ flag. */
+ support_write_file_string (_PATH_RESCONF,
+ "nameserver 192.0.2.1\n"
+ "nameserver 192.0.2.2\n");
+ TEST_VERIFY (res_init () == 0);
+ TEST_VERIFY (_res.nscount == 2);
+ TEST_VERIFY (_res.options & RES_USE_EDNS0);
+ /* Whether RES_ROTATE (originally in resolv.conf, now removed)
+ should be preserved is subject to debate. See bug 21701. */
+ /* TEST_VERIFY (!(_res.options & RES_ROTATE)); */
+ break;
+
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ support_write_file_string (_PATH_RESCONF,
+ "options edns0\n"
+ "nameserver 192.0.2.1\n");
+ goto reload_tests;
+ case 7: /* 7 and the following tests are with no-reload. */
+ case 8:
+ case 9:
+ case 10:
+ support_write_file_string (_PATH_RESCONF,
+ "options edns0 no-reload\n"
+ "nameserver 192.0.2.1\n");
+ /* Fall through. */
+ reload_tests:
+ for (int iteration = 0; iteration < 2; ++iteration)
+ {
+ switch (test_index)
+ {
+ case 3:
+ case 7:
+ TEST_VERIFY (res_init () == 0);
+ break;
+ case 4:
+ case 8:
+ {
+ unsigned char buf[512];
+ TEST_VERIFY
+ (res_mkquery (QUERY, test_hostname, C_IN, T_A,
+ NULL, 0, NULL, buf, sizeof (buf)) > 0);
+ }
+ break;
+ case 5:
+ case 9:
+ gethostbyname (test_hostname);
+ break;
+ case 6:
+ case 10:
+ {
+ struct addrinfo *ai;
+ (void) getaddrinfo (test_hostname, NULL, NULL, &ai);
+ }
+ break;
+ }
+ /* test_index == 7 is res_init and performs a reload even
+ with no-reload. */
+ if (iteration == 0 || test_index > 7)
+ {
+ TEST_VERIFY (_res.options & RES_USE_EDNS0);
+ TEST_VERIFY (!(_res.options & RES_ROTATE));
+ if (test_index < 7)
+ TEST_VERIFY (!(_res.options & RES_NORELOAD));
+ else
+ TEST_VERIFY (_res.options & RES_NORELOAD);
+ TEST_VERIFY (_res.nscount == 1);
+ /* File change triggers automatic reloading. */
+ support_write_file_string (_PATH_RESCONF,
+ "options rotate\n"
+ "nameserver 192.0.2.1\n"
+ "nameserver 192.0.2.2\n");
+ }
+ else
+ {
+ if (test_index != 3 && test_index != 7)
+ /* test_index 3, 7 are res_init; this function does
+ not reset flags. See bug 21701. */
+ TEST_VERIFY (!(_res.options & RES_USE_EDNS0));
+ TEST_VERIFY (_res.options & RES_ROTATE);
+ TEST_VERIFY (_res.nscount == 2);
+ }
+ }
+ break;
+ }
+}
+
+#if TEST_THREAD
+/* Helper function which calls special_test_callback from a
+ thread. */
+static void *
+special_test_thread_func (void *closure)
+{
+ special_test_callback (closure);
+ return NULL;
+}
+
+/* Variant of special_test_callback which runs the function on a
+ non-main thread. */
+static void
+run_special_test_on_thread (void *closure)
+{
+ xpthread_join (xpthread_create (NULL, special_test_thread_func, closure));
+}
+#endif /* TEST_THREAD */
+
+/* Perform the requested special test in a subprocess using
+ special_test_callback. */
+static void
+special_test (unsigned int test_index)
+{
+#if TEST_THREAD
+ for (int do_thread = 0; do_thread < 2; ++do_thread)
+#endif
+ {
+ void (*func) (void *) = special_test_callback;
+#if TEST_THREAD
+ if (do_thread)
+ func = run_special_test_on_thread;
+#endif
+ struct support_capture_subprocess proc
+ = support_capture_subprocess (func, &test_index);
+ char *test_name = xasprintf ("special test %u", test_index);
+ if (strcmp (proc.out.buffer, "") != 0)
+ {
+ support_record_failure ();
+ printf ("error: output mismatch for %s\n", test_name);
+ support_run_diff ("expected", "",
+ "actual", proc.out.buffer);
+ }
+ support_capture_subprocess_check (&proc, test_name, 0, sc_allow_stdout);
+ free (test_name);
+ support_capture_subprocess_free (&proc);
+ }
+}
+
+
/* Dummy DNS server. It ensures that the probe queries sent by
gethostbyname and getaddrinfo receive a reply even if the system
applies a very strict rate limit to localhost. */
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);
+ support_write_file_string (chroot_env->path_resolv_conf,
+ test_cases[i].conf);
test_file_contents (&test_cases[i]);
{
if (test_verbose > 0)
printf ("info: special test: missing file\n");
- TEST_VERIFY (unlink (path_resolv_conf) == 0);
+ TEST_VERIFY (unlink (chroot_env->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_VERIFY (symlink ("does-not-exist", chroot_env->path_resolv_conf) == 0);
test_file_contents (&test_cases[i]);
- TEST_VERIFY (unlink (path_resolv_conf) == 0);
+ TEST_VERIFY (unlink (chroot_env->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);
+ support_write_file_string (chroot_env->path_resolv_conf, "");
+ TEST_VERIFY (chmod (chroot_env->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, "");
+ TEST_VERIFY (unlink (chroot_env->path_resolv_conf) == 0);
+ support_write_file_string (chroot_env->path_resolv_conf, "");
}
}
+ /* The tests which do not follow a regular pattern. */
+ for (unsigned int test_index = 0;
+ test_index < special_tests_count; ++test_index)
+ special_test (test_index);
+
if (server > 0)
{
if (kill (server, SIGTERM) < 0)
xwaitpid (server, NULL, 0);
}
- free (path_chroot);
- path_chroot = NULL;
- free (path_resolv_conf);
- path_resolv_conf = NULL;
+ support_chroot_free (chroot_env);
return 0;
}