提交 f4b5f530 编写于 作者: P Peter Krempa

virsh: domain: Fix the change-media command

The command did not modify the disk type and thus didn't allow to change
media from a file image to a block backed image or vice versa. In
addition when operating on a network backed removable devices the
command would replace the while <source> subelement with an invalid one.

This patch adds the --block option that allows to specify that the new
image is block backed and assumes that without that option all images
are file backed. Since network backends were always mangled it should
not cause problems.
上级 4cbcaffb
...@@ -11177,11 +11177,10 @@ vshFindDisk(const char *doc, ...@@ -11177,11 +11177,10 @@ vshFindDisk(const char *doc,
} }
typedef enum { typedef enum {
VSH_PREPARE_DISK_XML_NONE = 0, VSH_UPDATE_DISK_XML_EJECT,
VSH_PREPARE_DISK_XML_EJECT, VSH_UPDATE_DISK_XML_INSERT,
VSH_PREPARE_DISK_XML_INSERT, VSH_UPDATE_DISK_XML_UPDATE,
VSH_PREPARE_DISK_XML_UPDATE, } vshUpdateDiskXMLType;
} vshPrepareDiskXMLType;
/* Helper function to prepare disk XML. Could be used for disk /* Helper function to prepare disk XML. Could be used for disk
* detaching, media changing(ejecting, inserting, updating) * detaching, media changing(ejecting, inserting, updating)
...@@ -11189,15 +11188,14 @@ typedef enum { ...@@ -11189,15 +11188,14 @@ typedef enum {
* success, or NULL on failure. Caller must free the result. * success, or NULL on failure. Caller must free the result.
*/ */
static char * static char *
vshPrepareDiskXML(xmlNodePtr disk_node, vshUpdateDiskXML(xmlNodePtr disk_node,
const char *source, const char *new_source,
const char *path, bool source_block,
int type) const char *target,
vshUpdateDiskXMLType type)
{ {
xmlNodePtr cur = NULL; xmlNodePtr source = NULL;
char *disk_type = NULL;
char *device_type = NULL; char *device_type = NULL;
xmlNodePtr new_node = NULL;
char *ret = NULL; char *ret = NULL;
if (!disk_node) if (!disk_node)
...@@ -11205,62 +11203,64 @@ vshPrepareDiskXML(xmlNodePtr disk_node, ...@@ -11205,62 +11203,64 @@ vshPrepareDiskXML(xmlNodePtr disk_node,
device_type = virXMLPropString(disk_node, "device"); device_type = virXMLPropString(disk_node, "device");
if (STREQ_NULLABLE(device_type, "cdrom") || if (!(STREQ_NULLABLE(device_type, "cdrom") ||
STREQ_NULLABLE(device_type, "floppy")) { STREQ_NULLABLE(device_type, "floppy"))) {
bool has_source = false; vshError(NULL, _("The disk device '%s' is not removable"), target);
disk_type = virXMLPropString(disk_node, "type"); goto cleanup;
}
cur = disk_node->children; /* find the current source subelement */
while (cur != NULL) { for (source = disk_node->children; source; source = source->next) {
if (cur->type == XML_ELEMENT_NODE && if (source->type == XML_ELEMENT_NODE &&
xmlStrEqual(cur->name, BAD_CAST "source")) { xmlStrEqual(source->name, BAD_CAST "source"))
has_source = true; break;
break; }
}
cur = cur->next; if (type == VSH_UPDATE_DISK_XML_EJECT) {
if (!source) {
vshError(NULL, _("The disk device '%s' doesn't have media"), target);
goto cleanup;
} }
if (!has_source) { /* forcibly switch to empty file cdrom */
if (type == VSH_PREPARE_DISK_XML_EJECT) { source_block = false;
vshError(NULL, _("The disk device '%s' doesn't have media"), new_source = NULL;
path); } else if (!new_source) {
goto cleanup; vshError(NULL, _("New disk media source was not specified"));
} goto cleanup;
}
if (source) { if (type == VSH_UPDATE_DISK_XML_INSERT && source) {
new_node = xmlNewNode(NULL, BAD_CAST "source"); vshError(NULL, _("The disk device '%s' already has media"), target);
if (STREQ(disk_type, "block")) goto cleanup;
xmlNewProp(new_node, BAD_CAST "dev", BAD_CAST source); }
else
xmlNewProp(new_node, BAD_CAST disk_type, BAD_CAST source);
xmlAddChild(disk_node, new_node);
} else if (type == VSH_PREPARE_DISK_XML_INSERT) {
vshError(NULL, _("No source is specified for inserting media"));
goto cleanup;
} else if (type == VSH_PREPARE_DISK_XML_UPDATE) {
vshError(NULL, _("No source is specified for updating media"));
goto cleanup;
}
}
if (has_source) { /* remove current source */
if (type == VSH_PREPARE_DISK_XML_INSERT) { if (source) {
vshError(NULL, _("The disk device '%s' already has media"), xmlUnlinkNode(source);
path); xmlFreeNode(source);
goto cleanup; source = NULL;
} }
/* Remove the source if it tends to eject/update media. */ /* set the correct disk type */
xmlUnlinkNode(cur); if (source_block)
xmlFreeNode(cur); xmlSetProp(disk_node, BAD_CAST "type", BAD_CAST "block");
else
xmlSetProp(disk_node, BAD_CAST "type", BAD_CAST "file");
if (source && (type == VSH_PREPARE_DISK_XML_UPDATE)) { if (new_source) {
new_node = xmlNewNode(NULL, BAD_CAST "source"); /* create new source subelement */
xmlNewProp(new_node, (const xmlChar *)disk_type, if (!(source = xmlNewNode(NULL, BAD_CAST "source"))) {
(const xmlChar *)source); vshError(NULL, _("Failed to allocate new source node"));
xmlAddChild(disk_node, new_node); goto cleanup;
}
} }
if (source_block)
xmlNewProp(source, BAD_CAST "dev", BAD_CAST new_source);
else
xmlNewProp(source, BAD_CAST "file", BAD_CAST new_source);
xmlAddChild(disk_node, source);
} }
if (!(ret = virXMLNodeToString(NULL, disk_node))) { if (!(ret = virXMLNodeToString(NULL, disk_node))) {
...@@ -11270,7 +11270,6 @@ vshPrepareDiskXML(xmlNodePtr disk_node, ...@@ -11270,7 +11270,6 @@ vshPrepareDiskXML(xmlNodePtr disk_node,
cleanup: cleanup:
VIR_FREE(device_type); VIR_FREE(device_type);
VIR_FREE(disk_type);
return ret; return ret;
} }
...@@ -12278,6 +12277,10 @@ static const vshCmdOptDef opts_change_media[] = { ...@@ -12278,6 +12277,10 @@ static const vshCmdOptDef opts_change_media[] = {
.type = VSH_OT_BOOL, .type = VSH_OT_BOOL,
.help = N_("print XML document rather than change media") .help = N_("print XML document rather than change media")
}, },
{.name = "block",
.type = VSH_OT_BOOL,
.help = N_("source media is a block device")
},
{.name = NULL} {.name = NULL}
}; };
...@@ -12291,7 +12294,7 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd) ...@@ -12291,7 +12294,7 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd)
xmlNodePtr disk_node = NULL; xmlNodePtr disk_node = NULL;
char *disk_xml = NULL; char *disk_xml = NULL;
bool ret = false; bool ret = false;
int prepare_type = 0; vshUpdateDiskXMLType update_type;
const char *action = NULL; const char *action = NULL;
bool config = vshCommandOptBool(cmd, "config"); bool config = vshCommandOptBool(cmd, "config");
bool live = vshCommandOptBool(cmd, "live"); bool live = vshCommandOptBool(cmd, "live");
...@@ -12300,24 +12303,27 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd) ...@@ -12300,24 +12303,27 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd)
bool eject = vshCommandOptBool(cmd, "eject"); bool eject = vshCommandOptBool(cmd, "eject");
bool insert = vshCommandOptBool(cmd, "insert"); bool insert = vshCommandOptBool(cmd, "insert");
bool update = vshCommandOptBool(cmd, "update"); bool update = vshCommandOptBool(cmd, "update");
bool block = vshCommandOptBool(cmd, "block");
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT; unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
VSH_EXCLUSIVE_OPTIONS_VAR(eject, insert); VSH_EXCLUSIVE_OPTIONS_VAR(eject, insert);
VSH_EXCLUSIVE_OPTIONS_VAR(eject, update); VSH_EXCLUSIVE_OPTIONS_VAR(eject, update);
VSH_EXCLUSIVE_OPTIONS_VAR(insert, update); VSH_EXCLUSIVE_OPTIONS_VAR(insert, update);
VSH_EXCLUSIVE_OPTIONS_VAR(eject, block);
if (eject) { if (eject) {
prepare_type = VSH_PREPARE_DISK_XML_EJECT; update_type = VSH_UPDATE_DISK_XML_EJECT;
action = "eject"; action = "eject";
} }
if (insert) { if (insert) {
prepare_type = VSH_PREPARE_DISK_XML_INSERT; update_type = VSH_UPDATE_DISK_XML_INSERT;
action = "insert"; action = "insert";
} }
if (update || (!eject && !insert)) { if (update || (!eject && !insert)) {
prepare_type = VSH_PREPARE_DISK_XML_UPDATE; update_type = VSH_UPDATE_DISK_XML_UPDATE;
action = "update"; action = "update";
} }
...@@ -12332,7 +12338,7 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd) ...@@ -12332,7 +12338,7 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd)
flags |= VIR_DOMAIN_DEVICE_MODIFY_FORCE; flags |= VIR_DOMAIN_DEVICE_MODIFY_FORCE;
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
goto cleanup; return false;
if (vshCommandOptStringReq(ctl, cmd, "path", &path) < 0) if (vshCommandOptStringReq(ctl, cmd, "path", &path) < 0)
goto cleanup; goto cleanup;
...@@ -12340,11 +12346,6 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd) ...@@ -12340,11 +12346,6 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd)
if (vshCommandOptStringReq(ctl, cmd, "source", &source) < 0) if (vshCommandOptStringReq(ctl, cmd, "source", &source) < 0)
goto cleanup; goto cleanup;
if (insert && !source) {
vshError(ctl, "%s", _("No disk source specified for inserting"));
goto cleanup;
}
if (flags & VIR_DOMAIN_AFFECT_CONFIG) if (flags & VIR_DOMAIN_AFFECT_CONFIG)
doc = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE); doc = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE);
else else
...@@ -12355,7 +12356,8 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd) ...@@ -12355,7 +12356,8 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd)
if (!(disk_node = vshFindDisk(doc, path, VSH_FIND_DISK_CHANGEABLE))) if (!(disk_node = vshFindDisk(doc, path, VSH_FIND_DISK_CHANGEABLE)))
goto cleanup; goto cleanup;
if (!(disk_xml = vshPrepareDiskXML(disk_node, source, path, prepare_type))) if (!(disk_xml = vshUpdateDiskXML(disk_node, source, block, path,
update_type)))
goto cleanup; goto cleanup;
if (vshCommandOptBool(cmd, "print-xml")) { if (vshCommandOptBool(cmd, "print-xml")) {
...@@ -12375,8 +12377,7 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd) ...@@ -12375,8 +12377,7 @@ cmdChangeMedia(vshControl *ctl, const vshCmd *cmd)
VIR_FREE(doc); VIR_FREE(doc);
xmlFreeNode(disk_node); xmlFreeNode(disk_node);
VIR_FREE(disk_xml); VIR_FREE(disk_xml);
if (dom) virDomainFree(dom);
virDomainFree(dom);
return ret; return ret;
} }
......
...@@ -2597,11 +2597,13 @@ expected. ...@@ -2597,11 +2597,13 @@ expected.
=item B<change-media> I<domain> I<path> [I<--eject>] [I<--insert>] =item B<change-media> I<domain> I<path> [I<--eject>] [I<--insert>]
[I<--update>] [I<source>] [I<--force>] [[I<--live>] [I<--config>] | [I<--current>]] [I<--update>] [I<source>] [I<--force>] [[I<--live>] [I<--config>] | [I<--current>]]
[I<--print-xml>] [I<--print-xml>] [I<--block>]
Change media of CDROM or floppy drive. I<path> can be the fully-qualified path Change media of CDROM or floppy drive. I<path> can be the fully-qualified path
or the unique target name (<target dev='hdc'>) of the disk device. I<source> or the unique target name (<target dev='hdc'>) of the disk device. I<source>
specifies the path of the media to be inserted or updated. specifies the path of the media to be inserted or updated. Flag I<--block>
allows to set the backing type in case a block device is used as media for the
CDROM or floppy drive instead of a file.
I<--eject> indicates the media will be ejected. I<--eject> indicates the media will be ejected.
I<--insert> indicates the media will be inserted. I<source> must be specified. I<--insert> indicates the media will be inserted. I<source> must be specified.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册