diff options
author | Thomas Haller <thaller@redhat.com> | 2015-05-15 11:36:28 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-06-05 12:38:29 +0200 |
commit | dc0193ac023e30a9a3794e78c66f8c5266695a60 (patch) | |
tree | 2017276f2bec76590e38c9552e3030005fcef543 /src/nm-config-data.c | |
parent | f031b926c452aea5a28390eee2cfb9b9f0d15652 (diff) |
config: support a [connection] section to NetworkManager.conf to specify connection defaults
Add support for a new section [connection] in NetworkManager.conf.
If the connection leaves an option at "unknown"/"default", we can
support overwriting the value from global configuration.
We also support other sections that are named with "connection"
as a prefix, such as [connection2], [connection-wifi]. This is
to support multiple default values that can be applied depending
on the used device.
I think this has great potential. Only downside is that when
the user looks at a connection value, it will see that it is
unspecified. But the actually used value depends on the device
type and might not be obvious.
https://bugzilla.gnome.org/show_bug.cgi?id=695383
https://bugzilla.redhat.com/show_bug.cgi?id=1164677
Diffstat (limited to 'src/nm-config-data.c')
-rw-r--r-- | src/nm-config-data.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/src/nm-config-data.c b/src/nm-config-data.c index 41995a043..73c36312f 100644 --- a/src/nm-config-data.c +++ b/src/nm-config-data.c @@ -27,6 +27,19 @@ #include "gsystem-local-alloc.h" #include "nm-device.h" #include "nm-core-internal.h" +#include "nm-macros-internal.h" + +typedef struct { + char *group_name; + gboolean stop_match; + struct { + /* have a separate boolean field @has, because a @spec with + * value %NULL does not necessarily mean, that the property + * "match-device" was unspecified. */ + gboolean has; + GSList *spec; + } match_device; +} ConnectionInfo; typedef struct { char *config_main_file; @@ -34,6 +47,10 @@ typedef struct { GKeyFile *keyfile; + /* A zero-terminated list of pre-processed information from the + * [connection] sections. This is to speed up lookup. */ + ConnectionInfo *connection_infos; + struct { char *uri; char *response; @@ -172,6 +189,100 @@ nm_config_data_get_assume_ipv6ll_only (const NMConfigData *self, NMDevice *devic /************************************************************************/ +char * +nm_config_data_get_connection_default (const NMConfigData *self, + const char *property, + NMDevice *device) +{ + NMConfigDataPrivate *priv; + const ConnectionInfo *connection_info; + + g_return_val_if_fail (self, NULL); + g_return_val_if_fail (property && *property, NULL); + g_return_val_if_fail (strchr (property, '.'), NULL); + + priv = NM_CONFIG_DATA_GET_PRIVATE (self); + + if (!priv->connection_infos) + return NULL; + + for (connection_info = &priv->connection_infos[0]; connection_info->group_name; connection_info++) { + char *value; + gboolean match; + + value = g_key_file_get_value (priv->keyfile, connection_info->group_name, property, NULL); + if (!value && !connection_info->stop_match) + continue; + + match = TRUE; + if (connection_info->match_device.has) + match = device && nm_device_spec_match_list (device, connection_info->match_device.spec); + + if (match) + return value; + g_free (value); + } + return NULL; +} + +static ConnectionInfo * +_get_connection_infos (GKeyFile *keyfile) +{ + char **groups; + guint i; + char *connection_tag = NULL; + GSList *connection_groups = NULL; + ConnectionInfo *connection_infos = NULL; + + /* get the list of existing [connection.\+] sections that we consider + * for nm_config_data_get_connection_default(). Also, get them + * in the right order. */ + groups = g_key_file_get_groups (keyfile, NULL); + for (i = 0; groups && groups[i]; i++) { + if (g_str_has_prefix (groups[i], "connection")) { + if (strlen (groups[i]) == STRLEN ("connection")) + connection_tag = groups[i]; + else + connection_groups = g_slist_prepend (connection_groups, groups[i]); + } else + g_free (groups[i]); + } + g_free (groups); + if (connection_tag) { + /* We want the group "connection" checked at last, so that + * all other "connection.\+" have preference. Those other + * groups are checked in order of appearance. */ + connection_groups = g_slist_prepend (connection_groups, connection_tag); + } + if (connection_groups) { + guint len = g_slist_length (connection_groups); + GSList *iter; + + connection_infos = g_new0 (ConnectionInfo, len + 1); + for (iter = connection_groups; iter; iter = iter->next) { + ConnectionInfo *connection_info; + char *value; + + nm_assert (len >= 1); + connection_info = &connection_infos[--len]; + connection_info->group_name = iter->data; + + value = g_key_file_get_value (keyfile, iter->data, "match-device", NULL); + if (value) { + connection_info->match_device.has = TRUE; + connection_info->match_device.spec = nm_match_spec_split (value); + g_free (value); + } + connection_info->stop_match = nm_config_keyfile_get_boolean (keyfile, iter->data, "stop-match", FALSE); + } + g_slist_free (connection_groups); + } + + return connection_infos; +} + +/************************************************************************/ + static gboolean _keyfile_a_contains_all_in_b (GKeyFile *kf_a, GKeyFile *kf_b) { @@ -324,6 +435,7 @@ static void finalize (GObject *gobject) { NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (gobject); + guint i; g_free (priv->config_main_file); g_free (priv->config_description); @@ -340,6 +452,14 @@ finalize (GObject *gobject) g_slist_free_full (priv->ignore_carrier, g_free); g_slist_free_full (priv->assume_ipv6ll_only, g_free); + if (priv->connection_infos) { + for (i = 0; priv->connection_infos[i].group_name; i++) { + g_free (priv->connection_infos[i].group_name); + g_slist_free_full (priv->connection_infos[i].match_device.spec, g_free); + } + g_free (priv->connection_infos); + } + g_key_file_unref (priv->keyfile); G_OBJECT_CLASS (nm_config_data_parent_class)->finalize (gobject); @@ -357,6 +477,8 @@ constructed (GObject *object) NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (self); char *interval; + priv->connection_infos = _get_connection_infos (priv->keyfile); + priv->connectivity.uri = g_key_file_get_value (priv->keyfile, "connectivity", "uri", NULL); priv->connectivity.response = g_key_file_get_value (priv->keyfile, "connectivity", "response", NULL); |