2008-04-22 Tambet Ingo <tambet@gmail.com>

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
This commit is contained in:
Tambet Ingo 2008-04-22 14:48:02 +00:00
parent bfa6b28b59
commit e6a5d0be51
19 changed files with 1228 additions and 244 deletions

View file

@ -1,3 +1,36 @@
2008-04-22 Tambet Ingo <tambet@gmail.com>
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 <dcbw@redhat.com>
Patch from Charles R. Anderson (cra@wpi.edu)

View file

@ -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

View file

@ -18,6 +18,25 @@
</arg>
</method>
<method name="Update">
<tp:docstring>
Update the connection.
</tp:docstring>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_exported_connection_update"/>
<arg name="properties" type="a{sa{sv}}" direction="in">
<tp:docstring>
New connection properties.
</tp:docstring>
</arg>
</method>
<method name="Delete">
<tp:docstring>
Delete the connection.
</tp:docstring>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_exported_connection_delete"/>
</method>
<method name="GetSettings">
<tp:docstring>
Get the settings maps describing this object.

View file

@ -6,6 +6,18 @@
Implemented by the system settings service to provide additional settings to NetworkManager.
</tp:docstring>
<method name="AddConnection">
<tp:docstring>
Add new connection.
</tp:docstring>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_settings_add_connection"/>
<arg name="connection" type="a{sa{sv}}" direction="in">
<tp:docstring>
Connection properties.
</tp:docstring>
</arg>
</method>
<property name="UnmanagedDevices" type="ao" access="read">
<tp:docstring>
The list of HAL UDIs of devices that should not be managed by NetworkManager.

View file

@ -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,

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,310 @@
/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <gmodule.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <gio/gio.h>
#include <nm-connection.h>
#include <nm-setting.h>
#include <nm-setting-connection.h>
#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);
}

View file

@ -0,0 +1,27 @@
/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
#ifndef _PLUGIN_H_
#define _PLUGIN_H_
#include <glib-object.h>
#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_ */

View file

@ -0,0 +1,196 @@
/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <dbus/dbus-glib.h>
#include <nm-setting.h>
#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;
}

View file

@ -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 <glib.h>
#include <nm-connection.h>
NMConnection *connection_from_file (const char *filename);
#endif /* _KEYFILE_PLUGIN_READER_H */

View file

@ -0,0 +1,160 @@
/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
#include <sys/stat.h>
#include <unistd.h>
#include <dbus/dbus-glib.h>
#include <nm-setting.h>
#include <nm-setting-connection.h>
#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;
}

View file

@ -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 <glib.h>
#include <nm-connection.h>
gboolean write_connection (NMConnection *connection);
#endif /* _KEYFILE_PLUGIN_WRITER_H */

View file

@ -1,3 +1,5 @@
/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
/* NetworkManager system settings service
*
* Søren Sandmann <sandmann@daimi.au.dk>
@ -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;
}
}

View file

@ -25,7 +25,8 @@
#include <nm-connection.h>
#include <nm-settings.h>
#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);

View file

@ -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);

View file

@ -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);
}

View file

@ -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 */