diff --git a/ChangeLog b/ChangeLog index 6c284a5c7..81ed518ea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2007-11-29 Dan Williams + + * system-settings/src/nm-system-config-interface.h + system-settings/src/nm-system-config-interface.c + - (nm_system_config_interface_init, + nm_system_config_interface_get_connections): add + + * system-settings/src/main.c + - (load_plugins, load_connections, main): use a GSList for plugins + to ensure priority ordering + + * system-settings/plugins/ifcfg/parser.c + - (ifcfg_error_quark): move to plugin.c, and rename + + * system-settings/plugins/ifcfg/plugin.h + system-settings/plugins/ifcfg/plugin.c + - (ifcfg_plugin_error_quark): move here from parser.c + - rework connection loading and initialization + - Add preliminary inotify support for network profile config file + 2007-11-28 Tambet Ingo Merge the beginnings of the new GSM card support. diff --git a/system-settings/plugins/ifcfg/parser.c b/system-settings/plugins/ifcfg/parser.c index 7875fc7d5..7c67cf571 100644 --- a/system-settings/plugins/ifcfg/parser.c +++ b/system-settings/plugins/ifcfg/parser.c @@ -40,17 +40,6 @@ #include "parser.h" #include "plugin.h" -static GQuark -ifcfg_error_quark (void) -{ - static GQuark error_quark = 0; - - if (G_UNLIKELY (error_quark == 0)) - error_quark = g_quark_from_static_string ("ifcfg-plugin-error-quark"); - - return error_quark; -} - char * parser_get_current_profile_name (void) { @@ -219,7 +208,7 @@ make_ip4_setting (shvarFile *ifcfg, GError **error) if (inet_pton (AF_INET, value, &ip4_addr)) tmp.address = ip4_addr.s_addr; else { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid IP4 address '%s'", value); goto error; } @@ -232,7 +221,7 @@ make_ip4_setting (shvarFile *ifcfg, GError **error) if (inet_pton (AF_INET, value, &gw_addr)) tmp.gateway = gw_addr.s_addr; else { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid IP4 gateway '%s'", value); goto error; } @@ -245,7 +234,7 @@ make_ip4_setting (shvarFile *ifcfg, GError **error) if (inet_pton (AF_INET, value, &mask_addr)) tmp.netmask = mask_addr.s_addr; else { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid IP4 netmask '%s'", value); goto error; } @@ -327,7 +316,7 @@ get_one_wep_key (shvarFile *ifcfg, guint8 idx, GError **error) while (*p) { if (!g_ascii_isxdigit (*p)) { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid hexadecimal WEP key."); goto out; } @@ -340,7 +329,7 @@ get_one_wep_key (shvarFile *ifcfg, guint8 idx, GError **error) while (*p) { if (!isascii ((int) (*p))) { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid ASCII WEP passphrase."); goto out; } @@ -349,7 +338,7 @@ get_one_wep_key (shvarFile *ifcfg, guint8 idx, GError **error) value = utils_bin2hexstr (value, strlen (value), strlen (value) * 2); } else { - g_set_error (error, ifcfg_error_quark (), 0, "Invalid WEP key length."); + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid WEP key length."); } out: @@ -395,7 +384,7 @@ make_wireless_security_setting (shvarFile *ifcfg, GError **error) if (success && (key_idx >= 0) && (key_idx <= 3)) s_wireless_sec->wep_tx_keyidx = key_idx; else { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid defualt WEP key '%s'", value); g_free (value); goto error; @@ -415,7 +404,7 @@ make_wireless_security_setting (shvarFile *ifcfg, GError **error) } else if (!strcmp (lcase, "restricted")) { s_wireless_sec->auth_alg = g_strdup ("shared"); } else { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid WEP authentication algoritm '%s'", lcase); g_free (lcase); @@ -451,7 +440,7 @@ make_wireless_setting (shvarFile *ifcfg, gsize len = strlen (value); if (len > 32 || len == 0) { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid SSID '%s' (size %d not between 1 and 32 inclusive)", value, len); goto error; @@ -474,7 +463,7 @@ make_wireless_setting (shvarFile *ifcfg, } else if (!strcmp (lcase, "managed")) { s_wireless->mode = g_strdup ("infrastructure"); } else { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid mode '%s' (not ad-hoc or managed)", lcase); g_free (lcase); @@ -513,7 +502,7 @@ wireless_connection_from_ifcfg (const char *file, shvarFile *ifcfg, GError **err connection = nm_connection_new (); if (!connection) { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Failed to allocate new connection for %s.", file); return NULL; } @@ -540,14 +529,14 @@ wireless_connection_from_ifcfg (const char *file, shvarFile *ifcfg, GError **err NM_SETTING_WIRELESS_SETTING_NAME, printable_ssid); if (!con_setting) { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Failed to create connection setting."); goto error; } nm_connection_add_setting (connection, con_setting); if (!nm_connection_verify (connection)) { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Connection from %s was invalid.", file); goto error; } @@ -579,7 +568,7 @@ make_wired_setting (shvarFile *ifcfg, GError **error) if (mtu >= 0 && mtu < 65536) s_wired->mtu = mtu; } else { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid MTU '%s'", value); g_object_unref (s_wired); s_wired = NULL; @@ -602,14 +591,14 @@ wired_connection_from_ifcfg (const char *file, shvarFile *ifcfg, GError **error) connection = nm_connection_new (); if (!connection) { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Failed to allocate new connection for %s.", file); return NULL; } con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL); if (!con_setting) { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Failed to create connection setting."); goto error; } @@ -622,7 +611,7 @@ wired_connection_from_ifcfg (const char *file, shvarFile *ifcfg, GError **error) nm_connection_add_setting (connection, wired_setting); if (!nm_connection_verify (connection)) { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Connection from %s was invalid.", file); goto error; } @@ -651,14 +640,14 @@ parser_parse_file (const char *file, parsed = svNewFile(file); if (!parsed) { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Couldn't parse file '%s'", file); return NULL; } type = svGetValue (parsed, "TYPE"); if (!type) { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "File '%s' didn't have a TYPE key.", file); goto done; } @@ -683,7 +672,7 @@ parser_parse_file (const char *file, else if (!strcmp (type, "Wireless")) connection = wireless_connection_from_ifcfg (file, parsed, error); else { - g_set_error (error, ifcfg_error_quark (), 0, + g_set_error (error, ifcfg_plugin_error_quark (), 0, "Unknown connection type '%s'", type); } diff --git a/system-settings/plugins/ifcfg/plugin.c b/system-settings/plugins/ifcfg/plugin.c index 359f6ee5d..05d7b5fd5 100644 --- a/system-settings/plugins/ifcfg/plugin.c +++ b/system-settings/plugins/ifcfg/plugin.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include @@ -43,30 +45,42 @@ G_DEFINE_TYPE_EXTENDED (SCPluginIfcfg, sc_plugin_ifcfg, G_TYPE_OBJECT, 0, typedef struct { + gboolean initialized; GSList *connections; + + char *profile; + + int ifd; + int profile_wd; } SCPluginIfcfgPrivate; #define PROFILE_DIR SYSCONFDIR "/sysconfig/networking/profiles/" -static gboolean -parse_files (gpointer data) +GQuark +ifcfg_plugin_error_quark (void) { - SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (data); - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); - char *profile = NULL; + static GQuark error_quark = 0; + + if (G_UNLIKELY (error_quark == 0)) + error_quark = g_quark_from_static_string ("ifcfg-plugin-error-quark"); + + return error_quark; +} + +static GSList * +get_initial_connections (char *profile_name) +{ + GSList *connections = NULL; char *profile_path = NULL; - gboolean added = FALSE; GDir *dir; const char *item; - profile = parser_get_current_profile_name (); - profile_path = g_strdup_printf (PROFILE_DIR "%s/", profile); + profile_path = g_strdup_printf (PROFILE_DIR "%s/", profile_name); if (!profile_path) { - PLUGIN_WARN (PLUGIN_NAME, "current network profile directory '%s' not found.", profile); - goto out; + PLUGIN_WARN (PLUGIN_NAME, "out of memory getting profile path."); + return NULL; } - g_free (profile); dir = g_dir_open (profile_path, 0, NULL); if (!dir) { @@ -94,12 +108,8 @@ parse_files (gpointer data) s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); g_assert (s_con); g_assert (s_con->id); - priv->connections = g_slist_append (priv->connections, connection); + connections = g_slist_append (connections, connection); PLUGIN_PRINT (PLUGIN_NAME, " added connection '%s'", s_con->id); - g_signal_emit_by_name (NM_SYSTEM_CONFIG_INTERFACE (plugin), - "connection-added", - connection); - added = TRUE; } else { PLUGIN_PRINT (PLUGIN_NAME, " error: %s", error->message ? error->message : "(unknown)"); @@ -112,7 +122,113 @@ parse_files (gpointer data) out: g_free (profile_path); - return FALSE; + return connections; +} + +static GSList * +get_connections (NMSystemConfigInterface *config) +{ + SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + + if (!priv->initialized) + priv->connections = get_initial_connections (priv->profile); + + return priv->connections; +} + +static gboolean +stuff_changed (GIOChannel *channel, GIOCondition cond, gpointer user_data) +{ + SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + struct inotify_event evt; + + /* read the notifications from the watch descriptor */ + while (g_io_channel_read_chars (channel, (gchar *) &evt, sizeof (struct inotify_event), NULL, NULL) == G_IO_STATUS_NORMAL) { + gchar filename[PATH_MAX + 1]; + + if (evt.len <= 0) + continue; + + g_io_channel_read_chars (channel, + filename, + evt.len > PATH_MAX ? PATH_MAX : evt.len, + NULL, NULL); + + if (evt.wd == priv->profile_wd) { + if (!strcmp (filename, "network")) { + char *new_profile = parser_get_current_profile_name (); + + if (strcmp (new_profile, priv->profile)) { + g_free (priv->profile); + priv->profile = g_strdup (new_profile); + } + g_free (new_profile); + } + } else { + } + } + + return TRUE; +} + +static gboolean +sc_plugin_inotify_init (SCPluginIfcfg *plugin, GError **error) +{ + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + GIOChannel *channel; + guint source_id; + int ifd, wd; + + ifd = inotify_init (); + if (ifd == -1) { + g_set_error (error, ifcfg_plugin_error_quark (), 0, + "Couldn't initialize inotify"); + return FALSE; + } + + wd = inotify_add_watch (ifd, SYSCONFDIR "/sysconfig/", IN_CLOSE_WRITE); + if (wd == -1) { + g_set_error (error, ifcfg_plugin_error_quark (), 0, + "Couldn't monitor "); + close (ifd); + return FALSE; + } + + priv->ifd = ifd; + priv->profile_wd = wd; + + /* Watch the inotify descriptor for file/directory change events */ + channel = g_io_channel_unix_new (ifd); + g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); + g_io_channel_set_encoding (channel, NULL, NULL); + + source_id = g_io_add_watch (channel, + G_IO_IN | G_IO_ERR, + (GIOFunc) stuff_changed, + plugin); + g_io_channel_unref (channel); + + + + return TRUE; +} + +static void +init (NMSystemConfigInterface *config) +{ + SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config); + SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + GError *error = NULL; + + priv->profile = parser_get_current_profile_name (); + + priv->ifd = sc_plugin_inotify_init (plugin, &error); + if (error) { + PLUGIN_PRINT (PLUGIN_NAME, " inotify error: %s", + error->message ? error->message : "(unknown)"); + } } static void @@ -173,6 +289,8 @@ 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->init = init; } G_MODULE_EXPORT GObject * @@ -182,10 +300,8 @@ nm_system_config_factory (void) static SCPluginIfcfg *singleton = NULL; g_static_mutex_lock (&mutex); - if (!singleton) { + if (!singleton) singleton = SC_PLUGIN_IFCFG (g_object_new (SC_TYPE_PLUGIN_IFCFG, NULL)); - g_idle_add (parse_files, singleton); - } g_object_ref (singleton); g_static_mutex_unlock (&mutex); diff --git a/system-settings/plugins/ifcfg/plugin.h b/system-settings/plugins/ifcfg/plugin.h index 2698cfc12..e5cce353e 100644 --- a/system-settings/plugins/ifcfg/plugin.h +++ b/system-settings/plugins/ifcfg/plugin.h @@ -46,5 +46,7 @@ struct _SCPluginIfcfgClass { GType sc_plugin_ifcfg_get_type (void); +GQuark ifcfg_plugin_error_quark (void); + #endif /* _PLUGIN_H_ */ diff --git a/system-settings/src/main.c b/system-settings/src/main.c index 73beb4503..7e867c89c 100644 --- a/system-settings/src/main.c +++ b/system-settings/src/main.c @@ -40,8 +40,7 @@ #include "dbus-settings.h" #include "nm-system-config-interface.h" -typedef struct Application -{ +typedef struct { DBusConnection *connection; DBusGConnection *g_connection; DBusGProxy *bus_proxy; @@ -50,7 +49,7 @@ typedef struct Application NMSysconfigSettings *settings; GMainLoop *loop; - GHashTable *plugins; + GSList *plugins; /* In priority order */ } Application; @@ -101,12 +100,36 @@ 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); + + nm_system_config_interface_init (plugin); } -static GHashTable * +static GObject * +find_plugin (GSList *list, const char *pname) +{ + GSList *iter; + + g_return_val_if_fail (pname != NULL, FALSE); + + for (iter = list; iter; iter = g_slist_next (iter)) { + NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + char *list_pname; + + g_object_get (G_OBJECT (plugin), + NM_SYSTEM_CONFIG_INTERFACE_NAME, + &list_pname, + NULL); + if (list_pname && !strcmp (pname, list_pname)) + return G_OBJECT (plugin); + } + + return NULL; +} + +static GSList * load_plugins (Application *app, const char *plugins, GError **error) { - GHashTable *table; + GSList *list = NULL; char **plist; char **pname; @@ -114,8 +137,6 @@ load_plugins (Application *app, const char *plugins, GError **error) if (!plist) return NULL; - table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - for (pname = plist; *pname; pname++) { GModule *plugin; char *full_name; @@ -123,7 +144,7 @@ load_plugins (Application *app, const char *plugins, GError **error) GObject *obj; GObject * (*factory_func) (void); - obj = g_hash_table_lookup (table, *pname); + obj = find_plugin (list, *pname); if (obj) continue; @@ -159,19 +180,19 @@ load_plugins (Application *app, const char *plugins, GError **error) } g_module_make_resident (plugin); - g_object_set_data_full (obj, "plugin", plugin, (GDestroyNotify) g_module_close); + g_object_set_data_full (obj, "nm-ss-plugin", plugin, (GDestroyNotify) g_module_close); register_plugin (app, NM_SYSTEM_CONFIG_INTERFACE (obj)); - g_hash_table_insert (table, g_strdup (*pname), obj); + list = g_slist_append (list, obj); } g_strfreev (plist); - return table; + return list; } static void -print_plugin_info (gpointer key, gpointer data, gpointer user_data) +print_plugin_info (gpointer item, gpointer user_data) { - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (data); + NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (item); char *pname; char *pinfo; @@ -190,6 +211,42 @@ print_plugin_info (gpointer key, gpointer data, gpointer user_data) g_free (pinfo); } +static void +free_plugin_connections (gpointer data) +{ + GSList *connections = (GSList *) data; + + g_slist_foreach (connections, (GFunc) g_object_unref, NULL); +} + +static gboolean +load_connections (gpointer user_data) +{ + Application *app = (Application *) user_data; + GSList *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 *connections; + + 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. + + g_slist_foreach (connections, (GFunc) g_object_ref, NULL); + g_object_set_data_full (G_OBJECT (plugin), "connections", + connections, free_plugin_connections); + } + + return FALSE; +} + +/******************************************************************/ + static gboolean dbus_reconnect (gpointer user_data) { @@ -361,17 +418,23 @@ main (int argc, char **argv) /* Load the plugins; fail if a plugin is not found. */ app->plugins = load_plugins (app, plugins, &error); if (error) { - g_hash_table_destroy (app->plugins); + 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_print ("Loaded plugins:\n"); - g_hash_table_foreach (app->plugins, print_plugin_info, NULL); + g_slist_foreach (app->plugins, print_plugin_info, NULL); g_print ("\n"); + g_idle_add (load_connections, app); + g_main_loop_run (app->loop); + g_slist_foreach (app->plugins, (GFunc) g_object_unref, NULL); + g_slist_free (app->plugins); + return 0; } diff --git a/system-settings/src/nm-system-config-interface.c b/system-settings/src/nm-system-config-interface.c index 5b929bc2a..da776a91d 100644 --- a/system-settings/src/nm-system-config-interface.c +++ b/system-settings/src/nm-system-config-interface.c @@ -23,7 +23,7 @@ #include "nm-system-config-interface.h" static void -nm_system_config_interface_init (gpointer g_iface) +interface_init (gpointer g_iface) { GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); static gboolean initialized = FALSE; @@ -88,7 +88,7 @@ nm_system_config_interface_get_type (void) if (!system_config_interface_type) { const GTypeInfo system_config_interface_info = { sizeof (NMSystemConfigInterface), /* class_size */ - nm_system_config_interface_init, /* base_init */ + interface_init, /* base_init */ NULL, /* base_finalize */ NULL, NULL, /* class_finalize */ @@ -109,3 +109,22 @@ nm_system_config_interface_get_type (void) return system_config_interface_type; } +void +nm_system_config_interface_init (NMSystemConfigInterface *config) +{ + g_return_if_fail (config != NULL); + + if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->init) + NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->init (config); +} + +GSList * +nm_system_config_interface_get_connections (NMSystemConfigInterface *config) +{ + g_return_val_if_fail (config != NULL, NULL); + + if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->get_connections) + return NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->get_connections (config); + return NULL; +} + diff --git a/system-settings/src/nm-system-config-interface.h b/system-settings/src/nm-system-config-interface.h index eba33f05c..bdcb50b46 100644 --- a/system-settings/src/nm-system-config-interface.h +++ b/system-settings/src/nm-system-config-interface.h @@ -71,6 +71,10 @@ typedef struct _NMSystemConfigInterface NMSystemConfigInterface; struct _NMSystemConfigInterface { GTypeInterface g_iface; + void (*init) (NMSystemConfigInterface *config); + + GSList * (*get_connections) (NMSystemConfigInterface *config); + /* Signals */ void (*connection_added) (NMSystemConfigInterface *config, NMConnection *connection); void (*connection_removed) (NMSystemConfigInterface *config, NMConnection *connection); @@ -79,6 +83,9 @@ struct _NMSystemConfigInterface { GType nm_system_config_interface_get_type (void); +void nm_system_config_interface_init (NMSystemConfigInterface *config); + +GSList * nm_system_config_interface_get_connections (NMSystemConfigInterface *config); G_END_DECLS