#include "qint.h"
#include "qfloat.h"
#include "qlist.h"
-#include "qdict.h"
#include "qbool.h"
#include "qstring.h"
-#include "qerror.h"
#include "qjson.h"
#include "json-streamer.h"
#include "json-parser.h"
* 'F' filename
* 'B' block device name
* 's' string (accept optional quote)
+ * 'O' option string of the form NAME=VALUE,...
+ * parsed according to QemuOptsList given by its name
+ * Example: 'device:O' uses qemu_device_opts.
+ * Restriction: only lists with empty desc are supported
+ * TODO lift the restriction
* '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
+ * 'f' 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
*
* '?' optional type (for all types, except '/')
* '.' other form of optional type (for 'i' and 'l')
+ * 'b' boolean
+ * user mode accepts "on" or "off"
* '-' optional parameter (eg. '-f')
*
*/
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[];
static const mon_cmd_t info_cmds[];
-Monitor *cur_mon = NULL;
+Monitor *cur_mon;
+Monitor *default_mon;
static void monitor_command_cb(Monitor *mon, const char *cmdline,
void *opaque);
return (mon->flags & MONITOR_USE_CONTROL);
}
+/* Return non-zero iff we have a current monitor, and it is in QMP mode. */
+int monitor_cur_is_qmp(void)
+{
+ return cur_mon && monitor_ctrl_mode(cur_mon);
+}
+
static void monitor_read_command(Monitor *mon, int show_prompt)
{
if (!mon->rs)
void *opaque)
{
if (monitor_ctrl_mode(mon)) {
- qemu_error_new(QERR_MISSING_PARAMETER, "password");
+ qerror_report(QERR_MISSING_PARAMETER, "password");
return -EINVAL;
} else if (mon->rs) {
readline_start(mon->rs, "Password: ", 1, readline_func, opaque);
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);
}
obj = qobject_from_jsonf("{ 'seconds': %" PRId64 ", "
"'microseconds': %" PRId64 " }",
(int64_t) tv.tv_sec, (int64_t) tv.tv_usec);
- assert(obj != NULL);
-
qdict_put_obj(qdict, "timestamp", obj);
}
assert(event < QEVENT_MAX);
switch (event) {
- case QEVENT_DEBUG:
- event_name = "DEBUG";
- break;
case QEVENT_SHUTDOWN:
event_name = "SHUTDOWN";
break;
case QEVENT_BLOCK_IO_ERROR:
event_name = "BLOCK_IO_ERROR";
break;
+ case QEVENT_RTC_CHANGE:
+ event_name = "RTC_CHANGE";
+ break;
+ case QEVENT_WATCHDOG:
+ event_name = "WATCHDOG";
+ break;
default:
abort();
break;
QDECREF(qmp);
}
-static void do_qmp_capabilities(Monitor *mon, const QDict *params,
- QObject **ret_data)
+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)
}
}
-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;
+ qerror_report(QERR_COMMAND_NOT_FOUND, item);
+ return -1;
}
goto help;
}
} else {
if (monitor_ctrl_mode(mon)) {
/* handler not converted yet */
- qemu_error_new(QERR_COMMAND_NOT_FOUND, item);
+ qerror_report(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)
obj = qobject_from_jsonf("{ 'CPU': %d, 'current': %i, 'halted': %i }",
env->cpu_index, env == mon->mon_cpu,
env->halted);
- assert(obj != NULL);
cpu = qobject_to_qdict(obj);
*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)
- qemu_error_new(QERR_INVALID_PARAMETER, "index");
+ if (mon_set_cpu(index) < 0) {
+ qerror_report(QERR_INVALID_PARAMETER_VALUE, "index",
+ "a CPU number");
+ 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)) {
- qemu_error_new(QERR_DEVICE_NOT_REMOVABLE,
+ qerror_report(QERR_DEVICE_NOT_REMOVABLE,
bdrv_get_device_name(bs));
return -1;
}
if (bdrv_is_locked(bs)) {
- qemu_error_new(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
+ qerror_report(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");
bs = bdrv_find(filename);
if (!bs) {
- qemu_error_new(QERR_DEVICE_NOT_FOUND, filename);
- return;
+ qerror_report(QERR_DEVICE_NOT_FOUND, filename);
+ 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;
+ int err;
bs = bdrv_find(qdict_get_str(qdict, "device"));
if (!bs) {
- qemu_error_new(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device"));
- return;
+ qerror_report(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);
+ err = bdrv_set_key(bs, qdict_get_str(qdict, "password"));
+ if (err == -EINVAL) {
+ qerror_report(QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
+ return -1;
+ } else if (err < 0) {
+ qerror_report(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;
+ qerror_report(QERR_DEVICE_NOT_FOUND, device);
+ return -1;
}
if (fmt) {
drv = bdrv_find_whitelisted_format(fmt);
if (!drv) {
- qemu_error_new(QERR_INVALID_BLOCK_FORMAT, fmt);
- return;
+ qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt);
+ 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) {
+ qerror_report(QERR_OPEN_FILE_FAILED, filename);
+ 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)
- qemu_error_new(QERR_SET_PASSWD_FAILED);
+ if (vnc_display_password(NULL, password) < 0) {
+ qerror_report(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)
- qemu_error_new(QERR_VNC_SERVER_FAILED, target);
+ if (vnc_display_open(NULL, target) < 0) {
+ qerror_report(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)
+static int do_screen_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
vga_hw_screen_dump(qdict_get_str(qdict, "filename"));
+ return 0;
}
static void do_logfile(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)
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;
+ qerror_report(QERR_OPEN_FILE_FAILED, filename);
+ 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;
+ qerror_report(QERR_OPEN_FILE_FAILED, filename);
+ 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)
/**
* 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)
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)
-{
- 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 int do_info_balloon(Monitor *mon, 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_status(cb, opaque);
- if (!ret) {
- qemu_error_new(QERR_DEVICE_NOT_ACTIVE, "balloon");
- return -1;
- }
-
- 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)
{
qemu_acl *acl = qemu_acl_find(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) {
- qemu_error_new(QERR_FD_NOT_SUPPLIED);
- return;
+ qerror_report(QERR_FD_NOT_SUPPLIED);
+ return -1;
}
if (qemu_isdigit(fdname[0])) {
- qemu_error_new(QERR_INVALID_PARAMETER, "fdname");
- return;
+ qerror_report(QERR_INVALID_PARAMETER_VALUE, "fdname",
+ "a name not starting with a digit");
+ return -1;
}
fd = dup(fd);
if (fd == -1) {
if (errno == EMFILE)
- qemu_error_new(QERR_TOO_MANY_FILES);
+ qerror_report(QERR_TOO_MANY_FILES);
else
- qemu_error_new(QERR_UNDEFINED_ERROR);
- return;
+ qerror_report(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;
}
- qemu_error_new(QERR_FD_NOT_FOUND, fdname);
+ qerror_report(QERR_FD_NOT_FOUND, fdname);
+ return -1;
}
static void do_loadvm(Monitor *mon, const QDict *qdict)
vm_stop(0);
- if (load_vmstate(mon, name) >= 0 && saved_vm_running)
+ if (load_vmstate(name) >= 0 && saved_vm_running)
vm_start();
}
qdict_put(qdict, key, qstring_from_str(buf));
}
break;
+ case 'O':
+ {
+ QemuOptsList *opts_list;
+ QemuOpts *opts;
+
+ opts_list = qemu_find_opts(key);
+ if (!opts_list || opts_list->desc->name) {
+ goto bad_type;
+ }
+ while (qemu_isspace(*p)) {
+ p++;
+ }
+ if (!*p)
+ break;
+ if (get_str(buf, sizeof(buf), &p) < 0) {
+ goto fail;
+ }
+ opts = qemu_opts_parse(opts_list, buf, 1);
+ if (!opts) {
+ goto fail;
+ }
+ qemu_opts_to_qdict(opts, qdict);
+ qemu_opts_del(opts);
+ }
+ break;
case '/':
{
int count, format, size;
qdict_put(qdict, key, qint_from_int(val));
}
break;
- case 'b':
+ case 'f':
case 'T':
{
double val;
if (get_double(mon, &val, &p) < 0) {
goto fail;
}
- if (c == 'b' && *p) {
+ if (c == 'f' && *p) {
switch (*p) {
case 'K': case 'k':
val *= 1 << 10; p++; break;
qdict_put(qdict, key, qfloat_from_double(val));
}
break;
+ case 'b':
+ {
+ const char *beg;
+ int val;
+
+ while (qemu_isspace(*p)) {
+ p++;
+ }
+ beg = p;
+ while (qemu_isgraph(*p)) {
+ p++;
+ }
+ if (p - beg == 2 && !memcmp(beg, "on", p - beg)) {
+ val = 1;
+ } else if (p - beg == 3 && !memcmp(beg, "off", p - beg)) {
+ val = 0;
+ } else {
+ monitor_printf(mon, "Expected 'on' or 'off'\n");
+ goto fail;
+ }
+ qdict_put(qdict, key, qbool_from_int(val));
+ }
+ break;
case '-':
{
const char *tmp = p;
return NULL;
}
-static void monitor_print_error(Monitor *mon)
+void monitor_set_error(Monitor *mon, QError *qerror)
{
- qerror_print(mon->error);
- QDECREF(mon->error);
- mon->error = NULL;
+ /* report only the first error */
+ if (!mon->error) {
+ mon->error = qerror;
+ } else {
+ MON_DEBUG("Additional error report at %s:%d\n",
+ qerror->file, qerror->linenr);
+ QDECREF(qerror);
+ }
}
static int is_async_return(const QObject *data)
return 0;
}
+static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret)
+{
+ if (monitor_ctrl_mode(mon)) {
+ 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.
+ */
+ qerror_report(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
+ } else {
+ assert(!monitor_has_error(mon));
+ QDECREF(mon->error);
+ mon->error = NULL;
+ }
+}
+
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);
+
+ ret = cmd->mhandler.cmd_new(mon, params, &data);
+ handler_audit(mon, cmd, ret);
if (is_async_return(data)) {
/*
if (!cmd)
goto out;
- qemu_errors_to_mon(mon);
-
if (monitor_handler_is_async(cmd)) {
user_async_cmd_handler(mon, cmd, qdict);
} else if (monitor_handler_ported(cmd)) {
cmd->mhandler.cmd(mon, qdict);
}
- if (monitor_has_error(mon))
- monitor_print_error(mon);
-
- qemu_errors_to_previous();
-
out:
QDECREF(qdict);
}
static int check_opt(const CmdArgs *cmd_args, const char *name, QDict *args)
{
if (!cmd_args->optional) {
- qemu_error_new(QERR_MISSING_PARAMETER, name);
+ qerror_report(QERR_MISSING_PARAMETER, name);
return -1;
}
case 'B':
case 's':
if (qobject_type(value) != QTYPE_QSTRING) {
- qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "string");
+ qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "string");
return -1;
}
break;
for (i = 0; keys[i]; i++) {
QObject *obj = qdict_get(args, keys[i]);
if (!obj) {
- qemu_error_new(QERR_MISSING_PARAMETER, name);
+ qerror_report(QERR_MISSING_PARAMETER, name);
return -1;
}
if (qobject_type(obj) != QTYPE_QINT) {
- qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "int");
+ qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "int");
return -1;
}
}
case 'l':
case 'M':
if (qobject_type(value) != QTYPE_QINT) {
- qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "int");
+ qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "int");
return -1;
}
break;
- case 'b':
+ case 'f':
case 'T':
if (qobject_type(value) != QTYPE_QINT && qobject_type(value) != QTYPE_QFLOAT) {
- qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "number");
+ qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "number");
+ return -1;
+ }
+ break;
+ case 'b':
+ if (qobject_type(value) != QTYPE_QBOOL) {
+ qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "bool");
return -1;
}
break;
case '-':
if (qobject_type(value) != QTYPE_QINT &&
qobject_type(value) != QTYPE_QBOOL) {
- qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "bool");
+ qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "bool");
return -1;
}
if (qobject_type(value) == QTYPE_QBOOL) {
qint_from_int(qbool_get_int(qobject_to_qbool(value))));
}
break;
+ case 'O':
default:
/* impossible */
abort();
cmd_args->type = cmd_args->flag = cmd_args->optional = 0;
}
+static int check_opts(QemuOptsList *opts_list, QDict *args)
+{
+ assert(!opts_list->desc->name);
+ return 0;
+}
+
/*
* This is not trivial, we have to parse Monitor command's argument
* type syntax to be able to check the arguments provided by clients.
int err;
const char *p;
CmdArgs cmd_args;
+ QemuOptsList *opts_list;
if (cmd->args_type == NULL) {
return (qdict_size(args) == 0 ? 0 : -1);
err = 0;
cmd_args_init(&cmd_args);
+ opts_list = NULL;
for (p = cmd->args_type;; p++) {
if (*p == ':') {
if (cmd_args.type == '-') {
cmd_args.flag = *p++;
cmd_args.optional = 1;
+ } else if (cmd_args.type == 'O') {
+ opts_list = qemu_find_opts(qstring_get_str(cmd_args.name));
+ assert(opts_list);
} else if (*p == '?') {
cmd_args.optional = 1;
p++;
}
assert(*p == ',' || *p == '\0');
- err = check_arg(&cmd_args, args);
-
- QDECREF(cmd_args.name);
- cmd_args_init(&cmd_args);
+ if (opts_list) {
+ err = check_opts(opts_list, args);
+ opts_list = NULL;
+ } else {
+ err = check_arg(&cmd_args, args);
+ QDECREF(cmd_args.name);
+ cmd_args_init(&cmd_args);
+ }
if (err < 0) {
break;
const char *cmd_name, *info_item;
args = NULL;
- qemu_errors_to_mon(mon);
obj = json_parser_parse(tokens, NULL);
if (!obj) {
// FIXME: should be triggered in json_parser_parse()
- qemu_error_new(QERR_JSON_PARSING);
+ qerror_report(QERR_JSON_PARSING);
goto err_out;
} else if (qobject_type(obj) != QTYPE_QDICT) {
- qemu_error_new(QERR_QMP_BAD_INPUT_OBJECT, "object");
+ qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "object");
qobject_decref(obj);
goto err_out;
}
obj = qdict_get(input, "execute");
if (!obj) {
- qemu_error_new(QERR_QMP_BAD_INPUT_OBJECT, "execute");
+ qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "execute");
goto err_input;
} else if (qobject_type(obj) != QTYPE_QSTRING) {
- qemu_error_new(QERR_QMP_BAD_INPUT_OBJECT, "string");
+ qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "string");
goto err_input;
}
cmd_name = qstring_get_str(qobject_to_qstring(obj));
if (invalid_qmp_mode(mon, cmd_name)) {
- qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name);
+ qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
goto err_input;
}
* converted into 'query-' commands
*/
if (compare_cmd(cmd_name, "info")) {
- qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name);
+ qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
goto err_input;
} else if (strstart(cmd_name, "query-", &info_item)) {
cmd = monitor_find_command("info");
} else {
cmd = monitor_find_command(cmd_name);
if (!cmd || !monitor_handler_ported(cmd)) {
- qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name);
+ qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
goto err_input;
}
}
monitor_protocol_emitter(mon, NULL);
out:
QDECREF(args);
- qemu_errors_to_previous();
}
/**
*/
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 = get_qmp_greeting();
- assert(data != NULL);
-
monitor_json_emitter(mon, data);
qobject_decref(data);
+ break;
+ case CHR_EVENT_CLOSED:
+ json_message_parser_destroy(&mon->mc->parser);
+ break;
}
}
}
QLIST_INSERT_HEAD(&mon_list, mon, entry);
- if (!cur_mon || (flags & MONITOR_IS_DEFAULT))
- cur_mon = mon;
+ if (!default_mon || (flags & MONITOR_IS_DEFAULT))
+ default_mon = mon;
}
static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
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;
+ qerror_report(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);
-}
-
-typedef struct QemuErrorSink QemuErrorSink;
-struct QemuErrorSink {
- enum {
- ERR_SINK_FILE,
- ERR_SINK_MONITOR,
- } dest;
- union {
- FILE *fp;
- Monitor *mon;
- };
- QemuErrorSink *previous;
-};
-
-static QemuErrorSink *qemu_error_sink;
-
-void qemu_errors_to_file(FILE *fp)
-{
- QemuErrorSink *sink;
-
- sink = qemu_mallocz(sizeof(*sink));
- sink->dest = ERR_SINK_FILE;
- sink->fp = fp;
- sink->previous = qemu_error_sink;
- qemu_error_sink = sink;
-}
-
-void qemu_errors_to_mon(Monitor *mon)
-{
- QemuErrorSink *sink;
-
- sink = qemu_mallocz(sizeof(*sink));
- sink->dest = ERR_SINK_MONITOR;
- sink->mon = mon;
- sink->previous = qemu_error_sink;
- qemu_error_sink = sink;
-}
-
-void qemu_errors_to_previous(void)
-{
- QemuErrorSink *sink;
-
- assert(qemu_error_sink != NULL);
- sink = qemu_error_sink;
- qemu_error_sink = sink->previous;
- qemu_free(sink);
-}
-void qemu_error(const char *fmt, ...)
-{
- va_list args;
-
- assert(qemu_error_sink != NULL);
- switch (qemu_error_sink->dest) {
- case ERR_SINK_FILE:
- va_start(args, fmt);
- vfprintf(qemu_error_sink->fp, fmt, args);
- va_end(args);
- break;
- case ERR_SINK_MONITOR:
- va_start(args, fmt);
- monitor_vprintf(qemu_error_sink->mon, fmt, args);
- va_end(args);
- break;
- }
-}
-
-void qemu_error_internal(const char *file, int linenr, const char *func,
- const char *fmt, ...)
-{
- va_list va;
- QError *qerror;
-
- assert(qemu_error_sink != NULL);
-
- va_start(va, fmt);
- qerror = qerror_from_info(file, linenr, func, fmt, &va);
- va_end(va);
-
- switch (qemu_error_sink->dest) {
- case ERR_SINK_FILE:
- qerror_print(qerror);
- QDECREF(qerror);
- break;
- case ERR_SINK_MONITOR:
- assert(qemu_error_sink->mon->error == NULL);
- qemu_error_sink->mon->error = qerror;
- break;
- }
+ return err;
}