libnm/keyfile: make parsing route/address keys reusable
Will be used for routing rules as well.
This commit is contained in:
@@ -534,13 +534,18 @@ typedef struct {
|
|||||||
const char *s_key;
|
const char *s_key;
|
||||||
gint32 key_idx;
|
gint32 key_idx;
|
||||||
gint8 key_type;
|
gint8 key_type;
|
||||||
} IPAddrRouteBuildListData;
|
} BuildListData;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BUILD_LIST_TYPE_ADDRESSES,
|
||||||
|
BUILD_LIST_TYPE_ROUTES,
|
||||||
|
} BuildListType;
|
||||||
|
|
||||||
static int
|
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 BuildListData *a = p_a;
|
||||||
const IPAddrRouteBuildListData *b = p_b;
|
const BuildListData *b = p_b;
|
||||||
|
|
||||||
NM_CMP_FIELD (a, b, key_idx);
|
NM_CMP_FIELD (a, b, key_idx);
|
||||||
NM_CMP_FIELD (a, b, key_type);
|
NM_CMP_FIELD (a, b, key_type);
|
||||||
@@ -549,7 +554,22 @@ _ip_addrroute_build_lst_data_cmp (gconstpointer p_a, gconstpointer p_b, gpointer
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
ip_addrroute_match_key_w_name_ (const char *key,
|
_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,
|
const char *base_name,
|
||||||
gsize base_name_l,
|
gsize base_name_l,
|
||||||
gint32 *out_key_idx)
|
gint32 *out_key_idx)
|
||||||
@@ -595,31 +615,79 @@ ip_addrroute_match_key_w_name_ (const char *key,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
#define _build_list_match_key_w_name(key, base_name, out_key_idx) \
|
||||||
ip_addrroute_match_key (const char *key,
|
_build_list_match_key_w_name_impl (key, base_name, NM_STRLEN (base_name), out_key_idx)
|
||||||
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)
|
|
||||||
|
|
||||||
if (is_routes) {
|
static BuildListData *
|
||||||
if (ip_addrroute_match_key_w_name (key, "route", out_key_idx))
|
_build_list_create (GKeyFile *keyfile,
|
||||||
NM_SET_OUT (out_key_type, 0);
|
const char *group_name,
|
||||||
else if (ip_addrroute_match_key_w_name (key, "routes", out_key_idx))
|
BuildListType build_list_type,
|
||||||
NM_SET_OUT (out_key_type, 1);
|
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
|
else
|
||||||
return FALSE;
|
continue;
|
||||||
} else {
|
break;
|
||||||
if (ip_addrroute_match_key_w_name (key, "address", out_key_idx))
|
case BUILD_LIST_TYPE_ADDRESSES:
|
||||||
NM_SET_OUT (out_key_type, 0);
|
if (_build_list_match_key_w_name (s_key, "address", &key_idx))
|
||||||
else if (ip_addrroute_match_key_w_name (key, "addresses", out_key_idx))
|
key_type = 0;
|
||||||
NM_SET_OUT (out_key_type, 1);
|
else if (_build_list_match_key_w_name (s_key, "addresses", &key_idx))
|
||||||
|
key_type = 1;
|
||||||
else
|
else
|
||||||
return FALSE;
|
continue;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nm_assert_not_reached ();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return TRUE;
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
static void
|
||||||
@@ -631,64 +699,35 @@ ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const c
|
|||||||
gs_free char *gateway = NULL;
|
gs_free char *gateway = NULL;
|
||||||
gs_unref_ptrarray GPtrArray *list = NULL;
|
gs_unref_ptrarray GPtrArray *list = NULL;
|
||||||
gs_strfreev char **keys = NULL;
|
gs_strfreev char **keys = NULL;
|
||||||
gsize i_keys, n_keys;
|
gs_free BuildListData *build_list = NULL;
|
||||||
gs_free IPAddrRouteBuildListData *build_list = NULL;
|
|
||||||
gsize i_build_list, build_list_len = 0;
|
gsize i_build_list, build_list_len = 0;
|
||||||
|
|
||||||
keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &n_keys, NULL);
|
build_list = _build_list_create (info->keyfile,
|
||||||
if (n_keys == 0)
|
setting_name,
|
||||||
|
is_routes
|
||||||
|
? BUILD_LIST_TYPE_ROUTES
|
||||||
|
: BUILD_LIST_TYPE_ADDRESSES,
|
||||||
|
&build_list_len,
|
||||||
|
&keys);
|
||||||
|
if (!build_list)
|
||||||
return;
|
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
|
list = g_ptr_array_new_with_free_func (is_routes
|
||||||
? (GDestroyNotify) nm_ip_route_unref
|
? (GDestroyNotify) nm_ip_route_unref
|
||||||
: (GDestroyNotify) nm_ip_address_unref);
|
: (GDestroyNotify) nm_ip_address_unref);
|
||||||
|
|
||||||
for (i_build_list = 0; i_build_list < build_list_len; i_build_list++) {
|
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;
|
gpointer item;
|
||||||
|
|
||||||
if ( i_build_list + 1 < build_list_len
|
if (_build_list_data_is_shadowed (build_list, build_list_len, i_build_list))
|
||||||
&& 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. */
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
|
s_key = build_list[i_build_list].s_key;
|
||||||
item = read_one_ip_address_or_route (info,
|
item = read_one_ip_address_or_route (info,
|
||||||
setting_key,
|
setting_key,
|
||||||
setting_name,
|
setting_name,
|
||||||
build_data->s_key,
|
s_key,
|
||||||
is_ipv6,
|
is_ipv6,
|
||||||
is_routes,
|
is_routes,
|
||||||
gateway ? NULL : &gateway,
|
gateway ? NULL : &gateway,
|
||||||
@@ -696,7 +735,7 @@ ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const c
|
|||||||
if (item && is_routes) {
|
if (item && is_routes) {
|
||||||
char options_key[128];
|
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,
|
fill_route_attributes (info->keyfile,
|
||||||
item,
|
item,
|
||||||
setting_name,
|
setting_name,
|
||||||
|
Reference in New Issue
Block a user