diff options
Diffstat (limited to 'libnm-core/nm-setting.c')
| -rw-r--r-- | libnm-core/nm-setting.c | 1199 |
1 files changed, 735 insertions, 464 deletions
diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index 047391ce..2e9081df 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -24,23 +24,12 @@ #include "nm-setting.h" -#include <string.h> - #include "nm-setting-private.h" #include "nm-utils.h" #include "nm-core-internal.h" #include "nm-utils-private.h" #include "nm-property-compare.h" -#include "nm-setting-connection.h" -#include "nm-setting-bond.h" -#include "nm-setting-bridge.h" -#include "nm-setting-bridge-port.h" -#include "nm-setting-pppoe.h" -#include "nm-setting-team.h" -#include "nm-setting-team-port.h" -#include "nm-setting-vpn.h" - /** * SECTION:nm-setting * @short_description: Describes related configuration information @@ -67,12 +56,9 @@ typedef struct { NMSettingPriority priority; } SettingInfo; -enum { - PROP_0, +NM_GOBJECT_PROPERTIES_DEFINE (NMSetting, PROP_NAME, - - PROP_LAST -}; +); typedef struct { GenData *gendata; @@ -354,6 +340,77 @@ _properties_override_add_transform (GArray *properties_override, static NMSettInfoSetting _sett_info_settings[_NM_META_SETTING_TYPE_NUM]; +static int +_property_infos_sort_cmp_setting_connection (gconstpointer p_a, + gconstpointer p_b, + gpointer user_data) +{ + const NMSettInfoProperty *a = *((const NMSettInfoProperty *const*) p_a); + const NMSettInfoProperty *b = *((const NMSettInfoProperty *const*) p_b); + int c_name; + + c_name = strcmp (a->name, b->name); + nm_assert (c_name != 0); + +#define CMP_AND_RETURN(n_a, n_b, name) \ + G_STMT_START { \ + gboolean _is = nm_streq (n_a, ""name); \ + \ + if ( _is \ + || nm_streq (n_b, ""name)) \ + return _is ? -1 : 1; \ + } G_STMT_END + + /* for [connection], report first id, uuid, type in that order. */ + if (c_name != 0) { + CMP_AND_RETURN (a->name, b->name, NM_SETTING_CONNECTION_ID); + CMP_AND_RETURN (a->name, b->name, NM_SETTING_CONNECTION_UUID); + CMP_AND_RETURN (a->name, b->name, NM_SETTING_CONNECTION_TYPE); + } + +#undef CMP_AND_RETURN + + return c_name; +} + +static const NMSettInfoProperty *const* +_property_infos_sort (const NMSettInfoProperty *property_infos, + guint property_infos_len, + NMSettingClass *setting_class) +{ + const NMSettInfoProperty **arr; + guint i; + +#if NM_MORE_ASSERTS > 5 + /* assert that the property names are all unique and sorted. */ + for (i = 0; i < property_infos_len; i++) { + if (property_infos[i].param_spec) + nm_assert (nm_streq (property_infos[i].name, property_infos[i].param_spec->name)); + if (i > 0) + nm_assert (strcmp (property_infos[i - 1].name, property_infos[i].name) < 0); + } +#endif + + if (property_infos_len <= 1) + return NULL; + if (G_TYPE_FROM_CLASS (setting_class) != NM_TYPE_SETTING_CONNECTION) { + /* we only do something special for certain setting types. This one, + * has just alphabetical sorting. */ + return NULL; + } + + arr = g_new (const NMSettInfoProperty *, property_infos_len); + for (i = 0; i < property_infos_len; i++) + arr[i] = &property_infos[i]; + + g_qsort_with_data (arr, + property_infos_len, + sizeof (const NMSettInfoProperty *), + _property_infos_sort_cmp_setting_connection, + NULL); + return arr; +} + void _nm_setting_class_commit_full (NMSettingClass *setting_class, NMMetaSettingType meta_type, @@ -387,19 +444,21 @@ _nm_setting_class_commit_full (NMSettingClass *setting_class, #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); + gboolean found = FALSE; + guint j; 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; - } + if (!nm_streq (property_specs[j]->name, p->name)) + continue; + nm_assert (!found); + found = TRUE; + nm_assert (p->param_spec == property_specs[j]); } - nm_assert ((j == n_property_specs) == (p->param_spec == NULL)); + nm_assert (found == (p->param_spec != NULL)); } #endif @@ -429,27 +488,21 @@ _nm_setting_class_commit_full (NMSettingClass *setting_class, 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) -{ - 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; + sett_info->property_infos_sorted = _property_infos_sort (sett_info->property_infos, + sett_info->property_infos_len, + setting_class); } const NMSettInfoProperty * -_nm_sett_info_property_get (NMSettingClass *setting_class, - const char *property_name) +_nm_sett_info_setting_get_property_info (const NMSettInfoSetting *sett_info, + const char *property_name) { - const NMSettInfoSetting *sett_info = _nm_sett_info_setting_get (setting_class); const NMSettInfoProperty *property; gssize idx; + nm_assert (property_name); + if (!sett_info) return NULL; @@ -472,6 +525,50 @@ _nm_sett_info_property_get (NMSettingClass *setting_class, return property; } +const NMSettInfoSetting * +_nm_setting_class_get_sett_info (NMSettingClass *setting_class) +{ + const NMSettInfoSetting *sett_info; + + if ( !NM_IS_SETTING_CLASS (setting_class) + || !setting_class->setting_info) + return NULL; + + nm_assert (setting_class->setting_info->meta_type < G_N_ELEMENTS (_sett_info_settings)); + sett_info = &_sett_info_settings[setting_class->setting_info->meta_type]; + nm_assert (sett_info->setting_class == setting_class); + return sett_info; +} + +/*****************************************************************************/ + +void +_nm_setting_emit_property_changed (NMSetting *setting) +{ + /* Some settings have "properties" that are not implemented as GObject properties. + * + * For example: + * + * - gendata-base settings like NMSettingEthtool. Here properties are just + * GVariant values in the gendata hash. + * + * - NMSettingWireGuard's peers are not backed by a GObject property. Instead + * there is C-API to access/modify peers. + * + * We still want to emit property-changed notifications for such properties, + * in particular because NMConnection registers to such signals to re-emit + * it as NM_CONNECTION_CHANGED signal. In fact, there are unlikely any other + * uses of such a property-changed signal, because generally it doesn't make + * too much sense. + * + * So, instead of adding yet another (artificial) signal "setting-changed", + * hijack the "notify" signal and just notify about changes of the "name". + * Of course, the "name" doesn't really ever change, because it's tied to + * the GObject's type. + */ + _notify (setting, PROP_NAME); +} + /*****************************************************************************/ gboolean @@ -654,7 +751,7 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionS g_hash_table_lookup (priv->gendata->hash, gendata_keys[i])); } - sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting)); + sett_info = _nm_setting_class_get_sett_info (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; @@ -662,10 +759,13 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionS if (!prop_spec) { if (!property->synth_func) continue; - - if (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS) - continue; } else { + + /* For the moment, properties backed by a GObject property don't + * define a synth function. There is no problem supporting that, + * however, for now just disallow it. */ + nm_assert (!property->synth_func); + if (!(prop_spec->flags & G_PARAM_WRITABLE)) continue; @@ -685,14 +785,10 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionS continue; } - if (property->synth_func) { - if (!(flags & NM_CONNECTION_SERIALIZE_NO_SYNTH)) - dbus_value = property->synth_func (setting, connection, property->name); - else - dbus_value = NULL; - } else { + if (property->synth_func) + dbus_value = property->synth_func (sett_info, i, connection, setting, flags); + else dbus_value = get_property_for_dbus (setting, property, TRUE); - } if (dbus_value) { /* Allow dbus_value to be either floating or not. */ @@ -780,7 +876,7 @@ _nm_setting_new_from_dbus (GType setting_type, } } - sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting)); + sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting)); if (sett_info->detail.gendata_info) { GHashTable *hash; @@ -802,89 +898,94 @@ _nm_setting_new_from_dbus (GType setting_type, } for (i = 0; i < sett_info->property_infos_len; i++) { - const NMSettInfoProperty *property = &sett_info->property_infos[i]; + const NMSettInfoProperty *property_info = &sett_info->property_infos[i]; gs_unref_variant GVariant *value = NULL; gs_free_error GError *local = NULL; - if (property->param_spec && !(property->param_spec->flags & G_PARAM_WRITABLE)) + if ( property_info->param_spec + && !(property_info->param_spec->flags & G_PARAM_WRITABLE)) continue; - value = g_variant_lookup_value (setting_dict, property->name, NULL); + value = g_variant_lookup_value (setting_dict, property_info->name, NULL); if (value && keys) - g_hash_table_remove (keys, property->name); + g_hash_table_remove (keys, property_info->name); - if (value && property->set_func) { + if ( value + && property_info->set_func) { - if (!g_variant_type_equal (g_variant_get_type (value), property->dbus_type)) { + if (!g_variant_type_equal (g_variant_get_type (value), property_info->dbus_type)) { /* 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)", + property_info->dbus_type ? + g_variant_type_peek_string (property_info->dbus_type) : + property_info->param_spec ? + g_type_name (property_info->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_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name); return NULL; } - if (!property->set_func (setting, - connection_dict, - property->name, - value, - parse_flags, - &local)) { + if (!property_info->set_func (setting, + connection_dict, + property_info->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); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name); return NULL; } - } else if (!value && property->not_set_func) { - if (!property->not_set_func (setting, - connection_dict, - property->name, - parse_flags, - &local)) { + } else if ( !value + && property_info->not_set_func) { + if (!property_info->not_set_func (setting, + connection_dict, + property_info->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); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name); return NULL; } - } else if (value && property->param_spec) { + } else if ( value + && property_info->param_spec) { 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)) { + g_value_init (&object_value, property_info->param_spec->value_type); + if (!set_property_from_dbus (property_info, 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)", + property_info->dbus_type + ? g_variant_type_peek_string (property_info->dbus_type) + : ( property_info->param_spec + ? g_type_name (property_info->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_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name); return NULL; } - if (!nm_g_object_set_property (G_OBJECT (setting), property->param_spec->name, &object_value, &local)) { + if (!nm_g_object_set_property (G_OBJECT (setting), property_info->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); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name); return NULL; } } @@ -926,7 +1027,7 @@ nm_setting_get_dbus_property_type (NMSetting *setting, g_return_val_if_fail (NM_IS_SETTING (setting), NULL); g_return_val_if_fail (property_name != NULL, NULL); - property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), property_name); + property = _nm_setting_class_get_property_info (NM_SETTING_GET_CLASS (setting), property_name); g_return_val_if_fail (property != NULL, NULL); if (property->dbus_type) @@ -939,13 +1040,13 @@ gboolean _nm_setting_get_property (NMSetting *setting, const char *property_name, GValue *value) { const NMSettInfoSetting *sett_info; - GParamSpec *prop_spec; + const NMSettInfoProperty *property_info; 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); - sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting)); + sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting)); if (sett_info->detail.gendata_info) { GVariant *variant; @@ -963,26 +1064,86 @@ _nm_setting_get_property (NMSetting *setting, const char *property_name, GValue return TRUE; } - prop_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), property_name); - if (!prop_spec) { + property_info = _nm_sett_info_setting_get_property_info (sett_info, property_name); + if ( !property_info + || !property_info->param_spec) { g_value_unset (value); return FALSE; } - g_value_init (value, prop_spec->value_type); + g_value_init (value, property_info->param_spec->value_type); g_object_get_property (G_OBJECT (setting), property_name, value); return TRUE; } static void -duplicate_setting (NMSetting *setting, - const char *name, - const GValue *value, - GParamFlags flags, - gpointer user_data) +_gobject_copy_property (GObject *src, + GObject *dst, + const char *property_name, + GType gtype) { - if ((flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) == G_PARAM_WRITABLE) - g_object_set_property (G_OBJECT (user_data), name, value); + nm_auto_unset_gvalue GValue value = G_VALUE_INIT; + + nm_assert (G_IS_OBJECT (src)); + nm_assert (G_IS_OBJECT (dst)); + + g_value_init (&value, gtype); + g_object_get_property (src, property_name, &value); + g_object_set_property (dst, property_name, &value); +} + +static void +duplicate_copy_properties (const NMSettInfoSetting *sett_info, + NMSetting *src, + NMSetting *dst) +{ + if (sett_info->detail.gendata_info) { + GenData *gendata = _gendata_hash (src, FALSE); + + nm_assert (!_gendata_hash (dst, FALSE)); + + if ( gendata + && g_hash_table_size (gendata->hash) > 0) { + GHashTableIter iter; + GHashTable *h = _gendata_hash (dst, 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)); + } + } + } + + if (sett_info->property_infos_len > 0) { + gboolean frozen = FALSE; + guint i; + + for (i = 0; i < sett_info->property_infos_len; i++) { + const NMSettInfoProperty *property_info = &sett_info->property_infos[i]; + + if (property_info->param_spec) { + if ((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) != G_PARAM_WRITABLE) + continue; + + if (!frozen) { + g_object_freeze_notify (G_OBJECT (dst)); + frozen = TRUE; + } + _gobject_copy_property (G_OBJECT (src), + G_OBJECT (dst), + property_info->param_spec->name, + G_PARAM_SPEC_VALUE_TYPE (property_info->param_spec)); + continue; + } + } + + if (frozen) + g_object_thaw_notify (G_OBJECT (dst)); + } } /** @@ -998,37 +1159,22 @@ NMSetting * nm_setting_duplicate (NMSetting *setting) { const NMSettInfoSetting *sett_info; - GObject *dup; + NMSettingClass *klass; + NMSetting *dst; g_return_val_if_fail (NM_IS_SETTING (setting), NULL); - dup = g_object_new (G_OBJECT_TYPE (setting), NULL); + klass = NM_SETTING_GET_CLASS (setting); + nm_assert (NM_IS_SETTING_CLASS (klass)); + nm_assert (klass->duplicate_copy_properties); - sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting)); + dst = g_object_new (G_TYPE_FROM_CLASS (klass), NULL); - if (sett_info->detail.gendata_info) { - GenData *gendata = _gendata_hash (setting, FALSE); + sett_info = _nm_setting_class_get_sett_info (klass); + nm_assert (sett_info); - 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); + klass->duplicate_copy_properties (sett_info, setting, dst); + return dst; } /** @@ -1136,58 +1282,148 @@ _nm_setting_verify_secret_string (const char *str, return TRUE; } -static gboolean -compare_property (NMSetting *setting, +gboolean +_nm_setting_should_compare_secret_property (NMSetting *setting, + NMSetting *other, + const char *secret_name, + NMSettingCompareFlags flags) +{ + NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE; + NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE; + + nm_assert (NM_IS_SETTING (setting)); + nm_assert (!other || G_OBJECT_TYPE (setting) == G_OBJECT_TYPE (other)); + + /* secret_name must be a valid secret for @setting. */ + nm_assert (nm_setting_get_secret_flags (setting, secret_name, NULL, NULL)); + + if (!NM_FLAGS_ANY (flags, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS + | NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) + return TRUE; + + nm_setting_get_secret_flags (setting, secret_name, &a_secret_flags, NULL); + if (other) { + if (!nm_setting_get_secret_flags (other, secret_name, &b_secret_flags, NULL)) { + /* secret-name may not be a valid secret for @other. That is fine, we ignore that + * and treat @b_secret_flags as NM_SETTING_SECRET_FLAG_NONE. + * + * This can happen with VPN secrets, where the caller knows that @secret_name + * is a secret for setting, but it may not be a secret for @other. Accept that. + * + * Mark @other as missing. */ + other = NULL; + } + } + + /* when @setting has the secret-flags that should be ignored, + * we skip the comparisong if: + * + * - @other is not present, + * - @other does not have a secret named @secret_name + * - @other also has the secret flat to be ignored. + * + * This makes the check symmetric (aside the fact that @setting must + * have the secret while @other may not -- which is asymmetric). */ + if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS) + && NM_FLAGS_HAS (a_secret_flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED) + && ( !other + || NM_FLAGS_HAS (b_secret_flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED))) + return FALSE; + + if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS) + && NM_FLAGS_HAS (a_secret_flags, NM_SETTING_SECRET_FLAG_NOT_SAVED) + && ( !other + || NM_FLAGS_HAS (b_secret_flags, NM_SETTING_SECRET_FLAG_NOT_SAVED))) + return FALSE; + + return TRUE; +} + +static NMTernary +compare_property (const NMSettInfoSetting *sett_info, + guint property_idx, + NMSetting *setting, NMSetting *other, - const GParamSpec *prop_spec, NMSettingCompareFlags flags) { - const NMSettInfoProperty *property; - GVariant *value1, *value2; - int cmp; + const NMSettInfoProperty *property_info = &sett_info->property_infos[property_idx]; + const GParamSpec *param_spec = property_info->param_spec; - /* Handle compare flags */ - if (prop_spec->flags & NM_SETTING_PARAM_SECRET) { - NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE; - NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE; + if (!param_spec) + return NM_TERNARY_DEFAULT; - g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE); + if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_FUZZY) + && NM_FLAGS_ANY (param_spec->flags, NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET)) + return NM_TERNARY_DEFAULT; - if (!nm_setting_get_secret_flags (setting, prop_spec->name, &a_secret_flags, NULL)) - g_return_val_if_reached (FALSE); - if (!nm_setting_get_secret_flags (other, prop_spec->name, &b_secret_flags, NULL)) - g_return_val_if_reached (FALSE); + if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE) + && !NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_INFERRABLE)) + return NM_TERNARY_DEFAULT; - /* If the secret flags aren't the same the settings aren't the same */ - if (a_secret_flags != b_secret_flags) - return FALSE; + if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY) + && NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_REAPPLY_IMMEDIATELY)) + return NM_TERNARY_DEFAULT; - /* Check for various secret flags that might cause us to ignore comparing - * this property. - */ - if ( (flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS) - && (a_secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED)) - return TRUE; + if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS) + && NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_SECRET)) + return NM_TERNARY_DEFAULT; - if ( (flags & NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS) - && (a_secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED)) - return TRUE; - } + if (nm_streq (param_spec->name, NM_SETTING_NAME)) + return NM_TERNARY_DEFAULT; + + if ( NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_SECRET) + && !_nm_setting_should_compare_secret_property (setting, + other, + param_spec->name, + flags)) + return NM_TERNARY_DEFAULT; - property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), prop_spec->name); - g_return_val_if_fail (property != NULL, FALSE); + if (other) { + gs_unref_variant GVariant *value1 = NULL; + gs_unref_variant GVariant *value2 = NULL; - value1 = get_property_for_dbus (setting, property, TRUE); - value2 = get_property_for_dbus (other, property, TRUE); + value1 = get_property_for_dbus (setting, property_info, TRUE); + value2 = get_property_for_dbus (other, property_info, TRUE); - cmp = nm_property_compare (value1, value2); + if (nm_property_compare (value1, value2) != 0) + return NM_TERNARY_FALSE; + } - if (value1) - g_variant_unref (value1); - if (value2) - g_variant_unref (value2); + return NM_TERNARY_TRUE; +} - return cmp == 0; +static NMTernary +_compare_property (const NMSettInfoSetting *sett_info, + guint property_idx, + NMSetting *setting, + NMSetting *other, + NMSettingCompareFlags flags) +{ + NMTernary compare_result; + + nm_assert (sett_info); + nm_assert (NM_IS_SETTING_CLASS (sett_info->setting_class)); + nm_assert (property_idx < sett_info->property_infos_len); + nm_assert (NM_SETTING_GET_CLASS (setting) == sett_info->setting_class); + nm_assert (!other || NM_SETTING_GET_CLASS (other) == sett_info->setting_class); + + compare_result = NM_SETTING_GET_CLASS (setting)->compare_property (sett_info, + property_idx, + setting, + other, + flags); + + nm_assert (NM_IN_SET (compare_result, NM_TERNARY_DEFAULT, + NM_TERNARY_FALSE, + NM_TERNARY_TRUE)); + + /* check that the inferable flag and the GObject property flag corresponds. */ + nm_assert ( !NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE) + || !sett_info->property_infos[property_idx].param_spec + || NM_FLAGS_HAS (sett_info->property_infos[property_idx].param_spec->flags, NM_SETTING_PARAM_INFERRABLE) + || compare_result == NM_TERNARY_DEFAULT); + + return compare_result; } /** @@ -1208,9 +1444,6 @@ nm_setting_compare (NMSetting *a, NMSettingCompareFlags flags) { const NMSettInfoSetting *sett_info; - GParamSpec **property_specs; - guint n_property_specs; - int same = TRUE; guint i; g_return_val_if_fail (NM_IS_SETTING (a), FALSE); @@ -1220,7 +1453,7 @@ 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)); + sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (a)); if (sett_info->detail.gendata_info) { GenData *a_gendata = _gendata_hash (a, FALSE); @@ -1232,88 +1465,11 @@ nm_setting_compare (NMSetting *a, 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++) { - GParamSpec *prop_spec = property_specs[i]; - - /* Fuzzy compare ignores secrets and properties defined with the FUZZY_IGNORE flag */ - if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_FUZZY) - && !NM_FLAGS_ANY (prop_spec->flags, NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET)) - continue; - - if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE) - && !NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_INFERRABLE)) - continue; - - if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY) - && NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_REAPPLY_IMMEDIATELY)) - continue; - - if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS) - && NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_SECRET)) - continue; - - same = NM_SETTING_GET_CLASS (a)->compare_property (a, b, prop_spec, flags); - } - g_free (property_specs); - - return same; -} - -static inline gboolean -should_compare_prop (NMSetting *setting, - const char *prop_name, - NMSettingCompareFlags comp_flags, - GParamFlags prop_flags) -{ - /* Fuzzy compare ignores secrets and properties defined with the FUZZY_IGNORE flag */ - if ( (comp_flags & NM_SETTING_COMPARE_FLAG_FUZZY) - && (prop_flags & (NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET))) - return FALSE; - - if ((comp_flags & NM_SETTING_COMPARE_FLAG_INFERRABLE) && !(prop_flags & NM_SETTING_PARAM_INFERRABLE)) - return FALSE; - - if ((comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY) && !(prop_flags & NM_SETTING_PARAM_REAPPLY_IMMEDIATELY)) - return FALSE; - - if (prop_flags & NM_SETTING_PARAM_SECRET) { - NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; - - if (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS) - return FALSE; - - if ( NM_IS_SETTING_VPN (setting) - && g_strcmp0 (prop_name, NM_SETTING_VPN_SECRETS) == 0) { - /* FIXME: NMSettingVPN:NM_SETTING_VPN_SECRETS has NM_SETTING_PARAM_SECRET. - * nm_setting_get_secret_flags() quite possibly fails, but it might succeed if the - * setting accidently uses a key "secrets". */ - return TRUE; - } - - if (!nm_setting_get_secret_flags (setting, prop_name, &secret_flags, NULL)) - g_return_val_if_reached (FALSE); - - if ( (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS) - && (secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED)) - return FALSE; - - if ( (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS) - && (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED)) + for (i = 0; i < sett_info->property_infos_len; i++) { + if (_compare_property (sett_info, i, a, b, flags) == NM_TERNARY_FALSE) return FALSE; } - if ( (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_ID) - && NM_IS_SETTING_CONNECTION (setting) - && !strcmp (prop_name, NM_SETTING_CONNECTION_ID)) - return FALSE; - - if ( (comp_flags & NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP) - && NM_IS_SETTING_CONNECTION (setting) - && !strcmp (prop_name, NM_SETTING_CONNECTION_TIMESTAMP)) - return FALSE; - return TRUE; } @@ -1404,7 +1560,7 @@ nm_setting_diff (NMSetting *a, results_created = TRUE; } - sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (a)); + sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (a)); if (sett_info->detail.gendata_info) { const char *key; @@ -1447,71 +1603,93 @@ nm_setting_diff (NMSetting *a, } } } 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]; + for (i = 0; i < sett_info->property_infos_len; i++) { NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN; + const NMSettInfoProperty *property_info; + NMTernary compare_result; + GParamSpec *prop_spec; - /* 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) + compare_result = _compare_property (sett_info, i, a, b, flags); + if (compare_result == NM_TERNARY_DEFAULT) 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; + if ( NM_FLAGS_ANY (flags, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS + | NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS) + && b + && compare_result == NM_TERNARY_FALSE) { + /* we have setting @b and the property is not the same. But we also are instructed + * to ignore secrets based on the flags. + * + * Note that compare_property() called with two settings will ignore secrets + * based on the flags, but it will do so if *both* settings have the flag we + * look for. So that is symmetric behavior and good. + * + * But for the purpose of diff(), we do a asymmetric comparison because and + * we want to skip testing the property if setting @a alone indicates to do + * so. + * + * We need to double-check whether the property should be ignored by + * looking at @a alone. */ + if (_compare_property (sett_info, i, a, NULL, flags) == NM_TERNARY_DEFAULT) + continue; + } - 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); + compared_any = TRUE; - 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); + property_info = &sett_info->property_infos[i]; + prop_spec = property_info->param_spec; - 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 { + if (b) { + if (compare_result == NM_TERNARY_FALSE) { + if (prop_spec) { + 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 (!NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT)) { + 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 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; + if (prop_spec) { + 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_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); + g_value_unset (&value); + } else + r |= a_result; } if (r != NM_SETTING_DIFF_RESULT_UNKNOWN) { diff_found = TRUE; - _setting_diff_add_result (*results, prop_spec->name, r); + _setting_diff_add_result (*results, property_info->name, r); } } } @@ -1540,32 +1718,26 @@ nm_setting_diff (NMSetting *a, } } -#define CMP_AND_RETURN(n_a, n_b, name) \ - G_STMT_START { \ - gboolean _is = (strcmp (n_a, ""name) == 0); \ - \ - if (_is || (strcmp (n_b, ""name) == 0)) \ - return _is ? -1 : 1; \ - } G_STMT_END +static void +enumerate_values (const NMSettInfoProperty *property_info, + NMSetting *setting, + NMSettingValueIterFn func, + gpointer user_data) +{ + GValue value = G_VALUE_INIT; -static int -_enumerate_values_sort (GParamSpec **p_a, GParamSpec **p_b, GType *p_type) -{ - const char *n_a = (*p_a)->name; - const char *n_b = (*p_b)->name; - int c = strcmp (n_a, n_b); - - if (c) { - if (*p_type == NM_TYPE_SETTING_CONNECTION) { - /* for [connection], report first id, uuid, type in that order. */ - CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_ID); - CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_UUID); - CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_TYPE); - } - } - return c; + if (!property_info->param_spec) + return; + + g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (property_info->param_spec)); + g_object_get_property (G_OBJECT (setting), property_info->param_spec->name, &value); + func (setting, + property_info->param_spec->name, + &value, + property_info->param_spec->flags, + user_data); + g_value_unset (&value); } -#undef CMP_AND_RETURN /** * nm_setting_enumerate_values: @@ -1582,18 +1754,16 @@ nm_setting_enumerate_values (NMSetting *setting, gpointer user_data) { const NMSettInfoSetting *sett_info; - GParamSpec **property_specs; - guint n_properties; guint i; - GType type; g_return_if_fail (NM_IS_SETTING (setting)); g_return_if_fail (func != NULL); - sett_info = _nm_sett_info_setting_get (NM_SETTING_GET_CLASS (setting)); + sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting)); if (sett_info->detail.gendata_info) { const char *const*names; + guint n_properties; /* the properties of this setting are not real GObject properties. * Hence, this API makes little sense (or does it?). Still, call @@ -1623,100 +1793,138 @@ nm_setting_enumerate_values (NMSetting *setting, 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_properties, sizeof (gpointer), - (GCompareDataFunc) _enumerate_values_sort, &type); - - for (i = 0; i < n_properties; i++) { - GParamSpec *prop_spec = property_specs[i]; - GValue value = G_VALUE_INIT; - - g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop_spec)); - g_object_get_property (G_OBJECT (setting), prop_spec->name, &value); - func (setting, prop_spec->name, &value, prop_spec->flags, user_data); - g_value_unset (&value); + for (i = 0; i < sett_info->property_infos_len; i++) { + NM_SETTING_GET_CLASS (setting)->enumerate_values (_nm_sett_info_property_info_get_sorted (sett_info, i), + setting, + func, + user_data); } - - g_free (property_specs); } -/** - * _nm_setting_clear_secrets: - * @setting: the #NMSetting - * - * Resets and clears any secrets in the setting. Secrets should be added to the - * setting only when needed, and cleared immediately after use to prevent - * leakage of information. - * - * Returns: %TRUE if the setting changed at all - **/ -gboolean -_nm_setting_clear_secrets (NMSetting *setting) +static gboolean +aggregate (NMSetting *setting, + int type_i, + gpointer arg) { - gs_free GParamSpec **property_specs = NULL; - guint n_property_specs; + NMConnectionAggregateType type = type_i; + const NMSettInfoSetting *sett_info; guint i; - gboolean changed = FALSE; - g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); + nm_assert (NM_IN_SET (type, NM_CONNECTION_AGGREGATE_ANY_SECRETS, + NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS)); - 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]; + sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting)); + for (i = 0; i < sett_info->property_infos_len; i++) { + const NMSettInfoProperty *property_info = &sett_info->property_infos[i]; + GParamSpec *prop_spec = property_info->param_spec; + nm_auto_unset_gvalue GValue value = G_VALUE_INIT; + NMSettingSecretFlags secret_flags; + + if ( !prop_spec + || !NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_SECRET)) { + nm_assert (!nm_setting_get_secret_flags (setting, property_info->name, NULL, NULL)); + continue; + } - if (prop_spec->flags & NM_SETTING_PARAM_SECRET) { - GValue value = G_VALUE_INIT; + /* for the moment, all aggregate types only care about secrets. */ + nm_assert (nm_setting_get_secret_flags (setting, property_info->name, NULL, NULL)); - g_value_init (&value, prop_spec->value_type); + switch (type) { + + case NM_CONNECTION_AGGREGATE_ANY_SECRETS: + g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop_spec)); g_object_get_property (G_OBJECT (setting), prop_spec->name, &value); if (!g_param_value_defaults (prop_spec, &value)) { - g_param_value_set_default (prop_spec, &value); - g_object_set_property (G_OBJECT (setting), prop_spec->name, &value); - changed = TRUE; + *((gboolean *) arg) = TRUE; + return TRUE; + } + break; + + case NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS: + if (!nm_setting_get_secret_flags (setting, prop_spec->name, &secret_flags, NULL)) + nm_assert_not_reached (); + if (secret_flags == NM_SETTING_SECRET_FLAG_NONE) { + *((gboolean *) arg) = TRUE; + return TRUE; } - g_value_unset (&value); + break; + } } - return changed; + + return FALSE; +} + +/** + * _nm_setting_aggregate: + * @setting: the #NMSetting to aggregate. + * @type: the #NMConnectionAggregateType aggregate type. + * @arg: the in/out arguments for aggregation. They depend on @type. + * + * This is the implementation detail of _nm_connection_aggregate(). It + * makes no sense to call this function directly outside of _nm_connection_aggregate(). + * + * Returns: %TRUE if afterwards the aggregation is complete. That means, + * the only caller _nm_connection_aggregate() will not visit other settings + * after a setting returns %TRUE (indicating that there is nothing further + * to aggregate). Note that is very different from the boolean return + * argument of _nm_connection_aggregate(), which serves a different purpose. + */ +gboolean +_nm_setting_aggregate (NMSetting *setting, + NMConnectionAggregateType type, + gpointer arg) +{ + g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); + g_return_val_if_fail (arg, FALSE); + g_return_val_if_fail (NM_IN_SET (type, NM_CONNECTION_AGGREGATE_ANY_SECRETS, + NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS), + FALSE); + + return NM_SETTING_GET_CLASS (setting)->aggregate (setting, type, arg); } static gboolean -clear_secrets_with_flags (NMSetting *setting, - GParamSpec *pspec, - NMSettingClearSecretsWithFlagsFn func, - gpointer user_data) +clear_secrets (const NMSettInfoSetting *sett_info, + guint property_idx, + NMSetting *setting, + NMSettingClearSecretsWithFlagsFn func, + gpointer user_data) { NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; - gboolean changed = FALSE; + GParamSpec *param_spec = sett_info->property_infos[property_idx].param_spec; - g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE); + if (!param_spec) + return FALSE; - /* Clear the secret if the user function says to do so */ - if (!nm_setting_get_secret_flags (setting, pspec->name, &flags, NULL)) - g_return_val_if_reached (FALSE); + if (!NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_SECRET)) + return FALSE; + + if (func) { + if (!nm_setting_get_secret_flags (setting, param_spec->name, &flags, NULL)) + nm_assert_not_reached (); + if (!func (setting, param_spec->name, flags, user_data)) + return FALSE; + } else + nm_assert (nm_setting_get_secret_flags (setting, param_spec->name, NULL, NULL)); - if (func (setting, pspec->name, flags, user_data) == TRUE) { - GValue value = G_VALUE_INIT; + { + nm_auto_unset_gvalue GValue value = G_VALUE_INIT; - g_value_init (&value, pspec->value_type); - g_object_get_property (G_OBJECT (setting), pspec->name, &value); - if (!g_param_value_defaults (pspec, &value)) { - g_param_value_set_default (pspec, &value); - g_object_set_property (G_OBJECT (setting), pspec->name, &value); - changed = TRUE; - } - g_value_unset (&value); + g_value_init (&value, param_spec->value_type); + g_object_get_property (G_OBJECT (setting), param_spec->name, &value); + if (g_param_value_defaults (param_spec, &value)) + return FALSE; + + g_param_value_set_default (param_spec, &value); + g_object_set_property (G_OBJECT (setting), param_spec->name, &value); } - return changed; + return TRUE; } /** - * _nm_setting_clear_secrets_with_flags: + * _nm_setting_clear_secrets: * @setting: the #NMSetting * @func: (scope call): function to be called to determine whether a * specific secret should be cleared or not @@ -1727,27 +1935,30 @@ clear_secrets_with_flags (NMSetting *setting, * Returns: %TRUE if the setting changed at all **/ gboolean -_nm_setting_clear_secrets_with_flags (NMSetting *setting, - NMSettingClearSecretsWithFlagsFn func, - gpointer user_data) +_nm_setting_clear_secrets (NMSetting *setting, + NMSettingClearSecretsWithFlagsFn func, + gpointer user_data) { - gs_free GParamSpec **property_specs = NULL; - guint n_property_specs; - guint i; + const NMSettInfoSetting *sett_info; gboolean changed = FALSE; + guint i; + gboolean (*my_clear_secrets) (const struct _NMSettInfoSetting *sett_info, + guint property_idx, + NMSetting *setting, + NMSettingClearSecretsWithFlagsFn func, + gpointer user_data); - g_return_val_if_fail (setting, FALSE); g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); - g_return_val_if_fail (func != NULL, FALSE); - property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs); - for (i = 0; i < n_property_specs; i++) { - if (property_specs[i]->flags & NM_SETTING_PARAM_SECRET) { - changed |= NM_SETTING_GET_CLASS (setting)->clear_secrets_with_flags (setting, - property_specs[i], - func, - user_data); - } + my_clear_secrets = NM_SETTING_GET_CLASS (setting)->clear_secrets; + + sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting)); + for (i = 0; i < sett_info->property_infos_len; i++) { + changed |= my_clear_secrets (sett_info, + i, + setting, + func, + user_data); } return changed; } @@ -1786,7 +1997,7 @@ update_one_secret (NMSetting *setting, const char *key, GVariant *value, GError GParamSpec *prop_spec; GValue prop_value = { 0, }; - property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), key); + property = _nm_setting_class_get_property_info (NM_SETTING_GET_CLASS (setting), key); if (!property) { g_set_error_literal (error, NM_CONNECTION_ERROR, @@ -1856,7 +2067,7 @@ _nm_setting_update_secrets (NMSetting *setting, GVariant *secrets, GError **erro int success; success = NM_SETTING_GET_CLASS (setting)->update_one_secret (setting, secret_key, secret_value, &tmp_error); - g_assert (!((success == NM_SETTING_UPDATE_SECRET_ERROR) ^ (!!tmp_error))); + nm_assert (!((success == NM_SETTING_UPDATE_SECRET_ERROR) ^ (!!tmp_error))); g_variant_unref (secret_value); @@ -1872,52 +2083,92 @@ _nm_setting_update_secrets (NMSetting *setting, GVariant *secrets, GError **erro return result; } -static gboolean -is_secret_prop (NMSetting *setting, const char *secret_name, GError **error) +static void +for_each_secret (NMSetting *setting, + const char *secret_name, + GVariant *val, + gboolean remove_non_secrets, + _NMConnectionForEachSecretFunc callback, + gpointer callback_data, + GVariantBuilder *setting_builder) { - const NMSettInfoProperty *property; - GParamSpec *pspec; + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; - property = _nm_sett_info_property_get (NM_SETTING_GET_CLASS (setting), secret_name); - if (!property) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_PROPERTY_NOT_FOUND, - _("secret is not set")); - g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), secret_name); - return FALSE; + if (!nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL)) { + if (!remove_non_secrets) + g_variant_builder_add (setting_builder, "{sv}", secret_name, val); + return; } + if (callback (secret_flags, callback_data)) + g_variant_builder_add (setting_builder, "{sv}", secret_name, val); +} - pspec = property->param_spec; - if (!pspec || !(pspec->flags & NM_SETTING_PARAM_SECRET)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_PROPERTY_NOT_SECRET, - _("not a secret property")); - g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), secret_name); - return FALSE; - } +static void +_set_error_secret_property_not_found (GError **error, + NMSetting *setting, + const char *secret_name) +{ + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_PROPERTY_NOT_FOUND, + _("not a secret property")); + g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), secret_name); +} - return TRUE; +gboolean +_nm_setting_property_is_regular_secret (NMSetting *setting, + const char *secret_name) +{ + const NMSettInfoProperty *property; + + nm_assert (NM_IS_SETTING (setting)); + nm_assert (secret_name); + + property = _nm_setting_class_get_property_info (NM_SETTING_GET_CLASS (setting), secret_name); + return property + && property->param_spec + && NM_FLAGS_HAS (property->param_spec->flags, NM_SETTING_PARAM_SECRET); +} + +gboolean +_nm_setting_property_is_regular_secret_flags (NMSetting *setting, + const char *secret_flags_name) +{ + const NMSettInfoProperty *property; + + nm_assert (NM_IS_SETTING (setting)); + nm_assert (secret_flags_name); + + property = _nm_setting_class_get_property_info (NM_SETTING_GET_CLASS (setting), secret_flags_name); + return property + && property->param_spec + && !NM_FLAGS_HAS (property->param_spec->flags, NM_SETTING_PARAM_SECRET) + && G_PARAM_SPEC_VALUE_TYPE (property->param_spec) == NM_TYPE_SETTING_SECRET_FLAGS; } static gboolean get_secret_flags (NMSetting *setting, const char *secret_name, - gboolean verify_secret, NMSettingSecretFlags *out_flags, GError **error) { - gs_free char *name_to_free = NULL; - NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; + gs_free char *secret_flags_name_free = NULL; + const char *secret_flags_name; + NMSettingSecretFlags flags; - if (verify_secret && !is_secret_prop (setting, secret_name, error)) { + if (!_nm_setting_property_is_regular_secret (setting, + secret_name)) { + _set_error_secret_property_not_found (error, setting, secret_name); NM_SET_OUT (out_flags, NM_SETTING_SECRET_FLAG_NONE); return FALSE; } + secret_flags_name = nm_construct_name_a ("%s-flags", secret_name, &secret_flags_name_free); + + nm_assert (_nm_setting_property_is_regular_secret_flags (setting, secret_flags_name)); + g_object_get (G_OBJECT (setting), - nm_construct_name_a ("%s-flags", secret_name, &name_to_free), + secret_flags_name, &flags, NULL); NM_SET_OUT (out_flags, flags); @@ -1946,25 +2197,34 @@ nm_setting_get_secret_flags (NMSetting *setting, g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); g_return_val_if_fail (secret_name != NULL, FALSE); - return NM_SETTING_GET_CLASS (setting)->get_secret_flags (setting, secret_name, TRUE, out_flags, error); + return NM_SETTING_GET_CLASS (setting)->get_secret_flags (setting, secret_name, out_flags, error); } static gboolean set_secret_flags (NMSetting *setting, const char *secret_name, - gboolean verify_secret, NMSettingSecretFlags flags, GError **error) { - gs_free char *name_to_free = NULL; + gs_free char *secret_flags_name_free = NULL; + const char *secret_flags_name; - if (verify_secret) - g_return_val_if_fail (is_secret_prop (setting, secret_name, error), FALSE); + if (!_nm_setting_property_is_regular_secret (setting, + secret_name)) { + _set_error_secret_property_not_found (error, setting, secret_name); + return FALSE; + } - g_object_set (G_OBJECT (setting), - nm_construct_name_a ("%s-flags", secret_name, &name_to_free), - flags, - NULL); + secret_flags_name = nm_construct_name_a ("%s-flags", secret_name, &secret_flags_name_free); + + nm_assert (_nm_setting_property_is_regular_secret_flags (setting, secret_flags_name)); + + if (!nm_g_object_set_property_flags (G_OBJECT (setting), + secret_flags_name, + NM_TYPE_SETTING_SECRET_FLAGS, + flags, + error)) + g_return_val_if_reached (FALSE); return TRUE; } @@ -1989,9 +2249,9 @@ nm_setting_set_secret_flags (NMSetting *setting, { g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); g_return_val_if_fail (secret_name != NULL, FALSE); - g_return_val_if_fail (flags <= NM_SETTING_SECRET_FLAGS_ALL, FALSE); + g_return_val_if_fail (_nm_setting_secret_flags_valid (flags), FALSE); - return NM_SETTING_GET_CLASS (setting)->set_secret_flags (setting, secret_name, TRUE, flags, error); + return NM_SETTING_GET_CLASS (setting)->set_secret_flags (setting, secret_name, flags, error); } /** @@ -2018,8 +2278,7 @@ nm_setting_to_string (NMSetting *setting) string = g_string_new (nm_setting_get_name (setting)); g_string_append_c (string, '\n'); - variant = _nm_setting_to_dbus (setting, NULL, NM_CONNECTION_SERIALIZE_ALL - | NM_CONNECTION_SERIALIZE_NO_SYNTH); + variant = _nm_setting_to_dbus (setting, NULL, NM_CONNECTION_SERIALIZE_ALL); g_variant_iter_init (&iter, variant); while ((child = g_variant_iter_next_value (&iter))) { @@ -2037,9 +2296,11 @@ nm_setting_to_string (NMSetting *setting) } GVariant * -_nm_setting_get_deprecated_virtual_interface_name (NMSetting *setting, +_nm_setting_get_deprecated_virtual_interface_name (const NMSettInfoSetting *sett_info, + guint property_idx, NMConnection *connection, - const char *property) + NMSetting *setting, + NMConnectionSerializationFlags flags) { NMSettingConnection *s_con; @@ -2096,7 +2357,7 @@ _nm_setting_gendata_notify (NMSetting *setting, gendata = _gendata_hash (setting, FALSE); if (!gendata) - return; + goto out; nm_clear_g_free (&gendata->values); @@ -2106,7 +2367,7 @@ _nm_setting_gendata_notify (NMSetting *setting, nm_clear_g_free (&gendata->names); } - /* Note, that currently there is now way to notify the subclass when gendata changed. + /* Note, currently there is no 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. @@ -2119,6 +2380,9 @@ _nm_setting_gendata_notify (NMSetting *setting, * * If we ever need it, then we would need to call a virtual function to notify the subclass * that gendata changed. */ + +out: + _nm_setting_emit_property_changed (setting); } GVariant * @@ -2185,7 +2449,7 @@ out_zero: /** * nm_setting_gendata_get_all_names: * @setting: the #NMSetting - * @out_len: (allow-none): (out): + * @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 @@ -2241,7 +2505,7 @@ nm_setting_gendata_get_all_values (NMSetting *setting) void _nm_setting_gendata_to_gvalue (NMSetting *setting, - GValue *value) + GValue *value) { GenData *gendata; GHashTable *new; @@ -2293,7 +2557,7 @@ _nm_setting_gendata_reset_from_hash (NMSetting *setting, } /* let's not bother to find out whether the new hash has any different - * content the the current gendata. Just replace it. */ + * content the current gendata. Just replace it. */ g_hash_table_remove_all (gendata->hash); if (num > 0) { g_hash_table_iter_init (&iter, new); @@ -2307,11 +2571,6 @@ _nm_setting_gendata_reset_from_hash (NMSetting *setting, /*****************************************************************************/ static void -nm_setting_init (NMSetting *setting) -{ -} - -static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { @@ -2327,6 +2586,13 @@ get_property (GObject *object, guint prop_id, } } +/*****************************************************************************/ + +static void +nm_setting_init (NMSetting *setting) +{ +} + static void finalize (GObject *object) { @@ -2367,11 +2633,15 @@ nm_setting_class_init (NMSettingClass *setting_class) 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; - setting_class->set_secret_flags = set_secret_flags; - setting_class->compare_property = compare_property; - setting_class->clear_secrets_with_flags = clear_secrets_with_flags; + setting_class->update_one_secret = update_one_secret; + setting_class->get_secret_flags = get_secret_flags; + setting_class->set_secret_flags = set_secret_flags; + setting_class->compare_property = compare_property; + setting_class->clear_secrets = clear_secrets; + setting_class->for_each_secret = for_each_secret; + setting_class->duplicate_copy_properties = duplicate_copy_properties; + setting_class->enumerate_values = enumerate_values; + setting_class->aggregate = aggregate; /** * NMSetting:name: @@ -2380,10 +2650,11 @@ nm_setting_class_init (NMSettingClass *setting_class) * connection. Each setting type has a name unique to that type, for * example "ppp" or "802-11-wireless" or "802-3-ethernet". **/ - g_object_class_install_property - (object_class, PROP_NAME, - g_param_spec_string (NM_SETTING_NAME, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + obj_properties[PROP_NAME] = + g_param_spec_string (NM_SETTING_NAME, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); } |