[libvirt] [PATCH 1/4] virsh: Two new helper functions for disk device changes
Eric Blake
eblake at redhat.com
Mon Feb 13 21:59:59 UTC 2012
On 02/03/2012 02:23 AM, Osier Yang wrote:
> vshFindDisk is to find the disk node in xml doc with given target
> and flags (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).
> ---
> tools/virsh.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 files changed, 207 insertions(+), 0 deletions(-)
>
> diff --git a/tools/virsh.c b/tools/virsh.c
> index af78102..ca69f30 100644
> --- a/tools/virsh.c
> +++ b/tools/virsh.c
> @@ -14210,6 +14210,213 @@ cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
> return functionReturn;
> }
>
> +typedef enum {
> + VSH_FIND_DISK_NORMAL,
> + VSH_FIND_DISK_CHANGEABLE,
> +} vshFindDiskFlags;
If these were really flags, they would be (1 << 0) and (1 << 1), not 0
and 1.
> +
> +
> +/* Helper function to find disk device in XML doc. Returns the disk
> + * node on success, or NULL on failure. Caller must free the result
> + * @type can be either VSH_FIND_DISK_NORMAL or VSH_FIND_DISK_CHANGEABLE.
> + */
> +static xmlNodePtr
> +vshFindDisk(const char *doc,
> + const char *target,
> + unsigned int flags)
I think it may be simpler to just treat this parameter as bool
changeable; and pass false for normal disks and true for cdrom, unless
you really do plan to add more flags later.
> +{
> + xmlDocPtr xml = NULL;
> + xmlXPathObjectPtr obj= NULL;
> + xmlXPathContextPtr ctxt = NULL;
> + xmlNodePtr cur = NULL;
> + xmlNodePtr ret = NULL;
> + int i = 0;
> +
> + xml = xmlReadDoc((const xmlChar *) doc, "domain.xml", NULL,
Shouldn't we be using something like virXMLParseString(), and not raw
xmlReadDoc(), for better error reporting purposes? No one else in this
file uses xmlReadDoc, and we _aren't_ reading from a file named
'domain.xml', but from an in-memory string (where using something like
_("(domain_definition)") will give a better error message on a parse error).
> + XML_PARSE_NOENT | XML_PARSE_NONET |
> + XML_PARSE_NOWARNING);
> +
> + if (!xml) {
> + vshError(NULL, "%s", _("Failed to get disk information"));
> + goto cleanup;
> + }
> +
> + ctxt = xmlXPathNewContext(xml);
> + if (!ctxt) {
> + 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 target */
> + for (; i < obj->nodesetval->nodeNr; i++) {
> + bool is_supported = true;
> +
> + if (flags & 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);
> + }
> + }
Right here, couldn't you just 'continue' the outer loop if is_supported
is false, rather than spinning your wheels...
> +
> + cur = obj->nodesetval->nodeTab[i]->children;
> + while (cur != NULL) {
> + if (cur->type == XML_ELEMENT_NODE &&
> + xmlStrEqual(cur->name, BAD_CAST "target")) {
> + char *tmp = virXMLPropString(cur, "dev");
> +
> + if (is_supported &&
> + STREQ_NULLABLE(tmp, target)) {
...on an inner loop that will never resolve?
> + ret = xmlCopyNode(obj->nodesetval->nodeTab[i], 1);
> + VIR_FREE(tmp);
> + goto cleanup;
> + }
> + VIR_FREE(tmp);
> + }
> + cur = cur->next;
> + }
> + }
> +
> + vshError(NULL, _("No found disk whose target is %s"), target);
> +
> +cleanup:
> + xmlXPathFreeObject(obj);
> + xmlXPathFreeContext(ctxt);
> + xmlFreeDoc(xml);
> + return ret;
> +}
> +
> +typedef enum {
> + VSH_PREPARE_DISK_XML_NONE = 0,
> + VSH_PREPARE_DISK_XML_EJECT = (1 << 0),
> + VSH_PREPARE_DISK_XML_INSERT = (1 << 1),
> + VSH_PREPARE_DISK_XML_UPDATE = (1 << 2),
> +} vshPrepareDiskXMLFlags;
Can you really eject and update at the same time? That is, should this
be a linear enum (1, 2, 3) rather than bits (1, 2, 4)?
> +
> +/* Helper function to prepare disk XML. Could be used for disk
> + * detaching, media changing(ejecting, inserting, updating)
> + * for changedable disk. Returns the processed XML as string on
s/changedable/changeable/
> + * success, or NULL on failure. Caller must free the result.
> + */
> +static char *
> +vshPrepareDiskXML(xmlNodePtr disk_node,
> + const char *source,
> + const char *target,
> + unsigned int flags)
> +{
> + 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 (xmlNodeDump(xml_buf, NULL, disk_node, 0, 0) < 0) {
> + vshError(NULL, "%s", _("Failed to create XML"));
> + goto error;
> + }
> +
> + goto cleanup;
> +
> +error:
> + xmlBufferFree(xml_buf);
> + xml_buf = NULL;
I've generally seen the style:
ret = ...
cleanup:
...
return ret;
error:
...
goto cleanup:
more than your style of:
ret = ...
goto cleanup;
error:
...
cleanup:
...
return ret;
> +
> +cleanup:
> + VIR_FREE(device_type);
> + VIR_FREE(disk_type);
> + if (xml_buf) {
> + ret = vshCalloc(NULL, xmlBufferLength(xml_buf), sizeof(char));
sizeof(char) is always 1; it always looks fishy to me to see it without
good reason. vshCalloc generally wants a non-NULL first parameter, for
better logging of OOM messages. Is it any easier to just use:
if (VIR_ALLOC_N(ret, xmlBufferLength(xml_buf)) < 0)
error reporting
--
Eric Blake eblake at redhat.com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 620 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20120213/3641f36e/attachment-0001.sig>
More information about the libvir-list
mailing list