all: merge branch 'th/strsplit'

https://github.com/NetworkManager/NetworkManager/pull/332
This commit is contained in:
Thomas Haller 2019-04-10 15:06:12 +02:00
commit ad77eed0d5
20 changed files with 882 additions and 561 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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"),

View file

@ -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;
}

View file

@ -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,

View file

@ -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,

View file

@ -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;
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);
g_assert (!NM_FLAGS_ANY (flags, ~( NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING
| NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY)));
args = (const char *const*) args_array->pdata;
/* 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];
words = nm_utils_strsplit_set (str, " \t\n", escape);
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)));
}
if (!args[0]) {
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);
}
}
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);
g_assert_cmpint (NM_PTRARRAY_LEN (words), ==, words_len);
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;
}
}
}
#define do_test_nm_utils_strsplit_set(str, ...) \
_do_test_nm_utils_strsplit_set (str, ##__VA_ARGS__, NULL)
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_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);
}
}
/*****************************************************************************/

View file

@ -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 "".
*
* 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.
* 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.
*
* 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).
* 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 "".
* 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)
nm_utils_strsplit_set_full (const char *str,
const char *delimiters,
NMUtilsStrsplitSetFlags flags)
{
const char **ptr, **ptr0;
gsize alloc_size, plen, i;
gsize str_len;
char *s0;
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
/* 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])
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;
}
str_len = strlen (str) + 1;
alloc_size = 8;
/* 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);
num_tokens = 1;
c_str = str;
while (TRUE) {
plen = 0;
s = s0;
ptr = ptr0;
while (G_LIKELY (!_char_lookup_has (ch_lookup, c_str[0]))) {
if (c_str[0] == '\0')
goto done1;
c_str++;
}
/* 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;
}
}
c_str++;
/* 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;
}
num_tokens++;
}
done1:
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) {
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);
}
ptr[plen++] = s;
nm_assert (s[0] && !_is_delimiter (s[0], delimiters_table, allow_escaping, escaped));
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 (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';
}

View file

@ -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);

View file

@ -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

View file

@ -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 (end)
return TRUE;
}
if (areq)
g_strfreev (areq);
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;
}

View file

@ -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;
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;
*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;
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);
o += 4;
if (inet_pton (AF_INET, next_hop, &tmp_addr) <= 0)
return FALSE;
*success = TRUE;
return o + 4; /* advance to past the next hop */
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;
}

View file

@ -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

View file

@ -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);

View file

@ -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 *

View file

@ -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"

View file

@ -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);

View file

@ -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 ();
}

View file

@ -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))