summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2015-02-03 15:49:11 +0100
committerThomas Haller <thaller@redhat.com>2015-02-03 15:49:11 +0100
commitf9e4af2d86251f4b9947fea3198f9aabf1f89ed5 (patch)
tree52117994ae95d4c33999f2d45312915e73037c28
parent205c109741b822e9475994b74232b6bf64d4f16d (diff)
parent5b47462f32489c726d6f79dfed431864d31f8dd2 (diff)
downloadNetworkManager-f9e4af2d86251f4b9947fea3198f9aabf1f89ed5.tar.gz
config,connectivity: merge branch 'th/rh1066697_reload_config'
Refactor NMConfig to support reloading. Implement reloading of NMConnectivity parameters https://bugzilla.redhat.com/show_bug.cgi?id=1066697
-rw-r--r--src/Makefile.am2
-rw-r--r--src/devices/nm-device-ethernet.c2
-rw-r--r--src/main-utils.c11
-rw-r--r--src/main-utils.h8
-rw-r--r--src/main.c24
-rw-r--r--src/nm-config-data.c408
-rw-r--r--src/nm-config-data.h91
-rw-r--r--src/nm-config.c715
-rw-r--r--src/nm-config.h45
-rw-r--r--src/nm-connectivity.c296
-rw-r--r--src/nm-connectivity.h6
-rw-r--r--src/nm-iface-helper.c7
-rw-r--r--src/nm-manager.c39
-rw-r--r--src/nm-types.h2
-rw-r--r--src/settings/nm-settings.c2
-rw-r--r--src/settings/plugins/example/plugin.c2
-rw-r--r--src/settings/plugins/ifnet/plugin.c12
-rw-r--r--src/settings/plugins/ifupdown/plugin.c8
-rw-r--r--src/settings/plugins/keyfile/plugin.c2
-rw-r--r--src/tests/config/test-config.c143
20 files changed, 1382 insertions, 443 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index a5a40fba35..e0ed6f3f66 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -287,6 +287,8 @@ nm_sources = \
nm-active-connection.h \
nm-config.c \
nm-config.h \
+ nm-config-data.c \
+ nm-config-data.h \
nm-connection-provider.c \
nm-connection-provider.h \
nm-connectivity.c \
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index 0027958c38..af24f8be6d 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -1463,7 +1463,7 @@ new_default_connection (NMDevice *self)
const char *hw_address;
char *defname, *uuid;
- if (!nm_config_get_ethernet_can_auto_default (nm_config_get (), self))
+ if (nm_config_get_no_auto_default_for_device (nm_config_get (), self))
return NULL;
hw_address = nm_device_get_hw_address (self);
diff --git a/src/main-utils.c b/src/main-utils.c
index 0825a7f01d..164dc84a99 100644
--- a/src/main-utils.c
+++ b/src/main-utils.c
@@ -40,9 +40,7 @@
static gboolean
sighup_handler (gpointer user_data)
{
- /* Reread config stuff like system config files, VPN service files, etc */
- nm_log_info (LOGD_CORE, "caught SIGHUP, not supported yet.");
-
+ nm_main_config_reload ();
return G_SOURCE_CONTINUE;
}
@@ -177,7 +175,8 @@ nm_main_utils_early_setup (const char *progname,
char **argv[],
int *argc,
GOptionEntry *options,
- GOptionEntry *more_options,
+ void (*option_context_hook) (gpointer user_data, GOptionContext *opt_ctx),
+ gpointer option_context_hook_data,
const char *summary)
{
GOptionContext *opt_ctx = NULL;
@@ -220,9 +219,9 @@ nm_main_utils_early_setup (const char *progname,
g_option_context_set_ignore_unknown_options (opt_ctx, FALSE);
g_option_context_set_help_enabled (opt_ctx, TRUE);
g_option_context_add_main_entries (opt_ctx, options, NULL);
- if (more_options)
- g_option_context_add_main_entries (opt_ctx, more_options, NULL);
g_option_context_set_summary (opt_ctx, summary);
+ if (option_context_hook)
+ option_context_hook (option_context_hook_data, opt_ctx);
success = g_option_context_parse (opt_ctx, argc, argv, &error);
if (!success) {
diff --git a/src/main-utils.h b/src/main-utils.h
index 30c8213ed3..9b29866be0 100644
--- a/src/main-utils.h
+++ b/src/main-utils.h
@@ -33,7 +33,13 @@ gboolean nm_main_utils_early_setup (const char *progname,
char **argv[],
int *argc,
GOptionEntry *options,
- GOptionEntry *more_options,
+ void (*option_context_hook) (gpointer user_data, GOptionContext *opt_ctx),
+ gpointer option_context_hook_data,
const char *summary);
+/* The following functions are not implemented inside nm-main-utils.c, instead
+ * main.c and nm-iface-helper.c */
+
+void nm_main_config_reload (void);
+
#endif /* __MAIN_UTILS_H__ */
diff --git a/src/main.c b/src/main.c
index 2d6af01594..11ecffca98 100644
--- a/src/main.c
+++ b/src/main.c
@@ -175,6 +175,19 @@ _init_nm_debug (const char *debug)
}
}
+void
+nm_main_config_reload ()
+{
+ nm_log_info (LOGD_CORE, "reload configuration...");
+ /* The signal handler thread is only installed after
+ * creating NMConfig instance, and on shut down we
+ * no longer run the mainloop (to reach this point).
+ *
+ * Hence, a NMConfig singleton instance must always be
+ * available. */
+ nm_config_reload (nm_config_get ());
+}
+
static void
manager_configure_quit (NMManager *manager, gpointer user_data)
{
@@ -204,6 +217,7 @@ main (int argc, char *argv[])
GError *error = NULL;
gboolean wrote_pidfile = FALSE;
char *bad_domains = NULL;
+ NMConfigCmdLineOptions *config_cli;
GOptionEntry options[] = {
{ "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Print NetworkManager version and exit"), NULL },
@@ -224,11 +238,13 @@ main (int argc, char *argv[])
main_loop = g_main_loop_new (NULL, FALSE);
+ config_cli = nm_config_cmd_line_options_new ();
if (!nm_main_utils_early_setup ("NetworkManager",
&argv,
&argc,
options,
- nm_config_get_options (),
+ (void (*)(gpointer, GOptionContext *)) nm_config_cmd_line_options_add_to_entries,
+ config_cli,
_("NetworkManager monitors all network connections and automatically\nchooses the best connection to use. It also allows the user to\nspecify wireless access points which wireless cards in the computer\nshould associate with.")))
exit (1);
@@ -290,7 +306,9 @@ main (int argc, char *argv[])
exit (1);
/* Read the config file and CLI overrides */
- config = nm_config_new (&error);
+ config = nm_config_setup (config_cli, &error);
+ nm_config_cmd_line_options_free (config_cli);
+ config_cli = NULL;
if (config == NULL) {
fprintf (stderr, _("Failed to read configuration: (%d) %s\n"),
error ? error->code : -1,
@@ -369,7 +387,7 @@ main (int argc, char *argv[])
nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting...");
success = FALSE;
- nm_log_info (LOGD_CORE, "Read config: %s", nm_config_get_description (config));
+ nm_log_info (LOGD_CORE, "Read config: %s", nm_config_data_get_config_description (nm_config_get_data (config)));
nm_log_info (LOGD_CORE, "WEXT support is %s",
#if HAVE_WEXT
"enabled"
diff --git a/src/nm-config-data.c b/src/nm-config-data.c
new file mode 100644
index 0000000000..f1a7bcfc62
--- /dev/null
+++ b/src/nm-config-data.c
@@ -0,0 +1,408 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2013 Thomas Bechtold <thomasbechtold@jpberlin.de>
+ */
+
+#include "nm-config-data.h"
+
+#include <string.h>
+
+#include "nm-config.h"
+#include "gsystem-local-alloc.h"
+
+typedef struct {
+ char *config_main_file;
+ char *config_description;
+
+ GKeyFile *keyfile;
+
+ struct {
+ char *uri;
+ char *response;
+ guint interval;
+ } connectivity;
+
+ struct {
+ char **arr;
+ GSList *specs;
+ } no_auto_default;
+} NMConfigDataPrivate;
+
+
+enum {
+ PROP_0,
+ PROP_CONFIG_MAIN_FILE,
+ PROP_CONFIG_DESCRIPTION,
+ PROP_KEYFILE,
+ PROP_CONNECTIVITY_URI,
+ PROP_CONNECTIVITY_INTERVAL,
+ PROP_CONNECTIVITY_RESPONSE,
+ PROP_NO_AUTO_DEFAULT,
+
+ LAST_PROP
+};
+
+G_DEFINE_TYPE (NMConfigData, nm_config_data, G_TYPE_OBJECT)
+
+#define NM_CONFIG_DATA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_CONFIG_DATA, NMConfigDataPrivate))
+
+/************************************************************************/
+
+const char *
+nm_config_data_get_config_main_file (const NMConfigData *self)
+{
+ g_return_val_if_fail (self, NULL);
+
+ return NM_CONFIG_DATA_GET_PRIVATE (self)->config_main_file;
+}
+
+const char *
+nm_config_data_get_config_description (const NMConfigData *self)
+{
+ g_return_val_if_fail (self, NULL);
+
+ return NM_CONFIG_DATA_GET_PRIVATE (self)->config_description;
+}
+
+char *
+nm_config_data_get_value (const NMConfigData *self, const char *group, const char *key, GError **error)
+{
+ g_return_val_if_fail (self, NULL);
+
+ return g_key_file_get_string (NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile, group, key, error);
+}
+
+const char *
+nm_config_data_get_connectivity_uri (const NMConfigData *self)
+{
+ g_return_val_if_fail (self, NULL);
+
+ return NM_CONFIG_DATA_GET_PRIVATE (self)->connectivity.uri;
+}
+
+const guint
+nm_config_data_get_connectivity_interval (const NMConfigData *self)
+{
+ g_return_val_if_fail (self, 0);
+
+ return MAX (NM_CONFIG_DATA_GET_PRIVATE (self)->connectivity.interval, 0);
+}
+
+const char *
+nm_config_data_get_connectivity_response (const NMConfigData *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+
+ return NM_CONFIG_DATA_GET_PRIVATE (self)->connectivity.response;
+}
+
+const char *const*
+nm_config_data_get_no_auto_default (const NMConfigData *self)
+{
+ g_return_val_if_fail (self, FALSE);
+
+ return (const char *const*) NM_CONFIG_DATA_GET_PRIVATE (self)->no_auto_default.arr;
+}
+
+const GSList *
+nm_config_data_get_no_auto_default_list (const NMConfigData *self)
+{
+ g_return_val_if_fail (self, NULL);
+
+ return NM_CONFIG_DATA_GET_PRIVATE (self)->no_auto_default.specs;
+}
+
+/************************************************************************/
+
+static gboolean
+_keyfile_a_contains_all_in_b (GKeyFile *kf_a, GKeyFile *kf_b)
+{
+ gs_strfreev char **groups = NULL;
+ guint i, j;
+
+ if (kf_a == kf_b)
+ return TRUE;
+
+ groups = g_key_file_get_groups (kf_a, NULL);
+ for (i = 0; groups && groups[i]; i++) {
+ gs_strfreev char **keys = NULL;
+
+ keys = g_key_file_get_keys (kf_a, groups[i], NULL, NULL);
+ if (keys) {
+ for (j = 0; keys[j]; j++) {
+ gs_free char *key_a = g_key_file_get_value (kf_a, groups[i], keys[j], NULL);
+ gs_free char *key_b = g_key_file_get_value (kf_b, groups[i], keys[j], NULL);
+
+ if (g_strcmp0 (key_a, key_b) != 0)
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+NMConfigChangeFlags
+nm_config_data_diff (NMConfigData *old_data, NMConfigData *new_data)
+{
+ NMConfigChangeFlags changes = NM_CONFIG_CHANGE_NONE;
+ NMConfigDataPrivate *priv_old, *priv_new;
+ GSList *spec_old, *spec_new;
+
+ g_return_val_if_fail (NM_IS_CONFIG_DATA (old_data), NM_CONFIG_CHANGE_NONE);
+ g_return_val_if_fail (NM_IS_CONFIG_DATA (new_data), NM_CONFIG_CHANGE_NONE);
+
+ priv_old = NM_CONFIG_DATA_GET_PRIVATE (old_data);
+ priv_new = NM_CONFIG_DATA_GET_PRIVATE (new_data);
+
+ if ( !_keyfile_a_contains_all_in_b (priv_old->keyfile, priv_new->keyfile)
+ || !_keyfile_a_contains_all_in_b (priv_new->keyfile, priv_old->keyfile))
+ changes |= NM_CONFIG_CHANGE_VALUES;
+
+ 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)
+ changes |= NM_CONFIG_CHANGE_CONFIG_FILES;
+
+ if ( nm_config_data_get_connectivity_interval (old_data) != nm_config_data_get_connectivity_interval (new_data)
+ || g_strcmp0 (nm_config_data_get_connectivity_uri (old_data), nm_config_data_get_connectivity_uri (new_data))
+ || g_strcmp0 (nm_config_data_get_connectivity_response (old_data), nm_config_data_get_connectivity_response (new_data)))
+ changes |= NM_CONFIG_CHANGE_CONNECTIVITY;
+
+ spec_old = priv_old->no_auto_default.specs;
+ spec_new = priv_new->no_auto_default.specs;
+ while (spec_old && spec_new && strcmp (spec_old->data, spec_new->data) == 0) {
+ spec_old = spec_old->next;
+ spec_new = spec_new->next;
+ }
+ if (spec_old || spec_new)
+ changes |= NM_CONFIG_CHANGE_NO_AUTO_DEFAULT;
+
+ return changes;
+}
+
+/************************************************************************/
+
+static void
+get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ NMConfigData *self = NM_CONFIG_DATA (object);
+
+ switch (prop_id) {
+ case PROP_CONFIG_MAIN_FILE:
+ g_value_set_string (value, nm_config_data_get_config_main_file (self));
+ break;
+ case PROP_CONFIG_DESCRIPTION:
+ g_value_set_string (value, nm_config_data_get_config_description (self));
+ break;
+ case PROP_NO_AUTO_DEFAULT:
+ g_value_take_boxed (value, g_strdupv ((char **) nm_config_data_get_no_auto_default (self)));
+ break;
+ case PROP_CONNECTIVITY_URI:
+ g_value_set_string (value, nm_config_data_get_connectivity_uri (self));
+ break;
+ case PROP_CONNECTIVITY_INTERVAL:
+ g_value_set_uint (value, nm_config_data_get_connectivity_interval (self));
+ break;
+ case PROP_CONNECTIVITY_RESPONSE:
+ g_value_set_string (value, nm_config_data_get_connectivity_response (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ NMConfigData *self = NM_CONFIG_DATA (object);
+ NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (self);
+ guint i;
+
+ /* This type is immutable. All properties are construct only. */
+ switch (prop_id) {
+ case PROP_CONFIG_MAIN_FILE:
+ priv->config_main_file = g_value_dup_string (value);
+ break;
+ 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 ();
+ break;
+ case PROP_NO_AUTO_DEFAULT:
+ priv->no_auto_default.arr = g_strdupv (g_value_get_boxed (value));
+ if (!priv->no_auto_default.arr)
+ priv->no_auto_default.arr = g_new0 (char *, 1);
+ for (i = 0; priv->no_auto_default.arr[i]; i++)
+ priv->no_auto_default.specs = g_slist_prepend (priv->no_auto_default.specs, priv->no_auto_default.arr[i]);
+ priv->no_auto_default.specs = g_slist_reverse (priv->no_auto_default.specs);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+dispose (GObject *object)
+{
+}
+
+static void
+finalize (GObject *gobject)
+{
+ NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (gobject);
+
+ g_free (priv->config_main_file);
+ g_free (priv->config_description);
+
+ g_free (priv->connectivity.uri);
+ g_free (priv->connectivity.response);
+
+ g_slist_free (priv->no_auto_default.specs);
+ g_strfreev (priv->no_auto_default.arr);
+
+ G_OBJECT_CLASS (nm_config_data_parent_class)->finalize (gobject);
+}
+
+static void
+nm_config_data_init (NMConfigData *self)
+{
+}
+
+static void
+constructed (GObject *object)
+{
+ NMConfigData *self = NM_CONFIG_DATA (object);
+ NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (self);
+ int interval;
+
+ 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);
+
+ interval = g_key_file_get_integer (priv->keyfile, "connectivity", "interval", NULL);
+ priv->connectivity.interval = MAX (0, interval);
+
+ G_OBJECT_CLASS (nm_config_data_parent_class)->constructed (object);
+}
+
+NMConfigData *
+nm_config_data_new (const char *config_main_file,
+ const char *config_description,
+ const char *const*no_auto_default,
+ GKeyFile *keyfile)
+{
+ 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_NO_AUTO_DEFAULT, no_auto_default,
+ NULL);
+}
+
+NMConfigData *
+nm_config_data_new_update_no_auto_default (const NMConfigData *base,
+ const char *const*no_auto_default)
+{
+ 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, priv->keyfile, /* the keyfile is unchanged. It's safe to share it. */
+ NM_CONFIG_DATA_NO_AUTO_DEFAULT, no_auto_default,
+ NULL);
+}
+
+static void
+nm_config_data_class_init (NMConfigDataClass *config_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (config_class);
+
+ g_type_class_add_private (config_class, sizeof (NMConfigDataPrivate));
+
+ object_class->constructed = constructed;
+ object_class->dispose = dispose;
+ object_class->finalize = finalize;
+ object_class->get_property = get_property;
+ object_class->set_property = set_property;
+
+ g_object_class_install_property
+ (object_class, PROP_CONFIG_MAIN_FILE,
+ g_param_spec_string (NM_CONFIG_DATA_CONFIG_MAIN_FILE, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_CONFIG_DESCRIPTION,
+ g_param_spec_string (NM_CONFIG_DATA_CONFIG_DESCRIPTION, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_KEYFILE,
+ g_param_spec_boxed (NM_CONFIG_DATA_KEYFILE, "", "",
+ G_TYPE_KEY_FILE,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_CONNECTIVITY_URI,
+ g_param_spec_string (NM_CONFIG_DATA_CONNECTIVITY_URI, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_CONNECTIVITY_INTERVAL,
+ g_param_spec_uint (NM_CONFIG_DATA_CONNECTIVITY_INTERVAL, "", "",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_CONNECTIVITY_RESPONSE,
+ g_param_spec_string (NM_CONFIG_DATA_CONNECTIVITY_RESPONSE, "", "",
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (object_class, PROP_NO_AUTO_DEFAULT,
+ g_param_spec_boxed (NM_CONFIG_DATA_NO_AUTO_DEFAULT, "", "",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+}
+
diff --git a/src/nm-config-data.h b/src/nm-config-data.h
new file mode 100644
index 0000000000..bb88bf7ea2
--- /dev/null
+++ b/src/nm-config-data.h
@@ -0,0 +1,91 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ */
+
+#ifndef NM_CONFIG_DATA_H
+#define NM_CONFIG_DATA_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "nm-types.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_CONFIG_DATA (nm_config_data_get_type ())
+#define NM_CONFIG_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONFIG_DATA, NMConfigData))
+#define NM_CONFIG_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_CONFIG_DATA, NMConfigDataClass))
+#define NM_IS_CONFIG_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_CONFIG_DATA))
+#define NM_IS_CONFIG_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_CONFIG_DATA))
+#define NM_CONFIG_DATA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CONFIG_DATA, NMConfigDataClass))
+
+
+#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_CONNECTIVITY_URI "connectivity-uri"
+#define NM_CONFIG_DATA_CONNECTIVITY_INTERVAL "connectivity-interval"
+#define NM_CONFIG_DATA_CONNECTIVITY_RESPONSE "connectivity-response"
+#define NM_CONFIG_DATA_NO_AUTO_DEFAULT "no-auto-default"
+
+typedef enum { /*< flags >*/
+ NM_CONFIG_CHANGE_NONE = 0,
+ NM_CONFIG_CHANGE_CONFIG_FILES = (1L << 0),
+ NM_CONFIG_CHANGE_VALUES = (1L << 1),
+ NM_CONFIG_CHANGE_CONNECTIVITY = (1L << 2),
+ NM_CONFIG_CHANGE_NO_AUTO_DEFAULT = (1L << 3),
+
+ _NM_CONFIG_CHANGE_LAST,
+ NM_CONFIG_CHANGE_ALL = ((_NM_CONFIG_CHANGE_LAST - 1) << 1) - 1,
+} NMConfigChangeFlags;
+
+struct _NMConfigData {
+ GObject parent;
+};
+
+typedef struct {
+ GObjectClass parent;
+} NMConfigDataClass;
+
+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);
+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);
+
+const char *nm_config_data_get_config_main_file (const NMConfigData *config_data);
+const char *nm_config_data_get_config_description (const NMConfigData *config_data);
+
+char *nm_config_data_get_value (const NMConfigData *config_data, const char *group, const char *key, GError **error);
+
+const char *nm_config_data_get_connectivity_uri (const NMConfigData *config_data);
+const guint nm_config_data_get_connectivity_interval (const NMConfigData *config_data);
+const char *nm_config_data_get_connectivity_response (const NMConfigData *config_data);
+
+const char *const*nm_config_data_get_no_auto_default (const NMConfigData *config_data);
+const GSList * nm_config_data_get_no_auto_default_list (const NMConfigData *config_data);
+
+G_END_DECLS
+
+#endif /* NM_CONFIG_DATA_H */
+
diff --git a/src/nm-config.c b/src/nm-config.c
index fa9a894429..03fca56b73 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -29,6 +29,9 @@
#include "nm-utils.h"
#include "nm-glib-compat.h"
#include "nm-device.h"
+#include "NetworkManagerUtils.h"
+#include "gsystem-local-alloc.h"
+#include "nm-enum-types.h"
#include <gio/gio.h>
#include <glib/gi18n.h>
@@ -38,12 +41,28 @@
#define NM_OLD_SYSTEM_CONF_FILE NMCONFDIR "/nm-system-settings.conf"
#define NM_NO_AUTO_DEFAULT_STATE_FILE NMSTATEDIR "/no-auto-default.state"
+struct NMConfigCmdLineOptions {
+ char *config_main_file;
+ char *config_dir;
+ char *no_auto_default_file;
+ char *plugins;
+ char *connectivity_uri;
+
+ /* We store interval as signed internally to track whether it's
+ * set or not via GOptionEntry
+ */
+ int connectivity_interval;
+ char *connectivity_response;
+};
+
typedef struct {
- char *nm_conf_path;
+ NMConfigCmdLineOptions cli;
+
+ NMConfigData *config_data;
+ NMConfigData *config_data_orig;
+
char *config_dir;
- char *config_description;
char *no_auto_default_file;
- GKeyFile *keyfile;
char **plugins;
gboolean monitor_connection_files;
@@ -56,24 +75,40 @@ typedef struct {
char *debug;
- char *connectivity_uri;
- gint connectivity_interval;
- char *connectivity_response;
-
- char **no_auto_default;
char **ignore_carrier;
gboolean configure_and_quit;
} NMConfigPrivate;
-static NMConfig *singleton = NULL;
+enum {
+ PROP_0,
+ PROP_CMD_LINE_OPTIONS,
+ LAST_PROP,
+};
+
+enum {
+ SIGNAL_CONFIG_CHANGED,
+
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void nm_config_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (NMConfig, nm_config, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, nm_config_initable_iface_init);
+ )
-G_DEFINE_TYPE (NMConfig, nm_config, G_TYPE_OBJECT)
#define NM_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_CONFIG, NMConfigPrivate))
/************************************************************************/
+static void _set_config_data (NMConfig *self, NMConfigData *new_data);
+
+/************************************************************************/
+
static gboolean
_get_bool_value (GKeyFile *keyfile,
const char *section,
@@ -109,20 +144,23 @@ _get_bool_value (GKeyFile *keyfile,
/************************************************************************/
-const char *
-nm_config_get_path (NMConfig *config)
+NMConfigData *
+nm_config_get_data (NMConfig *config)
{
g_return_val_if_fail (config != NULL, NULL);
- return NM_CONFIG_GET_PRIVATE (config)->nm_conf_path;
+ return NM_CONFIG_GET_PRIVATE (config)->config_data;
}
-const char *
-nm_config_get_description (NMConfig *config)
+/* The NMConfigData instance is reloadable and will be swapped on reload.
+ * nm_config_get_data_orig() returns the original configuration, when the NMConfig
+ * instance was created. */
+NMConfigData *
+nm_config_get_data_orig (NMConfig *config)
{
g_return_val_if_fail (config != NULL, NULL);
- return NM_CONFIG_GET_PRIVATE (config)->config_description;
+ return NM_CONFIG_GET_PRIVATE (config)->config_data_orig;
}
const char **
@@ -189,47 +227,12 @@ nm_config_get_debug (NMConfig *config)
return NM_CONFIG_GET_PRIVATE (config)->debug;
}
-const char *
-nm_config_get_connectivity_uri (NMConfig *config)
-{
- g_return_val_if_fail (config != NULL, NULL);
-
- return NM_CONFIG_GET_PRIVATE (config)->connectivity_uri;
-}
-
-guint
-nm_config_get_connectivity_interval (NMConfig *config)
-{
- g_return_val_if_fail (config != NULL, 0);
-
- /* We store interval as signed internally to track whether it's
- * set or not, but report as unsigned to callers.
- */
- return MAX (NM_CONFIG_GET_PRIVATE (config)->connectivity_interval, 0);
-}
-
-const char *
-nm_config_get_connectivity_response (NMConfig *config)
-{
- g_return_val_if_fail (config != NULL, NULL);
-
- return NM_CONFIG_GET_PRIVATE (config)->connectivity_response;
-}
-
gboolean
nm_config_get_configure_and_quit (NMConfig *config)
{
return NM_CONFIG_GET_PRIVATE (config)->configure_and_quit;
}
-char *
-nm_config_get_value (NMConfig *config, const char *group, const char *key, GError **error)
-{
- NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (config);
-
- return g_key_file_get_string (priv->keyfile, group, key, error);
-}
-
gboolean
nm_config_get_ignore_carrier (NMConfig *config, NMDevice *device)
{
@@ -252,72 +255,71 @@ nm_config_get_ignore_carrier (NMConfig *config, NMDevice *device)
/************************************************************************/
-static void
-merge_no_auto_default_state (NMConfig *config)
+static char **
+no_auto_default_merge_from_file (const char *no_auto_default_file, const char *const* no_auto_default)
{
- NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (config);
GPtrArray *updated;
char **list;
int i, j;
char *data;
- /* If the config already matches everything, we don't need to do anything else. */
- if (priv->no_auto_default && !g_strcmp0 (priv->no_auto_default[0], "*"))
- return;
-
updated = g_ptr_array_new ();
- if (priv->no_auto_default) {
- for (i = 0; priv->no_auto_default[i]; i++)
- g_ptr_array_add (updated, priv->no_auto_default[i]);
- g_free (priv->no_auto_default);
+ if (no_auto_default) {
+ for (i = 0; no_auto_default[i]; i++)
+ g_ptr_array_add (updated, g_strdup (no_auto_default[i]));
}
- if (g_file_get_contents (priv->no_auto_default_file, &data, NULL, NULL)) {
+ if ( no_auto_default_file
+ && g_file_get_contents (no_auto_default_file, &data, NULL, NULL)) {
list = g_strsplit (data, "\n", -1);
for (i = 0; list[i]; i++) {
if (!*list[i])
- continue;
- for (j = 0; j < updated->len; j++) {
- if (!strcmp (list[i], updated->pdata[j]))
- break;
+ g_free (list[i]);
+ else {
+ for (j = 0; j < updated->len; j++) {
+ if (!strcmp (list[i], updated->pdata[j]))
+ break;
+ }
+ if (j == updated->len)
+ g_ptr_array_add (updated, list[i]);
+ else
+ g_free (list[i]);
}
- if (j == updated->len)
- g_ptr_array_add (updated, list[i]);
}
g_free (list);
g_free (data);
}
g_ptr_array_add (updated, NULL);
- priv->no_auto_default = (char **) g_ptr_array_free (updated, FALSE);
+ return (char **) g_ptr_array_free (updated, FALSE);
}
gboolean
-nm_config_get_ethernet_can_auto_default (NMConfig *config, NMDevice *device)
+nm_config_get_no_auto_default_for_device (NMConfig *self, NMDevice *device)
{
- NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (config);
- GSList *specs = NULL;
- int i;
- gboolean match;
-
- for (i = 0; priv->no_auto_default[i]; i++)
- specs = g_slist_prepend (specs, priv->no_auto_default[i]);
+ NMConfigData *config_data;
- match = nm_device_spec_match_list (device, specs);
+ g_return_val_if_fail (NM_IS_CONFIG (self), FALSE);
+ g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
- g_slist_free (specs);
- return !match;
+ config_data = NM_CONFIG_GET_PRIVATE (self)->config_data;
+ return nm_device_spec_match_list (device, nm_config_data_get_no_auto_default_list (config_data));
}
void
-nm_config_set_ethernet_no_auto_default (NMConfig *config, NMDevice *device)
+nm_config_set_no_auto_default_for_device (NMConfig *self, NMDevice *device)
{
- NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (config);
+ NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (self);
char *current;
GString *updated;
GError *error = NULL;
+ char **no_auto_default;
+ NMConfigData *new_data = NULL;
+
+ g_return_if_fail (NM_IS_CONFIG (self));
+ g_return_if_fail (NM_IS_DEVICE (device));
- if (!nm_config_get_ethernet_can_auto_default (config, device))
+ if (nm_config_get_no_auto_default_for_device (self, device))
return;
updated = g_string_new (NULL);
@@ -339,48 +341,111 @@ nm_config_set_ethernet_no_auto_default (NMConfig *config, NMDevice *device)
g_string_free (updated, TRUE);
- merge_no_auto_default_state (config);
+ no_auto_default = no_auto_default_merge_from_file (priv->no_auto_default_file, nm_config_data_get_no_auto_default (priv->config_data));
+ new_data = nm_config_data_new_update_no_auto_default (priv->config_data, (const char *const*) no_auto_default);
+ g_strfreev (no_auto_default);
+
+ _set_config_data (self, new_data);
}
/************************************************************************/
-static char *cli_config_path;
-static char *cli_config_dir;
-static char *cli_no_auto_default_file;
-static char *cli_plugins;
-static char *cli_connectivity_uri;
-static int cli_connectivity_interval = -1;
-static char *cli_connectivity_response;
-
-static GOptionEntry config_options[] = {
- { "config", 0, 0, G_OPTION_ARG_FILENAME, &cli_config_path, N_("Config file location"), N_("/path/to/config.file") },
- { "config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli_config_dir, N_("Config directory location"), N_("/path/to/config/dir") },
- { "no-auto-default", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME, &cli_no_auto_default_file, "no-auto-default.state location", NULL },
- { "plugins", 0, 0, G_OPTION_ARG_STRING, &cli_plugins, N_("List of plugins separated by ','"), N_("plugin1,plugin2") },
-
- /* These three are hidden for now, and should eventually just go away. */
- { "connectivity-uri", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli_connectivity_uri, N_("An http(s) address for checking internet connectivity"), "http://example.com" },
- { "connectivity-interval", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &cli_connectivity_interval, N_("The interval between connectivity checks (in seconds)"), "60" },
- { "connectivity-response", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli_connectivity_response, N_("The expected start of the response"), N_("Bingo!") },
- {NULL}
-};
-GOptionEntry *
-nm_config_get_options (void)
+static void
+_nm_config_cmd_line_options_clear (NMConfigCmdLineOptions *cli)
{
- return config_options;
+ g_clear_pointer (&cli->config_main_file, g_free);
+ g_clear_pointer (&cli->config_dir, g_free);
+ g_clear_pointer (&cli->no_auto_default_file, g_free);
+ g_clear_pointer (&cli->plugins, g_free);
+ g_clear_pointer (&cli->connectivity_uri, g_free);
+ g_clear_pointer (&cli->connectivity_response, g_free);
+ cli->connectivity_interval = -1;
+}
+
+static void
+_nm_config_cmd_line_options_copy (const NMConfigCmdLineOptions *cli, NMConfigCmdLineOptions *dst)
+{
+ g_return_if_fail (cli);
+ g_return_if_fail (dst);
+ g_return_if_fail (cli != dst);
+
+ _nm_config_cmd_line_options_clear (dst);
+ dst->config_dir = g_strdup (cli->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->plugins = g_strdup (cli->plugins);
+ dst->connectivity_uri = g_strdup (cli->connectivity_uri);
+ dst->connectivity_response = g_strdup (cli->connectivity_response);
+ dst->connectivity_interval = cli->connectivity_interval;
+}
+
+NMConfigCmdLineOptions *
+nm_config_cmd_line_options_new ()
+{
+ NMConfigCmdLineOptions *cli = g_new0 (NMConfigCmdLineOptions, 1);
+
+ _nm_config_cmd_line_options_clear (cli);
+ return cli;
+}
+
+void
+nm_config_cmd_line_options_free (NMConfigCmdLineOptions *cli)
+{
+ g_return_if_fail (cli);
+
+ _nm_config_cmd_line_options_clear (cli);
+ g_free (cli);
+}
+
+void
+nm_config_cmd_line_options_add_to_entries (NMConfigCmdLineOptions *cli,
+ GOptionContext *opt_ctx)
+{
+ g_return_if_fail (opt_ctx);
+ g_return_if_fail (cli);
+
+ {
+ GOptionEntry config_options[] = {
+ { "config", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_main_file, N_("Config file location"), N_("/path/to/config.file") },
+ { "config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_dir, N_("Config directory location"), N_("/path/to/config/dir") },
+ { "no-auto-default", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME, &cli->no_auto_default_file, "no-auto-default.state location", NULL },
+ { "plugins", 0, 0, G_OPTION_ARG_STRING, &cli->plugins, N_("List of plugins separated by ','"), N_("plugin1,plugin2") },
+
+ /* These three are hidden for now, and should eventually just go away. */
+ { "connectivity-uri", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_uri, N_("An http(s) address for checking internet connectivity"), "http://example.com" },
+ { "connectivity-interval", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &cli->connectivity_interval, N_("The interval between connectivity checks (in seconds)"), "60" },
+ { "connectivity-response", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_response, N_("The expected start of the response"), N_("Bingo!") },
+ { 0 },
+ };
+
+ g_option_context_add_main_entries (opt_ctx, config_options, NULL);
+ }
}
/************************************************************************/
+GKeyFile *
+nm_config_create_keyfile ()
+{
+ GKeyFile *keyfile;
+
+ keyfile = g_key_file_new ();
+ g_key_file_set_list_separator (keyfile, ',');
+ return keyfile;
+}
+
static gboolean
-read_config (NMConfig *config, const char *path, GError **error)
+read_config (GKeyFile *keyfile, const char *path, GError **error)
{
- NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (config);
GKeyFile *kf;
char **groups, **keys;
gsize ngroups, nkeys;
int g, k;
+ g_return_val_if_fail (keyfile, FALSE);
+ g_return_val_if_fail (path, FALSE);
+ g_return_val_if_fail (!error || !*error, FALSE);
+
if (g_file_test (path, G_FILE_TEST_EXISTS) == FALSE) {
g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND, "file %s not found", path);
return FALSE;
@@ -388,8 +453,7 @@ read_config (NMConfig *config, const char *path, GError **error)
nm_log_dbg (LOGD_SETTINGS, "Reading config file '%s'", path);
- kf = g_key_file_new ();
- g_key_file_set_list_separator (kf, ',');
+ kf = nm_config_create_keyfile ();
if (!g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, error)) {
g_key_file_free (kf);
return FALSE;
@@ -407,22 +471,22 @@ read_config (NMConfig *config, const char *path, GError **error)
if (keys[k][len - 1] == '+') {
char *base_key = g_strndup (keys[k], len - 1);
- const char *old_val = g_key_file_get_value (priv->keyfile, groups[g], base_key, NULL);
+ const char *old_val = g_key_file_get_value (keyfile, groups[g], base_key, NULL);
const char *new_val = g_key_file_get_value (kf, groups[g], keys[k], NULL);
if (old_val && *old_val) {
char *combined = g_strconcat (old_val, ",", new_val, NULL);
- g_key_file_set_value (priv->keyfile, groups[g], base_key, combined);
+ g_key_file_set_value (keyfile, groups[g], base_key, combined);
g_free (combined);
} else
- g_key_file_set_value (priv->keyfile, groups[g], base_key, new_val);
+ g_key_file_set_value (keyfile, groups[g], base_key, new_val);
g_free (base_key);
continue;
}
- g_key_file_set_value (priv->keyfile, groups[g], keys[k],
+ g_key_file_set_value (keyfile, groups[g], keys[k],
v = g_key_file_get_value (kf, groups[g], keys[k], NULL));
g_free (v);
}
@@ -435,16 +499,22 @@ read_config (NMConfig *config, const char *path, GError **error)
}
static gboolean
-find_base_config (NMConfig *config, GError **error)
+read_base_config (GKeyFile *keyfile,
+ const char *cli_config_main_file,
+ char **out_config_main_file,
+ GError **error)
{
- NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (config);
GError *my_error = NULL;
+ g_return_val_if_fail (keyfile, FALSE);
+ g_return_val_if_fail (out_config_main_file && !*out_config_main_file, FALSE);
+ g_return_val_if_fail (!error || !*error, FALSE);
+
/* Try a user-specified config file first */
- if (cli_config_path) {
+ if (cli_config_main_file) {
/* Bad user-specific config file path is a hard error */
- if (read_config (config, cli_config_path, error)) {
- priv->nm_conf_path = g_strdup (cli_config_path);
+ if (read_config (keyfile, cli_config_main_file, error)) {
+ *out_config_main_file = g_strdup (cli_config_main_file);
return TRUE;
} else
return FALSE;
@@ -458,8 +528,8 @@ find_base_config (NMConfig *config, GError **error)
*/
/* Try deprecated nm-system-settings.conf first */
- if (read_config (config, NM_OLD_SYSTEM_CONF_FILE, &my_error)) {
- priv->nm_conf_path = g_strdup (NM_OLD_SYSTEM_CONF_FILE);
+ if (read_config (keyfile, NM_OLD_SYSTEM_CONF_FILE, &my_error)) {
+ *out_config_main_file = g_strdup (NM_OLD_SYSTEM_CONF_FILE);
return TRUE;
}
@@ -471,8 +541,8 @@ find_base_config (NMConfig *config, GError **error)
g_clear_error (&my_error);
/* Try the standard config file location next */
- if (read_config (config, NM_DEFAULT_SYSTEM_CONF_FILE, &my_error)) {
- priv->nm_conf_path = g_strdup (NM_DEFAULT_SYSTEM_CONF_FILE);
+ if (read_config (keyfile, NM_DEFAULT_SYSTEM_CONF_FILE, &my_error)) {
+ *out_config_main_file = g_strdup (NM_DEFAULT_SYSTEM_CONF_FILE);
return TRUE;
}
@@ -488,21 +558,12 @@ find_base_config (NMConfig *config, GError **error)
/* If for some reason no config file exists, use the default
* config file path.
*/
- priv->nm_conf_path = g_strdup (NM_DEFAULT_SYSTEM_CONF_FILE);
+ *out_config_main_file = g_strdup (NM_DEFAULT_SYSTEM_CONF_FILE);
nm_log_info (LOGD_CORE, "No config file found or given; using %s\n",
NM_DEFAULT_SYSTEM_CONF_FILE);
return TRUE;
}
-/************************************************************************/
-
-NMConfig *
-nm_config_get (void)
-{
- g_assert (singleton);
- return singleton;
-}
-
static int
sort_asciibetically (gconstpointer a, gconstpointer b)
{
@@ -512,45 +573,31 @@ sort_asciibetically (gconstpointer a, gconstpointer b)
return strcmp (s1, s2);
}
-/* call this function only once! */
-NMConfig *
-nm_config_new (GError **error)
+static GPtrArray *
+_get_config_dir_files (const char *config_main_file,
+ const char *config_dir,
+ char **out_config_description)
{
- NMConfigPrivate *priv = NULL;
GFile *dir;
GFileEnumerator *direnum;
GFileInfo *info;
GPtrArray *confs;
- const char *name;
- int i;
GString *config_description;
+ const char *name;
- g_assert (!singleton);
- singleton = NM_CONFIG (g_object_new (NM_TYPE_CONFIG, NULL));
- priv = NM_CONFIG_GET_PRIVATE (singleton);
-
- /* First read the base config file */
- if (!find_base_config (singleton, error)) {
- g_object_unref (singleton);
- singleton = NULL;
- return NULL;
- }
-
- /* Now read the overrides in the config dir */
- if (cli_config_dir)
- priv->config_dir = g_strdup (cli_config_dir);
- else
- priv->config_dir = g_strdup (NM_DEFAULT_SYSTEM_CONF_DIR);
+ g_return_val_if_fail (config_main_file, NULL);
+ g_return_val_if_fail (config_dir, NULL);
+ g_return_val_if_fail (out_config_description && !*out_config_description, NULL);
confs = g_ptr_array_new_with_free_func (g_free);
- config_description = g_string_new (priv->nm_conf_path);
- dir = g_file_new_for_path (priv->config_dir);
+ config_description = g_string_new (config_main_file);
+ dir = g_file_new_for_path (config_dir);
direnum = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, NULL);
if (direnum) {
while ((info = g_file_enumerator_next_file (direnum, NULL, NULL))) {
name = g_file_info_get_name (info);
if (g_str_has_suffix (name, ".conf")) {
- g_ptr_array_add (confs, g_build_filename (priv->config_dir, name, NULL));
+ g_ptr_array_add (confs, g_build_filename (config_dir, name, NULL));
if (confs->len == 1)
g_string_append (config_description, " and conf.d: ");
else
@@ -564,62 +611,273 @@ nm_config_new (GError **error)
g_object_unref (dir);
g_ptr_array_sort (confs, sort_asciibetically);
- priv->config_description = g_string_free (config_description, FALSE);
+
+ *out_config_description = g_string_free (config_description, FALSE);
+ return confs;
+}
+
+static GKeyFile *
+read_entire_config (const NMConfigCmdLineOptions *cli,
+ const char *config_dir,
+ char **out_config_main_file,
+ char **out_config_description,
+ GError **error)
+{
+ GKeyFile *keyfile = nm_config_create_keyfile ();
+ GPtrArray *confs;
+ guint i;
+ char *o_config_main_file = NULL;
+ char *o_config_description = NULL;
+ char **plugins_tmp;
+
+ g_return_val_if_fail (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 (!error || !*error, FALSE);
+
+ /* First read the base config file */
+ if ( cli
+ && !read_base_config (keyfile, cli->config_main_file, &o_config_main_file, error)) {
+ g_key_file_free (keyfile);
+ return NULL;
+ }
+
+ g_assert (o_config_main_file);
+
+ confs = _get_config_dir_files (o_config_main_file, config_dir, &o_config_description);
for (i = 0; i < confs->len; i++) {
- if (!read_config (singleton, confs->pdata[i], error)) {
- g_object_unref (singleton);
- singleton = NULL;
- break;
+ if (!read_config (keyfile, confs->pdata[i], error)) {
+ g_key_file_free (keyfile);
+ g_free (o_config_main_file);
+ g_free (o_config_description);
+ g_ptr_array_unref (confs);
+ return NULL;
}
}
g_ptr_array_unref (confs);
- if (!singleton)
+
+ /* Merge settings from command line. They overwrite everything read from
+ * config files. */
+
+ if (cli && cli->plugins && cli->plugins[0])
+ g_key_file_set_value (keyfile, "main", "plugins", cli->plugins);
+ plugins_tmp = g_key_file_get_string_list (keyfile, "main", "plugins", NULL, NULL);
+ if (!plugins_tmp) {
+ if (STRLEN (CONFIG_PLUGINS_DEFAULT) > 0)
+ g_key_file_set_value (keyfile, "main", "plugins", CONFIG_PLUGINS_DEFAULT);
+ } else
+ g_strfreev (plugins_tmp);
+
+ if (cli && cli->connectivity_uri && cli->connectivity_uri[0])
+ g_key_file_set_value (keyfile, "connectivity", "uri", cli->connectivity_uri);
+ if (cli && cli->connectivity_interval >= 0)
+ g_key_file_set_integer (keyfile, "connectivity", "interval", cli->connectivity_interval);
+ if (cli && cli->connectivity_response && cli->connectivity_response[0])
+ g_key_file_set_value (keyfile, "connectivity", "response", cli->connectivity_response);
+
+ *out_config_main_file = o_config_main_file;
+ *out_config_description = o_config_description;
+ return keyfile;
+}
+
+/************************************************************************/
+
+void
+nm_config_reload (NMConfig *self)
+{
+ NMConfigPrivate *priv;
+ GError *error = NULL;
+ GKeyFile *keyfile;
+ NMConfigData *new_data = NULL;
+ char *config_main_file = NULL;
+ char *config_description = NULL;
+
+ g_return_if_fail (NM_IS_CONFIG (self));
+
+ priv = NM_CONFIG_GET_PRIVATE (self);
+
+ /* pass on the original command line options. This means, that
+ * options specified at command line cannot ever be reloaded from
+ * file. That seems desirable.
+ */
+ keyfile = read_entire_config (&priv->cli,
+ priv->config_dir,
+ &config_main_file,
+ &config_description,
+ &error);
+ if (!keyfile) {
+ nm_log_err (LOGD_CORE, "Failed to reload the configuration: %s", error->message);
+ g_clear_error (&error);
+ return;
+ }
+ new_data = nm_config_data_new (config_main_file, config_description, nm_config_data_get_no_auto_default (priv->config_data), keyfile);
+ g_free (config_main_file);
+ g_free (config_description);
+ g_key_file_unref (keyfile);
+
+ _set_config_data (self, new_data);
+}
+
+static const char *
+_change_flags_one_to_string (NMConfigChangeFlags flag)
+{
+ switch (flag) {
+ case NM_CONFIG_CHANGE_CONFIG_FILES:
+ return "config-files";
+ case NM_CONFIG_CHANGE_VALUES:
+ return "values";
+ case NM_CONFIG_CHANGE_CONNECTIVITY:
+ return "connectivity";
+ case NM_CONFIG_CHANGE_NO_AUTO_DEFAULT:
+ return "no-auto-default";
+ default:
+ g_return_val_if_reached ("unknown");
+ }
+}
+
+char *
+nm_config_change_flags_to_string (NMConfigChangeFlags flags)
+{
+ GString *str = g_string_new ("");
+ NMConfigChangeFlags s = 0x01;
+
+ while (flags) {
+ if (NM_FLAGS_HAS (flags, s)) {
+ if (str->len)
+ g_string_append_c (str, ',');
+ g_string_append (str, _change_flags_one_to_string (s));
+ }
+ flags = flags & ~s;
+ s <<= 1;
+ }
+ return g_string_free (str, FALSE);
+}
+
+static void
+_set_config_data (NMConfig *self, NMConfigData *new_data)
+{
+ NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (self);
+ NMConfigData *old_data = priv->config_data;
+ NMConfigChangeFlags changes;
+ gs_free char *log_str = NULL;
+
+ changes = nm_config_data_diff (old_data, new_data);
+ if (changes == NM_CONFIG_CHANGE_NONE) {
+ g_object_unref (new_data);
+ return;
+ }
+
+ nm_log_info (LOGD_CORE, "config: update %s (%s)", nm_config_data_get_config_description (new_data),
+ (log_str = nm_config_change_flags_to_string (changes)));
+ priv->config_data = new_data;
+ g_signal_emit (self, signals[SIGNAL_CONFIG_CHANGED], 0, new_data, changes, old_data);
+ g_object_unref (old_data);
+}
+
+NM_DEFINE_SINGLETON_DESTRUCTOR (NMConfig);
+NM_DEFINE_SINGLETON_WEAK_REF (NMConfig);
+
+NMConfig *
+nm_config_get (void)
+{
+ g_assert (singleton_instance);
+ return singleton_instance;
+}
+
+NMConfig *
+nm_config_setup (const NMConfigCmdLineOptions *cli, GError **error)
+{
+ g_assert (!singleton_instance);
+
+ singleton_instance = nm_config_new (cli, error);
+ if (singleton_instance)
+ nm_singleton_instance_weak_ref_register ();
+ return singleton_instance;
+}
+
+static gboolean
+init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
+{
+ NMConfig *self = NM_CONFIG (initable);
+ NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (self);
+ GKeyFile *keyfile;
+ char *config_main_file = NULL;
+ char *config_description = NULL;
+ char **no_auto_default;
+ char **no_auto_default_orig;
+
+ if (priv->config_dir) {
+ /* Object is already initialized. */
+ if (priv->config_data)
+ return TRUE;
+ g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND, "unspecified error");
return FALSE;
+ }
- /* Handle no-auto-default key and state file */
- priv->no_auto_default = g_key_file_get_string_list (priv->keyfile, "main", "no-auto-default", NULL, NULL);
- if (cli_no_auto_default_file)
- priv->no_auto_default_file = g_strdup (cli_no_auto_default_file);
+ if (priv->cli.config_dir)
+ priv->config_dir = g_strdup (priv->cli.config_dir);
+ else
+ priv->config_dir = g_strdup (NM_DEFAULT_SYSTEM_CONF_DIR);
+
+ keyfile = read_entire_config (&priv->cli,
+ priv->config_dir,
+ &config_main_file,
+ &config_description,
+ error);
+ if (!keyfile)
+ return FALSE;
+
+ /* Initialize read only private members */
+
+ if (priv->cli.no_auto_default_file)
+ priv->no_auto_default_file = g_strdup (priv->cli.no_auto_default_file);
else
priv->no_auto_default_file = g_strdup (NM_NO_AUTO_DEFAULT_STATE_FILE);
- merge_no_auto_default_state (singleton);
- /* Now let command-line options override the config files, and fill in priv. */
- if (cli_plugins && cli_plugins[0])
- g_key_file_set_value (priv->keyfile, "main", "plugins", cli_plugins);
- priv->plugins = g_key_file_get_string_list (priv->keyfile, "main", "plugins", NULL, NULL);
- if (!priv->plugins && STRLEN (CONFIG_PLUGINS_DEFAULT) > 0)
- priv->plugins = g_strsplit (CONFIG_PLUGINS_DEFAULT, ",", -1);
+ priv->plugins = g_key_file_get_string_list (keyfile, "main", "plugins", NULL, NULL);
+ if (!priv->plugins)
+ priv->plugins = g_new0 (char *, 1);
+
+ priv->monitor_connection_files = _get_bool_value (keyfile, "main", "monitor-connection-files", FALSE);
- priv->monitor_connection_files = _get_bool_value (priv->keyfile, "main", "monitor-connection-files", FALSE);
+ priv->auth_polkit = _get_bool_value (keyfile, "main", "auth-polkit", NM_CONFIG_DEFAULT_AUTH_POLKIT);
- priv->auth_polkit = _get_bool_value (priv->keyfile, "main", "auth-polkit", NM_CONFIG_DEFAULT_AUTH_POLKIT);
+ priv->dhcp_client = g_key_file_get_value (keyfile, "main", "dhcp", NULL);
+ priv->dns_mode = g_key_file_get_value (keyfile, "main", "dns", NULL);
- priv->dhcp_client = g_key_file_get_value (priv->keyfile, "main", "dhcp", NULL);
- priv->dns_mode = g_key_file_get_value (priv->keyfile, "main", "dns", NULL);
+ priv->log_level = g_key_file_get_value (keyfile, "logging", "level", NULL);
+ priv->log_domains = g_key_file_get_value (keyfile, "logging", "domains", NULL);
- priv->log_level = g_key_file_get_value (priv->keyfile, "logging", "level", NULL);
- priv->log_domains = g_key_file_get_value (priv->keyfile, "logging", "domains", NULL);
+ priv->debug = g_key_file_get_value (keyfile, "main", "debug", NULL);
- priv->debug = g_key_file_get_value (priv->keyfile, "main", "debug", NULL);
+ priv->ignore_carrier = g_key_file_get_string_list (keyfile, "main", "ignore-carrier", NULL, NULL);
- if (cli_connectivity_uri && cli_connectivity_uri[0])
- g_key_file_set_value (priv->keyfile, "connectivity", "uri", cli_connectivity_uri);
- priv->connectivity_uri = g_key_file_get_value (priv->keyfile, "connectivity", "uri", NULL);
+ priv->configure_and_quit = _get_bool_value (keyfile, "main", "configure-and-quit", FALSE);
- if (cli_connectivity_interval >= 0)
- g_key_file_set_integer (priv->keyfile, "connectivity", "interval", cli_connectivity_interval);
- priv->connectivity_interval = g_key_file_get_integer (priv->keyfile, "connectivity", "interval", NULL);
+ no_auto_default_orig = g_key_file_get_string_list (keyfile, "main", "no-auto-default", NULL, NULL);
+ no_auto_default = no_auto_default_merge_from_file (priv->no_auto_default_file, (const char *const *) no_auto_default_orig);
- if (cli_connectivity_response && cli_connectivity_response[0])
- g_key_file_set_value (priv->keyfile, "connectivity", "response", cli_connectivity_response);
- priv->connectivity_response = g_key_file_get_value (priv->keyfile, "connectivity", "response", NULL);
+ priv->config_data_orig = nm_config_data_new (config_main_file, config_description, (const char *const*) no_auto_default, keyfile);
- priv->ignore_carrier = g_key_file_get_string_list (priv->keyfile, "main", "ignore-carrier", NULL, NULL);
+ g_strfreev (no_auto_default);
+ g_strfreev (no_auto_default_orig);
- priv->configure_and_quit = _get_bool_value (priv->keyfile, "main", "configure-and-quit", FALSE);
+ priv->config_data = g_object_ref (priv->config_data_orig);
- return singleton;
+ g_free (config_main_file);
+ g_free (config_description);
+ g_key_file_unref (keyfile);
+ return TRUE;
+}
+
+NMConfig *
+nm_config_new (const NMConfigCmdLineOptions *cli, GError **error)
+{
+ return NM_CONFIG (g_initable_new (NM_TYPE_CONFIG,
+ NULL,
+ error,
+ NM_CONFIG_CMD_LINE_OPTIONS, cli,
+ NULL));
}
static void
@@ -628,11 +886,6 @@ nm_config_init (NMConfig *config)
NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (config);
priv->auth_polkit = NM_CONFIG_DEFAULT_AUTH_POLKIT;
-
- priv->keyfile = g_key_file_new ();
- g_key_file_set_list_separator (priv->keyfile, ',');
-
- priv->connectivity_interval = -1;
}
static void
@@ -640,34 +893,46 @@ finalize (GObject *gobject)
{
NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (gobject);
- g_free (priv->nm_conf_path);
g_free (priv->config_dir);
- g_free (priv->config_description);
g_free (priv->no_auto_default_file);
- g_clear_pointer (&priv->keyfile, g_key_file_unref);
g_strfreev (priv->plugins);
g_free (priv->dhcp_client);
g_free (priv->dns_mode);
g_free (priv->log_level);
g_free (priv->log_domains);
g_free (priv->debug);
- g_free (priv->connectivity_uri);
- g_free (priv->connectivity_response);
- g_strfreev (priv->no_auto_default);
g_strfreev (priv->ignore_carrier);
- singleton = NULL;
+ _nm_config_cmd_line_options_clear (&priv->cli);
- g_clear_pointer (&cli_config_path, g_free);
- g_clear_pointer (&cli_config_dir, g_free);
- g_clear_pointer (&cli_no_auto_default_file, g_free);
- g_clear_pointer (&cli_plugins, g_free);
- g_clear_pointer (&cli_connectivity_uri, g_free);
- g_clear_pointer (&cli_connectivity_response, g_free);
+ g_clear_object (&priv->config_data);
+ g_clear_object (&priv->config_data_orig);
G_OBJECT_CLASS (nm_config_parent_class)->finalize (gobject);
}
+static void
+set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ NMConfig *self = NM_CONFIG (object);
+ NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (self);
+ NMConfigCmdLineOptions *cli;
+
+ switch (prop_id) {
+ case PROP_CMD_LINE_OPTIONS:
+ /* construct only */
+ cli = g_value_get_pointer (value);
+ if (!cli)
+ _nm_config_cmd_line_options_clear (&priv->cli);
+ else
+ _nm_config_cmd_line_options_copy (cli, &priv->cli);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
static void
nm_config_class_init (NMConfigClass *config_class)
@@ -676,5 +941,27 @@ nm_config_class_init (NMConfigClass *config_class)
g_type_class_add_private (config_class, sizeof (NMConfigPrivate));
object_class->finalize = finalize;
+ object_class->set_property = set_property;
+
+ g_object_class_install_property
+ (object_class, PROP_CMD_LINE_OPTIONS,
+ g_param_spec_pointer (NM_CONFIG_CMD_LINE_OPTIONS, "", "",
+ 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),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (NMConfigClass, config_changed),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 3, NM_TYPE_CONFIG_DATA, NM_TYPE_CONFIG_CHANGE_FLAGS, NM_TYPE_CONFIG_DATA);
+}
+
+static void
+nm_config_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = init_sync;
}
diff --git a/src/nm-config.h b/src/nm-config.h
index 56f75fb5f6..530cbade98 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -26,6 +26,7 @@
#include <glib-object.h>
#include "nm-types.h"
+#include "nm-config-data.h"
G_BEGIN_DECLS
@@ -36,20 +37,33 @@ G_BEGIN_DECLS
#define NM_IS_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_CONFIG))
#define NM_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CONFIG, NMConfigClass))
-typedef struct {
+/* Properties */
+#define NM_CONFIG_CMD_LINE_OPTIONS "cmd-line-options"
+
+/* Signals */
+#define NM_CONFIG_SIGNAL_CONFIG_CHANGED "config-changed"
+
+typedef struct NMConfigCmdLineOptions NMConfigCmdLineOptions;
+
+struct _NMConfig {
GObject parent;
-} NMConfig;
+};
typedef struct {
GObjectClass parent;
+
+ /* Signals */
+ void (*config_changed) (NMConfig *config, GHashTable *changes, NMConfigData *old_data);
} NMConfigClass;
GType nm_config_get_type (void);
NMConfig *nm_config_get (void);
-const char *nm_config_get_path (NMConfig *config);
-const char *nm_config_get_description (NMConfig *config);
+char *nm_config_change_flags_to_string (NMConfigChangeFlags flags);
+
+NMConfigData *nm_config_get_data (NMConfig *config);
+NMConfigData *nm_config_get_data_orig (NMConfig *config);
const char **nm_config_get_plugins (NMConfig *config);
gboolean nm_config_get_monitor_connection_files (NMConfig *config);
gboolean nm_config_get_auth_polkit (NMConfig *config);
@@ -58,21 +72,24 @@ const char *nm_config_get_dns_mode (NMConfig *config);
const char *nm_config_get_log_level (NMConfig *config);
const char *nm_config_get_log_domains (NMConfig *config);
const char *nm_config_get_debug (NMConfig *config);
-const char *nm_config_get_connectivity_uri (NMConfig *config);
-guint nm_config_get_connectivity_interval (NMConfig *config);
-const char *nm_config_get_connectivity_response (NMConfig *config);
gboolean nm_config_get_configure_and_quit (NMConfig *config);
-gboolean nm_config_get_ethernet_can_auto_default (NMConfig *config, NMDevice *device);
-void nm_config_set_ethernet_no_auto_default (NMConfig *config, NMDevice *device);
-
gboolean nm_config_get_ignore_carrier (NMConfig *config, NMDevice *device);
-char *nm_config_get_value (NMConfig *config, const char *group, const char *key, GError **error);
-
/* for main.c only */
-GOptionEntry *nm_config_get_options (void);
-NMConfig *nm_config_new (GError **error);
+NMConfigCmdLineOptions *nm_config_cmd_line_options_new (void);
+void nm_config_cmd_line_options_free (NMConfigCmdLineOptions *cli);
+void nm_config_cmd_line_options_add_to_entries (NMConfigCmdLineOptions *cli,
+ GOptionContext *opt_ctx);
+
+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);
+void nm_config_reload (NMConfig *config);
+
+GKeyFile *nm_config_create_keyfile (void);
G_END_DECLS
diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c
index d21626735f..804e3935fe 100644
--- a/src/nm-connectivity.c
+++ b/src/nm-connectivity.c
@@ -28,7 +28,6 @@
#include "nm-connectivity.h"
#include "nm-logging.h"
-#include "nm-config.h"
G_DEFINE_TYPE (NMConnectivity, nm_connectivity, G_TYPE_OBJECT)
@@ -37,14 +36,32 @@ G_DEFINE_TYPE (NMConnectivity, nm_connectivity, G_TYPE_OBJECT)
#define DEFAULT_RESPONSE "NetworkManager is online" /* NOT LOCALIZED */
+#define _LOG_DEFAULT_DOMAIN LOGD_CONCHECK
+
+#define _LOG(level, domain, ...) \
+ G_STMT_START { \
+ nm_log ((level), (domain), \
+ "%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+ "connectivity: " \
+ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+ } G_STMT_END
+
+#define _LOGT(...) _LOG (LOGL_TRACE, _LOG_DEFAULT_DOMAIN, __VA_ARGS__)
+#define _LOGD(...) _LOG (LOGL_DEBUG, _LOG_DEFAULT_DOMAIN, __VA_ARGS__)
+#define _LOGI(...) _LOG (LOGL_INFO, _LOG_DEFAULT_DOMAIN, __VA_ARGS__)
+#define _LOGW(...) _LOG (LOGL_WARN, _LOG_DEFAULT_DOMAIN, __VA_ARGS__)
+#define _LOGE(...) _LOG (LOGL_ERR, _LOG_DEFAULT_DOMAIN, __VA_ARGS__)
+
+
typedef struct {
char *uri;
char *response;
guint interval;
+ gboolean online; /* whether periodic connectivity checking is enabled. */
#if WITH_CONCHECK
SoupSession *soup_session;
- guint pending_checks;
+ gboolean initial_check_obsoleted;
guint check_id;
#endif
@@ -69,8 +86,8 @@ nm_connectivity_get_state (NMConnectivity *connectivity)
return NM_CONNECTIVITY_GET_PRIVATE (connectivity)->state;
}
-static const char *
-state_name (NMConnectivityState state)
+const char *
+nm_connectivity_state_to_string (NMConnectivityState state)
{
switch (state) {
case NM_CONNECTIVITY_UNKNOWN:
@@ -84,7 +101,7 @@ state_name (NMConnectivityState state)
case NM_CONNECTIVITY_FULL:
return "FULL";
default:
- return "???";
+ g_return_val_if_reached ("???");
}
}
@@ -94,31 +111,41 @@ update_state (NMConnectivity *self, NMConnectivityState state)
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
if (priv->state != state) {
- nm_log_dbg (LOGD_CONCHECK, "Connectivity state changed from %s to %s",
- state_name (priv->state), state_name (state));
+ _LOGD ("state changed from %s to %s",
+ nm_connectivity_state_to_string (priv->state),
+ nm_connectivity_state_to_string (state));
priv->state = state;
g_object_notify (G_OBJECT (self), NM_CONNECTIVITY_STATE);
}
}
#if WITH_CONCHECK
+typedef struct {
+ GSimpleAsyncResult *simple;
+ char *uri;
+ char *response;
+ guint check_id_when_scheduled;
+} ConCheckCbData;
+
static void
nm_connectivity_check_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
{
- GSimpleAsyncResult *simple = user_data;
NMConnectivity *self;
NMConnectivityPrivate *priv;
+ ConCheckCbData *cb_data = user_data;
+ GSimpleAsyncResult *simple = cb_data->simple;
NMConnectivityState new_state;
const char *nm_header;
+ const char *uri = cb_data->uri;
+ const char *response = cb_data->response ? cb_data->response : DEFAULT_RESPONSE;
self = NM_CONNECTIVITY (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
+ /* it is safe to unref @self here, @simple holds yet another reference. */
g_object_unref (self);
priv = NM_CONNECTIVITY_GET_PRIVATE (self);
- priv->pending_checks--;
if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
- nm_log_info (LOGD_CONCHECK, "Connectivity check for uri '%s' failed with '%s'.",
- priv->uri, msg->reason_phrase);
+ _LOGI ("check for uri '%s' failed with '%s'", uri, msg->reason_phrase);
new_state = NM_CONNECTIVITY_LIMITED;
goto done;
}
@@ -126,32 +153,47 @@ nm_connectivity_check_cb (SoupSession *session, SoupMessage *msg, gpointer user_
/* Check headers; if we find the NM-specific one we're done */
nm_header = soup_message_headers_get_one (msg->response_headers, "X-NetworkManager-Status");
if (g_strcmp0 (nm_header, "online") == 0) {
- nm_log_dbg (LOGD_CONCHECK, "Connectivity check for uri '%s' with Status header successful.", priv->uri);
+ _LOGD ("check for uri '%s' with Status header successful.", uri);
new_state = NM_CONNECTIVITY_FULL;
} else if (msg->status_code == SOUP_STATUS_OK) {
/* check response */
- if (msg->response_body->data && (g_str_has_prefix (msg->response_body->data, priv->response))) {
- nm_log_dbg (LOGD_CONCHECK, "Connectivity check for uri '%s' successful.",
- priv->uri);
+ if (msg->response_body->data && g_str_has_prefix (msg->response_body->data, response)) {
+ _LOGD ("check for uri '%s' successful.", uri);
new_state = NM_CONNECTIVITY_FULL;
} else {
- nm_log_info (LOGD_CONCHECK, "Connectivity check for uri '%s' did not match expected response '%s'; assuming captive portal.",
- priv->uri, priv->response);
+ _LOGI ("check for uri '%s' did not match expected response '%s'; assuming captive portal.",
+ uri, response);
new_state = NM_CONNECTIVITY_PORTAL;
}
} else {
- nm_log_info (LOGD_CONCHECK, "Connectivity check for uri '%s' returned status '%d %s'; assuming captive portal.",
- priv->uri, msg->status_code, msg->reason_phrase);
+ _LOGI ("check for uri '%s' returned status '%d %s'; assuming captive portal.",
+ uri, msg->status_code, msg->reason_phrase);
new_state = NM_CONNECTIVITY_PORTAL;
}
done:
- update_state (self, new_state);
+ /* Only update the state, if the call was done from external, or if the periodic check
+ * is still the one that called this async check. */
+ if (!cb_data->check_id_when_scheduled || cb_data->check_id_when_scheduled == priv->check_id) {
+ /* Only update the state, if the URI and response parameters did not change
+ * since invocation.
+ * The interval does not matter for exernal calls, and for internal calls
+ * we don't reach this line if the interval changed. */
+ if ( !g_strcmp0 (cb_data->uri, priv->uri)
+ && !g_strcmp0 (cb_data->response, priv->response))
+ update_state (self, new_state);
+ }
g_simple_async_result_set_op_res_gssize (simple, new_state);
g_simple_async_result_complete (simple);
+
+ g_free (cb_data->uri);
+ g_free (cb_data->response);
+ g_slice_free (ConCheckCbData, cb_data);
}
+#define IS_PERIODIC_CHECK(callback) (callback == run_check_complete)
+
static void
run_check_complete (GObject *object,
GAsyncResult *result,
@@ -162,7 +204,7 @@ run_check_complete (GObject *object,
nm_connectivity_check_finish (self, result, &error);
if (error) {
- nm_log_err (LOGD_CONCHECK, "Connectivity check failed: %s", error->message);
+ _LOGE ("check failed: %s", error->message);
g_error_free (error);
}
}
@@ -183,39 +225,54 @@ idle_start_periodic_checks (gpointer user_data)
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
priv->check_id = g_timeout_add_seconds (priv->interval, run_check, self);
- if (!priv->pending_checks)
+ if (!priv->initial_check_obsoleted)
run_check (self);
return FALSE;
}
#endif
-void
-nm_connectivity_set_online (NMConnectivity *self,
- gboolean online)
+static void
+_reschedule_periodic_checks (NMConnectivity *self, gboolean force_reschedule)
{
-#if WITH_CONCHECK
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
-#endif
-
- nm_log_dbg (LOGD_CONCHECK, "nm_connectivity_set_online(%s)", online ? "TRUE" : "FALSE");
#if WITH_CONCHECK
- if (online && priv->uri && priv->interval) {
- if (!priv->check_id)
+ if (priv->online && priv->uri && priv->interval) {
+ if (force_reschedule || !priv->check_id) {
+ if (priv->check_id)
+ g_source_remove (priv->check_id);
priv->check_id = g_timeout_add (0, idle_start_periodic_checks, self);
-
- return;
- } else if (priv->check_id) {
- g_source_remove (priv->check_id);
- priv->check_id = 0;
+ priv->initial_check_obsoleted = FALSE;
+ }
+ } else {
+ if (priv->check_id) {
+ g_source_remove (priv->check_id);
+ priv->check_id = 0;
+ }
}
+ if (priv->check_id)
+ return;
#endif
/* Either @online is %TRUE but we aren't checking connectivity, or
* @online is %FALSE. Either way we can update our status immediately.
*/
- update_state (self, online ? NM_CONNECTIVITY_FULL : NM_CONNECTIVITY_NONE);
+ update_state (self, priv->online ? NM_CONNECTIVITY_FULL : NM_CONNECTIVITY_NONE);
+}
+
+void
+nm_connectivity_set_online (NMConnectivity *self,
+ gboolean online)
+{
+ NMConnectivityPrivate *priv= NM_CONNECTIVITY_GET_PRIVATE (self);
+
+ online = !!online;
+ if (priv->online != online) {
+ _LOGD ("set %s", online ? "online" : "offline");
+ priv->online = online;
+ _reschedule_periodic_checks (self, FALSE);
+ }
}
void
@@ -224,36 +281,42 @@ nm_connectivity_check_async (NMConnectivity *self,
gpointer user_data)
{
NMConnectivityPrivate *priv;
-#if WITH_CONCHECK
- SoupMessage *msg;
-#endif
GSimpleAsyncResult *simple;
g_return_if_fail (NM_IS_CONNECTIVITY (self));
priv = NM_CONNECTIVITY_GET_PRIVATE (self);
-#if WITH_CONCHECK
- if (callback == run_check_complete)
- nm_log_dbg (LOGD_CONCHECK, "Periodic connectivity check started with uri '%s'.", priv->uri);
- else
-#endif
- nm_log_dbg (LOGD_CONCHECK, "Connectivity check started with uri '%s'.", priv->uri);
-
simple = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
nm_connectivity_check_async);
#if WITH_CONCHECK
if (priv->uri && priv->interval) {
+ SoupMessage *msg;
+ ConCheckCbData *cb_data = g_slice_new (ConCheckCbData);
+
msg = soup_message_new ("GET", priv->uri);
soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
+ cb_data->simple = simple;
+ cb_data->uri = g_strdup (priv->uri);
+ cb_data->response = g_strdup (priv->response);
+
+ /* For internal calls (periodic), remember the check-id at time of scheduling. */
+ cb_data->check_id_when_scheduled = IS_PERIODIC_CHECK (callback) ? priv->check_id : 0;
+
soup_session_queue_message (priv->soup_session,
msg,
nm_connectivity_check_cb,
- simple);
- priv->pending_checks++;
+ cb_data);
+ priv->initial_check_obsoleted = TRUE;
+ _LOGD ("check: send %srequest to '%s'", IS_PERIODIC_CHECK (callback) ? "periodic " : "", priv->uri);
return;
+ } else {
+ g_warn_if_fail (!IS_PERIODIC_CHECK (callback));
+ _LOGD ("check: faking request. Connectivity check disabled");
}
+#else
+ _LOGD ("check: faking request. Compiled without connectivity-check support");
#endif
g_simple_async_result_set_op_res_gssize (simple, priv->state);
@@ -275,38 +338,18 @@ nm_connectivity_check_finish (NMConnectivity *self,
return (NMConnectivityState) g_simple_async_result_get_op_res_gssize (simple);
}
+/**************************************************************************/
NMConnectivity *
-nm_connectivity_new (void)
+nm_connectivity_new (const char *uri,
+ guint interval,
+ const char *response)
{
- NMConnectivity *self;
- NMConfig *config;
- const char *check_response;
-
- config = nm_config_get ();
- check_response = nm_config_get_connectivity_response (config);
-
- self = g_object_new (NM_TYPE_CONNECTIVITY,
- NM_CONNECTIVITY_URI, nm_config_get_connectivity_uri (config),
- NM_CONNECTIVITY_INTERVAL, nm_config_get_connectivity_interval (config),
- NM_CONNECTIVITY_RESPONSE, check_response ? check_response : DEFAULT_RESPONSE,
+ return g_object_new (NM_TYPE_CONNECTIVITY,
+ NM_CONNECTIVITY_URI, uri,
+ NM_CONNECTIVITY_INTERVAL, interval,
+ NM_CONNECTIVITY_RESPONSE, response,
NULL);
- g_return_val_if_fail (self != NULL, NULL);
- update_state (self, NM_CONNECTIVITY_NONE);
-
- return self;
-}
-
-static char *
-get_non_empty_string_value (const GValue *val)
-{
- const char *s;
-
- s = g_value_get_string (val);
- if (s && s[0])
- return g_strdup (s);
- else
- return NULL;
}
static void
@@ -315,32 +358,48 @@ set_property (GObject *object, guint property_id,
{
NMConnectivity *self = NM_CONNECTIVITY (object);
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+ const char *uri, *response;
+ guint interval;
switch (property_id) {
case PROP_URI:
- g_free (priv->uri);
- priv->uri = get_non_empty_string_value (value);
-
+ uri = g_value_get_string (value);
+ if (uri && !*uri)
+ uri = NULL;
#if WITH_CONCHECK
- if (priv->uri) {
- SoupURI *uri = soup_uri_new (priv->uri);
+ if (uri) {
+ SoupURI *soup_uri = soup_uri_new (uri);
- if (!uri || !SOUP_URI_VALID_FOR_HTTP (uri)) {
- nm_log_err (LOGD_CONCHECK, "Invalid uri '%s' for connectivity check.", priv->uri);
- g_free (priv->uri);
- priv->uri = NULL;
+ if (!soup_uri || !SOUP_URI_VALID_FOR_HTTP (soup_uri)) {
+ _LOGE ("invalid uri '%s' for connectivity check.", uri);
+ uri = NULL;
}
- if (uri)
- soup_uri_free (uri);
+ if (soup_uri)
+ soup_uri_free (soup_uri);
}
#endif
+ if (g_strcmp0 (uri, priv->uri) != 0) {
+ g_free (priv->uri);
+ priv->uri = g_strdup (uri);
+ _reschedule_periodic_checks (self, TRUE);
+ }
break;
case PROP_INTERVAL:
- priv->interval = g_value_get_uint (value);
+ interval = g_value_get_uint (value);
+ if (priv->interval != interval) {
+ priv->interval = interval;
+ _reschedule_periodic_checks (self, TRUE);
+ }
break;
case PROP_RESPONSE:
- g_free (priv->response);
- priv->response = get_non_empty_string_value (value);
+ response = g_value_get_string (value);
+ if (g_strcmp0 (response, priv->response) != 0) {
+ /* a response %NULL means, DEFAULT_RESPONSE. Any other response
+ * (including "") is accepted. */
+ g_free (priv->response);
+ priv->response = g_strdup (response);
+ _reschedule_periodic_checks (self, TRUE);
+ }
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -363,7 +422,10 @@ get_property (GObject *object, guint property_id,
g_value_set_uint (value, priv->interval);
break;
case PROP_RESPONSE:
- g_value_set_string (value, priv->response);
+ if (priv->response)
+ g_value_set_string (value, priv->response);
+ else
+ g_value_set_static_string (value, DEFAULT_RESPONSE);
break;
case PROP_STATE:
g_value_set_uint (value, priv->state);
@@ -378,11 +440,12 @@ get_property (GObject *object, guint property_id,
static void
nm_connectivity_init (NMConnectivity *self)
{
-#if WITH_CONCHECK
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
+#if WITH_CONCHECK
priv->soup_session = soup_session_async_new_with_options (SOUP_SESSION_TIMEOUT, 15, NULL);
#endif
+ priv->state = NM_CONNECTIVITY_NONE;
}
@@ -392,8 +455,8 @@ dispose (GObject *object)
NMConnectivity *self = NM_CONNECTIVITY (object);
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (self);
- g_free (priv->uri);
- g_free (priv->response);
+ g_clear_pointer (&priv->uri, g_free);
+ g_clear_pointer (&priv->response, g_free);
#if WITH_CONCHECK
if (priv->soup_session) {
@@ -422,31 +485,34 @@ nm_connectivity_class_init (NMConnectivityClass *klass)
/* properties */
g_object_class_install_property
- (object_class, PROP_URI,
- g_param_spec_string (NM_CONNECTIVITY_URI, "", "",
- NULL,
- G_PARAM_READWRITE |
- G_PARAM_STATIC_STRINGS));
+ (object_class, PROP_URI,
+ g_param_spec_string (NM_CONNECTIVITY_URI, "", "",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
g_object_class_install_property
- (object_class, PROP_INTERVAL,
- g_param_spec_uint (NM_CONNECTIVITY_INTERVAL, "", "",
- 0, G_MAXUINT, 300,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
- G_PARAM_STATIC_STRINGS));
+ (object_class, PROP_INTERVAL,
+ g_param_spec_uint (NM_CONNECTIVITY_INTERVAL, "", "",
+ 0, G_MAXUINT, 300,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
g_object_class_install_property
- (object_class, PROP_RESPONSE,
- g_param_spec_string (NM_CONNECTIVITY_RESPONSE, "", "",
- DEFAULT_RESPONSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
- G_PARAM_STATIC_STRINGS));
+ (object_class, PROP_RESPONSE,
+ g_param_spec_string (NM_CONNECTIVITY_RESPONSE, "", "",
+ DEFAULT_RESPONSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
g_object_class_install_property
- (object_class, PROP_STATE,
- g_param_spec_uint (NM_CONNECTIVITY_STATE, "", "",
- NM_CONNECTIVITY_UNKNOWN, NM_CONNECTIVITY_FULL, NM_CONNECTIVITY_UNKNOWN,
- G_PARAM_READABLE |
- G_PARAM_STATIC_STRINGS));
+ (object_class, PROP_STATE,
+ g_param_spec_uint (NM_CONNECTIVITY_STATE, "", "",
+ NM_CONNECTIVITY_UNKNOWN, NM_CONNECTIVITY_FULL, NM_CONNECTIVITY_UNKNOWN,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
}
diff --git a/src/nm-connectivity.h b/src/nm-connectivity.h
index 771abdc237..fc584d5fed 100644
--- a/src/nm-connectivity.h
+++ b/src/nm-connectivity.h
@@ -51,7 +51,11 @@ typedef struct {
GType nm_connectivity_get_type (void);
-NMConnectivity *nm_connectivity_new (void);
+const char *nm_connectivity_state_to_string (NMConnectivityState state);
+
+NMConnectivity *nm_connectivity_new (const char *uri,
+ guint interval,
+ const char *response);
void nm_connectivity_set_online (NMConnectivity *self,
gboolean online);
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index 2d3768beb6..97678aa1e8 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -315,6 +315,7 @@ main (int argc, char *argv[])
&argc,
options,
NULL,
+ NULL,
_("nm-iface-helper is a small, standalone process that manages a single network interface.")))
exit (1);
@@ -480,6 +481,12 @@ main (int argc, char *argv[])
/*******************************************************/
/* Stub functions */
+void
+nm_main_config_reload ()
+{
+ nm_log_info (LOGD_CORE, "reloading configuration not supported");
+}
+
gconstpointer nm_config_get (void);
const char *nm_config_get_dhcp_client (gpointer unused);
gboolean nm_config_get_configure_and_quit (gpointer unused);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 0d0686319c..d16a912880 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -167,6 +167,7 @@ typedef struct {
GSList *devices;
NMState state;
+ NMConfig *config;
NMConnectivity *connectivity;
int ignore_link_added_cb;
@@ -463,6 +464,18 @@ active_connection_get_by_path (NMManager *manager, const char *path)
/************************************************************************/
+static void
+_config_changed_cb (NMConfig *config, NMConfigData *config_data, NMConfigChangeFlags changes, NMConfigData *old_data, NMManager *self)
+{
+ g_object_set (NM_MANAGER_GET_PRIVATE (self)->connectivity,
+ NM_CONNECTIVITY_URI, nm_config_data_get_connectivity_uri (config_data),
+ NM_CONNECTIVITY_INTERVAL, nm_config_data_get_connectivity_interval (config_data),
+ NM_CONNECTIVITY_RESPONSE, nm_config_data_get_connectivity_response (config_data),
+ NULL);
+}
+
+/************************************************************************/
+
static NMDevice *
nm_manager_get_device_by_udi (NMManager *manager, const char *udi)
{
@@ -4274,12 +4287,9 @@ connectivity_changed (NMConnectivity *connectivity,
gpointer user_data)
{
NMManager *self = NM_MANAGER (user_data);
- NMConnectivityState state;
- static const char *connectivity_states[] = { "UNKNOWN", "NONE", "PORTAL", "LIMITED", "FULL" };
- state = nm_connectivity_get_state (connectivity);
nm_log_dbg (LOGD_CORE, "connectivity checking indicates %s",
- connectivity_states[state]);
+ nm_connectivity_state_to_string (nm_connectivity_get_state (connectivity)));
nm_manager_update_state (self);
g_object_notify (G_OBJECT (self), NM_MANAGER_CONNECTIVITY);
@@ -4722,6 +4732,7 @@ nm_manager_new (NMSettings *settings,
NMManagerPrivate *priv;
DBusGConnection *bus;
DBusConnection *dbus_connection;
+ NMConfigData *config_data;
g_assert (settings);
@@ -4753,7 +4764,16 @@ nm_manager_new (NMSettings *settings,
g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP6_DEVICE,
G_CALLBACK (policy_activating_device_changed), singleton);
- priv->connectivity = nm_connectivity_new ();
+ priv->config = g_object_ref (nm_config_get ());
+ g_signal_connect (G_OBJECT (priv->config),
+ NM_CONFIG_SIGNAL_CONFIG_CHANGED,
+ G_CALLBACK (_config_changed_cb),
+ singleton);
+
+ config_data = nm_config_get_data (priv->config);
+ priv->connectivity = nm_connectivity_new (nm_config_data_get_connectivity_uri (config_data),
+ nm_config_data_get_connectivity_interval (config_data),
+ nm_config_data_get_connectivity_response (config_data));
g_signal_connect (priv->connectivity, "notify::" NM_CONNECTIVITY_STATE,
G_CALLBACK (connectivity_changed), singleton);
@@ -5074,7 +5094,14 @@ dispose (GObject *object)
g_clear_object (&priv->primary_connection);
g_clear_object (&priv->activating_connection);
- g_clear_object (&priv->connectivity);
+ if (priv->config) {
+ g_signal_handlers_disconnect_by_func (priv->config, _config_changed_cb, manager);
+ g_clear_object (&priv->config);
+ }
+ if (priv->connectivity) {
+ g_signal_handlers_disconnect_by_func (priv->connectivity, connectivity_changed, manager);
+ g_clear_object (&priv->connectivity);
+ }
g_free (priv->hostname);
diff --git a/src/nm-types.h b/src/nm-types.h
index 73a11e7567..7229eba8b0 100644
--- a/src/nm-types.h
+++ b/src/nm-types.h
@@ -26,6 +26,8 @@ typedef struct _NMActiveConnection NMActiveConnection;
typedef struct _NMVpnConnection NMVpnConnection;
typedef struct _NMActRequest NMActRequest;
typedef struct _NMAuthSubject NMAuthSubject;
+typedef struct _NMConfig NMConfig;
+typedef struct _NMConfigData NMConfigData;
typedef struct _NMConnectionProvider NMConnectionProvider;
typedef struct _NMConnectivity NMConnectivity;
typedef struct _NMDBusManager NMDBusManager;
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 36611938ef..3f7d6abf02 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -1669,7 +1669,7 @@ default_wired_clear_tag (NMSettings *self,
g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (default_wired_connection_updated_by_user_cb), self);
if (add_to_no_auto_default)
- nm_config_set_ethernet_no_auto_default (NM_SETTINGS_GET_PRIVATE (self)->config, device);
+ nm_config_set_no_auto_default_for_device (NM_SETTINGS_GET_PRIVATE (self)->config, device);
}
void
diff --git a/src/settings/plugins/example/plugin.c b/src/settings/plugins/example/plugin.c
index 9945e13b56..0bcb38fcf3 100644
--- a/src/settings/plugins/example/plugin.c
+++ b/src/settings/plugins/example/plugin.c
@@ -847,7 +847,7 @@ nm_system_config_factory (void)
priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (singleton);
/* Cache the config file path */
- priv->conf_file = nm_config_get_path (nm_config_get ());
+ priv->conf_file = nm_config_data_get_config_main_file (nm_config_get_data (nm_config_get ()));
} else {
/* This function should never be called twice */
g_assert_not_reached ();
diff --git a/src/settings/plugins/ifnet/plugin.c b/src/settings/plugins/ifnet/plugin.c
index 33711639da..7f1eb4ff93 100644
--- a/src/settings/plugins/ifnet/plugin.c
+++ b/src/settings/plugins/ifnet/plugin.c
@@ -123,9 +123,9 @@ is_managed_plugin (void)
{
char *result = NULL;
- result = nm_config_get_value (nm_config_get (),
- IFNET_KEY_FILE_GROUP, IFNET_KEY_FILE_KEY_MANAGED,
- NULL);
+ result = nm_config_data_get_value (nm_config_get_data_orig (nm_config_get ()),
+ IFNET_KEY_FILE_GROUP, IFNET_KEY_FILE_KEY_MANAGED,
+ NULL);
if (result) {
gboolean ret = is_true (result);
g_free (result);
@@ -264,9 +264,9 @@ reload_connections (NMSystemConfigInterface *config)
nm_log_info (LOGD_SETTINGS, "Loading connections");
- str_auto_refresh = nm_config_get_value (nm_config_get (),
- IFNET_KEY_FILE_GROUP, "auto_refresh",
- NULL);
+ str_auto_refresh = nm_config_data_get_value (nm_config_get_data_orig (nm_config_get ()),
+ IFNET_KEY_FILE_GROUP, "auto_refresh",
+ NULL);
if (str_auto_refresh && is_true (str_auto_refresh))
auto_refresh = TRUE;
g_free (str_auto_refresh);
diff --git a/src/settings/plugins/ifupdown/plugin.c b/src/settings/plugins/ifupdown/plugin.c
index 1b5642afb4..1cbff29b3d 100644
--- a/src/settings/plugins/ifupdown/plugin.c
+++ b/src/settings/plugins/ifupdown/plugin.c
@@ -456,12 +456,12 @@ SCPluginIfupdown_init (NMSystemConfigInterface *config)
g_hash_table_destroy (auto_ifaces);
/* Check the config file to find out whether to manage interfaces */
- value = nm_config_get_value (nm_config_get (),
- IFUPDOWN_KEY_FILE_GROUP, IFUPDOWN_KEY_FILE_KEY_MANAGED,
- &error);
+ value = nm_config_data_get_value (nm_config_get_data_orig (nm_config_get ()),
+ IFUPDOWN_KEY_FILE_GROUP, IFUPDOWN_KEY_FILE_KEY_MANAGED,
+ &error);
if (error) {
nm_log_info (LOGD_SETTINGS, "loading system config file (%s) caused error: %s",
- nm_config_get_path (nm_config_get ()),
+ nm_config_data_get_config_main_file (nm_config_get_data (nm_config_get ())),
error->message);
} else {
gboolean manage_well_known;
diff --git a/src/settings/plugins/keyfile/plugin.c b/src/settings/plugins/keyfile/plugin.c
index fcdb3c3cf0..edaa7d4566 100644
--- a/src/settings/plugins/keyfile/plugin.c
+++ b/src/settings/plugins/keyfile/plugin.c
@@ -843,7 +843,7 @@ nm_settings_keyfile_plugin_new (void)
singleton = SC_PLUGIN_KEYFILE (g_object_new (SC_TYPE_PLUGIN_KEYFILE, NULL));
priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (singleton);
- priv->conf_file = nm_config_get_path (nm_config_get ());
+ priv->conf_file = nm_config_data_get_config_main_file (nm_config_get_data (nm_config_get ()));
/* plugin_set_hostname() has to be called *after* priv->conf_file is set */
priv->hostname = plugin_get_hostname (singleton);
diff --git a/src/tests/config/test-config.c b/src/tests/config/test-config.c
index 808fc670b3..e5ac0dde4a 100644
--- a/src/tests/config/test-config.c
+++ b/src/tests/config/test-config.c
@@ -27,9 +27,12 @@
#include <nm-config.h>
#include "nm-test-device.h"
#include "nm-fake-platform.h"
+#include "nm-logging.h"
-static void
-setup_config (const char *config_file, const char *config_dir, ...)
+#include "nm-test-utils.h"
+
+static NMConfig *
+setup_config (GError **error, const char *config_file, const char *config_dir, ...)
{
va_list ap;
GPtrArray *args;
@@ -37,6 +40,11 @@ setup_config (const char *config_file, const char *config_dir, ...)
int argc;
GOptionContext *context;
gboolean success;
+ NMConfig *config;
+ GError *local_error = NULL;
+ NMConfigCmdLineOptions *cli;
+
+ g_assert (!error || !*error);
args = g_ptr_array_new ();
g_ptr_array_add (args, "test-config");
@@ -53,8 +61,10 @@ setup_config (const char *config_file, const char *config_dir, ...)
argv = (char **)args->pdata;
argc = args->len;
+ cli = nm_config_cmd_line_options_new ();
+
context = g_option_context_new (NULL);
- g_option_context_add_main_entries (context, nm_config_get_options (), NULL);
+ nm_config_cmd_line_options_add_to_entries (cli, context);
success = g_option_context_parse (context, &argc, &argv, NULL);
g_option_context_free (context);
@@ -62,6 +72,18 @@ setup_config (const char *config_file, const char *config_dir, ...)
g_printerr ("Invalid options.\n");
g_ptr_array_free (args, TRUE);
+
+ config = nm_config_setup (cli, &local_error);
+ if (error) {
+ g_assert (!config);
+ g_assert (local_error);
+ g_propagate_error (error, local_error);
+ } else {
+ g_assert (config);
+ g_assert_no_error (local_error);
+ }
+ nm_config_cmd_line_options_free (cli);
+ return config;
}
static void
@@ -72,14 +94,12 @@ test_config_simple (void)
const char **plugins;
char *value;
- setup_config (SRCDIR "/NetworkManager.conf", "/no/such/dir", NULL);
- config = nm_config_new (&error);
- g_assert_no_error (error);
+ config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", NULL);
- g_assert_cmpstr (nm_config_get_path (config), ==, SRCDIR "/NetworkManager.conf");
+ 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");
g_assert_cmpstr (nm_config_get_log_level (config), ==, "INFO");
- g_assert_cmpint (nm_config_get_connectivity_interval (config), ==, 100);
+ g_assert_cmpint (nm_config_data_get_connectivity_interval (nm_config_get_data_orig (config)), ==, 100);
plugins = nm_config_get_plugins (config);
g_assert_cmpint (g_strv_length ((char **)plugins), ==, 3);
@@ -87,16 +107,16 @@ test_config_simple (void)
g_assert_cmpstr (plugins[1], ==, "bar");
g_assert_cmpstr (plugins[2], ==, "baz");
- value = nm_config_get_value (config, "extra-section", "extra-key", NULL);
+ value = nm_config_data_get_value (nm_config_get_data_orig (config), "extra-section", "extra-key", NULL);
g_assert_cmpstr (value, ==, "some value");
g_free (value);
- value = nm_config_get_value (config, "extra-section", "no-key", &error);
+ value = nm_config_data_get_value (nm_config_get_data_orig (config), "extra-section", "no-key", &error);
g_assert (!value);
g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND);
g_clear_error (&error);
- value = nm_config_get_value (config, "no-section", "no-key", &error);
+ value = nm_config_data_get_value (nm_config_get_data_orig (config), "no-section", "no-key", &error);
g_assert (!value);
g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND);
g_clear_error (&error);
@@ -107,45 +127,38 @@ test_config_simple (void)
static void
test_config_non_existent (void)
{
- NMConfig *config;
GError *error = NULL;
- setup_config (SRCDIR "/no-such-file", "/no/such/dir", NULL);
- config = nm_config_new (&error);
- g_assert (!config);
+ 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);
}
static void
test_config_parse_error (void)
{
- NMConfig *config;
GError *error = NULL;
- setup_config (SRCDIR "/bad.conf", "/no/such/dir", NULL);
- config = nm_config_new (&error);
- g_assert (!config);
+ 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);
}
static void
test_config_override (void)
{
NMConfig *config;
- GError *error = NULL;
const char **plugins;
- setup_config (SRCDIR "/NetworkManager.conf", "/no/such/dir",
- "--plugins", "alpha,beta,gamma,delta",
- "--connectivity-interval", "12",
- NULL);
- config = nm_config_new (&error);
- g_assert_no_error (error);
+ config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir",
+ "--plugins", "alpha,beta,gamma,delta",
+ "--connectivity-interval", "12",
+ NULL);
- g_assert_cmpstr (nm_config_get_path (config), ==, SRCDIR "/NetworkManager.conf");
+ 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");
g_assert_cmpstr (nm_config_get_log_level (config), ==, "INFO");
- g_assert_cmpint (nm_config_get_connectivity_interval (config), ==, 12);
+ g_assert_cmpint (nm_config_data_get_connectivity_interval (nm_config_get_data_orig (config)), ==, 12);
plugins = nm_config_get_plugins (config);
g_assert_cmpint (g_strv_length ((char **)plugins), ==, 4);
@@ -175,37 +188,36 @@ test_config_no_auto_default (void)
g_assert_cmpint (nwrote, ==, 18);
close (fd);
- setup_config (SRCDIR "/NetworkManager.conf", "/no/such/dir",
- "--no-auto-default", state_file,
- NULL);
- config = nm_config_new (&error);
- g_assert_no_error (error);
+ config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir",
+ "--no-auto-default", state_file,
+ NULL);
dev1 = nm_test_device_new ("11:11:11:11:11:11");
dev2 = nm_test_device_new ("22:22:22:22:22:22");
dev3 = nm_test_device_new ("33:33:33:33:33:33");
dev4 = nm_test_device_new ("44:44:44:44:44:44");
- g_assert (!nm_config_get_ethernet_can_auto_default (config, dev1));
- g_assert (!nm_config_get_ethernet_can_auto_default (config, dev2));
- g_assert (nm_config_get_ethernet_can_auto_default (config, dev3));
- g_assert (!nm_config_get_ethernet_can_auto_default (config, dev4));
+ g_assert (nm_config_get_no_auto_default_for_device (config, dev1));
+ g_assert (nm_config_get_no_auto_default_for_device (config, dev2));
+ g_assert (!nm_config_get_no_auto_default_for_device (config, dev3));
+ g_assert (nm_config_get_no_auto_default_for_device (config, dev4));
- nm_config_set_ethernet_no_auto_default (config, dev3);
- g_assert (!nm_config_get_ethernet_can_auto_default (config, dev3));
+ g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*config: update * (no-auto-default)*");
+ nm_config_set_no_auto_default_for_device (config, dev3);
+ g_test_assert_expected_messages ();
+
+ g_assert (nm_config_get_no_auto_default_for_device (config, dev3));
g_object_unref (config);
- setup_config (SRCDIR "/NetworkManager.conf", "/no/such/dir",
- "--no-auto-default", state_file,
- NULL);
- config = nm_config_new (&error);
- g_assert_no_error (error);
+ config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir",
+ "--no-auto-default", state_file,
+ NULL);
- g_assert (!nm_config_get_ethernet_can_auto_default (config, dev1));
- g_assert (!nm_config_get_ethernet_can_auto_default (config, dev2));
- g_assert (!nm_config_get_ethernet_can_auto_default (config, dev3));
- g_assert (!nm_config_get_ethernet_can_auto_default (config, dev4));
+ g_assert (nm_config_get_no_auto_default_for_device (config, dev1));
+ g_assert (nm_config_get_no_auto_default_for_device (config, dev2));
+ g_assert (nm_config_get_no_auto_default_for_device (config, dev3));
+ g_assert (nm_config_get_no_auto_default_for_device (config, dev4));
g_object_unref (config);
@@ -222,20 +234,17 @@ static void
test_config_confdir (void)
{
NMConfig *config;
- GError *error = NULL;
const char **plugins;
char *value;
- setup_config (SRCDIR "/NetworkManager.conf", SRCDIR "/conf.d", NULL);
- config = nm_config_new (&error);
- g_assert_no_error (error);
+ config = setup_config (NULL, SRCDIR "/NetworkManager.conf", SRCDIR "/conf.d", NULL);
- g_assert_cmpstr (nm_config_get_path (config), ==, SRCDIR "/NetworkManager.conf");
+ 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");
g_assert_cmpstr (nm_config_get_log_level (config), ==, "INFO");
g_assert_cmpstr (nm_config_get_log_domains (config), ==, "PLATFORM,DNS,WIFI");
- g_assert_cmpstr (nm_config_get_connectivity_uri (config), ==, "http://example.net");
- g_assert_cmpint (nm_config_get_connectivity_interval (config), ==, 100);
+ g_assert_cmpstr (nm_config_data_get_connectivity_uri (nm_config_get_data_orig (config)), ==, "http://example.net");
+ g_assert_cmpint (nm_config_data_get_connectivity_interval (nm_config_get_data_orig (config)), ==, 100);
plugins = nm_config_get_plugins (config);
g_assert_cmpint (g_strv_length ((char **)plugins), ==, 5);
@@ -245,21 +254,21 @@ test_config_confdir (void)
g_assert_cmpstr (plugins[3], ==, "one");
g_assert_cmpstr (plugins[4], ==, "two");
- value = nm_config_get_value (config, "main", "extra", NULL);
+ value = nm_config_data_get_value (nm_config_get_data_orig (config), "main", "extra", NULL);
g_assert_cmpstr (value, ==, "hello");
g_free (value);
- value = nm_config_get_value (config, "main", "new", NULL);
+ value = nm_config_data_get_value (nm_config_get_data_orig (config), "main", "new", NULL);
g_assert_cmpstr (value, ==, "something"); /* not ",something" */
g_free (value);
- value = nm_config_get_value (config, "order", "a", NULL);
+ value = nm_config_data_get_value (nm_config_get_data_orig (config), "order", "a", NULL);
g_assert_cmpstr (value, ==, "90");
g_free (value);
- value = nm_config_get_value (config, "order", "b", NULL);
+ value = nm_config_data_get_value (nm_config_get_data_orig (config), "order", "b", NULL);
g_assert_cmpstr (value, ==, "10");
g_free (value);
- value = nm_config_get_value (config, "order", "c", NULL);
+ value = nm_config_data_get_value (nm_config_get_data_orig (config), "order", "c", NULL);
g_assert_cmpstr (value, ==, "0");
g_free (value);
@@ -269,24 +278,20 @@ test_config_confdir (void)
static void
test_config_confdir_parse_error (void)
{
- NMConfig *config;
GError *error = NULL;
/* Using SRCDIR as the conf dir will pick up bad.conf */
- setup_config (SRCDIR "/NetworkManager.conf", SRCDIR, NULL);
- config = nm_config_new (&error);
- g_assert (!config);
+ 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);
}
+NMTST_DEFINE ();
+
int
main (int argc, char **argv)
{
-#if !GLIB_CHECK_VERSION (2, 35, 0)
- g_type_init ();
-#endif
-
- g_test_init (&argc, &argv, NULL);
+ nmtst_init_assert_logging (&argc, &argv);
nm_fake_platform_setup ();