summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.c7
-rw-r--r--src/nm-config.c173
-rw-r--r--src/nm-config.h23
-rw-r--r--src/nm-manager.c64
-rw-r--r--src/nm-manager.h2
5 files changed, 265 insertions, 4 deletions
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 a4e8eb8cdb..b587f880a2 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -1870,6 +1870,179 @@ _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);
+
+ _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));
+
+ 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: failure to write #%d (%s): %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)
{
diff --git a/src/nm-config.h b/src/nm-config.h
index ef5430ee6c..6ada27672d 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -189,6 +189,29 @@ 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);