From: "Daniel P. Berrange" <berrange(a)redhat.com>
In preparation for the introduction of further drivers for the
networking initscripts on non-Red Hat derivative distros, rename
the existing 'initscripts' driver to 'redhat'.
---
.gitignore | 2 +-
Makefile.am | 2 +-
configure.ac | 4 +-
data/xml/initscripts-get.xsl | 245 -----
data/xml/initscripts-put.xsl | 270 ------
data/xml/redhat-get.xsl | 245 +++++
data/xml/redhat-put.xsl | 270 ++++++
src/Makefile.am | 4 +-
src/drv_initscripts.c | 1182 -----------------------
src/drv_redhat.c | 1182 +++++++++++++++++++++++
tests/Makefile.am | 16 +-
tests/initscripts/bond-arp.xml | 24 -
tests/initscripts/bond-defaults.xml | 28 -
tests/initscripts/bond.xml | 28 -
tests/initscripts/bridge-bond.xml | 37 -
tests/initscripts/bridge-empty.xml | 10 -
tests/initscripts/bridge-no-address.xml | 26 -
tests/initscripts/bridge-vlan.xml | 16 -
tests/initscripts/bridge.xml | 28 -
tests/initscripts/ethernet-dhcp.xml | 14 -
tests/initscripts/ethernet-static-no-prefix.xml | 14 -
tests/initscripts/ethernet-static.xml | 15 -
tests/initscripts/ipv6-autoconf-dhcp.xml | 10 -
tests/initscripts/ipv6-autoconf.xml | 10 -
tests/initscripts/ipv6-dhcp.xml | 10 -
tests/initscripts/ipv6-local.xml | 10 -
tests/initscripts/ipv6-static-multi.xml | 12 -
tests/initscripts/ipv6-static.xml | 12 -
tests/initscripts/schemas.xml | 4 -
tests/initscripts/vlan.xml | 10 -
tests/redhat/bond-arp.xml | 24 +
tests/redhat/bond-defaults.xml | 28 +
tests/redhat/bond.xml | 28 +
tests/redhat/bridge-bond.xml | 37 +
tests/redhat/bridge-empty.xml | 10 +
tests/redhat/bridge-no-address.xml | 26 +
tests/redhat/bridge-vlan.xml | 16 +
tests/redhat/bridge.xml | 28 +
tests/redhat/ethernet-dhcp.xml | 14 +
tests/redhat/ethernet-static-no-prefix.xml | 14 +
tests/redhat/ethernet-static.xml | 15 +
tests/redhat/ipv6-autoconf-dhcp.xml | 10 +
tests/redhat/ipv6-autoconf.xml | 10 +
tests/redhat/ipv6-dhcp.xml | 10 +
tests/redhat/ipv6-local.xml | 10 +
tests/redhat/ipv6-static-multi.xml | 12 +
tests/redhat/ipv6-static.xml | 12 +
tests/redhat/schemas.xml | 4 +
tests/redhat/vlan.xml | 10 +
tests/test-initscripts.c | 257 -----
tests/test-redhat.c | 257 +++++
51 files changed, 2286 insertions(+), 2286 deletions(-)
delete mode 100644 data/xml/initscripts-get.xsl
delete mode 100644 data/xml/initscripts-put.xsl
create mode 100644 data/xml/redhat-get.xsl
create mode 100644 data/xml/redhat-put.xsl
delete mode 100644 src/drv_initscripts.c
create mode 100644 src/drv_redhat.c
delete mode 100644 tests/initscripts/bond-arp.xml
delete mode 100644 tests/initscripts/bond-defaults.xml
delete mode 100644 tests/initscripts/bond.xml
delete mode 100644 tests/initscripts/bridge-bond.xml
delete mode 100644 tests/initscripts/bridge-empty.xml
delete mode 100644 tests/initscripts/bridge-no-address.xml
delete mode 100644 tests/initscripts/bridge-vlan.xml
delete mode 100644 tests/initscripts/bridge.xml
delete mode 100644 tests/initscripts/ethernet-dhcp.xml
delete mode 100644 tests/initscripts/ethernet-static-no-prefix.xml
delete mode 100644 tests/initscripts/ethernet-static.xml
delete mode 100644 tests/initscripts/ipv6-autoconf-dhcp.xml
delete mode 100644 tests/initscripts/ipv6-autoconf.xml
delete mode 100644 tests/initscripts/ipv6-dhcp.xml
delete mode 100644 tests/initscripts/ipv6-local.xml
delete mode 100644 tests/initscripts/ipv6-static-multi.xml
delete mode 100644 tests/initscripts/ipv6-static.xml
delete mode 100644 tests/initscripts/schemas.xml
delete mode 100644 tests/initscripts/vlan.xml
create mode 100644 tests/redhat/bond-arp.xml
create mode 100644 tests/redhat/bond-defaults.xml
create mode 100644 tests/redhat/bond.xml
create mode 100644 tests/redhat/bridge-bond.xml
create mode 100644 tests/redhat/bridge-empty.xml
create mode 100644 tests/redhat/bridge-no-address.xml
create mode 100644 tests/redhat/bridge-vlan.xml
create mode 100644 tests/redhat/bridge.xml
create mode 100644 tests/redhat/ethernet-dhcp.xml
create mode 100644 tests/redhat/ethernet-static-no-prefix.xml
create mode 100644 tests/redhat/ethernet-static.xml
create mode 100644 tests/redhat/ipv6-autoconf-dhcp.xml
create mode 100644 tests/redhat/ipv6-autoconf.xml
create mode 100644 tests/redhat/ipv6-dhcp.xml
create mode 100644 tests/redhat/ipv6-local.xml
create mode 100644 tests/redhat/ipv6-static-multi.xml
create mode 100644 tests/redhat/ipv6-static.xml
create mode 100644 tests/redhat/schemas.xml
create mode 100644 tests/redhat/vlan.xml
delete mode 100644 tests/test-initscripts.c
create mode 100644 tests/test-redhat.c
diff --git a/.gitignore b/.gitignore
index 6482a04..b090c77 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,5 +41,5 @@ src/ncftransform
src/netcf-transaction.init
src/netcf.syms
stamp-h1
-tests/test-initscripts
+tests/test-redhat
ylwrap
diff --git a/Makefile.am b/Makefile.am
index a658e27..6ff340d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,7 +13,7 @@ lensdir=$(netcfdir)/lenses
dist_xml_DATA=data/xml/augeas.rng data/xml/interface.rng \
data/xml/util-get.xsl data/xml/util-put.xsl \
- data/xml/initscripts-get.xsl data/xml/initscripts-put.xsl
+ data/xml/redhat-get.xsl data/xml/redhat-put.xsl
dist_netcf_DATA=data/iptables-forward-bridged
dist_lens_DATA=data/lenses/netcf.aug data/lenses/sysconfig.aug
diff --git a/configure.ac b/configure.ac
index 2e24246..58df429 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,9 +15,9 @@ gl_EARLY
AC_PROG_LIBTOOL
-dnl The backend driver. Right now hardcoded to initscripts, but
+dnl The backend driver. Right now hardcoded to redhat, but
dnl eventually needs to be configurable at buildtime
-AM_CONDITIONAL([NETCF_DRIVER_INITSCRIPTS], [true])
+AM_CONDITIONAL([NETCF_DRIVER_REDHAT], [true])
dnl Compiler flags to be used everywhere
AC_SUBST([NETCF_CFLAGS], ['--std=gnu99 -Wp,-D_FORTIFY_SOURCE=2 -fexceptions
-fasynchronous-unwind-tables'])
diff --git a/data/xml/initscripts-get.xsl b/data/xml/initscripts-get.xsl
deleted file mode 100644
index fab8ecb..0000000
--- a/data/xml/initscripts-get.xsl
+++ /dev/null
@@ -1,245 +0,0 @@
-<?xml version="1.0"?>
-<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- xmlns:ipcalc = "http://redhat.com/xslt/netcf/ipcalc/1.0"
- extension-element-prefixes="ipcalc"
- version="1.0">
-
- <xsl:import href="util-get.xsl"/>
-
- <xsl:output method="xml" indent="yes"/>
-
- <xsl:template match="/">
- <forest>
- <xsl:apply-templates/>
- </forest>
- </xsl:template>
-
- <!-- Some global variables
-
- To keep my sanity, all global variables start with 'g_'
- -->
- <xsl:variable name="g_startmode"
select="/interface/start/@mode"/>
- <xsl:variable name="g_mtu" select="/interface/mtu/@size"/>
-
- <!--
- Ethernet (physical interface)
- -->
- <xsl:template match="/interface[@type = 'ethernet']">
- <tree>
- <xsl:call-template name="bare-ethernet-interface"/>
- <xsl:call-template name="interface-addressing"/>
- </tree>
- </xsl:template>
-
- <!--
- VLAN's
- -->
- <xsl:template match="interface[@type = 'vlan']"
name="vlan-interface">
- <tree>
- <xsl:call-template name="vlan-interface-common"/>
- <xsl:call-template name="startmode"/>
- <xsl:call-template name="mtu"/>
- <xsl:call-template name="interface-addressing"/>
- <!-- nothing to do for vlan-device -->
- </tree>
- </xsl:template>
-
- <xsl:template name="vlan-interface-common">
- <xsl:variable name="iface" select="concat(vlan/interface/@name,
'.', vlan/@tag)"/>
-
- <xsl:attribute
name="path">/files/etc/sysconfig/network-scripts/ifcfg-<xsl:value-of
select="$iface"/></xsl:attribute>
- <node label="DEVICE" value="{$iface}"/>
- <node label="VLAN" value="yes"/>
- </xsl:template>
-
- <xsl:template name='bare-vlan-interface'>
- <xsl:call-template name='vlan-interface-common'/>
- <xsl:call-template name="startmode"/>
- <xsl:call-template name="mtu"/>
- <!-- nothing to do for vlan-device -->
- </xsl:template>
-
- <!--
- Bridge
- -->
- <xsl:template match="/interface[@type = 'bridge']">
- <tree>
- <xsl:call-template name="name-attr"/>
- <xsl:call-template name="startmode"/>
- <xsl:call-template name="mtu"/>
- <node label="TYPE" value="Bridge"/>
- <xsl:call-template name="interface-addressing"/>
- <xsl:if test="bridge/@stp">
- <node label="STP" value="{bridge/@stp}"/>
- </xsl:if>
- <xsl:if test="bridge/@delay">
- <node label="DELAY" value="{bridge/@delay}"/>
- </xsl:if>
- </tree>
- <xsl:for-each select='bridge/interface'>
- <tree>
- <xsl:if test="@type = 'ethernet'">
- <xsl:call-template name="bare-ethernet-interface"/>
- </xsl:if>
- <xsl:if test="@type = 'vlan'">
- <xsl:call-template name="bare-vlan-interface"/>
- </xsl:if>
- <xsl:if test="@type = 'bond'">
- <xsl:call-template name="bare-bond-interface"/>
- </xsl:if>
- <node label="BRIDGE" value="{../../@name}"/>
- </tree>
- <xsl:if test="@type = 'bond'">
- <xsl:call-template name="bond-slaves"/>
- </xsl:if>
- </xsl:for-each>
- </xsl:template>
-
- <!--
- Bond
- -->
- <xsl:template name="bond-slaves">
- <xsl:for-each select='bond/interface'>
- <tree>
- <xsl:call-template name="bare-ethernet-interface"/>
- <node label="MASTER" value="{../../@name}"/>
- <node label="SLAVE" value="yes"/>
- </tree>
- </xsl:for-each>
- </xsl:template>
-
- <xsl:template name="bonding-opts-node">
- <node label="BONDING_OPTS">
- <xsl:attribute name="value">
- <xsl:call-template name="bonding-opts"/>
- </xsl:attribute>
- </node>
- </xsl:template>
-
- <xsl:template name="bare-bond-interface">
- <xsl:call-template name="name-attr"/>
- <xsl:call-template name="startmode"/>
- <xsl:call-template name="mtu"/>
- <xsl:call-template name="bonding-opts-node"/>
- </xsl:template>
-
- <xsl:template match="/interface[@type = 'bond']">
- <tree>
- <xsl:call-template name="name-attr"/>
- <xsl:call-template name="startmode"/>
- <xsl:call-template name="mtu"/>
- <xsl:call-template name="interface-addressing"/>
- <xsl:call-template name="bonding-opts-node"/>
- </tree>
- <xsl:call-template name="bond-slaves"/>
- </xsl:template>
-
- <!--
- Named templates, following the Relax NG syntax
- -->
- <xsl:template name="name-attr">
- <xsl:attribute
name="path">/files/etc/sysconfig/network-scripts/ifcfg-<xsl:value-of
select="@name"/></xsl:attribute>
- <node label="DEVICE" value="{@name}"/>
- </xsl:template>
-
- <xsl:template name="mtu">
- <xsl:if test="$g_mtu != ''">
- <node label="MTU" value="{$g_mtu}"/>
- </xsl:if>
- </xsl:template>
-
- <xsl:template name="bare-ethernet-interface">
- <xsl:call-template name="name-attr"/>
- <xsl:if test="mac">
- <node label="HWADDR" value="{mac/@address}"/>
- </xsl:if>
- <xsl:call-template name="startmode"/>
- <xsl:call-template name="mtu"/>
- </xsl:template>
-
- <xsl:template name="startmode">
- <xsl:choose>
- <xsl:when test="$g_startmode = 'onboot'">
- <node label="ONBOOT" value="yes"/>
- </xsl:when>
- <xsl:when test="$g_startmode = 'none'">
- <node label="ONBOOT" value="no"/>
- </xsl:when>
- <xsl:when test="$g_startmode = 'hotplug'">
- <node label="ONBOOT" value="no"/>
- <node label="HOTPLUG" value="yes"/>
- </xsl:when>
- </xsl:choose>
- </xsl:template>
-
- <xsl:template name="interface-addressing">
- <xsl:for-each select="protocol[@family='ipv4']">
- <xsl:call-template name="protocol-ipv4"/>
- </xsl:for-each>
- <xsl:for-each select="protocol[@family='ipv6']">
- <xsl:call-template name="protocol-ipv6"/>
- </xsl:for-each>
- </xsl:template>
-
- <xsl:template name="protocol-ipv4">
- <xsl:choose>
- <xsl:when test="dhcp">
- <node label="BOOTPROTO" value="dhcp"/>
- <xsl:if test="dhcp/@peerdns">
- <node label="PEERDNS" value="{dhcp/@peerdns}"/>
- </xsl:if>
- </xsl:when>
- <xsl:when test="ip">
- <node label="BOOTPROTO" value="none"/>
- <node label="IPADDR" value="{ip/@address}"/>
- <xsl:if test="ip/@prefix">
- <node label="NETMASK"
value="{ipcalc:netmask(ip/@prefix)}"/>
- </xsl:if>
- <xsl:if test="route">
- <node label="GATEWAY" value="{route/@gateway}"/>
- </xsl:if>
- </xsl:when>
- </xsl:choose>
- </xsl:template>
-
- <xsl:template name="protocol-ipv6">
- <node label="IPV6INIT" value="yes"/>
- <xsl:if test="count(autoconf) > 0">
- <node label="IPV6_AUTOCONF" value="yes"/>
- </xsl:if>
- <xsl:if test="count(autoconf) = 0">
- <node label="IPV6_AUTOCONF" value="no"/>
- </xsl:if>
- <xsl:if test="count(dhcp) > 0">
- <node label="DHCPV6" value="yes"/>
- </xsl:if>
- <xsl:if test="count(dhcp) = 0">
- <node label="DHCPV6" value="no"/>
- </xsl:if>
- <xsl:if test="count(ip) > 0">
- <node label="IPV6ADDR">
- <xsl:attribute name="value">
- <xsl:value-of select="ip[1]/@address"/><xsl:if
test="ip[1]/@prefix">/<xsl:value-of
select="ip[1]/@prefix"/></xsl:if>
- </xsl:attribute>
- </node>
- </xsl:if>
- <xsl:if test="count(ip) > 1">
- <node label="IPV6ADDR_SECONDARIES">
- <xsl:attribute name="value">
- <xsl:text>'</xsl:text>
- <xsl:for-each
select="ip[1]/following-sibling::ip[following-sibling::ip]">
- <xsl:value-of select="@address"/><xsl:if
test="@prefix">/<xsl:value-of
select="@prefix"/></xsl:if><xsl:value-of select="string('
')"/>
- </xsl:for-each>
- <xsl:for-each select="ip[last()]">
- <xsl:value-of select="@address"/><xsl:if
test="@prefix">/<xsl:value-of
select="@prefix"/></xsl:if>
- </xsl:for-each>
- <xsl:text>'</xsl:text>
- </xsl:attribute>
- </node>
- </xsl:if>
- <xsl:if test="route">
- <node label="IPV6_DEFAULTGW" value="{route/@gateway}"/>
- </xsl:if>
- </xsl:template>
-
-</xsl:stylesheet>
diff --git a/data/xml/initscripts-put.xsl b/data/xml/initscripts-put.xsl
deleted file mode 100644
index 267d9cd..0000000
--- a/data/xml/initscripts-put.xsl
+++ /dev/null
@@ -1,270 +0,0 @@
-<?xml version="1.0"?>
-<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- xmlns:ipcalc = "http://redhat.com/xslt/netcf/ipcalc/1.0"
- xmlns:bond = "http://redhat.com/xslt/netcf/bond/1.0"
-
xmlns:str="http://exslt.org/strings"
- extension-element-prefixes="bond ipcalc str"
- version="1.0">
-
- <xsl:import href="util-put.xsl"/>
-
- <xsl:output method="xml" indent="yes"/>
- <xsl:strip-space elements="*"/>
-
- <xsl:template match="/">
- <xsl:apply-templates select="*"/>
- </xsl:template>
-
- <!--
- Ethernet adapter
- -->
- <xsl:template name="ethernet-interface"
- match="tree[count(node[@label = 'MASTER' or
@label='BRIDGE'
- or @label = 'VLAN']) = 0]">
- <interface type="ethernet">
- <xsl:call-template name="name-attr"/>
- <xsl:call-template name="startmode"/>
- <xsl:if test="node[@label = 'HWADDR']">
- <mac address="{node[@label = 'HWADDR']/@value}"/>
- </xsl:if>
- <xsl:call-template name="mtu"/>
- <xsl:call-template name="interface-addressing"/>
- </interface>
- </xsl:template>
-
- <!--
- VLAN's
- -->
- <xsl:template name="vlan-interface"
- match="tree[node[@label = 'VLAN' and @value =
'yes']][count(node[@label = 'MASTER' or @label='BRIDGE']) =
0]">
- <interface type="vlan">
- <xsl:call-template name="name-attr"/>
- <xsl:call-template name="startmode"/>
- <xsl:call-template name="mtu"/>
- <xsl:call-template name="interface-addressing"/>
- <xsl:call-template name="vlan-device"/>
- </interface>
- </xsl:template>
-
- <xsl:template name="bare-vlan-interface">
- <xsl:variable name="name" select="node[@label =
'DEVICE']/@value"/>
- <interface type="vlan">
- <xsl:call-template name="name-attr"/>
- <xsl:call-template name="vlan-device"/>
- </interface>
- </xsl:template>
-
- <xsl:template name="vlan-device">
- <xsl:variable name="name" select="node[@label =
'DEVICE']/@value"/>
- <xsl:variable name="device" select="substring-before($name,
'.')"/>
- <xsl:variable name="tag" select="substring-after($name,
'.')"/>
- <vlan tag="{$tag}">
- <interface name="{$device}"/>
- </vlan>
- </xsl:template>
-
- <!--
- Bridge
- -->
- <xsl:template name="bridge-interface"
- match="tree[node[@label = 'TYPE' and @value =
'Bridge']]">
- <interface type="bridge">
- <!-- the bridge node itself -->
- <xsl:variable name="iface" select="node[@label=
'DEVICE']/@value"/>
- <xsl:call-template name="name-attr"/>
- <xsl:call-template name="startmode"/>
- <xsl:call-template name="mtu"/>
- <xsl:call-template name="interface-addressing"/>
- <bridge>
- <xsl:if test="node[@label = 'STP']">
- <xsl:attribute name="stp"><xsl:value-of
select="node[@label = 'STP']/@value"/></xsl:attribute>
- </xsl:if>
- <xsl:if test="node[@label = 'DELAY']">
- <xsl:attribute name="delay"><xsl:value-of
select="node[@label = 'DELAY']/@value"/></xsl:attribute>
- </xsl:if>
- <xsl:for-each select="/descendant-or-self::*[node[@label =
'BRIDGE' and @value = $iface]]">
- <xsl:if test="count(node[@label = 'VLAN' or @label =
'BONDING_OPTS']) = 0">
- <xsl:call-template name="bare-ethernet-interface"/>
- </xsl:if>
- <xsl:if test="count(node[@label = 'BONDING_OPTS']) >
0">
- <xsl:call-template name="bare-bond-interface"/>
- </xsl:if>
- <xsl:if test="count(node[@label = 'VLAN']) > 0">
- <xsl:call-template name="bare-vlan-interface"/>
- </xsl:if>
- </xsl:for-each>
- </bridge>
- </interface>
- </xsl:template>
-
- <!--
- Bond
- -->
- <xsl:template name="bond-element">
- <xsl:variable name="iface" select="node[@label=
'DEVICE']/@value"/>
- <bond>
- <xsl:variable name="opts" select="node[@label =
'BONDING_OPTS']/@value"/>
- <xsl:call-template name="bonding-opts">
- <xsl:with-param name="opts" select="$opts"/>
- </xsl:call-template>
- <xsl:variable name="primary" select="bond:option($opts,
'primary')"/>
- <xsl:for-each select="/descendant-or-self::*[node[@label = 'MASTER'
and @value = $iface]][node[@label = 'DEVICE' and @value = $primary]]">
- <xsl:call-template name='bare-ethernet-interface'/>
- </xsl:for-each>
- <xsl:for-each select="/descendant-or-self::*[node[@label = 'MASTER'
and @value = $iface]][node[@label = 'DEVICE' and @value != $primary]]">
- <xsl:call-template name='bare-ethernet-interface'/>
- </xsl:for-each>
- </bond>
- </xsl:template>
-
- <xsl:template name="bare-bond-interface">
- <interface type="bond">
- <xsl:call-template name="name-attr"/>
- <xsl:call-template name="bond-element"/>
- </interface>
- </xsl:template>
-
- <xsl:template name="bond-interface"
- match="tree[node[@label = 'DEVICE'][@value =
//tree/node[@label = 'MASTER']/@value]][count(node[@label = 'BRIDGE']) =
0]">
- <interface type="bond">
- <xsl:call-template name="name-attr"/>
- <xsl:call-template name="startmode"/>
- <xsl:call-template name="mtu"/>
- <xsl:call-template name="interface-addressing"/>
- <xsl:call-template name="bond-element"/>
- </interface>
- </xsl:template>
-
- <!--
- Utility templates, names follow the names in interface.rng
- -->
- <xsl:template name="startmode">
- <xsl:choose>
- <xsl:when test="node[@label ='HOTPLUG']/@value =
'yes'">
- <start mode='hotplug'/>
- </xsl:when>
- <xsl:when test="node[@label = 'ONBOOT']/@value =
'yes'">
- <start mode='onboot'/>
- </xsl:when>
- <xsl:otherwise>
- <start mode='none'/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:template>
-
- <xsl:template name="name-attr">
- <xsl:attribute name="name">
- <xsl:value-of select="node[@label= 'DEVICE']/@value"/>
- </xsl:attribute>
- </xsl:template>
-
- <xsl:template name="mtu">
- <xsl:if test="node[@label='MTU']">
- <mtu size="{node[@label='MTU']/@value}"/>
- </xsl:if>
- </xsl:template>
-
- <xsl:template name="interface-addressing">
- <xsl:call-template name="protocol-ipv4"/>
- <xsl:call-template name="protocol-ipv6"/>
- </xsl:template>
-
- <xsl:template name="protocol-ipv4">
- <xsl:variable name="uses_dhcp"
- select="node[@label = 'BOOTPROTO']/@value =
'dhcp'"/>
- <xsl:variable name="uses_static"
- select="count(node[@label = 'IPADDR']) > 0"/>
- <xsl:variable name="uses_ipv4" select="$uses_dhcp or
$uses_static"/>
- <xsl:if test="$uses_ipv4">
- <protocol family="ipv4">
- <xsl:choose>
- <xsl:when test="$uses_dhcp">
- <dhcp>
- <xsl:if test="node[@label = 'PEERDNS']">
- <xsl:attribute name="peerdns"><xsl:value-of
select="node[@label =
'PEERDNS']/@value"></xsl:value-of></xsl:attribute>
- </xsl:if>
- </dhcp>
- </xsl:when>
- <xsl:when test="$uses_static">
- <ip address="{node[@label = 'IPADDR']/@value}">
- <xsl:choose>
- <xsl:when test="node[@label = 'PREFIX']">
- <xsl:attribute name="prefix"><xsl:value-of
select="node[@label = 'PREFIX']/@value"/></xsl:attribute>
- </xsl:when>
- <xsl:when test="node[@label = 'NETMASK']">
- <xsl:attribute name="prefix"><xsl:value-of
select="ipcalc:prefix(node[@label =
'NETMASK']/@value)"/></xsl:attribute>
- </xsl:when>
- </xsl:choose>
- </ip>
- <xsl:if test="node[@label = 'GATEWAY']">
- <route gateway="{node[@label = 'GATEWAY']/@value}"/>
- </xsl:if>
- </xsl:when>
- </xsl:choose>
- </protocol>
- </xsl:if>
- </xsl:template>
-
- <xsl:template name="protocol-ipv6">
- <xsl:if test="node[@label = 'IPV6INIT'][@value =
'yes']">
- <protocol family="ipv6">
- <xsl:if test="node[@label = 'IPV6_AUTOCONF'][@value =
'yes']">
- <autoconf/>
- </xsl:if>
- <xsl:if test="node[@label = 'DHCPV6'][@value =
'yes']">
- <dhcp/>
- </xsl:if>
- <xsl:if test="node[@label = 'IPV6ADDR']">
- <xsl:call-template name="ipv6-address">
- <xsl:with-param name="value"
- select="node[@label =
'IPV6ADDR']/@value"/>
- </xsl:call-template>
- </xsl:if>
- <xsl:if test="node[@label = 'IPV6ADDR_SECONDARIES']">
- <!-- Strip surrounding single quotes from $s -->
- <xsl:variable name="s"
- select="node[@label =
'IPV6ADDR_SECONDARIES']/@value"/>
- <xsl:variable name="q">'</xsl:variable>
- <xsl:variable name="sec">
- <xsl:choose>
- <xsl:when test="starts-with($s, $q)">
- <xsl:value-of select="substring($s, 2,
string-length($s)-2)"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$s"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:for-each select="str:split($sec)">
- <xsl:call-template name="ipv6-address">
- <xsl:with-param name="value" select="."/>
- </xsl:call-template>
- </xsl:for-each>
- </xsl:if>
- </protocol>
- </xsl:if>
- </xsl:template>
-
- <xsl:template name="ipv6-address">
- <xsl:param name="value"/>
- <xsl:variable name="address" select="substring-before($value,
'/')"/>
- <xsl:variable name="prefix" select="substring-after($value,
'/')"/>
- <ip address="{$address}">
- <xsl:if test="$prefix != ''">
- <xsl:attribute name="prefix"><xsl:value-of
select="$prefix"/></xsl:attribute>
- </xsl:if>
- </ip>
- <xsl:if test="node[@label = 'IPV6_DEFAULTGW']">
- <route gateway="{node[@label =
'IPV6_DEFAULTGW']/@value}"/>
- </xsl:if>
- </xsl:template>
-
- <xsl:template name="bare-ethernet-interface">
- <interface type="ethernet">
- <xsl:call-template name="name-attr"/>
- <xsl:if test="node[@label = 'HWADDR']">
- <mac address="{node[@label = 'HWADDR']/@value}"/>
- </xsl:if>
- </interface>
- </xsl:template>
-</xsl:stylesheet>
diff --git a/data/xml/redhat-get.xsl b/data/xml/redhat-get.xsl
new file mode 100644
index 0000000..fab8ecb
--- /dev/null
+++ b/data/xml/redhat-get.xsl
@@ -0,0 +1,245 @@
+<?xml version="1.0"?>
+<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:ipcalc = "http://redhat.com/xslt/netcf/ipcalc/1.0"
+ extension-element-prefixes="ipcalc"
+ version="1.0">
+
+ <xsl:import href="util-get.xsl"/>
+
+ <xsl:output method="xml" indent="yes"/>
+
+ <xsl:template match="/">
+ <forest>
+ <xsl:apply-templates/>
+ </forest>
+ </xsl:template>
+
+ <!-- Some global variables
+
+ To keep my sanity, all global variables start with 'g_'
+ -->
+ <xsl:variable name="g_startmode"
select="/interface/start/@mode"/>
+ <xsl:variable name="g_mtu" select="/interface/mtu/@size"/>
+
+ <!--
+ Ethernet (physical interface)
+ -->
+ <xsl:template match="/interface[@type = 'ethernet']">
+ <tree>
+ <xsl:call-template name="bare-ethernet-interface"/>
+ <xsl:call-template name="interface-addressing"/>
+ </tree>
+ </xsl:template>
+
+ <!--
+ VLAN's
+ -->
+ <xsl:template match="interface[@type = 'vlan']"
name="vlan-interface">
+ <tree>
+ <xsl:call-template name="vlan-interface-common"/>
+ <xsl:call-template name="startmode"/>
+ <xsl:call-template name="mtu"/>
+ <xsl:call-template name="interface-addressing"/>
+ <!-- nothing to do for vlan-device -->
+ </tree>
+ </xsl:template>
+
+ <xsl:template name="vlan-interface-common">
+ <xsl:variable name="iface" select="concat(vlan/interface/@name,
'.', vlan/@tag)"/>
+
+ <xsl:attribute
name="path">/files/etc/sysconfig/network-scripts/ifcfg-<xsl:value-of
select="$iface"/></xsl:attribute>
+ <node label="DEVICE" value="{$iface}"/>
+ <node label="VLAN" value="yes"/>
+ </xsl:template>
+
+ <xsl:template name='bare-vlan-interface'>
+ <xsl:call-template name='vlan-interface-common'/>
+ <xsl:call-template name="startmode"/>
+ <xsl:call-template name="mtu"/>
+ <!-- nothing to do for vlan-device -->
+ </xsl:template>
+
+ <!--
+ Bridge
+ -->
+ <xsl:template match="/interface[@type = 'bridge']">
+ <tree>
+ <xsl:call-template name="name-attr"/>
+ <xsl:call-template name="startmode"/>
+ <xsl:call-template name="mtu"/>
+ <node label="TYPE" value="Bridge"/>
+ <xsl:call-template name="interface-addressing"/>
+ <xsl:if test="bridge/@stp">
+ <node label="STP" value="{bridge/@stp}"/>
+ </xsl:if>
+ <xsl:if test="bridge/@delay">
+ <node label="DELAY" value="{bridge/@delay}"/>
+ </xsl:if>
+ </tree>
+ <xsl:for-each select='bridge/interface'>
+ <tree>
+ <xsl:if test="@type = 'ethernet'">
+ <xsl:call-template name="bare-ethernet-interface"/>
+ </xsl:if>
+ <xsl:if test="@type = 'vlan'">
+ <xsl:call-template name="bare-vlan-interface"/>
+ </xsl:if>
+ <xsl:if test="@type = 'bond'">
+ <xsl:call-template name="bare-bond-interface"/>
+ </xsl:if>
+ <node label="BRIDGE" value="{../../@name}"/>
+ </tree>
+ <xsl:if test="@type = 'bond'">
+ <xsl:call-template name="bond-slaves"/>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:template>
+
+ <!--
+ Bond
+ -->
+ <xsl:template name="bond-slaves">
+ <xsl:for-each select='bond/interface'>
+ <tree>
+ <xsl:call-template name="bare-ethernet-interface"/>
+ <node label="MASTER" value="{../../@name}"/>
+ <node label="SLAVE" value="yes"/>
+ </tree>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="bonding-opts-node">
+ <node label="BONDING_OPTS">
+ <xsl:attribute name="value">
+ <xsl:call-template name="bonding-opts"/>
+ </xsl:attribute>
+ </node>
+ </xsl:template>
+
+ <xsl:template name="bare-bond-interface">
+ <xsl:call-template name="name-attr"/>
+ <xsl:call-template name="startmode"/>
+ <xsl:call-template name="mtu"/>
+ <xsl:call-template name="bonding-opts-node"/>
+ </xsl:template>
+
+ <xsl:template match="/interface[@type = 'bond']">
+ <tree>
+ <xsl:call-template name="name-attr"/>
+ <xsl:call-template name="startmode"/>
+ <xsl:call-template name="mtu"/>
+ <xsl:call-template name="interface-addressing"/>
+ <xsl:call-template name="bonding-opts-node"/>
+ </tree>
+ <xsl:call-template name="bond-slaves"/>
+ </xsl:template>
+
+ <!--
+ Named templates, following the Relax NG syntax
+ -->
+ <xsl:template name="name-attr">
+ <xsl:attribute
name="path">/files/etc/sysconfig/network-scripts/ifcfg-<xsl:value-of
select="@name"/></xsl:attribute>
+ <node label="DEVICE" value="{@name}"/>
+ </xsl:template>
+
+ <xsl:template name="mtu">
+ <xsl:if test="$g_mtu != ''">
+ <node label="MTU" value="{$g_mtu}"/>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="bare-ethernet-interface">
+ <xsl:call-template name="name-attr"/>
+ <xsl:if test="mac">
+ <node label="HWADDR" value="{mac/@address}"/>
+ </xsl:if>
+ <xsl:call-template name="startmode"/>
+ <xsl:call-template name="mtu"/>
+ </xsl:template>
+
+ <xsl:template name="startmode">
+ <xsl:choose>
+ <xsl:when test="$g_startmode = 'onboot'">
+ <node label="ONBOOT" value="yes"/>
+ </xsl:when>
+ <xsl:when test="$g_startmode = 'none'">
+ <node label="ONBOOT" value="no"/>
+ </xsl:when>
+ <xsl:when test="$g_startmode = 'hotplug'">
+ <node label="ONBOOT" value="no"/>
+ <node label="HOTPLUG" value="yes"/>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="interface-addressing">
+ <xsl:for-each select="protocol[@family='ipv4']">
+ <xsl:call-template name="protocol-ipv4"/>
+ </xsl:for-each>
+ <xsl:for-each select="protocol[@family='ipv6']">
+ <xsl:call-template name="protocol-ipv6"/>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template name="protocol-ipv4">
+ <xsl:choose>
+ <xsl:when test="dhcp">
+ <node label="BOOTPROTO" value="dhcp"/>
+ <xsl:if test="dhcp/@peerdns">
+ <node label="PEERDNS" value="{dhcp/@peerdns}"/>
+ </xsl:if>
+ </xsl:when>
+ <xsl:when test="ip">
+ <node label="BOOTPROTO" value="none"/>
+ <node label="IPADDR" value="{ip/@address}"/>
+ <xsl:if test="ip/@prefix">
+ <node label="NETMASK"
value="{ipcalc:netmask(ip/@prefix)}"/>
+ </xsl:if>
+ <xsl:if test="route">
+ <node label="GATEWAY" value="{route/@gateway}"/>
+ </xsl:if>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="protocol-ipv6">
+ <node label="IPV6INIT" value="yes"/>
+ <xsl:if test="count(autoconf) > 0">
+ <node label="IPV6_AUTOCONF" value="yes"/>
+ </xsl:if>
+ <xsl:if test="count(autoconf) = 0">
+ <node label="IPV6_AUTOCONF" value="no"/>
+ </xsl:if>
+ <xsl:if test="count(dhcp) > 0">
+ <node label="DHCPV6" value="yes"/>
+ </xsl:if>
+ <xsl:if test="count(dhcp) = 0">
+ <node label="DHCPV6" value="no"/>
+ </xsl:if>
+ <xsl:if test="count(ip) > 0">
+ <node label="IPV6ADDR">
+ <xsl:attribute name="value">
+ <xsl:value-of select="ip[1]/@address"/><xsl:if
test="ip[1]/@prefix">/<xsl:value-of
select="ip[1]/@prefix"/></xsl:if>
+ </xsl:attribute>
+ </node>
+ </xsl:if>
+ <xsl:if test="count(ip) > 1">
+ <node label="IPV6ADDR_SECONDARIES">
+ <xsl:attribute name="value">
+ <xsl:text>'</xsl:text>
+ <xsl:for-each
select="ip[1]/following-sibling::ip[following-sibling::ip]">
+ <xsl:value-of select="@address"/><xsl:if
test="@prefix">/<xsl:value-of
select="@prefix"/></xsl:if><xsl:value-of select="string('
')"/>
+ </xsl:for-each>
+ <xsl:for-each select="ip[last()]">
+ <xsl:value-of select="@address"/><xsl:if
test="@prefix">/<xsl:value-of
select="@prefix"/></xsl:if>
+ </xsl:for-each>
+ <xsl:text>'</xsl:text>
+ </xsl:attribute>
+ </node>
+ </xsl:if>
+ <xsl:if test="route">
+ <node label="IPV6_DEFAULTGW" value="{route/@gateway}"/>
+ </xsl:if>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/data/xml/redhat-put.xsl b/data/xml/redhat-put.xsl
new file mode 100644
index 0000000..267d9cd
--- /dev/null
+++ b/data/xml/redhat-put.xsl
@@ -0,0 +1,270 @@
+<?xml version="1.0"?>
+<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:ipcalc = "http://redhat.com/xslt/netcf/ipcalc/1.0"
+ xmlns:bond = "http://redhat.com/xslt/netcf/bond/1.0"
+
xmlns:str="http://exslt.org/strings"
+ extension-element-prefixes="bond ipcalc str"
+ version="1.0">
+
+ <xsl:import href="util-put.xsl"/>
+
+ <xsl:output method="xml" indent="yes"/>
+ <xsl:strip-space elements="*"/>
+
+ <xsl:template match="/">
+ <xsl:apply-templates select="*"/>
+ </xsl:template>
+
+ <!--
+ Ethernet adapter
+ -->
+ <xsl:template name="ethernet-interface"
+ match="tree[count(node[@label = 'MASTER' or
@label='BRIDGE'
+ or @label = 'VLAN']) = 0]">
+ <interface type="ethernet">
+ <xsl:call-template name="name-attr"/>
+ <xsl:call-template name="startmode"/>
+ <xsl:if test="node[@label = 'HWADDR']">
+ <mac address="{node[@label = 'HWADDR']/@value}"/>
+ </xsl:if>
+ <xsl:call-template name="mtu"/>
+ <xsl:call-template name="interface-addressing"/>
+ </interface>
+ </xsl:template>
+
+ <!--
+ VLAN's
+ -->
+ <xsl:template name="vlan-interface"
+ match="tree[node[@label = 'VLAN' and @value =
'yes']][count(node[@label = 'MASTER' or @label='BRIDGE']) =
0]">
+ <interface type="vlan">
+ <xsl:call-template name="name-attr"/>
+ <xsl:call-template name="startmode"/>
+ <xsl:call-template name="mtu"/>
+ <xsl:call-template name="interface-addressing"/>
+ <xsl:call-template name="vlan-device"/>
+ </interface>
+ </xsl:template>
+
+ <xsl:template name="bare-vlan-interface">
+ <xsl:variable name="name" select="node[@label =
'DEVICE']/@value"/>
+ <interface type="vlan">
+ <xsl:call-template name="name-attr"/>
+ <xsl:call-template name="vlan-device"/>
+ </interface>
+ </xsl:template>
+
+ <xsl:template name="vlan-device">
+ <xsl:variable name="name" select="node[@label =
'DEVICE']/@value"/>
+ <xsl:variable name="device" select="substring-before($name,
'.')"/>
+ <xsl:variable name="tag" select="substring-after($name,
'.')"/>
+ <vlan tag="{$tag}">
+ <interface name="{$device}"/>
+ </vlan>
+ </xsl:template>
+
+ <!--
+ Bridge
+ -->
+ <xsl:template name="bridge-interface"
+ match="tree[node[@label = 'TYPE' and @value =
'Bridge']]">
+ <interface type="bridge">
+ <!-- the bridge node itself -->
+ <xsl:variable name="iface" select="node[@label=
'DEVICE']/@value"/>
+ <xsl:call-template name="name-attr"/>
+ <xsl:call-template name="startmode"/>
+ <xsl:call-template name="mtu"/>
+ <xsl:call-template name="interface-addressing"/>
+ <bridge>
+ <xsl:if test="node[@label = 'STP']">
+ <xsl:attribute name="stp"><xsl:value-of
select="node[@label = 'STP']/@value"/></xsl:attribute>
+ </xsl:if>
+ <xsl:if test="node[@label = 'DELAY']">
+ <xsl:attribute name="delay"><xsl:value-of
select="node[@label = 'DELAY']/@value"/></xsl:attribute>
+ </xsl:if>
+ <xsl:for-each select="/descendant-or-self::*[node[@label =
'BRIDGE' and @value = $iface]]">
+ <xsl:if test="count(node[@label = 'VLAN' or @label =
'BONDING_OPTS']) = 0">
+ <xsl:call-template name="bare-ethernet-interface"/>
+ </xsl:if>
+ <xsl:if test="count(node[@label = 'BONDING_OPTS']) >
0">
+ <xsl:call-template name="bare-bond-interface"/>
+ </xsl:if>
+ <xsl:if test="count(node[@label = 'VLAN']) > 0">
+ <xsl:call-template name="bare-vlan-interface"/>
+ </xsl:if>
+ </xsl:for-each>
+ </bridge>
+ </interface>
+ </xsl:template>
+
+ <!--
+ Bond
+ -->
+ <xsl:template name="bond-element">
+ <xsl:variable name="iface" select="node[@label=
'DEVICE']/@value"/>
+ <bond>
+ <xsl:variable name="opts" select="node[@label =
'BONDING_OPTS']/@value"/>
+ <xsl:call-template name="bonding-opts">
+ <xsl:with-param name="opts" select="$opts"/>
+ </xsl:call-template>
+ <xsl:variable name="primary" select="bond:option($opts,
'primary')"/>
+ <xsl:for-each select="/descendant-or-self::*[node[@label = 'MASTER'
and @value = $iface]][node[@label = 'DEVICE' and @value = $primary]]">
+ <xsl:call-template name='bare-ethernet-interface'/>
+ </xsl:for-each>
+ <xsl:for-each select="/descendant-or-self::*[node[@label = 'MASTER'
and @value = $iface]][node[@label = 'DEVICE' and @value != $primary]]">
+ <xsl:call-template name='bare-ethernet-interface'/>
+ </xsl:for-each>
+ </bond>
+ </xsl:template>
+
+ <xsl:template name="bare-bond-interface">
+ <interface type="bond">
+ <xsl:call-template name="name-attr"/>
+ <xsl:call-template name="bond-element"/>
+ </interface>
+ </xsl:template>
+
+ <xsl:template name="bond-interface"
+ match="tree[node[@label = 'DEVICE'][@value =
//tree/node[@label = 'MASTER']/@value]][count(node[@label = 'BRIDGE']) =
0]">
+ <interface type="bond">
+ <xsl:call-template name="name-attr"/>
+ <xsl:call-template name="startmode"/>
+ <xsl:call-template name="mtu"/>
+ <xsl:call-template name="interface-addressing"/>
+ <xsl:call-template name="bond-element"/>
+ </interface>
+ </xsl:template>
+
+ <!--
+ Utility templates, names follow the names in interface.rng
+ -->
+ <xsl:template name="startmode">
+ <xsl:choose>
+ <xsl:when test="node[@label ='HOTPLUG']/@value =
'yes'">
+ <start mode='hotplug'/>
+ </xsl:when>
+ <xsl:when test="node[@label = 'ONBOOT']/@value =
'yes'">
+ <start mode='onboot'/>
+ </xsl:when>
+ <xsl:otherwise>
+ <start mode='none'/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="name-attr">
+ <xsl:attribute name="name">
+ <xsl:value-of select="node[@label= 'DEVICE']/@value"/>
+ </xsl:attribute>
+ </xsl:template>
+
+ <xsl:template name="mtu">
+ <xsl:if test="node[@label='MTU']">
+ <mtu size="{node[@label='MTU']/@value}"/>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="interface-addressing">
+ <xsl:call-template name="protocol-ipv4"/>
+ <xsl:call-template name="protocol-ipv6"/>
+ </xsl:template>
+
+ <xsl:template name="protocol-ipv4">
+ <xsl:variable name="uses_dhcp"
+ select="node[@label = 'BOOTPROTO']/@value =
'dhcp'"/>
+ <xsl:variable name="uses_static"
+ select="count(node[@label = 'IPADDR']) > 0"/>
+ <xsl:variable name="uses_ipv4" select="$uses_dhcp or
$uses_static"/>
+ <xsl:if test="$uses_ipv4">
+ <protocol family="ipv4">
+ <xsl:choose>
+ <xsl:when test="$uses_dhcp">
+ <dhcp>
+ <xsl:if test="node[@label = 'PEERDNS']">
+ <xsl:attribute name="peerdns"><xsl:value-of
select="node[@label =
'PEERDNS']/@value"></xsl:value-of></xsl:attribute>
+ </xsl:if>
+ </dhcp>
+ </xsl:when>
+ <xsl:when test="$uses_static">
+ <ip address="{node[@label = 'IPADDR']/@value}">
+ <xsl:choose>
+ <xsl:when test="node[@label = 'PREFIX']">
+ <xsl:attribute name="prefix"><xsl:value-of
select="node[@label = 'PREFIX']/@value"/></xsl:attribute>
+ </xsl:when>
+ <xsl:when test="node[@label = 'NETMASK']">
+ <xsl:attribute name="prefix"><xsl:value-of
select="ipcalc:prefix(node[@label =
'NETMASK']/@value)"/></xsl:attribute>
+ </xsl:when>
+ </xsl:choose>
+ </ip>
+ <xsl:if test="node[@label = 'GATEWAY']">
+ <route gateway="{node[@label = 'GATEWAY']/@value}"/>
+ </xsl:if>
+ </xsl:when>
+ </xsl:choose>
+ </protocol>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="protocol-ipv6">
+ <xsl:if test="node[@label = 'IPV6INIT'][@value =
'yes']">
+ <protocol family="ipv6">
+ <xsl:if test="node[@label = 'IPV6_AUTOCONF'][@value =
'yes']">
+ <autoconf/>
+ </xsl:if>
+ <xsl:if test="node[@label = 'DHCPV6'][@value =
'yes']">
+ <dhcp/>
+ </xsl:if>
+ <xsl:if test="node[@label = 'IPV6ADDR']">
+ <xsl:call-template name="ipv6-address">
+ <xsl:with-param name="value"
+ select="node[@label =
'IPV6ADDR']/@value"/>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="node[@label = 'IPV6ADDR_SECONDARIES']">
+ <!-- Strip surrounding single quotes from $s -->
+ <xsl:variable name="s"
+ select="node[@label =
'IPV6ADDR_SECONDARIES']/@value"/>
+ <xsl:variable name="q">'</xsl:variable>
+ <xsl:variable name="sec">
+ <xsl:choose>
+ <xsl:when test="starts-with($s, $q)">
+ <xsl:value-of select="substring($s, 2,
string-length($s)-2)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$s"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:for-each select="str:split($sec)">
+ <xsl:call-template name="ipv6-address">
+ <xsl:with-param name="value" select="."/>
+ </xsl:call-template>
+ </xsl:for-each>
+ </xsl:if>
+ </protocol>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="ipv6-address">
+ <xsl:param name="value"/>
+ <xsl:variable name="address" select="substring-before($value,
'/')"/>
+ <xsl:variable name="prefix" select="substring-after($value,
'/')"/>
+ <ip address="{$address}">
+ <xsl:if test="$prefix != ''">
+ <xsl:attribute name="prefix"><xsl:value-of
select="$prefix"/></xsl:attribute>
+ </xsl:if>
+ </ip>
+ <xsl:if test="node[@label = 'IPV6_DEFAULTGW']">
+ <route gateway="{node[@label =
'IPV6_DEFAULTGW']/@value}"/>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="bare-ethernet-interface">
+ <interface type="ethernet">
+ <xsl:call-template name="name-attr"/>
+ <xsl:if test="node[@label = 'HWADDR']">
+ <mac address="{node[@label = 'HWADDR']/@value}"/>
+ </xsl:if>
+ </interface>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/src/Makefile.am b/src/Makefile.am
index 5595581..c652fad 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -17,8 +17,8 @@ EXTRA_DIST = netcf_public.syms \
netcf_private.syms \
netcf-transaction.init.sh
-if NETCF_DRIVER_INITSCRIPTS
-DRIVER_SOURCES = drv_initscripts.c dutil.h dutil.c \
+if NETCF_DRIVER_REDHAT
+DRIVER_SOURCES = drv_redhat.c dutil.h dutil.c \
dutil_linux.h dutil_linux.c
endif
diff --git a/src/drv_initscripts.c b/src/drv_initscripts.c
deleted file mode 100644
index 7b2930d..0000000
--- a/src/drv_initscripts.c
+++ /dev/null
@@ -1,1182 +0,0 @@
-/*
- * drv_initscripts.c: the initscripts backend for netcf
- *
- * Copyright (C) 2009 Red Hat Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: David Lutterkort <lutter(a)redhat.com>
- */
-
-#include <config.h>
-#include <internal.h>
-
-#include <augeas.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-#include "safe-alloc.h"
-#include "ref.h"
-#include "list.h"
-#include "dutil.h"
-#include "dutil_linux.h"
-
-#include <libxml/parser.h>
-#include <libxml/relaxng.h>
-#include <libxml/tree.h>
-#include <libxslt/xslt.h>
-#include <libxslt/xsltInternals.h>
-#include <libxslt/transform.h>
-#include <libxslt/xsltutils.h>
-
-#include <libexslt/exslt.h>
-
-static const char *const network_scripts_path =
- "/files/etc/sysconfig/network-scripts";
-
-static const char *const ifcfg_path =
- "/files/etc/sysconfig/network-scripts/*";
-
-/* Augeas should only load the files we are interested in */
-static const struct augeas_pv augeas_xfm_common_pv[] = {
- /* Ifcfg files */
- { "/augeas/load/Ifcfg/lens", "Sysconfig.lns" },
- { "/augeas/load/Ifcfg/incl",
- "/etc/sysconfig/network-scripts/ifcfg-*" },
- { "/augeas/load/Ifcfg/excl[1]", "*~" },
- { "/augeas/load/Ifcfg/excl[2]", "*.bak" },
- { "/augeas/load/Ifcfg/excl[3]", "*.orig" },
- { "/augeas/load/Ifcfg/excl[4]", "*.rpmnew" },
- { "/augeas/load/Ifcfg/excl[5]", "*.rpmorig" },
- { "/augeas/load/Ifcfg/excl[6]", "*.rpmsave" },
- { "/augeas/load/Ifcfg/excl[7]", "*.augnew" },
- { "/augeas/load/Ifcfg/excl[8]", "*.augsave" },
- /* modprobe config */
- { "/augeas/load/Modprobe/lens", "Modprobe.lns" },
- { "/augeas/load/Modprobe/incl[1]", "/etc/modprobe.d/*" },
- { "/augeas/load/Modprobe/incl[2]", "/etc/modprobe.conf" },
- { "/augeas/load/Modprobe/excl[1]", "*.augnew" },
- { "/augeas/load/Modprobe/excl[2]", "*.augsave" },
- { "/augeas/load/Modprobe/excl[3]", "*.rpmsave" },
- { "/augeas/load/Modprobe/excl[4]", "*.rpmnew" },
- { "/augeas/load/Modprobe/excl[5]", "*~" },
- /* sysfs (choice entries from /class/net) */
- { "/augeas/load/Sysfs/lens", "Netcf.id" },
- { "/augeas/load/Sysfs/incl", "/sys/class/net/*/address" }
-};
-
-static const struct augeas_xfm_table augeas_xfm_common =
- { .size = ARRAY_CARDINALITY(augeas_xfm_common_pv),
- .pv = augeas_xfm_common_pv };
-
-/* Entries in a ifcfg file that tell us that the interface
- * is not a toplevel interface
- */
-static const char *const subif_paths[] = {
- "MASTER", "BRIDGE"
-};
-
-static int is_slave(struct netcf *ncf, const char *intf) {
- for (int s = 0; s < ARRAY_CARDINALITY(subif_paths); s++) {
- int r;
- r = aug_fmt_match(ncf, NULL, "%s/%s", intf, subif_paths[s]);
- if (r != 0)
- return r;
- }
- return 0;
-}
-
-static bool has_ifcfg_file(struct netcf *ncf, const char *name) {
- int nmatches;
-
- nmatches = aug_fmt_match(ncf, NULL,
- "%s[ DEVICE = '%s'"
- " or BRIDGE = '%s'"
- " or MASTER = '%s'"
- " or MASTER = ../*[BRIDGE = '%s']/DEVICE
]/DEVICE",
- ifcfg_path, name, name, name, name);
- return nmatches > 0;
-}
-
-static int cmpstrp(const void *p1, const void *p2) {
- const char *s1 = * (const char **)p1;
- const char *s2 = * (const char **)p2;
- return strcmp(s1, s2);
-}
-
-/* Find the path to the ifcfg file that has the configuration for the
- * interface with MAC address MAC.
- */
-static char *find_ifcfg_path_by_hwaddr(struct netcf *ncf, const char *mac) {
- static const char *const hwaddr_str = "/HWADDR";
-
- int nhwaddr = 0, r;
- char **hwaddr = NULL;
- struct augeas *aug = NULL;
-
- aug = get_augeas(ncf);
- ERR_BAIL(ncf);
-
- // It would be nice if Augeas provided a way to do case-insensitive
- // matching. For now, we just write it out
- nhwaddr = aug_fmt_match(ncf, &hwaddr, "%s%s", ifcfg_path, hwaddr_str);
- ERR_COND_BAIL(nhwaddr < 0, ncf, EOTHER);
-
- /* Sort because need_config will return the last match in case
- * of multiple matches */
- qsort(hwaddr, nhwaddr, sizeof(*hwaddr), cmpstrp);
- int match = -1;
- for (int i=0; i < nhwaddr; i++) {
- const char *addr;
- r = aug_get(aug, hwaddr[i], &addr);
- ERR_COND_BAIL(r != 1, ncf, EOTHER);
- if (STRCASEEQ(addr, mac))
- match = i;
- }
- if (match != -1) {
- char *path = hwaddr[match];
- hwaddr[match] = NULL;
- path[strlen(path) - strlen(hwaddr_str)] = '\0';
- free_matches(nhwaddr, &hwaddr);
- return path;
- }
- error:
- free_matches(nhwaddr, &hwaddr);
- return NULL;
-}
-
-/* Find the path to the ifcfg file that has the configuration for the
- * interface by checking for an entry 'DEVICE=NAME'
- */
-static char *find_ifcfg_path_by_device(struct netcf *ncf, const char *name) {
- struct augeas *aug = NULL;
- int ndevs = 0;
- char **devs = NULL;
-
- aug = get_augeas(ncf);
- ERR_BAIL(ncf);
-
- ndevs = aug_fmt_match(ncf, &devs, "%s[DEVICE = '%s']",
- ifcfg_path, name);
- ERR_COND_BAIL(ndevs < 0, ncf, EOTHER);
-
- if (ndevs == 0)
- return NULL;
-
- qsort(devs, ndevs, sizeof(*devs), cmpstrp);
-
- char *path = devs[ndevs - 1];
- devs[ndevs - 1] = NULL;
-
- free_matches(ndevs, &devs);
-
- return path;
- error:
- free_matches(ndevs, &devs);
- return NULL;
-}
-
-/* Find the path to the ifcfg file that has the configuration for
- * the device NAME. The logic follows the need_config function
- * in /etc/sysconfig/network-scripts/network-functions
- */
-static char *find_ifcfg_path(struct netcf *ncf, const char *name) {
- struct augeas *aug = NULL;
- char *path = NULL;
- const char *mac = NULL;
- int r, nmatches;
-
- aug = get_augeas(ncf);
- ERR_BAIL(ncf);
-
- /* if ifcfg-NAME exists, use that */
- r = xasprintf(&path, "%s/ifcfg-%s", network_scripts_path, name);
- ERR_NOMEM(r < 0, ncf);
-
- nmatches = aug_match(aug, path, NULL);
- ERR_COND_BAIL(nmatches < 0, ncf, EOTHER);
-
- if (nmatches == 1)
- return path;
-
- FREE(path);
-
- /* Now find the config by MAC, matching on HWADDR */
- r = aug_get_mac(ncf, name, &mac);
- ERR_COND_BAIL(r < 0, ncf, EOTHER);
- if (r > 0) {
- path = find_ifcfg_path_by_hwaddr(ncf, mac);
- ERR_BAIL(ncf);
- if (path != NULL)
- return path;
- }
-
- path = find_ifcfg_path_by_device(ncf, name);
- ERR_BAIL(ncf);
-
- return path;
- error:
- FREE(path);
- return NULL;
-}
-
-/* Given NDEVS path to DEVICE entries which may contain duplicate devices,
- * produce a list of canonical paths to the interfaces in INTF and return
- * the number of entries. Return -1 on error
- */
-static int uniq_ifcfg_paths(struct netcf *ncf,
- int ndevs, char **devs,
- char ***intf) {
- struct augeas *aug;
- int r;
- int ndevnames = 0;
- const char **devnames = NULL;
-
- aug = get_augeas(ncf);
- ERR_BAIL(ncf);
-
- /* List unique device names */
- r = ALLOC_N(devnames, ndevs);
- ERR_NOMEM(r < 0, ncf);
-
- for (int i=0; i < ndevs; i++) {
- const char *name = NULL;
- r = aug_get(aug, devs[i], &name);
- ERR_COND_BAIL(r != 1, ncf, EOTHER);
- int exists = 0;
- for (int j = 0; j < ndevnames; j++)
- if (STREQ(name, devnames[j])) {
- exists = 1;
- break;
- }
- if (!exists)
- devnames[ndevnames++] = name;
- }
- qsort(devnames, ndevnames, sizeof(*devnames), cmpstrp);
-
- /* Find canonical config for each device name */
- r = ALLOC_N(*intf, ndevnames);
- ERR_NOMEM(r < 0, ncf);
- for (int i= 0; i < ndevnames; i++) {
- (*intf)[i] = find_ifcfg_path(ncf, devnames[i]);
- ERR_BAIL(ncf);
- }
-
- FREE(devnames);
- return ndevnames;
-
- error:
- FREE(devnames);
- free_matches(ndevnames, intf);
- return -1;
-}
-
-/* List all configured network devices; returns the number of devices or -1
- * on error. On success, the path to the config file for each interface
- * is returned in INTF
- */
-static int list_ifcfg_paths(struct netcf *ncf, char ***intf) {
- int result = 0, ndevs;
- char **devs = NULL;
-
- ndevs = aug_fmt_match(ncf, &devs, "%s/DEVICE", ifcfg_path);
- ERR_COND_BAIL(ndevs < 0, ncf, EOTHER);
-
- result = uniq_ifcfg_paths(ncf, ndevs, devs, intf);
- ERR_BAIL(ncf);
-
- free_matches(ndevs, &devs);
- return result;
-
- error:
- free_matches(ndevs, &devs);
- return -1;
-}
-
-static int list_interfaces(struct netcf *ncf, char ***intf) {
- int nint = 0, result = 0;
- struct augeas *aug = NULL;
-
- aug = get_augeas(ncf);
- ERR_BAIL(ncf);
-
- /* Look in augeas for all interfaces */
- nint = list_ifcfg_paths(ncf, intf);
- ERR_BAIL(ncf);
- result = nint;
-
- /* Filter out the interfaces that are slaves/subordinate */
- for (int i = 0; i < result;) {
- if (is_slave(ncf, (*intf)[i])) {
- FREE((*intf)[i]);
- memmove(*intf + i, *intf + i + 1,
- (nint - (i + 1))*sizeof((*intf)[0]));
- result -= 1;
- } else {
- i += 1;
- }
- }
- return result;
- error:
- free_matches(nint, intf);
- return -1;
-}
-
-int drv_init(struct netcf *ncf) {
- int r;
- struct stat stats;
-
- if (ALLOC(ncf->driver) < 0)
- return -1;
-
- ncf->driver->ioctl_fd = -1;
-
- r = add_augeas_xfm_table(ncf, &augeas_xfm_common);
- if (r < 0)
- goto error;
-
- if (stat(ncf->root, &stats) != 0 || !S_ISDIR(stats.st_mode)) {
- report_error(ncf, NETCF_EFILE,
- "invalid root '%s' is not a directory",
ncf->root);
- goto error;
- }
-
- // FIXME: Check for errors
- xsltInit();
- exsltStrRegister();
- ncf->driver->get = parse_stylesheet(ncf, "initscripts-get.xsl");
- ncf->driver->put = parse_stylesheet(ncf, "initscripts-put.xsl");
- ERR_BAIL(ncf);
-
- /* open a socket for interface ioctls */
- ncf->driver->ioctl_fd = init_ioctl_fd(ncf);
- if (ncf->driver->ioctl_fd < 0)
- goto error;
- if (netlink_init(ncf) < 0)
- goto error;
- return 0;
-
- error:
- drv_close(ncf);
- return -1;
-}
-
-void drv_close(struct netcf *ncf) {
- if (ncf == NULL || ncf->driver == NULL)
- return;
- xsltFreeStylesheet(ncf->driver->get);
- xsltFreeStylesheet(ncf->driver->put);
- netlink_close(ncf);
- if (ncf->driver->ioctl_fd >= 0)
- close(ncf->driver->ioctl_fd);
- aug_close(ncf->driver->augeas);
- FREE(ncf->driver->augeas_xfm_tables);
- FREE(ncf->driver);
-}
-
-void drv_entry(struct netcf *ncf) {
- ncf->driver->load_augeas = 1;
-}
-
-static int list_interface_ids(struct netcf *ncf,
- int maxnames, char **names,
- unsigned int flags,
- const char *id_attr) {
- struct augeas *aug = NULL;
- int nint = 0, nmatches = 0, nqualified = 0, result = 0, r;
- char **intf = NULL, **matches = NULL;
-
- aug = get_augeas(ncf);
- ERR_BAIL(ncf);
- nint = list_interfaces(ncf, &intf);
- ERR_BAIL(ncf);
- if (!names) {
- maxnames = nint; /* if not returning list, ignore maxnames too */
- }
- for (result = 0; (result < nint) && (nqualified < maxnames); result++)
{
- nmatches = aug_fmt_match(ncf, &matches,
- "%s/%s", intf[result], id_attr);
- ERR_BAIL(ncf);
- if (nmatches > 0) {
- const char *name;
- int is_qualified = ((flags & (NETCF_IFACE_ACTIVE|NETCF_IFACE_INACTIVE))
- == (NETCF_IFACE_ACTIVE|NETCF_IFACE_INACTIVE));
-
- r = aug_get(aug, matches[nmatches-1], &name);
- ERR_COND_BAIL(r < 0, ncf, EOTHER);
-
- if (!is_qualified) {
- int is_active = if_is_active(ncf, name);
- if ((is_active && (flags & NETCF_IFACE_ACTIVE))
- || ((!is_active) && (flags & NETCF_IFACE_INACTIVE))) {
-
- is_qualified = 1;
- }
- }
-
- if (is_qualified) {
- if (names) {
- names[nqualified] = strdup(name);
- ERR_NOMEM(names[nqualified] == NULL, ncf);
- }
- nqualified++;
- }
- }
- free_matches(nmatches, &matches);
- }
- free_matches(nint, &intf);
- return nqualified;
- error:
- free_matches(nmatches, &matches);
- free_matches(nint, &intf);
- return -1;
-}
-
-int drv_list_interfaces(struct netcf *ncf, int maxnames, char **names,
- unsigned int flags) {
- return list_interface_ids(ncf, maxnames, names, flags, "DEVICE");
-}
-
-int drv_num_of_interfaces(struct netcf *ncf, unsigned int flags) {
- return list_interface_ids(ncf, 0, NULL, flags, "DEVICE");
-}
-
-struct netcf_if *drv_lookup_by_name(struct netcf *ncf, const char *name) {
- struct netcf_if *nif = NULL;
- char *pathx = NULL;
- char *name_dup = NULL;
- struct augeas *aug;
-
- aug = get_augeas(ncf);
- ERR_BAIL(ncf);
-
- pathx = find_ifcfg_path(ncf, name);
- ERR_BAIL(ncf);
-
- if (pathx == NULL || is_slave(ncf, pathx))
- goto done;
-
- name_dup = strdup(name);
- ERR_NOMEM(name_dup == NULL, ncf);
-
- nif = make_netcf_if(ncf, name_dup);
- ERR_BAIL(ncf);
- goto done;
-
- error:
- unref(nif, netcf_if);
- FREE(name_dup);
- done:
- FREE(pathx);
- return nif;
-}
-
-/* Get an XML desription of the interfaces (just paths, really) in INTF.
- * The format is a very simple representation of the Augeas tree (see
- * xml/augeas.rng)
- */
-static xmlDocPtr aug_get_xml(struct netcf *ncf, int nint, char **intf) {
- struct augeas *aug;
- xmlDocPtr result = NULL;
- xmlNodePtr root = NULL, tree = NULL;
- char **matches = NULL;
- int nmatches, r;
-
- aug = get_augeas(ncf);
- ERR_BAIL(ncf);
-
- result = xmlNewDoc(BAD_CAST "1.0");
- root = xmlNewNode(NULL, BAD_CAST "forest");
- xmlDocSetRootElement(result, root);
-
- for (int i=0; i < nint; i++) {
- tree = xmlNewChild(root, NULL, BAD_CAST "tree", NULL);
- xmlNewProp(tree, BAD_CAST "path", BAD_CAST intf[i]);
- nmatches = aug_fmt_match(ncf, &matches, "%s/%s", intf[i],
"*");
- ERR_COND_BAIL(nint < 0, ncf, EOTHER);
- for (int j = 0; j < nmatches; j++) {
- xmlNodePtr node = xmlNewChild(tree, NULL, BAD_CAST "node", NULL);
- const char *value;
- xmlNewProp(node, BAD_CAST "label",
- BAD_CAST matches[j] + strlen(intf[i]) + 1);
- r = aug_get(aug, matches[j], &value);
- ERR_COND_BAIL(r < 0, ncf, EOTHER);
- xmlNewProp(node, BAD_CAST "value", BAD_CAST value);
- }
- free_matches(nmatches, &matches);
- }
-
- return result;
-
- error:
- free_matches(nmatches, &matches);
- xmlFreeDoc(result);
- return NULL;
-}
-
-/* Write the XML doc in the simple Augeas format into the Augeas tree */
-static int aug_put_xml(struct netcf *ncf, xmlDocPtr xml) {
- xmlNodePtr forest;
- char *path = NULL, *lpath = NULL, *label = NULL, *value = NULL;
- struct augeas *aug = NULL;
- int result = -1;
- int r;
-
- aug = get_augeas(ncf);
- ERR_BAIL(ncf);
-
- forest = xmlDocGetRootElement(xml);
- ERR_THROW(forest == NULL, ncf, EINTERNAL, "missing root element");
- ERR_THROW(! xmlStrEqual(forest->name, BAD_CAST "forest"), ncf,
- EINTERNAL, "expected root node labeled 'forest', not
'%s'",
- forest->name);
- list_for_each(tree, forest->children) {
- ERR_THROW(! xmlStrEqual(tree->name, BAD_CAST "tree"), ncf,
- EINTERNAL, "expected node labeled 'tree', not
'%s'",
- tree->name);
- path = xml_prop(tree, "path");
- int toplevel = 1;
- /* This is a little drastic, since it clears out the file entirely */
- r = aug_rm(aug, path);
- ERR_THROW(r < 0, ncf, EINTERNAL, "aug_rm of '%s' failed",
path);
- list_for_each(node, tree->children) {
- label = xml_prop(node, "label");
- value = xml_prop(node, "value");
- /* We should mark the toplevel interface from the XSLT */
- if (STREQ(label, "BRIDGE") || STREQ(label, "MASTER")) {
- toplevel = 0;
- }
- r = xasprintf(&lpath, "%s/%s", path, label);
- ERR_NOMEM(r < 0, ncf);
-
- r = aug_set(aug, lpath, value);
- ERR_THROW(r < 0, ncf, EOTHER,
- "aug_set of '%s' failed", lpath);
- FREE(lpath);
- xmlFree(label);
- xmlFree(value);
- label = value = NULL;
- }
- xmlFree(path);
- path = NULL;
- }
- result = 0;
- error:
- xmlFree(label);
- xmlFree(value);
- xmlFree(path);
- FREE(lpath);
- return result;
-}
-
-/* given a netcf_if, get the config for an interface in the simple
- * Augeas format
- */
-static xmlDocPtr aug_get_xml_for_nif(struct netcf_if *nif) {
- struct netcf *ncf;
- char **devs = NULL, **intf = NULL;
- xmlDocPtr aug_xml = NULL;
- int ndevs = 0, nint = 0;
-
- ncf = nif->ncf;
- ndevs = aug_fmt_match(ncf, &devs,
- "%s[ DEVICE = '%s' or BRIDGE = '%s' or MASTER =
'%s'"
- " or MASTER = ../*[BRIDGE = '%s']/DEVICE ]/DEVICE",
- ifcfg_path, nif->name, nif->name, nif->name, nif->name);
- ERR_BAIL(ncf);
-
- nint = uniq_ifcfg_paths(ncf, ndevs, devs, &intf);
- ERR_BAIL(ncf);
-
- aug_xml = aug_get_xml(ncf, nint, intf);
-
- error:
- free_matches(ndevs, &devs);
- free_matches(nint, &intf);
- return aug_xml;
-}
-
-/* return the current static configuration (as saved on disk) */
-char *drv_xml_desc(struct netcf_if *nif) {
- char *result = NULL;
- struct netcf *ncf;
- xmlDocPtr aug_xml = NULL;
-
- ncf = nif->ncf;
- aug_xml = aug_get_xml_for_nif(nif);
- ERR_BAIL(ncf);
-
- result = apply_stylesheet_to_string(ncf, ncf->driver->put, aug_xml);
-
- error:
- xmlFreeDoc(aug_xml);
- return result;
-}
-
-/* return the current live configuration state - a combination of
- * drv_xml_desc + results of querying the interface directly */
-
-char *drv_xml_state(struct netcf_if *nif) {
- char *result = NULL;
- int r, result_len;
- struct netcf *ncf;
- xmlDocPtr ncf_xml = NULL;
- xmlNodePtr root;
-
- ncf = nif->ncf;
-
- /* start out with an empty tree rather than the config tree. Just
- * put in the interface node and its name
- */
- ncf_xml = xmlNewDoc(BAD_CAST "1.0");
- ERR_NOMEM(ncf_xml == NULL, ncf);
- root = xmlNewNode(NULL, BAD_CAST "interface");
- ERR_NOMEM(root == NULL, ncf);
- xmlDocSetRootElement(ncf_xml, root);
-
- /* add all info we can gather from the kernel/sysfs/procfs */
- add_state_to_xml_doc(nif, ncf_xml);
- ERR_BAIL(ncf);
-
- r = xsltSaveResultToString((xmlChar **)&result, &result_len,
- ncf_xml, ncf->driver->put);
- ERR_NOMEM(r < 0, ncf);
-
- done:
- xmlFreeDoc(ncf_xml);
- return result;
- error:
- FREE(result);
- result = 0;
- goto done;
-}
-
-/* Report various status info about the interface as bits in
- * "flags". Returns 0 on success, -1 on failure
- */
-int drv_if_status(struct netcf_if *nif, unsigned int *flags) {
- int is_active;
-
- ERR_THROW(flags == NULL, nif->ncf, EOTHER, "NULL pointer for flags in
ncf_if_status");
- *flags = 0;
- is_active = if_is_active(nif->ncf, nif->name);
- if (is_active)
- *flags |= NETCF_IFACE_ACTIVE;
- else
- *flags |= NETCF_IFACE_INACTIVE;
- return 0;
-error:
- return -1;
-}
-
-/* Get the content of /interface/@name. Result must be freed with xmlFree()
- *
- * The name on VLAN interfaces is optional; if there is no
- * /interface/@name, construct a name for the VLAN interface and set
- * /interface/@name in NCF_XML to it. This way, other code can assume we
- * always have a name on the interface.
- */
-static char *device_name_from_xml(struct netcf *ncf, xmlDocPtr ncf_xml) {
- xmlXPathContextPtr context = NULL;
- xmlXPathObjectPtr obj = NULL;
- char *result = NULL;
-
- context = xmlXPathNewContext(ncf_xml);
- ERR_NOMEM(context == NULL, ncf);
-
- obj = xmlXPathEvalExpression(BAD_CAST "string(/interface/@name)", context);
- ERR_NOMEM(obj == NULL, ncf);
- assert(obj->type == XPATH_STRING);
-
- if (xmlStrlen(obj->stringval) == 0) {
- xmlXPathFreeObject(obj);
- obj = xmlXPathEvalExpression(BAD_CAST
- "concat(/interface/vlan/interface/@name, '.',
/interface/vlan/@tag)",
- context);
- ERR_NOMEM(obj == NULL, ncf);
- ERR_COND_BAIL(xmlStrlen(obj->stringval) == 0, ncf, EINTERNAL);
- assert(obj->type == XPATH_STRING);
-
- xmlNodePtr iface;
- iface = xmlDocGetRootElement(ncf_xml);
- ERR_COND_BAIL(iface == NULL, ncf, EINTERNAL);
- xmlSetProp(iface, BAD_CAST "name", BAD_CAST result);
- }
-
- result = (char *) xmlStrdup(obj->stringval);
- error:
- xmlXPathFreeObject(obj);
- xmlXPathFreeContext(context);
- return result;
-}
-
-/* The device NAME is a bond if it is mentioned as the MASTER in sopme
- * other devices config file
- */
-static bool is_bond(struct netcf *ncf, const char *name) {
- int nmatches = 0;
-
- nmatches = aug_fmt_match(ncf, NULL,
- "%s[ MASTER = '%s']", ifcfg_path, name);
- return nmatches > 0;
-}
-
-/* The device NAME is a bridge if it has an entry TYPE=Bridge */
-static bool is_bridge(struct netcf *ncf, const char *name) {
- int nmatches = 0;
-
- nmatches = aug_fmt_match(ncf, NULL,
- "%s[ DEVICE = '%s' and TYPE =
'Bridge']",
- ifcfg_path, name);
- return nmatches > 0;
-}
-
-static int bridge_slaves(struct netcf *ncf, const char *name, char ***slaves) {
- struct augeas *aug = NULL;
- int r, nslaves = 0;
-
- aug = get_augeas(ncf);
- ERR_BAIL(ncf);
-
- nslaves = aug_fmt_match(ncf, slaves,
- "%s[ BRIDGE = '%s' ]/DEVICE", ifcfg_path,
name);
- ERR_BAIL(ncf);
- for (int i=0; i < nslaves; i++) {
- char *p = (*slaves)[i];
- const char *dev;
- r = aug_get(aug, p, &dev);
- ERR_COND_BAIL(r < 0, ncf, EOTHER);
-
- (*slaves)[i] = strdup(dev);
- free(p);
- ERR_NOMEM(slaves[i] == NULL, ncf);
- }
- return nslaves;
- error:
- free_matches(nslaves, slaves);
- return -1;
-}
-
-
-/* For an interface NAME, remove the ifcfg-* files for that interface and
- * all its slaves. */
-static void rm_interface(struct netcf *ncf, const char *name) {
- int r;
- char *path = NULL;
- struct augeas *aug = NULL;
-
- aug = get_augeas(ncf);
- ERR_BAIL(ncf);
-
- /* The last or clause catches slaves of a bond that are enslaved to
- * a bridge NAME */
- r = xasprintf(&path,
- "%s[ DEVICE = '%s' or BRIDGE = '%s' or MASTER =
'%s' "
- " or MASTER = ../*[BRIDGE = '%s']/DEVICE ]",
- ifcfg_path, name, name, name, name);
- ERR_NOMEM(r < 0, ncf);
-
- r = aug_rm(aug, path);
- ERR_COND_BAIL(r < 0, ncf, EOTHER);
- error:
- FREE(path);
-}
-
-/* Remove all interfaces and their slaves mentioned in NCF_XML. We need to
- * remove interfaces one by one when we define an interface, since what
- * will become a subinterface may not be related to the new toplevel
- * interface, and calling RM_INTERFACE on the toplevel interface is
- * therefore not enough.
- */
-static void rm_all_interfaces(struct netcf *ncf, xmlDocPtr ncf_xml) {
- xmlXPathContextPtr context = NULL;
- xmlXPathObjectPtr obj = NULL;
-
- context = xmlXPathNewContext(ncf_xml);
- ERR_NOMEM(context == NULL, ncf);
-
- obj = xmlXPathEvalExpression(BAD_CAST
- "//interface[count(parent::vlan) = 0]",
- context);
- ERR_NOMEM(obj == NULL, ncf);
-
-
- xmlNodeSetPtr ns = obj->nodesetval;
- for (int i=0; i < ns->nodeNr; i++) {
- xmlChar *name = xmlGetProp(ns->nodeTab[i], BAD_CAST "name");
- ERR_NOMEM(name == NULL, ncf);
- rm_interface(ncf, (char *) name);
- xmlFree(name);
- ERR_BAIL(ncf);
- }
- error:
- xmlXPathFreeObject(obj);
- xmlXPathFreeContext(context);
-}
-
-/* Dig through interface NAME and all its subinterfaces for bonds
- * and either add aliases in modprobe.conf for it (ALIAS == true), or
- * remove such aliases (ALIAS == false)
- */
-static void bond_setup(struct netcf *ncf, const char *name, bool alias) {
- void (*setup)(struct netcf *ncf, const char *name);
- int nslaves = 0;
- char **slaves = NULL;
-
- if (alias)
- setup = modprobed_alias_bond;
- else
- setup = modprobed_unalias_bond;
-
- if (is_bond(ncf, name)) {
- setup(ncf, name);
- ERR_BAIL(ncf);
- }
-
- if (is_bridge(ncf, name)) {
- nslaves = bridge_slaves(ncf, name, &slaves);
- ERR_BAIL(ncf);
- for (int i=0; i < nslaves; i++) {
- if (is_bond(ncf, slaves[i])) {
- setup(ncf, slaves[i]);
- ERR_BAIL(ncf);
- }
- }
- }
-
- error:
- free_matches(nslaves, &slaves);
- return;
-}
-
-struct netcf_if *drv_define(struct netcf *ncf, const char *xml_str) {
- xmlDocPtr ncf_xml = NULL, aug_xml = NULL;
- char *name = NULL;
- struct netcf_if *result = NULL;
- int r;
- struct augeas *aug = get_augeas(ncf);
-
- ncf_xml = parse_xml(ncf, xml_str);
- ERR_BAIL(ncf);
-
- rng_validate(ncf, ncf_xml);
- ERR_BAIL(ncf);
-
- name = device_name_from_xml(ncf, ncf_xml);
- ERR_COND_BAIL(name == NULL, ncf, EINTERNAL);
-
- rm_all_interfaces(ncf, ncf_xml);
- ERR_BAIL(ncf);
-
- aug_xml = apply_stylesheet(ncf, ncf->driver->get, ncf_xml);
- ERR_BAIL(ncf);
-
- aug_put_xml(ncf, aug_xml);
- ERR_BAIL(ncf);
-
- bond_setup(ncf, name, true);
- ERR_BAIL(ncf);
-
- r = aug_save(aug);
- if (r < 0 && NCF_DEBUG(ncf)) {
- fprintf(stderr, "Errors from aug_save:\n");
- aug_print(aug, stderr, "/augeas//error");
- }
- ERR_THROW(r < 0, ncf, EOTHER, "aug_save failed");
-
- result = make_netcf_if(ncf, name);
- ERR_BAIL(ncf);
-
- done:
- xmlFreeDoc(ncf_xml);
- xmlFreeDoc(aug_xml);
- return result;
- error:
- unref(result, netcf_if);
- goto done;
-}
-
-int drv_undefine(struct netcf_if *nif) {
- struct augeas *aug = NULL;
- struct netcf *ncf = nif->ncf;
- int r;
-
- aug = get_augeas(ncf);
- ERR_BAIL(ncf);
-
- bond_setup(ncf, nif->name, false);
- ERR_BAIL(ncf);
-
- rm_interface(ncf, nif->name);
- ERR_BAIL(ncf);
-
- r = aug_save(aug);
- ERR_COND_BAIL(r < 0, ncf, EOTHER);
-
- return 0;
- error:
- return -1;
-}
-
-int drv_lookup_by_mac_string(struct netcf *ncf, const char *mac,
- int maxifaces, struct netcf_if **ifaces)
-{
- struct augeas *aug = NULL;
- char *path = NULL, *ifcfg = NULL;
- const char **names = NULL;
- int nmatches = 0;
- char **matches = NULL;
- int r;
- int result = -1;
-
- MEMZERO(ifaces, maxifaces);
-
- aug = get_augeas(ncf);
- ERR_BAIL(ncf);
-
- nmatches = aug_match_mac(ncf, mac, &matches);
- ERR_BAIL(ncf);
- if (nmatches == 0) {
- result = 0;
- goto done;
- }
-
- r = ALLOC_N(names, nmatches);
- ERR_NOMEM(r < 0, ncf);
-
- int cnt = 0;
- for (int i = 0; i < nmatches; i++) {
- if (!has_ifcfg_file(ncf, matches[i]))
- continue;
- r = xasprintf(&ifcfg, "%s[DEVICE = '%s']", ifcfg_path,
matches[i]);
- ERR_NOMEM(r < 0, ncf);
-
- if (! is_slave(ncf, ifcfg))
- names[cnt++] = matches[i];
- FREE(ifcfg);
- }
- for (int i=0; i < cnt && i < maxifaces; i++) {
- char *name = strdup(names[i]);
- ERR_NOMEM(name == NULL, ncf);
- ifaces[i] = make_netcf_if(ncf, name);
- ERR_BAIL(ncf);
- }
- result = cnt;
- goto done;
-
- error:
- for (int i=0; i < maxifaces; i++)
- unref(ifaces[i], netcf_if);
- done:
- free(names);
- free(ifcfg);
- free(path);
- free_matches(nmatches, &matches);
- return result;
-}
-
-const char *drv_mac_string(struct netcf_if *nif) {
- struct netcf *ncf = nif->ncf;
- const char *mac;
- char *path = NULL;
- int r;
-
- r = aug_get_mac(ncf, nif->name, &mac);
- ERR_THROW(r < 0, ncf, EOTHER, "could not lookup MAC of %s",
nif->name);
-
- if (mac != NULL) {
- if (nif->mac == NULL || STRNEQ(nif->mac, mac)) {
- FREE(nif->mac);
- nif->mac = strdup(mac);
- ERR_NOMEM(nif->mac == NULL, ncf);
- }
- } else {
- FREE(nif->mac);
- }
- /* fallthrough intentional */
- error:
- FREE(path);
- return nif->mac;
-}
-
-/*
- * Bringing interfaces up/down
- */
-
-int drv_if_up(struct netcf_if *nif) {
- static const char *const ifup = "ifup";
- struct netcf *ncf = nif->ncf;
- char **slaves = NULL;
- int nslaves = 0;
- int result = -1;
-
- if (is_bridge(ncf, nif->name)) {
- /* Bring up bridge slaves before the bridge */
- nslaves = bridge_slaves(ncf, nif->name, &slaves);
- ERR_BAIL(ncf);
-
- for (int i=0; i < nslaves; i++) {
- run1(ncf, ifup, slaves[i]);
- ERR_BAIL(ncf);
- }
- }
- run1(ncf, ifup, nif->name);
- ERR_BAIL(ncf);
- result = 0;
- error:
- free_matches(nslaves, &slaves);
- return result;
-}
-
-int drv_if_down(struct netcf_if *nif) {
- static const char *const ifdown = "ifdown";
- struct netcf *ncf = nif->ncf;
- char **slaves = NULL;
- int nslaves = 0;
- int result = -1;
-
- run1(ncf, ifdown, nif->name);
- ERR_BAIL(ncf);
- if (is_bridge(ncf, nif->name)) {
- /* Bring up bridge slaves after the bridge */
- nslaves = bridge_slaves(ncf, nif->name, &slaves);
- ERR_BAIL(ncf);
-
- for (int i=0; i < nslaves; i++) {
- run1(ncf, ifdown, slaves[i]);
- ERR_BAIL(ncf);
- }
- }
- result = 0;
- error:
- free_matches(nslaves, &slaves);
- return result;
-}
-
-/* Functions to take a snapshot of network config (change_begin), and
- * later either revert to that config (change_rollback), or make the
- * new config permanent (change_commit).
- */
-int
-drv_change_begin(struct netcf *ncf, unsigned int flags)
-{
- int result = -1;
-
- ERR_THROW(flags != 0, ncf, EOTHER, "unsupported flags value %d", flags);
- run1(ncf, NETCF_TRANSACTION, "change-begin");
- ERR_BAIL(ncf);
- result = 0;
-error:
- return result;
-}
-
-int
-drv_change_rollback(struct netcf *ncf, unsigned int flags)
-{
- int result = -1;
-
- ERR_THROW(flags != 0, ncf, EOTHER, "unsupported flags value %d", flags);
- run1(ncf, NETCF_TRANSACTION, "change-rollback");
- ERR_BAIL(ncf);
- result = 0;
-error:
- return result;
-}
-
-int
-drv_change_commit(struct netcf *ncf, unsigned int flags)
-{
- int result = -1;
-
- ERR_THROW(flags != 0, ncf, EOTHER, "unsupported flags value %d", flags);
- run1(ncf, NETCF_TRANSACTION, "change-commit");
- ERR_BAIL(ncf);
- result = 0;
-error:
- return result;
-}
-
-/*
- * Test interface
- */
-static int drv_get_aug(struct netcf *ncf, const char *ncf_xml, char **aug_xml) {
- xmlDocPtr ncf_doc = NULL, aug_doc = NULL;
- int result = -1;
-
- ncf_doc = parse_xml(ncf, ncf_xml);
- ERR_BAIL(ncf);
-
- rng_validate(ncf, ncf_doc);
- ERR_BAIL(ncf);
-
- *aug_xml = apply_stylesheet_to_string(ncf, ncf->driver->get, ncf_doc);
- ERR_BAIL(ncf);
-
- /* fallthrough intentional */
- result = 0;
- error:
- xmlFreeDoc(ncf_doc);
- xmlFreeDoc(aug_doc);
- return result;
-}
-
-/* Transform the Augeas XML AUG_XML into interface XML NCF_XML */
-static int drv_put_aug(struct netcf *ncf, const char *aug_xml, char **ncf_xml) {
- xmlDocPtr ncf_doc = NULL, aug_doc = NULL;
- int result = -1;
-
- aug_doc = parse_xml(ncf, aug_xml);
- ERR_BAIL(ncf);
-
- *ncf_xml = apply_stylesheet_to_string(ncf, ncf->driver->put, aug_doc);
- ERR_BAIL(ncf);
-
- /* fallthrough intentional */
- result = 0;
- error:
- xmlFreeDoc(ncf_doc);
- xmlFreeDoc(aug_doc);
- return result;
-}
-
-/*
- * Test interface
- */
-int ncf_get_aug(struct netcf *ncf, const char *ncf_xml, char **aug_xml) {
- API_ENTRY(ncf);
-
- return drv_get_aug(ncf, ncf_xml, aug_xml);
-}
-
-int ncf_put_aug(struct netcf *ncf, const char *aug_xml, char **ncf_xml) {
- API_ENTRY(ncf);
-
- return drv_put_aug(ncf, aug_xml, ncf_xml);
-}
-
-/*
- * Local variables:
- * indent-tabs-mode: nil
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- */
-/* vim: set ts=4 sw=4 et: */
diff --git a/src/drv_redhat.c b/src/drv_redhat.c
new file mode 100644
index 0000000..996d79f
--- /dev/null
+++ b/src/drv_redhat.c
@@ -0,0 +1,1182 @@
+/*
+ * drv_redhat.c: the Red Hat distro family backend for netcf
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: David Lutterkort <lutter(a)redhat.com>
+ */
+
+#include <config.h>
+#include <internal.h>
+
+#include <augeas.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "safe-alloc.h"
+#include "ref.h"
+#include "list.h"
+#include "dutil.h"
+#include "dutil_linux.h"
+
+#include <libxml/parser.h>
+#include <libxml/relaxng.h>
+#include <libxml/tree.h>
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+#include <libexslt/exslt.h>
+
+static const char *const network_scripts_path =
+ "/files/etc/sysconfig/network-scripts";
+
+static const char *const ifcfg_path =
+ "/files/etc/sysconfig/network-scripts/*";
+
+/* Augeas should only load the files we are interested in */
+static const struct augeas_pv augeas_xfm_common_pv[] = {
+ /* Ifcfg files */
+ { "/augeas/load/Ifcfg/lens", "Sysconfig.lns" },
+ { "/augeas/load/Ifcfg/incl",
+ "/etc/sysconfig/network-scripts/ifcfg-*" },
+ { "/augeas/load/Ifcfg/excl[1]", "*~" },
+ { "/augeas/load/Ifcfg/excl[2]", "*.bak" },
+ { "/augeas/load/Ifcfg/excl[3]", "*.orig" },
+ { "/augeas/load/Ifcfg/excl[4]", "*.rpmnew" },
+ { "/augeas/load/Ifcfg/excl[5]", "*.rpmorig" },
+ { "/augeas/load/Ifcfg/excl[6]", "*.rpmsave" },
+ { "/augeas/load/Ifcfg/excl[7]", "*.augnew" },
+ { "/augeas/load/Ifcfg/excl[8]", "*.augsave" },
+ /* modprobe config */
+ { "/augeas/load/Modprobe/lens", "Modprobe.lns" },
+ { "/augeas/load/Modprobe/incl[1]", "/etc/modprobe.d/*" },
+ { "/augeas/load/Modprobe/incl[2]", "/etc/modprobe.conf" },
+ { "/augeas/load/Modprobe/excl[1]", "*.augnew" },
+ { "/augeas/load/Modprobe/excl[2]", "*.augsave" },
+ { "/augeas/load/Modprobe/excl[3]", "*.rpmsave" },
+ { "/augeas/load/Modprobe/excl[4]", "*.rpmnew" },
+ { "/augeas/load/Modprobe/excl[5]", "*~" },
+ /* sysfs (choice entries from /class/net) */
+ { "/augeas/load/Sysfs/lens", "Netcf.id" },
+ { "/augeas/load/Sysfs/incl", "/sys/class/net/*/address" }
+};
+
+static const struct augeas_xfm_table augeas_xfm_common =
+ { .size = ARRAY_CARDINALITY(augeas_xfm_common_pv),
+ .pv = augeas_xfm_common_pv };
+
+/* Entries in a ifcfg file that tell us that the interface
+ * is not a toplevel interface
+ */
+static const char *const subif_paths[] = {
+ "MASTER", "BRIDGE"
+};
+
+static int is_slave(struct netcf *ncf, const char *intf) {
+ for (int s = 0; s < ARRAY_CARDINALITY(subif_paths); s++) {
+ int r;
+ r = aug_fmt_match(ncf, NULL, "%s/%s", intf, subif_paths[s]);
+ if (r != 0)
+ return r;
+ }
+ return 0;
+}
+
+static bool has_ifcfg_file(struct netcf *ncf, const char *name) {
+ int nmatches;
+
+ nmatches = aug_fmt_match(ncf, NULL,
+ "%s[ DEVICE = '%s'"
+ " or BRIDGE = '%s'"
+ " or MASTER = '%s'"
+ " or MASTER = ../*[BRIDGE = '%s']/DEVICE
]/DEVICE",
+ ifcfg_path, name, name, name, name);
+ return nmatches > 0;
+}
+
+static int cmpstrp(const void *p1, const void *p2) {
+ const char *s1 = * (const char **)p1;
+ const char *s2 = * (const char **)p2;
+ return strcmp(s1, s2);
+}
+
+/* Find the path to the ifcfg file that has the configuration for the
+ * interface with MAC address MAC.
+ */
+static char *find_ifcfg_path_by_hwaddr(struct netcf *ncf, const char *mac) {
+ static const char *const hwaddr_str = "/HWADDR";
+
+ int nhwaddr = 0, r;
+ char **hwaddr = NULL;
+ struct augeas *aug = NULL;
+
+ aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
+ // It would be nice if Augeas provided a way to do case-insensitive
+ // matching. For now, we just write it out
+ nhwaddr = aug_fmt_match(ncf, &hwaddr, "%s%s", ifcfg_path, hwaddr_str);
+ ERR_COND_BAIL(nhwaddr < 0, ncf, EOTHER);
+
+ /* Sort because need_config will return the last match in case
+ * of multiple matches */
+ qsort(hwaddr, nhwaddr, sizeof(*hwaddr), cmpstrp);
+ int match = -1;
+ for (int i=0; i < nhwaddr; i++) {
+ const char *addr;
+ r = aug_get(aug, hwaddr[i], &addr);
+ ERR_COND_BAIL(r != 1, ncf, EOTHER);
+ if (STRCASEEQ(addr, mac))
+ match = i;
+ }
+ if (match != -1) {
+ char *path = hwaddr[match];
+ hwaddr[match] = NULL;
+ path[strlen(path) - strlen(hwaddr_str)] = '\0';
+ free_matches(nhwaddr, &hwaddr);
+ return path;
+ }
+ error:
+ free_matches(nhwaddr, &hwaddr);
+ return NULL;
+}
+
+/* Find the path to the ifcfg file that has the configuration for the
+ * interface by checking for an entry 'DEVICE=NAME'
+ */
+static char *find_ifcfg_path_by_device(struct netcf *ncf, const char *name) {
+ struct augeas *aug = NULL;
+ int ndevs = 0;
+ char **devs = NULL;
+
+ aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
+ ndevs = aug_fmt_match(ncf, &devs, "%s[DEVICE = '%s']",
+ ifcfg_path, name);
+ ERR_COND_BAIL(ndevs < 0, ncf, EOTHER);
+
+ if (ndevs == 0)
+ return NULL;
+
+ qsort(devs, ndevs, sizeof(*devs), cmpstrp);
+
+ char *path = devs[ndevs - 1];
+ devs[ndevs - 1] = NULL;
+
+ free_matches(ndevs, &devs);
+
+ return path;
+ error:
+ free_matches(ndevs, &devs);
+ return NULL;
+}
+
+/* Find the path to the ifcfg file that has the configuration for
+ * the device NAME. The logic follows the need_config function
+ * in /etc/sysconfig/network-scripts/network-functions
+ */
+static char *find_ifcfg_path(struct netcf *ncf, const char *name) {
+ struct augeas *aug = NULL;
+ char *path = NULL;
+ const char *mac = NULL;
+ int r, nmatches;
+
+ aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
+ /* if ifcfg-NAME exists, use that */
+ r = xasprintf(&path, "%s/ifcfg-%s", network_scripts_path, name);
+ ERR_NOMEM(r < 0, ncf);
+
+ nmatches = aug_match(aug, path, NULL);
+ ERR_COND_BAIL(nmatches < 0, ncf, EOTHER);
+
+ if (nmatches == 1)
+ return path;
+
+ FREE(path);
+
+ /* Now find the config by MAC, matching on HWADDR */
+ r = aug_get_mac(ncf, name, &mac);
+ ERR_COND_BAIL(r < 0, ncf, EOTHER);
+ if (r > 0) {
+ path = find_ifcfg_path_by_hwaddr(ncf, mac);
+ ERR_BAIL(ncf);
+ if (path != NULL)
+ return path;
+ }
+
+ path = find_ifcfg_path_by_device(ncf, name);
+ ERR_BAIL(ncf);
+
+ return path;
+ error:
+ FREE(path);
+ return NULL;
+}
+
+/* Given NDEVS path to DEVICE entries which may contain duplicate devices,
+ * produce a list of canonical paths to the interfaces in INTF and return
+ * the number of entries. Return -1 on error
+ */
+static int uniq_ifcfg_paths(struct netcf *ncf,
+ int ndevs, char **devs,
+ char ***intf) {
+ struct augeas *aug;
+ int r;
+ int ndevnames = 0;
+ const char **devnames = NULL;
+
+ aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
+ /* List unique device names */
+ r = ALLOC_N(devnames, ndevs);
+ ERR_NOMEM(r < 0, ncf);
+
+ for (int i=0; i < ndevs; i++) {
+ const char *name = NULL;
+ r = aug_get(aug, devs[i], &name);
+ ERR_COND_BAIL(r != 1, ncf, EOTHER);
+ int exists = 0;
+ for (int j = 0; j < ndevnames; j++)
+ if (STREQ(name, devnames[j])) {
+ exists = 1;
+ break;
+ }
+ if (!exists)
+ devnames[ndevnames++] = name;
+ }
+ qsort(devnames, ndevnames, sizeof(*devnames), cmpstrp);
+
+ /* Find canonical config for each device name */
+ r = ALLOC_N(*intf, ndevnames);
+ ERR_NOMEM(r < 0, ncf);
+ for (int i= 0; i < ndevnames; i++) {
+ (*intf)[i] = find_ifcfg_path(ncf, devnames[i]);
+ ERR_BAIL(ncf);
+ }
+
+ FREE(devnames);
+ return ndevnames;
+
+ error:
+ FREE(devnames);
+ free_matches(ndevnames, intf);
+ return -1;
+}
+
+/* List all configured network devices; returns the number of devices or -1
+ * on error. On success, the path to the config file for each interface
+ * is returned in INTF
+ */
+static int list_ifcfg_paths(struct netcf *ncf, char ***intf) {
+ int result = 0, ndevs;
+ char **devs = NULL;
+
+ ndevs = aug_fmt_match(ncf, &devs, "%s/DEVICE", ifcfg_path);
+ ERR_COND_BAIL(ndevs < 0, ncf, EOTHER);
+
+ result = uniq_ifcfg_paths(ncf, ndevs, devs, intf);
+ ERR_BAIL(ncf);
+
+ free_matches(ndevs, &devs);
+ return result;
+
+ error:
+ free_matches(ndevs, &devs);
+ return -1;
+}
+
+static int list_interfaces(struct netcf *ncf, char ***intf) {
+ int nint = 0, result = 0;
+ struct augeas *aug = NULL;
+
+ aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
+ /* Look in augeas for all interfaces */
+ nint = list_ifcfg_paths(ncf, intf);
+ ERR_BAIL(ncf);
+ result = nint;
+
+ /* Filter out the interfaces that are slaves/subordinate */
+ for (int i = 0; i < result;) {
+ if (is_slave(ncf, (*intf)[i])) {
+ FREE((*intf)[i]);
+ memmove(*intf + i, *intf + i + 1,
+ (nint - (i + 1))*sizeof((*intf)[0]));
+ result -= 1;
+ } else {
+ i += 1;
+ }
+ }
+ return result;
+ error:
+ free_matches(nint, intf);
+ return -1;
+}
+
+int drv_init(struct netcf *ncf) {
+ int r;
+ struct stat stats;
+
+ if (ALLOC(ncf->driver) < 0)
+ return -1;
+
+ ncf->driver->ioctl_fd = -1;
+
+ r = add_augeas_xfm_table(ncf, &augeas_xfm_common);
+ if (r < 0)
+ goto error;
+
+ if (stat(ncf->root, &stats) != 0 || !S_ISDIR(stats.st_mode)) {
+ report_error(ncf, NETCF_EFILE,
+ "invalid root '%s' is not a directory",
ncf->root);
+ goto error;
+ }
+
+ // FIXME: Check for errors
+ xsltInit();
+ exsltStrRegister();
+ ncf->driver->get = parse_stylesheet(ncf, "redhat-get.xsl");
+ ncf->driver->put = parse_stylesheet(ncf, "redhat-put.xsl");
+ ERR_BAIL(ncf);
+
+ /* open a socket for interface ioctls */
+ ncf->driver->ioctl_fd = init_ioctl_fd(ncf);
+ if (ncf->driver->ioctl_fd < 0)
+ goto error;
+ if (netlink_init(ncf) < 0)
+ goto error;
+ return 0;
+
+ error:
+ drv_close(ncf);
+ return -1;
+}
+
+void drv_close(struct netcf *ncf) {
+ if (ncf == NULL || ncf->driver == NULL)
+ return;
+ xsltFreeStylesheet(ncf->driver->get);
+ xsltFreeStylesheet(ncf->driver->put);
+ netlink_close(ncf);
+ if (ncf->driver->ioctl_fd >= 0)
+ close(ncf->driver->ioctl_fd);
+ aug_close(ncf->driver->augeas);
+ FREE(ncf->driver->augeas_xfm_tables);
+ FREE(ncf->driver);
+}
+
+void drv_entry(struct netcf *ncf) {
+ ncf->driver->load_augeas = 1;
+}
+
+static int list_interface_ids(struct netcf *ncf,
+ int maxnames, char **names,
+ unsigned int flags,
+ const char *id_attr) {
+ struct augeas *aug = NULL;
+ int nint = 0, nmatches = 0, nqualified = 0, result = 0, r;
+ char **intf = NULL, **matches = NULL;
+
+ aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+ nint = list_interfaces(ncf, &intf);
+ ERR_BAIL(ncf);
+ if (!names) {
+ maxnames = nint; /* if not returning list, ignore maxnames too */
+ }
+ for (result = 0; (result < nint) && (nqualified < maxnames); result++)
{
+ nmatches = aug_fmt_match(ncf, &matches,
+ "%s/%s", intf[result], id_attr);
+ ERR_BAIL(ncf);
+ if (nmatches > 0) {
+ const char *name;
+ int is_qualified = ((flags & (NETCF_IFACE_ACTIVE|NETCF_IFACE_INACTIVE))
+ == (NETCF_IFACE_ACTIVE|NETCF_IFACE_INACTIVE));
+
+ r = aug_get(aug, matches[nmatches-1], &name);
+ ERR_COND_BAIL(r < 0, ncf, EOTHER);
+
+ if (!is_qualified) {
+ int is_active = if_is_active(ncf, name);
+ if ((is_active && (flags & NETCF_IFACE_ACTIVE))
+ || ((!is_active) && (flags & NETCF_IFACE_INACTIVE))) {
+
+ is_qualified = 1;
+ }
+ }
+
+ if (is_qualified) {
+ if (names) {
+ names[nqualified] = strdup(name);
+ ERR_NOMEM(names[nqualified] == NULL, ncf);
+ }
+ nqualified++;
+ }
+ }
+ free_matches(nmatches, &matches);
+ }
+ free_matches(nint, &intf);
+ return nqualified;
+ error:
+ free_matches(nmatches, &matches);
+ free_matches(nint, &intf);
+ return -1;
+}
+
+int drv_list_interfaces(struct netcf *ncf, int maxnames, char **names,
+ unsigned int flags) {
+ return list_interface_ids(ncf, maxnames, names, flags, "DEVICE");
+}
+
+int drv_num_of_interfaces(struct netcf *ncf, unsigned int flags) {
+ return list_interface_ids(ncf, 0, NULL, flags, "DEVICE");
+}
+
+struct netcf_if *drv_lookup_by_name(struct netcf *ncf, const char *name) {
+ struct netcf_if *nif = NULL;
+ char *pathx = NULL;
+ char *name_dup = NULL;
+ struct augeas *aug;
+
+ aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
+ pathx = find_ifcfg_path(ncf, name);
+ ERR_BAIL(ncf);
+
+ if (pathx == NULL || is_slave(ncf, pathx))
+ goto done;
+
+ name_dup = strdup(name);
+ ERR_NOMEM(name_dup == NULL, ncf);
+
+ nif = make_netcf_if(ncf, name_dup);
+ ERR_BAIL(ncf);
+ goto done;
+
+ error:
+ unref(nif, netcf_if);
+ FREE(name_dup);
+ done:
+ FREE(pathx);
+ return nif;
+}
+
+/* Get an XML desription of the interfaces (just paths, really) in INTF.
+ * The format is a very simple representation of the Augeas tree (see
+ * xml/augeas.rng)
+ */
+static xmlDocPtr aug_get_xml(struct netcf *ncf, int nint, char **intf) {
+ struct augeas *aug;
+ xmlDocPtr result = NULL;
+ xmlNodePtr root = NULL, tree = NULL;
+ char **matches = NULL;
+ int nmatches, r;
+
+ aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
+ result = xmlNewDoc(BAD_CAST "1.0");
+ root = xmlNewNode(NULL, BAD_CAST "forest");
+ xmlDocSetRootElement(result, root);
+
+ for (int i=0; i < nint; i++) {
+ tree = xmlNewChild(root, NULL, BAD_CAST "tree", NULL);
+ xmlNewProp(tree, BAD_CAST "path", BAD_CAST intf[i]);
+ nmatches = aug_fmt_match(ncf, &matches, "%s/%s", intf[i],
"*");
+ ERR_COND_BAIL(nint < 0, ncf, EOTHER);
+ for (int j = 0; j < nmatches; j++) {
+ xmlNodePtr node = xmlNewChild(tree, NULL, BAD_CAST "node", NULL);
+ const char *value;
+ xmlNewProp(node, BAD_CAST "label",
+ BAD_CAST matches[j] + strlen(intf[i]) + 1);
+ r = aug_get(aug, matches[j], &value);
+ ERR_COND_BAIL(r < 0, ncf, EOTHER);
+ xmlNewProp(node, BAD_CAST "value", BAD_CAST value);
+ }
+ free_matches(nmatches, &matches);
+ }
+
+ return result;
+
+ error:
+ free_matches(nmatches, &matches);
+ xmlFreeDoc(result);
+ return NULL;
+}
+
+/* Write the XML doc in the simple Augeas format into the Augeas tree */
+static int aug_put_xml(struct netcf *ncf, xmlDocPtr xml) {
+ xmlNodePtr forest;
+ char *path = NULL, *lpath = NULL, *label = NULL, *value = NULL;
+ struct augeas *aug = NULL;
+ int result = -1;
+ int r;
+
+ aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
+ forest = xmlDocGetRootElement(xml);
+ ERR_THROW(forest == NULL, ncf, EINTERNAL, "missing root element");
+ ERR_THROW(! xmlStrEqual(forest->name, BAD_CAST "forest"), ncf,
+ EINTERNAL, "expected root node labeled 'forest', not
'%s'",
+ forest->name);
+ list_for_each(tree, forest->children) {
+ ERR_THROW(! xmlStrEqual(tree->name, BAD_CAST "tree"), ncf,
+ EINTERNAL, "expected node labeled 'tree', not
'%s'",
+ tree->name);
+ path = xml_prop(tree, "path");
+ int toplevel = 1;
+ /* This is a little drastic, since it clears out the file entirely */
+ r = aug_rm(aug, path);
+ ERR_THROW(r < 0, ncf, EINTERNAL, "aug_rm of '%s' failed",
path);
+ list_for_each(node, tree->children) {
+ label = xml_prop(node, "label");
+ value = xml_prop(node, "value");
+ /* We should mark the toplevel interface from the XSLT */
+ if (STREQ(label, "BRIDGE") || STREQ(label, "MASTER")) {
+ toplevel = 0;
+ }
+ r = xasprintf(&lpath, "%s/%s", path, label);
+ ERR_NOMEM(r < 0, ncf);
+
+ r = aug_set(aug, lpath, value);
+ ERR_THROW(r < 0, ncf, EOTHER,
+ "aug_set of '%s' failed", lpath);
+ FREE(lpath);
+ xmlFree(label);
+ xmlFree(value);
+ label = value = NULL;
+ }
+ xmlFree(path);
+ path = NULL;
+ }
+ result = 0;
+ error:
+ xmlFree(label);
+ xmlFree(value);
+ xmlFree(path);
+ FREE(lpath);
+ return result;
+}
+
+/* given a netcf_if, get the config for an interface in the simple
+ * Augeas format
+ */
+static xmlDocPtr aug_get_xml_for_nif(struct netcf_if *nif) {
+ struct netcf *ncf;
+ char **devs = NULL, **intf = NULL;
+ xmlDocPtr aug_xml = NULL;
+ int ndevs = 0, nint = 0;
+
+ ncf = nif->ncf;
+ ndevs = aug_fmt_match(ncf, &devs,
+ "%s[ DEVICE = '%s' or BRIDGE = '%s' or MASTER =
'%s'"
+ " or MASTER = ../*[BRIDGE = '%s']/DEVICE ]/DEVICE",
+ ifcfg_path, nif->name, nif->name, nif->name, nif->name);
+ ERR_BAIL(ncf);
+
+ nint = uniq_ifcfg_paths(ncf, ndevs, devs, &intf);
+ ERR_BAIL(ncf);
+
+ aug_xml = aug_get_xml(ncf, nint, intf);
+
+ error:
+ free_matches(ndevs, &devs);
+ free_matches(nint, &intf);
+ return aug_xml;
+}
+
+/* return the current static configuration (as saved on disk) */
+char *drv_xml_desc(struct netcf_if *nif) {
+ char *result = NULL;
+ struct netcf *ncf;
+ xmlDocPtr aug_xml = NULL;
+
+ ncf = nif->ncf;
+ aug_xml = aug_get_xml_for_nif(nif);
+ ERR_BAIL(ncf);
+
+ result = apply_stylesheet_to_string(ncf, ncf->driver->put, aug_xml);
+
+ error:
+ xmlFreeDoc(aug_xml);
+ return result;
+}
+
+/* return the current live configuration state - a combination of
+ * drv_xml_desc + results of querying the interface directly */
+
+char *drv_xml_state(struct netcf_if *nif) {
+ char *result = NULL;
+ int r, result_len;
+ struct netcf *ncf;
+ xmlDocPtr ncf_xml = NULL;
+ xmlNodePtr root;
+
+ ncf = nif->ncf;
+
+ /* start out with an empty tree rather than the config tree. Just
+ * put in the interface node and its name
+ */
+ ncf_xml = xmlNewDoc(BAD_CAST "1.0");
+ ERR_NOMEM(ncf_xml == NULL, ncf);
+ root = xmlNewNode(NULL, BAD_CAST "interface");
+ ERR_NOMEM(root == NULL, ncf);
+ xmlDocSetRootElement(ncf_xml, root);
+
+ /* add all info we can gather from the kernel/sysfs/procfs */
+ add_state_to_xml_doc(nif, ncf_xml);
+ ERR_BAIL(ncf);
+
+ r = xsltSaveResultToString((xmlChar **)&result, &result_len,
+ ncf_xml, ncf->driver->put);
+ ERR_NOMEM(r < 0, ncf);
+
+ done:
+ xmlFreeDoc(ncf_xml);
+ return result;
+ error:
+ FREE(result);
+ result = 0;
+ goto done;
+}
+
+/* Report various status info about the interface as bits in
+ * "flags". Returns 0 on success, -1 on failure
+ */
+int drv_if_status(struct netcf_if *nif, unsigned int *flags) {
+ int is_active;
+
+ ERR_THROW(flags == NULL, nif->ncf, EOTHER, "NULL pointer for flags in
ncf_if_status");
+ *flags = 0;
+ is_active = if_is_active(nif->ncf, nif->name);
+ if (is_active)
+ *flags |= NETCF_IFACE_ACTIVE;
+ else
+ *flags |= NETCF_IFACE_INACTIVE;
+ return 0;
+error:
+ return -1;
+}
+
+/* Get the content of /interface/@name. Result must be freed with xmlFree()
+ *
+ * The name on VLAN interfaces is optional; if there is no
+ * /interface/@name, construct a name for the VLAN interface and set
+ * /interface/@name in NCF_XML to it. This way, other code can assume we
+ * always have a name on the interface.
+ */
+static char *device_name_from_xml(struct netcf *ncf, xmlDocPtr ncf_xml) {
+ xmlXPathContextPtr context = NULL;
+ xmlXPathObjectPtr obj = NULL;
+ char *result = NULL;
+
+ context = xmlXPathNewContext(ncf_xml);
+ ERR_NOMEM(context == NULL, ncf);
+
+ obj = xmlXPathEvalExpression(BAD_CAST "string(/interface/@name)", context);
+ ERR_NOMEM(obj == NULL, ncf);
+ assert(obj->type == XPATH_STRING);
+
+ if (xmlStrlen(obj->stringval) == 0) {
+ xmlXPathFreeObject(obj);
+ obj = xmlXPathEvalExpression(BAD_CAST
+ "concat(/interface/vlan/interface/@name, '.',
/interface/vlan/@tag)",
+ context);
+ ERR_NOMEM(obj == NULL, ncf);
+ ERR_COND_BAIL(xmlStrlen(obj->stringval) == 0, ncf, EINTERNAL);
+ assert(obj->type == XPATH_STRING);
+
+ xmlNodePtr iface;
+ iface = xmlDocGetRootElement(ncf_xml);
+ ERR_COND_BAIL(iface == NULL, ncf, EINTERNAL);
+ xmlSetProp(iface, BAD_CAST "name", BAD_CAST result);
+ }
+
+ result = (char *) xmlStrdup(obj->stringval);
+ error:
+ xmlXPathFreeObject(obj);
+ xmlXPathFreeContext(context);
+ return result;
+}
+
+/* The device NAME is a bond if it is mentioned as the MASTER in sopme
+ * other devices config file
+ */
+static bool is_bond(struct netcf *ncf, const char *name) {
+ int nmatches = 0;
+
+ nmatches = aug_fmt_match(ncf, NULL,
+ "%s[ MASTER = '%s']", ifcfg_path, name);
+ return nmatches > 0;
+}
+
+/* The device NAME is a bridge if it has an entry TYPE=Bridge */
+static bool is_bridge(struct netcf *ncf, const char *name) {
+ int nmatches = 0;
+
+ nmatches = aug_fmt_match(ncf, NULL,
+ "%s[ DEVICE = '%s' and TYPE =
'Bridge']",
+ ifcfg_path, name);
+ return nmatches > 0;
+}
+
+static int bridge_slaves(struct netcf *ncf, const char *name, char ***slaves) {
+ struct augeas *aug = NULL;
+ int r, nslaves = 0;
+
+ aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
+ nslaves = aug_fmt_match(ncf, slaves,
+ "%s[ BRIDGE = '%s' ]/DEVICE", ifcfg_path,
name);
+ ERR_BAIL(ncf);
+ for (int i=0; i < nslaves; i++) {
+ char *p = (*slaves)[i];
+ const char *dev;
+ r = aug_get(aug, p, &dev);
+ ERR_COND_BAIL(r < 0, ncf, EOTHER);
+
+ (*slaves)[i] = strdup(dev);
+ free(p);
+ ERR_NOMEM(slaves[i] == NULL, ncf);
+ }
+ return nslaves;
+ error:
+ free_matches(nslaves, slaves);
+ return -1;
+}
+
+
+/* For an interface NAME, remove the ifcfg-* files for that interface and
+ * all its slaves. */
+static void rm_interface(struct netcf *ncf, const char *name) {
+ int r;
+ char *path = NULL;
+ struct augeas *aug = NULL;
+
+ aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
+ /* The last or clause catches slaves of a bond that are enslaved to
+ * a bridge NAME */
+ r = xasprintf(&path,
+ "%s[ DEVICE = '%s' or BRIDGE = '%s' or MASTER =
'%s' "
+ " or MASTER = ../*[BRIDGE = '%s']/DEVICE ]",
+ ifcfg_path, name, name, name, name);
+ ERR_NOMEM(r < 0, ncf);
+
+ r = aug_rm(aug, path);
+ ERR_COND_BAIL(r < 0, ncf, EOTHER);
+ error:
+ FREE(path);
+}
+
+/* Remove all interfaces and their slaves mentioned in NCF_XML. We need to
+ * remove interfaces one by one when we define an interface, since what
+ * will become a subinterface may not be related to the new toplevel
+ * interface, and calling RM_INTERFACE on the toplevel interface is
+ * therefore not enough.
+ */
+static void rm_all_interfaces(struct netcf *ncf, xmlDocPtr ncf_xml) {
+ xmlXPathContextPtr context = NULL;
+ xmlXPathObjectPtr obj = NULL;
+
+ context = xmlXPathNewContext(ncf_xml);
+ ERR_NOMEM(context == NULL, ncf);
+
+ obj = xmlXPathEvalExpression(BAD_CAST
+ "//interface[count(parent::vlan) = 0]",
+ context);
+ ERR_NOMEM(obj == NULL, ncf);
+
+
+ xmlNodeSetPtr ns = obj->nodesetval;
+ for (int i=0; i < ns->nodeNr; i++) {
+ xmlChar *name = xmlGetProp(ns->nodeTab[i], BAD_CAST "name");
+ ERR_NOMEM(name == NULL, ncf);
+ rm_interface(ncf, (char *) name);
+ xmlFree(name);
+ ERR_BAIL(ncf);
+ }
+ error:
+ xmlXPathFreeObject(obj);
+ xmlXPathFreeContext(context);
+}
+
+/* Dig through interface NAME and all its subinterfaces for bonds
+ * and either add aliases in modprobe.conf for it (ALIAS == true), or
+ * remove such aliases (ALIAS == false)
+ */
+static void bond_setup(struct netcf *ncf, const char *name, bool alias) {
+ void (*setup)(struct netcf *ncf, const char *name);
+ int nslaves = 0;
+ char **slaves = NULL;
+
+ if (alias)
+ setup = modprobed_alias_bond;
+ else
+ setup = modprobed_unalias_bond;
+
+ if (is_bond(ncf, name)) {
+ setup(ncf, name);
+ ERR_BAIL(ncf);
+ }
+
+ if (is_bridge(ncf, name)) {
+ nslaves = bridge_slaves(ncf, name, &slaves);
+ ERR_BAIL(ncf);
+ for (int i=0; i < nslaves; i++) {
+ if (is_bond(ncf, slaves[i])) {
+ setup(ncf, slaves[i]);
+ ERR_BAIL(ncf);
+ }
+ }
+ }
+
+ error:
+ free_matches(nslaves, &slaves);
+ return;
+}
+
+struct netcf_if *drv_define(struct netcf *ncf, const char *xml_str) {
+ xmlDocPtr ncf_xml = NULL, aug_xml = NULL;
+ char *name = NULL;
+ struct netcf_if *result = NULL;
+ int r;
+ struct augeas *aug = get_augeas(ncf);
+
+ ncf_xml = parse_xml(ncf, xml_str);
+ ERR_BAIL(ncf);
+
+ rng_validate(ncf, ncf_xml);
+ ERR_BAIL(ncf);
+
+ name = device_name_from_xml(ncf, ncf_xml);
+ ERR_COND_BAIL(name == NULL, ncf, EINTERNAL);
+
+ rm_all_interfaces(ncf, ncf_xml);
+ ERR_BAIL(ncf);
+
+ aug_xml = apply_stylesheet(ncf, ncf->driver->get, ncf_xml);
+ ERR_BAIL(ncf);
+
+ aug_put_xml(ncf, aug_xml);
+ ERR_BAIL(ncf);
+
+ bond_setup(ncf, name, true);
+ ERR_BAIL(ncf);
+
+ r = aug_save(aug);
+ if (r < 0 && NCF_DEBUG(ncf)) {
+ fprintf(stderr, "Errors from aug_save:\n");
+ aug_print(aug, stderr, "/augeas//error");
+ }
+ ERR_THROW(r < 0, ncf, EOTHER, "aug_save failed");
+
+ result = make_netcf_if(ncf, name);
+ ERR_BAIL(ncf);
+
+ done:
+ xmlFreeDoc(ncf_xml);
+ xmlFreeDoc(aug_xml);
+ return result;
+ error:
+ unref(result, netcf_if);
+ goto done;
+}
+
+int drv_undefine(struct netcf_if *nif) {
+ struct augeas *aug = NULL;
+ struct netcf *ncf = nif->ncf;
+ int r;
+
+ aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
+ bond_setup(ncf, nif->name, false);
+ ERR_BAIL(ncf);
+
+ rm_interface(ncf, nif->name);
+ ERR_BAIL(ncf);
+
+ r = aug_save(aug);
+ ERR_COND_BAIL(r < 0, ncf, EOTHER);
+
+ return 0;
+ error:
+ return -1;
+}
+
+int drv_lookup_by_mac_string(struct netcf *ncf, const char *mac,
+ int maxifaces, struct netcf_if **ifaces)
+{
+ struct augeas *aug = NULL;
+ char *path = NULL, *ifcfg = NULL;
+ const char **names = NULL;
+ int nmatches = 0;
+ char **matches = NULL;
+ int r;
+ int result = -1;
+
+ MEMZERO(ifaces, maxifaces);
+
+ aug = get_augeas(ncf);
+ ERR_BAIL(ncf);
+
+ nmatches = aug_match_mac(ncf, mac, &matches);
+ ERR_BAIL(ncf);
+ if (nmatches == 0) {
+ result = 0;
+ goto done;
+ }
+
+ r = ALLOC_N(names, nmatches);
+ ERR_NOMEM(r < 0, ncf);
+
+ int cnt = 0;
+ for (int i = 0; i < nmatches; i++) {
+ if (!has_ifcfg_file(ncf, matches[i]))
+ continue;
+ r = xasprintf(&ifcfg, "%s[DEVICE = '%s']", ifcfg_path,
matches[i]);
+ ERR_NOMEM(r < 0, ncf);
+
+ if (! is_slave(ncf, ifcfg))
+ names[cnt++] = matches[i];
+ FREE(ifcfg);
+ }
+ for (int i=0; i < cnt && i < maxifaces; i++) {
+ char *name = strdup(names[i]);
+ ERR_NOMEM(name == NULL, ncf);
+ ifaces[i] = make_netcf_if(ncf, name);
+ ERR_BAIL(ncf);
+ }
+ result = cnt;
+ goto done;
+
+ error:
+ for (int i=0; i < maxifaces; i++)
+ unref(ifaces[i], netcf_if);
+ done:
+ free(names);
+ free(ifcfg);
+ free(path);
+ free_matches(nmatches, &matches);
+ return result;
+}
+
+const char *drv_mac_string(struct netcf_if *nif) {
+ struct netcf *ncf = nif->ncf;
+ const char *mac;
+ char *path = NULL;
+ int r;
+
+ r = aug_get_mac(ncf, nif->name, &mac);
+ ERR_THROW(r < 0, ncf, EOTHER, "could not lookup MAC of %s",
nif->name);
+
+ if (mac != NULL) {
+ if (nif->mac == NULL || STRNEQ(nif->mac, mac)) {
+ FREE(nif->mac);
+ nif->mac = strdup(mac);
+ ERR_NOMEM(nif->mac == NULL, ncf);
+ }
+ } else {
+ FREE(nif->mac);
+ }
+ /* fallthrough intentional */
+ error:
+ FREE(path);
+ return nif->mac;
+}
+
+/*
+ * Bringing interfaces up/down
+ */
+
+int drv_if_up(struct netcf_if *nif) {
+ static const char *const ifup = "ifup";
+ struct netcf *ncf = nif->ncf;
+ char **slaves = NULL;
+ int nslaves = 0;
+ int result = -1;
+
+ if (is_bridge(ncf, nif->name)) {
+ /* Bring up bridge slaves before the bridge */
+ nslaves = bridge_slaves(ncf, nif->name, &slaves);
+ ERR_BAIL(ncf);
+
+ for (int i=0; i < nslaves; i++) {
+ run1(ncf, ifup, slaves[i]);
+ ERR_BAIL(ncf);
+ }
+ }
+ run1(ncf, ifup, nif->name);
+ ERR_BAIL(ncf);
+ result = 0;
+ error:
+ free_matches(nslaves, &slaves);
+ return result;
+}
+
+int drv_if_down(struct netcf_if *nif) {
+ static const char *const ifdown = "ifdown";
+ struct netcf *ncf = nif->ncf;
+ char **slaves = NULL;
+ int nslaves = 0;
+ int result = -1;
+
+ run1(ncf, ifdown, nif->name);
+ ERR_BAIL(ncf);
+ if (is_bridge(ncf, nif->name)) {
+ /* Bring up bridge slaves after the bridge */
+ nslaves = bridge_slaves(ncf, nif->name, &slaves);
+ ERR_BAIL(ncf);
+
+ for (int i=0; i < nslaves; i++) {
+ run1(ncf, ifdown, slaves[i]);
+ ERR_BAIL(ncf);
+ }
+ }
+ result = 0;
+ error:
+ free_matches(nslaves, &slaves);
+ return result;
+}
+
+/* Functions to take a snapshot of network config (change_begin), and
+ * later either revert to that config (change_rollback), or make the
+ * new config permanent (change_commit).
+ */
+int
+drv_change_begin(struct netcf *ncf, unsigned int flags)
+{
+ int result = -1;
+
+ ERR_THROW(flags != 0, ncf, EOTHER, "unsupported flags value %d", flags);
+ run1(ncf, NETCF_TRANSACTION, "change-begin");
+ ERR_BAIL(ncf);
+ result = 0;
+error:
+ return result;
+}
+
+int
+drv_change_rollback(struct netcf *ncf, unsigned int flags)
+{
+ int result = -1;
+
+ ERR_THROW(flags != 0, ncf, EOTHER, "unsupported flags value %d", flags);
+ run1(ncf, NETCF_TRANSACTION, "change-rollback");
+ ERR_BAIL(ncf);
+ result = 0;
+error:
+ return result;
+}
+
+int
+drv_change_commit(struct netcf *ncf, unsigned int flags)
+{
+ int result = -1;
+
+ ERR_THROW(flags != 0, ncf, EOTHER, "unsupported flags value %d", flags);
+ run1(ncf, NETCF_TRANSACTION, "change-commit");
+ ERR_BAIL(ncf);
+ result = 0;
+error:
+ return result;
+}
+
+/*
+ * Test interface
+ */
+static int drv_get_aug(struct netcf *ncf, const char *ncf_xml, char **aug_xml) {
+ xmlDocPtr ncf_doc = NULL, aug_doc = NULL;
+ int result = -1;
+
+ ncf_doc = parse_xml(ncf, ncf_xml);
+ ERR_BAIL(ncf);
+
+ rng_validate(ncf, ncf_doc);
+ ERR_BAIL(ncf);
+
+ *aug_xml = apply_stylesheet_to_string(ncf, ncf->driver->get, ncf_doc);
+ ERR_BAIL(ncf);
+
+ /* fallthrough intentional */
+ result = 0;
+ error:
+ xmlFreeDoc(ncf_doc);
+ xmlFreeDoc(aug_doc);
+ return result;
+}
+
+/* Transform the Augeas XML AUG_XML into interface XML NCF_XML */
+static int drv_put_aug(struct netcf *ncf, const char *aug_xml, char **ncf_xml) {
+ xmlDocPtr ncf_doc = NULL, aug_doc = NULL;
+ int result = -1;
+
+ aug_doc = parse_xml(ncf, aug_xml);
+ ERR_BAIL(ncf);
+
+ *ncf_xml = apply_stylesheet_to_string(ncf, ncf->driver->put, aug_doc);
+ ERR_BAIL(ncf);
+
+ /* fallthrough intentional */
+ result = 0;
+ error:
+ xmlFreeDoc(ncf_doc);
+ xmlFreeDoc(aug_doc);
+ return result;
+}
+
+/*
+ * Test interface
+ */
+int ncf_get_aug(struct netcf *ncf, const char *ncf_xml, char **aug_xml) {
+ API_ENTRY(ncf);
+
+ return drv_get_aug(ncf, ncf_xml, aug_xml);
+}
+
+int ncf_put_aug(struct netcf *ncf, const char *aug_xml, char **ncf_xml) {
+ API_ENTRY(ncf);
+
+ return drv_put_aug(ncf, aug_xml, ncf_xml);
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
+/* vim: set ts=4 sw=4 et: */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b5688ef..701aba0 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -6,7 +6,7 @@ GNULIB_CFLAGS= -I $(top_srcdir)/gnulib/lib
AM_CFLAGS = $(NETCF_CFLAGS) $(WARN_CFLAGS) $(GNULIB_CFLAGS) \
$(LIBXML_CFLAGS) -I $(top_builddir)/src
-EXTRA_DIST = interface initscripts root
+EXTRA_DIST = interface redhat root
TESTS_ENVIRONMENT = \
PATH='$(abs_top_builddir)/src$(PATH_SEPARATOR)'"$$PATH" \
@@ -14,20 +14,20 @@ TESTS_ENVIRONMENT = \
abs_top_builddir='$(abs_top_builddir)' \
abs_top_srcdir='$(abs_top_srcdir)'
-TESTS=test-initscripts
+TESTS=test-redhat
INCLUDES = -I$(top_srcdir)/src
# FIXME: Needs to be conditionalized
-check_PROGRAMS=test-initscripts
+check_PROGRAMS=test-redhat
-test_initscripts_SOURCES = test-initscripts.c cutest.c cutest.h tutil.c tutil.h
-test_initscripts_LDADD = $(top_builddir)/src/libnetcf.la $(GNULIB)
+test_redhat_SOURCES = test-redhat.c cutest.c cutest.h tutil.c tutil.h
+test_redhat_LDADD = $(top_builddir)/src/libnetcf.la $(GNULIB)
-# Clean up files generated by test-initscripts
+# Clean up files generated by test-redhat
distclean-local:
- @chmod -R u+w $(top_builddir)/build/test_initscripts
- @rm -rf $(top_builddir)/build/test_initscripts
+ @chmod -R u+w $(top_builddir)/build/test_redhat
+ @rm -rf $(top_builddir)/build/test_redhat
xmllint:
@(for f in interface/*.xml; do \
diff --git a/tests/initscripts/bond-arp.xml b/tests/initscripts/bond-arp.xml
deleted file mode 100644
index 6a53d09..0000000
--- a/tests/initscripts/bond-arp.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0"?>
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-bond0">
- <node label="DEVICE" value="bond0"/>
- <node label="ONBOOT" value="no"/>
- <node label="BOOTPROTO" value="none"/>
- <node label="IPADDR" value="192.168.50.7"/>
- <node label="NETMASK" value="255.255.255.0"/>
- <node label="GATEWAY" value="192.168.50.1"/>
- <node label="BONDING_OPTS" value="'mode=active-backup
primary=eth1 arp_interval=100 arp_ip_target=192.168.50.1
arp_validate=active'"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
- <node label="DEVICE" value="eth1"/>
- <node label="ONBOOT" value="no"/>
- <node label="MASTER" value="bond0"/>
- <node label="SLAVE" value="yes"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
- <node label="DEVICE" value="eth0"/>
- <node label="ONBOOT" value="no"/>
- <node label="MASTER" value="bond0"/>
- <node label="SLAVE" value="yes"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/bond-defaults.xml b/tests/initscripts/bond-defaults.xml
deleted file mode 100644
index 3e92d19..0000000
--- a/tests/initscripts/bond-defaults.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!-- A sketch of how the ethernet-static.xml example would be
- turned into actual files.
-
- The XML notation is close to what would turn up in a Augeas tree -->
-
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-bond0">
- <node label="DEVICE" value="bond0"/>
- <node label="ONBOOT" value="no"/>
- <node label="BOOTPROTO" value="none"/>
- <node label="IPADDR" value="192.168.50.7"/>
- <node label="NETMASK" value="255.255.255.0"/>
- <node label="GATEWAY" value="192.168.50.1"/>
- <node label="BONDING_OPTS" value="''"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
- <node label="DEVICE" value="eth1"/>
- <node label="ONBOOT" value="no"/>
- <node label="MASTER" value="bond0"/>
- <node label="SLAVE" value="yes"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
- <node label="DEVICE" value="eth0"/>
- <node label="ONBOOT" value="no"/>
- <node label="MASTER" value="bond0"/>
- <node label="SLAVE" value="yes"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/bond.xml b/tests/initscripts/bond.xml
deleted file mode 100644
index d97542d..0000000
--- a/tests/initscripts/bond.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!-- A sketch of how the ethernet-static.xml example would be
- turned into actual files.
-
- The XML notation is close to what would turn up in a Augeas tree -->
-
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-bond0">
- <node label="DEVICE" value="bond0"/>
- <node label="ONBOOT" value="no"/>
- <node label="BOOTPROTO" value="none"/>
- <node label="IPADDR" value="192.168.50.7"/>
- <node label="NETMASK" value="255.255.255.0"/>
- <node label="GATEWAY" value="192.168.50.1"/>
- <node label="BONDING_OPTS" value="'mode=active-backup
primary=eth1 miimon=100 updelay=10 use_carrier=0'"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
- <node label="DEVICE" value="eth1"/>
- <node label="ONBOOT" value="no"/>
- <node label="MASTER" value="bond0"/>
- <node label="SLAVE" value="yes"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
- <node label="DEVICE" value="eth0"/>
- <node label="ONBOOT" value="no"/>
- <node label="MASTER" value="bond0"/>
- <node label="SLAVE" value="yes"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/bridge-bond.xml b/tests/initscripts/bridge-bond.xml
deleted file mode 100644
index c72f8d3..0000000
--- a/tests/initscripts/bridge-bond.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0"?>
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-br0">
- <node label="DEVICE" value="br0"/>
- <node label="ONBOOT" value="yes"/>
- <node label="MTU" value="1500"/>
- <node label="TYPE" value="Bridge"/>
- <node label="STP" value="off"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth2">
- <node label="DEVICE" value="eth2"/>
- <node label="ONBOOT" value="yes"/>
- <node label="MTU" value="1500"/>
- <node label="BRIDGE" value="br0"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-bond0">
- <node label="DEVICE" value="bond0"/>
- <node label="ONBOOT" value="yes"/>
- <node label="MTU" value="1500"/>
- <node label="BONDING_OPTS" value="'mode=active-backup
primary=eth1 miimon=100 updelay=10 use_carrier=0'"/>
- <node label="BRIDGE" value="br0"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
- <node label="DEVICE" value="eth1"/>
- <node label="ONBOOT" value="yes"/>
- <node label="MTU" value="1500"/>
- <node label="MASTER" value="bond0"/>
- <node label="SLAVE" value="yes"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
- <node label="DEVICE" value="eth0"/>
- <node label="ONBOOT" value="yes"/>
- <node label="MTU" value="1500"/>
- <node label="MASTER" value="bond0"/>
- <node label="SLAVE" value="yes"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/bridge-empty.xml b/tests/initscripts/bridge-empty.xml
deleted file mode 100644
index 17d9764..0000000
--- a/tests/initscripts/bridge-empty.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-br0">
- <node label="DEVICE" value="br0"/>
- <node label="ONBOOT" value="yes"/>
- <node label="MTU" value="1500"/>
- <node label="TYPE" value="Bridge"/>
- <node label="STP" value="off"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/bridge-no-address.xml
b/tests/initscripts/bridge-no-address.xml
deleted file mode 100644
index 2a36d60..0000000
--- a/tests/initscripts/bridge-no-address.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!-- A sketch of how the ethernet-static.xml example would be
- turned into actual files.
-
- The XML notation is close to what would turn up in a Augeas tree -->
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-br0">
- <node label="DEVICE" value="br0"/>
- <node label="ONBOOT" value="yes"/>
- <node label="MTU" value="1500"/>
- <node label="TYPE" value="Bridge"/>
- <node label="STP" value="off"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
- <node label="DEVICE" value="eth0"/>
- <node label="HWADDR" value="ab:bb:cc:dd:ee:ff"/>
- <node label="ONBOOT" value="yes"/>
- <node label="MTU" value="1500"/>
- <node label="BRIDGE" value="br0"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
- <node label="DEVICE" value="eth1"/>
- <node label="ONBOOT" value="yes"/>
- <node label="MTU" value="1500"/>
- <node label="BRIDGE" value="br0"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/bridge-vlan.xml b/tests/initscripts/bridge-vlan.xml
deleted file mode 100644
index d7c0ed5..0000000
--- a/tests/initscripts/bridge-vlan.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0"?>
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-br0">
- <node label="DEVICE" value="br0"/>
- <node label="ONBOOT" value="yes"/>
- <node label="TYPE" value="Bridge"/>
- <node label="BOOTPROTO" value="dhcp"/>
- <node label="STP" value="off"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0.42">
- <node label="DEVICE" value="eth0.42"/>
- <node label="VLAN" value="yes"/>
- <node label="ONBOOT" value="yes"/>
- <node label="BRIDGE" value="br0"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/bridge.xml b/tests/initscripts/bridge.xml
deleted file mode 100644
index d49313f..0000000
--- a/tests/initscripts/bridge.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!-- A sketch of how the ethernet-static.xml example would be
- turned into actual files.
-
- The XML notation is close to what would turn up in a Augeas tree -->
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-br0">
- <node label="DEVICE" value="br0"/>
- <node label="ONBOOT" value="yes"/>
- <node label="MTU" value="1500"/>
- <node label="TYPE" value="Bridge"/>
- <node label="BOOTPROTO" value="dhcp"/>
- <node label="STP" value="off"/>
- <node label="DELAY" value="0.01"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
- <node label="DEVICE" value="eth0"/>
- <node label="HWADDR" value="ab:bb:cc:dd:ee:ff"/>
- <node label="ONBOOT" value="yes"/>
- <node label="MTU" value="1500"/>
- <node label="BRIDGE" value="br0"/>
- </tree>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
- <node label="DEVICE" value="eth1"/>
- <node label="ONBOOT" value="yes"/>
- <node label="MTU" value="1500"/>
- <node label="BRIDGE" value="br0"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/ethernet-dhcp.xml b/tests/initscripts/ethernet-dhcp.xml
deleted file mode 100644
index 6ce4b2f..0000000
--- a/tests/initscripts/ethernet-dhcp.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<!-- A sketch of how the ethernet-static.xml example would be
- turned into actual files.
-
- The XML notation is close to what would turn up in a Augeas tree -->
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
- <node label="DEVICE" value="eth0"/>
- <node label="HWADDR" value="aa:bb:cc:dd:ee:ff"/>
- <node label="ONBOOT" value="no"/>
- <node label="MTU" value="1492"/>
- <node label="BOOTPROTO" value="dhcp"/>
- <node label="PEERDNS" value="no"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/ethernet-static-no-prefix.xml
b/tests/initscripts/ethernet-static-no-prefix.xml
deleted file mode 100644
index ddca034..0000000
--- a/tests/initscripts/ethernet-static-no-prefix.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<!-- A sketch of how the ethernet-static.xml example would be
- turned into actual files.
-
- The XML notation is close to what would turn up in a Augeas tree -->
-
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
- <node label="DEVICE" value="eth1"/>
- <node label="ONBOOT" value="yes"/>
- <node label="BOOTPROTO" value="none"/>
- <node label="IPADDR" value="192.168.0.5"/>
- <node label="GATEWAY" value="192.168.0.1"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/ethernet-static.xml
b/tests/initscripts/ethernet-static.xml
deleted file mode 100644
index 5fc6b42..0000000
--- a/tests/initscripts/ethernet-static.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<!-- A sketch of how the ethernet-static.xml example would be
- turned into actual files.
-
- The XML notation is close to what would turn up in a Augeas tree -->
-
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
- <node label="DEVICE" value="eth1"/>
- <node label="ONBOOT" value="yes"/>
- <node label="BOOTPROTO" value="none"/>
- <node label="IPADDR" value="192.168.0.5"/>
- <node label="NETMASK" value="255.255.255.0"/>
- <node label="GATEWAY" value="192.168.0.1"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/ipv6-autoconf-dhcp.xml
b/tests/initscripts/ipv6-autoconf-dhcp.xml
deleted file mode 100644
index f755fa4..0000000
--- a/tests/initscripts/ipv6-autoconf-dhcp.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
- <node label="DEVICE" value="eth0"/>
- <node label="ONBOOT" value="yes"/>
- <node label="IPV6INIT" value="yes"/>
- <node label="IPV6_AUTOCONF" value="yes"/>
- <node label="DHCPV6" value="yes"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/ipv6-autoconf.xml b/tests/initscripts/ipv6-autoconf.xml
deleted file mode 100644
index 637864c..0000000
--- a/tests/initscripts/ipv6-autoconf.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
- <node label="DEVICE" value="eth0"/>
- <node label="ONBOOT" value="yes"/>
- <node label="IPV6INIT" value="yes"/>
- <node label="IPV6_AUTOCONF" value="yes"/>
- <node label="DHCPV6" value="no"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/ipv6-dhcp.xml b/tests/initscripts/ipv6-dhcp.xml
deleted file mode 100644
index c87f0ce..0000000
--- a/tests/initscripts/ipv6-dhcp.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
- <node label="DEVICE" value="eth0"/>
- <node label="ONBOOT" value="yes"/>
- <node label="IPV6INIT" value="yes"/>
- <node label="IPV6_AUTOCONF" value="no"/>
- <node label="DHCPV6" value="yes"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/ipv6-local.xml b/tests/initscripts/ipv6-local.xml
deleted file mode 100644
index 96294f8..0000000
--- a/tests/initscripts/ipv6-local.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
- <node label="DEVICE" value="eth0"/>
- <node label="ONBOOT" value="yes"/>
- <node label="IPV6INIT" value="yes"/>
- <node label="IPV6_AUTOCONF" value="no"/>
- <node label="DHCPV6" value="no"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/ipv6-static-multi.xml
b/tests/initscripts/ipv6-static-multi.xml
deleted file mode 100644
index e8eec8f..0000000
--- a/tests/initscripts/ipv6-static-multi.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0"?>
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
- <node label="DEVICE" value="eth0"/>
- <node label="ONBOOT" value="yes"/>
- <node label="IPV6INIT" value="yes"/>
- <node label="IPV6_AUTOCONF" value="no"/>
- <node label="DHCPV6" value="no"/>
- <node label="IPV6ADDR" value="3ffe:ffff:0:5::1/128"/>
- <node label="IPV6ADDR_SECONDARIES" value="'3ffe:ffff:0:5::3/128
3ffe:ffff:0:5::5/128'"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/ipv6-static.xml b/tests/initscripts/ipv6-static.xml
deleted file mode 100644
index 187b1dc..0000000
--- a/tests/initscripts/ipv6-static.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0"?>
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
- <node label="DEVICE" value="eth0"/>
- <node label="ONBOOT" value="yes"/>
- <node label="IPV6INIT" value="yes"/>
- <node label="IPV6_AUTOCONF" value="no"/>
- <node label="DHCPV6" value="no"/>
- <node label="IPV6ADDR" value="3ffe:ffff:0:5::1/128"/>
- <node label="IPV6_DEFAULTGW"
value="3ffe:ffff:1234:5678::1"/>
- </tree>
-</forest>
diff --git a/tests/initscripts/schemas.xml b/tests/initscripts/schemas.xml
deleted file mode 100644
index a970597..0000000
--- a/tests/initscripts/schemas.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0"?>
-<locatingRules
xmlns="http://thaiopensource.com/ns/locating-rules/1.0">
- <include rules="../../data/xml/schemas.xml"/>
-</locatingRules>
diff --git a/tests/initscripts/vlan.xml b/tests/initscripts/vlan.xml
deleted file mode 100644
index 36ad0f2..0000000
--- a/tests/initscripts/vlan.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<forest>
- <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0.42">
- <node label="DEVICE" value="eth0.42"/>
- <node label="VLAN" value="yes"/>
- <node label="ONBOOT" value="yes"/>
- <node label="BOOTPROTO" value="dhcp"/>
- <node label="PEERDNS" value="no"/>
- </tree>
-</forest>
diff --git a/tests/redhat/bond-arp.xml b/tests/redhat/bond-arp.xml
new file mode 100644
index 0000000..6a53d09
--- /dev/null
+++ b/tests/redhat/bond-arp.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-bond0">
+ <node label="DEVICE" value="bond0"/>
+ <node label="ONBOOT" value="no"/>
+ <node label="BOOTPROTO" value="none"/>
+ <node label="IPADDR" value="192.168.50.7"/>
+ <node label="NETMASK" value="255.255.255.0"/>
+ <node label="GATEWAY" value="192.168.50.1"/>
+ <node label="BONDING_OPTS" value="'mode=active-backup
primary=eth1 arp_interval=100 arp_ip_target=192.168.50.1
arp_validate=active'"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
+ <node label="DEVICE" value="eth1"/>
+ <node label="ONBOOT" value="no"/>
+ <node label="MASTER" value="bond0"/>
+ <node label="SLAVE" value="yes"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
+ <node label="DEVICE" value="eth0"/>
+ <node label="ONBOOT" value="no"/>
+ <node label="MASTER" value="bond0"/>
+ <node label="SLAVE" value="yes"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/bond-defaults.xml b/tests/redhat/bond-defaults.xml
new file mode 100644
index 0000000..3e92d19
--- /dev/null
+++ b/tests/redhat/bond-defaults.xml
@@ -0,0 +1,28 @@
+<!-- A sketch of how the ethernet-static.xml example would be
+ turned into actual files.
+
+ The XML notation is close to what would turn up in a Augeas tree -->
+
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-bond0">
+ <node label="DEVICE" value="bond0"/>
+ <node label="ONBOOT" value="no"/>
+ <node label="BOOTPROTO" value="none"/>
+ <node label="IPADDR" value="192.168.50.7"/>
+ <node label="NETMASK" value="255.255.255.0"/>
+ <node label="GATEWAY" value="192.168.50.1"/>
+ <node label="BONDING_OPTS" value="''"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
+ <node label="DEVICE" value="eth1"/>
+ <node label="ONBOOT" value="no"/>
+ <node label="MASTER" value="bond0"/>
+ <node label="SLAVE" value="yes"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
+ <node label="DEVICE" value="eth0"/>
+ <node label="ONBOOT" value="no"/>
+ <node label="MASTER" value="bond0"/>
+ <node label="SLAVE" value="yes"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/bond.xml b/tests/redhat/bond.xml
new file mode 100644
index 0000000..d97542d
--- /dev/null
+++ b/tests/redhat/bond.xml
@@ -0,0 +1,28 @@
+<!-- A sketch of how the ethernet-static.xml example would be
+ turned into actual files.
+
+ The XML notation is close to what would turn up in a Augeas tree -->
+
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-bond0">
+ <node label="DEVICE" value="bond0"/>
+ <node label="ONBOOT" value="no"/>
+ <node label="BOOTPROTO" value="none"/>
+ <node label="IPADDR" value="192.168.50.7"/>
+ <node label="NETMASK" value="255.255.255.0"/>
+ <node label="GATEWAY" value="192.168.50.1"/>
+ <node label="BONDING_OPTS" value="'mode=active-backup
primary=eth1 miimon=100 updelay=10 use_carrier=0'"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
+ <node label="DEVICE" value="eth1"/>
+ <node label="ONBOOT" value="no"/>
+ <node label="MASTER" value="bond0"/>
+ <node label="SLAVE" value="yes"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
+ <node label="DEVICE" value="eth0"/>
+ <node label="ONBOOT" value="no"/>
+ <node label="MASTER" value="bond0"/>
+ <node label="SLAVE" value="yes"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/bridge-bond.xml b/tests/redhat/bridge-bond.xml
new file mode 100644
index 0000000..c72f8d3
--- /dev/null
+++ b/tests/redhat/bridge-bond.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-br0">
+ <node label="DEVICE" value="br0"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="MTU" value="1500"/>
+ <node label="TYPE" value="Bridge"/>
+ <node label="STP" value="off"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth2">
+ <node label="DEVICE" value="eth2"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="MTU" value="1500"/>
+ <node label="BRIDGE" value="br0"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-bond0">
+ <node label="DEVICE" value="bond0"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="MTU" value="1500"/>
+ <node label="BONDING_OPTS" value="'mode=active-backup
primary=eth1 miimon=100 updelay=10 use_carrier=0'"/>
+ <node label="BRIDGE" value="br0"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
+ <node label="DEVICE" value="eth1"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="MTU" value="1500"/>
+ <node label="MASTER" value="bond0"/>
+ <node label="SLAVE" value="yes"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
+ <node label="DEVICE" value="eth0"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="MTU" value="1500"/>
+ <node label="MASTER" value="bond0"/>
+ <node label="SLAVE" value="yes"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/bridge-empty.xml b/tests/redhat/bridge-empty.xml
new file mode 100644
index 0000000..17d9764
--- /dev/null
+++ b/tests/redhat/bridge-empty.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-br0">
+ <node label="DEVICE" value="br0"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="MTU" value="1500"/>
+ <node label="TYPE" value="Bridge"/>
+ <node label="STP" value="off"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/bridge-no-address.xml b/tests/redhat/bridge-no-address.xml
new file mode 100644
index 0000000..2a36d60
--- /dev/null
+++ b/tests/redhat/bridge-no-address.xml
@@ -0,0 +1,26 @@
+<!-- A sketch of how the ethernet-static.xml example would be
+ turned into actual files.
+
+ The XML notation is close to what would turn up in a Augeas tree -->
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-br0">
+ <node label="DEVICE" value="br0"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="MTU" value="1500"/>
+ <node label="TYPE" value="Bridge"/>
+ <node label="STP" value="off"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
+ <node label="DEVICE" value="eth0"/>
+ <node label="HWADDR" value="ab:bb:cc:dd:ee:ff"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="MTU" value="1500"/>
+ <node label="BRIDGE" value="br0"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
+ <node label="DEVICE" value="eth1"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="MTU" value="1500"/>
+ <node label="BRIDGE" value="br0"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/bridge-vlan.xml b/tests/redhat/bridge-vlan.xml
new file mode 100644
index 0000000..d7c0ed5
--- /dev/null
+++ b/tests/redhat/bridge-vlan.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-br0">
+ <node label="DEVICE" value="br0"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="TYPE" value="Bridge"/>
+ <node label="BOOTPROTO" value="dhcp"/>
+ <node label="STP" value="off"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0.42">
+ <node label="DEVICE" value="eth0.42"/>
+ <node label="VLAN" value="yes"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="BRIDGE" value="br0"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/bridge.xml b/tests/redhat/bridge.xml
new file mode 100644
index 0000000..d49313f
--- /dev/null
+++ b/tests/redhat/bridge.xml
@@ -0,0 +1,28 @@
+<!-- A sketch of how the ethernet-static.xml example would be
+ turned into actual files.
+
+ The XML notation is close to what would turn up in a Augeas tree -->
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-br0">
+ <node label="DEVICE" value="br0"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="MTU" value="1500"/>
+ <node label="TYPE" value="Bridge"/>
+ <node label="BOOTPROTO" value="dhcp"/>
+ <node label="STP" value="off"/>
+ <node label="DELAY" value="0.01"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
+ <node label="DEVICE" value="eth0"/>
+ <node label="HWADDR" value="ab:bb:cc:dd:ee:ff"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="MTU" value="1500"/>
+ <node label="BRIDGE" value="br0"/>
+ </tree>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
+ <node label="DEVICE" value="eth1"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="MTU" value="1500"/>
+ <node label="BRIDGE" value="br0"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/ethernet-dhcp.xml b/tests/redhat/ethernet-dhcp.xml
new file mode 100644
index 0000000..6ce4b2f
--- /dev/null
+++ b/tests/redhat/ethernet-dhcp.xml
@@ -0,0 +1,14 @@
+<!-- A sketch of how the ethernet-static.xml example would be
+ turned into actual files.
+
+ The XML notation is close to what would turn up in a Augeas tree -->
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
+ <node label="DEVICE" value="eth0"/>
+ <node label="HWADDR" value="aa:bb:cc:dd:ee:ff"/>
+ <node label="ONBOOT" value="no"/>
+ <node label="MTU" value="1492"/>
+ <node label="BOOTPROTO" value="dhcp"/>
+ <node label="PEERDNS" value="no"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/ethernet-static-no-prefix.xml
b/tests/redhat/ethernet-static-no-prefix.xml
new file mode 100644
index 0000000..ddca034
--- /dev/null
+++ b/tests/redhat/ethernet-static-no-prefix.xml
@@ -0,0 +1,14 @@
+<!-- A sketch of how the ethernet-static.xml example would be
+ turned into actual files.
+
+ The XML notation is close to what would turn up in a Augeas tree -->
+
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
+ <node label="DEVICE" value="eth1"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="BOOTPROTO" value="none"/>
+ <node label="IPADDR" value="192.168.0.5"/>
+ <node label="GATEWAY" value="192.168.0.1"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/ethernet-static.xml b/tests/redhat/ethernet-static.xml
new file mode 100644
index 0000000..5fc6b42
--- /dev/null
+++ b/tests/redhat/ethernet-static.xml
@@ -0,0 +1,15 @@
+<!-- A sketch of how the ethernet-static.xml example would be
+ turned into actual files.
+
+ The XML notation is close to what would turn up in a Augeas tree -->
+
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth1">
+ <node label="DEVICE" value="eth1"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="BOOTPROTO" value="none"/>
+ <node label="IPADDR" value="192.168.0.5"/>
+ <node label="NETMASK" value="255.255.255.0"/>
+ <node label="GATEWAY" value="192.168.0.1"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/ipv6-autoconf-dhcp.xml b/tests/redhat/ipv6-autoconf-dhcp.xml
new file mode 100644
index 0000000..f755fa4
--- /dev/null
+++ b/tests/redhat/ipv6-autoconf-dhcp.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
+ <node label="DEVICE" value="eth0"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="IPV6INIT" value="yes"/>
+ <node label="IPV6_AUTOCONF" value="yes"/>
+ <node label="DHCPV6" value="yes"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/ipv6-autoconf.xml b/tests/redhat/ipv6-autoconf.xml
new file mode 100644
index 0000000..637864c
--- /dev/null
+++ b/tests/redhat/ipv6-autoconf.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
+ <node label="DEVICE" value="eth0"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="IPV6INIT" value="yes"/>
+ <node label="IPV6_AUTOCONF" value="yes"/>
+ <node label="DHCPV6" value="no"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/ipv6-dhcp.xml b/tests/redhat/ipv6-dhcp.xml
new file mode 100644
index 0000000..c87f0ce
--- /dev/null
+++ b/tests/redhat/ipv6-dhcp.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
+ <node label="DEVICE" value="eth0"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="IPV6INIT" value="yes"/>
+ <node label="IPV6_AUTOCONF" value="no"/>
+ <node label="DHCPV6" value="yes"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/ipv6-local.xml b/tests/redhat/ipv6-local.xml
new file mode 100644
index 0000000..96294f8
--- /dev/null
+++ b/tests/redhat/ipv6-local.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
+ <node label="DEVICE" value="eth0"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="IPV6INIT" value="yes"/>
+ <node label="IPV6_AUTOCONF" value="no"/>
+ <node label="DHCPV6" value="no"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/ipv6-static-multi.xml b/tests/redhat/ipv6-static-multi.xml
new file mode 100644
index 0000000..e8eec8f
--- /dev/null
+++ b/tests/redhat/ipv6-static-multi.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
+ <node label="DEVICE" value="eth0"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="IPV6INIT" value="yes"/>
+ <node label="IPV6_AUTOCONF" value="no"/>
+ <node label="DHCPV6" value="no"/>
+ <node label="IPV6ADDR" value="3ffe:ffff:0:5::1/128"/>
+ <node label="IPV6ADDR_SECONDARIES" value="'3ffe:ffff:0:5::3/128
3ffe:ffff:0:5::5/128'"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/ipv6-static.xml b/tests/redhat/ipv6-static.xml
new file mode 100644
index 0000000..187b1dc
--- /dev/null
+++ b/tests/redhat/ipv6-static.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0">
+ <node label="DEVICE" value="eth0"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="IPV6INIT" value="yes"/>
+ <node label="IPV6_AUTOCONF" value="no"/>
+ <node label="DHCPV6" value="no"/>
+ <node label="IPV6ADDR" value="3ffe:ffff:0:5::1/128"/>
+ <node label="IPV6_DEFAULTGW"
value="3ffe:ffff:1234:5678::1"/>
+ </tree>
+</forest>
diff --git a/tests/redhat/schemas.xml b/tests/redhat/schemas.xml
new file mode 100644
index 0000000..a970597
--- /dev/null
+++ b/tests/redhat/schemas.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<locatingRules
xmlns="http://thaiopensource.com/ns/locating-rules/1.0">
+ <include rules="../../data/xml/schemas.xml"/>
+</locatingRules>
diff --git a/tests/redhat/vlan.xml b/tests/redhat/vlan.xml
new file mode 100644
index 0000000..36ad0f2
--- /dev/null
+++ b/tests/redhat/vlan.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<forest>
+ <tree path="/files/etc/sysconfig/network-scripts/ifcfg-eth0.42">
+ <node label="DEVICE" value="eth0.42"/>
+ <node label="VLAN" value="yes"/>
+ <node label="ONBOOT" value="yes"/>
+ <node label="BOOTPROTO" value="dhcp"/>
+ <node label="PEERDNS" value="no"/>
+ </tree>
+</forest>
diff --git a/tests/test-initscripts.c b/tests/test-initscripts.c
deleted file mode 100644
index 404ec0a..0000000
--- a/tests/test-initscripts.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * test-initscripts.c:
- *
- * Copyright (C) 2009 Red Hat Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: David Lutterkort <lutter(a)redhat.com>
- */
-
-#include <config.h>
-#include "netcf.h"
-#include "internal.h"
-#include "cutest.h"
-#include "safe-alloc.h"
-#include "read-file.h"
-
-#include "tutil.h"
-
-#include <stdio.h>
-
-#include <libxml/tree.h>
-
-extern const char *abs_top_srcdir;
-extern const char *abs_top_builddir;
-extern char *driver_name;
-extern char *root, *src_root;
-extern struct netcf *ncf;
-
-static void testListInterfaces(CuTest *tc) {
- int nint;
- char **names;
- static const char *const exp_names[] =
- { "br0", "bond0", "lo", "eth3",
"eth4" };
- static const int exp_nint = ARRAY_CARDINALITY(exp_names);
-
- nint = ncf_num_of_interfaces(ncf, NETCF_IFACE_ACTIVE|NETCF_IFACE_INACTIVE);
- CuAssertIntEquals(tc, exp_nint, nint);
- if (ALLOC_N(names, nint) < 0)
- die("allocation failed");
- nint = ncf_list_interfaces(ncf, nint, names,
NETCF_IFACE_ACTIVE|NETCF_IFACE_INACTIVE);
- CuAssertIntEquals(tc, exp_nint, nint);
- for (int i=0; i < exp_nint; i++) {
- int found = 0;
- for (int j=0; j < nint; j++) {
- if (STREQ(names[j], exp_names[i]))
- found = 1;
- }
- CuAssert(tc, "Unknown interface name", found);
- }
-}
-
-static void testLookupByName(CuTest *tc) {
- struct netcf_if *nif;
-
- nif = ncf_lookup_by_name(ncf, "br0");
- CuAssertPtrNotNull(tc, nif);
- CuAssertStrEquals(tc, "br0", nif->name);
- ncf_if_free(nif);
- CuAssertIntEquals(tc, 1, ncf->ref);
-}
-
-/* Check that we get the right ifcfg- file when we have to
- * look it up indirectly by HWADDR
- */
-static void testLookupByNameDecoy(CuTest *tc) {
- struct netcf_if *nif;
- char *xml, *loc;
-
- nif = ncf_lookup_by_name(ncf, "eth4");
- CuAssertPtrNotNull(tc, nif);
- CuAssertStrEquals(tc, "eth4", nif->name);
-
- xml = ncf_if_xml_desc(nif);
- CuAssertPtrNotNull(tc, xml);
- loc = strstr(xml, "<mac address=\"00:00:00:00:00:01\"/>");
- CuAssertPtrNotNull(tc, loc);
-
- free(xml);
- ncf_if_free(nif);
- CuAssertIntEquals(tc, 1, ncf->ref);
-}
-
-static void testLookupByMAC(CuTest *tc) {
- static const char *const good_mac = "aa:bb:cc:dd:ee:ff";
- static const char *const good_mac_caps = "AA:bb:cc:DD:Ee:ff";
- struct netcf_if *nif;
- int r;
-
- r = ncf_lookup_by_mac_string(ncf, "00:00:00:00:00:00", 1, &nif);
- CuAssertIntEquals(tc, 0, r);
- CuAssertPtrEquals(tc, NULL, nif);
-
- r = ncf_lookup_by_mac_string(ncf, good_mac, 1, &nif);
- CuAssertIntEquals(tc, 1, r);
- CuAssertPtrNotNull(tc, nif);
- CuAssertStrEquals(tc, "br0", nif->name);
- CuAssertStrEquals(tc, good_mac, ncf_if_mac_string(nif));
- ncf_if_free(nif);
- CuAssertIntEquals(tc, 1, ncf->ref);
-
- r = ncf_lookup_by_mac_string(ncf, good_mac_caps, 1, &nif);
- CuAssertIntEquals(tc, 1, r);
- CuAssertPtrNotNull(tc, nif);
- CuAssertStrEquals(tc, "br0", nif->name);
- CuAssertStrEquals(tc, good_mac, ncf_if_mac_string(nif));
- ncf_if_free(nif);
- CuAssertIntEquals(tc, 1, ncf->ref);
-}
-
-static void testDefineUndefine(CuTest *tc) {
- char *bridge_xml = NULL;
- struct netcf_if *nif = NULL;
- int r;
-
- bridge_xml = read_test_file(tc, "interface/bridge42.xml");
- CuAssertPtrNotNull(tc, bridge_xml);
-
- nif = ncf_define(ncf, bridge_xml);
- CuAssertPtrNotNull(tc, nif);
- assert_ncf_no_error(tc);
-
- r = ncf_if_undefine(nif);
- CuAssertIntEquals(tc, 0, r);
- assert_ncf_no_error(tc);
-
- ncf_close(ncf);
- r = ncf_init(&ncf, root);
- CuAssertIntEquals(tc, 0, r);
-
- nif = ncf_lookup_by_name(ncf, "br42");
- CuAssertPtrEquals(tc, NULL, nif);
-}
-
-static void assert_transforms(CuTest *tc, const char *base) {
- char *aug_fname = NULL, *ncf_fname = NULL;
- char *aug_xml_exp = NULL, *ncf_xml_exp = NULL;
- char *aug_xml_act = NULL, *ncf_xml_act = NULL;
- int r;
-
- r = asprintf(&aug_fname, "initscripts/%s.xml", base);
- r = asprintf(&ncf_fname, "interface/%s.xml", base);
-
- aug_xml_exp = read_test_file(tc, aug_fname);
- ncf_xml_exp = read_test_file(tc, ncf_fname);
-
- r = ncf_get_aug(ncf, ncf_xml_exp, &aug_xml_act);
- CuAssertIntEquals(tc, 0, r);
-
- r = ncf_put_aug(ncf, aug_xml_exp, &ncf_xml_act);
- CuAssertIntEquals(tc, 0, r);
-
- assert_xml_equals(tc, ncf_fname, ncf_xml_exp, ncf_xml_act);
- assert_xml_equals(tc, aug_fname, aug_xml_exp, aug_xml_act);
-
- free(ncf_xml_exp);
- free(ncf_xml_act);
- free(aug_xml_exp);
- free(aug_xml_act);
-}
-
-static void testTransforms(CuTest *tc) {
- assert_transforms(tc, "bond");
- assert_transforms(tc, "bond-arp");
- assert_transforms(tc, "bond-defaults");
- assert_transforms(tc, "bridge");
- assert_transforms(tc, "bridge-no-address");
- assert_transforms(tc, "bridge-vlan");
- assert_transforms(tc, "bridge-empty");
- assert_transforms(tc, "bridge-bond");
- assert_transforms(tc, "ethernet-static");
- assert_transforms(tc, "ethernet-static-no-prefix");
- assert_transforms(tc, "ethernet-dhcp");
- assert_transforms(tc, "vlan");
-
- assert_transforms(tc, "ipv6-local");
- assert_transforms(tc, "ipv6-static");
- assert_transforms(tc, "ipv6-dhcp");
- assert_transforms(tc, "ipv6-autoconf");
- assert_transforms(tc, "ipv6-autoconf-dhcp");
- assert_transforms(tc, "ipv6-static-multi");
-}
-
-static void testCorruptedSetup(CuTest *tc) {
- int r;
-
- ncf_close(ncf);
- ncf = NULL;
-
- r = ncf_init(&ncf, "/dev/null");
- CuAssertIntEquals(tc, -1, r);
- CuAssertPtrNotNull(tc, ncf);
- r = ncf_error(ncf, NULL, NULL);
- CuAssertIntEquals(tc, NETCF_EFILE, r);
-}
-
-int main(void) {
- char *output = NULL;
- CuSuite* suite = CuSuiteNew();
-
- abs_top_srcdir = getenv("abs_top_srcdir");
- if (abs_top_srcdir == NULL)
- die("env var abs_top_srcdir must be set");
-
- abs_top_builddir = getenv("abs_top_builddir");
- if (abs_top_builddir == NULL)
- die("env var abs_top_builddir must be set");
-
- if (asprintf(&src_root, "%s/tests/root", abs_top_srcdir) < 0) {
- die("failed to set src_root");
- }
-
- driver_name = strdup("initscripts");
- if (driver_name == NULL) {
- die("failed to set driver name");
- }
-
- CuSuiteSetup(suite, setup, teardown);
-
- SUITE_ADD_TEST(suite, testListInterfaces);
- SUITE_ADD_TEST(suite, testLookupByName);
- SUITE_ADD_TEST(suite, testLookupByNameDecoy);
- SUITE_ADD_TEST(suite, testLookupByMAC);
- SUITE_ADD_TEST(suite, testDefineUndefine);
- SUITE_ADD_TEST(suite, testTransforms);
- SUITE_ADD_TEST(suite, testCorruptedSetup);
-
- CuSuiteRun(suite);
- CuSuiteSummary(suite, &output);
- CuSuiteDetails(suite, &output);
- printf("%s\n", output);
- free(output);
- free(driver_name);
- return suite->failCount;
-}
-
-/*
- * Local variables:
- * indent-tabs-mode: nil
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- */
-/* vim: set ts=4 sw=4 et: */
diff --git a/tests/test-redhat.c b/tests/test-redhat.c
new file mode 100644
index 0000000..29b78b9
--- /dev/null
+++ b/tests/test-redhat.c
@@ -0,0 +1,257 @@
+/*
+ * test-redhat.c:
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: David Lutterkort <lutter(a)redhat.com>
+ */
+
+#include <config.h>
+#include "netcf.h"
+#include "internal.h"
+#include "cutest.h"
+#include "safe-alloc.h"
+#include "read-file.h"
+
+#include "tutil.h"
+
+#include <stdio.h>
+
+#include <libxml/tree.h>
+
+extern const char *abs_top_srcdir;
+extern const char *abs_top_builddir;
+extern char *driver_name;
+extern char *root, *src_root;
+extern struct netcf *ncf;
+
+static void testListInterfaces(CuTest *tc) {
+ int nint;
+ char **names;
+ static const char *const exp_names[] =
+ { "br0", "bond0", "lo", "eth3",
"eth4" };
+ static const int exp_nint = ARRAY_CARDINALITY(exp_names);
+
+ nint = ncf_num_of_interfaces(ncf, NETCF_IFACE_ACTIVE|NETCF_IFACE_INACTIVE);
+ CuAssertIntEquals(tc, exp_nint, nint);
+ if (ALLOC_N(names, nint) < 0)
+ die("allocation failed");
+ nint = ncf_list_interfaces(ncf, nint, names,
NETCF_IFACE_ACTIVE|NETCF_IFACE_INACTIVE);
+ CuAssertIntEquals(tc, exp_nint, nint);
+ for (int i=0; i < exp_nint; i++) {
+ int found = 0;
+ for (int j=0; j < nint; j++) {
+ if (STREQ(names[j], exp_names[i]))
+ found = 1;
+ }
+ CuAssert(tc, "Unknown interface name", found);
+ }
+}
+
+static void testLookupByName(CuTest *tc) {
+ struct netcf_if *nif;
+
+ nif = ncf_lookup_by_name(ncf, "br0");
+ CuAssertPtrNotNull(tc, nif);
+ CuAssertStrEquals(tc, "br0", nif->name);
+ ncf_if_free(nif);
+ CuAssertIntEquals(tc, 1, ncf->ref);
+}
+
+/* Check that we get the right ifcfg- file when we have to
+ * look it up indirectly by HWADDR
+ */
+static void testLookupByNameDecoy(CuTest *tc) {
+ struct netcf_if *nif;
+ char *xml, *loc;
+
+ nif = ncf_lookup_by_name(ncf, "eth4");
+ CuAssertPtrNotNull(tc, nif);
+ CuAssertStrEquals(tc, "eth4", nif->name);
+
+ xml = ncf_if_xml_desc(nif);
+ CuAssertPtrNotNull(tc, xml);
+ loc = strstr(xml, "<mac address=\"00:00:00:00:00:01\"/>");
+ CuAssertPtrNotNull(tc, loc);
+
+ free(xml);
+ ncf_if_free(nif);
+ CuAssertIntEquals(tc, 1, ncf->ref);
+}
+
+static void testLookupByMAC(CuTest *tc) {
+ static const char *const good_mac = "aa:bb:cc:dd:ee:ff";
+ static const char *const good_mac_caps = "AA:bb:cc:DD:Ee:ff";
+ struct netcf_if *nif;
+ int r;
+
+ r = ncf_lookup_by_mac_string(ncf, "00:00:00:00:00:00", 1, &nif);
+ CuAssertIntEquals(tc, 0, r);
+ CuAssertPtrEquals(tc, NULL, nif);
+
+ r = ncf_lookup_by_mac_string(ncf, good_mac, 1, &nif);
+ CuAssertIntEquals(tc, 1, r);
+ CuAssertPtrNotNull(tc, nif);
+ CuAssertStrEquals(tc, "br0", nif->name);
+ CuAssertStrEquals(tc, good_mac, ncf_if_mac_string(nif));
+ ncf_if_free(nif);
+ CuAssertIntEquals(tc, 1, ncf->ref);
+
+ r = ncf_lookup_by_mac_string(ncf, good_mac_caps, 1, &nif);
+ CuAssertIntEquals(tc, 1, r);
+ CuAssertPtrNotNull(tc, nif);
+ CuAssertStrEquals(tc, "br0", nif->name);
+ CuAssertStrEquals(tc, good_mac, ncf_if_mac_string(nif));
+ ncf_if_free(nif);
+ CuAssertIntEquals(tc, 1, ncf->ref);
+}
+
+static void testDefineUndefine(CuTest *tc) {
+ char *bridge_xml = NULL;
+ struct netcf_if *nif = NULL;
+ int r;
+
+ bridge_xml = read_test_file(tc, "interface/bridge42.xml");
+ CuAssertPtrNotNull(tc, bridge_xml);
+
+ nif = ncf_define(ncf, bridge_xml);
+ CuAssertPtrNotNull(tc, nif);
+ assert_ncf_no_error(tc);
+
+ r = ncf_if_undefine(nif);
+ CuAssertIntEquals(tc, 0, r);
+ assert_ncf_no_error(tc);
+
+ ncf_close(ncf);
+ r = ncf_init(&ncf, root);
+ CuAssertIntEquals(tc, 0, r);
+
+ nif = ncf_lookup_by_name(ncf, "br42");
+ CuAssertPtrEquals(tc, NULL, nif);
+}
+
+static void assert_transforms(CuTest *tc, const char *base) {
+ char *aug_fname = NULL, *ncf_fname = NULL;
+ char *aug_xml_exp = NULL, *ncf_xml_exp = NULL;
+ char *aug_xml_act = NULL, *ncf_xml_act = NULL;
+ int r;
+
+ r = asprintf(&aug_fname, "redhat/%s.xml", base);
+ r = asprintf(&ncf_fname, "interface/%s.xml", base);
+
+ aug_xml_exp = read_test_file(tc, aug_fname);
+ ncf_xml_exp = read_test_file(tc, ncf_fname);
+
+ r = ncf_get_aug(ncf, ncf_xml_exp, &aug_xml_act);
+ CuAssertIntEquals(tc, 0, r);
+
+ r = ncf_put_aug(ncf, aug_xml_exp, &ncf_xml_act);
+ CuAssertIntEquals(tc, 0, r);
+
+ assert_xml_equals(tc, ncf_fname, ncf_xml_exp, ncf_xml_act);
+ assert_xml_equals(tc, aug_fname, aug_xml_exp, aug_xml_act);
+
+ free(ncf_xml_exp);
+ free(ncf_xml_act);
+ free(aug_xml_exp);
+ free(aug_xml_act);
+}
+
+static void testTransforms(CuTest *tc) {
+ assert_transforms(tc, "bond");
+ assert_transforms(tc, "bond-arp");
+ assert_transforms(tc, "bond-defaults");
+ assert_transforms(tc, "bridge");
+ assert_transforms(tc, "bridge-no-address");
+ assert_transforms(tc, "bridge-vlan");
+ assert_transforms(tc, "bridge-empty");
+ assert_transforms(tc, "bridge-bond");
+ assert_transforms(tc, "ethernet-static");
+ assert_transforms(tc, "ethernet-static-no-prefix");
+ assert_transforms(tc, "ethernet-dhcp");
+ assert_transforms(tc, "vlan");
+
+ assert_transforms(tc, "ipv6-local");
+ assert_transforms(tc, "ipv6-static");
+ assert_transforms(tc, "ipv6-dhcp");
+ assert_transforms(tc, "ipv6-autoconf");
+ assert_transforms(tc, "ipv6-autoconf-dhcp");
+ assert_transforms(tc, "ipv6-static-multi");
+}
+
+static void testCorruptedSetup(CuTest *tc) {
+ int r;
+
+ ncf_close(ncf);
+ ncf = NULL;
+
+ r = ncf_init(&ncf, "/dev/null");
+ CuAssertIntEquals(tc, -1, r);
+ CuAssertPtrNotNull(tc, ncf);
+ r = ncf_error(ncf, NULL, NULL);
+ CuAssertIntEquals(tc, NETCF_EFILE, r);
+}
+
+int main(void) {
+ char *output = NULL;
+ CuSuite* suite = CuSuiteNew();
+
+ abs_top_srcdir = getenv("abs_top_srcdir");
+ if (abs_top_srcdir == NULL)
+ die("env var abs_top_srcdir must be set");
+
+ abs_top_builddir = getenv("abs_top_builddir");
+ if (abs_top_builddir == NULL)
+ die("env var abs_top_builddir must be set");
+
+ if (asprintf(&src_root, "%s/tests/root", abs_top_srcdir) < 0) {
+ die("failed to set src_root");
+ }
+
+ driver_name = strdup("redhat");
+ if (driver_name == NULL) {
+ die("failed to set driver name");
+ }
+
+ CuSuiteSetup(suite, setup, teardown);
+
+ SUITE_ADD_TEST(suite, testListInterfaces);
+ SUITE_ADD_TEST(suite, testLookupByName);
+ SUITE_ADD_TEST(suite, testLookupByNameDecoy);
+ SUITE_ADD_TEST(suite, testLookupByMAC);
+ SUITE_ADD_TEST(suite, testDefineUndefine);
+ SUITE_ADD_TEST(suite, testTransforms);
+ SUITE_ADD_TEST(suite, testCorruptedSetup);
+
+ CuSuiteRun(suite);
+ CuSuiteSummary(suite, &output);
+ CuSuiteDetails(suite, &output);
+ printf("%s\n", output);
+ free(output);
+ free(driver_name);
+ return suite->failCount;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
+/* vim: set ts=4 sw=4 et: */
--
1.7.6.2