diff options
Diffstat (limited to 'libnm-core/nm-setting.c')
| -rw-r--r-- | libnm-core/nm-setting.c | 128 |
1 files changed, 105 insertions, 23 deletions
diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index fec645b2..0c41bd84 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -774,6 +774,7 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionS * mapping property names to values * @connection_dict: the #GVariant containing an %NM_VARIANT_TYPE_CONNECTION * dictionary mapping setting names to dictionaries. + * @parse_flags: flags to determine behavior during parsing. * @error: location to store error, or %NULL * * Creates a new #NMSetting object and populates that object with the properties @@ -790,16 +791,20 @@ NMSetting * _nm_setting_new_from_dbus (GType setting_type, GVariant *setting_dict, GVariant *connection_dict, + NMSettingParseFlags parse_flags, GError **error) { - NMSetting *setting; + gs_unref_object NMSetting *setting = NULL; + gs_unref_hashtable GHashTable *keys = NULL; const NMSettingProperty *properties; - guint n_properties; - guint i; + guint i, n_properties; 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); + nm_assert (!NM_FLAGS_ANY (parse_flags, ~NM_SETTING_PARSE_FLAGS_ALL)); + nm_assert (!NM_FLAGS_ALL (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT | NM_SETTING_PARSE_FLAGS_BEST_EFFORT)); + /* connection_dict is not technically optional, but some tests in test-general * don't bother with it in cases where they know it's not needed. */ @@ -813,19 +818,49 @@ _nm_setting_new_from_dbus (GType setting_type, */ setting = (NMSetting *) g_object_new (setting_type, NULL); + if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) { + GVariantIter iter; + GVariant *entry, *entry_key; + char *key; + + keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + g_variant_iter_init (&iter, setting_dict); + while ((entry = g_variant_iter_next_value (&iter))) { + entry_key = g_variant_get_child_value (entry, 0); + key = g_strdup (g_variant_get_string (entry_key, NULL)); + g_variant_unref (entry_key); + g_variant_unref (entry); + + if (!nm_g_hash_table_add (keys, key)) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING, + _("duplicate property")); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), key); + return NULL; + } + } + } + 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]; - GVariant *value; + gs_unref_variant GVariant *value = NULL; + gs_free_error GError *local = NULL; if (property->param_spec && !(property->param_spec->flags & G_PARAM_WRITABLE)) continue; value = g_variant_lookup_value (setting_dict, property->name, NULL); + if (value && keys) + g_hash_table_remove (keys, property->name); + if (value && property->set_func) { + if (!g_variant_type_equal (g_variant_get_type (value), property->dbus_type)) { - property_type_error: + /* for backward behavior, fail unless best-effort is chosen. */ + if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT)) + continue; g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("can't set property of type '%s' from value of type '%s'"), property->dbus_type ? @@ -834,36 +869,83 @@ _nm_setting_new_from_dbus (GType setting_type, g_type_name (property->param_spec->value_type) : "(unknown)", g_variant_get_type_string (value)); g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name); - - g_variant_unref (value); - g_object_unref (setting); return NULL; } - property->set_func (setting, - connection_dict, - property->name, - value); + if (!property->set_func (setting, + connection_dict, + property->name, + value, + parse_flags, + &local)) { + if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) + continue; + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("failed to set property: %s"), + local->message); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name); + return NULL; + } } else if (!value && property->not_set_func) { - property->not_set_func (setting, - connection_dict, - property->name); + if (!property->not_set_func (setting, + connection_dict, + property->name, + parse_flags, + &local)) { + if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) + continue; + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("failed to set property: %s"), + local->message); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name); + return NULL; + } } else if (value && property->param_spec) { - GValue object_value = { 0, }; + nm_auto_unset_gvalue GValue object_value = G_VALUE_INIT; g_value_init (&object_value, property->param_spec->value_type); - if (!set_property_from_dbus (property, value, &object_value)) - goto property_type_error; + if (!set_property_from_dbus (property, value, &object_value)) { + /* for backward behavior, fail unless best-effort is chosen. */ + if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT)) + continue; + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("can't set property of type '%s' from value of type '%s'"), + property->dbus_type ? + g_variant_type_peek_string (property->dbus_type) : + property->param_spec ? + g_type_name (property->param_spec->value_type) : "(unknown)", + g_variant_get_type_string (value)); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name); + return NULL; + } - g_object_set_property (G_OBJECT (setting), property->param_spec->name, &object_value); - g_value_unset (&object_value); + if (!nm_g_object_set_property (G_OBJECT (setting), property->param_spec->name, &object_value, &local)) { + if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) + continue; + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("can not set property: %s"), + local->message); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name); + return NULL; + } } + } - if (value) - g_variant_unref (value); + if ( NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT) + && g_hash_table_size (keys) > 0) { + GHashTableIter iter; + const char *key; + + g_hash_table_iter_init (&iter, keys); + if (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("unknown property")); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), key); + return NULL; + } } - return setting; + return nm_unauto (&setting); } /** |