[libvirt] [PATCH 1/2] virsh: Introduce two new commands to insert or eject media

Osier Yang jyang at redhat.com
Wed Jun 29 12:19:19 UTC 2011


eject-media: eject media from CD or floppy drive.
insert-media: insert media into CD or floppy drive.

NB, only support CDROM or floppy disk.
---
 tools/virsh.c |  367 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 367 insertions(+), 0 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index d15d206..20a29f2 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -10295,6 +10295,371 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
 }
 
 /*
+ * "eject-media" command
+ */
+static const vshCmdInfo info_eject_media[] = {
+    {"help", N_("eject media from CD or floppy drive")},
+    {"desc", N_("Eject media from CD or floppy drive.")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_eject_media[] = {
+    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
+    {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("target of disk device")},
+    {"current", VSH_OT_BOOL, 0, N_("can be either or both of --live and --config, "
+                                   "depends on implementation of hypervisor driver")},
+    {"live", VSH_OT_BOOL, 0, N_("alter live configuration of running domain")},
+    {"config", VSH_OT_BOOL, 0, N_("alter persistent configuration, effect observed on next boot")},
+    {"force",  VSH_OT_BOOL, 0, N_("force media ejection")},
+    {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdEjectMedia(vshControl *ctl, const vshCmd *cmd)
+{
+    xmlDocPtr xml = NULL;
+    xmlXPathObjectPtr obj=NULL;
+    xmlXPathContextPtr ctxt = NULL;
+    xmlNodePtr cur = NULL;
+    xmlBufferPtr xml_buf = NULL;
+    virDomainPtr dom = NULL;
+    const char *target = NULL;
+    char *doc;
+    int i = 0, diff_tgt;
+    int ret;
+    bool functionReturn = false;
+    int flags = 0;
+    int config = vshCommandOptBool(cmd, "config");
+    int live = vshCommandOptBool(cmd, "live");
+    int current = vshCommandOptBool(cmd, "current");
+    int force = vshCommandOptBool(cmd, "force");
+    bool has_source = false;
+
+    if (current) {
+        if (live || config) {
+            vshError(ctl, "%s", _("--current must be specified exclusively"));
+            return false;
+        }
+        flags = VIR_DOMAIN_AFFECT_CURRENT;
+    } else {
+        if (config)
+            flags |= VIR_DOMAIN_AFFECT_CONFIG;
+        if (live)
+            flags |= VIR_DOMAIN_AFFECT_LIVE;
+    }
+
+    if (force)
+        flags |= VIR_DOMAIN_DEVICE_MODIFY_FORCE;
+
+    if (!vshConnectionUsability(ctl, ctl->conn))
+        goto cleanup;
+
+    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+        goto cleanup;
+
+    if (vshCommandOptString(cmd, "target", &target) <= 0)
+        goto cleanup;
+
+    doc = virDomainGetXMLDesc(dom, 0);
+    if (!doc)
+        goto cleanup;
+
+    xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
+                     XML_PARSE_NOENT | XML_PARSE_NONET |
+                     XML_PARSE_NOWARNING);
+    VIR_FREE(doc);
+    if (!xml) {
+        vshError(ctl, "%s", _("Failed to get disk information"));
+        goto cleanup;
+    }
+    ctxt = xmlXPathNewContext(xml);
+    if (!ctxt) {
+        vshError(ctl, "%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(ctl, "%s", _("Failed to get disk information"));
+        goto cleanup;
+    }
+
+    /* search target */
+    for (; i < obj->nodesetval->nodeNr; i++) {
+        xmlNodePtr n = obj->nodesetval->nodeTab[i];
+        bool 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);
+        }
+
+        cur = obj->nodesetval->nodeTab[i]->children;
+        while (cur != NULL) {
+            if (cur->type == XML_ELEMENT_NODE &&
+                xmlStrEqual(cur->name, BAD_CAST "target")) {
+                char *tmp_tgt = virXMLPropString(cur, "dev");
+
+                diff_tgt = STREQ(tmp_tgt, target);
+                VIR_FREE(tmp_tgt);
+
+                if (diff_tgt && is_supported) {
+                    goto hit;
+                }
+            }
+
+            cur = cur->next;
+        }
+    }
+    vshError(ctl, _("No found CDROM or floppy disk whose target is %s"), target);
+    goto cleanup;
+
+ hit:
+    xml_buf = xmlBufferCreate();
+    if (!xml_buf) {
+        vshError(ctl, "%s", _("Failed to allocate memory"));
+        goto cleanup;
+    }
+
+    cur = obj->nodesetval->nodeTab[i]->children;
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE &&
+            xmlStrEqual(cur->name, BAD_CAST "source")) {
+            xmlUnlinkNode(cur);
+            xmlFreeNode(cur);
+            has_source = true;
+            break;
+        }
+
+        cur = cur->next;
+    }
+
+    if (!has_source) {
+        vshError(ctl, _("The disk device whose target is '%s' doesn't "
+                         "have media"), target);
+        goto cleanup;
+    }
+
+    if (xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0) {
+        vshError(ctl, "%s", _("Failed to create XML"));
+        goto cleanup;
+    }
+
+    ret = virDomainUpdateDeviceFlags(dom, (char *)xmlBufferContent(xml_buf), flags);
+
+    if (ret != 0) {
+        vshError(ctl, "%s", _("Failed to eject media"));
+    } else {
+        vshPrint(ctl, "%s", _("Media ejected successfully\n"));
+        functionReturn = true;
+    }
+
+ cleanup:
+    xmlXPathFreeObject(obj);
+    xmlXPathFreeContext(ctxt);
+    if (xml)
+        xmlFreeDoc(xml);
+    if (xml_buf)
+        xmlBufferFree(xml_buf);
+    if (dom)
+        virDomainFree(dom);
+    return functionReturn;
+}
+
+/*
+ * "insert-media" command
+ */
+static const vshCmdInfo info_insert_media[] = {
+    {"help", N_("insert media into CD or floppy drive")},
+    {"desc", N_("Insert media into CD or floppy drive.")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_insert_media[] = {
+    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
+    {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("target of disk device")},
+    {"source", VSH_OT_DATA, VSH_OFLAG_REQ, N_("source of the media")},
+    {"current", VSH_OT_BOOL, 0, N_("can be either or both of --live and --config, "
+                                   "depends on implementation of hypervisor driver")},
+    {"live", VSH_OT_BOOL, 0, N_("alter live configuration of running domain")},
+    {"config", VSH_OT_BOOL, 0, N_("alter persistent configuration, effect observed on next boot")},
+    {"force",  VSH_OT_BOOL, 0, N_("force media insertion")},
+    {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdInsertMedia(vshControl *ctl, const vshCmd *cmd)
+{
+    xmlDocPtr xml = NULL;
+    xmlXPathObjectPtr obj=NULL;
+    xmlXPathContextPtr ctxt = NULL;
+    xmlNodePtr cur = NULL;
+    xmlNodePtr new_node = NULL;
+    xmlBufferPtr xml_buf = NULL;
+    virDomainPtr dom = NULL;
+    const char *target = NULL;
+    const char *source = NULL;
+    char *doc;
+    int i = 0, diff_tgt;
+    int ret;
+    bool functionReturn = false;
+    int flags = 0;
+    const char *disk_type = NULL;
+    int config = vshCommandOptBool(cmd, "config");
+    int live = vshCommandOptBool(cmd, "live");
+    int current = vshCommandOptBool(cmd, "current");
+    int force = vshCommandOptBool(cmd, "force");
+
+    if (current) {
+        if (live || config) {
+            vshError(ctl, "%s", _("--current must be specified exclusively"));
+            return false;
+        }
+        flags = VIR_DOMAIN_AFFECT_CURRENT;
+    } else {
+        if (config)
+            flags |= VIR_DOMAIN_AFFECT_CONFIG;
+        if (live)
+            flags |= VIR_DOMAIN_AFFECT_LIVE;
+    }
+
+    if (force)
+        flags |= VIR_DOMAIN_DEVICE_MODIFY_FORCE;
+
+    if (!vshConnectionUsability(ctl, ctl->conn))
+        goto cleanup;
+
+    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+        goto cleanup;
+
+    if (vshCommandOptString(cmd, "target", &target) <= 0)
+        goto cleanup;
+
+    if (vshCommandOptString(cmd, "source", &source) <= 0)
+        goto cleanup;
+
+    doc = virDomainGetXMLDesc(dom, 0);
+    if (!doc)
+        goto cleanup;
+
+    xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
+                     XML_PARSE_NOENT | XML_PARSE_NONET |
+                     XML_PARSE_NOWARNING);
+    VIR_FREE(doc);
+    if (!xml) {
+        vshError(ctl, "%s", _("Failed to get disk information"));
+        goto cleanup;
+    }
+    ctxt = xmlXPathNewContext(xml);
+    if (!ctxt) {
+        vshError(ctl, "%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(ctl, "%s", _("Failed to get disk information"));
+        goto cleanup;
+    }
+
+    /* search target */
+    for (; i < obj->nodesetval->nodeNr; i++) {
+        xmlNodePtr n = obj->nodesetval->nodeTab[i];
+        bool is_supported = false;
+
+        /* Check if the disk is CDROM or floppy disk */
+        if (xmlStrEqual(n->name, BAD_CAST "disk")) {
+            disk_type = virXMLPropString(n, "type");
+            char *device_value = virXMLPropString(n, "device");
+
+            if (STREQ(device_value, "cdrom") ||
+                STREQ(device_value, "floppy"))
+                is_supported = true;
+
+            VIR_FREE(device_value);
+        }
+
+        cur = obj->nodesetval->nodeTab[i]->children;
+        while (cur != NULL) {
+            if (cur->type == XML_ELEMENT_NODE &&
+                xmlStrEqual(cur->name, BAD_CAST "target")) {
+                char *tmp_tgt = virXMLPropString(cur, "dev");
+
+                diff_tgt = STREQ(tmp_tgt, target);
+                VIR_FREE(tmp_tgt);
+
+                if (diff_tgt && is_supported) {
+                    goto hit;
+                }
+            }
+
+            cur = cur->next;
+        }
+        VIR_FREE(disk_type);
+    }
+    vshError(ctl, _("No found CDROM or floppy disk whose target is %s"), target);
+    goto cleanup;
+
+ hit:
+    xml_buf = xmlBufferCreate();
+    if (!xml_buf) {
+        vshError(ctl, "%s", _("Failed to allocate memory"));
+        goto cleanup;
+    }
+
+    cur = obj->nodesetval->nodeTab[i]->children;
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE &&
+            xmlStrEqual(cur->name, BAD_CAST "source")) {
+            vshError(ctl, _("The disk device whose target is '%s' has media, "
+                             "you may need to eject it first"), target);
+            goto cleanup;
+        }
+
+        cur = cur->next;
+    }
+
+    /* Insert node <source> */
+    new_node = xmlNewNode(NULL, BAD_CAST "source");
+    xmlNewProp(new_node, (const xmlChar *)disk_type, (const xmlChar *)source);
+    VIR_FREE(disk_type);
+    xmlAddChild(obj->nodesetval->nodeTab[i], new_node);
+
+    if (xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0) {
+        vshError(ctl, "%s", _("Failed to create XML"));
+        goto cleanup;
+    }
+
+    ret = virDomainUpdateDeviceFlags(dom, (char *)xmlBufferContent(xml_buf), flags);
+
+    if (ret != 0) {
+        vshError(ctl, "%s", _("Failed to insert media"));
+    } else {
+        vshPrint(ctl, "%s", _("Media inserted successfully\n"));
+        functionReturn = true;
+    }
+
+ cleanup:
+    xmlXPathFreeObject(obj);
+    xmlXPathFreeContext(ctxt);
+    if (xml)
+        xmlFreeDoc(xml);
+    if (xml_buf)
+        xmlBufferFree(xml_buf);
+    if (dom)
+        virDomainFree(dom);
+    return functionReturn;
+}
+
+/*
  * "detach-disk" command
  */
 static const vshCmdInfo info_detach_disk[] = {
@@ -11645,7 +12010,9 @@ static const vshCmdDef domManagementCmds[] = {
     {"dump", cmdDump, opts_dump, info_dump, 0},
     {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml, 0},
     {"edit", cmdEdit, opts_edit, info_edit, 0},
+    {"eject-media", cmdEjectMedia, opts_eject_media, info_eject_media, 0},
     {"inject-nmi", cmdInjectNMI, opts_inject_nmi, info_inject_nmi, 0},
+    {"insert-media", cmdInsertMedia, opts_insert_media, info_insert_media, 0},
     {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave, 0},
     {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove,
      info_managedsaveremove, 0},
-- 
1.7.4




More information about the libvir-list mailing list