diff options
author | Thomas Haller <thaller@redhat.com> | 2017-03-02 15:06:28 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-03-02 15:06:28 +0100 |
commit | 9d39569287f6770b951e30f68d88e14f9ec68ac7 (patch) | |
tree | f4f5ea1bc392838fd1ffcdedae196af198cab01d | |
parent | d63b67b0e0254c0a1d39b5ed8b7b15ce4f9ad259 (diff) | |
parent | 24be1fd913887464e1ed0c0a523df7302140fc99 (diff) |
ifcfg-rh,keyfile: merge branch 'th/ifcfg-reread-rh1427482'
https://bugzilla.redhat.com/show_bug.cgi?id=1427482
23 files changed, 625 insertions, 180 deletions
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index ce6f405c3..fa195402e 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -73,10 +73,6 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; - -static NMSettingVerifyResult _nm_connection_verify (NMConnection *connection, GError **error); - - /*****************************************************************************/ static void @@ -136,15 +132,15 @@ nm_connection_add_setting (NMConnection *connection, NMSetting *setting) * Removes the #NMSetting with the given #GType from the #NMConnection. This * operation dereferences the #NMSetting object. **/ -void -nm_connection_remove_setting (NMConnection *connection, GType setting_type) +gboolean +_nm_connection_remove_setting (NMConnection *connection, GType setting_type) { NMConnectionPrivate *priv; NMSetting *setting; const char *setting_name; - g_return_if_fail (NM_IS_CONNECTION (connection)); - g_return_if_fail (g_type_is_a (setting_type, NM_TYPE_SETTING)); + g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + g_return_val_if_fail (g_type_is_a (setting_type, NM_TYPE_SETTING), FALSE); priv = NM_CONNECTION_GET_PRIVATE (connection); setting_name = g_type_name (setting_type); @@ -153,7 +149,23 @@ nm_connection_remove_setting (NMConnection *connection, GType setting_type) g_signal_handlers_disconnect_by_func (setting, setting_changed_cb, connection); g_hash_table_remove (priv->settings, setting_name); g_signal_emit (connection, signals[CHANGED], 0); + return TRUE; } + return FALSE; +} + +/** + * nm_connection_remove_setting: + * @connection: a #NMConnection + * @setting_type: the #GType of the setting object to remove + * + * Removes the #NMSetting with the given #GType from the #NMConnection. This + * operation dereferences the #NMSetting object. + **/ +void +nm_connection_remove_setting (NMConnection *connection, GType setting_type) +{ + _nm_connection_remove_setting (connection, setting_type); } /** @@ -602,17 +614,17 @@ static gboolean _normalize_connection_uuid (NMConnection *self) { NMSettingConnection *s_con = nm_connection_get_setting_connection (self); - char *uuid; + char uuid[37]; - g_assert (s_con); + nm_assert (s_con); if (nm_setting_connection_get_uuid (s_con)) return FALSE; - uuid = nm_utils_uuid_generate (); - g_object_set (s_con, NM_SETTING_CONNECTION_UUID, uuid, NULL); - g_free (uuid); - + g_object_set (s_con, + NM_SETTING_CONNECTION_UUID, + nm_utils_uuid_generate_buf (uuid), + NULL); return TRUE; } @@ -986,6 +998,38 @@ _normalize_team_port_config (NMConnection *self, GHashTable *parameters) return FALSE; } +static gboolean +_normalize_required_settings (NMConnection *self, GHashTable *parameters) +{ + if (nm_connection_get_setting_vlan (self)) { + if (!nm_connection_get_setting_wired (self)) { + nm_connection_add_setting (self, nm_setting_wired_new ()); + return TRUE; + } + } + return FALSE; +} + +static gboolean +_normalize_invalid_slave_port_settings (NMConnection *self, GHashTable *parameters) +{ + NMSettingConnection *s_con = nm_connection_get_setting_connection (self); + const char *slave_type; + gboolean changed = FALSE; + + slave_type = nm_setting_connection_get_slave_type (s_con); + + if ( !nm_streq0 (slave_type, NM_SETTING_BRIDGE_SETTING_NAME) + && _nm_connection_remove_setting (self, NM_TYPE_SETTING_BRIDGE_PORT)) + changed = TRUE; + + if ( !nm_streq0 (slave_type, NM_SETTING_TEAM_SETTING_NAME) + && _nm_connection_remove_setting (self, NM_TYPE_SETTING_TEAM_PORT)) + changed = TRUE; + + return changed; +} + /** * nm_connection_verify: * @connection: the #NMConnection to verify @@ -1017,7 +1061,7 @@ nm_connection_verify (NMConnection *connection, GError **error) return result == NM_SETTING_VERIFY_SUCCESS || result == NM_SETTING_VERIFY_NORMALIZABLE; } -static NMSettingVerifyResult +NMSettingVerifyResult _nm_connection_verify (NMConnection *connection, GError **error) { NMConnectionPrivate *priv; @@ -1233,8 +1277,10 @@ nm_connection_normalize (NMConnection *connection, was_modified |= _normalize_connection_uuid (connection); was_modified |= _normalize_connection_type (connection); was_modified |= _normalize_connection_slave_type (connection); - was_modified |= _normalize_ethernet_link_neg (connection); + was_modified |= _normalize_required_settings (connection, parameters); + was_modified |= _normalize_invalid_slave_port_settings (connection, parameters); was_modified |= _normalize_ip_config (connection, parameters); + was_modified |= _normalize_ethernet_link_neg (connection); was_modified |= _normalize_infiniband_mtu (connection, parameters); was_modified |= _normalize_bond_mode (connection, parameters); was_modified |= _normalize_wireless_mac_address_randomization (connection, parameters); diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 71e0ff893..ac292bfc1 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -118,6 +118,26 @@ gboolean _nm_connection_replace_settings (NMConnection *connection, NMSettingParseFlags parse_flags, GError **error); +/** + * 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; + +NMSettingVerifyResult _nm_connection_verify (NMConnection *connection, GError **error); + +gboolean _nm_connection_remove_setting (NMConnection *connection, GType setting_type); + NMConnection *_nm_simple_connection_new_from_dbus (GVariant *dict, NMSettingParseFlags parse_flags, GError **error); diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c index ac8bdf2d2..376da69f4 100644 --- a/libnm-core/nm-setting-connection.c +++ b/libnm-core/nm-setting-connection.c @@ -857,7 +857,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) { NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting); gboolean is_slave; - const char *slave_setting_type = NULL; + const char *slave_setting_type; NMSetting *normerr_base_type = NULL; const char *normerr_slave_setting_type = NULL; const char *normerr_missing_slave_type = NULL; @@ -958,16 +958,17 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } is_slave = FALSE; - if (priv->slave_type) + slave_setting_type = NULL; + if (priv->slave_type) { is_slave = _nm_setting_slave_type_is_valid (priv->slave_type, &slave_setting_type); - - if (priv->slave_type && !is_slave) { - g_set_error (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("Unknown slave type '%s'"), priv->slave_type); - g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_SLAVE_TYPE); - return FALSE; + if (!is_slave) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("Unknown slave type '%s'"), priv->slave_type); + g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_SLAVE_TYPE); + return FALSE; + } } if (is_slave) { @@ -1063,6 +1064,24 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return NM_SETTING_VERIFY_NORMALIZABLE_ERROR; } + if (connection) { + gboolean has_bridge_port = FALSE; + + if ( ( !nm_streq0 (priv->slave_type, NM_SETTING_BRIDGE_SETTING_NAME) + && (has_bridge_port = !!nm_connection_get_setting_by_name (connection, NM_SETTING_BRIDGE_PORT_SETTING_NAME))) + || ( !nm_streq0 (priv->slave_type, NM_SETTING_TEAM_SETTING_NAME) + && nm_connection_get_setting_by_name (connection, NM_SETTING_TEAM_PORT_SETTING_NAME))) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_SETTING, + _("A slave connection with '%s' set to '%s' cannot have a '%s' setting"), + NM_SETTING_CONNECTION_SLAVE_TYPE, priv->slave_type ?: "", + has_bridge_port ? NM_SETTING_BRIDGE_PORT_SETTING_NAME : NM_SETTING_TEAM_PORT_SETTING_NAME); + g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_SLAVE_TYPE); + return NM_SETTING_VERIFY_NORMALIZABLE_ERROR; + } + } + return TRUE; } diff --git a/libnm-core/nm-setting-private.h b/libnm-core/nm-setting-private.h index 8d09e3d75..79b6ac871 100644 --- a/libnm-core/nm-setting-private.h +++ b/libnm-core/nm-setting-private.h @@ -27,22 +27,6 @@ #include "nm-core-internal.h" -/** - * 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); diff --git a/libnm-core/nm-setting-vlan.c b/libnm-core/nm-setting-vlan.c index 612647847..bbda72d7b 100644 --- a/libnm-core/nm-setting-vlan.c +++ b/libnm-core/nm-setting-vlan.c @@ -600,7 +600,7 @@ nm_setting_vlan_init (NMSettingVlan *setting) { } -static gboolean +static int verify (NMSetting *setting, NMConnection *connection, GError **error) { NMSettingVlanPrivate *priv = NM_SETTING_VLAN_GET_PRIVATE (setting); @@ -681,6 +681,18 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + if (connection && !s_wired) { + /* technically, a VLAN setting does not require an ethernet setting. However, + * the ifcfg-rh reader always adds a ethernet setting when reading a vlan setting. + * Thus, in order to be consistent, always add one via normalization. */ + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_SETTING_NOT_FOUND, + _("vlan setting should have a ethernet setting as well")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_FLAGS); + return NM_SETTING_VERIFY_NORMALIZABLE; + } + return TRUE; } diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 55b660db8..20b871622 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -217,7 +217,7 @@ nm_utils_complete_generic (NMPlatform *platform, gboolean default_enable_ipv6) { NMSettingConnection *s_con; - char *id, *uuid, *ifname; + char *id, *ifname; GHashTable *parameters; g_assert (fallback_id_prefix); @@ -230,9 +230,9 @@ nm_utils_complete_generic (NMPlatform *platform, g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_TYPE, ctype, NULL); if (!nm_setting_connection_get_uuid (s_con)) { - uuid = nm_utils_uuid_generate (); - g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_UUID, uuid, NULL); - g_free (uuid); + char uuid[37]; + + g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_buf (uuid), NULL); } /* Add a connection ID if absent */ diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c index 92b2c9189..ebfa0d647 100644 --- a/src/devices/bluetooth/nm-bluez-device.c +++ b/src/devices/bluetooth/nm-bluez-device.c @@ -183,7 +183,8 @@ pan_connection_check_create (NMBluezDevice *self) NMConnection *connection; NMConnection *added; NMSetting *setting; - char *uuid, *id; + char *id; + char uuid[37]; GError *error = NULL; NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); @@ -205,7 +206,7 @@ pan_connection_check_create (NMBluezDevice *self) connection = nm_simple_connection_new (); /* Setting: Connection */ - uuid = nm_utils_uuid_generate (); + nm_utils_uuid_generate_buf (uuid); id = g_strdup_printf (_("%s Network"), priv->name); setting = nm_setting_connection_new (); g_object_set (setting, @@ -266,7 +267,6 @@ pan_connection_check_create (NMBluezDevice *self) g_object_unref (connection); g_free (id); - g_free (uuid); } static gboolean diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index a0a5ed2ae..ef96243b2 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3629,7 +3629,7 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master) NMSetting *s_con; NMSetting *s_ip4; NMSetting *s_ip6; - gs_free char *uuid = NULL; + char uuid[37]; const char *ip4_method, *ip6_method; GError *error = NULL; const NMPlatformLink *pllink; @@ -3646,10 +3646,9 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master) connection = nm_simple_connection_new (); s_con = nm_setting_connection_new (); - uuid = nm_utils_uuid_generate (); g_object_set (s_con, - NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_buf (uuid), NM_SETTING_CONNECTION_ID, ifname, NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c index ba8ea323e..b54f9549a 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c @@ -345,11 +345,15 @@ commit_changes (NMSettingsConnection *connection, success = writer_update_connection (NM_CONNECTION (connection), IFCFG_DIR, filename, + NULL, + NULL, &error); } else { success = writer_new_connection (NM_CONNECTION (connection), IFCFG_DIR, &ifcfg_path, + NULL, + NULL, &error); if (success) { nm_settings_connection_set_filename (connection, ifcfg_path); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c index 414f593b6..3c5ae91ff 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c @@ -687,7 +687,7 @@ add_connection (NMSettingsPlugin *config, return NULL; if (save_to_disk) { - if (!writer_new_connection (connection, IFCFG_DIR, &path, error)) + if (!writer_new_connection (connection, IFCFG_DIR, &path, NULL, NULL, error)) return NULL; } return NM_SETTINGS_CONNECTION (update_connection (self, connection, path, NULL, FALSE, NULL, error)); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index bbe990336..4a128024c 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -5087,8 +5087,15 @@ connection_from_file_full (const char *filename, if (devtype) { if (!strcasecmp (devtype, TYPE_TEAM)) type = g_strdup (TYPE_TEAM); - else if (!strcasecmp (devtype, TYPE_TEAM_PORT)) - type = g_strdup (TYPE_ETHERNET); + else if (!strcasecmp (devtype, TYPE_TEAM_PORT)) { + gs_free char *device = NULL; + + device = svGetValueStr_cp (parsed, "DEVICE"); + if (device && is_vlan_device (device, parsed)) + type = g_strdup (TYPE_VLAN); + else + type = g_strdup (TYPE_ETHERNET); + } g_free (devtype); } if (!type) { diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 6d4d5a3f9..620e89e4b 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -307,7 +307,6 @@ write_8021x_certs (NMSetting8021x *s_8021x, shvarFile *ifcfg, GError **error) { - gboolean success = FALSE; const Setting8021xSchemeVtable *otype = NULL; /* CA certificate */ @@ -326,7 +325,7 @@ write_8021x_certs (NMSetting8021x *s_8021x, /* Save the private key */ if (!write_object (s_8021x, ifcfg, otype, error)) - goto out; + return FALSE; /* Client certificate */ if (otype->vtable->format_func (s_8021x) == NM_SETTING_802_1X_CK_FORMAT_PKCS12) { @@ -343,13 +342,10 @@ write_8021x_certs (NMSetting8021x *s_8021x, ? &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT] : &setting_8021x_scheme_vtable[NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT], error)) - goto out; + return FALSE; } - success = TRUE; - -out: - return success; + return TRUE; } static gboolean @@ -362,7 +358,6 @@ write_8021x_setting (NMConnection *connection, NMSetting8021xAuthFlags auth_flags; const char *value, *match; char *tmp = NULL; - gboolean success = FALSE; GString *phase2_auth; GString *str; guint32 i, num; @@ -511,13 +506,14 @@ write_8021x_setting (NMConnection *connection, else svUnsetValue (ifcfg, "IEEE_8021X_AUTH_TIMEOUT"); - success = write_8021x_certs (s_8021x, FALSE, ifcfg, error); - if (success) { - /* phase2/inner certs */ - success = write_8021x_certs (s_8021x, TRUE, ifcfg, error); - } + if (!write_8021x_certs (s_8021x, FALSE, ifcfg, error)) + return FALSE; + + /* phase2/inner certs */ + if (!write_8021x_certs (s_8021x, TRUE, ifcfg, error)) + return FALSE; - return success; + return TRUE; } static gboolean @@ -1876,12 +1872,11 @@ write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError { const char *dest, *next_hop; char **route_items; - char *route_contents; + gs_free char *route_contents = NULL; NMIPRoute *route; guint32 prefix; gint64 metric; guint32 i, num; - gboolean success = FALSE; g_return_val_if_fail (filename != NULL, FALSE); g_return_val_if_fail (s_ip4 != NULL, FALSE); @@ -1915,15 +1910,10 @@ write_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError if (!g_file_set_contents (filename, route_contents, -1, NULL)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Writing route file '%s' failed", filename); - goto error; + return FALSE; } - success = TRUE; - -error: - g_free (route_contents); - - return success; + return TRUE; } static gboolean @@ -2382,10 +2372,9 @@ static gboolean write_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error) { char **route_items; - char *route_contents; + gs_free char *route_contents = NULL; NMIPRoute *route; guint32 i, num; - gboolean success = FALSE; g_return_val_if_fail (filename != NULL, FALSE); g_return_val_if_fail (s_ip6 != NULL, FALSE); @@ -2422,14 +2411,10 @@ write_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **erro if (!g_file_set_contents (filename, route_contents, -1, NULL)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Writing route6 file '%s' failed", filename); - goto error; + return FALSE; } - success = TRUE; - -error: - g_free (route_contents); - return success; + return TRUE; } static void @@ -2637,17 +2622,14 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) if (!route6_path) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Could not get route6 file path for '%s'", svFileGetName (ifcfg)); - goto error; + return FALSE; } write_route6_file (route6_path, s_ip6, error); g_free (route6_path); if (error && *error) - goto error; + return FALSE; return TRUE; - -error: - return FALSE; } static void @@ -2732,18 +2714,20 @@ write_connection (NMConnection *connection, const char *ifcfg_dir, const char *filename, char **out_filename, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error) { NMSettingConnection *s_con; - gboolean success = FALSE; - shvarFile *ifcfg = NULL; - char *ifcfg_name = NULL; + nm_auto_shvar_file_close shvarFile *ifcfg = NULL; + gs_free char *ifcfg_name = NULL; const char *type; gboolean no_8021x = FALSE; gboolean wired = FALSE; nm_assert (NM_IS_CONNECTION (connection)); - nm_assert (nm_connection_verify (connection, NULL)); + nm_assert (_nm_connection_verify (connection, NULL) == NM_SETTING_VERIFY_SUCCESS); + nm_assert (!out_reread || !*out_reread); if (!writer_can_write_connection (connection, error)) return FALSE; @@ -2772,13 +2756,12 @@ write_connection (NMConnection *connection, if (g_file_test (ifcfg_name, G_FILE_TEST_EXISTS)) { guint32 idx = 0; - g_free (ifcfg_name); + nm_clear_g_free (&ifcfg_name); while (idx++ < 500) { ifcfg_name = g_strdup_printf ("%s/ifcfg-%s-%u", ifcfg_dir, escaped, idx); if (g_file_test (ifcfg_name, G_FILE_TEST_EXISTS) == FALSE) break; - g_free (ifcfg_name); - ifcfg_name = NULL; + nm_clear_g_free (&ifcfg_name); } } g_free (escaped); @@ -2796,7 +2779,7 @@ write_connection (NMConnection *connection, if (!type) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Missing connection type!"); - goto out; + return FALSE; } if (!strcmp (type, NM_SETTING_WIRED_SETTING_NAME)) { @@ -2805,82 +2788,110 @@ write_connection (NMConnection *connection, g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Can't write connection type '%s'", NM_SETTING_PPPOE_SETTING_NAME); - goto out; + return FALSE; } if (!write_wired_setting (connection, ifcfg, error)) - goto out; + return FALSE; wired = TRUE; } else if (!strcmp (type, NM_SETTING_VLAN_SETTING_NAME)) { if (!write_vlan_setting (connection, ifcfg, &wired, error)) - goto out; + return FALSE; } else if (!strcmp (type, NM_SETTING_WIRELESS_SETTING_NAME)) { if (!write_wireless_setting (connection, ifcfg, &no_8021x, error)) - goto out; + return FALSE; } else if (!strcmp (type, NM_SETTING_INFINIBAND_SETTING_NAME)) { if (!write_infiniband_setting (connection, ifcfg, error)) - goto out; + return FALSE; } else if (!strcmp (type, NM_SETTING_BOND_SETTING_NAME)) { if (!write_bonding_setting (connection, ifcfg, &wired, error)) - goto out; + return FALSE; } else if (!strcmp (type, NM_SETTING_TEAM_SETTING_NAME)) { if (!write_team_setting (connection, ifcfg, &wired, error)) - goto out; + return FALSE; } else if (!strcmp (type, NM_SETTING_BRIDGE_SETTING_NAME)) { if (!write_bridge_setting (connection, ifcfg, error)) - goto out; + return FALSE; } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Can't write connection type '%s'", type); - goto out; + return FALSE; } if (!no_8021x) { if (!write_8021x_setting (connection, ifcfg, wired, error)) - goto out; + return FALSE; } if (!write_bridge_port_setting (connection, ifcfg, error)) - goto out; + return FALSE; if (!write_team_port_setting (connection, ifcfg, error)) - goto out; + return FALSE; if (!write_dcb_setting (connection, ifcfg, error)) - goto out; + return FALSE; if (!write_proxy_setting (connection, ifcfg, error)) - goto out; + return FALSE; svUnsetValue (ifcfg, "DHCP_HOSTNAME"); svUnsetValue (ifcfg, "DHCP_FQDN"); if (!write_ip4_setting (connection, ifcfg, error)) - goto out; + return FALSE; write_ip4_aliases (connection, ifcfg_name); if (!write_ip6_setting (connection, ifcfg, error)) - goto out; + return FALSE; if (!write_res_options (connection, ifcfg, error)) - goto out; + return FALSE; write_connection_setting (s_con, ifcfg); if (!svWriteFile (ifcfg, 0644, error)) - goto out; + return FALSE; + + if (out_reread || out_reread_same) { + gs_unref_object NMConnection *reread = NULL; + gs_free_error GError *local = NULL; + gs_free char *unhandled = NULL; + gboolean reread_same = FALSE; + + reread = connection_from_file (ifcfg_name, &unhandled, &local, NULL); + + if (unhandled) { + _LOGW ("failure to re-read the new connection from file \"%s\": %s", + ifcfg_name, "connection is unhandled"); + g_clear_object (&reread); + } else if (!reread) { + _LOGW ("failure to re-read the new connection from file \"%s\": %s", + ifcfg_name, local ? local->message : "<unknown>"); + } else { + if (out_reread_same) { + if (nm_connection_compare (reread, connection, NM_SETTING_COMPARE_FLAG_EXACT)) + reread_same = TRUE; + + nm_assert (reread_same == nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT)); + nm_assert (reread_same == ({ + gs_unref_hashtable GHashTable *_settings = NULL; + + ( nm_connection_diff (reread, connection, NM_SETTING_COMPARE_FLAG_EXACT, &_settings) + && !_settings); + })); + } + } + + NM_SET_OUT (out_reread, g_steal_pointer (&reread)); + NM_SET_OUT (out_reread_same, reread_same); + } /* Only return the filename if this was a newly written ifcfg */ if (out_filename && !filename) - *out_filename = g_strdup (ifcfg_name); + *out_filename = g_steal_pointer (&ifcfg_name); - success = TRUE; - -out: - if (ifcfg) - svCloseFile (ifcfg); - g_free (ifcfg_name); - return success; + return TRUE; } gboolean @@ -2912,15 +2923,19 @@ gboolean writer_new_connection (NMConnection *connection, const char *ifcfg_dir, char **out_filename, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error) { - return write_connection (connection, ifcfg_dir, NULL, out_filename, error); + return write_connection (connection, ifcfg_dir, NULL, out_filename, out_reread, out_reread_same, error); } gboolean writer_update_connection (NMConnection *connection, const char *ifcfg_dir, const char *filename, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error) { if (utils_has_complex_routes (filename)) { @@ -2929,6 +2944,6 @@ writer_update_connection (NMConnection *connection, return FALSE; } - return write_connection (connection, ifcfg_dir, filename, NULL, error); + return write_connection (connection, ifcfg_dir, filename, NULL, out_reread, out_reread_same, error); } diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h index 2662f79b0..9cd9513ec 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.h @@ -29,11 +29,15 @@ gboolean writer_can_write_connection (NMConnection *connection, gboolean writer_new_connection (NMConnection *connection, const char *ifcfg_dir, char **out_filename, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error); gboolean writer_update_connection (NMConnection *connection, const char *ifcfg_dir, const char *filename, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error); #endif /* _WRITER_H_ */ diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c index a05865793..d847ba73f 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.c +++ b/src/settings/plugins/ifcfg-rh/shvar.c @@ -637,15 +637,19 @@ svFileGetName (const shvarFile *s) } void -svFileSetName (shvarFile *s, const char *fileName) +svFileSetName_test_only (shvarFile *s, const char *fileName) { + /* changing the file name is not supported for regular + * operation. Only allowed to use in tests, othewise, + * the filename is immutable. */ g_free (s->fileName); s->fileName = g_strdup (fileName); } void -svFileSetModified (shvarFile *s) +svFileSetModified_test_only (shvarFile *s) { + /* marking a file as modified is only for testing. */ s->modified = TRUE; } diff --git a/src/settings/plugins/ifcfg-rh/shvar.h b/src/settings/plugins/ifcfg-rh/shvar.h index 5c384bb22..8eaf9b878 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.h +++ b/src/settings/plugins/ifcfg-rh/shvar.h @@ -34,9 +34,9 @@ typedef struct _shvarFile shvarFile; const char *svFileGetName (const shvarFile *s); -void svFileSetName (shvarFile *s, const char *fileName); -void svFileSetModified (shvarFile *s); +void svFileSetName_test_only (shvarFile *s, const char *fileName); +void svFileSetModified_test_only (shvarFile *s); /* Create the file <name>, return a shvarFile (never fails) */ shvarFile *svCreateFile (const char *name); diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index fd4bdfdf7..bd6068ce1 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -88,22 +88,72 @@ || ( _val_string && nm_streq0 (_val, _val_string))); \ } G_STMT_END -#define _writer_update_connection(connection, ifcfg_dir, filename) \ +static void +_assert_reread_same (NMConnection *connection, NMConnection *reread) +{ + nmtst_assert_connection_verifies_without_normalization (reread); + nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); +} + +static void +_assert_reread_same_FIXME (NMConnection *connection, NMConnection *reread) +{ + gs_unref_object NMConnection *connection_normalized = NULL; + gs_unref_hashtable GHashTable *settings = NULL; + + /* FIXME: these assertion failures should not happen as we expect + * that re-reading a connection after write yields the same result. + * + * Needs investation and fixing. */ + nmtst_assert_connection_verifies_without_normalization (reread); + + connection_normalized = nmtst_connection_duplicate_and_normalize (connection); + + g_assert (!nm_connection_compare (connection_normalized, reread, NM_SETTING_COMPARE_FLAG_EXACT)); + g_assert (!nm_connection_diff (connection_normalized, reread, NM_SETTING_COMPARE_FLAG_EXACT, &settings)); +} + +#define _writer_update_connection_reread(connection, ifcfg_dir, filename, out_reread, out_reread_same) \ G_STMT_START { \ - NMConnection *_connection = (connection); \ + gs_unref_object NMConnection *_connection = nmtst_connection_duplicate_and_normalize (connection); \ + NMConnection **_out_reread = (out_reread); \ + gboolean *_out_reread_same = (out_reread_same); \ const char *_ifcfg_dir = (ifcfg_dir); \ const char *_filename = (filename); \ GError *_error = NULL; \ gboolean _success; \ \ - g_assert (NM_IS_CONNECTION (connection)); \ g_assert (_ifcfg_dir && _ifcfg_dir[0]); \ g_assert (_filename && _filename[0]); \ \ - _success = writer_update_connection (_connection, _ifcfg_dir, _filename, &_error); \ + _success = writer_update_connection (_connection, _ifcfg_dir, _filename, _out_reread, _out_reread_same, &_error); \ nmtst_assert_success (_success, _error); \ } G_STMT_END +#define _writer_update_connection(connection, ifcfg_dir, filename) \ + G_STMT_START { \ + gs_unref_object NMConnection *_reread = NULL; \ + NMConnection *_c = (connection); \ + gboolean _reread_same = FALSE; \ + \ + _writer_update_connection_reread (_c, ifcfg_dir, filename, &_reread, &_reread_same); \ + _assert_reread_same (_c, _reread); \ + g_assert (_reread_same); \ + } G_STMT_END + +#define _writer_update_connection_FIXME(connection, ifcfg_dir, filename) \ + G_STMT_START { \ + gs_unref_object NMConnection *_reread = NULL; \ + NMConnection *_c = (connection); \ + gboolean _reread_same = FALSE; \ + \ + /* FIXME: this should not happen. Fix to use _writer_update_connection() */ \ + \ + _writer_update_connection_reread (_c, ifcfg_dir, filename, &_reread, &_reread_same); \ + _assert_reread_same_FIXME (_c, _reread); \ + g_assert (!_reread_same); \ + } G_STMT_END + static NMConnection * _connection_from_file (const char *filename, const char *network_file, @@ -147,14 +197,18 @@ _connection_from_file_fail (const char *filename, } static void -_writer_new_connection (NMConnection *connection, - const char *ifcfg_dir, - char **out_filename) +_writer_new_connection_reread (NMConnection *connection, + const char *ifcfg_dir, + char **out_filename, + NMConnection **out_reread, + gboolean *out_reread_same) { gboolean success; GError *error = NULL; char *filename = NULL; gs_unref_object NMConnection *con_verified = NULL; + gs_unref_object NMConnection *reread_copy = NULL; + NMConnection **reread = out_reread ?: ((nmtst_get_rand_int () % 2) ? &reread_copy : NULL); g_assert (NM_IS_CONNECTION (connection)); g_assert (ifcfg_dir); @@ -164,10 +218,15 @@ _writer_new_connection (NMConnection *connection, success = writer_new_connection (con_verified, ifcfg_dir, &filename, + reread, + out_reread_same, &error); nmtst_assert_success (success, error); g_assert (filename && filename[0]); + if (reread) + nmtst_assert_connection_verifies_without_normalization (*reread); + if (out_filename) *out_filename = filename; else @@ -175,10 +234,40 @@ _writer_new_connection (NMConnection *connection, } static void +_writer_new_connection (NMConnection *connection, + const char *ifcfg_dir, + char **out_filename) +{ + gs_unref_object NMConnection *reread = NULL; + gboolean reread_same = FALSE; + + _writer_new_connection_reread (connection, ifcfg_dir, out_filename, &reread, &reread_same); + _assert_reread_same (connection, reread); + g_assert (reread_same); +} + +static void +_writer_new_connection_FIXME (NMConnection *connection, + const char *ifcfg_dir, + char **out_filename) +{ + gs_unref_object NMConnection *reread = NULL; + gboolean reread_same = FALSE; + + /* FIXME: this should not happen. Fix it to use _writer_new_connection() instead. */ + + _writer_new_connection_reread (connection, ifcfg_dir, out_filename, &reread, &reread_same); + _assert_reread_same_FIXME (connection, reread); + g_assert (!reread_same); +} + +static void _writer_new_connection_fail (NMConnection *connection, const char *ifcfg_dir, GError **error) { + gs_unref_object NMConnection *connection_normalized = NULL; + gs_unref_object NMConnection *reread = NULL; gboolean success; GError *local = NULL; char *filename = NULL; @@ -186,12 +275,17 @@ _writer_new_connection_fail (NMConnection *connection, g_assert (NM_IS_CONNECTION (connection)); g_assert (ifcfg_dir); - success = writer_new_connection (connection, + connection_normalized = nmtst_connection_duplicate_and_normalize (connection); + + success = writer_new_connection (connection_normalized, ifcfg_dir, &filename, + &reread, + NULL, &local); nmtst_assert_no_success (success, local); g_assert (!filename); + g_assert (!reread); g_propagate_error (error, local); } @@ -1567,12 +1661,15 @@ test_read_write_802_1X_subj_matches (void) g_assert_cmpstr (nm_setting_802_1x_get_phase2_altsubject_match (s_8021x, 0), ==, "x.yourdomain.tld"); g_assert_cmpstr (nm_setting_802_1x_get_phase2_altsubject_match (s_8021x, 1), ==, "y.yourdomain.tld"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, + "*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!"); _writer_new_connection (connection, TEST_SCRATCH_DIR "/network-scripts/", &testfile); + g_test_assert_expected_messages (); g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, - "*missing IEEE_8021X_CA_CERT*peap*"); + "*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!"); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); g_test_assert_expected_messages (); @@ -1831,6 +1928,8 @@ test_clear_master (void) g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, NULL); g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NULL); + nmtst_assert_connection_verifies_after_normalization (connection, 0, 0); + /* 4. update the connection on disk */ _writer_update_connection (connection, TEST_SCRATCH_DIR "/network-scripts/", @@ -1917,9 +2016,9 @@ test_write_dns_options (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection_FIXME (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); @@ -3781,9 +3880,9 @@ test_write_wired_static (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection_FIXME (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); route6file = utils_get_route6_path (testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); @@ -4451,9 +4550,9 @@ test_write_wired_8021x_tls (gconstpointer test_data) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection_FIXME (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); reread = _connection_from_file (testfile, NULL, TYPE_WIRELESS, NULL); @@ -4590,9 +4689,9 @@ test_write_wired_aliases (void) svCloseFile (ifcfg); g_assert (g_file_test (TEST_SCRATCH_ALIAS_BASE ":5", G_FILE_TEST_EXISTS)); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection_FIXME (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); /* Re-check the alias files */ g_assert (g_file_test (TEST_SCRATCH_ALIAS_BASE ":2", G_FILE_TEST_EXISTS)); @@ -5444,9 +5543,9 @@ test_write_wifi_leap_secret_flags (gconstpointer data) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection_FIXME (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); reread = _connection_from_file (testfile, NULL, TYPE_WIRELESS, NULL); @@ -6592,9 +6691,9 @@ test_write_wifi_wep_agent_keys (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection_FIXME (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); reread = _connection_from_file (testfile, NULL, TYPE_WIRELESS, NULL); @@ -8289,6 +8388,68 @@ test_read_team_port_empty_config (void) } static void +test_team_reread_slave (void) +{ + nmtst_auto_unlinkfile char *testfile = NULL; + gs_unref_object NMConnection *connection_1 = NULL; + gs_unref_object NMConnection *connection_2 = NULL; + gs_unref_object NMConnection *reread = NULL; + gboolean reread_same = FALSE; + NMSettingConnection *s_con; + + connection_1 = nmtst_create_connection_from_keyfile ( + "[connection]\n" + "id=team-slave-enp31s0f1-142\n" + "uuid=74f435bb-ede4-415a-9d48-f580b60eba04\n" + "type=vlan\n" + "autoconnect=false\n" + "interface-name=enp31s0f1-142\n" + "master=team142\n" + "permissions=\n" + "slave-type=team\n" + "\n" + "[vlan]\n" + "egress-priority-map=\n" + "flags=1\n" + "id=142\n" + "ingress-priority-map=\n" + "parent=enp31s0f1\n" + , "/test_team_reread_slave", NULL); + + /* to double-check keyfile syntax, re-create the connection by hand. */ + connection_2 = nmtst_create_minimal_connection ("team-slave-enp31s0f1-142", "74f435bb-ede4-415a-9d48-f580b60eba04", NM_SETTING_VLAN_SETTING_NAME, &s_con); + g_object_set (s_con, + NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, + NM_SETTING_CONNECTION_INTERFACE_NAME, "enp31s0f1-142", + NM_SETTING_CONNECTION_MASTER, "team142", + NM_SETTING_CONNECTION_SLAVE_TYPE, "team", + NULL); + g_object_set (nm_connection_get_setting_vlan (connection_2), + NM_SETTING_VLAN_FLAGS, 1, + NM_SETTING_VLAN_ID, 142, + NM_SETTING_VLAN_PARENT, "enp31s0f1", + NULL); + nm_connection_add_setting (connection_2, nm_setting_team_port_new ()); + nmtst_connection_normalize (connection_2); + + nmtst_assert_connection_equals (connection_1, FALSE, connection_2, FALSE); + + _writer_new_connection_reread ((nmtst_get_rand_int () % 2) ? connection_1 : connection_2, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile, + &reread, + &reread_same); + _assert_reread_same ((nmtst_get_rand_int () % 2) ? connection_1 : connection_2, reread); + g_assert (reread_same); + g_clear_object (&reread); + + reread = _connection_from_file (testfile, NULL, TYPE_VLAN, + NULL); + nmtst_assert_connection_equals ((nmtst_get_rand_int () % 2) ? connection_1 : connection_2, FALSE, + reread, FALSE); +} + +static void test_read_proxy_basic (void) { NMConnection *connection; @@ -8702,8 +8863,8 @@ test_write_unknown (gconstpointer test_data) sv = _svOpenFile (testfile); - svFileSetName (sv, filename_tmp_1); - svFileSetModified (sv); + svFileSetName_test_only (sv, filename_tmp_1); + svFileSetModified_test_only (sv); if (g_str_has_suffix (testfile, "ifcfg-test-write-unknown-4")) { _svGetValue_check (sv, "NAME", "l4x"); @@ -9154,6 +9315,7 @@ int main (int argc, char **argv) g_test_add_data_func (TPATH "team/read-port-2", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-port-2", test_read_team_port); g_test_add_func (TPATH "team/write-port", test_write_team_port); g_test_add_func (TPATH "team/read-port-empty-config", test_read_team_port_empty_config); + g_test_add_func (TPATH "team/reread-slave", test_team_reread_slave); g_test_add_func (TPATH "proxy/read-proxy-basic", test_read_proxy_basic); g_test_add_func (TPATH "proxy/write-proxy-basic", test_write_proxy_basic); diff --git a/src/settings/plugins/keyfile/nms-keyfile-connection.c b/src/settings/plugins/keyfile/nms-keyfile-connection.c index ff654acf8..bd07d263c 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-connection.c +++ b/src/settings/plugins/keyfile/nms-keyfile-connection.c @@ -58,12 +58,16 @@ commit_changes (NMSettingsConnection *connection, { char *path = NULL; GError *error = NULL; + gs_unref_object NMConnection *reread = NULL; + gboolean reread_same = FALSE; if (!nms_keyfile_writer_connection (NM_CONNECTION (connection), nm_settings_connection_get_filename (connection), NM_FLAGS_ALL (commit_reason, NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION | NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED), &path, + &reread, + &reread_same, &error)) { callback (connection, error, user_data); g_clear_error (&error); @@ -89,6 +93,18 @@ commit_changes (NMSettingsConnection *connection, NMS_KEYFILE_CONNECTION_LOG_ARG (connection)); } + if (reread && !reread_same) { + gs_free_error GError *local = NULL; + + if (!nm_settings_connection_replace_settings (connection, reread, FALSE, "update-during-write", &local)) { + nm_log_warn (LOGD_SETTINGS, "keyfile: update "NMS_KEYFILE_CONNECTION_LOG_FMT" after persisting connection failed: %s", + NMS_KEYFILE_CONNECTION_LOG_ARG (connection), local->message); + } else { + nm_log_info (LOGD_SETTINGS, "keyfile: update "NMS_KEYFILE_CONNECTION_LOG_FMT" after persisting connection", + NMS_KEYFILE_CONNECTION_LOG_ARG (connection)); + } + } + g_free (path); NM_SETTINGS_CONNECTION_CLASS (nms_keyfile_connection_parent_class)->commit_changes (connection, diff --git a/src/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/settings/plugins/keyfile/nms-keyfile-plugin.c index 97306d665..d76b64c72 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-plugin.c +++ b/src/settings/plugins/keyfile/nms-keyfile-plugin.c @@ -530,12 +530,19 @@ add_connection (NMSettingsPlugin *config, { NMSKeyfilePlugin *self = NMS_KEYFILE_PLUGIN (config); gs_free char *path = NULL; + gs_unref_object NMConnection *reread = NULL; if (save_to_disk) { - if (!nms_keyfile_writer_connection (connection, NULL, FALSE, &path, error)) + if (!nms_keyfile_writer_connection (connection, + NULL, + FALSE, + &path, + &reread, + NULL, + error)) return NULL; } - return NM_SETTINGS_CONNECTION (update_connection (self, connection, path, NULL, FALSE, NULL, error)); + return NM_SETTINGS_CONNECTION (update_connection (self, reread ?: connection, path, NULL, FALSE, NULL, error)); } static GSList * diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.c b/src/settings/plugins/keyfile/nms-keyfile-reader.c index 39a014802..05aae855a 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-reader.c +++ b/src/settings/plugins/keyfile/nms-keyfile-reader.c @@ -56,6 +56,10 @@ _fmt_warn (const char *group, NMSetting *setting, const char *property_name, con return message; } +typedef struct { + bool verbose; +} HandlerReadData; + static gboolean _handler_read (GKeyFile *keyfile, NMConnection *connection, @@ -64,11 +68,16 @@ _handler_read (GKeyFile *keyfile, void *user_data, GError **error) { + const HandlerReadData *handler_data = user_data; + if (type == NM_KEYFILE_READ_TYPE_WARN) { NMKeyfileReadTypeDataWarn *warn_data = type_data; NMLogLevel level; char *message_free = NULL; + if (!handler_data->verbose) + return TRUE; + if (warn_data->severity > NM_KEYFILE_WARN_SEVERITY_WARN) level = LOGL_ERR; else if (warn_data->severity >= NM_KEYFILE_WARN_SEVERITY_WARN) @@ -89,6 +98,19 @@ _handler_read (GKeyFile *keyfile, } NMConnection * +nms_keyfile_reader_from_keyfile (GKeyFile *key_file, + const char *filename, + gboolean verbose, + GError **error) +{ + HandlerReadData data = { + .verbose = verbose, + }; + + return nm_keyfile_read (key_file, filename, NULL, _handler_read, &data, error); +} + +NMConnection * nms_keyfile_reader_from_file (const char *filename, GError **error) { GKeyFile *key_file; @@ -122,7 +144,7 @@ nms_keyfile_reader_from_file (const char *filename, GError **error) if (!g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, error)) goto out; - connection = nm_keyfile_read (key_file, filename, NULL, _handler_read, NULL, error); + connection = nms_keyfile_reader_from_keyfile (key_file, filename, TRUE, error); if (!connection) goto out; diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.h b/src/settings/plugins/keyfile/nms-keyfile-reader.h index c52fea31d..f8b3fac8f 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-reader.h +++ b/src/settings/plugins/keyfile/nms-keyfile-reader.h @@ -24,6 +24,11 @@ #include <nm-connection.h> +NMConnection *nms_keyfile_reader_from_keyfile (GKeyFile *key_file, + const char *filename, + gboolean verbose, + GError **error); + NMConnection *nms_keyfile_reader_from_file (const char *filename, GError **error); #endif /* __NMS_KEYFILE_READER_H__ */ diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.c b/src/settings/plugins/keyfile/nms-keyfile-writer.c index a67374205..92ed2849b 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-writer.c +++ b/src/settings/plugins/keyfile/nms-keyfile-writer.c @@ -32,6 +32,7 @@ #include "nm-keyfile-internal.h" #include "nms-keyfile-utils.h" +#include "nms-keyfile-reader.h" /*****************************************************************************/ @@ -174,9 +175,11 @@ _internal_write_connection (NMConnection *connection, const char *existing_path, gboolean force_rename, char **out_path, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error) { - GKeyFile *key_file; + gs_unref_keyfile GKeyFile *key_file = NULL; gs_free char *data = NULL; gsize len; gs_free char *path = NULL; @@ -188,8 +191,15 @@ _internal_write_connection (NMConnection *connection, g_return_val_if_fail (!out_path || !*out_path, FALSE); g_return_val_if_fail (keyfile_dir && keyfile_dir[0] == '/', FALSE); - if (!nm_connection_verify (connection, error)) + switch (_nm_connection_verify (connection, error)) { + case NM_SETTING_VERIFY_NORMALIZABLE: + nm_assert_not_reached (); + /* fall-through */ + case NM_SETTING_VERIFY_SUCCESS: + break; + default: g_return_val_if_reached (FALSE); + } id = nm_connection_get_id (connection); g_assert (id && *id); @@ -200,7 +210,6 @@ _internal_write_connection (NMConnection *connection, if (!key_file) return FALSE; data = g_key_file_to_data (key_file, &len, error); - g_key_file_unref (key_file); if (!data) return FALSE; @@ -290,15 +299,48 @@ _internal_write_connection (NMConnection *connection, path = NULL; } + if (out_reread || out_reread_same) + { + gs_unref_object NMConnection *reread = NULL; + gboolean reread_same = FALSE; + + reread = nms_keyfile_reader_from_keyfile (key_file, path, FALSE, NULL); + + nm_assert (NM_IS_CONNECTION (reread)); + + if ( reread + && !nm_connection_normalize (reread, NULL, NULL, NULL)) { + nm_assert_not_reached (); + g_clear_object (&reread); + } + + if (reread && out_reread_same) { + reread_same = !!nm_connection_compare (reread, connection, NM_SETTING_COMPARE_FLAG_EXACT); + + nm_assert (reread_same == nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT)); + nm_assert (reread_same == ({ + gs_unref_hashtable GHashTable *_settings = NULL; + + ( nm_connection_diff (reread, connection, NM_SETTING_COMPARE_FLAG_EXACT, &_settings) + && !_settings); + })); + } + + NM_SET_OUT (out_reread, g_steal_pointer (&reread)); + NM_SET_OUT (out_reread_same, reread_same); + } + return TRUE; } gboolean nms_keyfile_writer_connection (NMConnection *connection, - const char *existing_path, - gboolean force_rename, - char **out_path, - GError **error) + const char *existing_path, + gboolean force_rename, + char **out_path, + NMConnection **out_reread, + gboolean *out_reread_same, + GError **error) { return _internal_write_connection (connection, nms_keyfile_utils_get_path (), @@ -306,16 +348,20 @@ nms_keyfile_writer_connection (NMConnection *connection, existing_path, force_rename, out_path, + out_reread, + out_reread_same, error); } gboolean nms_keyfile_writer_test_connection (NMConnection *connection, - const char *keyfile_dir, - uid_t owner_uid, - pid_t owner_grp, - char **out_path, - GError **error) + const char *keyfile_dir, + uid_t owner_uid, + pid_t owner_grp, + char **out_path, + NMConnection **out_reread, + gboolean *out_reread_same, + GError **error) { return _internal_write_connection (connection, keyfile_dir, @@ -323,6 +369,8 @@ nms_keyfile_writer_test_connection (NMConnection *connection, NULL, FALSE, out_path, + out_reread, + out_reread_same, error); } diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.h b/src/settings/plugins/keyfile/nms-keyfile-writer.h index 4f43455d0..ca2e2a461 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-writer.h +++ b/src/settings/plugins/keyfile/nms-keyfile-writer.h @@ -28,6 +28,8 @@ gboolean nms_keyfile_writer_connection (NMConnection *connection, const char *existing_path, gboolean force_rename, char **out_path, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error); gboolean nms_keyfile_writer_test_connection (NMConnection *connection, @@ -35,6 +37,8 @@ gboolean nms_keyfile_writer_test_connection (NMConnection *connection, uid_t owner_uid, pid_t owner_grp, char **out_path, + NMConnection **out_reread, + gboolean *out_reread_same, GError **error); #endif /* __NMS_KEYFILE_WRITER_H__ */ diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c index f1102bd32..1d1f5d8cc 100644 --- a/src/settings/plugins/keyfile/tests/test-keyfile.c +++ b/src/settings/plugins/keyfile/tests/test-keyfile.c @@ -113,13 +113,25 @@ assert_reread_and_unlink (NMConnection *connection, gboolean normalize_connectio } static void -write_test_connection (NMConnection *connection, char **testfile) +assert_reread_same (NMConnection *connection, + NMConnection *reread) +{ + nmtst_assert_connection_verifies_without_normalization (reread); + nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); +} + +static void +write_test_connection_reread (NMConnection *connection, + char **testfile, + NMConnection **out_reread, + gboolean *out_reread_same) { uid_t owner_uid; gid_t owner_grp; gboolean success; GError *error = NULL; GError **p_error = (nmtst_get_rand_int () % 2) ? &error : NULL; + gs_unref_object NMConnection *connection_normalized = NULL; g_assert (NM_IS_CONNECTION (connection)); g_assert (testfile && !*testfile); @@ -127,13 +139,33 @@ write_test_connection (NMConnection *connection, char **testfile) owner_uid = geteuid (); owner_grp = getegid (); - success = nms_keyfile_writer_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, testfile, p_error); + connection_normalized = nmtst_connection_duplicate_and_normalize (connection); + + success = nms_keyfile_writer_test_connection (connection_normalized, + TEST_SCRATCH_DIR, + owner_uid, + owner_grp, + testfile, + out_reread, + out_reread_same, + p_error); g_assert_no_error (error); g_assert (success); g_assert (*testfile && (*testfile)[0]); } static void +write_test_connection (NMConnection *connection, char **testfile) +{ + gs_unref_object NMConnection *reread = NULL; + gboolean reread_same = FALSE; + + write_test_connection_reread (connection, testfile, &reread, &reread_same); + assert_reread_same (connection, reread); + g_assert (reread_same); +} + +static void write_test_connection_and_reread (NMConnection *connection, gboolean normalize_connection) { gs_free char *testfile = NULL; @@ -161,6 +193,27 @@ keyfile_load_from_file (const char *testfile) return keyfile; } +static void +_setting_copy_property_gbytes (NMConnection *src, NMConnection *dst, const char *setting_name, const char *property_name) +{ + gs_unref_bytes GBytes *blob = NULL; + NMSetting *s_src; + NMSetting *s_dst; + + g_assert (NM_IS_CONNECTION (src)); + g_assert (NM_IS_CONNECTION (dst)); + g_assert (setting_name); + g_assert (property_name); + + s_src = nm_connection_get_setting_by_name (src, setting_name); + g_assert (NM_IS_SETTING (s_src)); + s_dst = nm_connection_get_setting_by_name (dst, setting_name); + g_assert (NM_IS_SETTING (s_dst)); + + g_object_get (s_src, property_name, &blob, NULL); + g_object_set (s_dst, property_name, blob, NULL); +} + /*****************************************************************************/ static void @@ -1639,11 +1692,18 @@ test_write_wired_8021x_tls_connection_path (void) gs_free_error GError *error = NULL; gs_unref_keyfile GKeyFile *keyfile = NULL; gboolean relative = FALSE; + gboolean reread_same = FALSE; connection = create_wired_tls_connection (NM_SETTING_802_1X_CK_SCHEME_PATH); g_assert (connection != NULL); - write_test_connection (connection, &testfile); + write_test_connection_reread (connection, &testfile, &reread, &reread_same); + nmtst_assert_connection_verifies_without_normalization (reread); + _setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CA_CERT); + _setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CLIENT_CERT); + _setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PRIVATE_KEY); + assert_reread_same (connection, reread); + g_clear_object (&reread); /* Read the connection back in and compare it to the one we just wrote out */ reread = nms_keyfile_reader_from_file (testfile, &error); @@ -1716,6 +1776,7 @@ test_write_wired_8021x_tls_connection_blob (void) char *new_client_cert; char *new_priv_key; const char *uuid; + gboolean reread_same = FALSE; gs_free_error GError *error = NULL; GBytes *password_raw = NULL; #define PASSWORD_RAW "password-raw\0test" @@ -1733,7 +1794,13 @@ test_write_wired_8021x_tls_connection_blob (void) NULL); g_bytes_unref (password_raw); - write_test_connection (connection, &testfile); + write_test_connection_reread (connection, &testfile, &reread, &reread_same); + nmtst_assert_connection_verifies_without_normalization (reread); + _setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CA_CERT); + _setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CLIENT_CERT); + _setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PRIVATE_KEY); + assert_reread_same (connection, reread); + g_clear_object (&reread); /* Check that the new certs got written out */ s_con = nm_connection_get_setting_connection (connection); |