libnm-core: allow strict and relaxed error behavior for _nm_setting_new_from_dbus()
[NetworkManager.git] / libnm-core / nm-connection.c
index 04e601c..f0b2387 100644 (file)
@@ -233,9 +233,10 @@ validate_permissions_type (GVariant *variant, GError **error)
 }
 
 /**
- * nm_connection_replace_settings:
+ * _nm_connection_replace_settings:
  * @connection: a #NMConnection
  * @new_settings: a #GVariant of type %NM_VARIANT_TYPE_CONNECTION, with the new settings
+ * @parse_flags: flags.
  * @error: location to store error, or %NULL
  *
  * Replaces @connection's settings with @new_settings (which must be
@@ -246,9 +247,10 @@ validate_permissions_type (GVariant *variant, GError **error)
  *   be deserialized (in which case @connection will be unchanged).
  **/
 gboolean
-nm_connection_replace_settings (NMConnection *connection,
-                                GVariant *new_settings,
-                                GError **error)
+_nm_connection_replace_settings (NMConnection *connection,
+                                 GVariant *new_settings,
+                                 NMSettingParseFlags parse_flags,
+                                 GError **error)
 {
        NMConnectionPrivate *priv;
        GVariantIter iter;
@@ -261,32 +263,61 @@ nm_connection_replace_settings (NMConnection *connection,
        g_return_val_if_fail (g_variant_is_of_type (new_settings, NM_VARIANT_TYPE_CONNECTION), FALSE);
        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
+       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));
+
        priv = NM_CONNECTION_GET_PRIVATE (connection);
 
-       if (!validate_permissions_type (new_settings, error))
+       if (   !NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT)
+           && !validate_permissions_type (new_settings, error))
                return FALSE;
 
        g_variant_iter_init (&iter, new_settings);
        while (g_variant_iter_next (&iter, "{&s@a{sv}}", &setting_name, &setting_dict)) {
+               gs_unref_variant GVariant *setting_dict_free = NULL;
+               GError *local = NULL;
                NMSetting *setting;
                GType type;
 
+               setting_dict_free = setting_dict;
+
                type = nm_setting_lookup_type (setting_name);
                if (type == G_TYPE_INVALID) {
+                       if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
+                               continue;
                        g_set_error_literal (error,
                                             NM_CONNECTION_ERROR,
                                             NM_CONNECTION_ERROR_INVALID_SETTING,
                                             _("unknown setting name"));
                        g_prefix_error (error, "%s: ", setting_name);
-                       g_variant_unref (setting_dict);
                        g_slist_free_full (settings, g_object_unref);
                        return FALSE;
                }
 
-               setting = _nm_setting_new_from_dbus (type, setting_dict, new_settings, error);
-               g_variant_unref (setting_dict);
+               for (s = settings; s; s = s->next) {
+                       if (G_OBJECT_TYPE (s->data) == type) {
+                               if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) {
+                                       g_set_error_literal (error,
+                                                            NM_CONNECTION_ERROR,
+                                                            NM_CONNECTION_ERROR_INVALID_SETTING,
+                                                            _("duplicate setting name"));
+                                       g_prefix_error (error, "%s: ", setting_name);
+                                       g_slist_free_full (settings, g_object_unref);
+                                       return FALSE;
+                               }
+                               /* last wins. */
+                               g_object_unref (s->data);
+                               settings = g_slist_delete_link (settings, s);
+                               break;
+                       }
+               }
+
+               setting = _nm_setting_new_from_dbus (type, setting_dict, new_settings, parse_flags, &local);
 
                if (!setting) {
+                       if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
+                               continue;
+                       g_propagate_error (error, local);
                        g_slist_free_full (settings, g_object_unref);
                        return FALSE;
                }
@@ -300,6 +331,9 @@ nm_connection_replace_settings (NMConnection *connection,
        } else
                changed = (settings != NULL);
 
+       /* Note: @settings might be empty in which case the connection
+        * has no NMSetting instances... which is fine, just something
+        * to be aware of. */
        for (s = settings; s; s = s->next)
                _nm_connection_add_setting (connection, s->data);
 
@@ -310,6 +344,27 @@ nm_connection_replace_settings (NMConnection *connection,
        return TRUE;
 }
 
+/**
+ * nm_connection_replace_settings:
+ * @connection: a #NMConnection
+ * @new_settings: a #GVariant of type %NM_VARIANT_TYPE_CONNECTION, with the new settings
+ * @error: location to store error, or %NULL
+ *
+ * Replaces @connection's settings with @new_settings (which must be
+ * syntactically valid, and describe a known type of connection, but does not
+ * need to result in a connection that passes nm_connection_verify()).
+ *
+ * Returns: %TRUE if connection was updated, %FALSE if @new_settings could not
+ *   be deserialized (in which case @connection will be unchanged).
+ **/
+gboolean
+nm_connection_replace_settings (NMConnection *connection,
+                                GVariant *new_settings,
+                                GError **error)
+{
+       return _nm_connection_replace_settings (connection, new_settings, NM_SETTING_PARSE_FLAGS_NONE, error);
+}
+
 /**
  * nm_connection_replace_settings_from_connection:
  * @connection: a #NMConnection