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.
---
tools/virsh.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 215 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 66bbb0c..b65114f 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -14321,6 +14321,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 whose source path or target
"
+ "is '%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 whose source path or target
"
+ "is '%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
*/
--
1.7.7.3