diff options
author | Thomas Haller <thaller@redhat.com> | 2017-09-18 20:15:07 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-09-18 20:15:07 +0200 |
commit | 63104b721356dce8f31113a85232b219d45bfd04 (patch) | |
tree | 8c90197342ca1b25248d103a033071b83ac4545d | |
parent | 3be7910520c11a407e202edf83d249e58951b534 (diff) | |
parent | 6d675a943b99d0ed5ff9c8360dcc485174a41401 (diff) | |
download | NetworkManager-63104b721356dce8f31113a85232b219d45bfd04.tar.gz |
ifcfg-rh: merge branch 'th/ifcfg-route-parse'
https://github.com/NetworkManager/NetworkManager/pull/28
-rw-r--r-- | libnm-core/nm-core-internal.h | 10 | ||||
-rw-r--r-- | libnm-core/nm-setting-ip-config.c | 24 | ||||
-rw-r--r-- | libnm-core/tests/test-general.c | 62 | ||||
-rw-r--r-- | shared/nm-utils/nm-glib.h | 29 | ||||
-rw-r--r-- | shared/nm-utils/nm-macros-internal.h | 8 | ||||
-rw-r--r-- | shared/nm-utils/nm-shared-utils.c | 182 | ||||
-rw-r--r-- | shared/nm-utils/nm-shared-utils.h | 30 | ||||
-rw-r--r-- | src/nm-core-utils.c | 4 | ||||
-rw-r--r-- | src/nm-core-utils.h | 19 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 2 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 1810 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 12 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/shvar.c | 4 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/shvar.h | 4 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 4 |
15 files changed, 1228 insertions, 976 deletions
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index e4211c42dd..4ad3dfe385 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -198,6 +198,16 @@ GHashTable *_nm_utils_copy_strdict (GHashTable *strdict); typedef gpointer (*NMUtilsCopyFunc) (gpointer); +gboolean _nm_ip_route_attribute_validate_all (const NMIPRoute *route); + +static inline void +_nm_auto_ip_route_unref (NMIPRoute **v) +{ + if (*v) + nm_ip_route_unref (*v); +} +#define nm_auto_ip_route_unref nm_auto (_nm_auto_ip_route_unref) + GPtrArray *_nm_utils_copy_slist_to_array (const GSList *list, NMUtilsCopyFunc copy_func, GDestroyNotify unref_func); diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c index ac23ede0dc..2a8f38f839 100644 --- a/libnm-core/nm-setting-ip-config.c +++ b/libnm-core/nm-setting-ip-config.c @@ -1289,7 +1289,7 @@ nm_ip_route_attribute_validate (const char *name, char *sep; switch (spec->str_type) { - case 'a': /* IP address */ + case 'a': /* IP address */ if (!nm_utils_ipaddr_valid (family, string)) { g_set_error (error, NM_CONNECTION_ERROR, @@ -1301,7 +1301,7 @@ nm_ip_route_attribute_validate (const char *name, return FALSE; } break; - case 'p': /* IP address + optional prefix */ + case 'p': /* IP address + optional prefix */ string_free = g_strdup (string); sep = strchr (string_free, '/'); if (sep) { @@ -1333,6 +1333,26 @@ nm_ip_route_attribute_validate (const char *name, return TRUE; } +gboolean +_nm_ip_route_attribute_validate_all (const NMIPRoute *route) +{ + GHashTableIter iter; + const char *key; + GVariant *val; + + g_return_val_if_fail (route, FALSE); + + if (!route->attributes) + return TRUE; + + g_hash_table_iter_init (&iter, route->attributes); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) { + if (!nm_ip_route_attribute_validate (key, val, route->family, NULL, NULL)) + return FALSE; + } + return TRUE; +} + /*****************************************************************************/ G_DEFINE_ABSTRACT_TYPE (NMSettingIPConfig, nm_setting_ip_config, NM_TYPE_SETTING) diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index d33a6e87d2..e977e418fe 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -98,6 +98,67 @@ test_nm_g_slice_free_fcn (void) /*****************************************************************************/ +static void +_do_test_nm_utils_strsplit_set (const char *str, ...) +{ + gs_unref_ptrarray GPtrArray *args_array = g_ptr_array_new (); + const char *const*args; + gs_free const char **words = NULL; + const char *arg; + gsize i; + va_list ap; + + 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); + + args = (const char *const*) args_array->pdata; + + words = nm_utils_strsplit_set (str, " \t\n"); + + if (!args[0]) { + g_assert (!words); + g_assert ( !str + || NM_STRCHAR_ALL (str, ch, NM_IN_SET (ch, ' ', '\t', '\n'))); + 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 (NM_STRCHAR_ALL (args[i], ch, !NM_IN_SET (ch, ' ', '\t', '\n'))); + g_assert_cmpstr (args[i], ==, words[i]); + } +} + +#define do_test_nm_utils_strsplit_set(str, ...) \ + _do_test_nm_utils_strsplit_set (str, ##__VA_ARGS__, NULL) + +static void +test_nm_utils_strsplit_set (void) +{ + do_test_nm_utils_strsplit_set (NULL); + do_test_nm_utils_strsplit_set (""); + do_test_nm_utils_strsplit_set ("\t"); + do_test_nm_utils_strsplit_set (" \t\n"); + do_test_nm_utils_strsplit_set ("a", "a"); + do_test_nm_utils_strsplit_set ("a b", "a", "b"); + do_test_nm_utils_strsplit_set ("a\rb", "a\rb"); + do_test_nm_utils_strsplit_set (" a\rb ", "a\rb"); + do_test_nm_utils_strsplit_set (" a bbbd afds ere", "a", "bbbd", "afds", "ere"); + do_test_nm_utils_strsplit_set ("1 2 3 4 5 6 7 8 9 0 " + "1 2 3 4 5 6 7 8 9 0 " + "1 2 3 4 5 6 7 8 9 0", + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", + "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"); +} + +/*****************************************************************************/ + typedef struct { int val; int idx; @@ -6201,6 +6262,7 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/test_c_list_sort", test_c_list_sort); g_test_add_func ("/core/general/test_dedup_multi", test_dedup_multi); g_test_add_func ("/core/general/test_utils_str_utf8safe", test_utils_str_utf8safe); + g_test_add_func ("/core/general/test_nm_utils_strsplit_set", test_nm_utils_strsplit_set); g_test_add_func ("/core/general/test_nm_in_set", test_nm_in_set); g_test_add_func ("/core/general/test_nm_in_strset", test_nm_in_strset); g_test_add_func ("/core/general/test_setting_vpn_items", test_setting_vpn_items); diff --git a/shared/nm-utils/nm-glib.h b/shared/nm-utils/nm-glib.h index dd18756a16..4ef538e441 100644 --- a/shared/nm-utils/nm-glib.h +++ b/shared/nm-utils/nm-glib.h @@ -452,4 +452,33 @@ _nm_g_variant_new_take_string (gchar *string) } #define g_variant_new_take_string _nm_g_variant_new_take_string +#if !GLIB_CHECK_VERSION(2, 38, 0) +_nm_printf (1, 2) +static inline GVariant * +_nm_g_variant_new_printf (const char *format_string, ...) +{ + char *string; + va_list ap; + + g_return_val_if_fail (format_string, NULL); + + va_start (ap, format_string); + string = g_strdup_vprintf (format_string, ap); + va_end (ap); + + return g_variant_new_take_string (string); +} +#define g_variant_new_printf(...) _nm_g_variant_new_printf(__VA_ARGS__) +#else +#define g_variant_new_printf(...) \ + ({ \ + GVariant *_v; \ + \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + _v = g_variant_new_printf (__VA_ARGS__); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + _v; \ + }) +#endif + #endif /* __NM_GLIB_H__ */ diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index 5564197566..b946a276ca 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -26,16 +26,16 @@ #include <stdlib.h> #include <errno.h> -#include "nm-glib.h" - -/*****************************************************************************/ - #define _nm_packed __attribute__ ((packed)) #define _nm_unused __attribute__ ((unused)) #define _nm_pure __attribute__ ((pure)) #define _nm_const __attribute__ ((const)) #define _nm_printf(a,b) __attribute__ ((__format__ (__printf__, a, b))) +#include "nm-glib.h" + +/*****************************************************************************/ + #define nm_offsetofend(t,m) (G_STRUCT_OFFSET (t,m) + sizeof (((t *) NULL)->m)) #define nm_auto(fcn) __attribute__ ((cleanup(fcn))) diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c index 0109818a19..0810d7b1c1 100644 --- a/shared/nm-utils/nm-shared-utils.c +++ b/shared/nm-utils/nm-shared-utils.c @@ -32,6 +32,10 @@ const void *const _NM_PTRARRAY_EMPTY[1] = { NULL }; /*****************************************************************************/ +const NMIPAddr nm_ip_addr_zero = { 0 }; + +/*****************************************************************************/ + void nm_utils_strbuf_append_c (char **buf, gsize *len, char c) { @@ -170,15 +174,11 @@ nm_utils_ip_is_site_local (int addr_family, /*****************************************************************************/ gboolean -nm_utils_parse_inaddr (const char *text, - int family, - char **out_addr) +nm_utils_parse_inaddr_bin (const char *text, + int family, + gpointer out_addr) { - union { - in_addr_t v4; - struct in6_addr v6; - } addrbin; - char addrstr_buf[MAX (INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; + NMIPAddr addrbin; g_return_val_if_fail (text, FALSE); @@ -187,35 +187,49 @@ nm_utils_parse_inaddr (const char *text, else g_return_val_if_fail (NM_IN_SET (family, AF_INET, AF_INET6), FALSE); - if (inet_pton (family, text, &addrbin) != 1) + if (inet_pton (family, text, out_addr ?: &addrbin) != 1) return FALSE; + return TRUE; +} +gboolean +nm_utils_parse_inaddr (const char *text, + int family, + char **out_addr) +{ + NMIPAddr addrbin; + char addrstr_buf[MAX (INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; + + if (!nm_utils_parse_inaddr_bin (text, family, &addrbin)) + return FALSE; NM_SET_OUT (out_addr, g_strdup (inet_ntop (family, &addrbin, addrstr_buf, sizeof (addrstr_buf)))); return TRUE; } gboolean -nm_utils_parse_inaddr_prefix (const char *text, - int family, - char **out_addr, - int *out_prefix) +nm_utils_parse_inaddr_prefix_bin (const char *text, + int family, + gpointer out_addr, + int *out_prefix) { gs_free char *addrstr_free = NULL; int prefix = -1; const char *slash; const char *addrstr; - union { - in_addr_t v4; - struct in6_addr v6; - } addrbin; - char addrstr_buf[MAX (INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; + NMIPAddr addrbin; + int addr_len; g_return_val_if_fail (text, FALSE); if (family == AF_UNSPEC) family = strchr (text, ':') ? AF_INET6 : AF_INET; + + if (family == AF_INET) + addr_len = sizeof (in_addr_t); + else if (family == AF_INET6) + addr_len = sizeof (struct in6_addr); else - g_return_val_if_fail (NM_IN_SET (family, AF_INET, AF_INET6), FALSE); + g_return_val_if_reached (FALSE); slash = strchr (text, '/'); if (slash) @@ -235,11 +249,27 @@ nm_utils_parse_inaddr_prefix (const char *text, return FALSE; } - NM_SET_OUT (out_addr, g_strdup (inet_ntop (family, &addrbin, addrstr_buf, sizeof (addrstr_buf)))); + if (out_addr) + memcpy (out_addr, &addrbin, addr_len); NM_SET_OUT (out_prefix, prefix); return TRUE; } +gboolean +nm_utils_parse_inaddr_prefix (const char *text, + int family, + char **out_addr, + int *out_prefix) +{ + NMIPAddr addrbin; + char addrstr_buf[MAX (INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; + + if (!nm_utils_parse_inaddr_prefix_bin (text, family, &addrbin, out_prefix)) + return FALSE; + NM_SET_OUT (out_addr, g_strdup (inet_ntop (family, &addrbin, addrstr_buf, sizeof (addrstr_buf)))); + return TRUE; +} + /*****************************************************************************/ /* _nm_utils_ascii_str_to_int64: @@ -295,6 +325,118 @@ _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 ma /*****************************************************************************/ /** + * nm_utils_strsplit_set: + * @str: the string to split. + * @delimiters: the set of delimiters. If %NULL, defaults to " \t\n", + * like bash's $IFS. + * + * 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. + * + * 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). + * 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(). + */ +const char ** +nm_utils_strsplit_set (const char *str, const char *delimiters) +{ + const char **ptr, **ptr0; + gsize alloc_size, plen, i; + gsize str_len; + char *s0; + char *s; + guint8 delimiters_table[256]; + + if (!str) + return NULL; + + /* initialize lookup table for delimiter */ + if (!delimiters) + delimiters = " \t\n"; + memset (delimiters_table, 0, sizeof (delimiters_table)); + for (i = 0; delimiters[i]; i++) + delimiters_table[(guint8) delimiters[i]] = 1; + +#define _is_delimiter(ch, delimiters_table) \ + ((delimiters_table)[(guint8) (ch)] != 0) + + /* skip initial delimiters, and return of the remaining string is + * empty. */ + while (_is_delimiter (str[0], delimiters_table)) + str++; + if (!str[0]) + 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); + + plen = 0; + s = s0; + ptr = ptr0; + + 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)); + + while (TRUE) { + s++; + if (_is_delimiter (s[0], delimiters_table)) + break; + if (s[0] == '\0') + goto done; + } + + s[0] = '\0'; + s++; + while (_is_delimiter (s[0], delimiters_table)) + s++; + if (s[0] == '\0') + break; + } +done: + ptr[plen] = NULL; + + 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); + } + + return ptr; +} + +/** * nm_utils_strv_find_first: * @list: the strv list to search * @len: the length of the list, or a negative value if @list is %NULL terminated. diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index 065e629b4e..4a93016af1 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -22,6 +22,25 @@ #ifndef __NM_SHARED_UTILS_H__ #define __NM_SHARED_UTILS_H__ +#include <netinet/in.h> + +/*****************************************************************************/ + +typedef struct { + union { + guint8 addr_ptr[1]; + in_addr_t addr4; + struct in6_addr addr6; + + /* NMIPAddr is really a union for IP addresses. + * However, as ethernet addresses fit in here nicely, use + * it also for an ethernet MAC address. */ + guint8 addr_eth[6 /*ETH_ALEN*/]; + }; +} NMIPAddr; + +extern const NMIPAddr nm_ip_addr_zero; + /*****************************************************************************/ #define NM_CMP_RETURN(c) \ @@ -134,6 +153,8 @@ void nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str); /*****************************************************************************/ +const char **nm_utils_strsplit_set (const char *str, const char *delimiters); + gssize nm_utils_strv_find_first (char **list, gssize len, const char *needle); char **_nm_utils_strv_cleanup (char **strv, @@ -151,10 +172,19 @@ gboolean nm_utils_ip_is_site_local (int addr_family, /*****************************************************************************/ +gboolean nm_utils_parse_inaddr_bin (const char *text, + int family, + gpointer out_addr); + gboolean nm_utils_parse_inaddr (const char *text, int family, char **out_addr); +gboolean nm_utils_parse_inaddr_prefix_bin (const char *text, + int family, + gpointer out_addr, + int *out_prefix); + gboolean nm_utils_parse_inaddr_prefix (const char *text, int family, char **out_addr, diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 5cb53982e0..88614278f1 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -110,10 +110,6 @@ _nm_utils_set_testing (NMUtilsTestFlags flags) /*****************************************************************************/ -const NMIPAddr nm_ip_addr_zero = NMIPAddrInit; - -/*****************************************************************************/ - static GSList *_singletons = NULL; static gboolean _singletons_shutdown = FALSE; diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index 9956d96ac3..2561b6ec6b 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -90,25 +90,6 @@ GETTER (void) \ /*****************************************************************************/ -typedef struct { - union { - guint8 addr_ptr[1]; - in_addr_t addr4; - struct in6_addr addr6; - - /* NMIPAddr is really a union for IP addresses. - * However, as ethernet addresses fit in here nicely, use - * it also for an ethernet MAC address. */ - guint8 addr_eth[6 /*ETH_ALEN*/]; - }; -} NMIPAddr; - -extern const NMIPAddr nm_ip_addr_zero; - -#define NMIPAddrInit { .addr6 = IN6ADDR_ANY_INIT } - -/*****************************************************************************/ - guint nm_utils_in6_addr_hash (const struct in6_addr *addr); gboolean nm_ethernet_address_is_valid (gconstpointer addr, gssize len); diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 5c952a0b23..003df4e950 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2087,7 +2087,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) || tb[RTA_GATEWAY] || tb[RTA_FLOW]) { int ifindex = 0; - NMIPAddr gateway = NMIPAddrInit; + NMIPAddr gateway = { }; if (tb[RTA_OIF]) ifindex = nla_get_u32 (tb[RTA_OIF]); 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 ae720b9803..877ce13d68 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -128,8 +128,13 @@ make_connection_setting (const char *file, NMSettingConnection *s_con; NMSettingConnectionLldp lldp; const char *ifcfg_name = NULL; - char *new_id, *uuid = NULL, *zone = NULL, *value; + char *new_id; + const char *uuid; + gs_free char *uuid_free = NULL; + gs_free char *value = NULL; + const char *v; gs_free char *stable_id = NULL; + const char *const *iter; ifcfg_name = utils_get_ifcfg_name (file, TRUE); if (!ifcfg_name) @@ -142,38 +147,38 @@ make_connection_setting (const char *file, g_free (new_id); /* Try for a UUID key before falling back to hashing the file name */ - uuid = svGetValueStr_cp (ifcfg, "UUID"); - if (!uuid) - uuid = nm_utils_uuid_generate_from_string (svFileGetName (ifcfg), -1, NM_UTILS_UUID_TYPE_LEGACY, NULL); + uuid = svGetValueStr (ifcfg, "UUID", &uuid_free); + if (!uuid) { + uuid_free = nm_utils_uuid_generate_from_string (svFileGetName (ifcfg), -1, NM_UTILS_UUID_TYPE_LEGACY, NULL); + uuid = uuid_free; + } g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, type, NM_SETTING_CONNECTION_UUID, uuid, NM_SETTING_CONNECTION_STABLE_ID, svGetValue (ifcfg, "STABLE_ID", &stable_id), NULL); - g_free (uuid); - value = svGetValueStr_cp (ifcfg, "DEVICE"); - if (value) { + v = svGetValueStr (ifcfg, "DEVICE", &value); + if (v) { GError *error = NULL; - if (nm_utils_is_valid_iface_name (value, &error)) { + if (nm_utils_is_valid_iface_name (v, &error)) { g_object_set (s_con, - NM_SETTING_CONNECTION_INTERFACE_NAME, value, + NM_SETTING_CONNECTION_INTERFACE_NAME, v, NULL); } else { - PARSE_WARNING ("invalid DEVICE name '%s': %s", value, error->message); + PARSE_WARNING ("invalid DEVICE name '%s': %s", v, error->message); g_error_free (error); } - g_free (value); } - value = svGetValueStr_cp (ifcfg, "LLDP"); - if (!g_strcmp0 (value, "rx")) + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "LLDP", &value); + if (nm_streq0 (v, "rx")) lldp = NM_SETTING_CONNECTION_LLDP_ENABLE_RX; else - lldp = svParseBoolean (value, NM_SETTING_CONNECTION_LLDP_DEFAULT); - g_free (value); + lldp = svParseBoolean (v, NM_SETTING_CONNECTION_LLDP_DEFAULT); /* Missing ONBOOT is treated as "ONBOOT=true" by the old network service */ g_object_set (s_con, @@ -192,68 +197,62 @@ make_connection_setting (const char *file, NM_SETTING_CONNECTION_LLDP, lldp, NULL); - value = svGetValueStr_cp (ifcfg, "USERS"); - if (value) { - char **items, **iter; + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "USERS", &value); + if (v) { + gs_free const char **items = NULL; - items = g_strsplit_set (value, " ", -1); + items = nm_utils_strsplit_set (v, " "); for (iter = items; iter && *iter; iter++) { - if (strlen (*iter)) { - if (!nm_setting_connection_add_permission (s_con, "user", *iter, NULL)) - PARSE_WARNING ("invalid USERS item '%s'", *iter); - } + if (!nm_setting_connection_add_permission (s_con, "user", *iter, NULL)) + PARSE_WARNING ("invalid USERS item '%s'", *iter); } - g_free (value); - g_strfreev (items); } - zone = svGetValueStr_cp (ifcfg, "ZONE"); - g_object_set (s_con, NM_SETTING_CONNECTION_ZONE, zone, NULL); - g_free (zone); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "ZONE", &value); + g_object_set (s_con, NM_SETTING_CONNECTION_ZONE, v, NULL); - value = svGetValueStr_cp (ifcfg, "SECONDARY_UUIDS"); - if (value) { - char **items, **iter; + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "SECONDARY_UUIDS", &value); + if (v) { + gs_free const char **items = NULL; - items = g_strsplit_set (value, " \t", -1); + items = nm_utils_strsplit_set (v, " \t"); for (iter = items; iter && *iter; iter++) { - if (strlen (*iter)) { - if (!nm_setting_connection_add_secondary (s_con, *iter)) - PARSE_WARNING ("secondary connection UUID '%s' already added", *iter); - } + if (!nm_setting_connection_add_secondary (s_con, *iter)) + PARSE_WARNING ("secondary connection UUID '%s' already added", *iter); } - g_free (value); - g_strfreev (items); } - value = svGetValueStr_cp (ifcfg, "BRIDGE_UUID"); - if (!value) - value = svGetValueStr_cp (ifcfg, "BRIDGE"); - if (value) { + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "BRIDGE_UUID", &value); + if (!v) + v = svGetValueStr (ifcfg, "BRIDGE", &value); + if (v) { const char *old_value; if ((old_value = nm_setting_connection_get_master (s_con))) { PARSE_WARNING ("Already configured as slave of %s. Ignoring BRIDGE=\"%s\"", - old_value, value); + old_value, v); } else { - g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL); + g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, v, NULL); g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BRIDGE_SETTING_NAME, NULL); } - g_free (value); } - value = svGetValueStr_cp (ifcfg, "GATEWAY_PING_TIMEOUT"); - if (value) { + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "GATEWAY_PING_TIMEOUT", &value); + if (v) { gint64 tmp; - tmp = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXINT32 - 1, -1); + tmp = _nm_utils_ascii_str_to_int64 (v, 10, 0, G_MAXINT32 - 1, -1); if (tmp >= 0) g_object_set (s_con, NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, (guint) tmp, NULL); else PARSE_WARNING ("invalid GATEWAY_PING_TIMEOUT time"); - g_free (value); } switch (svGetValueBoolean (ifcfg, "CONNECTION_METERED", -1)) { @@ -344,6 +343,7 @@ read_full_ip4_address (shvarFile *ifcfg, char prefix_tag[256]; guint32 ipaddr; gs_free char *value = NULL; + const char *v; int prefix = 0; gboolean has_key; guint32 a; @@ -378,12 +378,12 @@ read_full_ip4_address (shvarFile *ifcfg, /* Prefix */ numbered_tag (prefix_tag, "PREFIX", which); - value = svGetValueStr_cp (ifcfg, prefix_tag); - if (value) { - prefix = _nm_utils_ascii_str_to_int64 (value, 10, 0, 32, -1); + v = svGetValueStr (ifcfg, prefix_tag, &value); + if (v) { + prefix = _nm_utils_ascii_str_to_int64 (v, 10, 0, 32, -1); if (prefix < 0) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid IP4 prefix '%s'", value); + "Invalid IP4 prefix '%s'", v); return FALSE; } } else { @@ -412,133 +412,440 @@ read_full_ip4_address (shvarFile *ifcfg, return FALSE; } -/* - * Use looser syntax to comprise all the possibilities. - * The validity must be checked after the match. - */ -#define IPV4_ADDR_REGEX "(?:[0-9]{1,3}\\.){3}[0-9]{1,3}" -#define IPV6_ADDR_REGEX "[0-9A-Fa-f:.]+" - -/* - * NOTE: The regexes below don't describe all variants allowed by 'ip route add', - * namely destination IP without 'to' keyword is recognized just at line start. - */ +/*****************************************************************************/ static gboolean -parse_route_options (NMIPRoute *route, int family, const char *line, GError **error) +parse_route_line_is_comment (const char *line) { - GRegex *regex = NULL; - GMatchInfo *match_info = NULL; - gboolean success = FALSE; - static const char *metrics[] = { NM_IP_ROUTE_ATTRIBUTE_WINDOW, NM_IP_ROUTE_ATTRIBUTE_CWND, - NM_IP_ROUTE_ATTRIBUTE_INITCWND, NM_IP_ROUTE_ATTRIBUTE_INITRWND, - NM_IP_ROUTE_ATTRIBUTE_MTU, NULL }; - char buffer[1024]; - int i; + /* we obtained the line from a legacy route file. Here we skip + * empty lines and comments. + * + * initscripts compares: "$line" =~ '^[[:space:]]*(\#.*)?$' + */ + while (NM_IN_SET (line[0], ' ', '\t')) + line++; + if (NM_IN_SET (line[0], '\0', '#')) + return TRUE; + return FALSE; +} + +/*****************************************************************************/ + +typedef struct { + const char *key; + + /* the element is not available in this case. */ + bool disabled:1; + + /* whether the element is to be ignored. Ignord is different from + * "disabled", because we still parse the option, but don't use it. */ + bool ignore:1; + + bool int_base_16:1; + + /* the type, one of PARSE_LINE_TYPE_* */ + char type; + + /* whether the command line option was found, and @v is + * initialized. */ + bool has:1; + + union { + guint8 uint8; + guint32 uint32; + struct { + guint32 uint32; + bool lock:1; + } uint32_with_lock; + struct { + NMIPAddr addr; + guint8 plen; + bool has_plen:1; + } addr; + } v; + +} ParseLineInfo; - g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); +enum { + /* route attributes */ + PARSE_LINE_ATTR_ROUTE_SRC, + PARSE_LINE_ATTR_ROUTE_FROM, + PARSE_LINE_ATTR_ROUTE_TOS, + PARSE_LINE_ATTR_ROUTE_WINDOW, + PARSE_LINE_ATTR_ROUTE_CWND, + PARSE_LINE_ATTR_ROUTE_INITCWND, + PARSE_LINE_ATTR_ROUTE_INITRWND, + PARSE_LINE_ATTR_ROUTE_MTU, + + /* iproute2 arguments that only matter when parsing the file. */ + PARSE_LINE_ATTR_ROUTE_TO, + PARSE_LINE_ATTR_ROUTE_VIA, + PARSE_LINE_ATTR_ROUTE_METRIC, + + /* iproute2 paramters that are well known and that we silently ignore. */ + PARSE_LINE_ATTR_ROUTE_DEV, +}; + +#define PARSE_LINE_TYPE_UINT8 '8' +#define PARSE_LINE_TYPE_UINT32 'u' +#define PARSE_LINE_TYPE_UINT32_WITH_LOCK 'l' +#define PARSE_LINE_TYPE_ADDR 'a' +#define PARSE_LINE_TYPE_ADDR_WITH_PREFIX 'p' +#define PARSE_LINE_TYPE_IFNAME 'i' + +/** + * parse_route_line: + * @line: the line to parse. This is either a line from the route-* or route6-* file, + * or the numbered OPTIONS setting. + * @addr_family: the address family. + * @options_route: (in-out): when line is from the OPTIONS setting, this is a pre-created + * route object that is completed with the settings from options. Otherwise, + * it shall point to %NULL and a new route is created and returned. + * @out_route: (out): (transfer-full): (allow-none): the parsed %NMIPRoute instance. + * In case a @options_route is passed in, it returns the input route that was modified + * in-place. But the caller must unref the returned route in either case. + * @error: the failure description. + * + * Parsing the route options line has two modes: one for the numbered OPTIONS + * setting, and one for initscript's handle_ip_file(), which takes the lines + * and passes them to `ip route add`. The modes are similar, but certain properties + * are not allowed for OPTIONS. + * The mode is differenciated by having an @options_route argument. + * + * Returns: returns a negative errno on failure. On success, it returns 0 + * and @out_route. + */ +static int +parse_route_line (const char *line, + int addr_family, + NMIPRoute *options_route, + NMIPRoute **out_route, + GError **error) +{ + nm_auto_ip_route_unref NMIPRoute *route = NULL; + gs_free const char **words = NULL; + const char *s; + gsize i_words; + guint i; + char buf1[256]; + char buf2[256]; + ParseLineInfo infos[] = { + [PARSE_LINE_ATTR_ROUTE_SRC] = { .key = NM_IP_ROUTE_ATTRIBUTE_SRC, + .type = PARSE_LINE_TYPE_ADDR, }, + [PARSE_LINE_ATTR_ROUTE_FROM] = { .key = NM_IP_ROUTE_ATTRIBUTE_FROM, + .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, + .disabled = (addr_family != AF_INET6), }, + [PARSE_LINE_ATTR_ROUTE_TOS] = { .key = NM_IP_ROUTE_ATTRIBUTE_TOS, + .type = PARSE_LINE_TYPE_UINT8, + .int_base_16 = TRUE, + .ignore = (addr_family != AF_INET), }, + [PARSE_LINE_ATTR_ROUTE_WINDOW] = { .key = NM_IP_ROUTE_ATTRIBUTE_WINDOW, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_CWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_CWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_INITCWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITCWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_INITRWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITRWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_MTU] = { .key = NM_IP_ROUTE_ATTRIBUTE_MTU, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + + [PARSE_LINE_ATTR_ROUTE_TO] = { .key = "to", + .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, + .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_VIA] = { .key = "via", + .type = PARSE_LINE_TYPE_ADDR, + .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_METRIC] = { .key = "metric", + .type = PARSE_LINE_TYPE_UINT32, + .disabled = (options_route != NULL), }, + + [PARSE_LINE_ATTR_ROUTE_DEV] = { .key = "dev", + .type = PARSE_LINE_TYPE_IFNAME, + .ignore = TRUE, + .disabled = (options_route != NULL), }, + }; + + nm_assert (line); + nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); + nm_assert (!options_route || nm_ip_route_get_family (options_route) == addr_family); + + /* initscripts read the legacy route file line-by-line and + * use it as `ip route add $line`, thus doing split+glob. + * Splitting on IFS (which we consider '<space><tab><newline>') + * and globbing (which we obviously don't do). + * + * I think it's a mess, because it doesn't support escaping or + * quoting. In fact, it can only encode benign values. + * + * We also use the same form for the numbered OPTIONS + * variable. I think it's bad not to support any form of + * escaping. But do that for now. + * + * Maybe later we want to support some form of quotation here. + * Which of course, would be incompatible with initscripts. + */ + words = nm_utils_strsplit_set (line, " \t\n"); + + if (!words) + words = (const char **) NM_PTRARRAY_EMPTY (const char *); + + for (i_words = 0; words[i_words]; ) { + const gsize i_words0 = i_words; + const char *const w = words[i_words0]; + ParseLineInfo *info; + gboolean unqualified_addr = FALSE; + + for (i = 0; i < G_N_ELEMENTS (infos); i++) { + info = &infos[i]; + + if (info->disabled) + continue; - for (i = 0; metrics[i]; i++) { - nm_sprintf_buf (buffer, "(?:\\s|^)%s\\s+(lock\\s+)?(\\d+)(?:$|\\s)", metrics[i]); - regex = g_regex_new (buffer, 0, 0, NULL); - g_regex_match (regex, line, 0, &match_info); - if (g_match_info_matches (match_info)) { - gs_free char *lock = g_match_info_fetch (match_info, 1); - gs_free char *str = g_match_info_fetch (match_info, 2); - gint64 num = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXUINT32, -1); + if (!nm_streq (w, info->key)) + continue; - if (num == -1) { - g_match_info_free (match_info); + if (info->has) { + /* iproute2 for most arguments allows specifying them multiple times. + * Let's not do that. */ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid route %s '%s'", metrics[i], str); - goto out; + "Duplicate option \"%s\"", w); + return -EINVAL; } - nm_ip_route_set_attribute (route, metrics[i], - g_variant_new_uint32 (num)); - if (lock && lock[0]) { - nm_sprintf_buf (buffer, "lock-%s", metrics[i]); - nm_ip_route_set_attribute (route, buffer, - g_variant_new_boolean (TRUE)); + info->has = TRUE; + switch (info->type) { + case PARSE_LINE_TYPE_UINT8: + i_words++; + goto parse_line_type_uint8; + case PARSE_LINE_TYPE_UINT32: + i_words++; + goto parse_line_type_uint32; + case PARSE_LINE_TYPE_UINT32_WITH_LOCK: + i_words++; + goto parse_line_type_uint32_with_lock; + case PARSE_LINE_TYPE_ADDR: + i_words++; + goto parse_line_type_addr; + case PARSE_LINE_TYPE_ADDR_WITH_PREFIX: + i_words++; + goto parse_line_type_addr_with_prefix; + case PARSE_LINE_TYPE_IFNAME: + i_words++; + goto parse_line_type_ifname; + default: + nm_assert_not_reached (); } } - g_clear_pointer (®ex, g_regex_unref); - g_clear_pointer (&match_info, g_match_info_free); - } - /* tos */ - if (family == AF_INET) { - regex = g_regex_new ("(?:\\s|^)tos\\s+(\\S+)(?:$|\\s)", 0, 0, NULL); - g_regex_match (regex, line, 0, &match_info); - if (g_match_info_matches (match_info)) { - gs_free char *str = g_match_info_fetch (match_info, 1); - gint64 num = _nm_utils_ascii_str_to_int64 (str, 16, 0, G_MAXUINT8, -1); + /* "to" is also accepted unqualified... (once) */ + info = &infos[PARSE_LINE_ATTR_ROUTE_TO]; + if (!info->has && !info->disabled) { + unqualified_addr = TRUE; + info->has = TRUE; + goto parse_line_type_addr; + } - if (num == -1) { - g_match_info_free (match_info); - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid route %s '%s'", "tos", str); - goto out; - } - nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_TOS, - g_variant_new_byte ((guchar) num)); + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Unrecognized argument (\"to\" is duplicate or \"%s\" is garbage)", w); + return -EINVAL; + +parse_line_type_uint8: + s = words[i_words]; + if (!s) + goto err_word_missing_argument; + info->v.uint8 = _nm_utils_ascii_str_to_int64 (s, + info->int_base_16 ? 16 : 10, + 0, + G_MAXUINT8, + 0);; + if (errno) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Argument for \"%s\" is not a valid number", w); + return -EINVAL; } - g_clear_pointer (®ex, g_regex_unref); - g_clear_pointer (&match_info, g_match_info_free); - } - - /* from */ - if (family == AF_INET6) { - regex = g_regex_new ("(?:\\s|^)from\\s+(" IPV6_ADDR_REGEX "(?:/\\d{1,3})?)(?:$|\\s)", 0, 0, NULL); - g_regex_match (regex, line, 0, &match_info); - if (g_match_info_matches (match_info)) { - gs_free char *str = g_match_info_fetch (match_info, 1); - gs_free_error GError *local_error = NULL; - GVariant *variant = g_variant_new_string (str); - - if (!nm_ip_route_attribute_validate (NM_IP_ROUTE_ATTRIBUTE_FROM, variant, family, NULL, &local_error)) { - g_match_info_free (match_info); - g_variant_unref (variant); - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid route from '%s': %s", str, local_error->message); - goto out; + i_words++; + goto next; + +parse_line_type_uint32: +parse_line_type_uint32_with_lock: + s = words[i_words]; + if (!s) + goto err_word_missing_argument; + if (info->type == PARSE_LINE_TYPE_UINT32_WITH_LOCK) { + if (nm_streq (s, "lock")) { + s = words[++i_words]; + if (!s) + goto err_word_missing_argument; + info->v.uint32_with_lock.lock = TRUE; + } else + info->v.uint32_with_lock.lock = FALSE; + info->v.uint32_with_lock.uint32 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT32, 0);; + } else { + info->v.uint32 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT32, 0); + } + if (errno) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Argument for \"%s\" is not a valid number", w); + return -EINVAL; + } + i_words++; + goto next; + +parse_line_type_ifname: + s = words[i_words]; + if (!s) + goto err_word_missing_argument; + i_words++; + goto next; + +parse_line_type_addr: +parse_line_type_addr_with_prefix: + s = words[i_words]; + if (!s) + goto err_word_missing_argument; + { + int prefix = -1; + + if (info->type == PARSE_LINE_TYPE_ADDR) { + if (!nm_utils_parse_inaddr_bin (s, + addr_family, + &info->v.addr.addr)) { + if ( info == &infos[PARSE_LINE_ATTR_ROUTE_VIA] + && nm_streq (s, "(null)")) { + /* Due to a bug, would older versions of NM write "via (null)" + * (rh#1452648). Workaround that, and accept it.*/ + memset (&info->v.addr.addr, 0, sizeof (info->v.addr.addr)); + } else { + if (unqualified_addr) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Unrecognized argument (inet prefix is expected rather then \"%s\")", w); + return -EINVAL; + } else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Argument for \"%s\" is not a valid IPv%c address", w, + addr_family == AF_INET ? '4' : '6'); + } + return -EINVAL; + } + } + } else { + nm_assert (info->type == PARSE_LINE_TYPE_ADDR_WITH_PREFIX); + if ( info == &infos[PARSE_LINE_ATTR_ROUTE_TO] + && nm_streq (s, "default")) { + memset (&info->v.addr.addr, 0, sizeof (info->v.addr.addr)); + prefix = 0; + } else if (!nm_utils_parse_inaddr_prefix_bin (s, + addr_family, + &info->v.addr.addr, + &prefix)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Argument for \"%s\" is not ADDR/PREFIX format", w); + return -EINVAL; + } + } + if (prefix == -1) + info->v.addr.has_plen = FALSE; + else { + info->v.addr.has_plen = TRUE; + info->v.addr.plen = prefix; } - nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_FROM, variant); } - g_clear_pointer (®ex, g_regex_unref); - g_clear_pointer (&match_info, g_match_info_free); + i_words++; + goto next; + +err_word_missing_argument: + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing argument for \"%s\"", w); + return -EINVAL; +next: + ; } - if (family == AF_INET) - regex = g_regex_new ("(?:\\s|^)src\\s+(" IPV4_ADDR_REGEX ")(?:$|\\s)", 0, 0, NULL); - else - regex = g_regex_new ("(?:\\s|^)src\\s+(" IPV6_ADDR_REGEX ")(?:$|\\s)", 0, 0, NULL); - g_regex_match (regex, line, 0, &match_info); - if (g_match_info_matches (match_info)) { - gs_free char *str = g_match_info_fetch (match_info, 1); - gs_free_error GError *local_error = NULL; - GVariant *variant = g_variant_new_string (str); - - if (!nm_ip_route_attribute_validate (NM_IP_ROUTE_ATTRIBUTE_SRC, variant, family, - NULL, &local_error)) { - g_match_info_free (match_info); - g_variant_unref (variant); + if (options_route) { + route = options_route; + nm_ip_route_ref (route); + } else { + ParseLineInfo *info_to = &infos[PARSE_LINE_ATTR_ROUTE_TO]; + ParseLineInfo *info_via = &infos[PARSE_LINE_ATTR_ROUTE_VIA]; + ParseLineInfo *info_metric = &infos[PARSE_LINE_ATTR_ROUTE_METRIC]; + guint prefix; + + if (!info_to->has) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing destination prefix"); + return -EINVAL; + } + + prefix = info_to->v.addr.has_plen + ? info_to->v.addr.plen + : (addr_family == AF_INET ? 32 : 128); + + if ( ( (addr_family == AF_INET && !info_to->v.addr.addr.addr4) + || (addr_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED (&info_to->v.addr.addr.addr6))) + && prefix == 0) { + /* we ignore default routes by returning -ERANGE. */ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid route src '%s': %s", str, local_error->message); - goto out; + "Ignore manual default route"); + return -ERANGE; } - nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_SRC, variant); + route = nm_ip_route_new_binary (addr_family, + &info_to->v.addr.addr, + prefix, + info_via->has ? &info_via->v.addr.addr : NULL, + info_metric->has ? (gint64) info_metric->v.uint32 : (gint64) -1, + error); + info_to->has = FALSE; + info_via->has = FALSE; + info_metric->has = FALSE; + if (!route) + return -EINVAL; } - success = TRUE; -out: - if (regex) - g_regex_unref (regex); - if (match_info) - g_match_info_free (match_info); + for (i = 0; i < G_N_ELEMENTS (infos); i++) { + ParseLineInfo *info = &infos[i]; - return success; + if (!info->has) + continue; + if (info->ignore || info->disabled) + continue; + switch (info->type) { + case PARSE_LINE_TYPE_UINT8: + nm_ip_route_set_attribute (route, + info->key, + g_variant_new_byte (info->v.uint8)); + break; + case PARSE_LINE_TYPE_UINT32_WITH_LOCK: + if (info->v.uint32_with_lock.lock) { + nm_ip_route_set_attribute (route, + nm_sprintf_buf (buf1, "lock-%s", info->key), + g_variant_new_boolean (TRUE)); + } + nm_ip_route_set_attribute (route, + info->key, + g_variant_new_uint32 (info->v.uint32_with_lock.uint32)); + break; + case PARSE_LINE_TYPE_ADDR: + case PARSE_LINE_TYPE_ADDR_WITH_PREFIX: + nm_ip_route_set_attribute (route, + info->key, + g_variant_new_printf ("%s%s", + inet_ntop (addr_family, &info->v.addr.addr, buf1, sizeof (buf1)), + info->v.addr.has_plen + ? nm_sprintf_buf (buf2, "/%u", (unsigned) info->v.addr.plen) + : "")); + break; + default: + nm_assert_not_reached (); + break; + } + } + + nm_assert (_nm_ip_route_attribute_validate_all (route)); + + NM_SET_OUT (out_route, g_steal_pointer (&route)); + return 0; } /* Returns TRUE on missing route or valid route */ @@ -554,13 +861,13 @@ read_one_ip4_route (shvarFile *ifcfg, guint32 next_hop; guint32 netmask; gboolean has_key; + const char *v; gs_free char *value = NULL; gint64 prefix, metric; char inet_buf[NM_UTILS_INET_ADDRSTRLEN]; g_return_val_if_fail (ifcfg != NULL, FALSE); - g_return_val_if_fail (out_route != NULL, FALSE); - g_return_val_if_fail (*out_route == NULL, FALSE); + g_return_val_if_fail (out_route && !*out_route, FALSE); g_return_val_if_fail (!error || !*error, FALSE); /* Destination */ @@ -601,12 +908,12 @@ read_one_ip4_route (shvarFile *ifcfg, /* Metric */ nm_clear_g_free (&value); - value = svGetValueStr_cp (ifcfg, numbered_tag (tag, "METRIC", which)); - if (value) { - metric = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, -1); + v = svGetValueStr (ifcfg, numbered_tag (tag, "METRIC", which), &value); + if (v) { + metric = _nm_utils_ascii_str_to_int64 (v, 10, 0, G_MAXUINT32, -1); if (metric < 0) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid IP4 route metric '%s'", value); + "Invalid IP4 route metric '%s'", v); return FALSE; } } else @@ -618,9 +925,9 @@ read_one_ip4_route (shvarFile *ifcfg, /* Options */ nm_clear_g_free (&value); - value = svGetValueStr_cp (ifcfg, numbered_tag (tag, "OPTIONS", which)); - if (value) { - if (!parse_route_options (*out_route, AF_INET, value, error)) { + v = svGetValueStr (ifcfg, numbered_tag (tag, "OPTIONS", which), &value); + if (v) { + if (parse_route_line (v, AF_INET, *out_route, NULL, error) < 0) { g_clear_pointer (out_route, nm_ip_route_unref); return FALSE; } @@ -630,155 +937,65 @@ read_one_ip4_route (shvarFile *ifcfg, } static gboolean -read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError **error) +read_route_file (int addr_family, + const char *filename, + NMSettingIPConfig *s_ip, + GError **error) { gs_free char *contents = NULL; - gs_strfreev char **lines = NULL; + char *contents_rest; + const char *line; gsize len = 0; - char **iter; - GRegex *regex_to1, *regex_to2, *regex_via, *regex_metric; - GMatchInfo *match_info; - int prefix_int; - gint64 metric_int; - gboolean success = FALSE; + gsize line_num; - const char *pattern_empty = "^\\s*(\\#.*)?$"; - const char *pattern_to1 = "^\\s*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|default)" /* IP or 'default' keyword */ - "(?:/(\\d{1,2}))?"; /* optional prefix */ - const char *pattern_to2 = "to\\s+(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|default)" /* IP or 'default' keyword */ - "(?:/(\\d{1,2}))?"; /* optional prefix */ - const char *pattern_via = "via\\s+(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})"; /* IP of gateway */ - const char *pattern_metric = "metric\\s+(\\d+)"; /* metric */ - - g_return_val_if_fail (filename != NULL, FALSE); - g_return_val_if_fail (s_ip4 != NULL, FALSE); + g_return_val_if_fail (filename, FALSE); + g_return_val_if_fail ( (addr_family == AF_INET && NM_IS_SETTING_IP4_CONFIG (s_ip)) + || (addr_family == AF_INET6 && NM_IS_SETTING_IP6_CONFIG (s_ip)), FALSE); g_return_val_if_fail (!error || !*error, FALSE); - /* Read the route file */ if ( !g_file_get_contents (filename, &contents, &len, NULL) || !len) { return TRUE; /* missing/empty = success */ } - /* Create regexes for pieces to be matched */ - regex_to1 = g_regex_new (pattern_to1, 0, 0, NULL); - regex_to2 = g_regex_new (pattern_to2, 0, 0, NULL); - regex_via = g_regex_new (pattern_via, 0, 0, NULL); - regex_metric = g_regex_new (pattern_metric, 0, 0, NULL); + line_num = 0; + for (line = strtok_r (contents, "\n", &contents_rest); + line; + line = strtok_r (NULL, "\n", &contents_rest)) { + nm_auto_ip_route_unref NMIPRoute *route = NULL; + gs_free_error GError *local = NULL; + int e; - /* Iterate through file lines */ - lines = g_strsplit_set (contents, "\n\r", -1); - for (iter = lines; iter && *iter; iter++) { - gs_free char *next_hop = NULL, *dest = NULL; - char *prefix, *metric; - NMIPRoute *route; + line_num++; - /* Skip empty lines */ - if (g_regex_match_simple (pattern_empty, *iter, 0, 0)) + if (parse_route_line_is_comment (line)) continue; - /* Destination */ - g_regex_match (regex_to1, *iter, 0, &match_info); - if (!g_match_info_matches (match_info)) { - g_match_info_free (match_info); - g_regex_match (regex_to2, *iter, 0, &match_info); - if (!g_match_info_matches (match_info)) { - g_match_info_free (match_info); - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Missing IP4 route destination address in record: '%s'", *iter); - goto error; - } - } - dest = g_match_info_fetch (match_info, 1); - if (!strcmp (dest, "default")) { - g_match_info_free (match_info); - PARSE_WARNING ("ignoring manual default route: '%s' (%s)", *iter, filename); - continue; - } - if (!nm_utils_ipaddr_valid (AF_INET, dest)) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid IP4 route destination address '%s'", dest); - g_match_info_free (match_info); - goto error; - } + e = parse_route_line (line, addr_family, NULL, &route, &local); - /* Prefix - is optional; 32 if missing */ - prefix = g_match_info_fetch (match_info, 2); - g_match_info_free (match_info); - prefix_int = 32; - if (prefix) { - prefix_int = _nm_utils_ascii_str_to_int64 (prefix, 10, 1, 32, -1); - if (prefix_int == -1) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid IP4 route destination prefix '%s'", prefix); - g_free (prefix); - goto error; - } - } - g_free (prefix); - - /* Next hop */ - g_regex_match (regex_via, *iter, 0, &match_info); - if (g_match_info_matches (match_info)) { - next_hop = g_match_info_fetch (match_info, 1); - if (!nm_utils_ipaddr_valid (AF_INET, next_hop)) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid IP4 route gateway address '%s'", - next_hop); - g_match_info_free (match_info); - goto error; - } - } else { - /* we don't make distinction between missing GATEWAY IP and 0.0.0.0 */ - } - g_match_info_free (match_info); - - /* Metric */ - g_regex_match (regex_metric, *iter, 0, &match_info); - metric_int = -1; - if (g_match_info_matches (match_info)) { - metric = g_match_info_fetch (match_info, 1); - metric_int = _nm_utils_ascii_str_to_int64 (metric, 10, 0, G_MAXUINT32, -1); - if (metric_int == -1) { - g_match_info_free (match_info); - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid IP4 route metric '%s'", metric); - g_free (metric); - goto error; + if (e < 0) { + if (e == -ERANGE) + PARSE_WARNING ("ignoring manual default route: '%s' (%s)", line, filename); + else { + /* we accept all unrecognized lines, because otherwise we would reject the + * entire connection. */ + PARSE_WARNING ("ignoring invalid route at \"%s\" (%s:%lu): %s", line, filename, (long unsigned) line_num, local->message); } - g_free (metric); - } - g_match_info_free (match_info); - - route = nm_ip_route_new (AF_INET, dest, prefix_int, next_hop, metric_int, error); - if (!route) - goto error; - - if (!parse_route_options (route, AF_INET, *iter, error)) { - nm_ip_route_unref (route); - goto error; + continue; } - if (!nm_setting_ip_config_add_route (s_ip4, route)) - PARSE_WARNING ("duplicate IP4 route"); - nm_ip_route_unref (route); + if (!nm_setting_ip_config_add_route (s_ip, route)) + PARSE_WARNING ("duplicate IPv%c route", addr_family == AF_INET ? '4' : '6'); } - success = TRUE; - -error: - g_regex_unref (regex_to1); - g_regex_unref (regex_to2); - g_regex_unref (regex_via); - g_regex_unref (regex_metric); - - return success; + return TRUE; } static void parse_dns_options (NMSettingIPConfig *ip_config, const char *value) { - char **options = NULL; + gs_free const char **options = NULL; + const char *const *item; g_return_if_fail (ip_config); @@ -788,16 +1005,12 @@ 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 = g_strsplit (value, " ", 0); + options = nm_utils_strsplit_set (value, " "); if (options) { - char **item; for (item = options; *item; item++) { - if (strlen (*item)) { - if (!nm_setting_ip_config_add_dns_option (ip_config, *item)) - PARSE_WARNING ("can't add DNS option '%s'", *item); - } + if (!nm_setting_ip_config_add_dns_option (ip_config, *item)) + PARSE_WARNING ("can't add DNS option '%s'", *item); } - g_strfreev (options); } } @@ -850,157 +1063,6 @@ error: return success; } -static gboolean -read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error) -{ - char *contents = NULL; - gsize len = 0; - char **lines = NULL, **iter; - GRegex *regex_to1, *regex_to2, *regex_via, *regex_metric; - GMatchInfo *match_info; - char *dest = NULL, *prefix = NULL, *next_hop = NULL, *metric = NULL; - int prefix_int; - gint64 metric_int; - gboolean success = FALSE; - - const char *pattern_empty = "^\\s*(\\#.*)?$"; - const char *pattern_to1 = "^\\s*(default|" IPV6_ADDR_REGEX ")" /* IPv6 or 'default' keyword */ - "(?:/(\\d{1,3}))?"; /* optional prefix */ - const char *pattern_to2 = "to\\s+(default|" IPV6_ADDR_REGEX ")" /* IPv6 or 'default' keyword */ - "(?:/(\\d{1,3}))?"; /* optional prefix */ - const char *pattern_via = "via\\s+(" IPV6_ADDR_REGEX ")"; /* IPv6 of gateway */ - const char *pattern_metric = "metric\\s+(\\d+)"; /* metric */ - - - g_return_val_if_fail (filename != NULL, FALSE); - g_return_val_if_fail (s_ip6 != NULL, FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - /* Read the route file */ - if (!g_file_get_contents (filename, &contents, &len, NULL) || !len) { - g_free (contents); - return TRUE; /* missing/empty = success */ - } - - /* Create regexes for pieces to be matched */ - regex_to1 = g_regex_new (pattern_to1, 0, 0, NULL); - regex_to2 = g_regex_new (pattern_to2, 0, 0, NULL); - regex_via = g_regex_new (pattern_via, 0, 0, NULL); - regex_metric = g_regex_new (pattern_metric, 0, 0, NULL); - - /* Iterate through file lines */ - lines = g_strsplit_set (contents, "\n\r", -1); - for (iter = lines; iter && *iter; iter++) { - NMIPRoute *route; - - /* Skip empty lines */ - if (g_regex_match_simple (pattern_empty, *iter, 0, 0)) - continue; - - /* Destination */ - g_regex_match (regex_to1, *iter, 0, &match_info); - if (!g_match_info_matches (match_info)) { - g_match_info_free (match_info); - g_regex_match (regex_to2, *iter, 0, &match_info); - if (!g_match_info_matches (match_info)) { - g_match_info_free (match_info); - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Missing IP6 route destination address in record: '%s'", *iter); - goto error; - } - } - dest = g_match_info_fetch (match_info, 1); - if (!g_strcmp0 (dest, "default")) { - /* Ignore default route - NM handles it internally */ - g_clear_pointer (&dest, g_free); - g_match_info_free (match_info); - PARSE_WARNING ("ignoring manual default route: '%s' (%s)", *iter, filename); - continue; - } - - /* Prefix - is optional; 128 if missing */ - prefix = g_match_info_fetch (match_info, 2); - g_match_info_free (match_info); - prefix_int = 128; - if (prefix) { - prefix_int = _nm_utils_ascii_str_to_int64 (prefix, 10, 1, 128, -1); - if (prefix_int == -1) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid IP6 route destination prefix '%s'", prefix); - g_free (dest); - g_free (prefix); - goto error; - } - } - g_free (prefix); - - /* Next hop */ - g_regex_match (regex_via, *iter, 0, &match_info); - if (g_match_info_matches (match_info)) { - next_hop = g_match_info_fetch (match_info, 1); - if (!nm_utils_ipaddr_valid (AF_INET6, next_hop)) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid IPv6 route nexthop address '%s'", - next_hop); - g_match_info_free (match_info); - g_free (dest); - g_free (next_hop); - goto error; - } - } else { - /* Missing "via" is taken as :: */ - next_hop = NULL; - } - g_match_info_free (match_info); - - /* Metric */ - g_regex_match (regex_metric, *iter, 0, &match_info); - metric_int = -1; - if (g_match_info_matches (match_info)) { - metric = g_match_info_fetch (match_info, 1); - metric_int = _nm_utils_ascii_str_to_int64 (metric, 10, 0, G_MAXUINT32, -1); - if (metric_int == -1) { - g_match_info_free (match_info); - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid IP6 route metric '%s'", metric); - g_free (dest); - g_free (next_hop); - g_free (metric); - goto error; - } - g_free (metric); - } - g_match_info_free (match_info); - - route = nm_ip_route_new (AF_INET6, dest, prefix_int, next_hop, metric_int, error); - g_free (dest); - g_free (next_hop); - if (!route) - goto error; - - if (!parse_route_options (route, AF_INET6, *iter, error)) { - nm_ip_route_unref (route); - goto error; - } - - if (!nm_setting_ip_config_add_route (s_ip6, route)) - PARSE_WARNING ("duplicate IP6 route"); - nm_ip_route_unref (route); - } - - success = TRUE; - -error: - g_free (contents); - g_strfreev (lines); - g_regex_unref (regex_to1); - g_regex_unref (regex_to2); - g_regex_unref (regex_via); - g_regex_unref (regex_metric); - - return success; -} - static NMSetting * make_user_setting (shvarFile *ifcfg, GError **error) { @@ -1053,18 +1115,18 @@ static NMSetting * make_proxy_setting (shvarFile *ifcfg, GError **error) { NMSettingProxy *s_proxy = NULL; - char *value = NULL; + gs_free char *value = NULL; + const char *v; NMSettingProxyMethod method; - value = svGetValueStr_cp (ifcfg, "PROXY_METHOD"); - if (!value) + v = svGetValueStr (ifcfg, "PROXY_METHOD", &value); + if (!v) return NULL; - if (!g_ascii_strcasecmp (value, "auto")) + if (!g_ascii_strcasecmp (v, "auto")) method = NM_SETTING_PROXY_METHOD_AUTO; else method = NM_SETTING_PROXY_METHOD_NONE; - g_free (value); s_proxy = (NMSettingProxy *) nm_setting_proxy_new (); @@ -1074,19 +1136,15 @@ make_proxy_setting (shvarFile *ifcfg, GError **error) NM_SETTING_PROXY_METHOD, (int) NM_SETTING_PROXY_METHOD_AUTO, NULL); - value = svGetValueStr_cp (ifcfg, "PAC_URL"); - if (value) { - value = g_strstrip (value); - g_object_set (s_proxy, NM_SETTING_PROXY_PAC_URL, value, NULL); - g_free (value); - } + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "PAC_URL", &value); + if (v) + g_object_set (s_proxy, NM_SETTING_PROXY_PAC_URL, v, NULL); - value = svGetValueStr_cp (ifcfg, "PAC_SCRIPT"); - if (value) { - value = g_strstrip (value); - g_object_set (s_proxy, NM_SETTING_PROXY_PAC_SCRIPT, value, NULL); - g_free (value); - } + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "PAC_SCRIPT", &value); + if (v) + g_object_set (s_proxy, NM_SETTING_PROXY_PAC_SCRIPT, v, NULL); break; case NM_SETTING_PROXY_METHOD_NONE: @@ -1096,12 +1154,8 @@ make_proxy_setting (shvarFile *ifcfg, GError **error) break; } - value = svGetValueStr_cp (ifcfg, "BROWSER_ONLY"); - if (value) { - if (!g_ascii_strcasecmp (value, "yes")) - g_object_set (s_proxy, NM_SETTING_PROXY_BROWSER_ONLY, TRUE, NULL); - g_free (value); - } + if (svGetValueBoolean (ifcfg, "BROWSER_ONLY", FALSE)) + g_object_set (s_proxy, NM_SETTING_PROXY_BROWSER_ONLY, TRUE, NULL); return NM_SETTING (s_proxy); } @@ -1114,7 +1168,8 @@ make_ip4_setting (shvarFile *ifcfg, { gs_unref_object NMSettingIPConfig *s_ip4 = NULL; gs_free char *route_path = NULL; - char *value = NULL; + gs_free char *value = NULL; + const char *v; char *method; gs_free char *dns_options_free = NULL; const char *dns_options = NULL; @@ -1128,6 +1183,7 @@ make_ip4_setting (shvarFile *ifcfg, gint64 timeout; gint priority; char inet_buf[NM_UTILS_INET_ADDRSTRLEN]; + const char *const *item; nm_assert (out_has_defroute && !*out_has_defroute); @@ -1149,44 +1205,43 @@ make_ip4_setting (shvarFile *ifcfg, /* Then check if GATEWAYDEV; it's global and overrides DEFROUTE */ network_ifcfg = svOpenFile (network_file, NULL); if (network_ifcfg) { - char *gatewaydev; + gs_free char *gatewaydev_value = NULL; + const char *gatewaydev; /* Get the connection ifcfg device name and the global gateway device */ - value = svGetValueStr_cp (ifcfg, "DEVICE"); - gatewaydev = svGetValueStr_cp (network_ifcfg, "GATEWAYDEV"); + v = svGetValueStr (ifcfg, "DEVICE", &value); + gatewaydev = svGetValueStr (network_ifcfg, "GATEWAYDEV", &gatewaydev_value); dns_options = svGetValue (network_ifcfg, "RES_OPTIONS", &dns_options_free); /* If there was a global gateway device specified, then only connections * for that device can be the default connection. */ - if (gatewaydev && value) - never_default = !!strcmp (value, gatewaydev); + if (gatewaydev && v) + never_default = !!strcmp (v, gatewaydev); - g_free (gatewaydev); - g_free (value); + nm_clear_g_free (&value); svCloseFile (network_ifcfg); } - value = svGetValueStr_cp (ifcfg, "BOOTPROTO"); + v = svGetValueStr (ifcfg, "BOOTPROTO", &value); - if (!value || !*value || !g_ascii_strcasecmp (value, "none")) { + if (!v || !*v || !g_ascii_strcasecmp (v, "none")) { if (is_any_ip4_address_defined (ifcfg, NULL)) method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL; else method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - } else if (!g_ascii_strcasecmp (value, "bootp") || !g_ascii_strcasecmp (value, "dhcp")) { + } else if (!g_ascii_strcasecmp (v, "bootp") || !g_ascii_strcasecmp (v, "dhcp")) { method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; - } else if (!g_ascii_strcasecmp (value, "static")) { + } else if (!g_ascii_strcasecmp (v, "static")) { if (is_any_ip4_address_defined (ifcfg, NULL)) method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL; else method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - } else if (!g_ascii_strcasecmp (value, "autoip")) { + } else if (!g_ascii_strcasecmp (v, "autoip")) { method = NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL; - } else if (!g_ascii_strcasecmp (value, "shared")) { + } else if (!g_ascii_strcasecmp (v, "shared")) { int idx; - g_free (value); g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_SHARED, NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default, @@ -1210,11 +1265,9 @@ make_ip4_setting (shvarFile *ifcfg, return g_steal_pointer (&s_ip4); } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Unknown BOOTPROTO '%s'", value); - g_free (value); + "Unknown BOOTPROTO '%s'", v); return NULL; } - g_free (value); g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, method, @@ -1230,31 +1283,29 @@ make_ip4_setting (shvarFile *ifcfg, return g_steal_pointer (&s_ip4); /* Handle DHCP settings */ - value = svGetValueStr_cp (ifcfg, "DHCP_HOSTNAME"); - if (value) { - g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, value, NULL); - g_free (value); - } + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "DHCP_HOSTNAME", &value); + if (v) + g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, v, NULL); - value = svGetValueStr_cp (ifcfg, "DHCP_FQDN"); - if (value) { + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "DHCP_FQDN", &value); + if (v) { g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, NULL, - NM_SETTING_IP4_CONFIG_DHCP_FQDN, value, + NM_SETTING_IP4_CONFIG_DHCP_FQDN, v, NULL); - g_free (value); } g_object_set (s_ip4, - NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, svGetValueBoolean (ifcfg, "DHCP_SEND_HOSTNAME", TRUE), - NM_SETTING_IP_CONFIG_DHCP_TIMEOUT, svGetValueInt64 (ifcfg, "IPV4_DHCP_TIMEOUT", 10, 0, G_MAXINT32, 0), - NULL); + NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, svGetValueBoolean (ifcfg, "DHCP_SEND_HOSTNAME", TRUE), + NM_SETTING_IP_CONFIG_DHCP_TIMEOUT, svGetValueInt64 (ifcfg, "IPV4_DHCP_TIMEOUT", 10, 0, G_MAXINT32, 0), + NULL); - value = svGetValueStr_cp (ifcfg, "DHCP_CLIENT_ID"); - if (value) { - g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, value, NULL); - g_free (value); - } + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "DHCP_CLIENT_ID", &value); + if (v) + g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, v, NULL); /* Read static IP addresses. * Read them even for AUTO method - in this case the addresses are @@ -1314,46 +1365,40 @@ make_ip4_setting (shvarFile *ifcfg, char tag[256]; numbered_tag (tag, "DNS", i); - value = svGetValueStr_cp (ifcfg, tag); - if (value) { - if (nm_utils_ipaddr_valid (AF_INET, value)) { - if (!nm_setting_ip_config_add_dns (s_ip4, value)) + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, tag, &value); + if (v) { + if (nm_utils_ipaddr_valid (AF_INET, v)) { + if (!nm_setting_ip_config_add_dns (s_ip4, v)) PARSE_WARNING ("duplicate DNS server %s", tag); - } else if (nm_utils_ipaddr_valid (AF_INET6, value)) { + } else if (nm_utils_ipaddr_valid (AF_INET6, v)) { /* Ignore IPv6 addresses */ } else { - PARSE_WARNING ("invalid DNS server address %s", value); - g_free (value); + PARSE_WARNING ("invalid DNS server address %s", v); return NULL; } - - g_free (value); } } /* DNS searches */ - value = svGetValueStr_cp (ifcfg, "DOMAIN"); - if (value) { - char **searches = NULL; + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "DOMAIN", &value); + if (v) { + gs_free const char **searches = NULL; - searches = g_strsplit (value, " ", 0); + searches = nm_utils_strsplit_set (v, " "); if (searches) { - char **item; for (item = searches; *item; item++) { - if (strlen (*item)) { - if (!nm_setting_ip_config_add_dns_search (s_ip4, *item)) - PARSE_WARNING ("duplicate DNS domain '%s'", *item); - } + if (!nm_setting_ip_config_add_dns_search (s_ip4, *item)) + PARSE_WARNING ("duplicate DNS domain '%s'", *item); } - g_strfreev (searches); } - g_free (value); } /* DNS options */ + nm_clear_g_free (&value); parse_dns_options (s_ip4, svGetValue (ifcfg, "RES_OPTIONS", &value)); parse_dns_options (s_ip4, dns_options); - g_free (value); /* DNS priority */ priority = svGetValueInt64 (ifcfg, "IPV4_DNS_PRIORITY", 10, G_MININT32, G_MAXINT32, 0); @@ -1389,28 +1434,24 @@ make_ip4_setting (shvarFile *ifcfg, svCloseFile (route_ifcfg); } } else { - if (!read_route_file_legacy (route_path, s_ip4, error)) + if (!read_route_file (AF_INET, route_path, s_ip4, error)) return NULL; } /* Legacy value NM used for a while but is incorrect (rh #459370) */ if (!nm_setting_ip_config_get_num_dns_searches (s_ip4)) { - value = svGetValueStr_cp (ifcfg, "SEARCH"); - if (value) { - char **searches = NULL; + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "SEARCH", &value); + if (v) { + gs_free const char **searches = NULL; - searches = g_strsplit (value, " ", 0); + searches = nm_utils_strsplit_set (v, " "); if (searches) { - char **item; for (item = searches; *item; item++) { - if (strlen (*item)) { - if (!nm_setting_ip_config_add_dns_search (s_ip4, *item)) - PARSE_WARNING ("duplicate DNS search '%s'", *item); - } + if (!nm_setting_ip_config_add_dns_search (s_ip4, *item)) + PARSE_WARNING ("duplicate DNS search '%s'", *item); } - g_strfreev (searches); } - g_free (value); } } @@ -1427,7 +1468,6 @@ read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *file { GDir *dir; char *dirname, *base; - shvarFile *parsed; NMIPAddress *base_addr = NULL; GError *err = NULL; @@ -1449,8 +1489,11 @@ read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *file gboolean ok; while ((item = g_dir_read_name (dir))) { + nm_auto_shvar_file_close shvarFile *parsed = NULL; gs_free char *gateway = NULL; - char *full_path, *device; + gs_free char *device_value = NULL; + gs_free char *full_path = NULL; + const char *device; const char *p; if (!utils_is_ifcfg_alias_file (item, base)) @@ -1466,32 +1509,25 @@ read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *file } if (*p) { PARSE_WARNING ("ignoring alias file '%s' with invalid name", full_path); - g_free (full_path); continue; } parsed = svOpenFile (full_path, &err); if (!parsed) { PARSE_WARNING ("couldn't parse alias file '%s': %s", full_path, err->message); - g_free (full_path); g_clear_error (&err); continue; } - device = svGetValueStr_cp (parsed, "DEVICE"); + device = svGetValueStr (parsed, "DEVICE", &device_value); if (!device) { PARSE_WARNING ("alias file '%s' has no DEVICE", full_path); - svCloseFile (parsed); - g_free (full_path); continue; } /* We know that item starts with IFCFG_TAG from utils_is_ifcfg_alias_file() */ if (strcmp (device, item + strlen (IFCFG_TAG)) != 0) { PARSE_WARNING ("alias file '%s' has invalid DEVICE (%s) for filename", full_path, device); - g_free (device); - svCloseFile (parsed); - g_free (full_path); continue; } @@ -1526,11 +1562,6 @@ read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *file g_clear_error (&err); } nm_ip_address_unref (addr); - - svCloseFile (parsed); - - g_free (device); - g_free (full_path); } g_dir_close (dir); @@ -1557,7 +1588,8 @@ make_ip6_setting (shvarFile *ifcfg, gboolean ipv6init, ipv6forwarding, dhcp6 = FALSE; char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; char *ipv6addr, *ipv6addr_secondaries; - char **list = NULL, **iter; + gs_free const char **list = NULL; + const char *const *iter; guint32 i; int i_val; GError *local = NULL; @@ -1714,21 +1746,18 @@ make_ip6_setting (shvarFile *ifcfg, g_free (ipv6addr); g_free (ipv6addr_secondaries); - list = g_strsplit_set (value, " ", 0); + list = nm_utils_strsplit_set (value, " "); g_free (value); for (iter = list, i = 0; iter && *iter; iter++, i++) { NMIPAddress *addr = NULL; - if (!parse_full_ip6_address (ifcfg, *iter, i, &addr, error)) { - g_strfreev (list); + if (!parse_full_ip6_address (ifcfg, *iter, i, &addr, error)) goto error; - } if (!nm_setting_ip_config_add_address (s_ip6, addr)) PARSE_WARNING ("duplicate IP6 address"); nm_ip_address_unref (addr); } - g_strfreev (list); /* Gateway */ if (nm_setting_ip_config_get_num_addresses (s_ip6)) { @@ -1805,7 +1834,7 @@ make_ip6_setting (shvarFile *ifcfg, if (!utils_has_complex_routes (svFileGetName (ifcfg))) { /* Read static routes from route6-<interface> file */ route6_path = utils_get_route6_path (svFileGetName (ifcfg)); - if (!read_route6_file (route6_path, s_ip6, error)) + if (!read_route_file (AF_INET6, route6_path, s_ip6, error)) goto error; g_free (route6_path); @@ -1835,18 +1864,18 @@ static void check_if_bond_slave (shvarFile *ifcfg, NMSettingConnection *s_con) { - char *value; + gs_free char *value = NULL; + const char *v; - value = svGetValueStr_cp (ifcfg, "MASTER_UUID"); - if (!value) - value = svGetValueStr_cp (ifcfg, "MASTER"); + v = svGetValueStr (ifcfg, "MASTER_UUID", &value); + if (!v) + v = svGetValueStr (ifcfg, "MASTER", &value); - if (value) { - g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL); + if (v) { g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, v, NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME, NULL); - g_free (value); } /* We should be checking for SLAVE=yes as well, but NM used to not set that, @@ -1859,15 +1888,18 @@ check_if_team_slave (shvarFile *ifcfg, NMSettingConnection *s_con) { gs_free char *value = NULL; + const char *v; - value = svGetValueStr_cp (ifcfg, "TEAM_MASTER_UUID"); - if (!value) - value = svGetValueStr_cp (ifcfg, "TEAM_MASTER"); - if (!value) + v = svGetValueStr (ifcfg, "TEAM_MASTER_UUID", &value); + if (!v) + v = svGetValueStr (ifcfg, "TEAM_MASTER", &value); + if (!v) return FALSE; - g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL); - g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, NULL); + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, v, + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, + NULL); return TRUE; } @@ -1930,29 +1962,29 @@ read_dcb_app (shvarFile *ifcfg, GError **error) { NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE; - char *tmp, *val; + gs_free char *value = NULL; + const char *v; gboolean success = TRUE; int priority = -1; + char key[255]; flags = read_dcb_flags (ifcfg, flags_prop); /* Priority */ - tmp = g_strdup_printf ("DCB_APP_%s_PRIORITY", app); - val = svGetValueStr_cp (ifcfg, tmp); - if (val) { - priority = _nm_utils_ascii_str_to_int64 (val, 0, 0, 7, -1); + nm_sprintf_buf (key, "DCB_APP_%s_PRIORITY", app); + v = svGetValueStr (ifcfg, key, &value); + if (v) { + priority = _nm_utils_ascii_str_to_int64 (v, 0, 0, 7, -1); if (priority < 0) { success = FALSE; g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid %s value '%s' (expected 0 - 7)", - tmp, val); + key, v); } - g_free (val); if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) PARSE_WARNING ("ignoring DCB %s priority; app not enabled", app); } - g_free (tmp); if (success) { g_object_set (G_OBJECT (s_dcb), @@ -1975,11 +2007,12 @@ read_dcb_bool_array (shvarFile *ifcfg, DcbSetBoolFunc set_func, GError **error) { - gs_free char *val = NULL; + gs_free char *value = NULL; + const char *v; guint i; - val = svGetValueStr_cp (ifcfg, prop); - if (!val) + v = svGetValueStr (ifcfg, prop, &value); + if (!v) return TRUE; if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { @@ -1987,8 +2020,8 @@ read_dcb_bool_array (shvarFile *ifcfg, return TRUE; } - if (strlen (val) != 8) { - PARSE_WARNING ("%s value '%s' must be 8 characters long", prop, val); + if (strlen (v) != 8) { + PARSE_WARNING ("%s value '%s' must be 8 characters long", prop, v); g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "boolean array must be 8 characters"); return FALSE; @@ -1996,13 +2029,13 @@ read_dcb_bool_array (shvarFile *ifcfg, /* All characters must be either 0 or 1 */ for (i = 0; i < 8; i++) { - if (val[i] != '0' && val[i] != '1') { - PARSE_WARNING ("invalid %s value '%s': not all 0s and 1s", prop, val); + if (v[i] != '0' && v[i] != '1') { + PARSE_WARNING ("invalid %s value '%s': not all 0s and 1s", prop, v); g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "invalid boolean digit"); return FALSE; } - set_func (s_dcb, i, (val[i] == '1')); + set_func (s_dcb, i, (v[i] == '1')); } return TRUE; } @@ -2067,8 +2100,8 @@ read_dcb_percent_array (shvarFile *ifcfg, GError **error) { gs_free char *val = NULL; - gs_strfreev char **split = NULL; - char **iter; + gs_free const char **split = NULL; + const char *const *iter; guint i, sum = 0; val = svGetValueStr_cp (ifcfg, prop); @@ -2080,8 +2113,8 @@ read_dcb_percent_array (shvarFile *ifcfg, return TRUE; } - split = g_strsplit_set (val, ",", 0); - if (!split || (g_strv_length (split) != 8)) { + 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, "percent array must be 8 elements"); @@ -2502,15 +2535,17 @@ fill_wpa_ciphers (shvarFile *ifcfg, gboolean group, gboolean adhoc) { - char *value = NULL, *p; - char **list = NULL, **iter; + gs_free char *value = NULL; + const char *p; + gs_free const char **list = NULL; + const char *const *iter; int i = 0; - p = value = svGetValueStr_cp (ifcfg, group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE"); - if (!value) + p = svGetValueStr (ifcfg, group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE", &value); + if (!p) return TRUE; - list = g_strsplit_set (p, " ", 0); + 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 @@ -2549,9 +2584,6 @@ fill_wpa_ciphers (shvarFile *ifcfg, } } - if (list) - g_strfreev (list); - g_free (value); return TRUE; } @@ -2844,98 +2876,89 @@ eap_peap_reader (const char *eap_method, gboolean phase2, GError **error) { - char *anon_ident = NULL; - char *ca_cert = NULL; - char *real_cert_value = NULL; - char *inner_auth = NULL; - char *peapver = NULL; - char *lower; - char **list = NULL, **iter; - gboolean success = FALSE; + gs_free char *value = NULL; + const char *v; + gs_free const char **list = NULL; + const char *const *iter; NMSetting8021xCKScheme scheme; - ca_cert = svGetValueStr_cp (ifcfg, "IEEE_8021X_CA_CERT"); - if (ca_cert) { - real_cert_value = get_cert_value (svFileGetName (ifcfg), ca_cert, &scheme); + v = svGetValueStr (ifcfg, "IEEE_8021X_CA_CERT", &value); + if (v) { + gs_free char *real_cert_value = NULL; + + real_cert_value = get_cert_value (svFileGetName (ifcfg), v, &scheme); if (!nm_setting_802_1x_set_ca_cert (s_8021x, real_cert_value, scheme, NULL, error)) - goto done; + return FALSE; } else { PARSE_WARNING ("missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!", eap_method); } - peapver = svGetValueStr_cp (ifcfg, "IEEE_8021X_PEAP_VERSION"); - if (peapver) { - if (!strcmp (peapver, "0")) + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IEEE_8021X_PEAP_VERSION", &value); + if (v) { + if (!strcmp (v, "0")) g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "0", NULL); - else if (!strcmp (peapver, "1")) + else if (!strcmp (v, "1")) g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "1", NULL); else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Unknown IEEE_8021X_PEAP_VERSION value '%s'", - peapver); - goto done; + v); + return FALSE; } } if (svGetValueBoolean (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", FALSE)) g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1", NULL); - anon_ident = svGetValueStr_cp (ifcfg, "IEEE_8021X_ANON_IDENTITY"); - if (anon_ident) - g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IEEE_8021X_ANON_IDENTITY", &value); + if (v) + g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, v, NULL); - inner_auth = svGetValueStr_cp (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS"); - if (!inner_auth) { + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", &value); + if (!v) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing IEEE_8021X_INNER_AUTH_METHODS."); - goto done; + return FALSE; } /* Handle options for the inner auth method */ - list = g_strsplit (inner_auth, " ", 0); + list = nm_utils_strsplit_set (v, " "); for (iter = list; iter && *iter; iter++) { - if (!strlen (*iter)) - continue; - - if ( !strcmp (*iter, "MSCHAPV2") - || !strcmp (*iter, "MD5") - || !strcmp (*iter, "GTC")) { + if (NM_IN_STRSET (*iter, "MSCHAPV2", + "MD5", + "GTC")) { if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error)) - goto done; - } else if (!strcmp (*iter, "TLS")) { + return FALSE; + } else if (nm_streq (*iter, "TLS")) { if (!eap_tls_reader (*iter, ifcfg, keys, s_8021x, TRUE, error)) - goto done; + return FALSE; } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.", *iter); - goto done; + return FALSE; } - lower = g_ascii_strdown (*iter, -1); - g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL); - g_free (lower); + { + gs_free char *lower = NULL; + + lower = g_ascii_strdown (*iter, -1); + g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL); + } break; } if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "No valid IEEE_8021X_INNER_AUTH_METHODS found."); - goto done; + return FALSE; } - success = TRUE; - -done: - if (list) - g_strfreev (list); - g_free (inner_auth); - g_free (peapver); - g_free (real_cert_value); - g_free (ca_cert); - g_free (anon_ident); - return success; + return TRUE; } static gboolean @@ -2946,81 +2969,70 @@ eap_ttls_reader (const char *eap_method, gboolean phase2, GError **error) { - gboolean success = FALSE; - char *anon_ident = NULL; - char *ca_cert = NULL; - char *real_cert_value = NULL; - char *inner_auth = NULL; - char *tmp; - char **list = NULL, **iter; + gs_free char *inner_auth = NULL; + gs_free char *value = NULL; + const char *v; + gs_free const char **list = NULL; + const char *const *iter; NMSetting8021xCKScheme scheme; - ca_cert = svGetValueStr_cp (ifcfg, "IEEE_8021X_CA_CERT"); - if (ca_cert) { - real_cert_value = get_cert_value (svFileGetName (ifcfg), ca_cert, &scheme); + v = svGetValueStr (ifcfg, "IEEE_8021X_CA_CERT", &value); + if (v) { + gs_free char *real_cert_value = NULL; + + real_cert_value = get_cert_value (svFileGetName (ifcfg), v, &scheme); if (!nm_setting_802_1x_set_ca_cert (s_8021x, real_cert_value, scheme, NULL, error)) - goto done; + return FALSE; } else { PARSE_WARNING ("missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!", eap_method); } - anon_ident = svGetValueStr_cp (ifcfg, "IEEE_8021X_ANON_IDENTITY"); - if (anon_ident) - g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IEEE_8021X_ANON_IDENTITY", &value); + if (v) + g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, v, NULL); - tmp = svGetValueStr_cp (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS"); - if (!tmp) { + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", &value); + if (!v) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing IEEE_8021X_INNER_AUTH_METHODS."); - goto done; + return FALSE; } - inner_auth = g_ascii_strdown (tmp, -1); - g_free (tmp); + inner_auth = g_ascii_strdown (v, -1); /* Handle options for the inner auth method */ - list = g_strsplit (inner_auth, " ", 0); + list = nm_utils_strsplit_set (inner_auth, " "); for (iter = list; iter && *iter; iter++) { - if (!strlen (*iter)) - continue; - - if ( !strcmp (*iter, "mschapv2") - || !strcmp (*iter, "mschap") - || !strcmp (*iter, "pap") - || !strcmp (*iter, "chap")) { + if (NM_IN_STRSET (*iter, "mschapv2", + "mschap", + "pap", + "chap")) { if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error)) - goto done; + return FALSE; g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, *iter, NULL); - } else if (!strcmp (*iter, "eap-tls")) { + } else if (nm_streq (*iter, "eap-tls")) { if (!eap_tls_reader (*iter, ifcfg, keys, s_8021x, TRUE, error)) - goto done; + return FALSE; g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, "tls", NULL); - } else if ( !strcmp (*iter, "eap-mschapv2") - || !strcmp (*iter, "eap-md5") - || !strcmp (*iter, "eap-gtc")) { + } else if (NM_IN_STRSET (*iter, "eap-mschapv2", + "eap-md5", + "eap-gtc")) { if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error)) - goto done; + return FALSE; g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, (*iter + NM_STRLEN ("eap-")), NULL); } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.", *iter); - goto done; + return FALSE; } break; } - success = TRUE; - -done: - if (list) - g_strfreev (list); - g_free (inner_auth); - g_free (real_cert_value); - g_free (ca_cert); - g_free (anon_ident); - return success; + return TRUE; } static gboolean @@ -3037,7 +3049,8 @@ eap_fast_reader (const char *eap_method, char *inner_auth = NULL; char *fast_provisioning = NULL; char *lower; - char **list = NULL, **iter; + gs_free const char **list = NULL; + const char *const *iter; const char *pac_prov_str; gboolean allow_unauth = FALSE, allow_auth = FALSE; gboolean success = FALSE; @@ -3050,10 +3063,10 @@ eap_fast_reader (const char *eap_method, fast_provisioning = svGetValueStr_cp (ifcfg, "IEEE_8021X_FAST_PROVISIONING"); if (fast_provisioning) { - list = g_strsplit_set (fast_provisioning, " \t", 0); - for (iter = list; iter && *iter; iter++) { - if (**iter == '\0') - continue; + gs_free const char **list1 = NULL; + + list1 = nm_utils_strsplit_set (fast_provisioning, " \t"); + for (iter = list1; iter && *iter; iter++) { if (strcmp (*iter, "allow-unauth") == 0) allow_unauth = TRUE; else if (strcmp (*iter, "allow-auth") == 0) @@ -3064,8 +3077,6 @@ eap_fast_reader (const char *eap_method, *iter); } } - g_strfreev (list); - list = NULL; } pac_prov_str = allow_unauth ? (allow_auth ? "3" : "1") : (allow_auth ? "2" : "0"); g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, pac_prov_str, NULL); @@ -3088,11 +3099,8 @@ eap_fast_reader (const char *eap_method, } /* Handle options for the inner auth method */ - list = g_strsplit (inner_auth, " ", 0); + list = nm_utils_strsplit_set (inner_auth, " "); for (iter = list; iter && *iter; iter++) { - if (!strlen (*iter)) - continue; - if ( !strcmp (*iter, "MSCHAPV2") || !strcmp (*iter, "GTC")) { if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error)) @@ -3119,7 +3127,6 @@ eap_fast_reader (const char *eap_method, success = TRUE; done: - g_strfreev (list); g_free (inner_auth); g_free (fast_provisioning); g_free (real_pac_path); @@ -3160,22 +3167,21 @@ read_8021x_list_value (shvarFile *ifcfg, NMSetting8021x *setting, const char *prop_name) { - char *value; - char **strv; + gs_free char *value = NULL; + gs_free const char **strv = NULL; + const char *v; g_return_if_fail (ifcfg != NULL); g_return_if_fail (ifcfg_var_name != NULL); g_return_if_fail (prop_name != NULL); - value = svGetValueStr_cp (ifcfg, ifcfg_var_name); - if (!value) + v = svGetValueStr (ifcfg, ifcfg_var_name, &value); + if (!v) return; - strv = g_strsplit_set (value, " \t", 0); - if (strv && strv[0]) + strv = nm_utils_strsplit_set (v, " \t"); + if (strv) g_object_set (setting, prop_name, strv, NULL); - g_strfreev (strv); - g_free (value); } static NMSetting8021x * @@ -3186,22 +3192,23 @@ fill_8021x (shvarFile *ifcfg, GError **error) { nm_auto_shvar_file_close shvarFile *keys = NULL; - NMSetting8021x *s_8021x; - char *value; - char **list = NULL, **iter; + gs_unref_object NMSetting8021x *s_8021x = NULL; + gs_free char *value = NULL; + const char *v; + gs_free const char **list = NULL; + const char *const *iter; gint64 timeout; int i_val; - value = svGetValueStr_cp (ifcfg, "IEEE_8021X_EAP_METHODS"); - if (!value) { + v = svGetValueStr (ifcfg, "IEEE_8021X_EAP_METHODS", &value); + if (!v) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing IEEE_8021X_EAP_METHODS for key management '%s'", key_mgmt); return NULL; } - list = g_strsplit (value, " ", 0); - g_free (value); + list = nm_utils_strsplit_set (v, " "); s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); @@ -3212,7 +3219,7 @@ fill_8021x (shvarFile *ifcfg, for (iter = list; iter && *iter; iter++) { EAPReader *eap = &eap_readers[0]; gboolean found = FALSE; - char *lower = NULL; + gs_free char *lower = NULL; lower = g_ascii_strdown (*iter, -1); while (eap->method) { @@ -3230,10 +3237,9 @@ fill_8021x (shvarFile *ifcfg, } /* Parse EAP method specific options */ - if (!(*eap->reader)(lower, ifcfg, keys, s_8021x, FALSE, error)) { - g_free (lower); - goto error; - } + if (!(*eap->reader)(lower, ifcfg, keys, s_8021x, FALSE, error)) + return NULL; + nm_setting_802_1x_add_eap_method (s_8021x, lower); found = TRUE; break; @@ -3244,28 +3250,27 @@ next: if (!found) PARSE_WARNING ("ignored unknown IEEE_8021X_EAP_METHOD '%s'.", lower); - g_free (lower); } if (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 0) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "No valid EAP methods found in IEEE_8021X_EAP_METHODS."); - goto error; + return NULL; } - value = svGetValueStr_cp (ifcfg, "IEEE_8021X_SUBJECT_MATCH"); - g_object_set (s_8021x, NM_SETTING_802_1X_SUBJECT_MATCH, value, NULL); - g_free (value); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IEEE_8021X_SUBJECT_MATCH", &value); + g_object_set (s_8021x, NM_SETTING_802_1X_SUBJECT_MATCH, v, NULL); - value = svGetValueStr_cp (ifcfg, "IEEE_8021X_PHASE2_SUBJECT_MATCH"); - g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_SUBJECT_MATCH, value, NULL); - g_free (value); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IEEE_8021X_PHASE2_SUBJECT_MATCH", &value); + g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_SUBJECT_MATCH, v, NULL); i_val = NM_SETTING_802_1X_AUTH_FLAGS_NONE; if (!svGetValueEnum (ifcfg, "IEEE_8021X_PHASE1_AUTH_FLAGS", nm_setting_802_1x_auth_flags_get_type (), &i_val, error)) - goto error; + return NULL; g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_AUTH_FLAGS, (guint) i_val, NULL); read_8021x_list_value (ifcfg, "IEEE_8021X_ALTSUBJECT_MATCHES", @@ -3273,25 +3278,18 @@ next: read_8021x_list_value (ifcfg, "IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES", s_8021x, NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES); - value = svGetValueStr_cp (ifcfg, "IEEE_8021X_DOMAIN_SUFFIX_MATCH"); - g_object_set (s_8021x, NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH, value, NULL); - g_free (value); - value = svGetValueStr_cp (ifcfg, "IEEE_8021X_PHASE2_DOMAIN_SUFFIX_MATCH"); - g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH, value, NULL); - g_free (value); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IEEE_8021X_DOMAIN_SUFFIX_MATCH", &value); + g_object_set (s_8021x, NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH, v, NULL); + + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IEEE_8021X_PHASE2_DOMAIN_SUFFIX_MATCH", &value); + g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH, v, NULL); timeout = svGetValueInt64 (ifcfg, "IEEE_8021X_AUTH_TIMEOUT", 10, 0, G_MAXINT32, 0); g_object_set (s_8021x, NM_SETTING_802_1X_AUTH_TIMEOUT, (gint32) timeout, NULL); - if (list) - g_strfreev (list); - return s_8021x; - -error: - if (list) - g_strfreev (list); - g_object_unref (s_8021x); - return NULL; + return g_steal_pointer (&s_8021x); } static NMSetting * @@ -3302,27 +3300,28 @@ make_wpa_setting (shvarFile *ifcfg, NMSetting8021x **s_8021x, GError **error) { - NMSettingWirelessSecurity *wsec; - char *value, *psk, *lower; + gs_unref_object NMSettingWirelessSecurity *wsec = NULL; + gs_free char *value = NULL; + const char *v; gboolean wpa_psk = FALSE, wpa_eap = FALSE, ieee8021x = FALSE; int i_val; GError *local = NULL; wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); - value = svGetValueStr_cp (ifcfg, "KEY_MGMT"); - wpa_psk = !g_strcmp0 (value, "WPA-PSK"); - wpa_eap = !g_strcmp0 (value, "WPA-EAP"); - ieee8021x = !g_strcmp0 (value, "IEEE8021X"); + v = svGetValueStr (ifcfg, "KEY_MGMT", &value); + wpa_psk = nm_streq0 (v, "WPA-PSK"); + wpa_eap = nm_streq0 (v, "WPA-EAP"); + ieee8021x = nm_streq0 (v, "IEEE8021X"); if (!wpa_psk && !wpa_eap && !ieee8021x) - goto error; /* Not WPA or Dynamic WEP */ + return NULL; /* Not WPA or Dynamic WEP */ /* WPS */ i_val = NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DEFAULT; if (!svGetValueEnum (ifcfg, "WPS_METHOD", nm_setting_wireless_security_wps_method_get_type (), &i_val, error)) - goto error; + return NULL; g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_WPS_METHOD, (guint) i_val, NULL); @@ -3338,18 +3337,17 @@ make_wpa_setting (shvarFile *ifcfg, /* Ad-Hoc mode only supports WPA proto for now */ nm_setting_wireless_security_add_proto (wsec, "wpa"); } else { - char *allow_wpa, *allow_rsn; + gs_free char *value2 = NULL; + const char *v2; - allow_wpa = svGetValueStr_cp (ifcfg, "WPA_ALLOW_WPA"); - allow_rsn = svGetValueStr_cp (ifcfg, "WPA_ALLOW_WPA2"); - - if (allow_wpa && svGetValueBoolean (ifcfg, "WPA_ALLOW_WPA", TRUE)) + v2 = svGetValueStr (ifcfg, "WPA_ALLOW_WPA", &value2); + if (v2 && svParseBoolean (v2, TRUE)) nm_setting_wireless_security_add_proto (wsec, "wpa"); - if (allow_rsn && svGetValueBoolean (ifcfg, "WPA_ALLOW_WPA2", TRUE)) - nm_setting_wireless_security_add_proto (wsec, "rsn"); - g_free (allow_wpa); - g_free (allow_rsn); + nm_clear_g_free (&value2); + v2 = svGetValueStr (ifcfg, "WPA_ALLOW_WPA2", &value2); + if (v2 && svParseBoolean (v2, TRUE)) + nm_setting_wireless_security_add_proto (wsec, "rsn"); } if (wpa_psk) { @@ -3360,13 +3358,14 @@ make_wpa_setting (shvarFile *ifcfg, /* Read PSK if it's system-owned */ if (psk_flags == NM_SETTING_SECRET_FLAG_NONE) { + gs_free char *psk = NULL; + psk = parse_wpa_psk (ifcfg, file, ssid, &local); - if (psk) { + if (psk) g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK, psk, NULL); - g_free (psk); - } else if (local) { + else if (local) { g_propagate_error (error, local); - goto error; + return NULL; } } @@ -3378,44 +3377,38 @@ make_wpa_setting (shvarFile *ifcfg, /* Adhoc mode is mutually exclusive with any 802.1x-based authentication */ if (adhoc) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Ad-Hoc mode cannot be used with KEY_MGMT type '%s'", value); - goto error; + "Ad-Hoc mode cannot be used with KEY_MGMT type '%s'", v); + return NULL; } - *s_8021x = fill_8021x (ifcfg, file, value, TRUE, error); + *s_8021x = fill_8021x (ifcfg, file, v, TRUE, error); if (!*s_8021x) - goto error; + return NULL; - lower = g_ascii_strdown (value, -1); - g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, lower, NULL); - g_free (lower); + { + gs_free char *lower = g_ascii_strdown (v, -1); + + g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, lower, NULL); + } } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Unknown wireless KEY_MGMT type '%s'", value); - goto error; + "Unknown wireless KEY_MGMT type '%s'", v); + return NULL; } - g_free (value); - i_val = NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT; if (!svGetValueEnum (ifcfg, "PMF", nm_setting_wireless_security_pmf_get_type (), &i_val, error)) - goto error; + return NULL; g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PMF, i_val, NULL); - value = svGetValueStr_cp (ifcfg, "SECURITYMODE"); - if (NM_IN_STRSET (value, NULL, "open")) - g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, value, NULL); - - g_free (value); - return (NMSetting *) wsec; + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "SECURITYMODE", &value); + if (NM_IN_STRSET (v, NULL, "open")) + g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, v, NULL); -error: - g_free (value); - if (wsec) - g_object_unref (wsec); - return NULL; + return (NMSetting *) g_steal_pointer (&wsec); } static NMSetting * @@ -3940,39 +3933,29 @@ parse_ethtool_option (const char *value, guint32 *out_speed, const char **out_duplex) { - gs_strfreev char **words = NULL; - const char **iter = NULL, *opt_val, *opt; + gs_free const char **words = NULL; + const char *const *iter; + const char *opt_val, *opt; - if (!value || !value[0]) + words = nm_utils_strsplit_set (value, "\t "); + if (!words) return; - words = g_strsplit_set (value, "\t ", 0); - iter = (const char **) words; + iter = words; while (iter[0]) { - /* g_strsplit_set() returns empty tokens when extra spaces are found: skip them */ - if (!*iter[0]) { - iter++; - continue; - } - opt = iter++[0]; - - /* skip over repeated space characters like to parse "wol d". */ - while (iter[0] && !*iter[0]) - iter++; - opt_val = iter[0]; - if (g_str_equal (opt, "autoneg")) + if (nm_streq (opt, "autoneg")) parse_ethtool_option_autoneg (opt_val, out_autoneg); - else if (g_str_equal (opt, "speed")) + else if (nm_streq (opt, "speed")) parse_ethtool_option_speed (opt_val, out_speed); - else if (g_str_equal (opt, "duplex")) + else if (nm_streq (opt, "duplex")) parse_ethtool_option_duplex (opt_val, out_duplex); - else if (g_str_equal (opt, "wol")) + else if (nm_streq (opt, "wol")) parse_ethtool_option_wol (opt_val, out_flags); - else if (g_str_equal (opt, "sopass")) + else if (nm_streq (opt, "sopass")) parse_ethtool_option_sopass (opt_val, out_password); else { /* Silently skip unknown options */ @@ -3994,15 +3977,15 @@ parse_ethtool_options (shvarFile *ifcfg, NMSettingWired *s_wired, const char *va const char *duplex = NULL; if (value) { - gs_strfreev char **opts = NULL; - const char **iter; + gs_free const char **opts = NULL; + const char *const *iter; /* WAKE_ON_LAN_IGNORE is inferred from a specified but empty ETHTOOL_OPTS */ if (!value[0]) wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE; - opts = g_strsplit_set (value, ";", 0); - for (iter = (const char **) opts; iter[0]; iter++) { + opts = nm_utils_strsplit_set (value, ";"); + 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. */ parse_ethtool_option (iter[0], &wol_flags, &wol_password, &autoneg, &speed, &duplex); @@ -4068,7 +4051,6 @@ make_wired_setting (shvarFile *ifcfg, if (value) { const char *p = value; gboolean success = TRUE; - char **chans = NULL; /* basic sanity checks */ while (*p) { @@ -4081,16 +4063,16 @@ make_wired_setting (shvarFile *ifcfg, } if (success) { + gs_free const char **chans = NULL; guint32 num_chans; - chans = g_strsplit_set (value, ",", 0); - num_chans = g_strv_length (chans); + chans = nm_utils_strsplit_set (value, ","); + num_chans = NM_PTRARRAY_LEN (chans); if (num_chans < 2 || num_chans > 3) { - PARSE_WARNING ("invalid SUBCHANNELS '%s' (%d channels, 2 or 3 expected)", - value, g_strv_length (chans)); + PARSE_WARNING ("invalid SUBCHANNELS '%s' (%u channels, 2 or 3 expected)", + value, (unsigned) NM_PTRARRAY_LEN (chans)); } else g_object_set (s_wired, NM_SETTING_WIRED_S390_SUBCHANNELS, chans, NULL); - g_strfreev (chans); } nm_clear_g_free (&value); } @@ -4396,40 +4378,37 @@ make_bond_setting (shvarFile *ifcfg, GError **error) { NMSettingBond *s_bond; - char *value; + gs_free char *value = NULL; + const char *v; - value = svGetValueStr_cp (ifcfg, "DEVICE"); - if (!value) { + v = svGetValueStr (ifcfg, "DEVICE", &value); + if (!v) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "mandatory DEVICE keyword missing"); return NULL; } - g_free (value); s_bond = NM_SETTING_BOND (nm_setting_bond_new ()); - value = svGetValueStr_cp (ifcfg, "BONDING_OPTS"); - if (value) { - char **items, **iter; + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "BONDING_OPTS", &value); + if (v) { + gs_free const char **items = NULL; + const char *const *iter; - items = g_strsplit_set (value, " ", -1); + items = nm_utils_strsplit_set (v, " "); for (iter = items; iter && *iter; iter++) { - if (strlen (*iter)) { - char **keys, *key, *val; - - keys = g_strsplit_set (*iter, "=", 2); - if (keys && *keys) { - key = *keys; - val = *(keys + 1); - if (val && key[0] && val[0]) - handle_bond_option (s_bond, key, val); - } + gs_strfreev char **keys = NULL; + const char *key, *val; - g_strfreev (keys); + keys = g_strsplit_set (*iter, "=", 2); + if (keys && *keys) { + key = *keys; + val = *(keys + 1); + if (val && key[0] && val[0]) + handle_bond_option (s_bond, key, val); } } - g_free (value); - g_strfreev (items); } return (NMSetting *) s_bond; @@ -4644,25 +4623,22 @@ handle_bridging_opts (NMSetting *setting, const char *value, BridgeOptFunc func) { - char **items, **iter; + gs_free const char **items = NULL; + const char *const *iter; - items = g_strsplit_set (value, " ", -1); + items = nm_utils_strsplit_set (value, " "); for (iter = items; iter && *iter; iter++) { - if (strlen (*iter)) { - char **keys, *key, *val; - - keys = g_strsplit_set (*iter, "=", 2); - if (keys && *keys) { - key = *keys; - val = *(keys + 1); - if (val && strlen (key) && strlen (val)) - func (setting, stp, key, val); - } - - g_strfreev (keys); + gs_strfreev char **keys = NULL; + const char *key, *val; + + keys = g_strsplit_set (*iter, "=", 2); + if (keys && *keys) { + key = *keys; + val = *(keys + 1); + if (val && key[0] && val[0]) + func (setting, stp, key, val); } } - g_strfreev (items); } static NMSetting * @@ -4884,24 +4860,22 @@ parse_prio_map_list (NMSettingVlan *s_vlan, const char *key, NMVlanPriorityMap map) { - char *value; - gchar **list = NULL, **iter; + gs_free char *value = NULL; + gs_free const char **list = NULL; + const char *const *iter; + const char *v; - value = svGetValueStr_cp (ifcfg, key); - if (!value) + v = svGetValueStr (ifcfg, key, &value); + if (!v) return; - - list = g_strsplit_set (value, ",", -1); - g_free (value); + list = nm_utils_strsplit_set (v, ","); for (iter = list; iter && *iter; iter++) { - if (!*iter || !strchr (*iter, ':')) + if (!strchr (*iter, ':')) continue; - if (!nm_setting_vlan_add_priority_str (s_vlan, map, *iter)) PARSE_WARNING ("invalid %s priority map item '%s'", key, *iter); } - g_strfreev (list); } static NMSetting * @@ -4912,22 +4886,20 @@ make_vlan_setting (shvarFile *ifcfg, gs_unref_object NMSettingVlan *s_vlan = NULL; gs_free char *parent = NULL; gs_free char *iface_name = NULL; - char *value = NULL; - const char *p = NULL; + gs_free char *value = NULL; + const char *v = NULL; int vlan_id = -1; guint32 vlan_flags = 0; gint gvrp, reorder_hdr; - value = svGetValueStr_cp (ifcfg, "VLAN_ID"); - if (value) { - vlan_id = _nm_utils_ascii_str_to_int64 (value, 10, 0, 4095, -1); + v = svGetValueStr (ifcfg, "VLAN_ID", &value); + if (v) { + vlan_id = _nm_utils_ascii_str_to_int64 (v, 10, 0, 4095, -1); if (vlan_id == -1) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid VLAN_ID '%s'", value); - g_free (value); + "Invalid VLAN_ID '%s'", v); return NULL; } - g_free (value); } /* Need DEVICE if we don't have a separate VLAN_ID property */ @@ -4944,11 +4916,11 @@ make_vlan_setting (shvarFile *ifcfg, parent = svGetValueStr_cp (ifcfg, "PHYSDEV"); if (iface_name) { - p = strchr (iface_name, '.'); - if (p) { + v = strchr (iface_name, '.'); + if (v) { /* eth0.43; PHYSDEV is assumed from it if unknown */ if (!parent) { - parent = g_strndup (iface_name, p - iface_name); + parent = g_strndup (iface_name, v - iface_name); if (g_str_has_prefix (parent, "vlan")) { /* Like initscripts, if no PHYSDEV and we get an obviously * invalid parent interface from DEVICE, fail. @@ -4956,20 +4928,20 @@ make_vlan_setting (shvarFile *ifcfg, nm_clear_g_free (&parent); } } - p++; + v++; } else { /* format like vlan43; PHYSDEV must be set */ if (g_str_has_prefix (iface_name, "vlan")) - p = iface_name + 4; + v = iface_name + 4; } - if (p) { + if (v) { int device_vlan_id; /* Grab VLAN ID from interface name; this takes precedence over the * separate VLAN_ID property for backwards compat. */ - device_vlan_id = _nm_utils_ascii_str_to_int64 (p, 10, 0, 4095, -1); + device_vlan_id = _nm_utils_ascii_str_to_int64 (v, 10, 0, 4095, -1); if (device_vlan_id != -1) vlan_id = device_vlan_id; } @@ -4995,13 +4967,13 @@ make_vlan_setting (shvarFile *ifcfg, if (gvrp > 0) vlan_flags |= NM_VLAN_FLAG_GVRP; - value = svGetValueStr_cp (ifcfg, "VLAN_FLAGS"); - if (value) { - gs_strfreev char **strv = NULL; - char **ptr; - - strv = g_strsplit_set (value, ", ", 0); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "VLAN_FLAGS", &value); + if (v) { + gs_free const char **strv = NULL; + const char *const *ptr; + 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; @@ -5021,7 +4993,6 @@ make_vlan_setting (shvarFile *ifcfg, vlan_flags |= NM_VLAN_FLAG_MVRP; g_object_set (s_vlan, NM_SETTING_VLAN_FLAGS, vlan_flags, NULL); - g_free (value); parse_prio_map_list (s_vlan, ifcfg, "VLAN_INGRESS_PRIORITY_MAP", NM_VLAN_INGRESS_MAP); parse_prio_map_list (s_vlan, ifcfg, "VLAN_EGRESS_PRIORITY_MAP", NM_VLAN_EGRESS_MAP); @@ -5081,7 +5052,8 @@ create_unhandled_connection (const char *filename, shvarFile *ifcfg, { NMConnection *connection; NMSetting *s_con; - char *value; + gs_free char *value = NULL; + const char *v; nm_assert (out_spec && !*out_spec); @@ -5098,26 +5070,25 @@ create_unhandled_connection (const char *filename, shvarFile *ifcfg, nm_connection_add_setting (connection, nm_setting_generic_new ()); /* Get a spec */ - value = svGetValueStr_cp (ifcfg, "HWADDR"); - if (value) { - char *lower = g_ascii_strdown (value, -1); + v = svGetValueStr (ifcfg, "HWADDR", &value); + if (v) { + gs_free char *lower = g_ascii_strdown (v, -1); + *out_spec = g_strdup_printf ("%s:mac:%s", type, lower); - g_free (lower); - g_free (value); return connection; } - value = svGetValueStr_cp (ifcfg, "SUBCHANNELS"); - if (value) { - *out_spec = g_strdup_printf ("%s:s390-subchannels:%s", type, value); - g_free (value); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "SUBCHANNELS", &value); + if (v) { + *out_spec = g_strdup_printf ("%s:s390-subchannels:%s", type, v); return connection; } - value = svGetValueStr_cp (ifcfg, "DEVICE"); - if (value) { - *out_spec = g_strdup_printf ("%s:interface-name:%s", type, value); - g_free (value); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "DEVICE", &value); + if (v) { + *out_spec = g_strdup_printf ("%s:interface-name:%s", type, v); return connection; } @@ -5134,23 +5105,24 @@ check_dns_search_domains (shvarFile *ifcfg, NMSetting *s_ip4, NMSetting *s_ip6) /* If there is no IPv4 config or it doesn't contain DNS searches, * read DOMAIN and put the domains into IPv6. */ - if (!s_ip4 || nm_setting_ip_config_get_num_dns_searches (NM_SETTING_IP_CONFIG (s_ip4)) == 0) { + if ( !s_ip4 + || nm_setting_ip_config_get_num_dns_searches (NM_SETTING_IP_CONFIG (s_ip4)) == 0) { /* DNS searches */ - char *value = svGetValueStr_cp (ifcfg, "DOMAIN"); + gs_free char *value = NULL; + const char *v; - if (value) { - char **searches = g_strsplit (value, " ", 0); + v = svGetValueStr (ifcfg, "DOMAIN", &value); + if (v) { + gs_free const char **searches = NULL; + const char *const *item; + + searches = nm_utils_strsplit_set (v, " "); if (searches) { - char **item; for (item = searches; *item; item++) { - if (strlen (*item)) { - if (!nm_setting_ip_config_add_dns_search (NM_SETTING_IP_CONFIG (s_ip6), *item)) - PARSE_WARNING ("duplicate DNS domain '%s'", *item); - } + if (!nm_setting_ip_config_add_dns_search (NM_SETTING_IP_CONFIG (s_ip6), *item)) + PARSE_WARNING ("duplicate DNS domain '%s'", *item); } - g_strfreev (searches); } - g_free (value); } } } diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index c1b927aadf..2f4c58e040 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1891,7 +1891,17 @@ get_route_attributes_string (NMIPRoute *route, int family) (lock && g_variant_get_boolean (lock)) ? "lock " : "", g_variant_get_uint32 (attr)); } else if (strstr (names[i], "lock-")) { - /* handled above */ + const char *n = &(names[i])[NM_STRLEN ("lock-")]; + + attr = nm_ip_route_get_attribute (route, n); + if (!attr) { + g_string_append_printf (str, + "%s lock 0", + n); + } else { + /* we also have a corresponding attribute with the numeric value. The + * lock setting is handled above. */ + } } else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_TOS)) { g_string_append_printf (str, "%s 0x%02x", names[i], (unsigned) g_variant_get_byte (attr)); } else if ( nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC) diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c index 0206f35861..d939d0ee6b 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.c +++ b/src/settings/plugins/ifcfg-rh/shvar.c @@ -645,7 +645,7 @@ svFileGetName (const shvarFile *s) } void -svFileSetName_test_only (shvarFile *s, const char *fileName) +_nmtst_svFileSetName (shvarFile *s, const char *fileName) { /* changing the file name is not supported for regular * operation. Only allowed to use in tests, othewise, @@ -655,7 +655,7 @@ svFileSetName_test_only (shvarFile *s, const char *fileName) } void -svFileSetModified_test_only (shvarFile *s) +_nmtst_svFileSetModified (shvarFile *s) { /* marking a file as modified is only for testing. */ s->modified = TRUE; diff --git a/src/settings/plugins/ifcfg-rh/shvar.h b/src/settings/plugins/ifcfg-rh/shvar.h index 34f952e4ef..8fbc14808e 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.h +++ b/src/settings/plugins/ifcfg-rh/shvar.h @@ -35,8 +35,8 @@ typedef struct _shvarFile shvarFile; const char *svFileGetName (const shvarFile *s); -void svFileSetName_test_only (shvarFile *s, const char *fileName); -void svFileSetModified_test_only (shvarFile *s); +void _nmtst_svFileSetName (shvarFile *s, const char *fileName); +void _nmtst_svFileSetModified (shvarFile *s); /* Create the file <name>, return a shvarFile (never fails) */ shvarFile *svCreateFile (const char *name); diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 1a70af5cec..3d3b672c6a 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -9156,8 +9156,8 @@ test_write_unknown (gconstpointer test_data) sv = _svOpenFile (testfile); - svFileSetName_test_only (sv, filename_tmp_1); - svFileSetModified_test_only (sv); + _nmtst_svFileSetName (sv, filename_tmp_1); + _nmtst_svFileSetModified (sv); if (g_str_has_suffix (testfile, "ifcfg-test-write-unknown-4")) { _svGetValue_check (sv, "NAME", "l4x"); |