[libvirt] [PATCH v2 1/2] virsh: Switch from generated cmd*Edit commands to nongenerated
Eric Blake
eblake at redhat.com
Thu May 31 17:49:22 UTC 2012
On 05/24/2012 10:20 AM, Michal Privoznik wrote:
> Currently, we either generate some cmd*Edit commands (cmdPoolEdit
> and cmdNetworkEdit) via sed script or copy the body of cmdEdit
> (e.g. cmdInterfaceEdit, cmdNWFilterEdit, etc.). This fact makes
> it harder to implement any new feature to our editing system.
> Therefore switch to new implementation - define macros to:
> - dump XML (EDIT_GET_XML)
> - take an action if XML wasn't changed,
> usually just vshPrint() (EDIT_NOT_CHANGED)
> - define new object (EDIT_DEFINE) - the edited XML is in @doc_edited
> and #include "virsh-edit.c"
> ---
> cfg.mk | 4 +-
> po/POTFILES.in | 1 +
> tools/Makefile.am | 40 +-----
> tools/virsh-edit.c | 111 ++++++++++++++
> tools/virsh.c | 421 +++++++++++++++++-----------------------------------
> 5 files changed, 255 insertions(+), 322 deletions(-)
> create mode 100644 tools/virsh-edit.c
Needs a v3. See my interleaved comments (hopefully it's obvious how I'm
pointing out two different causes and later the locations that need
fixes for those bugs).
> + *
> + * EDIT_DEFINE - which redefines the object. The edited XML from user is in
> + * 'doc_edited' variable. Don't overwrite the pointer to the object,
> + * as we may iterate once more over and therefore the pointer would be
> + * invalid. Hence assign object to a different variable.
> + * Moreover, this needs to be an expression where:
> + * - 0 is taken as error (our virDefine* APIs often return NULL on error)
> + * - everything else is taken as success
> + * For example:
> + * #define EDIT_DEFINE dom_edited = virDomainDefineXML(ctl->conn, doc_edited)
This recommendation is a memory leak - if you call EDIT_DEFINE more than
once, then the second call will overwrite the dom_edited from the first
call. The fix is to add a fourth macro, EDIT_FREE, which is called as a
statement [1]...
> + *
> + * Michal Privoznik <mprivozn at redhat.com>
> + */
> +
> +#ifndef EDIT_GET_XML
> +# error Missing EDIT_GET_XML definition
> +#endif
> +
> +#ifndef EDIT_NOT_CHANGED
> +# error Missing EDIT_NOT_CHANGED definition
> +#endif
> +
> +#ifndef EDIT_DEFINE
> +# error Missing EDIT_DEFINE definition
> +#endif
> +
> +do {
> + /* Read back the edited file. */
> + doc_edited = editReadBackFile(ctl, tmp);
> + if (!doc_edited)
> + goto edit_cleanup;
> +
> + /* Compare original XML with edited. Has it changed at all? */
> + if (STREQ(doc, doc_edited)) {
> + EDIT_NOT_CHANGED;
> + ret = true;
> + goto edit_cleanup;
> + }
You have a bug here. This _always_ skips the redefine phase, but at
least one caller[2]...
> +
> + /* Now re-read the object XML. Did someone else change it while
> + * it was being edited? This also catches problems such as us
> + * losing a connection or the object going away.
> + */
> + doc_reread = (EDIT_GET_XML);
> + if (!doc_reread)
> + goto edit_cleanup;
> +
> + if (STRNEQ(doc, doc_reread)) {
> + vshError(ctl, "%s", _("ERROR: the XML configuration "
> + "was changed by another user"));
> + goto edit_cleanup;
> + }
> +
> + /* Everything checks out, so redefine the domain. */
[1]...right here.
> + if (!(EDIT_DEFINE))
> + goto edit_cleanup;
> +
> + break;
> +
> +edit_cleanup:
> + VIR_FREE(doc);
> + VIR_FREE(doc_edited);
> + VIR_FREE(doc_reread);
> + if (tmp) {
> + unlink (tmp);
> + VIR_FREE(tmp);
> + }
> + goto cleanup;
> +
> +} while (0);
> +
> +
> +#undef EDIT_GET_XML
> +#undef EDIT_NOT_CHANGED
> +#undef EDIT_DEFINE
> diff --git a/tools/virsh.c b/tools/virsh.c
> - if (!tmp) goto cleanup;
> -
> - /* Start the editor. */
> - if (editFile (ctl, tmp) == -1) goto cleanup;
> + #define EDIT_GET_XML virInterfaceGetXMLDesc(iface, flags)
> + #define EDIT_NOT_CHANGED \
> + vshPrint(ctl, _("Interface %s XML configuration not changed.\n"), \
> + virInterfaceGetName(iface))
> + #define EDIT_DEFINE \
> + iface_edited = virInterfaceDefineXML(ctl->conn, doc_edited, 0)
> + #include "virsh-edit.c"
[1] Here, EDIT_FREE would be /* */ (no extra work, as no extra resources
are allocated).
> + #define EDIT_GET_XML virInterfaceGetXMLDesc(iface, flags)
> + #define EDIT_NOT_CHANGED \
> + vshPrint(ctl, _("Interface %s XML configuration not changed.\n"), \
> + virInterfaceGetName(iface))
> + #define EDIT_DEFINE \
> + iface_edited = virInterfaceDefineXML(ctl->conn, doc_edited, 0)
Here, EDIT_FREE would be:
if (iface_edited)
virInterfaceFree (iface_edited);
and so forth.
> -
> - /* Compare original XML with edited. Short-circuit if it did not
> - * change, and we do not have any flags. */
> - if (STREQ(doc, doc_edited) &&
> - !(define_flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) {
> - vshPrint(ctl, _("Snapshot %s XML configuration not changed.\n"),
> - name);
> - ret = true;
> - goto cleanup;
> - }
[2]...has semantics where the presence of a flag MUST trigger a
redefine, even if the XML didn't change, but your replacement...
> -
> - /* Everything checks out, so redefine the xml. */
> - edited = virDomainSnapshotCreateXML(dom, doc_edited, define_flags);
> - if (!edited) {
> - vshError(ctl, _("Failed to update %s"), name);
> - goto cleanup;
> - }
> + #define EDIT_GET_XML \
> + virDomainSnapshotGetXMLDesc(snapshot, getxml_flags)
> + #define EDIT_NOT_CHANGED \
> + if (define_flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT) \
> + goto cleanup; \
> + vshPrint(ctl, _("Snapshot %s XML configuration not changed.\n"), name)
[2]...is not following those semantics. Perhaps the right fix is to
change 'EDIT_NOT_CHANGED' to have the caller be in control of issuing
'ret=true; goto cleanup;' as appropriate, rather than blindly doing that
for all callers in the include file. Then this particular definition
would be:
#define EDIT_NOT_CHANGED \
/* Depending on flags, we re-edit even if XML is unchanged. */ \
if (!define_flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT) { \
vshPrint(ctl, \
_("Snapshot %s XML configuration not changed.\n"), \
name); \
ret = true; \
goto cleanup; \
}
while most other definitions skip the if(){} and just have the three
statements.
--
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/20120531/11821a57/attachment-0001.sig>
More information about the libvir-list
mailing list