about summary refs log tree commit diff
path: root/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c')
-rw-r--r--src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c286
1 files changed, 183 insertions, 103 deletions
diff --git a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
index 04d3d3e4..3db06f17 100644
--- a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
+++ b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c
@@ -35,10 +35,12 @@
 #include <nm-setting-8021x.h>
 
 #include "common.h"
+#include "nm-config.h"
 #include "nm-ifcfg-connection.h"
 #include "reader.h"
 #include "writer.h"
 #include "nm-inotify-helper.h"
+#include "utils.h"
 
 G_DEFINE_TYPE (NMIfcfgConnection, nm_ifcfg_connection, NM_TYPE_SETTINGS_CONNECTION)
 
@@ -59,12 +61,14 @@ typedef struct {
 	char *route6file;
 	int route6file_wd;
 
-	char *unmanaged;
+	char *unmanaged_spec;
+	char *unrecognized_spec;
 } NMIfcfgConnectionPrivate;
 
 enum {
 	PROP_0,
-	PROP_UNMANAGED,
+	PROP_UNMANAGED_SPEC,
+	PROP_UNRECOGNIZED_SPEC,
 	LAST_PROP
 };
 
@@ -96,86 +100,159 @@ files_changed_cb (NMInotifyHelper *ih,
 }
 
 NMIfcfgConnection *
-nm_ifcfg_connection_new (const char *full_path,
-                         NMConnection *source,
+nm_ifcfg_connection_new (NMConnection *source,
+                         const char *full_path,
                          GError **error,
                          gboolean *ignore_error)
 {
 	GObject *object;
-	NMIfcfgConnectionPrivate *priv;
 	NMConnection *tmp;
-	char *unmanaged = NULL;
-	char *keyfile = NULL;
-	char *routefile = NULL;
-	char *route6file = NULL;
-	NMInotifyHelper *ih;
+	char *unhandled_spec = NULL;
+	const char *unmanaged_spec = NULL, *unrecognized_spec = NULL;
+	gboolean update_unsaved = TRUE;
 
-	g_return_val_if_fail (full_path != NULL, NULL);
+	g_assert (source || full_path);
 
 	/* If we're given a connection already, prefer that instead of re-reading */
 	if (source)
 		tmp = g_object_ref (source);
 	else {
+		char *keyfile = NULL, *routefile = NULL, *route6file = NULL;
+
 		tmp = connection_from_file (full_path, NULL, NULL, NULL,
-		                            &unmanaged,
+		                            &unhandled_spec,
 		                            &keyfile,
 		                            &routefile,
 		                            &route6file,
 		                            error,
 		                            ignore_error);
+		g_free (keyfile);
+		g_free (routefile);
+		g_free (route6file);
 		if (!tmp)
 			return NULL;
+
+		/* If we just read the connection from disk, it's clearly not Unsaved */
+		update_unsaved = FALSE;
 	}
 
+	if (unhandled_spec && g_str_has_prefix (unhandled_spec, "unmanaged:"))
+		unmanaged_spec = unhandled_spec + strlen ("unmanaged:");
+	else if (unhandled_spec && g_str_has_prefix (unhandled_spec, "unrecognized:"))
+		unrecognized_spec = unhandled_spec + strlen ("unrecognized:");
+
 	object = (GObject *) g_object_new (NM_TYPE_IFCFG_CONNECTION,
-	                                   NM_IFCFG_CONNECTION_UNMANAGED, unmanaged,
+	                                   NM_IFCFG_CONNECTION_UNMANAGED_SPEC, unmanaged_spec,
+	                                   NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC, unrecognized_spec,
 	                                   NULL);
-	if (!object)
-		goto out;
-
-	/* Update our settings with what was read from the file */
-	if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), tmp, error)) {
-		g_object_unref (object);
-		object = NULL;
-		goto out;
+	if (object) {
+		/* Update our settings with what was read from the file */
+		if (nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object),
+		                                             tmp,
+		                                             update_unsaved,
+		                                             error)) {
+			/* Set the path and start monitoring */
+			if (full_path)
+				nm_ifcfg_connection_set_path (NM_IFCFG_CONNECTION (object), full_path);
+		} else {
+			g_object_unref (object);
+			object = NULL;
+		}
 	}
 
-	priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
-	priv->path = g_strdup (full_path);
+	g_object_unref (tmp);
+	g_free (unhandled_spec);
+	return (NMIfcfgConnection *) object;
+}
+
+const char *
+nm_ifcfg_connection_get_path (NMIfcfgConnection *self)
+{
+	g_return_val_if_fail (NM_IS_IFCFG_CONNECTION (self), NULL);
+
+	return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->path;
+}
+
+static void
+path_watch_stop (NMIfcfgConnection *self)
+{
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self);
+	NMInotifyHelper *ih;
 
 	ih = nm_inotify_helper_get ();
-	priv->ih_event_id = g_signal_connect (ih, "event", G_CALLBACK (files_changed_cb), object);
 
-	priv->file_wd = nm_inotify_helper_add_watch (ih, full_path);
+	if (priv->ih_event_id) {
+		g_signal_handler_disconnect (ih, priv->ih_event_id);
+		priv->ih_event_id = 0;
+	}
 
-	priv->keyfile = keyfile;
-	priv->keyfile_wd = nm_inotify_helper_add_watch (ih, keyfile);
+	if (priv->file_wd >= 0) {
+		nm_inotify_helper_remove_watch (ih, priv->file_wd);
+		priv->file_wd = -1;
+	}
 
-	priv->routefile = routefile;
-	priv->routefile_wd = nm_inotify_helper_add_watch (ih, routefile);
+	g_free (priv->keyfile);
+	priv->keyfile = NULL;
+	if (priv->keyfile_wd >= 0) {
+		nm_inotify_helper_remove_watch (ih, priv->keyfile_wd);
+		priv->keyfile_wd = -1;
+	}
 
-	priv->route6file = route6file;
-	priv->route6file_wd = nm_inotify_helper_add_watch (ih, route6file);
+	g_free (priv->routefile);
+	priv->routefile = NULL;
+	if (priv->routefile_wd >= 0) {
+		nm_inotify_helper_remove_watch (ih, priv->routefile_wd);
+		priv->routefile_wd = -1;
+	}
 
-out:
-	g_object_unref (tmp);
-	return (NMIfcfgConnection *) object;
+	g_free (priv->route6file);
+	priv->route6file = NULL;
+	if (priv->route6file_wd >= 0) {
+		nm_inotify_helper_remove_watch (ih, priv->route6file_wd);
+		priv->route6file_wd = -1;
+	}
+}
+
+void
+nm_ifcfg_connection_set_path (NMIfcfgConnection *self, const char *ifcfg_path)
+{
+	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self);
+
+	g_return_if_fail (ifcfg_path != NULL);
+
+	path_watch_stop (self);
+	g_free (priv->path);
+
+	priv->path = g_strdup (ifcfg_path);
+	priv->keyfile = utils_get_keys_path (ifcfg_path);
+	priv->routefile = utils_get_route_path (ifcfg_path);
+	priv->route6file = utils_get_route6_path (ifcfg_path);
+
+	if (nm_config_get_monitor_connection_files (nm_config_get ())) {
+		NMInotifyHelper *ih = nm_inotify_helper_get ();
+
+		priv->ih_event_id = g_signal_connect (ih, "event", G_CALLBACK (files_changed_cb), self);
+		priv->file_wd = nm_inotify_helper_add_watch (ih, ifcfg_path);
+		priv->keyfile_wd = nm_inotify_helper_add_watch (ih, priv->keyfile);
+		priv->routefile_wd = nm_inotify_helper_add_watch (ih, priv->routefile);
+		priv->route6file_wd = nm_inotify_helper_add_watch (ih, priv->route6file);
+	}
 }
 
 const char *
-nm_ifcfg_connection_get_path (NMIfcfgConnection *self)
+nm_ifcfg_connection_get_unmanaged_spec (NMIfcfgConnection *self)
 {
 	g_return_val_if_fail (NM_IS_IFCFG_CONNECTION (self), NULL);
 
-	return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->path;
+	return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->unmanaged_spec;
 }
 
 const char *
-nm_ifcfg_connection_get_unmanaged_spec (NMIfcfgConnection *self)
+nm_ifcfg_connection_get_unrecognized_spec (NMIfcfgConnection *self)
 {
 	g_return_val_if_fail (NM_IS_IFCFG_CONNECTION (self), NULL);
 
-	return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->unmanaged;
+	return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->unrecognized_spec;
 }
 
 static void
@@ -186,41 +263,50 @@ commit_changes (NMSettingsConnection *connection,
 	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (connection);
 	GError *error = NULL;
 	NMConnection *reread;
-	char *unmanaged = NULL, *keyfile = NULL, *routefile = NULL, *route6file = NULL;
-	gboolean same = FALSE;
+	gboolean same = FALSE, success = FALSE;
+	char *ifcfg_path = NULL;
 
 	/* To ensure we don't rewrite files that are only changed from other
 	 * processes on-disk, read the existing connection back in and only rewrite
 	 * it if it's really changed.
 	 */
-	reread = connection_from_file (priv->path, NULL, NULL, NULL,
-	                               &unmanaged, &keyfile, &routefile, &route6file,
-	                               NULL, NULL);
-	g_free (unmanaged);
-	g_free (keyfile);
-	g_free (routefile);
-	g_free (route6file);
-
-	if (reread) {
-		same = nm_connection_compare (NM_CONNECTION (connection),
-		                              reread,
-		                              NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
-		                                NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS);
-		g_object_unref (reread);
-
-		/* Don't bother writing anything out if in-memory and on-disk data are the same */
-		if (same) {
-			/* But chain up to parent to handle success - emits updated signal */
-			NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->commit_changes (connection, callback, user_data);
-			return;
+	if (priv->path) {
+		reread = connection_from_file (priv->path, NULL, NULL, NULL,
+		                               NULL, NULL, NULL, NULL,
+		                               &error, NULL);
+		g_clear_error (&error);
+		if (reread) {
+			same = nm_connection_compare (NM_CONNECTION (connection),
+			                              reread,
+			                              NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
+			                                 NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS);
+			g_object_unref (reread);
+
+			/* Don't bother writing anything out if in-memory and on-disk data are the same */
+			if (same) {
+				/* But chain up to parent to handle success - emits updated signal */
+				NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->commit_changes (connection, callback, user_data);
+				return;
+			}
+		}
+
+		success = writer_update_connection (NM_CONNECTION (connection),
+		                                    IFCFG_DIR,
+		                                    priv->path,
+		                                    priv->keyfile,
+		                                    &error);
+	} else {
+		success = writer_new_connection (NM_CONNECTION (connection),
+		                                 IFCFG_DIR,
+		                                 &ifcfg_path,
+		                                 &error);
+		if (success) {
+			nm_ifcfg_connection_set_path (NM_IFCFG_CONNECTION (connection), ifcfg_path);
+			g_free (ifcfg_path);
 		}
 	}
 
-	if (writer_update_connection (NM_CONNECTION (connection),
-	                              IFCFG_DIR,
-	                              priv->path,
-	                              priv->keyfile,
-	                              &error)) {
+	if (success) {
 		/* Chain up to parent to handle success */
 		NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->commit_changes (connection, callback, user_data);
 	} else {
@@ -237,14 +323,16 @@ do_delete (NMSettingsConnection *connection,
 {
 	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (connection);
 
-	g_unlink (priv->path);
-	if (priv->keyfile)
-		g_unlink (priv->keyfile);
-	if (priv->routefile)
-		g_unlink (priv->routefile);
+	if (priv->path) {
+		g_unlink (priv->path);
+		if (priv->keyfile)
+			g_unlink (priv->keyfile);
+		if (priv->routefile)
+			g_unlink (priv->routefile);
 
-	if (priv->route6file)
-		g_unlink (priv->route6file);
+		if (priv->route6file)
+			g_unlink (priv->route6file);
+	}
 
 	NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->delete (connection, callback, user_data);
 }
@@ -259,31 +347,10 @@ nm_ifcfg_connection_init (NMIfcfgConnection *connection)
 static void
 finalize (GObject *object)
 {
-	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
-	NMInotifyHelper *ih;
-
 	nm_connection_clear_secrets (NM_CONNECTION (object));
 
-	ih = nm_inotify_helper_get ();
-
-	if (priv->ih_event_id)
-		g_signal_handler_disconnect (ih, priv->ih_event_id);
-
-	g_free (priv->path);
-	if (priv->file_wd >= 0)
-		nm_inotify_helper_remove_watch (ih, priv->file_wd);
-
-	g_free (priv->keyfile);
-	if (priv->keyfile_wd >= 0)
-		nm_inotify_helper_remove_watch (ih, priv->keyfile_wd);
-
-	g_free (priv->routefile);
-	if (priv->routefile_wd >= 0)
-		nm_inotify_helper_remove_watch (ih, priv->routefile_wd);
-
-	g_free (priv->route6file);
-	if (priv->route6file_wd >= 0)
-		nm_inotify_helper_remove_watch (ih, priv->route6file_wd);
+	path_watch_stop (NM_IFCFG_CONNECTION (object));
+	g_free (NM_IFCFG_CONNECTION_GET_PRIVATE (object)->path);
 
 	G_OBJECT_CLASS (nm_ifcfg_connection_parent_class)->finalize (object);
 }
@@ -295,8 +362,11 @@ set_property (GObject *object, guint prop_id,
 	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
 
 	switch (prop_id) {
-	case PROP_UNMANAGED:
-		priv->unmanaged = g_value_dup_string (value);
+	case PROP_UNMANAGED_SPEC:
+		priv->unmanaged_spec = g_value_dup_string (value);
+		break;
+	case PROP_UNRECOGNIZED_SPEC:
+		priv->unrecognized_spec = g_value_dup_string (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -311,8 +381,11 @@ get_property (GObject *object, guint prop_id,
 	NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
 
 	switch (prop_id) {
-	case PROP_UNMANAGED:
-		g_value_set_string (value, priv->unmanaged);
+	case PROP_UNMANAGED_SPEC:
+		g_value_set_string (value, priv->unmanaged_spec);
+		break;
+	case PROP_UNRECOGNIZED_SPEC:
+		g_value_set_string (value, priv->unrecognized_spec);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -337,12 +410,19 @@ nm_ifcfg_connection_class_init (NMIfcfgConnectionClass *ifcfg_connection_class)
 
 	/* Properties */
 	g_object_class_install_property
-		(object_class, PROP_UNMANAGED,
-		 g_param_spec_string (NM_IFCFG_CONNECTION_UNMANAGED,
-						  "Unmanaged",
-						  "Unmanaged",
+		(object_class, PROP_UNMANAGED_SPEC,
+		 g_param_spec_string (NM_IFCFG_CONNECTION_UNMANAGED_SPEC,
+						  "Unmanaged spec",
+						  "Unmanaged spec",
 						  NULL,
 						  G_PARAM_READWRITE));
+	g_object_class_install_property
+		(object_class, PROP_UNRECOGNIZED_SPEC,
+		 g_param_spec_string (NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC,
+		                      "Unrecognized spec",
+		                      "Unrecognized spec",
+		                      NULL,
+		                      G_PARAM_READWRITE));
 
 	signals[IFCFG_CHANGED] =
 		g_signal_new ("ifcfg-changed",