From 28efb61d077d028c455cb1b34b50a0744a06aeef Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 20 Mar 2019 19:09:19 +0100 Subject: [PATCH] libnm/keyfile: make parsing route/address keys reusable Will be used for routing rules as well. --- libnm-core/nm-keyfile.c | 187 ++++++++++++++++++++++++---------------- 1 file changed, 113 insertions(+), 74 deletions(-) diff --git a/libnm-core/nm-keyfile.c b/libnm-core/nm-keyfile.c index 0d833752e..955015d65 100644 --- a/libnm-core/nm-keyfile.c +++ b/libnm-core/nm-keyfile.c @@ -534,13 +534,18 @@ typedef struct { const char *s_key; gint32 key_idx; gint8 key_type; -} IPAddrRouteBuildListData; +} BuildListData; + +typedef enum { + BUILD_LIST_TYPE_ADDRESSES, + BUILD_LIST_TYPE_ROUTES, +} BuildListType; static int -_ip_addrroute_build_lst_data_cmp (gconstpointer p_a, gconstpointer p_b, gpointer user_data) +_build_list_data_cmp (gconstpointer p_a, gconstpointer p_b, gpointer user_data) { - const IPAddrRouteBuildListData *a = p_a; - const IPAddrRouteBuildListData *b = p_b; + const BuildListData *a = p_a; + const BuildListData *b = p_b; NM_CMP_FIELD (a, b, key_idx); NM_CMP_FIELD (a, b, key_type); @@ -549,10 +554,25 @@ _ip_addrroute_build_lst_data_cmp (gconstpointer p_a, gconstpointer p_b, gpointer } static gboolean -ip_addrroute_match_key_w_name_ (const char *key, - const char *base_name, - gsize base_name_l, - gint32 *out_key_idx) +_build_list_data_is_shadowed (const BuildListData *build_list, + gsize build_list_len, + gsize idx) +{ + /* the keyfile contains duplicate keys, which are both returned + * by g_key_file_get_keys() (WHY??). + * + * Skip the earlier one. */ + return idx + 1 < build_list_len + && build_list[idx].key_idx == build_list[idx + 1].key_idx + && build_list[idx].key_type == build_list[idx + 1].key_type + && nm_streq (build_list[idx].s_key, build_list[idx + 1].s_key); +} + +static gboolean +_build_list_match_key_w_name_impl (const char *key, + const char *base_name, + gsize base_name_l, + gint32 *out_key_idx) { gint64 v; @@ -595,31 +615,79 @@ ip_addrroute_match_key_w_name_ (const char *key, return TRUE; } -static gboolean -ip_addrroute_match_key (const char *key, - gboolean is_routes, - gint32 *out_key_idx, - gint8 *out_key_type) -{ -#define ip_addrroute_match_key_w_name(key, base_name, out_key_idx) \ - ip_addrroute_match_key_w_name_ (key, base_name, NM_STRLEN (base_name), out_key_idx) +#define _build_list_match_key_w_name(key, base_name, out_key_idx) \ + _build_list_match_key_w_name_impl (key, base_name, NM_STRLEN (base_name), out_key_idx) - if (is_routes) { - if (ip_addrroute_match_key_w_name (key, "route", out_key_idx)) - NM_SET_OUT (out_key_type, 0); - else if (ip_addrroute_match_key_w_name (key, "routes", out_key_idx)) - NM_SET_OUT (out_key_type, 1); - else - return FALSE; - } else { - if (ip_addrroute_match_key_w_name (key, "address", out_key_idx)) - NM_SET_OUT (out_key_type, 0); - else if (ip_addrroute_match_key_w_name (key, "addresses", out_key_idx)) - NM_SET_OUT (out_key_type, 1); - else - return FALSE; +static BuildListData * +_build_list_create (GKeyFile *keyfile, + const char *group_name, + BuildListType build_list_type, + gsize *out_build_list_len, + char ***out_keys_strv) +{ + gs_strfreev char **keys = NULL; + gsize i_keys, n_keys; + gs_free BuildListData *build_list = NULL; + gsize build_list_len = 0; + + nm_assert (out_build_list_len && *out_build_list_len == 0); + nm_assert (out_keys_strv && !*out_keys_strv); + + keys = nm_keyfile_plugin_kf_get_keys (keyfile, group_name, &n_keys, NULL); + if (n_keys == 0) + return NULL; + + for (i_keys = 0; i_keys < n_keys; i_keys++) { + const char *s_key = keys[i_keys]; + gint32 key_idx; + gint8 key_type; + + switch (build_list_type) { + case BUILD_LIST_TYPE_ROUTES: + if (_build_list_match_key_w_name (s_key, "route", &key_idx)) + key_type = 0; + else if (_build_list_match_key_w_name (s_key, "routes", &key_idx)) + key_type = 1; + else + continue; + break; + case BUILD_LIST_TYPE_ADDRESSES: + if (_build_list_match_key_w_name (s_key, "address", &key_idx)) + key_type = 0; + else if (_build_list_match_key_w_name (s_key, "addresses", &key_idx)) + key_type = 1; + else + continue; + break; + default: + nm_assert_not_reached (); + break; + } + + if (G_UNLIKELY (!build_list)) + build_list = g_new (BuildListData, n_keys - i_keys); + + build_list[build_list_len++] = (BuildListData) { + .s_key = s_key, + .key_idx = key_idx, + .key_type = key_type, + }; } - return TRUE; + + if (build_list_len == 0) + return NULL; + + if (build_list_len > 1) { + g_qsort_with_data (build_list, + build_list_len, + sizeof (BuildListData), + _build_list_data_cmp, + NULL); + } + + *out_build_list_len = build_list_len; + *out_keys_strv = g_steal_pointer (&keys); + return g_steal_pointer (&build_list); } static void @@ -631,64 +699,35 @@ ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const c gs_free char *gateway = NULL; gs_unref_ptrarray GPtrArray *list = NULL; gs_strfreev char **keys = NULL; - gsize i_keys, n_keys; - gs_free IPAddrRouteBuildListData *build_list = NULL; + gs_free BuildListData *build_list = NULL; gsize i_build_list, build_list_len = 0; - keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &n_keys, NULL); - if (n_keys == 0) + build_list = _build_list_create (info->keyfile, + setting_name, + is_routes + ? BUILD_LIST_TYPE_ROUTES + : BUILD_LIST_TYPE_ADDRESSES, + &build_list_len, + &keys); + if (!build_list) return; - /* first create a list of all relevant keys, and sort them. */ - for (i_keys = 0; i_keys < n_keys; i_keys++) { - const char *s_key = keys[i_keys]; - gint32 key_idx; - gint8 key_type; - - if (!ip_addrroute_match_key (s_key, is_routes, &key_idx, &key_type)) - continue; - - if (G_UNLIKELY (!build_list)) - build_list = g_new (IPAddrRouteBuildListData, n_keys - i_keys); - - build_list[build_list_len].s_key = s_key; - build_list[build_list_len].key_idx = key_idx; - build_list[build_list_len].key_type = key_type; - build_list_len++; - } - - if (build_list_len == 0) - return; - - g_qsort_with_data (build_list, - build_list_len, - sizeof (IPAddrRouteBuildListData), - _ip_addrroute_build_lst_data_cmp, - NULL); - list = g_ptr_array_new_with_free_func (is_routes ? (GDestroyNotify) nm_ip_route_unref : (GDestroyNotify) nm_ip_address_unref); for (i_build_list = 0; i_build_list < build_list_len; i_build_list++) { - const IPAddrRouteBuildListData *build_data = &build_list[i_build_list]; + const char *s_key; gpointer item; - if ( i_build_list + 1 < build_list_len - && build_data->key_idx == build_data[1].key_idx - && build_data->key_type == build_data[1].key_type - && nm_streq (build_data->s_key, build_data[1].s_key)) { - /* the keyfile contains duplicate keys, which are both returned - * by g_key_file_get_keys() (WHY??). - * - * Skip the earlier one. */ + if (_build_list_data_is_shadowed (build_list, build_list_len, i_build_list)) continue; - } + s_key = build_list[i_build_list].s_key; item = read_one_ip_address_or_route (info, setting_key, setting_name, - build_data->s_key, + s_key, is_ipv6, is_routes, gateway ? NULL : &gateway, @@ -696,7 +735,7 @@ ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const c if (item && is_routes) { char options_key[128]; - nm_sprintf_buf (options_key, "%s_options", build_data->s_key); + nm_sprintf_buf (options_key, "%s_options", s_key); fill_route_attributes (info->keyfile, item, setting_name,