[libvirt] [PATCH v2 2/8] Qemu arbitrary command-line arguments.

Chris Lalancette clalance at redhat.com
Wed Apr 28 20:20:47 UTC 2010


Implement the qemu hooks for XML namespace data.  This
allows us to specify a qemu XML namespace, and then
specify:

<qemu:commandline>
 <qemu:arg value='arg'/>
 <qemu:env name='name' value='value'/>
</qemu:commandline>

In the domain XML.

Changes since v1:
 - Change the <qemu:arg>arg</qemu:arg> XML to <qemu:arg value='arg'/> XML
 - Fix up some memory leaks in qemuDomainDefNamespaceParse
 - Rename num_extra and extra to num_args and args, respectively
 - Fixed up some error messages
 - Make sure to escape user-provided data in qemuDomainDefNamesapceFormatXML

Signed-off-by: Chris Lalancette <clalance at redhat.com>
---
 src/qemu/qemu_conf.c   |   14 +++++
 src/qemu/qemu_conf.h   |   11 ++++
 src/qemu/qemu_driver.c |  149 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 174 insertions(+), 0 deletions(-)

diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index ed24916..132f801 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -4641,6 +4641,20 @@ int qemudBuildCommandLine(virConnectPtr conn,
         ADD_ARG_LIT(current_snapshot->def->name);
     }
 
+    if (def->namespaceData) {
+        qemuDomainCmdlineDefPtr cmd;
+
+        cmd = def->namespaceData;
+        for (i = 0; i < cmd->num_args; i++)
+            ADD_ARG_LIT(cmd->args[i]);
+        for (i = 0; i < cmd->num_env; i++) {
+            if (cmd->env_value[i])
+                ADD_ENV_PAIR(cmd->env_name[i], cmd->env_value[i]);
+            else
+                ADD_ENV_PAIR(cmd->env_name[i], "");
+        }
+    }
+
     ADD_ARG(NULL);
     ADD_ENV(NULL);
 
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index b2820f0..270d128 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -158,6 +158,17 @@ struct qemud_driver {
 typedef struct _qemuDomainPCIAddressSet qemuDomainPCIAddressSet;
 typedef qemuDomainPCIAddressSet *qemuDomainPCIAddressSetPtr;
 
+typedef struct _qemuDomainCmdlineDef qemuDomainCmdlineDef;
+typedef qemuDomainCmdlineDef *qemuDomainCmdlineDefPtr;
+struct _qemuDomainCmdlineDef {
+    unsigned int num_args;
+    char **args;
+
+    unsigned int num_env;
+    char **env_name;
+    char **env_value;
+};
+
 /* Port numbers used for KVM migration. */
 # define QEMUD_MIGRATION_FIRST_PORT 49152
 # define QEMUD_MIGRATION_NUM_PORTS 64
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 326cb58..23a1e1d 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -47,6 +47,8 @@
 #include <sys/ioctl.h>
 #include <sys/un.h>
 
+#include <libxml/xpathInternals.h>
+
 #ifdef __linux__
 # include <sys/vfs.h>
 # ifndef NFS_SUPER_MAGIC
@@ -88,6 +90,8 @@
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
+#define QEMU_NAMESPACE_HREF "http://libvirt.org/schemas/domain/qemu/1.0"
+
 /* Only 1 job is allowed at any time
  * A job includes *all* monitor commands, even those just querying
  * information, not merely actions */
@@ -526,6 +530,146 @@ static void qemuDomainObjExitMonitorWithDriver(struct qemud_driver *driver, virD
     }
 }
 
+static void qemuDomainDefNamespaceFree(void *nsdata)
+{
+    qemuDomainCmdlineDefPtr cmd = nsdata;
+    unsigned int i;
+
+    if (!cmd)
+        return;
+
+    for (i = 0; i < cmd->num_args; i++)
+        VIR_FREE(cmd->args[i]);
+    for (i = 0; i < cmd->num_env; i++) {
+        VIR_FREE(cmd->env_name[i]);
+        VIR_FREE(cmd->env_value[i]);
+    }
+    VIR_FREE(cmd->args);
+    VIR_FREE(cmd->env_name);
+    VIR_FREE(cmd->env_value);
+    VIR_FREE(cmd);
+}
+
+static int qemuDomainDefNamespaceParse(xmlDocPtr xml,
+                                       xmlNodePtr root,
+                                       xmlXPathContextPtr ctxt ATTRIBUTE_UNUSED,
+                                       void **data)
+{
+    qemuDomainCmdlineDefPtr cmd = NULL;
+    xmlNsPtr ns;
+    xmlNodePtr *nodes = NULL;
+    int n, i;
+
+    ns = xmlSearchNs(xml, root, BAD_CAST "qemu");
+    if (!ns)
+        /* this is fine; it just means there was no qemu namespace listed */
+        return 0;
+
+    if (STRNEQ((const char *)ns->href, QEMU_NAMESPACE_HREF)) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("Found namespace '%s' doesn't match expected '%s'"),
+                        ns->href, QEMU_NAMESPACE_HREF);
+        return -1;
+    }
+
+    if (xmlXPathRegisterNs(ctxt, ns->prefix, ns->href) < 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("Failed to register xml namespace '%s'"), ns->href);
+        return -1;
+    }
+
+    if (VIR_ALLOC(cmd) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    /* first handle the extra command-line arguments */
+    n = virXPathNodeSet("./qemu:commandline/qemu:arg", ctxt, &nodes);
+    if (n < 0)
+        /* virXPathNodeSet already set the error */
+        goto error;
+
+    if (n && VIR_ALLOC_N(cmd->args, n) < 0)
+        goto no_memory;
+
+    for (i = 0; i < n; i++) {
+        cmd->args[cmd->num_args] = virXMLPropString(nodes[i], "value");
+        if (cmd->args[cmd->num_args] == NULL) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            "%s", _("No qemu command-line argument specified"));
+            goto error;
+        }
+        cmd->num_args++;
+    }
+
+    VIR_FREE(nodes);
+
+    /* now handle the extra environment variables */
+    n = virXPathNodeSet("./qemu:commandline/qemu:env", ctxt, &nodes);
+    if (n < 0)
+        /* virXPathNodeSet already set the error */
+        goto error;
+
+    if (n && VIR_ALLOC_N(cmd->env_name, n) < 0)
+        goto no_memory;
+
+    if (n && VIR_ALLOC_N(cmd->env_value, n) < 0)
+        goto no_memory;
+
+    for (i = 0; i < n; i++) {
+        cmd->env_name[cmd->num_env] = virXMLPropString(nodes[i], "name");
+        if (cmd->env_name[cmd->num_env] == NULL) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            "%s", _("No qemu environment name specified"));
+            goto error;
+        }
+        cmd->env_value[cmd->num_env] = virXMLPropString(nodes[i], "value");
+        /* a NULL value for command is allowed, since it might be empty */
+        cmd->num_env++;
+    }
+
+    VIR_FREE(nodes);
+
+    *data = cmd;
+
+    return 0;
+
+no_memory:
+    virReportOOMError();
+
+error:
+    VIR_FREE(nodes);
+    qemuDomainDefNamespaceFree(cmd);
+    return -1;
+}
+
+static int qemuDomainDefNamespaceFormatXML(virBufferPtr buf,
+                                           void *nsdata)
+{
+    qemuDomainCmdlineDefPtr cmd = nsdata;
+    unsigned int i;
+
+    if (cmd->num_args || cmd->num_env)
+        virBufferAddLit(buf, "  <qemu:commandline>\n");
+    for (i = 0; i < cmd->num_args; i++)
+        virBufferEscapeString(buf, "    <qemu:arg value='%s'/>\n",
+                              cmd->args[i]);
+    for (i = 0; i < cmd->num_env; i++) {
+        virBufferVSprintf(buf, "    <qemu:env name='%s'", cmd->env_name[i]);
+        if (cmd->env_value[i])
+            virBufferEscapeString(buf, " value='%s'", cmd->env_value[i]);
+        virBufferAddLit(buf, "/>\n");
+    }
+    if (cmd->num_args || cmd->num_env)
+        virBufferAddLit(buf, "  </qemu:commandline>\n");
+
+    return 0;
+}
+
+static const char *qemuDomainDefNamespaceHref(void)
+{
+    return "xmlns:qemu='" QEMU_NAMESPACE_HREF "'";
+}
 
 static int qemuCgroupControllerActive(struct qemud_driver *driver,
                                       int controller)
@@ -1316,6 +1460,11 @@ qemuCreateCapabilities(virCapsPtr oldcaps,
     caps->privateDataXMLFormat = qemuDomainObjPrivateXMLFormat;
     caps->privateDataXMLParse = qemuDomainObjPrivateXMLParse;
 
+    /* Domain Namespace XML parser hooks */
+    caps->ns.parse = qemuDomainDefNamespaceParse;
+    caps->ns.free = qemuDomainDefNamespaceFree;
+    caps->ns.format = qemuDomainDefNamespaceFormatXML;
+    caps->ns.href = qemuDomainDefNamespaceHref;
 
     /* Security driver data */
     if (driver->securityPrimaryDriver) {
-- 
1.6.6.1




More information about the libvir-list mailing list