From 1a257a675277a17dc16ab8d8a0ef4c43e6e05cb8 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 20 Sep 2016 14:17:20 +0200 Subject: [PATCH 1/3] config: use logging macros For some logging lines we used the wrong logging domain LOGD_SETTINGS instead of LOGD_CORE. --- src/nm-config.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/nm-config.c b/src/nm-config.c index 4bc4f48340..a4e8eb8cdb 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); @@ -1907,7 +1907,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 +1989,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); From 1eca446c8c9044c3643c59f73d4396e7ef18d54d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 4 Apr 2016 18:18:49 +0200 Subject: [PATCH 2/3] main: create /run/NetworkManager/devices runtime directory --- src/main-utils.c | 15 ++++++++++++++- src/nm-config.h | 6 ++++++ 2 files changed, 20 insertions(+), 1 deletion(-) 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/nm-config.h b/src/nm-config.h index a75e393523..ef5430ee6c 100644 --- a/src/nm-config.h +++ b/src/nm-config.h @@ -185,5 +185,11 @@ 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" + +/*****************************************************************************/ + #endif /* __NETWORKMANAGER_CONFIG_H__ */ From 93396b8d526e99ac26a6e9c9d9b783333fc9b88e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 23 Sep 2016 17:36:21 +0200 Subject: [PATCH 3/3] config: store and load device runtime state to file The data is still unused, the actual fields might change. Note that the actual state we store is subject to change, according to which data we need. The file format is non stable, as the files don't survive reboot. So there is no backward compatibility to maintain and the format can be changed later. --- src/main.c | 7 ++ src/nm-config.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++ src/nm-config.h | 23 ++++++ src/nm-manager.c | 64 +++++++++++++++-- src/nm-manager.h | 2 + 5 files changed, 270 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..8536a77fd5 100644 --- a/src/nm-config.c +++ b/src/nm-config.c @@ -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) { 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);