/* * xml.c: XML based interfaces for the libvir library * * Copyright (C) 2005 Red Hat, Inc. * * See COPYING.LIB for the License of this software * * Daniel Veillard */ #include "libvirt/libvirt.h" #include #include #include #include #include #include #include #include #include "internal.h" #include "hash.h" #include "sexpr.h" #include "xml.h" static void virXMLError(virErrorNumber error, const char *info, int value) { const char *errmsg; if (error == VIR_ERR_OK) return; errmsg = __virErrorMsg(error, info); __virRaiseError(NULL, NULL, VIR_FROM_XML, error, VIR_ERR_ERROR, errmsg, info, NULL, value, 0, errmsg, info, value); } /** * virBufferGrow: * @buf: the buffer * @len: the minimum free size to allocate * * Grow the available space of an XML buffer. * * Returns the new available space or -1 in case of error */ static int virBufferGrow(virBufferPtr buf, unsigned int len) { int size; char *newbuf; if (buf == NULL) return (-1); if (len + buf->use < buf->size) return (0); size = buf->use + len + 1000; newbuf = (char *) realloc(buf->content, size); if (newbuf == NULL) { virXMLError(VIR_ERR_NO_MEMORY, "growing buffer", size); return (-1); } buf->content = newbuf; buf->size = size; return (buf->size - buf->use); } /** * virBufferAdd: * @buf: the buffer to dump * @str: the string * @len: the number of bytes to add * * Add a string range to an XML buffer. if len == -1, the length of * str is recomputed to the full string. * * Returns 0 successful, -1 in case of internal or API error. */ int virBufferAdd(virBufferPtr buf, const char *str, int len) { unsigned int needSize; if ((str == NULL) || (buf == NULL)) { return -1; } if (len == 0) return 0; if (len < 0) len = strlen(str); needSize = buf->use + len + 2; if (needSize > buf->size) { if (!virBufferGrow(buf, needSize)) { return (-1); } } /* XXX: memmove() is 2x slower than memcpy(), do we really need it? */ memmove(&buf->content[buf->use], str, len); buf->use += len; buf->content[buf->use] = 0; return (0); } virBufferPtr virBufferNew(unsigned int size) { virBufferPtr buf; if (!(buf = malloc(sizeof(*buf)))) { virXMLError(VIR_ERR_NO_MEMORY, "allocate new buffer", sizeof(*buf)); return NULL; } if (size && (buf->content = malloc(size))==NULL) { virXMLError(VIR_ERR_NO_MEMORY, "allocate buffer content", size); free(buf); return NULL; } buf->size = size; buf->use = 0; return buf; } void virBufferFree(virBufferPtr buf) { if (buf) { if (buf->content) free(buf->content); free(buf); } } /** * virBufferVSprintf: * @buf: the buffer to dump * @format: the format * @argptr: the variable list of arguments * * Do a formatted print to an XML buffer. * * Returns 0 successful, -1 in case of internal or API error. */ int virBufferVSprintf(virBufferPtr buf, const char *format, ...) { int size, count; va_list locarg, argptr; if ((format == NULL) || (buf == NULL)) { return (-1); } size = buf->size - buf->use - 1; va_start(argptr, format); va_copy(locarg, argptr); while (((count = vsnprintf(&buf->content[buf->use], size, format, locarg)) < 0) || (count >= size - 1)) { buf->content[buf->use] = 0; va_end(locarg); if (virBufferGrow(buf, 1000) < 0) { return (-1); } size = buf->size - buf->use - 1; va_copy(locarg, argptr); } va_end(locarg); buf->use += count; buf->content[buf->use] = 0; return (0); } /** * virBufferStrcat: * @buf: the buffer to dump * @argptr: the variable list of strings, the last argument must be NULL * * Concatenate strings to an XML buffer. * * Returns 0 successful, -1 in case of internal or API error. */ int virBufferStrcat(virBufferPtr buf, ...) { va_list ap; char *str; va_start(ap, buf); while ((str = va_arg(ap, char *)) != NULL) { unsigned int len = strlen(str); unsigned int needSize = buf->use + len + 2; if (needSize > buf->size) { if (!virBufferGrow(buf, needSize)) return -1; } memcpy(&buf->content[buf->use], str, len); buf->use += len; buf->content[buf->use] = 0; } va_end(ap); return 0; } #if 0 /* * This block of function are now implemented by a xend poll in * xend_internal.c instead of querying the Xen store, code is kept * for reference of in case Xend may not be available in the future ... */ /** * virDomainGetXMLDevice: * @domain: a domain object * @sub: the xenstore subsection 'vbd', 'vif', ... * @dev: the xenstrore internal device number * @name: the value's name * * Extract one information the device used by the domain from xensttore * * Returns the new string or NULL in case of error */ static char * virDomainGetXMLDeviceInfo(virDomainPtr domain, const char *sub, long dev, const char *name) { char s[256]; unsigned int len = 0; snprintf(s, 255, "/local/domain/0/backend/%s/%d/%ld/%s", sub, domain->handle, dev, name); s[255] = 0; return xs_read(domain->conn->xshandle, 0, &s[0], &len); } /** * virDomainGetXMLDevice: * @domain: a domain object * @buf: the output buffer object * @dev: the xenstrore internal device number * * Extract and dump in the buffer informations on the device used by the domain * * Returns 0 in case of success, -1 in case of failure */ static int virDomainGetXMLDevice(virDomainPtr domain, virBufferPtr buf, long dev) { char *type, *val; type = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "type"); if (type == NULL) return (-1); if (!strcmp(type, "file")) { virBufferVSprintf(buf, " \n"); val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "params"); if (val != NULL) { virBufferVSprintf(buf, " \n", val); free(val); } val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "dev"); if (val != NULL) { virBufferVSprintf(buf, " \n", val); free(val); } val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "read-only"); if (val != NULL) { virBufferVSprintf(buf, " \n", val); free(val); } virBufferAdd(buf, " \n", 12); } else if (!strcmp(type, "phy")) { virBufferVSprintf(buf, " \n"); val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "params"); if (val != NULL) { virBufferVSprintf(buf, " \n", val); free(val); } val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "dev"); if (val != NULL) { virBufferVSprintf(buf, " \n", val); free(val); } val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "read-only"); if (val != NULL) { virBufferVSprintf(buf, " \n", val); free(val); } virBufferAdd(buf, " \n", 12); } else { TODO fprintf(stderr, "Don't know how to handle device type %s\n", type); } free(type); return (0); } /** * virDomainGetXMLDevices: * @domain: a domain object * @buf: the output buffer object * * Extract the devices used by the domain and dumps then in the buffer * * Returns 0 in case of success, -1 in case of failure */ static int virDomainGetXMLDevices(virDomainPtr domain, virBufferPtr buf) { int ret = -1; unsigned int num, i; long id; char **list = NULL, *endptr; char backend[200]; virConnectPtr conn; if (!VIR_IS_CONNECTED_DOMAIN(domain)) return (-1); conn = domain->conn; snprintf(backend, 199, "/local/domain/0/backend/vbd/%d", virDomainGetID(domain)); backend[199] = 0; list = xs_directory(conn->xshandle, 0, backend, &num); ret = 0; if (list == NULL) goto done; for (i = 0; i < num; i++) { id = strtol(list[i], &endptr, 10); if ((endptr == list[i]) || (*endptr != 0)) { ret = -1; goto done; } virDomainGetXMLDevice(domain, buf, id); } done: if (list != NULL) free(list); return (ret); } /** * virDomainGetXMLInterface: * @domain: a domain object * @buf: the output buffer object * @dev: the xenstrore internal device number * * Extract and dump in the buffer informations on the interface used by * the domain * * Returns 0 in case of success, -1 in case of failure */ static int virDomainGetXMLInterface(virDomainPtr domain, virBufferPtr buf, long dev) { char *type, *val; type = virDomainGetXMLDeviceInfo(domain, "vif", dev, "bridge"); if (type == NULL) { virBufferVSprintf(buf, " \n"); val = virDomainGetXMLDeviceInfo(domain, "vif", dev, "mac"); if (val != NULL) { virBufferVSprintf(buf, " \n", val); free(val); } val = virDomainGetXMLDeviceInfo(domain, "vif", dev, "script"); if (val != NULL) { virBufferVSprintf(buf, "