summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-12-11 14:38:03 +0100
committerThomas Haller <thaller@redhat.com>2015-01-07 12:16:56 +0100
commitf5eb84ea5258c59e0d6ff71cb6fff210e9a45a84 (patch)
tree4f77a39cc30f3bdf7b388bb92c849055b5b4fe8f
parent49b52e21dc9e2a25a5f35f015e2ff3361996b43d (diff)
downloadNetworkManager-f5eb84ea5258c59e0d6ff71cb6fff210e9a45a84.tar.gz
ifcfg-rh: sort paths in read_connections()
Presort the files in read_connections() as we do it for keyfile. This alone has not much consequences. Do this patch first, to keep the next patches more self-contained.
-rw-r--r--src/settings/plugins/ifcfg-rh/plugin.c79
1 files changed, 72 insertions, 7 deletions
diff --git a/src/settings/plugins/ifcfg-rh/plugin.c b/src/settings/plugins/ifcfg-rh/plugin.c
index c7eb7365fa..580da7c917 100644
--- a/src/settings/plugins/ifcfg-rh/plugin.c
+++ b/src/settings/plugins/ifcfg-rh/plugin.c
@@ -464,6 +464,43 @@ setup_ifcfg_monitoring (SCPluginIfcfg *plugin)
}
}
+static GHashTable *
+_paths_from_connections (GHashTable *connections)
+{
+ GHashTableIter iter;
+ NMIfcfgConnection *connection;
+ GHashTable *paths = g_hash_table_new (g_str_hash, g_str_equal);
+
+ g_hash_table_iter_init (&iter, connections);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &connection)) {
+ const char *path = nm_ifcfg_connection_get_path (connection);
+
+ if (path)
+ g_hash_table_add (paths, (void *) path);
+ }
+ return paths;
+}
+
+static int
+_sort_paths (const char **f1, const char **f2, GHashTable *paths)
+{
+ struct stat st;
+ gboolean c1, c2;
+ gint64 m1, m2;
+
+ c1 = !!g_hash_table_contains (paths, *f1);
+ c2 = !!g_hash_table_contains (paths, *f2);
+ if (c1 != c2)
+ return c1 ? -1 : 1;
+
+ m1 = stat (*f1, &st) == 0 ? (gint64) st.st_mtime : G_MININT64;
+ m2 = stat (*f2, &st) == 0 ? (gint64) st.st_mtime : G_MININT64;
+ if (m1 != m2)
+ return m1 > m2 ? -1 : 1;
+
+ return strcmp (*f1, *f2);
+}
+
static void
read_connections (SCPluginIfcfg *plugin)
{
@@ -475,6 +512,9 @@ read_connections (SCPluginIfcfg *plugin)
GHashTableIter iter;
gpointer key, value;
NMIfcfgConnection *connection;
+ guint i;
+ GPtrArray *filenames;
+ GHashTable *paths;
dir = g_dir_open (IFCFG_DIR, 0, &err);
if (!dir) {
@@ -491,8 +531,9 @@ read_connections (SCPluginIfcfg *plugin)
g_hash_table_insert (oldconns, g_strdup (ifcfg_path), value);
}
+ filenames = g_ptr_array_new_with_free_func (g_free);
while ((item = g_dir_read_name (dir))) {
- char *full_path, *old_path;
+ char *full_path;
if (utils_should_ignore_file (item, TRUE))
continue;
@@ -501,8 +542,36 @@ read_connections (SCPluginIfcfg *plugin)
full_path = g_build_filename (IFCFG_DIR, item, NULL);
if (!utils_get_ifcfg_name (full_path, TRUE))
- goto next;
+ g_free (full_path);
+ else
+ g_ptr_array_add (filenames, full_path);
+ }
+ g_dir_close (dir);
+ /* While reloading, we don't replace connections that we already loaded while
+ * iterating over the files.
+ *
+ * To have sensible, reproducible behavior, sort the paths by last modification
+ * time.
+ *
+ * However, using an explicit load, the user still can load a file that would
+ * normally be shaddowed by another file. We want to stick with that user choice
+ * on the next reload. Hence, we firstly prefer filenames that we already loaded
+ * previously (@paths). On second priority, we sort by file modification timestamp.
+ *
+ * For ifcfg-rh this is less shiny then for keyfile because there might be more
+ * then one file. Still it's better then nothing (avoiding the complications to
+ * look for all files).
+ */
+ paths = _paths_from_connections (priv->connections);
+ g_ptr_array_sort_with_data (filenames, (GCompareDataFunc) _sort_paths, paths);
+ g_hash_table_destroy (paths);
+
+ for (i = 0; i < filenames->len; i++) {
+ const char *full_path;
+ char *old_path;
+
+ full_path = filenames->pdata[i];
connection = g_hash_table_lookup (oldconns, full_path);
g_hash_table_remove (oldconns, full_path);
update_connection (plugin, NULL, full_path, connection, NULL, &old_path, NULL);
@@ -511,12 +580,8 @@ read_connections (SCPluginIfcfg *plugin)
g_hash_table_remove (oldconns, old_path);
g_free (old_path);
}
-
- next:
- g_free (full_path);
}
-
- g_dir_close (dir);
+ g_ptr_array_free (filenames, TRUE);
g_hash_table_iter_init (&iter, oldconns);
while (g_hash_table_iter_next (&iter, &key, &value)) {