ifcfg-suse: Clean up, upstream the patch which has been in use for a while

Since openSUSE 11.1 NetworkManager does not support reading yast network
setup. It's for your own good - you either want to use static configuration
(yast) or dynamic (NetworkManager). Mixing the two has never worked very well
and has caused a lot of confusion. The only exception to this is hostname
handling, which is handled by ifcfg-suse plugin.
This commit is contained in:
Tambet Ingo
2009-12-21 12:07:18 +02:00
parent 1e1be1cd57
commit b9ca266d94
9 changed files with 126 additions and 1743 deletions

View File

@@ -2,12 +2,6 @@
pkglib_LTLIBRARIES = libnm-settings-plugin-ifcfg-suse.la
libnm_settings_plugin_ifcfg_suse_la_SOURCES = \
nm-suse-connection.c \
nm-suse-connection.h \
shvar.c \
shvar.h \
parser.c \
parser.h \
plugin.c \
plugin.h
@@ -15,8 +9,6 @@ libnm_settings_plugin_ifcfg_suse_la_CPPFLAGS = \
$(GLIB_CFLAGS) \
$(GMODULE_CFLAGS) \
$(DBUS_CFLAGS) \
$(POLKIT_CFLAGS) \
$(GUDEV_CFLAGS) \
-DG_DISABLE_DEPRECATED \
-I${top_srcdir}/src/system-settings \
-I$(top_srcdir)/include \
@@ -30,7 +22,5 @@ libnm_settings_plugin_ifcfg_suse_la_LIBADD = \
$(top_builddir)/libnm-glib/libnm-glib.la \
$(GLIB_LIBS) \
$(GMODULE_LIBS) \
$(POLKIT_LIBS) \
$(GUDEV_LIBS) \
$(GIO_LIBS)

View File

@@ -1,171 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2008 Novell, Inc.
*/
#include <string.h>
#include <glib/gstdio.h>
#include <gio/gio.h>
#include <NetworkManager.h>
#include <nm-settings-connection-interface.h>
#include <nm-setting-connection.h>
#include "nm-suse-connection.h"
#include "parser.h"
#include "nm-system-config-error.h"
G_DEFINE_TYPE (NMSuseConnection, nm_suse_connection, NM_TYPE_SYSCONFIG_CONNECTION)
#define NM_SUSE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SUSE_CONNECTION, NMSuseConnectionPrivate))
typedef struct {
GFileMonitor *monitor;
guint monitor_id;
const char *iface;
NMDeviceType dev_type;
char *filename;
} NMSuseConnectionPrivate;
static void
file_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer user_data)
{
NMSuseConnection *self = NM_SUSE_CONNECTION (user_data);
NMSuseConnectionPrivate *priv = NM_SUSE_CONNECTION_GET_PRIVATE (self);
NMConnection *new;
GError *error = NULL;
switch (event_type) {
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
new = parse_ifcfg (priv->iface, priv->dev_type);
if (new) {
if (!nm_sysconfig_connection_update (NM_SYSCONFIG_CONNECTION (self),
NM_CONNECTION (new),
TRUE,
&error)) {
g_warning ("%s: '%s' / '%s' invalid: %d",
__func__,
error ? g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)) : "(none)",
(error && error->message) ? error->message : "(none)",
error ? error->code : -1);
g_clear_error (&error);
}
g_object_unref (new);
} else
g_signal_emit_by_name (self, "removed");
break;
case G_FILE_MONITOR_EVENT_DELETED:
g_signal_emit_by_name (self, "removed");
break;
default:
break;
}
}
NMSuseConnection *
nm_suse_connection_new (const char *iface, NMDeviceType dev_type)
{
NMConnection *tmp;
GFile *file;
GFileMonitor *monitor;
NMSuseConnection *exported;
NMSuseConnectionPrivate *priv;
NMSettingConnection *s_con;
g_return_val_if_fail (iface != NULL, NULL);
tmp = parse_ifcfg (iface, dev_type);
if (!tmp)
return NULL;
/* Ensure the read connection is read-only since we don't have write capability yet */
s_con = (NMSettingConnection *) nm_connection_get_setting (tmp, NM_TYPE_SETTING_CONNECTION);
g_assert (s_con);
if (!nm_setting_connection_get_read_only (s_con)) {
g_warning ("%s: expected read-only connection!", __func__);
g_object_unref (tmp);
return NULL;
}
exported = (NMSuseConnection *) g_object_new (NM_TYPE_SUSE_CONNECTION, NULL);
if (!exported) {
g_object_unref (tmp);
return NULL;
}
/* Update our settings with what was read from the file */
nm_sysconfig_connection_update (NM_SYSCONFIG_CONNECTION (exported), tmp, FALSE, NULL);
g_object_unref (tmp);
priv = NM_SUSE_CONNECTION_GET_PRIVATE (exported);
priv->iface = g_strdup (iface);
priv->dev_type = dev_type;
priv->filename = g_strdup_printf (SYSCONFDIR "/sysconfig/network/ifcfg-%s", iface);
file = g_file_new_for_path (priv->filename);
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (monitor) {
priv->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (file_changed), exported);
priv->monitor = monitor;
}
return exported;
}
/* GObject */
static void
nm_suse_connection_init (NMSuseConnection *connection)
{
}
static void
finalize (GObject *object)
{
NMSuseConnectionPrivate *priv = NM_SUSE_CONNECTION_GET_PRIVATE (object);
if (priv->monitor) {
if (priv->monitor_id)
g_signal_handler_disconnect (priv->monitor, priv->monitor_id);
g_file_monitor_cancel (priv->monitor);
g_object_unref (priv->monitor);
}
nm_connection_clear_secrets (NM_CONNECTION (object));
g_free (priv->filename);
G_OBJECT_CLASS (nm_suse_connection_parent_class)->finalize (object);
}
static void
nm_suse_connection_class_init (NMSuseConnectionClass *suse_connection_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (suse_connection_class);
g_type_class_add_private (suse_connection_class, sizeof (NMSuseConnectionPrivate));
/* Virtual methods */
object_class->finalize = finalize;
}

View File

@@ -1,51 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2008 Novell, Inc.
*/
#ifndef NM_SUSE_CONNECTION_H
#define NM_SUSE_CONNECTION_H
#include <NetworkManager.h>
#include <nm-sysconfig-connection.h>
G_BEGIN_DECLS
#define NM_TYPE_SUSE_CONNECTION (nm_suse_connection_get_type ())
#define NM_SUSE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SUSE_CONNECTION, NMSuseConnection))
#define NM_SUSE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SUSE_CONNECTION, NMSuseConnectionClass))
#define NM_IS_SUSE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SUSE_CONNECTION))
#define NM_IS_SUSE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_SUSE_CONNECTION))
#define NM_SUSE_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SUSE_CONNECTION, NMSuseConnectionClass))
typedef struct {
NMSysconfigConnection parent;
} NMSuseConnection;
typedef struct {
NMSysconfigConnectionClass parent;
} NMSuseConnectionClass;
GType nm_suse_connection_get_type (void);
NMSuseConnection *nm_suse_connection_new (const char *iface,
NMDeviceType dev_type);
G_END_DECLS
#endif /* NM_SUSE_CONNECTION_H */

View File

@@ -1,703 +0,0 @@
/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
/* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2007 Red Hat, Inc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <sys/inotify.h>
#include <glib.h>
#include <nm-connection.h>
#include <NetworkManager.h>
#include <nm-setting-connection.h>
#include <nm-setting-ip4-config.h>
#include <nm-setting-wired.h>
#include <nm-setting-wireless.h>
#include <nm-setting-8021x.h>
#include <nm-utils.h>
#include "shvar.h"
#include "parser.h"
#include "plugin.h"
#define WPA_PMK_LEN 32
/* Common */
static gboolean
get_int (const char *str, int *value)
{
char *e;
*value = strtol (str, &e, 0);
if (*e != '\0')
return FALSE;
return TRUE;
}
static NMSetting *
make_connection_setting (shvarFile *file,
const char *iface,
const char *type,
const char *suggested)
{
NMSettingConnection *s_con;
char *str = NULL;
s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
if (suggested) {
/* For cosmetic reasons, if the suggested name is the same as
* the ifcfg files name, don't use it.
*/
if (strcmp (iface, suggested))
str = g_strdup_printf ("System %s (%s)", suggested, iface);
}
if (!str)
str = g_strdup_printf ("System %s", iface);
g_object_set (s_con,
NM_SETTING_CONNECTION_ID, str,
NM_SETTING_CONNECTION_TYPE, type,
NM_SETTING_CONNECTION_READ_ONLY, TRUE,
NULL);
g_free (str);
str = nm_utils_uuid_generate_from_string (file->fileName);
g_object_set (s_con, NM_SETTING_CONNECTION_UUID, str, NULL);
g_free (str);
str = svGetValue (file, "STARTMODE");
if (str && !g_ascii_strcasecmp (str, "manual"))
g_object_set (s_con, NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, NULL);
else
g_object_set (s_con, NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NULL);
g_free (str);
return (NMSetting *) s_con;
}
static NMSetting *
make_ip4_setting (shvarFile *ifcfg)
{
NMSettingIP4Config *s_ip4;
char *str;
NMIP4Address *addr;
s_ip4 = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ());
str = svGetValue (ifcfg, "BOOTPROTO");
if (str) {
if (!g_ascii_strcasecmp (str, "bootp") || !g_ascii_strcasecmp (str, "dhcp"))
g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
else if (!g_ascii_strcasecmp (str, "static"))
g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NULL);
else if (!g_ascii_strcasecmp (str, "autoip"))
g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL, NULL);
g_free (str);
}
if (!nm_setting_ip4_config_get_method (s_ip4))
g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
addr = nm_ip4_address_new ();
str = svGetValue (ifcfg, "IPADDR");
if (str) {
char **pieces;
struct in_addr ip4_addr;
pieces = g_strsplit (str, "/", 2);
if (inet_pton (AF_INET, pieces[0], &ip4_addr) > 0) {
nm_ip4_address_set_address (addr, ip4_addr.s_addr);
if (g_strv_length (pieces) == 2)
nm_ip4_address_set_prefix (addr, atoi (pieces[1]));
} else
g_warning ("Ignoring invalid IP4 address '%s'", str);
g_strfreev (pieces);
g_free (str);
}
if (nm_ip4_address_get_address (addr) && nm_ip4_address_get_prefix (addr) == 0) {
str = svGetValue (ifcfg, "PREFIXLEN");
if (str) {
nm_ip4_address_set_prefix (addr, atoi (str));
g_free (str);
}
}
if (nm_ip4_address_get_address (addr) && nm_ip4_address_get_prefix (addr) == 0) {
str = svGetValue (ifcfg, "NETMASK");
if (str) {
struct in_addr mask_addr;
if (inet_pton (AF_INET, str, &mask_addr) > 0)
nm_ip4_address_set_prefix (addr, nm_utils_ip4_netmask_to_prefix (mask_addr.s_addr));
else {
g_warning ("Ignoring invalid IP4 address: invalid netmask: '%s'", str);
nm_ip4_address_set_address (addr, 0);
nm_ip4_address_set_prefix (addr, 0);
}
g_free (str);
}
}
if (!nm_ip4_address_get_prefix (addr) || nm_ip4_address_get_prefix (addr) > 32) {
g_warning ("Ignoring invalid IP4 address: invalid prefix: '%d'", nm_ip4_address_get_prefix (addr));
nm_ip4_address_set_address (addr, 0);
nm_ip4_address_set_prefix (addr, 0);
}
if (nm_ip4_address_get_address (addr)) {
if (!nm_setting_ip4_config_add_address (s_ip4, addr))
g_warning ("Ignoring duplicate IP4 address");
}
nm_ip4_address_unref (addr);
return NM_SETTING (s_ip4);
}
/* Ethernet */
static NMSetting *
make_wired_setting (shvarFile *ifcfg)
{
NMSettingWired *s_wired;
char *str;
int mtu;
s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
str = svGetValue (ifcfg, "MTU");
if (str) {
if (strlen (str) < 1)
/* Ignore empty MTU */
;
else if (get_int (str, &mtu)) {
if (mtu >= 0 && mtu < G_MAXINT)
g_object_set (s_wired, NM_SETTING_WIRED_MTU, mtu, NULL);
} else
g_warning ("Ignoring invalid MTU: '%s'", str);
g_free (str);
}
return (NMSetting *) s_wired;
}
static void
parse_ethernet (NMConnection *connection, shvarFile *file, const char *iface)
{
NMSetting *setting;
setting = make_connection_setting (file, iface, NM_SETTING_WIRED_SETTING_NAME, NULL);
nm_connection_add_setting (connection, setting);
setting = make_wired_setting (file);
nm_connection_add_setting (connection, setting);
setting = make_ip4_setting (file);
nm_connection_add_setting (connection, setting);
}
/* Wireless */
static char *
get_one_wep_key (shvarFile *ifcfg, guint8 idx, GError **err)
{
char *shvar_key;
char *key = NULL;
char *value = NULL;
char *p;
g_return_val_if_fail (idx <= 3, NULL);
shvar_key = g_strdup_printf ("WIRELESS_KEY_%d", idx);
value = svGetValue (ifcfg, shvar_key);
g_free (shvar_key);
/* Ignore empty keys */
if (!value)
return NULL;
if (strlen (value) < 1) {
g_free (value);
return NULL;
}
/* ASCII */
if (g_str_has_prefix (value, "s:")) {
p = value + 2;
if (strlen (p) != 5 || strlen (p) != 13)
g_set_error (err, ifcfg_plugin_error_quark (), 0, "Invalid hexadecimal WEP key.");
else {
while (*p) {
if (!isascii (*p)) {
g_set_error (err, ifcfg_plugin_error_quark (), 0, "Invalid hexadecimal WEP key.");
break;
}
p++;
}
}
if (!err)
key = g_strdup (p);
} else if (g_str_has_prefix (value, "h:")) {
/* Hashed passphrase */
p = value + 2;
if (p && (strlen (p) > 0 || strlen (p) < 65))
key = g_strdup (p);
else
g_set_error (err, ifcfg_plugin_error_quark (), 0, "Invalid WEP passphrase.");
} else {
/* Hexadecimal */
GString *str;
str = g_string_sized_new (26);
p = value + 2;
while (*p) {
if (g_ascii_isxdigit (*p))
str = g_string_append_c (str, *p);
else if (*p != '-') {
g_set_error (err, ifcfg_plugin_error_quark (), 0, "Invalid hexadecimal WEP key.");
break;
}
p++;
}
p = str->str;
if (p && (strlen (p) == 10 || strlen (p) == 26))
key = g_string_free (str, FALSE);
else
g_set_error (err, ifcfg_plugin_error_quark (), 0, "Invalid hexadecimal WEP key.");
}
g_free (value);
return key;
}
#define READ_WEP_KEY(idx) \
{ \
char *key = get_one_wep_key (ifcfg, idx, &err); \
if (err) \
goto error; \
if (key) { \
g_object_set (G_OBJECT (security), \
NM_SETTING_WIRELESS_SECURITY_WEP_KEY##idx, \
key, \
NULL); \
g_free (key); \
have_key = TRUE; \
} \
}
static void
read_wep_settings (shvarFile *ifcfg, NMSettingWirelessSecurity *security)
{
char *value;
GError *err = NULL;
gboolean have_key = FALSE;
READ_WEP_KEY(0)
READ_WEP_KEY(1)
READ_WEP_KEY(2)
READ_WEP_KEY(3)
if (have_key)
g_object_set (security, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NULL);
value = svGetValue (ifcfg, "WIRELESS_DEFAULT_KEY");
if (value) {
gboolean success;
int key_idx = 0;
success = get_int (value, &key_idx);
if (success && (key_idx >= 0) && (key_idx <= 3))
g_object_set (security, NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, key_idx, NULL);
else
g_warning ("Invalid default WEP key: '%s'", value);
g_free (value);
}
error:
if (err) {
g_warning ("%s", err->message);
g_error_free (err);
}
}
static void
read_wpa_psk_settings (shvarFile *ifcfg,
NMSettingWirelessSecurity *security,
NMSettingWireless *s_wireless)
{
char *value;
value = svGetValue (ifcfg, "WIRELESS_WPA_PSK");
if (value) {
if (strlen (value) > 64 || strlen (value) < 8)
g_warning ("Error loading WIRELESS_WPA_PSK: not between 8 and 64 characters inclusive");
else
g_object_set (security, NM_SETTING_WIRELESS_SECURITY_PSK, value, NULL);
g_free (value);
} else
g_warning ("Missing WPA-PSK key");
}
static NMSetting *
read_wpa_eap_settings (shvarFile *ifcfg)
{
NMSetting8021x *s_802_1x;
char *str;
GError *err = NULL;
NMSetting8021xCKType cert_type;
s_802_1x = NM_SETTING_802_1X (nm_setting_802_1x_new ());
str = svGetValue (ifcfg, "WIRELESS_EAP_MODE");
if (str) {
char **pieces;
int i;
pieces = g_strsplit (str, " ", 0);
for (i = 0; pieces[i]; i++)
nm_setting_802_1x_add_eap_method (s_802_1x, pieces[i]);
g_free (pieces);
g_free (str);
}
str = svGetValue (ifcfg, "WIRELESS_WPA_ANONID");
g_object_set (s_802_1x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, str, NULL);
g_free (str);
str = svGetValue (ifcfg, "WIRELESS_PEAP_VERSION");
g_object_set (s_802_1x, NM_SETTING_802_1X_PHASE1_PEAPVER, str, NULL);
g_free (str);
str = svGetValue (ifcfg, "WIRELESS_EAP_AUTH");
g_object_set (s_802_1x, NM_SETTING_802_1X_PHASE2_AUTH, str, NULL);
g_free (str);
str = svGetValue (ifcfg, "WIRELESS_WPA_IDENTITY");
g_object_set (s_802_1x, NM_SETTING_802_1X_IDENTITY, str, NULL);
g_free (str);
str = svGetValue (ifcfg, "WIRELESS_WPA_PASSWORD");
g_object_set (s_802_1x, NM_SETTING_802_1X_PASSWORD, str, NULL);
g_free (str);
str = svGetValue (ifcfg, "WIRELESS_CA_CERT");
if (str) {
nm_setting_802_1x_set_ca_cert_from_file (s_802_1x, str, &cert_type, &err);
if (err) {
g_warning ("Error loading WIRELESS_CA_CERT: %s", err->message);
g_error_free (err);
}
g_free (str);
}
str = svGetValue (ifcfg, "WIRELESS_CLIENT_CERT");
if (str) {
nm_setting_802_1x_set_client_cert_from_file (s_802_1x, str, &cert_type, &err);
if (err) {
g_warning ("Error loading WIRELESS_CLIENT_CERT: %s", err->message);
g_error_free (err);
}
g_free (str);
}
str = svGetValue (ifcfg, "WIRELESS_CLIENT_KEY");
if (str) {
char *password;
password = svGetValue (ifcfg, "WIRELESS_CLIENT_KEY_PASSWORD");
if (password) {
nm_setting_802_1x_set_private_key_from_file (s_802_1x, str, password, &cert_type, &err);
if (err) {
g_warning ("Error loading WIRELESS_CLIENT_KEY: %s", err->message);
g_error_free (err);
}
g_free (password);
} else
g_warning ("Missing WIRELESS_CLIENT_KEY_PASSWORD");
g_free (str);
}
return (NMSetting *) s_802_1x;
}
static NMSetting *
make_wireless_security_setting (shvarFile *ifcfg, NMSettingWireless *s_wireless)
{
NMSettingWirelessSecurity *security;
char *str;
str = svGetValue (ifcfg, "WIRELESS_AUTH_MODE");
if (!str || !g_ascii_strcasecmp (str, "no-encryption")) {
g_free (str);
return NULL;
}
if (!g_ascii_strcasecmp (str, "eap"))
return read_wpa_eap_settings (ifcfg);
security = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
if (!g_ascii_strcasecmp (str, "open")) {
g_object_set (security, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL);
read_wep_settings (ifcfg, security);
} else if (!g_ascii_strcasecmp (str, "sharedkey")) {
g_object_set (security, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", NULL);
read_wep_settings (ifcfg, security);
} else if (!g_ascii_strcasecmp (str, "psk")) {
g_object_set (security, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", NULL);
read_wpa_psk_settings (ifcfg, security, s_wireless);
} else
g_warning ("Invalid authentication algorithm: '%s'", str);
g_free (str);
return (NMSetting *) security;
}
static NMSetting *
make_wireless_setting (shvarFile *ifcfg)
{
NMSettingWireless *s_wireless;
char *str;
s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
str = svGetValue (ifcfg, "WIRELESS_ESSID");
if (str) {
gsize len = strlen (str);
if (len > 0 && len <= 32) {
GByteArray *ssid;
ssid = g_byte_array_sized_new (len);
g_byte_array_append (ssid, (const guint8 *) str, len);
g_object_set (s_wireless, NM_SETTING_WIRELESS_SSID, ssid, NULL);
g_byte_array_free (ssid, TRUE);
} else
g_warning ("Ignoring invalid ESSID '%s', (size %zu not between 1 and 32 inclusive)", str, len);
g_free (str);
}
str = svGetValue (ifcfg, "WIRLESS_MODE");
if (str) {
const char *mode;
if (!g_ascii_strcasecmp (str, "ad-hoc"))
mode = "adhoc";
else if (!g_ascii_strcasecmp (str, "managed"))
mode = "infrastructure";
else
mode = NULL;
if (mode)
g_object_set (s_wireless, NM_SETTING_WIRELESS_MODE, mode, NULL);
g_free (str);
}
// FIXME: channel/freq, other L2 parameters like RTS
return NM_SETTING (s_wireless);
}
static char *
get_printable_ssid (NMSetting *setting)
{
const GByteArray *ssid;
char *printable_ssid = NULL;
ssid = nm_setting_wireless_get_ssid (NM_SETTING_WIRELESS (setting));
if (ssid)
printable_ssid = nm_utils_ssid_to_utf8 ((const char *) ssid->data, ssid->len);
return printable_ssid;
}
static void
parse_wireless (NMConnection *connection, shvarFile *file, const char *iface)
{
NMSetting *setting;
NMSetting *security;
char *printable_ssid;
setting = make_wireless_setting (file);
nm_connection_add_setting (connection, setting);
security = make_wireless_security_setting (file, NM_SETTING_WIRELESS (setting));
if (security) {
const char *security_str;
if (NM_IS_SETTING_802_1X (security))
security_str = NM_SETTING_802_1X_SETTING_NAME;
else if (NM_IS_SETTING_WIRELESS_SECURITY (security))
security_str = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME;
else {
security_str = NULL;
g_warning ("Invalid security type: '%s'", G_OBJECT_TYPE_NAME (security));
}
g_object_set (G_OBJECT (setting), NM_SETTING_WIRELESS_SEC, security_str, NULL);
nm_connection_add_setting (connection, security);
}
printable_ssid = get_printable_ssid (setting);
setting = make_connection_setting (file, iface, NM_SETTING_WIRELESS_SETTING_NAME, printable_ssid);
nm_connection_add_setting (connection, setting);
g_free (printable_ssid);
setting = make_ip4_setting (file);
nm_connection_add_setting (connection, setting);
}
static shvarFile *
parser_get_ifcfg_for_iface (const char *iface)
{
char *filename;
shvarFile *file = NULL;
filename = g_strdup_printf (SYSCONFDIR "/sysconfig/network/ifcfg-%s", iface);
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
file = svNewFile (filename);
g_free (filename);
return file;
}
NMConnection *
parse_ifcfg (const char *iface, NMDeviceType type)
{
shvarFile *file;
NMConnection *connection;
GError *error = NULL;
g_return_val_if_fail (iface != NULL, NULL);
file = parser_get_ifcfg_for_iface (iface);
if (!file)
return NULL;
connection = nm_connection_new ();
switch (type) {
case NM_DEVICE_TYPE_ETHERNET:
parse_ethernet (connection, file, iface);
break;
case NM_DEVICE_TYPE_WIFI:
parse_wireless (connection, file, iface);
break;
default:
break;
}
svCloseFile (file);
if (!nm_connection_verify (connection, &error)) {
g_warning ("%s: Invalid connection for %s: '%s' / '%s' invalid: %d",
__func__, iface,
g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)),
error->message, error->code);
g_error_free (error);
g_object_unref (connection);
connection = NULL;
}
return connection;
}
gboolean
parser_ignore_device (const char *iface)
{
shvarFile *file;
gboolean ignore = FALSE;
file = parser_get_ifcfg_for_iface (iface);
if (file) {
char *str;
if (!svTrueValue (file, "NM_CONTROLLED", 1))
ignore = TRUE;
str = svGetValue (file, "STARTMODE");
if (str && !g_ascii_strcasecmp (str, "off"))
ignore = TRUE;
g_free (str);
svCloseFile (file);
}
return ignore;
}
guint32
parser_parse_routes (const char *filename)
{
FILE *f;
char *buf;
char buffer[512];
guint route = 0;
g_return_val_if_fail (filename != NULL, 0);
if ((f = fopen (filename, "r"))) {
while (fgets (buffer, 512, f) && !feof (f)) {
buf = strtok (buffer, " ");
if (strcmp (buf, "default") == 0) {
buf = strtok (NULL, " ");
if (buf)
route = inet_addr (buf);
break;
}
fclose (f);
}
}
return route;
}

View File

@@ -1,37 +0,0 @@
/* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2007 Red Hat, Inc.
*/
#ifndef _PARSER_H_
#define _PARSER_H_
#include <glib.h>
#include <NetworkManager.h>
#include <nm-connection.h>
#define IFCFG_TAG "ifcfg-"
#define BAK_TAG ".bak"
NMConnection *parse_ifcfg (const char *iface, NMDeviceType type);
gboolean parser_ignore_device (const char *iface);
guint32 parser_parse_routes (const char *filename);
#endif /* _PARSER_H_ */

View File

@@ -24,32 +24,19 @@
#include <config.h>
#include <string.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <gmodule.h>
#include <glib-object.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
#include <nm-setting-connection.h>
#include <nm-setting-ip4-config.h>
#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
#include <gudev/gudev.h>
#include "plugin.h"
#include "parser.h"
#include "nm-suse-connection.h"
#include "nm-system-config-interface.h"
#include "wireless-helper.h"
#define IFCFG_PLUGIN_NAME "ifcfg-suse"
#define IFCFG_PLUGIN_INFO "(C) 2008 Novell, Inc. To report bugs please use the NetworkManager mailing list."
#define IFCFG_DIR SYSCONFDIR "/sysconfig/network"
#define CONF_DHCP IFCFG_DIR "/dhcp"
#define HOSTNAME_FILE "/etc/HOSTNAME"
static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class);
@@ -63,15 +50,9 @@ G_DEFINE_TYPE_EXTENDED (SCPluginIfcfg, sc_plugin_ifcfg, G_TYPE_OBJECT, 0,
#define IFCFG_FILE_PATH_TAG "ifcfg-file-path"
typedef struct {
GUdevClient *client;
gboolean initialized;
GHashTable *connections;
GHashTable *unmanaged_specs;
guint32 default_gw;
GFileMonitor *default_gw_monitor;
guint default_gw_monitor_id;
GFileMonitor *hostname_monitor;
GFileMonitor *dhcp_monitor;
char *hostname;
} SCPluginIfcfgPrivate;
GQuark
@@ -85,285 +66,153 @@ ifcfg_plugin_error_quark (void)
return error_quark;
}
static void
ignore_cb (NMSettingsConnectionInterface *connection,
GError *error,
gpointer user_data)
{
}
typedef void (*FileChangedFn) (gpointer user_data);
typedef struct {
FileChangedFn callback;
gpointer user_data;
} FileMonitorInfo;
static void
update_connections (SCPluginIfcfg *self)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
GHashTableIter iter;
gpointer value;
g_hash_table_iter_init (&iter, priv->connections);
while (g_hash_table_iter_next (&iter, NULL, &value)) {
NMSuseConnection *exported = NM_SUSE_CONNECTION (value);
NMSettingIP4Config *ip4_config;
ip4_config = (NMSettingIP4Config *) nm_connection_get_setting (NM_CONNECTION (exported), NM_TYPE_SETTING_IP4_CONFIG);
if (!ip4_config)
continue;
if (nm_setting_ip4_config_get_num_addresses (ip4_config)) {
/* suse only has one address per device */
NMIP4Address *ip4_address;
ip4_address = nm_setting_ip4_config_get_address (ip4_config, 0);
if (nm_ip4_address_get_gateway (ip4_address) != priv->default_gw) {
nm_ip4_address_set_gateway (ip4_address, priv->default_gw);
nm_settings_connection_interface_update (NM_SETTINGS_CONNECTION_INTERFACE (exported),
ignore_cb,
NULL);
}
}
}
}
static void
routes_changed (GFileMonitor *monitor,
file_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer user_data)
{
SCPluginIfcfg *self = SC_PLUGIN_IFCFG (user_data);
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
char *filename;
guint32 new_gw;
FileMonitorInfo *info;
switch (event_type) {
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
case G_FILE_MONITOR_EVENT_DELETED:
filename = g_file_get_path (file);
new_gw = parser_parse_routes (filename);
g_free (filename);
if (priv->default_gw != new_gw) {
priv->default_gw = new_gw;
update_connections (self);
}
info = (FileMonitorInfo *) user_data;
info->callback (info->user_data);
break;
default:
break;
}
}
static void
monitor_routes (SCPluginIfcfg *self, const char *filename)
static GFileMonitor *
monitor_file_changes (const char *filename,
FileChangedFn callback,
gpointer user_data)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
GFile *file;
GFileMonitor *monitor;
FileMonitorInfo *info;
file = g_file_new_for_path (filename);
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (monitor) {
priv->default_gw_monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (routes_changed), self);
priv->default_gw_monitor = monitor;
}
info = g_new0 (FileMonitorInfo, 1);
info->callback = callback;
info->user_data = user_data;
g_object_weak_ref (G_OBJECT (monitor), (GWeakNotify) g_free, info);
g_signal_connect (monitor, "changed", G_CALLBACK (file_changed), info);
}
static void
read_connection (SCPluginIfcfg *self, GUdevDevice *device, NMDeviceType dev_type)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
const char *iface, *address;
guint32 ifindex;
iface = g_udev_device_get_name (device);
if (!iface)
return;
ifindex = (guint32) g_udev_device_get_property_as_uint64 (device, "IFINDEX");
if (parser_ignore_device (iface)) {
char *spec;
address = g_udev_device_get_sysfs_attr (device, "address");
if (address && (strlen (address) == 17)) {
spec = g_strdup_printf ("mac:%s", address);
g_hash_table_insert (priv->unmanaged_specs, GUINT_TO_POINTER (ifindex), spec);
g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
} else
PLUGIN_WARN (IFCFG_PLUGIN_NAME, " (%s) error getting hardware address", iface);
} else {
NMSuseConnection *connection;
connection = nm_suse_connection_new (iface, dev_type);
if (connection) {
g_hash_table_insert (priv->connections,
GUINT_TO_POINTER (ifindex),
connection);
g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection);
}
}
}
static void
read_connections_by_type (SCPluginIfcfg *self, NMDeviceType dev_type)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
GList *devices, *iter;
if ( (dev_type != NM_DEVICE_TYPE_ETHERNET)
&& (dev_type != NM_DEVICE_TYPE_WIFI))
return;
devices = g_udev_client_query_by_subsystem (priv->client, "net");
for (iter = devices; iter; iter = g_list_next (iter)) {
read_connection (self, G_UDEV_DEVICE (iter->data), dev_type);
g_object_unref (G_UDEV_DEVICE (iter->data));
}
g_list_free (devices);
return monitor;
}
static gboolean
is_wireless (GUdevDevice *device)
hostname_is_dynamic (void)
{
char phy80211_path[255];
struct stat s;
int fd;
struct iwreq iwr;
const char *ifname, *path;
gboolean is_wifi = FALSE;
GIOChannel *channel;
const char *pattern = "DHCLIENT_SET_HOSTNAME=";
char *str = NULL;
int pattern_len;
gboolean dynamic = FALSE;
ifname = g_udev_device_get_name (device);
g_assert (ifname);
channel = g_io_channel_new_file (CONF_DHCP, "r", NULL);
if (!channel)
return dynamic;
fd = socket (PF_INET, SOCK_DGRAM, 0);
strncpy (iwr.ifr_ifrn.ifrn_name, ifname, IFNAMSIZ);
pattern_len = strlen (pattern);
path = g_udev_device_get_sysfs_path (device);
snprintf (phy80211_path, sizeof (phy80211_path), "%s/phy80211", path);
while (g_io_channel_read_line (channel, &str, NULL, NULL, NULL) != G_IO_STATUS_EOF) {
if (!strncmp (str, pattern, pattern_len)) {
if (!strncmp (str + pattern_len, "\"yes\"", 5))
dynamic = TRUE;
break;
}
g_free (str);
}
if ( (ioctl (fd, SIOCGIWNAME, &iwr) == 0)
|| (stat (phy80211_path, &s) == 0 && (s.st_mode & S_IFDIR)))
is_wifi = TRUE;
g_io_channel_shutdown (channel, FALSE, NULL);
g_io_channel_unref (channel);
close (fd);
return is_wifi;
return dynamic;
}
static char *
hostname_read ()
{
GIOChannel *channel;
char *hostname = NULL;
channel = g_io_channel_new_file (HOSTNAME_FILE, "r", NULL);
if (channel) {
g_io_channel_read_line (channel, &hostname, NULL, NULL, NULL);
g_io_channel_shutdown (channel, FALSE, NULL);
g_io_channel_unref (channel);
if (hostname)
hostname = g_strchomp (hostname);
}
return hostname;
}
static void
handle_uevent (GUdevClient *client,
const char *action,
GUdevDevice *device,
gpointer user_data)
hostname_changed (gpointer data)
{
SCPluginIfcfg *self = SC_PLUGIN_IFCFG (user_data);
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
const char *subsys;
gboolean wifi;
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (data);
g_return_if_fail (action != NULL);
g_free (priv->hostname);
if (hostname_is_dynamic ())
priv->hostname = NULL;
else
priv->hostname = hostname_read ();
/* A bit paranoid */
subsys = g_udev_device_get_subsystem (device);
g_return_if_fail (subsys != NULL);
g_return_if_fail (strcmp (subsys, "net") == 0);
wifi = is_wireless (device);
if (!strcmp (action, "add")) {
read_connection (self,
device,
wifi ? NM_DEVICE_TYPE_WIFI : NM_DEVICE_TYPE_ETHERNET);
} else if (!strcmp (action, "remove")) {
NMExportedConnection *exported;
guint32 ifindex;
ifindex = (guint32) g_udev_device_get_property_as_uint64 (device, "IFINDEX");
if (g_hash_table_remove (priv->unmanaged_specs, GUINT_TO_POINTER (ifindex)))
g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
exported = (NMExportedConnection *) g_hash_table_lookup (priv->connections,
GUINT_TO_POINTER (ifindex));
if (exported) {
nm_settings_connection_interface_delete (NM_SETTINGS_CONNECTION_INTERFACE (exported),
ignore_cb,
NULL);
g_hash_table_remove (priv->connections, GUINT_TO_POINTER (ifindex));
g_object_notify (G_OBJECT (data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
}
static void
plugin_set_hostname (SCPluginIfcfg *plugin, const char *hostname)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
GIOChannel *channel;
channel = g_io_channel_new_file (HOSTNAME_FILE, "w", NULL);
if (channel) {
g_io_channel_write_chars (channel, hostname, -1, NULL, NULL);
g_io_channel_write_chars (channel, "\n", -1, NULL, NULL);
g_io_channel_shutdown (channel, TRUE, NULL);
g_io_channel_unref (channel);
}
g_free (priv->hostname);
priv->hostname = hostname ? g_strdup (hostname) : NULL;
}
static void
init (NMSystemConfigInterface *config)
{
SCPluginIfcfg *self = SC_PLUGIN_IFCFG (config);
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
const char *subsys[2] = { "net", NULL };
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config);
priv->client = g_udev_client_new (subsys);
if (!priv->client) {
PLUGIN_WARN (IFCFG_PLUGIN_NAME, " error initializing libgudev");
} else
g_signal_connect (priv->client, "uevent", G_CALLBACK (handle_uevent), self);
}
priv->hostname_monitor = monitor_file_changes (HOSTNAME_FILE, hostname_changed, config);
priv->dhcp_monitor = monitor_file_changes (CONF_DHCP, hostname_changed, config);
static GSList *
get_connections (NMSystemConfigInterface *config)
{
SCPluginIfcfg *self = SC_PLUGIN_IFCFG (config);
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
GSList *list = NULL;
GHashTableIter iter;
gpointer value;
if (!priv->initialized) {
const char *filename;
read_connections_by_type (self, NM_DEVICE_TYPE_ETHERNET);
read_connections_by_type (self, NM_DEVICE_TYPE_WIFI);
filename = SYSCONFDIR"/sysconfig/network/routes";
monitor_routes (self, filename);
priv->default_gw = parser_parse_routes (filename);
if (priv->default_gw)
update_connections (self);
priv->initialized = TRUE;
}
g_hash_table_iter_init (&iter, priv->connections);
while (g_hash_table_iter_next (&iter, NULL, &value))
list = g_slist_prepend (list, value);
return list;
}
static void
add_one_unmanaged_spec (gpointer key, gpointer val, gpointer user_data)
{
GSList **list = (GSList **) key;
*list = g_slist_prepend (*list, g_strdup ((const char *) val));
}
static GSList *
get_unmanaged_specs (NMSystemConfigInterface *config)
{
SCPluginIfcfg *self = SC_PLUGIN_IFCFG (config);
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
GSList *list = NULL;
g_hash_table_foreach (priv->unmanaged_specs, add_one_unmanaged_spec, &list);
return list;
if (!hostname_is_dynamic ())
priv->hostname = hostname_read ();
}
static void
sc_plugin_ifcfg_init (SCPluginIfcfg *self)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
priv->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
priv->unmanaged_specs = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
}
static void
@@ -371,19 +220,13 @@ dispose (GObject *object)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (object);
g_hash_table_destroy (priv->connections);
g_hash_table_destroy (priv->unmanaged_specs);
if (priv->dhcp_monitor)
g_object_unref (priv->dhcp_monitor);
if (priv->default_gw_monitor) {
if (priv->default_gw_monitor_id)
g_signal_handler_disconnect (priv->default_gw_monitor, priv->default_gw_monitor_id);
if (priv->hostname_monitor)
g_object_unref (priv->hostname_monitor);
g_file_monitor_cancel (priv->default_gw_monitor);
g_object_unref (priv->default_gw_monitor);
}
if (priv->client)
g_object_unref (priv->client);
g_free (priv->hostname);
G_OBJECT_CLASS (sc_plugin_ifcfg_parent_class)->dispose (object);
}
@@ -400,10 +243,29 @@ get_property (GObject *object, guint prop_id,
g_value_set_string (value, IFCFG_PLUGIN_INFO);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES:
g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE);
g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
g_value_set_string (value, "");
g_value_set_string (value, SC_PLUGIN_IFCFG_GET_PRIVATE (object)->hostname);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
const char *hostname;
switch (prop_id) {
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
hostname = g_value_get_string (value);
if (hostname && strlen (hostname) < 1)
hostname = NULL;
plugin_set_hostname (SC_PLUGIN_IFCFG (object), hostname);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -419,6 +281,7 @@ sc_plugin_ifcfg_class_init (SCPluginIfcfgClass *req_class)
g_type_class_add_private (req_class, sizeof (SCPluginIfcfgPrivate));
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->dispose = dispose;
g_object_class_override_property (object_class,
@@ -442,8 +305,6 @@ 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->get_unmanaged_specs = get_unmanaged_specs;
system_config_interface_class->init = init;
}

View File

@@ -24,7 +24,7 @@
#include <glib-object.h>
#define PLUGIN_NAME "ifcfg"
#define PLUGIN_NAME "ifcfg-suse"
#define SC_TYPE_PLUGIN_IFCFG (sc_plugin_ifcfg_get_type ())
#define SC_PLUGIN_IFCFG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfg))

View File

@@ -1,403 +0,0 @@
/*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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;
if (i == 0)
s[0] = '\0';
else {
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_foreach (s->lineList, (GFunc) g_free, NULL);
g_list_free(s->lineList); /* implicitly frees s->current */
g_free(s);
return 0;
}

View File

@@ -1,103 +0,0 @@
/*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 */