diff --git a/docs/man/polkit.xml b/docs/man/polkit.xml index a4cdd180..aa27f471 100644 --- a/docs/man/polkit.xml +++ b/docs/man/polkit.xml @@ -103,9 +103,12 @@ System Context | | | PolicyKit1 |<---------+ +------------------+ | ^ | - | +--------------------------------------+ - | | /usr/share/polkit-1/actions/*.policy | - | +--------------------------------------+ + | +--------------------------------------------+ + | | /etc/polkit-1/actions/*.policy | + | | /run/polkit-1/actions/*.policy | + | | /usr/local/share/polkit-1/actions/*.policy | + | | /usr/share/polkit-1/actions/*.policy | + | +--------------------------------------------+ | +--------------------------------------+ | /etc/polkit-1/rules.d/*.rules | diff --git a/src/polkitbackend/polkitbackendactionpool.c b/src/polkitbackend/polkitbackendactionpool.c index 24ade4bd..153bbc59 100644 --- a/src/polkitbackend/polkitbackendactionpool.c +++ b/src/polkitbackend/polkitbackendactionpool.c @@ -88,15 +88,16 @@ static const gchar *_localize (GHashTable *translations, typedef struct { - /* directory with .policy files, e.g. /usr/share/polkit-1/actions */ - GFile *directory; + /* directories with .policy files, e.g. /usr/share/polkit-1/actions */ + GList *directories; - GFileMonitor *dir_monitor; + /* GFileMonitor instances for directories */ + GList *dir_monitors; /* maps from action_id to a ParsedAction struct */ GHashTable *parsed_actions; - /* maps from URI of parsed file to nothing */ + /* maps from basename of parsed file to nothing */ GHashTable *parsed_files; /* is TRUE only when we've read all files */ @@ -107,7 +108,7 @@ typedef struct enum { PROP_0, - PROP_DIRECTORY, + PROP_DIRECTORIES, }; enum @@ -147,11 +148,11 @@ polkit_backend_action_pool_finalize (GObject *object) pool = POLKIT_BACKEND_ACTION_POOL (object); priv = polkit_backend_action_pool_get_instance_private (pool); - if (priv->directory != NULL) - g_object_unref (priv->directory); + if (priv->directories != NULL) + g_list_free_full (priv->directories, g_object_unref); - if (priv->dir_monitor != NULL) - g_object_unref (priv->dir_monitor); + if (priv->dir_monitors != NULL) + g_list_free_full (priv->dir_monitors, g_object_unref); if (priv->parsed_actions != NULL) g_hash_table_unref (priv->parsed_actions); @@ -176,8 +177,8 @@ polkit_backend_action_pool_get_property (GObject *object, switch (prop_id) { - case PROP_DIRECTORY: - g_value_set_object (value, priv->directory); + case PROP_DIRECTORIES: + g_value_set_object (value, priv->directories); break; default: @@ -242,33 +243,49 @@ polkit_backend_action_pool_set_property (GObject *object, { PolkitBackendActionPool *pool; PolkitBackendActionPoolPrivate *priv; - GError *error; pool = POLKIT_BACKEND_ACTION_POOL (object); priv = polkit_backend_action_pool_get_instance_private (pool); switch (prop_id) { - case PROP_DIRECTORY: - priv->directory = g_value_dup_object (value); - - error = NULL; - priv->dir_monitor = g_file_monitor_directory (priv->directory, - G_FILE_MONITOR_NONE, - NULL, - &error); - if (priv->dir_monitor == NULL) - { - g_warning ("Error monitoring actions directory: %s", error->message); - g_error_free (error); - } - else - { - g_signal_connect (priv->dir_monitor, - "changed", - (GCallback) dir_monitor_changed, - pool); - } + case PROP_DIRECTORIES: + + const gchar **dir_names = (const gchar**) g_value_get_boxed (value); + + for (int n = 0; dir_names[n] != NULL; n++) + { + GFile *file; + GFileMonitor *monitor; + GError *error = NULL; + + const gchar *dir_name = dir_names[n]; + + file = g_file_new_for_path (dir_name); + priv->directories = g_list_prepend (priv->directories, file); + + monitor = g_file_monitor_directory (file, + G_FILE_MONITOR_NONE, + NULL, + &error); + if (monitor == NULL) + { + g_warning ("Error monitoring actions directory: %s", error->message); + g_error_free (error); + } + else + { + g_signal_connect (monitor, + "changed", + (GCallback) dir_monitor_changed, + pool); + priv->dir_monitors = g_list_prepend (priv->dir_monitors, monitor); + } + } + + priv->directories = g_list_reverse(priv->directories); + priv->dir_monitors = g_list_reverse(priv->dir_monitors); + break; default: @@ -292,16 +309,16 @@ polkit_backend_action_pool_class_init (PolkitBackendActionPoolClass *klass) * The directory to load action description files from. */ g_object_class_install_property (gobject_class, - PROP_DIRECTORY, - g_param_spec_object ("directory", - "Directory", - "Directory to load action description files from", - G_TYPE_FILE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); + PROP_DIRECTORIES, + g_param_spec_boxed ("directories", + "Directories", + "Directories to load action description files from", + G_TYPE_STRV, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB)); /** * PolkitBackendActionPool::changed: @@ -329,12 +346,12 @@ polkit_backend_action_pool_class_init (PolkitBackendActionPoolClass *klass) * Returns: A #PolkitBackendActionPool. Free with g_object_unref(). **/ PolkitBackendActionPool * -polkit_backend_action_pool_new (GFile *directory) +polkit_backend_action_pool_new (const gchar **directories) { PolkitBackendActionPool *pool; pool = POLKIT_BACKEND_ACTION_POOL (g_object_new (POLKIT_BACKEND_TYPE_ACTION_POOL, - "directory", directory, + "directories", directories, NULL)); return pool; @@ -454,17 +471,18 @@ ensure_file (PolkitBackendActionPool *pool, { PolkitBackendActionPoolPrivate *priv; gchar *contents; - GError *error; - gchar *uri; + GError *error = NULL; + gchar *path; + gchar *basename; priv = polkit_backend_action_pool_get_instance_private (pool); - uri = g_file_get_uri (file); + path = g_file_get_path (file); + basename = g_file_get_basename (file); - if (g_hash_table_lookup (priv->parsed_files, uri) != NULL) + if (g_hash_table_lookup_extended (priv->parsed_files, basename, NULL, NULL) == TRUE) goto out; - error = NULL; if (!g_file_load_contents (file, NULL, &contents, @@ -472,7 +490,7 @@ ensure_file (PolkitBackendActionPool *pool, NULL, &error)) { - g_warning ("Error loading file with URI '%s': %s", uri, error->message); + g_warning ("Error loading file with path '%s': %s", path, error->message); goto out; } @@ -480,75 +498,85 @@ ensure_file (PolkitBackendActionPool *pool, contents, &error)) { - g_warning ("Error parsing file with URI '%s': %s", uri, error->message); + g_warning ("Error parsing file with path '%s': %s", path, error->message); g_free (contents); goto out; } g_free (contents); - /* steal uri */ - g_hash_table_insert (priv->parsed_files, uri, NULL); - uri = NULL; + /* steal basename */ + g_hash_table_insert (priv->parsed_files, basename, NULL); + basename = NULL; out: - g_free (uri); + g_free (basename); + g_free (path); } static void ensure_all_files (PolkitBackendActionPool *pool) { PolkitBackendActionPoolPrivate *priv; - GFileEnumerator *e; - GFileInfo *file_info; - GError *error; - priv = polkit_backend_action_pool_get_instance_private (pool); + GList *files = NULL; - e = NULL; + priv = polkit_backend_action_pool_get_instance_private (pool); if (priv->has_loaded_all_files) goto out; - error = NULL; - e = g_file_enumerate_children (priv->directory, - "standard::name", - G_FILE_QUERY_INFO_NONE, - NULL, - &error); - if (error != NULL) + for (GList *l = priv->directories; l != NULL; l = l->next) + { + GError *error = NULL; + GFileEnumerator *enumerator; + + GFile* file = l->data; + + char *dir_name = g_file_get_path(file); + + enumerator = g_file_enumerate_children (file, + G_FILE_ATTRIBUTE_STANDARD_NAME, + G_FILE_QUERY_INFO_NONE, + NULL, + &error); + if (error != NULL) { - g_warning ("Error enumerating files: %s", error->message); - goto out; + g_warning ("Error enumerating files in %s: %s", dir_name, error->message); } - - while ((file_info = g_file_enumerator_next_file (e, NULL, &error)) != NULL) + else { - const gchar *name; - - name = g_file_info_get_name (file_info); - /* only consider files with the right suffix */ - if (g_str_has_suffix (name, ".policy")) - { - GFile *file; + GFileInfo *file_info; + while ((file_info = g_file_enumerator_next_file (enumerator, NULL, &error)) != NULL) + { + const gchar *name = g_file_info_get_name (file_info); + /* only consider files with the right suffix */ + if (g_str_has_suffix (name, ".policy")) + files = g_list_prepend (files, g_strdup_printf ("%s/%s", dir_name, name)); - file = g_file_get_child (priv->directory, name); + g_object_unref (file_info); + } /* for all files */ + } - ensure_file (pool, file); + g_object_unref (enumerator); + g_free (dir_name); + } - g_object_unref (file); - } + /* standard sorting places /etc before /usr as desired */ + files = g_list_sort (files, (GCompareFunc) g_strcmp0); - g_object_unref (file_info); + for (GList *l = files; l != NULL; l = l->next) + { + GFile *file = g_file_new_for_path((gchar *)l->data); + ensure_file (pool, file); + g_object_unref (file); + } - } /* for all files */ + g_list_free_full (files, g_free); priv->has_loaded_all_files = TRUE; out: - - if (e != NULL) - g_object_unref (e); } /* ---------------------------------------------------------------------------------------------------- */ diff --git a/src/polkitbackend/polkitbackendactionpool.h b/src/polkitbackend/polkitbackendactionpool.h index e992eea6..1597aee1 100644 --- a/src/polkitbackend/polkitbackendactionpool.h +++ b/src/polkitbackend/polkitbackendactionpool.h @@ -64,7 +64,7 @@ struct _PolkitBackendActionPoolClass }; GType polkit_backend_action_pool_get_type (void) G_GNUC_CONST; -PolkitBackendActionPool *polkit_backend_action_pool_new (GFile *directory); +PolkitBackendActionPool *polkit_backend_action_pool_new (const gchar **); GList *polkit_backend_action_pool_get_all_actions (PolkitBackendActionPool *pool, const gchar *locale); diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c index 972baf45..232e2ede 100644 --- a/src/polkitbackend/polkitbackendinteractiveauthority.c +++ b/src/polkitbackend/polkitbackendinteractiveauthority.c @@ -288,17 +288,22 @@ static void polkit_backend_interactive_authority_init (PolkitBackendInteractiveAuthority *authority) { PolkitBackendInteractiveAuthorityPrivate *priv; - GFile *directory; GError *error; + const gchar* directories[] = { + PACKAGE_SYSCONF_DIR "/polkit-1/actions", + "/run/polkit-1/actions", + "/usr/local/share/polkit-1/actions", + PACKAGE_DATA_DIR "/polkit-1/actions", + NULL + }; + /* Force registering error domain */ (void)POLKIT_ERROR; priv = polkit_backend_interactive_authority_get_instance_private (authority); - directory = g_file_new_for_path (PACKAGE_DATA_DIR "/polkit-1/actions"); - priv->action_pool = polkit_backend_action_pool_new (directory); - g_object_unref (directory); + priv->action_pool = polkit_backend_action_pool_new (directories); g_signal_connect (priv->action_pool, "changed", (GCallback) action_pool_changed,