summaryrefslogtreecommitdiff
path: root/nscd
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@gmail.com>2011-07-11 14:50:24 -0400
committerUlrich Drepper <drepper@gmail.com>2011-07-11 14:50:24 -0400
commit319b9ad4bccedb2a6b1a222cf446e873b2bc6de1 (patch)
tree7951727c0dbd4394af52715e226745986e8beeb4 /nscd
parent23bee3e8677c9357662ce789ed77fe25f3991c66 (diff)
Generalize framework to register monitoring of files in nscd
nscd can clear caches when certain files change. The list of files was hardcoded so far and worked for nss_files and nss_dns and those modules which need no monitoring. nss_db, for instance, has its own set of files to monitor. Now the NSS modules themselves can request that certain files are monitored.
Diffstat (limited to 'nscd')
-rw-r--r--nscd/cache.c46
-rw-r--r--nscd/connections.c165
-rw-r--r--nscd/nscd.c18
-rw-r--r--nscd/nscd.h19
4 files changed, 144 insertions, 104 deletions
diff --git a/nscd/cache.c b/nscd/cache.c
index ebc6e4c0d6..58f0bcc5f1 100644
--- a/nscd/cache.c
+++ b/nscd/cache.c
@@ -264,28 +264,40 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
/* If we check for the modification of the underlying file we invalidate
the entries also in this case. */
- if (table->inotify_descr < 0 && table->check_file && now != LONG_MAX)
+ if (table->check_file && now != LONG_MAX)
{
- struct stat64 st;
+ struct traced_file *runp = table->traced_files;
- if (stat64 (table->filename, &st) < 0)
+ while (runp != NULL)
{
- char buf[128];
- /* We cannot stat() the file, disable file checking if the
- file does not exist. */
- dbg_log (_("cannot stat() file `%s': %s"),
- table->filename, strerror_r (errno, buf, sizeof (buf)));
- if (errno == ENOENT)
- table->check_file = 0;
- }
- else
- {
- if (st.st_mtime != table->file_mtime)
+#ifdef HAVE_INOTIFY
+ if (runp->inotify_descr == -1)
+#endif
{
- /* The file changed. Invalidate all entries. */
- now = LONG_MAX;
- table->file_mtime = st.st_mtime;
+ struct stat64 st;
+
+ if (stat64 (runp->fname, &st) < 0)
+ {
+ char buf[128];
+ /* We cannot stat() the file, disable file checking if the
+ file does not exist. */
+ dbg_log (_("cannot stat() file `%s': %s"),
+ runp->fname, strerror_r (errno, buf, sizeof (buf)));
+ if (errno == ENOENT)
+ table->check_file = 0;
+ }
+ else
+ {
+ if (st.st_mtime != table->file_mtime)
+ {
+ /* The file changed. Invalidate all entries. */
+ now = LONG_MAX;
+ table->file_mtime = st.st_mtime;
+ }
+ }
}
+
+ runp = runp->next;
}
}
diff --git a/nscd/connections.c b/nscd/connections.c
index 1e47931bd2..6e48869c68 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -117,8 +117,6 @@ struct database_dyn dbs[lastdb] =
.shared = 0,
.max_db_size = DEFAULT_MAX_DB_SIZE,
.suggested_module = DEFAULT_SUGGESTED_MODULE,
- .reset_res = 0,
- .filename = "/etc/passwd",
.db_filename = _PATH_NSCD_PASSWD_DB,
.disabled_iov = &pwd_iov_disabled,
.postimeout = 3600,
@@ -138,8 +136,6 @@ struct database_dyn dbs[lastdb] =
.shared = 0,
.max_db_size = DEFAULT_MAX_DB_SIZE,
.suggested_module = DEFAULT_SUGGESTED_MODULE,
- .reset_res = 0,
- .filename = "/etc/group",
.db_filename = _PATH_NSCD_GROUP_DB,
.disabled_iov = &grp_iov_disabled,
.postimeout = 3600,
@@ -159,8 +155,6 @@ struct database_dyn dbs[lastdb] =
.shared = 0,
.max_db_size = DEFAULT_MAX_DB_SIZE,
.suggested_module = DEFAULT_SUGGESTED_MODULE,
- .reset_res = 1,
- .filename = "/etc/hosts",
.db_filename = _PATH_NSCD_HOSTS_DB,
.disabled_iov = &hst_iov_disabled,
.postimeout = 3600,
@@ -180,8 +174,6 @@ struct database_dyn dbs[lastdb] =
.shared = 0,
.max_db_size = DEFAULT_MAX_DB_SIZE,
.suggested_module = DEFAULT_SUGGESTED_MODULE,
- .reset_res = 0,
- .filename = "/etc/services",
.db_filename = _PATH_NSCD_SERVICES_DB,
.disabled_iov = &serv_iov_disabled,
.postimeout = 28800,
@@ -232,10 +224,7 @@ static int sock;
#ifdef HAVE_INOTIFY
/* Inotify descriptor. */
-static int inotify_fd = -1;
-
-/* Watch descriptor for resolver configuration file. */
-static int resolv_conf_descr = -1;
+int inotify_fd = -1;
#endif
#ifndef __ASSUME_SOCK_CLOEXEC
@@ -523,19 +512,6 @@ nscd_init (void)
/* No configuration for this value, assume a default. */
nthreads = 4;
-#ifdef HAVE_INOTIFY
- /* Use inotify to recognize changed files. */
- inotify_fd = inotify_init1 (IN_NONBLOCK);
-# ifndef __ASSUME_IN_NONBLOCK
- if (inotify_fd == -1 && errno == ENOSYS)
- {
- inotify_fd = inotify_init ();
- if (inotify_fd != -1)
- fcntl (inotify_fd, F_SETFL, O_RDONLY | O_NONBLOCK);
- }
-# endif
-#endif
-
for (size_t cnt = 0; cnt < lastdb; ++cnt)
if (dbs[cnt].enabled)
{
@@ -840,40 +816,6 @@ cannot set socket to close on exec: %s; disabling paranoia mode"),
dbs[cnt].shared = 0;
assert (dbs[cnt].ro_fd == -1);
}
-
- dbs[cnt].inotify_descr = -1;
- if (dbs[cnt].check_file)
- {
-#ifdef HAVE_INOTIFY
- if (inotify_fd < 0
- || (dbs[cnt].inotify_descr
- = inotify_add_watch (inotify_fd, dbs[cnt].filename,
- IN_DELETE_SELF | IN_MODIFY)) < 0)
- /* We cannot notice changes in the main thread. */
-#endif
- {
- /* We need the modification date of the file. */
- struct stat64 st;
-
- if (stat64 (dbs[cnt].filename, &st) < 0)
- {
- /* We cannot stat() the file, disable file checking. */
- dbg_log (_("cannot stat() file `%s': %s"),
- dbs[cnt].filename, strerror (errno));
- dbs[cnt].check_file = 0;
- }
- else
- dbs[cnt].file_mtime = st.st_mtime;
- }
- }
-
-#ifdef HAVE_INOTIFY
- if (cnt == hstdb && inotify_fd >= -1)
- /* We also monitor the resolver configuration file. */
- resolv_conf_descr = inotify_add_watch (inotify_fd,
- _PATH_RESCONF,
- IN_DELETE_SELF | IN_MODIFY);
-#endif
}
/* Create the socket. */
@@ -940,12 +882,50 @@ cannot set socket to close on exec: %s; disabling paranoia mode"),
exit (1);
}
- /* Change to unprivileged uid/gid/groups if specifed in config file */
+ /* Change to unprivileged uid/gid/groups if specified in config file */
if (server_user != NULL)
finish_drop_privileges ();
}
+void
+register_traced_file (size_t dbidx, struct traced_file *finfo)
+{
+ if (! dbs[dbidx].check_file)
+ return;
+
+ if (__builtin_expect (debug_level > 0, 0))
+ dbg_log (_("register trace file %s for database %s"),
+ finfo->fname, dbnames[dbidx]);
+
+#ifdef HAVE_INOTIFY
+ if (inotify_fd < 0
+ || (finfo->inotify_descr = inotify_add_watch (inotify_fd, finfo->fname,
+ IN_DELETE_SELF
+ | IN_MODIFY)) < 0)
+#endif
+ {
+ /* We need the modification date of the file. */
+ struct stat64 st;
+
+ if (stat64 (finfo->fname, &st) < 0)
+ {
+ /* We cannot stat() the file, disable file checking. */
+ dbg_log (_("cannot stat() file `%s': %s"),
+ finfo->fname, strerror (errno));
+ return;
+ }
+
+ finfo->inotify_descr = -1;
+ finfo->mtime = st.st_mtime;
+ }
+
+ /* Queue up the file name. */
+ finfo->next = dbs[dbidx].traced_files;
+ dbs[dbidx].traced_files = finfo;
+}
+
+
/* Close the connections. */
void
close_sockets (void)
@@ -963,11 +943,20 @@ invalidate_cache (char *key, int fd)
for (number = pwddb; number < lastdb; ++number)
if (strcmp (key, dbnames[number]) == 0)
{
- if (dbs[number].reset_res)
- res_init ();
-
+ if (number == hstdb)
+ {
+ struct traced_file *runp = dbs[hstdb].traced_files;
+ while (runp != NULL)
+ if (runp->call_res_init)
+ {
+ res_init ();
+ break;
+ }
+ else
+ runp = runp->next;
+ }
break;
- }
+ }
if (number == lastdb)
{
@@ -1913,16 +1902,21 @@ disabled inotify after read error %d"),
/* Check which of the files changed. */
for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
- if (inev.i.wd == dbs[dbcnt].inotify_descr)
- {
- to_clear[dbcnt] = true;
- goto next;
- }
-
- if (inev.i.wd == resolv_conf_descr)
{
- res_init ();
- to_clear[hstdb] = true;
+ struct traced_file *finfo = dbs[dbcnt].traced_files;
+
+ while (finfo != NULL)
+ {
+ if (finfo->inotify_descr == inev.i.wd)
+ {
+ to_clear[dbcnt] = true;
+ if (finfo->call_res_init)
+ res_init ();
+ goto next;
+ }
+
+ finfo = finfo->next;
+ }
}
next:;
}
@@ -2089,7 +2083,7 @@ main_loop_epoll (int efd)
while (1)
{
ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
- sizeof (inev)));
+ sizeof (inev)));
if (nb < (ssize_t) sizeof (struct inotify_event))
{
if (__builtin_expect (nb == -1 && errno != EAGAIN, 0))
@@ -2108,16 +2102,21 @@ main_loop_epoll (int efd)
/* Check which of the files changed. */
for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
- if (inev.i.wd == dbs[dbcnt].inotify_descr)
- {
- to_clear[dbcnt] = true;
- goto next;
- }
-
- if (inev.i.wd == resolv_conf_descr)
{
- res_init ();
- to_clear[hstdb] = true;
+ struct traced_file *finfo = dbs[dbcnt].traced_files;
+
+ while (finfo != NULL)
+ {
+ if (finfo->inotify_descr == inev.i.wd)
+ {
+ to_clear[dbcnt] = true;
+ if (finfo->call_res_init)
+ res_init ();
+ goto next;
+ }
+
+ finfo = finfo->next;
+ }
}
next:;
}
diff --git a/nscd/nscd.c b/nscd/nscd.c
index c3d9fe6cef..4894cb2faa 100644
--- a/nscd/nscd.c
+++ b/nscd/nscd.c
@@ -46,6 +46,9 @@
#include "selinux.h"
#include "../nss/nsswitch.h"
#include <device-nrs.h>
+#ifdef HAVE_INOTIFY
+# include <sys/inotify.h>
+#endif
/* Get libc version number. */
#include <version.h>
@@ -272,8 +275,21 @@ main (int argc, char **argv)
/* Cleanup files created by a previous 'bind'. */
unlink (_PATH_NSCDSOCKET);
+#ifdef HAVE_INOTIFY
+ /* Use inotify to recognize changed files. */
+ inotify_fd = inotify_init1 (IN_NONBLOCK);
+# ifndef __ASSUME_IN_NONBLOCK
+ if (inotify_fd == -1 && errno == ENOSYS)
+ {
+ inotify_fd = inotify_init ();
+ if (inotify_fd != -1)
+ fcntl (inotify_fd, F_SETFL, O_RDONLY | O_NONBLOCK);
+ }
+# endif
+#endif
+
/* Make sure we do not get recursive calls. */
- __nss_disable_nscd ();
+ __nss_disable_nscd (register_traced_file);
/* Init databases. */
nscd_init ();
diff --git a/nscd/nscd.h b/nscd/nscd.h
index 5e3c865a29..c15e88bb6f 100644
--- a/nscd/nscd.h
+++ b/nscd/nscd.h
@@ -62,6 +62,17 @@ typedef enum
#define MAX_STACK_USE ((8 * NSCD_THREAD_STACKSIZE) / 10)
+/* Registered filename used to fill database. */
+struct traced_file
+{
+ time_t mtime;
+ struct traced_file *next;
+ int call_res_init;
+ int inotify_descr;
+ char fname[];
+};
+
+
/* Structure describing dynamic part of one database. */
struct database_dyn
{
@@ -73,13 +84,11 @@ struct database_dyn
int enabled;
int check_file;
- int inotify_descr;
int clear_cache;
int persistent;
int shared;
int propagate;
- int reset_res;
- const char filename[16];
+ struct traced_file *traced_files;
const char *db_filename;
time_t file_mtime;
size_t suggested_module;
@@ -147,6 +156,9 @@ extern int nthreads;
/* Maximum number of threads to use. */
extern int max_nthreads;
+/* Inotify descriptor. */
+extern int inotify_fd;
+
/* User name to run server processes as. */
extern const char *server_user;
@@ -191,6 +203,7 @@ extern int nscd_open_socket (void);
/* connections.c */
extern void nscd_init (void);
+extern void register_traced_file (size_t dbidx, struct traced_file *finfo);
extern void close_sockets (void);
extern void start_threads (void) __attribute__ ((__noreturn__));