From b22ebaba2a6c077a7f09bd6567177197b63fff11 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Thu, 12 Jul 2007 15:12:30 -0400 Subject: [PATCH] replace configuration reload mechanism 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 | 2 +- doc/man/polkit-reload-config.1.in | 36 ++++++++ polkit/Makefile.am | 7 ++ polkit/polkit-context.c | 168 ++++++++++++++++++++++---------------- polkit/polkit-context.h | 161 +++++++++++++++++++----------------- tools/Makefile.am | 12 +++ tools/polkit-reload-config.in | 2 + 7 files changed, 240 insertions(+), 148 deletions(-) create mode 100644 doc/man/polkit-reload-config.1.in create mode 100644 tools/polkit-reload-config.in diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am index 8ed9175..2c06738 100644 --- a/doc/man/Makefile.am +++ b/doc/man/Makefile.am @@ -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 index 0000000..304a358 --- /dev/null +++ b/doc/man/polkit-reload-config.1.in @@ -0,0 +1,36 @@ +.\" +.\" polkit-reload-config manual page. +.\" Copyright (C) 2007 David Zeuthen +.\" +.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 with a lot of help from many +others. + diff --git a/polkit/Makefile.am b/polkit/Makefile.am index 8dfc805..36fae4c 100644 --- a/polkit/Makefile.am +++ b/polkit/Makefile.am @@ -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 + diff --git a/polkit/polkit-context.c b/polkit/polkit-context.c index b099bd0..19ba81d 100644 --- a/polkit/polkit-context.c +++ b/polkit/polkit-context.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #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; } /** diff --git a/polkit/polkit-context.h b/polkit/polkit-context.h index 0261338..3e4fe29 100644 --- a/polkit/polkit-context.h +++ b/polkit/polkit-context.h @@ -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: + * + * + * 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; + * } + * + * + * 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); + * + * static void + * io_remove_watch (PolKitContext *pk_context, int watch_id) + * { + * g_source_remove (watch_id); + * } + * + * + **/ +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 */ diff --git a/tools/Makefile.am b/tools/Makefile.am index d40298d..1f5de08 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -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 index 0000000..f4739f5 --- /dev/null +++ b/tools/polkit-reload-config.in @@ -0,0 +1,2 @@ +#!/bin/sh +touch @localstatedir@/lib/PolicyKit/reload -- 2.7.4