static char *nodeDeviceGetParent(virNodeDevicePtr dev) { virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData; virNodeDeviceObjPtr obj; char *ret = NULL; nodeDeviceLock(driver); obj = virNodeDeviceFindByName(&driver->devs, dev->name); nodeDeviceUnlock(driver); if (!obj) { virNodeDeviceReportError(VIR_ERR_NO_NODE_DEVICE, _("no node device with matching name '%s'"), dev->name); goto cleanup; } if (obj->def->parent) { ret = strdup(obj->def->parent); if (!ret) virReportOOMError(); } else { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no parent for this device")); } cleanup: if (obj) virNodeDeviceObjUnlock(obj); return ret; }
static virNodeDeviceDefPtr virNodeDeviceDefParseXML(xmlXPathContextPtr ctxt, int create) { virNodeDeviceDefPtr def; virNodeDevCapsDefPtr *next_cap; xmlNodePtr *nodes; int n, i; if (VIR_ALLOC(def) < 0) { virReportOOMError(); return NULL; } /* Extract device name */ if (create == EXISTING_DEVICE) { def->name = virXPathString("string(./name[1])", ctxt); if (!def->name) { virNodeDeviceReportError(VIR_ERR_NO_NAME, NULL); goto error; } } else { def->name = strdup("new device"); if (!def->name) { virReportOOMError(); goto error; } } /* Extract device parent, if any */ def->parent = virXPathString("string(./parent[1])", ctxt); /* Parse device capabilities */ nodes = NULL; if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) <= 0) { virNodeDeviceReportError(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(ctxt, def, nodes[i], create); if (!*next_cap) { VIR_FREE(nodes); goto error; } next_cap = &(*next_cap)->next; } VIR_FREE(nodes); return def; error: virNodeDeviceDefFree(def); return NULL; }
/* * Return fc_host dev's WWNN and WWPN */ int virNodeDeviceGetWWNs(virNodeDeviceDefPtr def, char **wwnn, char **wwpn) { virNodeDevCapsDefPtr cap = NULL; int ret = 0; cap = def->caps; while (cap != NULL) { if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST && cap->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) { *wwnn = strdup(cap->data.scsi_host.wwnn); *wwpn = strdup(cap->data.scsi_host.wwpn); break; } cap = cap->next; } if (cap == NULL) { virNodeDeviceReportError(VIR_ERR_NO_SUPPORT, "%s", _("Device is not a fibre channel HBA")); ret = -1; } else if (*wwnn == NULL || *wwpn == NULL) { /* Free the other one, if allocated... */ VIR_FREE(wwnn); VIR_FREE(wwpn); ret = -1; virReportOOMError(); } return ret; }
virNodeDeviceDefPtr virNodeDeviceDefParseNode(xmlDocPtr xml, xmlNodePtr root, int create) { xmlXPathContextPtr ctxt = NULL; virNodeDeviceDefPtr def = NULL; if (!xmlStrEqual(root->name, BAD_CAST "device")) { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("incorrect root element")); return NULL; } ctxt = xmlXPathNewContext(xml); if (ctxt == NULL) { virReportOOMError(); goto cleanup; } ctxt->node = root; def = virNodeDeviceDefParseXML(ctxt, create); cleanup: xmlXPathFreeContext(ctxt); return def; }
static char *nodeDeviceDumpXML(virNodeDevicePtr dev, unsigned int flags ATTRIBUTE_UNUSED) { virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData; virNodeDeviceObjPtr obj; char *ret = NULL; nodeDeviceLock(driver); obj = virNodeDeviceFindByName(&driver->devs, dev->name); nodeDeviceUnlock(driver); if (!obj) { virNodeDeviceReportError(VIR_ERR_NO_NODE_DEVICE, _("no node device with matching name '%s'"), dev->name); goto cleanup; } update_driver_name(obj); update_caps(obj); ret = virNodeDeviceDefFormat(obj->def); cleanup: if (obj) virNodeDeviceObjUnlock(obj); return ret; }
static int virNodeDevCapScsiTargetParseXML(xmlXPathContextPtr ctxt, virNodeDeviceDefPtr def, xmlNodePtr node, union _virNodeDevCapData *data) { xmlNodePtr orignode; int ret = -1; orignode = ctxt->node; ctxt->node = node; data->scsi_target.name = virXPathString("string(./name[1])", ctxt); if (!data->scsi_target.name) { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, _("no target name supplied for '%s'"), def->name); goto out; } ret = 0; out: ctxt->node = orignode; return ret; }
static int nodeDeviceNumOfCaps(virNodeDevicePtr dev) { virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData; virNodeDeviceObjPtr obj; virNodeDevCapsDefPtr caps; int ncaps = 0; int ret = -1; nodeDeviceLock(driver); obj = virNodeDeviceFindByName(&driver->devs, dev->name); nodeDeviceUnlock(driver); if (!obj) { virNodeDeviceReportError(VIR_ERR_NO_NODE_DEVICE, _("no node device with matching name '%s'"), dev->name); goto cleanup; } for (caps = obj->def->caps; caps; caps = caps->next) ++ncaps; ret = ncaps; cleanup: if (obj) virNodeDeviceObjUnlock(obj); return ret; }
static int nodeDeviceDestroy(virNodeDevicePtr dev) { int ret = -1; virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData; virNodeDeviceObjPtr obj = NULL; char *parent_name = NULL, *wwnn = NULL, *wwpn = NULL; int parent_host = -1; nodeDeviceLock(driver); obj = virNodeDeviceFindByName(&driver->devs, dev->name); nodeDeviceUnlock(driver); if (!obj) { virNodeDeviceReportError(VIR_ERR_NO_NODE_DEVICE, NULL); goto out; } if (virNodeDeviceGetWWNs(obj->def, &wwnn, &wwpn) == -1) { goto out; } parent_name = strdup(obj->def->parent); /* virNodeDeviceGetParentHost will cause the device object's lock to be * taken, so we have to dup the parent's name and drop the lock * before calling it. We don't need the reference to the object * any more once we have the parent's name. */ virNodeDeviceObjUnlock(obj); obj = NULL; if (parent_name == NULL) { virReportOOMError(); goto out; } if (virNodeDeviceGetParentHost(&driver->devs, dev->name, parent_name, &parent_host) == -1) { goto out; } if (nodeDeviceVportCreateDelete(parent_host, wwpn, wwnn, VPORT_DELETE) == -1) { goto out; } ret = 0; out: if (obj) virNodeDeviceObjUnlock(obj); VIR_FREE(parent_name); VIR_FREE(wwnn); VIR_FREE(wwpn); return ret; }
/* * Return the NPIV dev's parent device name */ int virNodeDeviceGetParentHost(const virNodeDeviceObjListPtr devs, const char *dev_name, const char *parent_name, int *parent_host) { virNodeDeviceObjPtr parent = NULL; virNodeDevCapsDefPtr cap = NULL; int ret = 0; parent = virNodeDeviceFindByName(devs, parent_name); if (parent == NULL) { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, _("Could not find parent device for '%s'"), dev_name); ret = -1; goto out; } cap = parent->def->caps; while (cap != NULL) { if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST && (cap->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS)) { *parent_host = cap->data.scsi_host.host; break; } cap = cap->next; } if (cap == NULL) { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, _("Parent device %s is not capable " "of vport operations"), parent->def->name); ret = -1; } virNodeDeviceObjUnlock(parent); out: return ret; }
static int virNodeDevCapSystemParseXML(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("string(./product[1])", ctxt); data->system.hardware.vendor_name = virXPathString("string(./hardware/vendor[1])", ctxt); data->system.hardware.version = virXPathString("string(./hardware/version[1])", ctxt); data->system.hardware.serial = virXPathString("string(./hardware/serial[1])", ctxt); tmp = virXPathString("string(./hardware/uuid[1])", ctxt); if (!tmp) { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, _("no system UUID supplied for '%s'"), def->name); goto out; } if (virUUIDParse(tmp, data->system.hardware.uuid) < 0) { virNodeDeviceReportError(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("string(./firmware/vendor[1])", ctxt); data->system.firmware.version = virXPathString("string(./firmware/version[1])", ctxt); data->system.firmware.release_date = virXPathString("string(./firmware/release_date[1])", ctxt); ret = 0; out: ctxt->node = orignode; return ret; }
static int virNodeDevCapNetParseXML(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("string(./interface[1])", ctxt); if (!data->net.ifname) { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, _("no network interface supplied for '%s'"), def->name); goto out; } data->net.address = virXPathString("string(./address[1])", ctxt); data->net.subtype = VIR_NODE_DEV_CAP_NET_LAST; tmp = virXPathString("string(./capability/@type)", ctxt); if (tmp) { int val = virNodeDevNetCapTypeFromString(tmp); VIR_FREE(tmp); if (val < 0) { virNodeDeviceReportError(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 virNodeDevicePtr nodeDeviceCreateXML(virConnectPtr conn, const char *xmlDesc, unsigned int flags ATTRIBUTE_UNUSED) { virDeviceMonitorStatePtr driver = conn->devMonPrivateData; virNodeDeviceDefPtr def = NULL; char *wwnn = NULL, *wwpn = NULL; int parent_host = -1; virNodeDevicePtr dev = NULL; nodeDeviceLock(driver); def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE); if (def == NULL) { goto cleanup; } if (virNodeDeviceGetWWNs(def, &wwnn, &wwpn) == -1) { goto cleanup; } if (virNodeDeviceGetParentHost(&driver->devs, def->name, def->parent, &parent_host) == -1) { goto cleanup; } if (nodeDeviceVportCreateDelete(parent_host, wwpn, wwnn, VPORT_CREATE) == -1) { goto cleanup; } dev = find_new_device(conn, wwnn, wwpn); /* We don't check the return value, because one way or another, * we're returning what we get... */ if (dev == NULL) { virNodeDeviceReportError(VIR_ERR_NO_NODE_DEVICE, NULL); } cleanup: nodeDeviceUnlock(driver); virNodeDeviceDefFree(def); VIR_FREE(wwnn); VIR_FREE(wwpn); return dev; }
static int get_time(time_t *t) { int ret = 0; *t = time(NULL); if (*t == (time_t)-1) { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not get current time")); *t = 0; ret = -1; } return ret; }
static int virNodeDevCapsDefParseString(const char *xpath, xmlXPathContextPtr ctxt, char **string, virNodeDeviceDefPtr def, const char *missing_error_fmt) { char *s; s = virXPathString(xpath, ctxt); if (s == NULL) { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, missing_error_fmt, def->name); return -1; } *string = s; return 0; }
static int nodeDeviceListCaps(virNodeDevicePtr dev, char **const names, int maxnames) { virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData; virNodeDeviceObjPtr obj; virNodeDevCapsDefPtr caps; int ncaps = 0; int ret = -1; nodeDeviceLock(driver); obj = virNodeDeviceFindByName(&driver->devs, dev->name); nodeDeviceUnlock(driver); if (!obj) { virNodeDeviceReportError(VIR_ERR_NO_NODE_DEVICE, _("no node device with matching name '%s'"), dev->name); goto cleanup; } for (caps = obj->def->caps; caps && ncaps < maxnames; caps = caps->next) { names[ncaps] = strdup(virNodeDevCapTypeToString(caps->type)); if (names[ncaps++] == NULL) { virReportOOMError(); goto cleanup; } } ret = ncaps; cleanup: if (obj) virNodeDeviceObjUnlock(obj); if (ret == -1) { --ncaps; while (--ncaps >= 0) VIR_FREE(names[ncaps]); } return ret; }
static int virNodeDevCapsDefParseHexId(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(xpath, ctxt, &val); if (ret < 0) { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, ret == -1 ? missing_error_fmt : invalid_error_fmt, def->name); return -1; } *value = val; return 0; }
static virNodeDevicePtr nodeDeviceLookupByName(virConnectPtr conn, const char *name) { virDeviceMonitorStatePtr driver = conn->devMonPrivateData; virNodeDeviceObjPtr obj; virNodeDevicePtr ret = NULL; nodeDeviceLock(driver); obj = virNodeDeviceFindByName(&driver->devs, name); nodeDeviceUnlock(driver); if (!obj) { virNodeDeviceReportError(VIR_ERR_NO_NODE_DEVICE, NULL); goto cleanup; } ret = virGetNodeDevice(conn, name); cleanup: if (obj) virNodeDeviceObjUnlock(obj); return ret; }
virNodeDeviceObjPtr virNodeDeviceAssignDef(virNodeDeviceObjListPtr devs, const virNodeDeviceDefPtr def) { virNodeDeviceObjPtr device; if ((device = virNodeDeviceFindByName(devs, def->name))) { virNodeDeviceDefFree(device->def); device->def = def; return device; } if (VIR_ALLOC(device) < 0) { virReportOOMError(); return NULL; } if (virMutexInit(&device->lock) < 0) { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot initialize mutex")); VIR_FREE(device); return NULL; } virNodeDeviceObjLock(device); device->def = def; if (VIR_REALLOC_N(devs->objs, devs->count+1) < 0) { device->def = NULL; virNodeDeviceObjUnlock(device); virNodeDeviceObjFree(device); virReportOOMError(); return NULL; } devs->objs[devs->count++] = device; return device; }
static int nodeDeviceVportCreateDelete(const int parent_host, const char *wwpn, const char *wwnn, int operation) { int retval = 0; char *operation_path = NULL, *vport_name = NULL; const char *operation_file = NULL; struct stat st; switch (operation) { case VPORT_CREATE: operation_file = LINUX_SYSFS_VPORT_CREATE_POSTFIX; break; case VPORT_DELETE: operation_file = LINUX_SYSFS_VPORT_DELETE_POSTFIX; break; default: virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid vport operation (%d)"), operation); retval = -1; goto cleanup; break; } if (virAsprintf(&operation_path, "%shost%d%s", LINUX_SYSFS_FC_HOST_PREFIX, parent_host, operation_file) < 0) { virReportOOMError(); retval = -1; goto cleanup; } if (stat(operation_path, &st) != 0) { VIR_FREE(operation_path); if (virAsprintf(&operation_path, "%shost%d%s", LINUX_SYSFS_SCSI_HOST_PREFIX, parent_host, operation_file) < 0) { virReportOOMError(); retval = -1; goto cleanup; } if (stat(operation_path, &st) != 0) { VIR_ERROR(_("No vport operation path found for host%d"), parent_host); retval = -1; goto cleanup; } } VIR_DEBUG("Vport operation path is '%s'", operation_path); if (virAsprintf(&vport_name, "%s:%s", wwpn, wwnn) < 0) { virReportOOMError(); retval = -1; goto cleanup; } if (virFileWriteStr(operation_path, vport_name, 0) == -1) { virReportSystemError(errno, _("Write of '%s' to '%s' during " "vport create/delete failed"), vport_name, operation_path); retval = -1; } cleanup: VIR_FREE(vport_name); VIR_FREE(operation_path); VIR_DEBUG("%s", _("Vport operation complete")); return retval; }
static int virNodeDevCapScsiHostParseXML(xmlXPathContextPtr ctxt, virNodeDeviceDefPtr def, xmlNodePtr node, union _virNodeDevCapData *data, int create) { xmlNodePtr orignode, *nodes = NULL; int ret = -1, n = 0, i; char *type = NULL; orignode = ctxt->node; ctxt->node = node; if (create == EXISTING_DEVICE && virNodeDevCapsDefParseULong("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; } if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0) { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, _("error parsing SCSI host capabilities for '%s'"), def->name); goto out; } for (i = 0 ; i < n ; i++) { type = virXMLPropString(nodes[i], "type"); if (!type) { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, _("missing SCSI host capability type for '%s'"), def->name); goto out; } if (STREQ(type, "vport_ops")) { data->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS; } else if (STREQ(type, "fc_host")) { xmlNodePtr orignode2; data->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST; orignode2 = ctxt->node; ctxt->node = nodes[i]; if (virNodeDevCapsDefParseString("string(./wwnn[1])", ctxt, &data->scsi_host.wwnn, def, _("no WWNN supplied for '%s'")) < 0) { goto out; } if (virNodeDevCapsDefParseString("string(./wwpn[1])", ctxt, &data->scsi_host.wwpn, def, _("no WWPN supplied for '%s'")) < 0) { goto out; } ctxt->node = orignode2; } else { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, _("unknown SCSI host capability type '%s' for '%s'"), type, def->name); goto out; } VIR_FREE(type); } ret = 0; out: VIR_FREE(type); ctxt->node = orignode; VIR_FREE(nodes); return ret; }
static virNodeDevCapsDefPtr virNodeDevCapsDefParseXML(xmlXPathContextPtr ctxt, virNodeDeviceDefPtr def, xmlNodePtr node, int create) { virNodeDevCapsDefPtr caps; char *tmp; int val, ret; if (VIR_ALLOC(caps) < 0) { virReportOOMError(); return NULL; } tmp = virXMLPropString(node, "type"); if (!tmp) { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing capability type")); goto error; } if ((val = virNodeDevCapTypeFromString(tmp)) < 0) { virNodeDeviceReportError(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(ctxt, def, node, &caps->data); break; case VIR_NODE_DEV_CAP_PCI_DEV: ret = virNodeDevCapPciDevParseXML(ctxt, def, node, &caps->data); break; case VIR_NODE_DEV_CAP_USB_DEV: ret = virNodeDevCapUsbDevParseXML(ctxt, def, node, &caps->data); break; case VIR_NODE_DEV_CAP_USB_INTERFACE: ret = virNodeDevCapUsbInterfaceParseXML(ctxt, def, node, &caps->data); break; case VIR_NODE_DEV_CAP_NET: ret = virNodeDevCapNetParseXML(ctxt, def, node, &caps->data); break; case VIR_NODE_DEV_CAP_SCSI_HOST: ret = virNodeDevCapScsiHostParseXML(ctxt, def, node, &caps->data, create); break; case VIR_NODE_DEV_CAP_SCSI_TARGET: ret = virNodeDevCapScsiTargetParseXML(ctxt, def, node, &caps->data); break; case VIR_NODE_DEV_CAP_SCSI: ret = virNodeDevCapScsiParseXML(ctxt, def, node, &caps->data); break; case VIR_NODE_DEV_CAP_STORAGE: ret = virNodeDevCapStorageParseXML(ctxt, def, node, &caps->data); break; default: virNodeDeviceReportError(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 int virNodeDevCapStorageParseXML(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("string(./block[1])", ctxt); if (!data->storage.block) { virNodeDeviceReportError(VIR_ERR_INTERNAL_ERROR, _("no block device path supplied for '%s'"), def->name); goto out; } data->storage.bus = virXPathString("string(./bus[1])", ctxt); data->storage.drive_type = virXPathString("string(./drive_type[1])", ctxt); data->storage.model = virXPathString("string(./model[1])", ctxt); data->storage.vendor = virXPathString("string(./vendor[1])", ctxt); data->storage.serial = virXPathString("string(./serial[1])", ctxt); if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0) { virNodeDeviceReportError(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(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("count(./media_available[. = '1']) > 0", ctxt)) data->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE; data->storage.media_label = virXPathString("string(./media_label[1])", ctxt); val = 0; if (virNodeDevCapsDefParseULongLong("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(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("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; }