diff options
author | Thomas Haller <thaller@redhat.com> | 2021-06-04 09:47:30 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2021-06-04 09:47:30 +0200 |
commit | 0d928c670d28a3e9f3fa19cb5a91414cafa1daa8 (patch) | |
tree | f4e54483cd7c8f0b1dc810e359b11c57b565d576 | |
parent | 74f9272d3d9e277b796c3360dbac7f5e4a352bd0 (diff) | |
parent | 3699c31eb16377415069efa475ad61561017fa56 (diff) | |
download | NetworkManager-0d928c670d28a3e9f3fa19cb5a91414cafa1daa8.tar.gz |
all: merge branch 'th/uuid-normalize'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/880
-rw-r--r-- | src/core/settings/nm-settings-storage.c | 5 | ||||
-rw-r--r-- | src/core/settings/nm-settings-storage.h | 6 | ||||
-rw-r--r-- | src/core/settings/nm-settings.c | 9 | ||||
-rw-r--r-- | src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c | 3 | ||||
-rw-r--r-- | src/core/settings/plugins/keyfile/nms-keyfile-plugin.c | 7 | ||||
-rw-r--r-- | src/core/settings/plugins/keyfile/nms-keyfile-storage.c | 5 | ||||
-rw-r--r-- | src/core/settings/plugins/keyfile/nms-keyfile-utils.c | 26 | ||||
-rw-r--r-- | src/libnm-core-impl/nm-connection-private.h | 2 | ||||
-rw-r--r-- | src/libnm-core-impl/nm-connection.c | 110 | ||||
-rw-r--r-- | src/libnm-core-impl/nm-setting-connection.c | 111 | ||||
-rw-r--r-- | src/libnm-core-impl/nm-setting-match.c | 49 | ||||
-rw-r--r-- | src/libnm-core-impl/tests/test-general.c | 4 | ||||
-rw-r--r-- | src/libnm-core-impl/tests/test-setting.c | 120 | ||||
-rw-r--r-- | src/libnm-core-intern/nm-core-internal.h | 4 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-shared-utils.c | 30 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-shared-utils.h | 80 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-uuid.c | 6 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-uuid.h | 12 |
18 files changed, 470 insertions, 119 deletions
diff --git a/src/core/settings/nm-settings-storage.c b/src/core/settings/nm-settings-storage.c index c56ba075de..e284b822a8 100644 --- a/src/core/settings/nm-settings-storage.c +++ b/src/core/settings/nm-settings-storage.c @@ -7,6 +7,7 @@ #include "nm-settings-storage.h" +#include "libnm-glib-aux/nm-uuid.h" #include "nm-utils.h" #include "nm-settings-plugin.h" @@ -72,7 +73,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps case PROP_UUID: /* construct-only */ self->_uuid = g_value_dup_string(value); - nm_assert(!self->_uuid || nm_utils_is_uuid(self->_uuid)); + nm_assert(!self->_uuid || nm_uuid_is_normalized(self->_uuid)); break; case PROP_FILENAME: /* construct-only */ @@ -97,7 +98,7 @@ NMSettingsStorage * nm_settings_storage_new(NMSettingsPlugin *plugin, const char *uuid, const char *filename) { nm_assert(NM_IS_SETTINGS_PLUGIN(plugin)); - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); return g_object_new(NM_TYPE_SETTINGS_STORAGE, NM_SETTINGS_STORAGE_PLUGIN, diff --git a/src/core/settings/nm-settings-storage.h b/src/core/settings/nm-settings-storage.h index d873a485bd..2e5e1c5579 100644 --- a/src/core/settings/nm-settings-storage.h +++ b/src/core/settings/nm-settings-storage.h @@ -60,14 +60,14 @@ nm_settings_storage_get_plugin(const NMSettingsStorage *self) return self->_plugin; } -gboolean nm_uuid_is_valid_full(const char *str); +gboolean nm_uuid_is_normalized_full(const char *str); static inline const char * nm_settings_storage_get_uuid(const NMSettingsStorage *self) { g_return_val_if_fail(NM_IS_SETTINGS_STORAGE(self), NULL); - nm_assert(nm_uuid_is_valid_full(self->_uuid)); + nm_assert(nm_uuid_is_normalized_full(self->_uuid)); return self->_uuid; } @@ -76,7 +76,7 @@ nm_settings_storage_get_uuid_opt(const NMSettingsStorage *self) { g_return_val_if_fail(NM_IS_SETTINGS_STORAGE(self), NULL); - nm_assert(!self->_uuid || nm_uuid_is_valid_full(self->_uuid)); + nm_assert(!self->_uuid || nm_uuid_is_normalized_full(self->_uuid)); return self->_uuid; } diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c index 1b1bfda88f..36a357748e 100644 --- a/src/core/settings/nm-settings.c +++ b/src/core/settings/nm-settings.c @@ -21,6 +21,7 @@ #endif #include "libnm-core-aux-intern/nm-common-macros.h" +#include "libnm-glib-aux/nm-uuid.h" #include "libnm-glib-aux/nm-keyfile-aux.h" #include "libnm-core-intern/nm-keyfile-internal.h" #include "nm-dbus-interface.h" @@ -139,7 +140,7 @@ nm_assert_storage_data_lst(CList *head) u = nm_settings_storage_get_uuid(sd->storage); if (!uuid) { uuid = u; - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); } else nm_assert(nm_streq0(uuid, u)); } @@ -182,7 +183,7 @@ _sett_conn_entry_new(const char *uuid) SettConnEntry *sett_conn_entry; gsize l_p_1; - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); l_p_1 = strlen(uuid) + 1; @@ -1461,7 +1462,7 @@ _add_connection_to_first_plugin(NMSettings * self, uuid = nm_connection_get_uuid(new_connection); - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); for (iter = priv->plugins; iter; iter = iter->next) { NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN(iter->data); @@ -2295,7 +2296,7 @@ nm_settings_delete_connection(NMSettings * self, nm_assert(NM_IS_SETTINGS_STORAGE(cur_storage)); uuid = nm_settings_storage_get_uuid(cur_storage); - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); sett_conn_entry = _sett_conn_entries_get(self, uuid); diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c index 714357a8be..134bdf6844 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c @@ -7,6 +7,7 @@ #include "nms-ifcfg-rh-storage.h" +#include "libnm-glib-aux/nm-uuid.h" #include "nm-utils.h" #include "libnm-core-intern/nm-core-internal.h" #include "nm-connection.h" @@ -88,7 +89,7 @@ static NMSIfcfgRHStorage * _storage_new(NMSIfcfgRHPlugin *plugin, const char *uuid, const char *filename) { nm_assert(NMS_IS_IFCFG_RH_PLUGIN(plugin)); - nm_assert(!uuid || nm_utils_is_uuid(uuid)); + nm_assert(!uuid || nm_uuid_is_normalized(uuid)); nm_assert(filename && filename[0] == '/'); return g_object_new(NMS_TYPE_IFCFG_RH_STORAGE, diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c index 5f7f26e58e..e8ae1814d8 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c +++ b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c @@ -15,6 +15,7 @@ #include "libnm-std-aux/c-list-util.h" #include "libnm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-uuid.h" #include "libnm-glib-aux/nm-io-utils.h" #include "nm-connection.h" @@ -233,7 +234,7 @@ _read_from_file(const char * full_filename, nm_assert(!connection || (_nm_connection_verify(connection, NULL) == NM_SETTING_VERIFY_SUCCESS)); - nm_assert(!connection || nm_utils_is_uuid(nm_connection_get_uuid(connection))); + nm_assert(!connection || nm_uuid_is_normalized(nm_connection_get_uuid(connection))); return connection; } @@ -260,7 +261,7 @@ _nm_assert_storage(gpointer plugin /* NMSKeyfilePlugin */, uuid = nms_keyfile_storage_get_uuid(storage); - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); nm_assert(((NMSKeyfileStorage *) storage)->is_meta_data || !(((NMSKeyfileStorage *) storage)->u.conn_data.connection) @@ -1106,7 +1107,7 @@ nms_keyfile_plugin_set_nmmeta_tombstone(NMSKeyfilePlugin * self, const char * dirname; nm_assert(NMS_IS_KEYFILE_PLUGIN(self)); - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); nm_assert(!out_storage || !*out_storage); nm_assert(!shadowed_storage || (set && in_memory)); diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-storage.c b/src/core/settings/plugins/keyfile/nms-keyfile-storage.c index c6b4b81f57..8c526c81b4 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-storage.c +++ b/src/core/settings/plugins/keyfile/nms-keyfile-storage.c @@ -7,6 +7,7 @@ #include "nms-keyfile-storage.h" +#include "libnm-glib-aux/nm-uuid.h" #include "nm-utils.h" #include "libnm-core-intern/nm-core-internal.h" #include "nms-keyfile-plugin.h" @@ -108,7 +109,7 @@ _storage_new(NMSKeyfilePlugin * plugin, NMSKeyfileStorage *self; nm_assert(NMS_IS_KEYFILE_PLUGIN(plugin)); - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); nm_assert(filename && filename[0] == '/'); self = g_object_new(NMS_TYPE_KEYFILE_STORAGE, @@ -135,7 +136,7 @@ nms_keyfile_storage_new_tombstone(NMSKeyfilePlugin * plugin, { NMSKeyfileStorage *self; - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); nm_assert(filename && filename[0] == '/'); nm_assert(nms_keyfile_nmmeta_check_filename(filename, NULL)); nm_assert(NM_IN_SET(storage_type, NMS_KEYFILE_STORAGE_TYPE_ETC, NMS_KEYFILE_STORAGE_TYPE_RUN)); diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-utils.c b/src/core/settings/plugins/keyfile/nms-keyfile-utils.c index affe1c3d2a..e2c68bbecc 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-utils.c +++ b/src/core/settings/plugins/keyfile/nms-keyfile-utils.c @@ -10,6 +10,7 @@ #include <stdlib.h> #include <sys/stat.h> +#include "libnm-glib-aux/nm-uuid.h" #include "libnm-glib-aux/nm-io-utils.h" #include "libnm-core-intern/nm-keyfile-internal.h" #include "nm-utils.h" @@ -30,9 +31,9 @@ const char * nms_keyfile_nmmeta_check_filename(const char *filename, guint *out_uuid_len) { - const char *uuid; const char *s; gsize len; + char uuid[37]; s = strrchr(filename, '/'); if (s) @@ -50,17 +51,18 @@ nms_keyfile_nmmeta_check_filename(const char *filename, guint *out_uuid_len) len -= NM_STRLEN(NM_KEYFILE_PATH_SUFFIX_NMMETA); - if (!NM_IN_SET(len, 36, 40)) { + if (len != 36) { /* the remaining part of the filename has not the right length to - * contain a UUID (according to nm_utils_is_uuid()). */ + * contain a UUID (according to nm_uuid_is_normalized()). */ return NULL; } - uuid = nm_strndup_a(100, filename, len, NULL); - if (!nm_utils_is_uuid(uuid)) + memcpy(uuid, filename, 36); + uuid[36] = '\0'; + if (!nm_uuid_is_normalized(uuid)) return NULL; - NM_SET_OUT(out_uuid_len, len); + NM_SET_OUT(out_uuid_len, 36); return filename; } @@ -71,7 +73,7 @@ nms_keyfile_nmmeta_filename(const char *dirname, const char *uuid, gboolean temp char *s; nm_assert(dirname && dirname[0] == '/'); - nm_assert(nm_utils_is_uuid(uuid) && !strchr(uuid, '/')); + nm_assert(nm_uuid_is_normalized(uuid) && !strchr(uuid, '/')); if (g_snprintf(filename, sizeof(filename), @@ -80,7 +82,7 @@ nms_keyfile_nmmeta_filename(const char *dirname, const char *uuid, gboolean temp NM_KEYFILE_PATH_SUFFIX_NMMETA, temporary ? "~" : "") >= sizeof(filename)) { - /* valid uuids are limited in length (nm_utils_is_uuid). The buffer should always + /* valid uuids are limited in length (nm_uuid_is_normalized). The buffer should always * be large enough. */ nm_assert_not_reached(); } @@ -137,7 +139,11 @@ nms_keyfile_nmmeta_read(const char * dirname, NMMETA_KF_GROUP_NAME_NMMETA, NMMETA_KF_KEY_NAME_NMMETA_UUID, NULL); - if (!nm_streq0(v_uuid, uuid)) + if (!v_uuid) + return FALSE; + if (strncmp(v_uuid, uuid, uuid_len) != 0) + return FALSE; + if (v_uuid[uuid_len] != '\0') return FALSE; loaded_path = g_key_file_get_string(kf, @@ -211,7 +217,7 @@ nms_keyfile_nmmeta_write(const char *dirname, int errsv; nm_assert(dirname && dirname[0] == '/'); - nm_assert(nm_utils_is_uuid(uuid) && !strchr(uuid, '/')); + nm_assert(nm_uuid_is_normalized(uuid) && !strchr(uuid, '/')); nm_assert(!loaded_path || loaded_path[0] == '/'); nm_assert(!shadowed_storage || loaded_path); diff --git a/src/libnm-core-impl/nm-connection-private.h b/src/libnm-core-impl/nm-connection-private.h index 532b17637b..0580625f4a 100644 --- a/src/libnm-core-impl/nm-connection-private.h +++ b/src/libnm-core-impl/nm-connection-private.h @@ -27,6 +27,8 @@ gboolean _nm_connection_detect_slave_type_full(NMSettingConnection *s_con, const char *_nm_connection_detect_bluetooth_type(NMConnection *self); +gboolean _nm_setting_connection_verify_secondaries(GArray *secondaries, GError **error); + gboolean _nm_connection_verify_required_interface_name(NMConnection *connection, GError **error); int _nm_setting_ovs_interface_verify_interface_type(NMSettingOvsInterface *self, diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c index a8435c909c..35a14a80b8 100644 --- a/src/libnm-core-impl/nm-connection.c +++ b/src/libnm-core-impl/nm-connection.c @@ -725,6 +725,113 @@ _normalize_connection_uuid(NMConnection *self) return TRUE; } +gboolean +_nm_setting_connection_verify_secondaries(GArray *secondaries, GError **error) +{ + const char *const *strv; + const guint len = nm_g_array_len(secondaries); + guint has_normalizable = FALSE; + gboolean has_invalid = FALSE; + gboolean has_duplicate = FALSE; + guint i; + + if (len == 0) + return TRUE; + + /* For historic reasons, the secondaries were not normalized/validated. + * + * Now, when we find any invalid/non-normalized values, we reject/normalize + * them. We also filter out duplicates. */ + + strv = nm_strvarray_get_strv_non_empty(secondaries, NULL); + + for (i = 0; i < len; i++) { + const char *uuid = strv[i]; + gboolean normalized; + + if (!nm_uuid_is_valid_nm(uuid, &normalized, NULL)) { + has_invalid = TRUE; + goto out; + } + if (normalized) + has_normalizable = TRUE; + } + if (has_normalizable) + goto out; + + if (len > 1) { + gs_free const char **strv_to_free = NULL; + const char ** strv2; + + strv2 = nm_utils_strv_dup_shallow_maybe_a(20, strv, len, &strv_to_free); + nm_utils_strv_sort(strv2, len); + has_duplicate = nm_strv_has_duplicate(strv2, len, TRUE); + } + +out: + if (has_invalid) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("has an invalid UUID")); + } else if (has_normalizable) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("has a UUID that requires normalization")); + } else if (has_duplicate) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("has duplicate UUIDs")); + } else + return TRUE; + + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_SECONDARIES); + return FALSE; +} + +static gboolean +_normalize_connection_secondaries(NMConnection *self) +{ + NMSettingConnection *s_con = nm_connection_get_setting_connection(self); + GArray * secondaries; + gs_strfreev char ** strv = NULL; + guint i; + guint j; + + nm_assert(s_con); + + secondaries = _nm_setting_connection_get_secondaries(s_con); + if (nm_g_array_len(secondaries) == 0) + return FALSE; + + if (_nm_setting_connection_verify_secondaries(secondaries, NULL)) + return FALSE; + + strv = nm_strvarray_get_strv_non_empty_dup(secondaries, NULL); + for (i = 0, j = 0; strv[i]; i++) { + gs_free char *s = g_steal_pointer(&strv[i]); + char uuid_normalized[37]; + gboolean uuid_is_normalized; + + if (!nm_uuid_is_valid_nm(s, &uuid_is_normalized, uuid_normalized)) + continue; + + if (nm_utils_strv_find_first(strv, j, uuid_is_normalized ? uuid_normalized : s) >= 0) + continue; + + strv[j++] = uuid_is_normalized ? g_strdup(uuid_normalized) : g_steal_pointer(&s); + } + strv[j] = NULL; + + g_object_set(s_con, NM_SETTING_CONNECTION_SECONDARIES, strv, NULL); + return TRUE; +} + static gboolean _normalize_connection_type(NMConnection *self) { @@ -1617,6 +1724,7 @@ _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_connection_secondaries(connection); was_modified |= _normalize_required_settings(connection); was_modified |= _normalize_invalid_slave_port_settings(connection); was_modified |= _normalize_ip_config(connection, parameters); @@ -1740,7 +1848,7 @@ _nm_connection_ensure_normalized(NMConnection * connection, nm_assert(NM_IS_CONNECTION(connection)); nm_assert(!out_connection_clone || !*out_connection_clone); - nm_assert(!expected_uuid || nm_utils_is_uuid(expected_uuid)); + nm_assert(!expected_uuid || nm_uuid_is_normalized(expected_uuid)); if (expected_uuid) { if (nm_streq0(expected_uuid, nm_connection_get_uuid(connection))) diff --git a/src/libnm-core-impl/nm-setting-connection.c b/src/libnm-core-impl/nm-setting-connection.c index 8693c85363..110f2937b0 100644 --- a/src/libnm-core-impl/nm-setting-connection.c +++ b/src/libnm-core-impl/nm-setting-connection.c @@ -70,26 +70,26 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingConnection, PROP_MUD_URL, ); typedef struct { - GArray *permissions; - GSList *secondaries; /* secondary connections to activate with the base connection */ - char * id; - char * uuid; - char * stable_id; - char * interface_name; - char * type; - char * master; - char * slave_type; - char * zone; - char * mud_url; - guint64 timestamp; - int autoconnect_priority; - int autoconnect_retries; - int multi_connect; - int auth_retries; - int mdns; - int llmnr; - int wait_device_timeout; - guint gateway_ping_timeout; + GArray * permissions; + GArray * secondaries; + char * id; + char * uuid; + char * stable_id; + char * interface_name; + char * type; + char * master; + char * slave_type; + char * zone; + char * mud_url; + guint64 timestamp; + int autoconnect_priority; + int autoconnect_retries; + int multi_connect; + int auth_retries; + int mdns; + int llmnr; + int wait_device_timeout; + guint gateway_ping_timeout; NMSettingConnectionAutoconnectSlaves autoconnect_slaves; NMMetered metered; NMSettingConnectionLldp lldp; @@ -741,6 +741,12 @@ nm_setting_connection_get_autoconnect_slaves(NMSettingConnection *setting) return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->autoconnect_slaves; } +GArray * +_nm_setting_connection_get_secondaries(NMSettingConnection *setting) +{ + return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->secondaries; +} + /** * nm_setting_connection_get_num_secondaries: * @setting: the #NMSettingConnection @@ -752,27 +758,37 @@ nm_setting_connection_get_num_secondaries(NMSettingConnection *setting) { g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), 0); - return g_slist_length(NM_SETTING_CONNECTION_GET_PRIVATE(setting)->secondaries); + return nm_g_array_len(NM_SETTING_CONNECTION_GET_PRIVATE(setting)->secondaries); } /** * nm_setting_connection_get_secondary: * @setting: the #NMSettingConnection - * @idx: the zero-based index of the secondary connection UUID entry + * @idx: the zero-based index of the secondary connection UUID entry. + * Access one past the length of secondaries is ok and will return + * %NULL. Otherwise, it is a user error. * - * Returns: the secondary connection UUID at index @idx + * Returns: the secondary connection UUID at index @idx or + * %NULL if @idx is the number of secondaries. **/ const char * nm_setting_connection_get_secondary(NMSettingConnection *setting, guint32 idx) { NMSettingConnectionPrivate *priv; + guint secondaries_len; g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), NULL); priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting); - g_return_val_if_fail(idx <= g_slist_length(priv->secondaries), NULL); - return (const char *) g_slist_nth_data(priv->secondaries, idx); + secondaries_len = nm_g_array_len(priv->secondaries); + if (idx >= secondaries_len) { + /* access one past the length is OK. */ + g_return_val_if_fail(idx == secondaries_len, NULL); + return NULL; + } + + return nm_strvarray_get_idx(priv->secondaries, idx); } /** @@ -806,19 +822,16 @@ gboolean nm_setting_connection_add_secondary(NMSettingConnection *setting, const char *sec_uuid) { NMSettingConnectionPrivate *priv; - GSList * iter; g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), FALSE); - g_return_val_if_fail(sec_uuid != NULL, FALSE); - g_return_val_if_fail(sec_uuid[0] != '\0', FALSE); + g_return_val_if_fail(sec_uuid, FALSE); priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting); - for (iter = priv->secondaries; iter; iter = g_slist_next(iter)) { - if (!strcmp(sec_uuid, (char *) iter->data)) - return FALSE; - } - priv->secondaries = g_slist_append(priv->secondaries, g_strdup(sec_uuid)); + if (nm_strvarray_find_first(priv->secondaries, sec_uuid) >= 0) + return FALSE; + + nm_strvarray_add(nm_strvarray_ensure(&priv->secondaries), sec_uuid); _notify(setting, PROP_SECONDARIES); return TRUE; } @@ -834,16 +847,14 @@ void nm_setting_connection_remove_secondary(NMSettingConnection *setting, guint32 idx) { NMSettingConnectionPrivate *priv; - GSList * elt; g_return_if_fail(NM_IS_SETTING_CONNECTION(setting)); priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting); - elt = g_slist_nth(priv->secondaries, idx); - g_return_if_fail(elt != NULL); - g_free(elt->data); - priv->secondaries = g_slist_delete_link(priv->secondaries, elt); + g_return_if_fail(idx < nm_g_array_len(priv->secondaries)); + + g_array_remove_index(priv->secondaries, idx); _notify(setting, PROP_SECONDARIES); } @@ -860,19 +871,15 @@ gboolean nm_setting_connection_remove_secondary_by_value(NMSettingConnection *setting, const char *sec_uuid) { NMSettingConnectionPrivate *priv; - GSList * iter; g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), FALSE); - g_return_val_if_fail(sec_uuid != NULL, FALSE); - g_return_val_if_fail(sec_uuid[0] != '\0', FALSE); + g_return_val_if_fail(sec_uuid, FALSE); priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting); - for (iter = priv->secondaries; iter; iter = g_slist_next(iter)) { - if (!strcmp(sec_uuid, (char *) iter->data)) { - priv->secondaries = g_slist_delete_link(priv->secondaries, iter); - _notify(setting, PROP_SECONDARIES); - return TRUE; - } + + if (nm_strvarray_remove_first(priv->secondaries, sec_uuid)) { + _notify(setting, PROP_SECONDARIES); + return TRUE; } return FALSE; } @@ -1474,6 +1481,9 @@ after_interface_name: return NM_SETTING_VERIFY_NORMALIZABLE; } + if (!_nm_setting_connection_verify_secondaries(priv->secondaries, error)) + return NM_SETTING_VERIFY_NORMALIZABLE; + return TRUE; } @@ -1622,7 +1632,7 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) g_value_set_enum(value, nm_setting_connection_get_autoconnect_slaves(setting)); break; case PROP_SECONDARIES: - g_value_take_boxed(value, _nm_utils_slist_to_strv(priv->secondaries, TRUE)); + g_value_take_boxed(value, nm_strvarray_get_strv_non_empty_dup(priv->secondaries, NULL)); break; case PROP_GATEWAY_PING_TIMEOUT: g_value_set_uint(value, priv->gateway_ping_timeout); @@ -1734,8 +1744,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps priv->autoconnect_slaves = g_value_get_enum(value); break; case PROP_SECONDARIES: - g_slist_free_full(priv->secondaries, g_free); - priv->secondaries = _nm_utils_strv_to_slist(g_value_get_boxed(value), TRUE); + nm_strvarray_set_strv(&priv->secondaries, g_value_get_boxed(value)); break; case PROP_GATEWAY_PING_TIMEOUT: priv->gateway_ping_timeout = g_value_get_uint(value); @@ -1814,7 +1823,7 @@ finalize(GObject *object) g_free(priv->slave_type); g_free(priv->mud_url); nm_clear_pointer(&priv->permissions, g_array_unref); - g_slist_free_full(priv->secondaries, g_free); + nm_clear_pointer(&priv->secondaries, g_array_unref); G_OBJECT_CLASS(nm_setting_connection_parent_class)->finalize(object); } diff --git a/src/libnm-core-impl/nm-setting-match.c b/src/libnm-core-impl/nm-setting-match.c index 9efca1e817..e4f7c1a810 100644 --- a/src/libnm-core-impl/nm-setting-match.c +++ b/src/libnm-core-impl/nm-setting-match.c @@ -80,7 +80,7 @@ nm_setting_match_get_interface_name(NMSettingMatch *setting, int idx) g_return_val_if_fail(setting->interface_name && idx >= 0 && idx < setting->interface_name->len, NULL); - return g_array_index(setting->interface_name, const char *, idx); + return nm_strvarray_get_idx(setting->interface_name, idx); } /** @@ -96,8 +96,7 @@ void nm_setting_match_add_interface_name(NMSettingMatch *setting, const char *interface_name) { g_return_if_fail(NM_IS_SETTING_MATCH(setting)); - g_return_if_fail(interface_name != NULL); - g_return_if_fail(interface_name[0] != '\0'); + g_return_if_fail(interface_name); nm_strvarray_add(nm_strvarray_ensure(&setting->interface_name), interface_name); _notify(setting, PROP_INTERFACE_NAME); @@ -138,8 +137,7 @@ gboolean nm_setting_match_remove_interface_name_by_value(NMSettingMatch *setting, const char *interface_name) { g_return_val_if_fail(NM_IS_SETTING_MATCH(setting), FALSE); - g_return_val_if_fail(interface_name != NULL, FALSE); - g_return_val_if_fail(interface_name[0] != '\0', FALSE); + g_return_val_if_fail(interface_name, FALSE); if (nm_strvarray_remove_first(setting->interface_name, interface_name)) { _notify(setting, PROP_INTERFACE_NAME); @@ -225,7 +223,7 @@ nm_setting_match_get_kernel_command_line(NMSettingMatch *setting, guint idx) g_return_val_if_fail(setting->kernel_command_line && idx < setting->kernel_command_line->len, NULL); - return g_array_index(setting->kernel_command_line, const char *, idx); + return nm_strvarray_get_idx(setting->kernel_command_line, idx); } /** @@ -241,8 +239,7 @@ void nm_setting_match_add_kernel_command_line(NMSettingMatch *setting, const char *kernel_command_line) { g_return_if_fail(NM_IS_SETTING_MATCH(setting)); - g_return_if_fail(kernel_command_line != NULL); - g_return_if_fail(kernel_command_line[0] != '\0'); + g_return_if_fail(kernel_command_line); nm_strvarray_add(nm_strvarray_ensure(&setting->kernel_command_line), kernel_command_line); _notify(setting, PROP_KERNEL_COMMAND_LINE); @@ -284,8 +281,7 @@ nm_setting_match_remove_kernel_command_line_by_value(NMSettingMatch *setting, const char * kernel_command_line) { g_return_val_if_fail(NM_IS_SETTING_MATCH(setting), FALSE); - g_return_val_if_fail(kernel_command_line != NULL, FALSE); - g_return_val_if_fail(kernel_command_line[0] != '\0', FALSE); + g_return_val_if_fail(kernel_command_line, FALSE); if (nm_strvarray_remove_first(setting->kernel_command_line, kernel_command_line)) { _notify(setting, PROP_KERNEL_COMMAND_LINE); @@ -367,7 +363,7 @@ nm_setting_match_get_driver(NMSettingMatch *setting, guint idx) g_return_val_if_fail(setting->driver && idx < setting->driver->len, NULL); - return g_array_index(setting->driver, const char *, idx); + return nm_strvarray_get_idx(setting->driver, idx); } /** @@ -383,8 +379,7 @@ void nm_setting_match_add_driver(NMSettingMatch *setting, const char *driver) { g_return_if_fail(NM_IS_SETTING_MATCH(setting)); - g_return_if_fail(driver != NULL); - g_return_if_fail(driver[0] != '\0'); + g_return_if_fail(driver); nm_strvarray_add(nm_strvarray_ensure(&setting->driver), driver); _notify(setting, PROP_DRIVER); @@ -425,8 +420,7 @@ gboolean nm_setting_match_remove_driver_by_value(NMSettingMatch *setting, const char *driver) { g_return_val_if_fail(NM_IS_SETTING_MATCH(setting), FALSE); - g_return_val_if_fail(driver != NULL, FALSE); - g_return_val_if_fail(driver[0] != '\0', FALSE); + g_return_val_if_fail(driver, FALSE); if (nm_strvarray_remove_first(setting->driver, driver)) { _notify(setting, PROP_DRIVER); @@ -508,7 +502,7 @@ nm_setting_match_get_path(NMSettingMatch *setting, guint idx) g_return_val_if_fail(setting->path && idx < setting->path->len, NULL); - return g_array_index(setting->path, const char *, idx); + return nm_strvarray_get_idx(setting->path, idx); } /** @@ -524,8 +518,7 @@ void nm_setting_match_add_path(NMSettingMatch *setting, const char *path) { g_return_if_fail(NM_IS_SETTING_MATCH(setting)); - g_return_if_fail(path != NULL); - g_return_if_fail(path[0] != '\0'); + g_return_if_fail(path); nm_strvarray_add(nm_strvarray_ensure(&setting->path), path); _notify(setting, PROP_PATH); @@ -566,8 +559,7 @@ gboolean nm_setting_match_remove_path_by_value(NMSettingMatch *setting, const char *path) { g_return_val_if_fail(NM_IS_SETTING_MATCH(setting), FALSE); - g_return_val_if_fail(path != NULL, FALSE); - g_return_val_if_fail(path[0] != '\0', FALSE); + g_return_val_if_fail(path, FALSE); if (nm_strvarray_remove_first(setting->path, path)) { _notify(setting, PROP_PATH); @@ -624,16 +616,17 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) switch (prop_id) { case PROP_INTERFACE_NAME: - g_value_set_boxed(value, nm_strvarray_get_strv_non_empty(self->interface_name, NULL)); + g_value_take_boxed(value, nm_strvarray_get_strv_non_empty_dup(self->interface_name, NULL)); break; case PROP_KERNEL_COMMAND_LINE: - g_value_set_boxed(value, nm_strvarray_get_strv_non_empty(self->kernel_command_line, NULL)); + g_value_take_boxed(value, + nm_strvarray_get_strv_non_empty_dup(self->kernel_command_line, NULL)); break; case PROP_DRIVER: - g_value_set_boxed(value, nm_strvarray_get_strv_non_empty(self->driver, NULL)); + g_value_take_boxed(value, nm_strvarray_get_strv_non_empty_dup(self->driver, NULL)); break; case PROP_PATH: - g_value_set_boxed(value, nm_strvarray_get_strv_non_empty(self->path, NULL)); + g_value_take_boxed(value, nm_strvarray_get_strv_non_empty_dup(self->path, NULL)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -707,7 +700,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) if (self->interface_name) { for (i = 0; i < self->interface_name->len; i++) { - if (nm_str_is_empty(g_array_index(self->interface_name, const char *, i))) { + if (nm_str_is_empty(nm_strvarray_get_idx(self->interface_name, i))) { g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -723,7 +716,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) if (self->kernel_command_line) { for (i = 0; i < self->kernel_command_line->len; i++) { - if (nm_str_is_empty(g_array_index(self->kernel_command_line, const char *, i))) { + if (nm_str_is_empty(nm_strvarray_get_idx(self->kernel_command_line, i))) { g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -739,7 +732,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) if (self->driver) { for (i = 0; i < self->driver->len; i++) { - if (nm_str_is_empty(g_array_index(self->driver, const char *, i))) { + if (nm_str_is_empty(nm_strvarray_get_idx(self->driver, i))) { g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -755,7 +748,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) if (self->path) { for (i = 0; i < self->path->len; i++) { - if (nm_str_is_empty(g_array_index(self->path, const char *, i))) { + if (nm_str_is_empty(nm_strvarray_get_idx(self->path, i))) { g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, diff --git a/src/libnm-core-impl/tests/test-general.c b/src/libnm-core-impl/tests/test-general.c index c911f0ec2c..f9cc5e54e4 100644 --- a/src/libnm-core-impl/tests/test-general.c +++ b/src/libnm-core-impl/tests/test-general.c @@ -5060,7 +5060,7 @@ test_setting_connection_changed_signal(void) ASSERT_CHANGED(nm_setting_connection_add_secondary(s_con, uuid)); ASSERT_CHANGED(nm_setting_connection_remove_secondary(s_con, 0)); - NMTST_EXPECT_LIBNM_CRITICAL(NMTST_G_RETURN_MSG(elt != NULL)); + NMTST_EXPECT_LIBNM_CRITICAL(NMTST_G_RETURN_MSG(idx < nm_g_array_len(priv->secondaries))); ASSERT_UNCHANGED(nm_setting_connection_remove_secondary(s_con, 1)); g_test_assert_expected_messages(); @@ -7788,7 +7788,7 @@ static void __test_uuid(const char *expected_uuid, const char *str, gssize slen, char *uuid_test) { g_assert(uuid_test); - g_assert(nm_utils_is_uuid(uuid_test)); + g_assert(nm_uuid_is_normalized(uuid_test)); if (strcmp(uuid_test, expected_uuid)) { g_error("UUID test failed (1): text=%s, len=%lld, expected=%s, uuid_test=%s", diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index 8b1b358279..f4b9b7cb48 100644 --- a/src/libnm-core-impl/tests/test-setting.c +++ b/src/libnm-core-impl/tests/test-setting.c @@ -4465,6 +4465,123 @@ test_setting_metadata(void) /*****************************************************************************/ +static void +test_setting_connection_secondaries_verify(void) +{ + gs_unref_object NMConnection *con = NULL; + NMSettingConnection * s_con; + guint i_run; + guint i_word; + + con = nmtst_create_minimal_connection("test-sec", NULL, NM_SETTING_WIRED_SETTING_NAME, &s_con); + nmtst_connection_normalize(con); + + for (i_run = 0; i_run < 100; i_run++) { + guint word_len = nmtst_get_rand_word_length(NULL); + gs_unref_ptrarray GPtrArray *arr = NULL; + gs_unref_ptrarray GPtrArray *arr_norm = NULL; + gboolean was_normalized; + gboolean was_normalized2; + + /* create a random list of invalid, normalizable and normalized UUIDs. */ + arr = g_ptr_array_new(); + for (i_word = 0; i_word < word_len; i_word++) { + g_ptr_array_add(arr, + (char *) nmtst_rand_select((const char *) "", + "52c3feb9-3aa2-46f6-a07b-1765918699eb", + "52C3feb9-3aa2-46f6-a07b-1765918699eb", + "52C3feb9-3aa2-46f6-a07b-1765918699eb", + "f86dfb13df764894ab3836b7cdb9d82dde8b27c4", + "52C3feb93-aa2-46f6-a07b-1765918699eb", + "bogus")); + } + g_ptr_array_add(arr, NULL); + + /* set the new list of secondaries, and assert that the result is as expected. */ + + nmtst_assert_connection_verifies_without_normalization(con); + + g_object_set(s_con, NM_SETTING_CONNECTION_SECONDARIES, arr->pdata, NULL); + +#define _assert_secondaries(s_con, expected) \ + G_STMT_START \ + { \ + NMSettingConnection *const _s_con = (s_con); \ + const char *const * _expected = (expected); \ + GArray * _secondaries; \ + const guint _expected_len = NM_PTRARRAY_LEN(_expected); \ + gs_strfreev char ** _sec_strv = NULL; \ + guint _i; \ + \ + g_assert(_expected); \ + \ + if (nmtst_get_rand_bool()) { \ + _secondaries = _nm_setting_connection_get_secondaries(_s_con); \ + g_assert_cmpint(_expected_len, ==, nm_g_array_len(_secondaries)); \ + g_assert((_expected_len == 0) == (!_secondaries)); \ + g_assert(nm_utils_strv_equal(_expected, nm_strvarray_get_strv(&_secondaries, NULL))); \ + } \ + \ + if (nmtst_get_rand_bool()) { \ + g_object_get(_s_con, NM_SETTING_CONNECTION_SECONDARIES, &_sec_strv, NULL); \ + g_assert_cmpint(_expected_len, ==, NM_PTRARRAY_LEN(_sec_strv)); \ + g_assert((_expected_len == 0) == (!_sec_strv)); \ + g_assert(nm_utils_strv_equal(_expected, _sec_strv ?: NM_STRV_EMPTY())); \ + } \ + \ + g_assert_cmpint(nm_setting_connection_get_num_secondaries(_s_con), ==, _expected_len); \ + if (nmtst_get_rand_bool()) { \ + for (_i = 0; _i < _expected_len; _i++) { \ + g_assert_cmpstr(nm_setting_connection_get_secondary(_s_con, _i), \ + ==, \ + _expected[_i]); \ + } \ + g_assert_null(nm_setting_connection_get_secondary(_s_con, _expected_len)); \ + } \ + } \ + G_STMT_END + + _assert_secondaries(s_con, (const char *const *) arr->pdata); + + /* reimplement the normalization that we expect to happen and + * create an array @arr_norm with the expected result after normalization. */ + arr_norm = g_ptr_array_new_with_free_func(g_free); + for (i_word = 0; i_word < word_len; i_word++) { + const char *s = arr->pdata[i_word]; + gboolean is_normalized; + char uuid_normalized[37]; + + if (!nm_uuid_is_valid_nm(s, &is_normalized, uuid_normalized)) + continue; + + if (is_normalized) + s = uuid_normalized; + + if (nm_utils_strv_find_first((char **) arr_norm->pdata, arr_norm->len, s) >= 0) + continue; + + g_ptr_array_add(arr_norm, g_strdup(s)); + } + g_ptr_array_add(arr_norm, NULL); + + was_normalized = !nm_utils_strv_equal((char **) arr->pdata, (char **) arr_norm->pdata); + + if (was_normalized) + nmtst_assert_connection_verifies_and_normalizable(con); + else + nmtst_assert_connection_verifies_without_normalization(con); + + if (was_normalized || nmtst_get_rand_bool()) { + was_normalized2 = nmtst_connection_normalize(con); + g_assert(was_normalized == was_normalized2); + } + + _assert_secondaries(s_con, (const char *const *) arr_norm->pdata); + } +} + +/*****************************************************************************/ + NMTST_DEFINE(); int @@ -4483,6 +4600,9 @@ main(int argc, char **argv) test_8021x); g_test_add_data_func("/libnm/setting-8021x/pkcs12", "test-cert.p12, test", test_8021x); + g_test_add_func("/libnm/settings/test_setting_connection_secondaries_verify", + test_setting_connection_secondaries_verify); + g_test_add_func("/libnm/settings/bond/verify", test_bond_verify); g_test_add_func("/libnm/settings/bond/compare", test_bond_compare); g_test_add_func("/libnm/settings/bond/normalize", test_bond_normalize); diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index d4e7bf4e38..d01e432c68 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -515,6 +515,10 @@ GPtrArray *_nm_setting_bridge_port_get_vlans(NMSettingBridgePort *setting); /*****************************************************************************/ +GArray *_nm_setting_connection_get_secondaries(NMSettingConnection *setting); + +/*****************************************************************************/ + NMSettingBluetooth *_nm_connection_get_setting_bluetooth_for_nap(NMConnection *connection); /*****************************************************************************/ diff --git a/src/libnm-glib-aux/nm-shared-utils.c b/src/libnm-glib-aux/nm-shared-utils.c index 626956aefa..0cac64b5d1 100644 --- a/src/libnm-glib-aux/nm-shared-utils.c +++ b/src/libnm-glib-aux/nm-shared-utils.c @@ -2290,6 +2290,36 @@ nm_utils_strv_find_first(char **list, gssize len, const char *needle) return -1; } +gboolean +nm_strv_has_duplicate(const char *const *strv, gssize len, gboolean is_sorted) +{ + gsize l; + gsize i; + gsize j; + + l = len < 0 ? NM_PTRARRAY_LEN(strv) : (gsize) len; + + if (is_sorted) { +#if NM_MORE_ASSERTS > 10 + for (i = 1; i < l; i++) + nm_assert(nm_strcmp0(strv[i - 1], strv[i]) <= 0); +#endif + for (i = 1; i < l; i++) { + if (nm_streq0(strv[i - 1], strv[i])) + return TRUE; + } + } else { + for (i = 1; i < l; i++) { + for (j = 0; j < i; j++) { + if (nm_streq0(strv[j], strv[i])) + return TRUE; + } + } + } + + return FALSE; +} + char ** _nm_utils_strv_cleanup(char ** strv, gboolean strip_whitespace, diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h index 4493e73bd5..f2231fefb7 100644 --- a/src/libnm-glib-aux/nm-shared-utils.h +++ b/src/libnm-glib-aux/nm-shared-utils.h @@ -710,6 +710,8 @@ nm_utils_strsplit_set(const char *str, const char *delimiters) gssize nm_utils_strv_find_first(char **list, gssize len, const char *needle); +gboolean nm_strv_has_duplicate(const char *const *list, gssize len, gboolean is_sorted); + char **_nm_utils_strv_cleanup(char ** strv, gboolean strip_whitespace, gboolean skip_empty, @@ -1907,6 +1909,34 @@ const char **_nm_utils_strv_dup_packed(const char *const *strv, gssize len); #define nm_utils_strv_dup_packed(strv, len) _nm_utils_strv_dup_packed(NM_CAST_STRV_CC(strv), (len)) +#define nm_utils_strv_dup_shallow_maybe_a(alloca_maxlen, strv, len, to_free) \ + ({ \ + const char *const *const _strv = NM_CAST_STRV_CC(strv); \ + const gssize _len = (len); \ + const char ** _result = NULL; \ + const char ***const _to_free = (to_free); \ + \ + G_STATIC_ASSERT_EXPR((alloca_maxlen) <= 500u / sizeof(const char *)); \ + G_STATIC_ASSERT_EXPR((alloca_maxlen) > 0u); \ + nm_assert(_to_free && !*_to_free); \ + \ + if (_len >= 0 || _strv) { \ + const gsize _l = (_len < 0) ? NM_PTRARRAY_LEN(_strv) : ((gsize) _len); \ + \ + if (G_LIKELY(_l < (alloca_maxlen))) { \ + _result = g_newa(const char *, _l + 1); \ + } else { \ + _result = g_new(const char *, _l + 1); \ + *_to_free = _result; \ + } \ + if (_l > 0) \ + memcpy(_result, _strv, _l * sizeof(const char *)); \ + _result[_l] = NULL; \ + } \ + \ + _result; \ + }) + /*****************************************************************************/ GSList *nm_utils_g_slist_find_str(const GSList *list, const char *needle); @@ -2717,6 +2747,15 @@ nm_strvarray_add(GArray *array, const char *str) g_array_append_val(array, s); } +static inline const char * +nm_strvarray_get_idx(GArray *array, guint idx) +{ + nm_assert(array); + nm_assert(idx < array->len); + + return g_array_index(array, const char *, idx); +} + static inline const char *const * nm_strvarray_get_strv_non_empty(GArray *arr, guint *length) { @@ -2729,6 +2768,21 @@ nm_strvarray_get_strv_non_empty(GArray *arr, guint *length) return &g_array_index(arr, const char *, 0); } +static inline char ** +nm_strvarray_get_strv_non_empty_dup(GArray *arr, guint *length) +{ + const char *const *strv; + + if (!arr || arr->len == 0) { + NM_SET_OUT(length, 0); + return NULL; + } + + NM_SET_OUT(length, arr->len); + strv = &g_array_index(arr, const char *, 0); + return nm_utils_strv_dup(strv, arr->len, TRUE); +} + static inline const char *const * nm_strvarray_get_strv(GArray **arr, guint *length) { @@ -2756,8 +2810,8 @@ nm_strvarray_set_strv(GArray **array, const char *const *strv) nm_strvarray_add(*array, strv[0]); } -static inline gboolean -nm_strvarray_remove_first(GArray *strv, const char *needle) +static inline gssize +nm_strvarray_find_first(GArray *strv, const char *needle) { guint i; @@ -2765,13 +2819,25 @@ nm_strvarray_remove_first(GArray *strv, const char *needle) if (strv) { for (i = 0; i < strv->len; i++) { - if (nm_streq(needle, g_array_index(strv, const char *, i))) { - g_array_remove_index(strv, i); - return TRUE; - } + if (nm_streq(needle, g_array_index(strv, const char *, i))) + return i; } } - return FALSE; + return -1; +} + +static inline gboolean +nm_strvarray_remove_first(GArray *strv, const char *needle) +{ + gssize idx; + + nm_assert(needle); + + idx = nm_strvarray_find_first(strv, needle); + if (idx < 0) + return FALSE; + g_array_remove_index(strv, idx); + return TRUE; } /*****************************************************************************/ diff --git a/src/libnm-glib-aux/nm-uuid.c b/src/libnm-glib-aux/nm-uuid.c index 977a9e79a9..2c6e218a7c 100644 --- a/src/libnm-glib-aux/nm-uuid.c +++ b/src/libnm-glib-aux/nm-uuid.c @@ -130,13 +130,13 @@ nm_uuid_generate_random(NMUuid *out_uuid) /*****************************************************************************/ gboolean -nm_uuid_is_valid_full(const char *str) +nm_uuid_is_normalized_full(const char *str) { - /* The only reason why this exists is that nm_uuid_is_valid() is an inline function. + /* The only reason why this exists is that nm_uuid_is_normalized() is an inline function. * If you need to forward declare the function, that won't work. * * Usually, you wouldn't use this variant! */ - return nm_uuid_is_valid(str); + return nm_uuid_is_normalized(str); } /*****************************************************************************/ diff --git a/src/libnm-glib-aux/nm-uuid.h b/src/libnm-glib-aux/nm-uuid.h index 0ead364090..10302bd87a 100644 --- a/src/libnm-glib-aux/nm-uuid.h +++ b/src/libnm-glib-aux/nm-uuid.h @@ -33,14 +33,22 @@ gboolean nm_uuid_is_null(const NMUuid *uuid); /*****************************************************************************/ -gboolean nm_uuid_is_valid_full(const char *str); - static inline gboolean nm_uuid_is_valid(const char *str) { return str && nm_uuid_parse_full(str, NULL, NULL); } +gboolean nm_uuid_is_normalized_full(const char *str); + +static inline gboolean +nm_uuid_is_normalized(const char *str) +{ + gboolean is_normalized; + + return str && nm_uuid_parse_full(str, NULL, &is_normalized) && is_normalized; +} + /*****************************************************************************/ gboolean nm_uuid_is_valid_nmlegacy(const char *str); |