summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2013-11-29 12:50:34 +0100
committerThomas Haller <thaller@redhat.com>2014-06-30 18:35:46 +0200
commitde5656a5707a5d2b23ec3f2738476ad59d9edd04 (patch)
tree54cca75445101b9a616eca2d95a01ad120977026
parent542f1fe3c996f900615f8d47de4c6dc667134a5a (diff)
downloadNetworkManager-de5656a5707a5d2b23ec3f2738476ad59d9edd04.tar.gz
libnm-util: add function nm_connection_normalize
This function behaves like verify(), but it also performs some normalization/fixing of inconsistent connections. Contrary to verify(), this function might modify the settings. This will be mainly used, to repair connections from older versions and to fix deprecated options. Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r--libnm-util/libnm-util.ver1
-rw-r--r--libnm-util/nm-connection.c172
-rw-r--r--libnm-util/nm-connection.h5
-rw-r--r--libnm-util/nm-setting-private.h20
-rw-r--r--libnm-util/nm-setting.c17
-rw-r--r--libnm-util/nm-setting.h2
6 files changed, 195 insertions, 22 deletions
diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver
index 7472ec4244..ff7a7697f6 100644
--- a/libnm-util/libnm-util.ver
+++ b/libnm-util/libnm-util.ver
@@ -53,6 +53,7 @@ global:
nm_connection_need_secrets;
nm_connection_new;
nm_connection_new_from_hash;
+ nm_connection_normalize;
nm_connection_remove_setting;
nm_connection_replace_settings;
nm_connection_replace_settings_from_connection;
diff --git a/libnm-util/nm-connection.c b/libnm-util/nm-connection.c
index 936090c83b..2b5746c3dd 100644
--- a/libnm-util/nm-connection.c
+++ b/libnm-util/nm-connection.c
@@ -122,6 +122,10 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
+
+static NMSettingVerifyResult _nm_connection_verify (NMConnection *connection, GError **error);
+
+
/*************************************************************/
/**
@@ -584,7 +588,7 @@ nm_connection_diff (NMConnection *a,
* have allowed values, and some values are dependent on other values. For
* example, if a Wi-Fi connection is security enabled, the #NMSettingWireless
* setting object's 'security' property must contain the setting name of the
- * #NMSettingWirelessSecurity object, which must also be present in the
+ * #NMSettingWirelessSecurity object, which must also be present in the
* connection for the connection to be valid. As another example, the
* #NMSettingWired object's 'mac-address' property must be a validly formatted
* MAC address. The returned #GError contains information about which
@@ -595,24 +599,40 @@ nm_connection_diff (NMConnection *a,
gboolean
nm_connection_verify (NMConnection *connection, GError **error)
{
+ NMSettingVerifyResult result;
+
+ result = _nm_connection_verify (connection, error);
+
+ /* we treat normalizable connections as valid. */
+ if (result == NM_SETTING_VERIFY_NORMALIZABLE)
+ g_clear_error (error);
+
+ return result == NM_SETTING_VERIFY_SUCCESS || result == NM_SETTING_VERIFY_NORMALIZABLE;
+}
+
+static NMSettingVerifyResult
+_nm_connection_verify (NMConnection *connection, GError **error)
+{
NMConnectionPrivate *priv;
NMSettingConnection *s_con;
GHashTableIter iter;
gpointer value;
- GSList *all_settings = NULL;
- gboolean success = TRUE;
+ GSList *all_settings = NULL, *setting_i;
+ NMSettingVerifyResult success = NM_SETTING_VERIFY_ERROR;
NMSetting *base;
const char *ctype;
+ GError *normalizable_error = NULL;
+ NMSettingVerifyResult normalizable_error_type = NM_SETTING_VERIFY_SUCCESS;
if (error)
- g_return_val_if_fail (*error == NULL, FALSE);
+ g_return_val_if_fail (*error == NULL, NM_SETTING_VERIFY_ERROR);
if (!NM_IS_CONNECTION (connection)) {
g_set_error_literal (error,
NM_SETTING_CONNECTION_ERROR,
NM_SETTING_CONNECTION_ERROR_UNKNOWN,
"invalid connection; failed verification");
- g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (NM_IS_CONNECTION (connection), NM_SETTING_VERIFY_ERROR);
}
priv = NM_CONNECTION_GET_PRIVATE (connection);
@@ -624,23 +644,62 @@ nm_connection_verify (NMConnection *connection, GError **error)
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_CONNECTION_SETTING_NOT_FOUND,
"connection setting not found");
- return FALSE;
+ goto EXIT;
}
/* Build up the list of settings */
g_hash_table_iter_init (&iter, priv->settings);
- while (g_hash_table_iter_next (&iter, NULL, &value))
- all_settings = g_slist_append (all_settings, value);
+ while (g_hash_table_iter_next (&iter, NULL, &value)) {
+ /* Order NMSettingConnection so that it will be verified first.
+ * The reason is, that NMSettingConnection:verify() modifies the connection
+ * by setting NMSettingConnection:interface_name. So we want to call that
+ * verify() first, because the order can affect the outcome.
+ * Another reason is, that errors in this setting might be more fundamental
+ * and should be checked and reported with higher priority.
+ * Another reason is, that some settings look especially at the
+ * NMSettingConnection, so they find it first in the all_settings list. */
+ if (value == s_con)
+ all_settings = g_slist_append (all_settings, value);
+ else
+ all_settings = g_slist_prepend (all_settings, value);
+ }
+ all_settings = g_slist_reverse (all_settings);
/* Now, run the verify function of each setting */
- g_hash_table_iter_init (&iter, priv->settings);
- while (g_hash_table_iter_next (&iter, NULL, &value) && success)
- success = nm_setting_verify (NM_SETTING (value), all_settings, error);
+ for (setting_i = all_settings; setting_i; setting_i = setting_i->next) {
+ GError *verify_error = NULL;
+ NMSettingVerifyResult verify_result;
+
+ /* verify all settings. We stop if we find the first non-normalizable
+ * @NM_SETTING_VERIFY_ERROR. If we find normalizable errors we continue
+ * but remember the error to return it to the user.
+ * @NM_SETTING_VERIFY_NORMALIZABLE_ERROR has a higher priority then
+ * @NM_SETTING_VERIFY_NORMALIZABLE, so, if we encounter such an error type,
+ * we remember it instead (to return it as output).
+ **/
+ verify_result = _nm_setting_verify (NM_SETTING (setting_i->data), all_settings, &verify_error);
+ if (verify_result == NM_SETTING_VERIFY_NORMALIZABLE ||
+ verify_result == NM_SETTING_VERIFY_NORMALIZABLE_ERROR) {
+ if ( verify_result == NM_SETTING_VERIFY_NORMALIZABLE_ERROR
+ && normalizable_error_type == NM_SETTING_VERIFY_NORMALIZABLE) {
+ /* NORMALIZABLE_ERROR has higher priority. */
+ g_clear_error (&normalizable_error);
+ }
+ if (!normalizable_error) {
+ g_propagate_error (&normalizable_error, verify_error);
+ verify_error = NULL;
+ normalizable_error_type = verify_result;
+ }
+ } else if (verify_result != NM_SETTING_VERIFY_SUCCESS) {
+ g_propagate_error (error, verify_error);
+ g_slist_free (all_settings);
+ g_return_val_if_fail (verify_result == NM_SETTING_VERIFY_ERROR, success);
+ goto EXIT;
+ }
+ g_clear_error (&verify_error);
+ }
g_slist_free (all_settings);
- if (success == FALSE)
- return FALSE;
-
/* Now make sure the given 'type' setting can actually be the base setting
* of the connection. Can't have type=ppp for example.
*/
@@ -650,7 +709,7 @@ nm_connection_verify (NMConnection *connection, GError **error)
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID,
"connection type missing");
- return FALSE;
+ goto EXIT;
}
base = nm_connection_get_setting_by_name (connection, ctype);
@@ -659,7 +718,7 @@ nm_connection_verify (NMConnection *connection, GError **error)
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID,
"base setting GType not found");
- return FALSE;
+ goto EXIT;
}
if (!_nm_setting_is_base_type (base)) {
@@ -668,10 +727,87 @@ nm_connection_verify (NMConnection *connection, GError **error)
NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID,
"connection type '%s' is not a base type",
ctype);
- return FALSE;
+ goto EXIT;
}
- return TRUE;
+ if (normalizable_error_type != NM_SETTING_VERIFY_SUCCESS) {
+ g_propagate_error (error, normalizable_error);
+ normalizable_error = NULL;
+ success = normalizable_error_type;
+ } else
+ success = NM_SETTING_VERIFY_SUCCESS;
+
+EXIT:
+ g_clear_error (&normalizable_error);
+ return success;
+}
+
+/**
+ * nm_connection_normalize:
+ * @connection: the #NMConnection to normalize
+ * @parameters: (allow-none) (element-type utf8 gpointer): a #GHashTable with
+ * normalization parameters to allow customization of the normalization by providing
+ * specific arguments. Unknown arguments will be ignored and the default will be
+ * used. The keys must be strings, hashed by g_str_hash() and g_str_equal() functions.
+ * The values are opaque and depend on the parameter name.
+ * @modified: (out) (allow-none): outputs whether any settings were modified.
+ * @error: location to store error, or %NULL. Contains the reason,
+ * why the connection is invalid, if the function returns an error.
+ *
+ * Does some basic normalization and fixup of well known inconsistencies
+ * and deprecated fields. If the connection was modified in any way,
+ * the output parameter @modified is set %TRUE.
+ *
+ * Finally the connection will be verified and %TRUE returns if the connection
+ * is valid. As this function only performs some specific normalization steps
+ * it cannot repair all connections. If the connection has errors that
+ * cannot be normalized, the connection will not be modified.
+ *
+ * Returns: %TRUE if the connection is valid, %FALSE if it is not
+ *
+ * Since: 1.0
+ **/
+gboolean
+nm_connection_normalize (NMConnection *connection,
+ GHashTable *parameters,
+ gboolean *modified,
+ GError **error)
+{
+ NMSettingVerifyResult success;
+ gboolean was_modified = FALSE;
+ GError *normalizable_error = NULL;
+
+ success = _nm_connection_verify (connection, &normalizable_error);
+
+ if (success == NM_SETTING_VERIFY_ERROR ||
+ success == NM_SETTING_VERIFY_SUCCESS) {
+ if (normalizable_error)
+ g_propagate_error (error, normalizable_error);
+ goto EXIT;
+ }
+ g_assert (success == NM_SETTING_VERIFY_NORMALIZABLE || success == NM_SETTING_VERIFY_NORMALIZABLE_ERROR);
+ g_clear_error (&normalizable_error);
+
+ /* Try to perform all kind of normalizations on the settings to fix it.
+ * We only do this, after verifying that the connection contains no un-normalizable
+ * errors, because in that case we rather fail without touching the settings. */
+
+ /* TODO: no normalizations implemented yet */
+
+ /* Verify anew. */
+ success = _nm_connection_verify (connection, error);
+
+ /* we would expect, that after normalization, the connection can be verified. */
+ g_return_val_if_fail (success == NM_SETTING_VERIFY_SUCCESS, success);
+
+ /* we would expect, that the connection was modified during normalization. */
+ g_return_val_if_fail (was_modified, success);
+
+EXIT:
+ if (modified)
+ *modified = was_modified;
+
+ return success == NM_SETTING_VERIFY_SUCCESS;
}
/**
diff --git a/libnm-util/nm-connection.h b/libnm-util/nm-connection.h
index 4f7680f495..dcc24b9178 100644
--- a/libnm-util/nm-connection.h
+++ b/libnm-util/nm-connection.h
@@ -159,6 +159,11 @@ gboolean nm_connection_diff (NMConnection *a,
GHashTable **out_settings);
gboolean nm_connection_verify (NMConnection *connection, GError **error);
+NM_AVAILABLE_IN_1_0
+gboolean nm_connection_normalize (NMConnection *connection,
+ GHashTable *parameters,
+ gboolean *modified,
+ GError **error);
const char * nm_connection_need_secrets (NMConnection *connection,
GPtrArray **hints);
diff --git a/libnm-util/nm-setting-private.h b/libnm-util/nm-setting-private.h
index c3ec9d1993..d1131133f7 100644
--- a/libnm-util/nm-setting-private.h
+++ b/libnm-util/nm-setting-private.h
@@ -30,6 +30,22 @@
NM_SETTING_SECRET_FLAG_NOT_SAVED | \
NM_SETTING_SECRET_FLAG_NOT_REQUIRED)
+/**
+ * NMSettingVerifyResult:
+ * @NM_SETTING_VERIFY_SUCCESS: the setting verifies successfully
+ * @NM_SETTING_VERIFY_ERROR: the setting has a serious misconfiguration
+ * @NM_SETTING_VERIFY_NORMALIZABLE: the setting is valid but has properties
+ * that should be normalized
+ * @NM_SETTING_VERIFY_NORMALIZABLE_ERROR: the setting is invalid but the
+ * errors can be fixed by nm_connection_normalize().
+ */
+typedef enum {
+ NM_SETTING_VERIFY_SUCCESS = TRUE,
+ NM_SETTING_VERIFY_ERROR = FALSE,
+ NM_SETTING_VERIFY_NORMALIZABLE = 2,
+ NM_SETTING_VERIFY_NORMALIZABLE_ERROR = 3,
+} NMSettingVerifyResult;
+
void _nm_register_setting (const char *name,
const GType type,
const guint32 priority,
@@ -92,5 +108,9 @@ NMSetting *nm_setting_find_in_list (GSList *settings_list, const char *setting_n
const char *nm_setting_ip4_config_get_address_label (NMSettingIP4Config *setting, guint32 i);
gboolean nm_setting_ip4_config_add_address_with_label (NMSettingIP4Config *setting, NMIP4Address *address, const char *label);
+NMSettingVerifyResult _nm_setting_verify (NMSetting *setting,
+ GSList *all_settings,
+ GError **error);
+
#endif /* NM_SETTING_PRIVATE_H */
diff --git a/libnm-util/nm-setting.c b/libnm-util/nm-setting.c
index a290fc766b..47d76aa48e 100644
--- a/libnm-util/nm-setting.c
+++ b/libnm-util/nm-setting.c
@@ -517,13 +517,24 @@ nm_setting_get_name (NMSetting *setting)
gboolean
nm_setting_verify (NMSetting *setting, GSList *all_settings, GError **error)
{
- g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
- g_return_val_if_fail (!error || *error == NULL, FALSE);
+ NMSettingVerifyResult result = _nm_setting_verify (setting, all_settings, error);
+
+ if (result == NM_SETTING_VERIFY_NORMALIZABLE)
+ g_clear_error (error);
+
+ return result == NM_SETTING_VERIFY_SUCCESS || result == NM_SETTING_VERIFY_NORMALIZABLE;
+}
+
+NMSettingVerifyResult
+_nm_setting_verify (NMSetting *setting, GSList *all_settings, GError **error)
+{
+ g_return_val_if_fail (NM_IS_SETTING (setting), NM_SETTING_VERIFY_ERROR);
+ g_return_val_if_fail (!error || *error == NULL, NM_SETTING_VERIFY_ERROR);
if (NM_SETTING_GET_CLASS (setting)->verify)
return NM_SETTING_GET_CLASS (setting)->verify (setting, all_settings, error);
- return TRUE;
+ return NM_SETTING_VERIFY_SUCCESS;
}
static gboolean
diff --git a/libnm-util/nm-setting.h b/libnm-util/nm-setting.h
index 51e7de48a7..f48c63dbe5 100644
--- a/libnm-util/nm-setting.h
+++ b/libnm-util/nm-setting.h
@@ -173,7 +173,7 @@ typedef struct {
GObjectClass parent;
/* Virtual functions */
- gboolean (*verify) (NMSetting *setting,
+ gint (*verify) (NMSetting *setting,
GSList *all_settings,
GError **error);