2009-09-22 18:48:40 +01:00
|
|
|
/*
|
|
|
|
* qemu_monitor_text.c: interaction with QEMU monitor console
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006-2009 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <poll.h>
|
|
|
|
#include <unistd.h>
|
2009-09-23 14:27:12 +01:00
|
|
|
#include <string.h>
|
2009-09-22 18:48:40 +01:00
|
|
|
|
|
|
|
#include "qemu_monitor_text.h"
|
|
|
|
#include "qemu_conf.h"
|
2009-09-23 11:49:14 +01:00
|
|
|
#include "c-ctype.h"
|
2009-09-22 18:48:40 +01:00
|
|
|
#include "memory.h"
|
|
|
|
#include "logging.h"
|
|
|
|
#include "driver.h"
|
|
|
|
#include "datatypes.h"
|
|
|
|
#include "virterror_internal.h"
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
2009-09-23 17:39:07 +01:00
|
|
|
#define QEMU_CMD_PROMPT "\n(qemu) "
|
|
|
|
#define QEMU_PASSWD_PROMPT "Password: "
|
|
|
|
|
|
|
|
/* Return -1 for error, 0 for success */
|
2009-10-09 21:13:06 +01:00
|
|
|
typedef int qemuMonitorExtraPromptHandler(qemuMonitorPtr mon,
|
2009-09-23 17:39:07 +01:00
|
|
|
const char *buf,
|
|
|
|
const char *prompt,
|
|
|
|
void *data);
|
|
|
|
|
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
/* When connecting to a monitor, QEMU will print a greeting like
|
|
|
|
*
|
|
|
|
* QEMU 0.11.0 monitor - type 'help' for more information
|
|
|
|
*
|
|
|
|
* Don't expect the version number bit to be stable :-)
|
2009-09-22 18:48:40 +01:00
|
|
|
*/
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
#define GREETING_PREFIX "QEMU "
|
|
|
|
#define GREETING_POSTFIX "type 'help' for more information\r\n(qemu) "
|
|
|
|
#define BASIC_PROMPT "(qemu) "
|
|
|
|
#define PASSWORD_PROMPT "Password:"
|
|
|
|
#define DISK_ENCRYPTION_PREFIX "("
|
|
|
|
#define DISK_ENCRYPTION_POSTFIX ") is encrypted."
|
|
|
|
#define LINE_ENDING "\r\n"
|
|
|
|
|
|
|
|
int qemuMonitorTextIOProcess(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
|
|
|
const char *data,
|
|
|
|
size_t len,
|
|
|
|
qemuMonitorMessagePtr msg)
|
|
|
|
{
|
|
|
|
int used = 0;
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
/* Check for & discard greeting */
|
|
|
|
if (STRPREFIX(data, GREETING_PREFIX)) {
|
|
|
|
const char *offset = strstr(data, GREETING_POSTFIX);
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
/* We see the greeting prefix, but not postfix, so pretend we've
|
|
|
|
not consumed anything. We'll restart when more data arrives. */
|
|
|
|
if (!offset) {
|
|
|
|
VIR_DEBUG0("Partial greeting seen, getting out & waiting for more");
|
|
|
|
return 0;
|
|
|
|
}
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
used = offset - data + strlen(GREETING_POSTFIX);
|
|
|
|
|
|
|
|
VIR_DEBUG0("Discarded monitor greeting");
|
2009-11-08 22:08:54 +01:00
|
|
|
}
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
/* Don't print raw data in debug because its full of control chars */
|
|
|
|
/*VIR_DEBUG("Process data %d byts of data [%s]", len - used, data + used);*/
|
2009-11-11 11:30:01 +01:00
|
|
|
VIR_DEBUG("Process data %d byts of data", (int)(len - used));
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
|
|
|
|
/* Look for a non-zero reply followed by prompt */
|
|
|
|
if (msg && !msg->finished) {
|
2009-12-08 18:05:02 +00:00
|
|
|
char *start = NULL;
|
|
|
|
char *end = NULL;
|
|
|
|
char *skip;
|
|
|
|
|
|
|
|
/* If we're here, we've already sent the command. We now
|
|
|
|
* strip the trailing '\r' because it makes the matching
|
|
|
|
* code that follows a little easier ie we can just strstr()
|
|
|
|
* for the original command
|
|
|
|
*/
|
|
|
|
if (msg->txLength > 0) {
|
|
|
|
char *tmp;
|
|
|
|
if ((tmp = strchr(msg->txBuffer, '\r'))) {
|
|
|
|
*tmp = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* QEMU echos the command back to us, full of control
|
|
|
|
* character junk that we don't want. We have to skip
|
|
|
|
* over this junk by looking for the first complete
|
|
|
|
* repetition of our command. Then we can look for
|
|
|
|
* the prompt that is supposed to follow
|
|
|
|
*
|
|
|
|
* NB, we can't optimize by immediately looking for
|
|
|
|
* LINE_ENDING, because QEMU 0.10 has bad problems
|
|
|
|
* when initially connecting where it might write a
|
|
|
|
* prompt in the wrong place. So we must not look
|
|
|
|
* for LINE_ENDING, or BASIC_PROMPT until we've
|
|
|
|
* seen our original command echod.
|
|
|
|
*/
|
|
|
|
skip = strstr(data + used, msg->txBuffer);
|
|
|
|
|
|
|
|
/* After the junk we should have a line ending... */
|
|
|
|
if (skip) {
|
|
|
|
start = strstr(skip + strlen(msg->txBuffer), LINE_ENDING);
|
|
|
|
}
|
2009-09-22 18:48:40 +01:00
|
|
|
|
2009-12-08 18:05:02 +00:00
|
|
|
/* ... then our command reply data, following by a (qemu) prompt */
|
|
|
|
if (start) {
|
|
|
|
char *passwd;
|
|
|
|
start += strlen(LINE_ENDING);
|
|
|
|
|
|
|
|
/* We might get a prompt for a password before the (qemu) prompt */
|
|
|
|
passwd = strstr(start, PASSWORD_PROMPT);
|
|
|
|
if (passwd) {
|
|
|
|
VIR_DEBUG("Seen a passwowrd prompt [%s]", data + used);
|
|
|
|
if (msg->passwordHandler) {
|
|
|
|
int i;
|
|
|
|
/* Try and handle the prompt */
|
|
|
|
if (msg->passwordHandler(mon, msg,
|
|
|
|
start,
|
|
|
|
passwd - start + strlen(PASSWORD_PROMPT),
|
|
|
|
msg->passwordOpaque) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Blank out the password prompt so we don't re-trigger
|
|
|
|
* if we have to go back to sleep for more I/O */
|
|
|
|
for (i = 0 ; i < strlen(PASSWORD_PROMPT) ; i++)
|
|
|
|
start[i] = ' ';
|
|
|
|
|
|
|
|
/* Handled, so skip forward over password prompt */
|
|
|
|
start = passwd;
|
|
|
|
} else {
|
|
|
|
errno = EACCES;
|
|
|
|
return -1;
|
|
|
|
}
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
}
|
2009-12-08 18:05:02 +00:00
|
|
|
|
|
|
|
end = strstr(start, BASIC_PROMPT);
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
}
|
2009-09-22 18:48:40 +01:00
|
|
|
|
2009-12-08 18:05:02 +00:00
|
|
|
if (start && end) {
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
int want = end - start;
|
|
|
|
/* Annoyingly some commands may not have any reply data
|
|
|
|
* at all upon success, but since we've detected the
|
|
|
|
* BASIC_PROMPT we can reasonably reliably cope */
|
|
|
|
if (want) {
|
|
|
|
if (VIR_REALLOC_N(msg->rxBuffer,
|
|
|
|
msg->rxLength + want + 1) < 0)
|
|
|
|
return -1;
|
|
|
|
memcpy(msg->rxBuffer + msg->rxLength, start, want);
|
|
|
|
msg->rxLength += want;
|
|
|
|
msg->rxBuffer[msg->rxLength] = '\0';
|
|
|
|
VIR_DEBUG("Finished %d byte reply [%s]", want, msg->rxBuffer);
|
|
|
|
} else {
|
|
|
|
VIR_DEBUG0("Finished 0 byte reply");
|
|
|
|
}
|
|
|
|
msg->finished = 1;
|
|
|
|
used += end - (data + used);
|
|
|
|
used += strlen(BASIC_PROMPT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_DEBUG("Total used %d", used);
|
|
|
|
return used;
|
2009-09-22 18:48:40 +01:00
|
|
|
}
|
|
|
|
|
2009-09-23 17:39:07 +01:00
|
|
|
static int
|
2009-10-09 21:13:06 +01:00
|
|
|
qemuMonitorCommandWithHandler(qemuMonitorPtr mon,
|
2009-09-23 17:39:07 +01:00
|
|
|
const char *cmd,
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
qemuMonitorPasswordHandler passwordHandler,
|
|
|
|
void *passwordOpaque,
|
2009-09-23 17:39:07 +01:00
|
|
|
int scm_fd,
|
|
|
|
char **reply) {
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
int ret;
|
|
|
|
qemuMonitorMessage msg;
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
*reply = NULL;
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
memset(&msg, 0, sizeof msg);
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
if (virAsprintf(&msg.txBuffer, "%s\r", cmd) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
msg.txLength = strlen(msg.txBuffer);
|
|
|
|
msg.txFD = scm_fd;
|
|
|
|
msg.passwordHandler = passwordHandler;
|
|
|
|
msg.passwordOpaque = passwordOpaque;
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
VIR_DEBUG("Send command '%s' for write with FD %d", cmd, scm_fd);
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
ret = qemuMonitorSend(mon, &msg);
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
VIR_DEBUG("Receive command reply ret=%d errno=%d %d bytes '%s'",
|
|
|
|
ret, msg.lastErrno, msg.rxLength, msg.rxBuffer);
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
/* Just in case buffer had some passwords in */
|
|
|
|
memset(msg.txBuffer, 0, msg.txLength);
|
|
|
|
VIR_FREE(msg.txBuffer);
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
/* To make life safer for callers, already ensure there's at least an empty string */
|
|
|
|
if (msg.rxBuffer) {
|
|
|
|
*reply = msg.rxBuffer;
|
|
|
|
} else {
|
|
|
|
*reply = strdup("");
|
|
|
|
if (!*reply) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
2009-09-22 18:48:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
if (ret < 0)
|
|
|
|
virReportSystemError(NULL, msg.lastErrno,
|
|
|
|
_("cannot send monitor command '%s'"), cmd);
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
return ret;
|
2009-09-22 18:48:40 +01:00
|
|
|
}
|
|
|
|
|
2009-09-23 17:39:07 +01:00
|
|
|
static int
|
2009-10-09 21:13:06 +01:00
|
|
|
qemuMonitorCommandWithFd(qemuMonitorPtr mon,
|
2009-09-22 18:48:40 +01:00
|
|
|
const char *cmd,
|
|
|
|
int scm_fd,
|
|
|
|
char **reply) {
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
return qemuMonitorCommandWithHandler(mon, cmd, NULL, NULL, scm_fd, reply);
|
2009-09-22 18:48:40 +01:00
|
|
|
}
|
|
|
|
|
2009-09-23 17:39:07 +01:00
|
|
|
static int
|
2009-10-09 21:13:06 +01:00
|
|
|
qemuMonitorCommand(qemuMonitorPtr mon,
|
2009-09-22 18:48:40 +01:00
|
|
|
const char *cmd,
|
|
|
|
char **reply) {
|
2009-10-09 21:13:06 +01:00
|
|
|
return qemuMonitorCommandWithFd(mon, cmd, -1, reply);
|
2009-09-22 18:48:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
qemuMonitorSendDiskPassphrase(qemuMonitorPtr mon,
|
|
|
|
qemuMonitorMessagePtr msg,
|
|
|
|
const char *data,
|
|
|
|
size_t len ATTRIBUTE_UNUSED,
|
|
|
|
void *opaque)
|
2009-09-22 18:48:40 +01:00
|
|
|
{
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
virConnectPtr conn = opaque;
|
|
|
|
char *path;
|
|
|
|
char *passphrase = NULL;
|
|
|
|
size_t passphrase_len = 0;
|
2009-09-22 18:48:40 +01:00
|
|
|
int res;
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
const char *pathStart;
|
|
|
|
const char *pathEnd;
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
/*
|
|
|
|
* For disk passwords:
|
|
|
|
*
|
|
|
|
* ide0-hd0 (/path/to/volume) is encrypted.
|
|
|
|
* Password:
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
pathStart = strstr(data, DISK_ENCRYPTION_PREFIX);
|
|
|
|
pathEnd = strstr(data, DISK_ENCRYPTION_POSTFIX);
|
|
|
|
if (!pathStart || !pathEnd || pathStart >= pathEnd) {
|
|
|
|
errno = -EINVAL;
|
2009-09-22 18:48:40 +01:00
|
|
|
return -1;
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Extra the path */
|
|
|
|
pathStart += strlen(DISK_ENCRYPTION_PREFIX);
|
|
|
|
path = strndup(pathStart, pathEnd - pathStart);
|
|
|
|
if (!path) {
|
|
|
|
errno = ENOMEM;
|
2009-09-22 18:48:40 +01:00
|
|
|
return -1;
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
}
|
2009-09-22 18:48:40 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
/* Fetch the disk password if possible */
|
|
|
|
res = qemuMonitorGetDiskSecret(mon,
|
|
|
|
conn,
|
|
|
|
path,
|
|
|
|
&passphrase,
|
|
|
|
&passphrase_len);
|
2009-09-22 18:48:40 +01:00
|
|
|
VIR_FREE(path);
|
2009-10-09 20:34:24 +01:00
|
|
|
if (res < 0)
|
2009-09-22 18:48:40 +01:00
|
|
|
return -1;
|
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
/* Enlarge transmit buffer to allow for the extra data
|
|
|
|
* to be sent back */
|
|
|
|
if (VIR_REALLOC_N(msg->txBuffer,
|
|
|
|
msg->txLength + passphrase_len + 1 + 1) < 0) {
|
|
|
|
memset(passphrase, 0, passphrase_len);
|
|
|
|
VIR_FREE(passphrase);
|
|
|
|
errno = ENOMEM;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Queue the password for sending */
|
|
|
|
memcpy(msg->txBuffer + msg->txLength,
|
|
|
|
passphrase, passphrase_len);
|
|
|
|
msg->txLength += passphrase_len;
|
|
|
|
msg->txBuffer[msg->txLength] = '\r';
|
|
|
|
msg->txLength++;
|
|
|
|
msg->txBuffer[msg->txLength] = '\0';
|
2009-09-22 18:48:40 +01:00
|
|
|
|
|
|
|
memset(passphrase, 0, passphrase_len);
|
|
|
|
VIR_FREE(passphrase);
|
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
return 0;
|
2009-09-22 18:48:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2009-10-09 21:13:06 +01:00
|
|
|
qemuMonitorTextStartCPUs(qemuMonitorPtr mon,
|
|
|
|
virConnectPtr conn) {
|
2009-09-22 18:48:40 +01:00
|
|
|
char *reply;
|
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
if (qemuMonitorCommandWithHandler(mon, "cont",
|
|
|
|
qemuMonitorSendDiskPassphrase,
|
|
|
|
conn,
|
2009-09-23 17:39:07 +01:00
|
|
|
-1, &reply) < 0)
|
2009-09-22 18:48:40 +01:00
|
|
|
return -1;
|
2009-09-24 15:37:05 +01:00
|
|
|
|
2009-09-22 18:48:40 +01:00
|
|
|
VIR_FREE(reply);
|
|
|
|
return 0;
|
|
|
|
}
|
2009-09-23 11:49:14 +01:00
|
|
|
|
|
|
|
|
2009-09-23 12:14:53 +01:00
|
|
|
int
|
2009-10-09 21:13:06 +01:00
|
|
|
qemuMonitorTextStopCPUs(qemuMonitorPtr mon) {
|
2009-09-23 12:14:53 +01:00
|
|
|
char *info;
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, "stop", &info) < 0) {
|
2009-09-23 12:14:53 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("cannot stop CPU execution"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(info);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-09-23 12:21:00 +01:00
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextSystemPowerdown(qemuMonitorPtr mon) {
|
2009-09-23 12:21:00 +01:00
|
|
|
char *info;
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, "system_powerdown", &info) < 0) {
|
2009-09-23 12:21:00 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("system shutdown operation failed"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(info);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextGetCPUInfo(qemuMonitorPtr mon,
|
|
|
|
int **pids)
|
2009-09-23 11:49:14 +01:00
|
|
|
{
|
|
|
|
char *qemucpus = NULL;
|
|
|
|
char *line;
|
|
|
|
int lastVcpu = -1;
|
|
|
|
pid_t *cpupids = NULL;
|
|
|
|
size_t ncpupids = 0;
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, "info cpus", &qemucpus) < 0) {
|
2009-09-23 11:49:14 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("cannot run monitor command to fetch CPU thread info"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the gross format we're about to parse :-{
|
|
|
|
*
|
|
|
|
* (qemu) info cpus
|
|
|
|
* * CPU #0: pc=0x00000000000f0c4a thread_id=30019
|
|
|
|
* CPU #1: pc=0x00000000fffffff0 thread_id=30020
|
|
|
|
* CPU #2: pc=0x00000000fffffff0 thread_id=30021
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
line = qemucpus;
|
|
|
|
do {
|
|
|
|
char *offset = strchr(line, '#');
|
|
|
|
char *end = NULL;
|
|
|
|
int vcpu = 0, tid = 0;
|
|
|
|
|
|
|
|
/* See if we're all done */
|
|
|
|
if (offset == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Extract VCPU number */
|
|
|
|
if (virStrToLong_i(offset + 1, &end, 10, &vcpu) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (end == NULL || *end != ':')
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* Extract host Thread ID */
|
|
|
|
if ((offset = strstr(line, "thread_id=")) == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virStrToLong_i(offset + strlen("thread_id="), &end, 10, &tid) < 0)
|
|
|
|
goto error;
|
|
|
|
if (end == NULL || !c_isspace(*end))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (vcpu != (lastVcpu + 1))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (VIR_REALLOC_N(cpupids, ncpupids+1) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2009-09-24 15:37:05 +01:00
|
|
|
DEBUG("vcpu=%d pid=%d", vcpu, tid);
|
2009-09-23 11:49:14 +01:00
|
|
|
cpupids[ncpupids++] = tid;
|
|
|
|
lastVcpu = vcpu;
|
|
|
|
|
|
|
|
/* Skip to next data line */
|
|
|
|
line = strchr(offset, '\r');
|
|
|
|
if (line == NULL)
|
|
|
|
line = strchr(offset, '\n');
|
|
|
|
} while (line != NULL);
|
|
|
|
|
|
|
|
/* Validate we got data for all VCPUs we expected */
|
|
|
|
VIR_FREE(qemucpus);
|
|
|
|
*pids = cpupids;
|
|
|
|
return ncpupids;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(qemucpus);
|
|
|
|
VIR_FREE(cpupids);
|
|
|
|
|
|
|
|
/* Returning 0 to indicate non-fatal failure, since
|
|
|
|
* older QEMU does not have VCPU<->PID mapping and
|
|
|
|
* we don't want to fail on that
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-23 12:29:39 +01:00
|
|
|
|
|
|
|
/* The reply from QEMU contains 'ballon: actual=421' where value is in MB */
|
|
|
|
#define BALLOON_PREFIX "balloon: actual="
|
|
|
|
|
2009-09-23 12:35:10 +01:00
|
|
|
/*
|
|
|
|
* Returns: 0 if balloon not supported, +1 if balloon query worked
|
|
|
|
* or -1 on failure
|
|
|
|
*/
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextGetBalloonInfo(qemuMonitorPtr mon,
|
|
|
|
unsigned long *currmem)
|
2009-09-23 12:29:39 +01:00
|
|
|
{
|
|
|
|
char *reply = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
char *offset;
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, "info balloon", &reply) < 0) {
|
2009-09-23 12:29:39 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("could not query memory balloon allocation"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((offset = strstr(reply, BALLOON_PREFIX)) != NULL) {
|
|
|
|
unsigned int memMB;
|
|
|
|
char *end;
|
|
|
|
offset += strlen(BALLOON_PREFIX);
|
|
|
|
if (virStrToLong_ui(offset, &end, 10, &memMB) < 0) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("could not parse memory balloon allocation from '%s'"), reply);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
*currmem = memMB * 1024;
|
|
|
|
ret = 1;
|
|
|
|
} else {
|
|
|
|
/* We don't raise an error here, since its to be expected that
|
|
|
|
* many QEMU's don't support ballooning
|
|
|
|
*/
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(reply);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
|
|
|
|
const char *devname,
|
|
|
|
long long *rd_req,
|
|
|
|
long long *rd_bytes,
|
|
|
|
long long *wr_req,
|
|
|
|
long long *wr_bytes,
|
|
|
|
long long *errs)
|
2009-09-23 13:51:05 +01:00
|
|
|
{
|
|
|
|
char *info = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
char *dummy;
|
|
|
|
const char *p, *eol;
|
|
|
|
int devnamelen = strlen(devname);
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand (mon, "info blockstats", &info) < 0) {
|
2009-09-23 13:51:05 +01:00
|
|
|
qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("'info blockstats' command failed"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the command isn't supported then qemu prints the supported
|
|
|
|
* info commands, so the output starts "info ". Since this is
|
|
|
|
* unlikely to be the name of a block device, we can use this
|
|
|
|
* to detect if qemu supports the command.
|
|
|
|
*/
|
|
|
|
if (strstr(info, "\ninfo ")) {
|
|
|
|
qemudReportError (NULL, NULL, NULL, VIR_ERR_NO_SUPPORT,
|
|
|
|
"%s",
|
|
|
|
_("'info blockstats' not supported by this qemu"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
*rd_req = -1;
|
|
|
|
*rd_bytes = -1;
|
|
|
|
*wr_req = -1;
|
|
|
|
*wr_bytes = -1;
|
|
|
|
*errs = -1;
|
|
|
|
|
|
|
|
/* The output format for both qemu & KVM is:
|
|
|
|
* blockdevice: rd_bytes=% wr_bytes=% rd_operations=% wr_operations=%
|
|
|
|
* (repeated for each block device)
|
|
|
|
* where '%' is a 64 bit number.
|
|
|
|
*/
|
|
|
|
p = info;
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
if (STREQLEN (p, devname, devnamelen)
|
|
|
|
&& p[devnamelen] == ':' && p[devnamelen+1] == ' ') {
|
|
|
|
|
|
|
|
eol = strchr (p, '\n');
|
|
|
|
if (!eol)
|
|
|
|
eol = p + strlen (p);
|
|
|
|
|
|
|
|
p += devnamelen+2; /* Skip to first label. */
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
if (STRPREFIX (p, "rd_bytes=")) {
|
|
|
|
p += 9;
|
|
|
|
if (virStrToLong_ll (p, &dummy, 10, rd_bytes) == -1)
|
2009-10-09 21:13:06 +01:00
|
|
|
DEBUG ("error reading rd_bytes: %s", p);
|
2009-09-23 13:51:05 +01:00
|
|
|
} else if (STRPREFIX (p, "wr_bytes=")) {
|
|
|
|
p += 9;
|
|
|
|
if (virStrToLong_ll (p, &dummy, 10, wr_bytes) == -1)
|
2009-10-09 21:13:06 +01:00
|
|
|
DEBUG ("error reading wr_bytes: %s", p);
|
2009-09-23 13:51:05 +01:00
|
|
|
} else if (STRPREFIX (p, "rd_operations=")) {
|
|
|
|
p += 14;
|
|
|
|
if (virStrToLong_ll (p, &dummy, 10, rd_req) == -1)
|
2009-10-09 21:13:06 +01:00
|
|
|
DEBUG ("error reading rd_req: %s", p);
|
2009-09-23 13:51:05 +01:00
|
|
|
} else if (STRPREFIX (p, "wr_operations=")) {
|
|
|
|
p += 14;
|
|
|
|
if (virStrToLong_ll (p, &dummy, 10, wr_req) == -1)
|
2009-10-09 21:13:06 +01:00
|
|
|
DEBUG ("error reading wr_req: %s", p);
|
2009-09-23 13:51:05 +01:00
|
|
|
} else
|
2009-10-09 21:13:06 +01:00
|
|
|
DEBUG ("unknown block stat near %s", p);
|
2009-09-23 13:51:05 +01:00
|
|
|
|
|
|
|
/* Skip to next label. */
|
|
|
|
p = strchr (p, ' ');
|
|
|
|
if (!p || p >= eol) break;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Skip to next line. */
|
|
|
|
p = strchr (p, '\n');
|
|
|
|
if (!p) break;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we reach here then the device was not found. */
|
|
|
|
qemudReportError (NULL, NULL, NULL, VIR_ERR_INVALID_ARG,
|
|
|
|
_("no stats found for device %s"), devname);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(info);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
static int
|
|
|
|
qemuMonitorSendVNCPassphrase(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
|
|
|
qemuMonitorMessagePtr msg,
|
|
|
|
const char *data ATTRIBUTE_UNUSED,
|
|
|
|
size_t len ATTRIBUTE_UNUSED,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
char *passphrase = opaque;
|
|
|
|
size_t passphrase_len = strlen(passphrase);
|
|
|
|
|
|
|
|
/* Enlarge transmit buffer to allow for the extra data
|
|
|
|
* to be sent back */
|
|
|
|
if (VIR_REALLOC_N(msg->txBuffer,
|
|
|
|
msg->txLength + passphrase_len + 1 + 1) < 0) {
|
|
|
|
errno = ENOMEM;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Queue the password for sending */
|
|
|
|
memcpy(msg->txBuffer + msg->txLength,
|
|
|
|
passphrase, passphrase_len);
|
|
|
|
msg->txLength += passphrase_len;
|
|
|
|
msg->txBuffer[msg->txLength] = '\r';
|
|
|
|
msg->txLength++;
|
|
|
|
msg->txBuffer[msg->txLength] = '\0';
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextSetVNCPassword(qemuMonitorPtr mon,
|
|
|
|
const char *password)
|
2009-09-23 12:06:57 +01:00
|
|
|
{
|
|
|
|
char *info = NULL;
|
2009-09-24 15:37:05 +01:00
|
|
|
|
Fully asynchronous monitor I/O processing
Change the QEMU monitor file handle watch to poll for both
read & write events, as well as EOF. All I/O to/from the
QEMU monitor FD is now done in the event callback thread.
When the QEMU driver needs to send a command, it puts the
data to be sent into a qemuMonitorMessagePtr object instance,
queues it for dispatch, and then goes to sleep on a condition
variable. The event thread sends all the data, and then waits
for the reply to arrive, putting the response / error data
back into the qemuMonitorMessagePtr and notifying the condition
variable.
There is a temporary hack in the disk passphrase callback to
avoid acquiring the domain lock. This avoids a deadlock in
the command processing, since the domain lock is still held
when running monitor commands. The next commit will remove
the locking when running commands & thus allow re-introduction
of locking the disk passphrase callback
* src/qemu/qemu_driver.c: Temporarily don't acquire lock in
disk passphrase callback. To be reverted in next commit
* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Remove
raw I/O functions, and a generic qemuMonitorSend() for
invoking a command
* src/qemu/qemu_monitor_text.c, src/qemu/qemu_monitor_text.h:
Remove all low level I/O, and use the new qemuMonitorSend()
API. Provide a qemuMonitorTextIOProcess() method for detecting
command/reply/prompt boundaries in the monitor data stream
2009-10-14 18:40:51 +01:00
|
|
|
if (qemuMonitorCommandWithHandler(mon, "change vnc password",
|
|
|
|
qemuMonitorSendVNCPassphrase,
|
|
|
|
(char *)password,
|
|
|
|
-1, &info) < 0) {
|
2009-09-23 12:06:57 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("setting VNC password failed"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(info);
|
|
|
|
return 0;
|
|
|
|
}
|
2009-09-23 12:35:10 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns: 0 if balloon not supported, +1 if balloon adjust worked
|
|
|
|
* or -1 on failure
|
|
|
|
*/
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextSetBalloon(qemuMonitorPtr mon,
|
|
|
|
unsigned long newmem)
|
2009-09-23 12:35:10 +01:00
|
|
|
{
|
|
|
|
char *cmd;
|
|
|
|
char *reply = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 'newmem' is in KB, QEMU monitor works in MB, and we all wish
|
|
|
|
* we just worked in bytes with unsigned long long everywhere.
|
|
|
|
*/
|
|
|
|
if (virAsprintf(&cmd, "balloon %lu", (newmem / 1024)) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
|
2009-09-23 12:35:10 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("could not balloon memory allocation"));
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
|
|
|
|
/* If the command failed qemu prints: 'unknown command'
|
|
|
|
* No message is printed on success it seems */
|
|
|
|
if (strstr(reply, "\nunknown command:")) {
|
|
|
|
/* Don't set error - it is expected memory balloon fails on many qemu */
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(reply);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextEjectMedia(qemuMonitorPtr mon,
|
|
|
|
const char *devname)
|
2009-09-23 12:51:59 +01:00
|
|
|
{
|
|
|
|
char *cmd = NULL;
|
|
|
|
char *reply = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (virAsprintf(&cmd, "eject %s", devname) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
|
2009-09-23 12:51:59 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("could not eject media on %s"), devname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the command failed qemu prints:
|
|
|
|
* device not found, device is locked ...
|
|
|
|
* No message is printed on success it seems */
|
|
|
|
if (strstr(reply, "\ndevice ")) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("could not eject media on %s: %s"), devname, reply);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(reply);
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextChangeMedia(qemuMonitorPtr mon,
|
|
|
|
const char *devname,
|
2009-11-26 13:48:17 +00:00
|
|
|
const char *newmedia,
|
|
|
|
const char *format ATTRIBUTE_UNUSED)
|
2009-09-23 12:51:59 +01:00
|
|
|
{
|
|
|
|
char *cmd = NULL;
|
|
|
|
char *reply = NULL;
|
|
|
|
char *safepath = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
2009-09-23 17:39:07 +01:00
|
|
|
if (!(safepath = qemuMonitorEscapeArg(newmedia))) {
|
2009-09-23 12:51:59 +01:00
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&cmd, "change %s \"%s\"", devname, safepath) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
|
2009-09-23 12:51:59 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("could not eject media on %s"), devname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the command failed qemu prints:
|
|
|
|
* device not found, device is locked ...
|
|
|
|
* No message is printed on success it seems */
|
|
|
|
if (strstr(reply, "\ndevice ")) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("could not eject media on %s: %s"), devname, reply);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(reply);
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
VIR_FREE(safepath);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
static int qemuMonitorTextSaveMemory(qemuMonitorPtr mon,
|
|
|
|
const char *cmdtype,
|
|
|
|
unsigned long long offset,
|
|
|
|
size_t length,
|
|
|
|
const char *path)
|
2009-09-23 13:33:45 +01:00
|
|
|
{
|
|
|
|
char *cmd = NULL;
|
|
|
|
char *reply = NULL;
|
|
|
|
char *safepath = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
2009-09-23 17:39:07 +01:00
|
|
|
if (!(safepath = qemuMonitorEscapeArg(path))) {
|
2009-09-23 13:33:45 +01:00
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&cmd, "%s %llu %zi \"%s\"", cmdtype, offset, length, safepath) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
|
2009-09-23 13:33:45 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("could save memory region to '%s'"), path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX what is printed on failure ? */
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
VIR_FREE(reply);
|
|
|
|
VIR_FREE(safepath);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextSaveVirtualMemory(qemuMonitorPtr mon,
|
|
|
|
unsigned long long offset,
|
|
|
|
size_t length,
|
|
|
|
const char *path)
|
2009-09-23 13:33:45 +01:00
|
|
|
{
|
2009-10-09 21:13:06 +01:00
|
|
|
return qemuMonitorTextSaveMemory(mon, "memsave", offset, length, path);
|
2009-09-23 13:33:45 +01:00
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextSavePhysicalMemory(qemuMonitorPtr mon,
|
|
|
|
unsigned long long offset,
|
|
|
|
size_t length,
|
|
|
|
const char *path)
|
2009-09-23 13:33:45 +01:00
|
|
|
{
|
2009-10-09 21:13:06 +01:00
|
|
|
return qemuMonitorTextSaveMemory(mon, "pmemsave", offset, length, path);
|
2009-09-23 13:33:45 +01:00
|
|
|
}
|
2009-09-23 13:57:56 +01:00
|
|
|
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextSetMigrationSpeed(qemuMonitorPtr mon,
|
|
|
|
unsigned long bandwidth)
|
2009-09-23 13:57:56 +01:00
|
|
|
{
|
|
|
|
char *cmd = NULL;
|
|
|
|
char *info = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (virAsprintf(&cmd, "migrate_set_speed %lum", bandwidth) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &info) < 0) {
|
2009-09-23 13:57:56 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("could restrict migration speed"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(info);
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
2009-09-23 14:27:12 +01:00
|
|
|
|
|
|
|
|
|
|
|
#define MIGRATION_PREFIX "Migration status: "
|
|
|
|
#define MIGRATION_TRANSFER_PREFIX "transferred ram: "
|
|
|
|
#define MIGRATION_REMAINING_PREFIX "remaining ram: "
|
|
|
|
#define MIGRATION_TOTAL_PREFIX "total ram: "
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextGetMigrationStatus(qemuMonitorPtr mon,
|
|
|
|
int *status,
|
|
|
|
unsigned long long *transferred,
|
|
|
|
unsigned long long *remaining,
|
|
|
|
unsigned long long *total) {
|
2009-09-23 14:27:12 +01:00
|
|
|
char *reply;
|
|
|
|
char *tmp;
|
|
|
|
char *end;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
*status = QEMU_MONITOR_MIGRATION_STATUS_INACTIVE;
|
|
|
|
*transferred = 0;
|
|
|
|
*remaining = 0;
|
|
|
|
*total = 0;
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, "info migrate", &reply) < 0) {
|
2009-09-23 14:27:12 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("cannot query migration status"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((tmp = strstr(reply, MIGRATION_PREFIX)) != NULL) {
|
|
|
|
tmp += strlen(MIGRATION_PREFIX);
|
2009-10-01 20:18:28 +02:00
|
|
|
end = strchr(tmp, '\r');
|
2009-09-23 14:27:12 +01:00
|
|
|
*end = '\0';
|
|
|
|
|
|
|
|
if ((*status = qemuMonitorMigrationStatusTypeFromString(tmp)) < 0) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unexpected migration status in %s"), reply);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*status == QEMU_MONITOR_MIGRATION_STATUS_ACTIVE) {
|
|
|
|
tmp = end + 1;
|
|
|
|
|
|
|
|
if (!(tmp = strstr(tmp, MIGRATION_TRANSFER_PREFIX)))
|
|
|
|
goto done;
|
|
|
|
tmp += strlen(MIGRATION_TRANSFER_PREFIX);
|
|
|
|
|
|
|
|
if (virStrToLong_ull(tmp, NULL, 10, transferred) < 0) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse migration data transferred statistic %s"), tmp);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
*transferred *= 1024;
|
|
|
|
|
|
|
|
if (!(tmp = strstr(tmp, MIGRATION_REMAINING_PREFIX)))
|
|
|
|
goto done;
|
|
|
|
tmp += strlen(MIGRATION_REMAINING_PREFIX);
|
|
|
|
|
|
|
|
if (virStrToLong_ull(tmp, NULL, 10, remaining) < 0) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse migration data remaining statistic %s"), tmp);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
*remaining *= 1024;
|
|
|
|
|
|
|
|
if (!(tmp = strstr(tmp, MIGRATION_TOTAL_PREFIX)))
|
|
|
|
goto done;
|
|
|
|
tmp += strlen(MIGRATION_TOTAL_PREFIX);
|
|
|
|
|
|
|
|
if (virStrToLong_ull(tmp, NULL, 10, total) < 0) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot parse migration data total statistic %s"), tmp);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
*total *= 1024;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(reply);
|
|
|
|
return ret;
|
|
|
|
}
|
2009-09-23 14:48:49 +01:00
|
|
|
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
static int qemuMonitorTextMigrate(qemuMonitorPtr mon,
|
|
|
|
int background,
|
|
|
|
const char *dest)
|
2009-09-23 14:48:49 +01:00
|
|
|
{
|
|
|
|
char *cmd = NULL;
|
|
|
|
char *info = NULL;
|
|
|
|
int ret = -1;
|
2009-09-23 17:39:07 +01:00
|
|
|
char *safedest = qemuMonitorEscapeArg(dest);
|
2009-09-30 14:51:32 +02:00
|
|
|
const char *extra;
|
2009-09-23 14:48:49 +01:00
|
|
|
|
2009-09-23 15:23:47 +01:00
|
|
|
if (!safedest) {
|
2009-09-23 14:48:49 +01:00
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-09-30 14:51:32 +02:00
|
|
|
if (background)
|
|
|
|
extra = "-d ";
|
|
|
|
else
|
|
|
|
extra = " ";
|
|
|
|
|
|
|
|
if (virAsprintf(&cmd, "migrate %s\"%s\"", extra, safedest) < 0) {
|
2009-09-23 15:23:47 +01:00
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &info) < 0) {
|
2009-09-23 14:48:49 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unable to start migration to %s"), dest);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now check for "fail" in the output string */
|
|
|
|
if (strstr(info, "fail") != NULL) {
|
2009-09-23 15:23:47 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("migration to '%s' failed: %s"), dest, info);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
/* If the command isn't supported then qemu prints:
|
|
|
|
* unknown command: migrate" */
|
|
|
|
if (strstr(info, "unknown command:")) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_SUPPORT,
|
|
|
|
_("migration to '%s' not supported by this qemu: %s"), dest, info);
|
2009-09-23 14:48:49 +01:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
2009-09-23 15:23:47 +01:00
|
|
|
VIR_FREE(safedest);
|
2009-09-23 14:48:49 +01:00
|
|
|
VIR_FREE(info);
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextMigrateToHost(qemuMonitorPtr mon,
|
|
|
|
int background,
|
|
|
|
const char *hostname,
|
|
|
|
int port)
|
2009-09-23 14:48:49 +01:00
|
|
|
{
|
2009-09-23 15:23:47 +01:00
|
|
|
char *uri = NULL;
|
2009-09-23 14:48:49 +01:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (virAsprintf(&uri, "tcp:%s:%d", hostname, port) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
ret = qemuMonitorTextMigrate(mon, background, uri);
|
2009-09-23 14:48:49 +01:00
|
|
|
|
|
|
|
VIR_FREE(uri);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2009-09-23 15:23:47 +01:00
|
|
|
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextMigrateToCommand(qemuMonitorPtr mon,
|
|
|
|
int background,
|
|
|
|
const char * const *argv,
|
|
|
|
const char *target)
|
2009-09-23 15:23:47 +01:00
|
|
|
{
|
|
|
|
char *argstr;
|
|
|
|
char *dest = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
char *safe_target = NULL;
|
|
|
|
|
|
|
|
argstr = virArgvToString(argv);
|
|
|
|
if (!argstr) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Migrate to file */
|
2009-09-23 17:39:07 +01:00
|
|
|
safe_target = qemuMonitorEscapeShell(target);
|
2009-09-23 15:23:47 +01:00
|
|
|
if (!safe_target) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&dest, "exec:%s >>%s 2>/dev/null", argstr, safe_target) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
ret = qemuMonitorTextMigrate(mon, background, dest);
|
2009-09-23 15:23:47 +01:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(safe_target);
|
|
|
|
VIR_FREE(argstr);
|
|
|
|
VIR_FREE(dest);
|
|
|
|
return ret;
|
|
|
|
}
|
2009-09-23 15:38:43 +01:00
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextMigrateToUnix(qemuMonitorPtr mon,
|
2009-11-26 13:48:17 +00:00
|
|
|
int background,
|
|
|
|
const char *unixfile)
|
2009-09-30 14:51:32 +02:00
|
|
|
{
|
|
|
|
char *dest = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (virAsprintf(&dest, "unix:%s", unixfile) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
ret = qemuMonitorTextMigrate(mon, background, dest);
|
2009-09-30 14:51:32 +02:00
|
|
|
|
|
|
|
VIR_FREE(dest);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextMigrateCancel(qemuMonitorPtr mon)
|
2009-09-30 14:51:32 +02:00
|
|
|
{
|
|
|
|
char *info = NULL;
|
|
|
|
|
2009-11-26 13:39:30 +00:00
|
|
|
if (qemuMonitorCommand(mon, "migrate_cancel", &info) < 0) {
|
2009-09-30 14:51:32 +02:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("cannot run monitor command to cancel migration"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(info);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2009-09-23 15:38:43 +01:00
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextAddUSBDisk(qemuMonitorPtr mon,
|
|
|
|
const char *path)
|
2009-09-23 15:38:43 +01:00
|
|
|
{
|
|
|
|
char *cmd = NULL;
|
|
|
|
char *safepath;
|
|
|
|
int ret = -1;
|
|
|
|
char *info = NULL;
|
|
|
|
|
2009-09-23 17:39:07 +01:00
|
|
|
safepath = qemuMonitorEscapeArg(path);
|
2009-09-23 15:38:43 +01:00
|
|
|
if (!safepath) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&cmd, "usb_add disk:%s", safepath) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &info) < 0) {
|
2009-09-23 15:38:43 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("cannot run monitor command to add usb disk"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the command failed qemu prints:
|
|
|
|
* Could not add ... */
|
|
|
|
if (strstr(info, "Could not add ")) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("unable to add USB disk %s: %s"), path, info);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
VIR_FREE(safepath);
|
|
|
|
return ret;
|
|
|
|
}
|
2009-09-23 16:04:55 +01:00
|
|
|
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
static int qemuMonitorTextAddUSBDevice(qemuMonitorPtr mon,
|
|
|
|
const char *addr)
|
2009-09-23 16:04:55 +01:00
|
|
|
{
|
|
|
|
char *cmd;
|
|
|
|
char *reply = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (virAsprintf(&cmd, "usb_add %s", addr) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
|
2009-09-23 16:04:55 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("cannot attach usb device"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the command failed qemu prints:
|
|
|
|
* Could not add ... */
|
|
|
|
if (strstr(reply, "Could not add ")) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("adding usb device failed"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
VIR_FREE(reply);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextAddUSBDeviceExact(qemuMonitorPtr mon,
|
|
|
|
int bus,
|
|
|
|
int dev)
|
2009-09-23 16:04:55 +01:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
char *addr;
|
|
|
|
|
|
|
|
if (virAsprintf(&addr, "host:%.3d.%.3d", bus, dev) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
ret = qemuMonitorTextAddUSBDevice(mon, addr);
|
2009-09-23 16:04:55 +01:00
|
|
|
|
|
|
|
VIR_FREE(addr);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextAddUSBDeviceMatch(qemuMonitorPtr mon,
|
|
|
|
int vendor,
|
|
|
|
int product)
|
2009-09-23 16:04:55 +01:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
char *addr;
|
|
|
|
|
|
|
|
if (virAsprintf(&addr, "host:%.4x:%.4x", vendor, product) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
ret = qemuMonitorTextAddUSBDevice(mon, addr);
|
2009-09-23 16:04:55 +01:00
|
|
|
|
|
|
|
VIR_FREE(addr);
|
|
|
|
return ret;
|
|
|
|
}
|
2009-09-23 16:15:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
static int
|
2009-10-09 21:13:06 +01:00
|
|
|
qemuMonitorTextParsePciAddReply(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
|
|
|
const char *reply,
|
|
|
|
unsigned *domain,
|
|
|
|
unsigned *bus,
|
|
|
|
unsigned *slot)
|
2009-09-23 16:15:51 +01:00
|
|
|
{
|
|
|
|
char *s, *e;
|
|
|
|
|
|
|
|
/* If the command succeeds qemu prints:
|
|
|
|
* OK bus 0, slot XXX...
|
|
|
|
* or
|
|
|
|
* OK domain 0, bus 0, slot XXX
|
|
|
|
*/
|
|
|
|
if (!(s = strstr(reply, "OK ")))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
s += 3;
|
|
|
|
|
|
|
|
if (STRPREFIX(s, "domain ")) {
|
|
|
|
s += strlen("domain ");
|
|
|
|
|
|
|
|
if (virStrToLong_ui(s, &e, 10, domain) == -1) {
|
|
|
|
VIR_WARN(_("Unable to parse domain number '%s'\n"), s);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!STRPREFIX(e, ", ")) {
|
|
|
|
VIR_WARN(_("Expected ', ' parsing pci_add reply '%s'\n"), s);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
s = e + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!STRPREFIX(s, "bus ")) {
|
|
|
|
VIR_WARN(_("Expected 'bus ' parsing pci_add reply '%s'\n"), s);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
s += strlen("bus ");
|
|
|
|
|
|
|
|
if (virStrToLong_ui(s, &e, 10, bus) == -1) {
|
|
|
|
VIR_WARN(_("Unable to parse bus number '%s'\n"), s);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!STRPREFIX(e, ", ")) {
|
|
|
|
VIR_WARN(_("Expected ', ' parsing pci_add reply '%s'\n"), s);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
s = e + 2;
|
|
|
|
|
|
|
|
if (!STRPREFIX(s, "slot ")) {
|
|
|
|
VIR_WARN(_("Expected 'slot ' parsing pci_add reply '%s'\n"), s);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
s += strlen("slot ");
|
|
|
|
|
|
|
|
if (virStrToLong_ui(s, &e, 10, slot) == -1) {
|
|
|
|
VIR_WARN(_("Unable to parse slot number '%s'\n"), s);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextAddPCIHostDevice(qemuMonitorPtr mon,
|
|
|
|
unsigned hostDomain ATTRIBUTE_UNUSED,
|
|
|
|
unsigned hostBus,
|
|
|
|
unsigned hostSlot,
|
|
|
|
unsigned hostFunction,
|
|
|
|
unsigned *guestDomain,
|
|
|
|
unsigned *guestBus,
|
|
|
|
unsigned *guestSlot)
|
2009-09-23 16:15:51 +01:00
|
|
|
{
|
|
|
|
char *cmd;
|
|
|
|
char *reply = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
*guestDomain = *guestBus = *guestSlot = 0;
|
|
|
|
|
|
|
|
/* XXX hostDomain */
|
|
|
|
if (virAsprintf(&cmd, "pci_add pci_addr=auto host host=%.2x:%.2x.%.1x",
|
|
|
|
hostBus, hostSlot, hostFunction) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
|
2009-09-23 16:15:51 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("cannot attach host pci device"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strstr(reply, "invalid type: host")) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("PCI device assignment is not supported by this version of qemu"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorTextParsePciAddReply(mon, reply,
|
|
|
|
guestDomain,
|
|
|
|
guestBus,
|
|
|
|
guestSlot) < 0) {
|
2009-09-23 16:15:51 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("parsing pci_add reply failed: %s"), reply);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
VIR_FREE(reply);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-09-23 16:25:05 +01:00
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextAddPCIDisk(qemuMonitorPtr mon,
|
|
|
|
const char *path,
|
|
|
|
const char *bus,
|
|
|
|
unsigned *guestDomain,
|
|
|
|
unsigned *guestBus,
|
|
|
|
unsigned *guestSlot) {
|
2009-09-23 16:38:44 +01:00
|
|
|
char *cmd = NULL;
|
|
|
|
char *reply = NULL;
|
|
|
|
char *safe_path = NULL;
|
|
|
|
int tryOldSyntax = 0;
|
|
|
|
int ret = -1;
|
|
|
|
|
2009-09-23 17:39:07 +01:00
|
|
|
safe_path = qemuMonitorEscapeArg(path);
|
2009-09-23 16:38:44 +01:00
|
|
|
if (!safe_path) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
try_command:
|
|
|
|
if (virAsprintf(&cmd, "pci_add %s storage file=%s,if=%s",
|
|
|
|
(tryOldSyntax ? "0": "pci_addr=auto"), safe_path, bus) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
|
2009-09-23 16:38:44 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("cannot attach %s disk %s"), bus, path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorTextParsePciAddReply(mon, reply,
|
|
|
|
guestDomain, guestBus, guestSlot) < 0) {
|
2009-09-23 16:38:44 +01:00
|
|
|
if (!tryOldSyntax && strstr(reply, "invalid char in expression")) {
|
|
|
|
VIR_FREE(reply);
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
tryOldSyntax = 1;
|
|
|
|
goto try_command;
|
|
|
|
}
|
|
|
|
|
|
|
|
qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("adding %s disk failed %s: %s"), bus, path, reply);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(safe_path);
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
VIR_FREE(reply);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextAddPCINetwork(qemuMonitorPtr mon,
|
|
|
|
const char *nicstr,
|
|
|
|
unsigned *guestDomain,
|
|
|
|
unsigned *guestBus,
|
|
|
|
unsigned *guestSlot)
|
2009-09-23 17:01:39 +01:00
|
|
|
{
|
|
|
|
char *cmd;
|
|
|
|
char *reply = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (virAsprintf(&cmd, "pci_add pci_addr=auto nic %s", nicstr) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
|
2009-09-23 17:01:39 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("failed to add NIC with '%s'"), cmd);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorTextParsePciAddReply(mon, reply,
|
|
|
|
guestDomain, guestBus, guestSlot) < 0) {
|
2009-09-23 17:01:39 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("parsing pci_add reply failed: %s"), reply);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(reply);
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-09-23 16:38:44 +01:00
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextRemovePCIDevice(qemuMonitorPtr mon,
|
|
|
|
unsigned guestDomain,
|
|
|
|
unsigned guestBus,
|
|
|
|
unsigned guestSlot)
|
2009-09-23 16:25:05 +01:00
|
|
|
{
|
|
|
|
char *cmd = NULL;
|
|
|
|
char *reply = NULL;
|
|
|
|
int tryOldSyntax = 0;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
try_command:
|
|
|
|
if (tryOldSyntax) {
|
|
|
|
if (virAsprintf(&cmd, "pci_del 0 %.2x", guestSlot) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (virAsprintf(&cmd, "pci_del pci_addr=%.4x:%.2x:%.2x",
|
|
|
|
guestDomain, guestBus, guestSlot) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
|
2009-09-23 16:25:05 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("failed to remove PCI device"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Syntax changed when KVM merged PCI hotplug upstream to QEMU,
|
|
|
|
* so check for an error message from old KVM indicating the
|
|
|
|
* need to try the old syntax */
|
|
|
|
if (!tryOldSyntax &&
|
|
|
|
strstr(reply, "extraneous characters")) {
|
|
|
|
tryOldSyntax = 1;
|
|
|
|
VIR_FREE(reply);
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
goto try_command;
|
|
|
|
}
|
|
|
|
/* If the command fails due to a wrong slot qemu prints: invalid slot,
|
|
|
|
* nothing is printed on success */
|
|
|
|
if (strstr(reply, "invalid slot") ||
|
|
|
|
strstr(reply, "Invalid pci address")) {
|
|
|
|
qemudReportError (NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("failed to detach PCI device, invalid address %.4x:%.2x:%.2x: %s"),
|
|
|
|
guestDomain, guestBus, guestSlot, reply);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
VIR_FREE(reply);
|
|
|
|
return ret;
|
|
|
|
}
|
2009-09-23 16:51:10 +01:00
|
|
|
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextSendFileHandle(qemuMonitorPtr mon,
|
|
|
|
const char *fdname,
|
|
|
|
int fd)
|
2009-09-23 16:51:10 +01:00
|
|
|
{
|
|
|
|
char *cmd;
|
|
|
|
char *reply = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (virAsprintf(&cmd, "getfd %s", fdname) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommandWithFd(mon, cmd, fd, &reply) < 0) {
|
2009-09-23 16:51:10 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("failed to pass fd to qemu with '%s'"), cmd);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the command isn't supported then qemu prints:
|
|
|
|
* unknown command: getfd" */
|
|
|
|
if (strstr(reply, "unknown command:")) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_SUPPORT,
|
|
|
|
_("qemu does not support sending of file handles: %s"),
|
|
|
|
reply);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
VIR_FREE(reply);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextCloseFileHandle(qemuMonitorPtr mon,
|
|
|
|
const char *fdname)
|
2009-09-23 16:51:10 +01:00
|
|
|
{
|
|
|
|
char *cmd;
|
|
|
|
char *reply = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (virAsprintf(&cmd, "closefd %s", fdname) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
|
2009-09-23 16:51:10 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("failed to close fd in qemu with '%s'"), cmd);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the command isn't supported then qemu prints:
|
|
|
|
* unknown command: getfd" */
|
|
|
|
if (strstr(reply, "unknown command:")) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_SUPPORT,
|
|
|
|
_("qemu does not support closing of file handles: %s"),
|
|
|
|
reply);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
VIR_FREE(reply);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-09-23 17:25:28 +01:00
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextAddHostNetwork(qemuMonitorPtr mon,
|
|
|
|
const char *netstr)
|
2009-09-23 17:25:28 +01:00
|
|
|
{
|
|
|
|
char *cmd;
|
|
|
|
char *reply = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (virAsprintf(&cmd, "host_net_add %s", netstr) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
|
2009-09-23 17:25:28 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("failed to close fd in qemu with '%s'"), cmd);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX error messages here ? */
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
VIR_FREE(reply);
|
|
|
|
return ret;
|
|
|
|
}
|
2009-09-23 17:32:50 +01:00
|
|
|
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
int qemuMonitorTextRemoveHostNetwork(qemuMonitorPtr mon,
|
|
|
|
int vlan,
|
|
|
|
const char *netname)
|
2009-09-23 17:32:50 +01:00
|
|
|
{
|
|
|
|
char *cmd;
|
|
|
|
char *reply = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (virAsprintf(&cmd, "host_net_remove %d %s", vlan, netname) < 0) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-10-09 21:13:06 +01:00
|
|
|
if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
|
2009-09-23 17:32:50 +01:00
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
2009-11-17 12:18:39 +01:00
|
|
|
_("failed to remove host network in qemu with '%s'"), cmd);
|
2009-09-23 17:32:50 +01:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX error messages here ? */
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(cmd);
|
|
|
|
VIR_FREE(reply);
|
|
|
|
return ret;
|
|
|
|
}
|
2009-12-14 10:50:01 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* Parse the output of "info chardev" and return a hash of pty paths.
|
|
|
|
*
|
|
|
|
* Output is:
|
|
|
|
* foo: filename=pty:/dev/pts/7
|
|
|
|
* monitor: filename=stdio
|
|
|
|
* serial0: filename=vc
|
|
|
|
* parallel0: filename=vc
|
|
|
|
*
|
|
|
|
* Non-pty lines are ignored. In the above example, key is 'foo', value is
|
|
|
|
* '/dev/pty/7'. The hash will contain only a single value.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int qemuMonitorTextGetPtyPaths(qemuMonitorPtr mon,
|
|
|
|
virHashTablePtr paths)
|
|
|
|
{
|
|
|
|
const char *cmd = "info chardev";
|
|
|
|
char *reply = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (qemuMonitorCommand(mon, cmd, &reply) < 0) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("failed to retrieve chardev info in qemu with '%s'"),
|
|
|
|
cmd);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *pos = reply; /* The current start of searching */
|
|
|
|
char *end = pos + strlen(reply); /* The end of the reply string */
|
|
|
|
char *eol; /* The character which ends the current line */
|
|
|
|
|
|
|
|
while (pos < end) {
|
|
|
|
/* Split the output into lines */
|
|
|
|
eol = memchr(pos, '\n', end - pos);
|
|
|
|
if (eol == NULL)
|
|
|
|
eol = end;
|
|
|
|
|
|
|
|
/* Look for 'filename=pty:' */
|
|
|
|
#define NEEDLE "filename=pty:"
|
|
|
|
char *needle = memmem(pos, eol - pos, NEEDLE, strlen(NEEDLE));
|
|
|
|
|
|
|
|
/* If it's not there we can ignore this line */
|
|
|
|
if (!needle)
|
|
|
|
goto next;
|
|
|
|
|
|
|
|
/* id is everthing from the beginning of the line to the ':'
|
|
|
|
* find ':' and turn it into a terminator */
|
|
|
|
char *colon = memchr(pos, ':', needle - pos);
|
|
|
|
if (colon == NULL)
|
|
|
|
goto next;
|
|
|
|
*colon = '\0';
|
|
|
|
char *id = pos;
|
|
|
|
|
|
|
|
/* Path is everything after needle to the end of the line */
|
|
|
|
*eol = '\0';
|
2009-12-14 11:05:55 +01:00
|
|
|
char *path = strdup(needle + strlen(NEEDLE));
|
|
|
|
if (path == NULL) {
|
|
|
|
virReportOOMError(NULL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-12-14 10:50:01 +01:00
|
|
|
|
2009-12-14 11:05:55 +01:00
|
|
|
if (virHashAddEntry(paths, id, path) < 0) {
|
|
|
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("failed to save chardev path '%s'"),
|
|
|
|
path);
|
|
|
|
VIR_FREE(path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-12-14 10:50:01 +01:00
|
|
|
#undef NEEDLE
|
|
|
|
|
|
|
|
next:
|
|
|
|
pos = eol + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(reply);
|
|
|
|
return ret;
|
|
|
|
}
|