From e6a5d0be511f2c8714be3cedf48aa64db9c23f89 Mon Sep 17 00:00:00 2001 From: Tambet Ingo Date: Tue, 22 Apr 2008 14:48:02 +0000 Subject: [PATCH] 2008-04-22 Tambet Ingo Implement GKeyFile system settings plugin. Implement writing system settings (currently supported only by GKeyFile plugin). * system-settings/src/main.c: * system-settings/src/dbus-settings.c: Move the communication with plugins from main.c to dbus-settings.c. Makes it possible to talk to all registered plugins for adding/updating/removing connections. * system-settings/src/nm-system-config-interface.c (nm_system_config_interface_add_connection): Implement (nm_system_config_interface_update_connection): Implement. (nm_system_config_interface_remove_connection): Implement. * system-settings/plugins/keyfile/Makefile.am: * system-settings/plugins/keyfile/plugin.[ch]: * system-settings/plugins/keyfile/writer.[ch]: * system-settings/plugins/keyfile/reader.[ch]: Implement. * system-settings/plugins/Makefile.am: Add GKeyFile plugin. * configure.in: Generate GKeyFile Makefile. * libnm-glib/nm-settings.c (impl_exported_connection_get_id): Fix a memory corruption, need to duplicate the returned string. (impl_exported_connection_update): Implement. (impl_exported_connection_delete): Implement. * introspection/nm-settings-system.xml: Add "AddConnection" method. * introspection/nm-exported-connection.xml: Add "Update" and "Delete" methods. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3587 4912f4e0-d625-0410-9fb7-b9a5a253dbdc --- ChangeLog | 33 ++ configure.in | 1 + introspection/nm-exported-connection.xml | 19 + introspection/nm-settings-system.xml | 12 + libnm-glib/nm-settings.c | 40 +- libnm-glib/nm-settings.h | 5 + system-settings/plugins/Makefile.am | 8 +- system-settings/plugins/keyfile/Makefile.am | 28 ++ system-settings/plugins/keyfile/plugin.c | 310 ++++++++++++++ system-settings/plugins/keyfile/plugin.h | 27 ++ system-settings/plugins/keyfile/reader.c | 196 +++++++++ system-settings/plugins/keyfile/reader.h | 11 + system-settings/plugins/keyfile/writer.c | 160 ++++++++ system-settings/plugins/keyfile/writer.h | 11 + system-settings/src/dbus-settings.c | 383 ++++++++++++++---- system-settings/src/dbus-settings.h | 13 +- system-settings/src/main.c | 158 +------- .../src/nm-system-config-interface.c | 32 ++ .../src/nm-system-config-interface.h | 25 ++ 19 files changed, 1228 insertions(+), 244 deletions(-) create mode 100644 system-settings/plugins/keyfile/Makefile.am create mode 100644 system-settings/plugins/keyfile/plugin.c create mode 100644 system-settings/plugins/keyfile/plugin.h create mode 100644 system-settings/plugins/keyfile/reader.c create mode 100644 system-settings/plugins/keyfile/reader.h create mode 100644 system-settings/plugins/keyfile/writer.c create mode 100644 system-settings/plugins/keyfile/writer.h diff --git a/ChangeLog b/ChangeLog index dace66f0b6..8d88af49c6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,36 @@ +2008-04-22 Tambet Ingo + + Implement GKeyFile system settings plugin. + Implement writing system settings (currently supported only by GKeyFile plugin). + + * system-settings/src/main.c: + * system-settings/src/dbus-settings.c: Move the communication with plugins + from main.c to dbus-settings.c. Makes it possible to talk to all registered + plugins for adding/updating/removing connections. + + * system-settings/src/nm-system-config-interface.c + (nm_system_config_interface_add_connection): Implement + (nm_system_config_interface_update_connection): Implement. + (nm_system_config_interface_remove_connection): Implement. + + * system-settings/plugins/keyfile/Makefile.am: + * system-settings/plugins/keyfile/plugin.[ch]: + * system-settings/plugins/keyfile/writer.[ch]: + * system-settings/plugins/keyfile/reader.[ch]: Implement. + + * system-settings/plugins/Makefile.am: Add GKeyFile plugin. + + * configure.in: Generate GKeyFile Makefile. + + * libnm-glib/nm-settings.c (impl_exported_connection_get_id): Fix a memory + corruption, need to duplicate the returned string. + (impl_exported_connection_update): Implement. + (impl_exported_connection_delete): Implement. + + * introspection/nm-settings-system.xml: Add "AddConnection" method. + + * introspection/nm-exported-connection.xml: Add "Update" and "Delete" methods. + 2008-04-22 Dan Williams Patch from Charles R. Anderson (cra@wpi.edu) diff --git a/configure.in b/configure.in index e6b9cd6c14..caab4a7b72 100644 --- a/configure.in +++ b/configure.in @@ -308,6 +308,7 @@ system-settings/src/Makefile system-settings/plugins/Makefile system-settings/plugins/ifcfg-fedora/Makefile system-settings/plugins/ifcfg-suse/Makefile +system-settings/plugins/keyfile/Makefile test/Makefile test/test-common/Makefile initscript/Makefile diff --git a/introspection/nm-exported-connection.xml b/introspection/nm-exported-connection.xml index 05fdfe0c55..251ccafd40 100644 --- a/introspection/nm-exported-connection.xml +++ b/introspection/nm-exported-connection.xml @@ -18,6 +18,25 @@ + + + Update the connection. + + + + + New connection properties. + + + + + + + Delete the connection. + + + + Get the settings maps describing this object. diff --git a/introspection/nm-settings-system.xml b/introspection/nm-settings-system.xml index b05f7e34db..a6e0e3b490 100644 --- a/introspection/nm-settings-system.xml +++ b/introspection/nm-settings-system.xml @@ -6,6 +6,18 @@ Implemented by the system settings service to provide additional settings to NetworkManager. + + + Add new connection. + + + + + Connection properties. + + + + The list of HAL UDIs of devices that should not be managed by NetworkManager. diff --git a/libnm-glib/nm-settings.c b/libnm-glib/nm-settings.c index 1dce10d5c8..1b1e1320c4 100644 --- a/libnm-glib/nm-settings.c +++ b/libnm-glib/nm-settings.c @@ -107,6 +107,14 @@ static gboolean impl_exported_connection_get_id (NMExportedConnection *connectio static gboolean impl_exported_connection_get_settings (NMExportedConnection *connection, GHashTable **settings, GError **error); + +static gboolean impl_exported_connection_update (NMExportedConnection *connection, + GHashTable *new_settings, + GError *err); + +static gboolean impl_exported_connection_delete (NMExportedConnection *connection, + GError *err); + static void impl_exported_connection_get_secrets (NMExportedConnection *connection, const gchar *setting_name, const gchar **hints, @@ -169,7 +177,7 @@ impl_exported_connection_get_id (NMExportedConnection *connection, { g_return_val_if_fail (NM_IS_EXPORTED_CONNECTION (connection), FALSE); - *id = (gchar *) nm_exported_connection_get_id (connection); + *id = g_strdup (nm_exported_connection_get_id (connection)); if (!*id) { g_set_error (error, NM_SETTINGS_ERROR, 1, "%s.%d - Could not get connection ID.", @@ -182,8 +190,8 @@ impl_exported_connection_get_id (NMExportedConnection *connection, static gboolean impl_exported_connection_get_settings (NMExportedConnection *connection, - GHashTable **settings, - GError **error) + GHashTable **settings, + GError **error) { NMExportedConnectionPrivate *priv; @@ -199,6 +207,32 @@ impl_exported_connection_get_settings (NMExportedConnection *connection, return TRUE; } +static gboolean +impl_exported_connection_update (NMExportedConnection *connection, + GHashTable *new_settings, + GError *err) +{ + if (EXPORTED_CONNECTION_CLASS (connection)->update) + EXPORTED_CONNECTION_CLASS (connection)->update (connection, new_settings); + else + nm_connection_replace_settings (NM_EXPORTED_CONNECTION_GET_PRIVATE (connection)->wrapped, new_settings); + + nm_exported_connection_signal_updated (connection, new_settings); + + return TRUE; +} + +static gboolean +impl_exported_connection_delete (NMExportedConnection *connection, GError *err) +{ + if (EXPORTED_CONNECTION_CLASS (connection)->delete) + EXPORTED_CONNECTION_CLASS (connection)->delete (connection); + + nm_exported_connection_signal_removed (connection); + + return TRUE; +} + static void impl_exported_connection_get_secrets (NMExportedConnection *connection, const gchar *setting_name, diff --git a/libnm-glib/nm-settings.h b/libnm-glib/nm-settings.h index 7fef7c5f88..62c3525c29 100644 --- a/libnm-glib/nm-settings.h +++ b/libnm-glib/nm-settings.h @@ -37,6 +37,11 @@ typedef struct { gboolean request_new, DBusGMethodInvocation *context); + void (*update) (NMExportedConnection *connection, + GHashTable *new_settings); + + void (*delete) (NMExportedConnection *connection); + /* signals */ void (* updated) (NMExportedConnection *connection, GHashTable *settings); void (* removed) (NMExportedConnection *connection); diff --git a/system-settings/plugins/Makefile.am b/system-settings/plugins/Makefile.am index 30c4228435..9beea07a95 100644 --- a/system-settings/plugins/Makefile.am +++ b/system-settings/plugins/Makefile.am @@ -1,11 +1,13 @@ +SUBDIRS=keyfile + if TARGET_REDHAT -SUBDIRS=ifcfg-fedora +SUBDIRS+=ifcfg-fedora endif if TARGET_SUSE -SUBDIRS=ifcfg-suse +SUBDIRS+=ifcfg-suse endif if TARGET_MANDRIVA -SUBDIRS=ifcfg-fedora +SUBDIRS+=ifcfg-fedora endif diff --git a/system-settings/plugins/keyfile/Makefile.am b/system-settings/plugins/keyfile/Makefile.am new file mode 100644 index 0000000000..1523d6eaec --- /dev/null +++ b/system-settings/plugins/keyfile/Makefile.am @@ -0,0 +1,28 @@ + +pkglib_LTLIBRARIES = libnm-settings-plugin-keyfile.la + +libnm_settings_plugin_keyfile_la_SOURCES = \ + plugin.c \ + plugin.h \ + reader.c \ + reader.h \ + writer.c \ + writer.h + +libnm_settings_plugin_keyfile_la_CPPFLAGS = \ + $(GLIB_CFLAGS) \ + $(GMODULE_CFLAGS) \ + $(DBUS_CFLAGS) \ + -DG_DISABLE_DEPRECATED \ + -I${top_srcdir}/system-settings/src \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/libnm-util \ + -DKEYFILE_DIR=\""$(sysconfdir)/NetworkManager/system_config"\" + +libnm_settings_plugin_keyfile_la_LDFLAGS = -module -avoid-version +libnm_settings_plugin_keyfile_la_LIBADD = \ + $(GLIB_LIBS) \ + $(GMODULE_LIBS) \ + $(GIO_LIBS) \ + $(top_builddir)/libnm-util/libnm-util.la + diff --git a/system-settings/plugins/keyfile/plugin.c b/system-settings/plugins/keyfile/plugin.c new file mode 100644 index 0000000000..c1d7deafa9 --- /dev/null +++ b/system-settings/plugins/keyfile/plugin.c @@ -0,0 +1,310 @@ +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "plugin.h" +#include "nm-system-config-interface.h" +#include "reader.h" +#include "writer.h" + +#define KEYFILE_PLUGIN_NAME "keyfile" +#define KEYFILE_PLUGIN_INFO "(c) 2007 - 2008 Red Hat, Inc. To report bugs please use the NetworkManager mailing list." + +static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class); + +G_DEFINE_TYPE_EXTENDED (SCPluginKeyfile, sc_plugin_keyfile, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, + system_config_interface_init)) + +#define SC_PLUGIN_KEYFILE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_KEYFILE, SCPluginKeyfilePrivate)) + +typedef struct { + GHashTable *hash; + + GFileMonitor *monitor; + guint monitor_id; + + gboolean disposed; +} SCPluginKeyfilePrivate; + +static NMConnection * +read_one_connection (NMSystemConfigInterface *config, const char *filename) +{ + SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config); + char *full_path; + NMConnection *connection = NULL; + + full_path = g_build_filename (KEYFILE_DIR, filename, NULL); + connection = connection_from_file (full_path); + if (connection) + g_hash_table_insert (priv->hash, g_strdup (filename), connection); + + g_free (full_path); + + return connection; +} + +static void +read_connections (NMSystemConfigInterface *config) +{ + GDir *dir; + GError *err = NULL; + + dir = g_dir_open (KEYFILE_DIR, 0, &err); + if (dir) { + const char *item; + + while ((item = g_dir_read_name (dir))) + read_one_connection (config, item); + + g_dir_close (dir); + } else { + g_warning ("Can not read directory '%s': %s", KEYFILE_DIR, err->message); + g_error_free (err); + } +} + +static void +delete_connection (NMSystemConfigInterface *config, NMConnection *connection) +{ + SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config); + NMSettingConnection *s_con; + char *filename; + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + if (!s_con) + return; + + filename = g_build_filename (KEYFILE_DIR, s_con->id, NULL); + + if (g_hash_table_lookup (priv->hash, s_con->id)) { + if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) + /* Monitoring takes care of the rest */ + g_unlink (filename); + else + g_warning ("File '%s' does not exist", filename); + } + + g_free (filename); +} + +/* Monitoring */ + +static void +dir_changed (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + NMSystemConfigInterface *config = NM_SYSTEM_CONFIG_INTERFACE (user_data); + SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config); + char *name; + NMConnection *connection; + + name = g_file_get_basename (file); + connection = g_hash_table_lookup (priv->hash, name); + + switch (event_type) { + case G_FILE_MONITOR_EVENT_DELETED: + if (connection) { + g_hash_table_remove (priv->hash, name); + g_signal_emit_by_name (config, "connection-removed", connection); + } + break; + case G_FILE_MONITOR_EVENT_CREATED: + case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: + if (connection) { + /* Update */ + char *full_path; + NMConnection *tmp; + + full_path = g_file_get_path (file); + tmp = connection_from_file (full_path); + g_free (full_path); + + if (tmp) { + GHashTable *settings; + + settings = nm_connection_to_hash (tmp); + + if (nm_connection_replace_settings (connection, settings)) + g_signal_emit_by_name (config, "connection-updated", connection); + + g_hash_table_destroy (settings); + g_object_unref (tmp); + } + } else { + /* New */ + connection = read_one_connection (config, name); + if (connection) + g_signal_emit_by_name (config, "connection-added", connection); + } + break; + default: + break; + } + + g_free (name); +} + +static void +setup_monitoring (NMSystemConfigInterface *config) +{ + SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config); + GFile *file; + GFileMonitor *monitor; + + priv->hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + + file = g_file_new_for_path (KEYFILE_DIR); + monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref (file); + + if (monitor) { + priv->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (dir_changed), config); + priv->monitor = monitor; + } +} + +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; + + if (!priv->hash) { + setup_monitoring (config); + read_connections (config); + } + + g_hash_table_foreach (priv->hash, hash_to_slist, &connections); + + return connections; +} + +static void +add_connection (NMSystemConfigInterface *config, NMConnection *connection) +{ + write_connection (connection); +} + +static void +update_connection (NMSystemConfigInterface *config, NMConnection *connection) +{ + write_connection (connection); +} + +static void +remove_connection (NMSystemConfigInterface *config, NMConnection *connection) +{ + delete_connection (config, connection); +} + +/* GObject */ + +static void +sc_plugin_keyfile_init (SCPluginKeyfile *plugin) +{ +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + switch (prop_id) { + case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME: + g_value_set_string (value, KEYFILE_PLUGIN_NAME); + break; + case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO: + g_value_set_string (value, KEYFILE_PLUGIN_INFO); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (object); + + if (priv->disposed) + return; + + priv->disposed = TRUE; + + if (priv->monitor) { + if (priv->monitor_id) + g_signal_handler_disconnect (priv->monitor, priv->monitor_id); + + g_file_monitor_cancel (priv->monitor); + g_object_unref (priv->monitor); + } + + g_hash_table_destroy (priv->hash); + + G_OBJECT_CLASS (sc_plugin_keyfile_parent_class)->dispose (object); +} + +static void +sc_plugin_keyfile_class_init (SCPluginKeyfileClass *req_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (req_class); + + g_type_class_add_private (req_class, sizeof (SCPluginKeyfilePrivate)); + + object_class->dispose = dispose; + object_class->get_property = get_property; + + g_object_class_override_property (object_class, + NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, + NM_SYSTEM_CONFIG_INTERFACE_NAME); + + g_object_class_override_property (object_class, + NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, + NM_SYSTEM_CONFIG_INTERFACE_INFO); +} + +static void +system_config_interface_init (NMSystemConfigInterface *system_config_interface_class) +{ + /* interface implementation */ + system_config_interface_class->get_connections = get_connections; + system_config_interface_class->add_connection = add_connection; + system_config_interface_class->update_connection = update_connection; + system_config_interface_class->remove_connection = remove_connection; +} + +G_MODULE_EXPORT GObject * +nm_system_config_factory (void) +{ + static SCPluginKeyfile *singleton = NULL; + + if (!singleton) + singleton = SC_PLUGIN_KEYFILE (g_object_new (SC_TYPE_PLUGIN_KEYFILE, NULL)); + else + g_object_ref (singleton); + + return G_OBJECT (singleton); +} diff --git a/system-settings/plugins/keyfile/plugin.h b/system-settings/plugins/keyfile/plugin.h new file mode 100644 index 0000000000..8a8262eab2 --- /dev/null +++ b/system-settings/plugins/keyfile/plugin.h @@ -0,0 +1,27 @@ +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ + +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +#include + +#define SC_TYPE_PLUGIN_KEYFILE (sc_plugin_keyfile_get_type ()) +#define SC_PLUGIN_KEYFILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_KEYFILE, SCPluginKeyfile)) +#define SC_PLUGIN_KEYFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_KEYFILE, SCPluginKeyfileClass)) +#define SC_IS_PLUGIN_KEYFILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_KEYFILE)) +#define SC_IS_PLUGIN_KEYFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SC_TYPE_PLUGIN_KEYFILE)) +#define SC_PLUGIN_KEYFILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_KEYFILE, SCPluginKeyfileClass)) + +typedef struct { + GObject parent; +} SCPluginKeyfile; + +typedef struct { + GObjectClass parent; +} SCPluginKeyfileClass; + +GType sc_plugin_keyfile_get_type (void); + +GQuark keyfile_plugin_error_quark (void); + +#endif /* _PLUGIN_H_ */ diff --git a/system-settings/plugins/keyfile/reader.c b/system-settings/plugins/keyfile/reader.c new file mode 100644 index 0000000000..05cc73a00f --- /dev/null +++ b/system-settings/plugins/keyfile/reader.c @@ -0,0 +1,196 @@ +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ + +#include +#include +#include +#include +#include + +#include "reader.h" + +#define DBUS_TYPE_G_ARRAY_OF_UINT (dbus_g_type_get_collection ("GArray", G_TYPE_UINT)) +#define DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_ARRAY_OF_UINT)) + +static void +read_one_setting_value (NMSetting *setting, + const char *key, + const GValue *value, + gboolean secret, + gpointer user_data) +{ + GKeyFile *file = (GKeyFile *) user_data; + GType type; + GError *err = NULL; + + if (!g_key_file_has_key (file, setting->name, key, &err)) { + if (err) { + g_warning ("Error loading setting '%s' value: %s", setting->name, err->message); + g_error_free (err); + } + + return; + } + + type = G_VALUE_TYPE (value); + + if (type == G_TYPE_STRING) { + char *str_val; + + str_val = g_key_file_get_string (file, setting->name, key, NULL); + g_object_set (setting, key, str_val, NULL); + g_free (str_val); + } else if (type == G_TYPE_UINT) { + int int_val; + + int_val = g_key_file_get_integer (file, setting->name, key, NULL); + if (int_val < 0) + g_warning ("Casting negative value (%i) to uint", int_val); + g_object_set (setting, key, int_val, NULL); + } else if (type == G_TYPE_INT) { + int int_val; + + int_val = g_key_file_get_integer (file, setting->name, key, NULL); + g_object_set (setting, key, int_val, NULL); + } else if (type == G_TYPE_BOOLEAN) { + gboolean bool_val; + + bool_val = g_key_file_get_boolean (file, setting->name, key, NULL); + g_object_set (setting, key, bool_val, NULL); + } else if (type == G_TYPE_CHAR) { + int int_val; + + int_val = g_key_file_get_integer (file, setting->name, key, NULL); + if (int_val < G_MININT8 || int_val > G_MAXINT8) + g_warning ("Casting value (%i) to char", int_val); + + g_object_set (setting, key, int_val, NULL); + } else if (type == G_TYPE_UINT64) { + char *tmp_str; + guint64 uint_val; + + tmp_str = g_key_file_get_value (file, setting->name, key, NULL); + uint_val = g_ascii_strtoull (tmp_str, NULL, 10); + g_object_set (setting, key, uint_val, NULL); + } else if (type == DBUS_TYPE_G_UCHAR_ARRAY) { + gint *tmp; + GByteArray *array; + gsize length; + int i; + + tmp = g_key_file_get_integer_list (file, setting->name, key, &length, NULL); + + array = g_byte_array_sized_new (length); + for (i = 0; i < length; i++) { + int val = tmp[i]; + unsigned char v = (unsigned char) (val & 0xFF); + + if (val < 0 || val > 255) + g_warning ("Value out of range for a byte value"); + else + g_byte_array_append (array, (const unsigned char *) &v, sizeof (v)); + } + + g_object_set (setting, key, array, NULL); + g_byte_array_free (array, TRUE); + } else if (type == dbus_g_type_get_collection ("GSList", G_TYPE_STRING)) { + gchar **sa; + gsize length; + int i; + GSList *list = NULL; + + sa = g_key_file_get_string_list (file, setting->name, key, &length, NULL); + for (i = 0; i < length; i++) + list = g_slist_prepend (list, sa[i]); + + list = g_slist_reverse (list); + g_object_set (setting, key, list, NULL); + + g_slist_free (list); + g_strfreev (sa); + } else if (type == dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)) { + /* FIXME */ + g_warning ("Implement me"); + } else if (type == DBUS_TYPE_G_UINT_ARRAY) { + gint *tmp; + GArray *array; + gsize length; + int i; + + tmp = g_key_file_get_integer_list (file, setting->name, key, &length, NULL); + + array = g_array_sized_new (FALSE, FALSE, sizeof (guint32), length); + for (i = 0; i < length; i++) + g_array_append_val (array, tmp[i]); + + g_object_set (setting, key, array, NULL); + g_array_free (array, TRUE); + } else if (type == DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT) { + /* FIXME */ + g_warning ("Implement me"); + } else { + g_warning ("Unhandled setting property type (read): '%s/%s' : '%s'", + setting->name, key, G_VALUE_TYPE_NAME (value)); + } +} + +static NMSetting * +read_setting (GKeyFile *file, const char *name) +{ + NMSetting *setting; + + setting = nm_connection_create_setting (name); + if (setting) { + nm_setting_enumerate_values (setting, read_one_setting_value, file); + } else + g_warning ("Invalid setting name '%s'", name); + + return setting; +} + +NMConnection * +connection_from_file (const char *filename) +{ + GKeyFile *key_file; + struct stat statbuf; + gboolean bad_owner, bad_permissions; + NMConnection *connection = NULL; + GError *err = NULL; + + if (stat (filename, &statbuf) != 0 || !S_ISREG (statbuf.st_mode)) + return NULL; + + bad_owner = getuid () != statbuf.st_uid; + bad_permissions = statbuf.st_mode & 0077; + + if (bad_owner || bad_permissions) { + g_warning ("Ignorning insecure configuration file '%s'", filename); + return NULL; + } + + key_file = g_key_file_new (); + if (g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &err)) { + gchar **groups; + gsize length; + int i; + + connection = nm_connection_new (); + + groups = g_key_file_get_groups (key_file, &length); + for (i = 0; i < length; i++) { + NMSetting *setting; + + setting = read_setting (key_file, groups[i]); + if (setting) + nm_connection_add_setting (connection, setting); + } + + g_strfreev (groups); + } else { + g_warning ("Error parsing file '%s': %s", filename, err->message); + g_error_free (err); + } + + g_key_file_free (key_file); + + return connection; +} diff --git a/system-settings/plugins/keyfile/reader.h b/system-settings/plugins/keyfile/reader.h new file mode 100644 index 0000000000..6e5ca471b1 --- /dev/null +++ b/system-settings/plugins/keyfile/reader.h @@ -0,0 +1,11 @@ +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ + +#ifndef _KEYFILE_PLUGIN_READER_H +#define _KEYFILE_PLUGIN_READER_H + +#include +#include + +NMConnection *connection_from_file (const char *filename); + +#endif /* _KEYFILE_PLUGIN_READER_H */ diff --git a/system-settings/plugins/keyfile/writer.c b/system-settings/plugins/keyfile/writer.c new file mode 100644 index 0000000000..b8bb5a1294 --- /dev/null +++ b/system-settings/plugins/keyfile/writer.c @@ -0,0 +1,160 @@ +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ + +#include +#include +#include +#include +#include + +#include "writer.h" + +#define DBUS_TYPE_G_ARRAY_OF_UINT (dbus_g_type_get_collection ("GArray", G_TYPE_UINT)) +#define DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_ARRAY_OF_UINT)) + +static void +write_setting_value (NMSetting *setting, + const char *key, + const GValue *value, + gboolean secret, + gpointer user_data) +{ + GKeyFile *file = (GKeyFile *) user_data; + GType type; + + type = G_VALUE_TYPE (value); + + if (type == G_TYPE_STRING) { + const char *str; + + str = g_value_get_string (value); + if (str) + g_key_file_set_string (file, setting->name, key, str); + } else if (type == G_TYPE_UINT) + g_key_file_set_integer (file, setting->name, key, (int) g_value_get_uint (value)); + else if (type == G_TYPE_INT) + g_key_file_set_integer (file, setting->name, key, g_value_get_int (value)); + else if (type == G_TYPE_UINT64) { + char *numstr; + + numstr = g_strdup_printf ("%" G_GUINT64_FORMAT, g_value_get_uint64 (value)); + g_key_file_set_value (file, setting->name, key, numstr); + g_free (numstr); + } else if (type == G_TYPE_BOOLEAN) { + g_key_file_set_boolean (file, setting->name, key, g_value_get_boolean (value)); + } else if (type == G_TYPE_CHAR) { + g_key_file_set_integer (file, setting->name, key, (int) g_value_get_char (value)); + } else if (type == DBUS_TYPE_G_UCHAR_ARRAY) { + GByteArray *array; + + array = (GByteArray *) g_value_get_boxed (value); + if (array && array->len > 0) { + int *tmp_array; + int i; + + tmp_array = g_new (gint, array->len); + for (i = 0; i < array->len; i++) + tmp_array[i] = (int) array->data[i]; + + g_key_file_set_integer_list (file, setting->name, key, tmp_array, array->len); + g_free (tmp_array); + } + } else if (type == dbus_g_type_get_collection ("GSList", G_TYPE_STRING)) { + GSList *list; + GSList *iter; + + list = (GSList *) g_value_get_boxed (value); + if (list) { + char **array; + int i = 0; + + array = g_new (char *, g_slist_length (list)); + for (iter = list; iter; iter = iter->next) + array[i++] = iter->data; + + g_key_file_set_string_list (file, setting->name, key, (const gchar **const) array, i); + g_free (array); + } + } else if (type == dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)) { + /* FIXME */ + g_warning ("Implement me"); + } else if (type == DBUS_TYPE_G_UINT_ARRAY) { + GArray *array; + + array = (GArray *) g_value_get_boxed (value); + if (array && array->len > 0) { + int *tmp_array; + int i; + + tmp_array = g_new (gint, array->len); + for (i = 0; i < array->len; i++) + tmp_array[i] = (int) array->data[i]; + + g_key_file_set_integer_list (file, setting->name, key, tmp_array, array->len); + g_free (tmp_array); + } + } else if (type == DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT) { + GPtrArray *array; + + array = (GPtrArray *) g_value_get_boxed (value); + if (array && array->len > 0) { + int i, j; + int* list; + + list = g_new (int, array->len * 3); + + for (i = 0, j = 0; i < array->len; i++) { + GArray *tuple = g_ptr_array_index (array, i); + + list[j++] = g_array_index (tuple, guint32, 0); + list[j++] = g_array_index (tuple, guint32, 1); + list[j++] = tuple->len == 3 ? g_array_index (tuple, guint32, 2) : 0; + } + + g_key_file_set_integer_list (file, setting->name, key, list, j); + g_free (list); + } + } else + g_warning ("Unhandled setting property type (write) '%s/%s' : '%s'", + setting->name, key, g_type_name (type)); +} + +gboolean +write_connection (NMConnection *connection) +{ + NMSettingConnection *s_con; + GKeyFile *key_file; + char *data; + gsize len; + gboolean success = FALSE; + GError *err = NULL; + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + if (!s_con) + return success; + + key_file = g_key_file_new (); + nm_connection_for_each_setting_value (connection, write_setting_value, key_file); + data = g_key_file_to_data (key_file, &len, &err); + + if (!err) { + char *filename; + + filename = g_build_filename (KEYFILE_DIR, s_con->id, NULL); + g_file_set_contents (filename, data, len, &err); + chmod (filename, S_IRUSR | S_IWUSR); + chown (filename, 0, 0); + + g_free (filename); + success = TRUE; + } + + if (err) { + g_warning ("Error while saving connection: %s", err->message); + g_error_free (err); + } + + g_free (data); + g_key_file_free (key_file); + + return success; +} diff --git a/system-settings/plugins/keyfile/writer.h b/system-settings/plugins/keyfile/writer.h new file mode 100644 index 0000000000..1e5726b9d9 --- /dev/null +++ b/system-settings/plugins/keyfile/writer.h @@ -0,0 +1,11 @@ +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ + +#ifndef _KEYFILE_PLUGIN_WRITER_H +#define _KEYFILE_PLUGIN_WRITER_H + +#include +#include + +gboolean write_connection (NMConnection *connection); + +#endif /* _KEYFILE_PLUGIN_WRITER_H */ diff --git a/system-settings/src/dbus-settings.c b/system-settings/src/dbus-settings.c index 888284c0d8..4d904e7513 100644 --- a/system-settings/src/dbus-settings.c +++ b/system-settings/src/dbus-settings.c @@ -1,3 +1,5 @@ +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ + /* NetworkManager system settings service * * Søren Sandmann @@ -28,9 +30,10 @@ #include "nm-dbus-glib-types.h" #include "dbus-settings.h" -#include "nm-system-config-interface.h" #include "nm-utils.h" +#define NM_SS_PLUGIN_TAG "nm-ss-plugin" + static void exported_connection_get_secrets (NMExportedConnection *connection, const gchar *setting_name, const gchar **hints, @@ -93,7 +96,7 @@ exported_connection_get_secrets (NMExportedConnection *sys_connection, goto error; } - plugin = g_object_get_data (G_OBJECT (connection), NM_SS_PLUGIN_TAG); + plugin = g_object_get_data (G_OBJECT (sys_connection), NM_SS_PLUGIN_TAG); if (!plugin) { g_set_error (&error, NM_SETTINGS_ERROR, 1, "%s.%d - Connection had no plugin to ask for secrets.", @@ -174,11 +177,21 @@ nm_sysconfig_exported_connection_new (NMConnection *connection, * NMSettings */ +static gboolean +impl_settings_add_connection (NMSysconfigSettings *self, GHashTable *hash, GError **err); + #include "nm-settings-system-glue.h" typedef struct { + DBusGConnection *g_connection; + NMSystemConfigHalManager *hal_mgr; + + GSList *plugins; + gboolean connections_loaded; GSList *connections; GHashTable *unmanaged_devices; + + gboolean in_plugin_signal_handler; } NMSysconfigSettingsPrivate; G_DEFINE_TYPE (NMSysconfigSettings, nm_sysconfig_settings, NM_TYPE_SETTINGS); @@ -204,12 +217,11 @@ static GPtrArray * list_connections (NMSettings *settings) { NMSysconfigSettings *self = NM_SYSCONFIG_SETTINGS (settings); - NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); GPtrArray *connections; GSList *iter; connections = g_ptr_array_new (); - for (iter = priv->connections; iter; iter = g_slist_next (iter)) { + for (iter = nm_sysconfig_settings_get_connections (self); iter; iter = g_slist_next (iter)) { NMExportedConnection *exported = NM_EXPORTED_CONNECTION (iter->data); NMConnection *connection; char *path; @@ -238,6 +250,12 @@ settings_finalize (GObject *object) g_hash_table_destroy (priv->unmanaged_devices); + g_slist_foreach (priv->plugins, (GFunc) g_object_unref, NULL); + g_slist_free (priv->plugins); + + g_object_unref (priv->hal_mgr); + dbus_g_connection_unref (priv->g_connection); + G_OBJECT_CLASS (nm_sysconfig_settings_parent_class)->finalize (object); } @@ -367,142 +385,296 @@ nm_sysconfig_settings_init (NMSysconfigSettings *self) } NMSysconfigSettings * -nm_sysconfig_settings_new (DBusGConnection *g_conn) +nm_sysconfig_settings_new (DBusGConnection *g_conn, NMSystemConfigHalManager *hal_mgr) { NMSysconfigSettings *settings; + NMSysconfigSettingsPrivate *priv; - settings = g_object_new (nm_sysconfig_settings_get_type (), NULL); + g_return_val_if_fail (g_conn != NULL, NULL); + g_return_val_if_fail (hal_mgr != NULL, NULL); + + settings = g_object_new (NM_TYPE_SYSCONFIG_SETTINGS, NULL); dbus_g_connection_register_g_object (g_conn, NM_DBUS_PATH_SETTINGS, G_OBJECT (settings)); + + priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (settings); + priv->g_connection = dbus_g_connection_ref (g_conn); + priv->hal_mgr = g_object_ref (hal_mgr); + return settings; } +static void +plugin_connection_added (NMSystemConfigInterface *config, + NMConnection *connection, + gpointer user_data) +{ + nm_sysconfig_settings_add_connection (NM_SYSCONFIG_SETTINGS (user_data), config, connection); +} + +static void +plugin_connection_removed (NMSystemConfigInterface *config, + NMConnection *connection, + gpointer user_data) +{ + NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (user_data); + + priv->in_plugin_signal_handler = TRUE; + nm_sysconfig_settings_remove_connection (NM_SYSCONFIG_SETTINGS (user_data), connection); + priv->in_plugin_signal_handler = FALSE; +} + +static void +plugin_connection_updated (NMSystemConfigInterface *config, + NMConnection *connection, + gpointer user_data) +{ + NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (user_data); + + priv->in_plugin_signal_handler = TRUE; + nm_sysconfig_settings_update_connection (NM_SYSCONFIG_SETTINGS (user_data), connection); + priv->in_plugin_signal_handler = FALSE; +} + +static void +unmanaged_devices_changed (NMSystemConfigInterface *config, + gpointer user_data) +{ + NMSysconfigSettings *self = NM_SYSCONFIG_SETTINGS (user_data); + NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); + GSList *iter; + + g_hash_table_remove_all (priv->unmanaged_devices); + + /* Ask all the plugins for their unmanaged devices */ + for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { + GSList *udis = nm_system_config_interface_get_unmanaged_devices (NM_SYSTEM_CONFIG_INTERFACE (iter->data)); + GSList *udi_iter; + + for (udi_iter = udis; udi_iter; udi_iter = udi_iter->next) { + if (!g_hash_table_lookup (priv->unmanaged_devices, udi_iter->data)) { + g_hash_table_insert (priv->unmanaged_devices, + udi_iter->data, + GUINT_TO_POINTER (1)); + } else + g_free (udi_iter->data); + } + + g_slist_free (udis); + } + + g_object_notify (G_OBJECT (self), NM_SYSCONFIG_SETTINGS_UNMANAGED_DEVICES); +} + +void +nm_sysconfig_settings_add_plugin (NMSysconfigSettings *self, + NMSystemConfigInterface *plugin) +{ + NMSysconfigSettingsPrivate *priv; + char *pname = NULL; + char *pinfo = NULL; + + g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self)); + g_return_if_fail (NM_IS_SYSTEM_CONFIG_INTERFACE (plugin)); + + priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); + + priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin)); + + g_signal_connect (plugin, "connection-added", G_CALLBACK (plugin_connection_added), self); + g_signal_connect (plugin, "connection-removed", G_CALLBACK (plugin_connection_removed), self); + g_signal_connect (plugin, "connection-updated", G_CALLBACK (plugin_connection_updated), self); + + g_signal_connect (plugin, "unmanaged-devices-changed", G_CALLBACK (unmanaged_devices_changed), self); + + nm_system_config_interface_init (plugin, priv->hal_mgr); + + g_object_get (G_OBJECT (plugin), + NM_SYSTEM_CONFIG_INTERFACE_NAME, &pname, + NM_SYSTEM_CONFIG_INTERFACE_INFO, &pinfo, + NULL); + + g_message ("Loaded plugin %s: %s", pname, pinfo); + g_free (pname); + g_free (pinfo); +} + +static void +connection_updated (NMExportedConnection *sys_connection, + GHashTable *new_settings, + gpointer user_data) +{ + NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (user_data); + NMSystemConfigInterface *plugin; + NMConnection *connection; + + if (priv->in_plugin_signal_handler) + return; + + connection = nm_exported_connection_get_connection (sys_connection); + plugin = (NMSystemConfigInterface *) g_object_get_data (G_OBJECT (sys_connection), NM_SS_PLUGIN_TAG); + + if (plugin) { + nm_system_config_interface_update_connection (plugin, connection); + } else { + GSList *iter; + + for (iter = priv->plugins; iter; iter = iter->next) + nm_system_config_interface_update_connection (NM_SYSTEM_CONFIG_INTERFACE (iter->data), connection); + } +} + +static void +connection_removed (NMExportedConnection *sys_connection, + gpointer user_data) +{ + NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (user_data); + NMSystemConfigInterface *plugin; + NMConnection *connection; + + if (priv->in_plugin_signal_handler) + return; + + connection = nm_exported_connection_get_connection (sys_connection); + plugin = (NMSystemConfigInterface *) g_object_get_data (G_OBJECT (sys_connection), NM_SS_PLUGIN_TAG); + + if (plugin) { + nm_system_config_interface_remove_connection (plugin, connection); + } else { + GSList *iter; + + for (iter = priv->plugins; iter; iter = iter->next) + nm_system_config_interface_remove_connection (NM_SYSTEM_CONFIG_INTERFACE (iter->data), connection); + } +} + +static NMExportedConnection * +find_existing_connection (NMSysconfigSettings *self, NMConnection *connection) +{ + NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); + GSList *iter; + + for (iter = priv->connections; iter; iter = g_slist_next (iter)) { + NMExportedConnection *exported = NM_EXPORTED_CONNECTION (iter->data); + NMConnection *wrapped = nm_exported_connection_get_connection (exported); + + if (wrapped == connection) + return exported; + } + + return NULL; +} + void nm_sysconfig_settings_add_connection (NMSysconfigSettings *self, - NMConnection *connection, - DBusGConnection *g_connection) + NMSystemConfigInterface *plugin, + NMConnection *connection) { - NMSysconfigSettingsPrivate *priv; + NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); NMSysconfigExportedConnection *exported; g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self)); g_return_if_fail (NM_IS_CONNECTION (connection)); - priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - exported = nm_sysconfig_exported_connection_new (connection, g_connection); - if (!exported) { - g_warning ("%s: couldn't export the connection!", __func__); + if (find_existing_connection (self, connection)) { + /* A plugin is lying to us */ + g_message ("Connection is already added, ignoring"); return; } - priv->connections = g_slist_append (priv->connections, exported); + exported = nm_sysconfig_exported_connection_new (connection, priv->g_connection); + if (exported) { + priv->connections = g_slist_append (priv->connections, exported); - nm_settings_signal_new_connection (NM_SETTINGS (self), - NM_EXPORTED_CONNECTION (exported)); + g_signal_connect (exported, "updated", G_CALLBACK (connection_updated), self); + g_signal_connect (exported, "removed", G_CALLBACK (connection_removed), self); + + if (plugin) + g_object_set_data (G_OBJECT (exported), NM_SS_PLUGIN_TAG, plugin); + + nm_settings_signal_new_connection (NM_SETTINGS (self), NM_EXPORTED_CONNECTION (exported)); + } else + g_warning ("%s: couldn't export the connection!", __func__); } -static void -remove_connection (NMSysconfigSettings *self, - NMConnection *connection) +void +nm_sysconfig_settings_remove_connection (NMSysconfigSettings *self, + NMConnection *connection) { - NMSysconfigSettingsPrivate *priv; - GSList *iter; + NMExportedConnection *exported; g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self)); g_return_if_fail (NM_IS_CONNECTION (connection)); - priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - for (iter = priv->connections; iter; iter = g_slist_next (iter)) { - NMSysconfigExportedConnection *item = NM_SYSCONFIG_EXPORTED_CONNECTION (iter->data); - NMExportedConnection *exported = NM_EXPORTED_CONNECTION (item); - NMConnection *wrapped; + exported = find_existing_connection (self, connection); + if (exported) { + NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - wrapped = nm_exported_connection_get_connection (exported); - - if (wrapped == connection) { - priv->connections = g_slist_remove_link (priv->connections, iter); - nm_exported_connection_signal_removed (exported); - g_object_unref (item); - g_slist_free (iter); - break; - } + priv->connections = g_slist_remove (priv->connections, exported); + nm_exported_connection_signal_removed (exported); + g_object_unref (exported); } } -void -nm_sysconfig_settings_remove_connection (NMSysconfigSettings *settings, - NMConnection *connection) -{ - remove_connection (settings, connection); -} - void nm_sysconfig_settings_update_connection (NMSysconfigSettings *self, - NMConnection *connection) + NMConnection *connection) { - NMSysconfigSettingsPrivate *priv; - GHashTable *hash; - GSList *iter; - NMSysconfigExportedConnection *found = NULL; + NMExportedConnection *exported; g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self)); g_return_if_fail (NM_IS_CONNECTION (connection)); - priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - for (iter = priv->connections; iter; iter = g_slist_next (iter)) { - NMSysconfigExportedConnection *item = NM_SYSCONFIG_EXPORTED_CONNECTION (iter->data); - NMConnection *wrapped; + exported = find_existing_connection (self, connection); + if (exported) { + if (nm_connection_verify (connection)) { + GHashTable *hash; - wrapped = nm_exported_connection_get_connection (NM_EXPORTED_CONNECTION (item)); - if (wrapped == connection) { - found = item; - break; - } - } - - if (!found) { + hash = nm_connection_to_hash (connection); + nm_exported_connection_signal_updated (exported, hash); + g_hash_table_destroy (hash); + } else + /* If the connection is no longer valid, it gets removed */ + nm_sysconfig_settings_remove_connection (self, connection); + } else g_warning ("%s: cannot update unknown connection", __func__); - return; - } - - /* If the connection is no longer valid, it gets removed */ - if (!nm_connection_verify (connection)) { - remove_connection (self, connection); - return; - } - - hash = nm_connection_to_hash (connection); - nm_exported_connection_signal_updated (NM_EXPORTED_CONNECTION (found), hash); - g_hash_table_destroy (hash); } GSList * nm_sysconfig_settings_get_connections (NMSysconfigSettings *self) -{ - g_return_val_if_fail (NM_IS_SYSCONFIG_SETTINGS (self), NULL); - - return NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self)->connections; -} - -void -nm_sysconfig_settings_update_unamanged_devices (NMSysconfigSettings *self, - GSList *new_list) { NMSysconfigSettingsPrivate *priv; - GSList *iter; - g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self)); + g_return_val_if_fail (NM_IS_SYSCONFIG_SETTINGS (self), NULL); priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - g_hash_table_remove_all (priv->unmanaged_devices); - for (iter = new_list; iter; iter = g_slist_next (iter)) { - if (!g_hash_table_lookup (priv->unmanaged_devices, iter->data)) { - g_hash_table_insert (priv->unmanaged_devices, - g_strdup (iter->data), - GUINT_TO_POINTER (1)); + if (!priv->connections_loaded) { + GSList *iter; + + for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { + NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + GSList *plugin_connections; + GSList *elt; + + plugin_connections = nm_system_config_interface_get_connections (plugin); + + // FIXME: ensure connections from plugins loaded with a lower priority + // get rejected when they conflict with connections from a higher + // priority plugin. + + for (elt = plugin_connections; elt; elt = g_slist_next (elt)) + nm_sysconfig_settings_add_connection (self, plugin, NM_CONNECTION (elt->data)); + + g_slist_free (plugin_connections); } + + /* FIXME: Bad hack */ + unmanaged_devices_changed (NULL, self); + + priv->connections_loaded = TRUE; } - g_object_notify (G_OBJECT (self), NM_SYSCONFIG_SETTINGS_UNMANAGED_DEVICES); + + return priv->connections; } gboolean @@ -519,3 +691,36 @@ nm_sysconfig_settings_is_device_managed (NMSysconfigSettings *self, return TRUE; } +static gboolean +impl_settings_add_connection (NMSysconfigSettings *self, GHashTable *hash, GError **err) +{ + NMConnection *connection; + + connection = nm_connection_new_from_hash (hash); + if (connection) { + NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); + GSList *iter; + + /* 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) NMSysconfigSettings receives the signal and adds it to it's connection list. + + This does not work if none of the plugins is able to write, but that is sort of by design - + if the connection is not saved, it won't be available after reboot and that would be very + inconsistent. Perhaps we should fail this call here as well, but with multiple plugins, + it's not very clear which failures we can ignore and which ones we can't. + */ + + for (iter = priv->plugins; iter; iter = iter->next) + nm_system_config_interface_add_connection (NM_SYSTEM_CONFIG_INTERFACE (iter->data), connection); + + g_object_unref (connection); + return TRUE; + } else { + /* Invalid connection hash */ + /* FIXME: Set error */ + return FALSE; + } +} diff --git a/system-settings/src/dbus-settings.h b/system-settings/src/dbus-settings.h index 3aa5e01bd8..1a1340f96b 100644 --- a/system-settings/src/dbus-settings.h +++ b/system-settings/src/dbus-settings.h @@ -25,7 +25,8 @@ #include #include -#define NM_SS_PLUGIN_TAG "nm-ss-plugin" +#include "nm-system-config-interface.h" +#include "nm-system-config-hal-manager.h" typedef struct _NMSysconfigExportedConnection NMSysconfigExportedConnection; typedef struct _NMSysconfigExportedConnectionClass NMSysconfigExportedConnectionClass; @@ -85,11 +86,15 @@ struct _NMSysconfigSettingsClass GType nm_sysconfig_settings_get_type (void); -NMSysconfigSettings *nm_sysconfig_settings_new (DBusGConnection *g_conn); +NMSysconfigSettings *nm_sysconfig_settings_new (DBusGConnection *g_conn, + NMSystemConfigHalManager *hal_mgr); + +void nm_sysconfig_settings_add_plugin (NMSysconfigSettings *settings, + NMSystemConfigInterface *plugin); void nm_sysconfig_settings_add_connection (NMSysconfigSettings *settings, - NMConnection *connection, - DBusGConnection *g_connection); + NMSystemConfigInterface *plugin, + NMConnection *connection); void nm_sysconfig_settings_remove_connection (NMSysconfigSettings *settings, NMConnection *connection); diff --git a/system-settings/src/main.c b/system-settings/src/main.c index cbd22e206f..10e2d98cc7 100644 --- a/system-settings/src/main.c +++ b/system-settings/src/main.c @@ -47,8 +47,6 @@ #include "nm-system-config-hal-manager-private.h" #include "nm-system-config-interface.h" -#define NM_SS_CONNECTIONS_TAG "nm-ss-connections" - typedef struct { DBusConnection *connection; DBusGConnection *g_connection; @@ -60,8 +58,6 @@ typedef struct { NMSysconfigSettings *settings; GMainLoop *loop; - GSList *plugins; /* In priority order */ - GHashTable *wired_devices; } Application; @@ -84,71 +80,6 @@ plugins_error_quark (void) return error_quark; } - - -static void -connection_added_cb (NMSystemConfigInterface *config, - NMConnection *connection, - Application *app) -{ - GSList **connections; - - connections = g_object_get_data (G_OBJECT (config), NM_SS_CONNECTIONS_TAG); - *connections = g_slist_append (*connections, connection); - - nm_sysconfig_settings_add_connection (app->settings, connection, app->g_connection); -} - -static void -connection_removed_cb (NMSystemConfigInterface *config, - NMConnection *connection, - Application *app) -{ - GSList **connections; - - connections = g_object_get_data (G_OBJECT (config), NM_SS_CONNECTIONS_TAG); - *connections = g_slist_remove (*connections, connection); - - nm_sysconfig_settings_remove_connection (app->settings, connection); -} - -static void -connection_updated_cb (NMSystemConfigInterface *config, - NMConnection *connection, - Application *app) -{ - nm_sysconfig_settings_update_connection (app->settings, connection); -} - -static void -unmanaged_devices_changed_cb (NMSystemConfigInterface *config, - Application *app) -{ - GSList *udis = NULL, *temp, *iter; - - /* Ask all the plugins for their unmanaged devices */ - for (iter = app->plugins; iter; iter = g_slist_next (iter)) { - temp = nm_system_config_interface_get_unmanaged_devices (NM_SYSTEM_CONFIG_INTERFACE (iter->data)); - udis = g_slist_concat (udis, temp); - } - - nm_sysconfig_settings_update_unamanged_devices (app->settings, udis); - g_slist_foreach (udis, (GFunc) g_free, NULL); - g_slist_free (udis); -} - -static void -register_plugin (Application *app, NMSystemConfigInterface *plugin) -{ - g_signal_connect (plugin, "connection-added", (GCallback) connection_added_cb, app); - g_signal_connect (plugin, "connection-removed", (GCallback) connection_removed_cb, app); - g_signal_connect (plugin, "connection-updated", (GCallback) connection_updated_cb, app); - - g_signal_connect (plugin, "unmanaged-devices-changed", (GCallback) unmanaged_devices_changed_cb, app); - - nm_system_config_interface_init (plugin, app->hal_mgr); -} - static GObject * find_plugin (GSList *list, const char *pname) { @@ -171,7 +102,7 @@ find_plugin (GSList *list, const char *pname) return NULL; } -static GSList * +static gboolean load_plugins (Application *app, const char *plugins, GError **error) { GSList *list = NULL; @@ -180,7 +111,7 @@ load_plugins (Application *app, const char *plugins, GError **error) plist = g_strsplit (plugins, ",", 0); if (!plist) - return NULL; + return FALSE; for (pname = plist; *pname; pname++) { GModule *plugin; @@ -225,44 +156,17 @@ load_plugins (Application *app, const char *plugins, GError **error) } g_module_make_resident (plugin); - g_object_set_data_full (obj, "nm-ss-plugin", plugin, (GDestroyNotify) g_module_close); - register_plugin (app, NM_SYSTEM_CONFIG_INTERFACE (obj)); + g_object_weak_ref (obj, (GWeakNotify) g_module_close, plugin); + nm_sysconfig_settings_add_plugin (app->settings, NM_SYSTEM_CONFIG_INTERFACE (obj)); list = g_slist_append (list, obj); } - + g_strfreev (plist); - return list; -} -static void -print_plugin_info (gpointer item, gpointer user_data) -{ - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (item); - char *pname; - char *pinfo; + g_slist_foreach (list, (GFunc) g_object_unref, NULL); + g_slist_free (list); - g_object_get (G_OBJECT (plugin), - NM_SYSTEM_CONFIG_INTERFACE_NAME, - &pname, - NULL); - - g_object_get (G_OBJECT (plugin), - NM_SYSTEM_CONFIG_INTERFACE_INFO, - &pinfo, - NULL); - - g_message (" %s: %s", pname, pinfo); - g_free (pname); - g_free (pinfo); -} - -static void -free_plugin_connections (gpointer data) -{ - GSList **connections = (GSList **) data; - - g_slist_foreach (*connections, (GFunc) g_object_unref, NULL); - g_slist_free (*connections); + return TRUE; } static gboolean @@ -271,34 +175,6 @@ load_stuff (gpointer user_data) Application *app = (Application *) user_data; GSList *devs, *iter; - g_return_val_if_fail (app != NULL, FALSE); - - for (iter = app->plugins; iter; iter = g_slist_next (iter)) { - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); - GSList *plugin_connections, **connections; - GSList *elt; - - plugin_connections = nm_system_config_interface_get_connections (plugin); - - connections = g_malloc0 (sizeof (GSList *)); - g_object_set_data_full (G_OBJECT (plugin), NM_SS_CONNECTIONS_TAG, - connections, free_plugin_connections); - - // FIXME: ensure connections from plugins loaded with a lower priority - // get rejected when they conflict with connections from a higher - // priority plugin. - - for (elt = plugin_connections; elt; elt = g_slist_next (elt)) { - g_object_ref (NM_CONNECTION (elt->data)); - g_object_set_data (G_OBJECT (elt->data), NM_SS_PLUGIN_TAG, plugin); - connection_added_cb (NM_SYSTEM_CONFIG_INTERFACE (plugin), NM_CONNECTION (elt->data), app); - } - - g_slist_free (plugin_connections); - } - - unmanaged_devices_changed_cb (NULL, app); - /* Grab wired devices to make default DHCP connections for them if needed */ devs = nm_system_config_hal_manager_get_devices_of_type (app->hal_mgr, DEVICE_TYPE_802_3_ETHERNET); for (iter = devs; iter; iter = g_slist_next (iter)) @@ -480,9 +356,8 @@ add_default_dhcp_connection (gpointer user_data) g_byte_array_append (s_wired->mac_address, info->mac->data, ETH_ALEN); nm_connection_add_setting (info->connection, NM_SETTING (s_wired)); - nm_sysconfig_settings_add_connection (info->app->settings, - info->connection, - info->app->g_connection); + nm_sysconfig_settings_add_connection (info->app->settings, NULL, info->connection); + return FALSE; ignore: @@ -782,27 +657,23 @@ main (int argc, char **argv) if (!dbus_init (app)) return -1; - app->settings = nm_sysconfig_settings_new (app->g_connection); + app->hal_mgr = nm_system_config_hal_manager_get (app->g_connection); + app->settings = nm_sysconfig_settings_new (app->g_connection, app->hal_mgr); app->wired_devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, wired_device_info_destroy); - app->hal_mgr = nm_system_config_hal_manager_get (app->g_connection); g_signal_connect (G_OBJECT (app->hal_mgr), "device-added", G_CALLBACK (device_added_cb), app); g_signal_connect (G_OBJECT (app->hal_mgr), "device-removed", G_CALLBACK (device_removed_cb), app); /* Load the plugins; fail if a plugin is not found. */ - app->plugins = load_plugins (app, plugins, &error); + load_plugins (app, plugins, &error); if (error) { - g_slist_foreach (app->plugins, (GFunc) g_object_unref, NULL); - g_slist_free (app->plugins); g_warning ("Error: %d - %s", error->code, error->message); return -1; } g_free (plugins); - g_message ("Loaded plugins:"); - g_slist_foreach (app->plugins, print_plugin_info, NULL); g_idle_add (load_stuff, app); @@ -810,9 +681,6 @@ main (int argc, char **argv) g_hash_table_destroy (app->wired_devices); - g_slist_foreach (app->plugins, (GFunc) g_object_unref, NULL); - g_slist_free (app->plugins); - g_object_unref (app->settings); g_object_unref (app->hal_mgr); diff --git a/system-settings/src/nm-system-config-interface.c b/system-settings/src/nm-system-config-interface.c index 4e0c2560ae..b3fda79598 100644 --- a/system-settings/src/nm-system-config-interface.c +++ b/system-settings/src/nm-system-config-interface.c @@ -161,3 +161,35 @@ nm_system_config_interface_get_unmanaged_devices (NMSystemConfigInterface *confi return NULL; } +void +nm_system_config_interface_add_connection (NMSystemConfigInterface *config, + NMConnection *connection) +{ + g_return_if_fail (config != NULL); + g_return_if_fail (NM_IS_CONNECTION (connection)); + + if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection) + NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection (config, connection); +} + +void +nm_system_config_interface_update_connection (NMSystemConfigInterface *config, + NMConnection *connection) +{ + g_return_if_fail (config != NULL); + g_return_if_fail (NM_IS_CONNECTION (connection)); + + if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->update_connection) + NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->update_connection (config, connection); +} + +void +nm_system_config_interface_remove_connection (NMSystemConfigInterface *config, + NMConnection *connection) +{ + g_return_if_fail (config != NULL); + g_return_if_fail (NM_IS_CONNECTION (connection)); + + if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->remove_connection) + NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->remove_connection (config, connection); +} diff --git a/system-settings/src/nm-system-config-interface.h b/system-settings/src/nm-system-config-interface.h index 43633319a7..b91b0921bc 100644 --- a/system-settings/src/nm-system-config-interface.h +++ b/system-settings/src/nm-system-config-interface.h @@ -99,6 +99,22 @@ struct _NMSystemConfigInterface { */ GSList * (*get_unmanaged_devices) (NMSystemConfigInterface *config); + /* + * Add a new connection. + */ + void (*add_connection) (NMSystemConfigInterface *config, NMConnection *connection); + + /* + * Update the connection. + */ + void (*update_connection) (NMSystemConfigInterface *config, NMConnection *connection); + + /* + * Remove the connection. + */ + void (*remove_connection) (NMSystemConfigInterface *config, NMConnection *connection); + + /* Signals */ /* Emitted when a new connection has been found by the plugin */ @@ -127,6 +143,15 @@ GHashTable *nm_system_config_interface_get_secrets (NMSystemConfigInterface *con GSList *nm_system_config_interface_get_unmanaged_devices (NMSystemConfigInterface *config); +void nm_system_config_interface_add_connection (NMSystemConfigInterface *config, + NMConnection *connection); + +void nm_system_config_interface_update_connection (NMSystemConfigInterface *config, + NMConnection *connection); + +void nm_system_config_interface_remove_connection (NMSystemConfigInterface *config, + NMConnection *connection); + G_END_DECLS #endif /* NM_SYSTEM_CONFIG_INTERFACE_H */