mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-07-23 19:24:38 +00:00
2008-02-28 Tambet Ingo <tambet@gmail.com>
Implement suse plugin for system settings daemon. * system-settings/plugins/ifcfg-suse/*: Implement. * system-settings/plugins/Makefile.am: Add ifcfg-suse to subdirs when targeting suse. * configure.in: Check (without failing) for gio. Create ifcfg-suse plugin's Makefile. git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@3355 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
parent
f37e10a2bc
commit
fd6f0fa08f
64
ChangeLog
64
ChangeLog
|
@ -1,64 +1,14 @@
|
|||
2008-02-27 Saleem Abdulrasool <compnerd@compnerd.org>
|
||||
2008-02-28 Tambet Ingo <tambet@gmail.com>
|
||||
|
||||
reviewed by: steev@steev.net
|
||||
Implement suse plugin for system settings daemon.
|
||||
|
||||
* initscript/Gentoo/NetworkManager.in:
|
||||
* initscript/Gentoo/NetworkManagerDispatcher.in:
|
||||
Update the scripts and move them to Gentoo style.
|
||||
* system-settings/plugins/ifcfg-suse/*: Implement.
|
||||
|
||||
2008-02-27 Dan Williams <dcbw@redhat.com>
|
||||
* system-settings/plugins/Makefile.am: Add ifcfg-suse to subdirs when targeting
|
||||
suse.
|
||||
|
||||
Patch from Will Stephenson <wstephenson@kde.org>
|
||||
|
||||
* Makefile.am
|
||||
configure.in
|
||||
- Set up spec autogeneration infrastructure
|
||||
|
||||
* docs/NetworkManager DBUS API.txt
|
||||
- Note how old this doc is and where to look for the canonical
|
||||
D-Bus specification
|
||||
|
||||
* introspection/*
|
||||
- Add annotations and comments
|
||||
|
||||
2008-02-27 Dan Williams <dcbw@redhat.com>
|
||||
|
||||
* src/nm-device-802-11-wireless.c
|
||||
- (device_cleanup): cleanup any association attempt that might be in
|
||||
progress
|
||||
- (nm_device_802_11_wireless_dispose): device_cleanup() already
|
||||
destroys the AP list
|
||||
|
||||
2008-02-25 Dan Williams <dcbw@redhat.com>
|
||||
|
||||
* libnm-glib/nm-settings.c
|
||||
- (set_property): use g_value_dup_object() to ref the object as was
|
||||
intended originally
|
||||
|
||||
2008-02-25 Dan Williams <dcbw@redhat.com>
|
||||
|
||||
* libnm-util/nm-utils.c
|
||||
- (nm_utils_ssid_to_utf8): use a dynamically allocated buffer
|
||||
|
||||
2008-02-25 Dan Williams <dcbw@redhat.com>
|
||||
|
||||
* libnm-util/nm-setting.c
|
||||
- (nm_setting_compare): Fix C&P error from r3068 that caused settings
|
||||
comparisons to always succeed; clarify assignment of values to
|
||||
'different'
|
||||
|
||||
2008-02-24 Dan Williams <dcbw@redhat.com>
|
||||
|
||||
* libnm-util/nm-setting.c
|
||||
libnm-util/nm-setting.h
|
||||
- (nm_setting_compare): fix 'fuzzy' compare logic; add IGNORE_ID bits;
|
||||
fix return value to match nm_connection_compare() meaning
|
||||
|
||||
2008-02-24 Dan Williams <dcbw@redhat.com>
|
||||
|
||||
* libnm-util/nm-setting-wireless.c
|
||||
- (nm_setting_wireless_class_init): 'seen bssids' should be ignored for
|
||||
fuzzy matches
|
||||
* configure.in: Check (without failing) for gio.
|
||||
Create ifcfg-suse plugin's Makefile.
|
||||
|
||||
2008-02-20 Dan Williams <dcbw@redhat.com>
|
||||
|
||||
|
|
23
configure.in
23
configure.in
|
@ -52,18 +52,6 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package])
|
|||
IT_PROG_INTLTOOL([0.35.0])
|
||||
AM_GLIB_GNU_GETTEXT
|
||||
|
||||
dnl
|
||||
dnl GNOME support
|
||||
dnl
|
||||
AC_ARG_WITH(docs, AC_HELP_STRING([--with-docs], [Build NetworkManager documentation]))
|
||||
AM_CONDITIONAL(WITH_DOCS, test "x$with_docs" = "xyes")
|
||||
case $with_docs in
|
||||
yes) ;;
|
||||
*)
|
||||
with_docs=no
|
||||
;;
|
||||
esac
|
||||
|
||||
dnl
|
||||
dnl Make sha1.c happy on big endian systems
|
||||
dnl
|
||||
|
@ -195,6 +183,11 @@ PKG_CHECK_MODULES(GOBJECT, gobject-2.0)
|
|||
AC_SUBST(GOBJECT_CFLAGS)
|
||||
AC_SUBST(GOBJECT_LIBS)
|
||||
|
||||
# This is optional, at least for now.
|
||||
PKG_CHECK_MODULES(GIO, gio-2.0,,true)
|
||||
AC_SUBST(GIO_CFLAGS)
|
||||
AC_SUBST(GIO_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES(HAL, hal >= 0.5.0)
|
||||
AC_SUBST(HAL_CFLAGS)
|
||||
AC_SUBST(HAL_LIBS)
|
||||
|
@ -290,6 +283,7 @@ system-settings/Makefile
|
|||
system-settings/src/Makefile
|
||||
system-settings/plugins/Makefile
|
||||
system-settings/plugins/ifcfg-fedora/Makefile
|
||||
system-settings/plugins/ifcfg-suse/Makefile
|
||||
test/Makefile
|
||||
test/test-common/Makefile
|
||||
initscript/Makefile
|
||||
|
@ -325,8 +319,3 @@ AC_OUTPUT
|
|||
echo
|
||||
echo Distribution targeting: ${with_distro}
|
||||
echo 'if this is not correct, please specifiy your distro with --with-distro=DISTRO'
|
||||
|
||||
echo
|
||||
echo Building documentation: ${with_docs}
|
||||
echo
|
||||
|
||||
|
|
|
@ -1,2 +1,7 @@
|
|||
if TARGET_REDHAT
|
||||
SUBDIRS=ifcfg-fedora
|
||||
endif
|
||||
|
||||
if TARGET_SUSE
|
||||
SUBDIRS=ifcfg-suse
|
||||
endif
|
||||
|
|
28
system-settings/plugins/ifcfg-suse/Makefile.am
Normal file
28
system-settings/plugins/ifcfg-suse/Makefile.am
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
pkglib_LTLIBRARIES = libnm-settings-plugin-ifcfg-suse.la
|
||||
|
||||
libnm_settings_plugin_ifcfg_suse_la_SOURCES = \
|
||||
shvar.c \
|
||||
shvar.h \
|
||||
parser.c \
|
||||
parser.h \
|
||||
plugin.c \
|
||||
plugin.h
|
||||
|
||||
libnm_settings_plugin_ifcfg_suse_la_CPPFLAGS = \
|
||||
$(GLIB_CFLAGS) \
|
||||
$(GMODULE_CFLAGS) \
|
||||
$(DBUS_CFLAGS) \
|
||||
-DG_DISABLE_DEPRECATED \
|
||||
-I${top_srcdir}/system-settings/src \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_srcdir)/libnm-util \
|
||||
-DSYSCONFDIR=\"$(sysconfdir)\"
|
||||
|
||||
libnm_settings_plugin_ifcfg_suse_la_LDFLAGS = -module -avoid-version
|
||||
libnm_settings_plugin_ifcfg_suse_la_LIBADD = \
|
||||
$(GLIB_LIBS) \
|
||||
$(GMODULE_LIBS) \
|
||||
$(GIO_LIBS) \
|
||||
$(top_builddir)/libnm-util/libnm-util.la
|
||||
|
798
system-settings/plugins/ifcfg-suse/parser.c
Normal file
798
system-settings/plugins/ifcfg-suse/parser.c
Normal file
|
@ -0,0 +1,798 @@
|
|||
/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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-utils.h>
|
||||
|
||||
#include "shvar.h"
|
||||
#include "parser.h"
|
||||
#include "plugin.h"
|
||||
|
||||
|
||||
static gboolean
|
||||
get_int (const char *str, int *value)
|
||||
{
|
||||
char *e;
|
||||
|
||||
*value = strtol (str, &e, 0);
|
||||
if (*e != '\0')
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static gboolean
|
||||
read_startmode (shvarFile *file)
|
||||
{
|
||||
char *value;
|
||||
gboolean automatic = TRUE;
|
||||
|
||||
value = svGetValue (file, "STARTMODE");
|
||||
if (value) {
|
||||
if (!g_ascii_strcasecmp (value, "manual"))
|
||||
automatic = FALSE;
|
||||
else if (!g_ascii_strcasecmp (value, "off")) {
|
||||
// FIXME: actually ignore the device, not the connection
|
||||
g_message ("Ignoring connection '%s' because NM_CONTROLLED was false", file);
|
||||
automatic = FALSE;
|
||||
}
|
||||
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
return automatic;
|
||||
}
|
||||
#endif
|
||||
|
||||
static NMSetting *
|
||||
make_connection_setting (const char *file,
|
||||
shvarFile *ifcfg,
|
||||
const char *type,
|
||||
const char *suggested)
|
||||
{
|
||||
NMSettingConnection *s_con;
|
||||
char *basename = NULL;
|
||||
int len;
|
||||
char *ifcfg_name;
|
||||
|
||||
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 ());
|
||||
|
||||
ifcfg_name = (char *) (basename + strlen (IFCFG_TAG));
|
||||
|
||||
if (suggested) {
|
||||
/* For cosmetic reasons, if the suggested name is the same as
|
||||
* the ifcfg files name, don't use it.
|
||||
*/
|
||||
if (strcmp (ifcfg_name, suggested)) {
|
||||
s_con->id = g_strdup_printf ("System %s (%s)", suggested, ifcfg_name);
|
||||
ifcfg_name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ifcfg_name)
|
||||
s_con->id = g_strdup_printf ("System %s", ifcfg_name);
|
||||
|
||||
s_con->type = g_strdup (type);
|
||||
s_con->autoconnect = TRUE;
|
||||
|
||||
return (NMSetting *) s_con;
|
||||
|
||||
error:
|
||||
g_free (basename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static guint32
|
||||
ip4_prefix_to_netmask (int prefix)
|
||||
{
|
||||
guint32 msk = 0x80000000;
|
||||
guint32 netmask = 0;
|
||||
|
||||
while (prefix > 0) {
|
||||
netmask |= msk;
|
||||
msk >>= 1;
|
||||
prefix--;
|
||||
}
|
||||
|
||||
return htonl (netmask);
|
||||
}
|
||||
|
||||
static NMSetting *
|
||||
make_ip4_setting (shvarFile *ifcfg, GError **error)
|
||||
{
|
||||
NMSettingIP4Config *s_ip4 = NULL;
|
||||
char *value = NULL;
|
||||
NMSettingIP4Address tmp = { 0, 0, 0 };
|
||||
gboolean manual = TRUE;
|
||||
|
||||
value = svGetValue (ifcfg, "BOOTPROTO");
|
||||
if (!value)
|
||||
return NULL;
|
||||
|
||||
if (!g_ascii_strcasecmp (value, "bootp") || !g_ascii_strcasecmp (value, "dhcp")) {
|
||||
manual = FALSE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
value = svGetValue (ifcfg, "IPADDR");
|
||||
if (value) {
|
||||
char **pieces;
|
||||
struct in_addr ip4_addr;
|
||||
|
||||
pieces = g_strsplit (value, "/", 2);
|
||||
|
||||
if (inet_pton (AF_INET, pieces[0], &ip4_addr))
|
||||
tmp.address = ip4_addr.s_addr;
|
||||
else {
|
||||
g_strfreev (pieces);
|
||||
g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid IP4 address '%s'", value);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (g_strv_length (pieces) == 2)
|
||||
tmp.netmask = ip4_prefix_to_netmask (atoi (pieces[1]));
|
||||
|
||||
g_strfreev (pieces);
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
if (tmp.netmask == 0) {
|
||||
value = svGetValue (ifcfg, "PREFIXLEN");
|
||||
if (value) {
|
||||
tmp.netmask = ip4_prefix_to_netmask (atoi (value));
|
||||
g_free (value);
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp.netmask == 0) {
|
||||
value = svGetValue (ifcfg, "NETMASK");
|
||||
if (value) {
|
||||
struct in_addr mask_addr;
|
||||
|
||||
if (inet_pton (AF_INET, value, &mask_addr))
|
||||
tmp.netmask = mask_addr.s_addr;
|
||||
else {
|
||||
g_set_error (error, ifcfg_plugin_error_quark (), 0, "Invalid IP4 netmask '%s'", value);
|
||||
goto error;
|
||||
}
|
||||
g_free (value);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return NM_SETTING (s_ip4);
|
||||
|
||||
error:
|
||||
g_free (value);
|
||||
if (s_ip4)
|
||||
g_object_unref (s_ip4);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* utils_bin2hexstr
|
||||
*
|
||||
* Convert a byte-array into a hexadecimal string.
|
||||
*
|
||||
* Code originally by Alex Larsson <alexl@redhat.com> and
|
||||
* copyright Red Hat, Inc. under terms of the LGPL.
|
||||
*
|
||||
*/
|
||||
static char *
|
||||
utils_bin2hexstr (const char *bytes, int len, int final_len)
|
||||
{
|
||||
static char hex_digits[] = "0123456789abcdef";
|
||||
char * result;
|
||||
int i;
|
||||
|
||||
g_return_val_if_fail (bytes != NULL, NULL);
|
||||
g_return_val_if_fail (len > 0, NULL);
|
||||
g_return_val_if_fail (len < 256, NULL); /* Arbitrary limit */
|
||||
|
||||
result = g_malloc0 (len * 2 + 1);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
result[2*i] = hex_digits[(bytes[i] >> 4) & 0xf];
|
||||
result[2*i+1] = hex_digits[bytes[i] & 0xf];
|
||||
}
|
||||
/* Cut converted key off at the correct length for this cipher type */
|
||||
if (final_len > -1)
|
||||
result[final_len] = '\0';
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
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_data_full (G_OBJECT (security), \
|
||||
NM_SETTING_WIRELESS_SECURITY_WEP_KEY##idx, \
|
||||
key, \
|
||||
g_free); \
|
||||
have_key = TRUE; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
read_wep_settings (shvarFile *ifcfg, NMSettingWirelessSecurity *security, GError **err)
|
||||
{
|
||||
char *value;
|
||||
gboolean have_key = FALSE;
|
||||
|
||||
READ_WEP_KEY(0)
|
||||
READ_WEP_KEY(1)
|
||||
READ_WEP_KEY(2)
|
||||
READ_WEP_KEY(3)
|
||||
|
||||
if (have_key)
|
||||
security->key_mgmt = g_strdup ("none");
|
||||
|
||||
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))
|
||||
security->wep_tx_keyidx = key_idx;
|
||||
else
|
||||
g_set_error (err, ifcfg_plugin_error_quark (), 0, "Invalid defualt WEP key '%s'", value);
|
||||
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
error:
|
||||
return;
|
||||
}
|
||||
|
||||
/* Copied from applet/src/wireless-secuirty/wireless-security.c */
|
||||
static void
|
||||
ws_wpa_fill_default_ciphers (NMSettingWirelessSecurity *s_wireless_sec)
|
||||
{
|
||||
// FIXME: allow protocol selection and filter on device capabilities
|
||||
s_wireless_sec->proto = g_slist_append (s_wireless_sec->proto, g_strdup ("wpa"));
|
||||
s_wireless_sec->proto = g_slist_append (s_wireless_sec->proto, g_strdup ("rsn"));
|
||||
|
||||
// FIXME: allow pairwise cipher selection and filter on device capabilities
|
||||
s_wireless_sec->pairwise = g_slist_append (s_wireless_sec->pairwise, g_strdup ("tkip"));
|
||||
s_wireless_sec->pairwise = g_slist_append (s_wireless_sec->pairwise, g_strdup ("ccmp"));
|
||||
|
||||
// FIXME: allow group cipher selection and filter on device capabilities
|
||||
s_wireless_sec->group = g_slist_append (s_wireless_sec->group, g_strdup ("wep40"));
|
||||
s_wireless_sec->group = g_slist_append (s_wireless_sec->group, g_strdup ("wep104"));
|
||||
s_wireless_sec->group = g_slist_append (s_wireless_sec->group, g_strdup ("tkip"));
|
||||
s_wireless_sec->group = g_slist_append (s_wireless_sec->group, g_strdup ("ccmp"));
|
||||
}
|
||||
|
||||
static void
|
||||
read_wpa_psk_settings (shvarFile *ifcfg, NMSettingWirelessSecurity *security, GError **err)
|
||||
{
|
||||
char *value;
|
||||
|
||||
value = svGetValue (ifcfg, "WIRELESS_WPA_PSK");
|
||||
if (value) {
|
||||
if (strlen (value) == 64) {
|
||||
/* HEX key */
|
||||
security->psk = value;
|
||||
} else {
|
||||
/* passphrase */
|
||||
|
||||
/* FIXME: */
|
||||
/* unsigned char *buf = g_malloc0 (WPA_PMK_LEN * 2); */
|
||||
/* pbkdf2_sha1 (value, (char *) s_wireless->ssid->data, s_wireless->ssid->len, 4096, buf, WPA_PMK_LEN); */
|
||||
/* security->psk = utils_bin2hexstr ((const char *) buf, WPA_PMK_LEN, WPA_PMK_LEN * 2); */
|
||||
/* g_free (buf); */
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
ws_wpa_fill_default_ciphers (security);
|
||||
} else
|
||||
g_set_error (err, ifcfg_plugin_error_quark (), 0, "Missing WPA-PSK key.");
|
||||
}
|
||||
|
||||
static void
|
||||
read_wpa_eap_settings (shvarFile *ifcfg, NMSettingWirelessSecurity *security, GError **err)
|
||||
{
|
||||
char *value;
|
||||
|
||||
value = svGetValue (ifcfg, "WIRELESS_EAP_AUTH");
|
||||
if (value) {
|
||||
/* valid values are TLS PEAP TTLS */
|
||||
security->eap = g_slist_append (NULL, value);
|
||||
}
|
||||
|
||||
value = svGetValue (ifcfg, "WIRELESS_WPA_PROTO");
|
||||
if (value) {
|
||||
/* valid values are WPA RSN (WPA2) */
|
||||
security->proto = g_slist_append (NULL, value);
|
||||
}
|
||||
|
||||
security->identity = svGetValue (ifcfg, "WIRELESS_WPA_IDENTITY");
|
||||
|
||||
/* FIXME: This should be in get_secrets? */
|
||||
value = svGetValue (ifcfg, "WIRELESS_WPA_PASSWORD");
|
||||
if (value) {
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
security->anonymous_identity = svGetValue (ifcfg, "WIRELESS_WPA_ANONID");
|
||||
|
||||
value = svGetValue (ifcfg, "WIRELESS_CA_CERT");
|
||||
if (value) {
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
value = svGetValue (ifcfg, "WIRELESS_CLIENT_CERT");
|
||||
if (value) {
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
/* FIXME: This should be in get_secrets? */
|
||||
value = svGetValue (ifcfg, "WIRELESS_CLIENT_KEY");
|
||||
if (value) {
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
/* FIXME: This should be in get_secrets? */
|
||||
value = svGetValue (ifcfg, "WIRELESS_CLIENT_KEY_PASSWORD");
|
||||
if (value) {
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
ws_wpa_fill_default_ciphers (security);
|
||||
}
|
||||
|
||||
static NMSetting *
|
||||
make_wireless_security_setting (shvarFile *ifcfg, GError **err)
|
||||
{
|
||||
NMSettingWirelessSecurity *s_wireless_sec = NULL;
|
||||
char *value;
|
||||
|
||||
value = svGetValue (ifcfg, "WIRELESS_AUTH_MODE");
|
||||
if (!value)
|
||||
return NULL;
|
||||
|
||||
if (!g_ascii_strcasecmp (value, "no-encryption")) {
|
||||
g_free (value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s_wireless_sec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
|
||||
|
||||
if (!g_ascii_strcasecmp (value, "open")) {
|
||||
s_wireless_sec->auth_alg = g_strdup ("open");
|
||||
read_wep_settings (ifcfg, s_wireless_sec, err);
|
||||
} else if (!g_ascii_strcasecmp (value, "sharedkey")) {
|
||||
s_wireless_sec->auth_alg = g_strdup ("shared");
|
||||
read_wep_settings (ifcfg, s_wireless_sec, err);
|
||||
}
|
||||
|
||||
else if (!g_ascii_strcasecmp (value, "psk")) {
|
||||
s_wireless_sec->key_mgmt = g_strdup ("wpa-psk");
|
||||
read_wpa_psk_settings (ifcfg, s_wireless_sec, err);
|
||||
} else if (!g_ascii_strcasecmp (value, "eap")) {
|
||||
s_wireless_sec->key_mgmt = g_strdup ("wps-eap");
|
||||
read_wpa_eap_settings (ifcfg, s_wireless_sec, err);
|
||||
} else
|
||||
g_set_error (err, ifcfg_plugin_error_quark (), 0, "Invalid authentication algoritm '%s'", value);
|
||||
|
||||
g_free (value);
|
||||
|
||||
if (*err == NULL)
|
||||
return NM_SETTING (s_wireless_sec);
|
||||
|
||||
if (s_wireless_sec)
|
||||
g_object_unref (s_wireless_sec);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static NMSetting *
|
||||
make_wireless_setting (shvarFile *ifcfg,
|
||||
NMSetting *security,
|
||||
GError **err)
|
||||
{
|
||||
NMSettingWireless *s_wireless;
|
||||
char *value;
|
||||
|
||||
s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
|
||||
|
||||
value = svGetValue (ifcfg, "WIRELESS_ESSID");
|
||||
if (value) {
|
||||
gsize len = strlen (value);
|
||||
|
||||
if (len > 32 || len == 0) {
|
||||
g_set_error (err, ifcfg_plugin_error_quark (), 0,
|
||||
"Invalid SSID '%s' (size %zu not between 1 and 32 inclusive)",
|
||||
value, len);
|
||||
goto error;
|
||||
}
|
||||
|
||||
s_wireless->ssid = g_byte_array_sized_new (strlen (value));
|
||||
g_byte_array_append (s_wireless->ssid, (const guint8 *) value, len);
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
value = svGetValue (ifcfg, "WIRLESS_MODE");
|
||||
if (value) {
|
||||
if (!g_ascii_strcasecmp (value, "ad-hoc")) {
|
||||
s_wireless->mode = g_strdup ("adhoc");
|
||||
} else if (!g_ascii_strcasecmp (value, "managed")) {
|
||||
s_wireless->mode = g_strdup ("infrastructure");
|
||||
} else {
|
||||
g_set_error (err, ifcfg_plugin_error_quark (), 0,
|
||||
"Invalid mode '%s' (not ad-hoc or managed)", value);
|
||||
g_free (value);
|
||||
goto error;
|
||||
}
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
if (security)
|
||||
s_wireless->security = g_strdup (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME);
|
||||
|
||||
// FIXME: channel/freq, other L2 parameters like RTS
|
||||
|
||||
return NM_SETTING (s_wireless);
|
||||
|
||||
error:
|
||||
if (s_wireless)
|
||||
g_object_unref (s_wireless);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static NMConnection *
|
||||
wireless_connection_from_ifcfg (const char *file, shvarFile *ifcfg, GError **err)
|
||||
{
|
||||
NMConnection *connection = NULL;
|
||||
NMSetting *con_setting = NULL;
|
||||
NMSetting *wireless_setting = NULL;
|
||||
NMSettingWireless *tmp;
|
||||
NMSetting *security_setting = NULL;
|
||||
char *printable_ssid = NULL;
|
||||
|
||||
connection = nm_connection_new ();
|
||||
if (!connection) {
|
||||
g_set_error (err, ifcfg_plugin_error_quark (), 0,
|
||||
"Failed to allocate new connection for %s.", file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Wireless security */
|
||||
security_setting = make_wireless_security_setting (ifcfg, err);
|
||||
if (*err)
|
||||
goto error;
|
||||
if (security_setting)
|
||||
nm_connection_add_setting (connection, security_setting);
|
||||
|
||||
/* Wireless */
|
||||
wireless_setting = make_wireless_setting (ifcfg, security_setting, err);
|
||||
if (!wireless_setting)
|
||||
goto error;
|
||||
|
||||
nm_connection_add_setting (connection, wireless_setting);
|
||||
|
||||
tmp = NM_SETTING_WIRELESS (wireless_setting);
|
||||
printable_ssid = nm_utils_ssid_to_utf8 ((const char *) tmp->ssid->data,
|
||||
(guint32) tmp->ssid->len);
|
||||
|
||||
con_setting = make_connection_setting (file, ifcfg,
|
||||
NM_SETTING_WIRELESS_SETTING_NAME,
|
||||
printable_ssid);
|
||||
g_free (printable_ssid);
|
||||
|
||||
if (!con_setting) {
|
||||
g_set_error (err, ifcfg_plugin_error_quark (), 0,
|
||||
"Failed to create connection setting.");
|
||||
goto error;
|
||||
}
|
||||
nm_connection_add_setting (connection, con_setting);
|
||||
|
||||
if (!nm_connection_verify (connection)) {
|
||||
g_set_error (err, ifcfg_plugin_error_quark (), 0,
|
||||
"Connection from %s was invalid.", file);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return connection;
|
||||
|
||||
error:
|
||||
g_object_unref (connection);
|
||||
if (con_setting)
|
||||
g_object_unref (con_setting);
|
||||
if (wireless_setting)
|
||||
g_object_unref (wireless_setting);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static NMSetting *
|
||||
make_wired_setting (shvarFile *ifcfg, GError **err)
|
||||
{
|
||||
NMSettingWired *s_wired;
|
||||
char *value;
|
||||
int mtu;
|
||||
|
||||
s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
|
||||
|
||||
value = svGetValue (ifcfg, "MTU");
|
||||
if (value) {
|
||||
if (strlen (value) < 1)
|
||||
/* Ignore empty MTU */
|
||||
;
|
||||
else if (get_int (value, &mtu)) {
|
||||
if (mtu >= 0 && mtu < 65536)
|
||||
s_wired->mtu = mtu;
|
||||
} else {
|
||||
g_set_error (err, ifcfg_plugin_error_quark (), 0, "Invalid MTU '%s'", value);
|
||||
g_object_unref (s_wired);
|
||||
s_wired = NULL;
|
||||
}
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
return (NMSetting *) s_wired;
|
||||
}
|
||||
|
||||
static NMConnection *
|
||||
wired_connection_from_ifcfg (const char *file, shvarFile *ifcfg, GError **err)
|
||||
{
|
||||
NMConnection *connection = NULL;
|
||||
NMSetting *con_setting = NULL;
|
||||
NMSetting *wired_setting = NULL;
|
||||
|
||||
connection = nm_connection_new ();
|
||||
con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL);
|
||||
if (!con_setting) {
|
||||
g_set_error (err, ifcfg_plugin_error_quark (), 0,
|
||||
"Failed to create connection setting.");
|
||||
goto error;
|
||||
}
|
||||
nm_connection_add_setting (connection, con_setting);
|
||||
|
||||
wired_setting = make_wired_setting (ifcfg, err);
|
||||
if (!wired_setting)
|
||||
goto error;
|
||||
|
||||
nm_connection_add_setting (connection, wired_setting);
|
||||
|
||||
if (!nm_connection_verify (connection)) {
|
||||
g_set_error (err, ifcfg_plugin_error_quark (), 0,
|
||||
"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;
|
||||
}
|
||||
|
||||
NMConnection *
|
||||
parser_parse_ifcfg (const char *file, GError **err)
|
||||
{
|
||||
NMConnection *connection = NULL;
|
||||
shvarFile *parsed;
|
||||
char *type;
|
||||
char *nmc = NULL;
|
||||
NMSetting *s_ip4;
|
||||
|
||||
g_return_val_if_fail (file != NULL, NULL);
|
||||
|
||||
parsed = svNewFile (file);
|
||||
if (!parsed) {
|
||||
g_set_error (err, ifcfg_plugin_error_quark (), 0,
|
||||
"Couldn't parse file '%s'", file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nmc = svGetValue (parsed, "NM_CONTROLLED");
|
||||
if (nmc) {
|
||||
if (!svTrueValue (parsed, nmc, 1)) {
|
||||
g_free (nmc);
|
||||
// FIXME: actually ignore the device, not the connection
|
||||
g_message ("Ignoring connection '%s' because NM_CONTROLLED was false", file);
|
||||
goto done;
|
||||
}
|
||||
g_free (nmc);
|
||||
}
|
||||
|
||||
type = svGetValue (parsed, "WIRELESS_ESSID");
|
||||
if (type) {
|
||||
g_free (type);
|
||||
connection = wireless_connection_from_ifcfg (file, parsed, err);
|
||||
} else
|
||||
connection = wired_connection_from_ifcfg (file, parsed, err);
|
||||
|
||||
if (!connection)
|
||||
goto done;
|
||||
|
||||
s_ip4 = make_ip4_setting (parsed, err);
|
||||
if (*err) {
|
||||
g_object_unref (connection);
|
||||
connection = NULL;
|
||||
goto done;
|
||||
} else if (s_ip4) {
|
||||
nm_connection_add_setting (connection, s_ip4);
|
||||
}
|
||||
|
||||
if (!nm_connection_verify (connection)) {
|
||||
g_object_unref (connection);
|
||||
connection = NULL;
|
||||
g_set_error (err, ifcfg_plugin_error_quark (), 0,
|
||||
"Connection was invalid");
|
||||
}
|
||||
|
||||
done:
|
||||
svCloseFile (parsed);
|
||||
return connection;
|
||||
}
|
||||
|
||||
guint32
|
||||
parser_parse_routes (const char *file, GError **err)
|
||||
{
|
||||
FILE *f;
|
||||
char *buf;
|
||||
char buffer[512];
|
||||
guint route = 0;
|
||||
|
||||
if ((f = fopen (SYSCONFDIR"/sysconfig/network/routes", "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;
|
||||
}
|
35
system-settings/plugins/ifcfg-suse/parser.h
Normal file
35
system-settings/plugins/ifcfg-suse/parser.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef _PARSER_H_
|
||||
#define _PARSER_H_
|
||||
|
||||
#include <glib.h>
|
||||
#include <nm-connection.h>
|
||||
|
||||
#define IFCFG_TAG "ifcfg-"
|
||||
#define BAK_TAG ".bak"
|
||||
|
||||
NMConnection * parser_parse_ifcfg (const char *file, GError **error);
|
||||
guint32 parser_parse_routes (const char *file, GError **err);
|
||||
|
||||
|
||||
#endif /* _PARSER_H_ */
|
438
system-settings/plugins/ifcfg-suse/plugin.c
Normal file
438
system-settings/plugins/ifcfg-suse/plugin.c
Normal file
|
@ -0,0 +1,438 @@
|
|||
/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* (C) Copyright 2007 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include <gmodule.h>
|
||||
#include <glib-object.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <string.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <unistd.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include <nm-setting-connection.h>
|
||||
#include <nm-setting-ip4-config.h>
|
||||
|
||||
#include "plugin.h"
|
||||
#include "parser.h"
|
||||
#include "nm-system-config-interface.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"
|
||||
|
||||
static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class);
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (SCPluginIfcfg, sc_plugin_ifcfg, G_TYPE_OBJECT, 0,
|
||||
G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE,
|
||||
system_config_interface_init))
|
||||
|
||||
#define SC_PLUGIN_IFCFG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgPrivate))
|
||||
|
||||
|
||||
#define IFCFG_FILE_PATH_TAG "ifcfg-file-path"
|
||||
|
||||
typedef struct {
|
||||
gboolean initialized;
|
||||
GSList *connections;
|
||||
|
||||
GFileMonitor *monitor;
|
||||
guint monitor_id;
|
||||
} SCPluginIfcfgPrivate;
|
||||
|
||||
|
||||
GQuark
|
||||
ifcfg_plugin_error_quark (void)
|
||||
{
|
||||
static GQuark error_quark = 0;
|
||||
|
||||
if (G_UNLIKELY (error_quark == 0))
|
||||
error_quark = g_quark_from_static_string ("ifcfg-plugin-error-quark");
|
||||
|
||||
return error_quark;
|
||||
}
|
||||
|
||||
struct FindInfo {
|
||||
const char *path;
|
||||
gboolean found;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
is_ifcfg_file (const char *file)
|
||||
{
|
||||
return g_str_has_prefix (file, IFCFG_TAG) && strcmp (file, IFCFG_TAG "lo");
|
||||
}
|
||||
|
||||
static NMConnection *
|
||||
build_one_connection (const char *ifcfg_file)
|
||||
{
|
||||
NMConnection *connection;
|
||||
GError *err = NULL;
|
||||
|
||||
PLUGIN_PRINT (PLUGIN_NAME, "parsing %s ... ", ifcfg_file);
|
||||
|
||||
connection = parser_parse_ifcfg (ifcfg_file, &err);
|
||||
if (connection) {
|
||||
NMSettingConnection *s_con;
|
||||
|
||||
s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
|
||||
g_assert (s_con);
|
||||
g_assert (s_con->id);
|
||||
PLUGIN_PRINT (PLUGIN_NAME, " found connection '%s'", s_con->id);
|
||||
} else
|
||||
PLUGIN_PRINT (PLUGIN_NAME, " error: %s", err->message ? err->message : "(unknown)");
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
SCPluginIfcfg *plugin;
|
||||
NMConnection *connection;
|
||||
GFileMonitor *monitor;
|
||||
guint monitor_id;
|
||||
} ConnectionMonitor;
|
||||
|
||||
static void
|
||||
connection_monitor_destroy (gpointer data)
|
||||
{
|
||||
ConnectionMonitor *monitor = (ConnectionMonitor *) data;
|
||||
|
||||
g_signal_handler_disconnect (monitor->monitor, monitor->monitor_id);
|
||||
g_file_monitor_cancel (monitor->monitor);
|
||||
g_object_unref (monitor->monitor);
|
||||
|
||||
g_free (monitor);
|
||||
}
|
||||
|
||||
static void
|
||||
connection_file_changed (GFileMonitor *monitor,
|
||||
GFile *file,
|
||||
GFile *other_file,
|
||||
GFileMonitorEvent event_type,
|
||||
gpointer user_data)
|
||||
{
|
||||
ConnectionMonitor *cm = (ConnectionMonitor *) user_data;
|
||||
gboolean remove_connection = FALSE;
|
||||
|
||||
switch (event_type) {
|
||||
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: {
|
||||
NMConnection *new_connection;
|
||||
GHashTable *new_settings;
|
||||
char *filename;
|
||||
char *ifcfg_file;
|
||||
|
||||
/* In case anything goes wrong */
|
||||
remove_connection = TRUE;
|
||||
|
||||
filename = g_file_get_basename (file);
|
||||
ifcfg_file = g_build_filename (IFCFG_DIR, filename, NULL);
|
||||
g_free (filename);
|
||||
|
||||
new_connection = build_one_connection (ifcfg_file);
|
||||
g_free (ifcfg_file);
|
||||
|
||||
if (new_connection) {
|
||||
new_settings = nm_connection_to_hash (new_connection);
|
||||
if (nm_connection_replace_settings (cm->connection, new_settings)) {
|
||||
/* Nothing went wrong */
|
||||
remove_connection = FALSE;
|
||||
g_signal_emit_by_name (cm->plugin, "connection-updated", cm->connection);
|
||||
}
|
||||
|
||||
g_object_unref (new_connection);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case G_FILE_MONITOR_EVENT_DELETED:
|
||||
remove_connection = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (remove_connection) {
|
||||
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (cm->plugin);
|
||||
|
||||
priv->connections = g_slist_remove (priv->connections, cm->connection);
|
||||
g_signal_emit_by_name (cm->plugin, "connection-removed", cm->connection);
|
||||
g_object_unref (cm->connection);
|
||||
PLUGIN_PRINT (IFCFG_PLUGIN_NAME, " removed connection");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
monitor_connection (NMSystemConfigInterface *config, NMConnection *connection, const char *filename)
|
||||
{
|
||||
GFile *file;
|
||||
GFileMonitor *monitor;
|
||||
|
||||
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) {
|
||||
ConnectionMonitor *cm;
|
||||
|
||||
cm = g_new (ConnectionMonitor, 1);
|
||||
cm->plugin = SC_PLUGIN_IFCFG (config);
|
||||
cm->connection = connection;
|
||||
cm->monitor = monitor;
|
||||
cm->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (connection_file_changed), cm);
|
||||
g_object_set_data_full (G_OBJECT (connection), "file-monitor", cm, connection_monitor_destroy);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_one_connection (NMSystemConfigInterface *config, const char *filename, gboolean emit_added)
|
||||
{
|
||||
char *ifcfg_file;
|
||||
NMConnection *connection;
|
||||
|
||||
if (!is_ifcfg_file (filename))
|
||||
return;
|
||||
|
||||
ifcfg_file = g_build_filename (IFCFG_DIR, filename, NULL);
|
||||
connection = build_one_connection (ifcfg_file);
|
||||
if (connection) {
|
||||
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config);
|
||||
|
||||
monitor_connection (config, connection, ifcfg_file);
|
||||
priv->connections = g_slist_append (priv->connections, connection);
|
||||
|
||||
if (emit_added)
|
||||
g_signal_emit_by_name (config, "connection-added", connection);
|
||||
}
|
||||
|
||||
g_free (ifcfg_file);
|
||||
}
|
||||
|
||||
static void
|
||||
update_default_routes (NMSystemConfigInterface *config, gboolean emit_updated)
|
||||
{
|
||||
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config);
|
||||
GSList *iter;
|
||||
NMConnection *connection;
|
||||
NMSettingIP4Config *ip4_setting;
|
||||
gboolean got_manual = FALSE;
|
||||
guint32 default_route;
|
||||
|
||||
/* First, make sure we have any non-DHCP connections */
|
||||
for (iter = priv->connections; iter; iter = iter->next) {
|
||||
connection = NM_CONNECTION (iter->data);
|
||||
ip4_setting = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
|
||||
if (ip4_setting && ip4_setting->manual) {
|
||||
got_manual = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!got_manual)
|
||||
return;
|
||||
|
||||
default_route = parser_parse_routes (IFCFG_DIR "/routes", NULL);
|
||||
if (!default_route)
|
||||
return;
|
||||
|
||||
for (iter = priv->connections; iter; iter = iter->next) {
|
||||
connection = NM_CONNECTION (iter->data);
|
||||
ip4_setting = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
|
||||
if (ip4_setting && ip4_setting->manual) {
|
||||
GSList *address_iter;
|
||||
|
||||
for (address_iter = ip4_setting->addresses; address_iter; address_iter = address_iter->next) {
|
||||
NMSettingIP4Address *addr = (NMSettingIP4Address *) address_iter->data;
|
||||
|
||||
addr->gateway = default_route;
|
||||
if (emit_updated)
|
||||
g_signal_emit_by_name (config, "connection-updated", connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GSList *
|
||||
get_connections (NMSystemConfigInterface *config)
|
||||
{
|
||||
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config);
|
||||
|
||||
if (!priv->initialized) {
|
||||
GDir *dir;
|
||||
const char *item;
|
||||
GError *err = NULL;
|
||||
|
||||
dir = g_dir_open (IFCFG_DIR, 0, &err);
|
||||
if (!dir) {
|
||||
PLUGIN_WARN (PLUGIN_NAME, "couldn't access network directory '%s': %s.", IFCFG_DIR, err->message);
|
||||
g_error_free (err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((item = g_dir_read_name (dir)))
|
||||
add_one_connection (config, item, FALSE);
|
||||
|
||||
g_dir_close (dir);
|
||||
priv->initialized = TRUE;
|
||||
}
|
||||
|
||||
if (!priv->connections)
|
||||
/* No need to do any futher work, we have nothing. */
|
||||
return priv->connections;
|
||||
|
||||
update_default_routes (config, FALSE);
|
||||
|
||||
return priv->connections;
|
||||
}
|
||||
|
||||
static void
|
||||
ifcfg_dir_changed (GFileMonitor *monitor,
|
||||
GFile *file,
|
||||
GFile *other_file,
|
||||
GFileMonitorEvent event_type,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMSystemConfigInterface *config = NM_SYSTEM_CONFIG_INTERFACE (user_data);
|
||||
char *name;
|
||||
|
||||
name = g_file_get_basename (file);
|
||||
|
||||
if (event_type == G_FILE_MONITOR_EVENT_CREATED) {
|
||||
add_one_connection (config, name, TRUE);
|
||||
}
|
||||
|
||||
if (!strcmp (name, "routes"))
|
||||
update_default_routes (config, TRUE);
|
||||
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
static void
|
||||
init (NMSystemConfigInterface *config)
|
||||
{
|
||||
GFile *file;
|
||||
GFileMonitor *monitor;
|
||||
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config);
|
||||
|
||||
file = g_file_new_for_path (IFCFG_DIR);
|
||||
monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
|
||||
g_object_unref (file);
|
||||
|
||||
if (monitor) {
|
||||
priv->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (ifcfg_dir_changed), config);
|
||||
priv->monitor = monitor;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
release_one_connection (gpointer item, gpointer user_data)
|
||||
{
|
||||
NMConnection *connection = NM_CONNECTION (item);
|
||||
SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data);
|
||||
|
||||
g_signal_emit_by_name (plugin, "connection-removed", connection);
|
||||
g_object_unref (connection);
|
||||
}
|
||||
|
||||
static void
|
||||
sc_plugin_ifcfg_init (SCPluginIfcfg *plugin)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (object);
|
||||
|
||||
if (priv->connections) {
|
||||
g_slist_foreach (priv->connections, release_one_connection, object);
|
||||
g_slist_free (priv->connections);
|
||||
}
|
||||
|
||||
if (priv->monitor) {
|
||||
if (priv->monitor_id)
|
||||
g_signal_handler_disconnect (priv->monitor, priv->monitor_id);
|
||||
|
||||
g_file_monitor_cancel (priv->monitor);
|
||||
g_object_unref (priv->monitor);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (sc_plugin_ifcfg_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
get_property (GObject *object, guint prop_id,
|
||||
GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
switch (prop_id) {
|
||||
case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME:
|
||||
g_value_set_string (value, IFCFG_PLUGIN_NAME);
|
||||
break;
|
||||
case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO:
|
||||
g_value_set_string (value, IFCFG_PLUGIN_INFO);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sc_plugin_ifcfg_class_init (SCPluginIfcfgClass *req_class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (req_class);
|
||||
|
||||
g_type_class_add_private (req_class, sizeof (SCPluginIfcfgPrivate));
|
||||
|
||||
object_class->get_property = get_property;
|
||||
object_class->dispose = dispose;
|
||||
|
||||
g_object_class_override_property (object_class,
|
||||
NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME,
|
||||
NM_SYSTEM_CONFIG_INTERFACE_NAME);
|
||||
|
||||
g_object_class_override_property (object_class,
|
||||
NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO,
|
||||
NM_SYSTEM_CONFIG_INTERFACE_INFO);
|
||||
}
|
||||
|
||||
static void
|
||||
system_config_interface_init (NMSystemConfigInterface *system_config_interface_class)
|
||||
{
|
||||
/* interface implementation */
|
||||
system_config_interface_class->get_connections = get_connections;
|
||||
system_config_interface_class->init = init;
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT GObject *
|
||||
nm_system_config_factory (void)
|
||||
{
|
||||
static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
|
||||
static SCPluginIfcfg *singleton = NULL;
|
||||
|
||||
g_static_mutex_lock (&mutex);
|
||||
if (!singleton)
|
||||
singleton = SC_PLUGIN_IFCFG (g_object_new (SC_TYPE_PLUGIN_IFCFG, NULL));
|
||||
g_object_ref (singleton);
|
||||
g_static_mutex_unlock (&mutex);
|
||||
|
||||
return G_OBJECT (singleton);
|
||||
}
|
52
system-settings/plugins/ifcfg-suse/plugin.h
Normal file
52
system-settings/plugins/ifcfg-suse/plugin.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef _PLUGIN_H_
|
||||
#define _PLUGIN_H_
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#define PLUGIN_NAME "ifcfg"
|
||||
|
||||
#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))
|
||||
#define SC_PLUGIN_IFCFG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgClass))
|
||||
#define SC_IS_PLUGIN_IFCFG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_IFCFG))
|
||||
#define SC_IS_PLUGIN_IFCFG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SC_TYPE_PLUGIN_IFCFG))
|
||||
#define SC_PLUGIN_IFCFG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgClass))
|
||||
|
||||
typedef struct _SCPluginIfcfg SCPluginIfcfg;
|
||||
typedef struct _SCPluginIfcfgClass SCPluginIfcfgClass;
|
||||
|
||||
struct _SCPluginIfcfg {
|
||||
GObject parent;
|
||||
};
|
||||
|
||||
struct _SCPluginIfcfgClass {
|
||||
GObjectClass parent;
|
||||
};
|
||||
|
||||
GType sc_plugin_ifcfg_get_type (void);
|
||||
|
||||
GQuark ifcfg_plugin_error_quark (void);
|
||||
|
||||
#endif /* _PLUGIN_H_ */
|
||||
|
402
system-settings/plugins/ifcfg-suse/shvar.c
Normal file
402
system-settings/plugins/ifcfg-suse/shvar.c
Normal file
|
@ -0,0 +1,402 @@
|
|||
/*
|
||||
* 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;
|
||||
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_free(s->lineList); /* implicitly frees s->current */
|
||||
g_free(s);
|
||||
return 0;
|
||||
}
|
103
system-settings/plugins/ifcfg-suse/shvar.h
Normal file
103
system-settings/plugins/ifcfg-suse/shvar.h
Normal file
|
@ -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 */
|
Loading…
Reference in a new issue