svn commit: r289315 - in head: include lib/libc/resolv share/man/man5

Eric van Gyzen vangyzen at FreeBSD.org
Wed Oct 14 14:26:46 UTC 2015


Author: vangyzen
Date: Wed Oct 14 14:26:44 2015
New Revision: 289315
URL: https://svnweb.freebsd.org/changeset/base/289315

Log:
  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

Modified:
  head/include/resolv.h
  head/lib/libc/resolv/res_init.c
  head/lib/libc/resolv/res_state.c
  head/share/man/man5/resolver.5

Modified: head/include/resolv.h
==============================================================================
--- head/include/resolv.h	Wed Oct 14 12:46:05 2015	(r289314)
+++ head/include/resolv.h	Wed Oct 14 14:26:44 2015	(r289315)
@@ -176,7 +176,8 @@ struct __res_state {
 	int	res_h_errno;		/*%< last one set for this context */
 	int	_vcsock;		/*%< PRIVATE: for res_send VC i/o */
 	u_int	_flags;			/*%< PRIVATE: see below */
-	u_int	_pad;			/*%< make _u 64 bit aligned */
+	u_short	reload_period;		/*%< seconds between stat(resolv.conf)*/
+	u_short	_pad;			/*%< make _u 64 bit aligned */
 	union {
 		/* On an 32-bit arch this means 512b total. */
 		char	pad[72 - 4*sizeof (int) - 3*sizeof (void *)];
@@ -188,6 +189,8 @@ struct __res_state {
 		} _ext;
 	} _u;
 	u_char	*_rnd;			/*%< PRIVATE: random state */
+	struct timespec	conf_mtim;	/*%< mod time of loaded resolv.conf */
+	time_t		conf_stat;	/*%< time of last stat(resolv.conf) */
 };
 
 typedef struct __res_state *res_state;

Modified: head/lib/libc/resolv/res_init.c
==============================================================================
--- head/lib/libc/resolv/res_init.c	Wed Oct 14 12:46:05 2015	(r289314)
+++ head/lib/libc/resolv/res_init.c	Wed Oct 14 14:26:44 2015	(r289315)
@@ -78,6 +78,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <sys/time.h>
 
 #include <netinet/in.h>
@@ -227,6 +228,7 @@ __res_vinit(res_state statp, int preinit
 	statp->pfcode = 0;
 	statp->_vcsock = -1;
 	statp->_flags = 0;
+	statp->reload_period = 2;
 	statp->qhook = NULL;
 	statp->rhook = NULL;
 	statp->_u._ext.nscount = 0;
@@ -321,6 +323,22 @@ __res_vinit(res_state statp, int preinit
 
 	nserv = 0;
 	if ((fp = fopen(_PATH_RESCONF, "re")) != NULL) {
+	    struct stat sb;
+	    struct timespec now;
+
+	    if (_fstat(fileno(fp), &sb) == 0) {
+		statp->conf_mtim = sb.st_mtim;
+		if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) == 0) {
+		    statp->conf_stat = now.tv_sec;
+		} else {
+		    statp->conf_stat = 0;
+		}
+	    } else {
+		statp->conf_mtim.tv_sec = 0;
+		statp->conf_mtim.tv_nsec = 0;
+		statp->conf_stat = 0;
+	    }
+
 	    /* read the config file */
 	    while (fgets(buf, sizeof(buf), fp) != NULL) {
 		/* skip comments */
@@ -666,6 +684,10 @@ res_setoptions(res_state statp, const ch
 		} else if (!strncmp(cp, "no-check-names",
 				    sizeof("no-check-names") - 1)) {
 			statp->options |= RES_NOCHECKNAME;
+		} else if (!strncmp(cp, "reload-period:",
+				    sizeof("reload-period:") - 1)) {
+			statp->reload_period = (u_short)
+				atoi(cp + sizeof("reload-period:") - 1);
 		}
 #ifdef RES_USE_EDNS0
 		else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {

Modified: head/lib/libc/resolv/res_state.c
==============================================================================
--- head/lib/libc/resolv/res_state.c	Wed Oct 14 12:46:05 2015	(r289314)
+++ head/lib/libc/resolv/res_state.c	Wed Oct 14 14:26:44 2015	(r289315)
@@ -26,6 +26,8 @@
  */
 
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
 #include <netinet/in.h>
 #include <arpa/nameser.h>
 #include <resolv.h>
@@ -59,13 +61,38 @@ 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);
+		return res_check_reload(&_res);
 
 	if (thr_once(&res_init_once, res_keycreate) != 0 ||
 	    !res_thr_keycreated)
@@ -73,7 +100,7 @@ __res_state(void)
 
 	statp = thr_getspecific(res_key);
 	if (statp != NULL)
-		return (statp);
+		return res_check_reload(statp);
 	statp = calloc(1, sizeof(*statp));
 	if (statp == NULL)
 		return (&_res);

Modified: head/share/man/man5/resolver.5
==============================================================================
--- head/share/man/man5/resolver.5	Wed Oct 14 12:46:05 2015	(r289314)
+++ head/share/man/man5/resolver.5	Wed Oct 14 14:26:44 2015	(r289315)
@@ -28,7 +28,7 @@
 .\"     @(#)resolver.5	8.1 (Berkeley) 6/5/93
 .\" $FreeBSD$
 .\"
-.Dd December 25, 2013
+.Dd October 12, 2015
 .Dt RESOLVER 5
 .Os
 .Sh NAME
@@ -175,6 +175,19 @@ the resolver from obeying the standard
 and
 .Sy search
 rules with the given name.
+.It Sy reload-period: Ns Ar n
+The resolver checks the modification time of
+.Pa /etc/resolv.conf
+every
+.Ar n
+seconds.
+If
+.Pa /etc/resolv.conf
+has changed, it is automatically reloaded.
+The default for
+.Ar n
+is two seconds.
+Setting it to zero disables the file check.
 .El
 .Pp
 Options may also be specified as a space or tab separated list using the
@@ -191,8 +204,7 @@ If more than one instance of these keywo
 the last instance will override.
 .Pp
 The keyword and value must appear on a single line, and the keyword
-(e.g.\&
-.Sy nameserver )
+.Pq for example, Sy nameserver
 must start the line.
 The value follows the keyword, separated by white space.
 .Sh FILES


More information about the svn-src-head mailing list