mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-20 07:59:00 +00:00
virsh: Two new helper functions for disk device changes
vshFindDisk is to find the disk node in xml doc with given source path or target of disk device, and type (indicates disk type, normal disk or changeable disk). vshPrepareDiskXML is to make changes on the disk node (e.g. create and insert the new <source> node for inserting media of CDROM drive). They are marked as unused temporarily.
This commit is contained in:
parent
c430248643
commit
025998eb79
215
tools/virsh.c
215
tools/virsh.c
@ -14381,6 +14381,221 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
|
||||
return functionReturn;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
VSH_FIND_DISK_NORMAL,
|
||||
VSH_FIND_DISK_CHANGEABLE,
|
||||
} vshFindDiskType;
|
||||
|
||||
/* Helper function to find disk device in XML doc. Returns the disk
|
||||
* node on success, or NULL on failure. Caller must free the result
|
||||
* @path: Fully-qualified path or target of disk device.
|
||||
* @type: Either VSH_FIND_DISK_NORMAL or VSH_FIND_DISK_CHANGEABLE.
|
||||
*/
|
||||
ATTRIBUTE_UNUSED
|
||||
static xmlNodePtr
|
||||
vshFindDisk(const char *doc,
|
||||
const char *path,
|
||||
int type)
|
||||
{
|
||||
xmlDocPtr xml = NULL;
|
||||
xmlXPathObjectPtr obj= NULL;
|
||||
xmlXPathContextPtr ctxt = NULL;
|
||||
xmlNodePtr cur = NULL;
|
||||
xmlNodePtr ret = NULL;
|
||||
int i = 0;
|
||||
|
||||
xml = virXMLParseStringCtxt(doc, _("(domain_definition)"), &ctxt);
|
||||
if (!xml) {
|
||||
vshError(NULL, "%s", _("Failed to get disk information"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
|
||||
if ((obj == NULL) ||
|
||||
(obj->type != XPATH_NODESET) ||
|
||||
(obj->nodesetval == NULL) ||
|
||||
(obj->nodesetval->nodeNr == 0)) {
|
||||
vshError(NULL, "%s", _("Failed to get disk information"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* search disk using @path */
|
||||
for (; i < obj->nodesetval->nodeNr; i++) {
|
||||
bool is_supported = true;
|
||||
|
||||
if (type == VSH_FIND_DISK_CHANGEABLE) {
|
||||
xmlNodePtr n = obj->nodesetval->nodeTab[i];
|
||||
is_supported = false;
|
||||
|
||||
/* Check if the disk is CDROM or floppy disk */
|
||||
if (xmlStrEqual(n->name, BAD_CAST "disk")) {
|
||||
char *device_value = virXMLPropString(n, "device");
|
||||
|
||||
if (STREQ(device_value, "cdrom") ||
|
||||
STREQ(device_value, "floppy"))
|
||||
is_supported = true;
|
||||
|
||||
VIR_FREE(device_value);
|
||||
}
|
||||
|
||||
if (!is_supported)
|
||||
continue;
|
||||
}
|
||||
|
||||
cur = obj->nodesetval->nodeTab[i]->children;
|
||||
while (cur != NULL) {
|
||||
if (cur->type == XML_ELEMENT_NODE) {
|
||||
char *tmp = NULL;
|
||||
|
||||
if (xmlStrEqual(cur->name, BAD_CAST "source")) {
|
||||
if ((tmp = virXMLPropString(cur, "file")) ||
|
||||
(tmp = virXMLPropString(cur, "dev")) ||
|
||||
(tmp = virXMLPropString(cur, "dir")) ||
|
||||
(tmp = virXMLPropString(cur, "name"))) {
|
||||
}
|
||||
} else if (xmlStrEqual(cur->name, BAD_CAST "target")) {
|
||||
tmp = virXMLPropString(cur, "dev");
|
||||
}
|
||||
|
||||
if (STREQ_NULLABLE(tmp, path)) {
|
||||
ret = xmlCopyNode(obj->nodesetval->nodeTab[i], 1);
|
||||
VIR_FREE(tmp);
|
||||
goto cleanup;
|
||||
}
|
||||
VIR_FREE(tmp);
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
|
||||
vshError(NULL, _("No found disk whose source path or target is %s"), path);
|
||||
|
||||
cleanup:
|
||||
xmlXPathFreeObject(obj);
|
||||
xmlXPathFreeContext(ctxt);
|
||||
xmlFreeDoc(xml);
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
VSH_PREPARE_DISK_XML_NONE = 0,
|
||||
VSH_PREPARE_DISK_XML_EJECT,
|
||||
VSH_PREPARE_DISK_XML_INSERT,
|
||||
VSH_PREPARE_DISK_XML_UPDATE,
|
||||
} vshPrepareDiskXMLType;
|
||||
|
||||
/* Helper function to prepare disk XML. Could be used for disk
|
||||
* detaching, media changing(ejecting, inserting, updating)
|
||||
* for changeable disk. Returns the processed XML as string on
|
||||
* success, or NULL on failure. Caller must free the result.
|
||||
*/
|
||||
ATTRIBUTE_UNUSED
|
||||
static char *
|
||||
vshPrepareDiskXML(xmlNodePtr disk_node,
|
||||
const char *source,
|
||||
const char *path,
|
||||
int type)
|
||||
{
|
||||
xmlNodePtr cur = NULL;
|
||||
xmlBufferPtr xml_buf = NULL;
|
||||
const char *disk_type = NULL;
|
||||
const char *device_type = NULL;
|
||||
xmlNodePtr new_node = NULL;
|
||||
char *ret = NULL;
|
||||
|
||||
if (!disk_node)
|
||||
return NULL;
|
||||
|
||||
xml_buf = xmlBufferCreate();
|
||||
if (!xml_buf) {
|
||||
vshError(NULL, "%s", _("Failed to allocate memory"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
device_type = virXMLPropString(disk_node, "device");
|
||||
|
||||
if (STREQ_NULLABLE(device_type, "cdrom") ||
|
||||
STREQ_NULLABLE(device_type, "floppy")) {
|
||||
bool has_source = false;
|
||||
disk_type = virXMLPropString(disk_node, "type");
|
||||
|
||||
cur = disk_node->children;
|
||||
while (cur != NULL) {
|
||||
if (cur->type == XML_ELEMENT_NODE &&
|
||||
xmlStrEqual(cur->name, BAD_CAST "source")) {
|
||||
has_source = true;
|
||||
break;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
if (!has_source) {
|
||||
if (type == VSH_PREPARE_DISK_XML_EJECT) {
|
||||
vshError(NULL, _("The disk device '%s' doesn't have media"),
|
||||
path);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (source) {
|
||||
new_node = xmlNewNode(NULL, BAD_CAST "source");
|
||||
xmlNewProp(new_node, (const xmlChar *)disk_type,
|
||||
(const xmlChar *)source);
|
||||
xmlAddChild(disk_node, new_node);
|
||||
} else if (type == VSH_PREPARE_DISK_XML_INSERT) {
|
||||
vshError(NULL, _("No source is specified for inserting media"));
|
||||
goto error;
|
||||
} else if (type == VSH_PREPARE_DISK_XML_UPDATE) {
|
||||
vshError(NULL, _("No source is specified for updating media"));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_source) {
|
||||
if (type == VSH_PREPARE_DISK_XML_INSERT) {
|
||||
vshError(NULL, _("The disk device '%s' already has media"),
|
||||
path);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Remove the source if it tends to eject/update media. */
|
||||
xmlUnlinkNode(cur);
|
||||
xmlFreeNode(cur);
|
||||
|
||||
if (source && (type == VSH_PREPARE_DISK_XML_UPDATE)) {
|
||||
new_node = xmlNewNode(NULL, BAD_CAST "source");
|
||||
xmlNewProp(new_node, (const xmlChar *)disk_type,
|
||||
(const xmlChar *)source);
|
||||
xmlAddChild(disk_node, new_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (xmlNodeDump(xml_buf, NULL, disk_node, 0, 0) < 0) {
|
||||
vshError(NULL, "%s", _("Failed to create XML"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(device_type);
|
||||
VIR_FREE(disk_type);
|
||||
if (xml_buf) {
|
||||
if (VIR_ALLOC_N(ret, xmlBufferLength(xml_buf)) < 0) {
|
||||
virReportOOMError();
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ret, (char *)xmlBufferContent(xml_buf), xmlBufferLength(xml_buf));
|
||||
xmlBufferFree(xml_buf);
|
||||
}
|
||||
return ret;
|
||||
|
||||
error:
|
||||
xmlBufferFree(xml_buf);
|
||||
xml_buf = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* "detach-disk" command
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user