about summary refs log tree commit diff
path: root/src/settings/nm-settings.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings/nm-settings.c')
-rw-r--r--src/settings/nm-settings.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 9ed03f69..9d40b06e 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -151,6 +151,8 @@ typedef struct {
 	GSList *unmanaged_specs;
 	GSList *unrecognized_specs;
 	GSList *get_connections_cache;
+
+	gboolean startup_complete;
 } NMSettingsPrivate;
 
 #define NM_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTINGS, NMSettingsPrivate))
@@ -175,11 +177,43 @@ enum {
 	PROP_HOSTNAME,
 	PROP_CAN_MODIFY,
 	PROP_CONNECTIONS,
+	PROP_STARTUP_COMPLETE,
 
 	LAST_PROP
 };
 
 static void
+check_startup_complete (NMSettings *self)
+{
+	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
+	GHashTableIter iter;
+	NMSettingsConnection *conn;
+
+	if (priv->startup_complete)
+		return;
+
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &conn)) {
+		if (!nm_settings_connection_get_ready (conn))
+			return;
+	}
+
+	priv->startup_complete = TRUE;
+	g_object_notify (G_OBJECT (self), NM_SETTINGS_STARTUP_COMPLETE);
+}
+
+static void
+connection_ready_changed (NMSettingsConnection *conn,
+                          GParamSpec *pspec,
+                          gpointer user_data)
+{
+	NMSettings *self = NM_SETTINGS (user_data);
+
+	if (nm_settings_connection_get_ready (conn))
+		check_startup_complete (self);
+}
+
+static void
 plugin_connection_added (NMSystemConfigInterface *config,
                          NMSettingsConnection *connection,
                          gpointer user_data)
@@ -772,6 +806,7 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data)
 	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_updated), self);
 	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_updated_by_user), self);
 	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_visibility_changed), self);
+	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_ready_changed), self);
 
 	/* Forget about the connection internally */
 	g_hash_table_remove (NM_SETTINGS_GET_PRIVATE (user_data)->connections,
@@ -784,6 +819,8 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data)
 	g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTION_REMOVED, connection);
 	g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTIONS);
 
+	check_startup_complete (self);
+
 	g_object_unref (connection);
 }
 
@@ -850,6 +887,7 @@ claim_connection (NMSettings *self,
 	GHashTableIter iter;
 	gpointer data;
 	char *path;
+	NMSettingsConnection *existing;
 
 	g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection));
 	g_return_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL);
@@ -868,6 +906,23 @@ claim_connection (NMSettings *self,
 		return;
 	}
 
+	existing = nm_settings_get_connection_by_uuid (self, nm_connection_get_uuid (NM_CONNECTION (connection)));
+	if (existing) {
+		/* Cannot add duplicate connections per UUID. Just return without action and
+		 * log a warning.
+		 *
+		 * This means, that plugins must not provide duplicate connections (UUID).
+		 * In fact, none of the plugins currently would do that.
+		 *
+		 * But globaly, over different setting plugins, there could be duplicates
+		 * without the individual plugins being aware. Don't handle that at all, just
+		 * error out. That should not happen unless the admin misconfigured the system
+		 * to create conflicting connections. */
+		nm_log_warn (LOGD_SETTINGS, "plugin provided duplicate connection with UUID %s",
+		             nm_connection_get_uuid (NM_CONNECTION (connection)));
+		return;
+	}
+
 	/* Read timestamp from look-aside file and put it into the connection's data */
 	nm_settings_connection_read_and_fill_timestamp (connection);
 
@@ -889,6 +944,11 @@ claim_connection (NMSettings *self,
 	g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_VISIBLE,
 	                  G_CALLBACK (connection_visibility_changed),
 	                  self);
+	if (!priv->startup_complete) {
+		g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_READY,
+		                  G_CALLBACK (connection_ready_changed),
+		                  self);
+	}
 
 	/* Export the connection over D-Bus */
 	g_warn_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL);
@@ -1780,6 +1840,16 @@ cp_get_connection_by_uuid (NMConnectionProvider *provider, const char *uuid)
 
 /***************************************************************/
 
+gboolean
+nm_settings_get_startup_complete (NMSettings *self)
+{
+	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
+
+	return priv->startup_complete;
+}
+
+/***************************************************************/
+
 NMSettings *
 nm_settings_new (GError **error)
 {
@@ -1800,6 +1870,7 @@ nm_settings_new (GError **error)
 	}
 
 	load_connections (self);
+	check_startup_complete (self);
 
 	nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH_SETTINGS, self);
 	return self;
@@ -1900,6 +1971,9 @@ get_property (GObject *object, guint prop_id,
 			g_ptr_array_add (array, g_strdup (path));
 		g_value_take_boxed (value, array);
 		break;
+	case PROP_STARTUP_COMPLETE:
+		g_value_set_boolean (value, nm_settings_get_startup_complete (self));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;