diff options
-rw-r--r-- | src/main.c | 7 | ||||
-rw-r--r-- | src/nm-config.c | 173 | ||||
-rw-r--r-- | src/nm-config.h | 23 | ||||
-rw-r--r-- | src/nm-manager.c | 64 | ||||
-rw-r--r-- | src/nm-manager.h | 2 |
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); |