Devel
  Threads by month 
                
            - ----- 2025 -----
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2024 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2023 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2022 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2021 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2020 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2019 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2018 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2017 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2016 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2015 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2014 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2013 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2012 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2011 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2010 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2009 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2008 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2007 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2006 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2005 -----
 - December
 
July 2012
- 99 participants
 - 305 discussions
 
                    
                        From: Ata E Husain Bohra <ata.husain(a)hotmail.com>
Add following routines to esx_interface_driver:
    esxNumOfInterfaces,
    esxNumOfDefinedInterfaces,
    esxListInterfaces,
    esxListDefinedInterfaces,
    esxInterfaceLookupByMACString,
    esxInterfaceGetXMLDesc,
    esxInterfaceUndefine,
    esxInterfaceCreate,
    esxInterfaceDestroy
Signed-off-by: Ata E Husain Bohra <ata.husain(a)hotmail.com>
---
 src/esx/esx_interface_driver.c |  506 +++++++++++++++++++++++++++++++++++++++-
 src/esx/esx_vi.c               |  126 ++++++++++
 src/esx/esx_vi.h               |   10 +
 src/esx/esx_vi_generator.input |  227 ++++++++++++++++++
 src/esx/esx_vi_generator.py    |   31 ++-
 src/esx/esx_vi_types.c         |   18 +-
 6 files changed, 913 insertions(+), 5 deletions(-)
diff --git a/src/esx/esx_interface_driver.c b/src/esx/esx_interface_driver.c
index 5713137..b1ba5e2 100644
--- a/src/esx/esx_interface_driver.c
+++ b/src/esx/esx_interface_driver.c
@@ -23,6 +23,9 @@
  */
 #include <config.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 #include "internal.h"
 #include "util.h"
@@ -34,6 +37,7 @@
 #include "esx_vi.h"
 #include "esx_vi_methods.h"
 #include "esx_util.h"
+#include "interface_conf.h"
 #define VIR_FROM_THIS VIR_FROM_ESX
@@ -67,10 +71,508 @@ esxInterfaceClose(virConnectPtr conn)
+static int
+esxNumOfInterfaces(virConnectPtr conn)
+{
+    esxPrivate *priv = conn->interfacePrivateData;
+    esxVI_HostVirtualNic *virtualNicList = NULL;
+    const esxVI_HostVirtualNic *virtualNic = NULL;
+    int count = 0;
+
+    if (esxVI_EnsureSession(priv->primary) < 0 ||
+        esxVI_LookupVirtualNicList(priv->primary, &virtualNicList) < 0) {
+        goto cleanup;
+    }
+
+    if (virtualNicList == NULL) {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Could not retrieve vNic List"));
+
+        goto cleanup;
+    }
+
+    for (virtualNic = virtualNicList;
+         virtualNic != NULL;
+         virtualNic = virtualNic->_next) {
+        count++;
+    }
+
+cleanup:
+
+    esxVI_HostVirtualNic_Free(&virtualNicList);
+
+    return count;
+}
+
+
+
+static int
+esxNumOfDefinedInterfaces(virConnectPtr conn)
+{
+    conn->interfacePrivateData = NULL;
+
+    // ESX interfaces are always active
+    return 0;
+}
+
+
+
+static int
+esxListInterfaces(virConnectPtr conn, char **names, int maxnames)
+{
+    esxPrivate *priv = conn->interfacePrivateData;
+    esxVI_HostVirtualNic *virtualNicList = NULL;
+    const esxVI_HostVirtualNic *virtualNic = NULL;
+    int result = -1;
+    int i = 0;
+
+    if (esxVI_EnsureSession(priv->primary) < 0 ||
+        esxVI_LookupVirtualNicList(priv->primary,
+                                   &virtualNicList) < 0) {
+        goto cleanup;
+    }
+
+    if (virtualNicList == NULL) {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Could not retrieve vNIC List"));
+        goto cleanup;
+    }
+
+    for (i= 0, virtualNic = virtualNicList;
+         virtualNic != NULL && i < maxnames;
+         ++i, virtualNic = virtualNic->_next) {
+        names[i] = strdup(virtualNic->device);
+
+        if (names[i] == NULL) {
+            for(;i >=0;--i) {
+                VIR_FREE(names[i]);
+            }
+            virReportOOMError();
+            goto cleanup;
+        }
+    }
+
+    result = i;
+ cleanup:
+    esxVI_HostVirtualNic_Free(&virtualNicList);
+
+    return result;
+}
+
+
+
+static int
+esxListDefinedInterfaces(virConnectPtr conn, char **names, int maxnames)
+{
+    conn->interfacePrivateData = conn->privateData;
+    *names = NULL;
+
+    /* keeps compiler happy */
+    VIR_DEBUG("max interfaces: %d", maxnames);
+
+    // ESX interfaces are always active
+    return 0;
+}
+
+
+
+static virInterfacePtr
+esxInterfaceLookupByName(virConnectPtr conn, const char *name)
+{
+    esxPrivate *priv = conn->interfacePrivateData;
+    esxVI_HostVirtualNic *virtualNicList = NULL;
+    const esxVI_HostVirtualNic *virtualNic = NULL;
+    virInterfacePtr ret = NULL;
+
+    if (esxVI_EnsureSession(priv->primary) < 0 ||
+        esxVI_LookupVirtualNicList(priv->primary,
+                                   &virtualNicList) < 0) {
+        goto cleanup;
+    }
+
+    if (virtualNicList == 0) {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Could not retrieve vNIC List"));
+        goto cleanup;
+    }
+
+
+    for(virtualNic = virtualNicList;
+        virtualNic != NULL;
+        virtualNic = virtualNic->_next) {
+        if (STREQ(virtualNic->device, name)) {
+            if (virtualNic->spec == NULL ||
+                virtualNic->spec->mac == NULL) {
+                ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("Malformed HostVirtualNicSpec"));
+                goto cleanup;
+            }
+
+            ret = virGetInterface(conn, virtualNic->device, virtualNic->spec->mac);
+            break;
+        }
+    }
+
+ cleanup:
+    esxVI_HostVirtualNic_Free(&virtualNicList);
+
+    return ret;
+}
+
+
+
+static virInterfacePtr
+esxInterfaceLookupByMACString(virConnectPtr conn, const char *mac)
+{
+    esxPrivate *priv = conn->interfacePrivateData;
+    esxVI_HostVirtualNic *virtualNicList = NULL;
+    const esxVI_HostVirtualNic *virtualNic = NULL;
+    virInterfacePtr ret = NULL;
+
+    if (esxVI_EnsureSession(priv->primary) < 0 ||
+        esxVI_LookupVirtualNicList(priv->primary,
+                                   &virtualNicList) < 0) {
+        goto cleanup;
+    }
+
+    if (virtualNicList == 0) {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Could not retrieve vNIC List"));
+        goto cleanup;
+    }
+
+
+    for(virtualNic = virtualNicList;
+        virtualNic != NULL;
+        virtualNic = virtualNic->_next) {
+        if (virtualNic->spec == NULL ||
+            virtualNic->spec->mac == NULL) {
+            ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+              _("Malformed HostVirtualNicSpec"));
+            goto cleanup;
+        }
+
+        if (STREQ(virtualNic->spec->mac, mac)) {
+            ret = virGetInterface(conn, virtualNic->device, virtualNic->spec->mac);
+            break;
+        }
+    }
+
+ cleanup:
+    esxVI_HostVirtualNic_Free(&virtualNicList);
+
+    return ret;
+}
+
+
+
+static char*
+esxInterfaceGetXMLDesc(virInterfacePtr iface, unsigned int flags)
+{
+    esxPrivate *priv = iface->conn->interfacePrivateData;
+    esxVI_HostVirtualNic *virtualNicList = NULL;
+    const esxVI_HostVirtualNic *virtualNic = NULL;
+    esxVI_PhysicalNic *physicalNicList = NULL;
+    const esxVI_PhysicalNic *physicalNic = NULL;
+    esxVI_PhysicalNic *matchingPhysicalNicList = NULL;
+    esxVI_HostIpRouteConfig *ipRouteConfig = NULL;
+    esxVI_HostPortGroup *portGroupList = NULL;
+    esxVI_HostVirtualSwitch *virtualSwitchList = NULL;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *hostSystem = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    virInterfaceDefPtr def = NULL;
+    int use_static = 0;
+    struct in_addr addr;
+    uint32_t host_addr = 0;
+    int zero_count = 0;
+    int masklen = 0;
+    int i = 0;
+    char *ret = NULL;
+
+    if (VIR_INTERFACE_XML_INACTIVE & flags) {
+        use_static = 1;
+    }
+
+    if (esxVI_EnsureSession(priv->primary) < 0 ||
+        esxVI_String_AppendValueListToList(&propertyNameList,
+                              "config.network.vnic\0"
+                              "config.network.ipRouteConfig\0"
+                              "config.network.vswitch\0"
+                              "config.network.pnic\0"
+                              "config.network.portgroup\0") < 0 ||
+        esxVI_LookupHostSystemProperties(priv->primary, propertyNameList,
+                                         &hostSystem) < 0) {
+        goto cleanup;
+    }
+
+    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, "config.network.vnic")) {
+            if (esxVI_HostVirtualNic_CastListFromAnyType(
+                  dynamicProperty->val, &virtualNicList) < 0) {
+                goto cleanup;
+            }
+        } else if (STREQ(dynamicProperty->name,
+              "config.network.ipRouteConfig")) {
+            if (esxVI_HostIpRouteConfig_CastFromAnyType(
+                  dynamicProperty->val, &ipRouteConfig)) {
+                goto cleanup;
+            }
+        } else if (STREQ(dynamicProperty->name, "config.network.vswitch")) {
+            if (esxVI_HostVirtualSwitch_CastListFromAnyType
+              (dynamicProperty->val, &virtualSwitchList) < 0) {
+                goto cleanup;
+            }
+        } else if (STREQ(dynamicProperty->name, "config.network.pnic")) {
+            if (esxVI_PhysicalNic_CastListFromAnyType(
+                  dynamicProperty->val, &physicalNicList) < 0) {
+                goto cleanup;
+            }
+        } else if (STREQ(dynamicProperty->name, "config.network.portgroup")) {
+            if (esxVI_HostPortGroup_CastListFromAnyType(
+                  dynamicProperty->val, &portGroupList) < 0) {
+                goto cleanup;
+            }
+        } else {
+            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+        }
+    }
+
+    if (!virtualNicList ||
+        !ipRouteConfig ||
+        !virtualSwitchList ||
+        !portGroupList) {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("Unable to retrieve network parameters"));
+
+        goto cleanup;
+    }
+
+    for (virtualNic = virtualNicList;
+         virtualNic != NULL;
+         virtualNic = virtualNic->_next) {
+        if (STREQ(virtualNic->device, iface->name)) {
+            break;
+        }
+    }
+
+    if (virtualNic == NULL) {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("Could not find Interface"));
+        goto cleanup;
+    }
+
+    if (esxVI_LookupPhysicalNicFromPortGroup(virtualNic->portgroup,
+                                             portGroupList,
+                                             virtualSwitchList,
+                                             physicalNicList,
+                                             &matchingPhysicalNicList) < 0) {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("No Physical NIC found matching Virtual NIC's portgroup"));
+        goto cleanup;
+    }
+
+    /*
+     * populate virInterfaceDef object to obtain
+     * libvirt interface domain xml.
+     */
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    def->type = VIR_INTERFACE_TYPE_BRIDGE;
+    def->name = strdup(virtualNic->device);
+    if (virtualNic->spec->mtu && virtualNic->spec->mtu->value) {
+        def->mtu = virtualNic->spec->mtu->value;
+    } else {
+        def->mtu = 1500;
+    }
+
+    def->startmode = VIR_INTERFACE_START_ONBOOT;
+
+    if (!use_static && virtualNic->spec->mac) {
+        def->mac = strdup(virtualNic->spec->mac);
+    }
+
+    /* TODO - Handle VLAN (via portgroup?) */
+    if (virtualNic->spec->ip->subnetMask &&
+        *virtualNic->spec->ip->subnetMask &&
+        inet_aton(virtualNic->spec->ip->subnetMask, &addr) == 0) {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("Error parsing netmask"));
+        goto cleanup;
+    }
+
+    host_addr = ntohl(addr.s_addr);
+    /* Calculate masklen */
+    for (i = 0; i < 32; ++i) {
+        if (host_addr & 0x01) {
+             break;
+        }
+        zero_count++;
+        host_addr >>= 1;
+    }
+    masklen = 32 - zero_count;
+
+    /* append protocol field */
+    def->nprotos = 1;
+    if (VIR_ALLOC_N(def->protos, def->nprotos) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    /* TODO - Add IPv6 Support */
+    for (i = 0; i < def->nprotos; ++i) {
+        if (VIR_ALLOC(def->protos[i]) < 0) {
+            goto cleanup;
+        }
+
+        def->protos[i]->family = strdup("ipv4");
+        if (virtualNic->spec->ip->dhcp == 1) {
+            def->protos[i]->dhcp = 1;
+        }
+        def->protos[i]->nips = 1;
+        if (virtualNic->spec->ip->dhcp != 1 || !use_static) {
+            if (virtualNic->spec->ip->ipAddress &&
+              *virtualNic->spec->ip->ipAddress) {
+                int j =0;
+                if (VIR_ALLOC_N(def->protos[i]->ips, def->protos[i]->nips)
+                  < 0) {
+                    virReportOOMError();
+                    goto cleanup;
+                }
+
+                for (j=0; j < def->protos[i]->nips; ++j) {
+                    if (VIR_ALLOC(def->protos[i]->ips[j]) < 0) {
+                        virReportOOMError();
+                        goto cleanup;
+                    }
+                    def->protos[i]->ips[0]->address =
+                        strdup(virtualNic->spec->ip->ipAddress);
+                    def->protos[i]->ips[0]->prefix = masklen;
+                    def->protos[i]->gateway =
+                        strdup(ipRouteConfig->defaultGateway);
+                }
+            }
+        }
+    }
+
+    /* Add bridge information */
+    def->data.bridge.stp = 0; /* off */
+
+    /**
+     * traversing physical nic list twice, first to get total
+     * interfaces and second to populate interface items.
+     * Total Complexity ~= O(N); also total physical nics
+     * cannot be that large number
+     */
+    for (physicalNic = matchingPhysicalNicList, i = 0; physicalNic != NULL;
+         physicalNic = physicalNic->_next, ++i) {
+    }
+
+    if ( i > 0) {
+        if (VIR_ALLOC_N(def->data.bridge.itf, i) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+        def->data.bridge.nbItf = i;
+        for (physicalNic = matchingPhysicalNicList, i = 0; physicalNic != NULL;
+             physicalNic = physicalNic->_next, ++i) {
+            virInterfaceDefPtr itf = NULL;
+            if (VIR_ALLOC(itf) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
+            itf->type = VIR_INTERFACE_TYPE_ETHERNET;
+            itf->name = strdup(physicalNic->device);
+            itf->mac = strdup(physicalNic->mac);
+
+            def->data.bridge.itf[i] = itf;
+        }
+    }
+
+    ret = virInterfaceDefFormat(def);
+    if (!ret) {
+        goto cleanup;
+    }
+
+ cleanup:
+    esxVI_HostVirtualNic_Free(&virtualNicList);
+    esxVI_PhysicalNic_Free(&physicalNicList);
+    esxVI_PhysicalNic_Free(&matchingPhysicalNicList);
+    esxVI_HostPortGroup_Free(&portGroupList);
+    esxVI_HostVirtualSwitch_Free(&virtualSwitchList);
+    esxVI_HostIpRouteConfig_Free(&ipRouteConfig);
+    esxVI_ObjectContent_Free(&hostSystem);
+    esxVI_String_Free(&propertyNameList);
+    virInterfaceDefFree(def);
+
+    return ret;
+}
+
+
+
+static int
+esxInterfaceUndefine(virInterfacePtr iface)
+{
+    esxPrivate *priv = iface->conn->interfacePrivateData;
+
+    if (esxVI_RemoveVirtualNic(
+          priv->primary,
+          priv->primary->hostSystem->configManager->networkSystem,
+          iface->name) < 0) {
+        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+          _("Error deleting interface"));
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+static int
+esxInterfaceCreate(virInterfacePtr iface, unsigned int flags)
+{
+    iface->conn->interfacePrivateData = NULL;
+
+    virCheckFlags(0, -1);
+
+    /* ESX interfaces are always active */
+    return 0;
+}
+
+
+
+static int
+esxInterfaceDestroy(virInterfacePtr iface, unsigned int flags)
+{
+    iface->conn->interfacePrivateData = NULL;
+
+    virCheckFlags(0, -1);
+
+    /* ESX interfaces can not be deactivated */
+    return 1;
+}
+
+
+
 static virInterfaceDriver esxInterfaceDriver = {
     .name = "ESX",
-    .open = esxInterfaceOpen, /* 0.7.6 */
-    .close = esxInterfaceClose, /* 0.7.6 */
+    .open = esxInterfaceOpen,                   /* 0.7.6 */
+    .close = esxInterfaceClose,                 /* 0.7.6 */
+    .numOfInterfaces = esxNumOfInterfaces,      /* 0.9.x */
+    .numOfDefinedInterfaces = esxNumOfDefinedInterfaces, /* 0.9.x */
+    .listInterfaces = esxListInterfaces,        /* 0.9.x */
+    .listDefinedInterfaces = esxListDefinedInterfaces, /* 0.9.x */
+    .interfaceLookupByName = esxInterfaceLookupByName, /* 0.9.x */
+    .interfaceLookupByMACString = esxInterfaceLookupByMACString, /* 0.9.x */
+    .interfaceGetXMLDesc = esxInterfaceGetXMLDesc, /* 0.9.x */
+    .interfaceUndefine = esxInterfaceUndefine, /* 0.9.x */
+    .interfaceCreate = esxInterfaceCreate, /* 0.9.x */
+    .interfaceDestroy = esxInterfaceDestroy, /* 0.9.x */
 };
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index 48718b6..80ddb76 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -4523,6 +4523,132 @@ esxVI_LookupManagedObjectHelper(esxVI_Context *ctx,
     return result;
 }
+int
+esxVI_LookupVirtualNicList(esxVI_Context* ctx,
+                           esxVI_HostVirtualNic** virtualNicList)
+{
+    int result = -1;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_ObjectContent* hostSystem = NULL;
+
+    if (esxVI_String_AppendValueListToList(
+          &propertyNameList, "config.network.vnic\0") < 0 ||
+        esxVI_LookupHostSystemProperties(ctx, propertyNameList, &hostSystem) < 0) {
+        goto cleanup;
+    }
+    if (hostSystem == NULL) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Could not retrieve the HostSystem object"));
+
+        goto cleanup;
+    }
+
+    for (dynamicProperty = hostSystem->propSet;
+         dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, "config.network.vnic")) {
+            if (esxVI_HostVirtualNic_CastListFromAnyType(dynamicProperty->val,
+                                                         virtualNicList) < 0) {
+                goto cleanup;
+            }
+            break;
+        } else {
+            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+        }
+    }
+
+    result = 0;
+
+cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&hostSystem);
+
+    return result;
+}
+
+int
+esxVI_LookupPhysicalNicFromPortGroup(
+    const char *portgroup,
+    const esxVI_HostPortGroup *portGroupList,
+    const esxVI_HostVirtualSwitch *virtualSwitchList,
+    const esxVI_PhysicalNic *physicalNicList,
+    esxVI_PhysicalNic **ret_physicalNicList)
+{
+    int result = -1;
+    const esxVI_HostPortGroup *portGroup = NULL;
+    const esxVI_HostVirtualSwitch *virtualSwitch = NULL;
+    esxVI_PhysicalNic *matchingPhysicalNicList = NULL;
+    const esxVI_PhysicalNic *physicalNic = NULL;
+    esxVI_PhysicalNic *tempPhysicalNic = NULL;
+    const esxVI_String *pnicKey = NULL;
+
+    if (portgroup == NULL) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("No Portgroup found!"));
+        goto cleanup;
+    }
+
+    /* Go through all the port groups to find the one that matches. */
+    for (portGroup = portGroupList;
+         portGroup != NULL;
+         portGroup = portGroup->_next) {
+        if (STREQ(portGroup->spec->name, portgroup)) {
+            break;
+        }
+    }
+
+    if (portGroup == NULL) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("Could not find Host port group"));
+        goto cleanup;
+    }
+
+    /* Go through all the virtual switches to find the one that matches */
+    for (virtualSwitch = virtualSwitchList;
+         virtualSwitch != NULL;
+         virtualSwitch = virtualSwitch->_next) {
+        if (STREQ(portGroup->spec->vswitchName, virtualSwitch->name)) {
+            break;
+        }
+    }
+
+    if (virtualSwitch == NULL) {
+        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
+                  _("Could not find Virtual Switch"));
+        goto cleanup;
+    }
+
+    /* Go through all physical nics */
+    for (pnicKey = virtualSwitch->pnic;
+         pnicKey != NULL;
+         pnicKey = pnicKey->_next) {
+        /* O(n^2), but probably faster than a hash due to small N */
+        for (physicalNic = physicalNicList;
+             physicalNic != NULL;
+             physicalNic = physicalNic->_next) {
+
+            if (STREQ(pnicKey->value, physicalNic->key)) {
+                if (esxVI_PhysicalNic_DeepCopy(&tempPhysicalNic,
+                                  (esxVI_PhysicalNic *)physicalNic) < 0 ||
+                    esxVI_PhysicalNic_AppendToList(&matchingPhysicalNicList,
+                                                   tempPhysicalNic) < 0) {
+                    goto cleanup;
+                }
+                tempPhysicalNic = NULL;
+            }
+        }
+    }
+
+   *ret_physicalNicList = matchingPhysicalNicList;
+    matchingPhysicalNicList = NULL; /* no cleanup needed */
+    tempPhysicalNic = NULL; /* no cleanup needed */
+    result = 0;
+ cleanup:
+    esxVI_PhysicalNic_Free(&matchingPhysicalNicList);
+    esxVI_PhysicalNic_Free(&tempPhysicalNic);
+    return result;
+}
 #include "esx_vi.generated.c"
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index 9560bd2..9b694b5 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -505,6 +505,16 @@ int esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo *parsedHostCpuIdInfo,
 int esxVI_ProductVersionToDefaultVirtualHWVersion(esxVI_ProductVersion productVersion);
+int esxVI_LookupVirtualNicList(esxVI_Context* ctx,
+                               esxVI_HostVirtualNic** virtualNicList);
+
+int esxVI_LookupPhysicalNicFromPortGroup(
+        const char *portgroup,
+        const esxVI_HostPortGroup *portGroupList,
+        const esxVI_HostVirtualSwitch *virtualSwitchList,
+        const esxVI_PhysicalNic *physicalNicList,
+        esxVI_PhysicalNic **ret_physicalNicList);
+
 # include "esx_vi.generated.h"
 #endif /* __ESX_VI_H__ */
diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input
index 1a67a8c..64f8389 100644
--- a/src/esx/esx_vi_generator.input
+++ b/src/esx/esx_vi_generator.input
@@ -57,6 +57,29 @@ enum AutoStartWaitHeartbeatSetting
     systemDefault
 end
+enum HostConfigChangeOperation
+    add
+    edit
+    remove
+end
+
+enum HostIpConfigIpV6AdressStatus
+    deprecated
+    duplicate
+    inaccessible
+    invalid
+    preferred
+    tentative
+    unknown
+end
+
+enum HostIpConfigV6AdressConfigType
+    dhcp
+    linklayer
+    manual
+    other
+    random
+end
 enum ManagedEntityStatus
     gray
@@ -197,6 +220,12 @@ object DeviceBackedVirtualDiskSpec   extends VirtualDiskSpec
     String                                   device                         r
 end
+object DistributedVirtualSwitchPortConnection
+    Int                                      connectionCookie               o
+    String                                   portgroupKey                   o
+    String                                   portKey                        o
+    String                                   switchUuid                     r
+end
 object DynamicProperty
     String                                   name                           r
@@ -316,6 +345,34 @@ object HostFileSystemVolume
     Long                                     capacity                       r
 end
+object HostIpConfig
+    Boolean                                  dhcp                           r
+    String                                   ipAddress                      o
+    HostIpConfigIpV6AddressConfiguration     ipV6Config                     o
+    String                                   subnetMask                     o
+end
+
+object HostIpConfigIpV6Address
+    String                                   dadState                       o
+    String                                   ipAddress                      r
+    DateTime                                 lifetime                       o
+    String                                   operation                      o
+    String                                   origin                         o
+    Int                                      prefixLength                   r
+end
+
+object HostIpConfigIpV6AddressConfiguration
+    Boolean                                  autoConfigurationEnabled       o
+    Boolean                                  dhcpV6Enabled                  o
+    HostIpConfigIpV6Address                  ipV6Address                    ol
+end
+
+object HostIpRouteConfig
+    String                                   defaultGateway                 o
+    String                                   gatewayDevice                  o
+    String                                   ipV6DefaultGateway             o
+    String                                   ipV6GatewayDevice              o
+end
 object HostMountInfo
     String                                   path                           o
@@ -331,11 +388,131 @@ object HostNasVolume                 extends HostFileSystemVolume
 end
+object HostNicTeamingPolicy
+    String                                   policy                         o
+    Boolean                                  reversePolicy                  o
+    Boolean                                  notifySwitches                 o
+    Boolean                                  rollingOrder                   o
+    HostNicFailureCriteria                   failureCriteria                o
+    HostNicOrderPolicy                       nicOrder                       o
+end
+
+object HostNetOffloadCapabilities
+    Boolean                                  csumOffload                    o
+    Boolean                                  tcpSegmentation                o
+    Boolean                                  zeroCopyXmit                   o
+end
+
+object HostNetworkSecurityPolicy
+    Boolean                                  allowPromiscuous               o
+    Boolean                                  macChanges                     o
+    Boolean                                  forgedTransmits                o
+end
+
+object HostNetworkPolicy
+    HostNetworkSecurityPolicy                security                       o
+    HostNicTeamingPolicy                     nicTeaming                     o
+    HostNetOffloadCapabilities               offloadPolicy                  o
+    HostNetworkTrafficShapingPolicy          shapingPolicy                  o
+end
+
+object HostNetworkTrafficShapingPolicy
+    Boolean                                  enabled                        o
+end
+
+object HostNicFailureCriteria
+    String                                   checkSpeed                     o
+    Int                                      speed                          o
+    Boolean                                  checkDuplex                    o
+    Boolean                                  fullDuplex                     o
+    Boolean                                  checkErrorPercent              o
+    Int                                      percentage                     o
+    Boolean                                  checkBeacon                    o
+end
+
+object HostNicOrderPolicy
+    String                                   activeNic                     ol
+    String                                   standbyNic                    ol
+end
+
+object HostPortGroup
+    String                                   key                            r
+    HostPortGroupPort                        port                           ol
+    String                                   vswitch                        r
+    HostNetworkPolicy                        computedPolicy                 r
+    HostPortGroupSpec                        spec                           r
+end
+
+object HostPortGroupPort
+    String                                   key                            o
+    String                                   mac                            ol
+    String                                   type                           r
+end
+
+object HostPortGroupSpec
+    String                                   name                           r
+    Int                                      vlanId                         r
+    String                                   vswitchName                    r
+    HostNetworkPolicy                        policy                         r
+end
+
 object HostScsiDiskPartition
     String                                   diskName                       r
     Int                                      partition                      r
 end
+object HostVirtualNic
+    String                                   device                         r
+    String                                   key                            r
+    String                                   port                           o
+    String                                   portgroup                      r
+    HostVirtualNicSpec                       spec                           r
+end
+
+object HostVirtualNicSpec
+   DistributedVirtualSwitchPortConnection    distributedVirtualPort         o
+   HostIpConfig                              ip                             o
+   String                                    mac                            o
+   Int                                       mtu                            o
+   String                                    portgroup                      o
+   Boolean                                   tsoEnabled                     o
+end
+
+
+object HostVirtualSwitch
+   String                                    key                            r
+   Int                                       mtu                            o
+   String                                    name                           r
+   Int                                       numPorts                       r
+   Int                                       numPortsAvailable              r
+   String                                    pnic                           ol
+   String                                    portgroup                      ol
+   HostVirtualSwitchSpec                     spec                           r
+end
+
+object HostVirtualSwitchBridge
+end
+
+object HostVirtualSwitchAutoBridge extends HostVirtualSwitchBridge
+   String                                    excludedNicDevice              ol
+end
+
+object HostVirtualSwitchBeaconBridge extends HostVirtualSwitchBridge
+   Int                                       interval                       r
+end
+
+object HostVirtualSwitchBondBridge extends HostVirtualSwitchBridge
+   HostVirtualSwitchBeaconBridge             beacon                         o
+   LinkDiscoveryProtocolConfig               linkDiscoveryProtocolConfig    o
+   String                                    nicDevice                      rl
+end
+
+object HostVirtualSwitchSpec
+  HostVirtualSwitchBridge                    bridge                         o
+  Int                                        mtu                            o
+  Int                                        numPorts                       r
+  HostNetworkPolicy                          policy                         o
+end
 object HostVmfsVolume                extends HostFileSystemVolume
     Int                                      blockSizeMb                    r
@@ -355,6 +532,10 @@ end
 object IsoImageFileQuery             extends FileQuery
 end
+object LinkDiscoveryProtocolConfig
+    String                                    operation                     r
+    String                                    protocol                      r
+end
 object LocalDatastoreInfo            extends DatastoreInfo
     String                                   path                           o
@@ -398,6 +579,10 @@ object OptionType
     Boolean                                  valueIsReadonly                o
 end
+object OptionValue
+    String                                   key                            r
+    AnyType                                  value                          r
+end
 object PerfCounterInfo
     Int                                      key                            r
@@ -454,6 +639,27 @@ object PerfSampleInfo
     Int                                      interval                       r
 end
+object PhysicalNic
+    String                                   device                         r
+    String                                   driver                         o
+    String                                   key                            o
+    PhysicalNicInfo                          linkSpeed                      o
+    String                                   mac                            r
+    String                                   pci                            r
+    PhysicalNicSpec                          spec                           r
+    PhysicalNicInfo                          validLinkSpecification         ol
+    Boolean                                  wakeOnLanSupported             r
+end
+
+object PhysicalNicInfo
+   Boolean                                   duplex                         r
+   Int                                       speedMb                        r
+end
+
+object PhysicalNicSpec
+    HostIpConfig                             ip                             o
+    PhysicalNicInfo                          linkSpeed                      o
+end
 object PropertyChange
     String                                   name                           r
@@ -773,6 +979,13 @@ end
 # Methods
 #
+method AddVirtualNic                 returns String                         r
+    ManagedObjectReference                   _this                          r
+    String                                   portgroup                      r
+    HostVirtualNicSpec                       nic                            r
+end
+
+
 method AnswerVM
     ManagedObjectReference                   _this                          r
     String                                   questionId                     r
@@ -954,6 +1167,10 @@ method RemoveSnapshot_Task           returns ManagedObjectReference         r
     Boolean                                  removeChildren                 r
 end
+method RemoveVirtualNic
+   ManagedObjectReference                    _this                          r
+   String                                    device                         r
+end
 method RetrieveProperties            returns ObjectContent                  ol
     ManagedObjectReference                   _this:propertyCollector        r
@@ -1002,6 +1219,16 @@ method UnregisterVM
     ManagedObjectReference                   _this                          r
 end
+method UpdateIpRouteConfig
+    ManagedObjectReference                   _this                          r
+    HostIpRouteConfig                        config                         r
+end
+
+method UpdateVirtualNic
+    ManagedObjectReference                   _this                          r
+    String                                   device                         r
+    HostVirtualNicSpec                       nic                            r
+end
 method WaitForUpdates                returns UpdateSet                      r
     ManagedObjectReference                   _this:propertyCollector        r
diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py
index 8a128df..f4e4a11 100755
--- a/src/esx/esx_vi_generator.py
+++ b/src/esx/esx_vi_generator.py
@@ -371,8 +371,12 @@ class Property(Member):
                    % self.name
         elif self.occurrence in [OCCURRENCE__REQUIRED_LIST,
                                  OCCURRENCE__OPTIONAL_LIST]:
-            return "    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(%s, %s)\n" \
-                   % (self.type, self.name)
+            if self.type == "String":
+                return "    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_STRING_LIST(%s, %s)\n" \
+                        % (self.type, self.name)
+            else:
+                return "    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(%s, %s)\n" \
+                        % (self.type, self.name)
         elif self.type == "String":
             return "    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, %s)\n" \
                    % self.name
@@ -1519,8 +1523,31 @@ additional_object_features = { "AutoStartDefaults"          : Object.FEATURE__AN
                                                               Object.FEATURE__ANY_TYPE,
                                "HostDatastoreBrowserSearchResults" : Object.FEATURE__LIST |
                                                               Object.FEATURE__ANY_TYPE,
+                               "HostIpConfig"               : Object.FEATURE__DEEP_COPY,
+                               "HostIpRouteConfig"          : Object.FEATURE__ANY_TYPE,
+                               "HostIpConfigIpV6Address"    : Object.FEATURE__LIST |
+                                                              Object.FEATURE__ANY_TYPE |
+                                                              Object.FEATURE__DEEP_COPY,
+                               "HostIpConfigIpV6AddressConfiguration"  : Object.FEATURE__DEEP_COPY,
+                               "HostPortGroup"              : Object.FEATURE__LIST |
+                                                              Object.FEATURE__ANY_TYPE,
+                               "HostVirtualNic"             : Object.FEATURE__ANY_TYPE |
+                                                              Object.FEATURE__LIST,
+                               "HostVirtualSwitch"          : Object.FEATURE__ANY_TYPE |
+                                                              Object.FEATURE__LIST,
+                               "KeyValue"                   : Object.FEATURE__ANY_TYPE,
                                "ManagedObjectReference"     : Object.FEATURE__ANY_TYPE,
+                               "PhysicalNic"                : Object.FEATURE__LIST |
+                                                              Object.FEATURE__ANY_TYPE |
+                                                              Object.FEATURE__DEEP_COPY,
                                "ObjectContent"              : Object.FEATURE__DEEP_COPY,
+                               "OptionValue"                : Object.FEATURE__ANY_TYPE |
+                                                              Object.FEATURE__LIST,
+                               "PhysicalNic"                : Object.FEATURE__LIST |
+                                                              Object.FEATURE__ANY_TYPE |
+                                                              Object.FEATURE__DEEP_COPY,
+                               "PhysicalNicSpec"            : Object.FEATURE__DEEP_COPY,
+                               "PhysicalNicLinkInfo"        : Object.FEATURE__LIST,
                                "ResourcePoolResourceUsage"  : Object.FEATURE__ANY_TYPE,
                                "ServiceContent"             : Object.FEATURE__DESERIALIZE,
                                "SharesInfo"                 : Object.FEATURE__ANY_TYPE,
diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c
index bcc310f..f23af8d 100644
--- a/src/esx/esx_vi_types.c
+++ b/src/esx/esx_vi_types.c
@@ -475,7 +475,23 @@
         continue;                                                             \
     }
-
+#define ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_STRING_LIST(_type, _name)     \
+    if (xmlStrEqual(childNode->name, BAD_CAST #_name)) {                      \
+        char *value = NULL;                                                   \
+                                                                              \
+        if (esxVI_String_DeserializeValue(childNode, &value) < 0 ||           \
+            value == NULL) {                                                  \
+            goto failure;                                                     \
+        }                                                                     \
+                                                                              \
+        if (esxVI_##_type##_AppendValueToList(&(*ptrptr)->_name,              \
+                                                value) < 0) {                 \
+            VIR_FREE(value);                                                  \
+            goto failure;                                                     \
+        }                                                                     \
+                                                                              \
+        continue;                                                             \
+    }
 /*
  * A required property must be != 0 (NULL for pointers, "undefined" == 0 for
--
1.7.9.5
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        
Following section indicates that CPU tuning with <period> and <quota>
tags are only supported for QEMU
	http://libvirt.org/formatdomain.html#elementsCPUTuning
I see this commit in libvirt.git:
        commit d9724a81b3c53a40f45bf76067a976cce73ed278
        Author: Daniel P. Berrange <berrange(a)redhat.com>
        Date:   Thu Nov 10 12:16:26 2011 +0000
            Add support for CPU quota/period to LXC driver
and the code seems to be included in libvirt-0.9.10-21.el6.
I have not had a chance to try on latest libvirt yet, but is it just
that the CPUTuning section on the above wiki needs an update ? 
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                    11 Jul '12
                    
                        libvirt's sVirt security driver provides SELinux MAC isolation for
Qemu guest processes and their corresponding image files.  In other
words, sVirt uses SELinux to prevent a QEMU process from opening
files that do not belong to it.
sVirt provides this support by labeling guests and resources with
security labels that are stored in file system extended attributes.
Some file systems, such as NFS, do not support the extended
attribute security namespace, and therefore cannot support sVirt
isolation.
A solution to this problem is to provide fd passing support, where
libvirt opens files and passes file descriptors to QEMU.  This,
along with SELinux policy to prevent QEMU from opening files, can
provide image file isolation for NFS files stored on the same NFS
mount.
This patch series adds the pass-fd QMP monitor command, which allows
an fd to be passed via SCM_RIGHTS, and returns the received file
descriptor.  Support is also added to the block layer to allow QEMU
to dup the fd when the filename is of the /dev/fd/X format.  This
is useful if MAC policy prevents QEMU from opening specific types
of files.
One nice thing about this approach is that no new SELinux policy is
required to prevent open of NFS files (files with type nfs_t).  The
virt_use_nfs boolean type simply needs to be set to false, and open
will be prevented (and dup will be allowed).  For example:
    # setsebool virt_use_nfs 0
    # getsebool virt_use_nfs
    virt_use_nfs --> off
Corey Bryant (7):
  qemu-char: Add MSG_CMSG_CLOEXEC flag to recvmsg
  qapi: Convert getfd and closefd
  qapi: Add pass-fd QMP command
  qapi: Re-arrange monitor.c functions
  block: Prevent /dev/fd/X filename from being detected as floppy
  block: Convert open calls to qemu_open
  osdep: Enable qemu_open to dup pre-opened fd
 block/raw-posix.c |   22 +++++-----
 block/raw-win32.c |    4 +-
 block/vdi.c       |    5 ++-
 block/vmdk.c      |   21 ++++------
 block/vpc.c       |    2 +-
 block/vvfat.c     |   21 +++++-----
 cutils.c          |   26 +++++++++---
 dump.c            |    3 +-
 hmp-commands.hx   |    6 +--
 hmp.c             |   18 ++++++++
 hmp.h             |    2 +
 main-loop.c       |    6 +--
 migration-fd.c    |    2 +-
 monitor.c         |  120 ++++++++++++++++++++++++++++++++---------------------
 monitor.h         |    2 +-
 net.c             |    6 ++-
 osdep.c           |   91 ++++++++++++++++++++++++++++++++++++++++
 qapi-schema.json  |   71 +++++++++++++++++++++++++++++++
 qemu-char.c       |    2 +-
 qemu-common.h     |    2 +-
 qmp-commands.hx   |   56 ++++++++++++++++++++++---
 21 files changed, 378 insertions(+), 110 deletions(-)
-- 
1.7.10.2
                    
                  
                  
                          
                            
                            7
                            
                          
                          
                            
                            95
                            
                          
                          
                            
    
                          
                        
                    11 Jul '12
                    
                        From: "Daniel P. Berrange" <berrange(a)redhat.com>
When calling 'lvcreate' if specifying both the '-L' and
'--virtualsize' options, the latter will be treated as
the capacity and the former as the allocation. This can
be used to support sparse volume creation. In addition,
when listing volumes it is neccessary to include the 'size'
field in lvs output, so that we can detect sparse volume
allocation correctly.
---
 src/storage/storage_backend_logical.c |   27 ++++++++++++++++++---------
 1 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/src/storage/storage_backend_logical.c b/src/storage/storage_backend_logical.c
index 9fe769b..c6e09e6 100644
--- a/src/storage/storage_backend_logical.c
+++ b/src/storage/storage_backend_logical.c
@@ -171,6 +171,11 @@ virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool,
                               "%s", _("malformed volume extent size value"));
         goto cleanup;
     }
+    if (virStrToLong_ull(groups[8], NULL, 10, &vol->allocation) < 0) {
+        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+                              "%s", _("malformed volume allocation value"));
+        goto cleanup;
+    }
 
     /* Now parse the "devices" field separately */
     regex = strdup(regex_unit);
@@ -271,12 +276,12 @@ virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
                                 virStorageVolDefPtr vol)
 {
     /*
-     *  # lvs --separator , --noheadings --units b --unbuffered --nosuffix --options "lv_name,origin,uuid,devices,seg_size,vg_extent_size" VGNAME
-     *  RootLV,,06UgP5-2rhb-w3Bo-3mdR-WeoL-pytO-SAa2ky,/dev/hda2(0),5234491392,33554432
-     *  SwapLV,,oHviCK-8Ik0-paqS-V20c-nkhY-Bm1e-zgzU0M,/dev/hda2(156),1040187392,33554432
-     *  Test2,,3pg3he-mQsA-5Sui-h0i6-HNmc-Cz7W-QSndcR,/dev/hda2(219),1073741824,33554432
-     *  Test3,,UB5hFw-kmlm-LSoX-EI1t-ioVd-h7GL-M0W8Ht,/dev/hda2(251),2181038080,33554432
-     *  Test3,Test2,UB5hFw-kmlm-LSoX-EI1t-ioVd-h7GL-M0W8Ht,/dev/hda2(187),1040187392,33554432
+     *  # lvs --separator , --noheadings --units b --unbuffered --nosuffix --options "lv_name,origin,uuid,devices,seg_size,vg_extent_size,size" VGNAME
+     *  RootLV,,06UgP5-2rhb-w3Bo-3mdR-WeoL-pytO-SAa2ky,/dev/hda2(0),5234491392,33554432,5234491392
+     *  SwapLV,,oHviCK-8Ik0-paqS-V20c-nkhY-Bm1e-zgzU0M,/dev/hda2(156),1040187392,33554432,1040187392
+     *  Test2,,3pg3he-mQsA-5Sui-h0i6-HNmc-Cz7W-QSndcR,/dev/hda2(219),1073741824,33554432,1073741824
+     *  Test3,,UB5hFw-kmlm-LSoX-EI1t-ioVd-h7GL-M0W8Ht,/dev/hda2(251),2181038080,33554432,2181038080
+     *  Test3,Test2,UB5hFw-kmlm-LSoX-EI1t-ioVd-h7GL-M0W8Ht,/dev/hda2(187),1040187392,33554432,1040187392
      *
      * Pull out name, origin, & uuid, device, device extent start #, segment size, extent size.
      *
@@ -290,10 +295,10 @@ virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
      *    striped, so "," is not a suitable separator either (rhbz 727474).
      */
     const char *regexes[] = {
-       "^\\s*(\\S+)#(\\S*)#(\\S+)#(\\S+)#(\\S+)#([0-9]+)#(\\S+)#([0-9]+)#?\\s*$"
+       "^\\s*(\\S+)#(\\S*)#(\\S+)#(\\S+)#(\\S+)#([0-9]+)#(\\S+)#([0-9]+)#([0-9]+)#?\\s*$"
     };
     int vars[] = {
-        8
+        9
     };
     int ret = -1;
     virCommandPtr cmd;
@@ -304,7 +309,7 @@ virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
                                "--units", "b",
                                "--unbuffered",
                                "--nosuffix",
-                               "--options", "lv_name,origin,uuid,devices,segtype,stripes,seg_size,vg_extent_size",
+                               "--options", "lv_name,origin,uuid,devices,segtype,stripes,seg_size,vg_extent_size,size",
                                pool->def->source.name,
                                NULL);
     if (virStorageBackendRunProgRegex(pool,
@@ -718,6 +723,10 @@ virStorageBackendLogicalCreateVol(virConnectPtr conn,
                                "--name", vol->name,
                                NULL);
     virCommandAddArg(cmd, "-L");
+    if (vol->capacity != vol->allocation) {
+        virCommandAddArgFormat(cmd, "%lluK", VIR_DIV_UP(vol->allocation, 1024));
+        virCommandAddArg(cmd, "--virtualsize");
+    }
     virCommandAddArgFormat(cmd, "%lluK", VIR_DIV_UP(vol->capacity, 1024));
     if (vol->backingStore.path)
         virCommandAddArgPair(cmd, "-s", vol->backingStore.path);
-- 
1.7.7.6
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                    11 Jul '12
                    
                        From: "Daniel P. Berrange" <berrange(a)redhat.com>
To make it easier to dynamically change the command line ARGV,
switch all storage code over to use virCommandPtr APIs for
running programs
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
 src/storage/storage_backend.c         |   15 +--
 src/storage/storage_backend.h         |    5 +-
 src/storage/storage_backend_disk.c    |   93 +++++++--------
 src/storage/storage_backend_fs.c      |  134 +++++++++-----------
 src/storage/storage_backend_iscsi.c   |  107 +++++++++-------
 src/storage/storage_backend_logical.c |  225 ++++++++++++++++++---------------
 6 files changed, 294 insertions(+), 285 deletions(-)
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index e2e9b51..e0ff717 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -57,7 +57,6 @@
 #include "storage_backend.h"
 #include "logging.h"
 #include "virfile.h"
-#include "command.h"
 
 #if WITH_STORAGE_LVM
 # include "storage_backend_logical.h"
@@ -1418,7 +1417,7 @@ virStorageBackendStablePath(virStoragePoolObjPtr pool,
  */
 int
 virStorageBackendRunProgRegex(virStoragePoolObjPtr pool,
-                              const char *const*prog,
+                              virCommandPtr cmd,
                               int nregex,
                               const char **regex,
                               int *nvars,
@@ -1433,7 +1432,6 @@ virStorageBackendRunProgRegex(virStoragePoolObjPtr pool,
     int maxReg = 0, i, j;
     int totgroups = 0, ngroup = 0, maxvars = 0;
     char **groups;
-    virCommandPtr cmd = NULL;
 
     /* Compile all regular expressions */
     if (VIR_ALLOC_N(reg, nregex) < 0) {
@@ -1470,7 +1468,6 @@ virStorageBackendRunProgRegex(virStoragePoolObjPtr pool,
         goto cleanup;
     }
 
-    cmd = virCommandNewArgs(prog);
     virCommandSetOutputFD(cmd, &fd);
     if (virCommandRunAsync(cmd, NULL) < 0) {
         goto cleanup;
@@ -1541,7 +1538,6 @@ cleanup:
         regfree(®[i]);
 
     VIR_FREE(reg);
-    virCommandFree(cmd);
 
     VIR_FORCE_FCLOSE(list);
     VIR_FORCE_CLOSE(fd);
@@ -1562,7 +1558,7 @@ cleanup:
  */
 int
 virStorageBackendRunProgNul(virStoragePoolObjPtr pool,
-                            const char **prog,
+                            virCommandPtr cmd,
                             size_t n_columns,
                             virStorageBackendListVolNulFunc func,
                             void *data)
@@ -1573,7 +1569,6 @@ virStorageBackendRunProgNul(virStoragePoolObjPtr pool,
     char **v;
     int ret = -1;
     int i;
-    virCommandPtr cmd = NULL;
 
     if (n_columns == 0)
         return -1;
@@ -1585,7 +1580,6 @@ virStorageBackendRunProgNul(virStoragePoolObjPtr pool,
     for (i = 0; i < n_columns; i++)
         v[i] = NULL;
 
-    cmd = virCommandNewArgs(prog);
     virCommandSetOutputFD(cmd, &fd);
     if (virCommandRunAsync(cmd, NULL) < 0) {
         goto cleanup;
@@ -1623,8 +1617,8 @@ virStorageBackendRunProgNul(virStoragePoolObjPtr pool,
     }
 
     if (feof (fp) < 0) {
-        virReportSystemError(errno,
-                             _("read error on pipe to '%s'"), prog[0]);
+        virReportSystemError(errno, "%s",
+                             _("read error on pipe"));
         goto cleanup;
     }
 
@@ -1633,7 +1627,6 @@ virStorageBackendRunProgNul(virStoragePoolObjPtr pool,
     for (i = 0; i < n_columns; i++)
         VIR_FREE(v[i]);
     VIR_FREE(v);
-    virCommandFree(cmd);
 
     VIR_FORCE_FCLOSE(fp);
     VIR_FORCE_CLOSE(fd);
diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h
index a37bf7c..4c371fb 100644
--- a/src/storage/storage_backend.h
+++ b/src/storage/storage_backend.h
@@ -27,6 +27,7 @@
 # include <stdint.h>
 # include "internal.h"
 # include "storage_conf.h"
+# include "command.h"
 
 typedef char * (*virStorageBackendFindPoolSources)(virConnectPtr conn, const char *srcSpec, unsigned int flags);
 typedef int (*virStorageBackendCheckPool)(virConnectPtr conn, virStoragePoolObjPtr pool, bool *active);
@@ -141,7 +142,7 @@ typedef int (*virStorageBackendListVolNulFunc)(virStoragePoolObjPtr pool,
                                                void *data);
 
 int virStorageBackendRunProgRegex(virStoragePoolObjPtr pool,
-                                  const char *const*prog,
+                                  virCommandPtr cmd,
                                   int nregex,
                                   const char **regex,
                                   int *nvars,
@@ -149,7 +150,7 @@ int virStorageBackendRunProgRegex(virStoragePoolObjPtr pool,
                                   void *data, const char *cmd_to_ignore);
 
 int virStorageBackendRunProgNul(virStoragePoolObjPtr pool,
-                                const char **prog,
+                                virCommandPtr cmd,
                                 size_t n_columns,
                                 virStorageBackendListVolNulFunc func,
                                 void *data);
diff --git a/src/storage/storage_backend_disk.c b/src/storage/storage_backend_disk.c
index 995ad2f..ecc51fd 100644
--- a/src/storage/storage_backend_disk.c
+++ b/src/storage/storage_backend_disk.c
@@ -269,17 +269,20 @@ virStorageBackendDiskReadPartitions(virStoragePoolObjPtr pool,
      * -              normal   metadata 100027630080 100030242304      2612736
      *
      */
-    const char *prog[] = {
-        PARTHELPER, pool->def->source.devices[0].path, NULL,
-    };
+    virCommandPtr cmd = virCommandNewArgList(PARTHELPER,
+                                             pool->def->source.devices[0].path,
+                                             NULL);
+    int ret;
 
     pool->def->allocation = pool->def->capacity = pool->def->available = 0;
 
-    return virStorageBackendRunProgNul(pool,
-                                       prog,
-                                       6,
-                                       virStorageBackendDiskMakeVol,
-                                       vol);
+    ret = virStorageBackendRunProgNul(pool,
+                                      cmd,
+                                      6,
+                                      virStorageBackendDiskMakeVol,
+                                      vol);
+    virCommandFree(cmd);
+    return ret;
 }
 
 static int
@@ -299,15 +302,19 @@ virStorageBackendDiskMakePoolGeometry(virStoragePoolObjPtr pool,
 static int
 virStorageBackendDiskReadGeometry(virStoragePoolObjPtr pool)
 {
-    const char *prog[] = {
-        PARTHELPER, pool->def->source.devices[0].path, "-g", NULL,
-    };
-
-    return virStorageBackendRunProgNul(pool,
-                                       prog,
-                                       3,
-                                       virStorageBackendDiskMakePoolGeometry,
-                                       NULL);
+    virCommandPtr cmd = virCommandNewArgList(PARTHELPER,
+                                             pool->def->source.devices[0].path,
+                                             "-g",
+                                             NULL);
+    int ret;
+
+    ret = virStorageBackendRunProgNul(pool,
+                                      cmd,
+                                      3,
+                                      virStorageBackendDiskMakePoolGeometry,
+                                      NULL);
+    virCommandFree(cmd);
+    return ret;
 }
 
 static int
@@ -379,15 +386,13 @@ virStorageBackendDiskBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
     bool ok_to_mklabel = false;
     int ret = -1;
     /* eg parted /dev/sda mklabel msdos */
-    const char *prog[] = {
-        PARTED,
-        pool->def->source.devices[0].path,
-        "mklabel",
-        "--script",
-        ((pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) ? "msdos" :
-          virStoragePoolFormatDiskTypeToString(pool->def->source.format)),
-        NULL,
-    };
+    virCommandPtr cmd = virCommandNewArgList(PARTED,
+                                             pool->def->source.devices[0].path,
+                                             "mklabel",
+                                             "--script",
+                                             ((pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) ? "msdos" :
+                                              virStoragePoolFormatDiskTypeToString(pool->def->source.format)),
+                                             NULL);
 
     virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
                   VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret);
@@ -419,9 +424,10 @@ virStorageBackendDiskBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
     }
 
     if (ok_to_mklabel)
-        ret = virRun(prog, NULL);
+        ret = virCommandRun(cmd, NULL);
 
 error:
+    virCommandFree(cmd);
     return ret;
 }
 
@@ -628,20 +634,13 @@ virStorageBackendDiskCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
                                virStorageVolDefPtr vol)
 {
     int res = -1;
-    char *start = NULL;
-    char *end = NULL;
     char *partFormat;
     unsigned long long startOffset = 0, endOffset = 0;
-    const char *cmdargv[] = {
-        PARTED,
-        pool->def->source.devices[0].path,
-        "mkpart",
-        "--script",
-        NULL /*partFormat*/,
-        NULL /*start*/,
-        NULL /*end*/,
-        NULL
-    };
+    virCommandPtr cmd = virCommandNewArgList(PARTED,
+                                             pool->def->source.devices[0].path,
+                                             "mkpart",
+                                             "--script",
+                                             NULL);
 
     if (vol->target.encryption != NULL) {
         virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -653,7 +652,7 @@ virStorageBackendDiskCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
     if (virStorageBackendDiskPartFormat(pool, vol, &partFormat) != 0) {
         return -1;
     }
-    cmdargv[4] = partFormat;
+    virCommandAddArg(cmd, partFormat);
 
     if (virStorageBackendDiskPartBoundries(pool, &startOffset,
                                            &endOffset,
@@ -661,15 +660,10 @@ virStorageBackendDiskCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
         goto cleanup;
     }
 
-    if (virAsprintf(&start, "%lluB", startOffset) < 0 ||
-        virAsprintf(&end, "%lluB", endOffset) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-    cmdargv[5] = start;
-    cmdargv[6] = end;
+    virCommandAddArgFormat(cmd, "%lluB", startOffset);
+    virCommandAddArgFormat(cmd, "%lluB", endOffset);
 
-    if (virRun(cmdargv, NULL) < 0)
+    if (virCommandRun(cmd, NULL) < 0)
         goto cleanup;
 
     /* wait for device node to show up */
@@ -690,8 +684,7 @@ virStorageBackendDiskCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
 
 cleanup:
     VIR_FREE(partFormat);
-    VIR_FREE(start);
-    VIR_FREE(end);
+    virCommandFree(cmd);
     return res;
 }
 
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index 4894994..b6ca858 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -251,10 +251,10 @@ virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSE
             .sources = NULL
         }
     };
-    const char *prog[] = { SHOWMOUNT, "--no-headers", "--exports", NULL, NULL };
     virStoragePoolSourcePtr source = NULL;
     char *retval = NULL;
     unsigned int i;
+    virCommandPtr cmd = NULL;
 
     virCheckFlags(0, NULL);
 
@@ -270,9 +270,14 @@ virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSE
     }
 
     state.host = source->hosts[0].name;
-    prog[3] = source->hosts[0].name;
 
-    if (virStorageBackendRunProgRegex(NULL, prog, 1, regexes, vars,
+    cmd = virCommandNewArgList(SHOWMOUNT,
+                               "--no-headers",
+                               "--exports",
+                               source->hosts[0].name,
+                               NULL);
+
+    if (virStorageBackendRunProgRegex(NULL, cmd, 1, regexes, vars,
                             virStorageBackendFileSystemNetFindPoolSourcesFunc,
                             &state, NULL) < 0)
         goto cleanup;
@@ -289,7 +294,7 @@ virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSE
     VIR_FREE(state.list.sources);
 
     virStoragePoolSourceFree(source);
-
+    virCommandFree(cmd);
     return retval;
 }
 
@@ -337,63 +342,16 @@ virStorageBackendFileSystemIsMounted(virStoragePoolObjPtr pool) {
  */
 static int
 virStorageBackendFileSystemMount(virStoragePoolObjPtr pool) {
-    char *src;
-    const char **mntargv;
-
+    char *src = NULL;
     /* 'mount -t auto' doesn't seem to auto determine nfs (or cifs),
      *  while plain 'mount' does. We have to craft separate argvs to
      *  accommodate this */
-    int netauto = (pool->def->type == VIR_STORAGE_POOL_NETFS &&
-                   pool->def->source.format == VIR_STORAGE_POOL_NETFS_AUTO);
-    int glusterfs = (pool->def->type == VIR_STORAGE_POOL_NETFS &&
-                 pool->def->source.format == VIR_STORAGE_POOL_NETFS_GLUSTERFS);
-
-    int source_index;
-
-    const char *netfs_auto_argv[] = {
-        MOUNT,
-        NULL, /* source path */
-        pool->def->target.path,
-        NULL,
-    };
-
-    const char *fs_argv[] =  {
-        MOUNT,
-        "-t",
-        pool->def->type == VIR_STORAGE_POOL_FS ?
-        virStoragePoolFormatFileSystemTypeToString(pool->def->source.format) :
-        virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format),
-        NULL, /* Fill in shortly - careful not to add extra fields
-                 before this */
-        pool->def->target.path,
-        NULL,
-    };
-
-    const char *glusterfs_argv[] = {
-        MOUNT,
-        "-t",
-        pool->def->type == VIR_STORAGE_POOL_FS ?
-        virStoragePoolFormatFileSystemTypeToString(pool->def->source.format) :
-        virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format),
-        NULL,
-        "-o",
-        "direct-io-mode=1",
-        pool->def->target.path,
-        NULL,
-    };
-
-    if (netauto) {
-        mntargv = netfs_auto_argv;
-        source_index = 1;
-    } else if (glusterfs) {
-        mntargv = glusterfs_argv;
-        source_index = 3;
-    } else {
-        mntargv = fs_argv;
-        source_index = 3;
-    }
-
-    int ret;
+    bool netauto = (pool->def->type == VIR_STORAGE_POOL_NETFS &&
+                    pool->def->source.format == VIR_STORAGE_POOL_NETFS_AUTO);
+    bool glusterfs = (pool->def->type == VIR_STORAGE_POOL_NETFS &&
+                      pool->def->source.format == VIR_STORAGE_POOL_NETFS_GLUSTERFS);
+    virCommandPtr cmd = NULL;
+    int ret = -1;
 
     if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
         if (pool->def->source.nhost != 1) {
@@ -441,14 +399,41 @@ virStorageBackendFileSystemMount(virStoragePoolObjPtr pool) {
             return -1;
         }
     }
-    mntargv[source_index] = src;
 
-    if (virRun(mntargv, NULL) < 0) {
-        VIR_FREE(src);
-        return -1;
-    }
+    if (netauto)
+        cmd = virCommandNewArgList(MOUNT,
+                                   src,
+                                   pool->def->target.path,
+                                   NULL);
+    else if (glusterfs)
+        cmd = virCommandNewArgList( MOUNT,
+                                    "-t",
+                                    (pool->def->type == VIR_STORAGE_POOL_FS ?
+                                     virStoragePoolFormatFileSystemTypeToString(pool->def->source.format) :
+                                     virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format)),
+                                    src,
+                                    "-o",
+                                    "direct-io-mode=1",
+                                    pool->def->target.path,
+                                    NULL);
+    else
+        cmd = virCommandNewArgList(MOUNT,
+                                   "-t",
+                                   (pool->def->type == VIR_STORAGE_POOL_FS ?
+                                    virStoragePoolFormatFileSystemTypeToString(pool->def->source.format) :
+                                    virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format)),
+                                   src,
+                                   pool->def->target.path,
+                                   NULL);
+
+    if (virCommandRun(cmd, NULL) < 0)
+        goto cleanup;
+
+    ret = 0;
+cleanup:
+    virCommandFree(cmd);
     VIR_FREE(src);
-    return 0;
+    return ret;
 }
 
 /**
@@ -462,8 +447,8 @@ virStorageBackendFileSystemMount(virStoragePoolObjPtr pool) {
  */
 static int
 virStorageBackendFileSystemUnmount(virStoragePoolObjPtr pool) {
-    const char *mntargv[3];
-    int ret;
+    virCommandPtr cmd = NULL;
+    int ret = -1;
 
     if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
         if (pool->def->source.nhost != 1) {
@@ -497,14 +482,17 @@ virStorageBackendFileSystemUnmount(virStoragePoolObjPtr pool) {
             return 0;
     }
 
-    mntargv[0] = UMOUNT;
-    mntargv[1] = pool->def->target.path;
-    mntargv[2] = NULL;
+    cmd = virCommandNewArgList(UMOUNT,
+                               pool->def->target.path,
+                               NULL);
 
-    if (virRun(mntargv, NULL) < 0) {
-        return -1;
-    }
-    return 0;
+    if (virCommandRun(cmd, NULL) < 0)
+        goto cleanup;
+
+    ret = 0;
+cleanup:
+    virCommandFree(cmd);
+    return ret;
 }
 #endif /* WITH_STORAGE_FS */
 
diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c
index e286c84..88de9fd 100644
--- a/src/storage/storage_backend_iscsi.c
+++ b/src/storage/storage_backend_iscsi.c
@@ -151,31 +151,32 @@ virStorageBackendISCSISession(virStoragePoolObjPtr pool,
     int vars[] = {
         2,
     };
-    const char *const prog[] = {
-        ISCSIADM, "--mode", "session", NULL
-    };
     char *session = NULL;
 
+    virCommandPtr cmd = virCommandNewArgList(ISCSIADM, "--mode", "session", NULL);
+
     /* Note that we ignore the exitstatus.  Older versions of iscsiadm tools
      * returned an exit status of > 0, even if they succeeded.  We will just
      * rely on whether session got filled in properly.
      */
     if (virStorageBackendRunProgRegex(pool,
-                                      prog,
+                                      cmd,
                                       1,
                                       regexes,
                                       vars,
                                       virStorageBackendISCSIExtractSession,
                                       &session, NULL) < 0)
-        return NULL;
+        goto cleanup;
 
     if (session == NULL &&
         !probe) {
         virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("cannot find session"));
-        return NULL;
+        goto cleanup;
     }
 
+cleanup:
+    virCommandFree(cmd);
     return session;
 }
 
@@ -279,42 +280,52 @@ virStorageBackendCreateIfaceIQN(const char *initiatoriqn,
                                 char **ifacename)
 {
     int ret = -1, exitstatus = -1;
-    char temp_ifacename[32];
-    const char *const cmdargv1[] = {
-        ISCSIADM, "--mode", "iface", "--interface",
-        temp_ifacename, "--op", "new", NULL
-    };
-    const char *const cmdargv2[] = {
-        ISCSIADM, "--mode", "iface", "--interface", temp_ifacename,
-        "--op", "update", "--name", "iface.initiatorname", "--value",
-        initiatoriqn, NULL
-    };
+    char *temp_ifacename;
+    virCommandPtr cmd = NULL;
 
-    snprintf(temp_ifacename, sizeof(temp_ifacename), "libvirt-iface-%08llx",
-             (unsigned long long)virRandomBits(30));
+    if (virAsprintf(&temp_ifacename,
+                    "libvirt-iface-%08llx",
+                    (unsigned long long)virRandomBits(30)) < 0) {
+        virReportOOMError();
+        return -1;
+    }
 
     VIR_DEBUG("Attempting to create interface '%s' with IQN '%s'",
-              &temp_ifacename[0], initiatoriqn);
+              temp_ifacename, initiatoriqn);
 
+    cmd = virCommandNewArgList(ISCSIADM,
+                               "--mode", "iface",
+                               "--interface", temp_ifacename,
+                               "--op", "new",
+                               NULL);
     /* Note that we ignore the exitstatus.  Older versions of iscsiadm
      * tools returned an exit status of > 0, even if they succeeded.
      * We will just rely on whether the interface got created
      * properly. */
-    if (virRun(cmdargv1, &exitstatus) < 0) {
+    if (virCommandRun(cmd, &exitstatus) < 0) {
         virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to run command '%s' to create new iscsi interface"),
-                              cmdargv1[0]);
-        goto out;
+                              ISCSIADM);
+        goto cleanup;
     }
+    virCommandFree(cmd);
 
+    cmd = virCommandNewArgList(ISCSIADM,
+                               "--mode", "iface",
+                               "--interface", temp_ifacename,
+                               "--op", "update",
+                               "--name", "iface.initiatorname",
+                               "--value",
+                               initiatoriqn,
+                               NULL);
     /* Note that we ignore the exitstatus.  Older versions of iscsiadm tools
      * returned an exit status of > 0, even if they succeeded.  We will just
      * rely on whether iface file got updated properly. */
-    if (virRun(cmdargv2, &exitstatus) < 0) {
+    if (virCommandRun(cmd, &exitstatus) < 0) {
         virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to run command '%s' to update iscsi interface with IQN '%s'"),
-                              cmdargv2[0], initiatoriqn);
-        goto out;
+                              ISCSIADM, initiatoriqn);
+        goto cleanup;
     }
 
     /* Check again to make sure the interface was created. */
@@ -322,7 +333,7 @@ virStorageBackendCreateIfaceIQN(const char *initiatoriqn,
         VIR_DEBUG("Failed to find interface '%s' with IQN '%s' "
                   "after attempting to create it",
                   &temp_ifacename[0], initiatoriqn);
-        goto out;
+        goto cleanup;
     } else {
         VIR_DEBUG("Interface '%s' with IQN '%s' was created successfully",
                   *ifacename, initiatoriqn);
@@ -330,7 +341,9 @@ virStorageBackendCreateIfaceIQN(const char *initiatoriqn,
 
     ret = 0;
 
-out:
+cleanup:
+    virCommandFree(cmd);
+    VIR_FREE(temp_ifacename);
     if (ret != 0)
         VIR_FREE(*ifacename);
     return ret;
@@ -426,14 +439,14 @@ static int
 virStorageBackendISCSIRescanLUNs(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                  const char *session)
 {
-    const char *const cmdargv[] = {
-        ISCSIADM, "--mode", "session", "-r", session, "-R", NULL,
-    };
-
-    if (virRun(cmdargv, NULL) < 0)
-        return -1;
-
-    return 0;
+    virCommandPtr cmd = virCommandNewArgList(ISCSIADM,
+                                             "--mode", "session",
+                                             "-r", session,
+                                             "-R",
+                                             NULL);
+    int ret = virCommandRun(cmd, NULL);
+    virCommandFree(cmd);
+    return ret;
 }
 
 struct virStorageBackendISCSITargetList {
@@ -501,24 +514,25 @@ virStorageBackendISCSIScanTargets(const char *portal,
         "^\\s*(\\S+)\\s+(\\S+)\\s*$"
     };
     int vars[] = { 2 };
-    const char *const cmdsendtarget[] = {
-        ISCSIADM, "--mode", "discovery", "--type", "sendtargets",
-        "--portal", portal, NULL
-    };
     struct virStorageBackendISCSITargetList list;
-    int i;
+    size_t i;
+    int ret = -1;
+    virCommandPtr cmd = virCommandNewArgList(ISCSIADM,
+                                             "--mode", "discovery",
+                                             "--type", "sendtargets",
+                                             "--portal", portal,
+                                             NULL);
 
     memset(&list, 0, sizeof(list));
 
     if (virStorageBackendRunProgRegex(NULL, /* No pool for callback */
-                                      cmdsendtarget,
+                                      cmd,
                                       1,
                                       regexes,
                                       vars,
                                       virStorageBackendISCSIGetTargets,
-                                      &list, NULL) < 0) {
-        return -1;
-    }
+                                      &list, NULL) < 0)
+        goto cleanup;
 
     for (i = 0 ; i < list.ntargets ; i++) {
         /* We have to ignore failure, because we can't undo
@@ -542,7 +556,10 @@ virStorageBackendISCSIScanTargets(const char *portal,
         VIR_FREE(list.targets);
     }
 
-    return 0;
+    ret = 0;
+cleanup:
+    virCommandFree(cmd);
+    return ret;
 }
 
 
diff --git a/src/storage/storage_backend_logical.c b/src/storage/storage_backend_logical.c
index 9a91dd9..9fe769b 100644
--- a/src/storage/storage_backend_logical.c
+++ b/src/storage/storage_backend_logical.c
@@ -48,17 +48,16 @@ static int
 virStorageBackendLogicalSetActive(virStoragePoolObjPtr pool,
                                   int on)
 {
-    const char *cmdargv[4];
-
-    cmdargv[0] = VGCHANGE;
-    cmdargv[1] = on ? "-aly" : "-aln";
-    cmdargv[2] = pool->def->source.name;
-    cmdargv[3] = NULL;
-
-    if (virRun(cmdargv, NULL) < 0)
-        return -1;
-
-    return 0;
+    int ret;
+    virCommandPtr cmd =
+        virCommandNewArgList(VGCHANGE,
+                             on ? "-aly" : "-aln",
+                             pool->def->source.name,
+                             NULL);
+
+    ret = virCommandRun(cmd, NULL);
+    virCommandFree(cmd);
+    return ret;
 }
 
 
@@ -296,24 +295,31 @@ virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
     int vars[] = {
         8
     };
-    const char *prog[] = {
-        LVS, "--separator", "#", "--noheadings", "--units", "b",
-        "--unbuffered", "--nosuffix", "--options",
-        "lv_name,origin,uuid,devices,segtype,stripes,seg_size,vg_extent_size",
-        pool->def->source.name, NULL
-    };
-
+    int ret = -1;
+    virCommandPtr cmd;
+
+    cmd = virCommandNewArgList(LVS,
+                               "--separator", "#",
+                               "--noheadings",
+                               "--units", "b",
+                               "--unbuffered",
+                               "--nosuffix",
+                               "--options", "lv_name,origin,uuid,devices,segtype,stripes,seg_size,vg_extent_size",
+                               pool->def->source.name,
+                               NULL);
     if (virStorageBackendRunProgRegex(pool,
-                                      prog,
+                                      cmd,
                                       1,
                                       regexes,
                                       vars,
                                       virStorageBackendLogicalMakeVol,
-                                      vol, "lvs") < 0) {
-        return -1;
-    }
+                                      vol, "lvs") < 0)
+        goto cleanup;
 
-    return 0;
+    ret = 0;
+cleanup:
+    virCommandFree(cmd);
+    return ret;
 }
 
 static int
@@ -405,8 +411,7 @@ virStorageBackendLogicalFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
     int vars[] = {
         2
     };
-    const char *const prog[] = { PVS, "--noheadings", "-o", "pv_name,vg_name", NULL };
-    const char *const scanprog[] = { VGSCAN, NULL };
+    virCommandPtr cmd;
     char *retval = NULL;
     virStoragePoolSourceList sourceList;
     int i;
@@ -418,17 +423,25 @@ virStorageBackendLogicalFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
      * that might be hanging around, so if this fails for some reason, the
      * worst that happens is that scanning doesn't pick everything up
      */
-    if (virRun(scanprog, NULL) < 0) {
+    cmd = virCommandNew(VGSCAN);
+    if (virCommandRun(cmd, NULL) < 0)
         VIR_WARN("Failure when running vgscan to refresh physical volumes");
-    }
+    virCommandFree(cmd);
 
     memset(&sourceList, 0, sizeof(sourceList));
     sourceList.type = VIR_STORAGE_POOL_LOGICAL;
 
-    if (virStorageBackendRunProgRegex(NULL, prog, 1, regexes, vars,
-                                virStorageBackendLogicalFindPoolSourcesFunc,
-                                &sourceList, "pvs") < 0)
+    cmd = virCommandNewArgList(PVS,
+                               "--noheadings",
+                               "-o", "pv_name,vg_name",
+                               NULL);
+    if (virStorageBackendRunProgRegex(NULL, cmd, 1, regexes, vars,
+                                      virStorageBackendLogicalFindPoolSourcesFunc,
+                                      &sourceList, "pvs") < 0) {
+        virCommandFree(cmd);
         return NULL;
+    }
+    virCommandFree(cmd);
 
     retval = virStoragePoolSourceListFormat(&sourceList);
     if (retval == NULL) {
@@ -483,26 +496,20 @@ virStorageBackendLogicalBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
                                   virStoragePoolObjPtr pool,
                                   unsigned int flags)
 {
-    const char **vgargv;
-    const char *pvargv[3];
-    int n = 0, i, fd;
+    virCommandPtr vgcmd;
+    int fd;
     char zeros[PV_BLANK_SECTOR_SIZE];
+    int ret = -1;
+    size_t i;
 
     virCheckFlags(0, -1);
 
     memset(zeros, 0, sizeof(zeros));
 
-    if (VIR_ALLOC_N(vgargv, 3 + pool->def->source.ndevice) < 0) {
-        virReportOOMError();
-        return -1;
-    }
+    vgcmd = virCommandNewArgList(VGCREATE, pool->def->source.name, NULL);
 
-    vgargv[n++] = VGCREATE;
-    vgargv[n++] = pool->def->source.name;
-
-    pvargv[0] = PVCREATE;
-    pvargv[2] = NULL;
     for (i = 0 ; i < pool->def->source.ndevice ; i++) {
+        virCommandPtr pvcmd;
         /*
          * LVM requires that the first sector is blanked if using
          * a whole disk as a PV. So we just blank them out regardless
@@ -539,25 +546,27 @@ virStorageBackendLogicalBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
          * Initialize the physical volume because vgcreate is not
          * clever enough todo this for us :-(
          */
-        vgargv[n++] = pool->def->source.devices[i].path;
-        pvargv[1] = pool->def->source.devices[i].path;
-        if (virRun(pvargv, NULL) < 0)
+        pvcmd = virCommandNewArgList(PVCREATE,
+                                     pool->def->source.devices[i].path,
+                                     NULL);
+        if (virCommandRun(pvcmd, NULL) < 0) {
+            virCommandFree(pvcmd);
             goto cleanup;
-    }
+        }
+        virCommandFree(pvcmd);
 
-    vgargv[n] = NULL;
+        virCommandAddArg(vgcmd, pool->def->source.devices[i].path);
+    }
 
     /* Now create the volume group itself */
-    if (virRun(vgargv, NULL) < 0)
+    if (virCommandRun(vgcmd, NULL) < 0)
         goto cleanup;
 
-    VIR_FREE(vgargv);
-
-    return 0;
+    ret = 0;
 
- cleanup:
-    VIR_FREE(vgargv);
-    return -1;
+cleanup:
+    virCommandFree(vgcmd);
+    return ret;
 }
 
 
@@ -579,33 +588,42 @@ virStorageBackendLogicalRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
     int vars[] = {
         2
     };
-    const char *prog[] = {
-        VGS, "--separator", ":", "--noheadings", "--units", "b", "--unbuffered",
-        "--nosuffix", "--options", "vg_size,vg_free",
-        pool->def->source.name, NULL
-    };
+    virCommandPtr cmd = NULL;
+    int ret = -1;
 
     virFileWaitForDevices();
 
     /* Get list of all logical volumes */
-    if (virStorageBackendLogicalFindLVs(pool, NULL) < 0) {
-        virStoragePoolObjClearVols(pool);
-        return -1;
-    }
+    if (virStorageBackendLogicalFindLVs(pool, NULL) < 0)
+        goto cleanup;
+
+    cmd = virCommandNewArgList(VGS,
+                               "--separator", ":",
+                               "--noheadings",
+                               "--units", "b",
+                               "--unbuffered",
+                               "--nosuffix",
+                               "--options", "vg_size,vg_free",
+                               pool->def->source.name,
+                               NULL);
 
     /* Now get basic volgrp metadata */
     if (virStorageBackendRunProgRegex(pool,
-                                      prog,
+                                      cmd,
                                       1,
                                       regexes,
                                       vars,
                                       virStorageBackendLogicalRefreshPoolFunc,
-                                      NULL, "vgs") < 0) {
-        virStoragePoolObjClearVols(pool);
-        return -1;
-    }
+                                      NULL, "vgs") < 0)
+        goto cleanup;
 
-    return 0;
+    ret = 0;
+
+cleanup:
+    virCommandFree(cmd);
+    if (ret < 0)
+        virStoragePoolObjClearVols(pool);
+    return ret;
 }
 
 /*
@@ -628,31 +646,37 @@ virStorageBackendLogicalDeletePool(virConnectPtr conn ATTRIBUTE_UNUSED,
                                    virStoragePoolObjPtr pool,
                                    unsigned int flags)
 {
-    const char *cmdargv[] = {
-        VGREMOVE, "-f", pool->def->source.name, NULL
-    };
-    const char *pvargv[3];
-    int i, error;
+    virCommandPtr cmd = NULL;
+    size_t i;
+    int ret = -1;
 
     virCheckFlags(0, -1);
 
     /* first remove the volume group */
-    if (virRun(cmdargv, NULL) < 0)
-        return -1;
+    cmd = virCommandNewArgList(VGREMOVE,
+                               "-f", pool->def->source.name,
+                               NULL);
+    if (virCommandRun(cmd, NULL) < 0)
+        goto cleanup;
+    virCommandFree(cmd);
 
     /* now remove the pv devices and clear them out */
-    error = 0;
-    pvargv[0] = PVREMOVE;
-    pvargv[2] = NULL;
+    ret = 0;
     for (i = 0 ; i < pool->def->source.ndevice ; i++) {
-        pvargv[1] = pool->def->source.devices[i].path;
-        if (virRun(pvargv, NULL) < 0) {
-            error = -1;
+        cmd = virCommandNewArgList(PVREMOVE,
+                                   pool->def->source.devices[i].path,
+                                   NULL);
+        if (virCommandRun(cmd, NULL) < 0) {
+            ret = -1;
             break;
         }
+        virCommandFree(cmd);
+        cmd = NULL;
     }
 
-    return error;
+cleanup:
+    virCommandFree(cmd);
+    return ret;
 }
 
 
@@ -669,16 +693,7 @@ virStorageBackendLogicalCreateVol(virConnectPtr conn,
                                   virStorageVolDefPtr vol)
 {
     int fdret, fd = -1;
-    char size[100];
-    const char *cmdargvnew[] = {
-        LVCREATE, "--name", vol->name, "-L", size,
-        pool->def->source.name, NULL
-    };
-    const char *cmdargvsnap[] = {
-        LVCREATE, "--name", vol->name, "-L", size,
-        "-s", vol->backingStore.path, NULL
-    };
-    const char **cmdargv = cmdargvnew;
+    virCommandPtr cmd = NULL;
 
     if (vol->target.encryption != NULL) {
         virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -687,15 +702,6 @@ virStorageBackendLogicalCreateVol(virConnectPtr conn,
         return -1;
     }
 
-    if (vol->backingStore.path) {
-        cmdargv = cmdargvsnap;
-    }
-
-    snprintf(size, sizeof(size)-1, "%lluK", VIR_DIV_UP(vol->capacity, 1024));
-    size[sizeof(size)-1] = '\0';
-
-    vol->type = VIR_STORAGE_VOL_BLOCK;
-
     if (vol->target.path != NULL) {
         /* A target path passed to CreateVol has no meaning */
         VIR_FREE(vol->target.path);
@@ -708,8 +714,18 @@ virStorageBackendLogicalCreateVol(virConnectPtr conn,
         return -1;
     }
 
-    if (virRun(cmdargv, NULL) < 0)
-        return -1;
+    cmd = virCommandNewArgList(LVCREATE,
+                               "--name", vol->name,
+                               NULL);
+    virCommandAddArg(cmd, "-L");
+    virCommandAddArgFormat(cmd, "%lluK", VIR_DIV_UP(vol->capacity, 1024));
+    if (vol->backingStore.path)
+        virCommandAddArgPair(cmd, "-s", vol->backingStore.path);
+    else
+        virCommandAddArg(cmd, pool->def->source.name);
+
+    if (virCommandRun(cmd, NULL) < 0)
+        goto cleanup;
 
     if ((fdret = virStorageBackendVolOpen(vol->target.path)) < 0)
         goto cleanup;
@@ -752,6 +768,7 @@ virStorageBackendLogicalCreateVol(virConnectPtr conn,
  cleanup:
     VIR_FORCE_CLOSE(fd);
     virStorageBackendLogicalDeleteVol(conn, pool, vol, 0);
+    virCommandFree(cmd);
     return -1;
 }
 
-- 
1.7.7.6
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                    
                        
                            
                                
                            
                            [libvirt] [glib PATCH] Add gvir_connection_domain_restore() and gvir_connection_domain_restore_async()
                        
                        
by Jovanka Gulicoska 11 Jul '12
                    by Jovanka Gulicoska 11 Jul '12
11 Jul '12
                    
                        ---
 libvirt-gobject/libvirt-gobject-connection.c |  136 ++++++++++++++++++++++++++
 libvirt-gobject/libvirt-gobject-connection.h |   19 ++++
 libvirt-gobject/libvirt-gobject.sym          |    3 +
 3 files changed, 158 insertions(+)
diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c
index 3a99034..2302328 100644
--- a/libvirt-gobject/libvirt-gobject-connection.c
+++ b/libvirt-gobject/libvirt-gobject-connection.c
@@ -57,6 +57,7 @@ enum {
     VIR_CONNECTION_CLOSED,
     VIR_DOMAIN_ADDED,
     VIR_DOMAIN_REMOVED,
+    VIR_DOMAIN_RESTORED,
     LAST_SIGNAL
 };
 
@@ -228,6 +229,15 @@ static void gvir_connection_class_init(GVirConnectionClass *klass)
                  1,
                  GVIR_TYPE_DOMAIN);
 
+    signals[VIR_DOMAIN_RESTORED] = g_signal_new("domain-restored",
+                                                G_OBJECT_CLASS_TYPE(object_class),
+                                                G_SIGNAL_RUN_FIRST,
+                                                G_STRUCT_OFFSET(GVirConnectionClass, domain_restored),
+                                                NULL, NULL,
+                                                g_cclosure_marshal_VOID__OBJECT,
+                                                G_TYPE_NONE,
+                                                0);
+
     g_type_class_add_private(klass, sizeof(GVirConnectionPrivate));
 }
 
@@ -1605,3 +1615,129 @@ gvir_connection_get_capabilities_finish(GVirConnection *conn,
 
     return g_object_ref(caps);
 }
+
+/*
+ * gvir_connection_domain_restore
+ */
+gboolean gvir_connection_domain_restore(GVirConnection *conn,
+                                        gchar *filename,
+                                        GVirConfigDomain *conf,
+                                        guint flags,
+                                        GError **err)
+{
+    GVirConnectionPrivate *priv;
+    gchar *custom_xml;
+    int ret;
+
+    g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE);
+    g_return_val_if_fail(GVIR_CONFIG_IS_DOMAIN (conf), FALSE);
+    g_return_val_if_fail((err == NULL) || (*err == NULL), FALSE);
+
+    priv = conn->priv;
+    custom_xml = gvir_config_object_to_xml(GVIR_CONFIG_OBJECT(conf));
+
+    g_return_val_if_fail(custom_xml != NULL, FALSE);
+
+    if(flags || custom_xml) {
+       ret = virDomainRestoreFlags(priv->conn, filename, custom_xml, flags);
+       g_free (custom_xml);
+    }
+    else {
+       ret = virDomainRestore(priv->conn, filename);
+       g_free (custom_xml);
+    }
+
+    if(ret < 0) {
+       gvir_set_error_literal(err, GVIR_CONNECTION_ERROR,
+                              0,
+                              "Unable to restore domain");
+
+       return FALSE;
+    }
+
+    return TRUE;
+}
+
+typedef struct {
+    gchar *filename;
+    gchar *custom_xml;
+    guint flags;
+} DomainRestoreFromFileData;
+
+static void domain_restore_from_file_data_free(DomainRestoreFromFileData *data)
+{
+    g_slice_free(DomainRestoreFromFileData, data);
+}
+
+static void
+gvir_connection_domain_restore_helper(GSimpleAsyncResult *res,
+                                      GObject *object,
+                                      GCancellable *cancellable G_GNUC_UNUSED)
+{
+    GVirConnection *conn = GVIR_CONNECTION(object);
+    DomainRestoreFromFileData *data;
+    GVirConfigDomain *conf;
+    GError *err = NULL;
+
+    data = g_simple_async_result_get_op_res_gpointer(res);
+    conf =  gvir_config_domain_new_from_xml(data->custom_xml, &err);
+
+    if(!gvir_connection_domain_restore(conn, data->filename, conf, data->flags, &err))
+       g_simple_async_result_take_error(res, err);
+}
+
+/*
+ * Async function of gvir_connection_domain_restore
+ */
+void gvir_connection_domain_restore_async(GVirConnection *conn,
+                                          gchar *filename,
+                                          GVirConfigDomain *conf,
+                                          guint flags,
+                                          GCancellable *cancellable,
+                                          GAsyncReadyCallback callback,
+                                          gpointer user_data)
+{
+    GSimpleAsyncResult *res;
+    DomainRestoreFromFileData *data;
+    gchar *custom_xml;
+
+    g_return_if_fail(GVIR_IS_CONNECTION(conn));
+    g_return_if_fail(GVIR_CONFIG_IS_DOMAIN (conf));
+    g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable));
+    
+    custom_xml = gvir_config_object_to_xml(GVIR_CONFIG_OBJECT(conf));
+
+    data = g_slice_new0(DomainRestoreFromFileData);
+    data->filename = filename;
+    data->custom_xml = custom_xml;
+    data->flags = flags;
+
+    res = g_simple_async_result_new(G_OBJECT(conn),
+                                    callback,
+                                    user_data,
+                                    gvir_connection_domain_restore_async);
+    g_simple_async_result_set_op_res_gpointer(res, data, 
+                                              (GDestroyNotify)domain_restore_from_file_data_free);
+
+    g_simple_async_result_run_in_thread(res,
+                                        gvir_connection_domain_restore_helper,
+                                        G_PRIORITY_DEFAULT,
+                                        cancellable);
+
+    g_object_unref(res);
+}
+
+gboolean gvir_connection_domain_restore_finish(GVirConnection *conn,
+                                               GAsyncResult *result,
+                                               GError **err)
+{
+    g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE);
+    g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(conn),
+                                                        gvir_connection_domain_restore_async),
+                                                        FALSE);
+
+     if (g_simple_async_result_propagate_error(G_SIMPLE_ASYNC_RESULT(result), err))
+        return FALSE;
+
+    return TRUE;
+}
diff --git a/libvirt-gobject/libvirt-gobject-connection.h b/libvirt-gobject/libvirt-gobject-connection.h
index c80eecf..01d5d0b 100644
--- a/libvirt-gobject/libvirt-gobject-connection.h
+++ b/libvirt-gobject/libvirt-gobject-connection.h
@@ -75,6 +75,8 @@ struct _GVirConnectionClass
     void (*domain_added)(GVirConnection *conn, GVirDomain *dom);
     void (*domain_removed)(GVirConnection *conn, GVirDomain *dom);
 
+    void (*domain_restored)(GVirConnection *conn);
+
     GVirStream *(*stream_new)(GVirConnection *conn, gpointer handle);
 
     gpointer padding[20];
@@ -202,6 +204,23 @@ gvir_connection_get_capabilities_finish(GVirConnection *conn,
                                         GAsyncResult *result,
                                         GError **err);
 
+gboolean gvir_connection_domain_restore(GVirConnection *conn,
+                                        gchar *filename,
+                                        GVirConfigDomain *conf,
+                                        guint flags,
+                                        GError **err);
+
+void gvir_connection_domain_restore_async(GVirConnection *conn,
+                                          gchar *filename,
+                                          GVirConfigDomain *conf,
+                                          guint flags,
+                                          GCancellable *cancellable,
+                                          GAsyncReadyCallback callback,
+                                          gpointer user_data);
+
+gboolean gvir_connection_domain_restore_finish(GVirConnection *conn,
+                                               GAsyncResult *result,
+                                               GError **err);
 G_END_DECLS
 
 #endif /* __LIBVIRT_GOBJECT_CONNECTION_H__ */
diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym
index 8ff9e24..0aaefa2 100644
--- a/libvirt-gobject/libvirt-gobject.sym
+++ b/libvirt-gobject/libvirt-gobject.sym
@@ -31,6 +31,9 @@ LIBVIRT_GOBJECT_0.0.8 {
 	gvir_connection_create_storage_pool;
 	gvir_connection_start_domain;
 	gvir_connection_get_node_info;
+        gvir_connection_domain_restore;
+        gvir_connection_domain_restore_async;
+        gvir_connection_domain_restore_finish;
 
 	gvir_domain_device_get_type;
 	gvir_domain_device_get_domain;
-- 
1.7.10.4
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            2
                            
                          
                          
                            
    
                          
                        
                    
                        
                            
                                
                            
                            [libvirt] [glib PATCH] Add bindings for virDomainSnapshotCreateXML()
                        
                        
by Jovanka Gulicoska 11 Jul '12
                    by Jovanka Gulicoska 11 Jul '12
11 Jul '12
                    
                        ---
 libvirt-gobject/libvirt-gobject-domain.c |   39 ++++++++++++++++++++++++++++++
 libvirt-gobject/libvirt-gobject-domain.h |    4 +++
 2 files changed, 43 insertions(+)
diff --git a/libvirt-gobject/libvirt-gobject-domain.c b/libvirt-gobject/libvirt-gobject-domain.c
index eda2427..ea621ff 100644
--- a/libvirt-gobject/libvirt-gobject-domain.c
+++ b/libvirt-gobject/libvirt-gobject-domain.c
@@ -1270,3 +1270,42 @@ GList *gvir_domain_get_devices(GVirDomain *domain,
 
     return g_list_reverse (ret);
 }
+
+/**
+ * gvir_domain_snapshot_create_xml:
+ * @dom: the domain
+ * @conf: configuration of domain
+ * @flags: the flags
+ * @err: (allow-none):Place-holder for error or NULL
+ *
+ * Returns: snapshot of existing domain
+ */
+GVirConfigDomainSnapshot *gvir_domain_snapshot_create_xml(GVirDomain *dom,
+                                                          GVirConfigDomain *conf,
+                                                          guint flags,
+                                                          GError **err)
+{
+    GVirDomainPrivate *priv;
+    virDomainSnapshot *snapshot;
+    gchar *xml_desc;
+    
+    g_return_val_if_fail(GVIR_IS_DOMAIN(dom), FALSE);
+    g_return_val_if_fail(GVIR_CONFIG_IS_DOMAIN (conf), FALSE);
+    g_return_val_if_fail(err == NULL || *err == NULL, NULL);
+
+    priv = dom->priv;
+    xml_desc = gvir_config_object_to_xml(GVIR_CONFIG_OBJECT(conf));
+
+    if(!(snapshot = virDomainSnapshotCreateXML(priv->handle, xml_desc, flags))) {
+       gvir_set_error_literal(err, GVIR_DOMAIN_ERROR,
+                              0,
+                             "Unable to create snapshot of domain");
+        return NULL;
+
+    }
+    
+    GVirConfigDomainSnapshot *conf_snapshot = gvir_config_domain_snapshot_new_from_xml(xml_desc, err);
+
+    g_free(xml_desc);
+    return conf_snapshot;
+}
diff --git a/libvirt-gobject/libvirt-gobject-domain.h b/libvirt-gobject/libvirt-gobject-domain.h
index 49516a7..6540f64 100644
--- a/libvirt-gobject/libvirt-gobject-domain.h
+++ b/libvirt-gobject/libvirt-gobject-domain.h
@@ -220,6 +220,10 @@ gboolean gvir_domain_get_saved(GVirDomain *dom);
 GList *gvir_domain_get_devices(GVirDomain *domain,
                                GError **err);
 
+GVirConfigDomainSnapshot *gvir_domain_snapshot_create_xml(GVirDomain *dom,
+                                                    GVirConfigDomain *conf,
+                                                    guint flags,
+                                                    GError **err);
 G_END_DECLS
 
 #endif /* __LIBVIRT_GOBJECT_DOMAIN_H__ */
-- 
1.7.10.4
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                    
                        
                            
                                
                            
                            [libvirt] [glib PATCH V2] Add bindings for virStorageVolDownload() and virStorageVolUpload()
                        
                        
by Jovanka Gulicoska 11 Jul '12
                    by Jovanka Gulicoska 11 Jul '12
11 Jul '12
                    
                        ---
 libvirt-gobject/libvirt-gobject-storage-vol.c |   75 +++++++++++++++++++++++++
 libvirt-gobject/libvirt-gobject-storage-vol.h |   14 +++++
 libvirt-gobject/libvirt-gobject.h             |    1 +
 libvirt-gobject/libvirt-gobject.sym           |    2 +
 4 files changed, 92 insertions(+)
diff --git a/libvirt-gobject/libvirt-gobject-storage-vol.c b/libvirt-gobject/libvirt-gobject-storage-vol.c
index 6f60fcd..7f9aeb7 100644
--- a/libvirt-gobject/libvirt-gobject-storage-vol.c
+++ b/libvirt-gobject/libvirt-gobject-storage-vol.c
@@ -349,3 +349,78 @@ gboolean gvir_storage_vol_resize(GVirStorageVol *vol,
 
     return TRUE;
 }
+
+/**
+ * gvir_storage_vol_download:
+ * @vol: the storage volume to download from
+ * @stream: stream to use as output
+ * @offset: position in @vol to start reading from
+ * @length: limit on amount of data to download
+ * @flags: extra flags, not used yet, pass 0
+ *
+ * Returns: #TRUE of success, #FALSE otherwise
+ */
+gboolean gvir_storage_vol_download(GVirStorageVol *vol,
+                                   GVirStream *stream,
+                                   unsigned long long offset,
+                                   unsigned long long length,
+                                   guint flags,
+                                   GError **err)
+{
+    virStreamPtr st = NULL;
+
+    g_object_get(stream, "handle", &st, NULL);
+
+    g_return_val_if_fail(GVIR_IS_STORAGE_VOL(vol), FALSE);
+    g_return_val_if_fail(GVIR_IS_STREAM(stream), FALSE);
+    g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+
+    if(virStorageVolDownload(vol->priv->handle, st, offset, length, 0) < 0) {
+       gvir_set_error_literal(err,
+                              GVIR_STORAGE_VOL_ERROR,
+                              0,
+                              "Unable to downlaod volume storage");
+
+       return FALSE;
+    }
+
+    return TRUE;
+}
+
+/**
+ * gvir_storage_vol_upload:
+ * @vol: the storage volume to upload
+ * @stream: stream to use as input
+ * @offset: position in @vol to start to write to
+ * @length: limit on amount of data to upload
+ * @flags: the flags, not set yet, pass 0
+ *
+ * Returns: #TRUE of success, #FALSE otherwise
+ */
+gboolean gvir_storage_vol_upload(GVirStorageVol *vol,
+                                 GVirStream *stream,
+                                 unsigned long long offset,
+                                 unsigned long long length,
+                                 guint flags,
+                                 GError **err)
+{
+    virStreamPtr st = NULL;
+
+    g_object_get(stream, "handle", &st, NULL);
+
+    g_return_val_if_fail(GVIR_IS_STORAGE_VOL(vol), FALSE);
+    g_return_val_if_fail(GVIR_IS_STREAM(stream), FALSE);
+    g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+
+    if(virStorageVolUpload(vol->priv->handle, st, offset, length, 0) < 0) {
+       gvir_set_error_literal(err,
+                              GVIR_STORAGE_VOL_ERROR,
+                              0,
+                              "Unable to upload to stream");
+
+       return FALSE;
+    }
+
+    return TRUE;
+}
+
diff --git a/libvirt-gobject/libvirt-gobject-storage-vol.h b/libvirt-gobject/libvirt-gobject-storage-vol.h
index b425f0a..e156792 100644
--- a/libvirt-gobject/libvirt-gobject-storage-vol.h
+++ b/libvirt-gobject/libvirt-gobject-storage-vol.h
@@ -110,6 +110,20 @@ gboolean gvir_storage_vol_resize(GVirStorageVol *vol,
                                  guint flags,
                                  GError **err);
 
+gboolean gvir_storage_vol_download(GVirStorageVol *vol,
+                                   GVirStream *stream,
+                                   unsigned long long offset,
+                                   unsigned long long length,
+                                   guint flags,
+                                   GError **err);
+
+gboolean gvir_storage_vol_upload(GVirStorageVol *vol,
+                                 GVirStream *stream,
+                                 unsigned long long offset,
+                                 unsigned long long length,
+                                 guint flags,
+                                 GError **err);
+
 G_END_DECLS
 
 #endif /* __LIBVIRT_GOBJECT_STORAGE_VOL_H__ */
diff --git a/libvirt-gobject/libvirt-gobject.h b/libvirt-gobject/libvirt-gobject.h
index f52cc00..b1158f7 100644
--- a/libvirt-gobject/libvirt-gobject.h
+++ b/libvirt-gobject/libvirt-gobject.h
@@ -44,5 +44,6 @@
 #include <libvirt-gobject/libvirt-gobject-storage-pool.h>
 #include <libvirt-gobject/libvirt-gobject-connection.h>
 #include <libvirt-gobject/libvirt-gobject-manager.h>
+#include <libvirt-gobject/libvirt-gobject-stream.h>
 
 #endif /* __LIBVIRT_GOBJECT_H__ */
diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym
index db32c7f..478881b 100644
--- a/libvirt-gobject/libvirt-gobject.sym
+++ b/libvirt-gobject/libvirt-gobject.sym
@@ -143,6 +143,8 @@ LIBVIRT_GOBJECT_0.0.8 {
 	gvir_storage_vol_get_info;
 	gvir_storage_vol_delete;
 	gvir_storage_vol_resize;
+	gvir_storage_vol_download;
+	gvir_storage_vol_upload;
 
 	gvir_connection_handle_get_type;
 
-- 
1.7.10.4
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                    11 Jul '12
                    
                        ---
 libvirt-gobject/libvirt-gobject-connection.c |  153 ++++++++++++++++++++++++++
 libvirt-gobject/libvirt-gobject-connection.h |   19 ++++
 libvirt-gobject/libvirt-gobject.sym          |    3 +
 3 files changed, 175 insertions(+)
diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c
index 3a99034..6fbf86b 100644
--- a/libvirt-gobject/libvirt-gobject-connection.c
+++ b/libvirt-gobject/libvirt-gobject-connection.c
@@ -1605,3 +1605,156 @@ gvir_connection_get_capabilities_finish(GVirConnection *conn,
 
     return g_object_ref(caps);
 }
+
+/**
+ * gvir_connection_domain_restore:
+ * @conn: a #GVirConnection
+ * @filename: path to input file
+ * @conf: configuration for domain
+ * @flags: the flags
+ *
+ * Returns: TRUE on success, FALSe otherwise
+ */
+gboolean gvir_connection_domain_restore(GVirConnection *conn,
+                                        gchar *filename,
+                                        GVirConfigDomain *conf,
+                                        guint flags,
+                                        GError **err)
+{
+    GVirConnectionPrivate *priv;
+    gchar *custom_xml;
+    int ret;
+
+    g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE);
+    g_return_val_if_fail(GVIR_CONFIG_IS_DOMAIN (conf), FALSE);
+    g_return_val_if_fail((err == NULL) || (*err == NULL), FALSE);
+
+    priv = conn->priv;
+    custom_xml = gvir_config_object_to_xml(GVIR_CONFIG_OBJECT(conf));
+
+    g_return_val_if_fail(custom_xml != NULL, FALSE);
+
+    if(flags || (custom_xml != NULL)) {
+       ret = virDomainRestoreFlags(priv->conn, filename, custom_xml, flags);
+       g_free (custom_xml);
+    }
+    else {
+       ret = virDomainRestore(priv->conn, filename);
+       g_free (custom_xml);
+    }
+
+    if(ret < 0) {
+       gvir_set_error_literal(err, GVIR_CONNECTION_ERROR,
+                              0,
+                              "Unable to restore domain");
+
+       return FALSE;
+    }
+
+    return TRUE;
+}
+
+typedef struct {
+    gchar *filename;
+    gchar *custom_xml;
+    guint flags;
+} DomainRestoreFromFileData;
+
+static void domain_restore_from_file_data_free(DomainRestoreFromFileData *data)
+{
+    g_free(data->filename);
+    g_free(data->custom_xml);
+    g_slice_free(DomainRestoreFromFileData, data);
+}
+
+static void
+gvir_connection_domain_restore_helper(GSimpleAsyncResult *res,
+                                      GObject *object,
+                                      GCancellable *cancellable G_GNUC_UNUSED)
+{
+    GVirConnection *conn = GVIR_CONNECTION(object);
+    DomainRestoreFromFileData *data;
+    GVirConfigDomain *conf;
+    GError *err = NULL;
+
+    data = g_simple_async_result_get_op_res_gpointer(res);
+    conf =  gvir_config_domain_new_from_xml(data->custom_xml, &err);
+
+    if(!gvir_connection_domain_restore(conn, data->filename, conf, data->flags, &err))
+       g_simple_async_result_take_error(res, err);
+}
+
+/**
+ * gvir_connection_domain_restore_async:
+ * @conn: a #GVirConnection
+ * @filename: path to input file
+ * @conf: configuration for domain
+ * @flags: the flags
+ * @cancellable: cancallation object
+ * @callback: (scope async): completion callback
+ * @user_data: (closure): opaque data for callback
+ *
+ * Asynchronous variant of #gvir_connection_domain_restore
+ */
+void gvir_connection_domain_restore_async(GVirConnection *conn,
+                                          gchar *filename,
+                                          GVirConfigDomain *conf,
+                                          guint flags,
+                                          GCancellable *cancellable,
+                                          GAsyncReadyCallback callback,
+                                          gpointer user_data)
+{
+    GSimpleAsyncResult *res;
+    DomainRestoreFromFileData *data;
+    gchar *custom_xml;
+
+    g_return_if_fail(GVIR_IS_CONNECTION(conn));
+    g_return_if_fail(GVIR_CONFIG_IS_DOMAIN (conf));
+    g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable));
+    
+    custom_xml = gvir_config_object_to_xml(GVIR_CONFIG_OBJECT(conf));
+
+    data = g_slice_new0(DomainRestoreFromFileData);
+    data->filename = g_strdup(filename);
+    data->custom_xml = g_strdup(custom_xml);
+    data->flags = flags;
+
+    res = g_simple_async_result_new(G_OBJECT(conn),
+                                    callback,
+                                    user_data,
+                                    gvir_connection_domain_restore_async);
+    g_simple_async_result_set_op_res_gpointer(res, data, 
+                                              (GDestroyNotify)domain_restore_from_file_data_free);
+
+    g_simple_async_result_run_in_thread(res,
+                                        gvir_connection_domain_restore_helper,
+                                        G_PRIORITY_DEFAULT,
+                                        cancellable);
+
+    g_object_unref(res);
+}
+
+/**
+ * gvir_connection_domain_finish:
+ * @conn: a #GVirConnection
+ * @result: (transfer none): async method result
+ * @err: Place-holder for possible errors
+ * 
+ * Finishes the operation started by #gvir_domain_restore_async.
+ *
+ * Returns: TRUE if domain was restored successfully, FALSE otherwise.
+ */
+gboolean gvir_connection_domain_restore_finish(GVirConnection *conn,
+                                               GAsyncResult *result,
+                                               GError **err)
+{
+    g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE);
+    g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(conn),
+                                                        gvir_connection_domain_restore_async),
+                                                        FALSE);
+
+     if (g_simple_async_result_propagate_error(G_SIMPLE_ASYNC_RESULT(result), err))
+        return FALSE;
+
+    return TRUE;
+}
diff --git a/libvirt-gobject/libvirt-gobject-connection.h b/libvirt-gobject/libvirt-gobject-connection.h
index c80eecf..01d5d0b 100644
--- a/libvirt-gobject/libvirt-gobject-connection.h
+++ b/libvirt-gobject/libvirt-gobject-connection.h
@@ -75,6 +75,8 @@ struct _GVirConnectionClass
     void (*domain_added)(GVirConnection *conn, GVirDomain *dom);
     void (*domain_removed)(GVirConnection *conn, GVirDomain *dom);
 
+    void (*domain_restored)(GVirConnection *conn);
+
     GVirStream *(*stream_new)(GVirConnection *conn, gpointer handle);
 
     gpointer padding[20];
@@ -202,6 +204,23 @@ gvir_connection_get_capabilities_finish(GVirConnection *conn,
                                         GAsyncResult *result,
                                         GError **err);
 
+gboolean gvir_connection_domain_restore(GVirConnection *conn,
+                                        gchar *filename,
+                                        GVirConfigDomain *conf,
+                                        guint flags,
+                                        GError **err);
+
+void gvir_connection_domain_restore_async(GVirConnection *conn,
+                                          gchar *filename,
+                                          GVirConfigDomain *conf,
+                                          guint flags,
+                                          GCancellable *cancellable,
+                                          GAsyncReadyCallback callback,
+                                          gpointer user_data);
+
+gboolean gvir_connection_domain_restore_finish(GVirConnection *conn,
+                                               GAsyncResult *result,
+                                               GError **err);
 G_END_DECLS
 
 #endif /* __LIBVIRT_GOBJECT_CONNECTION_H__ */
diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym
index 54a093a..db32c7f 100644
--- a/libvirt-gobject/libvirt-gobject.sym
+++ b/libvirt-gobject/libvirt-gobject.sym
@@ -31,6 +31,9 @@ LIBVIRT_GOBJECT_0.0.8 {
 	gvir_connection_create_storage_pool;
 	gvir_connection_start_domain;
 	gvir_connection_get_node_info;
+	gvir_connection_domain_restore;
+	gvir_connection_domain_restore_async;
+	gvir_connection_domain_restore_finish;
 
 	gvir_domain_device_get_type;
 	gvir_domain_device_get_domain;
-- 
1.7.10.4
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1
                            
                          
                          
                            
    
                          
                        
                    11 Jul '12
                    
                        ---
 libvirt-gobject/libvirt-gobject-domain.c |  149 +++++++++++++++++++++++++++++-
 libvirt-gobject/libvirt-gobject-domain.h |   20 +++-
 libvirt-gobject/libvirt-gobject.sym      |    3 +
 3 files changed, 170 insertions(+), 2 deletions(-)
diff --git a/libvirt-gobject/libvirt-gobject-domain.c b/libvirt-gobject/libvirt-gobject-domain.c
index 088cd33..eda2427 100644
--- a/libvirt-gobject/libvirt-gobject-domain.c
+++ b/libvirt-gobject/libvirt-gobject-domain.c
@@ -54,7 +54,7 @@ enum {
     VIR_SUSPENDED,
     VIR_RESUMED,
     VIR_STOPPED,
-    VIR_UPDATED,
+    VIR_UPDATED, 
     LAST_SIGNAL
 };
 
@@ -557,6 +557,153 @@ gboolean gvir_domain_reboot(GVirDomain *dom,
 }
 
 /**
+ * gvir_domain_save_to_file:
+ * @dom: the domain
+ * @filename: path to the output file
+ * @conf: configuration for domain
+ * @flags: the flags
+ *
+ * Returns: TRUE on success, FALSE otherwise 
+ */
+gboolean gvir_domain_save_to_file(GVirDomain *dom,
+                                  gchar *filename,
+                                  GVirConfigDomain *conf,
+                                  guint flags,
+                                  GError **err)
+{
+    GVirDomainPrivate *priv;    
+    gchar *custom_xml;
+    int ret;
+    
+    g_return_val_if_fail(GVIR_IS_DOMAIN(dom), FALSE);
+    g_return_val_if_fail(GVIR_CONFIG_IS_DOMAIN (conf), FALSE);
+    g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+
+    priv = dom->priv;
+    custom_xml = gvir_config_object_to_xml(GVIR_CONFIG_OBJECT(conf));
+   
+    if (flags || (custom_xml != NULL)) {
+        ret = virDomainSaveFlags(priv->handle, filename, custom_xml, flags);
+        g_free (custom_xml);
+    }
+    else {
+        ret = virDomainSave(priv->handle, filename);
+        g_free (custom_xml);
+    }
+    if (ret < 0) {
+        gvir_set_error_literal(err, GVIR_DOMAIN_ERROR,
+                                 0,
+                                 "Unable to save domain to file");
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+typedef struct {
+    gchar *filename;
+    gchar *custom_xml;
+    guint flags;
+} DomainSaveToFileData;
+
+static void domain_save_to_file_data_free(DomainSaveToFileData *data)
+{
+    g_free(data->filename);
+    g_free(data->custom_xml);
+    g_slice_free(DomainSaveToFileData, data);
+}
+
+static void
+gvir_domain_save_to_file_helper(GSimpleAsyncResult *res,
+                                GObject *object,
+                                GCancellable *cancellable G_GNUC_UNUSED)
+{
+    GVirDomain *dom = GVIR_DOMAIN(object);
+    DomainSaveToFileData *data;
+    GVirConfigDomain *conf;
+    GError *err = NULL;
+  
+    data = g_simple_async_result_get_op_res_gpointer(res);
+    conf = gvir_domain_get_config(dom, data->flags, &err);
+  
+    if (!gvir_domain_save_to_file(dom, data->filename, conf, data->flags, &err))
+                       g_simple_async_result_take_error(res, err);
+ }
+
+/**
+ * gvir_domain_save_to_file_async:
+ * @dom: the domain
+ * @filename: path to output file
+ * @conf: configuration for domain
+ * @flags: the flags
+ * @cancellable: cancallation object
+ * @callback: (scope async): completion callback
+ * @user_data: (closure): opaque data for callback
+ *
+ * Asynchronous variant of #gvir_domain_save_to_file
+ */
+void gvir_domain_save_to_file_async (GVirDomain *dom,
+                                     gchar *filename,
+                                     GVirConfigDomain *conf,
+                                     guint flags,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data)
+{
+    GSimpleAsyncResult *res;
+    DomainSaveToFileData *data;
+    gchar *xml;
+ 
+    g_return_if_fail(GVIR_IS_DOMAIN(dom));
+    g_return_if_fail(GVIR_CONFIG_IS_DOMAIN (conf));
+    g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable));
+
+    xml = gvir_config_object_to_xml(GVIR_CONFIG_OBJECT(conf));
+
+    data = g_slice_new0(DomainSaveToFileData);
+    data->filename = g_strdup(filename);
+    data->custom_xml = g_strdup(xml);
+    data->flags = flags;
+
+    res = g_simple_async_result_new(G_OBJECT(dom),
+                                    callback,
+                                    user_data,
+                                    gvir_domain_save_to_file_async);
+    g_simple_async_result_set_op_res_gpointer(res, data, (GDestroyNotify)domain_save_to_file_data_free);
+
+    g_simple_async_result_run_in_thread(res,
+                                        gvir_domain_save_to_file_helper,
+                                        G_PRIORITY_DEFAULT,
+                                        cancellable);
+   
+    g_object_unref(res);
+}
+
+/**
+ * gvir_domain_save_to_file_finish:
+ * @dom: the domain to save
+ * @result: (transfer none): async method result
+ * @err: Place-holder for possible errors
+ *
+ * Finishes the operation started by #gvir_domain_save_to_file_async.
+ *
+ * Returns: TRUE if domain was saved successfully, FALSE otherwise.
+ */
+gboolean gvir_domain_save_to_file_finish(GVirDomain *dom,
+                                         GAsyncResult *result,
+                                         GError **err)
+{
+    g_return_val_if_fail(GVIR_IS_DOMAIN(dom), FALSE);
+    g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(dom), gvir_domain_save_to_file_async), FALSE);
+    g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+
+    if (g_simple_async_result_propagate_error(G_SIMPLE_ASYNC_RESULT(result), err))
+        return FALSE;
+
+    return TRUE;
+} 
+                     
+/**
  * gvir_domain_get_config:
  * @dom: the domain
  * @flags:  the flags
diff --git a/libvirt-gobject/libvirt-gobject-domain.h b/libvirt-gobject/libvirt-gobject-domain.h
index 87b94f4..49516a7 100644
--- a/libvirt-gobject/libvirt-gobject-domain.h
+++ b/libvirt-gobject/libvirt-gobject-domain.h
@@ -65,7 +65,7 @@ struct _GVirDomainClass
     void (*resumed)(GVirDomain *dom);
     void (*updated)(GVirDomain *dom);
     void (*suspended)(GVirDomain *dom);
-
+    
     gpointer padding[20];
 };
 
@@ -148,6 +148,24 @@ gboolean gvir_domain_reboot(GVirDomain *dom,
                             guint flags,
                             GError **err);
 
+void gvir_domain_save_to_file_async (GVirDomain *dom,
+                                     gchar *filename,
+                                     GVirConfigDomain *conf,
+                                     guint flags,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data);
+
+gboolean gvir_domain_save_to_file_finish(GVirDomain *dom,
+                                         GAsyncResult *result,
+                                         GError **err);
+
+gboolean gvir_domain_save_to_file(GVirDomain *dom,
+                                  gchar *filename,
+                                  GVirConfigDomain *conf,
+                                  guint flags,
+                                  GError **err);
+
 GVirDomainInfo *gvir_domain_get_info(GVirDomain *dom,
                                      GError **err);
 void gvir_domain_get_info_async(GVirDomain *dom,
diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym
index 94e441a..54a093a 100644
--- a/libvirt-gobject/libvirt-gobject.sym
+++ b/libvirt-gobject/libvirt-gobject.sym
@@ -75,6 +75,9 @@ LIBVIRT_GOBJECT_0.0.8 {
 	gvir_domain_get_persistent;
 	gvir_domain_get_saved;
 	gvir_domain_screenshot;
+	gvir_domain_save_to_file;
+	gvir_domain_save_to_file_async;
+	gvir_domain_save_to_file_finish;
 
 	gvir_domain_snapshot_get_type;
 	gvir_domain_snapshot_handle_get_type;
-- 
1.7.10.4
                    
                  
                  
                          
                            
                            2
                            
                          
                          
                            
                            1