replace configuration reload mechanism
authorDavid Zeuthen <davidz@redhat.com>
Thu, 12 Jul 2007 19:12:30 +0000 (15:12 -0400)
committerDavid Zeuthen <davidz@redhat.com>
Thu, 12 Jul 2007 19:12:30 +0000 (15:12 -0400)
Instead of asking the user of libpolkit to provide a huge file
monitoring abstraction we simply ask for a simple interface for
watching file descriptors and use inotify (on Linux) to watch a file,
/var/lib/PolicyKit/reload. We provide a new tool,
polkit-reload-config, that simply touches this file.

doc/man/Makefile.am
doc/man/polkit-reload-config.1.in [new file with mode: 0644]
polkit/Makefile.am
polkit/polkit-context.c
polkit/polkit-context.h
tools/Makefile.am
tools/polkit-reload-config.in [new file with mode: 0644]

index 8ed9175..2c06738 100644 (file)
@@ -1,7 +1,7 @@
 
 if MAN_PAGES_ENABLED
 
-MAN_IN_FILES = polkit-check-caller.1.in polkit-check-session.1.in polkit-policy-file-validate.1.in PolicyKit.8.in
+MAN_IN_FILES = polkit-check-caller.1.in polkit-check-session.1.in polkit-policy-file-validate.1.in PolicyKit.8.in polkit-reload-config.1.in
 
 man_MANS = $(MAN_IN_FILES:.in=)
 
diff --git a/doc/man/polkit-reload-config.1.in b/doc/man/polkit-reload-config.1.in
new file mode 100644 (file)
index 0000000..304a358
--- /dev/null
@@ -0,0 +1,36 @@
+.\" 
+.\" polkit-reload-config manual page.
+.\" Copyright (C) 2007 David Zeuthen <david@fubar.dk>
+.\"
+.TH POLKIT-RELOAD-CONFIG 1
+.SH NAME
+polkit-reload-config \- reload configuration
+.SH SYNOPSIS
+.PP
+.B polkit-reload-config
+
+.SH DESCRIPTION
+
+\fIpolkit-reload-config\fP can be used to signal all processes using
+libpolkit to reload their configuration. For more information about
+the big picture refer to the \fIPolicyKit spec\fP which can be found
+in
+.I "@docdir@/spec/polkit-spec.html"
+depending on the distribution. Only the super user can invoke this
+tool.
+
+.SH BUGS
+.PP
+Please send bug reports to either the distribution or the HAL
+mailing list, see 
+.I "http://lists.freedesktop.org/mailman/listinfo/hal"
+on how to subscribe.
+
+.SH SEE ALSO
+.PP
+\&\fIPolicyKit\fR\|(8)
+
+.SH AUTHOR
+Written by David Zeuthen <david@fubar.dk> with a lot of help from many
+others.
+
index 8dfc805..36fae4c 100644 (file)
@@ -55,3 +55,10 @@ libpolkit_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
 
 clean-local :
        rm -f *~ $(BUILT_SOURCES)
+
+# Create /var/lib/PolicyKit/reload file; this is being watched by libpolkit
+# for config file changes.
+install-data-local:
+       touch $(DESTDIR)$(localstatedir)/lib/PolicyKit/reload
+       -chmod 700 $(DESTDIR)$(localstatedir)/lib/PolicyKit/reload
+
index b099bd0..19ba81d 100644 (file)
@@ -35,6 +35,7 @@
 #include <grp.h>
 #include <unistd.h>
 #include <errno.h>
+#include <sys/inotify.h>
 
 #include <glib.h>
 #include "polkit-debug.h"
@@ -67,14 +68,19 @@ struct PolKitContext
         PolKitContextConfigChangedCB config_changed_cb;
         void *config_changed_user_data;
 
-        PolKitContextFileMonitorAddWatch      file_monitor_add_watch_func;
-        PolKitContextFileMonitorRemoveWatch   file_monitor_remove_watch_func;
+        PolKitContextAddIOWatch      io_add_watch_func;
+        PolKitContextRemoveIOWatch   io_remove_watch_func;
 
         char *policy_dir;
 
         PolKitPolicyCache *priv_cache;
 
         polkit_bool_t load_descriptions;
+
+        int inotify_fd;
+        int inotify_fd_watch_id;
+
+        int inotify_reload_wd;
 };
 
 /**
@@ -92,40 +98,6 @@ polkit_context_new (void)
         pk_context->refcount = 1;
         return pk_context;
 }
-
-static void
-_config_file_events (PolKitContext                 *pk_context,
-                     PolKitContextFileMonitorEvent  event_mask,
-                     const char                    *path,
-                     void                          *user_data)
-{
-        _pk_debug ("Config file changed");
-
-        /* signal that our configuration (may have) changed */
-        if (pk_context->config_changed_cb) {
-                pk_context->config_changed_cb (pk_context, pk_context->config_changed_user_data);
-        }
-}
-
-static void
-_policy_dir_events (PolKitContext                 *pk_context,
-                       PolKitContextFileMonitorEvent  event_mask,
-                       const char                    *path,
-                       void                          *user_data)
-{
-        /* mark cache of policy files as stale.. (will be populated on-demand, see _get_cache()) */
-        if (pk_context->priv_cache != NULL) {
-                _pk_debug ("Something happened in %s - invalidating cache", pk_context->policy_dir);
-                polkit_policy_cache_unref (pk_context->priv_cache);
-                pk_context->priv_cache = NULL;
-        }
-
-        /* signal that our configuration (may have) changed */
-        if (pk_context->config_changed_cb) {
-                pk_context->config_changed_cb (pk_context, pk_context->config_changed_user_data);
-        }
-}
-
 /**
  * polkit_context_init:
  * @pk_context: the context object
@@ -150,39 +122,41 @@ polkit_context_init (PolKitContext *pk_context, PolKitError **error)
         }
         _pk_debug ("Using policy files from directory %s", pk_context->policy_dir);
 
-        /* don't populate the cache until it's needed.. */
+        /* we don't populate the cache until it's needed.. */
+        if (pk_context->io_add_watch_func != NULL) {
+                pk_context->inotify_fd = inotify_init ();
+                if (pk_context->inotify_fd < 0) {
+                        _pk_debug ("failed to initialize inotify: %s", strerror (errno));
+                        /* TODO: set error */
+                        goto error;
+                }
 
-        if (pk_context->file_monitor_add_watch_func == NULL) {
-                _pk_debug ("No file monitor; cannot monitor '%s' for .policy file changes", pk_context->policy_dir);
-        } else {
-                /* Watch when policy definitions file change */
-                pk_context->file_monitor_add_watch_func (pk_context, 
-                                                         pk_context->policy_dir,
-                                                         POLKIT_CONTEXT_FILE_MONITOR_EVENT_CREATE|
-                                                         POLKIT_CONTEXT_FILE_MONITOR_EVENT_DELETE|
-                                                         POLKIT_CONTEXT_FILE_MONITOR_EVENT_CHANGE,
-                                                         _policy_dir_events,
-                                                         NULL);
-
-                /* Config file changes */
-                pk_context->file_monitor_add_watch_func (pk_context, 
-                                                         PACKAGE_DATA_DIR "/PolicyKit",
-                                                         POLKIT_CONTEXT_FILE_MONITOR_EVENT_CREATE|
-                                                         POLKIT_CONTEXT_FILE_MONITOR_EVENT_DELETE|
-                                                         POLKIT_CONTEXT_FILE_MONITOR_EVENT_CHANGE,
-                                                         _config_file_events,
-                                                         NULL);
+                /* create a watch on /var/lib/PolicyKit/reload */
+                pk_context->inotify_reload_wd = inotify_add_watch (pk_context->inotify_fd, 
+                                                                   PACKAGE_LOCALSTATEDIR "/lib/PolicyKit/reload", 
+                                                                   IN_MODIFY | IN_CREATE | IN_ATTRIB);
+                if (pk_context->inotify_reload_wd < 0) {
+                        _pk_debug ("failed to add watch on file '" PACKAGE_LOCALSTATEDIR "/lib/PolicyKit/reload': %s",
+                                   strerror (errno));
+                        /* TODO: set error */
+                        goto error;
+                }
+
+                pk_context->inotify_fd_watch_id = pk_context->io_add_watch_func (pk_context, pk_context->inotify_fd);
+                if (pk_context->inotify_fd_watch_id == 0) {
+                        _pk_debug ("failed to add io watch");
+                        /* TODO: set error */
+                        goto error;
+                }
         }
 
         return TRUE;
 
-#if 0
 error:
         if (pk_context != NULL)
                 polkit_context_unref (pk_context);
 
         return FALSE;
-#endif
 }
 
 /**
@@ -244,8 +218,8 @@ polkit_context_unref (PolKitContext *pk_context)
  **/
 void
 polkit_context_set_config_changed (PolKitContext                *pk_context, 
-                                      PolKitContextConfigChangedCB  cb, 
-                                      void                         *user_data)
+                                   PolKitContextConfigChangedCB  cb, 
+                                   void                         *user_data)
 {
         g_return_if_fail (pk_context != NULL);
         pk_context->config_changed_cb = cb;
@@ -253,23 +227,77 @@ polkit_context_set_config_changed (PolKitContext                *pk_context,
 }
 
 /**
- * polkit_context_set_file_monitor:
+ * polkit_context_io_func:
+ * @pk_context: the object
+ * @fd: the file descriptor passed to the supplied function of type #PolKitContextAddIOWatch.
+ * 
+ * Method that the application must call when there is data to read
+ * from a file descriptor registered with the supplied function of
+ * type #PolKitContextAddIOWatch.
+ **/
+void 
+polkit_context_io_func (PolKitContext *pk_context, int fd)
+{
+        g_return_if_fail (pk_context != NULL);
+
+        _pk_debug ("polkit_context_io_func: data on fd %d", fd);
+
+        if (fd == pk_context->inotify_fd) {
+/* size of the event structure, not counting name */
+#define EVENT_SIZE  (sizeof (struct inotify_event))
+/* reasonable guess as to size of 1024 events */
+#define BUF_LEN        (1024 * (EVENT_SIZE + 16))
+                char buf[BUF_LEN];
+                int len;
+                int i = 0;
+again:
+                len = read (fd, buf, BUF_LEN);
+                if (len < 0) {
+                        if (errno == EINTR) {
+                                goto again;
+                        } else {
+                                _pk_debug ("read: %s", strerror (errno));
+                        }
+                } else if (len > 0) {
+                        /* BUF_LEN too small? */
+                }
+                while (i < len) {
+                        struct inotify_event *event;
+                        event = (struct inotify_event *) &buf[i];
+                        _pk_debug ("wd=%d mask=%u cookie=%u len=%u",
+                                   event->wd, event->mask, event->cookie, event->len);
+
+                        if (event->wd == pk_context->inotify_reload_wd) {
+                                _pk_debug ("config changed!");
+                                if (pk_context->config_changed_cb != NULL) {
+                                        pk_context->config_changed_cb (pk_context, 
+                                                                       pk_context->config_changed_user_data);
+                                }
+                        }
+
+                        i += EVENT_SIZE + event->len;
+                }
+        }
+}
+
+/**
+ * polkit_context_set_io_watch_functions:
  * @pk_context: the context object
- * @add_watch_func: the function that the PolicyKit library can invoke to start watching a file
- * @remove_watch_func: the function that the PolicyKit library can invoke to stop watching a file
+ * @io_add_watch_func: the function that the PolicyKit library can invoke to start watching a file descriptor
+ * @io_remove_watch_func: the function that the PolicyKit library can invoke to stop watching a file descriptor
  * 
- * Register a functions that PolicyKit can use for watching files.
+ * Register a functions that PolicyKit can use for watching IO descriptors.
  *
  * This method must be called before polkit_context_init().
  **/
 void
-polkit_context_set_file_monitor (PolKitContext                        *pk_context, 
-                                    PolKitContextFileMonitorAddWatch      add_watch_func,
-                                    PolKitContextFileMonitorRemoveWatch   remove_watch_func)
+polkit_context_set_io_watch_functions (PolKitContext                        *pk_context, 
+                                       PolKitContextAddIOWatch               io_add_watch_func,
+                                       PolKitContextRemoveIOWatch            io_remove_watch_func)
 {
         g_return_if_fail (pk_context != NULL);
-        pk_context->file_monitor_add_watch_func = add_watch_func;
-        pk_context->file_monitor_remove_watch_func = remove_watch_func;
+        pk_context->io_add_watch_func = io_add_watch_func;
+        pk_context->io_remove_watch_func = io_remove_watch_func;
 }
 
 /**
index 0261338..3e4fe29 100644 (file)
@@ -53,6 +53,9 @@ typedef struct PolKitContext PolKitContext;
  * permissions / acl's they have set in response to policy decisions
  * made from information provided by PolicyKit.
  *
+ * The user must have set up watches using #polkit_context_set_io_watch_functions
+ * for this to work.
+ *
  * Note that this function may be called many times within a short
  * interval due to how file monitoring works if e.g. the user is
  * editing a configuration file (editors typically create back-up
@@ -65,97 +68,101 @@ typedef void (*PolKitContextConfigChangedCB) (PolKitContext  *pk_context,
                                               void           *user_data);
 
 /**
- * PolKitContextFileMonitorEvent:
- * @POLKIT_CONTEXT_FILE_MONITOR_EVENT_NONE: TODO
- * @POLKIT_CONTEXT_FILE_MONITOR_EVENT_ACCESS: watch when a file is accessed
- * @POLKIT_CONTEXT_FILE_MONITOR_EVENT_CREATE: watch when a file is created
- * @POLKIT_CONTEXT_FILE_MONITOR_EVENT_DELETE: watch when a file is deleted
- * @POLKIT_CONTEXT_FILE_MONITOR_EVENT_CHANGE: watch when a file changes
- *
- * File monitoring events.
- **/
-typedef enum
-{
-        POLKIT_CONTEXT_FILE_MONITOR_EVENT_NONE    = 1 << 0,
-        POLKIT_CONTEXT_FILE_MONITOR_EVENT_ACCESS  = 1 << 1,
-        POLKIT_CONTEXT_FILE_MONITOR_EVENT_CREATE  = 1 << 2,
-        POLKIT_CONTEXT_FILE_MONITOR_EVENT_DELETE  = 1 << 3,
-        POLKIT_CONTEXT_FILE_MONITOR_EVENT_CHANGE  = 1 << 4,
-} PolKitContextFileMonitorEvent;
-
-/**
- * PolKitContextFileMonitorNotifyFunc:
- * @pk_context: PolicyKit context
- * @event_mask: event that happened
- * @path: the path to the monitored file
- * @user_data: the user data supplied to the function of type #PolKitContextFileMonitorAddWatch
+ * PolKitContextAddIOWatch:
+ * @pk_context: the polkit context
+ * @fd: the file descriptor to watch
  *
- * Callback when an event happens on a file that is monitored.
+ * Type for function supplied by the application to integrate a watch
+ * on a file descriptor into the applications main loop. The
+ * application must call polkit_grant_io_func() when there is data
+ * to read from the file descriptor.
+ *
+ * For glib mainloop, the function will typically look like this:
+ *
+ * <programlisting>
+ * static gboolean
+ * io_watch_have_data (GIOChannel *channel, GIOCondition condition, gpointer user_data)
+ * {
+ *         int fd;
+ *         PolKitContext *pk_context = user_data;
+ *         fd = g_io_channel_unix_get_fd (channel);
+ *         polkit_context_io_func (pk_context, fd);
+ *         return TRUE;
+ * }
+ * 
+ * static int 
+ * io_add_watch (PolKitContext *pk_context, int fd)
+ * {
+ *         guint id = 0;
+ *         GIOChannel *channel;
+ *         channel = g_io_channel_unix_new (fd);
+ *         if (channel == NULL)
+ *                 goto out;
+ *         id = g_io_add_watch (channel, G_IO_IN, io_watch_have_data, pk_context);
+ *         if (id == 0) {
+ *                 g_io_channel_unref (channel);
+ *                 goto out;
+ *         }
+ *         g_io_channel_unref (channel);
+ * out:
+ *         return id;
+ * }
+ * </programlisting>
+ *
+ * Returns: 0 if the watch couldn't be set up; otherwise an unique
+ * identifier for the watch.
  **/
-typedef void (*PolKitContextFileMonitorNotifyFunc) (PolKitContext                 *pk_context,
-                                                    PolKitContextFileMonitorEvent  event_mask,
-                                                    const char                    *path,
-                                                    void                          *user_data);
+typedef int (*PolKitContextAddIOWatch) (PolKitContext *pk_context, int fd);
 
 /**
- * PolKitContextFileMonitorAddWatch:
- * @pk_context: PolicyKit context
- * @path: path to file/directory to monitor for events
- * @event_mask: events to look for
- * @notify_cb: function to call on events
- * @user_data: user data
+ * PolKitContextRemoveIOWatch:
+ * @pk_context: the context object
+ * @watch_id: the id obtained from using the supplied function
+ * of type #PolKitContextAddIOWatch
  *
- * The type of a function that PolicyKit can use to watch file
- * events. This function must call the supplied @notify_cb function
- * (and pass @path and @user_data) on events
+ * Type for function supplied by the application to remove a watch set
+ * up via the supplied function of type #PolKitContextAddIOWatch
  *
- * Returns: A handle for the watch. If zero it means the file cannot
- * be watched. Caller can remove the watch using the supplied function
- * of type #PolKitContextFileMonitorRemoveWatch and the handle.
- */
-typedef int (*PolKitContextFileMonitorAddWatch) (PolKitContext                     *pk_context,
-                                                 const char                        *path,
-                                                 PolKitContextFileMonitorEvent      event_mask,
-                                                 PolKitContextFileMonitorNotifyFunc notify_cb,
-                                                 void                              *user_data);
-
-/**
- * PolKitContextFileMonitorRemoveWatch:
- * @pk_context: PolicyKit context
- * @watch_id: the watch id
+ * For the glib mainloop, the function will typically look like this:
  *
- * The type of a function that PolicyKit can use to stop monitoring
- * file events. Pass the handle obtained from the supplied function of
- * type #PolKitContextFileMonitorAddWatch.
- */
-typedef void (*PolKitContextFileMonitorRemoveWatch) (PolKitContext                     *pk_context,
-                                                     int                                watch_id);
+ * <programlisting>
+ * static void 
+ * io_remove_watch (PolKitContext *pk_context, int watch_id)
+ * {
+ *         g_source_remove (watch_id);
+ * }
+ * </programlisting>
+ *
+ **/
+typedef void (*PolKitContextRemoveIOWatch) (PolKitContext *pk_context, int watch_id);
+
 
+PolKitContext *polkit_context_new                    (void);
+void           polkit_context_set_config_changed     (PolKitContext                        *pk_context, 
+                                                      PolKitContextConfigChangedCB          cb, 
+                                                      void                                 *user_data);
+void           polkit_context_set_io_watch_functions (PolKitContext                        *pk_context,
+                                                      PolKitContextAddIOWatch               io_add_watch_func,
+                                                      PolKitContextRemoveIOWatch            io_remove_watch_func);
+void           polkit_context_set_load_descriptions  (PolKitContext                        *pk_context);
+polkit_bool_t  polkit_context_init                   (PolKitContext                        *pk_context, 
+                                                      PolKitError                         **error);
+PolKitContext *polkit_context_ref                    (PolKitContext                        *pk_context);
+void           polkit_context_unref                  (PolKitContext                        *pk_context);
 
-PolKitContext *polkit_context_new                (void);
-void           polkit_context_set_config_changed (PolKitContext                        *pk_context, 
-                                                  PolKitContextConfigChangedCB          cb, 
-                                                  void                                 *user_data);
-void           polkit_context_set_file_monitor   (PolKitContext                        *pk_context, 
-                                                  PolKitContextFileMonitorAddWatch      add_watch_func,
-                                                  PolKitContextFileMonitorRemoveWatch   remove_watch_func);
-void           polkit_context_set_load_descriptions (PolKitContext                        *pk_context);
-polkit_bool_t  polkit_context_init               (PolKitContext                        *pk_context, 
-                                                  PolKitError                         **error);
-PolKitContext *polkit_context_ref                (PolKitContext                        *pk_context);
-void           polkit_context_unref              (PolKitContext                        *pk_context);
+void           polkit_context_io_func                (PolKitContext *pk_context, int fd);
 
-PolKitPolicyCache *polkit_context_get_policy_cache (PolKitContext *pk_context);
+PolKitPolicyCache *polkit_context_get_policy_cache   (PolKitContext *pk_context);
 
 PolKitResult
-polkit_context_can_session_do_action (PolKitContext   *pk_context,
-                                      PolKitAction    *action,
-                                      PolKitSession   *session);
+polkit_context_can_session_do_action                 (PolKitContext   *pk_context,
+                                                      PolKitAction    *action,
+                                                      PolKitSession   *session);
 
 PolKitResult
-polkit_context_can_caller_do_action (PolKitContext   *pk_context,
-                                     PolKitAction    *action,
-                                     PolKitCaller    *caller);
+polkit_context_can_caller_do_action                  (PolKitContext   *pk_context,
+                                                      PolKitAction    *action,
+                                                      PolKitCaller    *caller);
 
 #endif /* POLKIT_CONTEXT_H */
 
index d40298d..1f5de08 100644 (file)
@@ -13,6 +13,8 @@ INCLUDES = \
 
 bin_PROGRAMS = polkit-check-caller polkit-check-session polkit-policy-file-validate polkit-grant polkit-list-actions
 
+bin_SCRIPTS = polkit-reload-config
+
 polkit_check_caller_SOURCES = polkit-check-caller.c
 polkit_check_caller_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ $(top_builddir)/polkit/libpolkit.la $(top_builddir)/polkit-dbus/libpolkit-dbus.la
 
@@ -28,6 +30,16 @@ polkit_grant_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ $(top_builddir)/polkit/libpolkit.la
 polkit_list_actions_SOURCES = polkit-list-actions.c
 polkit_list_actions_LDADD = $(GLIB) $(top_builddir)/polkit/libpolkit.la
 
+polkit-reload-config: polkit-reload-config.in Makefile
+       $(edit) $< >$@
+
+edit = sed \
+       -e 's|@docdir[@]|$(docdir)|g' \
+       -e 's|@sbindir[@]|$(sbindir)|g' \
+       -e 's|@sysconfdir[@]|$(sysconfdir)|g' \
+       -e 's|@datadir[@]|$(datadir)|g' \
+       -e 's|@localstatedir[@]|$(localstatedir)|g'
+
 clean-local :
        rm -f *~
 
diff --git a/tools/polkit-reload-config.in b/tools/polkit-reload-config.in
new file mode 100644 (file)
index 0000000..f4739f5
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+touch @localstatedir@/lib/PolicyKit/reload