about summary refs log tree commit diff
path: root/nscd
diff options
context:
space:
mode:
Diffstat (limited to 'nscd')
-rw-r--r--nscd/cache.c34
-rw-r--r--nscd/connections.c20
-rw-r--r--nscd/nscd.c30
-rw-r--r--nscd/nscd.h2
4 files changed, 68 insertions, 18 deletions
diff --git a/nscd/cache.c b/nscd/cache.c
index 899e2caf77..be9be2aa4f 100644
--- a/nscd/cache.c
+++ b/nscd/cache.c
@@ -190,20 +190,34 @@ cache_add (int type, const void *key, size_t len, struct datahead *packet,
    free the data structures since some hash table entries share the same
    data.  */
 void
-prune_cache (struct database_dyn *table, time_t now)
+prune_cache (struct database_dyn *table, time_t now, int fd)
 {
   size_t cnt = table->head->module;
 
   /* If this table is not actually used don't do anything.  */
   if (cnt == 0)
-    return;
+    {
+      if (fd != -1)
+	{
+	  /* Reply to the INVALIDATE initiator.  */
+	  int32_t resp = 0;
+	  writeall (fd, &resp, sizeof (resp));
+	}
+      return;
+    }
 
   /* This function can be called from the cleanup thread but also in
      response to an invalidate command.  Make sure only one thread is
-     running.  No need for the second to wait around.  */
-  if (pthread_mutex_trylock (&table->prunelock) != 0)
-    /* Te work is already being done.  */
-    return ;
+     running.  When not serving INVALIDATE request, no need for the
+     second to wait around.  */
+  if (fd == -1)
+    {
+      if (pthread_mutex_trylock (&table->prunelock) != 0)
+	/* The work is already being done.  */
+	return;
+    }
+  else
+    pthread_mutex_lock (&table->prunelock);
 
   /* If we check for the modification of the underlying file we invalidate
      the entries also in this case.  */
@@ -374,6 +388,14 @@ prune_cache (struct database_dyn *table, time_t now)
     }
   while (cnt > 0);
 
+  if (fd != -1)
+    {
+      /* Reply to the INVALIDATE initiator that the cache has been
+	 invalidated.  */
+      int32_t resp = 0;
+      writeall (fd, &resp, sizeof (resp));
+    }
+
   if (first <= last)
     {
       struct hashentry *head = NULL;
diff --git a/nscd/connections.c b/nscd/connections.c
index da837b5e8a..c4269ce548 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -816,9 +816,10 @@ close_sockets (void)
 
 
 static void
-invalidate_cache (char *key)
+invalidate_cache (char *key, int fd)
 {
   dbtype number;
+  int32_t resp;
 
   if (strcmp (key, "passwd") == 0)
     number = pwddb;
@@ -832,10 +833,19 @@ invalidate_cache (char *key)
       res_init ();
     }
   else
-    return;
+    {
+      resp = EINVAL;
+      writeall (fd, &resp, sizeof (resp));
+      return;
+    }
 
   if (dbs[number].enabled)
-    prune_cache (&dbs[number], LONG_MAX);
+    prune_cache (&dbs[number], LONG_MAX, fd);
+  else
+    {
+      resp = 0;
+      writeall (fd, &resp, sizeof (resp));
+    }
 }
 
 
@@ -1092,7 +1102,7 @@ cannot handle old request version %d; current version is %d"),
       else if (uid == 0)
 	{
 	  if (req->type == INVALIDATE)
-	    invalidate_cache (key);
+	    invalidate_cache (key, fd);
 	  else
 	    termination_handler (0);
 	}
@@ -1438,7 +1448,7 @@ handle_request: request received (Version = %d)"), req.version);
 	  /* The pthread_cond_timedwait() call timed out.  It is time
 		 to clean up the cache.  */
 	  assert (my_number < lastdb);
-	  prune_cache (&dbs[my_number], time (NULL));
+	  prune_cache (&dbs[my_number], time (NULL), -1);
 
 	  if (clock_gettime (timeout_clock, &prune_ts) == -1)
 	    /* Should never happen.  */
diff --git a/nscd/nscd.c b/nscd/nscd.c
index 16f55cfdeb..6d1e50a837 100644
--- a/nscd/nscd.c
+++ b/nscd/nscd.c
@@ -332,9 +332,6 @@ parse_opt (int key, char *arg, struct argp_state *state)
 	    exit (EXIT_FAILURE);
 
 	  request_header req;
-	  ssize_t nbytes;
-	  struct iovec iov[2];
-
 	  if (strcmp (arg, "passwd") == 0)
 	    req.key_len = sizeof "passwd";
 	  else if (strcmp (arg, "group") == 0)
@@ -347,17 +344,38 @@ parse_opt (int key, char *arg, struct argp_state *state)
 	  req.version = NSCD_VERSION;
 	  req.type = INVALIDATE;
 
+	  struct iovec iov[2];
 	  iov[0].iov_base = &req;
 	  iov[0].iov_len = sizeof (req);
 	  iov[1].iov_base = arg;
 	  iov[1].iov_len = req.key_len;
 
-	  nbytes = TEMP_FAILURE_RETRY (writev (sock, iov, 2));
+	  ssize_t nbytes = TEMP_FAILURE_RETRY (writev (sock, iov, 2));
+
+	  if (nbytes != iov[0].iov_len + iov[1].iov_len)
+	    {
+	      int err = errno;
+	      close (sock);
+	      error (EXIT_FAILURE, err, _("write incomplete"));
+	    }
+
+	  /* Wait for ack.  Older nscd just closed the socket when
+	     prune_cache finished, silently ignore that.  */
+	  int32_t resp = 0;
+	  nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
+	  if (nbytes != 0 && nbytes != sizeof (resp))
+	    {
+	      int err = errno;
+	      close (sock);
+	      error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
+	    }
 
 	  close (sock);
 
-	  exit (nbytes != iov[0].iov_len + iov[1].iov_len
-		? EXIT_FAILURE : EXIT_SUCCESS);
+	  if (resp != 0)
+	    error (EXIT_FAILURE, resp, _("invalidation failed"));
+
+	  exit (0);
 	}
 
     case 't':
diff --git a/nscd/nscd.h b/nscd/nscd.h
index 4a9547221a..5c2ff3a95b 100644
--- a/nscd/nscd.h
+++ b/nscd/nscd.h
@@ -185,7 +185,7 @@ extern struct datahead *cache_search (request_type, void *key, size_t len,
 extern int cache_add (int type, const void *key, size_t len,
 		      struct datahead *packet, bool first,
 		      struct database_dyn *table, uid_t owner);
-extern void prune_cache (struct database_dyn *table, time_t now);
+extern void prune_cache (struct database_dyn *table, time_t now, int fd);
 
 /* pwdcache.c */
 extern void addpwbyname (struct database_dyn *db, int fd, request_header *req,