diff --git a/ChangeLog b/ChangeLog index c962c181ce..ee5d11709b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,49 @@ +2008-04-07 Dan Williams + + * introspection/nm-settings-system.xml + introspection/Makefile.am + - Define the unmanaged devices interface for the system settings service + + * system-settings/src/nm-system-config-hal-manager.c + system-settings/src/nm-system-config-hal-manager.h + system-settings/src/nm-system-config-hal-manager-private.h + system-settings/src/Makefile.am + - Add a lightweight HAL manager object for tracking network devices for + the purpose of determining unmanaged devices and which devices need + the default DHCP connections + + * system-settings/src/nm-system-config-interface.c + system-settings/src/nm-system-config-interface.h + - (nm_system_config_interface_init): add the HAL manager as an argument + - (nm_system_config_interface_get_unmanaged_devices): implement + - Define 'unmanaged-devices-changed' signal + + * system-settings/src/dbus-settings.c + system-settings/src/dbus-settings.h + - Implement the unmanaged devices interface; some cleanups + + * system-settings/plugins/ifcfg-suse/plugin.c + - Fixup for plugin interface changes + + * system-settings/plugins/ifcfg-fedora/plugin.c + - (get_ether_device_udi): new function; find the device that has + a specified MAC address and return its UDI + - (get_udi_for_connection): new function; try to find the specific + device a connection is locked to, if any + - (device_added_cb, device_removed_cb): update unmanaged device list in + response to HAL events + - (get_unmanaged_devices): new function; return unmanaged device list + - (build_one_connection): set the connection's locked device, if any + - (write_auto_wired_connection): remove + - (kill_old_auto_wired_file): remove the ifcfg-Auto Wired file if found + - (handle_connection_changed): alert listeners that the unmanaged device + list has changed + - (init): fixup for plugin interface changes, implement unmanaged devices + + * system-settings/plugins/ifcfg-fedora/parser.c + system-settings/plugins/ifcfg-fedora/parser.h + - (connection_data_free): clean up connection UDI + 2008-04-07 Dan Williams * system-settings/plugins/ifcfg-fedora/parser.c diff --git a/introspection/Makefile.am b/introspection/Makefile.am index 6b74577a83..143af0c1b6 100644 --- a/introspection/Makefile.am +++ b/introspection/Makefile.am @@ -9,6 +9,7 @@ EXTRA_DIST = \ nm-manager.xml \ nm-manager-client.xml \ nm-settings.xml \ + nm-settings-system.xml \ nm-exported-connection.xml \ nm-vpn-plugin.xml \ nm-vpn-connection.xml \ diff --git a/introspection/nm-settings-system.xml b/introspection/nm-settings-system.xml new file mode 100644 index 0000000000..b05f7e34db --- /dev/null +++ b/introspection/nm-settings-system.xml @@ -0,0 +1,24 @@ + + + + + + Implemented by the system settings service to provide additional settings to NetworkManager. + + + + + The list of HAL UDIs of devices that should not be managed by NetworkManager. + + + + + + + A dictionary mapping property names to variant boxed values + + + + + + diff --git a/system-settings/plugins/ifcfg-fedora/parser.c b/system-settings/plugins/ifcfg-fedora/parser.c index 4046151e27..657c42e4d1 100644 --- a/system-settings/plugins/ifcfg-fedora/parser.c +++ b/system-settings/plugins/ifcfg-fedora/parser.c @@ -112,6 +112,8 @@ connection_data_free (gpointer userdata) g_hash_table_destroy (cdata->ppp_secrets); g_free (cdata->ifcfg_path); + g_free (cdata->udi); + memset (cdata, 0, sizeof (ConnectionData)); g_free (cdata); } diff --git a/system-settings/plugins/ifcfg-fedora/parser.h b/system-settings/plugins/ifcfg-fedora/parser.h index 03026bbd08..397ccbdd6f 100644 --- a/system-settings/plugins/ifcfg-fedora/parser.h +++ b/system-settings/plugins/ifcfg-fedora/parser.h @@ -35,6 +35,7 @@ typedef struct { char *ifcfg_path; + char *udi; gboolean ignored; gboolean exported; diff --git a/system-settings/plugins/ifcfg-fedora/plugin.c b/system-settings/plugins/ifcfg-fedora/plugin.c index a50c0ee37b..e8dde7ebe2 100644 --- a/system-settings/plugins/ifcfg-fedora/plugin.c +++ b/system-settings/plugins/ifcfg-fedora/plugin.c @@ -26,12 +26,21 @@ #include #include #include +#include +#include + +#include #include #include +#include +#include +#include +#include #include #include +#include "nm-dbus-glib-types.h" #include "plugin.h" #include "parser.h" #include "shvar.h" @@ -53,6 +62,10 @@ G_DEFINE_TYPE_EXTENDED (SCPluginIfcfg, sc_plugin_ifcfg, G_TYPE_OBJECT, 0, typedef struct { gboolean initialized; + + DBusGConnection *g_connection; + NMSystemConfigHalManager *hal_mgr; + GSList *connections; int ifd; @@ -72,31 +85,186 @@ ifcfg_plugin_error_quark (void) return error_quark; } -#define AUTO_WIRED_STAMP_FILE SYSCONFDIR"/NetworkManager/auto-wired-stamp" -#define AUTO_WIRED_FILE_NAME _("Auto Wired") +static char * +get_ether_device_udi (SCPluginIfcfg *plugin, GByteArray *mac, GSList *devices) +{ + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + GError *error = NULL; + GSList *iter; + char *udi = NULL; + + if (!priv->g_connection || !mac) + return NULL; + + for (iter = devices; !udi && iter; iter = g_slist_next (iter)) { + DBusGProxy *dev_proxy; + char *address = NULL; + + dev_proxy = dbus_g_proxy_new_for_name (priv->g_connection, + "org.freedesktop.Hal", + iter->data, + "org.freedesktop.Hal.Device"); + if (!dev_proxy) + continue; + + if (dbus_g_proxy_call_with_timeout (dev_proxy, + "GetPropertyString", 10000, &error, + G_TYPE_STRING, "net.address", G_TYPE_INVALID, + G_TYPE_STRING, &address, G_TYPE_INVALID)) { + struct ether_addr *dev_mac; + + if (address && strlen (address)) { + dev_mac = ether_aton (address); + if (!memcmp (dev_mac->ether_addr_octet, mac->data, ETH_ALEN)) + udi = g_strdup (iter->data); + } + } else { + g_error_free (error); + error = NULL; + } + g_free (address); + g_object_unref (dev_proxy); + } + + return udi; +} + +static NMDeviceType +get_device_type_for_connection (NMConnection *connection) +{ + NMDeviceType devtype = DEVICE_TYPE_UNKNOWN; + NMSettingConnection *s_con; + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + if (!s_con) + return DEVICE_TYPE_UNKNOWN; + + if ( !strcmp (s_con->type, NM_SETTING_WIRED_SETTING_NAME) + || !strcmp (s_con->type, NM_SETTING_PPPOE_SETTING_NAME)) { + if (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED)) + devtype = DEVICE_TYPE_802_3_ETHERNET; + } else if (!strcmp (s_con->type, NM_SETTING_WIRELESS_SETTING_NAME)) { + if (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS)) + devtype = DEVICE_TYPE_802_11_WIRELESS; + } else if (!strcmp (s_con->type, NM_SETTING_GSM_SETTING_NAME)) { + if (nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM)) + devtype = DEVICE_TYPE_GSM; + } else if (!strcmp (s_con->type, NM_SETTING_CDMA_SETTING_NAME)) { + if (nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA)) + devtype = DEVICE_TYPE_CDMA; + } + + return devtype; +} + +static char * +get_udi_for_connection (SCPluginIfcfg *plugin, NMConnection *connection, NMDeviceType devtype) +{ + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + NMSettingWired *s_wired; + NMSettingWireless *s_wireless; + char *udi = NULL; + GSList *devices = NULL; + + if (devtype == DEVICE_TYPE_UNKNOWN) + devtype = get_device_type_for_connection (connection); + + switch (devtype) { + case DEVICE_TYPE_802_3_ETHERNET: + s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED); + if (s_wired) { + devices = nm_system_config_hal_manager_get_devices_of_type (priv->hal_mgr, DEVICE_TYPE_802_3_ETHERNET); + udi = get_ether_device_udi (plugin, s_wired->mac_address, devices); + } + break; + + case DEVICE_TYPE_802_11_WIRELESS: + s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS); + if (s_wireless) { + devices = nm_system_config_hal_manager_get_devices_of_type (priv->hal_mgr, DEVICE_TYPE_802_11_WIRELESS); + udi = get_ether_device_udi (plugin, s_wireless->mac_address, devices); + } + break; + + default: + break; + } + + g_slist_foreach (devices, (GFunc) g_free, NULL); + g_slist_free (devices); + + return udi; +} static void -write_auto_wired_connection (const char *profile_path) +device_added_cb (NMSystemConfigHalManager *hal_mgr, + const char *udi, + NMDeviceType devtype, + gpointer user_data) { - GError *error = NULL; - char *path; - const char *contents = "# Written by nm-system-settings\nTYPE=Ethernet\nBOOTPROTO=dhcp\nONBOOT=yes\nUSERCTL=yes\nPEERDNS=yes\n"; + SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + GSList *iter; + gboolean changed = FALSE; - /* Write out a default autoconnect ethernet connection */ - if (g_file_test (AUTO_WIRED_STAMP_FILE, G_FILE_TEST_EXISTS) || !profile_path) - return; + /* Try to get the UDI for all connections that don't have a UDI yet */ + for (iter = priv->connections; iter; iter = g_slist_next (iter)) { + NMConnection *connection = NM_CONNECTION (iter->data); + ConnectionData *cdata = connection_data_get (connection); - path = g_strdup_printf ("%s/ifcfg-%s", profile_path, AUTO_WIRED_FILE_NAME); - if (g_file_test (path, G_FILE_TEST_EXISTS)) - return; - - PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "writing default Auto Wired connection"); - if (!g_file_set_contents (path, contents, -1, &error)) { - PLUGIN_WARN (IFCFG_PLUGIN_NAME, "could not write default wired connection: %s (%d).", error->message, error->code); - g_error_free (error); - } else { - g_file_set_contents (AUTO_WIRED_STAMP_FILE, "", -1, NULL); + if (!cdata->udi) { + cdata->udi = get_udi_for_connection (plugin, connection, devtype); + if (cdata->udi && cdata->ignored) + changed = TRUE; + } } + + if (changed) + g_signal_emit_by_name (plugin, "unmanaged-devices-changed"); +} + +static void +device_removed_cb (NMSystemConfigHalManager *hal_mgr, + const char *udi, + NMDeviceType devtype, + gpointer user_data) +{ + SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + GSList *iter; + gboolean changed = FALSE; + + /* Try to get the UDI for all connections that don't have a UDI yet */ + for (iter = priv->connections; iter; iter = g_slist_next (iter)) { + NMConnection *connection = NM_CONNECTION (iter->data); + ConnectionData *cdata = connection_data_get (connection); + + if (cdata->udi && !strcmp (cdata->udi, udi)) { + g_free (cdata->udi); + cdata->udi = NULL; + if (cdata->ignored) + changed = TRUE; + } + } + + if (changed) + g_signal_emit_by_name (plugin, "unmanaged-devices-changed"); +} + +static GSList * +get_unmanaged_devices (NMSystemConfigInterface *config) +{ + SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + GSList *copy = NULL, *iter; + + for (iter = priv->connections; iter; iter = g_slist_next (iter)) { + ConnectionData *cdata = connection_data_get (NM_CONNECTION (iter->data)); + + if (cdata->ignored && cdata->udi) + copy = g_slist_append (copy, g_strdup (cdata->udi)); + } + return copy; } struct FindInfo { @@ -143,7 +311,7 @@ watch_path (const char *path, const int inotify_fd, GHashTable *table) } static NMConnection * -build_one_connection (const char *path) +build_one_connection (SCPluginIfcfg *plugin, const char *path) { NMConnection *connection; GError *error = NULL; @@ -155,6 +323,9 @@ build_one_connection (const char *path) connection = parser_parse_file (path, &error); if (connection) { NMSettingConnection *s_con; + ConnectionData *cdata = connection_data_get (connection); + + cdata->udi = get_udi_for_connection (plugin, connection, DEVICE_TYPE_UNKNOWN); s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); g_assert (s_con); @@ -169,7 +340,8 @@ build_one_connection (const char *path) } static NMConnection * -handle_new_ifcfg (const char *basename, +handle_new_ifcfg (SCPluginIfcfg *plugin, + const char *basename, const int inotify_fd, GHashTable *watch_table) { @@ -187,7 +359,7 @@ handle_new_ifcfg (const char *basename, return NULL; } - connection = build_one_connection (path); + connection = build_one_connection (plugin, path); if (!connection) goto out; @@ -204,8 +376,8 @@ handle_new_ifcfg (const char *basename, cdata = connection_data_get (connection); if (cdata->ignored) { - PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' because " - "NM_CONTROLLED was false.", basename); + PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' and its " + "device because NM_CONTROLLED was false.", basename); } out: @@ -252,14 +424,47 @@ clear_all_connections (SCPluginIfcfg *plugin) } } +static void +kill_old_auto_wired_file (void) +{ + char *path; + const char *match = "# Written by nm-system-settings\nTYPE=Ethernet\nBOOTPROTO=dhcp\nONBOOT=yes\nUSERCTL=yes\nPEERDNS=yes\n"; + char *contents = NULL; + gsize length = 0; + + path = g_strdup_printf (IFCFG_DIR "/ifcfg-Auto Wired"); + if (!g_file_test (path, G_FILE_TEST_EXISTS)) { + g_free (path); + return; + } + + if (!g_file_get_contents (path, &contents, &length, NULL)) + goto out; + + if (!length && !contents) + goto out; + + if ( (length != strlen (match)) + && (length != (strlen (match) - 1)) + && (length != (strlen (match) + 1))) + goto out; + + if (strncmp (contents, match, MIN (length, strlen (match)))) + goto out; + + unlink (path); + +out: + g_free (contents); + g_free (path); +} + static void read_all_connections (SCPluginIfcfg *plugin) { SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); GDir *dir; const char *item; - GSList *iter; - gboolean have_wired = FALSE; clear_all_connections (plugin); @@ -269,31 +474,25 @@ read_all_connections (SCPluginIfcfg *plugin) if (dir) { while ((item = g_dir_read_name (dir))) { NMConnection *connection; + ConnectionData *cdata; if (strncmp (item, IFCFG_TAG, strlen (IFCFG_TAG))) continue; - connection = handle_new_ifcfg (item, priv->ifd, priv->watch_table); - if (connection) + connection = handle_new_ifcfg (plugin, item, priv->ifd, priv->watch_table); + if (connection) { priv->connections = g_slist_append (priv->connections, connection); + cdata = connection_data_get (connection); + if (cdata->ignored && cdata->udi) + g_signal_emit_by_name (plugin, "unmanaged-devices-changed"); + } } g_dir_close (dir); } else { PLUGIN_WARN (IFCFG_PLUGIN_NAME, "couldn't access network config directory '" IFCFG_DIR "'."); } - /* Check if we need to write out the auto wired connection */ - for (iter = priv->connections; iter; iter = g_slist_next (iter)) { - NMConnection *connection = NM_CONNECTION (iter->data); - NMSettingConnection *s_con; - - s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); - if (!strcmp (s_con->type, NM_SETTING_WIRED_SETTING_NAME)) - have_wired = TRUE; - } - - if (!have_wired) - write_auto_wired_connection (IFCFG_DIR); + kill_old_auto_wired_file (); } static GSList * @@ -427,7 +626,7 @@ handle_connection_changed (SCPluginIfcfg *plugin, } /* Could return NULL if the connection got deleted */ - new_connection = build_one_connection (filename); + new_connection = build_one_connection (plugin, filename); existing = find_connection_by_path (priv->connections, filename); if (!existing) { @@ -440,6 +639,11 @@ handle_connection_changed (SCPluginIfcfg *plugin, if (!new_cdata->ignored) { new_cdata->exported = TRUE; g_signal_emit_by_name (plugin, "connection-added", new_connection); + } else { + PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' and its " + "device because NM_CONTROLLED was false.", basename); + if (new_cdata->udi) + g_signal_emit_by_name (plugin, "unmanaged-devices-changed"); } } g_free (filename); @@ -466,24 +670,34 @@ handle_connection_changed (SCPluginIfcfg *plugin, g_assert (new_cdata); connection_data_copy_secrets (new_cdata, existing_cdata); + g_free (existing_cdata->udi); + existing_cdata->udi = new_cdata->udi ? g_strdup (new_cdata->udi) : NULL; if (new_cdata->ignored && !existing_cdata->ignored) { /* connection now ignored */ + PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "Ignoring connection '%s' and its " + "device because NM_CONTROLLED was false.", basename); + existing_cdata->ignored = TRUE; g_signal_emit_by_name (plugin, "connection-removed", existing); existing_cdata->exported = FALSE; + if (existing_cdata->udi) + g_signal_emit_by_name (plugin, "unmanaged-devices-changed"); } else if (!new_cdata->ignored && existing_cdata->ignored) { /* connection no longer ignored, let the system settings * service know about it now. */ existing_cdata->ignored = FALSE; existing_cdata->exported = TRUE; + if (existing_cdata->udi) + g_signal_emit_by_name (plugin, "unmanaged-devices-changed"); g_signal_emit_by_name (plugin, "connection-added", existing); } else if (!new_cdata->ignored && !existing_cdata->ignored) { /* connection updated and not ignored */ g_signal_emit_by_name (plugin, "connection-updated", existing); } else if (new_cdata->ignored && existing_cdata->ignored) { - /* do nothing */ + if (existing_cdata->udi) + g_signal_emit_by_name (plugin, "unmanaged-devices-changed"); } } g_object_unref (new_connection); @@ -495,6 +709,10 @@ handle_connection_changed (SCPluginIfcfg *plugin, priv->connections = g_slist_remove (priv->connections, existing); if (!existing_cdata->ignored) g_signal_emit_by_name (plugin, "connection-removed", existing); + else { + if (existing_cdata->udi) + g_signal_emit_by_name (plugin, "unmanaged-devices-changed"); + } g_object_unref (existing); PLUGIN_PRINT (IFCFG_PLUGIN_NAME, " removed connection"); } @@ -521,7 +739,7 @@ handle_new_item (SCPluginIfcfg *plugin, const char *basename) return; /* New connection */ - connection = handle_new_ifcfg (basename, priv->ifd, priv->watch_table); + connection = handle_new_ifcfg (plugin, basename, priv->ifd, priv->watch_table); if (!connection) return; @@ -533,6 +751,9 @@ handle_new_item (SCPluginIfcfg *plugin, const char *basename) if (!cdata->ignored) { cdata->exported = TRUE; g_signal_emit_by_name (plugin, "connection-added", connection); + } else { + if (cdata->udi) + g_signal_emit_by_name (plugin, "unmanaged-devices-changed"); } } @@ -665,9 +886,10 @@ sc_plugin_inotify_init (SCPluginIfcfg *plugin, GError **error) } static void -init (NMSystemConfigInterface *config) +init (NMSystemConfigInterface *config, NMSystemConfigHalManager *hal_manager) { SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); GError *error = NULL; if (!sc_plugin_inotify_init (plugin, &error)) { @@ -675,17 +897,38 @@ init (NMSystemConfigInterface *config) error->message ? error->message : "(unknown)"); g_error_free (error); } + + priv->hal_mgr = g_object_ref (hal_manager); + g_signal_connect (priv->hal_mgr, "device-added", G_CALLBACK (device_added_cb), config); + g_signal_connect (priv->hal_mgr, "device-removed", G_CALLBACK (device_removed_cb), config); } static void sc_plugin_ifcfg_init (SCPluginIfcfg *plugin) { + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + GError *error = NULL; + + priv->g_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (!priv->g_connection) { + PLUGIN_PRINT (IFCFG_PLUGIN_NAME, " dbus-glib error: %s", + error->message ? error->message : "(unknown)"); + g_free (error); + } } static void dispose (GObject *object) { - clear_all_connections (SC_PLUGIN_IFCFG (object)); + SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (object); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + + clear_all_connections (plugin); + + g_object_unref (priv->hal_mgr); + + if (priv->g_connection) + g_object_unref (priv->g_connection); G_OBJECT_CLASS (sc_plugin_ifcfg_parent_class)->dispose (object); } @@ -739,6 +982,7 @@ system_config_interface_init (NMSystemConfigInterface *system_config_interface_c /* interface implementation */ system_config_interface_class->get_connections = get_connections; system_config_interface_class->get_secrets = get_secrets; + system_config_interface_class->get_unmanaged_devices = get_unmanaged_devices; system_config_interface_class->init = init; } diff --git a/system-settings/plugins/ifcfg-suse/plugin.c b/system-settings/plugins/ifcfg-suse/plugin.c index f8dc693ae7..4ed5f86c50 100644 --- a/system-settings/plugins/ifcfg-suse/plugin.c +++ b/system-settings/plugins/ifcfg-suse/plugin.c @@ -326,7 +326,7 @@ ifcfg_dir_changed (GFileMonitor *monitor, } static void -init (NMSystemConfigInterface *config) +init (NMSystemConfigInterface *config, NMSystemConfigHalManager *hal_manager) { GFile *file; GFileMonitor *monitor; diff --git a/system-settings/src/Makefile.am b/system-settings/src/Makefile.am index 8417e882d4..b143e3bebd 100644 --- a/system-settings/src/Makefile.am +++ b/system-settings/src/Makefile.am @@ -1,16 +1,23 @@ INCLUDES = -I${top_srcdir} \ -I${top_srcdir}/include \ -I${top_srcdir}/libnm-util \ - -I${top_srcdir}/libnm-glib + -I${top_srcdir}/libnm-glib \ + -I${top_builddir}/marshallers sbin_PROGRAMS = nm-system-settings +BUILT_SOURCES = \ + nm-settings-system-glue.h + nm_system_settings_SOURCES = \ dbus-settings.c \ dbus-settings.h \ main.c \ nm-system-config-interface.c \ - nm-system-config-interface.h + nm-system-config-interface.h \ + nm-system-config-hal-manager.c \ + nm-system-config-hal-manager.h \ + nm-system-config-hal-manager-private.h nm_system_settings_CPPFLAGS = \ $(DBUS_CFLAGS) \ @@ -32,10 +39,15 @@ nm_system_settings_LDADD = \ $(GTHREAD_LIBS) \ $(GMODULE_LIBS) \ $(top_builddir)/libnm-util/libnm-util.la \ - $(top_builddir)/libnm-glib/libnm_glib.la + $(top_builddir)/libnm-glib/libnm_glib.la \ + $(top_builddir)/marshallers/libmarshallers.la nm_system_settings_LDFLAGS = -rdynamic +nm-settings-system-glue.h: $(top_srcdir)/introspection/nm-settings-system.xml + dbus-binding-tool --prefix=nm_settings_system --mode=glib-server --output=nm-settings-system-glue.h $(top_srcdir)/introspection/nm-settings-system.xml + + dbusservicedir = $(DBUS_SYS_DIR) dbusservice_DATA = nm-system-settings.conf @@ -46,4 +58,6 @@ EXTRA_DIST = \ $(dbusservice_DATA) \ $(dbusactivation_DATA) +CLEANFILES = \ + $(BUILT_SOURCES) diff --git a/system-settings/src/dbus-settings.c b/system-settings/src/dbus-settings.c index 3503762c9c..88e8e9216f 100644 --- a/system-settings/src/dbus-settings.c +++ b/system-settings/src/dbus-settings.c @@ -26,6 +26,7 @@ #include +#include "nm-dbus-glib-types.h" #include "dbus-settings.h" #include "nm-system-config-interface.h" #include "nm-utils.h" @@ -150,7 +151,6 @@ nm_sysconfig_exported_connection_class_init (NMSysconfigExportedConnectionClass static void nm_sysconfig_exported_connection_init (NMSysconfigExportedConnection *sysconfig_exported_connection) { - } NMSysconfigExportedConnection * @@ -174,21 +174,42 @@ nm_sysconfig_exported_connection_new (NMConnection *connection, * NMSettings */ +#include "nm-settings-system-glue.h" + +typedef struct { + GSList *connections; + GHashTable *unmanaged_devices; +} NMSysconfigSettingsPrivate; + G_DEFINE_TYPE (NMSysconfigSettings, nm_sysconfig_settings, NM_TYPE_SETTINGS); +#define NM_SYSCONFIG_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SYSCONFIG_SETTINGS, NMSysconfigSettingsPrivate)) + +enum { + PROPERTIES_CHANGED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +enum { + PROP_0, + PROP_UNMANAGED_DEVICES, + + LAST_PROP +}; + static GPtrArray * -nm_sysconfig_settings_list_connections (NMSettings *settings) +list_connections (NMSettings *settings) { + NMSysconfigSettings *self = NM_SYSCONFIG_SETTINGS (settings); + NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); GPtrArray *connections; - NMSysconfigSettings *sysconfig_settings; GSList *iter; - g_return_val_if_fail (NM_IS_SYSCONFIG_SETTINGS (settings), NULL); - - sysconfig_settings = NM_SYSCONFIG_SETTINGS (settings); - connections = g_ptr_array_new (); - for (iter = sysconfig_settings->connections; iter; iter = g_slist_next (iter)) { + for (iter = priv->connections; iter; iter = g_slist_next (iter)) { NMExportedConnection *exported = NM_EXPORTED_CONNECTION (iter->data); NMConnection *connection; char *path; @@ -204,33 +225,145 @@ nm_sysconfig_settings_list_connections (NMSettings *settings) } static void -nm_sysconfig_settings_finalize (GObject *object) +settings_finalize (GObject *object) { - NMSysconfigSettings *settings = NM_SYSCONFIG_SETTINGS (object); + NMSysconfigSettings *self = NM_SYSCONFIG_SETTINGS (object); + NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); - if (settings->connections) { - g_slist_foreach (settings->connections, (GFunc) g_object_unref, NULL); - g_slist_free (settings->connections); - settings->connections = NULL; + if (priv->connections) { + g_slist_foreach (priv->connections, (GFunc) g_object_unref, NULL); + g_slist_free (priv->connections); + priv->connections = NULL; } + g_hash_table_destroy (priv->unmanaged_devices); + G_OBJECT_CLASS (nm_sysconfig_settings_parent_class)->finalize (object); } +static void +add_one_unmanaged_device (gpointer key, gpointer data, gpointer user_data) +{ + GPtrArray *devices = (GPtrArray *) user_data; + + g_ptr_array_add (devices, g_strdup (key)); +} + +static char* +uscore_to_wincaps (const char *uscore) +{ + const char *p; + GString *str; + gboolean last_was_uscore; + + last_was_uscore = TRUE; + + str = g_string_new (NULL); + p = uscore; + while (p && *p) { + if (*p == '-' || *p == '_') + last_was_uscore = TRUE; + else { + if (last_was_uscore) { + g_string_append_c (str, g_ascii_toupper (*p)); + last_was_uscore = FALSE; + } else + g_string_append_c (str, *p); + } + ++p; + } + + return g_string_free (str, FALSE); +} + +static void +notify (GObject *object, GParamSpec *pspec) +{ + GValue *value; + GHashTable *hash; + + value = g_slice_new0 (GValue); + hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL); + + g_value_init (value, pspec->value_type); + g_object_get_property (object, pspec->name, value); + g_hash_table_insert (hash, uscore_to_wincaps (pspec->name), value); + g_signal_emit (object, signals[PROPERTIES_CHANGED], 0, hash); + g_hash_table_destroy (hash); + g_value_unset (value); + g_slice_free (GValue, value); +} + +static GPtrArray * +get_unmanaged_devices (NMSysconfigSettings *self) +{ + NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); + GPtrArray *devices; + + devices = g_ptr_array_sized_new (3); + g_hash_table_foreach (priv->unmanaged_devices, (GHFunc) add_one_unmanaged_device, devices); + return devices; +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSysconfigSettings *self = NM_SYSCONFIG_SETTINGS (object); + + switch (prop_id) { + case PROP_UNMANAGED_DEVICES: + g_value_take_boxed (value, get_unmanaged_devices (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void nm_sysconfig_settings_class_init (NMSysconfigSettingsClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); NMSettingsClass *settings_class = NM_SETTINGS_CLASS (class); - object_class->finalize = nm_sysconfig_settings_finalize; - settings_class->list_connections = nm_sysconfig_settings_list_connections; + g_type_class_add_private (settings_class, sizeof (NMSysconfigSettingsPrivate)); + + /* virtual methods */ + object_class->notify = notify; + object_class->get_property = get_property; + object_class->finalize = settings_finalize; + settings_class->list_connections = list_connections; + + /* properties */ + g_object_class_install_property + (object_class, PROP_UNMANAGED_DEVICES, + g_param_spec_boxed (NM_SYSCONFIG_SETTINGS_UNMANAGED_DEVICES, + "Unamanged devices", + "Unmanaged devices", + DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, + G_PARAM_READABLE)); + + /* signals */ + signals[PROPERTIES_CHANGED] = + g_signal_new ("properties-changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSysconfigSettingsClass, properties_changed), + NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, 1, DBUS_TYPE_G_MAP_OF_VARIANT); + + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (settings_class), + &dbus_glib_nm_settings_system_object_info); } static void -nm_sysconfig_settings_init (NMSysconfigSettings *sysconfig_settings) +nm_sysconfig_settings_init (NMSysconfigSettings *self) { - sysconfig_settings->connections = NULL; + NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self); + + priv->unmanaged_devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); } NMSysconfigSettings * @@ -244,37 +377,41 @@ nm_sysconfig_settings_new (DBusGConnection *g_conn) } void -nm_sysconfig_settings_add_connection (NMSysconfigSettings *settings, +nm_sysconfig_settings_add_connection (NMSysconfigSettings *self, NMConnection *connection, DBusGConnection *g_connection) { + NMSysconfigSettingsPrivate *priv; NMSysconfigExportedConnection *exported; - g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (settings)); + 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__); return; } - settings->connections = g_slist_append (settings->connections, exported); + priv->connections = g_slist_append (priv->connections, exported); - nm_settings_signal_new_connection (NM_SETTINGS (settings), + nm_settings_signal_new_connection (NM_SETTINGS (self), NM_EXPORTED_CONNECTION (exported)); } static void -remove_connection (NMSysconfigSettings *settings, +remove_connection (NMSysconfigSettings *self, NMConnection *connection) { + NMSysconfigSettingsPrivate *priv; GSList *iter; - g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (settings)); + g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self)); g_return_if_fail (NM_IS_CONNECTION (connection)); - for (iter = settings->connections; iter; iter = g_slist_next (iter)) { + 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; @@ -282,7 +419,7 @@ remove_connection (NMSysconfigSettings *settings, wrapped = nm_exported_connection_get_connection (exported); if (wrapped == connection) { - settings->connections = g_slist_remove (settings->connections, iter); + priv->connections = g_slist_remove_link (priv->connections, iter); nm_exported_connection_signal_removed (exported); g_object_unref (item); g_slist_free (iter); @@ -299,22 +436,23 @@ nm_sysconfig_settings_remove_connection (NMSysconfigSettings *settings, } void -nm_sysconfig_settings_update_connection (NMSysconfigSettings *settings, +nm_sysconfig_settings_update_connection (NMSysconfigSettings *self, NMConnection *connection) { + NMSysconfigSettingsPrivate *priv; GHashTable *hash; GSList *iter; NMSysconfigExportedConnection *found = NULL; - g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (settings)); + g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (self)); g_return_if_fail (NM_IS_CONNECTION (connection)); - for (iter = settings->connections; iter; iter = g_slist_next (iter)) { + 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; wrapped = nm_exported_connection_get_connection (NM_EXPORTED_CONNECTION (item)); - if (wrapped == connection) { found = item; break; @@ -328,7 +466,7 @@ nm_sysconfig_settings_update_connection (NMSysconfigSettings *settings, /* If the connection is no longer valid, it gets removed */ if (!nm_connection_verify (connection)) { - remove_connection (settings, connection); + remove_connection (self, connection); return; } @@ -337,3 +475,25 @@ nm_sysconfig_settings_update_connection (NMSysconfigSettings *settings, g_hash_table_destroy (hash); } +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)); + + 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)); + } + } + g_object_notify (G_OBJECT (self), NM_SYSCONFIG_SETTINGS_UNMANAGED_DEVICES); +} + diff --git a/system-settings/src/dbus-settings.h b/system-settings/src/dbus-settings.h index c0424db13f..7cf41b5ad6 100644 --- a/system-settings/src/dbus-settings.h +++ b/system-settings/src/dbus-settings.h @@ -43,12 +43,12 @@ typedef struct _NMSysconfigExportedConnectionClass NMSysconfigExportedConnection struct _NMSysconfigExportedConnection { - NMExportedConnection parent_instance; + NMExportedConnection parent_instance; }; struct _NMSysconfigExportedConnectionClass { - NMExportedConnectionClass parent_class; + NMExportedConnectionClass parent_class; }; GType nm_sysconfig_exported_connection_get_type (void); @@ -68,16 +68,19 @@ typedef struct _NMSysconfigSettingsClass NMSysconfigSettingsClass; #define NM_IS_SYSCONFIG_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SYSCONFIG_SETTINGS)) #define NM_SYSCONFIG_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SYSCONFIG_SETTINGS, NMSysconfigSettingsClass)) +#define NM_SYSCONFIG_SETTINGS_UNMANAGED_DEVICES "unmanaged-devices" + struct _NMSysconfigSettings { - NMSettings parent_instance; - - GSList *connections; + NMSettings parent_instance; }; struct _NMSysconfigSettingsClass { - NMSettingsClass parent_class; + NMSettingsClass parent_class; + + /* Signals */ + void (*properties_changed) (NMSysconfigSettings *settings, GHashTable *properties); }; GType nm_sysconfig_settings_get_type (void); @@ -94,4 +97,7 @@ void nm_sysconfig_settings_remove_connection (NMSysconfigSettings *settings, void nm_sysconfig_settings_update_connection (NMSysconfigSettings *settings, NMConnection *connection); +void nm_sysconfig_settings_update_unamanged_devices (NMSysconfigSettings *settings, + GSList *new_list); + #endif /* __DBUS_SETTINGS_H__ */ diff --git a/system-settings/src/nm-system-config-hal-manager-private.h b/system-settings/src/nm-system-config-hal-manager-private.h new file mode 100644 index 0000000000..cb7d551e27 --- /dev/null +++ b/system-settings/src/nm-system-config-hal-manager-private.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2008 Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* *** Not to be used by system settings service plugins *** */ + +#ifndef NM_SYSTEM_CONFIG_HAL_MANAGER_PRIVATE_H +#define NM_SYSTEM_CONFIG_HAL_MANAGER_PRIVATE_H + +#include "nm-system-config-hal-manager.h" + +NMSystemConfigHalManager *nm_system_config_hal_manager_get (DBusGConnection *g_connection); + +void nm_system_config_hal_manager_reinit_dbus (NMSystemConfigHalManager *manager, + DBusGConnection *g_connection); + +void nm_system_config_hal_manager_deinit_dbus (NMSystemConfigHalManager *manager); + +#endif /* NM_SYSTEM_CONFIG_HAL_MANAGER_PRIVATE_H */ diff --git a/system-settings/src/nm-system-config-hal-manager.c b/system-settings/src/nm-system-config-hal-manager.c new file mode 100644 index 0000000000..9545d1bf96 --- /dev/null +++ b/system-settings/src/nm-system-config-hal-manager.c @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2008 Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + + +#include +#include +#include +#include + +#include "nm-marshal.h" +#include "nm-dbus-glib-types.h" +#include "nm-system-config-hal-manager.h" +#include "nm-system-config-hal-manager-private.h" + +#define NUM_DEVICE_TYPES DEVICE_TYPE_CDMA + +typedef struct { + DBusGConnection *g_connection; + DBusGProxy *proxy; + GHashTable *devices; +} NMSystemConfigHalManagerPrivate; + +#define NM_SYSTEM_CONFIG_HAL_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ + NM_TYPE_SYSTEM_CONFIG_HAL_MANAGER, \ + NMSystemConfigHalManagerPrivate)) + +G_DEFINE_TYPE (NMSystemConfigHalManager, nm_system_config_hal_manager, G_TYPE_OBJECT) + +enum { + DEVICE_ADDED, + DEVICE_REMOVED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static NMDeviceType +get_type_for_udi (NMSystemConfigHalManager *manager, const char *udi) +{ + NMSystemConfigHalManagerPrivate *priv = NM_SYSTEM_CONFIG_HAL_MANAGER_GET_PRIVATE (manager); + NMDeviceType devtype = DEVICE_TYPE_UNKNOWN; + DBusGProxy *dev_proxy; + GError *error = NULL; + GSList *capabilities = NULL, *iter; + + dev_proxy = dbus_g_proxy_new_for_name (priv->g_connection, + "org.freedesktop.Hal", + udi, + "org.freedesktop.Hal.Device"); + if (!dev_proxy) + return DEVICE_TYPE_UNKNOWN; + + if (!dbus_g_proxy_call_with_timeout (dev_proxy, + "GetPropertyStringList", 10000, &error, + G_TYPE_STRING, "info.capabilities", G_TYPE_INVALID, + DBUS_TYPE_G_LIST_OF_STRING, &capabilities, G_TYPE_INVALID)) { + g_error_free (error); + goto out; + } + + if (!g_slist_length (capabilities)) + goto out; + + for (iter = capabilities; iter && (devtype == DEVICE_TYPE_UNKNOWN); iter = g_slist_next (iter)) { + if (!strcmp (iter->data, "net.80203")) + devtype = DEVICE_TYPE_802_3_ETHERNET; + else if (!strcmp (iter->data, "net.80211")) + devtype = DEVICE_TYPE_802_11_WIRELESS; + else if (!strcmp (iter->data, "modem")) { + GSList *csets = NULL, *elt; + + if (dbus_g_proxy_call_with_timeout (dev_proxy, + "GetPropertyStringList", 10000, &error, + G_TYPE_STRING, "modem.command_sets", G_TYPE_INVALID, + DBUS_TYPE_G_LIST_OF_STRING, &csets, G_TYPE_INVALID)) { + for (elt = csets; elt && (devtype == DEVICE_TYPE_UNKNOWN); elt = g_slist_next (elt)) { + if (!strcmp (elt->data, "GSM-07.07")) + devtype = DEVICE_TYPE_GSM; + else if (!strcmp (elt->data, "IS-707-A")) + devtype = DEVICE_TYPE_CDMA; + } + } + } + } + + g_boxed_free (DBUS_TYPE_G_LIST_OF_STRING, capabilities); + +out: + g_object_unref (dev_proxy); + return devtype; +} + +static void +device_added_cb (DBusGProxy *proxy, const char *udi, gpointer user_data) +{ + NMSystemConfigHalManager *manager = NM_SYSTEM_CONFIG_HAL_MANAGER (user_data); + NMSystemConfigHalManagerPrivate *priv = NM_SYSTEM_CONFIG_HAL_MANAGER_GET_PRIVATE (manager); + NMDeviceType devtype; + + if (!g_hash_table_lookup (priv->devices, udi)) { + devtype = get_type_for_udi (manager, udi); + if (devtype != DEVICE_TYPE_UNKNOWN) { + g_hash_table_insert (priv->devices, g_strdup (udi), GUINT_TO_POINTER (devtype)); + g_signal_emit (manager, signals[DEVICE_ADDED], 0, udi, devtype); + } + } +} + +static void +device_removed_cb (DBusGProxy *proxy, const char *udi, gpointer user_data) +{ + NMSystemConfigHalManager *manager = NM_SYSTEM_CONFIG_HAL_MANAGER (user_data); + NMSystemConfigHalManagerPrivate *priv = NM_SYSTEM_CONFIG_HAL_MANAGER_GET_PRIVATE (manager); + NMDeviceType devtype; + + devtype = GPOINTER_TO_UINT (g_hash_table_lookup (priv->devices, udi)); + if (devtype != DEVICE_TYPE_UNKNOWN) { + g_signal_emit (manager, signals[DEVICE_REMOVED], 0, udi, devtype); + g_hash_table_remove (priv->devices, udi); + } +} + +static void +device_new_capability_cb (DBusGProxy *proxy, + const char *udi, + const char *capability, + gpointer user_data) +{ + NMSystemConfigHalManager *manager = NM_SYSTEM_CONFIG_HAL_MANAGER (user_data); + NMSystemConfigHalManagerPrivate *priv = NM_SYSTEM_CONFIG_HAL_MANAGER_GET_PRIVATE (manager); + NMDeviceType devtype; + + if (!g_hash_table_lookup (priv->devices, udi)) { + devtype = get_type_for_udi (manager, udi); + if (devtype != DEVICE_TYPE_UNKNOWN) { + g_hash_table_insert (priv->devices, g_strdup (udi), GUINT_TO_POINTER (devtype)); + g_signal_emit (manager, signals[DEVICE_ADDED], 0, udi, devtype); + } + } +} + +static void +initial_add_devices_of_type (NMSystemConfigHalManager *manager, const char *capability) +{ + NMSystemConfigHalManagerPrivate *priv = NM_SYSTEM_CONFIG_HAL_MANAGER_GET_PRIVATE (manager); + GSList *devices = NULL, *iter; + GError *error = NULL; + + if (!dbus_g_proxy_call_with_timeout (priv->proxy, + "FindDeviceByCapability", 10000, &error, + G_TYPE_STRING, capability, G_TYPE_INVALID, + DBUS_TYPE_G_LIST_OF_STRING, &devices, G_TYPE_INVALID)) { + g_warning ("%s: could not get device from HAL: %s (%d).", + __func__, error->message, error->code); + g_error_free (error); + return; + } + + for (iter = devices; iter; iter = g_slist_next (iter)) + device_added_cb (priv->proxy, (const char *) iter->data, manager); + + if (devices) + g_boxed_free (DBUS_TYPE_G_LIST_OF_STRING, devices); +} + +static gboolean +init_dbus (NMSystemConfigHalManager *manager, DBusGConnection *g_connection) +{ + NMSystemConfigHalManagerPrivate *priv = NM_SYSTEM_CONFIG_HAL_MANAGER_GET_PRIVATE (manager); + + priv->g_connection = g_connection; + priv->proxy = dbus_g_proxy_new_for_name (priv->g_connection, + "org.freedesktop.Hal", + "/org/freedesktop/Hal/Manager", + "org.freedesktop.Hal.Manager"); + if (!priv->proxy) { + g_warning ("Could not get the HAL object!"); + priv->g_connection = NULL; + return FALSE; + } + + dbus_g_proxy_add_signal (priv->proxy, "DeviceAdded", G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "DeviceAdded", G_CALLBACK (device_added_cb), manager, NULL); + + dbus_g_proxy_add_signal (priv->proxy, "DeviceRemoved", G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "DeviceRemoved", G_CALLBACK (device_removed_cb), manager, NULL); + + dbus_g_object_register_marshaller (nm_marshal_VOID__STRING_STRING, + G_TYPE_NONE, + G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (priv->proxy, "NewCapability", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->proxy, "NewCapability", G_CALLBACK (device_new_capability_cb), manager, NULL); + + initial_add_devices_of_type (manager, "net.80203"); + initial_add_devices_of_type (manager, "net.80211"); + initial_add_devices_of_type (manager, "modem"); + + return TRUE; +} + +static void +remove_all_devices (gpointer key, gpointer data, gpointer user_data) +{ + NMSystemConfigHalManager *manager = NM_SYSTEM_CONFIG_HAL_MANAGER (user_data); + + g_signal_emit (manager, signals[DEVICE_REMOVED], 0, key, GPOINTER_TO_UINT (data)); +} + +static void +cleanup_dbus (NMSystemConfigHalManager *manager) +{ + NMSystemConfigHalManagerPrivate *priv = NM_SYSTEM_CONFIG_HAL_MANAGER_GET_PRIVATE (manager); + + g_hash_table_foreach (priv->devices, (GHFunc) remove_all_devices, manager); + g_hash_table_remove_all (priv->devices); + + if (priv->proxy) { + g_object_unref (priv->proxy); + priv->proxy = NULL; + } + + priv->g_connection = NULL; +} + +static NMSystemConfigHalManager * +nm_system_config_hal_manager_new (DBusGConnection *g_connection) +{ + NMSystemConfigHalManager *manager; + + g_return_val_if_fail (g_connection != NULL, NULL); + + manager = g_object_new (NM_TYPE_SYSTEM_CONFIG_HAL_MANAGER, NULL); + + if (!init_dbus (manager, g_connection)) { + g_object_unref (manager); + return NULL; + } + + return manager; +} + +NMSystemConfigHalManager * +nm_system_config_hal_manager_get (DBusGConnection *g_connection) +{ + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + static NMSystemConfigHalManager *singleton = NULL; + + g_static_mutex_lock (&mutex); + if (!singleton) + singleton = nm_system_config_hal_manager_new (g_connection); + else + g_object_ref (singleton); + g_static_mutex_unlock (&mutex); + + return singleton; +} + +static void +nm_system_config_hal_manager_init (NMSystemConfigHalManager *manager) +{ + NMSystemConfigHalManagerPrivate *priv = NM_SYSTEM_CONFIG_HAL_MANAGER_GET_PRIVATE (manager); + + priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); +} + +static void +dispose (GObject *object) +{ + cleanup_dbus (NM_SYSTEM_CONFIG_HAL_MANAGER (object)); + + G_OBJECT_CLASS (nm_system_config_hal_manager_parent_class)->dispose (object); +} + +static void +nm_system_config_hal_manager_class_init (NMSystemConfigHalManagerClass *manager_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (manager_class); + + g_type_class_add_private (manager_class, sizeof (NMSystemConfigHalManagerPrivate)); + + /* virtual methods */ + object_class->dispose = dispose; + + /* signals */ + signals[DEVICE_ADDED] = + g_signal_new ("device-added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSystemConfigHalManagerClass, device_added), + NULL, NULL, + nm_marshal_VOID__STRING_UINT, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_UINT); + + signals[DEVICE_REMOVED] = + g_signal_new ("device-removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSystemConfigHalManagerClass, device_removed), + NULL, NULL, + nm_marshal_VOID__STRING_UINT, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_UINT); +} + +void +nm_system_config_hal_manager_reinit_dbus (NMSystemConfigHalManager *manager, + DBusGConnection *g_connection) +{ + init_dbus (manager, g_connection); +} + +void +nm_system_config_hal_manager_deinit_dbus (NMSystemConfigHalManager *manager) +{ + cleanup_dbus (manager); +} + +typedef struct { + NMDeviceType devtype; + GSList **list; +} GetDeviceInfo; + +static void +add_devices_of_type (gpointer key, gpointer data, gpointer user_data) +{ + GetDeviceInfo *info = (GetDeviceInfo *) user_data; + + if (GPOINTER_TO_UINT (data) == info->devtype) + *(info->list) = g_slist_append (*(info->list), g_strdup (key)); +} + +GSList * +nm_system_config_hal_manager_get_devices_of_type (NMSystemConfigHalManager *manager, + NMDeviceType devtype) +{ + NMSystemConfigHalManagerPrivate *priv; + GetDeviceInfo info; + GSList *list = NULL; + + g_return_val_if_fail (NM_IS_SYSTEM_CONFIG_HAL_MANAGER (manager), NULL); + g_return_val_if_fail (devtype <= NUM_DEVICE_TYPES, NULL); + + priv = NM_SYSTEM_CONFIG_HAL_MANAGER_GET_PRIVATE (manager); + info.devtype = devtype; + info.list = &list; + g_hash_table_foreach (priv->devices, (GHFunc) add_devices_of_type, &info); + + return list; +} + +DBusGProxy * +nm_system_config_hal_manager_get_hal_proxy (NMSystemConfigHalManager *manager) +{ + g_return_val_if_fail (NM_IS_SYSTEM_CONFIG_HAL_MANAGER (manager), NULL); + + return NM_SYSTEM_CONFIG_HAL_MANAGER_GET_PRIVATE (manager)->proxy; +} + diff --git a/system-settings/src/nm-system-config-hal-manager.h b/system-settings/src/nm-system-config-hal-manager.h new file mode 100644 index 0000000000..471dc90489 --- /dev/null +++ b/system-settings/src/nm-system-config-hal-manager.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008 Dan Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef NM_SYSTEM_CONFIG_HAL_MANAGER_H +#define NM_SYSTEM_CONFIG_HAL_MANAGER_H + +#include +#include +#include +#include "NetworkManager.h" + +#define NM_TYPE_SYSTEM_CONFIG_HAL_MANAGER (nm_system_config_hal_manager_get_type ()) +#define NM_SYSTEM_CONFIG_HAL_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SYSTEM_CONFIG_HAL_MANAGER, NMSystemConfigHalManager)) +#define NM_SYSTEM_CONFIG_HAL_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SYSTEM_CONFIG_HAL_MANAGER, NMSystemConfigHalManagerClass)) +#define NM_IS_SYSTEM_CONFIG_HAL_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SYSTEM_CONFIG_HAL_MANAGER)) +#define NM_IS_SYSTEM_CONFIG_HAL_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_SYSTEM_CONFIG_HAL_MANAGER)) +#define NM_SYSTEM_CONFIG_HAL_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SYSTEM_CONFIG_HAL_MANAGER, NMSystemConfigHalManagerClass)) + +typedef struct { + GObject parent; +} NMSystemConfigHalManager; + +typedef struct { + GObjectClass parent; + + /* Signals */ + void (*device_added) (NMSystemConfigHalManager *manager, const char *udi, NMDeviceType type); + void (*device_removed) (NMSystemConfigHalManager *manager, const char *udi, NMDeviceType type); +} NMSystemConfigHalManagerClass; + +GType nm_system_config_hal_manager_get_type (void); + +/* Returned list is allocated and must be freed by caller */ +GSList *nm_system_config_hal_manager_get_devices_of_type (NMSystemConfigHalManager *manager, NMDeviceType devtype); + +DBusGProxy *nm_system_config_hal_manager_get_hal_proxy (NMSystemConfigHalManager *manager); + +#endif /* NM_SYSTEM_CONFIG_HAL_MANAGER_H */ diff --git a/system-settings/src/nm-system-config-interface.c b/system-settings/src/nm-system-config-interface.c index d6a480b400..4e0c2560ae 100644 --- a/system-settings/src/nm-system-config-interface.c +++ b/system-settings/src/nm-system-config-interface.c @@ -76,6 +76,14 @@ interface_init (gpointer g_iface) G_TYPE_NONE, 1, G_TYPE_OBJECT); + g_signal_new ("unmanaged-devices-changed", + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSystemConfigInterface, unmanaged_devices_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + initialized = TRUE; } @@ -110,12 +118,13 @@ nm_system_config_interface_get_type (void) } void -nm_system_config_interface_init (NMSystemConfigInterface *config) +nm_system_config_interface_init (NMSystemConfigInterface *config, + NMSystemConfigHalManager *hal_manager) { g_return_if_fail (config != NULL); if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->init) - NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->init (config); + NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->init (config, hal_manager); } GSList * @@ -142,3 +151,13 @@ nm_system_config_interface_get_secrets (NMSystemConfigInterface *config, return NULL; } +GSList * +nm_system_config_interface_get_unmanaged_devices (NMSystemConfigInterface *config) +{ + g_return_val_if_fail (config != NULL, NULL); + + if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->get_unmanaged_devices) + return NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->get_unmanaged_devices (config); + return NULL; +} + diff --git a/system-settings/src/nm-system-config-interface.h b/system-settings/src/nm-system-config-interface.h index bcc3748095..43633319a7 100644 --- a/system-settings/src/nm-system-config-interface.h +++ b/system-settings/src/nm-system-config-interface.h @@ -26,10 +26,12 @@ #include #include +#include "nm-system-config-hal-manager.h" + G_BEGIN_DECLS #define PLUGIN_PRINT(pname, fmt, args...) \ - { g_print (" " pname ": " fmt "\n", ##args); } + { g_message (" " pname ": " fmt, ##args); } #define PLUGIN_WARN(pname, fmt, args...) \ { g_warning (" " pname ": " fmt, ##args); } @@ -72,7 +74,7 @@ struct _NMSystemConfigInterface { GTypeInterface g_iface; /* Called when the plugin is loaded to initialize it */ - void (*init) (NMSystemConfigInterface *config); + void (*init) (NMSystemConfigInterface *config, NMSystemConfigHalManager *hal_manager); /* Returns the plugins currently known list of connections. The returned * list is freed by the system settings service. @@ -90,6 +92,13 @@ struct _NMSystemConfigInterface { */ GHashTable * (*get_secrets) (NMSystemConfigInterface *config, NMConnection *connection, NMSetting *setting); + /* + * Return a list of HAL UDIs of devices which NetworkManager should not + * manage. Returned list will be freed by the system settings service, and + * each element must be allocated using g_malloc() or its variants. + */ + GSList * (*get_unmanaged_devices) (NMSystemConfigInterface *config); + /* Signals */ /* Emitted when a new connection has been found by the plugin */ @@ -100,11 +109,15 @@ struct _NMSystemConfigInterface { /* Emitted when any non-secret settings of the connection change */ void (*connection_updated) (NMSystemConfigInterface *config, NMConnection *connection); + + /* Emitted when the list of unmanaged devices changes */ + void (*unmanaged_devices_changed) (NMSystemConfigInterface *config); }; GType nm_system_config_interface_get_type (void); -void nm_system_config_interface_init (NMSystemConfigInterface *config); +void nm_system_config_interface_init (NMSystemConfigInterface *config, + NMSystemConfigHalManager *hal_manager); GSList * nm_system_config_interface_get_connections (NMSystemConfigInterface *config); @@ -112,6 +125,8 @@ GHashTable *nm_system_config_interface_get_secrets (NMSystemConfigInterface *con NMConnection *connection, NMSetting *setting); +GSList *nm_system_config_interface_get_unmanaged_devices (NMSystemConfigInterface *config); + G_END_DECLS #endif /* NM_SYSTEM_CONFIG_INTERFACE_H */