summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2016-09-26 13:16:16 +0200
committerThomas Haller <thaller@redhat.com>2016-09-26 13:16:16 +0200
commit5db62eb51d0664cc815e146dc49b82bbddae3ae1 (patch)
treee2a3227e5a1e478f64688cc3105f6a0b76a447aa
parente152eea21819cb31e6da779b06ae1b6df7270bb1 (diff)
parent93396b8d526e99ac26a6e9c9d9b783333fc9b88e (diff)
downloadNetworkManager-5db62eb51d0664cc815e146dc49b82bbddae3ae1.tar.gz
core: merge branch 'th/device-state-bgo771890'
https://bugzilla.gnome.org/show_bug.cgi?id=771890
-rw-r--r--src/main-utils.c15
-rw-r--r--src/main.c7
-rw-r--r--src/nm-config.c218
-rw-r--r--src/nm-config.h29
-rw-r--r--src/nm-manager.c64
-rw-r--r--src/nm-manager.h2
6 files changed, 310 insertions, 25 deletions
diff --git a/src/main-utils.c b/src/main-utils.c
index c2ed9d1cbb..bad3141abf 100644
--- a/src/main-utils.c
+++ b/src/main-utils.c
@@ -34,6 +34,7 @@
#include "main-utils.h"
#include "NetworkManagerUtils.h"
+#include "nm-config.h"
static gboolean
sighup_handler (gpointer user_data)
@@ -139,11 +140,23 @@ nm_main_utils_ensure_statedir ()
void
nm_main_utils_ensure_rundir ()
{
+ int errsv;
+
/* Setup runtime directory */
if (g_mkdir_with_parents (NMRUNDIR, 0755) != 0) {
- fprintf (stderr, _("Cannot create '%s': %s"), NMRUNDIR, strerror (errno));
+ errsv = errno;
+ fprintf (stderr, _("Cannot create '%s': %s"), NMRUNDIR, g_strerror (errsv));
exit (1);
}
+
+ nm_assert (g_str_has_prefix (NM_CONFIG_DEVICE_STATE_DIR, NMRUNDIR"/"));
+ if (g_mkdir (NM_CONFIG_DEVICE_STATE_DIR, 0755) != 0) {
+ errsv = errno;
+ if (errsv != EEXIST) {
+ fprintf (stderr, _("Cannot create '%s': %s"), NM_CONFIG_DEVICE_STATE_DIR, g_strerror (errsv));
+ exit (1);
+ }
+ }
}
/**
diff --git a/src/main.c b/src/main.c
index 490dcfe97c..0dca1afad8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -412,6 +412,13 @@ main (int argc, char *argv[])
}
done:
+
+ /* write the device-state to file. Note that we only persist the
+ * state here. We don't bother updating the state as devices
+ * change during regular operation. If NM is killed with SIGKILL,
+ * it misses to update the state. */
+ nm_manager_write_device_state (nm_manager_get ());
+
nm_exported_object_class_set_quitting ();
nm_manager_stop (nm_manager_get ());
diff --git a/src/nm-config.c b/src/nm-config.c
index 4bc4f48340..8536a77fd5 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -418,8 +418,8 @@ nm_config_set_no_auto_default_for_device (NMConfig *self, NMDevice *device)
g_ptr_array_add (no_auto_default_new, NULL);
if (!no_auto_default_to_file (priv->no_auto_default_file, (const char *const*) no_auto_default_new->pdata, &error)) {
- nm_log_warn (LOGD_SETTINGS, "Could not update no-auto-default.state file: %s",
- error->message);
+ _LOGW ("Could not update no-auto-default.state file: %s",
+ error->message);
g_error_free (error);
}
@@ -680,7 +680,7 @@ read_config (GKeyFile *keyfile, gboolean is_base_config, const char *dirname, co
return FALSE;
}
- nm_log_dbg (LOGD_SETTINGS, "Reading config file '%s'", path);
+ _LOGD ("Reading config file '%s'", path);
kf = nm_config_create_keyfile ();
if (!g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, error)) {
@@ -866,8 +866,8 @@ read_base_config (GKeyFile *keyfile,
}
if (!g_error_matches (my_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND)) {
- nm_log_warn (LOGD_CORE, "Old default config file invalid: %s\n",
- my_error->message);
+ _LOGW ("Old default config file invalid: %s\n",
+ my_error->message);
}
g_clear_error (&my_error);
@@ -878,8 +878,8 @@ read_base_config (GKeyFile *keyfile,
}
if (!g_error_matches (my_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND)) {
- nm_log_warn (LOGD_CORE, "Default config file invalid: %s\n",
- my_error->message);
+ _LOGW ("Default config file invalid: %s\n",
+ my_error->message);
g_propagate_error (error, my_error);
return FALSE;
}
@@ -889,8 +889,8 @@ read_base_config (GKeyFile *keyfile,
* config file path.
*/
*out_config_main_file = g_strdup (DEFAULT_CONFIG_MAIN_FILE);
- nm_log_info (LOGD_CORE, "No config file found or given; using %s\n",
- DEFAULT_CONFIG_MAIN_FILE);
+ _LOGI ("No config file found or given; using %s\n",
+ DEFAULT_CONFIG_MAIN_FILE);
return TRUE;
}
@@ -1303,7 +1303,7 @@ out:
if (out_needs_rewrite)
*out_needs_rewrite = needs_rewrite;
- nm_log_dbg (LOGD_CORE, "intern config file \"%s\"", filename);
+ _LOGD ("intern config file \"%s\"", filename);
if (!has_intern) {
g_key_file_unref (keyfile_intern);
@@ -1502,7 +1502,7 @@ intern_config_write (const char *filename,
success = g_key_file_save_to_file (keyfile, filename, &local);
- nm_log_dbg (LOGD_CORE, "write intern config file \"%s\"%s%s", filename, success ? "" : ": ", success ? "" : local->message);
+ _LOGD ("write intern config file \"%s\"%s%s", filename, success ? "" : ": ", success ? "" : local->message);
g_key_file_unref (keyfile);
if (!success)
g_propagate_error (error, local);
@@ -1658,7 +1658,7 @@ nm_config_set_values (NMConfig *self,
if (!_nm_keyfile_equals (keyfile_intern_current, keyfile_new, TRUE))
new_data = nm_config_data_new_update_keyfile_intern (priv->config_data, keyfile_new);
- nm_log_dbg (LOGD_CORE, "set values(): %s", new_data ? "has changes" : "no changes");
+ _LOGD ("set values(): %s", new_data ? "has changes" : "no changes");
if (allow_write
&& (new_data || force_rewrite)) {
@@ -1673,11 +1673,11 @@ nm_config_set_values (NMConfig *self,
keyfile_user = _nm_config_data_get_keyfile_user (priv->config_data);
if (!intern_config_write (priv->intern_config_file, keyfile_new, keyfile_user,
(const char *const*) priv->atomic_section_prefixes, &local)) {
- nm_log_warn (LOGD_CORE, "error saving internal configuration \"%s\": %s", priv->intern_config_file, local->message);
+ _LOGW ("error saving internal configuration \"%s\": %s", priv->intern_config_file, local->message);
g_clear_error (&local);
}
} else
- nm_log_dbg (LOGD_CORE, "don't persistate internal configuration (no file set, use --intern-config?)");
+ _LOGD ("don't persist internal configuration (no file set, use --intern-config?)");
}
if (new_data)
_set_config_data (self, new_data, NM_CONFIG_CHANGE_CAUSE_SET_VALUES);
@@ -1870,6 +1870,184 @@ _nm_config_state_set (NMConfig *self,
/*****************************************************************************/
+#define DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE "device"
+#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED "managed"
+#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_CONNECTION_UUID "connection-uuid"
+
+static NMConfigDeviceStateData *
+_config_device_state_data_new (int ifindex, GKeyFile *kf)
+{
+ NMConfigDeviceStateData *device_state;
+ NMConfigDeviceStateManagedType managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNKNOWN;
+ gs_free char *connection_uuid = NULL;
+ gsize len_plus_1;
+
+ nm_assert (ifindex > 0);
+
+ if (kf) {
+ gboolean managed;
+
+ managed = nm_config_keyfile_get_boolean (kf,
+ DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
+ DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED,
+ FALSE);
+ managed_type = managed
+ ? NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED
+ : NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED;
+
+ if (managed) {
+ connection_uuid = nm_config_keyfile_get_value (kf,
+ DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
+ DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_CONNECTION_UUID,
+ NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
+ }
+ }
+
+ len_plus_1 = connection_uuid ? strlen (connection_uuid) + 1 : 0;
+
+ device_state = g_malloc (sizeof (NMConfigDeviceStateData) + len_plus_1);
+
+ device_state->ifindex = ifindex;
+ device_state->managed = managed_type;
+ device_state->connection_uuid = NULL;
+ if (connection_uuid) {
+ char *device_state_data;
+
+ device_state_data = (char *) (&device_state[1]);
+ memcpy (device_state_data, connection_uuid, len_plus_1);
+ device_state->connection_uuid = device_state_data;
+ }
+
+ return device_state;
+}
+
+/**
+ * nm_config_device_state_load:
+ * @self: the NMConfig instance
+ * @ifindex: the ifindex for which the state is to load
+ *
+ * Returns: (transfer full): a run state object.
+ * Must be freed with g_free().
+ */
+NMConfigDeviceStateData *
+nm_config_device_state_load (NMConfig *self,
+ int ifindex)
+{
+ NMConfigDeviceStateData *device_state;
+ char path[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR) + 60];
+ gs_unref_keyfile GKeyFile *kf = NULL;
+ gs_free_error GError *error = NULL;
+
+ g_return_val_if_fail (ifindex > 0, NULL);
+
+ nm_sprintf_buf (path, "%s/%d", NM_CONFIG_DEVICE_STATE_DIR, ifindex);
+
+ kf = nm_config_create_keyfile ();
+ if (!g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, &error))
+ g_clear_pointer (&kf, g_key_file_unref);
+
+ device_state = _config_device_state_data_new (ifindex, kf);
+
+ if (kf) {
+ _LOGT ("device-state: read #%d (%s); managed=%d, connection-uuid=%s%s%s",
+ ifindex, path,
+ device_state->managed,
+ NM_PRINT_FMT_QUOTE_STRING (device_state->connection_uuid));
+ } else {
+ _LOGT ("device-state: read #%d (%s); no persistent state",
+ ifindex, path);
+ }
+
+ return device_state;
+}
+
+gboolean
+nm_config_device_state_write (NMConfig *self,
+ int ifindex,
+ gboolean managed,
+ const char *connection_uuid)
+{
+ char path[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR) + 60];
+ GError *local = NULL;
+ gs_unref_keyfile GKeyFile *kf = NULL;
+
+ g_return_val_if_fail (NM_IS_CONFIG (self), FALSE);
+ g_return_val_if_fail (ifindex > 0, FALSE);
+ g_return_val_if_fail (!connection_uuid || *connection_uuid, FALSE);
+ g_return_val_if_fail (managed || !connection_uuid, FALSE);
+
+ nm_sprintf_buf (path, "%s/%d", NM_CONFIG_DEVICE_STATE_DIR, ifindex);
+
+ kf = nm_config_create_keyfile ();
+ g_key_file_set_boolean (kf,
+ DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
+ DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_MANAGED,
+ !!managed);
+ if (connection_uuid) {
+ g_key_file_set_string (kf,
+ DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
+ DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_CONNECTION_UUID,
+ connection_uuid);
+ }
+
+ if (!g_key_file_save_to_file (kf, path, &local)) {
+ _LOGW ("device-state: write #%d (%s) failed: %s", ifindex, path, local->message);
+ g_error_free (local);
+ return FALSE;
+ }
+ _LOGT ("device-state: write #%d (%s); managed=%d, connection-uuid=%s%s%s",
+ ifindex, path,
+ (bool) managed,
+ NM_PRINT_FMT_QUOTE_STRING (connection_uuid));
+ return TRUE;
+}
+
+void
+nm_config_device_state_prune_unseen (NMConfig *self,
+ GHashTable *seen_ifindexes)
+{
+ GDir *dir;
+ const char *fn;
+ int ifindex;
+ gsize fn_len;
+ gsize i;
+ char buf[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR"/") + 30 + 3] = NM_CONFIG_DEVICE_STATE_DIR"/";
+ char *buf_p = &buf[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR"/")];
+
+ g_return_if_fail (seen_ifindexes);
+
+ dir = g_dir_open (NM_CONFIG_DEVICE_STATE_DIR, 0, NULL);
+ if (!dir)
+ return;
+
+ while ((fn = g_dir_read_name (dir))) {
+ fn_len = strlen (fn);
+
+ /* skip over file names that are not plain integers. */
+ for (i = 0; i < fn_len; i++) {
+ if (!g_ascii_isdigit (fn[i]))
+ break;
+ }
+ if (fn_len == 0 || i != fn_len)
+ continue;
+
+ ifindex = _nm_utils_ascii_str_to_int64 (fn, 10, 1, G_MAXINT, 0);
+ if (!ifindex)
+ continue;
+
+ if (g_hash_table_contains (seen_ifindexes, GINT_TO_POINTER (ifindex)))
+ continue;
+
+ memcpy (buf_p, fn, fn_len + 1);
+ _LOGT ("device-state: prune #%d (%s)", ifindex, buf);
+ (void) unlink (buf);
+ }
+
+ g_dir_close (dir);
+}
+
+/*****************************************************************************/
+
void
nm_config_reload (NMConfig *self, NMConfigChangeFlags reload_flags)
{
@@ -1907,7 +2085,7 @@ nm_config_reload (NMConfig *self, NMConfigChangeFlags reload_flags)
&config_description,
&error);
if (!keyfile) {
- nm_log_err (LOGD_CORE, "Failed to reload the configuration: %s", error->message);
+ _LOGE ("Failed to reload the configuration: %s", error->message);
g_clear_error (&error);
_set_config_data (self, NULL, reload_flags);
return;
@@ -1989,15 +2167,15 @@ _set_config_data (NMConfig *self, NMConfigData *new_data, NMConfigChangeFlags re
}
if (new_data) {
- nm_log_info (LOGD_CORE, "config: signal %s (%s)",
- nm_config_change_flags_to_string (changes, NULL, 0),
- nm_config_data_get_config_description (new_data));
+ _LOGI ("config: signal %s (%s)",
+ nm_config_change_flags_to_string (changes, NULL, 0),
+ nm_config_data_get_config_description (new_data));
nm_config_data_log (new_data, "CONFIG: ", " ", NULL);
priv->config_data = new_data;
} else if (had_new_data)
- nm_log_info (LOGD_CORE, "config: signal %s (no changes from disk)", nm_config_change_flags_to_string (changes, NULL, 0));
+ _LOGI ("config: signal %s (no changes from disk)", nm_config_change_flags_to_string (changes, NULL, 0));
else
- nm_log_info (LOGD_CORE, "config: signal %s", nm_config_change_flags_to_string (changes, NULL, 0));
+ _LOGI ("config: signal %s", nm_config_change_flags_to_string (changes, NULL, 0));
g_signal_emit (self, signals[SIGNAL_CONFIG_CHANGED], 0,
new_data ? new_data : old_data,
changes, old_data);
diff --git a/src/nm-config.h b/src/nm-config.h
index a75e393523..6ada27672d 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -185,5 +185,34 @@ gboolean nm_config_set_global_dns (NMConfig *self, NMGlobalDnsConfig *global_dns
extern guint _nm_config_match_nm_version;
extern char *_nm_config_match_env;
+/*****************************************************************************/
+
+#define NM_CONFIG_DEVICE_STATE_DIR ""NMRUNDIR"/devices"
+
+typedef enum {
+ NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNKNOWN = -1,
+ NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED = 0,
+ NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED = 1,
+} NMConfigDeviceStateManagedType;
+
+typedef struct {
+ int ifindex;
+ NMConfigDeviceStateManagedType managed;
+
+ /* the UUID of the last settings-connection active
+ * on the device. */
+ const char *connection_uuid;
+} NMConfigDeviceStateData;
+
+NMConfigDeviceStateData *nm_config_device_state_load (NMConfig *self,
+ int ifindex);
+gboolean nm_config_device_state_write (NMConfig *self,
+ int ifindex,
+ gboolean managed,
+ const char *connection_uuid);
+void nm_config_device_state_prune_unseen (NMConfig *self, GHashTable *seen_ifindexes);
+
+/*****************************************************************************/
+
#endif /* __NETWORKMANAGER_CONFIG_H__ */
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 2335a731bf..efc21c9459 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -2083,7 +2083,8 @@ _register_device_factory (NMDeviceFactory *factory, gpointer user_data)
static void
platform_link_added (NMManager *self,
int ifindex,
- const NMPlatformLink *plink)
+ const NMPlatformLink *plink,
+ const NMConfigDeviceStateData *dev_state)
{
NMDeviceFactory *factory;
NMDevice *device = NULL;
@@ -2194,7 +2195,7 @@ _platform_link_cb_idle (PlatformLinkCbData *data)
NMPlatformLink pllink;
pllink = *l; /* make a copy of the link instance */
- platform_link_added (self, data->ifindex, &pllink);
+ platform_link_added (self, data->ifindex, &pllink, NULL);
} else {
NMDevice *device;
GError *error = NULL;
@@ -2249,14 +2250,24 @@ platform_link_cb (NMPlatform *platform,
static void
platform_query_devices (NMManager *self)
{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GArray *links_array;
NMPlatformLink *links;
int i;
links_array = nm_platform_link_get_all (NM_PLATFORM_GET);
links = (NMPlatformLink *) links_array->data;
- for (i = 0; i < links_array->len; i++)
- platform_link_added (self, links[i].ifindex, &links[i]);
+ for (i = 0; i < links_array->len; i++) {
+ gs_free NMConfigDeviceStateData *dev_state = NULL;
+
+ dev_state = nm_config_device_state_load (priv->config,
+ links[i].ifindex);
+
+ platform_link_added (self,
+ links[i].ifindex,
+ &links[i],
+ dev_state);
+ }
g_array_unref (links_array);
}
@@ -4586,6 +4597,51 @@ start_factory (NMDeviceFactory *factory, gpointer user_data)
nm_device_factory_start (factory);
}
+void
+nm_manager_write_device_state (NMManager *self)
+{
+ const GSList *devices;
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ gs_unref_hashtable GHashTable *seen_ifindexes = NULL;
+
+ seen_ifindexes = g_hash_table_new (NULL, NULL);
+
+ for (devices = priv->devices; devices; devices = devices->next) {
+ NMDevice *device = NM_DEVICE (devices->data);
+ int ifindex;
+ gboolean managed;
+ NMConnection *settings_connection;
+ const char *uuid = NULL;
+
+ ifindex = nm_device_get_ip_ifindex (device);
+ if (ifindex <= 0)
+ continue;
+ if (ifindex == 1) {
+ /* ignore loopback */
+ continue;
+ }
+
+ if (!nm_platform_link_get (NM_PLATFORM_GET, ifindex))
+ continue;
+
+ managed = nm_device_get_managed (device, FALSE);
+ if (managed) {
+ settings_connection = NM_CONNECTION (nm_device_get_settings_connection (device));
+ if (settings_connection)
+ uuid = nm_connection_get_uuid (settings_connection);
+ }
+
+ if (nm_config_device_state_write (priv->config,
+ ifindex,
+ managed,
+ uuid))
+ g_hash_table_add (seen_ifindexes, GINT_TO_POINTER (ifindex));
+ }
+
+ nm_config_device_state_prune_unseen (priv->config,
+ seen_ifindexes);
+}
+
gboolean
nm_manager_start (NMManager *self, GError **error)
{
diff --git a/src/nm-manager.h b/src/nm-manager.h
index 11c4eb4a18..fb97951ce3 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -86,6 +86,8 @@ NMState nm_manager_get_state (NMManager *manager);
const GSList *nm_manager_get_active_connections (NMManager *manager);
GSList * nm_manager_get_activatable_connections (NMManager *manager);
+void nm_manager_write_device_state (NMManager *manager);
+
/* Device handling */
const GSList * nm_manager_get_devices (NMManager *manager);