summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-07-09 18:54:47 +0200
committerThomas Haller <thaller@redhat.com>2014-09-25 10:06:17 +0200
commit95ec60d2eed099374a37f3034e12aaaf372fee91 (patch)
treeb8a4132f08e589bf77af2c1062e9b6342332ac38
parentac563aa5842787b96a6ce88bcad6586eba7094e1 (diff)
downloadNetworkManager-th/rh1066697_reload_config-dcbw.tar.gz
config: add support for reloading of configurationth/rh1066697_reload_config-dcbw-2th/rh1066697_reload_config-dcbw
Some configuration parameters can be set via command line. If a parameter is set from command line, the original value from command line will still be preserved after reloading. (heavily modified by dcbw) Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r--src/main.c4
-rw-r--r--src/nm-config-data.c57
-rw-r--r--src/nm-config-data.h2
-rw-r--r--src/nm-config.c205
-rw-r--r--src/nm-config.h7
5 files changed, 218 insertions, 57 deletions
diff --git a/src/main.c b/src/main.c
index 3eeab13f5b..b5061ea293 100644
--- a/src/main.c
+++ b/src/main.c
@@ -225,7 +225,9 @@ _handle_signal (gpointer user_data)
g_assert (signo == SIGHUP);
- nm_log_info (LOGD_CORE, "caught signal %d, not supported yet.", signo);
+ nm_log_info (LOGD_CORE, "caught signal %d, reload configuration...", signo);
+
+ nm_config_reload (nm_config_get ());
return G_SOURCE_REMOVE;
}
diff --git a/src/nm-config-data.c b/src/nm-config-data.c
index 57cfed8a07..824a481f56 100644
--- a/src/nm-config-data.c
+++ b/src/nm-config-data.c
@@ -290,6 +290,63 @@ nm_config_data_new_keyfile (GKeyFile *keyfile,
return self;
}
+#define CHANGED(p) g_hash_table_insert (changes, NM_CONFIG_DATA_##p, GUINT_TO_POINTER (1));
+
+GHashTable *
+nm_config_data_diff (NMConfigData *self, NMConfigData *other)
+{
+ NMConfigDataPrivate *priv, *other_priv;
+ GHashTable *changes;
+ guint i, n;
+
+ g_return_val_if_fail (NM_IS_CONFIG_DATA (self), NULL);
+ g_return_val_if_fail (NM_IS_CONFIG_DATA (other), NULL);
+
+ priv = NM_CONFIG_DATA_GET_PRIVATE (self);
+ other_priv = NM_CONFIG_DATA_GET_PRIVATE (other);
+
+ changes = g_hash_table_new (g_str_hash, g_str_equal);
+
+ n = g_strv_length (priv->plugins);
+ if (n != g_strv_length (other_priv->plugins))
+ CHANGED (PLUGINS);
+ for (i = 0; i < n; i++) {
+ if (g_strcmp0 (priv->plugins[i], other_priv->plugins[i])) {
+ CHANGED (PLUGINS);
+ break;
+ }
+ }
+
+ if (priv->monitor_connection_files != other_priv->monitor_connection_files)
+ CHANGED (MONITOR_CONNECTION_FILES);
+
+ if (g_strcmp0 (priv->dhcp_client, other_priv->dhcp_client))
+ CHANGED (DHCP_CLIENT);
+
+ if (g_strcmp0 (priv->dns_mode, other_priv->dns_mode))
+ CHANGED (DNS_MODE);
+
+ if (g_strcmp0 (priv->debug, other_priv->debug))
+ CHANGED (DEBUG);
+
+ if (g_strcmp0 (priv->log.level, other_priv->log.level))
+ CHANGED (LOG_LEVEL);
+
+ if (g_strcmp0 (priv->log.domains, other_priv->log.domains))
+ CHANGED (LOG_LEVEL);
+
+ if (g_strcmp0 (priv->connectivity.uri, other_priv->connectivity.uri))
+ CHANGED (CONNECTIVITY_URI);
+
+ if (priv->connectivity.interval != other_priv->connectivity.interval)
+ CHANGED (CONNECTIVITY_INTERVAL);
+
+ if (g_strcmp0 (priv->connectivity.response, other_priv->connectivity.response))
+ CHANGED (CONNECTIVITY_RESPONSE);
+
+ return changes;
+}
+
/************************************************************************/
static void
diff --git a/src/nm-config-data.h b/src/nm-config-data.h
index 31416f0f86..2ec41d140d 100644
--- a/src/nm-config-data.h
+++ b/src/nm-config-data.h
@@ -76,6 +76,8 @@ NMConfigData *nm_config_data_new_keyfile (GKeyFile *keyfile,
NMConfigData *override,
GError **error);
+GHashTable *nm_config_data_diff (NMConfigData *self, NMConfigData *other);
+
G_END_DECLS
#endif /* NM_CONFIG_DATA_H */
diff --git a/src/nm-config.c b/src/nm-config.c
index bd87a0ce4c..4b5e9903ce 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -28,6 +28,7 @@
#include "nm-utils.h"
#include "nm-glib-compat.h"
#include "nm-device.h"
+#include "NetworkManagerUtils.h"
#include <gio/gio.h>
#include <glib/gi18n.h>
@@ -54,6 +55,14 @@ typedef struct {
NMConfigData *config_data;
} NMConfigPrivate;
+enum {
+ SIGNAL_CONFIG_CHANGED,
+
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
static NMConfig *singleton = NULL;
G_DEFINE_TYPE (NMConfig, nm_config, G_TYPE_OBJECT)
@@ -300,9 +309,8 @@ nm_config_get_options (void)
/************************************************************************/
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;
@@ -332,22 +340,22 @@ read_config (NMConfig *config, const char *path, GError **error)
int len = strlen (keys[k]);
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],
g_key_file_get_value (kf, groups[g], keys[k], NULL));
}
}
@@ -365,7 +373,7 @@ find_base_config (NMConfig *config, GError **error)
/* Try a user-specified config file first */
if (cli_config_path) {
/* Bad user-specific config file path is a hard error */
- if (read_config (config, cli_config_path, error)) {
+ if (read_config (priv->keyfile, cli_config_path, error)) {
priv->nm_conf_path = g_strdup (cli_config_path);
return TRUE;
} else
@@ -380,7 +388,7 @@ 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)) {
+ if (read_config (priv->keyfile, NM_OLD_SYSTEM_CONF_FILE, &my_error)) {
priv->nm_conf_path = g_strdup (NM_OLD_SYSTEM_CONF_FILE);
return TRUE;
}
@@ -393,7 +401,7 @@ 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)) {
+ if (read_config (priv->keyfile, NM_DEFAULT_SYSTEM_CONF_FILE, &my_error)) {
priv->nm_conf_path = g_strdup (NM_DEFAULT_SYSTEM_CONF_FILE);
return TRUE;
}
@@ -418,13 +426,6 @@ find_base_config (NMConfig *config, GError **error)
/************************************************************************/
-NMConfig *
-nm_config_get (void)
-{
- g_assert (singleton);
- return singleton;
-}
-
static int
sort_asciibetically (gconstpointer a, gconstpointer b)
{
@@ -434,13 +435,14 @@ sort_asciibetically (gconstpointer a, gconstpointer b)
return strcmp (s1, s2);
}
-/* call this function only once! */
-NMConfig *
-nm_config_new (const char *cli_log_level,
- const char *cli_log_domains,
- GError **error)
+/* Updates keyfile with new merged values from config files */
+static gboolean
+reload_config_files (GKeyFile *keyfile,
+ const char *conf_path,
+ const char *config_dir,
+ char **out_config_description,
+ GError **error)
{
- NMConfigPrivate *priv = NULL;
GFile *dir;
GFileEnumerator *direnum;
GFileInfo *info;
@@ -448,35 +450,17 @@ nm_config_new (const char *cli_log_level,
const char *name;
int i;
GString *config_description;
-
- 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))
- goto fail;
-
- /* Read command-line overrides */
- priv->cli_data = nm_config_data_new_cli (cli_log_level, cli_log_domains, error);
- if (!priv->cli_data)
- goto fail;
-
- /* 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);
+ gboolean success = TRUE;
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 (conf_path);
+ 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
@@ -490,17 +474,117 @@ nm_config_new (const char *cli_log_level,
g_object_unref (dir);
g_ptr_array_sort (confs, sort_asciibetically);
- priv->config_description = g_string_free (config_description, FALSE);
+ if (out_config_description)
+ *out_config_description = g_string_free (config_description, FALSE);
+ else
+ g_string_free (config_description, TRUE);
+
for (i = 0; i < confs->len; i++) {
- if (!read_config (singleton, confs->pdata[i], error)) {
- g_object_unref (singleton);
- singleton = NULL;
+ if (!read_config (keyfile, confs->pdata[i], error)) {
+ success = FALSE;
break;
}
}
g_ptr_array_unref (confs);
- if (!singleton)
- return NULL;
+ return success;
+}
+
+void
+nm_config_reload (NMConfig *self)
+{
+ NMConfigPrivate *priv;
+ GError *error = NULL;
+ GHashTable *changes;
+ NMConfigData *new_data = NULL;
+ GKeyFile *new_kf;
+ char *config_desc = NULL;
+
+ g_return_if_fail (NM_IS_CONFIG (self));
+
+ priv = NM_CONFIG_GET_PRIVATE (self);
+
+ new_kf = g_key_file_new ();
+ g_key_file_set_list_separator (new_kf, ',');
+ if (!reload_config_files (new_kf,
+ priv->nm_conf_path,
+ priv->config_dir,
+ &config_desc,
+ &error))
+ goto fail;
+
+ new_data = nm_config_data_new_keyfile (new_kf, priv->cli_data, &error);
+ if (!new_data)
+ goto fail;
+
+ changes = nm_config_data_diff (priv->config_data, new_data);
+ if (g_hash_table_size (changes)) {
+ NMConfigData *old_data = priv->config_data;
+
+ g_object_unref (priv->keyfile);
+ priv->keyfile = new_kf;
+ g_free (priv->config_description);
+ priv->config_description = config_desc;
+
+ priv->config_data = new_data;
+ g_signal_emit (self, signals[SIGNAL_CONFIG_CHANGED], 0, changes, old_data);
+ g_object_unref (old_data);
+ } else {
+ g_key_file_unref (new_kf);
+ g_object_unref (new_data);
+ g_free (config_desc);
+ }
+ g_hash_table_destroy (changes);
+ return;
+
+fail:
+ if (error) {
+ nm_log_warn (LOGD_SETTINGS, "failed to read configuation: (%s) %s",
+ g_quark_to_string (error->domain), error->message);
+ g_error_free (error);
+ }
+ g_key_file_unref (new_kf);
+ g_free (config_desc);
+}
+
+/* call this function only once! */
+NMConfig *
+nm_config_new (const char *cli_log_level,
+ const char *cli_log_domains,
+ GError **error)
+{
+ NMConfigPrivate *priv;
+
+ 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))
+ goto fail;
+
+ /* Read command-line overrides */
+ priv->cli_data = nm_config_data_new_cli (cli_log_level, cli_log_domains, error);
+ if (!priv->cli_data)
+ goto fail;
+
+ /* 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);
+
+ if (!reload_config_files (priv->keyfile,
+ priv->nm_conf_path,
+ priv->config_dir,
+ &priv->config_description,
+ error))
+ goto fail;
+
+ priv->config_data = nm_config_data_new_keyfile (priv->keyfile,
+ priv->cli_data,
+ error);
+ if (!priv->config_data)
+ goto fail;
/* 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);
@@ -512,12 +596,6 @@ nm_config_new (const char *cli_log_level,
priv->ignore_carrier = g_key_file_get_string_list (priv->keyfile, "main", "ignore-carrier", NULL, NULL);
- priv->config_data = nm_config_data_new_keyfile (priv->keyfile,
- priv->cli_data,
- error);
- if (!priv->config_data)
- goto fail;
-
return singleton;
fail:
@@ -526,6 +604,13 @@ fail:
return NULL;
}
+NMConfig *
+nm_config_get (void)
+{
+ g_assert (singleton);
+ return singleton;
+}
+
static void
nm_config_init (NMConfig *config)
{
@@ -576,5 +661,13 @@ nm_config_class_init (NMConfigClass *config_class)
g_type_class_add_private (config_class, sizeof (NMConfigPrivate));
object_class->dispose = dispose;
object_class->finalize = finalize;
+
+ 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, 2, G_TYPE_HASH_TABLE, NM_TYPE_CONFIG_DATA);
}
diff --git a/src/nm-config.h b/src/nm-config.h
index c1d6aab0ea..0790320af9 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -37,12 +37,18 @@ 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))
+/* Signals */
+#define NM_CONFIG_SIGNAL_CONFIG_CHANGED "config-changed"
+
typedef struct {
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);
@@ -74,6 +80,7 @@ GOptionEntry *nm_config_get_options (void);
NMConfig *nm_config_new (const char *cli_log_level,
const char *cli_log_domains,
GError **error);
+void nm_config_reload (NMConfig *config);
G_END_DECLS