libvirt/src/proxy_internal.c
Jim Meyering bc18a91f91 error-reporting calls using VIR_ERR_NO_MEMORY: use virReportOOMError instead
* src/uml_conf.c (VIR_FROM_THIS): Define to VIR_FROM_UML.
* src/xs_internal.c (VIR_FROM_THIS): Define to VIR_FROM_XEN.
* src/xml.c (VIR_FROM_THIS): Define to VIR_FROM_XML.
* src/stats_linux.c (VIR_FROM_THIS): Define to VIR_FROM_STATS_LINUX.
* src/datatypes.c (VIR_FROM_THIS): Define to VIR_FROM_NONE.
* src/lxc_conf.c (VIR_FROM_THIS): Define to VIR_FROM_LXC.
* src/libvirt.c (VIR_FROM_THIS): Define to VIR_FROM_NONE.
* src/node_device_conf.c (VIR_FROM_THIS): Define to VIR_FROM_NODEDEV.
* src/openvz_conf.c (VIR_FROM_THIS): Define to VIR_FROM_OPENVZ.
* src/openvz_driver.c (VIR_FROM_THIS): Define to VIR_FROM_OPENVZ.
* src/conf.c (VIR_FROM_THIS): Define to VIR_FROM_CONF.
Note: this loses config_filename:config_lineno diagnostics,
but that's ok.
* src/node_device.c (VIR_FROM_THIS): Define to VIR_FROM_NODEDEV.
* src/sexpr.c (VIR_FROM_THIS): Define to VIR_FROM_SEXPR.
* po/POTFILES.in: remove src/sexpr.c and src/lxc_conf.c
2009-01-29 12:10:32 +00:00

1061 lines
28 KiB
C

/*
* 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 */
NULL, /* URI */
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();
int ret, status;
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 (virExec(NULL, proxyarg, NULL, NULL,
&pid, -1, NULL, NULL, VIR_EXEC_DAEMON) < 0)
VIR_ERROR0("Failed to fork libvirt_proxy\n");
/*
* do a waitpid on the intermediate process to avoid zombies.
*/
retry_wait:
ret = waitpid(pid, &status, 0);
if (ret < 0) {
if (errno == EINTR)
goto retry_wait;
}
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);
}