diff --git a/introspection/nm-settings.xml b/introspection/nm-settings.xml index f10a6e1c6..f816b0870 100644 --- a/introspection/nm-settings.xml +++ b/introspection/nm-settings.xml @@ -29,6 +29,11 @@ Connection settings and properties. + + + Object path of the new connection that was just added. + + diff --git a/libnm-glib/nm-remote-settings.c b/libnm-glib/nm-remote-settings.c index f263df29f..7b614854a 100644 --- a/libnm-glib/nm-remote-settings.c +++ b/libnm-glib/nm-remote-settings.c @@ -154,12 +154,12 @@ connection_init_result_cb (NMRemoteConnection *remote, g_signal_emit (self, signals[CONNECTIONS_READ], 0); } -static void +static NMRemoteConnection * new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data) { NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data); NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self); - NMRemoteConnection *connection; + NMRemoteConnection *connection = NULL; connection = nm_remote_connection_new (priv->bus, path); if (connection) { @@ -177,6 +177,7 @@ new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data) */ g_hash_table_insert (priv->pending, g_strdup (path), connection); } + return connection; } static void @@ -205,17 +206,17 @@ fetch_connections_done (DBusGProxy *proxy, } /* Let listeners know we are done getting connections */ - if (connections->len == 0) { + if (connections->len == 0) g_signal_emit (self, signals[CONNECTIONS_READ], 0); - return; + else { + for (i = 0; i < connections->len; i++) { + char *path = g_ptr_array_index (connections, i); + + new_connection_cb (proxy, path, user_data); + g_free (path); + } } - for (i = 0; connections && (i < connections->len); i++) { - char *path = g_ptr_array_index (connections, i); - - new_connection_cb (proxy, path, user_data); - g_free (path); - } g_ptr_array_free (connections, TRUE); } @@ -268,13 +269,19 @@ typedef struct { static void add_connection_done (DBusGProxy *proxy, + char *path, GError *error, gpointer user_data) { AddConnectionInfo *info = user_data; + NMRemoteConnection *connection; + + connection = new_connection_cb (proxy, path, info->self); + g_assert (connection); + info->callback (info->self, connection, error, info->callback_data); - info->callback (info->self, error, info->callback_data); g_free (info); + g_free (path); } /** * nm_remote_settings_add_connection: diff --git a/libnm-glib/nm-remote-settings.h b/libnm-glib/nm-remote-settings.h index a1d3cee83..78c7e827f 100644 --- a/libnm-glib/nm-remote-settings.h +++ b/libnm-glib/nm-remote-settings.h @@ -51,6 +51,7 @@ typedef struct _NMRemoteSettingsClass NMRemoteSettingsClass; typedef void (*NMRemoteSettingsAddConnectionFunc) (NMRemoteSettings *settings, + NMRemoteConnection *connection, GError *error, gpointer user_data); diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 37621c063..3b1653995 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -129,7 +129,6 @@ enum { NEW_CONNECTION, /* exported, not used internally */ LAST_SIGNAL }; - static guint signals[LAST_SIGNAL] = { 0 }; enum { @@ -575,16 +574,45 @@ load_plugins (NMSettings *self, const char *plugins, GError **error) return success; } +#define REMOVED_ID_TAG "removed-id-tag" +#define UPDATED_ID_TAG "updated-id-tag" +#define VISIBLE_ID_TAG "visible-id-tag" + static void -connection_removed (NMSysconfigConnection *connection, gpointer user_data) +connection_removed (NMSysconfigConnection *obj, gpointer user_data) { + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (user_data); + GObject *connection = G_OBJECT (obj); + guint id; + g_object_ref (connection); - g_hash_table_remove (NM_SETTINGS_GET_PRIVATE (user_data)->connections, connection); + /* Disconnect signal handlers, as plugins might still keep references + * to the connection (and thus the signal handlers would still be live) + * even after NMSettings has dropped all its references. + */ + + id = GPOINTER_TO_UINT (g_object_get_data (connection, REMOVED_ID_TAG)); + if (id) + g_signal_handler_disconnect (connection, id); + + id = GPOINTER_TO_UINT (g_object_get_data (connection, UPDATED_ID_TAG)); + if (id) + g_signal_handler_disconnect (connection, id); + + id = GPOINTER_TO_UINT (g_object_get_data (connection, VISIBLE_ID_TAG)); + if (id) + g_signal_handler_disconnect (connection, id); + + /* Unregister the connection with D-Bus and forget about it */ + dbus_g_connection_unregister_g_object (priv->bus, connection); + g_hash_table_remove (NM_SETTINGS_GET_PRIVATE (user_data)->connections, + (gpointer) nm_connection_get_path (NM_CONNECTION (connection))); g_signal_emit (NM_SETTINGS (user_data), signals[CONNECTION_REMOVED], 0, connection); + g_object_unref (connection); } @@ -619,6 +647,7 @@ claim_connection (NMSettings *self, GHashTableIter iter; gpointer data; char *path; + guint id; g_return_if_fail (NM_IS_SYSCONFIG_CONNECTION (connection)); @@ -640,19 +669,20 @@ claim_connection (NMSettings *self, /* Ensure it's initial visibility is up-to-date */ nm_sysconfig_connection_recheck_visibility (connection); - g_signal_connect (connection, - NM_SYSCONFIG_CONNECTION_REMOVED, - G_CALLBACK (connection_removed), - self); + id = g_signal_connect (connection, NM_SYSCONFIG_CONNECTION_REMOVED, + G_CALLBACK (connection_removed), + self); + g_object_set_data (G_OBJECT (connection), REMOVED_ID_TAG, GUINT_TO_POINTER (id)); - g_signal_connect (connection, - NM_SYSCONFIG_CONNECTION_UPDATED, - G_CALLBACK (connection_updated), - self); + id = g_signal_connect (connection, NM_SYSCONFIG_CONNECTION_UPDATED, + G_CALLBACK (connection_updated), + self); + g_object_set_data (G_OBJECT (connection), UPDATED_ID_TAG, GUINT_TO_POINTER (id)); - g_signal_connect (connection, "notify::" NM_SYSCONFIG_CONNECTION_VISIBLE, - G_CALLBACK (connection_visibility_changed), - self); + id = g_signal_connect (connection, "notify::" NM_SYSCONFIG_CONNECTION_VISIBLE, + G_CALLBACK (connection_visibility_changed), + self); + g_object_set_data (G_OBJECT (connection), VISIBLE_ID_TAG, GUINT_TO_POINTER (id)); /* Export the connection over D-Bus */ g_warn_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL); @@ -750,7 +780,7 @@ polkit_call_free (PolkitCall *call) g_free (call); } -static gboolean +static NMSysconfigConnection * add_new_connection (NMSettings *self, NMConnection *connection, GError **error) @@ -758,29 +788,28 @@ add_new_connection (NMSettings *self, NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GError *tmp_error = NULL, *last_error = NULL; GSList *iter; - gboolean success = FALSE; + NMSysconfigConnection *added = NULL; - /* Here's how it works: - 1) plugin writes a connection. - 2) plugin notices that a new connection is available for reading. - 3) plugin reads the new connection (the one it wrote in 1) and emits 'connection-added' signal. - 4) NMSettings receives the signal and adds it to it's connection list. - */ - - for (iter = priv->plugins; iter && !success; iter = iter->next) { - success = nm_system_config_interface_add_connection (NM_SYSTEM_CONFIG_INTERFACE (iter->data), - connection, - &tmp_error); + /* 1) plugin writes the NMConnection to disk + * 2) plugin creates a new NMSysconfigConnection subclass with the settings + * from the NMConnection and returns it to the settings service + * 3) settings service exports the new NMSysconfigConnection subclass + * 4) plugin notices that something on the filesystem has changed + * 5) plugin reads the changes and ignores them because they will + * contain the same data as the connection it already knows about + */ + for (iter = priv->plugins; iter && !added; iter = g_slist_next (iter)) { + added = nm_system_config_interface_add_connection (NM_SYSTEM_CONFIG_INTERFACE (iter->data), + connection, + &tmp_error); g_clear_error (&last_error); - if (!success) { - last_error = tmp_error; - tmp_error = NULL; - } + if (!added) + g_propagate_error (&last_error, tmp_error); } - if (!success) - *error = last_error; - return success; + if (!added) + g_propagate_error (error, last_error); + return added; } static void @@ -791,6 +820,7 @@ pk_add_cb (GObject *object, GAsyncResult *result, gpointer user_data) NMSettingsPrivate *priv; PolkitAuthorizationResult *pk_result; GError *error = NULL, *add_error = NULL; + NMSysconfigConnection *added_connection; /* If NMSettings is already gone, do nothing */ if (call->disposed) { @@ -825,8 +855,9 @@ pk_add_cb (GObject *object, GAsyncResult *result, gpointer user_data) goto out; } - if (add_new_connection (self, call->connection, &add_error)) - dbus_g_method_return (call->context); + added_connection = add_new_connection (self, call->connection, &add_error); + if (added_connection) + dbus_g_method_return (call->context, added_connection); else { error = g_error_new (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_ADD_FAILED, @@ -1201,6 +1232,7 @@ default_wired_try_update (NMDefaultWiredConnection *wired, GError *error = NULL; NMSettingConnection *s_con; const char *id; + NMSysconfigConnection *added; /* Try to move this default wired conneciton to a plugin so that it has * persistent storage. @@ -1213,7 +1245,8 @@ default_wired_try_update (NMDefaultWiredConnection *wired, g_assert (id); remove_default_wired_connection (self, NM_SYSCONFIG_CONNECTION (wired), FALSE); - if (add_new_connection (self, NM_CONNECTION (wired), &error)) { + added = add_new_connection (self, NM_CONNECTION (wired), &error); + if (added) { nm_sysconfig_connection_delete (NM_SYSCONFIG_CONNECTION (wired), delete_cb, NULL); @@ -1229,6 +1262,7 @@ default_wired_try_update (NMDefaultWiredConnection *wired, id, error ? error->code : -1, (error && error->message) ? error->message : "(unknown)"); + g_clear_error (&error); /* If there was an error, don't destroy the default wired connection, * but add it back to the system settings service. Connection is already diff --git a/src/settings/nm-system-config-interface.c b/src/settings/nm-system-config-interface.c index f522a9b44..b5f9d7207 100644 --- a/src/settings/nm-system-config-interface.c +++ b/src/settings/nm-system-config-interface.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2007 - 2008 Red Hat, Inc. + * Copyright (C) 2007 - 2010 Red Hat, Inc. * Copyright (C) 2008 Novell, Inc. */ @@ -146,18 +146,16 @@ nm_system_config_interface_get_unmanaged_specs (NMSystemConfigInterface *config) return NULL; } -gboolean +NMSysconfigConnection * nm_system_config_interface_add_connection (NMSystemConfigInterface *config, NMConnection *connection, GError **error) { - gboolean success = FALSE; - g_return_val_if_fail (config != NULL, FALSE); g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection) - success = NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection (config, connection, error); + return NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection (config, connection, error); - return success; + return NULL; } diff --git a/src/settings/nm-system-config-interface.h b/src/settings/nm-system-config-interface.h index 439586a40..f31beabc3 100644 --- a/src/settings/nm-system-config-interface.h +++ b/src/settings/nm-system-config-interface.h @@ -117,11 +117,13 @@ struct _NMSystemConfigInterface { GSList * (*get_unmanaged_specs) (NMSystemConfigInterface *config); /* - * Add a new connection. + * Save the given connection to backing storage, and return a new + * NMSysconfigConnection subclass that contains the same settings as the + * original connection. */ - gboolean (*add_connection) (NMSystemConfigInterface *config, - NMConnection *connection, - GError **error); + NMSysconfigConnection * (*add_connection) (NMSystemConfigInterface *config, + NMConnection *connection, + GError **error); /* Signals */ @@ -142,9 +144,9 @@ GSList *nm_system_config_interface_get_connections (NMSystemConfigInterface *con GSList *nm_system_config_interface_get_unmanaged_specs (NMSystemConfigInterface *config); -gboolean nm_system_config_interface_add_connection (NMSystemConfigInterface *config, - NMConnection *connection, - GError **error); +NMSysconfigConnection *nm_system_config_interface_add_connection (NMSystemConfigInterface *config, + NMConnection *connection, + GError **error); G_END_DECLS diff --git a/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c b/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c index 221230525..d43ab103f 100644 --- a/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c +++ b/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2008 - 2009 Red Hat, Inc. + * Copyright (C) 2008 - 2010 Red Hat, Inc. */ #include @@ -47,7 +47,7 @@ G_DEFINE_TYPE (NMIfcfgConnection, nm_ifcfg_connection, NM_TYPE_SYSCONFIG_CONNECT typedef struct { gulong ih_event_id; - char *filename; + char *path; int file_wd; char *keyfile; @@ -64,9 +64,7 @@ typedef struct { enum { PROP_0, - PROP_FILENAME, PROP_UNMANAGED, - LAST_PROP }; @@ -87,7 +85,10 @@ files_changed_cb (NMInotifyHelper *ih, NMIfcfgConnection *self = NM_IFCFG_CONNECTION (user_data); NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self); - if ((evt->wd != priv->file_wd) && (evt->wd != priv->keyfile_wd) && (evt->wd != priv->routefile_wd) && (evt->wd != priv->route6file_wd)) + if ( (evt->wd != priv->file_wd) + && (evt->wd != priv->keyfile_wd) + && (evt->wd != priv->routefile_wd) + && (evt->wd != priv->route6file_wd)) return; /* push the event up to the plugin */ @@ -95,7 +96,8 @@ files_changed_cb (NMInotifyHelper *ih, } NMIfcfgConnection * -nm_ifcfg_connection_new (const char *filename, +nm_ifcfg_connection_new (const char *full_path, + NMConnection *source, GError **error, gboolean *ignore_error) { @@ -108,14 +110,24 @@ nm_ifcfg_connection_new (const char *filename, char *route6file = NULL; NMInotifyHelper *ih; - g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (full_path != NULL, NULL); - tmp = connection_from_file (filename, NULL, NULL, NULL, &unmanaged, &keyfile, &routefile, &route6file, error, ignore_error); - if (!tmp) - return NULL; + /* If we're given a connection already, prefer that instead of re-reading */ + if (source) + tmp = g_object_ref (source); + else { + tmp = connection_from_file (full_path, NULL, NULL, NULL, + &unmanaged, + &keyfile, + &routefile, + &route6file, + error, + ignore_error); + if (!tmp) + return NULL; + } object = (GObject *) g_object_new (NM_TYPE_IFCFG_CONNECTION, - NM_IFCFG_CONNECTION_FILENAME, filename, NM_IFCFG_CONNECTION_UNMANAGED, unmanaged, NULL); if (!object) { @@ -128,11 +140,12 @@ nm_ifcfg_connection_new (const char *filename, g_object_unref (tmp); priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object); + priv->path = g_strdup (full_path); 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, filename); + priv->file_wd = nm_inotify_helper_add_watch (ih, full_path); priv->keyfile = keyfile; priv->keyfile_wd = nm_inotify_helper_add_watch (ih, keyfile); @@ -147,11 +160,11 @@ nm_ifcfg_connection_new (const char *filename, } const char * -nm_ifcfg_connection_get_filename (NMIfcfgConnection *self) +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)->filename; + return NM_IFCFG_CONNECTION_GET_PRIVATE (self)->path; } const char * @@ -176,7 +189,7 @@ commit_changes (NMSysconfigConnection *connection, * processes on-disk, read the existing connection back in and only rewrite * it if it's really changed. */ - reread = connection_from_file (priv->filename, NULL, NULL, NULL, + reread = connection_from_file (priv->path, NULL, NULL, NULL, &unmanaged, &keyfile, &routefile, &route6file, NULL, NULL); g_free (unmanaged); @@ -191,7 +204,7 @@ commit_changes (NMSysconfigConnection *connection, if (!writer_update_connection (NM_CONNECTION (connection), IFCFG_DIR, - priv->filename, + priv->path, priv->keyfile, &error)) { callback (connection, error, user_data); @@ -212,7 +225,7 @@ do_delete (NMSysconfigConnection *connection, { NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (connection); - g_unlink (priv->filename); + g_unlink (priv->path); if (priv->keyfile) g_unlink (priv->keyfile); if (priv->routefile) @@ -243,7 +256,7 @@ finalize (GObject *object) g_signal_handler_disconnect (ih, priv->ih_event_id); - g_free (priv->filename); + g_free (priv->path); if (priv->file_wd >= 0) nm_inotify_helper_remove_watch (ih, priv->file_wd); @@ -269,10 +282,6 @@ set_property (GObject *object, guint prop_id, NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object); switch (prop_id) { - case PROP_FILENAME: - /* Construct only */ - priv->filename = g_value_dup_string (value); - break; case PROP_UNMANAGED: priv->unmanaged = g_value_dup_string (value); break; @@ -289,9 +298,6 @@ get_property (GObject *object, guint prop_id, NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object); switch (prop_id) { - case PROP_FILENAME: - g_value_set_string (value, priv->filename); - break; case PROP_UNMANAGED: g_value_set_string (value, priv->unmanaged); break; @@ -317,14 +323,6 @@ nm_ifcfg_connection_class_init (NMIfcfgConnectionClass *ifcfg_connection_class) sysconfig_class->commit_changes = commit_changes; /* Properties */ - g_object_class_install_property - (object_class, PROP_FILENAME, - g_param_spec_string (NM_IFCFG_CONNECTION_FILENAME, - "FileName", - "File name", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - g_object_class_install_property (object_class, PROP_UNMANAGED, g_param_spec_string (NM_IFCFG_CONNECTION_UNMANAGED, diff --git a/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.h b/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.h index 860c428ca..4d9d699bc 100644 --- a/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.h +++ b/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.h @@ -33,7 +33,6 @@ G_BEGIN_DECLS #define NM_IS_IFCFG_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_IFCFG_CONNECTION)) #define NM_IFCFG_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_IFCFG_CONNECTION, NMIfcfgConnectionClass)) -#define NM_IFCFG_CONNECTION_FILENAME "filename" #define NM_IFCFG_CONNECTION_UNMANAGED "unmanaged" typedef struct { @@ -47,10 +46,11 @@ typedef struct { GType nm_ifcfg_connection_get_type (void); NMIfcfgConnection *nm_ifcfg_connection_new (const char *filename, + NMConnection *source, GError **error, gboolean *ignore_error); -const char *nm_ifcfg_connection_get_filename (NMIfcfgConnection *self); +const char *nm_ifcfg_connection_get_path (NMIfcfgConnection *self); const char *nm_ifcfg_connection_get_unmanaged_spec (NMIfcfgConnection *self); diff --git a/system-settings/plugins/ifcfg-rh/plugin.c b/system-settings/plugins/ifcfg-rh/plugin.c index 215ba6a9d..9e52b35df 100644 --- a/system-settings/plugins/ifcfg-rh/plugin.c +++ b/system-settings/plugins/ifcfg-rh/plugin.c @@ -18,7 +18,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2007 - 2008 Red Hat, Inc. + * Copyright (C) 2007 - 2010 Red Hat, Inc. */ #include @@ -62,20 +62,12 @@ static gboolean impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin, #include "nm-ifcfg-rh-glue.h" +static void connection_new_or_changed (SCPluginIfcfg *plugin, + const char *path, + NMIfcfgConnection *existing); + static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class); -static void connection_changed_handler (SCPluginIfcfg *plugin, - const char *path, - NMIfcfgConnection *connection, - gboolean *do_remove, - gboolean *do_new); - -static void handle_connection_remove_or_new (SCPluginIfcfg *plugin, - const char *path, - NMIfcfgConnection *connection, - gboolean do_remove, - gboolean do_new); - G_DEFINE_TYPE_EXTENDED (SCPluginIfcfg, sc_plugin_ifcfg, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, system_config_interface_init)) @@ -109,65 +101,67 @@ static void connection_ifcfg_changed (NMIfcfgConnection *connection, gpointer user_data) { SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data); - gboolean do_remove = FALSE, do_new = FALSE; const char *path; - path = nm_ifcfg_connection_get_filename (connection); + path = nm_ifcfg_connection_get_path (connection); g_return_if_fail (path != NULL); - connection_changed_handler (plugin, path, connection, &do_remove, &do_new); - handle_connection_remove_or_new (plugin, path, connection, do_remove, do_new); + connection_new_or_changed (plugin, path, connection); } static NMIfcfgConnection * -read_one_connection (SCPluginIfcfg *plugin, const char *filename) +_internal_new_connection (SCPluginIfcfg *self, + const char *path, + NMConnection *source, + GError **error) { - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); NMIfcfgConnection *connection; - GError *error = NULL; + NMSettingConnection *s_con; + const char *cid; + GError *local = NULL; gboolean ignore_error = FALSE; - PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "parsing %s ... ", filename); + if (!source) { + PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "parsing %s ... ", path); + } - connection = nm_ifcfg_connection_new (filename, &error, &ignore_error); - if (connection) { - NMSettingConnection *s_con; - const char *cid; - - s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION); - g_assert (s_con); - - cid = nm_setting_connection_get_id (s_con); - g_assert (cid); - - g_hash_table_insert (priv->connections, - (gpointer) nm_ifcfg_connection_get_filename (connection), - g_object_ref (connection)); - PLUGIN_PRINT (IFCFG_PLUGIN_NAME, " read connection '%s'", cid); - - if (nm_ifcfg_connection_get_unmanaged_spec (connection)) { - PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' and its " - "device due to NM_CONTROLLED/BRIDGE/VLAN.", cid); - g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); - } else { - /* Wait for the connection to become unmanaged once it knows the - * UDI of it's device, if/when the device gets plugged in. - */ - g_signal_connect (G_OBJECT (connection), "notify::unmanaged", - G_CALLBACK (connection_unmanaged_changed), plugin); - } - - /* watch changes of ifcfg hardlinks */ - g_signal_connect (G_OBJECT (connection), "ifcfg-changed", - G_CALLBACK (connection_ifcfg_changed), plugin); - } else { + connection = nm_ifcfg_connection_new (path, source, &local, &ignore_error); + if (!connection) { if (!ignore_error) { PLUGIN_PRINT (IFCFG_PLUGIN_NAME, " error: %s", - (error && error->message) ? error->message : "(unknown)"); + (local && local->message) ? local->message : "(unknown)"); } - g_clear_error (&error); + g_propagate_error (error, local); + return NULL; } + s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + cid = nm_setting_connection_get_id (s_con); + g_assert (cid); + + g_hash_table_insert (priv->connections, + (gpointer) nm_ifcfg_connection_get_path (connection), + connection); + PLUGIN_PRINT (IFCFG_PLUGIN_NAME, " read connection '%s'", cid); + + if (nm_ifcfg_connection_get_unmanaged_spec (connection)) { + PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' and its " + "device due to NM_CONTROLLED/BRIDGE/VLAN.", cid); + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); + } else { + /* Wait for the connection to become unmanaged once it knows the + * hardware IDs of its device, if/when the device gets plugged in. + */ + g_signal_connect (G_OBJECT (connection), "notify::" NM_IFCFG_CONNECTION_UNMANAGED, + G_CALLBACK (connection_unmanaged_changed), self); + } + + /* watch changes of ifcfg hardlinks */ + g_signal_connect (G_OBJECT (connection), "ifcfg-changed", + G_CALLBACK (connection_ifcfg_changed), self); + return connection; } @@ -188,7 +182,7 @@ read_connections (SCPluginIfcfg *plugin) continue; full_path = g_build_filename (IFCFG_DIR, item, NULL); - read_one_connection (plugin, full_path); + _internal_new_connection (plugin, full_path, NULL, NULL); g_free (full_path); } @@ -213,26 +207,53 @@ commit_cb (NMSysconfigConnection *connection, GError *error, gpointer unused) } static void -connection_changed_handler (SCPluginIfcfg *plugin, - const char *path, - NMIfcfgConnection *connection, - gboolean *do_remove, - gboolean *do_new) +remove_connection (SCPluginIfcfg *self, NMIfcfgConnection *connection) +{ + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); + gboolean managed = FALSE; + const char *path; + + g_return_if_fail (self != NULL); + g_return_if_fail (connection != NULL); + + managed = !!nm_ifcfg_connection_get_unmanaged_spec (connection); + path = nm_ifcfg_connection_get_path (connection); + + g_hash_table_remove (priv->connections, path); + g_signal_emit_by_name (connection, NM_SYSCONFIG_CONNECTION_REMOVED); + + /* Emit unmanaged changes _after_ removing the connection */ + if (managed == FALSE) + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); +} + +static void +connection_new_or_changed (SCPluginIfcfg *self, + const char *path, + NMIfcfgConnection *existing) { NMIfcfgConnection *new; GError *error = NULL; gboolean ignore_error = FALSE; const char *new_unmanaged = NULL, *old_unmanaged = NULL; - g_return_if_fail (plugin != NULL); + g_return_if_fail (self != NULL); g_return_if_fail (path != NULL); - g_return_if_fail (connection != NULL); - g_return_if_fail (do_remove != NULL); - g_return_if_fail (do_new != NULL); + if (!existing) { + /* Completely new connection */ + new = _internal_new_connection (self, path, NULL, NULL); + if (new && !nm_ifcfg_connection_get_unmanaged_spec (new)) { + /* Only managed connections are announced to the settings service */ + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, new); + } + return; + } + + /* Existing connection that got changed */ PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "updating %s", path); - new = (NMIfcfgConnection *) nm_ifcfg_connection_new (path, &error, &ignore_error); + new = (NMIfcfgConnection *) nm_ifcfg_connection_new (path, NULL, &error, &ignore_error); if (!new) { /* errors reading connection; remove it */ if (!ignore_error) { @@ -242,19 +263,23 @@ connection_changed_handler (SCPluginIfcfg *plugin, g_clear_error (&error); PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "removed %s.", path); - *do_remove = TRUE; + remove_connection (self, existing); return; } - /* Successfully read connection changes */ + /* Successfully read connection */ - old_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (NM_IFCFG_CONNECTION (connection)); + old_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (NM_IFCFG_CONNECTION (existing)); new_unmanaged = nm_ifcfg_connection_get_unmanaged_spec (NM_IFCFG_CONNECTION (new)); if (new_unmanaged) { if (!old_unmanaged) { - /* Unexport the connection by destroying it, then re-creating it as unmanaged */ - *do_remove = *do_new = TRUE; + /* Unexport the connection by telling the settings service it's + * been removed, and notify the settings service by signalling that + * unmanaged specs have changed. + */ + g_signal_emit_by_name (existing, NM_SYSCONFIG_CONNECTION_REMOVED); + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); } } else { if (old_unmanaged) { /* now managed */ @@ -263,60 +288,25 @@ connection_changed_handler (SCPluginIfcfg *plugin, s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (new), NM_TYPE_SETTING_CONNECTION); g_assert (s_con); - cid = nm_setting_connection_get_id (s_con); g_assert (cid); PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Managing connection '%s' and its " "device because NM_CONTROLLED was true.", cid); - g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection); + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, existing); } - nm_sysconfig_connection_replace_and_commit (NM_SYSCONFIG_CONNECTION (connection), + nm_sysconfig_connection_replace_and_commit (NM_SYSCONFIG_CONNECTION (existing), NM_CONNECTION (new), commit_cb, NULL); /* Update unmanaged status */ - g_object_set (connection, "unmanaged", new_unmanaged, NULL); - g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); + g_object_set (existing, NM_IFCFG_CONNECTION_UNMANAGED, new_unmanaged, NULL); + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); } g_object_unref (new); } -static void -handle_connection_remove_or_new (SCPluginIfcfg *plugin, - const char *path, - NMIfcfgConnection *connection, - gboolean do_remove, - gboolean do_new) -{ - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); - - g_return_if_fail (plugin != NULL); - g_return_if_fail (path != NULL); - - if (do_remove) { - const char *unmanaged; - - g_return_if_fail (connection != NULL); - - unmanaged = nm_ifcfg_connection_get_unmanaged_spec (connection); - g_hash_table_remove (priv->connections, path); - g_signal_emit_by_name (connection, "removed"); - - /* Emit unmanaged changes _after_ removing the connection */ - if (unmanaged) - g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); - } - - if (do_new) { - connection = read_one_connection (plugin, path); - if (connection) { - if (!nm_ifcfg_connection_get_unmanaged_spec (connection)) - g_signal_emit_by_name (plugin, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection); - } - } -} static void dir_changed (GFileMonitor *monitor, GFile *file, @@ -328,7 +318,6 @@ dir_changed (GFileMonitor *monitor, SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); char *path, *name; NMIfcfgConnection *connection; - gboolean do_remove = FALSE, do_new = FALSE; path = g_file_get_path (file); if (utils_should_ignore_file (path, FALSE)) { @@ -345,17 +334,12 @@ dir_changed (GFileMonitor *monitor, case G_FILE_MONITOR_EVENT_DELETED: PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "removed %s.", name); if (connection) - handle_connection_remove_or_new (plugin, name, connection, TRUE, FALSE); + remove_connection (plugin, connection); break; case G_FILE_MONITOR_EVENT_CREATED: case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: - /* Update */ - if (!connection) - do_new = TRUE; - else - connection_changed_handler (plugin, name, connection, &do_remove, &do_new); - - handle_connection_remove_or_new (plugin, name, connection, do_remove, do_new); + /* Update or new */ + connection_new_or_changed (plugin, name, connection); break; default: break; @@ -445,12 +429,22 @@ get_unmanaged_specs (NMSystemConfigInterface *config) return list; } -static gboolean +static NMSysconfigConnection * add_connection (NMSystemConfigInterface *config, NMConnection *connection, GError **error) { - return writer_new_connection (connection, IFCFG_DIR, NULL, error); + SCPluginIfcfg *self = SC_PLUGIN_IFCFG (config); + NMIfcfgConnection *added = NULL; + char *path = NULL; + + /* Write it out first, then add the connection to our internal list */ + if (writer_new_connection (connection, IFCFG_DIR, &path, error)) { + added = _internal_new_connection (self, path, connection, error); + g_free (path); + } + return NM_SYSCONFIG_CONNECTION (added); + } #define SC_NETWORK_FILE SYSCONFDIR"/sysconfig/network" diff --git a/system-settings/plugins/ifnet/connection_parser.c b/system-settings/plugins/ifnet/connection_parser.c index dc9f681d0..877957729 100644 --- a/system-settings/plugins/ifnet/connection_parser.c +++ b/system-settings/plugins/ifnet/connection_parser.c @@ -2973,8 +2973,8 @@ get_wireless_name (NMConnection * connection) return result; } -gboolean -ifnet_add_new_connection (NMConnection * connection, +char * +ifnet_add_new_connection (NMConnection *connection, const char *config_file, const char *wpa_file, GError **error) @@ -3024,10 +3024,10 @@ ifnet_add_new_connection (NMConnection * connection, } PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Added new connection: %s, result: %s", - new_name, success ? "success" : "fail"); + new_name, success ? "success" : "fail"); out: - if (new_name) + if (!success) g_free (new_name); - return success; + return success ? new_name : NULL; } diff --git a/system-settings/plugins/ifnet/connection_parser.h b/system-settings/plugins/ifnet/connection_parser.h index 24c1f7e90..2154f56e6 100644 --- a/system-settings/plugins/ifnet/connection_parser.h +++ b/system-settings/plugins/ifnet/connection_parser.h @@ -39,8 +39,8 @@ gboolean ifnet_delete_connection_in_parsers (const char *conn_name, const char *config_file, const char *wpa_file); -gboolean ifnet_add_new_connection (NMConnection *connection, - const char *config_file, - const char *wpa_file, - GError ** error); +char * ifnet_add_new_connection (NMConnection *connection, + const char *config_file, + const char *wpa_file, + GError ** error); #endif diff --git a/system-settings/plugins/ifnet/nm-ifnet-connection.c b/system-settings/plugins/ifnet/nm-ifnet-connection.c index 13af19239..8e774de8f 100644 --- a/system-settings/plugins/ifnet/nm-ifnet-connection.c +++ b/system-settings/plugins/ifnet/nm-ifnet-connection.c @@ -57,25 +57,32 @@ typedef struct { } NMIfnetConnectionPrivate; NMIfnetConnection * -nm_ifnet_connection_new (gchar * conn_name) +nm_ifnet_connection_new (const char *conn_name, NMConnection *source) { NMConnection *tmp; GObject *object; GError **error = NULL; g_return_val_if_fail (conn_name != NULL, NULL); - tmp = ifnet_update_connection_from_config_block (conn_name, error); - if (!tmp) - return NULL; - object = (GObject *) g_object_new (NM_TYPE_IFNET_CONNECTION, - NM_IFNET_CONNECTION_CONN_NAME, - conn_name, NULL); + + if (source) + tmp = g_object_ref (source); + else { + tmp = ifnet_update_connection_from_config_block (conn_name, error); + if (!tmp) + return NULL; + } + + object = (GObject *) g_object_new (NM_TYPE_IFNET_CONNECTION, NULL); if (!object) { g_object_unref (tmp); return NULL; } + + NM_IFNET_CONNECTION_GET_PRIVATE (object)->conn_name = g_strdup (conn_name); nm_sysconfig_connection_replace_settings (NM_SYSCONFIG_CONNECTION (object), tmp, NULL); g_object_unref (tmp); + return NM_IFNET_CONNECTION (object); } @@ -144,44 +151,6 @@ do_delete (NMSysconfigConnection *connection, g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0); } -static void -set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - NMIfnetConnectionPrivate *priv = - NM_IFNET_CONNECTION_GET_PRIVATE (object); - g_return_if_fail (priv); - - switch (prop_id) { - case PROP_CONN_NAME: - if (priv->conn_name) - g_free (priv->conn_name); - priv->conn_name = g_strdup (g_value_get_pointer (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - NMIfnetConnectionPrivate *priv = - NM_IFNET_CONNECTION_GET_PRIVATE (object); - g_return_if_fail (priv); - - switch (prop_id) { - case PROP_CONN_NAME: - g_value_set_pointer (value, priv->conn_name); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - static void finalize (GObject * object) { @@ -203,19 +172,10 @@ nm_ifnet_connection_class_init (NMIfnetConnectionClass * ifnet_connection_class) g_type_class_add_private (ifnet_connection_class, sizeof (NMIfnetConnectionPrivate)); - object_class->set_property = set_property; - object_class->get_property = get_property; object_class->finalize = finalize; sysconfig_class->delete = do_delete; sysconfig_class->commit_changes = commit_changes; - /* Properties */ - g_object_class_install_property - (object_class, PROP_CONN_NAME, - g_param_spec_pointer (NM_IFNET_CONNECTION_CONN_NAME, - "config_block", - "", - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); signals[IFNET_SETUP_MONITORS] = g_signal_new ("ifnet_setup_monitors", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, diff --git a/system-settings/plugins/ifnet/nm-ifnet-connection.h b/system-settings/plugins/ifnet/nm-ifnet-connection.h index 8b3d495f0..cde260a45 100644 --- a/system-settings/plugins/ifnet/nm-ifnet-connection.h +++ b/system-settings/plugins/ifnet/nm-ifnet-connection.h @@ -26,14 +26,15 @@ #include "net_parser.h" G_BEGIN_DECLS + #define NM_TYPE_IFNET_CONNECTION (nm_ifnet_connection_get_type ()) #define NM_IFNET_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IFNET_CONNECTION, NMIfnetConnection)) #define NM_IFNET_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IFNET_CONNECTION, NMIfnetConnectionClass)) #define NM_IS_IFNET_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_IFNET_CONNECTION)) #define NM_IS_IFNET_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_IFNET_CONNECTION)) #define NM_IFNET_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_IFNET_CONNECTION, NMIfnetConnectionClass)) -#define NM_IFNET_CONNECTION_CONN_NAME "connection_name" - typedef struct { + +typedef struct { NMSysconfigConnection parent; } NMIfnetConnection; @@ -43,7 +44,8 @@ typedef struct { GType nm_ifnet_connection_get_type (void); -NMIfnetConnection *nm_ifnet_connection_new (gchar * conn_name); +NMIfnetConnection *nm_ifnet_connection_new (const char *conn_name, + NMConnection *source); G_END_DECLS #endif /* NM_IFNET_CONNECTION_H */ diff --git a/system-settings/plugins/ifnet/plugin.c b/system-settings/plugins/ifnet/plugin.c index 66b124be6..c0077c875 100644 --- a/system-settings/plugins/ifnet/plugin.c +++ b/system-settings/plugins/ifnet/plugin.c @@ -201,18 +201,6 @@ commit_cb (NMSysconfigConnection *connection, GError *error, gpointer unused) } } -static void -update_old_connection (gchar * conn_name, - NMIfnetConnection * old_conn, - NMIfnetConnection * new_conn, - SCPluginIfnetPrivate * priv) -{ - nm_sysconfig_connection_replace_and_commit (NM_SYSCONFIG_CONNECTION (old_conn), - NM_CONNECTION (new_conn), - commit_cb, NULL); - g_object_unref (new_conn); -} - static void setup_monitors (NMIfnetConnection * connection, gpointer user_data) { @@ -267,90 +255,85 @@ reload_connections (gpointer config) if (!reload_parsers ()) return; - PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Loading connections"); - conn_names = ifnet_get_connection_names (); - new_conn_names = - g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - for (n_iter = conn_names; n_iter; n_iter = g_list_next (n_iter)) { - NMIfnetConnection *exported; - NMIfnetConnection *old; - gchar *conn_name = g_strdup (n_iter->data); - /* add the new connection */ - exported = nm_ifnet_connection_new (conn_name); - if (!exported) { - g_free (conn_name); + PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Loading connections"); + + conn_names = ifnet_get_connection_names (); + new_conn_names = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); + for (n_iter = conn_names; n_iter; n_iter = g_list_next (n_iter)) { + NMIfnetConnection *new; + NMIfnetConnection *old; + const char *conn_name = n_iter->data; + + /* read the new connection */ + new = nm_ifnet_connection_new (conn_name, NULL); + if (!new) continue; - } - g_signal_connect (G_OBJECT (exported), "ifnet_setup_monitors", - G_CALLBACK (setup_monitors), config); - g_signal_connect (G_OBJECT (exported), "ifnet_cancel_monitors", - G_CALLBACK (cancel_monitors), config); + + g_signal_connect (G_OBJECT (new), "ifnet_setup_monitors", + G_CALLBACK (setup_monitors), config); + g_signal_connect (G_OBJECT (new), "ifnet_cancel_monitors", + G_CALLBACK (cancel_monitors), config); + old = g_hash_table_lookup (priv->config_connections, conn_name); - if (old && exported) { + if (old && new) { const char *auto_refresh; auto_refresh = ifnet_get_global_setting (IFNET_KEY_FILE_GROUP, "auto_refresh"); if (auto_refresh && is_true (auto_refresh)) { if (!nm_connection_compare (NM_CONNECTION (old), - NM_CONNECTION - (exported), - NM_SETTING_COMPARE_FLAG_EXACT)) - { - PLUGIN_PRINT (IFNET_PLUGIN_NAME, - "Auto refreshing %s", - conn_name); - g_signal_emit_by_name (old, "removed"); - g_hash_table_remove - (priv->config_connections, - conn_name); - g_hash_table_insert - (priv->config_connections, - g_strdup (conn_name), exported); + NM_CONNECTION (new), + NM_SETTING_COMPARE_FLAG_EXACT)) { + PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Auto refreshing %s", conn_name); + + /* Remove and re-add to disconnect and reconnect with new settings */ + g_signal_emit_by_name (old, NM_SYSCONFIG_CONNECTION_REMOVED); + g_hash_table_remove (priv->config_connections, conn_name); + g_hash_table_insert (priv->config_connections, g_strdup (conn_name), new); if (is_managed (conn_name)) - g_signal_emit_by_name (self, - NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, - exported); + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, new); } - } else - update_old_connection (conn_name, old, - exported, priv); - g_signal_emit_by_name (self, - NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); - } else if (exported) { - g_hash_table_insert (priv->config_connections, - g_strdup (conn_name), exported); + } else { + /* Update existing connection with new settings */ + nm_sysconfig_connection_replace_and_commit (NM_SYSCONFIG_CONNECTION (old), + NM_CONNECTION (new), + commit_cb, NULL); + g_object_unref (new); + } + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); + } else if (new) { + g_hash_table_insert (priv->config_connections, g_strdup (conn_name), new); if (is_managed (conn_name)) - g_signal_emit_by_name (self, - NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, - exported); + g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, new); } - g_hash_table_insert (new_conn_names, conn_name, conn_name); + g_hash_table_insert (new_conn_names, (gpointer) conn_name, (gpointer) conn_name); } + /* remove unused connections */ g_hash_table_iter_init (&iter, priv->config_connections); while (g_hash_table_iter_next (&iter, &key, &value)) { if (!g_hash_table_lookup (new_conn_names, key)) { - g_signal_emit_by_name (value, "removed"); + g_signal_emit_by_name (value, NM_SYSCONFIG_CONNECTION_REMOVED); g_hash_table_remove (priv->config_connections, key); } } - g_hash_table_remove_all (new_conn_names); g_hash_table_destroy (new_conn_names); g_list_free (conn_names); } -static gboolean +static NMSysconfigConnection * add_connection (NMSystemConfigInterface *config, - NMConnection *connection, + NMConnection *source, GError **error) { - gboolean result; + NMIfnetConnection *connection = NULL; + char *conn_name; - result = ifnet_add_new_connection (connection, CONF_NET_FILE, - WPA_SUPPLICANT_CONF, error); + conn_name = ifnet_add_new_connection (source, CONF_NET_FILE, WPA_SUPPLICANT_CONF, error); + if (conn_name) + connection = nm_ifnet_connection_new (conn_name, source); reload_connections (config); - return result; + return connection ? NM_SYSCONFIG_CONNECTION (connection) : NULL; } static void diff --git a/system-settings/plugins/keyfile/nm-keyfile-connection.c b/system-settings/plugins/keyfile/nm-keyfile-connection.c index e14986917..99d6888c2 100644 --- a/system-settings/plugins/keyfile/nm-keyfile-connection.c +++ b/system-settings/plugins/keyfile/nm-keyfile-connection.c @@ -37,40 +37,38 @@ G_DEFINE_TYPE (NMKeyfileConnection, nm_keyfile_connection, NM_TYPE_SYSCONFIG_CON #define NM_KEYFILE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_KEYFILE_CONNECTION, NMKeyfileConnectionPrivate)) typedef struct { - char *filename; + char *path; } NMKeyfileConnectionPrivate; -enum { - PROP_0, - PROP_FILENAME, - - LAST_PROP -}; - NMKeyfileConnection * -nm_keyfile_connection_new (const char *filename, GError **error) +nm_keyfile_connection_new (const char *full_path, + NMConnection *source, + GError **error) { GObject *object; NMKeyfileConnectionPrivate *priv; NMSettingConnection *s_con; NMConnection *tmp; - g_return_val_if_fail (filename != NULL, NULL); + g_return_val_if_fail (full_path != NULL, NULL); - tmp = connection_from_file (filename, error); - if (!tmp) - return NULL; + /* If we're given a connection already, prefer that instead of re-reading */ + if (source) + tmp = g_object_ref (source); + else { + tmp = connection_from_file (full_path, error); + if (!tmp) + return NULL; + } - object = (GObject *) g_object_new (NM_TYPE_KEYFILE_CONNECTION, - NM_KEYFILE_CONNECTION_FILENAME, filename, - NULL); + object = (GObject *) g_object_new (NM_TYPE_KEYFILE_CONNECTION, NULL); if (!object) { g_object_unref (tmp); return NULL; } priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (object); - g_assert (priv->filename); + priv->path = g_strdup (full_path); /* Update our settings with what was read from the file */ nm_sysconfig_connection_replace_settings (NM_SYSCONFIG_CONNECTION (object), tmp, NULL); @@ -100,11 +98,11 @@ nm_keyfile_connection_new (const char *filename, GError **error) } const char * -nm_keyfile_connection_get_filename (NMKeyfileConnection *self) +nm_keyfile_connection_get_path (NMKeyfileConnection *self) { g_return_val_if_fail (NM_IS_KEYFILE_CONNECTION (self), NULL); - return NM_KEYFILE_CONNECTION_GET_PRIVATE (self)->filename; + return NM_KEYFILE_CONNECTION_GET_PRIVATE (self)->path; } static void @@ -113,21 +111,21 @@ commit_changes (NMSysconfigConnection *connection, gpointer user_data) { NMKeyfileConnectionPrivate *priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (connection); - char *filename = NULL; + char *path = NULL; GError *error = NULL; - if (!write_connection (NM_CONNECTION (connection), KEYFILE_DIR, 0, 0, &filename, &error)) { + if (!write_connection (NM_CONNECTION (connection), KEYFILE_DIR, 0, 0, &path, &error)) { callback (connection, error, user_data); g_clear_error (&error); return; } - if (g_strcmp0 (priv->filename, filename)) { + if (g_strcmp0 (priv->path, path)) { /* Update the filename if it changed */ - g_free (priv->filename); - priv->filename = filename; + g_free (priv->path); + priv->path = path; } else - g_free (filename); + g_free (path); NM_SYSCONFIG_CONNECTION_CLASS (nm_keyfile_connection_parent_class)->commit_changes (connection, callback, @@ -141,7 +139,7 @@ do_delete (NMSysconfigConnection *connection, { NMKeyfileConnectionPrivate *priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (connection); - g_unlink (priv->filename); + g_unlink (priv->path); NM_SYSCONFIG_CONNECTION_CLASS (nm_keyfile_connection_parent_class)->delete (connection, callback, @@ -162,44 +160,11 @@ finalize (GObject *object) nm_connection_clear_secrets (NM_CONNECTION (object)); - g_free (priv->filename); + g_free (priv->path); G_OBJECT_CLASS (nm_keyfile_connection_parent_class)->finalize (object); } -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NMKeyfileConnectionPrivate *priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_FILENAME: - /* Construct only */ - priv->filename = g_value_dup_string (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMKeyfileConnectionPrivate *priv = NM_KEYFILE_CONNECTION_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_FILENAME: - g_value_set_string (value, priv->filename); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - static void nm_keyfile_connection_class_init (NMKeyfileConnectionClass *keyfile_connection_class) { @@ -209,18 +174,7 @@ nm_keyfile_connection_class_init (NMKeyfileConnectionClass *keyfile_connection_c g_type_class_add_private (keyfile_connection_class, sizeof (NMKeyfileConnectionPrivate)); /* Virtual methods */ - object_class->set_property = set_property; - object_class->get_property = get_property; object_class->finalize = finalize; sysconfig_class->commit_changes = commit_changes; sysconfig_class->delete = do_delete; - - /* Properties */ - g_object_class_install_property - (object_class, PROP_FILENAME, - g_param_spec_string (NM_KEYFILE_CONNECTION_FILENAME, - "FileName", - "File name", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } diff --git a/system-settings/plugins/keyfile/nm-keyfile-connection.h b/system-settings/plugins/keyfile/nm-keyfile-connection.h index 68e795a6c..ab7b42eaa 100644 --- a/system-settings/plugins/keyfile/nm-keyfile-connection.h +++ b/system-settings/plugins/keyfile/nm-keyfile-connection.h @@ -33,8 +33,6 @@ G_BEGIN_DECLS #define NM_IS_KEYFILE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_KEYFILE_CONNECTION)) #define NM_KEYFILE_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_KEYFILE_CONNECTION, NMKeyfileConnectionClass)) -#define NM_KEYFILE_CONNECTION_FILENAME "filename" - typedef struct { NMSysconfigConnection parent; } NMKeyfileConnection; @@ -45,9 +43,11 @@ typedef struct { GType nm_keyfile_connection_get_type (void); -NMKeyfileConnection *nm_keyfile_connection_new (const char *filename, GError **error); +NMKeyfileConnection *nm_keyfile_connection_new (const char *filename, + NMConnection *source, + GError **error); -const char *nm_keyfile_connection_get_filename (NMKeyfileConnection *self); +const char *nm_keyfile_connection_get_path (NMKeyfileConnection *self); G_END_DECLS diff --git a/system-settings/plugins/keyfile/plugin.c b/system-settings/plugins/keyfile/plugin.c index 815650e91..847829ac8 100644 --- a/system-settings/plugins/keyfile/plugin.c +++ b/system-settings/plugins/keyfile/plugin.c @@ -67,13 +67,49 @@ typedef struct { gboolean disposed; } SCPluginKeyfilePrivate; +static NMSysconfigConnection * +_internal_new_connection (SCPluginKeyfile *self, + const char *full_path, + NMConnection *source, + const char **out_cid, + GError **error) +{ + SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self); + NMSettingConnection *s_con; + const char *cid, *uuid; + NMKeyfileConnection *connection; + + g_return_val_if_fail (full_path != NULL, NULL); + + connection = nm_keyfile_connection_new (full_path, source, error); + if (!connection) + return NULL; + + s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), + NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + + cid = nm_setting_connection_get_id (s_con); + g_assert (cid); + uuid = nm_setting_connection_get_uuid (s_con); + g_assert (uuid); + + g_hash_table_insert (priv->hash, + (gpointer) nm_keyfile_connection_get_path (connection), + connection); + + if (out_cid) + *out_cid = cid; + return NM_SYSCONFIG_CONNECTION (connection); +} + static void read_connections (NMSystemConfigInterface *config) { - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config); + SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config); GDir *dir; GError *error = NULL; - const char *item; + const char *item, *cid; dir = g_dir_open (KEYFILE_DIR, 0, &error); if (!dir) { @@ -86,62 +122,28 @@ read_connections (NMSystemConfigInterface *config) } while ((item = g_dir_read_name (dir))) { - NMKeyfileConnection *connection; + NMSysconfigConnection *connection; char *full_path; full_path = g_build_filename (KEYFILE_DIR, item, NULL); PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "parsing %s ... ", item); - connection = nm_keyfile_connection_new (full_path, &error); + + connection = _internal_new_connection (self, full_path, NULL, &cid, &error); if (connection) { - NMSettingConnection *s_con; - const char *cid; - - s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION); - g_assert (s_con); - - cid = nm_setting_connection_get_id (s_con); - g_assert (cid); - - g_hash_table_insert (priv->hash, - (gpointer) nm_keyfile_connection_get_filename (connection), - connection); - PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, " read connection '%s'", cid); } else { PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, " error: %s", (error && error->message) ? error->message : "(unknown)"); - g_clear_error (&error); } + g_clear_error (&error); g_free (full_path); } g_dir_close (dir); } -typedef struct { - const char *uuid; - NMKeyfileConnection *found; -} FindByUUIDInfo; - static void -find_by_uuid (gpointer key, gpointer data, gpointer user_data) +update_connection_settings_commit_cb (NMSysconfigConnection *orig, GError *error, gpointer user_data) { - NMKeyfileConnection *keyfile = NM_KEYFILE_CONNECTION (data); - FindByUUIDInfo *info = user_data; - NMSettingConnection *s_con; - const char *uuid; - - if (info->found) - return; - - s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (keyfile), NM_TYPE_SETTING_CONNECTION); - - uuid = s_con ? nm_setting_connection_get_uuid (s_con) : NULL; - if (uuid && !strcmp (info->uuid, uuid)) - info->found = keyfile; -} - -static void -update_connection_settings_commit_cb (NMSysconfigConnection *orig, GError *error, gpointer user_data) { if (error) { g_warning ("%s: '%s' / '%s' invalid: %d", __func__, @@ -180,6 +182,28 @@ remove_connection (SCPluginKeyfile *self, g_object_unref (connection); } +static NMKeyfileConnection * +find_by_uuid (SCPluginKeyfile *self, const char *uuid) +{ + SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self); + GHashTableIter iter; + gpointer data = NULL; + + g_return_val_if_fail (uuid != NULL, NULL); + + g_hash_table_iter_init (&iter, priv->hash); + while (g_hash_table_iter_next (&iter, NULL, &data)) { + NMConnection *candidate = NM_CONNECTION (data); + NMSettingConnection *s_con; + + s_con = (NMSettingConnection *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + if (strcmp (uuid, nm_setting_connection_get_uuid (s_con)) == 0) + return NM_KEYFILE_CONNECTION (candidate); + } + return NULL; +} + static void dir_changed (GFileMonitor *monitor, GFile *file, @@ -188,30 +212,31 @@ dir_changed (GFileMonitor *monitor, gpointer user_data) { NMSystemConfigInterface *config = NM_SYSTEM_CONFIG_INTERFACE (user_data); - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config); - char *name; + SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config); + SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self); + char *full_path; NMKeyfileConnection *connection; GError *error = NULL; - name = g_file_get_path (file); - connection = g_hash_table_lookup (priv->hash, name); + full_path = g_file_get_path (file); + connection = g_hash_table_lookup (priv->hash, full_path); switch (event_type) { case G_FILE_MONITOR_EVENT_DELETED: if (connection) { - PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "removed %s.", name); - remove_connection (SC_PLUGIN_KEYFILE (config), connection, name); + PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "removed %s.", full_path); + remove_connection (SC_PLUGIN_KEYFILE (config), connection, full_path); } break; case G_FILE_MONITOR_EVENT_CREATED: case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: - PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "updating %s", name); + PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "updating %s", full_path); if (connection) { /* Update */ NMKeyfileConnection *tmp; - tmp = nm_keyfile_connection_new (name, &error); + tmp = nm_keyfile_connection_new (full_path, NULL, &error); if (tmp) { update_connection_settings (connection, tmp); g_object_unref (tmp); @@ -220,40 +245,33 @@ dir_changed (GFileMonitor *monitor, PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, " error: %s", (error && error->message) ? error->message : "(unknown)"); g_clear_error (&error); - remove_connection (SC_PLUGIN_KEYFILE (config), connection, name); + remove_connection (SC_PLUGIN_KEYFILE (config), connection, full_path); } } else { /* New */ - connection = nm_keyfile_connection_new (name, &error); + connection = nm_keyfile_connection_new (full_path, NULL, &error); if (connection) { - NMSettingConnection *s_con; - const char *connection_uuid; NMKeyfileConnection *found = NULL; + NMSettingConnection *s_con; /* Connection renames will show up as different files but with * the same UUID. Try to find the original connection. */ s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION); - connection_uuid = s_con ? nm_setting_connection_get_uuid (s_con) : NULL; - - if (connection_uuid) { - FindByUUIDInfo info = { .found = NULL, .uuid = connection_uuid }; - - g_hash_table_foreach (priv->hash, find_by_uuid, &info); - found = info.found; - } + g_assert (s_con); /* A connection rename is treated just like an update except * there's a bit more housekeeping with the hash table. */ + found = find_by_uuid (self, nm_setting_connection_get_uuid (s_con)); if (found) { - const char *old_filename = nm_keyfile_connection_get_filename (connection); + const char *old_path = nm_keyfile_connection_get_path (connection); /* Removing from the hash table should drop the last reference, * but of course we want to keep the connection around. */ g_object_ref (found); - g_hash_table_remove (priv->hash, old_filename); + g_hash_table_remove (priv->hash, old_path); /* Updating settings should update the NMKeyfileConnection's * filename property too. @@ -262,14 +280,14 @@ dir_changed (GFileMonitor *monitor, /* Re-insert the connection back into the hash with the new filename */ g_hash_table_insert (priv->hash, - (gpointer) nm_keyfile_connection_get_filename (found), + (gpointer) nm_keyfile_connection_get_path (found), found); /* Get rid of the temporary connection */ g_object_unref (connection); } else { g_hash_table_insert (priv->hash, - (gpointer) nm_keyfile_connection_get_filename (connection), + (gpointer) nm_keyfile_connection_get_path (connection), connection); g_signal_emit_by_name (config, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection); } @@ -284,7 +302,7 @@ dir_changed (GFileMonitor *monitor, break; } - g_free (name); + g_free (full_path); } static void @@ -352,38 +370,42 @@ setup_monitoring (NMSystemConfigInterface *config) } } -static void -hash_to_slist (gpointer key, gpointer value, gpointer user_data) -{ - GSList **list = (GSList **) user_data; - - *list = g_slist_prepend (*list, value); -} - /* Plugin */ static GSList * get_connections (NMSystemConfigInterface *config) { SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config); - GSList *connections = NULL; + GHashTableIter iter; + gpointer data = NULL; + GSList *list = NULL; if (!priv->hash) { setup_monitoring (config); read_connections (config); } - g_hash_table_foreach (priv->hash, hash_to_slist, &connections); - - return connections; + g_hash_table_iter_init (&iter, priv->hash); + while (g_hash_table_iter_next (&iter, NULL, &data)) + list = g_slist_prepend (list, data); + return list; } -static gboolean +static NMSysconfigConnection * add_connection (NMSystemConfigInterface *config, NMConnection *connection, GError **error) { - return write_connection (connection, KEYFILE_DIR, 0, 0, NULL, error); + SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config); + NMSysconfigConnection *added = NULL; + char *path = NULL; + + /* Write it out first, then add the connection to our internal list */ + if (write_connection (connection, KEYFILE_DIR, 0, 0, &path, error)) { + added = _internal_new_connection (self, path, connection, NULL, error); + g_free (path); + } + return added; } static GSList *