On Wed, Apr 21, 2010 at 12:01:18PM -0400, Chris Lalancette wrote: > Implement the qemu hooks for XML namespace data. This > allows us to specify a qemu XML namespace, and then > specify: > > <qemu:commandline> > <qemu:arg>arg</qemu:arg> > <qemu:env name='name' value='value'/> > </qemu:commandline> Now I see it, it looks a little odd to use the element content for qemu:arg, while having an element attributes for qemu:env. Since changing qemu:env to use content isn't practical, I think we could do this instead <qemu:arg value='blah'/> > diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h > index b2820f0..ab0a4a4 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_extra; > + char **extra; Lets call these 'num_args' and 'args' instead. > + > + 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 5f4adfd..0b297a7 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,9 @@ > > #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 +531,144 @@ static void qemuDomainObjExitMonitorWithDriver(struct qemud_driver *driver, virD > } > } > > +static void qemuDomainDefNamespaceFree(void *nsdata) > +{ > + qemuDomainCmdlineDefPtr cmd = nsdata; > + int i; > + > + if (!cmd) > + return; > + > + for (i = 0; i < cmd->num_extra; i++) > + VIR_FREE(cmd->extra[i]); > + for (i = 0; i < cmd->num_env; i++) { > + VIR_FREE(cmd->env_name[i]); > + VIR_FREE(cmd->env_value[i]); > + } > + VIR_FREE(cmd->extra); > + VIR_FREE(cmd->env_name); > + VIR_FREE(cmd->env_value); > + VIR_FREE(cmd); > +} > + > +static int qemuDomainDefNamespaceParse(xmlDocPtr xml, > + xmlNodePtr root, > + xmlXPathContextPtr ctxt, > + void **data) > +{ > + qemuDomainCmdlineDefPtr cmd = NULL; > + xmlNsPtr ns; > + xmlNodePtr *nodes = NULL; > + int n, i; > + xmlNodePtr oldnode; > + > + 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->extra, n) < 0) { > + virReportOOMError(); > + goto error; > + } > + > + for (i = 0; i < n; i++) { > + oldnode = ctxt->node; > + ctxt->node = nodes[i]; > + cmd->extra[cmd->num_extra] = virXPathString("string(.)", ctxt); > + if (cmd->extra[cmd->num_extra] == NULL) > + goto error; > + cmd->num_extra++; > + ctxt->node = oldnode; > + } > + > + /* 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) { > + virReportOOMError(); > + goto error; > + } > + > + if (n && VIR_ALLOC_N(cmd->env_value, n) < 0) { > + virReportOOMError(); > + goto error; > + } > + > + for (i = 0; i < n; i++) { > + oldnode = ctxt->node; > + ctxt->node = nodes[i]; > + cmd->env_name[cmd->num_env] = virXPathString("string(./@name)", ctxt); > + if (cmd->env_name[cmd->num_env] == NULL) > + goto error; > + cmd->env_value[cmd->num_env] = virXPathString("string(./@value)", ctxt); > + /* a NULL value for command is allowed, since it might be empty */ > + cmd->num_env++; > + ctxt->node = oldnode; > + } Using xpath for getting immediate attributes is somewhat overkill. You can just avoid touching ctxt at all, and use virXMLPropString(nodes[i], "name"); virXMLPropString(nodes[i], "value"); > +static int qemuDomainDefNamespaceFormatXML(virBufferPtr buf, > + void *nsdata) > +{ > + qemuDomainCmdlineDefPtr cmd = nsdata; > + int i; > + > + if (cmd->num_extra || cmd->num_env) > + virBufferAddLit(buf, " <qemu:commandline>\n"); > + for (i = 0; i < cmd->num_extra; i++) > + virBufferVSprintf(buf, " <qemu:arg>%s</qemu:arg>\n", cmd->extra[i]); > + for (i = 0; i < cmd->num_env; i++) { > + virBufferVSprintf(buf, " <qemu:env name='%s'", cmd->env_name[i]); > + if (cmd->env_value[i]) > + virBufferVSprintf(buf, " value='%s'", cmd->env_value[i]); > + virBufferAddLit(buf, "/>\n"); > + } Should use escaping for all the attributes here > + if (cmd->num_extra || 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 +1459,14 @@ qemuCreateCapabilities(virCapsPtr oldcaps, > caps->privateDataXMLFormat = qemuDomainObjPrivateXMLFormat; > caps->privateDataXMLParse = qemuDomainObjPrivateXMLParse; > > + /* Domain Namespace XML parser hooks */ > + if (VIR_ALLOC(caps->ns) < 0) > + goto no_memory; > + > + caps->ns->parse = qemuDomainDefNamespaceParse; > + caps->ns->free = qemuDomainDefNamespaceFree; > + caps->ns->format = qemuDomainDefNamespaceFormatXML; > + caps->ns->href = qemuDomainDefNamespaceHref; Could avoid needing to allocate this, by just statically declaring the callback table. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list