libvirt/src/qemu/qemu_monitor.c
Daniel P. Berrange a48539c013 qemu: convert monitor to use qemuDomainLogContextPtr indirectly
Currently the QEMU monitor is given an FD to the logfile. This
won't work in the future with virtlogd, so it needs to use the
qemuDomainLogContextPtr instead, but it shouldn't directly
access that object either. So define a callback that the
monitor can use for reporting errors from the log file.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2015-11-26 14:30:15 +00:00

3802 lines
95 KiB
C

/*
* qemu_monitor.c: interaction with QEMU monitor console
*
* Copyright (C) 2006-2015 Red Hat, Inc.
* 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, see
* <http://www.gnu.org/licenses/>.
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#include <config.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
#include "qemu_monitor.h"
#include "qemu_monitor_text.h"
#include "qemu_monitor_json.h"
#include "qemu_domain.h"
#include "qemu_process.h"
#include "virerror.h"
#include "viralloc.h"
#include "virlog.h"
#include "virfile.h"
#include "virprocess.h"
#include "virobject.h"
#include "virprobe.h"
#include "virstring.h"
#ifdef WITH_DTRACE_PROBES
# include "libvirt_qemu_probes.h"
#endif
#define VIR_FROM_THIS VIR_FROM_QEMU
VIR_LOG_INIT("qemu.qemu_monitor");
#define DEBUG_IO 0
#define DEBUG_RAW_IO 0
struct _qemuMonitor {
virObjectLockable parent;
virCond notify;
int fd;
int watch;
int hasSendFD;
virDomainObjPtr vm;
qemuMonitorCallbacksPtr cb;
void *callbackOpaque;
/* If there's a command being processed this will be
* non-NULL */
qemuMonitorMessagePtr msg;
/* Buffer incoming data ready for Text/QMP monitor
* code to process & find message boundaries */
size_t bufferOffset;
size_t bufferLength;
char *buffer;
/* If anything went wrong, this will be fed back
* the next monitor msg */
virError lastError;
int nextSerial;
bool json;
bool waitGreeting;
/* cache of query-command-line-options results */
virJSONValuePtr options;
/* If found, path to the virtio memballoon driver */
char *balloonpath;
bool ballooninit;
/* Log file context of the qemu process to dig for usable info */
qemuMonitorReportDomainLogError logFunc;
void *logOpaque;
virFreeCallback logDestroy;
};
/**
* QEMU_CHECK_MONITOR_FULL:
* @mon: monitor pointer variable to check, evaluated multiple times, no parentheses
* @force_json: force JSON monitor, true or false
* @exit: statement that is used to exit the function
*
* This macro checks that the monitor is valid for given operation and exits
* the function if not. The macro also adds a debug statement regarding the
* monitor.
*/
#define QEMU_CHECK_MONITOR_FULL(mon, force_json, exit) \
if (!mon) { \
virReportError(VIR_ERR_INVALID_ARG, "%s", \
_("monitor must not be NULL")); \
exit; \
} \
VIR_DEBUG("mon:%p vm:%p json:%d fd:%d", mon, mon->vm, mon->json, mon->fd); \
if (force_json && !mon->json) { \
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", \
_("JSON monitor is required")); \
exit; \
}
/* Check monitor and return NULL on error */
#define QEMU_CHECK_MONITOR_NULL(mon) \
QEMU_CHECK_MONITOR_FULL(mon, false, return NULL)
#define QEMU_CHECK_MONITOR_JSON_NULL(mon) \
QEMU_CHECK_MONITOR_FULL(mon, true, return NULL)
/* Check monitor and return -1 on error */
#define QEMU_CHECK_MONITOR(mon) \
QEMU_CHECK_MONITOR_FULL(mon, false, return -1)
#define QEMU_CHECK_MONITOR_JSON(mon) \
QEMU_CHECK_MONITOR_FULL(mon, true, return -1)
/* Check monitor and jump to the provided label */
#define QEMU_CHECK_MONITOR_GOTO(mon, label) \
QEMU_CHECK_MONITOR_FULL(mon, false, goto label)
#define QEMU_CHECK_MONITOR_JSON_GOTO(mon, label) \
QEMU_CHECK_MONITOR_FULL(mon, true, goto label)
static virClassPtr qemuMonitorClass;
static void qemuMonitorDispose(void *obj);
static int qemuMonitorOnceInit(void)
{
if (!(qemuMonitorClass = virClassNew(virClassForObjectLockable(),
"qemuMonitor",
sizeof(qemuMonitor),
qemuMonitorDispose)))
return -1;
return 0;
}
VIR_ONCE_GLOBAL_INIT(qemuMonitor)
VIR_ENUM_IMPL(qemuMonitorMigrationStatus,
QEMU_MONITOR_MIGRATION_STATUS_LAST,
"inactive", "active", "completed", "failed", "cancelling",
"cancelled", "setup")
VIR_ENUM_IMPL(qemuMonitorMigrationCaps,
QEMU_MONITOR_MIGRATION_CAPS_LAST,
"xbzrle", "auto-converge", "rdma-pin-all", "events")
VIR_ENUM_IMPL(qemuMonitorVMStatus,
QEMU_MONITOR_VM_STATUS_LAST,
"debug", "inmigrate", "internal-error", "io-error", "paused",
"postmigrate", "prelaunch", "finish-migrate", "restore-vm",
"running", "save-vm", "shutdown", "watchdog", "guest-panicked")
typedef enum {
QEMU_MONITOR_BLOCK_IO_STATUS_OK,
QEMU_MONITOR_BLOCK_IO_STATUS_FAILED,
QEMU_MONITOR_BLOCK_IO_STATUS_NOSPACE,
QEMU_MONITOR_BLOCK_IO_STATUS_LAST
} qemuMonitorBlockIOStatus;
VIR_ENUM_DECL(qemuMonitorBlockIOStatus)
VIR_ENUM_IMPL(qemuMonitorBlockIOStatus,
QEMU_MONITOR_BLOCK_IO_STATUS_LAST,
"ok", "failed", "nospace")
char *
qemuMonitorEscapeArg(const char *in)
{
int len = 0;
size_t i, j;
char *out;
/* To pass through the QEMU monitor, we need to use escape
sequences: \r, \n, \", \\
*/
for (i = 0; in[i] != '\0'; i++) {
switch (in[i]) {
case '\r':
case '\n':
case '"':
case '\\':
len += 2;
break;
default:
len += 1;
break;
}
}
if (VIR_ALLOC_N(out, len + 1) < 0)
return NULL;
for (i = j = 0; in[i] != '\0'; i++) {
switch (in[i]) {
case '\r':
out[j++] = '\\';
out[j++] = 'r';
break;
case '\n':
out[j++] = '\\';
out[j++] = 'n';
break;
case '"':
case '\\':
out[j++] = '\\';
out[j++] = in[i];
break;
default:
out[j++] = in[i];
break;
}
}
out[j] = '\0';
return out;
}
char *
qemuMonitorUnescapeArg(const char *in)
{
size_t i, j;
char *out;
int len = strlen(in);
char next;
if (VIR_ALLOC_N(out, len + 1) < 0)
return NULL;
for (i = j = 0; i < len; ++i) {
next = in[i];
if (in[i] == '\\') {
++i;
switch (in[i]) {
case 'r':
next = '\r';
break;
case 'n':
next = '\n';
break;
case '"':
case '\\':
next = in[i];
break;
default:
/* invalid input (including trailing '\' at end of in) */
VIR_FREE(out);
return NULL;
}
}
out[j++] = next;
}
out[j] = '\0';
return out;
}
#if DEBUG_RAW_IO
# include <c-ctype.h>
static char *
qemuMonitorEscapeNonPrintable(const char *text)
{
size_t i;
virBuffer buf = VIR_BUFFER_INITIALIZER;
for (i = 0; text[i] != '\0'; i++) {
if (c_isprint(text[i]) ||
text[i] == '\n' ||
(text[i] == '\r' && text[i + 1] == '\n'))
virBufferAddChar(&buf, text[i]);
else
virBufferAsprintf(&buf, "0x%02x", text[i]);
}
return virBufferContentAndReset(&buf);
}
#endif
static void
qemuMonitorDispose(void *obj)
{
qemuMonitorPtr mon = obj;
VIR_DEBUG("mon=%p", mon);
if (mon->cb && mon->cb->destroy)
(mon->cb->destroy)(mon, mon->vm, mon->callbackOpaque);
virObjectUnref(mon->vm);
virResetError(&mon->lastError);
virCondDestroy(&mon->notify);
VIR_FREE(mon->buffer);
virJSONValueFree(mon->options);
VIR_FREE(mon->balloonpath);
}
static int
qemuMonitorOpenUnix(const char *monitor, pid_t cpid)
{
struct sockaddr_un addr;
int monfd;
int timeout = 30; /* In seconds */
int ret;
size_t i = 0;
if ((monfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
virReportSystemError(errno,
"%s", _("failed to create socket"));
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
if (virStrcpyStatic(addr.sun_path, monitor) == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Monitor path %s too big for destination"), monitor);
goto error;
}
do {
ret = connect(monfd, (struct sockaddr *) &addr, sizeof(addr));
if (ret == 0)
break;
if ((errno == ENOENT || errno == ECONNREFUSED) &&
(!cpid || virProcessKill(cpid, 0) == 0)) {
/* ENOENT : Socket may not have shown up yet
* ECONNREFUSED : Leftover socket hasn't been removed yet */
continue;
}
virReportSystemError(errno, "%s",
_("failed to connect to monitor socket"));
goto error;
} while ((++i <= timeout*5) && (usleep(.2 * 1000000) <= 0));
if (ret != 0) {
virReportSystemError(errno, "%s",
_("monitor socket did not show up"));
goto error;
}
return monfd;
error:
VIR_FORCE_CLOSE(monfd);
return -1;
}
static int
qemuMonitorOpenPty(const char *monitor)
{
int monfd;
if ((monfd = open(monitor, O_RDWR)) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unable to open monitor path %s"), monitor);
return -1;
}
return monfd;
}
/* This method processes data that has been received
* from the monitor. Looking for async events and
* replies/errors.
*/
static int
qemuMonitorIOProcess(qemuMonitorPtr mon)
{
int len;
qemuMonitorMessagePtr msg = NULL;
/* See if there's a message & whether its ready for its reply
* ie whether its completed writing all its data */
if (mon->msg && mon->msg->txOffset == mon->msg->txLength)
msg = mon->msg;
#if DEBUG_IO
# if DEBUG_RAW_IO
char *str1 = qemuMonitorEscapeNonPrintable(msg ? msg->txBuffer : "");
char *str2 = qemuMonitorEscapeNonPrintable(mon->buffer);
VIR_ERROR(_("Process %d %p %p [[[[%s]]][[[%s]]]"), (int)mon->bufferOffset, mon->msg, msg, str1, str2);
VIR_FREE(str1);
VIR_FREE(str2);
# else
VIR_DEBUG("Process %d", (int)mon->bufferOffset);
# endif
#endif
PROBE(QEMU_MONITOR_IO_PROCESS,
"mon=%p buf=%s len=%zu", mon, mon->buffer, mon->bufferOffset);
if (mon->json)
len = qemuMonitorJSONIOProcess(mon,
mon->buffer, mon->bufferOffset,
msg);
else
len = qemuMonitorTextIOProcess(mon,
mon->buffer, mon->bufferOffset,
msg);
if (len < 0)
return -1;
if (len && mon->waitGreeting)
mon->waitGreeting = false;
if (len < mon->bufferOffset) {
memmove(mon->buffer, mon->buffer + len, mon->bufferOffset - len);
mon->bufferOffset -= len;
} else {
VIR_FREE(mon->buffer);
mon->bufferOffset = mon->bufferLength = 0;
}
#if DEBUG_IO
VIR_DEBUG("Process done %d used %d", (int)mon->bufferOffset, len);
#endif
if (msg && msg->finished)
virCondBroadcast(&mon->notify);
return len;
}
/* Call this function while holding the monitor lock. */
static int
qemuMonitorIOWriteWithFD(qemuMonitorPtr mon,
const char *data,
size_t len,
int fd)
{
struct msghdr msg;
struct iovec iov[1];
int ret;
char control[CMSG_SPACE(sizeof(int))];
struct cmsghdr *cmsg;
memset(&msg, 0, sizeof(msg));
memset(control, 0, sizeof(control));
iov[0].iov_base = (void *)data;
iov[0].iov_len = len;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
cmsg = CMSG_FIRSTHDR(&msg);
/* Some static analyzers, like clang 2.6-0.6.pre2, fail to see
that our use of CMSG_FIRSTHDR will not return NULL. */
sa_assert(cmsg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
do {
ret = sendmsg(mon->fd, &msg, 0);
} while (ret < 0 && errno == EINTR);
return ret;
}
/*
* Called when the monitor is able to write data
* Call this function while holding the monitor lock.
*/
static int
qemuMonitorIOWrite(qemuMonitorPtr mon)
{
int done;
char *buf;
size_t len;
/* If no active message, or fully transmitted, the no-op */
if (!mon->msg || mon->msg->txOffset == mon->msg->txLength)
return 0;
if (mon->msg->txFD != -1 && !mon->hasSendFD) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Monitor does not support sending of file descriptors"));
return -1;
}
buf = mon->msg->txBuffer + mon->msg->txOffset;
len = mon->msg->txLength - mon->msg->txOffset;
if (mon->msg->txFD == -1)
done = write(mon->fd, buf, len);
else
done = qemuMonitorIOWriteWithFD(mon, buf, len, mon->msg->txFD);
PROBE(QEMU_MONITOR_IO_WRITE,
"mon=%p buf=%s len=%zu ret=%d errno=%d",
mon, buf, len, done, errno);
if (mon->msg->txFD != -1) {
PROBE(QEMU_MONITOR_IO_SEND_FD,
"mon=%p fd=%d ret=%d errno=%d",
mon, mon->msg->txFD, done, errno);
}
if (done < 0) {
if (errno == EAGAIN)
return 0;
virReportSystemError(errno, "%s",
_("Unable to write to monitor"));
return -1;
}
mon->msg->txOffset += done;
return done;
}
/*
* Called when the monitor has incoming data to read
* Call this function while holding the monitor lock.
*
* Returns -1 on error, or number of bytes read
*/
static int
qemuMonitorIORead(qemuMonitorPtr mon)
{
size_t avail = mon->bufferLength - mon->bufferOffset;
int ret = 0;
if (avail < 1024) {
if (VIR_REALLOC_N(mon->buffer,
mon->bufferLength + 1024) < 0)
return -1;
mon->bufferLength += 1024;
avail += 1024;
}
/* Read as much as we can get into our buffer,
until we block on EAGAIN, or hit EOF */
while (avail > 1) {
int got;
got = read(mon->fd,
mon->buffer + mon->bufferOffset,
avail - 1);
if (got < 0) {
if (errno == EAGAIN)
break;
virReportSystemError(errno, "%s",
_("Unable to read from monitor"));
ret = -1;
break;
}
if (got == 0)
break;
ret += got;
avail -= got;
mon->bufferOffset += got;
mon->buffer[mon->bufferOffset] = '\0';
}
#if DEBUG_IO
VIR_DEBUG("Now read %d bytes of data", (int)mon->bufferOffset);
#endif
return ret;
}
static void
qemuMonitorUpdateWatch(qemuMonitorPtr mon)
{
int events =
VIR_EVENT_HANDLE_HANGUP |
VIR_EVENT_HANDLE_ERROR;
if (!mon->watch)
return;
if (mon->lastError.code == VIR_ERR_OK) {
events |= VIR_EVENT_HANDLE_READABLE;
if ((mon->msg && mon->msg->txOffset < mon->msg->txLength) &&
!mon->waitGreeting)
events |= VIR_EVENT_HANDLE_WRITABLE;
}
virEventUpdateHandle(mon->watch, events);
}
static void
qemuMonitorIO(int watch, int fd, int events, void *opaque)
{
qemuMonitorPtr mon = opaque;
bool error = false;
bool eof = false;
bool hangup = false;
virObjectRef(mon);
/* lock access to the monitor and protect fd */
virObjectLock(mon);
#if DEBUG_IO
VIR_DEBUG("Monitor %p I/O on watch %d fd %d events %d", mon, watch, fd, events);
#endif
if (mon->fd == -1 || mon->watch == 0) {
virObjectUnlock(mon);
virObjectUnref(mon);
return;
}
if (mon->fd != fd || mon->watch != watch) {
if (events & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR))
eof = true;
virReportError(VIR_ERR_INTERNAL_ERROR,
_("event from unexpected fd %d!=%d / watch %d!=%d"),
mon->fd, fd, mon->watch, watch);
error = true;
} else if (mon->lastError.code != VIR_ERR_OK) {
if (events & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR))
eof = true;
error = true;
} else {
if (events & VIR_EVENT_HANDLE_WRITABLE) {
if (qemuMonitorIOWrite(mon) < 0) {
error = true;
if (errno == ECONNRESET)
hangup = true;
}
events &= ~VIR_EVENT_HANDLE_WRITABLE;
}
if (!error &&
events & VIR_EVENT_HANDLE_READABLE) {
int got = qemuMonitorIORead(mon);
events &= ~VIR_EVENT_HANDLE_READABLE;
if (got < 0) {
error = true;
if (errno == ECONNRESET)
hangup = true;
} else if (got == 0) {
eof = true;
} else {
/* Ignore hangup/error events if we read some data, to
* give time for that data to be consumed */
events = 0;
if (qemuMonitorIOProcess(mon) < 0)
error = true;
}
}
if (events & VIR_EVENT_HANDLE_HANGUP) {
hangup = true;
if (!error) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("End of file from monitor"));
eof = true;
events &= ~VIR_EVENT_HANDLE_HANGUP;
}
}
if (!error && !eof &&
events & VIR_EVENT_HANDLE_ERROR) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Invalid file descriptor while waiting for monitor"));
eof = true;
events &= ~VIR_EVENT_HANDLE_ERROR;
}
if (!error && events) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unhandled event %d for monitor fd %d"),
events, mon->fd);
error = true;
}
}
if (error || eof) {
if (hangup && mon->logFunc != NULL) {
/* Check if an error message from qemu is available and if so, use
* it to overwrite the actual message. It's done only in early
* startup phases or during incoming migration when the message
* from qemu is certainly more interesting than a
* "connection reset by peer" message.
*/
mon->logFunc(mon,
_("early end of file from monitor, "
"possible problem"),
mon->logOpaque);
virCopyLastError(&mon->lastError);
virResetLastError();
}
if (mon->lastError.code != VIR_ERR_OK) {
/* Already have an error, so clear any new error */
virResetLastError();
} else {
virErrorPtr err = virGetLastError();
if (!err)
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Error while processing monitor IO"));
virCopyLastError(&mon->lastError);
virResetLastError();
}
VIR_DEBUG("Error on monitor %s", NULLSTR(mon->lastError.message));
/* If IO process resulted in an error & we have a message,
* then wakeup that waiter */
if (mon->msg && !mon->msg->finished) {
mon->msg->finished = 1;
virCondSignal(&mon->notify);
}
}
qemuMonitorUpdateWatch(mon);
/* We have to unlock to avoid deadlock against command thread,
* but is this safe ? I think it is, because the callback
* will try to acquire the virDomainObjPtr mutex next */
if (eof) {
qemuMonitorEofNotifyCallback eofNotify = mon->cb->eofNotify;
virDomainObjPtr vm = mon->vm;
/* Make sure anyone waiting wakes up now */
virCondSignal(&mon->notify);
virObjectUnlock(mon);
VIR_DEBUG("Triggering EOF callback");
(eofNotify)(mon, vm, mon->callbackOpaque);
virObjectUnref(mon);
} else if (error) {
qemuMonitorErrorNotifyCallback errorNotify = mon->cb->errorNotify;
virDomainObjPtr vm = mon->vm;
/* Make sure anyone waiting wakes up now */
virCondSignal(&mon->notify);
virObjectUnlock(mon);
VIR_DEBUG("Triggering error callback");
(errorNotify)(mon, vm, mon->callbackOpaque);
virObjectUnref(mon);
} else {
virObjectUnlock(mon);
virObjectUnref(mon);
}
}
static qemuMonitorPtr
qemuMonitorOpenInternal(virDomainObjPtr vm,
int fd,
bool hasSendFD,
bool json,
qemuMonitorCallbacksPtr cb,
void *opaque)
{
qemuMonitorPtr mon;
if (!cb->eofNotify) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("EOF notify callback must be supplied"));
return NULL;
}
if (!cb->errorNotify) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Error notify callback must be supplied"));
return NULL;
}
if (qemuMonitorInitialize() < 0)
return NULL;
if (!(mon = virObjectLockableNew(qemuMonitorClass)))
return NULL;
if (virCondInit(&mon->notify) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot initialize monitor condition"));
goto cleanup;
}
mon->fd = fd;
mon->hasSendFD = hasSendFD;
mon->vm = virObjectRef(vm);
mon->json = json;
if (json)
mon->waitGreeting = true;
mon->cb = cb;
mon->callbackOpaque = opaque;
if (virSetCloseExec(mon->fd) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Unable to set monitor close-on-exec flag"));
goto cleanup;
}
if (virSetNonBlock(mon->fd) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("Unable to put monitor into non-blocking mode"));
goto cleanup;
}
virObjectLock(mon);
virObjectRef(mon);
if ((mon->watch = virEventAddHandle(mon->fd,
VIR_EVENT_HANDLE_HANGUP |
VIR_EVENT_HANDLE_ERROR |
VIR_EVENT_HANDLE_READABLE,
qemuMonitorIO,
mon,
virObjectFreeCallback)) < 0) {
virObjectUnref(mon);
virObjectUnlock(mon);
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("unable to register monitor events"));
goto cleanup;
}
PROBE(QEMU_MONITOR_NEW,
"mon=%p refs=%d fd=%d",
mon, mon->parent.parent.u.s.refs, mon->fd);
virObjectUnlock(mon);
return mon;
cleanup:
/* We don't want the 'destroy' callback invoked during
* cleanup from construction failure, because that can
* give a double-unref on virDomainObjPtr in the caller,
* so kill the callbacks now.
*/
mon->cb = NULL;
/* The caller owns 'fd' on failure */
mon->fd = -1;
qemuMonitorClose(mon);
return NULL;
}
qemuMonitorPtr
qemuMonitorOpen(virDomainObjPtr vm,
virDomainChrSourceDefPtr config,
bool json,
qemuMonitorCallbacksPtr cb,
void *opaque)
{
int fd;
bool hasSendFD = false;
qemuMonitorPtr ret;
switch (config->type) {
case VIR_DOMAIN_CHR_TYPE_UNIX:
hasSendFD = true;
if ((fd = qemuMonitorOpenUnix(config->data.nix.path, vm ? vm->pid : 0)) < 0)
return NULL;
break;
case VIR_DOMAIN_CHR_TYPE_PTY:
if ((fd = qemuMonitorOpenPty(config->data.file.path)) < 0)
return NULL;
break;
default:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unable to handle monitor type: %s"),
virDomainChrTypeToString(config->type));
return NULL;
}
ret = qemuMonitorOpenInternal(vm, fd, hasSendFD, json, cb, opaque);
if (!ret)
VIR_FORCE_CLOSE(fd);
return ret;
}
qemuMonitorPtr
qemuMonitorOpenFD(virDomainObjPtr vm,
int sockfd,
bool json,
qemuMonitorCallbacksPtr cb,
void *opaque)
{
return qemuMonitorOpenInternal(vm, sockfd, true, json, cb, opaque);
}
void
qemuMonitorClose(qemuMonitorPtr mon)
{
if (!mon)
return;
virObjectLock(mon);
PROBE(QEMU_MONITOR_CLOSE,
"mon=%p refs=%d", mon, mon->parent.parent.u.s.refs);
qemuMonitorSetDomainLog(mon, NULL, NULL, NULL);
if (mon->fd >= 0) {
if (mon->watch) {
virEventRemoveHandle(mon->watch);
mon->watch = 0;
}
VIR_FORCE_CLOSE(mon->fd);
}
/* In case another thread is waiting for its monitor command to be
* processed, we need to wake it up with appropriate error set.
*/
if (mon->msg) {
if (mon->lastError.code == VIR_ERR_OK) {
virErrorPtr err = virSaveLastError();
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("Qemu monitor was closed"));
virCopyLastError(&mon->lastError);
if (err) {
virSetError(err);
virFreeError(err);
} else {
virResetLastError();
}
}
mon->msg->finished = 1;
virCondSignal(&mon->notify);
}
/* Propagate existing monitor error in case the current thread has no
* error set.
*/
if (mon->lastError.code != VIR_ERR_OK && !virGetLastError())
virSetError(&mon->lastError);
virObjectUnlock(mon);
virObjectUnref(mon);
}
char *
qemuMonitorNextCommandID(qemuMonitorPtr mon)
{
char *id;
ignore_value(virAsprintf(&id, "libvirt-%d", ++mon->nextSerial));
return id;
}
int
qemuMonitorSend(qemuMonitorPtr mon,
qemuMonitorMessagePtr msg)
{
int ret = -1;
/* Check whether qemu quit unexpectedly */
if (mon->lastError.code != VIR_ERR_OK) {
VIR_DEBUG("Attempt to send command while error is set %s",
NULLSTR(mon->lastError.message));
virSetError(&mon->lastError);
return -1;
}
mon->msg = msg;
qemuMonitorUpdateWatch(mon);
PROBE(QEMU_MONITOR_SEND_MSG,
"mon=%p msg=%s fd=%d",
mon, mon->msg->txBuffer, mon->msg->txFD);
while (!mon->msg->finished) {
if (virCondWait(&mon->notify, &mon->parent.lock) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Unable to wait on monitor condition"));
goto cleanup;
}
}
if (mon->lastError.code != VIR_ERR_OK) {
VIR_DEBUG("Send command resulted in error %s",
NULLSTR(mon->lastError.message));
virSetError(&mon->lastError);
goto cleanup;
}
ret = 0;
cleanup:
mon->msg = NULL;
qemuMonitorUpdateWatch(mon);
return ret;
}
/**
* This function returns a new virError object; the caller is responsible
* for freeing it.
*/
virErrorPtr
qemuMonitorLastError(qemuMonitorPtr mon)
{
if (mon->lastError.code == VIR_ERR_OK)
return NULL;
return virErrorCopyNew(&mon->lastError);
}
virJSONValuePtr
qemuMonitorGetOptions(qemuMonitorPtr mon)
{
return mon->options;
}
void
qemuMonitorSetOptions(qemuMonitorPtr mon, virJSONValuePtr options)
{
mon->options = options;
}
/**
* Search the qom objects for the balloon driver object by its known names
* of "virtio-balloon-pci" or "virtio-balloon-ccw". The entry for the driver
* will be found by using function "qemuMonitorJSONFindLinkPath".
*
* Once found, check the entry to ensure it has the correct property listed.
* If it does not, then obtaining statistics from QEMU will not be possible.
* This feature was added to QEMU 1.5.
*/
static void
qemuMonitorInitBalloonObjectPath(qemuMonitorPtr mon)
{
ssize_t i, nprops = 0;
int flp_ret = 0;
char *path = NULL;
qemuMonitorJSONListPathPtr *bprops = NULL;
if (mon->balloonpath) {
return;
} else if (mon->ballooninit) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot determine balloon device path"));
return;
}
mon->ballooninit = true;
flp_ret = qemuMonitorJSONFindLinkPath(mon, "virtio-balloon-pci", &path);
if (flp_ret == -2) {
/* pci object was not found retry search for ccw object */
if (qemuMonitorJSONFindLinkPath(mon, "virtio-balloon-ccw", &path) < 0)
return;
} else if (flp_ret < 0) {
return;
}
nprops = qemuMonitorJSONGetObjectListPaths(mon, path, &bprops);
if (nprops < 0)
goto cleanup;
for (i = 0; i < nprops; i++) {
if (STREQ(bprops[i]->name, "guest-stats-polling-interval")) {
VIR_DEBUG("Found Balloon Object Path %s", path);
mon->balloonpath = path;
path = NULL;
goto cleanup;
}
}
/* If we get here, we found the path, but not the property */
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Property 'guest-stats-polling-interval' "
"not found on memory balloon driver."));
cleanup:
for (i = 0; i < nprops; i++)
qemuMonitorJSONListPathFree(bprops[i]);
VIR_FREE(bprops);
VIR_FREE(path);
return;
}
/**
* To update video memory size in status XML we need to load correct values from
* QEMU. This is supported only with JSON monitor.
*
* Returns 0 on success, -1 on failure and sets proper error message.
*/
int
qemuMonitorUpdateVideoMemorySize(qemuMonitorPtr mon,
virDomainVideoDefPtr video,
const char *videoName)
{
int ret = -1;
char *path = NULL;
QEMU_CHECK_MONITOR(mon);
if (mon->json) {
ret = qemuMonitorJSONFindLinkPath(mon, videoName, &path);
if (ret < 0) {
if (ret == -2)
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to find QOM Object path for "
"device '%s'"), videoName);
return -1;
}
ret = qemuMonitorJSONUpdateVideoMemorySize(mon, video, path);
VIR_FREE(path);
return ret;
}
return 0;
}
int
qemuMonitorHMPCommandWithFd(qemuMonitorPtr mon,
const char *cmd,
int scm_fd,
char **reply)
{
char *json_cmd = NULL;
int ret = -1;
QEMU_CHECK_MONITOR(mon);
if (mon->json) {
/* hack to avoid complicating each call to text monitor functions */
json_cmd = qemuMonitorUnescapeArg(cmd);
if (!json_cmd) {
VIR_DEBUG("Could not unescape command: %s", cmd);
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Unable to unescape command"));
goto cleanup;
}
ret = qemuMonitorJSONHumanCommandWithFd(mon, json_cmd, scm_fd, reply);
} else {
ret = qemuMonitorTextCommandWithFd(mon, cmd, scm_fd, reply);
}
cleanup:
VIR_FREE(json_cmd);
return ret;
}
/* Ensure proper locking around callbacks. */
#define QEMU_MONITOR_CALLBACK(mon, ret, callback, ...) \
do { \
virObjectRef(mon); \
virObjectUnlock(mon); \
if ((mon)->cb && (mon)->cb->callback) \
(ret) = (mon)->cb->callback(mon, __VA_ARGS__, \
(mon)->callbackOpaque); \
virObjectLock(mon); \
virObjectUnref(mon); \
} while (0)
int
qemuMonitorGetDiskSecret(qemuMonitorPtr mon,
virConnectPtr conn,
const char *path,
char **secret,
size_t *secretLen)
{
int ret = -1;
*secret = NULL;
*secretLen = 0;
QEMU_MONITOR_CALLBACK(mon, ret, diskSecretLookup, conn, mon->vm,
path, secret, secretLen);
return ret;
}
int
qemuMonitorEmitEvent(qemuMonitorPtr mon, const char *event,
long long seconds, unsigned int micros,
const char *details)
{
int ret = -1;
VIR_DEBUG("mon=%p event=%s", mon, event);
QEMU_MONITOR_CALLBACK(mon, ret, domainEvent, mon->vm, event, seconds,
micros, details);
return ret;
}
int
qemuMonitorEmitShutdown(qemuMonitorPtr mon)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainShutdown, mon->vm);
return ret;
}
int
qemuMonitorEmitReset(qemuMonitorPtr mon)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainReset, mon->vm);
return ret;
}
int
qemuMonitorEmitPowerdown(qemuMonitorPtr mon)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainPowerdown, mon->vm);
return ret;
}
int
qemuMonitorEmitStop(qemuMonitorPtr mon)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainStop, mon->vm);
return ret;
}
int
qemuMonitorEmitResume(qemuMonitorPtr mon)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainResume, mon->vm);
return ret;
}
int
qemuMonitorEmitGuestPanic(qemuMonitorPtr mon)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainGuestPanic, mon->vm);
return ret;
}
int
qemuMonitorEmitRTCChange(qemuMonitorPtr mon, long long offset)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainRTCChange, mon->vm, offset);
return ret;
}
int
qemuMonitorEmitWatchdog(qemuMonitorPtr mon, int action)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainWatchdog, mon->vm, action);
return ret;
}
int
qemuMonitorEmitIOError(qemuMonitorPtr mon,
const char *diskAlias,
int action,
const char *reason)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainIOError, mon->vm,
diskAlias, action, reason);
return ret;
}
int
qemuMonitorEmitGraphics(qemuMonitorPtr mon,
int phase,
int localFamily,
const char *localNode,
const char *localService,
int remoteFamily,
const char *remoteNode,
const char *remoteService,
const char *authScheme,
const char *x509dname,
const char *saslUsername)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainGraphics, mon->vm, phase,
localFamily, localNode, localService,
remoteFamily, remoteNode, remoteService,
authScheme, x509dname, saslUsername);
return ret;
}
int
qemuMonitorEmitTrayChange(qemuMonitorPtr mon,
const char *devAlias,
int reason)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainTrayChange, mon->vm,
devAlias, reason);
return ret;
}
int
qemuMonitorEmitPMWakeup(qemuMonitorPtr mon)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainPMWakeup, mon->vm);
return ret;
}
int
qemuMonitorEmitPMSuspend(qemuMonitorPtr mon)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainPMSuspend, mon->vm);
return ret;
}
int
qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainPMSuspendDisk, mon->vm);
return ret;
}
int
qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
const char *diskAlias,
int type,
int status)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainBlockJob, mon->vm,
diskAlias, type, status);
return ret;
}
int
qemuMonitorEmitBalloonChange(qemuMonitorPtr mon,
unsigned long long actual)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainBalloonChange, mon->vm, actual);
return ret;
}
int
qemuMonitorEmitDeviceDeleted(qemuMonitorPtr mon,
const char *devAlias)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainDeviceDeleted, mon->vm, devAlias);
return ret;
}
int
qemuMonitorEmitNicRxFilterChanged(qemuMonitorPtr mon,
const char *devAlias)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainNicRxFilterChanged, mon->vm, devAlias);
return ret;
}
int
qemuMonitorEmitSerialChange(qemuMonitorPtr mon,
const char *devAlias,
bool connected)
{
int ret = -1;
VIR_DEBUG("mon=%p, devAlias='%s', connected=%d", mon, devAlias, connected);
QEMU_MONITOR_CALLBACK(mon, ret, domainSerialChange, mon->vm, devAlias, connected);
return ret;
}
int
qemuMonitorEmitSpiceMigrated(qemuMonitorPtr mon)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainSpiceMigrated, mon->vm);
return ret;
}
int
qemuMonitorEmitMigrationStatus(qemuMonitorPtr mon,
int status)
{
int ret = -1;
VIR_DEBUG("mon=%p, status=%s",
mon, NULLSTR(qemuMonitorMigrationStatusTypeToString(status)));
QEMU_MONITOR_CALLBACK(mon, ret, domainMigrationStatus, mon->vm, status);
return ret;
}
int
qemuMonitorSetCapabilities(qemuMonitorPtr mon)
{
QEMU_CHECK_MONITOR(mon);
if (!mon->json)
return 0;
return qemuMonitorJSONSetCapabilities(mon);
}
int
qemuMonitorStartCPUs(qemuMonitorPtr mon,
virConnectPtr conn)
{
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONStartCPUs(mon, conn);
else
return qemuMonitorTextStartCPUs(mon, conn);
}
int
qemuMonitorStopCPUs(qemuMonitorPtr mon)
{
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONStopCPUs(mon);
else
return qemuMonitorTextStopCPUs(mon);
}
int
qemuMonitorGetStatus(qemuMonitorPtr mon,
bool *running,
virDomainPausedReason *reason)
{
VIR_DEBUG("running=%p, reason=%p", running, reason);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONGetStatus(mon, running, reason);
else
return qemuMonitorTextGetStatus(mon, running, reason);
}
int
qemuMonitorSystemPowerdown(qemuMonitorPtr mon)
{
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONSystemPowerdown(mon);
else
return qemuMonitorTextSystemPowerdown(mon);
}
int
qemuMonitorSystemReset(qemuMonitorPtr mon)
{
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONSystemReset(mon);
else
return qemuMonitorTextSystemReset(mon);
}
/**
* qemuMonitorGetCPUInfo:
* @mon: monitor
* @pids: returned array of thread ids corresponding to the vCPUs
*
* Detects the vCPU thread ids. Returns count of detected vCPUs on success,
* 0 if qemu didn't report thread ids (does not report libvirt error),
* -1 on error (reports libvirt error).
*/
int
qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
int **pids)
{
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONGetCPUInfo(mon, pids);
else
return qemuMonitorTextGetCPUInfo(mon, pids);
}
int
qemuMonitorSetLink(qemuMonitorPtr mon,
const char *name,
virDomainNetInterfaceLinkState state)
{
VIR_DEBUG("name=%s, state=%u", name, state);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONSetLink(mon, name, state);
else
return qemuMonitorTextSetLink(mon, name, state);
}
int
qemuMonitorGetVirtType(qemuMonitorPtr mon,
virDomainVirtType *virtType)
{
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONGetVirtType(mon, virtType);
else
return qemuMonitorTextGetVirtType(mon, virtType);
}
/**
* Returns: 0 if balloon not supported, +1 if balloon query worked
* or -1 on failure
*/
int
qemuMonitorGetBalloonInfo(qemuMonitorPtr mon,
unsigned long long *currmem)
{
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONGetBalloonInfo(mon, currmem);
else
return qemuMonitorTextGetBalloonInfo(mon, currmem);
}
int
qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
virDomainMemoryStatPtr stats,
unsigned int nr_stats)
{
VIR_DEBUG("stats=%p nstats=%u", stats, nr_stats);
QEMU_CHECK_MONITOR(mon);
if (mon->json) {
qemuMonitorInitBalloonObjectPath(mon);
return qemuMonitorJSONGetMemoryStats(mon, mon->balloonpath,
stats, nr_stats);
} else {
return qemuMonitorTextGetMemoryStats(mon, stats, nr_stats);
}
}
/**
* qemuMonitorSetMemoryStatsPeriod:
*
* This function sets balloon stats update period.
*
* Returns 0 on success and -1 on error, but does *not* set an error.
*/
int
qemuMonitorSetMemoryStatsPeriod(qemuMonitorPtr mon,
int period)
{
int ret = -1;
VIR_DEBUG("mon=%p period=%d", mon, period);
if (!mon)
return -1;
if (!mon->json)
return -1;
if (period < 0)
return -1;
qemuMonitorInitBalloonObjectPath(mon);
if (mon->balloonpath) {
ret = qemuMonitorJSONSetMemoryStatsPeriod(mon, mon->balloonpath,
period);
/*
* Most of the calls to this function are supposed to be
* non-fatal and the only one that should be fatal wants its
* own error message. More details for debugging will be in
* the log file.
*/
if (ret < 0)
virResetLastError();
}
return ret;
}
int
qemuMonitorBlockIOStatusToError(const char *status)
{
int st = qemuMonitorBlockIOStatusTypeFromString(status);
if (st < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown block IO status: %s"), status);
return -1;
}
switch ((qemuMonitorBlockIOStatus) st) {
case QEMU_MONITOR_BLOCK_IO_STATUS_OK:
return VIR_DOMAIN_DISK_ERROR_NONE;
case QEMU_MONITOR_BLOCK_IO_STATUS_FAILED:
return VIR_DOMAIN_DISK_ERROR_UNSPEC;
case QEMU_MONITOR_BLOCK_IO_STATUS_NOSPACE:
return VIR_DOMAIN_DISK_ERROR_NO_SPACE;
/* unreachable */
case QEMU_MONITOR_BLOCK_IO_STATUS_LAST:
break;
}
return -1;
}
virHashTablePtr
qemuMonitorGetBlockInfo(qemuMonitorPtr mon)
{
int ret;
virHashTablePtr table;
QEMU_CHECK_MONITOR_NULL(mon);
if (!(table = virHashCreate(32, virHashValueFree)))
return NULL;
if (mon->json)
ret = qemuMonitorJSONGetBlockInfo(mon, table);
else
ret = qemuMonitorTextGetBlockInfo(mon, table);
if (ret < 0) {
virHashFree(table);
return NULL;
}
return table;
}
struct qemuDomainDiskInfo *
qemuMonitorBlockInfoLookup(virHashTablePtr blockInfo,
const char *dev)
{
struct qemuDomainDiskInfo *info;
VIR_DEBUG("blockInfo=%p dev=%s", blockInfo, NULLSTR(dev));
if (!(info = virHashLookup(blockInfo, dev))) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot find info for device '%s'"),
NULLSTR(dev));
}
return info;
}
/**
* qemuMonitorGetAllBlockStatsInfo:
* @mon: monitor object
* @ret_stats: pointer that is filled with a hash table containing the stats
* @backingChain: recurse into the backing chain of devices
*
* Creates a hash table in @ret_stats with block stats of all devices. In case
* @backingChain is true @ret_stats will additionally contain stats for
* backing chain members of block devices.
*
* Returns < 0 on error, count of supported block stats fields on success.
*/
int
qemuMonitorGetAllBlockStatsInfo(qemuMonitorPtr mon,
virHashTablePtr *ret_stats,
bool backingChain)
{
int ret = -1;
VIR_DEBUG("ret_stats=%p, backing=%d", ret_stats, backingChain);
QEMU_CHECK_MONITOR(mon);
if (!(*ret_stats = virHashCreate(10, virHashValueFree)))
goto error;
if (mon->json) {
ret = qemuMonitorJSONGetAllBlockStatsInfo(mon, *ret_stats,
backingChain);
} else {
if (backingChain) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("text monitor doesn't support block stats for "
"backing chain members"));
goto error;
}
ret = qemuMonitorTextGetAllBlockStatsInfo(mon, *ret_stats);
}
if (ret < 0)
goto error;
return ret;
error:
virHashFree(*ret_stats);
*ret_stats = NULL;
return -1;
}
/* Updates "stats" to fill virtual and physical size of the image */
int
qemuMonitorBlockStatsUpdateCapacity(qemuMonitorPtr mon,
virHashTablePtr stats,
bool backingChain)
{
VIR_DEBUG("stats=%p, backing=%d", stats, backingChain);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONBlockStatsUpdateCapacity(mon, stats, backingChain);
}
int
qemuMonitorBlockResize(qemuMonitorPtr mon,
const char *device,
unsigned long long size)
{
VIR_DEBUG("device=%s size=%llu", device, size);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONBlockResize(mon, device, size);
else
return qemuMonitorTextBlockResize(mon, device, size);
}
int
qemuMonitorSetVNCPassword(qemuMonitorPtr mon,
const char *password)
{
VIR_DEBUG("password=%p", password);
QEMU_CHECK_MONITOR(mon);
if (!password)
password = "";
if (mon->json)
return qemuMonitorJSONSetVNCPassword(mon, password);
else
return qemuMonitorTextSetVNCPassword(mon, password);
}
static const char *
qemuMonitorTypeToProtocol(int type)
{
switch (type) {
case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
return "vnc";
case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
return "spice";
default:
virReportError(VIR_ERR_INVALID_ARG,
_("unsupported protocol type %s"),
virDomainGraphicsTypeToString(type));
return NULL;
}
}
/* Returns -2 if not supported with this monitor connection */
int
qemuMonitorSetPassword(qemuMonitorPtr mon,
int type,
const char *password,
const char *action_if_connected)
{
const char *protocol = qemuMonitorTypeToProtocol(type);
if (!protocol)
return -1;
VIR_DEBUG("protocol=%s, password=%p, action_if_connected=%s",
protocol, password, action_if_connected);
QEMU_CHECK_MONITOR(mon);
if (!password)
password = "";
if (!action_if_connected)
action_if_connected = "keep";
if (mon->json)
return qemuMonitorJSONSetPassword(mon, protocol, password, action_if_connected);
else
return qemuMonitorTextSetPassword(mon, protocol, password, action_if_connected);
}
int
qemuMonitorExpirePassword(qemuMonitorPtr mon,
int type,
const char *expire_time)
{
const char *protocol = qemuMonitorTypeToProtocol(type);
if (!protocol)
return -1;
VIR_DEBUG("protocol=%s, expire_time=%s", protocol, expire_time);
QEMU_CHECK_MONITOR(mon);
if (!expire_time)
expire_time = "now";
if (mon->json)
return qemuMonitorJSONExpirePassword(mon, protocol, expire_time);
else
return qemuMonitorTextExpirePassword(mon, protocol, expire_time);
}
/*
* Returns: 0 if balloon not supported, +1 if balloon adjust worked
* or -1 on failure
*/
int
qemuMonitorSetBalloon(qemuMonitorPtr mon,
unsigned long long newmem)
{
VIR_DEBUG("newmem=%llu", newmem);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONSetBalloon(mon, newmem);
else
return qemuMonitorTextSetBalloon(mon, newmem);
}
int
qemuMonitorSetCPU(qemuMonitorPtr mon, int cpu, bool online)
{
VIR_DEBUG("cpu=%d online=%d", cpu, online);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONSetCPU(mon, cpu, online);
else
return qemuMonitorTextSetCPU(mon, cpu, online);
}
int
qemuMonitorEjectMedia(qemuMonitorPtr mon,
const char *dev_name,
bool force)
{
VIR_DEBUG("dev_name=%s force=%d", dev_name, force);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONEjectMedia(mon, dev_name, force);
else
return qemuMonitorTextEjectMedia(mon, dev_name, force);
}
int
qemuMonitorChangeMedia(qemuMonitorPtr mon,
const char *dev_name,
const char *newmedia,
const char *format)
{
VIR_DEBUG("dev_name=%s newmedia=%s format=%s", dev_name, newmedia, format);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONChangeMedia(mon, dev_name, newmedia, format);
else
return qemuMonitorTextChangeMedia(mon, dev_name, newmedia, format);
}
int
qemuMonitorSaveVirtualMemory(qemuMonitorPtr mon,
unsigned long long offset,
size_t length,
const char *path)
{
VIR_DEBUG("offset=%llu length=%zu path=%s", offset, length, path);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONSaveVirtualMemory(mon, offset, length, path);
else
return qemuMonitorTextSaveVirtualMemory(mon, offset, length, path);
}
int
qemuMonitorSavePhysicalMemory(qemuMonitorPtr mon,
unsigned long long offset,
size_t length,
const char *path)
{
VIR_DEBUG("offset=%llu length=%zu path=%s", offset, length, path);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONSavePhysicalMemory(mon, offset, length, path);
else
return qemuMonitorTextSavePhysicalMemory(mon, offset, length, path);
}
int
qemuMonitorSetMigrationSpeed(qemuMonitorPtr mon,
unsigned long bandwidth)
{
VIR_DEBUG("bandwidth=%lu", bandwidth);
QEMU_CHECK_MONITOR(mon);
if (bandwidth > QEMU_DOMAIN_MIG_BANDWIDTH_MAX) {
virReportError(VIR_ERR_OVERFLOW,
_("bandwidth must be less than %llu"),
QEMU_DOMAIN_MIG_BANDWIDTH_MAX + 1ULL);
return -1;
}
if (mon->json)
return qemuMonitorJSONSetMigrationSpeed(mon, bandwidth);
else
return qemuMonitorTextSetMigrationSpeed(mon, bandwidth);
}
int
qemuMonitorSetMigrationDowntime(qemuMonitorPtr mon,
unsigned long long downtime)
{
VIR_DEBUG("downtime=%llu", downtime);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONSetMigrationDowntime(mon, downtime);
else
return qemuMonitorTextSetMigrationDowntime(mon, downtime);
}
int
qemuMonitorGetMigrationCacheSize(qemuMonitorPtr mon,
unsigned long long *cacheSize)
{
VIR_DEBUG("cacheSize=%p", cacheSize);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONGetMigrationCacheSize(mon, cacheSize);
}
int
qemuMonitorSetMigrationCacheSize(qemuMonitorPtr mon,
unsigned long long cacheSize)
{
VIR_DEBUG("cacheSize=%llu", cacheSize);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONSetMigrationCacheSize(mon, cacheSize);
}
int
qemuMonitorGetMigrationStatus(qemuMonitorPtr mon,
qemuMonitorMigrationStatusPtr status)
{
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONGetMigrationStatus(mon, status);
else
return qemuMonitorTextGetMigrationStatus(mon, status);
}
int
qemuMonitorMigrateToFd(qemuMonitorPtr mon,
unsigned int flags,
int fd)
{
int ret;
VIR_DEBUG("fd=%d flags=%x", fd, flags);
QEMU_CHECK_MONITOR(mon);
if (qemuMonitorSendFileHandle(mon, "migrate", fd) < 0)
return -1;
if (mon->json)
ret = qemuMonitorJSONMigrate(mon, flags, "fd:migrate");
else
ret = qemuMonitorTextMigrate(mon, flags, "fd:migrate");
if (ret < 0) {
if (qemuMonitorCloseFileHandle(mon, "migrate") < 0)
VIR_WARN("failed to close migration handle");
}
return ret;
}
int
qemuMonitorMigrateToHost(qemuMonitorPtr mon,
unsigned int flags,
const char *protocol,
const char *hostname,
int port)
{
int ret;
char *uri = NULL;
VIR_DEBUG("hostname=%s port=%d flags=%x", hostname, port, flags);
QEMU_CHECK_MONITOR(mon);
if (virAsprintf(&uri, "%s:%s:%d", protocol, hostname, port) < 0)
return -1;
if (mon->json)
ret = qemuMonitorJSONMigrate(mon, flags, uri);
else
ret = qemuMonitorTextMigrate(mon, flags, uri);
VIR_FREE(uri);
return ret;
}
int
qemuMonitorMigrateToCommand(qemuMonitorPtr mon,
unsigned int flags,
const char * const *argv)
{
char *argstr;
char *dest = NULL;
int ret = -1;
VIR_DEBUG("argv=%p flags=%x", argv, flags);
QEMU_CHECK_MONITOR(mon);
argstr = virArgvToString(argv);
if (!argstr)
goto cleanup;
if (virAsprintf(&dest, "exec:%s", argstr) < 0)
goto cleanup;
if (mon->json)
ret = qemuMonitorJSONMigrate(mon, flags, dest);
else
ret = qemuMonitorTextMigrate(mon, flags, dest);
cleanup:
VIR_FREE(argstr);
VIR_FREE(dest);
return ret;
}
int
qemuMonitorMigrateToFile(qemuMonitorPtr mon,
unsigned int flags,
const char * const *argv,
const char *target,
unsigned long long offset)
{
char *argstr;
char *dest = NULL;
int ret = -1;
char *safe_target = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
VIR_DEBUG("argv=%p target=%s offset=%llu flags=%x",
argv, target, offset, flags);
QEMU_CHECK_MONITOR(mon);
if (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("file offset must be a multiple of %llu"),
QEMU_MONITOR_MIGRATE_TO_FILE_BS);
return -1;
}
argstr = virArgvToString(argv);
if (!argstr)
goto cleanup;
/* Migrate to file */
virBufferEscapeShell(&buf, target);
if (virBufferCheckError(&buf) < 0)
goto cleanup;
safe_target = virBufferContentAndReset(&buf);
/* Two dd processes, sharing the same stdout, are necessary to
* allow starting at an alignment of 512, but without wasting
* padding to get to the larger alignment useful for speed. Use
* <> redirection to avoid truncating a regular file. */
if (virAsprintf(&dest, "exec:" VIR_WRAPPER_SHELL_PREFIX "%s | "
"{ dd bs=%llu seek=%llu if=/dev/null && "
"dd ibs=%llu obs=%llu; } 1<>%s" VIR_WRAPPER_SHELL_SUFFIX,
argstr, QEMU_MONITOR_MIGRATE_TO_FILE_BS,
offset / QEMU_MONITOR_MIGRATE_TO_FILE_BS,
QEMU_MONITOR_MIGRATE_TO_FILE_TRANSFER_SIZE,
QEMU_MONITOR_MIGRATE_TO_FILE_TRANSFER_SIZE,
safe_target) < 0)
goto cleanup;
if (mon->json)
ret = qemuMonitorJSONMigrate(mon, flags, dest);
else
ret = qemuMonitorTextMigrate(mon, flags, dest);
cleanup:
VIR_FREE(safe_target);
VIR_FREE(argstr);
VIR_FREE(dest);
return ret;
}
int
qemuMonitorMigrateToUnix(qemuMonitorPtr mon,
unsigned int flags,
const char *unixfile)
{
char *dest = NULL;
int ret = -1;
VIR_DEBUG("unixfile=%s flags=%x", unixfile, flags);
QEMU_CHECK_MONITOR(mon);
if (virAsprintf(&dest, "unix:%s", unixfile) < 0)
return -1;
if (mon->json)
ret = qemuMonitorJSONMigrate(mon, flags, dest);
else
ret = qemuMonitorTextMigrate(mon, flags, dest);
VIR_FREE(dest);
return ret;
}
int
qemuMonitorMigrateCancel(qemuMonitorPtr mon)
{
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONMigrateCancel(mon);
else
return qemuMonitorTextMigrateCancel(mon);
}
/**
* Returns 1 if @capability is supported, 0 if it's not, or -1 on error.
*/
int
qemuMonitorGetDumpGuestMemoryCapability(qemuMonitorPtr mon,
const char *capability)
{
VIR_DEBUG("capability=%s", capability);
QEMU_CHECK_MONITOR(mon);
/* No capability is supported without JSON monitor */
if (!mon->json)
return 0;
return qemuMonitorJSONGetDumpGuestMemoryCapability(mon, capability);
}
int
qemuMonitorDumpToFd(qemuMonitorPtr mon, int fd, const char *dumpformat)
{
int ret;
VIR_DEBUG("fd=%d dumpformat=%s", fd, dumpformat);
QEMU_CHECK_MONITOR_JSON(mon);
if (qemuMonitorSendFileHandle(mon, "dump", fd) < 0)
return -1;
ret = qemuMonitorJSONDump(mon, "fd:dump", dumpformat);
if (ret < 0) {
if (qemuMonitorCloseFileHandle(mon, "dump") < 0)
VIR_WARN("failed to close dumping handle");
}
return ret;
}
int
qemuMonitorGraphicsRelocate(qemuMonitorPtr mon,
int type,
const char *hostname,
int port,
int tlsPort,
const char *tlsSubject)
{
VIR_DEBUG("type=%d hostname=%s port=%d tlsPort=%d tlsSubject=%s",
type, hostname, port, tlsPort, NULLSTR(tlsSubject));
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONGraphicsRelocate(mon,
type,
hostname,
port,
tlsPort,
tlsSubject);
else
return qemuMonitorTextGraphicsRelocate(mon,
type,
hostname,
port,
tlsPort,
tlsSubject);
}
int
qemuMonitorAddUSBDisk(qemuMonitorPtr mon,
const char *path)
{
VIR_DEBUG("path=%s", path);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONAddUSBDisk(mon, path);
else
return qemuMonitorTextAddUSBDisk(mon, path);
}
int
qemuMonitorAddUSBDeviceExact(qemuMonitorPtr mon,
int bus,
int dev)
{
VIR_DEBUG("bus=%d dev=%d", bus, dev);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONAddUSBDeviceExact(mon, bus, dev);
else
return qemuMonitorTextAddUSBDeviceExact(mon, bus, dev);
}
int
qemuMonitorAddUSBDeviceMatch(qemuMonitorPtr mon,
int vendor,
int product)
{
VIR_DEBUG("vendor=%d product=%d", vendor, product);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONAddUSBDeviceMatch(mon, vendor, product);
else
return qemuMonitorTextAddUSBDeviceMatch(mon, vendor, product);
}
int
qemuMonitorAddPCIHostDevice(qemuMonitorPtr mon,
virDevicePCIAddress *hostAddr,
virDevicePCIAddress *guestAddr)
{
VIR_DEBUG("domain=%d bus=%d slot=%d function=%d",
hostAddr->domain, hostAddr->bus, hostAddr->slot, hostAddr->function);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONAddPCIHostDevice(mon, hostAddr, guestAddr);
else
return qemuMonitorTextAddPCIHostDevice(mon, hostAddr, guestAddr);
}
int
qemuMonitorAddPCIDisk(qemuMonitorPtr mon,
const char *path,
const char *bus,
virDevicePCIAddress *guestAddr)
{
VIR_DEBUG("path=%s bus=%s", path, bus);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONAddPCIDisk(mon, path, bus, guestAddr);
else
return qemuMonitorTextAddPCIDisk(mon, path, bus, guestAddr);
}
int
qemuMonitorAddPCINetwork(qemuMonitorPtr mon,
const char *nicstr,
virDevicePCIAddress *guestAddr)
{
VIR_DEBUG("nicstr=%s", nicstr);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONAddPCINetwork(mon, nicstr, guestAddr);
else
return qemuMonitorTextAddPCINetwork(mon, nicstr, guestAddr);
}
int
qemuMonitorRemovePCIDevice(qemuMonitorPtr mon,
virDevicePCIAddress *guestAddr)
{
VIR_DEBUG("domain=%d bus=%d slot=%d function=%d",
guestAddr->domain, guestAddr->bus, guestAddr->slot,
guestAddr->function);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONRemovePCIDevice(mon, guestAddr);
else
return qemuMonitorTextRemovePCIDevice(mon, guestAddr);
}
int
qemuMonitorSendFileHandle(qemuMonitorPtr mon,
const char *fdname,
int fd)
{
VIR_DEBUG("fdname=%s fd=%d", fdname, fd);
QEMU_CHECK_MONITOR(mon);
if (fd < 0) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("fd must be valid"));
return -1;
}
if (!mon->hasSendFD) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("qemu is not using a unix socket monitor, "
"cannot send fd %s"), fdname);
return -1;
}
if (mon->json)
return qemuMonitorJSONSendFileHandle(mon, fdname, fd);
else
return qemuMonitorTextSendFileHandle(mon, fdname, fd);
}
int
qemuMonitorCloseFileHandle(qemuMonitorPtr mon,
const char *fdname)
{
int ret = -1;
virErrorPtr error;
VIR_DEBUG("fdname=%s", fdname);
error = virSaveLastError();
QEMU_CHECK_MONITOR_GOTO(mon, cleanup);
if (mon->json)
ret = qemuMonitorJSONCloseFileHandle(mon, fdname);
else
ret = qemuMonitorTextCloseFileHandle(mon, fdname);
cleanup:
if (error) {
virSetError(error);
virFreeError(error);
}
return ret;
}
/* Add the open file descriptor FD into the non-negative set FDSET.
* If NAME is present, it will be passed along for logging purposes.
* Returns the counterpart fd that qemu received, or -1 on error. */
int
qemuMonitorAddFd(qemuMonitorPtr mon, int fdset, int fd, const char *name)
{
VIR_DEBUG("fdset=%d, fd=%d, name=%s", fdset, fd, NULLSTR(name));
QEMU_CHECK_MONITOR_JSON(mon);
if (fd < 0 || fdset < 0) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("fd and fdset must be valid"));
return -1;
}
if (!mon->hasSendFD) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("qemu is not using a unix socket monitor, "
"cannot send fd %s"), NULLSTR(name));
return -1;
}
return qemuMonitorJSONAddFd(mon, fdset, fd, name);
}
/* Remove one of qemu's fds from the given FDSET, or if FD is
* negative, remove the entire set. Preserve any previous error on
* entry. Returns 0 on success, -1 on error. */
int
qemuMonitorRemoveFd(qemuMonitorPtr mon, int fdset, int fd)
{
int ret = -1;
virErrorPtr error;
VIR_DEBUG("fdset=%d, fd=%d", fdset, fd);
error = virSaveLastError();
QEMU_CHECK_MONITOR_JSON_GOTO(mon, cleanup);
ret = qemuMonitorJSONRemoveFd(mon, fdset, fd);
cleanup:
if (error) {
virSetError(error);
virFreeError(error);
}
return ret;
}
int
qemuMonitorAddHostNetwork(qemuMonitorPtr mon,
const char *netstr,
int *tapfd, char **tapfdName, int tapfdSize,
int *vhostfd, char **vhostfdName, int vhostfdSize)
{
int ret = -1;
size_t i = 0, j = 0;
VIR_DEBUG("netstr=%s tapfd=%p tapfdName=%p tapfdSize=%d "
"vhostfd=%p vhostfdName=%p vhostfdSize=%d",
netstr, tapfd, tapfdName, tapfdSize,
vhostfd, vhostfdName, vhostfdSize);
QEMU_CHECK_MONITOR(mon);
for (i = 0; i < tapfdSize; i++) {
if (qemuMonitorSendFileHandle(mon, tapfdName[i], tapfd[i]) < 0)
goto cleanup;
}
for (j = 0; j < vhostfdSize; j++) {
if (qemuMonitorSendFileHandle(mon, vhostfdName[j], vhostfd[j]) < 0)
goto cleanup;
}
if (mon->json)
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("JSON monitor should be using AddNetdev"));
else
ret = qemuMonitorTextAddHostNetwork(mon, netstr);
cleanup:
if (ret < 0) {
while (i--) {
if (qemuMonitorCloseFileHandle(mon, tapfdName[i]) < 0)
VIR_WARN("failed to close device handle '%s'", tapfdName[i]);
}
while (j--) {
if (qemuMonitorCloseFileHandle(mon, vhostfdName[j]) < 0)
VIR_WARN("failed to close device handle '%s'", vhostfdName[j]);
}
}
return ret;
}
int
qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon,
int vlan,
const char *netname)
{
VIR_DEBUG("netname=%s", netname);
QEMU_CHECK_MONITOR(mon);
if (mon->json) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("JSON monitor should be using RemoveNetdev"));
return -1;
}
return qemuMonitorTextRemoveHostNetwork(mon, vlan, netname);
}
int
qemuMonitorAddNetdev(qemuMonitorPtr mon,
const char *netdevstr,
int *tapfd, char **tapfdName, int tapfdSize,
int *vhostfd, char **vhostfdName, int vhostfdSize)
{
int ret = -1;
size_t i = 0, j = 0;
VIR_DEBUG("netdevstr=%s tapfd=%p tapfdName=%p tapfdSize=%d"
"vhostfd=%p vhostfdName=%p vhostfdSize=%d",
netdevstr, tapfd, tapfdName, tapfdSize,
vhostfd, vhostfdName, vhostfdSize);
QEMU_CHECK_MONITOR(mon);
for (i = 0; i < tapfdSize; i++) {
if (qemuMonitorSendFileHandle(mon, tapfdName[i], tapfd[i]) < 0)
goto cleanup;
}
for (j = 0; j < vhostfdSize; j++) {
if (qemuMonitorSendFileHandle(mon, vhostfdName[j], vhostfd[j]) < 0)
goto cleanup;
}
if (mon->json)
ret = qemuMonitorJSONAddNetdev(mon, netdevstr);
else
ret = qemuMonitorTextAddNetdev(mon, netdevstr);
cleanup:
if (ret < 0) {
while (i--) {
if (qemuMonitorCloseFileHandle(mon, tapfdName[i]) < 0)
VIR_WARN("failed to close device handle '%s'", tapfdName[i]);
}
while (j--) {
if (qemuMonitorCloseFileHandle(mon, vhostfdName[j]) < 0)
VIR_WARN("failed to close device handle '%s'", vhostfdName[j]);
}
}
return ret;
}
int
qemuMonitorRemoveNetdev(qemuMonitorPtr mon,
const char *alias)
{
VIR_DEBUG("alias=%s", alias);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONRemoveNetdev(mon, alias);
else
return qemuMonitorTextRemoveNetdev(mon, alias);
}
int
qemuMonitorQueryRxFilter(qemuMonitorPtr mon, const char *alias,
virNetDevRxFilterPtr *filter)
{
VIR_DEBUG("alias=%s filter=%p", alias, filter);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONQueryRxFilter(mon, alias, filter);
}
void
qemuMonitorChardevInfoFree(void *data,
const void *name ATTRIBUTE_UNUSED)
{
qemuMonitorChardevInfoPtr info = data;
VIR_FREE(info->ptyPath);
VIR_FREE(info);
}
int
qemuMonitorGetChardevInfo(qemuMonitorPtr mon,
virHashTablePtr *retinfo)
{
int ret;
virHashTablePtr info = NULL;
VIR_DEBUG("retinfo=%p", retinfo);
QEMU_CHECK_MONITOR_GOTO(mon, error);
if (!(info = virHashCreate(10, qemuMonitorChardevInfoFree)))
goto error;
if (mon->json)
ret = qemuMonitorJSONGetChardevInfo(mon, info);
else
ret = qemuMonitorTextGetChardevInfo(mon, info);
if (ret < 0)
goto error;
*retinfo = info;
return 0;
error:
virHashFree(info);
*retinfo = NULL;
return -1;
}
int
qemuMonitorAttachPCIDiskController(qemuMonitorPtr mon,
const char *bus,
virDevicePCIAddress *guestAddr)
{
VIR_DEBUG("type=%s", bus);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONAttachPCIDiskController(mon, bus, guestAddr);
else
return qemuMonitorTextAttachPCIDiskController(mon, bus, guestAddr);
}
int
qemuMonitorAttachDrive(qemuMonitorPtr mon,
const char *drivestr,
virDevicePCIAddress *controllerAddr,
virDomainDeviceDriveAddress *driveAddr)
{
VIR_DEBUG("drivestr=%s domain=%d bus=%d slot=%d function=%d",
drivestr, controllerAddr->domain, controllerAddr->bus,
controllerAddr->slot, controllerAddr->function);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorTextAttachDrive(mon, drivestr, controllerAddr, driveAddr);
}
int
qemuMonitorGetAllPCIAddresses(qemuMonitorPtr mon,
qemuMonitorPCIAddress **addrs)
{
VIR_DEBUG("addrs=%p", addrs);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONGetAllPCIAddresses(mon, addrs);
else
return qemuMonitorTextGetAllPCIAddresses(mon, addrs);
}
int
qemuMonitorDriveDel(qemuMonitorPtr mon,
const char *drivestr)
{
VIR_DEBUG("drivestr=%s", drivestr);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONDriveDel(mon, drivestr);
else
return qemuMonitorTextDriveDel(mon, drivestr);
}
int
qemuMonitorDelDevice(qemuMonitorPtr mon,
const char *devalias)
{
VIR_DEBUG("devalias=%s", devalias);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONDelDevice(mon, devalias);
else
return qemuMonitorTextDelDevice(mon, devalias);
}
int
qemuMonitorAddDeviceWithFd(qemuMonitorPtr mon,
const char *devicestr,
int fd,
const char *fdname)
{
VIR_DEBUG("device=%s fd=%d fdname=%s", devicestr, fd, NULLSTR(fdname));
int ret;
QEMU_CHECK_MONITOR(mon);
if (fd >= 0 && qemuMonitorSendFileHandle(mon, fdname, fd) < 0)
return -1;
if (mon->json)
ret = qemuMonitorJSONAddDevice(mon, devicestr);
else
ret = qemuMonitorTextAddDevice(mon, devicestr);
if (ret < 0 && fd >= 0) {
if (qemuMonitorCloseFileHandle(mon, fdname) < 0)
VIR_WARN("failed to close device handle '%s'", fdname);
}
return ret;
}
int
qemuMonitorAddDevice(qemuMonitorPtr mon,
const char *devicestr)
{
return qemuMonitorAddDeviceWithFd(mon, devicestr, -1, NULL);
}
/**
* qemuMonitorAddObject:
* @mon: Pointer to monitor object
* @type: Type name of object to add
* @objalias: Alias of the new object
* @props: Optional arguments for the given type. The object is consumed and
* should not be referenced by the caller after this function returns.
*
* Returns 0 on success -1 on error.
*/
int
qemuMonitorAddObject(qemuMonitorPtr mon,
const char *type,
const char *objalias,
virJSONValuePtr props)
{
VIR_DEBUG("type=%s objalias=%s props=%p", type, objalias, props);
QEMU_CHECK_MONITOR_JSON_GOTO(mon, error);
return qemuMonitorJSONAddObject(mon, type, objalias, props);
error:
virJSONValueFree(props);
return -1;
}
int
qemuMonitorDelObject(qemuMonitorPtr mon,
const char *objalias)
{
VIR_DEBUG("objalias=%s", objalias);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONDelObject(mon, objalias);
}
int
qemuMonitorAddDrive(qemuMonitorPtr mon,
const char *drivestr)
{
VIR_DEBUG("drive=%s", drivestr);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONAddDrive(mon, drivestr);
else
return qemuMonitorTextAddDrive(mon, drivestr);
}
int
qemuMonitorSetDrivePassphrase(qemuMonitorPtr mon,
const char *alias,
const char *passphrase)
{
VIR_DEBUG("alias=%s passphrase=%p(value hidden)", alias, passphrase);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONSetDrivePassphrase(mon, alias, passphrase);
else
return qemuMonitorTextSetDrivePassphrase(mon, alias, passphrase);
}
int
qemuMonitorCreateSnapshot(qemuMonitorPtr mon, const char *name)
{
VIR_DEBUG("name=%s", name);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONCreateSnapshot(mon, name);
else
return qemuMonitorTextCreateSnapshot(mon, name);
}
int
qemuMonitorLoadSnapshot(qemuMonitorPtr mon, const char *name)
{
VIR_DEBUG("name=%s", name);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONLoadSnapshot(mon, name);
else
return qemuMonitorTextLoadSnapshot(mon, name);
}
int
qemuMonitorDeleteSnapshot(qemuMonitorPtr mon, const char *name)
{
VIR_DEBUG("name=%s", name);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONDeleteSnapshot(mon, name);
else
return qemuMonitorTextDeleteSnapshot(mon, name);
}
/* Use the snapshot_blkdev command to convert the existing file for
* device into a read-only backing file of a new qcow2 image located
* at file. */
int
qemuMonitorDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr actions,
const char *device, const char *file,
const char *format, bool reuse)
{
VIR_DEBUG("actions=%p, device=%s, file=%s, format=%s, reuse=%d",
actions, device, file, format, reuse);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONDiskSnapshot(mon, actions, device, file, format, reuse);
}
/* Start a drive-mirror block job. bandwidth is in bytes/sec. */
int
qemuMonitorDriveMirror(qemuMonitorPtr mon,
const char *device, const char *file,
const char *format, unsigned long long bandwidth,
unsigned int granularity, unsigned long long buf_size,
unsigned int flags)
{
VIR_DEBUG("device=%s, file=%s, format=%s, bandwidth=%lld, "
"granularity=%#x, buf_size=%lld, flags=%x",
device, file, NULLSTR(format), bandwidth, granularity,
buf_size, flags);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONDriveMirror(mon, device, file, format, bandwidth,
granularity, buf_size, flags);
}
/* Use the transaction QMP command to run atomic snapshot commands. */
int
qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
{
VIR_DEBUG("actions=%p", actions);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONTransaction(mon, actions);
}
/* Start a block-commit block job. bandwidth is in bytes/sec. */
int
qemuMonitorBlockCommit(qemuMonitorPtr mon, const char *device,
const char *top, const char *base,
const char *backingName,
unsigned long long bandwidth)
{
VIR_DEBUG("device=%s, top=%s, base=%s, backingName=%s, bandwidth=%llu",
device, top, base, NULLSTR(backingName), bandwidth);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONBlockCommit(mon, device, top, base,
backingName, bandwidth);
}
/* Probe whether active commits are supported by a given qemu binary. */
bool
qemuMonitorSupportsActiveCommit(qemuMonitorPtr mon)
{
if (!mon || !mon->json)
return false;
return qemuMonitorJSONBlockCommit(mon, "bogus", NULL, NULL, NULL, 0) == -2;
}
/* Determine the name that qemu is using for tracking the backing
* element TARGET within the chain starting at TOP. */
char *
qemuMonitorDiskNameLookup(qemuMonitorPtr mon,
const char *device,
virStorageSourcePtr top,
virStorageSourcePtr target)
{
QEMU_CHECK_MONITOR_JSON_NULL(mon);
return qemuMonitorJSONDiskNameLookup(mon, device, top, target);
}
/* Use the block-job-complete monitor command to pivot a block copy job. */
int
qemuMonitorDrivePivot(qemuMonitorPtr mon,
const char *device)
{
VIR_DEBUG("device=%s", device);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONDrivePivot(mon, device);
}
int
qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
const char *cmd,
char **reply,
bool hmp)
{
VIR_DEBUG("cmd=%s, reply=%p, hmp=%d", cmd, reply, hmp);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONArbitraryCommand(mon, cmd, reply, hmp);
else
return qemuMonitorTextArbitraryCommand(mon, cmd, reply);
}
int
qemuMonitorInjectNMI(qemuMonitorPtr mon)
{
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONInjectNMI(mon);
else
return qemuMonitorTextInjectNMI(mon);
}
int
qemuMonitorSendKey(qemuMonitorPtr mon,
unsigned int holdtime,
unsigned int *keycodes,
unsigned int nkeycodes)
{
VIR_DEBUG("holdtime=%u, nkeycodes=%u", holdtime, nkeycodes);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONSendKey(mon, holdtime, keycodes, nkeycodes);
else
return qemuMonitorTextSendKey(mon, holdtime, keycodes, nkeycodes);
}
int
qemuMonitorScreendump(qemuMonitorPtr mon,
const char *file)
{
VIR_DEBUG("file=%s", file);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONScreendump(mon, file);
else
return qemuMonitorTextScreendump(mon, file);
}
/* bandwidth is in bytes/sec */
int
qemuMonitorBlockStream(qemuMonitorPtr mon,
const char *device,
const char *base,
const char *backingName,
unsigned long long bandwidth,
bool modern)
{
VIR_DEBUG("device=%s, base=%s, backingName=%s, bandwidth=%lluB, modern=%d",
device, NULLSTR(base), NULLSTR(backingName), bandwidth, modern);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONBlockStream(mon, device, base, backingName,
bandwidth, modern);
}
int
qemuMonitorBlockJobCancel(qemuMonitorPtr mon,
const char *device,
bool modern)
{
VIR_DEBUG("device=%s, modern=%d", device, modern);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONBlockJobCancel(mon, device, modern);
}
int
qemuMonitorBlockJobSetSpeed(qemuMonitorPtr mon,
const char *device,
unsigned long long bandwidth,
bool modern)
{
VIR_DEBUG("device=%s, bandwidth=%lluB, modern=%d", device, bandwidth, modern);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONBlockJobSetSpeed(mon, device, bandwidth, modern);
}
virHashTablePtr
qemuMonitorGetAllBlockJobInfo(qemuMonitorPtr mon)
{
QEMU_CHECK_MONITOR_JSON_NULL(mon);
return qemuMonitorJSONGetAllBlockJobInfo(mon);
}
/**
* qemuMonitorGetBlockJobInfo:
* Parse Block Job information, and populate info for the named device.
* Return 1 if info available, 0 if device has no block job, and -1 on error.
*/
int
qemuMonitorGetBlockJobInfo(qemuMonitorPtr mon,
const char *alias,
qemuMonitorBlockJobInfoPtr info)
{
virHashTablePtr all;
qemuMonitorBlockJobInfoPtr data;
int ret = 0;
VIR_DEBUG("alias=%s, info=%p", alias, info);
if (!(all = qemuMonitorGetAllBlockJobInfo(mon)))
return -1;
if ((data = virHashLookup(all, alias))) {
*info = *data;
ret = 1;
}
virHashFree(all);
return ret;
}
int
qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr info,
bool supportMaxOptions)
{
VIR_DEBUG("device=%p, info=%p", device, info);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONSetBlockIoThrottle(mon, device, info, supportMaxOptions);
else
return qemuMonitorTextSetBlockIoThrottle(mon, device, info);
}
int
qemuMonitorGetBlockIoThrottle(qemuMonitorPtr mon,
const char *device,
virDomainBlockIoTuneInfoPtr reply,
bool supportMaxOptions)
{
VIR_DEBUG("device=%p, reply=%p", device, reply);
QEMU_CHECK_MONITOR(mon);
if (mon->json)
return qemuMonitorJSONGetBlockIoThrottle(mon, device, reply, supportMaxOptions);
else
return qemuMonitorTextGetBlockIoThrottle(mon, device, reply);
}
int
qemuMonitorVMStatusToPausedReason(const char *status)
{
int st;
if (!status)
return VIR_DOMAIN_PAUSED_UNKNOWN;
if ((st = qemuMonitorVMStatusTypeFromString(status)) < 0) {
VIR_WARN("Qemu reported unknown VM status: '%s'", status);
return VIR_DOMAIN_PAUSED_UNKNOWN;
}
switch ((qemuMonitorVMStatus) st) {
case QEMU_MONITOR_VM_STATUS_DEBUG:
case QEMU_MONITOR_VM_STATUS_INTERNAL_ERROR:
case QEMU_MONITOR_VM_STATUS_RESTORE_VM:
return VIR_DOMAIN_PAUSED_UNKNOWN;
case QEMU_MONITOR_VM_STATUS_INMIGRATE:
case QEMU_MONITOR_VM_STATUS_POSTMIGRATE:
case QEMU_MONITOR_VM_STATUS_FINISH_MIGRATE:
return VIR_DOMAIN_PAUSED_MIGRATION;
case QEMU_MONITOR_VM_STATUS_IO_ERROR:
return VIR_DOMAIN_PAUSED_IOERROR;
case QEMU_MONITOR_VM_STATUS_PAUSED:
case QEMU_MONITOR_VM_STATUS_PRELAUNCH:
return VIR_DOMAIN_PAUSED_USER;
case QEMU_MONITOR_VM_STATUS_RUNNING:
VIR_WARN("Qemu reports the guest is paused but status is 'running'");
return VIR_DOMAIN_PAUSED_UNKNOWN;
case QEMU_MONITOR_VM_STATUS_SAVE_VM:
return VIR_DOMAIN_PAUSED_SAVE;
case QEMU_MONITOR_VM_STATUS_SHUTDOWN:
return VIR_DOMAIN_PAUSED_SHUTTING_DOWN;
case QEMU_MONITOR_VM_STATUS_WATCHDOG:
return VIR_DOMAIN_PAUSED_WATCHDOG;
case QEMU_MONITOR_VM_STATUS_GUEST_PANICKED:
return VIR_DOMAIN_PAUSED_CRASHED;
/* unreachable from this point on */
case QEMU_MONITOR_VM_STATUS_LAST:
;
}
return VIR_DOMAIN_PAUSED_UNKNOWN;
}
int
qemuMonitorOpenGraphics(qemuMonitorPtr mon,
const char *protocol,
int fd,
const char *fdname,
bool skipauth)
{
VIR_DEBUG("protocol=%s fd=%d fdname=%s skipauth=%d",
protocol, fd, NULLSTR(fdname), skipauth);
int ret;
QEMU_CHECK_MONITOR(mon);
if (qemuMonitorSendFileHandle(mon, fdname, fd) < 0)
return -1;
if (mon->json)
ret = qemuMonitorJSONOpenGraphics(mon, protocol, fdname, skipauth);
else
ret = qemuMonitorTextOpenGraphics(mon, protocol, fdname, skipauth);
if (ret < 0) {
if (qemuMonitorCloseFileHandle(mon, fdname) < 0)
VIR_WARN("failed to close device handle '%s'", fdname);
}
return ret;
}
int
qemuMonitorSystemWakeup(qemuMonitorPtr mon)
{
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONSystemWakeup(mon);
}
int
qemuMonitorGetVersion(qemuMonitorPtr mon,
int *major,
int *minor,
int *micro,
char **package)
{
VIR_DEBUG("major=%p minor=%p micro=%p package=%p",
major, minor, micro, package);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONGetVersion(mon, major, minor, micro, package);
}
int
qemuMonitorGetMachines(qemuMonitorPtr mon,
qemuMonitorMachineInfoPtr **machines)
{
VIR_DEBUG("machines=%p", machines);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONGetMachines(mon, machines);
}
void
qemuMonitorMachineInfoFree(qemuMonitorMachineInfoPtr machine)
{
if (!machine)
return;
VIR_FREE(machine->name);
VIR_FREE(machine->alias);
VIR_FREE(machine);
}
int
qemuMonitorGetCPUDefinitions(qemuMonitorPtr mon,
char ***cpus)
{
VIR_DEBUG("cpus=%p", cpus);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONGetCPUDefinitions(mon, cpus);
}
int
qemuMonitorGetCommands(qemuMonitorPtr mon,
char ***commands)
{
VIR_DEBUG("commands=%p", commands);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONGetCommands(mon, commands);
}
int
qemuMonitorGetEvents(qemuMonitorPtr mon,
char ***events)
{
VIR_DEBUG("events=%p", events);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONGetEvents(mon, events);
}
/* Collect the parameters associated with a given command line option.
* Return count of known parameters or -1 on error. */
int
qemuMonitorGetCommandLineOptionParameters(qemuMonitorPtr mon,
const char *option,
char ***params,
bool *found)
{
VIR_DEBUG("option=%s params=%p", option, params);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONGetCommandLineOptionParameters(mon, option,
params, found);
}
int
qemuMonitorGetKVMState(qemuMonitorPtr mon,
bool *enabled,
bool *present)
{
VIR_DEBUG("enabled=%p present=%p", enabled, present);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONGetKVMState(mon, enabled, present);
}
int
qemuMonitorGetObjectTypes(qemuMonitorPtr mon,
char ***types)
{
VIR_DEBUG("types=%p", types);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONGetObjectTypes(mon, types);
}
int
qemuMonitorGetObjectProps(qemuMonitorPtr mon,
const char *type,
char ***props)
{
VIR_DEBUG("type=%s props=%p", type, props);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONGetObjectProps(mon, type, props);
}
char *
qemuMonitorGetTargetArch(qemuMonitorPtr mon)
{
QEMU_CHECK_MONITOR_JSON_NULL(mon);
return qemuMonitorJSONGetTargetArch(mon);
}
int
qemuMonitorGetMigrationCapabilities(qemuMonitorPtr mon,
char ***capabilities)
{
QEMU_CHECK_MONITOR(mon);
/* No capability is supported without JSON monitor */
if (!mon->json)
return 0;
return qemuMonitorJSONGetMigrationCapabilities(mon, capabilities);
}
/**
* Returns 1 if @capability is supported, 0 if it's not, or -1 on error.
*/
int
qemuMonitorGetMigrationCapability(qemuMonitorPtr mon,
qemuMonitorMigrationCaps capability)
{
VIR_DEBUG("capability=%d", capability);
QEMU_CHECK_MONITOR(mon);
/* No capability is supported without JSON monitor */
if (!mon->json)
return 0;
return qemuMonitorJSONGetMigrationCapability(mon, capability);
}
int
qemuMonitorSetMigrationCapability(qemuMonitorPtr mon,
qemuMonitorMigrationCaps capability,
bool state)
{
VIR_DEBUG("capability=%d", capability);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONSetMigrationCapability(mon, capability, state);
}
int
qemuMonitorNBDServerStart(qemuMonitorPtr mon,
const char *host,
unsigned int port)
{
VIR_DEBUG("host=%s port=%u", host, port);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONNBDServerStart(mon, host, port);
}
int
qemuMonitorNBDServerAdd(qemuMonitorPtr mon,
const char *deviceID,
bool writable)
{
VIR_DEBUG("deviceID=%s", deviceID);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONNBDServerAdd(mon, deviceID, writable);
}
int
qemuMonitorNBDServerStop(qemuMonitorPtr mon)
{
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONNBDServerStop(mon);
}
int
qemuMonitorGetTPMModels(qemuMonitorPtr mon,
char ***tpmmodels)
{
VIR_DEBUG("tpmmodels=%p", tpmmodels);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONGetTPMModels(mon, tpmmodels);
}
int
qemuMonitorGetTPMTypes(qemuMonitorPtr mon,
char ***tpmtypes)
{
VIR_DEBUG("tpmtypes=%p", tpmtypes);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONGetTPMTypes(mon, tpmtypes);
}
int
qemuMonitorAttachCharDev(qemuMonitorPtr mon,
const char *chrID,
virDomainChrSourceDefPtr chr)
{
VIR_DEBUG("chrID=%s chr=%p", chrID, chr);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONAttachCharDev(mon, chrID, chr);
}
int
qemuMonitorDetachCharDev(qemuMonitorPtr mon,
const char *chrID)
{
VIR_DEBUG("chrID=%s", chrID);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONDetachCharDev(mon, chrID);
}
int
qemuMonitorGetDeviceAliases(qemuMonitorPtr mon,
char ***aliases)
{
VIR_DEBUG("aliases=%p", aliases);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONGetDeviceAliases(mon, aliases);
}
/**
* qemuMonitorSetDomainLog:
* Set the file descriptor of the open VM log file to report potential
* early startup errors of qemu.
*
* @mon: Monitor object to set the log file reading on
* @func: the callback to report errors
* @opaque: data to pass to @func
* @destroy: optional callback to free @opaque
*/
void
qemuMonitorSetDomainLog(qemuMonitorPtr mon,
qemuMonitorReportDomainLogError func,
void *opaque,
virFreeCallback destroy)
{
if (mon->logDestroy && mon->logOpaque)
mon->logDestroy(mon->logOpaque);
mon->logFunc = func;
mon->logOpaque = opaque;
mon->logDestroy = destroy;
}
/**
* qemuMonitorJSONGetGuestCPU:
* @mon: Pointer to the monitor
* @arch: arch of the guest
* @data: returns the cpu data
*
* Retrieve the definition of the guest CPU from a running qemu instance.
*
* Returns 0 on success, -2 if the operation is not supported by the guest,
* -1 on other errors.
*/
int
qemuMonitorGetGuestCPU(qemuMonitorPtr mon,
virArch arch,
virCPUDataPtr *data)
{
VIR_DEBUG("arch='%s' data='%p'", virArchToString(arch), data);
QEMU_CHECK_MONITOR_JSON(mon);
*data = NULL;
return qemuMonitorJSONGetGuestCPU(mon, arch, data);
}
/**
* qemuMonitorRTCResetReinjection:
* @mon: Pointer to the monitor
*
* Issue rtc-reset-reinjection command.
* This should be used in cases where guest time is restored via
* guest agent, so RTC injection is not needed (in fact it would
* confuse guest's RTC).
*
* Returns 0 on success
* -1 on error.
*/
int
qemuMonitorRTCResetReinjection(qemuMonitorPtr mon)
{
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONRTCResetReinjection(mon);
}
/**
* qemuMonitorGetIOThreads:
* @mon: Pointer to the monitor
* @iothreads: Location to return array of IOThreadInfo data
*
* Issue query-iothreads command.
* Retrieve the list of iothreads defined/running for the machine
*
* Returns count of IOThreadInfo structures on success
* -1 on error.
*/
int
qemuMonitorGetIOThreads(qemuMonitorPtr mon,
qemuMonitorIOThreadInfoPtr **iothreads)
{
VIR_DEBUG("iothreads=%p", iothreads);
QEMU_CHECK_MONITOR(mon);
/* Requires JSON to make the query */
if (!mon->json) {
*iothreads = NULL;
return 0;
}
return qemuMonitorJSONGetIOThreads(mon, iothreads);
}
/**
* qemuMonitorGetMemoryDeviceInfo:
* @mon: pointer to the monitor
* @info: Location to return the hash of qemuMonitorMemoryDeviceInfo
*
* Retrieve state and addresses of frontend memory devices present in
* the guest.
*
* Returns 0 on success and fills @info with a newly allocated struct; if the
* data can't be retrieved due to lack of support in qemu, returns -2. On
* other errors returns -1.
*/
int
qemuMonitorGetMemoryDeviceInfo(qemuMonitorPtr mon,
virHashTablePtr *info)
{
VIR_DEBUG("info=%p", info);
int ret;
*info = NULL;
QEMU_CHECK_MONITOR(mon);
if (!mon->json)
return -2;
if (!(*info = virHashCreate(10, virHashValueFree)))
return -1;
if ((ret = qemuMonitorJSONGetMemoryDeviceInfo(mon, *info)) < 0) {
virHashFree(*info);
*info = NULL;
}
return ret;
}
int
qemuMonitorMigrateIncoming(qemuMonitorPtr mon,
const char *uri)
{
VIR_DEBUG("uri=%s", uri);
QEMU_CHECK_MONITOR_JSON(mon);
return qemuMonitorJSONMigrateIncoming(mon, uri);
}