const char *params;
const char *help;
void (*user_print)(Monitor *mon, const QObject *data);
- int (*cmd_new_ret)(Monitor *mon, const QDict *params, QObject **ret_data);
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;
typedef struct MonitorControl {
QObject *id;
- int print_enabled;
JSONMessageParser parser;
int command_mode;
} MonitorControl;
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[];
void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
{
+ char buf[4096];
+
if (!mon)
return;
- if (mon->mc && !mon->mc->print_enabled) {
- qemu_error_new(QERR_UNDEFINED_ERROR);
- } else {
- char buf[4096];
- vsnprintf(buf, sizeof(buf), fmt, ap);
- monitor_puts(mon, buf);
+ mon_print_count_inc(mon);
+
+ if (monitor_ctrl_mode(mon)) {
+ return;
}
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ monitor_puts(mon, buf);
}
void monitor_printf(Monitor *mon, const char *fmt, ...)
json = qobject_to_json(data);
assert(json != NULL);
- mon->mc->print_enabled = 1;
- monitor_printf(mon, "%s\n", qstring_get_str(json));
- mon->mc->print_enabled = 0;
+ qstring_append_chr(json, '\n');
+ monitor_puts(mon, qstring_get_str(json));
QDECREF(json);
}
}
}
-static void do_info(Monitor *mon, const QDict *qdict, QObject **ret_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_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)
*ret_data = QOBJECT(cpu_list);
}
-static void do_cpu_set(Monitor *mon, const QDict *qdict, QObject **ret_data)
+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)
+ if (mon_set_cpu(index) < 0) {
qemu_error_new(QERR_INVALID_PARAMETER, "index");
+ return -1;
+ }
+ return 0;
}
static void do_info_jit(Monitor *mon)
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");
bs = bdrv_find(filename);
if (!bs) {
qemu_error_new(QERR_DEVICE_NOT_FOUND, filename);
- return;
+ return -1;
}
- eject_device(mon, bs, force);
+ return eject_device(mon, bs, force);
}
-static void do_block_set_passwd(Monitor *mon, const QDict *qdict,
+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;
+ return -1;
}
if (bdrv_set_key(bs, qdict_get_str(qdict, "password")) < 0) {
qemu_error_new(QERR_INVALID_PASSWORD);
+ return -1;
}
+
+ return 0;
}
-static void do_change_block(Monitor *mon, const char *device,
- const char *filename, const char *fmt)
+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) {
qemu_error_new(QERR_DEVICE_NOT_FOUND, device);
- return;
+ return -1;
}
if (fmt) {
drv = bdrv_find_whitelisted_format(fmt);
if (!drv) {
qemu_error_new(QERR_INVALID_BLOCK_FORMAT, fmt);
- return;
+ return -1;
}
}
- if (eject_device(mon, bs, 0) < 0)
- return;
- bdrv_open2(bs, filename, BDRV_O_RDWR, 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 void change_vnc_password(const char *password)
+static int change_vnc_password(const char *password)
{
- if (vnc_display_password(NULL, password) < 0)
+ 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,
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(password);
+ 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)
+ if (vnc_display_open(NULL, target) < 0) {
qemu_error_new(QERR_VNC_SERVER_FAILED, target);
+ return -1;
+ }
}
+
+ return 0;
}
/**
* do_change(): Change a removable medium, or VNC configuration
*/
-static void do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
+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_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)
int flags;
flags = 0;
env = mon_get_cpu();
- if (!is_physical)
- return;
#ifdef TARGET_I386
if (wsize == 2) {
flags = 1;
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();
f = fopen(filename, "wb");
if (!f) {
qemu_error_new(QERR_OPEN_FILE_FAILED, filename);
- return;
+ return -1;
}
while (size != 0) {
l = sizeof(buf);
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) {
qemu_error_new(QERR_OPEN_FILE_FAILED, filename);
- return;
+ return -1;
}
while (size != 0) {
l = sizeof(buf);
addr += l;
size -= l;
}
+
+ ret = 0;
+
exit:
fclose(f);
+ return ret;
}
static void do_sum(Monitor *mon, const QDict *qdict)
return -1;
}
+ cb(opaque, NULL);
return 0;
}
}
#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) {
qemu_error_new(QERR_FD_NOT_SUPPLIED);
- return;
+ return -1;
}
if (qemu_isdigit(fdname[0])) {
qemu_error_new(QERR_INVALID_PARAMETER, "fdname");
- return;
+ return -1;
}
fd = dup(fd);
qemu_error_new(QERR_TOO_MANY_FILES);
else
qemu_error_new(QERR_UNDEFINED_ERROR);
- return;
+ 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;
}
qemu_error_new(QERR_FD_NOT_FOUND, fdname);
+ return -1;
}
static void do_loadvm(Monitor *mon, const QDict *qdict)
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;
- if (cmd->cmd_new_ret) {
- cmd->cmd_new_ret(mon, params, &data);
- } else {
- cmd->mhandler.cmd_new(mon, params, &data);
- }
+ mon_print_count_init(mon);
+
+ ret = cmd->mhandler.cmd_new(mon, params, &data);
+ handler_audit(mon, cmd, ret);
if (is_async_return(data)) {
/*
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;
+ 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;
if (!qemu_error_sink->mon->error) {
qemu_error_sink->mon->error = qerror;
} else {
- /* XXX: warn the programmer */
+ MON_DEBUG("Additional error report at %s:%d\n", qerror->file,
+ qerror->linenr);
QDECREF(qerror);
}
break;