#include "hw/loader.h"
#include "gdbstub.h"
#include "net.h"
+#include "net/slirp.h"
#include "qemu-char.h"
#include "sysemu.h"
#include "monitor.h"
#include "kvm.h"
#include "acl.h"
#include "qint.h"
+#include "qfloat.h"
#include "qlist.h"
#include "qdict.h"
#include "qbool.h"
#include "qjson.h"
#include "json-streamer.h"
#include "json-parser.h"
+#include "osdep.h"
//#define DEBUG
//#define DEBUG_COMPLETION
* 's' string (accept optional quote)
* 'i' 32 bit integer
* 'l' target long (32 or 64 bit)
+ * 'M' just like 'l', except in user mode the value is
+ * multiplied by 2^20 (think Mebibyte)
+ * 'b' double
+ * user mode accepts an optional G, g, M, m, K, k suffix,
+ * which multiplies the value by 2^30 for suffixes G and
+ * g, 2^20 for M and m, 2^10 for K and k
+ * 'T' double
+ * user mode accepts an optional ms, us, ns suffix,
+ * which divides the value by 1e3, 1e6, 1e9, respectively
* '/' optional gdb-like print format (like "/10x")
*
* '?' optional type (for all types, except '/')
*
*/
+typedef struct MonitorCompletionData MonitorCompletionData;
+struct MonitorCompletionData {
+ Monitor *mon;
+ void (*user_print)(Monitor *mon, const QObject *data);
+};
+
typedef struct mon_cmd_t {
const char *name;
const char *args_type;
union {
void (*info)(Monitor *mon);
void (*info_new)(Monitor *mon, QObject **ret_data);
+ int (*info_async)(Monitor *mon, MonitorCompletion *cb, void *opaque);
void (*cmd)(Monitor *mon, const QDict *qdict);
- void (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
+ int (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
+ int (*cmd_async)(Monitor *mon, const QDict *params,
+ MonitorCompletion *cb, void *opaque);
} mhandler;
+ int async;
} mon_cmd_t;
/* file descriptors passed via SCM_RIGHTS */
typedef struct MonitorControl {
QObject *id;
JSONMessageParser parser;
+ int command_mode;
} MonitorControl;
struct Monitor {
CPUState *mon_cpu;
BlockDriverCompletionFunc *password_completion_cb;
void *password_opaque;
+#ifdef CONFIG_DEBUG_MONITOR
+ int print_calls_nr;
+#endif
QError *error;
QLIST_HEAD(,mon_fd_t) fds;
QLIST_ENTRY(Monitor) entry;
};
+#ifdef CONFIG_DEBUG_MONITOR
+#define MON_DEBUG(fmt, ...) do { \
+ fprintf(stderr, "Monitor: "); \
+ fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+
+static inline void mon_print_count_inc(Monitor *mon)
+{
+ mon->print_calls_nr++;
+}
+
+static inline void mon_print_count_init(Monitor *mon)
+{
+ mon->print_calls_nr = 0;
+}
+
+static inline int mon_print_count_get(const Monitor *mon)
+{
+ return mon->print_calls_nr;
+}
+
+#else /* !CONFIG_DEBUG_MONITOR */
+#define MON_DEBUG(fmt, ...) do { } while (0)
+static inline void mon_print_count_inc(Monitor *mon) { }
+static inline void mon_print_count_init(Monitor *mon) { }
+static inline int mon_print_count_get(const Monitor *mon) { return 0; }
+#endif /* CONFIG_DEBUG_MONITOR */
+
static QLIST_HEAD(mon_list, Monitor) mon_list;
static const mon_cmd_t mon_cmds[];
static void monitor_command_cb(Monitor *mon, const char *cmdline,
void *opaque);
+static inline int qmp_cmd_mode(const Monitor *mon)
+{
+ return (mon->mc ? mon->mc->command_mode : 0);
+}
+
/* Return true if in control mode, false otherwise */
static inline int monitor_ctrl_mode(const Monitor *mon)
{
static void monitor_read_command(Monitor *mon, int show_prompt)
{
+ if (!mon->rs)
+ return;
+
readline_start(mon->rs, "(qemu) ", 0, monitor_command_cb, NULL);
if (show_prompt)
readline_show_prompt(mon->rs);
static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
void *opaque)
{
- if (mon->rs) {
+ if (monitor_ctrl_mode(mon)) {
+ qemu_error_new(QERR_MISSING_PARAMETER, "password");
+ return -EINVAL;
+ } else if (mon->rs) {
readline_start(mon->rs, "Password: ", 1, readline_func, opaque);
/* prompt is printed on return from the command handler */
return 0;
{
char c;
- if (!mon)
- return;
-
for(;;) {
c = *str++;
if (c == '\0')
void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
{
char buf[4096];
+
+ if (!mon)
+ return;
+
+ mon_print_count_inc(mon);
+
+ if (monitor_ctrl_mode(mon)) {
+ return;
+ }
+
vsnprintf(buf, sizeof(buf), fmt, ap);
monitor_puts(mon, buf);
}
return cmd->user_print != NULL;
}
-static inline int monitor_has_error(const Monitor *mon)
+static inline bool monitor_handler_is_async(const mon_cmd_t *cmd)
{
- return mon->error != NULL;
+ return cmd->async != 0;
}
-static void monitor_print_qobject(Monitor *mon, const QObject *data)
+static inline int monitor_has_error(const Monitor *mon)
{
- switch (qobject_type(data)) {
- case QTYPE_QSTRING:
- monitor_printf(mon, "%s",qstring_get_str(qobject_to_qstring(data)));
- break;
- case QTYPE_QINT:
- monitor_printf(mon, "%" PRId64,qint_get_int(qobject_to_qint(data)));
- break;
- default:
- monitor_printf(mon, "ERROR: unsupported type: %d",
- qobject_type(data));
- break;
- }
-
- monitor_puts(mon, "\n");
+ return mon->error != NULL;
}
static void monitor_json_emitter(Monitor *mon, const QObject *data)
json = qobject_to_json(data);
assert(json != NULL);
- monitor_printf(mon, "%s\n", qstring_get_str(json));
+ qstring_append_chr(json, '\n');
+ monitor_puts(mon, qstring_get_str(json));
+
QDECREF(json);
}
qobject_incref(data);
qdict_put_obj(qmp, "return", data);
} else {
- qdict_put(qmp, "return", qstring_from_str("OK"));
+ /* return an empty QDict by default */
+ qdict_put(qmp, "return", qdict_new());
}
} else {
/* error response */
+ qdict_put(mon->error->error, "desc", qerror_human(mon->error));
qdict_put(qmp, "error", mon->error->error);
QINCREF(mon->error->error);
QDECREF(mon->error);
QDECREF(qmp);
}
+static void timestamp_put(QDict *qdict)
+{
+ int err;
+ QObject *obj;
+ qemu_timeval tv;
+
+ err = qemu_gettimeofday(&tv);
+ if (err < 0)
+ return;
+
+ obj = qobject_from_jsonf("{ 'seconds': %" PRId64 ", "
+ "'microseconds': %" PRId64 " }",
+ (int64_t) tv.tv_sec, (int64_t) tv.tv_usec);
+ qdict_put_obj(qdict, "timestamp", obj);
+}
+
+/**
+ * monitor_protocol_event(): Generate a Monitor event
+ *
+ * Event-specific data can be emitted through the (optional) 'data' parameter.
+ */
+void monitor_protocol_event(MonitorEvent event, QObject *data)
+{
+ QDict *qmp;
+ const char *event_name;
+ Monitor *mon;
+
+ assert(event < QEVENT_MAX);
+
+ switch (event) {
+ case QEVENT_DEBUG:
+ event_name = "DEBUG";
+ break;
+ case QEVENT_SHUTDOWN:
+ event_name = "SHUTDOWN";
+ break;
+ case QEVENT_RESET:
+ event_name = "RESET";
+ break;
+ case QEVENT_POWERDOWN:
+ event_name = "POWERDOWN";
+ break;
+ case QEVENT_STOP:
+ event_name = "STOP";
+ break;
+ case QEVENT_VNC_CONNECTED:
+ event_name = "VNC_CONNECTED";
+ break;
+ case QEVENT_VNC_INITIALIZED:
+ event_name = "VNC_INITIALIZED";
+ break;
+ case QEVENT_VNC_DISCONNECTED:
+ event_name = "VNC_DISCONNECTED";
+ break;
+ case QEVENT_BLOCK_IO_ERROR:
+ event_name = "BLOCK_IO_ERROR";
+ break;
+ default:
+ abort();
+ break;
+ }
+
+ qmp = qdict_new();
+ timestamp_put(qmp);
+ qdict_put(qmp, "event", qstring_from_str(event_name));
+ if (data) {
+ qobject_incref(data);
+ qdict_put_obj(qmp, "data", data);
+ }
+
+ QLIST_FOREACH(mon, &mon_list, entry) {
+ if (monitor_ctrl_mode(mon) && qmp_cmd_mode(mon)) {
+ monitor_json_emitter(mon, QOBJECT(qmp));
+ }
+ }
+ QDECREF(qmp);
+}
+
+static int do_qmp_capabilities(Monitor *mon, const QDict *params,
+ QObject **ret_data)
+{
+ /* Will setup QMP capabilities in the future */
+ if (monitor_ctrl_mode(mon)) {
+ mon->mc->command_mode = 1;
+ }
+
+ return 0;
+}
+
static int compare_cmd(const char *name, const char *list)
{
const char *p, *pstart;
}
}
-static void do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static void user_monitor_complete(void *opaque, QObject *ret_data)
+{
+ MonitorCompletionData *data = (MonitorCompletionData *)opaque;
+
+ if (ret_data) {
+ data->user_print(data->mon, ret_data);
+ }
+ monitor_resume(data->mon);
+ qemu_free(data);
+}
+
+static void qmp_monitor_complete(void *opaque, QObject *ret_data)
+{
+ monitor_protocol_emitter(opaque, ret_data);
+}
+
+static void qmp_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
+ const QDict *params)
+{
+ cmd->mhandler.cmd_async(mon, params, qmp_monitor_complete, mon);
+}
+
+static void qmp_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
+{
+ cmd->mhandler.info_async(mon, qmp_monitor_complete, mon);
+}
+
+static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
+ const QDict *params)
+{
+ int ret;
+
+ MonitorCompletionData *cb_data = qemu_malloc(sizeof(*cb_data));
+ cb_data->mon = mon;
+ cb_data->user_print = cmd->user_print;
+ monitor_suspend(mon);
+ ret = cmd->mhandler.cmd_async(mon, params,
+ user_monitor_complete, cb_data);
+ if (ret < 0) {
+ monitor_resume(mon);
+ qemu_free(cb_data);
+ }
+}
+
+static void user_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
+{
+ int ret;
+
+ MonitorCompletionData *cb_data = qemu_malloc(sizeof(*cb_data));
+ cb_data->mon = mon;
+ cb_data->user_print = cmd->user_print;
+ monitor_suspend(mon);
+ ret = cmd->mhandler.info_async(mon, user_monitor_complete, cb_data);
+ if (ret < 0) {
+ monitor_resume(mon);
+ qemu_free(cb_data);
+ }
+}
+
+static int do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const mon_cmd_t *cmd;
const char *item = qdict_get_try_str(qdict, "item");
if (cmd->name == NULL) {
if (monitor_ctrl_mode(mon)) {
qemu_error_new(QERR_COMMAND_NOT_FOUND, item);
- return;
+ return -1;
}
goto help;
}
- if (monitor_handler_ported(cmd)) {
+ if (monitor_handler_is_async(cmd)) {
+ if (monitor_ctrl_mode(mon)) {
+ qmp_async_info_handler(mon, cmd);
+ } else {
+ user_async_info_handler(mon, cmd);
+ }
+ /*
+ * Indicate that this command is asynchronous and will not return any
+ * data (not even empty). Instead, the data will be returned via a
+ * completion callback.
+ */
+ *ret_data = qobject_from_jsonf("{ '__mon_async': 'return' }");
+ } else if (monitor_handler_ported(cmd)) {
cmd->mhandler.info_new(mon, ret_data);
if (!monitor_ctrl_mode(mon)) {
if (monitor_ctrl_mode(mon)) {
/* handler not converted yet */
qemu_error_new(QERR_COMMAND_NOT_FOUND, item);
+ return -1;
} else {
cmd->mhandler.info(mon);
}
}
- return;
+ return 0;
help:
help_cmd(mon, "info");
+ return 0;
+}
+
+static void do_info_version_print(Monitor *mon, const QObject *data)
+{
+ QDict *qdict;
+
+ qdict = qobject_to_qdict(data);
+
+ monitor_printf(mon, "%s%s\n", qdict_get_str(qdict, "qemu"),
+ qdict_get_str(qdict, "package"));
}
/**
* do_info_version(): Show QEMU version
+ *
+ * Return a QDict with the following information:
+ *
+ * - "qemu": QEMU's version
+ * - "package": package's version
+ *
+ * Example:
+ *
+ * { "qemu": "0.11.50", "package": "" }
*/
static void do_info_version(Monitor *mon, QObject **ret_data)
{
- *ret_data = QOBJECT(qstring_from_str(QEMU_VERSION QEMU_PKGVERSION));
+ *ret_data = qobject_from_jsonf("{ 'qemu': %s, 'package': %s }",
+ QEMU_VERSION, QEMU_PKGVERSION);
}
-static void do_info_name(Monitor *mon)
+static void do_info_name_print(Monitor *mon, const QObject *data)
{
- if (qemu_name)
- monitor_printf(mon, "%s\n", qemu_name);
+ QDict *qdict;
+
+ qdict = qobject_to_qdict(data);
+ if (qdict_size(qdict) == 0) {
+ return;
+ }
+
+ monitor_printf(mon, "%s\n", qdict_get_str(qdict, "name"));
+}
+
+/**
+ * do_info_name(): Show VM name
+ *
+ * Return a QDict with the following information:
+ *
+ * - "name": VM's name (optional)
+ *
+ * Example:
+ *
+ * { "name": "qemu-name" }
+ */
+static void do_info_name(Monitor *mon, QObject **ret_data)
+{
+ *ret_data = qemu_name ? qobject_from_jsonf("{'name': %s }", qemu_name) :
+ qobject_from_jsonf("{}");
+}
+
+static QObject *get_cmd_dict(const char *name)
+{
+ const char *p;
+
+ /* Remove '|' from some commands */
+ p = strchr(name, '|');
+ if (p) {
+ p++;
+ } else {
+ p = name;
+ }
+
+ return qobject_from_jsonf("{ 'name': %s }", p);
}
/**
* do_info_commands(): List QMP available commands
*
- * Return a QList of QStrings.
+ * Each command is represented by a QDict, the returned QObject is a QList
+ * of all commands.
+ *
+ * The QDict contains:
+ *
+ * - "name": command's name
+ *
+ * Example:
+ *
+ * { [ { "name": "query-balloon" }, { "name": "system_powerdown" } ] }
*/
static void do_info_commands(Monitor *mon, QObject **ret_data)
{
for (cmd = mon_cmds; cmd->name != NULL; cmd++) {
if (monitor_handler_ported(cmd) && !compare_cmd(cmd->name, "info")) {
- qlist_append(cmd_list, qstring_from_str(cmd->name));
+ qlist_append_obj(cmd_list, get_cmd_dict(cmd->name));
}
}
if (monitor_handler_ported(cmd)) {
char buf[128];
snprintf(buf, sizeof(buf), "query-%s", cmd->name);
- qlist_append(cmd_list, qstring_from_str(buf));
+ qlist_append_obj(cmd_list, get_cmd_dict(buf));
}
}
}
#if defined(TARGET_I386)
-static void do_info_hpet(Monitor *mon)
+static void do_info_hpet_print(Monitor *mon, const QObject *data)
{
monitor_printf(mon, "HPET is %s by QEMU\n",
- (no_hpet) ? "disabled" : "enabled");
+ qdict_get_bool(qobject_to_qdict(data), "enabled") ?
+ "enabled" : "disabled");
+}
+
+/**
+ * do_info_hpet(): Show HPET state
+ *
+ * Return a QDict with the following information:
+ *
+ * - "enabled": true if hpet if enabled, false otherwise
+ *
+ * Example:
+ *
+ * { "enabled": true }
+ */
+static void do_info_hpet(Monitor *mon, QObject **ret_data)
+{
+ *ret_data = qobject_from_jsonf("{ 'enabled': %i }", !no_hpet);
}
#endif
-static void do_info_uuid(Monitor *mon)
+static void do_info_uuid_print(Monitor *mon, const QObject *data)
+{
+ monitor_printf(mon, "%s\n", qdict_get_str(qobject_to_qdict(data), "UUID"));
+}
+
+/**
+ * do_info_uuid(): Show VM UUID
+ *
+ * Return a QDict with the following information:
+ *
+ * - "UUID": Universally Unique Identifier
+ *
+ * Example:
+ *
+ * { "UUID": "550e8400-e29b-41d4-a716-446655440000" }
+ */
+static void do_info_uuid(Monitor *mon, QObject **ret_data)
{
- monitor_printf(mon, UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1],
+ char uuid[64];
+
+ snprintf(uuid, sizeof(uuid), UUID_FMT, qemu_uuid[0], qemu_uuid[1],
qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], qemu_uuid[5],
qemu_uuid[6], qemu_uuid[7], qemu_uuid[8], qemu_uuid[9],
qemu_uuid[10], qemu_uuid[11], qemu_uuid[12], qemu_uuid[13],
qemu_uuid[14], qemu_uuid[15]);
+ *ret_data = qobject_from_jsonf("{ 'UUID': %s }", uuid);
}
/* get the current CPU defined by the user */
{
CPUState *env;
env = mon_get_cpu();
- if (!env)
- return;
#ifdef TARGET_I386
cpu_dump_state(env, (FILE *)mon, monitor_fprintf,
X86_DUMP_FPU);
assert(qobject_type(obj) == QTYPE_QDICT);
cpu = qobject_to_qdict(obj);
- if (strcmp(qdict_get_str(cpu, "current"), "yes") == 0)
+ if (qdict_get_bool(cpu, "current")) {
active = '*';
+ }
monitor_printf(mon, "%c CPU #%d: ", active, (int)qdict_get_int(cpu, "CPU"));
(target_long) qdict_get_int(cpu, "PC"));
#endif
- if (strcmp(qdict_get_str(cpu, "halted"), "yes") == 0)
+ if (qdict_get_bool(cpu, "halted")) {
monitor_printf(mon, " (halted)");
+ }
monitor_printf(mon, "\n");
}
/**
* do_info_cpus(): Show CPU information
*
- * Return a QList with a QDict for each CPU.
+ * Return a QList. Each CPU is represented by a QDict, which contains:
+ *
+ * - "cpu": CPU index
+ * - "current": true if this is the current CPU, false otherwise
+ * - "halted": true if the cpu is halted, false otherwise
+ * - Current program counter. The key's name depends on the architecture:
+ * "pc": i386/x86)64
+ * "nip": PPC
+ * "pc" and "npc": sparc
+ * "PC": mips
*
- * For example:
+ * Example:
*
- * [ { "CPU": 0, "current": "yes", "pc": 0x..., "halted": "no" },
- * { "CPU": 1, "current": "no", "pc": 0x..., "halted": "yes" } ]
+ * [ { "CPU": 0, "current": true, "halted": false, "pc": 3227107138 },
+ * { "CPU": 1, "current": false, "halted": true, "pc": 7108165 } ]
*/
static void do_info_cpus(Monitor *mon, QObject **ret_data)
{
mon_get_cpu();
for(env = first_cpu; env != NULL; env = env->next_cpu) {
- const char *answer;
- QDict *cpu = qdict_new();
+ QDict *cpu;
+ QObject *obj;
cpu_synchronize_state(env);
- qdict_put(cpu, "CPU", qint_from_int(env->cpu_index));
- answer = (env == mon->mon_cpu) ? "yes" : "no";
- qdict_put(cpu, "current", qstring_from_str(answer));
+ obj = qobject_from_jsonf("{ 'CPU': %d, 'current': %i, 'halted': %i }",
+ env->cpu_index, env == mon->mon_cpu,
+ env->halted);
+
+ cpu = qobject_to_qdict(obj);
#if defined(TARGET_I386)
qdict_put(cpu, "pc", qint_from_int(env->eip + env->segs[R_CS].base));
#elif defined(TARGET_MIPS)
qdict_put(cpu, "PC", qint_from_int(env->active_tc.PC));
#endif
- answer = env->halted ? "yes" : "no";
- qdict_put(cpu, "halted", qstring_from_str(answer));
qlist_append(cpu_list, cpu);
}
*ret_data = QOBJECT(cpu_list);
}
-static void do_cpu_set(Monitor *mon, const QDict *qdict)
+static int do_cpu_set(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
int index = qdict_get_int(qdict, "index");
- if (mon_set_cpu(index) < 0)
- monitor_printf(mon, "Invalid CPU index\n");
+ if (mon_set_cpu(index) < 0) {
+ qemu_error_new(QERR_INVALID_PARAMETER, "index");
+ return -1;
+ }
+ return 0;
}
static void do_info_jit(Monitor *mon)
/**
* do_quit(): Quit QEMU execution
*/
-static void do_quit(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_quit(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
exit(0);
+ return 0;
}
static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
if (bdrv_is_inserted(bs)) {
if (!force) {
if (!bdrv_is_removable(bs)) {
- monitor_printf(mon, "device is not removable\n");
+ qemu_error_new(QERR_DEVICE_NOT_REMOVABLE,
+ bdrv_get_device_name(bs));
return -1;
}
if (bdrv_is_locked(bs)) {
- monitor_printf(mon, "device is locked\n");
+ qemu_error_new(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
return -1;
}
}
return 0;
}
-static void do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
BlockDriverState *bs;
int force = qdict_get_int(qdict, "force");
- const char *filename = qdict_get_str(qdict, "filename");
+ const char *filename = qdict_get_str(qdict, "device");
bs = bdrv_find(filename);
if (!bs) {
- monitor_printf(mon, "device not found\n");
- return;
+ qemu_error_new(QERR_DEVICE_NOT_FOUND, filename);
+ return -1;
}
- eject_device(mon, bs, force);
+ return eject_device(mon, bs, force);
}
-static void do_change_block(Monitor *mon, const char *device,
- const char *filename, const char *fmt)
+static int do_block_set_passwd(Monitor *mon, const QDict *qdict,
+ QObject **ret_data)
+{
+ BlockDriverState *bs;
+
+ bs = bdrv_find(qdict_get_str(qdict, "device"));
+ if (!bs) {
+ qemu_error_new(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device"));
+ return -1;
+ }
+
+ if (bdrv_set_key(bs, qdict_get_str(qdict, "password")) < 0) {
+ qemu_error_new(QERR_INVALID_PASSWORD);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int do_change_block(Monitor *mon, const char *device,
+ const char *filename, const char *fmt)
{
BlockDriverState *bs;
BlockDriver *drv = NULL;
bs = bdrv_find(device);
if (!bs) {
- monitor_printf(mon, "device not found\n");
- return;
+ qemu_error_new(QERR_DEVICE_NOT_FOUND, device);
+ return -1;
}
if (fmt) {
drv = bdrv_find_whitelisted_format(fmt);
if (!drv) {
- monitor_printf(mon, "invalid format %s\n", fmt);
- return;
+ qemu_error_new(QERR_INVALID_BLOCK_FORMAT, fmt);
+ return -1;
}
}
- if (eject_device(mon, bs, 0) < 0)
- return;
- bdrv_open2(bs, filename, 0, drv);
- monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
+ if (eject_device(mon, bs, 0) < 0) {
+ return -1;
+ }
+ if (bdrv_open2(bs, filename, BDRV_O_RDWR, drv) < 0) {
+ return -1;
+ }
+ return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
+}
+
+static int change_vnc_password(const char *password)
+{
+ if (vnc_display_password(NULL, password) < 0) {
+ qemu_error_new(QERR_SET_PASSWD_FAILED);
+ return -1;
+ }
+
+ return 0;
}
static void change_vnc_password_cb(Monitor *mon, const char *password,
void *opaque)
{
- if (vnc_display_password(NULL, password) < 0)
- monitor_printf(mon, "could not set VNC server password\n");
-
+ change_vnc_password(password);
monitor_read_command(mon, 1);
}
-static void do_change_vnc(Monitor *mon, const char *target, const char *arg)
+static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
{
if (strcmp(target, "passwd") == 0 ||
strcmp(target, "password") == 0) {
char password[9];
strncpy(password, arg, sizeof(password));
password[sizeof(password) - 1] = '\0';
- change_vnc_password_cb(mon, password, NULL);
+ return change_vnc_password(password);
} else {
- monitor_read_password(mon, change_vnc_password_cb, NULL);
+ return monitor_read_password(mon, change_vnc_password_cb, NULL);
}
} else {
- if (vnc_display_open(NULL, target) < 0)
- monitor_printf(mon, "could not start VNC server on %s\n", target);
+ if (vnc_display_open(NULL, target) < 0) {
+ qemu_error_new(QERR_VNC_SERVER_FAILED, target);
+ return -1;
+ }
}
+
+ return 0;
}
-static void do_change(Monitor *mon, const QDict *qdict)
+/**
+ * do_change(): Change a removable medium, or VNC configuration
+ */
+static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *device = qdict_get_str(qdict, "device");
const char *target = qdict_get_str(qdict, "target");
const char *arg = qdict_get_try_str(qdict, "arg");
+ int ret;
+
if (strcmp(device, "vnc") == 0) {
- do_change_vnc(mon, target, arg);
+ ret = do_change_vnc(mon, target, arg);
} else {
- do_change_block(mon, device, target, arg);
+ ret = do_change_block(mon, device, target, arg);
}
+
+ return ret;
}
static void do_screen_dump(Monitor *mon, const QDict *qdict)
/**
* do_stop(): Stop VM execution
*/
-static void do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
vm_stop(EXCP_INTERRUPT);
+ return 0;
}
static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs);
/**
* do_cont(): Resume emulation.
*/
-static void do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
struct bdrv_iterate_context context = { mon, 0 };
bdrv_iterate(encrypted_bdrv_it, &context);
/* only resume the vm if all keys are set and valid */
- if (!context.err)
+ if (!context.err) {
vm_start();
+ return 0;
+ } else {
+ return -1;
+ }
}
static void bdrv_key_cb(void *opaque, int err)
target_phys_addr_t addr, int is_physical)
{
CPUState *env;
- int nb_per_line, l, line_size, i, max_digits, len;
+ int l, line_size, i, max_digits, len;
uint8_t buf[16];
uint64_t v;
int flags;
flags = 0;
env = mon_get_cpu();
- if (!env && !is_physical)
+ if (!is_physical)
return;
#ifdef TARGET_I386
if (wsize == 2) {
line_size = 8;
else
line_size = 16;
- nb_per_line = line_size / wsize;
max_digits = 0;
switch(format) {
cpu_physical_memory_rw(addr, buf, l, 0);
} else {
env = mon_get_cpu();
- if (!env)
- break;
if (cpu_memory_rw_debug(env, addr, buf, l, 0) < 0) {
monitor_printf(mon, " Cannot access memory\n");
break;
monitor_printf(mon, "\n");
}
-static void do_memory_save(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_memory_save(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
FILE *f;
uint32_t size = qdict_get_int(qdict, "size");
uint32_t l;
CPUState *env;
uint8_t buf[1024];
+ int ret = -1;
env = mon_get_cpu();
- if (!env)
- return;
f = fopen(filename, "wb");
if (!f) {
- monitor_printf(mon, "could not open '%s'\n", filename);
- return;
+ qemu_error_new(QERR_OPEN_FILE_FAILED, filename);
+ return -1;
}
while (size != 0) {
l = sizeof(buf);
if (l > size)
l = size;
cpu_memory_rw_debug(env, addr, buf, l, 0);
- fwrite(buf, 1, l, f);
+ if (fwrite(buf, 1, l, f) != l) {
+ monitor_printf(mon, "fwrite() error in do_memory_save\n");
+ goto exit;
+ }
addr += l;
size -= l;
}
+
+ ret = 0;
+
+exit:
fclose(f);
+ return ret;
}
-static void do_physical_memory_save(Monitor *mon, const QDict *qdict,
+static int do_physical_memory_save(Monitor *mon, const QDict *qdict,
QObject **ret_data)
{
FILE *f;
uint32_t size = qdict_get_int(qdict, "size");
const char *filename = qdict_get_str(qdict, "filename");
target_phys_addr_t addr = qdict_get_int(qdict, "val");
+ int ret = -1;
f = fopen(filename, "wb");
if (!f) {
- monitor_printf(mon, "could not open '%s'\n", filename);
- return;
+ qemu_error_new(QERR_OPEN_FILE_FAILED, filename);
+ return -1;
}
while (size != 0) {
l = sizeof(buf);
if (l > size)
l = size;
cpu_physical_memory_rw(addr, buf, l, 0);
- fwrite(buf, 1, l, f);
+ if (fwrite(buf, 1, l, f) != l) {
+ monitor_printf(mon, "fwrite() error in do_physical_memory_save\n");
+ goto exit;
+ }
fflush(f);
addr += l;
size -= l;
}
+
+ ret = 0;
+
+exit:
fclose(f);
+ return ret;
}
static void do_sum(Monitor *mon, const QDict *qdict)
/**
* do_system_reset(): Issue a machine reset
*/
-static void do_system_reset(Monitor *mon, const QDict *qdict,
- QObject **ret_data)
+static int do_system_reset(Monitor *mon, const QDict *qdict,
+ QObject **ret_data)
{
qemu_system_reset_request();
+ return 0;
}
/**
* do_system_powerdown(): Issue a machine powerdown
*/
-static void do_system_powerdown(Monitor *mon, const QDict *qdict,
- QObject **ret_data)
+static int do_system_powerdown(Monitor *mon, const QDict *qdict,
+ QObject **ret_data)
{
qemu_system_powerdown_request();
+ return 0;
}
#if defined(TARGET_I386)
uint32_t pgd, pde, pte;
env = mon_get_cpu();
- if (!env)
- return;
if (!(env->cr[0] & CR0_PG_MASK)) {
monitor_printf(mon, "PG disabled\n");
uint32_t pgd, pde, pte, start, end;
env = mon_get_cpu();
- if (!env)
- return;
if (!(env->cr[0] & CR0_PG_MASK)) {
monitor_printf(mon, "PG disabled\n");
#endif
-static void do_info_kvm(Monitor *mon)
+static void do_info_kvm_print(Monitor *mon, const QObject *data)
{
-#ifdef CONFIG_KVM
+ QDict *qdict;
+
+ qdict = qobject_to_qdict(data);
+
monitor_printf(mon, "kvm support: ");
- if (kvm_enabled())
- monitor_printf(mon, "enabled\n");
- else
- monitor_printf(mon, "disabled\n");
+ if (qdict_get_bool(qdict, "present")) {
+ monitor_printf(mon, "%s\n", qdict_get_bool(qdict, "enabled") ?
+ "enabled" : "disabled");
+ } else {
+ monitor_printf(mon, "not compiled\n");
+ }
+}
+
+/**
+ * do_info_kvm(): Show KVM information
+ *
+ * Return a QDict with the following information:
+ *
+ * - "enabled": true if KVM support is enabled, false otherwise
+ * - "present": true if QEMU has KVM support, false otherwise
+ *
+ * Example:
+ *
+ * { "enabled": true, "present": true }
+ */
+static void do_info_kvm(Monitor *mon, QObject **ret_data)
+{
+#ifdef CONFIG_KVM
+ *ret_data = qobject_from_jsonf("{ 'enabled': %i, 'present': true }",
+ kvm_enabled());
#else
- monitor_printf(mon, "kvm support: not compiled\n");
+ *ret_data = qobject_from_jsonf("{ 'enabled': false, 'present': false }");
#endif
}
}
#endif
-static void do_info_status(Monitor *mon)
+static void do_info_status_print(Monitor *mon, const QObject *data)
{
- if (vm_running) {
- if (singlestep) {
- monitor_printf(mon, "VM status: running (single step mode)\n");
- } else {
- monitor_printf(mon, "VM status: running\n");
+ QDict *qdict;
+
+ qdict = qobject_to_qdict(data);
+
+ monitor_printf(mon, "VM status: ");
+ if (qdict_get_bool(qdict, "running")) {
+ monitor_printf(mon, "running");
+ if (qdict_get_bool(qdict, "singlestep")) {
+ monitor_printf(mon, " (single step mode)");
}
- } else
- monitor_printf(mon, "VM status: paused\n");
+ } else {
+ monitor_printf(mon, "paused");
+ }
+
+ monitor_printf(mon, "\n");
}
/**
- * do_balloon(): Request VM to change its memory allocation
+ * do_info_status(): VM status
+ *
+ * Return a QDict with the following information:
+ *
+ * - "running": true if the VM is running, or false if it is paused
+ * - "singlestep": true if the VM is in single step mode, false otherwise
+ *
+ * Example:
+ *
+ * { "running": true, "singlestep": false }
*/
-static void do_balloon(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static void do_info_status(Monitor *mon, QObject **ret_data)
{
- int value = qdict_get_int(qdict, "value");
- ram_addr_t target = value;
- qemu_balloon(target << 20);
+ *ret_data = qobject_from_jsonf("{ 'running': %i, 'singlestep': %i }",
+ vm_running, singlestep);
+}
+
+static void print_balloon_stat(const char *key, QObject *obj, void *opaque)
+{
+ Monitor *mon = opaque;
+
+ if (strcmp(key, "actual"))
+ monitor_printf(mon, ",%s=%" PRId64, key,
+ qint_get_int(qobject_to_qint(obj)));
}
static void monitor_print_balloon(Monitor *mon, const QObject *data)
{
- monitor_printf(mon, "balloon: actual=%d\n",
- (int)qint_get_int(qobject_to_qint(data)));
+ QDict *qdict;
+
+ qdict = qobject_to_qdict(data);
+ if (!qdict_haskey(qdict, "actual"))
+ return;
+
+ monitor_printf(mon, "balloon: actual=%" PRId64,
+ qdict_get_int(qdict, "actual") >> 20);
+ qdict_iter(qdict, print_balloon_stat, mon);
+ monitor_printf(mon, "\n");
}
/**
* do_info_balloon(): Balloon information
+ *
+ * Make an asynchronous request for balloon info. When the request completes
+ * a QDict will be returned according to the following specification:
+ *
+ * - "actual": current balloon value in bytes
+ * The following fields may or may not be present:
+ * - "mem_swapped_in": Amount of memory swapped in (bytes)
+ * - "mem_swapped_out": Amount of memory swapped out (bytes)
+ * - "major_page_faults": Number of major faults
+ * - "minor_page_faults": Number of minor faults
+ * - "free_mem": Total amount of free and unused memory (bytes)
+ * - "total_mem": Total amount of available memory (bytes)
+ *
+ * Example:
+ *
+ * { "actual": 1073741824, "mem_swapped_in": 0, "mem_swapped_out": 0,
+ * "major_page_faults": 142, "minor_page_faults": 239245,
+ * "free_mem": 1014185984, "total_mem": 1044668416 }
*/
-static void do_info_balloon(Monitor *mon, QObject **ret_data)
+static int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque)
{
- ram_addr_t actual;
+ int ret;
- actual = qemu_balloon_status();
- if (kvm_enabled() && !kvm_has_sync_mmu())
+ if (kvm_enabled() && !kvm_has_sync_mmu()) {
qemu_error_new(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
- else if (actual == 0)
+ return -1;
+ }
+
+ ret = qemu_balloon_status(cb, opaque);
+ if (!ret) {
qemu_error_new(QERR_DEVICE_NOT_ACTIVE, "balloon");
- else
- *ret_data = QOBJECT(qint_from_int((int)(actual >> 20)));
+ return -1;
+ }
+
+ cb(opaque, NULL);
+ return 0;
+}
+
+/**
+ * do_balloon(): Request VM to change its memory allocation
+ */
+static int do_balloon(Monitor *mon, const QDict *params,
+ MonitorCompletion cb, void *opaque)
+{
+ int ret;
+
+ if (kvm_enabled() && !kvm_has_sync_mmu()) {
+ qemu_error_new(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
+ return -1;
+ }
+
+ ret = qemu_balloon(qdict_get_int(params, "value"), cb, opaque);
+ if (ret == 0) {
+ qemu_error_new(QERR_DEVICE_NOT_ACTIVE, "balloon");
+ return -1;
+ }
+
+ return 0;
}
static qemu_acl *find_acl(Monitor *mon, const char *name)
}
#endif
-static void do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *fdname = qdict_get_str(qdict, "fdname");
mon_fd_t *monfd;
fd = qemu_chr_get_msgfd(mon->chr);
if (fd == -1) {
- monitor_printf(mon, "getfd: no file descriptor supplied via SCM_RIGHTS\n");
- return;
+ qemu_error_new(QERR_FD_NOT_SUPPLIED);
+ return -1;
}
if (qemu_isdigit(fdname[0])) {
- monitor_printf(mon, "getfd: monitor names may not begin with a number\n");
- return;
+ qemu_error_new(QERR_INVALID_PARAMETER, "fdname");
+ return -1;
}
fd = dup(fd);
if (fd == -1) {
- monitor_printf(mon, "Failed to dup() file descriptor: %s\n",
- strerror(errno));
- return;
+ if (errno == EMFILE)
+ qemu_error_new(QERR_TOO_MANY_FILES);
+ else
+ qemu_error_new(QERR_UNDEFINED_ERROR);
+ return -1;
}
QLIST_FOREACH(monfd, &mon->fds, next) {
close(monfd->fd);
monfd->fd = fd;
- return;
+ return 0;
}
monfd = qemu_mallocz(sizeof(mon_fd_t));
monfd->fd = fd;
QLIST_INSERT_HEAD(&mon->fds, monfd, next);
+ return 0;
}
-static void do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *fdname = qdict_get_str(qdict, "fdname");
mon_fd_t *monfd;
close(monfd->fd);
qemu_free(monfd->name);
qemu_free(monfd);
- return;
+ return 0;
}
- monitor_printf(mon, "Failed to find file descriptor named %s\n",
- fdname);
+ qemu_error_new(QERR_FD_NOT_FOUND, fdname);
+ return -1;
}
static void do_loadvm(Monitor *mon, const QDict *qdict)
.args_type = "",
.params = "",
.help = "show the version of QEMU",
- .user_print = monitor_print_qobject,
+ .user_print = do_info_version_print,
.mhandler.info_new = do_info_version,
},
{
.args_type = "",
.params = "",
.help = "show the character devices",
- .mhandler.info = qemu_chr_info,
+ .user_print = qemu_chr_info_print,
+ .mhandler.info_new = qemu_chr_info,
},
{
.name = "block",
.args_type = "",
.params = "",
.help = "show the block devices",
- .mhandler.info = bdrv_info,
+ .user_print = bdrv_info_print,
+ .mhandler.info_new = bdrv_info,
},
{
.name = "blockstats",
.args_type = "",
.params = "",
.help = "show block device statistics",
- .mhandler.info = bdrv_info_stats,
+ .user_print = bdrv_stats_print,
+ .mhandler.info_new = bdrv_info_stats,
},
{
.name = "registers",
.args_type = "",
.params = "",
.help = "show PCI info",
- .mhandler.info = pci_info,
+ .user_print = do_pci_info_print,
+ .mhandler.info_new = do_pci_info,
},
#if defined(TARGET_I386) || defined(TARGET_SH4)
{
.args_type = "",
.params = "",
.help = "show state of HPET",
- .mhandler.info = do_info_hpet,
+ .user_print = do_info_hpet_print,
+ .mhandler.info_new = do_info_hpet,
},
#endif
{
.args_type = "",
.params = "",
.help = "show KVM information",
- .mhandler.info = do_info_kvm,
+ .user_print = do_info_kvm_print,
+ .mhandler.info_new = do_info_kvm,
},
{
.name = "numa",
.args_type = "",
.params = "",
.help = "show the current VM status (running|paused)",
- .mhandler.info = do_info_status,
+ .user_print = do_info_status_print,
+ .mhandler.info_new = do_info_status,
},
{
.name = "pcmcia",
.args_type = "",
.params = "",
.help = "show which guest mouse is receiving events",
- .mhandler.info = do_info_mice,
+ .user_print = do_info_mice_print,
+ .mhandler.info_new = do_info_mice,
},
{
.name = "vnc",
.args_type = "",
.params = "",
.help = "show the vnc server status",
- .mhandler.info = do_info_vnc,
+ .user_print = do_info_vnc_print,
+ .mhandler.info_new = do_info_vnc,
},
{
.name = "name",
.args_type = "",
.params = "",
.help = "show the current VM name",
- .mhandler.info = do_info_name,
+ .user_print = do_info_name_print,
+ .mhandler.info_new = do_info_name,
},
{
.name = "uuid",
.args_type = "",
.params = "",
.help = "show the current VM UUID",
- .mhandler.info = do_info_uuid,
+ .user_print = do_info_uuid_print,
+ .mhandler.info_new = do_info_uuid,
},
#if defined(TARGET_PPC)
{
.args_type = "",
.params = "",
.help = "show migration status",
- .mhandler.info = do_info_migrate,
+ .user_print = do_info_migrate_print,
+ .mhandler.info_new = do_info_migrate,
},
{
.name = "balloon",
.params = "",
.help = "show balloon information",
.user_print = monitor_print_balloon,
- .mhandler.info_new = do_info_balloon,
+ .mhandler.info_async = do_info_balloon,
+ .async = 1,
},
{
.name = "qtree",
static target_long monitor_get_pc (const struct MonitorDef *md, int val)
{
CPUState *env = mon_get_cpu();
- if (!env)
- return 0;
return env->eip + env->segs[R_CS].base;
}
#endif
unsigned int u;
int i;
- if (!env)
- return 0;
-
u = 0;
for (i = 0; i < 8; i++)
u |= env->crf[i] << (32 - (4 * i));
static target_long monitor_get_msr (const struct MonitorDef *md, int val)
{
CPUState *env = mon_get_cpu();
- if (!env)
- return 0;
return env->msr;
}
static target_long monitor_get_xer (const struct MonitorDef *md, int val)
{
CPUState *env = mon_get_cpu();
- if (!env)
- return 0;
return env->xer;
}
static target_long monitor_get_decr (const struct MonitorDef *md, int val)
{
CPUState *env = mon_get_cpu();
- if (!env)
- return 0;
return cpu_ppc_load_decr(env);
}
static target_long monitor_get_tbu (const struct MonitorDef *md, int val)
{
CPUState *env = mon_get_cpu();
- if (!env)
- return 0;
return cpu_ppc_load_tbu(env);
}
static target_long monitor_get_tbl (const struct MonitorDef *md, int val)
{
CPUState *env = mon_get_cpu();
- if (!env)
- return 0;
return cpu_ppc_load_tbl(env);
}
#endif
static target_long monitor_get_psr (const struct MonitorDef *md, int val)
{
CPUState *env = mon_get_cpu();
- if (!env)
- return 0;
return GET_PSR(env);
}
#endif
static target_long monitor_get_reg(const struct MonitorDef *md, int val)
{
CPUState *env = mon_get_cpu();
- if (!env)
- return 0;
return env->regwptr[val];
}
#endif
longjmp(expr_env, 1);
}
-/* return 0 if OK, -1 if not found, -2 if no CPU defined */
+/* return 0 if OK, -1 if not found */
static int get_monitor_def(target_long *pval, const char *name)
{
const MonitorDef *md;
*pval = md->get_value(md, md->offset);
} else {
CPUState *env = mon_get_cpu();
- if (!env)
- return -2;
ptr = (uint8_t *)env + md->offset;
switch(md->type) {
case MD_I32:
pch++;
*q = 0;
ret = get_monitor_def(®, buf);
- if (ret == -1)
+ if (ret < 0)
expr_error(mon, "unknown register");
- else if (ret == -2)
- expr_error(mon, "no cpu defined");
n = reg;
}
break;
return 0;
}
+static int get_double(Monitor *mon, double *pval, const char **pp)
+{
+ const char *p = *pp;
+ char *tailp;
+ double d;
+
+ d = strtod(p, &tailp);
+ if (tailp == p) {
+ monitor_printf(mon, "Number expected\n");
+ return -1;
+ }
+ if (d != d || d - d != 0) {
+ /* NaN or infinity */
+ monitor_printf(mon, "Bad number\n");
+ return -1;
+ }
+ *pval = d;
+ *pp = tailp;
+ return 0;
+}
+
static int get_str(char *buf, int buf_size, const char **pp)
{
const char *p;
break;
case 'i':
case 'l':
+ case 'M':
{
int64_t val;
monitor_printf(mon, "\'%s\' has failed: ", cmdname);
monitor_printf(mon, "integer is for 32-bit values\n");
goto fail;
+ } else if (c == 'M') {
+ val <<= 20;
}
qdict_put(qdict, key, qint_from_int(val));
}
break;
+ case 'b':
+ case 'T':
+ {
+ double val;
+
+ while (qemu_isspace(*p))
+ p++;
+ if (*typestr == '?') {
+ typestr++;
+ if (*p == '\0') {
+ break;
+ }
+ }
+ if (get_double(mon, &val, &p) < 0) {
+ goto fail;
+ }
+ if (c == 'b' && *p) {
+ switch (*p) {
+ case 'K': case 'k':
+ val *= 1 << 10; p++; break;
+ case 'M': case 'm':
+ val *= 1 << 20; p++; break;
+ case 'G': case 'g':
+ val *= 1 << 30; p++; break;
+ }
+ }
+ if (c == 'T' && p[0] && p[1] == 's') {
+ switch (*p) {
+ case 'm':
+ val /= 1e3; p += 2; break;
+ case 'u':
+ val /= 1e6; p += 2; break;
+ case 'n':
+ val /= 1e9; p += 2; break;
+ }
+ }
+ if (*p && !qemu_isspace(*p)) {
+ monitor_printf(mon, "Unknown unit suffix\n");
+ goto fail;
+ }
+ qdict_put(qdict, key, qfloat_from_double(val));
+ }
+ break;
case '-':
{
const char *tmp = p;
mon->error = NULL;
}
+static int is_async_return(const QObject *data)
+{
+ if (data && qobject_type(data) == QTYPE_QDICT) {
+ return qdict_haskey(qobject_to_qdict(data), "__mon_async");
+ }
+
+ return 0;
+}
+
+static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret)
+{
+ if (ret && !monitor_has_error(mon)) {
+ /*
+ * If it returns failure, it must have passed on error.
+ *
+ * Action: Report an internal error to the client if in QMP.
+ */
+ if (monitor_ctrl_mode(mon)) {
+ qemu_error_new(QERR_UNDEFINED_ERROR);
+ }
+ MON_DEBUG("command '%s' returned failure but did not pass an error\n",
+ cmd->name);
+ }
+
+#ifdef CONFIG_DEBUG_MONITOR
+ if (!ret && monitor_has_error(mon)) {
+ /*
+ * If it returns success, it must not have passed an error.
+ *
+ * Action: Report the passed error to the client.
+ */
+ MON_DEBUG("command '%s' returned success but passed an error\n",
+ cmd->name);
+ }
+
+ if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) {
+ /*
+ * Handlers should not call Monitor print functions.
+ *
+ * Action: Ignore them in QMP.
+ *
+ * (XXX: we don't check any 'info' or 'query' command here
+ * because the user print function _is_ called by do_info(), hence
+ * we will trigger this check. This problem will go away when we
+ * make 'query' commands real and kill do_info())
+ */
+ MON_DEBUG("command '%s' called print functions %d time(s)\n",
+ cmd->name, mon_print_count_get(mon));
+ }
+#endif
+}
+
static void monitor_call_handler(Monitor *mon, const mon_cmd_t *cmd,
const QDict *params)
{
+ int ret;
QObject *data = NULL;
- cmd->mhandler.cmd_new(mon, params, &data);
+ mon_print_count_init(mon);
- if (monitor_ctrl_mode(mon)) {
+ ret = cmd->mhandler.cmd_new(mon, params, &data);
+ handler_audit(mon, cmd, ret);
+
+ if (is_async_return(data)) {
+ /*
+ * Asynchronous commands have no initial return data but they can
+ * generate errors. Data is returned via the async completion handler.
+ */
+ if (monitor_ctrl_mode(mon) && monitor_has_error(mon)) {
+ monitor_protocol_emitter(mon, NULL);
+ }
+ } else if (monitor_ctrl_mode(mon)) {
/* Monitor Protocol */
monitor_protocol_emitter(mon, data);
} else {
qemu_errors_to_mon(mon);
- if (monitor_handler_ported(cmd)) {
+ if (monitor_handler_is_async(cmd)) {
+ user_async_cmd_handler(mon, cmd, qdict);
+ } else if (monitor_handler_ported(cmd)) {
monitor_call_handler(mon, cmd, qdict);
} else {
cmd->mhandler.cmd(mon, qdict);
{
Monitor *mon = opaque;
- return (mon->suspend_cnt == 0) ? 128 : 0;
+ return (mon->suspend_cnt == 0) ? 1 : 0;
}
typedef struct CmdArgs {
}
case 'i':
case 'l':
+ case 'M':
if (qobject_type(value) != QTYPE_QINT) {
qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "int");
return -1;
}
break;
+ case 'b':
+ case 'T':
+ if (qobject_type(value) != QTYPE_QINT && qobject_type(value) != QTYPE_QFLOAT) {
+ qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "number");
+ return -1;
+ }
+ break;
case '-':
if (qobject_type(value) != QTYPE_QINT &&
qobject_type(value) != QTYPE_QBOOL) {
const char *p;
CmdArgs cmd_args;
- if (cmd->args_type == '\0') {
+ if (cmd->args_type == NULL) {
return (qdict_size(args) == 0 ? 0 : -1);
}
return err;
}
+static int invalid_qmp_mode(const Monitor *mon, const char *cmd_name)
+{
+ int is_cap = compare_cmd(cmd_name, "qmp_capabilities");
+ return (qmp_cmd_mode(mon) ? is_cap : !is_cap);
+}
+
static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
{
int err;
QObject *obj;
QDict *input, *args;
- const char *cmd_name;
const mon_cmd_t *cmd;
Monitor *mon = cur_mon;
+ const char *cmd_name, *info_item;
args = NULL;
qemu_errors_to_mon(mon);
}
cmd_name = qstring_get_str(qobject_to_qstring(obj));
- cmd = monitor_find_command(cmd_name);
- if (!cmd) {
+
+ if (invalid_qmp_mode(mon, cmd_name)) {
+ qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name);
+ goto err_input;
+ }
+
+ /*
+ * XXX: We need this special case until we get info handlers
+ * converted into 'query-' commands
+ */
+ if (compare_cmd(cmd_name, "info")) {
qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name);
goto err_input;
+ } else if (strstart(cmd_name, "query-", &info_item)) {
+ cmd = monitor_find_command("info");
+ qdict_put_obj(input, "arguments",
+ qobject_from_jsonf("{ 'item': %s }", info_item));
+ } else {
+ cmd = monitor_find_command(cmd_name);
+ if (!cmd || !monitor_handler_ported(cmd)) {
+ qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name);
+ goto err_input;
+ }
}
obj = qdict_get(input, "arguments");
goto err_out;
}
- monitor_call_handler(mon, cmd, args);
+ if (monitor_handler_is_async(cmd)) {
+ qmp_async_cmd_handler(mon, cmd, args);
+ } else {
+ monitor_call_handler(mon, cmd, args);
+ }
goto out;
err_input:
readline_show_prompt(mon->rs);
}
+static QObject *get_qmp_greeting(void)
+{
+ QObject *ver;
+
+ do_info_version(NULL, &ver);
+ return qobject_from_jsonf("{'QMP':{'version': %p,'capabilities': []}}",ver);
+}
+
/**
* monitor_control_event(): Print QMP gretting
*/
static void monitor_control_event(void *opaque, int event)
{
- if (event == CHR_EVENT_OPENED) {
- QObject *data;
- Monitor *mon = opaque;
+ QObject *data;
+ Monitor *mon = opaque;
+ switch (event) {
+ case CHR_EVENT_OPENED:
+ mon->mc->command_mode = 0;
json_message_parser_init(&mon->mc->parser, handle_qmp_command);
-
- data = qobject_from_jsonf("{ 'QMP': { 'capabilities': [] } }");
- assert(data != NULL);
-
+ data = get_qmp_greeting();
monitor_json_emitter(mon, data);
qobject_decref(data);
+ break;
+ case CHR_EVENT_CLOSED:
+ json_message_parser_destroy(&mon->mc->parser);
+ break;
}
}
* End:
*/
-const char *monitor_cmdline_parse(const char *cmdline, int *flags)
-{
- const char *dev;
-
- if (strstart(cmdline, "control,", &dev)) {
- if (strstart(dev, "vc", NULL)) {
- fprintf(stderr, "qemu: control mode is for low-level interaction ");
- fprintf(stderr, "cannot be used with device 'vc'\n");
- exit(1);
- }
- *flags &= ~MONITOR_USE_READLINE;
- *flags |= MONITOR_USE_CONTROL;
- return dev;
- }
-
- return cmdline;
-}
-
void monitor_init(CharDriverState *chr, int flags)
{
static int is_first_init = 1;
monitor_read_command(mon, 1);
}
-void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
- BlockDriverCompletionFunc *completion_cb,
- void *opaque)
+int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
+ BlockDriverCompletionFunc *completion_cb,
+ void *opaque)
{
int err;
if (!bdrv_key_required(bs)) {
if (completion_cb)
completion_cb(opaque, 0);
- return;
+ return 0;
+ }
+
+ if (monitor_ctrl_mode(mon)) {
+ qemu_error_new(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs));
+ return -1;
}
monitor_printf(mon, "%s (%s) is encrypted.\n", bdrv_get_device_name(bs),
if (err && completion_cb)
completion_cb(opaque, err);
+
+ return err;
}
typedef struct QemuErrorSink QemuErrorSink;
QDECREF(qerror);
break;
case ERR_SINK_MONITOR:
- assert(qemu_error_sink->mon->error == NULL);
- qemu_error_sink->mon->error = qerror;
+ /* report only the first error */
+ if (!qemu_error_sink->mon->error) {
+ qemu_error_sink->mon->error = qerror;
+ } else {
+ MON_DEBUG("Additional error report at %s:%d\n", qerror->file,
+ qerror->linenr);
+ QDECREF(qerror);
+ }
break;
}
}