summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2015-06-10 11:59:46 +0200
committerThomas Haller <thaller@redhat.com>2015-07-02 16:01:20 +0200
commit40c57fa7f197ad9456b1359862d6bf1a7c3fd352 (patch)
tree916763501b5ae53f50ca7934d1f3a161c6114c77
parent947fc9a27885c268ea742e33d18f27666fa9a043 (diff)
downloadNetworkManager-40c57fa7f197ad9456b1359862d6bf1a7c3fd352.tar.gz
config: add write support to atomic-sections
We already support setting configuration values, either: (1) set any internal section, i.e. groups starting with [.intern*]. Those values don't ever interfere with that the user can configure. (2) set individual properties that overwrite user configuration. When doing that, we record the value from user configuration and on load, we reject our internal overwrite if the user configuration changed in the meantime. This is done by storing the values with ".set." and ".was." prefixes. Now add support for "atomic sections". In this case, certain groups can be marked as "atomic". When writing to such sections, we overwrite the entire user-provided setting. We also record the values from user configuration, and reject our internal value if we notice modifications. This basically extends (2) from individual properties to the entire section.
-rw-r--r--src/main.c2
-rw-r--r--src/nm-config-data.c57
-rw-r--r--src/nm-config-data.h1
-rw-r--r--src/nm-config.c209
-rw-r--r--src/nm-config.h6
-rw-r--r--src/tests/config/test-config.c2
6 files changed, 253 insertions, 24 deletions
diff --git a/src/main.c b/src/main.c
index dc6973446f..4f906f5574 100644
--- a/src/main.c
+++ b/src/main.c
@@ -343,7 +343,7 @@ main (int argc, char *argv[])
}
/* Read the config file and CLI overrides */
- config = nm_config_setup (config_cli, &error);
+ config = nm_config_setup (config_cli, NULL, &error);
nm_config_cmd_line_options_free (config_cli);
config_cli = NULL;
if (config == NULL) {
diff --git a/src/nm-config-data.c b/src/nm-config-data.c
index c3f279a521..03cae638c7 100644
--- a/src/nm-config-data.c
+++ b/src/nm-config-data.c
@@ -310,6 +310,42 @@ nm_config_data_get_keys (const NMConfigData *self, const char *group)
return g_key_file_get_keys (NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile, group, NULL, NULL);
}
+/**
+ * nm_config_data_is_intern_atomic_group:
+ * @self:
+ * @group: name of the group to check.
+ *
+ * whether a configuration group @group exists and is entirely overwritten
+ * by internal configuration, i.e. whether it is an atomic group that is
+ * overwritten.
+ *
+ * It doesn't say, that there actually is a user setting that was overwritten. That
+ * means there could be no corresponding section defined in user configuration
+ * that required overwriting.
+ *
+ * Returns: %TRUE if @group exists and is an atomic group set via internal configuration.
+ */
+gboolean
+nm_config_data_is_intern_atomic_group (const NMConfigData *self, const char *group)
+{
+ NMConfigDataPrivate *priv;
+
+ g_return_val_if_fail (NM_IS_CONFIG_DATA (self), FALSE);
+ g_return_val_if_fail (group && *group, FALSE);
+
+ priv = NM_CONFIG_DATA_GET_PRIVATE (self);
+
+ if ( !priv->keyfile_intern
+ || !g_key_file_has_key (priv->keyfile_intern, group, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, NULL))
+ return FALSE;
+
+ /* we have a .was entry for the section. That means that the section would be overwritten
+ * from user configuration. But it doesn't mean that the merged configuration contains this
+ * groups, because the internal setting could hide the user section.
+ * Only return TRUE, if we actually have such a group in the merged configuration.*/
+ return g_key_file_has_group (priv->keyfile, group);
+}
+
/************************************************************************/
static GKeyFile *
@@ -336,26 +372,36 @@ _merge_keyfiles (GKeyFile *keyfile_user, GKeyFile *keyfile_intern)
for (g = 0; groups[g]; g++) {
const char *group = groups[g];
gs_strfreev char **keys = NULL;
- gboolean is_intern;
+ gboolean is_intern, is_atomic = FALSE;
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);
+ if ( !is_intern
+ && g_key_file_has_key (keyfile_intern, group, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, NULL)) {
+ /* the entire section is atomically overwritten by @keyfile_intern. */
+ g_key_file_remove_group (keyfile, group, NULL);
+ is_atomic = TRUE;
+ }
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)) {
+ if (is_atomic && strcmp (key, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS) == 0)
+ continue;
+
+ if ( !is_intern && !is_atomic
+ && _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))
+ if (!is_intern && !is_atomic && _HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_SET))
continue;
value = g_key_file_get_value (keyfile_intern, group, key, NULL);
@@ -448,9 +494,12 @@ nm_config_data_log (const NMConfigData *self, const char *prefix)
for (g = 0; g < ngroups; g++) {
const char *group = groups[g];
gs_strfreev char **keys = NULL;
+ gboolean is_atomic;
+
+ is_atomic = nm_config_data_is_intern_atomic_group (self, group);
_LOG ("");
- _LOG ("[%s]", group);
+ _LOG ("[%s]%s", group, is_atomic ? "*" : "");
keys = g_key_file_get_keys (priv->keyfile, group, NULL, NULL);
for (k = 0; keys && keys[k]; k++) {
diff --git a/src/nm-config-data.h b/src/nm-config-data.h
index d061583540..0dfdf531ec 100644
--- a/src/nm-config-data.h
+++ b/src/nm-config-data.h
@@ -132,6 +132,7 @@ 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);
+gboolean nm_config_data_is_intern_atomic_group (const NMConfigData *self, const char *group);
GKeyFile *nm_config_data_clone_keyfile_intern (const NMConfigData *self);
diff --git a/src/nm-config.c b/src/nm-config.c
index 0c36f7a773..215595c208 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -84,11 +84,14 @@ typedef struct {
char *debug;
gboolean configure_and_quit;
+
+ char **atomic_section_prefixes;
} NMConfigPrivate;
enum {
PROP_0,
PROP_CMD_LINE_OPTIONS,
+ PROP_ATOMIC_SECTION_PREFIXES,
LAST_PROP,
};
@@ -655,6 +658,11 @@ read_config (GKeyFile *keyfile, const char *dirname, const char *path, GError **
continue;
}
+ if (!strcmp (key, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS)) {
+ /* the "was" key is protected and it cannot be set by user configuration. */
+ continue;
+ }
+
key_len = strlen (key);
last_char = key[key_len - 1];
if ( key_len > 1
@@ -963,6 +971,70 @@ read_entire_config (const NMConfigCmdLineOptions *cli,
return keyfile;
}
+static gboolean
+_is_atomic_section (const char *const*atomic_section_prefixes, const char *group)
+{
+ if (atomic_section_prefixes) {
+ for (; *atomic_section_prefixes; atomic_section_prefixes++) {
+ if ( **atomic_section_prefixes
+ && g_str_has_prefix (group, *atomic_section_prefixes))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+_string_append_val (GString *str, const char *value)
+{
+ if (!value)
+ return;
+ g_string_append_c (str, '+');
+ while (TRUE) {
+ switch (*value) {
+ case '\0':
+ return;
+ case '\\':
+ case '+':
+ case '#':
+ case ':':
+ g_string_append_c (str, '+');
+ default:
+ g_string_append_c (str, *value);
+ }
+ value++;
+ }
+}
+
+static char *
+_keyfile_serialize_section (GKeyFile *keyfile, const char *group)
+{
+ gs_strfreev char **keys = NULL;
+ GString *str;
+ guint k;
+
+ if (keyfile)
+ keys = g_key_file_get_keys (keyfile, group, NULL, NULL);
+ if (!keys)
+ return g_strdup ("0#");
+
+ /* prepend a version. */
+ str = g_string_new ("1#");
+
+ for (k = 0; keys[k]; k++) {
+ const char *key = keys[k];
+ gs_free char *value = NULL;
+
+ _string_append_val (str, key);
+ g_string_append_c (str, ':');
+
+ value = g_key_file_get_value (keyfile, group, key, NULL);
+ _string_append_val (str, value);
+ g_string_append_c (str, '#');
+ }
+ return g_string_free (str, FALSE);
+}
+
/**
* intern_config_read:
* @filename: the filename where to store the internal config
@@ -983,6 +1055,7 @@ read_entire_config (const NMConfigCmdLineOptions *cli,
static GKeyFile *
intern_config_read (const char *filename,
GKeyFile *keyfile_conf,
+ const char *const*atomic_section_prefixes,
gboolean *out_needs_rewrite)
{
GKeyFile *keyfile_intern;
@@ -1012,13 +1085,32 @@ intern_config_read (const char *filename,
for (g = 0; groups && groups[g]; g++) {
gs_strfreev char **keys = NULL;
const char *group = groups[g];
- gboolean is_intern;
+ gboolean is_intern, is_atomic;
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);
+ is_atomic = !is_intern && _is_atomic_section (atomic_section_prefixes, group);
+
+ if (is_atomic) {
+ gs_free char *conf_section_was = NULL;
+ gs_free char *conf_section_is = NULL;
+
+ conf_section_is = _keyfile_serialize_section (keyfile_conf, group);
+ conf_section_was = g_key_file_get_string (keyfile, group, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, NULL);
+
+ if (g_strcmp0 (conf_section_was, conf_section_is) != 0) {
+ /* the section no longer matches. Skip it entirely. */
+ needs_rewrite = TRUE;
+ continue;
+ }
+ /* we must set the "was" marker in our keyfile, so that we know that the section
+ * from user config is overwritten. The value doesn't matter, it's just a marker
+ * that this section is present. */
+ g_key_file_set_value (keyfile_intern, group, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, "");
+ }
for (k = 0; keys[k]; k++) {
gs_free char *value_set = NULL;
@@ -1029,6 +1121,10 @@ intern_config_read (const char *filename,
if (is_intern) {
has_intern = TRUE;
g_key_file_set_value (keyfile_intern, group, key, value_set);
+ } else if (is_atomic) {
+ if (strcmp (key, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS) == 0)
+ continue;
+ 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;
@@ -1098,7 +1194,7 @@ out:
}
static int
-_intern_config_write_sort_fcn (const char **a, const char **b, gpointer dummy)
+_intern_config_write_sort_fcn (const char **a, const char **b, const char *const*atomic_section_prefixes)
{
const char *g_a = (a ? *a : NULL);
const char *g_b = (b ? *b : NULL);
@@ -1112,6 +1208,16 @@ _intern_config_write_sort_fcn (const char **a, const char **b, gpointer dummy)
return 1;
return -1;
}
+ if (!a_is) {
+ a_is = _is_atomic_section (atomic_section_prefixes, g_a);
+ b_is = _is_atomic_section (atomic_section_prefixes, g_b);
+
+ if (a_is != b_is) {
+ if (a_is)
+ return 1;
+ return -1;
+ }
+ }
return g_strcmp0 (g_a, g_b);
}
@@ -1119,6 +1225,7 @@ static gboolean
intern_config_write (const char *filename,
GKeyFile *keyfile_intern,
GKeyFile *keyfile_conf,
+ const char *const*atomic_section_prefixes,
GError **error)
{
GKeyFile *keyfile;
@@ -1144,31 +1251,58 @@ intern_config_write (const char *filename,
g_strv_length (groups),
sizeof (char *),
(GCompareDataFunc) _intern_config_write_sort_fcn,
- NULL);
+ (gpointer) atomic_section_prefixes);
}
}
for (g = 0; groups && groups[g]; g++) {
gs_strfreev char **keys = NULL;
const char *group = groups[g];
- gboolean is_intern;
+ gboolean is_intern, is_atomic;
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);
+ is_atomic = !is_intern && _is_atomic_section (atomic_section_prefixes, group);
+
+ if (is_atomic) {
+ if ( (!keys[0] || (!keys[1] && strcmp (keys[0], NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS) == 0))
+ && !g_key_file_has_group (keyfile_conf, group)) {
+ /* we are about to save an atomic section. However, we don't have any additional
+ * keys on our own and there is no user-provided (overlapping) section either.
+ * We don't have to write an empty section (i.e. skip the useless ".was=0#"). */
+ continue;
+ } else {
+ gs_free char *conf_section_is = NULL;
+
+ conf_section_is = _keyfile_serialize_section (keyfile_conf, group);
+ g_key_file_set_string (keyfile, group, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, conf_section_is);
+ g_key_file_set_comment (keyfile, group, NULL,
+ " Overwrites entire section from 'NetworkManager.conf'",
+ NULL);
+ }
+ }
for (k = 0; keys[k]; k++) {
const char *key = keys[k];
gs_free char *value_set = NULL;
gs_free char *key_set = NULL;
+ if ( !is_intern
+ && strcmp (key, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS) == 0) {
+ g_warn_if_fail (is_atomic);
+ continue;
+ }
+
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 {
+ } else if (is_atomic)
+ 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)) {
@@ -1237,6 +1371,10 @@ intern_config_write (const char *filename,
" That means, if you modify a value in 'NetworkManager.conf', the internal\n"
" overwrite no longer matches and is ignored.\n"
"\n"
+ " Certain sections can only be overwritten whole, not on a per key basis.\n"
+ " Such sections are marked with a \""NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS"\" key that records the user configuration\n"
+ " at the time of writing.\n"
+ "\n"
" Internal sections of the form [" NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN "*] cannot\n"
" be set by user configuration.\n"
"\n"
@@ -1286,10 +1424,15 @@ nm_config_get_device_match_spec (const GKeyFile *keyfile, const char *group, con
* 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:
+ * There are 3 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.
+ * - there are atomic sections, i.e. sections whose name start with one of
+ * NM_CONFIG_ATOMIC_SECTION_PREFIXES. If you put values in these sections,
+ * it means you completely replace the section from user configuration.
+ * You can also hide a user provided section by only putting the special
+ * key NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS into that section.
* - 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.
@@ -1308,6 +1451,8 @@ nm_config_set_values (NMConfig *self,
GKeyFile *keyfile_new;
GError *local = NULL;
NMConfigData *new_data = NULL;
+ gs_strfreev char **groups = NULL;
+ gint g;
g_return_if_fail (NM_IS_CONFIG (self));
@@ -1319,6 +1464,13 @@ nm_config_set_values (NMConfig *self,
if (keyfile_intern_new)
_nm_keyfile_copy (keyfile_new, keyfile_intern_new);
+ /* ensure that every atomic section has a .was entry. */
+ groups = g_key_file_get_groups (keyfile_new, NULL);
+ for (g = 0; groups && groups[g]; g++) {
+ if (_is_atomic_section ((const char *const*) priv->atomic_section_prefixes, groups[g]))
+ g_key_file_set_value (keyfile_new, groups[g], NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, "");
+ }
+
if (!_nm_keyfile_equals (keyfile_intern_current, keyfile_new, TRUE))
new_data = nm_config_data_new_update_keyfile_intern (priv->config_data, keyfile_new);
@@ -1335,7 +1487,8 @@ nm_config_set_values (NMConfig *self,
* 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)) {
+ if (!intern_config_write (priv->intern_config_file, keyfile_new, keyfile_user,
+ (const char *const*) priv->atomic_section_prefixes, &local)) {
nm_log_warn (LOGD_CORE, "error saving internal configuration \"%s\": %s", priv->intern_config_file, local->message);
g_clear_error (&local);
}
@@ -1390,9 +1543,14 @@ nm_config_reload (NMConfig *self, int signal)
no_auto_default = no_auto_default_from_file (priv->no_auto_default_file);
- 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);
+ keyfile_intern = intern_config_read (priv->intern_config_file,
+ keyfile,
+ (const char *const*) priv->atomic_section_prefixes,
+ &intern_config_needs_rewrite);
+ if (intern_config_needs_rewrite) {
+ intern_config_write (priv->intern_config_file, keyfile_intern, keyfile,
+ (const char *const*) priv->atomic_section_prefixes, 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);
@@ -1515,11 +1673,11 @@ nm_config_get (void)
}
NMConfig *
-nm_config_setup (const NMConfigCmdLineOptions *cli, GError **error)
+nm_config_setup (const NMConfigCmdLineOptions *cli, char **atomic_section_prefixes, GError **error)
{
g_assert (!singleton_instance);
- singleton_instance = nm_config_new (cli, error);
+ singleton_instance = nm_config_new (cli, atomic_section_prefixes, error);
if (singleton_instance)
nm_singleton_instance_weak_ref_register ();
return singleton_instance;
@@ -1602,9 +1760,14 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
no_auto_default = no_auto_default_from_file (priv->no_auto_default_file);
- 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);
+ keyfile_intern = intern_config_read (priv->intern_config_file,
+ keyfile,
+ (const char *const*) priv->atomic_section_prefixes,
+ &intern_config_needs_rewrite);
+ if (intern_config_needs_rewrite) {
+ intern_config_write (priv->intern_config_file, keyfile_intern, keyfile,
+ (const char *const*) priv->atomic_section_prefixes, NULL);
+ }
priv->config_data_orig = nm_config_data_new (config_main_file, config_description, (const char *const*) no_auto_default, keyfile, keyfile_intern);
@@ -1619,12 +1782,13 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
}
NMConfig *
-nm_config_new (const NMConfigCmdLineOptions *cli, GError **error)
+nm_config_new (const NMConfigCmdLineOptions *cli, char **atomic_section_prefixes, GError **error)
{
return NM_CONFIG (g_initable_new (NM_TYPE_CONFIG,
NULL,
error,
NM_CONFIG_CMD_LINE_OPTIONS, cli,
+ NM_CONFIG_ATOMIC_SECTION_PREFIXES, atomic_section_prefixes,
NULL));
}
@@ -1650,6 +1814,7 @@ finalize (GObject *gobject)
g_free (priv->log_level);
g_free (priv->log_domains);
g_free (priv->debug);
+ g_strfreev (priv->atomic_section_prefixes);
_nm_config_cmd_line_options_clear (&priv->cli);
@@ -1676,6 +1841,10 @@ set_property (GObject *object, guint prop_id,
else
_nm_config_cmd_line_options_copy (cli, &priv->cli);
break;
+ case PROP_ATOMIC_SECTION_PREFIXES:
+ /* construct only */
+ priv->atomic_section_prefixes = g_strdupv (g_value_get_boxed (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1698,6 +1867,14 @@ nm_config_class_init (NMConfigClass *config_class)
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property
+ (object_class, PROP_ATOMIC_SECTION_PREFIXES,
+ g_param_spec_boxed (NM_CONFIG_ATOMIC_SECTION_PREFIXES, "", "",
+ G_TYPE_STRV,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
signals[SIGNAL_CONFIG_CHANGED] =
g_signal_new (NM_CONFIG_SIGNAL_CONFIG_CHANGED,
G_OBJECT_CLASS_TYPE (object_class),
diff --git a/src/nm-config.h b/src/nm-config.h
index d4ff887ba3..3caf0c5c31 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -39,6 +39,7 @@ G_BEGIN_DECLS
/* Properties */
#define NM_CONFIG_CMD_LINE_OPTIONS "cmd-line-options"
+#define NM_CONFIG_ATOMIC_SECTION_PREFIXES "atomic-section-prefixes"
/* Signals */
#define NM_CONFIG_SIGNAL_CONFIG_CHANGED "config-changed"
@@ -60,6 +61,7 @@ G_BEGIN_DECLS
#define NM_CONFIG_KEYFILE_GROUP_IFUPDOWN "ifupdown"
#define NM_CONFIG_KEYFILE_GROUP_IFNET "ifnet"
+#define NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS ".was"
#define NM_CONFIG_KEYFILE_KEY_IFNET_AUTO_REFRESH "auto_refresh"
#define NM_CONFIG_KEYFILE_KEY_IFNET_MANAGED "managed"
#define NM_CONFIG_KEYFILE_KEY_IFUPDOWN_MANAGED "managed"
@@ -115,8 +117,8 @@ void nm_config_cmd_line_options_add_to_entries (NMConfigCmdLi
gboolean nm_config_get_no_auto_default_for_device (NMConfig *config, NMDevice *device);
void nm_config_set_no_auto_default_for_device (NMConfig *config, NMDevice *device);
-NMConfig *nm_config_new (const NMConfigCmdLineOptions *cli, GError **error);
-NMConfig *nm_config_setup (const NMConfigCmdLineOptions *cli, GError **error);
+NMConfig *nm_config_new (const NMConfigCmdLineOptions *cli, char **atomic_section_prefixes, GError **error);
+NMConfig *nm_config_setup (const NMConfigCmdLineOptions *cli, char **atomic_section_prefixes, GError **error);
void nm_config_reload (NMConfig *config, int signal);
gint nm_config_parse_boolean (const char *str, gint default_value);
diff --git a/src/tests/config/test-config.c b/src/tests/config/test-config.c
index 82fb73dad2..d259b620bb 100644
--- a/src/tests/config/test-config.c
+++ b/src/tests/config/test-config.c
@@ -82,7 +82,7 @@ setup_config (GError **error, const char *config_file, const char *intern_config
g_ptr_array_free (args, TRUE);
- config = nm_config_setup (cli, &local_error);
+ config = nm_config_setup (cli, NULL, &local_error);
if (error) {
g_assert (!config);
g_assert (local_error);