[libvirt] [PATCH 1/5] Fix a typo in hostdev docs

It's: <address bus='0x06' slot='0x02' function='0x0'/> not: <address>bus='0x06' slot='0x02' function='0x0'</address> Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- docs/formatdomain.html | 2 +- docs/formatdomain.html.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/formatdomain.html b/docs/formatdomain.html index 17384b3..17dc0cd 100644 --- a/docs/formatdomain.html +++ b/docs/formatdomain.html @@ -485,7 +485,7 @@ ... <hostdev mode='subsystem' type='pci'> <source> - <address>bus='0x06' slot='0x02' function='0x0'</address> + <address bus='0x06' slot='0x02' function='0x0'/> </source> </hostdev> ...</pre> diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index c1e6a16..ee32354 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -397,7 +397,7 @@ ... <hostdev mode='subsystem' type='pci'> <source> - <address>bus='0x06' slot='0x02' function='0x0'</address> + <address bus='0x06' slot='0x02' function='0x0'/> </source> </hostdev> ...</pre> -- 1.6.0.6

Add new functions to allow parsing integers with base 16 This will be used to e.g. parse PCI vendor IDs. Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- src/xml.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++------------- src/xml.h | 8 ++++ 2 files changed, 96 insertions(+), 24 deletions(-) diff --git a/src/xml.c b/src/xml.c index 9c27a10..edfdc17 100644 --- a/src/xml.c +++ b/src/xml.c @@ -116,23 +116,12 @@ virXPathNumber(virConnectPtr conn, return (0); } -/** - * virXPathLong: - * @xpath: the XPath string to evaluate - * @ctxt: an XPath context - * @value: the returned long value - * - * Convenience function to evaluate an XPath number - * - * Returns 0 in case of success in which case @value is set, - * or -1 if the XPath evaluation failed or -2 if the - * value doesn't have a long format. - */ -int -virXPathLong(virConnectPtr conn, - const char *xpath, - xmlXPathContextPtr ctxt, - long *value) +static int +virXPathLongBase(virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + int base, + long *value) { xmlXPathObjectPtr obj; xmlNodePtr relnode; @@ -150,7 +139,7 @@ virXPathLong(virConnectPtr conn, char *conv = NULL; long val; - val = strtol((const char *) obj->stringval, &conv, 10); + val = strtol((const char *) obj->stringval, &conv, base); if (conv == (const char *) obj->stringval) { ret = -2; } else { @@ -172,7 +161,7 @@ virXPathLong(virConnectPtr conn, } /** - * virXPathULong: + * virXPathLong: * @xpath: the XPath string to evaluate * @ctxt: an XPath context * @value: the returned long value @@ -184,10 +173,42 @@ virXPathLong(virConnectPtr conn, * value doesn't have a long format. */ int -virXPathULong(virConnectPtr conn, - const char *xpath, - xmlXPathContextPtr ctxt, - unsigned long *value) +virXPathLong(virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + long *value) +{ + return virXPathLongBase(conn, xpath, ctxt, 10, value); +} + +/** + * virXPathLongHex: + * @xpath: the XPath string to evaluate + * @ctxt: an XPath context + * @value: the returned long value + * + * Convenience function to evaluate an XPath number + * according to a base of 16 + * + * Returns 0 in case of success in which case @value is set, + * or -1 if the XPath evaluation failed or -2 if the + * value doesn't have a long format. + */ +int +virXPathLongHex(virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + long *value) +{ + return virXPathLongBase(conn, xpath, ctxt, 16, value); +} + +static int +virXPathULongBase(virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + int base, + unsigned long *value) { xmlXPathObjectPtr obj; xmlNodePtr relnode; @@ -205,7 +226,7 @@ virXPathULong(virConnectPtr conn, char *conv = NULL; long val; - val = strtoul((const char *) obj->stringval, &conv, 10); + val = strtoul((const char *) obj->stringval, &conv, base); if (conv == (const char *) obj->stringval) { ret = -2; } else { @@ -226,6 +247,49 @@ virXPathULong(virConnectPtr conn, return (ret); } +/** + * virXPathULong: + * @xpath: the XPath string to evaluate + * @ctxt: an XPath context + * @value: the returned long value + * + * Convenience function to evaluate an XPath number + * + * Returns 0 in case of success in which case @value is set, + * or -1 if the XPath evaluation failed or -2 if the + * value doesn't have a long format. + */ +int +virXPathULong(virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + unsigned long *value) +{ + return virXPathULongBase(conn, xpath, ctxt, 10, value); +} + +/** + * virXPathUHex: + * @xpath: the XPath string to evaluate + * @ctxt: an XPath context + * @value: the returned long value + * + * Convenience function to evaluate an XPath number + * according to base of 16 + * + * Returns 0 in case of success in which case @value is set, + * or -1 if the XPath evaluation failed or -2 if the + * value doesn't have a long format. + */ +int +virXPathULongHex(virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + unsigned long *value) +{ + return virXPathULongBase(conn, xpath, ctxt, 16, value); +} + char * virXMLPropString(xmlNodePtr node, const char *name) diff --git a/src/xml.h b/src/xml.h index da9d3b5..3754af2 100644 --- a/src/xml.h +++ b/src/xml.h @@ -29,6 +29,14 @@ int virXPathULong (virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt, unsigned long *value); +int virXPathLongHex (virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + long *value); +int virXPathULongHex(virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + unsigned long *value); xmlNodePtr virXPathNode (virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt); -- 1.6.0.6

Add a variant of virXPathULong() which can handle long longs. Needed for parsing storage device capacities. Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- src/xml.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/xml.h | 4 ++++ 2 files changed, 59 insertions(+), 0 deletions(-) diff --git a/src/xml.c b/src/xml.c index edfdc17..a4465b2 100644 --- a/src/xml.c +++ b/src/xml.c @@ -290,6 +290,61 @@ virXPathULongHex(virConnectPtr conn, return virXPathULongBase(conn, xpath, ctxt, 16, value); } +/** + * virXPathULongLong: + * @xpath: the XPath string to evaluate + * @ctxt: an XPath context + * @value: the returned long long value + * + * Convenience function to evaluate an XPath number + * + * Returns 0 in case of success in which case @value is set, + * or -1 if the XPath evaluation failed or -2 if the + * value doesn't have a long format. + */ +int +virXPathULongLong(virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + unsigned long long *value) +{ + xmlXPathObjectPtr obj; + xmlNodePtr relnode; + int ret = 0; + + if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { + virXMLError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid parameter to virXPathULong()")); + return (-1); + } + relnode = ctxt->node; + obj = xmlXPathEval(BAD_CAST xpath, ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + char *conv = NULL; + unsigned long long val; + + val = strtoull((const char *) obj->stringval, &conv, 10); + if (conv == (const char *) obj->stringval) { + ret = -2; + } else { + *value = val; + } + } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) && + (!(isnan(obj->floatval)))) { + *value = (unsigned long long) obj->floatval; + if (*value != obj->floatval) { + ret = -2; + } + } else { + ret = -1; + } + + xmlXPathFreeObject(obj); + ctxt->node = relnode; + return (ret); +} + char * virXMLPropString(xmlNodePtr node, const char *name) diff --git a/src/xml.h b/src/xml.h index 3754af2..34b0f10 100644 --- a/src/xml.h +++ b/src/xml.h @@ -29,6 +29,10 @@ int virXPathULong (virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt, unsigned long *value); +int virXPathULongLong(virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + unsigned long long *value); int virXPathLongHex (virConnectPtr conn, const char *xpath, xmlXPathContextPtr ctxt, -- 1.6.0.6

Add support for parsing node device XML descriptions. This will be used by PCI passthrough related functions to obtain the PCI device address for a given node device. Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- src/libvirt_private.syms | 1 + src/node_device_conf.c | 687 ++++++++++++++++++++++++++++++++++++++++++++++ src/node_device_conf.h | 3 +- 3 files changed, 690 insertions(+), 1 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 9e9b3e5..fdda478 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -223,6 +223,7 @@ virNodeDeviceObjListFree; virNodeDeviceDefFree; virNodeDevCapsDefFree; virNodeDeviceDefFormat; +virNodeDeviceDefParseString; virNodeDeviceObjLock; virNodeDeviceObjUnlock; virNodeDeviceAssignDef; diff --git a/src/node_device_conf.c b/src/node_device_conf.c index af2f9a3..6e04112 100644 --- a/src/node_device_conf.c +++ b/src/node_device_conf.c @@ -27,6 +27,7 @@ #include <errno.h> #include "virterror_internal.h" +#include "datatypes.h" #include "memory.h" #include "node_device_conf.h" @@ -367,6 +368,692 @@ char *virNodeDeviceDefFormat(virConnectPtr conn, return NULL; } +static int +virNodeDevCapsDefParseULong(virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + unsigned *value, + virNodeDeviceDefPtr def, + const char *missing_error_fmt, + const char *invalid_error_fmt) +{ + int ret; + unsigned long val; + + ret = virXPathULong(conn, xpath, ctxt, &val); + if (ret < 0) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + ret == -1 ? missing_error_fmt : invalid_error_fmt, + def->name); + return -1; + } + + *value = val; + return 0; +} + +static int +virNodeDevCapsDefParseULongLong(virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + unsigned long long *value, + virNodeDeviceDefPtr def, + const char *missing_error_fmt, + const char *invalid_error_fmt) +{ + int ret; + unsigned long long val; + + ret = virXPathULongLong(conn, xpath, ctxt, &val); + if (ret < 0) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + ret == -1 ? missing_error_fmt : invalid_error_fmt, + def->name); + return -1; + } + + *value = val; + return 0; +} + +static int +virNodeDevCapStorageParseXML(virConnectPtr conn, + xmlXPathContextPtr ctxt, + virNodeDeviceDefPtr def, + xmlNodePtr node, + union _virNodeDevCapData *data) +{ + xmlNodePtr orignode, *nodes = NULL; + int i, n, ret = -1; + unsigned long long val; + + orignode = ctxt->node; + ctxt->node = node; + + data->storage.block = virXPathString(conn, "string(./block[1])", ctxt); + if (!data->storage.block) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("no block device path supplied for '%s'"), + def->name); + goto out; + } + + data->storage.bus = virXPathString(conn, "string(./bus[1])", ctxt); + data->storage.drive_type = virXPathString(conn, "string(./drive_type[1])", ctxt); + data->storage.model = virXPathString(conn, "string(./model[1])", ctxt); + data->storage.vendor = virXPathString(conn, "string(./vendor[1])", ctxt); + + if ((n = virXPathNodeSet(conn, "./capability", ctxt, &nodes)) < 0) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("error parsing storage capabilities for '%s'"), + def->name); + goto out; + } + + for (i = 0 ; i < n ; i++) { + char *type = virXMLPropString(nodes[i], "type"); + + if (!type) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("missing storage capability type for '%s'"), + def->name); + goto out; + } + + if (STREQ(type, "hotpluggable")) + data->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE; + else if (STREQ(type, "removable")) { + xmlNodePtr orignode2; + + data->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE; + + orignode2 = ctxt->node; + ctxt->node = nodes[i]; + + if (virXPathBoolean(conn, "count(./media_available[. = '1']) > 0", ctxt)) + data->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE; + + val = 0; + if (virNodeDevCapsDefParseULongLong(conn, "number(./media_size[1])", ctxt, &val, def, + _("no removable media size supplied for '%s'"), + _("invalid removable media size supplied for '%s'")) < 0) { + ctxt->node = orignode2; + VIR_FREE(type); + goto out; + } + data->storage.removable_media_size = val; + + ctxt->node = orignode2; + } else { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unknown storage capability type '%s' for '%s'"), + type, def->name); + VIR_FREE(type); + goto out; + } + + VIR_FREE(type); + } + + if (!(data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_REMOVABLE)) { + val = 0; + if (virNodeDevCapsDefParseULongLong(conn, "number(./size[1])", ctxt, &val, def, + _("no size supplied for '%s'"), + _("invalid size supplied for '%s'")) < 0) + goto out; + data->storage.size = val; + } + + ret = 0; +out: + VIR_FREE(nodes); + ctxt->node = orignode; + return ret; +} + +static int +virNodeDevCapScsiParseXML(virConnectPtr conn, + xmlXPathContextPtr ctxt, + virNodeDeviceDefPtr def, + xmlNodePtr node, + union _virNodeDevCapData *data) +{ + xmlNodePtr orignode; + int ret = -1; + + orignode = ctxt->node; + ctxt->node = node; + + if (virNodeDevCapsDefParseULong(conn, "number(./host[1])", ctxt, + &data->scsi.host, def, + _("no SCSI host ID supplied for '%s'"), + _("invalid SCSI host ID supplied for '%s'")) < 0) + goto out; + + if (virNodeDevCapsDefParseULong(conn, "number(./bus[1])", ctxt, + &data->scsi.bus, def, + _("no SCSI bus ID supplied for '%s'"), + _("invalid SCSI bus ID supplied for '%s'")) < 0) + goto out; + + if (virNodeDevCapsDefParseULong(conn, "number(./target[1])", ctxt, + &data->scsi.target, def, + _("no SCSI target ID supplied for '%s'"), + _("invalid SCSI target ID supplied for '%s'")) < 0) + goto out; + + if (virNodeDevCapsDefParseULong(conn, "number(./lun[1])", ctxt, + &data->scsi.lun, def, + _("no SCSI LUN ID supplied for '%s'"), + _("invalid SCSI LUN ID supplied for '%s'")) < 0) + goto out; + + data->scsi.type = virXPathString(conn, "string(./type[1])", ctxt); + + ret = 0; +out: + ctxt->node = orignode; + return ret; +} + +static int +virNodeDevCapScsiHostParseXML(virConnectPtr conn, + xmlXPathContextPtr ctxt, + virNodeDeviceDefPtr def, + xmlNodePtr node, + union _virNodeDevCapData *data) +{ + xmlNodePtr orignode; + int ret = -1; + + orignode = ctxt->node; + ctxt->node = node; + + if (virNodeDevCapsDefParseULong(conn, "number(./host[1])", ctxt, + &data->scsi_host.host, def, + _("no SCSI host ID supplied for '%s'"), + _("invalid SCSI host ID supplied for '%s'")) < 0) + goto out; + + ret = 0; +out: + ctxt->node = orignode; + return ret; +} + +static int +virNodeDevCapNetParseXML(virConnectPtr conn, + xmlXPathContextPtr ctxt, + virNodeDeviceDefPtr def, + xmlNodePtr node, + union _virNodeDevCapData *data) +{ + xmlNodePtr orignode; + int ret = -1; + char *tmp; + + orignode = ctxt->node; + ctxt->node = node; + + data->net.ifname = virXPathString(conn, "string(./interface[1])", ctxt); + if (!data->net.ifname) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("no network interface supplied for '%s'"), + def->name); + goto out; + } + + data->net.address = virXPathString(conn, "string(./address[1])", ctxt); + + data->net.subtype = VIR_NODE_DEV_CAP_NET_LAST; + + tmp = virXPathString(conn, "string(./capability/@type)", ctxt); + if (tmp) { + int val = virNodeDevNetCapTypeFromString(tmp); + VIR_FREE(tmp); + if (val < 0) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("invalid network type supplied for '%s'"), + def->name); + goto out; + } + data->net.subtype = val; + } + + ret = 0; +out: + ctxt->node = orignode; + return ret; +} + +static int +virNodeDevCapUsbInterfaceParseXML(virConnectPtr conn, + xmlXPathContextPtr ctxt, + virNodeDeviceDefPtr def, + xmlNodePtr node, + union _virNodeDevCapData *data) +{ + xmlNodePtr orignode; + int ret = -1; + + orignode = ctxt->node; + ctxt->node = node; + + if (virNodeDevCapsDefParseULong(conn, "number(./number[1])", ctxt, + &data->usb_if.number, def, + _("no USB interface number supplied for '%s'"), + _("invalid USB interface number supplied for '%s'")) < 0) + goto out; + + if (virNodeDevCapsDefParseULong(conn, "number(./class[1])", ctxt, + &data->usb_if._class, def, + _("no USB interface class supplied for '%s'"), + _("invalid USB interface class supplied for '%s'")) < 0) + goto out; + + if (virNodeDevCapsDefParseULong(conn, "number(./subclass[1])", ctxt, + &data->usb_if.subclass, def, + _("no USB interface subclass supplied for '%s'"), + _("invalid USB interface subclass supplied for '%s'")) < 0) + goto out; + + if (virNodeDevCapsDefParseULong(conn, "number(./protocol[1])", ctxt, + &data->usb_if.protocol, def, + _("no USB interface protocol supplied for '%s'"), + _("invalid USB interface protocol supplied for '%s'")) < 0) + goto out; + + data->usb_if.description = virXPathString(conn, "string(./description[1])", ctxt); + + ret = 0; +out: + ctxt->node = orignode; + return ret; +} + +static int +virNodeDevCapsDefParseHexId(virConnectPtr conn, + const char *xpath, + xmlXPathContextPtr ctxt, + unsigned *value, + virNodeDeviceDefPtr def, + const char *missing_error_fmt, + const char *invalid_error_fmt) +{ + int ret; + unsigned long val; + + ret = virXPathULongHex(conn, xpath, ctxt, &val); + if (ret < 0) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + ret == -1 ? missing_error_fmt : invalid_error_fmt, + def->name); + return -1; + } + + *value = val; + return 0; +} + +static int +virNodeDevCapUsbDevParseXML(virConnectPtr conn, + xmlXPathContextPtr ctxt, + virNodeDeviceDefPtr def, + xmlNodePtr node, + union _virNodeDevCapData *data) +{ + xmlNodePtr orignode; + int ret = -1; + + orignode = ctxt->node; + ctxt->node = node; + + if (virNodeDevCapsDefParseULong(conn, "number(./bus[1])", ctxt, + &data->usb_dev.bus, def, + _("no USB bus number supplied for '%s'"), + _("invalid USB bus number supplied for '%s'")) < 0) + goto out; + + if (virNodeDevCapsDefParseULong(conn, "number(./device[1])", ctxt, + &data->usb_dev.device, def, + _("no USB device number supplied for '%s'"), + _("invalid USB device number supplied for '%s'")) < 0) + goto out; + + if (virNodeDevCapsDefParseHexId(conn, "string(./vendor[1]/@id)", ctxt, + &data->usb_dev.vendor, def, + _("no USB vendor ID supplied for '%s'"), + _("invalid USB vendor ID supplied for '%s'")) < 0) + goto out; + + if (virNodeDevCapsDefParseHexId(conn, "string(./product[1]/@id)", ctxt, + &data->usb_dev.product, def, + _("no USB product ID supplied for '%s'"), + _("invalid USB product ID supplied for '%s'")) < 0) + goto out; + + data->usb_dev.vendor_name = virXPathString(conn, "string(./vendor[1])", ctxt); + data->usb_dev.product_name = virXPathString(conn, "string(./product[1])", ctxt); + + ret = 0; +out: + ctxt->node = orignode; + return ret; +} + +static int +virNodeDevCapPciDevParseXML(virConnectPtr conn, + xmlXPathContextPtr ctxt, + virNodeDeviceDefPtr def, + xmlNodePtr node, + union _virNodeDevCapData *data) +{ + xmlNodePtr orignode; + int ret = -1; + + orignode = ctxt->node; + ctxt->node = node; + + if (virNodeDevCapsDefParseULong(conn, "number(./domain[1])", ctxt, + &data->pci_dev.domain, def, + _("no PCI domain ID supplied for '%s'"), + _("invalid PCI domain ID supplied for '%s'")) < 0) + goto out; + + if (virNodeDevCapsDefParseULong(conn, "number(./bus[1])", ctxt, + &data->pci_dev.bus, def, + _("no PCI bus ID supplied for '%s'"), + _("invalid PCI bus ID supplied for '%s'")) < 0) + goto out; + + if (virNodeDevCapsDefParseULong(conn, "number(./slot[1])", ctxt, + &data->pci_dev.slot, def, + _("no PCI slot ID supplied for '%s'"), + _("invalid PCI slot ID supplied for '%s'")) < 0) + goto out; + + if (virNodeDevCapsDefParseULong(conn, "number(./function[1])", ctxt, + &data->pci_dev.function, def, + _("no PCI function ID supplied for '%s'"), + _("invalid PCI function ID supplied for '%s'")) < 0) + goto out; + + if (virNodeDevCapsDefParseHexId(conn, "string(./vendor[1]/@id)", ctxt, + &data->pci_dev.vendor, def, + _("no PCI vendor ID supplied for '%s'"), + _("invalid PCI vendor ID supplied for '%s'")) < 0) + goto out; + + if (virNodeDevCapsDefParseHexId(conn, "string(./product[1]/@id)", ctxt, + &data->pci_dev.product, def, + _("no PCI product ID supplied for '%s'"), + _("invalid PCI product ID supplied for '%s'")) < 0) + goto out; + + data->pci_dev.vendor_name = virXPathString(conn, "string(./vendor[1])", ctxt); + data->pci_dev.product_name = virXPathString(conn, "string(./product[1])", ctxt); + + ret = 0; +out: + ctxt->node = orignode; + return ret; +} + +static int +virNodeDevCapSystemParseXML(virConnectPtr conn, + xmlXPathContextPtr ctxt, + virNodeDeviceDefPtr def, + xmlNodePtr node, + union _virNodeDevCapData *data) +{ + xmlNodePtr orignode; + int ret = -1; + char *tmp; + + orignode = ctxt->node; + ctxt->node = node; + + data->system.product_name = virXPathString(conn, "string(./product[1])", ctxt); + + data->system.hardware.vendor_name = virXPathString(conn, "string(./hardware/vendor[1])", ctxt); + data->system.hardware.version = virXPathString(conn, "string(./hardware/version[1])", ctxt); + data->system.hardware.serial = virXPathString(conn, "string(./hardware/serial[1])", ctxt); + + tmp = virXPathString(conn, "string(./hardware/uuid[1])", ctxt); + if (!tmp) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("no system UUID supplied for '%s'"), def->name); + goto out; + } + + if (virUUIDParse(tmp, data->system.hardware.uuid) < 0) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("malformed uuid element for '%s'"), def->name); + VIR_FREE(tmp); + goto out; + } + VIR_FREE(tmp); + + data->system.firmware.vendor_name = virXPathString(conn, "string(./firmware/vendor[1])", ctxt); + data->system.firmware.version = virXPathString(conn, "string(./firmware/version[1])", ctxt); + data->system.firmware.release_date = virXPathString(conn, "string(./firmware/release_date[1])", ctxt); + + ret = 0; +out: + ctxt->node = orignode; + return ret; +} + +static virNodeDevCapsDefPtr +virNodeDevCapsDefParseXML(virConnectPtr conn, + xmlXPathContextPtr ctxt, + virNodeDeviceDefPtr def, + xmlNodePtr node) +{ + virNodeDevCapsDefPtr caps; + char *tmp; + int val, ret; + + if (VIR_ALLOC(caps) < 0) { + virReportOOMError(conn); + return NULL; + } + + tmp = virXMLPropString(node, "type"); + if (!tmp) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("missing capability type")); + goto error; + } + + if ((val = virNodeDevCapTypeFromString(tmp)) < 0) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unknown capability type '%s'"), tmp); + VIR_FREE(tmp); + goto error; + } + caps->type = val; + VIR_FREE(tmp); + + switch (caps->type) { + case VIR_NODE_DEV_CAP_SYSTEM: + ret = virNodeDevCapSystemParseXML(conn, ctxt, def, node, &caps->data); + break; + case VIR_NODE_DEV_CAP_PCI_DEV: + ret = virNodeDevCapPciDevParseXML(conn, ctxt, def, node, &caps->data); + break; + case VIR_NODE_DEV_CAP_USB_DEV: + ret = virNodeDevCapUsbDevParseXML(conn, ctxt, def, node, &caps->data); + break; + case VIR_NODE_DEV_CAP_USB_INTERFACE: + ret = virNodeDevCapUsbInterfaceParseXML(conn, ctxt, def, node, &caps->data); + break; + case VIR_NODE_DEV_CAP_NET: + ret = virNodeDevCapNetParseXML(conn, ctxt, def, node, &caps->data); + break; + case VIR_NODE_DEV_CAP_SCSI_HOST: + ret = virNodeDevCapScsiHostParseXML(conn, ctxt, def, node, &caps->data); + break; + case VIR_NODE_DEV_CAP_SCSI: + ret = virNodeDevCapScsiParseXML(conn, ctxt, def, node, &caps->data); + break; + case VIR_NODE_DEV_CAP_STORAGE: + ret = virNodeDevCapStorageParseXML(conn, ctxt, def, node, &caps->data); + break; + default: + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unknown capability type '%d' for '%s'"), + caps->type, def->name); + ret = -1; + break; + } + + if (ret < 0) + goto error; + return caps; + +error: + virNodeDevCapsDefFree(caps); + return NULL; +} + +static virNodeDeviceDefPtr +virNodeDeviceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt) +{ + virNodeDeviceDefPtr def; + virNodeDevCapsDefPtr *next_cap; + xmlNodePtr *nodes; + int n, i; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(conn); + return NULL; + } + + /* Extract device name */ + def->name = virXPathString(conn, "string(./name[1])", ctxt); + if (!def->name) { + virNodeDeviceReportError(conn, VIR_ERR_NO_NAME, NULL); + goto error; + } + + /* Extract device parent, if any */ + def->parent = virXPathString(conn, "string(./parent[1])", ctxt); + + /* Parse device capabilities */ + nodes = NULL; + if ((n = virXPathNodeSet(conn, "./capability", ctxt, &nodes)) <= 0) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("no device capabilities for '%s'"), + def->name); + goto error; + } + + next_cap = &def->caps; + for (i = 0 ; i < n ; i++) { + *next_cap = virNodeDevCapsDefParseXML(conn, ctxt, def, nodes[i]); + if (!*next_cap) { + VIR_FREE(nodes); + goto error; + } + + next_cap = &(*next_cap)->next; + } + VIR_FREE(nodes); + + return def; + + error: + virNodeDeviceDefFree(def); + return NULL; +} + +static virNodeDeviceDefPtr +virNodeDeviceDefParseNode(virConnectPtr conn, xmlDocPtr xml, xmlNodePtr root) +{ + xmlXPathContextPtr ctxt = NULL; + virNodeDeviceDefPtr def = NULL; + + if (!xmlStrEqual(root->name, BAD_CAST "device")) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("incorrect root element")); + return NULL; + } + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + virReportOOMError(conn); + goto cleanup; + } + + ctxt->node = root; + def = virNodeDeviceDefParseXML(conn, ctxt); + +cleanup: + xmlXPathFreeContext(ctxt); + return def; +} + +/* Called from SAX on parsing errors in the XML. */ +static void +catchXMLError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + + if (ctxt) { + virConnectPtr conn = ctxt->_private; + + if (virGetLastError() == NULL && + ctxt->lastError.level == XML_ERR_FATAL && + ctxt->lastError.message != NULL) { + virNodeDeviceReportError(conn, VIR_ERR_XML_DETAIL, + _("at line %d: %s"), + ctxt->lastError.line, + ctxt->lastError.message); + } + } +} + +virNodeDeviceDefPtr +virNodeDeviceDefParseString(virConnectPtr conn, const char *str) +{ + xmlParserCtxtPtr pctxt; + xmlDocPtr xml = NULL; + xmlNodePtr root; + virNodeDeviceDefPtr def = NULL; + + /* Set up a parser context so we can catch the details of XML errors. */ + pctxt = xmlNewParserCtxt (); + if (!pctxt || !pctxt->sax) + goto cleanup; + pctxt->sax->error = catchXMLError; + pctxt->_private = conn; + + if (conn) virResetError (&conn->err); + xml = xmlCtxtReadDoc(pctxt, BAD_CAST str, "device.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOWARNING); + if (!xml) { + if (conn && conn->err.code == VIR_ERR_NONE) + virNodeDeviceReportError(conn, VIR_ERR_XML_ERROR, + "%s", _("failed to parse xml document")); + goto cleanup; + } + + if ((root = xmlDocGetRootElement(xml)) == NULL) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("missing root element")); + goto cleanup; + } + + def = virNodeDeviceDefParseNode(conn, xml, root); + +cleanup: + xmlFreeParserCtxt(pctxt); + xmlFreeDoc(xml); + return def; +} + void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps) { union _virNodeDevCapData *data = &caps->data; diff --git a/src/node_device_conf.h b/src/node_device_conf.h index 2024755..26e5558 100644 --- a/src/node_device_conf.h +++ b/src/node_device_conf.h @@ -184,7 +184,8 @@ void virNodeDeviceObjRemove(virNodeDeviceObjListPtr devs, char *virNodeDeviceDefFormat(virConnectPtr conn, const virNodeDeviceDefPtr def); -// TODO: virNodeDeviceDefParseString/File/Node for virNodeDeviceCreate +virNodeDeviceDefPtr virNodeDeviceDefParseString(virConnectPtr conn, + const char *str); void virNodeDeviceDefFree(virNodeDeviceDefPtr def); -- 1.6.0.6

Add a test to check node device XML parsing by first parsing the XML, then re-formatting as XML and finally comparing the resulting XML to the original XML. Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- tests/.cvsignore | 1 + tests/.gitignore | 1 + tests/Makefile.am | 9 ++ tests/nodedevschemadata/DVD_GCC_4247N.xml | 2 - tests/nodedevschemadata/computer.xml | 2 - tests/nodedevschemadata/net_00_13_02_b9_f9_d3.xml | 2 - tests/nodedevschemadata/net_00_15_58_2f_e9_55.xml | 2 - tests/nodedevschemadata/pci_1002_71c4.xml | 2 - .../nodedevschemadata/pci_8086_27c5_scsi_host.xml | 2 - .../pci_8086_27c5_scsi_host_0.xml | 2 - .../pci_8086_27c5_scsi_host_scsi_device_lun0.xml | 2 - .../pci_8086_27c5_scsi_host_scsi_host.xml | 2 - ..._serial_SATA_HTS721010G9SA00_MPCZ12Y0GNGWSE.xml | 2 - .../usb_device_1d6b_1_0000_00_1d_0.xml | 2 - .../usb_device_1d6b_1_0000_00_1d_0_if0.xml | 2 - tests/nodedevxml2xmltest.c | 97 ++++++++++++++++++++ 16 files changed, 108 insertions(+), 24 deletions(-) create mode 100644 tests/nodedevxml2xmltest.c diff --git a/tests/.cvsignore b/tests/.cvsignore index 679cc20..9d809c9 100644 --- a/tests/.cvsignore +++ b/tests/.cvsignore @@ -11,6 +11,7 @@ xmconfigtest xencapstest qemuxml2xmltest qemuxml2argvtest +nodedevxml2xmltest nodeinfotest statstest qparamtest diff --git a/tests/.gitignore b/tests/.gitignore index 679cc20..9d809c9 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -11,6 +11,7 @@ xmconfigtest xencapstest qemuxml2xmltest qemuxml2argvtest +nodedevxml2xmltest nodeinfotest statstest qparamtest diff --git a/tests/Makefile.am b/tests/Makefile.am index 877884f..bec4f60 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -64,6 +64,8 @@ if WITH_QEMU noinst_PROGRAMS += qemuxml2argvtest qemuxml2xmltest endif +noinst_PROGRAMS += nodedevxml2xmltest + test_scripts = \ capabilityschematest \ networkschematest \ @@ -110,6 +112,8 @@ if WITH_QEMU TESTS += qemuxml2argvtest qemuxml2xmltest endif +TESTS += nodedevxml2xmltest + path_add = $$abs_top_builddir/src$(PATH_SEPARATOR)$$abs_top_builddir/qemud # NB, automake < 1.10 does not provide the real @@ -175,6 +179,11 @@ else EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c testutilsqemu.c testutilsqemu.h endif +nodedevxml2xmltest_SOURCES = \ + nodedevxml2xmltest.c \ + testutils.c testutils.h +nodedevxml2xmltest_LDADD = ../src/libvirt_driver_qemu.la $(LDADDS) + virshtest_SOURCES = \ virshtest.c \ testutils.c testutils.h diff --git a/tests/nodedevschemadata/DVD_GCC_4247N.xml b/tests/nodedevschemadata/DVD_GCC_4247N.xml index d81e983..aed787a 100644 --- a/tests/nodedevschemadata/DVD_GCC_4247N.xml +++ b/tests/nodedevschemadata/DVD_GCC_4247N.xml @@ -13,5 +13,3 @@ </capability> </capability> </device> - - diff --git a/tests/nodedevschemadata/computer.xml b/tests/nodedevschemadata/computer.xml index 4172c0c..4e4b918 100644 --- a/tests/nodedevschemadata/computer.xml +++ b/tests/nodedevschemadata/computer.xml @@ -14,5 +14,3 @@ </firmware> </capability> </device> - - diff --git a/tests/nodedevschemadata/net_00_13_02_b9_f9_d3.xml b/tests/nodedevschemadata/net_00_13_02_b9_f9_d3.xml index 9a09246..970ccca 100644 --- a/tests/nodedevschemadata/net_00_13_02_b9_f9_d3.xml +++ b/tests/nodedevschemadata/net_00_13_02_b9_f9_d3.xml @@ -7,5 +7,3 @@ <capability type='80211'/> </capability> </device> - - diff --git a/tests/nodedevschemadata/net_00_15_58_2f_e9_55.xml b/tests/nodedevschemadata/net_00_15_58_2f_e9_55.xml index b13215c..741c959 100644 --- a/tests/nodedevschemadata/net_00_15_58_2f_e9_55.xml +++ b/tests/nodedevschemadata/net_00_15_58_2f_e9_55.xml @@ -7,5 +7,3 @@ <capability type='80203'/> </capability> </device> - - diff --git a/tests/nodedevschemadata/pci_1002_71c4.xml b/tests/nodedevschemadata/pci_1002_71c4.xml index 305ca32..6de09c1 100644 --- a/tests/nodedevschemadata/pci_1002_71c4.xml +++ b/tests/nodedevschemadata/pci_1002_71c4.xml @@ -10,5 +10,3 @@ <vendor id='0x1002'>ATI Technologies Inc</vendor> </capability> </device> - - diff --git a/tests/nodedevschemadata/pci_8086_27c5_scsi_host.xml b/tests/nodedevschemadata/pci_8086_27c5_scsi_host.xml index 47937f1..3b377a3 100644 --- a/tests/nodedevschemadata/pci_8086_27c5_scsi_host.xml +++ b/tests/nodedevschemadata/pci_8086_27c5_scsi_host.xml @@ -5,5 +5,3 @@ <host>0</host> </capability> </device> - - diff --git a/tests/nodedevschemadata/pci_8086_27c5_scsi_host_0.xml b/tests/nodedevschemadata/pci_8086_27c5_scsi_host_0.xml index b58ee73..a160167 100644 --- a/tests/nodedevschemadata/pci_8086_27c5_scsi_host_0.xml +++ b/tests/nodedevschemadata/pci_8086_27c5_scsi_host_0.xml @@ -5,5 +5,3 @@ <host>1</host> </capability> </device> - - diff --git a/tests/nodedevschemadata/pci_8086_27c5_scsi_host_scsi_device_lun0.xml b/tests/nodedevschemadata/pci_8086_27c5_scsi_host_scsi_device_lun0.xml index 09887a8..5c2dff7 100644 --- a/tests/nodedevschemadata/pci_8086_27c5_scsi_host_scsi_device_lun0.xml +++ b/tests/nodedevschemadata/pci_8086_27c5_scsi_host_scsi_device_lun0.xml @@ -9,5 +9,3 @@ <type>disk</type> </capability> </device> - - diff --git a/tests/nodedevschemadata/pci_8086_27c5_scsi_host_scsi_host.xml b/tests/nodedevschemadata/pci_8086_27c5_scsi_host_scsi_host.xml index 18f9500..8ffb0a5 100644 --- a/tests/nodedevschemadata/pci_8086_27c5_scsi_host_scsi_host.xml +++ b/tests/nodedevschemadata/pci_8086_27c5_scsi_host_scsi_host.xml @@ -5,5 +5,3 @@ <host>0</host> </capability> </device> - - diff --git a/tests/nodedevschemadata/storage_serial_SATA_HTS721010G9SA00_MPCZ12Y0GNGWSE.xml b/tests/nodedevschemadata/storage_serial_SATA_HTS721010G9SA00_MPCZ12Y0GNGWSE.xml index 43294ac..3595a0b 100644 --- a/tests/nodedevschemadata/storage_serial_SATA_HTS721010G9SA00_MPCZ12Y0GNGWSE.xml +++ b/tests/nodedevschemadata/storage_serial_SATA_HTS721010G9SA00_MPCZ12Y0GNGWSE.xml @@ -10,5 +10,3 @@ <size>100030242816</size> </capability> </device> - - diff --git a/tests/nodedevschemadata/usb_device_1d6b_1_0000_00_1d_0.xml b/tests/nodedevschemadata/usb_device_1d6b_1_0000_00_1d_0.xml index 05999e8..29533e7 100644 --- a/tests/nodedevschemadata/usb_device_1d6b_1_0000_00_1d_0.xml +++ b/tests/nodedevschemadata/usb_device_1d6b_1_0000_00_1d_0.xml @@ -8,5 +8,3 @@ <vendor id='0x1d6b'>Linux Foundation</vendor> </capability> </device> - - diff --git a/tests/nodedevschemadata/usb_device_1d6b_1_0000_00_1d_0_if0.xml b/tests/nodedevschemadata/usb_device_1d6b_1_0000_00_1d_0_if0.xml index bc951ff..9de35c7 100644 --- a/tests/nodedevschemadata/usb_device_1d6b_1_0000_00_1d_0_if0.xml +++ b/tests/nodedevschemadata/usb_device_1d6b_1_0000_00_1d_0_if0.xml @@ -8,5 +8,3 @@ <protocol>0</protocol> </capability> </device> - - diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c new file mode 100644 index 0000000..29cdb9e --- /dev/null +++ b/tests/nodedevxml2xmltest.c @@ -0,0 +1,97 @@ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <sys/types.h> +#include <fcntl.h> + +#include "internal.h" +#include "testutils.h" +#include "node_device_conf.h" +#include "testutilsqemu.h" + +static char *progname; +static char *abs_srcdir; + +#define MAX_FILE 4096 + + +static int testCompareXMLToXMLFiles(const char *xml) { + char xmlData[MAX_FILE]; + char *xmlPtr = &(xmlData[0]); + char *actual = NULL; + int ret = -1; + virNodeDeviceDefPtr dev = NULL; + + if (virtTestLoadFile(xml, &xmlPtr, MAX_FILE) < 0) + goto fail; + + if (!(dev = virNodeDeviceDefParseString(NULL, xmlData))) + goto fail; + + if (!(actual = virNodeDeviceDefFormat(NULL, dev))) + goto fail; + + if (STRNEQ(xmlData, actual)) { + virtTestDifference(stderr, xmlData, actual); + goto fail; + } + + ret = 0; + + fail: + free(actual); + virNodeDeviceDefFree(dev); + return ret; +} + +static int testCompareXMLToXMLHelper(const void *data) { + char xml[PATH_MAX]; + snprintf(xml, PATH_MAX, "%s/nodedevschemadata/%s.xml", + abs_srcdir, (const char*)data); + return testCompareXMLToXMLFiles(xml); +} + + +static int +mymain(int argc, char **argv) +{ + int ret = 0; + char cwd[PATH_MAX]; + + progname = argv[0]; + + if (argc > 1) { + fprintf(stderr, "Usage: %s\n", progname); + return (EXIT_FAILURE); + } + + abs_srcdir = getenv("abs_srcdir"); + if (!abs_srcdir) + abs_srcdir = getcwd(cwd, sizeof(cwd)); + +#define DO_TEST(name) \ + if (virtTestRun("Node device XML-2-XML " name, \ + 1, testCompareXMLToXMLHelper, (name)) < 0) \ + ret = -1 + + DO_TEST("computer"); + DO_TEST("DVD_GCC_4247N"); + DO_TEST("net_00_13_02_b9_f9_d3"); + DO_TEST("net_00_15_58_2f_e9_55"); + DO_TEST("pci_1002_71c4"); + DO_TEST("pci_8086_27c5_scsi_host_0"); + DO_TEST("pci_8086_27c5_scsi_host_scsi_device_lun0"); + DO_TEST("pci_8086_27c5_scsi_host_scsi_host"); + DO_TEST("pci_8086_27c5_scsi_host"); + DO_TEST("storage_serial_SATA_HTS721010G9SA00_MPCZ12Y0GNGWSE"); + DO_TEST("usb_device_1d6b_1_0000_00_1d_0_if0"); + DO_TEST("usb_device_1d6b_1_0000_00_1d_0"); + + return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +VIRT_TEST_MAIN(mymain) -- 1.6.0.6

On Mon, Feb 23, 2009 at 11:28:40AM +0000, Mark McLoughlin wrote:
Add a test to check node device XML parsing by first parsing the XML, then re-formatting as XML and finally comparing the resulting XML to the original XML.
Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- tests/.cvsignore | 1 + tests/.gitignore | 1 + tests/Makefile.am | 9 ++ tests/nodedevschemadata/DVD_GCC_4247N.xml | 2 - tests/nodedevschemadata/computer.xml | 2 - tests/nodedevschemadata/net_00_13_02_b9_f9_d3.xml | 2 - tests/nodedevschemadata/net_00_15_58_2f_e9_55.xml | 2 - tests/nodedevschemadata/pci_1002_71c4.xml | 2 - .../nodedevschemadata/pci_8086_27c5_scsi_host.xml | 2 - .../pci_8086_27c5_scsi_host_0.xml | 2 - .../pci_8086_27c5_scsi_host_scsi_device_lun0.xml | 2 - .../pci_8086_27c5_scsi_host_scsi_host.xml | 2 - ..._serial_SATA_HTS721010G9SA00_MPCZ12Y0GNGWSE.xml | 2 - .../usb_device_1d6b_1_0000_00_1d_0.xml | 2 - .../usb_device_1d6b_1_0000_00_1d_0_if0.xml | 2 - tests/nodedevxml2xmltest.c | 97 ++++++++++++++++++++ 16 files changed, 108 insertions(+), 24 deletions(-) create mode 100644 tests/nodedevxml2xmltest.c
ACK Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Mon, Feb 23, 2009 at 11:28:39AM +0000, Mark McLoughlin wrote:
Add support for parsing node device XML descriptions.
This will be used by PCI passthrough related functions to obtain the PCI device address for a given node device.
Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- src/libvirt_private.syms | 1 + src/node_device_conf.c | 687 ++++++++++++++++++++++++++++++++++++++++++++++ src/node_device_conf.h | 3 +- 3 files changed, 690 insertions(+), 1 deletions(-)
ACK, this would also be useful for the test.c driver, letting us include a pre-defined list of host devices in the XML for the driver setup.
+/* Called from SAX on parsing errors in the XML. */ +static void +catchXMLError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + + if (ctxt) { + virConnectPtr conn = ctxt->_private; + + if (virGetLastError() == NULL && + ctxt->lastError.level == XML_ERR_FATAL && + ctxt->lastError.message != NULL) { + virNodeDeviceReportError(conn, VIR_ERR_XML_DETAIL, + _("at line %d: %s"), + ctxt->lastError.line, + ctxt->lastError.message); + } + } +} + +virNodeDeviceDefPtr +virNodeDeviceDefParseString(virConnectPtr conn, const char *str) +{ + xmlParserCtxtPtr pctxt; + xmlDocPtr xml = NULL; + xmlNodePtr root; + virNodeDeviceDefPtr def = NULL; + + /* Set up a parser context so we can catch the details of XML errors. */ + pctxt = xmlNewParserCtxt (); + if (!pctxt || !pctxt->sax) + goto cleanup; + pctxt->sax->error = catchXMLError; + pctxt->_private = conn; + + if (conn) virResetError (&conn->err); + xml = xmlCtxtReadDoc(pctxt, BAD_CAST str, "device.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOWARNING); + if (!xml) { + if (conn && conn->err.code == VIR_ERR_NONE) + virNodeDeviceReportError(conn, VIR_ERR_XML_ERROR, + "%s", _("failed to parse xml document")); + goto cleanup; + } + + if ((root = xmlDocGetRootElement(xml)) == NULL) { + virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR, + "%s", _("missing root element")); + goto cleanup; + } + + def = virNodeDeviceDefParseNode(conn, xml, root); + +cleanup: + xmlFreeParserCtxt(pctxt); + xmlFreeDoc(xml); + return def; +} +
If someone is feeling bored, I notice we've got quite alot of these top level methods for starting the XML parse across which duplicated code for setting up the XML context. We could usefully define a helper in xml.c to deal with this typedef void * (*virXMLParseHandler)(virConectPtr conn, xmlDocPtr doc, xmlNodePtr node); void * virXMLParseString(virConnectPtr conn, const char *xml, virXMLParseHandler); So this would simplify the top level string parse method to virNodeDevicePtr virNodeDeviceDefParseString(virConnectPtr conn, const char *xml) { return virXMLParseString(conn, xml, virNodeDeviceDefParseNode); } Likewise for the virXMLParseFile method Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Mon, Feb 23, 2009 at 11:28:38AM +0000, Mark McLoughlin wrote:
Add a variant of virXPathULong() which can handle long longs.
Needed for parsing storage device capacities.
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
ACK Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Mon, Feb 23, 2009 at 11:28:37AM +0000, Mark McLoughlin wrote:
Add new functions to allow parsing integers with base 16
This will be used to e.g. parse PCI vendor IDs.
Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- src/xml.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++------------- src/xml.h | 8 ++++ 2 files changed, 96 insertions(+), 24 deletions(-)
ACK Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Mon, Feb 23, 2009 at 11:28:36AM +0000, Mark McLoughlin wrote:
It's:
<address bus='0x06' slot='0x02' function='0x0'/>
not:
<address>bus='0x06' slot='0x02' function='0x0'</address>
ACK Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
participants (2)
-
Daniel P. Berrange
-
Mark McLoughlin