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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list