2004-03-14 21:38:27 +00:00
|
|
|
/*
|
|
|
|
* QEMU monitor
|
2007-09-16 21:08:06 +00:00
|
|
|
*
|
2004-03-14 21:38:27 +00:00
|
|
|
* Copyright (c) 2003-2004 Fabrice Bellard
|
2007-09-16 21:08:06 +00:00
|
|
|
*
|
2004-03-14 21:38:27 +00:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
2018-02-01 11:18:31 +00:00
|
|
|
|
2016-01-29 17:50:05 +00:00
|
|
|
#include "qemu/osdep.h"
|
2019-06-13 15:33:59 +00:00
|
|
|
#include "monitor-internal.h"
|
2016-03-15 15:58:45 +00:00
|
|
|
#include "cpu.h"
|
2013-02-04 10:37:52 +00:00
|
|
|
#include "monitor/qdev.h"
|
2007-11-17 17:14:51 +00:00
|
|
|
#include "hw/usb.h"
|
2012-12-12 12:24:50 +00:00
|
|
|
#include "hw/pci/pci.h"
|
2013-02-05 16:06:20 +00:00
|
|
|
#include "sysemu/watchdog.h"
|
2009-10-01 14:42:33 +00:00
|
|
|
#include "hw/loader.h"
|
2012-12-17 17:19:49 +00:00
|
|
|
#include "exec/gdbstub.h"
|
2012-10-24 06:43:34 +00:00
|
|
|
#include "net/net.h"
|
2009-11-25 18:48:54 +00:00
|
|
|
#include "net/slirp.h"
|
2018-03-26 06:38:56 +00:00
|
|
|
#include "chardev/char-mux.h"
|
2010-10-07 10:22:54 +00:00
|
|
|
#include "ui/qemu-spice.h"
|
2016-12-12 17:22:24 +00:00
|
|
|
#include "qemu/config-file.h"
|
2019-05-23 14:35:06 +00:00
|
|
|
#include "qemu/ctype.h"
|
2012-11-28 11:06:30 +00:00
|
|
|
#include "ui/console.h"
|
2013-12-04 14:02:28 +00:00
|
|
|
#include "ui/input.h"
|
2007-11-17 17:14:51 +00:00
|
|
|
#include "audio/audio.h"
|
2012-10-24 09:12:21 +00:00
|
|
|
#include "disas/disas.h"
|
2012-12-17 17:20:04 +00:00
|
|
|
#include "sysemu/balloon.h"
|
2012-12-17 17:20:00 +00:00
|
|
|
#include "qemu/timer.h"
|
2017-01-10 10:59:55 +00:00
|
|
|
#include "sysemu/hw_accel.h"
|
2019-08-12 05:23:59 +00:00
|
|
|
#include "sysemu/runstate.h"
|
2016-02-18 18:40:24 +00:00
|
|
|
#include "authz/list.h"
|
|
|
|
#include "qapi/util.h"
|
2019-06-19 20:10:44 +00:00
|
|
|
#include "sysemu/blockdev.h"
|
|
|
|
#include "sysemu/sysemu.h"
|
2019-05-23 14:35:05 +00:00
|
|
|
#include "sysemu/tcg.h"
|
2013-04-02 16:28:41 +00:00
|
|
|
#include "sysemu/tpm.h"
|
2018-02-01 11:18:39 +00:00
|
|
|
#include "qapi/qmp/qdict.h"
|
2015-03-17 16:22:46 +00:00
|
|
|
#include "qapi/qmp/qerror.h"
|
2018-02-01 11:18:40 +00:00
|
|
|
#include "qapi/qmp/qstring.h"
|
2016-06-22 17:11:19 +00:00
|
|
|
#include "qom/object_interfaces.h"
|
2011-08-31 18:31:24 +00:00
|
|
|
#include "trace/control.h"
|
2015-09-10 15:38:59 +00:00
|
|
|
#include "monitor/hmp-target.h"
|
2019-06-19 20:10:36 +00:00
|
|
|
#include "monitor/hmp.h"
|
2011-08-31 18:30:43 +00:00
|
|
|
#ifdef CONFIG_TRACE_SIMPLE
|
2011-08-31 18:31:24 +00:00
|
|
|
#include "trace/simple.h"
|
2010-06-24 11:34:53 +00:00
|
|
|
#endif
|
2012-12-17 17:19:49 +00:00
|
|
|
#include "exec/memory.h"
|
2016-03-15 12:18:37 +00:00
|
|
|
#include "exec/exec-all.h"
|
2018-02-01 11:18:46 +00:00
|
|
|
#include "qemu/option.h"
|
2012-12-17 17:20:00 +00:00
|
|
|
#include "qemu/thread.h"
|
2014-05-27 22:39:37 +00:00
|
|
|
#include "block/qapi.h"
|
2019-11-20 18:25:48 +00:00
|
|
|
#include "qapi/qapi-commands-char.h"
|
|
|
|
#include "qapi/qapi-commands-migration.h"
|
|
|
|
#include "qapi/qapi-commands-misc.h"
|
|
|
|
#include "qapi/qapi-commands-qom.h"
|
|
|
|
#include "qapi/qapi-commands-trace.h"
|
2019-02-14 15:22:38 +00:00
|
|
|
#include "qapi/qapi-emit-events.h"
|
2019-11-20 18:25:48 +00:00
|
|
|
#include "qapi/qapi-init-commands.h"
|
2018-02-01 11:18:31 +00:00
|
|
|
#include "qapi/error.h"
|
2014-06-18 06:43:31 +00:00
|
|
|
#include "qapi/qmp-event.h"
|
2018-02-11 09:36:05 +00:00
|
|
|
#include "qapi/qapi-introspect.h"
|
2017-03-03 11:01:16 +00:00
|
|
|
#include "sysemu/cpus.h"
|
2016-03-20 17:16:19 +00:00
|
|
|
#include "qemu/cutils.h"
|
2018-10-10 14:48:53 +00:00
|
|
|
#include "tcg/tcg.h"
|
2007-12-03 17:05:38 +00:00
|
|
|
|
2015-06-26 18:07:21 +00:00
|
|
|
#if defined(TARGET_S390X)
|
|
|
|
#include "hw/s390x/storage-keys.h"
|
2016-08-15 16:44:04 +00:00
|
|
|
#include "hw/s390x/storage-attributes.h"
|
2015-06-26 18:07:21 +00:00
|
|
|
#endif
|
|
|
|
|
2009-07-22 08:11:40 +00:00
|
|
|
/* file descriptors passed via SCM_RIGHTS */
|
2009-10-01 21:12:16 +00:00
|
|
|
typedef struct mon_fd_t mon_fd_t;
|
|
|
|
struct mon_fd_t {
|
2009-07-22 08:11:40 +00:00
|
|
|
char *name;
|
|
|
|
int fd;
|
2009-10-01 21:12:16 +00:00
|
|
|
QLIST_ENTRY(mon_fd_t) next;
|
2009-07-22 08:11:40 +00:00
|
|
|
};
|
|
|
|
|
2012-08-14 20:43:43 +00:00
|
|
|
/* file descriptor associated with a file descriptor set */
|
|
|
|
typedef struct MonFdsetFd MonFdsetFd;
|
|
|
|
struct MonFdsetFd {
|
|
|
|
int fd;
|
|
|
|
bool removed;
|
|
|
|
char *opaque;
|
|
|
|
QLIST_ENTRY(MonFdsetFd) next;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* file descriptor set containing fds passed via SCM_RIGHTS */
|
|
|
|
typedef struct MonFdset MonFdset;
|
|
|
|
struct MonFdset {
|
|
|
|
int64_t id;
|
|
|
|
QLIST_HEAD(, MonFdsetFd) fds;
|
2012-08-14 20:43:47 +00:00
|
|
|
QLIST_HEAD(, MonFdsetFd) dup_fds;
|
2012-08-14 20:43:43 +00:00
|
|
|
QLIST_ENTRY(MonFdset) next;
|
|
|
|
};
|
|
|
|
|
2018-06-08 03:55:11 +00:00
|
|
|
/* Protects mon_fdsets */
|
|
|
|
static QemuMutex mon_fdsets_lock;
|
2018-12-06 10:58:10 +00:00
|
|
|
static QLIST_HEAD(, MonFdset) mon_fdsets;
|
2018-06-08 03:55:11 +00:00
|
|
|
|
2019-06-13 15:33:56 +00:00
|
|
|
static HMPCommand hmp_info_cmds[];
|
2004-03-14 21:38:27 +00:00
|
|
|
|
2011-11-25 19:52:45 +00:00
|
|
|
char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
|
|
|
|
int64_t cpu_index, Error **errp)
|
2010-10-22 12:08:02 +00:00
|
|
|
{
|
2011-11-25 19:52:45 +00:00
|
|
|
char *output = NULL;
|
2019-06-13 15:33:52 +00:00
|
|
|
Monitor *old_mon;
|
2019-06-13 15:33:54 +00:00
|
|
|
MonitorHMP hmp = {};
|
2010-10-22 12:08:02 +00:00
|
|
|
|
2019-06-13 15:34:03 +00:00
|
|
|
monitor_data_init(&hmp.common, false, true, false);
|
2010-10-22 12:08:02 +00:00
|
|
|
|
|
|
|
old_mon = cur_mon;
|
2019-06-13 15:33:54 +00:00
|
|
|
cur_mon = &hmp.common;
|
2010-10-22 12:08:02 +00:00
|
|
|
|
2011-11-25 19:52:45 +00:00
|
|
|
if (has_cpu_index) {
|
|
|
|
int ret = monitor_set_cpu(cpu_index);
|
2010-10-22 12:08:02 +00:00
|
|
|
if (ret < 0) {
|
|
|
|
cur_mon = old_mon;
|
2015-03-17 10:54:50 +00:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
|
|
|
|
"a CPU number");
|
2010-10-22 12:08:02 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-06 18:12:36 +00:00
|
|
|
handle_hmp_command(&hmp, command_line);
|
2010-10-22 12:08:02 +00:00
|
|
|
cur_mon = old_mon;
|
|
|
|
|
2019-06-13 15:33:54 +00:00
|
|
|
qemu_mutex_lock(&hmp.common.mon_lock);
|
|
|
|
if (qstring_get_length(hmp.common.outbuf) > 0) {
|
|
|
|
output = g_strdup(qstring_get_str(hmp.common.outbuf));
|
2011-11-25 19:52:45 +00:00
|
|
|
} else {
|
|
|
|
output = g_strdup("");
|
2010-10-22 12:08:02 +00:00
|
|
|
}
|
2019-06-13 15:33:54 +00:00
|
|
|
qemu_mutex_unlock(&hmp.common.mon_lock);
|
2010-10-22 12:08:02 +00:00
|
|
|
|
|
|
|
out:
|
2019-06-13 15:33:54 +00:00
|
|
|
monitor_data_destroy(&hmp.common);
|
2011-11-25 19:52:45 +00:00
|
|
|
return output;
|
2010-10-22 12:08:02 +00:00
|
|
|
}
|
|
|
|
|
2019-06-13 15:34:01 +00:00
|
|
|
/**
|
|
|
|
* Is @name in the '|' separated list of names @list?
|
|
|
|
*/
|
|
|
|
int hmp_compare_cmd(const char *name, const char *list)
|
2004-03-14 21:38:27 +00:00
|
|
|
{
|
|
|
|
const char *p, *pstart;
|
|
|
|
int len;
|
|
|
|
len = strlen(name);
|
|
|
|
p = list;
|
2019-06-13 15:34:01 +00:00
|
|
|
for (;;) {
|
2004-03-14 21:38:27 +00:00
|
|
|
pstart = p;
|
2018-06-29 10:32:10 +00:00
|
|
|
p = qemu_strchrnul(p, '|');
|
2019-06-13 15:34:01 +00:00
|
|
|
if ((p - pstart) == len && !memcmp(pstart, name, len)) {
|
2004-03-14 21:38:27 +00:00
|
|
|
return 1;
|
2013-08-27 12:38:21 +00:00
|
|
|
}
|
|
|
|
if (*p == '\0') {
|
|
|
|
break;
|
|
|
|
}
|
2019-06-13 15:34:01 +00:00
|
|
|
p++;
|
2013-08-27 12:38:21 +00:00
|
|
|
}
|
2013-08-27 12:38:22 +00:00
|
|
|
return 0;
|
2004-03-14 21:38:27 +00:00
|
|
|
}
|
|
|
|
|
2009-08-28 18:27:13 +00:00
|
|
|
static void do_help_cmd(Monitor *mon, const QDict *qdict)
|
2009-08-28 18:27:08 +00:00
|
|
|
{
|
2009-08-28 18:27:13 +00:00
|
|
|
help_cmd(mon, qdict_get_try_str(qdict, "name"));
|
2009-08-28 18:27:08 +00:00
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_trace_event(Monitor *mon, const QDict *qdict)
|
2010-06-24 11:34:53 +00:00
|
|
|
{
|
|
|
|
const char *tp_name = qdict_get_str(qdict, "name");
|
|
|
|
bool new_state = qdict_get_bool(qdict, "option");
|
2016-07-11 10:53:57 +00:00
|
|
|
bool has_vcpu = qdict_haskey(qdict, "vcpu");
|
|
|
|
int vcpu = qdict_get_try_int(qdict, "vcpu", 0);
|
2014-08-25 11:20:03 +00:00
|
|
|
Error *local_err = NULL;
|
2010-10-13 19:14:29 +00:00
|
|
|
|
2016-07-11 10:53:57 +00:00
|
|
|
if (vcpu < 0) {
|
|
|
|
monitor_printf(mon, "argument vcpu must be positive");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
qmp_trace_event_set_state(tp_name, new_state, true, true, has_vcpu, vcpu, &local_err);
|
2014-08-25 11:20:03 +00:00
|
|
|
if (local_err) {
|
2015-02-10 14:15:43 +00:00
|
|
|
error_report_err(local_err);
|
2010-10-13 19:14:29 +00:00
|
|
|
}
|
2010-06-24 11:34:53 +00:00
|
|
|
}
|
2010-07-13 08:26:33 +00:00
|
|
|
|
2011-10-02 13:44:37 +00:00
|
|
|
#ifdef CONFIG_TRACE_SIMPLE
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_trace_file(Monitor *mon, const QDict *qdict)
|
2010-07-13 08:26:33 +00:00
|
|
|
{
|
|
|
|
const char *op = qdict_get_try_str(qdict, "op");
|
|
|
|
const char *arg = qdict_get_try_str(qdict, "arg");
|
|
|
|
|
|
|
|
if (!op) {
|
2019-04-17 19:17:50 +00:00
|
|
|
st_print_trace_file_status();
|
2010-07-13 08:26:33 +00:00
|
|
|
} else if (!strcmp(op, "on")) {
|
|
|
|
st_set_trace_file_enabled(true);
|
|
|
|
} else if (!strcmp(op, "off")) {
|
|
|
|
st_set_trace_file_enabled(false);
|
|
|
|
} else if (!strcmp(op, "flush")) {
|
|
|
|
st_flush_trace_buffer();
|
|
|
|
} else if (!strcmp(op, "set")) {
|
|
|
|
if (arg) {
|
|
|
|
st_set_trace_file(arg);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "unexpected argument \"%s\"\n", op);
|
|
|
|
help_cmd(mon, "trace-file");
|
|
|
|
}
|
|
|
|
}
|
2010-06-24 11:34:53 +00:00
|
|
|
#endif
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_info_help(Monitor *mon, const QDict *qdict)
|
2004-03-14 21:38:27 +00:00
|
|
|
{
|
2009-10-07 16:41:55 +00:00
|
|
|
help_cmd(mon, "info");
|
2004-03-14 21:38:27 +00:00
|
|
|
}
|
|
|
|
|
2016-09-12 09:19:05 +00:00
|
|
|
static void query_commands_cb(QmpCommand *cmd, void *opaque)
|
2009-11-27 00:58:56 +00:00
|
|
|
{
|
2016-09-12 09:19:05 +00:00
|
|
|
CommandInfoList *info, **list = opaque;
|
2009-11-27 00:58:56 +00:00
|
|
|
|
2016-09-12 09:19:05 +00:00
|
|
|
if (!cmd->enabled) {
|
|
|
|
return;
|
2009-11-27 00:58:56 +00:00
|
|
|
}
|
|
|
|
|
2016-09-12 09:19:05 +00:00
|
|
|
info = g_malloc0(sizeof(*info));
|
|
|
|
info->value = g_malloc0(sizeof(*info->value));
|
|
|
|
info->value->name = g_strdup(cmd->name);
|
|
|
|
info->next = *list;
|
|
|
|
*list = info;
|
|
|
|
}
|
|
|
|
|
|
|
|
CommandInfoList *qmp_query_commands(Error **errp)
|
|
|
|
{
|
|
|
|
CommandInfoList *list = NULL;
|
2019-06-13 15:33:53 +00:00
|
|
|
MonitorQMP *mon;
|
|
|
|
|
|
|
|
assert(monitor_is_qmp(cur_mon));
|
|
|
|
mon = container_of(cur_mon, MonitorQMP, common);
|
2016-09-12 09:19:05 +00:00
|
|
|
|
2019-06-13 15:33:53 +00:00
|
|
|
qmp_for_each_command(mon->commands, query_commands_cb, &list);
|
2016-09-12 09:19:05 +00:00
|
|
|
|
|
|
|
return list;
|
2007-12-02 05:18:19 +00:00
|
|
|
}
|
|
|
|
|
2012-05-21 16:59:51 +00:00
|
|
|
EventInfoList *qmp_query_events(Error **errp)
|
|
|
|
{
|
2019-02-14 15:22:50 +00:00
|
|
|
/*
|
|
|
|
* TODO This deprecated command is the only user of
|
|
|
|
* QAPIEvent_str() and QAPIEvent_lookup[]. When the command goes,
|
|
|
|
* they should go, too.
|
|
|
|
*/
|
2012-05-21 16:59:51 +00:00
|
|
|
EventInfoList *info, *ev_list = NULL;
|
2014-06-18 06:43:54 +00:00
|
|
|
QAPIEvent e;
|
2012-05-21 16:59:51 +00:00
|
|
|
|
qapi: Don't let implicit enum MAX member collide
Now that we guarantee the user doesn't have any enum values
beginning with a single underscore, we can use that for our
own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious
that the sentinel is generated.
This patch was mostly generated by applying a temporary patch:
|diff --git a/scripts/qapi.py b/scripts/qapi.py
|index e6d014b..b862ec9 100644
|--- a/scripts/qapi.py
|+++ b/scripts/qapi.py
|@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = {
| max_index = c_enum_const(name, 'MAX', prefix)
| ret += mcgen('''
| [%(max_index)s] = NULL,
|+// %(max_index)s
| };
| ''',
| max_index=max_index)
then running:
$ cat qapi-{types,event}.c tests/test-qapi-types.c |
sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list
$ git grep -l _MAX | xargs sed -i -f list
The only things not generated are the changes in scripts/qapi.py.
Rejecting enum members named 'MAX' is now useless, and will be dropped
in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
[Rebased to current master, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 08:52:57 +00:00
|
|
|
for (e = 0 ; e < QAPI_EVENT__MAX ; e++) {
|
2017-08-24 08:46:08 +00:00
|
|
|
const char *event_name = QAPIEvent_str(e);
|
2012-05-21 16:59:51 +00:00
|
|
|
assert(event_name != NULL);
|
|
|
|
info = g_malloc0(sizeof(*info));
|
|
|
|
info->value = g_malloc0(sizeof(*info->value));
|
|
|
|
info->value->name = g_strdup(event_name);
|
|
|
|
|
|
|
|
info->next = ev_list;
|
|
|
|
ev_list = info;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ev_list;
|
|
|
|
}
|
|
|
|
|
qapi: New QMP command query-qmp-schema for QMP introspection
qapi/introspect.json defines the introspection schema. It's designed
for QMP introspection, but should do for similar uses, such as QGA.
The introspection schema does not reflect all the rules and
restrictions that apply to QAPI schemata. A valid QAPI schema has an
introspection value conforming to the introspection schema, but the
converse is not true.
Introspection lowers away a number of schema details, and makes
implicit things explicit:
* The built-in types are declared with their JSON type.
All integer types are mapped to 'int', because how many bits we use
internally is an implementation detail. It could be pressed into
external interface service as very approximate range information,
but that's a bad idea. If we need range information, we better do
it properly.
* Implicit type definitions are made explicit, and given
auto-generated names:
- Array types, named by appending "List" to the name of their
element type, like in generated C.
- The enumeration types implicitly defined by simple union types,
named by appending "Kind" to the name of their simple union type,
like in generated C.
- Types that don't occur in generated C. Their names start with ':'
so they don't clash with the user's names.
* All type references are by name.
* The struct and union types are generalized into an object type.
* Base types are flattened.
* Commands take a single argument and return a single result.
Dictionary argument or list result is an implicit type definition.
The empty object type is used when a command takes no arguments or
produces no results.
The argument is always of object type, but the introspection schema
doesn't reflect that.
The 'gen': false directive is omitted as implementation detail.
The 'success-response' directive is omitted as well for now, even
though it's not an implementation detail, because it's not used by
QMP.
* Events carry a single data value.
Implicit type definition and empty object type use, just like for
commands.
The value is of object type, but the introspection schema doesn't
reflect that.
* Types not used by commands or events are omitted.
Indirect use counts as use.
* Optional members have a default, which can only be null right now
Instead of a mandatory "optional" flag, we have an optional default.
No default means mandatory, default null means optional without
default value. Non-null is available for optional with default
(possible future extension).
* Clients should *not* look up types by name, because type names are
not ABI. Look up the command or event you're interested in, then
follow the references.
TODO Should we hide the type names to eliminate the temptation?
New generator scripts/qapi-introspect.py computes an introspection
value for its input, and generates a C variable holding it.
It can generate awfully long lines. Marked TODO.
A new test-qmp-input-visitor test case feeds its result for both
tests/qapi-schema/qapi-schema-test.json and qapi-schema.json to a
QmpInputVisitor to verify it actually conforms to the schema.
New QMP command query-qmp-schema takes its return value from that
variable. Its reply is some 85KiBytes for me right now.
If this turns out to be too much, we have a couple of options:
* We can use shorter names in the JSON. Not the QMP style.
* Optionally return the sub-schema for commands and events given as
arguments.
Right now qmp_query_schema() sends the string literal computed by
qmp-introspect.py. To compute sub-schema at run time, we'd have to
duplicate parts of qapi-introspect.py in C. Unattractive.
* Let clients cache the output of query-qmp-schema.
It changes only on QEMU upgrades, i.e. rarely. Provide a command
query-qmp-schema-hash. Clients can have a cache indexed by hash,
and re-query the schema only when they don't have it cached. Even
simpler: put the hash in the QMP greeting.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-09-16 11:06:28 +00:00
|
|
|
/*
|
|
|
|
* Minor hack: generated marshalling suppressed for this command
|
|
|
|
* ('gen': false in the schema) so we can parse the JSON string
|
|
|
|
* directly into QObject instead of first parsing it with
|
|
|
|
* visit_type_SchemaInfoList() into a SchemaInfoList, then marshal it
|
|
|
|
* to QObject with generated output marshallers, every time. Instead,
|
2016-09-30 14:45:27 +00:00
|
|
|
* we do it in test-qobject-input-visitor.c, just to make sure
|
2018-02-26 19:48:58 +00:00
|
|
|
* qapi-gen.py's output actually conforms to the schema.
|
qapi: New QMP command query-qmp-schema for QMP introspection
qapi/introspect.json defines the introspection schema. It's designed
for QMP introspection, but should do for similar uses, such as QGA.
The introspection schema does not reflect all the rules and
restrictions that apply to QAPI schemata. A valid QAPI schema has an
introspection value conforming to the introspection schema, but the
converse is not true.
Introspection lowers away a number of schema details, and makes
implicit things explicit:
* The built-in types are declared with their JSON type.
All integer types are mapped to 'int', because how many bits we use
internally is an implementation detail. It could be pressed into
external interface service as very approximate range information,
but that's a bad idea. If we need range information, we better do
it properly.
* Implicit type definitions are made explicit, and given
auto-generated names:
- Array types, named by appending "List" to the name of their
element type, like in generated C.
- The enumeration types implicitly defined by simple union types,
named by appending "Kind" to the name of their simple union type,
like in generated C.
- Types that don't occur in generated C. Their names start with ':'
so they don't clash with the user's names.
* All type references are by name.
* The struct and union types are generalized into an object type.
* Base types are flattened.
* Commands take a single argument and return a single result.
Dictionary argument or list result is an implicit type definition.
The empty object type is used when a command takes no arguments or
produces no results.
The argument is always of object type, but the introspection schema
doesn't reflect that.
The 'gen': false directive is omitted as implementation detail.
The 'success-response' directive is omitted as well for now, even
though it's not an implementation detail, because it's not used by
QMP.
* Events carry a single data value.
Implicit type definition and empty object type use, just like for
commands.
The value is of object type, but the introspection schema doesn't
reflect that.
* Types not used by commands or events are omitted.
Indirect use counts as use.
* Optional members have a default, which can only be null right now
Instead of a mandatory "optional" flag, we have an optional default.
No default means mandatory, default null means optional without
default value. Non-null is available for optional with default
(possible future extension).
* Clients should *not* look up types by name, because type names are
not ABI. Look up the command or event you're interested in, then
follow the references.
TODO Should we hide the type names to eliminate the temptation?
New generator scripts/qapi-introspect.py computes an introspection
value for its input, and generates a C variable holding it.
It can generate awfully long lines. Marked TODO.
A new test-qmp-input-visitor test case feeds its result for both
tests/qapi-schema/qapi-schema-test.json and qapi-schema.json to a
QmpInputVisitor to verify it actually conforms to the schema.
New QMP command query-qmp-schema takes its return value from that
variable. Its reply is some 85KiBytes for me right now.
If this turns out to be too much, we have a couple of options:
* We can use shorter names in the JSON. Not the QMP style.
* Optionally return the sub-schema for commands and events given as
arguments.
Right now qmp_query_schema() sends the string literal computed by
qmp-introspect.py. To compute sub-schema at run time, we'd have to
duplicate parts of qapi-introspect.py in C. Unattractive.
* Let clients cache the output of query-qmp-schema.
It changes only on QEMU upgrades, i.e. rarely. Provide a command
query-qmp-schema-hash. Clients can have a cache indexed by hash,
and re-query the schema only when they don't have it cached. Even
simpler: put the hash in the QMP greeting.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-09-16 11:06:28 +00:00
|
|
|
*/
|
|
|
|
static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
|
|
|
|
Error **errp)
|
|
|
|
{
|
2018-03-05 17:29:51 +00:00
|
|
|
*ret_data = qobject_from_qlit(&qmp_schema_qlit);
|
qapi: New QMP command query-qmp-schema for QMP introspection
qapi/introspect.json defines the introspection schema. It's designed
for QMP introspection, but should do for similar uses, such as QGA.
The introspection schema does not reflect all the rules and
restrictions that apply to QAPI schemata. A valid QAPI schema has an
introspection value conforming to the introspection schema, but the
converse is not true.
Introspection lowers away a number of schema details, and makes
implicit things explicit:
* The built-in types are declared with their JSON type.
All integer types are mapped to 'int', because how many bits we use
internally is an implementation detail. It could be pressed into
external interface service as very approximate range information,
but that's a bad idea. If we need range information, we better do
it properly.
* Implicit type definitions are made explicit, and given
auto-generated names:
- Array types, named by appending "List" to the name of their
element type, like in generated C.
- The enumeration types implicitly defined by simple union types,
named by appending "Kind" to the name of their simple union type,
like in generated C.
- Types that don't occur in generated C. Their names start with ':'
so they don't clash with the user's names.
* All type references are by name.
* The struct and union types are generalized into an object type.
* Base types are flattened.
* Commands take a single argument and return a single result.
Dictionary argument or list result is an implicit type definition.
The empty object type is used when a command takes no arguments or
produces no results.
The argument is always of object type, but the introspection schema
doesn't reflect that.
The 'gen': false directive is omitted as implementation detail.
The 'success-response' directive is omitted as well for now, even
though it's not an implementation detail, because it's not used by
QMP.
* Events carry a single data value.
Implicit type definition and empty object type use, just like for
commands.
The value is of object type, but the introspection schema doesn't
reflect that.
* Types not used by commands or events are omitted.
Indirect use counts as use.
* Optional members have a default, which can only be null right now
Instead of a mandatory "optional" flag, we have an optional default.
No default means mandatory, default null means optional without
default value. Non-null is available for optional with default
(possible future extension).
* Clients should *not* look up types by name, because type names are
not ABI. Look up the command or event you're interested in, then
follow the references.
TODO Should we hide the type names to eliminate the temptation?
New generator scripts/qapi-introspect.py computes an introspection
value for its input, and generates a C variable holding it.
It can generate awfully long lines. Marked TODO.
A new test-qmp-input-visitor test case feeds its result for both
tests/qapi-schema/qapi-schema-test.json and qapi-schema.json to a
QmpInputVisitor to verify it actually conforms to the schema.
New QMP command query-qmp-schema takes its return value from that
variable. Its reply is some 85KiBytes for me right now.
If this turns out to be too much, we have a couple of options:
* We can use shorter names in the JSON. Not the QMP style.
* Optionally return the sub-schema for commands and events given as
arguments.
Right now qmp_query_schema() sends the string literal computed by
qmp-introspect.py. To compute sub-schema at run time, we'd have to
duplicate parts of qapi-introspect.py in C. Unattractive.
* Let clients cache the output of query-qmp-schema.
It changes only on QEMU upgrades, i.e. rarely. Provide a command
query-qmp-schema-hash. Clients can have a cache indexed by hash,
and re-query the schema only when they don't have it cached. Even
simpler: put the hash in the QMP greeting.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-09-16 11:06:28 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 08:59:50 +00:00
|
|
|
static void monitor_init_qmp_commands(void)
|
2016-09-12 09:19:00 +00:00
|
|
|
{
|
qmp: Clean up how we enforce capability negotiation
To enforce capability negotiation before normal operation,
handle_qmp_command() inspects every command before it's handed off to
qmp_dispatch(). This is a bit of a layering violation, and results in
duplicated code.
Before capability negotiation (!cur_mon->in_command_mode), we fail
commands other than "qmp_capabilities". This is what enforces
capability negotiation.
Afterwards, we fail command "qmp_capabilities".
Clean this up as follows.
The obvious place to fail a command is the command itself, so move the
"afterwards" check to qmp_qmp_capabilities().
We do the "before" check in every other command, but that would be
bothersome. Instead, start with an alternate list of commands that
contains only "qmp_capabilities". Switch to the full list in
qmp_qmp_capabilities().
Additionally, replace the generic human-readable error message for
CommandNotFound by one that reminds the user to run qmp_capabilities.
Without that, we'd regress commit 2d5a834.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1488544368-30622-8-git-send-email-armbru@redhat.com>
[Mirco-optimization squashed in, commit message typo fixed]
Reviewed-by: Eric Blake <eblake@redhat.com>
2017-03-03 12:32:27 +00:00
|
|
|
/*
|
|
|
|
* Two command lists:
|
|
|
|
* - qmp_commands contains all QMP commands
|
|
|
|
* - qmp_cap_negotiation_commands contains just
|
|
|
|
* "qmp_capabilities", to enforce capability negotiation
|
|
|
|
*/
|
|
|
|
|
2017-03-03 12:32:25 +00:00
|
|
|
qmp_init_marshal(&qmp_commands);
|
2017-03-03 12:32:24 +00:00
|
|
|
|
2017-03-03 12:32:25 +00:00
|
|
|
qmp_register_command(&qmp_commands, "query-qmp-schema",
|
2018-05-11 16:51:43 +00:00
|
|
|
qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
|
2017-03-03 12:32:25 +00:00
|
|
|
qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
|
2016-09-12 09:19:00 +00:00
|
|
|
QCO_NO_OPTIONS);
|
2017-03-03 12:32:25 +00:00
|
|
|
qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add,
|
2016-09-12 09:19:00 +00:00
|
|
|
QCO_NO_OPTIONS);
|
2016-09-12 09:19:02 +00:00
|
|
|
|
qmp: Clean up how we enforce capability negotiation
To enforce capability negotiation before normal operation,
handle_qmp_command() inspects every command before it's handed off to
qmp_dispatch(). This is a bit of a layering violation, and results in
duplicated code.
Before capability negotiation (!cur_mon->in_command_mode), we fail
commands other than "qmp_capabilities". This is what enforces
capability negotiation.
Afterwards, we fail command "qmp_capabilities".
Clean this up as follows.
The obvious place to fail a command is the command itself, so move the
"afterwards" check to qmp_qmp_capabilities().
We do the "before" check in every other command, but that would be
bothersome. Instead, start with an alternate list of commands that
contains only "qmp_capabilities". Switch to the full list in
qmp_qmp_capabilities().
Additionally, replace the generic human-readable error message for
CommandNotFound by one that reminds the user to run qmp_capabilities.
Without that, we'd regress commit 2d5a834.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1488544368-30622-8-git-send-email-armbru@redhat.com>
[Mirco-optimization squashed in, commit message typo fixed]
Reviewed-by: Eric Blake <eblake@redhat.com>
2017-03-03 12:32:27 +00:00
|
|
|
QTAILQ_INIT(&qmp_cap_negotiation_commands);
|
|
|
|
qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
|
2018-05-11 16:51:43 +00:00
|
|
|
qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG);
|
qmp: Clean up how we enforce capability negotiation
To enforce capability negotiation before normal operation,
handle_qmp_command() inspects every command before it's handed off to
qmp_dispatch(). This is a bit of a layering violation, and results in
duplicated code.
Before capability negotiation (!cur_mon->in_command_mode), we fail
commands other than "qmp_capabilities". This is what enforces
capability negotiation.
Afterwards, we fail command "qmp_capabilities".
Clean this up as follows.
The obvious place to fail a command is the command itself, so move the
"afterwards" check to qmp_qmp_capabilities().
We do the "before" check in every other command, but that would be
bothersome. Instead, start with an alternate list of commands that
contains only "qmp_capabilities". Switch to the full list in
qmp_qmp_capabilities().
Additionally, replace the generic human-readable error message for
CommandNotFound by one that reminds the user to run qmp_capabilities.
Without that, we'd regress commit 2d5a834.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1488544368-30622-8-git-send-email-armbru@redhat.com>
[Mirco-optimization squashed in, commit message typo fixed]
Reviewed-by: Eric Blake <eblake@redhat.com>
2017-03-03 12:32:27 +00:00
|
|
|
}
|
|
|
|
|
2018-03-11 02:38:05 +00:00
|
|
|
/*
|
2018-07-03 08:53:56 +00:00
|
|
|
* Accept QMP capabilities in @list for @mon.
|
|
|
|
* On success, set mon->qmp.capab[], and return true.
|
|
|
|
* On error, set @errp, and return false.
|
2018-03-11 02:38:05 +00:00
|
|
|
*/
|
2019-06-13 15:33:53 +00:00
|
|
|
static bool qmp_caps_accept(MonitorQMP *mon, QMPCapabilityList *list,
|
2018-07-03 08:53:56 +00:00
|
|
|
Error **errp)
|
2018-03-11 02:38:05 +00:00
|
|
|
{
|
2018-07-03 08:53:56 +00:00
|
|
|
GString *unavailable = NULL;
|
|
|
|
bool capab[QMP_CAPABILITY__MAX];
|
2018-03-11 02:38:05 +00:00
|
|
|
|
2018-07-03 08:53:56 +00:00
|
|
|
memset(capab, 0, sizeof(capab));
|
2018-03-11 02:38:05 +00:00
|
|
|
|
qmp: introduce QMPCapability
There were no QMP capabilities defined. Define the first capability,
"oob", to allow out-of-band messages.
After this patch, we will allow QMP clients to enable QMP capabilities
when sending the first "qmp_capabilities" command. Originally we are
starting QMP session with no arguments like:
{ "execute": "qmp_capabilities" }
Now we can enable some QMP capabilities using (take OOB as example,
which is the only capability that we support):
{ "execute": "qmp_capabilities",
"arguments": { "enable": [ "oob" ] } }
When the "arguments" key is not provided, no capability is enabled.
For capability "oob", the monitor needs to be run on a dedicated IO
thread, otherwise the command will fail. For example, trying to enable
OOB on a MUXed typed QMP monitor will fail.
One thing to mention is that QMP capabilities are per-monitor, and also
when the connection is closed due to some reason, the capabilities will
be reset.
Also, touch up qmp-test.c to test the new bits.
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20180309090006.10018-11-peterx@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
[eblake: touch up commit message]
Signed-off-by: Eric Blake <eblake@redhat.com>
2018-03-09 08:59:53 +00:00
|
|
|
for (; list; list = list->next) {
|
2019-06-13 15:33:53 +00:00
|
|
|
if (!mon->capab_offered[list->value]) {
|
2018-07-03 08:53:56 +00:00
|
|
|
if (!unavailable) {
|
|
|
|
unavailable = g_string_new(QMPCapability_str(list->value));
|
|
|
|
} else {
|
|
|
|
g_string_append_printf(unavailable, ", %s",
|
|
|
|
QMPCapability_str(list->value));
|
qmp: introduce QMPCapability
There were no QMP capabilities defined. Define the first capability,
"oob", to allow out-of-band messages.
After this patch, we will allow QMP clients to enable QMP capabilities
when sending the first "qmp_capabilities" command. Originally we are
starting QMP session with no arguments like:
{ "execute": "qmp_capabilities" }
Now we can enable some QMP capabilities using (take OOB as example,
which is the only capability that we support):
{ "execute": "qmp_capabilities",
"arguments": { "enable": [ "oob" ] } }
When the "arguments" key is not provided, no capability is enabled.
For capability "oob", the monitor needs to be run on a dedicated IO
thread, otherwise the command will fail. For example, trying to enable
OOB on a MUXed typed QMP monitor will fail.
One thing to mention is that QMP capabilities are per-monitor, and also
when the connection is closed due to some reason, the capabilities will
be reset.
Also, touch up qmp-test.c to test the new bits.
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20180309090006.10018-11-peterx@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
[eblake: touch up commit message]
Signed-off-by: Eric Blake <eblake@redhat.com>
2018-03-09 08:59:53 +00:00
|
|
|
}
|
2018-03-26 06:38:54 +00:00
|
|
|
}
|
2018-07-03 08:53:56 +00:00
|
|
|
capab[list->value] = true;
|
2018-03-11 02:38:05 +00:00
|
|
|
}
|
|
|
|
|
2018-07-03 08:53:56 +00:00
|
|
|
if (unavailable) {
|
|
|
|
error_setg(errp, "Capability %s not available", unavailable->str);
|
|
|
|
g_string_free(unavailable, true);
|
|
|
|
return false;
|
2018-03-11 02:38:05 +00:00
|
|
|
}
|
|
|
|
|
2019-06-13 15:33:53 +00:00
|
|
|
memcpy(mon->capab, capab, sizeof(capab));
|
2018-03-11 02:38:05 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
qmp: introduce QMPCapability
There were no QMP capabilities defined. Define the first capability,
"oob", to allow out-of-band messages.
After this patch, we will allow QMP clients to enable QMP capabilities
when sending the first "qmp_capabilities" command. Originally we are
starting QMP session with no arguments like:
{ "execute": "qmp_capabilities" }
Now we can enable some QMP capabilities using (take OOB as example,
which is the only capability that we support):
{ "execute": "qmp_capabilities",
"arguments": { "enable": [ "oob" ] } }
When the "arguments" key is not provided, no capability is enabled.
For capability "oob", the monitor needs to be run on a dedicated IO
thread, otherwise the command will fail. For example, trying to enable
OOB on a MUXed typed QMP monitor will fail.
One thing to mention is that QMP capabilities are per-monitor, and also
when the connection is closed due to some reason, the capabilities will
be reset.
Also, touch up qmp-test.c to test the new bits.
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20180309090006.10018-11-peterx@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
[eblake: touch up commit message]
Signed-off-by: Eric Blake <eblake@redhat.com>
2018-03-09 08:59:53 +00:00
|
|
|
void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable,
|
|
|
|
Error **errp)
|
|
|
|
{
|
2019-06-13 15:33:53 +00:00
|
|
|
MonitorQMP *mon;
|
|
|
|
|
|
|
|
assert(monitor_is_qmp(cur_mon));
|
|
|
|
mon = container_of(cur_mon, MonitorQMP, common);
|
|
|
|
|
|
|
|
if (mon->commands == &qmp_commands) {
|
qmp: Clean up how we enforce capability negotiation
To enforce capability negotiation before normal operation,
handle_qmp_command() inspects every command before it's handed off to
qmp_dispatch(). This is a bit of a layering violation, and results in
duplicated code.
Before capability negotiation (!cur_mon->in_command_mode), we fail
commands other than "qmp_capabilities". This is what enforces
capability negotiation.
Afterwards, we fail command "qmp_capabilities".
Clean this up as follows.
The obvious place to fail a command is the command itself, so move the
"afterwards" check to qmp_qmp_capabilities().
We do the "before" check in every other command, but that would be
bothersome. Instead, start with an alternate list of commands that
contains only "qmp_capabilities". Switch to the full list in
qmp_qmp_capabilities().
Additionally, replace the generic human-readable error message for
CommandNotFound by one that reminds the user to run qmp_capabilities.
Without that, we'd regress commit 2d5a834.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1488544368-30622-8-git-send-email-armbru@redhat.com>
[Mirco-optimization squashed in, commit message typo fixed]
Reviewed-by: Eric Blake <eblake@redhat.com>
2017-03-03 12:32:27 +00:00
|
|
|
error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
|
|
|
|
"Capabilities negotiation is already complete, command "
|
|
|
|
"ignored");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-13 15:33:53 +00:00
|
|
|
if (!qmp_caps_accept(mon, enable, errp)) {
|
2018-07-03 08:53:56 +00:00
|
|
|
return;
|
qmp: introduce QMPCapability
There were no QMP capabilities defined. Define the first capability,
"oob", to allow out-of-band messages.
After this patch, we will allow QMP clients to enable QMP capabilities
when sending the first "qmp_capabilities" command. Originally we are
starting QMP session with no arguments like:
{ "execute": "qmp_capabilities" }
Now we can enable some QMP capabilities using (take OOB as example,
which is the only capability that we support):
{ "execute": "qmp_capabilities",
"arguments": { "enable": [ "oob" ] } }
When the "arguments" key is not provided, no capability is enabled.
For capability "oob", the monitor needs to be run on a dedicated IO
thread, otherwise the command will fail. For example, trying to enable
OOB on a MUXed typed QMP monitor will fail.
One thing to mention is that QMP capabilities are per-monitor, and also
when the connection is closed due to some reason, the capabilities will
be reset.
Also, touch up qmp-test.c to test the new bits.
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20180309090006.10018-11-peterx@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
[eblake: touch up commit message]
Signed-off-by: Eric Blake <eblake@redhat.com>
2018-03-09 08:59:53 +00:00
|
|
|
}
|
|
|
|
|
2019-06-13 15:33:53 +00:00
|
|
|
mon->commands = &qmp_commands;
|
2016-09-12 09:19:00 +00:00
|
|
|
}
|
|
|
|
|
2018-06-08 03:55:07 +00:00
|
|
|
/* Set the current CPU defined by the user. Callers must hold BQL. */
|
2011-10-06 17:02:57 +00:00
|
|
|
int monitor_set_cpu(int cpu_index)
|
2005-11-21 23:25:50 +00:00
|
|
|
{
|
2012-12-17 05:18:02 +00:00
|
|
|
CPUState *cpu;
|
2005-11-21 23:25:50 +00:00
|
|
|
|
2013-02-15 16:01:09 +00:00
|
|
|
cpu = qemu_get_cpu(cpu_index);
|
|
|
|
if (cpu == NULL) {
|
|
|
|
return -1;
|
2005-11-21 23:25:50 +00:00
|
|
|
}
|
2017-10-17 08:16:22 +00:00
|
|
|
g_free(cur_mon->mon_cpu_path);
|
|
|
|
cur_mon->mon_cpu_path = object_get_canonical_path(OBJECT(cpu));
|
2013-02-15 16:01:09 +00:00
|
|
|
return 0;
|
2005-11-21 23:25:50 +00:00
|
|
|
}
|
|
|
|
|
2018-06-08 03:55:07 +00:00
|
|
|
/* Callers must hold BQL. */
|
2018-02-16 16:08:41 +00:00
|
|
|
static CPUState *mon_get_cpu_sync(bool synchronize)
|
2005-11-21 23:25:50 +00:00
|
|
|
{
|
2019-10-04 11:18:20 +00:00
|
|
|
CPUState *cpu = NULL;
|
2017-10-17 08:16:22 +00:00
|
|
|
|
|
|
|
if (cur_mon->mon_cpu_path) {
|
|
|
|
cpu = (CPUState *) object_resolve_path_type(cur_mon->mon_cpu_path,
|
|
|
|
TYPE_CPU, NULL);
|
|
|
|
if (!cpu) {
|
|
|
|
g_free(cur_mon->mon_cpu_path);
|
|
|
|
cur_mon->mon_cpu_path = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!cur_mon->mon_cpu_path) {
|
2017-01-13 12:12:35 +00:00
|
|
|
if (!first_cpu) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-09-21 05:29:26 +00:00
|
|
|
monitor_set_cpu(first_cpu->cpu_index);
|
2017-10-17 08:16:22 +00:00
|
|
|
cpu = first_cpu;
|
2005-11-21 23:25:50 +00:00
|
|
|
}
|
2019-10-04 11:18:20 +00:00
|
|
|
assert(cpu != NULL);
|
2018-02-16 16:08:41 +00:00
|
|
|
if (synchronize) {
|
|
|
|
cpu_synchronize_state(cpu);
|
|
|
|
}
|
2017-10-17 08:16:22 +00:00
|
|
|
return cpu;
|
2015-05-24 21:20:40 +00:00
|
|
|
}
|
|
|
|
|
2018-02-16 16:08:41 +00:00
|
|
|
CPUState *mon_get_cpu(void)
|
|
|
|
{
|
|
|
|
return mon_get_cpu_sync(true);
|
|
|
|
}
|
|
|
|
|
2015-09-10 15:38:59 +00:00
|
|
|
CPUArchState *mon_get_cpu_env(void)
|
2015-05-24 21:20:40 +00:00
|
|
|
{
|
2017-01-13 12:12:35 +00:00
|
|
|
CPUState *cs = mon_get_cpu();
|
|
|
|
|
|
|
|
return cs ? cs->env_ptr : NULL;
|
2005-11-21 23:25:50 +00:00
|
|
|
}
|
|
|
|
|
2011-10-24 12:53:44 +00:00
|
|
|
int monitor_get_cpu_index(void)
|
|
|
|
{
|
2018-02-16 16:08:41 +00:00
|
|
|
CPUState *cs = mon_get_cpu_sync(false);
|
2017-01-13 12:12:35 +00:00
|
|
|
|
|
|
|
return cs ? cs->cpu_index : UNASSIGNED_CPU_INDEX;
|
2011-10-24 12:53:44 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:18:24 +00:00
|
|
|
static void hmp_info_registers(Monitor *mon, const QDict *qdict)
|
2004-04-04 12:57:25 +00:00
|
|
|
{
|
2017-06-08 05:41:16 +00:00
|
|
|
bool all_cpus = qdict_get_try_bool(qdict, "cpustate_all", false);
|
|
|
|
CPUState *cs;
|
2017-01-13 12:12:35 +00:00
|
|
|
|
2017-06-08 05:41:16 +00:00
|
|
|
if (all_cpus) {
|
|
|
|
CPU_FOREACH(cs) {
|
|
|
|
monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index);
|
2019-04-17 19:18:02 +00:00
|
|
|
cpu_dump_state(cs, NULL, CPU_DUMP_FPU);
|
2017-06-08 05:41:16 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cs = mon_get_cpu();
|
|
|
|
|
|
|
|
if (!cs) {
|
|
|
|
monitor_printf(mon, "No CPU available\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-04-17 19:18:02 +00:00
|
|
|
cpu_dump_state(cs, NULL, CPU_DUMP_FPU);
|
2017-01-13 12:12:35 +00:00
|
|
|
}
|
2004-04-04 12:57:25 +00:00
|
|
|
}
|
|
|
|
|
2012-09-17 11:42:41 +00:00
|
|
|
#ifdef CONFIG_TCG
|
2015-02-06 13:18:24 +00:00
|
|
|
static void hmp_info_jit(Monitor *mon, const QDict *qdict)
|
2005-01-26 22:00:47 +00:00
|
|
|
{
|
2017-04-26 04:11:47 +00:00
|
|
|
if (!tcg_enabled()) {
|
|
|
|
error_report("JIT information is only available with accel=tcg");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-04-17 19:17:52 +00:00
|
|
|
dump_exec_info();
|
2019-04-17 19:17:53 +00:00
|
|
|
dump_drift_info();
|
2005-01-26 22:00:47 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:18:24 +00:00
|
|
|
static void hmp_info_opcount(Monitor *mon, const QDict *qdict)
|
2014-11-02 08:04:18 +00:00
|
|
|
{
|
2019-04-17 19:17:51 +00:00
|
|
|
dump_opcount_info();
|
2014-11-02 08:04:18 +00:00
|
|
|
}
|
2012-09-17 11:42:41 +00:00
|
|
|
#endif
|
2014-11-02 08:04:18 +00:00
|
|
|
|
2017-08-08 17:54:42 +00:00
|
|
|
static void hmp_info_sync_profile(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
int64_t max = qdict_get_try_int(qdict, "max", 10);
|
|
|
|
bool mean = qdict_get_try_bool(qdict, "mean", false);
|
|
|
|
bool coalesce = !qdict_get_try_bool(qdict, "no_coalesce", false);
|
|
|
|
enum QSPSortBy sort_by;
|
|
|
|
|
|
|
|
sort_by = mean ? QSP_SORT_BY_AVG_WAIT_TIME : QSP_SORT_BY_TOTAL_WAIT_TIME;
|
2019-04-17 19:17:54 +00:00
|
|
|
qsp_report(max, sort_by, coalesce);
|
2017-08-08 17:54:42 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:18:24 +00:00
|
|
|
static void hmp_info_history(Monitor *mon, const QDict *qdict)
|
2004-04-04 13:07:25 +00:00
|
|
|
{
|
2019-06-13 15:33:54 +00:00
|
|
|
MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common);
|
2004-04-04 13:07:25 +00:00
|
|
|
int i;
|
2004-08-01 21:52:19 +00:00
|
|
|
const char *str;
|
2007-09-17 08:09:54 +00:00
|
|
|
|
2019-06-13 15:33:54 +00:00
|
|
|
if (!hmp_mon->rs) {
|
2009-03-05 23:01:51 +00:00
|
|
|
return;
|
2019-06-13 15:33:54 +00:00
|
|
|
}
|
2004-08-01 21:52:19 +00:00
|
|
|
i = 0;
|
|
|
|
for(;;) {
|
2019-06-13 15:33:54 +00:00
|
|
|
str = readline_get_history(hmp_mon->rs, i);
|
|
|
|
if (!str) {
|
2004-08-01 21:52:19 +00:00
|
|
|
break;
|
2019-06-13 15:33:54 +00:00
|
|
|
}
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "%d: '%s'\n", i, str);
|
2004-10-09 17:32:58 +00:00
|
|
|
i++;
|
2004-04-04 13:07:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-06 13:18:24 +00:00
|
|
|
static void hmp_info_cpustats(Monitor *mon, const QDict *qdict)
|
2007-03-07 08:32:30 +00:00
|
|
|
{
|
2017-01-13 12:12:35 +00:00
|
|
|
CPUState *cs = mon_get_cpu();
|
|
|
|
|
|
|
|
if (!cs) {
|
|
|
|
monitor_printf(mon, "No CPU available\n");
|
|
|
|
return;
|
|
|
|
}
|
2019-04-17 19:18:00 +00:00
|
|
|
cpu_dump_statistics(cs, 0);
|
2007-03-07 08:32:30 +00:00
|
|
|
}
|
|
|
|
|
2015-02-06 13:18:24 +00:00
|
|
|
static void hmp_info_trace_events(Monitor *mon, const QDict *qdict)
|
2010-06-24 11:34:53 +00:00
|
|
|
{
|
2016-07-11 10:53:51 +00:00
|
|
|
const char *name = qdict_get_try_str(qdict, "name");
|
2016-07-11 10:53:57 +00:00
|
|
|
bool has_vcpu = qdict_haskey(qdict, "vcpu");
|
|
|
|
int vcpu = qdict_get_try_int(qdict, "vcpu", 0);
|
2016-07-11 10:53:51 +00:00
|
|
|
TraceEventInfoList *events;
|
2014-08-25 11:20:03 +00:00
|
|
|
TraceEventInfoList *elem;
|
2016-07-11 10:53:51 +00:00
|
|
|
Error *local_err = NULL;
|
|
|
|
|
|
|
|
if (name == NULL) {
|
|
|
|
name = "*";
|
|
|
|
}
|
2016-07-11 10:53:57 +00:00
|
|
|
if (vcpu < 0) {
|
|
|
|
monitor_printf(mon, "argument vcpu must be positive");
|
|
|
|
return;
|
|
|
|
}
|
2016-07-11 10:53:51 +00:00
|
|
|
|
2016-07-11 10:53:57 +00:00
|
|
|
events = qmp_trace_event_get_state(name, has_vcpu, vcpu, &local_err);
|
2016-07-11 10:53:51 +00:00
|
|
|
if (local_err) {
|
|
|
|
error_report_err(local_err);
|
|
|
|
return;
|
|
|
|
}
|
2014-08-25 11:20:03 +00:00
|
|
|
|
|
|
|
for (elem = events; elem != NULL; elem = elem->next) {
|
|
|
|
monitor_printf(mon, "%s : state %u\n",
|
|
|
|
elem->value->name,
|
|
|
|
elem->value->state == TRACE_EVENT_STATE_ENABLED ? 1 : 0);
|
|
|
|
}
|
|
|
|
qapi_free_TraceEventInfoList(events);
|
2010-06-24 11:34:53 +00:00
|
|
|
}
|
|
|
|
|
2015-03-05 16:29:02 +00:00
|
|
|
void qmp_client_migrate_info(const char *protocol, const char *hostname,
|
|
|
|
bool has_port, int64_t port,
|
|
|
|
bool has_tls_port, int64_t tls_port,
|
|
|
|
bool has_cert_subject, const char *cert_subject,
|
|
|
|
Error **errp)
|
2010-04-23 11:28:21 +00:00
|
|
|
{
|
|
|
|
if (strcmp(protocol, "spice") == 0) {
|
2015-03-05 16:29:02 +00:00
|
|
|
if (!qemu_using_spice(errp)) {
|
|
|
|
return;
|
2010-04-23 11:28:21 +00:00
|
|
|
}
|
|
|
|
|
2015-03-05 16:29:02 +00:00
|
|
|
if (!has_port && !has_tls_port) {
|
2015-03-17 10:54:50 +00:00
|
|
|
error_setg(errp, QERR_MISSING_PARAMETER, "port/tls-port");
|
2015-03-05 16:29:02 +00:00
|
|
|
return;
|
2012-03-18 07:42:39 +00:00
|
|
|
}
|
|
|
|
|
2015-03-05 16:29:02 +00:00
|
|
|
if (qemu_spice_migrate_info(hostname,
|
|
|
|
has_port ? port : -1,
|
|
|
|
has_tls_port ? tls_port : -1,
|
|
|
|
cert_subject)) {
|
2015-03-17 10:54:50 +00:00
|
|
|
error_setg(errp, QERR_UNDEFINED_ERROR);
|
2015-03-05 16:29:02 +00:00
|
|
|
return;
|
2010-04-23 11:28:21 +00:00
|
|
|
}
|
2015-03-05 16:29:02 +00:00
|
|
|
return;
|
2010-04-23 11:28:21 +00:00
|
|
|
}
|
|
|
|
|
2015-03-17 10:54:50 +00:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "protocol", "spice");
|
2010-04-23 11:28:21 +00:00
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_logfile(Monitor *mon, const QDict *qdict)
|
2007-06-30 13:53:24 +00:00
|
|
|
{
|
2016-06-15 17:27:16 +00:00
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qemu_set_log_filename(qdict_get_str(qdict, "filename"), &err);
|
|
|
|
if (err) {
|
|
|
|
error_report_err(err);
|
|
|
|
}
|
2007-06-30 13:53:24 +00:00
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_log(Monitor *mon, const QDict *qdict)
|
2004-03-21 17:06:25 +00:00
|
|
|
{
|
|
|
|
int mask;
|
2009-08-28 18:27:13 +00:00
|
|
|
const char *items = qdict_get_str(qdict, "items");
|
2007-09-17 08:09:54 +00:00
|
|
|
|
2004-04-04 12:57:25 +00:00
|
|
|
if (!strcmp(items, "none")) {
|
2004-03-21 17:06:25 +00:00
|
|
|
mask = 0;
|
|
|
|
} else {
|
2013-02-11 16:41:22 +00:00
|
|
|
mask = qemu_str_to_log_mask(items);
|
2004-03-21 17:06:25 +00:00
|
|
|
if (!mask) {
|
2009-03-05 23:01:23 +00:00
|
|
|
help_cmd(mon, "log");
|
2004-03-21 17:06:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2013-02-11 16:41:23 +00:00
|
|
|
qemu_set_log(mask);
|
2004-03-21 17:06:25 +00:00
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_singlestep(Monitor *mon, const QDict *qdict)
|
2009-04-05 20:08:59 +00:00
|
|
|
{
|
2009-08-28 18:27:13 +00:00
|
|
|
const char *option = qdict_get_try_str(qdict, "option");
|
2009-04-05 20:08:59 +00:00
|
|
|
if (!option || !strcmp(option, "on")) {
|
|
|
|
singlestep = 1;
|
|
|
|
} else if (!strcmp(option, "off")) {
|
|
|
|
singlestep = 0;
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "unexpected option %s\n", option);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_gdbserver(Monitor *mon, const QDict *qdict)
|
2009-04-05 18:43:41 +00:00
|
|
|
{
|
2009-08-28 18:27:13 +00:00
|
|
|
const char *device = qdict_get_try_str(qdict, "device");
|
2009-04-05 18:43:41 +00:00
|
|
|
if (!device)
|
|
|
|
device = "tcp::" DEFAULT_GDBSTUB_PORT;
|
|
|
|
if (gdbserver_start(device) < 0) {
|
|
|
|
monitor_printf(mon, "Could not open gdbserver on device '%s'\n",
|
|
|
|
device);
|
|
|
|
} else if (strcmp(device, "none") == 0) {
|
2009-03-28 18:05:53 +00:00
|
|
|
monitor_printf(mon, "Disabled gdbserver\n");
|
2004-03-31 19:00:16 +00:00
|
|
|
} else {
|
2009-04-05 18:43:41 +00:00
|
|
|
monitor_printf(mon, "Waiting for gdb connection on device '%s'\n",
|
|
|
|
device);
|
2004-03-31 19:00:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_watchdog_action(Monitor *mon, const QDict *qdict)
|
2009-04-25 12:56:19 +00:00
|
|
|
{
|
2009-08-28 18:27:13 +00:00
|
|
|
const char *action = qdict_get_str(qdict, "action");
|
2009-04-25 12:56:19 +00:00
|
|
|
if (select_watchdog_action(action) == -1) {
|
|
|
|
monitor_printf(mon, "Unknown watchdog action '%s'\n", action);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-05 23:01:23 +00:00
|
|
|
static void monitor_printc(Monitor *mon, int c)
|
2004-04-04 12:57:25 +00:00
|
|
|
{
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "'");
|
2004-04-04 12:57:25 +00:00
|
|
|
switch(c) {
|
|
|
|
case '\'':
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "\\'");
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
case '\\':
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "\\\\");
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
case '\n':
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "\\n");
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
case '\r':
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "\\r");
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (c >= 32 && c <= 126) {
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "%c", c);
|
2004-04-04 12:57:25 +00:00
|
|
|
} else {
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "\\x%02x", c);
|
2004-04-04 12:57:25 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "'");
|
2004-04-04 12:57:25 +00:00
|
|
|
}
|
|
|
|
|
2009-03-05 23:01:23 +00:00
|
|
|
static void memory_dump(Monitor *mon, int count, int format, int wsize,
|
2012-10-23 10:30:10 +00:00
|
|
|
hwaddr addr, int is_physical)
|
2004-04-04 12:57:25 +00:00
|
|
|
{
|
2010-01-12 20:27:43 +00:00
|
|
|
int l, line_size, i, max_digits, len;
|
2004-04-04 12:57:25 +00:00
|
|
|
uint8_t buf[16];
|
|
|
|
uint64_t v;
|
2017-01-13 12:12:35 +00:00
|
|
|
CPUState *cs = mon_get_cpu();
|
|
|
|
|
|
|
|
if (!cs && (format == 'i' || !is_physical)) {
|
|
|
|
monitor_printf(mon, "Can not dump without CPU\n");
|
|
|
|
return;
|
|
|
|
}
|
2004-04-04 12:57:25 +00:00
|
|
|
|
|
|
|
if (format == 'i') {
|
2017-09-14 15:38:35 +00:00
|
|
|
monitor_disas(mon, cs, addr, count, is_physical);
|
2004-04-04 12:57:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = wsize * count;
|
|
|
|
if (wsize == 1)
|
|
|
|
line_size = 8;
|
|
|
|
else
|
|
|
|
line_size = 16;
|
|
|
|
max_digits = 0;
|
|
|
|
|
|
|
|
switch(format) {
|
|
|
|
case 'o':
|
2017-06-22 11:04:16 +00:00
|
|
|
max_digits = DIV_ROUND_UP(wsize * 8, 3);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case 'x':
|
|
|
|
max_digits = (wsize * 8) / 4;
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
case 'd':
|
2017-06-22 11:04:16 +00:00
|
|
|
max_digits = DIV_ROUND_UP(wsize * 8 * 10, 33);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
wsize = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (len > 0) {
|
2007-09-24 18:39:04 +00:00
|
|
|
if (is_physical)
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, TARGET_FMT_plx ":", addr);
|
2007-09-24 18:39:04 +00:00
|
|
|
else
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, TARGET_FMT_lx ":", (target_ulong)addr);
|
2004-04-04 12:57:25 +00:00
|
|
|
l = len;
|
|
|
|
if (l > line_size)
|
|
|
|
l = line_size;
|
|
|
|
if (is_physical) {
|
2018-12-14 13:30:49 +00:00
|
|
|
AddressSpace *as = cs ? cs->as : &address_space_memory;
|
|
|
|
MemTxResult r = address_space_read(as, addr,
|
|
|
|
MEMTXATTRS_UNSPECIFIED, buf, l);
|
|
|
|
if (r != MEMTX_OK) {
|
|
|
|
monitor_printf(mon, " Cannot access memory\n");
|
|
|
|
break;
|
|
|
|
}
|
2004-04-04 12:57:25 +00:00
|
|
|
} else {
|
2017-01-13 12:12:35 +00:00
|
|
|
if (cpu_memory_rw_debug(cs, addr, buf, l, 0) < 0) {
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, " Cannot access memory\n");
|
2008-08-18 14:00:20 +00:00
|
|
|
break;
|
|
|
|
}
|
2004-04-04 12:57:25 +00:00
|
|
|
}
|
2007-09-16 21:08:06 +00:00
|
|
|
i = 0;
|
2004-04-04 12:57:25 +00:00
|
|
|
while (i < l) {
|
|
|
|
switch(wsize) {
|
|
|
|
default:
|
|
|
|
case 1:
|
2015-01-20 15:19:32 +00:00
|
|
|
v = ldub_p(buf + i);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2015-01-20 15:19:32 +00:00
|
|
|
v = lduw_p(buf + i);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2015-01-20 15:19:32 +00:00
|
|
|
v = (uint32_t)ldl_p(buf + i);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
case 8:
|
2015-01-20 15:19:32 +00:00
|
|
|
v = ldq_p(buf + i);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, " ");
|
2004-04-04 12:57:25 +00:00
|
|
|
switch(format) {
|
|
|
|
case 'o':
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "%#*" PRIo64, max_digits, v);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
case 'x':
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "0x%0*" PRIx64, max_digits, v);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
case 'u':
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "%*" PRIu64, max_digits, v);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
case 'd':
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "%*" PRId64, max_digits, v);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
case 'c':
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printc(mon, v);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
i += wsize;
|
|
|
|
}
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "\n");
|
2004-04-04 12:57:25 +00:00
|
|
|
addr += l;
|
|
|
|
len -= l;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_memory_dump(Monitor *mon, const QDict *qdict)
|
2004-04-04 12:57:25 +00:00
|
|
|
{
|
2009-08-28 18:27:17 +00:00
|
|
|
int count = qdict_get_int(qdict, "count");
|
|
|
|
int format = qdict_get_int(qdict, "format");
|
|
|
|
int size = qdict_get_int(qdict, "size");
|
|
|
|
target_long addr = qdict_get_int(qdict, "addr");
|
|
|
|
|
2009-03-05 23:01:23 +00:00
|
|
|
memory_dump(mon, count, format, size, addr, 0);
|
2004-04-04 12:57:25 +00:00
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_physical_memory_dump(Monitor *mon, const QDict *qdict)
|
2004-04-04 12:57:25 +00:00
|
|
|
{
|
2009-08-28 18:27:17 +00:00
|
|
|
int count = qdict_get_int(qdict, "count");
|
|
|
|
int format = qdict_get_int(qdict, "format");
|
|
|
|
int size = qdict_get_int(qdict, "size");
|
2012-10-23 10:30:10 +00:00
|
|
|
hwaddr addr = qdict_get_int(qdict, "addr");
|
2009-08-28 18:27:17 +00:00
|
|
|
|
2009-03-05 23:01:23 +00:00
|
|
|
memory_dump(mon, count, format, size, addr, 1);
|
2004-04-04 12:57:25 +00:00
|
|
|
}
|
|
|
|
|
2017-04-20 13:30:58 +00:00
|
|
|
static void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, Error **errp)
|
|
|
|
{
|
|
|
|
MemoryRegionSection mrs = memory_region_find(get_system_memory(),
|
|
|
|
addr, 1);
|
|
|
|
|
|
|
|
if (!mrs.mr) {
|
|
|
|
error_setg(errp, "No memory is mapped at address 0x%" HWADDR_PRIx, addr);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!memory_region_is_ram(mrs.mr) && !memory_region_is_romd(mrs.mr)) {
|
|
|
|
error_setg(errp, "Memory at address 0x%" HWADDR_PRIx "is not RAM", addr);
|
|
|
|
memory_region_unref(mrs.mr);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*p_mr = mrs.mr;
|
|
|
|
return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hmp_gpa2hva(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
hwaddr addr = qdict_get_int(qdict, "addr");
|
|
|
|
Error *local_err = NULL;
|
|
|
|
MemoryRegion *mr = NULL;
|
|
|
|
void *ptr;
|
|
|
|
|
|
|
|
ptr = gpa2hva(&mr, addr, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_report_err(local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "Host virtual address for 0x%" HWADDR_PRIx
|
|
|
|
" (%s) is %p\n",
|
|
|
|
addr, mr->name, ptr);
|
|
|
|
|
|
|
|
memory_region_unref(mr);
|
|
|
|
}
|
|
|
|
|
2019-04-12 15:26:52 +00:00
|
|
|
static void hmp_gva2gpa(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
target_ulong addr = qdict_get_int(qdict, "addr");
|
|
|
|
MemTxAttrs attrs;
|
|
|
|
CPUState *cs = mon_get_cpu();
|
|
|
|
hwaddr gpa;
|
|
|
|
|
|
|
|
if (!cs) {
|
|
|
|
monitor_printf(mon, "No cpu\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-10 18:56:20 +00:00
|
|
|
gpa = cpu_get_phys_page_attrs_debug(cs, addr & TARGET_PAGE_MASK, &attrs);
|
2019-04-12 15:26:52 +00:00
|
|
|
if (gpa == -1) {
|
|
|
|
monitor_printf(mon, "Unmapped\n");
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "gpa: %#" HWADDR_PRIx "\n",
|
|
|
|
gpa + (addr & ~TARGET_PAGE_MASK));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-20 13:30:58 +00:00
|
|
|
#ifdef CONFIG_LINUX
|
|
|
|
static uint64_t vtop(void *ptr, Error **errp)
|
|
|
|
{
|
|
|
|
uint64_t pinfo;
|
|
|
|
uint64_t ret = -1;
|
|
|
|
uintptr_t addr = (uintptr_t) ptr;
|
2019-10-13 02:11:45 +00:00
|
|
|
uintptr_t pagesize = qemu_real_host_page_size;
|
2017-04-20 13:30:58 +00:00
|
|
|
off_t offset = addr / pagesize * sizeof(pinfo);
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = open("/proc/self/pagemap", O_RDONLY);
|
|
|
|
if (fd == -1) {
|
|
|
|
error_setg_errno(errp, errno, "Cannot open /proc/self/pagemap");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Force copy-on-write if necessary. */
|
|
|
|
atomic_add((uint8_t *)ptr, 0);
|
|
|
|
|
|
|
|
if (pread(fd, &pinfo, sizeof(pinfo), offset) != sizeof(pinfo)) {
|
|
|
|
error_setg_errno(errp, errno, "Cannot read pagemap");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if ((pinfo & (1ull << 63)) == 0) {
|
|
|
|
error_setg(errp, "Page not present");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
ret = ((pinfo & 0x007fffffffffffffull) * pagesize) | (addr & (pagesize - 1));
|
|
|
|
|
|
|
|
out:
|
|
|
|
close(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hmp_gpa2hpa(Monitor *mon, const QDict *qdict)
|
|
|
|
{
|
|
|
|
hwaddr addr = qdict_get_int(qdict, "addr");
|
|
|
|
Error *local_err = NULL;
|
|
|
|
MemoryRegion *mr = NULL;
|
|
|
|
void *ptr;
|
|
|
|
uint64_t physaddr;
|
|
|
|
|
|
|
|
ptr = gpa2hva(&mr, addr, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_report_err(local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
physaddr = vtop(ptr, &local_err);
|
|
|
|
if (local_err) {
|
|
|
|
error_report_err(local_err);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "Host physical address for 0x%" HWADDR_PRIx
|
|
|
|
" (%s) is 0x%" PRIx64 "\n",
|
|
|
|
addr, mr->name, (uint64_t) physaddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
memory_region_unref(mr);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-08-28 18:27:17 +00:00
|
|
|
static void do_print(Monitor *mon, const QDict *qdict)
|
2004-04-04 12:57:25 +00:00
|
|
|
{
|
2009-08-28 18:27:17 +00:00
|
|
|
int format = qdict_get_int(qdict, "format");
|
2012-10-23 10:30:10 +00:00
|
|
|
hwaddr val = qdict_get_int(qdict, "val");
|
2009-08-28 18:27:17 +00:00
|
|
|
|
2004-04-04 12:57:25 +00:00
|
|
|
switch(format) {
|
|
|
|
case 'o':
|
2012-10-23 10:30:10 +00:00
|
|
|
monitor_printf(mon, "%#" HWADDR_PRIo, val);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
case 'x':
|
2012-10-23 10:30:10 +00:00
|
|
|
monitor_printf(mon, "%#" HWADDR_PRIx, val);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
case 'u':
|
2012-10-23 10:30:10 +00:00
|
|
|
monitor_printf(mon, "%" HWADDR_PRIu, val);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case 'd':
|
2012-10-23 10:30:10 +00:00
|
|
|
monitor_printf(mon, "%" HWADDR_PRId, val);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
case 'c':
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printc(mon, val);
|
2004-04-04 12:57:25 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "\n");
|
2004-04-04 12:57:25 +00:00
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_sum(Monitor *mon, const QDict *qdict)
|
2005-06-04 20:15:57 +00:00
|
|
|
{
|
|
|
|
uint32_t addr;
|
|
|
|
uint16_t sum;
|
2009-08-28 18:27:14 +00:00
|
|
|
uint32_t start = qdict_get_int(qdict, "start");
|
|
|
|
uint32_t size = qdict_get_int(qdict, "size");
|
2005-06-04 20:15:57 +00:00
|
|
|
|
|
|
|
sum = 0;
|
|
|
|
for(addr = start; addr < (start + size); addr++) {
|
Switch non-CPU callers from ld/st*_phys to address_space_ld/st*
Switch all the uses of ld/st*_phys to address_space_ld/st*,
except for those cases where the address space is the CPU's
(ie cs->as). This was done with the following script which
generates a Coccinelle patch.
A few over-80-columns lines in the result were rewrapped by
hand where Coccinelle failed to do the wrapping automatically,
as well as one location where it didn't put a line-continuation
'\' when wrapping lines on a change made to a match inside
a macro definition.
===begin===
#!/bin/sh -e
# Usage:
# ./ldst-phys.spatch.sh > ldst-phys.spatch
# spatch -sp_file ldst-phys.spatch -dir . | sed -e '/^+/s/\t/ /g' > out.patch
# patch -p1 < out.patch
for FN in ub uw_le uw_be l_le l_be q_le q_be uw l q; do
cat <<EOF
@ cpu_matches_ld_${FN} @
expression E1,E2;
identifier as;
@@
ld${FN}_phys(E1->as,E2)
@ other_matches_ld_${FN} depends on !cpu_matches_ld_${FN} @
expression E1,E2;
@@
-ld${FN}_phys(E1,E2)
+address_space_ld${FN}(E1,E2, MEMTXATTRS_UNSPECIFIED, NULL)
EOF
done
for FN in b w_le w_be l_le l_be q_le q_be w l q; do
cat <<EOF
@ cpu_matches_st_${FN} @
expression E1,E2,E3;
identifier as;
@@
st${FN}_phys(E1->as,E2,E3)
@ other_matches_st_${FN} depends on !cpu_matches_st_${FN} @
expression E1,E2,E3;
@@
-st${FN}_phys(E1,E2,E3)
+address_space_st${FN}(E1,E2,E3, MEMTXATTRS_UNSPECIFIED, NULL)
EOF
done
===endit===
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
2015-04-26 15:49:24 +00:00
|
|
|
uint8_t val = address_space_ldub(&address_space_memory, addr,
|
|
|
|
MEMTXATTRS_UNSPECIFIED, NULL);
|
2005-06-04 20:15:57 +00:00
|
|
|
/* BSD sum algorithm ('sum' Unix command) */
|
|
|
|
sum = (sum >> 1) | (sum << 15);
|
2011-04-10 16:23:39 +00:00
|
|
|
sum += val;
|
2005-06-04 20:15:57 +00:00
|
|
|
}
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "%05d\n", sum);
|
2005-06-04 20:15:57 +00:00
|
|
|
}
|
|
|
|
|
2006-07-14 22:03:35 +00:00
|
|
|
static int mouse_button_state;
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_mouse_move(Monitor *mon, const QDict *qdict)
|
2006-07-14 22:03:35 +00:00
|
|
|
{
|
2013-12-04 14:02:28 +00:00
|
|
|
int dx, dy, dz, button;
|
2009-08-28 18:27:15 +00:00
|
|
|
const char *dx_str = qdict_get_str(qdict, "dx_str");
|
|
|
|
const char *dy_str = qdict_get_str(qdict, "dy_str");
|
|
|
|
const char *dz_str = qdict_get_try_str(qdict, "dz_str");
|
2013-12-04 14:02:28 +00:00
|
|
|
|
2006-07-14 22:03:35 +00:00
|
|
|
dx = strtol(dx_str, NULL, 0);
|
|
|
|
dy = strtol(dy_str, NULL, 0);
|
2013-12-04 14:02:28 +00:00
|
|
|
qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx);
|
|
|
|
qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy);
|
|
|
|
|
|
|
|
if (dz_str) {
|
2006-07-14 22:03:35 +00:00
|
|
|
dz = strtol(dz_str, NULL, 0);
|
2013-12-04 14:02:28 +00:00
|
|
|
if (dz != 0) {
|
2016-01-12 11:14:12 +00:00
|
|
|
button = (dz > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN;
|
2013-12-04 14:02:28 +00:00
|
|
|
qemu_input_queue_btn(NULL, button, true);
|
|
|
|
qemu_input_event_sync();
|
|
|
|
qemu_input_queue_btn(NULL, button, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qemu_input_event_sync();
|
2006-07-14 22:03:35 +00:00
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_mouse_button(Monitor *mon, const QDict *qdict)
|
2006-07-14 22:03:35 +00:00
|
|
|
{
|
qapi: Don't let implicit enum MAX member collide
Now that we guarantee the user doesn't have any enum values
beginning with a single underscore, we can use that for our
own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious
that the sentinel is generated.
This patch was mostly generated by applying a temporary patch:
|diff --git a/scripts/qapi.py b/scripts/qapi.py
|index e6d014b..b862ec9 100644
|--- a/scripts/qapi.py
|+++ b/scripts/qapi.py
|@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = {
| max_index = c_enum_const(name, 'MAX', prefix)
| ret += mcgen('''
| [%(max_index)s] = NULL,
|+// %(max_index)s
| };
| ''',
| max_index=max_index)
then running:
$ cat qapi-{types,event}.c tests/test-qapi-types.c |
sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list
$ git grep -l _MAX | xargs sed -i -f list
The only things not generated are the changes in scripts/qapi.py.
Rejecting enum members named 'MAX' is now useless, and will be dropped
in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
[Rebased to current master, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 08:52:57 +00:00
|
|
|
static uint32_t bmap[INPUT_BUTTON__MAX] = {
|
2013-12-04 14:02:28 +00:00
|
|
|
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
|
|
|
|
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
|
|
|
|
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
|
|
|
|
};
|
2009-08-28 18:27:13 +00:00
|
|
|
int button_state = qdict_get_int(qdict, "button_state");
|
2013-12-04 14:02:28 +00:00
|
|
|
|
|
|
|
if (mouse_button_state == button_state) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
qemu_input_update_buttons(NULL, bmap, mouse_button_state, button_state);
|
|
|
|
qemu_input_event_sync();
|
2006-07-14 22:03:35 +00:00
|
|
|
mouse_button_state = button_state;
|
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_ioport_read(Monitor *mon, const QDict *qdict)
|
2004-06-08 00:55:58 +00:00
|
|
|
{
|
2009-08-28 18:27:18 +00:00
|
|
|
int size = qdict_get_int(qdict, "size");
|
|
|
|
int addr = qdict_get_int(qdict, "addr");
|
|
|
|
int has_index = qdict_haskey(qdict, "index");
|
2004-06-08 00:55:58 +00:00
|
|
|
uint32_t val;
|
|
|
|
int suffix;
|
|
|
|
|
|
|
|
if (has_index) {
|
2009-08-28 18:27:18 +00:00
|
|
|
int index = qdict_get_int(qdict, "index");
|
2009-09-20 16:05:47 +00:00
|
|
|
cpu_outb(addr & IOPORTS_MASK, index & 0xff);
|
2004-06-08 00:55:58 +00:00
|
|
|
addr++;
|
|
|
|
}
|
|
|
|
addr &= 0xffff;
|
|
|
|
|
|
|
|
switch(size) {
|
|
|
|
default:
|
|
|
|
case 1:
|
2009-09-20 16:05:47 +00:00
|
|
|
val = cpu_inb(addr);
|
2004-06-08 00:55:58 +00:00
|
|
|
suffix = 'b';
|
|
|
|
break;
|
|
|
|
case 2:
|
2009-09-20 16:05:47 +00:00
|
|
|
val = cpu_inw(addr);
|
2004-06-08 00:55:58 +00:00
|
|
|
suffix = 'w';
|
|
|
|
break;
|
|
|
|
case 4:
|
2009-09-20 16:05:47 +00:00
|
|
|
val = cpu_inl(addr);
|
2004-06-08 00:55:58 +00:00
|
|
|
suffix = 'l';
|
|
|
|
break;
|
|
|
|
}
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "port%c[0x%04x] = %#0*x\n",
|
|
|
|
suffix, addr, size * 2, val);
|
2004-06-08 00:55:58 +00:00
|
|
|
}
|
2004-06-04 11:06:21 +00:00
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_ioport_write(Monitor *mon, const QDict *qdict)
|
2009-07-14 08:20:11 +00:00
|
|
|
{
|
2009-08-28 18:27:17 +00:00
|
|
|
int size = qdict_get_int(qdict, "size");
|
|
|
|
int addr = qdict_get_int(qdict, "addr");
|
|
|
|
int val = qdict_get_int(qdict, "val");
|
|
|
|
|
2009-07-14 08:20:11 +00:00
|
|
|
addr &= IOPORTS_MASK;
|
|
|
|
|
|
|
|
switch (size) {
|
|
|
|
default:
|
|
|
|
case 1:
|
2009-09-20 16:05:47 +00:00
|
|
|
cpu_outb(addr, val);
|
2009-07-14 08:20:11 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2009-09-20 16:05:47 +00:00
|
|
|
cpu_outw(addr, val);
|
2009-07-14 08:20:11 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2009-09-20 16:05:47 +00:00
|
|
|
cpu_outl(addr, val);
|
2009-07-14 08:20:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_boot_set(Monitor *mon, const QDict *qdict)
|
2008-05-04 20:11:34 +00:00
|
|
|
{
|
2014-12-03 18:20:58 +00:00
|
|
|
Error *local_err = NULL;
|
2009-08-28 18:27:13 +00:00
|
|
|
const char *bootdevice = qdict_get_str(qdict, "bootdevice");
|
2008-05-04 20:11:34 +00:00
|
|
|
|
2014-12-03 18:20:58 +00:00
|
|
|
qemu_boot_set(bootdevice, &local_err);
|
|
|
|
if (local_err) {
|
error: Use error_report_err() instead of monitor_printf()
Both error_report_err() and monitor_printf() print to the same
destination when monitor_printf() is used correctly, i.e. within an
HMP monitor. Elsewhere, monitor_printf() does nothing, while
error_report_err() reports to stderr.
Most changed functions are HMP command handlers. These should only
run within an HMP monitor. The one exception is bdrv_password_cb(),
which should also only run within an HMP monitor.
Four command handlers prefix the error message with the command name:
balloon, migrate_set_capability, migrate_set_parameter, migrate.
Pointless, drop.
Unlike monitor_printf(), error_report_err() uses the error whole
instead of just its message obtained with error_get_pretty(). This
avoids suppressing its hint (see commit 50b7b00). Example:
(qemu) device_add ivshmem,id=666
Parameter 'id' expects an identifier
Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.
Try "help device_add" for more information
The "Identifiers consist of..." line is new with this patch.
Coccinelle semantic patch:
@@
expression M, E;
@@
- monitor_printf(M, "%s\n", error_get_pretty(E));
- error_free(E);
+ error_report_err(E);
@r1@
expression M, E;
format F;
position p;
@@
- monitor_printf(M, "...%@F@\n", error_get_pretty(E));@p
- error_free(E);
+ error_report_err(E);
@script:python@
p << r1.p;
@@
print "%s:%s:%s: prefix dropped" % (p[0].file, p[0].line, p[0].column)
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <1450452927-8346-4-git-send-email-armbru@redhat.com>
2015-12-18 15:35:06 +00:00
|
|
|
error_report_err(local_err);
|
2008-05-04 20:11:34 +00:00
|
|
|
} else {
|
2014-12-03 18:20:58 +00:00
|
|
|
monitor_printf(mon, "boot device list now set to %s\n", bootdevice);
|
2008-05-04 20:11:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-06 13:18:24 +00:00
|
|
|
static void hmp_info_mtree(Monitor *mon, const QDict *qdict)
|
2011-09-11 20:22:05 +00:00
|
|
|
{
|
2017-01-16 08:40:05 +00:00
|
|
|
bool flatview = qdict_get_try_bool(qdict, "flatview", false);
|
2017-09-21 08:51:06 +00:00
|
|
|
bool dispatch_tree = qdict_get_try_bool(qdict, "dispatch_tree", false);
|
2018-06-04 03:25:11 +00:00
|
|
|
bool owner = qdict_get_try_bool(qdict, "owner", false);
|
2017-01-16 08:40:05 +00:00
|
|
|
|
2019-04-17 19:17:56 +00:00
|
|
|
mtree_info(flatview, dispatch_tree, owner);
|
2011-09-11 20:22:05 +00:00
|
|
|
}
|
|
|
|
|
2006-02-08 22:40:15 +00:00
|
|
|
#ifdef CONFIG_PROFILER
|
|
|
|
|
2009-09-30 12:09:52 +00:00
|
|
|
int64_t dev_time;
|
|
|
|
|
2015-02-06 13:18:24 +00:00
|
|
|
static void hmp_info_profile(Monitor *mon, const QDict *qdict)
|
2006-02-08 22:40:15 +00:00
|
|
|
{
|
2018-10-10 14:48:53 +00:00
|
|
|
static int64_t last_cpu_exec_time;
|
|
|
|
int64_t cpu_exec_time;
|
|
|
|
int64_t delta;
|
|
|
|
|
|
|
|
cpu_exec_time = tcg_cpu_exec_time();
|
|
|
|
delta = cpu_exec_time - last_cpu_exec_time;
|
|
|
|
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "async time %" PRId64 " (%0.3f)\n",
|
2016-03-21 16:02:30 +00:00
|
|
|
dev_time, dev_time / (double)NANOSECONDS_PER_SECOND);
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "qemu time %" PRId64 " (%0.3f)\n",
|
2018-10-10 14:48:53 +00:00
|
|
|
delta, delta / (double)NANOSECONDS_PER_SECOND);
|
|
|
|
last_cpu_exec_time = cpu_exec_time;
|
2006-02-08 22:40:15 +00:00
|
|
|
dev_time = 0;
|
|
|
|
}
|
|
|
|
#else
|
2015-02-06 13:18:24 +00:00
|
|
|
static void hmp_info_profile(Monitor *mon, const QDict *qdict)
|
2006-02-08 22:40:15 +00:00
|
|
|
{
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "Internal profiler not compiled\n");
|
2006-02-08 22:40:15 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-07-16 18:57:03 +00:00
|
|
|
/* Capture support */
|
2009-09-12 07:36:22 +00:00
|
|
|
static QLIST_HEAD (capture_list_head, CaptureState) capture_head;
|
2006-07-16 18:57:03 +00:00
|
|
|
|
2015-02-06 13:18:24 +00:00
|
|
|
static void hmp_info_capture(Monitor *mon, const QDict *qdict)
|
2006-07-16 18:57:03 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
CaptureState *s;
|
|
|
|
|
|
|
|
for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) {
|
2009-03-05 23:01:23 +00:00
|
|
|
monitor_printf(mon, "[%d]: ", i);
|
2006-07-16 18:57:03 +00:00
|
|
|
s->ops.info (s->opaque);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_stopcapture(Monitor *mon, const QDict *qdict)
|
2006-07-16 18:57:03 +00:00
|
|
|
{
|
|
|
|
int i;
|
2009-08-28 18:27:13 +00:00
|
|
|
int n = qdict_get_int(qdict, "n");
|
2006-07-16 18:57:03 +00:00
|
|
|
CaptureState *s;
|
|
|
|
|
|
|
|
for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) {
|
|
|
|
if (i == n) {
|
|
|
|
s->ops.destroy (s->opaque);
|
2009-09-12 07:36:22 +00:00
|
|
|
QLIST_REMOVE (s, entries);
|
2011-08-21 03:09:37 +00:00
|
|
|
g_free (s);
|
2006-07-16 18:57:03 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_wavcapture(Monitor *mon, const QDict *qdict)
|
2009-08-28 18:27:19 +00:00
|
|
|
{
|
|
|
|
const char *path = qdict_get_str(qdict, "path");
|
2019-08-18 23:06:48 +00:00
|
|
|
int freq = qdict_get_try_int(qdict, "freq", 44100);
|
|
|
|
int bits = qdict_get_try_int(qdict, "bits", 16);
|
|
|
|
int nchannels = qdict_get_try_int(qdict, "nchannels", 2);
|
|
|
|
const char *audiodev = qdict_get_str(qdict, "audiodev");
|
2006-07-16 18:57:03 +00:00
|
|
|
CaptureState *s;
|
2019-08-18 23:06:48 +00:00
|
|
|
AudioState *as = audio_state_by_name(audiodev);
|
2006-07-16 18:57:03 +00:00
|
|
|
|
2019-08-18 23:06:48 +00:00
|
|
|
if (!as) {
|
|
|
|
monitor_printf(mon, "Audiodev '%s' not found\n", audiodev);
|
|
|
|
return;
|
|
|
|
}
|
2006-07-16 18:57:03 +00:00
|
|
|
|
2019-08-18 23:06:48 +00:00
|
|
|
s = g_malloc0 (sizeof (*s));
|
2006-07-16 18:57:03 +00:00
|
|
|
|
2019-08-18 23:06:48 +00:00
|
|
|
if (wav_start_capture(as, s, path, freq, bits, nchannels)) {
|
2011-01-21 10:53:55 +00:00
|
|
|
monitor_printf(mon, "Failed to add wave capture\n");
|
2011-08-21 03:09:37 +00:00
|
|
|
g_free (s);
|
2011-01-21 10:53:55 +00:00
|
|
|
return;
|
2006-07-16 18:57:03 +00:00
|
|
|
}
|
2009-09-12 07:36:22 +00:00
|
|
|
QLIST_INSERT_HEAD (&capture_head, s, entries);
|
2006-07-16 18:57:03 +00:00
|
|
|
}
|
|
|
|
|
2016-02-18 18:40:24 +00:00
|
|
|
static QAuthZList *find_auth(Monitor *mon, const char *name)
|
Support ACLs for controlling VNC access ("Daniel P. Berrange")
This patch introduces a generic internal API for access control lists
to be used by network servers in QEMU. It adds support for checking
these ACL in the VNC server, in two places. The first ACL is for the
SASL authentication mechanism, checking the SASL username. This ACL
is called 'vnc.username'. The second is for the TLS authentication
mechanism, when x509 client certificates are turned on, checking against
the Distinguished Name of the client. This ACL is called 'vnc.x509dname'
The internal API provides for an ACL with the following characteristics
- A unique name, eg vnc.username, and vnc.x509dname.
- A default policy, allow or deny
- An ordered series of match rules, with allow or deny policy
If none of the match rules apply, then the default policy is
used.
There is a monitor API to manipulate the ACLs, which I'll describe via
examples
(qemu) acl show vnc.username
policy: allow
(qemu) acl policy vnc.username denya
acl: policy set to 'deny'
(qemu) acl allow vnc.username fred
acl: added rule at position 1
(qemu) acl allow vnc.username bob
acl: added rule at position 2
(qemu) acl allow vnc.username joe 1
acl: added rule at position 1
(qemu) acl show vnc.username
policy: deny
0: allow fred
1: allow joe
2: allow bob
(qemu) acl show vnc.x509dname
policy: allow
(qemu) acl policy vnc.x509dname deny
acl: policy set to 'deny'
(qemu) acl allow vnc.x509dname C=GB,O=ACME,L=London,CN=*
acl: added rule at position 1
(qemu) acl allow vnc.x509dname C=GB,O=ACME,L=Boston,CN=bob
acl: added rule at position 2
(qemu) acl show vnc.x509dname
policy: deny
0: allow C=GB,O=ACME,L=London,CN=*
1: allow C=GB,O=ACME,L=Boston,CN=bob
By default the VNC server will not use any ACLs, allowing access to
the server if the user successfully authenticates. To enable use of
ACLs to restrict user access, the ',acl' flag should be given when
starting QEMU. The initial ACL activated will be a 'deny all' policy
and should be customized using monitor commands.
eg enable SASL auth and ACLs
qemu .... -vnc localhost:1,sasl,acl
The next patch will provide a way to load a pre-defined ACL when
starting up
Makefile | 6 +
b/acl.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
b/acl.h | 74 ++++++++++++++++++++++
configure | 18 +++++
monitor.c | 95 ++++++++++++++++++++++++++++
qemu-doc.texi | 49 ++++++++++++++
vnc-auth-sasl.c | 16 +++-
vnc-auth-sasl.h | 7 ++
vnc-tls.c | 19 +++++
vnc-tls.h | 3
vnc.c | 21 ++++++
vnc.h | 3
12 files changed, 491 insertions(+), 5 deletions(-)
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6726 c046a42c-6fe2-441c-8c8c-71466251a162
2009-03-06 20:27:37 +00:00
|
|
|
{
|
2016-02-18 18:40:24 +00:00
|
|
|
Object *obj;
|
|
|
|
Object *container;
|
Support ACLs for controlling VNC access ("Daniel P. Berrange")
This patch introduces a generic internal API for access control lists
to be used by network servers in QEMU. It adds support for checking
these ACL in the VNC server, in two places. The first ACL is for the
SASL authentication mechanism, checking the SASL username. This ACL
is called 'vnc.username'. The second is for the TLS authentication
mechanism, when x509 client certificates are turned on, checking against
the Distinguished Name of the client. This ACL is called 'vnc.x509dname'
The internal API provides for an ACL with the following characteristics
- A unique name, eg vnc.username, and vnc.x509dname.
- A default policy, allow or deny
- An ordered series of match rules, with allow or deny policy
If none of the match rules apply, then the default policy is
used.
There is a monitor API to manipulate the ACLs, which I'll describe via
examples
(qemu) acl show vnc.username
policy: allow
(qemu) acl policy vnc.username denya
acl: policy set to 'deny'
(qemu) acl allow vnc.username fred
acl: added rule at position 1
(qemu) acl allow vnc.username bob
acl: added rule at position 2
(qemu) acl allow vnc.username joe 1
acl: added rule at position 1
(qemu) acl show vnc.username
policy: deny
0: allow fred
1: allow joe
2: allow bob
(qemu) acl show vnc.x509dname
policy: allow
(qemu) acl policy vnc.x509dname deny
acl: policy set to 'deny'
(qemu) acl allow vnc.x509dname C=GB,O=ACME,L=London,CN=*
acl: added rule at position 1
(qemu) acl allow vnc.x509dname C=GB,O=ACME,L=Boston,CN=bob
acl: added rule at position 2
(qemu) acl show vnc.x509dname
policy: deny
0: allow C=GB,O=ACME,L=London,CN=*
1: allow C=GB,O=ACME,L=Boston,CN=bob
By default the VNC server will not use any ACLs, allowing access to
the server if the user successfully authenticates. To enable use of
ACLs to restrict user access, the ',acl' flag should be given when
starting QEMU. The initial ACL activated will be a 'deny all' policy
and should be customized using monitor commands.
eg enable SASL auth and ACLs
qemu .... -vnc localhost:1,sasl,acl
The next patch will provide a way to load a pre-defined ACL when
starting up
Makefile | 6 +
b/acl.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
b/acl.h | 74 ++++++++++++++++++++++
configure | 18 +++++
monitor.c | 95 ++++++++++++++++++++++++++++
qemu-doc.texi | 49 ++++++++++++++
vnc-auth-sasl.c | 16 +++-
vnc-auth-sasl.h | 7 ++
vnc-tls.c | 19 +++++
vnc-tls.h | 3
vnc.c | 21 ++++++
vnc.h | 3
12 files changed, 491 insertions(+), 5 deletions(-)
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6726 c046a42c-6fe2-441c-8c8c-71466251a162
2009-03-06 20:27:37 +00:00
|
|
|
|
2016-02-18 18:40:24 +00:00
|
|
|
container = object_get_objects_root();
|
|
|
|
obj = object_resolve_path_component(container, name);
|
|
|
|
if (!obj) {
|
2009-06-25 06:22:08 +00:00
|
|
|
monitor_printf(mon, "acl: unknown list '%s'\n", name);
|
2016-02-18 18:40:24 +00:00
|
|
|
return NULL;
|
Support ACLs for controlling VNC access ("Daniel P. Berrange")
This patch introduces a generic internal API for access control lists
to be used by network servers in QEMU. It adds support for checking
these ACL in the VNC server, in two places. The first ACL is for the
SASL authentication mechanism, checking the SASL username. This ACL
is called 'vnc.username'. The second is for the TLS authentication
mechanism, when x509 client certificates are turned on, checking against
the Distinguished Name of the client. This ACL is called 'vnc.x509dname'
The internal API provides for an ACL with the following characteristics
- A unique name, eg vnc.username, and vnc.x509dname.
- A default policy, allow or deny
- An ordered series of match rules, with allow or deny policy
If none of the match rules apply, then the default policy is
used.
There is a monitor API to manipulate the ACLs, which I'll describe via
examples
(qemu) acl show vnc.username
policy: allow
(qemu) acl policy vnc.username denya
acl: policy set to 'deny'
(qemu) acl allow vnc.username fred
acl: added rule at position 1
(qemu) acl allow vnc.username bob
acl: added rule at position 2
(qemu) acl allow vnc.username joe 1
acl: added rule at position 1
(qemu) acl show vnc.username
policy: deny
0: allow fred
1: allow joe
2: allow bob
(qemu) acl show vnc.x509dname
policy: allow
(qemu) acl policy vnc.x509dname deny
acl: policy set to 'deny'
(qemu) acl allow vnc.x509dname C=GB,O=ACME,L=London,CN=*
acl: added rule at position 1
(qemu) acl allow vnc.x509dname C=GB,O=ACME,L=Boston,CN=bob
acl: added rule at position 2
(qemu) acl show vnc.x509dname
policy: deny
0: allow C=GB,O=ACME,L=London,CN=*
1: allow C=GB,O=ACME,L=Boston,CN=bob
By default the VNC server will not use any ACLs, allowing access to
the server if the user successfully authenticates. To enable use of
ACLs to restrict user access, the ',acl' flag should be given when
starting QEMU. The initial ACL activated will be a 'deny all' policy
and should be customized using monitor commands.
eg enable SASL auth and ACLs
qemu .... -vnc localhost:1,sasl,acl
The next patch will provide a way to load a pre-defined ACL when
starting up
Makefile | 6 +
b/acl.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
b/acl.h | 74 ++++++++++++++++++++++
configure | 18 +++++
monitor.c | 95 ++++++++++++++++++++++++++++
qemu-doc.texi | 49 ++++++++++++++
vnc-auth-sasl.c | 16 +++-
vnc-auth-sasl.h | 7 ++
vnc-tls.c | 19 +++++
vnc-tls.h | 3
vnc.c | 21 ++++++
vnc.h | 3
12 files changed, 491 insertions(+), 5 deletions(-)
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6726 c046a42c-6fe2-441c-8c8c-71466251a162
2009-03-06 20:27:37 +00:00
|
|
|
}
|
2016-02-18 18:40:24 +00:00
|
|
|
|
|
|
|
return QAUTHZ_LIST(obj);
|
2009-06-25 06:22:08 +00:00
|
|
|
}
|
|
|
|
|
2019-02-27 14:57:55 +00:00
|
|
|
static bool warn_acl;
|
|
|
|
static void hmp_warn_acl(void)
|
|
|
|
{
|
|
|
|
if (warn_acl) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
error_report("The acl_show, acl_reset, acl_policy, acl_add, acl_remove "
|
|
|
|
"commands are deprecated with no replacement. Authorization "
|
|
|
|
"for VNC should be performed using the pluggable QAuthZ "
|
|
|
|
"objects");
|
|
|
|
warn_acl = true;
|
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_acl_show(Monitor *mon, const QDict *qdict)
|
2009-06-25 06:22:08 +00:00
|
|
|
{
|
2009-08-28 18:27:13 +00:00
|
|
|
const char *aclname = qdict_get_str(qdict, "aclname");
|
2016-02-18 18:40:24 +00:00
|
|
|
QAuthZList *auth = find_auth(mon, aclname);
|
|
|
|
QAuthZListRuleList *rules;
|
|
|
|
size_t i = 0;
|
|
|
|
|
2019-02-27 14:57:55 +00:00
|
|
|
hmp_warn_acl();
|
|
|
|
|
2016-02-18 18:40:24 +00:00
|
|
|
if (!auth) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_printf(mon, "policy: %s\n",
|
|
|
|
QAuthZListPolicy_str(auth->policy));
|
|
|
|
|
|
|
|
rules = auth->rules;
|
|
|
|
while (rules) {
|
|
|
|
QAuthZListRule *rule = rules->value;
|
|
|
|
i++;
|
|
|
|
monitor_printf(mon, "%zu: %s %s\n", i,
|
|
|
|
QAuthZListPolicy_str(rule->policy),
|
|
|
|
rule->match);
|
|
|
|
rules = rules->next;
|
2009-06-25 06:22:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_acl_reset(Monitor *mon, const QDict *qdict)
|
2009-06-25 06:22:08 +00:00
|
|
|
{
|
2009-08-28 18:27:13 +00:00
|
|
|
const char *aclname = qdict_get_str(qdict, "aclname");
|
2016-02-18 18:40:24 +00:00
|
|
|
QAuthZList *auth = find_auth(mon, aclname);
|
2009-06-25 06:22:08 +00:00
|
|
|
|
2019-02-27 14:57:55 +00:00
|
|
|
hmp_warn_acl();
|
|
|
|
|
2016-02-18 18:40:24 +00:00
|
|
|
if (!auth) {
|
|
|
|
return;
|
2009-06-25 06:22:08 +00:00
|
|
|
}
|
2016-02-18 18:40:24 +00:00
|
|
|
|
|
|
|
auth->policy = QAUTHZ_LIST_POLICY_DENY;
|
|
|
|
qapi_free_QAuthZListRuleList(auth->rules);
|
|
|
|
auth->rules = NULL;
|
|
|
|
monitor_printf(mon, "acl: removed all rules\n");
|
2009-06-25 06:22:08 +00:00
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_acl_policy(Monitor *mon, const QDict *qdict)
|
2009-06-25 06:22:08 +00:00
|
|
|
{
|
2009-08-28 18:27:14 +00:00
|
|
|
const char *aclname = qdict_get_str(qdict, "aclname");
|
|
|
|
const char *policy = qdict_get_str(qdict, "policy");
|
2016-02-18 18:40:24 +00:00
|
|
|
QAuthZList *auth = find_auth(mon, aclname);
|
|
|
|
int val;
|
|
|
|
Error *err = NULL;
|
2009-03-06 20:27:40 +00:00
|
|
|
|
2019-02-27 14:57:55 +00:00
|
|
|
hmp_warn_acl();
|
|
|
|
|
2016-02-18 18:40:24 +00:00
|
|
|
if (!auth) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
val = qapi_enum_parse(&QAuthZListPolicy_lookup,
|
|
|
|
policy,
|
|
|
|
QAUTHZ_LIST_POLICY_DENY,
|
|
|
|
&err);
|
|
|
|
if (err) {
|
|
|
|
error_free(err);
|
|
|
|
monitor_printf(mon, "acl: unknown policy '%s', "
|
|
|
|
"expected 'deny' or 'allow'\n", policy);
|
|
|
|
} else {
|
|
|
|
auth->policy = val;
|
|
|
|
if (auth->policy == QAUTHZ_LIST_POLICY_ALLOW) {
|
2009-03-06 20:27:40 +00:00
|
|
|
monitor_printf(mon, "acl: policy set to 'allow'\n");
|
|
|
|
} else {
|
2016-02-18 18:40:24 +00:00
|
|
|
monitor_printf(mon, "acl: policy set to 'deny'\n");
|
2009-03-06 20:27:40 +00:00
|
|
|
}
|
2009-06-25 06:22:08 +00:00
|
|
|
}
|
|
|
|
}
|
2009-03-06 20:27:40 +00:00
|
|
|
|
2016-02-18 18:40:24 +00:00
|
|
|
static QAuthZListFormat hmp_acl_get_format(const char *match)
|
|
|
|
{
|
|
|
|
if (strchr(match, '*')) {
|
|
|
|
return QAUTHZ_LIST_FORMAT_GLOB;
|
|
|
|
} else {
|
|
|
|
return QAUTHZ_LIST_FORMAT_EXACT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_acl_add(Monitor *mon, const QDict *qdict)
|
2009-06-25 06:22:08 +00:00
|
|
|
{
|
2009-08-28 18:27:17 +00:00
|
|
|
const char *aclname = qdict_get_str(qdict, "aclname");
|
|
|
|
const char *match = qdict_get_str(qdict, "match");
|
2016-02-18 18:40:24 +00:00
|
|
|
const char *policystr = qdict_get_str(qdict, "policy");
|
2009-08-28 18:27:17 +00:00
|
|
|
int has_index = qdict_haskey(qdict, "index");
|
|
|
|
int index = qdict_get_try_int(qdict, "index", -1);
|
2016-02-18 18:40:24 +00:00
|
|
|
QAuthZList *auth = find_auth(mon, aclname);
|
|
|
|
Error *err = NULL;
|
|
|
|
QAuthZListPolicy policy;
|
|
|
|
QAuthZListFormat format;
|
|
|
|
size_t i = 0;
|
|
|
|
|
2019-02-27 14:57:55 +00:00
|
|
|
hmp_warn_acl();
|
|
|
|
|
2016-02-18 18:40:24 +00:00
|
|
|
if (!auth) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
policy = qapi_enum_parse(&QAuthZListPolicy_lookup,
|
|
|
|
policystr,
|
|
|
|
QAUTHZ_LIST_POLICY_DENY,
|
|
|
|
&err);
|
|
|
|
if (err) {
|
|
|
|
error_free(err);
|
|
|
|
monitor_printf(mon, "acl: unknown policy '%s', "
|
|
|
|
"expected 'deny' or 'allow'\n", policystr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
format = hmp_acl_get_format(match);
|
|
|
|
|
|
|
|
if (has_index && index == 0) {
|
|
|
|
monitor_printf(mon, "acl: unable to add acl entry\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (has_index) {
|
|
|
|
i = qauthz_list_insert_rule(auth, match, policy,
|
|
|
|
format, index - 1, &err);
|
|
|
|
} else {
|
|
|
|
i = qauthz_list_append_rule(auth, match, policy,
|
|
|
|
format, &err);
|
|
|
|
}
|
|
|
|
if (err) {
|
|
|
|
monitor_printf(mon, "acl: unable to add rule: %s",
|
|
|
|
error_get_pretty(err));
|
|
|
|
error_free(err);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "acl: added rule at position %zu\n", i + 1);
|
2009-06-25 06:22:08 +00:00
|
|
|
}
|
|
|
|
}
|
2009-03-06 20:27:40 +00:00
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 12:55:43 +00:00
|
|
|
static void hmp_acl_remove(Monitor *mon, const QDict *qdict)
|
2009-06-25 06:22:08 +00:00
|
|
|
{
|
2009-08-28 18:27:14 +00:00
|
|
|
const char *aclname = qdict_get_str(qdict, "aclname");
|
|
|
|
const char *match = qdict_get_str(qdict, "match");
|
2016-02-18 18:40:24 +00:00
|
|
|
QAuthZList *auth = find_auth(mon, aclname);
|
|
|
|
ssize_t i = 0;
|
2009-03-06 20:27:40 +00:00
|
|
|
|
2019-02-27 14:57:55 +00:00
|
|
|
hmp_warn_acl();
|
|
|
|
|
2016-02-18 18:40:24 +00:00
|
|
|
if (!auth) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = qauthz_list_delete_rule(auth, match);
|
|
|
|
if (i >= 0) {
|
|
|
|
monitor_printf(mon, "acl: removed rule at position %zu\n", i + 1);
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "acl: no matching acl entry\n");
|
Support ACLs for controlling VNC access ("Daniel P. Berrange")
This patch introduces a generic internal API for access control lists
to be used by network servers in QEMU. It adds support for checking
these ACL in the VNC server, in two places. The first ACL is for the
SASL authentication mechanism, checking the SASL username. This ACL
is called 'vnc.username'. The second is for the TLS authentication
mechanism, when x509 client certificates are turned on, checking against
the Distinguished Name of the client. This ACL is called 'vnc.x509dname'
The internal API provides for an ACL with the following characteristics
- A unique name, eg vnc.username, and vnc.x509dname.
- A default policy, allow or deny
- An ordered series of match rules, with allow or deny policy
If none of the match rules apply, then the default policy is
used.
There is a monitor API to manipulate the ACLs, which I'll describe via
examples
(qemu) acl show vnc.username
policy: allow
(qemu) acl policy vnc.username denya
acl: policy set to 'deny'
(qemu) acl allow vnc.username fred
acl: added rule at position 1
(qemu) acl allow vnc.username bob
acl: added rule at position 2
(qemu) acl allow vnc.username joe 1
acl: added rule at position 1
(qemu) acl show vnc.username
policy: deny
0: allow fred
1: allow joe
2: allow bob
(qemu) acl show vnc.x509dname
policy: allow
(qemu) acl policy vnc.x509dname deny
acl: policy set to 'deny'
(qemu) acl allow vnc.x509dname C=GB,O=ACME,L=London,CN=*
acl: added rule at position 1
(qemu) acl allow vnc.x509dname C=GB,O=ACME,L=Boston,CN=bob
acl: added rule at position 2
(qemu) acl show vnc.x509dname
policy: deny
0: allow C=GB,O=ACME,L=London,CN=*
1: allow C=GB,O=ACME,L=Boston,CN=bob
By default the VNC server will not use any ACLs, allowing access to
the server if the user successfully authenticates. To enable use of
ACLs to restrict user access, the ',acl' flag should be given when
starting QEMU. The initial ACL activated will be a 'deny all' policy
and should be customized using monitor commands.
eg enable SASL auth and ACLs
qemu .... -vnc localhost:1,sasl,acl
The next patch will provide a way to load a pre-defined ACL when
starting up
Makefile | 6 +
b/acl.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
b/acl.h | 74 ++++++++++++++++++++++
configure | 18 +++++
monitor.c | 95 ++++++++++++++++++++++++++++
qemu-doc.texi | 49 ++++++++++++++
vnc-auth-sasl.c | 16 +++-
vnc-auth-sasl.h | 7 ++
vnc-tls.c | 19 +++++
vnc-tls.h | 3
vnc.c | 21 ++++++
vnc.h | 3
12 files changed, 491 insertions(+), 5 deletions(-)
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6726 c046a42c-6fe2-441c-8c8c-71466251a162
2009-03-06 20:27:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-22 18:36:09 +00:00
|
|
|
void qmp_getfd(const char *fdname, Error **errp)
|
2009-07-22 08:11:40 +00:00
|
|
|
{
|
2009-10-01 21:12:16 +00:00
|
|
|
mon_fd_t *monfd;
|
2018-06-08 03:55:06 +00:00
|
|
|
int fd, tmp_fd;
|
2009-07-22 08:11:40 +00:00
|
|
|
|
2016-10-22 09:52:55 +00:00
|
|
|
fd = qemu_chr_fe_get_msgfd(&cur_mon->chr);
|
2009-07-22 08:11:40 +00:00
|
|
|
if (fd == -1) {
|
2015-03-17 10:54:50 +00:00
|
|
|
error_setg(errp, QERR_FD_NOT_SUPPLIED);
|
2012-06-22 18:36:09 +00:00
|
|
|
return;
|
2009-07-22 08:11:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (qemu_isdigit(fdname[0])) {
|
2014-04-24 11:58:18 +00:00
|
|
|
close(fd);
|
2015-03-17 10:54:50 +00:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdname",
|
|
|
|
"a name not starting with a digit");
|
2012-06-22 18:36:09 +00:00
|
|
|
return;
|
2009-07-22 08:11:40 +00:00
|
|
|
}
|
|
|
|
|
2018-06-08 03:55:06 +00:00
|
|
|
qemu_mutex_lock(&cur_mon->mon_lock);
|
2012-06-22 18:36:09 +00:00
|
|
|
QLIST_FOREACH(monfd, &cur_mon->fds, next) {
|
2009-07-22 08:11:40 +00:00
|
|
|
if (strcmp(monfd->name, fdname) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-06-08 03:55:06 +00:00
|
|
|
tmp_fd = monfd->fd;
|
2009-07-22 08:11:40 +00:00
|
|
|
monfd->fd = fd;
|
2018-06-08 03:55:06 +00:00
|
|
|
qemu_mutex_unlock(&cur_mon->mon_lock);
|
2018-07-03 08:53:57 +00:00
|
|
|
/* Make sure close() is outside critical section */
|
2018-06-08 03:55:06 +00:00
|
|
|
close(tmp_fd);
|
2012-06-22 18:36:09 +00:00
|
|
|
return;
|
2009-07-22 08:11:40 +00:00
|
|
|
}
|
|
|
|
|
2011-08-21 03:09:37 +00:00
|
|
|
monfd = g_malloc0(sizeof(mon_fd_t));
|
|
|
|
monfd->name = g_strdup(fdname);
|
2009-07-22 08:11:40 +00:00
|
|
|
monfd->fd = fd;
|
|
|
|
|
2012-06-22 18:36:09 +00:00
|
|
|
QLIST_INSERT_HEAD(&cur_mon->fds, monfd, next);
|
2018-06-08 03:55:06 +00:00
|
|
|
qemu_mutex_unlock(&cur_mon->mon_lock);
|
2009-07-22 08:11:40 +00:00
|
|
|
}
|
|
|
|
|
2012-06-22 18:36:09 +00:00
|
|
|
void qmp_closefd(const char *fdname, Error **errp)
|
2009-07-22 08:11:40 +00:00
|
|
|
{
|
2009-10-01 21:12:16 +00:00
|
|
|
mon_fd_t *monfd;
|
2018-06-08 03:55:06 +00:00
|
|
|
int tmp_fd;
|
2009-07-22 08:11:40 +00:00
|
|
|
|
2018-06-08 03:55:06 +00:00
|
|
|
qemu_mutex_lock(&cur_mon->mon_lock);
|
2012-06-22 18:36:09 +00:00
|
|
|
QLIST_FOREACH(monfd, &cur_mon->fds, next) {
|
2009-07-22 08:11:40 +00:00
|
|
|
if (strcmp(monfd->name, fdname) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-09-12 07:36:22 +00:00
|
|
|
QLIST_REMOVE(monfd, next);
|
2018-06-08 03:55:06 +00:00
|
|
|
tmp_fd = monfd->fd;
|
2011-08-21 03:09:37 +00:00
|
|
|
g_free(monfd->name);
|
|
|
|
g_free(monfd);
|
2018-06-08 03:55:06 +00:00
|
|
|
qemu_mutex_unlock(&cur_mon->mon_lock);
|
2018-07-03 08:53:57 +00:00
|
|
|
/* Make sure close() is outside critical section */
|
2018-06-08 03:55:06 +00:00
|
|
|
close(tmp_fd);
|
2012-06-22 18:36:09 +00:00
|
|
|
return;
|
2009-07-22 08:11:40 +00:00
|
|
|
}
|
|
|
|
|
2018-06-08 03:55:06 +00:00
|
|
|
qemu_mutex_unlock(&cur_mon->mon_lock);
|
2015-03-17 10:54:50 +00:00
|
|
|
error_setg(errp, QERR_FD_NOT_FOUND, fdname);
|
2009-07-22 08:11:40 +00:00
|
|
|
}
|
|
|
|
|
2012-09-20 14:50:32 +00:00
|
|
|
int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
|
2009-07-22 08:11:41 +00:00
|
|
|
{
|
2009-10-01 21:12:16 +00:00
|
|
|
mon_fd_t *monfd;
|
2009-07-22 08:11:41 +00:00
|
|
|
|
2018-06-08 03:55:06 +00:00
|
|
|
qemu_mutex_lock(&mon->mon_lock);
|
2009-09-12 07:36:22 +00:00
|
|
|
QLIST_FOREACH(monfd, &mon->fds, next) {
|
2009-07-22 08:11:41 +00:00
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (strcmp(monfd->name, fdname) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = monfd->fd;
|
|
|
|
|
|
|
|
/* caller takes ownership of fd */
|
2009-09-12 07:36:22 +00:00
|
|
|
QLIST_REMOVE(monfd, next);
|
2011-08-21 03:09:37 +00:00
|
|
|
g_free(monfd->name);
|
|
|
|
g_free(monfd);
|
2018-06-08 03:55:06 +00:00
|
|
|
qemu_mutex_unlock(&mon->mon_lock);
|
2009-07-22 08:11:41 +00:00
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2018-06-08 03:55:06 +00:00
|
|
|
qemu_mutex_unlock(&mon->mon_lock);
|
2012-09-20 14:50:32 +00:00
|
|
|
error_setg(errp, "File descriptor named '%s' has not been found", fdname);
|
2009-07-22 08:11:41 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-08-14 20:43:43 +00:00
|
|
|
static void monitor_fdset_cleanup(MonFdset *mon_fdset)
|
|
|
|
{
|
|
|
|
MonFdsetFd *mon_fdset_fd;
|
|
|
|
MonFdsetFd *mon_fdset_fd_next;
|
|
|
|
|
|
|
|
QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next, mon_fdset_fd_next) {
|
2012-10-18 19:19:33 +00:00
|
|
|
if ((mon_fdset_fd->removed ||
|
|
|
|
(QLIST_EMPTY(&mon_fdset->dup_fds) && mon_refcount == 0)) &&
|
|
|
|
runstate_is_running()) {
|
2012-08-14 20:43:43 +00:00
|
|
|
close(mon_fdset_fd->fd);
|
|
|
|
g_free(mon_fdset_fd->opaque);
|
|
|
|
QLIST_REMOVE(mon_fdset_fd, next);
|
|
|
|
g_free(mon_fdset_fd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-14 20:43:47 +00:00
|
|
|
if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) {
|
2012-08-14 20:43:43 +00:00
|
|
|
QLIST_REMOVE(mon_fdset, next);
|
|
|
|
g_free(mon_fdset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-13 15:34:00 +00:00
|
|
|
void monitor_fdsets_cleanup(void)
|
2012-08-14 20:43:48 +00:00
|
|
|
{
|
|
|
|
MonFdset *mon_fdset;
|
|
|
|
MonFdset *mon_fdset_next;
|
|
|
|
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_lock(&mon_fdsets_lock);
|
2012-08-14 20:43:48 +00:00
|
|
|
QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) {
|
|
|
|
monitor_fdset_cleanup(mon_fdset);
|
|
|
|
}
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-08-14 20:43:48 +00:00
|
|
|
}
|
|
|
|
|
2012-08-14 20:43:43 +00:00
|
|
|
AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, bool has_opaque,
|
|
|
|
const char *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
Monitor *mon = cur_mon;
|
|
|
|
AddfdInfo *fdinfo;
|
|
|
|
|
2016-10-22 09:52:55 +00:00
|
|
|
fd = qemu_chr_fe_get_msgfd(&mon->chr);
|
2012-08-14 20:43:43 +00:00
|
|
|
if (fd == -1) {
|
2015-03-17 10:54:50 +00:00
|
|
|
error_setg(errp, QERR_FD_NOT_SUPPLIED);
|
2012-08-14 20:43:43 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-10-18 19:19:32 +00:00
|
|
|
fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id,
|
|
|
|
has_opaque, opaque, errp);
|
|
|
|
if (fdinfo) {
|
|
|
|
return fdinfo;
|
2012-08-14 20:43:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (fd != -1) {
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp)
|
|
|
|
{
|
|
|
|
MonFdset *mon_fdset;
|
|
|
|
MonFdsetFd *mon_fdset_fd;
|
|
|
|
char fd_str[60];
|
|
|
|
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_lock(&mon_fdsets_lock);
|
2012-08-14 20:43:43 +00:00
|
|
|
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
|
|
|
if (mon_fdset->id != fdset_id) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
|
|
|
|
if (has_fd) {
|
|
|
|
if (mon_fdset_fd->fd != fd) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
mon_fdset_fd->removed = true;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
mon_fdset_fd->removed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (has_fd && !mon_fdset_fd) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
monitor_fdset_cleanup(mon_fdset);
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-08-14 20:43:43 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
error:
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-08-14 20:43:43 +00:00
|
|
|
if (has_fd) {
|
|
|
|
snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64,
|
|
|
|
fdset_id, fd);
|
|
|
|
} else {
|
|
|
|
snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id);
|
|
|
|
}
|
2015-03-17 10:54:50 +00:00
|
|
|
error_setg(errp, QERR_FD_NOT_FOUND, fd_str);
|
2012-08-14 20:43:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FdsetInfoList *qmp_query_fdsets(Error **errp)
|
|
|
|
{
|
|
|
|
MonFdset *mon_fdset;
|
|
|
|
MonFdsetFd *mon_fdset_fd;
|
|
|
|
FdsetInfoList *fdset_list = NULL;
|
|
|
|
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_lock(&mon_fdsets_lock);
|
2012-08-14 20:43:43 +00:00
|
|
|
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
|
|
|
FdsetInfoList *fdset_info = g_malloc0(sizeof(*fdset_info));
|
|
|
|
FdsetFdInfoList *fdsetfd_list = NULL;
|
|
|
|
|
|
|
|
fdset_info->value = g_malloc0(sizeof(*fdset_info->value));
|
|
|
|
fdset_info->value->fdset_id = mon_fdset->id;
|
|
|
|
|
|
|
|
QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
|
|
|
|
FdsetFdInfoList *fdsetfd_info;
|
|
|
|
|
|
|
|
fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info));
|
|
|
|
fdsetfd_info->value = g_malloc0(sizeof(*fdsetfd_info->value));
|
|
|
|
fdsetfd_info->value->fd = mon_fdset_fd->fd;
|
|
|
|
if (mon_fdset_fd->opaque) {
|
|
|
|
fdsetfd_info->value->has_opaque = true;
|
|
|
|
fdsetfd_info->value->opaque = g_strdup(mon_fdset_fd->opaque);
|
|
|
|
} else {
|
|
|
|
fdsetfd_info->value->has_opaque = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fdsetfd_info->next = fdsetfd_list;
|
|
|
|
fdsetfd_list = fdsetfd_info;
|
|
|
|
}
|
|
|
|
|
|
|
|
fdset_info->value->fds = fdsetfd_list;
|
|
|
|
|
|
|
|
fdset_info->next = fdset_list;
|
|
|
|
fdset_list = fdset_info;
|
|
|
|
}
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-08-14 20:43:43 +00:00
|
|
|
|
|
|
|
return fdset_list;
|
|
|
|
}
|
|
|
|
|
2012-10-18 19:19:32 +00:00
|
|
|
AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
|
|
|
|
bool has_opaque, const char *opaque,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
MonFdset *mon_fdset = NULL;
|
|
|
|
MonFdsetFd *mon_fdset_fd;
|
|
|
|
AddfdInfo *fdinfo;
|
|
|
|
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_lock(&mon_fdsets_lock);
|
2012-10-18 19:19:32 +00:00
|
|
|
if (has_fdset_id) {
|
|
|
|
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
|
|
|
/* Break if match found or match impossible due to ordering by ID */
|
|
|
|
if (fdset_id <= mon_fdset->id) {
|
|
|
|
if (fdset_id < mon_fdset->id) {
|
|
|
|
mon_fdset = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mon_fdset == NULL) {
|
|
|
|
int64_t fdset_id_prev = -1;
|
|
|
|
MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets);
|
|
|
|
|
|
|
|
if (has_fdset_id) {
|
|
|
|
if (fdset_id < 0) {
|
2015-03-17 10:54:50 +00:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id",
|
|
|
|
"a non-negative value");
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-10-18 19:19:32 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* Use specified fdset ID */
|
|
|
|
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
|
|
|
mon_fdset_cur = mon_fdset;
|
|
|
|
if (fdset_id < mon_fdset_cur->id) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Use first available fdset ID */
|
|
|
|
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
|
|
|
mon_fdset_cur = mon_fdset;
|
|
|
|
if (fdset_id_prev == mon_fdset_cur->id - 1) {
|
|
|
|
fdset_id_prev = mon_fdset_cur->id;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mon_fdset = g_malloc0(sizeof(*mon_fdset));
|
|
|
|
if (has_fdset_id) {
|
|
|
|
mon_fdset->id = fdset_id;
|
|
|
|
} else {
|
|
|
|
mon_fdset->id = fdset_id_prev + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The fdset list is ordered by fdset ID */
|
|
|
|
if (!mon_fdset_cur) {
|
|
|
|
QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next);
|
|
|
|
} else if (mon_fdset->id < mon_fdset_cur->id) {
|
|
|
|
QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next);
|
|
|
|
} else {
|
|
|
|
QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd));
|
|
|
|
mon_fdset_fd->fd = fd;
|
|
|
|
mon_fdset_fd->removed = false;
|
|
|
|
if (has_opaque) {
|
|
|
|
mon_fdset_fd->opaque = g_strdup(opaque);
|
|
|
|
}
|
|
|
|
QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next);
|
|
|
|
|
|
|
|
fdinfo = g_malloc0(sizeof(*fdinfo));
|
|
|
|
fdinfo->fdset_id = mon_fdset->id;
|
|
|
|
fdinfo->fd = mon_fdset_fd->fd;
|
|
|
|
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-10-18 19:19:32 +00:00
|
|
|
return fdinfo;
|
|
|
|
}
|
|
|
|
|
2012-08-14 20:43:47 +00:00
|
|
|
int monitor_fdset_get_fd(int64_t fdset_id, int flags)
|
|
|
|
{
|
2018-06-08 03:55:11 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
return -ENOENT;
|
|
|
|
#else
|
2012-08-14 20:43:47 +00:00
|
|
|
MonFdset *mon_fdset;
|
|
|
|
MonFdsetFd *mon_fdset_fd;
|
|
|
|
int mon_fd_flags;
|
2018-06-08 03:55:11 +00:00
|
|
|
int ret;
|
2012-08-14 20:43:47 +00:00
|
|
|
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_lock(&mon_fdsets_lock);
|
2012-08-14 20:43:47 +00:00
|
|
|
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
|
|
|
if (mon_fdset->id != fdset_id) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
|
|
|
|
mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL);
|
|
|
|
if (mon_fd_flags == -1) {
|
2018-06-08 03:55:11 +00:00
|
|
|
ret = -errno;
|
|
|
|
goto out;
|
2012-08-14 20:43:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) {
|
2018-06-08 03:55:11 +00:00
|
|
|
ret = mon_fdset_fd->fd;
|
|
|
|
goto out;
|
2012-08-14 20:43:47 +00:00
|
|
|
}
|
|
|
|
}
|
2018-06-08 03:55:11 +00:00
|
|
|
ret = -EACCES;
|
|
|
|
goto out;
|
2012-08-14 20:43:47 +00:00
|
|
|
}
|
2018-06-08 03:55:11 +00:00
|
|
|
ret = -ENOENT;
|
2012-08-14 20:43:47 +00:00
|
|
|
|
2018-06-08 03:55:11 +00:00
|
|
|
out:
|
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
|
|
|
return ret;
|
|
|
|
#endif
|
2012-08-14 20:43:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
|
|
|
|
{
|
|
|
|
MonFdset *mon_fdset;
|
|
|
|
MonFdsetFd *mon_fdset_fd_dup;
|
|
|
|
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_lock(&mon_fdsets_lock);
|
2012-08-14 20:43:47 +00:00
|
|
|
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
|
|
|
if (mon_fdset->id != fdset_id) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
|
|
|
|
if (mon_fdset_fd_dup->fd == dup_fd) {
|
2018-06-08 03:55:11 +00:00
|
|
|
goto err;
|
2012-08-14 20:43:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup));
|
|
|
|
mon_fdset_fd_dup->fd = dup_fd;
|
|
|
|
QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next);
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-08-14 20:43:47 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2018-06-08 03:55:11 +00:00
|
|
|
|
|
|
|
err:
|
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-08-14 20:43:47 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-05-23 09:44:33 +00:00
|
|
|
static int64_t monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove)
|
2012-08-14 20:43:47 +00:00
|
|
|
{
|
|
|
|
MonFdset *mon_fdset;
|
|
|
|
MonFdsetFd *mon_fdset_fd_dup;
|
|
|
|
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_lock(&mon_fdsets_lock);
|
2012-08-14 20:43:47 +00:00
|
|
|
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
|
|
|
QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
|
|
|
|
if (mon_fdset_fd_dup->fd == dup_fd) {
|
|
|
|
if (remove) {
|
|
|
|
QLIST_REMOVE(mon_fdset_fd_dup, next);
|
2020-01-15 07:20:16 +00:00
|
|
|
g_free(mon_fdset_fd_dup);
|
2012-08-14 20:43:47 +00:00
|
|
|
if (QLIST_EMPTY(&mon_fdset->dup_fds)) {
|
|
|
|
monitor_fdset_cleanup(mon_fdset);
|
|
|
|
}
|
2018-06-08 03:55:11 +00:00
|
|
|
goto err;
|
2014-08-17 09:45:17 +00:00
|
|
|
} else {
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2014-08-17 09:45:17 +00:00
|
|
|
return mon_fdset->id;
|
2012-08-14 20:43:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-06-08 03:55:11 +00:00
|
|
|
|
|
|
|
err:
|
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-08-14 20:43:47 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-05-23 09:44:33 +00:00
|
|
|
int64_t monitor_fdset_dup_fd_find(int dup_fd)
|
2012-08-14 20:43:47 +00:00
|
|
|
{
|
|
|
|
return monitor_fdset_dup_fd_find_remove(dup_fd, false);
|
|
|
|
}
|
|
|
|
|
2014-08-17 09:45:17 +00:00
|
|
|
void monitor_fdset_dup_fd_remove(int dup_fd)
|
2012-08-14 20:43:47 +00:00
|
|
|
{
|
2014-08-17 09:45:17 +00:00
|
|
|
monitor_fdset_dup_fd_find_remove(dup_fd, true);
|
2012-08-14 20:43:47 +00:00
|
|
|
}
|
|
|
|
|
2015-02-09 13:03:19 +00:00
|
|
|
int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp)
|
2014-04-10 08:24:31 +00:00
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
Error *local_err = NULL;
|
2012-08-21 20:52:07 +00:00
|
|
|
|
2014-04-10 08:24:31 +00:00
|
|
|
if (!qemu_isdigit(fdname[0]) && mon) {
|
2012-09-20 14:50:32 +00:00
|
|
|
fd = monitor_get_fd(mon, fdname, &local_err);
|
2014-04-10 08:24:31 +00:00
|
|
|
} else {
|
|
|
|
fd = qemu_parse_fd(fdname);
|
2012-08-21 20:52:07 +00:00
|
|
|
if (fd == -1) {
|
2014-04-10 08:24:31 +00:00
|
|
|
error_setg(&local_err, "Invalid file descriptor number '%s'",
|
|
|
|
fdname);
|
2012-08-21 20:52:07 +00:00
|
|
|
}
|
2014-04-10 08:24:31 +00:00
|
|
|
}
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
assert(fd == -1);
|
2012-08-21 20:52:07 +00:00
|
|
|
} else {
|
2014-04-10 08:24:31 +00:00
|
|
|
assert(fd != -1);
|
2012-08-21 20:52:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2010-09-30 19:00:22 +00:00
|
|
|
/* Please update hmp-commands.hx when adding or changing commands */
|
2019-06-13 15:33:56 +00:00
|
|
|
static HMPCommand hmp_info_cmds[] = {
|
2015-09-10 15:38:58 +00:00
|
|
|
#include "hmp-commands-info.h"
|
|
|
|
{ NULL, NULL, },
|
2004-03-14 21:38:27 +00:00
|
|
|
};
|
|
|
|
|
2019-06-13 15:33:56 +00:00
|
|
|
/* hmp_cmds and hmp_info_cmds would be sorted at runtime */
|
2019-06-13 15:34:01 +00:00
|
|
|
HMPCommand hmp_cmds[] = {
|
2013-01-14 06:06:28 +00:00
|
|
|
#include "hmp-commands.h"
|
|
|
|
{ NULL, NULL, },
|
|
|
|
};
|
|
|
|
|
2019-06-13 15:34:01 +00:00
|
|
|
/*
|
|
|
|
* Set @pval to the value in the register identified by @name.
|
|
|
|
* return 0 if OK, -1 if not found
|
|
|
|
*/
|
|
|
|
int get_monitor_def(int64_t *pval, const char *name)
|
2004-04-04 12:57:25 +00:00
|
|
|
{
|
2015-09-10 15:38:59 +00:00
|
|
|
const MonitorDef *md = target_monitor_defs();
|
2017-01-13 12:12:35 +00:00
|
|
|
CPUState *cs = mon_get_cpu();
|
2005-02-10 22:00:52 +00:00
|
|
|
void *ptr;
|
2015-11-12 03:44:23 +00:00
|
|
|
uint64_t tmp = 0;
|
|
|
|
int ret;
|
2005-02-10 22:00:52 +00:00
|
|
|
|
2017-01-13 12:12:35 +00:00
|
|
|
if (cs == NULL || md == NULL) {
|
2015-09-10 15:38:59 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(; md->name != NULL; md++) {
|
2019-06-13 15:34:01 +00:00
|
|
|
if (hmp_compare_cmd(name, md->name)) {
|
2004-04-04 12:57:25 +00:00
|
|
|
if (md->get_value) {
|
2004-09-30 22:22:08 +00:00
|
|
|
*pval = md->get_value(md, md->offset);
|
2004-04-04 12:57:25 +00:00
|
|
|
} else {
|
2015-05-24 21:20:40 +00:00
|
|
|
CPUArchState *env = mon_get_cpu_env();
|
2005-11-21 23:25:50 +00:00
|
|
|
ptr = (uint8_t *)env + md->offset;
|
2005-02-10 22:00:52 +00:00
|
|
|
switch(md->type) {
|
|
|
|
case MD_I32:
|
|
|
|
*pval = *(int32_t *)ptr;
|
|
|
|
break;
|
|
|
|
case MD_TLONG:
|
|
|
|
*pval = *(target_long *)ptr;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
*pval = 0;
|
|
|
|
break;
|
|
|
|
}
|
2004-04-04 12:57:25 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2015-11-12 03:44:23 +00:00
|
|
|
|
2017-01-13 12:12:35 +00:00
|
|
|
ret = target_get_monitor_def(cs, name, &tmp);
|
2015-11-12 03:44:23 +00:00
|
|
|
if (!ret) {
|
|
|
|
*pval = (target_long) tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2004-04-04 12:57:25 +00:00
|
|
|
}
|
|
|
|
|
2014-05-07 22:41:30 +00:00
|
|
|
static void add_completion_option(ReadLineState *rs, const char *str,
|
|
|
|
const char *option)
|
|
|
|
{
|
|
|
|
if (!str || !option) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!strncmp(option, str, strlen(str))) {
|
|
|
|
readline_add_completion(rs, option);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-07 22:41:29 +00:00
|
|
|
void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
ChardevBackendInfoList *list, *start;
|
|
|
|
|
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
|
|
|
|
|
|
|
start = list = qmp_query_chardev_backends(NULL);
|
|
|
|
while (list) {
|
|
|
|
const char *chr_name = list->value->name;
|
|
|
|
|
|
|
|
if (!strncmp(chr_name, str, len)) {
|
|
|
|
readline_add_completion(rs, chr_name);
|
|
|
|
}
|
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
qapi_free_ChardevBackendInfoList(start);
|
|
|
|
}
|
|
|
|
|
2014-05-07 22:41:31 +00:00
|
|
|
void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
2017-08-24 08:46:06 +00:00
|
|
|
for (i = 0; i < NET_CLIENT_DRIVER__MAX; i++) {
|
2017-08-24 08:46:08 +00:00
|
|
|
add_completion_option(rs, str, NetClientDriver_str(i));
|
2014-05-07 22:41:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-13 15:25:07 +00:00
|
|
|
void device_add_completion(ReadLineState *rs, int nb_args, const char *str)
|
2014-02-06 22:30:11 +00:00
|
|
|
{
|
|
|
|
GSList *list, *elt;
|
|
|
|
size_t len;
|
|
|
|
|
2014-04-13 15:25:07 +00:00
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-06 22:30:11 +00:00
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
|
|
|
list = elt = object_class_get_list(TYPE_DEVICE, false);
|
|
|
|
while (elt) {
|
|
|
|
const char *name;
|
|
|
|
DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data,
|
|
|
|
TYPE_DEVICE);
|
|
|
|
name = object_class_get_name(OBJECT_CLASS(dc));
|
2014-04-13 15:25:07 +00:00
|
|
|
|
2017-05-03 20:35:44 +00:00
|
|
|
if (dc->user_creatable
|
2014-04-13 15:25:07 +00:00
|
|
|
&& !strncmp(name, str, len)) {
|
2014-02-06 22:30:11 +00:00
|
|
|
readline_add_completion(rs, name);
|
|
|
|
}
|
|
|
|
elt = elt->next;
|
|
|
|
}
|
|
|
|
g_slist_free(list);
|
|
|
|
}
|
|
|
|
|
2014-04-13 15:25:06 +00:00
|
|
|
void object_add_completion(ReadLineState *rs, int nb_args, const char *str)
|
2014-02-06 22:30:13 +00:00
|
|
|
{
|
|
|
|
GSList *list, *elt;
|
|
|
|
size_t len;
|
|
|
|
|
2014-04-13 15:25:06 +00:00
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-06 22:30:13 +00:00
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
|
|
|
list = elt = object_class_get_list(TYPE_USER_CREATABLE, false);
|
|
|
|
while (elt) {
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
name = object_class_get_name(OBJECT_CLASS(elt->data));
|
|
|
|
if (!strncmp(name, str, len) && strcmp(name, TYPE_USER_CREATABLE)) {
|
|
|
|
readline_add_completion(rs, name);
|
|
|
|
}
|
|
|
|
elt = elt->next;
|
|
|
|
}
|
|
|
|
g_slist_free(list);
|
|
|
|
}
|
|
|
|
|
2020-01-10 15:30:17 +00:00
|
|
|
static int qdev_add_hotpluggable_device(Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
GSList **list = opaque;
|
|
|
|
DeviceState *dev = (DeviceState *)object_dynamic_cast(OBJECT(obj),
|
|
|
|
TYPE_DEVICE);
|
|
|
|
|
|
|
|
if (dev == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->realized && object_property_get_bool(obj, "hotpluggable", NULL)) {
|
|
|
|
*list = g_slist_append(*list, dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GSList *qdev_build_hotpluggable_device_list(Object *peripheral)
|
|
|
|
{
|
|
|
|
GSList *list = NULL;
|
|
|
|
|
|
|
|
object_child_foreach(peripheral, qdev_add_hotpluggable_device, &list);
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2014-10-21 11:46:05 +00:00
|
|
|
static void peripheral_device_del_completion(ReadLineState *rs,
|
|
|
|
const char *str, size_t len)
|
|
|
|
{
|
2014-11-26 11:50:01 +00:00
|
|
|
Object *peripheral = container_get(qdev_get_machine(), "/peripheral");
|
|
|
|
GSList *list, *item;
|
2014-10-21 11:46:05 +00:00
|
|
|
|
2014-11-26 11:50:01 +00:00
|
|
|
list = qdev_build_hotpluggable_device_list(peripheral);
|
|
|
|
if (!list) {
|
2014-10-21 11:46:05 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (item = list; item; item = g_slist_next(item)) {
|
|
|
|
DeviceState *dev = item->data;
|
|
|
|
|
|
|
|
if (dev->id && !strncmp(str, dev->id, len)) {
|
|
|
|
readline_add_completion(rs, dev->id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_slist_free(list);
|
|
|
|
}
|
|
|
|
|
2014-05-07 22:41:28 +00:00
|
|
|
void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
ChardevInfoList *list, *start;
|
|
|
|
|
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
|
|
|
|
|
|
|
start = list = qmp_query_chardev(NULL);
|
|
|
|
while (list) {
|
|
|
|
ChardevInfo *chr = list->value;
|
|
|
|
|
|
|
|
if (!strncmp(chr->label, str, len)) {
|
|
|
|
readline_add_completion(rs, chr->label);
|
|
|
|
}
|
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
qapi_free_ChardevInfoList(start);
|
|
|
|
}
|
|
|
|
|
2014-05-27 22:39:30 +00:00
|
|
|
static void ringbuf_completion(ReadLineState *rs, const char *str)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
ChardevInfoList *list, *start;
|
|
|
|
|
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
|
|
|
|
|
|
|
start = list = qmp_query_chardev(NULL);
|
|
|
|
while (list) {
|
|
|
|
ChardevInfo *chr_info = list->value;
|
|
|
|
|
|
|
|
if (!strncmp(chr_info->label, str, len)) {
|
2016-12-07 13:20:22 +00:00
|
|
|
Chardev *chr = qemu_chr_find(chr_info->label);
|
2016-12-07 15:39:10 +00:00
|
|
|
if (chr && CHARDEV_IS_RINGBUF(chr)) {
|
2014-05-27 22:39:30 +00:00
|
|
|
readline_add_completion(rs, chr_info->label);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
qapi_free_ChardevInfoList(start);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ringbuf_write_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ringbuf_completion(rs, str);
|
|
|
|
}
|
|
|
|
|
2014-04-13 15:25:07 +00:00
|
|
|
void device_del_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
2014-10-21 11:46:05 +00:00
|
|
|
peripheral_device_del_completion(rs, str, len);
|
2014-04-13 15:25:07 +00:00
|
|
|
}
|
|
|
|
|
2014-04-13 15:25:06 +00:00
|
|
|
void object_del_completion(ReadLineState *rs, int nb_args, const char *str)
|
2014-02-06 22:30:12 +00:00
|
|
|
{
|
|
|
|
ObjectPropertyInfoList *list, *start;
|
|
|
|
size_t len;
|
|
|
|
|
2014-04-13 15:25:06 +00:00
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
2014-02-06 22:30:12 +00:00
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
|
|
|
|
|
|
|
start = list = qmp_qom_list("/objects", NULL);
|
|
|
|
while (list) {
|
|
|
|
ObjectPropertyInfo *info = list->value;
|
|
|
|
|
|
|
|
if (!strncmp(info->type, "child<", 5)
|
|
|
|
&& !strncmp(info->name, str, len)) {
|
|
|
|
readline_add_completion(rs, info->name);
|
|
|
|
}
|
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
qapi_free_ObjectPropertyInfoList(start);
|
|
|
|
}
|
|
|
|
|
2014-05-07 22:41:27 +00:00
|
|
|
void sendkey_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *sep;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sep = strrchr(str, '-');
|
|
|
|
if (sep) {
|
|
|
|
str = sep + 1;
|
|
|
|
}
|
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
qapi: Don't let implicit enum MAX member collide
Now that we guarantee the user doesn't have any enum values
beginning with a single underscore, we can use that for our
own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious
that the sentinel is generated.
This patch was mostly generated by applying a temporary patch:
|diff --git a/scripts/qapi.py b/scripts/qapi.py
|index e6d014b..b862ec9 100644
|--- a/scripts/qapi.py
|+++ b/scripts/qapi.py
|@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = {
| max_index = c_enum_const(name, 'MAX', prefix)
| ret += mcgen('''
| [%(max_index)s] = NULL,
|+// %(max_index)s
| };
| ''',
| max_index=max_index)
then running:
$ cat qapi-{types,event}.c tests/test-qapi-types.c |
sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list
$ git grep -l _MAX | xargs sed -i -f list
The only things not generated are the changes in scripts/qapi.py.
Rejecting enum members named 'MAX' is now useless, and will be dropped
in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
[Rebased to current master, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 08:52:57 +00:00
|
|
|
for (i = 0; i < Q_KEY_CODE__MAX; i++) {
|
2017-08-24 08:46:08 +00:00
|
|
|
if (!strncmp(str, QKeyCode_str(i), len)) {
|
|
|
|
readline_add_completion(rs, QKeyCode_str(i));
|
2014-05-07 22:41:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-07 22:41:30 +00:00
|
|
|
void set_link_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
|
|
|
if (nb_args == 2) {
|
2015-04-23 06:21:38 +00:00
|
|
|
NetClientState *ncs[MAX_QUEUE_NUM];
|
2014-05-07 22:41:30 +00:00
|
|
|
int count, i;
|
|
|
|
count = qemu_find_net_clients_except(NULL, ncs,
|
qapi: Change Netdev into a flat union
This is a mostly-mechanical conversion that creates a new flat
union 'Netdev' QAPI type that covers all the branches of the
former 'NetClientOptions' simple union, where the branches are
now listed in a new 'NetClientDriver' enum rather than generated
from the simple union. The existence of a flat union has no
change to the command line syntax accepted for new code, and
will make it possible for a future patch to switch the QMP
command to parse a boxed union for no change to valid QMP; but
it does have some ripple effect on the C code when dealing with
the new types.
While making the conversion, note that the 'NetLegacy' type
remains unchanged: it applies only to legacy command line options,
and will not be ported to QMP, so it should remain a wrapper
around a simple union; to avoid confusion, the type named
'NetClientOptions' is now gone, and we introduce 'NetLegacyOptions'
in its place. Then, in the C code, we convert from NetLegacy to
Netdev as soon as possible, so that the bulk of the net stack
only has to deal with one QAPI type, not two. Note that since
the old legacy code always rejected 'hubport', we can just omit
that branch from the new 'NetLegacyOptions' simple union.
Based on an idea originally by Zoltán Kővágó <DirtY.iCE.hu@gmail.com>:
Message-Id: <01a527fbf1a5de880091f98cf011616a78adeeee.1441627176.git.DirtY.iCE.hu@gmail.com>
although the sed script in that patch no longer applies due to
other changes in the tree since then, and I also did some manual
cleanups (such as fixing whitespace to keep checkpatch happy).
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1468468228-27827-13-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Fixup from Eric squashed in]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-07-14 03:50:23 +00:00
|
|
|
NET_CLIENT_DRIVER_NONE,
|
2015-04-23 06:21:38 +00:00
|
|
|
MAX_QUEUE_NUM);
|
2015-04-23 06:21:39 +00:00
|
|
|
for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
|
2014-05-07 22:41:30 +00:00
|
|
|
const char *name = ncs[i]->name;
|
|
|
|
if (!strncmp(str, name, len)) {
|
|
|
|
readline_add_completion(rs, name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (nb_args == 3) {
|
|
|
|
add_completion_option(rs, str, "on");
|
|
|
|
add_completion_option(rs, str, "off");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-07 22:41:32 +00:00
|
|
|
void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
|
|
|
int len, count, i;
|
2015-04-23 06:21:38 +00:00
|
|
|
NetClientState *ncs[MAX_QUEUE_NUM];
|
2014-05-07 22:41:32 +00:00
|
|
|
|
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
qapi: Change Netdev into a flat union
This is a mostly-mechanical conversion that creates a new flat
union 'Netdev' QAPI type that covers all the branches of the
former 'NetClientOptions' simple union, where the branches are
now listed in a new 'NetClientDriver' enum rather than generated
from the simple union. The existence of a flat union has no
change to the command line syntax accepted for new code, and
will make it possible for a future patch to switch the QMP
command to parse a boxed union for no change to valid QMP; but
it does have some ripple effect on the C code when dealing with
the new types.
While making the conversion, note that the 'NetLegacy' type
remains unchanged: it applies only to legacy command line options,
and will not be ported to QMP, so it should remain a wrapper
around a simple union; to avoid confusion, the type named
'NetClientOptions' is now gone, and we introduce 'NetLegacyOptions'
in its place. Then, in the C code, we convert from NetLegacy to
Netdev as soon as possible, so that the bulk of the net stack
only has to deal with one QAPI type, not two. Note that since
the old legacy code always rejected 'hubport', we can just omit
that branch from the new 'NetLegacyOptions' simple union.
Based on an idea originally by Zoltán Kővágó <DirtY.iCE.hu@gmail.com>:
Message-Id: <01a527fbf1a5de880091f98cf011616a78adeeee.1441627176.git.DirtY.iCE.hu@gmail.com>
although the sed script in that patch no longer applies due to
other changes in the tree since then, and I also did some manual
cleanups (such as fixing whitespace to keep checkpatch happy).
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1468468228-27827-13-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Fixup from Eric squashed in]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-07-14 03:50:23 +00:00
|
|
|
count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_DRIVER_NIC,
|
2015-04-23 06:21:38 +00:00
|
|
|
MAX_QUEUE_NUM);
|
2015-04-23 06:21:39 +00:00
|
|
|
for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
|
2014-05-07 22:41:32 +00:00
|
|
|
QemuOpts *opts;
|
|
|
|
const char *name = ncs[i]->name;
|
|
|
|
if (strncmp(str, name, len)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), name);
|
|
|
|
if (opts) {
|
|
|
|
readline_add_completion(rs, name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-11 10:53:51 +00:00
|
|
|
void info_trace_events_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
|
|
|
if (nb_args == 2) {
|
2016-10-04 13:35:43 +00:00
|
|
|
TraceEventIter iter;
|
|
|
|
TraceEvent *ev;
|
|
|
|
char *pattern = g_strdup_printf("%s*", str);
|
|
|
|
trace_event_iter_init(&iter, pattern);
|
|
|
|
while ((ev = trace_event_iter_next(&iter)) != NULL) {
|
|
|
|
readline_add_completion(rs, trace_event_get_name(ev));
|
2016-07-11 10:53:51 +00:00
|
|
|
}
|
2016-10-04 13:35:43 +00:00
|
|
|
g_free(pattern);
|
2016-07-11 10:53:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-14 10:27:43 +00:00
|
|
|
void trace_event_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
|
|
|
if (nb_args == 2) {
|
2016-10-04 13:35:43 +00:00
|
|
|
TraceEventIter iter;
|
|
|
|
TraceEvent *ev;
|
|
|
|
char *pattern = g_strdup_printf("%s*", str);
|
|
|
|
trace_event_iter_init(&iter, pattern);
|
|
|
|
while ((ev = trace_event_iter_next(&iter)) != NULL) {
|
|
|
|
readline_add_completion(rs, trace_event_get_name(ev));
|
|
|
|
}
|
|
|
|
g_free(pattern);
|
2015-08-14 10:27:43 +00:00
|
|
|
} else if (nb_args == 3) {
|
|
|
|
add_completion_option(rs, str, "on");
|
|
|
|
add_completion_option(rs, str, "off");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-27 22:39:31 +00:00
|
|
|
void watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
2014-07-29 22:22:40 +00:00
|
|
|
int i;
|
|
|
|
|
2014-05-27 22:39:31 +00:00
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
readline_set_completion_index(rs, strlen(str));
|
2017-09-07 08:05:24 +00:00
|
|
|
for (i = 0; i < WATCHDOG_ACTION__MAX; i++) {
|
|
|
|
add_completion_option(rs, str, WatchdogAction_str(i));
|
2014-07-29 22:22:40 +00:00
|
|
|
}
|
2014-05-27 22:39:31 +00:00
|
|
|
}
|
|
|
|
|
2014-05-27 22:39:32 +00:00
|
|
|
void migrate_set_capability_completion(ReadLineState *rs, int nb_args,
|
|
|
|
const char *str)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
|
|
|
if (nb_args == 2) {
|
|
|
|
int i;
|
qapi: Don't let implicit enum MAX member collide
Now that we guarantee the user doesn't have any enum values
beginning with a single underscore, we can use that for our
own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious
that the sentinel is generated.
This patch was mostly generated by applying a temporary patch:
|diff --git a/scripts/qapi.py b/scripts/qapi.py
|index e6d014b..b862ec9 100644
|--- a/scripts/qapi.py
|+++ b/scripts/qapi.py
|@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = {
| max_index = c_enum_const(name, 'MAX', prefix)
| ret += mcgen('''
| [%(max_index)s] = NULL,
|+// %(max_index)s
| };
| ''',
| max_index=max_index)
then running:
$ cat qapi-{types,event}.c tests/test-qapi-types.c |
sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list
$ git grep -l _MAX | xargs sed -i -f list
The only things not generated are the changes in scripts/qapi.py.
Rejecting enum members named 'MAX' is now useless, and will be dropped
in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
[Rebased to current master, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 08:52:57 +00:00
|
|
|
for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
|
2017-08-24 08:46:08 +00:00
|
|
|
const char *name = MigrationCapability_str(i);
|
2014-05-27 22:39:32 +00:00
|
|
|
if (!strncmp(str, name, len)) {
|
|
|
|
readline_add_completion(rs, name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (nb_args == 3) {
|
|
|
|
add_completion_option(rs, str, "on");
|
|
|
|
add_completion_option(rs, str, "off");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-23 08:32:29 +00:00
|
|
|
void migrate_set_parameter_completion(ReadLineState *rs, int nb_args,
|
|
|
|
const char *str)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
|
|
|
if (nb_args == 2) {
|
|
|
|
int i;
|
qapi: Don't let implicit enum MAX member collide
Now that we guarantee the user doesn't have any enum values
beginning with a single underscore, we can use that for our
own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious
that the sentinel is generated.
This patch was mostly generated by applying a temporary patch:
|diff --git a/scripts/qapi.py b/scripts/qapi.py
|index e6d014b..b862ec9 100644
|--- a/scripts/qapi.py
|+++ b/scripts/qapi.py
|@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = {
| max_index = c_enum_const(name, 'MAX', prefix)
| ret += mcgen('''
| [%(max_index)s] = NULL,
|+// %(max_index)s
| };
| ''',
| max_index=max_index)
then running:
$ cat qapi-{types,event}.c tests/test-qapi-types.c |
sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list
$ git grep -l _MAX | xargs sed -i -f list
The only things not generated are the changes in scripts/qapi.py.
Rejecting enum members named 'MAX' is now useless, and will be dropped
in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
[Rebased to current master, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 08:52:57 +00:00
|
|
|
for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
|
2017-08-24 08:46:08 +00:00
|
|
|
const char *name = MigrationParameter_str(i);
|
2015-03-23 08:32:29 +00:00
|
|
|
if (!strncmp(str, name, len)) {
|
|
|
|
readline_add_completion(rs, name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-27 22:39:37 +00:00
|
|
|
static void vm_completion(ReadLineState *rs, const char *str)
|
|
|
|
{
|
|
|
|
size_t len;
|
2016-03-22 17:58:50 +00:00
|
|
|
BlockDriverState *bs;
|
2016-05-20 16:49:07 +00:00
|
|
|
BdrvNextIterator it;
|
2014-05-27 22:39:37 +00:00
|
|
|
|
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
2016-03-22 17:58:50 +00:00
|
|
|
|
2016-05-20 16:49:07 +00:00
|
|
|
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
|
2014-05-27 22:39:37 +00:00
|
|
|
SnapshotInfoList *snapshots, *snapshot;
|
2015-11-04 17:19:42 +00:00
|
|
|
AioContext *ctx = bdrv_get_aio_context(bs);
|
|
|
|
bool ok = false;
|
2014-05-27 22:39:37 +00:00
|
|
|
|
2015-11-04 17:19:42 +00:00
|
|
|
aio_context_acquire(ctx);
|
|
|
|
if (bdrv_can_snapshot(bs)) {
|
|
|
|
ok = bdrv_query_snapshot_info_list(bs, &snapshots, NULL) == 0;
|
2014-05-27 22:39:37 +00:00
|
|
|
}
|
2015-11-04 17:19:42 +00:00
|
|
|
aio_context_release(ctx);
|
|
|
|
if (!ok) {
|
2014-05-27 22:39:37 +00:00
|
|
|
continue;
|
|
|
|
}
|
2015-11-04 17:19:42 +00:00
|
|
|
|
2014-05-27 22:39:37 +00:00
|
|
|
snapshot = snapshots;
|
|
|
|
while (snapshot) {
|
|
|
|
char *completion = snapshot->value->name;
|
|
|
|
if (!strncmp(str, completion, len)) {
|
|
|
|
readline_add_completion(rs, completion);
|
|
|
|
}
|
|
|
|
completion = snapshot->value->id;
|
|
|
|
if (!strncmp(str, completion, len)) {
|
|
|
|
readline_add_completion(rs, completion);
|
|
|
|
}
|
|
|
|
snapshot = snapshot->next;
|
|
|
|
}
|
|
|
|
qapi_free_SnapshotInfoList(snapshots);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void delvm_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
|
|
|
if (nb_args == 2) {
|
|
|
|
vm_completion(rs, str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void loadvm_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
|
|
|
if (nb_args == 2) {
|
|
|
|
vm_completion(rs, str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-12 03:32:41 +00:00
|
|
|
static int
|
|
|
|
compare_mon_cmd(const void *a, const void *b)
|
|
|
|
{
|
2019-06-13 15:33:56 +00:00
|
|
|
return strcmp(((const HMPCommand *)a)->name,
|
|
|
|
((const HMPCommand *)b)->name);
|
2011-10-12 03:32:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sortcmdlist(void)
|
|
|
|
{
|
2019-06-13 15:33:56 +00:00
|
|
|
qsort(hmp_cmds, ARRAY_SIZE(hmp_cmds) - 1,
|
|
|
|
sizeof(*hmp_cmds),
|
|
|
|
compare_mon_cmd);
|
|
|
|
qsort(hmp_info_cmds, ARRAY_SIZE(hmp_info_cmds) - 1,
|
|
|
|
sizeof(*hmp_info_cmds),
|
|
|
|
compare_mon_cmd);
|
2011-10-12 03:32:41 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 08:59:50 +00:00
|
|
|
void monitor_init_globals(void)
|
|
|
|
{
|
2019-06-13 15:34:02 +00:00
|
|
|
monitor_init_globals_core();
|
2018-03-09 08:59:50 +00:00
|
|
|
monitor_init_qmp_commands();
|
|
|
|
sortcmdlist();
|
2018-06-08 03:55:11 +00:00
|
|
|
qemu_mutex_init(&mon_fdsets_lock);
|
2004-04-04 13:07:25 +00:00
|
|
|
}
|