2005-12-13 16:22:05 +00:00
|
|
|
/*
|
|
|
|
* xml.c: XML based interfaces for the libvir library
|
|
|
|
*
|
2007-10-24 14:22:25 +00:00
|
|
|
* Copyright (C) 2005, 2007 Red Hat, Inc.
|
2005-12-13 16:22:05 +00:00
|
|
|
*
|
|
|
|
* See COPYING.LIB for the License of this software
|
|
|
|
*
|
|
|
|
* Daniel Veillard <veillard@redhat.com>
|
|
|
|
*/
|
|
|
|
|
2007-11-26 11:40:28 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
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>
|
2007-11-26 11:40:28 +00:00
|
|
|
#include <limits.h>
|
2007-03-15 07:43:16 +00:00
|
|
|
#ifdef WITH_XEN
|
2005-12-13 16:22:05 +00:00
|
|
|
#include <xs.h>
|
2007-03-15 07:43:16 +00:00
|
|
|
#endif
|
2007-10-24 14:22:25 +00:00
|
|
|
#include <math.h> /* for isnan() */
|
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"
|
2007-06-26 22:33:22 +00:00
|
|
|
#include "buf.h"
|
2007-10-24 14:22:25 +00:00
|
|
|
#include "xs_internal.h" /* for xenStoreDomainGetNetworkID */
|
2007-10-22 20:28:55 +00:00
|
|
|
#include "xen_unified.h"
|
2005-12-13 16:22:05 +00:00
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
/**
|
|
|
|
* virXMLError:
|
|
|
|
* @conn: a connection if any
|
|
|
|
* @error: the error number
|
|
|
|
* @info: information/format string
|
|
|
|
* @value: extra integer parameter for the error string
|
|
|
|
*
|
|
|
|
* Report an error coming from the XML module.
|
|
|
|
*/
|
2006-02-27 22:32:54 +00:00
|
|
|
static void
|
2007-10-24 14:22:25 +00:00
|
|
|
virXMLError(virConnectPtr conn, virErrorNumber error, const char *info,
|
|
|
|
int value)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
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);
|
2007-02-14 16:16:13 +00:00
|
|
|
__virRaiseError(conn, 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
|
|
|
}
|
|
|
|
|
2007-10-22 20:28:55 +00:00
|
|
|
/************************************************************************
|
|
|
|
* *
|
|
|
|
* Parser and converter for the CPUset strings used in libvirt *
|
|
|
|
* *
|
|
|
|
************************************************************************/
|
2007-11-30 22:51:54 +00:00
|
|
|
#if WITH_XEN
|
2007-10-22 20:28:55 +00:00
|
|
|
/**
|
|
|
|
* skipSpaces:
|
|
|
|
* @str: pointer to the char pointer used
|
|
|
|
*
|
|
|
|
* Skip potential blanks, this includes space tabs, line feed,
|
|
|
|
* carriage returns and also '\\' which can be erronously emitted
|
|
|
|
* by xend
|
|
|
|
*/
|
|
|
|
static void
|
2007-10-24 14:22:25 +00:00
|
|
|
skipSpaces(const char **str)
|
|
|
|
{
|
2007-10-22 20:28:55 +00:00
|
|
|
const char *cur = *str;
|
|
|
|
|
|
|
|
while ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') ||
|
2007-10-24 14:22:25 +00:00
|
|
|
(*cur == '\r') || (*cur == '\\'))
|
|
|
|
cur++;
|
2007-10-22 20:28:55 +00:00
|
|
|
*str = cur;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* parseNumber:
|
|
|
|
* @str: pointer to the char pointer used
|
|
|
|
*
|
2007-10-24 14:22:25 +00:00
|
|
|
* Parse an unsigned number
|
2007-10-22 20:28:55 +00:00
|
|
|
*
|
2007-10-24 14:22:25 +00:00
|
|
|
* Returns the unsigned number or -1 in case of error. @str will be
|
2007-10-22 20:28:55 +00:00
|
|
|
* updated to skip the number.
|
|
|
|
*/
|
|
|
|
static int
|
2007-10-24 14:22:25 +00:00
|
|
|
parseNumber(const char **str)
|
|
|
|
{
|
2007-10-22 20:28:55 +00:00
|
|
|
int ret = 0;
|
|
|
|
const char *cur = *str;
|
|
|
|
|
|
|
|
if ((*cur < '0') || (*cur > '9'))
|
2007-10-24 14:22:25 +00:00
|
|
|
return (-1);
|
2007-10-22 20:28:55 +00:00
|
|
|
|
|
|
|
while ((*cur >= '0') && (*cur <= '9')) {
|
2007-10-24 14:22:25 +00:00
|
|
|
unsigned int c = *cur - '0';
|
|
|
|
|
|
|
|
if ((ret > INT_MAX / 10) ||
|
|
|
|
((ret == INT_MAX / 10) && (c > INT_MAX % 10)))
|
|
|
|
return (-1);
|
|
|
|
ret = ret * 10 + c;
|
|
|
|
cur++;
|
2007-10-22 20:28:55 +00:00
|
|
|
}
|
|
|
|
*str = cur;
|
2007-10-24 14:22:25 +00:00
|
|
|
return (ret);
|
2007-10-22 20:28:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* parseCpuNumber:
|
|
|
|
* @str: pointer to the char pointer used
|
|
|
|
* @maxcpu: maximum CPU number allowed
|
|
|
|
*
|
|
|
|
* Parse a CPU number
|
|
|
|
*
|
|
|
|
* Returns the CPU number or -1 in case of error. @str will be
|
|
|
|
* updated to skip the number.
|
|
|
|
*/
|
|
|
|
static int
|
2007-10-24 14:22:25 +00:00
|
|
|
parseCpuNumber(const char **str, int maxcpu)
|
|
|
|
{
|
2007-10-22 20:28:55 +00:00
|
|
|
int ret = 0;
|
|
|
|
const char *cur = *str;
|
|
|
|
|
|
|
|
if ((*cur < '0') || (*cur > '9'))
|
2007-10-24 14:22:25 +00:00
|
|
|
return (-1);
|
2007-10-22 20:28:55 +00:00
|
|
|
|
|
|
|
while ((*cur >= '0') && (*cur <= '9')) {
|
|
|
|
ret = ret * 10 + (*cur - '0');
|
2007-11-05 10:14:42 +00:00
|
|
|
if (ret >= maxcpu)
|
2007-10-24 14:22:25 +00:00
|
|
|
return (-1);
|
|
|
|
cur++;
|
2007-10-22 20:28:55 +00:00
|
|
|
}
|
|
|
|
*str = cur;
|
2007-10-24 14:22:25 +00:00
|
|
|
return (ret);
|
2007-10-22 20:28:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-10-31 09:39:13 +00:00
|
|
|
* virSaveCpuSet:
|
2007-10-22 20:28:55 +00:00
|
|
|
* @conn: connection
|
|
|
|
* @cpuset: pointer to a char array for the CPU set
|
|
|
|
* @maxcpu: number of elements available in @cpuset
|
|
|
|
*
|
|
|
|
* Serialize the cpuset to a string
|
|
|
|
*
|
|
|
|
* Returns the new string NULL in case of error. The string need to be
|
|
|
|
* freed by the caller.
|
|
|
|
*/
|
2007-10-31 09:39:13 +00:00
|
|
|
char *
|
|
|
|
virSaveCpuSet(virConnectPtr conn, char *cpuset, int maxcpu)
|
2007-10-22 20:28:55 +00:00
|
|
|
{
|
|
|
|
virBufferPtr buf;
|
|
|
|
char *ret;
|
|
|
|
int start, cur;
|
|
|
|
int first = 1;
|
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
if ((cpuset == NULL) || (maxcpu <= 0) || (maxcpu > 100000))
|
|
|
|
return (NULL);
|
2007-10-22 20:28:55 +00:00
|
|
|
|
|
|
|
buf = virBufferNew(1000);
|
|
|
|
if (buf == NULL) {
|
2007-10-24 14:22:25 +00:00
|
|
|
virXMLError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"), 1000);
|
|
|
|
return (NULL);
|
2007-10-22 20:28:55 +00:00
|
|
|
}
|
|
|
|
cur = 0;
|
|
|
|
start = -1;
|
|
|
|
while (cur < maxcpu) {
|
|
|
|
if (cpuset[cur]) {
|
2007-10-24 14:22:25 +00:00
|
|
|
if (start == -1)
|
|
|
|
start = cur;
|
|
|
|
} else if (start != -1) {
|
|
|
|
if (!first)
|
|
|
|
virBufferAdd(buf, ",", -1);
|
2007-10-22 20:28:55 +00:00
|
|
|
else
|
2007-10-24 14:22:25 +00:00
|
|
|
first = 0;
|
|
|
|
if (cur == start + 1)
|
|
|
|
virBufferVSprintf(buf, "%d", start);
|
|
|
|
else
|
|
|
|
virBufferVSprintf(buf, "%d-%d", start, cur - 1);
|
|
|
|
start = -1;
|
|
|
|
}
|
|
|
|
cur++;
|
2007-10-22 20:28:55 +00:00
|
|
|
}
|
|
|
|
if (start != -1) {
|
2007-10-24 14:22:25 +00:00
|
|
|
if (!first)
|
|
|
|
virBufferAdd(buf, ",", -1);
|
|
|
|
if (maxcpu == start + 1)
|
|
|
|
virBufferVSprintf(buf, "%d", start);
|
|
|
|
else
|
|
|
|
virBufferVSprintf(buf, "%d-%d", start, maxcpu - 1);
|
2007-10-22 20:28:55 +00:00
|
|
|
}
|
|
|
|
ret = virBufferContentAndFree(buf);
|
2007-10-24 14:22:25 +00:00
|
|
|
return (ret);
|
2007-10-22 20:28:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virParseCpuSet:
|
2007-10-31 09:39:13 +00:00
|
|
|
* @conn: connection
|
2007-10-22 20:28:55 +00:00
|
|
|
* @str: pointer to a CPU set string pointer
|
|
|
|
* @sep: potential character used to mark the end of string if not 0
|
|
|
|
* @cpuset: pointer to a char array for the CPU set
|
|
|
|
* @maxcpu: number of elements available in @cpuset
|
|
|
|
*
|
|
|
|
* Parse the cpu set, it will set the value for enabled CPUs in the @cpuset
|
|
|
|
* to 1, and 0 otherwise. The syntax allows coma separated entries each
|
|
|
|
* can be either a CPU number, ^N to unset that CPU or N-M for ranges.
|
|
|
|
*
|
|
|
|
* Returns the number of CPU found in that set, or -1 in case of error.
|
|
|
|
* @cpuset is modified accordingly to the value parsed.
|
|
|
|
* @str is updated to the end of the part parsed
|
|
|
|
*/
|
|
|
|
int
|
2007-10-24 14:22:25 +00:00
|
|
|
virParseCpuSet(virConnectPtr conn, const char **str, char sep,
|
|
|
|
char *cpuset, int maxcpu)
|
2007-10-22 20:28:55 +00:00
|
|
|
{
|
|
|
|
const char *cur;
|
|
|
|
int ret = 0;
|
|
|
|
int i, start, last;
|
|
|
|
int neg = 0;
|
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
if ((str == NULL) || (cpuset == NULL) || (maxcpu <= 0) ||
|
|
|
|
(maxcpu > 100000))
|
|
|
|
return (-1);
|
2007-10-22 20:28:55 +00:00
|
|
|
|
|
|
|
cur = *str;
|
|
|
|
skipSpaces(&cur);
|
|
|
|
if (*cur == 0)
|
|
|
|
goto parse_error;
|
|
|
|
|
|
|
|
/* initialize cpumap to all 0s */
|
2007-10-24 14:22:25 +00:00
|
|
|
for (i = 0; i < maxcpu; i++)
|
|
|
|
cpuset[i] = 0;
|
2007-10-22 20:28:55 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
while ((*cur != 0) && (*cur != sep)) {
|
2007-10-24 14:22:25 +00:00
|
|
|
/*
|
|
|
|
* 3 constructs are allowed:
|
|
|
|
* - N : a single CPU number
|
|
|
|
* - N-M : a range of CPU numbers with N < M
|
|
|
|
* - ^N : remove a single CPU number from the current set
|
|
|
|
*/
|
|
|
|
if (*cur == '^') {
|
|
|
|
cur++;
|
|
|
|
neg = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((*cur < '0') || (*cur > '9'))
|
|
|
|
goto parse_error;
|
|
|
|
start = parseCpuNumber(&cur, maxcpu);
|
|
|
|
if (start < 0)
|
|
|
|
goto parse_error;
|
|
|
|
skipSpaces(&cur);
|
|
|
|
if ((*cur == ',') || (*cur == 0) || (*cur == sep)) {
|
|
|
|
if (neg) {
|
|
|
|
if (cpuset[start] == 1) {
|
|
|
|
cpuset[start] = 0;
|
|
|
|
ret--;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (cpuset[start] == 0) {
|
|
|
|
cpuset[start] = 1;
|
|
|
|
ret++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (*cur == '-') {
|
|
|
|
if (neg)
|
|
|
|
goto parse_error;
|
|
|
|
cur++;
|
|
|
|
skipSpaces(&cur);
|
|
|
|
last = parseCpuNumber(&cur, maxcpu);
|
|
|
|
if (last < start)
|
|
|
|
goto parse_error;
|
|
|
|
for (i = start; i <= last; i++) {
|
|
|
|
if (cpuset[i] == 0) {
|
|
|
|
cpuset[i] = 1;
|
|
|
|
ret++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
skipSpaces(&cur);
|
|
|
|
}
|
|
|
|
if (*cur == ',') {
|
|
|
|
cur++;
|
|
|
|
skipSpaces(&cur);
|
|
|
|
neg = 0;
|
|
|
|
} else if ((*cur == 0) || (*cur == sep)) {
|
|
|
|
break;
|
|
|
|
} else
|
|
|
|
goto parse_error;
|
2007-10-22 20:28:55 +00:00
|
|
|
}
|
|
|
|
*str = cur;
|
2007-10-24 14:22:25 +00:00
|
|
|
return (ret);
|
2007-10-22 20:28:55 +00:00
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
parse_error:
|
2007-10-22 20:28:55 +00:00
|
|
|
virXMLError(conn, VIR_ERR_XEN_CALL,
|
2007-10-24 14:22:25 +00:00
|
|
|
_("topology cpuset syntax error"), 0);
|
|
|
|
return (-1);
|
2007-10-22 20:28:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virParseXenCpuTopology:
|
2007-10-31 09:39:13 +00:00
|
|
|
* @conn: connection
|
2007-10-22 20:28:55 +00:00
|
|
|
* @xml: XML output buffer
|
|
|
|
* @str: the topology string
|
|
|
|
* @maxcpu: number of elements available in @cpuset
|
|
|
|
*
|
|
|
|
* Parse a Xend CPU topology string and build the associated XML
|
|
|
|
* format.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, -1 in case of error
|
|
|
|
*/
|
|
|
|
int
|
2007-10-24 14:22:25 +00:00
|
|
|
virParseXenCpuTopology(virConnectPtr conn, virBufferPtr xml,
|
|
|
|
const char *str, int maxcpu)
|
2007-10-22 20:28:55 +00:00
|
|
|
{
|
|
|
|
const char *cur;
|
|
|
|
char *cpuset = NULL;
|
|
|
|
int cell, cpu, nb_cpus;
|
|
|
|
int ret;
|
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
if ((str == NULL) || (xml == NULL) || (maxcpu <= 0) || (maxcpu > 100000))
|
|
|
|
return (-1);
|
2007-10-22 20:28:55 +00:00
|
|
|
|
2007-12-11 21:57:29 +00:00
|
|
|
cpuset = malloc(maxcpu * sizeof(*cpuset));
|
2007-10-22 20:28:55 +00:00
|
|
|
if (cpuset == NULL)
|
|
|
|
goto memory_error;
|
|
|
|
|
|
|
|
cur = str;
|
|
|
|
while (*cur != 0) {
|
|
|
|
/*
|
2007-10-24 14:22:25 +00:00
|
|
|
* Find the next NUMA cell described in the xend output
|
|
|
|
*/
|
2007-10-22 20:28:55 +00:00
|
|
|
cur = strstr(cur, "node");
|
2007-10-24 14:22:25 +00:00
|
|
|
if (cur == NULL)
|
|
|
|
break;
|
|
|
|
cur += 4;
|
2007-10-22 20:28:55 +00:00
|
|
|
cell = parseNumber(&cur);
|
2007-10-24 14:22:25 +00:00
|
|
|
if (cell < 0)
|
|
|
|
goto parse_error;
|
|
|
|
skipSpaces(&cur);
|
|
|
|
if (*cur != ':')
|
|
|
|
goto parse_error;
|
|
|
|
cur++;
|
|
|
|
skipSpaces(&cur);
|
|
|
|
if (!strncmp(cur, "no cpus", 7)) {
|
|
|
|
nb_cpus = 0;
|
|
|
|
for (cpu = 0; cpu < maxcpu; cpu++)
|
|
|
|
cpuset[cpu] = 0;
|
|
|
|
} else {
|
|
|
|
nb_cpus = virParseCpuSet(conn, &cur, 'n', cpuset, maxcpu);
|
|
|
|
if (nb_cpus < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* add xml for all cpus associated with that cell
|
|
|
|
*/
|
|
|
|
ret = virBufferVSprintf(xml, "\
|
2007-10-22 20:28:55 +00:00
|
|
|
<cell id='%d'>\n\
|
|
|
|
<cpus num='%d'>\n", cell, nb_cpus);
|
|
|
|
#ifdef STANDALONE
|
|
|
|
{
|
2007-10-24 14:22:25 +00:00
|
|
|
char *dump;
|
|
|
|
|
2007-10-31 09:39:13 +00:00
|
|
|
dump = virSaveCpuSet(conn, cpuset, maxcpu);
|
2007-10-24 14:22:25 +00:00
|
|
|
if (dump != NULL) {
|
|
|
|
virBufferVSprintf(xml, " <dump>%s</dump>\n",
|
|
|
|
dump);
|
|
|
|
free(dump);
|
|
|
|
} else {
|
|
|
|
virBufferVSprintf(xml, " <error>%s</error>\n",
|
|
|
|
"Failed to dump CPU set");
|
|
|
|
}
|
2007-10-22 20:28:55 +00:00
|
|
|
}
|
|
|
|
#endif
|
2007-10-24 14:22:25 +00:00
|
|
|
if (ret < 0)
|
|
|
|
goto memory_error;
|
|
|
|
for (cpu = 0; cpu < maxcpu; cpu++) {
|
|
|
|
if (cpuset[cpu] == 1) {
|
|
|
|
ret = virBufferVSprintf(xml, "\
|
2007-10-22 20:28:55 +00:00
|
|
|
<cpu id='%d'/>\n", cpu);
|
2007-10-24 14:22:25 +00:00
|
|
|
if (ret < 0)
|
|
|
|
goto memory_error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret = virBufferAdd(xml, "\
|
2007-10-22 20:28:55 +00:00
|
|
|
</cpus>\n\
|
|
|
|
</cell>\n", -1);
|
|
|
|
if (ret < 0)
|
2007-10-24 14:22:25 +00:00
|
|
|
goto memory_error;
|
|
|
|
|
2007-10-22 20:28:55 +00:00
|
|
|
}
|
|
|
|
free(cpuset);
|
2007-10-24 14:22:25 +00:00
|
|
|
return (0);
|
2007-10-22 20:28:55 +00:00
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
parse_error:
|
|
|
|
virXMLError(conn, VIR_ERR_XEN_CALL, _("topology syntax error"), 0);
|
|
|
|
error:
|
2007-10-22 20:28:55 +00:00
|
|
|
if (cpuset != NULL)
|
|
|
|
free(cpuset);
|
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
return (-1);
|
2007-10-22 20:28:55 +00:00
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
memory_error:
|
2007-10-22 20:28:55 +00:00
|
|
|
if (cpuset != NULL)
|
|
|
|
free(cpuset);
|
|
|
|
virXMLError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"), 0);
|
2007-10-24 14:22:25 +00:00
|
|
|
return (-1);
|
2007-10-22 20:28:55 +00:00
|
|
|
}
|
|
|
|
|
2007-10-31 09:39:13 +00:00
|
|
|
/**
|
|
|
|
* virConvertCpuSet:
|
|
|
|
* @conn: connection
|
|
|
|
* @str: pointer to a Xen or user provided CPU set string pointer
|
|
|
|
* @maxcpu: number of CPUs on the node, if 0 4096 will be used
|
|
|
|
*
|
|
|
|
* Parse the given CPU set string and convert it to a range based
|
|
|
|
* string.
|
|
|
|
*
|
|
|
|
* Returns a new string which must be freed by the caller or NULL in
|
|
|
|
* case of error.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
virConvertCpuSet(virConnectPtr conn, const char *str, int maxcpu) {
|
|
|
|
int ret;
|
|
|
|
char *res, *cpuset;
|
|
|
|
const char *cur = str;
|
|
|
|
|
|
|
|
if (str == NULL)
|
|
|
|
return(NULL);
|
|
|
|
|
|
|
|
if (maxcpu <= 0)
|
|
|
|
maxcpu = 4096;
|
|
|
|
|
2007-12-11 21:57:29 +00:00
|
|
|
cpuset = calloc(maxcpu, sizeof(*cpuset));
|
2007-10-31 09:39:13 +00:00
|
|
|
if (cpuset == NULL) {
|
|
|
|
virXMLError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"), 0);
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = virParseCpuSet(conn, &cur, 0, cpuset, maxcpu);
|
|
|
|
if (ret < 0) {
|
|
|
|
free(cpuset);
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
res = virSaveCpuSet(conn, cpuset, maxcpu);
|
|
|
|
free(cpuset);
|
|
|
|
return (res);
|
|
|
|
}
|
2007-11-30 22:51:54 +00:00
|
|
|
#endif /* WITH_XEN */
|
2007-10-23 15:31:33 +00:00
|
|
|
#ifndef PROXY
|
2007-10-22 20:28:55 +00:00
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* *
|
|
|
|
* Wrappers around libxml2 XPath specific functions *
|
|
|
|
* *
|
|
|
|
************************************************************************/
|
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
/**
|
|
|
|
* virXPathString:
|
|
|
|
* @xpath: the XPath string to evaluate
|
|
|
|
* @ctxt: an XPath context
|
|
|
|
*
|
|
|
|
* Convenience function to evaluate an XPath string
|
|
|
|
*
|
|
|
|
* Returns a new string which must be deallocated by the caller or NULL
|
|
|
|
* if the evaluation failed.
|
|
|
|
*/
|
|
|
|
char *
|
2007-10-24 14:22:25 +00:00
|
|
|
virXPathString(const char *xpath, xmlXPathContextPtr ctxt)
|
|
|
|
{
|
2007-04-06 12:28:24 +00:00
|
|
|
xmlXPathObjectPtr obj;
|
|
|
|
char *ret;
|
|
|
|
|
|
|
|
if ((ctxt == NULL) || (xpath == NULL)) {
|
2007-10-24 14:22:25 +00:00
|
|
|
virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"Invalid parameter to virXPathString()", 0);
|
|
|
|
return (NULL);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
|
|
|
obj = xmlXPathEval(BAD_CAST xpath, ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_STRING) ||
|
2007-07-31 14:27:12 +00:00
|
|
|
(obj->stringval == NULL) || (obj->stringval[0] == 0)) {
|
|
|
|
if (obj)
|
|
|
|
xmlXPathFreeObject(obj);
|
2007-10-24 14:22:25 +00:00
|
|
|
return (NULL);
|
2007-07-31 14:27:12 +00:00
|
|
|
}
|
2007-04-06 12:28:24 +00:00
|
|
|
ret = strdup((char *) obj->stringval);
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
if (ret == NULL) {
|
|
|
|
virXMLError(NULL, VIR_ERR_NO_MEMORY, "strdup", 0);
|
|
|
|
}
|
2007-10-24 14:22:25 +00:00
|
|
|
return (ret);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virXPathNumber:
|
|
|
|
* @xpath: the XPath string to evaluate
|
|
|
|
* @ctxt: an XPath context
|
|
|
|
* @value: the returned double value
|
|
|
|
*
|
|
|
|
* Convenience function to evaluate an XPath number
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success in which case @value is set,
|
|
|
|
* or -1 if the evaluation failed.
|
|
|
|
*/
|
|
|
|
int
|
2007-10-24 14:22:25 +00:00
|
|
|
virXPathNumber(const char *xpath, xmlXPathContextPtr ctxt, double *value)
|
|
|
|
{
|
2007-04-06 12:28:24 +00:00
|
|
|
xmlXPathObjectPtr obj;
|
|
|
|
|
|
|
|
if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
|
2007-10-24 14:22:25 +00:00
|
|
|
virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"Invalid parameter to virXPathNumber()", 0);
|
|
|
|
return (-1);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
|
|
|
obj = xmlXPathEval(BAD_CAST xpath, ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_NUMBER) ||
|
|
|
|
(isnan(obj->floatval))) {
|
2007-10-24 14:22:25 +00:00
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
return (-1);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
2007-10-24 14:22:25 +00:00
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
*value = obj->floatval;
|
|
|
|
xmlXPathFreeObject(obj);
|
2007-10-24 14:22:25 +00:00
|
|
|
return (0);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virXPathLong:
|
|
|
|
* @xpath: the XPath string to evaluate
|
|
|
|
* @ctxt: an XPath context
|
|
|
|
* @value: the returned long value
|
|
|
|
*
|
|
|
|
* Convenience function to evaluate an XPath number
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success in which case @value is set,
|
2007-04-06 15:34:09 +00:00
|
|
|
* or -1 if the XPath evaluation failed or -2 if the
|
|
|
|
* value doesn't have a long format.
|
2007-04-06 12:28:24 +00:00
|
|
|
*/
|
|
|
|
int
|
2007-10-24 14:22:25 +00:00
|
|
|
virXPathLong(const char *xpath, xmlXPathContextPtr ctxt, long *value)
|
|
|
|
{
|
2007-04-06 12:28:24 +00:00
|
|
|
xmlXPathObjectPtr obj;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
|
2007-10-24 14:22:25 +00:00
|
|
|
virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"Invalid parameter to virXPathNumber()", 0);
|
|
|
|
return (-1);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
|
|
|
obj = xmlXPathEval(BAD_CAST xpath, ctxt);
|
|
|
|
if ((obj != NULL) && (obj->type == XPATH_STRING) &&
|
|
|
|
(obj->stringval != NULL) && (obj->stringval[0] != 0)) {
|
|
|
|
char *conv = NULL;
|
2007-10-24 14:22:25 +00:00
|
|
|
long val;
|
2007-04-06 12:28:24 +00:00
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
val = strtol((const char *) obj->stringval, &conv, 10);
|
|
|
|
if (conv == (const char *) obj->stringval) {
|
2007-04-06 12:28:24 +00:00
|
|
|
ret = -2;
|
|
|
|
} else {
|
2007-10-24 14:22:25 +00:00
|
|
|
*value = val;
|
|
|
|
}
|
2007-04-06 12:28:24 +00:00
|
|
|
} else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
|
|
|
|
(!(isnan(obj->floatval)))) {
|
2007-10-24 14:22:25 +00:00
|
|
|
*value = (long) obj->floatval;
|
|
|
|
if (*value != obj->floatval) {
|
|
|
|
ret = -2;
|
|
|
|
}
|
2007-04-06 12:28:24 +00:00
|
|
|
} else {
|
2007-10-24 14:22:25 +00:00
|
|
|
ret = -1;
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
2007-10-24 14:22:25 +00:00
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
xmlXPathFreeObject(obj);
|
2007-10-24 14:22:25 +00:00
|
|
|
return (ret);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virXPathBoolean:
|
|
|
|
* @xpath: the XPath string to evaluate
|
|
|
|
* @ctxt: an XPath context
|
|
|
|
*
|
|
|
|
* Convenience function to evaluate an XPath boolean
|
|
|
|
*
|
|
|
|
* Returns 0 if false, 1 if true, or -1 if the evaluation failed.
|
|
|
|
*/
|
|
|
|
int
|
2007-10-24 14:22:25 +00:00
|
|
|
virXPathBoolean(const char *xpath, xmlXPathContextPtr ctxt)
|
|
|
|
{
|
2007-04-06 12:28:24 +00:00
|
|
|
xmlXPathObjectPtr obj;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if ((ctxt == NULL) || (xpath == NULL)) {
|
2007-10-24 14:22:25 +00:00
|
|
|
virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"Invalid parameter to virXPathBoolean()", 0);
|
|
|
|
return (-1);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
|
|
|
obj = xmlXPathEval(BAD_CAST xpath, ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_BOOLEAN) ||
|
|
|
|
(obj->boolval < 0) || (obj->boolval > 1)) {
|
2007-10-24 14:22:25 +00:00
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
return (-1);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
|
|
|
ret = obj->boolval;
|
2007-10-24 14:22:25 +00:00
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
xmlXPathFreeObject(obj);
|
2007-10-24 14:22:25 +00:00
|
|
|
return (ret);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virXPathNode:
|
|
|
|
* @xpath: the XPath string to evaluate
|
|
|
|
* @ctxt: an XPath context
|
|
|
|
*
|
|
|
|
* Convenience function to evaluate an XPath node set and returning
|
|
|
|
* only one node, the first one in the set if any
|
|
|
|
*
|
|
|
|
* Returns a pointer to the node or NULL if the evaluation failed.
|
|
|
|
*/
|
|
|
|
xmlNodePtr
|
2007-10-24 14:22:25 +00:00
|
|
|
virXPathNode(const char *xpath, xmlXPathContextPtr ctxt)
|
|
|
|
{
|
2007-04-06 12:28:24 +00:00
|
|
|
xmlXPathObjectPtr obj;
|
|
|
|
xmlNodePtr ret;
|
|
|
|
|
|
|
|
if ((ctxt == NULL) || (xpath == NULL)) {
|
2007-10-24 14:22:25 +00:00
|
|
|
virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"Invalid parameter to virXPathNode()", 0);
|
|
|
|
return (NULL);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
|
|
|
obj = xmlXPathEval(BAD_CAST xpath, ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
|
|
|
|
(obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) ||
|
2007-10-24 14:22:25 +00:00
|
|
|
(obj->nodesetval->nodeTab == NULL)) {
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
return (NULL);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
2007-10-24 14:22:25 +00:00
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
ret = obj->nodesetval->nodeTab[0];
|
|
|
|
xmlXPathFreeObject(obj);
|
2007-10-24 14:22:25 +00:00
|
|
|
return (ret);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
2007-10-24 14:22:25 +00:00
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
/**
|
|
|
|
* virXPathNodeSet:
|
|
|
|
* @xpath: the XPath string to evaluate
|
|
|
|
* @ctxt: an XPath context
|
|
|
|
* @list: the returned list of nodes (or NULL if only count matters)
|
|
|
|
*
|
|
|
|
* Convenience function to evaluate an XPath node set
|
|
|
|
*
|
|
|
|
* Returns the number of nodes found in which case @list is set (and
|
|
|
|
* must be freed) or -1 if the evaluation failed.
|
|
|
|
*/
|
|
|
|
int
|
2007-10-24 14:22:25 +00:00
|
|
|
virXPathNodeSet(const char *xpath, xmlXPathContextPtr ctxt,
|
|
|
|
xmlNodePtr ** list)
|
|
|
|
{
|
2007-04-06 12:28:24 +00:00
|
|
|
xmlXPathObjectPtr obj;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if ((ctxt == NULL) || (xpath == NULL)) {
|
2007-10-24 14:22:25 +00:00
|
|
|
virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"Invalid parameter to virXPathNodeSet()", 0);
|
|
|
|
return (-1);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
|
|
|
obj = xmlXPathEval(BAD_CAST xpath, ctxt);
|
|
|
|
if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
|
|
|
|
(obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) ||
|
2007-10-24 14:22:25 +00:00
|
|
|
(obj->nodesetval->nodeTab == NULL)) {
|
|
|
|
xmlXPathFreeObject(obj);
|
|
|
|
if (list != NULL)
|
|
|
|
*list = NULL;
|
|
|
|
return (-1);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
2007-10-24 14:22:25 +00:00
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
ret = obj->nodesetval->nodeNr;
|
|
|
|
if (list != NULL) {
|
2007-12-11 21:57:29 +00:00
|
|
|
*list = malloc(ret * sizeof(**list));
|
2007-10-24 14:22:25 +00:00
|
|
|
if (*list == NULL) {
|
|
|
|
virXMLError(NULL, VIR_ERR_NO_MEMORY,
|
|
|
|
_("allocate string array"),
|
2007-12-11 21:57:29 +00:00
|
|
|
ret * sizeof(**list));
|
2007-10-24 14:22:25 +00:00
|
|
|
} else {
|
|
|
|
memcpy(*list, obj->nodesetval->nodeTab,
|
|
|
|
ret * sizeof(xmlNodePtr));
|
|
|
|
}
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
|
|
|
xmlXPathFreeObject(obj);
|
2007-10-24 14:22:25 +00:00
|
|
|
return (ret);
|
2007-04-06 12:28:24 +00:00
|
|
|
}
|
|
|
|
|
2007-10-22 20:28:55 +00:00
|
|
|
/************************************************************************
|
|
|
|
* *
|
|
|
|
* Converter functions to go from the XML tree to an S-Expr for Xen *
|
|
|
|
* *
|
|
|
|
************************************************************************/
|
2007-11-30 22:51:54 +00:00
|
|
|
#if WITH_XEN
|
2006-08-26 15:30:44 +00:00
|
|
|
/**
|
2006-12-13 14:08:51 +00:00
|
|
|
* virtDomainParseXMLGraphicsDescImage:
|
2007-02-14 16:16:13 +00:00
|
|
|
* @conn: pointer to the hypervisor connection
|
2006-08-26 15:30:44 +00:00
|
|
|
* @node: node containing graphics description
|
|
|
|
* @buf: a buffer for the result S-Expr
|
2006-09-12 01:34:26 +00:00
|
|
|
* @xendConfigVersion: xend configuration file format
|
2006-08-26 15:30:44 +00:00
|
|
|
*
|
2007-02-07 13:50:18 +00:00
|
|
|
* Parse the graphics part of 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
|
2006-08-26 15:30:44 +00:00
|
|
|
* valid over time.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, -1 in case of error
|
|
|
|
*/
|
2007-10-24 14:22:25 +00:00
|
|
|
static int
|
|
|
|
virDomainParseXMLGraphicsDescImage(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
xmlNodePtr node, virBufferPtr buf,
|
|
|
|
int xendConfigVersion)
|
2006-08-26 15:30:44 +00:00
|
|
|
{
|
|
|
|
xmlChar *graphics_type = NULL;
|
|
|
|
|
|
|
|
graphics_type = xmlGetProp(node, BAD_CAST "type");
|
|
|
|
if (graphics_type != NULL) {
|
|
|
|
if (xmlStrEqual(graphics_type, BAD_CAST "sdl")) {
|
|
|
|
virBufferAdd(buf, "(sdl 1)", 7);
|
2006-12-13 14:08:51 +00:00
|
|
|
/* TODO:
|
|
|
|
* Need to understand sdl options
|
|
|
|
*
|
|
|
|
*virBufferAdd(buf, "(display localhost:10.0)", 24);
|
|
|
|
*virBufferAdd(buf, "(xauthority /root/.Xauthority)", 30);
|
|
|
|
*/
|
2007-10-24 14:22:25 +00:00
|
|
|
} else if (xmlStrEqual(graphics_type, BAD_CAST "vnc")) {
|
2006-08-26 15:30:44 +00:00
|
|
|
virBufferAdd(buf, "(vnc 1)", 7);
|
2006-09-12 01:34:26 +00:00
|
|
|
if (xendConfigVersion >= 2) {
|
2006-10-06 15:32:48 +00:00
|
|
|
xmlChar *vncport = xmlGetProp(node, BAD_CAST "port");
|
2006-12-13 14:08:51 +00:00
|
|
|
xmlChar *vnclisten = xmlGetProp(node, BAD_CAST "listen");
|
|
|
|
xmlChar *vncpasswd = xmlGetProp(node, BAD_CAST "passwd");
|
2007-03-06 20:00:17 +00:00
|
|
|
xmlChar *keymap = xmlGetProp(node, BAD_CAST "keymap");
|
2007-10-24 14:22:25 +00:00
|
|
|
|
2006-09-12 01:34:26 +00:00
|
|
|
if (vncport != NULL) {
|
2007-10-24 14:22:25 +00:00
|
|
|
long port = strtol((const char *) vncport, NULL, 10);
|
|
|
|
|
2006-09-12 01:34:26 +00:00
|
|
|
if (port == -1)
|
|
|
|
virBufferAdd(buf, "(vncunused 1)", 13);
|
2007-03-08 08:55:56 +00:00
|
|
|
else if (port >= 5900)
|
2007-10-24 14:22:25 +00:00
|
|
|
virBufferVSprintf(buf, "(vncdisplay %ld)",
|
|
|
|
port - 5900);
|
2006-10-06 15:32:48 +00:00
|
|
|
xmlFree(vncport);
|
2006-09-12 01:34:26 +00:00
|
|
|
}
|
2006-12-13 14:08:51 +00:00
|
|
|
if (vnclisten != NULL) {
|
|
|
|
virBufferVSprintf(buf, "(vnclisten %s)", vnclisten);
|
|
|
|
xmlFree(vnclisten);
|
|
|
|
}
|
|
|
|
if (vncpasswd != NULL) {
|
|
|
|
virBufferVSprintf(buf, "(vncpasswd %s)", vncpasswd);
|
|
|
|
xmlFree(vncpasswd);
|
|
|
|
}
|
2007-03-06 20:00:17 +00:00
|
|
|
if (keymap != NULL) {
|
|
|
|
virBufferVSprintf(buf, "(keymap %s)", keymap);
|
|
|
|
xmlFree(keymap);
|
|
|
|
}
|
2006-09-12 01:34:26 +00:00
|
|
|
}
|
|
|
|
}
|
2006-08-26 15:30:44 +00:00
|
|
|
xmlFree(graphics_type);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-12-13 14:08:51 +00:00
|
|
|
/**
|
|
|
|
* virtDomainParseXMLGraphicsDescVFB:
|
2007-02-14 16:16:13 +00:00
|
|
|
* @conn: pointer to the hypervisor connection
|
2006-12-13 14:08:51 +00:00
|
|
|
* @node: node containing graphics description
|
|
|
|
* @buf: a buffer for the result S-Expr
|
|
|
|
*
|
2007-02-07 13:50:18 +00:00
|
|
|
* Parse the graphics part of 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
|
2006-12-13 14:08:51 +00:00
|
|
|
* valid over time.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, -1 in case of error
|
|
|
|
*/
|
2007-10-24 14:22:25 +00:00
|
|
|
static int
|
|
|
|
virDomainParseXMLGraphicsDescVFB(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
xmlNodePtr node, virBufferPtr buf)
|
2006-12-13 14:08:51 +00:00
|
|
|
{
|
|
|
|
xmlChar *graphics_type = NULL;
|
|
|
|
|
|
|
|
graphics_type = xmlGetProp(node, BAD_CAST "type");
|
|
|
|
if (graphics_type != NULL) {
|
|
|
|
virBufferAdd(buf, "(device (vkbd))", 15);
|
|
|
|
virBufferAdd(buf, "(device (vfb ", 13);
|
|
|
|
if (xmlStrEqual(graphics_type, BAD_CAST "sdl")) {
|
|
|
|
virBufferAdd(buf, "(type sdl)", 10);
|
|
|
|
/* TODO:
|
|
|
|
* Need to understand sdl options
|
|
|
|
*
|
|
|
|
*virBufferAdd(buf, "(display localhost:10.0)", 24);
|
|
|
|
*virBufferAdd(buf, "(xauthority /root/.Xauthority)", 30);
|
|
|
|
*/
|
2007-10-24 14:22:25 +00:00
|
|
|
} else if (xmlStrEqual(graphics_type, BAD_CAST "vnc")) {
|
2006-12-13 14:08:51 +00:00
|
|
|
virBufferAdd(buf, "(type vnc)", 10);
|
|
|
|
xmlChar *vncport = xmlGetProp(node, BAD_CAST "port");
|
|
|
|
xmlChar *vnclisten = xmlGetProp(node, BAD_CAST "listen");
|
|
|
|
xmlChar *vncpasswd = xmlGetProp(node, BAD_CAST "passwd");
|
2007-03-06 20:00:17 +00:00
|
|
|
xmlChar *keymap = xmlGetProp(node, BAD_CAST "keymap");
|
2007-10-24 14:22:25 +00:00
|
|
|
|
2006-12-13 14:08:51 +00:00
|
|
|
if (vncport != NULL) {
|
2007-10-24 14:22:25 +00:00
|
|
|
long port = strtol((const char *) vncport, NULL, 10);
|
|
|
|
|
2006-12-13 14:08:51 +00:00
|
|
|
if (port == -1)
|
|
|
|
virBufferAdd(buf, "(vncunused 1)", 13);
|
2007-03-08 08:55:56 +00:00
|
|
|
else if (port >= 5900)
|
2007-10-24 14:22:25 +00:00
|
|
|
virBufferVSprintf(buf, "(vncdisplay %ld)",
|
|
|
|
port - 5900);
|
2006-12-13 14:08:51 +00:00
|
|
|
xmlFree(vncport);
|
|
|
|
}
|
|
|
|
if (vnclisten != NULL) {
|
|
|
|
virBufferVSprintf(buf, "(vnclisten %s)", vnclisten);
|
|
|
|
xmlFree(vnclisten);
|
|
|
|
}
|
|
|
|
if (vncpasswd != NULL) {
|
|
|
|
virBufferVSprintf(buf, "(vncpasswd %s)", vncpasswd);
|
|
|
|
xmlFree(vncpasswd);
|
|
|
|
}
|
2007-03-06 20:00:17 +00:00
|
|
|
if (keymap != NULL) {
|
|
|
|
virBufferVSprintf(buf, "(keymap %s)", keymap);
|
|
|
|
xmlFree(keymap);
|
|
|
|
}
|
2006-12-13 14:08:51 +00:00
|
|
|
}
|
|
|
|
virBufferAdd(buf, "))", 2);
|
|
|
|
xmlFree(graphics_type);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-16 22:50:52 +00:00
|
|
|
/**
|
2006-07-10 11:21:24 +00:00
|
|
|
* virDomainParseXMLOSDescHVM:
|
2007-02-14 16:16:13 +00:00
|
|
|
* @conn: pointer to the hypervisor connection
|
2006-07-10 11:21:24 +00:00
|
|
|
* @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
|
2007-02-07 13:44:22 +00:00
|
|
|
* @vcpus: number of virtual CPUs to configure
|
2006-09-12 01:16:22 +00:00
|
|
|
* @xendConfigVersion: xend configuration file format
|
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
|
2007-10-24 14:22:25 +00:00
|
|
|
virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node,
|
|
|
|
virBufferPtr buf, xmlXPathContextPtr ctxt,
|
|
|
|
int vcpus, int xendConfigVersion)
|
2006-07-10 11:21:24 +00:00
|
|
|
{
|
|
|
|
xmlNodePtr cur, txt;
|
2007-07-18 21:08:22 +00:00
|
|
|
xmlNodePtr *nodes = NULL;
|
2006-10-06 15:32:48 +00:00
|
|
|
xmlChar *type = NULL;
|
|
|
|
xmlChar *loader = NULL;
|
2007-04-13 00:43:57 +00:00
|
|
|
char bootorder[5];
|
|
|
|
int nbootorder = 0;
|
2007-07-18 21:08:22 +00:00
|
|
|
int res, nb_nodes;
|
2007-04-06 12:28:24 +00:00
|
|
|
char *str;
|
2006-07-10 11:21:24 +00:00
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE) {
|
2007-10-24 14:22:25 +00:00
|
|
|
if ((type == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "type"))) {
|
2006-07-10 11:21:24 +00:00
|
|
|
txt = cur->children;
|
|
|
|
if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
|
2007-02-07 13:50:18 +00:00
|
|
|
(txt->next == NULL))
|
2006-07-10 11:21:24 +00:00
|
|
|
type = txt->content;
|
|
|
|
} else if ((loader == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "loader"))) {
|
|
|
|
txt = cur->children;
|
|
|
|
if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
|
2007-02-07 13:50:18 +00:00
|
|
|
(txt->next == NULL))
|
2006-07-10 11:21:24 +00:00
|
|
|
loader = txt->content;
|
2007-04-13 00:43:57 +00:00
|
|
|
} else if ((xmlStrEqual(cur->name, BAD_CAST "boot"))) {
|
|
|
|
xmlChar *boot_dev = xmlGetProp(cur, BAD_CAST "dev");
|
2007-10-24 14:22:25 +00:00
|
|
|
|
|
|
|
if (nbootorder ==
|
|
|
|
((sizeof(bootorder) / sizeof(bootorder[0])) - 1)) {
|
|
|
|
virXMLError(conn, VIR_ERR_XML_ERROR,
|
|
|
|
"too many boot devices", 0);
|
2007-04-13 00:43:57 +00:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
if (xmlStrEqual(boot_dev, BAD_CAST "fd")) {
|
|
|
|
bootorder[nbootorder++] = 'a';
|
|
|
|
} else if (xmlStrEqual(boot_dev, BAD_CAST "cdrom")) {
|
|
|
|
bootorder[nbootorder++] = 'd';
|
|
|
|
} else if (xmlStrEqual(boot_dev, BAD_CAST "network")) {
|
|
|
|
bootorder[nbootorder++] = 'n';
|
|
|
|
} else if (xmlStrEqual(boot_dev, BAD_CAST "hd")) {
|
|
|
|
bootorder[nbootorder++] = 'c';
|
|
|
|
} else {
|
|
|
|
xmlFree(boot_dev);
|
|
|
|
/* Any other type of boot dev is unsupported right now */
|
|
|
|
virXMLError(conn, VIR_ERR_XML_ERROR, NULL, 0);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
xmlFree(boot_dev);
|
2006-07-10 11:21:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
2007-04-13 00:43:57 +00:00
|
|
|
bootorder[nbootorder] = '\0';
|
2006-07-10 11:21:24 +00:00
|
|
|
if ((type == NULL) || (!xmlStrEqual(type, BAD_CAST "hvm"))) {
|
|
|
|
/* VIR_ERR_OS_TYPE */
|
2007-02-14 16:16:13 +00:00
|
|
|
virXMLError(conn, VIR_ERR_OS_TYPE, (const char *) type, 0);
|
2006-07-10 11:21:24 +00:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
virBufferAdd(buf, "(image (hvm ", 12);
|
|
|
|
if (loader == NULL) {
|
2007-02-14 16:16:13 +00:00
|
|
|
virXMLError(conn, VIR_ERR_NO_KERNEL, NULL, 0);
|
2007-02-07 13:50:18 +00:00
|
|
|
goto error;
|
2006-07-10 11:21:24 +00:00
|
|
|
} else {
|
2007-02-07 13:50:18 +00:00
|
|
|
virBufferVSprintf(buf, "(kernel '%s')", (const char *) loader);
|
2006-07-10 11:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* get the device emulation model */
|
2007-04-06 12:28:24 +00:00
|
|
|
str = virXPathString("string(/domain/devices/emulator[1])", ctxt);
|
|
|
|
if (str == NULL) {
|
2007-10-24 14:22:25 +00:00
|
|
|
virXMLError(conn, VIR_ERR_NO_KERNEL, NULL, 0); /* TODO: error */
|
2006-07-10 11:21:24 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-04-06 12:28:24 +00:00
|
|
|
virBufferVSprintf(buf, "(device_model '%s')", str);
|
|
|
|
xmlFree(str);
|
2006-07-10 11:21:24 +00:00
|
|
|
|
2007-02-07 13:44:22 +00:00
|
|
|
virBufferVSprintf(buf, "(vcpus %d)", vcpus);
|
|
|
|
|
2007-04-13 00:43:57 +00:00
|
|
|
if (nbootorder)
|
|
|
|
virBufferVSprintf(buf, "(boot %s)", bootorder);
|
2007-02-07 13:50:18 +00:00
|
|
|
|
2007-04-13 00:43:57 +00:00
|
|
|
/* get the 1st floppy device file */
|
2007-10-24 14:22:25 +00:00
|
|
|
cur = virXPathNode(
|
|
|
|
"/domain/devices/disk[@device='floppy' and target/@dev='fda']/source",
|
|
|
|
ctxt);
|
|
|
|
if (cur != NULL) {
|
2007-04-13 00:43:57 +00:00
|
|
|
xmlChar *fdfile;
|
2007-10-24 14:22:25 +00:00
|
|
|
|
2007-04-13 00:43:57 +00:00
|
|
|
fdfile = xmlGetProp(cur, BAD_CAST "file");
|
2007-10-24 14:22:25 +00:00
|
|
|
if (fdfile != NULL) {
|
2007-04-13 00:43:57 +00:00
|
|
|
virBufferVSprintf(buf, "(fda '%s')", fdfile);
|
|
|
|
free(fdfile);
|
2007-10-24 14:22:25 +00:00
|
|
|
}
|
2007-04-13 00:43:57 +00:00
|
|
|
}
|
2007-02-07 13:50:18 +00:00
|
|
|
|
2007-04-13 00:43:57 +00:00
|
|
|
/* get the 2nd floppy device file */
|
2007-10-24 14:22:25 +00:00
|
|
|
cur = virXPathNode(
|
|
|
|
"/domain/devices/disk[@device='floppy' and target/@dev='fdb']/source",
|
|
|
|
ctxt);
|
|
|
|
if (cur != NULL) {
|
2007-04-13 00:43:57 +00:00
|
|
|
xmlChar *fdfile;
|
2007-10-24 14:22:25 +00:00
|
|
|
|
2007-04-13 00:43:57 +00:00
|
|
|
fdfile = xmlGetProp(cur, BAD_CAST "file");
|
2007-10-24 14:22:25 +00:00
|
|
|
if (fdfile != NULL) {
|
2007-04-13 00:43:57 +00:00
|
|
|
virBufferVSprintf(buf, "(fdb '%s')", fdfile);
|
|
|
|
free(fdfile);
|
2007-10-24 14:22:25 +00:00
|
|
|
}
|
2007-04-13 00:43:57 +00:00
|
|
|
}
|
2007-02-07 13:50:18 +00:00
|
|
|
|
|
|
|
|
2007-04-13 00:43:57 +00:00
|
|
|
/* get the cdrom device file */
|
|
|
|
/* Only XenD <= 3.0.2 wants cdrom config here */
|
|
|
|
if (xendConfigVersion == 1) {
|
2007-10-24 14:22:25 +00:00
|
|
|
cur = virXPathNode(
|
|
|
|
"/domain/devices/disk[@device='cdrom' and target/@dev='hdc']/source",
|
|
|
|
ctxt);
|
|
|
|
if (cur != NULL) {
|
2007-04-13 00:43:57 +00:00
|
|
|
xmlChar *cdfile;
|
|
|
|
|
|
|
|
cdfile = xmlGetProp(cur, BAD_CAST "file");
|
|
|
|
if (cdfile != NULL) {
|
|
|
|
virBufferVSprintf(buf, "(cdrom '%s')",
|
2007-10-24 14:22:25 +00:00
|
|
|
(const char *) cdfile);
|
2007-04-13 00:43:57 +00:00
|
|
|
xmlFree(cdfile);
|
2007-02-07 13:50:18 +00:00
|
|
|
}
|
|
|
|
}
|
2006-08-11 14:40:04 +00:00
|
|
|
}
|
|
|
|
|
2007-04-13 00:43:57 +00:00
|
|
|
if (virXPathNode("/domain/features/acpi", ctxt) != NULL)
|
|
|
|
virBufferAdd(buf, "(acpi 1)", 8);
|
|
|
|
if (virXPathNode("/domain/features/apic", ctxt) != NULL)
|
|
|
|
virBufferAdd(buf, "(apic 1)", 8);
|
|
|
|
if (virXPathNode("/domain/features/pae", ctxt) != NULL)
|
|
|
|
virBufferAdd(buf, "(pae 1)", 7);
|
|
|
|
|
2007-07-18 21:08:22 +00:00
|
|
|
virBufferAdd(buf, "(usb 1)", 7);
|
|
|
|
nb_nodes = virXPathNodeSet("/domain/devices/input", ctxt, &nodes);
|
|
|
|
if (nb_nodes > 0) {
|
|
|
|
int i;
|
2007-10-24 14:22:25 +00:00
|
|
|
|
2007-07-18 21:08:22 +00:00
|
|
|
for (i = 0; i < nb_nodes; i++) {
|
|
|
|
xmlChar *itype = NULL, *bus = NULL;
|
|
|
|
int isMouse = 1;
|
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
itype = xmlGetProp(nodes[i], (xmlChar *) "type");
|
2007-07-18 21:08:22 +00:00
|
|
|
|
|
|
|
if (!itype) {
|
|
|
|
goto error;
|
|
|
|
}
|
2007-10-24 14:22:25 +00:00
|
|
|
if (!strcmp((const char *) itype, "tablet"))
|
2007-07-18 21:08:22 +00:00
|
|
|
isMouse = 0;
|
2007-10-24 14:22:25 +00:00
|
|
|
else if (strcmp((const char *) itype, "mouse")) {
|
2007-07-18 21:08:22 +00:00
|
|
|
xmlFree(itype);
|
|
|
|
virXMLError(conn, VIR_ERR_XML_ERROR, "input", 0);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
xmlFree(itype);
|
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
bus = xmlGetProp(nodes[i], (xmlChar *) "bus");
|
2007-07-18 21:08:22 +00:00
|
|
|
if (!bus) {
|
|
|
|
if (!isMouse) {
|
|
|
|
/* Nothing - implicit ps2 */
|
|
|
|
} else {
|
|
|
|
virBufferAdd(buf, "(usbdevice tablet)", 13);
|
|
|
|
}
|
|
|
|
} else {
|
2007-10-24 14:22:25 +00:00
|
|
|
if (!strcmp((const char *) bus, "ps2")) {
|
2007-07-18 21:08:22 +00:00
|
|
|
if (!isMouse) {
|
|
|
|
xmlFree(bus);
|
|
|
|
virXMLError(conn, VIR_ERR_XML_ERROR, "input", 0);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
/* Nothing - implicit ps2 */
|
2007-10-24 14:22:25 +00:00
|
|
|
} else if (!strcmp((const char *) bus, "usb")) {
|
2007-07-18 21:08:22 +00:00
|
|
|
if (isMouse)
|
|
|
|
virBufferAdd(buf, "(usbdevice mouse)", 17);
|
|
|
|
else
|
|
|
|
virBufferAdd(buf, "(usbdevice tablet)", 18);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xmlFree(bus);
|
|
|
|
}
|
|
|
|
free(nodes);
|
|
|
|
nodes = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
res = virXPathBoolean("count(domain/devices/console) > 0", ctxt);
|
|
|
|
if (res < 0) {
|
2007-02-14 16:16:13 +00:00
|
|
|
virXMLError(conn, VIR_ERR_XML_ERROR, NULL, 0);
|
2007-02-07 13:50:18 +00:00
|
|
|
goto error;
|
2006-08-11 14:40:04 +00:00
|
|
|
}
|
2007-04-06 12:28:24 +00:00
|
|
|
if (res) {
|
2007-02-07 13:50:18 +00:00
|
|
|
virBufferAdd(buf, "(serial pty)", 12);
|
2006-08-11 14:40:04 +00:00
|
|
|
}
|
2007-02-07 13:50:18 +00:00
|
|
|
|
2007-04-13 00:43:57 +00:00
|
|
|
/* HVM graphics for xen <= 3.0.5 */
|
|
|
|
if (xendConfigVersion < 4) {
|
|
|
|
/* Is a graphics device specified? */
|
|
|
|
cur = virXPathNode("/domain/devices/graphics[1]", ctxt);
|
|
|
|
if (cur != NULL) {
|
|
|
|
res = virDomainParseXMLGraphicsDescImage(conn, cur, buf,
|
|
|
|
xendConfigVersion);
|
|
|
|
if (res != 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
2006-07-10 11:21:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-16 21:30:30 +00:00
|
|
|
str = virXPathString("string(/domain/clock/@offset)", ctxt);
|
|
|
|
if (str != NULL && !strcmp(str, "localtime")) {
|
|
|
|
virBufferAdd(buf, "(localtime 1)", 13);
|
|
|
|
}
|
2007-07-31 14:27:12 +00:00
|
|
|
if (str)
|
|
|
|
free(str);
|
2007-07-16 21:30:30 +00:00
|
|
|
|
2006-07-10 11:21:24 +00:00
|
|
|
virBufferAdd(buf, "))", 2);
|
|
|
|
|
|
|
|
return (0);
|
2007-04-13 00:43:57 +00:00
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
error:
|
2007-07-18 21:08:22 +00:00
|
|
|
if (nodes)
|
|
|
|
free(nodes);
|
2007-10-24 14:22:25 +00:00
|
|
|
return (-1);
|
2006-07-10 11:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virDomainParseXMLOSDescPV:
|
2007-02-14 16:16:13 +00:00
|
|
|
* @conn: pointer to the hypervisor connection
|
2006-07-10 11:21:24 +00:00
|
|
|
* @node: node containing PV OS description
|
|
|
|
* @buf: a buffer for the result S-Expr
|
2006-08-26 15:30:44 +00:00
|
|
|
* @ctxt: a path context representing the XML description
|
2006-09-12 01:34:26 +00:00
|
|
|
* @xendConfigVersion: xend configuration file format
|
2006-07-10 11:21:24 +00:00
|
|
|
*
|
|
|
|
* 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
|
2007-10-24 14:22:25 +00:00
|
|
|
virDomainParseXMLOSDescPV(virConnectPtr conn, xmlNodePtr node,
|
|
|
|
virBufferPtr buf, xmlXPathContextPtr ctxt,
|
|
|
|
int xendConfigVersion)
|
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;
|
2006-08-26 15:30:44 +00:00
|
|
|
int res;
|
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 ((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) &&
|
2007-02-07 13:50:18 +00:00
|
|
|
(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) &&
|
2007-02-07 13:50:18 +00:00
|
|
|
(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) &&
|
2007-02-07 13:50:18 +00:00
|
|
|
(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) &&
|
2007-02-07 13:50:18 +00:00
|
|
|
(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) &&
|
2007-02-07 13:50:18 +00:00
|
|
|
(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 */
|
2007-02-14 16:16:13 +00:00
|
|
|
virXMLError(conn, VIR_ERR_OS_TYPE, (const char *) type, 0);
|
2006-03-15 12:13:25 +00:00
|
|
|
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) {
|
2007-02-14 16:16:13 +00:00
|
|
|
virXMLError(conn, VIR_ERR_NO_KERNEL, NULL, 0);
|
2007-02-07 13:50:18 +00:00
|
|
|
return (-1);
|
2006-03-30 16:08:13 +00:00
|
|
|
} else {
|
2007-02-07 13:50:18 +00:00
|
|
|
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-08-26 15:30:44 +00:00
|
|
|
|
2007-04-13 00:43:57 +00:00
|
|
|
/* PV graphics for xen <= 3.0.4 */
|
2006-12-13 14:08:51 +00:00
|
|
|
if (xendConfigVersion < 3) {
|
2007-04-06 12:28:24 +00:00
|
|
|
cur = virXPathNode("/domain/devices/graphics[1]", ctxt);
|
|
|
|
if (cur != NULL) {
|
|
|
|
res = virDomainParseXMLGraphicsDescImage(conn, cur, buf,
|
2007-04-13 00:43:57 +00:00
|
|
|
xendConfigVersion);
|
2006-12-13 14:08:51 +00:00
|
|
|
if (res != 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
2006-08-26 15:30:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
error:
|
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
|
|
|
}
|
|
|
|
|
2006-11-08 16:55:20 +00:00
|
|
|
/**
|
|
|
|
* virCatchXMLParseError:
|
|
|
|
* @ctx: the context
|
|
|
|
* @msg: the error message
|
|
|
|
* @...: extra arguments
|
|
|
|
*
|
|
|
|
* SAX callback on parsing errors, act as a gate for libvirt own
|
|
|
|
* error reporting.
|
|
|
|
*/
|
|
|
|
static void
|
2007-10-24 14:22:25 +00:00
|
|
|
virCatchXMLParseError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
|
|
|
|
{
|
2006-11-08 16:55:20 +00:00
|
|
|
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
|
|
|
|
|
2006-11-17 00:10:51 +00:00
|
|
|
if ((ctxt != NULL) &&
|
2006-11-08 16:55:20 +00:00
|
|
|
(ctxt->lastError.level == XML_ERR_FATAL) &&
|
2006-11-17 00:10:51 +00:00
|
|
|
(ctxt->lastError.message != NULL)) {
|
2007-02-14 16:16:13 +00:00
|
|
|
virXMLError(NULL, VIR_ERR_XML_DETAIL, ctxt->lastError.message,
|
2007-02-07 13:50:18 +00:00
|
|
|
ctxt->lastError.line);
|
2006-11-08 16:55:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-16 22:50:52 +00:00
|
|
|
/**
|
|
|
|
* virDomainParseXMLDiskDesc:
|
2006-07-10 11:21:24 +00:00
|
|
|
* @node: node containing disk description
|
2007-02-14 16:16:13 +00:00
|
|
|
* @conn: pointer to the hypervisor connection
|
2006-02-16 22:50:52 +00:00
|
|
|
* @buf: a buffer for the result S-Expr
|
2006-09-12 01:16:22 +00:00
|
|
|
* @xendConfigVersion: xend configuration file format
|
2006-02-16 22:50:52 +00:00
|
|
|
*
|
|
|
|
* 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
|
2007-10-24 14:22:25 +00:00
|
|
|
virDomainParseXMLDiskDesc(virConnectPtr conn, xmlNodePtr node,
|
|
|
|
virBufferPtr buf, int hvm, int xendConfigVersion)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2006-02-16 22:50:52 +00:00
|
|
|
xmlNodePtr cur;
|
|
|
|
xmlChar *type = NULL;
|
2006-08-11 14:40:04 +00:00
|
|
|
xmlChar *device = NULL;
|
2006-02-16 22:50:52 +00:00
|
|
|
xmlChar *source = NULL;
|
|
|
|
xmlChar *target = NULL;
|
2006-10-09 14:32:07 +00:00
|
|
|
xmlChar *drvName = NULL;
|
|
|
|
xmlChar *drvType = NULL;
|
2006-02-16 22:50:52 +00:00
|
|
|
int ro = 0;
|
2006-11-13 17:09:31 +00:00
|
|
|
int shareable = 0;
|
2006-02-16 22:50:52 +00:00
|
|
|
int typ = 0;
|
2006-09-12 01:16:22 +00:00
|
|
|
int cdrom = 0;
|
2007-04-11 16:06:30 +00:00
|
|
|
int isNoSrcCdrom = 0;
|
2007-07-11 08:41:11 +00:00
|
|
|
int ret = 0;
|
2006-02-16 22:50:52 +00:00
|
|
|
|
|
|
|
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
|
|
|
}
|
2006-08-11 14:40:04 +00:00
|
|
|
device = xmlGetProp(node, BAD_CAST "device");
|
2006-10-09 14:32:07 +00:00
|
|
|
|
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");
|
2006-10-09 14:32:07 +00:00
|
|
|
} else if ((drvName == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "driver"))) {
|
|
|
|
drvName = xmlGetProp(cur, BAD_CAST "name");
|
2007-10-24 14:22:25 +00:00
|
|
|
if (drvName && !strcmp((const char *) drvName, "tap"))
|
2006-10-09 14:32:07 +00:00
|
|
|
drvType = xmlGetProp(cur, BAD_CAST "type");
|
2006-03-15 12:13:25 +00:00
|
|
|
} else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
|
|
|
|
ro = 1;
|
2006-11-13 17:09:31 +00:00
|
|
|
} else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
|
2007-02-07 13:50:18 +00:00
|
|
|
shareable = 1;
|
2006-03-15 12:13:25 +00:00
|
|
|
}
|
|
|
|
}
|
2006-02-16 22:50:52 +00:00
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (source == NULL) {
|
2007-04-11 16:06:30 +00:00
|
|
|
/* There is a case without the source
|
|
|
|
* to the CD-ROM device
|
|
|
|
*/
|
2007-10-24 14:22:25 +00:00
|
|
|
if (hvm && device && !strcmp((const char *) device, "cdrom")) {
|
2007-04-11 16:06:30 +00:00
|
|
|
isNoSrcCdrom = 1;
|
|
|
|
}
|
|
|
|
if (!isNoSrcCdrom) {
|
|
|
|
virXMLError(conn, VIR_ERR_NO_SOURCE, (const char *) target, 0);
|
2007-07-11 08:41:11 +00:00
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
2007-04-11 16:06:30 +00:00
|
|
|
}
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
if (target == NULL) {
|
2007-02-14 16:16:13 +00:00
|
|
|
virXMLError(conn, VIR_ERR_NO_TARGET, (const char *) source, 0);
|
2007-07-11 08:41:11 +00:00
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
2006-08-11 14:40:04 +00:00
|
|
|
|
2006-09-12 01:16:22 +00:00
|
|
|
/* Xend (all versions) put the floppy device config
|
|
|
|
* under the hvm (image (os)) block
|
2006-08-11 14:40:04 +00:00
|
|
|
*/
|
2007-10-24 14:22:25 +00:00
|
|
|
if (hvm && device && !strcmp((const char *) device, "floppy")) {
|
2006-10-06 15:32:48 +00:00
|
|
|
goto cleanup;
|
2006-09-12 01:16:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Xend <= 3.0.2 doesn't include cdrom config here */
|
2007-10-24 14:22:25 +00:00
|
|
|
if (hvm && device && !strcmp((const char *) device, "cdrom")) {
|
2006-09-12 01:16:22 +00:00
|
|
|
if (xendConfigVersion == 1)
|
2006-10-06 15:32:48 +00:00
|
|
|
goto cleanup;
|
2006-09-12 01:16:22 +00:00
|
|
|
else
|
|
|
|
cdrom = 1;
|
2006-08-11 14:40:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virBufferAdd(buf, "(device ", 8);
|
2006-10-09 14:32:07 +00:00
|
|
|
/* Normally disks are in a (device (vbd ...)) block
|
2007-10-24 14:22:25 +00:00
|
|
|
* but blktap disks ended up in a differently named
|
|
|
|
* (device (tap ....)) block.... */
|
|
|
|
if (drvName && !strcmp((const char *) drvName, "tap")) {
|
2006-10-09 14:32:07 +00:00
|
|
|
virBufferAdd(buf, "(tap ", 5);
|
|
|
|
} else {
|
|
|
|
virBufferAdd(buf, "(vbd ", 5);
|
|
|
|
}
|
2006-09-12 01:16:22 +00:00
|
|
|
|
2006-08-11 14:40:04 +00:00
|
|
|
if (hvm) {
|
2007-10-24 14:22:25 +00:00
|
|
|
char *tmp = (char *) target;
|
|
|
|
|
2006-09-12 01:16:22 +00:00
|
|
|
/* Just in case user mistakenly still puts ioemu: in their XML */
|
2006-08-11 14:40:04 +00:00
|
|
|
if (!strncmp((const char *) tmp, "ioemu:", 6))
|
|
|
|
tmp += 6;
|
2006-09-12 01:16:22 +00:00
|
|
|
|
|
|
|
/* Xend <= 3.0.2 wants a ioemu: prefix on devices for HVM */
|
|
|
|
if (xendConfigVersion == 1)
|
2007-10-24 14:22:25 +00:00
|
|
|
virBufferVSprintf(buf, "(dev 'ioemu:%s')", (const char *) tmp);
|
|
|
|
else /* But newer does not */
|
|
|
|
virBufferVSprintf(buf, "(dev '%s%s')", (const char *) tmp,
|
|
|
|
cdrom ? ":cdrom" : ":disk");
|
2006-08-11 14:40:04 +00:00
|
|
|
} else
|
2007-10-24 14:22:25 +00:00
|
|
|
virBufferVSprintf(buf, "(dev '%s')", (const char *) target);
|
2006-10-09 14:32:07 +00:00
|
|
|
|
2007-04-11 16:06:30 +00:00
|
|
|
if (drvName && !isNoSrcCdrom) {
|
2007-10-24 14:22:25 +00:00
|
|
|
if (!strcmp((const char *) drvName, "tap")) {
|
2006-10-09 14:32:07 +00:00
|
|
|
virBufferVSprintf(buf, "(uname '%s:%s:%s')",
|
2007-10-24 14:22:25 +00:00
|
|
|
(const char *) drvName,
|
|
|
|
(drvType ? (const char *) drvType : "aio"),
|
|
|
|
(const char *) source);
|
2006-10-09 14:32:07 +00:00
|
|
|
} else {
|
|
|
|
virBufferVSprintf(buf, "(uname '%s:%s')",
|
2007-10-24 14:22:25 +00:00
|
|
|
(const char *) drvName,
|
|
|
|
(const char *) source);
|
2006-10-09 14:32:07 +00:00
|
|
|
}
|
2007-04-11 16:06:30 +00:00
|
|
|
} else if (!isNoSrcCdrom) {
|
2006-10-09 14:32:07 +00:00
|
|
|
if (typ == 0)
|
|
|
|
virBufferVSprintf(buf, "(uname 'file:%s')", source);
|
|
|
|
else if (typ == 1) {
|
|
|
|
if (source[0] == '/')
|
|
|
|
virBufferVSprintf(buf, "(uname 'phy:%s')", source);
|
|
|
|
else
|
|
|
|
virBufferVSprintf(buf, "(uname 'phy:/dev/%s')", source);
|
|
|
|
}
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
2006-11-13 17:09:31 +00:00
|
|
|
if (ro == 1)
|
2006-02-16 22:50:52 +00:00
|
|
|
virBufferVSprintf(buf, "(mode 'r')");
|
2006-11-13 17:09:31 +00:00
|
|
|
else if (shareable == 1)
|
|
|
|
virBufferVSprintf(buf, "(mode 'w!')");
|
|
|
|
else
|
|
|
|
virBufferVSprintf(buf, "(mode 'w')");
|
2006-02-16 22:50:52 +00:00
|
|
|
|
2006-08-11 14:40:04 +00:00
|
|
|
virBufferAdd(buf, ")", 1);
|
2006-02-16 22:50:52 +00:00
|
|
|
virBufferAdd(buf, ")", 1);
|
2006-10-06 15:32:48 +00:00
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
cleanup:
|
|
|
|
if (drvType)
|
2007-07-11 08:41:11 +00:00
|
|
|
xmlFree(drvType);
|
2007-10-24 14:22:25 +00:00
|
|
|
if (drvName)
|
2007-07-11 08:41:11 +00:00
|
|
|
xmlFree(drvName);
|
2007-10-24 14:22:25 +00:00
|
|
|
if (device)
|
2007-07-11 08:41:11 +00:00
|
|
|
xmlFree(device);
|
2007-10-24 14:22:25 +00:00
|
|
|
if (target)
|
2007-07-11 08:41:11 +00:00
|
|
|
xmlFree(target);
|
2007-10-24 14:22:25 +00:00
|
|
|
if (source)
|
2007-07-11 08:41:11 +00:00
|
|
|
xmlFree(source);
|
|
|
|
return (ret);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virDomainParseXMLIfDesc:
|
2007-02-14 16:16:13 +00:00
|
|
|
* @conn: pointer to the hypervisor connection
|
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
|
2007-06-06 14:39:04 +00:00
|
|
|
* @xendConfigVersion: xend configuration file format
|
2006-02-16 22:50:52 +00:00
|
|
|
*
|
|
|
|
* 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
|
2007-10-24 14:22:25 +00:00
|
|
|
virDomainParseXMLIfDesc(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
xmlNodePtr node, virBufferPtr buf, int hvm,
|
|
|
|
int xendConfigVersion)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2006-02-16 22:50:52 +00:00
|
|
|
xmlNodePtr cur;
|
|
|
|
xmlChar *type = NULL;
|
|
|
|
xmlChar *source = NULL;
|
|
|
|
xmlChar *mac = NULL;
|
|
|
|
xmlChar *script = NULL;
|
2006-11-15 00:38:13 +00:00
|
|
|
xmlChar *ip = NULL;
|
2006-02-16 22:50:52 +00:00
|
|
|
int typ = 0;
|
2007-02-14 16:22:02 +00:00
|
|
|
int ret = -1;
|
2006-02-16 22:50:52 +00:00
|
|
|
|
|
|
|
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;
|
2007-02-14 16:22:02 +00:00
|
|
|
else if (xmlStrEqual(type, BAD_CAST "network"))
|
|
|
|
typ = 2;
|
2006-03-15 12:13:25 +00:00
|
|
|
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");
|
2007-02-14 16:22:02 +00:00
|
|
|
else if (typ == 1)
|
2006-03-15 12:13:25 +00:00
|
|
|
source = xmlGetProp(cur, BAD_CAST "dev");
|
2007-02-14 16:22:02 +00:00
|
|
|
else
|
|
|
|
source = xmlGetProp(cur, BAD_CAST "network");
|
2006-03-15 12:13:25 +00:00
|
|
|
} 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-11-15 00:38:13 +00:00
|
|
|
} else if ((ip == NULL) &&
|
|
|
|
(xmlStrEqual(cur->name, BAD_CAST "ip"))) {
|
|
|
|
/* XXX in future expect to need to have > 1 ip
|
2007-10-24 14:22:25 +00:00
|
|
|
* address element - eg ipv4 & ipv6. For now
|
|
|
|
* xen only supports a single address though
|
|
|
|
* so lets ignore that complication */
|
2006-11-15 00:38:13 +00:00
|
|
|
ip = xmlGetProp(cur, BAD_CAST "address");
|
2006-03-15 12:13:25 +00:00
|
|
|
}
|
|
|
|
}
|
2006-02-16 22:50:52 +00:00
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAdd(buf, "(vif ", 5);
|
2007-07-13 08:26:57 +00:00
|
|
|
if (mac != NULL) {
|
|
|
|
unsigned int addr[12];
|
2007-10-24 14:22:25 +00:00
|
|
|
int tmp = sscanf((const char *) mac,
|
|
|
|
"%01x%01x:%01x%01x:%01x%01x:%01x%01x:%01x%01x:%01x%01x",
|
|
|
|
(unsigned int *) &addr[0],
|
|
|
|
(unsigned int *) &addr[1],
|
|
|
|
(unsigned int *) &addr[2],
|
|
|
|
(unsigned int *) &addr[3],
|
|
|
|
(unsigned int *) &addr[4],
|
|
|
|
(unsigned int *) &addr[5],
|
|
|
|
(unsigned int *) &addr[6],
|
|
|
|
(unsigned int *) &addr[7],
|
|
|
|
(unsigned int *) &addr[8],
|
|
|
|
(unsigned int *) &addr[9],
|
|
|
|
(unsigned int *) &addr[10],
|
|
|
|
(unsigned int *) &addr[11]);
|
2007-07-13 08:26:57 +00:00
|
|
|
if (tmp != 12 || strlen((const char *) mac) != 17) {
|
|
|
|
virXMLError(conn, VIR_ERR_INVALID_MAC, (const char *) mac, 0);
|
|
|
|
goto error;
|
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferVSprintf(buf, "(mac '%s')", (const char *) mac);
|
2007-07-13 08:26:57 +00:00
|
|
|
}
|
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);
|
2007-02-14 16:22:02 +00:00
|
|
|
else if (typ == 1) /* TODO does that work like that ? */
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferVSprintf(buf, "(dev '%s')", (const char *) source);
|
2007-02-14 16:22:02 +00:00
|
|
|
else {
|
2007-10-24 14:22:25 +00:00
|
|
|
virNetworkPtr network =
|
|
|
|
virNetworkLookupByName(conn, (const char *) source);
|
2007-02-14 16:22:02 +00:00
|
|
|
char *bridge;
|
2007-10-24 14:22:25 +00:00
|
|
|
|
2007-02-14 16:22:02 +00:00
|
|
|
if (!network || !(bridge = virNetworkGetBridgeName(network))) {
|
2007-10-10 17:41:06 +00:00
|
|
|
if (network)
|
|
|
|
virNetworkFree(network);
|
2007-10-24 14:22:25 +00:00
|
|
|
virXMLError(conn, VIR_ERR_NO_SOURCE, (const char *) source,
|
|
|
|
0);
|
2007-02-14 16:22:02 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-10-10 17:41:06 +00:00
|
|
|
virNetworkFree(network);
|
2007-02-14 16:22:02 +00:00
|
|
|
virBufferVSprintf(buf, "(bridge '%s')", bridge);
|
|
|
|
free(bridge);
|
|
|
|
}
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
if (script != NULL)
|
|
|
|
virBufferVSprintf(buf, "(script '%s')", script);
|
2006-11-15 00:38:13 +00:00
|
|
|
if (ip != NULL)
|
|
|
|
virBufferVSprintf(buf, "(ip '%s')", ip);
|
2007-06-06 14:39:04 +00:00
|
|
|
/*
|
|
|
|
* apparently (type ioemu) breaks paravirt drivers on HVM so skip this
|
|
|
|
* from Xen 3.1.0
|
|
|
|
*/
|
|
|
|
if ((hvm) && (xendConfigVersion < 4))
|
2006-08-18 20:20:50 +00:00
|
|
|
virBufferAdd(buf, "(type ioemu)", 12);
|
2006-02-16 22:50:52 +00:00
|
|
|
|
|
|
|
virBufferAdd(buf, ")", 1);
|
2007-02-14 16:22:02 +00:00
|
|
|
ret = 0;
|
2007-10-24 14:22:25 +00:00
|
|
|
error:
|
2006-02-16 22:50:52 +00:00
|
|
|
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);
|
2006-11-15 00:38:13 +00:00
|
|
|
if (ip != NULL)
|
|
|
|
xmlFree(ip);
|
2007-02-14 16:22:02 +00:00
|
|
|
return (ret);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virDomainParseXMLDesc:
|
2007-02-14 16:16:13 +00:00
|
|
|
* @conn: pointer to the hypervisor connection
|
2006-02-16 22:50:52 +00:00
|
|
|
* @xmldesc: string with the XML description
|
2006-09-12 01:16:22 +00:00
|
|
|
* @xendConfigVersion: xend configuration file format
|
2006-02-16 22:50:52 +00:00
|
|
|
*
|
|
|
|
* 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 *
|
2007-10-24 14:22:25 +00:00
|
|
|
virDomainParseXMLDesc(virConnectPtr conn, const char *xmldesc, char **name,
|
|
|
|
int xendConfigVersion)
|
2006-03-15 12:13:25 +00:00
|
|
|
{
|
2006-02-16 22:50:52 +00:00
|
|
|
xmlDocPtr xml = NULL;
|
|
|
|
xmlNodePtr node;
|
2007-04-23 07:41:23 +00:00
|
|
|
char *nam = NULL;
|
2006-02-16 22:50:52 +00:00
|
|
|
virBuffer buf;
|
|
|
|
xmlChar *prop;
|
2006-11-08 16:55:20 +00:00
|
|
|
xmlParserCtxtPtr pctxt;
|
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-08-11 14:40:04 +00:00
|
|
|
int hvm = 0;
|
2007-02-07 13:44:22 +00:00
|
|
|
unsigned int vcpus = 1;
|
2006-11-10 11:13:01 +00:00
|
|
|
unsigned long mem = 0, max_mem = 0;
|
2007-04-06 12:28:24 +00:00
|
|
|
char *str;
|
|
|
|
double f;
|
|
|
|
xmlNodePtr *nodes;
|
|
|
|
int nb_nodes;
|
2006-02-16 22:50:52 +00:00
|
|
|
|
|
|
|
if (name != NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
*name = NULL;
|
2007-04-23 07:41:23 +00:00
|
|
|
buf.content = malloc(1000);
|
|
|
|
if (buf.content == NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
2006-02-16 22:50:52 +00:00
|
|
|
buf.size = 1000;
|
|
|
|
buf.use = 0;
|
|
|
|
|
2006-11-08 16:55:20 +00:00
|
|
|
pctxt = xmlNewParserCtxt();
|
|
|
|
if ((pctxt == NULL) || (pctxt->sax == NULL)) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2007-02-14 16:16:13 +00:00
|
|
|
/* TODO pass the connection point to the error handler:
|
|
|
|
* pctxt->userData = virConnectPtr;
|
|
|
|
*/
|
2006-11-08 16:55:20 +00:00
|
|
|
pctxt->sax->error = virCatchXMLParseError;
|
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
xml = xmlCtxtReadDoc(pctxt, (const xmlChar *) xmldesc, "domain.xml",
|
|
|
|
NULL, XML_PARSE_NOENT | XML_PARSE_NONET |
|
2006-11-08 16:55:20 +00:00
|
|
|
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
|
|
|
*/
|
2007-04-06 12:28:24 +00:00
|
|
|
nam = virXPathString("string(/domain/name[1])", ctxt);
|
2006-02-27 22:32:54 +00:00
|
|
|
if (nam == NULL) {
|
2007-04-06 12:28:24 +00:00
|
|
|
virXMLError(conn, VIR_ERR_NO_NAME, xmldesc, 0);
|
2006-03-15 12:13:25 +00:00
|
|
|
goto error;
|
2006-02-27 22:32:54 +00:00
|
|
|
}
|
2007-04-06 12:28:24 +00:00
|
|
|
virBufferVSprintf(&buf, "(name '%s')", nam);
|
2006-02-16 22:50:52 +00:00
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
if ((virXPathNumber("number(/domain/memory[1])", ctxt, &f) < 0) ||
|
|
|
|
(f < MIN_XEN_GUEST_SIZE * 1024)) {
|
2007-02-07 13:50:18 +00:00
|
|
|
max_mem = 128;
|
2006-02-16 22:50:52 +00:00
|
|
|
} else {
|
2007-04-06 12:28:24 +00:00
|
|
|
max_mem = (f / 1024);
|
2006-11-10 11:13:01 +00:00
|
|
|
}
|
2007-04-06 12:28:24 +00:00
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
if ((virXPathNumber("number(/domain/currentMemory[1])", ctxt, &f) < 0)
|
|
|
|
|| (f < MIN_XEN_GUEST_SIZE * 1024)) {
|
2006-11-10 11:13:01 +00:00
|
|
|
mem = max_mem;
|
|
|
|
} else {
|
2007-04-06 12:28:24 +00:00
|
|
|
mem = (f / 1024);
|
2007-02-07 13:50:18 +00:00
|
|
|
if (mem > max_mem) {
|
|
|
|
max_mem = mem;
|
|
|
|
}
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
2006-11-10 11:13:01 +00:00
|
|
|
virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)", mem, max_mem);
|
2006-02-16 22:50:52 +00:00
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
if ((virXPathNumber("number(/domain/vcpu[1])", ctxt, &f) == 0) &&
|
|
|
|
(f > 0)) {
|
|
|
|
vcpus = (unsigned int) f;
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
2007-02-07 13:44:22 +00:00
|
|
|
virBufferVSprintf(&buf, "(vcpus %u)", vcpus);
|
2006-02-16 22:50:52 +00:00
|
|
|
|
2007-10-22 20:28:55 +00:00
|
|
|
str = virXPathString("string(/domain/vcpu/@cpuset)", ctxt);
|
|
|
|
if (str != NULL) {
|
|
|
|
int maxcpu = xenNbCpus(conn);
|
2007-10-24 14:22:25 +00:00
|
|
|
char *cpuset = NULL;
|
|
|
|
char *ranges = NULL;
|
|
|
|
const char *cur = str;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse the CPUset attribute given in libvirt format and reserialize
|
|
|
|
* it in a range format guaranteed to be understood by Xen.
|
|
|
|
*/
|
|
|
|
if (maxcpu > 0) {
|
2007-12-11 21:57:29 +00:00
|
|
|
cpuset = malloc(maxcpu * sizeof(*cpuset));
|
2007-10-24 14:22:25 +00:00
|
|
|
if (cpuset != NULL) {
|
|
|
|
res = virParseCpuSet(conn, &cur, 0, cpuset, maxcpu);
|
|
|
|
if (res > 0) {
|
2007-10-31 09:39:13 +00:00
|
|
|
ranges = virSaveCpuSet(conn, cpuset, maxcpu);
|
2007-10-24 14:22:25 +00:00
|
|
|
if (ranges != NULL) {
|
|
|
|
virBufferVSprintf(&buf, "(cpus '%s')", ranges);
|
|
|
|
free(ranges);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(cpuset);
|
2007-11-05 10:14:42 +00:00
|
|
|
if (res < 0)
|
|
|
|
goto error;
|
2007-10-24 14:22:25 +00:00
|
|
|
} else {
|
|
|
|
virXMLError(conn, VIR_ERR_NO_MEMORY, xmldesc, 0);
|
|
|
|
}
|
|
|
|
}
|
2007-10-22 20:28:55 +00:00
|
|
|
free(str);
|
|
|
|
}
|
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
str = virXPathString("string(/domain/uuid[1])", ctxt);
|
|
|
|
if (str != NULL) {
|
|
|
|
virBufferVSprintf(&buf, "(uuid '%s')", str);
|
2007-10-24 14:22:25 +00:00
|
|
|
free(str);
|
2006-07-13 22:27:31 +00:00
|
|
|
}
|
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
str = virXPathString("string(/domain/bootloader[1])", ctxt);
|
|
|
|
if (str != NULL) {
|
|
|
|
virBufferVSprintf(&buf, "(bootloader '%s')", str);
|
2007-02-07 13:50:18 +00:00
|
|
|
/*
|
2007-06-07 13:50:18 +00:00
|
|
|
* if using a bootloader, the kernel and initrd strings are not
|
2007-02-07 13:50:18 +00:00
|
|
|
* significant and should be discarded
|
|
|
|
*/
|
2007-06-07 13:50:18 +00:00
|
|
|
bootloader = 1;
|
2007-10-24 14:22:25 +00:00
|
|
|
free(str);
|
|
|
|
} else if (virXPathNumber("count(/domain/bootloader)", ctxt, &f) == 0
|
|
|
|
&& (f > 0)) {
|
2007-09-29 18:31:05 +00:00
|
|
|
virBufferVSprintf(&buf, "(bootloader)");
|
|
|
|
/*
|
|
|
|
* if using a bootloader, the kernel and initrd strings are not
|
|
|
|
* significant and should be discarded
|
|
|
|
*/
|
2007-10-24 14:22:25 +00:00
|
|
|
bootloader = 1;
|
2007-06-07 13:50:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
str = virXPathString("string(/domain/bootloader_args[1])", ctxt);
|
|
|
|
if (str != NULL && bootloader) {
|
|
|
|
/*
|
|
|
|
* ignore the bootloader_args value unless a bootloader was specified
|
|
|
|
*/
|
|
|
|
virBufferVSprintf(&buf, "(bootloader_args '%s')", str);
|
2007-10-24 14:22:25 +00:00
|
|
|
free(str);
|
2006-03-30 16:08:13 +00:00
|
|
|
}
|
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
str = virXPathString("string(/domain/on_poweroff[1])", ctxt);
|
|
|
|
if (str != NULL) {
|
|
|
|
virBufferVSprintf(&buf, "(on_poweroff '%s')", str);
|
2007-10-24 14:22:25 +00:00
|
|
|
free(str);
|
2006-04-10 08:32:34 +00:00
|
|
|
}
|
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
str = virXPathString("string(/domain/on_reboot[1])", ctxt);
|
|
|
|
if (str != NULL) {
|
|
|
|
virBufferVSprintf(&buf, "(on_reboot '%s')", str);
|
2007-10-24 14:22:25 +00:00
|
|
|
free(str);
|
2006-04-10 08:32:34 +00:00
|
|
|
}
|
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
str = virXPathString("string(/domain/on_crash[1])", ctxt);
|
|
|
|
if (str != NULL) {
|
|
|
|
virBufferVSprintf(&buf, "(on_crash '%s')", str);
|
2007-10-24 14:22:25 +00:00
|
|
|
free(str);
|
2006-04-10 08:32:34 +00:00
|
|
|
}
|
|
|
|
|
2007-06-07 13:50:18 +00:00
|
|
|
if (!bootloader) {
|
2007-04-06 12:28:24 +00:00
|
|
|
if ((node = virXPathNode("/domain/os[1]", ctxt)) != NULL) {
|
2007-02-07 13:50:18 +00:00
|
|
|
/* Analyze of the os description, based on HVM or PV. */
|
2007-06-07 13:50:18 +00:00
|
|
|
str = virXPathString("string(/domain/os/type[1])", ctxt);
|
2007-02-07 13:50:18 +00:00
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
if ((str == NULL) || (strcmp(str, "hvm"))) {
|
|
|
|
res = virDomainParseXMLOSDescPV(conn, node,
|
2007-10-24 14:22:25 +00:00
|
|
|
&buf, ctxt,
|
|
|
|
xendConfigVersion);
|
2007-02-07 13:50:18 +00:00
|
|
|
} else {
|
|
|
|
hvm = 1;
|
2007-04-06 12:28:24 +00:00
|
|
|
res = virDomainParseXMLOSDescHVM(conn, node, &buf, ctxt,
|
2007-10-24 14:22:25 +00:00
|
|
|
vcpus, xendConfigVersion);
|
2007-02-07 13:50:18 +00:00
|
|
|
}
|
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
if (str != NULL)
|
|
|
|
free(str);
|
2007-02-07 13:50:18 +00:00
|
|
|
|
|
|
|
if (res != 0)
|
|
|
|
goto error;
|
2007-06-07 13:50:18 +00:00
|
|
|
} else {
|
2007-02-14 16:16:13 +00:00
|
|
|
virXMLError(conn, VIR_ERR_NO_OS, nam, 0);
|
2007-02-07 13:50:18 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* analyze of the devices */
|
2007-04-06 12:28:24 +00:00
|
|
|
nb_nodes = virXPathNodeSet("/domain/devices/disk", ctxt, &nodes);
|
|
|
|
if (nb_nodes > 0) {
|
|
|
|
for (i = 0; i < nb_nodes; i++) {
|
|
|
|
res = virDomainParseXMLDiskDesc(conn, nodes[i], &buf,
|
2007-10-24 14:22:25 +00:00
|
|
|
hvm, xendConfigVersion);
|
2007-02-07 13:50:18 +00:00
|
|
|
if (res != 0) {
|
2007-10-24 14:22:25 +00:00
|
|
|
free(nodes);
|
2007-02-07 13:50:18 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
2007-04-13 00:43:57 +00:00
|
|
|
free(nodes);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
2006-07-07 14:36:27 +00:00
|
|
|
|
2007-04-06 12:28:24 +00:00
|
|
|
nb_nodes = virXPathNodeSet("/domain/devices/interface", ctxt, &nodes);
|
|
|
|
if (nb_nodes > 0) {
|
|
|
|
for (i = 0; i < nb_nodes; i++) {
|
2006-03-15 12:13:25 +00:00
|
|
|
virBufferAdd(&buf, "(device ", 8);
|
2007-10-24 14:22:25 +00:00
|
|
|
res =
|
|
|
|
virDomainParseXMLIfDesc(conn, nodes[i], &buf, hvm,
|
|
|
|
xendConfigVersion);
|
2006-03-15 12:13:25 +00:00
|
|
|
if (res != 0) {
|
2007-10-24 14:22:25 +00:00
|
|
|
free(nodes);
|
2006-03-15 12:13:25 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
virBufferAdd(&buf, ")", 1);
|
|
|
|
}
|
2007-04-13 00:43:57 +00:00
|
|
|
free(nodes);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
|
|
|
|
2007-04-13 00:43:57 +00:00
|
|
|
/* New style PV graphics config xen >= 3.0.4,
|
|
|
|
* or HVM graphics config xen >= 3.0.5 */
|
|
|
|
if ((xendConfigVersion >= 3 && !hvm) ||
|
|
|
|
(xendConfigVersion >= 4 && hvm)) {
|
2007-04-06 12:28:24 +00:00
|
|
|
nb_nodes = virXPathNodeSet("/domain/devices/graphics", ctxt, &nodes);
|
2007-04-13 00:43:57 +00:00
|
|
|
if (nb_nodes > 0) {
|
2007-04-06 12:28:24 +00:00
|
|
|
for (i = 0; i < nb_nodes; i++) {
|
|
|
|
res = virDomainParseXMLGraphicsDescVFB(conn, nodes[i], &buf);
|
2006-12-13 14:08:51 +00:00
|
|
|
if (res != 0) {
|
2007-04-13 00:43:57 +00:00
|
|
|
free(nodes);
|
2006-12-13 14:08:51 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
2007-04-13 00:43:57 +00:00
|
|
|
free(nodes);
|
2006-12-13 14:08:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-16 22:50:52 +00:00
|
|
|
|
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-11-10 23:46:12 +00:00
|
|
|
xmlFreeParserCtxt(pctxt);
|
2006-02-27 22:32:54 +00:00
|
|
|
|
|
|
|
if (name != NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
*name = nam;
|
2006-10-06 15:32:48 +00:00
|
|
|
else
|
|
|
|
free(nam);
|
2006-02-16 22:50:52 +00:00
|
|
|
|
2007-04-23 07:41:23 +00:00
|
|
|
return (buf.content);
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2007-10-24 14:22:25 +00:00
|
|
|
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 (ctxt != NULL)
|
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
if (xml != NULL)
|
|
|
|
xmlFreeDoc(xml);
|
2006-11-10 23:46:12 +00:00
|
|
|
if (pctxt != NULL)
|
|
|
|
xmlFreeParserCtxt(pctxt);
|
2007-04-23 07:41:23 +00:00
|
|
|
if (buf.content != NULL)
|
|
|
|
free(buf.content);
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
2006-02-16 22:50:52 +00:00
|
|
|
}
|
2006-08-09 15:21:16 +00:00
|
|
|
|
2006-11-16 18:11:28 +00:00
|
|
|
/**
|
|
|
|
* virParseXMLDevice:
|
2007-02-14 16:16:13 +00:00
|
|
|
* @conn: pointer to the hypervisor connection
|
2006-11-16 18:11:28 +00:00
|
|
|
* @xmldesc: string with the XML description
|
|
|
|
* @hvm: 1 for fully virtualized guest, 0 for paravirtualized
|
|
|
|
* @xendConfigVersion: xend configuration file format
|
|
|
|
*
|
|
|
|
* Parse the XML description and turn it into the xend sexp needed to
|
|
|
|
* create the device. 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-terminated S-Expr string, or NULL in case of error.
|
|
|
|
* the caller must free() the returned value.
|
|
|
|
*/
|
|
|
|
char *
|
2007-10-24 14:22:25 +00:00
|
|
|
virParseXMLDevice(virConnectPtr conn, const char *xmldesc, int hvm,
|
|
|
|
int xendConfigVersion)
|
2006-11-16 18:11:28 +00:00
|
|
|
{
|
|
|
|
xmlDocPtr xml = NULL;
|
|
|
|
xmlNodePtr node;
|
|
|
|
virBuffer buf;
|
|
|
|
|
|
|
|
buf.content = malloc(1000);
|
|
|
|
if (buf.content == NULL)
|
|
|
|
return (NULL);
|
|
|
|
buf.size = 1000;
|
|
|
|
buf.use = 0;
|
2007-06-04 08:42:41 +00:00
|
|
|
buf.content[0] = 0;
|
2007-08-02 10:47:38 +00:00
|
|
|
xml = xmlReadDoc((const xmlChar *) xmldesc, "device.xml", NULL,
|
2006-11-16 18:11:28 +00:00
|
|
|
XML_PARSE_NOENT | XML_PARSE_NONET |
|
|
|
|
XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
|
2007-08-02 10:47:38 +00:00
|
|
|
if (xml == NULL) {
|
|
|
|
virXMLError(conn, VIR_ERR_XML_ERROR, NULL, 0);
|
2006-11-16 18:11:28 +00:00
|
|
|
goto error;
|
2007-08-02 10:47:38 +00:00
|
|
|
}
|
2006-11-16 18:11:28 +00:00
|
|
|
node = xmlDocGetRootElement(xml);
|
|
|
|
if (node == NULL)
|
|
|
|
goto error;
|
|
|
|
if (xmlStrEqual(node->name, BAD_CAST "disk")) {
|
2007-10-24 14:22:25 +00:00
|
|
|
if (virDomainParseXMLDiskDesc(conn, node, &buf, hvm,
|
|
|
|
xendConfigVersion) != 0)
|
2006-11-16 18:11:28 +00:00
|
|
|
goto error;
|
2007-06-04 08:42:41 +00:00
|
|
|
/* SXP is not created when device is "floppy". */
|
2007-10-24 14:22:25 +00:00
|
|
|
else if (buf.use == 0)
|
|
|
|
goto error;
|
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "interface")) {
|
|
|
|
if (virDomainParseXMLIfDesc(conn, node, &buf, hvm,
|
|
|
|
xendConfigVersion) != 0)
|
2006-11-16 18:11:28 +00:00
|
|
|
goto error;
|
2007-07-13 12:26:11 +00:00
|
|
|
} else {
|
|
|
|
virXMLError(conn, VIR_ERR_XML_ERROR, (const char *) node->name, 0);
|
2007-10-24 14:22:25 +00:00
|
|
|
goto error;
|
2006-11-16 18:11:28 +00:00
|
|
|
}
|
2007-10-24 14:22:25 +00:00
|
|
|
cleanup:
|
2006-11-16 18:11:28 +00:00
|
|
|
if (xml != NULL)
|
|
|
|
xmlFreeDoc(xml);
|
|
|
|
return buf.content;
|
2007-10-24 14:22:25 +00:00
|
|
|
error:
|
2006-11-16 18:11:28 +00:00
|
|
|
free(buf.content);
|
|
|
|
buf.content = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2007-11-30 22:51:54 +00:00
|
|
|
|
2006-11-16 18:11:28 +00:00
|
|
|
/**
|
|
|
|
* virDomainXMLDevID:
|
|
|
|
* @domain: pointer to domain object
|
|
|
|
* @xmldesc: string with the XML description
|
|
|
|
* @class: Xen device class "vbd" or "vif" (OUT)
|
|
|
|
* @ref: Xen device reference (OUT)
|
|
|
|
*
|
|
|
|
* Set class according to XML root, and:
|
|
|
|
* - if disk, copy in ref the target name from description
|
|
|
|
* - if network, get MAC address from description, scan XenStore and
|
|
|
|
* copy in ref the corresponding vif number.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, -1 in case of failure.
|
|
|
|
*/
|
|
|
|
int
|
2007-10-24 14:22:25 +00:00
|
|
|
virDomainXMLDevID(virDomainPtr domain, const char *xmldesc, char *class,
|
|
|
|
char *ref, int ref_len)
|
2006-11-16 18:11:28 +00:00
|
|
|
{
|
|
|
|
xmlDocPtr xml = NULL;
|
|
|
|
xmlNodePtr node, cur;
|
|
|
|
xmlChar *attr = NULL;
|
2007-10-24 14:22:25 +00:00
|
|
|
|
2006-11-20 16:42:16 +00:00
|
|
|
char *xref;
|
2006-11-17 00:10:51 +00:00
|
|
|
int ret = 0;
|
2006-11-16 18:11:28 +00:00
|
|
|
|
2007-08-02 10:47:38 +00:00
|
|
|
xml = xmlReadDoc((const xmlChar *) xmldesc, "device.xml", NULL,
|
2006-11-16 18:11:28 +00:00
|
|
|
XML_PARSE_NOENT | XML_PARSE_NONET |
|
|
|
|
XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
|
2007-08-02 10:47:38 +00:00
|
|
|
if (xml == NULL) {
|
|
|
|
virXMLError(NULL, VIR_ERR_XML_ERROR, NULL, 0);
|
2006-11-16 18:11:28 +00:00
|
|
|
goto error;
|
2007-08-02 10:47:38 +00:00
|
|
|
}
|
2006-11-16 18:11:28 +00:00
|
|
|
node = xmlDocGetRootElement(xml);
|
|
|
|
if (node == NULL)
|
|
|
|
goto error;
|
|
|
|
if (xmlStrEqual(node->name, BAD_CAST "disk")) {
|
|
|
|
strcpy(class, "vbd");
|
|
|
|
for (cur = node->children; cur != NULL; cur = cur->next) {
|
|
|
|
if ((cur->type != XML_ELEMENT_NODE) ||
|
2007-10-24 14:22:25 +00:00
|
|
|
(!xmlStrEqual(cur->name, BAD_CAST "target")))
|
|
|
|
continue;
|
2006-11-16 18:11:28 +00:00
|
|
|
attr = xmlGetProp(cur, BAD_CAST "dev");
|
|
|
|
if (attr == NULL)
|
|
|
|
goto error;
|
2007-11-06 11:49:01 +00:00
|
|
|
xref = xenStoreDomainGetDiskID(domain->conn, domain->id,
|
|
|
|
(char *) attr);
|
|
|
|
if (xref != NULL) {
|
|
|
|
strncpy(ref, xref, ref_len);
|
|
|
|
free(xref);
|
|
|
|
ref[ref_len - 1] = '\0';
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
/* hack to avoid the warning that domain is unused */
|
|
|
|
if (domain->id < 0)
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
goto error;
|
2006-11-16 18:11:28 +00:00
|
|
|
}
|
2007-10-24 14:22:25 +00:00
|
|
|
} else if (xmlStrEqual(node->name, BAD_CAST "interface")) {
|
2006-11-16 18:11:28 +00:00
|
|
|
strcpy(class, "vif");
|
|
|
|
for (cur = node->children; cur != NULL; cur = cur->next) {
|
|
|
|
if ((cur->type != XML_ELEMENT_NODE) ||
|
2007-10-24 14:22:25 +00:00
|
|
|
(!xmlStrEqual(cur->name, BAD_CAST "mac")))
|
|
|
|
continue;
|
2006-11-16 18:11:28 +00:00
|
|
|
attr = xmlGetProp(cur, BAD_CAST "address");
|
|
|
|
if (attr == NULL)
|
|
|
|
goto error;
|
|
|
|
|
2007-01-22 16:25:27 +00:00
|
|
|
xref = xenStoreDomainGetNetworkID(domain->conn, domain->id,
|
2007-02-07 13:50:18 +00:00
|
|
|
(char *) attr);
|
|
|
|
if (xref != NULL) {
|
2007-09-12 15:41:51 +00:00
|
|
|
strncpy(ref, xref, ref_len);
|
2007-02-07 13:50:18 +00:00
|
|
|
free(xref);
|
2007-09-12 15:41:51 +00:00
|
|
|
ref[ref_len - 1] = '\0';
|
2007-02-07 13:50:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2007-03-16 14:55:51 +00:00
|
|
|
/* hack to avoid the warning that domain is unused */
|
|
|
|
if (domain->id < 0)
|
2007-10-24 14:22:25 +00:00
|
|
|
ret = -1;
|
2007-02-07 13:50:18 +00:00
|
|
|
|
2006-11-16 18:11:28 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2007-08-02 10:47:38 +00:00
|
|
|
} else {
|
|
|
|
virXMLError(NULL, VIR_ERR_XML_ERROR, (const char *) node->name, 0);
|
2006-11-16 18:11:28 +00:00
|
|
|
}
|
2007-10-24 14:22:25 +00:00
|
|
|
error:
|
2006-11-16 18:11:28 +00:00
|
|
|
ret = -1;
|
2007-10-24 14:22:25 +00:00
|
|
|
cleanup:
|
2006-11-16 18:11:28 +00:00
|
|
|
if (xml != NULL)
|
|
|
|
xmlFreeDoc(xml);
|
|
|
|
if (attr != NULL)
|
|
|
|
xmlFree(attr);
|
|
|
|
return ret;
|
|
|
|
}
|
2007-11-30 22:51:54 +00:00
|
|
|
#endif /* WITH_XEN */
|
2006-11-16 18:11:28 +00:00
|
|
|
#endif /* !PROXY */
|
|
|
|
|
2006-09-12 01:34:26 +00:00
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* indent-tabs-mode: nil
|
|
|
|
* c-indent-level: 4
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* tab-width: 4
|
|
|
|
* End:
|
|
|
|
*/
|