2005-12-13 16:22:05 +00:00
|
|
|
/*
|
|
|
|
* 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 <veillard@redhat.com>
|
|
|
|
*/
|
|
|
|
|
2006-06-26 15:02:18 +00:00
|
|
|
#include "libvirt/libvirt.h"
|
2005-12-13 16:22:05 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <xs.h>
|
2006-02-16 22:50:52 +00:00
|
|
|
#include <libxml/parser.h>
|
|
|
|
#include <libxml/tree.h>
|
|
|
|
#include <libxml/xpath.h>
|
2005-12-13 16:22:05 +00:00
|
|
|
#include "internal.h"
|
|
|
|
#include "hash.h"
|
2006-02-20 17:22:16 +00:00
|
|
|
#include "sexpr.h"
|
2006-02-16 22:50:52 +00:00
|
|
|
#include "xml.h"
|
2005-12-13 16:22:05 +00:00
|
|
|
|
2006-02-27 22:32:54 +00:00
|
|
|
static void
|
2006-03-15 12:13:25 +00:00
|
|
|
virXMLError(virErrorNumber error, const char *info, int value)
|
|
|
|
{
|
2006-02-27 22:32:54 +00:00
|
|
|
const char *errmsg;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2006-02-27 22:32:54 +00:00
|
|
|
if (error == VIR_ERR_OK)
|
|
|
|
return;
|
|
|
|
|
|
|
|
errmsg = __virErrorMsg(error, info);
|
|
|
|
__virRaiseError(NULL, NULL, VIR_FROM_XML, error, VIR_ERR_ERROR,
|
2006-03-15 12:13:25 +00:00
|
|
|
errmsg, info, NULL, value, 0, errmsg, info, value);
|
2006-02-27 22:32:54 +00:00
|
|
|
}
|
|
|
|
|
2005-12-13 16:22:05 +00:00
|
|
|
/**
|
|
|
|
* 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
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferGrow(virBufferPtr buf, unsigned int len)
|
|
|
|
{
|
2005-12-13 16:22:05 +00:00
|
|
|
int size;
|
|
|
|
char *newbuf;
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
if (buf == NULL)
|
|
|
|
return (-1);
|
|
|
|
if (len + buf->use < buf->size)
|
|
|
|
return (0);
|
2005-12-13 16:22:05 +00:00
|
|
|
|
|
|
|
size = buf->use + len + 1000;
|
|
|
|
|
|
|
|
newbuf = (char *) realloc(buf->content, size);
|
|
|
|
if (newbuf == NULL) {
|
2006-02-27 22:32:54 +00:00
|
|
|
virXMLError(VIR_ERR_NO_MEMORY, "growing buffer", size);
|
2006-03-15 12:13:25 +00:00
|
|
|
return (-1);
|
2005-12-13 16:22:05 +00:00
|
|
|
}
|
|
|
|
buf->content = newbuf;
|
|
|
|
buf->size = size;
|
2006-03-15 12:13:25 +00:00
|
|
|
return (buf->size - buf->use);
|
2005-12-13 16:22:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2006-02-20 17:22:16 +00:00
|
|
|
int
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferAdd(virBufferPtr buf, const char *str, int len)
|
|
|
|
{
|
2005-12-13 16:22:05 +00:00
|
|
|
unsigned int needSize;
|
|
|
|
|
|
|
|
if ((str == NULL) || (buf == NULL)) {
|
2006-03-15 12:13:25 +00:00
|
|
|
return -1;
|
2005-12-13 16:22:05 +00:00
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
if (len == 0)
|
|
|
|
return 0;
|
2005-12-13 16:22:05 +00:00
|
|
|
|
|
|
|
if (len < 0)
|
|
|
|
len = strlen(str);
|
|
|
|
|
|
|
|
needSize = buf->use + len + 2;
|
2006-03-15 12:13:25 +00:00
|
|
|
if (needSize > buf->size) {
|
|
|
|
if (!virBufferGrow(buf, needSize)) {
|
|
|
|
return (-1);
|
2005-12-13 16:22:05 +00:00
|
|
|
}
|
|
|
|
}
|
2006-05-10 12:15:49 +00:00
|
|
|
/* XXX: memmove() is 2x slower than memcpy(), do we really need it? */
|
2005-12-13 16:22:05 +00:00
|
|
|
memmove(&buf->content[buf->use], str, len);
|
|
|
|
buf->use += len;
|
|
|
|
buf->content[buf->use] = 0;
|
2006-03-15 12:13:25 +00:00
|
|
|
return (0);
|
2005-12-13 16:22:05 +00:00
|
|
|
}
|
|
|
|
|
2006-05-10 12:15:49 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-05-09 15:35:46 +00:00
|
|
|
void
|
|
|
|
virBufferFree(virBufferPtr buf)
|
|
|
|
{
|
|
|
|
if (buf) {
|
2006-05-10 12:15:49 +00:00
|
|
|
if (buf->content)
|
|
|
|
free(buf->content);
|
|
|
|
free(buf);
|
2006-05-09 15:35:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-13 16:22:05 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2006-02-20 17:22:16 +00:00
|
|
|
int
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferVSprintf(virBufferPtr buf, const char *format, ...)
|
|
|
|
{
|
2005-12-13 16:22:05 +00:00
|
|
|
int size, count;
|
|
|
|
va_list locarg, argptr;
|
|
|
|
|
|
|
|
if ((format == NULL) || (buf == NULL)) {
|
2006-03-15 12:13:25 +00:00
|
|
|
return (-1);
|
2005-12-13 16:22:05 +00:00
|
|
|
}
|
|
|
|
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)) {
|
2006-03-15 12:13:25 +00:00
|
|
|
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);
|
2005-12-13 16:22:05 +00:00
|
|
|
}
|
|
|
|
va_end(locarg);
|
|
|
|
buf->use += count;
|
|
|
|
buf->content[buf->use] = 0;
|
2006-03-15 12:13:25 +00:00
|
|
|
return (0);
|
2005-12-13 16:22:05 +00:00
|
|
|
}
|
|
|
|
|
2006-05-10 12:15:49 +00:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2006-02-20 17:22:16 +00:00
|
|
|
#if 0
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2006-02-20 17:22:16 +00:00
|
|
|
/*
|
|
|
|
* 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 ...
|
|
|
|
*/
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-14 11:21:05 +00:00
|
|
|
/**
|
|
|
|
* 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 *
|
2006-03-15 12:13:25 +00:00
|
|
|
virDomainGetXMLDeviceInfo(virDomainPtr domain, const char *sub,
|
|
|
|
long dev, const char *name)
|
|
|
|
{
|
2005-12-14 11:21:05 +00:00
|
|
|
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;
|
|
|
|
|
2006-01-27 08:59:42 +00:00
|
|
|
return xs_read(domain->conn->xshandle, 0, &s[0], &len);
|
2005-12-14 11:21:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2006-03-15 12:13:25 +00:00
|
|
|
virDomainGetXMLDevice(virDomainPtr domain, virBufferPtr buf, long dev)
|
|
|
|
{
|
2005-12-14 11:21:05 +00:00
|
|
|
char *type, *val;
|
|
|
|
|
|
|
|
type = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "type");
|
|
|
|
if (type == NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (-1);
|
2005-12-14 11:21:05 +00:00
|
|
|
if (!strcmp(type, "file")) {
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferVSprintf(buf, " <disk type='file'>\n");
|
|
|
|
val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "params");
|
|
|
|
if (val != NULL) {
|
|
|
|
virBufferVSprintf(buf, " <source file='%s'/>\n", val);
|
|
|
|
free(val);
|
|
|
|
}
|
|
|
|
val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "dev");
|
|
|
|
if (val != NULL) {
|
|
|
|
virBufferVSprintf(buf, " <target dev='%s'/>\n", val);
|
|
|
|
free(val);
|
|
|
|
}
|
|
|
|
val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "read-only");
|
|
|
|
if (val != NULL) {
|
|
|
|
virBufferVSprintf(buf, " <readonly/>\n", val);
|
|
|
|
free(val);
|
|
|
|
}
|
|
|
|
virBufferAdd(buf, " </disk>\n", 12);
|
2005-12-14 12:36:43 +00:00
|
|
|
} else if (!strcmp(type, "phy")) {
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferVSprintf(buf, " <disk type='device'>\n");
|
|
|
|
val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "params");
|
|
|
|
if (val != NULL) {
|
|
|
|
virBufferVSprintf(buf, " <source device='%s'/>\n", val);
|
|
|
|
free(val);
|
|
|
|
}
|
|
|
|
val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "dev");
|
|
|
|
if (val != NULL) {
|
|
|
|
virBufferVSprintf(buf, " <target dev='%s'/>\n", val);
|
|
|
|
free(val);
|
|
|
|
}
|
|
|
|
val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "read-only");
|
|
|
|
if (val != NULL) {
|
|
|
|
virBufferVSprintf(buf, " <readonly/>\n", val);
|
|
|
|
free(val);
|
|
|
|
}
|
|
|
|
virBufferAdd(buf, " </disk>\n", 12);
|
2005-12-14 11:21:05 +00:00
|
|
|
} else {
|
2006-03-15 12:13:25 +00:00
|
|
|
TODO fprintf(stderr, "Don't know how to handle device type %s\n",
|
|
|
|
type);
|
2005-12-14 11:21:05 +00:00
|
|
|
}
|
|
|
|
free(type);
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
return (0);
|
2005-12-14 11:21:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2006-03-15 12:13:25 +00:00
|
|
|
virDomainGetXMLDevices(virDomainPtr domain, virBufferPtr buf)
|
|
|
|
{
|
2005-12-14 11:21:05 +00:00
|
|
|
int ret = -1;
|
|
|
|
unsigned int num, i;
|
|
|
|
long id;
|
|
|
|
char **list = NULL, *endptr;
|
|
|
|
char backend[200];
|
|
|
|
virConnectPtr conn;
|
|
|
|
|
2005-12-16 18:41:46 +00:00
|
|
|
if (!VIR_IS_CONNECTED_DOMAIN(domain))
|
2006-03-15 12:13:25 +00:00
|
|
|
return (-1);
|
|
|
|
|
2005-12-14 11:21:05 +00:00
|
|
|
conn = domain->conn;
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
snprintf(backend, 199, "/local/domain/0/backend/vbd/%d",
|
2005-12-14 11:21:05 +00:00
|
|
|
virDomainGetID(domain));
|
|
|
|
backend[199] = 0;
|
2006-01-27 08:59:42 +00:00
|
|
|
list = xs_directory(conn->xshandle, 0, backend, &num);
|
2005-12-14 11:21:05 +00:00
|
|
|
ret = 0;
|
|
|
|
if (list == NULL)
|
|
|
|
goto done;
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
for (i = 0; i < num; i++) {
|
2005-12-14 11:21:05 +00:00
|
|
|
id = strtol(list[i], &endptr, 10);
|
2006-03-15 12:13:25 +00:00
|
|
|
if ((endptr == list[i]) || (*endptr != 0)) {
|
|
|
|
ret = -1;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
virDomainGetXMLDevice(domain, buf, id);
|
2005-12-14 11:21:05 +00:00
|
|
|
}
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
done:
|
2005-12-14 11:21:05 +00:00
|
|
|
if (list != NULL)
|
|
|
|
free(list);
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
return (ret);
|
2005-12-14 11:21:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2006-03-15 12:13:25 +00:00
|
|
|
virDomainGetXMLInterface(virDomainPtr domain, virBufferPtr buf, long dev)
|
|
|
|
{
|
2005-12-14 11:21:05 +00:00
|
|
|
char *type, *val;
|
|
|
|
|
|
|
|
type = virDomainGetXMLDeviceInfo(domain, "vif", dev, "bridge");
|
|
|
|
if (type == NULL) {
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferVSprintf(buf, " <interface type='default'>\n");
|
|
|
|
val = virDomainGetXMLDeviceInfo(domain, "vif", dev, "mac");
|
|
|
|
if (val != NULL) {
|
|
|
|
virBufferVSprintf(buf, " <mac address='%s'/>\n", val);
|
|
|
|
free(val);
|
|
|
|
}
|
|
|
|
val = virDomainGetXMLDeviceInfo(domain, "vif", dev, "script");
|
|
|
|
if (val != NULL) {
|
|
|
|
virBufferVSprintf(buf, " <script path='%s'/>\n", val);
|
|
|
|
free(val);
|
|
|
|
}
|
|
|
|
virBufferAdd(buf, " </interface>\n", 17);
|
2005-12-14 11:21:05 +00:00
|
|
|
} else {
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferVSprintf(buf, " <interface type='bridge'>\n");
|
|
|
|
virBufferVSprintf(buf, " <source bridge='%s'/>\n", type);
|
|
|
|
val = virDomainGetXMLDeviceInfo(domain, "vif", dev, "mac");
|
|
|
|
if (val != NULL) {
|
|
|
|
virBufferVSprintf(buf, " <mac address='%s'/>\n", val);
|
|
|
|
free(val);
|
|
|
|
}
|
|
|
|
val = virDomainGetXMLDeviceInfo(domain, "vif", dev, "script");
|
|
|
|
if (val != NULL) {
|
|
|
|
virBufferVSprintf(buf, " <script path='%s'/>\n", val);
|
|
|
|
free(val);
|
|
|
|
}
|
|
|
|
virBufferAdd(buf, " </interface>\n", 17);
|
2005-12-14 11:21:05 +00:00
|
|
|
}
|
|
|
|
free(type);
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
return (0);
|
2005-12-14 11:21:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virDomainGetXMLInterfaces:
|
|
|
|
* @domain: a domain object
|
|
|
|
* @buf: the output buffer object
|
|
|
|
*
|
|
|
|
* Extract the interfaces used by the domain and dumps then in the buffer
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, -1 in case of failure
|
|
|
|
*/
|
|
|
|
static int
|
2006-03-15 12:13:25 +00:00
|
|
|
virDomainGetXMLInterfaces(virDomainPtr domain, virBufferPtr buf)
|
|
|
|
{
|
2005-12-14 11:21:05 +00:00
|
|
|
int ret = -1;
|
|
|
|
unsigned int num, i;
|
|
|
|
long id;
|
|
|
|
char **list = NULL, *endptr;
|
|
|
|
char backend[200];
|
|
|
|
virConnectPtr conn;
|
|
|
|
|
2005-12-16 18:41:46 +00:00
|
|
|
if (!VIR_IS_CONNECTED_DOMAIN(domain))
|
2006-03-15 12:13:25 +00:00
|
|
|
return (-1);
|
|
|
|
|
2005-12-14 11:21:05 +00:00
|
|
|
conn = domain->conn;
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
snprintf(backend, 199, "/local/domain/0/backend/vif/%d",
|
2005-12-14 11:21:05 +00:00
|
|
|
virDomainGetID(domain));
|
|
|
|
backend[199] = 0;
|
2006-01-27 08:59:42 +00:00
|
|
|
list = xs_directory(conn->xshandle, 0, backend, &num);
|
2005-12-14 11:21:05 +00:00
|
|
|
ret = 0;
|
|
|
|
if (list == NULL)
|
|
|
|
goto done;
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
for (i = 0; i < num; i++) {
|
2005-12-14 11:21:05 +00:00
|
|
|
id = strtol(list[i], &endptr, 10);
|
2006-03-15 12:13:25 +00:00
|
|
|
if ((endptr == list[i]) || (*endptr != 0)) {
|
|
|
|
ret = -1;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
virDomainGetXMLInterface(domain, buf, id);
|
2005-12-14 11:21:05 +00:00
|
|
|
}
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
done:
|
2005-12-14 11:21:05 +00:00
|
|
|
if (list != NULL)
|
|
|
|
free(list);
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
return (ret);
|
2005-12-14 11:21:05 +00:00
|
|
|
}
|
|
|
|
|
2005-12-16 00:51:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2005-12-14 15:29:16 +00:00
|
|
|
/**
|
|
|
|
* virDomainGetXMLBoot:
|
|
|
|
* @domain: a domain object
|
|
|
|
* @buf: the output buffer object
|
|
|
|
*
|
|
|
|
* Extract the boot informations used to start that domain
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, -1 in case of failure
|
|
|
|
*/
|
|
|
|
static int
|
2006-03-15 12:13:25 +00:00
|
|
|
virDomainGetXMLBoot(virDomainPtr domain, virBufferPtr buf)
|
|
|
|
{
|
2005-12-14 15:29:16 +00:00
|
|
|
char *vm, *str;
|
|
|
|
|
2005-12-16 18:41:46 +00:00
|
|
|
if (!VIR_IS_DOMAIN(domain))
|
2006-03-15 12:13:25 +00:00
|
|
|
return (-1);
|
|
|
|
|
2005-12-16 00:51:27 +00:00
|
|
|
vm = virDomainGetVM(domain);
|
2005-12-14 15:29:16 +00:00
|
|
|
if (vm == NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (-1);
|
2005-12-14 15:29:16 +00:00
|
|
|
|
|
|
|
virBufferAdd(buf, " <os>\n", 7);
|
|
|
|
str = virDomainGetVMInfo(domain, vm, "image/ostype");
|
|
|
|
if (str != NULL) {
|
|
|
|
virBufferVSprintf(buf, " <type>%s</type>\n", str);
|
|
|
|
free(str);
|
|
|
|
}
|
|
|
|
str = virDomainGetVMInfo(domain, vm, "image/kernel");
|
|
|
|
if (str != NULL) {
|
|
|
|
virBufferVSprintf(buf, " <kernel>%s</kernel>\n", str);
|
|
|
|
free(str);
|
|
|
|
}
|
|
|
|
str = virDomainGetVMInfo(domain, vm, "image/ramdisk");
|
|
|
|
if (str != NULL) {
|
2006-03-15 12:13:25 +00:00
|
|
|
if (str[0] != 0)
|
|
|
|
virBufferVSprintf(buf, " <initrd>%s</initrd>\n", str);
|
2005-12-14 15:29:16 +00:00
|
|
|
free(str);
|
|
|
|
}
|
|
|
|
str = virDomainGetVMInfo(domain, vm, "image/cmdline");
|
|
|
|
if (str != NULL) {
|
2006-03-15 12:13:25 +00:00
|
|
|
if (str[0] != 0)
|
|
|
|
virBufferVSprintf(buf, " <cmdline>%s</cmdline>\n", str);
|
2005-12-14 15:29:16 +00:00
|
|
|
free(str);
|
|
|
|
}
|
|
|
|
virBufferAdd(buf, " </os>\n", 8);
|
|
|
|
|
|
|
|
free(vm);
|
2006-03-15 12:13:25 +00:00
|
|
|
return (0);
|
2005-12-14 15:29:16 +00:00
|
|
|
}
|
|
|
|
|
2005-12-13 16:22:05 +00:00
|
|
|
/**
|
|
|
|
* virDomainGetXMLDesc:
|
|
|
|
* @domain: a domain object
|
|
|
|
* @flags: and OR'ed set of extraction flags, not used yet
|
|
|
|
*
|
|
|
|
* Provide an XML description of the domain. NOTE: this API is subject
|
|
|
|
* to changes.
|
|
|
|
*
|
|
|
|
* Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
|
|
|
|
* the caller must free() the returned value.
|
|
|
|
*/
|
|
|
|
char *
|
2006-03-15 12:13:25 +00:00
|
|
|
virDomainGetXMLDesc(virDomainPtr domain, int flags)
|
|
|
|
{
|
2005-12-13 16:22:05 +00:00
|
|
|
char *ret = NULL;
|
2006-04-27 14:14:23 +00:00
|
|
|
unsigned char uuid[16];
|
2005-12-13 16:22:05 +00:00
|
|
|
virBuffer buf;
|
|
|
|
virDomainInfo info;
|
|
|
|
|
2005-12-16 18:41:46 +00:00
|
|
|
if (!VIR_IS_DOMAIN(domain))
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
2005-12-16 18:41:46 +00:00
|
|
|
if (flags != 0)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
2005-12-13 16:22:05 +00:00
|
|
|
if (virDomainGetInfo(domain, &info) < 0)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
2005-12-13 16:22:05 +00:00
|
|
|
|
|
|
|
ret = malloc(1000);
|
|
|
|
if (ret == NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
2005-12-13 16:22:05 +00:00
|
|
|
buf.content = ret;
|
|
|
|
buf.size = 1000;
|
|
|
|
buf.use = 0;
|
|
|
|
|
|
|
|
virBufferVSprintf(&buf, "<domain type='xen' id='%d'>\n",
|
|
|
|
virDomainGetID(domain));
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferVSprintf(&buf, " <name>%s</name>\n",
|
|
|
|
virDomainGetName(domain));
|
2006-04-27 14:14:23 +00:00
|
|
|
if (virDomainGetUUID(domain, &uuid[0]) == 0) {
|
|
|
|
virBufferVSprintf(&buf,
|
|
|
|
" <uuid>%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x</uuid>\n",
|
|
|
|
uuid[0], uuid[1], uuid[2], uuid[3],
|
|
|
|
uuid[4], uuid[5], uuid[6], uuid[7],
|
|
|
|
uuid[8], uuid[9], uuid[10], uuid[11],
|
|
|
|
uuid[12], uuid[13], uuid[14], uuid[15]);
|
|
|
|
}
|
2005-12-14 15:29:16 +00:00
|
|
|
virDomainGetXMLBoot(domain, &buf);
|
2005-12-14 11:21:05 +00:00
|
|
|
virBufferVSprintf(&buf, " <memory>%lu</memory>\n", info.maxMem);
|
|
|
|
virBufferVSprintf(&buf, " <vcpu>%d</vcpu>\n", (int) info.nrVirtCpu);
|
|
|
|
virBufferAdd(&buf, " <devices>\n", 12);
|
|
|
|
virDomainGetXMLDevices(domain, &buf);
|
|
|
|
virDomainGetXMLInterfaces(domain, &buf);
|
|
|
|
virBufferAdd(&buf, " </devices>\n", 13);
|
2005-12-13 16:22:05 +00:00
|
|
|
virBufferAdd(&buf, "</domain>\n", 10);
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2005-12-13 16:22:05 +00:00
|
|
|
buf.content[buf.use] = 0;
|
2006-03-15 12:13:25 +00:00
|
|
|
return (ret);
|
2005-12-13 16:22:05 +00:00
|
|
|
}
|
2006-02-16 22:50:52 +00:00
|
|
|
|
2006-02-20 17:22:16 +00:00
|
|
|
#endif
|
|
|
|
|
2006-02-16 22:50:52 +00:00
|
|
|
/**
|
2006-07-10 11:21:24 +00:00
|
|
|
* virDomainParseXMLOSDescHVM:
|
|
|
|
* @node: node containing HVM OS description
|
2006-02-16 22:50:52 +00:00
|
|
|
* @buf: a buffer for the result S-Expr
|
2006-07-10 11:21:24 +00:00
|
|
|
* @ctxt: a path context representing the XML description
|
2006-02-16 22:50:52 +00:00
|
|
|
*
|
2006-07-10 11:21:24 +00:00
|
|
|
* Parse the OS part of the XML description for an HVM domain and add it to
|
|
|
|
* the S-Expr in buf. This is a temporary interface as the S-Expr interface
|
2006-02-16 22:50:52 +00:00
|
|
|
* will be replaced by XML-RPC in the future. However the XML format should
|
|
|
|
* stay valid over time.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, -1 in case of error.
|
|
|
|
*/
|
|
|
|
static int
|
2006-07-10 11:21:24 +00:00
|
|
|
virDomainParseXMLOSDescHVM(xmlNodePtr node, virBufferPtr buf, xmlXPathContextPtr ctxt)
|
|
|
|
{
|
|
|
|
xmlXPathObjectPtr obj = NULL;
|
|
|
|
xmlNodePtr cur, txt;
|
|
|
|
const xmlChar *type = NULL;
|
|
|
|
const xmlChar *loader = NULL;
|
|
|
|
const xmlChar *dev_model = NULL;
|
|
|
|
const xmlChar *boot_dev = NULL;
|
|
|
|
xmlChar *graphics_type = NULL;
|
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
|
|
|
if ((type == NULL)
|
|
|
|
&& (xmlStrEqual(cur->name, BAD_CAST "type"))) {
|
|
|
|
txt = cur->children;
|
|
|
|
if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
|
|
|
|
(txt->next == NULL))
|
|
|
|
type = txt->content;
|
|
|
|
} else if ((loader == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "loader"))) {
|
|
|
|
txt = cur->children;
|
|
|
|
if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
|
|
|
|
(txt->next == NULL))
|
|
|
|
loader = txt->content;
|
|
|
|
} else if ((boot_dev == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "boot"))) {
|
|
|
|
boot_dev = xmlGetProp(cur, BAD_CAST "dev");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
if ((type == NULL) || (!xmlStrEqual(type, BAD_CAST "hvm"))) {
|
|
|
|
/* VIR_ERR_OS_TYPE */
|
|
|
|
virXMLError(VIR_ERR_OS_TYPE, (const char *) type, 0);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
virBufferAdd(buf, "(image (hvm ", 12);
|
|
|
|
if (loader == NULL) {
|
|
|
|
virXMLError(VIR_ERR_NO_KERNEL, NULL, 0);
|
|
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
virBufferVSprintf(buf, "(kernel '%s')", (const char *) loader);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get the device emulation model */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/devices/emulator[1])", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
|
|
|
virXMLError(VIR_ERR_NO_KERNEL, NULL, 0); /* TODO: error */
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferVSprintf(buf, "(device_model '%s')",
|
|
|
|
(const char *) obj->stringval);
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
obj = NULL;
|
|
|
|
|
|
|
|
if (boot_dev) {
|
|
|
|
/* TODO:
|
|
|
|
* Have to figure out the naming used here.
|
|
|
|
*/
|
|
|
|
if (xmlStrEqual(type, BAD_CAST "hda")) {
|
|
|
|
virBufferVSprintf(buf, "(boot a)", (const char *) boot_dev);
|
|
|
|
} else if (xmlStrEqual(type, BAD_CAST "hdd")) {
|
|
|
|
virBufferVSprintf(buf, "(boot d)", (const char *) boot_dev);
|
|
|
|
} else {
|
|
|
|
/* Force hd[b|c] if boot_dev specified but not floppy or cdrom? */
|
|
|
|
virBufferVSprintf(buf, "(boot c)", (const char *) boot_dev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* TODO:
|
|
|
|
* Is a cdrom disk device specified?
|
|
|
|
* Kind of ugly since it is buried in the devices/diskk node.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Is a graphics device specified? */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "/domain/devices/graphics[1]", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
|
|
|
|
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr = 0)) {
|
|
|
|
virXMLError(VIR_ERR_NO_OS, "", 0); /* TODO: error */
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
graphics_type = xmlGetProp(obj->nodesetval->nodeTab[0], BAD_CAST "type");
|
|
|
|
if (graphics_type != NULL) {
|
|
|
|
if (xmlStrEqual(graphics_type, BAD_CAST "sdl")) {
|
|
|
|
virBufferAdd(buf, "(sdl 1)", 7);
|
|
|
|
// TODO:
|
|
|
|
// Need to understand sdl options
|
|
|
|
//
|
|
|
|
//virBufferAdd(buf, "(display localhost:10.0)", 24);
|
|
|
|
//virBufferAdd(buf, "(xauthority /root/.Xauthority)", 30);
|
|
|
|
}
|
|
|
|
else if (xmlStrEqual(graphics_type, BAD_CAST "vnc"))
|
|
|
|
virBufferAdd(buf, "(vnc 1)", 7);
|
|
|
|
xmlFree(graphics_type);
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
virBufferAdd(buf, "))", 2);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
error:
|
|
|
|
if (obj != NULL)
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virDomainParseXMLOSDescPV:
|
|
|
|
* @node: node containing PV OS description
|
|
|
|
* @buf: a buffer for the result S-Expr
|
|
|
|
*
|
|
|
|
* Parse the OS part of the XML description for a paravirtualized domain
|
|
|
|
* and add it to the S-Expr in buf. This is a temporary interface as the
|
|
|
|
* S-Expr interface will be replaced by XML-RPC in the future. However
|
|
|
|
* the XML format should stay valid over time.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, -1 in case of error.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virDomainParseXMLOSDescPV(xmlNodePtr node, virBufferPtr buf)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2006-02-16 22:50:52 +00:00
|
|
|
xmlNodePtr cur, txt;
|
|
|
|
const xmlChar *type = NULL;
|
|
|
|
const xmlChar *root = NULL;
|
|
|
|
const xmlChar *kernel = NULL;
|
|
|
|
const xmlChar *initrd = NULL;
|
|
|
|
const xmlChar *cmdline = NULL;
|
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
2006-03-15 12:13:25 +00:00
|
|
|
if ((type == NULL)
|
|
|
|
&& (xmlStrEqual(cur->name, BAD_CAST "type"))) {
|
|
|
|
txt = cur->children;
|
2006-07-04 12:46:14 +00:00
|
|
|
if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
|
|
|
|
(txt->next == NULL))
|
2006-03-15 12:13:25 +00:00
|
|
|
type = txt->content;
|
|
|
|
} else if ((kernel == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "kernel"))) {
|
|
|
|
txt = cur->children;
|
2006-07-04 12:46:14 +00:00
|
|
|
if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
|
|
|
|
(txt->next == NULL))
|
2006-03-15 12:13:25 +00:00
|
|
|
kernel = txt->content;
|
|
|
|
} else if ((root == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "root"))) {
|
|
|
|
txt = cur->children;
|
2006-07-04 12:46:14 +00:00
|
|
|
if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
|
|
|
|
(txt->next == NULL))
|
2006-03-15 12:13:25 +00:00
|
|
|
root = txt->content;
|
|
|
|
} else if ((initrd == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "initrd"))) {
|
|
|
|
txt = cur->children;
|
2006-07-04 12:46:14 +00:00
|
|
|
if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
|
|
|
|
(txt->next == NULL))
|
2006-03-15 12:13:25 +00:00
|
|
|
initrd = txt->content;
|
|
|
|
} else if ((cmdline == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "cmdline"))) {
|
|
|
|
txt = cur->children;
|
2006-07-04 12:46:14 +00:00
|
|
|
if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
|
|
|
|
(txt->next == NULL))
|
2006-03-15 12:13:25 +00:00
|
|
|
cmdline = txt->content;
|
|
|
|
}
|
|
|
|
}
|
2006-02-16 22:50:52 +00:00
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
if ((type != NULL) && (!xmlStrEqual(type, BAD_CAST "linux"))) {
|
|
|
|
/* VIR_ERR_OS_TYPE */
|
2006-03-15 12:13:25 +00:00
|
|
|
virXMLError(VIR_ERR_OS_TYPE, (const char *) type, 0);
|
|
|
|
return (-1);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
2006-07-05 17:08:40 +00:00
|
|
|
virBufferAdd(buf, "(image (linux ", 14);
|
2006-02-16 22:50:52 +00:00
|
|
|
if (kernel == NULL) {
|
2006-07-05 17:08:40 +00:00
|
|
|
virXMLError(VIR_ERR_NO_KERNEL, NULL, 0);
|
|
|
|
return (-1);
|
2006-03-30 16:08:13 +00:00
|
|
|
} else {
|
|
|
|
virBufferVSprintf(buf, "(kernel '%s')", (const char *) kernel);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
if (initrd != NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferVSprintf(buf, "(ramdisk '%s')", (const char *) initrd);
|
2006-04-26 07:31:16 +00:00
|
|
|
if (root != NULL)
|
2006-02-16 22:50:52 +00:00
|
|
|
virBufferVSprintf(buf, "(root '%s')", (const char *) root);
|
2006-04-26 07:31:16 +00:00
|
|
|
if (cmdline != NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferVSprintf(buf, "(args '%s')", (const char *) cmdline);
|
2006-07-05 17:08:40 +00:00
|
|
|
virBufferAdd(buf, "))", 2);
|
2006-03-15 12:13:25 +00:00
|
|
|
return (0);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virDomainParseXMLDiskDesc:
|
2006-07-10 11:21:24 +00:00
|
|
|
* @node: node containing disk description
|
2006-02-16 22:50:52 +00:00
|
|
|
* @buf: a buffer for the result S-Expr
|
|
|
|
*
|
|
|
|
* Parse the one disk in the XML description and add it to the S-Expr in buf
|
|
|
|
* This is a temporary interface as the S-Expr interface
|
|
|
|
* will be replaced by XML-RPC in the future. However the XML format should
|
|
|
|
* stay valid over time.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, -1 in case of error.
|
|
|
|
*/
|
|
|
|
static int
|
2006-03-15 12:13:25 +00:00
|
|
|
virDomainParseXMLDiskDesc(xmlNodePtr node, virBufferPtr buf)
|
|
|
|
{
|
2006-02-16 22:50:52 +00:00
|
|
|
xmlNodePtr cur;
|
|
|
|
xmlChar *type = NULL;
|
|
|
|
xmlChar *source = NULL;
|
|
|
|
xmlChar *target = NULL;
|
|
|
|
int ro = 0;
|
|
|
|
int typ = 0;
|
|
|
|
|
|
|
|
type = xmlGetProp(node, BAD_CAST "type");
|
|
|
|
if (type != NULL) {
|
2006-03-15 12:13:25 +00:00
|
|
|
if (xmlStrEqual(type, BAD_CAST "file"))
|
|
|
|
typ = 0;
|
|
|
|
else if (xmlStrEqual(type, BAD_CAST "block"))
|
|
|
|
typ = 1;
|
|
|
|
xmlFree(type);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
2006-03-15 12:13:25 +00:00
|
|
|
if ((source == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
|
|
|
|
|
|
|
|
if (typ == 0)
|
|
|
|
source = xmlGetProp(cur, BAD_CAST "file");
|
|
|
|
else
|
|
|
|
source = xmlGetProp(cur, BAD_CAST "dev");
|
|
|
|
} else if ((target == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "target"))) {
|
|
|
|
target = xmlGetProp(cur, BAD_CAST "dev");
|
|
|
|
} else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
|
|
|
|
ro = 1;
|
|
|
|
}
|
|
|
|
}
|
2006-02-16 22:50:52 +00:00
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (source == NULL) {
|
2006-03-15 12:13:25 +00:00
|
|
|
virXMLError(VIR_ERR_NO_SOURCE, (const char *) target, 0);
|
|
|
|
|
|
|
|
if (target != NULL)
|
|
|
|
xmlFree(target);
|
|
|
|
return (-1);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
if (target == NULL) {
|
2006-03-15 12:13:25 +00:00
|
|
|
virXMLError(VIR_ERR_NO_TARGET, (const char *) source, 0);
|
|
|
|
if (source != NULL)
|
|
|
|
xmlFree(source);
|
|
|
|
return (-1);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
virBufferAdd(buf, "(vbd ", 5);
|
2006-07-10 11:21:24 +00:00
|
|
|
virBufferVSprintf(buf, "(dev '%s')", (const char *) target);
|
2006-02-16 22:50:52 +00:00
|
|
|
if (typ == 0)
|
|
|
|
virBufferVSprintf(buf, "(uname 'file:%s')", source);
|
|
|
|
else if (typ == 1) {
|
|
|
|
if (source[0] == '/')
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferVSprintf(buf, "(uname 'phy:%s')", source);
|
|
|
|
else
|
|
|
|
virBufferVSprintf(buf, "(uname 'phy:/dev/%s')", source);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
if (ro == 0)
|
|
|
|
virBufferVSprintf(buf, "(mode 'w')");
|
|
|
|
else if (ro == 1)
|
|
|
|
virBufferVSprintf(buf, "(mode 'r')");
|
|
|
|
|
|
|
|
virBufferAdd(buf, ")", 1);
|
|
|
|
xmlFree(target);
|
|
|
|
xmlFree(source);
|
2006-03-15 12:13:25 +00:00
|
|
|
return (0);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virDomainParseXMLIfDesc:
|
2006-07-10 11:21:24 +00:00
|
|
|
* @node: node containing the interface description
|
2006-02-16 22:50:52 +00:00
|
|
|
* @buf: a buffer for the result S-Expr
|
|
|
|
*
|
|
|
|
* Parse the one interface the XML description and add it to the S-Expr in buf
|
|
|
|
* This is a temporary interface as the S-Expr interface
|
|
|
|
* will be replaced by XML-RPC in the future. However the XML format should
|
|
|
|
* stay valid over time.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, -1 in case of error.
|
|
|
|
*/
|
|
|
|
static int
|
2006-03-15 12:13:25 +00:00
|
|
|
virDomainParseXMLIfDesc(xmlNodePtr node, virBufferPtr buf)
|
|
|
|
{
|
2006-02-16 22:50:52 +00:00
|
|
|
xmlNodePtr cur;
|
|
|
|
xmlChar *type = NULL;
|
|
|
|
xmlChar *source = NULL;
|
|
|
|
xmlChar *mac = NULL;
|
|
|
|
xmlChar *script = NULL;
|
|
|
|
int typ = 0;
|
|
|
|
|
|
|
|
type = xmlGetProp(node, BAD_CAST "type");
|
|
|
|
if (type != NULL) {
|
2006-03-15 12:13:25 +00:00
|
|
|
if (xmlStrEqual(type, BAD_CAST "bridge"))
|
|
|
|
typ = 0;
|
|
|
|
else if (xmlStrEqual(type, BAD_CAST "ethernet"))
|
|
|
|
typ = 1;
|
|
|
|
xmlFree(type);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
2006-03-15 12:13:25 +00:00
|
|
|
if ((source == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
|
|
|
|
|
|
|
|
if (typ == 0)
|
|
|
|
source = xmlGetProp(cur, BAD_CAST "bridge");
|
|
|
|
else
|
|
|
|
source = xmlGetProp(cur, BAD_CAST "dev");
|
|
|
|
} else if ((mac == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "mac"))) {
|
|
|
|
mac = xmlGetProp(cur, BAD_CAST "address");
|
|
|
|
} else if ((script == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "script"))) {
|
|
|
|
script = xmlGetProp(cur, BAD_CAST "path");
|
|
|
|
}
|
|
|
|
}
|
2006-02-16 22:50:52 +00:00
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAdd(buf, "(vif ", 5);
|
|
|
|
if (mac != NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferVSprintf(buf, "(mac '%s')", (const char *) mac);
|
2006-02-16 22:50:52 +00:00
|
|
|
if (source != NULL) {
|
2006-03-15 12:13:25 +00:00
|
|
|
if (typ == 0)
|
|
|
|
virBufferVSprintf(buf, "(bridge '%s')", (const char *) source);
|
|
|
|
else /* TODO does that work like that ? */
|
|
|
|
virBufferVSprintf(buf, "(dev '%s')", (const char *) source);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
if (script != NULL)
|
|
|
|
virBufferVSprintf(buf, "(script '%s')", script);
|
|
|
|
|
|
|
|
virBufferAdd(buf, ")", 1);
|
|
|
|
if (mac != NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
xmlFree(mac);
|
2006-02-16 22:50:52 +00:00
|
|
|
if (source != NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
xmlFree(source);
|
2006-02-16 22:50:52 +00:00
|
|
|
if (script != NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
xmlFree(script);
|
|
|
|
return (0);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virDomainParseXMLDesc:
|
|
|
|
* @xmldesc: string with the XML description
|
|
|
|
*
|
|
|
|
* Parse the XML description and turn it into the xend sexp needed to
|
|
|
|
* create the comain. This is a temporary interface as the S-Expr interface
|
|
|
|
* will be replaced by XML-RPC in the future. However the XML format should
|
|
|
|
* stay valid over time.
|
|
|
|
*
|
|
|
|
* Returns the 0 terminatedi S-Expr string or NULL in case of error.
|
|
|
|
* the caller must free() the returned value.
|
|
|
|
*/
|
|
|
|
char *
|
2006-03-15 12:13:25 +00:00
|
|
|
virDomainParseXMLDesc(const char *xmldesc, char **name)
|
|
|
|
{
|
2006-02-16 22:50:52 +00:00
|
|
|
xmlDocPtr xml = NULL;
|
|
|
|
xmlNodePtr node;
|
2006-02-27 22:32:54 +00:00
|
|
|
char *ret = NULL, *nam = NULL;
|
2006-02-16 22:50:52 +00:00
|
|
|
virBuffer buf;
|
|
|
|
xmlChar *prop;
|
|
|
|
xmlXPathObjectPtr obj = NULL;
|
2006-07-10 11:21:24 +00:00
|
|
|
xmlXPathObjectPtr tmpobj = NULL;
|
2006-02-16 22:50:52 +00:00
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
|
|
int i, res;
|
2006-03-30 16:08:13 +00:00
|
|
|
int bootloader = 0;
|
2006-02-16 22:50:52 +00:00
|
|
|
|
|
|
|
if (name != NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
*name = NULL;
|
2006-02-16 22:50:52 +00:00
|
|
|
ret = malloc(1000);
|
|
|
|
if (ret == NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
2006-02-16 22:50:52 +00:00
|
|
|
buf.content = ret;
|
|
|
|
buf.size = 1000;
|
|
|
|
buf.use = 0;
|
|
|
|
|
|
|
|
xml = xmlReadDoc((const xmlChar *) xmldesc, "domain.xml", NULL,
|
2006-03-15 12:13:25 +00:00
|
|
|
XML_PARSE_NOENT | XML_PARSE_NONET |
|
|
|
|
XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
|
2006-02-16 22:50:52 +00:00
|
|
|
if (xml == NULL) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
node = xmlDocGetRootElement(xml);
|
|
|
|
if ((node == NULL) || (!xmlStrEqual(node->name, BAD_CAST "domain")))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
prop = xmlGetProp(node, BAD_CAST "type");
|
|
|
|
if (prop != NULL) {
|
|
|
|
if (!xmlStrEqual(prop, BAD_CAST "xen")) {
|
2006-03-15 12:13:25 +00:00
|
|
|
xmlFree(prop);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
xmlFree(prop);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
virBufferAdd(&buf, "(vm ", 4);
|
|
|
|
ctxt = xmlXPathNewContext(xml);
|
|
|
|
if (ctxt == NULL) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
/*
|
2006-07-10 11:21:24 +00:00
|
|
|
* extract some of the basics, name, memory, cpus ...
|
2006-02-16 22:50:52 +00:00
|
|
|
*/
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/name[1])", ctxt);
|
2006-03-15 12:13:25 +00:00
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
2006-02-16 22:50:52 +00:00
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
2006-03-15 12:13:25 +00:00
|
|
|
virXMLError(VIR_ERR_NO_NAME, xmldesc, 0);
|
2006-02-16 22:50:52 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferVSprintf(&buf, "(name '%s')", obj->stringval);
|
2006-02-27 22:32:54 +00:00
|
|
|
nam = strdup((const char *) obj->stringval);
|
|
|
|
if (nam == NULL) {
|
2006-03-15 12:13:25 +00:00
|
|
|
virXMLError(VIR_ERR_NO_MEMORY, "copying name", 0);
|
|
|
|
goto error;
|
2006-02-27 22:32:54 +00:00
|
|
|
}
|
2006-02-16 22:50:52 +00:00
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
obj = xmlXPathEval(BAD_CAST "number(/domain/memory[1])", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_NUMBER) ||
|
|
|
|
(obj->floatval < 64000)) {
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferVSprintf(&buf, "(memory 128)(maxmem 128)");
|
2006-02-16 22:50:52 +00:00
|
|
|
} else {
|
|
|
|
unsigned long mem = (obj->floatval / 1024);
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2006-02-16 22:50:52 +00:00
|
|
|
virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)", mem, mem);
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
obj = xmlXPathEval(BAD_CAST "number(/domain/vcpu[1])", ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_NUMBER) ||
|
|
|
|
(obj->floatval <= 0)) {
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferVSprintf(&buf, "(vcpus 1)");
|
2006-02-16 22:50:52 +00:00
|
|
|
} else {
|
|
|
|
unsigned int cpu = (unsigned int) obj->floatval;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2006-02-16 22:50:52 +00:00
|
|
|
virBufferVSprintf(&buf, "(vcpus %u)", cpu);
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
2006-03-30 16:08:13 +00:00
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/bootloader[1])", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_STRING) &&
|
|
|
|
(obj->stringval != NULL) && (obj->stringval[0] != 0)) {
|
|
|
|
virBufferVSprintf(&buf, "(bootloader '%s')", obj->stringval);
|
|
|
|
bootloader = 1;
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
2006-04-10 08:32:34 +00:00
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/on_poweroff[1])", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_STRING) &&
|
|
|
|
(obj->stringval != NULL) && (obj->stringval[0] != 0)) {
|
|
|
|
virBufferVSprintf(&buf, "(on_poweroff '%s')", obj->stringval);
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/on_reboot[1])", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_STRING) &&
|
|
|
|
(obj->stringval != NULL) && (obj->stringval[0] != 0)) {
|
|
|
|
virBufferVSprintf(&buf, "(on_reboot '%s')", obj->stringval);
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
obj = xmlXPathEval(BAD_CAST "string(/domain/on_crash[1])", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_STRING) &&
|
|
|
|
(obj->stringval != NULL) && (obj->stringval[0] != 0)) {
|
|
|
|
virBufferVSprintf(&buf, "(on_crash '%s')", obj->stringval);
|
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
2006-02-16 22:50:52 +00:00
|
|
|
obj = xmlXPathEval(BAD_CAST "/domain/os[1]", ctxt);
|
2006-07-05 17:08:40 +00:00
|
|
|
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
|
|
|
|
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) {
|
2006-07-10 11:21:24 +00:00
|
|
|
/* Analyze of the os description, based on HVM or PV. */
|
|
|
|
tmpobj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1])", ctxt);
|
|
|
|
if ((tmpobj != NULL) &&
|
|
|
|
((tmpobj->type != XPATH_STRING) || (tmpobj->stringval == NULL) ||
|
|
|
|
(tmpobj->stringval[0] == 0))) {
|
|
|
|
xmlXPathFreeObject(tmpobj);
|
|
|
|
virXMLError(VIR_ERR_OS_TYPE, nam, 0);
|
2006-07-05 17:08:40 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2006-07-10 11:21:24 +00:00
|
|
|
|
|
|
|
if ((tmpobj == NULL) || !xmlStrEqual(tmpobj->stringval, BAD_CAST "hvm")) {
|
|
|
|
res = virDomainParseXMLOSDescPV(obj->nodesetval->nodeTab[0], &buf);
|
|
|
|
} else {
|
|
|
|
res = virDomainParseXMLOSDescHVM(obj->nodesetval->nodeTab[0], &buf, ctxt);
|
|
|
|
}
|
|
|
|
|
|
|
|
xmlXPathFreeObject(tmpobj);
|
|
|
|
|
|
|
|
if (res != 0)
|
|
|
|
goto error;
|
2006-07-05 17:08:40 +00:00
|
|
|
} else if (bootloader == 0) {
|
|
|
|
virXMLError(VIR_ERR_NO_OS, nam, 0);
|
|
|
|
goto error;
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
/* analyze of the devices */
|
|
|
|
obj = xmlXPathEval(BAD_CAST "/domain/devices/disk", ctxt);
|
2006-07-07 14:36:27 +00:00
|
|
|
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
|
|
|
|
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
|
|
|
|
for (i = 0; i < obj->nodesetval->nodeNr; i++) {
|
|
|
|
virBufferAdd(&buf, "(device ", 8);
|
|
|
|
res = virDomainParseXMLDiskDesc(obj->nodesetval->nodeTab[i], &buf);
|
|
|
|
if (res != 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAdd(&buf, ")", 1);
|
|
|
|
}
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
2006-07-07 14:36:27 +00:00
|
|
|
|
2006-02-16 22:50:52 +00:00
|
|
|
obj = xmlXPathEval(BAD_CAST "/domain/devices/interface", ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_NODESET) &&
|
|
|
|
(obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) {
|
2006-03-15 12:13:25 +00:00
|
|
|
for (i = 0; i < obj->nodesetval->nodeNr; i++) {
|
|
|
|
virBufferAdd(&buf, "(device ", 8);
|
|
|
|
res =
|
|
|
|
virDomainParseXMLIfDesc(obj->nodesetval->nodeTab[i], &buf);
|
|
|
|
if (res != 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAdd(&buf, ")", 1);
|
|
|
|
}
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
|
|
|
|
|
2006-02-20 17:22:16 +00:00
|
|
|
virBufferAdd(&buf, ")", 1); /* closes (vm */
|
2006-02-16 22:50:52 +00:00
|
|
|
buf.content[buf.use] = 0;
|
|
|
|
|
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
xmlFreeDoc(xml);
|
2006-02-27 22:32:54 +00:00
|
|
|
|
|
|
|
if (name != NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
*name = nam;
|
2006-02-16 22:50:52 +00:00
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
return (ret);
|
|
|
|
|
|
|
|
error:
|
2006-02-27 22:32:54 +00:00
|
|
|
if (nam != NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
free(nam);
|
2006-02-27 22:32:54 +00:00
|
|
|
if (name != NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
*name = NULL;
|
2006-02-16 22:50:52 +00:00
|
|
|
if (obj != NULL)
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
if (ctxt != NULL)
|
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
if (xml != NULL)
|
|
|
|
xmlFreeDoc(xml);
|
|
|
|
if (ret != NULL)
|
|
|
|
free(ret);
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|