Revert all changes since a36d4918a6f646e085
[platform/upstream/dbus.git] / bus / dir-watch-kqueue.c
index d491284..4e436eb 100644 (file)
@@ -17,7 +17,7 @@
  * 
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 
 #include <dbus/dbus-watch.h>
 
 #include <dbus/dbus-internals.h>
+#include <dbus/dbus-list.h>
 #include "dir-watch.h"
 
 #define MAX_DIRS_TO_WATCH 128
 
 static int kq = -1;
 static int fds[MAX_DIRS_TO_WATCH];
+static char *dirs[MAX_DIRS_TO_WATCH];
 static int num_fds = 0;
 static DBusWatch *watch = NULL;
 static DBusLoop *loop = NULL;
@@ -90,13 +92,10 @@ _handle_kqueue_watch (DBusWatch *watch, unsigned int flags, void *data)
   return TRUE;
 }
 
-void
-bus_watch_directory (const char *dir, BusContext *context)
+static int
+_init_kqueue (BusContext *context)
 {
-  int fd;
-  struct kevent ev;
-
-  _dbus_assert (dir != NULL);
+  int ret = 0;
 
   if (kq < 0)
     {
@@ -133,49 +132,124 @@ bus_watch_directory (const char *dir, BusContext *context)
          }
     }
 
-  if (num_fds >= MAX_DIRS_TO_WATCH )
+  ret = 1;
+
+out:
+  return ret;
+}
+
+void
+bus_set_watched_dirs (BusContext *context, DBusList **directories)
+{
+  int new_fds[MAX_DIRS_TO_WATCH];
+  char *new_dirs[MAX_DIRS_TO_WATCH];
+  DBusList *link;
+  int i, j, f, fd;
+  struct kevent ev;
+
+  if (!_init_kqueue (context))
+    goto out;
+
+  for (i = 0; i < MAX_DIRS_TO_WATCH; i++)
     {
-      _dbus_warn ("Cannot watch config directory '%s'. Already watching %d directories\n", dir, MAX_DIRS_TO_WATCH);
-      goto out;
+      new_fds[i] = -1;
+      new_dirs[i] = NULL;
     }
 
-  fd = open (dir, O_RDONLY);
-  if (fd < 0)
+  i = 0;
+  link = _dbus_list_get_first_link (directories);
+  while (link != NULL)
     {
-      _dbus_warn ("Cannot open directory '%s'; error '%s'\n", dir, _dbus_strerror (errno));
-      goto out;
+      new_dirs[i++] = (char *)link->data;
+      link = _dbus_list_get_next_link (directories, link);
     }
 
-  EV_SET (&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
-          NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_RENAME, 0, 0);
-  if (kevent (kq, &ev, 1, NULL, 0, NULL) == -1)
+  /* Look for directories in both the old and new sets, if
+   * we find one, move its data into the new set.
+   */
+  for (i = 0; new_dirs[i]; i++)
     {
-      _dbus_warn ("Cannot setup a kevent for '%s'; error '%s'\n", dir, _dbus_strerror (errno));
-      close (fd);
-      goto out;
+      for (j = 0; j < num_fds; j++)
+        {
+          if (dirs[j] && strcmp (new_dirs[i], dirs[j]) == 0)
+            {
+              new_fds[i] = fds[j];
+             new_dirs[i] = dirs[j];
+             fds[j] = -1;
+             dirs[j] = NULL;
+             break;
+           }
+       }
     }
 
-  fds[num_fds++] = fd;
-  _dbus_verbose ("Added kqueue watch on config directory '%s'\n", dir);
-
- out:
-  ;
-}
-
-void
-bus_drop_all_directory_watches (void)
-{
-  int i;
-
-  _dbus_verbose ("Dropping all watches on config directories\n");
+  /* Any directory we find in "fds" with a nonzero fd must
+   * not be in the new set, so perform cleanup now.
+   */
+  for (j = 0; j < num_fds; j++)
+    {
+      if (fds[j] != -1)
+        {
+          close (fds[j]);
+         dbus_free (dirs[j]);
+         fds[j] = -1;
+         dirs[j] = NULL;
+       }
+    }
 
-  for (i = 0; i < num_fds; i++)
+  for (i = 0; new_dirs[i]; i++)
     {
-      if (close (fds[i]) != 0)
+      if (new_fds[i] == -1)
         {
-          _dbus_verbose ("Error closing fd %d for config directory watch\n", fds[i]);
+          /* FIXME - less lame error handling for failing to add a watch;
+          * we may need to sleep.
+          */
+          fd = open (new_dirs[i], O_RDONLY);
+          if (fd < 0)
+            {
+              if (errno != ENOENT)
+                {
+                  _dbus_warn ("Cannot open directory '%s'; error '%s'\n", new_dirs[i], _dbus_strerror (errno));
+                  goto out;
+                }
+              else
+                {
+                  new_fds[i] = -1;
+                  new_dirs[i] = NULL;
+                  continue;
+                }
+            }
+
+          EV_SET (&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
+                  NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_RENAME, 0, 0);
+          if (kevent (kq, &ev, 1, NULL, 0, NULL) == -1)
+            {
+              _dbus_warn ("Cannot setup a kevent for '%s'; error '%s'\n", new_dirs[i], _dbus_strerror (errno));
+              close (fd);
+              goto out;
+            }
+
+         new_fds[i] = fd;
+         new_dirs[i] = _dbus_strdup (new_dirs[i]);
+         if (!new_dirs[i])
+            {
+              /* FIXME have less lame handling for OOM, we just silently fail to
+              * watch.  (In reality though, the whole OOM handling in dbus is
+              * stupid but we won't go into that in this comment =) )
+              */
+              close (fd);
+             new_fds[i] = -1;
+           }
        }
     }
 
-  num_fds = 0;
+  num_fds = i;
+
+  for (i = 0; i < MAX_DIRS_TO_WATCH; i++)
+    {
+      fds[i] = new_fds[i];
+      dirs[i] = new_dirs[i];
+    }
+
+ out:
+  ;
 }