diff options
author | Dan Williams <dcbw@redhat.com> | 2007-11-21 06:24:15 +0000 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2007-11-21 06:24:15 +0000 |
commit | ac5206aa9c5a87d0ca5454dd2ba03da66e4300a8 (patch) | |
tree | 5593f27e6e54be6a3bead09abd74495890b2ab28 | |
parent | 36650e4a2470c8c2f2556946fc65140513770763 (diff) |
2007-11-21 Dan Williams <dcbw@redhat.com>
* system-settings/*
- Add Soren's system settings service. Needs work for distros other
than Fedora; the backends from NM should mostly migrate to here
and be converted to GObjects
git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3104 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | configure.in | 1 | ||||
-rw-r--r-- | system-settings/Makefile.am | 42 | ||||
-rw-r--r-- | system-settings/dbus-settings.c | 194 | ||||
-rw-r--r-- | system-settings/dbus-settings.h | 84 | ||||
-rw-r--r-- | system-settings/main.c | 600 | ||||
-rw-r--r-- | system-settings/nm-system-settings.conf | 20 | ||||
-rw-r--r-- | system-settings/shvar.c | 398 | ||||
-rw-r--r-- | system-settings/shvar.h | 103 |
10 files changed, 1451 insertions, 1 deletions
@@ -1,5 +1,12 @@ 2007-11-21 Dan Williams <dcbw@redhat.com> + * system-settings/* + - Add Soren's system settings service. Needs work for distros other + than Fedora; the backends from NM should mostly migrate to here + and be converted to GObjects + +2007-11-21 Dan Williams <dcbw@redhat.com> + * libnm-util/nm-setting-vpn-properties.c - (set_property): must deep-copy the given settings hash, otherwise double-free errors occur when the setting is disposed of diff --git a/Makefile.am b/Makefile.am index d36d88d64..59a4c1dd3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,8 @@ SUBDIRS = \ man \ include \ introspection \ - callouts + callouts \ + system-settings EXTRA_DIST = \ CONTRIBUTING \ diff --git a/configure.in b/configure.in index fea7f21bc..37e2fc990 100644 --- a/configure.in +++ b/configure.in @@ -273,6 +273,7 @@ libnm-glib/libnm_glib.pc libnm-glib/Makefile callouts/Makefile dispatcher-daemon/Makefile +system-settings/Makefile test/Makefile test/test-common/Makefile initscript/Makefile diff --git a/system-settings/Makefile.am b/system-settings/Makefile.am new file mode 100644 index 000000000..c2ec09b15 --- /dev/null +++ b/system-settings/Makefile.am @@ -0,0 +1,42 @@ +INCLUDES = -I${top_srcdir} \ + -I${top_srcdir}/include \ + -I${top_srcdir}/libnm-util \ + -I${top_srcdir}/libnm-glib + +sbin_PROGRAMS = nm-system-settings + +nm_system_settings_SOURCES = \ + dbus-settings.c \ + dbus-settings.h \ + main.c \ + shvar.c \ + shvar.h + +nm_system_settings_CPPFLAGS = \ + $(DBUS_CFLAGS) \ + $(GTHREAD_CFLAGS) \ + -DDBUS_API_SUBJECT_TO_CHANGE \ + -DG_DISABLE_DEPRECATED \ + -DBINDIR=\"$(bindir)\" \ + -DSBINDIR=\"$(sbindir)\" \ + -DLIBEXECDIR=\"$(libexecdir)\" \ + -DDATADIR=\"$(datadir)\" \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DLOCALSTATEDIR=\"$(localstatedir)\" \ + -DNM_RUN_DIR=\"$(rundir)\" \ + -DGNOMELOCALEDIR=\"$(datadir)/locale\" + +nm_system_settings_LDADD = \ + $(DBUS_LIBS) \ + $(GTHREAD_LIBS) \ + $(top_builddir)/libnm-util/libnm-util.la \ + $(top_builddir)/libnm-glib/libnm_glib.la + +nm_system_settings_LDFLAGS = -rdynamic + +dbusservicedir = $(DBUS_SYS_DIR) +dbusservice_DATA = nm-system-settings.conf + +EXTRA_DIST = \ + $(dbusservice_DATA) + diff --git a/system-settings/dbus-settings.c b/system-settings/dbus-settings.c new file mode 100644 index 000000000..0166dd49f --- /dev/null +++ b/system-settings/dbus-settings.c @@ -0,0 +1,194 @@ +/* NetworkManager system settings service + * + * Søren Sandmann <sandmann@daimi.au.dk> + * + * 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 of the License, 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. + * + * (C) Copyright 2007 Red Hat, Inc. + */ + +#include <NetworkManager.h> +#include <nm-connection.h> +#include <dbus/dbus.h> + +#include <nm-setting-connection.h> + +#include "dbus-settings.h" +#include "nm-utils.h" + +static gchar *connection_settings_get_id (NMConnectionSettings *connection); +static void connection_settings_get_secrets (NMConnectionSettings *connection, + const gchar *setting_name, + const gchar **hints, + gboolean request_new, + DBusGMethodInvocation *context); + +G_DEFINE_TYPE (NMSysconfigConnectionSettings, nm_sysconfig_connection_settings, NM_TYPE_CONNECTION_SETTINGS); + +/* + * NMSysconfigConnectionSettings + */ +static gchar * +connection_settings_get_id (NMConnectionSettings *connection) +{ + NMSysconfigConnectionSettings *c = NM_SYSCONFIG_CONNECTION_SETTINGS (connection); + + return g_strdup (c->id); +} + +static GHashTable * +connection_settings_get_settings (NMConnectionSettings *connection) +{ + NMSysconfigConnectionSettings *c = NM_SYSCONFIG_CONNECTION_SETTINGS (connection); + + return nm_connection_to_hash (c->connection); +} + +static void +connection_settings_get_secrets (NMConnectionSettings *connection, + const gchar *setting_name, + const gchar **hints, + gboolean request_new, + DBusGMethodInvocation *context) +{ + +} + +static void +nm_sysconfig_connection_settings_finalize (GObject *object) +{ + G_OBJECT_CLASS (nm_sysconfig_connection_settings_parent_class)->finalize (object); +} + +static void +nm_sysconfig_connection_settings_class_init (NMSysconfigConnectionSettingsClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + NMConnectionSettingsClass *connection = NM_CONNECTION_SETTINGS_CLASS (class); + + object_class->finalize = nm_sysconfig_connection_settings_finalize; + + connection->get_id = connection_settings_get_id; + connection->get_settings = connection_settings_get_settings; + connection->get_secrets = connection_settings_get_secrets; +} + +static void +nm_sysconfig_connection_settings_init (NMSysconfigConnectionSettings *sysconfig_connection_settings) +{ + +} + +NMSysconfigConnectionSettings * +nm_sysconfig_connection_settings_new (NMConnection *connection, + DBusGConnection *g_conn) +{ + NMSysconfigConnectionSettings *settings; + NMSettingConnection *s_con; + + settings = g_object_new (nm_sysconfig_connection_settings_get_type(), NULL); + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + settings->id = g_strdup (s_con->id); + settings->connection = connection; + + nm_connection_settings_register_object (NM_CONNECTION_SETTINGS (settings), g_conn); + + return settings; +} + +/* + * NMSettings + */ +static GPtrArray *nm_sysconfig_settings_list_connections (NMSettings *settings); + +G_DEFINE_TYPE (NMSysconfigSettings, nm_sysconfig_settings, NM_TYPE_SETTINGS); + +static GPtrArray * +nm_sysconfig_settings_list_connections (NMSettings *settings) +{ + 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)) { + NMConnectionSettings *connection = NM_CONNECTION_SETTINGS (iter->data); + char *path; + + path = g_strdup (nm_connection_settings_get_dbus_object_path (connection)); + if (path) + g_ptr_array_add (connections, path); + } + + /* Return a list of strings with paths to connection settings objects */ + return connections; +} + +static void +nm_sysconfig_settings_finalize (GObject *object) +{ + NMSysconfigSettings *settings = NM_SYSCONFIG_SETTINGS (object); + + if (settings->connections) { + g_slist_foreach (settings->connections, (GFunc) g_object_unref, NULL); + g_slist_free (settings->connections); + settings->connections = NULL; + } + + G_OBJECT_CLASS (nm_sysconfig_settings_parent_class)->finalize (object); +} + +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; +} + +static void +nm_sysconfig_settings_init (NMSysconfigSettings *sysconfig_settings) +{ + sysconfig_settings->connections = NULL; +} + +NMSysconfigSettings * +nm_sysconfig_settings_new (DBusGConnection *g_conn) +{ + NMSysconfigSettings *settings; + + settings = g_object_new (nm_sysconfig_settings_get_type (), NULL); + dbus_g_connection_register_g_object (g_conn, NM_DBUS_PATH_SETTINGS, G_OBJECT (settings)); + return settings; +} + +void +nm_sysconfig_settings_add_connection (NMSysconfigSettings *settings, + NMSysconfigConnectionSettings *connection) +{ + g_return_if_fail (NM_IS_SYSCONFIG_SETTINGS (settings)); + g_return_if_fail (NM_IS_SYSCONFIG_CONNECTION_SETTINGS (connection)); + + settings->connections = g_slist_append (settings->connections, connection); + + nm_settings_signal_new_connection (NM_SETTINGS (settings), + NM_CONNECTION_SETTINGS (connection)); +} diff --git a/system-settings/dbus-settings.h b/system-settings/dbus-settings.h new file mode 100644 index 000000000..327cffe41 --- /dev/null +++ b/system-settings/dbus-settings.h @@ -0,0 +1,84 @@ +/* NetworkManager system settings service + * + * Søren Sandmann <sandmann@daimi.au.dk> + * + * 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 of the License, 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. + * + * (C) Copyright 2007 Red Hat, Inc. + */ + +#include <nm-connection.h> +#include <nm-settings.h> + +typedef struct _NMSysconfigConnectionSettings NMSysconfigConnectionSettings; +typedef struct _NMSysconfigConnectionSettingsClass NMSysconfigConnectionSettingsClass; + +/* + * NMSysconfigConnectionSettings + */ + +#define NM_TYPE_SYSCONFIG_CONNECTION_SETTINGS (nm_sysconfig_connection_settings_get_type ()) +#define NM_SYSCONFIG_CONNECTION_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SYSCONFIG_CONNECTION_SETTINGS, NMSysconfigConnectionSettings)) +#define NM_SYSCONFIG_CONNECTION_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SYSCONFIG_CONNECTION_SETTINGS, NMSysconfigConnectionSettingsClass)) +#define NM_IS_SYSCONFIG_CONNECTION_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SYSCONFIG_CONNECTION_SETTINGS)) +#define NM_IS_SYSCONFIG_CONNECTION_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SYSCONFIG_CONNECTION_SETTINGS)) +#define NM_SYSCONFIG_CONNECTION_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SYSCONFIG_CONNECTION_SETTINGS, NMSysconfigConnectionSettingsClass)) + +struct _NMSysconfigConnectionSettings +{ + NMConnectionSettings parent_instance; + + char *id; + NMConnection *connection; +}; + +struct _NMSysconfigConnectionSettingsClass +{ + NMConnectionSettingsClass parent_class; +}; + +GType nm_sysconfig_connection_settings_get_type (void); +NMSysconfigConnectionSettings *nm_sysconfig_connection_settings_new (NMConnection *connection, + DBusGConnection *g_conn); + +/* + * NMSysconfigSetttings + */ +typedef struct _NMSysconfigSettings NMSysconfigSettings; +typedef struct _NMSysconfigSettingsClass NMSysconfigSettingsClass; + +#define NM_TYPE_SYSCONFIG_SETTINGS (nm_sysconfig_settings_get_type ()) +#define NM_SYSCONFIG_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SYSCONFIG_SETTINGS, NMSysconfigSettings)) +#define NM_SYSCONFIG_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SYSCONFIG_SETTINGS, NMSysconfigSettingsClass)) +#define NM_IS_SYSCONFIG_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SYSCONFIG_SETTINGS)) +#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)) + +struct _NMSysconfigSettings +{ + NMSettings parent_instance; + + GSList *connections; +}; + +struct _NMSysconfigSettingsClass +{ + NMSettingsClass parent_class; +}; + +GType nm_sysconfig_settings_get_type (void); +NMSysconfigSettings *nm_sysconfig_settings_new (DBusGConnection *g_conn); +void nm_sysconfig_settings_add_connection (NMSysconfigSettings *settings, + NMSysconfigConnectionSettings *connection); diff --git a/system-settings/main.c b/system-settings/main.c new file mode 100644 index 000000000..72ea8ea56 --- /dev/null +++ b/system-settings/main.c @@ -0,0 +1,600 @@ +/* NetworkManager system settings service + * + * Søren Sandmann <sandmann@daimi.au.dk> + * + * 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 of the License, 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. + * + * (C) Copyright 2007 Red Hat, Inc. + */ + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> + +#include <glib.h> + +#include <dbus/dbus.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include <nm-connection.h> +#include <nm-settings.h> +#include <NetworkManager.h> +#include <nm-setting-connection.h> +#include <nm-setting-ip4-config.h> +#include <nm-setting-wired.h> + +#include "dbus-settings.h" +#include "shvar.h" + +#define SYSCONFDIR "/etc" +#define PROFILE_DIR SYSCONFDIR "/sysconfig/networking/profiles/" + +typedef struct Application +{ + DBusConnection *connection; + DBusGConnection *g_connection; + DBusGProxy *bus_proxy; + gboolean started; + + NMSysconfigSettings *settings; + char *profile_path; + GMainLoop *loop; +} Application; + + +static gboolean dbus_init (Application *app); +static void dbus_cleanup (Application *app); +static gboolean start_dbus_service (Application *app); +static void destroy_cb (DBusGProxy *proxy, gpointer user_data); + +static gboolean +get_int (const char *str, int *value) +{ + char *e; + + *value = strtol (str, &e, 0); + if (*e != '\0') + return FALSE; + + return TRUE; +} + +#define IFCFG_TAG "ifcfg-" +#define BAK_TAG ".bak" + +static NMSetting * +make_connection_setting (const char *file, shvarFile *ifcfg, const char *type) +{ + NMSettingConnection *s_con; + char *basename = NULL; + int len; + + basename = g_path_get_basename (file); + if (!basename) + goto error; + len = strlen (basename); + + if (len < strlen (IFCFG_TAG) + 1) + goto error; + + if (strncmp (basename, IFCFG_TAG, strlen (IFCFG_TAG))) + goto error; + + /* ignore .bak files */ + if ((len > 4) && !strcmp (basename + len - 4, BAK_TAG)) + goto error; + + s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ()); + + s_con->id = g_strdup_printf ("System %s", basename + strlen (IFCFG_TAG)); + s_con->type = g_strdup (type); + s_con->autoconnect = TRUE; + + return (NMSetting *) s_con; + +error: + g_free (basename); + return NULL; +} + +static char * +get_current_profile_name (void) +{ + shvarFile * file; + char * buf; + + if (!(file = svNewFile (SYSCONFDIR"/sysconfig/network"))) + return NULL; + + buf = svGetValue (file, "CURRENT_PROFILE"); + if (!buf) + buf = strdup ("default"); + svCloseFile (file); + + return buf; +} + +#define SEARCH_TAG "search " +#define NS_TAG "nameserver " + +static void +read_profile_resolv_conf (NMSettingIP4Config *s_ip4) +{ + char *file; + char *profile; + char *contents = NULL; + char **lines = NULL; + char **line; + + profile = get_current_profile_name (); + if (!profile) + return; + + file = g_strdup_printf ("/etc/sysconfig/networking/profiles/%s/resolv.conf", profile); + g_free (profile); + if (!file) + return; + + if (!g_file_get_contents (file, &contents, NULL, NULL)) + goto out; + + lines = g_strsplit (contents, "\n", 0); + if (!lines || !*lines) + goto out; + + s_ip4->dns = g_array_new (FALSE, FALSE, sizeof (guint32)); + + for (line = lines; *line; line++) { + if (!strncmp (*line, SEARCH_TAG, strlen (SEARCH_TAG))) { + char **searches; + + if (s_ip4->dns_search) + continue; + + searches = g_strsplit (*line + strlen (SEARCH_TAG), " ", 0); + if (searches) { + char **item; + for (item = searches; *item; item++) + s_ip4->dns_search = g_slist_append (s_ip4->dns_search, *item); + g_free (searches); + } + } else if (!strncmp (*line, NS_TAG, strlen (NS_TAG))) { + char *pdns = g_strdup (*line + strlen (NS_TAG)); + struct in_addr dns; + + pdns = g_strstrip (pdns); + if (inet_pton (AF_INET, pdns, &dns)) { + g_array_append_val (s_ip4->dns, dns.s_addr); + } else + g_warning ("Invalid IP4 DNS server address '%s'", pdns); + g_free (pdns); + } + } + +out: + if (lines) + g_strfreev (lines); + g_free (file); +} + +static NMSetting * +make_ip4_setting (shvarFile *ifcfg) +{ + NMSettingIP4Config *s_ip4; + char *value; + NMSettingIP4Address tmp = { 0, 0, 0 }; + char *ip4 = NULL, *gw = NULL, *mask = NULL; + gboolean manual = TRUE; + + value = svGetValue (ifcfg, "BOOTPROTO"); + if (!value) + return NULL; + + if (!strcmp (value, "bootp") || !strcmp (value, "dhcp")) { + manual = FALSE; + return NULL; + } + + ip4 = svGetValue (ifcfg, "IPADDR"); + if (ip4) { + struct in_addr ip4_addr; + if (inet_pton (AF_INET, ip4, &ip4_addr)) + tmp.address = ip4_addr.s_addr; + else + g_warning ("Invalid IP4 address '%s'", ip4); + g_free (ip4); + } + + gw = svGetValue (ifcfg, "GATEWAY"); + if (gw) { + struct in_addr gw_addr; + if (inet_pton (AF_INET, gw, &gw_addr)) + tmp.gateway = gw_addr.s_addr; + else + g_warning ("Invalid IP4 gateway '%s'", gw); + g_free (gw); + } + + mask = svGetValue (ifcfg, "NETMASK"); + if (mask) { + struct in_addr mask_addr; + if (inet_pton (AF_INET, mask, &mask_addr)) + tmp.netmask = mask_addr.s_addr; + else + g_warning ("Invalid IP4 netmask '%s'", mask); + g_free (mask); + } + + s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new (); + s_ip4->manual = manual; + if (tmp.address || tmp.netmask || tmp.gateway) { + NMSettingIP4Address *addr; + addr = g_new0 (NMSettingIP4Address, 1); + memcpy (addr, &tmp, sizeof (NMSettingIP4Address)); + s_ip4->addresses = g_slist_append (s_ip4->addresses, addr); + } + + read_profile_resolv_conf (s_ip4); + + return (NMSetting *) s_ip4; +} + + +static NMSetting * +make_wired_setting (shvarFile *ifcfg) +{ + NMSettingWired *s_wired; + char *value; + int mtu; + + s_wired = (NMSettingWired *) nm_setting_wired_new (); + + value = svGetValue (ifcfg, "MTU"); + if (value) { + if (get_int (value, &mtu)) { + if (mtu >= 0 && mtu < 65536) + s_wired->mtu = mtu; + } else { + g_warning ("Invalid MTU '%s'", value); + } + g_free (value); + } + + return (NMSetting *) s_wired; +} + +static NMConnection * +wired_connection_from_ifcfg (const char *file, shvarFile *ifcfg) +{ + NMConnection *connection = NULL; + NMSetting *con_setting = NULL; + NMSetting *wired_setting = NULL; + + g_return_val_if_fail (file != NULL, NULL); + g_return_val_if_fail (ifcfg != NULL, NULL); + + connection = nm_connection_new (); + if (!connection) { + g_warning ("Failed to allocate new connection for %s.", file); + return NULL; + } + + con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME); + if (!con_setting) { + g_warning ("Failed to create connection setting."); + goto error; + } + nm_connection_add_setting (connection, con_setting); + + wired_setting = make_wired_setting (ifcfg); + if (!wired_setting) { + g_warning ("Failed to create wired setting."); + goto error; + } + nm_connection_add_setting (connection, wired_setting); + + if (!nm_connection_verify (connection)) { + g_warning ("Connection from %s was invalid.", file); + goto error; + } + + return connection; + +error: + g_object_unref (connection); + if (con_setting) + g_object_unref (con_setting); + if (wired_setting) + g_object_unref (wired_setting); + return NULL; +} + +static NMSysconfigConnectionSettings * +parse_file (Application *app, + const char *file, + char **err) +{ + NMSysconfigConnectionSettings *sys_connection = NULL; + NMConnection *connection = NULL; + shvarFile *parsed; + char *type; + char *nmc = NULL; + + g_return_val_if_fail (app != NULL, NULL); + g_return_val_if_fail (file != NULL, NULL); + + parsed = svNewFile(file); + if (!parsed) { + *err = g_strdup_printf ("Couldn't parse file '%s'", file); + return NULL; + } + + type = svGetValue (parsed, "TYPE"); + if (!type) { + *err = g_strdup_printf ("File '%s' didn't have a TYPE key.", file); + goto done; + } + + nmc = svGetValue (parsed, "NM_CONTROLLED"); + if (nmc) { + char *lower; + + lower = g_ascii_strdown (nmc, -1); + g_free (nmc); + + if (!strcmp (lower, "no") || !strcmp (lower, "n") || !strcmp (lower, "false")) { + g_free (lower); + g_message ("Ignoring connection '%s' because NM_CONTROLLED was false", file); + goto done; + } + g_free (lower); + } + + if (!strcmp (type, "Ethernet")) { + connection = wired_connection_from_ifcfg (file, parsed); + } else if (!strcmp (type, "Wireless")) { +// connection = wireless_connection_from_ifcfg (file, parsed); + } + g_free (type); + + if (connection) { + NMSetting *s_ip4; + + s_ip4 = make_ip4_setting (parsed); + if (s_ip4) + nm_connection_add_setting (connection, s_ip4); + +nm_connection_dump (connection); + sys_connection = nm_sysconfig_connection_settings_new (connection, app->g_connection); + } + +done: + svCloseFile (parsed); + return sys_connection; +} + +static gboolean +parse_files (gpointer data) +{ + Application *app = data; + gboolean added = FALSE; + GDir *dir; + const char *item; + + dir = g_dir_open (app->profile_path, 0, NULL); + if (!dir) { + g_warning ("Couldn't access network profile directory '%s'.", app->profile_path); + goto out; + } + + while ((item = g_dir_read_name (dir))) { + NMSysconfigConnectionSettings *connection; + char *err = NULL; + char *filename; + + if (strncmp (item, IFCFG_TAG, strlen (IFCFG_TAG))) + continue; + + filename = g_build_filename (app->profile_path, item, NULL); + if (!filename) + continue; + + g_print ("Parsing %s ... \n", filename); + + if ((connection = parse_file (app, filename, &err))) { + NMSettingConnection *s_con; + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection->connection, NM_TYPE_SETTING_CONNECTION)); + g_assert (s_con); + g_assert (s_con->id); + + g_print (" adding connection '%s'\n", s_con->id); + nm_sysconfig_settings_add_connection (app->settings, connection); + added = TRUE; + } else { + g_print (" error: %s\n", err ? err : "(unknown)"); + } + + g_free (filename); + } + g_dir_close (dir); + +out: + if (!added) { + g_print ("Warning: No useable configurations found\n"); + g_main_loop_quit (app->loop); + } + + return FALSE; +} + +/* ------------------------------------------------------------------------- */ + +static gboolean +dbus_reconnect (gpointer user_data) +{ + Application *app = (Application *) user_data; + + if (dbus_init (app)) { + if (start_dbus_service (app)) { + g_message ("reconnected to the system bus."); + return TRUE; + } + } + + dbus_cleanup (app); + return FALSE; +} + +static void +dbus_cleanup (Application *app) +{ + if (app->g_connection) { + dbus_g_connection_unref (app->g_connection); + app->g_connection = NULL; + app->connection = NULL; + } + + if (app->bus_proxy) { + g_signal_handlers_disconnect_by_func (app->bus_proxy, destroy_cb, app); + g_object_unref (app->bus_proxy); + app->bus_proxy = NULL; + } + + app->started = FALSE; +} + +static void +destroy_cb (DBusGProxy *proxy, gpointer user_data) +{ + Application *app = (Application *) user_data; + + /* Clean up existing connection */ + g_warning ("disconnected by the system bus."); + dbus_cleanup (app); + + g_timeout_add (3000, dbus_reconnect, app); +} + +static gboolean +start_dbus_service (Application *app) +{ + int request_name_result; + GError *err = NULL; + + if (app->started) { + g_warning ("Service has already started."); + return FALSE; + } + + if (!dbus_g_proxy_call (app->bus_proxy, "RequestName", &err, + G_TYPE_STRING, NM_DBUS_SERVICE_SYSTEM_SETTINGS, + G_TYPE_UINT, DBUS_NAME_FLAG_DO_NOT_QUEUE, + G_TYPE_INVALID, + G_TYPE_UINT, &request_name_result, + G_TYPE_INVALID)) { + g_warning ("Could not acquire the NetworkManagerSystemSettings service.\n" + " Message: '%s'", err->message); + g_error_free (err); + goto out; + } + + if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + g_warning ("Could not acquire the NetworkManagerSystemSettings service " + "as it is already taken. Return: %d", + request_name_result); + goto out; + } + + app->started = TRUE; + +out: + if (!app->started) + dbus_cleanup (app); + + return app->started; +} + +static gboolean +dbus_init (Application *app) +{ + GError *err = NULL; + + dbus_connection_set_change_sigpipe (TRUE); + + app->g_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err); + if (!app->g_connection) { + g_warning ("Could not get the system bus. Make sure " + "the message bus daemon is running! Message: %s", + err->message); + g_error_free (err); + return FALSE; + } + + app->connection = dbus_g_connection_get_connection (app->g_connection); + dbus_connection_set_exit_on_disconnect (app->connection, FALSE); + + app->bus_proxy = dbus_g_proxy_new_for_name (app->g_connection, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus"); + if (!app->bus_proxy) { + g_warning ("Could not get the DBus object!"); + goto error; + } + + g_signal_connect (app->bus_proxy, "destroy", G_CALLBACK (destroy_cb), app); + return TRUE; + +error: + dbus_cleanup (app); + return FALSE; +} + +int +main (int argc, char **argv) +{ + Application *app = g_new0 (Application, 1); + char *profile; + + g_type_init (); + + profile = get_current_profile_name (); + app->profile_path = g_strdup_printf (PROFILE_DIR "%s/", profile); + if (!app->profile_path) { + g_warning ("Current network profile directory '%s' not found.", profile); + g_free (profile); + return 1; + } + g_free (profile); + + app->loop = g_main_loop_new (NULL, FALSE); + + if (!dbus_init (app)) + return -1; + + if (!start_dbus_service (app)) + return -1; + + app->settings = nm_sysconfig_settings_new (app->g_connection); + g_idle_add (parse_files, app); + + g_main_loop_run (app->loop); + + return 0; +} + diff --git a/system-settings/nm-system-settings.conf b/system-settings/nm-system-settings.conf new file mode 100644 index 000000000..8a3829d89 --- /dev/null +++ b/system-settings/nm-system-settings.conf @@ -0,0 +1,20 @@ +<!DOCTYPE busconfig PUBLIC + "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> +<busconfig> + <policy user="root"> + <allow own="org.freedesktop.NetworkManagerSystemSettings"/> + + <allow send_destination="org.freedesktop.NetworkManagerSystemSettings"/> + <allow send_interface="org.freedesktop.NetworkManagerSystemSettings"/> + </policy> + <policy context="default"> + <deny own="org.freedesktop.NetworkManagerSystemSettings"/> + + <deny send_destination="org.freedesktop.NetworkManagerSystemSettings"/> + <deny send_interface="org.freedesktop.NetworkManagerSystemSettings"/> + </policy> + + <limit name="max_replies_per_connection">512</limit> +</busconfig> + diff --git a/system-settings/shvar.c b/system-settings/shvar.c new file mode 100644 index 000000000..c2d1b5afb --- /dev/null +++ b/system-settings/shvar.c @@ -0,0 +1,398 @@ +/* + * shvar.c + * + * Implementation of non-destructively reading/writing files containing + * only shell variable declarations and full-line comments. + * + * Includes explicit inheritance mechanism intended for use with + * Red Hat Linux ifcfg-* files. There is no protection against + * inheritance loops; they will generally cause stack overflows. + * Furthermore, they are only intended for one level of inheritance; + * the value setting algorithm assumes this. + * + * Copyright 1999,2000 Red Hat, Inc. + * + * This 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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "shvar.h" + +/* Open the file <name>, returning a shvarFile on success and NULL on failure. + Add a wrinkle to let the caller specify whether or not to create the file + (actually, return a structure anyway) if it doesn't exist. */ +static shvarFile * +svOpenFile(const char *name, gboolean create) +{ + shvarFile *s = NULL; + int closefd = 0; + + s = g_malloc0(sizeof(shvarFile)); + +#if 1 /* NetworkManager local change */ + s->fd = open(name, O_RDONLY); /* NOT O_CREAT */ + if (s->fd != -1) closefd = 1; +#else + s->fd = open(name, O_RDWR); /* NOT O_CREAT */ + if (s->fd == -1) { + /* try read-only */ + s->fd = open(name, O_RDONLY); /* NOT O_CREAT */ + if (s->fd != -1) closefd = 1; + } +#endif + s->fileName = g_strdup(name); + + if (s->fd != -1) { + struct stat buf; + char *p, *q; + + if (fstat(s->fd, &buf) < 0) goto bail; + s->arena = g_malloc0(buf.st_size + 1); + + if (read(s->fd, s->arena, buf.st_size) < 0) goto bail; + + /* we'd use g_strsplit() here, but we want a list, not an array */ + for(p = s->arena; (q = strchr(p, '\n')) != NULL; p = q + 1) { + s->lineList = g_list_append(s->lineList, g_strndup(p, q - p)); + } + + /* closefd is set if we opened the file read-only, so go ahead and + close it, because we can't write to it anyway */ + if (closefd) { + close(s->fd); + s->fd = -1; + } + + return s; + } + + if (create) { + return s; + } + +bail: + if (s->fd != -1) close(s->fd); + if (s->arena) g_free (s->arena); + if (s->fileName) g_free (s->fileName); + g_free (s); + return NULL; +} + +/* Open the file <name>, return shvarFile on success, NULL on failure */ +shvarFile * +svNewFile(const char *name) +{ + return svOpenFile(name, FALSE); +} + +/* Create a new file structure, returning actual data if the file exists, + * and a suitable starting point if it doesn't. */ +shvarFile * +svCreateFile(const char *name) +{ + return svOpenFile(name, TRUE); +} + +/* remove escaped characters in place */ +static void +unescape(char *s) { + int len, i; + + len = strlen(s); + if ((s[0] == '"' || s[0] == '\'') && s[0] == s[len-1]) { + i = len - 2; + memmove(s, s+1, i); + s[i+1] = '\0'; + len = i; + } + for (i = 0; i < len; i++) { + if (s[i] == '\\') { + memmove(s+i, s+i+1, len-(i+1)); + len--; + } + s[len] = '\0'; + } +} + + +/* create a new string with all necessary characters escaped. + * caller must free returned string + */ +static const char escapees[] = "\"'\\$~`"; /* must be escaped */ +static const char spaces[] = " \t|&;()<>"; /* only require "" */ +static char * +escape(const char *s) { + char *new; + int i, j, mangle = 0, space = 0; + int newlen, slen; + static int esclen, splen; + + if (!esclen) esclen = strlen(escapees); + if (!splen) splen = strlen(spaces); + slen = strlen(s); + + for (i = 0; i < slen; i++) { + if (strchr(escapees, s[i])) mangle++; + if (strchr(spaces, s[i])) space++; + } + if (!mangle && !space) return strdup(s); + + newlen = slen + mangle + 3; /* 3 is extra ""\0 */ + new = g_malloc0(newlen); + if (!new) return NULL; + + j = 0; + new[j++] = '"'; + for (i = 0; i < slen; i++) { + if (strchr(escapees, s[i])) { + new[j++] = '\\'; + } + new[j++] = s[i]; + } + new[j++] = '"'; + g_assert(j == slen + mangle + 2); /* j is the index of the '\0' */ + + return new; +} + +/* Get the value associated with the key, and leave the current pointer + * pointing at the line containing the value. The char* returned MUST + * be freed by the caller. + */ +char * +svGetValue(shvarFile *s, const char *key) +{ + char *value = NULL; + char *line; + char *keyString; + int len; + + g_assert(s); + g_assert(key); + + keyString = g_malloc0(strlen(key) + 2); + strcpy(keyString, key); + keyString[strlen(key)] = '='; + len = strlen(keyString); + + for (s->current = s->lineList; s->current; s->current = s->current->next) { + line = s->current->data; + if (!strncmp(keyString, line, len)) { + value = g_strdup(line + len); + unescape(value); + break; + } + } + g_free(keyString); + + if (value) { + if (value[0]) { + return value; + } else { + g_free(value); + return NULL; + } + } + if (s->parent) value = svGetValue(s->parent, key); + return value; +} + +/* return 1 if <key> resolves to any truth value (e.g. "yes", "y", "true") + * return 0 if <key> resolves to any non-truth value (e.g. "no", "n", "false") + * return <default> otherwise + */ +int +svTrueValue(shvarFile *s, const char *key, int def) +{ + char *tmp; + int returnValue = def; + + tmp = svGetValue(s, key); + if (!tmp) return returnValue; + + if ( (!strcasecmp("yes", tmp)) || + (!strcasecmp("true", tmp)) || + (!strcasecmp("t", tmp)) || + (!strcasecmp("y", tmp)) ) returnValue = 1; + else + if ( (!strcasecmp("no", tmp)) || + (!strcasecmp("false", tmp)) || + (!strcasecmp("f", tmp)) || + (!strcasecmp("n", tmp)) ) returnValue = 0; + + g_free (tmp); + return returnValue; +} + + +/* Set the variable <key> equal to the value <value>. + * If <key> does not exist, and the <current> pointer is set, append + * the key=value pair after that line. Otherwise, prepend the pair + * to the top of the file. Here's the algorithm, as the C code + * seems to be rather dense: + * + * if (value == NULL), then: + * if val2 (parent): change line to key= or append line key= + * if val1 (this) : delete line + * else noop + * else use this table: + * val2 + * NULL value other + * v NULL append line noop append line + * a + * l value noop noop noop + * 1 + * other change line delete line change line + * + * No changes are ever made to the parent config file, only to the + * specific file passed on the command line. + * + */ +void +svSetValue(shvarFile *s, const char *key, const char *value) +{ + char *newval = NULL, *val1 = NULL, *val2 = NULL; + char *keyValue; + + g_assert(s); + g_assert(key); + /* value may be NULL */ + + if (value) newval = escape(value); + keyValue = g_strdup_printf("%s=%s", key, newval ? newval : ""); + + val1 = svGetValue(s, key); + if (val1 && newval && !strcmp(val1, newval)) goto bail; + if (s->parent) val2 = svGetValue(s->parent, key); + + if (!newval || !newval[0]) { + /* delete value somehow */ + if (val2) { + /* change/append line to get key= */ + if (s->current) s->current->data = keyValue; + else s->lineList = g_list_append(s->lineList, keyValue); + s->freeList = g_list_append(s->freeList, keyValue); + s->modified = 1; + } else if (val1) { + /* delete line */ + s->lineList = g_list_remove_link(s->lineList, s->current); + g_list_free_1(s->current); + s->modified = 1; + goto bail; /* do not need keyValue */ + } + goto end; + } + + if (!val1) { + if (val2 && !strcmp(val2, newval)) goto end; + /* append line */ + s->lineList = g_list_append(s->lineList, keyValue); + s->freeList = g_list_append(s->freeList, keyValue); + s->modified = 1; + goto end; + } + + /* deal with a whole line of noops */ + if (val1 && !strcmp(val1, newval)) goto end; + + /* At this point, val1 && val1 != value */ + if (val2 && !strcmp(val2, newval)) { + /* delete line */ + s->lineList = g_list_remove_link(s->lineList, s->current); + g_list_free_1(s->current); + s->modified = 1; + goto bail; /* do not need keyValue */ + } else { + /* change line */ + if (s->current) s->current->data = keyValue; + else s->lineList = g_list_append(s->lineList, keyValue); + s->freeList = g_list_append(s->freeList, keyValue); + s->modified = 1; + } + +end: + if (newval) free(newval); + if (val1) free(val1); + if (val2) free(val2); + return; + +bail: + if (keyValue) free (keyValue); + goto end; +} + +/* Write the current contents iff modified. Returns -1 on error + * and 0 on success. Do not write if no values have been modified. + * The mode argument is only used if creating the file, not if + * re-writing an existing file, and is passed unchanged to the + * open() syscall. + */ +int +svWriteFile(shvarFile *s, int mode) +{ + FILE *f; + int tmpfd; + + if (s->modified) { + if (s->fd == -1) + s->fd = open(s->fileName, O_WRONLY|O_CREAT, mode); + if (s->fd == -1) + return -1; + if (ftruncate(s->fd, 0) < 0) + return -1; + + tmpfd = dup(s->fd); + f = fdopen(tmpfd, "w"); + fseek(f, 0, SEEK_SET); + for (s->current = s->lineList; s->current; s->current = s->current->next) { + char *line = s->current->data; + fprintf(f, "%s\n", line); + } + fclose(f); + } + + return 0; +} + + +/* Close the file descriptor (if open) and delete the shvarFile. + * Returns -1 on error and 0 on success. + */ +int +svCloseFile(shvarFile *s) +{ + + g_assert(s); + + if (s->fd != -1) close(s->fd); + + g_free(s->arena); + for (s->current = s->freeList; s->current; s->current = s->current->next) { + g_free(s->current->data); + } + g_free(s->fileName); + g_list_free(s->freeList); + g_list_free(s->lineList); /* implicitly frees s->current */ + g_free(s); + return 0; +} diff --git a/system-settings/shvar.h b/system-settings/shvar.h new file mode 100644 index 000000000..50d10680d --- /dev/null +++ b/system-settings/shvar.h @@ -0,0 +1,103 @@ +/* + * shvar.h + * + * Interface for non-destructively reading/writing files containing + * only shell variable declarations and full-line comments. + * + * Includes explicit inheritance mechanism intended for use with + * Red Hat Linux ifcfg-* files. There is no protection against + * inheritance loops; they will generally cause stack overflows. + * Furthermore, they are only intended for one level of inheritance; + * the value setting algorithm assumes this. + * + * Copyright 1999 Red Hat, Inc. + * + * This 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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef _SHVAR_H +#define _SHVAR_H + +#include <glib.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _shvarFile shvarFile; +struct _shvarFile { + char *fileName; /* read-only */ + int fd; /* read-only */ + char *arena; /* ignore */ + GList *lineList; /* read-only */ + GList *freeList; /* ignore */ + GList *current; /* set implicitly or explicitly, + points to element of lineList */ + shvarFile *parent; /* set explicitly */ + int modified; /* ignore */ +}; + + +/* Create the file <name>, return shvarFile on success, NULL on failure */ +shvarFile * +svCreateFile(const char *name); + +/* Open the file <name>, return shvarFile on success, NULL on failure */ +shvarFile * +svNewFile(const char *name); + +/* Get the value associated with the key, and leave the current pointer + * pointing at the line containing the value. The char* returned MUST + * be freed by the caller. + */ +char * +svGetValue(shvarFile *s, const char *key); + +/* return 1 if <key> resolves to any truth value (e.g. "yes", "y", "true") + * return 0 if <key> resolves to any non-truth value (e.g. "no", "n", "false") + * return <def> otherwise + */ +int +svTrueValue(shvarFile *s, const char *key, int def); + +/* Set the variable <key> equal to the value <value>. + * If <key> does not exist, and the <current> pointer is set, append + * the key=value pair after that line. Otherwise, prepend the pair + * to the top of the file. + */ +void +svSetValue(shvarFile *s, const char *key, const char *value); + + +/* Write the current contents iff modified. Returns -1 on error + * and 0 on success. Do not write if no values have been modified. + * The mode argument is only used if creating the file, not if + * re-writing an existing file, and is passed unchanged to the + * open() syscall. + */ +int +svWriteFile(shvarFile *s, int mode); + +/* Close the file descriptor (if open) and delete the shvarFile. + * Returns -1 on error and 0 on success. + */ +int +svCloseFile(shvarFile *s); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ! _SHVAR_H */ |