summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2015-06-24 20:11:42 +0200
committerThomas Haller <thaller@redhat.com>2015-07-02 16:01:20 +0200
commit947fc9a27885c268ea742e33d18f27666fa9a043 (patch)
treea6e095b02e400c7dd5dd8e8802ade9680db3febc
parent6f0036151f464921a62d15c03cd9aa0f213e6200 (diff)
downloadNetworkManager-947fc9a27885c268ea742e33d18f27666fa9a043.tar.gz
config: add write support for NMConfig
Internal configuration is written as keyfile to NMSTATEDIR"/NetworkManager-intern.conf" Basically, the content of this file is merged with user configuration from "NetworkManager.conf" files. After loading the configuration, NMConfig exposes a merged view of user-provided settings and internal overwrites. All sections/groups named [.intern*] are reserved for internal configuration values. They can be written by API, but are ignored when the user sets them via "NetworkManager.conf". For these internal sections, no conflicts can arise. We can also overwrite individual properties from user configuration. In this case, we store the value we want to set, but also remember the value that the user configuration had, at the time of setting. If on a later reload the user configuration changed, we ignore our internal value -- as we assume that the user modified the value afterwards. We can also hide/delete value from user configuration. This works on a per-setting basis.
-rw-r--r--man/NetworkManager.conf.xml.in17
-rw-r--r--src/devices/nm-device.c2
-rw-r--r--src/nm-config-data.c181
-rw-r--r--src/nm-config-data.h24
-rw-r--r--src/nm-config.c468
-rw-r--r--src/nm-config.h11
-rw-r--r--src/tests/config/test-config.c22
7 files changed, 677 insertions, 48 deletions
diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in
index 9557d7a9be..bf15c9e8b5 100644
--- a/man/NetworkManager.conf.xml.in
+++ b/man/NetworkManager.conf.xml.in
@@ -28,16 +28,19 @@ Copyright 2010 - 2014 Red Hat, Inc.
<refsynopsisdiv>
<para><filename>/etc/NetworkManager/NetworkManager.conf</filename>,
<filename>/etc/NetworkManager/conf.d/<replaceable>name</replaceable>.conf</filename>,
- <filename>/usr/lib/NetworkManager/conf.d/<replaceable>name</replaceable>.conf</filename>
+ <filename>/usr/lib/NetworkManager/conf.d/<replaceable>name</replaceable>.conf</filename>,
+ <filename>/var/lib/NetworkManager/NetworkManager-intern.conf</filename>
</para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
- <para>This is a configuration file for NetworkManager. It is used
+ <para><literal>NetworkManager.conf</literal> is the configuration file for NetworkManager. It is used
to set up various aspects of NetworkManager's behavior. The
- location of the file may be changed through use of the
- <option>--config</option> argument for NetworkManager.
+ location of the main file and configuration directories may be changed
+ through use of the <option>--config</option>, <option>--config-dir</option>,
+ <option>--system-config-dir</option>, and <option>--intern-config</option>
+ argument for NetworkManager, respectively.
</para>
<para>If a default <literal>NetworkManager.conf</literal> is
provided by your distribution's packages, you should not modify
@@ -52,6 +55,12 @@ Copyright 2010 - 2014 Red Hat, Inc.
In this case, the file from the etc configuration shadows the file from the
system configuration directory.
</para>
+ <para>
+ NetworkManager can overwrite certain user configuration options via D-Bus or other internal
+ operations. In this case it writes those changes to <literal>/var/lib/NetworkManager/NetworkManager-intern.conf</literal>.
+ This file is not intended to be modified by the user, but it is read last and can shadow
+ user configuration from <literal>NetworkManager.conf</literal>.
+ </para>
</refsect1>
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index dcdd29e440..16d4c48c69 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -3323,7 +3323,7 @@ ip4_config_merge_and_apply (NMDevice *self,
if ( !priv->default_route.v4_configure_first_time
&& !nm_device_uses_assumed_connection (self)
&& connection_is_never_default) {
- /* If the connection is explicitly configured as never-default, we enforce the (absense of the)
+ /* If the connection is explicitly configured as never-default, we enforce the (absence of the)
* default-route only once. That allows the user to configure a connection as never-default,
* but he can add default routes externally (via a dispatcher script) and NM will not interfere. */
goto END_ADD_DEFAULT_ROUTE;
diff --git a/src/nm-config-data.c b/src/nm-config-data.c
index 82c1deab11..c3f279a521 100644
--- a/src/nm-config-data.c
+++ b/src/nm-config-data.c
@@ -48,6 +48,8 @@ typedef struct {
char *config_description;
GKeyFile *keyfile;
+ GKeyFile *keyfile_user;
+ GKeyFile *keyfile_intern;
/* A zero-terminated list of pre-processed information from the
* [connection] sections. This is to speed up lookup. */
@@ -77,7 +79,8 @@ enum {
PROP_0,
PROP_CONFIG_MAIN_FILE,
PROP_CONFIG_DESCRIPTION,
- PROP_KEYFILE,
+ PROP_KEYFILE_USER,
+ PROP_KEYFILE_INTERN,
PROP_CONNECTIVITY_URI,
PROP_CONNECTIVITY_INTERVAL,
PROP_CONNECTIVITY_RESPONSE,
@@ -92,6 +95,14 @@ G_DEFINE_TYPE (NMConfigData, nm_config_data, G_TYPE_OBJECT)
/************************************************************************/
+#define _HAS_PREFIX(str, prefix) \
+ ({ \
+ const char *_str = (str); \
+ g_str_has_prefix ( _str, ""prefix"") && _str[STRLEN(prefix)] != '\0'; \
+ })
+
+/************************************************************************/
+
const char *
nm_config_data_get_config_main_file (const NMConfigData *self)
{
@@ -238,6 +249,40 @@ nm_config_data_get_assume_ipv6ll_only (const NMConfigData *self, NMDevice *devic
return nm_device_spec_match_list (device, NM_CONFIG_DATA_GET_PRIVATE (self)->assume_ipv6ll_only);
}
+GKeyFile *
+nm_config_data_clone_keyfile_intern (const NMConfigData *self)
+{
+ NMConfigDataPrivate *priv;
+ GKeyFile *keyfile;
+
+ g_return_val_if_fail (NM_IS_CONFIG_DATA (self), FALSE);
+
+ priv = NM_CONFIG_DATA_GET_PRIVATE (self);
+
+ keyfile = nm_config_create_keyfile ();
+ if (priv->keyfile_intern)
+ _nm_keyfile_copy (keyfile, priv->keyfile_intern);
+ return keyfile;
+}
+
+GKeyFile *
+_nm_config_data_get_keyfile (const NMConfigData *self)
+{
+ return NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile;
+}
+
+GKeyFile *
+_nm_config_data_get_keyfile_intern (const NMConfigData *self)
+{
+ return NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile_intern;
+}
+
+GKeyFile *
+_nm_config_data_get_keyfile_user (const NMConfigData *self)
+{
+ return NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile_user;
+}
+
/************************************************************************/
/**
@@ -267,13 +312,80 @@ nm_config_data_get_keys (const NMConfigData *self, const char *group)
/************************************************************************/
+static GKeyFile *
+_merge_keyfiles (GKeyFile *keyfile_user, GKeyFile *keyfile_intern)
+{
+ gs_strfreev char **groups = NULL;
+ guint g, k;
+ GKeyFile *keyfile;
+ gsize ngroups;
+
+ keyfile = nm_config_create_keyfile ();
+ if (keyfile_user)
+ _nm_keyfile_copy (keyfile, keyfile_user);
+ if (!keyfile_intern)
+ return keyfile;
+
+ groups = g_key_file_get_groups (keyfile_intern, &ngroups);
+ if (!groups)
+ return keyfile;
+
+ /* we must reverse the order of the connection settings so that we
+ * have lowest priority last. */
+ _nm_config_sort_groups (groups, ngroups);
+ for (g = 0; groups[g]; g++) {
+ const char *group = groups[g];
+ gs_strfreev char **keys = NULL;
+ gboolean is_intern;
+
+ keys = g_key_file_get_keys (keyfile_intern, group, NULL, NULL);
+ if (!keys)
+ continue;
+
+ is_intern = g_str_has_prefix (group, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
+
+ for (k = 0; keys[k]; k++) {
+ const char *key = keys[k];
+ gs_free char *value = NULL;
+
+ if (!is_intern && _HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_WAS)) {
+ const char *key_base = &key[STRLEN (NM_CONFIG_KEYFILE_KEYPREFIX_WAS)];
+
+ if (!g_key_file_has_key (keyfile_intern, group, key_base, NULL))
+ g_key_file_remove_key (keyfile, group, key_base, NULL);
+ continue;
+ }
+ if (!is_intern && _HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_SET))
+ continue;
+
+ value = g_key_file_get_value (keyfile_intern, group, key, NULL);
+ g_key_file_set_value (keyfile, group, key, value);
+ }
+ }
+ return keyfile;
+}
+
+/************************************************************************/
+
static int
_nm_config_data_log_sort (const char **pa, const char **pb, gpointer dummy)
{
gboolean a_is_connection, b_is_connection;
+ gboolean a_is_intern, b_is_intern;
const char *a = *pa;
const char *b = *pb;
+ /* we sort intern groups to the end. */
+ a_is_intern = g_str_has_prefix (a, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
+ b_is_intern = g_str_has_prefix (b, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
+
+ if (a_is_intern && b_is_intern)
+ return 0;
+ if (a_is_intern)
+ return 1;
+ if (b_is_intern)
+ return -1;
+
/* we sort connection groups before intern groups (to the end). */
a_is_connection = a && g_str_has_prefix (a, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION);
b_is_connection = b && g_str_has_prefix (b, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION);
@@ -479,8 +591,11 @@ nm_config_data_diff (NMConfigData *old_data, NMConfigData *new_data)
priv_old = NM_CONFIG_DATA_GET_PRIVATE (old_data);
priv_new = NM_CONFIG_DATA_GET_PRIVATE (new_data);
- if (!_nm_keyfile_equals (priv_old->keyfile, priv_new->keyfile, TRUE))
- changes |= NM_CONFIG_CHANGE_VALUES;
+ if (!_nm_keyfile_equals (priv_old->keyfile_user, priv_new->keyfile_user, TRUE))
+ changes |= NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER;
+
+ if (!_nm_keyfile_equals (priv_old->keyfile_intern, priv_new->keyfile_intern, TRUE))
+ changes |= NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN;
if ( g_strcmp0 (nm_config_data_get_config_main_file (old_data), nm_config_data_get_config_main_file (new_data)) != 0
|| g_strcmp0 (nm_config_data_get_config_description (old_data), nm_config_data_get_config_description (new_data)) != 0)
@@ -553,10 +668,21 @@ set_property (GObject *object,
case PROP_CONFIG_DESCRIPTION:
priv->config_description = g_value_dup_string (value);
break;
- case PROP_KEYFILE:
- priv->keyfile = g_value_dup_boxed (value);
- if (!priv->keyfile)
- priv->keyfile = nm_config_create_keyfile ();
+ case PROP_KEYFILE_USER:
+ priv->keyfile_user = g_value_dup_boxed (value);
+ if ( priv->keyfile_user
+ && !_nm_keyfile_has_values (priv->keyfile_user)) {
+ g_key_file_unref (priv->keyfile_user);
+ priv->keyfile_user = NULL;
+ }
+ break;
+ case PROP_KEYFILE_INTERN:
+ priv->keyfile_intern = g_value_dup_boxed (value);
+ if ( priv->keyfile_intern
+ && !_nm_keyfile_has_values (priv->keyfile_intern)) {
+ g_key_file_unref (priv->keyfile_intern);
+ priv->keyfile_intern = NULL;
+ }
break;
case PROP_NO_AUTO_DEFAULT:
{
@@ -620,6 +746,10 @@ finalize (GObject *gobject)
}
g_key_file_unref (priv->keyfile);
+ if (priv->keyfile_user)
+ g_key_file_unref (priv->keyfile_user);
+ if (priv->keyfile_intern)
+ g_key_file_unref (priv->keyfile_intern);
G_OBJECT_CLASS (nm_config_data_parent_class)->finalize (gobject);
}
@@ -636,6 +766,8 @@ constructed (GObject *object)
NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (self);
char *interval;
+ priv->keyfile = _merge_keyfiles (priv->keyfile_user, priv->keyfile_intern);
+
priv->connection_infos = _get_connection_infos (priv->keyfile);
priv->connectivity.uri = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "uri", NULL));
@@ -664,17 +796,33 @@ NMConfigData *
nm_config_data_new (const char *config_main_file,
const char *config_description,
const char *const*no_auto_default,
- GKeyFile *keyfile)
+ GKeyFile *keyfile_user,
+ GKeyFile *keyfile_intern)
{
return g_object_new (NM_TYPE_CONFIG_DATA,
NM_CONFIG_DATA_CONFIG_MAIN_FILE, config_main_file,
NM_CONFIG_DATA_CONFIG_DESCRIPTION, config_description,
- NM_CONFIG_DATA_KEYFILE, keyfile,
+ NM_CONFIG_DATA_KEYFILE_USER, keyfile_user,
+ NM_CONFIG_DATA_KEYFILE_INTERN, keyfile_intern,
NM_CONFIG_DATA_NO_AUTO_DEFAULT, no_auto_default,
NULL);
}
NMConfigData *
+nm_config_data_new_update_keyfile_intern (const NMConfigData *base, GKeyFile *keyfile_intern)
+{
+ NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (base);
+
+ return g_object_new (NM_TYPE_CONFIG_DATA,
+ NM_CONFIG_DATA_CONFIG_MAIN_FILE, priv->config_main_file,
+ NM_CONFIG_DATA_CONFIG_DESCRIPTION, priv->config_description,
+ NM_CONFIG_DATA_KEYFILE_USER, priv->keyfile_user, /* the keyfile is unchanged. It's safe to share it. */
+ NM_CONFIG_DATA_KEYFILE_INTERN, keyfile_intern,
+ NM_CONFIG_DATA_NO_AUTO_DEFAULT, priv->no_auto_default.arr,
+ NULL);
+}
+
+NMConfigData *
nm_config_data_new_update_no_auto_default (const NMConfigData *base,
const char *const*no_auto_default)
{
@@ -683,7 +831,8 @@ nm_config_data_new_update_no_auto_default (const NMConfigData *base,
return g_object_new (NM_TYPE_CONFIG_DATA,
NM_CONFIG_DATA_CONFIG_MAIN_FILE, priv->config_main_file,
NM_CONFIG_DATA_CONFIG_DESCRIPTION, priv->config_description,
- NM_CONFIG_DATA_KEYFILE, priv->keyfile, /* the keyfile is unchanged. It's safe to share it. */
+ NM_CONFIG_DATA_KEYFILE_USER, priv->keyfile_user, /* the keyfile is unchanged. It's safe to share it. */
+ NM_CONFIG_DATA_KEYFILE_INTERN, priv->keyfile_intern,
NM_CONFIG_DATA_NO_AUTO_DEFAULT, no_auto_default,
NULL);
}
@@ -718,8 +867,16 @@ nm_config_data_class_init (NMConfigDataClass *config_class)
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
- (object_class, PROP_KEYFILE,
- g_param_spec_boxed (NM_CONFIG_DATA_KEYFILE, "", "",
+ (object_class, PROP_KEYFILE_USER,
+ g_param_spec_boxed (NM_CONFIG_DATA_KEYFILE_USER, "", "",
+ G_TYPE_KEY_FILE,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_KEYFILE_INTERN,
+ g_param_spec_boxed (NM_CONFIG_DATA_KEYFILE_INTERN, "", "",
G_TYPE_KEY_FILE,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
diff --git a/src/nm-config-data.h b/src/nm-config-data.h
index bd26b9dfbb..d061583540 100644
--- a/src/nm-config-data.h
+++ b/src/nm-config-data.h
@@ -38,7 +38,8 @@ G_BEGIN_DECLS
#define NM_CONFIG_DATA_CONFIG_MAIN_FILE "config-main-file"
#define NM_CONFIG_DATA_CONFIG_DESCRIPTION "config-description"
-#define NM_CONFIG_DATA_KEYFILE "keyfile"
+#define NM_CONFIG_DATA_KEYFILE_USER "keyfile-user"
+#define NM_CONFIG_DATA_KEYFILE_INTERN "keyfile-intern"
#define NM_CONFIG_DATA_CONNECTIVITY_URI "connectivity-uri"
#define NM_CONFIG_DATA_CONNECTIVITY_INTERVAL "connectivity-interval"
#define NM_CONFIG_DATA_CONNECTIVITY_RESPONSE "connectivity-response"
@@ -71,10 +72,12 @@ typedef enum { /*< flags >*/
NM_CONFIG_CHANGE_CONFIG_FILES = (1L << 3),
NM_CONFIG_CHANGE_VALUES = (1L << 4),
- NM_CONFIG_CHANGE_CONNECTIVITY = (1L << 5),
- NM_CONFIG_CHANGE_NO_AUTO_DEFAULT = (1L << 6),
- NM_CONFIG_CHANGE_DNS_MODE = (1L << 7),
- NM_CONFIG_CHANGE_RC_MANAGER = (1L << 8),
+ NM_CONFIG_CHANGE_VALUES_USER = (1L << 5),
+ NM_CONFIG_CHANGE_VALUES_INTERN = (1L << 6),
+ NM_CONFIG_CHANGE_CONNECTIVITY = (1L << 7),
+ NM_CONFIG_CHANGE_NO_AUTO_DEFAULT = (1L << 8),
+ NM_CONFIG_CHANGE_DNS_MODE = (1L << 9),
+ NM_CONFIG_CHANGE_RC_MANAGER = (1L << 10),
_NM_CONFIG_CHANGE_LAST,
NM_CONFIG_CHANGE_ALL = ((_NM_CONFIG_CHANGE_LAST - 1) << 1) - 1,
@@ -93,7 +96,9 @@ GType nm_config_data_get_type (void);
NMConfigData *nm_config_data_new (const char *config_main_file,
const char *config_description,
const char *const*no_auto_default,
- GKeyFile *keyfile);
+ GKeyFile *keyfile_user,
+ GKeyFile *keyfile_intern);
+NMConfigData *nm_config_data_new_update_keyfile_intern (const NMConfigData *base, GKeyFile *keyfile_intern);
NMConfigData *nm_config_data_new_update_no_auto_default (const NMConfigData *base, const char *const*no_auto_default);
NMConfigChangeFlags nm_config_data_diff (NMConfigData *old_data, NMConfigData *new_data);
@@ -128,6 +133,13 @@ char *nm_config_data_get_connection_default (const NMConfigData *self,
char **nm_config_data_get_groups (const NMConfigData *self);
char **nm_config_data_get_keys (const NMConfigData *self, const char *group);
+GKeyFile *nm_config_data_clone_keyfile_intern (const NMConfigData *self);
+
+/* private accessors */
+GKeyFile *_nm_config_data_get_keyfile (const NMConfigData *self);
+GKeyFile *_nm_config_data_get_keyfile_user (const NMConfigData *self);
+GKeyFile *_nm_config_data_get_keyfile_intern (const NMConfigData *self);
+
G_END_DECLS
#endif /* NM_CONFIG_DATA_H */
diff --git a/src/nm-config.c b/src/nm-config.c
index 9e49905954..0c36f7a773 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -33,6 +33,7 @@
#include "gsystem-local-alloc.h"
#include "nm-enum-types.h"
#include "nm-core-internal.h"
+#include "nm-keyfile-internal.h"
#include <gio/gio.h>
#include <glib/gi18n.h>
@@ -42,9 +43,11 @@
#define DEFAULT_CONFIG_MAIN_FILE_OLD NMCONFDIR "/nm-system-settings.conf"
#define DEFAULT_SYSTEM_CONFIG_DIR NMLIBDIR "/conf.d"
#define DEFAULT_NO_AUTO_DEFAULT_FILE NMSTATEDIR "/no-auto-default.state"
+#define DEFAULT_INTERN_CONFIG_FILE NMSTATEDIR "/NetworkManager-intern.conf"
struct NMConfigCmdLineOptions {
char *config_main_file;
+ char *intern_config_file;
char *config_dir;
char *system_config_dir;
char *no_auto_default_file;
@@ -68,6 +71,7 @@ typedef struct {
char *config_dir;
char *system_config_dir;
char *no_auto_default_file;
+ char *intern_config_file;
char **plugins;
gboolean monitor_connection_files;
@@ -111,6 +115,14 @@ static void _set_config_data (NMConfig *self, NMConfigData *new_data, int signal
/************************************************************************/
+#define _HAS_PREFIX(str, prefix) \
+ ({ \
+ const char *_str = (str); \
+ g_str_has_prefix ( _str, ""prefix"") && _str[STRLEN(prefix)] != '\0'; \
+ })
+
+/************************************************************************/
+
gint
nm_config_parse_boolean (const char *str,
gint default_value)
@@ -362,7 +374,7 @@ nm_config_get_no_auto_default_for_device (NMConfig *self, NMDevice *device)
void
nm_config_set_no_auto_default_for_device (NMConfig *self, NMDevice *device)
{
- NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (self);
+ NMConfigPrivate *priv;
GError *error = NULL;
NMConfigData *new_data = NULL;
const char *hw_address;
@@ -373,6 +385,8 @@ nm_config_set_no_auto_default_for_device (NMConfig *self, NMDevice *device)
g_return_if_fail (NM_IS_CONFIG (self));
g_return_if_fail (NM_IS_DEVICE (device));
+ priv = NM_CONFIG_GET_PRIVATE (self);
+
hw_address = nm_device_get_hw_address (device);
no_auto_default_current = nm_config_data_get_no_auto_default (priv->config_data);
@@ -412,6 +426,7 @@ _nm_config_cmd_line_options_clear (NMConfigCmdLineOptions *cli)
g_clear_pointer (&cli->config_dir, g_free);
g_clear_pointer (&cli->system_config_dir, g_free);
g_clear_pointer (&cli->no_auto_default_file, g_free);
+ g_clear_pointer (&cli->intern_config_file, g_free);
g_clear_pointer (&cli->plugins, g_free);
cli->configure_and_quit = FALSE;
g_clear_pointer (&cli->connectivity_uri, g_free);
@@ -431,6 +446,7 @@ _nm_config_cmd_line_options_copy (const NMConfigCmdLineOptions *cli, NMConfigCmd
dst->system_config_dir = g_strdup (cli->system_config_dir);
dst->config_main_file = g_strdup (cli->config_main_file);
dst->no_auto_default_file = g_strdup (cli->no_auto_default_file);
+ dst->intern_config_file = g_strdup (cli->intern_config_file);
dst->plugins = g_strdup (cli->plugins);
dst->configure_and_quit = cli->configure_and_quit;
dst->connectivity_uri = g_strdup (cli->connectivity_uri);
@@ -468,6 +484,7 @@ nm_config_cmd_line_options_add_to_entries (NMConfigCmdLineOptions *cli,
{ "config", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_main_file, N_("Config file location"), N_(DEFAULT_CONFIG_MAIN_FILE) },
{ "config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_dir, N_("Config directory location"), N_(DEFAULT_CONFIG_DIR) },
{ "system-config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->system_config_dir, N_("System config directory location"), N_(DEFAULT_SYSTEM_CONFIG_DIR) },
+ { "intern-config", 0, 0, G_OPTION_ARG_FILENAME, &cli->intern_config_file, N_("Internal config file location"), N_(DEFAULT_INTERN_CONFIG_FILE) },
{ "no-auto-default", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME, &cli->no_auto_default_file, N_("State file for no-auto-default devices"), N_(DEFAULT_NO_AUTO_DEFAULT_FILE) },
{ "plugins", 0, 0, G_OPTION_ARG_STRING, &cli->plugins, N_("List of plugins separated by ','"), N_(CONFIG_PLUGINS_DEFAULT) },
{ "configure-and-quit", 0, 0, G_OPTION_ARG_NONE, &cli->configure_and_quit, N_("Quit after initial configuration"), NULL },
@@ -534,6 +551,18 @@ _sort_groups_cmp (const char **pa, const char **pb, gpointer dummy)
return pa > pb ? -1 : 1;
}
+void
+_nm_config_sort_groups (char **groups, gsize ngroups)
+{
+ if (ngroups > 1) {
+ g_qsort_with_data (groups,
+ ngroups,
+ sizeof (char *),
+ (GCompareDataFunc) _sort_groups_cmp,
+ NULL);
+ }
+}
+
static gboolean
_setting_is_device_spec (const char *group, const char *key)
{
@@ -599,17 +628,15 @@ read_config (GKeyFile *keyfile, const char *dirname, const char *path, GError **
* At the very end, we will revert the order of all sections again and
* get thus the right behavior. This final reversing is done in
* NMConfigData:_get_connection_infos(). */
- if (ngroups > 1) {
- g_qsort_with_data (groups,
- ngroups,
- sizeof (char *),
- (GCompareDataFunc) _sort_groups_cmp,
- NULL);
- }
+ _nm_config_sort_groups (groups, ngroups);
for (g = 0; groups[g]; g++) {
const char *group = groups[g];
+ if (g_str_has_prefix (group, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN)) {
+ /* internal groups cannot be set by user configuration. */
+ continue;
+ }
keys = g_key_file_get_keys (kf, group, &nkeys, NULL);
if (!keys)
continue;
@@ -621,6 +648,13 @@ read_config (GKeyFile *keyfile, const char *dirname, const char *path, GError **
key = keys[k];
g_assert (key && *key);
+
+ if ( _HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_WAS)
+ || _HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_SET)) {
+ /* these keys are protected. We ignore them if the user sets them. */
+ continue;
+ }
+
key_len = strlen (key);
last_char = key[key_len - 1];
if ( key_len > 1
@@ -832,8 +866,8 @@ read_entire_config (const NMConfigCmdLineOptions *cli,
g_return_val_if_fail (config_dir, NULL);
g_return_val_if_fail (system_config_dir, NULL);
- g_return_val_if_fail (out_config_main_file && !*out_config_main_file, FALSE);
- g_return_val_if_fail (out_config_description && !*out_config_description, NULL);
+ g_return_val_if_fail (!out_config_main_file || !*out_config_main_file, FALSE);
+ g_return_val_if_fail (!out_config_description || !*out_config_description, NULL);
g_return_val_if_fail (!error || !*error, FALSE);
/* create a default configuration file. */
@@ -916,13 +950,310 @@ read_entire_config (const NMConfigCmdLineOptions *cli,
g_string_append (str, ")");
}
- *out_config_main_file = o_config_main_file;
- *out_config_description = g_string_free (str, FALSE);
+ if (out_config_main_file)
+ *out_config_main_file = o_config_main_file;
+ else
+ g_free (o_config_main_file);
+ if (out_config_description)
+ *out_config_description = g_string_free (str, FALSE);
+ else
+ g_string_free (str, TRUE);
o_config_main_file = NULL;
return keyfile;
}
+/**
+ * intern_config_read:
+ * @filename: the filename where to store the internal config
+ * @keyfile_conf: the merged configuration from user (/etc/NM/NetworkManager.conf).
+ * @out_needs_rewrite: (allow-none): whether the read keyfile contains inconsistent
+ * data (compared to @keyfile_conf). If %TRUE, you might want to rewrite
+ * the file.
+ *
+ * Does the opposite of intern_config_write(). It reads the internal configuration.
+ * Note that the actual format of how the configuration is saved in @filename
+ * is different then what we return here. NMConfig manages what is written internally
+ * by having it inside a keyfile_intern. But we don't write that to disk as is.
+ * Especially, we also store parts of @keyfile_conf as ".was" and on read we compare
+ * what we have, with what ".was".
+ *
+ * Returns: a #GKeyFile instance with the internal configuration.
+ */
+static GKeyFile *
+intern_config_read (const char *filename,
+ GKeyFile *keyfile_conf,
+ gboolean *out_needs_rewrite)
+{
+ GKeyFile *keyfile_intern;
+ GKeyFile *keyfile;
+ gboolean needs_rewrite = FALSE;
+ gs_strfreev char **groups = NULL;
+ guint g, k;
+ gboolean has_intern = FALSE;
+
+ g_return_val_if_fail (filename, NULL);
+
+ if (!*filename) {
+ if (out_needs_rewrite)
+ *out_needs_rewrite = FALSE;
+ return NULL;
+ }
+
+ keyfile_intern = nm_config_create_keyfile ();
+
+ keyfile = nm_config_create_keyfile ();
+ if (!g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, NULL)) {
+ needs_rewrite = TRUE;
+ goto out;
+ }
+
+ groups = g_key_file_get_groups (keyfile, NULL);
+ for (g = 0; groups && groups[g]; g++) {
+ gs_strfreev char **keys = NULL;
+ const char *group = groups[g];
+ gboolean is_intern;
+
+ keys = g_key_file_get_keys (keyfile, group, NULL, NULL);
+ if (!keys)
+ continue;
+
+ is_intern = g_str_has_prefix (group, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
+
+ for (k = 0; keys[k]; k++) {
+ gs_free char *value_set = NULL;
+ const char *key = keys[k];
+
+ value_set = g_key_file_get_value (keyfile, group, key, NULL);
+
+ if (is_intern) {
+ has_intern = TRUE;
+ g_key_file_set_value (keyfile_intern, group, key, value_set);
+ } else if (_HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_SET)) {
+ const char *key_base = &key[STRLEN (NM_CONFIG_KEYFILE_KEYPREFIX_SET)];
+ gs_free char *value_was = NULL;
+ gs_free char *value_conf = NULL;
+ gs_free char *key_was = g_strdup_printf (NM_CONFIG_KEYFILE_KEYPREFIX_WAS"%s", key_base);
+
+ if (keyfile_conf)
+ value_conf = g_key_file_get_value (keyfile_conf, group, key_base, NULL);
+ value_was = g_key_file_get_value (keyfile, group, key_was, NULL);
+
+ if (g_strcmp0 (value_conf, value_was) != 0) {
+ /* if value_was is no longer the same as @value_conf, it means the user
+ * changed the configuration since the last write. In this case, we
+ * drop the value. It also means our file is out-of-date, and we should
+ * rewrite it. */
+ needs_rewrite = TRUE;
+ continue;
+ }
+ has_intern = TRUE;
+ g_key_file_set_value (keyfile_intern, group, key_base, value_set);
+ } else if (_HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_WAS)) {
+ const char *key_base = &key[STRLEN (NM_CONFIG_KEYFILE_KEYPREFIX_WAS)];
+ gs_free char *key_set = g_strdup_printf (NM_CONFIG_KEYFILE_KEYPREFIX_SET"%s", key_base);
+ gs_free char *value_was = NULL;
+ gs_free char *value_conf = NULL;
+
+ if (g_key_file_has_key (keyfile, group, key_set, NULL)) {
+ /* we have a matching "set" key too. Handle the "was" key there. */
+ continue;
+ }
+
+ if (keyfile_conf)
+ value_conf = g_key_file_get_value (keyfile_conf, group, key_base, NULL);
+ value_was = g_key_file_get_value (keyfile, group, key, NULL);
+
+ if (g_strcmp0 (value_conf, value_was) != 0) {
+ /* if value_was is no longer the same as @value_conf, it means the user
+ * changed the configuration since the last write. In this case, we
+ * don't overwrite the user-provided value. It also means our file is
+ * out-of-date, and we should rewrite it. */
+ needs_rewrite = TRUE;
+ continue;
+ }
+ has_intern = TRUE;
+ /* signal the absence of the value. That means, we must propagate the
+ * "was" key to NMConfigData, so that it knows to hide the corresponding
+ * user key. */
+ g_key_file_set_value (keyfile_intern, group, key, "");
+ } else
+ needs_rewrite = TRUE;
+ }
+ }
+
+out:
+ g_key_file_unref (keyfile);
+
+ if (out_needs_rewrite)
+ *out_needs_rewrite = needs_rewrite;
+
+ nm_log_dbg (LOGD_CORE, "intern config file \"%s\"", filename);
+
+ if (!has_intern) {
+ g_key_file_unref (keyfile_intern);
+ return NULL;
+ }
+ return keyfile_intern;
+}
+
+static int
+_intern_config_write_sort_fcn (const char **a, const char **b, gpointer dummy)
+{
+ const char *g_a = (a ? *a : NULL);
+ const char *g_b = (b ? *b : NULL);
+ gboolean a_is, b_is;
+
+ a_is = g_str_has_prefix (g_a, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
+ b_is = g_str_has_prefix (g_b, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
+
+ if (a_is != b_is) {
+ if (a_is)
+ return 1;
+ return -1;
+ }
+ return g_strcmp0 (g_a, g_b);
+}
+
+static gboolean
+intern_config_write (const char *filename,
+ GKeyFile *keyfile_intern,
+ GKeyFile *keyfile_conf,
+ GError **error)
+{
+ GKeyFile *keyfile;
+ gs_strfreev char **groups = NULL;
+ guint g, k;
+ gboolean has_intern = FALSE;
+ gboolean success = FALSE;
+ GError *local = NULL;
+
+ g_return_val_if_fail (filename, FALSE);
+
+ if (!*filename) {
+ g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND, "no filename to write (use --intern-config?)");
+ return FALSE;
+ }
+
+ keyfile = nm_config_create_keyfile ();
+
+ if (keyfile_intern) {
+ groups = g_key_file_get_groups (keyfile_intern, NULL);
+ if (groups && groups[0]) {
+ g_qsort_with_data (groups,
+ g_strv_length (groups),
+ sizeof (char *),
+ (GCompareDataFunc) _intern_config_write_sort_fcn,
+ NULL);
+ }
+ }
+ for (g = 0; groups && groups[g]; g++) {
+ gs_strfreev char **keys = NULL;
+ const char *group = groups[g];
+ gboolean is_intern;
+
+ keys = g_key_file_get_keys (keyfile_intern, group, NULL, NULL);
+ if (!keys)
+ continue;
+
+ is_intern = g_str_has_prefix (group, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
+
+ for (k = 0; keys[k]; k++) {
+ const char *key = keys[k];
+ gs_free char *value_set = NULL;
+ gs_free char *key_set = NULL;
+
+ value_set = g_key_file_get_value (keyfile_intern, group, key, NULL);
+
+ if (is_intern) {
+ has_intern = TRUE;
+ g_key_file_set_value (keyfile, group, key, value_set);
+ } else {
+ gs_free char *value_was = NULL;
+
+ if (_HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_SET)) {
+ /* Setting a key with .set prefix has no meaning, as these keys
+ * are protected. Just set the value you want to set instead.
+ * Why did this happen?? */
+ g_warn_if_reached ();
+ } else if (_HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_WAS)) {
+ const char *key_base = &key[STRLEN (NM_CONFIG_KEYFILE_KEYPREFIX_WAS)];
+
+ if ( _HAS_PREFIX (key_base, NM_CONFIG_KEYFILE_KEYPREFIX_SET)
+ || _HAS_PREFIX (key_base, NM_CONFIG_KEYFILE_KEYPREFIX_WAS)) {
+ g_warn_if_reached ();
+ continue;
+ }
+
+ if (g_key_file_has_key (keyfile_intern, group, key_base, NULL)) {
+ /* There is also a matching key_base entry. Skip processing
+ * the .was. key ad handle the key_base in the other else branch. */
+ continue;
+ }
+
+ if (keyfile_conf) {
+ value_was = g_key_file_get_value (keyfile_conf, group, key_base, NULL);
+ if (value_was)
+ g_key_file_set_value (keyfile, group, key, value_was);
+ }
+ } else {
+ if (keyfile_conf) {
+ value_was = g_key_file_get_value (keyfile_conf, group, key, NULL);
+ if (g_strcmp0 (value_set, value_was) == 0) {
+ /* there is no point in storing the identical value as we have via
+ * user configuration. Skip it. */
+ continue;
+ }
+ if (value_was) {
+ gs_free char *key_was = NULL;
+
+ key_was = g_strdup_printf (NM_CONFIG_KEYFILE_KEYPREFIX_WAS"%s", key);
+ g_key_file_set_value (keyfile, group, key_was, value_was);
+ }
+ }
+ key = key_set = g_strdup_printf (NM_CONFIG_KEYFILE_KEYPREFIX_SET"%s", key);
+ g_key_file_set_value (keyfile, group, key, value_set);
+ }
+ }
+ }
+ if ( is_intern
+ && g_key_file_has_group (keyfile, group)) {
+ g_key_file_set_comment (keyfile, group, NULL,
+ " Internal section. Not overwritable via user configuration in 'NetworkManager.conf'",
+ NULL);
+ }
+ }
+
+ g_key_file_set_comment (keyfile, NULL, NULL,
+ " Internal configuration file. This file is written and read\n"
+ " by NetworkManager and its configuration values are merged\n"
+ " with the configuration from 'NetworkManager.conf'.\n"
+ "\n"
+ " Keys with a \""NM_CONFIG_KEYFILE_KEYPREFIX_SET"\" prefix specify the value to set.\n"
+ " A corresponding key with a \""NM_CONFIG_KEYFILE_KEYPREFIX_WAS"\" prefix records the value\n"
+ " of the user configuration at the time of storing the file.\n"
+ " The value from internal configuration is rejected if the corresponding\n"
+ " \""NM_CONFIG_KEYFILE_KEYPREFIX_WAS"\" key no longer matches the configuration from 'NetworkManager.conf'.\n"
+ " That means, if you modify a value in 'NetworkManager.conf', the internal\n"
+ " overwrite no longer matches and is ignored.\n"
+ "\n"
+ " Internal sections of the form [" NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN "*] cannot\n"
+ " be set by user configuration.\n"
+ "\n"
+ " CHANGES TO THIS FILE WILL BE OVERWRITTEN",
+ NULL);
+
+ success = g_key_file_save_to_file (keyfile, filename, &local);
+
+ nm_log_dbg (LOGD_CORE, "write intern config file \"%s\"%s%s", filename, success ? "" : ": ", success ? "" : local->message);
+ g_key_file_unref (keyfile);
+ if (!success)
+ g_propagate_error (error, local);
+ return success;
+}
+
+/************************************************************************/
+
GSList *
nm_config_get_device_match_spec (const GKeyFile *keyfile, const char *group, const char *key, gboolean *out_has_key)
{
@@ -939,16 +1270,97 @@ nm_config_get_device_match_spec (const GKeyFile *keyfile, const char *group, con
/************************************************************************/
+/**
+ * nm_config_set_values:
+ * @self: the NMConfig instance
+ * @keyfile_intern_new: (allow-none): the new internal settings to set.
+ * If %NULL, it is equal to an empty keyfile.
+ * @allow_write: only if %TRUE, allow writing the changes to file. Otherwise,
+ * do the changes in-memory only.
+ * @force_rewrite: if @allow_write is %FALSE, this has no effect. If %FALSE,
+ * only write the configuration to file, if there are any actual changes.
+ * If %TRUE, always write the configuration to file, even if tere are seemingly
+ * no changes.
+ *
+ * This is the most flexible function to set values. It all depends on the
+ * keys and values you set in @keyfile_intern_new. You basically reset all
+ * internal configuration values to what is in @keyfile_intern_new.
+ *
+ * There are 2 types of settings:
+ * - all groups/sections with a prefix [.intern.*] are taken as is. As these
+ * groups are separate from user configuration, there is no conflict. You set
+ * them, that's it.
+ * - otherwise you can overwrite individual values from user-configuration.
+ * Just set the value. Keys with a prefix NM_CONFIG_KEYFILE_KEYPREFIX_*
+ * are protected -- as they are not value user keys.
+ * You can also hide a certain user setting by putting only a key
+ * NM_CONFIG_KEYFILE_KEYPREFIX_WAS"keyname" into the keyfile.
+ */
+void
+nm_config_set_values (NMConfig *self,
+ GKeyFile *keyfile_intern_new,
+ gboolean allow_write,
+ gboolean force_rewrite)
+{
+ NMConfigPrivate *priv;
+ GKeyFile *keyfile_intern_current;
+ GKeyFile *keyfile_user;
+ GKeyFile *keyfile_new;
+ GError *local = NULL;
+ NMConfigData *new_data = NULL;
+
+ g_return_if_fail (NM_IS_CONFIG (self));
+
+ priv = NM_CONFIG_GET_PRIVATE (self);
+
+ keyfile_intern_current = _nm_config_data_get_keyfile_intern (priv->config_data);
+
+ keyfile_new = nm_config_create_keyfile ();
+ if (keyfile_intern_new)
+ _nm_keyfile_copy (keyfile_new, keyfile_intern_new);
+
+ if (!_nm_keyfile_equals (keyfile_intern_current, keyfile_new, TRUE))
+ new_data = nm_config_data_new_update_keyfile_intern (priv->config_data, keyfile_new);
+
+ nm_log_dbg (LOGD_CORE, "set values(): %s", new_data ? "has changes" : "no changes");
+
+ if (allow_write
+ && (new_data || force_rewrite)) {
+ /* We write the internal config file based on the user configuration from
+ * the last load/reload. That is correct, because the intern properties might
+ * be in accordance to what NM thinks is currently configured. Even if the files
+ * on disk changed in the meantime.
+ * But if they changed, on the next reload with might throw away our just
+ * written data. That is correct, because from NM's point of view, those
+ * changes on disk happened in any case *after* now. */
+ if (*priv->intern_config_file) {
+ keyfile_user = _nm_config_data_get_keyfile_user (priv->config_data);
+ if (!intern_config_write (priv->intern_config_file, keyfile_new, keyfile_user, &local)) {
+ nm_log_warn (LOGD_CORE, "error saving internal configuration \"%s\": %s", priv->intern_config_file, local->message);
+ g_clear_error (&local);
+ }
+ } else
+ nm_log_dbg (LOGD_CORE, "don't persistate internal configuration (no file set, use --intern-config?)");
+ }
+ if (new_data)
+ _set_config_data (self, new_data, 0);
+
+ g_key_file_unref (keyfile_new);
+}
+
+/************************************************************************/
+
void
nm_config_reload (NMConfig *self, int signal)
{
NMConfigPrivate *priv;
GError *error = NULL;
- GKeyFile *keyfile;
+ GKeyFile *keyfile, *keyfile_intern;
NMConfigData *new_data = NULL;
char *config_main_file = NULL;
char *config_description = NULL;
gs_strfreev char **no_auto_default = NULL;
+ gboolean intern_config_needs_rewrite;
g_return_if_fail (NM_IS_CONFIG (self));
@@ -975,12 +1387,19 @@ nm_config_reload (NMConfig *self, int signal)
_set_config_data (self, NULL, signal);
return;
}
+
no_auto_default = no_auto_default_from_file (priv->no_auto_default_file);
- new_data = nm_config_data_new (config_main_file, config_description, (const char *const*) no_auto_default, keyfile);
+ keyfile_intern = intern_config_read (priv->intern_config_file, keyfile, &intern_config_needs_rewrite);
+ if (intern_config_needs_rewrite)
+ intern_config_write (priv->intern_config_file, keyfile_intern, keyfile, NULL);
+
+ new_data = nm_config_data_new (config_main_file, config_description, (const char *const*) no_auto_default, keyfile, keyfile_intern);
g_free (config_main_file);
g_free (config_description);
g_key_file_unref (keyfile);
+ if (keyfile_intern)
+ g_key_file_unref (keyfile_intern);
_set_config_data (self, new_data, signal);
}
@@ -999,6 +1418,10 @@ _change_flags_one_to_string (NMConfigChangeFlags flag)
return "config-files";
case NM_CONFIG_CHANGE_VALUES:
return "values";
+ case NM_CONFIG_CHANGE_VALUES_USER:
+ return "values-user";
+ case NM_CONFIG_CHANGE_VALUES_INTERN:
+ return "values-intern";
case NM_CONFIG_CHANGE_CONNECTIVITY:
return "connectivity";
case NM_CONFIG_CHANGE_NO_AUTO_DEFAULT:
@@ -1107,10 +1530,11 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
{
NMConfig *self = NM_CONFIG (initable);
NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (self);
- GKeyFile *keyfile;
+ GKeyFile *keyfile, *keyfile_intern;
char *config_main_file = NULL;
char *config_description = NULL;
gs_strfreev char **no_auto_default = NULL;
+ gboolean intern_config_needs_rewrite;
if (priv->config_dir) {
/* Object is already initialized. */
@@ -1137,6 +1561,11 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
priv->system_config_dir = g_strdup ("");
}
+ if (priv->cli.intern_config_file)
+ priv->intern_config_file = g_strdup (priv->cli.intern_config_file);
+ else
+ priv->intern_config_file = g_strdup (DEFAULT_INTERN_CONFIG_FILE);
+
keyfile = read_entire_config (&priv->cli,
priv->config_dir,
priv->system_config_dir,
@@ -1173,13 +1602,19 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
no_auto_default = no_auto_default_from_file (priv->no_auto_default_file);
- priv->config_data_orig = nm_config_data_new (config_main_file, config_description, (const char *const*) no_auto_default, keyfile);
+ keyfile_intern = intern_config_read (priv->intern_config_file, keyfile, &intern_config_needs_rewrite);
+ if (intern_config_needs_rewrite)
+ intern_config_write (priv->intern_config_file, keyfile_intern, keyfile, NULL);
+
+ priv->config_data_orig = nm_config_data_new (config_main_file, config_description, (const char *const*) no_auto_default, keyfile, keyfile_intern);
priv->config_data = g_object_ref (priv->config_data_orig);
g_free (config_main_file);
g_free (config_description);
g_key_file_unref (keyfile);
+ if (keyfile_intern)
+ g_key_file_unref (keyfile_intern);
return TRUE;
}
@@ -1209,6 +1644,7 @@ finalize (GObject *gobject)
g_free (priv->config_dir);
g_free (priv->system_config_dir);
g_free (priv->no_auto_default_file);
+ g_free (priv->intern_config_file);
g_strfreev (priv->plugins);
g_free (priv->dhcp_client);
g_free (priv->log_level);
diff --git a/src/nm-config.h b/src/nm-config.h
index 5b096f165d..d4ff887ba3 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -48,6 +48,7 @@ G_BEGIN_DECLS
#define NM_CONFIG_KEYFILE_LIST_SEPARATOR ','
+#define NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN ".intern."
#define NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION "connection"
#define NM_CONFIG_KEYFILE_GROUPPREFIX_TEST_APPEND_STRINGLIST ".test-append-stringlist"
@@ -63,6 +64,9 @@ G_BEGIN_DECLS
#define NM_CONFIG_KEYFILE_KEY_IFNET_MANAGED "managed"
#define NM_CONFIG_KEYFILE_KEY_IFUPDOWN_MANAGED "managed"
+#define NM_CONFIG_KEYFILE_KEYPREFIX_WAS ".was."
+#define NM_CONFIG_KEYFILE_KEYPREFIX_SET ".set."
+
typedef struct NMConfigCmdLineOptions NMConfigCmdLineOptions;
struct _NMConfig {
@@ -97,6 +101,11 @@ const char *nm_config_get_log_domains (NMConfig *config);
const char *nm_config_get_debug (NMConfig *config);
gboolean nm_config_get_configure_and_quit (NMConfig *config);
+void nm_config_set_values (NMConfig *self,
+ GKeyFile *keyfile_intern_new,
+ gboolean allow_write,
+ gboolean force_rewrite);
+
/* for main.c only */
NMConfigCmdLineOptions *nm_config_cmd_line_options_new (void);
void nm_config_cmd_line_options_free (NMConfigCmdLineOptions *cli);
@@ -128,6 +137,8 @@ void nm_config_keyfile_set_string_list (GKeyFile *keyfile,
gssize len);
GSList *nm_config_get_device_match_spec (const GKeyFile *keyfile, const char *group, const char *key, gboolean *out_has_key);
+void _nm_config_sort_groups (char **groups, gsize ngroups);
+
G_END_DECLS
#endif /* __NETWORKMANAGER_CONFIG_H__ */
diff --git a/src/tests/config/test-config.c b/src/tests/config/test-config.c
index bc4944e021..82fb73dad2 100644
--- a/src/tests/config/test-config.c
+++ b/src/tests/config/test-config.c
@@ -33,7 +33,7 @@
#include "nm-test-utils.h"
static NMConfig *
-setup_config (GError **error, const char *config_file, const char *config_dir, const char *system_config_dir, ...)
+setup_config (GError **error, const char *config_file, const char *intern_config, const char *config_dir, const char *system_config_dir, ...)
{
va_list ap;
GPtrArray *args;
@@ -51,6 +51,10 @@ setup_config (GError **error, const char *config_file, const char *config_dir, c
g_ptr_array_add (args, "test-config");
g_ptr_array_add (args, "--config");
g_ptr_array_add (args, (char *)config_file);
+ if (intern_config) {
+ g_ptr_array_add (args, "--intern-config");
+ g_ptr_array_add (args, (char *)intern_config);
+ }
g_ptr_array_add (args, "--config-dir");
g_ptr_array_add (args, (char *)config_dir);
if (system_config_dir) {
@@ -101,7 +105,7 @@ test_config_simple (void)
gs_unref_object NMDevice *dev51 = nm_test_device_new ("00:00:00:00:00:51");
gs_unref_object NMDevice *dev52 = nm_test_device_new ("00:00:00:00:00:52");
- config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", "", NULL);
+ config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", "/no/such/dir", "", NULL);
g_assert_cmpstr (nm_config_data_get_config_main_file (nm_config_get_data_orig (config)), ==, SRCDIR "/NetworkManager.conf");
g_assert_cmpstr (nm_config_get_dhcp_client (config), ==, "dhclient");
@@ -180,7 +184,7 @@ test_config_non_existent (void)
{
GError *error = NULL;
- setup_config (&error, SRCDIR "/no-such-file", "/no/such/dir", "", NULL);
+ setup_config (&error, SRCDIR "/no-such-file", "", "/no/such/dir", "", NULL);
g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND);
g_clear_error (&error);
}
@@ -190,7 +194,7 @@ test_config_parse_error (void)
{
GError *error = NULL;
- setup_config (&error, SRCDIR "/bad.conf", "/no/such/dir", "", NULL);
+ setup_config (&error, SRCDIR "/bad.conf", "", "/no/such/dir", "", NULL);
g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE);
g_clear_error (&error);
}
@@ -201,7 +205,7 @@ test_config_override (void)
NMConfig *config;
const char **plugins;
- config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", "",
+ config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", "/no/such/dir", "",
"--plugins", "alpha,beta,gamma,delta",
"--connectivity-interval", "12",
NULL);
@@ -239,7 +243,7 @@ test_config_no_auto_default (void)
g_assert_cmpint (nwrote, ==, 18);
close (fd);
- config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", "",
+ config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", "/no/such/dir", "",
"--no-auto-default", state_file,
NULL);
@@ -261,7 +265,7 @@ test_config_no_auto_default (void)
g_object_unref (config);
- config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", "",
+ config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", "/no/such/dir", "",
"--no-auto-default", state_file,
NULL);
@@ -289,7 +293,7 @@ test_config_confdir (void)
char *value;
GSList *specs;
- config = setup_config (NULL, SRCDIR "/NetworkManager.conf", SRCDIR "/conf.d", "", NULL);
+ config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", SRCDIR "/conf.d", "", NULL);
g_assert_cmpstr (nm_config_data_get_config_main_file (nm_config_get_data_orig (config)), ==, SRCDIR "/NetworkManager.conf");
g_assert_cmpstr (nm_config_get_dhcp_client (config), ==, "dhcpcd");
@@ -395,7 +399,7 @@ test_config_confdir_parse_error (void)
GError *error = NULL;
/* Using SRCDIR as the conf dir will pick up bad.conf */
- setup_config (&error, SRCDIR "/NetworkManager.conf", SRCDIR, "", NULL);
+ setup_config (&error, SRCDIR "/NetworkManager.conf", "", SRCDIR, "", NULL);
g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE);
g_clear_error (&error);
}