[libvirt] [PATCH v4] virsh: Increase device-detach intelligence

Eric Blake eblake at redhat.com
Wed Sep 14 15:25:30 UTC 2011


On 09/14/2011 08:46 AM, Michal Privoznik wrote:
> From: Michal Prívozník<mprivozn at redhat.com>
>
> Up to now users have to give a full XML description on input when
> device-detaching. If they omitted something it lead to unclear
> error messages (like generated MAC wasn't found, etc.).
> With this patch users can specify only those information which
> specify one device sufficiently precise. Remaining information is
> completed from domain.
> ---
> diff to v3:
> -change the superset search
> -tweak little snippets acording to Eric's review
>
>   tools/virsh.c |  278 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
>   1 files changed, 262 insertions(+), 16 deletions(-)
>
> @@ -10986,6 +10987,237 @@ cmdAttachDevice(vshControl *ctl, const vshCmd *cmd)
>       return true;
>   }
>
> +/**
> + * Check if n1 is superset of n2, meaning n1 contains all elements and
> + * attributes as n2 at lest. Including children.

s/lest/least/

> + * @n1 first node
> + * @n2 second node
> + * return 1 in case n1 covers n2, 0 otherwise.
> + */
> +static bool
> +vshNodeIsSuperset(xmlNodePtr n1, xmlNodePtr n2) {
> +    xmlNodePtr child1, child2;
> +    xmlAttrPtr attr;
> +    char *prop1, *prop2;
> +    bool found;
> +    bool visited;
> +    bool ret = false;
> +    unsigned long n1_child_size, n1_iter;
> +    virBitmapPtr bitmap;
> +
> +    if (!n1&&  !n2)
> +        return true;
> +
> +    if (!n1 || !n2)
> +        return false;
> +
> +    if (!xmlStrEqual(n1->name, n2->name))
> +        return true;

return false - if the names differ, there is no superset relation.

> +
> +    /* Iterate over n2 attributes and check if n1 contains them*/
> +    attr = n2->properties;
> +    while (attr) {
> +        if (attr->type == XML_ATTRIBUTE_NODE) {
> +            prop1 = virXMLPropString(n1, (const char *) attr->name);
> +            prop2 = virXMLPropString(n2, (const char *) attr->name);
> +            if (STRNEQ_NULLABLE(prop1, prop2)){

Space before { (at least, this one looks like a real spacing issue in 
your patch, and not yet another instance of thunderbird mangling things 
in my reply).

> +                xmlFree(prop1);
> +                xmlFree(prop2);
> +                return false;
> +            }
> +            xmlFree(prop1);
> +            xmlFree(prop2);
> +        }
> +        attr = attr->next;
> +    }
> +
> +    n1_child_size = xmlChildElementCount(n1);
> +    if (!n1_child_size) {
> +        return (n1->type == XML_ELEMENT_NODE) ? true : false;

I'm not a fan of 'return bool_cond ? true : false', when 'return 
bool_cond' gives the same results.

I'm not sure this line is right.  If n1 has no children, then it is a 
superset of n2 only if n2 has no children, not if n1 is a node.  Maybe 
you were trying to do this short circuit:  If n2 has no children, then 
it doesn't matter how many children n1 has, and you can return true at 
this point.

Also, why are you checking n1->type here?  Shouldn't we already know 
that n1->type and n2->type are both XML_ELEMENT_NODE before this 
function is ever called?

> + *
> + * To given domain and (probably incomplete) device XML specification try to

s/To given/For a given/

> +
> +    domDoc = virXMLParseStringCtxt(domXML, _("(domain definition)"),&domCtxt);

Peter's recent patch means that you need to:
s/domain definition/domain_definition/

> +    if (!domDoc) {
> +        vshError(ctl, _("Failed to parse domain definition xml"));
> +        goto cleanup;
> +    }
> +
> +    devDoc = virXMLParseStringCtxt(oldXML, _("(device definition)"),&devCtxt);

s/device definition/device_definition/

> +
> +    buf = xmlBufferCreate();

Why are we using xmlBuffer instead of virBuf APIs?  Not necessarily 
wrong, but also not typical in the rest of our code.

> +    if (!buf) {
> +        vshError(ctl, "%s", _("out of memory"));
> +        goto cleanup;
> +    }
> +
> +    xmlBufferCat(buf, BAD_CAST "/domain/devices/");
> +    xmlBufferCat(buf, node->name);

In fact, you could probably do the same in fewer lines of code, with:

virAsprintf(xpath, "/domain/devices/%s", node->name)

> +        goto cleanup;
> +    }
> +
> +    /* and refine */
> +    int i = 0;
> +    int indx = -1;

gcc didn't warn about declarations after goto?  I would float the 
declaration of i and indx earlier in the function, to match our style.

> +    if (newXML) {
> +        sctxt = xmlSaveToBuffer(buf, NULL, 0);
> +        if (!sctxt) {
> +            vshError(ctl, "%s", _("failed to create document saving context"));
> +            goto cleanup;
> +        }
> +
> +        xmlSaveTree(sctxt, devices[indx]);
> +        xmlSaveClose(sctxt);
> +        *newXML = (char *) xmlBufferContent(buf);

if (!*newXML) report OOM and goto cleanup, with funcRet of -1

> +        buf->content = NULL;
> +    }
> +
> +    vshDebug(ctl, VSH_ERR_DEBUG, "Old xml:\n%s\nNew xml:\n%s\n", oldXML, *newXML);

Null deref unless you use: newXML ? NULLSTR(*newXML) : "(null)"

-- 
Eric Blake   eblake at redhat.com    +1-801-349-2682
Libvirt virtualization library http://libvirt.org




More information about the libvir-list mailing list