about summary refs log tree commit diff
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)
downloadglibc-319b9ad4bccedb2a6b1a222cf446e873b2bc6de1.tar.gz
glibc-319b9ad4bccedb2a6b1a222cf446e873b2bc6de1.tar.xz
glibc-319b9ad4bccedb2a6b1a222cf446e873b2bc6de1.zip
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__));