freebsd-dev/lib/libc/resolv/res_state.c
Eric van Gyzen 60b27ebb25 resolver: automatically reload /etc/resolv.conf
On each resolver query, use stat(2) to see if the modification time
of /etc/resolv.conf has changed.  If so, reload the file and reinitialize
the resolver library.  However, only call stat(2) if at least two seconds
have passed since the last call to stat(2), since calling it on every
query could kill performance.

This new behavior is enabled by default.  Add a "reload-period" option
to disable it or change the period of the test.

Document this behavior and option in resolv.conf(5).

Polish the man page just enough to appease igor.

https://lists.freebsd.org/pipermail/freebsd-arch/2015-October/017342.html

Reviewed by:	kp, wblock
Discussed with:	jilles, imp, alfred
MFC after:	1 month
Relnotes:	yes
Sponsored by:	Dell Inc.
Differential Revision:	https://reviews.freebsd.org/D3867
2015-10-14 14:26:44 +00:00

115 lines
3.0 KiB
C

/*-
* Copyright (c) 2006 The FreeBSD Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <stdlib.h>
#include "namespace.h"
#include "reentrant.h"
#include "un-namespace.h"
#undef _res
struct __res_state _res;
static thread_key_t res_key;
static once_t res_init_once = ONCE_INITIALIZER;
static int res_thr_keycreated = 0;
static void
free_res(void *ptr)
{
res_state statp = ptr;
if (statp->_u._ext.ext != NULL)
res_ndestroy(statp);
free(statp);
}
static void
res_keycreate(void)
{
res_thr_keycreated = thr_keycreate(&res_key, free_res) == 0;
}
static res_state
res_check_reload(res_state statp)
{
struct timespec now;
struct stat sb;
if ((statp->options & RES_INIT) == 0 || statp->reload_period == 0) {
return (statp);
}
if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) != 0 ||
(now.tv_sec - statp->conf_stat) < statp->reload_period) {
return (statp);
}
statp->conf_stat = now.tv_sec;
if (stat(_PATH_RESCONF, &sb) == 0 &&
(sb.st_mtim.tv_sec != statp->conf_mtim.tv_sec ||
sb.st_mtim.tv_nsec != statp->conf_mtim.tv_nsec)) {
statp->options &= ~RES_INIT;
}
return (statp);
}
res_state
__res_state(void)
{
res_state statp;
if (thr_main() != 0)
return res_check_reload(&_res);
if (thr_once(&res_init_once, res_keycreate) != 0 ||
!res_thr_keycreated)
return (&_res);
statp = thr_getspecific(res_key);
if (statp != NULL)
return res_check_reload(statp);
statp = calloc(1, sizeof(*statp));
if (statp == NULL)
return (&_res);
#ifdef __BIND_RES_TEXT
statp->options = RES_TIMEOUT; /* Motorola, et al. */
#endif
if (thr_setspecific(res_key, statp) == 0)
return (statp);
free(statp);
return (&_res);
}