[PATCH] Make xmlgen.c use libxml2 instead of hacking it out manually

# HG changeset patch # User Dan Smith <danms@us.ibm.com> # Date 1228236226 28800 # Node ID c34ae7c0ded8870aeba40a0798ac31f1ea2c5bbd # Parent 6e8a488cf67b47efb618c28aa2a9104d5b0e1b91 Make xmlgen.c use libxml2 instead of hacking it out manually Now that our XML generation is getting complex enough, I think it's worth using libxml2 to build a proper DOM tree and XML string. Note that due to the invasiveness of this patch, it's almost unreadable. It may be easier to review after it's applied to the tree. Also, it deserves some serious review and testing for correctness and error-handling abilities. Comments on this approach are welcome too, of course. Signed-off-by: Dan Smith <danms@us.ibm.com> diff -r 6e8a488cf67b -r c34ae7c0ded8 libxkutil/xmlgen.c --- a/libxkutil/xmlgen.c Mon Dec 01 10:00:45 2008 -0800 +++ b/libxkutil/xmlgen.c Tue Dec 02 08:43:46 2008 -0800 @@ -24,6 +24,8 @@ #include <inttypes.h> #include <uuid/uuid.h> +#include <libxml/tree.h> + #include "xmlgen.h" #ifndef TEST @@ -32,487 +34,378 @@ #include "cmpimacs.h" #endif -static char *__tag_attr(struct kv *attrs, int count) +#define XML_ERROR "Failed to allocate XML memory" + +typedef const char *(*devfn_t)(xmlNodePtr node, struct domain *dominfo); + +static char *disk_block_xml(xmlNodePtr root, struct disk_device *dev) { - char *result = strdup(""); - char *new = NULL; - int i; - int size = 0; + xmlNodePtr disk; + xmlNodePtr tmp; - for (i = 0; i < count; i++) { - char *tmp; - int ret; + disk = xmlNewChild(root, NULL, BAD_CAST "disk", NULL); + if (disk == NULL) + return XML_ERROR; + xmlNewProp(disk, BAD_CAST "type", BAD_CAST "block"); + xmlNewProp(disk, BAD_CAST "device", BAD_CAST dev->device); - ret = asprintf(&new, " %s='%s'", - attrs[i].key, attrs[i].val); + tmp = xmlNewChild(disk, NULL, BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "dev", BAD_CAST dev->source); - if (ret == -1) - goto err; + tmp = xmlNewChild(disk, NULL, BAD_CAST "target", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "dev", BAD_CAST dev->virtual_dev); - size += strlen(new) + 1; - tmp = realloc(result, size); - if (tmp == NULL) - goto err; + if (dev->readonly) + xmlNewChild(disk, NULL, BAD_CAST "readonly", NULL); - result = tmp; - - strcat(result, new); - free(new); - } - - return result; - - err: - free(result); - return NULL; -} - -static char *tagify(char *tagname, char *content, struct kv *attrs, int count) -{ - char *result; - int ret; - char *opentag; - - if (count) - opentag = __tag_attr(attrs, count); - else - opentag = strdup(""); - - if (content) - ret = asprintf(&result, - "<%s%s>%s</%s>", - tagname, opentag, content, tagname); - else - ret = asprintf(&result, - "<%s%s/>", tagname, opentag); - if (ret == -1) - result = NULL; - - free(opentag); - - return result; -} - -static int astrcat(char **dest, char *source) -{ - char *tmp; - int ret; - - if (*dest) { - ret = asprintf(&tmp, "%s%s", *dest, source); - if (ret == -1) - return 0; - } else { - tmp = strdup(source); - } - - free(*dest); - - *dest = tmp; - - return 1; -} - -static char *disk_block_xml(struct disk_device *dev) -{ - char *xml; - int ret; - - ret = asprintf(&xml, - "<disk type='block' device='%s'>\n" - " <source dev='%s'/>\n" - " <target dev='%s'/>\n" - "%s" - "%s" - "</disk>\n", - dev->device, - dev->source, - dev->virtual_dev, - dev->readonly ? "<readonly/>\n" : "", - dev->shareable ? "<shareable/>\n" : ""); - if (ret == -1) - xml = NULL; - - return xml; -} - -static char *disk_file_xml(struct disk_device *dev) -{ - char *xml; - int ret; - - ret = asprintf(&xml, - "<disk type='file' device='%s'>\n" - " <source file='%s'/>\n" - " <target dev='%s'/>\n" - "%s" - "%s" - "</disk>\n", - dev->device, - dev->source, - dev->virtual_dev, - dev->readonly ? "<readonly/>" : "", - dev->shareable ? "<shareable/>" : ""); - if (ret == -1) - xml = NULL; - - return xml; -} - -static char *disk_fs_xml(struct disk_device *dev) -{ - char *xml; - int ret; - - ret = asprintf(&xml, - "<filesystem type='mount'>\n" - " <source dir='%s'/>\n" - " <target dir='%s'/>\n" - "</filesystem>\n", - dev->source, - dev->virtual_dev); - if (ret == -1) - xml = NULL; - - return xml; -} - -static bool disk_to_xml(char **xml, struct virt_device *dev) -{ - char *_xml = NULL; - struct disk_device *disk = &dev->dev.disk; - - if (disk->disk_type == DISK_PHY) - _xml = disk_block_xml(disk); - else if (disk->disk_type == DISK_FILE) - /* If it's not a block device, we assume a file, - which should be a reasonable fail-safe */ - _xml = disk_file_xml(disk); - else if (disk->disk_type == DISK_FS) - _xml = disk_fs_xml(disk); - else - return false; - - astrcat(xml, _xml); - free(_xml); - - return true; -} - -static bool bridge_net_to_xml(char **xml, struct virt_device *dev) -{ - int ret; - char *_xml; - char *script = "vif-bridge"; - struct net_device *net = &dev->dev.net; - - if (net->source == NULL) - ret = asprintf(&_xml, - "<interface type='%s'>\n" - " <mac address='%s'/>\n" - " <script path='%s'/>\n" - "</interface>\n", - net->type, - net->mac, - script); - else - ret = asprintf(&_xml, - "<interface type='%s'>\n" - " <source bridge='%s'/>\n" - " <mac address='%s'/>\n" - " <script path='%s'/>\n" - "</interface>\n", - net->type, - net->source, - net->mac, - script); - - if (ret == -1) - return false; - else - astrcat(xml, _xml); - - free(_xml); - - return true; -} - -static bool network_net_to_xml(char **xml, struct virt_device *dev) -{ - int ret; - char *_xml; - struct net_device *net = &dev->dev.net; - - if (net->source == NULL) - ret = asprintf(&_xml, - "<interface type='%s'>\n" - " <mac address='%s'/>\n" - "</interface>\n", - net->type, - net->mac); - else - ret = asprintf(&_xml, - "<interface type='%s'>\n" - " <mac address='%s'/>\n" - " <source network='%s'/>\n" - "</interface>\n", - net->type, - net->mac, - net->source); - if (ret == -1) - return false; - else - astrcat(xml, _xml); - - free(_xml); - - return true; -} - -static bool user_net_to_xml(char **xml, struct virt_device *dev) -{ - int ret; - char *_xml; - struct net_device *net = &dev->dev.net; - - ret = asprintf(&_xml, - "<interface type='%s'>\n" - " <mac address='%s'/>\n" - "</interface>\n", - net->type, - net->mac); - if (ret == -1) - return false; - else - astrcat(xml, _xml); - - free(_xml); - - return true; -} - -static bool net_to_xml(char **xml, struct virt_device *dev) -{ - if (STREQ(dev->dev.net.type, "network")) - return network_net_to_xml(xml, dev); - else if (STREQ(dev->dev.net.type, "bridge")) - return bridge_net_to_xml(xml, dev); - else if (STREQ(dev->dev.net.type, "user")) - return user_net_to_xml(xml, dev); - else - return false; -} - -static bool vcpu_to_xml(char **xml, struct virt_device *dev) -{ - int ret; - char *_xml; - - ret = asprintf(&_xml, "<vcpu>%" PRIu64 "</vcpu>\n", - dev->dev.vcpu.quantity); - if (ret == -1) - return false; - else - astrcat(xml, _xml); - - return true; -} - -static bool mem_to_xml(char **xml, struct virt_device *dev) -{ - int ret; - char *_xml; - struct mem_device *mem = &dev->dev.mem; - - ret = asprintf(&_xml, - "<currentMemory>%" PRIu64 "</currentMemory>\n" - "<memory>%" PRIu64 "</memory>\n", - mem->size, - mem->maxsize); - - - if (ret == -1) - return false; - else - astrcat(xml, _xml); - - free(_xml); - - return true; -} - -static bool emu_to_xml(char **xml, struct virt_device *dev) -{ - int ret; - char *_xml; - struct emu_device *emu = &dev->dev.emu; - - ret = asprintf(&_xml, - "<emulator>%s</emulator>\n", - emu->path); - if (ret == -1) - return false; - else - astrcat(xml, _xml); - - free(_xml); - - return true; -} - -static bool graphics_to_xml(char **xml, struct virt_device *dev) -{ - int ret; - char *_xml; - struct graphics_device *graphics = &dev->dev.graphics; - - ret = asprintf(&_xml, - "<graphics type='%s' port='%s' " - "listen='%s' keymap='%s'/>\n", - graphics->type, - graphics->port, - graphics->host != NULL ? graphics->host : "127.0.0.1", - graphics->keymap != NULL ? graphics->keymap : "en-us"); - if (ret == -1) - return false; - else - astrcat(xml, _xml); - - free(_xml); - - return true; -} - -static bool input_to_xml(char **xml, struct virt_device *dev) -{ - int ret; - char *_xml; - struct input_device *input = &dev->dev.input; - - ret = asprintf(&_xml, - "<input type='%s' bus='%s'/>\n", - input->type != NULL ? input->type: "mouse", - input->bus != NULL ? input->bus : "ps2"); - if (ret == -1) - return false; - else - astrcat(xml, _xml); - - free(_xml); - - return true; -} - -static bool concat_devxml(char **xml, - struct virt_device *list, - int count, - bool (*func)(char **, struct virt_device *)) -{ - char *_xml = NULL; - int i; - - for (i = 0; i < count; i++) { - /* Deleted devices are marked as CIM_RES_TYPE_UNKNOWN - * and should be skipped - */ - if (list[i].type != CIM_RES_TYPE_UNKNOWN) - func(&_xml, &list[i]); - } - - if (_xml != NULL) - astrcat(xml, _xml); - free(_xml); - - return true; -} - -char *device_to_xml(struct virt_device *dev) -{ - char *xml = NULL; - int type = dev->type; - bool (*func)(char **, struct virt_device *); - - switch (type) { - case CIM_RES_TYPE_DISK: - func = disk_to_xml; - break; - case CIM_RES_TYPE_PROC: - func = vcpu_to_xml; - break; - case CIM_RES_TYPE_NET: - func = net_to_xml; - break; - case CIM_RES_TYPE_MEM: - func = mem_to_xml; - break; - case CIM_RES_TYPE_EMU: - func = emu_to_xml; - break; - case CIM_RES_TYPE_GRAPHICS: - func = graphics_to_xml; - break; - case CIM_RES_TYPE_INPUT: - func = input_to_xml; - break; - default: - return NULL; - } - - if (concat_devxml(&xml, dev, 1, func)) - return xml; - - free(xml); + if (dev->shareable) + xmlNewChild(disk, NULL, BAD_CAST "shareable", NULL); return NULL; } -static char *system_xml(struct domain *domain) +static const char *disk_file_xml(xmlNodePtr root, struct disk_device *dev) { - int ret; - char *bl = NULL; - char *bl_args = NULL; - char *xml; + xmlNodePtr disk; + xmlNodePtr tmp; - if (domain->bootloader) - bl = tagify("bootloader", - domain->bootloader, - NULL, - 0); - if (domain->bootloader_args) - bl_args = tagify("bootloader_args", - domain->bootloader_args, - NULL, - 0); + disk = xmlNewChild(root, NULL, BAD_CAST "disk", NULL); + if (disk == NULL) + return XML_ERROR; + xmlNewProp(disk, BAD_CAST "type", BAD_CAST "file"); + xmlNewProp(disk, BAD_CAST "device", BAD_CAST dev->device); - ret = asprintf(&xml, - "<name>%s</name>\n" - "%s\n" - "%s\n" - "<on_poweroff>%s</on_poweroff>\n" - "<on_crash>%s</on_crash>\n", - domain->name, - bl ? bl : "", - bl_args ? bl_args : "", - vssd_recovery_action_str(domain->on_poweroff), - vssd_recovery_action_str(domain->on_crash)); - if (ret == -1) - xml = NULL; + tmp = xmlNewChild(disk, NULL, BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "file", BAD_CAST dev->source); - free(bl); - free(bl_args); + tmp = xmlNewChild(disk, NULL, BAD_CAST "target", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "dev", BAD_CAST dev->virtual_dev); - return xml; + if (dev->readonly) + xmlNewChild(disk, NULL, BAD_CAST "readonly", NULL); + + if (dev->shareable) + xmlNewChild(disk, NULL, BAD_CAST "shareable", NULL); + + + return NULL; } -static char *_xenpv_os_xml(struct domain *domain) +static const char *disk_fs_xml(xmlNodePtr root, struct disk_device *dev) +{ + xmlNodePtr fs; + xmlNodePtr tmp; + + fs = xmlNewChild(root, NULL, BAD_CAST "filesystem", NULL); + if (fs == NULL) + return XML_ERROR; + + tmp = xmlNewChild(fs, NULL, BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "dir", BAD_CAST dev->source); + + tmp = xmlNewChild(fs, NULL, BAD_CAST "target", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "dir", BAD_CAST dev->virtual_dev); + + return NULL; +} + +static const char *disk_xml(xmlNodePtr root, struct domain *dominfo) +{ + int i; + const char *msg = NULL;; + + for (i = 0; (i < dominfo->dev_disk_ct) && (msg == NULL); i++) { + struct disk_device *disk = &dominfo->dev_disk[i].dev.disk; + CU_DEBUG("Disk: %i %s %s", + disk->disk_type, + disk->source, + disk->virtual_dev); + if (disk->disk_type == DISK_PHY) + msg = disk_block_xml(root, disk); + else if (disk->disk_type == DISK_FILE) + /* If it's not a block device, we assume a file, + which should be a reasonable fail-safe */ + msg = disk_file_xml(root, disk); + else if (disk->disk_type == DISK_FS) + msg = disk_fs_xml(root, disk); + else + msg = "Unknown disk type"; + } + + return msg; +} + +static const char *bridge_net_to_xml(xmlNodePtr root, struct net_device *dev) +{ + const char *script = "vif-bridge"; + xmlNodePtr nic; + xmlNodePtr tmp; + + nic = xmlNewChild(root, NULL, BAD_CAST "interface", NULL); + if (nic == NULL) + return XML_ERROR; + xmlNewProp(nic, BAD_CAST "type", BAD_CAST dev->type); + + tmp = xmlNewChild(nic, NULL, BAD_CAST "mac", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "address", BAD_CAST dev->mac); + + tmp = xmlNewChild(nic, NULL, BAD_CAST "script", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "path", BAD_CAST script); + + if (dev->source != NULL) { + tmp = xmlNewChild(nic, NULL, BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "bridge", BAD_CAST dev->source); + } + + return NULL; +} + +static const char *network_net_to_xml(xmlNodePtr root, struct net_device *dev) +{ + xmlNodePtr nic; + xmlNodePtr tmp; + + nic = xmlNewChild(root, NULL, BAD_CAST "interface", NULL); + if (nic == NULL) + return XML_ERROR; + xmlNewProp(nic, BAD_CAST "type", BAD_CAST dev->type); + + tmp = xmlNewChild(nic, NULL, BAD_CAST "mac", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "address", BAD_CAST dev->mac); + + if (dev->source != NULL) { + tmp = xmlNewChild(nic, NULL, BAD_CAST "source", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "network", BAD_CAST dev->source); + } + + return NULL; +} + +static const char *user_net_to_xml(xmlNodePtr root, struct net_device *dev) +{ + xmlNodePtr nic; + xmlNodePtr tmp; + + nic = xmlNewChild(root, NULL, BAD_CAST "interface", NULL); + if (nic == NULL) + return XML_ERROR; + xmlNewProp(nic, BAD_CAST "type", BAD_CAST dev->type); + + tmp = xmlNewChild(nic, NULL, BAD_CAST "mac", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "address", BAD_CAST dev->mac); + + return NULL; +} + +static const char *net_xml(xmlNodePtr root, struct domain *dominfo) +{ + int i; + const char *msg = NULL; + + for (i = 0; (i < dominfo->dev_net_ct) && (msg == NULL); i++) { + struct virt_device *dev = &dominfo->dev_net[i]; + struct net_device *net = &dev->dev.net; + + if (STREQ(dev->dev.net.type, "network")) + msg = network_net_to_xml(root, net); + else if (STREQ(dev->dev.net.type, "bridge")) + msg = bridge_net_to_xml(root, net); + else if (STREQ(dev->dev.net.type, "user")) + msg = user_net_to_xml(root, net); + else + msg = "Unknown interface type"; + } + + return msg; +} + +static const char *vcpu_xml(xmlNodePtr root, struct domain *dominfo) +{ + struct vcpu_device *vcpu; + xmlNodePtr tmp; + int ret; + char *string = NULL; + + if (dominfo->dev_vcpu == NULL) + return NULL; + + vcpu = &dominfo->dev_vcpu[0].dev.vcpu; + + ret = asprintf(&string, "%" PRIu64, vcpu->quantity); + if (ret == -1) + return XML_ERROR; + + tmp = xmlNewChild(root, NULL, BAD_CAST "vcpu", BAD_CAST string); + free(string); + + if (tmp == NULL) + return XML_ERROR; + else + return NULL; +} + +static const char *mem_xml(xmlNodePtr root, struct domain *dominfo) +{ + struct mem_device *mem; + xmlNodePtr tmp = NULL; + int ret; + char *string = NULL; + + if (dominfo->dev_mem == NULL) + return NULL; + + mem = &dominfo->dev_mem[0].dev.mem; + + ret = asprintf(&string, "%" PRIu64, mem->size); + if (ret == -1) + goto out; + tmp = xmlNewChild(root, + NULL, + BAD_CAST "currentMemory", + BAD_CAST string); + + free(string); + tmp = NULL; + + ret = asprintf(&string, "%" PRIu64, mem->maxsize); + if (ret == -1) + goto out; + tmp = xmlNewChild(root, + NULL, + BAD_CAST "memory", + BAD_CAST string); + + free(string); + out: + if (tmp == NULL) + return XML_ERROR; + else + return NULL; +} + +static const char *emu_xml(xmlNodePtr root, struct domain *dominfo) +{ + struct emu_device *emu; + xmlNodePtr tmp; + + if (dominfo->dev_emu == NULL) + return NULL; + + emu = &dominfo->dev_emu->dev.emu; + tmp = xmlNewChild(root, NULL, BAD_CAST "emulator", BAD_CAST emu->path); + if (tmp == NULL) + return XML_ERROR; + + return NULL; +} + +static const char *graphics_xml(xmlNodePtr root, struct domain *dominfo) +{ + int i; + + for (i = 0; i < dominfo->dev_graphics_ct; i++) { + xmlNodePtr tmp; + struct virt_device *_dev = &dominfo->dev_graphics[i]; + struct graphics_device *dev = &_dev->dev.graphics; + + tmp = xmlNewChild(root, NULL, BAD_CAST "graphics", NULL); + if (tmp == NULL) + return XML_ERROR; + + xmlNewProp(tmp, BAD_CAST "type", BAD_CAST dev->type); + xmlNewProp(tmp, BAD_CAST "port", BAD_CAST dev->port); + xmlNewProp(tmp, BAD_CAST "listen", BAD_CAST dev->host); + xmlNewProp(tmp, BAD_CAST "keymap", BAD_CAST dev->keymap); + } + + return NULL; +} + +static const char *input_xml(xmlNodePtr root, struct domain *dominfo) +{ + int i; + + for (i = 0; i < dominfo->dev_input_ct; i++) { + xmlNodePtr tmp; + struct virt_device *_dev = &dominfo->dev_input[i]; + struct input_device *dev = &_dev->dev.input; + + tmp = xmlNewChild(root, NULL, BAD_CAST "input", NULL); + if (tmp == NULL) + return XML_ERROR; + + xmlNewProp(tmp, BAD_CAST "type", BAD_CAST dev->type); + xmlNewProp(tmp, BAD_CAST "bus", BAD_CAST dev->bus); + } + + return NULL; +} + +static char *system_xml(xmlNodePtr root, struct domain *domain) +{ + xmlNodePtr tmp; + + tmp = xmlNewChild(root, NULL, BAD_CAST "name", BAD_CAST domain->name); + + if (domain->bootloader) { + xmlNodePtr bl; + + bl = xmlNewChild(root, + NULL, + BAD_CAST "bootloader", + BAD_CAST domain->bootloader); + } + + if (domain->bootloader_args) { + xmlNodePtr bl_args; + + bl_args = xmlNewChild(root, + NULL, + BAD_CAST "bootloader_args", + BAD_CAST domain->bootloader_args); + } + + tmp = xmlNewChild(root, + NULL, + BAD_CAST "on_poweroff", + BAD_CAST vssd_recovery_action_str(domain->on_poweroff)); + + tmp = xmlNewChild(root, + NULL, + BAD_CAST "on_crash", + BAD_CAST vssd_recovery_action_str(domain->on_crash)); + + return NULL; +} + +static char *_xenpv_os_xml(xmlNodePtr root, struct domain *domain) { struct pv_os_info *os = &domain->os_info.pv; - int ret; - char *xml; - char *type = NULL; - char *kernel = NULL; - char *initrd = NULL; - char *cmdline = NULL; + xmlNodePtr tmp; if (os->type == NULL) os->type = strdup("linux"); @@ -520,42 +413,29 @@ if (os->kernel == NULL) os->kernel = strdup("/dev/null"); - type = tagify("type", os->type, NULL, 0); - kernel = tagify("kernel", os->kernel, NULL, 0); - initrd = tagify("initrd", os->initrd, NULL, 0); - cmdline = tagify("cmdline", os->cmdline, NULL, 0); + tmp = xmlNewChild(root, NULL, BAD_CAST "type", BAD_CAST os->type); + if (tmp == NULL) + return XML_ERROR; - ret = asprintf(&xml, - "<os>\n" - " %s\n" - " %s\n" - " %s\n" - " %s\n" - "</os>\n", - type, - kernel, - initrd, - cmdline); - if (ret == -1) - xml = NULL; + tmp = xmlNewChild(root, NULL, BAD_CAST "kernel", BAD_CAST os->kernel); + if (tmp == NULL) + return XML_ERROR; - free(type); - free(kernel); - free(initrd); - free(cmdline); + tmp = xmlNewChild(root, NULL, BAD_CAST "initrd", BAD_CAST os->initrd); + if (tmp == NULL) + return XML_ERROR; - return xml; + tmp = xmlNewChild(root, NULL, BAD_CAST "cmdline", BAD_CAST os->cmdline); + if (tmp == NULL) + return XML_ERROR; + + return NULL; } -static char *_xenfv_os_xml(struct domain *domain) +static char *_xenfv_os_xml(xmlNodePtr root, struct domain *domain) { struct fv_os_info *os = &domain->os_info.fv; - int ret; - char *xml; - char *type; - char *loader; - char *boot; - struct kv bootattr = {"dev", NULL}; + xmlNodePtr tmp; if (os->type == NULL) os->type = strdup("hvm"); @@ -566,44 +446,30 @@ if (os->boot == NULL) os->boot = strdup("hd"); - type = tagify("type", os->type, NULL, 0); - loader = tagify("loader", os->loader, NULL, 0); + tmp = xmlNewChild(root, NULL, BAD_CAST "type", BAD_CAST os->type); + if (tmp == NULL) + return XML_ERROR; - bootattr.val = os->boot; - boot = tagify("boot", NULL, &bootattr, 1); + tmp = xmlNewChild(root, NULL, BAD_CAST "loader", BAD_CAST os->loader); + if (tmp == NULL) + return XML_ERROR; - ret = asprintf(&xml, - "<os>\n" - " %s\n" - " %s\n" - " %s\n" - "</os>\n" - "<features>\n" - " <pae/>\n" - " <acpi/>\n" - " <apic/>\n" - "</features>\n", - type, - loader, - boot); - if (ret == -1) - xml = NULL; + tmp = xmlNewChild(root, NULL, BAD_CAST "boot", BAD_CAST os->boot); + if (tmp == NULL) + return XML_ERROR; - free(type); - free(loader); - free(boot); + tmp = xmlNewChild(root, NULL, BAD_CAST "features", NULL); + xmlNewChild(tmp, NULL, BAD_CAST "pae", NULL); + xmlNewChild(tmp, NULL, BAD_CAST "acpi", NULL); + xmlNewChild(tmp, NULL, BAD_CAST "apic", NULL); - return xml; + return NULL; } -static char *_kvm_os_xml(struct domain *domain) +static char *_kvm_os_xml(xmlNodePtr root, struct domain *domain) { struct fv_os_info *os = &domain->os_info.fv; - int ret; - char *xml; - char *type; - char *boot; - struct kv bootattr = {"dev", NULL}; + xmlNodePtr tmp; if (os->type == NULL) os->type = strdup("hvm"); @@ -611,84 +477,162 @@ if (os->boot == NULL) os->boot = strdup("hd"); - type = tagify("type", os->type, NULL, 0); + tmp = xmlNewChild(root, NULL, BAD_CAST "type", BAD_CAST os->type); + if (tmp == NULL) + return XML_ERROR; - bootattr.val = os->boot; - boot = tagify("boot", NULL, &bootattr, 1); + tmp = xmlNewChild(root, NULL, BAD_CAST "boot", NULL); + if (tmp == NULL) + return XML_ERROR; + xmlNewProp(tmp, BAD_CAST "dev", BAD_CAST os->boot); - ret = asprintf(&xml, - "<os>\n" - " %s\n" - " %s\n" - "</os>\n", - type, - boot); - if (ret == -1) - xml = NULL; + return NULL; +} - free(type); - free(boot); +static char *_lxc_os_xml(xmlNodePtr root, struct domain *domain) +{ + struct lxc_os_info *os = &domain->os_info.lxc; + xmlNodePtr tmp; + + if (os->type == NULL) + os->type = strdup("exe"); + + tmp = xmlNewChild(root, NULL, BAD_CAST "init", BAD_CAST os->init); + if (tmp == NULL) + return XML_ERROR; + + tmp = xmlNewChild(root, NULL, BAD_CAST "type", BAD_CAST os->type); + if (tmp == NULL) + return XML_ERROR; + + return NULL; +} + +static char *os_xml(xmlNodePtr root, struct domain *domain) +{ + xmlNodePtr os; + + os = xmlNewChild(root, NULL, BAD_CAST "os", NULL); + if (os == NULL) + return "Failed to allocate XML memory"; + + if (domain->type == DOMAIN_XENPV) + return _xenpv_os_xml(os, domain); + else if (domain->type == DOMAIN_XENFV) + return _xenfv_os_xml(os, domain); + else if (domain->type == DOMAIN_KVM) + return _kvm_os_xml(os, domain); + else if (domain->type == DOMAIN_LXC) + return _lxc_os_xml(os, domain); + else + return "Unsupported domain type"; +} + +char *device_to_xml(struct virt_device *dev) +{ + char *xml = NULL; + int type = dev->type; + xmlDocPtr doc = NULL; + xmlNodePtr root = NULL; + xmlChar *_xml = NULL; + int xml_size; + const char *msg; + struct domain *dominfo; + devfn_t func; + + dominfo = calloc(1, sizeof(*dominfo)); + if (dominfo == NULL) + return NULL; + + doc = xmlNewDoc(BAD_CAST "1.0"); + if (doc == NULL) + goto out; + root = xmlNewNode(NULL, BAD_CAST "tmp"); + if (root == NULL) + goto out; + + switch (type) { + case CIM_RES_TYPE_DISK: + func = disk_xml; + dominfo->dev_disk_ct = 1; + dominfo->dev_disk = dev; + break; + case CIM_RES_TYPE_PROC: + func = vcpu_xml; + dominfo->dev_vcpu_ct = 1; + dominfo->dev_vcpu = dev; + break; + case CIM_RES_TYPE_NET: + func = net_xml; + dominfo->dev_net_ct = 1; + dominfo->dev_vcpu = dev; + break; + case CIM_RES_TYPE_MEM: + func = mem_xml; + dominfo->dev_mem_ct = 1; + dominfo->dev_mem = dev; + break; + case CIM_RES_TYPE_EMU: + func = emu_xml; + dominfo->dev_emu = dev; + break; + case CIM_RES_TYPE_GRAPHICS: + func = graphics_xml; + dominfo->dev_graphics_ct = 1; + dominfo->dev_graphics = dev; + break; + case CIM_RES_TYPE_INPUT: + func = input_xml; + dominfo->dev_input_ct = 1; + dominfo->dev_input = dev; + break; + default: + return NULL; + } + + msg = func(root, dominfo); + if (msg != NULL) { + CU_DEBUG("Failed to create device XML: %s", msg); + goto out; + } + + xmlDocSetRootElement(doc, root->children); + + xmlDocDumpFormatMemory(doc, &_xml, &xml_size, 1); + xml = strdup((char *)_xml); + xmlFree(_xml); + out: + CU_DEBUG("Created Device XML:\n%s\n", xml); + + cleanup_dominfo(&dominfo); + xmlFreeNode(root); + xmlFreeDoc(doc); return xml; } -static char *_lxc_os_xml(struct domain *domain) -{ - struct lxc_os_info *os = &domain->os_info.lxc; - int ret; - char *xml = NULL; - - if (os->type == NULL) - os->type = strdup("exe"); - - ret = asprintf(&xml, - "<os>\n" - " <init>%s</init>\n" - " <type>%s</type>\n" - "</os>\n", - os->init, - os->type); - if (ret == -1) - xml = NULL; - - return xml; -} - -static char *os_xml(struct domain *domain) -{ - if (domain->type == DOMAIN_XENPV) - return _xenpv_os_xml(domain); - else if (domain->type == DOMAIN_XENFV) - return _xenfv_os_xml(domain); - else if (domain->type == DOMAIN_KVM) - return _kvm_os_xml(domain); - else if (domain->type == DOMAIN_LXC) - return _lxc_os_xml(domain); - else - return strdup("<!-- unsupported domain type -->\n"); -} - -static int console_xml(struct domain *dominfo, - char **xml) -{ - if (dominfo->type == DOMAIN_LXC) { - astrcat(xml, "<console type='pty'/>\n"); - } - - return 0; -} char *system_to_xml(struct domain *dominfo) { - char *devxml = strdup(""); - char *sysdevxml = strdup(""); - char *sysxml = NULL; - char *osxml = NULL; + xmlDocPtr doc = NULL; + xmlNodePtr root = NULL; + xmlNodePtr devices = NULL; + xmlChar *_xml = NULL; char *xml = NULL; - int ret; + int xml_len; uint8_t uuid[16]; char uuidstr[37]; const char *domtype; + const char *msg = XML_ERROR; + int i; + devfn_t device_handlers[] = { + &disk_xml, + &net_xml, + &input_xml, + &graphics_xml, + &emu_xml, + NULL + }; if ((dominfo->type == DOMAIN_XENPV) || (dominfo->type == DOMAIN_XENFV)) domtype = "xen"; @@ -708,70 +652,92 @@ uuid_unparse(uuid, uuidstr); } - concat_devxml(&devxml, - dominfo->dev_net, - dominfo->dev_net_ct, - net_to_xml); - concat_devxml(&devxml, - dominfo->dev_disk, - dominfo->dev_disk_ct, - disk_to_xml); + CU_DEBUG("foo"); + doc = xmlNewDoc(BAD_CAST "1.0"); + if (doc == NULL) + goto out; - if (dominfo->dev_emu) - concat_devxml(&devxml, - dominfo->dev_emu, - 1, - emu_to_xml); + CU_DEBUG("foo"); + root = xmlNewNode(NULL, BAD_CAST "domain"); + if (root == NULL) + goto out; - if (dominfo->dev_graphics) - concat_devxml(&devxml, - dominfo->dev_graphics, - dominfo->dev_graphics_ct, - graphics_to_xml); + CU_DEBUG("foo"); + if (xmlNewProp(root, BAD_CAST "type", BAD_CAST domtype) == NULL) + goto out; - if (dominfo->dev_input) - concat_devxml(&devxml, - dominfo->dev_input, - dominfo->dev_input_ct, - input_to_xml); + CU_DEBUG("foo"); + xmlDocSetRootElement(doc, root); - console_xml(dominfo, &devxml); + CU_DEBUG("foo"); + msg = system_xml(root, dominfo); + if (msg != NULL) + goto out; - concat_devxml(&sysdevxml, - dominfo->dev_mem, - dominfo->dev_mem_ct, - mem_to_xml); - concat_devxml(&sysdevxml, - dominfo->dev_vcpu, - dominfo->dev_vcpu_ct, - vcpu_to_xml); + CU_DEBUG("foo"); + msg = os_xml(root, dominfo); + if (msg != NULL) + goto out; - sysxml = system_xml(dominfo); - osxml = os_xml(dominfo); + CU_DEBUG("foo"); + msg = mem_xml(root, dominfo); + if (msg != NULL) + goto out; - ret = asprintf(&xml, - "<domain type='%s'>\n" - "<uuid>%s</uuid>\n" - "%s" - "%s" - "%s" - "<devices>\n" - "%s" - "</devices>\n" - "</domain>\n", - domtype, - uuidstr, - sysxml, - osxml, - sysdevxml, - devxml); - if (ret == -1) - xml = NULL; + CU_DEBUG("foo"); + msg = vcpu_xml(root, dominfo); + if (msg != NULL) + goto out; - free(devxml); - free(sysdevxml); - free(osxml); - free(sysxml); + CU_DEBUG("foo"); + devices = xmlNewChild(root, NULL, BAD_CAST "devices", NULL); + if (devices == NULL) { + msg = XML_ERROR; + goto out; + } + + CU_DEBUG("foo"); + for (i = 0; device_handlers[i] != NULL; i++) { + devfn_t fn = device_handlers[i]; + + msg = fn(devices, dominfo); + if (msg != NULL) + goto out; + } + + CU_DEBUG("foo"); + msg = XML_ERROR; + if (dominfo->type == DOMAIN_LXC) { + xmlNodePtr cons; + + cons = xmlNewChild(devices, NULL, BAD_CAST "console", NULL); + if (cons == NULL) + goto out; + + if (xmlNewProp(cons, BAD_CAST "type", BAD_CAST "pty") == NULL) + goto out; + } + + CU_DEBUG("Generating XML"); + xmlDocDumpFormatMemory(doc, &_xml, &xml_len, 1); + if (_xml == NULL) + goto out; + + xml = strdup((char *)_xml); + if (xml == NULL) + msg = "Out of memory generating XML"; + else + msg = NULL; + + xmlFree(_xml); + out: + if (msg != NULL) { + CU_DEBUG("Failed to create XML: %s", msg); + } else { + CU_DEBUG("Created System XML:\n%s\n", xml); + } + + xmlFreeDoc(doc); return xml; }

On Tue, Dec 02, 2008 at 08:43:48AM -0800, Dan Smith wrote:
# HG changeset patch # User Dan Smith <danms@us.ibm.com> # Date 1228236226 28800 # Node ID c34ae7c0ded8870aeba40a0798ac31f1ea2c5bbd # Parent 6e8a488cf67b47efb618c28aa2a9104d5b0e1b91 Make xmlgen.c use libxml2 instead of hacking it out manually
Now that our XML generation is getting complex enough, I think it's worth using libxml2 to build a proper DOM tree and XML string.
Note that due to the invasiveness of this patch, it's almost unreadable. It may be easier to review after it's applied to the tree. Also, it deserves some serious review and testing for correctness and error-handling abilities.
Comments on this approach are welcome too, of course.
up to here no real comment about the libxml2 API usage :-)
+char *device_to_xml(struct virt_device *dev) +{ [...] + doc = xmlNewDoc(BAD_CAST "1.0"); + if (doc == NULL) + goto out; + root = xmlNewNode(NULL, BAD_CAST "tmp"); + if (root == NULL) + goto out;
okay you need to build a root, surprizing but okay [...]
+ msg = func(root, dominfo); + if (msg != NULL) { + CU_DEBUG("Failed to create device XML: %s", msg); + goto out; + } + + xmlDocSetRootElement(doc, root->children); + + xmlDocDumpFormatMemory(doc, &_xml, &xml_size, 1); + xml = strdup((char *)_xml); + xmlFree(_xml);
ouch it hurts a bit. In general I would rather suggest to use the new xmlsave APIs http://xmlsoft.org/html/libxml-xmlsave.html since you rely on the indenting, and hence some of the saving options - create an xmlBufferPtr (xmlNewBuffer IIRC) - http://xmlsoft.org/html/libxml-xmlsave.html#xmlSaveToBuffer with XML_SAVE_FORMAT option - http://xmlsoft.org/html/libxml-xmlsave.html#xmlSaveTree - http://xmlsoft.org/html/libxml-xmlsave.html#xmlSaveClose - then grab the string from the buffer and free the buffer it's a bit more complex but gives you more control over the saving in the long run, which may be useful. Could be encapsulated as a generic node serialization routine if you plan to do this many times.
+ xmlDocDumpFormatMemory(doc, &_xml, &xml_len, 1); + if (_xml == NULL) + goto out; + + xml = strdup((char *)_xml); + if (xml == NULL) + msg = "Out of memory generating XML"; + else + msg = NULL;
similar here but with http://xmlsoft.org/html/libxml-xmlsave.html#xmlSaveDoc instead of xmlSaveTree() yours :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

DV> - http://xmlsoft.org/html/libxml-xmlsave.html#xmlSaveTree The documentation says that function is not yet implemented, and it appears to be correct :) Any reason not to use xmlSaveDoc() here as well? -- Dan Smith IBM Linux Technology Center Open Hypervisor Team email: danms@us.ibm.com

On Tue, Dec 02, 2008 at 10:31:52AM -0800, Dan Smith wrote:
DV> - http://xmlsoft.org/html/libxml-xmlsave.html#xmlSaveTree
The documentation says that function is not yet implemented, and it appears to be correct :)
well it just misses the number of bytes output, which I guess you can ignore just fine :-) Unless you have a very old libxml2 which would not export xmlSaveTree, but that sounds unlikely.
Any reason not to use xmlSaveDoc() here as well?
IIRC you have a root node called <tmp> and what you really want to to is serialize the subtree under tmp, so xmlSaveTree() sounds the right API to use in the first case. Also note that xmlSaveDoc has the same defect as xmlSaveTree(), but that's not a problem (for example you can get the lenght from the buffer directly. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

DV> well it just misses the number of bytes output, which I guess DV> you can ignore just fine :-) Unless you have a very old libxml2 DV> which would not export xmlSaveTree, but that sounds unlikely. Ah, okay. I wasn't getting any output in the buffer either, but that's because I hadn't done an xmlSaveClose() yet, so I was too hasty in assuming that it was unimplemented. Replacement patch on the way. Thanks for the feedback! -- Dan Smith IBM Linux Technology Center Open Hypervisor Team email: danms@us.ibm.com
participants (2)
-
Dan Smith
-
Daniel Veillard