From 0f9e338279ee2a17350d20d460ce1532d6366eac Mon Sep 17 00:00:00 2001 From: Iain Lane Date: Tue, 12 Nov 2013 13:10:59 +0000 Subject: [PATCH 1/2] Support overrides for vendor extensions. These live in XDG_DATA_DIRS. Similar to GSettings overrides, the highest named file takes priority, and the format is key files whose groups are interface names and key-value pairs are keys and values in serialised GVariant form. https://bugs.freedesktop.org/show_bug.cgi?id=71393 --- src/daemon.c | 12 +++++ src/daemon.h | 2 + src/extensions.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/user.c | 13 ++++- 4 files changed, 186 insertions(+), 1 deletion(-) diff --git a/src/daemon.c b/src/daemon.c index b2720f4..92b1559 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -81,6 +81,7 @@ struct DaemonPrivate { PolkitAuthority *authority; GHashTable *extension_ifaces; + GHashTable *vendor_overrides; }; typedef struct passwd * (* EntryGeneratorFunc) (GHashTable *, gpointer *); @@ -685,6 +686,9 @@ daemon_init (Daemon *daemon) daemon->priv->extension_ifaces = daemon_read_extension_ifaces (); + daemon->priv->vendor_overrides = daemon_read_vendor_overrides ( + daemon->priv->extension_ifaces); + daemon->priv->users = create_users_hash_table (); daemon->priv->passwd_monitor = setup_monitor (daemon, @@ -730,6 +734,8 @@ daemon_finalize (GObject *object) g_hash_table_unref (daemon->priv->extension_ifaces); + g_hash_table_unref (daemon->priv->vendor_overrides); + G_OBJECT_CLASS (daemon_parent_class)->finalize (object); } @@ -1559,6 +1565,12 @@ daemon_get_extension_ifaces (Daemon *daemon) return daemon->priv->extension_ifaces; } +GHashTable * +daemon_get_vendor_overrides (Daemon *daemon) +{ + return daemon->priv->vendor_overrides; +} + static void get_property (GObject *object, guint prop_id, diff --git a/src/daemon.h b/src/daemon.h index b7e072e..004a16e 100644 --- a/src/daemon.h +++ b/src/daemon.h @@ -97,7 +97,9 @@ gboolean daemon_local_set_automatic_login (Daemon *daemon, GError **error); GHashTable * daemon_read_extension_ifaces (void); +GHashTable * daemon_read_vendor_overrides (GHashTable *extension_ifaces); GHashTable * daemon_get_extension_ifaces (Daemon *daemon); +GHashTable * daemon_get_vendor_overrides (Daemon *daemon); G_END_DECLS diff --git a/src/extensions.c b/src/extensions.c index 9e9a7ea..705967e 100644 --- a/src/extensions.c +++ b/src/extensions.c @@ -165,3 +165,163 @@ daemon_read_extension_ifaces (void) return ifaces; } + +static void +daemon_read_override_directory (gchar *path, + GPtrArray *overrides) +{ + const gchar *name; + GDir *dir; + + dir = g_dir_open (path, 0, NULL); + + if (!dir) + return; + + while ((name = g_dir_read_name (dir))) { + if (g_str_has_suffix (name, ".override")) { + char *filename = g_build_filename (path, name, NULL); + g_debug ("Found override file '%s'", filename); + g_ptr_array_add (overrides, (gpointer) filename); + } + } + + g_dir_close (dir); +} + +static GVariant * +get_extension_iface_property_type (GHashTable *extension_ifaces, + const gchar *interface, + const gchar *property) +{ + GDBusPropertyInfo *property_info; + GDBusInterfaceInfo *info = g_hash_table_lookup (extension_ifaces, + interface); + + if (!info) + return NULL; + + property_info = g_dbus_interface_info_lookup_property (info, property); + + if (!property_info) + return NULL; + + return g_variant_new_signature (property_info->signature); +} + + +static void +daemon_read_override_file (const gchar *filename, + GHashTable *results, + GHashTable *extension_ifaces) +{ + GKeyFile *key_file = g_key_file_new (); + + char **groups = NULL, **keys = NULL; + GError *error = NULL; + GVariant *signature, *tmp; + GHashTable *hash; + gint i, j; + + g_key_file_load_from_file (key_file, filename, 0, &error); + + if (error) { + g_warning ("Couldn't load override file '%s': %s", + filename, + error->message); + g_error_free (error); + + return; + } + + groups = g_key_file_get_groups (key_file, NULL); + + for (i = 0; groups[i]; ++i) { + hash = g_hash_table_lookup (results, groups[i]); + if (!hash) { + hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + (GDestroyNotify) g_variant_unref); + g_hash_table_insert (results, g_strdup (groups[i]), hash); + } + keys = g_key_file_get_keys (key_file, groups[i], NULL, NULL); + for (j = 0; keys[j]; ++j) { + signature = get_extension_iface_property_type (extension_ifaces, + groups[i], + keys[j]); + if (!signature) { + g_warning ("Found override for '%s' on '%s' but no property " + "by this name was found.", keys[j], groups[i]); + } else { + tmp = g_variant_parse ( + G_VARIANT_TYPE (g_variant_get_string (signature, + NULL)), + g_key_file_get_value (key_file, groups[i], keys[j], + NULL), + NULL, NULL, &error); + if (!tmp) { + gchar * type = g_variant_print (signature, TRUE); + g_warning ("Couldn't parse override for '%s' on '%s' with " + "type '%s'",keys[j], groups[i], type); + g_free (type); + } else { + g_hash_table_insert (hash, g_strdup (keys[j]), tmp); + } + } + } + g_strfreev (keys); + } + + g_strfreev (groups); + + if (key_file) + g_key_file_free (key_file); +} + +static gint +compare_strings (gconstpointer a, + gconstpointer b) +{ + gchar *one = *(gchar **) a; + gchar *two = *(gchar **) b; + + return strcmp(one, two); +} + + +GHashTable * +daemon_read_vendor_overrides (GHashTable *extension_ifaces) +{ + const gchar * const *data_dirs; + GPtrArray *overrides; + GHashTable *results; + + results = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + (GDestroyNotify) g_hash_table_unref); + + data_dirs = g_get_system_data_dirs (); + overrides = g_ptr_array_new_with_free_func (g_free); + + gint i; + for (i = 0; data_dirs[i]; ++i) { + gchar *path = g_build_filename (data_dirs[i], + "accountsservice/interfaces", + NULL); + + daemon_read_override_directory (path, overrides); + + g_free (path); + } + + g_ptr_array_sort (overrides, compare_strings); + g_ptr_array_add (overrides, NULL); + + const gchar *filename; + i = 0; + while ((filename = (char *) g_ptr_array_index (overrides, i++))) { + daemon_read_override_file (filename, results, extension_ifaces); + } + + g_ptr_array_free (overrides, TRUE); + + return results; +} diff --git a/src/user.c b/src/user.c index 1698eeb..0d54cc1 100644 --- a/src/user.c +++ b/src/user.c @@ -470,6 +470,7 @@ user_extension_get_value (User *user, { const GVariantType *type = G_VARIANT_TYPE (property->signature); GVariant *value; + GHashTable *overrides; gchar *printed; gint i; @@ -483,7 +484,17 @@ user_extension_get_value (User *user, return value; } - /* If that didn't work, try for a default value annotation */ + /* If that didn't work, try to look up a vendor override */ + overrides = (GHashTable *) g_hash_table_lookup + (daemon_get_vendor_overrides (user->daemon), interface->name); + + if (overrides) + value = g_hash_table_lookup (overrides, property->name); + + if (value) + return value; + + /* If *that* didn't work, try for a default value annotation */ for (i = 0; property->annotations && property->annotations[i]; i++) { GDBusAnnotationInfo *annotation = property->annotations[i]; -- 1.8.4.3