hal: Branch 'master' - 2 commits

David Zeuthen david at kemper.freedesktop.org
Fri Apr 6 18:07:47 PDT 2007


 hald/Makefile.am              |    3 
 hald/freebsd/osspec.c         |    7 
 hald/hal-file-monitor.h       |   86 +++++
 hald/hald.c                   |  130 +++++++-
 hald/hald_dbus.c              |   73 ++--
 hald/hald_dbus.h              |    2 
 hald/linux/Makefile.am        |   35 --
 hald/linux/hal-file-monitor.c |  676 ++++++++++++++++++++++++++++++++++++++++++
 hald/linux/osspec.c           |   37 +-
 hald/osspec.h                 |    3 
 hald/solaris/osspec.c         |    7 
 privileges/Makefile.am        |    9 
 tools/hal-acl-tool.c          |    8 
 13 files changed, 993 insertions(+), 83 deletions(-)

New commits:
diff-tree 8c1b67d8dd16b69e4b4be7b6ae8cebf65b90aeb3 (from c7f7bfcbfa708874497c519b2b8a41fbec9406d7)
Author: David Zeuthen <davidz at redhat.com>
Date:   Fri Apr 6 21:07:31 2007 -0400

    use new file monitoring interface and integrate witk PK master
    
    Yay, I can now edit my privilege configuration files and see
    permissions on /dev/scd0 change in real time. Very cool.

diff --git a/hald/Makefile.am b/hald/Makefile.am
index 47d9b44..0625f4a 100644
--- a/hald/Makefile.am
+++ b/hald/Makefile.am
@@ -66,7 +66,8 @@ hald_SOURCES =                          
 	rule.h				mmap_cache.c			\
 	mmap_cache.h							\
 	ci-tracker.h			ci-tracker.c			\
-	access-check.h			access-check.c
+	access-check.h			access-check.c			\
+	hal-file-monitor.h
 
 if HAVE_CONKIT
 hald_SOURCES += ck-tracker.h ck-tracker.c
diff --git a/hald/freebsd/osspec.c b/hald/freebsd/osspec.c
index 8959019..1b047b1 100644
--- a/hald/freebsd/osspec.c
+++ b/hald/freebsd/osspec.c
@@ -62,6 +62,13 @@ static HFHandler *handlers[] = {
   &hf_devd_handler
 };
 
+HalFileMonitor *
+osspec_get_file_monitor (void)
+{
+#warning Please implement
+        return NULL;
+}
+
 void
 osspec_privileged_init (void)
 {
diff --git a/hald/hald.c b/hald/hald.c
index 3392068..bf9a889 100644
--- a/hald/hald.c
+++ b/hald/hald.c
@@ -386,6 +386,114 @@ out:
 
 /*--------------------------------------------------------------------------------------------------*/
 
+#ifdef HAVE_POLKIT
+
+typedef struct
+{
+        PolKitContextFileMonitorNotifyFunc notify_cb;
+        gpointer user_data;
+} PolkitFMClosure;
+
+static void
+_polkit_fm_notify_func (HalFileMonitor      *monitor,
+                        HalFileMonitorEvent  event,
+                        const char          *path,
+                        gpointer             user_data)
+{
+        PolkitFMClosure *closure = user_data;
+        if (closure->notify_cb != NULL) {
+                closure->notify_cb (pk_context,
+                                    event, /* binary compatible */
+                                    path,
+                                    closure->user_data);
+        }
+}
+
+static unsigned int
+_polkit_fm_add_watch (PolKitContext                     *pk_context,
+                      const char                        *path,
+                      PolKitContextFileMonitorEvent      event_mask,
+                      PolKitContextFileMonitorNotifyFunc notify_cb,
+                      gpointer                           user_data)
+{
+        unsigned int ret;
+        HalFileMonitor *file_monitor;
+        PolkitFMClosure *closure;
+
+        ret = 0;
+
+        file_monitor = osspec_get_file_monitor ();
+        if (file_monitor == NULL)
+                goto out;
+
+        closure = g_new0 (PolkitFMClosure, 1);
+        closure->notify_cb = notify_cb;
+        closure->user_data = user_data;
+
+        /* TODO FIXME: ugh, we probably leak this... too bad. */
+
+        ret = hal_file_monitor_add_notify (file_monitor,
+                                           path,
+                                           event_mask, /* binary compatible */
+                                           _polkit_fm_notify_func,
+                                           closure);
+        if (ret == 0) {
+                g_free (closure);
+        }
+
+out:
+        return ret;
+}
+
+static void 
+_polkit_fm_remove_watch (PolKitContext *pk_context,
+                         unsigned int   watch_id)
+{
+        HalFileMonitor *file_monitor;
+
+        file_monitor = osspec_get_file_monitor ();
+        if (file_monitor == NULL)
+                goto out;
+
+        hal_file_monitor_remove_notify (file_monitor, watch_id);
+
+out:
+        ;
+}
+
+static guint _polkit_cooloff_timer = 0;
+
+static gboolean
+_polkit_config_really_changed (gpointer user_data)
+{
+        HAL_INFO (("Acting on PolicyKit config change"));
+        _polkit_cooloff_timer = 0;
+        reconfigure_all_policy ();
+        return FALSE;
+}
+
+static void
+_polkit_config_changed_cb (PolKitContext *pk_context, gpointer user_data)
+{
+        HAL_INFO (("PolicyKit reports that the config have changed; starting cool-off timer"));
+
+        /* Start a cool-off timer since we get a lot of events within
+         * a short time-frame...
+         */
+
+        if (_polkit_cooloff_timer > 0) {
+                /* cancel old cool-off timer */
+                g_source_remove (_polkit_cooloff_timer);
+                HAL_INFO (("restarting cool-off timer"));
+        }
+        _polkit_cooloff_timer = g_timeout_add (1000, /* one second... */
+                                               _polkit_config_really_changed,
+                                               NULL);
+}
+
+#endif /* HAVE_POLKIT */
+
+
 /**  
  *  main:
  *  @argc:               Number of arguments
@@ -621,13 +729,6 @@ main (int argc, char *argv[])
 	/* Finally, setup unix signal handler for TERM */
 	signal (SIGTERM, handle_sigterm);
 
-#ifdef HAVE_POLKIT
-        g_error = NULL;
-        pk_context = libpolkit_context_new (&g_error);
-        if (pk_context == NULL)
-                DIE (("Could not create PolicyKit context: %s", g_error->message));
-#endif
-
 	/* set up the local dbus server */
 	if (!hald_dbus_local_server_init ())
 		return 1;
@@ -644,6 +745,21 @@ main (int argc, char *argv[])
 	/* initialize privileged operating system specific parts */
 	osspec_privileged_init ();
 
+#ifdef HAVE_POLKIT
+        g_error = NULL;
+        pk_context = libpolkit_context_new ();
+        if (pk_context == NULL)
+                DIE (("Could not create PolicyKit context"));
+        libpolkit_context_set_config_changed (pk_context,
+                                              _polkit_config_changed_cb,
+                                              NULL);
+        libpolkit_context_set_file_monitor (pk_context, 
+                                            _polkit_fm_add_watch,
+                                            _polkit_fm_remove_watch);
+        if (!libpolkit_context_init (pk_context, &g_error))
+                DIE (("Could not init PolicyKit context: %s", g_error->message));
+#endif
+
 	/* sometimes we don't want to drop root privs, for instance
 	   if we are profiling memory usage */
 	if (opt_retain_privileges == FALSE) {
diff --git a/hald/hald_dbus.c b/hald/hald_dbus.c
index eecd2ab..9e19bf6 100644
--- a/hald/hald_dbus.c
+++ b/hald/hald_dbus.c
@@ -5120,6 +5120,47 @@ validate_locks (void)
         hal_device_store_foreach (hald_get_gdl (), validate_lock_for_device, NULL);
 }
 
+static void
+reconfigure_acl (void)
+{
+#ifdef HAVE_ACLMGMT
+	HalDevice *d;
+	char *extra_env[1] = {NULL};
+
+	d = hal_device_store_find (hald_get_gdl (), "/org/freedesktop/Hal/devices/computer");
+	if (d == NULL) {
+		d = hal_device_store_find (hald_get_tdl (), "/org/freedesktop/Hal/devices/computer");
+	}
+	if (d == NULL) {
+		HAL_ERROR (("No computer object?!?"));
+		goto out;
+	}
+
+	hald_runner_run (d,
+			 "hal-acl-tool --reconfigure", 
+			 extra_env,
+			 HAL_HELPER_TIMEOUT, 
+			 NULL, /* run_terminated_cb */
+			 NULL  /* userdata1 */, 
+			 NULL  /* userdata2 */ );
+out:
+	;
+#endif /* HAVE_ACLMGMT */
+}
+
+/* this function is normally called in response to when PolicyKit says the policy have changed */
+void
+reconfigure_all_policy (void)
+{
+        HAL_INFO (("Reconfiguring all policy"));
+
+        /* first, validate all the locks */
+        validate_locks ();
+
+        /* second, reconfigure all ACL's */
+        reconfigure_acl ();
+}
+
 static void 
 hald_dbus_session_active_changed (CKTracker *tracker, CKSession *session, void *user_data)
 {
@@ -5172,45 +5213,17 @@ out:
 }
 
 static void
-hald_dbus_ck_availability_changed (gboolean ck_available)
-{
-#ifdef HAVE_ACLMGMT
-	HalDevice *d;
-	char *extra_env[1] = {NULL};
-
-	d = hal_device_store_find (hald_get_gdl (), "/org/freedesktop/Hal/devices/computer");
-	if (d == NULL) {
-		d = hal_device_store_find (hald_get_tdl (), "/org/freedesktop/Hal/devices/computer");
-	}
-	if (d == NULL) {
-		HAL_ERROR (("No computer object?!?"));
-		goto out;
-	}
-
-	hald_runner_run (d,
-			 "hal-acl-tool --reconfigure", 
-			 extra_env,
-			 HAL_HELPER_TIMEOUT, 
-			 NULL, /* run_terminated_cb */
-			 NULL  /* userdata1 */, 
-			 NULL  /* userdata2 */ );
-out:
-	;
-#endif /* HAVE_ACLMGMT */
-}
-
-static void
 hald_dbus_ck_disappeared (CKTracker *tracker, void *user_data)
 {
 	HAL_INFO (("In hald_dbus_ck_disappeared"));
-	hald_dbus_ck_availability_changed (FALSE);
+        reconfigure_acl ();
 }
 
 static void
 hald_dbus_ck_appeared (CKTracker *tracker, void *user_data)
 {
 	HAL_INFO (("In hald_dbus_ck_appeared"));
-	hald_dbus_ck_availability_changed (TRUE);
+        reconfigure_acl ();
 }
 
 #endif /* HAVE_CONKIT */
diff --git a/hald/hald_dbus.h b/hald/hald_dbus.h
index 4a5deb1..4ec9239 100644
--- a/hald/hald_dbus.h
+++ b/hald/hald_dbus.h
@@ -100,6 +100,8 @@ void device_send_signal_condition (HalDe
 void device_property_atomic_update_begin (void);
 void device_property_atomic_update_end   (void);
 
+void reconfigure_all_policy (void);
+
 gboolean hald_dbus_init_preprobe (void);
 
 gboolean hald_dbus_init (void);
diff --git a/hald/linux/Makefile.am b/hald/linux/Makefile.am
index 9ee500d..76df7f5 100644
--- a/hald/linux/Makefile.am
+++ b/hald/linux/Makefile.am
@@ -14,34 +14,31 @@ if HALD_COMPILE_LINUX
 noinst_LTLIBRARIES = libhald_linux.la
 endif
 
-libhald_linux_la_SOURCES =					\
-	acpi.h							\
-	apm.h							\
-	pmu.h							\
-	osspec.c						\
-	osspec_linux.h						\
-	hotplug.h						\
-	hotplug.c						\
-	hotplug_helper.h					\
-	coldplug.h						\
-	coldplug.c						\
-	device.h						\
-	device.c						\
-	blockdev.h						\
-	blockdev.c						\
-	inotify_local.h
+libhald_linux_la_SOURCES =				\
+	acpi.h						\
+	apm.h						\
+	pmu.h						\
+				osspec.c		\
+	osspec_linux.h					\
+	hotplug.h		hotplug.c		\
+	hotplug_helper.h				\
+	coldplug.h		coldplug.c		\
+	device.h		device.c		\
+	blockdev.h		blockdev.c		\
+	inotify_local.h					\
+				hal-file-monitor.c
 
 if HAVE_ACPI
-libhald_linux_la_SOURCES +=					\
+libhald_linux_la_SOURCES +=				\
 	acpi.c
 endif
 
 if HAVE_APM
-libhald_linux_la_SOURCES +=					\
+libhald_linux_la_SOURCES +=				\
 	apm.c
 endif
 
 if HAVE_PMU
-libhald_linux_la_SOURCES +=					\
+libhald_linux_la_SOURCES +=				\
 	pmu.c
 endif
diff --git a/hald/linux/hal-file-monitor.c b/hald/linux/hal-file-monitor.c
new file mode 100644
index 0000000..cdf3775
--- /dev/null
+++ b/hald/linux/hal-file-monitor.c
@@ -0,0 +1,676 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann at jhu.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_INOTIFY_H
+#include <sys/inotify.h>
+#else
+#include "inotify_local.h"
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+
+#include "../hal-file-monitor.h"
+
+#define HAL_FILE_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), HAL_TYPE_FILE_MONITOR, HalFileMonitorPrivate))
+
+typedef struct
+{
+        int     wd;
+        char   *path;
+        GSList *notifies;
+} FileInotifyWatch;
+
+typedef struct
+{
+        guint                   id;
+        int                     mask;
+        HalFileMonitorNotifyFunc notify_func;
+        gpointer                user_data;
+        FileInotifyWatch       *watch;
+} FileMonitorNotify;
+
+typedef struct
+{
+        FileInotifyWatch  *watch;
+        HalFileMonitorEvent event;
+        char              *path;
+} FileMonitorEventInfo;
+
+#define DEFAULT_NOTIFY_BUFLEN (32 * (sizeof (struct inotify_event) + 16))
+#define MAX_NOTIFY_BUFLEN     (32 * DEFAULT_NOTIFY_BUFLEN)
+
+struct HalFileMonitorPrivate
+{
+        guint       serial;
+
+        gboolean    initialized_inotify;
+
+        int         inotify_fd;
+        guint       io_watch;
+
+        GHashTable *wd_to_watch;
+        GHashTable *path_to_watch;
+        GHashTable *notifies;
+
+        guint       buflen;
+        guchar     *buffer;
+
+        guint       events_idle_id;
+        GQueue     *notify_events;
+};
+
+enum {
+        PROP_0,
+};
+
+static void     hal_file_monitor_class_init  (HalFileMonitorClass *klass);
+static void     hal_file_monitor_init        (HalFileMonitor      *file_monitor);
+static void     hal_file_monitor_finalize    (GObject            *object);
+
+G_DEFINE_TYPE (HalFileMonitor, hal_file_monitor, G_TYPE_OBJECT)
+
+static gpointer monitor_object = NULL;
+
+GQuark
+hal_file_monitor_error_quark (void)
+{
+        static GQuark ret = 0;
+        if (ret == 0) {
+                ret = g_quark_from_static_string ("hal_file_monitor_error");
+        }
+
+        return ret;
+}
+
+/* most of this is adapted from libgnome-menu */
+
+static int
+our_event_mask_to_inotify_mask (int our_mask)
+{
+        int mask;
+
+        mask = 0;
+
+        if (our_mask & HAL_FILE_MONITOR_EVENT_ACCESS) {
+                mask |= IN_ACCESS;
+        }
+
+        if (our_mask & HAL_FILE_MONITOR_EVENT_CREATE) {
+                mask |= IN_CREATE | IN_MOVED_TO;
+        }
+
+        if (our_mask & HAL_FILE_MONITOR_EVENT_DELETE) {
+                mask |= IN_DELETE | IN_DELETE_SELF | IN_MOVED_FROM | IN_MOVE_SELF;
+        }
+
+        if (our_mask & HAL_FILE_MONITOR_EVENT_CHANGE) {
+                mask |= IN_MODIFY | IN_ATTRIB;
+        }
+
+        return mask;
+}
+
+static char *
+imask_to_string (guint32 mask)
+{
+        GString *out;
+
+        out = g_string_new (NULL);
+
+        if (mask & IN_ACCESS) {
+                g_string_append (out, "ACCESS ");
+        }
+        if (mask & IN_MODIFY) {
+                g_string_append (out, "MODIFY ");
+        }
+        if (mask & IN_ATTRIB) {
+                g_string_append (out, "ATTRIB ");
+        }
+        if (mask & IN_CLOSE_WRITE) {
+                g_string_append (out, "CLOSE_WRITE ");
+        }
+        if (mask & IN_CLOSE_NOWRITE) {
+                g_string_append (out, "CLOSE_NOWRITE ");
+        }
+        if (mask & IN_OPEN) {
+                g_string_append (out, "OPEN ");
+        }
+        if (mask & IN_MOVED_FROM) {
+                g_string_append (out, "MOVED_FROM ");
+        }
+        if (mask & IN_MOVED_TO) {
+                g_string_append (out, "MOVED_TO ");
+        }
+        if (mask & IN_DELETE) {
+                g_string_append (out, "DELETE ");
+        }
+        if (mask & IN_CREATE) {
+                g_string_append (out, "CREATE ");
+        }
+        if (mask & IN_DELETE_SELF) {
+                g_string_append (out, "DELETE_SELF ");
+        }
+        if (mask & IN_UNMOUNT) {
+                g_string_append (out, "UNMOUNT ");
+        }
+        if (mask & IN_Q_OVERFLOW) {
+                g_string_append (out, "Q_OVERFLOW ");
+        }
+        if (mask & IN_IGNORED) {
+                g_string_append (out, "IGNORED ");
+        }
+
+        return g_string_free (out, FALSE);
+}
+
+static FileInotifyWatch *
+file_monitor_add_watch_for_path (HalFileMonitor *monitor,
+                                 const char    *path,
+                                 int            mask)
+
+{
+        FileInotifyWatch *watch;
+        int               wd;
+        int               imask;
+        char             *mask_str;
+
+        imask = our_event_mask_to_inotify_mask (mask);
+
+        mask_str = imask_to_string (imask);
+        g_debug ("adding inotify watch %s", mask_str);
+        g_free (mask_str);
+
+        wd = inotify_add_watch (monitor->priv->inotify_fd, path, IN_MASK_ADD | imask);
+        if (wd < 0) {
+                /* FIXME: remove watch etc */
+                return NULL;
+        }
+
+        watch = g_hash_table_lookup (monitor->priv->path_to_watch, path);
+        if (watch == NULL) {
+                watch = g_new0 (FileInotifyWatch, 1);
+
+                watch->wd = wd;
+                watch->path = g_strdup (path);
+
+                g_hash_table_insert (monitor->priv->path_to_watch, watch->path, watch);
+                g_hash_table_insert (monitor->priv->wd_to_watch, GINT_TO_POINTER (wd), watch);
+        }
+
+        return watch;
+}
+
+static void
+monitor_release_watch (HalFileMonitor    *monitor,
+                       FileInotifyWatch *watch)
+{
+        g_slist_free (watch->notifies);
+        watch->notifies = NULL;
+
+        g_free (watch->path);
+        watch->path = NULL;
+
+        inotify_rm_watch (monitor->priv->inotify_fd, watch->wd);
+        watch->wd = -1;
+}
+
+static void
+file_monitor_remove_watch (HalFileMonitor    *monitor,
+                           FileInotifyWatch *watch)
+{
+        g_hash_table_remove (monitor->priv->path_to_watch,
+                             watch->path);
+        g_hash_table_remove (monitor->priv->wd_to_watch,
+                             GINT_TO_POINTER (watch->wd));
+        monitor_release_watch (monitor, watch);
+}
+
+static gboolean
+remove_watch_foreach (const char       *path,
+                      FileInotifyWatch *watch,
+                      HalFileMonitor    *monitor)
+{
+        monitor_release_watch (monitor, watch);
+        return TRUE;
+}
+
+static void
+close_inotify (HalFileMonitor *monitor)
+{
+        if (! monitor->priv->initialized_inotify) {
+                return;
+        }
+
+        monitor->priv->initialized_inotify = FALSE;
+
+        g_hash_table_foreach_remove (monitor->priv->path_to_watch,
+                                     (GHRFunc) remove_watch_foreach,
+                                     monitor);
+        monitor->priv->path_to_watch = NULL;
+
+        if (monitor->priv->wd_to_watch != NULL) {
+                g_hash_table_destroy (monitor->priv->wd_to_watch);
+        }
+        monitor->priv->wd_to_watch = NULL;
+
+        g_free (monitor->priv->buffer);
+        monitor->priv->buffer = NULL;
+        monitor->priv->buflen = 0;
+
+        if (monitor->priv->io_watch) {
+                g_source_remove (monitor->priv->io_watch);
+        }
+        monitor->priv->io_watch = 0;
+
+        if (monitor->priv->inotify_fd > 0) {
+                close (monitor->priv->inotify_fd);
+        }
+        monitor->priv->inotify_fd = 0;
+}
+
+static gboolean
+emit_events_in_idle (HalFileMonitor *monitor)
+{
+        FileMonitorEventInfo *event_info;
+
+        monitor->priv->events_idle_id = 0;
+
+        while ((event_info = g_queue_pop_head (monitor->priv->notify_events)) != NULL) {
+                GSList           *l;
+                FileInotifyWatch *watch;
+
+                watch = event_info->watch;
+
+                for (l = watch->notifies; l != NULL; l = l->next) {
+                        FileMonitorNotify *notify;
+
+                        notify = g_hash_table_lookup (monitor->priv->notifies,
+                                                      GUINT_TO_POINTER (l->data));
+                        if (notify == NULL) {
+                                continue;
+                        }
+
+                        if (! (notify->mask & event_info->event)) {
+                                continue;
+                        }
+
+                        if (notify->notify_func) {
+                                notify->notify_func (monitor, event_info->event, event_info->path, notify->user_data);
+                        }
+                }
+
+                g_free (event_info->path);
+                event_info->path = NULL;
+
+                event_info->event = HAL_FILE_MONITOR_EVENT_NONE;
+
+                g_free (event_info);
+        }
+
+        return FALSE;
+}
+
+static void
+file_monitor_queue_event (HalFileMonitor        *monitor,
+                          FileMonitorEventInfo *event_info)
+{
+        g_queue_push_tail (monitor->priv->notify_events, event_info);
+
+        if (monitor->priv->events_idle_id == 0) {
+                monitor->priv->events_idle_id = g_idle_add ((GSourceFunc) emit_events_in_idle, monitor);
+        }
+}
+
+static void
+queue_watch_event (HalFileMonitor     *monitor,
+                   FileInotifyWatch  *watch,
+                   HalFileMonitorEvent event,
+                   const char        *path)
+{
+        FileMonitorEventInfo *event_info;
+
+        event_info = g_new0 (FileMonitorEventInfo, 1);
+
+        event_info->watch   = watch;
+        event_info->path    = g_strdup (path);
+        event_info->event   = event;
+
+        file_monitor_queue_event (monitor, event_info);
+}
+
+static void
+handle_inotify_event (HalFileMonitor        *monitor,
+                      FileInotifyWatch     *watch,
+                      struct inotify_event *ievent)
+{
+        HalFileMonitorEvent  event;
+        const char         *path;
+        char               *freeme;
+        char               *mask_str;
+
+        freeme = NULL;
+
+        if (ievent->len > 0) {
+                path = freeme = g_build_filename (watch->path, ievent->name, NULL);
+        } else {
+                path = watch->path;
+        }
+
+        mask_str = imask_to_string (ievent->mask);
+        g_debug ("handing inotify event %s for %s", mask_str, path);
+        g_free (mask_str);
+
+        event = HAL_FILE_MONITOR_EVENT_NONE;
+
+        if (ievent->mask & (IN_CREATE | IN_MOVED_TO)) {
+                event = HAL_FILE_MONITOR_EVENT_CREATE;
+        } else if (ievent->mask & (IN_DELETE | IN_DELETE_SELF | IN_MOVED_FROM | IN_MOVE_SELF)) {
+                event = HAL_FILE_MONITOR_EVENT_DELETE;
+        } else if (ievent->mask & (IN_MODIFY | IN_ATTRIB)) {
+                event = HAL_FILE_MONITOR_EVENT_CHANGE;
+        } else if (ievent->mask & IN_ACCESS) {
+                event = HAL_FILE_MONITOR_EVENT_ACCESS;
+        }
+
+        if (event != HAL_FILE_MONITOR_EVENT_NONE) {
+                queue_watch_event (monitor, watch, event, path);
+        }
+
+        if (ievent->mask & IN_IGNORED) {
+                file_monitor_remove_watch (monitor, watch);
+        }
+}
+
+static gboolean
+inotify_data_pending (GIOChannel    *source,
+		      GIOCondition   condition,
+                      HalFileMonitor *monitor)
+{
+        int len;
+        int i;
+
+        g_debug ("Inotify data pending");
+
+        g_assert (monitor->priv->inotify_fd > 0);
+        g_assert (monitor->priv->buffer != NULL);
+
+        do {
+                while ((len = read (monitor->priv->inotify_fd, monitor->priv->buffer, monitor->priv->buflen)) < 0 && errno == EINTR);
+
+                if (len > 0) {
+                        break;
+                } else if (len < 0) {
+                        g_warning ("Error reading inotify event: %s",
+                                   g_strerror (errno));
+                        goto error_cancel;
+                }
+
+                g_assert (len == 0);
+
+                if ((monitor->priv->buflen << 1) > MAX_NOTIFY_BUFLEN) {
+                        g_warning ("Error reading inotify event: Exceded maximum buffer size");
+                        goto error_cancel;
+                }
+
+                g_debug ("Buffer size %u too small, trying again at %u\n",
+                         monitor->priv->buflen, monitor->priv->buflen << 1);
+
+                monitor->priv->buflen <<= 1;
+                monitor->priv->buffer = g_realloc (monitor->priv->buffer, monitor->priv->buflen);
+        } while (TRUE);
+
+        g_debug ("Inotify buffer filled");
+
+        i = 0;
+        while (i < len) {
+                struct inotify_event *ievent = (struct inotify_event *) &monitor->priv->buffer [i];
+                FileInotifyWatch     *watch;
+
+                g_debug ("Got event wd = %d, mask = 0x%x, cookie = %d, len = %d, name= %s\n",
+                         ievent->wd,
+                         ievent->mask,
+                         ievent->cookie,
+                         ievent->len,
+                         ievent->len > 0 ? ievent->name : "<none>");
+
+                watch = g_hash_table_lookup (monitor->priv->wd_to_watch,
+                                             GINT_TO_POINTER (ievent->wd));
+                if (watch != NULL) {
+                        handle_inotify_event (monitor, watch, ievent);
+                }
+
+                i += sizeof (struct inotify_event) + ievent->len;
+        }
+
+        return TRUE;
+
+ error_cancel:
+        monitor->priv->io_watch = 0;
+
+        close_inotify (monitor);
+
+        return FALSE;
+}
+
+static FileMonitorNotify *
+file_monitor_add_notify_for_path (HalFileMonitor          *monitor,
+                                  const char             *path,
+                                  int                     mask,
+                                  HalFileMonitorNotifyFunc notify_func,
+                                  gpointer                data)
+{
+        FileMonitorNotify *notify;
+        FileInotifyWatch  *watch;
+
+        notify = NULL;
+
+        watch = file_monitor_add_watch_for_path (monitor, path, mask);
+        if (watch != NULL) {
+                notify = g_new0 (FileMonitorNotify, 1);
+                notify->notify_func = notify_func;
+                notify->user_data = data;
+                notify->id = monitor->priv->serial++;
+                notify->watch = watch;
+                notify->mask = mask;
+
+                g_debug ("Adding notify for %s mask:%d", path, mask);
+
+                g_hash_table_insert (monitor->priv->notifies, GUINT_TO_POINTER (notify->id), notify);
+                watch->notifies = g_slist_prepend (watch->notifies, GUINT_TO_POINTER (notify->id));
+        }
+
+        return notify;
+}
+
+static void
+file_monitor_remove_notify (HalFileMonitor *monitor,
+                            guint          id)
+{
+        FileMonitorNotify *notify;
+
+        g_debug ("removing notify for %u", id);
+
+        notify = g_hash_table_lookup (monitor->priv->notifies,
+                                      GUINT_TO_POINTER (id));
+        if (notify == NULL) {
+                return;
+        }
+
+        g_hash_table_steal (monitor->priv->notifies,
+                            GUINT_TO_POINTER (id));
+
+        notify->watch->notifies = g_slist_remove (notify->watch->notifies, GUINT_TO_POINTER (id));
+
+        if (g_slist_length (notify->watch->notifies) == 0) {
+                file_monitor_remove_watch (monitor, notify->watch);
+                g_free (notify->watch);
+        }
+
+        g_free (notify);
+}
+
+guint
+hal_file_monitor_add_notify (HalFileMonitor          *monitor,
+                            const char             *path,
+                            int                     mask,
+                            HalFileMonitorNotifyFunc notify_func,
+                            gpointer                data)
+{
+        FileMonitorNotify *notify;
+
+        if (! monitor->priv->initialized_inotify) {
+                return 0;
+        }
+
+        notify = file_monitor_add_notify_for_path (monitor,
+                                                   path,
+                                                   mask,
+                                                   notify_func,
+                                                   data);
+        if (notify == NULL) {
+                g_warning ("Failed to add monitor on '%s': %s",
+                           path,
+                           g_strerror (errno));
+                return 0;
+        }
+
+        return notify->id;
+}
+
+void
+hal_file_monitor_remove_notify (HalFileMonitor *monitor,
+                               guint          id)
+{
+        if (! monitor->priv->initialized_inotify) {
+                return;
+        }
+
+        file_monitor_remove_notify (monitor, id);
+}
+
+static void
+hal_file_monitor_class_init (HalFileMonitorClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->finalize = hal_file_monitor_finalize;
+
+        g_type_class_add_private (klass, sizeof (HalFileMonitorPrivate));
+}
+
+
+static void
+setup_inotify (HalFileMonitor *monitor)
+{
+        GIOChannel *io_channel;
+        int         fd;
+
+        if (monitor->priv->initialized_inotify) {
+                return;
+        }
+
+        if ((fd = inotify_init ()) < 0) {
+                g_warning ("Failed to initialize inotify: %s",
+                           g_strerror (errno));
+                return;
+        }
+
+        monitor->priv->inotify_fd = fd;
+
+        io_channel = g_io_channel_unix_new (fd);
+        monitor->priv->io_watch = g_io_add_watch (io_channel,
+                                                  G_IO_IN|G_IO_PRI,
+                                                  (GIOFunc) inotify_data_pending,
+                                                  monitor);
+        g_io_channel_unref (io_channel);
+
+        monitor->priv->buflen = DEFAULT_NOTIFY_BUFLEN;
+        monitor->priv->buffer = g_malloc (DEFAULT_NOTIFY_BUFLEN);
+
+        monitor->priv->notifies = g_hash_table_new (g_direct_hash,
+                                                    g_direct_equal);
+
+        monitor->priv->wd_to_watch = g_hash_table_new (g_direct_hash,
+                                                       g_direct_equal);
+        monitor->priv->path_to_watch = g_hash_table_new (g_str_hash,
+                                                         g_str_equal);
+
+        monitor->priv->initialized_inotify = TRUE;
+}
+
+static void
+hal_file_monitor_init (HalFileMonitor *monitor)
+{
+        monitor->priv = HAL_FILE_MONITOR_GET_PRIVATE (monitor);
+
+        monitor->priv->serial = 1;
+        monitor->priv->notify_events = g_queue_new ();
+
+        setup_inotify (monitor);
+}
+
+static void
+hal_file_monitor_finalize (GObject *object)
+{
+        HalFileMonitor *monitor;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (HAL_IS_FILE_MONITOR (object));
+
+        monitor = HAL_FILE_MONITOR (object);
+
+        g_return_if_fail (monitor->priv != NULL);
+
+        close_inotify (monitor);
+
+        g_hash_table_destroy (monitor->priv->notifies);
+        g_queue_free (monitor->priv->notify_events);
+
+        G_OBJECT_CLASS (hal_file_monitor_parent_class)->finalize (object);
+}
+
+HalFileMonitor *
+hal_file_monitor_new (void)
+{
+        if (monitor_object != NULL) {
+                g_object_ref (monitor_object);
+        } else {
+                monitor_object = g_object_new (HAL_TYPE_FILE_MONITOR, NULL);
+
+                g_object_add_weak_pointer (monitor_object,
+                                           (gpointer *) &monitor_object);
+        }
+
+        return HAL_FILE_MONITOR (monitor_object);
+}
diff --git a/hald/linux/osspec.c b/hald/linux/osspec.c
index 13e943a..46aa9fa 100644
--- a/hald/linux/osspec.c
+++ b/hald/linux/osspec.c
@@ -44,12 +44,6 @@
 #include <sys/utsname.h>
 #include <unistd.h>
 
-#ifdef HAVE_SYS_INOTIFY_H
-#include <sys/inotify.h>
-#else
-#include "inotify_local.h"
-#endif
-
 #include <dbus/dbus.h>
 #include <dbus/dbus-glib.h>
 
@@ -62,6 +56,8 @@
 #include "../util.h"
 #include "../ids.h"
 
+#include "hal-file-monitor.h"
+
 #include "acpi.h"
 #include "apm.h"
 #include "blockdev.h"
@@ -265,11 +261,7 @@ mount_tree_changed_event (GIOChannel *ch
 	return TRUE;
 }
 
-void
-osspec_privileged_init (void)
-{
-}
-
+#if 0
 static gboolean
 inotify_data (GIOChannel *source, GIOCondition condition, gpointer user_data)
 {
@@ -353,7 +345,6 @@ watch_fdi_files (void)
 	g_io_add_watch (inotify_channel, G_IO_IN, inotify_data, NULL);
 	g_io_channel_unref (inotify_channel);
 
-
 	if (hal_fdi_source_preprobe != NULL) {
 		if (!add_fdi_watch (inotify_fd, hal_fdi_source_preprobe))
 			goto out;
@@ -388,6 +379,24 @@ watch_fdi_files (void)
 out:
 	DIE (("Error watching fdi files"));
 }
+#endif
+
+static HalFileMonitor *file_monitor = NULL;
+
+HalFileMonitor *
+osspec_get_file_monitor (void)
+{
+        return file_monitor;
+}
+
+void
+osspec_privileged_init (void)
+{
+        file_monitor = hal_file_monitor_new ();
+        if (file_monitor == NULL) {
+                DIE (("Cannot initialize file monitor"));
+        }
+}
 
 void
 osspec_init (void)
@@ -452,9 +461,11 @@ osspec_init (void)
 	ids_init ();
 
 	/* watch fdi directories */
-	watch_fdi_files ();	
+	/* TODO: temporarily disabled... 
+           watch_fdi_files (); */
 }
 
+
 static void 
 computer_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
 {
diff --git a/hald/osspec.h b/hald/osspec.h
index 66f9550..08cf6a2 100644
--- a/hald/osspec.h
+++ b/hald/osspec.h
@@ -31,6 +31,7 @@
 #include <dbus/dbus.h>
 
 #include "device.h"
+#include "hal-file-monitor.h"
 
 /** Initialize the kernel specific parts of the daemon, as root */
 void osspec_privileged_init (void);
@@ -64,4 +65,6 @@ void osspec_fdi_cache_invalid (void);
  */
 DBusHandlerResult osspec_filter_function (DBusConnection *connection, DBusMessage *message, void *user_data);
 
+HalFileMonitor *osspec_get_file_monitor (void);
+
 #endif /* OSSPEC_H */
diff --git a/hald/solaris/osspec.c b/hald/solaris/osspec.c
index eca1d11..4863965 100644
--- a/hald/solaris/osspec.c
+++ b/hald/solaris/osspec.c
@@ -41,6 +41,13 @@
 static void mnttab_event_init ();
 static gboolean mnttab_event (GIOChannel *channel, GIOCondition cond, gpointer user_data);
 
+HalFileMonitor *
+osspec_get_file_monitor (void)
+{
+#warning Please implement
+        return NULL;
+}
+
 void
 osspec_init (void)
 {
diff --git a/privileges/Makefile.am b/privileges/Makefile.am
index 9754140..3287f14 100644
--- a/privileges/Makefile.am
+++ b/privileges/Makefile.am
@@ -12,14 +12,7 @@ dist_polkit_privilege_DATA += hal-device
 endif
 
 check:
-	for f in $(dist_polkit_privilege_DATA); do \
-          echo "Validating privilege file: $$f"; \
-          $(POLKIT_PRIVILEGE_FILE_VALIDATE) --file $(srcdir)/$$f; \
-          if [ "$$?" != "0" ]; then \
-            echo "failed"; \
-            exit 1; \
-          fi; \
-        done
+	$(POLKIT_PRIVILEGE_FILE_VALIDATE) $(dist_polkit_privilege_DATA)
 
 endif
 
diff --git a/tools/hal-acl-tool.c b/tools/hal-acl-tool.c
index e110ac3..1c5249c 100644
--- a/tools/hal-acl-tool.c
+++ b/tools/hal-acl-tool.c
@@ -1072,12 +1072,10 @@ main (int argc, char *argv[])
 		goto out;
 	}
 
-        printf ("foo='%s'\n", getenv ("POLKIT_PRIVILEGE_DIR"));
-
         g_error = NULL;
-        pk_context = libpolkit_context_new (&g_error);
-        if (pk_context == NULL) {
-                printf ("Could not create PolicyKit context: %s", g_error->message);
+        pk_context = libpolkit_context_new ();
+        if (!libpolkit_context_init (pk_context, &g_error)) {
+                printf ("Could not init PolicyKit context: %s", g_error->message);
                 goto out;
         }
 
diff-tree c7f7bfcbfa708874497c519b2b8a41fbec9406d7 (from e2cdd3577964013b46878c86083e4315357cdb6f)
Author: David Zeuthen <davidz at redhat.com>
Date:   Fri Apr 6 21:05:56 2007 -0400

    file monitoring interface
    
    From ConsoleKit - relicensed under the AFL 2.1 with permission from
    Jon William McCann:
    
    On 4/6/07, David Zeuthen <david at fubar.dk> wrote:
    > On Wed, 2007-04-04 at 20:13 -0400, William Jon McCann wrote:
    > > Somewhat off topic but since you mentioned that polkit will need to do
    > > file monitoring I'm in the process of writing a little inotify
    > > abstraction to use in CK.  I should be done in the next couple of days
    > > and it may be useful to you too.
    > >
    > > I need it in CK to be able to detect idleness on text sessions.
    >
    > This is very cool; I'm copying into HAL right now. Are you OK with
    > relicensing the header file under the AFL 2.1? I'd like that interface
    > to be shared code and each HAL backend implements an object like this.
    > If so, I'll just copy paste your reply into the commit log when
    > committing the code. Thanks!
    
    Yes, you have my permission to relicense the code under the AFL 2.1.  :)

diff --git a/hald/hal-file-monitor.h b/hald/hal-file-monitor.h
new file mode 100644
index 0000000..2a41d4d
--- /dev/null
+++ b/hald/hal-file-monitor.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann at jhu.edu>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ *
+ */
+
+#ifndef HAL_FILE_MONITOR_H
+#define HAL_FILE_MONITOR_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define HAL_TYPE_FILE_MONITOR         (hal_file_monitor_get_type ())
+#define HAL_FILE_MONITOR(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), HAL_TYPE_FILE_MONITOR, HalFileMonitor))
+#define HAL_FILE_MONITOR_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), HAL_TYPE_FILE_MONITOR, HalFileMonitorClass))
+#define HAL_IS_FILE_MONITOR(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), HAL_TYPE_FILE_MONITOR))
+#define HAL_IS_FILE_MONITOR_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), HAL_TYPE_FILE_MONITOR))
+#define HAL_FILE_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), HAL_TYPE_FILE_MONITOR, HalFileMonitorClass))
+
+typedef struct HalFileMonitorPrivate HalFileMonitorPrivate;
+
+typedef struct
+{
+        GObject               parent;
+        HalFileMonitorPrivate *priv;
+} HalFileMonitor;
+
+typedef struct
+{
+        GObjectClass parent_class;
+} HalFileMonitorClass;
+
+typedef enum
+{
+        HAL_FILE_MONITOR_EVENT_NONE    = 1 << 0,
+        HAL_FILE_MONITOR_EVENT_ACCESS  = 1 << 1,
+        HAL_FILE_MONITOR_EVENT_CREATE  = 1 << 2,
+        HAL_FILE_MONITOR_EVENT_DELETE  = 1 << 3,
+        HAL_FILE_MONITOR_EVENT_CHANGE  = 1 << 4,
+} HalFileMonitorEvent;
+
+typedef enum
+{
+        HAL_FILE_MONITOR_ERROR_GENERAL
+} HalFileMonitorError;
+
+#define HAL_FILE_MONITOR_ERROR hal_file_monitor_error_quark ()
+
+typedef void (*HalFileMonitorNotifyFunc) (HalFileMonitor      *monitor,
+                                          HalFileMonitorEvent  event,
+                                          const char         *path,
+                                          gpointer            user_data);
+
+GQuark              hal_file_monitor_error_quark           (void);
+GType               hal_file_monitor_get_type              (void);
+
+HalFileMonitor     * hal_file_monitor_new                   (void);
+
+guint               hal_file_monitor_add_notify            (HalFileMonitor          *monitor,
+                                                           const char             *path,
+                                                           int                     mask,
+                                                           HalFileMonitorNotifyFunc notify_func,
+                                                           gpointer                data);
+void                hal_file_monitor_remove_notify         (HalFileMonitor          *monitor,
+                                                           guint                   id);
+
+G_END_DECLS
+
+#endif /* HAL_FILE_MONITOR_H */


More information about the hal-commit mailing list