if WITH_PROXY
INCLUDES = -I$(top_srcdir)/gnulib/lib -I../gnulib/lib \
-I$(top_builddir)/include -I@top_srcdir@/include \
- -I@top_srcdir@/proxy -I@top_srcdir@/src @LIBXML_CFLAGS@ \
+ -I@top_srcdir@/proxy -I@top_srcdir@/src -I@top_srcdir@/src/xen @LIBXML_CFLAGS@ \
-DPROXY -DLOCALEBASEDIR=\""$(datadir)/locale"\" \
-DGETTEXT_PACKAGE=\"$(PACKAGE)\" $(WARN_CFLAGS) $(XEN_CFLAGS)
libexec_PROGRAMS = libvirt_proxy
-libvirt_proxy_SOURCES = libvirt_proxy.c @top_srcdir@/src/xend_internal.c \
- @top_srcdir@/src/xen_internal.c @top_srcdir@/src/virterror.c \
- @top_srcdir@/src/sexpr.c \
+libvirt_proxy_SOURCES = libvirt_proxy.c @top_srcdir@/src/xen/xend_internal.c \
+ @top_srcdir@/src/xen/xen_hypervisor.c @top_srcdir@/src/virterror.c \
+ @top_srcdir@/src/xen/sexpr.c \
@top_srcdir@/src/threads.c \
- @top_srcdir@/src/xs_internal.c @top_srcdir@/src/buf.c \
+ @top_srcdir@/src/xen/xs_internal.c @top_srcdir@/src/buf.c \
@top_srcdir@/src/capabilities.c \
@top_srcdir@/src/memory.c \
@top_srcdir@/src/storage_encryption_conf.c \
#include "datatypes.h"
#include "proxy_internal.h"
#include "util.h"
-#include "xen_internal.h"
+#include "xen_hypervisor.h"
#include "xend_internal.h"
#include "xs_internal.h"
-#include "xen_unified.h"
+#include "xen_driver.h"
static int fdServer = -1;
static int debug = 0;
-I@top_srcdir@/daemon \
$(LIBXML_CFLAGS) \
$(LIBSSH2_CFLAGS) \
- $(XEN_CFLAGS) \
$(SELINUX_CFLAGS) \
$(DRIVER_MODULE_CFLAGS) \
-DLIBDIR=\""$(libdir)"\" \
# Now the Hypervisor specific drivers
XEN_DRIVER_SOURCES = \
- proxy_internal.c proxy_internal.h \
- sexpr.c sexpr.h \
- xen_internal.c xen_internal.h \
- xen_unified.c xen_unified.h \
- xend_internal.c xend_internal.h \
- xm_internal.c xm_internal.h \
- xs_internal.c xs_internal.h
+ xen/proxy_internal.c xen/proxy_internal.h \
+ xen/sexpr.c xen/sexpr.h \
+ xen/block_stats.c xen/block_stats.h \
+ xen/xen_hypervisor.c xen/xen_hypervisor.h \
+ xen/xen_driver.c xen/xen_driver.h \
+ xen/xend_internal.c xen/xend_internal.h \
+ xen/xm_internal.c xen/xm_internal.h \
+ xen/xs_internal.c xen/xs_internal.h
if WITH_XEN_INOTIFY
-XEN_DRIVER_SOURCES += xen_inotify.c xen_inotify.h
+XEN_DRIVER_SOURCES += xen/xen_inotify.c xen/xen_inotify.h
endif
LXC_DRIVER_SOURCES = \
$(NODE_DEVICE_CONF_SOURCES) \
$(SECRET_CONF_SOURCES)
-libvirt_driver_la_CFLAGS = $(XEN_CFLAGS) $(NUMACTL_CFLAGS)
-libvirt_driver_la_LDFLAGS = $(XEN_LIBS) $(NUMACTL_LIBS)
+libvirt_driver_la_CFLAGS = $(NUMACTL_CFLAGS)
+libvirt_driver_la_LDFLAGS = $(NUMACTL_LIBS)
USED_SYM_FILES = libvirt_private.syms
#include "test.h"
#endif
#ifdef WITH_XEN
-#include "xen_unified.h"
+#include "xen/xen_driver.h"
#endif
#ifdef WITH_REMOTE
#include "remote_internal.h"
+++ /dev/null
-/*
- * proxy_client.c: client side of the communication with the libvirt proxy.
- *
- * Copyright (C) 2006, 2008, 2009 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Daniel Veillard <veillard@redhat.com>
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/poll.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/wait.h>
-#include <string.h>
-
-#include "virterror_internal.h"
-#include "logging.h"
-#include "datatypes.h"
-#include "driver.h"
-#include "proxy_internal.h"
-#include "util.h"
-#include "xen_unified.h"
-#include "memory.h"
-
-#define STANDALONE
-
-#define VIR_FROM_THIS VIR_FROM_PROXY
-
-static int xenProxyClose(virConnectPtr conn);
-static virDrvOpenStatus xenProxyOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags);
-static int xenProxyGetVersion(virConnectPtr conn, unsigned long *hvVer);
-static int xenProxyNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info);
-static char *xenProxyGetCapabilities(virConnectPtr conn);
-static int xenProxyNumOfDomains(virConnectPtr conn);
-static unsigned long xenProxyDomainGetMaxMemory(virDomainPtr domain);
-static int xenProxyDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info);
-static char *xenProxyDomainGetOSType(virDomainPtr domain);
-
-struct xenUnifiedDriver xenProxyDriver = {
- xenProxyOpen, /* open */
- xenProxyClose, /* close */
- xenProxyGetVersion, /* version */
- NULL, /* hostname */
- xenProxyNodeGetInfo, /* nodeGetInfo */
- xenProxyGetCapabilities, /* getCapabilities */
- xenProxyListDomains, /* listDomains */
- xenProxyNumOfDomains, /* numOfDomains */
- NULL, /* domainCreateXML */
- NULL, /* domainSuspend */
- NULL, /* domainResume */
- NULL, /* domainShutdown */
- NULL, /* domainReboot */
- NULL, /* domainDestroy */
- xenProxyDomainGetOSType, /* domainGetOSType */
- xenProxyDomainGetMaxMemory, /* domainGetMaxMemory */
- NULL, /* domainSetMaxMemory */
- NULL, /* domainSetMemory */
- xenProxyDomainGetInfo, /* domainGetInfo */
- NULL, /* domainSave */
- NULL, /* domainRestore */
- NULL, /* domainCoreDump */
- NULL, /* domainSetVcpus */
- NULL, /* domainPinVcpu */
- NULL, /* domainGetVcpus */
- NULL, /* domainGetMaxVcpus */
- NULL, /* listDefinedDomains */
- NULL, /* numOfDefinedDomains */
- NULL, /* domainCreate */
- NULL, /* domainDefineXML */
- NULL, /* domainUndefine */
- NULL, /* domainAttachDevice */
- NULL, /* domainDetachDevice */
- NULL, /* domainGetAutostart */
- NULL, /* domainSetAutostart */
- NULL, /* domainGetSchedulerType */
- NULL, /* domainGetSchedulerParameters */
- NULL, /* domainSetSchedulerParameters */
-};
-
-
-/************************************************************************
- * *
- * Error handling *
- * *
- ************************************************************************/
-
-#define virProxyError(conn, code, fmt...) \
- virReportErrorHelper(conn, VIR_FROM_PROXY, code, __FILE__, \
- __FUNCTION__, __LINE__, fmt)
-
-/************************************************************************
- * *
- * Automatic startup of the proxy server if it is not running *
- * *
- ************************************************************************/
-/**
- * virProxyFindServerPath:
- *
- * Tries to find the path to the gam_server binary.
- *
- * Returns path on success or NULL in case of error.
- */
-static const char *
-virProxyFindServerPath(void)
-{
- static const char *serverPaths[] = {
- BINDIR "/libvirt_proxy",
- "/usr/bin/libvirt_proxy_dbg",
- NULL
- };
- int i;
- const char *debugProxy = getenv("LIBVIRT_DEBUG_PROXY");
-
- if (debugProxy)
- return(debugProxy);
-
- for (i = 0; serverPaths[i]; i++) {
- if (access(serverPaths[i], X_OK | R_OK) == 0) {
- return serverPaths[i];
- }
- }
- return NULL;
-}
-
-/**
- * virProxyForkServer:
- *
- * Forks and try to launch the proxy server processing the requests for
- * libvirt when communicating with Xen.
- *
- * Returns 0 in case of success or -1 in case of detected error.
- */
-static int
-virProxyForkServer(void)
-{
- const char *proxyPath = virProxyFindServerPath();
- pid_t pid;
- const char *proxyarg[2];
-
- if (!proxyPath) {
- VIR_WARN0("failed to find libvirt_proxy\n");
- return(-1);
- }
-
- VIR_DEBUG("Asking to launch %s\n", proxyPath);
-
- proxyarg[0] = proxyPath;
- proxyarg[1] = NULL;
-
- if (virExecDaemonize(NULL, proxyarg, NULL, NULL,
- &pid, -1, NULL, NULL, 0,
- NULL, NULL, NULL) < 0)
- VIR_ERROR0("Failed to fork libvirt_proxy\n");
-
- return (0);
-}
-
-/************************************************************************
- * *
- * Processing of client sockets *
- * *
- ************************************************************************/
-
-/**
- * virProxyOpenClientSocket:
- * @path: the filename for the socket
- *
- * try to connect to the socket open by libvirt_proxy
- *
- * Returns the associated file descriptor or -1 in case of failure
- */
-static int
-virProxyOpenClientSocket(const char *path) {
- int fd;
- struct sockaddr_un addr;
- int trials = 0;
-
-retry:
- fd = socket(PF_UNIX, SOCK_STREAM, 0);
- if (fd < 0) {
- return(-1);
- }
-
- /*
- * Abstract socket do not hit the filesystem, way more secure and
- * guaranteed to be atomic
- */
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- addr.sun_path[0] = '\0';
- strncpy(&addr.sun_path[1], path, (sizeof(addr) - 4) - 2);
-
- /*
- * now bind the socket to that address and listen on it
- */
- if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- close(fd);
- if (trials < 3) {
- if (virProxyForkServer() < 0)
- return(-1);
- trials++;
- usleep(5000 * trials * trials);
- goto retry;
- }
- return (-1);
- }
-
- DEBUG("connected to unix socket %s via %d\n", path, fd);
-
- return (fd);
-}
-
-/**
- * virProxyCloseSocket:
- * @priv: the Xen proxy data
- *
- * Close the socket from that client. The caller must
- * hold the lock on 'priv' before calling
- *
- * Returns 0 in case of success and -1 in case of error
- */
-static int
-virProxyCloseSocket(xenUnifiedPrivatePtr priv) {
- int ret;
-
- if (priv->proxy < 0)
- return(-1);
-
- ret = close(priv->proxy);
- if (ret != 0)
- VIR_WARN(_("Failed to close socket %d\n"), priv->proxy);
- else
- VIR_DEBUG("Closed socket %d\n", priv->proxy);
- priv->proxy = -1;
- return(ret);
-}
-
-/**
- * virProxyReadClientSocket:
- * @fd: the socket
- * @buffer: the target memory area
- * @len: the length in bytes
- *
- * Process a read from a client socket
- *
- * Returns the number of byte read or -1 in case of error.
- */
-static int
-virProxyReadClientSocket(int fd, char *buffer, int len) {
- int ret;
-
- if ((fd < 0) || (buffer == NULL) || (len < 0))
- return(-1);
-
-retry:
- ret = read(fd, buffer, len);
- if (ret < 0) {
- if (errno == EINTR) {
- VIR_DEBUG("read socket %d interrupted\n", fd);
- goto retry;
- }
- VIR_WARN("Failed to read socket %d\n", fd);
- return(-1);
- }
-
- VIR_DEBUG("read %d bytes from socket %d\n",
- ret, fd);
- return(ret);
-}
-
-/**
- * virProxyWriteClientSocket:
- * @fd: the socket
- * @data: the data
- * @len: the length of data in bytes
- *
- * Process a read from a client socket
- */
-static int
-virProxyWriteClientSocket(int fd, const char *data, int len) {
- int ret;
-
- if ((fd < 0) || (data == NULL) || (len < 0))
- return(-1);
-
- ret = safewrite(fd, data, len);
- if (ret < 0) {
- VIR_WARN(_("Failed to write to socket %d\n"), fd);
- return(-1);
- }
- VIR_DEBUG("wrote %d bytes to socket %d\n",
- len, fd);
-
- return(0);
-}
-
-/************************************************************************
- * *
- * Proxy commands processing *
- * *
- ************************************************************************/
-
-/**
- * xenProxyClose:
- * @conn: pointer to the hypervisor connection
- *
- * Shutdown the Xen proxy communication layer
- */
-static int
-xenProxyClose(virConnectPtr conn)
-{
- xenUnifiedPrivatePtr priv;
-
- if (conn == NULL) {
- virProxyError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return -1;
- }
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (!priv) {
- virProxyError (NULL, VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
- return -1;
- }
-
- xenUnifiedLock(priv);
- virProxyCloseSocket (priv);
- xenUnifiedUnlock(priv);
-
- return 0;
-}
-
-static int
-xenProxyCommand(virConnectPtr conn, virProxyPacketPtr request,
- virProxyFullPacketPtr answer, int quiet) {
- static int serial = 0;
- int ret;
- virProxyPacketPtr res = NULL;
- xenUnifiedPrivatePtr priv;
-
- if (conn == NULL) {
- virProxyError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return -1;
- }
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (!priv) {
- virProxyError (NULL, VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
- return -1;
- }
-
- xenUnifiedLock(priv);
-
- /* Fail silently. */
- if (priv->proxy == -1)
- goto error;
-
- /*
- * normal communication serial numbers are in 0..4095
- */
- ++serial;
- if (serial >= 4096)
- serial = 0;
- request->version = PROXY_PROTO_VERSION;
- request->serial = serial;
- ret = virProxyWriteClientSocket(priv->proxy, (const char *) request,
- request->len);
- if (ret < 0) {
- if (!quiet)
- virReportSystemError(conn, errno, "%s",
- _("failed to write proxy request"));
- goto error;
- }
-retry:
- if (answer == NULL) {
- /* read in situ */
- ret = virProxyReadClientSocket(priv->proxy, (char *) request,
- sizeof(virProxyPacket));
- if (ret < 0) {
- if (!quiet)
- virReportSystemError(conn, errno, "%s",
- _("failed to read proxy reply"));
- goto error;
- }
- if (ret != sizeof(virProxyPacket)) {
- virProxyError(conn, VIR_ERR_INTERNAL_ERROR,
- _("Communication error with proxy: got %d bytes of %d\n"),
- ret, (int) sizeof(virProxyPacket));
- goto error;
- }
- res = request;
- if (res->len != sizeof(virProxyPacket)) {
- virProxyError(conn, VIR_ERR_INTERNAL_ERROR,
- _("Communication error with proxy: expected %d bytes got %d\n"),
- (int) sizeof(virProxyPacket), res->len);
- goto error;
- }
- } else {
- /* read in packet provided */
- ret = virProxyReadClientSocket(priv->proxy, (char *) answer,
- sizeof(virProxyPacket));
- if (ret < 0) {
- if (!quiet)
- virReportSystemError(conn, errno, "%s",
- _("failed to read proxy reply"));
- goto error;
- }
- if (ret != sizeof(virProxyPacket)) {
- virProxyError(conn, VIR_ERR_INTERNAL_ERROR,
- _("Communication error with proxy: got %d bytes of %d\n"),
- ret, (int) sizeof(virProxyPacket));
- goto error;
- }
- res = (virProxyPacketPtr) answer;
- if ((res->len < sizeof(virProxyPacket)) ||
- (res->len > sizeof(virProxyFullPacket))) {
- virProxyError(conn, VIR_ERR_INTERNAL_ERROR,
- _("Communication error with proxy: got %d bytes packet\n"),
- res->len);
- goto error;
- }
- if (res->len > sizeof(virProxyPacket)) {
- ret = virProxyReadClientSocket(priv->proxy,
- (char *) &(answer->extra.arg[0]),
- res->len - ret);
- if (ret != (int) (res->len - sizeof(virProxyPacket))) {
- virProxyError(conn, VIR_ERR_INTERNAL_ERROR,
- _("Communication error with proxy: got %d bytes of %d\n"),
- ret, (int) sizeof(virProxyPacket));
- goto error;
- }
- }
- }
- /*
- * do more checks on the incoming packet.
- */
- if ((res == NULL) || (res->version != PROXY_PROTO_VERSION) ||
- (res->len < sizeof(virProxyPacket))) {
- virProxyError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
- _("Communication error with proxy: malformed packet\n"));
- goto error;
- }
- if (res->serial != serial) {
- VIR_WARN(_("got asynchronous packet number %d\n"), res->serial);
- goto retry;
- }
-
- xenUnifiedUnlock(priv);
- return 0;
-
-error:
- virProxyCloseSocket(priv);
- xenUnifiedUnlock(priv);
- return -1;
-}
-
-/**
- * xenProxyOpen:
- * @conn: pointer to the hypervisor connection
- * @name: URL for the target, NULL for local
- * @flags: combination of virDrvOpenFlag(s)
- *
- * Try to initialize the Xen proxy communication layer
- * This can be opened only for a read-only kind of access
- *
- * Returns 0 in case of success, and -1 in case of failure
- */
-virDrvOpenStatus
-xenProxyOpen(virConnectPtr conn,
- virConnectAuthPtr auth ATTRIBUTE_UNUSED,
- int flags)
-{
- virProxyPacket req;
- int ret;
- int fd;
- xenUnifiedPrivatePtr priv;
-
- if (!(flags & VIR_CONNECT_RO))
- return(-1);
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- priv->proxy = -1;
-
- fd = virProxyOpenClientSocket(PROXY_SOCKET_PATH);
- if (fd < 0) {
- virProxyError(NULL, VIR_ERR_NO_XEN, PROXY_SOCKET_PATH);
- return(-1);
- }
- priv->proxy = fd;
-
- memset(&req, 0, sizeof(req));
- req.command = VIR_PROXY_NONE;
- req.len = sizeof(req);
- ret = xenProxyCommand(conn, &req, NULL, 1);
- if ((ret < 0) || (req.command != VIR_PROXY_NONE)) {
- virProxyError(NULL, VIR_ERR_OPERATION_FAILED, __FUNCTION__);
- return(-1);
- }
- return(0);
-}
-
-/************************************************************************
- * *
- * Driver entry points *
- * *
- ************************************************************************/
-
-/**
- * xenProxyGetVersion:
- * @conn: pointer to the Xen Daemon block
- * @hvVer: return value for the version of the running hypervisor (OUT)
- *
- * Get the version level of the Hypervisor running.
- *
- * Returns -1 in case of error, 0 otherwise. if the version can't be
- * extracted by lack of capacities returns 0 and @hvVer is 0, otherwise
- * @hvVer value is major * 1,000,000 + minor * 1,000 + release
- */
-static int
-xenProxyGetVersion(virConnectPtr conn, unsigned long *hvVer)
-{
- virProxyPacket req;
- int ret;
-
- if (!VIR_IS_CONNECT(conn)) {
- virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (-1);
- }
- if (hvVer == NULL) {
- virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (-1);
- }
- memset(&req, 0, sizeof(req));
- req.command = VIR_PROXY_VERSION;
- req.len = sizeof(req);
- ret = xenProxyCommand(conn, &req, NULL, 0);
- if (ret < 0) {
- return(-1);
- }
- *hvVer = req.data.larg;
- return(0);
-}
-
-/**
- * xenProxyListDomains:
- * @conn: pointer to the hypervisor connection
- * @ids: array to collect the list of IDs of active domains
- * @maxids: size of @ids
- *
- * Collect the list of active domains, and store their ID in @maxids
- *
- * Returns the number of domain found or -1 in case of error
- */
-int
-xenProxyListDomains(virConnectPtr conn, int *ids, int maxids)
-{
- virProxyPacket req;
- virProxyFullPacket ans;
- int ret;
- int nb;
-
- if (!VIR_IS_CONNECT(conn)) {
- virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (-1);
- }
- if ((ids == NULL) || (maxids <= 0)) {
- virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (-1);
- }
- memset(&req, 0, sizeof(req));
- req.command = VIR_PROXY_LIST;
- req.len = sizeof(req);
- ret = xenProxyCommand(conn, &req, &ans, 0);
- if (ret < 0) {
- return(-1);
- }
- nb = ans.data.arg;
- if ((nb > 1020) || (nb <= 0) ||
- (ans.len <= sizeof(virProxyPacket)) ||
- (ans.len > sizeof(virProxyFullPacket))) {
- virProxyError(conn, VIR_ERR_OPERATION_FAILED, __FUNCTION__);
- return(-1);
- }
- if (nb > maxids)
- nb = maxids;
- memmove(ids, &ans.extra.arg[0], nb * sizeof(int));
-
- return(nb);
-}
-
-/**
- * xenProxyNumOfDomains:
- * @conn: pointer to the hypervisor connection
- *
- * Provides the number of active domains.
- *
- * Returns the number of domain found or -1 in case of error
- */
-static int
-xenProxyNumOfDomains(virConnectPtr conn)
-{
- virProxyPacket req;
- int ret;
-
- if (!VIR_IS_CONNECT(conn)) {
- virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (-1);
- }
- memset(&req, 0, sizeof(req));
- req.command = VIR_PROXY_NUM_DOMAIN;
- req.len = sizeof(req);
- ret = xenProxyCommand(conn, &req, NULL, 0);
- if (ret < 0) {
- return(-1);
- }
- return(req.data.arg);
-}
-
-
-/**
- * xenProxyDomainGetDomMaxMemory:
- * @conn: pointer to the hypervisor connection
- * @id: the domain ID number
- *
- * Ask the Xen Daemon for the maximum memory allowed for a domain
- *
- * Returns the memory size in kilobytes or 0 in case of error.
- */
-static unsigned long
-xenProxyDomainGetDomMaxMemory(virConnectPtr conn, int id)
-{
- virProxyPacket req;
- int ret;
-
- if (!VIR_IS_CONNECT(conn)) {
- virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (0);
- }
- memset(&req, 0, sizeof(req));
- req.command = VIR_PROXY_MAX_MEMORY;
- req.data.arg = id;
- req.len = sizeof(req);
- ret = xenProxyCommand(conn, &req, NULL, 0);
- if (ret < 0) {
- return(0);
- }
- return(req.data.larg);
-}
-
-/**
- * xenProxyDomainGetMaxMemory:
- * @domain: pointer to the domain block
- *
- * Ask the Xen Daemon for the maximum memory allowed for a domain
- *
- * Returns the memory size in kilobytes or 0 in case of error.
- */
-static unsigned long
-xenProxyDomainGetMaxMemory(virDomainPtr domain)
-{
- if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
- if (domain == NULL)
- virProxyError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
- else
- virProxyError(domain->conn, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
- return (0);
- }
- if (domain->id < 0)
- return (0);
- return(xenProxyDomainGetDomMaxMemory(domain->conn, domain->id));
-}
-
-/**
- * xenProxyDomainGetInfo:
- * @domain: a domain object
- * @info: pointer to a virDomainInfo structure allocated by the user
- *
- * This method looks up information about a domain and update the
- * information block provided.
- *
- * Returns 0 in case of success, -1 in case of error
- */
-static int
-xenProxyDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
-{
- virProxyPacket req;
- virProxyFullPacket ans;
- int ret;
-
- if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
- if (domain == NULL)
- virProxyError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
- else
- virProxyError(domain->conn, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
- return (-1);
- }
- if (domain->id < 0)
- return (-1);
- if (info == NULL) {
- virProxyError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (-1);
- }
- memset(&req, 0, sizeof(req));
- req.command = VIR_PROXY_DOMAIN_INFO;
- req.data.arg = domain->id;
- req.len = sizeof(req);
- ret = xenProxyCommand(domain->conn, &req, &ans, 0);
- if (ret < 0) {
- return(-1);
- }
- if (ans.len != sizeof(virProxyPacket) + sizeof(virDomainInfo)) {
- virProxyError(domain->conn, VIR_ERR_OPERATION_FAILED, __FUNCTION__);
- return (-1);
- }
- memmove(info, &ans.extra.dinfo, sizeof(virDomainInfo));
-
- return(0);
-}
-
-/**
- * xenProxyLookupByID:
- * @conn: pointer to the hypervisor connection
- * @id: the domain ID number
- *
- * Try to find a domain based on the hypervisor ID number
- *
- * Returns a new domain object or NULL in case of failure
- */
-virDomainPtr
-xenProxyLookupByID(virConnectPtr conn, int id)
-{
- virProxyPacket req;
- virProxyFullPacket ans;
- unsigned char uuid[VIR_UUID_BUFLEN];
- const char *name;
- int ret;
- virDomainPtr res;
-
- if (!VIR_IS_CONNECT(conn)) {
- virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (NULL);
- }
- if (id < 0) {
- virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (NULL);
- }
- memset(&req, 0, sizeof(req));
- req.command = VIR_PROXY_LOOKUP_ID;
- req.data.arg = id;
- req.len = sizeof(req);
- ret = xenProxyCommand(conn, &req, &ans, 0);
- if (ret < 0) {
- return(NULL);
- }
- if (ans.data.arg == -1) {
- return(NULL);
- }
- memcpy(uuid, &ans.extra.str[0], VIR_UUID_BUFLEN);
- name = &ans.extra.str[VIR_UUID_BUFLEN];
- res = virGetDomain(conn, name, uuid);
- if (res) res->id = id;
- return(res);
-}
-
-/**
- * xenProxyLookupByUUID:
- * @conn: pointer to the hypervisor connection
- * @uuid: the raw UUID for the domain
- *
- * Try to lookup a domain on xend based on its UUID.
- *
- * Returns a new domain object or NULL in case of failure
- */
-virDomainPtr
-xenProxyLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
-{
- virProxyFullPacket req;
- const char *name;
- int ret;
- virDomainPtr res;
-
- if (!VIR_IS_CONNECT(conn)) {
- virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (NULL);
- }
- if (uuid == NULL) {
- virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (NULL);
- }
- memset(&req, 0, sizeof(virProxyPacket));
- req.command = VIR_PROXY_LOOKUP_UUID;
- req.len = sizeof(virProxyPacket) + VIR_UUID_BUFLEN;
- memcpy(&req.extra.str[0], uuid, VIR_UUID_BUFLEN);
-
- ret = xenProxyCommand(conn, (virProxyPacketPtr) &req, &req, 0);
- if (ret < 0) {
- return(NULL);
- }
- if (req.data.arg == -1) {
- return(NULL);
- }
- name = &req.extra.str[0];
- res = virGetDomain(conn, name, uuid);
- if (res) res->id = req.data.arg;
- return(res);
-}
-
-/**
- * xenProxyLookupByName:
- * @conn: A xend instance
- * @name: The name of the domain
- *
- * This method looks up information about a domain based on its name
- *
- * Returns a new domain object or NULL in case of failure
- */
-virDomainPtr
-xenProxyLookupByName(virConnectPtr conn, const char *name)
-{
- virProxyFullPacket req;
- int ret, len;
- virDomainPtr res;
-
- if (!VIR_IS_CONNECT(conn)) {
- virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (NULL);
- }
- if (name == NULL) {
- virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (NULL);
- }
- len = strlen(name);
- if (len > 1000) {
- virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (NULL);
- }
- memset(&req, 0, sizeof(virProxyPacket));
- req.command = VIR_PROXY_LOOKUP_NAME;
- req.len = sizeof(virProxyPacket) + len + 1;
- strcpy(&req.extra.str[0], name);
- ret = xenProxyCommand(conn, (virProxyPacketPtr) &req, &req, 0);
- if (ret < 0) {
- return(NULL);
- }
- if (req.data.arg == -1) {
- return(NULL);
- }
- res = virGetDomain(conn, name, (const unsigned char *)&req.extra.str[0]);
- if (res) res->id = req.data.arg;
- return(res);
-}
-
-/**
- * xenProxyNodeGetInfo:
- * @conn: pointer to the Xen Daemon block
- * @info: pointer to a virNodeInfo structure allocated by the user
- *
- * Extract hardware information about the node.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-static int
-xenProxyNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) {
- virProxyPacket req;
- virProxyFullPacket ans;
- int ret;
-
- if (!VIR_IS_CONNECT(conn)) {
- virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (-1);
- }
- if (info == NULL) {
- virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (-1);
- }
- memset(&req, 0, sizeof(req));
- req.command = VIR_PROXY_NODE_INFO;
- req.data.arg = 0;
- req.len = sizeof(req);
- ret = xenProxyCommand(conn, &req, &ans, 0);
- if (ret < 0) {
- return(-1);
- }
- if (ans.data.arg == -1) {
- return(-1);
- }
- if (ans.len != sizeof(virProxyPacket) + sizeof(virNodeInfo)) {
- return(-1);
- }
- memcpy(info, &ans.extra.ninfo, sizeof(virNodeInfo));
- return(0);
-}
-
-/**
- * xenProxyGetCapabilities:
- * @conn: pointer to the Xen Daemon block
- *
- * Extract capabilities of the hypervisor.
- *
- * Returns capabilities in case of success (freed by caller)
- * and NULL in case of failure.
- */
-static char *
-xenProxyGetCapabilities (virConnectPtr conn)
-{
- virProxyPacket req;
- virProxyFullPacket ans;
- int ret, xmllen;
- char *xml;
-
- if (!VIR_IS_CONNECT(conn)) {
- virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return NULL;
- }
- memset(&req, 0, sizeof(req));
- req.command = VIR_PROXY_GET_CAPABILITIES;
- req.data.arg = 0;
- req.len = sizeof(req);
- ret = xenProxyCommand(conn, &req, &ans, 0);
- if (ret < 0) {
- return NULL;
- }
- if (ans.data.arg == -1)
- return NULL;
- if (ans.len <= sizeof(virProxyPacket)) {
- virProxyError(conn, VIR_ERR_OPERATION_FAILED, __FUNCTION__);
- return NULL;
- }
-
- xmllen = ans.len - sizeof (virProxyPacket);
- if (VIR_ALLOC_N(xml, xmllen+1) < 0) {
- virReportOOMError (conn);
- return NULL;
- }
- memmove (xml, ans.extra.str, xmllen);
- xml[xmllen] = '\0';
-
- return xml;
-}
-
-/**
- * xenProxyDomainDumpXML:
- * @domain: a domain object
- * @flags: xml generation flags
- *
- * This method generates an XML description of a domain.
- *
- * Returns the XML document on success, NULL otherwise.
- */
-char *
-xenProxyDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED)
-{
- virProxyPacket req;
- virProxyFullPacket ans;
- int ret;
- int xmllen;
- char *xml;
-
- if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
- if (domain == NULL)
- virProxyError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
- else
- virProxyError(domain->conn, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
- return (NULL);
- }
- if (domain->id < 0)
- return (NULL);
- memset(&req, 0, sizeof(req));
- req.command = VIR_PROXY_DOMAIN_XML;
- req.data.arg = domain->id;
- req.len = sizeof(req);
- ret = xenProxyCommand(domain->conn, &req, &ans, 0);
- if (ret < 0) {
- return(NULL);
- }
- if (ans.len <= sizeof(virProxyPacket)) {
- virProxyError(domain->conn, VIR_ERR_OPERATION_FAILED, __FUNCTION__);
- return (NULL);
- }
- xmllen = ans.len - sizeof(virProxyPacket);
- if (VIR_ALLOC_N(xml, xmllen+1) < 0) {
- virReportOOMError(domain->conn);
- return NULL;
- }
- memmove(xml, &ans.extra.dinfo, xmllen);
- xml[xmllen] = '\0';
-
- return(xml);
-}
-
-/**
- * xenProxyDomainGetOSType:
- * @domain: a domain object
- *
- * Get the type of domain operation system.
- *
- * Returns the new string or NULL in case of error, the string must be
- * freed by the caller.
- */
-static char *
-xenProxyDomainGetOSType(virDomainPtr domain)
-{
- virProxyPacket req;
- virProxyFullPacket ans;
- int ret;
- int oslen;
- char *ostype;
-
- if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
- if (domain == NULL)
- virProxyError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
- else
- virProxyError(domain->conn, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
- return (NULL);
- }
- memset(&req, 0, sizeof(req));
- req.command = VIR_PROXY_DOMAIN_OSTYPE;
- req.data.arg = domain->id;
- req.len = sizeof(req);
- ret = xenProxyCommand(domain->conn, &req, &ans, 0);
- if (ret < 0) {
- return(NULL);
- }
- if ((ans.len == sizeof(virProxyPacket)) && (ans.data.arg < 0)) {
- return(NULL);
- }
-
- if (ans.len <= sizeof(virProxyPacket)) {
- virProxyError(domain->conn, VIR_ERR_OPERATION_FAILED, __FUNCTION__);
- return (NULL);
- }
- oslen = ans.len - sizeof(virProxyPacket);
- if (VIR_ALLOC_N(ostype, oslen+1) < 0) {
- virReportOOMError(domain->conn);
- return NULL;
- }
- memmove(ostype, &ans.extra.dinfo, oslen);
- ostype[oslen] = '\0';
-
- return(ostype);
-}
+++ /dev/null
-/*
- * proxy.h: common definitions for proxy usage
- *
- * Copyright (C) 2006 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Daniel Veillard <veillard@redhat.com>
- */
-
-
-#ifndef __LIBVIR_PROXY_H__
-#define __LIBVIR_PROXY_H__
-
-#include "internal.h"
-
-#define PROXY_SOCKET_PATH "/tmp/livirt_proxy_conn"
-#define PROXY_PROTO_VERSION 1
-
-/*
- * the command allowed though the proxy
- */
-typedef enum {
- VIR_PROXY_NONE = 0,
- VIR_PROXY_VERSION = 1,
- VIR_PROXY_NODE_INFO = 2,
- VIR_PROXY_LIST = 3,
- VIR_PROXY_NUM_DOMAIN = 4,
- VIR_PROXY_LOOKUP_ID = 5,
- VIR_PROXY_LOOKUP_UUID = 6,
- VIR_PROXY_LOOKUP_NAME = 7,
- VIR_PROXY_MAX_MEMORY = 8,
- VIR_PROXY_DOMAIN_INFO = 9,
- VIR_PROXY_DOMAIN_XML = 10,
- VIR_PROXY_DOMAIN_OSTYPE = 11,
- VIR_PROXY_GET_CAPABILITIES = 12
-} virProxyCommand;
-
-/*
- * structure used by the client to make a request to the proxy
- * and by the proxy when answering the client.
- * the size may not be fixed, it's passed as len.
- */
-struct _virProxyPacket {
- unsigned short version; /* version of the proxy protocol */
- unsigned short command; /* command number a virProxyCommand */
- unsigned short serial; /* command serial number */
- unsigned short len; /* the length of the request */
- union {
- char string[8]; /* string data */
- int arg; /* or int argument */
- long larg; /* or long argument */
- } data;
-};
-typedef struct _virProxyPacket virProxyPacket;
-typedef virProxyPacket *virProxyPacketPtr;
-
-/*
- * If there is extra data sent from the proxy to the client,
- * they are appended after the packet.
- * the size may not be fixed, it's passed as len and includes the
- * extra data.
- */
-struct _virProxyFullPacket {
- unsigned short version; /* version of the proxy protocol */
- unsigned short command; /* command number a virProxyCommand */
- unsigned short serial; /* command serial number */
- unsigned short len; /* the length of the request */
- union {
- char string[8]; /* string data */
- int arg; /* or int argument */
- long larg; /* or long argument */
- } data;
- /* that should be aligned on a 16bytes boundary */
- union {
- char str[4080]; /* extra char array */
- int arg[1020]; /* extra int array */
- virDomainInfo dinfo; /* domain information */
- virNodeInfo ninfo; /* node information */
- } extra;
-};
-typedef struct _virProxyFullPacket virProxyFullPacket;
-typedef virProxyFullPacket *virProxyFullPacketPtr;
-
-/* xen_unified makes direct calls or indirect calls through here. */
-extern struct xenUnifiedDriver xenProxyDriver;
-extern int xenProxyInit (void);
-
-extern virDomainPtr xenProxyLookupByID(virConnectPtr conn, int id);
-extern virDomainPtr xenProxyLookupByUUID(virConnectPtr conn,
- const unsigned char *uuid);
-extern virDomainPtr xenProxyLookupByName(virConnectPtr conn,
- const char *domname);
-
-extern char * xenProxyDomainDumpXML(virDomainPtr domain,
- int flags);
-extern int xenProxyListDomains(virConnectPtr conn, int *ids,
- int maxids);
-#endif /* __LIBVIR_PROXY_H__ */
#include <stdio.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
+#include <sys/un.h>
#if HAVE_SCHED_H
#include <sched.h>
+++ /dev/null
-/*
- * sexpr.c : S-Expression routines to communicate with the Xen Daemon
- *
- * Copyright (C) 2005
- *
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License. See the file COPYING.LIB in the main directory of this
- * archive for more details.
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "c-ctype.h"
-#include <errno.h>
-
-#include "virterror_internal.h"
-#include "sexpr.h"
-#include "util.h"
-#include "memory.h"
-
-#define VIR_FROM_THIS VIR_FROM_SEXPR
-
-#define virSexprError(code, fmt...) \
- virReportErrorHelper(NULL, VIR_FROM_SEXPR, code, __FILE__, \
- __FUNCTION__, __LINE__, fmt)
-
-/**
- * sexpr_new:
- *
- * Create a new S-Expression
- *
- * Returns the new node or NULL in case of memory allocation error
- */
-static struct sexpr *
-sexpr_new(void)
-{
- struct sexpr *ret;
-
- if (VIR_ALLOC(ret) < 0) {
- virReportOOMError(NULL);
- return (NULL);
- }
- ret->kind = SEXPR_NIL;
- return ret;
-}
-
-/**
- * sexpr_free:
- * @sexpr: the S-Expression pointer
- *
- * Free an S-Expression
- */
-void
-sexpr_free(struct sexpr *sexpr)
-{
- int serrno = errno;
-
- if (sexpr == NULL) {
- return;
- }
-
- switch (sexpr->kind) {
- case SEXPR_CONS:
- sexpr_free(sexpr->u.s.car);
- sexpr_free(sexpr->u.s.cdr);
- break;
- case SEXPR_VALUE:
- VIR_FREE(sexpr->u.value);
- break;
- case SEXPR_NIL:
- break;
- }
-
- VIR_FREE(sexpr);
-
- errno = serrno;
-}
-
-/**
- * sexpr_nil:
- *
- * Provide a NIL S-Expression (the pointer is not shared so NIL equality
- * testing won't work at the pointer level).
- *
- * Returns a new NIL S-Expression of NULL in case of error.
- */
-struct sexpr *
-sexpr_nil(void)
-{
- return sexpr_new();
-}
-
-/**
- * sexpr_string:
- * @str: the input string, assumed to be UTF-8
- * @len: the length in bytes of the input
- *
- * Parse the input S-Expression and return a pointer to the result
- *
- * Returns the S-Expression pointer or NULL in case of error
- */
-struct sexpr *
-sexpr_string(const char *str, ssize_t len)
-{
- struct sexpr *ret = sexpr_new();
-
- if (ret == NULL)
- return ret;
- ret->kind = SEXPR_VALUE;
- if (len > 0) {
- ret->u.value = strndup(str, len);
- } else {
- ret->u.value = strdup(str);
- }
-
- if (ret->u.value == NULL) {
- return NULL;
- }
-
- return ret;
-}
-
-/**
- * sexpr_cons:
- * @car: the left operand
- * @cdr: the right operand
- *
- * Implement the CONS operation assembling 2 existing S-Expressions.
- * Note that in case of error the input data are not freed.
- *
- * Returns the resulting S-Expression pointer or NULL in case of error.
- */
-struct sexpr *
-sexpr_cons(const struct sexpr *car, const struct sexpr *cdr)
-{
- struct sexpr *ret = sexpr_new();
-
- if (ret == NULL)
- return ret;
- ret->kind = SEXPR_CONS;
- ret->u.s.car = (struct sexpr *) car;
- ret->u.s.cdr = (struct sexpr *) cdr;
-
- return ret;
-}
-
-/**
- * append:
- * @lst: an existing list
- * @value: the value
- *
- * Internal operation appending a value at the end of an existing list
- */
-static int
-append(struct sexpr *lst, const struct sexpr *value)
-{
- struct sexpr *nil = sexpr_nil();
-
- if (nil == NULL)
- return -1;
-
- while (lst->kind != SEXPR_NIL) {
- lst = lst->u.s.cdr;
- }
-
- lst->kind = SEXPR_CONS;
- lst->u.s.car = (struct sexpr *) value;
- lst->u.s.cdr = nil;
-
- return 0;
-}
-
-/**
- * @lst: an existing list
- * @value: the value
- *
- * Append a value at the end of an existing list
- *
- * Returns lst or NULL in case of error
- */
-struct sexpr *
-sexpr_append(struct sexpr *lst, const struct sexpr *value)
-{
- if (lst == NULL)
- return (NULL);
- if (value == NULL)
- return (lst);
- if (append(lst, value) < 0)
- return (NULL);
- return (lst);
-}
-
-/**
- * sexpr2string:
- * @sexpr: an S-Expression pointer
- * @buffer: the output buffer
- * @n_buffer: the size of the buffer in bytes
- *
- * Serialize the S-Expression in the buffer.
- * Note that the output may be truncated if @n_buffer is too small
- * resulting in an unparseable value.
- *
- * Returns the number of bytes used by the serialization in the buffer or
- * 0 in case of error.
- */
-size_t
-sexpr2string(const struct sexpr * sexpr, char *buffer, size_t n_buffer)
-{
- size_t ret = 0, tmp;
-
- if ((sexpr == NULL) || (buffer == NULL) || (n_buffer <= 0))
- return (0);
-
- switch (sexpr->kind) {
- case SEXPR_CONS:
- tmp = snprintf(buffer + ret, n_buffer - ret, "(");
- if (tmp == 0)
- goto error;
- ret += tmp;
- tmp = sexpr2string(sexpr->u.s.car, buffer + ret, n_buffer - ret);
- if (tmp == 0)
- goto error;
- ret += tmp;
- while (sexpr->u.s.cdr->kind != SEXPR_NIL) {
- sexpr = sexpr->u.s.cdr;
- tmp = snprintf(buffer + ret, n_buffer - ret, " ");
- if (tmp == 0)
- goto error;
- ret += tmp;
- tmp =
- sexpr2string(sexpr->u.s.car, buffer + ret, n_buffer - ret);
- if (tmp == 0)
- goto error;
- ret += tmp;
- }
- tmp = snprintf(buffer + ret, n_buffer - ret, ")");
- if (tmp == 0)
- goto error;
- ret += tmp;
- break;
- case SEXPR_VALUE:
- if (strchr(sexpr->u.value, ' '))
- tmp = snprintf(buffer + ret, n_buffer - ret, "'%s'",
- sexpr->u.value);
- else
- tmp = snprintf(buffer + ret, n_buffer - ret, "%s",
- sexpr->u.value);
- if (tmp == 0)
- goto error;
- ret += tmp;
- break;
- case SEXPR_NIL:
- tmp = snprintf(buffer + ret, n_buffer - ret, "()");
- if (tmp == 0)
- goto error;
- ret += tmp;
- break;
- default:
- goto error;
- }
-
- return (ret);
- error:
- buffer[n_buffer - 1] = 0;
- virSexprError(VIR_ERR_SEXPR_SERIAL, "%s", buffer);
- return (0);
-}
-
-#define IS_SPACE(c) ((c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA))
-
-static const char *
-trim(const char *string)
-{
- while (IS_SPACE(*string))
- string++;
- return (string);
-}
-
-/**
- * _string2sexpr:
- * @buffer: a zero terminated buffer containing an S-Expression in UTF-8
- * @end: pointer to an index in the buffer for the already parsed bytes
- *
- * Internal routine implementing the parse of S-Expression
- * Note that failure in this function is catastrophic. If it returns
- * NULL, you've leaked memory and you're currently OOM. It will always
- * parse an SEXPR given a buffer
- *
- * Returns a pointer to the resulting parsed S-Expression, or NULL in case of
- * hard error.
- */
-static struct sexpr *
-_string2sexpr(const char *buffer, size_t * end)
-{
- const char *ptr = buffer + *end;
- struct sexpr *ret = sexpr_new();
-
- if (ret == NULL)
- return NULL;
-
- ptr = trim(ptr);
-
- if (ptr[0] == '(') {
- ret->kind = SEXPR_NIL;
-
- ptr = trim(ptr + 1);
- while (*ptr && *ptr != ')') {
- struct sexpr *tmp;
- size_t tmp_len = 0;
-
- tmp = _string2sexpr(ptr, &tmp_len);
- if (tmp == NULL)
- goto error;
- if (append(ret, tmp) < 0) {
- sexpr_free(tmp);
- goto error;
- }
-#if 0
- if (0) {
- char buf[4096];
-
- sexpr2string(ret, buf, sizeof(buf));
- printf("%s\n", buffer);
- }
-#endif
- ptr = trim(ptr + tmp_len);
- }
-
- if (*ptr == ')') {
- ptr++;
- }
- } else {
- const char *start;
-
- if (*ptr == '\'') {
- ptr++;
- start = ptr;
-
- while (*ptr && *ptr != '\'') {
- if (*ptr == '\\' && ptr[1])
- ptr++;
- ptr++;
- }
-
- ret->u.value = strndup(start, ptr - start);
- if (ret->u.value == NULL) {
- virReportOOMError(NULL);
- goto error;
- }
-
- if (*ptr == '\'')
- ptr++;
- } else {
- start = ptr;
-
- while (*ptr && !c_isspace(*ptr)
- && *ptr != ')' && *ptr != '(') {
- ptr++;
- }
-
- ret->u.value = strndup(start, ptr - start);
- if (ret->u.value == NULL) {
- virReportOOMError(NULL);
- goto error;
- }
- }
-
- ret->kind = SEXPR_VALUE;
- if (ret->u.value == NULL)
- goto error;
- }
-
- *end = ptr - buffer;
-
- return ret;
-
- error:
- sexpr_free(ret);
- return (NULL);
-}
-
-/**
- * string2sexpr:
- * @buffer: a zero terminated buffer containing an S-Expression in UTF-8
- *
- * Parse the S-Expression in the buffer.
- * Note that failure in this function is catastrophic. If it returns
- * NULL, you've leaked memory and you're currently OOM. It will always
- * parse an SEXPR given a buffer
- *
- * Returns a pointer to the resulting parsed S-Expression, or NULL in case of
- * hard error.
- */
-struct sexpr *
-string2sexpr(const char *buffer)
-{
- size_t dummy = 0;
-
- return _string2sexpr(buffer, &dummy);
-}
-
-
-/**
- * sexpr_lookup_key:
- * @sexpr: a pointer to a parsed S-Expression
- * @node: a path for the sub expression to lookup in the S-Expression
- *
- * Search a sub expression in the S-Expression based on its path
- * Returns the key node, rather than the data node.
- * NOTE: path are limited to 4096 bytes.
- *
- * Returns the pointer to the sub expression or NULL if not found.
- */
-static struct sexpr *
-sexpr_lookup_key(const struct sexpr *sexpr, const char *node)
-{
- char buffer[4096], *ptr, *token;
-
- if ((node == NULL) || (sexpr == NULL))
- return (NULL);
-
- snprintf(buffer, sizeof(buffer), "%s", node);
-
- ptr = buffer;
- token = strsep(&ptr, "/");
-
- if (sexpr->kind != SEXPR_CONS || sexpr->u.s.car->kind != SEXPR_VALUE) {
- return NULL;
- }
-
- if (STRNEQ(sexpr->u.s.car->u.value, token)) {
- return NULL;
- }
-
- for (token = strsep(&ptr, "/"); token; token = strsep(&ptr, "/")) {
- const struct sexpr *i;
-
- if (token == NULL)
- continue;
-
- sexpr = sexpr->u.s.cdr;
- for (i = sexpr; i->kind != SEXPR_NIL; i = i->u.s.cdr) {
- if (i->kind != SEXPR_CONS ||
- i->u.s.car->kind != SEXPR_CONS ||
- i->u.s.car->u.s.car->kind != SEXPR_VALUE) {
- continue;
- }
-
- if (STREQ(i->u.s.car->u.s.car->u.value, token)) {
- sexpr = i->u.s.car;
- break;
- }
- }
-
- if (i->kind == SEXPR_NIL) {
- break;
- }
- }
-
- if (token != NULL) {
- return NULL;
- }
-
- return (struct sexpr *) sexpr;
-}
-
-/**
- * sexpr_lookup:
- * @sexpr: a pointer to a parsed S-Expression
- * @node: a path for the sub expression to lookup in the S-Expression
- *
- * Search a sub expression in the S-Expression based on its path.
- * NOTE: path are limited to 4096 bytes.
- *
- * Returns the pointer to the sub expression or NULL if not found.
- */
-struct sexpr *
-sexpr_lookup(const struct sexpr *sexpr, const char *node)
-{
- struct sexpr *s = sexpr_lookup_key(sexpr, node);
-
- if (s == NULL)
- return NULL;
-
- if (s->kind != SEXPR_CONS || s->u.s.cdr->kind != SEXPR_CONS)
- return NULL;
-
- return s->u.s.cdr;
-}
-
-/**
- * sexpr_has:
- * @sexpr: a pointer to a parsed S-Expression
- * @node: a path for the sub expression to lookup in the S-Expression
- *
- * Search a sub expression in the S-Expression based on its path.
- * NOTE: path are limited to 4096 bytes.
- * NB, even if the key was found sexpr_lookup may return NULL if
- * the corresponding value was empty
- *
- * Returns true if the key was found, false otherwise
- */
-int
-sexpr_has(const struct sexpr *sexpr, const char *node)
-{
- struct sexpr *s = sexpr_lookup_key(sexpr, node);
-
- if (s == NULL)
- return 0;
-
- if (s->kind != SEXPR_CONS)
- return 0;
-
- return 1;
-}
-
-/**
- * sexpr_node:
- * @sexpr: a pointer to a parsed S-Expression
- * @node: a path for the node to lookup in the S-Expression
- *
- * Search a node value in the S-Expression based on its path
- * NOTE: path are limited to 4096 bytes.
- *
- * Returns the value of the node or NULL if not found.
- */
-const char *
-sexpr_node(const struct sexpr *sexpr, const char *node)
-{
- struct sexpr *n = sexpr_lookup(sexpr, node);
-
- return (n && n->u.s.car->kind == SEXPR_VALUE) ? n->u.s.car->u.value : NULL;
-}
-
-int sexpr_node_copy(const struct sexpr *sexpr, const char *node, char **dst)
-{
- const char *val = sexpr_node(sexpr, node);
-
- if (val) {
- *dst = strdup(val);
- if (!(*dst))
- return -1;
- } else {
- *dst = NULL;
- }
- return 0;
-}
-
-
-/**
- * sexpr_fmt_node:
- * @sexpr: a pointer to a parsed S-Expression
- * @fmt: a path for the node to lookup in the S-Expression
- * @... extra data to build the path
- *
- * Search a node value in the S-Expression based on its path
- * NOTE: path are limited to 4096 bytes.
- *
- * Returns the value of the node or NULL if not found.
- */
-const char *
-sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...)
-{
- va_list ap;
- char node[4096];
-
- va_start(ap, fmt);
- vsnprintf(node, sizeof(node), fmt, ap);
- va_end(ap);
-
- return sexpr_node(sexpr, node);
-}
+++ /dev/null
-/*
- * sexpr.h : S-Expression interfaces needed to communicate with the Xen Daemon
- *
- * Copyright (C) 2005
- *
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License. See the file COPYING.LIB in the main directory of this
- * archive for more details.
- */
-
-#ifndef _LIBVIR_SEXPR_H_
-#define _LIBVIR_SEXPR_H_
-
-#include "internal.h"
-
-#include <sys/types.h>
-
-enum sexpr_type {
- SEXPR_NIL,
- SEXPR_CONS,
- SEXPR_VALUE,
-};
-
-struct sexpr {
- enum sexpr_type kind;
- union {
- struct {
- struct sexpr *car;
- struct sexpr *cdr;
- } s;
- char *value;
- } u;
-};
-
-/* conversion to/from strings */
-size_t sexpr2string(const struct sexpr *sexpr, char *buffer, size_t n_buffer);
-struct sexpr *string2sexpr(const char *buffer);
-
-/* constructors and destructors */
-struct sexpr *sexpr_nil(void);
-struct sexpr *sexpr_string(const char *str, ssize_t len);
-struct sexpr *sexpr_cons(const struct sexpr *car, const struct sexpr *cdr);
-struct sexpr *sexpr_append(struct sexpr *lst, const struct sexpr *item);
-void sexpr_free(struct sexpr *sexpr);
-
-/* lookup in S-Expressions */
-const char *sexpr_node(const struct sexpr *sexpr, const char *node);
-int sexpr_node_copy(const struct sexpr *sexpr, const char *node, char **dst);
-const char *sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...)
- ATTRIBUTE_FMT_PRINTF(2,3);
-struct sexpr *sexpr_lookup(const struct sexpr *sexpr, const char *node);
-int sexpr_has(const struct sexpr *sexpr, const char *node);
-#endif
#include <unistd.h>
#include <regex.h>
-#ifdef WITH_XEN
-#include <xs.h>
-#endif
-
#include "virterror_internal.h"
#include "datatypes.h"
#include "util.h"
-#include "xen_unified.h"
#include "stats_linux.h"
#include "memory.h"
value);
}
-#ifdef WITH_XEN
-/*-------------------- Xen: block stats --------------------*/
-
-#include <linux/major.h>
-
-/* This is normally defined in <linux/major.h> but previously we
- * hard-coded it. So if it's not defined, hard-code again.
- */
-#ifndef XENVBD_MAJOR
-#define XENVBD_MAJOR 202
-#endif
-
-static int
-xstrtoint64 (char const *s, int base, int64_t *result)
-{
- long long int lli;
- char *p;
-
- errno = 0;
- lli = strtoll (s, &p, base);
- if (errno || !(*p == 0 || *p == '\n') || p == s || (int64_t) lli != lli)
- return -1;
- *result = lli;
- return 0;
-}
-
-static int64_t
-read_stat (const char *path)
-{
- char str[64];
- int64_t r;
- int i;
- FILE *fp;
-
- fp = fopen (path, "r");
- if (!fp)
- return -1;
-
- /* read, but don't bail out before closing */
- i = fread (str, 1, sizeof str - 1, fp);
-
- if (fclose (fp) != 0 /* disk error */
- || i < 1) /* ensure we read at least one byte */
- return -1;
-
- str[i] = '\0'; /* make sure the string is nul-terminated */
- if (xstrtoint64 (str, 10, &r) == -1)
- return -1;
-
- return r;
-}
-
-static int64_t
-read_bd_stat (int device, int domid, const char *str)
-{
- char path[PATH_MAX];
- int64_t r;
-
- snprintf (path, sizeof path,
- "/sys/devices/xen-backend/vbd-%d-%d/statistics/%s",
- domid, device, str);
- r = read_stat (path);
- if (r >= 0) return r;
-
- snprintf (path, sizeof path,
- "/sys/devices/xen-backend/tap-%d-%d/statistics/%s",
- domid, device, str);
- r = read_stat (path);
- return r;
-}
-
-/* In Xenstore, /local/domain/0/backend/vbd/<domid>/<device>/state,
- * if available, must be XenbusStateConnected (= 4), otherwise there
- * is no connected device.
- */
-static int
-check_bd_connected (xenUnifiedPrivatePtr priv, int device, int domid)
-{
- char s[256], *rs;
- int r;
- unsigned len = 0;
-
- /* This code assumes we're connected if we can't get to
- * xenstore, etc.
- */
- if (!priv->xshandle) return 1;
- snprintf (s, sizeof s, "/local/domain/0/backend/vbd/%d/%d/state",
- domid, device);
- s[sizeof s - 1] = '\0';
-
- rs = xs_read (priv->xshandle, 0, s, &len);
- if (!rs) return 1;
- if (len == 0) {
- /* Hmmm ... we can get to xenstore but it returns an empty
- * string instead of an error. Assume it's not connected
- * in this case.
- */
- free (rs);
- return 0;
- }
-
- r = STREQ (rs, "4");
- free (rs);
- return r;
-}
-
-static int
-read_bd_stats (virConnectPtr conn, xenUnifiedPrivatePtr priv,
- int device, int domid, struct _virDomainBlockStats *stats)
-{
- stats->rd_req = read_bd_stat (device, domid, "rd_req");
- stats->rd_bytes = read_bd_stat (device, domid, "rd_sect");
- stats->wr_req = read_bd_stat (device, domid, "wr_req");
- stats->wr_bytes = read_bd_stat (device, domid, "wr_sect");
- stats->errs = read_bd_stat (device, domid, "oo_req");
-
- /* None of the files were found - it's likely that this version
- * of Xen is an old one which just doesn't support stats collection.
- */
- if (stats->rd_req == -1 && stats->rd_bytes == -1 &&
- stats->wr_req == -1 && stats->wr_bytes == -1 &&
- stats->errs == -1) {
- statsErrorFunc (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
- "Failed to read any block statistics", domid);
- return -1;
- }
-
- /* If stats are all zero then either there really isn't any block
- * device activity, or there is no connected front end device
- * in which case there are no stats.
- */
- if (stats->rd_req == 0 && stats->rd_bytes == 0 &&
- stats->wr_req == 0 && stats->wr_bytes == 0 &&
- stats->errs == 0 &&
- !check_bd_connected (priv, device, domid)) {
- statsErrorFunc (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
- "Frontend block device not connected", domid);
- return -1;
- }
-
- /* 'Bytes' was really sectors when we read it. Scale up by
- * an assumed sector size.
- */
- if (stats->rd_bytes > 0) {
- if (stats->rd_bytes >= ((unsigned long long)1)<<(63-9)) {
- statsErrorFunc (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
- "stats->rd_bytes would overflow 64 bit counter",
- domid);
- return -1;
- }
- stats->rd_bytes *= 512;
- }
- if (stats->wr_bytes > 0) {
- if (stats->wr_bytes >= ((unsigned long long)1)<<(63-9)) {
- statsErrorFunc (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
- "stats->wr_bytes would overflow 64 bit counter",
- domid);
- return -1;
- }
- stats->wr_bytes *= 512;
- }
-
- return 0;
-}
-
-static int
-disk_re_match(const char *regex, const char *path, int *part)
-{
- regex_t myreg;
- int err;
- int retval;
- regmatch_t pmatch[3];
-
- retval = 0;
-
- err = regcomp(&myreg, regex, REG_EXTENDED);
- if (err != 0)
- return 0;
-
- err = regexec(&myreg, path, 3, pmatch, 0);
-
- if (err == 0) {
- /* OK, we have a match; see if we have a partition */
- *part = 0;
- retval = 1;
- if (pmatch[1].rm_so != -1) {
- if (virStrToLong_i(path + pmatch[1].rm_so, NULL, 10, part) < 0)
- retval = 0;
- }
- }
-
- regfree(&myreg);
-
- return retval;
-}
-
-int
-xenLinuxDomainDeviceID(virConnectPtr conn, int domid, const char *path)
-{
- int major, minor;
- int part;
- int retval;
- char *mod_path;
-
- int const scsi_majors[] = { SCSI_DISK0_MAJOR, SCSI_DISK1_MAJOR,
- SCSI_DISK2_MAJOR, SCSI_DISK3_MAJOR,
- SCSI_DISK4_MAJOR, SCSI_DISK5_MAJOR,
- SCSI_DISK6_MAJOR, SCSI_DISK7_MAJOR,
- SCSI_DISK8_MAJOR, SCSI_DISK9_MAJOR,
- SCSI_DISK10_MAJOR, SCSI_DISK11_MAJOR,
- SCSI_DISK12_MAJOR, SCSI_DISK13_MAJOR,
- SCSI_DISK14_MAJOR, SCSI_DISK15_MAJOR };
- int const ide_majors[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
- IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR,
- IDE8_MAJOR, IDE9_MAJOR };
-
- /*
- * Possible block device majors & partition ranges. This
- * matches the ranges supported in Xend xen/util/blkif.py
- *
- * hdNM: N=a-t, M=1-63, major={IDE0_MAJOR -> IDE9_MAJOR}
- * sdNM: N=a-z,aa-iv, M=1-15, major={SCSI_DISK0_MAJOR -> SCSI_DISK15_MAJOR}
- * xvdNM: N=a-p M=1-15, major=XENVBD_MAJOR
- * xvdNM: N=q-z,aa-iz M=1-15, major=(1<<28)
- *
- * The path for statistics will be
- *
- * /sys/devices/xen-backend/(vbd|tap)-{domid}-{devid}/statistics/{...}
- */
-
- if (strlen(path) >= 5 && STRPREFIX(path, "/dev/"))
- retval = virAsprintf(&mod_path, "%s", path);
- else
- retval = virAsprintf(&mod_path, "/dev/%s", path);
-
- if (retval < 0) {
- virReportOOMError (conn);
- return -1;
- }
-
- retval = -1;
-
- if (disk_re_match("/dev/sd[a-z]([1-9]|1[0-5])?$", mod_path, &part)) {
- major = scsi_majors[(mod_path[7] - 'a') / 16];
- minor = ((mod_path[7] - 'a') % 16) * 16 + part;
- retval = major * 256 + minor;
- }
- else if (disk_re_match("/dev/sd[a-h][a-z]([1-9]|1[0-5])?$",
- mod_path, &part) ||
- disk_re_match("/dev/sdi[a-v]([1-9]|1[0-5])?$",
- mod_path, &part)) {
- major = scsi_majors[((mod_path[7] - 'a' + 1) * 26 + (mod_path[8] - 'a')) / 16];
- minor = (((mod_path[7] - 'a' + 1) * 26 + (mod_path[8] - 'a')) % 16)
- * 16 + part;
- retval = major * 256 + minor;
- }
- else if (disk_re_match("/dev/hd[a-t]([1-9]|[1-5][0-9]|6[0-3])?$",
- mod_path, &part)) {
- major = ide_majors[(mod_path[7] - 'a') / 2];
- minor = ((mod_path[7] - 'a') % 2) * 64 + part;
- retval = major * 256 + minor;
- }
- else if (disk_re_match("/dev/xvd[a-p]([1-9]|1[0-5])?$", mod_path, &part))
- retval = (202 << 8) + ((mod_path[8] - 'a') << 4) + part;
- else if (disk_re_match("/dev/xvd[q-z]([1-9]|1[0-5])?$", mod_path, &part))
- retval = (1 << 28) + ((mod_path[8] - 'a') << 8) + part;
- else if (disk_re_match("/dev/xvd[a-i][a-z]([1-9]|1[0-5])?$",
- mod_path, &part))
- retval = (1 << 28) + (((mod_path[8] - 'a' + 1) * 26 + (mod_path[9] - 'a')) << 8) + part;
- /*
- * OK, we've now checked the common case (things that work); check the
- * beginning of the strings for better error messages
- */
- else if (strlen(mod_path) >= 7 && STRPREFIX(mod_path, "/dev/sd"))
- statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "invalid path, device names must be in the range sda[1-15] - sdiv[1-15]",
- domid);
- else if (strlen(mod_path) >= 7 && STRPREFIX(mod_path, "/dev/hd"))
- statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "invalid path, device names must be in the range hda[1-63] - hdt[1-63]",
- domid);
- else if (strlen(mod_path) >= 8 && STRPREFIX(mod_path, "/dev/xvd"))
- statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "invalid path, device names must be in the range xvda[1-15] - xvdiz[1-15]",
- domid);
- else
- statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "unsupported path, use xvdN, hdN, or sdN", domid);
-
- VIR_FREE(mod_path);
-
- return retval;
-}
-
-int
-xenLinuxDomainBlockStats (xenUnifiedPrivatePtr priv,
- virDomainPtr dom,
- const char *path,
- struct _virDomainBlockStats *stats)
-{
- int device = xenLinuxDomainDeviceID(dom->conn, dom->id, path);
-
- if (device < 0)
- return -1;
-
- return read_bd_stats (dom->conn, priv, device, dom->id, stats);
-}
-
-#endif /* WITH_XEN */
/*-------------------- interface stats --------------------*/
/* Just reads the named interface, so not Xen or QEMU-specific.
#ifdef __linux__
-#include "xen_unified.h"
+#include "internal.h"
-extern int xenLinuxDomainBlockStats (xenUnifiedPrivatePtr priv,
- virDomainPtr dom, const char *path,
- struct _virDomainBlockStats *stats);
extern int linuxDomainInterfaceStats (virConnectPtr conn, const char *path,
struct _virDomainInterfaceStats *stats);
-extern int xenLinuxDomainDeviceID(virConnectPtr conn, int domid, const char *dev);
-
#endif /* __linux__ */
#endif /* __STATS_LINUX_H__ */
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/inotify.h>
+#include <sys/un.h>
#include "uml_driver.h"
#include "uml_conf.h"
--- /dev/null
+/*
+ * Linux block and network stats.
+ *
+ * Copyright (C) 2007-2009 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Richard W.M. Jones <rjones@redhat.com>
+ */
+
+#include <config.h>
+
+/* This file only applies on Linux. */
+#ifdef __linux__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <regex.h>
+
+#include <xs.h>
+
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "util.h"
+#include "block_stats.h"
+#include "memory.h"
+
+#define VIR_FROM_THIS VIR_FROM_STATS_LINUX
+
+/**
+ * statsErrorFunc:
+ * @conn: the connection
+ * @error: the error number
+ * @func: the function failing
+ * @info: extra information string
+ * @value: extra information number
+ *
+ * Handle a stats error.
+ */
+static void
+statsErrorFunc (virConnectPtr conn,
+ virErrorNumber error, const char *func, const char *info,
+ int value)
+{
+ char fullinfo[1000];
+ const char *errmsg;
+
+ errmsg = virErrorMsg(error, info);
+ if (func != NULL) {
+ snprintf(fullinfo, sizeof (fullinfo) - 1, "%s: %s", func, info);
+ fullinfo[sizeof (fullinfo) - 1] = 0;
+ info = fullinfo;
+ }
+ virRaiseError(conn, NULL, NULL, VIR_FROM_STATS_LINUX, error,
+ VIR_ERR_ERROR,
+ errmsg, info, NULL, value, 0, errmsg, info,
+ value);
+}
+
+/*-------------------- Xen: block stats --------------------*/
+
+#include <linux/major.h>
+
+/* This is normally defined in <linux/major.h> but previously we
+ * hard-coded it. So if it's not defined, hard-code again.
+ */
+#ifndef XENVBD_MAJOR
+#define XENVBD_MAJOR 202
+#endif
+
+static int
+xstrtoint64 (char const *s, int base, int64_t *result)
+{
+ long long int lli;
+ char *p;
+
+ errno = 0;
+ lli = strtoll (s, &p, base);
+ if (errno || !(*p == 0 || *p == '\n') || p == s || (int64_t) lli != lli)
+ return -1;
+ *result = lli;
+ return 0;
+}
+
+static int64_t
+read_stat (const char *path)
+{
+ char str[64];
+ int64_t r;
+ int i;
+ FILE *fp;
+
+ fp = fopen (path, "r");
+ if (!fp)
+ return -1;
+
+ /* read, but don't bail out before closing */
+ i = fread (str, 1, sizeof str - 1, fp);
+
+ if (fclose (fp) != 0 /* disk error */
+ || i < 1) /* ensure we read at least one byte */
+ return -1;
+
+ str[i] = '\0'; /* make sure the string is nul-terminated */
+ if (xstrtoint64 (str, 10, &r) == -1)
+ return -1;
+
+ return r;
+}
+
+static int64_t
+read_bd_stat (int device, int domid, const char *str)
+{
+ char path[PATH_MAX];
+ int64_t r;
+
+ snprintf (path, sizeof path,
+ "/sys/devices/xen-backend/vbd-%d-%d/statistics/%s",
+ domid, device, str);
+ r = read_stat (path);
+ if (r >= 0) return r;
+
+ snprintf (path, sizeof path,
+ "/sys/devices/xen-backend/tap-%d-%d/statistics/%s",
+ domid, device, str);
+ r = read_stat (path);
+ return r;
+}
+
+/* In Xenstore, /local/domain/0/backend/vbd/<domid>/<device>/state,
+ * if available, must be XenbusStateConnected (= 4), otherwise there
+ * is no connected device.
+ */
+static int
+check_bd_connected (xenUnifiedPrivatePtr priv, int device, int domid)
+{
+ char s[256], *rs;
+ int r;
+ unsigned len = 0;
+
+ /* This code assumes we're connected if we can't get to
+ * xenstore, etc.
+ */
+ if (!priv->xshandle) return 1;
+ snprintf (s, sizeof s, "/local/domain/0/backend/vbd/%d/%d/state",
+ domid, device);
+ s[sizeof s - 1] = '\0';
+
+ rs = xs_read (priv->xshandle, 0, s, &len);
+ if (!rs) return 1;
+ if (len == 0) {
+ /* Hmmm ... we can get to xenstore but it returns an empty
+ * string instead of an error. Assume it's not connected
+ * in this case.
+ */
+ free (rs);
+ return 0;
+ }
+
+ r = STREQ (rs, "4");
+ free (rs);
+ return r;
+}
+
+static int
+read_bd_stats (virConnectPtr conn, xenUnifiedPrivatePtr priv,
+ int device, int domid, struct _virDomainBlockStats *stats)
+{
+ stats->rd_req = read_bd_stat (device, domid, "rd_req");
+ stats->rd_bytes = read_bd_stat (device, domid, "rd_sect");
+ stats->wr_req = read_bd_stat (device, domid, "wr_req");
+ stats->wr_bytes = read_bd_stat (device, domid, "wr_sect");
+ stats->errs = read_bd_stat (device, domid, "oo_req");
+
+ /* None of the files were found - it's likely that this version
+ * of Xen is an old one which just doesn't support stats collection.
+ */
+ if (stats->rd_req == -1 && stats->rd_bytes == -1 &&
+ stats->wr_req == -1 && stats->wr_bytes == -1 &&
+ stats->errs == -1) {
+ statsErrorFunc (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
+ "Failed to read any block statistics", domid);
+ return -1;
+ }
+
+ /* If stats are all zero then either there really isn't any block
+ * device activity, or there is no connected front end device
+ * in which case there are no stats.
+ */
+ if (stats->rd_req == 0 && stats->rd_bytes == 0 &&
+ stats->wr_req == 0 && stats->wr_bytes == 0 &&
+ stats->errs == 0 &&
+ !check_bd_connected (priv, device, domid)) {
+ statsErrorFunc (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
+ "Frontend block device not connected", domid);
+ return -1;
+ }
+
+ /* 'Bytes' was really sectors when we read it. Scale up by
+ * an assumed sector size.
+ */
+ if (stats->rd_bytes > 0) {
+ if (stats->rd_bytes >= ((unsigned long long)1)<<(63-9)) {
+ statsErrorFunc (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
+ "stats->rd_bytes would overflow 64 bit counter",
+ domid);
+ return -1;
+ }
+ stats->rd_bytes *= 512;
+ }
+ if (stats->wr_bytes > 0) {
+ if (stats->wr_bytes >= ((unsigned long long)1)<<(63-9)) {
+ statsErrorFunc (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
+ "stats->wr_bytes would overflow 64 bit counter",
+ domid);
+ return -1;
+ }
+ stats->wr_bytes *= 512;
+ }
+
+ return 0;
+}
+
+static int
+disk_re_match(const char *regex, const char *path, int *part)
+{
+ regex_t myreg;
+ int err;
+ int retval;
+ regmatch_t pmatch[3];
+
+ retval = 0;
+
+ err = regcomp(&myreg, regex, REG_EXTENDED);
+ if (err != 0)
+ return 0;
+
+ err = regexec(&myreg, path, 3, pmatch, 0);
+
+ if (err == 0) {
+ /* OK, we have a match; see if we have a partition */
+ *part = 0;
+ retval = 1;
+ if (pmatch[1].rm_so != -1) {
+ if (virStrToLong_i(path + pmatch[1].rm_so, NULL, 10, part) < 0)
+ retval = 0;
+ }
+ }
+
+ regfree(&myreg);
+
+ return retval;
+}
+
+int
+xenLinuxDomainDeviceID(virConnectPtr conn, int domid, const char *path)
+{
+ int major, minor;
+ int part;
+ int retval;
+ char *mod_path;
+
+ int const scsi_majors[] = { SCSI_DISK0_MAJOR, SCSI_DISK1_MAJOR,
+ SCSI_DISK2_MAJOR, SCSI_DISK3_MAJOR,
+ SCSI_DISK4_MAJOR, SCSI_DISK5_MAJOR,
+ SCSI_DISK6_MAJOR, SCSI_DISK7_MAJOR,
+ SCSI_DISK8_MAJOR, SCSI_DISK9_MAJOR,
+ SCSI_DISK10_MAJOR, SCSI_DISK11_MAJOR,
+ SCSI_DISK12_MAJOR, SCSI_DISK13_MAJOR,
+ SCSI_DISK14_MAJOR, SCSI_DISK15_MAJOR };
+ int const ide_majors[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
+ IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR,
+ IDE8_MAJOR, IDE9_MAJOR };
+
+ /*
+ * Possible block device majors & partition ranges. This
+ * matches the ranges supported in Xend xen/util/blkif.py
+ *
+ * hdNM: N=a-t, M=1-63, major={IDE0_MAJOR -> IDE9_MAJOR}
+ * sdNM: N=a-z,aa-iv, M=1-15, major={SCSI_DISK0_MAJOR -> SCSI_DISK15_MAJOR}
+ * xvdNM: N=a-p M=1-15, major=XENVBD_MAJOR
+ * xvdNM: N=q-z,aa-iz M=1-15, major=(1<<28)
+ *
+ * The path for statistics will be
+ *
+ * /sys/devices/xen-backend/(vbd|tap)-{domid}-{devid}/statistics/{...}
+ */
+
+ if (strlen(path) >= 5 && STRPREFIX(path, "/dev/"))
+ retval = virAsprintf(&mod_path, "%s", path);
+ else
+ retval = virAsprintf(&mod_path, "/dev/%s", path);
+
+ if (retval < 0) {
+ virReportOOMError (conn);
+ return -1;
+ }
+
+ retval = -1;
+
+ if (disk_re_match("/dev/sd[a-z]([1-9]|1[0-5])?$", mod_path, &part)) {
+ major = scsi_majors[(mod_path[7] - 'a') / 16];
+ minor = ((mod_path[7] - 'a') % 16) * 16 + part;
+ retval = major * 256 + minor;
+ }
+ else if (disk_re_match("/dev/sd[a-h][a-z]([1-9]|1[0-5])?$",
+ mod_path, &part) ||
+ disk_re_match("/dev/sdi[a-v]([1-9]|1[0-5])?$",
+ mod_path, &part)) {
+ major = scsi_majors[((mod_path[7] - 'a' + 1) * 26 + (mod_path[8] - 'a')) / 16];
+ minor = (((mod_path[7] - 'a' + 1) * 26 + (mod_path[8] - 'a')) % 16)
+ * 16 + part;
+ retval = major * 256 + minor;
+ }
+ else if (disk_re_match("/dev/hd[a-t]([1-9]|[1-5][0-9]|6[0-3])?$",
+ mod_path, &part)) {
+ major = ide_majors[(mod_path[7] - 'a') / 2];
+ minor = ((mod_path[7] - 'a') % 2) * 64 + part;
+ retval = major * 256 + minor;
+ }
+ else if (disk_re_match("/dev/xvd[a-p]([1-9]|1[0-5])?$", mod_path, &part))
+ retval = (202 << 8) + ((mod_path[8] - 'a') << 4) + part;
+ else if (disk_re_match("/dev/xvd[q-z]([1-9]|1[0-5])?$", mod_path, &part))
+ retval = (1 << 28) + ((mod_path[8] - 'a') << 8) + part;
+ else if (disk_re_match("/dev/xvd[a-i][a-z]([1-9]|1[0-5])?$",
+ mod_path, &part))
+ retval = (1 << 28) + (((mod_path[8] - 'a' + 1) * 26 + (mod_path[9] - 'a')) << 8) + part;
+ /*
+ * OK, we've now checked the common case (things that work); check the
+ * beginning of the strings for better error messages
+ */
+ else if (strlen(mod_path) >= 7 && STRPREFIX(mod_path, "/dev/sd"))
+ statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "invalid path, device names must be in the range sda[1-15] - sdiv[1-15]",
+ domid);
+ else if (strlen(mod_path) >= 7 && STRPREFIX(mod_path, "/dev/hd"))
+ statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "invalid path, device names must be in the range hda[1-63] - hdt[1-63]",
+ domid);
+ else if (strlen(mod_path) >= 8 && STRPREFIX(mod_path, "/dev/xvd"))
+ statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "invalid path, device names must be in the range xvda[1-15] - xvdiz[1-15]",
+ domid);
+ else
+ statsErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "unsupported path, use xvdN, hdN, or sdN", domid);
+
+ VIR_FREE(mod_path);
+
+ return retval;
+}
+
+int
+xenLinuxDomainBlockStats (xenUnifiedPrivatePtr priv,
+ virDomainPtr dom,
+ const char *path,
+ struct _virDomainBlockStats *stats)
+{
+ int device = xenLinuxDomainDeviceID(dom->conn, dom->id, path);
+
+ if (device < 0)
+ return -1;
+
+ return read_bd_stats (dom->conn, priv, device, dom->id, stats);
+}
+
+#endif /* __linux__ */
--- /dev/null
+/*
+ * Linux block and network stats.
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Richard W.M. Jones <rjones@redhat.com>
+ */
+
+#ifndef __BLOCK_STATS_H__
+#define __BLOCK_STATS_H__
+
+#ifdef __linux__
+
+#include "xen_driver.h"
+
+extern int xenLinuxDomainBlockStats (xenUnifiedPrivatePtr priv,
+ virDomainPtr dom, const char *path,
+ struct _virDomainBlockStats *stats);
+
+extern int xenLinuxDomainDeviceID(virConnectPtr conn, int domid, const char *dev);
+
+#endif /* __linux__ */
+
+#endif /* __STATS_LINUX_H__ */
--- /dev/null
+/*
+ * proxy_client.c: client side of the communication with the libvirt proxy.
+ *
+ * Copyright (C) 2006, 2008, 2009 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <string.h>
+
+#include "virterror_internal.h"
+#include "logging.h"
+#include "datatypes.h"
+#include "driver.h"
+#include "proxy_internal.h"
+#include "util.h"
+#include "xen_driver.h"
+#include "memory.h"
+
+#define STANDALONE
+
+#define VIR_FROM_THIS VIR_FROM_PROXY
+
+static int xenProxyClose(virConnectPtr conn);
+static virDrvOpenStatus xenProxyOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags);
+static int xenProxyGetVersion(virConnectPtr conn, unsigned long *hvVer);
+static int xenProxyNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info);
+static char *xenProxyGetCapabilities(virConnectPtr conn);
+static int xenProxyNumOfDomains(virConnectPtr conn);
+static unsigned long xenProxyDomainGetMaxMemory(virDomainPtr domain);
+static int xenProxyDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info);
+static char *xenProxyDomainGetOSType(virDomainPtr domain);
+
+struct xenUnifiedDriver xenProxyDriver = {
+ xenProxyOpen, /* open */
+ xenProxyClose, /* close */
+ xenProxyGetVersion, /* version */
+ NULL, /* hostname */
+ xenProxyNodeGetInfo, /* nodeGetInfo */
+ xenProxyGetCapabilities, /* getCapabilities */
+ xenProxyListDomains, /* listDomains */
+ xenProxyNumOfDomains, /* numOfDomains */
+ NULL, /* domainCreateXML */
+ NULL, /* domainSuspend */
+ NULL, /* domainResume */
+ NULL, /* domainShutdown */
+ NULL, /* domainReboot */
+ NULL, /* domainDestroy */
+ xenProxyDomainGetOSType, /* domainGetOSType */
+ xenProxyDomainGetMaxMemory, /* domainGetMaxMemory */
+ NULL, /* domainSetMaxMemory */
+ NULL, /* domainSetMemory */
+ xenProxyDomainGetInfo, /* domainGetInfo */
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
+ NULL, /* domainCoreDump */
+ NULL, /* domainSetVcpus */
+ NULL, /* domainPinVcpu */
+ NULL, /* domainGetVcpus */
+ NULL, /* domainGetMaxVcpus */
+ NULL, /* listDefinedDomains */
+ NULL, /* numOfDefinedDomains */
+ NULL, /* domainCreate */
+ NULL, /* domainDefineXML */
+ NULL, /* domainUndefine */
+ NULL, /* domainAttachDevice */
+ NULL, /* domainDetachDevice */
+ NULL, /* domainGetAutostart */
+ NULL, /* domainSetAutostart */
+ NULL, /* domainGetSchedulerType */
+ NULL, /* domainGetSchedulerParameters */
+ NULL, /* domainSetSchedulerParameters */
+};
+
+
+/************************************************************************
+ * *
+ * Error handling *
+ * *
+ ************************************************************************/
+
+#define virProxyError(conn, code, fmt...) \
+ virReportErrorHelper(conn, VIR_FROM_PROXY, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
+/************************************************************************
+ * *
+ * Automatic startup of the proxy server if it is not running *
+ * *
+ ************************************************************************/
+/**
+ * virProxyFindServerPath:
+ *
+ * Tries to find the path to the gam_server binary.
+ *
+ * Returns path on success or NULL in case of error.
+ */
+static const char *
+virProxyFindServerPath(void)
+{
+ static const char *serverPaths[] = {
+ BINDIR "/libvirt_proxy",
+ "/usr/bin/libvirt_proxy_dbg",
+ NULL
+ };
+ int i;
+ const char *debugProxy = getenv("LIBVIRT_DEBUG_PROXY");
+
+ if (debugProxy)
+ return(debugProxy);
+
+ for (i = 0; serverPaths[i]; i++) {
+ if (access(serverPaths[i], X_OK | R_OK) == 0) {
+ return serverPaths[i];
+ }
+ }
+ return NULL;
+}
+
+/**
+ * virProxyForkServer:
+ *
+ * Forks and try to launch the proxy server processing the requests for
+ * libvirt when communicating with Xen.
+ *
+ * Returns 0 in case of success or -1 in case of detected error.
+ */
+static int
+virProxyForkServer(void)
+{
+ const char *proxyPath = virProxyFindServerPath();
+ pid_t pid;
+ const char *proxyarg[2];
+
+ if (!proxyPath) {
+ VIR_WARN0("failed to find libvirt_proxy\n");
+ return(-1);
+ }
+
+ VIR_DEBUG("Asking to launch %s\n", proxyPath);
+
+ proxyarg[0] = proxyPath;
+ proxyarg[1] = NULL;
+
+ if (virExecDaemonize(NULL, proxyarg, NULL, NULL,
+ &pid, -1, NULL, NULL, 0,
+ NULL, NULL, NULL) < 0)
+ VIR_ERROR0("Failed to fork libvirt_proxy\n");
+
+ return (0);
+}
+
+/************************************************************************
+ * *
+ * Processing of client sockets *
+ * *
+ ************************************************************************/
+
+/**
+ * virProxyOpenClientSocket:
+ * @path: the filename for the socket
+ *
+ * try to connect to the socket open by libvirt_proxy
+ *
+ * Returns the associated file descriptor or -1 in case of failure
+ */
+static int
+virProxyOpenClientSocket(const char *path) {
+ int fd;
+ struct sockaddr_un addr;
+ int trials = 0;
+
+retry:
+ fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ return(-1);
+ }
+
+ /*
+ * Abstract socket do not hit the filesystem, way more secure and
+ * guaranteed to be atomic
+ */
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ addr.sun_path[0] = '\0';
+ strncpy(&addr.sun_path[1], path, (sizeof(addr) - 4) - 2);
+
+ /*
+ * now bind the socket to that address and listen on it
+ */
+ if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ close(fd);
+ if (trials < 3) {
+ if (virProxyForkServer() < 0)
+ return(-1);
+ trials++;
+ usleep(5000 * trials * trials);
+ goto retry;
+ }
+ return (-1);
+ }
+
+ DEBUG("connected to unix socket %s via %d\n", path, fd);
+
+ return (fd);
+}
+
+/**
+ * virProxyCloseSocket:
+ * @priv: the Xen proxy data
+ *
+ * Close the socket from that client. The caller must
+ * hold the lock on 'priv' before calling
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+virProxyCloseSocket(xenUnifiedPrivatePtr priv) {
+ int ret;
+
+ if (priv->proxy < 0)
+ return(-1);
+
+ ret = close(priv->proxy);
+ if (ret != 0)
+ VIR_WARN(_("Failed to close socket %d\n"), priv->proxy);
+ else
+ VIR_DEBUG("Closed socket %d\n", priv->proxy);
+ priv->proxy = -1;
+ return(ret);
+}
+
+/**
+ * virProxyReadClientSocket:
+ * @fd: the socket
+ * @buffer: the target memory area
+ * @len: the length in bytes
+ *
+ * Process a read from a client socket
+ *
+ * Returns the number of byte read or -1 in case of error.
+ */
+static int
+virProxyReadClientSocket(int fd, char *buffer, int len) {
+ int ret;
+
+ if ((fd < 0) || (buffer == NULL) || (len < 0))
+ return(-1);
+
+retry:
+ ret = read(fd, buffer, len);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ VIR_DEBUG("read socket %d interrupted\n", fd);
+ goto retry;
+ }
+ VIR_WARN("Failed to read socket %d\n", fd);
+ return(-1);
+ }
+
+ VIR_DEBUG("read %d bytes from socket %d\n",
+ ret, fd);
+ return(ret);
+}
+
+/**
+ * virProxyWriteClientSocket:
+ * @fd: the socket
+ * @data: the data
+ * @len: the length of data in bytes
+ *
+ * Process a read from a client socket
+ */
+static int
+virProxyWriteClientSocket(int fd, const char *data, int len) {
+ int ret;
+
+ if ((fd < 0) || (data == NULL) || (len < 0))
+ return(-1);
+
+ ret = safewrite(fd, data, len);
+ if (ret < 0) {
+ VIR_WARN(_("Failed to write to socket %d\n"), fd);
+ return(-1);
+ }
+ VIR_DEBUG("wrote %d bytes to socket %d\n",
+ len, fd);
+
+ return(0);
+}
+
+/************************************************************************
+ * *
+ * Proxy commands processing *
+ * *
+ ************************************************************************/
+
+/**
+ * xenProxyClose:
+ * @conn: pointer to the hypervisor connection
+ *
+ * Shutdown the Xen proxy communication layer
+ */
+static int
+xenProxyClose(virConnectPtr conn)
+{
+ xenUnifiedPrivatePtr priv;
+
+ if (conn == NULL) {
+ virProxyError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return -1;
+ }
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (!priv) {
+ virProxyError (NULL, VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
+ return -1;
+ }
+
+ xenUnifiedLock(priv);
+ virProxyCloseSocket (priv);
+ xenUnifiedUnlock(priv);
+
+ return 0;
+}
+
+static int
+xenProxyCommand(virConnectPtr conn, virProxyPacketPtr request,
+ virProxyFullPacketPtr answer, int quiet) {
+ static int serial = 0;
+ int ret;
+ virProxyPacketPtr res = NULL;
+ xenUnifiedPrivatePtr priv;
+
+ if (conn == NULL) {
+ virProxyError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return -1;
+ }
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (!priv) {
+ virProxyError (NULL, VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
+ return -1;
+ }
+
+ xenUnifiedLock(priv);
+
+ /* Fail silently. */
+ if (priv->proxy == -1)
+ goto error;
+
+ /*
+ * normal communication serial numbers are in 0..4095
+ */
+ ++serial;
+ if (serial >= 4096)
+ serial = 0;
+ request->version = PROXY_PROTO_VERSION;
+ request->serial = serial;
+ ret = virProxyWriteClientSocket(priv->proxy, (const char *) request,
+ request->len);
+ if (ret < 0) {
+ if (!quiet)
+ virReportSystemError(conn, errno, "%s",
+ _("failed to write proxy request"));
+ goto error;
+ }
+retry:
+ if (answer == NULL) {
+ /* read in situ */
+ ret = virProxyReadClientSocket(priv->proxy, (char *) request,
+ sizeof(virProxyPacket));
+ if (ret < 0) {
+ if (!quiet)
+ virReportSystemError(conn, errno, "%s",
+ _("failed to read proxy reply"));
+ goto error;
+ }
+ if (ret != sizeof(virProxyPacket)) {
+ virProxyError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Communication error with proxy: got %d bytes of %d\n"),
+ ret, (int) sizeof(virProxyPacket));
+ goto error;
+ }
+ res = request;
+ if (res->len != sizeof(virProxyPacket)) {
+ virProxyError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Communication error with proxy: expected %d bytes got %d\n"),
+ (int) sizeof(virProxyPacket), res->len);
+ goto error;
+ }
+ } else {
+ /* read in packet provided */
+ ret = virProxyReadClientSocket(priv->proxy, (char *) answer,
+ sizeof(virProxyPacket));
+ if (ret < 0) {
+ if (!quiet)
+ virReportSystemError(conn, errno, "%s",
+ _("failed to read proxy reply"));
+ goto error;
+ }
+ if (ret != sizeof(virProxyPacket)) {
+ virProxyError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Communication error with proxy: got %d bytes of %d\n"),
+ ret, (int) sizeof(virProxyPacket));
+ goto error;
+ }
+ res = (virProxyPacketPtr) answer;
+ if ((res->len < sizeof(virProxyPacket)) ||
+ (res->len > sizeof(virProxyFullPacket))) {
+ virProxyError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Communication error with proxy: got %d bytes packet\n"),
+ res->len);
+ goto error;
+ }
+ if (res->len > sizeof(virProxyPacket)) {
+ ret = virProxyReadClientSocket(priv->proxy,
+ (char *) &(answer->extra.arg[0]),
+ res->len - ret);
+ if (ret != (int) (res->len - sizeof(virProxyPacket))) {
+ virProxyError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Communication error with proxy: got %d bytes of %d\n"),
+ ret, (int) sizeof(virProxyPacket));
+ goto error;
+ }
+ }
+ }
+ /*
+ * do more checks on the incoming packet.
+ */
+ if ((res == NULL) || (res->version != PROXY_PROTO_VERSION) ||
+ (res->len < sizeof(virProxyPacket))) {
+ virProxyError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Communication error with proxy: malformed packet\n"));
+ goto error;
+ }
+ if (res->serial != serial) {
+ VIR_WARN(_("got asynchronous packet number %d\n"), res->serial);
+ goto retry;
+ }
+
+ xenUnifiedUnlock(priv);
+ return 0;
+
+error:
+ virProxyCloseSocket(priv);
+ xenUnifiedUnlock(priv);
+ return -1;
+}
+
+/**
+ * xenProxyOpen:
+ * @conn: pointer to the hypervisor connection
+ * @name: URL for the target, NULL for local
+ * @flags: combination of virDrvOpenFlag(s)
+ *
+ * Try to initialize the Xen proxy communication layer
+ * This can be opened only for a read-only kind of access
+ *
+ * Returns 0 in case of success, and -1 in case of failure
+ */
+virDrvOpenStatus
+xenProxyOpen(virConnectPtr conn,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+ int flags)
+{
+ virProxyPacket req;
+ int ret;
+ int fd;
+ xenUnifiedPrivatePtr priv;
+
+ if (!(flags & VIR_CONNECT_RO))
+ return(-1);
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ priv->proxy = -1;
+
+ fd = virProxyOpenClientSocket(PROXY_SOCKET_PATH);
+ if (fd < 0) {
+ virProxyError(NULL, VIR_ERR_NO_XEN, PROXY_SOCKET_PATH);
+ return(-1);
+ }
+ priv->proxy = fd;
+
+ memset(&req, 0, sizeof(req));
+ req.command = VIR_PROXY_NONE;
+ req.len = sizeof(req);
+ ret = xenProxyCommand(conn, &req, NULL, 1);
+ if ((ret < 0) || (req.command != VIR_PROXY_NONE)) {
+ virProxyError(NULL, VIR_ERR_OPERATION_FAILED, __FUNCTION__);
+ return(-1);
+ }
+ return(0);
+}
+
+/************************************************************************
+ * *
+ * Driver entry points *
+ * *
+ ************************************************************************/
+
+/**
+ * xenProxyGetVersion:
+ * @conn: pointer to the Xen Daemon block
+ * @hvVer: return value for the version of the running hypervisor (OUT)
+ *
+ * Get the version level of the Hypervisor running.
+ *
+ * Returns -1 in case of error, 0 otherwise. if the version can't be
+ * extracted by lack of capacities returns 0 and @hvVer is 0, otherwise
+ * @hvVer value is major * 1,000,000 + minor * 1,000 + release
+ */
+static int
+xenProxyGetVersion(virConnectPtr conn, unsigned long *hvVer)
+{
+ virProxyPacket req;
+ int ret;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+ if (hvVer == NULL) {
+ virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (-1);
+ }
+ memset(&req, 0, sizeof(req));
+ req.command = VIR_PROXY_VERSION;
+ req.len = sizeof(req);
+ ret = xenProxyCommand(conn, &req, NULL, 0);
+ if (ret < 0) {
+ return(-1);
+ }
+ *hvVer = req.data.larg;
+ return(0);
+}
+
+/**
+ * xenProxyListDomains:
+ * @conn: pointer to the hypervisor connection
+ * @ids: array to collect the list of IDs of active domains
+ * @maxids: size of @ids
+ *
+ * Collect the list of active domains, and store their ID in @maxids
+ *
+ * Returns the number of domain found or -1 in case of error
+ */
+int
+xenProxyListDomains(virConnectPtr conn, int *ids, int maxids)
+{
+ virProxyPacket req;
+ virProxyFullPacket ans;
+ int ret;
+ int nb;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+ if ((ids == NULL) || (maxids <= 0)) {
+ virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (-1);
+ }
+ memset(&req, 0, sizeof(req));
+ req.command = VIR_PROXY_LIST;
+ req.len = sizeof(req);
+ ret = xenProxyCommand(conn, &req, &ans, 0);
+ if (ret < 0) {
+ return(-1);
+ }
+ nb = ans.data.arg;
+ if ((nb > 1020) || (nb <= 0) ||
+ (ans.len <= sizeof(virProxyPacket)) ||
+ (ans.len > sizeof(virProxyFullPacket))) {
+ virProxyError(conn, VIR_ERR_OPERATION_FAILED, __FUNCTION__);
+ return(-1);
+ }
+ if (nb > maxids)
+ nb = maxids;
+ memmove(ids, &ans.extra.arg[0], nb * sizeof(int));
+
+ return(nb);
+}
+
+/**
+ * xenProxyNumOfDomains:
+ * @conn: pointer to the hypervisor connection
+ *
+ * Provides the number of active domains.
+ *
+ * Returns the number of domain found or -1 in case of error
+ */
+static int
+xenProxyNumOfDomains(virConnectPtr conn)
+{
+ virProxyPacket req;
+ int ret;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+ memset(&req, 0, sizeof(req));
+ req.command = VIR_PROXY_NUM_DOMAIN;
+ req.len = sizeof(req);
+ ret = xenProxyCommand(conn, &req, NULL, 0);
+ if (ret < 0) {
+ return(-1);
+ }
+ return(req.data.arg);
+}
+
+
+/**
+ * xenProxyDomainGetDomMaxMemory:
+ * @conn: pointer to the hypervisor connection
+ * @id: the domain ID number
+ *
+ * Ask the Xen Daemon for the maximum memory allowed for a domain
+ *
+ * Returns the memory size in kilobytes or 0 in case of error.
+ */
+static unsigned long
+xenProxyDomainGetDomMaxMemory(virConnectPtr conn, int id)
+{
+ virProxyPacket req;
+ int ret;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (0);
+ }
+ memset(&req, 0, sizeof(req));
+ req.command = VIR_PROXY_MAX_MEMORY;
+ req.data.arg = id;
+ req.len = sizeof(req);
+ ret = xenProxyCommand(conn, &req, NULL, 0);
+ if (ret < 0) {
+ return(0);
+ }
+ return(req.data.larg);
+}
+
+/**
+ * xenProxyDomainGetMaxMemory:
+ * @domain: pointer to the domain block
+ *
+ * Ask the Xen Daemon for the maximum memory allowed for a domain
+ *
+ * Returns the memory size in kilobytes or 0 in case of error.
+ */
+static unsigned long
+xenProxyDomainGetMaxMemory(virDomainPtr domain)
+{
+ if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+ if (domain == NULL)
+ virProxyError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ else
+ virProxyError(domain->conn, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ return (0);
+ }
+ if (domain->id < 0)
+ return (0);
+ return(xenProxyDomainGetDomMaxMemory(domain->conn, domain->id));
+}
+
+/**
+ * xenProxyDomainGetInfo:
+ * @domain: a domain object
+ * @info: pointer to a virDomainInfo structure allocated by the user
+ *
+ * This method looks up information about a domain and update the
+ * information block provided.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+static int
+xenProxyDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
+{
+ virProxyPacket req;
+ virProxyFullPacket ans;
+ int ret;
+
+ if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+ if (domain == NULL)
+ virProxyError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ else
+ virProxyError(domain->conn, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ return (-1);
+ }
+ if (domain->id < 0)
+ return (-1);
+ if (info == NULL) {
+ virProxyError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (-1);
+ }
+ memset(&req, 0, sizeof(req));
+ req.command = VIR_PROXY_DOMAIN_INFO;
+ req.data.arg = domain->id;
+ req.len = sizeof(req);
+ ret = xenProxyCommand(domain->conn, &req, &ans, 0);
+ if (ret < 0) {
+ return(-1);
+ }
+ if (ans.len != sizeof(virProxyPacket) + sizeof(virDomainInfo)) {
+ virProxyError(domain->conn, VIR_ERR_OPERATION_FAILED, __FUNCTION__);
+ return (-1);
+ }
+ memmove(info, &ans.extra.dinfo, sizeof(virDomainInfo));
+
+ return(0);
+}
+
+/**
+ * xenProxyLookupByID:
+ * @conn: pointer to the hypervisor connection
+ * @id: the domain ID number
+ *
+ * Try to find a domain based on the hypervisor ID number
+ *
+ * Returns a new domain object or NULL in case of failure
+ */
+virDomainPtr
+xenProxyLookupByID(virConnectPtr conn, int id)
+{
+ virProxyPacket req;
+ virProxyFullPacket ans;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ const char *name;
+ int ret;
+ virDomainPtr res;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (NULL);
+ }
+ if (id < 0) {
+ virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (NULL);
+ }
+ memset(&req, 0, sizeof(req));
+ req.command = VIR_PROXY_LOOKUP_ID;
+ req.data.arg = id;
+ req.len = sizeof(req);
+ ret = xenProxyCommand(conn, &req, &ans, 0);
+ if (ret < 0) {
+ return(NULL);
+ }
+ if (ans.data.arg == -1) {
+ return(NULL);
+ }
+ memcpy(uuid, &ans.extra.str[0], VIR_UUID_BUFLEN);
+ name = &ans.extra.str[VIR_UUID_BUFLEN];
+ res = virGetDomain(conn, name, uuid);
+ if (res) res->id = id;
+ return(res);
+}
+
+/**
+ * xenProxyLookupByUUID:
+ * @conn: pointer to the hypervisor connection
+ * @uuid: the raw UUID for the domain
+ *
+ * Try to lookup a domain on xend based on its UUID.
+ *
+ * Returns a new domain object or NULL in case of failure
+ */
+virDomainPtr
+xenProxyLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+ virProxyFullPacket req;
+ const char *name;
+ int ret;
+ virDomainPtr res;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (NULL);
+ }
+ if (uuid == NULL) {
+ virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (NULL);
+ }
+ memset(&req, 0, sizeof(virProxyPacket));
+ req.command = VIR_PROXY_LOOKUP_UUID;
+ req.len = sizeof(virProxyPacket) + VIR_UUID_BUFLEN;
+ memcpy(&req.extra.str[0], uuid, VIR_UUID_BUFLEN);
+
+ ret = xenProxyCommand(conn, (virProxyPacketPtr) &req, &req, 0);
+ if (ret < 0) {
+ return(NULL);
+ }
+ if (req.data.arg == -1) {
+ return(NULL);
+ }
+ name = &req.extra.str[0];
+ res = virGetDomain(conn, name, uuid);
+ if (res) res->id = req.data.arg;
+ return(res);
+}
+
+/**
+ * xenProxyLookupByName:
+ * @conn: A xend instance
+ * @name: The name of the domain
+ *
+ * This method looks up information about a domain based on its name
+ *
+ * Returns a new domain object or NULL in case of failure
+ */
+virDomainPtr
+xenProxyLookupByName(virConnectPtr conn, const char *name)
+{
+ virProxyFullPacket req;
+ int ret, len;
+ virDomainPtr res;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (NULL);
+ }
+ if (name == NULL) {
+ virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (NULL);
+ }
+ len = strlen(name);
+ if (len > 1000) {
+ virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (NULL);
+ }
+ memset(&req, 0, sizeof(virProxyPacket));
+ req.command = VIR_PROXY_LOOKUP_NAME;
+ req.len = sizeof(virProxyPacket) + len + 1;
+ strcpy(&req.extra.str[0], name);
+ ret = xenProxyCommand(conn, (virProxyPacketPtr) &req, &req, 0);
+ if (ret < 0) {
+ return(NULL);
+ }
+ if (req.data.arg == -1) {
+ return(NULL);
+ }
+ res = virGetDomain(conn, name, (const unsigned char *)&req.extra.str[0]);
+ if (res) res->id = req.data.arg;
+ return(res);
+}
+
+/**
+ * xenProxyNodeGetInfo:
+ * @conn: pointer to the Xen Daemon block
+ * @info: pointer to a virNodeInfo structure allocated by the user
+ *
+ * Extract hardware information about the node.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+static int
+xenProxyNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) {
+ virProxyPacket req;
+ virProxyFullPacket ans;
+ int ret;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+ if (info == NULL) {
+ virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (-1);
+ }
+ memset(&req, 0, sizeof(req));
+ req.command = VIR_PROXY_NODE_INFO;
+ req.data.arg = 0;
+ req.len = sizeof(req);
+ ret = xenProxyCommand(conn, &req, &ans, 0);
+ if (ret < 0) {
+ return(-1);
+ }
+ if (ans.data.arg == -1) {
+ return(-1);
+ }
+ if (ans.len != sizeof(virProxyPacket) + sizeof(virNodeInfo)) {
+ return(-1);
+ }
+ memcpy(info, &ans.extra.ninfo, sizeof(virNodeInfo));
+ return(0);
+}
+
+/**
+ * xenProxyGetCapabilities:
+ * @conn: pointer to the Xen Daemon block
+ *
+ * Extract capabilities of the hypervisor.
+ *
+ * Returns capabilities in case of success (freed by caller)
+ * and NULL in case of failure.
+ */
+static char *
+xenProxyGetCapabilities (virConnectPtr conn)
+{
+ virProxyPacket req;
+ virProxyFullPacket ans;
+ int ret, xmllen;
+ char *xml;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return NULL;
+ }
+ memset(&req, 0, sizeof(req));
+ req.command = VIR_PROXY_GET_CAPABILITIES;
+ req.data.arg = 0;
+ req.len = sizeof(req);
+ ret = xenProxyCommand(conn, &req, &ans, 0);
+ if (ret < 0) {
+ return NULL;
+ }
+ if (ans.data.arg == -1)
+ return NULL;
+ if (ans.len <= sizeof(virProxyPacket)) {
+ virProxyError(conn, VIR_ERR_OPERATION_FAILED, __FUNCTION__);
+ return NULL;
+ }
+
+ xmllen = ans.len - sizeof (virProxyPacket);
+ if (VIR_ALLOC_N(xml, xmllen+1) < 0) {
+ virReportOOMError (conn);
+ return NULL;
+ }
+ memmove (xml, ans.extra.str, xmllen);
+ xml[xmllen] = '\0';
+
+ return xml;
+}
+
+/**
+ * xenProxyDomainDumpXML:
+ * @domain: a domain object
+ * @flags: xml generation flags
+ *
+ * This method generates an XML description of a domain.
+ *
+ * Returns the XML document on success, NULL otherwise.
+ */
+char *
+xenProxyDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED)
+{
+ virProxyPacket req;
+ virProxyFullPacket ans;
+ int ret;
+ int xmllen;
+ char *xml;
+
+ if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+ if (domain == NULL)
+ virProxyError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ else
+ virProxyError(domain->conn, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ return (NULL);
+ }
+ if (domain->id < 0)
+ return (NULL);
+ memset(&req, 0, sizeof(req));
+ req.command = VIR_PROXY_DOMAIN_XML;
+ req.data.arg = domain->id;
+ req.len = sizeof(req);
+ ret = xenProxyCommand(domain->conn, &req, &ans, 0);
+ if (ret < 0) {
+ return(NULL);
+ }
+ if (ans.len <= sizeof(virProxyPacket)) {
+ virProxyError(domain->conn, VIR_ERR_OPERATION_FAILED, __FUNCTION__);
+ return (NULL);
+ }
+ xmllen = ans.len - sizeof(virProxyPacket);
+ if (VIR_ALLOC_N(xml, xmllen+1) < 0) {
+ virReportOOMError(domain->conn);
+ return NULL;
+ }
+ memmove(xml, &ans.extra.dinfo, xmllen);
+ xml[xmllen] = '\0';
+
+ return(xml);
+}
+
+/**
+ * xenProxyDomainGetOSType:
+ * @domain: a domain object
+ *
+ * Get the type of domain operation system.
+ *
+ * Returns the new string or NULL in case of error, the string must be
+ * freed by the caller.
+ */
+static char *
+xenProxyDomainGetOSType(virDomainPtr domain)
+{
+ virProxyPacket req;
+ virProxyFullPacket ans;
+ int ret;
+ int oslen;
+ char *ostype;
+
+ if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+ if (domain == NULL)
+ virProxyError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ else
+ virProxyError(domain->conn, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ return (NULL);
+ }
+ memset(&req, 0, sizeof(req));
+ req.command = VIR_PROXY_DOMAIN_OSTYPE;
+ req.data.arg = domain->id;
+ req.len = sizeof(req);
+ ret = xenProxyCommand(domain->conn, &req, &ans, 0);
+ if (ret < 0) {
+ return(NULL);
+ }
+ if ((ans.len == sizeof(virProxyPacket)) && (ans.data.arg < 0)) {
+ return(NULL);
+ }
+
+ if (ans.len <= sizeof(virProxyPacket)) {
+ virProxyError(domain->conn, VIR_ERR_OPERATION_FAILED, __FUNCTION__);
+ return (NULL);
+ }
+ oslen = ans.len - sizeof(virProxyPacket);
+ if (VIR_ALLOC_N(ostype, oslen+1) < 0) {
+ virReportOOMError(domain->conn);
+ return NULL;
+ }
+ memmove(ostype, &ans.extra.dinfo, oslen);
+ ostype[oslen] = '\0';
+
+ return(ostype);
+}
--- /dev/null
+/*
+ * proxy.h: common definitions for proxy usage
+ *
+ * Copyright (C) 2006 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+
+#ifndef __LIBVIR_PROXY_H__
+#define __LIBVIR_PROXY_H__
+
+#include "internal.h"
+
+#define PROXY_SOCKET_PATH "/tmp/livirt_proxy_conn"
+#define PROXY_PROTO_VERSION 1
+
+/*
+ * the command allowed though the proxy
+ */
+typedef enum {
+ VIR_PROXY_NONE = 0,
+ VIR_PROXY_VERSION = 1,
+ VIR_PROXY_NODE_INFO = 2,
+ VIR_PROXY_LIST = 3,
+ VIR_PROXY_NUM_DOMAIN = 4,
+ VIR_PROXY_LOOKUP_ID = 5,
+ VIR_PROXY_LOOKUP_UUID = 6,
+ VIR_PROXY_LOOKUP_NAME = 7,
+ VIR_PROXY_MAX_MEMORY = 8,
+ VIR_PROXY_DOMAIN_INFO = 9,
+ VIR_PROXY_DOMAIN_XML = 10,
+ VIR_PROXY_DOMAIN_OSTYPE = 11,
+ VIR_PROXY_GET_CAPABILITIES = 12
+} virProxyCommand;
+
+/*
+ * structure used by the client to make a request to the proxy
+ * and by the proxy when answering the client.
+ * the size may not be fixed, it's passed as len.
+ */
+struct _virProxyPacket {
+ unsigned short version; /* version of the proxy protocol */
+ unsigned short command; /* command number a virProxyCommand */
+ unsigned short serial; /* command serial number */
+ unsigned short len; /* the length of the request */
+ union {
+ char string[8]; /* string data */
+ int arg; /* or int argument */
+ long larg; /* or long argument */
+ } data;
+};
+typedef struct _virProxyPacket virProxyPacket;
+typedef virProxyPacket *virProxyPacketPtr;
+
+/*
+ * If there is extra data sent from the proxy to the client,
+ * they are appended after the packet.
+ * the size may not be fixed, it's passed as len and includes the
+ * extra data.
+ */
+struct _virProxyFullPacket {
+ unsigned short version; /* version of the proxy protocol */
+ unsigned short command; /* command number a virProxyCommand */
+ unsigned short serial; /* command serial number */
+ unsigned short len; /* the length of the request */
+ union {
+ char string[8]; /* string data */
+ int arg; /* or int argument */
+ long larg; /* or long argument */
+ } data;
+ /* that should be aligned on a 16bytes boundary */
+ union {
+ char str[4080]; /* extra char array */
+ int arg[1020]; /* extra int array */
+ virDomainInfo dinfo; /* domain information */
+ virNodeInfo ninfo; /* node information */
+ } extra;
+};
+typedef struct _virProxyFullPacket virProxyFullPacket;
+typedef virProxyFullPacket *virProxyFullPacketPtr;
+
+/* xen_unified makes direct calls or indirect calls through here. */
+extern struct xenUnifiedDriver xenProxyDriver;
+extern int xenProxyInit (void);
+
+extern virDomainPtr xenProxyLookupByID(virConnectPtr conn, int id);
+extern virDomainPtr xenProxyLookupByUUID(virConnectPtr conn,
+ const unsigned char *uuid);
+extern virDomainPtr xenProxyLookupByName(virConnectPtr conn,
+ const char *domname);
+
+extern char * xenProxyDomainDumpXML(virDomainPtr domain,
+ int flags);
+extern int xenProxyListDomains(virConnectPtr conn, int *ids,
+ int maxids);
+#endif /* __LIBVIR_PROXY_H__ */
--- /dev/null
+/*
+ * sexpr.c : S-Expression routines to communicate with the Xen Daemon
+ *
+ * Copyright (C) 2005
+ *
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License. See the file COPYING.LIB in the main directory of this
+ * archive for more details.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "c-ctype.h"
+#include <errno.h>
+
+#include "virterror_internal.h"
+#include "sexpr.h"
+#include "util.h"
+#include "memory.h"
+
+#define VIR_FROM_THIS VIR_FROM_SEXPR
+
+#define virSexprError(code, fmt...) \
+ virReportErrorHelper(NULL, VIR_FROM_SEXPR, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
+/**
+ * sexpr_new:
+ *
+ * Create a new S-Expression
+ *
+ * Returns the new node or NULL in case of memory allocation error
+ */
+static struct sexpr *
+sexpr_new(void)
+{
+ struct sexpr *ret;
+
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError(NULL);
+ return (NULL);
+ }
+ ret->kind = SEXPR_NIL;
+ return ret;
+}
+
+/**
+ * sexpr_free:
+ * @sexpr: the S-Expression pointer
+ *
+ * Free an S-Expression
+ */
+void
+sexpr_free(struct sexpr *sexpr)
+{
+ int serrno = errno;
+
+ if (sexpr == NULL) {
+ return;
+ }
+
+ switch (sexpr->kind) {
+ case SEXPR_CONS:
+ sexpr_free(sexpr->u.s.car);
+ sexpr_free(sexpr->u.s.cdr);
+ break;
+ case SEXPR_VALUE:
+ VIR_FREE(sexpr->u.value);
+ break;
+ case SEXPR_NIL:
+ break;
+ }
+
+ VIR_FREE(sexpr);
+
+ errno = serrno;
+}
+
+/**
+ * sexpr_nil:
+ *
+ * Provide a NIL S-Expression (the pointer is not shared so NIL equality
+ * testing won't work at the pointer level).
+ *
+ * Returns a new NIL S-Expression of NULL in case of error.
+ */
+struct sexpr *
+sexpr_nil(void)
+{
+ return sexpr_new();
+}
+
+/**
+ * sexpr_string:
+ * @str: the input string, assumed to be UTF-8
+ * @len: the length in bytes of the input
+ *
+ * Parse the input S-Expression and return a pointer to the result
+ *
+ * Returns the S-Expression pointer or NULL in case of error
+ */
+struct sexpr *
+sexpr_string(const char *str, ssize_t len)
+{
+ struct sexpr *ret = sexpr_new();
+
+ if (ret == NULL)
+ return ret;
+ ret->kind = SEXPR_VALUE;
+ if (len > 0) {
+ ret->u.value = strndup(str, len);
+ } else {
+ ret->u.value = strdup(str);
+ }
+
+ if (ret->u.value == NULL) {
+ return NULL;
+ }
+
+ return ret;
+}
+
+/**
+ * sexpr_cons:
+ * @car: the left operand
+ * @cdr: the right operand
+ *
+ * Implement the CONS operation assembling 2 existing S-Expressions.
+ * Note that in case of error the input data are not freed.
+ *
+ * Returns the resulting S-Expression pointer or NULL in case of error.
+ */
+struct sexpr *
+sexpr_cons(const struct sexpr *car, const struct sexpr *cdr)
+{
+ struct sexpr *ret = sexpr_new();
+
+ if (ret == NULL)
+ return ret;
+ ret->kind = SEXPR_CONS;
+ ret->u.s.car = (struct sexpr *) car;
+ ret->u.s.cdr = (struct sexpr *) cdr;
+
+ return ret;
+}
+
+/**
+ * append:
+ * @lst: an existing list
+ * @value: the value
+ *
+ * Internal operation appending a value at the end of an existing list
+ */
+static int
+append(struct sexpr *lst, const struct sexpr *value)
+{
+ struct sexpr *nil = sexpr_nil();
+
+ if (nil == NULL)
+ return -1;
+
+ while (lst->kind != SEXPR_NIL) {
+ lst = lst->u.s.cdr;
+ }
+
+ lst->kind = SEXPR_CONS;
+ lst->u.s.car = (struct sexpr *) value;
+ lst->u.s.cdr = nil;
+
+ return 0;
+}
+
+/**
+ * @lst: an existing list
+ * @value: the value
+ *
+ * Append a value at the end of an existing list
+ *
+ * Returns lst or NULL in case of error
+ */
+struct sexpr *
+sexpr_append(struct sexpr *lst, const struct sexpr *value)
+{
+ if (lst == NULL)
+ return (NULL);
+ if (value == NULL)
+ return (lst);
+ if (append(lst, value) < 0)
+ return (NULL);
+ return (lst);
+}
+
+/**
+ * sexpr2string:
+ * @sexpr: an S-Expression pointer
+ * @buffer: the output buffer
+ * @n_buffer: the size of the buffer in bytes
+ *
+ * Serialize the S-Expression in the buffer.
+ * Note that the output may be truncated if @n_buffer is too small
+ * resulting in an unparseable value.
+ *
+ * Returns the number of bytes used by the serialization in the buffer or
+ * 0 in case of error.
+ */
+size_t
+sexpr2string(const struct sexpr * sexpr, char *buffer, size_t n_buffer)
+{
+ size_t ret = 0, tmp;
+
+ if ((sexpr == NULL) || (buffer == NULL) || (n_buffer <= 0))
+ return (0);
+
+ switch (sexpr->kind) {
+ case SEXPR_CONS:
+ tmp = snprintf(buffer + ret, n_buffer - ret, "(");
+ if (tmp == 0)
+ goto error;
+ ret += tmp;
+ tmp = sexpr2string(sexpr->u.s.car, buffer + ret, n_buffer - ret);
+ if (tmp == 0)
+ goto error;
+ ret += tmp;
+ while (sexpr->u.s.cdr->kind != SEXPR_NIL) {
+ sexpr = sexpr->u.s.cdr;
+ tmp = snprintf(buffer + ret, n_buffer - ret, " ");
+ if (tmp == 0)
+ goto error;
+ ret += tmp;
+ tmp =
+ sexpr2string(sexpr->u.s.car, buffer + ret, n_buffer - ret);
+ if (tmp == 0)
+ goto error;
+ ret += tmp;
+ }
+ tmp = snprintf(buffer + ret, n_buffer - ret, ")");
+ if (tmp == 0)
+ goto error;
+ ret += tmp;
+ break;
+ case SEXPR_VALUE:
+ if (strchr(sexpr->u.value, ' '))
+ tmp = snprintf(buffer + ret, n_buffer - ret, "'%s'",
+ sexpr->u.value);
+ else
+ tmp = snprintf(buffer + ret, n_buffer - ret, "%s",
+ sexpr->u.value);
+ if (tmp == 0)
+ goto error;
+ ret += tmp;
+ break;
+ case SEXPR_NIL:
+ tmp = snprintf(buffer + ret, n_buffer - ret, "()");
+ if (tmp == 0)
+ goto error;
+ ret += tmp;
+ break;
+ default:
+ goto error;
+ }
+
+ return (ret);
+ error:
+ buffer[n_buffer - 1] = 0;
+ virSexprError(VIR_ERR_SEXPR_SERIAL, "%s", buffer);
+ return (0);
+}
+
+#define IS_SPACE(c) ((c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA))
+
+static const char *
+trim(const char *string)
+{
+ while (IS_SPACE(*string))
+ string++;
+ return (string);
+}
+
+/**
+ * _string2sexpr:
+ * @buffer: a zero terminated buffer containing an S-Expression in UTF-8
+ * @end: pointer to an index in the buffer for the already parsed bytes
+ *
+ * Internal routine implementing the parse of S-Expression
+ * Note that failure in this function is catastrophic. If it returns
+ * NULL, you've leaked memory and you're currently OOM. It will always
+ * parse an SEXPR given a buffer
+ *
+ * Returns a pointer to the resulting parsed S-Expression, or NULL in case of
+ * hard error.
+ */
+static struct sexpr *
+_string2sexpr(const char *buffer, size_t * end)
+{
+ const char *ptr = buffer + *end;
+ struct sexpr *ret = sexpr_new();
+
+ if (ret == NULL)
+ return NULL;
+
+ ptr = trim(ptr);
+
+ if (ptr[0] == '(') {
+ ret->kind = SEXPR_NIL;
+
+ ptr = trim(ptr + 1);
+ while (*ptr && *ptr != ')') {
+ struct sexpr *tmp;
+ size_t tmp_len = 0;
+
+ tmp = _string2sexpr(ptr, &tmp_len);
+ if (tmp == NULL)
+ goto error;
+ if (append(ret, tmp) < 0) {
+ sexpr_free(tmp);
+ goto error;
+ }
+#if 0
+ if (0) {
+ char buf[4096];
+
+ sexpr2string(ret, buf, sizeof(buf));
+ printf("%s\n", buffer);
+ }
+#endif
+ ptr = trim(ptr + tmp_len);
+ }
+
+ if (*ptr == ')') {
+ ptr++;
+ }
+ } else {
+ const char *start;
+
+ if (*ptr == '\'') {
+ ptr++;
+ start = ptr;
+
+ while (*ptr && *ptr != '\'') {
+ if (*ptr == '\\' && ptr[1])
+ ptr++;
+ ptr++;
+ }
+
+ ret->u.value = strndup(start, ptr - start);
+ if (ret->u.value == NULL) {
+ virReportOOMError(NULL);
+ goto error;
+ }
+
+ if (*ptr == '\'')
+ ptr++;
+ } else {
+ start = ptr;
+
+ while (*ptr && !c_isspace(*ptr)
+ && *ptr != ')' && *ptr != '(') {
+ ptr++;
+ }
+
+ ret->u.value = strndup(start, ptr - start);
+ if (ret->u.value == NULL) {
+ virReportOOMError(NULL);
+ goto error;
+ }
+ }
+
+ ret->kind = SEXPR_VALUE;
+ if (ret->u.value == NULL)
+ goto error;
+ }
+
+ *end = ptr - buffer;
+
+ return ret;
+
+ error:
+ sexpr_free(ret);
+ return (NULL);
+}
+
+/**
+ * string2sexpr:
+ * @buffer: a zero terminated buffer containing an S-Expression in UTF-8
+ *
+ * Parse the S-Expression in the buffer.
+ * Note that failure in this function is catastrophic. If it returns
+ * NULL, you've leaked memory and you're currently OOM. It will always
+ * parse an SEXPR given a buffer
+ *
+ * Returns a pointer to the resulting parsed S-Expression, or NULL in case of
+ * hard error.
+ */
+struct sexpr *
+string2sexpr(const char *buffer)
+{
+ size_t dummy = 0;
+
+ return _string2sexpr(buffer, &dummy);
+}
+
+
+/**
+ * sexpr_lookup_key:
+ * @sexpr: a pointer to a parsed S-Expression
+ * @node: a path for the sub expression to lookup in the S-Expression
+ *
+ * Search a sub expression in the S-Expression based on its path
+ * Returns the key node, rather than the data node.
+ * NOTE: path are limited to 4096 bytes.
+ *
+ * Returns the pointer to the sub expression or NULL if not found.
+ */
+static struct sexpr *
+sexpr_lookup_key(const struct sexpr *sexpr, const char *node)
+{
+ char buffer[4096], *ptr, *token;
+
+ if ((node == NULL) || (sexpr == NULL))
+ return (NULL);
+
+ snprintf(buffer, sizeof(buffer), "%s", node);
+
+ ptr = buffer;
+ token = strsep(&ptr, "/");
+
+ if (sexpr->kind != SEXPR_CONS || sexpr->u.s.car->kind != SEXPR_VALUE) {
+ return NULL;
+ }
+
+ if (STRNEQ(sexpr->u.s.car->u.value, token)) {
+ return NULL;
+ }
+
+ for (token = strsep(&ptr, "/"); token; token = strsep(&ptr, "/")) {
+ const struct sexpr *i;
+
+ if (token == NULL)
+ continue;
+
+ sexpr = sexpr->u.s.cdr;
+ for (i = sexpr; i->kind != SEXPR_NIL; i = i->u.s.cdr) {
+ if (i->kind != SEXPR_CONS ||
+ i->u.s.car->kind != SEXPR_CONS ||
+ i->u.s.car->u.s.car->kind != SEXPR_VALUE) {
+ continue;
+ }
+
+ if (STREQ(i->u.s.car->u.s.car->u.value, token)) {
+ sexpr = i->u.s.car;
+ break;
+ }
+ }
+
+ if (i->kind == SEXPR_NIL) {
+ break;
+ }
+ }
+
+ if (token != NULL) {
+ return NULL;
+ }
+
+ return (struct sexpr *) sexpr;
+}
+
+/**
+ * sexpr_lookup:
+ * @sexpr: a pointer to a parsed S-Expression
+ * @node: a path for the sub expression to lookup in the S-Expression
+ *
+ * Search a sub expression in the S-Expression based on its path.
+ * NOTE: path are limited to 4096 bytes.
+ *
+ * Returns the pointer to the sub expression or NULL if not found.
+ */
+struct sexpr *
+sexpr_lookup(const struct sexpr *sexpr, const char *node)
+{
+ struct sexpr *s = sexpr_lookup_key(sexpr, node);
+
+ if (s == NULL)
+ return NULL;
+
+ if (s->kind != SEXPR_CONS || s->u.s.cdr->kind != SEXPR_CONS)
+ return NULL;
+
+ return s->u.s.cdr;
+}
+
+/**
+ * sexpr_has:
+ * @sexpr: a pointer to a parsed S-Expression
+ * @node: a path for the sub expression to lookup in the S-Expression
+ *
+ * Search a sub expression in the S-Expression based on its path.
+ * NOTE: path are limited to 4096 bytes.
+ * NB, even if the key was found sexpr_lookup may return NULL if
+ * the corresponding value was empty
+ *
+ * Returns true if the key was found, false otherwise
+ */
+int
+sexpr_has(const struct sexpr *sexpr, const char *node)
+{
+ struct sexpr *s = sexpr_lookup_key(sexpr, node);
+
+ if (s == NULL)
+ return 0;
+
+ if (s->kind != SEXPR_CONS)
+ return 0;
+
+ return 1;
+}
+
+/**
+ * sexpr_node:
+ * @sexpr: a pointer to a parsed S-Expression
+ * @node: a path for the node to lookup in the S-Expression
+ *
+ * Search a node value in the S-Expression based on its path
+ * NOTE: path are limited to 4096 bytes.
+ *
+ * Returns the value of the node or NULL if not found.
+ */
+const char *
+sexpr_node(const struct sexpr *sexpr, const char *node)
+{
+ struct sexpr *n = sexpr_lookup(sexpr, node);
+
+ return (n && n->u.s.car->kind == SEXPR_VALUE) ? n->u.s.car->u.value : NULL;
+}
+
+int sexpr_node_copy(const struct sexpr *sexpr, const char *node, char **dst)
+{
+ const char *val = sexpr_node(sexpr, node);
+
+ if (val) {
+ *dst = strdup(val);
+ if (!(*dst))
+ return -1;
+ } else {
+ *dst = NULL;
+ }
+ return 0;
+}
+
+
+/**
+ * sexpr_fmt_node:
+ * @sexpr: a pointer to a parsed S-Expression
+ * @fmt: a path for the node to lookup in the S-Expression
+ * @... extra data to build the path
+ *
+ * Search a node value in the S-Expression based on its path
+ * NOTE: path are limited to 4096 bytes.
+ *
+ * Returns the value of the node or NULL if not found.
+ */
+const char *
+sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...)
+{
+ va_list ap;
+ char node[4096];
+
+ va_start(ap, fmt);
+ vsnprintf(node, sizeof(node), fmt, ap);
+ va_end(ap);
+
+ return sexpr_node(sexpr, node);
+}
--- /dev/null
+/*
+ * sexpr.h : S-Expression interfaces needed to communicate with the Xen Daemon
+ *
+ * Copyright (C) 2005
+ *
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License. See the file COPYING.LIB in the main directory of this
+ * archive for more details.
+ */
+
+#ifndef _LIBVIR_SEXPR_H_
+#define _LIBVIR_SEXPR_H_
+
+#include "internal.h"
+
+#include <sys/types.h>
+
+enum sexpr_type {
+ SEXPR_NIL,
+ SEXPR_CONS,
+ SEXPR_VALUE,
+};
+
+struct sexpr {
+ enum sexpr_type kind;
+ union {
+ struct {
+ struct sexpr *car;
+ struct sexpr *cdr;
+ } s;
+ char *value;
+ } u;
+};
+
+/* conversion to/from strings */
+size_t sexpr2string(const struct sexpr *sexpr, char *buffer, size_t n_buffer);
+struct sexpr *string2sexpr(const char *buffer);
+
+/* constructors and destructors */
+struct sexpr *sexpr_nil(void);
+struct sexpr *sexpr_string(const char *str, ssize_t len);
+struct sexpr *sexpr_cons(const struct sexpr *car, const struct sexpr *cdr);
+struct sexpr *sexpr_append(struct sexpr *lst, const struct sexpr *item);
+void sexpr_free(struct sexpr *sexpr);
+
+/* lookup in S-Expressions */
+const char *sexpr_node(const struct sexpr *sexpr, const char *node);
+int sexpr_node_copy(const struct sexpr *sexpr, const char *node, char **dst);
+const char *sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...)
+ ATTRIBUTE_FMT_PRINTF(2,3);
+struct sexpr *sexpr_lookup(const struct sexpr *sexpr, const char *node);
+int sexpr_has(const struct sexpr *sexpr, const char *node);
+#endif
--- /dev/null
+/*
+ * xen_driver.c: Unified Xen driver.
+ *
+ * Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Richard W.M. Jones <rjones@redhat.com>
+ */
+
+#include <config.h>
+
+/* Note:
+ *
+ * This driver provides a unified interface to the five
+ * separate underlying Xen drivers (xen_internal, proxy_internal,
+ * xend_internal, xs_internal and xm_internal). Historically
+ * the body of libvirt.c handled the five Xen drivers,
+ * and contained Xen-specific code.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <xen/dom0_ops.h>
+#include <libxml/uri.h>
+
+#include "virterror_internal.h"
+#include "logging.h"
+#include "datatypes.h"
+#include "xen_driver.h"
+
+#include "xen_hypervisor.h"
+#include "proxy_internal.h"
+#include "xend_internal.h"
+#include "xs_internal.h"
+#include "xm_internal.h"
+#if WITH_XEN_INOTIFY
+#include "xen_inotify.h"
+#endif
+#include "xml.h"
+#include "util.h"
+#include "memory.h"
+#include "node_device_conf.h"
+#include "pci.h"
+
+#define VIR_FROM_THIS VIR_FROM_XEN
+
+static int
+xenUnifiedNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info);
+static int
+xenUnifiedDomainGetMaxVcpus (virDomainPtr dom);
+static int
+xenUnifiedDomainGetVcpus (virDomainPtr dom,
+ virVcpuInfoPtr info, int maxinfo,
+ unsigned char *cpumaps, int maplen);
+
+/* The five Xen drivers below us. */
+static struct xenUnifiedDriver const * const drivers[XEN_UNIFIED_NR_DRIVERS] = {
+ [XEN_UNIFIED_HYPERVISOR_OFFSET] = &xenHypervisorDriver,
+ [XEN_UNIFIED_PROXY_OFFSET] = &xenProxyDriver,
+ [XEN_UNIFIED_XEND_OFFSET] = &xenDaemonDriver,
+ [XEN_UNIFIED_XS_OFFSET] = &xenStoreDriver,
+ [XEN_UNIFIED_XM_OFFSET] = &xenXMDriver,
+#if WITH_XEN_INOTIFY
+ [XEN_UNIFIED_INOTIFY_OFFSET] = &xenInotifyDriver,
+#endif
+};
+
+static int inside_daemon;
+
+#define xenUnifiedError(conn, code, fmt...) \
+ virReportErrorHelper(conn, VIR_FROM_XEN, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
+/**
+ * xenNumaInit:
+ * @conn: pointer to the hypervisor connection
+ *
+ * Initializer for previous variables. We currently assume that
+ * the number of physical CPU and the number of NUMA cell is fixed
+ * until reboot which might be false in future Xen implementations.
+ */
+static void
+xenNumaInit(virConnectPtr conn) {
+ virNodeInfo nodeInfo;
+ xenUnifiedPrivatePtr priv;
+ int ret;
+
+ ret = xenUnifiedNodeGetInfo(conn, &nodeInfo);
+ if (ret < 0)
+ return;
+
+ priv = conn->privateData;
+
+ priv->nbNodeCells = nodeInfo.nodes;
+ priv->nbNodeCpus = nodeInfo.cpus;
+}
+
+
+/**
+ * xenDomainUsedCpus:
+ * @dom: the domain
+ *
+ * Analyze which set of CPUs are used by the domain and
+ * return a string providing the ranges.
+ *
+ * Returns the string which needs to be freed by the caller or
+ * NULL if the domain uses all CPU or in case of error.
+ */
+char *
+xenDomainUsedCpus(virDomainPtr dom)
+{
+ char *res = NULL;
+ int ncpus;
+ int nb_vcpu;
+ char *cpulist = NULL;
+ unsigned char *cpumap = NULL;
+ size_t cpumaplen;
+ int nb = 0;
+ int n, m;
+ virVcpuInfoPtr cpuinfo = NULL;
+ virNodeInfo nodeinfo;
+ xenUnifiedPrivatePtr priv;
+
+ if (!VIR_IS_CONNECTED_DOMAIN(dom))
+ return (NULL);
+
+ priv = dom->conn->privateData;
+
+ if (priv->nbNodeCpus <= 0)
+ return(NULL);
+ nb_vcpu = xenUnifiedDomainGetMaxVcpus(dom);
+ if (nb_vcpu <= 0)
+ return(NULL);
+ if (xenUnifiedNodeGetInfo(dom->conn, &nodeinfo) < 0)
+ return(NULL);
+
+ if (VIR_ALLOC_N(cpulist, priv->nbNodeCpus) < 0)
+ goto done;
+ if (VIR_ALLOC_N(cpuinfo, nb_vcpu) < 0)
+ goto done;
+ cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
+ if (xalloc_oversized(nb_vcpu, cpumaplen) ||
+ VIR_ALLOC_N(cpumap, nb_vcpu * cpumaplen) < 0)
+ goto done;
+
+ if ((ncpus = xenUnifiedDomainGetVcpus(dom, cpuinfo, nb_vcpu,
+ cpumap, cpumaplen)) >= 0) {
+ for (n = 0 ; n < ncpus ; n++) {
+ for (m = 0 ; m < priv->nbNodeCpus; m++) {
+ if ((cpulist[m] == 0) &&
+ (VIR_CPU_USABLE(cpumap, cpumaplen, n, m))) {
+ cpulist[m] = 1;
+ nb++;
+ /* if all CPU are used just return NULL */
+ if (nb == priv->nbNodeCpus)
+ goto done;
+
+ }
+ }
+ }
+ res = virDomainCpuSetFormat(dom->conn, cpulist, priv->nbNodeCpus);
+ }
+
+done:
+ VIR_FREE(cpulist);
+ VIR_FREE(cpumap);
+ VIR_FREE(cpuinfo);
+ return(res);
+}
+
+#ifdef WITH_LIBVIRTD
+
+static int
+xenInitialize (int privileged ATTRIBUTE_UNUSED)
+{
+ inside_daemon = 1;
+ return 0;
+}
+
+static virStateDriver state_driver = {
+ .initialize = xenInitialize,
+};
+
+#endif
+
+/*----- Dispatch functions. -----*/
+
+/* These dispatch functions follow the model used historically
+ * by libvirt.c -- trying each low-level Xen driver in turn
+ * until one succeeds. However since we know what low-level
+ * drivers can perform which functions, it is probably better
+ * in future to optimise these dispatch functions to just call
+ * the single function (or small number of appropriate functions)
+ * in the low level drivers directly.
+ */
+
+static int
+xenUnifiedProbe (void)
+{
+#ifdef __linux__
+ if (virFileExists("/proc/xen"))
+ return 1;
+#endif
+#ifdef __sun
+ FILE *fh;
+
+ if (fh = fopen("/dev/xen/domcaps", "r")) {
+ fclose(fh);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+static virDrvOpenStatus
+xenUnifiedOpen (virConnectPtr conn, virConnectAuthPtr auth, int flags)
+{
+ int i, ret = VIR_DRV_OPEN_DECLINED;
+ xenUnifiedPrivatePtr priv;
+ virDomainEventCallbackListPtr cbList;
+
+#ifdef __sun
+ /*
+ * Only the libvirtd instance can open this driver.
+ * Everything else falls back to the remote driver.
+ */
+ if (!inside_daemon)
+ return VIR_DRV_OPEN_DECLINED;
+#endif
+
+ if (conn->uri == NULL) {
+ if (!xenUnifiedProbe())
+ return VIR_DRV_OPEN_DECLINED;
+
+ conn->uri = xmlParseURI("xen:///");
+ if (!conn->uri) {
+ virReportOOMError (NULL);
+ return VIR_DRV_OPEN_ERROR;
+ }
+ } else {
+ if (conn->uri->scheme) {
+ /* Decline any scheme which isn't "xen://" or "http://". */
+ if (STRCASENEQ(conn->uri->scheme, "xen") &&
+ STRCASENEQ(conn->uri->scheme, "http"))
+ return VIR_DRV_OPEN_DECLINED;
+
+
+ /* Return an error if the path isn't '' or '/' */
+ if (conn->uri->path &&
+ STRNEQ(conn->uri->path, "") &&
+ STRNEQ(conn->uri->path, "/")) {
+ xenUnifiedError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected Xen URI path '%s', try xen:///"),
+ conn->uri->path);
+ return VIR_DRV_OPEN_ERROR;
+ }
+
+ /* Decline any xen:// URI with a server specified, allowing remote
+ * driver to handle, but keep any http:/// URIs */
+ if (STRCASEEQ(conn->uri->scheme, "xen") &&
+ conn->uri->server)
+ return VIR_DRV_OPEN_DECLINED;
+ } else {
+ /* Special case URI for Xen driver only:
+ *
+ * Treat a plain path as a Xen UNIX socket path, and give
+ * error unless path is absolute
+ */
+ if (!conn->uri->path || conn->uri->path[0] != '/') {
+ xenUnifiedError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected Xen URI path '%s', try ///var/lib/xen/xend-socket"),
+ NULLSTR(conn->uri->path));
+ return VIR_DRV_OPEN_ERROR;
+ }
+ }
+ }
+
+ /* We now know the URI is definitely for this driver, so beyond
+ * here, don't return DECLINED, always use ERROR */
+
+ /* Allocate per-connection private data. */
+ if (VIR_ALLOC(priv) < 0) {
+ virReportOOMError (NULL);
+ return VIR_DRV_OPEN_ERROR;
+ }
+ if (virMutexInit(&priv->lock) < 0) {
+ xenUnifiedError (NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot initialise mutex"));
+ VIR_FREE(priv);
+ return VIR_DRV_OPEN_ERROR;
+ }
+
+ /* Allocate callback list */
+ if (VIR_ALLOC(cbList) < 0) {
+ virReportOOMError (NULL);
+ virMutexDestroy(&priv->lock);
+ VIR_FREE(priv);
+ return VIR_DRV_OPEN_ERROR;
+ }
+ conn->privateData = priv;
+
+ priv->domainEventCallbacks = cbList;
+
+ priv->handle = -1;
+ priv->xendConfigVersion = -1;
+ priv->xshandle = NULL;
+ priv->proxy = -1;
+
+
+ /* Hypervisor is only run with privilege & required to succeed */
+ if (xenHavePrivilege()) {
+ DEBUG0("Trying hypervisor sub-driver");
+ if (drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->open(conn, auth, flags) ==
+ VIR_DRV_OPEN_SUCCESS) {
+ DEBUG0("Activated hypervisor sub-driver");
+ priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] = 1;
+ }
+ }
+
+ /* XenD is required to succeed if privileged.
+ * If it fails as non-root, then the proxy driver may take over
+ */
+ DEBUG0("Trying XenD sub-driver");
+ if (drivers[XEN_UNIFIED_XEND_OFFSET]->open(conn, auth, flags) ==
+ VIR_DRV_OPEN_SUCCESS) {
+ DEBUG0("Activated XenD sub-driver");
+ priv->opened[XEN_UNIFIED_XEND_OFFSET] = 1;
+
+ /* XenD is active, so try the xm & xs drivers too, both requird to
+ * succeed if root, optional otherwise */
+ if (priv->xendConfigVersion <= 2) {
+ DEBUG0("Trying XM sub-driver");
+ if (drivers[XEN_UNIFIED_XM_OFFSET]->open(conn, auth, flags) ==
+ VIR_DRV_OPEN_SUCCESS) {
+ DEBUG0("Activated XM sub-driver");
+ priv->opened[XEN_UNIFIED_XM_OFFSET] = 1;
+ }
+ }
+ DEBUG0("Trying XS sub-driver");
+ if (drivers[XEN_UNIFIED_XS_OFFSET]->open(conn, auth, flags) ==
+ VIR_DRV_OPEN_SUCCESS) {
+ DEBUG0("Activated XS sub-driver");
+ priv->opened[XEN_UNIFIED_XS_OFFSET] = 1;
+ } else {
+ if (xenHavePrivilege())
+ goto fail; /* XS is mandatory when privileged */
+ }
+ } else {
+ if (xenHavePrivilege()) {
+ goto fail; /* XenD is mandatory when privileged */
+ } else {
+#if WITH_PROXY
+ DEBUG0("Trying proxy sub-driver");
+ if (drivers[XEN_UNIFIED_PROXY_OFFSET]->open(conn, auth, flags) ==
+ VIR_DRV_OPEN_SUCCESS) {
+ DEBUG0("Activated proxy sub-driver");
+ priv->opened[XEN_UNIFIED_PROXY_OFFSET] = 1;
+ } else {
+ goto fail; /* Proxy is mandatory if XenD failed */
+ }
+#else
+ DEBUG0("Handing off for remote driver");
+ ret = VIR_DRV_OPEN_DECLINED; /* Let remote_driver try instead */
+ goto clean;
+#endif
+ }
+ }
+
+ xenNumaInit(conn);
+
+ if (!(priv->caps = xenHypervisorMakeCapabilities(conn))) {
+ DEBUG0("Failed to make capabilities");
+ goto fail;
+ }
+
+#if WITH_XEN_INOTIFY
+ if (xenHavePrivilege()) {
+ DEBUG0("Trying Xen inotify sub-driver");
+ if (drivers[XEN_UNIFIED_INOTIFY_OFFSET]->open(conn, auth, flags) ==
+ VIR_DRV_OPEN_SUCCESS) {
+ DEBUG0("Activated Xen inotify sub-driver");
+ priv->opened[XEN_UNIFIED_INOTIFY_OFFSET] = 1;
+ }
+ }
+#endif
+
+ return VIR_DRV_OPEN_SUCCESS;
+
+fail:
+ ret = VIR_DRV_OPEN_ERROR;
+#ifndef WITH_PROXY
+clean:
+#endif
+ DEBUG0("Failed to activate a mandatory sub-driver");
+ for (i = 0 ; i < XEN_UNIFIED_NR_DRIVERS ; i++)
+ if (priv->opened[i]) drivers[i]->close(conn);
+ virMutexDestroy(&priv->lock);
+ VIR_FREE(priv);
+ conn->privateData = NULL;
+ return ret;
+}
+
+#define GET_PRIVATE(conn) \
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) (conn)->privateData
+
+static int
+xenUnifiedClose (virConnectPtr conn)
+{
+ GET_PRIVATE(conn);
+ int i;
+
+ virCapabilitiesFree(priv->caps);
+ virDomainEventCallbackListFree(priv->domainEventCallbacks);
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] && drivers[i]->close)
+ (void) drivers[i]->close (conn);
+
+ virMutexDestroy(&priv->lock);
+ VIR_FREE(conn->privateData);
+
+ return 0;
+}
+
+
+#define HV_VERSION ((DOM0_INTERFACE_VERSION >> 24) * 1000000 + \
+ ((DOM0_INTERFACE_VERSION >> 16) & 0xFF) * 1000 + \
+ (DOM0_INTERFACE_VERSION & 0xFFFF))
+
+unsigned long xenUnifiedVersion(void)
+{
+ return HV_VERSION;
+}
+
+
+static const char *
+xenUnifiedType (virConnectPtr conn)
+{
+ GET_PRIVATE(conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i])
+ return "Xen";
+
+ return NULL;
+}
+
+/* Which features are supported by this driver? */
+static int
+xenUnifiedSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
+{
+ switch (feature) {
+ case VIR_DRV_FEATURE_MIGRATION_V1: return 1;
+ default: return 0;
+ }
+}
+
+static int
+xenUnifiedGetVersion (virConnectPtr conn, unsigned long *hvVer)
+{
+ GET_PRIVATE(conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] &&
+ drivers[i]->version &&
+ drivers[i]->version (conn, hvVer) == 0)
+ return 0;
+
+ return -1;
+}
+
+/* NB: Even if connected to the proxy, we're still on the
+ * same machine.
+ */
+static char *
+xenUnifiedGetHostname (virConnectPtr conn)
+{
+ char *result;
+
+ result = virGetHostname();
+ if (result == NULL) {
+ virReportSystemError(conn, errno,
+ "%s", _("cannot lookup hostname"));
+ return NULL;
+ }
+ /* Caller frees this string. */
+ return result;
+}
+
+static int
+xenUnifiedGetMaxVcpus (virConnectPtr conn, const char *type)
+{
+ GET_PRIVATE(conn);
+
+ if (type && STRCASENEQ (type, "Xen")) {
+ xenUnifiedError (conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return -1;
+ }
+
+ if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET])
+ return xenHypervisorGetMaxVcpus (conn, type);
+ else {
+ xenUnifiedError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+ }
+}
+
+static int
+xenUnifiedNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info)
+{
+ GET_PRIVATE(conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] &&
+ drivers[i]->nodeGetInfo &&
+ drivers[i]->nodeGetInfo (conn, info) == 0)
+ return 0;
+
+ return -1;
+}
+
+static char *
+xenUnifiedGetCapabilities (virConnectPtr conn)
+{
+ xenUnifiedPrivatePtr priv = conn->privateData;
+ char *xml;
+
+ if (!(xml = virCapabilitiesFormatXML(priv->caps))) {
+ virReportOOMError(conn);
+ return NULL;
+ }
+
+ return xml;
+}
+
+static int
+xenUnifiedListDomains (virConnectPtr conn, int *ids, int maxids)
+{
+ GET_PRIVATE(conn);
+ int ret;
+
+ /* Try xenstore. */
+ if (priv->opened[XEN_UNIFIED_XS_OFFSET]) {
+ ret = xenStoreListDomains (conn, ids, maxids);
+ if (ret >= 0) return ret;
+ }
+
+ /* Try HV. */
+ if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) {
+ ret = xenHypervisorListDomains (conn, ids, maxids);
+ if (ret >= 0) return ret;
+ }
+
+ /* Try xend. */
+ if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
+ ret = xenDaemonListDomains (conn, ids, maxids);
+ if (ret >= 0) return ret;
+ }
+
+ /* Try proxy. */
+ if (priv->opened[XEN_UNIFIED_PROXY_OFFSET]) {
+ ret = xenProxyListDomains (conn, ids, maxids);
+ if (ret >= 0) return ret;
+ }
+ return -1;
+}
+
+static int
+xenUnifiedNumOfDomains (virConnectPtr conn)
+{
+ GET_PRIVATE(conn);
+ int i, ret;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] && drivers[i]->numOfDomains) {
+ ret = drivers[i]->numOfDomains (conn);
+ if (ret >= 0) return ret;
+ }
+
+ return -1;
+}
+
+static virDomainPtr
+xenUnifiedDomainCreateXML (virConnectPtr conn,
+ const char *xmlDesc, unsigned int flags)
+{
+ GET_PRIVATE(conn);
+ int i;
+ virDomainPtr ret;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] && drivers[i]->domainCreateXML) {
+ ret = drivers[i]->domainCreateXML (conn, xmlDesc, flags);
+ if (ret) return ret;
+ }
+
+ return NULL;
+}
+
+/* Assumption made in underlying drivers:
+ * If the domain is "not found" and there is no other error, then
+ * the Lookup* functions return a NULL but do not set virterror.
+ */
+static virDomainPtr
+xenUnifiedDomainLookupByID (virConnectPtr conn, int id)
+{
+ GET_PRIVATE(conn);
+ virDomainPtr ret;
+
+ /* Reset any connection-level errors in virterror first, in case
+ * there is one hanging around from a previous call.
+ */
+ virConnResetLastError (conn);
+
+ /* Try hypervisor/xenstore combo. */
+ if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) {
+ ret = xenHypervisorLookupDomainByID (conn, id);
+ if (ret || conn->err.code != VIR_ERR_OK)
+ return ret;
+ }
+
+ /* Try proxy. */
+ if (priv->opened[XEN_UNIFIED_PROXY_OFFSET]) {
+ ret = xenProxyLookupByID (conn, id);
+ if (ret || conn->err.code != VIR_ERR_OK)
+ return ret;
+ }
+
+ /* Try xend. */
+ if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
+ ret = xenDaemonLookupByID (conn, id);
+ if (ret || conn->err.code != VIR_ERR_OK)
+ return ret;
+ }
+
+ /* Not found. */
+ xenUnifiedError (conn, VIR_ERR_NO_DOMAIN, __FUNCTION__);
+ return NULL;
+}
+
+static virDomainPtr
+xenUnifiedDomainLookupByUUID (virConnectPtr conn,
+ const unsigned char *uuid)
+{
+ GET_PRIVATE(conn);
+ virDomainPtr ret;
+
+ /* Reset any connection-level errors in virterror first, in case
+ * there is one hanging around from a previous call.
+ */
+ virConnResetLastError (conn);
+
+ /* Try hypervisor/xenstore combo. */
+ if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) {
+ ret = xenHypervisorLookupDomainByUUID (conn, uuid);
+ if (ret || conn->err.code != VIR_ERR_OK)
+ return ret;
+ }
+
+ /* Try proxy. */
+ if (priv->opened[XEN_UNIFIED_PROXY_OFFSET]) {
+ ret = xenProxyLookupByUUID (conn, uuid);
+ if (ret || conn->err.code != VIR_ERR_OK)
+ return ret;
+ }
+
+ /* Try xend. */
+ if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
+ ret = xenDaemonLookupByUUID (conn, uuid);
+ if (ret || conn->err.code != VIR_ERR_OK)
+ return ret;
+ }
+
+ /* Try XM for inactive domains. */
+ if (priv->opened[XEN_UNIFIED_XM_OFFSET]) {
+ ret = xenXMDomainLookupByUUID (conn, uuid);
+ if (ret || conn->err.code != VIR_ERR_OK)
+ return ret;
+ }
+
+ /* Not found. */
+ xenUnifiedError (conn, VIR_ERR_NO_DOMAIN, __FUNCTION__);
+ return NULL;
+}
+
+static virDomainPtr
+xenUnifiedDomainLookupByName (virConnectPtr conn,
+ const char *name)
+{
+ GET_PRIVATE(conn);
+ virDomainPtr ret;
+
+ /* Reset any connection-level errors in virterror first, in case
+ * there is one hanging around from a previous call.
+ */
+ virConnResetLastError (conn);
+
+ /* Try proxy. */
+ if (priv->opened[XEN_UNIFIED_PROXY_OFFSET]) {
+ ret = xenProxyLookupByName (conn, name);
+ if (ret || conn->err.code != VIR_ERR_OK)
+ return ret;
+ }
+
+ /* Try xend. */
+ if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
+ ret = xenDaemonLookupByName (conn, name);
+ if (ret || conn->err.code != VIR_ERR_OK)
+ return ret;
+ }
+
+ /* Try xenstore for inactive domains. */
+ if (priv->opened[XEN_UNIFIED_XS_OFFSET]) {
+ ret = xenStoreLookupByName (conn, name);
+ if (ret || conn->err.code != VIR_ERR_OK)
+ return ret;
+ }
+
+ /* Try XM for inactive domains. */
+ if (priv->opened[XEN_UNIFIED_XM_OFFSET]) {
+ ret = xenXMDomainLookupByName (conn, name);
+ if (ret || conn->err.code != VIR_ERR_OK)
+ return ret;
+ }
+
+ /* Not found. */
+ xenUnifiedError (conn, VIR_ERR_NO_DOMAIN, __FUNCTION__);
+ return NULL;
+}
+
+static int
+xenUnifiedDomainSuspend (virDomainPtr dom)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ /* Try non-hypervisor methods first, then hypervisor direct method
+ * as a last resort.
+ */
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (i != XEN_UNIFIED_HYPERVISOR_OFFSET &&
+ priv->opened[i] &&
+ drivers[i]->domainSuspend &&
+ drivers[i]->domainSuspend (dom) == 0)
+ return 0;
+
+ if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] &&
+ drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSuspend &&
+ drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSuspend (dom) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainResume (virDomainPtr dom)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ /* Try non-hypervisor methods first, then hypervisor direct method
+ * as a last resort.
+ */
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (i != XEN_UNIFIED_HYPERVISOR_OFFSET &&
+ priv->opened[i] &&
+ drivers[i]->domainResume &&
+ drivers[i]->domainResume (dom) == 0)
+ return 0;
+
+ if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] &&
+ drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainResume &&
+ drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainResume (dom) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainShutdown (virDomainPtr dom)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] &&
+ drivers[i]->domainShutdown &&
+ drivers[i]->domainShutdown (dom) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainReboot (virDomainPtr dom, unsigned int flags)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] &&
+ drivers[i]->domainReboot &&
+ drivers[i]->domainReboot (dom, flags) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainDestroy (virDomainPtr dom)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ /* Try non-hypervisor methods first, then hypervisor direct method
+ * as a last resort.
+ */
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (i != XEN_UNIFIED_HYPERVISOR_OFFSET &&
+ priv->opened[i] &&
+ drivers[i]->domainDestroy &&
+ drivers[i]->domainDestroy (dom) == 0)
+ return 0;
+
+ if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] &&
+ drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainDestroy &&
+ drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainDestroy (dom) == 0)
+ return 0;
+
+ return -1;
+}
+
+static char *
+xenUnifiedDomainGetOSType (virDomainPtr dom)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+ char *ret;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] && drivers[i]->domainGetOSType) {
+ ret = drivers[i]->domainGetOSType (dom);
+ if (ret) return ret;
+ }
+
+ return NULL;
+}
+
+static unsigned long
+xenUnifiedDomainGetMaxMemory (virDomainPtr dom)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+ unsigned long ret;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] && drivers[i]->domainGetMaxMemory) {
+ ret = drivers[i]->domainGetMaxMemory (dom);
+ if (ret != 0) return ret;
+ }
+
+ return 0;
+}
+
+static int
+xenUnifiedDomainSetMaxMemory (virDomainPtr dom, unsigned long memory)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ /* Prefer xend for setting max memory */
+ if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
+ if (xenDaemonDomainSetMaxMemory (dom, memory) == 0)
+ return 0;
+ }
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (i != XEN_UNIFIED_XEND_OFFSET &&
+ priv->opened[i] &&
+ drivers[i]->domainSetMaxMemory &&
+ drivers[i]->domainSetMaxMemory (dom, memory) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainSetMemory (virDomainPtr dom, unsigned long memory)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] &&
+ drivers[i]->domainSetMemory &&
+ drivers[i]->domainSetMemory (dom, memory) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] &&
+ drivers[i]->domainGetInfo &&
+ drivers[i]->domainGetInfo (dom, info) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainSave (virDomainPtr dom, const char *to)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] &&
+ drivers[i]->domainSave &&
+ drivers[i]->domainSave (dom, to) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainRestore (virConnectPtr conn, const char *from)
+{
+ GET_PRIVATE(conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] &&
+ drivers[i]->domainRestore &&
+ drivers[i]->domainRestore (conn, from) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainCoreDump (virDomainPtr dom, const char *to, int flags)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] &&
+ drivers[i]->domainCoreDump &&
+ drivers[i]->domainCoreDump (dom, to, flags) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ /* Try non-hypervisor methods first, then hypervisor direct method
+ * as a last resort.
+ */
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (i != XEN_UNIFIED_HYPERVISOR_OFFSET &&
+ priv->opened[i] &&
+ drivers[i]->domainSetVcpus &&
+ drivers[i]->domainSetVcpus (dom, nvcpus) == 0)
+ return 0;
+
+ if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] &&
+ drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSetVcpus &&
+ drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSetVcpus (dom, nvcpus) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainPinVcpu (virDomainPtr dom, unsigned int vcpu,
+ unsigned char *cpumap, int maplen)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] &&
+ drivers[i]->domainPinVcpu &&
+ drivers[i]->domainPinVcpu (dom, vcpu, cpumap, maplen) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainGetVcpus (virDomainPtr dom,
+ virVcpuInfoPtr info, int maxinfo,
+ unsigned char *cpumaps, int maplen)
+{
+ GET_PRIVATE(dom->conn);
+ int i, ret;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] && drivers[i]->domainGetVcpus) {
+ ret = drivers[i]->domainGetVcpus (dom, info, maxinfo, cpumaps, maplen);
+ if (ret > 0)
+ return ret;
+ }
+ return -1;
+}
+
+static int
+xenUnifiedDomainGetMaxVcpus (virDomainPtr dom)
+{
+ GET_PRIVATE(dom->conn);
+ int i, ret;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] && drivers[i]->domainGetMaxVcpus) {
+ ret = drivers[i]->domainGetMaxVcpus (dom);
+ if (ret != 0) return ret;
+ }
+
+ return -1;
+}
+
+static char *
+xenUnifiedDomainDumpXML (virDomainPtr dom, int flags)
+{
+ GET_PRIVATE(dom->conn);
+
+ if (dom->id == -1 && priv->xendConfigVersion < 3 ) {
+ if (priv->opened[XEN_UNIFIED_XM_OFFSET])
+ return xenXMDomainDumpXML(dom, flags);
+ } else {
+ if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
+ char *cpus, *res;
+ xenUnifiedLock(priv);
+ cpus = xenDomainUsedCpus(dom);
+ xenUnifiedUnlock(priv);
+ res = xenDaemonDomainDumpXML(dom, flags, cpus);
+ VIR_FREE(cpus);
+ return(res);
+ }
+ if (priv->opened[XEN_UNIFIED_PROXY_OFFSET])
+ return xenProxyDomainDumpXML(dom, flags);
+ }
+
+ xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return NULL;
+}
+
+
+static char *
+xenUnifiedDomainXMLFromNative(virConnectPtr conn,
+ const char *format,
+ const char *config,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ virDomainDefPtr def = NULL;
+ char *ret = NULL;
+ virConfPtr conf = NULL;
+ GET_PRIVATE(conn);
+
+ if (STRNEQ(format, XEN_CONFIG_FORMAT_XM) &&
+ STRNEQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
+ xenUnifiedError(conn, VIR_ERR_INVALID_ARG,
+ _("unsupported config type %s"), format);
+ return NULL;
+ }
+
+ if (STREQ(format, XEN_CONFIG_FORMAT_XM)) {
+ conf = virConfReadMem(config, strlen(config), 0);
+ if (!conf)
+ goto cleanup;
+
+ def = xenXMDomainConfigParse(conn, conf);
+ } else if (STREQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
+ def = xenDaemonParseSxprString(conn, config, priv->xendConfigVersion);
+ }
+ if (!def)
+ goto cleanup;
+
+ ret = virDomainDefFormat(conn, def, 0);
+
+cleanup:
+ virDomainDefFree(def);
+ return ret;
+}
+
+
+#define MAX_CONFIG_SIZE (1024 * 65)
+static char *
+xenUnifiedDomainXMLToNative(virConnectPtr conn,
+ const char *format,
+ const char *xmlData,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ virDomainDefPtr def = NULL;
+ char *ret = NULL;
+ virConfPtr conf = NULL;
+ GET_PRIVATE(conn);
+
+ if (STRNEQ(format, XEN_CONFIG_FORMAT_XM) &&
+ STRNEQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
+ xenUnifiedError(conn, VIR_ERR_INVALID_ARG,
+ _("unsupported config type %s"), format);
+ goto cleanup;
+ }
+
+ if (!(def = virDomainDefParseString(conn,
+ priv->caps,
+ xmlData,
+ 0)))
+ goto cleanup;
+
+ if (STREQ(format, XEN_CONFIG_FORMAT_XM)) {
+ int len = MAX_CONFIG_SIZE;
+ conf = xenXMDomainConfigFormat(conn, def);
+ if (!conf)
+ goto cleanup;
+
+ if (VIR_ALLOC_N(ret, len) < 0) {
+ virReportOOMError(conn);
+ goto cleanup;
+ }
+
+ if (virConfWriteMem(ret, &len, conf) < 0) {
+ VIR_FREE(ret);
+ goto cleanup;
+ }
+ } else if (STREQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
+ ret = xenDaemonFormatSxpr(conn, def, priv->xendConfigVersion);
+ }
+
+cleanup:
+ virDomainDefFree(def);
+ if (conf)
+ virConfFree(conf);
+ return ret;
+}
+
+
+static int
+xenUnifiedDomainMigratePrepare (virConnectPtr dconn,
+ char **cookie,
+ int *cookielen,
+ const char *uri_in,
+ char **uri_out,
+ unsigned long flags,
+ const char *dname,
+ unsigned long resource)
+{
+ GET_PRIVATE(dconn);
+
+ if (priv->opened[XEN_UNIFIED_XEND_OFFSET])
+ return xenDaemonDomainMigratePrepare (dconn, cookie, cookielen,
+ uri_in, uri_out,
+ flags, dname, resource);
+
+ xenUnifiedError (dconn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+static int
+xenUnifiedDomainMigratePerform (virDomainPtr dom,
+ const char *cookie,
+ int cookielen,
+ const char *uri,
+ unsigned long flags,
+ const char *dname,
+ unsigned long resource)
+{
+ GET_PRIVATE(dom->conn);
+
+ if (priv->opened[XEN_UNIFIED_XEND_OFFSET])
+ return xenDaemonDomainMigratePerform (dom, cookie, cookielen, uri,
+ flags, dname, resource);
+
+ xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+static virDomainPtr
+xenUnifiedDomainMigrateFinish (virConnectPtr dconn,
+ const char *dname,
+ const char *cookie ATTRIBUTE_UNUSED,
+ int cookielen ATTRIBUTE_UNUSED,
+ const char *uri ATTRIBUTE_UNUSED,
+ unsigned long flags ATTRIBUTE_UNUSED)
+{
+ return xenUnifiedDomainLookupByName (dconn, dname);
+}
+
+static int
+xenUnifiedListDefinedDomains (virConnectPtr conn, char **const names,
+ int maxnames)
+{
+ GET_PRIVATE(conn);
+ int i;
+ int ret;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] && drivers[i]->listDefinedDomains) {
+ ret = drivers[i]->listDefinedDomains (conn, names, maxnames);
+ if (ret >= 0) return ret;
+ }
+
+ return -1;
+}
+
+static int
+xenUnifiedNumOfDefinedDomains (virConnectPtr conn)
+{
+ GET_PRIVATE(conn);
+ int i;
+ int ret;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] && drivers[i]->numOfDefinedDomains) {
+ ret = drivers[i]->numOfDefinedDomains (conn);
+ if (ret >= 0) return ret;
+ }
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainCreate (virDomainPtr dom)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] && drivers[i]->domainCreate &&
+ drivers[i]->domainCreate (dom) == 0)
+ return 0;
+
+ return -1;
+}
+
+static virDomainPtr
+xenUnifiedDomainDefineXML (virConnectPtr conn, const char *xml)
+{
+ GET_PRIVATE(conn);
+ int i;
+ virDomainPtr ret;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] && drivers[i]->domainDefineXML) {
+ ret = drivers[i]->domainDefineXML (conn, xml);
+ if (ret) return ret;
+ }
+
+ return NULL;
+}
+
+static int
+xenUnifiedDomainUndefine (virDomainPtr dom)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] && drivers[i]->domainUndefine &&
+ drivers[i]->domainUndefine (dom) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainAttachDevice (virDomainPtr dom, const char *xml)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] && drivers[i]->domainAttachDevice &&
+ drivers[i]->domainAttachDevice (dom, xml) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainDetachDevice (virDomainPtr dom, const char *xml)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+ if (priv->opened[i] && drivers[i]->domainDetachDevice &&
+ drivers[i]->domainDetachDevice (dom, xml) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int
+xenUnifiedDomainGetAutostart (virDomainPtr dom, int *autostart)
+{
+ GET_PRIVATE(dom->conn);
+
+ if (priv->xendConfigVersion < 3) {
+ if (priv->opened[XEN_UNIFIED_XM_OFFSET])
+ return xenXMDomainGetAutostart(dom, autostart);
+ } else {
+ if (priv->opened[XEN_UNIFIED_XEND_OFFSET])
+ return xenDaemonDomainGetAutostart(dom, autostart);
+ }
+
+ xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+static int
+xenUnifiedDomainSetAutostart (virDomainPtr dom, int autostart)
+{
+ GET_PRIVATE(dom->conn);
+
+ if (priv->xendConfigVersion < 3) {
+ if (priv->opened[XEN_UNIFIED_XM_OFFSET])
+ return xenXMDomainSetAutostart(dom, autostart);
+ } else {
+ if (priv->opened[XEN_UNIFIED_XEND_OFFSET])
+ return xenDaemonDomainSetAutostart(dom, autostart);
+ }
+
+ xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+static char *
+xenUnifiedDomainGetSchedulerType (virDomainPtr dom, int *nparams)
+{
+ GET_PRIVATE(dom->conn);
+ int i;
+ char *schedulertype;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; i++) {
+ if (priv->opened[i] && drivers[i]->domainGetSchedulerType) {
+ schedulertype = drivers[i]->domainGetSchedulerType (dom, nparams);
+ if (schedulertype != NULL)
+ return(schedulertype);
+ }
+ }
+ return(NULL);
+}
+
+static int
+xenUnifiedDomainGetSchedulerParameters (virDomainPtr dom,
+ virSchedParameterPtr params, int *nparams)
+{
+ GET_PRIVATE(dom->conn);
+ int i, ret;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) {
+ if (priv->opened[i] && drivers[i]->domainGetSchedulerParameters) {
+ ret = drivers[i]->domainGetSchedulerParameters(dom, params, nparams);
+ if (ret == 0)
+ return(0);
+ }
+ }
+ return(-1);
+}
+
+static int
+xenUnifiedDomainSetSchedulerParameters (virDomainPtr dom,
+ virSchedParameterPtr params, int nparams)
+{
+ GET_PRIVATE(dom->conn);
+ int i, ret;
+
+ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) {
+ if (priv->opened[i] && drivers[i]->domainSetSchedulerParameters) {
+ ret = drivers[i]->domainSetSchedulerParameters(dom, params, nparams);
+ if (ret == 0)
+ return 0;
+ }
+ }
+
+ return(-1);
+}
+
+static int
+xenUnifiedDomainBlockStats (virDomainPtr dom, const char *path,
+ struct _virDomainBlockStats *stats)
+{
+ GET_PRIVATE (dom->conn);
+
+ if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET])
+ return xenHypervisorDomainBlockStats (dom, path, stats);
+
+ xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+static int
+xenUnifiedDomainInterfaceStats (virDomainPtr dom, const char *path,
+ struct _virDomainInterfaceStats *stats)
+{
+ GET_PRIVATE (dom->conn);
+
+ if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET])
+ return xenHypervisorDomainInterfaceStats (dom, path, stats);
+
+ xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+static int
+xenUnifiedDomainBlockPeek (virDomainPtr dom, const char *path,
+ unsigned long long offset, size_t size,
+ void *buffer, unsigned int flags ATTRIBUTE_UNUSED)
+{
+ int r;
+ GET_PRIVATE (dom->conn);
+
+ if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
+ r = xenDaemonDomainBlockPeek (dom, path, offset, size, buffer);
+ if (r != -2) return r;
+ /* r == -2 means declined, so fall through to XM driver ... */
+ }
+
+ if (priv->opened[XEN_UNIFIED_XM_OFFSET]) {
+ if (xenXMDomainBlockPeek (dom, path, offset, size, buffer) == 0)
+ return 0;
+ }
+
+ xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+static int
+xenUnifiedNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems,
+ int startCell, int maxCells)
+{
+ GET_PRIVATE (conn);
+
+ if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET])
+ return xenHypervisorNodeGetCellsFreeMemory (conn, freeMems,
+ startCell, maxCells);
+
+ xenUnifiedError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+static unsigned long long
+xenUnifiedNodeGetFreeMemory (virConnectPtr conn)
+{
+ unsigned long long freeMem = 0;
+ int ret;
+ GET_PRIVATE (conn);
+
+ if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) {
+ ret = xenHypervisorNodeGetCellsFreeMemory (conn, &freeMem,
+ -1, 1);
+ if (ret != 1)
+ return (0);
+ return(freeMem);
+ }
+
+ xenUnifiedError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return(0);
+}
+
+static int
+xenUnifiedDomainEventRegister (virConnectPtr conn,
+ virConnectDomainEventCallback callback,
+ void *opaque,
+ void (*freefunc)(void *))
+{
+ GET_PRIVATE (conn);
+
+ int ret;
+ xenUnifiedLock(priv);
+
+ if (priv->xsWatch == -1) {
+ xenUnifiedError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ xenUnifiedUnlock(priv);
+ return -1;
+ }
+
+ ret = virDomainEventCallbackListAdd(conn, priv->domainEventCallbacks,
+ callback, opaque, freefunc);
+
+ if (ret == 0)
+ conn->refs++;
+
+ xenUnifiedUnlock(priv);
+ return (ret);
+}
+
+static int
+xenUnifiedDomainEventDeregister (virConnectPtr conn,
+ virConnectDomainEventCallback callback)
+{
+ int ret;
+ GET_PRIVATE (conn);
+ xenUnifiedLock(priv);
+
+ if (priv->xsWatch == -1) {
+ xenUnifiedError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ xenUnifiedUnlock(priv);
+ return -1;
+ }
+
+ if (priv->domainEventDispatching)
+ ret = virDomainEventCallbackListMarkDelete(conn, priv->domainEventCallbacks,
+ callback);
+ else
+ ret = virDomainEventCallbackListRemove(conn, priv->domainEventCallbacks,
+ callback);
+
+ if (ret == 0)
+ virUnrefConnect(conn);
+
+ xenUnifiedUnlock(priv);
+ return ret;
+}
+
+
+static int
+xenUnifiedNodeDeviceGetPciInfo (virNodeDevicePtr dev,
+ unsigned *domain,
+ unsigned *bus,
+ unsigned *slot,
+ unsigned *function)
+{
+ virNodeDeviceDefPtr def = NULL;
+ virNodeDevCapsDefPtr cap;
+ char *xml = NULL;
+ int ret = -1;
+
+ xml = virNodeDeviceGetXMLDesc(dev, 0);
+ if (!xml)
+ goto out;
+
+ def = virNodeDeviceDefParseString(dev->conn, xml, EXISTING_DEVICE);
+ if (!def)
+ goto out;
+
+ cap = def->caps;
+ while (cap) {
+ if (cap->type == VIR_NODE_DEV_CAP_PCI_DEV) {
+ *domain = cap->data.pci_dev.domain;
+ *bus = cap->data.pci_dev.bus;
+ *slot = cap->data.pci_dev.slot;
+ *function = cap->data.pci_dev.function;
+ break;
+ }
+
+ cap = cap->next;
+ }
+
+ if (!cap) {
+ xenUnifiedError(dev->conn, VIR_ERR_INVALID_ARG,
+ _("device %s is not a PCI device"), dev->name);
+ goto out;
+ }
+
+ ret = 0;
+out:
+ virNodeDeviceDefFree(def);
+ VIR_FREE(xml);
+ return ret;
+}
+
+static int
+xenUnifiedNodeDeviceDettach (virNodeDevicePtr dev)
+{
+ pciDevice *pci;
+ unsigned domain, bus, slot, function;
+ int ret = -1;
+
+ if (xenUnifiedNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
+ return -1;
+
+ pci = pciGetDevice(dev->conn, domain, bus, slot, function);
+ if (!pci)
+ return -1;
+
+ if (pciDettachDevice(dev->conn, pci) < 0)
+ goto out;
+
+ ret = 0;
+out:
+ pciFreeDevice(dev->conn, pci);
+ return ret;
+}
+
+static int
+xenUnifiedNodeDeviceReAttach (virNodeDevicePtr dev)
+{
+ pciDevice *pci;
+ unsigned domain, bus, slot, function;
+ int ret = -1;
+
+ if (xenUnifiedNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
+ return -1;
+
+ pci = pciGetDevice(dev->conn, domain, bus, slot, function);
+ if (!pci)
+ return -1;
+
+ if (pciReAttachDevice(dev->conn, pci) < 0)
+ goto out;
+
+ ret = 0;
+out:
+ pciFreeDevice(dev->conn, pci);
+ return ret;
+}
+
+static int
+xenUnifiedNodeDeviceReset (virNodeDevicePtr dev)
+{
+ pciDevice *pci;
+ unsigned domain, bus, slot, function;
+ int ret = -1;
+
+ if (xenUnifiedNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
+ return -1;
+
+ pci = pciGetDevice(dev->conn, domain, bus, slot, function);
+ if (!pci)
+ return -1;
+
+ if (pciResetDevice(dev->conn, pci, NULL) < 0)
+ goto out;
+
+ ret = 0;
+out:
+ pciFreeDevice(dev->conn, pci);
+ return ret;
+}
+
+
+/*----- Register with libvirt.c, and initialise Xen drivers. -----*/
+
+/* The interface which we export upwards to libvirt.c. */
+static virDriver xenUnifiedDriver = {
+ VIR_DRV_XEN_UNIFIED,
+ "Xen",
+ xenUnifiedOpen, /* open */
+ xenUnifiedClose, /* close */
+ xenUnifiedSupportsFeature, /* supports_feature */
+ xenUnifiedType, /* type */
+ xenUnifiedGetVersion, /* version */
+ xenUnifiedGetHostname, /* getHostname */
+ xenUnifiedGetMaxVcpus, /* getMaxVcpus */
+ xenUnifiedNodeGetInfo, /* nodeGetInfo */
+ xenUnifiedGetCapabilities, /* getCapabilities */
+ xenUnifiedListDomains, /* listDomains */
+ xenUnifiedNumOfDomains, /* numOfDomains */
+ xenUnifiedDomainCreateXML, /* domainCreateXML */
+ xenUnifiedDomainLookupByID, /* domainLookupByID */
+ xenUnifiedDomainLookupByUUID, /* domainLookupByUUID */
+ xenUnifiedDomainLookupByName, /* domainLookupByName */
+ xenUnifiedDomainSuspend, /* domainSuspend */
+ xenUnifiedDomainResume, /* domainResume */
+ xenUnifiedDomainShutdown, /* domainShutdown */
+ xenUnifiedDomainReboot, /* domainReboot */
+ xenUnifiedDomainDestroy, /* domainDestroy */
+ xenUnifiedDomainGetOSType, /* domainGetOSType */
+ xenUnifiedDomainGetMaxMemory, /* domainGetMaxMemory */
+ xenUnifiedDomainSetMaxMemory, /* domainSetMaxMemory */
+ xenUnifiedDomainSetMemory, /* domainSetMemory */
+ xenUnifiedDomainGetInfo, /* domainGetInfo */
+ xenUnifiedDomainSave, /* domainSave */
+ xenUnifiedDomainRestore, /* domainRestore */
+ xenUnifiedDomainCoreDump, /* domainCoreDump */
+ xenUnifiedDomainSetVcpus, /* domainSetVcpus */
+ xenUnifiedDomainPinVcpu, /* domainPinVcpu */
+ xenUnifiedDomainGetVcpus, /* domainGetVcpus */
+ xenUnifiedDomainGetMaxVcpus, /* domainGetMaxVcpus */
+ NULL, /* domainGetSecurityLabel */
+ NULL, /* nodeGetSecurityModel */
+ xenUnifiedDomainDumpXML, /* domainDumpXML */
+ xenUnifiedDomainXMLFromNative, /* domainXmlFromNative */
+ xenUnifiedDomainXMLToNative, /* domainXmlToNative */
+ xenUnifiedListDefinedDomains, /* listDefinedDomains */
+ xenUnifiedNumOfDefinedDomains, /* numOfDefinedDomains */
+ xenUnifiedDomainCreate, /* domainCreate */
+ xenUnifiedDomainDefineXML, /* domainDefineXML */
+ xenUnifiedDomainUndefine, /* domainUndefine */
+ xenUnifiedDomainAttachDevice, /* domainAttachDevice */
+ xenUnifiedDomainDetachDevice, /* domainDetachDevice */
+ xenUnifiedDomainGetAutostart, /* domainGetAutostart */
+ xenUnifiedDomainSetAutostart, /* domainSetAutostart */
+ xenUnifiedDomainGetSchedulerType, /* domainGetSchedulerType */
+ xenUnifiedDomainGetSchedulerParameters, /* domainGetSchedulerParameters */
+ xenUnifiedDomainSetSchedulerParameters, /* domainSetSchedulerParameters */
+ xenUnifiedDomainMigratePrepare, /* domainMigratePrepare */
+ xenUnifiedDomainMigratePerform, /* domainMigratePerform */
+ xenUnifiedDomainMigrateFinish, /* domainMigrateFinish */
+ xenUnifiedDomainBlockStats, /* domainBlockStats */
+ xenUnifiedDomainInterfaceStats, /* domainInterfaceStats */
+ xenUnifiedDomainBlockPeek, /* domainBlockPeek */
+ NULL, /* domainMemoryPeek */
+ xenUnifiedNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
+ xenUnifiedNodeGetFreeMemory, /* getFreeMemory */
+ xenUnifiedDomainEventRegister, /* domainEventRegister */
+ xenUnifiedDomainEventDeregister, /* domainEventDeregister */
+ NULL, /* domainMigratePrepare2 */
+ NULL, /* domainMigrateFinish2 */
+ xenUnifiedNodeDeviceDettach, /* nodeDeviceDettach */
+ xenUnifiedNodeDeviceReAttach, /* nodeDeviceReAttach */
+ xenUnifiedNodeDeviceReset, /* nodeDeviceReset */
+};
+
+/**
+ * xenRegister:
+ *
+ * Register xen related drivers
+ *
+ * Returns the driver priority or -1 in case of error.
+ */
+int
+xenRegister (void)
+{
+ /* Ignore failures here. */
+ (void) xenHypervisorInit ();
+
+#ifdef WITH_LIBVIRTD
+ if (virRegisterStateDriver (&state_driver) == -1) return -1;
+#endif
+
+ return virRegisterDriver (&xenUnifiedDriver);
+}
+
+/**
+ * xenUnifiedDomainInfoListFree:
+ *
+ * Free the Domain Info List
+ */
+void
+xenUnifiedDomainInfoListFree(xenUnifiedDomainInfoListPtr list)
+{
+ int i;
+
+ if (list == NULL)
+ return;
+
+ for (i=0; i<list->count; i++) {
+ VIR_FREE(list->doms[i]->name);
+ VIR_FREE(list->doms[i]);
+ }
+ VIR_FREE(list);
+}
+
+/**
+ * xenUnifiedAddDomainInfo:
+ *
+ * Add name and uuid to the domain info list
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+int
+xenUnifiedAddDomainInfo(xenUnifiedDomainInfoListPtr list,
+ int id, char *name,
+ unsigned char *uuid)
+{
+ xenUnifiedDomainInfoPtr info;
+ int n;
+
+ /* check if we already have this callback on our list */
+ for (n=0; n < list->count; n++) {
+ if (STREQ(list->doms[n]->name, name) &&
+ !memcmp(list->doms[n]->uuid, uuid, VIR_UUID_BUFLEN)) {
+ DEBUG0("WARNING: dom already tracked");
+ return -1;
+ }
+ }
+
+ if (VIR_ALLOC(info) < 0)
+ goto memory_error;
+ if (!(info->name = strdup(name)))
+ goto memory_error;
+
+ memcpy(info->uuid, uuid, VIR_UUID_BUFLEN);
+ info->id = id;
+
+ /* Make space on list */
+ n = list->count;
+ if (VIR_REALLOC_N(list->doms, n + 1) < 0) {
+ goto memory_error;
+ }
+
+ list->doms[n] = info;
+ list->count++;
+ return 0;
+memory_error:
+ virReportOOMError (NULL);
+ if (info)
+ VIR_FREE(info->name);
+ VIR_FREE(info);
+ return -1;
+}
+
+/**
+ * xenUnifiedRemoveDomainInfo:
+ *
+ * Removes name and uuid to the domain info list
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+int
+xenUnifiedRemoveDomainInfo(xenUnifiedDomainInfoListPtr list,
+ int id, char *name,
+ unsigned char *uuid)
+{
+ int i;
+ for (i = 0 ; i < list->count ; i++) {
+ if( list->doms[i]->id == id &&
+ STREQ(list->doms[i]->name, name) &&
+ !memcmp(list->doms[i]->uuid, uuid, VIR_UUID_BUFLEN)) {
+
+ VIR_FREE(list->doms[i]->name);
+ VIR_FREE(list->doms[i]);
+
+ if (i < (list->count - 1))
+ memmove(list->doms + i,
+ list->doms + i + 1,
+ sizeof(*(list->doms)) *
+ (list->count - (i + 1)));
+
+ if (VIR_REALLOC_N(list->doms,
+ list->count - 1) < 0) {
+ ; /* Failure to reduce memory allocation isn't fatal */
+ }
+ list->count--;
+
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static void
+xenUnifiedDomainEventDispatchFunc(virConnectPtr conn,
+ virDomainEventPtr event,
+ virConnectDomainEventCallback cb,
+ void *cbopaque,
+ void *opaque)
+{
+ xenUnifiedPrivatePtr priv = opaque;
+
+ /*
+ * Release the lock while the callback is running so that
+ * we're re-entrant safe for callback work - the callback
+ * may want to invoke other virt functions & we have already
+ * protected the one piece of state we have - the callback
+ * list
+ */
+ xenUnifiedUnlock(priv);
+ virDomainEventDispatchDefaultFunc(conn, event, cb, cbopaque, NULL);
+ xenUnifiedLock(priv);
+}
+
+/**
+ * xenUnifiedDomainEventDispatch:
+ * @priv: the connection to dispatch events on
+ * @event: the event to dispatch
+ *
+ * Dispatch domain events to registered callbacks
+ *
+ * The caller must hold the lock in 'priv' before invoking
+ *
+ */
+void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
+ virDomainEventPtr event)
+{
+ if (!priv)
+ return;
+
+ priv->domainEventDispatching = 1;
+
+ if (priv->domainEventCallbacks) {
+ virDomainEventDispatch(event,
+ priv->domainEventCallbacks,
+ xenUnifiedDomainEventDispatchFunc,
+ priv);
+
+ /* Purge any deleted callbacks */
+ virDomainEventCallbackListPurgeMarked(priv->domainEventCallbacks);
+ }
+
+ virDomainEventFree(event);
+
+ priv->domainEventDispatching = 0;
+}
+
+void xenUnifiedLock(xenUnifiedPrivatePtr priv)
+{
+ virMutexLock(&priv->lock);
+}
+
+void xenUnifiedUnlock(xenUnifiedPrivatePtr priv)
+{
+ virMutexUnlock(&priv->lock);
+}
--- /dev/null
+/*
+ * xen_unified.c: Unified Xen driver.
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Richard W.M. Jones <rjones@redhat.com>
+ */
+
+#ifndef __VIR_XEN_UNIFIED_H__
+#define __VIR_XEN_UNIFIED_H__
+
+#include "internal.h"
+#include "capabilities.h"
+#include "driver.h"
+#include "domain_conf.h"
+#include "xs_internal.h"
+#if WITH_XEN_INOTIFY
+#include "xen_inotify.h"
+#endif
+#include "domain_event.h"
+#include "hash.h"
+
+#ifndef HAVE_WINSOCK2_H
+#include <sys/un.h>
+#include <netinet/in.h>
+#else
+#include <winsock2.h>
+#endif
+
+extern int xenRegister (void);
+
+#define XEN_UNIFIED_HYPERVISOR_OFFSET 0
+#define XEN_UNIFIED_PROXY_OFFSET 1
+#define XEN_UNIFIED_XEND_OFFSET 2
+#define XEN_UNIFIED_XS_OFFSET 3
+#define XEN_UNIFIED_XM_OFFSET 4
+
+#if WITH_XEN_INOTIFY
+#define XEN_UNIFIED_INOTIFY_OFFSET 5
+#define XEN_UNIFIED_NR_DRIVERS 6
+#else
+#define XEN_UNIFIED_NR_DRIVERS 5
+#endif
+
+#define MIN_XEN_GUEST_SIZE 64 /* 64 megabytes */
+
+#define XEN_CONFIG_FORMAT_XM "xen-xm"
+#define XEN_CONFIG_FORMAT_SEXPR "xen-sxpr"
+
+/* _xenUnifiedDriver:
+ *
+ * Entry points into the underlying Xen drivers. This structure
+ * will eventually go away and instead xen unified will make direct
+ * calls to the underlying Xen drivers.
+ *
+ * To reiterate - the goal is to remove elements from this structure
+ * until it is empty, replacing indirect calls through this
+ * structure with direct calls in xen_unified.c.
+ */
+struct xenUnifiedDriver {
+ virDrvOpen open;
+ virDrvClose close;
+ virDrvGetVersion version;
+ virDrvGetHostname getHostname;
+ virDrvNodeGetInfo nodeGetInfo;
+ virDrvGetCapabilities getCapabilities;
+ virDrvListDomains listDomains;
+ virDrvNumOfDomains numOfDomains;
+ virDrvDomainCreateXML domainCreateXML;
+ virDrvDomainSuspend domainSuspend;
+ virDrvDomainResume domainResume;
+ virDrvDomainShutdown domainShutdown;
+ virDrvDomainReboot domainReboot;
+ virDrvDomainDestroy domainDestroy;
+ virDrvDomainGetOSType domainGetOSType;
+ virDrvDomainGetMaxMemory domainGetMaxMemory;
+ virDrvDomainSetMaxMemory domainSetMaxMemory;
+ virDrvDomainSetMemory domainSetMemory;
+ virDrvDomainGetInfo domainGetInfo;
+ virDrvDomainSave domainSave;
+ virDrvDomainRestore domainRestore;
+ virDrvDomainCoreDump domainCoreDump;
+ virDrvDomainSetVcpus domainSetVcpus;
+ virDrvDomainPinVcpu domainPinVcpu;
+ virDrvDomainGetVcpus domainGetVcpus;
+ virDrvDomainGetMaxVcpus domainGetMaxVcpus;
+ virDrvListDefinedDomains listDefinedDomains;
+ virDrvNumOfDefinedDomains numOfDefinedDomains;
+ virDrvDomainCreate domainCreate;
+ virDrvDomainDefineXML domainDefineXML;
+ virDrvDomainUndefine domainUndefine;
+ virDrvDomainAttachDevice domainAttachDevice;
+ virDrvDomainDetachDevice domainDetachDevice;
+ virDrvDomainGetAutostart domainGetAutostart;
+ virDrvDomainSetAutostart domainSetAutostart;
+ virDrvDomainGetSchedulerType domainGetSchedulerType;
+ virDrvDomainGetSchedulerParameters domainGetSchedulerParameters;
+ virDrvDomainSetSchedulerParameters domainSetSchedulerParameters;
+};
+
+typedef struct xenXMConfCache *xenXMConfCachePtr;
+typedef struct xenXMConfCache {
+ time_t refreshedAt;
+ char filename[PATH_MAX];
+ virDomainDefPtr def;
+} xenXMConfCache;
+
+/* xenUnifiedDomainInfoPtr:
+ * The minimal state we have about active domains
+ * This is the minmal info necessary to still get a
+ * virDomainPtr when the domain goes away
+ */
+struct _xenUnifiedDomainInfo {
+ int id;
+ char *name;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+};
+typedef struct _xenUnifiedDomainInfo xenUnifiedDomainInfo;
+typedef xenUnifiedDomainInfo *xenUnifiedDomainInfoPtr;
+
+struct _xenUnifiedDomainInfoList {
+ unsigned int count;
+ xenUnifiedDomainInfoPtr *doms;
+};
+typedef struct _xenUnifiedDomainInfoList xenUnifiedDomainInfoList;
+typedef xenUnifiedDomainInfoList *xenUnifiedDomainInfoListPtr;
+
+/* xenUnifiedPrivatePtr:
+ *
+ * Per-connection private data, stored in conn->privateData. All Xen
+ * low-level drivers access parts of this structure.
+ */
+struct _xenUnifiedPrivate {
+ virMutex lock;
+
+ /* These initial vars are initialized in Open method
+ * and readonly thereafter, so can be used without
+ * holding the lock
+ */
+ virCapsPtr caps;
+ int handle; /* Xen hypervisor handle */
+
+ int xendConfigVersion; /* XenD config version */
+
+ /* connection to xend */
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ int addrfamily;
+ int addrprotocol;
+
+ /* Keep track of the drivers which opened. We keep a yes/no flag
+ * here for each driver, corresponding to the array drivers in
+ * xen_unified.c.
+ */
+ int opened[XEN_UNIFIED_NR_DRIVERS];
+
+
+ /*
+ * Everything from this point onwards must be protected
+ * by the lock when used
+ */
+
+ struct xs_handle *xshandle; /* handle to talk to the xenstore */
+
+ int proxy; /* fd of proxy. */
+
+
+ /* A list of xenstore watches */
+ xenStoreWatchListPtr xsWatchList;
+ int xsWatch;
+ /* A list of active domain name/uuids */
+ xenUnifiedDomainInfoListPtr activeDomainList;
+
+ /* NUMA topology info cache */
+ int nbNodeCells;
+ int nbNodeCpus;
+
+ /* An list of callbacks */
+ virDomainEventCallbackListPtr domainEventCallbacks;
+ int domainEventDispatching;
+
+ /* Location of config files, either /etc
+ * or /var/lib/xen */
+ const char *configDir;
+
+#if WITH_XEN_INOTIFY
+ /* The inotify fd */
+ int inotifyFD;
+ int inotifyWatch;
+
+ int useXenConfigCache ;
+ xenUnifiedDomainInfoListPtr configInfoList;
+#endif
+
+ /* For the 'xm' driver */
+ /* Primary config file name -> virDomainDef map */
+ virHashTablePtr configCache;
+ /* Domain name to config file name */
+ virHashTablePtr nameConfigMap;
+ /* So we don't refresh too often */
+ time_t lastRefresh;
+};
+
+typedef struct _xenUnifiedPrivate *xenUnifiedPrivatePtr;
+
+char *xenDomainUsedCpus(virDomainPtr dom);
+
+void xenUnifiedDomainInfoListFree(xenUnifiedDomainInfoListPtr info);
+int xenUnifiedAddDomainInfo(xenUnifiedDomainInfoListPtr info,
+ int id, char *name,
+ unsigned char *uuid);
+int xenUnifiedRemoveDomainInfo(xenUnifiedDomainInfoListPtr info,
+ int id, char *name,
+ unsigned char *uuid);
+void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
+ virDomainEventPtr event);
+unsigned long xenUnifiedVersion(void);
+
+#ifndef PROXY
+void xenUnifiedLock(xenUnifiedPrivatePtr priv);
+void xenUnifiedUnlock(xenUnifiedPrivatePtr priv);
+#else
+#define xenUnifiedLock(p) do {} while(0)
+#define xenUnifiedUnlock(p) do {} while(0)
+#endif
+
+#endif /* __VIR_XEN_UNIFIED_H__ */
--- /dev/null
+/*
+ * xen_internal.c: direct access to Xen hypervisor level
+ *
+ * Copyright (C) 2005, 2006, 2007, 2008, 2009 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+/* required for uint8_t, uint32_t, etc ... */
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <limits.h>
+#include <stdint.h>
+#include <regex.h>
+#include <errno.h>
+#include <sys/utsname.h>
+
+#ifdef __sun
+#include <sys/systeminfo.h>
+
+#include <priv.h>
+
+#ifndef PRIV_XVM_CONTROL
+#define PRIV_XVM_CONTROL ((const char *)"xvm_control")
+#endif
+
+#endif /* __sun */
+
+/* required for dom0_getdomaininfo_t */
+#include <xen/dom0_ops.h>
+#include <xen/version.h>
+#ifdef HAVE_XEN_LINUX_PRIVCMD_H
+#include <xen/linux/privcmd.h>
+#else
+#ifdef HAVE_XEN_SYS_PRIVCMD_H
+#include <xen/sys/privcmd.h>
+#endif
+#endif
+
+/* required for shutdown flags */
+#include <xen/sched.h>
+
+#include "virterror_internal.h"
+#include "logging.h"
+#include "datatypes.h"
+#include "driver.h"
+#include "util.h"
+#include "xen_driver.h"
+#include "xen_hypervisor.h"
+#include "xs_internal.h"
+#include "stats_linux.h"
+#include "block_stats.h"
+#include "xend_internal.h"
+#include "buf.h"
+#include "capabilities.h"
+#include "memory.h"
+
+#define VIR_FROM_THIS VIR_FROM_XEN
+
+/*
+ * so far there is 2 versions of the structures usable for doing
+ * hypervisor calls.
+ */
+/* the old one */
+typedef struct v0_hypercall_struct {
+ unsigned long op;
+ unsigned long arg[5];
+} v0_hypercall_t;
+
+#ifdef __linux__
+#define XEN_V0_IOCTL_HYPERCALL_CMD \
+ _IOC(_IOC_NONE, 'P', 0, sizeof(v0_hypercall_t))
+/* the new one */
+typedef struct v1_hypercall_struct
+{
+ uint64_t op;
+ uint64_t arg[5];
+} v1_hypercall_t;
+#define XEN_V1_IOCTL_HYPERCALL_CMD \
+ _IOC(_IOC_NONE, 'P', 0, sizeof(v1_hypercall_t))
+typedef v1_hypercall_t hypercall_t;
+#elif defined(__sun)
+typedef privcmd_hypercall_t hypercall_t;
+#else
+#error "unsupported platform"
+#endif
+
+#ifndef __HYPERVISOR_sysctl
+#define __HYPERVISOR_sysctl 35
+#endif
+#ifndef __HYPERVISOR_domctl
+#define __HYPERVISOR_domctl 36
+#endif
+
+#ifdef WITH_RHEL5_API
+#define SYS_IFACE_MIN_VERS_NUMA 3
+#else
+#define SYS_IFACE_MIN_VERS_NUMA 4
+#endif
+
+static int xen_ioctl_hypercall_cmd = 0;
+static int initialized = 0;
+static int in_init = 0;
+static int hv_version = 0;
+static int hypervisor_version = 2;
+static int sys_interface_version = -1;
+static int dom_interface_version = -1;
+static int kb_per_pages = 0;
+
+/* Regular expressions used by xenHypervisorGetCapabilities, and
+ * compiled once by xenHypervisorInit. Note that these are POSIX.2
+ * extended regular expressions (regex(7)).
+ */
+static const char *flags_hvm_re = "^flags[[:blank:]]+:.* (vmx|svm)[[:space:]]";
+static regex_t flags_hvm_rec;
+static const char *flags_pae_re = "^flags[[:blank:]]+:.* pae[[:space:]]";
+static regex_t flags_pae_rec;
+static const char *xen_cap_re = "(xen|hvm)-[[:digit:]]+\\.[[:digit:]]+-(x86_32|x86_64|ia64|powerpc64)(p|be)?";
+static regex_t xen_cap_rec;
+
+/*
+ * The content of the structures for a getdomaininfolist system hypercall
+ */
+#ifndef DOMFLAGS_DYING
+#define DOMFLAGS_DYING (1<<0) /* Domain is scheduled to die. */
+#define DOMFLAGS_HVM (1<<1) /* Domain is HVM */
+#define DOMFLAGS_SHUTDOWN (1<<2) /* The guest OS has shut down. */
+#define DOMFLAGS_PAUSED (1<<3) /* Currently paused by control software. */
+#define DOMFLAGS_BLOCKED (1<<4) /* Currently blocked pending an event. */
+#define DOMFLAGS_RUNNING (1<<5) /* Domain is currently running. */
+#define DOMFLAGS_CPUMASK 255 /* CPU to which this domain is bound. */
+#define DOMFLAGS_CPUSHIFT 8
+#define DOMFLAGS_SHUTDOWNMASK 255 /* DOMFLAGS_SHUTDOWN guest-supplied code. */
+#define DOMFLAGS_SHUTDOWNSHIFT 16
+#endif
+
+/*
+ * These flags explain why a system is in the state of "shutdown". Normally,
+ * They are defined in xen/sched.h
+ */
+#ifndef SHUTDOWN_poweroff
+#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */
+#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */
+#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */
+#define SHUTDOWN_crash 3 /* Tell controller we've crashed. */
+#endif
+
+#define XEN_V0_OP_GETDOMAININFOLIST 38
+#define XEN_V1_OP_GETDOMAININFOLIST 38
+#define XEN_V2_OP_GETDOMAININFOLIST 6
+
+struct xen_v0_getdomaininfo {
+ domid_t domain; /* the domain number */
+ uint32_t flags; /* flags, see before */
+ uint64_t tot_pages; /* total number of pages used */
+ uint64_t max_pages; /* maximum number of pages allowed */
+ unsigned long shared_info_frame; /* MFN of shared_info struct */
+ uint64_t cpu_time; /* CPU time used */
+ uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */
+ uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
+ uint32_t ssidref;
+ xen_domain_handle_t handle;
+};
+typedef struct xen_v0_getdomaininfo xen_v0_getdomaininfo;
+
+struct xen_v2_getdomaininfo {
+ domid_t domain; /* the domain number */
+ uint32_t flags; /* flags, see before */
+ uint64_t tot_pages; /* total number of pages used */
+ uint64_t max_pages; /* maximum number of pages allowed */
+ uint64_t shared_info_frame; /* MFN of shared_info struct */
+ uint64_t cpu_time; /* CPU time used */
+ uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */
+ uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
+ uint32_t ssidref;
+ xen_domain_handle_t handle;
+};
+typedef struct xen_v2_getdomaininfo xen_v2_getdomaininfo;
+
+
+/* As of Hypervisor Call v2, DomCtl v5 we are now 8-byte aligned
+ even on 32-bit archs when dealing with uint64_t */
+#define ALIGN_64 __attribute__((aligned(8)))
+
+struct xen_v2d5_getdomaininfo {
+ domid_t domain; /* the domain number */
+ uint32_t flags; /* flags, see before */
+ uint64_t tot_pages ALIGN_64; /* total number of pages used */
+ uint64_t max_pages ALIGN_64; /* maximum number of pages allowed */
+ uint64_t shared_info_frame ALIGN_64; /* MFN of shared_info struct */
+ uint64_t cpu_time ALIGN_64; /* CPU time used */
+ uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */
+ uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
+ uint32_t ssidref;
+ xen_domain_handle_t handle;
+};
+typedef struct xen_v2d5_getdomaininfo xen_v2d5_getdomaininfo;
+
+union xen_getdomaininfo {
+ struct xen_v0_getdomaininfo v0;
+ struct xen_v2_getdomaininfo v2;
+ struct xen_v2d5_getdomaininfo v2d5;
+};
+typedef union xen_getdomaininfo xen_getdomaininfo;
+
+union xen_getdomaininfolist {
+ struct xen_v0_getdomaininfo *v0;
+ struct xen_v2_getdomaininfo *v2;
+ struct xen_v2d5_getdomaininfo *v2d5;
+};
+typedef union xen_getdomaininfolist xen_getdomaininfolist;
+
+
+struct xen_v2_getschedulerid {
+ uint32_t sched_id; /* Get Scheduler ID from Xen */
+};
+typedef struct xen_v2_getschedulerid xen_v2_getschedulerid;
+
+
+union xen_getschedulerid {
+ struct xen_v2_getschedulerid *v2;
+};
+typedef union xen_getschedulerid xen_getschedulerid;
+
+struct xen_v2s4_availheap {
+ uint32_t min_bitwidth; /* Smallest address width (zero if don't care). */
+ uint32_t max_bitwidth; /* Largest address width (zero if don't care). */
+ int32_t node; /* NUMA node (-1 for sum across all nodes). */
+ uint64_t avail_bytes; /* Bytes available in the specified region. */
+};
+
+typedef struct xen_v2s4_availheap xen_v2s4_availheap;
+
+struct xen_v2s5_availheap {
+ uint32_t min_bitwidth; /* Smallest address width (zero if don't care). */
+ uint32_t max_bitwidth; /* Largest address width (zero if don't care). */
+ int32_t node; /* NUMA node (-1 for sum across all nodes). */
+ uint64_t avail_bytes ALIGN_64; /* Bytes available in the specified region. */
+};
+
+typedef struct xen_v2s5_availheap xen_v2s5_availheap;
+
+
+#define XEN_GETDOMAININFOLIST_ALLOC(domlist, size) \
+ (hypervisor_version < 2 ? \
+ (VIR_ALLOC_N(domlist.v0, (size)) == 0) : \
+ (dom_interface_version < 5 ? \
+ (VIR_ALLOC_N(domlist.v2, (size)) == 0) : \
+ (VIR_ALLOC_N(domlist.v2d5, (size)) == 0)))
+
+#define XEN_GETDOMAININFOLIST_FREE(domlist) \
+ (hypervisor_version < 2 ? \
+ VIR_FREE(domlist.v0) : \
+ (dom_interface_version < 5 ? \
+ VIR_FREE(domlist.v2) : \
+ VIR_FREE(domlist.v2d5)))
+
+#define XEN_GETDOMAININFOLIST_CLEAR(domlist, size) \
+ (hypervisor_version < 2 ? \
+ memset(domlist.v0, 0, sizeof(*domlist.v0) * size) : \
+ (dom_interface_version < 5 ? \
+ memset(domlist.v2, 0, sizeof(*domlist.v2) * size) : \
+ memset(domlist.v2d5, 0, sizeof(*domlist.v2d5) * size)))
+
+#define XEN_GETDOMAININFOLIST_DOMAIN(domlist, n) \
+ (hypervisor_version < 2 ? \
+ domlist.v0[n].domain : \
+ (dom_interface_version < 5 ? \
+ domlist.v2[n].domain : \
+ domlist.v2d5[n].domain))
+
+#define XEN_GETDOMAININFOLIST_UUID(domlist, n) \
+ (hypervisor_version < 2 ? \
+ domlist.v0[n].handle : \
+ (dom_interface_version < 5 ? \
+ domlist.v2[n].handle : \
+ domlist.v2d5[n].handle))
+
+#define XEN_GETDOMAININFOLIST_DATA(domlist) \
+ (hypervisor_version < 2 ? \
+ (void*)(domlist->v0) : \
+ (dom_interface_version < 5 ? \
+ (void*)(domlist->v2) : \
+ (void*)(domlist->v2d5)))
+
+#define XEN_GETDOMAININFO_SIZE \
+ (hypervisor_version < 2 ? \
+ sizeof(xen_v0_getdomaininfo) : \
+ (dom_interface_version < 5 ? \
+ sizeof(xen_v2_getdomaininfo) : \
+ sizeof(xen_v2d5_getdomaininfo)))
+
+#define XEN_GETDOMAININFO_CLEAR(dominfo) \
+ (hypervisor_version < 2 ? \
+ memset(&(dominfo.v0), 0, sizeof(xen_v0_getdomaininfo)) : \
+ (dom_interface_version < 5 ? \
+ memset(&(dominfo.v2), 0, sizeof(xen_v2_getdomaininfo)) : \
+ memset(&(dominfo.v2d5), 0, sizeof(xen_v2d5_getdomaininfo))))
+
+#define XEN_GETDOMAININFO_DOMAIN(dominfo) \
+ (hypervisor_version < 2 ? \
+ dominfo.v0.domain : \
+ (dom_interface_version < 5 ? \
+ dominfo.v2.domain : \
+ dominfo.v2d5.domain))
+
+#define XEN_GETDOMAININFO_CPUTIME(dominfo) \
+ (hypervisor_version < 2 ? \
+ dominfo.v0.cpu_time : \
+ (dom_interface_version < 5 ? \
+ dominfo.v2.cpu_time : \
+ dominfo.v2d5.cpu_time))
+
+#define XEN_GETDOMAININFO_CPUCOUNT(dominfo) \
+ (hypervisor_version < 2 ? \
+ dominfo.v0.nr_online_vcpus : \
+ (dom_interface_version < 5 ? \
+ dominfo.v2.nr_online_vcpus : \
+ dominfo.v2d5.nr_online_vcpus))
+
+#define XEN_GETDOMAININFO_MAXCPUID(dominfo) \
+ (hypervisor_version < 2 ? \
+ dominfo.v0.max_vcpu_id : \
+ (dom_interface_version < 5 ? \
+ dominfo.v2.max_vcpu_id : \
+ dominfo.v2d5.max_vcpu_id))
+
+#define XEN_GETDOMAININFO_FLAGS(dominfo) \
+ (hypervisor_version < 2 ? \
+ dominfo.v0.flags : \
+ (dom_interface_version < 5 ? \
+ dominfo.v2.flags : \
+ dominfo.v2d5.flags))
+
+#define XEN_GETDOMAININFO_TOT_PAGES(dominfo) \
+ (hypervisor_version < 2 ? \
+ dominfo.v0.tot_pages : \
+ (dom_interface_version < 5 ? \
+ dominfo.v2.tot_pages : \
+ dominfo.v2d5.tot_pages))
+
+#define XEN_GETDOMAININFO_MAX_PAGES(dominfo) \
+ (hypervisor_version < 2 ? \
+ dominfo.v0.max_pages : \
+ (dom_interface_version < 5 ? \
+ dominfo.v2.max_pages : \
+ dominfo.v2d5.max_pages))
+
+#define XEN_GETDOMAININFO_UUID(dominfo) \
+ (hypervisor_version < 2 ? \
+ dominfo.v0.handle : \
+ (dom_interface_version < 5 ? \
+ dominfo.v2.handle : \
+ dominfo.v2d5.handle))
+
+
+static int
+lock_pages(void *addr, size_t len)
+{
+#ifdef __linux__
+ return (mlock(addr, len));
+#elif defined(__sun)
+ return (0);
+#endif
+}
+
+static int
+unlock_pages(void *addr, size_t len)
+{
+#ifdef __linux__
+ return (munlock(addr, len));
+#elif defined(__sun)
+ return (0);
+#endif
+}
+
+
+struct xen_v0_getdomaininfolistop {
+ domid_t first_domain;
+ uint32_t max_domains;
+ struct xen_v0_getdomaininfo *buffer;
+ uint32_t num_domains;
+};
+typedef struct xen_v0_getdomaininfolistop xen_v0_getdomaininfolistop;
+
+
+struct xen_v2_getdomaininfolistop {
+ domid_t first_domain;
+ uint32_t max_domains;
+ struct xen_v2_getdomaininfo *buffer;
+ uint32_t num_domains;
+};
+typedef struct xen_v2_getdomaininfolistop xen_v2_getdomaininfolistop;
+
+/* As of HV version 2, sysctl version 3 the *buffer pointer is 64-bit aligned */
+struct xen_v2s3_getdomaininfolistop {
+ domid_t first_domain;
+ uint32_t max_domains;
+#ifdef __BIG_ENDIAN__
+ struct {
+ int __pad[(sizeof (long long) - sizeof (struct xen_v2d5_getdomaininfo *)) / sizeof (int)];
+ struct xen_v2d5_getdomaininfo *v;
+ } buffer;
+#else
+ union {
+ struct xen_v2d5_getdomaininfo *v;
+ uint64_t pad ALIGN_64;
+ } buffer;
+#endif
+ uint32_t num_domains;
+};
+typedef struct xen_v2s3_getdomaininfolistop xen_v2s3_getdomaininfolistop;
+
+
+
+struct xen_v0_domainop {
+ domid_t domain;
+};
+typedef struct xen_v0_domainop xen_v0_domainop;
+
+/*
+ * The information for a destroydomain system hypercall
+ */
+#define XEN_V0_OP_DESTROYDOMAIN 9
+#define XEN_V1_OP_DESTROYDOMAIN 9
+#define XEN_V2_OP_DESTROYDOMAIN 2
+
+/*
+ * The information for a pausedomain system hypercall
+ */
+#define XEN_V0_OP_PAUSEDOMAIN 10
+#define XEN_V1_OP_PAUSEDOMAIN 10
+#define XEN_V2_OP_PAUSEDOMAIN 3
+
+/*
+ * The information for an unpausedomain system hypercall
+ */
+#define XEN_V0_OP_UNPAUSEDOMAIN 11
+#define XEN_V1_OP_UNPAUSEDOMAIN 11
+#define XEN_V2_OP_UNPAUSEDOMAIN 4
+
+/*
+ * The information for an setmaxmem system hypercall
+ */
+#define XEN_V0_OP_SETMAXMEM 28
+#define XEN_V1_OP_SETMAXMEM 28
+#define XEN_V2_OP_SETMAXMEM 11
+
+struct xen_v0_setmaxmem {
+ domid_t domain;
+ uint64_t maxmem;
+};
+typedef struct xen_v0_setmaxmem xen_v0_setmaxmem;
+typedef struct xen_v0_setmaxmem xen_v1_setmaxmem;
+
+struct xen_v2_setmaxmem {
+ uint64_t maxmem;
+};
+typedef struct xen_v2_setmaxmem xen_v2_setmaxmem;
+
+struct xen_v2d5_setmaxmem {
+ uint64_t maxmem ALIGN_64;
+};
+typedef struct xen_v2d5_setmaxmem xen_v2d5_setmaxmem;
+
+/*
+ * The information for an setmaxvcpu system hypercall
+ */
+#define XEN_V0_OP_SETMAXVCPU 41
+#define XEN_V1_OP_SETMAXVCPU 41
+#define XEN_V2_OP_SETMAXVCPU 15
+
+struct xen_v0_setmaxvcpu {
+ domid_t domain;
+ uint32_t maxvcpu;
+};
+typedef struct xen_v0_setmaxvcpu xen_v0_setmaxvcpu;
+typedef struct xen_v0_setmaxvcpu xen_v1_setmaxvcpu;
+
+struct xen_v2_setmaxvcpu {
+ uint32_t maxvcpu;
+};
+typedef struct xen_v2_setmaxvcpu xen_v2_setmaxvcpu;
+
+/*
+ * The information for an setvcpumap system hypercall
+ * Note that between 1 and 2 the limitation to 64 physical CPU was lifted
+ * hence the difference in structures
+ */
+#define XEN_V0_OP_SETVCPUMAP 20
+#define XEN_V1_OP_SETVCPUMAP 20
+#define XEN_V2_OP_SETVCPUMAP 9
+
+struct xen_v0_setvcpumap {
+ domid_t domain;
+ uint32_t vcpu;
+ cpumap_t cpumap;
+};
+typedef struct xen_v0_setvcpumap xen_v0_setvcpumap;
+typedef struct xen_v0_setvcpumap xen_v1_setvcpumap;
+
+struct xen_v2_cpumap {
+ uint8_t *bitmap;
+ uint32_t nr_cpus;
+};
+struct xen_v2_setvcpumap {
+ uint32_t vcpu;
+ struct xen_v2_cpumap cpumap;
+};
+typedef struct xen_v2_setvcpumap xen_v2_setvcpumap;
+
+/* HV version 2, Dom version 5 requires 64-bit alignment */
+struct xen_v2d5_cpumap {
+#ifdef __BIG_ENDIAN__
+ struct {
+ int __pad[(sizeof (long long) - sizeof (uint8_t *)) / sizeof (int)];
+ uint8_t *v;
+ } bitmap;
+#else
+ union {
+ uint8_t *v;
+ uint64_t pad ALIGN_64;
+ } bitmap;
+#endif
+ uint32_t nr_cpus;
+};
+struct xen_v2d5_setvcpumap {
+ uint32_t vcpu;
+ struct xen_v2d5_cpumap cpumap;
+};
+typedef struct xen_v2d5_setvcpumap xen_v2d5_setvcpumap;
+
+/*
+ * The information for an vcpuinfo system hypercall
+ */
+#define XEN_V0_OP_GETVCPUINFO 43
+#define XEN_V1_OP_GETVCPUINFO 43
+#define XEN_V2_OP_GETVCPUINFO 14
+
+struct xen_v0_vcpuinfo {
+ domid_t domain; /* owner's domain */
+ uint32_t vcpu; /* the vcpu number */
+ uint8_t online; /* seen as on line */
+ uint8_t blocked; /* blocked on event */
+ uint8_t running; /* scheduled on CPU */
+ uint64_t cpu_time; /* nanosecond of CPU used */
+ uint32_t cpu; /* current mapping */
+ cpumap_t cpumap; /* deprecated in V2 */
+};
+typedef struct xen_v0_vcpuinfo xen_v0_vcpuinfo;
+typedef struct xen_v0_vcpuinfo xen_v1_vcpuinfo;
+
+struct xen_v2_vcpuinfo {
+ uint32_t vcpu; /* the vcpu number */
+ uint8_t online; /* seen as on line */
+ uint8_t blocked; /* blocked on event */
+ uint8_t running; /* scheduled on CPU */
+ uint64_t cpu_time; /* nanosecond of CPU used */
+ uint32_t cpu; /* current mapping */
+};
+typedef struct xen_v2_vcpuinfo xen_v2_vcpuinfo;
+
+struct xen_v2d5_vcpuinfo {
+ uint32_t vcpu; /* the vcpu number */
+ uint8_t online; /* seen as on line */
+ uint8_t blocked; /* blocked on event */
+ uint8_t running; /* scheduled on CPU */
+ uint64_t cpu_time ALIGN_64; /* nanosecond of CPU used */
+ uint32_t cpu; /* current mapping */
+};
+typedef struct xen_v2d5_vcpuinfo xen_v2d5_vcpuinfo;
+
+/*
+ * from V2 the pinning of a vcpu is read with a separate call
+ */
+#define XEN_V2_OP_GETVCPUMAP 25
+typedef struct xen_v2_setvcpumap xen_v2_getvcpumap;
+typedef struct xen_v2d5_setvcpumap xen_v2d5_getvcpumap;
+
+/*
+ * from V2 we get the scheduler information
+ */
+#define XEN_V2_OP_GETSCHEDULERID 4
+
+/*
+ * from V2 we get the available heap information
+ */
+#define XEN_V2_OP_GETAVAILHEAP 9
+
+/*
+ * from V2 we get the scheduler parameter
+ */
+#define XEN_V2_OP_SCHEDULER 16
+/* Scheduler types. */
+#define XEN_SCHEDULER_SEDF 4
+#define XEN_SCHEDULER_CREDIT 5
+/* get/set scheduler parameters */
+#define XEN_DOMCTL_SCHEDOP_putinfo 0
+#define XEN_DOMCTL_SCHEDOP_getinfo 1
+
+struct xen_v2_setschedinfo {
+ uint32_t sched_id;
+ uint32_t cmd;
+ union {
+ struct xen_domctl_sched_sedf {
+ uint64_t period ALIGN_64;
+ uint64_t slice ALIGN_64;
+ uint64_t latency ALIGN_64;
+ uint32_t extratime;
+ uint32_t weight;
+ } sedf;
+ struct xen_domctl_sched_credit {
+ uint16_t weight;
+ uint16_t cap;
+ } credit;
+ } u;
+};
+typedef struct xen_v2_setschedinfo xen_v2_setschedinfo;
+typedef struct xen_v2_setschedinfo xen_v2_getschedinfo;
+
+
+/*
+ * The hypercall operation structures also have changed on
+ * changeset 86d26e6ec89b
+ */
+/* the old structure */
+struct xen_op_v0 {
+ uint32_t cmd;
+ uint32_t interface_version;
+ union {
+ xen_v0_getdomaininfolistop getdomaininfolist;
+ xen_v0_domainop domain;
+ xen_v0_setmaxmem setmaxmem;
+ xen_v0_setmaxvcpu setmaxvcpu;
+ xen_v0_setvcpumap setvcpumap;
+ xen_v0_vcpuinfo getvcpuinfo;
+ uint8_t padding[128];
+ } u;
+};
+typedef struct xen_op_v0 xen_op_v0;
+typedef struct xen_op_v0 xen_op_v1;
+
+/* the new structure for systems operations */
+struct xen_op_v2_sys {
+ uint32_t cmd;
+ uint32_t interface_version;
+ union {
+ xen_v2_getdomaininfolistop getdomaininfolist;
+ xen_v2s3_getdomaininfolistop getdomaininfolists3;
+ xen_v2_getschedulerid getschedulerid;
+ xen_v2s4_availheap availheap;
+ xen_v2s5_availheap availheap5;
+ uint8_t padding[128];
+ } u;
+};
+typedef struct xen_op_v2_sys xen_op_v2_sys;
+
+/* the new structure for domains operation */
+struct xen_op_v2_dom {
+ uint32_t cmd;
+ uint32_t interface_version;
+ domid_t domain;
+ union {
+ xen_v2_setmaxmem setmaxmem;
+ xen_v2d5_setmaxmem setmaxmemd5;
+ xen_v2_setmaxvcpu setmaxvcpu;
+ xen_v2_setvcpumap setvcpumap;
+ xen_v2d5_setvcpumap setvcpumapd5;
+ xen_v2_vcpuinfo getvcpuinfo;
+ xen_v2d5_vcpuinfo getvcpuinfod5;
+ xen_v2_getvcpumap getvcpumap;
+ xen_v2d5_getvcpumap getvcpumapd5;
+ xen_v2_setschedinfo setschedinfo;
+ xen_v2_getschedinfo getschedinfo;
+ uint8_t padding[128];
+ } u;
+};
+typedef struct xen_op_v2_dom xen_op_v2_dom;
+
+
+#ifdef __linux__
+#define XEN_HYPERVISOR_SOCKET "/proc/xen/privcmd"
+#define HYPERVISOR_CAPABILITIES "/sys/hypervisor/properties/capabilities"
+#elif defined(__sun)
+#define XEN_HYPERVISOR_SOCKET "/dev/xen/privcmd"
+#else
+#error "unsupported platform"
+#endif
+
+#ifndef PROXY
+static unsigned long xenHypervisorGetMaxMemory(virDomainPtr domain);
+#endif
+
+#ifndef PROXY
+struct xenUnifiedDriver xenHypervisorDriver = {
+ xenHypervisorOpen, /* open */
+ xenHypervisorClose, /* close */
+ xenHypervisorGetVersion, /* version */
+ NULL, /* hostname */
+ NULL, /* nodeGetInfo */
+ xenHypervisorGetCapabilities, /* getCapabilities */
+ xenHypervisorListDomains, /* listDomains */
+ xenHypervisorNumOfDomains, /* numOfDomains */
+ NULL, /* domainCreateXML */
+ xenHypervisorPauseDomain, /* domainSuspend */
+ xenHypervisorResumeDomain, /* domainResume */
+ NULL, /* domainShutdown */
+ NULL, /* domainReboot */
+ xenHypervisorDestroyDomain, /* domainDestroy */
+ xenHypervisorDomainGetOSType, /* domainGetOSType */
+ xenHypervisorGetMaxMemory, /* domainGetMaxMemory */
+ xenHypervisorSetMaxMemory, /* domainSetMaxMemory */
+ NULL, /* domainSetMemory */
+ xenHypervisorGetDomainInfo, /* domainGetInfo */
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
+ NULL, /* domainCoreDump */
+ xenHypervisorSetVcpus, /* domainSetVcpus */
+ xenHypervisorPinVcpu, /* domainPinVcpu */
+ xenHypervisorGetVcpus, /* domainGetVcpus */
+ xenHypervisorGetVcpuMax, /* domainGetMaxVcpus */
+ NULL, /* listDefinedDomains */
+ NULL, /* numOfDefinedDomains */
+ NULL, /* domainCreate */
+ NULL, /* domainDefineXML */
+ NULL, /* domainUndefine */
+ NULL, /* domainAttachDevice */
+ NULL, /* domainDetachDevice */
+ NULL, /* domainGetAutostart */
+ NULL, /* domainSetAutostart */
+ xenHypervisorGetSchedulerType, /* domainGetSchedulerType */
+ xenHypervisorGetSchedulerParameters, /* domainGetSchedulerParameters */
+ xenHypervisorSetSchedulerParameters, /* domainSetSchedulerParameters */
+};
+#endif /* !PROXY */
+
+#define virXenError(conn, code, fmt...) \
+ if (in_init == 0) \
+ virReportErrorHelper(conn, VIR_FROM_XEN, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
+#ifndef PROXY
+
+/**
+ * virXenErrorFunc:
+ * @conn: connection, if known
+ * @error: the error number
+ * @func: the function failing
+ * @info: extra information string
+ * @value: extra information number
+ *
+ * Handle an error at the xend daemon interface
+ */
+static void
+virXenErrorFunc(virConnectPtr conn,
+ virErrorNumber error, const char *func, const char *info,
+ int value)
+{
+ char fullinfo[1000];
+ const char *errmsg;
+
+ if ((error == VIR_ERR_OK) || (in_init != 0))
+ return;
+
+
+ errmsg =virErrorMsg(error, info);
+ if (func != NULL) {
+ snprintf(fullinfo, 999, "%s: %s", func, info);
+ fullinfo[999] = 0;
+ virRaiseError(conn, NULL, NULL, VIR_FROM_XEN, error, VIR_ERR_ERROR,
+ errmsg, fullinfo, NULL, value, 0, errmsg, fullinfo,
+ value);
+ } else {
+ virRaiseError(conn, NULL, NULL, VIR_FROM_XEN, error, VIR_ERR_ERROR,
+ errmsg, info, NULL, value, 0, errmsg, info,
+ value);
+ }
+}
+
+#endif /* PROXY */
+
+/**
+ * xenHypervisorDoV0Op:
+ * @handle: the handle to the Xen hypervisor
+ * @op: pointer to the hypervisor operation structure
+ *
+ * Do an hypervisor operation though the old interface,
+ * this leads to an hypervisor call through ioctl.
+ *
+ * Returns 0 in case of success and -1 in case of error.
+ */
+static int
+xenHypervisorDoV0Op(int handle, xen_op_v0 * op)
+{
+ int ret;
+ v0_hypercall_t hc;
+
+ memset(&hc, 0, sizeof(hc));
+ op->interface_version = hv_version << 8;
+ hc.op = __HYPERVISOR_dom0_op;
+ hc.arg[0] = (unsigned long) op;
+
+ if (lock_pages(op, sizeof(dom0_op_t)) < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " locking");
+ return (-1);
+ }
+
+ ret = ioctl(handle, xen_ioctl_hypercall_cmd, (unsigned long) &hc);
+ if (ret < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " ioctl %d",
+ xen_ioctl_hypercall_cmd);
+ }
+
+ if (unlock_pages(op, sizeof(dom0_op_t)) < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " releasing");
+ ret = -1;
+ }
+
+ if (ret < 0)
+ return (-1);
+
+ return (0);
+}
+/**
+ * xenHypervisorDoV1Op:
+ * @handle: the handle to the Xen hypervisor
+ * @op: pointer to the hypervisor operation structure
+ *
+ * Do an hypervisor v1 operation, this leads to an hypervisor call through
+ * ioctl.
+ *
+ * Returns 0 in case of success and -1 in case of error.
+ */
+static int
+xenHypervisorDoV1Op(int handle, xen_op_v1* op)
+{
+ int ret;
+ hypercall_t hc;
+
+ memset(&hc, 0, sizeof(hc));
+ op->interface_version = DOM0_INTERFACE_VERSION;
+ hc.op = __HYPERVISOR_dom0_op;
+ hc.arg[0] = (unsigned long) op;
+
+ if (lock_pages(op, sizeof(dom0_op_t)) < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " locking");
+ return (-1);
+ }
+
+ ret = ioctl(handle, xen_ioctl_hypercall_cmd, (unsigned long) &hc);
+ if (ret < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " ioctl %d",
+ xen_ioctl_hypercall_cmd);
+ }
+
+ if (unlock_pages(op, sizeof(dom0_op_t)) < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " releasing");
+ ret = -1;
+ }
+
+ if (ret < 0)
+ return (-1);
+
+ return (0);
+}
+
+/**
+ * xenHypervisorDoV2Sys:
+ * @handle: the handle to the Xen hypervisor
+ * @op: pointer to the hypervisor operation structure
+ *
+ * Do an hypervisor v2 system operation, this leads to an hypervisor
+ * call through ioctl.
+ *
+ * Returns 0 in case of success and -1 in case of error.
+ */
+static int
+xenHypervisorDoV2Sys(int handle, xen_op_v2_sys* op)
+{
+ int ret;
+ hypercall_t hc;
+
+ memset(&hc, 0, sizeof(hc));
+ op->interface_version = sys_interface_version;
+ hc.op = __HYPERVISOR_sysctl;
+ hc.arg[0] = (unsigned long) op;
+
+ if (lock_pages(op, sizeof(dom0_op_t)) < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " locking");
+ return (-1);
+ }
+
+ ret = ioctl(handle, xen_ioctl_hypercall_cmd, (unsigned long) &hc);
+ if (ret < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " sys ioctl %d",
+ xen_ioctl_hypercall_cmd);
+ }
+
+ if (unlock_pages(op, sizeof(dom0_op_t)) < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " releasing");
+ ret = -1;
+ }
+
+ if (ret < 0)
+ return (-1);
+
+ return (0);
+}
+
+/**
+ * xenHypervisorDoV2Dom:
+ * @handle: the handle to the Xen hypervisor
+ * @op: pointer to the hypervisor domain operation structure
+ *
+ * Do an hypervisor v2 domain operation, this leads to an hypervisor
+ * call through ioctl.
+ *
+ * Returns 0 in case of success and -1 in case of error.
+ */
+static int
+xenHypervisorDoV2Dom(int handle, xen_op_v2_dom* op)
+{
+ int ret;
+ hypercall_t hc;
+
+ memset(&hc, 0, sizeof(hc));
+ op->interface_version = dom_interface_version;
+ hc.op = __HYPERVISOR_domctl;
+ hc.arg[0] = (unsigned long) op;
+
+ if (lock_pages(op, sizeof(dom0_op_t)) < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " locking");
+ return (-1);
+ }
+
+ ret = ioctl(handle, xen_ioctl_hypercall_cmd, (unsigned long) &hc);
+ if (ret < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " ioctl %d",
+ xen_ioctl_hypercall_cmd);
+ }
+
+ if (unlock_pages(op, sizeof(dom0_op_t)) < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " releasing");
+ ret = -1;
+ }
+
+ if (ret < 0)
+ return (-1);
+
+ return (0);
+}
+
+/**
+ * virXen_getdomaininfolist:
+ * @handle: the hypervisor handle
+ * @first_domain: first domain in the range
+ * @maxids: maximum number of domains to list
+ * @dominfos: output structures
+ *
+ * Do a low level hypercall to list existing domains information
+ *
+ * Returns the number of domains or -1 in case of failure
+ */
+static int
+virXen_getdomaininfolist(int handle, int first_domain, int maxids,
+ xen_getdomaininfolist *dominfos)
+{
+ int ret = -1;
+
+ if (lock_pages(XEN_GETDOMAININFOLIST_DATA(dominfos),
+ XEN_GETDOMAININFO_SIZE * maxids) < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " locking");
+ return (-1);
+ }
+ if (hypervisor_version > 1) {
+ xen_op_v2_sys op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V2_OP_GETDOMAININFOLIST;
+
+ if (sys_interface_version < 3) {
+ op.u.getdomaininfolist.first_domain = (domid_t) first_domain;
+ op.u.getdomaininfolist.max_domains = maxids;
+ op.u.getdomaininfolist.buffer = dominfos->v2;
+ op.u.getdomaininfolist.num_domains = maxids;
+ } else {
+ op.u.getdomaininfolists3.first_domain = (domid_t) first_domain;
+ op.u.getdomaininfolists3.max_domains = maxids;
+ op.u.getdomaininfolists3.buffer.v = dominfos->v2d5;
+ op.u.getdomaininfolists3.num_domains = maxids;
+ }
+ ret = xenHypervisorDoV2Sys(handle, &op);
+
+ if (ret == 0) {
+ if (sys_interface_version < 3)
+ ret = op.u.getdomaininfolist.num_domains;
+ else
+ ret = op.u.getdomaininfolists3.num_domains;
+ }
+ } else if (hypervisor_version == 1) {
+ xen_op_v1 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V1_OP_GETDOMAININFOLIST;
+ op.u.getdomaininfolist.first_domain = (domid_t) first_domain;
+ op.u.getdomaininfolist.max_domains = maxids;
+ op.u.getdomaininfolist.buffer = dominfos->v0;
+ op.u.getdomaininfolist.num_domains = maxids;
+ ret = xenHypervisorDoV1Op(handle, &op);
+ if (ret == 0)
+ ret = op.u.getdomaininfolist.num_domains;
+ } else if (hypervisor_version == 0) {
+ xen_op_v0 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V0_OP_GETDOMAININFOLIST;
+ op.u.getdomaininfolist.first_domain = (domid_t) first_domain;
+ op.u.getdomaininfolist.max_domains = maxids;
+ op.u.getdomaininfolist.buffer = dominfos->v0;
+ op.u.getdomaininfolist.num_domains = maxids;
+ ret = xenHypervisorDoV0Op(handle, &op);
+ if (ret == 0)
+ ret = op.u.getdomaininfolist.num_domains;
+ }
+ if (unlock_pages(XEN_GETDOMAININFOLIST_DATA(dominfos),
+ XEN_GETDOMAININFO_SIZE * maxids) < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " release");
+ ret = -1;
+ }
+ return(ret);
+}
+
+static int
+virXen_getdomaininfo(int handle, int first_domain,
+ xen_getdomaininfo *dominfo) {
+ xen_getdomaininfolist dominfos;
+
+ if (hypervisor_version < 2) {
+ dominfos.v0 = &(dominfo->v0);
+ } else {
+ dominfos.v2 = &(dominfo->v2);
+ }
+
+ return virXen_getdomaininfolist(handle, first_domain, 1, &dominfos);
+}
+
+
+#ifndef PROXY
+/**
+ * xenHypervisorGetSchedulerType:
+ * @domain: pointer to the Xen Hypervisor block
+ * @nparams:give a number of scheduler parameters.
+ *
+ * Do a low level hypercall to get scheduler type
+ *
+ * Returns scheduler name or NULL in case of failure
+ */
+char *
+xenHypervisorGetSchedulerType(virDomainPtr domain, int *nparams)
+{
+ char *schedulertype = NULL;
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL)) {
+ virXenErrorFunc(NULL, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
+ "domain or conn is NULL", 0);
+ return NULL;
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->handle < 0) {
+ virXenErrorFunc(domain->conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
+ "priv->handle invalid", 0);
+ return NULL;
+ }
+ if (domain->id < 0) {
+ virXenError(domain->conn, VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ return NULL;
+ }
+
+ /*
+ * Support only dom_interface_version >=5
+ * (Xen3.1.0 or later)
+ * TODO: check on Xen 3.0.3
+ */
+ if (dom_interface_version < 5) {
+ virXenErrorFunc(domain->conn, VIR_ERR_NO_XEN, __FUNCTION__,
+ "unsupported in dom interface < 5", 0);
+ return NULL;
+ }
+
+ if (hypervisor_version > 1) {
+ xen_op_v2_sys op;
+ int ret;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V2_OP_GETSCHEDULERID;
+ ret = xenHypervisorDoV2Sys(priv->handle, &op);
+ if (ret < 0)
+ return(NULL);
+
+ switch (op.u.getschedulerid.sched_id){
+ case XEN_SCHEDULER_SEDF:
+ schedulertype = strdup("sedf");
+ if (nparams)
+ *nparams = 6;
+ break;
+ case XEN_SCHEDULER_CREDIT:
+ schedulertype = strdup("credit");
+ if (nparams)
+ *nparams = 2;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return schedulertype;
+}
+
+static const char *str_weight = "weight";
+static const char *str_cap = "cap";
+
+/**
+ * xenHypervisorGetSchedulerParameters:
+ * @domain: pointer to the Xen Hypervisor block
+ * @params: pointer to scheduler parameters.
+ * This memory area should be allocated before calling.
+ * @nparams:this parameter should be same as
+ * a given number of scheduler parameters.
+ * from xenHypervisorGetSchedulerType().
+ *
+ * Do a low level hypercall to get scheduler parameters
+ *
+ * Returns 0 or -1 in case of failure
+ */
+int
+xenHypervisorGetSchedulerParameters(virDomainPtr domain,
+ virSchedParameterPtr params, int *nparams)
+{
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL)) {
+ virXenErrorFunc(NULL, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
+ "domain or conn is NULL", 0);
+ return -1;
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->handle < 0) {
+ virXenErrorFunc(domain->conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
+ "priv->handle invalid", 0);
+ return -1;
+ }
+ if (domain->id < 0) {
+ virXenError(domain->conn, VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ return -1;
+ }
+
+ /*
+ * Support only dom_interface_version >=5
+ * (Xen3.1.0 or later)
+ * TODO: check on Xen 3.0.3
+ */
+ if (dom_interface_version < 5) {
+ virXenErrorFunc(domain->conn, VIR_ERR_NO_XEN, __FUNCTION__,
+ "unsupported in dom interface < 5", 0);
+ return -1;
+ }
+
+ if (hypervisor_version > 1) {
+ xen_op_v2_sys op_sys;
+ xen_op_v2_dom op_dom;
+ int ret;
+
+ memset(&op_sys, 0, sizeof(op_sys));
+ op_sys.cmd = XEN_V2_OP_GETSCHEDULERID;
+ ret = xenHypervisorDoV2Sys(priv->handle, &op_sys);
+ if (ret < 0)
+ return -1;
+
+ switch (op_sys.u.getschedulerid.sched_id){
+ case XEN_SCHEDULER_SEDF:
+ /* TODO: Implement for Xen/SEDF */
+ TODO
+ return(-1);
+ case XEN_SCHEDULER_CREDIT:
+ if (*nparams < 2)
+ return(-1);
+ memset(&op_dom, 0, sizeof(op_dom));
+ op_dom.cmd = XEN_V2_OP_SCHEDULER;
+ op_dom.domain = (domid_t) domain->id;
+ op_dom.u.getschedinfo.sched_id = XEN_SCHEDULER_CREDIT;
+ op_dom.u.getschedinfo.cmd = XEN_DOMCTL_SCHEDOP_getinfo;
+ ret = xenHypervisorDoV2Dom(priv->handle, &op_dom);
+ if (ret < 0)
+ return(-1);
+
+ strncpy (params[0].field, str_weight, VIR_DOMAIN_SCHED_FIELD_LENGTH);
+ params[0].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
+ params[0].type = VIR_DOMAIN_SCHED_FIELD_UINT;
+ params[0].value.ui = op_dom.u.getschedinfo.u.credit.weight;
+
+ strncpy (params[1].field, str_cap, VIR_DOMAIN_SCHED_FIELD_LENGTH);
+ params[1].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
+ params[1].type = VIR_DOMAIN_SCHED_FIELD_UINT;
+ params[1].value.ui = op_dom.u.getschedinfo.u.credit.cap;
+
+ *nparams = 2;
+ break;
+ default:
+ virXenErrorFunc(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "Unknown scheduler", op_sys.u.getschedulerid.sched_id);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * xenHypervisorSetSchedulerParameters:
+ * @domain: pointer to the Xen Hypervisor block
+ * @nparams:give a number of scheduler setting parameters .
+ *
+ * Do a low level hypercall to set scheduler parameters
+ *
+ * Returns 0 or -1 in case of failure
+ */
+int
+xenHypervisorSetSchedulerParameters(virDomainPtr domain,
+ virSchedParameterPtr params, int nparams)
+{
+ int i;
+ unsigned int val;
+ xenUnifiedPrivatePtr priv;
+ char buf[256];
+
+ if ((domain == NULL) || (domain->conn == NULL)) {
+ virXenErrorFunc (NULL, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
+ "domain or conn is NULL", 0);
+ return -1;
+ }
+
+ if ((nparams == 0) || (params == NULL)) {
+ virXenErrorFunc (domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "Noparameters given", 0);
+ return(-1);
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->handle < 0) {
+ virXenErrorFunc(domain->conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
+ "priv->handle invalid", 0);
+ return -1;
+ }
+ if (domain->id < 0) {
+ virXenError(domain->conn, VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ return -1;
+ }
+
+ /*
+ * Support only dom_interface_version >=5
+ * (Xen3.1.0 or later)
+ * TODO: check on Xen 3.0.3
+ */
+ if (dom_interface_version < 5) {
+ virXenErrorFunc(domain->conn, VIR_ERR_NO_XEN, __FUNCTION__,
+ "unsupported in dom interface < 5", 0);
+ return -1;
+ }
+
+ if (hypervisor_version > 1) {
+ xen_op_v2_sys op_sys;
+ xen_op_v2_dom op_dom;
+ int ret;
+
+ memset(&op_sys, 0, sizeof(op_sys));
+ op_sys.cmd = XEN_V2_OP_GETSCHEDULERID;
+ ret = xenHypervisorDoV2Sys(priv->handle, &op_sys);
+ if (ret == -1) return -1;
+
+ switch (op_sys.u.getschedulerid.sched_id){
+ case XEN_SCHEDULER_SEDF:
+ /* TODO: Implement for Xen/SEDF */
+ TODO
+ return(-1);
+ case XEN_SCHEDULER_CREDIT: {
+ memset(&op_dom, 0, sizeof(op_dom));
+ op_dom.cmd = XEN_V2_OP_SCHEDULER;
+ op_dom.domain = (domid_t) domain->id;
+ op_dom.u.getschedinfo.sched_id = XEN_SCHEDULER_CREDIT;
+ op_dom.u.getschedinfo.cmd = XEN_DOMCTL_SCHEDOP_putinfo;
+
+ /*
+ * credit scheduler parameters
+ * following values do not change the parameters
+ */
+ op_dom.u.getschedinfo.u.credit.weight = 0;
+ op_dom.u.getschedinfo.u.credit.cap = (uint16_t)~0U;
+
+ for (i = 0; i < nparams; i++) {
+ memset(&buf, 0, sizeof(buf));
+ if (STREQ (params[i].field, str_weight) &&
+ params[i].type == VIR_DOMAIN_SCHED_FIELD_UINT) {
+ val = params[i].value.ui;
+ if ((val < 1) || (val > USHRT_MAX)) {
+ snprintf(buf, sizeof(buf), _("Credit scheduler weight parameter (%d) is out of range (1-65535)"), val);
+ virXenErrorFunc (domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__, buf, val);
+ return(-1);
+ }
+ op_dom.u.getschedinfo.u.credit.weight = val;
+ } else if (STREQ (params[i].field, str_cap) &&
+ params[i].type == VIR_DOMAIN_SCHED_FIELD_UINT) {
+ val = params[i].value.ui;
+ if (val > USHRT_MAX) {
+ snprintf(buf, sizeof(buf), _("Credit scheduler cap parameter (%d) is out of range (0-65535)"), val);
+ virXenErrorFunc (domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__, buf, val);
+ return(-1);
+ }
+ op_dom.u.getschedinfo.u.credit.cap = val;
+ } else {
+ virXenErrorFunc (domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "Credit scheduler accepts 'cap' and 'weight' integer parameters",
+ 0);
+ return(-1);
+ }
+ }
+
+ ret = xenHypervisorDoV2Dom(priv->handle, &op_dom);
+ if (ret < 0)
+ return -1;
+ break;
+ }
+ default:
+ virXenErrorFunc(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "Unknown scheduler", op_sys.u.getschedulerid.sched_id);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int
+xenHypervisorDomainBlockStats (virDomainPtr dom,
+ const char *path,
+ struct _virDomainBlockStats *stats)
+{
+#ifdef __linux__
+ xenUnifiedPrivatePtr priv;
+ int ret;
+
+ priv = (xenUnifiedPrivatePtr) dom->conn->privateData;
+ xenUnifiedLock(priv);
+ /* Need to lock because it hits the xenstore handle :-( */
+ ret = xenLinuxDomainBlockStats (priv, dom, path, stats);
+ xenUnifiedUnlock(priv);
+ return ret;
+#else
+ virXenErrorFunc (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__,
+ "block statistics not supported on this platform",
+ dom->id);
+ return -1;
+#endif
+}
+
+/* Paths have the form vif<domid>.<n> (this interface checks that
+ * <domid> is the real domain ID and returns an error if not).
+ *
+ * In future we may allow you to query bridge stats (virbrX or
+ * xenbrX), but that will probably be through a separate
+ * virNetwork interface, as yet not decided.
+ */
+int
+xenHypervisorDomainInterfaceStats (virDomainPtr dom,
+ const char *path,
+ struct _virDomainInterfaceStats *stats)
+{
+#ifdef __linux__
+ int rqdomid, device;
+
+ /* Verify that the vif requested is one belonging to the current
+ * domain.
+ */
+ if (sscanf (path, "vif%d.%d", &rqdomid, &device) != 2) {
+ virXenErrorFunc (dom->conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "invalid path, should be vif<domid>.<n>.", 0);
+ return -1;
+ }
+ if (rqdomid != dom->id) {
+ virXenErrorFunc (dom->conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "invalid path, vif<domid> should match this domain ID", 0);
+ return -1;
+ }
+
+ return linuxDomainInterfaceStats (dom->conn, path, stats);
+#else
+ virXenErrorFunc (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__,
+ "/proc/net/dev: Interface not found", 0);
+ return -1;
+#endif
+}
+
+/**
+ * virXen_pausedomain:
+ * @handle: the hypervisor handle
+ * @id: the domain id
+ *
+ * Do a low level hypercall to pause the domain
+ *
+ * Returns 0 or -1 in case of failure
+ */
+static int
+virXen_pausedomain(int handle, int id)
+{
+ int ret = -1;
+
+ if (hypervisor_version > 1) {
+ xen_op_v2_dom op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V2_OP_PAUSEDOMAIN;
+ op.domain = (domid_t) id;
+ ret = xenHypervisorDoV2Dom(handle, &op);
+ } else if (hypervisor_version == 1) {
+ xen_op_v1 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V1_OP_PAUSEDOMAIN;
+ op.u.domain.domain = (domid_t) id;
+ ret = xenHypervisorDoV1Op(handle, &op);
+ } else if (hypervisor_version == 0) {
+ xen_op_v0 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V0_OP_PAUSEDOMAIN;
+ op.u.domain.domain = (domid_t) id;
+ ret = xenHypervisorDoV0Op(handle, &op);
+ }
+ return(ret);
+}
+
+/**
+ * virXen_unpausedomain:
+ * @handle: the hypervisor handle
+ * @id: the domain id
+ *
+ * Do a low level hypercall to unpause the domain
+ *
+ * Returns 0 or -1 in case of failure
+ */
+static int
+virXen_unpausedomain(int handle, int id)
+{
+ int ret = -1;
+
+ if (hypervisor_version > 1) {
+ xen_op_v2_dom op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V2_OP_UNPAUSEDOMAIN;
+ op.domain = (domid_t) id;
+ ret = xenHypervisorDoV2Dom(handle, &op);
+ } else if (hypervisor_version == 1) {
+ xen_op_v1 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V1_OP_UNPAUSEDOMAIN;
+ op.u.domain.domain = (domid_t) id;
+ ret = xenHypervisorDoV1Op(handle, &op);
+ } else if (hypervisor_version == 0) {
+ xen_op_v0 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V0_OP_UNPAUSEDOMAIN;
+ op.u.domain.domain = (domid_t) id;
+ ret = xenHypervisorDoV0Op(handle, &op);
+ }
+ return(ret);
+}
+
+/**
+ * virXen_destroydomain:
+ * @handle: the hypervisor handle
+ * @id: the domain id
+ *
+ * Do a low level hypercall to destroy the domain
+ *
+ * Returns 0 or -1 in case of failure
+ */
+static int
+virXen_destroydomain(int handle, int id)
+{
+ int ret = -1;
+
+ if (hypervisor_version > 1) {
+ xen_op_v2_dom op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V2_OP_DESTROYDOMAIN;
+ op.domain = (domid_t) id;
+ ret = xenHypervisorDoV2Dom(handle, &op);
+ } else if (hypervisor_version == 1) {
+ xen_op_v1 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V1_OP_DESTROYDOMAIN;
+ op.u.domain.domain = (domid_t) id;
+ ret = xenHypervisorDoV1Op(handle, &op);
+ } else if (hypervisor_version == 0) {
+ xen_op_v0 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V0_OP_DESTROYDOMAIN;
+ op.u.domain.domain = (domid_t) id;
+ ret = xenHypervisorDoV0Op(handle, &op);
+ }
+ return(ret);
+}
+
+/**
+ * virXen_setmaxmem:
+ * @handle: the hypervisor handle
+ * @id: the domain id
+ * @memory: the amount of memory in kilobytes
+ *
+ * Do a low level hypercall to change the max memory amount
+ *
+ * Returns 0 or -1 in case of failure
+ */
+static int
+virXen_setmaxmem(int handle, int id, unsigned long memory)
+{
+ int ret = -1;
+
+ if (hypervisor_version > 1) {
+ xen_op_v2_dom op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V2_OP_SETMAXMEM;
+ op.domain = (domid_t) id;
+ if (dom_interface_version < 5)
+ op.u.setmaxmem.maxmem = memory;
+ else
+ op.u.setmaxmemd5.maxmem = memory;
+ ret = xenHypervisorDoV2Dom(handle, &op);
+ } else if (hypervisor_version == 1) {
+ xen_op_v1 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V1_OP_SETMAXMEM;
+ op.u.setmaxmem.domain = (domid_t) id;
+ op.u.setmaxmem.maxmem = memory;
+ ret = xenHypervisorDoV1Op(handle, &op);
+ } else if (hypervisor_version == 0) {
+ xen_op_v0 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V0_OP_SETMAXMEM;
+ op.u.setmaxmem.domain = (domid_t) id;
+ op.u.setmaxmem.maxmem = memory;
+ ret = xenHypervisorDoV0Op(handle, &op);
+ }
+ return(ret);
+}
+
+/**
+ * virXen_setmaxvcpus:
+ * @handle: the hypervisor handle
+ * @id: the domain id
+ * @vcpus: the numbers of vcpus
+ *
+ * Do a low level hypercall to change the max vcpus amount
+ *
+ * Returns 0 or -1 in case of failure
+ */
+static int
+virXen_setmaxvcpus(int handle, int id, unsigned int vcpus)
+{
+ int ret = -1;
+
+ if (hypervisor_version > 1) {
+ xen_op_v2_dom op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V2_OP_SETMAXVCPU;
+ op.domain = (domid_t) id;
+ op.u.setmaxvcpu.maxvcpu = vcpus;
+ ret = xenHypervisorDoV2Dom(handle, &op);
+ } else if (hypervisor_version == 1) {
+ xen_op_v1 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V1_OP_SETMAXVCPU;
+ op.u.setmaxvcpu.domain = (domid_t) id;
+ op.u.setmaxvcpu.maxvcpu = vcpus;
+ ret = xenHypervisorDoV1Op(handle, &op);
+ } else if (hypervisor_version == 0) {
+ xen_op_v0 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V0_OP_SETMAXVCPU;
+ op.u.setmaxvcpu.domain = (domid_t) id;
+ op.u.setmaxvcpu.maxvcpu = vcpus;
+ ret = xenHypervisorDoV0Op(handle, &op);
+ }
+ return(ret);
+}
+
+/**
+ * virXen_setvcpumap:
+ * @handle: the hypervisor handle
+ * @id: the domain id
+ * @vcpu: the vcpu to map
+ * @cpumap: the bitmap for this vcpu
+ * @maplen: the size of the bitmap in bytes
+ *
+ * Do a low level hypercall to change the pinning for vcpu
+ *
+ * Returns 0 or -1 in case of failure
+ */
+static int
+virXen_setvcpumap(int handle, int id, unsigned int vcpu,
+ unsigned char * cpumap, int maplen)
+{
+ int ret = -1;
+ unsigned char *new = NULL;
+ unsigned char *bitmap = NULL;
+ uint32_t nr_cpus;
+
+ if (hypervisor_version > 1) {
+ xen_op_v2_dom op;
+
+ if (lock_pages(cpumap, maplen) < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " locking");
+ return (-1);
+ }
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V2_OP_SETVCPUMAP;
+ op.domain = (domid_t) id;
+
+ /* The allocated memory to cpumap must be 'sizeof(uint64_t)' byte *
+ * for Xen, and also nr_cpus must be 'sizeof(uint64_t) * 8' */
+ if (maplen < 8) {
+ if (VIR_ALLOC_N(new, sizeof(uint64_t)) < 0) {
+ virReportOOMError(NULL);
+ return (-1);
+ }
+ memcpy(new, cpumap, maplen);
+ bitmap = new;
+ nr_cpus = sizeof(uint64_t) * 8;
+ } else {
+ bitmap = cpumap;
+ nr_cpus = maplen * 8;
+ }
+
+ if (dom_interface_version < 5) {
+ op.u.setvcpumap.vcpu = vcpu;
+ op.u.setvcpumap.cpumap.bitmap = bitmap;
+ op.u.setvcpumap.cpumap.nr_cpus = nr_cpus;
+ } else {
+ op.u.setvcpumapd5.vcpu = vcpu;
+ op.u.setvcpumapd5.cpumap.bitmap.v = bitmap;
+ op.u.setvcpumapd5.cpumap.nr_cpus = nr_cpus;
+ }
+ ret = xenHypervisorDoV2Dom(handle, &op);
+ VIR_FREE(new);
+
+ if (unlock_pages(cpumap, maplen) < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " release");
+ ret = -1;
+ }
+ } else {
+ cpumap_t xen_cpumap; /* limited to 64 CPUs in old hypervisors */
+ uint64_t *pm = &xen_cpumap;
+ int j;
+
+ if ((maplen > (int)sizeof(cpumap_t)) || (sizeof(cpumap_t) & 7))
+ return (-1);
+
+ memset(pm, 0, sizeof(cpumap_t));
+ for (j = 0; j < maplen; j++)
+ *(pm + (j / 8)) |= cpumap[j] << (8 * (j & 7));
+
+ if (hypervisor_version == 1) {
+ xen_op_v1 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V1_OP_SETVCPUMAP;
+ op.u.setvcpumap.domain = (domid_t) id;
+ op.u.setvcpumap.vcpu = vcpu;
+ op.u.setvcpumap.cpumap = xen_cpumap;
+ ret = xenHypervisorDoV1Op(handle, &op);
+ } else if (hypervisor_version == 0) {
+ xen_op_v0 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V0_OP_SETVCPUMAP;
+ op.u.setvcpumap.domain = (domid_t) id;
+ op.u.setvcpumap.vcpu = vcpu;
+ op.u.setvcpumap.cpumap = xen_cpumap;
+ ret = xenHypervisorDoV0Op(handle, &op);
+ }
+ }
+ return(ret);
+}
+#endif /* !PROXY*/
+
+/**
+ * virXen_getvcpusinfo:
+ * @handle: the hypervisor handle
+ * @id: the domain id
+ * @vcpu: the vcpu to map
+ * @cpumap: the bitmap for this vcpu
+ * @maplen: the size of the bitmap in bytes
+ *
+ * Do a low level hypercall to change the pinning for vcpu
+ *
+ * Returns 0 or -1 in case of failure
+ */
+static int
+virXen_getvcpusinfo(int handle, int id, unsigned int vcpu, virVcpuInfoPtr ipt,
+ unsigned char *cpumap, int maplen)
+{
+ int ret = -1;
+
+ if (hypervisor_version > 1) {
+ xen_op_v2_dom op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V2_OP_GETVCPUINFO;
+ op.domain = (domid_t) id;
+ if (dom_interface_version < 5)
+ op.u.getvcpuinfo.vcpu = (uint16_t) vcpu;
+ else
+ op.u.getvcpuinfod5.vcpu = (uint16_t) vcpu;
+ ret = xenHypervisorDoV2Dom(handle, &op);
+
+ if (ret < 0)
+ return(-1);
+ ipt->number = vcpu;
+ if (dom_interface_version < 5) {
+ if (op.u.getvcpuinfo.online) {
+ if (op.u.getvcpuinfo.running)
+ ipt->state = VIR_VCPU_RUNNING;
+ if (op.u.getvcpuinfo.blocked)
+ ipt->state = VIR_VCPU_BLOCKED;
+ } else
+ ipt->state = VIR_VCPU_OFFLINE;
+
+ ipt->cpuTime = op.u.getvcpuinfo.cpu_time;
+ ipt->cpu = op.u.getvcpuinfo.online ? (int)op.u.getvcpuinfo.cpu : -1;
+ } else {
+ if (op.u.getvcpuinfod5.online) {
+ if (op.u.getvcpuinfod5.running)
+ ipt->state = VIR_VCPU_RUNNING;
+ if (op.u.getvcpuinfod5.blocked)
+ ipt->state = VIR_VCPU_BLOCKED;
+ } else
+ ipt->state = VIR_VCPU_OFFLINE;
+
+ ipt->cpuTime = op.u.getvcpuinfod5.cpu_time;
+ ipt->cpu = op.u.getvcpuinfod5.online ? (int)op.u.getvcpuinfod5.cpu : -1;
+ }
+ if ((cpumap != NULL) && (maplen > 0)) {
+ if (lock_pages(cpumap, maplen) < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " locking");
+ return (-1);
+ }
+ memset(cpumap, 0, maplen);
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V2_OP_GETVCPUMAP;
+ op.domain = (domid_t) id;
+ if (dom_interface_version < 5) {
+ op.u.getvcpumap.vcpu = vcpu;
+ op.u.getvcpumap.cpumap.bitmap = cpumap;
+ op.u.getvcpumap.cpumap.nr_cpus = maplen * 8;
+ } else {
+ op.u.getvcpumapd5.vcpu = vcpu;
+ op.u.getvcpumapd5.cpumap.bitmap.v = cpumap;
+ op.u.getvcpumapd5.cpumap.nr_cpus = maplen * 8;
+ }
+ ret = xenHypervisorDoV2Dom(handle, &op);
+ if (unlock_pages(cpumap, maplen) < 0) {
+ virXenError(NULL, VIR_ERR_XEN_CALL, " release");
+ ret = -1;
+ }
+ }
+ } else {
+ int mapl = maplen;
+ int cpu;
+
+ if (maplen > (int)sizeof(cpumap_t))
+ mapl = (int)sizeof(cpumap_t);
+
+ if (hypervisor_version == 1) {
+ xen_op_v1 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V1_OP_GETVCPUINFO;
+ op.u.getvcpuinfo.domain = (domid_t) id;
+ op.u.getvcpuinfo.vcpu = vcpu;
+ ret = xenHypervisorDoV1Op(handle, &op);
+ if (ret < 0)
+ return(-1);
+ ipt->number = vcpu;
+ if (op.u.getvcpuinfo.online) {
+ if (op.u.getvcpuinfo.running) ipt->state = VIR_VCPU_RUNNING;
+ if (op.u.getvcpuinfo.blocked) ipt->state = VIR_VCPU_BLOCKED;
+ }
+ else ipt->state = VIR_VCPU_OFFLINE;
+ ipt->cpuTime = op.u.getvcpuinfo.cpu_time;
+ ipt->cpu = op.u.getvcpuinfo.online ? (int)op.u.getvcpuinfo.cpu : -1;
+ if ((cpumap != NULL) && (maplen > 0)) {
+ for (cpu = 0; cpu < (mapl * 8); cpu++) {
+ if (op.u.getvcpuinfo.cpumap & ((uint64_t)1<<cpu))
+ VIR_USE_CPU(cpumap, cpu);
+ }
+ }
+ } else if (hypervisor_version == 0) {
+ xen_op_v1 op;
+
+ memset(&op, 0, sizeof(op));
+ op.cmd = XEN_V0_OP_GETVCPUINFO;
+ op.u.getvcpuinfo.domain = (domid_t) id;
+ op.u.getvcpuinfo.vcpu = vcpu;
+ ret = xenHypervisorDoV0Op(handle, &op);
+ if (ret < 0)
+ return(-1);
+ ipt->number = vcpu;
+ if (op.u.getvcpuinfo.online) {
+ if (op.u.getvcpuinfo.running) ipt->state = VIR_VCPU_RUNNING;
+ if (op.u.getvcpuinfo.blocked) ipt->state = VIR_VCPU_BLOCKED;
+ }
+ else ipt->state = VIR_VCPU_OFFLINE;
+ ipt->cpuTime = op.u.getvcpuinfo.cpu_time;
+ ipt->cpu = op.u.getvcpuinfo.online ? (int)op.u.getvcpuinfo.cpu : -1;
+ if ((cpumap != NULL) && (maplen > 0)) {
+ for (cpu = 0; cpu < (mapl * 8); cpu++) {
+ if (op.u.getvcpuinfo.cpumap & ((uint64_t)1<<cpu))
+ VIR_USE_CPU(cpumap, cpu);
+ }
+ }
+ }
+ }
+ return(ret);
+}
+
+/**
+ * xenHypervisorInit:
+ *
+ * Initialize the hypervisor layer. Try to detect the kind of interface
+ * used i.e. pre or post changeset 10277
+ */
+int
+xenHypervisorInit(void)
+{
+ int fd, ret, cmd, errcode;
+ hypercall_t hc;
+ v0_hypercall_t v0_hc;
+ xen_getdomaininfo info;
+ virVcpuInfoPtr ipt = NULL;
+
+ if (initialized) {
+ if (hypervisor_version == -1)
+ return (-1);
+ return(0);
+ }
+ initialized = 1;
+ in_init = 1;
+
+ /* Compile regular expressions used by xenHypervisorGetCapabilities.
+ * Note that errors here are really internal errors since these
+ * regexps should never fail to compile.
+ */
+ errcode = regcomp (&flags_hvm_rec, flags_hvm_re, REG_EXTENDED);
+ if (errcode != 0) {
+ char error[100];
+ regerror (errcode, &flags_hvm_rec, error, sizeof error);
+ regfree (&flags_hvm_rec);
+ virXenError (NULL, VIR_ERR_INTERNAL_ERROR, "%s", error);
+ in_init = 0;
+ return -1;
+ }
+ errcode = regcomp (&flags_pae_rec, flags_pae_re, REG_EXTENDED);
+ if (errcode != 0) {
+ char error[100];
+ regerror (errcode, &flags_pae_rec, error, sizeof error);
+ regfree (&flags_pae_rec);
+ regfree (&flags_hvm_rec);
+ virXenError (NULL, VIR_ERR_INTERNAL_ERROR, "%s", error);
+ in_init = 0;
+ return -1;
+ }
+ errcode = regcomp (&xen_cap_rec, xen_cap_re, REG_EXTENDED);
+ if (errcode != 0) {
+ char error[100];
+ regerror (errcode, &xen_cap_rec, error, sizeof error);
+ regfree (&xen_cap_rec);
+ regfree (&flags_pae_rec);
+ regfree (&flags_hvm_rec);
+ virXenError (NULL, VIR_ERR_INTERNAL_ERROR, "%s", error);
+ in_init = 0;
+ return -1;
+ }
+
+ /* Xen hypervisor version detection begins. */
+ ret = open(XEN_HYPERVISOR_SOCKET, O_RDWR);
+ if (ret < 0) {
+ hypervisor_version = -1;
+ return(-1);
+ }
+ fd = ret;
+
+ /*
+ * The size of the hypervisor call block changed July 2006
+ * this detect if we are using the new or old hypercall_t structure
+ */
+ hc.op = __HYPERVISOR_xen_version;
+ hc.arg[0] = (unsigned long) XENVER_version;
+ hc.arg[1] = 0;
+
+ cmd = IOCTL_PRIVCMD_HYPERCALL;
+ ret = ioctl(fd, cmd, (unsigned long) &hc);
+
+ if ((ret != -1) && (ret != 0)) {
+ DEBUG("Using new hypervisor call: %X\n", ret);
+ hv_version = ret;
+ xen_ioctl_hypercall_cmd = cmd;
+ goto detect_v2;
+ }
+
+#ifndef __sun
+ /*
+ * check if the old hypercall are actually working
+ */
+ v0_hc.op = __HYPERVISOR_xen_version;
+ v0_hc.arg[0] = (unsigned long) XENVER_version;
+ v0_hc.arg[1] = 0;
+ cmd = _IOC(_IOC_NONE, 'P', 0, sizeof(v0_hypercall_t));
+ ret = ioctl(fd, cmd, (unsigned long) &v0_hc);
+ if ((ret != -1) && (ret != 0)) {
+ DEBUG("Using old hypervisor call: %X\n", ret);
+ hv_version = ret;
+ xen_ioctl_hypercall_cmd = cmd;
+ hypervisor_version = 0;
+ goto done;
+ }
+#endif
+
+ /*
+ * we failed to make any hypercall
+ */
+
+ hypervisor_version = -1;
+ virXenError(NULL, VIR_ERR_XEN_CALL, " ioctl %lu",
+ (unsigned long) IOCTL_PRIVCMD_HYPERCALL);
+ close(fd);
+ in_init = 0;
+ return(-1);
+
+ detect_v2:
+ /*
+ * The hypercalls were refactored into 3 different section in August 2006
+ * Try to detect if we are running a version post 3.0.2 with the new ones
+ * or the old ones
+ */
+ hypervisor_version = 2;
+
+ if (VIR_ALLOC(ipt) < 0) {
+ virReportOOMError(NULL);
+ return(-1);
+ }
+ /* Currently consider RHEL5.0 Fedora7, xen-3.1, and xen-unstable */
+ sys_interface_version = 2; /* XEN_SYSCTL_INTERFACE_VERSION */
+ if (virXen_getdomaininfo(fd, 0, &info) == 1) {
+ /* RHEL 5.0 */
+ dom_interface_version = 3; /* XEN_DOMCTL_INTERFACE_VERSION */
+ if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0){
+ DEBUG0("Using hypervisor call v2, sys ver2 dom ver3\n");
+ goto done;
+ }
+ /* Fedora 7 */
+ dom_interface_version = 4; /* XEN_DOMCTL_INTERFACE_VERSION */
+ if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0){
+ DEBUG0("Using hypervisor call v2, sys ver2 dom ver4\n");
+ goto done;
+ }
+ }
+
+ sys_interface_version = 3; /* XEN_SYSCTL_INTERFACE_VERSION */
+ if (virXen_getdomaininfo(fd, 0, &info) == 1) {
+ /* xen-3.1 */
+ dom_interface_version = 5; /* XEN_DOMCTL_INTERFACE_VERSION */
+ if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0){
+ DEBUG0("Using hypervisor call v2, sys ver3 dom ver5\n");
+ goto done;
+ }
+ }
+
+ sys_interface_version = 4; /* XEN_SYSCTL_INTERFACE_VERSION */
+ if (virXen_getdomaininfo(fd, 0, &info) == 1) {
+ /* Fedora 8 */
+ dom_interface_version = 5; /* XEN_DOMCTL_INTERFACE_VERSION */
+ if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0){
+ DEBUG0("Using hypervisor call v2, sys ver4 dom ver5\n");
+ goto done;
+ }
+ }
+
+ sys_interface_version = 6; /* XEN_SYSCTL_INTERFACE_VERSION */
+ if (virXen_getdomaininfo(fd, 0, &info) == 1) {
+ /* Xen 3.2, Fedora 9 */
+ dom_interface_version = 5; /* XEN_DOMCTL_INTERFACE_VERSION */
+ if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0){
+ DEBUG0("Using hypervisor call v2, sys ver6 dom ver5\n");
+ goto done;
+ }
+ }
+
+ hypervisor_version = 1;
+ sys_interface_version = -1;
+ if (virXen_getdomaininfo(fd, 0, &info) == 1) {
+ DEBUG0("Using hypervisor call v1\n");
+ goto done;
+ }
+
+ /*
+ * we failed to make the getdomaininfolist hypercall
+ */
+
+ DEBUG0("Failed to find any Xen hypervisor method\n");
+ hypervisor_version = -1;
+ virXenError(NULL, VIR_ERR_XEN_CALL, " ioctl %lu",
+ (unsigned long)IOCTL_PRIVCMD_HYPERCALL);
+ close(fd);
+ in_init = 0;
+ VIR_FREE(ipt);
+ return(-1);
+
+ done:
+ close(fd);
+ in_init = 0;
+ VIR_FREE(ipt);
+ return(0);
+}
+
+/**
+ * xenHypervisorOpen:
+ * @conn: pointer to the connection block
+ * @name: URL for the target, NULL for local
+ * @flags: combination of virDrvOpenFlag(s)
+ *
+ * Connects to the Xen hypervisor.
+ *
+ * Returns 0 or -1 in case of error.
+ */
+virDrvOpenStatus
+xenHypervisorOpen(virConnectPtr conn,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED)
+{
+ int ret;
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ if (initialized == 0)
+ if (xenHypervisorInit() == -1)
+ return -1;
+
+ priv->handle = -1;
+
+ ret = open(XEN_HYPERVISOR_SOCKET, O_RDWR);
+ if (ret < 0) {
+ virXenError(conn, VIR_ERR_NO_XEN, "%s", XEN_HYPERVISOR_SOCKET);
+ return (-1);
+ }
+
+ priv->handle = ret;
+
+ return(0);
+}
+
+/**
+ * xenHypervisorClose:
+ * @conn: pointer to the connection block
+ *
+ * Close the connection to the Xen hypervisor.
+ *
+ * Returns 0 in case of success or -1 in case of error.
+ */
+int
+xenHypervisorClose(virConnectPtr conn)
+{
+ int ret;
+ xenUnifiedPrivatePtr priv;
+
+ if (conn == NULL)
+ return (-1);
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ if (priv->handle < 0)
+ return -1;
+
+ ret = close(priv->handle);
+ if (ret < 0)
+ return (-1);
+
+ return (0);
+}
+
+
+/**
+ * xenHypervisorGetVersion:
+ * @conn: pointer to the connection block
+ * @hvVer: where to store the version
+ *
+ * Call the hypervisor to extracts his own internal API version
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+xenHypervisorGetVersion(virConnectPtr conn, unsigned long *hvVer)
+{
+ xenUnifiedPrivatePtr priv;
+
+ if (conn == NULL)
+ return -1;
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->handle < 0 || hvVer == NULL)
+ return (-1);
+ *hvVer = (hv_version >> 16) * 1000000 + (hv_version & 0xFFFF) * 1000;
+ return(0);
+}
+
+struct guest_arch {
+ const char *model;
+ int bits;
+ int hvm;
+ int pae;
+ int nonpae;
+ int ia64_be;
+};
+
+
+static virCapsPtr
+xenHypervisorBuildCapabilities(virConnectPtr conn,
+ const char *hostmachine,
+ int host_pae,
+ const char *hvm_type,
+ struct guest_arch *guest_archs,
+ int nr_guest_archs) {
+ virCapsPtr caps;
+ int i;
+ int hv_major = hv_version >> 16;
+ int hv_minor = hv_version & 0xFFFF;
+
+ if ((caps = virCapabilitiesNew(hostmachine, 1, 1)) == NULL)
+ goto no_memory;
+
+ virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x00, 0x16, 0x3e });
+
+ if (hvm_type && STRNEQ(hvm_type, "") &&
+ virCapabilitiesAddHostFeature(caps, hvm_type) < 0)
+ goto no_memory;
+ if (host_pae &&
+ virCapabilitiesAddHostFeature(caps, "pae") < 0)
+ goto no_memory;
+
+
+ if (virCapabilitiesAddHostMigrateTransport(caps,
+ "xenmigr") < 0)
+ goto no_memory;
+
+
+ if (sys_interface_version >= SYS_IFACE_MIN_VERS_NUMA) {
+ if (xenDaemonNodeGetTopology(conn, caps) != 0) {
+ virCapabilitiesFree(caps);
+ return NULL;
+ }
+ }
+
+ for (i = 0; i < nr_guest_archs; ++i) {
+ virCapsGuestPtr guest;
+ char const *const xen_machines[] = {guest_archs[i].hvm ? "xenfv" : "xenpv"};
+ virCapsGuestMachinePtr *machines;
+
+ if ((machines = virCapabilitiesAllocMachines(xen_machines, 1)) == NULL)
+ goto no_memory;
+
+ if ((guest = virCapabilitiesAddGuest(caps,
+ guest_archs[i].hvm ? "hvm" : "xen",
+ guest_archs[i].model,
+ guest_archs[i].bits,
+ (STREQ(hostmachine, "x86_64") ?
+ "/usr/lib64/xen/bin/qemu-dm" :
+ "/usr/lib/xen/bin/qemu-dm"),
+ (guest_archs[i].hvm ?
+ "/usr/lib/xen/boot/hvmloader" :
+ NULL),
+ 1,
+ machines)) == NULL) {
+ virCapabilitiesFreeMachines(machines, 1);
+ goto no_memory;
+ }
+ machines = NULL;
+
+ if (virCapabilitiesAddGuestDomain(guest,
+ "xen",
+ NULL,
+ NULL,
+ 0,
+ NULL) == NULL)
+ goto no_memory;
+
+ if (guest_archs[i].pae &&
+ virCapabilitiesAddGuestFeature(guest,
+ "pae",
+ 1,
+ 0) == NULL)
+ goto no_memory;
+
+ if (guest_archs[i].nonpae &&
+ virCapabilitiesAddGuestFeature(guest,
+ "nonpae",
+ 1,
+ 0) == NULL)
+ goto no_memory;
+
+ if (guest_archs[i].ia64_be &&
+ virCapabilitiesAddGuestFeature(guest,
+ "ia64_be",
+ 1,
+ 0) == NULL)
+ goto no_memory;
+
+ if (guest_archs[i].hvm) {
+ if (virCapabilitiesAddGuestFeature(guest,
+ "acpi",
+ 1, 1) == NULL)
+ goto no_memory;
+
+ // In Xen 3.1.0, APIC is always on and can't be toggled
+ if (virCapabilitiesAddGuestFeature(guest,
+ "apic",
+ 1,
+ (hv_major > 3 &&
+ hv_minor > 0 ?
+ 0 : 1)) == NULL)
+ goto no_memory;
+ }
+ }
+
+ return caps;
+
+ no_memory:
+ virCapabilitiesFree(caps);
+ return NULL;
+}
+
+#ifdef __sun
+
+static int
+get_cpu_flags(virConnectPtr conn, const char **hvm, int *pae, int *longmode)
+{
+ struct {
+ uint32_t r_eax, r_ebx, r_ecx, r_edx;
+ } regs;
+
+ char tmpbuf[20];
+ int ret = 0;
+ int fd;
+
+ /* returns -1, errno 22 if in 32-bit mode */
+ *longmode = (sysinfo(SI_ARCHITECTURE_64, tmpbuf, sizeof(tmpbuf)) != -1);
+
+ if ((fd = open("/dev/cpu/self/cpuid", O_RDONLY)) == -1 ||
+ pread(fd, ®s, sizeof(regs), 0) != sizeof(regs)) {
+ char ebuf[1024];
+ virXenError(conn, VIR_ERR_SYSTEM_ERROR,
+ "couldn't read CPU flags: %s", virStrerror(errno, ebuf, sizeof ebuf));
+ goto out;
+ }
+
+ *pae = 0;
+ *hvm = "";
+
+ if (STREQLEN((const char *)®s.r_ebx, "AuthcAMDenti", 12)) {
+ if (pread(fd, ®s, sizeof (regs), 0x80000001) == sizeof (regs)) {
+ /* Read secure virtual machine bit (bit 2 of ECX feature ID) */
+ if ((regs.r_ecx >> 2) & 1) {
+ *hvm = "svm";
+ }
+ if ((regs.r_edx >> 6) & 1)
+ *pae = 1;
+ }
+ } else if (STREQLEN((const char *)®s.r_ebx, "GenuntelineI", 12)) {
+ if (pread(fd, ®s, sizeof (regs), 0x00000001) == sizeof (regs)) {
+ /* Read VMXE feature bit (bit 5 of ECX feature ID) */
+ if ((regs.r_ecx >> 5) & 1)
+ *hvm = "vmx";
+ if ((regs.r_edx >> 6) & 1)
+ *pae = 1;
+ }
+ }
+
+ ret = 1;
+
+out:
+ if (fd != -1)
+ close(fd);
+ return ret;
+}
+
+static virCapsPtr
+xenHypervisorMakeCapabilitiesSunOS(virConnectPtr conn)
+{
+ struct guest_arch guest_arches[32];
+ int i = 0;
+ virCapsPtr caps = NULL;
+ struct utsname utsname;
+ int pae, longmode;
+ const char *hvm;
+
+ if (!get_cpu_flags(conn, &hvm, &pae, &longmode))
+ return NULL;
+
+ /* Really, this never fails - look at the man-page. */
+ uname (&utsname);
+
+ guest_arches[i].model = "i686";
+ guest_arches[i].bits = 32;
+ guest_arches[i].hvm = 0;
+ guest_arches[i].pae = pae;
+ guest_arches[i].nonpae = !pae;
+ guest_arches[i].ia64_be = 0;
+ i++;
+
+ if (longmode) {
+ guest_arches[i].model = "x86_64";
+ guest_arches[i].bits = 64;
+ guest_arches[i].hvm = 0;
+ guest_arches[i].pae = 0;
+ guest_arches[i].nonpae = 0;
+ guest_arches[i].ia64_be = 0;
+ i++;
+ }
+
+ if (hvm[0] != '\0') {
+ guest_arches[i].model = "i686";
+ guest_arches[i].bits = 32;
+ guest_arches[i].hvm = 1;
+ guest_arches[i].pae = pae;
+ guest_arches[i].nonpae = 1;
+ guest_arches[i].ia64_be = 0;
+ i++;
+
+ if (longmode) {
+ guest_arches[i].model = "x86_64";
+ guest_arches[i].bits = 64;
+ guest_arches[i].hvm = 1;
+ guest_arches[i].pae = 0;
+ guest_arches[i].nonpae = 0;
+ guest_arches[i].ia64_be = 0;
+ i++;
+ }
+ }
+
+ if ((caps = xenHypervisorBuildCapabilities(conn,
+ utsname.machine,
+ pae, hvm,
+ guest_arches, i)) == NULL)
+ virReportOOMError(NULL);
+
+ return caps;
+}
+
+#endif /* __sun */
+
+/**
+ * xenHypervisorMakeCapabilitiesInternal:
+ * @conn: pointer to the connection block
+ * @cpuinfo: file handle containing /proc/cpuinfo data, or NULL
+ * @capabilities: file handle containing /sys/hypervisor/properties/capabilities data, or NULL
+ *
+ * Return the capabilities of this hypervisor.
+ */
+virCapsPtr
+xenHypervisorMakeCapabilitiesInternal(virConnectPtr conn,
+ const char *hostmachine,
+ FILE *cpuinfo, FILE *capabilities)
+{
+ char line[1024], *str, *token;
+ regmatch_t subs[4];
+ char *saveptr = NULL;
+ int i;
+
+ char hvm_type[4] = ""; /* "vmx" or "svm" (or "" if not in CPU). */
+ int host_pae = 0;
+ struct guest_arch guest_archs[32];
+ int nr_guest_archs = 0;
+ virCapsPtr caps = NULL;
+
+ memset(guest_archs, 0, sizeof(guest_archs));
+
+ /* /proc/cpuinfo: flags: Intel calls HVM "vmx", AMD calls it "svm".
+ * It's not clear if this will work on IA64, let alone other
+ * architectures and non-Linux. (XXX)
+ */
+ if (cpuinfo) {
+ while (fgets (line, sizeof line, cpuinfo)) {
+ if (regexec (&flags_hvm_rec, line, sizeof(subs)/sizeof(regmatch_t), subs, 0) == 0
+ && subs[0].rm_so != -1) {
+ strncpy (hvm_type,
+ &line[subs[1].rm_so], subs[1].rm_eo-subs[1].rm_so+1);
+ hvm_type[subs[1].rm_eo-subs[1].rm_so] = '\0';
+ } else if (regexec (&flags_pae_rec, line, 0, NULL, 0) == 0)
+ host_pae = 1;
+ }
+ }
+
+ /* Most of the useful info is in /sys/hypervisor/properties/capabilities
+ * which is documented in the code in xen-unstable.hg/xen/arch/.../setup.c.
+ *
+ * It is a space-separated list of supported guest architectures.
+ *
+ * For x86:
+ * TYP-VER-ARCH[p]
+ * ^ ^ ^ ^
+ * | | | +-- PAE supported
+ * | | +------- x86_32 or x86_64
+ * | +----------- the version of Xen, eg. "3.0"
+ * +--------------- "xen" or "hvm" for para or full virt respectively
+ *
+ * For PPC this file appears to be always empty (?)
+ *
+ * For IA64:
+ * TYP-VER-ARCH[be]
+ * ^ ^ ^ ^
+ * | | | +-- Big-endian supported
+ * | | +------- always "ia64"
+ * | +----------- the version of Xen, eg. "3.0"
+ * +--------------- "xen" or "hvm" for para or full virt respectively
+ */
+
+ /* Expecting one line in this file - ignore any more. */
+ if ((capabilities) && (fgets (line, sizeof line, capabilities))) {
+ /* Split the line into tokens. strtok_r is OK here because we "own"
+ * this buffer. Parse out the features from each token.
+ */
+ for (str = line, nr_guest_archs = 0;
+ nr_guest_archs < sizeof guest_archs / sizeof guest_archs[0]
+ && (token = strtok_r (str, " ", &saveptr)) != NULL;
+ str = NULL) {
+
+ if (regexec (&xen_cap_rec, token, sizeof subs / sizeof subs[0],
+ subs, 0) == 0) {
+ int hvm = STRPREFIX(&token[subs[1].rm_so], "hvm");
+ const char *model;
+ int bits, pae = 0, nonpae = 0, ia64_be = 0;
+
+ if (STRPREFIX(&token[subs[2].rm_so], "x86_32")) {
+ model = "i686";
+ bits = 32;
+ if (subs[3].rm_so != -1 &&
+ STRPREFIX(&token[subs[3].rm_so], "p"))
+ pae = 1;
+ else
+ nonpae = 1;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "x86_64")) {
+ model = "x86_64";
+ bits = 64;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "ia64")) {
+ model = "ia64";
+ bits = 64;
+ if (subs[3].rm_so != -1 &&
+ STRPREFIX(&token[subs[3].rm_so], "be"))
+ ia64_be = 1;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "powerpc64")) {
+ model = "ppc64";
+ bits = 64;
+ } else {
+ /* XXX surely no other Xen archs exist */
+ continue;
+ }
+
+ /* Search for existing matching (model,hvm) tuple */
+ for (i = 0 ; i < nr_guest_archs ; i++) {
+ if (STREQ(guest_archs[i].model, model) &&
+ guest_archs[i].hvm == hvm) {
+ break;
+ }
+ }
+
+ /* Too many arch flavours - highly unlikely ! */
+ if (i >= ARRAY_CARDINALITY(guest_archs))
+ continue;
+ /* Didn't find a match, so create a new one */
+ if (i == nr_guest_archs)
+ nr_guest_archs++;
+
+ guest_archs[i].model = model;
+ guest_archs[i].bits = bits;
+ guest_archs[i].hvm = hvm;
+
+ /* Careful not to overwrite a previous positive
+ setting with a negative one here - some archs
+ can do both pae & non-pae, but Xen reports
+ separately capabilities so we're merging archs */
+ if (pae)
+ guest_archs[i].pae = pae;
+ if (nonpae)
+ guest_archs[i].nonpae = nonpae;
+ if (ia64_be)
+ guest_archs[i].ia64_be = ia64_be;
+ }
+ }
+ }
+
+ if ((caps = xenHypervisorBuildCapabilities(conn,
+ hostmachine,
+ host_pae,
+ hvm_type,
+ guest_archs,
+ nr_guest_archs)) == NULL)
+ goto no_memory;
+
+ return caps;
+
+ no_memory:
+ virReportOOMError(NULL);
+ virCapabilitiesFree(caps);
+ return NULL;
+}
+
+/**
+ * xenHypervisorMakeCapabilities:
+ *
+ * Return the capabilities of this hypervisor.
+ */
+virCapsPtr
+xenHypervisorMakeCapabilities(virConnectPtr conn)
+{
+#ifdef __sun
+ return xenHypervisorMakeCapabilitiesSunOS(conn);
+#else
+ virCapsPtr caps;
+ FILE *cpuinfo, *capabilities;
+ struct utsname utsname;
+
+ /* Really, this never fails - look at the man-page. */
+ uname (&utsname);
+
+ cpuinfo = fopen ("/proc/cpuinfo", "r");
+ if (cpuinfo == NULL) {
+ if (errno != ENOENT) {
+ virReportSystemError(conn, errno,
+ _("cannot read file %s"),
+ "/proc/cpuinfo");
+ return NULL;
+ }
+ }
+
+ capabilities = fopen ("/sys/hypervisor/properties/capabilities", "r");
+ if (capabilities == NULL) {
+ if (errno != ENOENT) {
+ fclose(cpuinfo);
+ virReportSystemError(conn, errno,
+ _("cannot read file %s"),
+ "/sys/hypervisor/properties/capabilities");
+ return NULL;
+ }
+ }
+
+ caps = xenHypervisorMakeCapabilitiesInternal(conn,
+ utsname.machine,
+ cpuinfo,
+ capabilities);
+
+ if (cpuinfo)
+ fclose(cpuinfo);
+ if (capabilities)
+ fclose(capabilities);
+
+ return caps;
+#endif /* __sun */
+}
+
+
+
+/**
+ * xenHypervisorGetCapabilities:
+ * @conn: pointer to the connection block
+ *
+ * Return the capabilities of this hypervisor.
+ */
+char *
+xenHypervisorGetCapabilities (virConnectPtr conn)
+{
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+ char *xml;
+
+ if (!(xml = virCapabilitiesFormatXML(priv->caps))) {
+ virReportOOMError(conn);
+ return NULL;
+ }
+
+ return xml;
+}
+
+
+/**
+ * xenHypervisorNumOfDomains:
+ * @conn: pointer to the connection block
+ *
+ * Provides the number of active domains.
+ *
+ * Returns the number of domain found or -1 in case of error
+ */
+int
+xenHypervisorNumOfDomains(virConnectPtr conn)
+{
+ xen_getdomaininfolist dominfos;
+ int ret, nbids;
+ static int last_maxids = 2;
+ int maxids = last_maxids;
+ xenUnifiedPrivatePtr priv;
+
+ if (conn == NULL)
+ return -1;
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->handle < 0)
+ return (-1);
+
+ retry:
+ if (!(XEN_GETDOMAININFOLIST_ALLOC(dominfos, maxids))) {
+ virReportOOMError(conn);
+ return(-1);
+ }
+
+ XEN_GETDOMAININFOLIST_CLEAR(dominfos, maxids);
+
+ ret = virXen_getdomaininfolist(priv->handle, 0, maxids, &dominfos);
+
+ XEN_GETDOMAININFOLIST_FREE(dominfos);
+
+ if (ret < 0)
+ return (-1);
+
+ nbids = ret;
+ /* Can't possibly have more than 65,000 concurrent guests
+ * so limit how many times we try, to avoid increasing
+ * without bound & thus allocating all of system memory !
+ * XXX I'll regret this comment in a few years time ;-)
+ */
+ if (nbids == maxids) {
+ if (maxids < 65000) {
+ last_maxids *= 2;
+ maxids *= 2;
+ goto retry;
+ }
+ nbids = -1;
+ }
+ if ((nbids < 0) || (nbids > maxids))
+ return(-1);
+ return(nbids);
+}
+
+/**
+ * xenHypervisorListDomains:
+ * @conn: pointer to the connection block
+ * @ids: array to collect the list of IDs of active domains
+ * @maxids: size of @ids
+ *
+ * Collect the list of active domains, and store their ID in @maxids
+ *
+ * Returns the number of domain found or -1 in case of error
+ */
+int
+xenHypervisorListDomains(virConnectPtr conn, int *ids, int maxids)
+{
+ xen_getdomaininfolist dominfos;
+ int ret, nbids, i;
+ xenUnifiedPrivatePtr priv;
+
+ if (conn == NULL)
+ return -1;
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->handle < 0 ||
+ (ids == NULL) || (maxids < 0))
+ return (-1);
+
+ if (maxids == 0)
+ return(0);
+
+ if (!(XEN_GETDOMAININFOLIST_ALLOC(dominfos, maxids))) {
+ virReportOOMError(conn);
+ return(-1);
+ }
+
+ XEN_GETDOMAININFOLIST_CLEAR(dominfos, maxids);
+ memset(ids, 0, maxids * sizeof(int));
+
+ ret = virXen_getdomaininfolist(priv->handle, 0, maxids, &dominfos);
+
+ if (ret < 0) {
+ XEN_GETDOMAININFOLIST_FREE(dominfos);
+ return (-1);
+ }
+
+ nbids = ret;
+ if ((nbids < 0) || (nbids > maxids)) {
+ XEN_GETDOMAININFOLIST_FREE(dominfos);
+ return(-1);
+ }
+
+ for (i = 0;i < nbids;i++) {
+ ids[i] = XEN_GETDOMAININFOLIST_DOMAIN(dominfos, i);
+ }
+
+ XEN_GETDOMAININFOLIST_FREE(dominfos);
+ return (nbids);
+}
+
+
+#ifndef PROXY
+char *
+xenHypervisorDomainGetOSType (virDomainPtr dom)
+{
+ xenUnifiedPrivatePtr priv;
+ xen_getdomaininfo dominfo;
+
+ priv = (xenUnifiedPrivatePtr) dom->conn->privateData;
+ if (priv->handle < 0)
+ return (NULL);
+
+ /* HV's earlier than 3.1.0 don't include the HVM flags in guests status*/
+ if (hypervisor_version < 2 ||
+ dom_interface_version < 4)
+ return (NULL);
+
+ XEN_GETDOMAININFO_CLEAR(dominfo);
+
+ if (virXen_getdomaininfo(priv->handle, dom->id, &dominfo) < 0)
+ return (NULL);
+
+ if (XEN_GETDOMAININFO_DOMAIN(dominfo) != dom->id)
+ return (NULL);
+
+ if (XEN_GETDOMAININFO_FLAGS(dominfo) & DOMFLAGS_HVM)
+ return strdup("hvm");
+ return strdup("linux");
+}
+
+virDomainPtr
+xenHypervisorLookupDomainByID(virConnectPtr conn,
+ int id)
+{
+ xenUnifiedPrivatePtr priv;
+ xen_getdomaininfo dominfo;
+ virDomainPtr ret;
+ char *name;
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->handle < 0)
+ return (NULL);
+
+ XEN_GETDOMAININFO_CLEAR(dominfo);
+
+ if (virXen_getdomaininfo(priv->handle, id, &dominfo) < 0)
+ return (NULL);
+
+ if (XEN_GETDOMAININFO_DOMAIN(dominfo) != id)
+ return (NULL);
+
+ xenUnifiedLock(priv);
+ name = xenStoreDomainGetName(conn, id);
+ xenUnifiedUnlock(priv);
+ if (!name)
+ return (NULL);
+
+ ret = virGetDomain(conn, name, XEN_GETDOMAININFO_UUID(dominfo));
+ if (ret)
+ ret->id = id;
+ VIR_FREE(name);
+ return ret;
+}
+
+
+virDomainPtr
+xenHypervisorLookupDomainByUUID(virConnectPtr conn,
+ const unsigned char *uuid)
+{
+ xen_getdomaininfolist dominfos;
+ xenUnifiedPrivatePtr priv;
+ virDomainPtr ret;
+ char *name;
+ int maxids = 100, nids, i, id;
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->handle < 0)
+ return (NULL);
+
+ retry:
+ if (!(XEN_GETDOMAININFOLIST_ALLOC(dominfos, maxids))) {
+ virReportOOMError(conn);
+ return(NULL);
+ }
+
+ XEN_GETDOMAININFOLIST_CLEAR(dominfos, maxids);
+
+ nids = virXen_getdomaininfolist(priv->handle, 0, maxids, &dominfos);
+
+ if (nids < 0) {
+ XEN_GETDOMAININFOLIST_FREE(dominfos);
+ return (NULL);
+ }
+
+ /* Can't possibly have more than 65,000 concurrent guests
+ * so limit how many times we try, to avoid increasing
+ * without bound & thus allocating all of system memory !
+ * XXX I'll regret this comment in a few years time ;-)
+ */
+ if (nids == maxids) {
+ XEN_GETDOMAININFOLIST_FREE(dominfos);
+ if (maxids < 65000) {
+ maxids *= 2;
+ goto retry;
+ }
+ return (NULL);
+ }
+
+ id = -1;
+ for (i = 0 ; i < nids ; i++) {
+ if (memcmp(XEN_GETDOMAININFOLIST_UUID(dominfos, i), uuid, VIR_UUID_BUFLEN) == 0) {
+ id = XEN_GETDOMAININFOLIST_DOMAIN(dominfos, i);
+ break;
+ }
+ }
+ XEN_GETDOMAININFOLIST_FREE(dominfos);
+
+ if (id == -1)
+ return (NULL);
+
+ xenUnifiedLock(priv);
+ name = xenStoreDomainGetName(conn, id);
+ xenUnifiedUnlock(priv);
+ if (!name)
+ return (NULL);
+
+ ret = virGetDomain(conn, name, uuid);
+ if (ret)
+ ret->id = id;
+ VIR_FREE(name);
+ return ret;
+}
+#endif
+
+/**
+ * xenHypervisorGetMaxVcpus:
+ *
+ * Returns the maximum of CPU defined by Xen.
+ */
+int
+xenHypervisorGetMaxVcpus(virConnectPtr conn,
+ const char *type ATTRIBUTE_UNUSED)
+{
+ xenUnifiedPrivatePtr priv;
+
+ if (conn == NULL)
+ return -1;
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->handle < 0)
+ return (-1);
+
+ return MAX_VIRT_CPUS;
+}
+
+/**
+ * xenHypervisorGetDomMaxMemory:
+ * @conn: connection data
+ * @id: domain id
+ *
+ * Retrieve the maximum amount of physical memory allocated to a
+ * domain.
+ *
+ * Returns the memory size in kilobytes or 0 in case of error.
+ */
+unsigned long
+xenHypervisorGetDomMaxMemory(virConnectPtr conn, int id)
+{
+ xenUnifiedPrivatePtr priv;
+ xen_getdomaininfo dominfo;
+ int ret;
+
+ if (conn == NULL)
+ return 0;
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->handle < 0)
+ return 0;
+
+ if (kb_per_pages == 0) {
+ kb_per_pages = sysconf(_SC_PAGESIZE) / 1024;
+ if (kb_per_pages <= 0)
+ kb_per_pages = 4;
+ }
+
+ XEN_GETDOMAININFO_CLEAR(dominfo);
+
+ ret = virXen_getdomaininfo(priv->handle, id, &dominfo);
+
+ if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != id))
+ return (0);
+
+ return((unsigned long) XEN_GETDOMAININFO_MAX_PAGES(dominfo) * kb_per_pages);
+}
+
+#ifndef PROXY
+/**
+ * xenHypervisorGetMaxMemory:
+ * @domain: a domain object or NULL
+ *
+ * Retrieve the maximum amount of physical memory allocated to a
+ * domain. If domain is NULL, then this get the amount of memory reserved
+ * to Domain0 i.e. the domain where the application runs.
+ *
+ * Returns the memory size in kilobytes or 0 in case of error.
+ */
+static unsigned long
+xenHypervisorGetMaxMemory(virDomainPtr domain)
+{
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL))
+ return 0;
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->handle < 0 || domain->id < 0)
+ return (0);
+
+ return(xenHypervisorGetDomMaxMemory(domain->conn, domain->id));
+}
+#endif
+
+/**
+ * xenHypervisorGetDomInfo:
+ * @conn: connection data
+ * @id: the domain ID
+ * @info: the place where information should be stored
+ *
+ * Do an hypervisor call to get the related set of domain information.
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+int
+xenHypervisorGetDomInfo(virConnectPtr conn, int id, virDomainInfoPtr info)
+{
+ xenUnifiedPrivatePtr priv;
+ xen_getdomaininfo dominfo;
+ int ret;
+ uint32_t domain_flags, domain_state, domain_shutdown_cause;
+
+ if (kb_per_pages == 0) {
+ kb_per_pages = sysconf(_SC_PAGESIZE) / 1024;
+ if (kb_per_pages <= 0)
+ kb_per_pages = 4;
+ }
+
+ if (conn == NULL)
+ return -1;
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->handle < 0 || info == NULL)
+ return (-1);
+
+ memset(info, 0, sizeof(virDomainInfo));
+ XEN_GETDOMAININFO_CLEAR(dominfo);
+
+ ret = virXen_getdomaininfo(priv->handle, id, &dominfo);
+
+ if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != id))
+ return (-1);
+
+ domain_flags = XEN_GETDOMAININFO_FLAGS(dominfo);
+ domain_flags &= ~DOMFLAGS_HVM; /* Mask out HVM flags */
+ domain_state = domain_flags & 0xFF; /* Mask out high bits */
+ switch (domain_state) {
+ case DOMFLAGS_DYING:
+ info->state = VIR_DOMAIN_SHUTDOWN;
+ break;
+ case DOMFLAGS_SHUTDOWN:
+ /* The domain is shutdown. Determine the cause. */
+ domain_shutdown_cause = domain_flags >> DOMFLAGS_SHUTDOWNSHIFT;
+ switch (domain_shutdown_cause) {
+ case SHUTDOWN_crash:
+ info->state = VIR_DOMAIN_CRASHED;
+ break;
+ default:
+ info->state = VIR_DOMAIN_SHUTOFF;
+ }
+ break;
+ case DOMFLAGS_PAUSED:
+ info->state = VIR_DOMAIN_PAUSED;
+ break;
+ case DOMFLAGS_BLOCKED:
+ info->state = VIR_DOMAIN_BLOCKED;
+ break;
+ case DOMFLAGS_RUNNING:
+ info->state = VIR_DOMAIN_RUNNING;
+ break;
+ default:
+ info->state = VIR_DOMAIN_NOSTATE;
+ }
+
+ /*
+ * the API brings back the cpu time in nanoseconds,
+ * convert to microseconds, same thing convert to
+ * kilobytes from page counts
+ */
+ info->cpuTime = XEN_GETDOMAININFO_CPUTIME(dominfo);
+ info->memory = XEN_GETDOMAININFO_TOT_PAGES(dominfo) * kb_per_pages;
+ info->maxMem = XEN_GETDOMAININFO_MAX_PAGES(dominfo);
+ if(info->maxMem != UINT_MAX)
+ info->maxMem *= kb_per_pages;
+ info->nrVirtCpu = XEN_GETDOMAININFO_CPUCOUNT(dominfo);
+ return (0);
+}
+
+/**
+ * xenHypervisorGetDomainInfo:
+ * @domain: pointer to the domain block
+ * @info: the place where information should be stored
+ *
+ * Do an hypervisor call to get the related set of domain information.
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+int
+xenHypervisorGetDomainInfo(virDomainPtr domain, virDomainInfoPtr info)
+{
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL))
+ return -1;
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->handle < 0 || info == NULL ||
+ (domain->id < 0))
+ return (-1);
+
+ return(xenHypervisorGetDomInfo(domain->conn, domain->id, info));
+
+}
+
+#ifndef PROXY
+/**
+ * xenHypervisorNodeGetCellsFreeMemory:
+ * @conn: pointer to the hypervisor connection
+ * @freeMems: pointer to the array of unsigned long long
+ * @startCell: index of first cell to return freeMems info on.
+ * @maxCells: Maximum number of cells for which freeMems information can
+ * be returned.
+ *
+ * This call returns the amount of free memory in one or more NUMA cells.
+ * The @freeMems array must be allocated by the caller and will be filled
+ * with the amount of free memory in kilobytes for each cell requested,
+ * starting with startCell (in freeMems[0]), up to either
+ * (startCell + maxCells), or the number of additional cells in the node,
+ * whichever is smaller.
+ *
+ * Returns the number of entries filled in freeMems, or -1 in case of error.
+ */
+int
+xenHypervisorNodeGetCellsFreeMemory(virConnectPtr conn, unsigned long long *freeMems,
+ int startCell, int maxCells)
+{
+ xen_op_v2_sys op_sys;
+ int i, j, ret;
+ xenUnifiedPrivatePtr priv;
+
+ if (conn == NULL) {
+ virXenErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "invalid argument", 0);
+ return -1;
+ }
+
+ priv = conn->privateData;
+
+ if (priv->nbNodeCells < 0) {
+ virXenErrorFunc (conn, VIR_ERR_XEN_CALL, __FUNCTION__,
+ "cannot determine actual number of cells",0);
+ return(-1);
+ }
+
+ if ((maxCells < 1) || (startCell >= priv->nbNodeCells)) {
+ virXenErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
+ "invalid argument", 0);
+ return -1;
+ }
+
+ /*
+ * Support only sys_interface_version >=4
+ */
+ if (sys_interface_version < SYS_IFACE_MIN_VERS_NUMA) {
+ virXenErrorFunc (conn, VIR_ERR_XEN_CALL, __FUNCTION__,
+ "unsupported in sys interface < 4", 0);
+ return -1;
+ }
+
+ if (priv->handle < 0) {
+ virXenErrorFunc (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
+ "priv->handle invalid", 0);
+ return -1;
+ }
+
+ memset(&op_sys, 0, sizeof(op_sys));
+ op_sys.cmd = XEN_V2_OP_GETAVAILHEAP;
+
+ for (i = startCell, j = 0;(i < priv->nbNodeCells) && (j < maxCells);i++,j++) {
+ if (sys_interface_version >= 5)
+ op_sys.u.availheap5.node = i;
+ else
+ op_sys.u.availheap.node = i;
+ ret = xenHypervisorDoV2Sys(priv->handle, &op_sys);
+ if (ret < 0) {
+ return(-1);
+ }
+ if (sys_interface_version >= 5)
+ freeMems[j] = op_sys.u.availheap5.avail_bytes;
+ else
+ freeMems[j] = op_sys.u.availheap.avail_bytes;
+ }
+ return (j);
+}
+
+
+/**
+ * xenHypervisorPauseDomain:
+ * @domain: pointer to the domain block
+ *
+ * Do an hypervisor call to pause the given domain
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+int
+xenHypervisorPauseDomain(virDomainPtr domain)
+{
+ int ret;
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL))
+ return -1;
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->handle < 0 || domain->id < 0)
+ return (-1);
+
+ ret = virXen_pausedomain(priv->handle, domain->id);
+ if (ret < 0)
+ return (-1);
+ return (0);
+}
+
+/**
+ * xenHypervisorResumeDomain:
+ * @domain: pointer to the domain block
+ *
+ * Do an hypervisor call to resume the given domain
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+int
+xenHypervisorResumeDomain(virDomainPtr domain)
+{
+ int ret;
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL))
+ return -1;
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->handle < 0 || domain->id < 0)
+ return (-1);
+
+ ret = virXen_unpausedomain(priv->handle, domain->id);
+ if (ret < 0)
+ return (-1);
+ return (0);
+}
+
+/**
+ * xenHypervisorDestroyDomain:
+ * @domain: pointer to the domain block
+ *
+ * Do an hypervisor call to destroy the given domain
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+int
+xenHypervisorDestroyDomain(virDomainPtr domain)
+{
+ int ret;
+ xenUnifiedPrivatePtr priv;
+
+ if (domain == NULL || domain->conn == NULL)
+ return -1;
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->handle < 0 || domain->id < 0)
+ return (-1);
+
+ ret = virXen_destroydomain(priv->handle, domain->id);
+ if (ret < 0)
+ return (-1);
+ return (0);
+}
+
+/**
+ * xenHypervisorSetMaxMemory:
+ * @domain: pointer to the domain block
+ * @memory: the max memory size in kilobytes.
+ *
+ * Do an hypervisor call to change the maximum amount of memory used
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+int
+xenHypervisorSetMaxMemory(virDomainPtr domain, unsigned long memory)
+{
+ int ret;
+ xenUnifiedPrivatePtr priv;
+
+ if (domain == NULL || domain->conn == NULL)
+ return -1;
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->handle < 0 || domain->id < 0)
+ return (-1);
+
+ ret = virXen_setmaxmem(priv->handle, domain->id, memory);
+ if (ret < 0)
+ return (-1);
+ return (0);
+}
+#endif /* PROXY */
+
+#ifndef PROXY
+/**
+ * xenHypervisorSetVcpus:
+ * @domain: pointer to domain object
+ * @nvcpus: the new number of virtual CPUs for this domain
+ *
+ * Dynamically change the number of virtual CPUs used by the domain.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+
+int
+xenHypervisorSetVcpus(virDomainPtr domain, unsigned int nvcpus)
+{
+ int ret;
+ xenUnifiedPrivatePtr priv;
+
+ if (domain == NULL || domain->conn == NULL)
+ return -1;
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->handle < 0 || domain->id < 0 || nvcpus < 1)
+ return (-1);
+
+ ret = virXen_setmaxvcpus(priv->handle, domain->id, nvcpus);
+ if (ret < 0)
+ return (-1);
+ return (0);
+}
+
+/**
+ * xenHypervisorPinVcpu:
+ * @domain: pointer to domain object
+ * @vcpu: virtual CPU number
+ * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes)
+ * @maplen: length of cpumap in bytes
+ *
+ * Dynamically change the real CPUs which can be allocated to a virtual CPU.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+
+int
+xenHypervisorPinVcpu(virDomainPtr domain, unsigned int vcpu,
+ unsigned char *cpumap, int maplen)
+{
+ int ret;
+ xenUnifiedPrivatePtr priv;
+
+ if (domain == NULL || domain->conn == NULL)
+ return -1;
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->handle < 0 || (domain->id < 0) ||
+ (cpumap == NULL) || (maplen < 1))
+ return (-1);
+
+ ret = virXen_setvcpumap(priv->handle, domain->id, vcpu,
+ cpumap, maplen);
+ if (ret < 0)
+ return (-1);
+ return (0);
+}
+#endif
+
+/**
+ * virDomainGetVcpus:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @info: pointer to an array of virVcpuInfo structures (OUT)
+ * @maxinfo: number of structures in info array
+ * @cpumaps: pointer to an bit map of real CPUs for all vcpus of this domain (in 8-bit bytes) (OUT)
+ * If cpumaps is NULL, then no cpumap information is returned by the API.
+ * It's assumed there is <maxinfo> cpumap in cpumaps array.
+ * The memory allocated to cpumaps must be (maxinfo * maplen) bytes
+ * (ie: calloc(maxinfo, maplen)).
+ * One cpumap inside cpumaps has the format described in virDomainPinVcpu() API.
+ * @maplen: number of bytes in one cpumap, from 1 up to size of CPU map in
+ * underlying virtualization system (Xen...).
+ *
+ * Extract information about virtual CPUs of domain, store it in info array
+ * and also in cpumaps if this pointer isn't NULL.
+ *
+ * Returns the number of info filled in case of success, -1 in case of failure.
+ */
+#ifndef PROXY
+int
+xenHypervisorGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo,
+ unsigned char *cpumaps, int maplen)
+{
+ xen_getdomaininfo dominfo;
+ int ret;
+ xenUnifiedPrivatePtr priv;
+ virVcpuInfoPtr ipt;
+ int nbinfo, i;
+
+ if (domain == NULL || domain->conn == NULL)
+ return -1;
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->handle < 0 || (domain->id < 0) ||
+ (info == NULL) || (maxinfo < 1) ||
+ (sizeof(cpumap_t) & 7))
+ return (-1);
+ if ((cpumaps != NULL) && (maplen < 1))
+ return -1;
+
+ /* first get the number of virtual CPUs in this domain */
+ XEN_GETDOMAININFO_CLEAR(dominfo);
+ ret = virXen_getdomaininfo(priv->handle, domain->id,
+ &dominfo);
+
+ if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != domain->id))
+ return (-1);
+ nbinfo = XEN_GETDOMAININFO_CPUCOUNT(dominfo) + 1;
+ if (nbinfo > maxinfo) nbinfo = maxinfo;
+
+ if (cpumaps != NULL)
+ memset(cpumaps, 0, maxinfo * maplen);
+
+ for (i = 0, ipt = info; i < nbinfo; i++, ipt++) {
+ if ((cpumaps != NULL) && (i < maxinfo)) {
+ ret = virXen_getvcpusinfo(priv->handle, domain->id, i,
+ ipt,
+ (unsigned char *)VIR_GET_CPUMAP(cpumaps, maplen, i),
+ maplen);
+ if (ret < 0)
+ return(-1);
+ } else {
+ ret = virXen_getvcpusinfo(priv->handle, domain->id, i,
+ ipt, NULL, 0);
+ if (ret < 0)
+ return(-1);
+ }
+ }
+ return nbinfo;
+}
+#endif /* PROXY */
+
+/**
+ * xenHypervisorGetVcpuMax:
+ *
+ * Returns the maximum number of virtual CPUs supported for
+ * the guest VM. If the guest is inactive, this is the maximum
+ * of CPU defined by Xen. If the guest is running this reflect
+ * the maximum number of virtual CPUs the guest was booted with.
+ */
+int
+xenHypervisorGetVcpuMax(virDomainPtr domain)
+{
+ xen_getdomaininfo dominfo;
+ int ret;
+ int maxcpu;
+ xenUnifiedPrivatePtr priv;
+
+ if (domain == NULL || domain->conn == NULL)
+ return -1;
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->handle < 0)
+ return (-1);
+
+ /* inactive domain */
+ if (domain->id < 0) {
+ maxcpu = MAX_VIRT_CPUS;
+ } else {
+ XEN_GETDOMAININFO_CLEAR(dominfo);
+ ret = virXen_getdomaininfo(priv->handle, domain->id,
+ &dominfo);
+
+ if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != domain->id))
+ return (-1);
+ maxcpu = XEN_GETDOMAININFO_MAXCPUID(dominfo) + 1;
+ }
+
+ return maxcpu;
+}
+
+/**
+ * xenHavePrivilege()
+ *
+ * Return true if the current process should be able to connect to Xen.
+ */
+int
+xenHavePrivilege()
+{
+#ifdef __sun
+ return priv_ineffect (PRIV_XVM_CONTROL);
+#else
+ return access(XEN_HYPERVISOR_SOCKET, R_OK) == 0;
+#endif
+}
--- /dev/null
+/*
+ * xen_internal.h: internal API for direct access to Xen hypervisor level
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#ifndef __VIR_XEN_INTERNAL_H__
+#define __VIR_XEN_INTERNAL_H__
+
+#include <libxml/uri.h>
+
+#include "internal.h"
+#include "capabilities.h"
+#include "driver.h"
+
+extern struct xenUnifiedDriver xenHypervisorDriver;
+int xenHypervisorInit (void);
+
+virCapsPtr xenHypervisorMakeCapabilities (virConnectPtr conn);
+
+/* The following calls are made directly by the Xen proxy: */
+
+virDomainPtr
+ xenHypervisorLookupDomainByID (virConnectPtr conn,
+ int id);
+virDomainPtr
+ xenHypervisorLookupDomainByUUID (virConnectPtr conn,
+ const unsigned char *uuid);
+char *
+ xenHypervisorDomainGetOSType (virDomainPtr dom);
+
+virDrvOpenStatus
+ xenHypervisorOpen (virConnectPtr conn,
+ virConnectAuthPtr auth,
+ int flags);
+int xenHypervisorClose (virConnectPtr conn);
+int xenHypervisorGetVersion (virConnectPtr conn,
+ unsigned long *hvVer);
+virCapsPtr
+ xenHypervisorMakeCapabilitiesInternal(virConnectPtr conn,
+ const char *hostmachine,
+ FILE *cpuinfo,
+ FILE *capabilities);
+char *
+ xenHypervisorGetCapabilities (virConnectPtr conn);
+unsigned long
+ xenHypervisorGetDomMaxMemory (virConnectPtr conn,
+ int id);
+int xenHypervisorNumOfDomains (virConnectPtr conn);
+int xenHypervisorListDomains (virConnectPtr conn,
+ int *ids,
+ int maxids);
+int xenHypervisorGetMaxVcpus (virConnectPtr conn,
+ const char *type);
+int xenHypervisorDestroyDomain (virDomainPtr domain);
+int xenHypervisorResumeDomain (virDomainPtr domain);
+int xenHypervisorPauseDomain (virDomainPtr domain);
+int xenHypervisorGetDomainInfo (virDomainPtr domain,
+ virDomainInfoPtr info);
+int xenHypervisorGetDomInfo (virConnectPtr conn,
+ int id,
+ virDomainInfoPtr info);
+int xenHypervisorSetMaxMemory (virDomainPtr domain,
+ unsigned long memory);
+int xenHypervisorCheckID (virConnectPtr conn,
+ int id);
+int xenHypervisorSetVcpus (virDomainPtr domain,
+ unsigned int nvcpus);
+int xenHypervisorPinVcpu (virDomainPtr domain,
+ unsigned int vcpu,
+ unsigned char *cpumap,
+ int maplen);
+int xenHypervisorGetVcpus (virDomainPtr domain,
+ virVcpuInfoPtr info,
+ int maxinfo,
+ unsigned char *cpumaps,
+ int maplen);
+int xenHypervisorGetVcpuMax (virDomainPtr domain);
+
+char * xenHypervisorGetSchedulerType (virDomainPtr domain,
+ int *nparams);
+
+int xenHypervisorGetSchedulerParameters(virDomainPtr domain,
+ virSchedParameterPtr params,
+ int *nparams);
+
+int xenHypervisorSetSchedulerParameters(virDomainPtr domain,
+ virSchedParameterPtr params,
+ int nparams);
+
+int xenHypervisorDomainBlockStats (virDomainPtr domain,
+ const char *path,
+ struct _virDomainBlockStats *stats);
+int xenHypervisorDomainInterfaceStats (virDomainPtr domain,
+ const char *path,
+ struct _virDomainInterfaceStats *stats);
+
+int xenHypervisorNodeGetCellsFreeMemory(virConnectPtr conn,
+ unsigned long long *freeMems,
+ int startCell,
+ int maxCells);
+
+int xenHavePrivilege(void);
+
+#endif /* __VIR_XEN_INTERNAL_H__ */
--- /dev/null
+/*
+ * xen_inofify.c: Xen notification of xml file activity in the
+ * following dirs:
+ * /etc/xen
+ * /var/lib/xend/domains
+ *
+ * Copyright (C) 2008 VirtualIron
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Ben Guthro
+ */
+#include <config.h>
+#include <dirent.h>
+#include <sys/inotify.h>
+
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "driver.h"
+#include "memory.h"
+#include "event.h"
+#include "xen_driver.h"
+#include "conf.h"
+#include "domain_conf.h"
+#include "xen_inotify.h"
+#include "xend_internal.h"
+#include "logging.h"
+#include "uuid.h"
+
+#include "xm_internal.h" /* for xenXMDomainConfigParse */
+
+#define VIR_FROM_THIS VIR_FROM_XEN_INOTIFY
+
+#define virXenInotifyError(conn, code, fmt...) \
+ virReportErrorHelper(NULL, VIR_FROM_XEN_INOTIFY, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
+#define LIBVIRTD_DOMAINS_DIR "/var/lib/xend/domains"
+
+struct xenUnifiedDriver xenInotifyDriver = {
+ xenInotifyOpen, /* open */
+ xenInotifyClose, /* close */
+ NULL, /* version */
+ NULL, /* hostname */
+ NULL, /* nodeGetInfo */
+ NULL, /* getCapabilities */
+ NULL, /* listDomains */
+ NULL, /* numOfDomains */
+ NULL, /* domainCreateLinux */
+ NULL, /* domainSuspend */
+ NULL, /* domainResume */
+ NULL, /* domainShutdown */
+ NULL, /* domainReboot */
+ NULL, /* domainDestroy */
+ NULL, /* domainGetOSType */
+ NULL, /* domainGetMaxMemory */
+ NULL, /* domainSetMaxMemory */
+ NULL, /* domainSetMemory */
+ NULL, /* domainGetInfo */
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
+ NULL, /* domainCoreDump */
+ NULL, /* domainSetVcpus */
+ NULL, /* domainPinVcpu */
+ NULL, /* domainGetVcpus */
+ NULL, /* domainGetMaxVcpus */
+ NULL, /* listDefinedDomains */
+ NULL, /* numOfDefinedDomains */
+ NULL, /* domainCreate */
+ NULL, /* domainDefineXML */
+ NULL, /* domainUndefine */
+ NULL, /* domainAttachDevice */
+ NULL, /* domainDetachDevice */
+ NULL, /* domainGetAutostart */
+ NULL, /* domainSetAutostart */
+ NULL, /* domainGetSchedulerType */
+ NULL, /* domainGetSchedulerParameters */
+ NULL, /* domainSetSchedulerParameters */
+};
+
+static int
+xenInotifyXenCacheLookup(virConnectPtr conn,
+ const char *filename,
+ char **name, unsigned char *uuid) {
+ xenUnifiedPrivatePtr priv = conn->privateData;
+ xenXMConfCachePtr entry;
+
+ if (!(entry = virHashLookup(priv->configCache, filename))) {
+ DEBUG("No config found for %s", filename);
+ return -1;
+ }
+
+ *name = strdup(entry->def->name);
+ memcpy(uuid, entry->def->uuid, VIR_UUID_BUFLEN);
+
+ if (!*name) {
+ DEBUG0("Error getting dom from def");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+xenInotifyXendDomainsDirLookup(virConnectPtr conn, const char *filename,
+ char **name, unsigned char *uuid) {
+ int i;
+ virDomainPtr dom;
+ const char *uuid_str;
+ unsigned char rawuuid[VIR_UUID_BUFLEN];
+ xenUnifiedPrivatePtr priv = conn->privateData;
+
+ /* xend is managing domains. we will get
+ * a filename in the manner:
+ * /var/lib/xend/domains/<uuid>/
+ */
+ uuid_str = filename + strlen(LIBVIRTD_DOMAINS_DIR) + 1;
+
+ if (virUUIDParse(uuid_str, rawuuid) < 0) {
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("parsing uuid %s"), uuid_str);
+ return -1;
+ }
+ /* call directly into xend here, as driver may not yet
+ be set during open while we are building our
+ initial list of domains */
+ DEBUG("Looking for dom with uuid: %s", uuid_str);
+ /* XXX Should not have to go via a virDomainPtr obj instance */
+ if(!(dom = xenDaemonLookupByUUID(conn, rawuuid))) {
+ /* If we are here, the domain has gone away.
+ search for, and create a domain from the stored
+ list info */
+ for (i = 0 ; i < priv->configInfoList->count ; i++) {
+ if (!memcmp(uuid, priv->configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN)) {
+ *name = strdup(priv->configInfoList->doms[i]->name);
+ if (!*name) {
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("finding dom for %s"), uuid_str);
+ return -1;
+ }
+ memcpy(uuid, priv->configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN);
+ DEBUG0("Found dom on list");
+ return 0;
+ }
+ }
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("finding dom on config list"));
+ return -1;
+ }
+
+ if (!(*name = strdup(dom->name)))
+ return -1;
+ memcpy(uuid, dom->uuid, VIR_UUID_BUFLEN);
+ virDomainFree(dom);
+ /* succeeded too find domain by uuid */
+ return 0;
+}
+
+static int
+xenInotifyDomainLookup(virConnectPtr conn,
+ const char *filename,
+ char **name, unsigned char *uuid) {
+ xenUnifiedPrivatePtr priv = conn->privateData;
+ if (priv->useXenConfigCache)
+ return xenInotifyXenCacheLookup(conn, filename, name, uuid);
+ else
+ return xenInotifyXendDomainsDirLookup(conn, filename, name, uuid);
+}
+
+static virDomainEventPtr
+xenInotifyDomainEventFromFile(virConnectPtr conn,
+ const char *filename,
+ int type, int detail) {
+ virDomainEventPtr event;
+ char *name = NULL;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+
+ if (xenInotifyDomainLookup(conn, filename, &name, uuid) < 0)
+ return NULL;
+
+ event = virDomainEventNew(-1, name, uuid, type, detail);
+ VIR_FREE(name);
+ return event;
+}
+
+static int
+xenInotifyXendDomainsDirRemoveEntry(virConnectPtr conn,
+ const char *fname) {
+ xenUnifiedPrivatePtr priv = conn->privateData;
+ const char *uuidstr = fname + strlen(LIBVIRTD_DOMAINS_DIR) + 1;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ int i;
+
+ if (virUUIDParse(uuidstr, uuid) < 0) {
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("parsing uuid %s"), uuidstr);
+ return -1;
+ }
+
+ /* match and remove on uuid */
+ for (i = 0 ; i < priv->configInfoList->count ; i++) {
+ if (!memcmp(uuid, priv->configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN)) {
+ VIR_FREE(priv->configInfoList->doms[i]->name);
+ VIR_FREE(priv->configInfoList->doms[i]);
+
+ if (i < (priv->configInfoList->count - 1))
+ memmove(priv->configInfoList->doms + i,
+ priv->configInfoList->doms + i + 1,
+ sizeof(*(priv->configInfoList->doms)) *
+ (priv->configInfoList->count - (i + 1)));
+
+ if (VIR_REALLOC_N(priv->configInfoList->doms,
+ priv->configInfoList->count - 1) < 0) {
+ ; /* Failure to reduce memory allocation isn't fatal */
+ }
+ priv->configInfoList->count--;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+xenInotifyXendDomainsDirAddEntry(virConnectPtr conn,
+ const char *fname) {
+ char *name = NULL;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ xenUnifiedPrivatePtr priv = conn->privateData;
+
+ if (xenInotifyDomainLookup(conn, fname, &name, uuid) < 0) {
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Error looking up domain"));
+ return -1;
+ }
+
+ if (xenUnifiedAddDomainInfo(priv->configInfoList,
+ -1, name, uuid) < 0) {
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Error adding file to config cache"));
+ VIR_FREE(name);
+ return -1;
+ }
+ VIR_FREE(name);
+ return 0;
+}
+
+static int
+xenInotifyRemoveDomainConfigInfo(virConnectPtr conn,
+ const char *fname) {
+ xenUnifiedPrivatePtr priv = conn->privateData;
+ return priv->useXenConfigCache ?
+ xenXMConfigCacheRemoveFile(conn, fname) :
+ xenInotifyXendDomainsDirRemoveEntry(conn, fname);
+}
+
+static int
+xenInotifyAddDomainConfigInfo(virConnectPtr conn,
+ const char *fname) {
+ xenUnifiedPrivatePtr priv = conn->privateData;
+ return priv->useXenConfigCache ?
+ xenXMConfigCacheAddFile(conn, fname) :
+ xenInotifyXendDomainsDirAddEntry(conn, fname);
+}
+
+static void
+xenInotifyEvent(int watch ATTRIBUTE_UNUSED,
+ int fd,
+ int events ATTRIBUTE_UNUSED,
+ void *data)
+{
+ char buf[1024];
+ char fname[1024];
+ struct inotify_event *e;
+ int got;
+ char *tmp, *name;
+ virConnectPtr conn = data;
+ xenUnifiedPrivatePtr priv = NULL;
+
+ DEBUG0("got inotify event");
+
+ if( conn && conn->privateData ) {
+ priv = conn->privateData;
+ } else {
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("conn, or private data is NULL"));
+ return;
+ }
+
+ xenUnifiedLock(priv);
+
+reread:
+ got = read(fd, buf, sizeof(buf));
+ if (got == -1) {
+ if (errno == EINTR)
+ goto reread;
+ goto cleanup;
+ }
+
+ tmp = buf;
+ while (got) {
+ if (got < sizeof(struct inotify_event))
+ goto cleanup; /* bad */
+
+ e = (struct inotify_event *)tmp;
+ tmp += sizeof(struct inotify_event);
+ got -= sizeof(struct inotify_event);
+
+ if (got < e->len)
+ goto cleanup;
+
+ tmp += e->len;
+ got -= e->len;
+
+ name = (char *)&(e->name);
+
+ snprintf(fname, 1024, "%s/%s",
+ priv->configDir, name);
+
+ if (e->mask & (IN_DELETE | IN_MOVED_FROM)) {
+ virDomainEventPtr event =
+ xenInotifyDomainEventFromFile(conn, fname,
+ VIR_DOMAIN_EVENT_UNDEFINED,
+ VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
+ if (!event)
+ xenUnifiedDomainEventDispatch(conn->privateData, event);
+ else
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("looking up dom"));
+
+ if (xenInotifyRemoveDomainConfigInfo(conn, fname) < 0 ) {
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Error adding file to config cache"));
+ goto cleanup;
+ }
+ } else if (e->mask & ( IN_CREATE | IN_CLOSE_WRITE | IN_MOVED_TO) ) {
+ virDomainEventPtr event;
+ if (xenInotifyAddDomainConfigInfo(conn, fname) < 0 ) {
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Error adding file to config cache"));
+ goto cleanup;
+ }
+
+ event = xenInotifyDomainEventFromFile(conn, fname,
+ VIR_DOMAIN_EVENT_DEFINED,
+ VIR_DOMAIN_EVENT_DEFINED_ADDED);
+
+ if (event)
+ xenUnifiedDomainEventDispatch(conn->privateData, event);
+ else
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("looking up dom"));
+
+ }
+
+ }
+
+cleanup:
+ xenUnifiedUnlock(priv);
+}
+
+/**
+ * xenInotifyOpen:
+ * @conn: pointer to the connection block
+ * @name: URL for the target, NULL for local
+ * @flags: combination of virDrvOpenFlag(s)
+ *
+ * Connects and starts listening for inotify events
+ *
+ * Returns 0 or -1 in case of error.
+ */
+virDrvOpenStatus
+xenInotifyOpen(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED)
+{
+ DIR *dh;
+ struct dirent *ent;
+ char path[PATH_MAX];
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ if (priv->configDir) {
+ priv->useXenConfigCache = 1;
+ } else {
+ /* /var/lib/xend/domains/<uuid>/config.sxp */
+ priv->configDir = LIBVIRTD_DOMAINS_DIR;
+ priv->useXenConfigCache = 0;
+
+ if (VIR_ALLOC(priv->configInfoList) < 0) {
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to allocate configInfoList"));
+ return -1;
+ }
+
+ /* populate initial list */
+ if (!(dh = opendir(priv->configDir))) {
+ virReportSystemError(NULL, errno,
+ _("cannot open directory: %s"),
+ priv->configDir);
+ return -1;
+ }
+ while ((ent = readdir(dh))) {
+ if (STRPREFIX(ent->d_name, "."))
+ continue;
+
+ /* Build the full file path */
+ if ((strlen(priv->configDir) + 1 +
+ strlen(ent->d_name) + 1) > PATH_MAX)
+ continue;
+ strcpy(path, priv->configDir);
+ strcat(path, "/");
+ strcat(path, ent->d_name);
+
+ if (xenInotifyAddDomainConfigInfo(conn, path) < 0 ) {
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Error adding file to config list"));
+ closedir(dh);
+ return -1;
+ }
+ }
+ closedir(dh);
+ }
+
+ if ((priv->inotifyFD = inotify_init()) < 0) {
+ virReportSystemError(NULL, errno,
+ "%s", _("initializing inotify"));
+ return -1;
+ }
+
+ DEBUG("Adding a watch on %s", priv->configDir);
+ if (inotify_add_watch(priv->inotifyFD,
+ priv->configDir,
+ IN_CREATE |
+ IN_CLOSE_WRITE | IN_DELETE |
+ IN_MOVED_TO | IN_MOVED_FROM) < 0) {
+ virReportSystemError(NULL, errno,
+ _("adding watch on %s"),
+ priv->configDir);
+ return -1;
+ }
+
+ DEBUG0("Building initial config cache");
+ if (priv->useXenConfigCache &&
+ xenXMConfigCacheRefresh (conn) < 0) {
+ DEBUG("Failed to enable XM config cache %s", conn->err.message);
+ return -1;
+ }
+
+ DEBUG0("Registering with event loop");
+ /* Add the handle for monitoring */
+ if ((priv->inotifyWatch = virEventAddHandle(priv->inotifyFD, VIR_EVENT_HANDLE_READABLE,
+ xenInotifyEvent, conn, NULL)) < 0) {
+ DEBUG0("Failed to add inotify handle, disabling events");
+ }
+
+ virConnectRef(conn);
+ return 0;
+}
+
+/**
+ * xenInotifyClose:
+ * @conn: pointer to the connection block
+ *
+ * Close and stop listening for inotify events
+ *
+ * Returns 0 in case of success or -1 in case of error.
+ */
+int
+xenInotifyClose(virConnectPtr conn)
+{
+ xenUnifiedPrivatePtr priv = conn->privateData;
+
+ if (priv->configInfoList)
+ xenUnifiedDomainInfoListFree(priv->configInfoList);
+
+ if (priv->inotifyWatch != -1)
+ virEventRemoveHandle(priv->inotifyWatch);
+ close(priv->inotifyFD);
+ virUnrefConnect(conn);
+
+ return 0;
+}
--- /dev/null
+/*
+ * xen_inofify.h: Xen notification of xml files
+ *
+ * Copyright (C) 2008 VirtualIron
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Ben Guthro
+ */
+#ifndef __VIR_XEN_INOTIFY_H__
+#define __VIR_XEN_INOTIFY_H__
+
+#include "internal.h"
+#include "driver.h"
+
+extern struct xenUnifiedDriver xenInotifyDriver;
+
+virDrvOpenStatus xenInotifyOpen (virConnectPtr conn,
+ virConnectAuthPtr auth,
+ int flags);
+int xenInotifyClose (virConnectPtr conn);
+#endif
--- /dev/null
+/*
+ * xend_internal.c: access to Xen though the Xen Daemon interface
+ *
+ * Copyright (C) 2005
+ *
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License. See the file COPYING.LIB in the main directory of this
+ * archive for more details.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <math.h>
+#include <stdarg.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <libxml/uri.h>
+#include <errno.h>
+
+#include "virterror_internal.h"
+#include "logging.h"
+#include "datatypes.h"
+#include "xend_internal.h"
+#include "driver.h"
+#include "util.h"
+#include "sexpr.h"
+#include "buf.h"
+#include "uuid.h"
+#include "xen_driver.h"
+#include "xen_hypervisor.h"
+#include "xs_internal.h" /* To extract VNC port & Serial console TTY */
+#include "memory.h"
+
+/* required for cpumap_t */
+#include <xen/dom0_ops.h>
+
+#define VIR_FROM_THIS VIR_FROM_XEND
+
+#ifndef PROXY
+
+/*
+ * The number of Xen scheduler parameters
+ */
+#define XEN_SCHED_SEDF_NPARAM 6
+#define XEN_SCHED_CRED_NPARAM 2
+
+#endif /* PROXY */
+
+#ifdef WITH_RHEL5_API
+#define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 0
+#define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 2
+#else
+#define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 3
+#define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 3
+#endif
+
+
+#ifndef PROXY
+static int
+xenDaemonFormatSxprDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainDiskDefPtr def,
+ virBufferPtr buf,
+ int hvm,
+ int xendConfigVersion,
+ int isAttach);
+static int
+xenDaemonFormatSxprNet(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainNetDefPtr def,
+ virBufferPtr buf,
+ int hvm,
+ int xendConfigVersion,
+ int isAttach);
+static int
+xenDaemonFormatSxprOnePCI(virConnectPtr conn,
+ virDomainHostdevDefPtr def,
+ virBufferPtr buf);
+
+static int
+virDomainXMLDevID(virDomainPtr domain,
+ virDomainDeviceDefPtr dev,
+ char *class,
+ char *ref,
+ int ref_len);
+#endif
+
+#define virXendError(conn, code, fmt...) \
+ virReportErrorHelper(conn, VIR_FROM_XEND, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
+#define virXendErrorInt(conn, code, ival) \
+ virXendError(conn, code, "%d", ival)
+
+/**
+ * do_connect:
+ * @xend: pointer to the Xen Daemon structure
+ *
+ * Internal routine to (re)connect to the daemon
+ *
+ * Returns the socket file descriptor or -1 in case of error
+ */
+static int
+do_connect(virConnectPtr xend)
+{
+ int s;
+ int serrno;
+ int no_slow_start = 1;
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) xend->privateData;
+
+ s = socket(priv->addrfamily, SOCK_STREAM, priv->addrprotocol);
+ if (s == -1) {
+ virXendError(xend, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to create a socket"));
+ return -1;
+ }
+
+ /*
+ * try to desactivate slow-start
+ */
+ setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *)&no_slow_start,
+ sizeof(no_slow_start));
+
+
+ if (connect(s, (struct sockaddr *)&priv->addr, priv->addrlen) == -1) {
+ serrno = errno;
+ close(s);
+ errno = serrno;
+ s = -1;
+
+ /*
+ * Connecting to XenD when privileged is mandatory, so log this
+ * error
+ */
+ if (xenHavePrivilege()) {
+ virXendError(xend, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to connect to xend"));
+ }
+ }
+
+ return s;
+}
+
+/**
+ * wr_sync:
+ * @xend: the xend connection object
+ * @fd: the file descriptor
+ * @buffer: the I/O buffer
+ * @size: the size of the I/O
+ * @do_read: write operation if 0, read operation otherwise
+ *
+ * Do a synchronous read or write on the file descriptor
+ *
+ * Returns the number of bytes exchanged, or -1 in case of error
+ */
+static size_t
+wr_sync(virConnectPtr xend, int fd, void *buffer, size_t size, int do_read)
+{
+ size_t offset = 0;
+
+ while (offset < size) {
+ ssize_t len;
+
+ if (do_read) {
+ len = read(fd, ((char *) buffer) + offset, size - offset);
+ } else {
+ len = write(fd, ((char *) buffer) + offset, size - offset);
+ }
+
+ /* recoverable error, retry */
+ if ((len == -1) && ((errno == EAGAIN) || (errno == EINTR))) {
+ continue;
+ }
+
+ /* eof */
+ if (len == 0) {
+ break;
+ }
+
+ /* unrecoverable error */
+ if (len == -1) {
+ if (do_read)
+ virXendError(xend, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to read from Xen Daemon"));
+ else
+ virXendError(xend, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to read from Xen Daemon"));
+
+ return (-1);
+ }
+
+ offset += len;
+ }
+
+ return offset;
+}
+
+/**
+ * sread:
+ * @xend: the xend connection object
+ * @fd: the file descriptor
+ * @buffer: the I/O buffer
+ * @size: the size of the I/O
+ *
+ * Internal routine to do a synchronous read
+ *
+ * Returns the number of bytes read, or -1 in case of error
+ */
+static ssize_t
+sread(virConnectPtr xend, int fd, void *buffer, size_t size)
+{
+ return wr_sync(xend, fd, buffer, size, 1);
+}
+
+/**
+ * swrite:
+ * @xend: the xend connection object
+ * @fd: the file descriptor
+ * @buffer: the I/O buffer
+ * @size: the size of the I/O
+ *
+ * Internal routine to do a synchronous write
+ *
+ * Returns the number of bytes written, or -1 in case of error
+ */
+static ssize_t
+swrite(virConnectPtr xend, int fd, const void *buffer, size_t size)
+{
+ return wr_sync(xend, fd, (void *) buffer, size, 0);
+}
+
+/**
+ * swrites:
+ * @xend: the xend connection object
+ * @fd: the file descriptor
+ * @string: the string to write
+ *
+ * Internal routine to do a synchronous write of a string
+ *
+ * Returns the number of bytes written, or -1 in case of error
+ */
+static ssize_t
+swrites(virConnectPtr xend, int fd, const char *string)
+{
+ return swrite(xend, fd, string, strlen(string));
+}
+
+/**
+ * sreads:
+ * @xend: the xend connection object
+ * @fd: the file descriptor
+ * @buffer: the I/O buffer
+ * @n_buffer: the size of the I/O buffer
+ *
+ * Internal routine to do a synchronous read of a line
+ *
+ * Returns the number of bytes read, or -1 in case of error
+ */
+static ssize_t
+sreads(virConnectPtr xend, int fd, char *buffer, size_t n_buffer)
+{
+ size_t offset;
+
+ if (n_buffer < 1)
+ return (-1);
+
+ for (offset = 0; offset < (n_buffer - 1); offset++) {
+ ssize_t ret;
+
+ ret = sread(xend, fd, buffer + offset, 1);
+ if (ret == 0)
+ break;
+ else if (ret == -1)
+ return ret;
+
+ if (buffer[offset] == '\n') {
+ offset++;
+ break;
+ }
+ }
+ buffer[offset] = 0;
+
+ return offset;
+}
+
+static int
+istartswith(const char *haystack, const char *needle)
+{
+ return STRCASEEQLEN(haystack, needle, strlen(needle));
+}
+
+
+/**
+ * xend_req:
+ * @xend: the xend connection object
+ * @fd: the file descriptor
+ * @content: the buffer to store the content
+ * @n_content: the size of the buffer
+ *
+ * Read the HTTP response from a Xen Daemon request.
+ *
+ * Returns the HTTP return code.
+ */
+static int
+xend_req(virConnectPtr xend, int fd, char *content, size_t n_content)
+{
+ char buffer[4096];
+ int content_length = -1;
+ int retcode = 0;
+
+ while (sreads(xend, fd, buffer, sizeof(buffer)) > 0) {
+ if (STREQ(buffer, "\r\n"))
+ break;
+
+ if (istartswith(buffer, "Content-Length: "))
+ content_length = atoi(buffer + 16);
+ else if (istartswith(buffer, "HTTP/1.1 "))
+ retcode = atoi(buffer + 9);
+ }
+
+ if (content_length > -1) {
+ ssize_t ret;
+
+ if ((unsigned int) content_length > (n_content + 1))
+ content_length = n_content - 1;
+
+ ret = sread(xend, fd, content, content_length);
+ if (ret < 0)
+ return -1;
+
+ content[ret] = 0;
+ } else {
+ content[0] = 0;
+ }
+
+ return retcode;
+}
+
+/**
+ * xend_get:
+ * @xend: pointer to the Xen Daemon structure
+ * @path: the path used for the HTTP request
+ * @content: the buffer to store the content
+ * @n_content: the size of the buffer
+ *
+ * Do an HTTP GET RPC with the Xen Daemon
+ *
+ * Returns the HTTP return code or -1 in case or error.
+ */
+static int
+xend_get(virConnectPtr xend, const char *path,
+ char *content, size_t n_content)
+{
+ int ret;
+ int s = do_connect(xend);
+
+ if (s == -1)
+ return s;
+
+ swrites(xend, s, "GET ");
+ swrites(xend, s, path);
+ swrites(xend, s, " HTTP/1.1\r\n");
+
+ swrites(xend, s,
+ "Host: localhost:8000\r\n"
+ "Accept-Encoding: identity\r\n"
+ "Content-Type: application/x-www-form-urlencoded\r\n" "\r\n");
+
+ ret = xend_req(xend, s, content, n_content);
+ close(s);
+
+ if (((ret < 0) || (ret >= 300)) &&
+ ((ret != 404) || (!STRPREFIX(path, "/xend/domain/")))) {
+ virXendError(xend, VIR_ERR_GET_FAILED,
+ _("%d status from xen daemon: %s:%s"),
+ ret, path, content);
+ }
+
+ return ret;
+}
+
+#ifndef PROXY
+/**
+ * xend_post:
+ * @xend: pointer to the Xen Daemon structure
+ * @path: the path used for the HTTP request
+ * @ops: the information sent for the POST
+ * @content: the buffer to store the content
+ * @n_content: the size of the buffer
+ *
+ * Do an HTTP POST RPC with the Xen Daemon, this usually makes changes at the
+ * Xen level.
+ *
+ * Returns the HTTP return code or -1 in case or error.
+ */
+static int
+xend_post(virConnectPtr xend, const char *path, const char *ops,
+ char *content, size_t n_content)
+{
+ char buffer[100];
+ int ret;
+ int s = do_connect(xend);
+
+ if (s == -1)
+ return s;
+
+ swrites(xend, s, "POST ");
+ swrites(xend, s, path);
+ swrites(xend, s, " HTTP/1.1\r\n");
+
+ swrites(xend, s,
+ "Host: localhost:8000\r\n"
+ "Accept-Encoding: identity\r\n"
+ "Content-Type: application/x-www-form-urlencoded\r\n"
+ "Content-Length: ");
+ snprintf(buffer, sizeof(buffer), "%d", (int) strlen(ops));
+ swrites(xend ,s, buffer);
+ swrites(xend, s, "\r\n\r\n");
+ swrites(xend, s, ops);
+
+ ret = xend_req(xend, s, content, n_content);
+ close(s);
+
+ if ((ret < 0) || (ret >= 300)) {
+ virXendError(xend, VIR_ERR_POST_FAILED,
+ _("xend_post: error from xen daemon: %s"), content);
+ } else if ((ret == 202) && (strstr(content, "failed") != NULL)) {
+ virXendError(xend, VIR_ERR_POST_FAILED,
+ _("xend_post: error from xen daemon: %s"), content);
+ ret = -1;
+ } else if (((ret >= 200) && (ret <= 202)) && (strstr(content, "xend.err") != NULL)) {
+ /* This is to catch case of things like 'virsh dump Domain-0 foo'
+ * which returns a success code, but the word 'xend.err'
+ * in body to indicate error :-(
+ */
+ virXendError(xend, VIR_ERR_POST_FAILED,
+ _("xend_post: error from xen daemon: %s"), content);
+ ret = -1;
+ }
+
+ return ret;
+}
+#endif /* ! PROXY */
+
+
+/**
+ * http2unix:
+ * @xend: the xend connection object
+ * @ret: the http return code
+ *
+ * Convert the HTTP return code to 0/-1 and set errno if needed
+ *
+ * Return -1 in case of error code 0 otherwise
+ */
+static int
+http2unix(virConnectPtr xend, int ret)
+{
+ switch (ret) {
+ case -1:
+ break;
+ case 200:
+ case 201:
+ case 202:
+ return 0;
+ case 404:
+ errno = ESRCH;
+ break;
+ case 500:
+ errno = EIO;
+ break;
+ default:
+ virXendErrorInt(xend, VIR_ERR_HTTP_ERROR, ret);
+ errno = EINVAL;
+ break;
+ }
+ return -1;
+}
+
+#ifndef PROXY
+/**
+ * xend_op_ext:
+ * @xend: pointer to the Xen Daemon structure
+ * @path: path for the object
+ * @error: buffer for the error output
+ * @n_error: size of @error
+ * @key: the key for the operation
+ * @ap: input values to pass to the operation
+ *
+ * internal routine to run a POST RPC operation to the Xen Daemon
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+static int
+xend_op_ext(virConnectPtr xend, const char *path, char *error,
+ size_t n_error, const char *key, va_list ap)
+{
+ const char *k = key, *v;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ int ret;
+ char *content;
+
+ while (k) {
+ v = va_arg(ap, const char *);
+
+ virBufferVSprintf(&buf, "%s", k);
+ virBufferVSprintf(&buf, "%s", "=");
+ virBufferVSprintf(&buf, "%s", v);
+ k = va_arg(ap, const char *);
+
+ if (k)
+ virBufferVSprintf(&buf, "%s", "&");
+ }
+
+ if (virBufferError(&buf)) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+
+ content = virBufferContentAndReset(&buf);
+ ret = http2unix(xend, xend_post(xend, path, content, error, n_error));
+ VIR_FREE(content);
+
+ return ret;
+}
+
+
+/**
+ * xend_op:
+ * @xend: pointer to the Xen Daemon structure
+ * @name: the domain name target of this operation
+ * @error: buffer for the error output
+ * @n_error: size of @error
+ * @key: the key for the operation
+ * @ap: input values to pass to the operation
+ * @...: input values to pass to the operation
+ *
+ * internal routine to run a POST RPC operation to the Xen Daemon targetting
+ * a given domain.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+static int
+xend_op(virConnectPtr xend, const char *name, const char *key, ...)
+{
+ char buffer[1024];
+ char error[1024];
+ va_list ap;
+ int ret;
+
+ snprintf(buffer, sizeof(buffer), "/xend/domain/%s", name);
+
+ va_start(ap, key);
+ ret = xend_op_ext(xend, buffer, error, sizeof(error), key, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+#endif /* ! PROXY */
+
+/**
+ * sexpr_get:
+ * @xend: pointer to the Xen Daemon structure
+ * @fmt: format string for the path of the operation
+ * @...: extra data to build the path of the operation
+ *
+ * Internal routine to run a simple GET RPC operation to the Xen Daemon
+ *
+ * Returns a parsed S-Expression in case of success, NULL in case of failure
+ */
+static struct sexpr *sexpr_get(virConnectPtr xend, const char *fmt, ...)
+ ATTRIBUTE_FMT_PRINTF(2,3);
+
+static struct sexpr *
+sexpr_get(virConnectPtr xend, const char *fmt, ...)
+{
+ char buffer[4096];
+ char path[1024];
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ vsnprintf(path, sizeof(path), fmt, ap);
+ va_end(ap);
+
+ ret = xend_get(xend, path, buffer, sizeof(buffer));
+ ret = http2unix(xend ,ret);
+ if (ret == -1)
+ return NULL;
+
+ return string2sexpr(buffer);
+}
+
+/**
+ * sexpr_int:
+ * @sexpr: an S-Expression
+ * @name: the name for the value
+ *
+ * convenience function to lookup an int value in the S-Expression
+ *
+ * Returns the value found or 0 if not found (but may not be an error).
+ * This function suffers from the flaw that zero is both a correct
+ * return value and an error indicator: careful!
+ */
+static int
+sexpr_int(const struct sexpr *sexpr, const char *name)
+{
+ const char *value = sexpr_node(sexpr, name);
+
+ if (value) {
+ return strtol(value, NULL, 0);
+ }
+ return 0;
+}
+
+
+/**
+ * sexpr_float:
+ * @sexpr: an S-Expression
+ * @name: the name for the value
+ *
+ * convenience function to lookup a float value in the S-Expression
+ *
+ * Returns the value found or 0 if not found (but may not be an error)
+ */
+static double
+sexpr_float(const struct sexpr *sexpr, const char *name)
+{
+ const char *value = sexpr_node(sexpr, name);
+
+ if (value) {
+ return strtod(value, NULL);
+ }
+ return 0;
+}
+
+/**
+ * sexpr_u64:
+ * @sexpr: an S-Expression
+ * @name: the name for the value
+ *
+ * convenience function to lookup a 64bits unsigned int value in the
+ * S-Expression
+ *
+ * Returns the value found or 0 if not found (but may not be an error)
+ */
+static uint64_t
+sexpr_u64(const struct sexpr *sexpr, const char *name)
+{
+ const char *value = sexpr_node(sexpr, name);
+
+ if (value) {
+ return strtoll(value, NULL, 0);
+ }
+ return 0;
+}
+
+
+/**
+ * sexpr_uuid:
+ * @ptr: where to store the UUID, incremented
+ * @sexpr: an S-Expression
+ * @name: the name for the value
+ *
+ * convenience function to lookup an UUID value from the S-Expression
+ *
+ * Returns a -1 on error, 0 on success
+ */
+static int
+sexpr_uuid(unsigned char *ptr, const struct sexpr *node, const char *path)
+{
+ const char *r = sexpr_node(node, path);
+ if (!r)
+ return -1;
+ return virUUIDParse(r, ptr);
+}
+
+
+#ifndef PROXY
+/**
+ * urlencode:
+ * @string: the input URL
+ *
+ * Encode an URL see RFC 2396 and following
+ *
+ * Returns the new string or NULL in case of error.
+ */
+static char *
+urlencode(const char *string)
+{
+ size_t len = strlen(string);
+ char *buffer;
+ char *ptr;
+ size_t i;
+
+ if (VIR_ALLOC_N(buffer, len * 3 + 1) < 0) {
+ virReportOOMError(NULL);
+ return (NULL);
+ }
+ ptr = buffer;
+ for (i = 0; i < len; i++) {
+ switch (string[i]) {
+ case ' ':
+ case '\n':
+ snprintf(ptr, 4, "%%%02x", string[i]);
+ ptr += 3;
+ break;
+ default:
+ *ptr = string[i];
+ ptr++;
+ }
+ }
+
+ *ptr = 0;
+
+ return buffer;
+}
+#endif /* ! PROXY */
+
+/* PUBLIC FUNCTIONS */
+
+/**
+ * xenDaemonOpen_unix:
+ * @conn: an existing virtual connection block
+ * @path: the path for the Xen Daemon socket
+ *
+ * Creates a localhost Xen Daemon connection
+ * Note: this doesn't try to check if the connection actually works
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+int
+xenDaemonOpen_unix(virConnectPtr conn, const char *path)
+{
+ struct sockaddr_un *addr;
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ if ((conn == NULL) || (path == NULL))
+ return (-1);
+
+ memset(&priv->addr, 0, sizeof(priv->addr));
+ priv->addrfamily = AF_UNIX;
+ /*
+ * This must be zero on Solaris at least for AF_UNIX (which should
+ * really be PF_UNIX, but doesn't matter).
+ */
+ priv->addrprotocol = 0;
+ priv->addrlen = sizeof(struct sockaddr_un);
+
+ addr = (struct sockaddr_un *)&priv->addr;
+ addr->sun_family = AF_UNIX;
+ memset(addr->sun_path, 0, sizeof(addr->sun_path));
+ strncpy(addr->sun_path, path, sizeof(addr->sun_path));
+
+ return (0);
+}
+
+#ifndef PROXY
+/**
+ * xenDaemonOpen_tcp:
+ * @conn: an existing virtual connection block
+ * @host: the host name for the Xen Daemon
+ * @port: the port
+ *
+ * Creates a possibly remote Xen Daemon connection
+ * Note: this doesn't try to check if the connection actually works
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+static int
+xenDaemonOpen_tcp(virConnectPtr conn, const char *host, const char *port)
+{
+ xenUnifiedPrivatePtr priv;
+ struct addrinfo *res, *r;
+ struct addrinfo hints;
+ int saved_errno = EINVAL;
+ int ret;
+
+ if ((conn == NULL) || (host == NULL) || (port == NULL))
+ return (-1);
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ priv->addrlen = 0;
+ memset(&priv->addr, 0, sizeof(priv->addr));
+
+ // http://people.redhat.com/drepper/userapi-ipv6.html
+ memset (&hints, 0, sizeof hints);
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_ADDRCONFIG;
+
+ ret = getaddrinfo (host, port, &hints, &res);
+ if (ret != 0) {
+ virXendError(NULL, VIR_ERR_UNKNOWN_HOST,
+ _("unable to resolve hostname '%s': %s"),
+ host, gai_strerror (ret));
+ return -1;
+ }
+
+ /* Try to connect to each returned address in turn. */
+ for (r = res; r; r = r->ai_next) {
+ int sock;
+
+ sock = socket (r->ai_family, SOCK_STREAM, r->ai_protocol);
+ if (sock == -1) {
+ saved_errno = errno;
+ continue;
+ }
+
+ if (connect (sock, r->ai_addr, r->ai_addrlen) == -1) {
+ saved_errno = errno;
+ close (sock);
+ continue;
+ }
+
+ priv->addrlen = r->ai_addrlen;
+ priv->addrfamily = r->ai_family;
+ priv->addrprotocol = r->ai_protocol;
+ memcpy(&priv->addr,
+ r->ai_addr,
+ r->ai_addrlen);
+ close(sock);
+ break;
+ }
+
+ freeaddrinfo (res);
+
+ if (!priv->addrlen) {
+ /* Don't raise error when unprivileged, since proxy takes over */
+ if (xenHavePrivilege())
+ virReportSystemError(conn, saved_errno,
+ _("unable to connect to '%s:%s'"),
+ host, port);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * xend_wait_for_devices:
+ * @xend: pointer to the Xem Daemon block
+ * @name: name for the domain
+ *
+ * Block the domain until all the virtual devices are ready. This operation
+ * is needed when creating a domain before resuming it.
+ *
+ * Returns 0 in case of success, -1 (with errno) in case of error.
+ */
+int
+xend_wait_for_devices(virConnectPtr xend, const char *name)
+{
+ return xend_op(xend, name, "op", "wait_for_devices", NULL);
+}
+
+
+#endif /* PROXY */
+
+
+/**
+ * xenDaemonListDomainsOld:
+ * @xend: pointer to the Xem Daemon block
+ *
+ * This method will return an array of names of currently running
+ * domains. The memory should be released will a call to free().
+ *
+ * Returns a list of names or NULL in case of error.
+ */
+char **
+xenDaemonListDomainsOld(virConnectPtr xend)
+{
+ size_t extra = 0;
+ struct sexpr *root = NULL;
+ char **ret = NULL;
+ int count = 0;
+ int i;
+ char *ptr;
+ struct sexpr *_for_i, *node;
+
+ root = sexpr_get(xend, "/xend/domain");
+ if (root == NULL)
+ goto error;
+
+ for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
+ _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
+ if (node->kind != SEXPR_VALUE)
+ continue;
+ extra += strlen(node->u.value) + 1;
+ count++;
+ }
+
+ /*
+ * We can'tuse the normal allocation routines as we are mixing
+ * an array of char * at the beginning followed by an array of char
+ * ret points to the NULL terminated array of char *
+ * ptr points to the current string after that array but in the same
+ * allocated block
+ */
+ if (virAlloc((void *)&ptr,
+ (count + 1) * sizeof(char *) + extra * sizeof(char)) < 0)
+ goto error;
+
+ ret = (char **) ptr;
+ ptr += sizeof(char *) * (count + 1);
+
+ i = 0;
+ for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
+ _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
+ if (node->kind != SEXPR_VALUE)
+ continue;
+ ret[i] = ptr;
+ strcpy(ptr, node->u.value);
+ ptr += strlen(node->u.value) + 1;
+ i++;
+ }
+
+ ret[i] = NULL;
+
+ error:
+ sexpr_free(root);
+ return ret;
+}
+
+#ifndef PROXY
+/**
+ * xenDaemonDomainCreateXML:
+ * @xend: A xend instance
+ * @sexpr: An S-Expr description of the domain.
+ *
+ * This method will create a domain based the passed in description. The
+ * domain will be paused after creation and must be unpaused with
+ * xenDaemonResumeDomain() to begin execution.
+ * This method may be deprecated once switching to XML-RPC based communcations
+ * with xend.
+ *
+ * Returns 0 for success, -1 (with errno) on error
+ */
+
+int
+xenDaemonDomainCreateXML(virConnectPtr xend, const char *sexpr)
+{
+ int ret, serrno;
+ char *ptr;
+
+ ptr = urlencode(sexpr);
+ if (ptr == NULL) {
+ /* this should be caught at the interface but ... */
+ virXendError(xend, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to urlencode the create S-Expr"));
+ return (-1);
+ }
+
+ ret = xend_op(xend, "", "op", "create", "config", ptr, NULL);
+
+ serrno = errno;
+ VIR_FREE(ptr);
+ errno = serrno;
+
+ return ret;
+}
+#endif /* ! PROXY */
+
+/**
+ * xenDaemonDomainLookupByName_ids:
+ * @xend: A xend instance
+ * @domname: The name of the domain
+ * @uuid: return value for the UUID if not NULL
+ *
+ * This method looks up the id of a domain
+ *
+ * Returns the id on success; -1 (with errno) on error
+ */
+int
+xenDaemonDomainLookupByName_ids(virConnectPtr xend, const char *domname,
+ unsigned char *uuid)
+{
+ struct sexpr *root;
+ const char *value;
+ int ret = -1;
+
+ if (uuid != NULL)
+ memset(uuid, 0, VIR_UUID_BUFLEN);
+ root = sexpr_get(xend, "/xend/domain/%s?detail=1", domname);
+ if (root == NULL)
+ goto error;
+
+ value = sexpr_node(root, "domain/domid");
+ if (value == NULL) {
+ virXendError(xend, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, missing domid"));
+ goto error;
+ }
+ ret = strtol(value, NULL, 0);
+ if ((ret == 0) && (value[0] != '0')) {
+ virXendError(xend, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incorrect domid not numeric"));
+ ret = -1;
+ } else if (uuid != NULL) {
+ if (sexpr_uuid(uuid, root, "domain/uuid") < 0) {
+ virXendError(xend, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, missing uuid"));
+ }
+ }
+
+ error:
+ sexpr_free(root);
+ return (ret);
+}
+
+
+/**
+ * xenDaemonDomainLookupByID:
+ * @xend: A xend instance
+ * @id: The id of the domain
+ * @name: return value for the name if not NULL
+ * @uuid: return value for the UUID if not NULL
+ *
+ * This method looks up the name of a domain based on its id
+ *
+ * Returns the 0 on success; -1 (with errno) on error
+ */
+int
+xenDaemonDomainLookupByID(virConnectPtr xend,
+ int id,
+ char **domname,
+ unsigned char *uuid)
+{
+ const char *name = NULL;
+ struct sexpr *root;
+
+ memset(uuid, 0, VIR_UUID_BUFLEN);
+
+ root = sexpr_get(xend, "/xend/domain/%d?detail=1", id);
+ if (root == NULL)
+ goto error;
+
+ name = sexpr_node(root, "domain/name");
+ if (name == NULL) {
+ virXendError(xend, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, missing name"));
+ goto error;
+ }
+ if (domname)
+ *domname = strdup(name);
+
+ if (sexpr_uuid(uuid, root, "domain/uuid") < 0) {
+ virXendError(xend, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, missing uuid"));
+ goto error;
+ }
+
+ sexpr_free(root);
+ return (0);
+
+error:
+ sexpr_free(root);
+ if (domname)
+ VIR_FREE(*domname);
+ return (-1);
+}
+
+
+#ifndef PROXY
+static int
+xend_detect_config_version(virConnectPtr conn) {
+ struct sexpr *root;
+ const char *value;
+ xenUnifiedPrivatePtr priv;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virXendError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ root = sexpr_get(conn, "/xend/node/");
+ if (root == NULL)
+ return (-1);
+
+ value = sexpr_node(root, "node/xend_config_format");
+
+ if (value) {
+ priv->xendConfigVersion = strtol(value, NULL, 10);
+ } else {
+ /* Xen prior to 3.0.3 did not have the xend_config_format
+ field, and is implicitly version 1. */
+ priv->xendConfigVersion = 1;
+ }
+ sexpr_free(root);
+ return (0);
+}
+
+#endif /* PROXY */
+
+/*****************************************************************
+ ******
+ ****** Parsing of SEXPR into virDomainDef objects
+ ******
+ *****************************************************************/
+
+/**
+ * xenDaemonParseSxprOS
+ * @xend: the xend connection object
+ * @node: the root of the parsed S-Expression
+ * @def: the domain config
+ * @hvm: true or 1 if no contains HVM S-Expression
+ * @bootloader: true or 1 if a bootloader is defined
+ *
+ * Parse the xend sexp for description of os and append it to buf.
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+static int
+xenDaemonParseSxprOS(virConnectPtr xend,
+ const struct sexpr *node,
+ virDomainDefPtr def,
+ int hvm)
+{
+ if (hvm) {
+ if (sexpr_node_copy(node, "domain/image/hvm/loader", &def->os.loader) < 0)
+ goto no_memory;
+ if (def->os.loader == NULL) {
+ if (sexpr_node_copy(node, "domain/image/hvm/kernel", &def->os.loader) < 0)
+ goto no_memory;
+
+ if (def->os.loader == NULL) {
+ virXendError(xend, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, missing HVM loader"));
+ return(-1);
+ }
+ } else {
+ if (sexpr_node_copy(node, "domain/image/hvm/kernel", &def->os.kernel) < 0)
+ goto no_memory;
+ if (sexpr_node_copy(node, "domain/image/hvm/ramdisk", &def->os.initrd) < 0)
+ goto no_memory;
+ if (sexpr_node_copy(node, "domain/image/hvm/args", &def->os.cmdline) < 0)
+ goto no_memory;
+ if (sexpr_node_copy(node, "domain/image/hvm/root", &def->os.root) < 0)
+ goto no_memory;
+ }
+ } else {
+ if (sexpr_node_copy(node, "domain/image/linux/kernel", &def->os.kernel) < 0)
+ goto no_memory;
+ if (sexpr_node_copy(node, "domain/image/linux/ramdisk", &def->os.initrd) < 0)
+ goto no_memory;
+ if (sexpr_node_copy(node, "domain/image/linux/args", &def->os.cmdline) < 0)
+ goto no_memory;
+ if (sexpr_node_copy(node, "domain/image/linux/root", &def->os.root) < 0)
+ goto no_memory;
+ }
+
+ /* If HVM kenrel == loader, then old xend, so kill off kernel */
+ if (hvm &&
+ def->os.kernel &&
+ STREQ(def->os.kernel, def->os.loader)) {
+ VIR_FREE(def->os.kernel);
+ }
+
+ if (!def->os.kernel &&
+ hvm) {
+ const char *boot = sexpr_node(node, "domain/image/hvm/boot");
+ if ((boot != NULL) && (boot[0] != 0)) {
+ while (*boot &&
+ def->os.nBootDevs < VIR_DOMAIN_BOOT_LAST) {
+ if (*boot == 'a')
+ def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_FLOPPY;
+ else if (*boot == 'c')
+ def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_DISK;
+ else if (*boot == 'd')
+ def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_CDROM;
+ else if (*boot == 'n')
+ def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_NET;
+ boot++;
+ }
+ }
+ }
+
+ if (!hvm &&
+ !def->os.kernel &&
+ !def->os.bootloader) {
+ virXendError(xend, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, missing kernel & bootloader"));
+ return -1;
+ }
+
+ return 0;
+
+no_memory:
+ virReportOOMError(xend);
+ return -1;
+}
+
+
+int
+xend_parse_sexp_desc_char(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *devtype,
+ int portNum,
+ const char *value,
+ const char *tty)
+{
+ const char *type;
+ int telnet = 0;
+ char *bindPort = NULL;
+ char *bindHost = NULL;
+ char *connectPort = NULL;
+ char *connectHost = NULL;
+ char *path = NULL;
+ int ret = -1;
+
+ if (value[0] == '/') {
+ type = "dev";
+ } else if (STRPREFIX(value, "null")) {
+ type = "null";
+ value = NULL;
+ } else if (STRPREFIX(value, "vc")) {
+ type = "vc";
+ value = NULL;
+ } else if (STRPREFIX(value, "pty")) {
+ type = "pty";
+ value = NULL;
+ } else if (STRPREFIX(value, "stdio")) {
+ type = "stdio";
+ value = NULL;
+ } else if (STRPREFIX(value, "file:")) {
+ type = "file";
+ value += sizeof("file:")-1;
+ } else if (STRPREFIX(value, "pipe:")) {
+ type = "pipe";
+ value += sizeof("pipe:")-1;
+ } else if (STRPREFIX(value, "tcp:")) {
+ type = "tcp";
+ value += sizeof("tcp:")-1;
+ } else if (STRPREFIX(value, "telnet:")) {
+ type = "tcp";
+ value += sizeof("telnet:")-1;
+ telnet = 1;
+ } else if (STRPREFIX(value, "udp:")) {
+ type = "udp";
+ value += sizeof("udp:")-1;
+ } else if (STRPREFIX(value, "unix:")) {
+ type = "unix";
+ value += sizeof("unix:")-1;
+ } else {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Unknown char device type"));
+ return -1;
+ }
+
+ /* Compat with legacy <console tty='/dev/pts/5'/> syntax */
+ if (STREQ(devtype, "console") &&
+ STREQ(type, "pty") &&
+ tty != NULL) {
+ virBufferVSprintf(buf, " <%s type='%s' tty='%s'>\n",
+ devtype, type, tty);
+ } else {
+ virBufferVSprintf(buf, " <%s type='%s'>\n",
+ devtype, type);
+ }
+
+ if (STREQ(type, "null") ||
+ STREQ(type, "vc") ||
+ STREQ(type, "stdio")) {
+ /* no source needed */
+ } else if (STREQ(type, "pty")) {
+ if (tty)
+ virBufferVSprintf(buf, " <source path='%s'/>\n",
+ tty);
+ } else if (STREQ(type, "file") ||
+ STREQ(type, "pipe")) {
+ virBufferVSprintf(buf, " <source path='%s'/>\n",
+ value);
+ } else if (STREQ(type, "tcp")) {
+ const char *offset = strchr(value, ':');
+ const char *offset2;
+ const char *mode, *protocol;
+
+ if (offset == NULL) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("malformed char device string"));
+ goto error;
+ }
+
+ if (offset != value &&
+ (bindHost = strndup(value, offset - value)) == NULL)
+ goto no_memory;
+
+ offset2 = strchr(offset, ',');
+ if (offset2 == NULL)
+ bindPort = strdup(offset+1);
+ else
+ bindPort = strndup(offset+1, offset2-(offset+1));
+ if (bindPort == NULL)
+ goto no_memory;
+
+ if (offset2 && strstr(offset2, ",listen"))
+ mode = "bind";
+ else
+ mode = "connect";
+ protocol = telnet ? "telnet":"raw";
+
+ if (bindHost) {
+ virBufferVSprintf(buf,
+ " <source mode='%s' host='%s' service='%s'/>\n",
+ mode, bindHost, bindPort);
+ } else {
+ virBufferVSprintf(buf,
+ " <source mode='%s' service='%s'/>\n",
+ mode, bindPort);
+ }
+ virBufferVSprintf(buf,
+ " <protocol type='%s'/>\n",
+ protocol);
+ } else if (STREQ(type, "udp")) {
+ const char *offset = strchr(value, ':');
+ const char *offset2, *offset3;
+
+ if (offset == NULL) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("malformed char device string"));
+ goto error;
+ }
+
+ if (offset != value &&
+ (connectHost = strndup(value, offset - value)) == NULL)
+ goto no_memory;
+
+ offset2 = strchr(offset, '@');
+ if (offset2 != NULL) {
+ if ((connectPort = strndup(offset + 1, offset2-(offset+1))) == NULL)
+ goto no_memory;
+
+ offset3 = strchr(offset2, ':');
+ if (offset3 == NULL) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("malformed char device string"));
+ goto error;
+ }
+
+ if (offset3 > (offset2 + 1) &&
+ (bindHost = strndup(offset2 + 1, offset3 - (offset2+1))) == NULL)
+ goto no_memory;
+
+ if ((bindPort = strdup(offset3 + 1)) == NULL)
+ goto no_memory;
+ } else {
+ if ((connectPort = strdup(offset + 1)) == NULL)
+ goto no_memory;
+ }
+
+ if (connectPort) {
+ if (connectHost) {
+ virBufferVSprintf(buf,
+ " <source mode='connect' host='%s' service='%s'/>\n",
+ connectHost, connectPort);
+ } else {
+ virBufferVSprintf(buf,
+ " <source mode='connect' service='%s'/>\n",
+ connectPort);
+ }
+ }
+ if (bindPort) {
+ if (bindHost) {
+ virBufferVSprintf(buf,
+ " <source mode='bind' host='%s' service='%s'/>\n",
+ bindHost, bindPort);
+ } else {
+ virBufferVSprintf(buf,
+ " <source mode='bind' service='%s'/>\n",
+ bindPort);
+ }
+ }
+
+ } else if (STREQ(type, "unix")) {
+ const char *offset = strchr(value, ',');
+ int dolisten = 0;
+ if (offset)
+ path = strndup(value, (offset - value));
+ else
+ path = strdup(value);
+ if (path == NULL)
+ goto no_memory;
+
+ if (offset != NULL &&
+ strstr(offset, ",listen") != NULL)
+ dolisten = 1;
+
+ virBufferVSprintf(buf, " <source mode='%s' path='%s'/>\n",
+ dolisten ? "bind" : "connect", path);
+ }
+
+ virBufferVSprintf(buf, " <target port='%d'/>\n",
+ portNum);
+
+ virBufferVSprintf(buf, " </%s>\n",
+ devtype);
+
+ ret = 0;
+
+ if (ret == -1) {
+no_memory:
+ virReportOOMError(conn);
+ }
+
+error:
+
+ VIR_FREE(path);
+ VIR_FREE(bindHost);
+ VIR_FREE(bindPort);
+ VIR_FREE(connectHost);
+ VIR_FREE(connectPort);
+
+ return ret;
+}
+
+virDomainChrDefPtr
+xenDaemonParseSxprChar(virConnectPtr conn,
+ const char *value,
+ const char *tty)
+{
+ char prefix[10];
+ char *tmp;
+ virDomainChrDefPtr def;
+
+ if (VIR_ALLOC(def) < 0) {
+ virReportOOMError(conn);
+ return NULL;
+ }
+
+ strncpy(prefix, value, sizeof(prefix)-1);
+ NUL_TERMINATE(prefix);
+
+ if (value[0] == '/') {
+ def->type = VIR_DOMAIN_CHR_TYPE_DEV;
+ } else {
+ if ((tmp = strchr(prefix, ':')) != NULL) {
+ *tmp = '\0';
+ value += (tmp - prefix) + 1;
+ }
+
+ if (STREQ(prefix, "telnet")) {
+ def->type = VIR_DOMAIN_CHR_TYPE_TCP;
+ def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
+ } else {
+ if ((def->type = virDomainChrTypeFromString(prefix)) < 0) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown chr device type '%s'"), prefix);
+ goto error;
+ }
+ }
+ }
+
+ /* Compat with legacy <console tty='/dev/pts/5'/> syntax */
+ switch (def->type) {
+ case VIR_DOMAIN_CHR_TYPE_PTY:
+ if (tty != NULL &&
+ !(def->data.file.path = strdup(tty)))
+ goto no_memory;
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_FILE:
+ case VIR_DOMAIN_CHR_TYPE_PIPE:
+ if (!(def->data.file.path = strdup(value)))
+ goto no_memory;
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_TCP:
+ {
+ const char *offset = strchr(value, ':');
+ const char *offset2;
+
+ if (offset == NULL) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("malformed char device string"));
+ goto error;
+ }
+
+ if (offset != value &&
+ (def->data.tcp.host = strndup(value, offset - value)) == NULL)
+ goto no_memory;
+
+ offset2 = strchr(offset, ',');
+ if (offset2 == NULL)
+ def->data.tcp.service = strdup(offset+1);
+ else
+ def->data.tcp.service = strndup(offset+1, offset2-(offset+1));
+ if (def->data.tcp.service == NULL)
+ goto no_memory;
+
+ if (offset2 && strstr(offset2, ",listen"))
+ def->data.tcp.listen = 1;
+ }
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UDP:
+ {
+ const char *offset = strchr(value, ':');
+ const char *offset2, *offset3;
+
+ if (offset == NULL) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("malformed char device string"));
+ goto error;
+ }
+
+ if (offset != value &&
+ (def->data.udp.connectHost = strndup(value, offset - value)) == NULL)
+ goto no_memory;
+
+ offset2 = strchr(offset, '@');
+ if (offset2 != NULL) {
+ if ((def->data.udp.connectService = strndup(offset + 1, offset2-(offset+1))) == NULL)
+ goto no_memory;
+
+ offset3 = strchr(offset2, ':');
+ if (offset3 == NULL) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("malformed char device string"));
+ goto error;
+ }
+
+ if (offset3 > (offset2 + 1) &&
+ (def->data.udp.bindHost = strndup(offset2 + 1, offset3 - (offset2+1))) == NULL)
+ goto no_memory;
+
+ if ((def->data.udp.bindService = strdup(offset3 + 1)) == NULL)
+ goto no_memory;
+ } else {
+ if ((def->data.udp.connectService = strdup(offset + 1)) == NULL)
+ goto no_memory;
+ }
+ }
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UNIX:
+ {
+ const char *offset = strchr(value, ',');
+ if (offset)
+ def->data.nix.path = strndup(value, (offset - value));
+ else
+ def->data.nix.path = strdup(value);
+ if (def->data.nix.path == NULL)
+ goto no_memory;
+
+ if (offset != NULL &&
+ strstr(offset, ",listen") != NULL)
+ def->data.nix.listen = 1;
+ }
+ break;
+ }
+
+ return def;
+
+no_memory:
+ virReportOOMError(conn);
+error:
+ virDomainChrDefFree(def);
+ return NULL;
+}
+
+/**
+ * xend_parse_sexp_desc_disks
+ * @conn: connection
+ * @root: root sexpr
+ * @xendConfigVersion: version of xend
+ *
+ * This parses out block devices from the domain sexpr
+ *
+ * Returns 0 if successful or -1 if failed.
+ */
+static int
+xenDaemonParseSxprDisks(virConnectPtr conn,
+ virDomainDefPtr def,
+ const struct sexpr *root,
+ int hvm,
+ int xendConfigVersion)
+{
+ const struct sexpr *cur, *node;
+ virDomainDiskDefPtr disk = NULL;
+
+ for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
+ node = cur->u.s.car;
+ /* Normally disks are in a (device (vbd ...)) block
+ but blktap disks ended up in a differently named
+ (device (tap ....)) block.... */
+ if (sexpr_lookup(node, "device/vbd") ||
+ sexpr_lookup(node, "device/tap")) {
+ char *offset;
+ const char *src = NULL;
+ const char *dst = NULL;
+ const char *mode = NULL;
+
+ /* Again dealing with (vbd...) vs (tap ...) differences */
+ if (sexpr_lookup(node, "device/vbd")) {
+ src = sexpr_node(node, "device/vbd/uname");
+ dst = sexpr_node(node, "device/vbd/dev");
+ mode = sexpr_node(node, "device/vbd/mode");
+ } else {
+ src = sexpr_node(node, "device/tap/uname");
+ dst = sexpr_node(node, "device/tap/dev");
+ mode = sexpr_node(node, "device/tap/mode");
+ }
+
+ if (VIR_ALLOC(disk) < 0)
+ goto no_memory;
+
+ if (dst == NULL) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, vbd has no dev"));
+ goto error;
+ }
+
+ if (src == NULL) {
+ /* There is a case without the uname to the CD-ROM device */
+ offset = strchr(dst, ':');
+ if (!offset ||
+ !hvm ||
+ STRNEQ(offset, ":cdrom")) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, vbd has no src"));
+ goto error;
+ }
+ }
+
+ if (src != NULL) {
+ offset = strchr(src, ':');
+ if (!offset) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot parse vbd filename, missing driver name"));
+ goto error;
+ }
+
+ if (VIR_ALLOC_N(disk->driverName, (offset-src)+1) < 0)
+ goto no_memory;
+ strncpy(disk->driverName, src, (offset-src));
+ disk->driverName[offset-src] = '\0';
+
+ src = offset + 1;
+
+ if (STREQ (disk->driverName, "tap")) {
+ offset = strchr(src, ':');
+ if (!offset) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot parse vbd filename, missing driver type"));
+ goto error;
+ }
+
+ if (VIR_ALLOC_N(disk->driverType, (offset-src)+1)< 0)
+ goto no_memory;
+ strncpy(disk->driverType, src, (offset-src));
+ disk->driverType[offset-src] = '\0';
+
+ src = offset + 1;
+ /* Its possible to use blktap driver for block devs
+ too, but kinda pointless because blkback is better,
+ so we assume common case here. If blktap becomes
+ omnipotent, we can revisit this, perhaps stat()'ing
+ the src file in question */
+ disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
+ } else if (STREQ(disk->driverName, "phy")) {
+ disk->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
+ } else if (STREQ(disk->driverName, "file")) {
+ disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
+ }
+ } else {
+ /* No CDROM media so can't really tell. We'll just
+ call if a FILE for now and update when media
+ is inserted later */
+ disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
+ }
+
+ if (STREQLEN (dst, "ioemu:", 6))
+ dst += 6;
+
+ disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
+ /* New style disk config from Xen >= 3.0.3 */
+ if (xendConfigVersion > 1) {
+ offset = strrchr(dst, ':');
+ if (offset) {
+ if (STREQ (offset, ":cdrom")) {
+ disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
+ } else if (STREQ (offset, ":disk")) {
+ /* The default anyway */
+ } else {
+ /* Unknown, lets pretend its a disk too */
+ }
+ offset[0] = '\0';
+ }
+ }
+
+ if (!(disk->dst = strdup(dst)))
+ goto no_memory;
+ if (src &&
+ !(disk->src = strdup(src)))
+ goto no_memory;
+
+ if (STRPREFIX(disk->dst, "xvd"))
+ disk->bus = VIR_DOMAIN_DISK_BUS_XEN;
+ else if (STRPREFIX(disk->dst, "hd"))
+ disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
+ else if (STRPREFIX(disk->dst, "sd"))
+ disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
+ else
+ disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
+
+ if (mode &&
+ strchr(mode, 'r'))
+ disk->readonly = 1;
+ if (mode &&
+ strchr(mode, '!'))
+ disk->shared = 1;
+
+ if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
+ goto no_memory;
+
+ def->disks[def->ndisks++] = disk;
+ disk = NULL;
+ }
+ }
+
+ return 0;
+
+no_memory:
+ virReportOOMError(conn);
+
+error:
+ virDomainDiskDefFree(disk);
+ return -1;
+}
+
+
+static int
+xenDaemonParseSxprNets(virConnectPtr conn,
+ virDomainDefPtr def,
+ const struct sexpr *root)
+{
+ virDomainNetDefPtr net = NULL;
+ const struct sexpr *cur, *node;
+ const char *tmp;
+ int vif_index = 0;
+
+ for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
+ node = cur->u.s.car;
+ if (sexpr_lookup(node, "device/vif")) {
+ const char *tmp2, *model;
+ char buf[50];
+ tmp2 = sexpr_node(node, "device/vif/script");
+ tmp = sexpr_node(node, "device/vif/bridge");
+ model = sexpr_node(node, "device/vif/model");
+
+ if (VIR_ALLOC(net) < 0)
+ goto no_memory;
+
+ if (tmp != NULL ||
+ (tmp2 != NULL && STREQ(tmp2, DEFAULT_VIF_SCRIPT))) {
+ net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
+ /* XXX virtual network reverse resolve */
+
+ if (tmp &&
+ !(net->data.bridge.brname = strdup(tmp)))
+ goto no_memory;
+ if (tmp2 &&
+ net->type == VIR_DOMAIN_NET_TYPE_BRIDGE &&
+ !(net->data.bridge.script = strdup(tmp2)))
+ goto no_memory;
+ tmp = sexpr_node(node, "device/vif/ip");
+ if (tmp &&
+ !(net->data.bridge.ipaddr = strdup(tmp)))
+ goto no_memory;
+ } else {
+ net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
+ if (tmp2 &&
+ !(net->data.ethernet.script = strdup(tmp2)))
+ goto no_memory;
+ tmp = sexpr_node(node, "device/vif/ip");
+ if (tmp &&
+ !(net->data.ethernet.ipaddr = strdup(tmp)))
+ goto no_memory;
+ }
+
+ tmp = sexpr_node(node, "device/vif/vifname");
+ if (!tmp) {
+ snprintf(buf, sizeof(buf), "vif%d.%d", def->id, vif_index);
+ tmp = buf;
+ }
+ if (!(net->ifname = strdup(tmp)))
+ goto no_memory;
+
+ tmp = sexpr_node(node, "device/vif/mac");
+ if (tmp) {
+ unsigned int mac[6];
+ if (sscanf(tmp, "%02x:%02x:%02x:%02x:%02x:%02x",
+ (unsigned int*)&mac[0],
+ (unsigned int*)&mac[1],
+ (unsigned int*)&mac[2],
+ (unsigned int*)&mac[3],
+ (unsigned int*)&mac[4],
+ (unsigned int*)&mac[5]) != 6) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("malformed mac address '%s'"),
+ tmp);
+ goto cleanup;
+ }
+ net->mac[0] = mac[0];
+ net->mac[1] = mac[1];
+ net->mac[2] = mac[2];
+ net->mac[3] = mac[3];
+ net->mac[4] = mac[4];
+ net->mac[5] = mac[5];
+ }
+
+ if (model &&
+ !(net->model = strdup(model)))
+ goto no_memory;
+
+ if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0)
+ goto no_memory;
+
+ def->nets[def->nnets++] = net;
+ vif_index++;
+ }
+ }
+
+ return 0;
+
+no_memory:
+ virReportOOMError(conn);
+cleanup:
+ virDomainNetDefFree(net);
+ return -1;
+}
+
+
+int
+xenDaemonParseSxprSound(virConnectPtr conn,
+ virDomainDefPtr def,
+ const char *str)
+{
+ if (STREQ(str, "all")) {
+ int i;
+
+ /*
+ * Special compatability code for Xen with a bogus
+ * sound=all in config.
+ *
+ * NB delibrately, don't include all possible
+ * sound models anymore, just the 2 that were
+ * historically present in Xen's QEMU.
+ *
+ * ie just es1370 + sb16.
+ *
+ * Hence use of MODEL_ES1370 + 1, instead of MODEL_LAST
+ */
+
+ if (VIR_ALLOC_N(def->sounds,
+ VIR_DOMAIN_SOUND_MODEL_ES1370 + 1) < 0)
+ goto no_memory;
+
+
+ for (i = 0 ; i < (VIR_DOMAIN_SOUND_MODEL_ES1370 + 1) ; i++) {
+ virDomainSoundDefPtr sound;
+ if (VIR_ALLOC(sound) < 0)
+ goto no_memory;
+ sound->model = i;
+ def->sounds[def->nsounds++] = sound;
+ }
+ } else {
+ char model[10];
+ const char *offset = str, *offset2;
+
+ do {
+ int len;
+ virDomainSoundDefPtr sound;
+ offset2 = strchr(offset, ',');
+ if (offset2)
+ len = (offset2 - offset);
+ else
+ len = strlen(offset);
+ if (len > (sizeof(model)-1)) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected sound model %s"), offset);
+ goto error;
+ }
+ strncpy(model, offset, len);
+ model[len] = '\0';
+
+ if (VIR_ALLOC(sound) < 0)
+ goto no_memory;
+
+ if ((sound->model = virDomainSoundModelTypeFromString(model)) < 0) {
+ VIR_FREE(sound);
+ goto error;
+ }
+
+ if (VIR_REALLOC_N(def->sounds, def->nsounds+1) < 0) {
+ virDomainSoundDefFree(sound);
+ goto no_memory;
+ }
+
+ def->sounds[def->nsounds++] = sound;
+ offset = offset2 ? offset2 + 1 : NULL;
+ } while (offset);
+ }
+
+ return 0;
+
+no_memory:
+ virReportOOMError(conn);
+error:
+ return -1;
+}
+
+
+static int
+xenDaemonParseSxprUSB(virConnectPtr conn,
+ virDomainDefPtr def,
+ const struct sexpr *root)
+{
+ struct sexpr *cur, *node;
+ const char *tmp;
+
+ for (cur = sexpr_lookup(root, "domain/image/hvm"); cur && cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
+ node = cur->u.s.car;
+ if (sexpr_lookup(node, "usbdevice")) {
+ tmp = sexpr_node(node, "usbdevice");
+ if (tmp && *tmp) {
+ if (STREQ(tmp, "tablet") ||
+ STREQ(tmp, "mouse")) {
+ virDomainInputDefPtr input;
+ if (VIR_ALLOC(input) < 0)
+ goto no_memory;
+ input->bus = VIR_DOMAIN_INPUT_BUS_USB;
+ if (STREQ(tmp, "tablet"))
+ input->type = VIR_DOMAIN_INPUT_TYPE_TABLET;
+ else
+ input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
+
+ if (VIR_REALLOC_N(def->inputs, def->ninputs+1) < 0) {
+ VIR_FREE(input);
+ goto no_memory;
+ }
+ def->inputs[def->ninputs++] = input;
+ } else {
+ /* XXX Handle other non-input USB devices later */
+ }
+ }
+ }
+ }
+ return 0;
+
+no_memory:
+ virReportOOMError(conn);
+ return -1;
+}
+
+static int
+xenDaemonParseSxprGraphicsOld(virConnectPtr conn,
+ virDomainDefPtr def,
+ const struct sexpr *root,
+ int hvm,
+ int xendConfigVersion)
+{
+#ifndef PROXY
+ xenUnifiedPrivatePtr priv = conn->privateData;
+#endif
+ const char *tmp;
+ virDomainGraphicsDefPtr graphics = NULL;
+
+ if ((tmp = sexpr_fmt_node(root, "domain/image/%s/vnc", hvm ? "hvm" : "linux")) &&
+ tmp[0] == '1') {
+ /* Graphics device (HVM, or old (pre-3.0.4) style PV VNC config) */
+ int port;
+ const char *listenAddr = sexpr_fmt_node(root, "domain/image/%s/vnclisten", hvm ? "hvm" : "linux");
+ const char *vncPasswd = sexpr_fmt_node(root, "domain/image/%s/vncpasswd", hvm ? "hvm" : "linux");
+ const char *keymap = sexpr_fmt_node(root, "domain/image/%s/keymap", hvm ? "hvm" : "linux");
+ const char *unused = sexpr_fmt_node(root, "domain/image/%s/vncunused", hvm ? "hvm" : "linux");
+
+ xenUnifiedLock(priv);
+ port = xenStoreDomainGetVNCPort(conn, def->id);
+ xenUnifiedUnlock(priv);
+
+ if (VIR_ALLOC(graphics) < 0)
+ goto no_memory;
+
+ graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
+ /* For Xen >= 3.0.3, don't generate a fixed port mapping
+ * because it will almost certainly be wrong ! Just leave
+ * it as -1 which lets caller see that the VNC server isn't
+ * present yet. Subsquent dumps of the XML will eventually
+ * find the port in XenStore once VNC server has started
+ */
+ if (port == -1 && xendConfigVersion < 2)
+ port = 5900 + def->id;
+
+ if ((unused && STREQ(unused, "1")) || port == -1)
+ graphics->data.vnc.autoport = 1;
+ graphics->data.vnc.port = port;
+
+ if (listenAddr &&
+ !(graphics->data.vnc.listenAddr = strdup(listenAddr)))
+ goto no_memory;
+
+ if (vncPasswd &&
+ !(graphics->data.vnc.passwd = strdup(vncPasswd)))
+ goto no_memory;
+
+ if (keymap &&
+ !(graphics->data.vnc.keymap = strdup(keymap)))
+ goto no_memory;
+
+ if (VIR_ALLOC_N(def->graphics, 1) < 0)
+ goto no_memory;
+ def->graphics[0] = graphics;
+ def->ngraphics = 1;
+ graphics = NULL;
+ } else if ((tmp = sexpr_fmt_node(root, "domain/image/%s/sdl", hvm ? "hvm" : "linux")) &&
+ tmp[0] == '1') {
+ /* Graphics device (HVM, or old (pre-3.0.4) style PV sdl config) */
+ const char *display = sexpr_fmt_node(root, "domain/image/%s/display", hvm ? "hvm" : "linux");
+ const char *xauth = sexpr_fmt_node(root, "domain/image/%s/xauthority", hvm ? "hvm" : "linux");
+
+ if (VIR_ALLOC(graphics) < 0)
+ goto no_memory;
+
+ graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
+ if (display &&
+ !(graphics->data.sdl.display = strdup(display)))
+ goto no_memory;
+ if (xauth &&
+ !(graphics->data.sdl.xauth = strdup(xauth)))
+ goto no_memory;
+
+ if (VIR_ALLOC_N(def->graphics, 1) < 0)
+ goto no_memory;
+ def->graphics[0] = graphics;
+ def->ngraphics = 1;
+ graphics = NULL;
+ }
+
+ return 0;
+
+no_memory:
+ virReportOOMError(conn);
+ virDomainGraphicsDefFree(graphics);
+ return -1;
+}
+
+
+static int
+xenDaemonParseSxprGraphicsNew(virConnectPtr conn,
+ virDomainDefPtr def,
+ const struct sexpr *root)
+{
+#ifndef PROXY
+ xenUnifiedPrivatePtr priv = conn->privateData;
+#endif
+ virDomainGraphicsDefPtr graphics = NULL;
+ const struct sexpr *cur, *node;
+ const char *tmp;
+
+ /* append network devices and framebuffer */
+ for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
+ node = cur->u.s.car;
+ if (sexpr_lookup(node, "device/vfb")) {
+ /* New style graphics config for PV guests in >= 3.0.4,
+ * or for HVM guests in >= 3.0.5 */
+ if (sexpr_node(node, "device/vfb/type")) {
+ tmp = sexpr_node(node, "device/vfb/type");
+ } else if (sexpr_node(node, "device/vfb/vnc")) {
+ tmp = "vnc";
+ } else if (sexpr_node(node, "device/vfb/sdl")) {
+ tmp = "sdl";
+ } else {
+ tmp = "unknown";
+ }
+
+ if (VIR_ALLOC(graphics) < 0)
+ goto no_memory;
+
+ if ((graphics->type = virDomainGraphicsTypeFromString(tmp)) < 0) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown graphics type '%s'"), tmp);
+ goto error;
+ }
+
+ if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
+ const char *display = sexpr_node(node, "device/vfb/display");
+ const char *xauth = sexpr_node(node, "device/vfb/xauthority");
+ if (display &&
+ !(graphics->data.sdl.display = strdup(display)))
+ goto no_memory;
+ if (xauth &&
+ !(graphics->data.sdl.xauth = strdup(xauth)))
+ goto no_memory;
+ } else {
+ int port;
+ const char *listenAddr = sexpr_node(node, "device/vfb/vnclisten");
+ const char *vncPasswd = sexpr_node(node, "device/vfb/vncpasswd");
+ const char *keymap = sexpr_node(node, "device/vfb/keymap");
+ const char *unused = sexpr_node(node, "device/vfb/vncunused");
+
+ xenUnifiedLock(priv);
+ port = xenStoreDomainGetVNCPort(conn, def->id);
+ xenUnifiedUnlock(priv);
+
+ // Didn't find port entry in xenstore
+ if (port == -1) {
+ const char *str = sexpr_node(node, "device/vfb/vncdisplay");
+ int val;
+ if (str != NULL && virStrToLong_i(str, NULL, 0, &val) == 0)
+ port = val;
+ }
+
+ if ((unused && STREQ(unused, "1")) || port == -1)
+ graphics->data.vnc.autoport = 1;
+
+ if (port >= 0 && port < 5900)
+ port += 5900;
+ graphics->data.vnc.port = port;
+
+ if (listenAddr &&
+ !(graphics->data.vnc.listenAddr = strdup(listenAddr)))
+ goto no_memory;
+
+ if (vncPasswd &&
+ !(graphics->data.vnc.passwd = strdup(vncPasswd)))
+ goto no_memory;
+
+ if (keymap &&
+ !(graphics->data.vnc.keymap = strdup(keymap)))
+ goto no_memory;
+ }
+
+ if (VIR_ALLOC_N(def->graphics, 1) < 0)
+ goto no_memory;
+ def->graphics[0] = graphics;
+ def->ngraphics = 1;
+ graphics = NULL;
+ break;
+ }
+ }
+
+ return 0;
+
+no_memory:
+ virReportOOMError(conn);
+error:
+ virDomainGraphicsDefFree(graphics);
+ return -1;
+}
+
+/**
+ * xenDaemonParseSxprPCI
+ * @conn: connection
+ * @root: root sexpr
+ *
+ * This parses out block devices from the domain sexpr
+ *
+ * Returns 0 if successful or -1 if failed.
+ */
+static int
+xenDaemonParseSxprPCI(virConnectPtr conn,
+ virDomainDefPtr def,
+ const struct sexpr *root)
+{
+ const struct sexpr *cur, *tmp = NULL, *node;
+ virDomainHostdevDefPtr dev = NULL;
+
+ /*
+ * With the (domain ...) block we have the following odd setup
+ *
+ * (device
+ * (pci
+ * (dev (domain 0x0000) (bus 0x00) (slot 0x1b) (func 0x0))
+ * (dev (domain 0x0000) (bus 0x00) (slot 0x13) (func 0x0))
+ * )
+ * )
+ *
+ * Normally there is one (device ...) block per device, but in
+ * wierd world of Xen PCI, once (device ...) covers multiple
+ * devices.
+ */
+
+ for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
+ node = cur->u.s.car;
+ if ((tmp = sexpr_lookup(node, "device/pci")) != NULL)
+ break;
+ }
+
+ if (!tmp)
+ return 0;
+
+ for (cur = tmp; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
+ const char *domain = NULL;
+ const char *bus = NULL;
+ const char *slot = NULL;
+ const char *func = NULL;
+ int domainID;
+ int busID;
+ int slotID;
+ int funcID;
+
+ node = cur->u.s.car;
+ if (!sexpr_lookup(node, "dev"))
+ continue;
+
+ if (!(domain = sexpr_node(node, "dev/domain"))) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing PCI domain"));
+ goto error;
+ }
+ if (!(bus = sexpr_node(node, "dev/bus"))) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing PCI bus"));
+ goto error;
+ }
+ if (!(slot = sexpr_node(node, "dev/slot"))) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing PCI slot"));
+ goto error;
+ }
+ if (!(func = sexpr_node(node, "dev/func"))) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing PCI func"));
+ goto error;
+ }
+
+ if (virStrToLong_i(domain, NULL, 0, &domainID) < 0) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse PCI domain '%s'"), domain);
+ goto error;
+ }
+ if (virStrToLong_i(bus, NULL, 0, &busID) < 0) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse PCI bus '%s'"), bus);
+ goto error;
+ }
+ if (virStrToLong_i(slot, NULL, 0, &slotID) < 0) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse PCI slot '%s'"), slot);
+ goto error;
+ }
+ if (virStrToLong_i(func, NULL, 0, &funcID) < 0) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse PCI func '%s'"), func);
+ goto error;
+ }
+
+ if (VIR_ALLOC(dev) < 0)
+ goto no_memory;
+
+ dev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
+ dev->managed = 0;
+ dev->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
+ dev->source.subsys.u.pci.domain = domainID;
+ dev->source.subsys.u.pci.bus = busID;
+ dev->source.subsys.u.pci.slot = slotID;
+ dev->source.subsys.u.pci.function = funcID;
+
+ if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0) {
+ goto no_memory;
+ }
+
+ def->hostdevs[def->nhostdevs++] = dev;
+ }
+
+ return 0;
+
+no_memory:
+ virReportOOMError(conn);
+
+error:
+ virDomainHostdevDefFree(dev);
+ return -1;
+}
+
+
+/**
+ * xenDaemonParseSxpr:
+ * @conn: the connection associated with the XML
+ * @root: the root of the parsed S-Expression
+ * @xendConfigVersion: version of xend
+ * @cpus: set of cpus the domain may be pinned to
+ *
+ * Parse the xend sexp description and turn it into the XML format similar
+ * to the one unsed for creation.
+ *
+ * Returns the 0 terminated XML string or NULL in case of error.
+ * the caller must free() the returned value.
+ */
+static virDomainDefPtr
+xenDaemonParseSxpr(virConnectPtr conn,
+ const struct sexpr *root,
+ int xendConfigVersion,
+ const char *cpus)
+{
+#ifndef PROXY
+ xenUnifiedPrivatePtr priv = conn->privateData;
+#endif
+ const char *tmp;
+ virDomainDefPtr def;
+ int hvm = 0;
+ char *tty = NULL;
+
+ if (VIR_ALLOC(def) < 0)
+ goto no_memory;
+
+ tmp = sexpr_node(root, "domain/domid");
+ if (tmp == NULL && xendConfigVersion < 3) { /* Old XenD, domid was mandatory */
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, missing id"));
+ goto error;
+ }
+ def->virtType = VIR_DOMAIN_VIRT_XEN;
+ if (tmp)
+ def->id = sexpr_int(root, "domain/domid");
+ else
+ def->id = -1;
+
+ if (sexpr_node_copy(root, "domain/name", &def->name) < 0)
+ goto no_memory;
+ if (def->name == NULL) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, missing name"));
+ goto error;
+ }
+
+ tmp = sexpr_node(root, "domain/uuid");
+ if (tmp == NULL) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, missing name"));
+ goto error;
+ }
+ virUUIDParse(tmp, def->uuid);
+
+ hvm = sexpr_lookup(root, "domain/image/hvm") ? 1 : 0;
+ if (!hvm) {
+ if (sexpr_node_copy(root, "domain/bootloader",
+ &def->os.bootloader) < 0)
+ goto no_memory;
+
+ if (!def->os.bootloader &&
+ sexpr_has(root, "domain/bootloader") &&
+ (def->os.bootloader = strdup("")) == NULL)
+ goto no_memory;
+
+ if (def->os.bootloader &&
+ sexpr_node_copy(root, "domain/bootloader_args",
+ &def->os.bootloaderArgs) < 0)
+ goto no_memory;
+ }
+
+ if (!(def->os.type = strdup(hvm ? "hvm" : "linux")))
+ goto no_memory;
+
+ if (def->id != 0) {
+ if (sexpr_lookup(root, "domain/image")) {
+ if (xenDaemonParseSxprOS(conn, root, def, hvm) < 0)
+ goto error;
+ }
+ }
+
+ def->maxmem = (unsigned long) (sexpr_u64(root, "domain/maxmem") << 10);
+ def->memory = (unsigned long) (sexpr_u64(root, "domain/memory") << 10);
+ if (def->memory > def->maxmem)
+ def->maxmem = def->memory;
+
+ if (cpus != NULL) {
+ def->cpumasklen = VIR_DOMAIN_CPUMASK_LEN;
+ if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0) {
+ virReportOOMError(conn);
+ goto error;
+ }
+
+ if (virDomainCpuSetParse(conn, &cpus,
+ 0, def->cpumask,
+ def->cpumasklen) < 0) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("invalid CPU mask %s"), cpus);
+ goto error;
+ }
+ }
+
+ def->vcpus = sexpr_int(root, "domain/vcpus");
+
+ tmp = sexpr_node(root, "domain/on_poweroff");
+ if (tmp != NULL) {
+ if ((def->onPoweroff = virDomainLifecycleTypeFromString(tmp)) < 0) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown lifecycle type %s"), tmp);
+ goto error;
+ }
+ } else
+ def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY;
+
+ tmp = sexpr_node(root, "domain/on_reboot");
+ if (tmp != NULL) {
+ if ((def->onReboot = virDomainLifecycleTypeFromString(tmp)) < 0) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown lifecycle type %s"), tmp);
+ goto error;
+ }
+ } else
+ def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART;
+
+ tmp = sexpr_node(root, "domain/on_crash");
+ if (tmp != NULL) {
+ if ((def->onCrash = virDomainLifecycleTypeFromString(tmp)) < 0) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown lifecycle type %s"), tmp);
+ goto error;
+ }
+ } else
+ def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY;
+
+
+ if (hvm) {
+ if (sexpr_int(root, "domain/image/hvm/acpi"))
+ def->features |= (1 << VIR_DOMAIN_FEATURE_ACPI);
+ if (sexpr_int(root, "domain/image/hvm/apic"))
+ def->features |= (1 << VIR_DOMAIN_FEATURE_APIC);
+ if (sexpr_int(root, "domain/image/hvm/pae"))
+ def->features |= (1 << VIR_DOMAIN_FEATURE_PAE);
+
+ /* Old XenD only allows localtime here for HVM */
+ if (sexpr_int(root, "domain/image/hvm/localtime"))
+ def->localtime = 1;
+ }
+
+ /* Current XenD allows localtime here, for PV and HVM */
+ if (sexpr_int(root, "domain/localtime"))
+ def->localtime = 1;
+
+ if (sexpr_node_copy(root, hvm ?
+ "domain/image/hvm/device_model" :
+ "domain/image/linux/device_model",
+ &def->emulator) < 0)
+ goto no_memory;
+
+ /* append block devices */
+ if (xenDaemonParseSxprDisks(conn, def, root, hvm, xendConfigVersion) < 0)
+ goto error;
+
+ if (xenDaemonParseSxprNets(conn, def, root) < 0)
+ goto error;
+
+ if (xenDaemonParseSxprPCI(conn, def, root) < 0)
+ goto error;
+
+ /* New style graphics device config */
+ if (xenDaemonParseSxprGraphicsNew(conn, def, root) < 0)
+ goto error;
+
+ /* Graphics device (HVM <= 3.0.4, or PV <= 3.0.3) vnc config */
+ if ((def->ngraphics == 0) &&
+ xenDaemonParseSxprGraphicsOld(conn, def, root, hvm, xendConfigVersion) < 0)
+ goto error;
+
+
+ /* Old style cdrom config from Xen <= 3.0.2 */
+ if (hvm &&
+ xendConfigVersion == 1) {
+ tmp = sexpr_node(root, "domain/image/hvm/cdrom");
+ if ((tmp != NULL) && (tmp[0] != 0)) {
+ virDomainDiskDefPtr disk;
+ if (VIR_ALLOC(disk) < 0)
+ goto no_memory;
+ if (!(disk->src = strdup(tmp))) {
+ virDomainDiskDefFree(disk);
+ goto no_memory;
+ }
+ disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
+ disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
+ if (!(disk->dst = strdup("hdc"))) {
+ virDomainDiskDefFree(disk);
+ goto no_memory;
+ }
+ if (!(disk->driverName = strdup("file"))) {
+ virDomainDiskDefFree(disk);
+ goto no_memory;
+ }
+ disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
+ disk->readonly = 1;
+
+ if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
+ virDomainDiskDefFree(disk);
+ goto no_memory;
+ }
+ def->disks[def->ndisks++] = disk;
+ }
+ }
+
+
+ /* Floppy disk config */
+ if (hvm) {
+ const char *const fds[] = { "fda", "fdb" };
+ int i;
+ for (i = 0 ; i < ARRAY_CARDINALITY(fds) ; i++) {
+ tmp = sexpr_fmt_node(root, "domain/image/hvm/%s", fds[i]);
+ if ((tmp != NULL) && (tmp[0] != 0)) {
+ virDomainDiskDefPtr disk;
+ if (VIR_ALLOC(disk) < 0)
+ goto no_memory;
+ if (!(disk->src = strdup(tmp))) {
+ VIR_FREE(disk);
+ goto no_memory;
+ }
+ disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
+ disk->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
+ if (!(disk->dst = strdup(fds[i]))) {
+ virDomainDiskDefFree(disk);
+ goto no_memory;
+ }
+ if (!(disk->driverName = strdup("file"))) {
+ virDomainDiskDefFree(disk);
+ goto no_memory;
+ }
+ disk->bus = VIR_DOMAIN_DISK_BUS_FDC;
+
+ if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
+ virDomainDiskDefFree(disk);
+ goto no_memory;
+ }
+ def->disks[def->ndisks++] = disk;
+ }
+ }
+ }
+
+ /* in case of HVM we have USB device emulation */
+ if (hvm &&
+ xenDaemonParseSxprUSB(conn, def, root) < 0)
+ goto error;
+
+ /* Character device config */
+ xenUnifiedLock(priv);
+ tty = xenStoreDomainGetConsolePath(conn, def->id);
+ xenUnifiedUnlock(priv);
+ if (hvm) {
+ tmp = sexpr_node(root, "domain/image/hvm/serial");
+ if (tmp && STRNEQ(tmp, "none")) {
+ virDomainChrDefPtr chr;
+ if ((chr = xenDaemonParseSxprChar(conn, tmp, tty)) == NULL)
+ goto error;
+ if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) {
+ virDomainChrDefFree(chr);
+ goto no_memory;
+ }
+ def->serials[def->nserials++] = chr;
+ }
+ tmp = sexpr_node(root, "domain/image/hvm/parallel");
+ if (tmp && STRNEQ(tmp, "none")) {
+ virDomainChrDefPtr chr;
+ /* XXX does XenD stuff parallel port tty info into xenstore somewhere ? */
+ if ((chr = xenDaemonParseSxprChar(conn, tmp, NULL)) == NULL)
+ goto error;
+ if (VIR_REALLOC_N(def->parallels, def->nparallels+1) < 0) {
+ virDomainChrDefFree(chr);
+ goto no_memory;
+ }
+ def->parallels[def->nparallels++] = chr;
+ }
+ } else {
+ /* Fake a paravirt console, since that's not in the sexpr */
+ if (!(def->console = xenDaemonParseSxprChar(conn, "pty", tty)))
+ goto error;
+ }
+ VIR_FREE(tty);
+
+
+ /* Sound device config */
+ if (hvm &&
+ (tmp = sexpr_node(root, "domain/image/hvm/soundhw")) != NULL &&
+ *tmp) {
+ if (xenDaemonParseSxprSound(conn, def, tmp) < 0)
+ goto error;
+ }
+
+ return def;
+
+no_memory:
+ virReportOOMError(conn);
+error:
+ VIR_FREE(tty);
+ virDomainDefFree(def);
+ return NULL;
+}
+
+virDomainDefPtr
+xenDaemonParseSxprString(virConnectPtr conn,
+ const char *sexpr,
+ int xendConfigVersion)
+{
+ struct sexpr *root = string2sexpr(sexpr);
+ virDomainDefPtr def;
+
+ if (!root)
+ return NULL;
+
+ def = xenDaemonParseSxpr(conn, root, xendConfigVersion, NULL);
+
+ sexpr_free(root);
+
+ return def;
+}
+
+
+/**
+ * sexpr_to_xend_domain_info:
+ * @root: an S-Expression describing a domain
+ * @info: a info data structure to fill=up
+ *
+ * Internal routine filling up the info structure with the values from
+ * the domain root provided.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+static int
+sexpr_to_xend_domain_info(virDomainPtr domain, const struct sexpr *root,
+ virDomainInfoPtr info)
+{
+ const char *flags;
+
+
+ if ((root == NULL) || (info == NULL))
+ return (-1);
+
+ info->memory = sexpr_u64(root, "domain/memory") << 10;
+ info->maxMem = sexpr_u64(root, "domain/maxmem") << 10;
+ flags = sexpr_node(root, "domain/state");
+
+ if (flags) {
+ if (strchr(flags, 'c'))
+ info->state = VIR_DOMAIN_CRASHED;
+ else if (strchr(flags, 's'))
+ info->state = VIR_DOMAIN_SHUTOFF;
+ else if (strchr(flags, 'd'))
+ info->state = VIR_DOMAIN_SHUTDOWN;
+ else if (strchr(flags, 'p'))
+ info->state = VIR_DOMAIN_PAUSED;
+ else if (strchr(flags, 'b'))
+ info->state = VIR_DOMAIN_BLOCKED;
+ else if (strchr(flags, 'r'))
+ info->state = VIR_DOMAIN_RUNNING;
+ } else {
+ /* Inactive domains don't have a state reported, so
+ mark them SHUTOFF, rather than NOSTATE */
+ if (domain->id < 0)
+ info->state = VIR_DOMAIN_SHUTOFF;
+ else
+ info->state = VIR_DOMAIN_NOSTATE;
+ }
+ info->cpuTime = sexpr_float(root, "domain/cpu_time") * 1000000000;
+ info->nrVirtCpu = sexpr_int(root, "domain/vcpus");
+ return (0);
+}
+
+/**
+ * sexpr_to_xend_node_info:
+ * @root: an S-Expression describing a domain
+ * @info: a info data structure to fill up
+ *
+ * Internal routine filling up the info structure with the values from
+ * the node root provided.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+static int
+sexpr_to_xend_node_info(const struct sexpr *root, virNodeInfoPtr info)
+{
+ const char *machine;
+
+
+ if ((root == NULL) || (info == NULL))
+ return (-1);
+
+ machine = sexpr_node(root, "node/machine");
+ if (machine == NULL) {
+ info->model[0] = 0;
+ } else {
+ snprintf(&info->model[0], sizeof(info->model) - 1, "%s", machine);
+ info->model[sizeof(info->model) - 1] = 0;
+ }
+ info->memory = (unsigned long) sexpr_u64(root, "node/total_memory") << 10;
+
+ info->cpus = sexpr_int(root, "node/nr_cpus");
+ info->mhz = sexpr_int(root, "node/cpu_mhz");
+ info->nodes = sexpr_int(root, "node/nr_nodes");
+ info->sockets = sexpr_int(root, "node/sockets_per_node");
+ info->cores = sexpr_int(root, "node/cores_per_socket");
+ info->threads = sexpr_int(root, "node/threads_per_core");
+
+ /* Xen 3.2.0 replaces sockets_per_node with 'nr_cpus'.
+ * Old Xen calculated sockets_per_node using its internal
+ * nr_cpus / (nodes*cores*threads), so fake it ourselves
+ * in the same way
+ */
+ if (info->sockets == 0) {
+ int nr_cpus = sexpr_int(root, "node/nr_cpus");
+ int procs = info->nodes * info->cores * info->threads;
+ if (procs == 0) /* Sanity check in case of Xen bugs in futures..*/
+ return (-1);
+ info->sockets = nr_cpus / procs;
+ /* Should already be fine, but for further sanity make
+ * sure we have at least one socket
+ */
+ if (info->sockets == 0)
+ info->sockets = 1;
+ }
+ return (0);
+}
+
+
+/**
+ * sexpr_to_xend_topology
+ * @root: an S-Expression describing a node
+ * @caps: capability info
+ *
+ * Internal routine populating capability info with
+ * NUMA node mapping details
+ *
+ * Does nothing when the system doesn't support NUMA (not an error).
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+static int
+sexpr_to_xend_topology(virConnectPtr conn,
+ const struct sexpr *root,
+ virCapsPtr caps)
+{
+ const char *nodeToCpu;
+ const char *cur;
+ char *cpuset = NULL;
+ int *cpuNums = NULL;
+ int cell, cpu, nb_cpus;
+ int n = 0;
+ int numCpus;
+
+ nodeToCpu = sexpr_node(root, "node/node_to_cpu");
+ if (nodeToCpu == NULL)
+ return 0; /* no NUMA support */
+
+ numCpus = sexpr_int(root, "node/nr_cpus");
+
+
+ if (VIR_ALLOC_N(cpuset, numCpus) < 0)
+ goto memory_error;
+ if (VIR_ALLOC_N(cpuNums, numCpus) < 0)
+ goto memory_error;
+
+ cur = nodeToCpu;
+ while (*cur != 0) {
+ /*
+ * Find the next NUMA cell described in the xend output
+ */
+ cur = strstr(cur, "node");
+ if (cur == NULL)
+ break;
+ cur += 4;
+ cell = virParseNumber(&cur);
+ if (cell < 0)
+ goto parse_error;
+ virSkipSpaces(&cur);
+ if (*cur != ':')
+ goto parse_error;
+ cur++;
+ virSkipSpaces(&cur);
+ if (STRPREFIX(cur, "no cpus")) {
+ nb_cpus = 0;
+ for (cpu = 0; cpu < numCpus; cpu++)
+ cpuset[cpu] = 0;
+ } else {
+ nb_cpus = virDomainCpuSetParse(conn, &cur, 'n', cpuset, numCpus);
+ if (nb_cpus < 0)
+ goto error;
+ }
+
+ for (n = 0, cpu = 0; cpu < numCpus; cpu++)
+ if (cpuset[cpu] == 1)
+ cpuNums[n++] = cpu;
+
+ if (virCapabilitiesAddHostNUMACell(caps,
+ cell,
+ nb_cpus,
+ cpuNums) < 0)
+ goto memory_error;
+ }
+ VIR_FREE(cpuNums);
+ VIR_FREE(cpuset);
+ return (0);
+
+ parse_error:
+ virXendError(conn, VIR_ERR_XEN_CALL, "%s", _("topology syntax error"));
+ error:
+ VIR_FREE(cpuNums);
+ VIR_FREE(cpuset);
+
+ return (-1);
+
+ memory_error:
+ VIR_FREE(cpuNums);
+ VIR_FREE(cpuset);
+ virReportOOMError(conn);
+ return (-1);
+}
+
+
+#ifndef PROXY
+/**
+ * sexpr_to_domain:
+ * @conn: an existing virtual connection block
+ * @root: an S-Expression describing a domain
+ *
+ * Internal routine returning the associated virDomainPtr for this domain
+ *
+ * Returns the domain pointer or NULL in case of error.
+ */
+static virDomainPtr
+sexpr_to_domain(virConnectPtr conn, const struct sexpr *root)
+{
+ virDomainPtr ret = NULL;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ const char *name;
+ const char *tmp;
+ xenUnifiedPrivatePtr priv;
+
+ if ((conn == NULL) || (root == NULL))
+ return(NULL);
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ if (sexpr_uuid(uuid, root, "domain/uuid") < 0)
+ goto error;
+ name = sexpr_node(root, "domain/name");
+ if (name == NULL)
+ goto error;
+
+ ret = virGetDomain(conn, name, uuid);
+ if (ret == NULL) return NULL;
+
+ tmp = sexpr_node(root, "domain/domid");
+ /* New 3.0.4 XenD will not report a domid for inactive domains,
+ * so only error out for old XenD
+ */
+ if (!tmp && priv->xendConfigVersion < 3)
+ goto error;
+
+ if (tmp)
+ ret->id = sexpr_int(root, "domain/domid");
+ else
+ ret->id = -1; /* An inactive domain */
+
+ return (ret);
+
+error:
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to parse Xend domain information"));
+ if (ret != NULL)
+ virUnrefDomain(ret);
+ return(NULL);
+}
+#endif /* !PROXY */
+
+/*****************************************************************
+ ******
+ ******
+ ******
+ ******
+ Refactored
+ ******
+ ******
+ ******
+ ******
+ *****************************************************************/
+#ifndef PROXY
+/**
+ * xenDaemonOpen:
+ * @conn: an existing virtual connection block
+ * @name: optional argument to select a connection type
+ * @flags: combination of virDrvOpenFlag(s)
+ *
+ * Creates a localhost Xen Daemon connection
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+virDrvOpenStatus
+xenDaemonOpen(virConnectPtr conn,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED)
+{
+ char *port = NULL;
+ int ret = VIR_DRV_OPEN_ERROR;
+
+ /* Switch on the scheme, which we expect to be NULL (file),
+ * "http" or "xen".
+ */
+ if (conn->uri->scheme == NULL) {
+ /* It should be a file access */
+ if (conn->uri->path == NULL) {
+ virXendError(NULL, VIR_ERR_NO_CONNECT, __FUNCTION__);
+ goto failed;
+ }
+ if (xenDaemonOpen_unix(conn, conn->uri->path) < 0 ||
+ xend_detect_config_version(conn) == -1)
+ goto failed;
+ }
+ else if (STRCASEEQ (conn->uri->scheme, "xen")) {
+ /*
+ * try first to open the unix socket
+ */
+ if (xenDaemonOpen_unix(conn, "/var/lib/xend/xend-socket") == 0 &&
+ xend_detect_config_version(conn) != -1)
+ goto done;
+
+ /*
+ * try though http on port 8000
+ */
+ if (xenDaemonOpen_tcp(conn, "localhost", "8000") < 0 ||
+ xend_detect_config_version(conn) == -1)
+ goto failed;
+ } else if (STRCASEEQ (conn->uri->scheme, "http")) {
+ if (conn->uri->port &&
+ virAsprintf(&port, "%d", conn->uri->port) == -1)
+ goto failed;
+
+ if (xenDaemonOpen_tcp(conn,
+ conn->uri->server ? conn->uri->server : "localhost",
+ port ? port : "8000") < 0 ||
+ xend_detect_config_version(conn) == -1)
+ goto failed;
+ } else {
+ virXendError(NULL, VIR_ERR_NO_CONNECT, __FUNCTION__);
+ goto failed;
+ }
+
+ done:
+ ret = VIR_DRV_OPEN_SUCCESS;
+
+failed:
+ VIR_FREE(port);
+ return ret;
+}
+
+
+/**
+ * xenDaemonClose:
+ * @conn: an existing virtual connection block
+ *
+ * This method should be called when a connection to xend instance
+ * initialized with xenDaemonOpen is no longer needed
+ * to free the associated resources.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+xenDaemonClose(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+/**
+ * xenDaemonDomainSuspend:
+ * @domain: pointer to the Domain block
+ *
+ * Pause the domain, the domain is not scheduled anymore though its resources
+ * are preserved. Use xenDaemonDomainResume() to resume execution.
+ *
+ * Returns 0 in case of success, -1 (with errno) in case of error.
+ */
+int
+xenDaemonDomainSuspend(virDomainPtr domain)
+{
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ if (domain->id < 0) {
+ virXendError(domain->conn, VIR_ERR_OPERATION_INVALID,
+ _("Domain %s isn't running."), domain->name);
+ return(-1);
+ }
+
+ return xend_op(domain->conn, domain->name, "op", "pause", NULL);
+}
+
+/**
+ * xenDaemonDomainResume:
+ * @xend: pointer to the Xem Daemon block
+ * @name: name for the domain
+ *
+ * Resume the domain after xenDaemonDomainSuspend() has been called
+ *
+ * Returns 0 in case of success, -1 (with errno) in case of error.
+ */
+int
+xenDaemonDomainResume(virDomainPtr domain)
+{
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ if (domain->id < 0) {
+ virXendError(domain->conn, VIR_ERR_OPERATION_INVALID,
+ _("Domain %s isn't running."), domain->name);
+ return(-1);
+ }
+
+ return xend_op(domain->conn, domain->name, "op", "unpause", NULL);
+}
+
+/**
+ * xenDaemonDomainShutdown:
+ * @domain: pointer to the Domain block
+ *
+ * Shutdown the domain, the OS is requested to properly shutdown
+ * and the domain may ignore it. It will return immediately
+ * after queuing the request.
+ *
+ * Returns 0 in case of success, -1 (with errno) in case of error.
+ */
+int
+xenDaemonDomainShutdown(virDomainPtr domain)
+{
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ if (domain->id < 0) {
+ virXendError(domain->conn, VIR_ERR_OPERATION_INVALID,
+ _("Domain %s isn't running."), domain->name);
+ return(-1);
+ }
+
+ return xend_op(domain->conn, domain->name, "op", "shutdown", "reason", "poweroff", NULL);
+}
+
+/**
+ * xenDaemonDomainReboot:
+ * @domain: pointer to the Domain block
+ * @flags: extra flags for the reboot operation, not used yet
+ *
+ * Reboot the domain, the OS is requested to properly shutdown
+ * and restart but the domain may ignore it. It will return immediately
+ * after queuing the request.
+ *
+ * Returns 0 in case of success, -1 (with errno) in case of error.
+ */
+int
+xenDaemonDomainReboot(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED)
+{
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ if (domain->id < 0) {
+ virXendError(domain->conn, VIR_ERR_OPERATION_INVALID,
+ _("Domain %s isn't running."), domain->name);
+ return(-1);
+ }
+
+ return xend_op(domain->conn, domain->name, "op", "shutdown", "reason", "reboot", NULL);
+}
+
+/**
+ * xenDaemonDomainDestroy:
+ * @domain: pointer to the Domain block
+ *
+ * Abruptly halt the domain, the OS is not properly shutdown and the
+ * resources allocated for the domain are immediately freed, mounted
+ * filesystems will be marked as uncleanly shutdown.
+ * After calling this function, the domain's status will change to
+ * dying and will go away completely once all of the resources have been
+ * unmapped (usually from the backend devices).
+ *
+ * Returns 0 in case of success, -1 (with errno) in case of error.
+ */
+int
+xenDaemonDomainDestroy(virDomainPtr domain)
+{
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ if (domain->id < 0) {
+ virXendError(domain->conn, VIR_ERR_OPERATION_INVALID,
+ _("Domain %s isn't running."), domain->name);
+ return(-1);
+ }
+
+ return xend_op(domain->conn, domain->name, "op", "destroy", NULL);
+}
+
+/**
+ * xenDaemonDomainGetOSType:
+ * @domain: a domain object
+ *
+ * Get the type of domain operation system.
+ *
+ * Returns the new string or NULL in case of error, the string must be
+ * freed by the caller.
+ */
+static char *
+xenDaemonDomainGetOSType(virDomainPtr domain)
+{
+ char *type;
+ struct sexpr *root;
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(NULL);
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+ if (domain->id < 0 && priv->xendConfigVersion < 3)
+ return(NULL);
+
+ /* can we ask for a subset ? worth it ? */
+ root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
+ if (root == NULL)
+ return(NULL);
+
+ if (sexpr_lookup(root, "domain/image/hvm")) {
+ type = strdup("hvm");
+ } else {
+ type = strdup("linux");
+ }
+
+ sexpr_free(root);
+
+ return(type);
+}
+
+/**
+ * xenDaemonDomainSave:
+ * @domain: pointer to the Domain block
+ * @filename: path for the output file
+ *
+ * This method will suspend a domain and save its memory contents to
+ * a file on disk. Use xenDaemonDomainRestore() to restore a domain after
+ * saving.
+ * Note that for remote Xen Daemon the file path will be interpreted in
+ * the remote host.
+ *
+ * Returns 0 in case of success, -1 (with errno) in case of error.
+ */
+int
+xenDaemonDomainSave(virDomainPtr domain, const char *filename)
+{
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
+ (filename == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ if (domain->id < 0) {
+ virXendError(domain->conn, VIR_ERR_OPERATION_INVALID,
+ _("Domain %s isn't running."), domain->name);
+ return(-1);
+ }
+
+ /* We can't save the state of Domain-0, that would mean stopping it too */
+ if (domain->id == 0) {
+ return(-1);
+ }
+
+ return xend_op(domain->conn, domain->name, "op", "save", "file", filename, NULL);
+}
+
+/**
+ * xenDaemonDomainCoreDump:
+ * @domain: pointer to the Domain block
+ * @filename: path for the output file
+ * @flags: extra flags, currently unused
+ *
+ * This method will dump the core of a domain on a given file for analysis.
+ * Note that for remote Xen Daemon the file path will be interpreted in
+ * the remote host.
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+static int
+xenDaemonDomainCoreDump(virDomainPtr domain, const char *filename,
+ int flags ATTRIBUTE_UNUSED)
+{
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
+ (filename == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ if (domain->id < 0) {
+ virXendError(domain->conn, VIR_ERR_OPERATION_INVALID,
+ _("Domain %s isn't running."), domain->name);
+ return(-1);
+ }
+
+ return xend_op(domain->conn, domain->name, "op", "dump", "file", filename,
+ "live", "0", "crash", "0", NULL);
+}
+
+/**
+ * xenDaemonDomainRestore:
+ * @conn: pointer to the Xem Daemon block
+ * @filename: path for the output file
+ *
+ * This method will restore a domain saved to disk by xenDaemonDomainSave().
+ * Note that for remote Xen Daemon the file path will be interpreted in
+ * the remote host.
+ *
+ * Returns 0 in case of success, -1 (with errno) in case of error.
+ */
+int
+xenDaemonDomainRestore(virConnectPtr conn, const char *filename)
+{
+ if ((conn == NULL) || (filename == NULL)) {
+ /* this should be caught at the interface but ... */
+ virXendError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (-1);
+ }
+ return xend_op(conn, "", "op", "restore", "file", filename, NULL);
+}
+#endif /* !PROXY */
+
+/**
+ * xenDaemonDomainGetMaxMemory:
+ * @domain: pointer to the domain block
+ *
+ * Ask the Xen Daemon for the maximum memory allowed for a domain
+ *
+ * Returns the memory size in kilobytes or 0 in case of error.
+ */
+unsigned long
+xenDaemonDomainGetMaxMemory(virDomainPtr domain)
+{
+ unsigned long ret = 0;
+ struct sexpr *root;
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+ if (domain->id < 0 && priv->xendConfigVersion < 3)
+ return(-1);
+
+ /* can we ask for a subset ? worth it ? */
+ root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
+ if (root == NULL)
+ return(0);
+
+ ret = (unsigned long) sexpr_u64(root, "domain/memory") << 10;
+ sexpr_free(root);
+
+ return(ret);
+}
+
+#ifndef PROXY
+/**
+ * xenDaemonDomainSetMaxMemory:
+ * @domain: pointer to the Domain block
+ * @memory: The maximum memory in kilobytes
+ *
+ * This method will set the maximum amount of memory that can be allocated to
+ * a domain. Please note that a domain is able to allocate up to this amount
+ * on its own.
+ *
+ * Returns 0 for success; -1 (with errno) on error
+ */
+int
+xenDaemonDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
+{
+ char buf[1024];
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+ if (domain->id < 0 && priv->xendConfigVersion < 3)
+ return(-1);
+
+ snprintf(buf, sizeof(buf), "%lu", memory >> 10);
+ return xend_op(domain->conn, domain->name, "op", "maxmem_set", "memory",
+ buf, NULL);
+}
+
+/**
+ * xenDaemonDomainSetMemory:
+ * @domain: pointer to the Domain block
+ * @memory: The target memory in kilobytes
+ *
+ * This method will set a target memory allocation for a given domain and
+ * request that the guest meet this target. The guest may or may not actually
+ * achieve this target. When this function returns, it does not signify that
+ * the domain has actually reached that target.
+ *
+ * Memory for a domain can only be allocated up to the maximum memory setting.
+ * There is no safe guard for allocations that are too small so be careful
+ * when using this function to reduce a domain's memory usage.
+ *
+ * Returns 0 for success; -1 (with errno) on error
+ */
+int
+xenDaemonDomainSetMemory(virDomainPtr domain, unsigned long memory)
+{
+ char buf[1024];
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+ if (domain->id < 0 && priv->xendConfigVersion < 3)
+ return(-1);
+
+ snprintf(buf, sizeof(buf), "%lu", memory >> 10);
+ return xend_op(domain->conn, domain->name, "op", "mem_target_set",
+ "target", buf, NULL);
+}
+
+#endif /* ! PROXY */
+
+virDomainDefPtr
+xenDaemonDomainFetch(virConnectPtr conn,
+ int domid,
+ const char *name,
+ const char *cpus)
+{
+ struct sexpr *root;
+ xenUnifiedPrivatePtr priv;
+ virDomainDefPtr def;
+
+ if (name)
+ root = sexpr_get(conn, "/xend/domain/%s?detail=1", name);
+ else
+ root = sexpr_get(conn, "/xend/domain/%d?detail=1", domid);
+ if (root == NULL) {
+ virXendError (conn, VIR_ERR_XEN_CALL,
+ "%s", _("xenDaemonDomainFetch failed to"
+ " find this domain"));
+ return (NULL);
+ }
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ if (!(def = xenDaemonParseSxpr(conn,
+ root,
+ priv->xendConfigVersion,
+ cpus)))
+ goto cleanup;
+
+cleanup:
+ sexpr_free(root);
+
+ return (def);
+}
+
+
+#ifndef PROXY
+/**
+ * xenDaemonDomainDumpXML:
+ * @domain: a domain object
+ * @flags: potential dump flags
+ * @cpus: list of cpu the domain is pinned to.
+ *
+ * Provide an XML description of the domain.
+ *
+ * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
+ * the caller must free() the returned value.
+ */
+char *
+xenDaemonDomainDumpXML(virDomainPtr domain, int flags, const char *cpus)
+{
+ xenUnifiedPrivatePtr priv;
+ virDomainDefPtr def;
+ char *xml;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(NULL);
+ }
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+ if (domain->id < 0 && priv->xendConfigVersion < 3) {
+ // fall-through to the next driver to handle
+ return(NULL);
+ }
+
+ if (!(def = xenDaemonDomainFetch(domain->conn,
+ domain->id,
+ domain->name,
+ cpus)))
+ return(NULL);
+
+ xml = virDomainDefFormat(domain->conn, def, flags);
+
+ virDomainDefFree(def);
+
+ return xml;
+}
+#endif /* !PROXY */
+
+/**
+ * xenDaemonDomainGetInfo:
+ * @domain: a domain object
+ * @info: pointer to a virDomainInfo structure allocated by the user
+ *
+ * This method looks up information about a domain and update the
+ * information block provided.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+xenDaemonDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
+{
+ struct sexpr *root;
+ int ret;
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
+ (info == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+ if (domain->id < 0 && priv->xendConfigVersion < 3)
+ return(-1);
+
+ root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
+ if (root == NULL)
+ return (-1);
+
+ ret = sexpr_to_xend_domain_info(domain, root, info);
+ sexpr_free(root);
+ return (ret);
+}
+
+#ifndef PROXY
+/**
+ * xenDaemonLookupByName:
+ * @conn: A xend instance
+ * @name: The name of the domain
+ *
+ * This method looks up information about a domain and returns
+ * it in the form of a struct xend_domain. This should be
+ * free()'d when no longer needed.
+ *
+ * Returns domain info on success; NULL (with errno) on error
+ */
+virDomainPtr
+xenDaemonLookupByName(virConnectPtr conn, const char *domname)
+{
+ struct sexpr *root;
+ virDomainPtr ret = NULL;
+
+ if ((conn == NULL) || (domname == NULL)) {
+ virXendError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(NULL);
+ }
+
+ root = sexpr_get(conn, "/xend/domain/%s?detail=1", domname);
+ if (root == NULL)
+ goto error;
+
+ ret = sexpr_to_domain(conn, root);
+
+error:
+ sexpr_free(root);
+ return(ret);
+}
+#endif /* ! PROXY */
+
+/**
+ * xenDaemonNodeGetInfo:
+ * @conn: pointer to the Xen Daemon block
+ * @info: pointer to a virNodeInfo structure allocated by the user
+ *
+ * Extract hardware information about the node.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+xenDaemonNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) {
+ int ret = -1;
+ struct sexpr *root;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virXendError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+ if (info == NULL) {
+ virXendError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (-1);
+ }
+
+ root = sexpr_get(conn, "/xend/node/");
+ if (root == NULL)
+ return (-1);
+
+ ret = sexpr_to_xend_node_info(root, info);
+ sexpr_free(root);
+ return (ret);
+}
+
+/**
+ * xenDaemonNodeGetTopology:
+ * @conn: pointer to the Xen Daemon block
+ * @caps: capabilities info
+ *
+ * This method retrieves a node's topology information.
+ *
+ * Returns -1 in case of error, 0 otherwise.
+ */
+int
+xenDaemonNodeGetTopology(virConnectPtr conn,
+ virCapsPtr caps) {
+ int ret = -1;
+ struct sexpr *root;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virXendError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+
+ if (caps == NULL) {
+ virXendError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (-1);
+ }
+
+ root = sexpr_get(conn, "/xend/node/");
+ if (root == NULL) {
+ return (-1);
+ }
+
+ ret = sexpr_to_xend_topology(conn, root, caps);
+ sexpr_free(root);
+ return (ret);
+}
+
+/**
+ * xenDaemonGetVersion:
+ * @conn: pointer to the Xen Daemon block
+ * @hvVer: return value for the version of the running hypervisor (OUT)
+ *
+ * Get the version level of the Hypervisor running.
+ *
+ * Returns -1 in case of error, 0 otherwise. if the version can't be
+ * extracted by lack of capacities returns 0 and @hvVer is 0, otherwise
+ * @hvVer value is major * 1,000,000 + minor * 1,000 + release
+ */
+int
+xenDaemonGetVersion(virConnectPtr conn, unsigned long *hvVer)
+{
+ struct sexpr *root;
+ int major, minor;
+ unsigned long version;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virXendError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+ if (hvVer == NULL) {
+ virXendError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (-1);
+ }
+ root = sexpr_get(conn, "/xend/node/");
+ if (root == NULL)
+ return(-1);
+
+ major = sexpr_int(root, "node/xen_major");
+ minor = sexpr_int(root, "node/xen_minor");
+ sexpr_free(root);
+ version = major * 1000000 + minor * 1000;
+ *hvVer = version;
+ return(0);
+}
+
+#ifndef PROXY
+/**
+ * xenDaemonListDomains:
+ * @conn: pointer to the hypervisor connection
+ * @ids: array to collect the list of IDs of active domains
+ * @maxids: size of @ids
+ *
+ * Collect the list of active domains, and store their ID in @maxids
+ * TODO: this is quite expensive at the moment since there isn't one
+ * xend RPC providing both name and id for all domains.
+ *
+ * Returns the number of domain found or -1 in case of error
+ */
+int
+xenDaemonListDomains(virConnectPtr conn, int *ids, int maxids)
+{
+ struct sexpr *root = NULL;
+ int ret = -1;
+ struct sexpr *_for_i, *node;
+ long id;
+
+ if (maxids == 0)
+ return(0);
+
+ if ((ids == NULL) || (maxids < 0))
+ goto error;
+ root = sexpr_get(conn, "/xend/domain");
+ if (root == NULL)
+ goto error;
+
+ ret = 0;
+
+ for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
+ _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
+ if (node->kind != SEXPR_VALUE)
+ continue;
+ id = xenDaemonDomainLookupByName_ids(conn, node->u.value, NULL);
+ if (id >= 0)
+ ids[ret++] = (int) id;
+ if (ret >= maxids)
+ break;
+ }
+
+error:
+ sexpr_free(root);
+ return(ret);
+}
+
+/**
+ * xenDaemonNumOfDomains:
+ * @conn: pointer to the hypervisor connection
+ *
+ * Provides the number of active domains.
+ *
+ * Returns the number of domain found or -1 in case of error
+ */
+static int
+xenDaemonNumOfDomains(virConnectPtr conn)
+{
+ struct sexpr *root = NULL;
+ int ret = -1;
+ struct sexpr *_for_i, *node;
+
+ root = sexpr_get(conn, "/xend/domain");
+ if (root == NULL)
+ goto error;
+
+ ret = 0;
+
+ for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
+ _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
+ if (node->kind != SEXPR_VALUE)
+ continue;
+ ret++;
+ }
+
+error:
+ sexpr_free(root);
+ return(ret);
+}
+#endif /* ! PROXY */
+
+#ifndef PROXY
+/**
+ * xenDaemonLookupByID:
+ * @conn: pointer to the hypervisor connection
+ * @id: the domain ID number
+ *
+ * Try to find a domain based on the hypervisor ID number
+ *
+ * Returns a new domain object or NULL in case of failure
+ */
+virDomainPtr
+xenDaemonLookupByID(virConnectPtr conn, int id) {
+ char *name = NULL;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ virDomainPtr ret;
+
+ if (xenDaemonDomainLookupByID(conn, id, &name, uuid) < 0) {
+ goto error;
+ }
+
+ ret = virGetDomain(conn, name, uuid);
+ if (ret == NULL) goto error;
+
+ ret->id = id;
+ VIR_FREE(name);
+ return (ret);
+
+ error:
+ VIR_FREE(name);
+ return (NULL);
+}
+
+/**
+ * xenDaemonDomainSetVcpus:
+ * @domain: pointer to domain object
+ * @nvcpus: the new number of virtual CPUs for this domain
+ *
+ * Dynamically change the number of virtual CPUs used by the domain.
+ *
+ * Returns 0 for success; -1 (with errno) on error
+ */
+int
+xenDaemonDomainSetVcpus(virDomainPtr domain, unsigned int vcpus)
+{
+ char buf[VIR_UUID_BUFLEN];
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
+ || (vcpus < 1)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return (-1);
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+ if (domain->id < 0 && priv->xendConfigVersion < 3)
+ return(-1);
+
+ snprintf(buf, sizeof(buf), "%d", vcpus);
+ return(xend_op(domain->conn, domain->name, "op", "set_vcpus", "vcpus",
+ buf, NULL));
+}
+
+/**
+ * xenDaemonDomainPinCpu:
+ * @domain: pointer to domain object
+ * @vcpu: virtual CPU number
+ * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes)
+ * @maplen: length of cpumap in bytes
+ *
+ * Dynamically change the real CPUs which can be allocated to a virtual CPU.
+ * NOTE: The XenD cpu affinity map format changed from "[0,1,2]" to
+ * "0,1,2"
+ * the XenD cpu affinity works only after cset 19579.
+ * there is no fine grained xend version detection possible, so we
+ * use the old format for anything before version 3
+ *
+ * Returns 0 for success; -1 (with errno) on error
+ */
+int
+xenDaemonDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
+ unsigned char *cpumap, int maplen)
+{
+ char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64];
+ int i, j;
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
+ || (cpumap == NULL) || (maplen < 1) || (maplen > (int)sizeof(cpumap_t))) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return (-1);
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->xendConfigVersion < 3) {
+ mapstr[0] = '[';
+ mapstr[1] = 0;
+ } else {
+ mapstr[0] = 0;
+ }
+
+ /* from bit map, build character string of mapped CPU numbers */
+ for (i = 0; i < maplen; i++) for (j = 0; j < 8; j++)
+ if (cpumap[i] & (1 << j)) {
+ snprintf(buf, sizeof(buf), "%d,", (8 * i) + j);
+ strcat(mapstr, buf);
+ }
+ if (priv->xendConfigVersion < 3)
+ mapstr[strlen(mapstr) - 1] = ']';
+ else
+ mapstr[strlen(mapstr) - 1] = 0;
+
+ snprintf(buf, sizeof(buf), "%d", vcpu);
+ return(xend_op(domain->conn, domain->name, "op", "pincpu", "vcpu", buf,
+ "cpumap", mapstr, NULL));
+}
+
+/**
+ * virDomainGetVcpus:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @info: pointer to an array of virVcpuInfo structures (OUT)
+ * @maxinfo: number of structures in info array
+ * @cpumaps: pointer to an bit map of real CPUs for all vcpus of this domain (in 8-bit bytes) (OUT)
+ * If cpumaps is NULL, then no cpumap information is returned by the API.
+ * It's assumed there is <maxinfo> cpumap in cpumaps array.
+ * The memory allocated to cpumaps must be (maxinfo * maplen) bytes
+ * (ie: calloc(maxinfo, maplen)).
+ * One cpumap inside cpumaps has the format described in virDomainPinVcpu() API.
+ * @maplen: number of bytes in one cpumap, from 1 up to size of CPU map in
+ * underlying virtualization system (Xen...).
+ *
+ * Extract information about virtual CPUs of domain, store it in info array
+ * and also in cpumaps if this pointer isn't NULL.
+ *
+ * Returns the number of info filled in case of success, -1 in case of failure.
+ */
+int
+xenDaemonDomainGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo,
+ unsigned char *cpumaps, int maplen)
+{
+ struct sexpr *root, *s, *t;
+ virVcpuInfoPtr ipt = info;
+ int nbinfo = 0, oln;
+ unsigned char *cpumap;
+ int vcpu, cpu;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
+ || (info == NULL) || (maxinfo < 1)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return (-1);
+ }
+ if (cpumaps != NULL && maplen < 1) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return (-1);
+ }
+
+ root = sexpr_get(domain->conn, "/xend/domain/%s?op=vcpuinfo", domain->name);
+ if (root == NULL)
+ return (-1);
+
+ if (cpumaps != NULL)
+ memset(cpumaps, 0, maxinfo * maplen);
+
+ /* scan the sexprs from "(vcpu (number x)...)" and get parameter values */
+ for (s = root; s->kind == SEXPR_CONS; s = s->u.s.cdr) {
+ if ((s->u.s.car->kind == SEXPR_CONS) &&
+ (s->u.s.car->u.s.car->kind == SEXPR_VALUE) &&
+ STREQ(s->u.s.car->u.s.car->u.value, "vcpu")) {
+ t = s->u.s.car;
+ vcpu = ipt->number = sexpr_int(t, "vcpu/number");
+ if ((oln = sexpr_int(t, "vcpu/online")) != 0) {
+ if (sexpr_int(t, "vcpu/running")) ipt->state = VIR_VCPU_RUNNING;
+ if (sexpr_int(t, "vcpu/blocked")) ipt->state = VIR_VCPU_BLOCKED;
+ }
+ else
+ ipt->state = VIR_VCPU_OFFLINE;
+ ipt->cpuTime = sexpr_float(t, "vcpu/cpu_time") * 1000000000;
+ ipt->cpu = oln ? sexpr_int(t, "vcpu/cpu") : -1;
+
+ if (cpumaps != NULL && vcpu >= 0 && vcpu < maxinfo) {
+ cpumap = (unsigned char *) VIR_GET_CPUMAP(cpumaps, maplen, vcpu);
+ /*
+ * get sexpr from "(cpumap (x y z...))" and convert values
+ * to bitmap
+ */
+ for (t = t->u.s.cdr; t->kind == SEXPR_CONS; t = t->u.s.cdr)
+ if ((t->u.s.car->kind == SEXPR_CONS) &&
+ (t->u.s.car->u.s.car->kind == SEXPR_VALUE) &&
+ STREQ(t->u.s.car->u.s.car->u.value, "cpumap") &&
+ (t->u.s.car->u.s.cdr->kind == SEXPR_CONS)) {
+ for (t = t->u.s.car->u.s.cdr->u.s.car; t->kind == SEXPR_CONS; t = t->u.s.cdr)
+ if (t->u.s.car->kind == SEXPR_VALUE
+ && virStrToLong_i(t->u.s.car->u.value, NULL, 10, &cpu) == 0
+ && cpu >= 0
+ && (VIR_CPU_MAPLEN(cpu+1) <= maplen)) {
+ VIR_USE_CPU(cpumap, cpu);
+ }
+ break;
+ }
+ }
+
+ if (++nbinfo == maxinfo) break;
+ ipt++;
+ }
+ }
+ sexpr_free(root);
+ return(nbinfo);
+}
+
+/**
+ * xenDaemonLookupByUUID:
+ * @conn: pointer to the hypervisor connection
+ * @uuid: the raw UUID for the domain
+ *
+ * Try to lookup a domain on xend based on its UUID.
+ *
+ * Returns a new domain object or NULL in case of failure
+ */
+virDomainPtr
+xenDaemonLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+ virDomainPtr ret;
+ char *name = NULL;
+ int id = -1;
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ /* Old approach for xen <= 3.0.3 */
+ if (priv->xendConfigVersion < 3) {
+ char **names, **tmp;
+ unsigned char ident[VIR_UUID_BUFLEN];
+ names = xenDaemonListDomainsOld(conn);
+ tmp = names;
+
+ if (names == NULL) {
+ return (NULL);
+ }
+ while (*tmp != NULL) {
+ id = xenDaemonDomainLookupByName_ids(conn, *tmp, &ident[0]);
+ if (id >= 0) {
+ if (!memcmp(uuid, ident, VIR_UUID_BUFLEN)) {
+ name = strdup(*tmp);
+ break;
+ }
+ }
+ tmp++;
+ }
+ VIR_FREE(names);
+ } else { /* New approach for xen >= 3.0.4 */
+ char *domname = NULL;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ struct sexpr *root = NULL;
+
+ virUUIDFormat(uuid, uuidstr);
+ root = sexpr_get(conn, "/xend/domain/%s?detail=1", uuidstr);
+ if (root == NULL)
+ return (NULL);
+ domname = (char*)sexpr_node(root, "domain/name");
+ if (sexpr_node(root, "domain/domid")) /* only active domains have domid */
+ id = sexpr_int(root, "domain/domid");
+ else
+ id = -1;
+ name = domname ? strdup(domname) : NULL;
+ sexpr_free(root);
+ }
+
+ if (name == NULL)
+ return (NULL);
+
+ ret = virGetDomain(conn, name, uuid);
+ if (ret == NULL) goto cleanup;
+
+ ret->id = id;
+
+ cleanup:
+ VIR_FREE(name);
+ return (ret);
+}
+
+/**
+ * xenDaemonCreateXML:
+ * @conn: pointer to the hypervisor connection
+ * @xmlDesc: an XML description of the domain
+ * @flags: an optional set of virDomainFlags
+ *
+ * Launch a new Linux guest domain, based on an XML description similar
+ * to the one returned by virDomainGetXMLDesc()
+ * This function may requires privileged access to the hypervisor.
+ *
+ * Returns a new domain object or NULL in case of failure
+ */
+static virDomainPtr
+xenDaemonCreateXML(virConnectPtr conn, const char *xmlDesc,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ int ret;
+ char *sexpr;
+ virDomainPtr dom = NULL;
+ xenUnifiedPrivatePtr priv;
+ virDomainDefPtr def;
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ if (!(def = virDomainDefParseString(conn,
+ priv->caps,
+ xmlDesc,
+ VIR_DOMAIN_XML_INACTIVE)))
+ return (NULL);
+
+ if (!(sexpr = xenDaemonFormatSxpr(conn, def, priv->xendConfigVersion))) {
+ virDomainDefFree(def);
+ return (NULL);
+ }
+
+ ret = xenDaemonDomainCreateXML(conn, sexpr);
+ VIR_FREE(sexpr);
+ if (ret != 0) {
+ goto error;
+ }
+
+ /* This comes before wait_for_devices, to ensure that latter
+ cleanup will destroy the domain upon failure */
+ if (!(dom = virDomainLookupByName(conn, def->name)))
+ goto error;
+
+ if (xend_wait_for_devices(conn, def->name) < 0)
+ goto error;
+
+ if (xenDaemonDomainResume(dom) < 0)
+ goto error;
+
+ virDomainDefFree(def);
+ return (dom);
+
+ error:
+ /* Make sure we don't leave a still-born domain around */
+ if (dom != NULL) {
+ xenDaemonDomainDestroy(dom);
+ virUnrefDomain(dom);
+ }
+ virDomainDefFree(def);
+ return (NULL);
+}
+
+/**
+ * xenDaemonAttachDevice:
+ * @domain: pointer to domain object
+ * @xml: pointer to XML description of device
+ *
+ * Create a virtual device attachment to backend.
+ * XML description is translated into S-expression.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+static int
+xenDaemonAttachDevice(virDomainPtr domain, const char *xml)
+{
+ xenUnifiedPrivatePtr priv;
+ char *sexpr = NULL;
+ int ret = -1;
+ virDomainDeviceDefPtr dev = NULL;
+ virDomainDefPtr def = NULL;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ char class[8], ref[80];
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return -1;
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+ /*
+ * on older Xen without the inactive guests management
+ * avoid doing this on inactive guests
+ */
+ if ((domain->id < 0) && (priv->xendConfigVersion < 3))
+ return -1;
+
+ if (!(def = xenDaemonDomainFetch(domain->conn,
+ domain->id,
+ domain->name,
+ NULL)))
+ goto cleanup;
+
+ if (!(dev = virDomainDeviceDefParse(domain->conn,
+ priv->caps,
+ def, xml, VIR_DOMAIN_XML_INACTIVE)))
+ goto cleanup;
+
+
+ switch (dev->type) {
+ case VIR_DOMAIN_DEVICE_DISK:
+ if (xenDaemonFormatSxprDisk(domain->conn,
+ dev->data.disk,
+ &buf,
+ STREQ(def->os.type, "hvm") ? 1 : 0,
+ priv->xendConfigVersion, 1) < 0)
+ goto cleanup;
+ break;
+
+ case VIR_DOMAIN_DEVICE_NET:
+ if (xenDaemonFormatSxprNet(domain->conn,
+ dev->data.net,
+ &buf,
+ STREQ(def->os.type, "hvm") ? 1 : 0,
+ priv->xendConfigVersion, 1) < 0)
+ goto cleanup;
+ break;
+
+ case VIR_DOMAIN_DEVICE_HOSTDEV:
+ if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+ dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
+ if (xenDaemonFormatSxprOnePCI(domain->conn,
+ dev->data.hostdev,
+ &buf) < 0)
+ goto cleanup;
+ } else {
+ virXendError(domain->conn, VIR_ERR_NO_SUPPORT, "%s",
+ _("unsupported device type"));
+ goto cleanup;
+ }
+ break;
+
+ default:
+ virXendError(domain->conn, VIR_ERR_NO_SUPPORT, "%s",
+ _("unsupported device type"));
+ goto cleanup;
+ }
+
+ sexpr = virBufferContentAndReset(&buf);
+
+ if (virDomainXMLDevID(domain, dev, class, ref, sizeof(ref))) {
+ /* device doesn't exist, define it */
+ ret = xend_op(domain->conn, domain->name, "op", "device_create",
+ "config", sexpr, NULL);
+ }
+ else {
+ /* device exists, attempt to modify it */
+ ret = xend_op(domain->conn, domain->name, "op", "device_configure",
+ "config", sexpr, "dev", ref, NULL);
+ }
+
+cleanup:
+ VIR_FREE(sexpr);
+ virDomainDefFree(def);
+ virDomainDeviceDefFree(dev);
+ return ret;
+}
+
+/**
+ * xenDaemonDetachDevice:
+ * @domain: pointer to domain object
+ * @xml: pointer to XML description of device
+ *
+ * Destroy a virtual device attachment to backend.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+static int
+xenDaemonDetachDevice(virDomainPtr domain, const char *xml)
+{
+ xenUnifiedPrivatePtr priv;
+ char class[8], ref[80];
+ virDomainDeviceDefPtr dev = NULL;
+ virDomainDefPtr def = NULL;
+ int ret = -1;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return (-1);
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+ /*
+ * on older Xen without the inactive guests management
+ * avoid doing this on inactive guests
+ */
+ if ((domain->id < 0) && (priv->xendConfigVersion < 3))
+ return -1;
+
+ if (!(def = xenDaemonDomainFetch(domain->conn,
+ domain->id,
+ domain->name,
+ NULL)))
+ goto cleanup;
+
+ if (!(dev = virDomainDeviceDefParse(domain->conn,
+ priv->caps,
+ def, xml, VIR_DOMAIN_XML_INACTIVE)))
+ goto cleanup;
+
+ if (virDomainXMLDevID(domain, dev, class, ref, sizeof(ref)))
+ goto cleanup;
+
+ ret = xend_op(domain->conn, domain->name, "op", "device_destroy",
+ "type", class, "dev", ref, "force", "0", "rm_cfg", "1", NULL);
+
+cleanup:
+ virDomainDefFree(def);
+ virDomainDeviceDefFree(dev);
+
+ return ret;
+}
+
+int
+xenDaemonDomainGetAutostart(virDomainPtr domain,
+ int *autostart)
+{
+ struct sexpr *root;
+ const char *tmp;
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return (-1);
+ }
+
+ /* xm_internal.c (the support for defined domains from /etc/xen
+ * config files used by old Xen) will handle this.
+ */
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->xendConfigVersion < 3)
+ return(-1);
+
+ root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
+ if (root == NULL) {
+ virXendError (domain->conn, VIR_ERR_XEN_CALL,
+ "%s", _("xenDaemonGetAutostart failed to find this domain"));
+ return (-1);
+ }
+
+ *autostart = 0;
+
+ tmp = sexpr_node(root, "domain/on_xend_start");
+ if (tmp && STREQ(tmp, "start")) {
+ *autostart = 1;
+ }
+
+ sexpr_free(root);
+ return 0;
+}
+
+int
+xenDaemonDomainSetAutostart(virDomainPtr domain,
+ int autostart)
+{
+ struct sexpr *root, *autonode;
+ const char *autostr;
+ char buf[4096];
+ int ret = -1;
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INTERNAL_ERROR,
+ __FUNCTION__);
+ return (-1);
+ }
+
+ /* xm_internal.c (the support for defined domains from /etc/xen
+ * config files used by old Xen) will handle this.
+ */
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->xendConfigVersion < 3)
+ return(-1);
+
+ root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
+ if (root == NULL) {
+ virXendError (domain->conn, VIR_ERR_XEN_CALL,
+ "%s", _("xenDaemonSetAutostart failed to find this domain"));
+ return (-1);
+ }
+
+ autostr = sexpr_node(root, "domain/on_xend_start");
+ if (autostr) {
+ if (!STREQ(autostr, "ignore") && !STREQ(autostr, "start")) {
+ virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unexpected value from on_xend_start"));
+ goto error;
+ }
+
+ // Change the autostart value in place, then define the new sexpr
+ autonode = sexpr_lookup(root, "domain/on_xend_start");
+ VIR_FREE(autonode->u.s.car->u.value);
+ autonode->u.s.car->u.value = (autostart ? strdup("start")
+ : strdup("ignore"));
+ if (!(autonode->u.s.car->u.value)) {
+ virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("no memory"));
+ goto error;
+ }
+
+ if (sexpr2string(root, buf, sizeof(buf)) == 0) {
+ virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("sexpr2string failed"));
+ goto error;
+ }
+ if (xend_op(domain->conn, "", "op", "new", "config", buf, NULL) != 0) {
+ virXendError(domain->conn, VIR_ERR_XEN_CALL,
+ "%s", _("Failed to redefine sexpr"));
+ goto error;
+ }
+ } else {
+ virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("on_xend_start not present in sexpr"));
+ goto error;
+ }
+
+ ret = 0;
+ error:
+ sexpr_free(root);
+ return ret;
+}
+
+int
+xenDaemonDomainMigratePrepare (virConnectPtr dconn,
+ char **cookie ATTRIBUTE_UNUSED,
+ int *cookielen ATTRIBUTE_UNUSED,
+ const char *uri_in,
+ char **uri_out,
+ unsigned long flags ATTRIBUTE_UNUSED,
+ const char *dname ATTRIBUTE_UNUSED,
+ unsigned long resource ATTRIBUTE_UNUSED)
+{
+ int r;
+ char hostname [HOST_NAME_MAX+1];
+
+ /* If uri_in is NULL, get the current hostname as a best guess
+ * of how the source host should connect to us. Note that caller
+ * deallocates this string.
+ */
+ if (uri_in == NULL) {
+ r = gethostname (hostname, HOST_NAME_MAX+1);
+ if (r == -1) {
+ virReportSystemError(dconn, errno,
+ _("unable to resolve name %s"), hostname);
+ return -1;
+ }
+ *uri_out = strdup (hostname);
+ if (*uri_out == NULL) {
+ virReportOOMError(dconn);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int
+xenDaemonDomainMigratePerform (virDomainPtr domain,
+ const char *cookie ATTRIBUTE_UNUSED,
+ int cookielen ATTRIBUTE_UNUSED,
+ const char *uri,
+ unsigned long flags,
+ const char *dname,
+ unsigned long bandwidth)
+{
+ /* Upper layers have already checked domain. */
+ virConnectPtr conn = domain->conn;
+ /* NB: Passing port=0 to xend means it ignores
+ * the port. However this is somewhat specific to
+ * the internals of the xend Python code. (XXX).
+ */
+ char port[16] = "0";
+ char live[2] = "0";
+ int ret;
+ char *p, *hostname = NULL;
+
+ /* Xen doesn't support renaming domains during migration. */
+ if (dname) {
+ virXendError (conn, VIR_ERR_NO_SUPPORT,
+ "%s", _("xenDaemonDomainMigrate: Xen does not support"
+ " renaming domains during migration"));
+ return -1;
+ }
+
+ /* Xen (at least up to 3.1.0) takes a resource parameter but
+ * ignores it.
+ */
+ if (bandwidth) {
+ virXendError (conn, VIR_ERR_NO_SUPPORT,
+ "%s", _("xenDaemonDomainMigrate: Xen does not support"
+ " bandwidth limits during migration"));
+ return -1;
+ }
+
+ /* Check the flags. */
+ if ((flags & VIR_MIGRATE_LIVE)) {
+ strcpy (live, "1");
+ flags &= ~VIR_MIGRATE_LIVE;
+ }
+ if (flags != 0) {
+ virXendError (conn, VIR_ERR_NO_SUPPORT,
+ "%s", _("xenDaemonDomainMigrate: unsupported flag"));
+ return -1;
+ }
+
+ /* Set hostname and port.
+ *
+ * URI is non-NULL (guaranteed by caller). We expect either
+ * "hostname", "hostname:port" or "xenmigr://hostname[:port]/".
+ */
+ if (strstr (uri, "//")) { /* Full URI. */
+ xmlURIPtr uriptr = xmlParseURI (uri);
+ if (!uriptr) {
+ virXendError (conn, VIR_ERR_INVALID_ARG,
+ "%s", _("xenDaemonDomainMigrate: invalid URI"));
+ return -1;
+ }
+ if (uriptr->scheme && STRCASENEQ (uriptr->scheme, "xenmigr")) {
+ virXendError (conn, VIR_ERR_INVALID_ARG,
+ "%s", _("xenDaemonDomainMigrate: only xenmigr://"
+ " migrations are supported by Xen"));
+ xmlFreeURI (uriptr);
+ return -1;
+ }
+ if (!uriptr->server) {
+ virXendError (conn, VIR_ERR_INVALID_ARG,
+ "%s", _("xenDaemonDomainMigrate: a hostname must be"
+ " specified in the URI"));
+ xmlFreeURI (uriptr);
+ return -1;
+ }
+ hostname = strdup (uriptr->server);
+ if (!hostname) {
+ virReportOOMError (conn);
+ xmlFreeURI (uriptr);
+ return -1;
+ }
+ if (uriptr->port)
+ snprintf (port, sizeof port, "%d", uriptr->port);
+ xmlFreeURI (uriptr);
+ }
+ else if ((p = strrchr (uri, ':')) != NULL) { /* "hostname:port" */
+ int port_nr, n;
+
+ if (sscanf (p+1, "%d", &port_nr) != 1) {
+ virXendError (conn, VIR_ERR_INVALID_ARG,
+ "%s", _("xenDaemonDomainMigrate: invalid port number"));
+ return -1;
+ }
+ snprintf (port, sizeof port, "%d", port_nr);
+
+ /* Get the hostname. */
+ n = p - uri; /* n = Length of hostname in bytes. */
+ hostname = strdup (uri);
+ if (!hostname) {
+ virReportOOMError (conn);
+ return -1;
+ }
+ hostname[n] = '\0';
+ }
+ else { /* "hostname" (or IP address) */
+ hostname = strdup (uri);
+ if (!hostname) {
+ virReportOOMError (conn);
+ return -1;
+ }
+ }
+
+ DEBUG("hostname = %s, port = %s", hostname, port);
+
+ /* Make the call. */
+ ret = xend_op (domain->conn, domain->name,
+ "op", "migrate",
+ "destination", hostname,
+ "live", live,
+ "port", port,
+ "node", "-1",
+ "ssl", "0",
+ "resource", "0", /* required, xend ignores it */
+ NULL);
+ VIR_FREE (hostname);
+
+ DEBUG0("migration done");
+
+ return ret;
+}
+
+virDomainPtr xenDaemonDomainDefineXML(virConnectPtr conn, const char *xmlDesc) {
+ int ret;
+ char *sexpr;
+ virDomainPtr dom;
+ xenUnifiedPrivatePtr priv;
+ virDomainDefPtr def;
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ if (priv->xendConfigVersion < 3)
+ return(NULL);
+
+ if (!(def = virDomainDefParseString(conn, priv->caps, xmlDesc,
+ VIR_DOMAIN_XML_INACTIVE))) {
+ virXendError(conn, VIR_ERR_XML_ERROR,
+ "%s", _("failed to parse domain description"));
+ return (NULL);
+ }
+
+ if (!(sexpr = xenDaemonFormatSxpr(conn, def, priv->xendConfigVersion))) {
+ virXendError(conn, VIR_ERR_XML_ERROR,
+ "%s", _("failed to build sexpr"));
+ goto error;
+ }
+
+ DEBUG("Defining w/ sexpr: \n%s", sexpr);
+
+ ret = xend_op(conn, "", "op", "new", "config", sexpr, NULL);
+ VIR_FREE(sexpr);
+ if (ret != 0) {
+ virXendError(conn, VIR_ERR_XEN_CALL,
+ _("Failed to create inactive domain %s\n"), def->name);
+ goto error;
+ }
+
+ dom = virDomainLookupByName(conn, def->name);
+ if (dom == NULL) {
+ goto error;
+ }
+ virDomainDefFree(def);
+ return (dom);
+
+ error:
+ virDomainDefFree(def);
+ return (NULL);
+}
+int xenDaemonDomainCreate(virDomainPtr domain)
+{
+ xenUnifiedPrivatePtr priv;
+ int ret;
+ virDomainPtr tmp;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+ if (priv->xendConfigVersion < 3)
+ return(-1);
+
+ ret = xend_op(domain->conn, domain->name, "op", "start", NULL);
+
+ if (ret != -1) {
+ /* Need to force a refresh of this object's ID */
+ tmp = virDomainLookupByName(domain->conn, domain->name);
+ if (tmp) {
+ domain->id = tmp->id;
+ virDomainFree(tmp);
+ }
+ }
+ return ret;
+}
+
+int xenDaemonDomainUndefine(virDomainPtr domain)
+{
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+ if (priv->xendConfigVersion < 3)
+ return(-1);
+
+ return xend_op(domain->conn, domain->name, "op", "delete", NULL);
+}
+
+/**
+ * xenDaemonNumOfDomains:
+ * @conn: pointer to the hypervisor connection
+ *
+ * Provides the number of active domains.
+ *
+ * Returns the number of domain found or -1 in case of error
+ */
+static int
+xenDaemonNumOfDefinedDomains(virConnectPtr conn)
+{
+ struct sexpr *root = NULL;
+ int ret = -1;
+ struct sexpr *_for_i, *node;
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ /* xm_internal.c (the support for defined domains from /etc/xen
+ * config files used by old Xen) will handle this.
+ */
+ if (priv->xendConfigVersion < 3)
+ return(-1);
+
+ root = sexpr_get(conn, "/xend/domain?state=halted");
+ if (root == NULL)
+ goto error;
+
+ ret = 0;
+
+ for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
+ _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
+ if (node->kind != SEXPR_VALUE)
+ continue;
+ ret++;
+ }
+
+error:
+ sexpr_free(root);
+ return(ret);
+}
+
+static int
+xenDaemonListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) {
+ struct sexpr *root = NULL;
+ int ret = -1;
+ struct sexpr *_for_i, *node;
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ if (priv->xendConfigVersion < 3)
+ return(-1);
+
+ if ((names == NULL) || (maxnames < 0))
+ goto error;
+ if (maxnames == 0)
+ return(0);
+
+ root = sexpr_get(conn, "/xend/domain?state=halted");
+ if (root == NULL)
+ goto error;
+
+ ret = 0;
+
+ for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
+ _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
+ if (node->kind != SEXPR_VALUE)
+ continue;
+
+ names[ret++] = strdup(node->u.value);
+ if (ret >= maxnames)
+ break;
+ }
+
+error:
+ sexpr_free(root);
+ return(ret);
+}
+
+/**
+ * xenDaemonGetSchedulerType:
+ * @domain: pointer to the Domain block
+ * @nparams: give a number of scheduler parameters
+ *
+ * Get the scheduler type of Xen
+ *
+ * Returns a scheduler name (credit or sedf) which must be freed by the
+ * caller or NULL in case of failure
+ */
+static char *
+xenDaemonGetSchedulerType(virDomainPtr domain, int *nparams)
+{
+ xenUnifiedPrivatePtr priv;
+ struct sexpr *root;
+ const char *ret = NULL;
+ char *schedulertype = NULL;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
+ || (nparams == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return NULL;
+ }
+
+ /* Support only xendConfigVersion >=4 */
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->xendConfigVersion < 4) {
+ virXendError (domain->conn, VIR_ERR_NO_SUPPORT,
+ "%s", _("unsupported in xendConfigVersion < 4"));
+ return NULL;
+ }
+
+ root = sexpr_get(domain->conn, "/xend/node/");
+ if (root == NULL)
+ return NULL;
+
+ /* get xen_scheduler from xend/node */
+ ret = sexpr_node(root, "node/xen_scheduler");
+ if (ret == NULL){
+ virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("node information incomplete, missing scheduler name"));
+ goto error;
+ }
+ if (STREQ (ret, "credit")) {
+ schedulertype = strdup("credit");
+ if (schedulertype == NULL){
+ virXendError(domain->conn, VIR_ERR_SYSTEM_ERROR, "%s", _("strdup failed"));
+ goto error;
+ }
+ *nparams = XEN_SCHED_CRED_NPARAM;
+ } else if (STREQ (ret, "sedf")) {
+ schedulertype = strdup("sedf");
+ if (schedulertype == NULL){
+ virXendError(domain->conn, VIR_ERR_SYSTEM_ERROR, "%s", _("strdup failed"));
+ goto error;
+ }
+ *nparams = XEN_SCHED_SEDF_NPARAM;
+ } else {
+ virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
+ goto error;
+ }
+
+error:
+ sexpr_free(root);
+ return schedulertype;
+
+}
+
+static const char *str_weight = "weight";
+static const char *str_cap = "cap";
+
+/**
+ * xenDaemonGetSchedulerParameters:
+ * @domain: pointer to the Domain block
+ * @params: pointer to scheduler parameters
+ * This memory area must be allocated by the caller
+ * @nparams: a number of scheduler parameters which should be same as a
+ * given number from xenDaemonGetSchedulerType()
+ *
+ * Get the scheduler parameters
+ *
+ * Returns 0 or -1 in case of failure
+ */
+static int
+xenDaemonGetSchedulerParameters(virDomainPtr domain,
+ virSchedParameterPtr params, int *nparams)
+{
+ xenUnifiedPrivatePtr priv;
+ struct sexpr *root;
+ char *sched_type = NULL;
+ int sched_nparam = 0;
+ int ret = -1;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
+ || (params == NULL) || (nparams == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return (-1);
+ }
+
+ /* Support only xendConfigVersion >=4 */
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->xendConfigVersion < 4) {
+ virXendError (domain->conn, VIR_ERR_NO_SUPPORT,
+ "%s", _("unsupported in xendConfigVersion < 4"));
+ return (-1);
+ }
+
+ /* look up the information by domain name */
+ root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
+ if (root == NULL)
+ return (-1);
+
+ /* get the scheduler type */
+ sched_type = xenDaemonGetSchedulerType(domain, &sched_nparam);
+ if (sched_type == NULL) {
+ virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Failed to get a scheduler name"));
+ goto error;
+ }
+
+ switch (sched_nparam){
+ case XEN_SCHED_SEDF_NPARAM:
+ /* TODO: Implement for Xen/SEDF */
+ TODO
+ goto error;
+ case XEN_SCHED_CRED_NPARAM:
+ /* get cpu_weight/cpu_cap from xend/domain */
+ if (sexpr_node(root, "domain/cpu_weight") == NULL) {
+ virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, missing cpu_weight"));
+ goto error;
+ }
+ if (sexpr_node(root, "domain/cpu_cap") == NULL) {
+ virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, missing cpu_cap"));
+ goto error;
+ }
+
+ strncpy (params[0].field, str_weight, VIR_DOMAIN_SCHED_FIELD_LENGTH);
+ params[0].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
+ params[0].type = VIR_DOMAIN_SCHED_FIELD_UINT;
+ params[0].value.ui = sexpr_int(root, "domain/cpu_weight");
+
+ strncpy (params[1].field, str_cap, VIR_DOMAIN_SCHED_FIELD_LENGTH);
+ params[1].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
+ params[1].type = VIR_DOMAIN_SCHED_FIELD_UINT;
+ params[1].value.ui = sexpr_int(root, "domain/cpu_cap");
+ *nparams = XEN_SCHED_CRED_NPARAM;
+ ret = 0;
+ break;
+ default:
+ virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
+ goto error;
+ }
+
+error:
+ sexpr_free(root);
+ VIR_FREE(sched_type);
+ return (ret);
+}
+
+/**
+ * xenDaemonSetSchedulerParameters:
+ * @domain: pointer to the Domain block
+ * @params: pointer to scheduler parameters
+ * @nparams: a number of scheduler setting parameters
+ *
+ * Set the scheduler parameters
+ *
+ * Returns 0 or -1 in case of failure
+ */
+static int
+xenDaemonSetSchedulerParameters(virDomainPtr domain,
+ virSchedParameterPtr params, int nparams)
+{
+ xenUnifiedPrivatePtr priv;
+ struct sexpr *root;
+ char *sched_type = NULL;
+ int i;
+ int sched_nparam = 0;
+ int ret = -1;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
+ || (params == NULL)) {
+ virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return (-1);
+ }
+
+ /* Support only xendConfigVersion >=4 and active domains */
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->xendConfigVersion < 4) {
+ virXendError (domain->conn, VIR_ERR_NO_SUPPORT,
+ "%s", _("unsupported in xendConfigVersion < 4"));
+ return (-1);
+ }
+
+ /* look up the information by domain name */
+ root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
+ if (root == NULL)
+ return (-1);
+
+ /* get the scheduler type */
+ sched_type = xenDaemonGetSchedulerType(domain, &sched_nparam);
+ if (sched_type == NULL) {
+ virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Failed to get a scheduler name"));
+ goto error;
+ }
+
+ switch (sched_nparam){
+ case XEN_SCHED_SEDF_NPARAM:
+ /* TODO: Implement for Xen/SEDF */
+ TODO
+ goto error;
+ case XEN_SCHED_CRED_NPARAM: {
+ char buf_weight[VIR_UUID_BUFLEN];
+ char buf_cap[VIR_UUID_BUFLEN];
+ const char *weight = NULL;
+ const char *cap = NULL;
+
+ /* get the scheduler parameters */
+ memset(&buf_weight, 0, VIR_UUID_BUFLEN);
+ memset(&buf_cap, 0, VIR_UUID_BUFLEN);
+ for (i = 0; i < nparams; i++) {
+ if (STREQ (params[i].field, str_weight) &&
+ params[i].type == VIR_DOMAIN_SCHED_FIELD_UINT) {
+ snprintf(buf_weight, sizeof(buf_weight), "%u", params[i].value.ui);
+ } else if (STREQ (params[i].field, str_cap) &&
+ params[i].type == VIR_DOMAIN_SCHED_FIELD_UINT) {
+ snprintf(buf_cap, sizeof(buf_cap), "%u", params[i].value.ui);
+ } else {
+ virXendError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+ }
+
+ /* if not get the scheduler parameter, set the current setting */
+ if (strlen(buf_weight) == 0) {
+ weight = sexpr_node(root, "domain/cpu_weight");
+ if (weight == NULL) {
+ virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, missing cpu_weight"));
+ goto error;
+ }
+ snprintf(buf_weight, sizeof(buf_weight), "%s", weight);
+ }
+ if (strlen(buf_cap) == 0) {
+ cap = sexpr_node(root, "domain/cpu_cap");
+ if (cap == NULL) {
+ virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, missing cpu_cap"));
+ goto error;
+ }
+ snprintf(buf_cap, sizeof(buf_cap), "%s", cap);
+ }
+
+ ret = xend_op(domain->conn, domain->name, "op",
+ "domain_sched_credit_set", "weight", buf_weight,
+ "cap", buf_cap, NULL);
+ break;
+ }
+ default:
+ virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
+ goto error;
+ }
+
+error:
+ sexpr_free(root);
+ VIR_FREE(sched_type);
+ return (ret);
+}
+
+/**
+ * xenDaemonDomainBlockPeek:
+ * @dom: domain object
+ * @path: path to the file or device
+ * @offset: offset
+ * @size: size
+ * @buffer: return buffer
+ *
+ * Returns 0 if successful, -1 if error, -2 if declined.
+ */
+int
+xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path,
+ unsigned long long offset, size_t size,
+ void *buffer)
+{
+ xenUnifiedPrivatePtr priv;
+ struct sexpr *root = NULL;
+ int fd = -1, ret = -1;
+ int found = 0, i;
+ virDomainDefPtr def;
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+ if (domain->id < 0 && priv->xendConfigVersion < 3)
+ return -2; /* Decline, allow XM to handle it. */
+
+ /* Security check: The path must correspond to a block device. */
+ if (domain->id > 0)
+ root = sexpr_get (domain->conn, "/xend/domain/%d?detail=1",
+ domain->id);
+ else if (domain->id < 0)
+ root = sexpr_get (domain->conn, "/xend/domain/%s?detail=1",
+ domain->name);
+ else {
+ /* This call always fails for dom0. */
+ virXendError (domain->conn, VIR_ERR_NO_SUPPORT,
+ "%s", _("domainBlockPeek is not supported for dom0"));
+ return -1;
+ }
+
+ if (!root) {
+ virXendError (domain->conn, VIR_ERR_XEN_CALL, __FUNCTION__);
+ return -1;
+ }
+
+ if (!(def = xenDaemonParseSxpr(domain->conn, root, priv->xendConfigVersion, NULL)))
+ goto cleanup;
+
+ for (i = 0 ; i < def->ndisks ; i++) {
+ if (def->disks[i]->src &&
+ STREQ(def->disks[i]->src, path)) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ virXendError (domain->conn, VIR_ERR_INVALID_ARG,
+ _("%s: invalid path"), path);
+ goto cleanup;
+ }
+
+ /* The path is correct, now try to open it and get its size. */
+ fd = open (path, O_RDONLY);
+ if (fd == -1) {
+ virReportSystemError(domain->conn, errno,
+ _("failed to open for reading: %s"),
+ path);
+ goto cleanup;
+ }
+
+ /* Seek and read. */
+ /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
+ * be 64 bits on all platforms.
+ */
+ if (lseek (fd, offset, SEEK_SET) == (off_t) -1 ||
+ saferead (fd, buffer, size) == (ssize_t) -1) {
+ virReportSystemError(domain->conn, errno,
+ _("failed to lseek or read from file: %s"),
+ path);
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ if (fd >= 0) close (fd);
+ sexpr_free(root);
+ virDomainDefFree(def);
+ return ret;
+}
+
+struct xenUnifiedDriver xenDaemonDriver = {
+ xenDaemonOpen, /* open */
+ xenDaemonClose, /* close */
+ xenDaemonGetVersion, /* version */
+ NULL, /* hostname */
+ xenDaemonNodeGetInfo, /* nodeGetInfo */
+ NULL, /* getCapabilities */
+ xenDaemonListDomains, /* listDomains */
+ xenDaemonNumOfDomains, /* numOfDomains */
+ xenDaemonCreateXML, /* domainCreateXML */
+ xenDaemonDomainSuspend, /* domainSuspend */
+ xenDaemonDomainResume, /* domainResume */
+ xenDaemonDomainShutdown, /* domainShutdown */
+ xenDaemonDomainReboot, /* domainReboot */
+ xenDaemonDomainDestroy, /* domainDestroy */
+ xenDaemonDomainGetOSType, /* domainGetOSType */
+ xenDaemonDomainGetMaxMemory, /* domainGetMaxMemory */
+ xenDaemonDomainSetMaxMemory, /* domainSetMaxMemory */
+ xenDaemonDomainSetMemory, /* domainMaxMemory */
+ xenDaemonDomainGetInfo, /* domainGetInfo */
+ xenDaemonDomainSave, /* domainSave */
+ xenDaemonDomainRestore, /* domainRestore */
+ xenDaemonDomainCoreDump, /* domainCoreDump */
+ xenDaemonDomainSetVcpus, /* domainSetVcpus */
+ xenDaemonDomainPinVcpu, /* domainPinVcpu */
+ xenDaemonDomainGetVcpus, /* domainGetVcpus */
+ NULL, /* domainGetMaxVcpus */
+ xenDaemonListDefinedDomains, /* listDefinedDomains */
+ xenDaemonNumOfDefinedDomains,/* numOfDefinedDomains */
+ xenDaemonDomainCreate, /* domainCreate */
+ xenDaemonDomainDefineXML, /* domainDefineXML */
+ xenDaemonDomainUndefine, /* domainUndefine */
+ xenDaemonAttachDevice, /* domainAttachDevice */
+ xenDaemonDetachDevice, /* domainDetachDevice */
+ xenDaemonDomainGetAutostart, /* domainGetAutostart */
+ xenDaemonDomainSetAutostart, /* domainSetAutostart */
+ xenDaemonGetSchedulerType, /* domainGetSchedulerType */
+ xenDaemonGetSchedulerParameters, /* domainGetSchedulerParameters */
+ xenDaemonSetSchedulerParameters, /* domainSetSchedulerParameters */
+};
+
+/************************************************************************
+ * *
+ * Converter functions to go from the XML tree to an S-Expr for Xen *
+ * *
+ ************************************************************************/
+
+
+/**
+ * virtDomainParseXMLGraphicsDescVFB:
+ * @conn: pointer to the hypervisor connection
+ * @node: node containing graphics description
+ * @buf: a buffer for the result S-Expr
+ *
+ * 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
+ * valid over time.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+static int
+xenDaemonFormatSxprGraphicsNew(virConnectPtr conn,
+ virDomainGraphicsDefPtr def,
+ virBufferPtr buf)
+{
+ if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_SDL &&
+ def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected graphics type %d"),
+ def->type);
+ return -1;
+ }
+
+ virBufferAddLit(buf, "(device (vkbd))");
+ virBufferAddLit(buf, "(device (vfb ");
+
+ if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
+ virBufferAddLit(buf, "(type sdl)");
+ if (def->data.sdl.display)
+ virBufferVSprintf(buf, "(display '%s')", def->data.sdl.display);
+ if (def->data.sdl.xauth)
+ virBufferVSprintf(buf, "(xauthority '%s')", def->data.sdl.xauth);
+ } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
+ virBufferAddLit(buf, "(type vnc)");
+ if (def->data.vnc.autoport) {
+ virBufferAddLit(buf, "(vncunused 1)");
+ } else {
+ virBufferAddLit(buf, "(vncunused 0)");
+ virBufferVSprintf(buf, "(vncdisplay %d)", def->data.vnc.port-5900);
+ }
+
+ if (def->data.vnc.listenAddr)
+ virBufferVSprintf(buf, "(vnclisten '%s')", def->data.vnc.listenAddr);
+ if (def->data.vnc.passwd)
+ virBufferVSprintf(buf, "(vncpasswd '%s')", def->data.vnc.passwd);
+ if (def->data.vnc.keymap)
+ virBufferVSprintf(buf, "(keymap '%s')", def->data.vnc.keymap);
+ }
+
+ virBufferAddLit(buf, "))");
+
+ return 0;
+}
+
+
+static int
+xenDaemonFormatSxprGraphicsOld(virConnectPtr conn,
+ virDomainGraphicsDefPtr def,
+ virBufferPtr buf,
+ int xendConfigVersion)
+{
+ if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_SDL &&
+ def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected graphics type %d"),
+ def->type);
+ return -1;
+ }
+
+ if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
+ virBufferAddLit(buf, "(sdl 1)");
+ if (def->data.sdl.display)
+ virBufferVSprintf(buf, "(display '%s')", def->data.sdl.display);
+ if (def->data.sdl.xauth)
+ virBufferVSprintf(buf, "(xauthority '%s')", def->data.sdl.xauth);
+ } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
+ virBufferAddLit(buf, "(vnc 1)");
+ if (xendConfigVersion >= 2) {
+ if (def->data.vnc.autoport) {
+ virBufferAddLit(buf, "(vncunused 1)");
+ } else {
+ virBufferAddLit(buf, "(vncunused 0)");
+ virBufferVSprintf(buf, "(vncdisplay %d)", def->data.vnc.port-5900);
+ }
+
+ if (def->data.vnc.listenAddr)
+ virBufferVSprintf(buf, "(vnclisten '%s')", def->data.vnc.listenAddr);
+ if (def->data.vnc.passwd)
+ virBufferVSprintf(buf, "(vncpasswd '%s')", def->data.vnc.passwd);
+ if (def->data.vnc.keymap)
+ virBufferVSprintf(buf, "(keymap '%s')", def->data.vnc.keymap);
+
+ }
+ }
+
+ return 0;
+}
+
+int
+xenDaemonFormatSxprChr(virConnectPtr conn,
+ virDomainChrDefPtr def,
+ virBufferPtr buf)
+{
+ const char *type = virDomainChrTypeToString(def->type);
+
+ if (!type) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unexpected chr device type"));
+ return -1;
+ }
+
+ switch (def->type) {
+ case VIR_DOMAIN_CHR_TYPE_NULL:
+ case VIR_DOMAIN_CHR_TYPE_STDIO:
+ case VIR_DOMAIN_CHR_TYPE_VC:
+ case VIR_DOMAIN_CHR_TYPE_PTY:
+ virBufferVSprintf(buf, "%s", type);
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_FILE:
+ case VIR_DOMAIN_CHR_TYPE_PIPE:
+ virBufferVSprintf(buf, "%s:%s", type, def->data.file.path);
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_DEV:
+ virBufferVSprintf(buf, "%s", def->data.file.path);
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_TCP:
+ virBufferVSprintf(buf, "%s:%s:%s%s",
+ (def->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW ?
+ "tcp" : "telnet"),
+ (def->data.tcp.host ? def->data.tcp.host : ""),
+ (def->data.tcp.service ? def->data.tcp.service : ""),
+ (def->data.tcp.listen ? ",listen" : ""));
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UDP:
+ virBufferVSprintf(buf, "%s:%s:%s@%s:%s", type,
+ (def->data.udp.connectHost ? def->data.udp.connectHost : ""),
+ (def->data.udp.connectService ? def->data.udp.connectService : ""),
+ (def->data.udp.bindHost ? def->data.udp.bindHost : ""),
+ (def->data.udp.bindService ? def->data.udp.bindService : ""));
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UNIX:
+ virBufferVSprintf(buf, "%s:%s%s", type,
+ def->data.nix.path,
+ def->data.nix.listen ? ",listen" : "");
+ break;
+ }
+
+ if (virBufferError(buf))
+ return -1;
+
+ return 0;
+}
+
+
+/**
+ * virDomainParseXMLDiskDesc:
+ * @node: node containing disk description
+ * @conn: pointer to the hypervisor connection
+ * @buf: a buffer for the result S-Expr
+ * @xendConfigVersion: xend configuration file format
+ *
+ * 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
+xenDaemonFormatSxprDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainDiskDefPtr def,
+ virBufferPtr buf,
+ int hvm,
+ int xendConfigVersion,
+ int isAttach)
+{
+ /* Xend (all versions) put the floppy device config
+ * under the hvm (image (os)) block
+ */
+ if (hvm &&
+ def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
+ if (isAttach) {
+ virXendError(conn, VIR_ERR_INVALID_ARG,
+ _("Cannot directly attach floppy %s"), def->src);
+ return -1;
+ }
+ return 0;
+ }
+
+ /* Xend <= 3.0.2 doesn't include cdrom config here */
+ if (hvm &&
+ def->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
+ xendConfigVersion == 1) {
+ if (isAttach) {
+ virXendError(conn, VIR_ERR_INVALID_ARG,
+ _("Cannot directly attach CDROM %s"), def->src);
+ return -1;
+ }
+ return 0;
+ }
+
+ if (!isAttach)
+ virBufferAddLit(buf, "(device ");
+
+ /* Normally disks are in a (device (vbd ...)) block
+ * but blktap disks ended up in a differently named
+ * (device (tap ....)) block.... */
+ if (def->driverName &&
+ STREQ(def->driverName, "tap")) {
+ virBufferAddLit(buf, "(tap ");
+ } else {
+ virBufferAddLit(buf, "(vbd ");
+ }
+
+ if (hvm) {
+ /* Xend <= 3.0.2 wants a ioemu: prefix on devices for HVM */
+ if (xendConfigVersion == 1)
+ virBufferVSprintf(buf, "(dev 'ioemu:%s')", def->dst);
+ else /* But newer does not */
+ virBufferVSprintf(buf, "(dev '%s:%s')", def->dst,
+ def->device == VIR_DOMAIN_DISK_DEVICE_CDROM ?
+ "cdrom" : "disk");
+ } else if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
+ virBufferVSprintf(buf, "(dev '%s:cdrom')", def->dst);
+ } else {
+ virBufferVSprintf(buf, "(dev '%s')", def->dst);
+ }
+
+ if (def->src) {
+ if (def->driverName) {
+ if (STREQ(def->driverName, "tap")) {
+ virBufferVSprintf(buf, "(uname '%s:%s:%s')",
+ def->driverName,
+ def->driverType ? def->driverType : "aio",
+ def->src);
+ } else {
+ virBufferVSprintf(buf, "(uname '%s:%s')",
+ def->driverName,
+ def->src);
+ }
+ } else {
+ if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
+ virBufferVSprintf(buf, "(uname 'file:%s')", def->src);
+ } else {
+ if (def->src[0] == '/')
+ virBufferVSprintf(buf, "(uname 'phy:%s')", def->src);
+ else
+ virBufferVSprintf(buf, "(uname 'phy:/dev/%s')", def->src);
+ }
+ }
+ }
+
+ if (def->readonly)
+ virBufferAddLit(buf, "(mode 'r')");
+ else if (def->shared)
+ virBufferAddLit(buf, "(mode 'w!')");
+ else
+ virBufferAddLit(buf, "(mode 'w')");
+
+ if (!isAttach)
+ virBufferAddLit(buf, ")");
+
+ virBufferAddLit(buf, ")");
+
+ return 0;
+}
+
+/**
+ * xenDaemonFormatSxprNet
+ * @conn: pointer to the hypervisor connection
+ * @node: node containing the interface description
+ * @buf: a buffer for the result S-Expr
+ * @xendConfigVersion: xend configuration file format
+ *
+ * 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
+xenDaemonFormatSxprNet(virConnectPtr conn,
+ virDomainNetDefPtr def,
+ virBufferPtr buf,
+ int hvm,
+ int xendConfigVersion,
+ int isAttach)
+{
+ const char *script = DEFAULT_VIF_SCRIPT;
+
+ if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
+ def->type != VIR_DOMAIN_NET_TYPE_NETWORK &&
+ def->type != VIR_DOMAIN_NET_TYPE_ETHERNET) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported network type %d"), def->type);
+ return -1;
+ }
+
+ if (!isAttach)
+ virBufferAddLit(buf, "(device ");
+
+ virBufferAddLit(buf, "(vif ");
+
+ virBufferVSprintf(buf,
+ "(mac '%02x:%02x:%02x:%02x:%02x:%02x')",
+ def->mac[0], def->mac[1], def->mac[2],
+ def->mac[3], def->mac[4], def->mac[5]);
+
+ switch (def->type) {
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ virBufferVSprintf(buf, "(bridge '%s')", def->data.bridge.brname);
+ if (def->data.bridge.script)
+ script = def->data.bridge.script;
+
+ virBufferVSprintf(buf, "(script '%s')", script);
+ if (def->data.bridge.ipaddr != NULL)
+ virBufferVSprintf(buf, "(ip '%s')", def->data.bridge.ipaddr);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ {
+ virNetworkPtr network =
+ virNetworkLookupByName(conn, def->data.network.name);
+ char *bridge;
+
+ if (!network) {
+ virXendError(conn, VIR_ERR_NO_NETWORK, "%s",
+ def->data.network.name);
+ return -1;
+ }
+
+ bridge = virNetworkGetBridgeName(network);
+ virNetworkFree(network);
+ if (!bridge) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("network %s is not active"),
+ def->data.network.name);
+ return -1;
+ }
+ virBufferVSprintf(buf, "(bridge '%s')", bridge);
+ virBufferVSprintf(buf, "(script '%s')", script);
+ VIR_FREE(bridge);
+ }
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ if (def->data.ethernet.script)
+ virBufferVSprintf(buf, "(script '%s')", def->data.ethernet.script);
+ if (def->data.ethernet.ipaddr != NULL)
+ virBufferVSprintf(buf, "(ip '%s')", def->data.ethernet.ipaddr);
+ break;
+ }
+
+ if (def->ifname != NULL &&
+ !STRPREFIX(def->ifname, "vif"))
+ virBufferVSprintf(buf, "(vifname '%s')", def->ifname);
+
+ if (def->model != NULL)
+ virBufferVSprintf(buf, "(model '%s')", def->model);
+
+ /*
+ * apparently (type ioemu) breaks paravirt drivers on HVM so skip this
+ * from Xen 3.1.0
+ */
+ if (hvm && xendConfigVersion <= XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU)
+ virBufferAddLit(buf, "(type ioemu)");
+
+ if (!isAttach)
+ virBufferAddLit(buf, ")");
+
+ virBufferAddLit(buf, ")");
+
+ return 0;
+}
+
+
+static void
+xenDaemonFormatSxprPCI(virDomainHostdevDefPtr def,
+ virBufferPtr buf)
+{
+ virBufferVSprintf(buf, "(dev (domain 0x%04x)(bus 0x%02x)(slot 0x%02x)(func 0x%x))",
+ def->source.subsys.u.pci.domain,
+ def->source.subsys.u.pci.bus,
+ def->source.subsys.u.pci.slot,
+ def->source.subsys.u.pci.function);
+}
+
+static int
+xenDaemonFormatSxprOnePCI(virConnectPtr conn,
+ virDomainHostdevDefPtr def,
+ virBufferPtr buf)
+{
+ if (def->managed) {
+ virXendError(conn, VIR_ERR_NO_SUPPORT, "%s",
+ _("managed PCI devices not supported with XenD"));
+ return -1;
+ }
+
+ virBufferAddLit(buf, "(pci ");
+ xenDaemonFormatSxprPCI(def, buf);
+ virBufferAddLit(buf, ")");
+
+ return 0;
+}
+
+static int
+xenDaemonFormatSxprAllPCI(virConnectPtr conn,
+ virDomainDefPtr def,
+ virBufferPtr buf)
+{
+ int hasPCI = 0;
+ int i;
+
+ for (i = 0 ; i < def->nhostdevs ; i++)
+ if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+ def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+ hasPCI = 1;
+
+ if (!hasPCI)
+ return 0;
+
+ /*
+ * With the (domain ...) block we have the following odd setup
+ *
+ * (device
+ * (pci
+ * (dev (domain 0x0000) (bus 0x00) (slot 0x1b) (func 0x0))
+ * (dev (domain 0x0000) (bus 0x00) (slot 0x13) (func 0x0))
+ * )
+ * )
+ *
+ * Normally there is one (device ...) block per device, but in
+ * wierd world of Xen PCI, once (device ...) covers multiple
+ * devices.
+ */
+
+ virBufferAddLit(buf, "(device (pci ");
+ for (i = 0 ; i < def->nhostdevs ; i++) {
+ if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+ def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
+ if (def->hostdevs[i]->managed) {
+ virXendError(conn, VIR_ERR_NO_SUPPORT, "%s",
+ _("managed PCI devices not supported with XenD"));
+ return -1;
+ }
+
+ xenDaemonFormatSxprPCI(def->hostdevs[i], buf);
+ }
+ }
+ virBufferAddLit(buf, "))");
+
+ return 0;
+}
+
+int
+xenDaemonFormatSxprSound(virConnectPtr conn,
+ virDomainDefPtr def,
+ virBufferPtr buf)
+{
+ const char *str;
+ int i;
+
+ for (i = 0 ; i < def->nsounds ; i++) {
+ if (!(str = virDomainSoundModelTypeToString(def->sounds[i]->model))) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected sound model %d"),
+ def->sounds[i]->model);
+ return -1;
+ }
+ virBufferVSprintf(buf, "%s%s", i ? "," : "", str);
+ }
+
+ if (virBufferError(buf))
+ return -1;
+
+ return 0;
+}
+
+
+static int
+xenDaemonFormatSxprInput(virConnectPtr conn,
+ virDomainInputDefPtr input,
+ virBufferPtr buf)
+{
+ if (input->bus != VIR_DOMAIN_INPUT_BUS_USB)
+ return 0;
+
+ if (input->type != VIR_DOMAIN_INPUT_TYPE_MOUSE &&
+ input->type != VIR_DOMAIN_INPUT_TYPE_TABLET) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected input type %d"), input->type);
+ return -1;
+ }
+
+ virBufferVSprintf(buf, "(usbdevice %s)",
+ input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
+ "mouse" : "tablet");
+
+ return 0;
+}
+
+
+/**
+ * xenDaemonFormatSxpr:
+ * @conn: pointer to the hypervisor connection
+ * @def: domain config definition
+ * @xendConfigVersion: xend configuration file format
+ *
+ * Generate an SEXPR representing the domain configuration.
+ *
+ * Returns the 0 terminatedi S-Expr string or NULL in case of error.
+ * the caller must free() the returned value.
+ */
+char *
+xenDaemonFormatSxpr(virConnectPtr conn,
+ virDomainDefPtr def,
+ int xendConfigVersion)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ const char *tmp;
+ int hvm = 0, i;
+
+ virBufferAddLit(&buf, "(vm ");
+ virBufferVSprintf(&buf, "(name '%s')", def->name);
+ virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)",
+ def->memory/1024, def->maxmem/1024);
+ virBufferVSprintf(&buf, "(vcpus %lu)", def->vcpus);
+
+ if (def->cpumask) {
+ char *ranges = virDomainCpuSetFormat(conn, def->cpumask, def->cpumasklen);
+ if (ranges == NULL)
+ goto error;
+ virBufferVSprintf(&buf, "(cpus '%s')", ranges);
+ VIR_FREE(ranges);
+ }
+
+ virUUIDFormat(def->uuid, uuidstr);
+ virBufferVSprintf(&buf, "(uuid '%s')", uuidstr);
+
+ if (def->os.bootloader) {
+ if (def->os.bootloader[0])
+ virBufferVSprintf(&buf, "(bootloader '%s')", def->os.bootloader);
+ else
+ virBufferAddLit(&buf, "(bootloader)");
+
+ if (def->os.bootloaderArgs)
+ virBufferVSprintf(&buf, "(bootloader_args '%s')", def->os.bootloaderArgs);
+ }
+
+ if (!(tmp = virDomainLifecycleTypeToString(def->onPoweroff))) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected lifecycle value %d"), def->onPoweroff);
+ goto error;
+ }
+ virBufferVSprintf(&buf, "(on_poweroff '%s')", tmp);
+
+ if (!(tmp = virDomainLifecycleTypeToString(def->onReboot))) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected lifecycle value %d"), def->onReboot);
+ goto error;
+ }
+ virBufferVSprintf(&buf, "(on_reboot '%s')", tmp);
+
+ if (!(tmp = virDomainLifecycleTypeToString(def->onCrash))) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected lifecycle value %d"), def->onCrash);
+ goto error;
+ }
+ virBufferVSprintf(&buf, "(on_crash '%s')", tmp);
+
+ /* Set localtime here for current XenD (both PV & HVM) */
+ if (def->localtime)
+ virBufferAddLit(&buf, "(localtime 1)");
+
+ if (!def->os.bootloader) {
+ if (STREQ(def->os.type, "hvm"))
+ hvm = 1;
+
+ if (hvm)
+ virBufferAddLit(&buf, "(image (hvm ");
+ else
+ virBufferAddLit(&buf, "(image (linux ");
+
+ if (hvm &&
+ def->os.loader == NULL) {
+ virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s",_("no HVM domain loader"));
+ goto error;
+ }
+
+ if (def->os.kernel)
+ virBufferVSprintf(&buf, "(kernel '%s')", def->os.kernel);
+ if (def->os.initrd)
+ virBufferVSprintf(&buf, "(ramdisk '%s')", def->os.initrd);
+ if (def->os.root)
+ virBufferVSprintf(&buf, "(root '%s')", def->os.root);
+ if (def->os.cmdline)
+ virBufferVSprintf(&buf, "(args '%s')", def->os.cmdline);
+
+ if (hvm) {
+ char bootorder[VIR_DOMAIN_BOOT_LAST+1];
+ if (def->os.kernel)
+ virBufferVSprintf(&buf, "(loader '%s')", def->os.loader);
+ else
+ virBufferVSprintf(&buf, "(kernel '%s')", def->os.loader);
+
+ virBufferVSprintf(&buf, "(vcpus %lu)", def->vcpus);
+
+ for (i = 0 ; i < def->os.nBootDevs ; i++) {
+ switch (def->os.bootDevs[i]) {
+ case VIR_DOMAIN_BOOT_FLOPPY:
+ bootorder[i] = 'a';
+ break;
+ default:
+ case VIR_DOMAIN_BOOT_DISK:
+ bootorder[i] = 'c';
+ break;
+ case VIR_DOMAIN_BOOT_CDROM:
+ bootorder[i] = 'd';
+ break;
+ case VIR_DOMAIN_BOOT_NET:
+ bootorder[i] = 'n';
+ break;
+ }
+ }
+ if (def->os.nBootDevs == 0) {
+ bootorder[0] = 'c';
+ bootorder[1] = '\0';
+ } else {
+ bootorder[def->os.nBootDevs] = '\0';
+ }
+ virBufferVSprintf(&buf, "(boot %s)", bootorder);
+
+ /* some disk devices are defined here */
+ for (i = 0 ; i < def->ndisks ; i++) {
+ switch (def->disks[i]->device) {
+ case VIR_DOMAIN_DISK_DEVICE_CDROM:
+ /* Only xend <= 3.0.2 wants cdrom config here */
+ if (xendConfigVersion != 1)
+ break;
+ if (!STREQ(def->disks[i]->dst, "hdc") ||
+ def->disks[i]->src == NULL)
+ break;
+
+ virBufferVSprintf(&buf, "(cdrom '%s')",
+ def->disks[i]->src);
+ break;
+
+ case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
+ /* all xend versions define floppies here */
+ virBufferVSprintf(&buf, "(%s '%s')", def->disks[i]->dst,
+ def->disks[i]->src);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (def->features & (1 << VIR_DOMAIN_FEATURE_ACPI))
+ virBufferAddLit(&buf, "(acpi 1)");
+ if (def->features & (1 << VIR_DOMAIN_FEATURE_APIC))
+ virBufferAddLit(&buf, "(apic 1)");
+ if (def->features & (1 << VIR_DOMAIN_FEATURE_PAE))
+ virBufferAddLit(&buf, "(pae 1)");
+
+ virBufferAddLit(&buf, "(usb 1)");
+
+ for (i = 0 ; i < def->ninputs ; i++)
+ if (xenDaemonFormatSxprInput(conn, def->inputs[i], &buf) < 0)
+ goto error;
+
+ if (def->parallels) {
+ virBufferAddLit(&buf, "(parallel ");
+ if (xenDaemonFormatSxprChr(conn, def->parallels[0], &buf) < 0)
+ goto error;
+ virBufferAddLit(&buf, ")");
+ } else {
+ virBufferAddLit(&buf, "(parallel none)");
+ }
+ if (def->serials) {
+ virBufferAddLit(&buf, "(serial ");
+ if (xenDaemonFormatSxprChr(conn, def->serials[0], &buf) < 0)
+ goto error;
+ virBufferAddLit(&buf, ")");
+ } else {
+ virBufferAddLit(&buf, "(serial none)");
+ }
+
+ /* Set localtime here to keep old XenD happy for HVM */
+ if (def->localtime)
+ virBufferAddLit(&buf, "(localtime 1)");
+
+ if (def->sounds) {
+ virBufferAddLit(&buf, "(soundhw '");
+ if (xenDaemonFormatSxprSound(conn, def, &buf) < 0)
+ goto error;
+ virBufferAddLit(&buf, "')");
+ }
+ }
+
+ /* get the device emulation model */
+ if (def->emulator && (hvm || xendConfigVersion >= 3))
+ virBufferVSprintf(&buf, "(device_model '%s')", def->emulator);
+
+
+ /* PV graphics for xen <= 3.0.4, or HVM graphics for xen <= 3.1.0 */
+ if ((!hvm && xendConfigVersion < XEND_CONFIG_MIN_VERS_PVFB_NEWCONF) ||
+ (hvm && xendConfigVersion < 4)) {
+ if ((def->ngraphics == 1) &&
+ xenDaemonFormatSxprGraphicsOld(conn, def->graphics[0],
+ &buf, xendConfigVersion) < 0)
+ goto error;
+ }
+
+ virBufferAddLit(&buf, "))");
+ }
+
+ for (i = 0 ; i < def->ndisks ; i++)
+ if (xenDaemonFormatSxprDisk(conn, def->disks[i],
+ &buf, hvm, xendConfigVersion, 0) < 0)
+ goto error;
+
+ for (i = 0 ; i < def->nnets ; i++)
+ if (xenDaemonFormatSxprNet(conn, def->nets[i],
+ &buf, hvm, xendConfigVersion, 0) < 0)
+ goto error;
+
+ if (xenDaemonFormatSxprAllPCI(conn, def, &buf) < 0)
+ goto error;
+
+ /* New style PV graphics config xen >= 3.0.4,
+ * or HVM graphics config xen >= 3.0.5 */
+ if ((xendConfigVersion >= XEND_CONFIG_MIN_VERS_PVFB_NEWCONF && !hvm) ||
+ (xendConfigVersion >= 4 && hvm)) {
+ if ((def->ngraphics == 1) &&
+ xenDaemonFormatSxprGraphicsNew(conn, def->graphics[0], &buf) < 0)
+ goto error;
+ }
+
+ virBufferAddLit(&buf, ")"); /* closes (vm */
+
+ if (virBufferError(&buf)) {
+ virReportOOMError(conn);
+ return NULL;
+ }
+
+ return virBufferContentAndReset(&buf);
+
+error:
+ tmp = virBufferContentAndReset(&buf);
+ VIR_FREE(tmp);
+ return NULL;
+}
+
+
+/**
+ * virDomainXMLDevID:
+ * @domain: pointer to domain object
+ * @dev: pointer to device config object
+ * @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.
+ */
+static int
+virDomainXMLDevID(virDomainPtr domain,
+ virDomainDeviceDefPtr dev,
+ char *class,
+ char *ref,
+ int ref_len)
+{
+ xenUnifiedPrivatePtr priv = domain->conn->privateData;
+ char *xref;
+
+ if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
+ if (dev->data.disk->driverName &&
+ STREQ(dev->data.disk->driverName, "tap"))
+ strcpy(class, "tap");
+ else
+ strcpy(class, "vbd");
+
+ if (dev->data.disk->dst == NULL)
+ return -1;
+ xenUnifiedLock(priv);
+ xref = xenStoreDomainGetDiskID(domain->conn, domain->id,
+ dev->data.disk->dst);
+ xenUnifiedUnlock(priv);
+ if (xref == NULL)
+ return -1;
+
+ strncpy(ref, xref, ref_len);
+ free(xref);
+ ref[ref_len - 1] = '\0';
+ } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
+ char mac[30];
+ virDomainNetDefPtr def = dev->data.net;
+ snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
+ def->mac[0], def->mac[1], def->mac[2],
+ def->mac[3], def->mac[4], def->mac[5]);
+
+ strcpy(class, "vif");
+
+ xenUnifiedLock(priv);
+ xref = xenStoreDomainGetNetworkID(domain->conn, domain->id,
+ mac);
+ xenUnifiedUnlock(priv);
+ if (xref == NULL)
+ return -1;
+
+ strncpy(ref, xref, ref_len);
+ free(xref);
+ ref[ref_len - 1] = '\0';
+ } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
+ dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+ dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
+ } else {
+ virXendError(NULL, VIR_ERR_NO_SUPPORT,
+ "%s", _("hotplug of device type not supported"));
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* ! PROXY */
--- /dev/null
+/*
+ * xend_internal.h
+ *
+ * Copyright (C) 2005,2006
+ *
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Daniel Veillard <veillard@redhat.com>
+ *
+ * Copyright 2006-2008 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __XEND_INTERNAL_H_
+#define __XEND_INTERNAL_H_
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <libxml/uri.h>
+
+#include "internal.h"
+#include "capabilities.h"
+#include "domain_conf.h"
+#include "driver.h"
+#include "buf.h"
+
+#ifdef __sun
+#define DEFAULT_VIF_SCRIPT "vif-vnic"
+#else
+#define DEFAULT_VIF_SCRIPT "vif-bridge"
+#endif
+
+int
+xenDaemonOpen_unix(virConnectPtr conn, const char *path);
+
+/**
+ * \brief Blocks until a domain's devices are initialized
+ * \param xend A xend instance
+ * \param name The domain's name
+ * \return 0 for success; -1 (with errno) on error
+ *
+ * xen_create() returns after a domain has been allocated including
+ * its memory. This does not guarentee, though, that the devices
+ * have come up properly. For instance, if you create a VBD with an
+ * invalid filename, the error won't occur until after this function
+ * returns.
+ */
+ int xend_wait_for_devices(virConnectPtr xend, const char *name);
+
+
+/**
+ * \brief Create a new domain
+ * \param xend A xend instance
+ * \param sexpr An S-Expr defining the domain
+ * \return 0 for success; -1 (with errno) on error
+ *
+ * This method will create a domain based the passed in description. The
+ * domain will be paused after creation and must be unpaused with
+ * xenDaemonResumeDomain() to begin execution.
+ */
+int xenDaemonDomainCreateXML(virConnectPtr xend, const char *sexpr);
+
+/**
+ * \brief Lookup the id of a domain
+ * \param xend A xend instance
+ * \param name The name of the domain
+ * \param uuid pointer to store a copy of the uuid
+ * \return the id number on success; -1 (with errno) on error
+ *
+ * This method looks up the ids of a domain
+ */
+int xenDaemonDomainLookupByName_ids(virConnectPtr xend,
+ const char *name, unsigned char *uuid);
+
+
+/**
+ * \brief Lookup the name of a domain
+ * \param xend A xend instance
+ * \param id The id of the domain
+ * \param name pointer to store a copy of the name
+ * \param uuid pointer to store a copy of the uuid
+ *
+ * This method looks up the name/uuid of a domain
+ */
+int xenDaemonDomainLookupByID(virConnectPtr xend,
+ int id,
+ char **name, unsigned char *uuid);
+
+
+virDomainDefPtr
+xenDaemonDomainFetch(virConnectPtr xend,
+ int domid,
+ const char *name,
+ const char *cpus);
+
+ int xend_parse_sexp_desc_char(virConnectPtr conn,
+ virBufferPtr buf,
+ const char *devtype,
+ int portNum,
+ const char *value,
+ const char *tty);
+
+virDomainDefPtr
+xenDaemonParseSxprString(virConnectPtr conn,
+ const char *sexpr,
+ int xendConfigVersion);
+
+int
+xenDaemonParseSxprSound(virConnectPtr conn,
+ virDomainDefPtr def,
+ const char *str);
+virDomainChrDefPtr
+xenDaemonParseSxprChar(virConnectPtr conn,
+ const char *value,
+ const char *tty);
+
+int
+xenDaemonFormatSxprChr(virConnectPtr conn,
+ virDomainChrDefPtr def,
+ virBufferPtr buf);
+int
+xenDaemonFormatSxprSound(virConnectPtr conn,
+ virDomainDefPtr def,
+ virBufferPtr buf);
+
+char *
+xenDaemonFormatSxpr(virConnectPtr conn,
+ virDomainDefPtr def,
+ int xendConfigVersion);
+
+ int is_sound_model_valid(const char *model);
+ int is_sound_model_conflict(const char *model, const char *soundstr);
+
+
+/* refactored ones */
+virDrvOpenStatus xenDaemonOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags);
+int xenDaemonClose(virConnectPtr conn);
+int xenDaemonGetVersion(virConnectPtr conn, unsigned long *hvVer);
+int xenDaemonNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info);
+int xenDaemonNodeGetTopology(virConnectPtr conn, virCapsPtr caps);
+int xenDaemonDomainSuspend(virDomainPtr domain);
+int xenDaemonDomainResume(virDomainPtr domain);
+int xenDaemonDomainShutdown(virDomainPtr domain);
+int xenDaemonDomainReboot(virDomainPtr domain, unsigned int flags);
+int xenDaemonDomainDestroy(virDomainPtr domain);
+int xenDaemonDomainSave(virDomainPtr domain, const char *filename);
+int xenDaemonDomainRestore(virConnectPtr conn, const char *filename);
+int xenDaemonDomainSetMemory(virDomainPtr domain, unsigned long memory);
+int xenDaemonDomainSetMaxMemory(virDomainPtr domain, unsigned long memory);
+int xenDaemonDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info);
+char *xenDaemonDomainDumpXML(virDomainPtr domain, int flags, const char *cpus);
+unsigned long xenDaemonDomainGetMaxMemory(virDomainPtr domain);
+char **xenDaemonListDomainsOld(virConnectPtr xend);
+
+virDomainPtr xenDaemonDomainDefineXML(virConnectPtr xend, const char *sexpr);
+int xenDaemonDomainCreate(virDomainPtr domain);
+int xenDaemonDomainUndefine(virDomainPtr domain);
+
+int xenDaemonDomainSetVcpus (virDomainPtr domain,
+ unsigned int vcpus);
+int xenDaemonDomainPinVcpu (virDomainPtr domain,
+ unsigned int vcpu,
+ unsigned char *cpumap,
+ int maplen);
+int xenDaemonDomainGetVcpus (virDomainPtr domain,
+ virVcpuInfoPtr info,
+ int maxinfo,
+ unsigned char *cpumaps,
+ int maplen);
+int xenDaemonDomainGetAutostart (virDomainPtr dom,
+ int *autostart);
+int xenDaemonDomainSetAutostart (virDomainPtr domain,
+ int autostart);
+
+/* xen_unified calls through here. */
+extern struct xenUnifiedDriver xenDaemonDriver;
+int xenDaemonInit (void);
+
+virDomainPtr xenDaemonLookupByID(virConnectPtr conn, int id);
+virDomainPtr xenDaemonLookupByUUID(virConnectPtr conn, const unsigned char *uuid);
+virDomainPtr xenDaemonLookupByName(virConnectPtr conn, const char *domname);
+int xenDaemonDomainMigratePrepare (virConnectPtr dconn, char **cookie, int *cookielen, const char *uri_in, char **uri_out, unsigned long flags, const char *dname, unsigned long resource);
+int xenDaemonDomainMigratePerform (virDomainPtr domain, const char *cookie, int cookielen, const char *uri, unsigned long flags, const char *dname, unsigned long resource);
+
+int xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path, unsigned long long offset, size_t size, void *buffer);
+int xenDaemonListDomains(virConnectPtr conn, int *ids, int maxids);
+
+#endif /* __XEND_INTERNAL_H_ */
--- /dev/null
+/*
+ * xm_internal.h: helper routines for dealing with inactive domains
+ *
+ * Copyright (C) 2006-2007, 2009 Red Hat
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange@redhat.com>
+ *
+ */
+
+#include <config.h>
+
+#include <dirent.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+
+#include <unistd.h>
+#include <stdint.h>
+#include <xen/dom0_ops.h>
+
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "xm_internal.h"
+#include "xen_driver.h"
+#include "xend_internal.h"
+#include "hash.h"
+#include "buf.h"
+#include "uuid.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+
+#define VIR_FROM_THIS VIR_FROM_XENXM
+
+#ifdef WITH_RHEL5_API
+#define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 0
+#define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 2
+#else
+#define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 3
+#define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 3
+#endif
+
+/* The true Xen limit varies but so far is always way
+ less than 1024, which is the Linux kernel limit according
+ to sched.h, so we'll match that for now */
+#define XEN_MAX_PHYSICAL_CPU 1024
+
+static int xenXMConfigSetString(virConfPtr conf, const char *setting,
+ const char *str);
+char * xenXMAutoAssignMac(void);
+static int xenXMDomainAttachDevice(virDomainPtr domain, const char *xml);
+static int xenXMDomainDetachDevice(virDomainPtr domain, const char *xml);
+
+#define XM_REFRESH_INTERVAL 10
+
+#define XM_CONFIG_DIR "/etc/xen"
+#define XM_EXAMPLE_PREFIX "xmexample"
+#define XEND_CONFIG_FILE "xend-config.sxp"
+#define XEND_PCI_CONFIG_PREFIX "xend-pci-"
+#define QEMU_IF_SCRIPT "qemu-ifup"
+#define XM_XML_ERROR "Invalid xml"
+
+struct xenUnifiedDriver xenXMDriver = {
+ xenXMOpen, /* open */
+ xenXMClose, /* close */
+ NULL, /* version */
+ NULL, /* hostname */
+ NULL, /* nodeGetInfo */
+ NULL, /* getCapabilities */
+ NULL, /* listDomains */
+ NULL, /* numOfDomains */
+ NULL, /* domainCreateXML */
+ NULL, /* domainSuspend */
+ NULL, /* domainResume */
+ NULL, /* domainShutdown */
+ NULL, /* domainReboot */
+ NULL, /* domainDestroy */
+ NULL, /* domainGetOSType */
+ xenXMDomainGetMaxMemory, /* domainGetMaxMemory */
+ xenXMDomainSetMaxMemory, /* domainSetMaxMemory */
+ xenXMDomainSetMemory, /* domainMaxMemory */
+ xenXMDomainGetInfo, /* domainGetInfo */
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
+ NULL, /* domainCoreDump */
+ xenXMDomainSetVcpus, /* domainSetVcpus */
+ xenXMDomainPinVcpu, /* domainPinVcpu */
+ NULL, /* domainGetVcpus */
+ NULL, /* domainGetMaxVcpus */
+ xenXMListDefinedDomains, /* listDefinedDomains */
+ xenXMNumOfDefinedDomains, /* numOfDefinedDomains */
+ xenXMDomainCreate, /* domainCreate */
+ xenXMDomainDefineXML, /* domainDefineXML */
+ xenXMDomainUndefine, /* domainUndefine */
+ xenXMDomainAttachDevice, /* domainAttachDevice */
+ xenXMDomainDetachDevice, /* domainDetachDevice */
+ NULL, /* domainGetAutostart */
+ NULL, /* domainSetAutostart */
+ NULL, /* domainGetSchedulerType */
+ NULL, /* domainGetSchedulerParameters */
+ NULL, /* domainSetSchedulerParameters */
+};
+
+#define xenXMError(conn, code, fmt...) \
+ virReportErrorHelper(conn, VIR_FROM_XENXM, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
+#ifndef WITH_XEN_INOTIFY
+static int xenInotifyActive(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+#else
+static int xenInotifyActive(virConnectPtr conn)
+{
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+ return priv->inotifyWatch > 0;
+}
+#endif
+
+/* Convenience method to grab a int from the config file object */
+static int xenXMConfigGetBool(virConnectPtr conn,
+ virConfPtr conf,
+ const char *name,
+ int *value,
+ int def) {
+ virConfValuePtr val;
+
+ *value = 0;
+ if (!(val = virConfGetValue(conf, name))) {
+ *value = def;
+ return 0;
+ }
+
+ if (val->type == VIR_CONF_LONG) {
+ *value = val->l ? 1 : 0;
+ } else if (val->type == VIR_CONF_STRING) {
+ if (!val->str) {
+ *value = def;
+ }
+ *value = STREQ(val->str, "1") ? 1 : 0;
+ } else {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("config value %s was malformed"), name);
+ return -1;
+ }
+ return 0;
+}
+
+
+/* Convenience method to grab a int from the config file object */
+static int xenXMConfigGetULong(virConnectPtr conn,
+ virConfPtr conf,
+ const char *name,
+ unsigned long *value,
+ int def) {
+ virConfValuePtr val;
+
+ *value = 0;
+ if (!(val = virConfGetValue(conf, name))) {
+ *value = def;
+ return 0;
+ }
+
+ if (val->type == VIR_CONF_LONG) {
+ *value = val->l;
+ } else if (val->type == VIR_CONF_STRING) {
+ char *ret;
+ if (!val->str) {
+ *value = def;
+ }
+ *value = strtol(val->str, &ret, 10);
+ if (ret == val->str) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("config value %s was malformed"), name);
+ return -1;
+ }
+ } else {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("config value %s was malformed"), name);
+ return -1;
+ }
+ return 0;
+}
+
+
+/* Convenience method to grab a string from the config file object */
+static int xenXMConfigGetString(virConnectPtr conn,
+ virConfPtr conf,
+ const char *name,
+ const char **value,
+ const char *def) {
+ virConfValuePtr val;
+
+ *value = NULL;
+ if (!(val = virConfGetValue(conf, name))) {
+ *value = def;
+ return 0;
+ }
+
+ if (val->type != VIR_CONF_STRING) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("config value %s was malformed"), name);
+ return -1;
+ }
+ if (!val->str)
+ *value = def;
+ else
+ *value = val->str;
+ return 0;
+}
+
+static int xenXMConfigCopyStringInternal(virConnectPtr conn,
+ virConfPtr conf,
+ const char *name,
+ char **value,
+ int allowMissing) {
+ virConfValuePtr val;
+
+ *value = NULL;
+ if (!(val = virConfGetValue(conf, name))) {
+ if (allowMissing)
+ return 0;
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("config value %s was missing"), name);
+ return -1;
+ }
+
+ if (val->type != VIR_CONF_STRING) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("config value %s was not a string"), name);
+ return -1;
+ }
+ if (!val->str) {
+ if (allowMissing)
+ return 0;
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("config value %s was missing"), name);
+ return -1;
+ }
+
+ if (!(*value = strdup(val->str))) {
+ virReportOOMError(conn);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int xenXMConfigCopyString(virConnectPtr conn,
+ virConfPtr conf,
+ const char *name,
+ char **value) {
+ return xenXMConfigCopyStringInternal(conn, conf, name, value, 0);
+}
+
+static int xenXMConfigCopyStringOpt(virConnectPtr conn,
+ virConfPtr conf,
+ const char *name,
+ char **value) {
+ return xenXMConfigCopyStringInternal(conn, conf, name, value, 1);
+}
+
+
+/* Convenience method to grab a string UUID from the config file object */
+static int xenXMConfigGetUUID(virConfPtr conf, const char *name, unsigned char *uuid) {
+ virConfValuePtr val;
+ if (!uuid || !name || !conf)
+ return (-1);
+ if (!(val = virConfGetValue(conf, name))) {
+ return (-1);
+ }
+
+ if (val->type != VIR_CONF_STRING)
+ return (-1);
+ if (!val->str)
+ return (-1);
+
+ if (virUUIDParse(val->str, uuid) < 0)
+ return (-1);
+
+ return (0);
+}
+
+
+/* Release memory associated with a cached config object */
+static void xenXMConfigFree(void *payload, const char *key ATTRIBUTE_UNUSED) {
+ xenXMConfCachePtr entry = (xenXMConfCachePtr)payload;
+ virDomainDefFree(entry->def);
+ VIR_FREE(entry);
+}
+
+struct xenXMConfigReaperData {
+ xenUnifiedPrivatePtr priv;
+ time_t now;
+};
+
+/* Remove any configs which were not refreshed recently */
+static int xenXMConfigReaper(const void *payload, const char *key ATTRIBUTE_UNUSED, const void *data) {
+ const struct xenXMConfigReaperData *args = data;
+ xenXMConfCachePtr entry = (xenXMConfCachePtr)payload;
+
+ /* We're going to purge this config file, so check if it
+ is currently mapped as owner of a named domain. */
+ if (entry->refreshedAt != args->now) {
+ const char *olddomname = entry->def->name;
+ char *nameowner = (char *)virHashLookup(args->priv->nameConfigMap, olddomname);
+ if (nameowner && STREQ(nameowner, key)) {
+ virHashRemoveEntry(args->priv->nameConfigMap, olddomname, NULL);
+ }
+ return (1);
+ }
+ return (0);
+}
+
+
+static virDomainDefPtr
+xenXMConfigReadFile(virConnectPtr conn, const char *filename) {
+ virConfPtr conf;
+ virDomainDefPtr def;
+
+ if (!(conf = virConfReadFile(filename, 0)))
+ return NULL;
+
+ def = xenXMDomainConfigParse(conn, conf);
+ virConfFree(conf);
+
+ return def;
+}
+
+static int
+xenXMConfigSaveFile(virConnectPtr conn, const char *filename, virDomainDefPtr def) {
+ virConfPtr conf;
+ int ret;
+
+ if (!(conf = xenXMDomainConfigFormat(conn, def)))
+ return -1;
+
+ ret = virConfWriteFile(filename, conf);
+ virConfFree(conf);
+ return ret;
+}
+
+
+/*
+ * Caller must hold the lock on 'conn->privateData' before
+ * calling this funtion
+ */
+int
+xenXMConfigCacheRemoveFile(virConnectPtr conn,
+ const char *filename)
+{
+ xenUnifiedPrivatePtr priv = conn->privateData;
+ xenXMConfCachePtr entry;
+
+ entry = virHashLookup(priv->configCache, filename);
+ if (!entry) {
+ DEBUG("No config entry for %s", filename);
+ return 0;
+ }
+
+ virHashRemoveEntry(priv->nameConfigMap, entry->def->name, NULL);
+ virHashRemoveEntry(priv->configCache, filename, xenXMConfigFree);
+ DEBUG("Removed %s %s", entry->def->name, filename);
+ return 0;
+}
+
+
+/*
+ * Caller must hold the lock on 'conn->privateData' before
+ * calling this funtion
+ */
+int
+xenXMConfigCacheAddFile(virConnectPtr conn, const char *filename)
+{
+ xenUnifiedPrivatePtr priv = conn->privateData;
+ xenXMConfCachePtr entry;
+ struct stat st;
+ int newborn = 0;
+ time_t now = time(NULL);
+
+ DEBUG("Adding file %s", filename);
+
+ /* Get modified time */
+ if ((stat(filename, &st) < 0)) {
+ virReportSystemError(conn, errno,
+ _("cannot stat: %s"),
+ filename);
+ return -1;
+ }
+
+ /* Ignore zero length files, because inotify fires before
+ any content has actually been created */
+ if (st.st_size == 0) {
+ DEBUG("Ignoring zero length file %s", filename);
+ return -1;
+ }
+
+ /* If we already have a matching entry and it is not
+ modified, then carry on to next one*/
+ if ((entry = virHashLookup(priv->configCache, filename))) {
+ char *nameowner;
+
+ if (entry->refreshedAt >= st.st_mtime) {
+ entry->refreshedAt = now;
+ /* return success if up-to-date */
+ return 0;
+ }
+
+ /* If we currently own the name, then release it and
+ re-acquire it later - just in case it was renamed */
+ nameowner = (char *)virHashLookup(priv->nameConfigMap, entry->def->name);
+ if (nameowner && STREQ(nameowner, filename)) {
+ virHashRemoveEntry(priv->nameConfigMap, entry->def->name, NULL);
+ }
+
+ /* Clear existing config entry which needs refresh */
+ virDomainDefFree(entry->def);
+ entry->def = NULL;
+ } else { /* Completely new entry */
+ newborn = 1;
+ if (VIR_ALLOC(entry) < 0) {
+ virReportOOMError(conn);
+ return -1;
+ }
+ memcpy(entry->filename, filename, PATH_MAX);
+ }
+ entry->refreshedAt = now;
+
+ if (!(entry->def = xenXMConfigReadFile(conn, entry->filename))) {
+ DEBUG("Failed to read %s", entry->filename);
+ if (!newborn)
+ virHashRemoveEntry(priv->configCache, filename, NULL);
+ VIR_FREE(entry);
+ return -1;
+ }
+
+ /* If its a completely new entry, it must be stuck into
+ the cache (refresh'd entries are already registered) */
+ if (newborn) {
+ if (virHashAddEntry(priv->configCache, entry->filename, entry) < 0) {
+ virDomainDefFree(entry->def);
+ VIR_FREE(entry);
+ xenXMError (conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("xenXMConfigCacheRefresh: virHashAddEntry"));
+ return -1;
+ }
+ }
+
+ /* See if we need to map this config file in as the primary owner
+ * of the domain in question
+ */
+ if (!virHashLookup(priv->nameConfigMap, entry->def->name)) {
+ if (virHashAddEntry(priv->nameConfigMap, entry->def->name, entry->filename) < 0) {
+ virHashRemoveEntry(priv->configCache, filename, NULL);
+ virDomainDefFree(entry->def);
+ VIR_FREE(entry);
+ }
+ }
+ DEBUG("Added config %s %s", entry->def->name, filename);
+
+ return 0;
+}
+
+/* This method is called by various methods to scan /etc/xen
+ * (or whatever directory was set by LIBVIRT_XM_CONFIG_DIR
+ * environment variable) and process any domain configs. It
+ * has rate-limited so never rescans more frequently than
+ * once every X seconds
+ *
+ * Caller must hold the lock on 'conn->privateData' before
+ * calling this funtion
+ */
+int xenXMConfigCacheRefresh (virConnectPtr conn) {
+ xenUnifiedPrivatePtr priv = conn->privateData;
+ DIR *dh;
+ struct dirent *ent;
+ time_t now = time(NULL);
+ int ret = -1;
+ struct xenXMConfigReaperData args;
+
+ if (now == ((time_t)-1)) {
+ virReportSystemError(conn, errno,
+ "%s", _("cannot get time of day"));
+ return (-1);
+ }
+
+ /* Rate limit re-scans */
+ if ((now - priv->lastRefresh) < XM_REFRESH_INTERVAL)
+ return (0);
+
+ priv->lastRefresh = now;
+
+ /* Process the files in the config dir */
+ if (!(dh = opendir(priv->configDir))) {
+ virReportSystemError(conn, errno,
+ _("cannot read directory %s"),
+ priv->configDir);
+ return (-1);
+ }
+
+ while ((ent = readdir(dh))) {
+ struct stat st;
+ char path[PATH_MAX];
+
+ /*
+ * Skip a bunch of crufty files that clearly aren't config files
+ */
+
+ /* Like 'dot' files... */
+ if (STRPREFIX(ent->d_name, "."))
+ continue;
+ /* ...and the XenD server config file */
+ if (STRPREFIX(ent->d_name, XEND_CONFIG_FILE))
+ continue;
+ /* ...and random PCI config cruft */
+ if (STRPREFIX(ent->d_name, XEND_PCI_CONFIG_PREFIX))
+ continue;
+ /* ...and the example domain configs */
+ if (STRPREFIX(ent->d_name, XM_EXAMPLE_PREFIX))
+ continue;
+ /* ...and the QEMU networking script */
+ if (STRPREFIX(ent->d_name, QEMU_IF_SCRIPT))
+ continue;
+
+ /* ...and editor backups */
+ if (ent->d_name[0] == '#')
+ continue;
+ if (ent->d_name[strlen(ent->d_name)-1] == '~')
+ continue;
+
+ /* Build the full file path */
+ if ((strlen(priv->configDir) + 1 + strlen(ent->d_name) + 1) > PATH_MAX)
+ continue;
+ strcpy(path, priv->configDir);
+ strcat(path, "/");
+ strcat(path, ent->d_name);
+
+ /* Skip anything which isn't a file (takes care of scripts/ subdir */
+ if ((stat(path, &st) < 0) ||
+ (!S_ISREG(st.st_mode))) {
+ continue;
+ }
+
+ /* If we already have a matching entry and it is not
+ modified, then carry on to next one*/
+ if (xenXMConfigCacheAddFile(conn, path) < 0) {
+ /* Ignoring errors, since alot of stuff goes wrong in /etc/xen */
+ }
+ }
+
+ /* Reap all entries which were not changed, by comparing
+ their refresh timestamp - the timestamp should match
+ 'now' if they were refreshed. If timestamp doesn't match
+ then the config is no longer on disk */
+ args.now = now;
+ args.priv = priv;
+ virHashRemoveSet(priv->configCache, xenXMConfigReaper, xenXMConfigFree, &args);
+ ret = 0;
+
+ if (dh)
+ closedir(dh);
+
+ return (ret);
+}
+
+
+/*
+ * The XM driver keeps a cache of config files as virDomainDefPtr
+ * objects in the xenUnifiedPrivatePtr. Optionally inotify lets
+ * us watch for changes (see separate driver), otherwise we poll
+ * every few seconds
+ */
+virDrvOpenStatus
+xenXMOpen (virConnectPtr conn,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED)
+{
+ xenUnifiedPrivatePtr priv = conn->privateData;
+
+ priv->configDir = XM_CONFIG_DIR;
+
+ priv->configCache = virHashCreate(50);
+ if (!priv->configCache)
+ return (-1);
+ priv->nameConfigMap = virHashCreate(50);
+ if (!priv->nameConfigMap) {
+ virHashFree(priv->configCache, NULL);
+ priv->configCache = NULL;
+ return (-1);
+ }
+ /* Force the cache to be reloaded next time that
+ * xenXMConfigCacheRefresh is called.
+ */
+ priv->lastRefresh = 0;
+
+ return (0);
+}
+
+/*
+ * Free the cached config files associated with this
+ * connection
+ */
+int xenXMClose(virConnectPtr conn) {
+ xenUnifiedPrivatePtr priv = conn->privateData;
+
+ virHashFree(priv->nameConfigMap, NULL);
+ virHashFree(priv->configCache, xenXMConfigFree);
+
+ return (0);
+}
+
+/*
+ * Since these are all offline domains, we only return info about
+ * VCPUs and memory.
+ */
+int xenXMDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) {
+ xenUnifiedPrivatePtr priv;
+ const char *filename;
+ xenXMConfCachePtr entry;
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ if (domain->id != -1)
+ return (-1);
+
+ priv = domain->conn->privateData;
+ xenUnifiedLock(priv);
+
+ if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
+ goto error;
+
+ if (!(entry = virHashLookup(priv->configCache, filename)))
+ goto error;
+
+ memset(info, 0, sizeof(virDomainInfo));
+ info->maxMem = entry->def->maxmem;
+ info->memory = entry->def->memory;
+ info->nrVirtCpu = entry->def->vcpus;
+ info->state = VIR_DOMAIN_SHUTOFF;
+ info->cpuTime = 0;
+
+ xenUnifiedUnlock(priv);
+ return (0);
+
+error:
+ xenUnifiedUnlock(priv);
+ return -1;
+}
+
+#define MAX_VFB 1024
+/*
+ * Turn a config record into a lump of XML describing the
+ * domain, suitable for later feeding for virDomainCreateXML
+ */
+virDomainDefPtr
+xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
+ const char *str;
+ int hvm = 0;
+ int val;
+ virConfValuePtr list;
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+ virDomainDefPtr def = NULL;
+ virDomainDiskDefPtr disk = NULL;
+ virDomainNetDefPtr net = NULL;
+ virDomainGraphicsDefPtr graphics = NULL;
+ virDomainHostdevDefPtr hostdev = NULL;
+ int i;
+ const char *defaultArch, *defaultMachine;
+
+ if (VIR_ALLOC(def) < 0)
+ return NULL;
+
+ def->virtType = VIR_DOMAIN_VIRT_XEN;
+ def->id = -1;
+
+ if (xenXMConfigCopyString(conn, conf, "name", &def->name) < 0)
+ goto cleanup;
+ if (xenXMConfigGetUUID(conf, "uuid", def->uuid) < 0)
+ goto cleanup;
+
+
+ if ((xenXMConfigGetString(conn, conf, "builder", &str, "linux") == 0) &&
+ STREQ(str, "hvm"))
+ hvm = 1;
+
+ if (!(def->os.type = strdup(hvm ? "hvm" : "xen")))
+ goto no_memory;
+
+ defaultArch = virCapabilitiesDefaultGuestArch(priv->caps, def->os.type, virDomainVirtTypeToString(def->virtType));
+ if (defaultArch == NULL) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("no supported architecture for os type '%s'"),
+ def->os.type);
+ goto cleanup;
+ }
+ if (!(def->os.arch = strdup(defaultArch)))
+ goto no_memory;
+
+ defaultMachine = virCapabilitiesDefaultGuestMachine(priv->caps,
+ def->os.type,
+ def->os.arch);
+ if (defaultMachine != NULL) {
+ if (!(def->os.machine = strdup(defaultMachine)))
+ goto no_memory;
+ }
+
+ if (hvm) {
+ const char *boot;
+ if (xenXMConfigCopyString(conn, conf, "kernel", &def->os.loader) < 0)
+ goto cleanup;
+
+ if (xenXMConfigGetString(conn, conf, "boot", &boot, "c") < 0)
+ goto cleanup;
+
+ for (i = 0 ; i < VIR_DOMAIN_BOOT_LAST && boot[i] ; i++) {
+ switch (*boot) {
+ case 'a':
+ def->os.bootDevs[i] = VIR_DOMAIN_BOOT_FLOPPY;
+ break;
+ case 'd':
+ def->os.bootDevs[i] = VIR_DOMAIN_BOOT_CDROM;
+ break;
+ case 'n':
+ def->os.bootDevs[i] = VIR_DOMAIN_BOOT_NET;
+ break;
+ case 'c':
+ default:
+ def->os.bootDevs[i] = VIR_DOMAIN_BOOT_DISK;
+ break;
+ }
+ def->os.nBootDevs++;
+ }
+ } else {
+ if (xenXMConfigCopyStringOpt(conn, conf, "bootloader", &def->os.bootloader) < 0)
+ goto cleanup;
+ if (xenXMConfigCopyStringOpt(conn, conf, "bootargs", &def->os.bootloaderArgs) < 0)
+ goto cleanup;
+
+ if (xenXMConfigCopyStringOpt(conn, conf, "kernel", &def->os.kernel) < 0)
+ goto cleanup;
+ if (xenXMConfigCopyStringOpt(conn, conf, "ramdisk", &def->os.initrd) < 0)
+ goto cleanup;
+ if (xenXMConfigCopyStringOpt(conn, conf, "extra", &def->os.cmdline) < 0)
+ goto cleanup;
+ }
+
+ if (xenXMConfigGetULong(conn, conf, "memory", &def->memory, MIN_XEN_GUEST_SIZE * 2) < 0)
+ goto cleanup;
+
+ if (xenXMConfigGetULong(conn, conf, "maxmem", &def->maxmem, def->memory) < 0)
+ goto cleanup;
+
+ def->memory *= 1024;
+ def->maxmem *= 1024;
+
+
+ if (xenXMConfigGetULong(conn, conf, "vcpus", &def->vcpus, 1) < 0)
+ goto cleanup;
+
+ if (xenXMConfigGetString(conn, conf, "cpus", &str, NULL) < 0)
+ goto cleanup;
+ if (str) {
+ def->cpumasklen = 4096;
+ if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0)
+ goto no_memory;
+
+ if (virDomainCpuSetParse(conn, &str, 0,
+ def->cpumask, def->cpumasklen) < 0)
+ goto cleanup;
+ }
+
+
+ if (xenXMConfigGetString(conn, conf, "on_poweroff", &str, "destroy") < 0)
+ goto cleanup;
+ if ((def->onPoweroff = virDomainLifecycleTypeFromString(str)) < 0) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected value %s for on_poweroff"), str);
+ goto cleanup;
+ }
+
+ if (xenXMConfigGetString(conn, conf, "on_reboot", &str, "restart") < 0)
+ goto cleanup;
+ if ((def->onReboot = virDomainLifecycleTypeFromString(str)) < 0) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected value %s for on_reboot"), str);
+ goto cleanup;
+ }
+
+ if (xenXMConfigGetString(conn, conf, "on_crash", &str, "restart") < 0)
+ goto cleanup;
+ if ((def->onCrash = virDomainLifecycleTypeFromString(str)) < 0) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected value %s for on_crash"), str);
+ goto cleanup;
+ }
+
+
+
+ if (hvm) {
+ if (xenXMConfigGetBool(conn, conf, "pae", &val, 0) < 0)
+ goto cleanup;
+ else if (val)
+ def->features |= (1 << VIR_DOMAIN_FEATURE_PAE);
+ if (xenXMConfigGetBool(conn, conf, "acpi", &val, 0) < 0)
+ goto cleanup;
+ else if (val)
+ def->features |= (1 << VIR_DOMAIN_FEATURE_ACPI);
+ if (xenXMConfigGetBool(conn, conf, "apic", &val, 0) < 0)
+ goto cleanup;
+ else if (val)
+ def->features |= (1 << VIR_DOMAIN_FEATURE_APIC);
+ }
+ if (xenXMConfigGetBool(conn, conf, "localtime", &def->localtime, 0) < 0)
+ goto cleanup;
+
+ if (xenXMConfigCopyStringOpt(conn, conf, "device_model", &def->emulator) < 0)
+ goto cleanup;
+
+ list = virConfGetValue(conf, "disk");
+ if (list && list->type == VIR_CONF_LIST) {
+ list = list->list;
+ while (list) {
+ char *head;
+ char *offset;
+ char *tmp;
+
+ if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
+ goto skipdisk;
+ head = list->str;
+
+ if (VIR_ALLOC(disk) < 0)
+ goto no_memory;
+
+ /*
+ * Disks have 3 components, SOURCE,DEST-DEVICE,MODE
+ * eg, phy:/dev/HostVG/XenGuest1,xvda,w
+ * The SOURCE is usually prefixed with a driver type,
+ * and optionally driver sub-type
+ * The DEST-DEVICE is optionally post-fixed with disk type
+ */
+
+ /* Extract the source file path*/
+ if (!(offset = strchr(head, ',')))
+ goto skipdisk;
+ if ((offset - head) >= (PATH_MAX-1))
+ goto skipdisk;
+
+ if (offset == head) {
+ disk->src = NULL; /* No source file given, eg CDROM with no media */
+ } else {
+ if (VIR_ALLOC_N(disk->src, (offset - head) + 1) < 0)
+ goto no_memory;
+ strncpy(disk->src, head, (offset - head));
+ disk->src[(offset-head)] = '\0';
+ }
+ head = offset + 1;
+
+ /* Remove legacy ioemu: junk */
+ if (STRPREFIX(head, "ioemu:"))
+ head = head + 6;
+
+ /* Extract the dest device name */
+ if (!(offset = strchr(head, ',')))
+ goto skipdisk;
+ if (VIR_ALLOC_N(disk->dst, (offset - head) + 1) < 0)
+ goto no_memory;
+ strncpy(disk->dst, head, (offset - head));
+ disk->dst[(offset-head)] = '\0';
+ head = offset + 1;
+
+
+ /* Extract source driver type */
+ if (disk->src) {
+ /* The main type phy:, file:, tap: ... */
+ if ((tmp = strchr(disk->src, ':')) != NULL) {
+ if (VIR_ALLOC_N(disk->driverName, (tmp - disk->src) + 1) < 0)
+ goto no_memory;
+ strncpy(disk->driverName, disk->src, (tmp - disk->src));
+ disk->driverName[tmp - disk->src] = '\0';
+
+ /* Strip the prefix we found off the source file name */
+ memmove(disk->src, disk->src+(tmp-disk->src)+1,
+ strlen(disk->src)-(tmp-disk->src));
+ }
+
+ /* And the sub-type for tap:XXX: type */
+ if (disk->driverName &&
+ STREQ(disk->driverName, "tap")) {
+ if (!(tmp = strchr(disk->src, ':')))
+ goto skipdisk;
+ if (VIR_ALLOC_N(disk->driverType, (tmp - disk->src) + 1) < 0)
+ goto no_memory;
+ strncpy(disk->driverType, disk->src, (tmp - disk->src));
+ disk->driverType[tmp - disk->src] = '\0';
+
+ /* Strip the prefix we found off the source file name */
+ memmove(disk->src, disk->src+(tmp-disk->src)+1,
+ strlen(disk->src)-(tmp-disk->src));
+ }
+ }
+
+ /* No source, or driver name, so fix to phy: */
+ if (!disk->driverName &&
+ !(disk->driverName = strdup("phy")))
+ goto no_memory;
+
+
+ /* phy: type indicates a block device */
+ disk->type = STREQ(disk->driverName, "phy") ?
+ VIR_DOMAIN_DISK_TYPE_BLOCK : VIR_DOMAIN_DISK_TYPE_FILE;
+
+ /* Check for a :cdrom/:disk postfix */
+ disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
+ if ((tmp = strchr(disk->dst, ':')) != NULL) {
+ if (STREQ(tmp, ":cdrom"))
+ disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
+ tmp[0] = '\0';
+ }
+
+ if (STRPREFIX(disk->dst, "xvd") || !hvm) {
+ disk->bus = VIR_DOMAIN_DISK_BUS_XEN;
+ } else if (STRPREFIX(disk->dst, "sd")) {
+ disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
+ } else {
+ disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
+ }
+
+ if (STREQ(head, "r") ||
+ STREQ(head, "ro"))
+ disk->readonly = 1;
+ else if ((STREQ(head, "w!")) ||
+ (STREQ(head, "!")))
+ disk->shared = 1;
+
+ /* Maintain list in sorted order according to target device name */
+ if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
+ goto no_memory;
+ def->disks[def->ndisks++] = disk;
+ disk = NULL;
+
+ skipdisk:
+ list = list->next;
+ virDomainDiskDefFree(disk);
+ }
+ }
+
+ if (hvm && priv->xendConfigVersion == 1) {
+ if (xenXMConfigGetString(conn, conf, "cdrom", &str, NULL) < 0)
+ goto cleanup;
+ if (str) {
+ if (VIR_ALLOC(disk) < 0)
+ goto no_memory;
+
+ disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
+ disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
+ if (!(disk->driverName = strdup("file")))
+ goto no_memory;
+ if (!(disk->src = strdup(str)))
+ goto no_memory;
+ if (!(disk->dst = strdup("hdc")))
+ goto no_memory;
+ disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
+ disk->readonly = 1;
+
+ if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
+ goto no_memory;
+ def->disks[def->ndisks++] = disk;
+ disk = NULL;
+ }
+ }
+
+ list = virConfGetValue(conf, "vif");
+ if (list && list->type == VIR_CONF_LIST) {
+ list = list->list;
+ while (list) {
+ char script[PATH_MAX];
+ char model[10];
+ char ip[16];
+ char mac[18];
+ char bridge[50];
+ char vifname[50];
+ char *key;
+
+ bridge[0] = '\0';
+ mac[0] = '\0';
+ script[0] = '\0';
+ ip[0] = '\0';
+ model[0] = '\0';
+ vifname[0] = '\0';
+
+ if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
+ goto skipnic;
+
+ key = list->str;
+ while (key) {
+ char *data;
+ char *nextkey = strchr(key, ',');
+
+ if (!(data = strchr(key, '=')))
+ goto skipnic;
+ data++;
+
+ if (STRPREFIX(key, "mac=")) {
+ int len = nextkey ? (nextkey - data) : 17;
+ if (len > 17)
+ len = 17;
+ strncpy(mac, data, len);
+ mac[len] = '\0';
+ } else if (STRPREFIX(key, "bridge=")) {
+ int len = nextkey ? (nextkey - data) : sizeof(bridge)-1;
+ if (len > (sizeof(bridge)-1))
+ len = sizeof(bridge)-1;
+ strncpy(bridge, data, len);
+ bridge[len] = '\0';
+ } else if (STRPREFIX(key, "script=")) {
+ int len = nextkey ? (nextkey - data) : PATH_MAX-1;
+ if (len > (PATH_MAX-1))
+ len = PATH_MAX-1;
+ strncpy(script, data, len);
+ script[len] = '\0';
+ } else if (STRPREFIX(key, "model=")) {
+ int len = nextkey ? (nextkey - data) : sizeof(model)-1;
+ if (len > (sizeof(model)-1))
+ len = sizeof(model)-1;
+ strncpy(model, data, len);
+ model[len] = '\0';
+ } else if (STRPREFIX(key, "vifname=")) {
+ int len = nextkey ? (nextkey - data) : sizeof(vifname)-1;
+ if (len > (sizeof(vifname)-1))
+ len = sizeof(vifname)-1;
+ strncpy(vifname, data, len);
+ vifname[len] = '\0';
+ } else if (STRPREFIX(key, "ip=")) {
+ int len = nextkey ? (nextkey - data) : 15;
+ if (len > 15)
+ len = 15;
+ strncpy(ip, data, len);
+ ip[len] = '\0';
+ }
+
+ while (nextkey && (nextkey[0] == ',' ||
+ nextkey[0] == ' ' ||
+ nextkey[0] == '\t'))
+ nextkey++;
+ key = nextkey;
+ }
+
+ if (VIR_ALLOC(net) < 0)
+ goto cleanup;
+
+ if (mac[0]) {
+ unsigned int rawmac[6];
+ sscanf(mac, "%02x:%02x:%02x:%02x:%02x:%02x",
+ (unsigned int*)&rawmac[0],
+ (unsigned int*)&rawmac[1],
+ (unsigned int*)&rawmac[2],
+ (unsigned int*)&rawmac[3],
+ (unsigned int*)&rawmac[4],
+ (unsigned int*)&rawmac[5]);
+ net->mac[0] = rawmac[0];
+ net->mac[1] = rawmac[1];
+ net->mac[2] = rawmac[2];
+ net->mac[3] = rawmac[3];
+ net->mac[4] = rawmac[4];
+ net->mac[5] = rawmac[5];
+ }
+
+ if (bridge[0] || STREQ(script, "vif-bridge") ||
+ STREQ(script, "vif-vnic")) {
+ net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
+ } else {
+ net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
+ }
+
+ if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+ if (bridge[0] &&
+ !(net->data.bridge.brname = strdup(bridge)))
+ goto no_memory;
+ if (script[0] &&
+ !(net->data.bridge.script = strdup(script)))
+ goto no_memory;
+ if (ip[0] &&
+ !(net->data.bridge.ipaddr = strdup(ip)))
+ goto no_memory;
+ } else {
+ if (script[0] &&
+ !(net->data.ethernet.script = strdup(script)))
+ goto no_memory;
+ if (ip[0] &&
+ !(net->data.ethernet.ipaddr = strdup(ip)))
+ goto no_memory;
+ }
+ if (model[0] &&
+ !(net->model = strdup(model)))
+ goto no_memory;
+
+ if (vifname[0] &&
+ !(net->ifname = strdup(vifname)))
+ goto no_memory;
+
+ if (VIR_REALLOC_N(def->nets, def->nnets+1) < 0)
+ goto no_memory;
+ def->nets[def->nnets++] = net;
+ net = NULL;
+
+ skipnic:
+ list = list->next;
+ virDomainNetDefFree(net);
+ }
+ }
+
+ list = virConfGetValue(conf, "pci");
+ if (list && list->type == VIR_CONF_LIST) {
+ list = list->list;
+ while (list) {
+ char domain[5];
+ char bus[3];
+ char slot[3];
+ char func[2];
+ char *key, *nextkey;
+ int domainID;
+ int busID;
+ int slotID;
+ int funcID;
+
+ domain[0] = bus[0] = slot[0] = func[0] = '\0';
+
+ if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
+ goto skippci;
+
+ /* pci=['0000:00:1b.0','0000:00:13.0'] */
+ if (!(key = list->str))
+ goto skippci;
+ if (!(nextkey = strchr(key, ':')))
+ goto skippci;
+
+ if ((nextkey - key) > (sizeof(domain)-1))
+ goto skippci;
+
+ strncpy(domain, key, sizeof(domain));
+ domain[sizeof(domain)-1] = '\0';
+
+ key = nextkey + 1;
+ if (!(nextkey = strchr(key, ':')))
+ goto skippci;
+
+ strncpy(bus, key, sizeof(bus));
+ bus[sizeof(bus)-1] = '\0';
+
+ key = nextkey + 1;
+ if (!(nextkey = strchr(key, '.')))
+ goto skippci;
+
+ strncpy(slot, key, sizeof(slot));
+ slot[sizeof(slot)-1] = '\0';
+
+ key = nextkey + 1;
+ if (strlen(key) != 1)
+ goto skippci;
+
+ strncpy(func, key, sizeof(func));
+ func[sizeof(func)-1] = '\0';
+
+ if (virStrToLong_i(domain, NULL, 16, &domainID) < 0)
+ goto skippci;
+ if (virStrToLong_i(bus, NULL, 16, &busID) < 0)
+ goto skippci;
+ if (virStrToLong_i(slot, NULL, 16, &slotID) < 0)
+ goto skippci;
+ if (virStrToLong_i(func, NULL, 16, &funcID) < 0)
+ goto skippci;
+
+ if (VIR_ALLOC(hostdev) < 0)
+ goto cleanup;
+
+ hostdev->managed = 0;
+ hostdev->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
+ hostdev->source.subsys.u.pci.domain = domainID;
+ hostdev->source.subsys.u.pci.bus = busID;
+ hostdev->source.subsys.u.pci.slot = slotID;
+ hostdev->source.subsys.u.pci.function = funcID;
+
+ if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0)
+ goto no_memory;
+ def->hostdevs[def->nhostdevs++] = hostdev;
+ hostdev = NULL;
+
+ skippci:
+ list = list->next;
+ }
+ }
+
+ if (hvm) {
+ if (xenXMConfigGetString(conn, conf, "usbdevice", &str, NULL) < 0)
+ goto cleanup;
+ if (str &&
+ (STREQ(str, "tablet") ||
+ STREQ(str, "mouse"))) {
+ virDomainInputDefPtr input;
+ if (VIR_ALLOC(input) < 0)
+ goto no_memory;
+ input->bus = VIR_DOMAIN_INPUT_BUS_USB;
+ input->type = STREQ(str, "tablet") ?
+ VIR_DOMAIN_INPUT_TYPE_TABLET :
+ VIR_DOMAIN_INPUT_TYPE_MOUSE;
+ if (VIR_ALLOC_N(def->inputs, 1) < 0) {
+ virDomainInputDefFree(input);
+ goto no_memory;
+ }
+ def->inputs[0] = input;
+ def->ninputs = 1;
+ }
+ }
+
+ /* HVM guests, or old PV guests use this config format */
+ if (hvm || priv->xendConfigVersion < 3) {
+ if (xenXMConfigGetBool(conn, conf, "vnc", &val, 0) < 0)
+ goto cleanup;
+
+ if (val) {
+ if (VIR_ALLOC(graphics) < 0)
+ goto no_memory;
+ graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
+ if (xenXMConfigGetBool(conn, conf, "vncunused", &val, 1) < 0)
+ goto cleanup;
+ graphics->data.vnc.autoport = val ? 1 : 0;
+
+ if (!graphics->data.vnc.autoport) {
+ unsigned long vncdisplay;
+ if (xenXMConfigGetULong(conn, conf, "vncdisplay", &vncdisplay, 0) < 0)
+ goto cleanup;
+ graphics->data.vnc.port = (int)vncdisplay + 5900;
+ }
+ if (xenXMConfigCopyStringOpt(conn, conf, "vnclisten", &graphics->data.vnc.listenAddr) < 0)
+ goto cleanup;
+ if (xenXMConfigCopyStringOpt(conn, conf, "vncpasswd", &graphics->data.vnc.passwd) < 0)
+ goto cleanup;
+ if (xenXMConfigCopyStringOpt(conn, conf, "keymap", &graphics->data.vnc.keymap) < 0)
+ goto cleanup;
+
+ if (VIR_ALLOC_N(def->graphics, 1) < 0)
+ goto no_memory;
+ def->graphics[0] = graphics;
+ def->ngraphics = 1;
+ graphics = NULL;
+ } else {
+ if (xenXMConfigGetBool(conn, conf, "sdl", &val, 0) < 0)
+ goto cleanup;
+ if (val) {
+ if (VIR_ALLOC(graphics) < 0)
+ goto no_memory;
+ graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
+ if (xenXMConfigCopyStringOpt(conn, conf, "display", &graphics->data.sdl.display) < 0)
+ goto cleanup;
+ if (xenXMConfigCopyStringOpt(conn, conf, "xauthority", &graphics->data.sdl.xauth) < 0)
+ goto cleanup;
+ if (VIR_ALLOC_N(def->graphics, 1) < 0)
+ goto no_memory;
+ def->graphics[0] = graphics;
+ def->ngraphics = 1;
+ graphics = NULL;
+ }
+ }
+ }
+
+ if (!hvm && def->graphics == NULL) { /* New PV guests use this format */
+ list = virConfGetValue(conf, "vfb");
+ if (list && list->type == VIR_CONF_LIST &&
+ list->list && list->list->type == VIR_CONF_STRING &&
+ list->list->str) {
+ char vfb[MAX_VFB];
+ char *key = vfb;
+ strncpy(vfb, list->list->str, MAX_VFB-1);
+ vfb[MAX_VFB-1] = '\0';
+
+ if (VIR_ALLOC(graphics) < 0)
+ goto no_memory;
+
+ if (strstr(key, "type=sdl"))
+ graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
+ else
+ graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
+
+ while (key) {
+ char *data;
+ char *nextkey = strchr(key, ',');
+ char *end = nextkey;
+ if (nextkey) {
+ *end = '\0';
+ nextkey++;
+ }
+
+ if (!(data = strchr(key, '=')))
+ break;
+
+ if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
+ if (STRPREFIX(key, "vncunused=")) {
+ if (STREQ(key + 10, "1"))
+ graphics->data.vnc.autoport = 1;
+ } else if (STRPREFIX(key, "vnclisten=")) {
+ if (!(graphics->data.vnc.listenAddr = strdup(key + 10)))
+ goto no_memory;
+ } else if (STRPREFIX(key, "vncpasswd=")) {
+ if (!(graphics->data.vnc.passwd = strdup(key + 10)))
+ goto no_memory;
+ } else if (STRPREFIX(key, "keymap=")) {
+ if (!(graphics->data.vnc.keymap = strdup(key + 7)))
+ goto no_memory;
+ } else if (STRPREFIX(key, "vncdisplay=")) {
+ graphics->data.vnc.port = strtol(key+11, NULL, 10) + 5900;
+ }
+ } else {
+ if (STRPREFIX(key, "display=")) {
+ if (!(graphics->data.sdl.display = strdup(key + 8)))
+ goto no_memory;
+ } else if (STRPREFIX(key, "xauthority=")) {
+ if (!(graphics->data.sdl.xauth = strdup(key + 11)))
+ goto no_memory;
+ }
+ }
+
+ while (nextkey && (nextkey[0] == ',' ||
+ nextkey[0] == ' ' ||
+ nextkey[0] == '\t'))
+ nextkey++;
+ key = nextkey;
+ }
+ if (VIR_ALLOC_N(def->graphics, 1) < 0)
+ goto no_memory;
+ def->graphics[0] = graphics;
+ def->ngraphics = 1;
+ graphics = NULL;
+ }
+ }
+
+ if (hvm) {
+ virDomainChrDefPtr chr = NULL;
+
+ if (xenXMConfigGetString(conn, conf, "parallel", &str, NULL) < 0)
+ goto cleanup;
+ if (str && STRNEQ(str, "none") &&
+ !(chr = xenDaemonParseSxprChar(conn, str, NULL)))
+ goto cleanup;
+
+ if (chr) {
+ if (VIR_ALLOC_N(def->parallels, 1) < 0) {
+ virDomainChrDefFree(chr);
+ goto no_memory;
+ }
+ def->parallels[0] = chr;
+ def->nparallels++;
+ chr = NULL;
+ }
+
+ if (xenXMConfigGetString(conn, conf, "serial", &str, NULL) < 0)
+ goto cleanup;
+ if (str && STRNEQ(str, "none") &&
+ !(chr = xenDaemonParseSxprChar(conn, str, NULL)))
+ goto cleanup;
+
+ if (chr) {
+ if (VIR_ALLOC_N(def->serials, 1) < 0) {
+ virDomainChrDefFree(chr);
+ goto no_memory;
+ }
+ def->serials[0] = chr;
+ def->nserials++;
+ }
+ } else {
+ if (!(def->console = xenDaemonParseSxprChar(conn, "pty", NULL)))
+ goto cleanup;
+ }
+
+ if (hvm) {
+ if (xenXMConfigGetString(conn, conf, "soundhw", &str, NULL) < 0)
+ goto cleanup;
+
+ if (str &&
+ xenDaemonParseSxprSound(conn, def, str) < 0)
+ goto cleanup;
+ }
+
+ return def;
+
+no_memory:
+ virReportOOMError(conn);
+ /* fallthrough */
+cleanup:
+ virDomainGraphicsDefFree(graphics);
+ virDomainNetDefFree(net);
+ virDomainDiskDefFree(disk);
+ virDomainDefFree(def);
+ return NULL;
+}
+
+
+/*
+ * Turn a config record into a lump of XML describing the
+ * domain, suitable for later feeding for virDomainCreateXML
+ */
+char *xenXMDomainDumpXML(virDomainPtr domain, int flags) {
+ xenUnifiedPrivatePtr priv;
+ const char *filename;
+ xenXMConfCachePtr entry;
+ char *ret = NULL;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(NULL);
+ }
+ if (domain->id != -1)
+ return (NULL);
+
+ priv = domain->conn->privateData;
+ xenUnifiedLock(priv);
+
+ if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
+ goto cleanup;
+
+ if (!(entry = virHashLookup(priv->configCache, filename)))
+ goto cleanup;
+
+ ret = virDomainDefFormat(domain->conn, entry->def, flags);
+
+cleanup:
+ xenUnifiedUnlock(priv);
+ return ret;
+}
+
+
+/*
+ * Update amount of memory in the config file
+ */
+int xenXMDomainSetMemory(virDomainPtr domain, unsigned long memory) {
+ xenUnifiedPrivatePtr priv;
+ const char *filename;
+ xenXMConfCachePtr entry;
+ int ret = -1;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return (-1);
+ }
+ if (domain->conn->flags & VIR_CONNECT_RO)
+ return (-1);
+ if (domain->id != -1)
+ return (-1);
+ if (memory < 1024 * MIN_XEN_GUEST_SIZE)
+ return (-1);
+
+ priv = domain->conn->privateData;
+ xenUnifiedLock(priv);
+
+ if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
+ goto cleanup;
+
+ if (!(entry = virHashLookup(priv->configCache, filename)))
+ goto cleanup;
+
+ entry->def->memory = memory;
+ if (entry->def->memory > entry->def->maxmem)
+ entry->def->memory = entry->def->maxmem;
+
+ /* If this fails, should we try to undo our changes to the
+ * in-memory representation of the config file. I say not!
+ */
+ if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
+ goto cleanup;
+ ret = 0;
+
+cleanup:
+ xenUnifiedUnlock(priv);
+ return ret;
+}
+
+/*
+ * Update maximum memory limit in config
+ */
+int xenXMDomainSetMaxMemory(virDomainPtr domain, unsigned long memory) {
+ xenUnifiedPrivatePtr priv;
+ const char *filename;
+ xenXMConfCachePtr entry;
+ int ret = -1;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return (-1);
+ }
+ if (domain->conn->flags & VIR_CONNECT_RO)
+ return (-1);
+ if (domain->id != -1)
+ return (-1);
+
+ priv = domain->conn->privateData;
+ xenUnifiedLock(priv);
+
+ if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
+ goto cleanup;
+
+ if (!(entry = virHashLookup(priv->configCache, filename)))
+ goto cleanup;
+
+ entry->def->maxmem = memory;
+ if (entry->def->memory > entry->def->maxmem)
+ entry->def->memory = entry->def->maxmem;
+
+ /* If this fails, should we try to undo our changes to the
+ * in-memory representation of the config file. I say not!
+ */
+ if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
+ goto cleanup;
+ ret = 0;
+
+cleanup:
+ xenUnifiedUnlock(priv);
+ return ret;
+}
+
+/*
+ * Get max memory limit from config
+ */
+unsigned long xenXMDomainGetMaxMemory(virDomainPtr domain) {
+ xenUnifiedPrivatePtr priv;
+ const char *filename;
+ xenXMConfCachePtr entry;
+ unsigned long ret = 0;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return (0);
+ }
+ if (domain->id != -1)
+ return (0);
+
+ priv = domain->conn->privateData;
+ xenUnifiedLock(priv);
+
+ if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
+ goto cleanup;
+
+ if (!(entry = virHashLookup(priv->configCache, filename)))
+ goto cleanup;
+
+ ret = entry->def->maxmem;
+
+cleanup:
+ xenUnifiedUnlock(priv);
+ return ret;
+}
+
+/*
+ * Set the VCPU count in config
+ */
+int xenXMDomainSetVcpus(virDomainPtr domain, unsigned int vcpus) {
+ xenUnifiedPrivatePtr priv;
+ const char *filename;
+ xenXMConfCachePtr entry;
+ int ret = -1;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return (-1);
+ }
+ if (domain->conn->flags & VIR_CONNECT_RO)
+ return (-1);
+ if (domain->id != -1)
+ return (-1);
+
+ priv = domain->conn->privateData;
+ xenUnifiedLock(priv);
+
+ if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
+ goto cleanup;
+
+ if (!(entry = virHashLookup(priv->configCache, filename)))
+ goto cleanup;
+
+ entry->def->vcpus = vcpus;
+
+ /* If this fails, should we try to undo our changes to the
+ * in-memory representation of the config file. I say not!
+ */
+ if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
+ goto cleanup;
+ ret = 0;
+
+cleanup:
+ xenUnifiedUnlock(priv);
+ return ret;
+}
+
+/**
+ * xenXMDomainPinVcpu:
+ * @domain: pointer to domain object
+ * @vcpu: virtual CPU number (reserved)
+ * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes)
+ * @maplen: length of cpumap in bytes
+ *
+ * Set the vcpu affinity in config
+ *
+ * Returns 0 for success; -1 (with errno) on error
+ */
+int xenXMDomainPinVcpu(virDomainPtr domain,
+ unsigned int vcpu ATTRIBUTE_UNUSED,
+ unsigned char *cpumap, int maplen)
+{
+ xenUnifiedPrivatePtr priv;
+ const char *filename;
+ xenXMConfCachePtr entry;
+ virBuffer mapbuf = VIR_BUFFER_INITIALIZER;
+ char *mapstr = NULL, *mapsave = NULL;
+ int i, j, n, comma = 0;
+ int ret = -1;
+ char *cpuset = NULL;
+ int maxcpu = XEN_MAX_PHYSICAL_CPU;
+
+ if (domain == NULL || domain->conn == NULL || domain->name == NULL
+ || cpumap == NULL || maplen < 1 || maplen > (int)sizeof(cpumap_t)) {
+ xenXMError(domain ? domain->conn : NULL, VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return -1;
+ }
+ if (domain->conn->flags & VIR_CONNECT_RO) {
+ xenXMError (domain->conn, VIR_ERR_INVALID_ARG,
+ "%s", _("read only connection"));
+ return -1;
+ }
+ if (domain->id != -1) {
+ xenXMError (domain->conn, VIR_ERR_INVALID_ARG,
+ "%s", _("not inactive domain"));
+ return -1;
+ }
+
+ priv = domain->conn->privateData;
+ xenUnifiedLock(priv);
+
+ if (!(filename = virHashLookup(priv->nameConfigMap, domain->name))) {
+ xenXMError (domain->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("virHashLookup"));
+ goto cleanup;
+ }
+ if (!(entry = virHashLookup(priv->configCache, filename))) {
+ xenXMError (domain->conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("can't retrieve config file for domain"));
+ goto cleanup;
+ }
+
+ /* from bit map, build character string of mapped CPU numbers */
+ for (i = 0; i < maplen; i++)
+ for (j = 0; j < 8; j++)
+ if ((cpumap[i] & (1 << j))) {
+ n = i*8 + j;
+
+ if (comma)
+ virBufferAddLit (&mapbuf, ",");
+ comma = 1;
+
+ virBufferVSprintf (&mapbuf, "%d", n);
+ }
+
+ if (virBufferError(&mapbuf)) {
+ virReportOOMError(domain->conn);
+ goto cleanup;
+ }
+
+ mapstr = virBufferContentAndReset(&mapbuf);
+ mapsave = mapstr;
+
+ if (VIR_ALLOC_N(cpuset, maxcpu) < 0) {
+ virReportOOMError(domain->conn);
+ goto cleanup;
+ }
+ if (virDomainCpuSetParse(domain->conn,
+ (const char **)&mapstr, 0,
+ cpuset, maxcpu) < 0)
+ goto cleanup;
+
+ VIR_FREE(entry->def->cpumask);
+ entry->def->cpumask = cpuset;
+ entry->def->cpumasklen = maxcpu;
+ cpuset = NULL;
+
+ if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(mapsave);
+ VIR_FREE(cpuset);
+ xenUnifiedUnlock(priv);
+ return (ret);
+}
+
+/*
+ * Find an inactive domain based on its name
+ */
+virDomainPtr xenXMDomainLookupByName(virConnectPtr conn, const char *domname) {
+ xenUnifiedPrivatePtr priv;
+ const char *filename;
+ xenXMConfCachePtr entry;
+ virDomainPtr ret = NULL;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (NULL);
+ }
+ if (domname == NULL) {
+ xenXMError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (NULL);
+ }
+
+ priv = conn->privateData;
+ xenUnifiedLock(priv);
+
+ if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
+ goto cleanup;
+
+ if (!(filename = virHashLookup(priv->nameConfigMap, domname)))
+ goto cleanup;
+
+ if (!(entry = virHashLookup(priv->configCache, filename)))
+ goto cleanup;
+
+ if (!(ret = virGetDomain(conn, domname, entry->def->uuid)))
+ goto cleanup;
+
+ /* Ensure its marked inactive, because may be cached
+ handle to a previously active domain */
+ ret->id = -1;
+
+cleanup:
+ xenUnifiedUnlock(priv);
+ return (ret);
+}
+
+
+/*
+ * Hash table iterator to search for a domain based on UUID
+ */
+static int xenXMDomainSearchForUUID(const void *payload, const char *name ATTRIBUTE_UNUSED, const void *data) {
+ const unsigned char *wantuuid = (const unsigned char *)data;
+ const xenXMConfCachePtr entry = (const xenXMConfCachePtr)payload;
+
+ if (!memcmp(entry->def->uuid, wantuuid, VIR_UUID_BUFLEN))
+ return (1);
+
+ return (0);
+}
+
+/*
+ * Find an inactive domain based on its UUID
+ */
+virDomainPtr xenXMDomainLookupByUUID(virConnectPtr conn,
+ const unsigned char *uuid) {
+ xenUnifiedPrivatePtr priv;
+ xenXMConfCachePtr entry;
+ virDomainPtr ret = NULL;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (NULL);
+ }
+ if (uuid == NULL) {
+ xenXMError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (NULL);
+ }
+
+ priv = conn->privateData;
+ xenUnifiedLock(priv);
+
+ if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
+ goto cleanup;
+
+ if (!(entry = virHashSearch(priv->configCache, xenXMDomainSearchForUUID, (const void *)uuid)))
+ goto cleanup;
+
+ if (!(ret = virGetDomain(conn, entry->def->name, uuid)))
+ goto cleanup;
+
+ /* Ensure its marked inactive, because may be cached
+ handle to a previously active domain */
+ ret->id = -1;
+
+cleanup:
+ xenUnifiedUnlock(priv);
+ return (ret);
+}
+
+
+/*
+ * Start a domain from an existing defined config file
+ */
+int xenXMDomainCreate(virDomainPtr domain) {
+ char *sexpr;
+ int ret = -1;
+ xenUnifiedPrivatePtr priv;
+ const char *filename;
+ xenXMConfCachePtr entry;
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+ if (domain->id != -1)
+ return (-1);
+
+ xenUnifiedLock(priv);
+
+ if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
+ goto error;
+
+ if (!(entry = virHashLookup(priv->configCache, filename)))
+ goto error;
+
+ if (!(sexpr = xenDaemonFormatSxpr(domain->conn, entry->def, priv->xendConfigVersion)))
+ goto error;
+
+ ret = xenDaemonDomainCreateXML(domain->conn, sexpr);
+ VIR_FREE(sexpr);
+ if (ret != 0)
+ goto error;
+
+ if ((ret = xenDaemonDomainLookupByName_ids(domain->conn, domain->name,
+ entry->def->uuid)) < 0)
+ goto error;
+ domain->id = ret;
+
+ if (xend_wait_for_devices(domain->conn, domain->name) < 0)
+ goto error;
+
+ if (xenDaemonDomainResume(domain) < 0)
+ goto error;
+
+ xenUnifiedUnlock(priv);
+ return (0);
+
+ error:
+ if (domain->id != -1) {
+ xenDaemonDomainDestroy(domain);
+ domain->id = -1;
+ }
+ xenUnifiedUnlock(priv);
+ return (-1);
+}
+
+
+static
+int xenXMConfigSetInt(virConfPtr conf, const char *setting, long l) {
+ virConfValuePtr value = NULL;
+
+ if (VIR_ALLOC(value) < 0)
+ return -1;
+
+ value->type = VIR_CONF_LONG;
+ value->next = NULL;
+ value->l = l;
+
+ return virConfSetValue(conf, setting, value);
+}
+
+
+static
+int xenXMConfigSetString(virConfPtr conf, const char *setting, const char *str) {
+ virConfValuePtr value = NULL;
+
+ if (VIR_ALLOC(value) < 0)
+ return -1;
+
+ value->type = VIR_CONF_STRING;
+ value->next = NULL;
+ if (!(value->str = strdup(str))) {
+ VIR_FREE(value);
+ return -1;
+ }
+
+ return virConfSetValue(conf, setting, value);
+}
+
+
+static int xenXMDomainConfigFormatDisk(virConnectPtr conn,
+ virConfValuePtr list,
+ virDomainDiskDefPtr disk,
+ int hvm,
+ int xendConfigVersion)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ virConfValuePtr val, tmp;
+ char *str;
+
+ if(disk->src) {
+ if (disk->driverName) {
+ virBufferVSprintf(&buf, "%s:", disk->driverName);
+ if (STREQ(disk->driverName, "tap"))
+ virBufferVSprintf(&buf, "%s:", disk->driverType ? disk->driverType : "aio");
+ } else {
+ virBufferVSprintf(&buf, "%s:",
+ disk->type == VIR_DOMAIN_DISK_TYPE_FILE ?
+ "file" : "phy");
+ }
+ virBufferVSprintf(&buf, "%s", disk->src);
+ }
+ virBufferAddLit(&buf, ",");
+ if (hvm && xendConfigVersion == 1)
+ virBufferAddLit(&buf, "ioemu:");
+
+ virBufferVSprintf(&buf, "%s", disk->dst);
+ if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
+ virBufferAddLit(&buf, ":cdrom");
+
+ if (disk->readonly)
+ virBufferAddLit(&buf, ",r");
+ else if (disk->shared)
+ virBufferAddLit(&buf, ",!");
+ else
+ virBufferAddLit(&buf, ",w");
+
+ if (virBufferError(&buf)) {
+ virReportOOMError(conn);
+ return -1;
+ }
+
+ if (VIR_ALLOC(val) < 0) {
+ virReportOOMError(conn);
+ goto cleanup;
+ }
+
+ val->type = VIR_CONF_STRING;
+ val->str = virBufferContentAndReset(&buf);
+ tmp = list->list;
+ while (tmp && tmp->next)
+ tmp = tmp->next;
+ if (tmp)
+ tmp->next = val;
+ else
+ list->list = val;
+
+ return 0;
+
+cleanup:
+ str = virBufferContentAndReset(&buf);
+ VIR_FREE(str);
+ return -1;
+}
+
+static int xenXMDomainConfigFormatNet(virConnectPtr conn,
+ virConfValuePtr list,
+ virDomainNetDefPtr net,
+ int hvm)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ virConfValuePtr val, tmp;
+ char *str;
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ virBufferVSprintf(&buf, "mac=%02x:%02x:%02x:%02x:%02x:%02x",
+ net->mac[0], net->mac[1],
+ net->mac[2], net->mac[3],
+ net->mac[4], net->mac[5]);
+
+ switch (net->type) {
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ virBufferVSprintf(&buf, ",bridge=%s", net->data.bridge.brname);
+ if (net->data.bridge.ipaddr)
+ virBufferVSprintf(&buf, ",ip=%s", net->data.bridge.ipaddr);
+ virBufferVSprintf(&buf, ",script=%s", DEFAULT_VIF_SCRIPT);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ if (net->data.ethernet.script)
+ virBufferVSprintf(&buf, ",script=%s", net->data.ethernet.script);
+ if (net->data.ethernet.ipaddr)
+ virBufferVSprintf(&buf, ",ip=%s", net->data.ethernet.ipaddr);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ {
+ virNetworkPtr network = virNetworkLookupByName(conn, net->data.network.name);
+ char *bridge;
+ if (!network) {
+ xenXMError(conn, VIR_ERR_NO_NETWORK, "%s",
+ net->data.network.name);
+ return -1;
+ }
+ bridge = virNetworkGetBridgeName(network);
+ virNetworkFree(network);
+ if (!bridge) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("network %s is not active"),
+ net->data.network.name);
+ return -1;
+ }
+
+ virBufferVSprintf(&buf, ",bridge=%s", bridge);
+ virBufferVSprintf(&buf, ",script=%s", DEFAULT_VIF_SCRIPT);
+ }
+ break;
+
+ default:
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported network type %d"),
+ net->type);
+ goto cleanup;
+ }
+
+ if (hvm && priv->xendConfigVersion <= XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU)
+ virBufferAddLit(&buf, ",type=ioemu");
+
+ if (net->model)
+ virBufferVSprintf(&buf, ",model=%s",
+ net->model);
+
+ if (net->ifname)
+ virBufferVSprintf(&buf, ",vifname=%s",
+ net->ifname);
+
+ if (virBufferError(&buf))
+ goto cleanup;
+
+ if (VIR_ALLOC(val) < 0) {
+ virReportOOMError(conn);
+ goto cleanup;
+ }
+
+ val->type = VIR_CONF_STRING;
+ val->str = virBufferContentAndReset(&buf);
+ tmp = list->list;
+ while (tmp && tmp->next)
+ tmp = tmp->next;
+ if (tmp)
+ tmp->next = val;
+ else
+ list->list = val;
+
+ return 0;
+
+cleanup:
+ str = virBufferContentAndReset(&buf);
+ VIR_FREE(str);
+ return -1;
+}
+
+
+
+static int
+xenXMDomainConfigFormatPCI(virConnectPtr conn,
+ virConfPtr conf,
+ virDomainDefPtr def)
+{
+
+ virConfValuePtr pciVal = NULL;
+ int hasPCI = 0;
+ int i;
+
+ for (i = 0 ; i < def->nhostdevs ; i++)
+ if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+ def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+ hasPCI = 1;
+
+ if (!hasPCI)
+ return 0;
+
+ if (VIR_ALLOC(pciVal) < 0)
+ return -1;
+
+ pciVal->type = VIR_CONF_LIST;
+ pciVal->list = NULL;
+
+ for (i = 0 ; i < def->nhostdevs ; i++) {
+ if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+ def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
+ virConfValuePtr val, tmp;
+ char *buf;
+
+ if (virAsprintf(&buf, "%04x:%02x:%02x.%x",
+ def->hostdevs[i]->source.subsys.u.pci.domain,
+ def->hostdevs[i]->source.subsys.u.pci.bus,
+ def->hostdevs[i]->source.subsys.u.pci.slot,
+ def->hostdevs[i]->source.subsys.u.pci.function) < 0)
+ goto error;
+
+ if (VIR_ALLOC(val) < 0) {
+ VIR_FREE(buf);
+ virReportOOMError(conn);
+ goto error;
+ }
+ val->type = VIR_CONF_STRING;
+ val->str = buf;
+ tmp = pciVal->list;
+ while (tmp && tmp->next)
+ tmp = tmp->next;
+ if (tmp)
+ tmp->next = val;
+ else
+ pciVal->list = val;
+ }
+ }
+
+ if (pciVal->list != NULL) {
+ int ret = virConfSetValue(conf, "pci", pciVal);
+ pciVal = NULL;
+ if (ret < 0)
+ return -1;
+ }
+ VIR_FREE(pciVal);
+
+ return 0;
+
+error:
+ virConfFreeValue(pciVal);
+ return -1;
+}
+
+
+virConfPtr xenXMDomainConfigFormat(virConnectPtr conn,
+ virDomainDefPtr def) {
+ virConfPtr conf = NULL;
+ int hvm = 0, i;
+ xenUnifiedPrivatePtr priv;
+ char *cpus = NULL;
+ const char *lifecycle;
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ virConfValuePtr diskVal = NULL;
+ virConfValuePtr netVal = NULL;
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ if (!(conf = virConfNew()))
+ goto cleanup;
+
+
+ if (xenXMConfigSetString(conf, "name", def->name) < 0)
+ goto no_memory;
+
+ virUUIDFormat(def->uuid, uuid);
+ if (xenXMConfigSetString(conf, "uuid", uuid) < 0)
+ goto no_memory;
+
+ if (xenXMConfigSetInt(conf, "maxmem", def->maxmem / 1024) < 0)
+ goto no_memory;
+
+ if (xenXMConfigSetInt(conf, "memory", def->memory / 1024) < 0)
+ goto no_memory;
+
+ if (xenXMConfigSetInt(conf, "vcpus", def->vcpus) < 0)
+ goto no_memory;
+
+ if (def->cpumask &&
+ !(cpus = virDomainCpuSetFormat(conn, def->cpumask, def->cpumasklen)) < 0)
+ goto cleanup;
+
+ if (cpus &&
+ xenXMConfigSetString(conf, "cpus", cpus) < 0)
+ goto no_memory;
+ VIR_FREE(cpus);
+
+ hvm = STREQ(def->os.type, "hvm") ? 1 : 0;
+
+ if (hvm) {
+ char boot[VIR_DOMAIN_BOOT_LAST+1];
+ if (xenXMConfigSetString(conf, "builder", "hvm") < 0)
+ goto no_memory;
+
+ if (def->os.loader &&
+ xenXMConfigSetString(conf, "kernel", def->os.loader) < 0)
+ goto no_memory;
+
+ for (i = 0 ; i < def->os.nBootDevs ; i++) {
+ switch (def->os.bootDevs[i]) {
+ case VIR_DOMAIN_BOOT_FLOPPY:
+ boot[i] = 'a';
+ break;
+ case VIR_DOMAIN_BOOT_CDROM:
+ boot[i] = 'd';
+ break;
+ case VIR_DOMAIN_BOOT_NET:
+ boot[i] = 'n';
+ break;
+ case VIR_DOMAIN_BOOT_DISK:
+ default:
+ boot[i] = 'c';
+ break;
+ }
+ }
+ if (!def->os.nBootDevs) {
+ boot[0] = 'c';
+ boot[1] = '\0';
+ } else {
+ boot[def->os.nBootDevs] = '\0';
+ }
+
+ if (xenXMConfigSetString(conf, "boot", boot) < 0)
+ goto no_memory;
+
+ if (xenXMConfigSetInt(conf, "pae",
+ (def->features &
+ (1 << VIR_DOMAIN_FEATURE_PAE)) ? 1 : 0) < 0)
+ goto no_memory;
+
+ if (xenXMConfigSetInt(conf, "acpi",
+ (def->features &
+ (1 << VIR_DOMAIN_FEATURE_ACPI)) ? 1 : 0) < 0)
+ goto no_memory;
+
+ if (xenXMConfigSetInt(conf, "apic",
+ (def->features &
+ (1 << VIR_DOMAIN_FEATURE_APIC)) ? 1 : 0) < 0)
+ goto no_memory;
+
+
+ if (xenXMConfigSetInt(conf, "localtime", def->localtime ? 1 : 0) < 0)
+ goto no_memory;
+
+ if (priv->xendConfigVersion == 1) {
+ for (i = 0 ; i < def->ndisks ; i++) {
+ if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
+ def->disks[i]->dst &&
+ STREQ(def->disks[i]->dst, "hdc") &&
+ def->disks[i]->src) {
+ if (xenXMConfigSetString(conf, "cdrom",
+ def->disks[i]->src) < 0)
+ goto no_memory;
+ break;
+ }
+ }
+ }
+
+ /* XXX floppy disks */
+ } else {
+ if (def->os.bootloader &&
+ xenXMConfigSetString(conf, "bootloader", def->os.bootloader) < 0)
+ goto no_memory;
+ if (def->os.bootloaderArgs &&
+ xenXMConfigSetString(conf, "bootloader_args", def->os.bootloaderArgs) < 0)
+ goto no_memory;
+ if (def->os.kernel &&
+ xenXMConfigSetString(conf, "kernel", def->os.kernel) < 0)
+ goto no_memory;
+ if (def->os.initrd &&
+ xenXMConfigSetString(conf, "ramdisk", def->os.initrd) < 0)
+ goto no_memory;
+ if (def->os.cmdline &&
+ xenXMConfigSetString(conf, "extra", def->os.cmdline) < 0)
+ goto no_memory;
+
+ }
+
+ if (!(lifecycle = virDomainLifecycleTypeToString(def->onPoweroff))) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected lifecycle action %d"), def->onPoweroff);
+ goto cleanup;
+ }
+ if (xenXMConfigSetString(conf, "on_poweroff", lifecycle) < 0)
+ goto no_memory;
+
+
+ if (!(lifecycle = virDomainLifecycleTypeToString(def->onReboot))) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected lifecycle action %d"), def->onReboot);
+ goto cleanup;
+ }
+ if (xenXMConfigSetString(conf, "on_reboot", lifecycle) < 0)
+ goto no_memory;
+
+
+ if (!(lifecycle = virDomainLifecycleTypeToString(def->onCrash))) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected lifecycle action %d"), def->onCrash);
+ goto cleanup;
+ }
+ if (xenXMConfigSetString(conf, "on_crash", lifecycle) < 0)
+ goto no_memory;
+
+
+
+ if (hvm) {
+ if (def->emulator &&
+ xenXMConfigSetString(conf, "device_model", def->emulator) < 0)
+ goto no_memory;
+
+ for (i = 0 ; i < def->ninputs ; i++) {
+ if (def->inputs[i]->bus == VIR_DOMAIN_INPUT_BUS_USB) {
+ if (xenXMConfigSetInt(conf, "usb", 1) < 0)
+ goto no_memory;
+ if (xenXMConfigSetString(conf, "usbdevice",
+ def->inputs[i]->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
+ "mouse" : "tablet") < 0)
+ goto no_memory;
+ break;
+ }
+ }
+ }
+
+ if (def->ngraphics == 1) {
+ if (priv->xendConfigVersion < (hvm ? 4 : XEND_CONFIG_MIN_VERS_PVFB_NEWCONF)) {
+ if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
+ if (xenXMConfigSetInt(conf, "sdl", 1) < 0)
+ goto no_memory;
+ if (xenXMConfigSetInt(conf, "vnc", 0) < 0)
+ goto no_memory;
+ if (def->graphics[0]->data.sdl.display &&
+ xenXMConfigSetString(conf, "display",
+ def->graphics[0]->data.sdl.display) < 0)
+ goto no_memory;
+ if (def->graphics[0]->data.sdl.xauth &&
+ xenXMConfigSetString(conf, "xauthority",
+ def->graphics[0]->data.sdl.xauth) < 0)
+ goto no_memory;
+ } else {
+ if (xenXMConfigSetInt(conf, "sdl", 0) < 0)
+ goto no_memory;
+ if (xenXMConfigSetInt(conf, "vnc", 1) < 0)
+ goto no_memory;
+ if (xenXMConfigSetInt(conf, "vncunused",
+ def->graphics[0]->data.vnc.autoport ? 1 : 0) < 0)
+ goto no_memory;
+ if (!def->graphics[0]->data.vnc.autoport &&
+ xenXMConfigSetInt(conf, "vncdisplay",
+ def->graphics[0]->data.vnc.port - 5900) < 0)
+ goto no_memory;
+ if (def->graphics[0]->data.vnc.listenAddr &&
+ xenXMConfigSetString(conf, "vnclisten",
+ def->graphics[0]->data.vnc.listenAddr) < 0)
+ goto no_memory;
+ if (def->graphics[0]->data.vnc.passwd &&
+ xenXMConfigSetString(conf, "vncpasswd",
+ def->graphics[0]->data.vnc.passwd) < 0)
+ goto no_memory;
+ if (def->graphics[0]->data.vnc.keymap &&
+ xenXMConfigSetString(conf, "keymap",
+ def->graphics[0]->data.vnc.keymap) < 0)
+ goto no_memory;
+ }
+ } else {
+ virConfValuePtr vfb, disp;
+ char *vfbstr = NULL;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
+ virBufferAddLit(&buf, "type=sdl");
+ if (def->graphics[0]->data.sdl.display)
+ virBufferVSprintf(&buf, ",display=%s",
+ def->graphics[0]->data.sdl.display);
+ if (def->graphics[0]->data.sdl.xauth)
+ virBufferVSprintf(&buf, ",xauthority=%s",
+ def->graphics[0]->data.sdl.xauth);
+ } else {
+ virBufferAddLit(&buf, "type=vnc");
+ virBufferVSprintf(&buf, ",vncunused=%d",
+ def->graphics[0]->data.vnc.autoport ? 1 : 0);
+ if (!def->graphics[0]->data.vnc.autoport)
+ virBufferVSprintf(&buf, ",vncdisplay=%d",
+ def->graphics[0]->data.vnc.port - 5900);
+ if (def->graphics[0]->data.vnc.listenAddr)
+ virBufferVSprintf(&buf, ",vnclisten=%s",
+ def->graphics[0]->data.vnc.listenAddr);
+ if (def->graphics[0]->data.vnc.passwd)
+ virBufferVSprintf(&buf, ",vncpasswd=%s",
+ def->graphics[0]->data.vnc.passwd);
+ if (def->graphics[0]->data.vnc.keymap)
+ virBufferVSprintf(&buf, ",keymap=%s",
+ def->graphics[0]->data.vnc.keymap);
+ }
+ if (virBufferError(&buf))
+ goto no_memory;
+
+ vfbstr = virBufferContentAndReset(&buf);
+
+ if (VIR_ALLOC(vfb) < 0) {
+ VIR_FREE(vfbstr);
+ goto no_memory;
+ }
+
+ if (VIR_ALLOC(disp) < 0) {
+ VIR_FREE(vfb);
+ VIR_FREE(vfbstr);
+ goto no_memory;
+ }
+
+ vfb->type = VIR_CONF_LIST;
+ vfb->list = disp;
+ disp->type = VIR_CONF_STRING;
+ disp->str = vfbstr;
+
+ if (virConfSetValue(conf, "vfb", vfb) < 0)
+ goto no_memory;
+ }
+ }
+
+ /* analyze of the devices */
+ if (VIR_ALLOC(diskVal) < 0)
+ goto no_memory;
+ diskVal->type = VIR_CONF_LIST;
+ diskVal->list = NULL;
+
+ for (i = 0 ; i < def->ndisks ; i++) {
+ if (priv->xendConfigVersion == 1 &&
+ def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
+ def->disks[i]->dst &&
+ STREQ(def->disks[i]->dst, "hdc")) {
+ continue;
+ }
+ if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
+ continue;
+
+ if (xenXMDomainConfigFormatDisk(conn, diskVal, def->disks[i],
+ hvm, priv->xendConfigVersion) < 0)
+ goto cleanup;
+ }
+ if (diskVal->list != NULL) {
+ int ret = virConfSetValue(conf, "disk", diskVal);
+ diskVal = NULL;
+ if (ret < 0)
+ goto no_memory;
+ }
+ VIR_FREE(diskVal);
+
+ if (VIR_ALLOC(netVal) < 0)
+ goto no_memory;
+ netVal->type = VIR_CONF_LIST;
+ netVal->list = NULL;
+
+ for (i = 0 ; i < def->nnets ; i++) {
+ if (xenXMDomainConfigFormatNet(conn, netVal,
+ def->nets[i],
+ hvm) < 0)
+ goto cleanup;
+ }
+ if (netVal->list != NULL) {
+ int ret = virConfSetValue(conf, "vif", netVal);
+ netVal = NULL;
+ if (ret < 0)
+ goto no_memory;
+ }
+ VIR_FREE(netVal);
+
+ if (xenXMDomainConfigFormatPCI(conn, conf, def) < 0)
+ goto cleanup;
+
+ if (hvm) {
+ if (def->nparallels) {
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ char *str;
+ int ret;
+
+ ret = xenDaemonFormatSxprChr(conn, def->parallels[0], &buf);
+ str = virBufferContentAndReset(&buf);
+ if (ret == 0)
+ ret = xenXMConfigSetString(conf, "parallel", str);
+ VIR_FREE(str);
+ if (ret < 0)
+ goto no_memory;
+ } else {
+ if (xenXMConfigSetString(conf, "parallel", "none") < 0)
+ goto no_memory;
+ }
+
+ if (def->nserials) {
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ char *str;
+ int ret;
+
+ ret = xenDaemonFormatSxprChr(conn, def->serials[0], &buf);
+ str = virBufferContentAndReset(&buf);
+ if (ret == 0)
+ ret = xenXMConfigSetString(conf, "serial", str);
+ VIR_FREE(str);
+ if (ret < 0)
+ goto no_memory;
+ } else {
+ if (xenXMConfigSetString(conf, "serial", "none") < 0)
+ goto no_memory;
+ }
+
+
+ if (def->sounds) {
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ char *str = NULL;
+ int ret = xenDaemonFormatSxprSound(conn,
+ def,
+ &buf);
+ str = virBufferContentAndReset(&buf);
+ if (ret == 0)
+ ret = xenXMConfigSetString(conf, "soundhw", str);
+
+ VIR_FREE(str);
+ if (ret < 0)
+ goto no_memory;
+ }
+ }
+
+ return conf;
+
+no_memory:
+ virReportOOMError(conn);
+
+cleanup:
+ virConfFreeValue(diskVal);
+ virConfFreeValue(netVal);
+ VIR_FREE(cpus);
+ if (conf)
+ virConfFree(conf);
+ return (NULL);
+}
+
+/*
+ * Create a config file for a domain, based on an XML
+ * document describing its config
+ */
+virDomainPtr xenXMDomainDefineXML(virConnectPtr conn, const char *xml) {
+ virDomainPtr ret;
+ virDomainPtr olddomain;
+ char filename[PATH_MAX];
+ const char * oldfilename;
+ virDomainDefPtr def = NULL;
+ xenXMConfCachePtr entry = NULL;
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (NULL);
+ }
+ if (xml == NULL) {
+ xenXMError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return (NULL);
+ }
+ if (conn->flags & VIR_CONNECT_RO)
+ return (NULL);
+
+ xenUnifiedLock(priv);
+
+ if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0) {
+ xenUnifiedUnlock(priv);
+ return (NULL);
+ }
+
+ if (!(def = virDomainDefParseString(conn, priv->caps, xml,
+ VIR_DOMAIN_XML_INACTIVE))) {
+ xenUnifiedUnlock(priv);
+ return (NULL);
+ }
+
+ if (virHashLookup(priv->nameConfigMap, def->name)) {
+ /* domain exists, we will overwrite it */
+
+ if (!(oldfilename = (char *)virHashLookup(priv->nameConfigMap, def->name))) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("can't retrieve config filename for domain to overwrite"));
+ goto error;
+ }
+
+ if (!(entry = virHashLookup(priv->configCache, oldfilename))) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("can't retrieve config entry for domain to overwrite"));
+ goto error;
+ }
+
+ /* XXX wtf.com is this line for - it appears to be amemory leak */
+ if (!(olddomain = virGetDomain(conn, def->name, entry->def->uuid)))
+ goto error;
+
+ /* Remove the name -> filename mapping */
+ if (virHashRemoveEntry(priv->nameConfigMap, def->name, NULL) < 0) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to remove old domain from config map"));
+ goto error;
+ }
+
+ /* Remove the config record itself */
+ if (virHashRemoveEntry(priv->configCache, oldfilename, xenXMConfigFree) < 0) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to remove old domain from config map"));
+ goto error;
+ }
+
+ entry = NULL;
+ }
+
+ if ((strlen(priv->configDir) + 1 + strlen(def->name) + 1) > PATH_MAX) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("config file name is too long"));
+ goto error;
+ }
+
+ strcpy(filename, priv->configDir);
+ strcat(filename, "/");
+ strcat(filename, def->name);
+
+ if (xenXMConfigSaveFile(conn, filename, def) < 0)
+ goto error;
+
+ if (VIR_ALLOC(entry) < 0) {
+ virReportOOMError(conn);
+ goto error;
+ }
+
+ if ((entry->refreshedAt = time(NULL)) == ((time_t)-1)) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unable to get current time"));
+ goto error;
+ }
+
+ memmove(entry->filename, filename, PATH_MAX);
+ entry->def = def;
+
+ if (virHashAddEntry(priv->configCache, filename, entry) < 0) {
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unable to store config file handle"));
+ goto error;
+ }
+
+ if (virHashAddEntry(priv->nameConfigMap, def->name, entry->filename) < 0) {
+ virHashRemoveEntry(priv->configCache, filename, NULL);
+ xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unable to store config file handle"));
+ goto error;
+ }
+
+ ret = virGetDomain(conn, def->name, def->uuid);
+ xenUnifiedUnlock(priv);
+ return (ret);
+
+ error:
+ VIR_FREE(entry);
+ virDomainDefFree(def);
+ xenUnifiedUnlock(priv);
+ return (NULL);
+}
+
+/*
+ * Delete a domain from disk
+ */
+int xenXMDomainUndefine(virDomainPtr domain) {
+ xenUnifiedPrivatePtr priv;
+ const char *filename;
+ xenXMConfCachePtr entry;
+ int ret = -1;
+
+ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+ xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return (-1);
+ }
+
+ if (domain->id != -1)
+ return (-1);
+ if (domain->conn->flags & VIR_CONNECT_RO)
+ return (-1);
+
+ priv = domain->conn->privateData;
+ xenUnifiedLock(priv);
+
+ if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
+ goto cleanup;
+
+ if (!(entry = virHashLookup(priv->configCache, filename)))
+ goto cleanup;
+
+ if (unlink(entry->filename) < 0)
+ goto cleanup;
+
+ /* Remove the name -> filename mapping */
+ if (virHashRemoveEntry(priv->nameConfigMap, domain->name, NULL) < 0)
+ goto cleanup;
+
+ /* Remove the config record itself */
+ if (virHashRemoveEntry(priv->configCache, entry->filename, xenXMConfigFree) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ xenUnifiedUnlock(priv);
+ return ret;
+}
+
+struct xenXMListIteratorContext {
+ virConnectPtr conn;
+ int max;
+ int count;
+ char ** names;
+};
+
+static void xenXMListIterator(const void *payload ATTRIBUTE_UNUSED, const char *name, const void *data) {
+ struct xenXMListIteratorContext *ctx = (struct xenXMListIteratorContext *)data;
+ virDomainPtr dom = NULL;
+
+ if (ctx->count == ctx->max)
+ return;
+
+ dom = xenDaemonLookupByName(ctx->conn, name);
+ if (!dom) {
+ ctx->names[ctx->count] = strdup(name);
+ ctx->count++;
+ } else {
+ virDomainFree(dom);
+ }
+}
+
+
+/*
+ * List all defined domains, filtered to remove any which
+ * are currently running
+ */
+int xenXMListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) {
+ xenUnifiedPrivatePtr priv;
+ struct xenXMListIteratorContext ctx;
+ int ret = -1;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+
+ priv = conn->privateData;
+ xenUnifiedLock(priv);
+
+ if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
+ goto cleanup;
+
+ if (maxnames > virHashSize(priv->configCache))
+ maxnames = virHashSize(priv->configCache);
+
+ ctx.conn = conn;
+ ctx.count = 0;
+ ctx.max = maxnames;
+ ctx.names = names;
+
+ virHashForEach(priv->nameConfigMap, xenXMListIterator, &ctx);
+ ret = ctx.count;
+
+cleanup:
+ xenUnifiedUnlock(priv);
+ return ret;
+}
+
+/*
+ * Return the maximum number of defined domains - not filtered
+ * based on number running
+ */
+int xenXMNumOfDefinedDomains(virConnectPtr conn) {
+ xenUnifiedPrivatePtr priv;
+ int ret = -1;
+
+ if (!VIR_IS_CONNECT(conn)) {
+ xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+
+ priv = conn->privateData;
+ xenUnifiedLock(priv);
+
+ if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
+ goto cleanup;
+
+ ret = virHashSize(priv->nameConfigMap);
+
+cleanup:
+ xenUnifiedUnlock(priv);
+ return ret;
+}
+
+
+/**
+ * xenXMDomainAttachDevice:
+ * @domain: pointer to domain object
+ * @xml: pointer to XML description of device
+ *
+ * Create a virtual device attachment to backend.
+ * XML description is translated into config file.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+static int
+xenXMDomainAttachDevice(virDomainPtr domain, const char *xml) {
+ const char *filename = NULL;
+ xenXMConfCachePtr entry = NULL;
+ int ret = -1;
+ virDomainDeviceDefPtr dev = NULL;
+ virDomainDefPtr def;
+ xenUnifiedPrivatePtr priv;
+
+ if ((!domain) || (!domain->conn) || (!domain->name) || (!xml)) {
+ xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return -1;
+ }
+
+ if (domain->conn->flags & VIR_CONNECT_RO)
+ return -1;
+ if (domain->id != -1)
+ return -1;
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ xenUnifiedLock(priv);
+
+ if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
+ goto cleanup;
+ if (!(entry = virHashLookup(priv->configCache, filename)))
+ goto cleanup;
+ def = entry->def;
+
+ if (!(dev = virDomainDeviceDefParse(domain->conn,
+ priv->caps,
+ entry->def,
+ xml, VIR_DOMAIN_XML_INACTIVE)))
+ goto cleanup;
+
+ switch (dev->type) {
+ case VIR_DOMAIN_DEVICE_DISK:
+ {
+ if (virDomainDiskInsert(def, dev->data.disk) < 0) {
+ virReportOOMError(domain->conn);
+ goto cleanup;
+ }
+ dev->data.disk = NULL;
+ }
+ break;
+
+ case VIR_DOMAIN_DEVICE_NET:
+ {
+ if (VIR_REALLOC_N(def->nets, def->nnets+1) < 0) {
+ virReportOOMError(domain->conn);
+ goto cleanup;
+ }
+ def->nets[def->nnets++] = dev->data.net;
+ dev->data.net = NULL;
+ break;
+ }
+
+ default:
+ xenXMError(domain->conn, VIR_ERR_XML_ERROR,
+ "%s", _("unknown device"));
+ goto cleanup;
+ }
+
+ /* If this fails, should we try to undo our changes to the
+ * in-memory representation of the config file. I say not!
+ */
+ if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ virDomainDeviceDefFree(dev);
+ xenUnifiedUnlock(priv);
+ return ret;
+}
+
+
+/**
+ * xenXMDomainDetachDevice:
+ * @domain: pointer to domain object
+ * @xml: pointer to XML description of device
+ *
+ * Destroy a virtual device attachment to backend.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+static int
+xenXMDomainDetachDevice(virDomainPtr domain, const char *xml) {
+ const char *filename = NULL;
+ xenXMConfCachePtr entry = NULL;
+ virDomainDeviceDefPtr dev = NULL;
+ virDomainDefPtr def;
+ int ret = -1;
+ int i;
+ xenUnifiedPrivatePtr priv;
+
+ if ((!domain) || (!domain->conn) || (!domain->name) || (!xml)) {
+ xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return -1;
+ }
+
+
+ if (domain->conn->flags & VIR_CONNECT_RO)
+ return -1;
+ if (domain->id != -1)
+ return -1;
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ xenUnifiedLock(priv);
+
+ if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
+ goto cleanup;
+ if (!(entry = virHashLookup(priv->configCache, filename)))
+ goto cleanup;
+ def = entry->def;
+
+ if (!(dev = virDomainDeviceDefParse(domain->conn,
+ priv->caps,
+ entry->def,
+ xml, VIR_DOMAIN_XML_INACTIVE)))
+ goto cleanup;
+
+ switch (dev->type) {
+ case VIR_DOMAIN_DEVICE_DISK:
+ {
+ for (i = 0 ; i < def->ndisks ; i++) {
+ if (def->disks[i]->dst &&
+ dev->data.disk->dst &&
+ STREQ(def->disks[i]->dst, dev->data.disk->dst)) {
+ virDomainDiskDefFree(def->disks[i]);
+ if (i < (def->ndisks - 1))
+ memmove(def->disks + i,
+ def->disks + i + 1,
+ sizeof(*def->disks) *
+ (def->ndisks - (i + 1)));
+ break;
+ }
+ }
+ break;
+ }
+
+ case VIR_DOMAIN_DEVICE_NET:
+ {
+ for (i = 0 ; i < def->nnets ; i++) {
+ if (!memcmp(def->nets[i]->mac,
+ dev->data.net->mac,
+ sizeof(def->nets[i]->mac))) {
+ virDomainNetDefFree(def->nets[i]);
+ if (i < (def->nnets - 1))
+ memmove(def->nets + i,
+ def->nets + i + 1,
+ sizeof(*def->nets) *
+ (def->nnets - (i + 1)));
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ xenXMError(domain->conn, VIR_ERR_XML_ERROR,
+ "%s", _("unknown device"));
+ goto cleanup;
+ }
+
+ /* If this fails, should we try to undo our changes to the
+ * in-memory representation of the config file. I say not!
+ */
+ if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ virDomainDeviceDefFree(dev);
+ xenUnifiedUnlock(priv);
+ return (ret);
+}
+
+int
+xenXMDomainBlockPeek (virDomainPtr dom,
+ const char *path ATTRIBUTE_UNUSED,
+ unsigned long long offset ATTRIBUTE_UNUSED,
+ size_t size ATTRIBUTE_UNUSED,
+ void *buffer ATTRIBUTE_UNUSED)
+{
+ xenXMError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+
+static char *xenXMAutostartLinkName(virDomainPtr dom)
+{
+ char *ret;
+ virAsprintf(&ret, "/etc/xen/auto/%s", dom->name);
+ return ret;
+}
+
+static char *xenXMDomainConfigName(virDomainPtr dom)
+{
+ char *ret;
+ virAsprintf(&ret, "/etc/xen/%s", dom->name);
+ return ret;
+}
+
+int xenXMDomainGetAutostart(virDomainPtr dom, int *autostart)
+{
+ char *linkname = xenXMAutostartLinkName(dom);
+ char *config = xenXMDomainConfigName(dom);
+ int ret = -1;
+
+ if (!linkname || !config) {
+ virReportOOMError(dom->conn);
+ goto cleanup;
+ }
+
+ *autostart = virFileLinkPointsTo(linkname, config);
+ if (*autostart < 0) {
+ virReportSystemError(dom->conn, errno,
+ _("cannot check link %s points to config %s"),
+ linkname, config);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(linkname);
+ VIR_FREE(config);
+ return ret;
+}
+
+
+int xenXMDomainSetAutostart(virDomainPtr dom, int autostart)
+{
+ char *linkname = xenXMAutostartLinkName(dom);
+ char *config = xenXMDomainConfigName(dom);
+ int ret = -1;
+
+ if (!linkname || !config) {
+ virReportOOMError(dom->conn);
+ goto cleanup;
+ }
+
+ if (autostart) {
+ if (symlink(config, linkname) < 0 &&
+ errno != EEXIST) {
+ virReportSystemError(dom->conn, errno,
+ _("failed to create link %s to %s"),
+ config, linkname);
+ goto cleanup;
+ }
+ } else {
+ if (unlink(linkname) < 0 &&
+ errno != ENOENT) {
+ virReportSystemError(dom->conn, errno,
+ _("failed to remove link %s"),
+ linkname);
+ goto cleanup;
+ }
+ }
+ ret = 0;
+
+cleanup:
+ VIR_FREE(linkname);
+ VIR_FREE(config);
+
+ return ret;
+}
--- /dev/null
+/*
+ * xm_internal.h: helper routines for dealing with inactive domains
+ *
+ * Copyright (C) 2006-2007 Red Hat
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange@redhat.com>
+ *
+ */
+
+#ifndef _LIBVIRT_XM_INTERNAL_H_
+#define _LIBVIRT_XM_INTERNAL_H_
+
+#include "internal.h"
+#include "driver.h"
+#include "conf.h"
+#include "domain_conf.h"
+
+extern struct xenUnifiedDriver xenXMDriver;
+
+int xenXMConfigCacheRefresh (virConnectPtr conn);
+int xenXMConfigCacheAddFile(virConnectPtr conn, const char *filename);
+int xenXMConfigCacheRemoveFile(virConnectPtr conn, const char *filename);
+
+virDrvOpenStatus xenXMOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags);
+int xenXMClose(virConnectPtr conn);
+const char *xenXMGetType(virConnectPtr conn);
+int xenXMDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info);
+char *xenXMDomainDumpXML(virDomainPtr domain, int flags);
+int xenXMDomainSetMemory(virDomainPtr domain, unsigned long memory);
+int xenXMDomainSetMaxMemory(virDomainPtr domain, unsigned long memory);
+unsigned long xenXMDomainGetMaxMemory(virDomainPtr domain);
+int xenXMDomainSetVcpus(virDomainPtr domain, unsigned int vcpus);
+int xenXMDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
+ unsigned char *cpumap, int maplen);
+virDomainPtr xenXMDomainLookupByName(virConnectPtr conn, const char *domname);
+virDomainPtr xenXMDomainLookupByUUID(virConnectPtr conn,
+ const unsigned char *uuid);
+
+int xenXMListDefinedDomains(virConnectPtr conn, char ** const names, int maxnames);
+int xenXMNumOfDefinedDomains(virConnectPtr conn);
+
+int xenXMDomainCreate(virDomainPtr domain);
+virDomainPtr xenXMDomainDefineXML(virConnectPtr con, const char *xml);
+int xenXMDomainUndefine(virDomainPtr domain);
+
+virConfPtr xenXMDomainConfigFormat(virConnectPtr conn, virDomainDefPtr def);
+virDomainDefPtr xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf);
+
+int xenXMDomainBlockPeek (virDomainPtr dom, const char *path, unsigned long long offset, size_t size, void *buffer);
+
+int xenXMDomainGetAutostart(virDomainPtr dom, int *autostart);
+int xenXMDomainSetAutostart(virDomainPtr dom, int autostart);
+
+#endif
--- /dev/null
+/*
+ * xs_internal.c: access to Xen Store
+ *
+ * Copyright (C) 2006, 2009 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <stdint.h>
+
+#include <xen/dom0_ops.h>
+#include <xen/version.h>
+#include <xen/xen.h>
+
+#include <xs.h>
+
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "driver.h"
+#include "memory.h"
+#include "event.h"
+#include "logging.h"
+#include "uuid.h"
+#include "xen_driver.h"
+#include "xs_internal.h"
+#include "xen_hypervisor.h"
+
+#define VIR_FROM_THIS VIR_FROM_XEN
+
+#ifndef PROXY
+static char *xenStoreDomainGetOSType(virDomainPtr domain);
+static void xenStoreWatchEvent(int watch, int fd, int events, void *data);
+static void xenStoreWatchListFree(xenStoreWatchListPtr list);
+
+struct xenUnifiedDriver xenStoreDriver = {
+ xenStoreOpen, /* open */
+ xenStoreClose, /* close */
+ NULL, /* version */
+ NULL, /* hostname */
+ NULL, /* nodeGetInfo */
+ NULL, /* getCapabilities */
+ xenStoreListDomains, /* listDomains */
+ NULL, /* numOfDomains */
+ NULL, /* domainCreateXML */
+ NULL, /* domainSuspend */
+ NULL, /* domainResume */
+ xenStoreDomainShutdown, /* domainShutdown */
+ xenStoreDomainReboot, /* domainReboot */
+ NULL, /* domainDestroy */
+ xenStoreDomainGetOSType, /* domainGetOSType */
+ xenStoreDomainGetMaxMemory, /* domainGetMaxMemory */
+ NULL, /* domainSetMaxMemory */
+ xenStoreDomainSetMemory, /* domainSetMemory */
+ xenStoreGetDomainInfo, /* domainGetInfo */
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
+ NULL, /* domainCoreDump */
+ NULL, /* domainSetVcpus */
+ NULL, /* domainPinVcpu */
+ NULL, /* domainGetVcpus */
+ NULL, /* domainGetMaxVcpus */
+ NULL, /* listDefinedDomains */
+ NULL, /* numOfDefinedDomains */
+ NULL, /* domainCreate */
+ NULL, /* domainDefineXML */
+ NULL, /* domainUndefine */
+ NULL, /* domainAttachDevice */
+ NULL, /* domainDetachDevice */
+ NULL, /* domainGetAutostart */
+ NULL, /* domainSetAutostart */
+ NULL, /* domainGetSchedulerType */
+ NULL, /* domainGetSchedulerParameters */
+ NULL, /* domainSetSchedulerParameters */
+};
+
+#endif /* ! PROXY */
+
+#define virXenStoreError(conn, code, fmt...) \
+ virReportErrorHelper(NULL, VIR_FROM_XENSTORE, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
+/************************************************************************
+ * *
+ * Helper internal APIs *
+ * *
+ ************************************************************************/
+#ifndef PROXY
+/**
+ * virConnectDoStoreList:
+ * @conn: pointer to the hypervisor connection
+ * @path: the absolute path of the directory in the store to list
+ * @nb: OUT pointer to the number of items found
+ *
+ * Internal API querying the Xenstore for a list
+ *
+ * Returns a string which must be freed by the caller or NULL in case of error
+ */
+static char **
+virConnectDoStoreList(virConnectPtr conn, const char *path,
+ unsigned int *nb)
+{
+ xenUnifiedPrivatePtr priv;
+
+ if (conn == NULL)
+ return NULL;
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->xshandle == NULL || path == NULL || nb == NULL)
+ return (NULL);
+
+ return xs_directory (priv->xshandle, 0, path, nb);
+}
+#endif /* ! PROXY */
+
+/**
+ * virDomainDoStoreQuery:
+ * @conn: pointer to the hypervisor connection
+ * @domid: id of the domain
+ * @path: the relative path of the data in the store to retrieve
+ *
+ * Internal API querying the Xenstore for a string value.
+ *
+ * Returns a string which must be freed by the caller or NULL in case of error
+ */
+static char *
+virDomainDoStoreQuery(virConnectPtr conn, int domid, const char *path)
+{
+ char s[256];
+ unsigned int len = 0;
+ xenUnifiedPrivatePtr priv;
+
+ if (!conn)
+ return NULL;
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->xshandle == NULL)
+ return (NULL);
+
+ snprintf(s, 255, "/local/domain/%d/%s", domid, path);
+ s[255] = 0;
+
+ return xs_read(priv->xshandle, 0, &s[0], &len);
+}
+
+#ifndef PROXY
+/**
+ * virDomainDoStoreWrite:
+ * @domain: a domain object
+ * @path: the relative path of the data in the store to retrieve
+ *
+ * Internal API setting up a string value in the Xenstore
+ * Requires write access to the XenStore
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+static int
+virDomainDoStoreWrite(virDomainPtr domain, const char *path,
+ const char *value)
+{
+ char s[256];
+ xenUnifiedPrivatePtr priv;
+ int ret = -1;
+
+ if (!VIR_IS_CONNECTED_DOMAIN(domain))
+ return (-1);
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->xshandle == NULL)
+ return (-1);
+ if (domain->conn->flags & VIR_CONNECT_RO)
+ return (-1);
+
+ snprintf(s, 255, "/local/domain/%d/%s", domain->id, path);
+ s[255] = 0;
+
+ if (xs_write(priv->xshandle, 0, &s[0], value, strlen(value)))
+ ret = 0;
+
+ return (ret);
+}
+
+/**
+ * virDomainGetVM:
+ * @domain: a domain object
+ *
+ * Internal API extracting a xenstore vm path.
+ *
+ * Returns the new string or NULL in case of error
+ */
+static char *
+virDomainGetVM(virDomainPtr domain)
+{
+ char *vm;
+ char query[200];
+ unsigned int len;
+ xenUnifiedPrivatePtr priv;
+
+ if (!VIR_IS_CONNECTED_DOMAIN(domain))
+ return (NULL);
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->xshandle == NULL)
+ return (NULL);
+
+ snprintf(query, 199, "/local/domain/%d/vm", virDomainGetID(domain));
+ query[199] = 0;
+
+ vm = xs_read(priv->xshandle, 0, &query[0], &len);
+
+ return (vm);
+}
+
+/**
+ * virDomainGetVMInfo:
+ * @domain: a domain object
+ * @vm: the xenstore vm path
+ * @name: the value's path
+ *
+ * Internal API extracting one information the device used
+ * by the domain from xensttore
+ *
+ * Returns the new string or NULL in case of error
+ */
+static char *
+virDomainGetVMInfo(virDomainPtr domain, const char *vm, const char *name)
+{
+ char s[256];
+ char *ret = NULL;
+ unsigned int len = 0;
+ xenUnifiedPrivatePtr priv;
+
+ if (!VIR_IS_CONNECTED_DOMAIN(domain))
+ return (NULL);
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->xshandle == NULL)
+ return (NULL);
+
+ snprintf(s, 255, "%s/%s", vm, name);
+ s[255] = 0;
+
+ ret = xs_read(priv->xshandle, 0, &s[0], &len);
+
+ return (ret);
+}
+
+#endif /* ! PROXY */
+
+/************************************************************************
+ * *
+ * Canonical internal APIs *
+ * *
+ ************************************************************************/
+/**
+ * xenStoreOpen:
+ * @conn: pointer to the connection block
+ * @name: URL for the target, NULL for local
+ * @flags: combination of virDrvOpenFlag(s)
+ *
+ * Connects to the Xen hypervisor.
+ *
+ * Returns 0 or -1 in case of error.
+ */
+virDrvOpenStatus
+xenStoreOpen(virConnectPtr conn,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED)
+{
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+#ifdef PROXY
+ priv->xshandle = xs_daemon_open_readonly();
+#else
+ if (flags & VIR_CONNECT_RO)
+ priv->xshandle = xs_daemon_open_readonly();
+ else
+ priv->xshandle = xs_daemon_open();
+#endif /* ! PROXY */
+
+ if (priv->xshandle == NULL) {
+ /*
+ * not being able to connect via the socket as an unprivileged
+ * user is rather normal, this should fallback to the proxy (or
+ * remote) mechanism.
+ */
+ if (xenHavePrivilege()) {
+ virXenStoreError(NULL, VIR_ERR_NO_XEN,
+ "%s", _("failed to connect to Xen Store"));
+ }
+ return (-1);
+ }
+
+#ifndef PROXY
+ /* Init activeDomainList */
+ if (VIR_ALLOC(priv->activeDomainList) < 0) {
+ virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to allocate activeDomainList"));
+ return -1;
+ }
+
+ /* Init watch list before filling in domInfoList,
+ so we can know if it is the first time through
+ when the callback fires */
+ if ( VIR_ALLOC(priv->xsWatchList) < 0 ) {
+ virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to allocate xsWatchList"));
+ return -1;
+ }
+
+ /* This will get called once at start */
+ if ( xenStoreAddWatch(conn, "@releaseDomain",
+ "releaseDomain", xenStoreDomainReleased, priv) < 0 )
+ {
+ virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("adding watch @releaseDomain"));
+ return -1;
+ }
+
+ /* The initial call of this will fill domInfoList */
+ if( xenStoreAddWatch(conn, "@introduceDomain",
+ "introduceDomain", xenStoreDomainIntroduced, priv) < 0 )
+ {
+ virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("adding watch @introduceDomain"));
+ return -1;
+ }
+
+ /* Add an event handle */
+ if ((priv->xsWatch = virEventAddHandle(xs_fileno(priv->xshandle),
+ VIR_EVENT_HANDLE_READABLE,
+ xenStoreWatchEvent,
+ conn,
+ NULL)) < 0)
+ DEBUG0("Failed to add event handle, disabling events\n");
+
+#endif //PROXY
+ return 0;
+}
+
+/**
+ * xenStoreClose:
+ * @conn: pointer to the connection block
+ *
+ * Close the connection to the Xen hypervisor.
+ *
+ * Returns 0 in case of success or -1 in case of error.
+ */
+int
+xenStoreClose(virConnectPtr conn)
+{
+ xenUnifiedPrivatePtr priv;
+
+ if (conn == NULL) {
+ virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(-1);
+ }
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+#ifndef PROXY
+ if (xenStoreRemoveWatch(conn, "@introduceDomain", "introduceDomain") < 0) {
+ DEBUG0("Warning, could not remove @introduceDomain watch");
+ /* not fatal */
+ }
+
+ if (xenStoreRemoveWatch(conn, "@releaseDomain", "releaseDomain") < 0) {
+ DEBUG0("Warning, could not remove @releaseDomain watch");
+ /* not fatal */
+ }
+
+ xenStoreWatchListFree(priv->xsWatchList);
+ priv->xsWatchList = NULL;
+ xenUnifiedDomainInfoListFree(priv->activeDomainList);
+ priv->activeDomainList = NULL;
+#endif
+ if (priv->xshandle == NULL)
+ return(-1);
+
+ if (priv->xsWatch != -1)
+ virEventRemoveHandle(priv->xsWatch);
+ xs_daemon_close(priv->xshandle);
+ priv->xshandle = NULL;
+
+ return (0);
+}
+
+#ifndef PROXY
+/**
+ * xenStoreGetDomainInfo:
+ * @domain: pointer to the domain block
+ * @info: the place where information should be stored
+ *
+ * Do an hypervisor call to get the related set of domain information.
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+int
+xenStoreGetDomainInfo(virDomainPtr domain, virDomainInfoPtr info)
+{
+ char *tmp, **tmp2;
+ unsigned int nb_vcpus;
+ char request[200];
+ xenUnifiedPrivatePtr priv;
+
+ if (!VIR_IS_CONNECTED_DOMAIN(domain))
+ return (-1);
+
+ if ((domain == NULL) || (domain->conn == NULL) || (info == NULL)) {
+ virXenStoreError(domain ? domain->conn : NULL, VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+
+ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+ if (priv->xshandle == NULL)
+ return(-1);
+
+ if (domain->id == -1)
+ return(-1);
+
+ tmp = virDomainDoStoreQuery(domain->conn, domain->id, "running");
+ if (tmp != NULL) {
+ if (tmp[0] == '1')
+ info->state = VIR_DOMAIN_RUNNING;
+ free(tmp);
+ } else {
+ info->state = VIR_DOMAIN_NOSTATE;
+ }
+ tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
+ if (tmp != NULL) {
+ info->memory = atol(tmp);
+ info->maxMem = atol(tmp);
+ free(tmp);
+ } else {
+ info->memory = 0;
+ info->maxMem = 0;
+ }
+#if 0
+ /* doesn't seems to work */
+ tmp = virDomainDoStoreQuery(domain->conn, domain->id, "cpu_time");
+ if (tmp != NULL) {
+ info->cpuTime = atol(tmp);
+ free(tmp);
+ } else {
+ info->cpuTime = 0;
+ }
+#endif
+ snprintf(request, 199, "/local/domain/%d/cpu", domain->id);
+ request[199] = 0;
+ tmp2 = virConnectDoStoreList(domain->conn, request, &nb_vcpus);
+ if (tmp2 != NULL) {
+ info->nrVirtCpu = nb_vcpus;
+ free(tmp2);
+ }
+ return (0);
+}
+
+/**
+ * xenStoreDomainSetMemory:
+ * @domain: pointer to the domain block
+ * @memory: the max memory size in kilobytes.
+ *
+ * Change the maximum amount of memory allowed in the xen store
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+int
+xenStoreDomainSetMemory(virDomainPtr domain, unsigned long memory)
+{
+ int ret;
+ char value[20];
+
+ if ((domain == NULL) || (domain->conn == NULL) ||
+ (memory < 1024 * MIN_XEN_GUEST_SIZE)) {
+ virXenStoreError(domain ? domain->conn : NULL, VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+ if (domain->id == -1)
+ return(-1);
+ if ((domain->id == 0) && (memory < (2 * MIN_XEN_GUEST_SIZE * 1024)))
+ return(-1);
+ snprintf(value, 19, "%lu", memory);
+ value[19] = 0;
+ ret = virDomainDoStoreWrite(domain, "memory/target", &value[0]);
+ if (ret < 0)
+ return (-1);
+ return (0);
+}
+
+/**
+ * xenStoreDomainGetMaxMemory:
+ * @domain: pointer to the domain block
+ *
+ * Ask the xenstore for the maximum memory allowed for a domain
+ *
+ * Returns the memory size in kilobytes or 0 in case of error.
+ */
+unsigned long
+xenStoreDomainGetMaxMemory(virDomainPtr domain)
+{
+ char *tmp;
+ unsigned long ret = 0;
+ xenUnifiedPrivatePtr priv;
+
+ if (!VIR_IS_CONNECTED_DOMAIN(domain))
+ return (ret);
+ if (domain->id == -1)
+ return(-1);
+
+ priv = domain->conn->privateData;
+ xenUnifiedLock(priv);
+ tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
+ if (tmp != NULL) {
+ ret = (unsigned long) atol(tmp);
+ VIR_FREE(tmp);
+ }
+ xenUnifiedUnlock(priv);
+ return(ret);
+}
+
+/**
+ * xenStoreNumOfDomains:
+ * @conn: pointer to the hypervisor connection
+ *
+ * Provides the number of active domains.
+ *
+ * Returns the number of domain found or -1 in case of error
+ */
+int
+xenStoreNumOfDomains(virConnectPtr conn)
+{
+ unsigned int num;
+ char **idlist;
+ int ret = -1;
+ xenUnifiedPrivatePtr priv;
+
+ if (conn == NULL) {
+ virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return -1;
+ }
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->xshandle == NULL) {
+ virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(-1);
+ }
+ idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
+ if (idlist) {
+ free(idlist);
+ ret = num;
+ }
+ return(ret);
+}
+
+/**
+ * xenStoreDoListDomains:
+ * @conn: pointer to the hypervisor connection
+ * @ids: array to collect the list of IDs of active domains
+ * @maxids: size of @ids
+ *
+ * Internal API: collect the list of active domains, and store
+ * their ID in @maxids. The driver lock must be held.
+ *
+ * Returns the number of domain found or -1 in case of error
+ */
+static int
+xenStoreDoListDomains(xenUnifiedPrivatePtr priv, int *ids, int maxids)
+{
+ char **idlist = NULL, *endptr;
+ unsigned int num, i;
+ int ret = -1;
+ long id;
+
+ if (priv->xshandle == NULL)
+ goto out;
+
+ idlist = xs_directory (priv->xshandle, 0, "/local/domain", &num);
+ if (idlist == NULL)
+ goto out;
+
+ for (ret = 0, i = 0; (i < num) && (ret < maxids); i++) {
+ id = strtol(idlist[i], &endptr, 10);
+ if ((endptr == idlist[i]) || (*endptr != 0))
+ goto out;
+ ids[ret++] = (int) id;
+ }
+
+out:
+ VIR_FREE (idlist);
+ return ret;
+}
+
+/**
+ * xenStoreListDomains:
+ * @conn: pointer to the hypervisor connection
+ * @ids: array to collect the list of IDs of active domains
+ * @maxids: size of @ids
+ *
+ * Collect the list of active domains, and store their ID in @maxids
+ *
+ * Returns the number of domain found or -1 in case of error
+ */
+int
+xenStoreListDomains(virConnectPtr conn, int *ids, int maxids)
+{
+ xenUnifiedPrivatePtr priv;
+ int ret;
+
+ if ((conn == NULL) || (ids == NULL)) {
+ virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(-1);
+ }
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ xenUnifiedLock(priv);
+ ret = xenStoreDoListDomains(priv, ids, maxids);
+ xenUnifiedUnlock(priv);
+
+ return(ret);
+}
+
+/**
+ * xenStoreLookupByName:
+ * @conn: A xend instance
+ * @name: The name of the domain
+ *
+ * Try to lookup a domain on the Xen Store based on its name.
+ *
+ * Returns a new domain object or NULL in case of failure
+ */
+virDomainPtr
+xenStoreLookupByName(virConnectPtr conn, const char *name)
+{
+ virDomainPtr ret = NULL;
+ unsigned int num, i, len;
+ long id = -1;
+ char **idlist = NULL, *endptr;
+ char prop[200], *tmp;
+ int found = 0;
+ struct xend_domain *xenddomain = NULL;
+ xenUnifiedPrivatePtr priv;
+
+ if ((conn == NULL) || (name == NULL)) {
+ virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(NULL);
+ }
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->xshandle == NULL)
+ return(NULL);
+
+ idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
+ if (idlist == NULL)
+ goto done;
+
+ for (i = 0; i < num; i++) {
+ id = strtol(idlist[i], &endptr, 10);
+ if ((endptr == idlist[i]) || (*endptr != 0)) {
+ goto done;
+ }
+#if 0
+ if (virConnectCheckStoreID(conn, (int) id) < 0)
+ continue;
+#endif
+ snprintf(prop, 199, "/local/domain/%s/name", idlist[i]);
+ prop[199] = 0;
+ tmp = xs_read(priv->xshandle, 0, prop, &len);
+ if (tmp != NULL) {
+ found = STREQ (name, tmp);
+ free(tmp);
+ if (found)
+ break;
+ }
+ }
+ if (!found)
+ goto done;
+
+ ret = virGetDomain(conn, name, NULL);
+ if (ret == NULL)
+ goto done;
+
+ ret->id = id;
+
+done:
+ free(xenddomain);
+ free(idlist);
+
+ return(ret);
+}
+
+/**
+ * xenStoreDomainShutdown:
+ * @domain: pointer to the Domain block
+ *
+ * Shutdown the domain, the OS is requested to properly shutdown
+ * and the domain may ignore it. It will return immediately
+ * after queuing the request.
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+int
+xenStoreDomainShutdown(virDomainPtr domain)
+{
+ int ret;
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL)) {
+ virXenStoreError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+ if (domain->id == -1 || domain->id == 0)
+ return(-1);
+ /*
+ * this is very hackish, the domU kernel probes for a special
+ * node in the xenstore and launch the shutdown command if found.
+ */
+ priv = domain->conn->privateData;
+ xenUnifiedLock(priv);
+ ret = virDomainDoStoreWrite(domain, "control/shutdown", "poweroff");
+ xenUnifiedUnlock(priv);
+ return ret;
+}
+
+/**
+ * xenStoreDomainReboot:
+ * @domain: pointer to the Domain block
+ * @flags: extra flags for the reboot operation, not used yet
+ *
+ * Reboot the domain, the OS is requested to properly shutdown
+ * and reboot but the domain may ignore it. It will return immediately
+ * after queuing the request.
+ *
+ * Returns 0 in case of success, -1 in case of error.
+ */
+int
+xenStoreDomainReboot(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED)
+{
+ int ret;
+ xenUnifiedPrivatePtr priv;
+
+ if ((domain == NULL) || (domain->conn == NULL)) {
+ virXenStoreError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(-1);
+ }
+ if (domain->id == -1 || domain->id == 0)
+ return(-1);
+ /*
+ * this is very hackish, the domU kernel probes for a special
+ * node in the xenstore and launch the shutdown command if found.
+ */
+ priv = domain->conn->privateData;
+ xenUnifiedLock(priv);
+ ret = virDomainDoStoreWrite(domain, "control/shutdown", "reboot");
+ xenUnifiedUnlock(priv);
+ return ret;
+}
+
+/*
+ * xenStoreDomainGetOSType:
+ * @domain: a domain object
+ *
+ * Get the type of domain operation system.
+ *
+ * Returns the new string or NULL in case of error, the string must be
+ * freed by the caller.
+ */
+static char *
+xenStoreDomainGetOSType(virDomainPtr domain) {
+ char *vm, *str = NULL;
+
+ if ((domain == NULL) || (domain->conn == NULL)) {
+ virXenStoreError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+ __FUNCTION__);
+ return(NULL);
+ }
+
+ vm = virDomainGetVM(domain);
+ if (vm) {
+ xenUnifiedPrivatePtr priv = domain->conn->privateData;
+ xenUnifiedLock(priv);
+ str = virDomainGetVMInfo(domain, vm, "image/ostype");
+ xenUnifiedUnlock(priv);
+ VIR_FREE(vm);
+ }
+
+ return (str);
+}
+#endif /* ! PROXY */
+
+/**
+ * xenStoreDomainGetVNCPort:
+ * @conn: the hypervisor connection
+ * @domid: id of the domain
+ *
+ * Return the port number on which the domain is listening for VNC
+ * connections.
+ *
+ * The caller must hold the lock on the privateData
+ * associated with the 'conn' parameter.
+ *
+ * Returns the port number, -1 in case of error
+ */
+int xenStoreDomainGetVNCPort(virConnectPtr conn, int domid) {
+ char *tmp;
+ int ret = -1;
+
+ tmp = virDomainDoStoreQuery(conn, domid, "console/vnc-port");
+ if (tmp != NULL) {
+ char *end;
+ ret = strtol(tmp, &end, 10);
+ if (ret == 0 && end == tmp)
+ ret = -1;
+ free(tmp);
+ }
+ return(ret);
+}
+
+/**
+ * xenStoreDomainGetConsolePath:
+ * @conn: the hypervisor connection
+ * @domid: id of the domain
+ *
+ * Return the path to the psuedo TTY on which the guest domain's
+ * serial console is attached.
+ *
+ * Returns the path to the serial console. It is the callers
+ * responsibilty to free() the return string. Returns NULL
+ * on error
+ *
+ * The caller must hold the lock on the privateData
+ * associated with the 'conn' parameter.
+ */
+char * xenStoreDomainGetConsolePath(virConnectPtr conn, int domid) {
+ return virDomainDoStoreQuery(conn, domid, "console/tty");
+}
+
+#ifdef PROXY
+/*
+ * xenStoreDomainGetOSTypeID:
+ * @conn: pointer to the connection.
+ * @id: the domain id
+ *
+ * Get the type of domain operation system.
+ *
+ * The caller must hold the lock on the privateData
+ * associated with the 'conn' parameter.
+ *
+ * Returns the new string or NULL in case of error, the string must be
+ * freed by the caller.
+ */
+char *
+xenStoreDomainGetOSTypeID(virConnectPtr conn, int id) {
+ char *vm, *str = NULL;
+ char query[200];
+ unsigned int len;
+ xenUnifiedPrivatePtr priv;
+
+ if (id < 0)
+ return(NULL);
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->xshandle == NULL)
+ return (NULL);
+
+ snprintf(query, 199, "/local/domain/%d/vm", id);
+ query[199] = 0;
+
+ vm = xs_read(priv->xshandle, 0, &query[0], &len);
+
+ if (vm) {
+ snprintf(query, 199, "%s/image/ostype", vm);
+ str = xs_read(priv->xshandle, 0, &query[0], &len);
+ free(vm);
+ }
+ if (str == NULL)
+ str = strdup("linux");
+
+
+ return (str);
+}
+#endif /* PROXY */
+
+/*
+ * xenStoreDomainGetNetworkID:
+ * @conn: pointer to the connection.
+ * @id: the domain id
+ * @mac: the mac address
+ *
+ * Get the reference (i.e. the string number) for the device on that domain
+ * which uses the given mac address
+ *
+ * The caller must hold the lock on the privateData
+ * associated with the 'conn' parameter.
+ *
+ * Returns the new string or NULL in case of error, the string must be
+ * freed by the caller.
+ */
+char *
+xenStoreDomainGetNetworkID(virConnectPtr conn, int id, const char *mac) {
+ char dir[80], path[128], **list = NULL, *val = NULL;
+ unsigned int len, i, num;
+ char *ret = NULL;
+ xenUnifiedPrivatePtr priv;
+
+ if (id < 0)
+ return(NULL);
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->xshandle == NULL)
+ return (NULL);
+ if (mac == NULL)
+ return (NULL);
+
+ snprintf(dir, sizeof(dir), "/local/domain/0/backend/vif/%d", id);
+ list = xs_directory(priv->xshandle, 0, dir, &num);
+ if (list == NULL)
+ return(NULL);
+ for (i = 0; i < num; i++) {
+ snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "mac");
+ if ((val = xs_read(priv->xshandle, 0, path, &len)) == NULL)
+ break;
+
+ bool match = (virMacAddrCompare(val, mac) == 0);
+
+ VIR_FREE(val);
+
+ if (match) {
+ ret = strdup(list[i]);
+ break;
+ }
+ }
+
+ VIR_FREE(list);
+ return(ret);
+}
+
+/*
+ * xenStoreDomainGetDiskID:
+ * @conn: pointer to the connection.
+ * @id: the domain id
+ * @dev: the virtual block device name
+ *
+ * Get the reference (i.e. the string number) for the device on that domain
+ * which uses the given virtual block device name
+ *
+ * The caller must hold the lock on the privateData
+ * associated with the 'conn' parameter.
+ *
+ * Returns the new string or NULL in case of error, the string must be
+ * freed by the caller.
+ */
+char *
+xenStoreDomainGetDiskID(virConnectPtr conn, int id, const char *dev) {
+ char dir[80], path[128], **list = NULL, *val = NULL;
+ unsigned int devlen, len, i, num;
+ char *ret = NULL;
+ xenUnifiedPrivatePtr priv;
+
+ if (id < 0)
+ return(NULL);
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->xshandle == NULL)
+ return (NULL);
+ if (dev == NULL)
+ return (NULL);
+ devlen = strlen(dev);
+ if (devlen <= 0)
+ return (NULL);
+
+ snprintf(dir, sizeof(dir), "/local/domain/0/backend/vbd/%d", id);
+ list = xs_directory(priv->xshandle, 0, dir, &num);
+ if (list != NULL) {
+ for (i = 0; i < num; i++) {
+ snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev");
+ val = xs_read(priv->xshandle, 0, path, &len);
+ if (val == NULL)
+ break;
+ if ((devlen != len) || memcmp(val, dev, len)) {
+ free (val);
+ } else {
+ ret = strdup(list[i]);
+ free (val);
+ free (list);
+ return (ret);
+ }
+ }
+ free (list);
+ }
+ snprintf(dir, sizeof(dir), "/local/domain/0/backend/tap/%d", id);
+ list = xs_directory(priv->xshandle, 0, dir, &num);
+ if (list != NULL) {
+ for (i = 0; i < num; i++) {
+ snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev");
+ val = xs_read(priv->xshandle, 0, path, &len);
+ if (val == NULL)
+ break;
+ if ((devlen != len) || memcmp(val, dev, len)) {
+ free (val);
+ } else {
+ ret = strdup(list[i]);
+ free (val);
+ free (list);
+ return (ret);
+ }
+ }
+ free (list);
+ }
+ return (NULL);
+}
+
+/*
+ * The caller must hold the lock on the privateData
+ * associated with the 'conn' parameter.
+ */
+char *xenStoreDomainGetName(virConnectPtr conn,
+ int id) {
+ char prop[200];
+ xenUnifiedPrivatePtr priv;
+ unsigned int len;
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->xshandle == NULL)
+ return(NULL);
+
+ snprintf(prop, 199, "/local/domain/%d/name", id);
+ prop[199] = 0;
+ return xs_read(priv->xshandle, 0, prop, &len);
+}
+
+#ifndef PROXY
+/*
+ * The caller must hold the lock on the privateData
+ * associated with the 'conn' parameter.
+ */
+int xenStoreDomainGetUUID(virConnectPtr conn,
+ int id,
+ unsigned char *uuid) {
+ char prop[200];
+ xenUnifiedPrivatePtr priv;
+ unsigned int len;
+ char *uuidstr;
+ int ret = 0;
+
+ priv = (xenUnifiedPrivatePtr) conn->privateData;
+ if (priv->xshandle == NULL)
+ return -1;
+
+ snprintf(prop, 199, "/local/domain/%d/vm", id);
+ prop[199] = 0;
+ // This will return something like
+ // /vm/00000000-0000-0000-0000-000000000000
+ uuidstr = xs_read(priv->xshandle, 0, prop, &len);
+
+ // remove "/vm/"
+ ret = virUUIDParse(uuidstr + 4, uuid);
+
+ VIR_FREE(uuidstr);
+
+ return ret;
+}
+
+static void
+xenStoreWatchListFree(xenStoreWatchListPtr list)
+{
+ int i;
+ for (i=0; i<list->count; i++) {
+ VIR_FREE(list->watches[i]->path);
+ VIR_FREE(list->watches[i]->token);
+ VIR_FREE(list->watches[i]);
+ }
+ VIR_FREE(list);
+}
+
+/*
+ * The caller must hold the lock on the privateData
+ * associated with the 'conn' parameter.
+ */
+int xenStoreAddWatch(virConnectPtr conn,
+ const char *path,
+ const char *token,
+ xenStoreWatchCallback cb,
+ void *opaque)
+{
+ xenStoreWatchPtr watch;
+ int n;
+ xenStoreWatchListPtr list;
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ if (priv->xshandle == NULL)
+ return -1;
+
+ list = priv->xsWatchList;
+ if(!list)
+ return -1;
+
+ /* check if we already have this callback on our list */
+ for (n=0; n < list->count; n++) {
+ if( STREQ(list->watches[n]->path, path) &&
+ STREQ(list->watches[n]->token, token)) {
+ virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("watch already tracked"));
+ return -1;
+ }
+ }
+
+ if (VIR_ALLOC(watch) < 0)
+ return -1;
+ watch->path = strdup(path);
+ watch->token = strdup(token);
+ watch->cb = cb;
+ watch->opaque = opaque;
+
+ /* Make space on list */
+ n = list->count;
+ if (VIR_REALLOC_N(list->watches, n + 1) < 0) {
+ virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("reallocating list"));
+ VIR_FREE(watch);
+ return -1;
+ }
+
+ list->watches[n] = watch;
+ list->count++;
+
+ conn->refs++;
+
+ return xs_watch(priv->xshandle, watch->path, watch->token);
+}
+
+/*
+ * The caller must hold the lock on the privateData
+ * associated with the 'conn' parameter.
+ */
+int xenStoreRemoveWatch(virConnectPtr conn,
+ const char *path,
+ const char *token)
+{
+ int i;
+ xenStoreWatchListPtr list;
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ if (priv->xshandle == NULL)
+ return -1;
+
+ list = priv->xsWatchList;
+ if(!list)
+ return -1;
+
+ for (i = 0 ; i < list->count ; i++) {
+ if( STREQ(list->watches[i]->path, path) &&
+ STREQ(list->watches[i]->token, token)) {
+
+ if (!xs_unwatch(priv->xshandle,
+ list->watches[i]->path,
+ list->watches[i]->token))
+ {
+ DEBUG0("WARNING: Could not remove watch");
+ /* Not fatal, continue */
+ }
+
+ VIR_FREE(list->watches[i]->path);
+ VIR_FREE(list->watches[i]->token);
+ VIR_FREE(list->watches[i]);
+
+ if (i < (list->count - 1))
+ memmove(list->watches + i,
+ list->watches + i + 1,
+ sizeof(*(list->watches)) *
+ (list->count - (i + 1)));
+
+ if (VIR_REALLOC_N(list->watches,
+ list->count - 1) < 0) {
+ ; /* Failure to reduce memory allocation isn't fatal */
+ }
+ list->count--;
+ virUnrefConnect(conn);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static xenStoreWatchPtr
+xenStoreFindWatch(xenStoreWatchListPtr list,
+ const char *path,
+ const char *token)
+{
+ int i;
+ for (i = 0 ; i < list->count ; i++)
+ if( STREQ(path, list->watches[i]->path) &&
+ STREQ(token, list->watches[i]->token) )
+ return list->watches[i];
+
+ return NULL;
+}
+
+static void
+xenStoreWatchEvent(int watch ATTRIBUTE_UNUSED,
+ int fd ATTRIBUTE_UNUSED,
+ int events,
+ void *data)
+{
+ char **event;
+ char *path;
+ char *token;
+ unsigned int stringCount;
+ xenStoreWatchPtr sw;
+
+ virConnectPtr conn = data;
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
+
+ if(!priv) return;
+
+ /* only set a watch on read and write events */
+ if (events & (VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP)) return;
+
+ xenUnifiedLock(priv);
+
+ if(!priv->xshandle)
+ goto cleanup;
+
+ event = xs_read_watch(priv->xshandle, &stringCount);
+ if (!event)
+ goto cleanup;
+
+ path = event[XS_WATCH_PATH];
+ token = event[XS_WATCH_TOKEN];
+
+ sw = xenStoreFindWatch(priv->xsWatchList, path, token);
+ if( sw )
+ sw->cb(conn, path, token, sw->opaque);
+ VIR_FREE(event);
+
+cleanup:
+ xenUnifiedUnlock(priv);
+}
+
+
+/*
+ * The domain callback for the @introduceDomain watch
+ *
+ * The lock on 'priv' is held when calling this
+ */
+int xenStoreDomainIntroduced(virConnectPtr conn,
+ const char *path ATTRIBUTE_UNUSED,
+ const char *token ATTRIBUTE_UNUSED,
+ void *opaque)
+{
+ int i, j, found, missing = 0, retries = 20;
+ int new_domain_cnt;
+ int *new_domids;
+ int nread;
+
+ xenUnifiedPrivatePtr priv = opaque;
+
+retry:
+ new_domain_cnt = xenStoreNumOfDomains(conn);
+ if( VIR_ALLOC_N(new_domids,new_domain_cnt) < 0 ) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+ nread = xenStoreDoListDomains(priv, new_domids, new_domain_cnt);
+ if (nread != new_domain_cnt) {
+ // mismatch. retry this read
+ VIR_FREE(new_domids);
+ goto retry;
+ }
+
+ missing = 0;
+ for (i=0 ; i < new_domain_cnt ; i++) {
+ found = 0;
+ for (j = 0 ; j < priv->activeDomainList->count ; j++) {
+ if (priv->activeDomainList->doms[j]->id == new_domids[i]) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ virDomainEventPtr event;
+ char *name;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+
+ if (!(name = xenStoreDomainGetName(conn, new_domids[i]))) {
+ missing = 1;
+ continue;
+ }
+ if (xenStoreDomainGetUUID(conn, new_domids[i], uuid) < 0) {
+ missing = 1;
+ VIR_FREE(name);
+ continue;
+ }
+
+ event = virDomainEventNew(new_domids[i], name, uuid,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_BOOTED);
+ if (event)
+ xenUnifiedDomainEventDispatch(priv, event);
+
+ /* Add to the list */
+ xenUnifiedAddDomainInfo(priv->activeDomainList,
+ new_domids[i], name, uuid);
+
+ VIR_FREE(name);
+ }
+ }
+ VIR_FREE(new_domids);
+
+ if (missing && retries--) {
+ DEBUG0("Some domains were missing, trying again");
+ usleep(100 * 1000);
+ goto retry;
+ }
+ return 0;
+}
+
+/*
+ * The domain callback for the @destroyDomain watch
+ *
+ * The lock on 'priv' is held when calling this
+ */
+int xenStoreDomainReleased(virConnectPtr conn,
+ const char *path ATTRIBUTE_UNUSED,
+ const char *token ATTRIBUTE_UNUSED,
+ void *opaque)
+{
+ int i, j, found, removed, retries = 20;
+ int new_domain_cnt;
+ int *new_domids;
+ int nread;
+
+ xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) opaque;
+
+ if(!priv->activeDomainList->count) return 0;
+
+retry:
+ new_domain_cnt = xenStoreNumOfDomains(conn);
+
+ if( VIR_ALLOC_N(new_domids,new_domain_cnt) < 0 ) {
+ virReportOOMError(NULL);
+ return -1;
+ }
+ nread = xenStoreDoListDomains(priv, new_domids, new_domain_cnt);
+ if (nread != new_domain_cnt) {
+ // mismatch. retry this read
+ VIR_FREE(new_domids);
+ goto retry;
+ }
+
+ removed = 0;
+ for (j=0 ; j < priv->activeDomainList->count ; j++) {
+ found = 0;
+ for (i=0 ; i < new_domain_cnt ; i++) {
+ if (priv->activeDomainList->doms[j]->id == new_domids[i]) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ virDomainEventPtr event =
+ virDomainEventNew(-1,
+ priv->activeDomainList->doms[j]->name,
+ priv->activeDomainList->doms[j]->uuid,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
+ if (event)
+ xenUnifiedDomainEventDispatch(priv, event);
+
+ /* Remove from the list */
+ xenUnifiedRemoveDomainInfo(priv->activeDomainList,
+ priv->activeDomainList->doms[j]->id,
+ priv->activeDomainList->doms[j]->name,
+ priv->activeDomainList->doms[j]->uuid);
+
+ removed = 1;
+ }
+ }
+
+ VIR_FREE(new_domids);
+
+ if (!removed && retries--) {
+ DEBUG0("No domains removed, retrying");
+ usleep(100 * 1000);
+ goto retry;
+ }
+ return 0;
+}
+
+#endif //PROXY
--- /dev/null
+/*
+ * xs_internal.h: internal API for access to XenStore
+ *
+ * Copyright (C) 2006 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <veillard@redhat.com>
+ */
+
+#ifndef __VIR_XS_INTERNAL_H__
+#define __VIR_XS_INTERNAL_H__
+
+#include "internal.h"
+#include "driver.h"
+
+extern struct xenUnifiedDriver xenStoreDriver;
+int xenStoreInit (void);
+
+virDrvOpenStatus xenStoreOpen (virConnectPtr conn,
+ virConnectAuthPtr auth,
+ int flags);
+int xenStoreClose (virConnectPtr conn);
+int xenStoreGetDomainInfo (virDomainPtr domain,
+ virDomainInfoPtr info);
+int xenStoreNumOfDomains (virConnectPtr conn);
+int xenStoreListDomains (virConnectPtr conn,
+ int *ids,
+ int maxids);
+virDomainPtr xenStoreLookupByName(virConnectPtr conn,
+ const char *name);
+unsigned long xenStoreGetMaxMemory (virDomainPtr domain);
+int xenStoreDomainSetMemory (virDomainPtr domain,
+ unsigned long memory);
+unsigned long xenStoreDomainGetMaxMemory(virDomainPtr domain);
+int xenStoreDomainShutdown (virDomainPtr domain);
+int xenStoreDomainReboot (virDomainPtr domain,
+ unsigned int flags);
+
+/* those are entry point for the proxy */
+int xenStoreDomainGetVNCPort(virConnectPtr conn,
+ int domid);
+char * xenStoreDomainGetConsolePath(virConnectPtr conn,
+ int domid);
+char * xenStoreDomainGetOSTypeID(virConnectPtr conn,
+ int id);
+char * xenStoreDomainGetNetworkID(virConnectPtr conn,
+ int id,
+ const char *mac);
+char * xenStoreDomainGetDiskID(virConnectPtr conn,
+ int id,
+ const char *dev);
+char * xenStoreDomainGetName(virConnectPtr conn,
+ int id);
+int xenStoreDomainGetUUID(virConnectPtr conn,
+ int id,
+ unsigned char *uuid);
+
+typedef int (*xenStoreWatchCallback)(virConnectPtr conn,
+ const char *path,
+ const char *token,
+ void *opaque);
+
+struct _xenStoreWatch {
+ char *path;
+ char *token;
+ xenStoreWatchCallback cb;
+ void *opaque;
+};
+typedef struct _xenStoreWatch xenStoreWatch;
+typedef xenStoreWatch *xenStoreWatchPtr;
+
+struct _xenStoreWatchList {
+ unsigned int count;
+ xenStoreWatchPtr *watches;
+};
+typedef struct _xenStoreWatchList xenStoreWatchList;
+typedef xenStoreWatchList *xenStoreWatchListPtr;
+
+
+int xenStoreAddWatch(virConnectPtr conn,
+ const char *path,
+ const char *token,
+ xenStoreWatchCallback cb,
+ void *opaque);
+int xenStoreRemoveWatch(virConnectPtr conn,
+ const char *path,
+ const char *token);
+
+/* domain events */
+int xenStoreDomainIntroduced(virConnectPtr conn,
+ const char *path,
+ const char *token,
+ void *opaque);
+int xenStoreDomainReleased(virConnectPtr conn,
+ const char *path,
+ const char *token,
+ void *opaque);
+
+int xenStoreDomainEventEmitted(virDomainEventType evt);
+#endif /* __VIR_XS_INTERNAL_H__ */
+++ /dev/null
-/*
- * xen_inofify.c: Xen notification of xml file activity in the
- * following dirs:
- * /etc/xen
- * /var/lib/xend/domains
- *
- * Copyright (C) 2008 VirtualIron
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Ben Guthro
- */
-#include <config.h>
-#include <dirent.h>
-#include <sys/inotify.h>
-
-#include "virterror_internal.h"
-#include "datatypes.h"
-#include "driver.h"
-#include "memory.h"
-#include "event.h"
-#include "xen_unified.h"
-#include "conf.h"
-#include "domain_conf.h"
-#include "xen_inotify.h"
-#include "xend_internal.h"
-#include "logging.h"
-#include "uuid.h"
-
-#include "xm_internal.h" /* for xenXMDomainConfigParse */
-
-#define VIR_FROM_THIS VIR_FROM_XEN_INOTIFY
-
-#define virXenInotifyError(conn, code, fmt...) \
- virReportErrorHelper(NULL, VIR_FROM_XEN_INOTIFY, code, __FILE__, \
- __FUNCTION__, __LINE__, fmt)
-
-#define LIBVIRTD_DOMAINS_DIR "/var/lib/xend/domains"
-
-struct xenUnifiedDriver xenInotifyDriver = {
- xenInotifyOpen, /* open */
- xenInotifyClose, /* close */
- NULL, /* version */
- NULL, /* hostname */
- NULL, /* nodeGetInfo */
- NULL, /* getCapabilities */
- NULL, /* listDomains */
- NULL, /* numOfDomains */
- NULL, /* domainCreateLinux */
- NULL, /* domainSuspend */
- NULL, /* domainResume */
- NULL, /* domainShutdown */
- NULL, /* domainReboot */
- NULL, /* domainDestroy */
- NULL, /* domainGetOSType */
- NULL, /* domainGetMaxMemory */
- NULL, /* domainSetMaxMemory */
- NULL, /* domainSetMemory */
- NULL, /* domainGetInfo */
- NULL, /* domainSave */
- NULL, /* domainRestore */
- NULL, /* domainCoreDump */
- NULL, /* domainSetVcpus */
- NULL, /* domainPinVcpu */
- NULL, /* domainGetVcpus */
- NULL, /* domainGetMaxVcpus */
- NULL, /* listDefinedDomains */
- NULL, /* numOfDefinedDomains */
- NULL, /* domainCreate */
- NULL, /* domainDefineXML */
- NULL, /* domainUndefine */
- NULL, /* domainAttachDevice */
- NULL, /* domainDetachDevice */
- NULL, /* domainGetAutostart */
- NULL, /* domainSetAutostart */
- NULL, /* domainGetSchedulerType */
- NULL, /* domainGetSchedulerParameters */
- NULL, /* domainSetSchedulerParameters */
-};
-
-static int
-xenInotifyXenCacheLookup(virConnectPtr conn,
- const char *filename,
- char **name, unsigned char *uuid) {
- xenUnifiedPrivatePtr priv = conn->privateData;
- xenXMConfCachePtr entry;
-
- if (!(entry = virHashLookup(priv->configCache, filename))) {
- DEBUG("No config found for %s", filename);
- return -1;
- }
-
- *name = strdup(entry->def->name);
- memcpy(uuid, entry->def->uuid, VIR_UUID_BUFLEN);
-
- if (!*name) {
- DEBUG0("Error getting dom from def");
- return -1;
- }
- return 0;
-}
-
-static int
-xenInotifyXendDomainsDirLookup(virConnectPtr conn, const char *filename,
- char **name, unsigned char *uuid) {
- int i;
- virDomainPtr dom;
- const char *uuid_str;
- unsigned char rawuuid[VIR_UUID_BUFLEN];
- xenUnifiedPrivatePtr priv = conn->privateData;
-
- /* xend is managing domains. we will get
- * a filename in the manner:
- * /var/lib/xend/domains/<uuid>/
- */
- uuid_str = filename + strlen(LIBVIRTD_DOMAINS_DIR) + 1;
-
- if (virUUIDParse(uuid_str, rawuuid) < 0) {
- virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- _("parsing uuid %s"), uuid_str);
- return -1;
- }
- /* call directly into xend here, as driver may not yet
- be set during open while we are building our
- initial list of domains */
- DEBUG("Looking for dom with uuid: %s", uuid_str);
- /* XXX Should not have to go via a virDomainPtr obj instance */
- if(!(dom = xenDaemonLookupByUUID(conn, rawuuid))) {
- /* If we are here, the domain has gone away.
- search for, and create a domain from the stored
- list info */
- for (i = 0 ; i < priv->configInfoList->count ; i++) {
- if (!memcmp(uuid, priv->configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN)) {
- *name = strdup(priv->configInfoList->doms[i]->name);
- if (!*name) {
- virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- _("finding dom for %s"), uuid_str);
- return -1;
- }
- memcpy(uuid, priv->configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN);
- DEBUG0("Found dom on list");
- return 0;
- }
- }
- virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("finding dom on config list"));
- return -1;
- }
-
- if (!(*name = strdup(dom->name)))
- return -1;
- memcpy(uuid, dom->uuid, VIR_UUID_BUFLEN);
- virDomainFree(dom);
- /* succeeded too find domain by uuid */
- return 0;
-}
-
-static int
-xenInotifyDomainLookup(virConnectPtr conn,
- const char *filename,
- char **name, unsigned char *uuid) {
- xenUnifiedPrivatePtr priv = conn->privateData;
- if (priv->useXenConfigCache)
- return xenInotifyXenCacheLookup(conn, filename, name, uuid);
- else
- return xenInotifyXendDomainsDirLookup(conn, filename, name, uuid);
-}
-
-static virDomainEventPtr
-xenInotifyDomainEventFromFile(virConnectPtr conn,
- const char *filename,
- int type, int detail) {
- virDomainEventPtr event;
- char *name = NULL;
- unsigned char uuid[VIR_UUID_BUFLEN];
-
- if (xenInotifyDomainLookup(conn, filename, &name, uuid) < 0)
- return NULL;
-
- event = virDomainEventNew(-1, name, uuid, type, detail);
- VIR_FREE(name);
- return event;
-}
-
-static int
-xenInotifyXendDomainsDirRemoveEntry(virConnectPtr conn,
- const char *fname) {
- xenUnifiedPrivatePtr priv = conn->privateData;
- const char *uuidstr = fname + strlen(LIBVIRTD_DOMAINS_DIR) + 1;
- unsigned char uuid[VIR_UUID_BUFLEN];
- int i;
-
- if (virUUIDParse(uuidstr, uuid) < 0) {
- virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- _("parsing uuid %s"), uuidstr);
- return -1;
- }
-
- /* match and remove on uuid */
- for (i = 0 ; i < priv->configInfoList->count ; i++) {
- if (!memcmp(uuid, priv->configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN)) {
- VIR_FREE(priv->configInfoList->doms[i]->name);
- VIR_FREE(priv->configInfoList->doms[i]);
-
- if (i < (priv->configInfoList->count - 1))
- memmove(priv->configInfoList->doms + i,
- priv->configInfoList->doms + i + 1,
- sizeof(*(priv->configInfoList->doms)) *
- (priv->configInfoList->count - (i + 1)));
-
- if (VIR_REALLOC_N(priv->configInfoList->doms,
- priv->configInfoList->count - 1) < 0) {
- ; /* Failure to reduce memory allocation isn't fatal */
- }
- priv->configInfoList->count--;
- return 0;
- }
- }
- return -1;
-}
-
-static int
-xenInotifyXendDomainsDirAddEntry(virConnectPtr conn,
- const char *fname) {
- char *name = NULL;
- unsigned char uuid[VIR_UUID_BUFLEN];
- xenUnifiedPrivatePtr priv = conn->privateData;
-
- if (xenInotifyDomainLookup(conn, fname, &name, uuid) < 0) {
- virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Error looking up domain"));
- return -1;
- }
-
- if (xenUnifiedAddDomainInfo(priv->configInfoList,
- -1, name, uuid) < 0) {
- virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Error adding file to config cache"));
- VIR_FREE(name);
- return -1;
- }
- VIR_FREE(name);
- return 0;
-}
-
-static int
-xenInotifyRemoveDomainConfigInfo(virConnectPtr conn,
- const char *fname) {
- xenUnifiedPrivatePtr priv = conn->privateData;
- return priv->useXenConfigCache ?
- xenXMConfigCacheRemoveFile(conn, fname) :
- xenInotifyXendDomainsDirRemoveEntry(conn, fname);
-}
-
-static int
-xenInotifyAddDomainConfigInfo(virConnectPtr conn,
- const char *fname) {
- xenUnifiedPrivatePtr priv = conn->privateData;
- return priv->useXenConfigCache ?
- xenXMConfigCacheAddFile(conn, fname) :
- xenInotifyXendDomainsDirAddEntry(conn, fname);
-}
-
-static void
-xenInotifyEvent(int watch ATTRIBUTE_UNUSED,
- int fd,
- int events ATTRIBUTE_UNUSED,
- void *data)
-{
- char buf[1024];
- char fname[1024];
- struct inotify_event *e;
- int got;
- char *tmp, *name;
- virConnectPtr conn = data;
- xenUnifiedPrivatePtr priv = NULL;
-
- DEBUG0("got inotify event");
-
- if( conn && conn->privateData ) {
- priv = conn->privateData;
- } else {
- virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("conn, or private data is NULL"));
- return;
- }
-
- xenUnifiedLock(priv);
-
-reread:
- got = read(fd, buf, sizeof(buf));
- if (got == -1) {
- if (errno == EINTR)
- goto reread;
- goto cleanup;
- }
-
- tmp = buf;
- while (got) {
- if (got < sizeof(struct inotify_event))
- goto cleanup; /* bad */
-
- e = (struct inotify_event *)tmp;
- tmp += sizeof(struct inotify_event);
- got -= sizeof(struct inotify_event);
-
- if (got < e->len)
- goto cleanup;
-
- tmp += e->len;
- got -= e->len;
-
- name = (char *)&(e->name);
-
- snprintf(fname, 1024, "%s/%s",
- priv->configDir, name);
-
- if (e->mask & (IN_DELETE | IN_MOVED_FROM)) {
- virDomainEventPtr event =
- xenInotifyDomainEventFromFile(conn, fname,
- VIR_DOMAIN_EVENT_UNDEFINED,
- VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
- if (!event)
- xenUnifiedDomainEventDispatch(conn->privateData, event);
- else
- virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("looking up dom"));
-
- if (xenInotifyRemoveDomainConfigInfo(conn, fname) < 0 ) {
- virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Error adding file to config cache"));
- goto cleanup;
- }
- } else if (e->mask & ( IN_CREATE | IN_CLOSE_WRITE | IN_MOVED_TO) ) {
- virDomainEventPtr event;
- if (xenInotifyAddDomainConfigInfo(conn, fname) < 0 ) {
- virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Error adding file to config cache"));
- goto cleanup;
- }
-
- event = xenInotifyDomainEventFromFile(conn, fname,
- VIR_DOMAIN_EVENT_DEFINED,
- VIR_DOMAIN_EVENT_DEFINED_ADDED);
-
- if (event)
- xenUnifiedDomainEventDispatch(conn->privateData, event);
- else
- virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("looking up dom"));
-
- }
-
- }
-
-cleanup:
- xenUnifiedUnlock(priv);
-}
-
-/**
- * xenInotifyOpen:
- * @conn: pointer to the connection block
- * @name: URL for the target, NULL for local
- * @flags: combination of virDrvOpenFlag(s)
- *
- * Connects and starts listening for inotify events
- *
- * Returns 0 or -1 in case of error.
- */
-virDrvOpenStatus
-xenInotifyOpen(virConnectPtr conn ATTRIBUTE_UNUSED,
- virConnectAuthPtr auth ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED)
-{
- DIR *dh;
- struct dirent *ent;
- char path[PATH_MAX];
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- if (priv->configDir) {
- priv->useXenConfigCache = 1;
- } else {
- /* /var/lib/xend/domains/<uuid>/config.sxp */
- priv->configDir = LIBVIRTD_DOMAINS_DIR;
- priv->useXenConfigCache = 0;
-
- if (VIR_ALLOC(priv->configInfoList) < 0) {
- virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("failed to allocate configInfoList"));
- return -1;
- }
-
- /* populate initial list */
- if (!(dh = opendir(priv->configDir))) {
- virReportSystemError(NULL, errno,
- _("cannot open directory: %s"),
- priv->configDir);
- return -1;
- }
- while ((ent = readdir(dh))) {
- if (STRPREFIX(ent->d_name, "."))
- continue;
-
- /* Build the full file path */
- if ((strlen(priv->configDir) + 1 +
- strlen(ent->d_name) + 1) > PATH_MAX)
- continue;
- strcpy(path, priv->configDir);
- strcat(path, "/");
- strcat(path, ent->d_name);
-
- if (xenInotifyAddDomainConfigInfo(conn, path) < 0 ) {
- virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Error adding file to config list"));
- closedir(dh);
- return -1;
- }
- }
- closedir(dh);
- }
-
- if ((priv->inotifyFD = inotify_init()) < 0) {
- virReportSystemError(NULL, errno,
- "%s", _("initializing inotify"));
- return -1;
- }
-
- DEBUG("Adding a watch on %s", priv->configDir);
- if (inotify_add_watch(priv->inotifyFD,
- priv->configDir,
- IN_CREATE |
- IN_CLOSE_WRITE | IN_DELETE |
- IN_MOVED_TO | IN_MOVED_FROM) < 0) {
- virReportSystemError(NULL, errno,
- _("adding watch on %s"),
- priv->configDir);
- return -1;
- }
-
- DEBUG0("Building initial config cache");
- if (priv->useXenConfigCache &&
- xenXMConfigCacheRefresh (conn) < 0) {
- DEBUG("Failed to enable XM config cache %s", conn->err.message);
- return -1;
- }
-
- DEBUG0("Registering with event loop");
- /* Add the handle for monitoring */
- if ((priv->inotifyWatch = virEventAddHandle(priv->inotifyFD, VIR_EVENT_HANDLE_READABLE,
- xenInotifyEvent, conn, NULL)) < 0) {
- DEBUG0("Failed to add inotify handle, disabling events");
- }
-
- virConnectRef(conn);
- return 0;
-}
-
-/**
- * xenInotifyClose:
- * @conn: pointer to the connection block
- *
- * Close and stop listening for inotify events
- *
- * Returns 0 in case of success or -1 in case of error.
- */
-int
-xenInotifyClose(virConnectPtr conn)
-{
- xenUnifiedPrivatePtr priv = conn->privateData;
-
- if (priv->configInfoList)
- xenUnifiedDomainInfoListFree(priv->configInfoList);
-
- if (priv->inotifyWatch != -1)
- virEventRemoveHandle(priv->inotifyWatch);
- close(priv->inotifyFD);
- virUnrefConnect(conn);
-
- return 0;
-}
+++ /dev/null
-/*
- * xen_inofify.h: Xen notification of xml files
- *
- * Copyright (C) 2008 VirtualIron
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Ben Guthro
- */
-#ifndef __VIR_XEN_INOTIFY_H__
-#define __VIR_XEN_INOTIFY_H__
-
-#include "internal.h"
-#include "driver.h"
-
-extern struct xenUnifiedDriver xenInotifyDriver;
-
-virDrvOpenStatus xenInotifyOpen (virConnectPtr conn,
- virConnectAuthPtr auth,
- int flags);
-int xenInotifyClose (virConnectPtr conn);
-#endif
+++ /dev/null
-/*
- * xen_internal.c: direct access to Xen hypervisor level
- *
- * Copyright (C) 2005, 2006, 2007, 2008, 2009 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Daniel Veillard <veillard@redhat.com>
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <string.h>
-/* required for uint8_t, uint32_t, etc ... */
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/ioctl.h>
-#include <limits.h>
-#include <stdint.h>
-#include <regex.h>
-#include <errno.h>
-#include <sys/utsname.h>
-
-#ifdef __sun
-#include <sys/systeminfo.h>
-
-#include <priv.h>
-
-#ifndef PRIV_XVM_CONTROL
-#define PRIV_XVM_CONTROL ((const char *)"xvm_control")
-#endif
-
-#endif /* __sun */
-
-/* required for dom0_getdomaininfo_t */
-#include <xen/dom0_ops.h>
-#include <xen/version.h>
-#ifdef HAVE_XEN_LINUX_PRIVCMD_H
-#include <xen/linux/privcmd.h>
-#else
-#ifdef HAVE_XEN_SYS_PRIVCMD_H
-#include <xen/sys/privcmd.h>
-#endif
-#endif
-
-/* required for shutdown flags */
-#include <xen/sched.h>
-
-#include "virterror_internal.h"
-#include "logging.h"
-#include "datatypes.h"
-#include "driver.h"
-#include "util.h"
-#include "xen_unified.h"
-#include "xen_internal.h"
-#include "xs_internal.h"
-#include "stats_linux.h"
-#include "xend_internal.h"
-#include "buf.h"
-#include "capabilities.h"
-#include "memory.h"
-
-#define VIR_FROM_THIS VIR_FROM_XEN
-
-/*
- * so far there is 2 versions of the structures usable for doing
- * hypervisor calls.
- */
-/* the old one */
-typedef struct v0_hypercall_struct {
- unsigned long op;
- unsigned long arg[5];
-} v0_hypercall_t;
-
-#ifdef __linux__
-#define XEN_V0_IOCTL_HYPERCALL_CMD \
- _IOC(_IOC_NONE, 'P', 0, sizeof(v0_hypercall_t))
-/* the new one */
-typedef struct v1_hypercall_struct
-{
- uint64_t op;
- uint64_t arg[5];
-} v1_hypercall_t;
-#define XEN_V1_IOCTL_HYPERCALL_CMD \
- _IOC(_IOC_NONE, 'P', 0, sizeof(v1_hypercall_t))
-typedef v1_hypercall_t hypercall_t;
-#elif defined(__sun)
-typedef privcmd_hypercall_t hypercall_t;
-#else
-#error "unsupported platform"
-#endif
-
-#ifndef __HYPERVISOR_sysctl
-#define __HYPERVISOR_sysctl 35
-#endif
-#ifndef __HYPERVISOR_domctl
-#define __HYPERVISOR_domctl 36
-#endif
-
-#ifdef WITH_RHEL5_API
-#define SYS_IFACE_MIN_VERS_NUMA 3
-#else
-#define SYS_IFACE_MIN_VERS_NUMA 4
-#endif
-
-static int xen_ioctl_hypercall_cmd = 0;
-static int initialized = 0;
-static int in_init = 0;
-static int hv_version = 0;
-static int hypervisor_version = 2;
-static int sys_interface_version = -1;
-static int dom_interface_version = -1;
-static int kb_per_pages = 0;
-
-/* Regular expressions used by xenHypervisorGetCapabilities, and
- * compiled once by xenHypervisorInit. Note that these are POSIX.2
- * extended regular expressions (regex(7)).
- */
-static const char *flags_hvm_re = "^flags[[:blank:]]+:.* (vmx|svm)[[:space:]]";
-static regex_t flags_hvm_rec;
-static const char *flags_pae_re = "^flags[[:blank:]]+:.* pae[[:space:]]";
-static regex_t flags_pae_rec;
-static const char *xen_cap_re = "(xen|hvm)-[[:digit:]]+\\.[[:digit:]]+-(x86_32|x86_64|ia64|powerpc64)(p|be)?";
-static regex_t xen_cap_rec;
-
-/*
- * The content of the structures for a getdomaininfolist system hypercall
- */
-#ifndef DOMFLAGS_DYING
-#define DOMFLAGS_DYING (1<<0) /* Domain is scheduled to die. */
-#define DOMFLAGS_HVM (1<<1) /* Domain is HVM */
-#define DOMFLAGS_SHUTDOWN (1<<2) /* The guest OS has shut down. */
-#define DOMFLAGS_PAUSED (1<<3) /* Currently paused by control software. */
-#define DOMFLAGS_BLOCKED (1<<4) /* Currently blocked pending an event. */
-#define DOMFLAGS_RUNNING (1<<5) /* Domain is currently running. */
-#define DOMFLAGS_CPUMASK 255 /* CPU to which this domain is bound. */
-#define DOMFLAGS_CPUSHIFT 8
-#define DOMFLAGS_SHUTDOWNMASK 255 /* DOMFLAGS_SHUTDOWN guest-supplied code. */
-#define DOMFLAGS_SHUTDOWNSHIFT 16
-#endif
-
-/*
- * These flags explain why a system is in the state of "shutdown". Normally,
- * They are defined in xen/sched.h
- */
-#ifndef SHUTDOWN_poweroff
-#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */
-#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */
-#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */
-#define SHUTDOWN_crash 3 /* Tell controller we've crashed. */
-#endif
-
-#define XEN_V0_OP_GETDOMAININFOLIST 38
-#define XEN_V1_OP_GETDOMAININFOLIST 38
-#define XEN_V2_OP_GETDOMAININFOLIST 6
-
-struct xen_v0_getdomaininfo {
- domid_t domain; /* the domain number */
- uint32_t flags; /* flags, see before */
- uint64_t tot_pages; /* total number of pages used */
- uint64_t max_pages; /* maximum number of pages allowed */
- unsigned long shared_info_frame; /* MFN of shared_info struct */
- uint64_t cpu_time; /* CPU time used */
- uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */
- uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
- uint32_t ssidref;
- xen_domain_handle_t handle;
-};
-typedef struct xen_v0_getdomaininfo xen_v0_getdomaininfo;
-
-struct xen_v2_getdomaininfo {
- domid_t domain; /* the domain number */
- uint32_t flags; /* flags, see before */
- uint64_t tot_pages; /* total number of pages used */
- uint64_t max_pages; /* maximum number of pages allowed */
- uint64_t shared_info_frame; /* MFN of shared_info struct */
- uint64_t cpu_time; /* CPU time used */
- uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */
- uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
- uint32_t ssidref;
- xen_domain_handle_t handle;
-};
-typedef struct xen_v2_getdomaininfo xen_v2_getdomaininfo;
-
-
-/* As of Hypervisor Call v2, DomCtl v5 we are now 8-byte aligned
- even on 32-bit archs when dealing with uint64_t */
-#define ALIGN_64 __attribute__((aligned(8)))
-
-struct xen_v2d5_getdomaininfo {
- domid_t domain; /* the domain number */
- uint32_t flags; /* flags, see before */
- uint64_t tot_pages ALIGN_64; /* total number of pages used */
- uint64_t max_pages ALIGN_64; /* maximum number of pages allowed */
- uint64_t shared_info_frame ALIGN_64; /* MFN of shared_info struct */
- uint64_t cpu_time ALIGN_64; /* CPU time used */
- uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */
- uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
- uint32_t ssidref;
- xen_domain_handle_t handle;
-};
-typedef struct xen_v2d5_getdomaininfo xen_v2d5_getdomaininfo;
-
-union xen_getdomaininfo {
- struct xen_v0_getdomaininfo v0;
- struct xen_v2_getdomaininfo v2;
- struct xen_v2d5_getdomaininfo v2d5;
-};
-typedef union xen_getdomaininfo xen_getdomaininfo;
-
-union xen_getdomaininfolist {
- struct xen_v0_getdomaininfo *v0;
- struct xen_v2_getdomaininfo *v2;
- struct xen_v2d5_getdomaininfo *v2d5;
-};
-typedef union xen_getdomaininfolist xen_getdomaininfolist;
-
-
-struct xen_v2_getschedulerid {
- uint32_t sched_id; /* Get Scheduler ID from Xen */
-};
-typedef struct xen_v2_getschedulerid xen_v2_getschedulerid;
-
-
-union xen_getschedulerid {
- struct xen_v2_getschedulerid *v2;
-};
-typedef union xen_getschedulerid xen_getschedulerid;
-
-struct xen_v2s4_availheap {
- uint32_t min_bitwidth; /* Smallest address width (zero if don't care). */
- uint32_t max_bitwidth; /* Largest address width (zero if don't care). */
- int32_t node; /* NUMA node (-1 for sum across all nodes). */
- uint64_t avail_bytes; /* Bytes available in the specified region. */
-};
-
-typedef struct xen_v2s4_availheap xen_v2s4_availheap;
-
-struct xen_v2s5_availheap {
- uint32_t min_bitwidth; /* Smallest address width (zero if don't care). */
- uint32_t max_bitwidth; /* Largest address width (zero if don't care). */
- int32_t node; /* NUMA node (-1 for sum across all nodes). */
- uint64_t avail_bytes ALIGN_64; /* Bytes available in the specified region. */
-};
-
-typedef struct xen_v2s5_availheap xen_v2s5_availheap;
-
-
-#define XEN_GETDOMAININFOLIST_ALLOC(domlist, size) \
- (hypervisor_version < 2 ? \
- (VIR_ALLOC_N(domlist.v0, (size)) == 0) : \
- (dom_interface_version < 5 ? \
- (VIR_ALLOC_N(domlist.v2, (size)) == 0) : \
- (VIR_ALLOC_N(domlist.v2d5, (size)) == 0)))
-
-#define XEN_GETDOMAININFOLIST_FREE(domlist) \
- (hypervisor_version < 2 ? \
- VIR_FREE(domlist.v0) : \
- (dom_interface_version < 5 ? \
- VIR_FREE(domlist.v2) : \
- VIR_FREE(domlist.v2d5)))
-
-#define XEN_GETDOMAININFOLIST_CLEAR(domlist, size) \
- (hypervisor_version < 2 ? \
- memset(domlist.v0, 0, sizeof(*domlist.v0) * size) : \
- (dom_interface_version < 5 ? \
- memset(domlist.v2, 0, sizeof(*domlist.v2) * size) : \
- memset(domlist.v2d5, 0, sizeof(*domlist.v2d5) * size)))
-
-#define XEN_GETDOMAININFOLIST_DOMAIN(domlist, n) \
- (hypervisor_version < 2 ? \
- domlist.v0[n].domain : \
- (dom_interface_version < 5 ? \
- domlist.v2[n].domain : \
- domlist.v2d5[n].domain))
-
-#define XEN_GETDOMAININFOLIST_UUID(domlist, n) \
- (hypervisor_version < 2 ? \
- domlist.v0[n].handle : \
- (dom_interface_version < 5 ? \
- domlist.v2[n].handle : \
- domlist.v2d5[n].handle))
-
-#define XEN_GETDOMAININFOLIST_DATA(domlist) \
- (hypervisor_version < 2 ? \
- (void*)(domlist->v0) : \
- (dom_interface_version < 5 ? \
- (void*)(domlist->v2) : \
- (void*)(domlist->v2d5)))
-
-#define XEN_GETDOMAININFO_SIZE \
- (hypervisor_version < 2 ? \
- sizeof(xen_v0_getdomaininfo) : \
- (dom_interface_version < 5 ? \
- sizeof(xen_v2_getdomaininfo) : \
- sizeof(xen_v2d5_getdomaininfo)))
-
-#define XEN_GETDOMAININFO_CLEAR(dominfo) \
- (hypervisor_version < 2 ? \
- memset(&(dominfo.v0), 0, sizeof(xen_v0_getdomaininfo)) : \
- (dom_interface_version < 5 ? \
- memset(&(dominfo.v2), 0, sizeof(xen_v2_getdomaininfo)) : \
- memset(&(dominfo.v2d5), 0, sizeof(xen_v2d5_getdomaininfo))))
-
-#define XEN_GETDOMAININFO_DOMAIN(dominfo) \
- (hypervisor_version < 2 ? \
- dominfo.v0.domain : \
- (dom_interface_version < 5 ? \
- dominfo.v2.domain : \
- dominfo.v2d5.domain))
-
-#define XEN_GETDOMAININFO_CPUTIME(dominfo) \
- (hypervisor_version < 2 ? \
- dominfo.v0.cpu_time : \
- (dom_interface_version < 5 ? \
- dominfo.v2.cpu_time : \
- dominfo.v2d5.cpu_time))
-
-#define XEN_GETDOMAININFO_CPUCOUNT(dominfo) \
- (hypervisor_version < 2 ? \
- dominfo.v0.nr_online_vcpus : \
- (dom_interface_version < 5 ? \
- dominfo.v2.nr_online_vcpus : \
- dominfo.v2d5.nr_online_vcpus))
-
-#define XEN_GETDOMAININFO_MAXCPUID(dominfo) \
- (hypervisor_version < 2 ? \
- dominfo.v0.max_vcpu_id : \
- (dom_interface_version < 5 ? \
- dominfo.v2.max_vcpu_id : \
- dominfo.v2d5.max_vcpu_id))
-
-#define XEN_GETDOMAININFO_FLAGS(dominfo) \
- (hypervisor_version < 2 ? \
- dominfo.v0.flags : \
- (dom_interface_version < 5 ? \
- dominfo.v2.flags : \
- dominfo.v2d5.flags))
-
-#define XEN_GETDOMAININFO_TOT_PAGES(dominfo) \
- (hypervisor_version < 2 ? \
- dominfo.v0.tot_pages : \
- (dom_interface_version < 5 ? \
- dominfo.v2.tot_pages : \
- dominfo.v2d5.tot_pages))
-
-#define XEN_GETDOMAININFO_MAX_PAGES(dominfo) \
- (hypervisor_version < 2 ? \
- dominfo.v0.max_pages : \
- (dom_interface_version < 5 ? \
- dominfo.v2.max_pages : \
- dominfo.v2d5.max_pages))
-
-#define XEN_GETDOMAININFO_UUID(dominfo) \
- (hypervisor_version < 2 ? \
- dominfo.v0.handle : \
- (dom_interface_version < 5 ? \
- dominfo.v2.handle : \
- dominfo.v2d5.handle))
-
-
-static int
-lock_pages(void *addr, size_t len)
-{
-#ifdef __linux__
- return (mlock(addr, len));
-#elif defined(__sun)
- return (0);
-#endif
-}
-
-static int
-unlock_pages(void *addr, size_t len)
-{
-#ifdef __linux__
- return (munlock(addr, len));
-#elif defined(__sun)
- return (0);
-#endif
-}
-
-
-struct xen_v0_getdomaininfolistop {
- domid_t first_domain;
- uint32_t max_domains;
- struct xen_v0_getdomaininfo *buffer;
- uint32_t num_domains;
-};
-typedef struct xen_v0_getdomaininfolistop xen_v0_getdomaininfolistop;
-
-
-struct xen_v2_getdomaininfolistop {
- domid_t first_domain;
- uint32_t max_domains;
- struct xen_v2_getdomaininfo *buffer;
- uint32_t num_domains;
-};
-typedef struct xen_v2_getdomaininfolistop xen_v2_getdomaininfolistop;
-
-/* As of HV version 2, sysctl version 3 the *buffer pointer is 64-bit aligned */
-struct xen_v2s3_getdomaininfolistop {
- domid_t first_domain;
- uint32_t max_domains;
-#ifdef __BIG_ENDIAN__
- struct {
- int __pad[(sizeof (long long) - sizeof (struct xen_v2d5_getdomaininfo *)) / sizeof (int)];
- struct xen_v2d5_getdomaininfo *v;
- } buffer;
-#else
- union {
- struct xen_v2d5_getdomaininfo *v;
- uint64_t pad ALIGN_64;
- } buffer;
-#endif
- uint32_t num_domains;
-};
-typedef struct xen_v2s3_getdomaininfolistop xen_v2s3_getdomaininfolistop;
-
-
-
-struct xen_v0_domainop {
- domid_t domain;
-};
-typedef struct xen_v0_domainop xen_v0_domainop;
-
-/*
- * The information for a destroydomain system hypercall
- */
-#define XEN_V0_OP_DESTROYDOMAIN 9
-#define XEN_V1_OP_DESTROYDOMAIN 9
-#define XEN_V2_OP_DESTROYDOMAIN 2
-
-/*
- * The information for a pausedomain system hypercall
- */
-#define XEN_V0_OP_PAUSEDOMAIN 10
-#define XEN_V1_OP_PAUSEDOMAIN 10
-#define XEN_V2_OP_PAUSEDOMAIN 3
-
-/*
- * The information for an unpausedomain system hypercall
- */
-#define XEN_V0_OP_UNPAUSEDOMAIN 11
-#define XEN_V1_OP_UNPAUSEDOMAIN 11
-#define XEN_V2_OP_UNPAUSEDOMAIN 4
-
-/*
- * The information for an setmaxmem system hypercall
- */
-#define XEN_V0_OP_SETMAXMEM 28
-#define XEN_V1_OP_SETMAXMEM 28
-#define XEN_V2_OP_SETMAXMEM 11
-
-struct xen_v0_setmaxmem {
- domid_t domain;
- uint64_t maxmem;
-};
-typedef struct xen_v0_setmaxmem xen_v0_setmaxmem;
-typedef struct xen_v0_setmaxmem xen_v1_setmaxmem;
-
-struct xen_v2_setmaxmem {
- uint64_t maxmem;
-};
-typedef struct xen_v2_setmaxmem xen_v2_setmaxmem;
-
-struct xen_v2d5_setmaxmem {
- uint64_t maxmem ALIGN_64;
-};
-typedef struct xen_v2d5_setmaxmem xen_v2d5_setmaxmem;
-
-/*
- * The information for an setmaxvcpu system hypercall
- */
-#define XEN_V0_OP_SETMAXVCPU 41
-#define XEN_V1_OP_SETMAXVCPU 41
-#define XEN_V2_OP_SETMAXVCPU 15
-
-struct xen_v0_setmaxvcpu {
- domid_t domain;
- uint32_t maxvcpu;
-};
-typedef struct xen_v0_setmaxvcpu xen_v0_setmaxvcpu;
-typedef struct xen_v0_setmaxvcpu xen_v1_setmaxvcpu;
-
-struct xen_v2_setmaxvcpu {
- uint32_t maxvcpu;
-};
-typedef struct xen_v2_setmaxvcpu xen_v2_setmaxvcpu;
-
-/*
- * The information for an setvcpumap system hypercall
- * Note that between 1 and 2 the limitation to 64 physical CPU was lifted
- * hence the difference in structures
- */
-#define XEN_V0_OP_SETVCPUMAP 20
-#define XEN_V1_OP_SETVCPUMAP 20
-#define XEN_V2_OP_SETVCPUMAP 9
-
-struct xen_v0_setvcpumap {
- domid_t domain;
- uint32_t vcpu;
- cpumap_t cpumap;
-};
-typedef struct xen_v0_setvcpumap xen_v0_setvcpumap;
-typedef struct xen_v0_setvcpumap xen_v1_setvcpumap;
-
-struct xen_v2_cpumap {
- uint8_t *bitmap;
- uint32_t nr_cpus;
-};
-struct xen_v2_setvcpumap {
- uint32_t vcpu;
- struct xen_v2_cpumap cpumap;
-};
-typedef struct xen_v2_setvcpumap xen_v2_setvcpumap;
-
-/* HV version 2, Dom version 5 requires 64-bit alignment */
-struct xen_v2d5_cpumap {
-#ifdef __BIG_ENDIAN__
- struct {
- int __pad[(sizeof (long long) - sizeof (uint8_t *)) / sizeof (int)];
- uint8_t *v;
- } bitmap;
-#else
- union {
- uint8_t *v;
- uint64_t pad ALIGN_64;
- } bitmap;
-#endif
- uint32_t nr_cpus;
-};
-struct xen_v2d5_setvcpumap {
- uint32_t vcpu;
- struct xen_v2d5_cpumap cpumap;
-};
-typedef struct xen_v2d5_setvcpumap xen_v2d5_setvcpumap;
-
-/*
- * The information for an vcpuinfo system hypercall
- */
-#define XEN_V0_OP_GETVCPUINFO 43
-#define XEN_V1_OP_GETVCPUINFO 43
-#define XEN_V2_OP_GETVCPUINFO 14
-
-struct xen_v0_vcpuinfo {
- domid_t domain; /* owner's domain */
- uint32_t vcpu; /* the vcpu number */
- uint8_t online; /* seen as on line */
- uint8_t blocked; /* blocked on event */
- uint8_t running; /* scheduled on CPU */
- uint64_t cpu_time; /* nanosecond of CPU used */
- uint32_t cpu; /* current mapping */
- cpumap_t cpumap; /* deprecated in V2 */
-};
-typedef struct xen_v0_vcpuinfo xen_v0_vcpuinfo;
-typedef struct xen_v0_vcpuinfo xen_v1_vcpuinfo;
-
-struct xen_v2_vcpuinfo {
- uint32_t vcpu; /* the vcpu number */
- uint8_t online; /* seen as on line */
- uint8_t blocked; /* blocked on event */
- uint8_t running; /* scheduled on CPU */
- uint64_t cpu_time; /* nanosecond of CPU used */
- uint32_t cpu; /* current mapping */
-};
-typedef struct xen_v2_vcpuinfo xen_v2_vcpuinfo;
-
-struct xen_v2d5_vcpuinfo {
- uint32_t vcpu; /* the vcpu number */
- uint8_t online; /* seen as on line */
- uint8_t blocked; /* blocked on event */
- uint8_t running; /* scheduled on CPU */
- uint64_t cpu_time ALIGN_64; /* nanosecond of CPU used */
- uint32_t cpu; /* current mapping */
-};
-typedef struct xen_v2d5_vcpuinfo xen_v2d5_vcpuinfo;
-
-/*
- * from V2 the pinning of a vcpu is read with a separate call
- */
-#define XEN_V2_OP_GETVCPUMAP 25
-typedef struct xen_v2_setvcpumap xen_v2_getvcpumap;
-typedef struct xen_v2d5_setvcpumap xen_v2d5_getvcpumap;
-
-/*
- * from V2 we get the scheduler information
- */
-#define XEN_V2_OP_GETSCHEDULERID 4
-
-/*
- * from V2 we get the available heap information
- */
-#define XEN_V2_OP_GETAVAILHEAP 9
-
-/*
- * from V2 we get the scheduler parameter
- */
-#define XEN_V2_OP_SCHEDULER 16
-/* Scheduler types. */
-#define XEN_SCHEDULER_SEDF 4
-#define XEN_SCHEDULER_CREDIT 5
-/* get/set scheduler parameters */
-#define XEN_DOMCTL_SCHEDOP_putinfo 0
-#define XEN_DOMCTL_SCHEDOP_getinfo 1
-
-struct xen_v2_setschedinfo {
- uint32_t sched_id;
- uint32_t cmd;
- union {
- struct xen_domctl_sched_sedf {
- uint64_t period ALIGN_64;
- uint64_t slice ALIGN_64;
- uint64_t latency ALIGN_64;
- uint32_t extratime;
- uint32_t weight;
- } sedf;
- struct xen_domctl_sched_credit {
- uint16_t weight;
- uint16_t cap;
- } credit;
- } u;
-};
-typedef struct xen_v2_setschedinfo xen_v2_setschedinfo;
-typedef struct xen_v2_setschedinfo xen_v2_getschedinfo;
-
-
-/*
- * The hypercall operation structures also have changed on
- * changeset 86d26e6ec89b
- */
-/* the old structure */
-struct xen_op_v0 {
- uint32_t cmd;
- uint32_t interface_version;
- union {
- xen_v0_getdomaininfolistop getdomaininfolist;
- xen_v0_domainop domain;
- xen_v0_setmaxmem setmaxmem;
- xen_v0_setmaxvcpu setmaxvcpu;
- xen_v0_setvcpumap setvcpumap;
- xen_v0_vcpuinfo getvcpuinfo;
- uint8_t padding[128];
- } u;
-};
-typedef struct xen_op_v0 xen_op_v0;
-typedef struct xen_op_v0 xen_op_v1;
-
-/* the new structure for systems operations */
-struct xen_op_v2_sys {
- uint32_t cmd;
- uint32_t interface_version;
- union {
- xen_v2_getdomaininfolistop getdomaininfolist;
- xen_v2s3_getdomaininfolistop getdomaininfolists3;
- xen_v2_getschedulerid getschedulerid;
- xen_v2s4_availheap availheap;
- xen_v2s5_availheap availheap5;
- uint8_t padding[128];
- } u;
-};
-typedef struct xen_op_v2_sys xen_op_v2_sys;
-
-/* the new structure for domains operation */
-struct xen_op_v2_dom {
- uint32_t cmd;
- uint32_t interface_version;
- domid_t domain;
- union {
- xen_v2_setmaxmem setmaxmem;
- xen_v2d5_setmaxmem setmaxmemd5;
- xen_v2_setmaxvcpu setmaxvcpu;
- xen_v2_setvcpumap setvcpumap;
- xen_v2d5_setvcpumap setvcpumapd5;
- xen_v2_vcpuinfo getvcpuinfo;
- xen_v2d5_vcpuinfo getvcpuinfod5;
- xen_v2_getvcpumap getvcpumap;
- xen_v2d5_getvcpumap getvcpumapd5;
- xen_v2_setschedinfo setschedinfo;
- xen_v2_getschedinfo getschedinfo;
- uint8_t padding[128];
- } u;
-};
-typedef struct xen_op_v2_dom xen_op_v2_dom;
-
-
-#ifdef __linux__
-#define XEN_HYPERVISOR_SOCKET "/proc/xen/privcmd"
-#define HYPERVISOR_CAPABILITIES "/sys/hypervisor/properties/capabilities"
-#elif defined(__sun)
-#define XEN_HYPERVISOR_SOCKET "/dev/xen/privcmd"
-#else
-#error "unsupported platform"
-#endif
-
-#ifndef PROXY
-static unsigned long xenHypervisorGetMaxMemory(virDomainPtr domain);
-#endif
-
-#ifndef PROXY
-struct xenUnifiedDriver xenHypervisorDriver = {
- xenHypervisorOpen, /* open */
- xenHypervisorClose, /* close */
- xenHypervisorGetVersion, /* version */
- NULL, /* hostname */
- NULL, /* nodeGetInfo */
- xenHypervisorGetCapabilities, /* getCapabilities */
- xenHypervisorListDomains, /* listDomains */
- xenHypervisorNumOfDomains, /* numOfDomains */
- NULL, /* domainCreateXML */
- xenHypervisorPauseDomain, /* domainSuspend */
- xenHypervisorResumeDomain, /* domainResume */
- NULL, /* domainShutdown */
- NULL, /* domainReboot */
- xenHypervisorDestroyDomain, /* domainDestroy */
- xenHypervisorDomainGetOSType, /* domainGetOSType */
- xenHypervisorGetMaxMemory, /* domainGetMaxMemory */
- xenHypervisorSetMaxMemory, /* domainSetMaxMemory */
- NULL, /* domainSetMemory */
- xenHypervisorGetDomainInfo, /* domainGetInfo */
- NULL, /* domainSave */
- NULL, /* domainRestore */
- NULL, /* domainCoreDump */
- xenHypervisorSetVcpus, /* domainSetVcpus */
- xenHypervisorPinVcpu, /* domainPinVcpu */
- xenHypervisorGetVcpus, /* domainGetVcpus */
- xenHypervisorGetVcpuMax, /* domainGetMaxVcpus */
- NULL, /* listDefinedDomains */
- NULL, /* numOfDefinedDomains */
- NULL, /* domainCreate */
- NULL, /* domainDefineXML */
- NULL, /* domainUndefine */
- NULL, /* domainAttachDevice */
- NULL, /* domainDetachDevice */
- NULL, /* domainGetAutostart */
- NULL, /* domainSetAutostart */
- xenHypervisorGetSchedulerType, /* domainGetSchedulerType */
- xenHypervisorGetSchedulerParameters, /* domainGetSchedulerParameters */
- xenHypervisorSetSchedulerParameters, /* domainSetSchedulerParameters */
-};
-#endif /* !PROXY */
-
-#define virXenError(conn, code, fmt...) \
- if (in_init == 0) \
- virReportErrorHelper(conn, VIR_FROM_XEN, code, __FILE__, \
- __FUNCTION__, __LINE__, fmt)
-
-#ifndef PROXY
-
-/**
- * virXenErrorFunc:
- * @conn: connection, if known
- * @error: the error number
- * @func: the function failing
- * @info: extra information string
- * @value: extra information number
- *
- * Handle an error at the xend daemon interface
- */
-static void
-virXenErrorFunc(virConnectPtr conn,
- virErrorNumber error, const char *func, const char *info,
- int value)
-{
- char fullinfo[1000];
- const char *errmsg;
-
- if ((error == VIR_ERR_OK) || (in_init != 0))
- return;
-
-
- errmsg =virErrorMsg(error, info);
- if (func != NULL) {
- snprintf(fullinfo, 999, "%s: %s", func, info);
- fullinfo[999] = 0;
- virRaiseError(conn, NULL, NULL, VIR_FROM_XEN, error, VIR_ERR_ERROR,
- errmsg, fullinfo, NULL, value, 0, errmsg, fullinfo,
- value);
- } else {
- virRaiseError(conn, NULL, NULL, VIR_FROM_XEN, error, VIR_ERR_ERROR,
- errmsg, info, NULL, value, 0, errmsg, info,
- value);
- }
-}
-
-#endif /* PROXY */
-
-/**
- * xenHypervisorDoV0Op:
- * @handle: the handle to the Xen hypervisor
- * @op: pointer to the hypervisor operation structure
- *
- * Do an hypervisor operation though the old interface,
- * this leads to an hypervisor call through ioctl.
- *
- * Returns 0 in case of success and -1 in case of error.
- */
-static int
-xenHypervisorDoV0Op(int handle, xen_op_v0 * op)
-{
- int ret;
- v0_hypercall_t hc;
-
- memset(&hc, 0, sizeof(hc));
- op->interface_version = hv_version << 8;
- hc.op = __HYPERVISOR_dom0_op;
- hc.arg[0] = (unsigned long) op;
-
- if (lock_pages(op, sizeof(dom0_op_t)) < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " locking");
- return (-1);
- }
-
- ret = ioctl(handle, xen_ioctl_hypercall_cmd, (unsigned long) &hc);
- if (ret < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " ioctl %d",
- xen_ioctl_hypercall_cmd);
- }
-
- if (unlock_pages(op, sizeof(dom0_op_t)) < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " releasing");
- ret = -1;
- }
-
- if (ret < 0)
- return (-1);
-
- return (0);
-}
-/**
- * xenHypervisorDoV1Op:
- * @handle: the handle to the Xen hypervisor
- * @op: pointer to the hypervisor operation structure
- *
- * Do an hypervisor v1 operation, this leads to an hypervisor call through
- * ioctl.
- *
- * Returns 0 in case of success and -1 in case of error.
- */
-static int
-xenHypervisorDoV1Op(int handle, xen_op_v1* op)
-{
- int ret;
- hypercall_t hc;
-
- memset(&hc, 0, sizeof(hc));
- op->interface_version = DOM0_INTERFACE_VERSION;
- hc.op = __HYPERVISOR_dom0_op;
- hc.arg[0] = (unsigned long) op;
-
- if (lock_pages(op, sizeof(dom0_op_t)) < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " locking");
- return (-1);
- }
-
- ret = ioctl(handle, xen_ioctl_hypercall_cmd, (unsigned long) &hc);
- if (ret < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " ioctl %d",
- xen_ioctl_hypercall_cmd);
- }
-
- if (unlock_pages(op, sizeof(dom0_op_t)) < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " releasing");
- ret = -1;
- }
-
- if (ret < 0)
- return (-1);
-
- return (0);
-}
-
-/**
- * xenHypervisorDoV2Sys:
- * @handle: the handle to the Xen hypervisor
- * @op: pointer to the hypervisor operation structure
- *
- * Do an hypervisor v2 system operation, this leads to an hypervisor
- * call through ioctl.
- *
- * Returns 0 in case of success and -1 in case of error.
- */
-static int
-xenHypervisorDoV2Sys(int handle, xen_op_v2_sys* op)
-{
- int ret;
- hypercall_t hc;
-
- memset(&hc, 0, sizeof(hc));
- op->interface_version = sys_interface_version;
- hc.op = __HYPERVISOR_sysctl;
- hc.arg[0] = (unsigned long) op;
-
- if (lock_pages(op, sizeof(dom0_op_t)) < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " locking");
- return (-1);
- }
-
- ret = ioctl(handle, xen_ioctl_hypercall_cmd, (unsigned long) &hc);
- if (ret < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " sys ioctl %d",
- xen_ioctl_hypercall_cmd);
- }
-
- if (unlock_pages(op, sizeof(dom0_op_t)) < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " releasing");
- ret = -1;
- }
-
- if (ret < 0)
- return (-1);
-
- return (0);
-}
-
-/**
- * xenHypervisorDoV2Dom:
- * @handle: the handle to the Xen hypervisor
- * @op: pointer to the hypervisor domain operation structure
- *
- * Do an hypervisor v2 domain operation, this leads to an hypervisor
- * call through ioctl.
- *
- * Returns 0 in case of success and -1 in case of error.
- */
-static int
-xenHypervisorDoV2Dom(int handle, xen_op_v2_dom* op)
-{
- int ret;
- hypercall_t hc;
-
- memset(&hc, 0, sizeof(hc));
- op->interface_version = dom_interface_version;
- hc.op = __HYPERVISOR_domctl;
- hc.arg[0] = (unsigned long) op;
-
- if (lock_pages(op, sizeof(dom0_op_t)) < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " locking");
- return (-1);
- }
-
- ret = ioctl(handle, xen_ioctl_hypercall_cmd, (unsigned long) &hc);
- if (ret < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " ioctl %d",
- xen_ioctl_hypercall_cmd);
- }
-
- if (unlock_pages(op, sizeof(dom0_op_t)) < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " releasing");
- ret = -1;
- }
-
- if (ret < 0)
- return (-1);
-
- return (0);
-}
-
-/**
- * virXen_getdomaininfolist:
- * @handle: the hypervisor handle
- * @first_domain: first domain in the range
- * @maxids: maximum number of domains to list
- * @dominfos: output structures
- *
- * Do a low level hypercall to list existing domains information
- *
- * Returns the number of domains or -1 in case of failure
- */
-static int
-virXen_getdomaininfolist(int handle, int first_domain, int maxids,
- xen_getdomaininfolist *dominfos)
-{
- int ret = -1;
-
- if (lock_pages(XEN_GETDOMAININFOLIST_DATA(dominfos),
- XEN_GETDOMAININFO_SIZE * maxids) < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " locking");
- return (-1);
- }
- if (hypervisor_version > 1) {
- xen_op_v2_sys op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V2_OP_GETDOMAININFOLIST;
-
- if (sys_interface_version < 3) {
- op.u.getdomaininfolist.first_domain = (domid_t) first_domain;
- op.u.getdomaininfolist.max_domains = maxids;
- op.u.getdomaininfolist.buffer = dominfos->v2;
- op.u.getdomaininfolist.num_domains = maxids;
- } else {
- op.u.getdomaininfolists3.first_domain = (domid_t) first_domain;
- op.u.getdomaininfolists3.max_domains = maxids;
- op.u.getdomaininfolists3.buffer.v = dominfos->v2d5;
- op.u.getdomaininfolists3.num_domains = maxids;
- }
- ret = xenHypervisorDoV2Sys(handle, &op);
-
- if (ret == 0) {
- if (sys_interface_version < 3)
- ret = op.u.getdomaininfolist.num_domains;
- else
- ret = op.u.getdomaininfolists3.num_domains;
- }
- } else if (hypervisor_version == 1) {
- xen_op_v1 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V1_OP_GETDOMAININFOLIST;
- op.u.getdomaininfolist.first_domain = (domid_t) first_domain;
- op.u.getdomaininfolist.max_domains = maxids;
- op.u.getdomaininfolist.buffer = dominfos->v0;
- op.u.getdomaininfolist.num_domains = maxids;
- ret = xenHypervisorDoV1Op(handle, &op);
- if (ret == 0)
- ret = op.u.getdomaininfolist.num_domains;
- } else if (hypervisor_version == 0) {
- xen_op_v0 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V0_OP_GETDOMAININFOLIST;
- op.u.getdomaininfolist.first_domain = (domid_t) first_domain;
- op.u.getdomaininfolist.max_domains = maxids;
- op.u.getdomaininfolist.buffer = dominfos->v0;
- op.u.getdomaininfolist.num_domains = maxids;
- ret = xenHypervisorDoV0Op(handle, &op);
- if (ret == 0)
- ret = op.u.getdomaininfolist.num_domains;
- }
- if (unlock_pages(XEN_GETDOMAININFOLIST_DATA(dominfos),
- XEN_GETDOMAININFO_SIZE * maxids) < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " release");
- ret = -1;
- }
- return(ret);
-}
-
-static int
-virXen_getdomaininfo(int handle, int first_domain,
- xen_getdomaininfo *dominfo) {
- xen_getdomaininfolist dominfos;
-
- if (hypervisor_version < 2) {
- dominfos.v0 = &(dominfo->v0);
- } else {
- dominfos.v2 = &(dominfo->v2);
- }
-
- return virXen_getdomaininfolist(handle, first_domain, 1, &dominfos);
-}
-
-
-#ifndef PROXY
-/**
- * xenHypervisorGetSchedulerType:
- * @domain: pointer to the Xen Hypervisor block
- * @nparams:give a number of scheduler parameters.
- *
- * Do a low level hypercall to get scheduler type
- *
- * Returns scheduler name or NULL in case of failure
- */
-char *
-xenHypervisorGetSchedulerType(virDomainPtr domain, int *nparams)
-{
- char *schedulertype = NULL;
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL)) {
- virXenErrorFunc(NULL, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
- "domain or conn is NULL", 0);
- return NULL;
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->handle < 0) {
- virXenErrorFunc(domain->conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
- "priv->handle invalid", 0);
- return NULL;
- }
- if (domain->id < 0) {
- virXenError(domain->conn, VIR_ERR_OPERATION_INVALID,
- "%s", _("domain is not running"));
- return NULL;
- }
-
- /*
- * Support only dom_interface_version >=5
- * (Xen3.1.0 or later)
- * TODO: check on Xen 3.0.3
- */
- if (dom_interface_version < 5) {
- virXenErrorFunc(domain->conn, VIR_ERR_NO_XEN, __FUNCTION__,
- "unsupported in dom interface < 5", 0);
- return NULL;
- }
-
- if (hypervisor_version > 1) {
- xen_op_v2_sys op;
- int ret;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V2_OP_GETSCHEDULERID;
- ret = xenHypervisorDoV2Sys(priv->handle, &op);
- if (ret < 0)
- return(NULL);
-
- switch (op.u.getschedulerid.sched_id){
- case XEN_SCHEDULER_SEDF:
- schedulertype = strdup("sedf");
- if (nparams)
- *nparams = 6;
- break;
- case XEN_SCHEDULER_CREDIT:
- schedulertype = strdup("credit");
- if (nparams)
- *nparams = 2;
- break;
- default:
- break;
- }
- }
-
- return schedulertype;
-}
-
-static const char *str_weight = "weight";
-static const char *str_cap = "cap";
-
-/**
- * xenHypervisorGetSchedulerParameters:
- * @domain: pointer to the Xen Hypervisor block
- * @params: pointer to scheduler parameters.
- * This memory area should be allocated before calling.
- * @nparams:this parameter should be same as
- * a given number of scheduler parameters.
- * from xenHypervisorGetSchedulerType().
- *
- * Do a low level hypercall to get scheduler parameters
- *
- * Returns 0 or -1 in case of failure
- */
-int
-xenHypervisorGetSchedulerParameters(virDomainPtr domain,
- virSchedParameterPtr params, int *nparams)
-{
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL)) {
- virXenErrorFunc(NULL, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
- "domain or conn is NULL", 0);
- return -1;
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->handle < 0) {
- virXenErrorFunc(domain->conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
- "priv->handle invalid", 0);
- return -1;
- }
- if (domain->id < 0) {
- virXenError(domain->conn, VIR_ERR_OPERATION_INVALID,
- "%s", _("domain is not running"));
- return -1;
- }
-
- /*
- * Support only dom_interface_version >=5
- * (Xen3.1.0 or later)
- * TODO: check on Xen 3.0.3
- */
- if (dom_interface_version < 5) {
- virXenErrorFunc(domain->conn, VIR_ERR_NO_XEN, __FUNCTION__,
- "unsupported in dom interface < 5", 0);
- return -1;
- }
-
- if (hypervisor_version > 1) {
- xen_op_v2_sys op_sys;
- xen_op_v2_dom op_dom;
- int ret;
-
- memset(&op_sys, 0, sizeof(op_sys));
- op_sys.cmd = XEN_V2_OP_GETSCHEDULERID;
- ret = xenHypervisorDoV2Sys(priv->handle, &op_sys);
- if (ret < 0)
- return -1;
-
- switch (op_sys.u.getschedulerid.sched_id){
- case XEN_SCHEDULER_SEDF:
- /* TODO: Implement for Xen/SEDF */
- TODO
- return(-1);
- case XEN_SCHEDULER_CREDIT:
- if (*nparams < 2)
- return(-1);
- memset(&op_dom, 0, sizeof(op_dom));
- op_dom.cmd = XEN_V2_OP_SCHEDULER;
- op_dom.domain = (domid_t) domain->id;
- op_dom.u.getschedinfo.sched_id = XEN_SCHEDULER_CREDIT;
- op_dom.u.getschedinfo.cmd = XEN_DOMCTL_SCHEDOP_getinfo;
- ret = xenHypervisorDoV2Dom(priv->handle, &op_dom);
- if (ret < 0)
- return(-1);
-
- strncpy (params[0].field, str_weight, VIR_DOMAIN_SCHED_FIELD_LENGTH);
- params[0].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
- params[0].type = VIR_DOMAIN_SCHED_FIELD_UINT;
- params[0].value.ui = op_dom.u.getschedinfo.u.credit.weight;
-
- strncpy (params[1].field, str_cap, VIR_DOMAIN_SCHED_FIELD_LENGTH);
- params[1].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
- params[1].type = VIR_DOMAIN_SCHED_FIELD_UINT;
- params[1].value.ui = op_dom.u.getschedinfo.u.credit.cap;
-
- *nparams = 2;
- break;
- default:
- virXenErrorFunc(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "Unknown scheduler", op_sys.u.getschedulerid.sched_id);
- return -1;
- }
- }
-
- return 0;
-}
-
-/**
- * xenHypervisorSetSchedulerParameters:
- * @domain: pointer to the Xen Hypervisor block
- * @nparams:give a number of scheduler setting parameters .
- *
- * Do a low level hypercall to set scheduler parameters
- *
- * Returns 0 or -1 in case of failure
- */
-int
-xenHypervisorSetSchedulerParameters(virDomainPtr domain,
- virSchedParameterPtr params, int nparams)
-{
- int i;
- unsigned int val;
- xenUnifiedPrivatePtr priv;
- char buf[256];
-
- if ((domain == NULL) || (domain->conn == NULL)) {
- virXenErrorFunc (NULL, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
- "domain or conn is NULL", 0);
- return -1;
- }
-
- if ((nparams == 0) || (params == NULL)) {
- virXenErrorFunc (domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "Noparameters given", 0);
- return(-1);
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->handle < 0) {
- virXenErrorFunc(domain->conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
- "priv->handle invalid", 0);
- return -1;
- }
- if (domain->id < 0) {
- virXenError(domain->conn, VIR_ERR_OPERATION_INVALID,
- "%s", _("domain is not running"));
- return -1;
- }
-
- /*
- * Support only dom_interface_version >=5
- * (Xen3.1.0 or later)
- * TODO: check on Xen 3.0.3
- */
- if (dom_interface_version < 5) {
- virXenErrorFunc(domain->conn, VIR_ERR_NO_XEN, __FUNCTION__,
- "unsupported in dom interface < 5", 0);
- return -1;
- }
-
- if (hypervisor_version > 1) {
- xen_op_v2_sys op_sys;
- xen_op_v2_dom op_dom;
- int ret;
-
- memset(&op_sys, 0, sizeof(op_sys));
- op_sys.cmd = XEN_V2_OP_GETSCHEDULERID;
- ret = xenHypervisorDoV2Sys(priv->handle, &op_sys);
- if (ret == -1) return -1;
-
- switch (op_sys.u.getschedulerid.sched_id){
- case XEN_SCHEDULER_SEDF:
- /* TODO: Implement for Xen/SEDF */
- TODO
- return(-1);
- case XEN_SCHEDULER_CREDIT: {
- memset(&op_dom, 0, sizeof(op_dom));
- op_dom.cmd = XEN_V2_OP_SCHEDULER;
- op_dom.domain = (domid_t) domain->id;
- op_dom.u.getschedinfo.sched_id = XEN_SCHEDULER_CREDIT;
- op_dom.u.getschedinfo.cmd = XEN_DOMCTL_SCHEDOP_putinfo;
-
- /*
- * credit scheduler parameters
- * following values do not change the parameters
- */
- op_dom.u.getschedinfo.u.credit.weight = 0;
- op_dom.u.getschedinfo.u.credit.cap = (uint16_t)~0U;
-
- for (i = 0; i < nparams; i++) {
- memset(&buf, 0, sizeof(buf));
- if (STREQ (params[i].field, str_weight) &&
- params[i].type == VIR_DOMAIN_SCHED_FIELD_UINT) {
- val = params[i].value.ui;
- if ((val < 1) || (val > USHRT_MAX)) {
- snprintf(buf, sizeof(buf), _("Credit scheduler weight parameter (%d) is out of range (1-65535)"), val);
- virXenErrorFunc (domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__, buf, val);
- return(-1);
- }
- op_dom.u.getschedinfo.u.credit.weight = val;
- } else if (STREQ (params[i].field, str_cap) &&
- params[i].type == VIR_DOMAIN_SCHED_FIELD_UINT) {
- val = params[i].value.ui;
- if (val > USHRT_MAX) {
- snprintf(buf, sizeof(buf), _("Credit scheduler cap parameter (%d) is out of range (0-65535)"), val);
- virXenErrorFunc (domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__, buf, val);
- return(-1);
- }
- op_dom.u.getschedinfo.u.credit.cap = val;
- } else {
- virXenErrorFunc (domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "Credit scheduler accepts 'cap' and 'weight' integer parameters",
- 0);
- return(-1);
- }
- }
-
- ret = xenHypervisorDoV2Dom(priv->handle, &op_dom);
- if (ret < 0)
- return -1;
- break;
- }
- default:
- virXenErrorFunc(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "Unknown scheduler", op_sys.u.getschedulerid.sched_id);
- return -1;
- }
- }
-
- return 0;
-}
-
-
-int
-xenHypervisorDomainBlockStats (virDomainPtr dom,
- const char *path,
- struct _virDomainBlockStats *stats)
-{
-#ifdef __linux__
- xenUnifiedPrivatePtr priv;
- int ret;
-
- priv = (xenUnifiedPrivatePtr) dom->conn->privateData;
- xenUnifiedLock(priv);
- /* Need to lock because it hits the xenstore handle :-( */
- ret = xenLinuxDomainBlockStats (priv, dom, path, stats);
- xenUnifiedUnlock(priv);
- return ret;
-#else
- virXenErrorFunc (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__,
- "block statistics not supported on this platform",
- dom->id);
- return -1;
-#endif
-}
-
-/* Paths have the form vif<domid>.<n> (this interface checks that
- * <domid> is the real domain ID and returns an error if not).
- *
- * In future we may allow you to query bridge stats (virbrX or
- * xenbrX), but that will probably be through a separate
- * virNetwork interface, as yet not decided.
- */
-int
-xenHypervisorDomainInterfaceStats (virDomainPtr dom,
- const char *path,
- struct _virDomainInterfaceStats *stats)
-{
-#ifdef __linux__
- int rqdomid, device;
-
- /* Verify that the vif requested is one belonging to the current
- * domain.
- */
- if (sscanf (path, "vif%d.%d", &rqdomid, &device) != 2) {
- virXenErrorFunc (dom->conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "invalid path, should be vif<domid>.<n>.", 0);
- return -1;
- }
- if (rqdomid != dom->id) {
- virXenErrorFunc (dom->conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "invalid path, vif<domid> should match this domain ID", 0);
- return -1;
- }
-
- return linuxDomainInterfaceStats (dom->conn, path, stats);
-#else
- virXenErrorFunc (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__,
- "/proc/net/dev: Interface not found", 0);
- return -1;
-#endif
-}
-
-/**
- * virXen_pausedomain:
- * @handle: the hypervisor handle
- * @id: the domain id
- *
- * Do a low level hypercall to pause the domain
- *
- * Returns 0 or -1 in case of failure
- */
-static int
-virXen_pausedomain(int handle, int id)
-{
- int ret = -1;
-
- if (hypervisor_version > 1) {
- xen_op_v2_dom op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V2_OP_PAUSEDOMAIN;
- op.domain = (domid_t) id;
- ret = xenHypervisorDoV2Dom(handle, &op);
- } else if (hypervisor_version == 1) {
- xen_op_v1 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V1_OP_PAUSEDOMAIN;
- op.u.domain.domain = (domid_t) id;
- ret = xenHypervisorDoV1Op(handle, &op);
- } else if (hypervisor_version == 0) {
- xen_op_v0 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V0_OP_PAUSEDOMAIN;
- op.u.domain.domain = (domid_t) id;
- ret = xenHypervisorDoV0Op(handle, &op);
- }
- return(ret);
-}
-
-/**
- * virXen_unpausedomain:
- * @handle: the hypervisor handle
- * @id: the domain id
- *
- * Do a low level hypercall to unpause the domain
- *
- * Returns 0 or -1 in case of failure
- */
-static int
-virXen_unpausedomain(int handle, int id)
-{
- int ret = -1;
-
- if (hypervisor_version > 1) {
- xen_op_v2_dom op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V2_OP_UNPAUSEDOMAIN;
- op.domain = (domid_t) id;
- ret = xenHypervisorDoV2Dom(handle, &op);
- } else if (hypervisor_version == 1) {
- xen_op_v1 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V1_OP_UNPAUSEDOMAIN;
- op.u.domain.domain = (domid_t) id;
- ret = xenHypervisorDoV1Op(handle, &op);
- } else if (hypervisor_version == 0) {
- xen_op_v0 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V0_OP_UNPAUSEDOMAIN;
- op.u.domain.domain = (domid_t) id;
- ret = xenHypervisorDoV0Op(handle, &op);
- }
- return(ret);
-}
-
-/**
- * virXen_destroydomain:
- * @handle: the hypervisor handle
- * @id: the domain id
- *
- * Do a low level hypercall to destroy the domain
- *
- * Returns 0 or -1 in case of failure
- */
-static int
-virXen_destroydomain(int handle, int id)
-{
- int ret = -1;
-
- if (hypervisor_version > 1) {
- xen_op_v2_dom op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V2_OP_DESTROYDOMAIN;
- op.domain = (domid_t) id;
- ret = xenHypervisorDoV2Dom(handle, &op);
- } else if (hypervisor_version == 1) {
- xen_op_v1 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V1_OP_DESTROYDOMAIN;
- op.u.domain.domain = (domid_t) id;
- ret = xenHypervisorDoV1Op(handle, &op);
- } else if (hypervisor_version == 0) {
- xen_op_v0 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V0_OP_DESTROYDOMAIN;
- op.u.domain.domain = (domid_t) id;
- ret = xenHypervisorDoV0Op(handle, &op);
- }
- return(ret);
-}
-
-/**
- * virXen_setmaxmem:
- * @handle: the hypervisor handle
- * @id: the domain id
- * @memory: the amount of memory in kilobytes
- *
- * Do a low level hypercall to change the max memory amount
- *
- * Returns 0 or -1 in case of failure
- */
-static int
-virXen_setmaxmem(int handle, int id, unsigned long memory)
-{
- int ret = -1;
-
- if (hypervisor_version > 1) {
- xen_op_v2_dom op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V2_OP_SETMAXMEM;
- op.domain = (domid_t) id;
- if (dom_interface_version < 5)
- op.u.setmaxmem.maxmem = memory;
- else
- op.u.setmaxmemd5.maxmem = memory;
- ret = xenHypervisorDoV2Dom(handle, &op);
- } else if (hypervisor_version == 1) {
- xen_op_v1 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V1_OP_SETMAXMEM;
- op.u.setmaxmem.domain = (domid_t) id;
- op.u.setmaxmem.maxmem = memory;
- ret = xenHypervisorDoV1Op(handle, &op);
- } else if (hypervisor_version == 0) {
- xen_op_v0 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V0_OP_SETMAXMEM;
- op.u.setmaxmem.domain = (domid_t) id;
- op.u.setmaxmem.maxmem = memory;
- ret = xenHypervisorDoV0Op(handle, &op);
- }
- return(ret);
-}
-
-/**
- * virXen_setmaxvcpus:
- * @handle: the hypervisor handle
- * @id: the domain id
- * @vcpus: the numbers of vcpus
- *
- * Do a low level hypercall to change the max vcpus amount
- *
- * Returns 0 or -1 in case of failure
- */
-static int
-virXen_setmaxvcpus(int handle, int id, unsigned int vcpus)
-{
- int ret = -1;
-
- if (hypervisor_version > 1) {
- xen_op_v2_dom op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V2_OP_SETMAXVCPU;
- op.domain = (domid_t) id;
- op.u.setmaxvcpu.maxvcpu = vcpus;
- ret = xenHypervisorDoV2Dom(handle, &op);
- } else if (hypervisor_version == 1) {
- xen_op_v1 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V1_OP_SETMAXVCPU;
- op.u.setmaxvcpu.domain = (domid_t) id;
- op.u.setmaxvcpu.maxvcpu = vcpus;
- ret = xenHypervisorDoV1Op(handle, &op);
- } else if (hypervisor_version == 0) {
- xen_op_v0 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V0_OP_SETMAXVCPU;
- op.u.setmaxvcpu.domain = (domid_t) id;
- op.u.setmaxvcpu.maxvcpu = vcpus;
- ret = xenHypervisorDoV0Op(handle, &op);
- }
- return(ret);
-}
-
-/**
- * virXen_setvcpumap:
- * @handle: the hypervisor handle
- * @id: the domain id
- * @vcpu: the vcpu to map
- * @cpumap: the bitmap for this vcpu
- * @maplen: the size of the bitmap in bytes
- *
- * Do a low level hypercall to change the pinning for vcpu
- *
- * Returns 0 or -1 in case of failure
- */
-static int
-virXen_setvcpumap(int handle, int id, unsigned int vcpu,
- unsigned char * cpumap, int maplen)
-{
- int ret = -1;
- unsigned char *new = NULL;
- unsigned char *bitmap = NULL;
- uint32_t nr_cpus;
-
- if (hypervisor_version > 1) {
- xen_op_v2_dom op;
-
- if (lock_pages(cpumap, maplen) < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " locking");
- return (-1);
- }
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V2_OP_SETVCPUMAP;
- op.domain = (domid_t) id;
-
- /* The allocated memory to cpumap must be 'sizeof(uint64_t)' byte *
- * for Xen, and also nr_cpus must be 'sizeof(uint64_t) * 8' */
- if (maplen < 8) {
- if (VIR_ALLOC_N(new, sizeof(uint64_t)) < 0) {
- virReportOOMError(NULL);
- return (-1);
- }
- memcpy(new, cpumap, maplen);
- bitmap = new;
- nr_cpus = sizeof(uint64_t) * 8;
- } else {
- bitmap = cpumap;
- nr_cpus = maplen * 8;
- }
-
- if (dom_interface_version < 5) {
- op.u.setvcpumap.vcpu = vcpu;
- op.u.setvcpumap.cpumap.bitmap = bitmap;
- op.u.setvcpumap.cpumap.nr_cpus = nr_cpus;
- } else {
- op.u.setvcpumapd5.vcpu = vcpu;
- op.u.setvcpumapd5.cpumap.bitmap.v = bitmap;
- op.u.setvcpumapd5.cpumap.nr_cpus = nr_cpus;
- }
- ret = xenHypervisorDoV2Dom(handle, &op);
- VIR_FREE(new);
-
- if (unlock_pages(cpumap, maplen) < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " release");
- ret = -1;
- }
- } else {
- cpumap_t xen_cpumap; /* limited to 64 CPUs in old hypervisors */
- uint64_t *pm = &xen_cpumap;
- int j;
-
- if ((maplen > (int)sizeof(cpumap_t)) || (sizeof(cpumap_t) & 7))
- return (-1);
-
- memset(pm, 0, sizeof(cpumap_t));
- for (j = 0; j < maplen; j++)
- *(pm + (j / 8)) |= cpumap[j] << (8 * (j & 7));
-
- if (hypervisor_version == 1) {
- xen_op_v1 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V1_OP_SETVCPUMAP;
- op.u.setvcpumap.domain = (domid_t) id;
- op.u.setvcpumap.vcpu = vcpu;
- op.u.setvcpumap.cpumap = xen_cpumap;
- ret = xenHypervisorDoV1Op(handle, &op);
- } else if (hypervisor_version == 0) {
- xen_op_v0 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V0_OP_SETVCPUMAP;
- op.u.setvcpumap.domain = (domid_t) id;
- op.u.setvcpumap.vcpu = vcpu;
- op.u.setvcpumap.cpumap = xen_cpumap;
- ret = xenHypervisorDoV0Op(handle, &op);
- }
- }
- return(ret);
-}
-#endif /* !PROXY*/
-
-/**
- * virXen_getvcpusinfo:
- * @handle: the hypervisor handle
- * @id: the domain id
- * @vcpu: the vcpu to map
- * @cpumap: the bitmap for this vcpu
- * @maplen: the size of the bitmap in bytes
- *
- * Do a low level hypercall to change the pinning for vcpu
- *
- * Returns 0 or -1 in case of failure
- */
-static int
-virXen_getvcpusinfo(int handle, int id, unsigned int vcpu, virVcpuInfoPtr ipt,
- unsigned char *cpumap, int maplen)
-{
- int ret = -1;
-
- if (hypervisor_version > 1) {
- xen_op_v2_dom op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V2_OP_GETVCPUINFO;
- op.domain = (domid_t) id;
- if (dom_interface_version < 5)
- op.u.getvcpuinfo.vcpu = (uint16_t) vcpu;
- else
- op.u.getvcpuinfod5.vcpu = (uint16_t) vcpu;
- ret = xenHypervisorDoV2Dom(handle, &op);
-
- if (ret < 0)
- return(-1);
- ipt->number = vcpu;
- if (dom_interface_version < 5) {
- if (op.u.getvcpuinfo.online) {
- if (op.u.getvcpuinfo.running)
- ipt->state = VIR_VCPU_RUNNING;
- if (op.u.getvcpuinfo.blocked)
- ipt->state = VIR_VCPU_BLOCKED;
- } else
- ipt->state = VIR_VCPU_OFFLINE;
-
- ipt->cpuTime = op.u.getvcpuinfo.cpu_time;
- ipt->cpu = op.u.getvcpuinfo.online ? (int)op.u.getvcpuinfo.cpu : -1;
- } else {
- if (op.u.getvcpuinfod5.online) {
- if (op.u.getvcpuinfod5.running)
- ipt->state = VIR_VCPU_RUNNING;
- if (op.u.getvcpuinfod5.blocked)
- ipt->state = VIR_VCPU_BLOCKED;
- } else
- ipt->state = VIR_VCPU_OFFLINE;
-
- ipt->cpuTime = op.u.getvcpuinfod5.cpu_time;
- ipt->cpu = op.u.getvcpuinfod5.online ? (int)op.u.getvcpuinfod5.cpu : -1;
- }
- if ((cpumap != NULL) && (maplen > 0)) {
- if (lock_pages(cpumap, maplen) < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " locking");
- return (-1);
- }
- memset(cpumap, 0, maplen);
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V2_OP_GETVCPUMAP;
- op.domain = (domid_t) id;
- if (dom_interface_version < 5) {
- op.u.getvcpumap.vcpu = vcpu;
- op.u.getvcpumap.cpumap.bitmap = cpumap;
- op.u.getvcpumap.cpumap.nr_cpus = maplen * 8;
- } else {
- op.u.getvcpumapd5.vcpu = vcpu;
- op.u.getvcpumapd5.cpumap.bitmap.v = cpumap;
- op.u.getvcpumapd5.cpumap.nr_cpus = maplen * 8;
- }
- ret = xenHypervisorDoV2Dom(handle, &op);
- if (unlock_pages(cpumap, maplen) < 0) {
- virXenError(NULL, VIR_ERR_XEN_CALL, " release");
- ret = -1;
- }
- }
- } else {
- int mapl = maplen;
- int cpu;
-
- if (maplen > (int)sizeof(cpumap_t))
- mapl = (int)sizeof(cpumap_t);
-
- if (hypervisor_version == 1) {
- xen_op_v1 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V1_OP_GETVCPUINFO;
- op.u.getvcpuinfo.domain = (domid_t) id;
- op.u.getvcpuinfo.vcpu = vcpu;
- ret = xenHypervisorDoV1Op(handle, &op);
- if (ret < 0)
- return(-1);
- ipt->number = vcpu;
- if (op.u.getvcpuinfo.online) {
- if (op.u.getvcpuinfo.running) ipt->state = VIR_VCPU_RUNNING;
- if (op.u.getvcpuinfo.blocked) ipt->state = VIR_VCPU_BLOCKED;
- }
- else ipt->state = VIR_VCPU_OFFLINE;
- ipt->cpuTime = op.u.getvcpuinfo.cpu_time;
- ipt->cpu = op.u.getvcpuinfo.online ? (int)op.u.getvcpuinfo.cpu : -1;
- if ((cpumap != NULL) && (maplen > 0)) {
- for (cpu = 0; cpu < (mapl * 8); cpu++) {
- if (op.u.getvcpuinfo.cpumap & ((uint64_t)1<<cpu))
- VIR_USE_CPU(cpumap, cpu);
- }
- }
- } else if (hypervisor_version == 0) {
- xen_op_v1 op;
-
- memset(&op, 0, sizeof(op));
- op.cmd = XEN_V0_OP_GETVCPUINFO;
- op.u.getvcpuinfo.domain = (domid_t) id;
- op.u.getvcpuinfo.vcpu = vcpu;
- ret = xenHypervisorDoV0Op(handle, &op);
- if (ret < 0)
- return(-1);
- ipt->number = vcpu;
- if (op.u.getvcpuinfo.online) {
- if (op.u.getvcpuinfo.running) ipt->state = VIR_VCPU_RUNNING;
- if (op.u.getvcpuinfo.blocked) ipt->state = VIR_VCPU_BLOCKED;
- }
- else ipt->state = VIR_VCPU_OFFLINE;
- ipt->cpuTime = op.u.getvcpuinfo.cpu_time;
- ipt->cpu = op.u.getvcpuinfo.online ? (int)op.u.getvcpuinfo.cpu : -1;
- if ((cpumap != NULL) && (maplen > 0)) {
- for (cpu = 0; cpu < (mapl * 8); cpu++) {
- if (op.u.getvcpuinfo.cpumap & ((uint64_t)1<<cpu))
- VIR_USE_CPU(cpumap, cpu);
- }
- }
- }
- }
- return(ret);
-}
-
-/**
- * xenHypervisorInit:
- *
- * Initialize the hypervisor layer. Try to detect the kind of interface
- * used i.e. pre or post changeset 10277
- */
-int
-xenHypervisorInit(void)
-{
- int fd, ret, cmd, errcode;
- hypercall_t hc;
- v0_hypercall_t v0_hc;
- xen_getdomaininfo info;
- virVcpuInfoPtr ipt = NULL;
-
- if (initialized) {
- if (hypervisor_version == -1)
- return (-1);
- return(0);
- }
- initialized = 1;
- in_init = 1;
-
- /* Compile regular expressions used by xenHypervisorGetCapabilities.
- * Note that errors here are really internal errors since these
- * regexps should never fail to compile.
- */
- errcode = regcomp (&flags_hvm_rec, flags_hvm_re, REG_EXTENDED);
- if (errcode != 0) {
- char error[100];
- regerror (errcode, &flags_hvm_rec, error, sizeof error);
- regfree (&flags_hvm_rec);
- virXenError (NULL, VIR_ERR_INTERNAL_ERROR, "%s", error);
- in_init = 0;
- return -1;
- }
- errcode = regcomp (&flags_pae_rec, flags_pae_re, REG_EXTENDED);
- if (errcode != 0) {
- char error[100];
- regerror (errcode, &flags_pae_rec, error, sizeof error);
- regfree (&flags_pae_rec);
- regfree (&flags_hvm_rec);
- virXenError (NULL, VIR_ERR_INTERNAL_ERROR, "%s", error);
- in_init = 0;
- return -1;
- }
- errcode = regcomp (&xen_cap_rec, xen_cap_re, REG_EXTENDED);
- if (errcode != 0) {
- char error[100];
- regerror (errcode, &xen_cap_rec, error, sizeof error);
- regfree (&xen_cap_rec);
- regfree (&flags_pae_rec);
- regfree (&flags_hvm_rec);
- virXenError (NULL, VIR_ERR_INTERNAL_ERROR, "%s", error);
- in_init = 0;
- return -1;
- }
-
- /* Xen hypervisor version detection begins. */
- ret = open(XEN_HYPERVISOR_SOCKET, O_RDWR);
- if (ret < 0) {
- hypervisor_version = -1;
- return(-1);
- }
- fd = ret;
-
- /*
- * The size of the hypervisor call block changed July 2006
- * this detect if we are using the new or old hypercall_t structure
- */
- hc.op = __HYPERVISOR_xen_version;
- hc.arg[0] = (unsigned long) XENVER_version;
- hc.arg[1] = 0;
-
- cmd = IOCTL_PRIVCMD_HYPERCALL;
- ret = ioctl(fd, cmd, (unsigned long) &hc);
-
- if ((ret != -1) && (ret != 0)) {
- DEBUG("Using new hypervisor call: %X\n", ret);
- hv_version = ret;
- xen_ioctl_hypercall_cmd = cmd;
- goto detect_v2;
- }
-
-#ifndef __sun
- /*
- * check if the old hypercall are actually working
- */
- v0_hc.op = __HYPERVISOR_xen_version;
- v0_hc.arg[0] = (unsigned long) XENVER_version;
- v0_hc.arg[1] = 0;
- cmd = _IOC(_IOC_NONE, 'P', 0, sizeof(v0_hypercall_t));
- ret = ioctl(fd, cmd, (unsigned long) &v0_hc);
- if ((ret != -1) && (ret != 0)) {
- DEBUG("Using old hypervisor call: %X\n", ret);
- hv_version = ret;
- xen_ioctl_hypercall_cmd = cmd;
- hypervisor_version = 0;
- goto done;
- }
-#endif
-
- /*
- * we failed to make any hypercall
- */
-
- hypervisor_version = -1;
- virXenError(NULL, VIR_ERR_XEN_CALL, " ioctl %lu",
- (unsigned long) IOCTL_PRIVCMD_HYPERCALL);
- close(fd);
- in_init = 0;
- return(-1);
-
- detect_v2:
- /*
- * The hypercalls were refactored into 3 different section in August 2006
- * Try to detect if we are running a version post 3.0.2 with the new ones
- * or the old ones
- */
- hypervisor_version = 2;
-
- if (VIR_ALLOC(ipt) < 0) {
- virReportOOMError(NULL);
- return(-1);
- }
- /* Currently consider RHEL5.0 Fedora7, xen-3.1, and xen-unstable */
- sys_interface_version = 2; /* XEN_SYSCTL_INTERFACE_VERSION */
- if (virXen_getdomaininfo(fd, 0, &info) == 1) {
- /* RHEL 5.0 */
- dom_interface_version = 3; /* XEN_DOMCTL_INTERFACE_VERSION */
- if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0){
- DEBUG0("Using hypervisor call v2, sys ver2 dom ver3\n");
- goto done;
- }
- /* Fedora 7 */
- dom_interface_version = 4; /* XEN_DOMCTL_INTERFACE_VERSION */
- if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0){
- DEBUG0("Using hypervisor call v2, sys ver2 dom ver4\n");
- goto done;
- }
- }
-
- sys_interface_version = 3; /* XEN_SYSCTL_INTERFACE_VERSION */
- if (virXen_getdomaininfo(fd, 0, &info) == 1) {
- /* xen-3.1 */
- dom_interface_version = 5; /* XEN_DOMCTL_INTERFACE_VERSION */
- if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0){
- DEBUG0("Using hypervisor call v2, sys ver3 dom ver5\n");
- goto done;
- }
- }
-
- sys_interface_version = 4; /* XEN_SYSCTL_INTERFACE_VERSION */
- if (virXen_getdomaininfo(fd, 0, &info) == 1) {
- /* Fedora 8 */
- dom_interface_version = 5; /* XEN_DOMCTL_INTERFACE_VERSION */
- if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0){
- DEBUG0("Using hypervisor call v2, sys ver4 dom ver5\n");
- goto done;
- }
- }
-
- sys_interface_version = 6; /* XEN_SYSCTL_INTERFACE_VERSION */
- if (virXen_getdomaininfo(fd, 0, &info) == 1) {
- /* Xen 3.2, Fedora 9 */
- dom_interface_version = 5; /* XEN_DOMCTL_INTERFACE_VERSION */
- if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0){
- DEBUG0("Using hypervisor call v2, sys ver6 dom ver5\n");
- goto done;
- }
- }
-
- hypervisor_version = 1;
- sys_interface_version = -1;
- if (virXen_getdomaininfo(fd, 0, &info) == 1) {
- DEBUG0("Using hypervisor call v1\n");
- goto done;
- }
-
- /*
- * we failed to make the getdomaininfolist hypercall
- */
-
- DEBUG0("Failed to find any Xen hypervisor method\n");
- hypervisor_version = -1;
- virXenError(NULL, VIR_ERR_XEN_CALL, " ioctl %lu",
- (unsigned long)IOCTL_PRIVCMD_HYPERCALL);
- close(fd);
- in_init = 0;
- VIR_FREE(ipt);
- return(-1);
-
- done:
- close(fd);
- in_init = 0;
- VIR_FREE(ipt);
- return(0);
-}
-
-/**
- * xenHypervisorOpen:
- * @conn: pointer to the connection block
- * @name: URL for the target, NULL for local
- * @flags: combination of virDrvOpenFlag(s)
- *
- * Connects to the Xen hypervisor.
- *
- * Returns 0 or -1 in case of error.
- */
-virDrvOpenStatus
-xenHypervisorOpen(virConnectPtr conn,
- virConnectAuthPtr auth ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED)
-{
- int ret;
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- if (initialized == 0)
- if (xenHypervisorInit() == -1)
- return -1;
-
- priv->handle = -1;
-
- ret = open(XEN_HYPERVISOR_SOCKET, O_RDWR);
- if (ret < 0) {
- virXenError(conn, VIR_ERR_NO_XEN, "%s", XEN_HYPERVISOR_SOCKET);
- return (-1);
- }
-
- priv->handle = ret;
-
- return(0);
-}
-
-/**
- * xenHypervisorClose:
- * @conn: pointer to the connection block
- *
- * Close the connection to the Xen hypervisor.
- *
- * Returns 0 in case of success or -1 in case of error.
- */
-int
-xenHypervisorClose(virConnectPtr conn)
-{
- int ret;
- xenUnifiedPrivatePtr priv;
-
- if (conn == NULL)
- return (-1);
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- if (priv->handle < 0)
- return -1;
-
- ret = close(priv->handle);
- if (ret < 0)
- return (-1);
-
- return (0);
-}
-
-
-/**
- * xenHypervisorGetVersion:
- * @conn: pointer to the connection block
- * @hvVer: where to store the version
- *
- * Call the hypervisor to extracts his own internal API version
- *
- * Returns 0 in case of success, -1 in case of error
- */
-int
-xenHypervisorGetVersion(virConnectPtr conn, unsigned long *hvVer)
-{
- xenUnifiedPrivatePtr priv;
-
- if (conn == NULL)
- return -1;
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->handle < 0 || hvVer == NULL)
- return (-1);
- *hvVer = (hv_version >> 16) * 1000000 + (hv_version & 0xFFFF) * 1000;
- return(0);
-}
-
-struct guest_arch {
- const char *model;
- int bits;
- int hvm;
- int pae;
- int nonpae;
- int ia64_be;
-};
-
-
-static virCapsPtr
-xenHypervisorBuildCapabilities(virConnectPtr conn,
- const char *hostmachine,
- int host_pae,
- const char *hvm_type,
- struct guest_arch *guest_archs,
- int nr_guest_archs) {
- virCapsPtr caps;
- int i;
- int hv_major = hv_version >> 16;
- int hv_minor = hv_version & 0xFFFF;
-
- if ((caps = virCapabilitiesNew(hostmachine, 1, 1)) == NULL)
- goto no_memory;
-
- virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x00, 0x16, 0x3e });
-
- if (hvm_type && STRNEQ(hvm_type, "") &&
- virCapabilitiesAddHostFeature(caps, hvm_type) < 0)
- goto no_memory;
- if (host_pae &&
- virCapabilitiesAddHostFeature(caps, "pae") < 0)
- goto no_memory;
-
-
- if (virCapabilitiesAddHostMigrateTransport(caps,
- "xenmigr") < 0)
- goto no_memory;
-
-
- if (sys_interface_version >= SYS_IFACE_MIN_VERS_NUMA) {
- if (xenDaemonNodeGetTopology(conn, caps) != 0) {
- virCapabilitiesFree(caps);
- return NULL;
- }
- }
-
- for (i = 0; i < nr_guest_archs; ++i) {
- virCapsGuestPtr guest;
- char const *const xen_machines[] = {guest_archs[i].hvm ? "xenfv" : "xenpv"};
- virCapsGuestMachinePtr *machines;
-
- if ((machines = virCapabilitiesAllocMachines(xen_machines, 1)) == NULL)
- goto no_memory;
-
- if ((guest = virCapabilitiesAddGuest(caps,
- guest_archs[i].hvm ? "hvm" : "xen",
- guest_archs[i].model,
- guest_archs[i].bits,
- (STREQ(hostmachine, "x86_64") ?
- "/usr/lib64/xen/bin/qemu-dm" :
- "/usr/lib/xen/bin/qemu-dm"),
- (guest_archs[i].hvm ?
- "/usr/lib/xen/boot/hvmloader" :
- NULL),
- 1,
- machines)) == NULL) {
- virCapabilitiesFreeMachines(machines, 1);
- goto no_memory;
- }
- machines = NULL;
-
- if (virCapabilitiesAddGuestDomain(guest,
- "xen",
- NULL,
- NULL,
- 0,
- NULL) == NULL)
- goto no_memory;
-
- if (guest_archs[i].pae &&
- virCapabilitiesAddGuestFeature(guest,
- "pae",
- 1,
- 0) == NULL)
- goto no_memory;
-
- if (guest_archs[i].nonpae &&
- virCapabilitiesAddGuestFeature(guest,
- "nonpae",
- 1,
- 0) == NULL)
- goto no_memory;
-
- if (guest_archs[i].ia64_be &&
- virCapabilitiesAddGuestFeature(guest,
- "ia64_be",
- 1,
- 0) == NULL)
- goto no_memory;
-
- if (guest_archs[i].hvm) {
- if (virCapabilitiesAddGuestFeature(guest,
- "acpi",
- 1, 1) == NULL)
- goto no_memory;
-
- // In Xen 3.1.0, APIC is always on and can't be toggled
- if (virCapabilitiesAddGuestFeature(guest,
- "apic",
- 1,
- (hv_major > 3 &&
- hv_minor > 0 ?
- 0 : 1)) == NULL)
- goto no_memory;
- }
- }
-
- return caps;
-
- no_memory:
- virCapabilitiesFree(caps);
- return NULL;
-}
-
-#ifdef __sun
-
-static int
-get_cpu_flags(virConnectPtr conn, const char **hvm, int *pae, int *longmode)
-{
- struct {
- uint32_t r_eax, r_ebx, r_ecx, r_edx;
- } regs;
-
- char tmpbuf[20];
- int ret = 0;
- int fd;
-
- /* returns -1, errno 22 if in 32-bit mode */
- *longmode = (sysinfo(SI_ARCHITECTURE_64, tmpbuf, sizeof(tmpbuf)) != -1);
-
- if ((fd = open("/dev/cpu/self/cpuid", O_RDONLY)) == -1 ||
- pread(fd, ®s, sizeof(regs), 0) != sizeof(regs)) {
- char ebuf[1024];
- virXenError(conn, VIR_ERR_SYSTEM_ERROR,
- "couldn't read CPU flags: %s", virStrerror(errno, ebuf, sizeof ebuf));
- goto out;
- }
-
- *pae = 0;
- *hvm = "";
-
- if (STREQLEN((const char *)®s.r_ebx, "AuthcAMDenti", 12)) {
- if (pread(fd, ®s, sizeof (regs), 0x80000001) == sizeof (regs)) {
- /* Read secure virtual machine bit (bit 2 of ECX feature ID) */
- if ((regs.r_ecx >> 2) & 1) {
- *hvm = "svm";
- }
- if ((regs.r_edx >> 6) & 1)
- *pae = 1;
- }
- } else if (STREQLEN((const char *)®s.r_ebx, "GenuntelineI", 12)) {
- if (pread(fd, ®s, sizeof (regs), 0x00000001) == sizeof (regs)) {
- /* Read VMXE feature bit (bit 5 of ECX feature ID) */
- if ((regs.r_ecx >> 5) & 1)
- *hvm = "vmx";
- if ((regs.r_edx >> 6) & 1)
- *pae = 1;
- }
- }
-
- ret = 1;
-
-out:
- if (fd != -1)
- close(fd);
- return ret;
-}
-
-static virCapsPtr
-xenHypervisorMakeCapabilitiesSunOS(virConnectPtr conn)
-{
- struct guest_arch guest_arches[32];
- int i = 0;
- virCapsPtr caps = NULL;
- struct utsname utsname;
- int pae, longmode;
- const char *hvm;
-
- if (!get_cpu_flags(conn, &hvm, &pae, &longmode))
- return NULL;
-
- /* Really, this never fails - look at the man-page. */
- uname (&utsname);
-
- guest_arches[i].model = "i686";
- guest_arches[i].bits = 32;
- guest_arches[i].hvm = 0;
- guest_arches[i].pae = pae;
- guest_arches[i].nonpae = !pae;
- guest_arches[i].ia64_be = 0;
- i++;
-
- if (longmode) {
- guest_arches[i].model = "x86_64";
- guest_arches[i].bits = 64;
- guest_arches[i].hvm = 0;
- guest_arches[i].pae = 0;
- guest_arches[i].nonpae = 0;
- guest_arches[i].ia64_be = 0;
- i++;
- }
-
- if (hvm[0] != '\0') {
- guest_arches[i].model = "i686";
- guest_arches[i].bits = 32;
- guest_arches[i].hvm = 1;
- guest_arches[i].pae = pae;
- guest_arches[i].nonpae = 1;
- guest_arches[i].ia64_be = 0;
- i++;
-
- if (longmode) {
- guest_arches[i].model = "x86_64";
- guest_arches[i].bits = 64;
- guest_arches[i].hvm = 1;
- guest_arches[i].pae = 0;
- guest_arches[i].nonpae = 0;
- guest_arches[i].ia64_be = 0;
- i++;
- }
- }
-
- if ((caps = xenHypervisorBuildCapabilities(conn,
- utsname.machine,
- pae, hvm,
- guest_arches, i)) == NULL)
- virReportOOMError(NULL);
-
- return caps;
-}
-
-#endif /* __sun */
-
-/**
- * xenHypervisorMakeCapabilitiesInternal:
- * @conn: pointer to the connection block
- * @cpuinfo: file handle containing /proc/cpuinfo data, or NULL
- * @capabilities: file handle containing /sys/hypervisor/properties/capabilities data, or NULL
- *
- * Return the capabilities of this hypervisor.
- */
-virCapsPtr
-xenHypervisorMakeCapabilitiesInternal(virConnectPtr conn,
- const char *hostmachine,
- FILE *cpuinfo, FILE *capabilities)
-{
- char line[1024], *str, *token;
- regmatch_t subs[4];
- char *saveptr = NULL;
- int i;
-
- char hvm_type[4] = ""; /* "vmx" or "svm" (or "" if not in CPU). */
- int host_pae = 0;
- struct guest_arch guest_archs[32];
- int nr_guest_archs = 0;
- virCapsPtr caps = NULL;
-
- memset(guest_archs, 0, sizeof(guest_archs));
-
- /* /proc/cpuinfo: flags: Intel calls HVM "vmx", AMD calls it "svm".
- * It's not clear if this will work on IA64, let alone other
- * architectures and non-Linux. (XXX)
- */
- if (cpuinfo) {
- while (fgets (line, sizeof line, cpuinfo)) {
- if (regexec (&flags_hvm_rec, line, sizeof(subs)/sizeof(regmatch_t), subs, 0) == 0
- && subs[0].rm_so != -1) {
- strncpy (hvm_type,
- &line[subs[1].rm_so], subs[1].rm_eo-subs[1].rm_so+1);
- hvm_type[subs[1].rm_eo-subs[1].rm_so] = '\0';
- } else if (regexec (&flags_pae_rec, line, 0, NULL, 0) == 0)
- host_pae = 1;
- }
- }
-
- /* Most of the useful info is in /sys/hypervisor/properties/capabilities
- * which is documented in the code in xen-unstable.hg/xen/arch/.../setup.c.
- *
- * It is a space-separated list of supported guest architectures.
- *
- * For x86:
- * TYP-VER-ARCH[p]
- * ^ ^ ^ ^
- * | | | +-- PAE supported
- * | | +------- x86_32 or x86_64
- * | +----------- the version of Xen, eg. "3.0"
- * +--------------- "xen" or "hvm" for para or full virt respectively
- *
- * For PPC this file appears to be always empty (?)
- *
- * For IA64:
- * TYP-VER-ARCH[be]
- * ^ ^ ^ ^
- * | | | +-- Big-endian supported
- * | | +------- always "ia64"
- * | +----------- the version of Xen, eg. "3.0"
- * +--------------- "xen" or "hvm" for para or full virt respectively
- */
-
- /* Expecting one line in this file - ignore any more. */
- if ((capabilities) && (fgets (line, sizeof line, capabilities))) {
- /* Split the line into tokens. strtok_r is OK here because we "own"
- * this buffer. Parse out the features from each token.
- */
- for (str = line, nr_guest_archs = 0;
- nr_guest_archs < sizeof guest_archs / sizeof guest_archs[0]
- && (token = strtok_r (str, " ", &saveptr)) != NULL;
- str = NULL) {
-
- if (regexec (&xen_cap_rec, token, sizeof subs / sizeof subs[0],
- subs, 0) == 0) {
- int hvm = STRPREFIX(&token[subs[1].rm_so], "hvm");
- const char *model;
- int bits, pae = 0, nonpae = 0, ia64_be = 0;
-
- if (STRPREFIX(&token[subs[2].rm_so], "x86_32")) {
- model = "i686";
- bits = 32;
- if (subs[3].rm_so != -1 &&
- STRPREFIX(&token[subs[3].rm_so], "p"))
- pae = 1;
- else
- nonpae = 1;
- }
- else if (STRPREFIX(&token[subs[2].rm_so], "x86_64")) {
- model = "x86_64";
- bits = 64;
- }
- else if (STRPREFIX(&token[subs[2].rm_so], "ia64")) {
- model = "ia64";
- bits = 64;
- if (subs[3].rm_so != -1 &&
- STRPREFIX(&token[subs[3].rm_so], "be"))
- ia64_be = 1;
- }
- else if (STRPREFIX(&token[subs[2].rm_so], "powerpc64")) {
- model = "ppc64";
- bits = 64;
- } else {
- /* XXX surely no other Xen archs exist */
- continue;
- }
-
- /* Search for existing matching (model,hvm) tuple */
- for (i = 0 ; i < nr_guest_archs ; i++) {
- if (STREQ(guest_archs[i].model, model) &&
- guest_archs[i].hvm == hvm) {
- break;
- }
- }
-
- /* Too many arch flavours - highly unlikely ! */
- if (i >= ARRAY_CARDINALITY(guest_archs))
- continue;
- /* Didn't find a match, so create a new one */
- if (i == nr_guest_archs)
- nr_guest_archs++;
-
- guest_archs[i].model = model;
- guest_archs[i].bits = bits;
- guest_archs[i].hvm = hvm;
-
- /* Careful not to overwrite a previous positive
- setting with a negative one here - some archs
- can do both pae & non-pae, but Xen reports
- separately capabilities so we're merging archs */
- if (pae)
- guest_archs[i].pae = pae;
- if (nonpae)
- guest_archs[i].nonpae = nonpae;
- if (ia64_be)
- guest_archs[i].ia64_be = ia64_be;
- }
- }
- }
-
- if ((caps = xenHypervisorBuildCapabilities(conn,
- hostmachine,
- host_pae,
- hvm_type,
- guest_archs,
- nr_guest_archs)) == NULL)
- goto no_memory;
-
- return caps;
-
- no_memory:
- virReportOOMError(NULL);
- virCapabilitiesFree(caps);
- return NULL;
-}
-
-/**
- * xenHypervisorMakeCapabilities:
- *
- * Return the capabilities of this hypervisor.
- */
-virCapsPtr
-xenHypervisorMakeCapabilities(virConnectPtr conn)
-{
-#ifdef __sun
- return xenHypervisorMakeCapabilitiesSunOS(conn);
-#else
- virCapsPtr caps;
- FILE *cpuinfo, *capabilities;
- struct utsname utsname;
-
- /* Really, this never fails - look at the man-page. */
- uname (&utsname);
-
- cpuinfo = fopen ("/proc/cpuinfo", "r");
- if (cpuinfo == NULL) {
- if (errno != ENOENT) {
- virReportSystemError(conn, errno,
- _("cannot read file %s"),
- "/proc/cpuinfo");
- return NULL;
- }
- }
-
- capabilities = fopen ("/sys/hypervisor/properties/capabilities", "r");
- if (capabilities == NULL) {
- if (errno != ENOENT) {
- fclose(cpuinfo);
- virReportSystemError(conn, errno,
- _("cannot read file %s"),
- "/sys/hypervisor/properties/capabilities");
- return NULL;
- }
- }
-
- caps = xenHypervisorMakeCapabilitiesInternal(conn,
- utsname.machine,
- cpuinfo,
- capabilities);
-
- if (cpuinfo)
- fclose(cpuinfo);
- if (capabilities)
- fclose(capabilities);
-
- return caps;
-#endif /* __sun */
-}
-
-
-
-/**
- * xenHypervisorGetCapabilities:
- * @conn: pointer to the connection block
- *
- * Return the capabilities of this hypervisor.
- */
-char *
-xenHypervisorGetCapabilities (virConnectPtr conn)
-{
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
- char *xml;
-
- if (!(xml = virCapabilitiesFormatXML(priv->caps))) {
- virReportOOMError(conn);
- return NULL;
- }
-
- return xml;
-}
-
-
-/**
- * xenHypervisorNumOfDomains:
- * @conn: pointer to the connection block
- *
- * Provides the number of active domains.
- *
- * Returns the number of domain found or -1 in case of error
- */
-int
-xenHypervisorNumOfDomains(virConnectPtr conn)
-{
- xen_getdomaininfolist dominfos;
- int ret, nbids;
- static int last_maxids = 2;
- int maxids = last_maxids;
- xenUnifiedPrivatePtr priv;
-
- if (conn == NULL)
- return -1;
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->handle < 0)
- return (-1);
-
- retry:
- if (!(XEN_GETDOMAININFOLIST_ALLOC(dominfos, maxids))) {
- virReportOOMError(conn);
- return(-1);
- }
-
- XEN_GETDOMAININFOLIST_CLEAR(dominfos, maxids);
-
- ret = virXen_getdomaininfolist(priv->handle, 0, maxids, &dominfos);
-
- XEN_GETDOMAININFOLIST_FREE(dominfos);
-
- if (ret < 0)
- return (-1);
-
- nbids = ret;
- /* Can't possibly have more than 65,000 concurrent guests
- * so limit how many times we try, to avoid increasing
- * without bound & thus allocating all of system memory !
- * XXX I'll regret this comment in a few years time ;-)
- */
- if (nbids == maxids) {
- if (maxids < 65000) {
- last_maxids *= 2;
- maxids *= 2;
- goto retry;
- }
- nbids = -1;
- }
- if ((nbids < 0) || (nbids > maxids))
- return(-1);
- return(nbids);
-}
-
-/**
- * xenHypervisorListDomains:
- * @conn: pointer to the connection block
- * @ids: array to collect the list of IDs of active domains
- * @maxids: size of @ids
- *
- * Collect the list of active domains, and store their ID in @maxids
- *
- * Returns the number of domain found or -1 in case of error
- */
-int
-xenHypervisorListDomains(virConnectPtr conn, int *ids, int maxids)
-{
- xen_getdomaininfolist dominfos;
- int ret, nbids, i;
- xenUnifiedPrivatePtr priv;
-
- if (conn == NULL)
- return -1;
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->handle < 0 ||
- (ids == NULL) || (maxids < 0))
- return (-1);
-
- if (maxids == 0)
- return(0);
-
- if (!(XEN_GETDOMAININFOLIST_ALLOC(dominfos, maxids))) {
- virReportOOMError(conn);
- return(-1);
- }
-
- XEN_GETDOMAININFOLIST_CLEAR(dominfos, maxids);
- memset(ids, 0, maxids * sizeof(int));
-
- ret = virXen_getdomaininfolist(priv->handle, 0, maxids, &dominfos);
-
- if (ret < 0) {
- XEN_GETDOMAININFOLIST_FREE(dominfos);
- return (-1);
- }
-
- nbids = ret;
- if ((nbids < 0) || (nbids > maxids)) {
- XEN_GETDOMAININFOLIST_FREE(dominfos);
- return(-1);
- }
-
- for (i = 0;i < nbids;i++) {
- ids[i] = XEN_GETDOMAININFOLIST_DOMAIN(dominfos, i);
- }
-
- XEN_GETDOMAININFOLIST_FREE(dominfos);
- return (nbids);
-}
-
-
-#ifndef PROXY
-char *
-xenHypervisorDomainGetOSType (virDomainPtr dom)
-{
- xenUnifiedPrivatePtr priv;
- xen_getdomaininfo dominfo;
-
- priv = (xenUnifiedPrivatePtr) dom->conn->privateData;
- if (priv->handle < 0)
- return (NULL);
-
- /* HV's earlier than 3.1.0 don't include the HVM flags in guests status*/
- if (hypervisor_version < 2 ||
- dom_interface_version < 4)
- return (NULL);
-
- XEN_GETDOMAININFO_CLEAR(dominfo);
-
- if (virXen_getdomaininfo(priv->handle, dom->id, &dominfo) < 0)
- return (NULL);
-
- if (XEN_GETDOMAININFO_DOMAIN(dominfo) != dom->id)
- return (NULL);
-
- if (XEN_GETDOMAININFO_FLAGS(dominfo) & DOMFLAGS_HVM)
- return strdup("hvm");
- return strdup("linux");
-}
-
-virDomainPtr
-xenHypervisorLookupDomainByID(virConnectPtr conn,
- int id)
-{
- xenUnifiedPrivatePtr priv;
- xen_getdomaininfo dominfo;
- virDomainPtr ret;
- char *name;
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->handle < 0)
- return (NULL);
-
- XEN_GETDOMAININFO_CLEAR(dominfo);
-
- if (virXen_getdomaininfo(priv->handle, id, &dominfo) < 0)
- return (NULL);
-
- if (XEN_GETDOMAININFO_DOMAIN(dominfo) != id)
- return (NULL);
-
- xenUnifiedLock(priv);
- name = xenStoreDomainGetName(conn, id);
- xenUnifiedUnlock(priv);
- if (!name)
- return (NULL);
-
- ret = virGetDomain(conn, name, XEN_GETDOMAININFO_UUID(dominfo));
- if (ret)
- ret->id = id;
- VIR_FREE(name);
- return ret;
-}
-
-
-virDomainPtr
-xenHypervisorLookupDomainByUUID(virConnectPtr conn,
- const unsigned char *uuid)
-{
- xen_getdomaininfolist dominfos;
- xenUnifiedPrivatePtr priv;
- virDomainPtr ret;
- char *name;
- int maxids = 100, nids, i, id;
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->handle < 0)
- return (NULL);
-
- retry:
- if (!(XEN_GETDOMAININFOLIST_ALLOC(dominfos, maxids))) {
- virReportOOMError(conn);
- return(NULL);
- }
-
- XEN_GETDOMAININFOLIST_CLEAR(dominfos, maxids);
-
- nids = virXen_getdomaininfolist(priv->handle, 0, maxids, &dominfos);
-
- if (nids < 0) {
- XEN_GETDOMAININFOLIST_FREE(dominfos);
- return (NULL);
- }
-
- /* Can't possibly have more than 65,000 concurrent guests
- * so limit how many times we try, to avoid increasing
- * without bound & thus allocating all of system memory !
- * XXX I'll regret this comment in a few years time ;-)
- */
- if (nids == maxids) {
- XEN_GETDOMAININFOLIST_FREE(dominfos);
- if (maxids < 65000) {
- maxids *= 2;
- goto retry;
- }
- return (NULL);
- }
-
- id = -1;
- for (i = 0 ; i < nids ; i++) {
- if (memcmp(XEN_GETDOMAININFOLIST_UUID(dominfos, i), uuid, VIR_UUID_BUFLEN) == 0) {
- id = XEN_GETDOMAININFOLIST_DOMAIN(dominfos, i);
- break;
- }
- }
- XEN_GETDOMAININFOLIST_FREE(dominfos);
-
- if (id == -1)
- return (NULL);
-
- xenUnifiedLock(priv);
- name = xenStoreDomainGetName(conn, id);
- xenUnifiedUnlock(priv);
- if (!name)
- return (NULL);
-
- ret = virGetDomain(conn, name, uuid);
- if (ret)
- ret->id = id;
- VIR_FREE(name);
- return ret;
-}
-#endif
-
-/**
- * xenHypervisorGetMaxVcpus:
- *
- * Returns the maximum of CPU defined by Xen.
- */
-int
-xenHypervisorGetMaxVcpus(virConnectPtr conn,
- const char *type ATTRIBUTE_UNUSED)
-{
- xenUnifiedPrivatePtr priv;
-
- if (conn == NULL)
- return -1;
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->handle < 0)
- return (-1);
-
- return MAX_VIRT_CPUS;
-}
-
-/**
- * xenHypervisorGetDomMaxMemory:
- * @conn: connection data
- * @id: domain id
- *
- * Retrieve the maximum amount of physical memory allocated to a
- * domain.
- *
- * Returns the memory size in kilobytes or 0 in case of error.
- */
-unsigned long
-xenHypervisorGetDomMaxMemory(virConnectPtr conn, int id)
-{
- xenUnifiedPrivatePtr priv;
- xen_getdomaininfo dominfo;
- int ret;
-
- if (conn == NULL)
- return 0;
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->handle < 0)
- return 0;
-
- if (kb_per_pages == 0) {
- kb_per_pages = sysconf(_SC_PAGESIZE) / 1024;
- if (kb_per_pages <= 0)
- kb_per_pages = 4;
- }
-
- XEN_GETDOMAININFO_CLEAR(dominfo);
-
- ret = virXen_getdomaininfo(priv->handle, id, &dominfo);
-
- if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != id))
- return (0);
-
- return((unsigned long) XEN_GETDOMAININFO_MAX_PAGES(dominfo) * kb_per_pages);
-}
-
-#ifndef PROXY
-/**
- * xenHypervisorGetMaxMemory:
- * @domain: a domain object or NULL
- *
- * Retrieve the maximum amount of physical memory allocated to a
- * domain. If domain is NULL, then this get the amount of memory reserved
- * to Domain0 i.e. the domain where the application runs.
- *
- * Returns the memory size in kilobytes or 0 in case of error.
- */
-static unsigned long
-xenHypervisorGetMaxMemory(virDomainPtr domain)
-{
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL))
- return 0;
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->handle < 0 || domain->id < 0)
- return (0);
-
- return(xenHypervisorGetDomMaxMemory(domain->conn, domain->id));
-}
-#endif
-
-/**
- * xenHypervisorGetDomInfo:
- * @conn: connection data
- * @id: the domain ID
- * @info: the place where information should be stored
- *
- * Do an hypervisor call to get the related set of domain information.
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-int
-xenHypervisorGetDomInfo(virConnectPtr conn, int id, virDomainInfoPtr info)
-{
- xenUnifiedPrivatePtr priv;
- xen_getdomaininfo dominfo;
- int ret;
- uint32_t domain_flags, domain_state, domain_shutdown_cause;
-
- if (kb_per_pages == 0) {
- kb_per_pages = sysconf(_SC_PAGESIZE) / 1024;
- if (kb_per_pages <= 0)
- kb_per_pages = 4;
- }
-
- if (conn == NULL)
- return -1;
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->handle < 0 || info == NULL)
- return (-1);
-
- memset(info, 0, sizeof(virDomainInfo));
- XEN_GETDOMAININFO_CLEAR(dominfo);
-
- ret = virXen_getdomaininfo(priv->handle, id, &dominfo);
-
- if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != id))
- return (-1);
-
- domain_flags = XEN_GETDOMAININFO_FLAGS(dominfo);
- domain_flags &= ~DOMFLAGS_HVM; /* Mask out HVM flags */
- domain_state = domain_flags & 0xFF; /* Mask out high bits */
- switch (domain_state) {
- case DOMFLAGS_DYING:
- info->state = VIR_DOMAIN_SHUTDOWN;
- break;
- case DOMFLAGS_SHUTDOWN:
- /* The domain is shutdown. Determine the cause. */
- domain_shutdown_cause = domain_flags >> DOMFLAGS_SHUTDOWNSHIFT;
- switch (domain_shutdown_cause) {
- case SHUTDOWN_crash:
- info->state = VIR_DOMAIN_CRASHED;
- break;
- default:
- info->state = VIR_DOMAIN_SHUTOFF;
- }
- break;
- case DOMFLAGS_PAUSED:
- info->state = VIR_DOMAIN_PAUSED;
- break;
- case DOMFLAGS_BLOCKED:
- info->state = VIR_DOMAIN_BLOCKED;
- break;
- case DOMFLAGS_RUNNING:
- info->state = VIR_DOMAIN_RUNNING;
- break;
- default:
- info->state = VIR_DOMAIN_NOSTATE;
- }
-
- /*
- * the API brings back the cpu time in nanoseconds,
- * convert to microseconds, same thing convert to
- * kilobytes from page counts
- */
- info->cpuTime = XEN_GETDOMAININFO_CPUTIME(dominfo);
- info->memory = XEN_GETDOMAININFO_TOT_PAGES(dominfo) * kb_per_pages;
- info->maxMem = XEN_GETDOMAININFO_MAX_PAGES(dominfo);
- if(info->maxMem != UINT_MAX)
- info->maxMem *= kb_per_pages;
- info->nrVirtCpu = XEN_GETDOMAININFO_CPUCOUNT(dominfo);
- return (0);
-}
-
-/**
- * xenHypervisorGetDomainInfo:
- * @domain: pointer to the domain block
- * @info: the place where information should be stored
- *
- * Do an hypervisor call to get the related set of domain information.
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-int
-xenHypervisorGetDomainInfo(virDomainPtr domain, virDomainInfoPtr info)
-{
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL))
- return -1;
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->handle < 0 || info == NULL ||
- (domain->id < 0))
- return (-1);
-
- return(xenHypervisorGetDomInfo(domain->conn, domain->id, info));
-
-}
-
-#ifndef PROXY
-/**
- * xenHypervisorNodeGetCellsFreeMemory:
- * @conn: pointer to the hypervisor connection
- * @freeMems: pointer to the array of unsigned long long
- * @startCell: index of first cell to return freeMems info on.
- * @maxCells: Maximum number of cells for which freeMems information can
- * be returned.
- *
- * This call returns the amount of free memory in one or more NUMA cells.
- * The @freeMems array must be allocated by the caller and will be filled
- * with the amount of free memory in kilobytes for each cell requested,
- * starting with startCell (in freeMems[0]), up to either
- * (startCell + maxCells), or the number of additional cells in the node,
- * whichever is smaller.
- *
- * Returns the number of entries filled in freeMems, or -1 in case of error.
- */
-int
-xenHypervisorNodeGetCellsFreeMemory(virConnectPtr conn, unsigned long long *freeMems,
- int startCell, int maxCells)
-{
- xen_op_v2_sys op_sys;
- int i, j, ret;
- xenUnifiedPrivatePtr priv;
-
- if (conn == NULL) {
- virXenErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "invalid argument", 0);
- return -1;
- }
-
- priv = conn->privateData;
-
- if (priv->nbNodeCells < 0) {
- virXenErrorFunc (conn, VIR_ERR_XEN_CALL, __FUNCTION__,
- "cannot determine actual number of cells",0);
- return(-1);
- }
-
- if ((maxCells < 1) || (startCell >= priv->nbNodeCells)) {
- virXenErrorFunc (conn, VIR_ERR_INVALID_ARG, __FUNCTION__,
- "invalid argument", 0);
- return -1;
- }
-
- /*
- * Support only sys_interface_version >=4
- */
- if (sys_interface_version < SYS_IFACE_MIN_VERS_NUMA) {
- virXenErrorFunc (conn, VIR_ERR_XEN_CALL, __FUNCTION__,
- "unsupported in sys interface < 4", 0);
- return -1;
- }
-
- if (priv->handle < 0) {
- virXenErrorFunc (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
- "priv->handle invalid", 0);
- return -1;
- }
-
- memset(&op_sys, 0, sizeof(op_sys));
- op_sys.cmd = XEN_V2_OP_GETAVAILHEAP;
-
- for (i = startCell, j = 0;(i < priv->nbNodeCells) && (j < maxCells);i++,j++) {
- if (sys_interface_version >= 5)
- op_sys.u.availheap5.node = i;
- else
- op_sys.u.availheap.node = i;
- ret = xenHypervisorDoV2Sys(priv->handle, &op_sys);
- if (ret < 0) {
- return(-1);
- }
- if (sys_interface_version >= 5)
- freeMems[j] = op_sys.u.availheap5.avail_bytes;
- else
- freeMems[j] = op_sys.u.availheap.avail_bytes;
- }
- return (j);
-}
-
-
-/**
- * xenHypervisorPauseDomain:
- * @domain: pointer to the domain block
- *
- * Do an hypervisor call to pause the given domain
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-int
-xenHypervisorPauseDomain(virDomainPtr domain)
-{
- int ret;
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL))
- return -1;
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->handle < 0 || domain->id < 0)
- return (-1);
-
- ret = virXen_pausedomain(priv->handle, domain->id);
- if (ret < 0)
- return (-1);
- return (0);
-}
-
-/**
- * xenHypervisorResumeDomain:
- * @domain: pointer to the domain block
- *
- * Do an hypervisor call to resume the given domain
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-int
-xenHypervisorResumeDomain(virDomainPtr domain)
-{
- int ret;
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL))
- return -1;
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->handle < 0 || domain->id < 0)
- return (-1);
-
- ret = virXen_unpausedomain(priv->handle, domain->id);
- if (ret < 0)
- return (-1);
- return (0);
-}
-
-/**
- * xenHypervisorDestroyDomain:
- * @domain: pointer to the domain block
- *
- * Do an hypervisor call to destroy the given domain
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-int
-xenHypervisorDestroyDomain(virDomainPtr domain)
-{
- int ret;
- xenUnifiedPrivatePtr priv;
-
- if (domain == NULL || domain->conn == NULL)
- return -1;
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->handle < 0 || domain->id < 0)
- return (-1);
-
- ret = virXen_destroydomain(priv->handle, domain->id);
- if (ret < 0)
- return (-1);
- return (0);
-}
-
-/**
- * xenHypervisorSetMaxMemory:
- * @domain: pointer to the domain block
- * @memory: the max memory size in kilobytes.
- *
- * Do an hypervisor call to change the maximum amount of memory used
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-int
-xenHypervisorSetMaxMemory(virDomainPtr domain, unsigned long memory)
-{
- int ret;
- xenUnifiedPrivatePtr priv;
-
- if (domain == NULL || domain->conn == NULL)
- return -1;
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->handle < 0 || domain->id < 0)
- return (-1);
-
- ret = virXen_setmaxmem(priv->handle, domain->id, memory);
- if (ret < 0)
- return (-1);
- return (0);
-}
-#endif /* PROXY */
-
-#ifndef PROXY
-/**
- * xenHypervisorSetVcpus:
- * @domain: pointer to domain object
- * @nvcpus: the new number of virtual CPUs for this domain
- *
- * Dynamically change the number of virtual CPUs used by the domain.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-
-int
-xenHypervisorSetVcpus(virDomainPtr domain, unsigned int nvcpus)
-{
- int ret;
- xenUnifiedPrivatePtr priv;
-
- if (domain == NULL || domain->conn == NULL)
- return -1;
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->handle < 0 || domain->id < 0 || nvcpus < 1)
- return (-1);
-
- ret = virXen_setmaxvcpus(priv->handle, domain->id, nvcpus);
- if (ret < 0)
- return (-1);
- return (0);
-}
-
-/**
- * xenHypervisorPinVcpu:
- * @domain: pointer to domain object
- * @vcpu: virtual CPU number
- * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes)
- * @maplen: length of cpumap in bytes
- *
- * Dynamically change the real CPUs which can be allocated to a virtual CPU.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-
-int
-xenHypervisorPinVcpu(virDomainPtr domain, unsigned int vcpu,
- unsigned char *cpumap, int maplen)
-{
- int ret;
- xenUnifiedPrivatePtr priv;
-
- if (domain == NULL || domain->conn == NULL)
- return -1;
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->handle < 0 || (domain->id < 0) ||
- (cpumap == NULL) || (maplen < 1))
- return (-1);
-
- ret = virXen_setvcpumap(priv->handle, domain->id, vcpu,
- cpumap, maplen);
- if (ret < 0)
- return (-1);
- return (0);
-}
-#endif
-
-/**
- * virDomainGetVcpus:
- * @domain: pointer to domain object, or NULL for Domain0
- * @info: pointer to an array of virVcpuInfo structures (OUT)
- * @maxinfo: number of structures in info array
- * @cpumaps: pointer to an bit map of real CPUs for all vcpus of this domain (in 8-bit bytes) (OUT)
- * If cpumaps is NULL, then no cpumap information is returned by the API.
- * It's assumed there is <maxinfo> cpumap in cpumaps array.
- * The memory allocated to cpumaps must be (maxinfo * maplen) bytes
- * (ie: calloc(maxinfo, maplen)).
- * One cpumap inside cpumaps has the format described in virDomainPinVcpu() API.
- * @maplen: number of bytes in one cpumap, from 1 up to size of CPU map in
- * underlying virtualization system (Xen...).
- *
- * Extract information about virtual CPUs of domain, store it in info array
- * and also in cpumaps if this pointer isn't NULL.
- *
- * Returns the number of info filled in case of success, -1 in case of failure.
- */
-#ifndef PROXY
-int
-xenHypervisorGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo,
- unsigned char *cpumaps, int maplen)
-{
- xen_getdomaininfo dominfo;
- int ret;
- xenUnifiedPrivatePtr priv;
- virVcpuInfoPtr ipt;
- int nbinfo, i;
-
- if (domain == NULL || domain->conn == NULL)
- return -1;
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->handle < 0 || (domain->id < 0) ||
- (info == NULL) || (maxinfo < 1) ||
- (sizeof(cpumap_t) & 7))
- return (-1);
- if ((cpumaps != NULL) && (maplen < 1))
- return -1;
-
- /* first get the number of virtual CPUs in this domain */
- XEN_GETDOMAININFO_CLEAR(dominfo);
- ret = virXen_getdomaininfo(priv->handle, domain->id,
- &dominfo);
-
- if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != domain->id))
- return (-1);
- nbinfo = XEN_GETDOMAININFO_CPUCOUNT(dominfo) + 1;
- if (nbinfo > maxinfo) nbinfo = maxinfo;
-
- if (cpumaps != NULL)
- memset(cpumaps, 0, maxinfo * maplen);
-
- for (i = 0, ipt = info; i < nbinfo; i++, ipt++) {
- if ((cpumaps != NULL) && (i < maxinfo)) {
- ret = virXen_getvcpusinfo(priv->handle, domain->id, i,
- ipt,
- (unsigned char *)VIR_GET_CPUMAP(cpumaps, maplen, i),
- maplen);
- if (ret < 0)
- return(-1);
- } else {
- ret = virXen_getvcpusinfo(priv->handle, domain->id, i,
- ipt, NULL, 0);
- if (ret < 0)
- return(-1);
- }
- }
- return nbinfo;
-}
-#endif /* PROXY */
-
-/**
- * xenHypervisorGetVcpuMax:
- *
- * Returns the maximum number of virtual CPUs supported for
- * the guest VM. If the guest is inactive, this is the maximum
- * of CPU defined by Xen. If the guest is running this reflect
- * the maximum number of virtual CPUs the guest was booted with.
- */
-int
-xenHypervisorGetVcpuMax(virDomainPtr domain)
-{
- xen_getdomaininfo dominfo;
- int ret;
- int maxcpu;
- xenUnifiedPrivatePtr priv;
-
- if (domain == NULL || domain->conn == NULL)
- return -1;
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->handle < 0)
- return (-1);
-
- /* inactive domain */
- if (domain->id < 0) {
- maxcpu = MAX_VIRT_CPUS;
- } else {
- XEN_GETDOMAININFO_CLEAR(dominfo);
- ret = virXen_getdomaininfo(priv->handle, domain->id,
- &dominfo);
-
- if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != domain->id))
- return (-1);
- maxcpu = XEN_GETDOMAININFO_MAXCPUID(dominfo) + 1;
- }
-
- return maxcpu;
-}
-
-/**
- * xenHavePrivilege()
- *
- * Return true if the current process should be able to connect to Xen.
- */
-int
-xenHavePrivilege()
-{
-#ifdef __sun
- return priv_ineffect (PRIV_XVM_CONTROL);
-#else
- return access(XEN_HYPERVISOR_SOCKET, R_OK) == 0;
-#endif
-}
+++ /dev/null
-/*
- * xen_internal.h: internal API for direct access to Xen hypervisor level
- *
- * Copyright (C) 2005 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Daniel Veillard <veillard@redhat.com>
- */
-
-#ifndef __VIR_XEN_INTERNAL_H__
-#define __VIR_XEN_INTERNAL_H__
-
-#include <libxml/uri.h>
-
-#include "internal.h"
-#include "capabilities.h"
-#include "driver.h"
-
-extern struct xenUnifiedDriver xenHypervisorDriver;
-int xenHypervisorInit (void);
-
-virCapsPtr xenHypervisorMakeCapabilities (virConnectPtr conn);
-
-/* The following calls are made directly by the Xen proxy: */
-
-virDomainPtr
- xenHypervisorLookupDomainByID (virConnectPtr conn,
- int id);
-virDomainPtr
- xenHypervisorLookupDomainByUUID (virConnectPtr conn,
- const unsigned char *uuid);
-char *
- xenHypervisorDomainGetOSType (virDomainPtr dom);
-
-virDrvOpenStatus
- xenHypervisorOpen (virConnectPtr conn,
- virConnectAuthPtr auth,
- int flags);
-int xenHypervisorClose (virConnectPtr conn);
-int xenHypervisorGetVersion (virConnectPtr conn,
- unsigned long *hvVer);
-virCapsPtr
- xenHypervisorMakeCapabilitiesInternal(virConnectPtr conn,
- const char *hostmachine,
- FILE *cpuinfo,
- FILE *capabilities);
-char *
- xenHypervisorGetCapabilities (virConnectPtr conn);
-unsigned long
- xenHypervisorGetDomMaxMemory (virConnectPtr conn,
- int id);
-int xenHypervisorNumOfDomains (virConnectPtr conn);
-int xenHypervisorListDomains (virConnectPtr conn,
- int *ids,
- int maxids);
-int xenHypervisorGetMaxVcpus (virConnectPtr conn,
- const char *type);
-int xenHypervisorDestroyDomain (virDomainPtr domain);
-int xenHypervisorResumeDomain (virDomainPtr domain);
-int xenHypervisorPauseDomain (virDomainPtr domain);
-int xenHypervisorGetDomainInfo (virDomainPtr domain,
- virDomainInfoPtr info);
-int xenHypervisorGetDomInfo (virConnectPtr conn,
- int id,
- virDomainInfoPtr info);
-int xenHypervisorSetMaxMemory (virDomainPtr domain,
- unsigned long memory);
-int xenHypervisorCheckID (virConnectPtr conn,
- int id);
-int xenHypervisorSetVcpus (virDomainPtr domain,
- unsigned int nvcpus);
-int xenHypervisorPinVcpu (virDomainPtr domain,
- unsigned int vcpu,
- unsigned char *cpumap,
- int maplen);
-int xenHypervisorGetVcpus (virDomainPtr domain,
- virVcpuInfoPtr info,
- int maxinfo,
- unsigned char *cpumaps,
- int maplen);
-int xenHypervisorGetVcpuMax (virDomainPtr domain);
-
-char * xenHypervisorGetSchedulerType (virDomainPtr domain,
- int *nparams);
-
-int xenHypervisorGetSchedulerParameters(virDomainPtr domain,
- virSchedParameterPtr params,
- int *nparams);
-
-int xenHypervisorSetSchedulerParameters(virDomainPtr domain,
- virSchedParameterPtr params,
- int nparams);
-
-int xenHypervisorDomainBlockStats (virDomainPtr domain,
- const char *path,
- struct _virDomainBlockStats *stats);
-int xenHypervisorDomainInterfaceStats (virDomainPtr domain,
- const char *path,
- struct _virDomainInterfaceStats *stats);
-
-int xenHypervisorNodeGetCellsFreeMemory(virConnectPtr conn,
- unsigned long long *freeMems,
- int startCell,
- int maxCells);
-
-int xenHavePrivilege(void);
-
-#endif /* __VIR_XEN_INTERNAL_H__ */
+++ /dev/null
-/*
- * xen_unified.c: Unified Xen driver.
- *
- * Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Richard W.M. Jones <rjones@redhat.com>
- */
-
-#include <config.h>
-
-/* Note:
- *
- * This driver provides a unified interface to the five
- * separate underlying Xen drivers (xen_internal, proxy_internal,
- * xend_internal, xs_internal and xm_internal). Historically
- * the body of libvirt.c handled the five Xen drivers,
- * and contained Xen-specific code.
- */
-
-#include <stdint.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <xen/dom0_ops.h>
-#include <libxml/uri.h>
-
-#include "virterror_internal.h"
-#include "logging.h"
-#include "datatypes.h"
-#include "xen_unified.h"
-
-#include "xen_internal.h"
-#include "proxy_internal.h"
-#include "xend_internal.h"
-#include "xs_internal.h"
-#include "xm_internal.h"
-#if WITH_XEN_INOTIFY
-#include "xen_inotify.h"
-#endif
-#include "xml.h"
-#include "util.h"
-#include "memory.h"
-#include "node_device_conf.h"
-#include "pci.h"
-
-#define VIR_FROM_THIS VIR_FROM_XEN
-
-static int
-xenUnifiedNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info);
-static int
-xenUnifiedDomainGetMaxVcpus (virDomainPtr dom);
-static int
-xenUnifiedDomainGetVcpus (virDomainPtr dom,
- virVcpuInfoPtr info, int maxinfo,
- unsigned char *cpumaps, int maplen);
-
-/* The five Xen drivers below us. */
-static struct xenUnifiedDriver const * const drivers[XEN_UNIFIED_NR_DRIVERS] = {
- [XEN_UNIFIED_HYPERVISOR_OFFSET] = &xenHypervisorDriver,
- [XEN_UNIFIED_PROXY_OFFSET] = &xenProxyDriver,
- [XEN_UNIFIED_XEND_OFFSET] = &xenDaemonDriver,
- [XEN_UNIFIED_XS_OFFSET] = &xenStoreDriver,
- [XEN_UNIFIED_XM_OFFSET] = &xenXMDriver,
-#if WITH_XEN_INOTIFY
- [XEN_UNIFIED_INOTIFY_OFFSET] = &xenInotifyDriver,
-#endif
-};
-
-static int inside_daemon;
-
-#define xenUnifiedError(conn, code, fmt...) \
- virReportErrorHelper(conn, VIR_FROM_XEN, code, __FILE__, \
- __FUNCTION__, __LINE__, fmt)
-
-/**
- * xenNumaInit:
- * @conn: pointer to the hypervisor connection
- *
- * Initializer for previous variables. We currently assume that
- * the number of physical CPU and the number of NUMA cell is fixed
- * until reboot which might be false in future Xen implementations.
- */
-static void
-xenNumaInit(virConnectPtr conn) {
- virNodeInfo nodeInfo;
- xenUnifiedPrivatePtr priv;
- int ret;
-
- ret = xenUnifiedNodeGetInfo(conn, &nodeInfo);
- if (ret < 0)
- return;
-
- priv = conn->privateData;
-
- priv->nbNodeCells = nodeInfo.nodes;
- priv->nbNodeCpus = nodeInfo.cpus;
-}
-
-
-/**
- * xenDomainUsedCpus:
- * @dom: the domain
- *
- * Analyze which set of CPUs are used by the domain and
- * return a string providing the ranges.
- *
- * Returns the string which needs to be freed by the caller or
- * NULL if the domain uses all CPU or in case of error.
- */
-char *
-xenDomainUsedCpus(virDomainPtr dom)
-{
- char *res = NULL;
- int ncpus;
- int nb_vcpu;
- char *cpulist = NULL;
- unsigned char *cpumap = NULL;
- size_t cpumaplen;
- int nb = 0;
- int n, m;
- virVcpuInfoPtr cpuinfo = NULL;
- virNodeInfo nodeinfo;
- xenUnifiedPrivatePtr priv;
-
- if (!VIR_IS_CONNECTED_DOMAIN(dom))
- return (NULL);
-
- priv = dom->conn->privateData;
-
- if (priv->nbNodeCpus <= 0)
- return(NULL);
- nb_vcpu = xenUnifiedDomainGetMaxVcpus(dom);
- if (nb_vcpu <= 0)
- return(NULL);
- if (xenUnifiedNodeGetInfo(dom->conn, &nodeinfo) < 0)
- return(NULL);
-
- if (VIR_ALLOC_N(cpulist, priv->nbNodeCpus) < 0)
- goto done;
- if (VIR_ALLOC_N(cpuinfo, nb_vcpu) < 0)
- goto done;
- cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
- if (xalloc_oversized(nb_vcpu, cpumaplen) ||
- VIR_ALLOC_N(cpumap, nb_vcpu * cpumaplen) < 0)
- goto done;
-
- if ((ncpus = xenUnifiedDomainGetVcpus(dom, cpuinfo, nb_vcpu,
- cpumap, cpumaplen)) >= 0) {
- for (n = 0 ; n < ncpus ; n++) {
- for (m = 0 ; m < priv->nbNodeCpus; m++) {
- if ((cpulist[m] == 0) &&
- (VIR_CPU_USABLE(cpumap, cpumaplen, n, m))) {
- cpulist[m] = 1;
- nb++;
- /* if all CPU are used just return NULL */
- if (nb == priv->nbNodeCpus)
- goto done;
-
- }
- }
- }
- res = virDomainCpuSetFormat(dom->conn, cpulist, priv->nbNodeCpus);
- }
-
-done:
- VIR_FREE(cpulist);
- VIR_FREE(cpumap);
- VIR_FREE(cpuinfo);
- return(res);
-}
-
-#ifdef WITH_LIBVIRTD
-
-static int
-xenInitialize (int privileged ATTRIBUTE_UNUSED)
-{
- inside_daemon = 1;
- return 0;
-}
-
-static virStateDriver state_driver = {
- .initialize = xenInitialize,
-};
-
-#endif
-
-/*----- Dispatch functions. -----*/
-
-/* These dispatch functions follow the model used historically
- * by libvirt.c -- trying each low-level Xen driver in turn
- * until one succeeds. However since we know what low-level
- * drivers can perform which functions, it is probably better
- * in future to optimise these dispatch functions to just call
- * the single function (or small number of appropriate functions)
- * in the low level drivers directly.
- */
-
-static int
-xenUnifiedProbe (void)
-{
-#ifdef __linux__
- if (virFileExists("/proc/xen"))
- return 1;
-#endif
-#ifdef __sun
- FILE *fh;
-
- if (fh = fopen("/dev/xen/domcaps", "r")) {
- fclose(fh);
- return 1;
- }
-#endif
- return 0;
-}
-
-static virDrvOpenStatus
-xenUnifiedOpen (virConnectPtr conn, virConnectAuthPtr auth, int flags)
-{
- int i, ret = VIR_DRV_OPEN_DECLINED;
- xenUnifiedPrivatePtr priv;
- virDomainEventCallbackListPtr cbList;
-
-#ifdef __sun
- /*
- * Only the libvirtd instance can open this driver.
- * Everything else falls back to the remote driver.
- */
- if (!inside_daemon)
- return VIR_DRV_OPEN_DECLINED;
-#endif
-
- if (conn->uri == NULL) {
- if (!xenUnifiedProbe())
- return VIR_DRV_OPEN_DECLINED;
-
- conn->uri = xmlParseURI("xen:///");
- if (!conn->uri) {
- virReportOOMError (NULL);
- return VIR_DRV_OPEN_ERROR;
- }
- } else {
- if (conn->uri->scheme) {
- /* Decline any scheme which isn't "xen://" or "http://". */
- if (STRCASENEQ(conn->uri->scheme, "xen") &&
- STRCASENEQ(conn->uri->scheme, "http"))
- return VIR_DRV_OPEN_DECLINED;
-
-
- /* Return an error if the path isn't '' or '/' */
- if (conn->uri->path &&
- STRNEQ(conn->uri->path, "") &&
- STRNEQ(conn->uri->path, "/")) {
- xenUnifiedError(NULL, VIR_ERR_INTERNAL_ERROR,
- _("unexpected Xen URI path '%s', try xen:///"),
- conn->uri->path);
- return VIR_DRV_OPEN_ERROR;
- }
-
- /* Decline any xen:// URI with a server specified, allowing remote
- * driver to handle, but keep any http:/// URIs */
- if (STRCASEEQ(conn->uri->scheme, "xen") &&
- conn->uri->server)
- return VIR_DRV_OPEN_DECLINED;
- } else {
- /* Special case URI for Xen driver only:
- *
- * Treat a plain path as a Xen UNIX socket path, and give
- * error unless path is absolute
- */
- if (!conn->uri->path || conn->uri->path[0] != '/') {
- xenUnifiedError(NULL, VIR_ERR_INTERNAL_ERROR,
- _("unexpected Xen URI path '%s', try ///var/lib/xen/xend-socket"),
- NULLSTR(conn->uri->path));
- return VIR_DRV_OPEN_ERROR;
- }
- }
- }
-
- /* We now know the URI is definitely for this driver, so beyond
- * here, don't return DECLINED, always use ERROR */
-
- /* Allocate per-connection private data. */
- if (VIR_ALLOC(priv) < 0) {
- virReportOOMError (NULL);
- return VIR_DRV_OPEN_ERROR;
- }
- if (virMutexInit(&priv->lock) < 0) {
- xenUnifiedError (NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("cannot initialise mutex"));
- VIR_FREE(priv);
- return VIR_DRV_OPEN_ERROR;
- }
-
- /* Allocate callback list */
- if (VIR_ALLOC(cbList) < 0) {
- virReportOOMError (NULL);
- virMutexDestroy(&priv->lock);
- VIR_FREE(priv);
- return VIR_DRV_OPEN_ERROR;
- }
- conn->privateData = priv;
-
- priv->domainEventCallbacks = cbList;
-
- priv->handle = -1;
- priv->xendConfigVersion = -1;
- priv->xshandle = NULL;
- priv->proxy = -1;
-
-
- /* Hypervisor is only run with privilege & required to succeed */
- if (xenHavePrivilege()) {
- DEBUG0("Trying hypervisor sub-driver");
- if (drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->open(conn, auth, flags) ==
- VIR_DRV_OPEN_SUCCESS) {
- DEBUG0("Activated hypervisor sub-driver");
- priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] = 1;
- }
- }
-
- /* XenD is required to succeed if privileged.
- * If it fails as non-root, then the proxy driver may take over
- */
- DEBUG0("Trying XenD sub-driver");
- if (drivers[XEN_UNIFIED_XEND_OFFSET]->open(conn, auth, flags) ==
- VIR_DRV_OPEN_SUCCESS) {
- DEBUG0("Activated XenD sub-driver");
- priv->opened[XEN_UNIFIED_XEND_OFFSET] = 1;
-
- /* XenD is active, so try the xm & xs drivers too, both requird to
- * succeed if root, optional otherwise */
- if (priv->xendConfigVersion <= 2) {
- DEBUG0("Trying XM sub-driver");
- if (drivers[XEN_UNIFIED_XM_OFFSET]->open(conn, auth, flags) ==
- VIR_DRV_OPEN_SUCCESS) {
- DEBUG0("Activated XM sub-driver");
- priv->opened[XEN_UNIFIED_XM_OFFSET] = 1;
- }
- }
- DEBUG0("Trying XS sub-driver");
- if (drivers[XEN_UNIFIED_XS_OFFSET]->open(conn, auth, flags) ==
- VIR_DRV_OPEN_SUCCESS) {
- DEBUG0("Activated XS sub-driver");
- priv->opened[XEN_UNIFIED_XS_OFFSET] = 1;
- } else {
- if (xenHavePrivilege())
- goto fail; /* XS is mandatory when privileged */
- }
- } else {
- if (xenHavePrivilege()) {
- goto fail; /* XenD is mandatory when privileged */
- } else {
-#if WITH_PROXY
- DEBUG0("Trying proxy sub-driver");
- if (drivers[XEN_UNIFIED_PROXY_OFFSET]->open(conn, auth, flags) ==
- VIR_DRV_OPEN_SUCCESS) {
- DEBUG0("Activated proxy sub-driver");
- priv->opened[XEN_UNIFIED_PROXY_OFFSET] = 1;
- } else {
- goto fail; /* Proxy is mandatory if XenD failed */
- }
-#else
- DEBUG0("Handing off for remote driver");
- ret = VIR_DRV_OPEN_DECLINED; /* Let remote_driver try instead */
- goto clean;
-#endif
- }
- }
-
- xenNumaInit(conn);
-
- if (!(priv->caps = xenHypervisorMakeCapabilities(conn))) {
- DEBUG0("Failed to make capabilities");
- goto fail;
- }
-
-#if WITH_XEN_INOTIFY
- if (xenHavePrivilege()) {
- DEBUG0("Trying Xen inotify sub-driver");
- if (drivers[XEN_UNIFIED_INOTIFY_OFFSET]->open(conn, auth, flags) ==
- VIR_DRV_OPEN_SUCCESS) {
- DEBUG0("Activated Xen inotify sub-driver");
- priv->opened[XEN_UNIFIED_INOTIFY_OFFSET] = 1;
- }
- }
-#endif
-
- return VIR_DRV_OPEN_SUCCESS;
-
-fail:
- ret = VIR_DRV_OPEN_ERROR;
-#ifndef WITH_PROXY
-clean:
-#endif
- DEBUG0("Failed to activate a mandatory sub-driver");
- for (i = 0 ; i < XEN_UNIFIED_NR_DRIVERS ; i++)
- if (priv->opened[i]) drivers[i]->close(conn);
- virMutexDestroy(&priv->lock);
- VIR_FREE(priv);
- conn->privateData = NULL;
- return ret;
-}
-
-#define GET_PRIVATE(conn) \
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) (conn)->privateData
-
-static int
-xenUnifiedClose (virConnectPtr conn)
-{
- GET_PRIVATE(conn);
- int i;
-
- virCapabilitiesFree(priv->caps);
- virDomainEventCallbackListFree(priv->domainEventCallbacks);
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->close)
- (void) drivers[i]->close (conn);
-
- virMutexDestroy(&priv->lock);
- VIR_FREE(conn->privateData);
-
- return 0;
-}
-
-
-#define HV_VERSION ((DOM0_INTERFACE_VERSION >> 24) * 1000000 + \
- ((DOM0_INTERFACE_VERSION >> 16) & 0xFF) * 1000 + \
- (DOM0_INTERFACE_VERSION & 0xFFFF))
-
-unsigned long xenUnifiedVersion(void)
-{
- return HV_VERSION;
-}
-
-
-static const char *
-xenUnifiedType (virConnectPtr conn)
-{
- GET_PRIVATE(conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i])
- return "Xen";
-
- return NULL;
-}
-
-/* Which features are supported by this driver? */
-static int
-xenUnifiedSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
-{
- switch (feature) {
- case VIR_DRV_FEATURE_MIGRATION_V1: return 1;
- default: return 0;
- }
-}
-
-static int
-xenUnifiedGetVersion (virConnectPtr conn, unsigned long *hvVer)
-{
- GET_PRIVATE(conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] &&
- drivers[i]->version &&
- drivers[i]->version (conn, hvVer) == 0)
- return 0;
-
- return -1;
-}
-
-/* NB: Even if connected to the proxy, we're still on the
- * same machine.
- */
-static char *
-xenUnifiedGetHostname (virConnectPtr conn)
-{
- char *result;
-
- result = virGetHostname();
- if (result == NULL) {
- virReportSystemError(conn, errno,
- "%s", _("cannot lookup hostname"));
- return NULL;
- }
- /* Caller frees this string. */
- return result;
-}
-
-static int
-xenUnifiedGetMaxVcpus (virConnectPtr conn, const char *type)
-{
- GET_PRIVATE(conn);
-
- if (type && STRCASENEQ (type, "Xen")) {
- xenUnifiedError (conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return -1;
- }
-
- if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET])
- return xenHypervisorGetMaxVcpus (conn, type);
- else {
- xenUnifiedError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
- return -1;
- }
-}
-
-static int
-xenUnifiedNodeGetInfo (virConnectPtr conn, virNodeInfoPtr info)
-{
- GET_PRIVATE(conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] &&
- drivers[i]->nodeGetInfo &&
- drivers[i]->nodeGetInfo (conn, info) == 0)
- return 0;
-
- return -1;
-}
-
-static char *
-xenUnifiedGetCapabilities (virConnectPtr conn)
-{
- xenUnifiedPrivatePtr priv = conn->privateData;
- char *xml;
-
- if (!(xml = virCapabilitiesFormatXML(priv->caps))) {
- virReportOOMError(conn);
- return NULL;
- }
-
- return xml;
-}
-
-static int
-xenUnifiedListDomains (virConnectPtr conn, int *ids, int maxids)
-{
- GET_PRIVATE(conn);
- int ret;
-
- /* Try xenstore. */
- if (priv->opened[XEN_UNIFIED_XS_OFFSET]) {
- ret = xenStoreListDomains (conn, ids, maxids);
- if (ret >= 0) return ret;
- }
-
- /* Try HV. */
- if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) {
- ret = xenHypervisorListDomains (conn, ids, maxids);
- if (ret >= 0) return ret;
- }
-
- /* Try xend. */
- if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
- ret = xenDaemonListDomains (conn, ids, maxids);
- if (ret >= 0) return ret;
- }
-
- /* Try proxy. */
- if (priv->opened[XEN_UNIFIED_PROXY_OFFSET]) {
- ret = xenProxyListDomains (conn, ids, maxids);
- if (ret >= 0) return ret;
- }
- return -1;
-}
-
-static int
-xenUnifiedNumOfDomains (virConnectPtr conn)
-{
- GET_PRIVATE(conn);
- int i, ret;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->numOfDomains) {
- ret = drivers[i]->numOfDomains (conn);
- if (ret >= 0) return ret;
- }
-
- return -1;
-}
-
-static virDomainPtr
-xenUnifiedDomainCreateXML (virConnectPtr conn,
- const char *xmlDesc, unsigned int flags)
-{
- GET_PRIVATE(conn);
- int i;
- virDomainPtr ret;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->domainCreateXML) {
- ret = drivers[i]->domainCreateXML (conn, xmlDesc, flags);
- if (ret) return ret;
- }
-
- return NULL;
-}
-
-/* Assumption made in underlying drivers:
- * If the domain is "not found" and there is no other error, then
- * the Lookup* functions return a NULL but do not set virterror.
- */
-static virDomainPtr
-xenUnifiedDomainLookupByID (virConnectPtr conn, int id)
-{
- GET_PRIVATE(conn);
- virDomainPtr ret;
-
- /* Reset any connection-level errors in virterror first, in case
- * there is one hanging around from a previous call.
- */
- virConnResetLastError (conn);
-
- /* Try hypervisor/xenstore combo. */
- if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) {
- ret = xenHypervisorLookupDomainByID (conn, id);
- if (ret || conn->err.code != VIR_ERR_OK)
- return ret;
- }
-
- /* Try proxy. */
- if (priv->opened[XEN_UNIFIED_PROXY_OFFSET]) {
- ret = xenProxyLookupByID (conn, id);
- if (ret || conn->err.code != VIR_ERR_OK)
- return ret;
- }
-
- /* Try xend. */
- if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
- ret = xenDaemonLookupByID (conn, id);
- if (ret || conn->err.code != VIR_ERR_OK)
- return ret;
- }
-
- /* Not found. */
- xenUnifiedError (conn, VIR_ERR_NO_DOMAIN, __FUNCTION__);
- return NULL;
-}
-
-static virDomainPtr
-xenUnifiedDomainLookupByUUID (virConnectPtr conn,
- const unsigned char *uuid)
-{
- GET_PRIVATE(conn);
- virDomainPtr ret;
-
- /* Reset any connection-level errors in virterror first, in case
- * there is one hanging around from a previous call.
- */
- virConnResetLastError (conn);
-
- /* Try hypervisor/xenstore combo. */
- if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) {
- ret = xenHypervisorLookupDomainByUUID (conn, uuid);
- if (ret || conn->err.code != VIR_ERR_OK)
- return ret;
- }
-
- /* Try proxy. */
- if (priv->opened[XEN_UNIFIED_PROXY_OFFSET]) {
- ret = xenProxyLookupByUUID (conn, uuid);
- if (ret || conn->err.code != VIR_ERR_OK)
- return ret;
- }
-
- /* Try xend. */
- if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
- ret = xenDaemonLookupByUUID (conn, uuid);
- if (ret || conn->err.code != VIR_ERR_OK)
- return ret;
- }
-
- /* Try XM for inactive domains. */
- if (priv->opened[XEN_UNIFIED_XM_OFFSET]) {
- ret = xenXMDomainLookupByUUID (conn, uuid);
- if (ret || conn->err.code != VIR_ERR_OK)
- return ret;
- }
-
- /* Not found. */
- xenUnifiedError (conn, VIR_ERR_NO_DOMAIN, __FUNCTION__);
- return NULL;
-}
-
-static virDomainPtr
-xenUnifiedDomainLookupByName (virConnectPtr conn,
- const char *name)
-{
- GET_PRIVATE(conn);
- virDomainPtr ret;
-
- /* Reset any connection-level errors in virterror first, in case
- * there is one hanging around from a previous call.
- */
- virConnResetLastError (conn);
-
- /* Try proxy. */
- if (priv->opened[XEN_UNIFIED_PROXY_OFFSET]) {
- ret = xenProxyLookupByName (conn, name);
- if (ret || conn->err.code != VIR_ERR_OK)
- return ret;
- }
-
- /* Try xend. */
- if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
- ret = xenDaemonLookupByName (conn, name);
- if (ret || conn->err.code != VIR_ERR_OK)
- return ret;
- }
-
- /* Try xenstore for inactive domains. */
- if (priv->opened[XEN_UNIFIED_XS_OFFSET]) {
- ret = xenStoreLookupByName (conn, name);
- if (ret || conn->err.code != VIR_ERR_OK)
- return ret;
- }
-
- /* Try XM for inactive domains. */
- if (priv->opened[XEN_UNIFIED_XM_OFFSET]) {
- ret = xenXMDomainLookupByName (conn, name);
- if (ret || conn->err.code != VIR_ERR_OK)
- return ret;
- }
-
- /* Not found. */
- xenUnifiedError (conn, VIR_ERR_NO_DOMAIN, __FUNCTION__);
- return NULL;
-}
-
-static int
-xenUnifiedDomainSuspend (virDomainPtr dom)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- /* Try non-hypervisor methods first, then hypervisor direct method
- * as a last resort.
- */
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (i != XEN_UNIFIED_HYPERVISOR_OFFSET &&
- priv->opened[i] &&
- drivers[i]->domainSuspend &&
- drivers[i]->domainSuspend (dom) == 0)
- return 0;
-
- if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] &&
- drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSuspend &&
- drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSuspend (dom) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainResume (virDomainPtr dom)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- /* Try non-hypervisor methods first, then hypervisor direct method
- * as a last resort.
- */
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (i != XEN_UNIFIED_HYPERVISOR_OFFSET &&
- priv->opened[i] &&
- drivers[i]->domainResume &&
- drivers[i]->domainResume (dom) == 0)
- return 0;
-
- if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] &&
- drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainResume &&
- drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainResume (dom) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainShutdown (virDomainPtr dom)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] &&
- drivers[i]->domainShutdown &&
- drivers[i]->domainShutdown (dom) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainReboot (virDomainPtr dom, unsigned int flags)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] &&
- drivers[i]->domainReboot &&
- drivers[i]->domainReboot (dom, flags) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainDestroy (virDomainPtr dom)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- /* Try non-hypervisor methods first, then hypervisor direct method
- * as a last resort.
- */
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (i != XEN_UNIFIED_HYPERVISOR_OFFSET &&
- priv->opened[i] &&
- drivers[i]->domainDestroy &&
- drivers[i]->domainDestroy (dom) == 0)
- return 0;
-
- if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] &&
- drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainDestroy &&
- drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainDestroy (dom) == 0)
- return 0;
-
- return -1;
-}
-
-static char *
-xenUnifiedDomainGetOSType (virDomainPtr dom)
-{
- GET_PRIVATE(dom->conn);
- int i;
- char *ret;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->domainGetOSType) {
- ret = drivers[i]->domainGetOSType (dom);
- if (ret) return ret;
- }
-
- return NULL;
-}
-
-static unsigned long
-xenUnifiedDomainGetMaxMemory (virDomainPtr dom)
-{
- GET_PRIVATE(dom->conn);
- int i;
- unsigned long ret;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->domainGetMaxMemory) {
- ret = drivers[i]->domainGetMaxMemory (dom);
- if (ret != 0) return ret;
- }
-
- return 0;
-}
-
-static int
-xenUnifiedDomainSetMaxMemory (virDomainPtr dom, unsigned long memory)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- /* Prefer xend for setting max memory */
- if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
- if (xenDaemonDomainSetMaxMemory (dom, memory) == 0)
- return 0;
- }
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (i != XEN_UNIFIED_XEND_OFFSET &&
- priv->opened[i] &&
- drivers[i]->domainSetMaxMemory &&
- drivers[i]->domainSetMaxMemory (dom, memory) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainSetMemory (virDomainPtr dom, unsigned long memory)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] &&
- drivers[i]->domainSetMemory &&
- drivers[i]->domainSetMemory (dom, memory) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] &&
- drivers[i]->domainGetInfo &&
- drivers[i]->domainGetInfo (dom, info) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainSave (virDomainPtr dom, const char *to)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] &&
- drivers[i]->domainSave &&
- drivers[i]->domainSave (dom, to) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainRestore (virConnectPtr conn, const char *from)
-{
- GET_PRIVATE(conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] &&
- drivers[i]->domainRestore &&
- drivers[i]->domainRestore (conn, from) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainCoreDump (virDomainPtr dom, const char *to, int flags)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] &&
- drivers[i]->domainCoreDump &&
- drivers[i]->domainCoreDump (dom, to, flags) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- /* Try non-hypervisor methods first, then hypervisor direct method
- * as a last resort.
- */
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (i != XEN_UNIFIED_HYPERVISOR_OFFSET &&
- priv->opened[i] &&
- drivers[i]->domainSetVcpus &&
- drivers[i]->domainSetVcpus (dom, nvcpus) == 0)
- return 0;
-
- if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] &&
- drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSetVcpus &&
- drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSetVcpus (dom, nvcpus) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainPinVcpu (virDomainPtr dom, unsigned int vcpu,
- unsigned char *cpumap, int maplen)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] &&
- drivers[i]->domainPinVcpu &&
- drivers[i]->domainPinVcpu (dom, vcpu, cpumap, maplen) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainGetVcpus (virDomainPtr dom,
- virVcpuInfoPtr info, int maxinfo,
- unsigned char *cpumaps, int maplen)
-{
- GET_PRIVATE(dom->conn);
- int i, ret;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->domainGetVcpus) {
- ret = drivers[i]->domainGetVcpus (dom, info, maxinfo, cpumaps, maplen);
- if (ret > 0)
- return ret;
- }
- return -1;
-}
-
-static int
-xenUnifiedDomainGetMaxVcpus (virDomainPtr dom)
-{
- GET_PRIVATE(dom->conn);
- int i, ret;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->domainGetMaxVcpus) {
- ret = drivers[i]->domainGetMaxVcpus (dom);
- if (ret != 0) return ret;
- }
-
- return -1;
-}
-
-static char *
-xenUnifiedDomainDumpXML (virDomainPtr dom, int flags)
-{
- GET_PRIVATE(dom->conn);
-
- if (dom->id == -1 && priv->xendConfigVersion < 3 ) {
- if (priv->opened[XEN_UNIFIED_XM_OFFSET])
- return xenXMDomainDumpXML(dom, flags);
- } else {
- if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
- char *cpus, *res;
- xenUnifiedLock(priv);
- cpus = xenDomainUsedCpus(dom);
- xenUnifiedUnlock(priv);
- res = xenDaemonDomainDumpXML(dom, flags, cpus);
- VIR_FREE(cpus);
- return(res);
- }
- if (priv->opened[XEN_UNIFIED_PROXY_OFFSET])
- return xenProxyDomainDumpXML(dom, flags);
- }
-
- xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
- return NULL;
-}
-
-
-static char *
-xenUnifiedDomainXMLFromNative(virConnectPtr conn,
- const char *format,
- const char *config,
- unsigned int flags ATTRIBUTE_UNUSED)
-{
- virDomainDefPtr def = NULL;
- char *ret = NULL;
- virConfPtr conf = NULL;
- GET_PRIVATE(conn);
-
- if (STRNEQ(format, XEN_CONFIG_FORMAT_XM) &&
- STRNEQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
- xenUnifiedError(conn, VIR_ERR_INVALID_ARG,
- _("unsupported config type %s"), format);
- return NULL;
- }
-
- if (STREQ(format, XEN_CONFIG_FORMAT_XM)) {
- conf = virConfReadMem(config, strlen(config), 0);
- if (!conf)
- goto cleanup;
-
- def = xenXMDomainConfigParse(conn, conf);
- } else if (STREQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
- def = xenDaemonParseSxprString(conn, config, priv->xendConfigVersion);
- }
- if (!def)
- goto cleanup;
-
- ret = virDomainDefFormat(conn, def, 0);
-
-cleanup:
- virDomainDefFree(def);
- return ret;
-}
-
-
-#define MAX_CONFIG_SIZE (1024 * 65)
-static char *
-xenUnifiedDomainXMLToNative(virConnectPtr conn,
- const char *format,
- const char *xmlData,
- unsigned int flags ATTRIBUTE_UNUSED)
-{
- virDomainDefPtr def = NULL;
- char *ret = NULL;
- virConfPtr conf = NULL;
- GET_PRIVATE(conn);
-
- if (STRNEQ(format, XEN_CONFIG_FORMAT_XM) &&
- STRNEQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
- xenUnifiedError(conn, VIR_ERR_INVALID_ARG,
- _("unsupported config type %s"), format);
- goto cleanup;
- }
-
- if (!(def = virDomainDefParseString(conn,
- priv->caps,
- xmlData,
- 0)))
- goto cleanup;
-
- if (STREQ(format, XEN_CONFIG_FORMAT_XM)) {
- int len = MAX_CONFIG_SIZE;
- conf = xenXMDomainConfigFormat(conn, def);
- if (!conf)
- goto cleanup;
-
- if (VIR_ALLOC_N(ret, len) < 0) {
- virReportOOMError(conn);
- goto cleanup;
- }
-
- if (virConfWriteMem(ret, &len, conf) < 0) {
- VIR_FREE(ret);
- goto cleanup;
- }
- } else if (STREQ(format, XEN_CONFIG_FORMAT_SEXPR)) {
- ret = xenDaemonFormatSxpr(conn, def, priv->xendConfigVersion);
- }
-
-cleanup:
- virDomainDefFree(def);
- if (conf)
- virConfFree(conf);
- return ret;
-}
-
-
-static int
-xenUnifiedDomainMigratePrepare (virConnectPtr dconn,
- char **cookie,
- int *cookielen,
- const char *uri_in,
- char **uri_out,
- unsigned long flags,
- const char *dname,
- unsigned long resource)
-{
- GET_PRIVATE(dconn);
-
- if (priv->opened[XEN_UNIFIED_XEND_OFFSET])
- return xenDaemonDomainMigratePrepare (dconn, cookie, cookielen,
- uri_in, uri_out,
- flags, dname, resource);
-
- xenUnifiedError (dconn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
- return -1;
-}
-
-static int
-xenUnifiedDomainMigratePerform (virDomainPtr dom,
- const char *cookie,
- int cookielen,
- const char *uri,
- unsigned long flags,
- const char *dname,
- unsigned long resource)
-{
- GET_PRIVATE(dom->conn);
-
- if (priv->opened[XEN_UNIFIED_XEND_OFFSET])
- return xenDaemonDomainMigratePerform (dom, cookie, cookielen, uri,
- flags, dname, resource);
-
- xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
- return -1;
-}
-
-static virDomainPtr
-xenUnifiedDomainMigrateFinish (virConnectPtr dconn,
- const char *dname,
- const char *cookie ATTRIBUTE_UNUSED,
- int cookielen ATTRIBUTE_UNUSED,
- const char *uri ATTRIBUTE_UNUSED,
- unsigned long flags ATTRIBUTE_UNUSED)
-{
- return xenUnifiedDomainLookupByName (dconn, dname);
-}
-
-static int
-xenUnifiedListDefinedDomains (virConnectPtr conn, char **const names,
- int maxnames)
-{
- GET_PRIVATE(conn);
- int i;
- int ret;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->listDefinedDomains) {
- ret = drivers[i]->listDefinedDomains (conn, names, maxnames);
- if (ret >= 0) return ret;
- }
-
- return -1;
-}
-
-static int
-xenUnifiedNumOfDefinedDomains (virConnectPtr conn)
-{
- GET_PRIVATE(conn);
- int i;
- int ret;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->numOfDefinedDomains) {
- ret = drivers[i]->numOfDefinedDomains (conn);
- if (ret >= 0) return ret;
- }
-
- return -1;
-}
-
-static int
-xenUnifiedDomainCreate (virDomainPtr dom)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->domainCreate &&
- drivers[i]->domainCreate (dom) == 0)
- return 0;
-
- return -1;
-}
-
-static virDomainPtr
-xenUnifiedDomainDefineXML (virConnectPtr conn, const char *xml)
-{
- GET_PRIVATE(conn);
- int i;
- virDomainPtr ret;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->domainDefineXML) {
- ret = drivers[i]->domainDefineXML (conn, xml);
- if (ret) return ret;
- }
-
- return NULL;
-}
-
-static int
-xenUnifiedDomainUndefine (virDomainPtr dom)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->domainUndefine &&
- drivers[i]->domainUndefine (dom) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainAttachDevice (virDomainPtr dom, const char *xml)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->domainAttachDevice &&
- drivers[i]->domainAttachDevice (dom, xml) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainDetachDevice (virDomainPtr dom, const char *xml)
-{
- GET_PRIVATE(dom->conn);
- int i;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
- if (priv->opened[i] && drivers[i]->domainDetachDevice &&
- drivers[i]->domainDetachDevice (dom, xml) == 0)
- return 0;
-
- return -1;
-}
-
-static int
-xenUnifiedDomainGetAutostart (virDomainPtr dom, int *autostart)
-{
- GET_PRIVATE(dom->conn);
-
- if (priv->xendConfigVersion < 3) {
- if (priv->opened[XEN_UNIFIED_XM_OFFSET])
- return xenXMDomainGetAutostart(dom, autostart);
- } else {
- if (priv->opened[XEN_UNIFIED_XEND_OFFSET])
- return xenDaemonDomainGetAutostart(dom, autostart);
- }
-
- xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
- return -1;
-}
-
-static int
-xenUnifiedDomainSetAutostart (virDomainPtr dom, int autostart)
-{
- GET_PRIVATE(dom->conn);
-
- if (priv->xendConfigVersion < 3) {
- if (priv->opened[XEN_UNIFIED_XM_OFFSET])
- return xenXMDomainSetAutostart(dom, autostart);
- } else {
- if (priv->opened[XEN_UNIFIED_XEND_OFFSET])
- return xenDaemonDomainSetAutostart(dom, autostart);
- }
-
- xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
- return -1;
-}
-
-static char *
-xenUnifiedDomainGetSchedulerType (virDomainPtr dom, int *nparams)
-{
- GET_PRIVATE(dom->conn);
- int i;
- char *schedulertype;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; i++) {
- if (priv->opened[i] && drivers[i]->domainGetSchedulerType) {
- schedulertype = drivers[i]->domainGetSchedulerType (dom, nparams);
- if (schedulertype != NULL)
- return(schedulertype);
- }
- }
- return(NULL);
-}
-
-static int
-xenUnifiedDomainGetSchedulerParameters (virDomainPtr dom,
- virSchedParameterPtr params, int *nparams)
-{
- GET_PRIVATE(dom->conn);
- int i, ret;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) {
- if (priv->opened[i] && drivers[i]->domainGetSchedulerParameters) {
- ret = drivers[i]->domainGetSchedulerParameters(dom, params, nparams);
- if (ret == 0)
- return(0);
- }
- }
- return(-1);
-}
-
-static int
-xenUnifiedDomainSetSchedulerParameters (virDomainPtr dom,
- virSchedParameterPtr params, int nparams)
-{
- GET_PRIVATE(dom->conn);
- int i, ret;
-
- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) {
- if (priv->opened[i] && drivers[i]->domainSetSchedulerParameters) {
- ret = drivers[i]->domainSetSchedulerParameters(dom, params, nparams);
- if (ret == 0)
- return 0;
- }
- }
-
- return(-1);
-}
-
-static int
-xenUnifiedDomainBlockStats (virDomainPtr dom, const char *path,
- struct _virDomainBlockStats *stats)
-{
- GET_PRIVATE (dom->conn);
-
- if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET])
- return xenHypervisorDomainBlockStats (dom, path, stats);
-
- xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
- return -1;
-}
-
-static int
-xenUnifiedDomainInterfaceStats (virDomainPtr dom, const char *path,
- struct _virDomainInterfaceStats *stats)
-{
- GET_PRIVATE (dom->conn);
-
- if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET])
- return xenHypervisorDomainInterfaceStats (dom, path, stats);
-
- xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
- return -1;
-}
-
-static int
-xenUnifiedDomainBlockPeek (virDomainPtr dom, const char *path,
- unsigned long long offset, size_t size,
- void *buffer, unsigned int flags ATTRIBUTE_UNUSED)
-{
- int r;
- GET_PRIVATE (dom->conn);
-
- if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
- r = xenDaemonDomainBlockPeek (dom, path, offset, size, buffer);
- if (r != -2) return r;
- /* r == -2 means declined, so fall through to XM driver ... */
- }
-
- if (priv->opened[XEN_UNIFIED_XM_OFFSET]) {
- if (xenXMDomainBlockPeek (dom, path, offset, size, buffer) == 0)
- return 0;
- }
-
- xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
- return -1;
-}
-
-static int
-xenUnifiedNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems,
- int startCell, int maxCells)
-{
- GET_PRIVATE (conn);
-
- if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET])
- return xenHypervisorNodeGetCellsFreeMemory (conn, freeMems,
- startCell, maxCells);
-
- xenUnifiedError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
- return -1;
-}
-
-static unsigned long long
-xenUnifiedNodeGetFreeMemory (virConnectPtr conn)
-{
- unsigned long long freeMem = 0;
- int ret;
- GET_PRIVATE (conn);
-
- if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET]) {
- ret = xenHypervisorNodeGetCellsFreeMemory (conn, &freeMem,
- -1, 1);
- if (ret != 1)
- return (0);
- return(freeMem);
- }
-
- xenUnifiedError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
- return(0);
-}
-
-static int
-xenUnifiedDomainEventRegister (virConnectPtr conn,
- virConnectDomainEventCallback callback,
- void *opaque,
- void (*freefunc)(void *))
-{
- GET_PRIVATE (conn);
-
- int ret;
- xenUnifiedLock(priv);
-
- if (priv->xsWatch == -1) {
- xenUnifiedError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
- xenUnifiedUnlock(priv);
- return -1;
- }
-
- ret = virDomainEventCallbackListAdd(conn, priv->domainEventCallbacks,
- callback, opaque, freefunc);
-
- if (ret == 0)
- conn->refs++;
-
- xenUnifiedUnlock(priv);
- return (ret);
-}
-
-static int
-xenUnifiedDomainEventDeregister (virConnectPtr conn,
- virConnectDomainEventCallback callback)
-{
- int ret;
- GET_PRIVATE (conn);
- xenUnifiedLock(priv);
-
- if (priv->xsWatch == -1) {
- xenUnifiedError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
- xenUnifiedUnlock(priv);
- return -1;
- }
-
- if (priv->domainEventDispatching)
- ret = virDomainEventCallbackListMarkDelete(conn, priv->domainEventCallbacks,
- callback);
- else
- ret = virDomainEventCallbackListRemove(conn, priv->domainEventCallbacks,
- callback);
-
- if (ret == 0)
- virUnrefConnect(conn);
-
- xenUnifiedUnlock(priv);
- return ret;
-}
-
-
-static int
-xenUnifiedNodeDeviceGetPciInfo (virNodeDevicePtr dev,
- unsigned *domain,
- unsigned *bus,
- unsigned *slot,
- unsigned *function)
-{
- virNodeDeviceDefPtr def = NULL;
- virNodeDevCapsDefPtr cap;
- char *xml = NULL;
- int ret = -1;
-
- xml = virNodeDeviceGetXMLDesc(dev, 0);
- if (!xml)
- goto out;
-
- def = virNodeDeviceDefParseString(dev->conn, xml, EXISTING_DEVICE);
- if (!def)
- goto out;
-
- cap = def->caps;
- while (cap) {
- if (cap->type == VIR_NODE_DEV_CAP_PCI_DEV) {
- *domain = cap->data.pci_dev.domain;
- *bus = cap->data.pci_dev.bus;
- *slot = cap->data.pci_dev.slot;
- *function = cap->data.pci_dev.function;
- break;
- }
-
- cap = cap->next;
- }
-
- if (!cap) {
- xenUnifiedError(dev->conn, VIR_ERR_INVALID_ARG,
- _("device %s is not a PCI device"), dev->name);
- goto out;
- }
-
- ret = 0;
-out:
- virNodeDeviceDefFree(def);
- VIR_FREE(xml);
- return ret;
-}
-
-static int
-xenUnifiedNodeDeviceDettach (virNodeDevicePtr dev)
-{
- pciDevice *pci;
- unsigned domain, bus, slot, function;
- int ret = -1;
-
- if (xenUnifiedNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
- return -1;
-
- pci = pciGetDevice(dev->conn, domain, bus, slot, function);
- if (!pci)
- return -1;
-
- if (pciDettachDevice(dev->conn, pci) < 0)
- goto out;
-
- ret = 0;
-out:
- pciFreeDevice(dev->conn, pci);
- return ret;
-}
-
-static int
-xenUnifiedNodeDeviceReAttach (virNodeDevicePtr dev)
-{
- pciDevice *pci;
- unsigned domain, bus, slot, function;
- int ret = -1;
-
- if (xenUnifiedNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
- return -1;
-
- pci = pciGetDevice(dev->conn, domain, bus, slot, function);
- if (!pci)
- return -1;
-
- if (pciReAttachDevice(dev->conn, pci) < 0)
- goto out;
-
- ret = 0;
-out:
- pciFreeDevice(dev->conn, pci);
- return ret;
-}
-
-static int
-xenUnifiedNodeDeviceReset (virNodeDevicePtr dev)
-{
- pciDevice *pci;
- unsigned domain, bus, slot, function;
- int ret = -1;
-
- if (xenUnifiedNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
- return -1;
-
- pci = pciGetDevice(dev->conn, domain, bus, slot, function);
- if (!pci)
- return -1;
-
- if (pciResetDevice(dev->conn, pci, NULL) < 0)
- goto out;
-
- ret = 0;
-out:
- pciFreeDevice(dev->conn, pci);
- return ret;
-}
-
-
-/*----- Register with libvirt.c, and initialise Xen drivers. -----*/
-
-/* The interface which we export upwards to libvirt.c. */
-static virDriver xenUnifiedDriver = {
- VIR_DRV_XEN_UNIFIED,
- "Xen",
- xenUnifiedOpen, /* open */
- xenUnifiedClose, /* close */
- xenUnifiedSupportsFeature, /* supports_feature */
- xenUnifiedType, /* type */
- xenUnifiedGetVersion, /* version */
- xenUnifiedGetHostname, /* getHostname */
- xenUnifiedGetMaxVcpus, /* getMaxVcpus */
- xenUnifiedNodeGetInfo, /* nodeGetInfo */
- xenUnifiedGetCapabilities, /* getCapabilities */
- xenUnifiedListDomains, /* listDomains */
- xenUnifiedNumOfDomains, /* numOfDomains */
- xenUnifiedDomainCreateXML, /* domainCreateXML */
- xenUnifiedDomainLookupByID, /* domainLookupByID */
- xenUnifiedDomainLookupByUUID, /* domainLookupByUUID */
- xenUnifiedDomainLookupByName, /* domainLookupByName */
- xenUnifiedDomainSuspend, /* domainSuspend */
- xenUnifiedDomainResume, /* domainResume */
- xenUnifiedDomainShutdown, /* domainShutdown */
- xenUnifiedDomainReboot, /* domainReboot */
- xenUnifiedDomainDestroy, /* domainDestroy */
- xenUnifiedDomainGetOSType, /* domainGetOSType */
- xenUnifiedDomainGetMaxMemory, /* domainGetMaxMemory */
- xenUnifiedDomainSetMaxMemory, /* domainSetMaxMemory */
- xenUnifiedDomainSetMemory, /* domainSetMemory */
- xenUnifiedDomainGetInfo, /* domainGetInfo */
- xenUnifiedDomainSave, /* domainSave */
- xenUnifiedDomainRestore, /* domainRestore */
- xenUnifiedDomainCoreDump, /* domainCoreDump */
- xenUnifiedDomainSetVcpus, /* domainSetVcpus */
- xenUnifiedDomainPinVcpu, /* domainPinVcpu */
- xenUnifiedDomainGetVcpus, /* domainGetVcpus */
- xenUnifiedDomainGetMaxVcpus, /* domainGetMaxVcpus */
- NULL, /* domainGetSecurityLabel */
- NULL, /* nodeGetSecurityModel */
- xenUnifiedDomainDumpXML, /* domainDumpXML */
- xenUnifiedDomainXMLFromNative, /* domainXmlFromNative */
- xenUnifiedDomainXMLToNative, /* domainXmlToNative */
- xenUnifiedListDefinedDomains, /* listDefinedDomains */
- xenUnifiedNumOfDefinedDomains, /* numOfDefinedDomains */
- xenUnifiedDomainCreate, /* domainCreate */
- xenUnifiedDomainDefineXML, /* domainDefineXML */
- xenUnifiedDomainUndefine, /* domainUndefine */
- xenUnifiedDomainAttachDevice, /* domainAttachDevice */
- xenUnifiedDomainDetachDevice, /* domainDetachDevice */
- xenUnifiedDomainGetAutostart, /* domainGetAutostart */
- xenUnifiedDomainSetAutostart, /* domainSetAutostart */
- xenUnifiedDomainGetSchedulerType, /* domainGetSchedulerType */
- xenUnifiedDomainGetSchedulerParameters, /* domainGetSchedulerParameters */
- xenUnifiedDomainSetSchedulerParameters, /* domainSetSchedulerParameters */
- xenUnifiedDomainMigratePrepare, /* domainMigratePrepare */
- xenUnifiedDomainMigratePerform, /* domainMigratePerform */
- xenUnifiedDomainMigrateFinish, /* domainMigrateFinish */
- xenUnifiedDomainBlockStats, /* domainBlockStats */
- xenUnifiedDomainInterfaceStats, /* domainInterfaceStats */
- xenUnifiedDomainBlockPeek, /* domainBlockPeek */
- NULL, /* domainMemoryPeek */
- xenUnifiedNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
- xenUnifiedNodeGetFreeMemory, /* getFreeMemory */
- xenUnifiedDomainEventRegister, /* domainEventRegister */
- xenUnifiedDomainEventDeregister, /* domainEventDeregister */
- NULL, /* domainMigratePrepare2 */
- NULL, /* domainMigrateFinish2 */
- xenUnifiedNodeDeviceDettach, /* nodeDeviceDettach */
- xenUnifiedNodeDeviceReAttach, /* nodeDeviceReAttach */
- xenUnifiedNodeDeviceReset, /* nodeDeviceReset */
-};
-
-/**
- * xenRegister:
- *
- * Register xen related drivers
- *
- * Returns the driver priority or -1 in case of error.
- */
-int
-xenRegister (void)
-{
- /* Ignore failures here. */
- (void) xenHypervisorInit ();
-
-#ifdef WITH_LIBVIRTD
- if (virRegisterStateDriver (&state_driver) == -1) return -1;
-#endif
-
- return virRegisterDriver (&xenUnifiedDriver);
-}
-
-/**
- * xenUnifiedDomainInfoListFree:
- *
- * Free the Domain Info List
- */
-void
-xenUnifiedDomainInfoListFree(xenUnifiedDomainInfoListPtr list)
-{
- int i;
-
- if (list == NULL)
- return;
-
- for (i=0; i<list->count; i++) {
- VIR_FREE(list->doms[i]->name);
- VIR_FREE(list->doms[i]);
- }
- VIR_FREE(list);
-}
-
-/**
- * xenUnifiedAddDomainInfo:
- *
- * Add name and uuid to the domain info list
- *
- * Returns: 0 on success, -1 on failure
- */
-int
-xenUnifiedAddDomainInfo(xenUnifiedDomainInfoListPtr list,
- int id, char *name,
- unsigned char *uuid)
-{
- xenUnifiedDomainInfoPtr info;
- int n;
-
- /* check if we already have this callback on our list */
- for (n=0; n < list->count; n++) {
- if (STREQ(list->doms[n]->name, name) &&
- !memcmp(list->doms[n]->uuid, uuid, VIR_UUID_BUFLEN)) {
- DEBUG0("WARNING: dom already tracked");
- return -1;
- }
- }
-
- if (VIR_ALLOC(info) < 0)
- goto memory_error;
- if (!(info->name = strdup(name)))
- goto memory_error;
-
- memcpy(info->uuid, uuid, VIR_UUID_BUFLEN);
- info->id = id;
-
- /* Make space on list */
- n = list->count;
- if (VIR_REALLOC_N(list->doms, n + 1) < 0) {
- goto memory_error;
- }
-
- list->doms[n] = info;
- list->count++;
- return 0;
-memory_error:
- virReportOOMError (NULL);
- if (info)
- VIR_FREE(info->name);
- VIR_FREE(info);
- return -1;
-}
-
-/**
- * xenUnifiedRemoveDomainInfo:
- *
- * Removes name and uuid to the domain info list
- *
- * Returns: 0 on success, -1 on failure
- */
-int
-xenUnifiedRemoveDomainInfo(xenUnifiedDomainInfoListPtr list,
- int id, char *name,
- unsigned char *uuid)
-{
- int i;
- for (i = 0 ; i < list->count ; i++) {
- if( list->doms[i]->id == id &&
- STREQ(list->doms[i]->name, name) &&
- !memcmp(list->doms[i]->uuid, uuid, VIR_UUID_BUFLEN)) {
-
- VIR_FREE(list->doms[i]->name);
- VIR_FREE(list->doms[i]);
-
- if (i < (list->count - 1))
- memmove(list->doms + i,
- list->doms + i + 1,
- sizeof(*(list->doms)) *
- (list->count - (i + 1)));
-
- if (VIR_REALLOC_N(list->doms,
- list->count - 1) < 0) {
- ; /* Failure to reduce memory allocation isn't fatal */
- }
- list->count--;
-
- return 0;
- }
- }
- return -1;
-}
-
-static void
-xenUnifiedDomainEventDispatchFunc(virConnectPtr conn,
- virDomainEventPtr event,
- virConnectDomainEventCallback cb,
- void *cbopaque,
- void *opaque)
-{
- xenUnifiedPrivatePtr priv = opaque;
-
- /*
- * Release the lock while the callback is running so that
- * we're re-entrant safe for callback work - the callback
- * may want to invoke other virt functions & we have already
- * protected the one piece of state we have - the callback
- * list
- */
- xenUnifiedUnlock(priv);
- virDomainEventDispatchDefaultFunc(conn, event, cb, cbopaque, NULL);
- xenUnifiedLock(priv);
-}
-
-/**
- * xenUnifiedDomainEventDispatch:
- * @priv: the connection to dispatch events on
- * @event: the event to dispatch
- *
- * Dispatch domain events to registered callbacks
- *
- * The caller must hold the lock in 'priv' before invoking
- *
- */
-void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
- virDomainEventPtr event)
-{
- if (!priv)
- return;
-
- priv->domainEventDispatching = 1;
-
- if (priv->domainEventCallbacks) {
- virDomainEventDispatch(event,
- priv->domainEventCallbacks,
- xenUnifiedDomainEventDispatchFunc,
- priv);
-
- /* Purge any deleted callbacks */
- virDomainEventCallbackListPurgeMarked(priv->domainEventCallbacks);
- }
-
- virDomainEventFree(event);
-
- priv->domainEventDispatching = 0;
-}
-
-void xenUnifiedLock(xenUnifiedPrivatePtr priv)
-{
- virMutexLock(&priv->lock);
-}
-
-void xenUnifiedUnlock(xenUnifiedPrivatePtr priv)
-{
- virMutexUnlock(&priv->lock);
-}
+++ /dev/null
-/*
- * xen_unified.c: Unified Xen driver.
- *
- * Copyright (C) 2007 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Richard W.M. Jones <rjones@redhat.com>
- */
-
-#ifndef __VIR_XEN_UNIFIED_H__
-#define __VIR_XEN_UNIFIED_H__
-
-#include "internal.h"
-#include "capabilities.h"
-#include "driver.h"
-#include "domain_conf.h"
-#include "xs_internal.h"
-#if WITH_XEN_INOTIFY
-#include "xen_inotify.h"
-#endif
-#include "domain_event.h"
-#include "hash.h"
-
-#ifndef HAVE_WINSOCK2_H
-#include <sys/un.h>
-#include <netinet/in.h>
-#else
-#include <winsock2.h>
-#endif
-
-extern int xenRegister (void);
-
-#define XEN_UNIFIED_HYPERVISOR_OFFSET 0
-#define XEN_UNIFIED_PROXY_OFFSET 1
-#define XEN_UNIFIED_XEND_OFFSET 2
-#define XEN_UNIFIED_XS_OFFSET 3
-#define XEN_UNIFIED_XM_OFFSET 4
-
-#if WITH_XEN_INOTIFY
-#define XEN_UNIFIED_INOTIFY_OFFSET 5
-#define XEN_UNIFIED_NR_DRIVERS 6
-#else
-#define XEN_UNIFIED_NR_DRIVERS 5
-#endif
-
-#define MIN_XEN_GUEST_SIZE 64 /* 64 megabytes */
-
-#define XEN_CONFIG_FORMAT_XM "xen-xm"
-#define XEN_CONFIG_FORMAT_SEXPR "xen-sxpr"
-
-/* _xenUnifiedDriver:
- *
- * Entry points into the underlying Xen drivers. This structure
- * will eventually go away and instead xen unified will make direct
- * calls to the underlying Xen drivers.
- *
- * To reiterate - the goal is to remove elements from this structure
- * until it is empty, replacing indirect calls through this
- * structure with direct calls in xen_unified.c.
- */
-struct xenUnifiedDriver {
- virDrvOpen open;
- virDrvClose close;
- virDrvGetVersion version;
- virDrvGetHostname getHostname;
- virDrvNodeGetInfo nodeGetInfo;
- virDrvGetCapabilities getCapabilities;
- virDrvListDomains listDomains;
- virDrvNumOfDomains numOfDomains;
- virDrvDomainCreateXML domainCreateXML;
- virDrvDomainSuspend domainSuspend;
- virDrvDomainResume domainResume;
- virDrvDomainShutdown domainShutdown;
- virDrvDomainReboot domainReboot;
- virDrvDomainDestroy domainDestroy;
- virDrvDomainGetOSType domainGetOSType;
- virDrvDomainGetMaxMemory domainGetMaxMemory;
- virDrvDomainSetMaxMemory domainSetMaxMemory;
- virDrvDomainSetMemory domainSetMemory;
- virDrvDomainGetInfo domainGetInfo;
- virDrvDomainSave domainSave;
- virDrvDomainRestore domainRestore;
- virDrvDomainCoreDump domainCoreDump;
- virDrvDomainSetVcpus domainSetVcpus;
- virDrvDomainPinVcpu domainPinVcpu;
- virDrvDomainGetVcpus domainGetVcpus;
- virDrvDomainGetMaxVcpus domainGetMaxVcpus;
- virDrvListDefinedDomains listDefinedDomains;
- virDrvNumOfDefinedDomains numOfDefinedDomains;
- virDrvDomainCreate domainCreate;
- virDrvDomainDefineXML domainDefineXML;
- virDrvDomainUndefine domainUndefine;
- virDrvDomainAttachDevice domainAttachDevice;
- virDrvDomainDetachDevice domainDetachDevice;
- virDrvDomainGetAutostart domainGetAutostart;
- virDrvDomainSetAutostart domainSetAutostart;
- virDrvDomainGetSchedulerType domainGetSchedulerType;
- virDrvDomainGetSchedulerParameters domainGetSchedulerParameters;
- virDrvDomainSetSchedulerParameters domainSetSchedulerParameters;
-};
-
-typedef struct xenXMConfCache *xenXMConfCachePtr;
-typedef struct xenXMConfCache {
- time_t refreshedAt;
- char filename[PATH_MAX];
- virDomainDefPtr def;
-} xenXMConfCache;
-
-/* xenUnifiedDomainInfoPtr:
- * The minimal state we have about active domains
- * This is the minmal info necessary to still get a
- * virDomainPtr when the domain goes away
- */
-struct _xenUnifiedDomainInfo {
- int id;
- char *name;
- unsigned char uuid[VIR_UUID_BUFLEN];
-};
-typedef struct _xenUnifiedDomainInfo xenUnifiedDomainInfo;
-typedef xenUnifiedDomainInfo *xenUnifiedDomainInfoPtr;
-
-struct _xenUnifiedDomainInfoList {
- unsigned int count;
- xenUnifiedDomainInfoPtr *doms;
-};
-typedef struct _xenUnifiedDomainInfoList xenUnifiedDomainInfoList;
-typedef xenUnifiedDomainInfoList *xenUnifiedDomainInfoListPtr;
-
-/* xenUnifiedPrivatePtr:
- *
- * Per-connection private data, stored in conn->privateData. All Xen
- * low-level drivers access parts of this structure.
- */
-struct _xenUnifiedPrivate {
- virMutex lock;
-
- /* These initial vars are initialized in Open method
- * and readonly thereafter, so can be used without
- * holding the lock
- */
- virCapsPtr caps;
- int handle; /* Xen hypervisor handle */
-
- int xendConfigVersion; /* XenD config version */
-
- /* connection to xend */
- struct sockaddr_storage addr;
- socklen_t addrlen;
- int addrfamily;
- int addrprotocol;
-
- /* Keep track of the drivers which opened. We keep a yes/no flag
- * here for each driver, corresponding to the array drivers in
- * xen_unified.c.
- */
- int opened[XEN_UNIFIED_NR_DRIVERS];
-
-
- /*
- * Everything from this point onwards must be protected
- * by the lock when used
- */
-
- struct xs_handle *xshandle; /* handle to talk to the xenstore */
-
- int proxy; /* fd of proxy. */
-
-
- /* A list of xenstore watches */
- xenStoreWatchListPtr xsWatchList;
- int xsWatch;
- /* A list of active domain name/uuids */
- xenUnifiedDomainInfoListPtr activeDomainList;
-
- /* NUMA topology info cache */
- int nbNodeCells;
- int nbNodeCpus;
-
- /* An list of callbacks */
- virDomainEventCallbackListPtr domainEventCallbacks;
- int domainEventDispatching;
-
- /* Location of config files, either /etc
- * or /var/lib/xen */
- const char *configDir;
-
-#if WITH_XEN_INOTIFY
- /* The inotify fd */
- int inotifyFD;
- int inotifyWatch;
-
- int useXenConfigCache ;
- xenUnifiedDomainInfoListPtr configInfoList;
-#endif
-
- /* For the 'xm' driver */
- /* Primary config file name -> virDomainDef map */
- virHashTablePtr configCache;
- /* Domain name to config file name */
- virHashTablePtr nameConfigMap;
- /* So we don't refresh too often */
- time_t lastRefresh;
-};
-
-typedef struct _xenUnifiedPrivate *xenUnifiedPrivatePtr;
-
-char *xenDomainUsedCpus(virDomainPtr dom);
-
-void xenUnifiedDomainInfoListFree(xenUnifiedDomainInfoListPtr info);
-int xenUnifiedAddDomainInfo(xenUnifiedDomainInfoListPtr info,
- int id, char *name,
- unsigned char *uuid);
-int xenUnifiedRemoveDomainInfo(xenUnifiedDomainInfoListPtr info,
- int id, char *name,
- unsigned char *uuid);
-void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
- virDomainEventPtr event);
-unsigned long xenUnifiedVersion(void);
-
-#ifndef PROXY
-void xenUnifiedLock(xenUnifiedPrivatePtr priv);
-void xenUnifiedUnlock(xenUnifiedPrivatePtr priv);
-#else
-#define xenUnifiedLock(p) do {} while(0)
-#define xenUnifiedUnlock(p) do {} while(0)
-#endif
-
-#endif /* __VIR_XEN_UNIFIED_H__ */
+++ /dev/null
-/*
- * xend_internal.c: access to Xen though the Xen Daemon interface
- *
- * Copyright (C) 2005
- *
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License. See the file COPYING.LIB in the main directory of this
- * archive for more details.
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <math.h>
-#include <stdarg.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <libxml/uri.h>
-#include <errno.h>
-
-#include "virterror_internal.h"
-#include "logging.h"
-#include "datatypes.h"
-#include "xend_internal.h"
-#include "driver.h"
-#include "util.h"
-#include "sexpr.h"
-#include "buf.h"
-#include "uuid.h"
-#include "xen_unified.h"
-#include "xen_internal.h"
-#include "xs_internal.h" /* To extract VNC port & Serial console TTY */
-#include "memory.h"
-
-/* required for cpumap_t */
-#include <xen/dom0_ops.h>
-
-#define VIR_FROM_THIS VIR_FROM_XEND
-
-#ifndef PROXY
-
-/*
- * The number of Xen scheduler parameters
- */
-#define XEN_SCHED_SEDF_NPARAM 6
-#define XEN_SCHED_CRED_NPARAM 2
-
-#endif /* PROXY */
-
-#ifdef WITH_RHEL5_API
-#define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 0
-#define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 2
-#else
-#define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 3
-#define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 3
-#endif
-
-
-#ifndef PROXY
-static int
-xenDaemonFormatSxprDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
- virDomainDiskDefPtr def,
- virBufferPtr buf,
- int hvm,
- int xendConfigVersion,
- int isAttach);
-static int
-xenDaemonFormatSxprNet(virConnectPtr conn ATTRIBUTE_UNUSED,
- virDomainNetDefPtr def,
- virBufferPtr buf,
- int hvm,
- int xendConfigVersion,
- int isAttach);
-static int
-xenDaemonFormatSxprOnePCI(virConnectPtr conn,
- virDomainHostdevDefPtr def,
- virBufferPtr buf);
-
-static int
-virDomainXMLDevID(virDomainPtr domain,
- virDomainDeviceDefPtr dev,
- char *class,
- char *ref,
- int ref_len);
-#endif
-
-#define virXendError(conn, code, fmt...) \
- virReportErrorHelper(conn, VIR_FROM_XEND, code, __FILE__, \
- __FUNCTION__, __LINE__, fmt)
-
-#define virXendErrorInt(conn, code, ival) \
- virXendError(conn, code, "%d", ival)
-
-/**
- * do_connect:
- * @xend: pointer to the Xen Daemon structure
- *
- * Internal routine to (re)connect to the daemon
- *
- * Returns the socket file descriptor or -1 in case of error
- */
-static int
-do_connect(virConnectPtr xend)
-{
- int s;
- int serrno;
- int no_slow_start = 1;
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) xend->privateData;
-
- s = socket(priv->addrfamily, SOCK_STREAM, priv->addrprotocol);
- if (s == -1) {
- virXendError(xend, VIR_ERR_INTERNAL_ERROR,
- "%s", _("failed to create a socket"));
- return -1;
- }
-
- /*
- * try to desactivate slow-start
- */
- setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *)&no_slow_start,
- sizeof(no_slow_start));
-
-
- if (connect(s, (struct sockaddr *)&priv->addr, priv->addrlen) == -1) {
- serrno = errno;
- close(s);
- errno = serrno;
- s = -1;
-
- /*
- * Connecting to XenD when privileged is mandatory, so log this
- * error
- */
- if (xenHavePrivilege()) {
- virXendError(xend, VIR_ERR_INTERNAL_ERROR,
- "%s", _("failed to connect to xend"));
- }
- }
-
- return s;
-}
-
-/**
- * wr_sync:
- * @xend: the xend connection object
- * @fd: the file descriptor
- * @buffer: the I/O buffer
- * @size: the size of the I/O
- * @do_read: write operation if 0, read operation otherwise
- *
- * Do a synchronous read or write on the file descriptor
- *
- * Returns the number of bytes exchanged, or -1 in case of error
- */
-static size_t
-wr_sync(virConnectPtr xend, int fd, void *buffer, size_t size, int do_read)
-{
- size_t offset = 0;
-
- while (offset < size) {
- ssize_t len;
-
- if (do_read) {
- len = read(fd, ((char *) buffer) + offset, size - offset);
- } else {
- len = write(fd, ((char *) buffer) + offset, size - offset);
- }
-
- /* recoverable error, retry */
- if ((len == -1) && ((errno == EAGAIN) || (errno == EINTR))) {
- continue;
- }
-
- /* eof */
- if (len == 0) {
- break;
- }
-
- /* unrecoverable error */
- if (len == -1) {
- if (do_read)
- virXendError(xend, VIR_ERR_INTERNAL_ERROR,
- "%s", _("failed to read from Xen Daemon"));
- else
- virXendError(xend, VIR_ERR_INTERNAL_ERROR,
- "%s", _("failed to read from Xen Daemon"));
-
- return (-1);
- }
-
- offset += len;
- }
-
- return offset;
-}
-
-/**
- * sread:
- * @xend: the xend connection object
- * @fd: the file descriptor
- * @buffer: the I/O buffer
- * @size: the size of the I/O
- *
- * Internal routine to do a synchronous read
- *
- * Returns the number of bytes read, or -1 in case of error
- */
-static ssize_t
-sread(virConnectPtr xend, int fd, void *buffer, size_t size)
-{
- return wr_sync(xend, fd, buffer, size, 1);
-}
-
-/**
- * swrite:
- * @xend: the xend connection object
- * @fd: the file descriptor
- * @buffer: the I/O buffer
- * @size: the size of the I/O
- *
- * Internal routine to do a synchronous write
- *
- * Returns the number of bytes written, or -1 in case of error
- */
-static ssize_t
-swrite(virConnectPtr xend, int fd, const void *buffer, size_t size)
-{
- return wr_sync(xend, fd, (void *) buffer, size, 0);
-}
-
-/**
- * swrites:
- * @xend: the xend connection object
- * @fd: the file descriptor
- * @string: the string to write
- *
- * Internal routine to do a synchronous write of a string
- *
- * Returns the number of bytes written, or -1 in case of error
- */
-static ssize_t
-swrites(virConnectPtr xend, int fd, const char *string)
-{
- return swrite(xend, fd, string, strlen(string));
-}
-
-/**
- * sreads:
- * @xend: the xend connection object
- * @fd: the file descriptor
- * @buffer: the I/O buffer
- * @n_buffer: the size of the I/O buffer
- *
- * Internal routine to do a synchronous read of a line
- *
- * Returns the number of bytes read, or -1 in case of error
- */
-static ssize_t
-sreads(virConnectPtr xend, int fd, char *buffer, size_t n_buffer)
-{
- size_t offset;
-
- if (n_buffer < 1)
- return (-1);
-
- for (offset = 0; offset < (n_buffer - 1); offset++) {
- ssize_t ret;
-
- ret = sread(xend, fd, buffer + offset, 1);
- if (ret == 0)
- break;
- else if (ret == -1)
- return ret;
-
- if (buffer[offset] == '\n') {
- offset++;
- break;
- }
- }
- buffer[offset] = 0;
-
- return offset;
-}
-
-static int
-istartswith(const char *haystack, const char *needle)
-{
- return STRCASEEQLEN(haystack, needle, strlen(needle));
-}
-
-
-/**
- * xend_req:
- * @xend: the xend connection object
- * @fd: the file descriptor
- * @content: the buffer to store the content
- * @n_content: the size of the buffer
- *
- * Read the HTTP response from a Xen Daemon request.
- *
- * Returns the HTTP return code.
- */
-static int
-xend_req(virConnectPtr xend, int fd, char *content, size_t n_content)
-{
- char buffer[4096];
- int content_length = -1;
- int retcode = 0;
-
- while (sreads(xend, fd, buffer, sizeof(buffer)) > 0) {
- if (STREQ(buffer, "\r\n"))
- break;
-
- if (istartswith(buffer, "Content-Length: "))
- content_length = atoi(buffer + 16);
- else if (istartswith(buffer, "HTTP/1.1 "))
- retcode = atoi(buffer + 9);
- }
-
- if (content_length > -1) {
- ssize_t ret;
-
- if ((unsigned int) content_length > (n_content + 1))
- content_length = n_content - 1;
-
- ret = sread(xend, fd, content, content_length);
- if (ret < 0)
- return -1;
-
- content[ret] = 0;
- } else {
- content[0] = 0;
- }
-
- return retcode;
-}
-
-/**
- * xend_get:
- * @xend: pointer to the Xen Daemon structure
- * @path: the path used for the HTTP request
- * @content: the buffer to store the content
- * @n_content: the size of the buffer
- *
- * Do an HTTP GET RPC with the Xen Daemon
- *
- * Returns the HTTP return code or -1 in case or error.
- */
-static int
-xend_get(virConnectPtr xend, const char *path,
- char *content, size_t n_content)
-{
- int ret;
- int s = do_connect(xend);
-
- if (s == -1)
- return s;
-
- swrites(xend, s, "GET ");
- swrites(xend, s, path);
- swrites(xend, s, " HTTP/1.1\r\n");
-
- swrites(xend, s,
- "Host: localhost:8000\r\n"
- "Accept-Encoding: identity\r\n"
- "Content-Type: application/x-www-form-urlencoded\r\n" "\r\n");
-
- ret = xend_req(xend, s, content, n_content);
- close(s);
-
- if (((ret < 0) || (ret >= 300)) &&
- ((ret != 404) || (!STRPREFIX(path, "/xend/domain/")))) {
- virXendError(xend, VIR_ERR_GET_FAILED,
- _("%d status from xen daemon: %s:%s"),
- ret, path, content);
- }
-
- return ret;
-}
-
-#ifndef PROXY
-/**
- * xend_post:
- * @xend: pointer to the Xen Daemon structure
- * @path: the path used for the HTTP request
- * @ops: the information sent for the POST
- * @content: the buffer to store the content
- * @n_content: the size of the buffer
- *
- * Do an HTTP POST RPC with the Xen Daemon, this usually makes changes at the
- * Xen level.
- *
- * Returns the HTTP return code or -1 in case or error.
- */
-static int
-xend_post(virConnectPtr xend, const char *path, const char *ops,
- char *content, size_t n_content)
-{
- char buffer[100];
- int ret;
- int s = do_connect(xend);
-
- if (s == -1)
- return s;
-
- swrites(xend, s, "POST ");
- swrites(xend, s, path);
- swrites(xend, s, " HTTP/1.1\r\n");
-
- swrites(xend, s,
- "Host: localhost:8000\r\n"
- "Accept-Encoding: identity\r\n"
- "Content-Type: application/x-www-form-urlencoded\r\n"
- "Content-Length: ");
- snprintf(buffer, sizeof(buffer), "%d", (int) strlen(ops));
- swrites(xend ,s, buffer);
- swrites(xend, s, "\r\n\r\n");
- swrites(xend, s, ops);
-
- ret = xend_req(xend, s, content, n_content);
- close(s);
-
- if ((ret < 0) || (ret >= 300)) {
- virXendError(xend, VIR_ERR_POST_FAILED,
- _("xend_post: error from xen daemon: %s"), content);
- } else if ((ret == 202) && (strstr(content, "failed") != NULL)) {
- virXendError(xend, VIR_ERR_POST_FAILED,
- _("xend_post: error from xen daemon: %s"), content);
- ret = -1;
- } else if (((ret >= 200) && (ret <= 202)) && (strstr(content, "xend.err") != NULL)) {
- /* This is to catch case of things like 'virsh dump Domain-0 foo'
- * which returns a success code, but the word 'xend.err'
- * in body to indicate error :-(
- */
- virXendError(xend, VIR_ERR_POST_FAILED,
- _("xend_post: error from xen daemon: %s"), content);
- ret = -1;
- }
-
- return ret;
-}
-#endif /* ! PROXY */
-
-
-/**
- * http2unix:
- * @xend: the xend connection object
- * @ret: the http return code
- *
- * Convert the HTTP return code to 0/-1 and set errno if needed
- *
- * Return -1 in case of error code 0 otherwise
- */
-static int
-http2unix(virConnectPtr xend, int ret)
-{
- switch (ret) {
- case -1:
- break;
- case 200:
- case 201:
- case 202:
- return 0;
- case 404:
- errno = ESRCH;
- break;
- case 500:
- errno = EIO;
- break;
- default:
- virXendErrorInt(xend, VIR_ERR_HTTP_ERROR, ret);
- errno = EINVAL;
- break;
- }
- return -1;
-}
-
-#ifndef PROXY
-/**
- * xend_op_ext:
- * @xend: pointer to the Xen Daemon structure
- * @path: path for the object
- * @error: buffer for the error output
- * @n_error: size of @error
- * @key: the key for the operation
- * @ap: input values to pass to the operation
- *
- * internal routine to run a POST RPC operation to the Xen Daemon
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-static int
-xend_op_ext(virConnectPtr xend, const char *path, char *error,
- size_t n_error, const char *key, va_list ap)
-{
- const char *k = key, *v;
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- int ret;
- char *content;
-
- while (k) {
- v = va_arg(ap, const char *);
-
- virBufferVSprintf(&buf, "%s", k);
- virBufferVSprintf(&buf, "%s", "=");
- virBufferVSprintf(&buf, "%s", v);
- k = va_arg(ap, const char *);
-
- if (k)
- virBufferVSprintf(&buf, "%s", "&");
- }
-
- if (virBufferError(&buf)) {
- virReportOOMError(NULL);
- return -1;
- }
-
- content = virBufferContentAndReset(&buf);
- ret = http2unix(xend, xend_post(xend, path, content, error, n_error));
- VIR_FREE(content);
-
- return ret;
-}
-
-
-/**
- * xend_op:
- * @xend: pointer to the Xen Daemon structure
- * @name: the domain name target of this operation
- * @error: buffer for the error output
- * @n_error: size of @error
- * @key: the key for the operation
- * @ap: input values to pass to the operation
- * @...: input values to pass to the operation
- *
- * internal routine to run a POST RPC operation to the Xen Daemon targetting
- * a given domain.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-static int
-xend_op(virConnectPtr xend, const char *name, const char *key, ...)
-{
- char buffer[1024];
- char error[1024];
- va_list ap;
- int ret;
-
- snprintf(buffer, sizeof(buffer), "/xend/domain/%s", name);
-
- va_start(ap, key);
- ret = xend_op_ext(xend, buffer, error, sizeof(error), key, ap);
- va_end(ap);
-
- return ret;
-}
-
-#endif /* ! PROXY */
-
-/**
- * sexpr_get:
- * @xend: pointer to the Xen Daemon structure
- * @fmt: format string for the path of the operation
- * @...: extra data to build the path of the operation
- *
- * Internal routine to run a simple GET RPC operation to the Xen Daemon
- *
- * Returns a parsed S-Expression in case of success, NULL in case of failure
- */
-static struct sexpr *sexpr_get(virConnectPtr xend, const char *fmt, ...)
- ATTRIBUTE_FMT_PRINTF(2,3);
-
-static struct sexpr *
-sexpr_get(virConnectPtr xend, const char *fmt, ...)
-{
- char buffer[4096];
- char path[1024];
- va_list ap;
- int ret;
-
- va_start(ap, fmt);
- vsnprintf(path, sizeof(path), fmt, ap);
- va_end(ap);
-
- ret = xend_get(xend, path, buffer, sizeof(buffer));
- ret = http2unix(xend ,ret);
- if (ret == -1)
- return NULL;
-
- return string2sexpr(buffer);
-}
-
-/**
- * sexpr_int:
- * @sexpr: an S-Expression
- * @name: the name for the value
- *
- * convenience function to lookup an int value in the S-Expression
- *
- * Returns the value found or 0 if not found (but may not be an error).
- * This function suffers from the flaw that zero is both a correct
- * return value and an error indicator: careful!
- */
-static int
-sexpr_int(const struct sexpr *sexpr, const char *name)
-{
- const char *value = sexpr_node(sexpr, name);
-
- if (value) {
- return strtol(value, NULL, 0);
- }
- return 0;
-}
-
-
-/**
- * sexpr_float:
- * @sexpr: an S-Expression
- * @name: the name for the value
- *
- * convenience function to lookup a float value in the S-Expression
- *
- * Returns the value found or 0 if not found (but may not be an error)
- */
-static double
-sexpr_float(const struct sexpr *sexpr, const char *name)
-{
- const char *value = sexpr_node(sexpr, name);
-
- if (value) {
- return strtod(value, NULL);
- }
- return 0;
-}
-
-/**
- * sexpr_u64:
- * @sexpr: an S-Expression
- * @name: the name for the value
- *
- * convenience function to lookup a 64bits unsigned int value in the
- * S-Expression
- *
- * Returns the value found or 0 if not found (but may not be an error)
- */
-static uint64_t
-sexpr_u64(const struct sexpr *sexpr, const char *name)
-{
- const char *value = sexpr_node(sexpr, name);
-
- if (value) {
- return strtoll(value, NULL, 0);
- }
- return 0;
-}
-
-
-/**
- * sexpr_uuid:
- * @ptr: where to store the UUID, incremented
- * @sexpr: an S-Expression
- * @name: the name for the value
- *
- * convenience function to lookup an UUID value from the S-Expression
- *
- * Returns a -1 on error, 0 on success
- */
-static int
-sexpr_uuid(unsigned char *ptr, const struct sexpr *node, const char *path)
-{
- const char *r = sexpr_node(node, path);
- if (!r)
- return -1;
- return virUUIDParse(r, ptr);
-}
-
-
-#ifndef PROXY
-/**
- * urlencode:
- * @string: the input URL
- *
- * Encode an URL see RFC 2396 and following
- *
- * Returns the new string or NULL in case of error.
- */
-static char *
-urlencode(const char *string)
-{
- size_t len = strlen(string);
- char *buffer;
- char *ptr;
- size_t i;
-
- if (VIR_ALLOC_N(buffer, len * 3 + 1) < 0) {
- virReportOOMError(NULL);
- return (NULL);
- }
- ptr = buffer;
- for (i = 0; i < len; i++) {
- switch (string[i]) {
- case ' ':
- case '\n':
- snprintf(ptr, 4, "%%%02x", string[i]);
- ptr += 3;
- break;
- default:
- *ptr = string[i];
- ptr++;
- }
- }
-
- *ptr = 0;
-
- return buffer;
-}
-#endif /* ! PROXY */
-
-/* PUBLIC FUNCTIONS */
-
-/**
- * xenDaemonOpen_unix:
- * @conn: an existing virtual connection block
- * @path: the path for the Xen Daemon socket
- *
- * Creates a localhost Xen Daemon connection
- * Note: this doesn't try to check if the connection actually works
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-int
-xenDaemonOpen_unix(virConnectPtr conn, const char *path)
-{
- struct sockaddr_un *addr;
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- if ((conn == NULL) || (path == NULL))
- return (-1);
-
- memset(&priv->addr, 0, sizeof(priv->addr));
- priv->addrfamily = AF_UNIX;
- /*
- * This must be zero on Solaris at least for AF_UNIX (which should
- * really be PF_UNIX, but doesn't matter).
- */
- priv->addrprotocol = 0;
- priv->addrlen = sizeof(struct sockaddr_un);
-
- addr = (struct sockaddr_un *)&priv->addr;
- addr->sun_family = AF_UNIX;
- memset(addr->sun_path, 0, sizeof(addr->sun_path));
- strncpy(addr->sun_path, path, sizeof(addr->sun_path));
-
- return (0);
-}
-
-#ifndef PROXY
-/**
- * xenDaemonOpen_tcp:
- * @conn: an existing virtual connection block
- * @host: the host name for the Xen Daemon
- * @port: the port
- *
- * Creates a possibly remote Xen Daemon connection
- * Note: this doesn't try to check if the connection actually works
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-static int
-xenDaemonOpen_tcp(virConnectPtr conn, const char *host, const char *port)
-{
- xenUnifiedPrivatePtr priv;
- struct addrinfo *res, *r;
- struct addrinfo hints;
- int saved_errno = EINVAL;
- int ret;
-
- if ((conn == NULL) || (host == NULL) || (port == NULL))
- return (-1);
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- priv->addrlen = 0;
- memset(&priv->addr, 0, sizeof(priv->addr));
-
- // http://people.redhat.com/drepper/userapi-ipv6.html
- memset (&hints, 0, sizeof hints);
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_ADDRCONFIG;
-
- ret = getaddrinfo (host, port, &hints, &res);
- if (ret != 0) {
- virXendError(NULL, VIR_ERR_UNKNOWN_HOST,
- _("unable to resolve hostname '%s': %s"),
- host, gai_strerror (ret));
- return -1;
- }
-
- /* Try to connect to each returned address in turn. */
- for (r = res; r; r = r->ai_next) {
- int sock;
-
- sock = socket (r->ai_family, SOCK_STREAM, r->ai_protocol);
- if (sock == -1) {
- saved_errno = errno;
- continue;
- }
-
- if (connect (sock, r->ai_addr, r->ai_addrlen) == -1) {
- saved_errno = errno;
- close (sock);
- continue;
- }
-
- priv->addrlen = r->ai_addrlen;
- priv->addrfamily = r->ai_family;
- priv->addrprotocol = r->ai_protocol;
- memcpy(&priv->addr,
- r->ai_addr,
- r->ai_addrlen);
- close(sock);
- break;
- }
-
- freeaddrinfo (res);
-
- if (!priv->addrlen) {
- /* Don't raise error when unprivileged, since proxy takes over */
- if (xenHavePrivilege())
- virReportSystemError(conn, saved_errno,
- _("unable to connect to '%s:%s'"),
- host, port);
- return -1;
- }
-
- return 0;
-}
-
-
-/**
- * xend_wait_for_devices:
- * @xend: pointer to the Xem Daemon block
- * @name: name for the domain
- *
- * Block the domain until all the virtual devices are ready. This operation
- * is needed when creating a domain before resuming it.
- *
- * Returns 0 in case of success, -1 (with errno) in case of error.
- */
-int
-xend_wait_for_devices(virConnectPtr xend, const char *name)
-{
- return xend_op(xend, name, "op", "wait_for_devices", NULL);
-}
-
-
-#endif /* PROXY */
-
-
-/**
- * xenDaemonListDomainsOld:
- * @xend: pointer to the Xem Daemon block
- *
- * This method will return an array of names of currently running
- * domains. The memory should be released will a call to free().
- *
- * Returns a list of names or NULL in case of error.
- */
-char **
-xenDaemonListDomainsOld(virConnectPtr xend)
-{
- size_t extra = 0;
- struct sexpr *root = NULL;
- char **ret = NULL;
- int count = 0;
- int i;
- char *ptr;
- struct sexpr *_for_i, *node;
-
- root = sexpr_get(xend, "/xend/domain");
- if (root == NULL)
- goto error;
-
- for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
- _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
- if (node->kind != SEXPR_VALUE)
- continue;
- extra += strlen(node->u.value) + 1;
- count++;
- }
-
- /*
- * We can'tuse the normal allocation routines as we are mixing
- * an array of char * at the beginning followed by an array of char
- * ret points to the NULL terminated array of char *
- * ptr points to the current string after that array but in the same
- * allocated block
- */
- if (virAlloc((void *)&ptr,
- (count + 1) * sizeof(char *) + extra * sizeof(char)) < 0)
- goto error;
-
- ret = (char **) ptr;
- ptr += sizeof(char *) * (count + 1);
-
- i = 0;
- for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
- _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
- if (node->kind != SEXPR_VALUE)
- continue;
- ret[i] = ptr;
- strcpy(ptr, node->u.value);
- ptr += strlen(node->u.value) + 1;
- i++;
- }
-
- ret[i] = NULL;
-
- error:
- sexpr_free(root);
- return ret;
-}
-
-#ifndef PROXY
-/**
- * xenDaemonDomainCreateXML:
- * @xend: A xend instance
- * @sexpr: An S-Expr description of the domain.
- *
- * This method will create a domain based the passed in description. The
- * domain will be paused after creation and must be unpaused with
- * xenDaemonResumeDomain() to begin execution.
- * This method may be deprecated once switching to XML-RPC based communcations
- * with xend.
- *
- * Returns 0 for success, -1 (with errno) on error
- */
-
-int
-xenDaemonDomainCreateXML(virConnectPtr xend, const char *sexpr)
-{
- int ret, serrno;
- char *ptr;
-
- ptr = urlencode(sexpr);
- if (ptr == NULL) {
- /* this should be caught at the interface but ... */
- virXendError(xend, VIR_ERR_INTERNAL_ERROR,
- "%s", _("failed to urlencode the create S-Expr"));
- return (-1);
- }
-
- ret = xend_op(xend, "", "op", "create", "config", ptr, NULL);
-
- serrno = errno;
- VIR_FREE(ptr);
- errno = serrno;
-
- return ret;
-}
-#endif /* ! PROXY */
-
-/**
- * xenDaemonDomainLookupByName_ids:
- * @xend: A xend instance
- * @domname: The name of the domain
- * @uuid: return value for the UUID if not NULL
- *
- * This method looks up the id of a domain
- *
- * Returns the id on success; -1 (with errno) on error
- */
-int
-xenDaemonDomainLookupByName_ids(virConnectPtr xend, const char *domname,
- unsigned char *uuid)
-{
- struct sexpr *root;
- const char *value;
- int ret = -1;
-
- if (uuid != NULL)
- memset(uuid, 0, VIR_UUID_BUFLEN);
- root = sexpr_get(xend, "/xend/domain/%s?detail=1", domname);
- if (root == NULL)
- goto error;
-
- value = sexpr_node(root, "domain/domid");
- if (value == NULL) {
- virXendError(xend, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, missing domid"));
- goto error;
- }
- ret = strtol(value, NULL, 0);
- if ((ret == 0) && (value[0] != '0')) {
- virXendError(xend, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incorrect domid not numeric"));
- ret = -1;
- } else if (uuid != NULL) {
- if (sexpr_uuid(uuid, root, "domain/uuid") < 0) {
- virXendError(xend, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, missing uuid"));
- }
- }
-
- error:
- sexpr_free(root);
- return (ret);
-}
-
-
-/**
- * xenDaemonDomainLookupByID:
- * @xend: A xend instance
- * @id: The id of the domain
- * @name: return value for the name if not NULL
- * @uuid: return value for the UUID if not NULL
- *
- * This method looks up the name of a domain based on its id
- *
- * Returns the 0 on success; -1 (with errno) on error
- */
-int
-xenDaemonDomainLookupByID(virConnectPtr xend,
- int id,
- char **domname,
- unsigned char *uuid)
-{
- const char *name = NULL;
- struct sexpr *root;
-
- memset(uuid, 0, VIR_UUID_BUFLEN);
-
- root = sexpr_get(xend, "/xend/domain/%d?detail=1", id);
- if (root == NULL)
- goto error;
-
- name = sexpr_node(root, "domain/name");
- if (name == NULL) {
- virXendError(xend, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, missing name"));
- goto error;
- }
- if (domname)
- *domname = strdup(name);
-
- if (sexpr_uuid(uuid, root, "domain/uuid") < 0) {
- virXendError(xend, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, missing uuid"));
- goto error;
- }
-
- sexpr_free(root);
- return (0);
-
-error:
- sexpr_free(root);
- if (domname)
- VIR_FREE(*domname);
- return (-1);
-}
-
-
-#ifndef PROXY
-static int
-xend_detect_config_version(virConnectPtr conn) {
- struct sexpr *root;
- const char *value;
- xenUnifiedPrivatePtr priv;
-
- if (!VIR_IS_CONNECT(conn)) {
- virXendError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (-1);
- }
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- root = sexpr_get(conn, "/xend/node/");
- if (root == NULL)
- return (-1);
-
- value = sexpr_node(root, "node/xend_config_format");
-
- if (value) {
- priv->xendConfigVersion = strtol(value, NULL, 10);
- } else {
- /* Xen prior to 3.0.3 did not have the xend_config_format
- field, and is implicitly version 1. */
- priv->xendConfigVersion = 1;
- }
- sexpr_free(root);
- return (0);
-}
-
-#endif /* PROXY */
-
-/*****************************************************************
- ******
- ****** Parsing of SEXPR into virDomainDef objects
- ******
- *****************************************************************/
-
-/**
- * xenDaemonParseSxprOS
- * @xend: the xend connection object
- * @node: the root of the parsed S-Expression
- * @def: the domain config
- * @hvm: true or 1 if no contains HVM S-Expression
- * @bootloader: true or 1 if a bootloader is defined
- *
- * Parse the xend sexp for description of os and append it to buf.
- *
- * Returns 0 in case of success and -1 in case of error
- */
-static int
-xenDaemonParseSxprOS(virConnectPtr xend,
- const struct sexpr *node,
- virDomainDefPtr def,
- int hvm)
-{
- if (hvm) {
- if (sexpr_node_copy(node, "domain/image/hvm/loader", &def->os.loader) < 0)
- goto no_memory;
- if (def->os.loader == NULL) {
- if (sexpr_node_copy(node, "domain/image/hvm/kernel", &def->os.loader) < 0)
- goto no_memory;
-
- if (def->os.loader == NULL) {
- virXendError(xend, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, missing HVM loader"));
- return(-1);
- }
- } else {
- if (sexpr_node_copy(node, "domain/image/hvm/kernel", &def->os.kernel) < 0)
- goto no_memory;
- if (sexpr_node_copy(node, "domain/image/hvm/ramdisk", &def->os.initrd) < 0)
- goto no_memory;
- if (sexpr_node_copy(node, "domain/image/hvm/args", &def->os.cmdline) < 0)
- goto no_memory;
- if (sexpr_node_copy(node, "domain/image/hvm/root", &def->os.root) < 0)
- goto no_memory;
- }
- } else {
- if (sexpr_node_copy(node, "domain/image/linux/kernel", &def->os.kernel) < 0)
- goto no_memory;
- if (sexpr_node_copy(node, "domain/image/linux/ramdisk", &def->os.initrd) < 0)
- goto no_memory;
- if (sexpr_node_copy(node, "domain/image/linux/args", &def->os.cmdline) < 0)
- goto no_memory;
- if (sexpr_node_copy(node, "domain/image/linux/root", &def->os.root) < 0)
- goto no_memory;
- }
-
- /* If HVM kenrel == loader, then old xend, so kill off kernel */
- if (hvm &&
- def->os.kernel &&
- STREQ(def->os.kernel, def->os.loader)) {
- VIR_FREE(def->os.kernel);
- }
-
- if (!def->os.kernel &&
- hvm) {
- const char *boot = sexpr_node(node, "domain/image/hvm/boot");
- if ((boot != NULL) && (boot[0] != 0)) {
- while (*boot &&
- def->os.nBootDevs < VIR_DOMAIN_BOOT_LAST) {
- if (*boot == 'a')
- def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_FLOPPY;
- else if (*boot == 'c')
- def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_DISK;
- else if (*boot == 'd')
- def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_CDROM;
- else if (*boot == 'n')
- def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_NET;
- boot++;
- }
- }
- }
-
- if (!hvm &&
- !def->os.kernel &&
- !def->os.bootloader) {
- virXendError(xend, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, missing kernel & bootloader"));
- return -1;
- }
-
- return 0;
-
-no_memory:
- virReportOOMError(xend);
- return -1;
-}
-
-
-int
-xend_parse_sexp_desc_char(virConnectPtr conn,
- virBufferPtr buf,
- const char *devtype,
- int portNum,
- const char *value,
- const char *tty)
-{
- const char *type;
- int telnet = 0;
- char *bindPort = NULL;
- char *bindHost = NULL;
- char *connectPort = NULL;
- char *connectHost = NULL;
- char *path = NULL;
- int ret = -1;
-
- if (value[0] == '/') {
- type = "dev";
- } else if (STRPREFIX(value, "null")) {
- type = "null";
- value = NULL;
- } else if (STRPREFIX(value, "vc")) {
- type = "vc";
- value = NULL;
- } else if (STRPREFIX(value, "pty")) {
- type = "pty";
- value = NULL;
- } else if (STRPREFIX(value, "stdio")) {
- type = "stdio";
- value = NULL;
- } else if (STRPREFIX(value, "file:")) {
- type = "file";
- value += sizeof("file:")-1;
- } else if (STRPREFIX(value, "pipe:")) {
- type = "pipe";
- value += sizeof("pipe:")-1;
- } else if (STRPREFIX(value, "tcp:")) {
- type = "tcp";
- value += sizeof("tcp:")-1;
- } else if (STRPREFIX(value, "telnet:")) {
- type = "tcp";
- value += sizeof("telnet:")-1;
- telnet = 1;
- } else if (STRPREFIX(value, "udp:")) {
- type = "udp";
- value += sizeof("udp:")-1;
- } else if (STRPREFIX(value, "unix:")) {
- type = "unix";
- value += sizeof("unix:")-1;
- } else {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Unknown char device type"));
- return -1;
- }
-
- /* Compat with legacy <console tty='/dev/pts/5'/> syntax */
- if (STREQ(devtype, "console") &&
- STREQ(type, "pty") &&
- tty != NULL) {
- virBufferVSprintf(buf, " <%s type='%s' tty='%s'>\n",
- devtype, type, tty);
- } else {
- virBufferVSprintf(buf, " <%s type='%s'>\n",
- devtype, type);
- }
-
- if (STREQ(type, "null") ||
- STREQ(type, "vc") ||
- STREQ(type, "stdio")) {
- /* no source needed */
- } else if (STREQ(type, "pty")) {
- if (tty)
- virBufferVSprintf(buf, " <source path='%s'/>\n",
- tty);
- } else if (STREQ(type, "file") ||
- STREQ(type, "pipe")) {
- virBufferVSprintf(buf, " <source path='%s'/>\n",
- value);
- } else if (STREQ(type, "tcp")) {
- const char *offset = strchr(value, ':');
- const char *offset2;
- const char *mode, *protocol;
-
- if (offset == NULL) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("malformed char device string"));
- goto error;
- }
-
- if (offset != value &&
- (bindHost = strndup(value, offset - value)) == NULL)
- goto no_memory;
-
- offset2 = strchr(offset, ',');
- if (offset2 == NULL)
- bindPort = strdup(offset+1);
- else
- bindPort = strndup(offset+1, offset2-(offset+1));
- if (bindPort == NULL)
- goto no_memory;
-
- if (offset2 && strstr(offset2, ",listen"))
- mode = "bind";
- else
- mode = "connect";
- protocol = telnet ? "telnet":"raw";
-
- if (bindHost) {
- virBufferVSprintf(buf,
- " <source mode='%s' host='%s' service='%s'/>\n",
- mode, bindHost, bindPort);
- } else {
- virBufferVSprintf(buf,
- " <source mode='%s' service='%s'/>\n",
- mode, bindPort);
- }
- virBufferVSprintf(buf,
- " <protocol type='%s'/>\n",
- protocol);
- } else if (STREQ(type, "udp")) {
- const char *offset = strchr(value, ':');
- const char *offset2, *offset3;
-
- if (offset == NULL) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("malformed char device string"));
- goto error;
- }
-
- if (offset != value &&
- (connectHost = strndup(value, offset - value)) == NULL)
- goto no_memory;
-
- offset2 = strchr(offset, '@');
- if (offset2 != NULL) {
- if ((connectPort = strndup(offset + 1, offset2-(offset+1))) == NULL)
- goto no_memory;
-
- offset3 = strchr(offset2, ':');
- if (offset3 == NULL) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("malformed char device string"));
- goto error;
- }
-
- if (offset3 > (offset2 + 1) &&
- (bindHost = strndup(offset2 + 1, offset3 - (offset2+1))) == NULL)
- goto no_memory;
-
- if ((bindPort = strdup(offset3 + 1)) == NULL)
- goto no_memory;
- } else {
- if ((connectPort = strdup(offset + 1)) == NULL)
- goto no_memory;
- }
-
- if (connectPort) {
- if (connectHost) {
- virBufferVSprintf(buf,
- " <source mode='connect' host='%s' service='%s'/>\n",
- connectHost, connectPort);
- } else {
- virBufferVSprintf(buf,
- " <source mode='connect' service='%s'/>\n",
- connectPort);
- }
- }
- if (bindPort) {
- if (bindHost) {
- virBufferVSprintf(buf,
- " <source mode='bind' host='%s' service='%s'/>\n",
- bindHost, bindPort);
- } else {
- virBufferVSprintf(buf,
- " <source mode='bind' service='%s'/>\n",
- bindPort);
- }
- }
-
- } else if (STREQ(type, "unix")) {
- const char *offset = strchr(value, ',');
- int dolisten = 0;
- if (offset)
- path = strndup(value, (offset - value));
- else
- path = strdup(value);
- if (path == NULL)
- goto no_memory;
-
- if (offset != NULL &&
- strstr(offset, ",listen") != NULL)
- dolisten = 1;
-
- virBufferVSprintf(buf, " <source mode='%s' path='%s'/>\n",
- dolisten ? "bind" : "connect", path);
- }
-
- virBufferVSprintf(buf, " <target port='%d'/>\n",
- portNum);
-
- virBufferVSprintf(buf, " </%s>\n",
- devtype);
-
- ret = 0;
-
- if (ret == -1) {
-no_memory:
- virReportOOMError(conn);
- }
-
-error:
-
- VIR_FREE(path);
- VIR_FREE(bindHost);
- VIR_FREE(bindPort);
- VIR_FREE(connectHost);
- VIR_FREE(connectPort);
-
- return ret;
-}
-
-virDomainChrDefPtr
-xenDaemonParseSxprChar(virConnectPtr conn,
- const char *value,
- const char *tty)
-{
- char prefix[10];
- char *tmp;
- virDomainChrDefPtr def;
-
- if (VIR_ALLOC(def) < 0) {
- virReportOOMError(conn);
- return NULL;
- }
-
- strncpy(prefix, value, sizeof(prefix)-1);
- NUL_TERMINATE(prefix);
-
- if (value[0] == '/') {
- def->type = VIR_DOMAIN_CHR_TYPE_DEV;
- } else {
- if ((tmp = strchr(prefix, ':')) != NULL) {
- *tmp = '\0';
- value += (tmp - prefix) + 1;
- }
-
- if (STREQ(prefix, "telnet")) {
- def->type = VIR_DOMAIN_CHR_TYPE_TCP;
- def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
- } else {
- if ((def->type = virDomainChrTypeFromString(prefix)) < 0) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unknown chr device type '%s'"), prefix);
- goto error;
- }
- }
- }
-
- /* Compat with legacy <console tty='/dev/pts/5'/> syntax */
- switch (def->type) {
- case VIR_DOMAIN_CHR_TYPE_PTY:
- if (tty != NULL &&
- !(def->data.file.path = strdup(tty)))
- goto no_memory;
- break;
-
- case VIR_DOMAIN_CHR_TYPE_FILE:
- case VIR_DOMAIN_CHR_TYPE_PIPE:
- if (!(def->data.file.path = strdup(value)))
- goto no_memory;
- break;
-
- case VIR_DOMAIN_CHR_TYPE_TCP:
- {
- const char *offset = strchr(value, ':');
- const char *offset2;
-
- if (offset == NULL) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("malformed char device string"));
- goto error;
- }
-
- if (offset != value &&
- (def->data.tcp.host = strndup(value, offset - value)) == NULL)
- goto no_memory;
-
- offset2 = strchr(offset, ',');
- if (offset2 == NULL)
- def->data.tcp.service = strdup(offset+1);
- else
- def->data.tcp.service = strndup(offset+1, offset2-(offset+1));
- if (def->data.tcp.service == NULL)
- goto no_memory;
-
- if (offset2 && strstr(offset2, ",listen"))
- def->data.tcp.listen = 1;
- }
- break;
-
- case VIR_DOMAIN_CHR_TYPE_UDP:
- {
- const char *offset = strchr(value, ':');
- const char *offset2, *offset3;
-
- if (offset == NULL) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("malformed char device string"));
- goto error;
- }
-
- if (offset != value &&
- (def->data.udp.connectHost = strndup(value, offset - value)) == NULL)
- goto no_memory;
-
- offset2 = strchr(offset, '@');
- if (offset2 != NULL) {
- if ((def->data.udp.connectService = strndup(offset + 1, offset2-(offset+1))) == NULL)
- goto no_memory;
-
- offset3 = strchr(offset2, ':');
- if (offset3 == NULL) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("malformed char device string"));
- goto error;
- }
-
- if (offset3 > (offset2 + 1) &&
- (def->data.udp.bindHost = strndup(offset2 + 1, offset3 - (offset2+1))) == NULL)
- goto no_memory;
-
- if ((def->data.udp.bindService = strdup(offset3 + 1)) == NULL)
- goto no_memory;
- } else {
- if ((def->data.udp.connectService = strdup(offset + 1)) == NULL)
- goto no_memory;
- }
- }
- break;
-
- case VIR_DOMAIN_CHR_TYPE_UNIX:
- {
- const char *offset = strchr(value, ',');
- if (offset)
- def->data.nix.path = strndup(value, (offset - value));
- else
- def->data.nix.path = strdup(value);
- if (def->data.nix.path == NULL)
- goto no_memory;
-
- if (offset != NULL &&
- strstr(offset, ",listen") != NULL)
- def->data.nix.listen = 1;
- }
- break;
- }
-
- return def;
-
-no_memory:
- virReportOOMError(conn);
-error:
- virDomainChrDefFree(def);
- return NULL;
-}
-
-/**
- * xend_parse_sexp_desc_disks
- * @conn: connection
- * @root: root sexpr
- * @xendConfigVersion: version of xend
- *
- * This parses out block devices from the domain sexpr
- *
- * Returns 0 if successful or -1 if failed.
- */
-static int
-xenDaemonParseSxprDisks(virConnectPtr conn,
- virDomainDefPtr def,
- const struct sexpr *root,
- int hvm,
- int xendConfigVersion)
-{
- const struct sexpr *cur, *node;
- virDomainDiskDefPtr disk = NULL;
-
- for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
- node = cur->u.s.car;
- /* Normally disks are in a (device (vbd ...)) block
- but blktap disks ended up in a differently named
- (device (tap ....)) block.... */
- if (sexpr_lookup(node, "device/vbd") ||
- sexpr_lookup(node, "device/tap")) {
- char *offset;
- const char *src = NULL;
- const char *dst = NULL;
- const char *mode = NULL;
-
- /* Again dealing with (vbd...) vs (tap ...) differences */
- if (sexpr_lookup(node, "device/vbd")) {
- src = sexpr_node(node, "device/vbd/uname");
- dst = sexpr_node(node, "device/vbd/dev");
- mode = sexpr_node(node, "device/vbd/mode");
- } else {
- src = sexpr_node(node, "device/tap/uname");
- dst = sexpr_node(node, "device/tap/dev");
- mode = sexpr_node(node, "device/tap/mode");
- }
-
- if (VIR_ALLOC(disk) < 0)
- goto no_memory;
-
- if (dst == NULL) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, vbd has no dev"));
- goto error;
- }
-
- if (src == NULL) {
- /* There is a case without the uname to the CD-ROM device */
- offset = strchr(dst, ':');
- if (!offset ||
- !hvm ||
- STRNEQ(offset, ":cdrom")) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, vbd has no src"));
- goto error;
- }
- }
-
- if (src != NULL) {
- offset = strchr(src, ':');
- if (!offset) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("cannot parse vbd filename, missing driver name"));
- goto error;
- }
-
- if (VIR_ALLOC_N(disk->driverName, (offset-src)+1) < 0)
- goto no_memory;
- strncpy(disk->driverName, src, (offset-src));
- disk->driverName[offset-src] = '\0';
-
- src = offset + 1;
-
- if (STREQ (disk->driverName, "tap")) {
- offset = strchr(src, ':');
- if (!offset) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("cannot parse vbd filename, missing driver type"));
- goto error;
- }
-
- if (VIR_ALLOC_N(disk->driverType, (offset-src)+1)< 0)
- goto no_memory;
- strncpy(disk->driverType, src, (offset-src));
- disk->driverType[offset-src] = '\0';
-
- src = offset + 1;
- /* Its possible to use blktap driver for block devs
- too, but kinda pointless because blkback is better,
- so we assume common case here. If blktap becomes
- omnipotent, we can revisit this, perhaps stat()'ing
- the src file in question */
- disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
- } else if (STREQ(disk->driverName, "phy")) {
- disk->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
- } else if (STREQ(disk->driverName, "file")) {
- disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
- }
- } else {
- /* No CDROM media so can't really tell. We'll just
- call if a FILE for now and update when media
- is inserted later */
- disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
- }
-
- if (STREQLEN (dst, "ioemu:", 6))
- dst += 6;
-
- disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
- /* New style disk config from Xen >= 3.0.3 */
- if (xendConfigVersion > 1) {
- offset = strrchr(dst, ':');
- if (offset) {
- if (STREQ (offset, ":cdrom")) {
- disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
- } else if (STREQ (offset, ":disk")) {
- /* The default anyway */
- } else {
- /* Unknown, lets pretend its a disk too */
- }
- offset[0] = '\0';
- }
- }
-
- if (!(disk->dst = strdup(dst)))
- goto no_memory;
- if (src &&
- !(disk->src = strdup(src)))
- goto no_memory;
-
- if (STRPREFIX(disk->dst, "xvd"))
- disk->bus = VIR_DOMAIN_DISK_BUS_XEN;
- else if (STRPREFIX(disk->dst, "hd"))
- disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
- else if (STRPREFIX(disk->dst, "sd"))
- disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
- else
- disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
-
- if (mode &&
- strchr(mode, 'r'))
- disk->readonly = 1;
- if (mode &&
- strchr(mode, '!'))
- disk->shared = 1;
-
- if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
- goto no_memory;
-
- def->disks[def->ndisks++] = disk;
- disk = NULL;
- }
- }
-
- return 0;
-
-no_memory:
- virReportOOMError(conn);
-
-error:
- virDomainDiskDefFree(disk);
- return -1;
-}
-
-
-static int
-xenDaemonParseSxprNets(virConnectPtr conn,
- virDomainDefPtr def,
- const struct sexpr *root)
-{
- virDomainNetDefPtr net = NULL;
- const struct sexpr *cur, *node;
- const char *tmp;
- int vif_index = 0;
-
- for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
- node = cur->u.s.car;
- if (sexpr_lookup(node, "device/vif")) {
- const char *tmp2, *model;
- char buf[50];
- tmp2 = sexpr_node(node, "device/vif/script");
- tmp = sexpr_node(node, "device/vif/bridge");
- model = sexpr_node(node, "device/vif/model");
-
- if (VIR_ALLOC(net) < 0)
- goto no_memory;
-
- if (tmp != NULL ||
- (tmp2 != NULL && STREQ(tmp2, DEFAULT_VIF_SCRIPT))) {
- net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
- /* XXX virtual network reverse resolve */
-
- if (tmp &&
- !(net->data.bridge.brname = strdup(tmp)))
- goto no_memory;
- if (tmp2 &&
- net->type == VIR_DOMAIN_NET_TYPE_BRIDGE &&
- !(net->data.bridge.script = strdup(tmp2)))
- goto no_memory;
- tmp = sexpr_node(node, "device/vif/ip");
- if (tmp &&
- !(net->data.bridge.ipaddr = strdup(tmp)))
- goto no_memory;
- } else {
- net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
- if (tmp2 &&
- !(net->data.ethernet.script = strdup(tmp2)))
- goto no_memory;
- tmp = sexpr_node(node, "device/vif/ip");
- if (tmp &&
- !(net->data.ethernet.ipaddr = strdup(tmp)))
- goto no_memory;
- }
-
- tmp = sexpr_node(node, "device/vif/vifname");
- if (!tmp) {
- snprintf(buf, sizeof(buf), "vif%d.%d", def->id, vif_index);
- tmp = buf;
- }
- if (!(net->ifname = strdup(tmp)))
- goto no_memory;
-
- tmp = sexpr_node(node, "device/vif/mac");
- if (tmp) {
- unsigned int mac[6];
- if (sscanf(tmp, "%02x:%02x:%02x:%02x:%02x:%02x",
- (unsigned int*)&mac[0],
- (unsigned int*)&mac[1],
- (unsigned int*)&mac[2],
- (unsigned int*)&mac[3],
- (unsigned int*)&mac[4],
- (unsigned int*)&mac[5]) != 6) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("malformed mac address '%s'"),
- tmp);
- goto cleanup;
- }
- net->mac[0] = mac[0];
- net->mac[1] = mac[1];
- net->mac[2] = mac[2];
- net->mac[3] = mac[3];
- net->mac[4] = mac[4];
- net->mac[5] = mac[5];
- }
-
- if (model &&
- !(net->model = strdup(model)))
- goto no_memory;
-
- if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0)
- goto no_memory;
-
- def->nets[def->nnets++] = net;
- vif_index++;
- }
- }
-
- return 0;
-
-no_memory:
- virReportOOMError(conn);
-cleanup:
- virDomainNetDefFree(net);
- return -1;
-}
-
-
-int
-xenDaemonParseSxprSound(virConnectPtr conn,
- virDomainDefPtr def,
- const char *str)
-{
- if (STREQ(str, "all")) {
- int i;
-
- /*
- * Special compatability code for Xen with a bogus
- * sound=all in config.
- *
- * NB delibrately, don't include all possible
- * sound models anymore, just the 2 that were
- * historically present in Xen's QEMU.
- *
- * ie just es1370 + sb16.
- *
- * Hence use of MODEL_ES1370 + 1, instead of MODEL_LAST
- */
-
- if (VIR_ALLOC_N(def->sounds,
- VIR_DOMAIN_SOUND_MODEL_ES1370 + 1) < 0)
- goto no_memory;
-
-
- for (i = 0 ; i < (VIR_DOMAIN_SOUND_MODEL_ES1370 + 1) ; i++) {
- virDomainSoundDefPtr sound;
- if (VIR_ALLOC(sound) < 0)
- goto no_memory;
- sound->model = i;
- def->sounds[def->nsounds++] = sound;
- }
- } else {
- char model[10];
- const char *offset = str, *offset2;
-
- do {
- int len;
- virDomainSoundDefPtr sound;
- offset2 = strchr(offset, ',');
- if (offset2)
- len = (offset2 - offset);
- else
- len = strlen(offset);
- if (len > (sizeof(model)-1)) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unexpected sound model %s"), offset);
- goto error;
- }
- strncpy(model, offset, len);
- model[len] = '\0';
-
- if (VIR_ALLOC(sound) < 0)
- goto no_memory;
-
- if ((sound->model = virDomainSoundModelTypeFromString(model)) < 0) {
- VIR_FREE(sound);
- goto error;
- }
-
- if (VIR_REALLOC_N(def->sounds, def->nsounds+1) < 0) {
- virDomainSoundDefFree(sound);
- goto no_memory;
- }
-
- def->sounds[def->nsounds++] = sound;
- offset = offset2 ? offset2 + 1 : NULL;
- } while (offset);
- }
-
- return 0;
-
-no_memory:
- virReportOOMError(conn);
-error:
- return -1;
-}
-
-
-static int
-xenDaemonParseSxprUSB(virConnectPtr conn,
- virDomainDefPtr def,
- const struct sexpr *root)
-{
- struct sexpr *cur, *node;
- const char *tmp;
-
- for (cur = sexpr_lookup(root, "domain/image/hvm"); cur && cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
- node = cur->u.s.car;
- if (sexpr_lookup(node, "usbdevice")) {
- tmp = sexpr_node(node, "usbdevice");
- if (tmp && *tmp) {
- if (STREQ(tmp, "tablet") ||
- STREQ(tmp, "mouse")) {
- virDomainInputDefPtr input;
- if (VIR_ALLOC(input) < 0)
- goto no_memory;
- input->bus = VIR_DOMAIN_INPUT_BUS_USB;
- if (STREQ(tmp, "tablet"))
- input->type = VIR_DOMAIN_INPUT_TYPE_TABLET;
- else
- input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
-
- if (VIR_REALLOC_N(def->inputs, def->ninputs+1) < 0) {
- VIR_FREE(input);
- goto no_memory;
- }
- def->inputs[def->ninputs++] = input;
- } else {
- /* XXX Handle other non-input USB devices later */
- }
- }
- }
- }
- return 0;
-
-no_memory:
- virReportOOMError(conn);
- return -1;
-}
-
-static int
-xenDaemonParseSxprGraphicsOld(virConnectPtr conn,
- virDomainDefPtr def,
- const struct sexpr *root,
- int hvm,
- int xendConfigVersion)
-{
-#ifndef PROXY
- xenUnifiedPrivatePtr priv = conn->privateData;
-#endif
- const char *tmp;
- virDomainGraphicsDefPtr graphics = NULL;
-
- if ((tmp = sexpr_fmt_node(root, "domain/image/%s/vnc", hvm ? "hvm" : "linux")) &&
- tmp[0] == '1') {
- /* Graphics device (HVM, or old (pre-3.0.4) style PV VNC config) */
- int port;
- const char *listenAddr = sexpr_fmt_node(root, "domain/image/%s/vnclisten", hvm ? "hvm" : "linux");
- const char *vncPasswd = sexpr_fmt_node(root, "domain/image/%s/vncpasswd", hvm ? "hvm" : "linux");
- const char *keymap = sexpr_fmt_node(root, "domain/image/%s/keymap", hvm ? "hvm" : "linux");
- const char *unused = sexpr_fmt_node(root, "domain/image/%s/vncunused", hvm ? "hvm" : "linux");
-
- xenUnifiedLock(priv);
- port = xenStoreDomainGetVNCPort(conn, def->id);
- xenUnifiedUnlock(priv);
-
- if (VIR_ALLOC(graphics) < 0)
- goto no_memory;
-
- graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
- /* For Xen >= 3.0.3, don't generate a fixed port mapping
- * because it will almost certainly be wrong ! Just leave
- * it as -1 which lets caller see that the VNC server isn't
- * present yet. Subsquent dumps of the XML will eventually
- * find the port in XenStore once VNC server has started
- */
- if (port == -1 && xendConfigVersion < 2)
- port = 5900 + def->id;
-
- if ((unused && STREQ(unused, "1")) || port == -1)
- graphics->data.vnc.autoport = 1;
- graphics->data.vnc.port = port;
-
- if (listenAddr &&
- !(graphics->data.vnc.listenAddr = strdup(listenAddr)))
- goto no_memory;
-
- if (vncPasswd &&
- !(graphics->data.vnc.passwd = strdup(vncPasswd)))
- goto no_memory;
-
- if (keymap &&
- !(graphics->data.vnc.keymap = strdup(keymap)))
- goto no_memory;
-
- if (VIR_ALLOC_N(def->graphics, 1) < 0)
- goto no_memory;
- def->graphics[0] = graphics;
- def->ngraphics = 1;
- graphics = NULL;
- } else if ((tmp = sexpr_fmt_node(root, "domain/image/%s/sdl", hvm ? "hvm" : "linux")) &&
- tmp[0] == '1') {
- /* Graphics device (HVM, or old (pre-3.0.4) style PV sdl config) */
- const char *display = sexpr_fmt_node(root, "domain/image/%s/display", hvm ? "hvm" : "linux");
- const char *xauth = sexpr_fmt_node(root, "domain/image/%s/xauthority", hvm ? "hvm" : "linux");
-
- if (VIR_ALLOC(graphics) < 0)
- goto no_memory;
-
- graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
- if (display &&
- !(graphics->data.sdl.display = strdup(display)))
- goto no_memory;
- if (xauth &&
- !(graphics->data.sdl.xauth = strdup(xauth)))
- goto no_memory;
-
- if (VIR_ALLOC_N(def->graphics, 1) < 0)
- goto no_memory;
- def->graphics[0] = graphics;
- def->ngraphics = 1;
- graphics = NULL;
- }
-
- return 0;
-
-no_memory:
- virReportOOMError(conn);
- virDomainGraphicsDefFree(graphics);
- return -1;
-}
-
-
-static int
-xenDaemonParseSxprGraphicsNew(virConnectPtr conn,
- virDomainDefPtr def,
- const struct sexpr *root)
-{
-#ifndef PROXY
- xenUnifiedPrivatePtr priv = conn->privateData;
-#endif
- virDomainGraphicsDefPtr graphics = NULL;
- const struct sexpr *cur, *node;
- const char *tmp;
-
- /* append network devices and framebuffer */
- for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
- node = cur->u.s.car;
- if (sexpr_lookup(node, "device/vfb")) {
- /* New style graphics config for PV guests in >= 3.0.4,
- * or for HVM guests in >= 3.0.5 */
- if (sexpr_node(node, "device/vfb/type")) {
- tmp = sexpr_node(node, "device/vfb/type");
- } else if (sexpr_node(node, "device/vfb/vnc")) {
- tmp = "vnc";
- } else if (sexpr_node(node, "device/vfb/sdl")) {
- tmp = "sdl";
- } else {
- tmp = "unknown";
- }
-
- if (VIR_ALLOC(graphics) < 0)
- goto no_memory;
-
- if ((graphics->type = virDomainGraphicsTypeFromString(tmp)) < 0) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unknown graphics type '%s'"), tmp);
- goto error;
- }
-
- if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
- const char *display = sexpr_node(node, "device/vfb/display");
- const char *xauth = sexpr_node(node, "device/vfb/xauthority");
- if (display &&
- !(graphics->data.sdl.display = strdup(display)))
- goto no_memory;
- if (xauth &&
- !(graphics->data.sdl.xauth = strdup(xauth)))
- goto no_memory;
- } else {
- int port;
- const char *listenAddr = sexpr_node(node, "device/vfb/vnclisten");
- const char *vncPasswd = sexpr_node(node, "device/vfb/vncpasswd");
- const char *keymap = sexpr_node(node, "device/vfb/keymap");
- const char *unused = sexpr_node(node, "device/vfb/vncunused");
-
- xenUnifiedLock(priv);
- port = xenStoreDomainGetVNCPort(conn, def->id);
- xenUnifiedUnlock(priv);
-
- // Didn't find port entry in xenstore
- if (port == -1) {
- const char *str = sexpr_node(node, "device/vfb/vncdisplay");
- int val;
- if (str != NULL && virStrToLong_i(str, NULL, 0, &val) == 0)
- port = val;
- }
-
- if ((unused && STREQ(unused, "1")) || port == -1)
- graphics->data.vnc.autoport = 1;
-
- if (port >= 0 && port < 5900)
- port += 5900;
- graphics->data.vnc.port = port;
-
- if (listenAddr &&
- !(graphics->data.vnc.listenAddr = strdup(listenAddr)))
- goto no_memory;
-
- if (vncPasswd &&
- !(graphics->data.vnc.passwd = strdup(vncPasswd)))
- goto no_memory;
-
- if (keymap &&
- !(graphics->data.vnc.keymap = strdup(keymap)))
- goto no_memory;
- }
-
- if (VIR_ALLOC_N(def->graphics, 1) < 0)
- goto no_memory;
- def->graphics[0] = graphics;
- def->ngraphics = 1;
- graphics = NULL;
- break;
- }
- }
-
- return 0;
-
-no_memory:
- virReportOOMError(conn);
-error:
- virDomainGraphicsDefFree(graphics);
- return -1;
-}
-
-/**
- * xenDaemonParseSxprPCI
- * @conn: connection
- * @root: root sexpr
- *
- * This parses out block devices from the domain sexpr
- *
- * Returns 0 if successful or -1 if failed.
- */
-static int
-xenDaemonParseSxprPCI(virConnectPtr conn,
- virDomainDefPtr def,
- const struct sexpr *root)
-{
- const struct sexpr *cur, *tmp = NULL, *node;
- virDomainHostdevDefPtr dev = NULL;
-
- /*
- * With the (domain ...) block we have the following odd setup
- *
- * (device
- * (pci
- * (dev (domain 0x0000) (bus 0x00) (slot 0x1b) (func 0x0))
- * (dev (domain 0x0000) (bus 0x00) (slot 0x13) (func 0x0))
- * )
- * )
- *
- * Normally there is one (device ...) block per device, but in
- * wierd world of Xen PCI, once (device ...) covers multiple
- * devices.
- */
-
- for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
- node = cur->u.s.car;
- if ((tmp = sexpr_lookup(node, "device/pci")) != NULL)
- break;
- }
-
- if (!tmp)
- return 0;
-
- for (cur = tmp; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
- const char *domain = NULL;
- const char *bus = NULL;
- const char *slot = NULL;
- const char *func = NULL;
- int domainID;
- int busID;
- int slotID;
- int funcID;
-
- node = cur->u.s.car;
- if (!sexpr_lookup(node, "dev"))
- continue;
-
- if (!(domain = sexpr_node(node, "dev/domain"))) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("missing PCI domain"));
- goto error;
- }
- if (!(bus = sexpr_node(node, "dev/bus"))) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("missing PCI bus"));
- goto error;
- }
- if (!(slot = sexpr_node(node, "dev/slot"))) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("missing PCI slot"));
- goto error;
- }
- if (!(func = sexpr_node(node, "dev/func"))) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("missing PCI func"));
- goto error;
- }
-
- if (virStrToLong_i(domain, NULL, 0, &domainID) < 0) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("cannot parse PCI domain '%s'"), domain);
- goto error;
- }
- if (virStrToLong_i(bus, NULL, 0, &busID) < 0) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("cannot parse PCI bus '%s'"), bus);
- goto error;
- }
- if (virStrToLong_i(slot, NULL, 0, &slotID) < 0) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("cannot parse PCI slot '%s'"), slot);
- goto error;
- }
- if (virStrToLong_i(func, NULL, 0, &funcID) < 0) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("cannot parse PCI func '%s'"), func);
- goto error;
- }
-
- if (VIR_ALLOC(dev) < 0)
- goto no_memory;
-
- dev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
- dev->managed = 0;
- dev->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
- dev->source.subsys.u.pci.domain = domainID;
- dev->source.subsys.u.pci.bus = busID;
- dev->source.subsys.u.pci.slot = slotID;
- dev->source.subsys.u.pci.function = funcID;
-
- if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0) {
- goto no_memory;
- }
-
- def->hostdevs[def->nhostdevs++] = dev;
- }
-
- return 0;
-
-no_memory:
- virReportOOMError(conn);
-
-error:
- virDomainHostdevDefFree(dev);
- return -1;
-}
-
-
-/**
- * xenDaemonParseSxpr:
- * @conn: the connection associated with the XML
- * @root: the root of the parsed S-Expression
- * @xendConfigVersion: version of xend
- * @cpus: set of cpus the domain may be pinned to
- *
- * Parse the xend sexp description and turn it into the XML format similar
- * to the one unsed for creation.
- *
- * Returns the 0 terminated XML string or NULL in case of error.
- * the caller must free() the returned value.
- */
-static virDomainDefPtr
-xenDaemonParseSxpr(virConnectPtr conn,
- const struct sexpr *root,
- int xendConfigVersion,
- const char *cpus)
-{
-#ifndef PROXY
- xenUnifiedPrivatePtr priv = conn->privateData;
-#endif
- const char *tmp;
- virDomainDefPtr def;
- int hvm = 0;
- char *tty = NULL;
-
- if (VIR_ALLOC(def) < 0)
- goto no_memory;
-
- tmp = sexpr_node(root, "domain/domid");
- if (tmp == NULL && xendConfigVersion < 3) { /* Old XenD, domid was mandatory */
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, missing id"));
- goto error;
- }
- def->virtType = VIR_DOMAIN_VIRT_XEN;
- if (tmp)
- def->id = sexpr_int(root, "domain/domid");
- else
- def->id = -1;
-
- if (sexpr_node_copy(root, "domain/name", &def->name) < 0)
- goto no_memory;
- if (def->name == NULL) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, missing name"));
- goto error;
- }
-
- tmp = sexpr_node(root, "domain/uuid");
- if (tmp == NULL) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, missing name"));
- goto error;
- }
- virUUIDParse(tmp, def->uuid);
-
- hvm = sexpr_lookup(root, "domain/image/hvm") ? 1 : 0;
- if (!hvm) {
- if (sexpr_node_copy(root, "domain/bootloader",
- &def->os.bootloader) < 0)
- goto no_memory;
-
- if (!def->os.bootloader &&
- sexpr_has(root, "domain/bootloader") &&
- (def->os.bootloader = strdup("")) == NULL)
- goto no_memory;
-
- if (def->os.bootloader &&
- sexpr_node_copy(root, "domain/bootloader_args",
- &def->os.bootloaderArgs) < 0)
- goto no_memory;
- }
-
- if (!(def->os.type = strdup(hvm ? "hvm" : "linux")))
- goto no_memory;
-
- if (def->id != 0) {
- if (sexpr_lookup(root, "domain/image")) {
- if (xenDaemonParseSxprOS(conn, root, def, hvm) < 0)
- goto error;
- }
- }
-
- def->maxmem = (unsigned long) (sexpr_u64(root, "domain/maxmem") << 10);
- def->memory = (unsigned long) (sexpr_u64(root, "domain/memory") << 10);
- if (def->memory > def->maxmem)
- def->maxmem = def->memory;
-
- if (cpus != NULL) {
- def->cpumasklen = VIR_DOMAIN_CPUMASK_LEN;
- if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0) {
- virReportOOMError(conn);
- goto error;
- }
-
- if (virDomainCpuSetParse(conn, &cpus,
- 0, def->cpumask,
- def->cpumasklen) < 0) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("invalid CPU mask %s"), cpus);
- goto error;
- }
- }
-
- def->vcpus = sexpr_int(root, "domain/vcpus");
-
- tmp = sexpr_node(root, "domain/on_poweroff");
- if (tmp != NULL) {
- if ((def->onPoweroff = virDomainLifecycleTypeFromString(tmp)) < 0) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unknown lifecycle type %s"), tmp);
- goto error;
- }
- } else
- def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY;
-
- tmp = sexpr_node(root, "domain/on_reboot");
- if (tmp != NULL) {
- if ((def->onReboot = virDomainLifecycleTypeFromString(tmp)) < 0) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unknown lifecycle type %s"), tmp);
- goto error;
- }
- } else
- def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART;
-
- tmp = sexpr_node(root, "domain/on_crash");
- if (tmp != NULL) {
- if ((def->onCrash = virDomainLifecycleTypeFromString(tmp)) < 0) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unknown lifecycle type %s"), tmp);
- goto error;
- }
- } else
- def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY;
-
-
- if (hvm) {
- if (sexpr_int(root, "domain/image/hvm/acpi"))
- def->features |= (1 << VIR_DOMAIN_FEATURE_ACPI);
- if (sexpr_int(root, "domain/image/hvm/apic"))
- def->features |= (1 << VIR_DOMAIN_FEATURE_APIC);
- if (sexpr_int(root, "domain/image/hvm/pae"))
- def->features |= (1 << VIR_DOMAIN_FEATURE_PAE);
-
- /* Old XenD only allows localtime here for HVM */
- if (sexpr_int(root, "domain/image/hvm/localtime"))
- def->localtime = 1;
- }
-
- /* Current XenD allows localtime here, for PV and HVM */
- if (sexpr_int(root, "domain/localtime"))
- def->localtime = 1;
-
- if (sexpr_node_copy(root, hvm ?
- "domain/image/hvm/device_model" :
- "domain/image/linux/device_model",
- &def->emulator) < 0)
- goto no_memory;
-
- /* append block devices */
- if (xenDaemonParseSxprDisks(conn, def, root, hvm, xendConfigVersion) < 0)
- goto error;
-
- if (xenDaemonParseSxprNets(conn, def, root) < 0)
- goto error;
-
- if (xenDaemonParseSxprPCI(conn, def, root) < 0)
- goto error;
-
- /* New style graphics device config */
- if (xenDaemonParseSxprGraphicsNew(conn, def, root) < 0)
- goto error;
-
- /* Graphics device (HVM <= 3.0.4, or PV <= 3.0.3) vnc config */
- if ((def->ngraphics == 0) &&
- xenDaemonParseSxprGraphicsOld(conn, def, root, hvm, xendConfigVersion) < 0)
- goto error;
-
-
- /* Old style cdrom config from Xen <= 3.0.2 */
- if (hvm &&
- xendConfigVersion == 1) {
- tmp = sexpr_node(root, "domain/image/hvm/cdrom");
- if ((tmp != NULL) && (tmp[0] != 0)) {
- virDomainDiskDefPtr disk;
- if (VIR_ALLOC(disk) < 0)
- goto no_memory;
- if (!(disk->src = strdup(tmp))) {
- virDomainDiskDefFree(disk);
- goto no_memory;
- }
- disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
- disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
- if (!(disk->dst = strdup("hdc"))) {
- virDomainDiskDefFree(disk);
- goto no_memory;
- }
- if (!(disk->driverName = strdup("file"))) {
- virDomainDiskDefFree(disk);
- goto no_memory;
- }
- disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
- disk->readonly = 1;
-
- if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
- virDomainDiskDefFree(disk);
- goto no_memory;
- }
- def->disks[def->ndisks++] = disk;
- }
- }
-
-
- /* Floppy disk config */
- if (hvm) {
- const char *const fds[] = { "fda", "fdb" };
- int i;
- for (i = 0 ; i < ARRAY_CARDINALITY(fds) ; i++) {
- tmp = sexpr_fmt_node(root, "domain/image/hvm/%s", fds[i]);
- if ((tmp != NULL) && (tmp[0] != 0)) {
- virDomainDiskDefPtr disk;
- if (VIR_ALLOC(disk) < 0)
- goto no_memory;
- if (!(disk->src = strdup(tmp))) {
- VIR_FREE(disk);
- goto no_memory;
- }
- disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
- disk->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
- if (!(disk->dst = strdup(fds[i]))) {
- virDomainDiskDefFree(disk);
- goto no_memory;
- }
- if (!(disk->driverName = strdup("file"))) {
- virDomainDiskDefFree(disk);
- goto no_memory;
- }
- disk->bus = VIR_DOMAIN_DISK_BUS_FDC;
-
- if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
- virDomainDiskDefFree(disk);
- goto no_memory;
- }
- def->disks[def->ndisks++] = disk;
- }
- }
- }
-
- /* in case of HVM we have USB device emulation */
- if (hvm &&
- xenDaemonParseSxprUSB(conn, def, root) < 0)
- goto error;
-
- /* Character device config */
- xenUnifiedLock(priv);
- tty = xenStoreDomainGetConsolePath(conn, def->id);
- xenUnifiedUnlock(priv);
- if (hvm) {
- tmp = sexpr_node(root, "domain/image/hvm/serial");
- if (tmp && STRNEQ(tmp, "none")) {
- virDomainChrDefPtr chr;
- if ((chr = xenDaemonParseSxprChar(conn, tmp, tty)) == NULL)
- goto error;
- if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) {
- virDomainChrDefFree(chr);
- goto no_memory;
- }
- def->serials[def->nserials++] = chr;
- }
- tmp = sexpr_node(root, "domain/image/hvm/parallel");
- if (tmp && STRNEQ(tmp, "none")) {
- virDomainChrDefPtr chr;
- /* XXX does XenD stuff parallel port tty info into xenstore somewhere ? */
- if ((chr = xenDaemonParseSxprChar(conn, tmp, NULL)) == NULL)
- goto error;
- if (VIR_REALLOC_N(def->parallels, def->nparallels+1) < 0) {
- virDomainChrDefFree(chr);
- goto no_memory;
- }
- def->parallels[def->nparallels++] = chr;
- }
- } else {
- /* Fake a paravirt console, since that's not in the sexpr */
- if (!(def->console = xenDaemonParseSxprChar(conn, "pty", tty)))
- goto error;
- }
- VIR_FREE(tty);
-
-
- /* Sound device config */
- if (hvm &&
- (tmp = sexpr_node(root, "domain/image/hvm/soundhw")) != NULL &&
- *tmp) {
- if (xenDaemonParseSxprSound(conn, def, tmp) < 0)
- goto error;
- }
-
- return def;
-
-no_memory:
- virReportOOMError(conn);
-error:
- VIR_FREE(tty);
- virDomainDefFree(def);
- return NULL;
-}
-
-virDomainDefPtr
-xenDaemonParseSxprString(virConnectPtr conn,
- const char *sexpr,
- int xendConfigVersion)
-{
- struct sexpr *root = string2sexpr(sexpr);
- virDomainDefPtr def;
-
- if (!root)
- return NULL;
-
- def = xenDaemonParseSxpr(conn, root, xendConfigVersion, NULL);
-
- sexpr_free(root);
-
- return def;
-}
-
-
-/**
- * sexpr_to_xend_domain_info:
- * @root: an S-Expression describing a domain
- * @info: a info data structure to fill=up
- *
- * Internal routine filling up the info structure with the values from
- * the domain root provided.
- *
- * Returns 0 in case of success, -1 in case of error
- */
-static int
-sexpr_to_xend_domain_info(virDomainPtr domain, const struct sexpr *root,
- virDomainInfoPtr info)
-{
- const char *flags;
-
-
- if ((root == NULL) || (info == NULL))
- return (-1);
-
- info->memory = sexpr_u64(root, "domain/memory") << 10;
- info->maxMem = sexpr_u64(root, "domain/maxmem") << 10;
- flags = sexpr_node(root, "domain/state");
-
- if (flags) {
- if (strchr(flags, 'c'))
- info->state = VIR_DOMAIN_CRASHED;
- else if (strchr(flags, 's'))
- info->state = VIR_DOMAIN_SHUTOFF;
- else if (strchr(flags, 'd'))
- info->state = VIR_DOMAIN_SHUTDOWN;
- else if (strchr(flags, 'p'))
- info->state = VIR_DOMAIN_PAUSED;
- else if (strchr(flags, 'b'))
- info->state = VIR_DOMAIN_BLOCKED;
- else if (strchr(flags, 'r'))
- info->state = VIR_DOMAIN_RUNNING;
- } else {
- /* Inactive domains don't have a state reported, so
- mark them SHUTOFF, rather than NOSTATE */
- if (domain->id < 0)
- info->state = VIR_DOMAIN_SHUTOFF;
- else
- info->state = VIR_DOMAIN_NOSTATE;
- }
- info->cpuTime = sexpr_float(root, "domain/cpu_time") * 1000000000;
- info->nrVirtCpu = sexpr_int(root, "domain/vcpus");
- return (0);
-}
-
-/**
- * sexpr_to_xend_node_info:
- * @root: an S-Expression describing a domain
- * @info: a info data structure to fill up
- *
- * Internal routine filling up the info structure with the values from
- * the node root provided.
- *
- * Returns 0 in case of success, -1 in case of error
- */
-static int
-sexpr_to_xend_node_info(const struct sexpr *root, virNodeInfoPtr info)
-{
- const char *machine;
-
-
- if ((root == NULL) || (info == NULL))
- return (-1);
-
- machine = sexpr_node(root, "node/machine");
- if (machine == NULL) {
- info->model[0] = 0;
- } else {
- snprintf(&info->model[0], sizeof(info->model) - 1, "%s", machine);
- info->model[sizeof(info->model) - 1] = 0;
- }
- info->memory = (unsigned long) sexpr_u64(root, "node/total_memory") << 10;
-
- info->cpus = sexpr_int(root, "node/nr_cpus");
- info->mhz = sexpr_int(root, "node/cpu_mhz");
- info->nodes = sexpr_int(root, "node/nr_nodes");
- info->sockets = sexpr_int(root, "node/sockets_per_node");
- info->cores = sexpr_int(root, "node/cores_per_socket");
- info->threads = sexpr_int(root, "node/threads_per_core");
-
- /* Xen 3.2.0 replaces sockets_per_node with 'nr_cpus'.
- * Old Xen calculated sockets_per_node using its internal
- * nr_cpus / (nodes*cores*threads), so fake it ourselves
- * in the same way
- */
- if (info->sockets == 0) {
- int nr_cpus = sexpr_int(root, "node/nr_cpus");
- int procs = info->nodes * info->cores * info->threads;
- if (procs == 0) /* Sanity check in case of Xen bugs in futures..*/
- return (-1);
- info->sockets = nr_cpus / procs;
- /* Should already be fine, but for further sanity make
- * sure we have at least one socket
- */
- if (info->sockets == 0)
- info->sockets = 1;
- }
- return (0);
-}
-
-
-/**
- * sexpr_to_xend_topology
- * @root: an S-Expression describing a node
- * @caps: capability info
- *
- * Internal routine populating capability info with
- * NUMA node mapping details
- *
- * Does nothing when the system doesn't support NUMA (not an error).
- *
- * Returns 0 in case of success, -1 in case of error
- */
-static int
-sexpr_to_xend_topology(virConnectPtr conn,
- const struct sexpr *root,
- virCapsPtr caps)
-{
- const char *nodeToCpu;
- const char *cur;
- char *cpuset = NULL;
- int *cpuNums = NULL;
- int cell, cpu, nb_cpus;
- int n = 0;
- int numCpus;
-
- nodeToCpu = sexpr_node(root, "node/node_to_cpu");
- if (nodeToCpu == NULL)
- return 0; /* no NUMA support */
-
- numCpus = sexpr_int(root, "node/nr_cpus");
-
-
- if (VIR_ALLOC_N(cpuset, numCpus) < 0)
- goto memory_error;
- if (VIR_ALLOC_N(cpuNums, numCpus) < 0)
- goto memory_error;
-
- cur = nodeToCpu;
- while (*cur != 0) {
- /*
- * Find the next NUMA cell described in the xend output
- */
- cur = strstr(cur, "node");
- if (cur == NULL)
- break;
- cur += 4;
- cell = virParseNumber(&cur);
- if (cell < 0)
- goto parse_error;
- virSkipSpaces(&cur);
- if (*cur != ':')
- goto parse_error;
- cur++;
- virSkipSpaces(&cur);
- if (STRPREFIX(cur, "no cpus")) {
- nb_cpus = 0;
- for (cpu = 0; cpu < numCpus; cpu++)
- cpuset[cpu] = 0;
- } else {
- nb_cpus = virDomainCpuSetParse(conn, &cur, 'n', cpuset, numCpus);
- if (nb_cpus < 0)
- goto error;
- }
-
- for (n = 0, cpu = 0; cpu < numCpus; cpu++)
- if (cpuset[cpu] == 1)
- cpuNums[n++] = cpu;
-
- if (virCapabilitiesAddHostNUMACell(caps,
- cell,
- nb_cpus,
- cpuNums) < 0)
- goto memory_error;
- }
- VIR_FREE(cpuNums);
- VIR_FREE(cpuset);
- return (0);
-
- parse_error:
- virXendError(conn, VIR_ERR_XEN_CALL, "%s", _("topology syntax error"));
- error:
- VIR_FREE(cpuNums);
- VIR_FREE(cpuset);
-
- return (-1);
-
- memory_error:
- VIR_FREE(cpuNums);
- VIR_FREE(cpuset);
- virReportOOMError(conn);
- return (-1);
-}
-
-
-#ifndef PROXY
-/**
- * sexpr_to_domain:
- * @conn: an existing virtual connection block
- * @root: an S-Expression describing a domain
- *
- * Internal routine returning the associated virDomainPtr for this domain
- *
- * Returns the domain pointer or NULL in case of error.
- */
-static virDomainPtr
-sexpr_to_domain(virConnectPtr conn, const struct sexpr *root)
-{
- virDomainPtr ret = NULL;
- unsigned char uuid[VIR_UUID_BUFLEN];
- const char *name;
- const char *tmp;
- xenUnifiedPrivatePtr priv;
-
- if ((conn == NULL) || (root == NULL))
- return(NULL);
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- if (sexpr_uuid(uuid, root, "domain/uuid") < 0)
- goto error;
- name = sexpr_node(root, "domain/name");
- if (name == NULL)
- goto error;
-
- ret = virGetDomain(conn, name, uuid);
- if (ret == NULL) return NULL;
-
- tmp = sexpr_node(root, "domain/domid");
- /* New 3.0.4 XenD will not report a domid for inactive domains,
- * so only error out for old XenD
- */
- if (!tmp && priv->xendConfigVersion < 3)
- goto error;
-
- if (tmp)
- ret->id = sexpr_int(root, "domain/domid");
- else
- ret->id = -1; /* An inactive domain */
-
- return (ret);
-
-error:
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("failed to parse Xend domain information"));
- if (ret != NULL)
- virUnrefDomain(ret);
- return(NULL);
-}
-#endif /* !PROXY */
-
-/*****************************************************************
- ******
- ******
- ******
- ******
- Refactored
- ******
- ******
- ******
- ******
- *****************************************************************/
-#ifndef PROXY
-/**
- * xenDaemonOpen:
- * @conn: an existing virtual connection block
- * @name: optional argument to select a connection type
- * @flags: combination of virDrvOpenFlag(s)
- *
- * Creates a localhost Xen Daemon connection
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-virDrvOpenStatus
-xenDaemonOpen(virConnectPtr conn,
- virConnectAuthPtr auth ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED)
-{
- char *port = NULL;
- int ret = VIR_DRV_OPEN_ERROR;
-
- /* Switch on the scheme, which we expect to be NULL (file),
- * "http" or "xen".
- */
- if (conn->uri->scheme == NULL) {
- /* It should be a file access */
- if (conn->uri->path == NULL) {
- virXendError(NULL, VIR_ERR_NO_CONNECT, __FUNCTION__);
- goto failed;
- }
- if (xenDaemonOpen_unix(conn, conn->uri->path) < 0 ||
- xend_detect_config_version(conn) == -1)
- goto failed;
- }
- else if (STRCASEEQ (conn->uri->scheme, "xen")) {
- /*
- * try first to open the unix socket
- */
- if (xenDaemonOpen_unix(conn, "/var/lib/xend/xend-socket") == 0 &&
- xend_detect_config_version(conn) != -1)
- goto done;
-
- /*
- * try though http on port 8000
- */
- if (xenDaemonOpen_tcp(conn, "localhost", "8000") < 0 ||
- xend_detect_config_version(conn) == -1)
- goto failed;
- } else if (STRCASEEQ (conn->uri->scheme, "http")) {
- if (conn->uri->port &&
- virAsprintf(&port, "%d", conn->uri->port) == -1)
- goto failed;
-
- if (xenDaemonOpen_tcp(conn,
- conn->uri->server ? conn->uri->server : "localhost",
- port ? port : "8000") < 0 ||
- xend_detect_config_version(conn) == -1)
- goto failed;
- } else {
- virXendError(NULL, VIR_ERR_NO_CONNECT, __FUNCTION__);
- goto failed;
- }
-
- done:
- ret = VIR_DRV_OPEN_SUCCESS;
-
-failed:
- VIR_FREE(port);
- return ret;
-}
-
-
-/**
- * xenDaemonClose:
- * @conn: an existing virtual connection block
- *
- * This method should be called when a connection to xend instance
- * initialized with xenDaemonOpen is no longer needed
- * to free the associated resources.
- *
- * Returns 0 in case of success, -1 in case of error
- */
-int
-xenDaemonClose(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- return 0;
-}
-
-/**
- * xenDaemonDomainSuspend:
- * @domain: pointer to the Domain block
- *
- * Pause the domain, the domain is not scheduled anymore though its resources
- * are preserved. Use xenDaemonDomainResume() to resume execution.
- *
- * Returns 0 in case of success, -1 (with errno) in case of error.
- */
-int
-xenDaemonDomainSuspend(virDomainPtr domain)
-{
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- if (domain->id < 0) {
- virXendError(domain->conn, VIR_ERR_OPERATION_INVALID,
- _("Domain %s isn't running."), domain->name);
- return(-1);
- }
-
- return xend_op(domain->conn, domain->name, "op", "pause", NULL);
-}
-
-/**
- * xenDaemonDomainResume:
- * @xend: pointer to the Xem Daemon block
- * @name: name for the domain
- *
- * Resume the domain after xenDaemonDomainSuspend() has been called
- *
- * Returns 0 in case of success, -1 (with errno) in case of error.
- */
-int
-xenDaemonDomainResume(virDomainPtr domain)
-{
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- if (domain->id < 0) {
- virXendError(domain->conn, VIR_ERR_OPERATION_INVALID,
- _("Domain %s isn't running."), domain->name);
- return(-1);
- }
-
- return xend_op(domain->conn, domain->name, "op", "unpause", NULL);
-}
-
-/**
- * xenDaemonDomainShutdown:
- * @domain: pointer to the Domain block
- *
- * Shutdown the domain, the OS is requested to properly shutdown
- * and the domain may ignore it. It will return immediately
- * after queuing the request.
- *
- * Returns 0 in case of success, -1 (with errno) in case of error.
- */
-int
-xenDaemonDomainShutdown(virDomainPtr domain)
-{
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- if (domain->id < 0) {
- virXendError(domain->conn, VIR_ERR_OPERATION_INVALID,
- _("Domain %s isn't running."), domain->name);
- return(-1);
- }
-
- return xend_op(domain->conn, domain->name, "op", "shutdown", "reason", "poweroff", NULL);
-}
-
-/**
- * xenDaemonDomainReboot:
- * @domain: pointer to the Domain block
- * @flags: extra flags for the reboot operation, not used yet
- *
- * Reboot the domain, the OS is requested to properly shutdown
- * and restart but the domain may ignore it. It will return immediately
- * after queuing the request.
- *
- * Returns 0 in case of success, -1 (with errno) in case of error.
- */
-int
-xenDaemonDomainReboot(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED)
-{
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- if (domain->id < 0) {
- virXendError(domain->conn, VIR_ERR_OPERATION_INVALID,
- _("Domain %s isn't running."), domain->name);
- return(-1);
- }
-
- return xend_op(domain->conn, domain->name, "op", "shutdown", "reason", "reboot", NULL);
-}
-
-/**
- * xenDaemonDomainDestroy:
- * @domain: pointer to the Domain block
- *
- * Abruptly halt the domain, the OS is not properly shutdown and the
- * resources allocated for the domain are immediately freed, mounted
- * filesystems will be marked as uncleanly shutdown.
- * After calling this function, the domain's status will change to
- * dying and will go away completely once all of the resources have been
- * unmapped (usually from the backend devices).
- *
- * Returns 0 in case of success, -1 (with errno) in case of error.
- */
-int
-xenDaemonDomainDestroy(virDomainPtr domain)
-{
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- if (domain->id < 0) {
- virXendError(domain->conn, VIR_ERR_OPERATION_INVALID,
- _("Domain %s isn't running."), domain->name);
- return(-1);
- }
-
- return xend_op(domain->conn, domain->name, "op", "destroy", NULL);
-}
-
-/**
- * xenDaemonDomainGetOSType:
- * @domain: a domain object
- *
- * Get the type of domain operation system.
- *
- * Returns the new string or NULL in case of error, the string must be
- * freed by the caller.
- */
-static char *
-xenDaemonDomainGetOSType(virDomainPtr domain)
-{
- char *type;
- struct sexpr *root;
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(NULL);
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
-
- if (domain->id < 0 && priv->xendConfigVersion < 3)
- return(NULL);
-
- /* can we ask for a subset ? worth it ? */
- root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
- if (root == NULL)
- return(NULL);
-
- if (sexpr_lookup(root, "domain/image/hvm")) {
- type = strdup("hvm");
- } else {
- type = strdup("linux");
- }
-
- sexpr_free(root);
-
- return(type);
-}
-
-/**
- * xenDaemonDomainSave:
- * @domain: pointer to the Domain block
- * @filename: path for the output file
- *
- * This method will suspend a domain and save its memory contents to
- * a file on disk. Use xenDaemonDomainRestore() to restore a domain after
- * saving.
- * Note that for remote Xen Daemon the file path will be interpreted in
- * the remote host.
- *
- * Returns 0 in case of success, -1 (with errno) in case of error.
- */
-int
-xenDaemonDomainSave(virDomainPtr domain, const char *filename)
-{
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
- (filename == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- if (domain->id < 0) {
- virXendError(domain->conn, VIR_ERR_OPERATION_INVALID,
- _("Domain %s isn't running."), domain->name);
- return(-1);
- }
-
- /* We can't save the state of Domain-0, that would mean stopping it too */
- if (domain->id == 0) {
- return(-1);
- }
-
- return xend_op(domain->conn, domain->name, "op", "save", "file", filename, NULL);
-}
-
-/**
- * xenDaemonDomainCoreDump:
- * @domain: pointer to the Domain block
- * @filename: path for the output file
- * @flags: extra flags, currently unused
- *
- * This method will dump the core of a domain on a given file for analysis.
- * Note that for remote Xen Daemon the file path will be interpreted in
- * the remote host.
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-static int
-xenDaemonDomainCoreDump(virDomainPtr domain, const char *filename,
- int flags ATTRIBUTE_UNUSED)
-{
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
- (filename == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- if (domain->id < 0) {
- virXendError(domain->conn, VIR_ERR_OPERATION_INVALID,
- _("Domain %s isn't running."), domain->name);
- return(-1);
- }
-
- return xend_op(domain->conn, domain->name, "op", "dump", "file", filename,
- "live", "0", "crash", "0", NULL);
-}
-
-/**
- * xenDaemonDomainRestore:
- * @conn: pointer to the Xem Daemon block
- * @filename: path for the output file
- *
- * This method will restore a domain saved to disk by xenDaemonDomainSave().
- * Note that for remote Xen Daemon the file path will be interpreted in
- * the remote host.
- *
- * Returns 0 in case of success, -1 (with errno) in case of error.
- */
-int
-xenDaemonDomainRestore(virConnectPtr conn, const char *filename)
-{
- if ((conn == NULL) || (filename == NULL)) {
- /* this should be caught at the interface but ... */
- virXendError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (-1);
- }
- return xend_op(conn, "", "op", "restore", "file", filename, NULL);
-}
-#endif /* !PROXY */
-
-/**
- * xenDaemonDomainGetMaxMemory:
- * @domain: pointer to the domain block
- *
- * Ask the Xen Daemon for the maximum memory allowed for a domain
- *
- * Returns the memory size in kilobytes or 0 in case of error.
- */
-unsigned long
-xenDaemonDomainGetMaxMemory(virDomainPtr domain)
-{
- unsigned long ret = 0;
- struct sexpr *root;
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
-
- if (domain->id < 0 && priv->xendConfigVersion < 3)
- return(-1);
-
- /* can we ask for a subset ? worth it ? */
- root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
- if (root == NULL)
- return(0);
-
- ret = (unsigned long) sexpr_u64(root, "domain/memory") << 10;
- sexpr_free(root);
-
- return(ret);
-}
-
-#ifndef PROXY
-/**
- * xenDaemonDomainSetMaxMemory:
- * @domain: pointer to the Domain block
- * @memory: The maximum memory in kilobytes
- *
- * This method will set the maximum amount of memory that can be allocated to
- * a domain. Please note that a domain is able to allocate up to this amount
- * on its own.
- *
- * Returns 0 for success; -1 (with errno) on error
- */
-int
-xenDaemonDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
-{
- char buf[1024];
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
-
- if (domain->id < 0 && priv->xendConfigVersion < 3)
- return(-1);
-
- snprintf(buf, sizeof(buf), "%lu", memory >> 10);
- return xend_op(domain->conn, domain->name, "op", "maxmem_set", "memory",
- buf, NULL);
-}
-
-/**
- * xenDaemonDomainSetMemory:
- * @domain: pointer to the Domain block
- * @memory: The target memory in kilobytes
- *
- * This method will set a target memory allocation for a given domain and
- * request that the guest meet this target. The guest may or may not actually
- * achieve this target. When this function returns, it does not signify that
- * the domain has actually reached that target.
- *
- * Memory for a domain can only be allocated up to the maximum memory setting.
- * There is no safe guard for allocations that are too small so be careful
- * when using this function to reduce a domain's memory usage.
- *
- * Returns 0 for success; -1 (with errno) on error
- */
-int
-xenDaemonDomainSetMemory(virDomainPtr domain, unsigned long memory)
-{
- char buf[1024];
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
-
- if (domain->id < 0 && priv->xendConfigVersion < 3)
- return(-1);
-
- snprintf(buf, sizeof(buf), "%lu", memory >> 10);
- return xend_op(domain->conn, domain->name, "op", "mem_target_set",
- "target", buf, NULL);
-}
-
-#endif /* ! PROXY */
-
-virDomainDefPtr
-xenDaemonDomainFetch(virConnectPtr conn,
- int domid,
- const char *name,
- const char *cpus)
-{
- struct sexpr *root;
- xenUnifiedPrivatePtr priv;
- virDomainDefPtr def;
-
- if (name)
- root = sexpr_get(conn, "/xend/domain/%s?detail=1", name);
- else
- root = sexpr_get(conn, "/xend/domain/%d?detail=1", domid);
- if (root == NULL) {
- virXendError (conn, VIR_ERR_XEN_CALL,
- "%s", _("xenDaemonDomainFetch failed to"
- " find this domain"));
- return (NULL);
- }
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- if (!(def = xenDaemonParseSxpr(conn,
- root,
- priv->xendConfigVersion,
- cpus)))
- goto cleanup;
-
-cleanup:
- sexpr_free(root);
-
- return (def);
-}
-
-
-#ifndef PROXY
-/**
- * xenDaemonDomainDumpXML:
- * @domain: a domain object
- * @flags: potential dump flags
- * @cpus: list of cpu the domain is pinned to.
- *
- * Provide an XML description of the domain.
- *
- * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
- * the caller must free() the returned value.
- */
-char *
-xenDaemonDomainDumpXML(virDomainPtr domain, int flags, const char *cpus)
-{
- xenUnifiedPrivatePtr priv;
- virDomainDefPtr def;
- char *xml;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(NULL);
- }
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
-
- if (domain->id < 0 && priv->xendConfigVersion < 3) {
- // fall-through to the next driver to handle
- return(NULL);
- }
-
- if (!(def = xenDaemonDomainFetch(domain->conn,
- domain->id,
- domain->name,
- cpus)))
- return(NULL);
-
- xml = virDomainDefFormat(domain->conn, def, flags);
-
- virDomainDefFree(def);
-
- return xml;
-}
-#endif /* !PROXY */
-
-/**
- * xenDaemonDomainGetInfo:
- * @domain: a domain object
- * @info: pointer to a virDomainInfo structure allocated by the user
- *
- * This method looks up information about a domain and update the
- * information block provided.
- *
- * Returns 0 in case of success, -1 in case of error
- */
-int
-xenDaemonDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
-{
- struct sexpr *root;
- int ret;
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
- (info == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
-
- if (domain->id < 0 && priv->xendConfigVersion < 3)
- return(-1);
-
- root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
- if (root == NULL)
- return (-1);
-
- ret = sexpr_to_xend_domain_info(domain, root, info);
- sexpr_free(root);
- return (ret);
-}
-
-#ifndef PROXY
-/**
- * xenDaemonLookupByName:
- * @conn: A xend instance
- * @name: The name of the domain
- *
- * This method looks up information about a domain and returns
- * it in the form of a struct xend_domain. This should be
- * free()'d when no longer needed.
- *
- * Returns domain info on success; NULL (with errno) on error
- */
-virDomainPtr
-xenDaemonLookupByName(virConnectPtr conn, const char *domname)
-{
- struct sexpr *root;
- virDomainPtr ret = NULL;
-
- if ((conn == NULL) || (domname == NULL)) {
- virXendError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return(NULL);
- }
-
- root = sexpr_get(conn, "/xend/domain/%s?detail=1", domname);
- if (root == NULL)
- goto error;
-
- ret = sexpr_to_domain(conn, root);
-
-error:
- sexpr_free(root);
- return(ret);
-}
-#endif /* ! PROXY */
-
-/**
- * xenDaemonNodeGetInfo:
- * @conn: pointer to the Xen Daemon block
- * @info: pointer to a virNodeInfo structure allocated by the user
- *
- * Extract hardware information about the node.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-xenDaemonNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) {
- int ret = -1;
- struct sexpr *root;
-
- if (!VIR_IS_CONNECT(conn)) {
- virXendError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (-1);
- }
- if (info == NULL) {
- virXendError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (-1);
- }
-
- root = sexpr_get(conn, "/xend/node/");
- if (root == NULL)
- return (-1);
-
- ret = sexpr_to_xend_node_info(root, info);
- sexpr_free(root);
- return (ret);
-}
-
-/**
- * xenDaemonNodeGetTopology:
- * @conn: pointer to the Xen Daemon block
- * @caps: capabilities info
- *
- * This method retrieves a node's topology information.
- *
- * Returns -1 in case of error, 0 otherwise.
- */
-int
-xenDaemonNodeGetTopology(virConnectPtr conn,
- virCapsPtr caps) {
- int ret = -1;
- struct sexpr *root;
-
- if (!VIR_IS_CONNECT(conn)) {
- virXendError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (-1);
- }
-
- if (caps == NULL) {
- virXendError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (-1);
- }
-
- root = sexpr_get(conn, "/xend/node/");
- if (root == NULL) {
- return (-1);
- }
-
- ret = sexpr_to_xend_topology(conn, root, caps);
- sexpr_free(root);
- return (ret);
-}
-
-/**
- * xenDaemonGetVersion:
- * @conn: pointer to the Xen Daemon block
- * @hvVer: return value for the version of the running hypervisor (OUT)
- *
- * Get the version level of the Hypervisor running.
- *
- * Returns -1 in case of error, 0 otherwise. if the version can't be
- * extracted by lack of capacities returns 0 and @hvVer is 0, otherwise
- * @hvVer value is major * 1,000,000 + minor * 1,000 + release
- */
-int
-xenDaemonGetVersion(virConnectPtr conn, unsigned long *hvVer)
-{
- struct sexpr *root;
- int major, minor;
- unsigned long version;
-
- if (!VIR_IS_CONNECT(conn)) {
- virXendError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (-1);
- }
- if (hvVer == NULL) {
- virXendError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (-1);
- }
- root = sexpr_get(conn, "/xend/node/");
- if (root == NULL)
- return(-1);
-
- major = sexpr_int(root, "node/xen_major");
- minor = sexpr_int(root, "node/xen_minor");
- sexpr_free(root);
- version = major * 1000000 + minor * 1000;
- *hvVer = version;
- return(0);
-}
-
-#ifndef PROXY
-/**
- * xenDaemonListDomains:
- * @conn: pointer to the hypervisor connection
- * @ids: array to collect the list of IDs of active domains
- * @maxids: size of @ids
- *
- * Collect the list of active domains, and store their ID in @maxids
- * TODO: this is quite expensive at the moment since there isn't one
- * xend RPC providing both name and id for all domains.
- *
- * Returns the number of domain found or -1 in case of error
- */
-int
-xenDaemonListDomains(virConnectPtr conn, int *ids, int maxids)
-{
- struct sexpr *root = NULL;
- int ret = -1;
- struct sexpr *_for_i, *node;
- long id;
-
- if (maxids == 0)
- return(0);
-
- if ((ids == NULL) || (maxids < 0))
- goto error;
- root = sexpr_get(conn, "/xend/domain");
- if (root == NULL)
- goto error;
-
- ret = 0;
-
- for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
- _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
- if (node->kind != SEXPR_VALUE)
- continue;
- id = xenDaemonDomainLookupByName_ids(conn, node->u.value, NULL);
- if (id >= 0)
- ids[ret++] = (int) id;
- if (ret >= maxids)
- break;
- }
-
-error:
- sexpr_free(root);
- return(ret);
-}
-
-/**
- * xenDaemonNumOfDomains:
- * @conn: pointer to the hypervisor connection
- *
- * Provides the number of active domains.
- *
- * Returns the number of domain found or -1 in case of error
- */
-static int
-xenDaemonNumOfDomains(virConnectPtr conn)
-{
- struct sexpr *root = NULL;
- int ret = -1;
- struct sexpr *_for_i, *node;
-
- root = sexpr_get(conn, "/xend/domain");
- if (root == NULL)
- goto error;
-
- ret = 0;
-
- for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
- _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
- if (node->kind != SEXPR_VALUE)
- continue;
- ret++;
- }
-
-error:
- sexpr_free(root);
- return(ret);
-}
-#endif /* ! PROXY */
-
-#ifndef PROXY
-/**
- * xenDaemonLookupByID:
- * @conn: pointer to the hypervisor connection
- * @id: the domain ID number
- *
- * Try to find a domain based on the hypervisor ID number
- *
- * Returns a new domain object or NULL in case of failure
- */
-virDomainPtr
-xenDaemonLookupByID(virConnectPtr conn, int id) {
- char *name = NULL;
- unsigned char uuid[VIR_UUID_BUFLEN];
- virDomainPtr ret;
-
- if (xenDaemonDomainLookupByID(conn, id, &name, uuid) < 0) {
- goto error;
- }
-
- ret = virGetDomain(conn, name, uuid);
- if (ret == NULL) goto error;
-
- ret->id = id;
- VIR_FREE(name);
- return (ret);
-
- error:
- VIR_FREE(name);
- return (NULL);
-}
-
-/**
- * xenDaemonDomainSetVcpus:
- * @domain: pointer to domain object
- * @nvcpus: the new number of virtual CPUs for this domain
- *
- * Dynamically change the number of virtual CPUs used by the domain.
- *
- * Returns 0 for success; -1 (with errno) on error
- */
-int
-xenDaemonDomainSetVcpus(virDomainPtr domain, unsigned int vcpus)
-{
- char buf[VIR_UUID_BUFLEN];
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
- || (vcpus < 1)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return (-1);
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
-
- if (domain->id < 0 && priv->xendConfigVersion < 3)
- return(-1);
-
- snprintf(buf, sizeof(buf), "%d", vcpus);
- return(xend_op(domain->conn, domain->name, "op", "set_vcpus", "vcpus",
- buf, NULL));
-}
-
-/**
- * xenDaemonDomainPinCpu:
- * @domain: pointer to domain object
- * @vcpu: virtual CPU number
- * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes)
- * @maplen: length of cpumap in bytes
- *
- * Dynamically change the real CPUs which can be allocated to a virtual CPU.
- * NOTE: The XenD cpu affinity map format changed from "[0,1,2]" to
- * "0,1,2"
- * the XenD cpu affinity works only after cset 19579.
- * there is no fine grained xend version detection possible, so we
- * use the old format for anything before version 3
- *
- * Returns 0 for success; -1 (with errno) on error
- */
-int
-xenDaemonDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
- unsigned char *cpumap, int maplen)
-{
- char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64];
- int i, j;
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
- || (cpumap == NULL) || (maplen < 1) || (maplen > (int)sizeof(cpumap_t))) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return (-1);
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->xendConfigVersion < 3) {
- mapstr[0] = '[';
- mapstr[1] = 0;
- } else {
- mapstr[0] = 0;
- }
-
- /* from bit map, build character string of mapped CPU numbers */
- for (i = 0; i < maplen; i++) for (j = 0; j < 8; j++)
- if (cpumap[i] & (1 << j)) {
- snprintf(buf, sizeof(buf), "%d,", (8 * i) + j);
- strcat(mapstr, buf);
- }
- if (priv->xendConfigVersion < 3)
- mapstr[strlen(mapstr) - 1] = ']';
- else
- mapstr[strlen(mapstr) - 1] = 0;
-
- snprintf(buf, sizeof(buf), "%d", vcpu);
- return(xend_op(domain->conn, domain->name, "op", "pincpu", "vcpu", buf,
- "cpumap", mapstr, NULL));
-}
-
-/**
- * virDomainGetVcpus:
- * @domain: pointer to domain object, or NULL for Domain0
- * @info: pointer to an array of virVcpuInfo structures (OUT)
- * @maxinfo: number of structures in info array
- * @cpumaps: pointer to an bit map of real CPUs for all vcpus of this domain (in 8-bit bytes) (OUT)
- * If cpumaps is NULL, then no cpumap information is returned by the API.
- * It's assumed there is <maxinfo> cpumap in cpumaps array.
- * The memory allocated to cpumaps must be (maxinfo * maplen) bytes
- * (ie: calloc(maxinfo, maplen)).
- * One cpumap inside cpumaps has the format described in virDomainPinVcpu() API.
- * @maplen: number of bytes in one cpumap, from 1 up to size of CPU map in
- * underlying virtualization system (Xen...).
- *
- * Extract information about virtual CPUs of domain, store it in info array
- * and also in cpumaps if this pointer isn't NULL.
- *
- * Returns the number of info filled in case of success, -1 in case of failure.
- */
-int
-xenDaemonDomainGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo,
- unsigned char *cpumaps, int maplen)
-{
- struct sexpr *root, *s, *t;
- virVcpuInfoPtr ipt = info;
- int nbinfo = 0, oln;
- unsigned char *cpumap;
- int vcpu, cpu;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
- || (info == NULL) || (maxinfo < 1)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return (-1);
- }
- if (cpumaps != NULL && maplen < 1) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return (-1);
- }
-
- root = sexpr_get(domain->conn, "/xend/domain/%s?op=vcpuinfo", domain->name);
- if (root == NULL)
- return (-1);
-
- if (cpumaps != NULL)
- memset(cpumaps, 0, maxinfo * maplen);
-
- /* scan the sexprs from "(vcpu (number x)...)" and get parameter values */
- for (s = root; s->kind == SEXPR_CONS; s = s->u.s.cdr) {
- if ((s->u.s.car->kind == SEXPR_CONS) &&
- (s->u.s.car->u.s.car->kind == SEXPR_VALUE) &&
- STREQ(s->u.s.car->u.s.car->u.value, "vcpu")) {
- t = s->u.s.car;
- vcpu = ipt->number = sexpr_int(t, "vcpu/number");
- if ((oln = sexpr_int(t, "vcpu/online")) != 0) {
- if (sexpr_int(t, "vcpu/running")) ipt->state = VIR_VCPU_RUNNING;
- if (sexpr_int(t, "vcpu/blocked")) ipt->state = VIR_VCPU_BLOCKED;
- }
- else
- ipt->state = VIR_VCPU_OFFLINE;
- ipt->cpuTime = sexpr_float(t, "vcpu/cpu_time") * 1000000000;
- ipt->cpu = oln ? sexpr_int(t, "vcpu/cpu") : -1;
-
- if (cpumaps != NULL && vcpu >= 0 && vcpu < maxinfo) {
- cpumap = (unsigned char *) VIR_GET_CPUMAP(cpumaps, maplen, vcpu);
- /*
- * get sexpr from "(cpumap (x y z...))" and convert values
- * to bitmap
- */
- for (t = t->u.s.cdr; t->kind == SEXPR_CONS; t = t->u.s.cdr)
- if ((t->u.s.car->kind == SEXPR_CONS) &&
- (t->u.s.car->u.s.car->kind == SEXPR_VALUE) &&
- STREQ(t->u.s.car->u.s.car->u.value, "cpumap") &&
- (t->u.s.car->u.s.cdr->kind == SEXPR_CONS)) {
- for (t = t->u.s.car->u.s.cdr->u.s.car; t->kind == SEXPR_CONS; t = t->u.s.cdr)
- if (t->u.s.car->kind == SEXPR_VALUE
- && virStrToLong_i(t->u.s.car->u.value, NULL, 10, &cpu) == 0
- && cpu >= 0
- && (VIR_CPU_MAPLEN(cpu+1) <= maplen)) {
- VIR_USE_CPU(cpumap, cpu);
- }
- break;
- }
- }
-
- if (++nbinfo == maxinfo) break;
- ipt++;
- }
- }
- sexpr_free(root);
- return(nbinfo);
-}
-
-/**
- * xenDaemonLookupByUUID:
- * @conn: pointer to the hypervisor connection
- * @uuid: the raw UUID for the domain
- *
- * Try to lookup a domain on xend based on its UUID.
- *
- * Returns a new domain object or NULL in case of failure
- */
-virDomainPtr
-xenDaemonLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
-{
- virDomainPtr ret;
- char *name = NULL;
- int id = -1;
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- /* Old approach for xen <= 3.0.3 */
- if (priv->xendConfigVersion < 3) {
- char **names, **tmp;
- unsigned char ident[VIR_UUID_BUFLEN];
- names = xenDaemonListDomainsOld(conn);
- tmp = names;
-
- if (names == NULL) {
- return (NULL);
- }
- while (*tmp != NULL) {
- id = xenDaemonDomainLookupByName_ids(conn, *tmp, &ident[0]);
- if (id >= 0) {
- if (!memcmp(uuid, ident, VIR_UUID_BUFLEN)) {
- name = strdup(*tmp);
- break;
- }
- }
- tmp++;
- }
- VIR_FREE(names);
- } else { /* New approach for xen >= 3.0.4 */
- char *domname = NULL;
- char uuidstr[VIR_UUID_STRING_BUFLEN];
- struct sexpr *root = NULL;
-
- virUUIDFormat(uuid, uuidstr);
- root = sexpr_get(conn, "/xend/domain/%s?detail=1", uuidstr);
- if (root == NULL)
- return (NULL);
- domname = (char*)sexpr_node(root, "domain/name");
- if (sexpr_node(root, "domain/domid")) /* only active domains have domid */
- id = sexpr_int(root, "domain/domid");
- else
- id = -1;
- name = domname ? strdup(domname) : NULL;
- sexpr_free(root);
- }
-
- if (name == NULL)
- return (NULL);
-
- ret = virGetDomain(conn, name, uuid);
- if (ret == NULL) goto cleanup;
-
- ret->id = id;
-
- cleanup:
- VIR_FREE(name);
- return (ret);
-}
-
-/**
- * xenDaemonCreateXML:
- * @conn: pointer to the hypervisor connection
- * @xmlDesc: an XML description of the domain
- * @flags: an optional set of virDomainFlags
- *
- * Launch a new Linux guest domain, based on an XML description similar
- * to the one returned by virDomainGetXMLDesc()
- * This function may requires privileged access to the hypervisor.
- *
- * Returns a new domain object or NULL in case of failure
- */
-static virDomainPtr
-xenDaemonCreateXML(virConnectPtr conn, const char *xmlDesc,
- unsigned int flags ATTRIBUTE_UNUSED)
-{
- int ret;
- char *sexpr;
- virDomainPtr dom = NULL;
- xenUnifiedPrivatePtr priv;
- virDomainDefPtr def;
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- if (!(def = virDomainDefParseString(conn,
- priv->caps,
- xmlDesc,
- VIR_DOMAIN_XML_INACTIVE)))
- return (NULL);
-
- if (!(sexpr = xenDaemonFormatSxpr(conn, def, priv->xendConfigVersion))) {
- virDomainDefFree(def);
- return (NULL);
- }
-
- ret = xenDaemonDomainCreateXML(conn, sexpr);
- VIR_FREE(sexpr);
- if (ret != 0) {
- goto error;
- }
-
- /* This comes before wait_for_devices, to ensure that latter
- cleanup will destroy the domain upon failure */
- if (!(dom = virDomainLookupByName(conn, def->name)))
- goto error;
-
- if (xend_wait_for_devices(conn, def->name) < 0)
- goto error;
-
- if (xenDaemonDomainResume(dom) < 0)
- goto error;
-
- virDomainDefFree(def);
- return (dom);
-
- error:
- /* Make sure we don't leave a still-born domain around */
- if (dom != NULL) {
- xenDaemonDomainDestroy(dom);
- virUnrefDomain(dom);
- }
- virDomainDefFree(def);
- return (NULL);
-}
-
-/**
- * xenDaemonAttachDevice:
- * @domain: pointer to domain object
- * @xml: pointer to XML description of device
- *
- * Create a virtual device attachment to backend.
- * XML description is translated into S-expression.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-static int
-xenDaemonAttachDevice(virDomainPtr domain, const char *xml)
-{
- xenUnifiedPrivatePtr priv;
- char *sexpr = NULL;
- int ret = -1;
- virDomainDeviceDefPtr dev = NULL;
- virDomainDefPtr def = NULL;
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- char class[8], ref[80];
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return -1;
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
-
- /*
- * on older Xen without the inactive guests management
- * avoid doing this on inactive guests
- */
- if ((domain->id < 0) && (priv->xendConfigVersion < 3))
- return -1;
-
- if (!(def = xenDaemonDomainFetch(domain->conn,
- domain->id,
- domain->name,
- NULL)))
- goto cleanup;
-
- if (!(dev = virDomainDeviceDefParse(domain->conn,
- priv->caps,
- def, xml, VIR_DOMAIN_XML_INACTIVE)))
- goto cleanup;
-
-
- switch (dev->type) {
- case VIR_DOMAIN_DEVICE_DISK:
- if (xenDaemonFormatSxprDisk(domain->conn,
- dev->data.disk,
- &buf,
- STREQ(def->os.type, "hvm") ? 1 : 0,
- priv->xendConfigVersion, 1) < 0)
- goto cleanup;
- break;
-
- case VIR_DOMAIN_DEVICE_NET:
- if (xenDaemonFormatSxprNet(domain->conn,
- dev->data.net,
- &buf,
- STREQ(def->os.type, "hvm") ? 1 : 0,
- priv->xendConfigVersion, 1) < 0)
- goto cleanup;
- break;
-
- case VIR_DOMAIN_DEVICE_HOSTDEV:
- if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
- dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
- if (xenDaemonFormatSxprOnePCI(domain->conn,
- dev->data.hostdev,
- &buf) < 0)
- goto cleanup;
- } else {
- virXendError(domain->conn, VIR_ERR_NO_SUPPORT, "%s",
- _("unsupported device type"));
- goto cleanup;
- }
- break;
-
- default:
- virXendError(domain->conn, VIR_ERR_NO_SUPPORT, "%s",
- _("unsupported device type"));
- goto cleanup;
- }
-
- sexpr = virBufferContentAndReset(&buf);
-
- if (virDomainXMLDevID(domain, dev, class, ref, sizeof(ref))) {
- /* device doesn't exist, define it */
- ret = xend_op(domain->conn, domain->name, "op", "device_create",
- "config", sexpr, NULL);
- }
- else {
- /* device exists, attempt to modify it */
- ret = xend_op(domain->conn, domain->name, "op", "device_configure",
- "config", sexpr, "dev", ref, NULL);
- }
-
-cleanup:
- VIR_FREE(sexpr);
- virDomainDefFree(def);
- virDomainDeviceDefFree(dev);
- return ret;
-}
-
-/**
- * xenDaemonDetachDevice:
- * @domain: pointer to domain object
- * @xml: pointer to XML description of device
- *
- * Destroy a virtual device attachment to backend.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-static int
-xenDaemonDetachDevice(virDomainPtr domain, const char *xml)
-{
- xenUnifiedPrivatePtr priv;
- char class[8], ref[80];
- virDomainDeviceDefPtr dev = NULL;
- virDomainDefPtr def = NULL;
- int ret = -1;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return (-1);
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
-
- /*
- * on older Xen without the inactive guests management
- * avoid doing this on inactive guests
- */
- if ((domain->id < 0) && (priv->xendConfigVersion < 3))
- return -1;
-
- if (!(def = xenDaemonDomainFetch(domain->conn,
- domain->id,
- domain->name,
- NULL)))
- goto cleanup;
-
- if (!(dev = virDomainDeviceDefParse(domain->conn,
- priv->caps,
- def, xml, VIR_DOMAIN_XML_INACTIVE)))
- goto cleanup;
-
- if (virDomainXMLDevID(domain, dev, class, ref, sizeof(ref)))
- goto cleanup;
-
- ret = xend_op(domain->conn, domain->name, "op", "device_destroy",
- "type", class, "dev", ref, "force", "0", "rm_cfg", "1", NULL);
-
-cleanup:
- virDomainDefFree(def);
- virDomainDeviceDefFree(dev);
-
- return ret;
-}
-
-int
-xenDaemonDomainGetAutostart(virDomainPtr domain,
- int *autostart)
-{
- struct sexpr *root;
- const char *tmp;
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return (-1);
- }
-
- /* xm_internal.c (the support for defined domains from /etc/xen
- * config files used by old Xen) will handle this.
- */
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->xendConfigVersion < 3)
- return(-1);
-
- root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
- if (root == NULL) {
- virXendError (domain->conn, VIR_ERR_XEN_CALL,
- "%s", _("xenDaemonGetAutostart failed to find this domain"));
- return (-1);
- }
-
- *autostart = 0;
-
- tmp = sexpr_node(root, "domain/on_xend_start");
- if (tmp && STREQ(tmp, "start")) {
- *autostart = 1;
- }
-
- sexpr_free(root);
- return 0;
-}
-
-int
-xenDaemonDomainSetAutostart(virDomainPtr domain,
- int autostart)
-{
- struct sexpr *root, *autonode;
- const char *autostr;
- char buf[4096];
- int ret = -1;
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INTERNAL_ERROR,
- __FUNCTION__);
- return (-1);
- }
-
- /* xm_internal.c (the support for defined domains from /etc/xen
- * config files used by old Xen) will handle this.
- */
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->xendConfigVersion < 3)
- return(-1);
-
- root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
- if (root == NULL) {
- virXendError (domain->conn, VIR_ERR_XEN_CALL,
- "%s", _("xenDaemonSetAutostart failed to find this domain"));
- return (-1);
- }
-
- autostr = sexpr_node(root, "domain/on_xend_start");
- if (autostr) {
- if (!STREQ(autostr, "ignore") && !STREQ(autostr, "start")) {
- virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("unexpected value from on_xend_start"));
- goto error;
- }
-
- // Change the autostart value in place, then define the new sexpr
- autonode = sexpr_lookup(root, "domain/on_xend_start");
- VIR_FREE(autonode->u.s.car->u.value);
- autonode->u.s.car->u.value = (autostart ? strdup("start")
- : strdup("ignore"));
- if (!(autonode->u.s.car->u.value)) {
- virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("no memory"));
- goto error;
- }
-
- if (sexpr2string(root, buf, sizeof(buf)) == 0) {
- virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("sexpr2string failed"));
- goto error;
- }
- if (xend_op(domain->conn, "", "op", "new", "config", buf, NULL) != 0) {
- virXendError(domain->conn, VIR_ERR_XEN_CALL,
- "%s", _("Failed to redefine sexpr"));
- goto error;
- }
- } else {
- virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("on_xend_start not present in sexpr"));
- goto error;
- }
-
- ret = 0;
- error:
- sexpr_free(root);
- return ret;
-}
-
-int
-xenDaemonDomainMigratePrepare (virConnectPtr dconn,
- char **cookie ATTRIBUTE_UNUSED,
- int *cookielen ATTRIBUTE_UNUSED,
- const char *uri_in,
- char **uri_out,
- unsigned long flags ATTRIBUTE_UNUSED,
- const char *dname ATTRIBUTE_UNUSED,
- unsigned long resource ATTRIBUTE_UNUSED)
-{
- int r;
- char hostname [HOST_NAME_MAX+1];
-
- /* If uri_in is NULL, get the current hostname as a best guess
- * of how the source host should connect to us. Note that caller
- * deallocates this string.
- */
- if (uri_in == NULL) {
- r = gethostname (hostname, HOST_NAME_MAX+1);
- if (r == -1) {
- virReportSystemError(dconn, errno,
- _("unable to resolve name %s"), hostname);
- return -1;
- }
- *uri_out = strdup (hostname);
- if (*uri_out == NULL) {
- virReportOOMError(dconn);
- return -1;
- }
- }
-
- return 0;
-}
-
-int
-xenDaemonDomainMigratePerform (virDomainPtr domain,
- const char *cookie ATTRIBUTE_UNUSED,
- int cookielen ATTRIBUTE_UNUSED,
- const char *uri,
- unsigned long flags,
- const char *dname,
- unsigned long bandwidth)
-{
- /* Upper layers have already checked domain. */
- virConnectPtr conn = domain->conn;
- /* NB: Passing port=0 to xend means it ignores
- * the port. However this is somewhat specific to
- * the internals of the xend Python code. (XXX).
- */
- char port[16] = "0";
- char live[2] = "0";
- int ret;
- char *p, *hostname = NULL;
-
- /* Xen doesn't support renaming domains during migration. */
- if (dname) {
- virXendError (conn, VIR_ERR_NO_SUPPORT,
- "%s", _("xenDaemonDomainMigrate: Xen does not support"
- " renaming domains during migration"));
- return -1;
- }
-
- /* Xen (at least up to 3.1.0) takes a resource parameter but
- * ignores it.
- */
- if (bandwidth) {
- virXendError (conn, VIR_ERR_NO_SUPPORT,
- "%s", _("xenDaemonDomainMigrate: Xen does not support"
- " bandwidth limits during migration"));
- return -1;
- }
-
- /* Check the flags. */
- if ((flags & VIR_MIGRATE_LIVE)) {
- strcpy (live, "1");
- flags &= ~VIR_MIGRATE_LIVE;
- }
- if (flags != 0) {
- virXendError (conn, VIR_ERR_NO_SUPPORT,
- "%s", _("xenDaemonDomainMigrate: unsupported flag"));
- return -1;
- }
-
- /* Set hostname and port.
- *
- * URI is non-NULL (guaranteed by caller). We expect either
- * "hostname", "hostname:port" or "xenmigr://hostname[:port]/".
- */
- if (strstr (uri, "//")) { /* Full URI. */
- xmlURIPtr uriptr = xmlParseURI (uri);
- if (!uriptr) {
- virXendError (conn, VIR_ERR_INVALID_ARG,
- "%s", _("xenDaemonDomainMigrate: invalid URI"));
- return -1;
- }
- if (uriptr->scheme && STRCASENEQ (uriptr->scheme, "xenmigr")) {
- virXendError (conn, VIR_ERR_INVALID_ARG,
- "%s", _("xenDaemonDomainMigrate: only xenmigr://"
- " migrations are supported by Xen"));
- xmlFreeURI (uriptr);
- return -1;
- }
- if (!uriptr->server) {
- virXendError (conn, VIR_ERR_INVALID_ARG,
- "%s", _("xenDaemonDomainMigrate: a hostname must be"
- " specified in the URI"));
- xmlFreeURI (uriptr);
- return -1;
- }
- hostname = strdup (uriptr->server);
- if (!hostname) {
- virReportOOMError (conn);
- xmlFreeURI (uriptr);
- return -1;
- }
- if (uriptr->port)
- snprintf (port, sizeof port, "%d", uriptr->port);
- xmlFreeURI (uriptr);
- }
- else if ((p = strrchr (uri, ':')) != NULL) { /* "hostname:port" */
- int port_nr, n;
-
- if (sscanf (p+1, "%d", &port_nr) != 1) {
- virXendError (conn, VIR_ERR_INVALID_ARG,
- "%s", _("xenDaemonDomainMigrate: invalid port number"));
- return -1;
- }
- snprintf (port, sizeof port, "%d", port_nr);
-
- /* Get the hostname. */
- n = p - uri; /* n = Length of hostname in bytes. */
- hostname = strdup (uri);
- if (!hostname) {
- virReportOOMError (conn);
- return -1;
- }
- hostname[n] = '\0';
- }
- else { /* "hostname" (or IP address) */
- hostname = strdup (uri);
- if (!hostname) {
- virReportOOMError (conn);
- return -1;
- }
- }
-
- DEBUG("hostname = %s, port = %s", hostname, port);
-
- /* Make the call. */
- ret = xend_op (domain->conn, domain->name,
- "op", "migrate",
- "destination", hostname,
- "live", live,
- "port", port,
- "node", "-1",
- "ssl", "0",
- "resource", "0", /* required, xend ignores it */
- NULL);
- VIR_FREE (hostname);
-
- DEBUG0("migration done");
-
- return ret;
-}
-
-virDomainPtr xenDaemonDomainDefineXML(virConnectPtr conn, const char *xmlDesc) {
- int ret;
- char *sexpr;
- virDomainPtr dom;
- xenUnifiedPrivatePtr priv;
- virDomainDefPtr def;
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- if (priv->xendConfigVersion < 3)
- return(NULL);
-
- if (!(def = virDomainDefParseString(conn, priv->caps, xmlDesc,
- VIR_DOMAIN_XML_INACTIVE))) {
- virXendError(conn, VIR_ERR_XML_ERROR,
- "%s", _("failed to parse domain description"));
- return (NULL);
- }
-
- if (!(sexpr = xenDaemonFormatSxpr(conn, def, priv->xendConfigVersion))) {
- virXendError(conn, VIR_ERR_XML_ERROR,
- "%s", _("failed to build sexpr"));
- goto error;
- }
-
- DEBUG("Defining w/ sexpr: \n%s", sexpr);
-
- ret = xend_op(conn, "", "op", "new", "config", sexpr, NULL);
- VIR_FREE(sexpr);
- if (ret != 0) {
- virXendError(conn, VIR_ERR_XEN_CALL,
- _("Failed to create inactive domain %s\n"), def->name);
- goto error;
- }
-
- dom = virDomainLookupByName(conn, def->name);
- if (dom == NULL) {
- goto error;
- }
- virDomainDefFree(def);
- return (dom);
-
- error:
- virDomainDefFree(def);
- return (NULL);
-}
-int xenDaemonDomainCreate(virDomainPtr domain)
-{
- xenUnifiedPrivatePtr priv;
- int ret;
- virDomainPtr tmp;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
-
- if (priv->xendConfigVersion < 3)
- return(-1);
-
- ret = xend_op(domain->conn, domain->name, "op", "start", NULL);
-
- if (ret != -1) {
- /* Need to force a refresh of this object's ID */
- tmp = virDomainLookupByName(domain->conn, domain->name);
- if (tmp) {
- domain->id = tmp->id;
- virDomainFree(tmp);
- }
- }
- return ret;
-}
-
-int xenDaemonDomainUndefine(virDomainPtr domain)
-{
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
-
- if (priv->xendConfigVersion < 3)
- return(-1);
-
- return xend_op(domain->conn, domain->name, "op", "delete", NULL);
-}
-
-/**
- * xenDaemonNumOfDomains:
- * @conn: pointer to the hypervisor connection
- *
- * Provides the number of active domains.
- *
- * Returns the number of domain found or -1 in case of error
- */
-static int
-xenDaemonNumOfDefinedDomains(virConnectPtr conn)
-{
- struct sexpr *root = NULL;
- int ret = -1;
- struct sexpr *_for_i, *node;
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- /* xm_internal.c (the support for defined domains from /etc/xen
- * config files used by old Xen) will handle this.
- */
- if (priv->xendConfigVersion < 3)
- return(-1);
-
- root = sexpr_get(conn, "/xend/domain?state=halted");
- if (root == NULL)
- goto error;
-
- ret = 0;
-
- for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
- _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
- if (node->kind != SEXPR_VALUE)
- continue;
- ret++;
- }
-
-error:
- sexpr_free(root);
- return(ret);
-}
-
-static int
-xenDaemonListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) {
- struct sexpr *root = NULL;
- int ret = -1;
- struct sexpr *_for_i, *node;
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- if (priv->xendConfigVersion < 3)
- return(-1);
-
- if ((names == NULL) || (maxnames < 0))
- goto error;
- if (maxnames == 0)
- return(0);
-
- root = sexpr_get(conn, "/xend/domain?state=halted");
- if (root == NULL)
- goto error;
-
- ret = 0;
-
- for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
- _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
- if (node->kind != SEXPR_VALUE)
- continue;
-
- names[ret++] = strdup(node->u.value);
- if (ret >= maxnames)
- break;
- }
-
-error:
- sexpr_free(root);
- return(ret);
-}
-
-/**
- * xenDaemonGetSchedulerType:
- * @domain: pointer to the Domain block
- * @nparams: give a number of scheduler parameters
- *
- * Get the scheduler type of Xen
- *
- * Returns a scheduler name (credit or sedf) which must be freed by the
- * caller or NULL in case of failure
- */
-static char *
-xenDaemonGetSchedulerType(virDomainPtr domain, int *nparams)
-{
- xenUnifiedPrivatePtr priv;
- struct sexpr *root;
- const char *ret = NULL;
- char *schedulertype = NULL;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
- || (nparams == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return NULL;
- }
-
- /* Support only xendConfigVersion >=4 */
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->xendConfigVersion < 4) {
- virXendError (domain->conn, VIR_ERR_NO_SUPPORT,
- "%s", _("unsupported in xendConfigVersion < 4"));
- return NULL;
- }
-
- root = sexpr_get(domain->conn, "/xend/node/");
- if (root == NULL)
- return NULL;
-
- /* get xen_scheduler from xend/node */
- ret = sexpr_node(root, "node/xen_scheduler");
- if (ret == NULL){
- virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("node information incomplete, missing scheduler name"));
- goto error;
- }
- if (STREQ (ret, "credit")) {
- schedulertype = strdup("credit");
- if (schedulertype == NULL){
- virXendError(domain->conn, VIR_ERR_SYSTEM_ERROR, "%s", _("strdup failed"));
- goto error;
- }
- *nparams = XEN_SCHED_CRED_NPARAM;
- } else if (STREQ (ret, "sedf")) {
- schedulertype = strdup("sedf");
- if (schedulertype == NULL){
- virXendError(domain->conn, VIR_ERR_SYSTEM_ERROR, "%s", _("strdup failed"));
- goto error;
- }
- *nparams = XEN_SCHED_SEDF_NPARAM;
- } else {
- virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
- goto error;
- }
-
-error:
- sexpr_free(root);
- return schedulertype;
-
-}
-
-static const char *str_weight = "weight";
-static const char *str_cap = "cap";
-
-/**
- * xenDaemonGetSchedulerParameters:
- * @domain: pointer to the Domain block
- * @params: pointer to scheduler parameters
- * This memory area must be allocated by the caller
- * @nparams: a number of scheduler parameters which should be same as a
- * given number from xenDaemonGetSchedulerType()
- *
- * Get the scheduler parameters
- *
- * Returns 0 or -1 in case of failure
- */
-static int
-xenDaemonGetSchedulerParameters(virDomainPtr domain,
- virSchedParameterPtr params, int *nparams)
-{
- xenUnifiedPrivatePtr priv;
- struct sexpr *root;
- char *sched_type = NULL;
- int sched_nparam = 0;
- int ret = -1;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
- || (params == NULL) || (nparams == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return (-1);
- }
-
- /* Support only xendConfigVersion >=4 */
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->xendConfigVersion < 4) {
- virXendError (domain->conn, VIR_ERR_NO_SUPPORT,
- "%s", _("unsupported in xendConfigVersion < 4"));
- return (-1);
- }
-
- /* look up the information by domain name */
- root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
- if (root == NULL)
- return (-1);
-
- /* get the scheduler type */
- sched_type = xenDaemonGetSchedulerType(domain, &sched_nparam);
- if (sched_type == NULL) {
- virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Failed to get a scheduler name"));
- goto error;
- }
-
- switch (sched_nparam){
- case XEN_SCHED_SEDF_NPARAM:
- /* TODO: Implement for Xen/SEDF */
- TODO
- goto error;
- case XEN_SCHED_CRED_NPARAM:
- /* get cpu_weight/cpu_cap from xend/domain */
- if (sexpr_node(root, "domain/cpu_weight") == NULL) {
- virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, missing cpu_weight"));
- goto error;
- }
- if (sexpr_node(root, "domain/cpu_cap") == NULL) {
- virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, missing cpu_cap"));
- goto error;
- }
-
- strncpy (params[0].field, str_weight, VIR_DOMAIN_SCHED_FIELD_LENGTH);
- params[0].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
- params[0].type = VIR_DOMAIN_SCHED_FIELD_UINT;
- params[0].value.ui = sexpr_int(root, "domain/cpu_weight");
-
- strncpy (params[1].field, str_cap, VIR_DOMAIN_SCHED_FIELD_LENGTH);
- params[1].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
- params[1].type = VIR_DOMAIN_SCHED_FIELD_UINT;
- params[1].value.ui = sexpr_int(root, "domain/cpu_cap");
- *nparams = XEN_SCHED_CRED_NPARAM;
- ret = 0;
- break;
- default:
- virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
- goto error;
- }
-
-error:
- sexpr_free(root);
- VIR_FREE(sched_type);
- return (ret);
-}
-
-/**
- * xenDaemonSetSchedulerParameters:
- * @domain: pointer to the Domain block
- * @params: pointer to scheduler parameters
- * @nparams: a number of scheduler setting parameters
- *
- * Set the scheduler parameters
- *
- * Returns 0 or -1 in case of failure
- */
-static int
-xenDaemonSetSchedulerParameters(virDomainPtr domain,
- virSchedParameterPtr params, int nparams)
-{
- xenUnifiedPrivatePtr priv;
- struct sexpr *root;
- char *sched_type = NULL;
- int i;
- int sched_nparam = 0;
- int ret = -1;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
- || (params == NULL)) {
- virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return (-1);
- }
-
- /* Support only xendConfigVersion >=4 and active domains */
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->xendConfigVersion < 4) {
- virXendError (domain->conn, VIR_ERR_NO_SUPPORT,
- "%s", _("unsupported in xendConfigVersion < 4"));
- return (-1);
- }
-
- /* look up the information by domain name */
- root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
- if (root == NULL)
- return (-1);
-
- /* get the scheduler type */
- sched_type = xenDaemonGetSchedulerType(domain, &sched_nparam);
- if (sched_type == NULL) {
- virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Failed to get a scheduler name"));
- goto error;
- }
-
- switch (sched_nparam){
- case XEN_SCHED_SEDF_NPARAM:
- /* TODO: Implement for Xen/SEDF */
- TODO
- goto error;
- case XEN_SCHED_CRED_NPARAM: {
- char buf_weight[VIR_UUID_BUFLEN];
- char buf_cap[VIR_UUID_BUFLEN];
- const char *weight = NULL;
- const char *cap = NULL;
-
- /* get the scheduler parameters */
- memset(&buf_weight, 0, VIR_UUID_BUFLEN);
- memset(&buf_cap, 0, VIR_UUID_BUFLEN);
- for (i = 0; i < nparams; i++) {
- if (STREQ (params[i].field, str_weight) &&
- params[i].type == VIR_DOMAIN_SCHED_FIELD_UINT) {
- snprintf(buf_weight, sizeof(buf_weight), "%u", params[i].value.ui);
- } else if (STREQ (params[i].field, str_cap) &&
- params[i].type == VIR_DOMAIN_SCHED_FIELD_UINT) {
- snprintf(buf_cap, sizeof(buf_cap), "%u", params[i].value.ui);
- } else {
- virXendError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- goto error;
- }
- }
-
- /* if not get the scheduler parameter, set the current setting */
- if (strlen(buf_weight) == 0) {
- weight = sexpr_node(root, "domain/cpu_weight");
- if (weight == NULL) {
- virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, missing cpu_weight"));
- goto error;
- }
- snprintf(buf_weight, sizeof(buf_weight), "%s", weight);
- }
- if (strlen(buf_cap) == 0) {
- cap = sexpr_node(root, "domain/cpu_cap");
- if (cap == NULL) {
- virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("domain information incomplete, missing cpu_cap"));
- goto error;
- }
- snprintf(buf_cap, sizeof(buf_cap), "%s", cap);
- }
-
- ret = xend_op(domain->conn, domain->name, "op",
- "domain_sched_credit_set", "weight", buf_weight,
- "cap", buf_cap, NULL);
- break;
- }
- default:
- virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
- goto error;
- }
-
-error:
- sexpr_free(root);
- VIR_FREE(sched_type);
- return (ret);
-}
-
-/**
- * xenDaemonDomainBlockPeek:
- * @dom: domain object
- * @path: path to the file or device
- * @offset: offset
- * @size: size
- * @buffer: return buffer
- *
- * Returns 0 if successful, -1 if error, -2 if declined.
- */
-int
-xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path,
- unsigned long long offset, size_t size,
- void *buffer)
-{
- xenUnifiedPrivatePtr priv;
- struct sexpr *root = NULL;
- int fd = -1, ret = -1;
- int found = 0, i;
- virDomainDefPtr def;
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
-
- if (domain->id < 0 && priv->xendConfigVersion < 3)
- return -2; /* Decline, allow XM to handle it. */
-
- /* Security check: The path must correspond to a block device. */
- if (domain->id > 0)
- root = sexpr_get (domain->conn, "/xend/domain/%d?detail=1",
- domain->id);
- else if (domain->id < 0)
- root = sexpr_get (domain->conn, "/xend/domain/%s?detail=1",
- domain->name);
- else {
- /* This call always fails for dom0. */
- virXendError (domain->conn, VIR_ERR_NO_SUPPORT,
- "%s", _("domainBlockPeek is not supported for dom0"));
- return -1;
- }
-
- if (!root) {
- virXendError (domain->conn, VIR_ERR_XEN_CALL, __FUNCTION__);
- return -1;
- }
-
- if (!(def = xenDaemonParseSxpr(domain->conn, root, priv->xendConfigVersion, NULL)))
- goto cleanup;
-
- for (i = 0 ; i < def->ndisks ; i++) {
- if (def->disks[i]->src &&
- STREQ(def->disks[i]->src, path)) {
- found = 1;
- break;
- }
- }
- if (!found) {
- virXendError (domain->conn, VIR_ERR_INVALID_ARG,
- _("%s: invalid path"), path);
- goto cleanup;
- }
-
- /* The path is correct, now try to open it and get its size. */
- fd = open (path, O_RDONLY);
- if (fd == -1) {
- virReportSystemError(domain->conn, errno,
- _("failed to open for reading: %s"),
- path);
- goto cleanup;
- }
-
- /* Seek and read. */
- /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
- * be 64 bits on all platforms.
- */
- if (lseek (fd, offset, SEEK_SET) == (off_t) -1 ||
- saferead (fd, buffer, size) == (ssize_t) -1) {
- virReportSystemError(domain->conn, errno,
- _("failed to lseek or read from file: %s"),
- path);
- goto cleanup;
- }
-
- ret = 0;
- cleanup:
- if (fd >= 0) close (fd);
- sexpr_free(root);
- virDomainDefFree(def);
- return ret;
-}
-
-struct xenUnifiedDriver xenDaemonDriver = {
- xenDaemonOpen, /* open */
- xenDaemonClose, /* close */
- xenDaemonGetVersion, /* version */
- NULL, /* hostname */
- xenDaemonNodeGetInfo, /* nodeGetInfo */
- NULL, /* getCapabilities */
- xenDaemonListDomains, /* listDomains */
- xenDaemonNumOfDomains, /* numOfDomains */
- xenDaemonCreateXML, /* domainCreateXML */
- xenDaemonDomainSuspend, /* domainSuspend */
- xenDaemonDomainResume, /* domainResume */
- xenDaemonDomainShutdown, /* domainShutdown */
- xenDaemonDomainReboot, /* domainReboot */
- xenDaemonDomainDestroy, /* domainDestroy */
- xenDaemonDomainGetOSType, /* domainGetOSType */
- xenDaemonDomainGetMaxMemory, /* domainGetMaxMemory */
- xenDaemonDomainSetMaxMemory, /* domainSetMaxMemory */
- xenDaemonDomainSetMemory, /* domainMaxMemory */
- xenDaemonDomainGetInfo, /* domainGetInfo */
- xenDaemonDomainSave, /* domainSave */
- xenDaemonDomainRestore, /* domainRestore */
- xenDaemonDomainCoreDump, /* domainCoreDump */
- xenDaemonDomainSetVcpus, /* domainSetVcpus */
- xenDaemonDomainPinVcpu, /* domainPinVcpu */
- xenDaemonDomainGetVcpus, /* domainGetVcpus */
- NULL, /* domainGetMaxVcpus */
- xenDaemonListDefinedDomains, /* listDefinedDomains */
- xenDaemonNumOfDefinedDomains,/* numOfDefinedDomains */
- xenDaemonDomainCreate, /* domainCreate */
- xenDaemonDomainDefineXML, /* domainDefineXML */
- xenDaemonDomainUndefine, /* domainUndefine */
- xenDaemonAttachDevice, /* domainAttachDevice */
- xenDaemonDetachDevice, /* domainDetachDevice */
- xenDaemonDomainGetAutostart, /* domainGetAutostart */
- xenDaemonDomainSetAutostart, /* domainSetAutostart */
- xenDaemonGetSchedulerType, /* domainGetSchedulerType */
- xenDaemonGetSchedulerParameters, /* domainGetSchedulerParameters */
- xenDaemonSetSchedulerParameters, /* domainSetSchedulerParameters */
-};
-
-/************************************************************************
- * *
- * Converter functions to go from the XML tree to an S-Expr for Xen *
- * *
- ************************************************************************/
-
-
-/**
- * virtDomainParseXMLGraphicsDescVFB:
- * @conn: pointer to the hypervisor connection
- * @node: node containing graphics description
- * @buf: a buffer for the result S-Expr
- *
- * 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
- * valid over time.
- *
- * Returns 0 in case of success, -1 in case of error
- */
-static int
-xenDaemonFormatSxprGraphicsNew(virConnectPtr conn,
- virDomainGraphicsDefPtr def,
- virBufferPtr buf)
-{
- if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_SDL &&
- def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unexpected graphics type %d"),
- def->type);
- return -1;
- }
-
- virBufferAddLit(buf, "(device (vkbd))");
- virBufferAddLit(buf, "(device (vfb ");
-
- if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
- virBufferAddLit(buf, "(type sdl)");
- if (def->data.sdl.display)
- virBufferVSprintf(buf, "(display '%s')", def->data.sdl.display);
- if (def->data.sdl.xauth)
- virBufferVSprintf(buf, "(xauthority '%s')", def->data.sdl.xauth);
- } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
- virBufferAddLit(buf, "(type vnc)");
- if (def->data.vnc.autoport) {
- virBufferAddLit(buf, "(vncunused 1)");
- } else {
- virBufferAddLit(buf, "(vncunused 0)");
- virBufferVSprintf(buf, "(vncdisplay %d)", def->data.vnc.port-5900);
- }
-
- if (def->data.vnc.listenAddr)
- virBufferVSprintf(buf, "(vnclisten '%s')", def->data.vnc.listenAddr);
- if (def->data.vnc.passwd)
- virBufferVSprintf(buf, "(vncpasswd '%s')", def->data.vnc.passwd);
- if (def->data.vnc.keymap)
- virBufferVSprintf(buf, "(keymap '%s')", def->data.vnc.keymap);
- }
-
- virBufferAddLit(buf, "))");
-
- return 0;
-}
-
-
-static int
-xenDaemonFormatSxprGraphicsOld(virConnectPtr conn,
- virDomainGraphicsDefPtr def,
- virBufferPtr buf,
- int xendConfigVersion)
-{
- if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_SDL &&
- def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unexpected graphics type %d"),
- def->type);
- return -1;
- }
-
- if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
- virBufferAddLit(buf, "(sdl 1)");
- if (def->data.sdl.display)
- virBufferVSprintf(buf, "(display '%s')", def->data.sdl.display);
- if (def->data.sdl.xauth)
- virBufferVSprintf(buf, "(xauthority '%s')", def->data.sdl.xauth);
- } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
- virBufferAddLit(buf, "(vnc 1)");
- if (xendConfigVersion >= 2) {
- if (def->data.vnc.autoport) {
- virBufferAddLit(buf, "(vncunused 1)");
- } else {
- virBufferAddLit(buf, "(vncunused 0)");
- virBufferVSprintf(buf, "(vncdisplay %d)", def->data.vnc.port-5900);
- }
-
- if (def->data.vnc.listenAddr)
- virBufferVSprintf(buf, "(vnclisten '%s')", def->data.vnc.listenAddr);
- if (def->data.vnc.passwd)
- virBufferVSprintf(buf, "(vncpasswd '%s')", def->data.vnc.passwd);
- if (def->data.vnc.keymap)
- virBufferVSprintf(buf, "(keymap '%s')", def->data.vnc.keymap);
-
- }
- }
-
- return 0;
-}
-
-int
-xenDaemonFormatSxprChr(virConnectPtr conn,
- virDomainChrDefPtr def,
- virBufferPtr buf)
-{
- const char *type = virDomainChrTypeToString(def->type);
-
- if (!type) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("unexpected chr device type"));
- return -1;
- }
-
- switch (def->type) {
- case VIR_DOMAIN_CHR_TYPE_NULL:
- case VIR_DOMAIN_CHR_TYPE_STDIO:
- case VIR_DOMAIN_CHR_TYPE_VC:
- case VIR_DOMAIN_CHR_TYPE_PTY:
- virBufferVSprintf(buf, "%s", type);
- break;
-
- case VIR_DOMAIN_CHR_TYPE_FILE:
- case VIR_DOMAIN_CHR_TYPE_PIPE:
- virBufferVSprintf(buf, "%s:%s", type, def->data.file.path);
- break;
-
- case VIR_DOMAIN_CHR_TYPE_DEV:
- virBufferVSprintf(buf, "%s", def->data.file.path);
- break;
-
- case VIR_DOMAIN_CHR_TYPE_TCP:
- virBufferVSprintf(buf, "%s:%s:%s%s",
- (def->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW ?
- "tcp" : "telnet"),
- (def->data.tcp.host ? def->data.tcp.host : ""),
- (def->data.tcp.service ? def->data.tcp.service : ""),
- (def->data.tcp.listen ? ",listen" : ""));
- break;
-
- case VIR_DOMAIN_CHR_TYPE_UDP:
- virBufferVSprintf(buf, "%s:%s:%s@%s:%s", type,
- (def->data.udp.connectHost ? def->data.udp.connectHost : ""),
- (def->data.udp.connectService ? def->data.udp.connectService : ""),
- (def->data.udp.bindHost ? def->data.udp.bindHost : ""),
- (def->data.udp.bindService ? def->data.udp.bindService : ""));
- break;
-
- case VIR_DOMAIN_CHR_TYPE_UNIX:
- virBufferVSprintf(buf, "%s:%s%s", type,
- def->data.nix.path,
- def->data.nix.listen ? ",listen" : "");
- break;
- }
-
- if (virBufferError(buf))
- return -1;
-
- return 0;
-}
-
-
-/**
- * virDomainParseXMLDiskDesc:
- * @node: node containing disk description
- * @conn: pointer to the hypervisor connection
- * @buf: a buffer for the result S-Expr
- * @xendConfigVersion: xend configuration file format
- *
- * 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
-xenDaemonFormatSxprDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
- virDomainDiskDefPtr def,
- virBufferPtr buf,
- int hvm,
- int xendConfigVersion,
- int isAttach)
-{
- /* Xend (all versions) put the floppy device config
- * under the hvm (image (os)) block
- */
- if (hvm &&
- def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
- if (isAttach) {
- virXendError(conn, VIR_ERR_INVALID_ARG,
- _("Cannot directly attach floppy %s"), def->src);
- return -1;
- }
- return 0;
- }
-
- /* Xend <= 3.0.2 doesn't include cdrom config here */
- if (hvm &&
- def->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
- xendConfigVersion == 1) {
- if (isAttach) {
- virXendError(conn, VIR_ERR_INVALID_ARG,
- _("Cannot directly attach CDROM %s"), def->src);
- return -1;
- }
- return 0;
- }
-
- if (!isAttach)
- virBufferAddLit(buf, "(device ");
-
- /* Normally disks are in a (device (vbd ...)) block
- * but blktap disks ended up in a differently named
- * (device (tap ....)) block.... */
- if (def->driverName &&
- STREQ(def->driverName, "tap")) {
- virBufferAddLit(buf, "(tap ");
- } else {
- virBufferAddLit(buf, "(vbd ");
- }
-
- if (hvm) {
- /* Xend <= 3.0.2 wants a ioemu: prefix on devices for HVM */
- if (xendConfigVersion == 1)
- virBufferVSprintf(buf, "(dev 'ioemu:%s')", def->dst);
- else /* But newer does not */
- virBufferVSprintf(buf, "(dev '%s:%s')", def->dst,
- def->device == VIR_DOMAIN_DISK_DEVICE_CDROM ?
- "cdrom" : "disk");
- } else if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
- virBufferVSprintf(buf, "(dev '%s:cdrom')", def->dst);
- } else {
- virBufferVSprintf(buf, "(dev '%s')", def->dst);
- }
-
- if (def->src) {
- if (def->driverName) {
- if (STREQ(def->driverName, "tap")) {
- virBufferVSprintf(buf, "(uname '%s:%s:%s')",
- def->driverName,
- def->driverType ? def->driverType : "aio",
- def->src);
- } else {
- virBufferVSprintf(buf, "(uname '%s:%s')",
- def->driverName,
- def->src);
- }
- } else {
- if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
- virBufferVSprintf(buf, "(uname 'file:%s')", def->src);
- } else {
- if (def->src[0] == '/')
- virBufferVSprintf(buf, "(uname 'phy:%s')", def->src);
- else
- virBufferVSprintf(buf, "(uname 'phy:/dev/%s')", def->src);
- }
- }
- }
-
- if (def->readonly)
- virBufferAddLit(buf, "(mode 'r')");
- else if (def->shared)
- virBufferAddLit(buf, "(mode 'w!')");
- else
- virBufferAddLit(buf, "(mode 'w')");
-
- if (!isAttach)
- virBufferAddLit(buf, ")");
-
- virBufferAddLit(buf, ")");
-
- return 0;
-}
-
-/**
- * xenDaemonFormatSxprNet
- * @conn: pointer to the hypervisor connection
- * @node: node containing the interface description
- * @buf: a buffer for the result S-Expr
- * @xendConfigVersion: xend configuration file format
- *
- * 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
-xenDaemonFormatSxprNet(virConnectPtr conn,
- virDomainNetDefPtr def,
- virBufferPtr buf,
- int hvm,
- int xendConfigVersion,
- int isAttach)
-{
- const char *script = DEFAULT_VIF_SCRIPT;
-
- if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
- def->type != VIR_DOMAIN_NET_TYPE_NETWORK &&
- def->type != VIR_DOMAIN_NET_TYPE_ETHERNET) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unsupported network type %d"), def->type);
- return -1;
- }
-
- if (!isAttach)
- virBufferAddLit(buf, "(device ");
-
- virBufferAddLit(buf, "(vif ");
-
- virBufferVSprintf(buf,
- "(mac '%02x:%02x:%02x:%02x:%02x:%02x')",
- def->mac[0], def->mac[1], def->mac[2],
- def->mac[3], def->mac[4], def->mac[5]);
-
- switch (def->type) {
- case VIR_DOMAIN_NET_TYPE_BRIDGE:
- virBufferVSprintf(buf, "(bridge '%s')", def->data.bridge.brname);
- if (def->data.bridge.script)
- script = def->data.bridge.script;
-
- virBufferVSprintf(buf, "(script '%s')", script);
- if (def->data.bridge.ipaddr != NULL)
- virBufferVSprintf(buf, "(ip '%s')", def->data.bridge.ipaddr);
- break;
-
- case VIR_DOMAIN_NET_TYPE_NETWORK:
- {
- virNetworkPtr network =
- virNetworkLookupByName(conn, def->data.network.name);
- char *bridge;
-
- if (!network) {
- virXendError(conn, VIR_ERR_NO_NETWORK, "%s",
- def->data.network.name);
- return -1;
- }
-
- bridge = virNetworkGetBridgeName(network);
- virNetworkFree(network);
- if (!bridge) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("network %s is not active"),
- def->data.network.name);
- return -1;
- }
- virBufferVSprintf(buf, "(bridge '%s')", bridge);
- virBufferVSprintf(buf, "(script '%s')", script);
- VIR_FREE(bridge);
- }
- break;
-
- case VIR_DOMAIN_NET_TYPE_ETHERNET:
- if (def->data.ethernet.script)
- virBufferVSprintf(buf, "(script '%s')", def->data.ethernet.script);
- if (def->data.ethernet.ipaddr != NULL)
- virBufferVSprintf(buf, "(ip '%s')", def->data.ethernet.ipaddr);
- break;
- }
-
- if (def->ifname != NULL &&
- !STRPREFIX(def->ifname, "vif"))
- virBufferVSprintf(buf, "(vifname '%s')", def->ifname);
-
- if (def->model != NULL)
- virBufferVSprintf(buf, "(model '%s')", def->model);
-
- /*
- * apparently (type ioemu) breaks paravirt drivers on HVM so skip this
- * from Xen 3.1.0
- */
- if (hvm && xendConfigVersion <= XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU)
- virBufferAddLit(buf, "(type ioemu)");
-
- if (!isAttach)
- virBufferAddLit(buf, ")");
-
- virBufferAddLit(buf, ")");
-
- return 0;
-}
-
-
-static void
-xenDaemonFormatSxprPCI(virDomainHostdevDefPtr def,
- virBufferPtr buf)
-{
- virBufferVSprintf(buf, "(dev (domain 0x%04x)(bus 0x%02x)(slot 0x%02x)(func 0x%x))",
- def->source.subsys.u.pci.domain,
- def->source.subsys.u.pci.bus,
- def->source.subsys.u.pci.slot,
- def->source.subsys.u.pci.function);
-}
-
-static int
-xenDaemonFormatSxprOnePCI(virConnectPtr conn,
- virDomainHostdevDefPtr def,
- virBufferPtr buf)
-{
- if (def->managed) {
- virXendError(conn, VIR_ERR_NO_SUPPORT, "%s",
- _("managed PCI devices not supported with XenD"));
- return -1;
- }
-
- virBufferAddLit(buf, "(pci ");
- xenDaemonFormatSxprPCI(def, buf);
- virBufferAddLit(buf, ")");
-
- return 0;
-}
-
-static int
-xenDaemonFormatSxprAllPCI(virConnectPtr conn,
- virDomainDefPtr def,
- virBufferPtr buf)
-{
- int hasPCI = 0;
- int i;
-
- for (i = 0 ; i < def->nhostdevs ; i++)
- if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
- def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
- hasPCI = 1;
-
- if (!hasPCI)
- return 0;
-
- /*
- * With the (domain ...) block we have the following odd setup
- *
- * (device
- * (pci
- * (dev (domain 0x0000) (bus 0x00) (slot 0x1b) (func 0x0))
- * (dev (domain 0x0000) (bus 0x00) (slot 0x13) (func 0x0))
- * )
- * )
- *
- * Normally there is one (device ...) block per device, but in
- * wierd world of Xen PCI, once (device ...) covers multiple
- * devices.
- */
-
- virBufferAddLit(buf, "(device (pci ");
- for (i = 0 ; i < def->nhostdevs ; i++) {
- if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
- def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
- if (def->hostdevs[i]->managed) {
- virXendError(conn, VIR_ERR_NO_SUPPORT, "%s",
- _("managed PCI devices not supported with XenD"));
- return -1;
- }
-
- xenDaemonFormatSxprPCI(def->hostdevs[i], buf);
- }
- }
- virBufferAddLit(buf, "))");
-
- return 0;
-}
-
-int
-xenDaemonFormatSxprSound(virConnectPtr conn,
- virDomainDefPtr def,
- virBufferPtr buf)
-{
- const char *str;
- int i;
-
- for (i = 0 ; i < def->nsounds ; i++) {
- if (!(str = virDomainSoundModelTypeToString(def->sounds[i]->model))) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unexpected sound model %d"),
- def->sounds[i]->model);
- return -1;
- }
- virBufferVSprintf(buf, "%s%s", i ? "," : "", str);
- }
-
- if (virBufferError(buf))
- return -1;
-
- return 0;
-}
-
-
-static int
-xenDaemonFormatSxprInput(virConnectPtr conn,
- virDomainInputDefPtr input,
- virBufferPtr buf)
-{
- if (input->bus != VIR_DOMAIN_INPUT_BUS_USB)
- return 0;
-
- if (input->type != VIR_DOMAIN_INPUT_TYPE_MOUSE &&
- input->type != VIR_DOMAIN_INPUT_TYPE_TABLET) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unexpected input type %d"), input->type);
- return -1;
- }
-
- virBufferVSprintf(buf, "(usbdevice %s)",
- input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
- "mouse" : "tablet");
-
- return 0;
-}
-
-
-/**
- * xenDaemonFormatSxpr:
- * @conn: pointer to the hypervisor connection
- * @def: domain config definition
- * @xendConfigVersion: xend configuration file format
- *
- * Generate an SEXPR representing the domain configuration.
- *
- * Returns the 0 terminatedi S-Expr string or NULL in case of error.
- * the caller must free() the returned value.
- */
-char *
-xenDaemonFormatSxpr(virConnectPtr conn,
- virDomainDefPtr def,
- int xendConfigVersion)
-{
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- char uuidstr[VIR_UUID_STRING_BUFLEN];
- const char *tmp;
- int hvm = 0, i;
-
- virBufferAddLit(&buf, "(vm ");
- virBufferVSprintf(&buf, "(name '%s')", def->name);
- virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)",
- def->memory/1024, def->maxmem/1024);
- virBufferVSprintf(&buf, "(vcpus %lu)", def->vcpus);
-
- if (def->cpumask) {
- char *ranges = virDomainCpuSetFormat(conn, def->cpumask, def->cpumasklen);
- if (ranges == NULL)
- goto error;
- virBufferVSprintf(&buf, "(cpus '%s')", ranges);
- VIR_FREE(ranges);
- }
-
- virUUIDFormat(def->uuid, uuidstr);
- virBufferVSprintf(&buf, "(uuid '%s')", uuidstr);
-
- if (def->os.bootloader) {
- if (def->os.bootloader[0])
- virBufferVSprintf(&buf, "(bootloader '%s')", def->os.bootloader);
- else
- virBufferAddLit(&buf, "(bootloader)");
-
- if (def->os.bootloaderArgs)
- virBufferVSprintf(&buf, "(bootloader_args '%s')", def->os.bootloaderArgs);
- }
-
- if (!(tmp = virDomainLifecycleTypeToString(def->onPoweroff))) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unexpected lifecycle value %d"), def->onPoweroff);
- goto error;
- }
- virBufferVSprintf(&buf, "(on_poweroff '%s')", tmp);
-
- if (!(tmp = virDomainLifecycleTypeToString(def->onReboot))) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unexpected lifecycle value %d"), def->onReboot);
- goto error;
- }
- virBufferVSprintf(&buf, "(on_reboot '%s')", tmp);
-
- if (!(tmp = virDomainLifecycleTypeToString(def->onCrash))) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unexpected lifecycle value %d"), def->onCrash);
- goto error;
- }
- virBufferVSprintf(&buf, "(on_crash '%s')", tmp);
-
- /* Set localtime here for current XenD (both PV & HVM) */
- if (def->localtime)
- virBufferAddLit(&buf, "(localtime 1)");
-
- if (!def->os.bootloader) {
- if (STREQ(def->os.type, "hvm"))
- hvm = 1;
-
- if (hvm)
- virBufferAddLit(&buf, "(image (hvm ");
- else
- virBufferAddLit(&buf, "(image (linux ");
-
- if (hvm &&
- def->os.loader == NULL) {
- virXendError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s",_("no HVM domain loader"));
- goto error;
- }
-
- if (def->os.kernel)
- virBufferVSprintf(&buf, "(kernel '%s')", def->os.kernel);
- if (def->os.initrd)
- virBufferVSprintf(&buf, "(ramdisk '%s')", def->os.initrd);
- if (def->os.root)
- virBufferVSprintf(&buf, "(root '%s')", def->os.root);
- if (def->os.cmdline)
- virBufferVSprintf(&buf, "(args '%s')", def->os.cmdline);
-
- if (hvm) {
- char bootorder[VIR_DOMAIN_BOOT_LAST+1];
- if (def->os.kernel)
- virBufferVSprintf(&buf, "(loader '%s')", def->os.loader);
- else
- virBufferVSprintf(&buf, "(kernel '%s')", def->os.loader);
-
- virBufferVSprintf(&buf, "(vcpus %lu)", def->vcpus);
-
- for (i = 0 ; i < def->os.nBootDevs ; i++) {
- switch (def->os.bootDevs[i]) {
- case VIR_DOMAIN_BOOT_FLOPPY:
- bootorder[i] = 'a';
- break;
- default:
- case VIR_DOMAIN_BOOT_DISK:
- bootorder[i] = 'c';
- break;
- case VIR_DOMAIN_BOOT_CDROM:
- bootorder[i] = 'd';
- break;
- case VIR_DOMAIN_BOOT_NET:
- bootorder[i] = 'n';
- break;
- }
- }
- if (def->os.nBootDevs == 0) {
- bootorder[0] = 'c';
- bootorder[1] = '\0';
- } else {
- bootorder[def->os.nBootDevs] = '\0';
- }
- virBufferVSprintf(&buf, "(boot %s)", bootorder);
-
- /* some disk devices are defined here */
- for (i = 0 ; i < def->ndisks ; i++) {
- switch (def->disks[i]->device) {
- case VIR_DOMAIN_DISK_DEVICE_CDROM:
- /* Only xend <= 3.0.2 wants cdrom config here */
- if (xendConfigVersion != 1)
- break;
- if (!STREQ(def->disks[i]->dst, "hdc") ||
- def->disks[i]->src == NULL)
- break;
-
- virBufferVSprintf(&buf, "(cdrom '%s')",
- def->disks[i]->src);
- break;
-
- case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
- /* all xend versions define floppies here */
- virBufferVSprintf(&buf, "(%s '%s')", def->disks[i]->dst,
- def->disks[i]->src);
- break;
-
- default:
- break;
- }
- }
-
- if (def->features & (1 << VIR_DOMAIN_FEATURE_ACPI))
- virBufferAddLit(&buf, "(acpi 1)");
- if (def->features & (1 << VIR_DOMAIN_FEATURE_APIC))
- virBufferAddLit(&buf, "(apic 1)");
- if (def->features & (1 << VIR_DOMAIN_FEATURE_PAE))
- virBufferAddLit(&buf, "(pae 1)");
-
- virBufferAddLit(&buf, "(usb 1)");
-
- for (i = 0 ; i < def->ninputs ; i++)
- if (xenDaemonFormatSxprInput(conn, def->inputs[i], &buf) < 0)
- goto error;
-
- if (def->parallels) {
- virBufferAddLit(&buf, "(parallel ");
- if (xenDaemonFormatSxprChr(conn, def->parallels[0], &buf) < 0)
- goto error;
- virBufferAddLit(&buf, ")");
- } else {
- virBufferAddLit(&buf, "(parallel none)");
- }
- if (def->serials) {
- virBufferAddLit(&buf, "(serial ");
- if (xenDaemonFormatSxprChr(conn, def->serials[0], &buf) < 0)
- goto error;
- virBufferAddLit(&buf, ")");
- } else {
- virBufferAddLit(&buf, "(serial none)");
- }
-
- /* Set localtime here to keep old XenD happy for HVM */
- if (def->localtime)
- virBufferAddLit(&buf, "(localtime 1)");
-
- if (def->sounds) {
- virBufferAddLit(&buf, "(soundhw '");
- if (xenDaemonFormatSxprSound(conn, def, &buf) < 0)
- goto error;
- virBufferAddLit(&buf, "')");
- }
- }
-
- /* get the device emulation model */
- if (def->emulator && (hvm || xendConfigVersion >= 3))
- virBufferVSprintf(&buf, "(device_model '%s')", def->emulator);
-
-
- /* PV graphics for xen <= 3.0.4, or HVM graphics for xen <= 3.1.0 */
- if ((!hvm && xendConfigVersion < XEND_CONFIG_MIN_VERS_PVFB_NEWCONF) ||
- (hvm && xendConfigVersion < 4)) {
- if ((def->ngraphics == 1) &&
- xenDaemonFormatSxprGraphicsOld(conn, def->graphics[0],
- &buf, xendConfigVersion) < 0)
- goto error;
- }
-
- virBufferAddLit(&buf, "))");
- }
-
- for (i = 0 ; i < def->ndisks ; i++)
- if (xenDaemonFormatSxprDisk(conn, def->disks[i],
- &buf, hvm, xendConfigVersion, 0) < 0)
- goto error;
-
- for (i = 0 ; i < def->nnets ; i++)
- if (xenDaemonFormatSxprNet(conn, def->nets[i],
- &buf, hvm, xendConfigVersion, 0) < 0)
- goto error;
-
- if (xenDaemonFormatSxprAllPCI(conn, def, &buf) < 0)
- goto error;
-
- /* New style PV graphics config xen >= 3.0.4,
- * or HVM graphics config xen >= 3.0.5 */
- if ((xendConfigVersion >= XEND_CONFIG_MIN_VERS_PVFB_NEWCONF && !hvm) ||
- (xendConfigVersion >= 4 && hvm)) {
- if ((def->ngraphics == 1) &&
- xenDaemonFormatSxprGraphicsNew(conn, def->graphics[0], &buf) < 0)
- goto error;
- }
-
- virBufferAddLit(&buf, ")"); /* closes (vm */
-
- if (virBufferError(&buf)) {
- virReportOOMError(conn);
- return NULL;
- }
-
- return virBufferContentAndReset(&buf);
-
-error:
- tmp = virBufferContentAndReset(&buf);
- VIR_FREE(tmp);
- return NULL;
-}
-
-
-/**
- * virDomainXMLDevID:
- * @domain: pointer to domain object
- * @dev: pointer to device config object
- * @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.
- */
-static int
-virDomainXMLDevID(virDomainPtr domain,
- virDomainDeviceDefPtr dev,
- char *class,
- char *ref,
- int ref_len)
-{
- xenUnifiedPrivatePtr priv = domain->conn->privateData;
- char *xref;
-
- if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
- if (dev->data.disk->driverName &&
- STREQ(dev->data.disk->driverName, "tap"))
- strcpy(class, "tap");
- else
- strcpy(class, "vbd");
-
- if (dev->data.disk->dst == NULL)
- return -1;
- xenUnifiedLock(priv);
- xref = xenStoreDomainGetDiskID(domain->conn, domain->id,
- dev->data.disk->dst);
- xenUnifiedUnlock(priv);
- if (xref == NULL)
- return -1;
-
- strncpy(ref, xref, ref_len);
- free(xref);
- ref[ref_len - 1] = '\0';
- } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
- char mac[30];
- virDomainNetDefPtr def = dev->data.net;
- snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
- def->mac[0], def->mac[1], def->mac[2],
- def->mac[3], def->mac[4], def->mac[5]);
-
- strcpy(class, "vif");
-
- xenUnifiedLock(priv);
- xref = xenStoreDomainGetNetworkID(domain->conn, domain->id,
- mac);
- xenUnifiedUnlock(priv);
- if (xref == NULL)
- return -1;
-
- strncpy(ref, xref, ref_len);
- free(xref);
- ref[ref_len - 1] = '\0';
- } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
- dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
- dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
- } else {
- virXendError(NULL, VIR_ERR_NO_SUPPORT,
- "%s", _("hotplug of device type not supported"));
- return -1;
- }
-
- return 0;
-}
-
-#endif /* ! PROXY */
+++ /dev/null
-/*
- * xend_internal.h
- *
- * Copyright (C) 2005,2006
- *
- * Anthony Liguori <aliguori@us.ibm.com>
- * Daniel Veillard <veillard@redhat.com>
- *
- * Copyright 2006-2008 Red Hat
- *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#ifndef __XEND_INTERNAL_H_
-#define __XEND_INTERNAL_H_
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <libxml/uri.h>
-
-#include "internal.h"
-#include "capabilities.h"
-#include "domain_conf.h"
-#include "driver.h"
-#include "buf.h"
-
-#ifdef __sun
-#define DEFAULT_VIF_SCRIPT "vif-vnic"
-#else
-#define DEFAULT_VIF_SCRIPT "vif-bridge"
-#endif
-
-int
-xenDaemonOpen_unix(virConnectPtr conn, const char *path);
-
-/**
- * \brief Blocks until a domain's devices are initialized
- * \param xend A xend instance
- * \param name The domain's name
- * \return 0 for success; -1 (with errno) on error
- *
- * xen_create() returns after a domain has been allocated including
- * its memory. This does not guarentee, though, that the devices
- * have come up properly. For instance, if you create a VBD with an
- * invalid filename, the error won't occur until after this function
- * returns.
- */
- int xend_wait_for_devices(virConnectPtr xend, const char *name);
-
-
-/**
- * \brief Create a new domain
- * \param xend A xend instance
- * \param sexpr An S-Expr defining the domain
- * \return 0 for success; -1 (with errno) on error
- *
- * This method will create a domain based the passed in description. The
- * domain will be paused after creation and must be unpaused with
- * xenDaemonResumeDomain() to begin execution.
- */
-int xenDaemonDomainCreateXML(virConnectPtr xend, const char *sexpr);
-
-/**
- * \brief Lookup the id of a domain
- * \param xend A xend instance
- * \param name The name of the domain
- * \param uuid pointer to store a copy of the uuid
- * \return the id number on success; -1 (with errno) on error
- *
- * This method looks up the ids of a domain
- */
-int xenDaemonDomainLookupByName_ids(virConnectPtr xend,
- const char *name, unsigned char *uuid);
-
-
-/**
- * \brief Lookup the name of a domain
- * \param xend A xend instance
- * \param id The id of the domain
- * \param name pointer to store a copy of the name
- * \param uuid pointer to store a copy of the uuid
- *
- * This method looks up the name/uuid of a domain
- */
-int xenDaemonDomainLookupByID(virConnectPtr xend,
- int id,
- char **name, unsigned char *uuid);
-
-
-virDomainDefPtr
-xenDaemonDomainFetch(virConnectPtr xend,
- int domid,
- const char *name,
- const char *cpus);
-
- int xend_parse_sexp_desc_char(virConnectPtr conn,
- virBufferPtr buf,
- const char *devtype,
- int portNum,
- const char *value,
- const char *tty);
-
-virDomainDefPtr
-xenDaemonParseSxprString(virConnectPtr conn,
- const char *sexpr,
- int xendConfigVersion);
-
-int
-xenDaemonParseSxprSound(virConnectPtr conn,
- virDomainDefPtr def,
- const char *str);
-virDomainChrDefPtr
-xenDaemonParseSxprChar(virConnectPtr conn,
- const char *value,
- const char *tty);
-
-int
-xenDaemonFormatSxprChr(virConnectPtr conn,
- virDomainChrDefPtr def,
- virBufferPtr buf);
-int
-xenDaemonFormatSxprSound(virConnectPtr conn,
- virDomainDefPtr def,
- virBufferPtr buf);
-
-char *
-xenDaemonFormatSxpr(virConnectPtr conn,
- virDomainDefPtr def,
- int xendConfigVersion);
-
- int is_sound_model_valid(const char *model);
- int is_sound_model_conflict(const char *model, const char *soundstr);
-
-
-/* refactored ones */
-virDrvOpenStatus xenDaemonOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags);
-int xenDaemonClose(virConnectPtr conn);
-int xenDaemonGetVersion(virConnectPtr conn, unsigned long *hvVer);
-int xenDaemonNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info);
-int xenDaemonNodeGetTopology(virConnectPtr conn, virCapsPtr caps);
-int xenDaemonDomainSuspend(virDomainPtr domain);
-int xenDaemonDomainResume(virDomainPtr domain);
-int xenDaemonDomainShutdown(virDomainPtr domain);
-int xenDaemonDomainReboot(virDomainPtr domain, unsigned int flags);
-int xenDaemonDomainDestroy(virDomainPtr domain);
-int xenDaemonDomainSave(virDomainPtr domain, const char *filename);
-int xenDaemonDomainRestore(virConnectPtr conn, const char *filename);
-int xenDaemonDomainSetMemory(virDomainPtr domain, unsigned long memory);
-int xenDaemonDomainSetMaxMemory(virDomainPtr domain, unsigned long memory);
-int xenDaemonDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info);
-char *xenDaemonDomainDumpXML(virDomainPtr domain, int flags, const char *cpus);
-unsigned long xenDaemonDomainGetMaxMemory(virDomainPtr domain);
-char **xenDaemonListDomainsOld(virConnectPtr xend);
-
-virDomainPtr xenDaemonDomainDefineXML(virConnectPtr xend, const char *sexpr);
-int xenDaemonDomainCreate(virDomainPtr domain);
-int xenDaemonDomainUndefine(virDomainPtr domain);
-
-int xenDaemonDomainSetVcpus (virDomainPtr domain,
- unsigned int vcpus);
-int xenDaemonDomainPinVcpu (virDomainPtr domain,
- unsigned int vcpu,
- unsigned char *cpumap,
- int maplen);
-int xenDaemonDomainGetVcpus (virDomainPtr domain,
- virVcpuInfoPtr info,
- int maxinfo,
- unsigned char *cpumaps,
- int maplen);
-int xenDaemonDomainGetAutostart (virDomainPtr dom,
- int *autostart);
-int xenDaemonDomainSetAutostart (virDomainPtr domain,
- int autostart);
-
-/* xen_unified calls through here. */
-extern struct xenUnifiedDriver xenDaemonDriver;
-int xenDaemonInit (void);
-
-virDomainPtr xenDaemonLookupByID(virConnectPtr conn, int id);
-virDomainPtr xenDaemonLookupByUUID(virConnectPtr conn, const unsigned char *uuid);
-virDomainPtr xenDaemonLookupByName(virConnectPtr conn, const char *domname);
-int xenDaemonDomainMigratePrepare (virConnectPtr dconn, char **cookie, int *cookielen, const char *uri_in, char **uri_out, unsigned long flags, const char *dname, unsigned long resource);
-int xenDaemonDomainMigratePerform (virDomainPtr domain, const char *cookie, int cookielen, const char *uri, unsigned long flags, const char *dname, unsigned long resource);
-
-int xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path, unsigned long long offset, size_t size, void *buffer);
-int xenDaemonListDomains(virConnectPtr conn, int *ids, int maxids);
-
-#endif /* __XEND_INTERNAL_H_ */
+++ /dev/null
-/*
- * xm_internal.h: helper routines for dealing with inactive domains
- *
- * Copyright (C) 2006-2007, 2009 Red Hat
- * Copyright (C) 2006 Daniel P. Berrange
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Daniel P. Berrange <berrange@redhat.com>
- *
- */
-
-#include <config.h>
-
-#include <dirent.h>
-#include <time.h>
-#include <sys/stat.h>
-#include <limits.h>
-#include <string.h>
-#include <errno.h>
-
-#include <unistd.h>
-#include <stdint.h>
-#include <xen/dom0_ops.h>
-
-#include "virterror_internal.h"
-#include "datatypes.h"
-#include "xm_internal.h"
-#include "xen_unified.h"
-#include "xend_internal.h"
-#include "hash.h"
-#include "buf.h"
-#include "uuid.h"
-#include "util.h"
-#include "memory.h"
-#include "logging.h"
-
-#define VIR_FROM_THIS VIR_FROM_XENXM
-
-#ifdef WITH_RHEL5_API
-#define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 0
-#define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 2
-#else
-#define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 3
-#define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 3
-#endif
-
-/* The true Xen limit varies but so far is always way
- less than 1024, which is the Linux kernel limit according
- to sched.h, so we'll match that for now */
-#define XEN_MAX_PHYSICAL_CPU 1024
-
-static int xenXMConfigSetString(virConfPtr conf, const char *setting,
- const char *str);
-char * xenXMAutoAssignMac(void);
-static int xenXMDomainAttachDevice(virDomainPtr domain, const char *xml);
-static int xenXMDomainDetachDevice(virDomainPtr domain, const char *xml);
-
-#define XM_REFRESH_INTERVAL 10
-
-#define XM_CONFIG_DIR "/etc/xen"
-#define XM_EXAMPLE_PREFIX "xmexample"
-#define XEND_CONFIG_FILE "xend-config.sxp"
-#define XEND_PCI_CONFIG_PREFIX "xend-pci-"
-#define QEMU_IF_SCRIPT "qemu-ifup"
-#define XM_XML_ERROR "Invalid xml"
-
-struct xenUnifiedDriver xenXMDriver = {
- xenXMOpen, /* open */
- xenXMClose, /* close */
- NULL, /* version */
- NULL, /* hostname */
- NULL, /* nodeGetInfo */
- NULL, /* getCapabilities */
- NULL, /* listDomains */
- NULL, /* numOfDomains */
- NULL, /* domainCreateXML */
- NULL, /* domainSuspend */
- NULL, /* domainResume */
- NULL, /* domainShutdown */
- NULL, /* domainReboot */
- NULL, /* domainDestroy */
- NULL, /* domainGetOSType */
- xenXMDomainGetMaxMemory, /* domainGetMaxMemory */
- xenXMDomainSetMaxMemory, /* domainSetMaxMemory */
- xenXMDomainSetMemory, /* domainMaxMemory */
- xenXMDomainGetInfo, /* domainGetInfo */
- NULL, /* domainSave */
- NULL, /* domainRestore */
- NULL, /* domainCoreDump */
- xenXMDomainSetVcpus, /* domainSetVcpus */
- xenXMDomainPinVcpu, /* domainPinVcpu */
- NULL, /* domainGetVcpus */
- NULL, /* domainGetMaxVcpus */
- xenXMListDefinedDomains, /* listDefinedDomains */
- xenXMNumOfDefinedDomains, /* numOfDefinedDomains */
- xenXMDomainCreate, /* domainCreate */
- xenXMDomainDefineXML, /* domainDefineXML */
- xenXMDomainUndefine, /* domainUndefine */
- xenXMDomainAttachDevice, /* domainAttachDevice */
- xenXMDomainDetachDevice, /* domainDetachDevice */
- NULL, /* domainGetAutostart */
- NULL, /* domainSetAutostart */
- NULL, /* domainGetSchedulerType */
- NULL, /* domainGetSchedulerParameters */
- NULL, /* domainSetSchedulerParameters */
-};
-
-#define xenXMError(conn, code, fmt...) \
- virReportErrorHelper(conn, VIR_FROM_XENXM, code, __FILE__, \
- __FUNCTION__, __LINE__, fmt)
-
-#ifndef WITH_XEN_INOTIFY
-static int xenInotifyActive(virConnectPtr conn ATTRIBUTE_UNUSED)
-{
- return 0;
-}
-#else
-static int xenInotifyActive(virConnectPtr conn)
-{
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
- return priv->inotifyWatch > 0;
-}
-#endif
-
-/* Convenience method to grab a int from the config file object */
-static int xenXMConfigGetBool(virConnectPtr conn,
- virConfPtr conf,
- const char *name,
- int *value,
- int def) {
- virConfValuePtr val;
-
- *value = 0;
- if (!(val = virConfGetValue(conf, name))) {
- *value = def;
- return 0;
- }
-
- if (val->type == VIR_CONF_LONG) {
- *value = val->l ? 1 : 0;
- } else if (val->type == VIR_CONF_STRING) {
- if (!val->str) {
- *value = def;
- }
- *value = STREQ(val->str, "1") ? 1 : 0;
- } else {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("config value %s was malformed"), name);
- return -1;
- }
- return 0;
-}
-
-
-/* Convenience method to grab a int from the config file object */
-static int xenXMConfigGetULong(virConnectPtr conn,
- virConfPtr conf,
- const char *name,
- unsigned long *value,
- int def) {
- virConfValuePtr val;
-
- *value = 0;
- if (!(val = virConfGetValue(conf, name))) {
- *value = def;
- return 0;
- }
-
- if (val->type == VIR_CONF_LONG) {
- *value = val->l;
- } else if (val->type == VIR_CONF_STRING) {
- char *ret;
- if (!val->str) {
- *value = def;
- }
- *value = strtol(val->str, &ret, 10);
- if (ret == val->str) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("config value %s was malformed"), name);
- return -1;
- }
- } else {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("config value %s was malformed"), name);
- return -1;
- }
- return 0;
-}
-
-
-/* Convenience method to grab a string from the config file object */
-static int xenXMConfigGetString(virConnectPtr conn,
- virConfPtr conf,
- const char *name,
- const char **value,
- const char *def) {
- virConfValuePtr val;
-
- *value = NULL;
- if (!(val = virConfGetValue(conf, name))) {
- *value = def;
- return 0;
- }
-
- if (val->type != VIR_CONF_STRING) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("config value %s was malformed"), name);
- return -1;
- }
- if (!val->str)
- *value = def;
- else
- *value = val->str;
- return 0;
-}
-
-static int xenXMConfigCopyStringInternal(virConnectPtr conn,
- virConfPtr conf,
- const char *name,
- char **value,
- int allowMissing) {
- virConfValuePtr val;
-
- *value = NULL;
- if (!(val = virConfGetValue(conf, name))) {
- if (allowMissing)
- return 0;
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("config value %s was missing"), name);
- return -1;
- }
-
- if (val->type != VIR_CONF_STRING) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("config value %s was not a string"), name);
- return -1;
- }
- if (!val->str) {
- if (allowMissing)
- return 0;
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("config value %s was missing"), name);
- return -1;
- }
-
- if (!(*value = strdup(val->str))) {
- virReportOOMError(conn);
- return -1;
- }
-
- return 0;
-}
-
-
-static int xenXMConfigCopyString(virConnectPtr conn,
- virConfPtr conf,
- const char *name,
- char **value) {
- return xenXMConfigCopyStringInternal(conn, conf, name, value, 0);
-}
-
-static int xenXMConfigCopyStringOpt(virConnectPtr conn,
- virConfPtr conf,
- const char *name,
- char **value) {
- return xenXMConfigCopyStringInternal(conn, conf, name, value, 1);
-}
-
-
-/* Convenience method to grab a string UUID from the config file object */
-static int xenXMConfigGetUUID(virConfPtr conf, const char *name, unsigned char *uuid) {
- virConfValuePtr val;
- if (!uuid || !name || !conf)
- return (-1);
- if (!(val = virConfGetValue(conf, name))) {
- return (-1);
- }
-
- if (val->type != VIR_CONF_STRING)
- return (-1);
- if (!val->str)
- return (-1);
-
- if (virUUIDParse(val->str, uuid) < 0)
- return (-1);
-
- return (0);
-}
-
-
-/* Release memory associated with a cached config object */
-static void xenXMConfigFree(void *payload, const char *key ATTRIBUTE_UNUSED) {
- xenXMConfCachePtr entry = (xenXMConfCachePtr)payload;
- virDomainDefFree(entry->def);
- VIR_FREE(entry);
-}
-
-struct xenXMConfigReaperData {
- xenUnifiedPrivatePtr priv;
- time_t now;
-};
-
-/* Remove any configs which were not refreshed recently */
-static int xenXMConfigReaper(const void *payload, const char *key ATTRIBUTE_UNUSED, const void *data) {
- const struct xenXMConfigReaperData *args = data;
- xenXMConfCachePtr entry = (xenXMConfCachePtr)payload;
-
- /* We're going to purge this config file, so check if it
- is currently mapped as owner of a named domain. */
- if (entry->refreshedAt != args->now) {
- const char *olddomname = entry->def->name;
- char *nameowner = (char *)virHashLookup(args->priv->nameConfigMap, olddomname);
- if (nameowner && STREQ(nameowner, key)) {
- virHashRemoveEntry(args->priv->nameConfigMap, olddomname, NULL);
- }
- return (1);
- }
- return (0);
-}
-
-
-static virDomainDefPtr
-xenXMConfigReadFile(virConnectPtr conn, const char *filename) {
- virConfPtr conf;
- virDomainDefPtr def;
-
- if (!(conf = virConfReadFile(filename, 0)))
- return NULL;
-
- def = xenXMDomainConfigParse(conn, conf);
- virConfFree(conf);
-
- return def;
-}
-
-static int
-xenXMConfigSaveFile(virConnectPtr conn, const char *filename, virDomainDefPtr def) {
- virConfPtr conf;
- int ret;
-
- if (!(conf = xenXMDomainConfigFormat(conn, def)))
- return -1;
-
- ret = virConfWriteFile(filename, conf);
- virConfFree(conf);
- return ret;
-}
-
-
-/*
- * Caller must hold the lock on 'conn->privateData' before
- * calling this funtion
- */
-int
-xenXMConfigCacheRemoveFile(virConnectPtr conn,
- const char *filename)
-{
- xenUnifiedPrivatePtr priv = conn->privateData;
- xenXMConfCachePtr entry;
-
- entry = virHashLookup(priv->configCache, filename);
- if (!entry) {
- DEBUG("No config entry for %s", filename);
- return 0;
- }
-
- virHashRemoveEntry(priv->nameConfigMap, entry->def->name, NULL);
- virHashRemoveEntry(priv->configCache, filename, xenXMConfigFree);
- DEBUG("Removed %s %s", entry->def->name, filename);
- return 0;
-}
-
-
-/*
- * Caller must hold the lock on 'conn->privateData' before
- * calling this funtion
- */
-int
-xenXMConfigCacheAddFile(virConnectPtr conn, const char *filename)
-{
- xenUnifiedPrivatePtr priv = conn->privateData;
- xenXMConfCachePtr entry;
- struct stat st;
- int newborn = 0;
- time_t now = time(NULL);
-
- DEBUG("Adding file %s", filename);
-
- /* Get modified time */
- if ((stat(filename, &st) < 0)) {
- virReportSystemError(conn, errno,
- _("cannot stat: %s"),
- filename);
- return -1;
- }
-
- /* Ignore zero length files, because inotify fires before
- any content has actually been created */
- if (st.st_size == 0) {
- DEBUG("Ignoring zero length file %s", filename);
- return -1;
- }
-
- /* If we already have a matching entry and it is not
- modified, then carry on to next one*/
- if ((entry = virHashLookup(priv->configCache, filename))) {
- char *nameowner;
-
- if (entry->refreshedAt >= st.st_mtime) {
- entry->refreshedAt = now;
- /* return success if up-to-date */
- return 0;
- }
-
- /* If we currently own the name, then release it and
- re-acquire it later - just in case it was renamed */
- nameowner = (char *)virHashLookup(priv->nameConfigMap, entry->def->name);
- if (nameowner && STREQ(nameowner, filename)) {
- virHashRemoveEntry(priv->nameConfigMap, entry->def->name, NULL);
- }
-
- /* Clear existing config entry which needs refresh */
- virDomainDefFree(entry->def);
- entry->def = NULL;
- } else { /* Completely new entry */
- newborn = 1;
- if (VIR_ALLOC(entry) < 0) {
- virReportOOMError(conn);
- return -1;
- }
- memcpy(entry->filename, filename, PATH_MAX);
- }
- entry->refreshedAt = now;
-
- if (!(entry->def = xenXMConfigReadFile(conn, entry->filename))) {
- DEBUG("Failed to read %s", entry->filename);
- if (!newborn)
- virHashRemoveEntry(priv->configCache, filename, NULL);
- VIR_FREE(entry);
- return -1;
- }
-
- /* If its a completely new entry, it must be stuck into
- the cache (refresh'd entries are already registered) */
- if (newborn) {
- if (virHashAddEntry(priv->configCache, entry->filename, entry) < 0) {
- virDomainDefFree(entry->def);
- VIR_FREE(entry);
- xenXMError (conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("xenXMConfigCacheRefresh: virHashAddEntry"));
- return -1;
- }
- }
-
- /* See if we need to map this config file in as the primary owner
- * of the domain in question
- */
- if (!virHashLookup(priv->nameConfigMap, entry->def->name)) {
- if (virHashAddEntry(priv->nameConfigMap, entry->def->name, entry->filename) < 0) {
- virHashRemoveEntry(priv->configCache, filename, NULL);
- virDomainDefFree(entry->def);
- VIR_FREE(entry);
- }
- }
- DEBUG("Added config %s %s", entry->def->name, filename);
-
- return 0;
-}
-
-/* This method is called by various methods to scan /etc/xen
- * (or whatever directory was set by LIBVIRT_XM_CONFIG_DIR
- * environment variable) and process any domain configs. It
- * has rate-limited so never rescans more frequently than
- * once every X seconds
- *
- * Caller must hold the lock on 'conn->privateData' before
- * calling this funtion
- */
-int xenXMConfigCacheRefresh (virConnectPtr conn) {
- xenUnifiedPrivatePtr priv = conn->privateData;
- DIR *dh;
- struct dirent *ent;
- time_t now = time(NULL);
- int ret = -1;
- struct xenXMConfigReaperData args;
-
- if (now == ((time_t)-1)) {
- virReportSystemError(conn, errno,
- "%s", _("cannot get time of day"));
- return (-1);
- }
-
- /* Rate limit re-scans */
- if ((now - priv->lastRefresh) < XM_REFRESH_INTERVAL)
- return (0);
-
- priv->lastRefresh = now;
-
- /* Process the files in the config dir */
- if (!(dh = opendir(priv->configDir))) {
- virReportSystemError(conn, errno,
- _("cannot read directory %s"),
- priv->configDir);
- return (-1);
- }
-
- while ((ent = readdir(dh))) {
- struct stat st;
- char path[PATH_MAX];
-
- /*
- * Skip a bunch of crufty files that clearly aren't config files
- */
-
- /* Like 'dot' files... */
- if (STRPREFIX(ent->d_name, "."))
- continue;
- /* ...and the XenD server config file */
- if (STRPREFIX(ent->d_name, XEND_CONFIG_FILE))
- continue;
- /* ...and random PCI config cruft */
- if (STRPREFIX(ent->d_name, XEND_PCI_CONFIG_PREFIX))
- continue;
- /* ...and the example domain configs */
- if (STRPREFIX(ent->d_name, XM_EXAMPLE_PREFIX))
- continue;
- /* ...and the QEMU networking script */
- if (STRPREFIX(ent->d_name, QEMU_IF_SCRIPT))
- continue;
-
- /* ...and editor backups */
- if (ent->d_name[0] == '#')
- continue;
- if (ent->d_name[strlen(ent->d_name)-1] == '~')
- continue;
-
- /* Build the full file path */
- if ((strlen(priv->configDir) + 1 + strlen(ent->d_name) + 1) > PATH_MAX)
- continue;
- strcpy(path, priv->configDir);
- strcat(path, "/");
- strcat(path, ent->d_name);
-
- /* Skip anything which isn't a file (takes care of scripts/ subdir */
- if ((stat(path, &st) < 0) ||
- (!S_ISREG(st.st_mode))) {
- continue;
- }
-
- /* If we already have a matching entry and it is not
- modified, then carry on to next one*/
- if (xenXMConfigCacheAddFile(conn, path) < 0) {
- /* Ignoring errors, since alot of stuff goes wrong in /etc/xen */
- }
- }
-
- /* Reap all entries which were not changed, by comparing
- their refresh timestamp - the timestamp should match
- 'now' if they were refreshed. If timestamp doesn't match
- then the config is no longer on disk */
- args.now = now;
- args.priv = priv;
- virHashRemoveSet(priv->configCache, xenXMConfigReaper, xenXMConfigFree, &args);
- ret = 0;
-
- if (dh)
- closedir(dh);
-
- return (ret);
-}
-
-
-/*
- * The XM driver keeps a cache of config files as virDomainDefPtr
- * objects in the xenUnifiedPrivatePtr. Optionally inotify lets
- * us watch for changes (see separate driver), otherwise we poll
- * every few seconds
- */
-virDrvOpenStatus
-xenXMOpen (virConnectPtr conn,
- virConnectAuthPtr auth ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED)
-{
- xenUnifiedPrivatePtr priv = conn->privateData;
-
- priv->configDir = XM_CONFIG_DIR;
-
- priv->configCache = virHashCreate(50);
- if (!priv->configCache)
- return (-1);
- priv->nameConfigMap = virHashCreate(50);
- if (!priv->nameConfigMap) {
- virHashFree(priv->configCache, NULL);
- priv->configCache = NULL;
- return (-1);
- }
- /* Force the cache to be reloaded next time that
- * xenXMConfigCacheRefresh is called.
- */
- priv->lastRefresh = 0;
-
- return (0);
-}
-
-/*
- * Free the cached config files associated with this
- * connection
- */
-int xenXMClose(virConnectPtr conn) {
- xenUnifiedPrivatePtr priv = conn->privateData;
-
- virHashFree(priv->nameConfigMap, NULL);
- virHashFree(priv->configCache, xenXMConfigFree);
-
- return (0);
-}
-
-/*
- * Since these are all offline domains, we only return info about
- * VCPUs and memory.
- */
-int xenXMDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) {
- xenUnifiedPrivatePtr priv;
- const char *filename;
- xenXMConfCachePtr entry;
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- if (domain->id != -1)
- return (-1);
-
- priv = domain->conn->privateData;
- xenUnifiedLock(priv);
-
- if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
- goto error;
-
- if (!(entry = virHashLookup(priv->configCache, filename)))
- goto error;
-
- memset(info, 0, sizeof(virDomainInfo));
- info->maxMem = entry->def->maxmem;
- info->memory = entry->def->memory;
- info->nrVirtCpu = entry->def->vcpus;
- info->state = VIR_DOMAIN_SHUTOFF;
- info->cpuTime = 0;
-
- xenUnifiedUnlock(priv);
- return (0);
-
-error:
- xenUnifiedUnlock(priv);
- return -1;
-}
-
-#define MAX_VFB 1024
-/*
- * Turn a config record into a lump of XML describing the
- * domain, suitable for later feeding for virDomainCreateXML
- */
-virDomainDefPtr
-xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
- const char *str;
- int hvm = 0;
- int val;
- virConfValuePtr list;
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
- virDomainDefPtr def = NULL;
- virDomainDiskDefPtr disk = NULL;
- virDomainNetDefPtr net = NULL;
- virDomainGraphicsDefPtr graphics = NULL;
- virDomainHostdevDefPtr hostdev = NULL;
- int i;
- const char *defaultArch, *defaultMachine;
-
- if (VIR_ALLOC(def) < 0)
- return NULL;
-
- def->virtType = VIR_DOMAIN_VIRT_XEN;
- def->id = -1;
-
- if (xenXMConfigCopyString(conn, conf, "name", &def->name) < 0)
- goto cleanup;
- if (xenXMConfigGetUUID(conf, "uuid", def->uuid) < 0)
- goto cleanup;
-
-
- if ((xenXMConfigGetString(conn, conf, "builder", &str, "linux") == 0) &&
- STREQ(str, "hvm"))
- hvm = 1;
-
- if (!(def->os.type = strdup(hvm ? "hvm" : "xen")))
- goto no_memory;
-
- defaultArch = virCapabilitiesDefaultGuestArch(priv->caps, def->os.type, virDomainVirtTypeToString(def->virtType));
- if (defaultArch == NULL) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("no supported architecture for os type '%s'"),
- def->os.type);
- goto cleanup;
- }
- if (!(def->os.arch = strdup(defaultArch)))
- goto no_memory;
-
- defaultMachine = virCapabilitiesDefaultGuestMachine(priv->caps,
- def->os.type,
- def->os.arch);
- if (defaultMachine != NULL) {
- if (!(def->os.machine = strdup(defaultMachine)))
- goto no_memory;
- }
-
- if (hvm) {
- const char *boot;
- if (xenXMConfigCopyString(conn, conf, "kernel", &def->os.loader) < 0)
- goto cleanup;
-
- if (xenXMConfigGetString(conn, conf, "boot", &boot, "c") < 0)
- goto cleanup;
-
- for (i = 0 ; i < VIR_DOMAIN_BOOT_LAST && boot[i] ; i++) {
- switch (*boot) {
- case 'a':
- def->os.bootDevs[i] = VIR_DOMAIN_BOOT_FLOPPY;
- break;
- case 'd':
- def->os.bootDevs[i] = VIR_DOMAIN_BOOT_CDROM;
- break;
- case 'n':
- def->os.bootDevs[i] = VIR_DOMAIN_BOOT_NET;
- break;
- case 'c':
- default:
- def->os.bootDevs[i] = VIR_DOMAIN_BOOT_DISK;
- break;
- }
- def->os.nBootDevs++;
- }
- } else {
- if (xenXMConfigCopyStringOpt(conn, conf, "bootloader", &def->os.bootloader) < 0)
- goto cleanup;
- if (xenXMConfigCopyStringOpt(conn, conf, "bootargs", &def->os.bootloaderArgs) < 0)
- goto cleanup;
-
- if (xenXMConfigCopyStringOpt(conn, conf, "kernel", &def->os.kernel) < 0)
- goto cleanup;
- if (xenXMConfigCopyStringOpt(conn, conf, "ramdisk", &def->os.initrd) < 0)
- goto cleanup;
- if (xenXMConfigCopyStringOpt(conn, conf, "extra", &def->os.cmdline) < 0)
- goto cleanup;
- }
-
- if (xenXMConfigGetULong(conn, conf, "memory", &def->memory, MIN_XEN_GUEST_SIZE * 2) < 0)
- goto cleanup;
-
- if (xenXMConfigGetULong(conn, conf, "maxmem", &def->maxmem, def->memory) < 0)
- goto cleanup;
-
- def->memory *= 1024;
- def->maxmem *= 1024;
-
-
- if (xenXMConfigGetULong(conn, conf, "vcpus", &def->vcpus, 1) < 0)
- goto cleanup;
-
- if (xenXMConfigGetString(conn, conf, "cpus", &str, NULL) < 0)
- goto cleanup;
- if (str) {
- def->cpumasklen = 4096;
- if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0)
- goto no_memory;
-
- if (virDomainCpuSetParse(conn, &str, 0,
- def->cpumask, def->cpumasklen) < 0)
- goto cleanup;
- }
-
-
- if (xenXMConfigGetString(conn, conf, "on_poweroff", &str, "destroy") < 0)
- goto cleanup;
- if ((def->onPoweroff = virDomainLifecycleTypeFromString(str)) < 0) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unexpected value %s for on_poweroff"), str);
- goto cleanup;
- }
-
- if (xenXMConfigGetString(conn, conf, "on_reboot", &str, "restart") < 0)
- goto cleanup;
- if ((def->onReboot = virDomainLifecycleTypeFromString(str)) < 0) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unexpected value %s for on_reboot"), str);
- goto cleanup;
- }
-
- if (xenXMConfigGetString(conn, conf, "on_crash", &str, "restart") < 0)
- goto cleanup;
- if ((def->onCrash = virDomainLifecycleTypeFromString(str)) < 0) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unexpected value %s for on_crash"), str);
- goto cleanup;
- }
-
-
-
- if (hvm) {
- if (xenXMConfigGetBool(conn, conf, "pae", &val, 0) < 0)
- goto cleanup;
- else if (val)
- def->features |= (1 << VIR_DOMAIN_FEATURE_PAE);
- if (xenXMConfigGetBool(conn, conf, "acpi", &val, 0) < 0)
- goto cleanup;
- else if (val)
- def->features |= (1 << VIR_DOMAIN_FEATURE_ACPI);
- if (xenXMConfigGetBool(conn, conf, "apic", &val, 0) < 0)
- goto cleanup;
- else if (val)
- def->features |= (1 << VIR_DOMAIN_FEATURE_APIC);
- }
- if (xenXMConfigGetBool(conn, conf, "localtime", &def->localtime, 0) < 0)
- goto cleanup;
-
- if (xenXMConfigCopyStringOpt(conn, conf, "device_model", &def->emulator) < 0)
- goto cleanup;
-
- list = virConfGetValue(conf, "disk");
- if (list && list->type == VIR_CONF_LIST) {
- list = list->list;
- while (list) {
- char *head;
- char *offset;
- char *tmp;
-
- if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
- goto skipdisk;
- head = list->str;
-
- if (VIR_ALLOC(disk) < 0)
- goto no_memory;
-
- /*
- * Disks have 3 components, SOURCE,DEST-DEVICE,MODE
- * eg, phy:/dev/HostVG/XenGuest1,xvda,w
- * The SOURCE is usually prefixed with a driver type,
- * and optionally driver sub-type
- * The DEST-DEVICE is optionally post-fixed with disk type
- */
-
- /* Extract the source file path*/
- if (!(offset = strchr(head, ',')))
- goto skipdisk;
- if ((offset - head) >= (PATH_MAX-1))
- goto skipdisk;
-
- if (offset == head) {
- disk->src = NULL; /* No source file given, eg CDROM with no media */
- } else {
- if (VIR_ALLOC_N(disk->src, (offset - head) + 1) < 0)
- goto no_memory;
- strncpy(disk->src, head, (offset - head));
- disk->src[(offset-head)] = '\0';
- }
- head = offset + 1;
-
- /* Remove legacy ioemu: junk */
- if (STRPREFIX(head, "ioemu:"))
- head = head + 6;
-
- /* Extract the dest device name */
- if (!(offset = strchr(head, ',')))
- goto skipdisk;
- if (VIR_ALLOC_N(disk->dst, (offset - head) + 1) < 0)
- goto no_memory;
- strncpy(disk->dst, head, (offset - head));
- disk->dst[(offset-head)] = '\0';
- head = offset + 1;
-
-
- /* Extract source driver type */
- if (disk->src) {
- /* The main type phy:, file:, tap: ... */
- if ((tmp = strchr(disk->src, ':')) != NULL) {
- if (VIR_ALLOC_N(disk->driverName, (tmp - disk->src) + 1) < 0)
- goto no_memory;
- strncpy(disk->driverName, disk->src, (tmp - disk->src));
- disk->driverName[tmp - disk->src] = '\0';
-
- /* Strip the prefix we found off the source file name */
- memmove(disk->src, disk->src+(tmp-disk->src)+1,
- strlen(disk->src)-(tmp-disk->src));
- }
-
- /* And the sub-type for tap:XXX: type */
- if (disk->driverName &&
- STREQ(disk->driverName, "tap")) {
- if (!(tmp = strchr(disk->src, ':')))
- goto skipdisk;
- if (VIR_ALLOC_N(disk->driverType, (tmp - disk->src) + 1) < 0)
- goto no_memory;
- strncpy(disk->driverType, disk->src, (tmp - disk->src));
- disk->driverType[tmp - disk->src] = '\0';
-
- /* Strip the prefix we found off the source file name */
- memmove(disk->src, disk->src+(tmp-disk->src)+1,
- strlen(disk->src)-(tmp-disk->src));
- }
- }
-
- /* No source, or driver name, so fix to phy: */
- if (!disk->driverName &&
- !(disk->driverName = strdup("phy")))
- goto no_memory;
-
-
- /* phy: type indicates a block device */
- disk->type = STREQ(disk->driverName, "phy") ?
- VIR_DOMAIN_DISK_TYPE_BLOCK : VIR_DOMAIN_DISK_TYPE_FILE;
-
- /* Check for a :cdrom/:disk postfix */
- disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
- if ((tmp = strchr(disk->dst, ':')) != NULL) {
- if (STREQ(tmp, ":cdrom"))
- disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
- tmp[0] = '\0';
- }
-
- if (STRPREFIX(disk->dst, "xvd") || !hvm) {
- disk->bus = VIR_DOMAIN_DISK_BUS_XEN;
- } else if (STRPREFIX(disk->dst, "sd")) {
- disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
- } else {
- disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
- }
-
- if (STREQ(head, "r") ||
- STREQ(head, "ro"))
- disk->readonly = 1;
- else if ((STREQ(head, "w!")) ||
- (STREQ(head, "!")))
- disk->shared = 1;
-
- /* Maintain list in sorted order according to target device name */
- if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
- goto no_memory;
- def->disks[def->ndisks++] = disk;
- disk = NULL;
-
- skipdisk:
- list = list->next;
- virDomainDiskDefFree(disk);
- }
- }
-
- if (hvm && priv->xendConfigVersion == 1) {
- if (xenXMConfigGetString(conn, conf, "cdrom", &str, NULL) < 0)
- goto cleanup;
- if (str) {
- if (VIR_ALLOC(disk) < 0)
- goto no_memory;
-
- disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
- disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
- if (!(disk->driverName = strdup("file")))
- goto no_memory;
- if (!(disk->src = strdup(str)))
- goto no_memory;
- if (!(disk->dst = strdup("hdc")))
- goto no_memory;
- disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
- disk->readonly = 1;
-
- if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
- goto no_memory;
- def->disks[def->ndisks++] = disk;
- disk = NULL;
- }
- }
-
- list = virConfGetValue(conf, "vif");
- if (list && list->type == VIR_CONF_LIST) {
- list = list->list;
- while (list) {
- char script[PATH_MAX];
- char model[10];
- char ip[16];
- char mac[18];
- char bridge[50];
- char vifname[50];
- char *key;
-
- bridge[0] = '\0';
- mac[0] = '\0';
- script[0] = '\0';
- ip[0] = '\0';
- model[0] = '\0';
- vifname[0] = '\0';
-
- if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
- goto skipnic;
-
- key = list->str;
- while (key) {
- char *data;
- char *nextkey = strchr(key, ',');
-
- if (!(data = strchr(key, '=')))
- goto skipnic;
- data++;
-
- if (STRPREFIX(key, "mac=")) {
- int len = nextkey ? (nextkey - data) : 17;
- if (len > 17)
- len = 17;
- strncpy(mac, data, len);
- mac[len] = '\0';
- } else if (STRPREFIX(key, "bridge=")) {
- int len = nextkey ? (nextkey - data) : sizeof(bridge)-1;
- if (len > (sizeof(bridge)-1))
- len = sizeof(bridge)-1;
- strncpy(bridge, data, len);
- bridge[len] = '\0';
- } else if (STRPREFIX(key, "script=")) {
- int len = nextkey ? (nextkey - data) : PATH_MAX-1;
- if (len > (PATH_MAX-1))
- len = PATH_MAX-1;
- strncpy(script, data, len);
- script[len] = '\0';
- } else if (STRPREFIX(key, "model=")) {
- int len = nextkey ? (nextkey - data) : sizeof(model)-1;
- if (len > (sizeof(model)-1))
- len = sizeof(model)-1;
- strncpy(model, data, len);
- model[len] = '\0';
- } else if (STRPREFIX(key, "vifname=")) {
- int len = nextkey ? (nextkey - data) : sizeof(vifname)-1;
- if (len > (sizeof(vifname)-1))
- len = sizeof(vifname)-1;
- strncpy(vifname, data, len);
- vifname[len] = '\0';
- } else if (STRPREFIX(key, "ip=")) {
- int len = nextkey ? (nextkey - data) : 15;
- if (len > 15)
- len = 15;
- strncpy(ip, data, len);
- ip[len] = '\0';
- }
-
- while (nextkey && (nextkey[0] == ',' ||
- nextkey[0] == ' ' ||
- nextkey[0] == '\t'))
- nextkey++;
- key = nextkey;
- }
-
- if (VIR_ALLOC(net) < 0)
- goto cleanup;
-
- if (mac[0]) {
- unsigned int rawmac[6];
- sscanf(mac, "%02x:%02x:%02x:%02x:%02x:%02x",
- (unsigned int*)&rawmac[0],
- (unsigned int*)&rawmac[1],
- (unsigned int*)&rawmac[2],
- (unsigned int*)&rawmac[3],
- (unsigned int*)&rawmac[4],
- (unsigned int*)&rawmac[5]);
- net->mac[0] = rawmac[0];
- net->mac[1] = rawmac[1];
- net->mac[2] = rawmac[2];
- net->mac[3] = rawmac[3];
- net->mac[4] = rawmac[4];
- net->mac[5] = rawmac[5];
- }
-
- if (bridge[0] || STREQ(script, "vif-bridge") ||
- STREQ(script, "vif-vnic")) {
- net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
- } else {
- net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
- }
-
- if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
- if (bridge[0] &&
- !(net->data.bridge.brname = strdup(bridge)))
- goto no_memory;
- if (script[0] &&
- !(net->data.bridge.script = strdup(script)))
- goto no_memory;
- if (ip[0] &&
- !(net->data.bridge.ipaddr = strdup(ip)))
- goto no_memory;
- } else {
- if (script[0] &&
- !(net->data.ethernet.script = strdup(script)))
- goto no_memory;
- if (ip[0] &&
- !(net->data.ethernet.ipaddr = strdup(ip)))
- goto no_memory;
- }
- if (model[0] &&
- !(net->model = strdup(model)))
- goto no_memory;
-
- if (vifname[0] &&
- !(net->ifname = strdup(vifname)))
- goto no_memory;
-
- if (VIR_REALLOC_N(def->nets, def->nnets+1) < 0)
- goto no_memory;
- def->nets[def->nnets++] = net;
- net = NULL;
-
- skipnic:
- list = list->next;
- virDomainNetDefFree(net);
- }
- }
-
- list = virConfGetValue(conf, "pci");
- if (list && list->type == VIR_CONF_LIST) {
- list = list->list;
- while (list) {
- char domain[5];
- char bus[3];
- char slot[3];
- char func[2];
- char *key, *nextkey;
- int domainID;
- int busID;
- int slotID;
- int funcID;
-
- domain[0] = bus[0] = slot[0] = func[0] = '\0';
-
- if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
- goto skippci;
-
- /* pci=['0000:00:1b.0','0000:00:13.0'] */
- if (!(key = list->str))
- goto skippci;
- if (!(nextkey = strchr(key, ':')))
- goto skippci;
-
- if ((nextkey - key) > (sizeof(domain)-1))
- goto skippci;
-
- strncpy(domain, key, sizeof(domain));
- domain[sizeof(domain)-1] = '\0';
-
- key = nextkey + 1;
- if (!(nextkey = strchr(key, ':')))
- goto skippci;
-
- strncpy(bus, key, sizeof(bus));
- bus[sizeof(bus)-1] = '\0';
-
- key = nextkey + 1;
- if (!(nextkey = strchr(key, '.')))
- goto skippci;
-
- strncpy(slot, key, sizeof(slot));
- slot[sizeof(slot)-1] = '\0';
-
- key = nextkey + 1;
- if (strlen(key) != 1)
- goto skippci;
-
- strncpy(func, key, sizeof(func));
- func[sizeof(func)-1] = '\0';
-
- if (virStrToLong_i(domain, NULL, 16, &domainID) < 0)
- goto skippci;
- if (virStrToLong_i(bus, NULL, 16, &busID) < 0)
- goto skippci;
- if (virStrToLong_i(slot, NULL, 16, &slotID) < 0)
- goto skippci;
- if (virStrToLong_i(func, NULL, 16, &funcID) < 0)
- goto skippci;
-
- if (VIR_ALLOC(hostdev) < 0)
- goto cleanup;
-
- hostdev->managed = 0;
- hostdev->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
- hostdev->source.subsys.u.pci.domain = domainID;
- hostdev->source.subsys.u.pci.bus = busID;
- hostdev->source.subsys.u.pci.slot = slotID;
- hostdev->source.subsys.u.pci.function = funcID;
-
- if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0)
- goto no_memory;
- def->hostdevs[def->nhostdevs++] = hostdev;
- hostdev = NULL;
-
- skippci:
- list = list->next;
- }
- }
-
- if (hvm) {
- if (xenXMConfigGetString(conn, conf, "usbdevice", &str, NULL) < 0)
- goto cleanup;
- if (str &&
- (STREQ(str, "tablet") ||
- STREQ(str, "mouse"))) {
- virDomainInputDefPtr input;
- if (VIR_ALLOC(input) < 0)
- goto no_memory;
- input->bus = VIR_DOMAIN_INPUT_BUS_USB;
- input->type = STREQ(str, "tablet") ?
- VIR_DOMAIN_INPUT_TYPE_TABLET :
- VIR_DOMAIN_INPUT_TYPE_MOUSE;
- if (VIR_ALLOC_N(def->inputs, 1) < 0) {
- virDomainInputDefFree(input);
- goto no_memory;
- }
- def->inputs[0] = input;
- def->ninputs = 1;
- }
- }
-
- /* HVM guests, or old PV guests use this config format */
- if (hvm || priv->xendConfigVersion < 3) {
- if (xenXMConfigGetBool(conn, conf, "vnc", &val, 0) < 0)
- goto cleanup;
-
- if (val) {
- if (VIR_ALLOC(graphics) < 0)
- goto no_memory;
- graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
- if (xenXMConfigGetBool(conn, conf, "vncunused", &val, 1) < 0)
- goto cleanup;
- graphics->data.vnc.autoport = val ? 1 : 0;
-
- if (!graphics->data.vnc.autoport) {
- unsigned long vncdisplay;
- if (xenXMConfigGetULong(conn, conf, "vncdisplay", &vncdisplay, 0) < 0)
- goto cleanup;
- graphics->data.vnc.port = (int)vncdisplay + 5900;
- }
- if (xenXMConfigCopyStringOpt(conn, conf, "vnclisten", &graphics->data.vnc.listenAddr) < 0)
- goto cleanup;
- if (xenXMConfigCopyStringOpt(conn, conf, "vncpasswd", &graphics->data.vnc.passwd) < 0)
- goto cleanup;
- if (xenXMConfigCopyStringOpt(conn, conf, "keymap", &graphics->data.vnc.keymap) < 0)
- goto cleanup;
-
- if (VIR_ALLOC_N(def->graphics, 1) < 0)
- goto no_memory;
- def->graphics[0] = graphics;
- def->ngraphics = 1;
- graphics = NULL;
- } else {
- if (xenXMConfigGetBool(conn, conf, "sdl", &val, 0) < 0)
- goto cleanup;
- if (val) {
- if (VIR_ALLOC(graphics) < 0)
- goto no_memory;
- graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
- if (xenXMConfigCopyStringOpt(conn, conf, "display", &graphics->data.sdl.display) < 0)
- goto cleanup;
- if (xenXMConfigCopyStringOpt(conn, conf, "xauthority", &graphics->data.sdl.xauth) < 0)
- goto cleanup;
- if (VIR_ALLOC_N(def->graphics, 1) < 0)
- goto no_memory;
- def->graphics[0] = graphics;
- def->ngraphics = 1;
- graphics = NULL;
- }
- }
- }
-
- if (!hvm && def->graphics == NULL) { /* New PV guests use this format */
- list = virConfGetValue(conf, "vfb");
- if (list && list->type == VIR_CONF_LIST &&
- list->list && list->list->type == VIR_CONF_STRING &&
- list->list->str) {
- char vfb[MAX_VFB];
- char *key = vfb;
- strncpy(vfb, list->list->str, MAX_VFB-1);
- vfb[MAX_VFB-1] = '\0';
-
- if (VIR_ALLOC(graphics) < 0)
- goto no_memory;
-
- if (strstr(key, "type=sdl"))
- graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
- else
- graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
-
- while (key) {
- char *data;
- char *nextkey = strchr(key, ',');
- char *end = nextkey;
- if (nextkey) {
- *end = '\0';
- nextkey++;
- }
-
- if (!(data = strchr(key, '=')))
- break;
-
- if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
- if (STRPREFIX(key, "vncunused=")) {
- if (STREQ(key + 10, "1"))
- graphics->data.vnc.autoport = 1;
- } else if (STRPREFIX(key, "vnclisten=")) {
- if (!(graphics->data.vnc.listenAddr = strdup(key + 10)))
- goto no_memory;
- } else if (STRPREFIX(key, "vncpasswd=")) {
- if (!(graphics->data.vnc.passwd = strdup(key + 10)))
- goto no_memory;
- } else if (STRPREFIX(key, "keymap=")) {
- if (!(graphics->data.vnc.keymap = strdup(key + 7)))
- goto no_memory;
- } else if (STRPREFIX(key, "vncdisplay=")) {
- graphics->data.vnc.port = strtol(key+11, NULL, 10) + 5900;
- }
- } else {
- if (STRPREFIX(key, "display=")) {
- if (!(graphics->data.sdl.display = strdup(key + 8)))
- goto no_memory;
- } else if (STRPREFIX(key, "xauthority=")) {
- if (!(graphics->data.sdl.xauth = strdup(key + 11)))
- goto no_memory;
- }
- }
-
- while (nextkey && (nextkey[0] == ',' ||
- nextkey[0] == ' ' ||
- nextkey[0] == '\t'))
- nextkey++;
- key = nextkey;
- }
- if (VIR_ALLOC_N(def->graphics, 1) < 0)
- goto no_memory;
- def->graphics[0] = graphics;
- def->ngraphics = 1;
- graphics = NULL;
- }
- }
-
- if (hvm) {
- virDomainChrDefPtr chr = NULL;
-
- if (xenXMConfigGetString(conn, conf, "parallel", &str, NULL) < 0)
- goto cleanup;
- if (str && STRNEQ(str, "none") &&
- !(chr = xenDaemonParseSxprChar(conn, str, NULL)))
- goto cleanup;
-
- if (chr) {
- if (VIR_ALLOC_N(def->parallels, 1) < 0) {
- virDomainChrDefFree(chr);
- goto no_memory;
- }
- def->parallels[0] = chr;
- def->nparallels++;
- chr = NULL;
- }
-
- if (xenXMConfigGetString(conn, conf, "serial", &str, NULL) < 0)
- goto cleanup;
- if (str && STRNEQ(str, "none") &&
- !(chr = xenDaemonParseSxprChar(conn, str, NULL)))
- goto cleanup;
-
- if (chr) {
- if (VIR_ALLOC_N(def->serials, 1) < 0) {
- virDomainChrDefFree(chr);
- goto no_memory;
- }
- def->serials[0] = chr;
- def->nserials++;
- }
- } else {
- if (!(def->console = xenDaemonParseSxprChar(conn, "pty", NULL)))
- goto cleanup;
- }
-
- if (hvm) {
- if (xenXMConfigGetString(conn, conf, "soundhw", &str, NULL) < 0)
- goto cleanup;
-
- if (str &&
- xenDaemonParseSxprSound(conn, def, str) < 0)
- goto cleanup;
- }
-
- return def;
-
-no_memory:
- virReportOOMError(conn);
- /* fallthrough */
-cleanup:
- virDomainGraphicsDefFree(graphics);
- virDomainNetDefFree(net);
- virDomainDiskDefFree(disk);
- virDomainDefFree(def);
- return NULL;
-}
-
-
-/*
- * Turn a config record into a lump of XML describing the
- * domain, suitable for later feeding for virDomainCreateXML
- */
-char *xenXMDomainDumpXML(virDomainPtr domain, int flags) {
- xenUnifiedPrivatePtr priv;
- const char *filename;
- xenXMConfCachePtr entry;
- char *ret = NULL;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(NULL);
- }
- if (domain->id != -1)
- return (NULL);
-
- priv = domain->conn->privateData;
- xenUnifiedLock(priv);
-
- if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
- goto cleanup;
-
- if (!(entry = virHashLookup(priv->configCache, filename)))
- goto cleanup;
-
- ret = virDomainDefFormat(domain->conn, entry->def, flags);
-
-cleanup:
- xenUnifiedUnlock(priv);
- return ret;
-}
-
-
-/*
- * Update amount of memory in the config file
- */
-int xenXMDomainSetMemory(virDomainPtr domain, unsigned long memory) {
- xenUnifiedPrivatePtr priv;
- const char *filename;
- xenXMConfCachePtr entry;
- int ret = -1;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return (-1);
- }
- if (domain->conn->flags & VIR_CONNECT_RO)
- return (-1);
- if (domain->id != -1)
- return (-1);
- if (memory < 1024 * MIN_XEN_GUEST_SIZE)
- return (-1);
-
- priv = domain->conn->privateData;
- xenUnifiedLock(priv);
-
- if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
- goto cleanup;
-
- if (!(entry = virHashLookup(priv->configCache, filename)))
- goto cleanup;
-
- entry->def->memory = memory;
- if (entry->def->memory > entry->def->maxmem)
- entry->def->memory = entry->def->maxmem;
-
- /* If this fails, should we try to undo our changes to the
- * in-memory representation of the config file. I say not!
- */
- if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
- goto cleanup;
- ret = 0;
-
-cleanup:
- xenUnifiedUnlock(priv);
- return ret;
-}
-
-/*
- * Update maximum memory limit in config
- */
-int xenXMDomainSetMaxMemory(virDomainPtr domain, unsigned long memory) {
- xenUnifiedPrivatePtr priv;
- const char *filename;
- xenXMConfCachePtr entry;
- int ret = -1;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return (-1);
- }
- if (domain->conn->flags & VIR_CONNECT_RO)
- return (-1);
- if (domain->id != -1)
- return (-1);
-
- priv = domain->conn->privateData;
- xenUnifiedLock(priv);
-
- if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
- goto cleanup;
-
- if (!(entry = virHashLookup(priv->configCache, filename)))
- goto cleanup;
-
- entry->def->maxmem = memory;
- if (entry->def->memory > entry->def->maxmem)
- entry->def->memory = entry->def->maxmem;
-
- /* If this fails, should we try to undo our changes to the
- * in-memory representation of the config file. I say not!
- */
- if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
- goto cleanup;
- ret = 0;
-
-cleanup:
- xenUnifiedUnlock(priv);
- return ret;
-}
-
-/*
- * Get max memory limit from config
- */
-unsigned long xenXMDomainGetMaxMemory(virDomainPtr domain) {
- xenUnifiedPrivatePtr priv;
- const char *filename;
- xenXMConfCachePtr entry;
- unsigned long ret = 0;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return (0);
- }
- if (domain->id != -1)
- return (0);
-
- priv = domain->conn->privateData;
- xenUnifiedLock(priv);
-
- if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
- goto cleanup;
-
- if (!(entry = virHashLookup(priv->configCache, filename)))
- goto cleanup;
-
- ret = entry->def->maxmem;
-
-cleanup:
- xenUnifiedUnlock(priv);
- return ret;
-}
-
-/*
- * Set the VCPU count in config
- */
-int xenXMDomainSetVcpus(virDomainPtr domain, unsigned int vcpus) {
- xenUnifiedPrivatePtr priv;
- const char *filename;
- xenXMConfCachePtr entry;
- int ret = -1;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return (-1);
- }
- if (domain->conn->flags & VIR_CONNECT_RO)
- return (-1);
- if (domain->id != -1)
- return (-1);
-
- priv = domain->conn->privateData;
- xenUnifiedLock(priv);
-
- if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
- goto cleanup;
-
- if (!(entry = virHashLookup(priv->configCache, filename)))
- goto cleanup;
-
- entry->def->vcpus = vcpus;
-
- /* If this fails, should we try to undo our changes to the
- * in-memory representation of the config file. I say not!
- */
- if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
- goto cleanup;
- ret = 0;
-
-cleanup:
- xenUnifiedUnlock(priv);
- return ret;
-}
-
-/**
- * xenXMDomainPinVcpu:
- * @domain: pointer to domain object
- * @vcpu: virtual CPU number (reserved)
- * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes)
- * @maplen: length of cpumap in bytes
- *
- * Set the vcpu affinity in config
- *
- * Returns 0 for success; -1 (with errno) on error
- */
-int xenXMDomainPinVcpu(virDomainPtr domain,
- unsigned int vcpu ATTRIBUTE_UNUSED,
- unsigned char *cpumap, int maplen)
-{
- xenUnifiedPrivatePtr priv;
- const char *filename;
- xenXMConfCachePtr entry;
- virBuffer mapbuf = VIR_BUFFER_INITIALIZER;
- char *mapstr = NULL, *mapsave = NULL;
- int i, j, n, comma = 0;
- int ret = -1;
- char *cpuset = NULL;
- int maxcpu = XEN_MAX_PHYSICAL_CPU;
-
- if (domain == NULL || domain->conn == NULL || domain->name == NULL
- || cpumap == NULL || maplen < 1 || maplen > (int)sizeof(cpumap_t)) {
- xenXMError(domain ? domain->conn : NULL, VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return -1;
- }
- if (domain->conn->flags & VIR_CONNECT_RO) {
- xenXMError (domain->conn, VIR_ERR_INVALID_ARG,
- "%s", _("read only connection"));
- return -1;
- }
- if (domain->id != -1) {
- xenXMError (domain->conn, VIR_ERR_INVALID_ARG,
- "%s", _("not inactive domain"));
- return -1;
- }
-
- priv = domain->conn->privateData;
- xenUnifiedLock(priv);
-
- if (!(filename = virHashLookup(priv->nameConfigMap, domain->name))) {
- xenXMError (domain->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("virHashLookup"));
- goto cleanup;
- }
- if (!(entry = virHashLookup(priv->configCache, filename))) {
- xenXMError (domain->conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("can't retrieve config file for domain"));
- goto cleanup;
- }
-
- /* from bit map, build character string of mapped CPU numbers */
- for (i = 0; i < maplen; i++)
- for (j = 0; j < 8; j++)
- if ((cpumap[i] & (1 << j))) {
- n = i*8 + j;
-
- if (comma)
- virBufferAddLit (&mapbuf, ",");
- comma = 1;
-
- virBufferVSprintf (&mapbuf, "%d", n);
- }
-
- if (virBufferError(&mapbuf)) {
- virReportOOMError(domain->conn);
- goto cleanup;
- }
-
- mapstr = virBufferContentAndReset(&mapbuf);
- mapsave = mapstr;
-
- if (VIR_ALLOC_N(cpuset, maxcpu) < 0) {
- virReportOOMError(domain->conn);
- goto cleanup;
- }
- if (virDomainCpuSetParse(domain->conn,
- (const char **)&mapstr, 0,
- cpuset, maxcpu) < 0)
- goto cleanup;
-
- VIR_FREE(entry->def->cpumask);
- entry->def->cpumask = cpuset;
- entry->def->cpumasklen = maxcpu;
- cpuset = NULL;
-
- if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
- goto cleanup;
-
- ret = 0;
-
- cleanup:
- VIR_FREE(mapsave);
- VIR_FREE(cpuset);
- xenUnifiedUnlock(priv);
- return (ret);
-}
-
-/*
- * Find an inactive domain based on its name
- */
-virDomainPtr xenXMDomainLookupByName(virConnectPtr conn, const char *domname) {
- xenUnifiedPrivatePtr priv;
- const char *filename;
- xenXMConfCachePtr entry;
- virDomainPtr ret = NULL;
-
- if (!VIR_IS_CONNECT(conn)) {
- xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (NULL);
- }
- if (domname == NULL) {
- xenXMError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (NULL);
- }
-
- priv = conn->privateData;
- xenUnifiedLock(priv);
-
- if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
- goto cleanup;
-
- if (!(filename = virHashLookup(priv->nameConfigMap, domname)))
- goto cleanup;
-
- if (!(entry = virHashLookup(priv->configCache, filename)))
- goto cleanup;
-
- if (!(ret = virGetDomain(conn, domname, entry->def->uuid)))
- goto cleanup;
-
- /* Ensure its marked inactive, because may be cached
- handle to a previously active domain */
- ret->id = -1;
-
-cleanup:
- xenUnifiedUnlock(priv);
- return (ret);
-}
-
-
-/*
- * Hash table iterator to search for a domain based on UUID
- */
-static int xenXMDomainSearchForUUID(const void *payload, const char *name ATTRIBUTE_UNUSED, const void *data) {
- const unsigned char *wantuuid = (const unsigned char *)data;
- const xenXMConfCachePtr entry = (const xenXMConfCachePtr)payload;
-
- if (!memcmp(entry->def->uuid, wantuuid, VIR_UUID_BUFLEN))
- return (1);
-
- return (0);
-}
-
-/*
- * Find an inactive domain based on its UUID
- */
-virDomainPtr xenXMDomainLookupByUUID(virConnectPtr conn,
- const unsigned char *uuid) {
- xenUnifiedPrivatePtr priv;
- xenXMConfCachePtr entry;
- virDomainPtr ret = NULL;
-
- if (!VIR_IS_CONNECT(conn)) {
- xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (NULL);
- }
- if (uuid == NULL) {
- xenXMError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (NULL);
- }
-
- priv = conn->privateData;
- xenUnifiedLock(priv);
-
- if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
- goto cleanup;
-
- if (!(entry = virHashSearch(priv->configCache, xenXMDomainSearchForUUID, (const void *)uuid)))
- goto cleanup;
-
- if (!(ret = virGetDomain(conn, entry->def->name, uuid)))
- goto cleanup;
-
- /* Ensure its marked inactive, because may be cached
- handle to a previously active domain */
- ret->id = -1;
-
-cleanup:
- xenUnifiedUnlock(priv);
- return (ret);
-}
-
-
-/*
- * Start a domain from an existing defined config file
- */
-int xenXMDomainCreate(virDomainPtr domain) {
- char *sexpr;
- int ret = -1;
- xenUnifiedPrivatePtr priv;
- const char *filename;
- xenXMConfCachePtr entry;
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
-
- if (domain->id != -1)
- return (-1);
-
- xenUnifiedLock(priv);
-
- if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
- goto error;
-
- if (!(entry = virHashLookup(priv->configCache, filename)))
- goto error;
-
- if (!(sexpr = xenDaemonFormatSxpr(domain->conn, entry->def, priv->xendConfigVersion)))
- goto error;
-
- ret = xenDaemonDomainCreateXML(domain->conn, sexpr);
- VIR_FREE(sexpr);
- if (ret != 0)
- goto error;
-
- if ((ret = xenDaemonDomainLookupByName_ids(domain->conn, domain->name,
- entry->def->uuid)) < 0)
- goto error;
- domain->id = ret;
-
- if (xend_wait_for_devices(domain->conn, domain->name) < 0)
- goto error;
-
- if (xenDaemonDomainResume(domain) < 0)
- goto error;
-
- xenUnifiedUnlock(priv);
- return (0);
-
- error:
- if (domain->id != -1) {
- xenDaemonDomainDestroy(domain);
- domain->id = -1;
- }
- xenUnifiedUnlock(priv);
- return (-1);
-}
-
-
-static
-int xenXMConfigSetInt(virConfPtr conf, const char *setting, long l) {
- virConfValuePtr value = NULL;
-
- if (VIR_ALLOC(value) < 0)
- return -1;
-
- value->type = VIR_CONF_LONG;
- value->next = NULL;
- value->l = l;
-
- return virConfSetValue(conf, setting, value);
-}
-
-
-static
-int xenXMConfigSetString(virConfPtr conf, const char *setting, const char *str) {
- virConfValuePtr value = NULL;
-
- if (VIR_ALLOC(value) < 0)
- return -1;
-
- value->type = VIR_CONF_STRING;
- value->next = NULL;
- if (!(value->str = strdup(str))) {
- VIR_FREE(value);
- return -1;
- }
-
- return virConfSetValue(conf, setting, value);
-}
-
-
-static int xenXMDomainConfigFormatDisk(virConnectPtr conn,
- virConfValuePtr list,
- virDomainDiskDefPtr disk,
- int hvm,
- int xendConfigVersion)
-{
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- virConfValuePtr val, tmp;
- char *str;
-
- if(disk->src) {
- if (disk->driverName) {
- virBufferVSprintf(&buf, "%s:", disk->driverName);
- if (STREQ(disk->driverName, "tap"))
- virBufferVSprintf(&buf, "%s:", disk->driverType ? disk->driverType : "aio");
- } else {
- virBufferVSprintf(&buf, "%s:",
- disk->type == VIR_DOMAIN_DISK_TYPE_FILE ?
- "file" : "phy");
- }
- virBufferVSprintf(&buf, "%s", disk->src);
- }
- virBufferAddLit(&buf, ",");
- if (hvm && xendConfigVersion == 1)
- virBufferAddLit(&buf, "ioemu:");
-
- virBufferVSprintf(&buf, "%s", disk->dst);
- if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
- virBufferAddLit(&buf, ":cdrom");
-
- if (disk->readonly)
- virBufferAddLit(&buf, ",r");
- else if (disk->shared)
- virBufferAddLit(&buf, ",!");
- else
- virBufferAddLit(&buf, ",w");
-
- if (virBufferError(&buf)) {
- virReportOOMError(conn);
- return -1;
- }
-
- if (VIR_ALLOC(val) < 0) {
- virReportOOMError(conn);
- goto cleanup;
- }
-
- val->type = VIR_CONF_STRING;
- val->str = virBufferContentAndReset(&buf);
- tmp = list->list;
- while (tmp && tmp->next)
- tmp = tmp->next;
- if (tmp)
- tmp->next = val;
- else
- list->list = val;
-
- return 0;
-
-cleanup:
- str = virBufferContentAndReset(&buf);
- VIR_FREE(str);
- return -1;
-}
-
-static int xenXMDomainConfigFormatNet(virConnectPtr conn,
- virConfValuePtr list,
- virDomainNetDefPtr net,
- int hvm)
-{
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- virConfValuePtr val, tmp;
- char *str;
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- virBufferVSprintf(&buf, "mac=%02x:%02x:%02x:%02x:%02x:%02x",
- net->mac[0], net->mac[1],
- net->mac[2], net->mac[3],
- net->mac[4], net->mac[5]);
-
- switch (net->type) {
- case VIR_DOMAIN_NET_TYPE_BRIDGE:
- virBufferVSprintf(&buf, ",bridge=%s", net->data.bridge.brname);
- if (net->data.bridge.ipaddr)
- virBufferVSprintf(&buf, ",ip=%s", net->data.bridge.ipaddr);
- virBufferVSprintf(&buf, ",script=%s", DEFAULT_VIF_SCRIPT);
- break;
-
- case VIR_DOMAIN_NET_TYPE_ETHERNET:
- if (net->data.ethernet.script)
- virBufferVSprintf(&buf, ",script=%s", net->data.ethernet.script);
- if (net->data.ethernet.ipaddr)
- virBufferVSprintf(&buf, ",ip=%s", net->data.ethernet.ipaddr);
- break;
-
- case VIR_DOMAIN_NET_TYPE_NETWORK:
- {
- virNetworkPtr network = virNetworkLookupByName(conn, net->data.network.name);
- char *bridge;
- if (!network) {
- xenXMError(conn, VIR_ERR_NO_NETWORK, "%s",
- net->data.network.name);
- return -1;
- }
- bridge = virNetworkGetBridgeName(network);
- virNetworkFree(network);
- if (!bridge) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("network %s is not active"),
- net->data.network.name);
- return -1;
- }
-
- virBufferVSprintf(&buf, ",bridge=%s", bridge);
- virBufferVSprintf(&buf, ",script=%s", DEFAULT_VIF_SCRIPT);
- }
- break;
-
- default:
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unsupported network type %d"),
- net->type);
- goto cleanup;
- }
-
- if (hvm && priv->xendConfigVersion <= XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU)
- virBufferAddLit(&buf, ",type=ioemu");
-
- if (net->model)
- virBufferVSprintf(&buf, ",model=%s",
- net->model);
-
- if (net->ifname)
- virBufferVSprintf(&buf, ",vifname=%s",
- net->ifname);
-
- if (virBufferError(&buf))
- goto cleanup;
-
- if (VIR_ALLOC(val) < 0) {
- virReportOOMError(conn);
- goto cleanup;
- }
-
- val->type = VIR_CONF_STRING;
- val->str = virBufferContentAndReset(&buf);
- tmp = list->list;
- while (tmp && tmp->next)
- tmp = tmp->next;
- if (tmp)
- tmp->next = val;
- else
- list->list = val;
-
- return 0;
-
-cleanup:
- str = virBufferContentAndReset(&buf);
- VIR_FREE(str);
- return -1;
-}
-
-
-
-static int
-xenXMDomainConfigFormatPCI(virConnectPtr conn,
- virConfPtr conf,
- virDomainDefPtr def)
-{
-
- virConfValuePtr pciVal = NULL;
- int hasPCI = 0;
- int i;
-
- for (i = 0 ; i < def->nhostdevs ; i++)
- if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
- def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
- hasPCI = 1;
-
- if (!hasPCI)
- return 0;
-
- if (VIR_ALLOC(pciVal) < 0)
- return -1;
-
- pciVal->type = VIR_CONF_LIST;
- pciVal->list = NULL;
-
- for (i = 0 ; i < def->nhostdevs ; i++) {
- if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
- def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
- virConfValuePtr val, tmp;
- char *buf;
-
- if (virAsprintf(&buf, "%04x:%02x:%02x.%x",
- def->hostdevs[i]->source.subsys.u.pci.domain,
- def->hostdevs[i]->source.subsys.u.pci.bus,
- def->hostdevs[i]->source.subsys.u.pci.slot,
- def->hostdevs[i]->source.subsys.u.pci.function) < 0)
- goto error;
-
- if (VIR_ALLOC(val) < 0) {
- VIR_FREE(buf);
- virReportOOMError(conn);
- goto error;
- }
- val->type = VIR_CONF_STRING;
- val->str = buf;
- tmp = pciVal->list;
- while (tmp && tmp->next)
- tmp = tmp->next;
- if (tmp)
- tmp->next = val;
- else
- pciVal->list = val;
- }
- }
-
- if (pciVal->list != NULL) {
- int ret = virConfSetValue(conf, "pci", pciVal);
- pciVal = NULL;
- if (ret < 0)
- return -1;
- }
- VIR_FREE(pciVal);
-
- return 0;
-
-error:
- virConfFreeValue(pciVal);
- return -1;
-}
-
-
-virConfPtr xenXMDomainConfigFormat(virConnectPtr conn,
- virDomainDefPtr def) {
- virConfPtr conf = NULL;
- int hvm = 0, i;
- xenUnifiedPrivatePtr priv;
- char *cpus = NULL;
- const char *lifecycle;
- char uuid[VIR_UUID_STRING_BUFLEN];
- virConfValuePtr diskVal = NULL;
- virConfValuePtr netVal = NULL;
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- if (!(conf = virConfNew()))
- goto cleanup;
-
-
- if (xenXMConfigSetString(conf, "name", def->name) < 0)
- goto no_memory;
-
- virUUIDFormat(def->uuid, uuid);
- if (xenXMConfigSetString(conf, "uuid", uuid) < 0)
- goto no_memory;
-
- if (xenXMConfigSetInt(conf, "maxmem", def->maxmem / 1024) < 0)
- goto no_memory;
-
- if (xenXMConfigSetInt(conf, "memory", def->memory / 1024) < 0)
- goto no_memory;
-
- if (xenXMConfigSetInt(conf, "vcpus", def->vcpus) < 0)
- goto no_memory;
-
- if (def->cpumask &&
- !(cpus = virDomainCpuSetFormat(conn, def->cpumask, def->cpumasklen)) < 0)
- goto cleanup;
-
- if (cpus &&
- xenXMConfigSetString(conf, "cpus", cpus) < 0)
- goto no_memory;
- VIR_FREE(cpus);
-
- hvm = STREQ(def->os.type, "hvm") ? 1 : 0;
-
- if (hvm) {
- char boot[VIR_DOMAIN_BOOT_LAST+1];
- if (xenXMConfigSetString(conf, "builder", "hvm") < 0)
- goto no_memory;
-
- if (def->os.loader &&
- xenXMConfigSetString(conf, "kernel", def->os.loader) < 0)
- goto no_memory;
-
- for (i = 0 ; i < def->os.nBootDevs ; i++) {
- switch (def->os.bootDevs[i]) {
- case VIR_DOMAIN_BOOT_FLOPPY:
- boot[i] = 'a';
- break;
- case VIR_DOMAIN_BOOT_CDROM:
- boot[i] = 'd';
- break;
- case VIR_DOMAIN_BOOT_NET:
- boot[i] = 'n';
- break;
- case VIR_DOMAIN_BOOT_DISK:
- default:
- boot[i] = 'c';
- break;
- }
- }
- if (!def->os.nBootDevs) {
- boot[0] = 'c';
- boot[1] = '\0';
- } else {
- boot[def->os.nBootDevs] = '\0';
- }
-
- if (xenXMConfigSetString(conf, "boot", boot) < 0)
- goto no_memory;
-
- if (xenXMConfigSetInt(conf, "pae",
- (def->features &
- (1 << VIR_DOMAIN_FEATURE_PAE)) ? 1 : 0) < 0)
- goto no_memory;
-
- if (xenXMConfigSetInt(conf, "acpi",
- (def->features &
- (1 << VIR_DOMAIN_FEATURE_ACPI)) ? 1 : 0) < 0)
- goto no_memory;
-
- if (xenXMConfigSetInt(conf, "apic",
- (def->features &
- (1 << VIR_DOMAIN_FEATURE_APIC)) ? 1 : 0) < 0)
- goto no_memory;
-
-
- if (xenXMConfigSetInt(conf, "localtime", def->localtime ? 1 : 0) < 0)
- goto no_memory;
-
- if (priv->xendConfigVersion == 1) {
- for (i = 0 ; i < def->ndisks ; i++) {
- if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
- def->disks[i]->dst &&
- STREQ(def->disks[i]->dst, "hdc") &&
- def->disks[i]->src) {
- if (xenXMConfigSetString(conf, "cdrom",
- def->disks[i]->src) < 0)
- goto no_memory;
- break;
- }
- }
- }
-
- /* XXX floppy disks */
- } else {
- if (def->os.bootloader &&
- xenXMConfigSetString(conf, "bootloader", def->os.bootloader) < 0)
- goto no_memory;
- if (def->os.bootloaderArgs &&
- xenXMConfigSetString(conf, "bootloader_args", def->os.bootloaderArgs) < 0)
- goto no_memory;
- if (def->os.kernel &&
- xenXMConfigSetString(conf, "kernel", def->os.kernel) < 0)
- goto no_memory;
- if (def->os.initrd &&
- xenXMConfigSetString(conf, "ramdisk", def->os.initrd) < 0)
- goto no_memory;
- if (def->os.cmdline &&
- xenXMConfigSetString(conf, "extra", def->os.cmdline) < 0)
- goto no_memory;
-
- }
-
- if (!(lifecycle = virDomainLifecycleTypeToString(def->onPoweroff))) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unexpected lifecycle action %d"), def->onPoweroff);
- goto cleanup;
- }
- if (xenXMConfigSetString(conf, "on_poweroff", lifecycle) < 0)
- goto no_memory;
-
-
- if (!(lifecycle = virDomainLifecycleTypeToString(def->onReboot))) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unexpected lifecycle action %d"), def->onReboot);
- goto cleanup;
- }
- if (xenXMConfigSetString(conf, "on_reboot", lifecycle) < 0)
- goto no_memory;
-
-
- if (!(lifecycle = virDomainLifecycleTypeToString(def->onCrash))) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- _("unexpected lifecycle action %d"), def->onCrash);
- goto cleanup;
- }
- if (xenXMConfigSetString(conf, "on_crash", lifecycle) < 0)
- goto no_memory;
-
-
-
- if (hvm) {
- if (def->emulator &&
- xenXMConfigSetString(conf, "device_model", def->emulator) < 0)
- goto no_memory;
-
- for (i = 0 ; i < def->ninputs ; i++) {
- if (def->inputs[i]->bus == VIR_DOMAIN_INPUT_BUS_USB) {
- if (xenXMConfigSetInt(conf, "usb", 1) < 0)
- goto no_memory;
- if (xenXMConfigSetString(conf, "usbdevice",
- def->inputs[i]->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
- "mouse" : "tablet") < 0)
- goto no_memory;
- break;
- }
- }
- }
-
- if (def->ngraphics == 1) {
- if (priv->xendConfigVersion < (hvm ? 4 : XEND_CONFIG_MIN_VERS_PVFB_NEWCONF)) {
- if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
- if (xenXMConfigSetInt(conf, "sdl", 1) < 0)
- goto no_memory;
- if (xenXMConfigSetInt(conf, "vnc", 0) < 0)
- goto no_memory;
- if (def->graphics[0]->data.sdl.display &&
- xenXMConfigSetString(conf, "display",
- def->graphics[0]->data.sdl.display) < 0)
- goto no_memory;
- if (def->graphics[0]->data.sdl.xauth &&
- xenXMConfigSetString(conf, "xauthority",
- def->graphics[0]->data.sdl.xauth) < 0)
- goto no_memory;
- } else {
- if (xenXMConfigSetInt(conf, "sdl", 0) < 0)
- goto no_memory;
- if (xenXMConfigSetInt(conf, "vnc", 1) < 0)
- goto no_memory;
- if (xenXMConfigSetInt(conf, "vncunused",
- def->graphics[0]->data.vnc.autoport ? 1 : 0) < 0)
- goto no_memory;
- if (!def->graphics[0]->data.vnc.autoport &&
- xenXMConfigSetInt(conf, "vncdisplay",
- def->graphics[0]->data.vnc.port - 5900) < 0)
- goto no_memory;
- if (def->graphics[0]->data.vnc.listenAddr &&
- xenXMConfigSetString(conf, "vnclisten",
- def->graphics[0]->data.vnc.listenAddr) < 0)
- goto no_memory;
- if (def->graphics[0]->data.vnc.passwd &&
- xenXMConfigSetString(conf, "vncpasswd",
- def->graphics[0]->data.vnc.passwd) < 0)
- goto no_memory;
- if (def->graphics[0]->data.vnc.keymap &&
- xenXMConfigSetString(conf, "keymap",
- def->graphics[0]->data.vnc.keymap) < 0)
- goto no_memory;
- }
- } else {
- virConfValuePtr vfb, disp;
- char *vfbstr = NULL;
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
- virBufferAddLit(&buf, "type=sdl");
- if (def->graphics[0]->data.sdl.display)
- virBufferVSprintf(&buf, ",display=%s",
- def->graphics[0]->data.sdl.display);
- if (def->graphics[0]->data.sdl.xauth)
- virBufferVSprintf(&buf, ",xauthority=%s",
- def->graphics[0]->data.sdl.xauth);
- } else {
- virBufferAddLit(&buf, "type=vnc");
- virBufferVSprintf(&buf, ",vncunused=%d",
- def->graphics[0]->data.vnc.autoport ? 1 : 0);
- if (!def->graphics[0]->data.vnc.autoport)
- virBufferVSprintf(&buf, ",vncdisplay=%d",
- def->graphics[0]->data.vnc.port - 5900);
- if (def->graphics[0]->data.vnc.listenAddr)
- virBufferVSprintf(&buf, ",vnclisten=%s",
- def->graphics[0]->data.vnc.listenAddr);
- if (def->graphics[0]->data.vnc.passwd)
- virBufferVSprintf(&buf, ",vncpasswd=%s",
- def->graphics[0]->data.vnc.passwd);
- if (def->graphics[0]->data.vnc.keymap)
- virBufferVSprintf(&buf, ",keymap=%s",
- def->graphics[0]->data.vnc.keymap);
- }
- if (virBufferError(&buf))
- goto no_memory;
-
- vfbstr = virBufferContentAndReset(&buf);
-
- if (VIR_ALLOC(vfb) < 0) {
- VIR_FREE(vfbstr);
- goto no_memory;
- }
-
- if (VIR_ALLOC(disp) < 0) {
- VIR_FREE(vfb);
- VIR_FREE(vfbstr);
- goto no_memory;
- }
-
- vfb->type = VIR_CONF_LIST;
- vfb->list = disp;
- disp->type = VIR_CONF_STRING;
- disp->str = vfbstr;
-
- if (virConfSetValue(conf, "vfb", vfb) < 0)
- goto no_memory;
- }
- }
-
- /* analyze of the devices */
- if (VIR_ALLOC(diskVal) < 0)
- goto no_memory;
- diskVal->type = VIR_CONF_LIST;
- diskVal->list = NULL;
-
- for (i = 0 ; i < def->ndisks ; i++) {
- if (priv->xendConfigVersion == 1 &&
- def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
- def->disks[i]->dst &&
- STREQ(def->disks[i]->dst, "hdc")) {
- continue;
- }
- if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
- continue;
-
- if (xenXMDomainConfigFormatDisk(conn, diskVal, def->disks[i],
- hvm, priv->xendConfigVersion) < 0)
- goto cleanup;
- }
- if (diskVal->list != NULL) {
- int ret = virConfSetValue(conf, "disk", diskVal);
- diskVal = NULL;
- if (ret < 0)
- goto no_memory;
- }
- VIR_FREE(diskVal);
-
- if (VIR_ALLOC(netVal) < 0)
- goto no_memory;
- netVal->type = VIR_CONF_LIST;
- netVal->list = NULL;
-
- for (i = 0 ; i < def->nnets ; i++) {
- if (xenXMDomainConfigFormatNet(conn, netVal,
- def->nets[i],
- hvm) < 0)
- goto cleanup;
- }
- if (netVal->list != NULL) {
- int ret = virConfSetValue(conf, "vif", netVal);
- netVal = NULL;
- if (ret < 0)
- goto no_memory;
- }
- VIR_FREE(netVal);
-
- if (xenXMDomainConfigFormatPCI(conn, conf, def) < 0)
- goto cleanup;
-
- if (hvm) {
- if (def->nparallels) {
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- char *str;
- int ret;
-
- ret = xenDaemonFormatSxprChr(conn, def->parallels[0], &buf);
- str = virBufferContentAndReset(&buf);
- if (ret == 0)
- ret = xenXMConfigSetString(conf, "parallel", str);
- VIR_FREE(str);
- if (ret < 0)
- goto no_memory;
- } else {
- if (xenXMConfigSetString(conf, "parallel", "none") < 0)
- goto no_memory;
- }
-
- if (def->nserials) {
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- char *str;
- int ret;
-
- ret = xenDaemonFormatSxprChr(conn, def->serials[0], &buf);
- str = virBufferContentAndReset(&buf);
- if (ret == 0)
- ret = xenXMConfigSetString(conf, "serial", str);
- VIR_FREE(str);
- if (ret < 0)
- goto no_memory;
- } else {
- if (xenXMConfigSetString(conf, "serial", "none") < 0)
- goto no_memory;
- }
-
-
- if (def->sounds) {
- virBuffer buf = VIR_BUFFER_INITIALIZER;
- char *str = NULL;
- int ret = xenDaemonFormatSxprSound(conn,
- def,
- &buf);
- str = virBufferContentAndReset(&buf);
- if (ret == 0)
- ret = xenXMConfigSetString(conf, "soundhw", str);
-
- VIR_FREE(str);
- if (ret < 0)
- goto no_memory;
- }
- }
-
- return conf;
-
-no_memory:
- virReportOOMError(conn);
-
-cleanup:
- virConfFreeValue(diskVal);
- virConfFreeValue(netVal);
- VIR_FREE(cpus);
- if (conf)
- virConfFree(conf);
- return (NULL);
-}
-
-/*
- * Create a config file for a domain, based on an XML
- * document describing its config
- */
-virDomainPtr xenXMDomainDefineXML(virConnectPtr conn, const char *xml) {
- virDomainPtr ret;
- virDomainPtr olddomain;
- char filename[PATH_MAX];
- const char * oldfilename;
- virDomainDefPtr def = NULL;
- xenXMConfCachePtr entry = NULL;
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- if (!VIR_IS_CONNECT(conn)) {
- xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (NULL);
- }
- if (xml == NULL) {
- xenXMError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return (NULL);
- }
- if (conn->flags & VIR_CONNECT_RO)
- return (NULL);
-
- xenUnifiedLock(priv);
-
- if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0) {
- xenUnifiedUnlock(priv);
- return (NULL);
- }
-
- if (!(def = virDomainDefParseString(conn, priv->caps, xml,
- VIR_DOMAIN_XML_INACTIVE))) {
- xenUnifiedUnlock(priv);
- return (NULL);
- }
-
- if (virHashLookup(priv->nameConfigMap, def->name)) {
- /* domain exists, we will overwrite it */
-
- if (!(oldfilename = (char *)virHashLookup(priv->nameConfigMap, def->name))) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("can't retrieve config filename for domain to overwrite"));
- goto error;
- }
-
- if (!(entry = virHashLookup(priv->configCache, oldfilename))) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("can't retrieve config entry for domain to overwrite"));
- goto error;
- }
-
- /* XXX wtf.com is this line for - it appears to be amemory leak */
- if (!(olddomain = virGetDomain(conn, def->name, entry->def->uuid)))
- goto error;
-
- /* Remove the name -> filename mapping */
- if (virHashRemoveEntry(priv->nameConfigMap, def->name, NULL) < 0) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("failed to remove old domain from config map"));
- goto error;
- }
-
- /* Remove the config record itself */
- if (virHashRemoveEntry(priv->configCache, oldfilename, xenXMConfigFree) < 0) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("failed to remove old domain from config map"));
- goto error;
- }
-
- entry = NULL;
- }
-
- if ((strlen(priv->configDir) + 1 + strlen(def->name) + 1) > PATH_MAX) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("config file name is too long"));
- goto error;
- }
-
- strcpy(filename, priv->configDir);
- strcat(filename, "/");
- strcat(filename, def->name);
-
- if (xenXMConfigSaveFile(conn, filename, def) < 0)
- goto error;
-
- if (VIR_ALLOC(entry) < 0) {
- virReportOOMError(conn);
- goto error;
- }
-
- if ((entry->refreshedAt = time(NULL)) == ((time_t)-1)) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("unable to get current time"));
- goto error;
- }
-
- memmove(entry->filename, filename, PATH_MAX);
- entry->def = def;
-
- if (virHashAddEntry(priv->configCache, filename, entry) < 0) {
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("unable to store config file handle"));
- goto error;
- }
-
- if (virHashAddEntry(priv->nameConfigMap, def->name, entry->filename) < 0) {
- virHashRemoveEntry(priv->configCache, filename, NULL);
- xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("unable to store config file handle"));
- goto error;
- }
-
- ret = virGetDomain(conn, def->name, def->uuid);
- xenUnifiedUnlock(priv);
- return (ret);
-
- error:
- VIR_FREE(entry);
- virDomainDefFree(def);
- xenUnifiedUnlock(priv);
- return (NULL);
-}
-
-/*
- * Delete a domain from disk
- */
-int xenXMDomainUndefine(virDomainPtr domain) {
- xenUnifiedPrivatePtr priv;
- const char *filename;
- xenXMConfCachePtr entry;
- int ret = -1;
-
- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
- xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return (-1);
- }
-
- if (domain->id != -1)
- return (-1);
- if (domain->conn->flags & VIR_CONNECT_RO)
- return (-1);
-
- priv = domain->conn->privateData;
- xenUnifiedLock(priv);
-
- if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
- goto cleanup;
-
- if (!(entry = virHashLookup(priv->configCache, filename)))
- goto cleanup;
-
- if (unlink(entry->filename) < 0)
- goto cleanup;
-
- /* Remove the name -> filename mapping */
- if (virHashRemoveEntry(priv->nameConfigMap, domain->name, NULL) < 0)
- goto cleanup;
-
- /* Remove the config record itself */
- if (virHashRemoveEntry(priv->configCache, entry->filename, xenXMConfigFree) < 0)
- goto cleanup;
-
- ret = 0;
-
-cleanup:
- xenUnifiedUnlock(priv);
- return ret;
-}
-
-struct xenXMListIteratorContext {
- virConnectPtr conn;
- int max;
- int count;
- char ** names;
-};
-
-static void xenXMListIterator(const void *payload ATTRIBUTE_UNUSED, const char *name, const void *data) {
- struct xenXMListIteratorContext *ctx = (struct xenXMListIteratorContext *)data;
- virDomainPtr dom = NULL;
-
- if (ctx->count == ctx->max)
- return;
-
- dom = xenDaemonLookupByName(ctx->conn, name);
- if (!dom) {
- ctx->names[ctx->count] = strdup(name);
- ctx->count++;
- } else {
- virDomainFree(dom);
- }
-}
-
-
-/*
- * List all defined domains, filtered to remove any which
- * are currently running
- */
-int xenXMListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) {
- xenUnifiedPrivatePtr priv;
- struct xenXMListIteratorContext ctx;
- int ret = -1;
-
- if (!VIR_IS_CONNECT(conn)) {
- xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (-1);
- }
-
- priv = conn->privateData;
- xenUnifiedLock(priv);
-
- if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
- goto cleanup;
-
- if (maxnames > virHashSize(priv->configCache))
- maxnames = virHashSize(priv->configCache);
-
- ctx.conn = conn;
- ctx.count = 0;
- ctx.max = maxnames;
- ctx.names = names;
-
- virHashForEach(priv->nameConfigMap, xenXMListIterator, &ctx);
- ret = ctx.count;
-
-cleanup:
- xenUnifiedUnlock(priv);
- return ret;
-}
-
-/*
- * Return the maximum number of defined domains - not filtered
- * based on number running
- */
-int xenXMNumOfDefinedDomains(virConnectPtr conn) {
- xenUnifiedPrivatePtr priv;
- int ret = -1;
-
- if (!VIR_IS_CONNECT(conn)) {
- xenXMError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
- return (-1);
- }
-
- priv = conn->privateData;
- xenUnifiedLock(priv);
-
- if (!xenInotifyActive(conn) && xenXMConfigCacheRefresh (conn) < 0)
- goto cleanup;
-
- ret = virHashSize(priv->nameConfigMap);
-
-cleanup:
- xenUnifiedUnlock(priv);
- return ret;
-}
-
-
-/**
- * xenXMDomainAttachDevice:
- * @domain: pointer to domain object
- * @xml: pointer to XML description of device
- *
- * Create a virtual device attachment to backend.
- * XML description is translated into config file.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-static int
-xenXMDomainAttachDevice(virDomainPtr domain, const char *xml) {
- const char *filename = NULL;
- xenXMConfCachePtr entry = NULL;
- int ret = -1;
- virDomainDeviceDefPtr dev = NULL;
- virDomainDefPtr def;
- xenUnifiedPrivatePtr priv;
-
- if ((!domain) || (!domain->conn) || (!domain->name) || (!xml)) {
- xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return -1;
- }
-
- if (domain->conn->flags & VIR_CONNECT_RO)
- return -1;
- if (domain->id != -1)
- return -1;
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- xenUnifiedLock(priv);
-
- if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
- goto cleanup;
- if (!(entry = virHashLookup(priv->configCache, filename)))
- goto cleanup;
- def = entry->def;
-
- if (!(dev = virDomainDeviceDefParse(domain->conn,
- priv->caps,
- entry->def,
- xml, VIR_DOMAIN_XML_INACTIVE)))
- goto cleanup;
-
- switch (dev->type) {
- case VIR_DOMAIN_DEVICE_DISK:
- {
- if (virDomainDiskInsert(def, dev->data.disk) < 0) {
- virReportOOMError(domain->conn);
- goto cleanup;
- }
- dev->data.disk = NULL;
- }
- break;
-
- case VIR_DOMAIN_DEVICE_NET:
- {
- if (VIR_REALLOC_N(def->nets, def->nnets+1) < 0) {
- virReportOOMError(domain->conn);
- goto cleanup;
- }
- def->nets[def->nnets++] = dev->data.net;
- dev->data.net = NULL;
- break;
- }
-
- default:
- xenXMError(domain->conn, VIR_ERR_XML_ERROR,
- "%s", _("unknown device"));
- goto cleanup;
- }
-
- /* If this fails, should we try to undo our changes to the
- * in-memory representation of the config file. I say not!
- */
- if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
- goto cleanup;
-
- ret = 0;
-
- cleanup:
- virDomainDeviceDefFree(dev);
- xenUnifiedUnlock(priv);
- return ret;
-}
-
-
-/**
- * xenXMDomainDetachDevice:
- * @domain: pointer to domain object
- * @xml: pointer to XML description of device
- *
- * Destroy a virtual device attachment to backend.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-static int
-xenXMDomainDetachDevice(virDomainPtr domain, const char *xml) {
- const char *filename = NULL;
- xenXMConfCachePtr entry = NULL;
- virDomainDeviceDefPtr dev = NULL;
- virDomainDefPtr def;
- int ret = -1;
- int i;
- xenUnifiedPrivatePtr priv;
-
- if ((!domain) || (!domain->conn) || (!domain->name) || (!xml)) {
- xenXMError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return -1;
- }
-
-
- if (domain->conn->flags & VIR_CONNECT_RO)
- return -1;
- if (domain->id != -1)
- return -1;
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- xenUnifiedLock(priv);
-
- if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
- goto cleanup;
- if (!(entry = virHashLookup(priv->configCache, filename)))
- goto cleanup;
- def = entry->def;
-
- if (!(dev = virDomainDeviceDefParse(domain->conn,
- priv->caps,
- entry->def,
- xml, VIR_DOMAIN_XML_INACTIVE)))
- goto cleanup;
-
- switch (dev->type) {
- case VIR_DOMAIN_DEVICE_DISK:
- {
- for (i = 0 ; i < def->ndisks ; i++) {
- if (def->disks[i]->dst &&
- dev->data.disk->dst &&
- STREQ(def->disks[i]->dst, dev->data.disk->dst)) {
- virDomainDiskDefFree(def->disks[i]);
- if (i < (def->ndisks - 1))
- memmove(def->disks + i,
- def->disks + i + 1,
- sizeof(*def->disks) *
- (def->ndisks - (i + 1)));
- break;
- }
- }
- break;
- }
-
- case VIR_DOMAIN_DEVICE_NET:
- {
- for (i = 0 ; i < def->nnets ; i++) {
- if (!memcmp(def->nets[i]->mac,
- dev->data.net->mac,
- sizeof(def->nets[i]->mac))) {
- virDomainNetDefFree(def->nets[i]);
- if (i < (def->nnets - 1))
- memmove(def->nets + i,
- def->nets + i + 1,
- sizeof(*def->nets) *
- (def->nnets - (i + 1)));
- break;
- }
- }
- break;
- }
- default:
- xenXMError(domain->conn, VIR_ERR_XML_ERROR,
- "%s", _("unknown device"));
- goto cleanup;
- }
-
- /* If this fails, should we try to undo our changes to the
- * in-memory representation of the config file. I say not!
- */
- if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
- goto cleanup;
-
- ret = 0;
-
- cleanup:
- virDomainDeviceDefFree(dev);
- xenUnifiedUnlock(priv);
- return (ret);
-}
-
-int
-xenXMDomainBlockPeek (virDomainPtr dom,
- const char *path ATTRIBUTE_UNUSED,
- unsigned long long offset ATTRIBUTE_UNUSED,
- size_t size ATTRIBUTE_UNUSED,
- void *buffer ATTRIBUTE_UNUSED)
-{
- xenXMError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
- return -1;
-}
-
-
-static char *xenXMAutostartLinkName(virDomainPtr dom)
-{
- char *ret;
- virAsprintf(&ret, "/etc/xen/auto/%s", dom->name);
- return ret;
-}
-
-static char *xenXMDomainConfigName(virDomainPtr dom)
-{
- char *ret;
- virAsprintf(&ret, "/etc/xen/%s", dom->name);
- return ret;
-}
-
-int xenXMDomainGetAutostart(virDomainPtr dom, int *autostart)
-{
- char *linkname = xenXMAutostartLinkName(dom);
- char *config = xenXMDomainConfigName(dom);
- int ret = -1;
-
- if (!linkname || !config) {
- virReportOOMError(dom->conn);
- goto cleanup;
- }
-
- *autostart = virFileLinkPointsTo(linkname, config);
- if (*autostart < 0) {
- virReportSystemError(dom->conn, errno,
- _("cannot check link %s points to config %s"),
- linkname, config);
- goto cleanup;
- }
-
- ret = 0;
-
-cleanup:
- VIR_FREE(linkname);
- VIR_FREE(config);
- return ret;
-}
-
-
-int xenXMDomainSetAutostart(virDomainPtr dom, int autostart)
-{
- char *linkname = xenXMAutostartLinkName(dom);
- char *config = xenXMDomainConfigName(dom);
- int ret = -1;
-
- if (!linkname || !config) {
- virReportOOMError(dom->conn);
- goto cleanup;
- }
-
- if (autostart) {
- if (symlink(config, linkname) < 0 &&
- errno != EEXIST) {
- virReportSystemError(dom->conn, errno,
- _("failed to create link %s to %s"),
- config, linkname);
- goto cleanup;
- }
- } else {
- if (unlink(linkname) < 0 &&
- errno != ENOENT) {
- virReportSystemError(dom->conn, errno,
- _("failed to remove link %s"),
- linkname);
- goto cleanup;
- }
- }
- ret = 0;
-
-cleanup:
- VIR_FREE(linkname);
- VIR_FREE(config);
-
- return ret;
-}
+++ /dev/null
-/*
- * xm_internal.h: helper routines for dealing with inactive domains
- *
- * Copyright (C) 2006-2007 Red Hat
- * Copyright (C) 2006 Daniel P. Berrange
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Daniel P. Berrange <berrange@redhat.com>
- *
- */
-
-#ifndef _LIBVIRT_XM_INTERNAL_H_
-#define _LIBVIRT_XM_INTERNAL_H_
-
-#include "internal.h"
-#include "driver.h"
-#include "conf.h"
-#include "domain_conf.h"
-
-extern struct xenUnifiedDriver xenXMDriver;
-
-int xenXMConfigCacheRefresh (virConnectPtr conn);
-int xenXMConfigCacheAddFile(virConnectPtr conn, const char *filename);
-int xenXMConfigCacheRemoveFile(virConnectPtr conn, const char *filename);
-
-virDrvOpenStatus xenXMOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags);
-int xenXMClose(virConnectPtr conn);
-const char *xenXMGetType(virConnectPtr conn);
-int xenXMDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info);
-char *xenXMDomainDumpXML(virDomainPtr domain, int flags);
-int xenXMDomainSetMemory(virDomainPtr domain, unsigned long memory);
-int xenXMDomainSetMaxMemory(virDomainPtr domain, unsigned long memory);
-unsigned long xenXMDomainGetMaxMemory(virDomainPtr domain);
-int xenXMDomainSetVcpus(virDomainPtr domain, unsigned int vcpus);
-int xenXMDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
- unsigned char *cpumap, int maplen);
-virDomainPtr xenXMDomainLookupByName(virConnectPtr conn, const char *domname);
-virDomainPtr xenXMDomainLookupByUUID(virConnectPtr conn,
- const unsigned char *uuid);
-
-int xenXMListDefinedDomains(virConnectPtr conn, char ** const names, int maxnames);
-int xenXMNumOfDefinedDomains(virConnectPtr conn);
-
-int xenXMDomainCreate(virDomainPtr domain);
-virDomainPtr xenXMDomainDefineXML(virConnectPtr con, const char *xml);
-int xenXMDomainUndefine(virDomainPtr domain);
-
-virConfPtr xenXMDomainConfigFormat(virConnectPtr conn, virDomainDefPtr def);
-virDomainDefPtr xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf);
-
-int xenXMDomainBlockPeek (virDomainPtr dom, const char *path, unsigned long long offset, size_t size, void *buffer);
-
-int xenXMDomainGetAutostart(virDomainPtr dom, int *autostart);
-int xenXMDomainSetAutostart(virDomainPtr dom, int autostart);
-
-#endif
+++ /dev/null
-/*
- * xs_internal.c: access to Xen Store
- *
- * Copyright (C) 2006, 2009 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Daniel Veillard <veillard@redhat.com>
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/ioctl.h>
-
-#include <stdint.h>
-
-#include <xen/dom0_ops.h>
-#include <xen/version.h>
-#include <xen/xen.h>
-
-#include <xs.h>
-
-#include "virterror_internal.h"
-#include "datatypes.h"
-#include "driver.h"
-#include "memory.h"
-#include "event.h"
-#include "logging.h"
-#include "uuid.h"
-#include "xen_unified.h"
-#include "xs_internal.h"
-#include "xen_internal.h"
-
-#define VIR_FROM_THIS VIR_FROM_XEN
-
-#ifndef PROXY
-static char *xenStoreDomainGetOSType(virDomainPtr domain);
-static void xenStoreWatchEvent(int watch, int fd, int events, void *data);
-static void xenStoreWatchListFree(xenStoreWatchListPtr list);
-
-struct xenUnifiedDriver xenStoreDriver = {
- xenStoreOpen, /* open */
- xenStoreClose, /* close */
- NULL, /* version */
- NULL, /* hostname */
- NULL, /* nodeGetInfo */
- NULL, /* getCapabilities */
- xenStoreListDomains, /* listDomains */
- NULL, /* numOfDomains */
- NULL, /* domainCreateXML */
- NULL, /* domainSuspend */
- NULL, /* domainResume */
- xenStoreDomainShutdown, /* domainShutdown */
- xenStoreDomainReboot, /* domainReboot */
- NULL, /* domainDestroy */
- xenStoreDomainGetOSType, /* domainGetOSType */
- xenStoreDomainGetMaxMemory, /* domainGetMaxMemory */
- NULL, /* domainSetMaxMemory */
- xenStoreDomainSetMemory, /* domainSetMemory */
- xenStoreGetDomainInfo, /* domainGetInfo */
- NULL, /* domainSave */
- NULL, /* domainRestore */
- NULL, /* domainCoreDump */
- NULL, /* domainSetVcpus */
- NULL, /* domainPinVcpu */
- NULL, /* domainGetVcpus */
- NULL, /* domainGetMaxVcpus */
- NULL, /* listDefinedDomains */
- NULL, /* numOfDefinedDomains */
- NULL, /* domainCreate */
- NULL, /* domainDefineXML */
- NULL, /* domainUndefine */
- NULL, /* domainAttachDevice */
- NULL, /* domainDetachDevice */
- NULL, /* domainGetAutostart */
- NULL, /* domainSetAutostart */
- NULL, /* domainGetSchedulerType */
- NULL, /* domainGetSchedulerParameters */
- NULL, /* domainSetSchedulerParameters */
-};
-
-#endif /* ! PROXY */
-
-#define virXenStoreError(conn, code, fmt...) \
- virReportErrorHelper(NULL, VIR_FROM_XENSTORE, code, __FILE__, \
- __FUNCTION__, __LINE__, fmt)
-
-/************************************************************************
- * *
- * Helper internal APIs *
- * *
- ************************************************************************/
-#ifndef PROXY
-/**
- * virConnectDoStoreList:
- * @conn: pointer to the hypervisor connection
- * @path: the absolute path of the directory in the store to list
- * @nb: OUT pointer to the number of items found
- *
- * Internal API querying the Xenstore for a list
- *
- * Returns a string which must be freed by the caller or NULL in case of error
- */
-static char **
-virConnectDoStoreList(virConnectPtr conn, const char *path,
- unsigned int *nb)
-{
- xenUnifiedPrivatePtr priv;
-
- if (conn == NULL)
- return NULL;
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->xshandle == NULL || path == NULL || nb == NULL)
- return (NULL);
-
- return xs_directory (priv->xshandle, 0, path, nb);
-}
-#endif /* ! PROXY */
-
-/**
- * virDomainDoStoreQuery:
- * @conn: pointer to the hypervisor connection
- * @domid: id of the domain
- * @path: the relative path of the data in the store to retrieve
- *
- * Internal API querying the Xenstore for a string value.
- *
- * Returns a string which must be freed by the caller or NULL in case of error
- */
-static char *
-virDomainDoStoreQuery(virConnectPtr conn, int domid, const char *path)
-{
- char s[256];
- unsigned int len = 0;
- xenUnifiedPrivatePtr priv;
-
- if (!conn)
- return NULL;
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->xshandle == NULL)
- return (NULL);
-
- snprintf(s, 255, "/local/domain/%d/%s", domid, path);
- s[255] = 0;
-
- return xs_read(priv->xshandle, 0, &s[0], &len);
-}
-
-#ifndef PROXY
-/**
- * virDomainDoStoreWrite:
- * @domain: a domain object
- * @path: the relative path of the data in the store to retrieve
- *
- * Internal API setting up a string value in the Xenstore
- * Requires write access to the XenStore
- *
- * Returns 0 in case of success, -1 in case of failure
- */
-static int
-virDomainDoStoreWrite(virDomainPtr domain, const char *path,
- const char *value)
-{
- char s[256];
- xenUnifiedPrivatePtr priv;
- int ret = -1;
-
- if (!VIR_IS_CONNECTED_DOMAIN(domain))
- return (-1);
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->xshandle == NULL)
- return (-1);
- if (domain->conn->flags & VIR_CONNECT_RO)
- return (-1);
-
- snprintf(s, 255, "/local/domain/%d/%s", domain->id, path);
- s[255] = 0;
-
- if (xs_write(priv->xshandle, 0, &s[0], value, strlen(value)))
- ret = 0;
-
- return (ret);
-}
-
-/**
- * virDomainGetVM:
- * @domain: a domain object
- *
- * Internal API extracting a xenstore vm path.
- *
- * Returns the new string or NULL in case of error
- */
-static char *
-virDomainGetVM(virDomainPtr domain)
-{
- char *vm;
- char query[200];
- unsigned int len;
- xenUnifiedPrivatePtr priv;
-
- if (!VIR_IS_CONNECTED_DOMAIN(domain))
- return (NULL);
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->xshandle == NULL)
- return (NULL);
-
- snprintf(query, 199, "/local/domain/%d/vm", virDomainGetID(domain));
- query[199] = 0;
-
- vm = xs_read(priv->xshandle, 0, &query[0], &len);
-
- return (vm);
-}
-
-/**
- * virDomainGetVMInfo:
- * @domain: a domain object
- * @vm: the xenstore vm path
- * @name: the value's path
- *
- * Internal API extracting one information the device used
- * by the domain from xensttore
- *
- * Returns the new string or NULL in case of error
- */
-static char *
-virDomainGetVMInfo(virDomainPtr domain, const char *vm, const char *name)
-{
- char s[256];
- char *ret = NULL;
- unsigned int len = 0;
- xenUnifiedPrivatePtr priv;
-
- if (!VIR_IS_CONNECTED_DOMAIN(domain))
- return (NULL);
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->xshandle == NULL)
- return (NULL);
-
- snprintf(s, 255, "%s/%s", vm, name);
- s[255] = 0;
-
- ret = xs_read(priv->xshandle, 0, &s[0], &len);
-
- return (ret);
-}
-
-#endif /* ! PROXY */
-
-/************************************************************************
- * *
- * Canonical internal APIs *
- * *
- ************************************************************************/
-/**
- * xenStoreOpen:
- * @conn: pointer to the connection block
- * @name: URL for the target, NULL for local
- * @flags: combination of virDrvOpenFlag(s)
- *
- * Connects to the Xen hypervisor.
- *
- * Returns 0 or -1 in case of error.
- */
-virDrvOpenStatus
-xenStoreOpen(virConnectPtr conn,
- virConnectAuthPtr auth ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED)
-{
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
-
-#ifdef PROXY
- priv->xshandle = xs_daemon_open_readonly();
-#else
- if (flags & VIR_CONNECT_RO)
- priv->xshandle = xs_daemon_open_readonly();
- else
- priv->xshandle = xs_daemon_open();
-#endif /* ! PROXY */
-
- if (priv->xshandle == NULL) {
- /*
- * not being able to connect via the socket as an unprivileged
- * user is rather normal, this should fallback to the proxy (or
- * remote) mechanism.
- */
- if (xenHavePrivilege()) {
- virXenStoreError(NULL, VIR_ERR_NO_XEN,
- "%s", _("failed to connect to Xen Store"));
- }
- return (-1);
- }
-
-#ifndef PROXY
- /* Init activeDomainList */
- if (VIR_ALLOC(priv->activeDomainList) < 0) {
- virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("failed to allocate activeDomainList"));
- return -1;
- }
-
- /* Init watch list before filling in domInfoList,
- so we can know if it is the first time through
- when the callback fires */
- if ( VIR_ALLOC(priv->xsWatchList) < 0 ) {
- virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("failed to allocate xsWatchList"));
- return -1;
- }
-
- /* This will get called once at start */
- if ( xenStoreAddWatch(conn, "@releaseDomain",
- "releaseDomain", xenStoreDomainReleased, priv) < 0 )
- {
- virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("adding watch @releaseDomain"));
- return -1;
- }
-
- /* The initial call of this will fill domInfoList */
- if( xenStoreAddWatch(conn, "@introduceDomain",
- "introduceDomain", xenStoreDomainIntroduced, priv) < 0 )
- {
- virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("adding watch @introduceDomain"));
- return -1;
- }
-
- /* Add an event handle */
- if ((priv->xsWatch = virEventAddHandle(xs_fileno(priv->xshandle),
- VIR_EVENT_HANDLE_READABLE,
- xenStoreWatchEvent,
- conn,
- NULL)) < 0)
- DEBUG0("Failed to add event handle, disabling events\n");
-
-#endif //PROXY
- return 0;
-}
-
-/**
- * xenStoreClose:
- * @conn: pointer to the connection block
- *
- * Close the connection to the Xen hypervisor.
- *
- * Returns 0 in case of success or -1 in case of error.
- */
-int
-xenStoreClose(virConnectPtr conn)
-{
- xenUnifiedPrivatePtr priv;
-
- if (conn == NULL) {
- virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return(-1);
- }
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
-
-#ifndef PROXY
- if (xenStoreRemoveWatch(conn, "@introduceDomain", "introduceDomain") < 0) {
- DEBUG0("Warning, could not remove @introduceDomain watch");
- /* not fatal */
- }
-
- if (xenStoreRemoveWatch(conn, "@releaseDomain", "releaseDomain") < 0) {
- DEBUG0("Warning, could not remove @releaseDomain watch");
- /* not fatal */
- }
-
- xenStoreWatchListFree(priv->xsWatchList);
- priv->xsWatchList = NULL;
- xenUnifiedDomainInfoListFree(priv->activeDomainList);
- priv->activeDomainList = NULL;
-#endif
- if (priv->xshandle == NULL)
- return(-1);
-
- if (priv->xsWatch != -1)
- virEventRemoveHandle(priv->xsWatch);
- xs_daemon_close(priv->xshandle);
- priv->xshandle = NULL;
-
- return (0);
-}
-
-#ifndef PROXY
-/**
- * xenStoreGetDomainInfo:
- * @domain: pointer to the domain block
- * @info: the place where information should be stored
- *
- * Do an hypervisor call to get the related set of domain information.
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-int
-xenStoreGetDomainInfo(virDomainPtr domain, virDomainInfoPtr info)
-{
- char *tmp, **tmp2;
- unsigned int nb_vcpus;
- char request[200];
- xenUnifiedPrivatePtr priv;
-
- if (!VIR_IS_CONNECTED_DOMAIN(domain))
- return (-1);
-
- if ((domain == NULL) || (domain->conn == NULL) || (info == NULL)) {
- virXenStoreError(domain ? domain->conn : NULL, VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
-
- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
- if (priv->xshandle == NULL)
- return(-1);
-
- if (domain->id == -1)
- return(-1);
-
- tmp = virDomainDoStoreQuery(domain->conn, domain->id, "running");
- if (tmp != NULL) {
- if (tmp[0] == '1')
- info->state = VIR_DOMAIN_RUNNING;
- free(tmp);
- } else {
- info->state = VIR_DOMAIN_NOSTATE;
- }
- tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
- if (tmp != NULL) {
- info->memory = atol(tmp);
- info->maxMem = atol(tmp);
- free(tmp);
- } else {
- info->memory = 0;
- info->maxMem = 0;
- }
-#if 0
- /* doesn't seems to work */
- tmp = virDomainDoStoreQuery(domain->conn, domain->id, "cpu_time");
- if (tmp != NULL) {
- info->cpuTime = atol(tmp);
- free(tmp);
- } else {
- info->cpuTime = 0;
- }
-#endif
- snprintf(request, 199, "/local/domain/%d/cpu", domain->id);
- request[199] = 0;
- tmp2 = virConnectDoStoreList(domain->conn, request, &nb_vcpus);
- if (tmp2 != NULL) {
- info->nrVirtCpu = nb_vcpus;
- free(tmp2);
- }
- return (0);
-}
-
-/**
- * xenStoreDomainSetMemory:
- * @domain: pointer to the domain block
- * @memory: the max memory size in kilobytes.
- *
- * Change the maximum amount of memory allowed in the xen store
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-int
-xenStoreDomainSetMemory(virDomainPtr domain, unsigned long memory)
-{
- int ret;
- char value[20];
-
- if ((domain == NULL) || (domain->conn == NULL) ||
- (memory < 1024 * MIN_XEN_GUEST_SIZE)) {
- virXenStoreError(domain ? domain->conn : NULL, VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
- if (domain->id == -1)
- return(-1);
- if ((domain->id == 0) && (memory < (2 * MIN_XEN_GUEST_SIZE * 1024)))
- return(-1);
- snprintf(value, 19, "%lu", memory);
- value[19] = 0;
- ret = virDomainDoStoreWrite(domain, "memory/target", &value[0]);
- if (ret < 0)
- return (-1);
- return (0);
-}
-
-/**
- * xenStoreDomainGetMaxMemory:
- * @domain: pointer to the domain block
- *
- * Ask the xenstore for the maximum memory allowed for a domain
- *
- * Returns the memory size in kilobytes or 0 in case of error.
- */
-unsigned long
-xenStoreDomainGetMaxMemory(virDomainPtr domain)
-{
- char *tmp;
- unsigned long ret = 0;
- xenUnifiedPrivatePtr priv;
-
- if (!VIR_IS_CONNECTED_DOMAIN(domain))
- return (ret);
- if (domain->id == -1)
- return(-1);
-
- priv = domain->conn->privateData;
- xenUnifiedLock(priv);
- tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
- if (tmp != NULL) {
- ret = (unsigned long) atol(tmp);
- VIR_FREE(tmp);
- }
- xenUnifiedUnlock(priv);
- return(ret);
-}
-
-/**
- * xenStoreNumOfDomains:
- * @conn: pointer to the hypervisor connection
- *
- * Provides the number of active domains.
- *
- * Returns the number of domain found or -1 in case of error
- */
-int
-xenStoreNumOfDomains(virConnectPtr conn)
-{
- unsigned int num;
- char **idlist;
- int ret = -1;
- xenUnifiedPrivatePtr priv;
-
- if (conn == NULL) {
- virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return -1;
- }
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->xshandle == NULL) {
- virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return(-1);
- }
- idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
- if (idlist) {
- free(idlist);
- ret = num;
- }
- return(ret);
-}
-
-/**
- * xenStoreDoListDomains:
- * @conn: pointer to the hypervisor connection
- * @ids: array to collect the list of IDs of active domains
- * @maxids: size of @ids
- *
- * Internal API: collect the list of active domains, and store
- * their ID in @maxids. The driver lock must be held.
- *
- * Returns the number of domain found or -1 in case of error
- */
-static int
-xenStoreDoListDomains(xenUnifiedPrivatePtr priv, int *ids, int maxids)
-{
- char **idlist = NULL, *endptr;
- unsigned int num, i;
- int ret = -1;
- long id;
-
- if (priv->xshandle == NULL)
- goto out;
-
- idlist = xs_directory (priv->xshandle, 0, "/local/domain", &num);
- if (idlist == NULL)
- goto out;
-
- for (ret = 0, i = 0; (i < num) && (ret < maxids); i++) {
- id = strtol(idlist[i], &endptr, 10);
- if ((endptr == idlist[i]) || (*endptr != 0))
- goto out;
- ids[ret++] = (int) id;
- }
-
-out:
- VIR_FREE (idlist);
- return ret;
-}
-
-/**
- * xenStoreListDomains:
- * @conn: pointer to the hypervisor connection
- * @ids: array to collect the list of IDs of active domains
- * @maxids: size of @ids
- *
- * Collect the list of active domains, and store their ID in @maxids
- *
- * Returns the number of domain found or -1 in case of error
- */
-int
-xenStoreListDomains(virConnectPtr conn, int *ids, int maxids)
-{
- xenUnifiedPrivatePtr priv;
- int ret;
-
- if ((conn == NULL) || (ids == NULL)) {
- virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return(-1);
- }
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- xenUnifiedLock(priv);
- ret = xenStoreDoListDomains(priv, ids, maxids);
- xenUnifiedUnlock(priv);
-
- return(ret);
-}
-
-/**
- * xenStoreLookupByName:
- * @conn: A xend instance
- * @name: The name of the domain
- *
- * Try to lookup a domain on the Xen Store based on its name.
- *
- * Returns a new domain object or NULL in case of failure
- */
-virDomainPtr
-xenStoreLookupByName(virConnectPtr conn, const char *name)
-{
- virDomainPtr ret = NULL;
- unsigned int num, i, len;
- long id = -1;
- char **idlist = NULL, *endptr;
- char prop[200], *tmp;
- int found = 0;
- struct xend_domain *xenddomain = NULL;
- xenUnifiedPrivatePtr priv;
-
- if ((conn == NULL) || (name == NULL)) {
- virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
- return(NULL);
- }
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->xshandle == NULL)
- return(NULL);
-
- idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
- if (idlist == NULL)
- goto done;
-
- for (i = 0; i < num; i++) {
- id = strtol(idlist[i], &endptr, 10);
- if ((endptr == idlist[i]) || (*endptr != 0)) {
- goto done;
- }
-#if 0
- if (virConnectCheckStoreID(conn, (int) id) < 0)
- continue;
-#endif
- snprintf(prop, 199, "/local/domain/%s/name", idlist[i]);
- prop[199] = 0;
- tmp = xs_read(priv->xshandle, 0, prop, &len);
- if (tmp != NULL) {
- found = STREQ (name, tmp);
- free(tmp);
- if (found)
- break;
- }
- }
- if (!found)
- goto done;
-
- ret = virGetDomain(conn, name, NULL);
- if (ret == NULL)
- goto done;
-
- ret->id = id;
-
-done:
- free(xenddomain);
- free(idlist);
-
- return(ret);
-}
-
-/**
- * xenStoreDomainShutdown:
- * @domain: pointer to the Domain block
- *
- * Shutdown the domain, the OS is requested to properly shutdown
- * and the domain may ignore it. It will return immediately
- * after queuing the request.
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-int
-xenStoreDomainShutdown(virDomainPtr domain)
-{
- int ret;
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL)) {
- virXenStoreError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
- if (domain->id == -1 || domain->id == 0)
- return(-1);
- /*
- * this is very hackish, the domU kernel probes for a special
- * node in the xenstore and launch the shutdown command if found.
- */
- priv = domain->conn->privateData;
- xenUnifiedLock(priv);
- ret = virDomainDoStoreWrite(domain, "control/shutdown", "poweroff");
- xenUnifiedUnlock(priv);
- return ret;
-}
-
-/**
- * xenStoreDomainReboot:
- * @domain: pointer to the Domain block
- * @flags: extra flags for the reboot operation, not used yet
- *
- * Reboot the domain, the OS is requested to properly shutdown
- * and reboot but the domain may ignore it. It will return immediately
- * after queuing the request.
- *
- * Returns 0 in case of success, -1 in case of error.
- */
-int
-xenStoreDomainReboot(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED)
-{
- int ret;
- xenUnifiedPrivatePtr priv;
-
- if ((domain == NULL) || (domain->conn == NULL)) {
- virXenStoreError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(-1);
- }
- if (domain->id == -1 || domain->id == 0)
- return(-1);
- /*
- * this is very hackish, the domU kernel probes for a special
- * node in the xenstore and launch the shutdown command if found.
- */
- priv = domain->conn->privateData;
- xenUnifiedLock(priv);
- ret = virDomainDoStoreWrite(domain, "control/shutdown", "reboot");
- xenUnifiedUnlock(priv);
- return ret;
-}
-
-/*
- * xenStoreDomainGetOSType:
- * @domain: a domain object
- *
- * Get the type of domain operation system.
- *
- * Returns the new string or NULL in case of error, the string must be
- * freed by the caller.
- */
-static char *
-xenStoreDomainGetOSType(virDomainPtr domain) {
- char *vm, *str = NULL;
-
- if ((domain == NULL) || (domain->conn == NULL)) {
- virXenStoreError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
- __FUNCTION__);
- return(NULL);
- }
-
- vm = virDomainGetVM(domain);
- if (vm) {
- xenUnifiedPrivatePtr priv = domain->conn->privateData;
- xenUnifiedLock(priv);
- str = virDomainGetVMInfo(domain, vm, "image/ostype");
- xenUnifiedUnlock(priv);
- VIR_FREE(vm);
- }
-
- return (str);
-}
-#endif /* ! PROXY */
-
-/**
- * xenStoreDomainGetVNCPort:
- * @conn: the hypervisor connection
- * @domid: id of the domain
- *
- * Return the port number on which the domain is listening for VNC
- * connections.
- *
- * The caller must hold the lock on the privateData
- * associated with the 'conn' parameter.
- *
- * Returns the port number, -1 in case of error
- */
-int xenStoreDomainGetVNCPort(virConnectPtr conn, int domid) {
- char *tmp;
- int ret = -1;
-
- tmp = virDomainDoStoreQuery(conn, domid, "console/vnc-port");
- if (tmp != NULL) {
- char *end;
- ret = strtol(tmp, &end, 10);
- if (ret == 0 && end == tmp)
- ret = -1;
- free(tmp);
- }
- return(ret);
-}
-
-/**
- * xenStoreDomainGetConsolePath:
- * @conn: the hypervisor connection
- * @domid: id of the domain
- *
- * Return the path to the psuedo TTY on which the guest domain's
- * serial console is attached.
- *
- * Returns the path to the serial console. It is the callers
- * responsibilty to free() the return string. Returns NULL
- * on error
- *
- * The caller must hold the lock on the privateData
- * associated with the 'conn' parameter.
- */
-char * xenStoreDomainGetConsolePath(virConnectPtr conn, int domid) {
- return virDomainDoStoreQuery(conn, domid, "console/tty");
-}
-
-#ifdef PROXY
-/*
- * xenStoreDomainGetOSTypeID:
- * @conn: pointer to the connection.
- * @id: the domain id
- *
- * Get the type of domain operation system.
- *
- * The caller must hold the lock on the privateData
- * associated with the 'conn' parameter.
- *
- * Returns the new string or NULL in case of error, the string must be
- * freed by the caller.
- */
-char *
-xenStoreDomainGetOSTypeID(virConnectPtr conn, int id) {
- char *vm, *str = NULL;
- char query[200];
- unsigned int len;
- xenUnifiedPrivatePtr priv;
-
- if (id < 0)
- return(NULL);
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->xshandle == NULL)
- return (NULL);
-
- snprintf(query, 199, "/local/domain/%d/vm", id);
- query[199] = 0;
-
- vm = xs_read(priv->xshandle, 0, &query[0], &len);
-
- if (vm) {
- snprintf(query, 199, "%s/image/ostype", vm);
- str = xs_read(priv->xshandle, 0, &query[0], &len);
- free(vm);
- }
- if (str == NULL)
- str = strdup("linux");
-
-
- return (str);
-}
-#endif /* PROXY */
-
-/*
- * xenStoreDomainGetNetworkID:
- * @conn: pointer to the connection.
- * @id: the domain id
- * @mac: the mac address
- *
- * Get the reference (i.e. the string number) for the device on that domain
- * which uses the given mac address
- *
- * The caller must hold the lock on the privateData
- * associated with the 'conn' parameter.
- *
- * Returns the new string or NULL in case of error, the string must be
- * freed by the caller.
- */
-char *
-xenStoreDomainGetNetworkID(virConnectPtr conn, int id, const char *mac) {
- char dir[80], path[128], **list = NULL, *val = NULL;
- unsigned int len, i, num;
- char *ret = NULL;
- xenUnifiedPrivatePtr priv;
-
- if (id < 0)
- return(NULL);
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->xshandle == NULL)
- return (NULL);
- if (mac == NULL)
- return (NULL);
-
- snprintf(dir, sizeof(dir), "/local/domain/0/backend/vif/%d", id);
- list = xs_directory(priv->xshandle, 0, dir, &num);
- if (list == NULL)
- return(NULL);
- for (i = 0; i < num; i++) {
- snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "mac");
- if ((val = xs_read(priv->xshandle, 0, path, &len)) == NULL)
- break;
-
- bool match = (virMacAddrCompare(val, mac) == 0);
-
- VIR_FREE(val);
-
- if (match) {
- ret = strdup(list[i]);
- break;
- }
- }
-
- VIR_FREE(list);
- return(ret);
-}
-
-/*
- * xenStoreDomainGetDiskID:
- * @conn: pointer to the connection.
- * @id: the domain id
- * @dev: the virtual block device name
- *
- * Get the reference (i.e. the string number) for the device on that domain
- * which uses the given virtual block device name
- *
- * The caller must hold the lock on the privateData
- * associated with the 'conn' parameter.
- *
- * Returns the new string or NULL in case of error, the string must be
- * freed by the caller.
- */
-char *
-xenStoreDomainGetDiskID(virConnectPtr conn, int id, const char *dev) {
- char dir[80], path[128], **list = NULL, *val = NULL;
- unsigned int devlen, len, i, num;
- char *ret = NULL;
- xenUnifiedPrivatePtr priv;
-
- if (id < 0)
- return(NULL);
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->xshandle == NULL)
- return (NULL);
- if (dev == NULL)
- return (NULL);
- devlen = strlen(dev);
- if (devlen <= 0)
- return (NULL);
-
- snprintf(dir, sizeof(dir), "/local/domain/0/backend/vbd/%d", id);
- list = xs_directory(priv->xshandle, 0, dir, &num);
- if (list != NULL) {
- for (i = 0; i < num; i++) {
- snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev");
- val = xs_read(priv->xshandle, 0, path, &len);
- if (val == NULL)
- break;
- if ((devlen != len) || memcmp(val, dev, len)) {
- free (val);
- } else {
- ret = strdup(list[i]);
- free (val);
- free (list);
- return (ret);
- }
- }
- free (list);
- }
- snprintf(dir, sizeof(dir), "/local/domain/0/backend/tap/%d", id);
- list = xs_directory(priv->xshandle, 0, dir, &num);
- if (list != NULL) {
- for (i = 0; i < num; i++) {
- snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev");
- val = xs_read(priv->xshandle, 0, path, &len);
- if (val == NULL)
- break;
- if ((devlen != len) || memcmp(val, dev, len)) {
- free (val);
- } else {
- ret = strdup(list[i]);
- free (val);
- free (list);
- return (ret);
- }
- }
- free (list);
- }
- return (NULL);
-}
-
-/*
- * The caller must hold the lock on the privateData
- * associated with the 'conn' parameter.
- */
-char *xenStoreDomainGetName(virConnectPtr conn,
- int id) {
- char prop[200];
- xenUnifiedPrivatePtr priv;
- unsigned int len;
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->xshandle == NULL)
- return(NULL);
-
- snprintf(prop, 199, "/local/domain/%d/name", id);
- prop[199] = 0;
- return xs_read(priv->xshandle, 0, prop, &len);
-}
-
-#ifndef PROXY
-/*
- * The caller must hold the lock on the privateData
- * associated with the 'conn' parameter.
- */
-int xenStoreDomainGetUUID(virConnectPtr conn,
- int id,
- unsigned char *uuid) {
- char prop[200];
- xenUnifiedPrivatePtr priv;
- unsigned int len;
- char *uuidstr;
- int ret = 0;
-
- priv = (xenUnifiedPrivatePtr) conn->privateData;
- if (priv->xshandle == NULL)
- return -1;
-
- snprintf(prop, 199, "/local/domain/%d/vm", id);
- prop[199] = 0;
- // This will return something like
- // /vm/00000000-0000-0000-0000-000000000000
- uuidstr = xs_read(priv->xshandle, 0, prop, &len);
-
- // remove "/vm/"
- ret = virUUIDParse(uuidstr + 4, uuid);
-
- VIR_FREE(uuidstr);
-
- return ret;
-}
-
-static void
-xenStoreWatchListFree(xenStoreWatchListPtr list)
-{
- int i;
- for (i=0; i<list->count; i++) {
- VIR_FREE(list->watches[i]->path);
- VIR_FREE(list->watches[i]->token);
- VIR_FREE(list->watches[i]);
- }
- VIR_FREE(list);
-}
-
-/*
- * The caller must hold the lock on the privateData
- * associated with the 'conn' parameter.
- */
-int xenStoreAddWatch(virConnectPtr conn,
- const char *path,
- const char *token,
- xenStoreWatchCallback cb,
- void *opaque)
-{
- xenStoreWatchPtr watch;
- int n;
- xenStoreWatchListPtr list;
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- if (priv->xshandle == NULL)
- return -1;
-
- list = priv->xsWatchList;
- if(!list)
- return -1;
-
- /* check if we already have this callback on our list */
- for (n=0; n < list->count; n++) {
- if( STREQ(list->watches[n]->path, path) &&
- STREQ(list->watches[n]->token, token)) {
- virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("watch already tracked"));
- return -1;
- }
- }
-
- if (VIR_ALLOC(watch) < 0)
- return -1;
- watch->path = strdup(path);
- watch->token = strdup(token);
- watch->cb = cb;
- watch->opaque = opaque;
-
- /* Make space on list */
- n = list->count;
- if (VIR_REALLOC_N(list->watches, n + 1) < 0) {
- virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("reallocating list"));
- VIR_FREE(watch);
- return -1;
- }
-
- list->watches[n] = watch;
- list->count++;
-
- conn->refs++;
-
- return xs_watch(priv->xshandle, watch->path, watch->token);
-}
-
-/*
- * The caller must hold the lock on the privateData
- * associated with the 'conn' parameter.
- */
-int xenStoreRemoveWatch(virConnectPtr conn,
- const char *path,
- const char *token)
-{
- int i;
- xenStoreWatchListPtr list;
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- if (priv->xshandle == NULL)
- return -1;
-
- list = priv->xsWatchList;
- if(!list)
- return -1;
-
- for (i = 0 ; i < list->count ; i++) {
- if( STREQ(list->watches[i]->path, path) &&
- STREQ(list->watches[i]->token, token)) {
-
- if (!xs_unwatch(priv->xshandle,
- list->watches[i]->path,
- list->watches[i]->token))
- {
- DEBUG0("WARNING: Could not remove watch");
- /* Not fatal, continue */
- }
-
- VIR_FREE(list->watches[i]->path);
- VIR_FREE(list->watches[i]->token);
- VIR_FREE(list->watches[i]);
-
- if (i < (list->count - 1))
- memmove(list->watches + i,
- list->watches + i + 1,
- sizeof(*(list->watches)) *
- (list->count - (i + 1)));
-
- if (VIR_REALLOC_N(list->watches,
- list->count - 1) < 0) {
- ; /* Failure to reduce memory allocation isn't fatal */
- }
- list->count--;
- virUnrefConnect(conn);
- return 0;
- }
- }
- return -1;
-}
-
-static xenStoreWatchPtr
-xenStoreFindWatch(xenStoreWatchListPtr list,
- const char *path,
- const char *token)
-{
- int i;
- for (i = 0 ; i < list->count ; i++)
- if( STREQ(path, list->watches[i]->path) &&
- STREQ(token, list->watches[i]->token) )
- return list->watches[i];
-
- return NULL;
-}
-
-static void
-xenStoreWatchEvent(int watch ATTRIBUTE_UNUSED,
- int fd ATTRIBUTE_UNUSED,
- int events,
- void *data)
-{
- char **event;
- char *path;
- char *token;
- unsigned int stringCount;
- xenStoreWatchPtr sw;
-
- virConnectPtr conn = data;
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
-
- if(!priv) return;
-
- /* only set a watch on read and write events */
- if (events & (VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP)) return;
-
- xenUnifiedLock(priv);
-
- if(!priv->xshandle)
- goto cleanup;
-
- event = xs_read_watch(priv->xshandle, &stringCount);
- if (!event)
- goto cleanup;
-
- path = event[XS_WATCH_PATH];
- token = event[XS_WATCH_TOKEN];
-
- sw = xenStoreFindWatch(priv->xsWatchList, path, token);
- if( sw )
- sw->cb(conn, path, token, sw->opaque);
- VIR_FREE(event);
-
-cleanup:
- xenUnifiedUnlock(priv);
-}
-
-
-/*
- * The domain callback for the @introduceDomain watch
- *
- * The lock on 'priv' is held when calling this
- */
-int xenStoreDomainIntroduced(virConnectPtr conn,
- const char *path ATTRIBUTE_UNUSED,
- const char *token ATTRIBUTE_UNUSED,
- void *opaque)
-{
- int i, j, found, missing = 0, retries = 20;
- int new_domain_cnt;
- int *new_domids;
- int nread;
-
- xenUnifiedPrivatePtr priv = opaque;
-
-retry:
- new_domain_cnt = xenStoreNumOfDomains(conn);
- if( VIR_ALLOC_N(new_domids,new_domain_cnt) < 0 ) {
- virReportOOMError(NULL);
- return -1;
- }
- nread = xenStoreDoListDomains(priv, new_domids, new_domain_cnt);
- if (nread != new_domain_cnt) {
- // mismatch. retry this read
- VIR_FREE(new_domids);
- goto retry;
- }
-
- missing = 0;
- for (i=0 ; i < new_domain_cnt ; i++) {
- found = 0;
- for (j = 0 ; j < priv->activeDomainList->count ; j++) {
- if (priv->activeDomainList->doms[j]->id == new_domids[i]) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- virDomainEventPtr event;
- char *name;
- unsigned char uuid[VIR_UUID_BUFLEN];
-
- if (!(name = xenStoreDomainGetName(conn, new_domids[i]))) {
- missing = 1;
- continue;
- }
- if (xenStoreDomainGetUUID(conn, new_domids[i], uuid) < 0) {
- missing = 1;
- VIR_FREE(name);
- continue;
- }
-
- event = virDomainEventNew(new_domids[i], name, uuid,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_BOOTED);
- if (event)
- xenUnifiedDomainEventDispatch(priv, event);
-
- /* Add to the list */
- xenUnifiedAddDomainInfo(priv->activeDomainList,
- new_domids[i], name, uuid);
-
- VIR_FREE(name);
- }
- }
- VIR_FREE(new_domids);
-
- if (missing && retries--) {
- DEBUG0("Some domains were missing, trying again");
- usleep(100 * 1000);
- goto retry;
- }
- return 0;
-}
-
-/*
- * The domain callback for the @destroyDomain watch
- *
- * The lock on 'priv' is held when calling this
- */
-int xenStoreDomainReleased(virConnectPtr conn,
- const char *path ATTRIBUTE_UNUSED,
- const char *token ATTRIBUTE_UNUSED,
- void *opaque)
-{
- int i, j, found, removed, retries = 20;
- int new_domain_cnt;
- int *new_domids;
- int nread;
-
- xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) opaque;
-
- if(!priv->activeDomainList->count) return 0;
-
-retry:
- new_domain_cnt = xenStoreNumOfDomains(conn);
-
- if( VIR_ALLOC_N(new_domids,new_domain_cnt) < 0 ) {
- virReportOOMError(NULL);
- return -1;
- }
- nread = xenStoreDoListDomains(priv, new_domids, new_domain_cnt);
- if (nread != new_domain_cnt) {
- // mismatch. retry this read
- VIR_FREE(new_domids);
- goto retry;
- }
-
- removed = 0;
- for (j=0 ; j < priv->activeDomainList->count ; j++) {
- found = 0;
- for (i=0 ; i < new_domain_cnt ; i++) {
- if (priv->activeDomainList->doms[j]->id == new_domids[i]) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- virDomainEventPtr event =
- virDomainEventNew(-1,
- priv->activeDomainList->doms[j]->name,
- priv->activeDomainList->doms[j]->uuid,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
- if (event)
- xenUnifiedDomainEventDispatch(priv, event);
-
- /* Remove from the list */
- xenUnifiedRemoveDomainInfo(priv->activeDomainList,
- priv->activeDomainList->doms[j]->id,
- priv->activeDomainList->doms[j]->name,
- priv->activeDomainList->doms[j]->uuid);
-
- removed = 1;
- }
- }
-
- VIR_FREE(new_domids);
-
- if (!removed && retries--) {
- DEBUG0("No domains removed, retrying");
- usleep(100 * 1000);
- goto retry;
- }
- return 0;
-}
-
-#endif //PROXY
+++ /dev/null
-/*
- * xs_internal.h: internal API for access to XenStore
- *
- * Copyright (C) 2006 Red Hat, Inc.
- *
- * See COPYING.LIB for the License of this software
- *
- * Daniel Veillard <veillard@redhat.com>
- */
-
-#ifndef __VIR_XS_INTERNAL_H__
-#define __VIR_XS_INTERNAL_H__
-
-#include "internal.h"
-#include "driver.h"
-
-extern struct xenUnifiedDriver xenStoreDriver;
-int xenStoreInit (void);
-
-virDrvOpenStatus xenStoreOpen (virConnectPtr conn,
- virConnectAuthPtr auth,
- int flags);
-int xenStoreClose (virConnectPtr conn);
-int xenStoreGetDomainInfo (virDomainPtr domain,
- virDomainInfoPtr info);
-int xenStoreNumOfDomains (virConnectPtr conn);
-int xenStoreListDomains (virConnectPtr conn,
- int *ids,
- int maxids);
-virDomainPtr xenStoreLookupByName(virConnectPtr conn,
- const char *name);
-unsigned long xenStoreGetMaxMemory (virDomainPtr domain);
-int xenStoreDomainSetMemory (virDomainPtr domain,
- unsigned long memory);
-unsigned long xenStoreDomainGetMaxMemory(virDomainPtr domain);
-int xenStoreDomainShutdown (virDomainPtr domain);
-int xenStoreDomainReboot (virDomainPtr domain,
- unsigned int flags);
-
-/* those are entry point for the proxy */
-int xenStoreDomainGetVNCPort(virConnectPtr conn,
- int domid);
-char * xenStoreDomainGetConsolePath(virConnectPtr conn,
- int domid);
-char * xenStoreDomainGetOSTypeID(virConnectPtr conn,
- int id);
-char * xenStoreDomainGetNetworkID(virConnectPtr conn,
- int id,
- const char *mac);
-char * xenStoreDomainGetDiskID(virConnectPtr conn,
- int id,
- const char *dev);
-char * xenStoreDomainGetName(virConnectPtr conn,
- int id);
-int xenStoreDomainGetUUID(virConnectPtr conn,
- int id,
- unsigned char *uuid);
-
-typedef int (*xenStoreWatchCallback)(virConnectPtr conn,
- const char *path,
- const char *token,
- void *opaque);
-
-struct _xenStoreWatch {
- char *path;
- char *token;
- xenStoreWatchCallback cb;
- void *opaque;
-};
-typedef struct _xenStoreWatch xenStoreWatch;
-typedef xenStoreWatch *xenStoreWatchPtr;
-
-struct _xenStoreWatchList {
- unsigned int count;
- xenStoreWatchPtr *watches;
-};
-typedef struct _xenStoreWatchList xenStoreWatchList;
-typedef xenStoreWatchList *xenStoreWatchListPtr;
-
-
-int xenStoreAddWatch(virConnectPtr conn,
- const char *path,
- const char *token,
- xenStoreWatchCallback cb,
- void *opaque);
-int xenStoreRemoveWatch(virConnectPtr conn,
- const char *path,
- const char *token);
-
-/* domain events */
-int xenStoreDomainIntroduced(virConnectPtr conn,
- const char *path,
- const char *token,
- void *opaque);
-int xenStoreDomainReleased(virConnectPtr conn,
- const char *path,
- const char *token,
- void *opaque);
-
-int xenStoreDomainEventEmitted(virDomainEventType evt);
-#endif /* __VIR_XS_INTERNAL_H__ */
#include "internal.h"
#include "xml.h"
#include "datatypes.h"
-#include "xen_unified.h"
-#include "xend_internal.h"
+#include "xen/xen_driver.h"
+#include "xen/xend_internal.h"
#include "testutils.h"
#include "testutilsxen.h"
#include "stats_linux.h"
#include "internal.h"
-
+#include "xen/block_stats.h"
#include "testutils.h"
#if WITH_XEN
#include "internal.h"
#include "xml.h"
#include "testutils.h"
-#include "xen_internal.h"
+#include "xen/xen_hypervisor.h"
static char *progname;
static char *abs_srcdir;
#include "internal.h"
#include "datatypes.h"
-#include "xen_unified.h"
-#include "xm_internal.h"
+#include "xen/xen_driver.h"
+#include "xen/xm_internal.h"
#include "testutils.h"
#include "testutilsxen.h"
#include "memory.h"
#include <unistd.h>
#include "internal.h"
-#include "xend_internal.h"
+#include "xen/xend_internal.h"
#include "testutils.h"
#include "testutilsxen.h"