diff options
| author | Michael Biebl <biebl@debian.org> | 2018-09-08 17:44:06 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2018-09-08 17:44:06 +0200 |
| commit | 8f7a3cbbdd0c0a48277c341dd3a8ec8743ae9735 (patch) | |
| tree | 4353551fcb59cc822c3cadf2f4888f70601e8fbf /libnm-core/nm-setting.c | |
| parent | caf1db9d6fbc056cc6c76a24574890f6c7895f3d (diff) | |
New upstream version 1.13.90 upstream/1.13.90
Diffstat (limited to 'libnm-core/nm-setting.c')
| -rw-r--r-- | libnm-core/nm-setting.c | 1303 |
1 files changed, 828 insertions, 475 deletions
diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index 218f0dad..0cec5165 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -53,9 +53,13 @@ * of properties and allowed values. */ -G_DEFINE_ABSTRACT_TYPE (NMSetting, nm_setting, G_TYPE_OBJECT) +/*****************************************************************************/ -#define NM_SETTING_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING, NMSettingPrivate)) +typedef struct { + GHashTable *hash; + const char **names; + GVariant **values; +} GenData; typedef struct { const char *name; @@ -63,10 +67,6 @@ typedef struct { NMSettingPriority priority; } SettingInfo; -typedef struct { - const SettingInfo *info; -} NMSettingPrivate; - enum { PROP_0, PROP_NAME, @@ -74,136 +74,66 @@ enum { PROP_LAST }; -/*****************************************************************************/ - -static GHashTable *registered_settings = NULL; -static GHashTable *registered_settings_by_type = NULL; - -static gboolean -_nm_gtype_equal (gconstpointer v1, gconstpointer v2) -{ - return *((const GType *) v1) == *((const GType *) v2); -} -static guint -_nm_gtype_hash (gconstpointer v) -{ - return *((const GType *) v); -} - -static void -_ensure_registered (void) -{ - if (G_UNLIKELY (registered_settings == NULL)) { - registered_settings = g_hash_table_new (nm_str_hash, g_str_equal); - registered_settings_by_type = g_hash_table_new (_nm_gtype_hash, _nm_gtype_equal); - } -} +typedef struct { + GenData *gendata; +} NMSettingPrivate; -static void __attribute__((constructor)) -_ensure_registered_constructor (void) -{ - _ensure_registered (); -} +G_DEFINE_ABSTRACT_TYPE (NMSetting, nm_setting, G_TYPE_OBJECT) -#define _ensure_setting_info(self, priv) \ - G_STMT_START { \ - NMSettingPrivate *_priv_esi = (priv); \ - if (G_UNLIKELY (!_priv_esi->info)) { \ - _priv_esi->info = _nm_setting_lookup_setting_by_type (G_OBJECT_TYPE (self)); \ - g_assert (_priv_esi->info); \ - } \ - } G_STMT_END +#define NM_SETTING_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING, NMSettingPrivate)) /*****************************************************************************/ -/* - * _nm_register_setting_impl: - * @name: the name of the #NMSetting object to register - * @type: the #GType of the #NMSetting - * @priority: the sort priority of the setting, see #NMSettingPriority - * - * INTERNAL ONLY: registers a setting's internal properties with libnm. - */ -void -_nm_register_setting_impl (const char *name, - GType type, - NMSettingPriority priority) -{ - SettingInfo *info; - - nm_assert (name && *name); - nm_assert (!NM_IN_SET (type, G_TYPE_INVALID, G_TYPE_NONE)); - nm_assert (priority != NM_SETTING_PRIORITY_INVALID); - - _ensure_registered (); - - nm_assert (!g_hash_table_lookup (registered_settings, name)); - nm_assert (!g_hash_table_lookup (registered_settings_by_type, &type)); - - nm_assert ( priority != NM_SETTING_PRIORITY_CONNECTION - || nm_streq (name, NM_SETTING_CONNECTION_SETTING_NAME)); +static GenData *_gendata_hash (NMSetting *setting, gboolean create_if_necessary); - info = g_slice_new0 (SettingInfo); - info->type = type; - info->priority = priority; - info->name = name; - g_hash_table_insert (registered_settings, (void *) info->name, info); - g_hash_table_insert (registered_settings_by_type, &info->type, info); -} - -static const SettingInfo * -_nm_setting_lookup_setting_by_type (GType type) -{ - _ensure_registered (); - return g_hash_table_lookup (registered_settings_by_type, &type); -} +/*****************************************************************************/ static NMSettingPriority -_get_setting_type_priority (GType type) +_get_base_type_priority (const NMMetaSettingInfo *setting_info, + GType gtype) { - const SettingInfo *info; + /* Historical oddity: PPPoE is a base-type even though it's not + * priority 1. It needs to be sorted *after* lower-level stuff like + * Wi-Fi security or 802.1x for secrets, but it's still allowed as a + * base type. + */ - g_return_val_if_fail (g_type_is_a (type, NM_TYPE_SETTING), G_MAXUINT32); + if (setting_info) { + if ( NM_IN_SET (setting_info->setting_priority, + NM_SETTING_PRIORITY_HW_BASE, + NM_SETTING_PRIORITY_HW_NON_BASE) + || gtype == NM_TYPE_SETTING_PPPOE) + return setting_info->setting_priority; + } - info = _nm_setting_lookup_setting_by_type (type); - return info->priority; + return NM_SETTING_PRIORITY_INVALID; } NMSettingPriority _nm_setting_get_setting_priority (NMSetting *setting) { - NMSettingPrivate *priv; + const NMMetaSettingInfo *setting_info; - g_return_val_if_fail (NM_IS_SETTING (setting), G_MAXUINT32); - priv = NM_SETTING_GET_PRIVATE (setting); - _ensure_setting_info (setting, priv); - return priv->info->priority; + g_return_val_if_fail (NM_IS_SETTING (setting), NM_SETTING_PRIORITY_INVALID); + + setting_info = NM_SETTING_GET_CLASS (setting)->setting_info; + return setting_info ? setting_info->setting_priority : NM_SETTING_PRIORITY_INVALID; } NMSettingPriority _nm_setting_type_get_base_type_priority (GType type) { - NMSettingPriority priority; - - /* Historical oddity: PPPoE is a base-type even though it's not - * priority 1. It needs to be sorted *after* lower-level stuff like - * Wi-Fi security or 802.1x for secrets, but it's still allowed as a - * base type. - */ - priority = _get_setting_type_priority (type); - if ( NM_IN_SET (priority, - NM_SETTING_PRIORITY_HW_BASE, - NM_SETTING_PRIORITY_HW_NON_BASE) - || type == NM_TYPE_SETTING_PPPOE) - return priority; - else - return NM_SETTING_PRIORITY_INVALID; + return _get_base_type_priority (nm_meta_setting_infos_by_gtype (type), + type); } NMSettingPriority _nm_setting_get_base_type_priority (NMSetting *setting) { - return _nm_setting_type_get_base_type_priority (G_OBJECT_TYPE (setting)); + g_return_val_if_fail (NM_IS_SETTING (setting), NM_SETTING_PRIORITY_INVALID); + + return _get_base_type_priority (NM_SETTING_GET_CLASS (setting)->setting_info, + G_OBJECT_TYPE (setting)); } /** @@ -218,17 +148,15 @@ _nm_setting_get_base_type_priority (NMSetting *setting) GType nm_setting_lookup_type (const char *name) { - const SettingInfo *info; + const NMMetaSettingInfo *setting_info; g_return_val_if_fail (name, G_TYPE_INVALID); - _ensure_registered (); - - info = g_hash_table_lookup (registered_settings, name); - return info ? info->type : G_TYPE_INVALID; + setting_info = nm_meta_setting_infos_by_name (name); + return setting_info ? setting_info->get_setting_gtype () : G_TYPE_INVALID; } -gint +int _nm_setting_compare_priority (gconstpointer a, gconstpointer b) { NMSettingPriority prio_a, prio_b; @@ -273,90 +201,53 @@ _nm_setting_slave_type_is_valid (const char *slave_type, const char **out_port_t /*****************************************************************************/ -typedef struct { - const char *name; - GParamSpec *param_spec; - const GVariantType *dbus_type; - - NMSettingPropertyGetFunc get_func; - NMSettingPropertySynthFunc synth_func; - NMSettingPropertySetFunc set_func; - NMSettingPropertyNotSetFunc not_set_func; - - NMSettingPropertyTransformToFunc to_dbus; - NMSettingPropertyTransformFromFunc from_dbus; -} NMSettingProperty; - -static NM_CACHED_QUARK_FCN ("nm-setting-property-overrides", setting_property_overrides_quark) -static NM_CACHED_QUARK_FCN ("nm-setting-properties", setting_properties_quark) - -static NMSettingProperty * -find_property (GArray *properties, const char *name) +static const NMSettInfoProperty * +_nm_sett_info_property_find_in_array (const NMSettInfoProperty *properties, guint len, const char *name) { - NMSettingProperty *property; - int i; - - if (!properties) - return NULL; + guint i; - for (i = 0; i < properties->len; i++) { - property = &g_array_index (properties, NMSettingProperty, i); - if (strcmp (name, property->name) == 0) - return property; + for (i = 0; i < len; i++) { + if (nm_streq (name, properties[i].name)) + return &properties[i]; } - return NULL; } -static void -add_property_override (NMSettingClass *setting_class, - const char *property_name, - GParamSpec *param_spec, - const GVariantType *dbus_type, - NMSettingPropertyGetFunc get_func, - NMSettingPropertySynthFunc synth_func, - NMSettingPropertySetFunc set_func, - NMSettingPropertyNotSetFunc not_set_func, - NMSettingPropertyTransformToFunc to_dbus, - NMSettingPropertyTransformFromFunc from_dbus) +void +_properties_override_add_struct (GArray *properties_override, + const NMSettInfoProperty *prop_info) { - GType setting_type = G_TYPE_FROM_CLASS (setting_class); - GArray *overrides; - NMSettingProperty override; - - g_return_if_fail (g_type_get_qdata (setting_type, setting_properties_quark ()) == NULL); - - memset (&override, 0, sizeof (override)); - override.name = property_name; - override.param_spec = param_spec; - override.dbus_type = dbus_type; - override.get_func = get_func; - override.synth_func = synth_func; - override.set_func = set_func; - override.not_set_func = not_set_func; - override.to_dbus = to_dbus; - override.from_dbus = from_dbus; - - overrides = g_type_get_qdata (setting_type, setting_property_overrides_quark ()); - if (!overrides) { - overrides = g_array_new (FALSE, FALSE, sizeof (NMSettingProperty)); - g_type_set_qdata (setting_type, setting_property_overrides_quark (), overrides); + nm_assert (properties_override); + nm_assert (prop_info); + nm_assert (prop_info->name || prop_info->param_spec); + nm_assert (!prop_info->param_spec || !prop_info->name || nm_streq0 (prop_info->name, prop_info->param_spec->name)); + nm_assert (!_nm_sett_info_property_find_in_array ((NMSettInfoProperty *) properties_override->data, + properties_override->len, + prop_info->name ?: prop_info->param_spec->name)); + + nm_assert (!prop_info->from_dbus || prop_info->dbus_type); + nm_assert (!prop_info->set_func || prop_info->dbus_type); + + g_array_append_vals (properties_override, prop_info, 1); + + if (!prop_info->name) { + /* for convenience, allow omitting "name" if "param_spec" is given. */ + g_array_index (properties_override, + NMSettInfoProperty, + properties_override->len - 1).name = prop_info->param_spec->name; } - g_return_if_fail (find_property (overrides, property_name) == NULL); - - g_array_append_val (overrides, override); } /** - * _nm_setting_class_add_dbus_only_property: - * @setting_class: the setting class + * _properties_override_add_dbus_only: + * @properties_override: an array collecting the overrides * @property_name: the name of the property to override * @dbus_type: the type of the property (in its D-Bus representation) * @synth_func: (allow-none): function to call to synthesize a value for the property * @set_func: (allow-none): function to call to set the value of the property * * Registers a property named @property_name, which will be used in the D-Bus - * serialization of objects of @setting_class, but which does not correspond to + * serialization of objects of this setting type, but which does not correspond to * a #GObject property. * * When serializing a setting to D-Bus, @synth_func will be called to synthesize @@ -369,35 +260,30 @@ add_property_override (NMSettingClass *setting_class, * then the property will be ignored when deserializing.) */ void -_nm_setting_class_add_dbus_only_property (NMSettingClass *setting_class, - const char *property_name, - const GVariantType *dbus_type, - NMSettingPropertySynthFunc synth_func, - NMSettingPropertySetFunc set_func) +_properties_override_add_dbus_only (GArray *properties_override, + const char *property_name, + const GVariantType *dbus_type, + NMSettingPropertySynthFunc synth_func, + NMSettingPropertySetFunc set_func) { - g_return_if_fail (NM_IS_SETTING_CLASS (setting_class)); - g_return_if_fail (property_name != NULL); - - /* Must not match any GObject property. */ - g_return_if_fail (!g_object_class_find_property (G_OBJECT_CLASS (setting_class), property_name)); - - add_property_override (setting_class, - property_name, NULL, dbus_type, - NULL, synth_func, set_func, NULL, - NULL, NULL); + _properties_override_add (properties_override, + .name = property_name, + .dbus_type = dbus_type, + .synth_func = synth_func, + .set_func = set_func); } /** - * _nm_setting_class_override_property: - * @setting_class: the setting class - * @property_name: the name of the property to override + * _properties_override_add_override: + * @properties_override: an array collecting the overrides + * @param_spec: the name of the property to override * @dbus_type: the type of the property (in its D-Bus representation) * @get_func: (allow-none): function to call to get the value of the property * @set_func: (allow-none): function to call to set the value of the property * @not_set_func: (allow-none): function to call to indicate the property was not set * - * Overrides the D-Bus representation of the #GObject property named - * @property_name on @setting_class. + * Overrides the D-Bus representation of the #GObject property that shares the + * same name as @param_spec. * * When serializing a setting to D-Bus, if @get_func is non-%NULL, then it will * be called to get the property's value. If it returns a #GVariant, the @@ -406,38 +292,38 @@ _nm_setting_class_add_dbus_only_property (NMSettingClass *setting_class, * with g_object_get_property(), and added to the hash if it is not the default * value.) * - * When deserializing a D-Bus representation into a setting, if @property_name - * is present, then @set_func will be called to set it. (If @set_func is %NULL - * then the property will be set normally with g_object_set_property().) + * When deserializing a D-Bus representation into a setting, if a value with + * the name of @param_spec is present, then @set_func will be called to set it. + * (If @set_func is %NULL then the property will be set normally with + * g_object_set_property().) * * If @not_set_func is non-%NULL, then it will be called when deserializing a - * representation that does NOT contain @property_name. This can be used, eg, if - * a new property needs to be initialized from some older deprecated property + * representation that does NOT contain a value for the property. This can be used, + * eg, if a new property needs to be initialized from some older deprecated property * when it is not present. */ void -_nm_setting_class_override_property (NMSettingClass *setting_class, - const char *property_name, - const GVariantType *dbus_type, - NMSettingPropertyGetFunc get_func, - NMSettingPropertySetFunc set_func, - NMSettingPropertyNotSetFunc not_set_func) +_properties_override_add_override (GArray *properties_override, + GParamSpec *param_spec, + const GVariantType *dbus_type, + NMSettingPropertyGetFunc get_func, + NMSettingPropertySetFunc set_func, + NMSettingPropertyNotSetFunc not_set_func) { - GParamSpec *param_spec; - - param_spec = g_object_class_find_property (G_OBJECT_CLASS (setting_class), property_name); - g_return_if_fail (param_spec != NULL); - - add_property_override (setting_class, - property_name, param_spec, dbus_type, - get_func, NULL, set_func, not_set_func, - NULL, NULL); + nm_assert (param_spec); + + _properties_override_add (properties_override, + .param_spec = param_spec, + .dbus_type = dbus_type, + .get_func = get_func, + .set_func = set_func, + .not_set_func = not_set_func); } /** - * _nm_setting_class_transform_property: - * @setting_class: the setting class - * @property: the name of the property to transform + * _properties_override_add_transform: + * @properties_override: an array collecting the overrides + * @param_spec: the param spec of the property to transform. * @dbus_type: the type of the property (in its D-Bus representation) * @to_dbus: function to convert from object to D-Bus format * @from_dbus: function to convert from D-Bus to object format @@ -451,23 +337,143 @@ _nm_setting_class_override_property (NMSettingClass *setting_class, * nm_property_compare() recognizes, as long as it recognizes @dbus_type. */ void -_nm_setting_class_transform_property (NMSettingClass *setting_class, - const char *property, - const GVariantType *dbus_type, - NMSettingPropertyTransformToFunc to_dbus, - NMSettingPropertyTransformFromFunc from_dbus) +_properties_override_add_transform (GArray *properties_override, + GParamSpec *param_spec, + const GVariantType *dbus_type, + NMSettingPropertyTransformToFunc to_dbus, + NMSettingPropertyTransformFromFunc from_dbus) +{ + nm_assert (param_spec); + + _properties_override_add (properties_override, + .param_spec = param_spec, + .dbus_type = dbus_type, + .to_dbus = to_dbus, + .from_dbus = from_dbus); +} + +static NMSettInfoSetting _sett_info_settings[_NM_META_SETTING_TYPE_NUM]; + +void +_nm_setting_class_commit_full (NMSettingClass *setting_class, + NMMetaSettingType meta_type, + const NMSettInfoSettDetail *detail, + GArray *properties_override) +{ + NMSettInfoSetting *sett_info; + gs_free GParamSpec **property_specs = NULL; + guint i, n_property_specs, override_len; + + nm_assert (NM_IS_SETTING_CLASS (setting_class)); + nm_assert (!setting_class->setting_info); + + nm_assert (meta_type < G_N_ELEMENTS (_sett_info_settings)); + + sett_info = &_sett_info_settings[meta_type]; + + nm_assert (!sett_info->setting_class); + nm_assert (!sett_info->property_infos_len); + nm_assert (!sett_info->property_infos); + + if (!properties_override) { + override_len = 0; + properties_override = _nm_sett_info_property_override_create_array (); + } else + override_len = properties_override->len; + + property_specs = g_object_class_list_properties (G_OBJECT_CLASS (setting_class), + &n_property_specs); + +#if NM_MORE_ASSERTS > 10 + /* assert that properties_override is constructed consistently. */ + for (i = 0; i < override_len; i++) { + guint j; + const NMSettInfoProperty *p = &g_array_index (properties_override, NMSettInfoProperty, i); + + nm_assert (!_nm_sett_info_property_find_in_array ((NMSettInfoProperty *) properties_override->data, + i, + p->name)); + for (j = 0; j < n_property_specs; j++) { + if (nm_streq (property_specs[j]->name, p->name)) { + nm_assert (p->param_spec == property_specs[j]); + break; + } + } + nm_assert ((j == n_property_specs) == (p->param_spec == NULL)); + } +#endif + + for (i = 0; i < n_property_specs; i++) { + const char *name = property_specs[i]->name; + NMSettInfoProperty *p; + + if (_nm_sett_info_property_find_in_array ((NMSettInfoProperty *) properties_override->data, + override_len, + name)) + continue; + + g_array_set_size (properties_override, properties_override->len + 1); + p = &g_array_index (properties_override, NMSettInfoProperty, properties_override->len - 1); + memset (p, 0, sizeof (*p)); + p->name = name; + p->param_spec = property_specs[i]; + } + + G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMSettInfoProperty, name) == 0); + g_array_sort (properties_override, nm_strcmp_p); + + setting_class->setting_info = &nm_meta_setting_infos[meta_type]; + sett_info->setting_class = setting_class; + if (detail) + sett_info->detail = *detail; + sett_info->property_infos_len = properties_override->len; + sett_info->property_infos = (const NMSettInfoProperty *) g_array_free (properties_override, + properties_override->len == 0); +} + +const NMSettInfoSetting * +_nm_sett_info_setting_get (NMSettingClass *setting_class) { - GParamSpec *param_spec; + if ( NM_IS_SETTING_CLASS (setting_class) + && setting_class->setting_info) { + nm_assert (setting_class->setting_info->meta_type < G_N_ELEMENTS (_sett_info_settings)); + return &_sett_info_settings[setting_class->setting_info->meta_type]; + } + return NULL; +} + +const NMSettInfoProperty * +_nm_sett_info_property_get (NMSettingClass *setting_class, + const char *property_name) +{ + const NMSettInfoSetting *sett_info = _nm_sett_info_setting_get (setting_class); + const NMSettInfoProperty *property; + gssize idx; + + if (!sett_info) + return NULL; + + G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMSettInfoProperty, name) == 0); + idx = nm_utils_array_find_binary_search (sett_info->property_infos, + sizeof (NMSettInfoProperty), + sett_info->property_infos_len, + &property_name, + nm_strcmp_p_with_data, + NULL); + + if (idx < 0) + return NULL; + + property = &sett_info->property_infos[idx]; - param_spec = g_object_class_find_property (G_OBJECT_CLASS (setting_class), property); - g_return_if_fail (param_spec != NULL); + nm_assert (idx == 0 || strcmp (property[-1].name, property[0].name) < 0); + nm_assert (idx == sett_info->property_infos_len - 1 || strcmp (property[0].name, property[1].name) < 0); - add_property_override (setting_class, - property, param_spec, dbus_type, - NULL, NULL, NULL, NULL, - to_dbus, from_dbus); + return property; } +/*****************************************************************************/ + gboolean _nm_setting_use_legacy_property (NMSetting *setting, GVariant *connection_dict, @@ -504,77 +510,6 @@ _nm_setting_use_legacy_property (NMSetting *setting, return FALSE; } -static GArray * -nm_setting_class_ensure_properties (NMSettingClass *setting_class) -{ - GType type = G_TYPE_FROM_CLASS (setting_class), otype; - NMSettingProperty property, *override; - GArray *overrides, *type_overrides, *properties; - GParamSpec **property_specs; - guint n_property_specs, i; - - properties = g_type_get_qdata (type, setting_properties_quark ()); - if (properties) - return properties; - - /* Build overrides array from @setting_class and its superclasses */ - overrides = g_array_new (FALSE, FALSE, sizeof (NMSettingProperty)); - for (otype = type; otype != G_TYPE_OBJECT; otype = g_type_parent (otype)) { - type_overrides = g_type_get_qdata (otype, setting_property_overrides_quark ()); - if (type_overrides) - g_array_append_vals (overrides, (NMSettingProperty *)type_overrides->data, type_overrides->len); - } - - /* Build the properties array from the GParamSpecs, obeying overrides */ - properties = g_array_new (FALSE, FALSE, sizeof (NMSettingProperty)); - - property_specs = g_object_class_list_properties (G_OBJECT_CLASS (setting_class), - &n_property_specs); - for (i = 0; i < n_property_specs; i++) { - override = find_property (overrides, property_specs[i]->name); - if (override) - property = *override; - else { - memset (&property, 0, sizeof (property)); - property.name = property_specs[i]->name; - property.param_spec = property_specs[i]; - } - g_array_append_val (properties, property); - } - g_free (property_specs); - - /* Add any remaining overrides not corresponding to GObject properties */ - for (i = 0; i < overrides->len; i++) { - override = &g_array_index (overrides, NMSettingProperty, i); - if (!g_object_class_find_property (G_OBJECT_CLASS (setting_class), override->name)) - g_array_append_val (properties, *override); - } - g_array_unref (overrides); - - g_type_set_qdata (type, setting_properties_quark (), properties); - return properties; -} - -static const NMSettingProperty * -nm_setting_class_get_properties (NMSettingClass *setting_class, guint *n_properties) -{ - GArray *properties; - - properties = nm_setting_class_ensure_properties (setting_class); - - *n_properties = properties->len; - return (NMSettingProperty *) properties->data; -} - -static const NMSettingProperty * -nm_setting_class_find_property (NMSettingClass *setting_class, const char *property_name) -{ - GArray *properties; - - properties = nm_setting_class_ensure_properties (setting_class); - return find_property (properties, property_name); -} - /*****************************************************************************/ static const GVariantType * @@ -610,7 +545,7 @@ variant_type_for_gtype (GType type) static GVariant * get_property_for_dbus (NMSetting *setting, - const NMSettingProperty *property, + const NMSettInfoProperty *property, gboolean ignore_default) { GValue prop_value = { 0, }; @@ -638,7 +573,7 @@ get_property_for_dbus (NMSetting *setting, else if (g_type_is_a (prop_value.g_type, G_TYPE_FLAGS)) dbus_value = g_variant_new_uint32 (g_value_get_flags (&prop_value)); else if (prop_value.g_type == G_TYPE_BYTES) - dbus_value = _nm_utils_bytes_to_dbus (&prop_value); + dbus_value = nm_utils_gbytes_to_variant_ay (g_value_get_boxed (&prop_value)); else dbus_value = g_dbus_gvalue_to_gvariant (&prop_value, variant_type_for_gtype (prop_value.g_type)); g_value_unset (&prop_value); @@ -647,7 +582,7 @@ get_property_for_dbus (NMSetting *setting, } static gboolean -set_property_from_dbus (const NMSettingProperty *property, +set_property_from_dbus (const NMSettInfoProperty *property, GVariant *src_value, GValue *dst_value) { @@ -698,40 +633,57 @@ set_property_from_dbus (const NMSettingProperty *property, GVariant * _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionSerializationFlags flags) { + NMSettingPrivate *priv; GVariantBuilder builder; GVariant *dbus_value; - const NMSettingProperty *properties; + const NMSettInfoSetting *sett_info; guint n_properties, i; + const char *const*gendata_keys; g_return_val_if_fail (NM_IS_SETTING (setting), NULL); - properties = nm_setting_class_get_properties (NM_SETTING_GET_CLASS (setting), &n_properties); + priv = NM_SETTING_GET_PRIVATE (setting); g_variant_builder_init (&builder, NM_VARIANT_TYPE_SETTING); + n_properties = _nm_setting_gendata_get_all (setting, &gendata_keys, NULL); for (i = 0; i < n_properties; i++) { - const NMSettingProperty *property = &properties[i]; + g_variant_builder_add (&builder, + "{sv}", + gendata_keys[i], + g_hash_table_lookup (priv->gendata->hash, gendata_keys[i])); + } + + sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting)); + for (i = 0; i < sett_info->property_infos_len; i++) { + const NMSettInfoProperty *property = &sett_info->property_infos[i]; GParamSpec *prop_spec = property->param_spec; - if (!prop_spec && !property->synth_func) { - /* D-Bus-only property with no synth_func, so we skip it. */ - continue; - } + if (!prop_spec) { + if (!property->synth_func) + continue; - if (prop_spec && !(prop_spec->flags & G_PARAM_WRITABLE)) - continue; + if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS) + continue; + } else { + if (!(prop_spec->flags & G_PARAM_WRITABLE)) + continue; - if ( prop_spec && (prop_spec->flags & NM_SETTING_PARAM_LEGACY) - && !_nm_utils_is_manager_process) - continue; + if (NM_FLAGS_ANY (prop_spec->flags, NM_SETTING_PARAM_GENDATA_BACKED)) + continue; - if ( (flags & NM_CONNECTION_SERIALIZE_NO_SECRETS) - && (prop_spec && (prop_spec->flags & NM_SETTING_PARAM_SECRET))) - continue; + if ( (prop_spec->flags & NM_SETTING_PARAM_LEGACY) + && !_nm_utils_is_manager_process) + continue; - if ( (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS) - && !(prop_spec && (prop_spec->flags & NM_SETTING_PARAM_SECRET))) - continue; + if ( (flags & NM_CONNECTION_SERIALIZE_NO_SECRETS) + && (prop_spec->flags & NM_SETTING_PARAM_SECRET)) + continue; + + if ( (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS) + && !(prop_spec->flags & NM_SETTING_PARAM_SECRET)) + continue; + } if (property->synth_func) dbus_value = property->synth_func (setting, connection, property->name); @@ -778,8 +730,8 @@ _nm_setting_new_from_dbus (GType setting_type, { gs_unref_object NMSetting *setting = NULL; gs_unref_hashtable GHashTable *keys = NULL; - const NMSettingProperty *properties; - guint i, n_properties; + const NMSettInfoSetting *sett_info; + guint i; g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (setting_type), NULL); g_return_val_if_fail (g_variant_is_of_type (setting_dict, NM_VARIANT_TYPE_SETTING), NULL); @@ -823,9 +775,29 @@ _nm_setting_new_from_dbus (GType setting_type, } } - properties = nm_setting_class_get_properties (NM_SETTING_GET_CLASS (setting), &n_properties); - for (i = 0; i < n_properties; i++) { - const NMSettingProperty *property = &properties[i]; + sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting)); + + if (sett_info->detail.gendata_info) { + GHashTable *hash; + GVariantIter iter; + char *key; + GVariant *val; + + hash = _gendata_hash (setting, TRUE)->hash; + + g_variant_iter_init (&iter, setting_dict); + while (g_variant_iter_next (&iter, "{sv}", &key, &val)) { + g_hash_table_insert (hash, + key, + val); + } + + _nm_setting_gendata_notify (setting, TRUE); + return g_steal_pointer (&setting); + } + + for (i = 0; i < sett_info->property_infos_len; i++) { + const NMSettInfoProperty *property = &sett_info->property_infos[i]; gs_unref_variant GVariant *value = NULL; gs_free_error GError *local = NULL; @@ -944,12 +916,12 @@ const GVariantType * nm_setting_get_dbus_property_type (NMSetting *setting, const char *property_name) { - const NMSettingProperty *property; + const NMSettInfoProperty *property; g_return_val_if_fail (NM_IS_SETTING (setting), NULL); g_return_val_if_fail (property_name != NULL, NULL); - property = nm_setting_class_find_property (NM_SETTING_GET_CLASS (setting), property_name); + property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), property_name); g_return_val_if_fail (property != NULL, NULL); if (property->dbus_type) @@ -961,14 +933,32 @@ nm_setting_get_dbus_property_type (NMSetting *setting, gboolean _nm_setting_get_property (NMSetting *setting, const char *property_name, GValue *value) { + const NMSettInfoSetting *sett_info; GParamSpec *prop_spec; g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); g_return_val_if_fail (property_name, FALSE); g_return_val_if_fail (value, FALSE); - prop_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property_name); + sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting)); + + if (sett_info->detail.gendata_info) { + GVariant *variant; + GenData *gendata = _gendata_hash (setting, FALSE); + + variant = gendata ? g_hash_table_lookup (gendata->hash, property_name) : NULL; + + if (!variant) { + g_value_unset (value); + return FALSE; + } + + g_value_init (value, G_TYPE_VARIANT); + g_value_set_variant (value, variant); + return TRUE; + } + prop_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property_name); if (!prop_spec) { g_value_unset (value); return FALSE; @@ -1002,16 +992,37 @@ duplicate_setting (NMSetting *setting, NMSetting * nm_setting_duplicate (NMSetting *setting) { + const NMSettInfoSetting *sett_info; GObject *dup; g_return_val_if_fail (NM_IS_SETTING (setting), NULL); dup = g_object_new (G_OBJECT_TYPE (setting), NULL); - g_object_freeze_notify (dup); - nm_setting_enumerate_values (setting, duplicate_setting, dup); - g_object_thaw_notify (dup); + sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting)); + + if (sett_info->detail.gendata_info) { + GenData *gendata = _gendata_hash (setting, FALSE); + + if ( gendata + && g_hash_table_size (gendata->hash) > 0) { + GHashTableIter iter; + GHashTable *h = _gendata_hash (NM_SETTING (dup), TRUE)->hash; + const char *key; + GVariant *val; + g_hash_table_iter_init (&iter, gendata->hash); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) { + g_hash_table_insert (h, + g_strdup (key), + g_variant_ref (val)); + } + } + } else { + g_object_freeze_notify (dup); + nm_setting_enumerate_values (setting, duplicate_setting, dup); + g_object_thaw_notify (dup); + } return NM_SETTING (dup); } @@ -1027,12 +1038,12 @@ nm_setting_duplicate (NMSetting *setting) const char * nm_setting_get_name (NMSetting *setting) { - NMSettingPrivate *priv; + const NMMetaSettingInfo *setting_info; g_return_val_if_fail (NM_IS_SETTING (setting), NULL); - priv = NM_SETTING_GET_PRIVATE (setting); - _ensure_setting_info (setting, priv); - return priv->info->name; + + setting_info = NM_SETTING_GET_CLASS (setting)->setting_info; + return setting_info ? setting_info->setting_name : NULL; } /** @@ -1126,7 +1137,7 @@ compare_property (NMSetting *setting, const GParamSpec *prop_spec, NMSettingCompareFlags flags) { - const NMSettingProperty *property; + const NMSettInfoProperty *property; GVariant *value1, *value2; int cmp; @@ -1158,7 +1169,7 @@ compare_property (NMSetting *setting, return TRUE; } - property = nm_setting_class_find_property (NM_SETTING_GET_CLASS (setting), prop_spec->name); + property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), prop_spec->name); g_return_val_if_fail (property != NULL, FALSE); value1 = get_property_for_dbus (setting, property, TRUE); @@ -1191,9 +1202,10 @@ nm_setting_compare (NMSetting *a, NMSetting *b, NMSettingCompareFlags flags) { + const NMSettInfoSetting *sett_info; GParamSpec **property_specs; guint n_property_specs; - gint same = TRUE; + int same = TRUE; guint i; g_return_val_if_fail (NM_IS_SETTING (a), FALSE); @@ -1203,6 +1215,18 @@ nm_setting_compare (NMSetting *a, if (G_OBJECT_TYPE (a) != G_OBJECT_TYPE (b)) return FALSE; + sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (a)); + + if (sett_info->detail.gendata_info) { + GenData *a_gendata = _gendata_hash (a, FALSE); + GenData *b_gendata = _gendata_hash (b, FALSE); + + return nm_utils_hash_table_equal (a_gendata ? a_gendata->hash : NULL, + b_gendata ? b_gendata->hash : NULL, + TRUE, + g_variant_equal); + } + /* And now all properties */ property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a), &n_property_specs); for (i = 0; i < n_property_specs && same; i++) { @@ -1288,6 +1312,21 @@ should_compare_prop (NMSetting *setting, return TRUE; } +static void +_setting_diff_add_result (GHashTable *results, const char *prop_name, NMSettingDiffResult r) +{ + void *p; + + if (r == NM_SETTING_DIFF_RESULT_UNKNOWN) + return; + + if (g_hash_table_lookup_extended (results, prop_name, NULL, &p)) { + if (!NM_FLAGS_ALL ((guint) r, GPOINTER_TO_UINT (p))) + g_hash_table_insert (results, g_strdup (prop_name), GUINT_TO_POINTER (((guint) r) | GPOINTER_TO_UINT (p))); + } else + g_hash_table_insert (results, g_strdup (prop_name), GUINT_TO_POINTER (r)); +} + /** * nm_setting_diff: * @a: a #NMSetting @@ -1316,8 +1355,7 @@ nm_setting_diff (NMSetting *a, gboolean invert_results, GHashTable **results) { - GParamSpec **property_specs; - guint n_property_specs; + const NMSettInfoSetting *sett_info; guint i; NMSettingDiffResult a_result = NM_SETTING_DIFF_RESULT_IN_A; NMSettingDiffResult b_result = NM_SETTING_DIFF_RESULT_IN_B; @@ -1361,78 +1399,117 @@ nm_setting_diff (NMSetting *a, results_created = TRUE; } - /* And now all properties */ - property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a), &n_property_specs); + sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (a)); - for (i = 0; i < n_property_specs; i++) { - GParamSpec *prop_spec = property_specs[i]; - NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN; - - /* Handle compare flags */ - if (!should_compare_prop (a, prop_spec->name, flags, prop_spec->flags)) - continue; - if (strcmp (prop_spec->name, NM_SETTING_NAME) == 0) - continue; - - compared_any = TRUE; - - if (b) { - gboolean different; - - different = !NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags); - if (different) { - gboolean a_is_default, b_is_default; + if (sett_info->detail.gendata_info) { + const char *key; + GVariant *val, *val2; + GHashTableIter iter; + GenData *a_gendata = _gendata_hash (a, FALSE); + GenData *b_gendata = b ? _gendata_hash (b, FALSE) : NULL; + + if (!a_gendata || !b_gendata) { + if (a_gendata || b_gendata) { + NMSettingDiffResult one_sided_result; + + one_sided_result = a_gendata ? a_result : b_result; + g_hash_table_iter_init (&iter, a_gendata ? a_gendata->hash : b_gendata->hash); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) { + diff_found = TRUE; + _setting_diff_add_result (*results, key, one_sided_result); + } + } + } else { + g_hash_table_iter_init (&iter, a_gendata->hash); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) { + val2 = b_gendata ? g_hash_table_lookup (b_gendata->hash, key) : NULL; + compared_any = TRUE; + if ( !val2 + || !g_variant_equal (val, val2)) { + diff_found = TRUE; + _setting_diff_add_result (*results, key, a_result); + } + } + g_hash_table_iter_init (&iter, b_gendata->hash); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) { + val2 = a_gendata ? g_hash_table_lookup (a_gendata->hash, key) : NULL; + compared_any = TRUE; + if ( !val2 + || !g_variant_equal (val, val2)) { + diff_found = TRUE; + _setting_diff_add_result (*results, key, b_result); + } + } + } + } else { + gs_free GParamSpec **property_specs = NULL; + guint n_property_specs; + + property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a), &n_property_specs); + + for (i = 0; i < n_property_specs; i++) { + GParamSpec *prop_spec = property_specs[i]; + NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN; + + /* Handle compare flags */ + if (!should_compare_prop (a, prop_spec->name, flags, prop_spec->flags)) + continue; + if (strcmp (prop_spec->name, NM_SETTING_NAME) == 0) + continue; + + compared_any = TRUE; + + if (b) { + gboolean different; + + different = !NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags); + if (different) { + gboolean a_is_default, b_is_default; + GValue value = G_VALUE_INIT; + + g_value_init (&value, prop_spec->value_type); + g_object_get_property (G_OBJECT (a), prop_spec->name, &value); + a_is_default = g_param_value_defaults (prop_spec, &value); + + g_value_reset (&value); + g_object_get_property (G_OBJECT (b), prop_spec->name, &value); + b_is_default = g_param_value_defaults (prop_spec, &value); + + g_value_unset (&value); + if ((flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT) == 0) { + if (!a_is_default) + r |= a_result; + if (!b_is_default) + r |= b_result; + } else { + r |= a_result | b_result; + if (a_is_default) + r |= a_result_default; + if (b_is_default) + r |= b_result_default; + } + } + } else if ((flags & (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) == 0) + r = a_result; /* only in A */ + else { GValue value = G_VALUE_INIT; g_value_init (&value, prop_spec->value_type); g_object_get_property (G_OBJECT (a), prop_spec->name, &value); - a_is_default = g_param_value_defaults (prop_spec, &value); - - g_value_reset (&value); - g_object_get_property (G_OBJECT (b), prop_spec->name, &value); - b_is_default = g_param_value_defaults (prop_spec, &value); + if (!g_param_value_defaults (prop_spec, &value)) + r |= a_result; + else if (flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT) + r |= a_result | a_result_default; g_value_unset (&value); - if ((flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT) == 0) { - if (!a_is_default) - r |= a_result; - if (!b_is_default) - r |= b_result; - } else { - r |= a_result | b_result; - if (a_is_default) - r |= a_result_default; - if (b_is_default) - r |= b_result_default; - } } - } else if ((flags & (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) == 0) - r = a_result; /* only in A */ - else { - GValue value = G_VALUE_INIT; - g_value_init (&value, prop_spec->value_type); - g_object_get_property (G_OBJECT (a), prop_spec->name, &value); - if (!g_param_value_defaults (prop_spec, &value)) - r |= a_result; - else if (flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT) - r |= a_result | a_result_default; - - g_value_unset (&value); - } - - if (r != NM_SETTING_DIFF_RESULT_UNKNOWN) { - void *p; - - diff_found = TRUE; - if (g_hash_table_lookup_extended (*results, prop_spec->name, NULL, &p)) { - if ((r & GPOINTER_TO_UINT (p)) != r) - g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (r | GPOINTER_TO_UINT (p))); - } else - g_hash_table_insert (*results, g_strdup (prop_spec->name), GUINT_TO_POINTER (r)); + if (r != NM_SETTING_DIFF_RESULT_UNKNOWN) { + diff_found = TRUE; + _setting_diff_add_result (*results, prop_spec->name, r); + } } } - g_free (property_specs); if (!compared_any && !b) { /* special case: the setting has no properties, and the opposite @@ -1443,7 +1520,7 @@ nm_setting_diff (NMSetting *a, if (diff_found) { /* if there is a difference, we always return FALSE. It also means, we might - * have allocated a new @results hash, and return if to the caller. */ + * have allocated a new @results hash, and return it to the caller. */ return FALSE; } else { if (results_created) { @@ -1499,23 +1576,57 @@ nm_setting_enumerate_values (NMSetting *setting, NMSettingValueIterFn func, gpointer user_data) { + const NMSettInfoSetting *sett_info; GParamSpec **property_specs; - guint n_property_specs; - int i; + guint n_properties; + guint i; GType type; g_return_if_fail (NM_IS_SETTING (setting)); g_return_if_fail (func != NULL); - property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs); + sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting)); + + if (sett_info->detail.gendata_info) { + const char *const*names; + + /* the properties of this setting are not real GObject properties. + * Hence, this API makes little sense (or does it?). Still, call + * @func with each value. */ + n_properties = _nm_setting_gendata_get_all (setting, &names, NULL); + if (n_properties > 0) { + gs_strfreev char **keys = g_strdupv ((char **) names); + GHashTable *h = _gendata_hash (setting, FALSE)->hash; + + for (i = 0; i < n_properties; i++) { + GValue value = G_VALUE_INIT; + GVariant *val = g_hash_table_lookup (h, keys[i]); + + if (!val) { + /* was deleted in the meantime? Skip */ + continue; + } + + g_value_init (&value, G_TYPE_VARIANT); + g_value_set_variant (&value, val); + /* call it will GParamFlags 0. It shall indicate that this + * is not a "real" GObject property. */ + func (setting, keys[i], &value, 0, user_data); + g_value_unset (&value); + } + } + return; + } + + property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_properties); /* sort the properties. This has an effect on the order in which keyfile * prints them. */ type = G_OBJECT_TYPE (setting); - g_qsort_with_data (property_specs, n_property_specs, sizeof (gpointer), + g_qsort_with_data (property_specs, n_properties, sizeof (gpointer), (GCompareDataFunc) _enumerate_values_sort, &type); - for (i = 0; i < n_property_specs; i++) { + for (i = 0; i < n_properties; i++) { GParamSpec *prop_spec = property_specs[i]; GValue value = G_VALUE_INIT; @@ -1541,7 +1652,7 @@ nm_setting_enumerate_values (NMSetting *setting, gboolean _nm_setting_clear_secrets (NMSetting *setting) { - GParamSpec **property_specs; + gs_free GParamSpec **property_specs = NULL; guint n_property_specs; guint i; gboolean changed = FALSE; @@ -1549,7 +1660,6 @@ _nm_setting_clear_secrets (NMSetting *setting) g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs); - for (i = 0; i < n_property_specs; i++) { GParamSpec *prop_spec = property_specs[i]; @@ -1566,9 +1676,6 @@ _nm_setting_clear_secrets (NMSetting *setting) g_value_unset (&value); } } - - g_free (property_specs); - return changed; } @@ -1619,7 +1726,7 @@ _nm_setting_clear_secrets_with_flags (NMSetting *setting, NMSettingClearSecretsWithFlagsFn func, gpointer user_data) { - GParamSpec **property_specs; + gs_free GParamSpec **property_specs = NULL; guint n_property_specs; guint i; gboolean changed = FALSE; @@ -1637,8 +1744,6 @@ _nm_setting_clear_secrets_with_flags (NMSetting *setting, user_data); } } - - g_free (property_specs); return changed; } @@ -1672,11 +1777,11 @@ _nm_setting_need_secrets (NMSetting *setting) static int update_one_secret (NMSetting *setting, const char *key, GVariant *value, GError **error) { - const NMSettingProperty *property; + const NMSettInfoProperty *property; GParamSpec *prop_spec; GValue prop_value = { 0, }; - property = nm_setting_class_find_property (NM_SETTING_GET_CLASS (setting), key); + property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), key); if (!property) { g_set_error_literal (error, NM_CONNECTION_ERROR, @@ -1765,10 +1870,10 @@ _nm_setting_update_secrets (NMSetting *setting, GVariant *secrets, GError **erro static gboolean is_secret_prop (NMSetting *setting, const char *secret_name, GError **error) { - const NMSettingProperty *property; + const NMSettInfoProperty *property; GParamSpec *pspec; - property = nm_setting_class_find_property (NM_SETTING_GET_CLASS (setting), secret_name); + property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), secret_name); if (!property) { g_set_error_literal (error, NM_CONNECTION_ERROR, @@ -1888,59 +1993,40 @@ nm_setting_set_secret_flags (NMSetting *setting, * nm_setting_to_string: * @setting: the #NMSetting * - * Convert the setting into a string. For debugging purposes ONLY, should NOT - * be used for serialization of the setting, or machine-parsed in any way. The - * output format is not guaranteed to be stable and may change at any time. + * Convert the setting (including secrets!) into a string. For debugging + * purposes ONLY, should NOT be used for serialization of the setting, + * or machine-parsed in any way. The output format is not guaranteed to + * be stable and may change at any time. * * Returns: an allocated string containing a textual representation of the - * setting's properties and values (including secrets!), which the caller should + * setting's properties and values, which the caller should * free with g_free() **/ char * nm_setting_to_string (NMSetting *setting) { GString *string; - GParamSpec **property_specs; - guint n_property_specs; - guint i; - - g_return_val_if_fail (NM_IS_SETTING (setting), NULL); - - property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs); + gs_unref_variant GVariant *variant = NULL; + GVariant *child; + GVariantIter iter; string = g_string_new (nm_setting_get_name (setting)); g_string_append_c (string, '\n'); - for (i = 0; i < n_property_specs; i++) { - GParamSpec *prop_spec = property_specs[i]; - GValue value = G_VALUE_INIT; - char *value_str; - gboolean is_default; - - if (strcmp (prop_spec->name, NM_SETTING_NAME) == 0) - continue; - - g_value_init (&value, prop_spec->value_type); - g_object_get_property (G_OBJECT (setting), prop_spec->name, &value); + variant = _nm_setting_to_dbus (setting, NULL, NM_CONNECTION_SERIALIZE_ALL); - value_str = g_strdup_value_contents (&value); - g_string_append_printf (string, "\t%s : %s", prop_spec->name, value_str); - g_free (value_str); + g_variant_iter_init (&iter, variant); + while ((child = g_variant_iter_next_value (&iter))) { + gs_free char *name = NULL; + gs_free char *value_str = NULL; + gs_unref_variant GVariant *value = NULL; - is_default = g_param_value_defaults (prop_spec, &value); - g_value_unset (&value); + g_variant_get (child, "{sv}", &name, &value); + value_str = g_variant_print (value, FALSE); - g_string_append (string, " ("); - g_string_append_c (string, 's'); - if (is_default) - g_string_append_c (string, 'd'); - g_string_append_c (string, ')'); - g_string_append_c (string, '\n'); + g_string_append_printf (string, "\t%s : %s\n", name, value_str); } - g_free (property_specs); - g_string_append_c (string, '\n'); - return g_string_free (string, FALSE); } @@ -1962,17 +2048,257 @@ _nm_setting_get_deprecated_virtual_interface_name (NMSetting *setting, /*****************************************************************************/ -static void -nm_setting_init (NMSetting *setting) +static GenData * +_gendata_hash (NMSetting *setting, gboolean create_if_necessary) { + NMSettingPrivate *priv; + + nm_assert (NM_IS_SETTING (setting)); + + priv = NM_SETTING_GET_PRIVATE (setting); + + if (G_UNLIKELY (!priv->gendata)) { + if (!create_if_necessary) + return NULL; + priv->gendata = g_slice_new (GenData); + priv->gendata->hash = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref); + priv->gendata->names = NULL; + priv->gendata->values = NULL; + } + + return priv->gendata; } -static void -constructed (GObject *object) +GHashTable * +_nm_setting_gendata_hash (NMSetting *setting, gboolean create_if_necessary) { - _ensure_setting_info (object, NM_SETTING_GET_PRIVATE (object)); + GenData *gendata; - G_OBJECT_CLASS (nm_setting_parent_class)->constructed (object); + gendata = _gendata_hash (setting, create_if_necessary); + return gendata ? gendata->hash : NULL; +} + +void +_nm_setting_gendata_notify (NMSetting *setting, + gboolean names_changed) +{ + GenData *gendata; + + gendata = _gendata_hash (setting, FALSE); + if (!gendata) + return; + + nm_clear_g_free (&gendata->values); + + if (names_changed) { + /* if only the values changed, it's sufficient to invalidate the + * values cache. Otherwise, the names cache must be invalidated too. */ + nm_clear_g_free (&gendata->names); + } + + /* Note, that currently there is now way to notify the subclass when gendata changed. + * gendata is only changed in two situations: + * 1) from within NMSetting itself, for example when creating a NMSetting instance + * from keyfile or a D-Bus GVariant. + * 2) actively from the subclass itself + * For 2), we don't need the notification, because the subclass knows that something + * changed. + * For 1), we currently don't need the notification either, because all that the subclass + * currently would do, is emit a g_object_notify() signal. However, 1) only happens when + * the setting instance is newly created, at that point, nobody listens to the signal. + * + * If we ever need it, then we would need to call a virtual function to notify the subclass + * that gendata changed. */ +} + +GVariant * +nm_setting_gendata_get (NMSetting *setting, + const char *name) +{ + GenData *gendata; + + g_return_val_if_fail (NM_IS_SETTING (setting), NULL); + g_return_val_if_fail (name, NULL); + + gendata = _gendata_hash (setting, FALSE); + return gendata ? g_hash_table_lookup (gendata->hash, name) : NULL; +} + +guint +_nm_setting_gendata_get_all (NMSetting *setting, + const char *const**out_names, + GVariant *const**out_values) +{ + GenData *gendata; + GHashTable *hash; + guint i, len; + + nm_assert (NM_IS_SETTING (setting)); + + gendata = _gendata_hash (setting, FALSE); + if (!gendata) + goto out_zero; + + hash = gendata->hash; + len = g_hash_table_size (hash); + if (len == 0) + goto out_zero; + + if (!out_names && !out_values) + return len; + + if (G_UNLIKELY (!gendata->names)) { + gendata->names = nm_utils_strdict_get_keys (hash, + TRUE, + NULL); + } + + if (out_values) { + if (G_UNLIKELY (!gendata->values)) { + gendata->values = g_new (GVariant *, len + 1); + for (i = 0; i < len; i++) + gendata->values[i] = g_hash_table_lookup (hash, gendata->names[i]); + gendata->values[i] = NULL; + } + *out_values = gendata->values; + } + + NM_SET_OUT (out_names, (const char *const*) gendata->names); + return len; + +out_zero: + NM_SET_OUT (out_names, NULL); + NM_SET_OUT (out_values, NULL); + return 0; +} + +/** + * nm_setting_gendata_get_all_names: + * @setting: the #NMSetting + * @out_len: (allow-none): (out): + * + * Gives the number of generic data elements and optionally returns all their + * key names and values. This API is low level access and unless you know what you + * are doing, it might not be what you want. + * + * Returns: (array length=out_len zero-terminated=1) (transfer none): + * A %NULL terminated array of key names. If no names are present, this returns + * %NULL. The returned array and the names are owned by %NMSetting and might be invalidated + * soon. + * + * Since: 1.14 + **/ +const char *const* +nm_setting_gendata_get_all_names (NMSetting *setting, + guint *out_len) +{ + const char *const*names; + guint len; + + g_return_val_if_fail (NM_IS_SETTING (setting), NULL); + + len = _nm_setting_gendata_get_all (setting, &names, NULL); + NM_SET_OUT (out_len, len); + return names; +} + +/** + * nm_setting_gendata_get_all_values: + * @setting: the #NMSetting + * + * Gives the number of generic data elements and optionally returns all their + * key names and values. This API is low level access and unless you know what you + * are doing, it might not be what you want. + * + * Returns: (array zero-terminated=1) (transfer none): + * A %NULL terminated array of #GVariant. If no data is present, this returns + * %NULL. The returned array and the variants are owned by %NMSetting and might be invalidated + * soon. The sort order of nm_setting_gendata_get_all_names() and nm_setting_gendata_get_all_values() + * is consistent. That means, the nth value has the nth name returned by nm_setting_gendata_get_all_names(). + * + * Since: 1.14 + **/ +GVariant *const* +nm_setting_gendata_get_all_values (NMSetting *setting) +{ + GVariant *const*values; + + g_return_val_if_fail (NM_IS_SETTING (setting), NULL); + + _nm_setting_gendata_get_all (setting, NULL, &values); + return values; +} + +void +_nm_setting_gendata_to_gvalue (NMSetting *setting, + GValue *value) +{ + GenData *gendata; + GHashTable *new; + const char *key; + GVariant *val; + GHashTableIter iter; + + nm_assert (NM_IS_SETTING (setting)); + nm_assert (value); + nm_assert (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_HASH_TABLE)); + + new = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref); + + gendata = _gendata_hash (setting, FALSE); + if (gendata) { + g_hash_table_iter_init (&iter, gendata->hash); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) + g_hash_table_insert (new, g_strdup (key), g_variant_ref (val)); + } + + g_value_take_boxed (value, new); +} + +gboolean +_nm_setting_gendata_reset_from_hash (NMSetting *setting, + GHashTable *new) +{ + GenData *gendata; + GHashTableIter iter; + const char *key; + GVariant *val; + guint num; + + nm_assert (NM_IS_SETTING (setting)); + nm_assert (new); + + num = new ? g_hash_table_size (new) : 0; + + gendata = _gendata_hash (setting, num > 0); + + if (num == 0) { + if ( !gendata + || g_hash_table_size (gendata->hash) == 0) + return FALSE; + + g_hash_table_remove_all (gendata->hash); + _nm_setting_gendata_notify (setting, TRUE); + return TRUE; + } + + /* let's not bother to find out whether the new hash has any different + * content the the current gendata. Just replace it. */ + g_hash_table_remove_all (gendata->hash); + if (num > 0) { + g_hash_table_iter_init (&iter, new); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) + g_hash_table_insert (gendata->hash, g_strdup (key), g_variant_ref (val)); + } + _nm_setting_gendata_notify (setting, TRUE); + return TRUE; +} + +/*****************************************************************************/ + +static void +nm_setting_init (NMSetting *setting) +{ } static void @@ -1992,15 +2318,44 @@ get_property (GObject *object, guint prop_id, } static void +finalize (GObject *object) +{ + NMSettingPrivate *priv = NM_SETTING_GET_PRIVATE (object); + + if (priv->gendata) { + g_free (priv->gendata->names); + g_free (priv->gendata->values); + g_hash_table_unref (priv->gendata->hash); + g_slice_free (GenData, priv->gendata); + } + + G_OBJECT_CLASS (nm_setting_parent_class)->finalize (object); +} + +static void nm_setting_class_init (NMSettingClass *setting_class) { GObjectClass *object_class = G_OBJECT_CLASS (setting_class); + GModule *self_module; + gpointer func; + + /* loading libnm and legacy libraries libnm-util/libnm-glib at the same + * time is not supported. The reason is, that both libraries use the same + * glib type names ("NMSetting"), and glib does not support namespacing + * to allow for that. + * + * Arbitrarily, add a check here, see whether a known symbol from libnm-util + * is present. If it is, it indicates that the process is borked and we + * abort. */ + self_module = g_module_open (NULL, 0); + if (g_module_symbol (self_module, "nm_util_get_private", &func)) + g_error ("libnm-util symbols detected; Mixing libnm with libnm-util/libnm-glib is not supported"); + g_module_close (self_module); g_type_class_add_private (setting_class, sizeof (NMSettingPrivate)); - /* virtual methods */ - object_class->constructed = constructed; object_class->get_property = get_property; + object_class->finalize = finalize; setting_class->update_one_secret = update_one_secret; setting_class->get_secret_flags = get_secret_flags; @@ -2008,14 +2363,12 @@ nm_setting_class_init (NMSettingClass *setting_class) setting_class->compare_property = compare_property; setting_class->clear_secrets_with_flags = clear_secrets_with_flags; - /* Properties */ - /** * NMSetting:name: * * The setting's name, which uniquely identifies the setting within the * connection. Each setting type has a name unique to that type, for - * example "ppp" or "wireless" or "wired". + * example "ppp" or "802-11-wireless" or "802-3-ethernet". **/ g_object_class_install_property (object_class, PROP_NAME, |