|
|
fa3bfd |
commit cf9313e7d1dd42addd6cf8c9277f0f18a62cdeff
|
|
|
fa3bfd |
Author: Carlos O'Donell <carlos@systemhalted.org>
|
|
|
fa3bfd |
Date: Fri Mar 13 09:49:24 2015 -0400
|
|
|
fa3bfd |
|
|
|
fa3bfd |
Enhance nscd's inotify support (Bug 14906).
|
|
|
fa3bfd |
|
|
|
12745e |
--- glibc-2.17-c758a686/nscd/cache.c 2012-12-24 22:02:13.000000000 -0500
|
|
|
12745e |
+++ glibc-2.17-c758a686/nscd/cache.c 2015-05-13 13:45:57.259958374 -0400
|
|
|
12745e |
@@ -272,28 +272,38 @@
|
|
|
12745e |
while (runp != NULL)
|
|
|
12745e |
{
|
|
|
12745e |
#ifdef HAVE_INOTIFY
|
|
|
12745e |
- if (runp->inotify_descr == -1)
|
|
|
12745e |
+ if (runp->inotify_descr[TRACED_FILE] == -1)
|
|
|
12745e |
#endif
|
|
|
12745e |
{
|
|
|
12745e |
struct stat64 st;
|
|
|
12745e |
|
|
|
12745e |
if (stat64 (runp->fname, &st) < 0)
|
|
|
12745e |
{
|
|
|
12745e |
+ /* Print a diagnostic that the traced file was missing.
|
|
|
12745e |
+ We must not disable tracing since the file might return
|
|
|
12745e |
+ shortly and we want to reload it at the next pruning.
|
|
|
12745e |
+ Disabling tracing here would go against the configuration
|
|
|
12745e |
+ as specified by the user via check-files. */
|
|
|
12745e |
char buf[128];
|
|
|
12745e |
- /* We cannot stat() the file, disable file checking if the
|
|
|
12745e |
- file does not exist. */
|
|
|
12745e |
- dbg_log (_("cannot stat() file `%s': %s"),
|
|
|
12745e |
+ dbg_log (_("checking for monitored file `%s': %s"),
|
|
|
12745e |
runp->fname, strerror_r (errno, buf, sizeof (buf)));
|
|
|
12745e |
- if (errno == ENOENT)
|
|
|
12745e |
- table->check_file = 0;
|
|
|
12745e |
}
|
|
|
12745e |
else
|
|
|
12745e |
{
|
|
|
12745e |
- if (st.st_mtime != table->file_mtime)
|
|
|
12745e |
+ /* This must be `!=` to catch cases where users turn the
|
|
|
12745e |
+ clocks back and we still want to detect any time difference
|
|
|
12745e |
+ in mtime. */
|
|
|
12745e |
+ if (st.st_mtime != runp->mtime)
|
|
|
12745e |
{
|
|
|
12745e |
- /* The file changed. Invalidate all entries. */
|
|
|
12745e |
+ dbg_log (_("monitored file `%s` changed (mtime)"),
|
|
|
12745e |
+ runp->fname);
|
|
|
12745e |
+ /* The file changed. Invalidate all entries. */
|
|
|
12745e |
now = LONG_MAX;
|
|
|
12745e |
- table->file_mtime = st.st_mtime;
|
|
|
12745e |
+ runp->mtime = st.st_mtime;
|
|
|
12745e |
+#ifdef HAVE_INOTIFY
|
|
|
12745e |
+ /* Attempt to install a watch on the file. */
|
|
|
12745e |
+ install_watches (runp);
|
|
|
12745e |
+#endif
|
|
|
12745e |
}
|
|
|
12745e |
}
|
|
|
12745e |
}
|
|
|
12745e |
--- glibc-2.17-c758a686/nscd/connections.c 2015-05-12 15:03:02.870274443 -0400
|
|
|
12745e |
+++ glibc-2.17-c758a686/nscd/connections.c 2015-05-13 13:45:57.259958374 -0400
|
|
|
12745e |
@@ -974,6 +974,44 @@
|
|
|
12745e |
finish_drop_privileges ();
|
|
|
12745e |
}
|
|
|
12745e |
|
|
|
12745e |
+#ifdef HAVE_INOTIFY
|
|
|
12745e |
+#define TRACED_FILE_MASK (IN_DELETE_SELF | IN_CLOSE_WRITE | IN_MOVE_SELF)
|
|
|
12745e |
+#define TRACED_DIR_MASK (IN_DELETE_SELF | IN_CREATE | IN_MOVED_TO | IN_MOVE_SELF)
|
|
|
12745e |
+void
|
|
|
12745e |
+install_watches (struct traced_file *finfo)
|
|
|
12745e |
+{
|
|
|
12745e |
+ /* Use inotify support if we have it. */
|
|
|
12745e |
+ if (finfo->inotify_descr[TRACED_FILE] < 0)
|
|
|
12745e |
+ finfo->inotify_descr[TRACED_FILE] = inotify_add_watch (inotify_fd,
|
|
|
12745e |
+ finfo->fname,
|
|
|
12745e |
+ TRACED_FILE_MASK);
|
|
|
12745e |
+ if (finfo->inotify_descr[TRACED_FILE] < 0)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ dbg_log (_("disabled inotify-based monitoring for file `%s': %s"),
|
|
|
12745e |
+ finfo->fname, strerror (errno));
|
|
|
12745e |
+ return;
|
|
|
12745e |
+ }
|
|
|
12745e |
+ dbg_log (_("monitoring file `%s` (%d)"),
|
|
|
12745e |
+ finfo->fname, finfo->inotify_descr[TRACED_FILE]);
|
|
|
12745e |
+ /* Additionally listen for events in the file's parent directory.
|
|
|
12745e |
+ We do this because the file to be watched might be
|
|
|
12745e |
+ deleted and then added back again. When it is added back again
|
|
|
12745e |
+ we must re-add the watch. We must also cover IN_MOVED_TO to
|
|
|
12745e |
+ detect a file being moved into the directory. */
|
|
|
12745e |
+ if (finfo->inotify_descr[TRACED_DIR] < 0)
|
|
|
12745e |
+ finfo->inotify_descr[TRACED_DIR] = inotify_add_watch (inotify_fd,
|
|
|
12745e |
+ finfo->dname,
|
|
|
12745e |
+ TRACED_DIR_MASK);
|
|
|
12745e |
+ if (finfo->inotify_descr[TRACED_DIR] < 0)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ dbg_log (_("disabled inotify-based monitoring for directory `%s': %s"),
|
|
|
12745e |
+ finfo->fname, strerror (errno));
|
|
|
12745e |
+ return;
|
|
|
12745e |
+ }
|
|
|
12745e |
+ dbg_log (_("monitoring directory `%s` (%d)"),
|
|
|
12745e |
+ finfo->dname, finfo->inotify_descr[TRACED_DIR]);
|
|
|
12745e |
+}
|
|
|
12745e |
+#endif
|
|
|
12745e |
|
|
|
12745e |
void
|
|
|
12745e |
register_traced_file (size_t dbidx, struct traced_file *finfo)
|
|
|
12745e |
@@ -982,30 +1020,24 @@
|
|
|
12745e |
return;
|
|
|
12745e |
|
|
|
12745e |
if (__builtin_expect (debug_level > 0, 0))
|
|
|
12745e |
- dbg_log (_("register trace file %s for database %s"),
|
|
|
12745e |
- finfo->fname, dbnames[dbidx]);
|
|
|
12745e |
+ dbg_log (_("monitoring file `%s' for database `%s' (%d)"),
|
|
|
12745e |
+ finfo->fname, dbnames[dbidx],
|
|
|
12745e |
+ finfo->inotify_descr[TRACED_DIR]);
|
|
|
12745e |
|
|
|
12745e |
#ifdef HAVE_INOTIFY
|
|
|
12745e |
- if (inotify_fd < 0
|
|
|
12745e |
- || (finfo->inotify_descr = inotify_add_watch (inotify_fd, finfo->fname,
|
|
|
12745e |
- IN_DELETE_SELF
|
|
|
12745e |
- | IN_MODIFY)) < 0)
|
|
|
12745e |
+ install_watches (finfo);
|
|
|
12745e |
#endif
|
|
|
12745e |
- {
|
|
|
12745e |
- /* We need the modification date of the file. */
|
|
|
12745e |
- struct stat64 st;
|
|
|
12745e |
-
|
|
|
12745e |
- if (stat64 (finfo->fname, &st) < 0)
|
|
|
12745e |
- {
|
|
|
12745e |
- /* We cannot stat() the file, disable file checking. */
|
|
|
12745e |
- dbg_log (_("cannot stat() file `%s': %s"),
|
|
|
12745e |
- finfo->fname, strerror (errno));
|
|
|
12745e |
- return;
|
|
|
12745e |
- }
|
|
|
12745e |
|
|
|
12745e |
- finfo->inotify_descr = -1;
|
|
|
12745e |
- finfo->mtime = st.st_mtime;
|
|
|
12745e |
+ struct stat64 st;
|
|
|
12745e |
+ if (stat64 (finfo->fname, &st) < 0)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ /* We cannot stat() the file. Set mtime to zero and try again later. */
|
|
|
12745e |
+ dbg_log (_("stat failed for file `%s'; will try again later: %s"),
|
|
|
12745e |
+ finfo->fname, strerror (errno));
|
|
|
12745e |
+ finfo->mtime = 0;
|
|
|
12745e |
}
|
|
|
12745e |
+ else
|
|
|
12745e |
+ finfo->mtime = st.st_mtime;
|
|
|
12745e |
|
|
|
12745e |
/* Queue up the file name. */
|
|
|
12745e |
finfo->next = dbs[dbidx].traced_files;
|
|
|
12745e |
@@ -1030,20 +1062,27 @@
|
|
|
12745e |
for (number = pwddb; number < lastdb; ++number)
|
|
|
12745e |
if (strcmp (key, dbnames[number]) == 0)
|
|
|
12745e |
{
|
|
|
12745e |
- if (number == hstdb)
|
|
|
12745e |
+ struct traced_file *runp = dbs[number].traced_files;
|
|
|
12745e |
+ while (runp != NULL)
|
|
|
12745e |
{
|
|
|
12745e |
- struct traced_file *runp = dbs[hstdb].traced_files;
|
|
|
12745e |
- while (runp != NULL)
|
|
|
12745e |
- if (runp->call_res_init)
|
|
|
12745e |
- {
|
|
|
12745e |
- res_init ();
|
|
|
12745e |
- break;
|
|
|
12745e |
- }
|
|
|
12745e |
- else
|
|
|
12745e |
- runp = runp->next;
|
|
|
12745e |
+ /* Make sure we reload from file when checking mtime. */
|
|
|
12745e |
+ runp->mtime = 0;
|
|
|
12745e |
+#ifdef HAVE_INOTIFY
|
|
|
12745e |
+ /* During an invalidation we try to reload the traced
|
|
|
12745e |
+ file watches. This allows the user to re-sync if
|
|
|
12745e |
+ inotify events were lost. Similar to what we do during
|
|
|
12745e |
+ pruning. */
|
|
|
12745e |
+ install_watches (runp);
|
|
|
12745e |
+#endif
|
|
|
12745e |
+ if (runp->call_res_init)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ res_init ();
|
|
|
12745e |
+ break;
|
|
|
12745e |
+ }
|
|
|
12745e |
+ runp = runp->next;
|
|
|
12745e |
}
|
|
|
12745e |
break;
|
|
|
12745e |
- }
|
|
|
12745e |
+ }
|
|
|
12745e |
|
|
|
12745e |
if (number == lastdb)
|
|
|
12745e |
{
|
|
|
12745e |
@@ -1871,6 +1910,234 @@
|
|
|
12745e |
static time_t *starttime;
|
|
|
12745e |
|
|
|
12745e |
|
|
|
12745e |
+#ifdef HAVE_INOTIFY
|
|
|
12745e |
+/* Inotify event for changed file. */
|
|
|
12745e |
+union __inev
|
|
|
12745e |
+{
|
|
|
12745e |
+ struct inotify_event i;
|
|
|
12745e |
+# ifndef PATH_MAX
|
|
|
12745e |
+# define PATH_MAX 1024
|
|
|
12745e |
+# endif
|
|
|
12745e |
+ char buf[sizeof (struct inotify_event) + PATH_MAX];
|
|
|
12745e |
+};
|
|
|
12745e |
+
|
|
|
12745e |
+/* Returns 0 if the file is there otherwise -1. */
|
|
|
12745e |
+int
|
|
|
12745e |
+check_file (struct traced_file *finfo)
|
|
|
12745e |
+{
|
|
|
12745e |
+ struct stat64 st;
|
|
|
12745e |
+ /* We could check mtime and if different re-add
|
|
|
12745e |
+ the watches, and invalidate the database, but we
|
|
|
12745e |
+ don't because we are called from inotify_check_files
|
|
|
12745e |
+ which should be doing that work. If sufficient inotify
|
|
|
12745e |
+ events were lost then the next pruning or invalidation
|
|
|
12745e |
+ will do the stat and mtime check. We don't do it here to
|
|
|
12745e |
+ keep the logic simple. */
|
|
|
12745e |
+ if (stat64 (finfo->fname, &st) < 0)
|
|
|
12745e |
+ return -1;
|
|
|
12745e |
+ return 0;
|
|
|
12745e |
+}
|
|
|
12745e |
+
|
|
|
12745e |
+/* Process the inotify event in INEV. If the event matches any of the files
|
|
|
12745e |
+ registered with a database then mark that database as requiring its cache
|
|
|
12745e |
+ to be cleared. We indicate the cache needs clearing by setting
|
|
|
12745e |
+ TO_CLEAR[DBCNT] to true for the matching database. */
|
|
|
12745e |
+static void
|
|
|
12745e |
+inotify_check_files (bool *to_clear, union __inev *inev)
|
|
|
12745e |
+{
|
|
|
12745e |
+ /* Check which of the files changed. */
|
|
|
12745e |
+ for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ struct traced_file *finfo = dbs[dbcnt].traced_files;
|
|
|
12745e |
+
|
|
|
12745e |
+ while (finfo != NULL)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ /* The configuration file was moved or deleted.
|
|
|
12745e |
+ We stop watching it at that point, and reinitialize. */
|
|
|
12745e |
+ if (finfo->inotify_descr[TRACED_FILE] == inev->i.wd
|
|
|
12745e |
+ && ((inev->i.mask & IN_MOVE_SELF)
|
|
|
12745e |
+ || (inev->i.mask & IN_DELETE_SELF)
|
|
|
12745e |
+ || (inev->i.mask & IN_IGNORED)))
|
|
|
12745e |
+ {
|
|
|
12745e |
+ int ret;
|
|
|
12745e |
+ bool moved = (inev->i.mask & IN_MOVE_SELF) != 0;
|
|
|
12745e |
+
|
|
|
12745e |
+ if (check_file (finfo) == 0)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ dbg_log (_("ignored inotify event for `%s` (file exists)"),
|
|
|
12745e |
+ finfo->fname);
|
|
|
12745e |
+ return;
|
|
|
12745e |
+ }
|
|
|
12745e |
+
|
|
|
12745e |
+ dbg_log (_("monitored file `%s` was %s, removing watch"),
|
|
|
12745e |
+ finfo->fname, moved ? "moved" : "deleted");
|
|
|
12745e |
+ /* File was moved out, remove the watch. Watches are
|
|
|
12745e |
+ automatically removed when the file is deleted. */
|
|
|
12745e |
+ if (moved)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ ret = inotify_rm_watch (inotify_fd, inev->i.wd);
|
|
|
12745e |
+ if (ret < 0)
|
|
|
12745e |
+ dbg_log (_("failed to remove file watch `%s`: %s"),
|
|
|
12745e |
+ finfo->fname, strerror (errno));
|
|
|
12745e |
+ }
|
|
|
12745e |
+ finfo->inotify_descr[TRACED_FILE] = -1;
|
|
|
12745e |
+ to_clear[dbcnt] = true;
|
|
|
12745e |
+ if (finfo->call_res_init)
|
|
|
12745e |
+ res_init ();
|
|
|
12745e |
+ return;
|
|
|
12745e |
+ }
|
|
|
12745e |
+ /* The configuration file was open for writing and has just closed.
|
|
|
12745e |
+ We reset the cache and reinitialize. */
|
|
|
12745e |
+ if (finfo->inotify_descr[TRACED_FILE] == inev->i.wd
|
|
|
12745e |
+ && inev->i.mask & IN_CLOSE_WRITE)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ /* Mark cache as needing to be cleared and reinitialize. */
|
|
|
12745e |
+ dbg_log (_("monitored file `%s` was written to"), finfo->fname);
|
|
|
12745e |
+ to_clear[dbcnt] = true;
|
|
|
12745e |
+ if (finfo->call_res_init)
|
|
|
12745e |
+ res_init ();
|
|
|
12745e |
+ return;
|
|
|
12745e |
+ }
|
|
|
12745e |
+ /* The parent directory was moved or deleted. We trigger one last
|
|
|
12745e |
+ invalidation. At the next pruning or invalidation we may add
|
|
|
12745e |
+ this watch back if the file is present again. */
|
|
|
12745e |
+ if (finfo->inotify_descr[TRACED_DIR] == inev->i.wd
|
|
|
12745e |
+ && ((inev->i.mask & IN_DELETE_SELF)
|
|
|
12745e |
+ || (inev->i.mask & IN_MOVE_SELF)
|
|
|
12745e |
+ || (inev->i.mask & IN_IGNORED)))
|
|
|
12745e |
+ {
|
|
|
12745e |
+ bool moved = (inev->i.mask & IN_MOVE_SELF) != 0;
|
|
|
12745e |
+ /* The directory watch may have already been removed
|
|
|
12745e |
+ but we don't know so we just remove it again and
|
|
|
12745e |
+ ignore the error. Then we remove the file watch.
|
|
|
12745e |
+ Note: watches are automatically removed for deleted
|
|
|
12745e |
+ files. */
|
|
|
12745e |
+ if (moved)
|
|
|
12745e |
+ inotify_rm_watch (inotify_fd, inev->i.wd);
|
|
|
12745e |
+ if (finfo->inotify_descr[TRACED_FILE] != -1)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ dbg_log (_("monitored parent directory `%s` was %s, removing watch on `%s`"),
|
|
|
12745e |
+ finfo->dname, moved ? "moved" : "deleted", finfo->fname);
|
|
|
12745e |
+ if (inotify_rm_watch (inotify_fd, finfo->inotify_descr[TRACED_FILE]) < 0)
|
|
|
12745e |
+ dbg_log (_("failed to remove file watch `%s`: %s"),
|
|
|
12745e |
+ finfo->dname, strerror (errno));
|
|
|
12745e |
+ }
|
|
|
12745e |
+ finfo->inotify_descr[TRACED_FILE] = -1;
|
|
|
12745e |
+ finfo->inotify_descr[TRACED_DIR] = -1;
|
|
|
12745e |
+ to_clear[dbcnt] = true;
|
|
|
12745e |
+ if (finfo->call_res_init)
|
|
|
12745e |
+ res_init ();
|
|
|
12745e |
+ /* Continue to the next entry since this might be the
|
|
|
12745e |
+ parent directory for multiple registered files and
|
|
|
12745e |
+ we want to remove watches for all registered files. */
|
|
|
12745e |
+ continue;
|
|
|
12745e |
+ }
|
|
|
12745e |
+ /* The parent directory had a create or moved to event. */
|
|
|
12745e |
+ if (finfo->inotify_descr[TRACED_DIR] == inev->i.wd
|
|
|
12745e |
+ && ((inev->i.mask & IN_MOVED_TO)
|
|
|
12745e |
+ || (inev->i.mask & IN_CREATE))
|
|
|
12745e |
+ && strcmp (inev->i.name, finfo->sfname) == 0)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ /* We detected a directory change. We look for the creation
|
|
|
12745e |
+ of the file we are tracking or the move of the same file
|
|
|
12745e |
+ into the directory. */
|
|
|
12745e |
+ int ret;
|
|
|
12745e |
+ dbg_log (_("monitored file `%s` was %s, adding watch"),
|
|
|
12745e |
+ finfo->fname,
|
|
|
12745e |
+ inev->i.mask & IN_CREATE ? "created" : "moved into place");
|
|
|
12745e |
+ /* File was moved in or created. Regenerate the watch. */
|
|
|
12745e |
+ if (finfo->inotify_descr[TRACED_FILE] != -1)
|
|
|
12745e |
+ inotify_rm_watch (inotify_fd,
|
|
|
12745e |
+ finfo->inotify_descr[TRACED_FILE]);
|
|
|
12745e |
+
|
|
|
12745e |
+ ret = inotify_add_watch (inotify_fd,
|
|
|
12745e |
+ finfo->fname,
|
|
|
12745e |
+ TRACED_FILE_MASK);
|
|
|
12745e |
+ if (ret < 0)
|
|
|
12745e |
+ dbg_log (_("failed to add file watch `%s`: %s"),
|
|
|
12745e |
+ finfo->fname, strerror (errno));
|
|
|
12745e |
+
|
|
|
12745e |
+ finfo->inotify_descr[TRACED_FILE] = ret;
|
|
|
12745e |
+
|
|
|
12745e |
+ /* The file is new or moved so mark cache as needing to
|
|
|
12745e |
+ be cleared and reinitialize. */
|
|
|
12745e |
+ to_clear[dbcnt] = true;
|
|
|
12745e |
+ if (finfo->call_res_init)
|
|
|
12745e |
+ res_init ();
|
|
|
12745e |
+
|
|
|
12745e |
+ /* Done re-adding the watch. Don't return, we may still
|
|
|
12745e |
+ have other files in this same directory, same watch
|
|
|
12745e |
+ descriptor, and need to process them. */
|
|
|
12745e |
+ }
|
|
|
12745e |
+ /* Other events are ignored, and we move on to the next file. */
|
|
|
12745e |
+ finfo = finfo->next;
|
|
|
12745e |
+ }
|
|
|
12745e |
+ }
|
|
|
12745e |
+}
|
|
|
12745e |
+
|
|
|
12745e |
+/* If an entry in the array of booleans TO_CLEAR is TRUE then clear the cache
|
|
|
12745e |
+ for the associated database, otherwise do nothing. The TO_CLEAR array must
|
|
|
12745e |
+ have LASTDB entries. */
|
|
|
12745e |
+static inline void
|
|
|
12745e |
+clear_db_cache (bool *to_clear)
|
|
|
12745e |
+{
|
|
|
12745e |
+ for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
|
|
|
12745e |
+ if (to_clear[dbcnt])
|
|
|
12745e |
+ {
|
|
|
12745e |
+ pthread_mutex_lock (&dbs[dbcnt].prune_lock);
|
|
|
12745e |
+ dbs[dbcnt].clear_cache = 1;
|
|
|
12745e |
+ pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
|
|
|
12745e |
+ pthread_cond_signal (&dbs[dbcnt].prune_cond);
|
|
|
12745e |
+ }
|
|
|
12745e |
+}
|
|
|
12745e |
+
|
|
|
12745e |
+int
|
|
|
12745e |
+handle_inotify_events (void)
|
|
|
12745e |
+{
|
|
|
12745e |
+ bool to_clear[lastdb] = { false, };
|
|
|
12745e |
+ union __inev inev;
|
|
|
12745e |
+
|
|
|
12745e |
+ /* Read all inotify events for files registered via
|
|
|
12745e |
+ register_traced_file(). */
|
|
|
12745e |
+ while (1)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ /* Potentially read multiple events into buf. */
|
|
|
12745e |
+ ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd,
|
|
|
12745e |
+ &inev.buf,
|
|
|
12745e |
+ sizeof (inev)));
|
|
|
12745e |
+ if (nb < (ssize_t) sizeof (struct inotify_event))
|
|
|
12745e |
+ {
|
|
|
12745e |
+ /* Not even 1 event. */
|
|
|
12745e |
+ if (__glibc_unlikely (nb == -1 && errno != EAGAIN))
|
|
|
12745e |
+ return -1;
|
|
|
12745e |
+ /* Done reading events that are ready. */
|
|
|
12745e |
+ break;
|
|
|
12745e |
+ }
|
|
|
12745e |
+ /* Process all events. The normal inotify interface delivers
|
|
|
12745e |
+ complete events on a read and never a partial event. */
|
|
|
12745e |
+ char *eptr = &inev.buf[0];
|
|
|
12745e |
+ ssize_t count;
|
|
|
12745e |
+ while (1)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ /* Check which of the files changed. */
|
|
|
12745e |
+ inotify_check_files (to_clear, &inev);
|
|
|
12745e |
+ count = sizeof (struct inotify_event) + inev.i.len;
|
|
|
12745e |
+ eptr += count;
|
|
|
12745e |
+ nb -= count;
|
|
|
12745e |
+ if (nb >= (ssize_t) sizeof (struct inotify_event))
|
|
|
12745e |
+ memcpy (&inev, eptr, nb);
|
|
|
12745e |
+ else
|
|
|
12745e |
+ break;
|
|
|
12745e |
+ }
|
|
|
12745e |
+ continue;
|
|
|
12745e |
+ }
|
|
|
12745e |
+ /* Actually perform the cache clearing. */
|
|
|
12745e |
+ clear_db_cache (to_clear);
|
|
|
12745e |
+ return 0;
|
|
|
12745e |
+}
|
|
|
12745e |
+
|
|
|
12745e |
+#endif
|
|
|
12745e |
+
|
|
|
12745e |
static void
|
|
|
12745e |
__attribute__ ((__noreturn__))
|
|
|
12745e |
main_loop_poll (void)
|
|
|
12745e |
@@ -1975,72 +2242,21 @@
|
|
|
12745e |
{
|
|
|
12745e |
if (conns[1].revents != 0)
|
|
|
12745e |
{
|
|
|
12745e |
- bool to_clear[lastdb] = { false, };
|
|
|
12745e |
- union
|
|
|
12745e |
- {
|
|
|
12745e |
-# ifndef PATH_MAX
|
|
|
12745e |
-# define PATH_MAX 1024
|
|
|
12745e |
-# endif
|
|
|
12745e |
- struct inotify_event i;
|
|
|
12745e |
- char buf[sizeof (struct inotify_event) + PATH_MAX];
|
|
|
12745e |
- } inev;
|
|
|
12745e |
-
|
|
|
12745e |
- while (1)
|
|
|
12745e |
- {
|
|
|
12745e |
- ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
|
|
|
12745e |
- sizeof (inev)));
|
|
|
12745e |
- if (nb < (ssize_t) sizeof (struct inotify_event))
|
|
|
12745e |
- {
|
|
|
12745e |
- if (__builtin_expect (nb == -1 && errno != EAGAIN,
|
|
|
12745e |
- 0))
|
|
|
12745e |
- {
|
|
|
12745e |
- /* Something went wrong when reading the inotify
|
|
|
12745e |
- data. Better disable inotify. */
|
|
|
12745e |
- dbg_log (_("\
|
|
|
12745e |
-disabled inotify after read error %d"),
|
|
|
12745e |
- errno);
|
|
|
12745e |
- conns[1].fd = -1;
|
|
|
12745e |
- firstfree = 1;
|
|
|
12745e |
- if (nused == 2)
|
|
|
12745e |
- nused = 1;
|
|
|
12745e |
- close (inotify_fd);
|
|
|
12745e |
- inotify_fd = -1;
|
|
|
12745e |
- }
|
|
|
12745e |
- break;
|
|
|
12745e |
- }
|
|
|
12745e |
-
|
|
|
12745e |
- /* Check which of the files changed. */
|
|
|
12745e |
- for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
|
|
|
12745e |
- {
|
|
|
12745e |
- struct traced_file *finfo = dbs[dbcnt].traced_files;
|
|
|
12745e |
-
|
|
|
12745e |
- while (finfo != NULL)
|
|
|
12745e |
- {
|
|
|
12745e |
- if (finfo->inotify_descr == inev.i.wd)
|
|
|
12745e |
- {
|
|
|
12745e |
- to_clear[dbcnt] = true;
|
|
|
12745e |
- if (finfo->call_res_init)
|
|
|
12745e |
- res_init ();
|
|
|
12745e |
- goto next;
|
|
|
12745e |
- }
|
|
|
12745e |
-
|
|
|
12745e |
- finfo = finfo->next;
|
|
|
12745e |
- }
|
|
|
12745e |
- }
|
|
|
12745e |
- next:;
|
|
|
12745e |
- }
|
|
|
12745e |
-
|
|
|
12745e |
- /* Actually perform the cache clearing. */
|
|
|
12745e |
- for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
|
|
|
12745e |
- if (to_clear[dbcnt])
|
|
|
12745e |
- {
|
|
|
12745e |
- pthread_mutex_lock (&dbs[dbcnt].prune_lock);
|
|
|
12745e |
- dbs[dbcnt].clear_cache = 1;
|
|
|
12745e |
- pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
|
|
|
12745e |
- pthread_cond_signal (&dbs[dbcnt].prune_cond);
|
|
|
12745e |
- }
|
|
|
12745e |
-
|
|
|
12745e |
- --n;
|
|
|
12745e |
+ int ret;
|
|
|
12745e |
+ ret = handle_inotify_events ();
|
|
|
12745e |
+ if (ret == -1)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ /* Something went wrong when reading the inotify
|
|
|
12745e |
+ data. Better disable inotify. */
|
|
|
12745e |
+ dbg_log (_("disabled inotify-based monitoring after read error %d"), errno);
|
|
|
12745e |
+ conns[1].fd = -1;
|
|
|
12745e |
+ firstfree = 1;
|
|
|
12745e |
+ if (nused == 2)
|
|
|
12745e |
+ nused = 1;
|
|
|
12745e |
+ close (inotify_fd);
|
|
|
12745e |
+ inotify_fd = -1;
|
|
|
12745e |
+ }
|
|
|
12745e |
+ --n;
|
|
|
12745e |
}
|
|
|
12745e |
|
|
|
12745e |
first = 2;
|
|
|
12745e |
@@ -2207,64 +2423,18 @@
|
|
|
12745e |
# ifdef HAVE_INOTIFY
|
|
|
12745e |
else if (revs[cnt].data.fd == inotify_fd)
|
|
|
12745e |
{
|
|
|
12745e |
- bool to_clear[lastdb] = { false, };
|
|
|
12745e |
- union
|
|
|
12745e |
- {
|
|
|
12745e |
- struct inotify_event i;
|
|
|
12745e |
- char buf[sizeof (struct inotify_event) + PATH_MAX];
|
|
|
12745e |
- } inev;
|
|
|
12745e |
-
|
|
|
12745e |
- while (1)
|
|
|
12745e |
+ int ret;
|
|
|
12745e |
+ ret = handle_inotify_events ();
|
|
|
12745e |
+ if (ret == -1)
|
|
|
12745e |
{
|
|
|
12745e |
- ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev,
|
|
|
12745e |
- sizeof (inev)));
|
|
|
12745e |
- if (nb < (ssize_t) sizeof (struct inotify_event))
|
|
|
12745e |
- {
|
|
|
12745e |
- if (__builtin_expect (nb == -1 && errno != EAGAIN, 0))
|
|
|
12745e |
- {
|
|
|
12745e |
- /* Something went wrong when reading the inotify
|
|
|
12745e |
- data. Better disable inotify. */
|
|
|
12745e |
- dbg_log (_("disabled inotify after read error %d"),
|
|
|
12745e |
- errno);
|
|
|
12745e |
- (void) epoll_ctl (efd, EPOLL_CTL_DEL, inotify_fd,
|
|
|
12745e |
- NULL);
|
|
|
12745e |
- close (inotify_fd);
|
|
|
12745e |
- inotify_fd = -1;
|
|
|
12745e |
- }
|
|
|
12745e |
- break;
|
|
|
12745e |
- }
|
|
|
12745e |
-
|
|
|
12745e |
- /* Check which of the files changed. */
|
|
|
12745e |
- for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
|
|
|
12745e |
- {
|
|
|
12745e |
- struct traced_file *finfo = dbs[dbcnt].traced_files;
|
|
|
12745e |
-
|
|
|
12745e |
- while (finfo != NULL)
|
|
|
12745e |
- {
|
|
|
12745e |
- if (finfo->inotify_descr == inev.i.wd)
|
|
|
12745e |
- {
|
|
|
12745e |
- to_clear[dbcnt] = true;
|
|
|
12745e |
- if (finfo->call_res_init)
|
|
|
12745e |
- res_init ();
|
|
|
12745e |
- goto next;
|
|
|
12745e |
- }
|
|
|
12745e |
-
|
|
|
12745e |
- finfo = finfo->next;
|
|
|
12745e |
- }
|
|
|
12745e |
- }
|
|
|
12745e |
- next:;
|
|
|
12745e |
- }
|
|
|
12745e |
-
|
|
|
12745e |
- /* Actually perform the cache clearing. */
|
|
|
12745e |
- for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt)
|
|
|
12745e |
- if (to_clear[dbcnt])
|
|
|
12745e |
- {
|
|
|
12745e |
- pthread_mutex_lock (&dbs[dbcnt].prune_lock);
|
|
|
12745e |
- dbs[dbcnt].clear_cache = 1;
|
|
|
12745e |
- pthread_mutex_unlock (&dbs[dbcnt].prune_lock);
|
|
|
12745e |
- pthread_cond_signal (&dbs[dbcnt].prune_cond);
|
|
|
12745e |
- }
|
|
|
12745e |
- }
|
|
|
12745e |
+ /* Something went wrong when reading the inotify
|
|
|
12745e |
+ data. Better disable inotify. */
|
|
|
12745e |
+ dbg_log (_("disabled inotify-based monitoring after read error %d"), errno);
|
|
|
12745e |
+ close (inotify_fd);
|
|
|
12745e |
+ inotify_fd = -1;
|
|
|
12745e |
+ break;
|
|
|
12745e |
+ }
|
|
|
12745e |
+ }
|
|
|
12745e |
# endif
|
|
|
12745e |
# ifdef HAVE_NETLINK
|
|
|
12745e |
else if (revs[cnt].data.fd == nl_status_fd)
|
|
|
12745e |
@@ -2300,7 +2470,9 @@
|
|
|
12745e |
no reply in too long of a time. */
|
|
|
12745e |
time_t laststart = now - ACCEPT_TIMEOUT;
|
|
|
12745e |
assert (starttime[sock] == 0);
|
|
|
12745e |
+# ifdef HAVE_INOTIFY
|
|
|
12745e |
assert (inotify_fd == -1 || starttime[inotify_fd] == 0);
|
|
|
12745e |
+# endif
|
|
|
12745e |
assert (nl_status_fd == -1 || starttime[nl_status_fd] == 0);
|
|
|
12745e |
for (int cnt = highest; cnt > STDERR_FILENO; --cnt)
|
|
|
12745e |
if (starttime[cnt] != 0 && starttime[cnt] < laststart)
|
|
|
12745e |
--- glibc-2.17-c758a686/nscd/nscd.h 2015-05-12 15:03:02.870274443 -0400
|
|
|
12745e |
+++ glibc-2.17-c758a686/nscd/nscd.h 2015-05-13 13:45:57.259958374 -0400
|
|
|
12745e |
@@ -61,17 +61,67 @@
|
|
|
12745e |
80% of the thread stack size. */
|
|
|
12745e |
#define MAX_STACK_USE ((8 * NSCD_THREAD_STACKSIZE) / 10)
|
|
|
12745e |
|
|
|
12745e |
-
|
|
|
12745e |
-/* Registered filename used to fill database. */
|
|
|
12745e |
+/* Records the file registered per database that when changed
|
|
|
12745e |
+ or modified requires invalidating the database. */
|
|
|
12745e |
struct traced_file
|
|
|
12745e |
{
|
|
|
12745e |
+ /* Tracks the last modified time of the traced file. */
|
|
|
12745e |
time_t mtime;
|
|
|
12745e |
+ /* Support multiple registered files per database. */
|
|
|
12745e |
struct traced_file *next;
|
|
|
12745e |
int call_res_init;
|
|
|
12745e |
- int inotify_descr;
|
|
|
12745e |
+ /* Requires Inotify support to do anything useful. */
|
|
|
12745e |
+#define TRACED_FILE 0
|
|
|
12745e |
+#define TRACED_DIR 1
|
|
|
12745e |
+ int inotify_descr[2];
|
|
|
12745e |
+# ifndef PATH_MAX
|
|
|
12745e |
+# define PATH_MAX 1024
|
|
|
12745e |
+# endif
|
|
|
12745e |
+ /* The parent directory is used to scan for creation/deletion. */
|
|
|
12745e |
+ char dname[PATH_MAX];
|
|
|
12745e |
+ /* Just the name of the file with no directory component. */
|
|
|
12745e |
+ char *sfname;
|
|
|
12745e |
+ /* The full-path name of the registered file. */
|
|
|
12745e |
char fname[];
|
|
|
12745e |
};
|
|
|
12745e |
|
|
|
12745e |
+/* Initialize a `struct traced_file`. As input we need the name
|
|
|
12745e |
+ of the file, and if invalidation requires calling res_init.
|
|
|
12745e |
+ If CRINIT is 1 then res_init will be called after invalidation
|
|
|
12745e |
+ or if the traced file is changed in any way, otherwise it will
|
|
|
12745e |
+ not. */
|
|
|
12745e |
+static inline void
|
|
|
12745e |
+init_traced_file(struct traced_file *file, const char *fname, int crinit)
|
|
|
12745e |
+{
|
|
|
12745e |
+ char *dname;
|
|
|
12745e |
+ file->mtime = 0;
|
|
|
12745e |
+ file->inotify_descr[TRACED_FILE] = -1;
|
|
|
12745e |
+ file->inotify_descr[TRACED_DIR] = -1;
|
|
|
12745e |
+ strcpy (file->fname, fname);
|
|
|
12745e |
+ /* Compute the parent directory name and store a copy. The copy makes
|
|
|
12745e |
+ it much faster to add/remove watches while nscd is running instead
|
|
|
12745e |
+ of computing this over and over again in a temp buffer. */
|
|
|
12745e |
+ file->dname[0] = '\0';
|
|
|
12745e |
+ dname = strrchr (fname, '/');
|
|
|
12745e |
+ if (dname != NULL)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ size_t len = (size_t)(dname - fname);
|
|
|
12745e |
+ if (len > sizeof (file->dname))
|
|
|
12745e |
+ abort ();
|
|
|
12745e |
+ strncpy (file->dname, file->fname, len);
|
|
|
12745e |
+ file->dname[len] = '\0';
|
|
|
12745e |
+ }
|
|
|
12745e |
+ /* The basename is the name just after the last forward slash. */
|
|
|
12745e |
+ file->sfname = &dname[1];
|
|
|
12745e |
+ file->call_res_init = crinit;
|
|
|
12745e |
+}
|
|
|
12745e |
+
|
|
|
12745e |
+#define define_traced_file(id, filename) \
|
|
|
12745e |
+static union \
|
|
|
12745e |
+{ \
|
|
|
12745e |
+ struct traced_file file; \
|
|
|
12745e |
+ char buf[sizeof (struct traced_file) + sizeof (filename)]; \
|
|
|
12745e |
+} id##_traced_file;
|
|
|
12745e |
|
|
|
12745e |
/* Structure describing dynamic part of one database. */
|
|
|
12745e |
struct database_dyn
|
|
|
12745e |
@@ -90,7 +140,6 @@
|
|
|
12745e |
int propagate;
|
|
|
12745e |
struct traced_file *traced_files;
|
|
|
12745e |
const char *db_filename;
|
|
|
12745e |
- time_t file_mtime;
|
|
|
12745e |
size_t suggested_module;
|
|
|
12745e |
size_t max_db_size;
|
|
|
12745e |
|
|
|
12745e |
@@ -216,6 +265,9 @@
|
|
|
12745e |
/* connections.c */
|
|
|
12745e |
extern void nscd_init (void);
|
|
|
12745e |
extern void register_traced_file (size_t dbidx, struct traced_file *finfo);
|
|
|
12745e |
+#ifdef HAVE_INOTIFY
|
|
|
12745e |
+extern void install_watches (struct traced_file *finfo);
|
|
|
12745e |
+#endif
|
|
|
12745e |
extern void close_sockets (void);
|
|
|
12745e |
extern void start_threads (void) __attribute__ ((__noreturn__));
|
|
|
12745e |
|
|
|
12745e |
--- glibc-2.17-c758a686/nss/nss_db/db-init.c 2012-12-24 22:02:13.000000000 -0500
|
|
|
12745e |
+++ glibc-2.17-c758a686/nss/nss_db/db-init.c 2015-05-13 13:45:57.269958504 -0400
|
|
|
12745e |
@@ -22,35 +22,25 @@
|
|
|
12745e |
#include <nscd/nscd.h>
|
|
|
12745e |
#include <string.h>
|
|
|
12745e |
|
|
|
12745e |
-static union
|
|
|
12745e |
-{
|
|
|
12745e |
- struct traced_file file;
|
|
|
12745e |
- char buf[sizeof (struct traced_file) + sizeof (_PATH_VARDB "passwd.db")];
|
|
|
12745e |
-} pwd_traced_file;
|
|
|
12745e |
-
|
|
|
12745e |
-static union
|
|
|
12745e |
-{
|
|
|
12745e |
- struct traced_file file;
|
|
|
12745e |
- char buf[sizeof (struct traced_file) + sizeof (_PATH_VARDB "group.db")];
|
|
|
12745e |
-} grp_traced_file;
|
|
|
12745e |
+#define PWD_FILENAME (_PATH_VARDB "passwd.db")
|
|
|
12745e |
+define_traced_file (pwd, PWD_FILENAME);
|
|
|
12745e |
|
|
|
12745e |
-static union
|
|
|
12745e |
-{
|
|
|
12745e |
- struct traced_file file;
|
|
|
12745e |
- char buf[sizeof (struct traced_file) + sizeof (_PATH_VARDB "services.db")];
|
|
|
12745e |
-} serv_traced_file;
|
|
|
12745e |
+#define GRP_FILENAME (_PATH_VARDB "group.db")
|
|
|
12745e |
+define_traced_file (grp, GRP_FILENAME);
|
|
|
12745e |
|
|
|
12745e |
+#define SERV_FILENAME (_PATH_VARDB "services.db")
|
|
|
12745e |
+define_traced_file (serv, SERV_FILENAME);
|
|
|
12745e |
|
|
|
12745e |
void
|
|
|
12745e |
_nss_db_init (void (*cb) (size_t, struct traced_file *))
|
|
|
12745e |
{
|
|
|
12745e |
- strcpy (pwd_traced_file.file.fname,_PATH_VARDB "passwd.db");
|
|
|
12745e |
+ init_traced_file (&pwd_traced_file.file, PWD_FILENAME, 0);
|
|
|
12745e |
cb (pwddb, &pwd_traced_file.file);
|
|
|
12745e |
|
|
|
12745e |
- strcpy (grp_traced_file.file.fname, _PATH_VARDB "group.db");
|
|
|
12745e |
+ init_traced_file (&grp_traced_file.file, GRP_FILENAME, 0);
|
|
|
12745e |
cb (grpdb, &grp_traced_file.file);
|
|
|
12745e |
|
|
|
12745e |
- strcpy (serv_traced_file.file.fname, _PATH_VARDB "services.db");
|
|
|
12745e |
+ init_traced_file (&serv_traced_file.file, SERV_FILENAME, 0);
|
|
|
12745e |
cb (servdb, &serv_traced_file.file);
|
|
|
12745e |
}
|
|
|
12745e |
|
|
|
12745e |
--- glibc-2.17-c758a686/nss/nss_files/files-init.c 2012-12-24 22:02:13.000000000 -0500
|
|
|
12745e |
+++ glibc-2.17-c758a686/nss/nss_files/files-init.c 2015-05-13 13:45:57.269958504 -0400
|
|
|
12745e |
@@ -18,43 +18,46 @@
|
|
|
12745e |
|
|
|
12745e |
#ifdef USE_NSCD
|
|
|
12745e |
|
|
|
12745e |
+#include <string.h>
|
|
|
12745e |
#include <nscd/nscd.h>
|
|
|
12745e |
|
|
|
12745e |
+#define PWD_FILENAME "/etc/passwd"
|
|
|
12745e |
+define_traced_file (pwd, PWD_FILENAME);
|
|
|
12745e |
|
|
|
12745e |
-#define TF(id, filename, ...) \
|
|
|
12745e |
-static union \
|
|
|
12745e |
-{ \
|
|
|
12745e |
- struct traced_file file; \
|
|
|
12745e |
- char buf[sizeof (struct traced_file) + sizeof (filename)]; \
|
|
|
12745e |
-} id##_traced_file = \
|
|
|
12745e |
- { \
|
|
|
12745e |
- .file = \
|
|
|
12745e |
- { \
|
|
|
12745e |
- .fname = filename, ## __VA_ARGS__ \
|
|
|
12745e |
- } \
|
|
|
12745e |
- }
|
|
|
12745e |
-
|
|
|
12745e |
-TF (pwd, "/etc/passwd");
|
|
|
12745e |
-TF (grp, "/etc/group");
|
|
|
12745e |
-TF (hst, "/etc/hosts");
|
|
|
12745e |
-TF (resolv, "/etc/resolv.conf", .call_res_init = 1);
|
|
|
12745e |
-TF (serv, "/etc/services");
|
|
|
12745e |
-TF (netgr, "/etc/netgroup");
|
|
|
12745e |
-
|
|
|
12745e |
-
|
|
|
12745e |
+#define GRP_FILENAME "/etc/group"
|
|
|
12745e |
+define_traced_file (grp, GRP_FILENAME);
|
|
|
12745e |
+
|
|
|
12745e |
+#define HST_FILENAME "/etc/hosts"
|
|
|
12745e |
+define_traced_file (hst, HST_FILENAME);
|
|
|
12745e |
+
|
|
|
12745e |
+#define RESOLV_FILENAME "/etc/resolv.conf"
|
|
|
12745e |
+define_traced_file (resolv, RESOLV_FILENAME);
|
|
|
12745e |
+
|
|
|
12745e |
+#define SERV_FILENAME "/etc/services"
|
|
|
12745e |
+define_traced_file (serv, SERV_FILENAME);
|
|
|
12745e |
+
|
|
|
12745e |
+#define NETGR_FILENAME "/etc/netgroup"
|
|
|
12745e |
+define_traced_file (netgr, NETGR_FILENAME);
|
|
|
12745e |
+
|
|
|
12745e |
void
|
|
|
12745e |
_nss_files_init (void (*cb) (size_t, struct traced_file *))
|
|
|
12745e |
{
|
|
|
12745e |
+ init_traced_file (&pwd_traced_file.file, PWD_FILENAME, 0);
|
|
|
12745e |
cb (pwddb, &pwd_traced_file.file);
|
|
|
12745e |
|
|
|
12745e |
+ init_traced_file (&grp_traced_file.file, GRP_FILENAME, 0);
|
|
|
12745e |
cb (grpdb, &grp_traced_file.file);
|
|
|
12745e |
|
|
|
12745e |
+ init_traced_file (&hst_traced_file.file, HST_FILENAME, 0);
|
|
|
12745e |
cb (hstdb, &hst_traced_file.file);
|
|
|
12745e |
|
|
|
12745e |
+ init_traced_file (&resolv_traced_file.file, RESOLV_FILENAME, 1);
|
|
|
12745e |
cb (hstdb, &resolv_traced_file.file);
|
|
|
12745e |
|
|
|
12745e |
+ init_traced_file (&serv_traced_file.file, SERV_FILENAME, 0);
|
|
|
12745e |
cb (servdb, &serv_traced_file.file);
|
|
|
12745e |
-
|
|
|
12745e |
+
|
|
|
12745e |
+ init_traced_file (&netgr_traced_file.file, NETGR_FILENAME, 0);
|
|
|
12745e |
cb (netgrdb, &netgr_traced_file.file);
|
|
|
12745e |
}
|
|
|
12745e |
|