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