From owner-svn-src-all@freebsd.org Sat Dec 19 02:50:01 2015 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 132DFA4CF36; Sat, 19 Dec 2015 02:50:01 +0000 (UTC) (envelope-from vangyzen@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id C824C1AE6; Sat, 19 Dec 2015 02:50:00 +0000 (UTC) (envelope-from vangyzen@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id tBJ2nxwS026234; Sat, 19 Dec 2015 02:49:59 GMT (envelope-from vangyzen@FreeBSD.org) Received: (from vangyzen@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id tBJ2nx27026231; Sat, 19 Dec 2015 02:49:59 GMT (envelope-from vangyzen@FreeBSD.org) Message-Id: <201512190249.tBJ2nx27026231@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: vangyzen set sender to vangyzen@FreeBSD.org using -f From: Eric van Gyzen Date: Sat, 19 Dec 2015 02:49:59 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r292464 - stable/9/lib/libc/resolv X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 19 Dec 2015 02:50:01 -0000 Author: vangyzen Date: Sat Dec 19 02:49:59 2015 New Revision: 292464 URL: https://svnweb.freebsd.org/changeset/base/292464 Log: MFC r289315,r292216 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. Relnotes: yes Sponsored by: Dell Inc. Modified: stable/9/lib/libc/resolv/res_init.c stable/9/lib/libc/resolv/res_private.h stable/9/lib/libc/resolv/res_state.c Directory Properties: stable/9/include/ (props changed) stable/9/lib/libc/ (props changed) Modified: stable/9/lib/libc/resolv/res_init.c ============================================================================== --- stable/9/lib/libc/resolv/res_init.c Sat Dec 19 02:47:05 2015 (r292463) +++ stable/9/lib/libc/resolv/res_init.c Sat Dec 19 02:49:59 2015 (r292464) @@ -78,6 +78,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -238,6 +239,7 @@ __res_vinit(res_state statp, int preinit statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr; strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa"); strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int"); + statp->_u._ext.ext->reload_period = 2; } else { /* * Historically res_init() rarely, if at all, failed. @@ -323,6 +325,18 @@ __res_vinit(res_state statp, int preinit nserv = 0; if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { + struct stat sb; + struct timespec now; + + if (statp->_u._ext.ext != NULL) { + if (_fstat(fileno(fp), &sb) == 0) { + statp->_u._ext.ext->conf_mtim = sb.st_mtim; + if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) == 0) { + statp->_u._ext.ext->conf_stat = now.tv_sec; + } + } + } + /* read the config file */ while (fgets(buf, sizeof(buf), fp) != NULL) { /* skip comments */ @@ -583,9 +597,7 @@ res_setoptions(res_state statp, const ch { const char *cp = options; int i; -#ifndef _LIBC struct __res_state_ext *ext = statp->_u._ext.ext; -#endif #ifdef DEBUG if (statp->options & RES_DEBUG) @@ -668,6 +680,12 @@ 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)) { + if (ext != NULL) { + ext->reload_period = (u_short) + atoi(cp + sizeof("reload-period:") - 1); + } } #ifdef RES_USE_EDNS0 else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) { Modified: stable/9/lib/libc/resolv/res_private.h ============================================================================== --- stable/9/lib/libc/resolv/res_private.h Sat Dec 19 02:47:05 2015 (r292463) +++ stable/9/lib/libc/resolv/res_private.h Sat Dec 19 02:49:59 2015 (r292464) @@ -1,3 +1,5 @@ +/* $FreeBSD$ */ + #ifndef res_private_h #define res_private_h @@ -12,6 +14,9 @@ struct __res_state_ext { } sort_list[MAXRESOLVSORT]; char nsuffix[64]; char nsuffix2[64]; + struct timespec conf_mtim; /* mod time of loaded resolv.conf */ + time_t conf_stat; /* time of last stat(resolv.conf) */ + u_short reload_period; /* seconds between stat(resolv.conf) */ }; extern int Modified: stable/9/lib/libc/resolv/res_state.c ============================================================================== --- stable/9/lib/libc/resolv/res_state.c Sat Dec 19 02:47:05 2015 (r292463) +++ stable/9/lib/libc/resolv/res_state.c Sat Dec 19 02:49:59 2015 (r292464) @@ -26,6 +26,8 @@ */ #include +#include +#include #include #include #include @@ -35,6 +37,8 @@ #include "reentrant.h" #include "un-namespace.h" +#include "res_private.h" + #undef _res struct __res_state _res; @@ -59,13 +63,44 @@ 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; + struct __res_state_ext *ext; + + if ((statp->options & RES_INIT) == 0) { + return (statp); + } + + ext = statp->_u._ext.ext; + if (ext == NULL || ext->reload_period == 0) { + return (statp); + } + + if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) != 0 || + (now.tv_sec - ext->conf_stat) < ext->reload_period) { + return (statp); + } + + ext->conf_stat = now.tv_sec; + if (stat(_PATH_RESCONF, &sb) == 0 && + (sb.st_mtim.tv_sec != ext->conf_mtim.tv_sec || + sb.st_mtim.tv_nsec != ext->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 +108,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);