diff options
author | Thomas Haller <thaller@redhat.com> | 2019-04-10 15:06:12 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-04-10 15:06:21 +0200 |
commit | ad77eed0d5abfc2a4a042f593c02bfc8cd3c6287 (patch) | |
tree | 5bd723ad960486148912680392d3cd7f01ac7bf9 | |
parent | 3f62c49295d9ced878e49bbd89e5bed7b740d568 (diff) | |
parent | a1425a4c91d2b653dfdeea5972b12262abf251c3 (diff) | |
download | NetworkManager-ad77eed0d5abfc2a4a042f593c02bfc8cd3c6287.tar.gz |
all: merge branch 'th/strsplit'
https://github.com/NetworkManager/NetworkManager/pull/332
-rw-r--r-- | clients/cli/connections.c | 96 | ||||
-rw-r--r-- | clients/cli/settings.c | 2 | ||||
-rw-r--r-- | clients/cli/utils.c | 3 | ||||
-rw-r--r-- | clients/common/nm-meta-setting-desc.c | 34 | ||||
-rw-r--r-- | clients/common/nm-vpn-helpers.c | 63 | ||||
-rw-r--r-- | libnm-core/nm-setting-bridge.c | 2 | ||||
-rw-r--r-- | libnm-core/nm-utils.c | 2 | ||||
-rw-r--r-- | libnm-core/tests/test-general.c | 333 | ||||
-rw-r--r-- | shared/nm-utils/nm-shared-utils.c | 237 | ||||
-rw-r--r-- | shared/nm-utils/nm-shared-utils.h | 28 | ||||
-rw-r--r-- | src/devices/nm-device-bond.c | 18 | ||||
-rw-r--r-- | src/dhcp/nm-dhcp-dhclient-utils.c | 179 | ||||
-rw-r--r-- | src/dhcp/nm-dhcp-utils.c | 101 | ||||
-rw-r--r-- | src/nm-dcb.c | 38 | ||||
-rw-r--r-- | src/nm-logging.c | 40 | ||||
-rw-r--r-- | src/settings/plugins/ibft/nms-ibft-plugin.c | 23 | ||||
-rw-r--r-- | src/settings/plugins/ibft/nms-ibft-reader.c | 66 | ||||
-rw-r--r-- | src/settings/plugins/ibft/nms-ibft-reader.h | 8 | ||||
-rw-r--r-- | src/settings/plugins/ibft/tests/test-ibft.c | 17 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 155 |
20 files changed, 883 insertions, 562 deletions
diff --git a/clients/cli/connections.c b/clients/cli/connections.c index 9a71d3944d..d3193ccb3c 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -1528,15 +1528,12 @@ split_required_fields_for_con_show (const char *input, char **active_flds, GError **error) { - char **fields, **iter; - char *dot; - GString *str1, *str2; - gboolean found; + gs_free const char **fields = NULL; + const char *const*iter; + nm_auto_free_gstring GString *str1 = NULL; + nm_auto_free_gstring GString *str2 = NULL; gboolean group_profile = FALSE; gboolean group_active = FALSE; - gboolean success = TRUE; - gboolean is_all, is_common; - int i; if (!input) { *profile_flds = NULL; @@ -1547,25 +1544,30 @@ split_required_fields_for_con_show (const char *input, str1 = g_string_new (NULL); str2 = g_string_new (NULL); - /* Split supplied fields string */ - fields = g_strsplit_set (input, ",", -1); + fields = nm_utils_strsplit_set_with_empty (input, ","); for (iter = fields; iter && *iter; iter++) { - g_strstrip (*iter); - dot = strchr (*iter, '.'); + char *s_mutable = (char *) (*iter); + char *dot; + gboolean is_all; + gboolean is_common; + gboolean found; + int i; + + g_strstrip (s_mutable); + dot = strchr (s_mutable, '.'); if (dot) *dot = '\0'; - is_all = !dot && strcasecmp (*iter, "all") == 0; - is_common = !dot && strcasecmp (*iter, "common") == 0; + is_all = !dot && strcasecmp (s_mutable, "all") == 0; + is_common = !dot && strcasecmp (s_mutable, "common") == 0; found = FALSE; - for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { if ( is_all || is_common - || !strcasecmp (*iter, nm_meta_setting_infos[i].setting_name)) { + || !strcasecmp (s_mutable, nm_meta_setting_infos[i].setting_name)) { if (dot) *dot = '.'; - g_string_append (str1, *iter); + g_string_append (str1, s_mutable); g_string_append_c (str1, ','); found = TRUE; break; @@ -1573,12 +1575,13 @@ split_required_fields_for_con_show (const char *input, } if (found) continue; + for (i = 0; nmc_fields_con_active_details_groups[i]; i++) { if ( is_all || is_common - || !strcasecmp (*iter, nmc_fields_con_active_details_groups[i]->name)) { + || !strcasecmp (s_mutable, nmc_fields_con_active_details_groups[i]->name)) { if (dot) *dot = '.'; - g_string_append (str2, *iter); + g_string_append (str2, s_mutable); g_string_append_c (str2, ','); found = TRUE; break; @@ -1587,55 +1590,46 @@ split_required_fields_for_con_show (const char *input, if (!found) { if (dot) *dot = '.'; - if (!strcasecmp (*iter, CON_SHOW_DETAIL_GROUP_PROFILE)) + if (!strcasecmp (s_mutable, CON_SHOW_DETAIL_GROUP_PROFILE)) group_profile = TRUE; - else if (!strcasecmp (*iter, CON_SHOW_DETAIL_GROUP_ACTIVE)) + else if (!strcasecmp (s_mutable, CON_SHOW_DETAIL_GROUP_ACTIVE)) group_active = TRUE; else { - char *allowed1 = nm_meta_abstract_infos_get_names_str ((const NMMetaAbstractInfo *const*) nm_meta_setting_infos_editor_p (), NULL); - char *allowed2 = nm_meta_abstract_infos_get_names_str ((const NMMetaAbstractInfo *const*) nmc_fields_con_active_details_groups, NULL); + gs_free char *allowed1 = nm_meta_abstract_infos_get_names_str ((const NMMetaAbstractInfo *const*) nm_meta_setting_infos_editor_p (), NULL); + gs_free char *allowed2 = nm_meta_abstract_infos_get_names_str ((const NMMetaAbstractInfo *const*) nmc_fields_con_active_details_groups, NULL); + g_set_error (error, NMCLI_ERROR, 0, _("invalid field '%s'; allowed fields: %s and %s, or %s,%s"), - *iter, allowed1, allowed2, CON_SHOW_DETAIL_GROUP_PROFILE, CON_SHOW_DETAIL_GROUP_ACTIVE); - g_free (allowed1); - g_free (allowed2); - success = FALSE; - break; + s_mutable, allowed1, allowed2, CON_SHOW_DETAIL_GROUP_PROFILE, CON_SHOW_DETAIL_GROUP_ACTIVE); + return FALSE; } } } - if (fields) - g_strfreev (fields); /* Handle pseudo groups: profile, active */ - if (success && group_profile) { + if (group_profile) { if (str1->len > 0) { g_set_error (error, NMCLI_ERROR, 0, _("'%s' has to be alone"), CON_SHOW_DETAIL_GROUP_PROFILE); - success = FALSE; - } else - g_string_assign (str1, "all,"); + return FALSE; + } + g_string_assign (str1, "all,"); } - if (success && group_active) { + if (group_active) { if (str2->len > 0) { g_set_error (error, NMCLI_ERROR, 0, _("'%s' has to be alone"), CON_SHOW_DETAIL_GROUP_ACTIVE); - success = FALSE; - } else - g_string_assign (str2, "all,"); + return FALSE; + } + g_string_assign (str2, "all,"); } - if (success) { - if (str1->len > 0) - g_string_truncate (str1, str1->len - 1); - if (str2->len > 0) - g_string_truncate (str2, str2->len - 1); - *profile_flds = g_string_free (str1, str1->len == 0); - *active_flds = g_string_free (str2, str2->len == 0); - } else { - g_string_free (str1, TRUE); - g_string_free (str2, TRUE); - } - return success; + if (str1->len > 0) + g_string_truncate (str1, str1->len - 1); + if (str2->len > 0) + g_string_truncate (str2, str2->len - 1); + *profile_flds = g_string_free (g_steal_pointer (&str1), str1->len == 0); + *active_flds = g_string_free (g_steal_pointer (&str2), str2->len == 0); + return TRUE; } typedef enum { @@ -1876,7 +1870,7 @@ parse_preferred_connection_order (const char *order, GError **error) gboolean inverse, unique; int i; - strv = nm_utils_strsplit_set (order, ":", FALSE); + strv = nm_utils_strsplit_set (order, ":"); if (!strv) { g_set_error (error, NMCLI_ERROR, 0, _("incorrect string '%s' of '--order' option"), order); @@ -2680,7 +2674,7 @@ parse_passwords (const char *passwd_file, GError **error) return NULL; } - strv = nm_utils_strsplit_set (contents, "\r\n", FALSE); + strv = nm_utils_strsplit_set (contents, "\r\n"); for (iter = strv; *iter; iter++) { gs_free char *iter_s = g_strdup (*iter); diff --git a/clients/cli/settings.c b/clients/cli/settings.c index d050e24e28..70348dbfec 100644 --- a/clients/cli/settings.c +++ b/clients/cli/settings.c @@ -338,7 +338,7 @@ _set_fcn_precheck_connection_secondaries (NMClient *client, char **iter; gboolean modified = FALSE; - strv0 = nm_utils_strsplit_set (value, " \t,", FALSE); + strv0 = nm_utils_strsplit_set (value, " \t,"); if (!strv0) return TRUE; diff --git a/clients/cli/utils.c b/clients/cli/utils.c index 0e74ba8867..a8b81279ed 100644 --- a/clients/cli/utils.c +++ b/clients/cli/utils.c @@ -508,7 +508,8 @@ nmc_string_to_arg_array (const char *line, const char *delim, gboolean unquote, gs_free const char **arr0 = NULL; char **arr; - arr0 = nm_utils_strsplit_set (line ?: "", delim ?: " \t", FALSE); + arr0 = nm_utils_strsplit_set (line ?: "", + delim ?: " \t"); if (!arr0) arr = g_new0 (char *, 1); else diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index d47e1bd67e..2b0386265c 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -197,19 +197,19 @@ _value_strsplit (const char *value, /* note that all modes remove empty tokens (",", "a,,b", ",,"). */ switch (split_mode) { case VALUE_STRSPLIT_MODE_STRIPPED: - strv = nm_utils_strsplit_set (value, NM_ASCII_SPACES",", FALSE); + strv = nm_utils_strsplit_set (value, NM_ASCII_SPACES","); break; case VALUE_STRSPLIT_MODE_OBJLIST: - strv = nm_utils_strsplit_set (value, ",", FALSE); + strv = nm_utils_strsplit_set (value, ","); break; case VALUE_STRSPLIT_MODE_OBJLIST_WITH_ESCAPE: - strv = nm_utils_strsplit_set (value, ",", TRUE); + strv = nm_utils_strsplit_set_full (value, ",", NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING); break; case VALUE_STRSPLIT_MODE_MULTILIST: - strv = nm_utils_strsplit_set (value, " \t,", FALSE); + strv = nm_utils_strsplit_set (value, " \t,"); break; case VALUE_STRSPLIT_MODE_MULTILIST_WITH_ESCAPE: - strv = nm_utils_strsplit_set (value, MULTILIST_WITH_ESCAPE_CHARS, TRUE); + strv = nm_utils_strsplit_set_full (value, MULTILIST_WITH_ESCAPE_CHARS, NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING); break; default: nm_assert_not_reached (); @@ -306,7 +306,7 @@ _parse_ip_route (int family, nm_assert (!error || !*error); str_clean = nm_strstrip_avoid_copy_a (300, str, &str_clean_free); - routev = nm_utils_strsplit_set (str_clean, " \t", FALSE); + routev = nm_utils_strsplit_set (str_clean, " \t"); if (!routev) { g_set_error (error, 1, 0, "'%s' is not valid. %s", @@ -480,7 +480,7 @@ _parse_team_link_watcher (const char *str, nm_assert (!error || !*error); str_clean = nm_strstrip_avoid_copy_a (300, str, &str_clean_free); - watcherv = nm_utils_strsplit_set (str_clean, " \t", FALSE); + watcherv = nm_utils_strsplit_set (str_clean, " \t"); if (!watcherv) { g_set_error (error, 1, 0, "'%s' is not valid", str); return NULL; @@ -489,7 +489,7 @@ _parse_team_link_watcher (const char *str, for (i = 0; watcherv[i]; i++) { gs_free const char **pair = NULL; - pair = nm_utils_strsplit_set (watcherv[i], "=", FALSE); + pair = nm_utils_strsplit_set (watcherv[i], "="); if (!pair) { g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i], "properties should be specified as 'key=value'"); @@ -1935,7 +1935,7 @@ _set_fcn_optionlist (ARGS_SET_FCN) return _gobject_property_reset_default (setting, property_info->property_name); nstrv = 0; - strv = nm_utils_strsplit_set (value, ",", FALSE); + strv = nm_utils_strsplit_set (value, ","); if (strv) { strv_val = g_new (const char *, NM_PTRARRAY_LEN (strv)); for (i = 0; strv[i]; i++) { @@ -2187,7 +2187,7 @@ _set_fcn_gobject_bytes (ARGS_SET_FCN) } /* Otherwise, consider the following format: AA b 0xCc D */ - strv = nm_utils_strsplit_set (value, " \t", FALSE); + strv = nm_utils_strsplit_set (value, " \t"); array = g_byte_array_sized_new (NM_PTRARRAY_LEN (strv)); for (iter = strv; iter && *iter; iter++) { int v; @@ -2797,7 +2797,7 @@ _set_fcn_dcb_flags (ARGS_SET_FCN) const char *const*iter; /* Check for individual flag numbers */ - strv = nm_utils_strsplit_set (value, " \t,", FALSE); + strv = nm_utils_strsplit_set (value, " \t,"); for (iter = strv; iter && *iter; iter++) { t = _nm_utils_ascii_str_to_int64 (*iter, 0, 0, DCB_ALL_FLAGS, -1); @@ -2837,12 +2837,12 @@ dcb_parse_uint_array (const char *val, guint out_array[static 8], GError **error) { - gs_strfreev char **items = NULL; - char **iter; + gs_free const char **items = NULL; + const char *const*iter; gsize i; - items = g_strsplit_set (val, ",", -1); - if (g_strv_length (items) != 8) { + items = nm_utils_strsplit_set_with_empty (val, ","); + if (NM_PTRARRAY_LEN (items) != 8) { g_set_error_literal (error, 1, 0, _("must contain 8 comma-separated numbers")); return FALSE; } @@ -2851,8 +2851,6 @@ dcb_parse_uint_array (const char *val, for (iter = items; *iter; iter++) { gint64 num; - *iter = g_strstrip (*iter); - num = _nm_utils_ascii_str_to_int64 (*iter, 10, 0, other ?: max, -1); /* If number is greater than 'max' it must equal 'other' */ @@ -3948,7 +3946,7 @@ _set_fcn_wired_s390_subchannels (ARGS_SET_FCN) if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) return _gobject_property_reset_default (setting, property_info->property_name); - strv = nm_utils_strsplit_set (value, " ,\t", FALSE); + strv = nm_utils_strsplit_set (value, " ,\t"); len = NM_PTRARRAY_LEN (strv); if (len != 2 && len != 3) { g_set_error (error, 1, 0, _("'%s' is not valid; 2 or 3 strings should be provided"), diff --git a/clients/common/nm-vpn-helpers.c b/clients/common/nm-vpn-helpers.c index ea905972f5..47a827409f 100644 --- a/clients/common/nm-vpn-helpers.c +++ b/clients/common/nm-vpn-helpers.c @@ -181,18 +181,17 @@ _extract_variable_value (char *line, const char *tag, char **value) { char *p1, *p2; - if (g_str_has_prefix (line, tag)) { - p1 = line + strlen (tag); - p2 = line + strlen (line) - 1; - if ((*p1 == '\'' || *p1 == '"') && (*p1 == *p2)) { - p1++; - *p2 = '\0'; - } - if (value) - *value = g_strdup (p1); - return TRUE; + if (!g_str_has_prefix (line, tag)) + return FALSE; + + p1 = line + strlen (tag); + p2 = line + strlen (line) - 1; + if ((*p1 == '\'' || *p1 == '"') && (*p1 == *p2)) { + p1++; + *p2 = '\0'; } - return FALSE; + NM_SET_OUT (value, g_strdup (p1)); + return TRUE; } gboolean @@ -203,10 +202,9 @@ nm_vpn_openconnect_authenticate_helper (const char *host, int *status, GError **error) { - char *output = NULL; - gboolean ret; - char **strv = NULL, **iter; - char *argv[4]; + gs_free char *output = NULL; + gs_free const char **output_v = NULL; + const char *const*iter; const char *path; const char *const DEFAULT_PATHS[] = { "/sbin/", @@ -223,17 +221,17 @@ nm_vpn_openconnect_authenticate_helper (const char *host, if (!path) return FALSE; - argv[0] = (char *) path; - argv[1] = "--authenticate"; - argv[2] = (char *) host; - argv[3] = NULL; - - ret = g_spawn_sync (NULL, argv, NULL, - G_SPAWN_SEARCH_PATH | G_SPAWN_CHILD_INHERITS_STDIN, - NULL, NULL, &output, NULL, - status, error); - - if (!ret) + if (!g_spawn_sync (NULL, + (char **) NM_MAKE_STRV (path, "--authenticate", host), + NULL, + G_SPAWN_SEARCH_PATH + | G_SPAWN_CHILD_INHERITS_STDIN, + NULL, + NULL, + &output, + NULL, + status, + error)) return FALSE; /* Parse output and set cookie, gateway and gwcert @@ -242,13 +240,14 @@ nm_vpn_openconnect_authenticate_helper (const char *host, * HOST='1.2.3.4' * FINGERPRINT='sha1:32bac90cf09a722e10ecc1942c67fe2ac8c21e2e' */ - strv = g_strsplit_set (output ?: "", "\r\n", 0); - for (iter = strv; iter && *iter; iter++) { - _extract_variable_value (*iter, "COOKIE=", cookie); - _extract_variable_value (*iter, "HOST=", gateway); - _extract_variable_value (*iter, "FINGERPRINT=", gwcert); + output_v = nm_utils_strsplit_set_with_empty (output, "\r\n"); + for (iter = output_v; iter && *iter; iter++) { + char *s_mutable = (char *) *iter; + + _extract_variable_value (s_mutable, "COOKIE=", cookie); + _extract_variable_value (s_mutable, "HOST=", gateway); + _extract_variable_value (s_mutable, "FINGERPRINT=", gwcert); } - g_strfreev (strv); return TRUE; } diff --git a/libnm-core/nm-setting-bridge.c b/libnm-core/nm-setting-bridge.c index f87abd0654..590f6ea2bd 100644 --- a/libnm-core/nm-setting-bridge.c +++ b/libnm-core/nm-setting-bridge.c @@ -432,7 +432,7 @@ nm_bridge_vlan_from_str (const char *str, GError **error) g_return_val_if_fail (str, NULL); g_return_val_if_fail (!error || !*error, NULL); - tokens = nm_utils_strsplit_set (str, " ", FALSE); + tokens = nm_utils_strsplit_set (str, " "); if (!tokens || !tokens[0]) { g_set_error_literal (error, NM_CONNECTION_ERROR, diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index cf7ddb08f9..0d9118adee 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -2849,7 +2849,7 @@ _nm_sriov_vf_parse_vlans (NMSriovVF *vf, const char *str, GError **error) gs_free const char **vlans = NULL; guint i; - vlans = nm_utils_strsplit_set (str, ";", FALSE); + vlans = nm_utils_strsplit_set (str, ";"); if (!vlans) { g_set_error_literal (error, NM_CONNECTION_ERROR, diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 765957135a..175b48b505 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -259,47 +259,279 @@ test_nm_g_slice_free_fcn (void) /*****************************************************************************/ static void -_do_test_nm_utils_strsplit_set (gboolean escape, const char *str, ...) +_do_test_nm_utils_strsplit_set_f_one (NMUtilsStrsplitSetFlags flags, + const char *str, + gsize words_len, + const char *const*exp_words) { - gs_unref_ptrarray GPtrArray *args_array = g_ptr_array_new (); - const char *const*args; + const char *DELIMITERS = " \t\n"; +#define DELIMITERS_C ' ', '\t', '\n' + gs_free const char **words = NULL; - const char *arg; - gsize i; - va_list ap; + gsize i, j, k; + const gboolean f_allow_escaping = NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING); + const gboolean f_preserve_empty = NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY); + const char *s1; + gsize initial_offset; + gs_strfreev char **words_g = NULL; + + g_assert (!NM_FLAGS_ANY (flags, ~( NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING + | NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY))); + + /* assert that the epected words are valid (and don't contain unescaped delimiters). */ + for (i = 0; i < words_len; i++) { + const char *w = exp_words[i]; + + g_assert (w); + if (!f_preserve_empty) + g_assert (w[0]); + for (k = 0; w[k]; ) { + if ( f_allow_escaping + && w[k] == '\\') { + k++; + if (w[k] == '\0') + break; + k++; + continue; + } + g_assert (!NM_IN_SET (w[k], DELIMITERS_C)); + k++; + } + if (!f_allow_escaping) + g_assert (!NM_STRCHAR_ANY (w, ch, NM_IN_SET (ch, DELIMITERS_C))); + } - va_start (ap, str); - while ((arg = va_arg (ap, const char *))) - g_ptr_array_add (args_array, (gpointer) arg); - va_end (ap); - g_ptr_array_add (args_array, NULL); + initial_offset = (f_preserve_empty || !str) + ? 0u + : strspn (str, DELIMITERS); + + /* first compare our expected values with what g_strsplit_set() would + * do. */ + words_g = str ? g_strsplit_set (str, DELIMITERS, -1) : NULL; + if (str == NULL) { + g_assert_cmpint (words_len, ==, 0); + g_assert (!words_g); + } else if (nm_streq0 (str, "")) { + g_assert_cmpint (words_len, ==, 0); + g_assert (words_g); + g_assert (!words_g[0]); + } else { + g_assert (words_g); + g_assert (words_g[0]); + if (!f_allow_escaping) { + if (!f_preserve_empty) { + for (i = 0, j = 0; words_g[i]; i++) { + if (words_g[i][0] == '\0') + g_free (words_g[i]); + else + words_g[j++] = words_g[i]; + } + words_g[j] = NULL; + } + if (f_preserve_empty) + g_assert_cmpint (words_len, >, 0); + for (i = 0; i < words_len; i++) { + g_assert (exp_words[i]); + g_assert_cmpstr (exp_words[i], ==, words_g[i]); + } + g_assert (words_g[words_len] == NULL); + g_assert_cmpint (NM_PTRARRAY_LEN (words_g), ==, words_len); + g_assert (_nm_utils_strv_cmp_n (exp_words, words_len, NM_CAST_STRV_CC (words_g), -1) == 0); + } + } - args = (const char *const*) args_array->pdata; + if ( flags == NM_UTILS_STRSPLIT_SET_FLAGS_NONE + && nmtst_get_rand_bool ()) + words = nm_utils_strsplit_set (str, DELIMITERS); + else if ( flags == NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY + && nmtst_get_rand_bool ()) + words = nm_utils_strsplit_set_with_empty (str, DELIMITERS); + else + words = nm_utils_strsplit_set_full (str, DELIMITERS, flags); - words = nm_utils_strsplit_set (str, " \t\n", escape); + g_assert_cmpint (NM_PTRARRAY_LEN (words), ==, words_len); - if (!args[0]) { + if (words_len == 0) { g_assert (!words); g_assert ( !str - || NM_STRCHAR_ALL (str, ch, NM_IN_SET (ch, ' ', '\t', '\n'))); + || NM_STRCHAR_ALL (str, ch, NM_IN_SET (ch, DELIMITERS_C))); return; } + g_assert (words); - for (i = 0; args[i] || words[i]; i++) { - g_assert (args[i]); - g_assert (words[i]); - g_assert (args[i][0]); - g_assert (escape || NM_STRCHAR_ALL (args[i], ch, !NM_IN_SET (ch, ' ', '\t', '\n'))); - g_assert_cmpstr (args[i], ==, words[i]); + for (i = 0; i < words_len; i++) + g_assert_cmpstr (exp_words[i], ==, words[i]); + g_assert (words[words_len] == NULL); + + g_assert (_nm_utils_strv_cmp_n (exp_words, words_len, words, -1) == 0); + + s1 = words[0]; + g_assert (s1 >= (char *) &words[words_len + 1]); + s1 = &s1[strlen (str)]; + for (i = 1; i < words_len; i++) { + g_assert (&(words[i - 1])[strlen (words[i - 1])] < words[i]); + g_assert (words[i] <= s1); + } + + /* while strsplit removes all delimiters, we can relatively easily find them + * in the original string. Assert that the original string and the pointer offsets + * of words correspond. In particular, find idx_delim_after and idx_delim_before + * to determine which delimiter was after/before a word. */ + { + gsize idx_word_start; + gsize idx_delim_after_old = G_MAXSIZE; + + idx_word_start = initial_offset; + for (i = 0; i < words_len; i++) { + const gsize l_i = strlen (words[i]); + gsize idx_delim_after; + gsize idx_delim_before; + + /* find the delimiter *after* words[i]. We can do that by looking at the next + * word and calculating the pointer difference. + * + * The delimiter after the very last word is '\0' and requires strlen() to find. */ + idx_delim_after = initial_offset + ((words[i] - words[0]) + l_i); + if (idx_delim_after != idx_word_start + l_i) { + g_assert (!f_preserve_empty); + g_assert_cmpint (idx_word_start + l_i, <, idx_delim_after); + idx_word_start = idx_delim_after - l_i; + } + if (i + 1 < words_len) { + gsize x = initial_offset + ((words[i + 1] - words[0]) - 1); + + if (idx_delim_after != x) { + g_assert (!f_preserve_empty); + g_assert_cmpint (idx_delim_after, <, x); + for (k = idx_delim_after; k <= x; k++) + g_assert (NM_IN_SET (str[k], DELIMITERS_C)); + } + g_assert (NM_IN_SET (str[idx_delim_after], DELIMITERS_C)); + } else { + if (f_preserve_empty) + g_assert (NM_IN_SET (str[idx_delim_after], '\0')); + else + g_assert (NM_IN_SET (str[idx_delim_after], '\0', DELIMITERS_C)); + } + + /* find the delimiter *before* words[i]. */ + if (i == 0) { + /* there is only a delimiter *before*, with !f_preserve_empty and leading + * delimiters. */ + idx_delim_before = G_MAXSIZE; + if (initial_offset > 0) { + g_assert (!f_preserve_empty); + idx_delim_before = initial_offset - 1; + } + } else + idx_delim_before = initial_offset + (words[i] - words[0]) - 1; + if (idx_delim_before != G_MAXSIZE) + g_assert (NM_IN_SET (str[idx_delim_before], DELIMITERS_C)); + if (idx_delim_after_old != idx_delim_before) { + g_assert (!f_preserve_empty); + if (i == 0) { + g_assert_cmpint (initial_offset, >, 0); + g_assert_cmpint (idx_delim_before, !=, G_MAXSIZE); + g_assert_cmpint (idx_delim_before, ==, initial_offset - 1); + } else { + g_assert_cmpint (idx_delim_after_old, !=, G_MAXSIZE); + g_assert_cmpint (idx_delim_before, !=, G_MAXSIZE); + g_assert_cmpint (idx_delim_after_old, <, idx_delim_before); + for (k = idx_delim_after_old; k <= idx_delim_before; k++) + g_assert (NM_IN_SET (str[k], DELIMITERS_C)); + } + } + + for (k = 0; k < l_i; ) { + if ( f_allow_escaping + && str[idx_word_start + k] == '\\') { + k++; + if (k >= l_i) + break; + k++; + continue; + } + g_assert (!NM_IN_SET (str[idx_word_start + k], DELIMITERS_C)); + k++; + } + g_assert (strncmp (words[i], &str[idx_word_start], l_i) == 0); + + if (i > 0) { + const char *s = &(words[i - 1])[strlen (words[i - 1]) + 1]; + + if (s != words[i]) { + g_assert (!f_preserve_empty); + g_assert (s < words[i]); + } + } + + idx_word_start += l_i + 1; + idx_delim_after_old = idx_delim_after; + } + } +} + +static void +_do_test_nm_utils_strsplit_set_f (NMUtilsStrsplitSetFlags flags, + const char *str, + gsize words_len, + const char *const*exp_words) +{ + _do_test_nm_utils_strsplit_set_f_one (flags, str, words_len, exp_words); + + if (NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY)) { + gs_unref_ptrarray GPtrArray *exp_words2 = NULL; + gsize k; + + exp_words2 = g_ptr_array_new (); + for (k = 0; k < words_len; k++) { + if (exp_words[k][0] != '\0') + g_ptr_array_add (exp_words2, (gpointer) exp_words[k]); + } + + _do_test_nm_utils_strsplit_set_f_one (flags & (~NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY), + str, + exp_words2->len, + (const char *const*) exp_words2->pdata); } } -#define do_test_nm_utils_strsplit_set(str, ...) \ - _do_test_nm_utils_strsplit_set (str, ##__VA_ARGS__, NULL) +#define do_test_nm_utils_strsplit_set_f(flags, str, ...) \ + _do_test_nm_utils_strsplit_set_f (flags, \ + str, \ + NM_NARG (__VA_ARGS__), \ + NM_MAKE_STRV (__VA_ARGS__)) + +#define do_test_nm_utils_strsplit_set(allow_escaping, str, ...) \ + do_test_nm_utils_strsplit_set_f ( (allow_escaping) \ + ? NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING \ + : NM_UTILS_STRSPLIT_SET_FLAGS_NONE, \ + str, \ + ##__VA_ARGS__) static void test_nm_utils_strsplit_set (void) { + gs_unref_ptrarray GPtrArray *words_exp = NULL; + guint test_run; + + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_NONE, NULL); + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_NONE, ""); + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_NONE, " "); + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_NONE, "a b", "a", "b"); + + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, NULL); + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, ""); + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, " ", "", ""); + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, " ", "", "", ""); + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, "a ", "a", "", ""); + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, "a b", "a", "", "b"); + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, " ab b", "", "ab", "", "b"); + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, "ab b", "ab", "", "b"); + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, "abb", "abb"); + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, "abb bb ", "abb", "", "bb", ""); + do_test_nm_utils_strsplit_set_f (NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, "abb bcb ", "abb", "bcb", ""); + do_test_nm_utils_strsplit_set (FALSE, NULL); do_test_nm_utils_strsplit_set (FALSE, ""); do_test_nm_utils_strsplit_set (FALSE, "\t"); @@ -323,6 +555,61 @@ test_nm_utils_strsplit_set (void) do_test_nm_utils_strsplit_set (TRUE, "foo\\", "foo\\"); do_test_nm_utils_strsplit_set (TRUE, "bar foo\\", "bar", "foo\\"); do_test_nm_utils_strsplit_set (TRUE, "\\ a b\\ \\ c", "\\ a", "b\\ \\ ", "c"); + + words_exp = g_ptr_array_new_with_free_func (g_free); + for (test_run = 0; test_run < 100; test_run++) { + gboolean f_allow_escaping = nmtst_get_rand_bool (); + guint words_len = nmtst_get_rand_int () % 100; + gs_free char *str = NULL; + guint i; + + g_ptr_array_set_size (words_exp, 0); + for (i = 0; i < words_len; i++) { + guint word_len; + char *word; + guint j; + + word_len = nmtst_get_rand_int (); + if ((word_len % 100) < 30) + word_len = 0; + else + word_len = (word_len >> 10) % 100; + word = g_new (char, word_len + 3); + for (j = 0; j < word_len; ) { + guint32 p = nmtst_get_rand_int (); + static const char delimiters_arr[] = { DELIMITERS_C }; + static const char regular_chars[] = "abcdefghijklmnopqrstuvwxyz"; + + if ( !f_allow_escaping + || (p % 1000) < 700) { + if (((p >> 20) % 100) < 20) + word[j++] = '\\'; + word[j++] = regular_chars[(p >> 11) % (G_N_ELEMENTS (regular_chars) - 1)]; + continue; + } + word[j++] = '\\'; + word[j++] = delimiters_arr[(p >> 11) % G_N_ELEMENTS (delimiters_arr)]; + } + word[j] = '\0'; + g_ptr_array_add (words_exp, word); + } + g_ptr_array_add (words_exp, NULL); + + str = g_strjoinv (" ", (char **) words_exp->pdata); + + if ( str[0] == '\0' + && words_len > 0) { + g_assert (words_len == 1); + g_assert_cmpstr (words_exp->pdata[0], ==, ""); + words_len = 0; + } + + _do_test_nm_utils_strsplit_set_f ( (f_allow_escaping ? NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING : NM_UTILS_STRSPLIT_SET_FLAGS_NONE) + | NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, + str, + words_len, + (const char *const*) words_exp->pdata); + } } /*****************************************************************************/ diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c index 5f317e4144..879d1e7b9e 100644 --- a/shared/nm-utils/nm-shared-utils.c +++ b/shared/nm-utils/nm-shared-utils.c @@ -971,28 +971,44 @@ _char_lookup_table_init (guint8 lookup[static 256], lookup[(guint8) ((candidates++)[0])] = 1; } +static gboolean +_char_lookup_has (const guint8 lookup[static 256], + char ch) +{ + nm_assert (lookup[(guint8) '\0'] == 0); + return lookup[(guint8) ch] != 0; +} + /** - * nm_utils_strsplit_set: + * nm_utils_strsplit_set_full: * @str: the string to split. - * @delimiters: the set of delimiters. If %NULL, defaults to " \t\n", - * like bash's $IFS. - * @allow_escaping: whether delimiters can be escaped by a backslash + * @delimiters: the set of delimiters. + * @flags: additional flags for controlling the operation. * * This is a replacement for g_strsplit_set() which avoids copying * each word once (the entire strv array), but instead copies it once * and all words point into that internal copy. * - * Another difference from g_strsplit_set() is that this never returns - * empty words. Multiple delimiters are combined and treated as one. + * Note that for @str %NULL and "", this always returns %NULL too. That differs + * from g_strsplit_set(), which would return an empty strv array for "". + * + * Note that g_strsplit_set() returns empty words as well. By default, + * nm_utils_strsplit_set_full() strips all empty tokens (that is, repeated + * delimiters. With %NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, empty tokens + * are not removed. * - * If @allow_escaping is %TRUE, delimiters prefixed by a backslash are - * not treated as a separator. Such delimiters and their escape - * character are copied to the current word without unescaping them. + * If @flags has %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING, delimiters prefixed + * by a backslash are not treated as a separator. Such delimiters and their escape + * character are copied to the current word without unescaping them. In general, + * nm_utils_strsplit_set_full() does not remove any backslash escape characters + * and does not unescaping. It only considers them for skipping to split at + * an escaped delimiter. * - * Returns: %NULL if @str is %NULL or contains only delimiters. - * Otherwise, a %NULL terminated strv array containing non-empty - * words, split at the delimiter characters (delimiter characters - * are removed). + * Returns: %NULL if @str is %NULL or "". + * If @str only contains delimiters and %NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY + * is not set, it also returns %NULL. + * Otherwise, a %NULL terminated strv array containing the split words. + * (delimiter characters are removed). * The strings to which the result strv array points to are allocated * after the returned result itself. Don't free the strings themself, * but free everything with g_free(). @@ -1000,103 +1016,140 @@ _char_lookup_table_init (guint8 lookup[static 256], * like "g_strstrip((char *) iter[0])". */ const char ** -nm_utils_strsplit_set (const char *str, const char *delimiters, gboolean allow_escaping) -{ - const char **ptr, **ptr0; - gsize alloc_size, plen, i; - gsize str_len; - char *s0; +nm_utils_strsplit_set_full (const char *str, + const char *delimiters, + NMUtilsStrsplitSetFlags flags) +{ + const char **ptr; + gsize num_tokens; + gsize i_token; + gsize str_len_p1; + const char *c_str; char *s; - guint8 delimiters_table[256]; - gboolean escaped = FALSE; + guint8 ch_lookup[256]; + const gboolean f_allow_escaping = NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING); + const gboolean f_preseve_empty = NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY); if (!str) return NULL; - /* initialize lookup table for delimiter */ - if (!delimiters) + if (!delimiters) { + nm_assert_not_reached (); delimiters = " \t\n"; + } + _char_lookup_table_init (ch_lookup, delimiters); - _char_lookup_table_init (delimiters_table, delimiters); + nm_assert ( !f_allow_escaping + || !_char_lookup_has (ch_lookup, '\\')); -#define _is_delimiter(ch, delimiters_table, allow_esc, esc) \ - ((delimiters_table)[(guint8) (ch)] != 0 && (!allow_esc || !esc)) + if (!f_preseve_empty) { + while (_char_lookup_has (ch_lookup, str[0])) + str++; + } -#define next_char(p, esc) \ - G_STMT_START { \ - if (esc) \ - esc = FALSE; \ - else \ - esc = p[0] == '\\'; \ - p++; \ - } G_STMT_END + if (!str[0]) { + /* We return %NULL here, also with NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY. + * That makes nm_utils_strsplit_set_full() with NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY + * different from g_strsplit_set(), which would in this case return an empty array. + * If you need to handle %NULL, and "" specially, then check the input string first. */ + return NULL; + } - /* skip initial delimiters, and return of the remaining string is - * empty. */ - while (_is_delimiter (str[0], delimiters_table, allow_escaping, escaped)) - next_char (str, escaped); - if (!str[0]) - return NULL; + num_tokens = 1; + c_str = str; + while (TRUE) { - str_len = strlen (str) + 1; - alloc_size = 8; + while (G_LIKELY (!_char_lookup_has (ch_lookup, c_str[0]))) { + if (c_str[0] == '\0') + goto done1; + c_str++; + } - /* we allocate the buffer larger, so to copy @str at the - * end of it as @s0. */ - ptr0 = g_malloc ((sizeof (const char *) * (alloc_size + 1)) + str_len); - s0 = (char *) &ptr0[alloc_size + 1]; - memcpy (s0, str, str_len); + /* we assume escapings are not frequent. After we found + * this delimiter, check whether it was escaped by counting + * the backslashed before. */ + if (f_allow_escaping) { + const char *c2 = c_str; + + while ( c2 > str + && c2[-1] == '\\') + c2--; + if (((c_str - c2) % 2) != 0) { + /* the delimiter is escaped. This was not an accepted delimiter. */ + c_str++; + continue; + } + } - plen = 0; - s = s0; - ptr = ptr0; + c_str++; - while (TRUE) { - if (plen >= alloc_size) { - const char **ptr_old = ptr; - - /* reallocate the buffer. Note that for now the string - * continues to be in ptr0/s0. We fix that at the end. */ - alloc_size *= 2; - ptr = g_malloc ((sizeof (const char *) * (alloc_size + 1)) + str_len); - memcpy (ptr, ptr_old, sizeof (const char *) * plen); - if (ptr_old != ptr0) - g_free (ptr_old); + /* if we drop empty tokens, then we now skip over all consecutive delimiters. */ + if (!f_preseve_empty) { + while (_char_lookup_has (ch_lookup, c_str[0])) + c_str++; + if (c_str[0] == '\0') + break; } - ptr[plen++] = s; + num_tokens++; + } - nm_assert (s[0] && !_is_delimiter (s[0], delimiters_table, allow_escaping, escaped)); +done1: - while (TRUE) { - next_char (s, escaped); - if (_is_delimiter (s[0], delimiters_table, allow_escaping, escaped)) - break; - if (s[0] == '\0') - goto done; + nm_assert (c_str[0] == '\0'); + + str_len_p1 = (c_str - str) + 1; + + nm_assert (str[str_len_p1 - 1] == '\0'); + + ptr = g_malloc ((sizeof (const char *) * (num_tokens + 1)) + str_len_p1); + s = (char *) &ptr[num_tokens + 1]; + memcpy (s, str, str_len_p1); + + i_token = 0; + + while (TRUE) { + + nm_assert (i_token < num_tokens); + ptr[i_token++] = s; + + if (s[0] == '\0') { + nm_assert (f_preseve_empty); + goto done2; + } + nm_assert ( f_preseve_empty + || !_char_lookup_has (ch_lookup, s[0])); + + while (!_char_lookup_has (ch_lookup, s[0])) { + if (G_UNLIKELY ( s[0] == '\\' + && f_allow_escaping)) { + s++; + if (s[0] == '\0') + goto done2; + s++; + } else if (s[0] == '\0') + goto done2; + else + s++; } + nm_assert (_char_lookup_has (ch_lookup, s[0])); s[0] = '\0'; - next_char (s, escaped); - while (_is_delimiter (s[0], delimiters_table, allow_escaping, escaped)) - next_char (s, escaped); - if (s[0] == '\0') - break; - } -done: - ptr[plen] = NULL; + s++; - if (ptr != ptr0) { - /* we reallocated the buffer. We must copy over the - * string @s0 and adjust the pointers. */ - s = (char *) &ptr[alloc_size + 1]; - memcpy (s, s0, str_len); - for (i = 0; i < plen; i++) - ptr[i] = &s[ptr[i] - s0]; - g_free (ptr0); + if (!f_preseve_empty) { + while (_char_lookup_has (ch_lookup, s[0])) + s++; + if (s[0] == '\0') + goto done2; + } } +done2: + nm_assert (i_token == num_tokens); + ptr[i_token] = NULL; + return ptr; } @@ -2272,7 +2325,7 @@ nm_utils_get_start_time_for_pid (pid_t pid, char *out_state, pid_t *out_ppid) state = p[0]; - tokens = nm_utils_strsplit_set (p, " ", FALSE); + tokens = nm_utils_strsplit_set (p, " "); if (NM_PTRARRAY_LEN (tokens) < 20) goto fail; @@ -2426,8 +2479,6 @@ _nm_utils_user_data_unpack (gpointer user_data, int nargs, ...) /*****************************************************************************/ -#define _CH_LOOKUP(ch_lookup, ch) (!!((ch_lookup)[(guint8) (ch)])) - const char * _nm_utils_escape_plain (const char *str, const char *candidates, char **to_free) { @@ -2445,7 +2496,7 @@ _nm_utils_escape_plain (const char *str, const char *candidates, char **to_free) while (TRUE) { if (!*ptr) return str; - if (_CH_LOOKUP (ch_lookup, *ptr)) + if (_char_lookup_has (ch_lookup, *ptr)) break; ptr++; } @@ -2455,7 +2506,7 @@ _nm_utils_escape_plain (const char *str, const char *candidates, char **to_free) r = ret; *to_free = ret; while (*ptr) { - if (_CH_LOOKUP (ch_lookup, *ptr)) + if (_char_lookup_has (ch_lookup, *ptr)) *r++ = '\\'; *r++ = *ptr++; } @@ -2478,13 +2529,13 @@ _nm_utils_unescape_plain (char *str, const char *candidates, gboolean do_strip) _char_lookup_table_init (ch_lookup, candidates ?: NM_ASCII_SPACES); if (do_strip) { - while (str[i] && _CH_LOOKUP (ch_lookup, str[i])) + while (str[i] && _char_lookup_has (ch_lookup, str[i])) i++; } for (; str[i]; i++) { if ( str[i] == '\\' - && _CH_LOOKUP (ch_lookup, str[i+1])) { + && _char_lookup_has (ch_lookup, str[i+1])) { preserve_space_at = j; i++; } @@ -2494,7 +2545,7 @@ _nm_utils_unescape_plain (char *str, const char *candidates, gboolean do_strip) if (do_strip && j > 0) { while ( --j > preserve_space_at - && _CH_LOOKUP (ch_lookup, str[j])) + && _char_lookup_has (ch_lookup, str[j])) str[j] = '\0'; } diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index 95ed5c946f..8ec6fa2f5a 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -332,7 +332,33 @@ int nm_utils_dbus_path_cmp (const char *dbus_path_a, const char *dbus_path_b); /*****************************************************************************/ -const char **nm_utils_strsplit_set (const char *str, const char *delimiters, gboolean allow_escaping); +typedef enum { + NM_UTILS_STRSPLIT_SET_FLAGS_NONE = 0, + NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY = (1u << 0), + NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING = (1u << 1), +} NMUtilsStrsplitSetFlags; + +const char **nm_utils_strsplit_set_full (const char *str, + const char *delimiter, + NMUtilsStrsplitSetFlags flags); + +static inline const char ** +nm_utils_strsplit_set_with_empty (const char *str, + const char *delimiters) +{ + /* this returns the same result as g_strsplit_set(str, delimiters, -1), except + * it does not deep-clone the strv array. + * Also, for @str == "", this returns %NULL while g_strsplit_set() would return + * an empty strv array. */ + return nm_utils_strsplit_set_full (str, delimiters, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY); +} + +static inline const char ** +nm_utils_strsplit_set (const char *str, + const char *delimiters) +{ + return nm_utils_strsplit_set_full (str, delimiters, NM_UTILS_STRSPLIT_SET_FLAGS_NONE); +} char *nm_utils_str_simpletokens_extract_next (char **p_line_start); diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 6dabdfe855..37159fca8c 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -185,20 +185,18 @@ set_arp_targets (NMDevice *device, const char *delim, const char *prefix) { - char **items, **iter, *tmp; + gs_free const char **value_v = NULL; + gsize i; - if (!value || !*value) + value_v = nm_utils_strsplit_set (value, delim); + if (!value_v) return; + for (i = 0; value_v[i]; i++) { + gs_free char *tmp = NULL; - items = g_strsplit_set (value, delim, 0); - for (iter = items; iter && *iter; iter++) { - if (*iter[0]) { - tmp = g_strdup_printf ("%s%s", prefix, *iter); - set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, tmp); - g_free (tmp); - } + tmp = g_strdup_printf ("%s%s", prefix, value_v[i]); + set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, tmp); } - g_strfreev (items); } static void diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index cbd706fa69..9d1bdceb17 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -50,10 +50,10 @@ static void add_request (GPtrArray *array, const char *item) { - int i; + guint i; for (i = 0; i < array->len; i++) { - if (!strcmp (g_ptr_array_index (array, i), item)) + if (nm_streq (array->pdata[i], item)) return; } g_ptr_array_add (array, g_strdup (item)); @@ -62,37 +62,48 @@ add_request (GPtrArray *array, const char *item) static gboolean grab_request_options (GPtrArray *store, const char* line) { - char **areq, **aiter; - gboolean end = FALSE; + gs_free const char **line_v = NULL; + gsize i; /* Grab each 'request' or 'also request' option and save for later */ - areq = g_strsplit_set (line, "\t ,", -1); - for (aiter = areq; aiter && *aiter; aiter++) { - if (!strlen (g_strstrip (*aiter))) - continue; + line_v = nm_utils_strsplit_set (line, "\t ,"); + for (i = 0; line_v && line_v[i]; i++) { + const char *ss = nm_str_skip_leading_spaces (line_v[i]); + gsize l; + gboolean end = FALSE; - if (*aiter[0] == ';') { + if (!ss[0]) + continue; + if (ss[0] == ';') { /* all done */ - end = TRUE; - break; + return TRUE; } - if (!g_ascii_isalnum ((*aiter)[0])) + if (!g_ascii_isalnum (ss[0])) continue; - if ((*aiter)[strlen (*aiter) - 1] == ';') { + l = strlen (ss); + + while ( l > 0 + && g_ascii_isspace (ss[l - 1])) { + ((char *) ss)[l - 1] = '\0'; + l--; + } + if ( l > 0 + && ss[l - 1] == ';') { /* Remove the EOL marker */ - (*aiter)[strlen (*aiter) - 1] = '\0'; + ((char *) ss)[l - 1] = '\0'; end = TRUE; } - add_request (store, *aiter); - } + if (ss[0]) + add_request (store, ss); - if (areq) - g_strfreev (areq); + if (end) + return TRUE; + } - return end; + return FALSE; } static void @@ -278,8 +289,9 @@ nm_dhcp_dhclient_create_config (const char *interface, const char *orig_contents, GBytes **out_new_client_id) { - GString *new_contents; - GPtrArray *fqdn_opts, *reqs; + nm_auto_free_gstring GString *new_contents = NULL; + gs_unref_ptrarray GPtrArray *fqdn_opts = NULL; + gs_unref_ptrarray GPtrArray *reqs = NULL; gboolean reset_reqlist = FALSE; int i; @@ -288,11 +300,11 @@ nm_dhcp_dhclient_create_config (const char *interface, nm_assert (!out_new_client_id || !*out_new_client_id); new_contents = g_string_new (_("# Created by NetworkManager\n")); - fqdn_opts = g_ptr_array_sized_new (5); reqs = g_ptr_array_new_full (5, g_free); if (orig_contents) { - char **lines, **line; + gs_free const char **lines = NULL; + gsize line_i; int nest = 0; gboolean in_alsoreq = FALSE; gboolean in_req = FALSE; @@ -301,19 +313,23 @@ nm_dhcp_dhclient_create_config (const char *interface, g_string_append_printf (new_contents, _("# Merged from %s\n\n"), orig_path); intf[0] = '\0'; - lines = g_strsplit_set (orig_contents, "\n\r", 0); - for (line = lines; lines && *line; line++) { - char *p = *line; + lines = nm_utils_strsplit_set (orig_contents, "\n\r"); + for (line_i = 0; lines && lines[line_i]; line_i++) { + const char *line = nm_str_skip_leading_spaces (lines[line_i]); + const char *p; - if (!strlen (g_strstrip (p))) + if (line[0] == '\0') continue; + g_strchomp ((char *) line); + + p = line; if (in_req) { /* pass */ } else if (strchr (p, '{')) { nest++; if ( !intf[0] - && g_str_has_prefix (p, "interface")) + && NM_STR_HAS_PREFIX (p, "interface")) if (read_interface (p, intf, sizeof (intf))) continue; } else if (strchr (p, '}')) { @@ -363,6 +379,8 @@ nm_dhcp_dhclient_create_config (const char *interface, * default ones set by NM, add them later */ if (!strncmp (p, FQDN_TAG_PREFIX, NM_STRLEN (FQDN_TAG_PREFIX))) { + if (!fqdn_opts) + fqdn_opts = g_ptr_array_new_full (5, g_free); g_ptr_array_add (fqdn_opts, g_strdup (p + NM_STRLEN (FQDN_TAG_PREFIX))); continue; } @@ -397,12 +415,9 @@ nm_dhcp_dhclient_create_config (const char *interface, } /* Existing configuration line is OK, add it to new configuration */ - g_string_append (new_contents, *line); + g_string_append (new_contents, line); g_string_append_c (new_contents, '\n'); } - - if (lines) - g_strfreev (lines); } else g_string_append_c (new_contents, '\n'); @@ -436,17 +451,16 @@ nm_dhcp_dhclient_create_config (const char *interface, /* And add it to the dhclient configuration */ for (i = 0; i < reqs->len; i++) g_string_append_printf (new_contents, "also request %s;\n", (char *) reqs->pdata[i]); - g_ptr_array_free (reqs, TRUE); - for (i = 0; i < fqdn_opts->len; i++) { - char *t = g_ptr_array_index (fqdn_opts, i); + if (fqdn_opts) { + for (i = 0; i < fqdn_opts->len; i++) { + const char *t = fqdn_opts->pdata[i]; - if (i == 0) - g_string_append_printf (new_contents, "\n# FQDN options from %s\n", orig_path); - g_string_append_printf (new_contents, FQDN_TAG_PREFIX "%s\n", t); - g_free (t); + if (i == 0) + g_string_append_printf (new_contents, "\n# FQDN options from %s\n", orig_path); + g_string_append_printf (new_contents, FQDN_TAG_PREFIX "%s\n", t); + } } - g_ptr_array_free (fqdn_opts, TRUE); g_string_append_c (new_contents, '\n'); @@ -458,7 +472,7 @@ nm_dhcp_dhclient_create_config (const char *interface, interface, anycast_addr); } - return g_string_free (new_contents, FALSE); + return g_string_free (g_steal_pointer (&new_contents), FALSE); } /* Roughly follow what dhclient's quotify_buf() and pretty_escape() functions do */ @@ -553,9 +567,9 @@ error: GBytes * nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error) { - GBytes *duid = NULL; - char *contents; - char **line, **split, *p, *e; + gs_free char *contents = NULL; + gs_free const char **contents_v = NULL; + gsize i; if (!g_file_test (leasefile, G_FILE_TEST_EXISTS)) return NULL; @@ -563,25 +577,29 @@ nm_dhcp_dhclient_read_duid (const char *leasefile, GError **error) if (!g_file_get_contents (leasefile, &contents, NULL, error)) return NULL; - split = g_strsplit_set (contents, "\n\r", -1); - for (line = split; line && *line && (duid == NULL); line++) { - p = g_strstrip (*line); - if (g_str_has_prefix (p, DUID_PREFIX)) { - p += strlen (DUID_PREFIX); + contents_v = nm_utils_strsplit_set (contents, "\n\r"); + for (i = 0; contents_v && contents_v[i]; i++) { + const char *p = nm_str_skip_leading_spaces (contents_v[i]); + GBytes *duid; - /* look for trailing "; */ - e = p + strlen (p) - 2; - if (strcmp (e, "\";") != 0) - continue; - *e = '\0'; + if (!NM_STR_HAS_PREFIX (p, DUID_PREFIX)) + continue; - duid = nm_dhcp_dhclient_unescape_duid (p); - } + p += NM_STRLEN (DUID_PREFIX); + + g_strchomp ((char *) p); + + if (!NM_STR_HAS_SUFFIX (p, "\";")) + continue; + + ((char *) p)[strlen (p) - 2] = '\0'; + + duid = nm_dhcp_dhclient_unescape_duid (p); + if (duid) + return duid; } - g_free (contents); - g_strfreev (split); - return duid; + return NULL; } gboolean @@ -590,14 +608,12 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, GError **error) { gs_free char *escaped_duid = NULL; - gs_strfreev char **lines = NULL; - char **iter, *l; - GString *s; - gboolean success; + gs_free const char **lines = NULL; + nm_auto_free_gstring GString *s = NULL; + const char *const*iter; gsize len = 0; g_return_val_if_fail (leasefile != NULL, FALSE); - if (!duid) { nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "missing duid"); @@ -605,19 +621,17 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, } escaped_duid = nm_dhcp_dhclient_escape_duid (duid); - g_return_val_if_fail (escaped_duid != NULL, FALSE); + nm_assert (escaped_duid); if (g_file_test (leasefile, G_FILE_TEST_EXISTS)) { - char *contents = NULL; + gs_free char *contents = NULL; if (!g_file_get_contents (leasefile, &contents, &len, error)) { g_prefix_error (error, "failed to read lease file %s: ", leasefile); return FALSE; } - g_assert (contents); - lines = g_strsplit_set (contents, "\n\r", -1); - g_free (contents); + lines = nm_utils_strsplit_set_with_empty (contents, "\n\r"); } s = g_string_sized_new (len + 50); @@ -625,37 +639,38 @@ nm_dhcp_dhclient_save_duid (const char *leasefile, /* Preserve existing leasefile contents */ if (lines) { - for (iter = lines; iter && *iter; iter++) { - l = *iter; - while (g_ascii_isspace (*l)) - l++; + for (iter = lines; *iter; iter++) { + const char *str = *iter; + const char *l; + /* If we find an uncommented DUID in the file, check if * equal to the one we are going to write: if so, no need * to update the lease file, otherwise skip the old DUID. */ + l = nm_str_skip_leading_spaces (str); if (g_str_has_prefix (l, DUID_PREFIX)) { gs_strfreev char **split = NULL; split = g_strsplit (l, "\"", -1); - if (nm_streq0 (split[1], escaped_duid)) { - g_string_free (s, TRUE); + if ( split[0] + && nm_streq0 (split[1], escaped_duid)) return TRUE; - } + continue; } - if (*iter[0]) - g_string_append (s, *iter); + if (str) + g_string_append (s, str); /* avoid to add an extra '\n' at the end of file */ if ((iter[1]) != NULL) g_string_append_c (s, '\n'); } } - success = g_file_set_contents (leasefile, s->str, -1, error); - if (!success) + if (!g_file_set_contents (leasefile, s->str, -1, error)) { g_prefix_error (error, "failed to set DUID in lease file %s: ", leasefile); + return FALSE; + } - g_string_free (s, TRUE); - return success; + return TRUE; } diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c index 5227eea777..a8e0413da3 100644 --- a/src/dhcp/nm-dhcp-utils.c +++ b/src/dhcp/nm-dhcp-utils.c @@ -100,67 +100,56 @@ out: return have_routes; } -static const char ** -process_dhclient_rfc3442_route (const char **octets, - NMPlatformIP4Route *route, - gboolean *success) +static gboolean +process_dhclient_rfc3442_route (const char *const**p_octets, + NMPlatformIP4Route *route) { - const char **o = octets; - int addr_len = 0, i = 0; - long int tmp; - char *next_hop; - guint32 tmp_addr; - - *success = FALSE; - - if (!*o) - return o; /* no prefix */ - - tmp = strtol (*o, NULL, 10); - if (tmp < 0 || tmp > 32) /* 32 == max IP4 prefix length */ - return o; - - memset (route, 0, sizeof (*route)); - route->plen = tmp; + const char *const*o = *p_octets; + gs_free char *next_hop = NULL; + int addr_len; + int v_plen; + in_addr_t tmp_addr; + in_addr_t v_network = 0; + + v_plen = _nm_utils_ascii_str_to_int64 (*o, 10, 0, 32, -1); + if (v_plen == -1) + return FALSE; o++; - if (tmp > 0) - addr_len = ((tmp - 1) / 8) + 1; + addr_len = v_plen > 0 + ? ((v_plen - 1) / 8) + 1 + : 0; /* ensure there's at least the address + next hop left */ - if (g_strv_length ((char **) o) < addr_len + 4) - goto error; + if (NM_PTRARRAY_LEN (o) < addr_len + 4) + return FALSE; - if (tmp) { + if (v_plen > 0) { const char *addr[4] = { "0", "0", "0", "0" }; - char *str_addr; + gs_free char *str_addr = NULL; + int i; for (i = 0; i < addr_len; i++) addr[i] = *o++; str_addr = g_strjoin (".", addr[0], addr[1], addr[2], addr[3], NULL); - if (inet_pton (AF_INET, str_addr, &tmp_addr) <= 0) { - g_free (str_addr); - goto error; - } - g_free (str_addr); - route->network = nm_utils_ip4_address_clear_host_address (tmp_addr, tmp); + if (inet_pton (AF_INET, str_addr, &tmp_addr) <= 0) + return FALSE; + v_network = nm_utils_ip4_address_clear_host_address (tmp_addr, v_plen); } - /* Handle next hop */ next_hop = g_strjoin (".", o[0], o[1], o[2], o[3], NULL); - if (inet_pton (AF_INET, next_hop, &tmp_addr) <= 0) { - g_free (next_hop); - goto error; - } - route->gateway = tmp_addr; - g_free (next_hop); - - *success = TRUE; - return o + 4; /* advance to past the next hop */ + o += 4; + if (inet_pton (AF_INET, next_hop, &tmp_addr) <= 0) + return FALSE; -error: - return o; + *route = (NMPlatformIP4Route) { + .network = v_network, + .plen = v_plen, + .gateway = tmp_addr, + }; + *p_octets = o; + return TRUE; } static gboolean @@ -171,23 +160,23 @@ ip4_process_dhclient_rfc3442_routes (const char *iface, NMIP4Config *ip4_config, guint32 *gwaddr) { - char **octets, **o; + gs_free const char **octets = NULL; + const char *const*o; gboolean have_routes = FALSE; - NMPlatformIP4Route route; - gboolean success; - o = octets = g_strsplit_set (str, " .", 0); - if (g_strv_length (octets) < 5) { + octets = nm_utils_strsplit_set_with_empty (str, " ."); + if (NM_PTRARRAY_LEN (octets) < 5) { _LOG2W (LOGD_DHCP4, iface, "ignoring invalid classless static routes '%s'", str); - goto out; + return FALSE; } + o = octets; while (*o) { - memset (&route, 0, sizeof (route)); - o = (char **) process_dhclient_rfc3442_route ((const char **) o, &route, &success); - if (!success) { + NMPlatformIP4Route route; + + if (!process_dhclient_rfc3442_route (&o, &route)) { _LOG2W (LOGD_DHCP4, iface, "ignoring invalid classless static routes"); - break; + return have_routes; } have_routes = TRUE; @@ -211,8 +200,6 @@ ip4_process_dhclient_rfc3442_routes (const char *iface, } } -out: - g_strfreev (octets); return have_routes; } diff --git a/src/nm-dcb.c b/src/nm-dcb.c index a63fdf3d96..b2e59154f0 100644 --- a/src/nm-dcb.c +++ b/src/nm-dcb.c @@ -37,9 +37,11 @@ do_helper (const char *iface, const char *fmt, ...) { - char **argv = NULL, **split = NULL, *cmdline, *errmsg = NULL; - gboolean success = FALSE; - guint i, u; + gs_free const char **split = NULL; + gs_free char *cmdline = NULL; + gs_free const char **argv = NULL; + gsize i; + gsize u; va_list args; g_return_val_if_fail (fmt != NULL, FALSE); @@ -48,35 +50,31 @@ do_helper (const char *iface, cmdline = g_strdup_vprintf (fmt, args); va_end (args); - split = g_strsplit_set (cmdline, " ", 0); + split = nm_utils_strsplit_set_with_empty (cmdline, " "); if (!split) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "failure parsing %s command line", helper_names[which]); - goto out; + return FALSE; } /* Allocate space for path, custom arg, interface name, arguments, and NULL */ - i = u = 0; - argv = g_new0 (char *, g_strv_length (split) + 4); + i = 0; + argv = g_new (const char *, NM_PTRARRAY_LEN (split) + 4); argv[i++] = NULL; /* Placeholder for dcbtool path */ if (which == DCBTOOL) { argv[i++] = "sc"; argv[i++] = (char *) iface; } - while (u < g_strv_length (split)) - argv[i++] = split[u++]; + for (u = 0; split[u]; u++) + argv[i++] = split[u]; argv[i++] = NULL; - success = run_func (argv, which, user_data, error); - if (!success && error) - g_assert (*error); - -out: - if (split) - g_strfreev (split); - g_free (argv); - g_free (cmdline); - g_free (errmsg); - return success; + + if (!run_func ((char **) argv, which, user_data, error)) { + g_assert (!error || !*error); + return FALSE; + } + + return TRUE; } gboolean diff --git a/src/nm-logging.c b/src/nm-logging.c index 1ee9464541..511a4fdd66 100644 --- a/src/nm-logging.c +++ b/src/nm-logging.c @@ -302,7 +302,8 @@ nm_logging_setup (const char *level, NMLogDomain new_log_state[_LOGL_N_REAL]; NMLogLevel cur_log_level; NMLogLevel new_log_level; - char **tmp, **iter; + gs_free const char **domains_v = NULL; + gsize i_d; int i; gboolean had_platform_debug; gs_free char *domains_free = NULL; @@ -337,28 +338,24 @@ nm_logging_setup (const char *level, } } - tmp = g_strsplit_set (domains, ", ", 0); - for (iter = tmp; iter && *iter; iter++) { + domains_v = nm_utils_strsplit_set (domains, ", "); + for (i_d = 0; domains_v && domains_v[i_d]; i_d++) { + const char *s = domains_v[i_d]; + const char *p; const LogDesc *diter; NMLogLevel domain_log_level; NMLogDomain bits; - char *p; /* LOGD_VPN_PLUGIN is protected, that is, when setting ALL or DEFAULT, * it does not enable the verbose levels DEBUG and TRACE, because that * may expose sensitive data. */ NMLogDomain protect = LOGD_NONE; - if (!strlen (*iter)) - continue; - - p = strchr (*iter, ':'); + p = strchr (s, ':'); if (p) { - *p = '\0'; - if (!match_log_level (p + 1, &domain_log_level, error)) { - g_strfreev (tmp); + *((char *) p) = '\0'; + if (!match_log_level (p + 1, &domain_log_level, error)) return FALSE; - } } else domain_log_level = new_log_level; @@ -372,26 +369,26 @@ nm_logging_setup (const char *level, } /* Check for combined domains */ - if (!g_ascii_strcasecmp (*iter, LOGD_ALL_STRING)) { + if (!g_ascii_strcasecmp (s, LOGD_ALL_STRING)) { bits = LOGD_ALL; protect = LOGD_VPN_PLUGIN; - } else if (!g_ascii_strcasecmp (*iter, LOGD_DEFAULT_STRING)) { + } else if (!g_ascii_strcasecmp (s, LOGD_DEFAULT_STRING)) { bits = LOGD_DEFAULT; protect = LOGD_VPN_PLUGIN; - } else if (!g_ascii_strcasecmp (*iter, LOGD_DHCP_STRING)) + } else if (!g_ascii_strcasecmp (s, LOGD_DHCP_STRING)) bits = LOGD_DHCP; - else if (!g_ascii_strcasecmp (*iter, LOGD_IP_STRING)) + else if (!g_ascii_strcasecmp (s, LOGD_IP_STRING)) bits = LOGD_IP; /* Check for compatibility domains */ - else if (!g_ascii_strcasecmp (*iter, "HW")) + else if (!g_ascii_strcasecmp (s, "HW")) bits = LOGD_PLATFORM; - else if (!g_ascii_strcasecmp (*iter, "WIMAX")) + else if (!g_ascii_strcasecmp (s, "WIMAX")) continue; else { for (diter = &domain_desc[0]; diter->name; diter++) { - if (!g_ascii_strcasecmp (diter->name, *iter)) { + if (!g_ascii_strcasecmp (diter->name, s)) { bits = diter->num; break; } @@ -400,7 +397,7 @@ nm_logging_setup (const char *level, if (!bits) { if (!bad_domains) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_LOG_DOMAIN, - _("Unknown log domain '%s'"), *iter); + _("Unknown log domain '%s'"), s); return FALSE; } @@ -408,7 +405,7 @@ nm_logging_setup (const char *level, g_string_append (unrecognized, ", "); else unrecognized = g_string_new (NULL); - g_string_append (unrecognized, *iter); + g_string_append (unrecognized, s); continue; } } @@ -429,7 +426,6 @@ nm_logging_setup (const char *level, } } } - g_strfreev (tmp); g_clear_pointer (&gl_main.logging_domains_to_string, g_free); diff --git a/src/settings/plugins/ibft/nms-ibft-plugin.c b/src/settings/plugins/ibft/nms-ibft-plugin.c index 00b25068fc..47051995c1 100644 --- a/src/settings/plugins/ibft/nms-ibft-plugin.c +++ b/src/settings/plugins/ibft/nms-ibft-plugin.c @@ -64,31 +64,30 @@ static void read_connections (NMSIbftPlugin *self) { NMSIbftPluginPrivate *priv = NMS_IBFT_PLUGIN_GET_PRIVATE (self); - GSList *blocks = NULL, *iter; - GError *error = NULL; + nm_auto_free_ibft_blocks GSList *blocks = NULL; + GSList *iter; + gs_free_error GError *error = NULL; NMSIbftConnection *connection; if (!nms_ibft_reader_load_blocks ("/sbin/iscsiadm", &blocks, &error)) { nm_log_dbg (LOGD_SETTINGS, "ibft: failed to read iscsiadm records: %s", error->message); - g_error_free (error); return; } for (iter = blocks; iter; iter = iter->next) { connection = nms_ibft_connection_new (iter->data, &error); - if (connection) { - nm_log_info (LOGD_SETTINGS, "ibft: read connection '%s'", - nm_settings_connection_get_id (NM_SETTINGS_CONNECTION (connection))); - g_hash_table_insert (priv->connections, - g_strdup (nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (connection))), - connection); - } else { + if (!connection) { nm_log_warn (LOGD_SETTINGS, "ibft: failed to read iscsiadm record: %s", error->message); g_clear_error (&error); + continue; } - } - g_slist_free_full (blocks, (GDestroyNotify) g_ptr_array_unref); + nm_log_info (LOGD_SETTINGS, "ibft: read connection '%s'", + nm_settings_connection_get_id (NM_SETTINGS_CONNECTION (connection))); + g_hash_table_insert (priv->connections, + g_strdup (nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (connection))), + connection); + } } static GSList * diff --git a/src/settings/plugins/ibft/nms-ibft-reader.c b/src/settings/plugins/ibft/nms-ibft-reader.c index c6c1437651..fde3038321 100644 --- a/src/settings/plugins/ibft/nms-ibft-reader.c +++ b/src/settings/plugins/ibft/nms-ibft-reader.c @@ -46,8 +46,7 @@ remove_most_whitespace (const char *src) char *s_new, *s2; const char *svalue; - while (*src && g_ascii_isspace (*src)) - src++; + src = nm_str_skip_leading_spaces (src); svalue = strchr (src, '='); if (!svalue || svalue == src) @@ -94,24 +93,25 @@ nms_ibft_reader_load_blocks (const char *iscsiadm_path, { const char *argv[4] = { iscsiadm_path, "-m", "fw", NULL }; const char *envp[1] = { NULL }; - GSList *blocks = NULL; - char *out = NULL, *err = NULL; - int status = 0; - char **lines = NULL, **iter; + nm_auto_free_ibft_blocks GSList *blocks = NULL; + gs_free char *out = NULL; + gs_free char *err = NULL; + gs_free const char **lines = NULL; GPtrArray *block_lines = NULL; - gboolean success = FALSE; + gsize i; + int status = 0; g_return_val_if_fail (iscsiadm_path != NULL, FALSE); g_return_val_if_fail (out_blocks != NULL && *out_blocks == NULL, FALSE); if (!g_spawn_sync ("/", (char **) argv, (char **) envp, 0, NULL, NULL, &out, &err, &status, error)) - goto done; + return FALSE; if (!WIFEXITED (status)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "iBFT: %s exited abnormally.", iscsiadm_path); - goto done; + return FALSE; } if (WEXITSTATUS (status) != 0) { @@ -127,59 +127,47 @@ nms_ibft_reader_load_blocks (const char *iscsiadm_path, g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "iBFT: %s exited with error %d. Message: '%s'", iscsiadm_path, WEXITSTATUS (status), err ?: "(none)"); - goto done; + return FALSE; } nm_log_dbg (LOGD_SETTINGS, "iBFT records:\n%s", out); - lines = g_strsplit_set (out, "\n\r", -1); - for (iter = lines; iter && *iter; iter++) { - if (!*iter[0]) - continue; + lines = nm_utils_strsplit_set (out, "\n\r"); + for (i = 0; lines && lines[i]; i++) { + const char *ss = lines[i]; - if (!g_ascii_strncasecmp (*iter, TAG_BEGIN, NM_STRLEN (TAG_BEGIN))) { + if (!g_ascii_strncasecmp (ss, TAG_BEGIN, NM_STRLEN (TAG_BEGIN))) { if (block_lines) { PARSE_WARNING ("malformed iscsiadm record: missing END RECORD."); - g_ptr_array_unref (block_lines); + nm_clear_pointer (&block_lines, g_ptr_array_unref); } /* Start new record */ block_lines = g_ptr_array_new_full (15, g_free); - } else if (!g_ascii_strncasecmp (*iter, TAG_END, NM_STRLEN (TAG_END))) { + } else if (!g_ascii_strncasecmp (ss, TAG_END, NM_STRLEN (TAG_END))) { if (block_lines) { if (block_lines->len) - blocks = g_slist_prepend (blocks, block_lines); + blocks = g_slist_prepend (blocks, g_steal_pointer (&block_lines)); else - g_ptr_array_unref (block_lines); - block_lines = NULL; + g_ptr_array_unref (g_steal_pointer (&block_lines)); } } else if (block_lines) { - char *s = remove_most_whitespace (*iter); + char *s = remove_most_whitespace (ss); - if (s) + if (!s) { + PARSE_WARNING ("malformed iscsiadm record: no = in '%s'.", ss); + nm_clear_pointer (&block_lines, g_ptr_array_unref); + } else g_ptr_array_add (block_lines, s); - else { - PARSE_WARNING ("malformed iscsiadm record: no = in '%s'.", *iter); - g_clear_pointer (&block_lines, g_ptr_array_unref); - } } } if (block_lines) { PARSE_WARNING ("malformed iscsiadm record: missing # END RECORD."); - g_clear_pointer (&block_lines, g_ptr_array_unref); + nm_clear_pointer (&block_lines, g_ptr_array_unref); } - success = TRUE; - -done: - if (lines) - g_strfreev (lines); - g_free (out); - g_free (err); - if (success) - *out_blocks = blocks; - else - g_slist_free_full (blocks, (GDestroyNotify) g_ptr_array_unref); - return success; + + *out_blocks = g_steal_pointer (&blocks); + return TRUE; } #define ISCSI_HWADDR_TAG "iface.hwaddress" diff --git a/src/settings/plugins/ibft/nms-ibft-reader.h b/src/settings/plugins/ibft/nms-ibft-reader.h index 27500cc50b..baa81e99c4 100644 --- a/src/settings/plugins/ibft/nms-ibft-reader.h +++ b/src/settings/plugins/ibft/nms-ibft-reader.h @@ -23,6 +23,14 @@ #include "nm-connection.h" +static inline void +_nm_auto_free_ibft_blocks (GSList **p_blocks) +{ + if (*p_blocks) + g_slist_free_full (*p_blocks, (GDestroyNotify) g_ptr_array_unref); +} +#define nm_auto_free_ibft_blocks nm_auto (_nm_auto_free_ibft_blocks) + gboolean nms_ibft_reader_load_blocks (const char *iscsiadm_path, GSList **out_blocks, GError **error); diff --git a/src/settings/plugins/ibft/tests/test-ibft.c b/src/settings/plugins/ibft/tests/test-ibft.c index 4c45f574d2..f5b584a17b 100644 --- a/src/settings/plugins/ibft/tests/test-ibft.c +++ b/src/settings/plugins/ibft/tests/test-ibft.c @@ -40,16 +40,16 @@ static GPtrArray * read_block (const char *iscsiadm_path, const char *expected_mac) { - GSList *blocks = NULL, *iter; + nm_auto_free_ibft_blocks GSList *blocks = NULL; + GSList *iter; GPtrArray *block = NULL; GError *error = NULL; gboolean success; success = nms_ibft_reader_load_blocks (iscsiadm_path, &blocks, &error); - g_assert_no_error (error); - g_assert (success); - g_assert (blocks); + nmtst_assert_success (success, error); + g_assert (blocks); for (iter = blocks; iter; iter = iter->next) { const char *s_hwaddr = NULL; @@ -63,7 +63,6 @@ read_block (const char *iscsiadm_path, const char *expected_mac) } g_assert (block); - g_slist_free_full (blocks, (GDestroyNotify) g_ptr_array_unref); return block; } @@ -176,7 +175,7 @@ static void test_read_ibft_malformed (gconstpointer user_data) { const char *iscsiadm_path = user_data; - GSList *blocks = NULL; + nm_auto_free_ibft_blocks GSList *blocks = NULL; GError *error = NULL; gboolean success; @@ -185,9 +184,9 @@ test_read_ibft_malformed (gconstpointer user_data) NMTST_EXPECT_NM_WARN ("*malformed iscsiadm record*"); success = nms_ibft_reader_load_blocks (iscsiadm_path, &blocks, &error); - g_assert_no_error (error); - g_assert (success); - g_assert (blocks == NULL); + nmtst_assert_success (success, error); + + g_assert (!blocks); g_test_assert_expected_messages (); } 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 f9722b8f37..3393fca2e2 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -82,7 +82,8 @@ static char * get_full_file_path (const char *ifcfg_path, const char *file_path) { const char *base = file_path; - char *p, *ret, *dirname; + gs_free char *dirname = NULL; + char *p; g_return_val_if_fail (ifcfg_path != NULL, NULL); g_return_val_if_fail (file_path != NULL, NULL); @@ -95,9 +96,7 @@ get_full_file_path (const char *ifcfg_path, const char *file_path) base = p + 1; dirname = g_path_get_dirname (ifcfg_path); - ret = g_build_path ("/", dirname, base, NULL); - g_free (dirname); - return ret; + return g_build_path ("/", dirname, base, NULL); } /*****************************************************************************/ @@ -379,7 +378,7 @@ make_connection_setting (const char *file, NMSettingConnection *s_con; NMSettingConnectionLldp lldp; const char *ifcfg_name = NULL; - char *new_id; + gs_free char *new_id = NULL; const char *uuid; gs_free char *uuid_free = NULL; gs_free char *value = NULL; @@ -396,7 +395,6 @@ make_connection_setting (const char *file, new_id = make_connection_name (ifcfg, ifcfg_name, suggested, prefix); g_object_set (s_con, NM_SETTING_CONNECTION_ID, new_id, NULL); - g_free (new_id); /* Try for a UUID key before falling back to hashing the file name */ uuid = svGetValueStr (ifcfg, "UUID", &uuid_free); @@ -457,7 +455,7 @@ make_connection_setting (const char *file, if (v) { gs_free const char **items = NULL; - items = nm_utils_strsplit_set (v, " ", FALSE); + items = nm_utils_strsplit_set (v, " "); for (iter = items; iter && *iter; iter++) { if (!nm_setting_connection_add_permission (s_con, "user", *iter, NULL)) PARSE_WARNING ("invalid USERS item '%s'", *iter); @@ -473,7 +471,7 @@ make_connection_setting (const char *file, if (v) { gs_free const char **items = NULL; - items = nm_utils_strsplit_set (v, " \t", FALSE); + items = nm_utils_strsplit_set (v, " \t"); for (iter = items; iter && *iter; iter++) { if (!nm_setting_connection_add_secondary (s_con, *iter)) PARSE_WARNING ("secondary connection UUID '%s' already added", *iter); @@ -889,7 +887,7 @@ parse_route_line (const char *line, * Maybe later we want to support some form of quotation here. * Which of course, would be incompatible with initscripts. */ - words_free = nm_utils_strsplit_set (line, " \t\n", FALSE); + words_free = nm_utils_strsplit_set (line, " \t\n"); words = words_free ?: NM_PTRARRAY_EMPTY (const char *); @@ -1327,7 +1325,7 @@ parse_dns_options (NMSettingIPConfig *ip_config, const char *value) if (!nm_setting_ip_config_has_dns_options (ip_config)) nm_setting_ip_config_clear_dns_options (ip_config, TRUE); - options = nm_utils_strsplit_set (value, " ", FALSE); + options = nm_utils_strsplit_set (value, " "); if (options) { for (item = options; *item; item++) { if (!nm_setting_ip_config_add_dns_option (ip_config, *item)) @@ -1443,7 +1441,7 @@ make_match_setting (shvarFile *ifcfg) if (!v) return NULL; - strv = nm_utils_strsplit_set (v, " \t", TRUE); + strv = nm_utils_strsplit_set_full (v, " \t", NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING); if (strv) { for (i = 0; strv[i]; i++) { if (!s_match) @@ -1722,7 +1720,7 @@ make_ip4_setting (shvarFile *ifcfg, if (v) { gs_free const char **searches = NULL; - searches = nm_utils_strsplit_set (v, " ", FALSE); + searches = nm_utils_strsplit_set (v, " "); if (searches) { for (item = searches; *item; item++) { if (!nm_setting_ip_config_add_dns_search (s_ip4, *item)) @@ -1783,7 +1781,7 @@ make_ip4_setting (shvarFile *ifcfg, if (v) { gs_free const char **searches = NULL; - searches = nm_utils_strsplit_set (v, " ", FALSE); + searches = nm_utils_strsplit_set (v, " "); if (searches) { for (item = searches; *item; item++) { if (!nm_setting_ip_config_add_dns_search (s_ip4, *item)) @@ -1809,7 +1807,8 @@ static void read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *filename) { GDir *dir; - char *dirname, *base; + gs_free char *dirname = NULL; + gs_free char *base = NULL; NMIPAddress *base_addr = NULL; GError *err = NULL; @@ -1820,9 +1819,9 @@ read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *file base_addr = nm_setting_ip_config_get_address (s_ip4, 0); dirname = g_path_get_dirname (filename); - g_return_if_fail (dirname != NULL); + nm_assert (dirname != NULL); base = g_path_get_basename (filename); - g_return_if_fail (base != NULL); + nm_assert (base != NULL); dir = g_dir_open (dirname, 0, &err); if (dir) { @@ -1911,9 +1910,6 @@ read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *file PARSE_WARNING ("can not read directory '%s': %s", dirname, err->message); g_error_free (err); } - - g_free (base); - g_free (dirname); } static NMSetting * @@ -1922,10 +1918,9 @@ make_ip6_setting (shvarFile *ifcfg, gboolean routes_read, GError **error) { - NMSettingIPConfig *s_ip6 = NULL; + gs_unref_object NMSettingIPConfig *s_ip6 = NULL; const char *v; gs_free char *value = NULL; - char *route6_path = NULL; gboolean ipv6init, ipv6forwarding, dhcp6 = FALSE; char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; const char *ipv6addr, *ipv6addr_secondaries; @@ -2060,7 +2055,7 @@ make_ip6_setting (shvarFile *ifcfg, /* Don't bother to read IP, DNS and routes when IPv6 is disabled */ if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0) - return NM_SETTING (s_ip6); + return NM_SETTING (g_steal_pointer (&s_ip6)); nm_clear_g_free (&value); v = svGetValueStr (ifcfg, "DHCPV6_DUID", &value); @@ -2099,12 +2094,12 @@ make_ip6_setting (shvarFile *ifcfg, ipv6addr_secondaries ?: "", NULL); - list = nm_utils_strsplit_set (value, " ", FALSE); + list = nm_utils_strsplit_set (value, " "); for (iter = list, i = 0; iter && *iter; iter++, i++) { NMIPAddress *addr = NULL; if (!parse_full_ip6_address (ifcfg, *iter, i, &addr, error)) - goto error; + return NULL; if (!nm_setting_ip_config_add_address (s_ip6, addr)) PARSE_WARNING ("duplicate IP6 address"); @@ -2129,7 +2124,7 @@ make_ip6_setting (shvarFile *ifcfg, if (!nm_utils_ipaddr_valid (AF_INET6, v)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid IP6 address '%s'", v); - goto error; + return NULL; } g_object_set (s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, v, NULL); @@ -2172,18 +2167,19 @@ make_ip6_setting (shvarFile *ifcfg, /* Ignore IPv4 addresses */ } else { PARSE_WARNING ("invalid DNS server address %s", v); - goto error; + return NULL; } } if (!routes_read) { /* NOP */ } else { + gs_free char *route6_path = NULL; + /* Read static routes from route6-<interface> file */ route6_path = utils_get_route6_path (svFileGetName (ifcfg)); if (!read_route_file (AF_INET6, route6_path, s_ip6, error)) - goto error; - g_free (route6_path); + return NULL; } /* DNS searches */ @@ -2192,7 +2188,7 @@ make_ip6_setting (shvarFile *ifcfg, if (v) { gs_free const char **searches = NULL; - searches = nm_utils_strsplit_set (v, " ", FALSE); + searches = nm_utils_strsplit_set (v, " "); if (searches) { for (iter = searches; *iter; iter++) { if (!nm_setting_ip_config_add_dns_search (s_ip6, *iter)) @@ -2212,12 +2208,7 @@ make_ip6_setting (shvarFile *ifcfg, priority, NULL); - return NM_SETTING (s_ip6); - -error: - g_free (route6_path); - g_object_unref (s_ip6); - return NULL; + return NM_SETTING (g_steal_pointer (&s_ip6)); } static NMSetting * @@ -2551,7 +2542,7 @@ read_dcb_percent_array (shvarFile *ifcfg, return TRUE; } - split = nm_utils_strsplit_set (val, ",", FALSE); + split = nm_utils_strsplit_set (val, ","); if (NM_PTRARRAY_LEN (split) != 8) { PARSE_WARNING ("invalid %s percentage list value '%s'", prop, val); g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, @@ -2588,10 +2579,9 @@ make_dcb_setting (shvarFile *ifcfg, NMSetting **out_setting, GError **error) { - NMSettingDcb *s_dcb = NULL; + gs_unref_object NMSettingDcb *s_dcb = NULL; gboolean dcb_on; NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE; - char *val; g_return_val_if_fail (out_setting != NULL, FALSE); @@ -2600,31 +2590,28 @@ make_dcb_setting (shvarFile *ifcfg, return TRUE; s_dcb = (NMSettingDcb *) nm_setting_dcb_new (); - g_assert (s_dcb); /* FCOE */ if (!read_dcb_app (ifcfg, s_dcb, "FCOE", &dcb_flags_props[DCB_APP_FCOE_FLAGS], NM_SETTING_DCB_APP_FCOE_PRIORITY, error)) { - g_object_unref (s_dcb); return FALSE; } if (nm_setting_dcb_get_app_fcoe_flags (s_dcb) & NM_SETTING_DCB_FLAG_ENABLE) { + gs_free char *val = NULL; + val = svGetValueStr_cp (ifcfg, KEY_DCB_APP_FCOE_MODE); if (val) { - if (strcmp (val, NM_SETTING_DCB_FCOE_MODE_FABRIC) == 0 || - strcmp (val, NM_SETTING_DCB_FCOE_MODE_VN2VN) == 0) + if (NM_IN_STRSET (val, NM_SETTING_DCB_FCOE_MODE_FABRIC, + NM_SETTING_DCB_FCOE_MODE_VN2VN)) g_object_set (G_OBJECT (s_dcb), NM_SETTING_DCB_APP_FCOE_MODE, val, NULL); else { PARSE_WARNING ("invalid FCoE mode '%s'", val); g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "invalid FCoE mode"); - g_free (val); - g_object_unref (s_dcb); return FALSE; } - g_free (val); } } @@ -2633,7 +2620,6 @@ make_dcb_setting (shvarFile *ifcfg, &dcb_flags_props[DCB_APP_ISCSI_FLAGS], NM_SETTING_DCB_APP_ISCSI_PRIORITY, error)) { - g_object_unref (s_dcb); return FALSE; } @@ -2642,7 +2628,6 @@ make_dcb_setting (shvarFile *ifcfg, &dcb_flags_props[DCB_APP_FIP_FLAGS], NM_SETTING_DCB_APP_FIP_PRIORITY, error)) { - g_object_unref (s_dcb); return FALSE; } @@ -2657,7 +2642,6 @@ make_dcb_setting (shvarFile *ifcfg, "PFC", nm_setting_dcb_set_priority_flow_control, error)) { - g_object_unref (s_dcb); return FALSE; } @@ -2673,7 +2657,6 @@ make_dcb_setting (shvarFile *ifcfg, TRUE, nm_setting_dcb_set_priority_group_id, error)) { - g_object_unref (s_dcb); return FALSE; } @@ -2686,7 +2669,6 @@ make_dcb_setting (shvarFile *ifcfg, TRUE, nm_setting_dcb_set_priority_group_bandwidth, error)) { - g_object_unref (s_dcb); return FALSE; } @@ -2699,7 +2681,6 @@ make_dcb_setting (shvarFile *ifcfg, FALSE, nm_setting_dcb_set_priority_bandwidth, error)) { - g_object_unref (s_dcb); return FALSE; } @@ -2711,7 +2692,6 @@ make_dcb_setting (shvarFile *ifcfg, "STRICT", nm_setting_dcb_set_priority_strict_bandwidth, error)) { - g_object_unref (s_dcb); return FALSE; } @@ -2723,11 +2703,10 @@ make_dcb_setting (shvarFile *ifcfg, FALSE, nm_setting_dcb_set_priority_traffic_class, error)) { - g_object_unref (s_dcb); return FALSE; } - *out_setting = NM_SETTING (s_dcb); + *out_setting = NM_SETTING (g_steal_pointer (&s_dcb)); return TRUE; } @@ -2834,7 +2813,7 @@ make_wep_setting (shvarFile *ifcfg, GError **error) { gs_unref_object NMSettingWirelessSecurity *s_wsec = NULL; - char *value; + gs_free char *value = NULL; shvarFile *keys_ifcfg = NULL; int default_key_idx = 0; gboolean has_default_key = FALSE; @@ -2849,13 +2828,12 @@ make_wep_setting (shvarFile *ifcfg, if (default_key_idx == 0) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid default WEP key '%s'", value); - g_free (value); return NULL; } has_default_key = TRUE; default_key_idx--; /* convert to [0...3] */ g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, (guint) default_key_idx, NULL); - g_free (value); + nm_clear_g_free (&value); } /* Read WEP key flags */ @@ -2902,23 +2880,21 @@ make_wep_setting (shvarFile *ifcfg, value = svGetValueStr_cp (ifcfg, "SECURITYMODE"); if (value) { - char *lcase; + gs_free char *lcase = NULL; lcase = g_ascii_strdown (value, -1); - g_free (value); + nm_clear_g_free (&value); - if (!strcmp (lcase, "open")) { + if (nm_streq (lcase, "open")) { g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL); - } else if (!strcmp (lcase, "restricted")) { + } else if (nm_streq (lcase, "restricted")) { g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", NULL); } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid WEP authentication algorithm '%s'", lcase); - g_free (lcase); return NULL; } - g_free (lcase); } /* If no WEP keys were given, and the keys are not agent-owned, and no @@ -2963,7 +2939,7 @@ fill_wpa_ciphers (shvarFile *ifcfg, if (!p) return TRUE; - list = nm_utils_strsplit_set (p, " ", FALSE); + list = nm_utils_strsplit_set (p, " "); for (iter = list; iter && *iter; iter++, i++) { /* Ad-Hoc configurations cannot have pairwise ciphers, and can only * have one group cipher. Ignore any additional group ciphers and @@ -3233,7 +3209,7 @@ eap_peap_reader (const char *eap_method, } /* Handle options for the inner auth method */ - list = nm_utils_strsplit_set (v, " ", FALSE); + list = nm_utils_strsplit_set (v, " "); iter = list; if (iter) { if (NM_IN_STRSET (*iter, "MSCHAPV2", @@ -3311,7 +3287,7 @@ eap_ttls_reader (const char *eap_method, inner_auth = g_ascii_strdown (v, -1); /* Handle options for the inner auth method */ - list = nm_utils_strsplit_set (inner_auth, " ", FALSE); + list = nm_utils_strsplit_set (inner_auth, " "); iter = list; if (iter) { if (NM_IN_STRSET (*iter, "mschapv2", @@ -3372,7 +3348,7 @@ eap_fast_reader (const char *eap_method, if (fast_provisioning) { gs_free const char **list1 = NULL; - list1 = nm_utils_strsplit_set (fast_provisioning, " \t", FALSE); + list1 = nm_utils_strsplit_set (fast_provisioning, " \t"); for (iter = list1; iter && *iter; iter++) { if (strcmp (*iter, "allow-unauth") == 0) allow_unauth = TRUE; @@ -3406,7 +3382,7 @@ eap_fast_reader (const char *eap_method, } /* Handle options for the inner auth method */ - list = nm_utils_strsplit_set (inner_auth, " ", FALSE); + list = nm_utils_strsplit_set (inner_auth, " "); iter = list; if (iter) { if ( !strcmp (*iter, "MSCHAPV2") @@ -3486,7 +3462,7 @@ read_8021x_list_value (shvarFile *ifcfg, if (!v) return; - strv = nm_utils_strsplit_set (v, " \t", FALSE); + strv = nm_utils_strsplit_set (v, " \t"); if (strv) g_object_set (setting, prop_name, strv, NULL); } @@ -3515,7 +3491,7 @@ fill_8021x (shvarFile *ifcfg, return NULL; } - list = nm_utils_strsplit_set (v, " ", FALSE); + list = nm_utils_strsplit_set (v, " "); s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); @@ -3829,7 +3805,7 @@ transform_hwaddr_blacklist (const char *blacklist) const char **strv; gsize i, j; - strv = nm_utils_strsplit_set (blacklist, " \t", FALSE); + strv = nm_utils_strsplit_set (blacklist, " \t"); if (!strv) return NULL; for (i = 0, j = 0; strv[j]; j++) { @@ -4147,7 +4123,7 @@ parse_ethtool_option (const char *value, gs_free const char **words = NULL; guint i; - words = nm_utils_strsplit_set (value, NULL, FALSE); + words = nm_utils_strsplit_set (value, " \t\n"); if (!words) return; @@ -4418,7 +4394,7 @@ parse_ethtool_options (shvarFile *ifcfg, NMConnection *connection) gs_free const char **opts = NULL; const char *const *iter; - opts = nm_utils_strsplit_set (ethtool_opts, ";", FALSE); + opts = nm_utils_strsplit_set (ethtool_opts, ";"); for (iter = opts; iter && iter[0]; iter++) { /* in case of repeated wol_passwords, parse_ethtool_option() * will do the right thing and clear wol_password before resetting. */ @@ -4514,7 +4490,7 @@ make_wired_setting (shvarFile *ifcfg, gs_free const char **chans = NULL; guint32 num_chans; - chans = nm_utils_strsplit_set (value, ",", FALSE); + chans = nm_utils_strsplit_set (value, ","); num_chans = NM_PTRARRAY_LEN (chans); if (num_chans < 2 || num_chans > 3) { PARSE_WARNING ("invalid SUBCHANNELS '%s' (%u channels, 2 or 3 expected)", @@ -4548,22 +4524,23 @@ make_wired_setting (shvarFile *ifcfg, value = svGetValueStr_cp (ifcfg, "OPTIONS"); if (value) { - char **options, **iter; + gs_free const char **options = NULL; + gsize i; - iter = options = g_strsplit_set (value, " ", 0); - while (iter && *iter) { - char *equals = strchr (*iter, '='); + options = nm_utils_strsplit_set_with_empty (value, " "); + for (i = 0; options && options[i]; i++) { + const char *line = options[i]; + const char *equals; gboolean valid = FALSE; + equals = strchr (line, '='); if (equals) { - *equals = '\0'; - valid = nm_setting_wired_add_s390_option (s_wired, *iter, equals + 1); + ((char *) equals)[0] = '\0'; + valid = nm_setting_wired_add_s390_option (s_wired, line, equals + 1); } if (!valid) - PARSE_WARNING ("invalid s390 OPTION '%s'", *iter); - iter++; + PARSE_WARNING ("invalid s390 OPTION '%s'", line); } - g_strfreev (options); nm_clear_g_free (&value); } @@ -4837,7 +4814,7 @@ make_bond_setting (shvarFile *ifcfg, gs_free const char **items = NULL; const char *const *iter; - items = nm_utils_strsplit_set (v, " ", FALSE); + items = nm_utils_strsplit_set (v, " "); for (iter = items; iter && *iter; iter++) { gs_strfreev char **keys = NULL; const char *key, *val; @@ -5117,7 +5094,7 @@ handle_bridging_opts (NMSetting *setting, gs_free const char **items = NULL; const char *const *iter; - items = nm_utils_strsplit_set (value, " ", FALSE); + items = nm_utils_strsplit_set (value, " "); for (iter = items; iter && *iter; iter++) { gs_strfreev char **keys = NULL; const char *key, *val; @@ -5151,7 +5128,7 @@ read_bridge_vlans (shvarFile *ifcfg, array = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_bridge_vlan_unref); - strv = nm_utils_strsplit_set (value, ",", FALSE); + strv = nm_utils_strsplit_set (value, ","); if (strv) { for (iter = strv; *iter; iter++) { vlan = nm_bridge_vlan_from_str (*iter, &local); @@ -5382,7 +5359,7 @@ parse_prio_map_list (NMSettingVlan *s_vlan, v = svGetValueStr (ifcfg, key, &value); if (!v) return; - list = nm_utils_strsplit_set (v, ",", FALSE); + list = nm_utils_strsplit_set (v, ","); for (iter = list; iter && *iter; iter++) { if (!strchr (*iter, ':')) @@ -5487,7 +5464,7 @@ make_vlan_setting (shvarFile *ifcfg, gs_free const char **strv = NULL; const char *const *ptr; - strv = nm_utils_strsplit_set (v, ", ", FALSE); + strv = nm_utils_strsplit_set (v, ", "); for (ptr = strv; ptr && *ptr; ptr++) { if (nm_streq (*ptr, "GVRP") && gvrp == -1) vlan_flags |= NM_VLAN_FLAG_GVRP; @@ -5629,7 +5606,7 @@ check_dns_search_domains (shvarFile *ifcfg, NMSetting *s_ip4, NMSetting *s_ip6) gs_free const char **searches = NULL; const char *const *item; - searches = nm_utils_strsplit_set (v, " ", FALSE); + searches = nm_utils_strsplit_set (v, " "); if (searches) { for (item = searches; *item; item++) { if (!nm_setting_ip_config_add_dns_search (NM_SETTING_IP_CONFIG (s_ip6), *item)) |