2004-03-14 22:38:27 +01:00
|
|
|
/*
|
|
|
|
* QEMU monitor
|
2007-09-16 23:08:06 +02:00
|
|
|
*
|
2004-03-14 22:38:27 +01:00
|
|
|
* Copyright (c) 2003-2004 Fabrice Bellard
|
2007-09-16 23:08:06 +02:00
|
|
|
*
|
2004-03-14 22:38:27 +01: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 12:18:31 +01:00
|
|
|
|
2016-01-29 18:50:05 +01:00
|
|
|
#include "qemu/osdep.h"
|
2018-06-25 14:42:34 +02:00
|
|
|
#include "qemu/units.h"
|
2009-03-07 16:32:56 +01:00
|
|
|
#include <dirent.h>
|
2016-03-15 16:58:45 +01:00
|
|
|
#include "cpu.h"
|
2007-11-17 18:14:51 +01:00
|
|
|
#include "hw/hw.h"
|
2013-02-04 11:37:52 +01:00
|
|
|
#include "monitor/qdev.h"
|
2007-11-17 18:14:51 +01:00
|
|
|
#include "hw/usb.h"
|
2012-12-12 13:24:50 +01:00
|
|
|
#include "hw/pci/pci.h"
|
2013-02-05 17:06:20 +01:00
|
|
|
#include "sysemu/watchdog.h"
|
2009-10-01 16:42:33 +02:00
|
|
|
#include "hw/loader.h"
|
2012-12-17 18:19:49 +01:00
|
|
|
#include "exec/gdbstub.h"
|
2012-10-24 08:43:34 +02:00
|
|
|
#include "net/net.h"
|
2009-11-25 19:48:54 +01:00
|
|
|
#include "net/slirp.h"
|
2017-01-26 15:26:44 +01:00
|
|
|
#include "chardev/char-fe.h"
|
2018-03-09 09:59:52 +01:00
|
|
|
#include "chardev/char-io.h"
|
2018-03-26 08:38:56 +02:00
|
|
|
#include "chardev/char-mux.h"
|
2010-10-07 12:22:54 +02:00
|
|
|
#include "ui/qemu-spice.h"
|
2015-02-08 19:51:16 +01:00
|
|
|
#include "sysemu/numa.h"
|
2012-12-17 18:19:49 +01:00
|
|
|
#include "monitor/monitor.h"
|
2016-12-12 18:22:24 +01:00
|
|
|
#include "qemu/config-file.h"
|
2013-11-14 11:54:15 +01:00
|
|
|
#include "qemu/readline.h"
|
2012-11-28 12:06:30 +01:00
|
|
|
#include "ui/console.h"
|
2013-12-04 15:02:28 +01:00
|
|
|
#include "ui/input.h"
|
2016-03-16 19:54:29 +01:00
|
|
|
#include "sysemu/block-backend.h"
|
2007-11-17 18:14:51 +01:00
|
|
|
#include "audio/audio.h"
|
2012-10-24 11:12:21 +02:00
|
|
|
#include "disas/disas.h"
|
2012-12-17 18:20:04 +01:00
|
|
|
#include "sysemu/balloon.h"
|
2012-12-17 18:20:00 +01:00
|
|
|
#include "qemu/timer.h"
|
2017-01-10 11:59:55 +01:00
|
|
|
#include "sysemu/hw_accel.h"
|
2016-02-18 19:40:24 +01:00
|
|
|
#include "authz/list.h"
|
|
|
|
#include "qapi/util.h"
|
2013-04-02 18:28:41 +02:00
|
|
|
#include "sysemu/tpm.h"
|
2018-02-01 12:18:39 +01:00
|
|
|
#include "qapi/qmp/qdict.h"
|
2015-03-17 17:22:46 +01:00
|
|
|
#include "qapi/qmp/qerror.h"
|
2018-02-01 12:18:36 +01:00
|
|
|
#include "qapi/qmp/qnum.h"
|
2018-02-01 12:18:40 +01:00
|
|
|
#include "qapi/qmp/qstring.h"
|
2012-12-17 18:19:43 +01:00
|
|
|
#include "qapi/qmp/qjson.h"
|
2018-08-23 18:40:20 +02:00
|
|
|
#include "qapi/qmp/json-parser.h"
|
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 09:59:53 +01:00
|
|
|
#include "qapi/qmp/qlist.h"
|
2016-06-22 19:11:19 +02:00
|
|
|
#include "qom/object_interfaces.h"
|
2017-01-25 17:14:15 +01:00
|
|
|
#include "trace-root.h"
|
2011-08-31 20:31:24 +02:00
|
|
|
#include "trace/control.h"
|
2015-09-10 17:38:59 +02:00
|
|
|
#include "monitor/hmp-target.h"
|
2011-08-31 20:30:43 +02:00
|
|
|
#ifdef CONFIG_TRACE_SIMPLE
|
2011-08-31 20:31:24 +02:00
|
|
|
#include "trace/simple.h"
|
2010-06-24 13:34:53 +02:00
|
|
|
#endif
|
2012-12-17 18:19:49 +01:00
|
|
|
#include "exec/memory.h"
|
2016-03-15 13:18:37 +01:00
|
|
|
#include "exec/exec-all.h"
|
2015-12-15 13:16:16 +01:00
|
|
|
#include "qemu/log.h"
|
2018-02-01 12:18:46 +01:00
|
|
|
#include "qemu/option.h"
|
2011-09-02 19:34:48 +02:00
|
|
|
#include "hmp.h"
|
2012-12-17 18:20:00 +01:00
|
|
|
#include "qemu/thread.h"
|
2014-05-28 00:39:37 +02:00
|
|
|
#include "block/qapi.h"
|
2018-02-11 10:36:05 +01:00
|
|
|
#include "qapi/qapi-commands.h"
|
2019-02-14 16:22:38 +01:00
|
|
|
#include "qapi/qapi-emit-events.h"
|
2018-02-01 12:18:31 +01:00
|
|
|
#include "qapi/error.h"
|
2014-06-18 08:43:31 +02:00
|
|
|
#include "qapi/qmp-event.h"
|
2018-02-11 10:36:05 +01:00
|
|
|
#include "qapi/qapi-introspect.h"
|
2016-03-10 12:55:26 +01:00
|
|
|
#include "sysemu/qtest.h"
|
2017-03-03 12:01:16 +01:00
|
|
|
#include "sysemu/cpus.h"
|
2018-03-09 09:59:52 +01:00
|
|
|
#include "sysemu/iothread.h"
|
2016-03-20 18:16:19 +01:00
|
|
|
#include "qemu/cutils.h"
|
2018-10-10 16:48:53 +02:00
|
|
|
#include "tcg/tcg.h"
|
2007-12-03 18:05:38 +01:00
|
|
|
|
2015-06-26 20:07:21 +02:00
|
|
|
#if defined(TARGET_S390X)
|
|
|
|
#include "hw/s390x/storage-keys.h"
|
2016-08-15 18:44:04 +02:00
|
|
|
#include "hw/s390x/storage-attributes.h"
|
2015-06-26 20:07:21 +02:00
|
|
|
#endif
|
|
|
|
|
2004-04-04 14:57:25 +02:00
|
|
|
/*
|
|
|
|
* Supported types:
|
2007-09-16 23:08:06 +02:00
|
|
|
*
|
2004-04-04 14:57:25 +02:00
|
|
|
* 'F' filename
|
2004-07-14 19:21:37 +02:00
|
|
|
* 'B' block device name
|
2004-04-04 14:57:25 +02:00
|
|
|
* 's' string (accept optional quote)
|
2013-08-27 14:38:26 +02:00
|
|
|
* 'S' it just appends the rest of the string (accept optional quote)
|
2010-02-10 20:24:35 +01:00
|
|
|
* 'O' option string of the form NAME=VALUE,...
|
|
|
|
* parsed according to QemuOptsList given by its name
|
|
|
|
* Example: 'device:O' uses qemu_device_opts.
|
|
|
|
* Restriction: only lists with empty desc are supported
|
|
|
|
* TODO lift the restriction
|
2005-02-10 23:00:52 +01:00
|
|
|
* 'i' 32 bit integer
|
|
|
|
* 'l' target long (32 or 64 bit)
|
2012-04-26 22:34:30 +02:00
|
|
|
* 'M' Non-negative target long (32 or 64 bit), in user mode the
|
|
|
|
* value is multiplied by 2^20 (think Mebibyte)
|
2010-10-21 17:15:47 +02:00
|
|
|
* 'o' octets (aka bytes)
|
2013-06-05 14:19:27 +02:00
|
|
|
* user mode accepts an optional E, e, P, p, T, t, G, g, M, m,
|
|
|
|
* K, k suffix, which multiplies the value by 2^60 for suffixes E
|
|
|
|
* and e, 2^50 for suffixes P and p, 2^40 for suffixes T and t,
|
|
|
|
* 2^30 for suffixes G and g, 2^20 for M and m, 2^10 for K and k
|
2010-01-25 14:23:06 +01:00
|
|
|
* 'T' double
|
|
|
|
* user mode accepts an optional ms, us, ns suffix,
|
|
|
|
* which divides the value by 1e3, 1e6, 1e9, respectively
|
2004-04-04 14:57:25 +02:00
|
|
|
* '/' optional gdb-like print format (like "/10x")
|
|
|
|
*
|
2009-08-28 20:27:27 +02:00
|
|
|
* '?' optional type (for all types, except '/')
|
|
|
|
* '.' other form of optional type (for 'i' and 'l')
|
2010-03-26 09:07:09 +01:00
|
|
|
* 'b' boolean
|
|
|
|
* user mode accepts "on" or "off"
|
2009-08-28 20:27:27 +02:00
|
|
|
* '-' optional parameter (eg. '-f')
|
2004-04-04 14:57:25 +02:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2009-10-01 23:12:16 +02:00
|
|
|
typedef struct mon_cmd_t {
|
2004-03-14 22:38:27 +01:00
|
|
|
const char *name;
|
2004-04-04 14:57:25 +02:00
|
|
|
const char *args_type;
|
2004-03-14 22:38:27 +01:00
|
|
|
const char *params;
|
|
|
|
const char *help;
|
2018-06-20 17:39:41 +02:00
|
|
|
const char *flags; /* p=preconfig */
|
2016-09-12 11:19:06 +02:00
|
|
|
void (*cmd)(Monitor *mon, const QDict *qdict);
|
|
|
|
/* @sub_table is a list of 2nd level of commands. If it does not exist,
|
|
|
|
* cmd should be used. If it exists, sub_table[?].cmd should be
|
|
|
|
* used, and cmd of 1st level plays the role of help function.
|
2013-01-14 07:06:27 +01:00
|
|
|
*/
|
|
|
|
struct mon_cmd_t *sub_table;
|
2014-04-13 17:25:06 +02:00
|
|
|
void (*command_completion)(ReadLineState *rs, int nb_args, const char *str);
|
2009-10-01 23:12:16 +02:00
|
|
|
} mon_cmd_t;
|
2004-03-14 22:38:27 +01:00
|
|
|
|
2009-07-22 10:11:40 +02:00
|
|
|
/* file descriptors passed via SCM_RIGHTS */
|
2009-10-01 23:12:16 +02:00
|
|
|
typedef struct mon_fd_t mon_fd_t;
|
|
|
|
struct mon_fd_t {
|
2009-07-22 10:11:40 +02:00
|
|
|
char *name;
|
|
|
|
int fd;
|
2009-10-01 23:12:16 +02:00
|
|
|
QLIST_ENTRY(mon_fd_t) next;
|
2009-07-22 10:11:40 +02:00
|
|
|
};
|
|
|
|
|
2012-08-14 22:43:43 +02: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 22:43:47 +02:00
|
|
|
QLIST_HEAD(, MonFdsetFd) dup_fds;
|
2012-08-14 22:43:43 +02:00
|
|
|
QLIST_ENTRY(MonFdset) next;
|
|
|
|
};
|
|
|
|
|
2015-03-06 19:35:59 +01:00
|
|
|
typedef struct {
|
2009-11-27 01:59:01 +01:00
|
|
|
JSONMessageParser parser;
|
2015-03-06 19:51:51 +01:00
|
|
|
/*
|
|
|
|
* When a client connects, we're in capabilities negotiation mode.
|
2018-07-03 10:53:57 +02:00
|
|
|
* @commands is &qmp_cap_negotiation_commands then. When command
|
|
|
|
* qmp_capabilities succeeds, we go into command mode, and
|
|
|
|
* @command becomes &qmp_commands.
|
2015-03-06 19:51:51 +01: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 13:32:27 +01:00
|
|
|
QmpCommandList *commands;
|
2018-07-03 10:53:56 +02:00
|
|
|
bool capab_offered[QMP_CAPABILITY__MAX]; /* capabilities offered */
|
|
|
|
bool capab[QMP_CAPABILITY__MAX]; /* offered and accepted */
|
2018-03-09 09:59:57 +01:00
|
|
|
/*
|
2018-07-03 10:53:57 +02:00
|
|
|
* Protects qmp request/response queue.
|
|
|
|
* Take monitor_lock first when you need both.
|
2018-03-09 09:59:57 +01:00
|
|
|
*/
|
|
|
|
QemuMutex qmp_queue_lock;
|
|
|
|
/* Input queue that holds all the parsed QMP requests */
|
|
|
|
GQueue *qmp_requests;
|
2015-03-06 19:35:59 +01:00
|
|
|
} MonitorQMP;
|
2009-11-27 01:59:01 +01:00
|
|
|
|
2012-06-14 19:12:57 +02:00
|
|
|
/*
|
|
|
|
* To prevent flooding clients, events can be throttled. The
|
|
|
|
* throttling is calculated globally, rather than per-Monitor
|
|
|
|
* instance.
|
|
|
|
*/
|
2014-06-18 08:43:31 +02:00
|
|
|
typedef struct MonitorQAPIEventState {
|
2015-10-15 17:08:35 +02:00
|
|
|
QAPIEvent event; /* Throttling state for this event type and... */
|
|
|
|
QDict *data; /* ... data, see qapi_event_throttle_equal() */
|
2012-06-14 19:12:57 +02:00
|
|
|
QEMUTimer *timer; /* Timer for handling delayed events */
|
2015-10-15 17:08:30 +02:00
|
|
|
QDict *qdict; /* Delayed event (if any) */
|
2014-06-18 08:43:31 +02:00
|
|
|
} MonitorQAPIEventState;
|
2012-06-14 19:12:57 +02:00
|
|
|
|
2015-10-15 17:08:33 +02:00
|
|
|
typedef struct {
|
|
|
|
int64_t rate; /* Minimum time (in ns) between two events */
|
|
|
|
} MonitorQAPIEventConf;
|
|
|
|
|
2009-03-06 00:01:29 +01:00
|
|
|
struct Monitor {
|
2016-10-22 11:52:52 +02:00
|
|
|
CharBackend chr;
|
2009-09-10 10:58:54 +02:00
|
|
|
int reset_seen;
|
2009-03-06 00:01:42 +01:00
|
|
|
int flags;
|
2018-03-09 09:59:55 +01:00
|
|
|
int suspend_cnt; /* Needs to be accessed atomically */
|
2013-04-02 21:07:33 +02:00
|
|
|
bool skip_flush;
|
2018-07-03 10:53:45 +02:00
|
|
|
bool use_io_thread;
|
2018-06-08 05:55:07 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* State used only in the thread "owning" the monitor.
|
2018-07-03 10:53:46 +02:00
|
|
|
* If @use_io_thread, this is @mon_iothread.
|
2018-06-08 05:55:07 +02:00
|
|
|
* Else, it's the main thread.
|
|
|
|
* These members can be safely accessed without locks.
|
|
|
|
*/
|
2009-03-06 00:01:42 +01:00
|
|
|
ReadLineState *rs;
|
2018-06-08 05:55:07 +02:00
|
|
|
|
2015-03-06 19:35:59 +01:00
|
|
|
MonitorQMP qmp;
|
2017-10-17 10:16:22 +02:00
|
|
|
gchar *mon_cpu_path;
|
2014-10-07 13:59:15 +02:00
|
|
|
BlockCompletionFunc *password_completion_cb;
|
2009-03-06 00:01:42 +01:00
|
|
|
void *password_opaque;
|
2013-08-27 14:38:20 +02:00
|
|
|
mon_cmd_t *cmd_table;
|
2018-03-09 09:59:51 +01:00
|
|
|
QTAILQ_ENTRY(Monitor) entry;
|
2018-06-08 05:55:05 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The per-monitor lock. We can't access guest memory when holding
|
|
|
|
* the lock.
|
|
|
|
*/
|
|
|
|
QemuMutex mon_lock;
|
|
|
|
|
|
|
|
/*
|
2018-07-03 10:53:57 +02:00
|
|
|
* Members that are protected by the per-monitor lock
|
2018-06-08 05:55:05 +02:00
|
|
|
*/
|
2018-06-08 05:55:06 +02:00
|
|
|
QLIST_HEAD(, mon_fd_t) fds;
|
2018-06-08 05:55:05 +02:00
|
|
|
QString *outbuf;
|
|
|
|
guint out_watch;
|
|
|
|
/* Read under either BQL or mon_lock, written with BQL+mon_lock. */
|
|
|
|
int mux_out;
|
2009-03-06 00:01:29 +01:00
|
|
|
};
|
|
|
|
|
2018-07-03 10:53:57 +02:00
|
|
|
/* Shared monitor I/O thread */
|
2018-07-03 10:53:46 +02:00
|
|
|
IOThread *mon_iothread;
|
|
|
|
|
|
|
|
/* Bottom half to dispatch the requests received from I/O thread */
|
|
|
|
QEMUBH *qmp_dispatcher_bh;
|
|
|
|
|
2018-03-26 08:38:55 +02:00
|
|
|
struct QMPRequest {
|
|
|
|
/* Owner of the request */
|
|
|
|
Monitor *mon;
|
2018-07-03 10:53:44 +02:00
|
|
|
/*
|
|
|
|
* Request object to be handled or Error to be reported
|
|
|
|
* (exactly one of them is non-null)
|
|
|
|
*/
|
2018-03-26 08:38:55 +02:00
|
|
|
QObject *req;
|
2018-07-03 10:53:44 +02:00
|
|
|
Error *err;
|
2018-03-26 08:38:55 +02:00
|
|
|
};
|
|
|
|
typedef struct QMPRequest QMPRequest;
|
|
|
|
|
2010-05-26 21:13:09 +02:00
|
|
|
/* QMP checker flags */
|
|
|
|
#define QMP_ACCEPT_UNKNOWNS 1
|
|
|
|
|
2018-12-05 21:37:36 +01:00
|
|
|
/* Protects mon_list, monitor_qapi_event_state, monitor_destroyed. */
|
2014-06-18 08:44:00 +02:00
|
|
|
static QemuMutex monitor_lock;
|
2018-06-08 05:55:08 +02:00
|
|
|
static GHashTable *monitor_qapi_event_state;
|
2018-12-06 11:58:10 +01:00
|
|
|
static QTAILQ_HEAD(, Monitor) mon_list;
|
2018-12-05 21:37:36 +01:00
|
|
|
static bool monitor_destroyed;
|
2018-06-08 05:55:08 +02:00
|
|
|
|
2018-06-08 05:55:11 +02:00
|
|
|
/* Protects mon_fdsets */
|
|
|
|
static QemuMutex mon_fdsets_lock;
|
2018-12-06 11:58:10 +01:00
|
|
|
static QLIST_HEAD(, MonFdset) mon_fdsets;
|
2018-06-08 05:55:11 +02:00
|
|
|
|
2012-08-14 22:43:48 +02:00
|
|
|
static int mon_refcount;
|
2004-08-01 23:52:19 +02:00
|
|
|
|
2011-10-12 05:32:41 +02:00
|
|
|
static mon_cmd_t mon_cmds[];
|
|
|
|
static mon_cmd_t info_cmds[];
|
2004-03-14 22:38:27 +01: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 13:32:27 +01:00
|
|
|
QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
|
2017-03-03 13:32:25 +01:00
|
|
|
|
monitor: Fix unsafe sharing of @cur_mon among threads
@cur_mon is null unless the main thread is running monitor code, either
HMP code within monitor_read(), or QMP code within
monitor_qmp_dispatch().
Use of @cur_mon outside the main thread is therefore unsafe.
Most of its uses are in monitor command handlers. These run in the main
thread.
However, there are also uses hiding elsewhere, such as in
error_vprintf(), and thus error_report(), making these functions unsafe
outside the main thread. No such unsafe uses are known at this time.
Regardless, this is an unnecessary trap. It's an ancient trap, though.
More recently, commit cf869d53172 "qmp: support out-of-band (oob)
execution" spiced things up: the monitor I/O thread assigns to @cur_mon
when executing commands out-of-band. Having two threads save, set and
restore @cur_mon without synchronization is definitely unsafe. We can
end up with @cur_mon null while the main thread runs monitor code, or
non-null while it runs non-monitor code.
We could fix this by making the I/O thread not mess with @cur_mon, but
that would leave the trap armed and ready.
Instead, make @cur_mon thread-local. It's now reliably null unless the
thread is running monitor code.
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
[peterx: update subject and commit message written by Markus]
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20180720033451.32710-1-peterx@redhat.com>
2018-07-20 05:34:51 +02:00
|
|
|
__thread Monitor *cur_mon;
|
2009-03-06 00:01:23 +01:00
|
|
|
|
2013-11-14 11:54:14 +01:00
|
|
|
static void monitor_command_cb(void *opaque, const char *cmdline,
|
|
|
|
void *readline_opaque);
|
2008-08-19 16:44:22 +02:00
|
|
|
|
2015-03-06 19:56:38 +01:00
|
|
|
/**
|
|
|
|
* Is @mon a QMP monitor?
|
|
|
|
*/
|
|
|
|
static inline bool monitor_is_qmp(const Monitor *mon)
|
2009-11-27 01:58:51 +01:00
|
|
|
{
|
|
|
|
return (mon->flags & MONITOR_USE_CONTROL);
|
|
|
|
}
|
|
|
|
|
2018-03-09 09:59:56 +01:00
|
|
|
/**
|
2018-07-03 10:53:57 +02:00
|
|
|
* Is @mon is using readline?
|
|
|
|
* Note: not all HMP monitors use readline, e.g., gdbserver has a
|
|
|
|
* non-interactive HMP monitor, so readline is not used there.
|
2018-03-09 09:59:56 +01:00
|
|
|
*/
|
|
|
|
static inline bool monitor_uses_readline(const Monitor *mon)
|
|
|
|
{
|
|
|
|
return mon->flags & MONITOR_USE_READLINE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool monitor_is_hmp_non_interactive(const Monitor *mon)
|
|
|
|
{
|
|
|
|
return !monitor_is_qmp(mon) && !monitor_uses_readline(mon);
|
|
|
|
}
|
|
|
|
|
2018-06-08 05:55:09 +02:00
|
|
|
/*
|
|
|
|
* Return the clock to use for recording an event's time.
|
2018-07-03 10:53:57 +02:00
|
|
|
* It's QEMU_CLOCK_REALTIME, except for qtests it's
|
|
|
|
* QEMU_CLOCK_VIRTUAL, to support testing rate limits.
|
2018-06-08 05:55:09 +02:00
|
|
|
* Beware: result is invalid before configure_accelerator().
|
|
|
|
*/
|
|
|
|
static inline QEMUClockType monitor_get_event_clock(void)
|
|
|
|
{
|
|
|
|
return qtest_enabled() ? QEMU_CLOCK_VIRTUAL : QEMU_CLOCK_REALTIME;
|
|
|
|
}
|
|
|
|
|
2015-03-06 20:01:05 +01:00
|
|
|
/**
|
|
|
|
* Is the current monitor, if any, a QMP monitor?
|
|
|
|
*/
|
|
|
|
bool monitor_cur_is_qmp(void)
|
2010-02-11 17:05:43 +01:00
|
|
|
{
|
2015-03-06 19:56:38 +01:00
|
|
|
return cur_mon && monitor_is_qmp(cur_mon);
|
2010-02-11 17:05:43 +01:00
|
|
|
}
|
|
|
|
|
2011-09-02 19:34:50 +02:00
|
|
|
void monitor_read_command(Monitor *mon, int show_prompt)
|
2009-03-06 00:01:42 +01:00
|
|
|
{
|
2009-12-14 21:53:23 +01:00
|
|
|
if (!mon->rs)
|
|
|
|
return;
|
|
|
|
|
2009-03-06 00:01:42 +01:00
|
|
|
readline_start(mon->rs, "(qemu) ", 0, monitor_command_cb, NULL);
|
|
|
|
if (show_prompt)
|
|
|
|
readline_show_prompt(mon->rs);
|
|
|
|
}
|
2005-11-22 00:25:50 +01:00
|
|
|
|
2011-09-02 19:34:50 +02:00
|
|
|
int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
|
|
|
|
void *opaque)
|
2009-03-06 00:01:15 +01:00
|
|
|
{
|
2015-03-12 17:26:46 +01:00
|
|
|
if (mon->rs) {
|
2009-03-06 00:01:51 +01:00
|
|
|
readline_start(mon->rs, "Password: ", 1, readline_func, opaque);
|
|
|
|
/* prompt is printed on return from the command handler */
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "terminal does not support password prompting\n");
|
|
|
|
return -ENOTTY;
|
|
|
|
}
|
2009-03-06 00:01:15 +01:00
|
|
|
}
|
|
|
|
|
2018-03-26 08:38:55 +02:00
|
|
|
static void qmp_request_free(QMPRequest *req)
|
|
|
|
{
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(req->req);
|
2018-07-03 10:53:44 +02:00
|
|
|
error_free(req->err);
|
2018-03-26 08:38:55 +02:00
|
|
|
g_free(req);
|
|
|
|
}
|
|
|
|
|
2018-07-03 10:53:57 +02:00
|
|
|
/* Caller must hold mon->qmp.qmp_queue_lock */
|
2018-03-26 08:38:55 +02:00
|
|
|
static void monitor_qmp_cleanup_req_queue_locked(Monitor *mon)
|
|
|
|
{
|
|
|
|
while (!g_queue_is_empty(mon->qmp.qmp_requests)) {
|
|
|
|
qmp_request_free(g_queue_pop_head(mon->qmp.qmp_requests));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void monitor_qmp_cleanup_queues(Monitor *mon)
|
|
|
|
{
|
|
|
|
qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
|
|
|
|
monitor_qmp_cleanup_req_queue_locked(mon);
|
|
|
|
qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-18 08:43:59 +02:00
|
|
|
static void monitor_flush_locked(Monitor *mon);
|
|
|
|
|
2013-03-19 10:57:56 +01:00
|
|
|
static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond,
|
|
|
|
void *opaque)
|
|
|
|
{
|
2013-07-16 20:19:41 +02:00
|
|
|
Monitor *mon = opaque;
|
|
|
|
|
2018-06-08 05:55:05 +02:00
|
|
|
qemu_mutex_lock(&mon->mon_lock);
|
2014-06-18 08:43:59 +02:00
|
|
|
mon->out_watch = 0;
|
|
|
|
monitor_flush_locked(mon);
|
2018-06-08 05:55:05 +02:00
|
|
|
qemu_mutex_unlock(&mon->mon_lock);
|
2013-03-19 10:57:56 +01:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2018-07-03 10:53:57 +02:00
|
|
|
/* Caller must hold mon->mon_lock */
|
2014-06-18 08:43:59 +02:00
|
|
|
static void monitor_flush_locked(Monitor *mon)
|
2004-08-01 23:52:19 +02:00
|
|
|
{
|
2013-03-19 10:57:56 +01:00
|
|
|
int rc;
|
2013-03-25 18:52:26 +01:00
|
|
|
size_t len;
|
|
|
|
const char *buf;
|
|
|
|
|
2013-04-02 21:07:33 +02:00
|
|
|
if (mon->skip_flush) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-03-25 18:52:26 +01:00
|
|
|
buf = qstring_get_str(mon->outbuf);
|
|
|
|
len = qstring_get_length(mon->outbuf);
|
2013-03-19 10:57:56 +01:00
|
|
|
|
2013-05-31 14:00:27 +02:00
|
|
|
if (len && !mon->mux_out) {
|
2016-10-22 11:52:55 +02:00
|
|
|
rc = qemu_chr_fe_write(&mon->chr, (const uint8_t *) buf, len);
|
2014-01-27 11:30:15 +01:00
|
|
|
if ((rc < 0 && errno != EAGAIN) || (rc == len)) {
|
|
|
|
/* all flushed or error */
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(mon->outbuf);
|
2013-03-25 18:52:26 +01:00
|
|
|
mon->outbuf = qstring_new();
|
2013-03-19 10:57:56 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (rc > 0) {
|
2016-05-18 00:00:15 +02:00
|
|
|
/* partial write */
|
2013-03-25 18:52:26 +01:00
|
|
|
QString *tmp = qstring_from_str(buf + rc);
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(mon->outbuf);
|
2013-03-25 18:52:26 +01:00
|
|
|
mon->outbuf = tmp;
|
2013-03-19 10:57:56 +01:00
|
|
|
}
|
2014-06-18 08:43:59 +02:00
|
|
|
if (mon->out_watch == 0) {
|
2016-10-22 11:52:52 +02:00
|
|
|
mon->out_watch =
|
2016-10-22 11:52:55 +02:00
|
|
|
qemu_chr_fe_add_watch(&mon->chr, G_IO_OUT | G_IO_HUP,
|
2016-10-22 11:52:52 +02:00
|
|
|
monitor_unblocked, mon);
|
2013-07-16 20:19:41 +02:00
|
|
|
}
|
2004-08-01 23:52:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-18 08:43:59 +02:00
|
|
|
void monitor_flush(Monitor *mon)
|
|
|
|
{
|
2018-06-08 05:55:05 +02:00
|
|
|
qemu_mutex_lock(&mon->mon_lock);
|
2014-06-18 08:43:59 +02:00
|
|
|
monitor_flush_locked(mon);
|
2018-06-08 05:55:05 +02:00
|
|
|
qemu_mutex_unlock(&mon->mon_lock);
|
2014-06-18 08:43:59 +02:00
|
|
|
}
|
|
|
|
|
2013-03-25 18:52:26 +01:00
|
|
|
/* flush at every end of line */
|
2019-04-17 21:06:36 +02:00
|
|
|
static int monitor_puts(Monitor *mon, const char *str)
|
2004-08-01 23:52:19 +02:00
|
|
|
{
|
2019-04-17 21:06:36 +02:00
|
|
|
int i;
|
2007-12-16 04:02:09 +01:00
|
|
|
char c;
|
2009-03-06 00:01:42 +01:00
|
|
|
|
2018-06-08 05:55:05 +02:00
|
|
|
qemu_mutex_lock(&mon->mon_lock);
|
2019-04-17 21:06:36 +02:00
|
|
|
for (i = 0; str[i]; i++) {
|
|
|
|
c = str[i];
|
2013-03-25 18:52:26 +01:00
|
|
|
if (c == '\n') {
|
|
|
|
qstring_append_chr(mon->outbuf, '\r');
|
|
|
|
}
|
|
|
|
qstring_append_chr(mon->outbuf, c);
|
|
|
|
if (c == '\n') {
|
2014-06-18 08:43:59 +02:00
|
|
|
monitor_flush_locked(mon);
|
2013-03-25 18:52:26 +01:00
|
|
|
}
|
2004-08-01 23:52:19 +02:00
|
|
|
}
|
2018-06-08 05:55:05 +02:00
|
|
|
qemu_mutex_unlock(&mon->mon_lock);
|
2019-04-17 21:06:36 +02:00
|
|
|
|
|
|
|
return i;
|
2004-08-01 23:52:19 +02:00
|
|
|
}
|
|
|
|
|
2019-04-17 21:06:36 +02:00
|
|
|
int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
|
2004-03-14 22:38:27 +01:00
|
|
|
{
|
2013-03-25 18:52:26 +01:00
|
|
|
char *buf;
|
2019-04-17 21:06:36 +02:00
|
|
|
int n;
|
2010-02-11 02:50:04 +01:00
|
|
|
|
2009-12-14 21:53:24 +01:00
|
|
|
if (!mon)
|
2019-04-17 21:06:36 +02:00
|
|
|
return -1;
|
2009-12-14 21:53:24 +01:00
|
|
|
|
2015-03-06 19:56:38 +01:00
|
|
|
if (monitor_is_qmp(mon)) {
|
2019-04-17 21:06:36 +02:00
|
|
|
return -1;
|
2009-11-27 01:59:05 +01:00
|
|
|
}
|
2010-02-11 02:50:04 +01:00
|
|
|
|
2013-03-25 18:52:26 +01:00
|
|
|
buf = g_strdup_vprintf(fmt, ap);
|
2019-04-17 21:06:36 +02:00
|
|
|
n = monitor_puts(mon, buf);
|
2013-03-25 18:52:26 +01:00
|
|
|
g_free(buf);
|
2019-04-17 21:06:36 +02:00
|
|
|
return n;
|
2004-03-14 22:38:27 +01:00
|
|
|
}
|
|
|
|
|
2019-04-17 21:06:36 +02:00
|
|
|
int monitor_printf(Monitor *mon, const char *fmt, ...)
|
2004-03-14 22:38:27 +01:00
|
|
|
{
|
2019-04-17 21:06:36 +02:00
|
|
|
int ret;
|
|
|
|
|
2004-08-01 23:52:19 +02:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
2019-04-17 21:06:36 +02:00
|
|
|
ret = monitor_vprintf(mon, fmt, ap);
|
2004-08-01 23:52:19 +02:00
|
|
|
va_end(ap);
|
2019-04-17 21:06:36 +02:00
|
|
|
return ret;
|
2004-03-14 22:38:27 +01:00
|
|
|
}
|
|
|
|
|
2018-08-29 15:40:34 +02:00
|
|
|
static void qmp_send_response(Monitor *mon, const QDict *rsp)
|
2009-11-27 01:58:58 +01:00
|
|
|
{
|
2018-08-29 15:40:34 +02:00
|
|
|
const QObject *data = QOBJECT(rsp);
|
2009-11-27 01:58:58 +01:00
|
|
|
QString *json;
|
|
|
|
|
2010-11-22 20:10:37 +01:00
|
|
|
json = mon->flags & MONITOR_USE_PRETTY ? qobject_to_json_pretty(data) :
|
|
|
|
qobject_to_json(data);
|
2009-11-27 01:58:58 +01:00
|
|
|
assert(json != NULL);
|
|
|
|
|
2010-02-11 02:50:04 +01:00
|
|
|
qstring_append_chr(json, '\n');
|
|
|
|
monitor_puts(mon, qstring_get_str(json));
|
2009-11-27 01:59:05 +01:00
|
|
|
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(json);
|
2009-11-27 01:58:58 +01: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 09:52:57 +01:00
|
|
|
static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = {
|
2015-10-15 17:08:33 +02:00
|
|
|
/* Limit guest-triggerable events to 1 per second */
|
|
|
|
[QAPI_EVENT_RTC_CHANGE] = { 1000 * SCALE_MS },
|
|
|
|
[QAPI_EVENT_WATCHDOG] = { 1000 * SCALE_MS },
|
|
|
|
[QAPI_EVENT_BALLOON_CHANGE] = { 1000 * SCALE_MS },
|
|
|
|
[QAPI_EVENT_QUORUM_REPORT_BAD] = { 1000 * SCALE_MS },
|
|
|
|
[QAPI_EVENT_QUORUM_FAILURE] = { 1000 * SCALE_MS },
|
|
|
|
[QAPI_EVENT_VSERPORT_CHANGE] = { 1000 * SCALE_MS },
|
|
|
|
};
|
|
|
|
|
2012-06-14 19:12:57 +02:00
|
|
|
/*
|
2018-07-03 10:53:57 +02:00
|
|
|
* Broadcast an event to all monitors.
|
|
|
|
* @qdict is the event object. Its member "event" must match @event.
|
|
|
|
* Caller must hold monitor_lock.
|
2012-06-14 19:12:57 +02:00
|
|
|
*/
|
2015-10-15 17:08:30 +02:00
|
|
|
static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict)
|
2012-06-14 19:12:57 +02:00
|
|
|
{
|
|
|
|
Monitor *mon;
|
|
|
|
|
2015-10-15 17:08:30 +02:00
|
|
|
trace_monitor_protocol_event_emit(event, qdict);
|
2018-03-09 09:59:51 +01:00
|
|
|
QTAILQ_FOREACH(mon, &mon_list, entry) {
|
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 13:32:27 +01:00
|
|
|
if (monitor_is_qmp(mon)
|
|
|
|
&& mon->qmp.commands != &qmp_cap_negotiation_commands) {
|
2018-08-29 15:40:36 +02:00
|
|
|
qmp_send_response(mon, qdict);
|
2012-06-14 19:12:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-15 17:08:34 +02:00
|
|
|
static void monitor_qapi_event_handler(void *opaque);
|
|
|
|
|
2012-06-14 19:12:57 +02:00
|
|
|
/*
|
|
|
|
* Queue a new event for emission to Monitor instances,
|
|
|
|
* applying any rate limiting if required.
|
|
|
|
*/
|
|
|
|
static void
|
monitor: temporary fix for dead-lock on event recursion
With a Spice port chardev, it is possible to reenter
monitor_qapi_event_queue() (when the client disconnects for
example). This will dead-lock on monitor_lock.
Instead, use some TLS variables to check for recursion and queue the
events.
Fixes:
(gdb) bt
#0 0x00007fa69e7217fd in __lll_lock_wait () at /lib64/libpthread.so.0
#1 0x00007fa69e71acf4 in pthread_mutex_lock () at /lib64/libpthread.so.0
#2 0x0000563303567619 in qemu_mutex_lock_impl (mutex=0x563303d3e220 <monitor_lock>, file=0x5633036589a8 "/home/elmarco/src/qq/monitor.c", line=645) at /home/elmarco/src/qq/util/qemu-thread-posix.c:66
#3 0x0000563302fa6c25 in monitor_qapi_event_queue (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x56330602bde0, errp=0x7ffc6ab5e728) at /home/elmarco/src/qq/monitor.c:645
#4 0x0000563303549aca in qapi_event_send_spice_disconnected (server=0x563305afd630, client=0x563305745360, errp=0x563303d8d0f0 <error_abort>) at qapi/qapi-events-ui.c:149
#5 0x00005633033e600f in channel_event (event=3, info=0x5633061b0050) at /home/elmarco/src/qq/ui/spice-core.c:235
#6 0x00007fa69f6c86bb in reds_handle_channel_event (reds=<optimized out>, event=3, info=0x5633061b0050) at reds.c:316
#7 0x00007fa69f6b193b in main_dispatcher_self_handle_channel_event (info=0x5633061b0050, event=3, self=0x563304e088c0) at main-dispatcher.c:197
#8 0x00007fa69f6b193b in main_dispatcher_channel_event (self=0x563304e088c0, event=event@entry=3, info=0x5633061b0050) at main-dispatcher.c:197
#9 0x00007fa69f6d0833 in red_stream_push_channel_event (s=s@entry=0x563305ad8f50, event=event@entry=3) at red-stream.c:414
#10 0x00007fa69f6d086b in red_stream_free (s=0x563305ad8f50) at red-stream.c:388
#11 0x00007fa69f6b7ddc in red_channel_client_finalize (object=0x563304df2360) at red-channel-client.c:347
#12 0x00007fa6a56b7fb9 in g_object_unref () at /lib64/libgobject-2.0.so.0
#13 0x00007fa69f6ba212 in red_channel_client_push (rcc=0x563304df2360) at red-channel-client.c:1341
#14 0x00007fa69f68b259 in red_char_device_send_msg_to_client (client=<optimized out>, msg=0x5633059b6310, dev=0x563304e08bc0) at char-device.c:305
#15 0x00007fa69f68b259 in red_char_device_send_msg_to_clients (msg=0x5633059b6310, dev=0x563304e08bc0) at char-device.c:305
#16 0x00007fa69f68b259 in red_char_device_read_from_device (dev=0x563304e08bc0) at char-device.c:353
#17 0x000056330317d01d in spice_chr_write (chr=0x563304cafe20, buf=0x563304cc50b0 "{\"timestamp\": {\"seconds\": 1532944763, \"microseconds\": 326636}, \"event\": \"SHUTDOWN\", \"data\": {\"guest\": false}}\r\n", len=111) at /home/elmarco/src/qq/chardev/spice.c:199
#18 0x00005633034deee7 in qemu_chr_write_buffer (s=0x563304cafe20, buf=0x563304cc50b0 "{\"timestamp\": {\"seconds\": 1532944763, \"microseconds\": 326636}, \"event\": \"SHUTDOWN\", \"data\": {\"guest\": false}}\r\n", len=111, offset=0x7ffc6ab5ea70, write_all=false) at /home/elmarco/src/qq/chardev/char.c:112
#19 0x00005633034df054 in qemu_chr_write (s=0x563304cafe20, buf=0x563304cc50b0 "{\"timestamp\": {\"seconds\": 1532944763, \"microseconds\": 326636}, \"event\": \"SHUTDOWN\", \"data\": {\"guest\": false}}\r\n", len=111, write_all=false) at /home/elmarco/src/qq/chardev/char.c:147
#20 0x00005633034e1e13 in qemu_chr_fe_write (be=0x563304dbb800, buf=0x563304cc50b0 "{\"timestamp\": {\"seconds\": 1532944763, \"microseconds\": 326636}, \"event\": \"SHUTDOWN\", \"data\": {\"guest\": false}}\r\n", len=111) at /home/elmarco/src/qq/chardev/char-fe.c:42
#21 0x0000563302fa6334 in monitor_flush_locked (mon=0x563304dbb800) at /home/elmarco/src/qq/monitor.c:425
#22 0x0000563302fa6520 in monitor_puts (mon=0x563304dbb800, str=0x563305de7e9e "") at /home/elmarco/src/qq/monitor.c:468
#23 0x0000563302fa680c in qmp_send_response (mon=0x563304dbb800, rsp=0x563304df5730) at /home/elmarco/src/qq/monitor.c:517
#24 0x0000563302fa6905 in qmp_queue_response (mon=0x563304dbb800, rsp=0x563304df5730) at /home/elmarco/src/qq/monitor.c:538
#25 0x0000563302fa6b5b in monitor_qapi_event_emit (event=QAPI_EVENT_SHUTDOWN, qdict=0x563304df5730) at /home/elmarco/src/qq/monitor.c:624
#26 0x0000563302fa6c4b in monitor_qapi_event_queue (event=QAPI_EVENT_SHUTDOWN, qdict=0x563304df5730, errp=0x7ffc6ab5ed00) at /home/elmarco/src/qq/monitor.c:649
#27 0x0000563303548cce in qapi_event_send_shutdown (guest=false, errp=0x563303d8d0f0 <error_abort>) at qapi/qapi-events-run-state.c:58
#28 0x000056330313bcd7 in main_loop_should_exit () at /home/elmarco/src/qq/vl.c:1822
#29 0x000056330313bde3 in main_loop () at /home/elmarco/src/qq/vl.c:1862
#30 0x0000563303143781 in main (argc=3, argv=0x7ffc6ab5f068, envp=0x7ffc6ab5f088) at /home/elmarco/src/qq/vl.c:4644
Note that error report is now moved to the first caller, which may
receive an error for a recursed event. This is probably fine (95% of
callers use &error_abort, the rest have NULL error and ignore it)
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20180731150144.14022-1-marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[*_no_recurse renamed to *_no_reenter, local variables reordered]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-07-31 17:01:44 +02:00
|
|
|
monitor_qapi_event_queue_no_reenter(QAPIEvent event, QDict *qdict)
|
2012-06-14 19:12:57 +02:00
|
|
|
{
|
2015-10-15 17:08:33 +02:00
|
|
|
MonitorQAPIEventConf *evconf;
|
2014-06-18 08:43:31 +02:00
|
|
|
MonitorQAPIEventState *evstate;
|
2012-06-14 19:12:57 +02: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 09:52:57 +01:00
|
|
|
assert(event < QAPI_EVENT__MAX);
|
2015-10-15 17:08:33 +02:00
|
|
|
evconf = &monitor_qapi_event_conf[event];
|
|
|
|
trace_monitor_protocol_event_queue(event, qdict, evconf->rate);
|
2012-06-14 19:12:57 +02:00
|
|
|
|
2014-06-18 08:44:00 +02:00
|
|
|
qemu_mutex_lock(&monitor_lock);
|
monitor: Simplify event throttling
The event throttling state machine is hard to understand. I'm not
sure it's entirely correct. Rewrite it in a more straightforward
manner:
State 1: No event sent recently (less than evconf->rate ns ago)
Invariant: evstate->timer is not pending, evstate->qdict is null
On event: send event, arm timer, goto state 2
State 2: Event sent recently, no additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is null
On event: store it in evstate->qdict, goto state 3
On timer: goto state 1
State 3: Event sent recently, additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is non-null
On event: store it in evstate->qdict, goto state 3
On timer: send evstate->qdict, clear evstate->qdict,
arm timer, goto state 2
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1444921716-9511-3-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-10-15 17:08:31 +02:00
|
|
|
|
2015-10-15 17:08:33 +02:00
|
|
|
if (!evconf->rate) {
|
monitor: Simplify event throttling
The event throttling state machine is hard to understand. I'm not
sure it's entirely correct. Rewrite it in a more straightforward
manner:
State 1: No event sent recently (less than evconf->rate ns ago)
Invariant: evstate->timer is not pending, evstate->qdict is null
On event: send event, arm timer, goto state 2
State 2: Event sent recently, no additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is null
On event: store it in evstate->qdict, goto state 3
On timer: goto state 1
State 3: Event sent recently, additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is non-null
On event: store it in evstate->qdict, goto state 3
On timer: send evstate->qdict, clear evstate->qdict,
arm timer, goto state 2
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1444921716-9511-3-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-10-15 17:08:31 +02:00
|
|
|
/* Unthrottled event */
|
2015-10-15 17:08:30 +02:00
|
|
|
monitor_qapi_event_emit(event, qdict);
|
2012-06-14 19:12:57 +02:00
|
|
|
} else {
|
2018-02-24 16:40:29 +01:00
|
|
|
QDict *data = qobject_to(QDict, qdict_get(qdict, "data"));
|
2015-10-15 17:08:35 +02:00
|
|
|
MonitorQAPIEventState key = { .event = event, .data = data };
|
2015-10-15 17:08:34 +02:00
|
|
|
|
|
|
|
evstate = g_hash_table_lookup(monitor_qapi_event_state, &key);
|
|
|
|
assert(!evstate || timer_pending(evstate->timer));
|
|
|
|
|
|
|
|
if (evstate) {
|
monitor: Simplify event throttling
The event throttling state machine is hard to understand. I'm not
sure it's entirely correct. Rewrite it in a more straightforward
manner:
State 1: No event sent recently (less than evconf->rate ns ago)
Invariant: evstate->timer is not pending, evstate->qdict is null
On event: send event, arm timer, goto state 2
State 2: Event sent recently, no additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is null
On event: store it in evstate->qdict, goto state 3
On timer: goto state 1
State 3: Event sent recently, additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is non-null
On event: store it in evstate->qdict, goto state 3
On timer: send evstate->qdict, clear evstate->qdict,
arm timer, goto state 2
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1444921716-9511-3-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-10-15 17:08:31 +02:00
|
|
|
/*
|
2015-10-15 17:08:33 +02:00
|
|
|
* Timer is pending for (at least) evconf->rate ns after
|
monitor: Simplify event throttling
The event throttling state machine is hard to understand. I'm not
sure it's entirely correct. Rewrite it in a more straightforward
manner:
State 1: No event sent recently (less than evconf->rate ns ago)
Invariant: evstate->timer is not pending, evstate->qdict is null
On event: send event, arm timer, goto state 2
State 2: Event sent recently, no additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is null
On event: store it in evstate->qdict, goto state 3
On timer: goto state 1
State 3: Event sent recently, additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is non-null
On event: store it in evstate->qdict, goto state 3
On timer: send evstate->qdict, clear evstate->qdict,
arm timer, goto state 2
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1444921716-9511-3-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-10-15 17:08:31 +02:00
|
|
|
* last send. Store event for sending when timer fires,
|
|
|
|
* replacing a prior stored event if any.
|
2012-06-14 19:12:57 +02:00
|
|
|
*/
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(evstate->qdict);
|
2018-04-19 17:01:44 +02:00
|
|
|
evstate->qdict = qobject_ref(qdict);
|
2012-06-14 19:12:57 +02:00
|
|
|
} else {
|
monitor: Simplify event throttling
The event throttling state machine is hard to understand. I'm not
sure it's entirely correct. Rewrite it in a more straightforward
manner:
State 1: No event sent recently (less than evconf->rate ns ago)
Invariant: evstate->timer is not pending, evstate->qdict is null
On event: send event, arm timer, goto state 2
State 2: Event sent recently, no additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is null
On event: store it in evstate->qdict, goto state 3
On timer: goto state 1
State 3: Event sent recently, additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is non-null
On event: store it in evstate->qdict, goto state 3
On timer: send evstate->qdict, clear evstate->qdict,
arm timer, goto state 2
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1444921716-9511-3-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-10-15 17:08:31 +02:00
|
|
|
/*
|
2015-10-15 17:08:33 +02:00
|
|
|
* Last send was (at least) evconf->rate ns ago.
|
monitor: Simplify event throttling
The event throttling state machine is hard to understand. I'm not
sure it's entirely correct. Rewrite it in a more straightforward
manner:
State 1: No event sent recently (less than evconf->rate ns ago)
Invariant: evstate->timer is not pending, evstate->qdict is null
On event: send event, arm timer, goto state 2
State 2: Event sent recently, no additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is null
On event: store it in evstate->qdict, goto state 3
On timer: goto state 1
State 3: Event sent recently, additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is non-null
On event: store it in evstate->qdict, goto state 3
On timer: send evstate->qdict, clear evstate->qdict,
arm timer, goto state 2
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1444921716-9511-3-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-10-15 17:08:31 +02:00
|
|
|
* Send immediately, and arm the timer to call
|
2015-10-15 17:08:33 +02:00
|
|
|
* monitor_qapi_event_handler() in evconf->rate ns. Any
|
monitor: Simplify event throttling
The event throttling state machine is hard to understand. I'm not
sure it's entirely correct. Rewrite it in a more straightforward
manner:
State 1: No event sent recently (less than evconf->rate ns ago)
Invariant: evstate->timer is not pending, evstate->qdict is null
On event: send event, arm timer, goto state 2
State 2: Event sent recently, no additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is null
On event: store it in evstate->qdict, goto state 3
On timer: goto state 1
State 3: Event sent recently, additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is non-null
On event: store it in evstate->qdict, goto state 3
On timer: send evstate->qdict, clear evstate->qdict,
arm timer, goto state 2
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1444921716-9511-3-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-10-15 17:08:31 +02:00
|
|
|
* events arriving before then will be delayed until then.
|
|
|
|
*/
|
2018-06-08 05:55:09 +02:00
|
|
|
int64_t now = qemu_clock_get_ns(monitor_get_event_clock());
|
monitor: Simplify event throttling
The event throttling state machine is hard to understand. I'm not
sure it's entirely correct. Rewrite it in a more straightforward
manner:
State 1: No event sent recently (less than evconf->rate ns ago)
Invariant: evstate->timer is not pending, evstate->qdict is null
On event: send event, arm timer, goto state 2
State 2: Event sent recently, no additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is null
On event: store it in evstate->qdict, goto state 3
On timer: goto state 1
State 3: Event sent recently, additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is non-null
On event: store it in evstate->qdict, goto state 3
On timer: send evstate->qdict, clear evstate->qdict,
arm timer, goto state 2
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1444921716-9511-3-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-10-15 17:08:31 +02:00
|
|
|
|
2015-10-15 17:08:30 +02:00
|
|
|
monitor_qapi_event_emit(event, qdict);
|
2015-10-15 17:08:34 +02:00
|
|
|
|
|
|
|
evstate = g_new(MonitorQAPIEventState, 1);
|
|
|
|
evstate->event = event;
|
2018-04-19 17:01:44 +02:00
|
|
|
evstate->data = qobject_ref(data);
|
2015-10-15 17:08:34 +02:00
|
|
|
evstate->qdict = NULL;
|
2018-06-08 05:55:09 +02:00
|
|
|
evstate->timer = timer_new_ns(monitor_get_event_clock(),
|
2015-10-15 17:08:34 +02:00
|
|
|
monitor_qapi_event_handler,
|
|
|
|
evstate);
|
|
|
|
g_hash_table_add(monitor_qapi_event_state, evstate);
|
2015-10-15 17:08:33 +02:00
|
|
|
timer_mod_ns(evstate->timer, now + evconf->rate);
|
2012-06-14 19:12:57 +02:00
|
|
|
}
|
|
|
|
}
|
monitor: Simplify event throttling
The event throttling state machine is hard to understand. I'm not
sure it's entirely correct. Rewrite it in a more straightforward
manner:
State 1: No event sent recently (less than evconf->rate ns ago)
Invariant: evstate->timer is not pending, evstate->qdict is null
On event: send event, arm timer, goto state 2
State 2: Event sent recently, no additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is null
On event: store it in evstate->qdict, goto state 3
On timer: goto state 1
State 3: Event sent recently, additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is non-null
On event: store it in evstate->qdict, goto state 3
On timer: send evstate->qdict, clear evstate->qdict,
arm timer, goto state 2
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1444921716-9511-3-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-10-15 17:08:31 +02:00
|
|
|
|
2014-06-18 08:44:00 +02:00
|
|
|
qemu_mutex_unlock(&monitor_lock);
|
2012-06-14 19:12:57 +02:00
|
|
|
}
|
|
|
|
|
qapi: Eliminate indirection through qmp_event_get_func_emit()
The qapi_event_send_FOO() functions emit events like this:
QMPEventFuncEmit emit;
emit = qmp_event_get_func_emit();
if (!emit) {
return;
}
qmp = qmp_event_build_dict("FOO");
[put event arguments into @qmp...]
emit(QAPI_EVENT_FOO, qmp);
The value of qmp_event_get_func_emit() depends only on the program:
* In qemu-system-FOO, it's always monitor_qapi_event_queue.
* In tests/test-qmp-event, it's always event_test_emit.
* In all other programs, it's always null.
This is exactly the kind of dependence the linker is supposed to
resolve; we don't actually need an indirection.
Note that things would fall apart if we linked more than one QAPI
schema into a single program: each set of qapi_event_send_FOO() uses
its own event enumeration, yet they share a single emit function.
Which takes the event enumeration as an argument. Which one if
there's more than one?
More seriously: how does this work even now? qemu-system-FOO wants
QAPIEvent, and passes a function taking that to
qmp_event_set_func_emit(). test-qmp-event wants test_QAPIEvent, and
passes a function taking that to qmp_event_set_func_emit().
It works by type trickery, of course:
typedef void (*QMPEventFuncEmit)(unsigned event, QDict *dict);
void qmp_event_set_func_emit(QMPEventFuncEmit emit);
QMPEventFuncEmit qmp_event_get_func_emit(void);
We use unsigned instead of the enumeration type. Relies on both
enumerations boiling down to unsigned, which happens to be true for
the compilers we use.
Clean this up as follows:
* Generate qapi_event_send_FOO() that call PREFIX_qapi_event_emit()
instead of the value of qmp_event_set_func_emit().
* Generate a prototype for PREFIX_qapi_event_emit() into
qapi-events.h.
* PREFIX_ is empty for qapi/qapi-schema.json, and test_ for
tests/qapi-schema/qapi-schema-test.json. It's qga_ for
qga/qapi-schema.json, and doc-good- for
tests/qapi-schema/doc-good.json, but those don't define any events.
* Rename monitor_qapi_event_queue() to qapi_event_emit() instead of
passing it to qmp_event_set_func_emit(). This takes care of
qemu-system-FOO.
* Rename event_test_emit() to test_qapi_event_emit() instead of
passing it to qmp_event_set_func_emit(). This takes care of
tests/test-qmp-event.
* Add a qapi_event_emit() that does nothing to stubs/monitor.c. This
takes care of all other programs that link code emitting QMP events.
* Drop qmp_event_set_func_emit(), qmp_event_get_func_emit().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20181218182234.28876-3-armbru@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
[Commit message typos fixed]
2018-12-18 19:22:21 +01:00
|
|
|
void qapi_event_emit(QAPIEvent event, QDict *qdict)
|
monitor: temporary fix for dead-lock on event recursion
With a Spice port chardev, it is possible to reenter
monitor_qapi_event_queue() (when the client disconnects for
example). This will dead-lock on monitor_lock.
Instead, use some TLS variables to check for recursion and queue the
events.
Fixes:
(gdb) bt
#0 0x00007fa69e7217fd in __lll_lock_wait () at /lib64/libpthread.so.0
#1 0x00007fa69e71acf4 in pthread_mutex_lock () at /lib64/libpthread.so.0
#2 0x0000563303567619 in qemu_mutex_lock_impl (mutex=0x563303d3e220 <monitor_lock>, file=0x5633036589a8 "/home/elmarco/src/qq/monitor.c", line=645) at /home/elmarco/src/qq/util/qemu-thread-posix.c:66
#3 0x0000563302fa6c25 in monitor_qapi_event_queue (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x56330602bde0, errp=0x7ffc6ab5e728) at /home/elmarco/src/qq/monitor.c:645
#4 0x0000563303549aca in qapi_event_send_spice_disconnected (server=0x563305afd630, client=0x563305745360, errp=0x563303d8d0f0 <error_abort>) at qapi/qapi-events-ui.c:149
#5 0x00005633033e600f in channel_event (event=3, info=0x5633061b0050) at /home/elmarco/src/qq/ui/spice-core.c:235
#6 0x00007fa69f6c86bb in reds_handle_channel_event (reds=<optimized out>, event=3, info=0x5633061b0050) at reds.c:316
#7 0x00007fa69f6b193b in main_dispatcher_self_handle_channel_event (info=0x5633061b0050, event=3, self=0x563304e088c0) at main-dispatcher.c:197
#8 0x00007fa69f6b193b in main_dispatcher_channel_event (self=0x563304e088c0, event=event@entry=3, info=0x5633061b0050) at main-dispatcher.c:197
#9 0x00007fa69f6d0833 in red_stream_push_channel_event (s=s@entry=0x563305ad8f50, event=event@entry=3) at red-stream.c:414
#10 0x00007fa69f6d086b in red_stream_free (s=0x563305ad8f50) at red-stream.c:388
#11 0x00007fa69f6b7ddc in red_channel_client_finalize (object=0x563304df2360) at red-channel-client.c:347
#12 0x00007fa6a56b7fb9 in g_object_unref () at /lib64/libgobject-2.0.so.0
#13 0x00007fa69f6ba212 in red_channel_client_push (rcc=0x563304df2360) at red-channel-client.c:1341
#14 0x00007fa69f68b259 in red_char_device_send_msg_to_client (client=<optimized out>, msg=0x5633059b6310, dev=0x563304e08bc0) at char-device.c:305
#15 0x00007fa69f68b259 in red_char_device_send_msg_to_clients (msg=0x5633059b6310, dev=0x563304e08bc0) at char-device.c:305
#16 0x00007fa69f68b259 in red_char_device_read_from_device (dev=0x563304e08bc0) at char-device.c:353
#17 0x000056330317d01d in spice_chr_write (chr=0x563304cafe20, buf=0x563304cc50b0 "{\"timestamp\": {\"seconds\": 1532944763, \"microseconds\": 326636}, \"event\": \"SHUTDOWN\", \"data\": {\"guest\": false}}\r\n", len=111) at /home/elmarco/src/qq/chardev/spice.c:199
#18 0x00005633034deee7 in qemu_chr_write_buffer (s=0x563304cafe20, buf=0x563304cc50b0 "{\"timestamp\": {\"seconds\": 1532944763, \"microseconds\": 326636}, \"event\": \"SHUTDOWN\", \"data\": {\"guest\": false}}\r\n", len=111, offset=0x7ffc6ab5ea70, write_all=false) at /home/elmarco/src/qq/chardev/char.c:112
#19 0x00005633034df054 in qemu_chr_write (s=0x563304cafe20, buf=0x563304cc50b0 "{\"timestamp\": {\"seconds\": 1532944763, \"microseconds\": 326636}, \"event\": \"SHUTDOWN\", \"data\": {\"guest\": false}}\r\n", len=111, write_all=false) at /home/elmarco/src/qq/chardev/char.c:147
#20 0x00005633034e1e13 in qemu_chr_fe_write (be=0x563304dbb800, buf=0x563304cc50b0 "{\"timestamp\": {\"seconds\": 1532944763, \"microseconds\": 326636}, \"event\": \"SHUTDOWN\", \"data\": {\"guest\": false}}\r\n", len=111) at /home/elmarco/src/qq/chardev/char-fe.c:42
#21 0x0000563302fa6334 in monitor_flush_locked (mon=0x563304dbb800) at /home/elmarco/src/qq/monitor.c:425
#22 0x0000563302fa6520 in monitor_puts (mon=0x563304dbb800, str=0x563305de7e9e "") at /home/elmarco/src/qq/monitor.c:468
#23 0x0000563302fa680c in qmp_send_response (mon=0x563304dbb800, rsp=0x563304df5730) at /home/elmarco/src/qq/monitor.c:517
#24 0x0000563302fa6905 in qmp_queue_response (mon=0x563304dbb800, rsp=0x563304df5730) at /home/elmarco/src/qq/monitor.c:538
#25 0x0000563302fa6b5b in monitor_qapi_event_emit (event=QAPI_EVENT_SHUTDOWN, qdict=0x563304df5730) at /home/elmarco/src/qq/monitor.c:624
#26 0x0000563302fa6c4b in monitor_qapi_event_queue (event=QAPI_EVENT_SHUTDOWN, qdict=0x563304df5730, errp=0x7ffc6ab5ed00) at /home/elmarco/src/qq/monitor.c:649
#27 0x0000563303548cce in qapi_event_send_shutdown (guest=false, errp=0x563303d8d0f0 <error_abort>) at qapi/qapi-events-run-state.c:58
#28 0x000056330313bcd7 in main_loop_should_exit () at /home/elmarco/src/qq/vl.c:1822
#29 0x000056330313bde3 in main_loop () at /home/elmarco/src/qq/vl.c:1862
#30 0x0000563303143781 in main (argc=3, argv=0x7ffc6ab5f068, envp=0x7ffc6ab5f088) at /home/elmarco/src/qq/vl.c:4644
Note that error report is now moved to the first caller, which may
receive an error for a recursed event. This is probably fine (95% of
callers use &error_abort, the rest have NULL error and ignore it)
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20180731150144.14022-1-marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[*_no_recurse renamed to *_no_reenter, local variables reordered]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-07-31 17:01:44 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* monitor_qapi_event_queue_no_reenter() is not reentrant: it
|
|
|
|
* would deadlock on monitor_lock. Work around by queueing
|
|
|
|
* events in thread-local storage.
|
|
|
|
* TODO: remove this, make it re-enter safe.
|
|
|
|
*/
|
|
|
|
typedef struct MonitorQapiEvent {
|
|
|
|
QAPIEvent event;
|
|
|
|
QDict *qdict;
|
|
|
|
QSIMPLEQ_ENTRY(MonitorQapiEvent) entry;
|
|
|
|
} MonitorQapiEvent;
|
|
|
|
static __thread QSIMPLEQ_HEAD(, MonitorQapiEvent) event_queue;
|
|
|
|
static __thread bool reentered;
|
|
|
|
MonitorQapiEvent *ev;
|
|
|
|
|
|
|
|
if (!reentered) {
|
|
|
|
QSIMPLEQ_INIT(&event_queue);
|
|
|
|
}
|
|
|
|
|
|
|
|
ev = g_new(MonitorQapiEvent, 1);
|
|
|
|
ev->qdict = qobject_ref(qdict);
|
|
|
|
ev->event = event;
|
|
|
|
QSIMPLEQ_INSERT_TAIL(&event_queue, ev, entry);
|
|
|
|
if (reentered) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
reentered = true;
|
|
|
|
|
|
|
|
while ((ev = QSIMPLEQ_FIRST(&event_queue)) != NULL) {
|
|
|
|
QSIMPLEQ_REMOVE_HEAD(&event_queue, entry);
|
|
|
|
monitor_qapi_event_queue_no_reenter(ev->event, ev->qdict);
|
|
|
|
qobject_unref(ev->qdict);
|
|
|
|
g_free(ev);
|
|
|
|
}
|
|
|
|
|
|
|
|
reentered = false;
|
|
|
|
}
|
|
|
|
|
2012-06-14 19:12:57 +02:00
|
|
|
/*
|
2015-10-15 17:08:33 +02:00
|
|
|
* This function runs evconf->rate ns after sending a throttled
|
monitor: Simplify event throttling
The event throttling state machine is hard to understand. I'm not
sure it's entirely correct. Rewrite it in a more straightforward
manner:
State 1: No event sent recently (less than evconf->rate ns ago)
Invariant: evstate->timer is not pending, evstate->qdict is null
On event: send event, arm timer, goto state 2
State 2: Event sent recently, no additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is null
On event: store it in evstate->qdict, goto state 3
On timer: goto state 1
State 3: Event sent recently, additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is non-null
On event: store it in evstate->qdict, goto state 3
On timer: send evstate->qdict, clear evstate->qdict,
arm timer, goto state 2
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1444921716-9511-3-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-10-15 17:08:31 +02:00
|
|
|
* event.
|
|
|
|
* If another event has since been stored, send it.
|
2012-06-14 19:12:57 +02:00
|
|
|
*/
|
2014-06-18 08:43:31 +02:00
|
|
|
static void monitor_qapi_event_handler(void *opaque)
|
2012-06-14 19:12:57 +02:00
|
|
|
{
|
2014-06-18 08:43:31 +02:00
|
|
|
MonitorQAPIEventState *evstate = opaque;
|
2015-10-15 17:08:33 +02:00
|
|
|
MonitorQAPIEventConf *evconf = &monitor_qapi_event_conf[evstate->event];
|
2012-06-14 19:12:57 +02:00
|
|
|
|
monitor: Simplify event throttling
The event throttling state machine is hard to understand. I'm not
sure it's entirely correct. Rewrite it in a more straightforward
manner:
State 1: No event sent recently (less than evconf->rate ns ago)
Invariant: evstate->timer is not pending, evstate->qdict is null
On event: send event, arm timer, goto state 2
State 2: Event sent recently, no additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is null
On event: store it in evstate->qdict, goto state 3
On timer: goto state 1
State 3: Event sent recently, additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is non-null
On event: store it in evstate->qdict, goto state 3
On timer: send evstate->qdict, clear evstate->qdict,
arm timer, goto state 2
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1444921716-9511-3-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-10-15 17:08:31 +02:00
|
|
|
trace_monitor_protocol_event_handler(evstate->event, evstate->qdict);
|
2014-06-18 08:44:00 +02:00
|
|
|
qemu_mutex_lock(&monitor_lock);
|
monitor: Simplify event throttling
The event throttling state machine is hard to understand. I'm not
sure it's entirely correct. Rewrite it in a more straightforward
manner:
State 1: No event sent recently (less than evconf->rate ns ago)
Invariant: evstate->timer is not pending, evstate->qdict is null
On event: send event, arm timer, goto state 2
State 2: Event sent recently, no additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is null
On event: store it in evstate->qdict, goto state 3
On timer: goto state 1
State 3: Event sent recently, additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is non-null
On event: store it in evstate->qdict, goto state 3
On timer: send evstate->qdict, clear evstate->qdict,
arm timer, goto state 2
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1444921716-9511-3-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-10-15 17:08:31 +02:00
|
|
|
|
2015-10-15 17:08:30 +02:00
|
|
|
if (evstate->qdict) {
|
2018-06-08 05:55:09 +02:00
|
|
|
int64_t now = qemu_clock_get_ns(monitor_get_event_clock());
|
monitor: Simplify event throttling
The event throttling state machine is hard to understand. I'm not
sure it's entirely correct. Rewrite it in a more straightforward
manner:
State 1: No event sent recently (less than evconf->rate ns ago)
Invariant: evstate->timer is not pending, evstate->qdict is null
On event: send event, arm timer, goto state 2
State 2: Event sent recently, no additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is null
On event: store it in evstate->qdict, goto state 3
On timer: goto state 1
State 3: Event sent recently, additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is non-null
On event: store it in evstate->qdict, goto state 3
On timer: send evstate->qdict, clear evstate->qdict,
arm timer, goto state 2
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1444921716-9511-3-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-10-15 17:08:31 +02:00
|
|
|
|
2015-10-15 17:08:30 +02:00
|
|
|
monitor_qapi_event_emit(evstate->event, evstate->qdict);
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(evstate->qdict);
|
2015-10-15 17:08:30 +02:00
|
|
|
evstate->qdict = NULL;
|
2015-10-15 17:08:33 +02:00
|
|
|
timer_mod_ns(evstate->timer, now + evconf->rate);
|
2015-10-15 17:08:34 +02:00
|
|
|
} else {
|
|
|
|
g_hash_table_remove(monitor_qapi_event_state, evstate);
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(evstate->data);
|
2015-10-15 17:08:34 +02:00
|
|
|
timer_free(evstate->timer);
|
|
|
|
g_free(evstate);
|
2012-06-14 19:12:57 +02:00
|
|
|
}
|
monitor: Simplify event throttling
The event throttling state machine is hard to understand. I'm not
sure it's entirely correct. Rewrite it in a more straightforward
manner:
State 1: No event sent recently (less than evconf->rate ns ago)
Invariant: evstate->timer is not pending, evstate->qdict is null
On event: send event, arm timer, goto state 2
State 2: Event sent recently, no additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is null
On event: store it in evstate->qdict, goto state 3
On timer: goto state 1
State 3: Event sent recently, additional event being delayed
Invariant: evstate->timer is pending, evstate->qdict is non-null
On event: store it in evstate->qdict, goto state 3
On timer: send evstate->qdict, clear evstate->qdict,
arm timer, goto state 2
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1444921716-9511-3-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-10-15 17:08:31 +02:00
|
|
|
|
2014-06-18 08:44:00 +02:00
|
|
|
qemu_mutex_unlock(&monitor_lock);
|
2012-06-14 19:12:57 +02:00
|
|
|
}
|
|
|
|
|
2015-10-15 17:08:34 +02:00
|
|
|
static unsigned int qapi_event_throttle_hash(const void *key)
|
2012-06-14 19:12:57 +02:00
|
|
|
{
|
2015-10-15 17:08:34 +02:00
|
|
|
const MonitorQAPIEventState *evstate = key;
|
2015-10-15 17:08:35 +02:00
|
|
|
unsigned int hash = evstate->event * 255;
|
2012-06-14 19:12:57 +02:00
|
|
|
|
2015-10-15 17:08:35 +02:00
|
|
|
if (evstate->event == QAPI_EVENT_VSERPORT_CHANGE) {
|
|
|
|
hash += g_str_hash(qdict_get_str(evstate->data, "id"));
|
|
|
|
}
|
|
|
|
|
2016-03-10 12:55:25 +01:00
|
|
|
if (evstate->event == QAPI_EVENT_QUORUM_REPORT_BAD) {
|
|
|
|
hash += g_str_hash(qdict_get_str(evstate->data, "node-name"));
|
|
|
|
}
|
|
|
|
|
2015-10-15 17:08:35 +02:00
|
|
|
return hash;
|
2015-10-15 17:08:34 +02:00
|
|
|
}
|
2009-11-27 01:59:03 +01:00
|
|
|
|
2015-10-15 17:08:34 +02:00
|
|
|
static gboolean qapi_event_throttle_equal(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
const MonitorQAPIEventState *eva = a;
|
|
|
|
const MonitorQAPIEventState *evb = b;
|
|
|
|
|
2015-10-15 17:08:35 +02:00
|
|
|
if (eva->event != evb->event) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (eva->event == QAPI_EVENT_VSERPORT_CHANGE) {
|
|
|
|
return !strcmp(qdict_get_str(eva->data, "id"),
|
|
|
|
qdict_get_str(evb->data, "id"));
|
|
|
|
}
|
|
|
|
|
2016-03-10 12:55:25 +01:00
|
|
|
if (eva->event == QAPI_EVENT_QUORUM_REPORT_BAD) {
|
|
|
|
return !strcmp(qdict_get_str(eva->data, "node-name"),
|
|
|
|
qdict_get_str(evb->data, "node-name"));
|
|
|
|
}
|
|
|
|
|
2015-10-15 17:08:35 +02:00
|
|
|
return TRUE;
|
2015-10-15 17:08:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void monitor_qapi_event_init(void)
|
|
|
|
{
|
|
|
|
monitor_qapi_event_state = g_hash_table_new(qapi_event_throttle_hash,
|
|
|
|
qapi_event_throttle_equal);
|
2009-11-27 01:59:03 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 19:12:36 +01:00
|
|
|
static void handle_hmp_command(Monitor *mon, const char *cmdline);
|
2010-10-22 14:08:02 +02:00
|
|
|
|
2018-09-25 10:15:07 +02:00
|
|
|
static void monitor_iothread_init(void);
|
|
|
|
|
2018-03-09 09:59:52 +01:00
|
|
|
static void monitor_data_init(Monitor *mon, bool skip_flush,
|
2018-07-03 10:53:45 +02:00
|
|
|
bool use_io_thread)
|
2013-08-27 14:38:19 +02:00
|
|
|
{
|
2018-09-25 10:15:07 +02:00
|
|
|
if (use_io_thread && !mon_iothread) {
|
|
|
|
monitor_iothread_init();
|
|
|
|
}
|
2013-08-27 14:38:19 +02:00
|
|
|
memset(mon, 0, sizeof(Monitor));
|
2018-06-08 05:55:05 +02:00
|
|
|
qemu_mutex_init(&mon->mon_lock);
|
2018-03-09 09:59:57 +01:00
|
|
|
qemu_mutex_init(&mon->qmp.qmp_queue_lock);
|
2013-08-27 14:38:19 +02:00
|
|
|
mon->outbuf = qstring_new();
|
2013-08-27 14:38:20 +02:00
|
|
|
/* Use *mon_cmds by default. */
|
|
|
|
mon->cmd_table = mon_cmds;
|
2018-03-09 09:59:48 +01:00
|
|
|
mon->skip_flush = skip_flush;
|
2018-07-03 10:53:45 +02:00
|
|
|
mon->use_io_thread = use_io_thread;
|
2018-03-09 09:59:57 +01:00
|
|
|
mon->qmp.qmp_requests = g_queue_new();
|
2013-08-27 14:38:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void monitor_data_destroy(Monitor *mon)
|
|
|
|
{
|
2017-10-17 10:16:22 +02:00
|
|
|
g_free(mon->mon_cpu_path);
|
2017-01-26 21:49:13 +01:00
|
|
|
qemu_chr_fe_deinit(&mon->chr, false);
|
monitor: fix crash when leaving qemu with spice audio
Since aa5cb7f5e, the chardevs are being cleaned up when leaving
qemu. However, the monitor has still references to them, which may
lead to crashes when running atexit() and trying to send monitor
events:
#0 0x00007fffdb18f6f5 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007fffdb1912fa in __GI_abort () at abort.c:89
#2 0x0000555555c263e7 in error_exit (err=22, msg=0x555555d47980 <__func__.13537> "qemu_mutex_lock") at util/qemu-thread-posix.c:39
#3 0x0000555555c26488 in qemu_mutex_lock (mutex=0x5555567a2420) at util/qemu-thread-posix.c:66
#4 0x00005555558c52db in qemu_chr_fe_write (s=0x5555567a2420, buf=0x55555740dc40 "{\"timestamp\": {\"seconds\": 1470041716, \"microseconds\": 989699}, \"event\": \"SPICE_DISCONNECTED\", \"data\": {\"server\": {\"port\": \"5900\", \"family\": \"ipv4\", \"host\": \"127.0.0.1\"}, \"client\": {\"port\": \"40272\", \"f"..., len=240) at qemu-char.c:280
#5 0x0000555555787cad in monitor_flush_locked (mon=0x5555567bd9e0) at /home/elmarco/src/qemu/monitor.c:311
#6 0x0000555555787e46 in monitor_puts (mon=0x5555567bd9e0, str=0x5555567a44ef "") at /home/elmarco/src/qemu/monitor.c:353
#7 0x00005555557880fe in monitor_json_emitter (mon=0x5555567bd9e0, data=0x5555567c73a0) at /home/elmarco/src/qemu/monitor.c:401
#8 0x00005555557882d2 in monitor_qapi_event_emit (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x5555567c73a0) at /home/elmarco/src/qemu/monitor.c:472
#9 0x000055555578838f in monitor_qapi_event_queue (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x5555567c73a0, errp=0x7fffffffca88) at /home/elmarco/src/qemu/monitor.c:497
#10 0x0000555555c15541 in qapi_event_send_spice_disconnected (server=0x5555571139d0, client=0x5555570d0db0, errp=0x5555566c0428 <error_abort>) at qapi-event.c:1038
#11 0x0000555555b11bc6 in channel_event (event=3, info=0x5555570d6c00) at ui/spice-core.c:248
#12 0x00007fffdcc9983a in adapter_channel_event (event=3, info=0x5555570d6c00) at reds.c:120
#13 0x00007fffdcc99a25 in reds_handle_channel_event (reds=0x5555567a9d60, event=3, info=0x5555570d6c00) at reds.c:324
#14 0x00007fffdcc7d4c4 in main_dispatcher_self_handle_channel_event (self=0x5555567b28b0, event=3, info=0x5555570d6c00) at main-dispatcher.c:175
#15 0x00007fffdcc7d5b1 in main_dispatcher_channel_event (self=0x5555567b28b0, event=3, info=0x5555570d6c00) at main-dispatcher.c:194
#16 0x00007fffdcca7674 in reds_stream_push_channel_event (s=0x5555570d9910, event=3) at reds-stream.c:354
#17 0x00007fffdcca749b in reds_stream_free (s=0x5555570d9910) at reds-stream.c:323
#18 0x00007fffdccb5dad in snd_disconnect_channel (channel=0x5555576a89a0) at sound.c:229
#19 0x00007fffdccb9e57 in snd_detach_common (worker=0x555557739720) at sound.c:1589
#20 0x00007fffdccb9f0e in snd_detach_playback (sin=0x5555569fe3f8) at sound.c:1602
#21 0x00007fffdcca3373 in spice_server_remove_interface (sin=0x5555569fe3f8) at reds.c:3387
#22 0x00005555558ff6e2 in line_out_fini (hw=0x5555569fe370) at audio/spiceaudio.c:152
#23 0x00005555558f909e in audio_atexit () at audio/audio.c:1754
#24 0x00007fffdb1941e8 in __run_exit_handlers (status=0, listp=0x7fffdb5175d8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true) at exit.c:82
#25 0x00007fffdb194235 in __GI_exit (status=<optimized out>) at exit.c:104
#26 0x00007fffdb17b738 in __libc_start_main (main=0x5555558d7874 <main>, argc=67, argv=0x7fffffffcf48, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffcf38) at ../csu/libc-start.c:323
Add a monitor_cleanup() functions to remove all the monitors before
cleaning up the chardev. Note that we are "losing" some events that
used to be sent during atexit().
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20160801112343.29082-2-marcandre.lureau@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-08-01 13:23:42 +02:00
|
|
|
if (monitor_is_qmp(mon)) {
|
|
|
|
json_message_parser_destroy(&mon->qmp.parser);
|
|
|
|
}
|
2018-01-04 17:05:15 +01:00
|
|
|
readline_free(mon->rs);
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(mon->outbuf);
|
2018-06-08 05:55:05 +02:00
|
|
|
qemu_mutex_destroy(&mon->mon_lock);
|
2018-03-09 09:59:57 +01:00
|
|
|
qemu_mutex_destroy(&mon->qmp.qmp_queue_lock);
|
2018-03-26 08:38:55 +02:00
|
|
|
monitor_qmp_cleanup_req_queue_locked(mon);
|
2018-03-09 09:59:57 +01:00
|
|
|
g_queue_free(mon->qmp.qmp_requests);
|
2013-08-27 14:38:19 +02:00
|
|
|
}
|
|
|
|
|
2011-11-25 20:52:45 +01:00
|
|
|
char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
|
|
|
|
int64_t cpu_index, Error **errp)
|
2010-10-22 14:08:02 +02:00
|
|
|
{
|
2011-11-25 20:52:45 +01:00
|
|
|
char *output = NULL;
|
2010-10-22 14:08:02 +02:00
|
|
|
Monitor *old_mon, hmp;
|
|
|
|
|
2018-03-09 09:59:52 +01:00
|
|
|
monitor_data_init(&hmp, true, false);
|
2010-10-22 14:08:02 +02:00
|
|
|
|
|
|
|
old_mon = cur_mon;
|
|
|
|
cur_mon = &hmp;
|
|
|
|
|
2011-11-25 20:52:45 +01:00
|
|
|
if (has_cpu_index) {
|
|
|
|
int ret = monitor_set_cpu(cpu_index);
|
2010-10-22 14:08:02 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
cur_mon = old_mon;
|
2015-03-17 11:54:50 +01:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
|
|
|
|
"a CPU number");
|
2010-10-22 14:08:02 +02:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-06 19:12:36 +01:00
|
|
|
handle_hmp_command(&hmp, command_line);
|
2010-10-22 14:08:02 +02:00
|
|
|
cur_mon = old_mon;
|
|
|
|
|
2018-06-08 05:55:05 +02:00
|
|
|
qemu_mutex_lock(&hmp.mon_lock);
|
2013-04-02 21:07:33 +02:00
|
|
|
if (qstring_get_length(hmp.outbuf) > 0) {
|
|
|
|
output = g_strdup(qstring_get_str(hmp.outbuf));
|
2011-11-25 20:52:45 +01:00
|
|
|
} else {
|
|
|
|
output = g_strdup("");
|
2010-10-22 14:08:02 +02:00
|
|
|
}
|
2018-06-08 05:55:05 +02:00
|
|
|
qemu_mutex_unlock(&hmp.mon_lock);
|
2010-10-22 14:08:02 +02:00
|
|
|
|
|
|
|
out:
|
2013-08-27 14:38:19 +02:00
|
|
|
monitor_data_destroy(&hmp);
|
2011-11-25 20:52:45 +01:00
|
|
|
return output;
|
2010-10-22 14:08:02 +02:00
|
|
|
}
|
|
|
|
|
2004-03-14 22:38:27 +01:00
|
|
|
static int compare_cmd(const char *name, const char *list)
|
|
|
|
{
|
|
|
|
const char *p, *pstart;
|
|
|
|
int len;
|
|
|
|
len = strlen(name);
|
|
|
|
p = list;
|
|
|
|
for(;;) {
|
|
|
|
pstart = p;
|
2018-06-29 12:32:10 +02:00
|
|
|
p = qemu_strchrnul(p, '|');
|
2004-03-14 22:38:27 +01:00
|
|
|
if ((p - pstart) == len && !memcmp(pstart, name, len))
|
|
|
|
return 1;
|
|
|
|
if (*p == '\0')
|
|
|
|
break;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-08-27 14:38:21 +02:00
|
|
|
static int get_str(char *buf, int buf_size, const char **pp)
|
|
|
|
{
|
|
|
|
const char *p;
|
|
|
|
char *q;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
q = buf;
|
|
|
|
p = *pp;
|
|
|
|
while (qemu_isspace(*p)) {
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (*p == '\0') {
|
|
|
|
fail:
|
|
|
|
*q = '\0';
|
|
|
|
*pp = p;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (*p == '\"') {
|
|
|
|
p++;
|
|
|
|
while (*p != '\0' && *p != '\"') {
|
|
|
|
if (*p == '\\') {
|
|
|
|
p++;
|
|
|
|
c = *p++;
|
|
|
|
switch (c) {
|
|
|
|
case 'n':
|
|
|
|
c = '\n';
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
c = '\r';
|
|
|
|
break;
|
|
|
|
case '\\':
|
|
|
|
case '\'':
|
|
|
|
case '\"':
|
|
|
|
break;
|
|
|
|
default:
|
2015-08-19 17:20:19 +02:00
|
|
|
printf("unsupported escape code: '\\%c'\n", c);
|
2013-08-27 14:38:21 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
if ((q - buf) < buf_size - 1) {
|
|
|
|
*q++ = c;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((q - buf) < buf_size - 1) {
|
|
|
|
*q++ = *p;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (*p != '\"') {
|
2015-08-19 17:20:19 +02:00
|
|
|
printf("unterminated string\n");
|
2013-08-27 14:38:21 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
} else {
|
|
|
|
while (*p != '\0' && !qemu_isspace(*p)) {
|
|
|
|
if ((q - buf) < buf_size - 1) {
|
|
|
|
*q++ = *p;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*q = '\0';
|
|
|
|
*pp = p;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MAX_ARGS 16
|
|
|
|
|
2013-08-27 14:38:22 +02:00
|
|
|
static void free_cmdline_args(char **args, int nb_args)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
assert(nb_args <= MAX_ARGS);
|
|
|
|
|
|
|
|
for (i = 0; i < nb_args; i++) {
|
|
|
|
g_free(args[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse the command line to get valid args.
|
|
|
|
* @cmdline: command line to be parsed.
|
|
|
|
* @pnb_args: location to store the number of args, must NOT be NULL.
|
|
|
|
* @args: location to store the args, which should be freed by caller, must
|
|
|
|
* NOT be NULL.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, negative on failure.
|
|
|
|
*
|
|
|
|
* NOTE: this parser is an approximate form of the real command parser. Number
|
|
|
|
* of args have a limit of MAX_ARGS. If cmdline contains more, it will
|
|
|
|
* return with failure.
|
|
|
|
*/
|
|
|
|
static int parse_cmdline(const char *cmdline,
|
|
|
|
int *pnb_args, char **args)
|
2013-08-27 14:38:21 +02:00
|
|
|
{
|
|
|
|
const char *p;
|
|
|
|
int nb_args, ret;
|
|
|
|
char buf[1024];
|
|
|
|
|
|
|
|
p = cmdline;
|
|
|
|
nb_args = 0;
|
|
|
|
for (;;) {
|
|
|
|
while (qemu_isspace(*p)) {
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (*p == '\0') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (nb_args >= MAX_ARGS) {
|
2013-08-27 14:38:22 +02:00
|
|
|
goto fail;
|
2013-08-27 14:38:21 +02:00
|
|
|
}
|
|
|
|
ret = get_str(buf, sizeof(buf), &p);
|
|
|
|
if (ret < 0) {
|
2013-08-27 14:38:22 +02:00
|
|
|
goto fail;
|
2013-08-27 14:38:21 +02:00
|
|
|
}
|
2013-08-27 14:38:22 +02:00
|
|
|
args[nb_args] = g_strdup(buf);
|
|
|
|
nb_args++;
|
2013-08-27 14:38:21 +02:00
|
|
|
}
|
|
|
|
*pnb_args = nb_args;
|
2013-08-27 14:38:22 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
free_cmdline_args(args, nb_args);
|
|
|
|
return -1;
|
2013-08-27 14:38:21 +02:00
|
|
|
}
|
|
|
|
|
2018-06-20 17:39:41 +02:00
|
|
|
/*
|
2018-07-03 10:53:57 +02:00
|
|
|
* Can command @cmd be executed in preconfig state?
|
2018-06-20 17:39:41 +02:00
|
|
|
*/
|
|
|
|
static bool cmd_can_preconfig(const mon_cmd_t *cmd)
|
|
|
|
{
|
|
|
|
if (!cmd->flags) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return strchr(cmd->flags, 'p');
|
|
|
|
}
|
|
|
|
|
monitor: support sub command in help
The old code in help_cmd() uses global 'info_cmds' and treats it as a
special case. Actually 'info_cmds' is a sub command group of 'mon_cmds',
in order to avoid direct use of it, help_cmd() needs to change its work
mechanism to support sub command and not treat it as a special case
any more.
To support sub command, help_cmd() will first parse the input and then call
help_cmd_dump(), which works as a reentrant function. When it meets a sub
command, it simply enters the function again. Since help dumping needs to
know whole input to printf full help message include prefix, for example,
"help info block" need to printf prefix "info", so help_cmd_dump() takes all
args from input and extra parameter arg_index to identify the progress.
Another function help_cmd_dump_one() is introduced to printf the prefix
and command's help message.
Now help supports sub command, so later if another sub command group is
added in any depth, help will automatically work for it. Still "help info
block" will show error since command parser reject additional parameter,
which can be improved later. "log" is still treated as a special case.
Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2013-08-27 14:38:23 +02:00
|
|
|
static void help_cmd_dump_one(Monitor *mon,
|
|
|
|
const mon_cmd_t *cmd,
|
|
|
|
char **prefix_args,
|
|
|
|
int prefix_args_nb)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2018-06-20 17:39:42 +02:00
|
|
|
if (runstate_check(RUN_STATE_PRECONFIG) && !cmd_can_preconfig(cmd)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
monitor: support sub command in help
The old code in help_cmd() uses global 'info_cmds' and treats it as a
special case. Actually 'info_cmds' is a sub command group of 'mon_cmds',
in order to avoid direct use of it, help_cmd() needs to change its work
mechanism to support sub command and not treat it as a special case
any more.
To support sub command, help_cmd() will first parse the input and then call
help_cmd_dump(), which works as a reentrant function. When it meets a sub
command, it simply enters the function again. Since help dumping needs to
know whole input to printf full help message include prefix, for example,
"help info block" need to printf prefix "info", so help_cmd_dump() takes all
args from input and extra parameter arg_index to identify the progress.
Another function help_cmd_dump_one() is introduced to printf the prefix
and command's help message.
Now help supports sub command, so later if another sub command group is
added in any depth, help will automatically work for it. Still "help info
block" will show error since command parser reject additional parameter,
which can be improved later. "log" is still treated as a special case.
Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2013-08-27 14:38:23 +02:00
|
|
|
for (i = 0; i < prefix_args_nb; i++) {
|
|
|
|
monitor_printf(mon, "%s ", prefix_args[i]);
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "%s %s -- %s\n", cmd->name, cmd->params, cmd->help);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* @args[@arg_index] is the valid command need to find in @cmds */
|
2009-10-01 23:12:16 +02:00
|
|
|
static void help_cmd_dump(Monitor *mon, const mon_cmd_t *cmds,
|
monitor: support sub command in help
The old code in help_cmd() uses global 'info_cmds' and treats it as a
special case. Actually 'info_cmds' is a sub command group of 'mon_cmds',
in order to avoid direct use of it, help_cmd() needs to change its work
mechanism to support sub command and not treat it as a special case
any more.
To support sub command, help_cmd() will first parse the input and then call
help_cmd_dump(), which works as a reentrant function. When it meets a sub
command, it simply enters the function again. Since help dumping needs to
know whole input to printf full help message include prefix, for example,
"help info block" need to printf prefix "info", so help_cmd_dump() takes all
args from input and extra parameter arg_index to identify the progress.
Another function help_cmd_dump_one() is introduced to printf the prefix
and command's help message.
Now help supports sub command, so later if another sub command group is
added in any depth, help will automatically work for it. Still "help info
block" will show error since command parser reject additional parameter,
which can be improved later. "log" is still treated as a special case.
Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2013-08-27 14:38:23 +02:00
|
|
|
char **args, int nb_args, int arg_index)
|
2004-03-14 22:38:27 +01:00
|
|
|
{
|
2009-10-01 23:12:16 +02:00
|
|
|
const mon_cmd_t *cmd;
|
2018-07-20 21:40:24 +02:00
|
|
|
size_t i;
|
2004-03-14 22:38:27 +01:00
|
|
|
|
monitor: support sub command in help
The old code in help_cmd() uses global 'info_cmds' and treats it as a
special case. Actually 'info_cmds' is a sub command group of 'mon_cmds',
in order to avoid direct use of it, help_cmd() needs to change its work
mechanism to support sub command and not treat it as a special case
any more.
To support sub command, help_cmd() will first parse the input and then call
help_cmd_dump(), which works as a reentrant function. When it meets a sub
command, it simply enters the function again. Since help dumping needs to
know whole input to printf full help message include prefix, for example,
"help info block" need to printf prefix "info", so help_cmd_dump() takes all
args from input and extra parameter arg_index to identify the progress.
Another function help_cmd_dump_one() is introduced to printf the prefix
and command's help message.
Now help supports sub command, so later if another sub command group is
added in any depth, help will automatically work for it. Still "help info
block" will show error since command parser reject additional parameter,
which can be improved later. "log" is still treated as a special case.
Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2013-08-27 14:38:23 +02:00
|
|
|
/* No valid arg need to compare with, dump all in *cmds */
|
|
|
|
if (arg_index >= nb_args) {
|
|
|
|
for (cmd = cmds; cmd->name != NULL; cmd++) {
|
|
|
|
help_cmd_dump_one(mon, cmd, args, arg_index);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find one entry to dump */
|
|
|
|
for (cmd = cmds; cmd->name != NULL; cmd++) {
|
2018-06-20 17:39:42 +02:00
|
|
|
if (compare_cmd(args[arg_index], cmd->name) &&
|
|
|
|
((!runstate_check(RUN_STATE_PRECONFIG) ||
|
|
|
|
cmd_can_preconfig(cmd)))) {
|
monitor: support sub command in help
The old code in help_cmd() uses global 'info_cmds' and treats it as a
special case. Actually 'info_cmds' is a sub command group of 'mon_cmds',
in order to avoid direct use of it, help_cmd() needs to change its work
mechanism to support sub command and not treat it as a special case
any more.
To support sub command, help_cmd() will first parse the input and then call
help_cmd_dump(), which works as a reentrant function. When it meets a sub
command, it simply enters the function again. Since help dumping needs to
know whole input to printf full help message include prefix, for example,
"help info block" need to printf prefix "info", so help_cmd_dump() takes all
args from input and extra parameter arg_index to identify the progress.
Another function help_cmd_dump_one() is introduced to printf the prefix
and command's help message.
Now help supports sub command, so later if another sub command group is
added in any depth, help will automatically work for it. Still "help info
block" will show error since command parser reject additional parameter,
which can be improved later. "log" is still treated as a special case.
Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2013-08-27 14:38:23 +02:00
|
|
|
if (cmd->sub_table) {
|
|
|
|
/* continue with next arg */
|
|
|
|
help_cmd_dump(mon, cmd->sub_table,
|
|
|
|
args, nb_args, arg_index + 1);
|
|
|
|
} else {
|
|
|
|
help_cmd_dump_one(mon, cmd, args, arg_index);
|
|
|
|
}
|
2018-07-20 21:40:24 +02:00
|
|
|
return;
|
monitor: support sub command in help
The old code in help_cmd() uses global 'info_cmds' and treats it as a
special case. Actually 'info_cmds' is a sub command group of 'mon_cmds',
in order to avoid direct use of it, help_cmd() needs to change its work
mechanism to support sub command and not treat it as a special case
any more.
To support sub command, help_cmd() will first parse the input and then call
help_cmd_dump(), which works as a reentrant function. When it meets a sub
command, it simply enters the function again. Since help dumping needs to
know whole input to printf full help message include prefix, for example,
"help info block" need to printf prefix "info", so help_cmd_dump() takes all
args from input and extra parameter arg_index to identify the progress.
Another function help_cmd_dump_one() is introduced to printf the prefix
and command's help message.
Now help supports sub command, so later if another sub command group is
added in any depth, help will automatically work for it. Still "help info
block" will show error since command parser reject additional parameter,
which can be improved later. "log" is still treated as a special case.
Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2013-08-27 14:38:23 +02:00
|
|
|
}
|
2004-03-14 22:38:27 +01:00
|
|
|
}
|
2018-07-20 21:40:24 +02:00
|
|
|
|
|
|
|
/* Command not found */
|
|
|
|
monitor_printf(mon, "unknown command: '");
|
|
|
|
for (i = 0; i <= arg_index; i++) {
|
|
|
|
monitor_printf(mon, "%s%s", args[i], i == arg_index ? "'\n" : " ");
|
|
|
|
}
|
2004-03-14 22:38:27 +01:00
|
|
|
}
|
|
|
|
|
2009-03-06 00:01:23 +01:00
|
|
|
static void help_cmd(Monitor *mon, const char *name)
|
2004-03-14 22:38:27 +01:00
|
|
|
{
|
monitor: support sub command in help
The old code in help_cmd() uses global 'info_cmds' and treats it as a
special case. Actually 'info_cmds' is a sub command group of 'mon_cmds',
in order to avoid direct use of it, help_cmd() needs to change its work
mechanism to support sub command and not treat it as a special case
any more.
To support sub command, help_cmd() will first parse the input and then call
help_cmd_dump(), which works as a reentrant function. When it meets a sub
command, it simply enters the function again. Since help dumping needs to
know whole input to printf full help message include prefix, for example,
"help info block" need to printf prefix "info", so help_cmd_dump() takes all
args from input and extra parameter arg_index to identify the progress.
Another function help_cmd_dump_one() is introduced to printf the prefix
and command's help message.
Now help supports sub command, so later if another sub command group is
added in any depth, help will automatically work for it. Still "help info
block" will show error since command parser reject additional parameter,
which can be improved later. "log" is still treated as a special case.
Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2013-08-27 14:38:23 +02:00
|
|
|
char *args[MAX_ARGS];
|
|
|
|
int nb_args = 0;
|
|
|
|
|
|
|
|
/* 1. parse user input */
|
|
|
|
if (name) {
|
|
|
|
/* special case for log, directly dump and return */
|
|
|
|
if (!strcmp(name, "log")) {
|
2013-02-11 17:41:25 +01:00
|
|
|
const QEMULogItem *item;
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "Log items (comma separated):\n");
|
|
|
|
monitor_printf(mon, "%-10s %s\n", "none", "remove all logs");
|
2013-02-11 17:41:25 +01:00
|
|
|
for (item = qemu_log_items; item->mask != 0; item++) {
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "%-10s %s\n", item->name, item->help);
|
2004-03-21 18:06:25 +01:00
|
|
|
}
|
monitor: support sub command in help
The old code in help_cmd() uses global 'info_cmds' and treats it as a
special case. Actually 'info_cmds' is a sub command group of 'mon_cmds',
in order to avoid direct use of it, help_cmd() needs to change its work
mechanism to support sub command and not treat it as a special case
any more.
To support sub command, help_cmd() will first parse the input and then call
help_cmd_dump(), which works as a reentrant function. When it meets a sub
command, it simply enters the function again. Since help dumping needs to
know whole input to printf full help message include prefix, for example,
"help info block" need to printf prefix "info", so help_cmd_dump() takes all
args from input and extra parameter arg_index to identify the progress.
Another function help_cmd_dump_one() is introduced to printf the prefix
and command's help message.
Now help supports sub command, so later if another sub command group is
added in any depth, help will automatically work for it. Still "help info
block" will show error since command parser reject additional parameter,
which can be improved later. "log" is still treated as a special case.
Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2013-08-27 14:38:23 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parse_cmdline(name, &nb_args, args) < 0) {
|
|
|
|
return;
|
2004-03-21 18:06:25 +01:00
|
|
|
}
|
2004-03-14 22:38:27 +01:00
|
|
|
}
|
monitor: support sub command in help
The old code in help_cmd() uses global 'info_cmds' and treats it as a
special case. Actually 'info_cmds' is a sub command group of 'mon_cmds',
in order to avoid direct use of it, help_cmd() needs to change its work
mechanism to support sub command and not treat it as a special case
any more.
To support sub command, help_cmd() will first parse the input and then call
help_cmd_dump(), which works as a reentrant function. When it meets a sub
command, it simply enters the function again. Since help dumping needs to
know whole input to printf full help message include prefix, for example,
"help info block" need to printf prefix "info", so help_cmd_dump() takes all
args from input and extra parameter arg_index to identify the progress.
Another function help_cmd_dump_one() is introduced to printf the prefix
and command's help message.
Now help supports sub command, so later if another sub command group is
added in any depth, help will automatically work for it. Still "help info
block" will show error since command parser reject additional parameter,
which can be improved later. "log" is still treated as a special case.
Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2013-08-27 14:38:23 +02:00
|
|
|
|
|
|
|
/* 2. dump the contents according to parsed args */
|
|
|
|
help_cmd_dump(mon, mon->cmd_table, args, nb_args, 0);
|
|
|
|
|
|
|
|
free_cmdline_args(args, nb_args);
|
2004-03-14 22:38:27 +01:00
|
|
|
}
|
|
|
|
|
2009-08-28 20:27:13 +02:00
|
|
|
static void do_help_cmd(Monitor *mon, const QDict *qdict)
|
2009-08-28 20:27:08 +02:00
|
|
|
{
|
2009-08-28 20:27:13 +02:00
|
|
|
help_cmd(mon, qdict_get_try_str(qdict, "name"));
|
2009-08-28 20:27:08 +02: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 13:55:43 +01:00
|
|
|
static void hmp_trace_event(Monitor *mon, const QDict *qdict)
|
2010-06-24 13:34:53 +02:00
|
|
|
{
|
|
|
|
const char *tp_name = qdict_get_str(qdict, "name");
|
|
|
|
bool new_state = qdict_get_bool(qdict, "option");
|
2016-07-11 12:53:57 +02:00
|
|
|
bool has_vcpu = qdict_haskey(qdict, "vcpu");
|
|
|
|
int vcpu = qdict_get_try_int(qdict, "vcpu", 0);
|
2014-08-25 13:20:03 +02:00
|
|
|
Error *local_err = NULL;
|
2010-10-13 21:14:29 +02:00
|
|
|
|
2016-07-11 12:53:57 +02: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 13:20:03 +02:00
|
|
|
if (local_err) {
|
2015-02-10 15:15:43 +01:00
|
|
|
error_report_err(local_err);
|
2010-10-13 21:14:29 +02:00
|
|
|
}
|
2010-06-24 13:34:53 +02:00
|
|
|
}
|
2010-07-13 10:26:33 +02:00
|
|
|
|
2011-10-02 15:44:37 +02: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 13:55:43 +01:00
|
|
|
static void hmp_trace_file(Monitor *mon, const QDict *qdict)
|
2010-07-13 10:26:33 +02:00
|
|
|
{
|
|
|
|
const char *op = qdict_get_try_str(qdict, "op");
|
|
|
|
const char *arg = qdict_get_try_str(qdict, "arg");
|
|
|
|
|
|
|
|
if (!op) {
|
2019-04-17 21:17:50 +02:00
|
|
|
st_print_trace_file_status();
|
2010-07-13 10:26:33 +02: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 13:34:53 +02: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 13:55:43 +01:00
|
|
|
static void hmp_info_help(Monitor *mon, const QDict *qdict)
|
2004-03-14 22:38:27 +01:00
|
|
|
{
|
2009-10-07 18:41:55 +02:00
|
|
|
help_cmd(mon, "info");
|
2004-03-14 22:38:27 +01:00
|
|
|
}
|
|
|
|
|
2016-09-12 11:19:05 +02:00
|
|
|
static void query_commands_cb(QmpCommand *cmd, void *opaque)
|
2009-11-27 01:58:56 +01:00
|
|
|
{
|
2016-09-12 11:19:05 +02:00
|
|
|
CommandInfoList *info, **list = opaque;
|
2009-11-27 01:58:56 +01:00
|
|
|
|
2016-09-12 11:19:05 +02:00
|
|
|
if (!cmd->enabled) {
|
|
|
|
return;
|
2009-11-27 01:58:56 +01:00
|
|
|
}
|
|
|
|
|
2016-09-12 11:19:05 +02: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;
|
|
|
|
|
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 13:32:27 +01:00
|
|
|
qmp_for_each_command(cur_mon->qmp.commands, query_commands_cb, &list);
|
2016-09-12 11:19:05 +02:00
|
|
|
|
|
|
|
return list;
|
2007-12-02 06:18:19 +01:00
|
|
|
}
|
|
|
|
|
2012-05-21 18:59:51 +02:00
|
|
|
EventInfoList *qmp_query_events(Error **errp)
|
|
|
|
{
|
2019-02-14 16:22:50 +01: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 18:59:51 +02:00
|
|
|
EventInfoList *info, *ev_list = NULL;
|
2014-06-18 08:43:54 +02:00
|
|
|
QAPIEvent e;
|
2012-05-21 18:59:51 +02: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 09:52:57 +01:00
|
|
|
for (e = 0 ; e < QAPI_EVENT__MAX ; e++) {
|
2017-08-24 10:46:08 +02:00
|
|
|
const char *event_name = QAPIEvent_str(e);
|
2012-05-21 18:59:51 +02: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 13:06:28 +02: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 16:45:27 +02:00
|
|
|
* we do it in test-qobject-input-visitor.c, just to make sure
|
2018-02-26 20:48:58 +01: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 13:06:28 +02:00
|
|
|
*/
|
|
|
|
static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
|
|
|
|
Error **errp)
|
|
|
|
{
|
2018-03-05 18:29:51 +01: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 13:06:28 +02:00
|
|
|
}
|
|
|
|
|
2018-03-09 09:59:50 +01:00
|
|
|
static void monitor_init_qmp_commands(void)
|
2016-09-12 11:19:00 +02: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 13:32:27 +01: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 13:32:25 +01:00
|
|
|
qmp_init_marshal(&qmp_commands);
|
2017-03-03 13:32:24 +01:00
|
|
|
|
2017-03-03 13:32:25 +01:00
|
|
|
qmp_register_command(&qmp_commands, "query-qmp-schema",
|
2018-05-11 18:51:43 +02:00
|
|
|
qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
|
2017-03-03 13:32:25 +01:00
|
|
|
qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
|
2016-09-12 11:19:00 +02:00
|
|
|
QCO_NO_OPTIONS);
|
2017-03-03 13:32:25 +01:00
|
|
|
qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add,
|
2016-09-12 11:19:00 +02:00
|
|
|
QCO_NO_OPTIONS);
|
2016-09-12 11:19:02 +02: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 13:32:27 +01:00
|
|
|
QTAILQ_INIT(&qmp_cap_negotiation_commands);
|
|
|
|
qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
|
2018-05-11 18:51:43 +02: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 13:32:27 +01:00
|
|
|
}
|
|
|
|
|
2018-03-09 09:59:57 +01:00
|
|
|
static bool qmp_oob_enabled(Monitor *mon)
|
|
|
|
{
|
2018-07-03 10:53:56 +02:00
|
|
|
return mon->qmp.capab[QMP_CAPABILITY_OOB];
|
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 09:59:53 +01:00
|
|
|
}
|
|
|
|
|
2018-07-03 10:53:56 +02:00
|
|
|
static void monitor_qmp_caps_reset(Monitor *mon)
|
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 13:32:27 +01:00
|
|
|
{
|
2018-07-03 10:53:56 +02:00
|
|
|
memset(mon->qmp.capab_offered, 0, sizeof(mon->qmp.capab_offered));
|
|
|
|
memset(mon->qmp.capab, 0, sizeof(mon->qmp.capab));
|
|
|
|
mon->qmp.capab_offered[QMP_CAPABILITY_OOB] = mon->use_io_thread;
|
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 09:59:53 +01:00
|
|
|
}
|
|
|
|
|
2018-03-11 03:38:05 +01:00
|
|
|
/*
|
2018-07-03 10:53:56 +02: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 03:38:05 +01:00
|
|
|
*/
|
2018-07-03 10:53:56 +02:00
|
|
|
static bool qmp_caps_accept(Monitor *mon, QMPCapabilityList *list,
|
|
|
|
Error **errp)
|
2018-03-11 03:38:05 +01:00
|
|
|
{
|
2018-07-03 10:53:56 +02:00
|
|
|
GString *unavailable = NULL;
|
|
|
|
bool capab[QMP_CAPABILITY__MAX];
|
2018-03-11 03:38:05 +01:00
|
|
|
|
2018-07-03 10:53:56 +02:00
|
|
|
memset(capab, 0, sizeof(capab));
|
2018-03-11 03:38:05 +01: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 09:59:53 +01:00
|
|
|
for (; list; list = list->next) {
|
2018-07-03 10:53:56 +02:00
|
|
|
if (!mon->qmp.capab_offered[list->value]) {
|
|
|
|
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 09:59:53 +01:00
|
|
|
}
|
2018-03-26 08:38:54 +02:00
|
|
|
}
|
2018-07-03 10:53:56 +02:00
|
|
|
capab[list->value] = true;
|
2018-03-11 03:38:05 +01:00
|
|
|
}
|
|
|
|
|
2018-07-03 10:53:56 +02:00
|
|
|
if (unavailable) {
|
|
|
|
error_setg(errp, "Capability %s not available", unavailable->str);
|
|
|
|
g_string_free(unavailable, true);
|
|
|
|
return false;
|
2018-03-11 03:38:05 +01:00
|
|
|
}
|
|
|
|
|
2018-07-03 10:53:56 +02:00
|
|
|
memcpy(mon->qmp.capab, capab, sizeof(capab));
|
2018-03-11 03:38:05 +01: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 09:59:53 +01:00
|
|
|
void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable,
|
|
|
|
Error **errp)
|
|
|
|
{
|
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 13:32:27 +01:00
|
|
|
if (cur_mon->qmp.commands == &qmp_commands) {
|
|
|
|
error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
|
|
|
|
"Capabilities negotiation is already complete, command "
|
|
|
|
"ignored");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-03 10:53:56 +02:00
|
|
|
if (!qmp_caps_accept(cur_mon, enable, errp)) {
|
|
|
|
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 09:59:53 +01: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 13:32:27 +01:00
|
|
|
cur_mon->qmp.commands = &qmp_commands;
|
2016-09-12 11:19:00 +02:00
|
|
|
}
|
|
|
|
|
2018-06-08 05:55:07 +02:00
|
|
|
/* Set the current CPU defined by the user. Callers must hold BQL. */
|
2011-10-06 19:02:57 +02:00
|
|
|
int monitor_set_cpu(int cpu_index)
|
2005-11-22 00:25:50 +01:00
|
|
|
{
|
2012-12-17 06:18:02 +01:00
|
|
|
CPUState *cpu;
|
2005-11-22 00:25:50 +01:00
|
|
|
|
2013-02-15 17:01:09 +01:00
|
|
|
cpu = qemu_get_cpu(cpu_index);
|
|
|
|
if (cpu == NULL) {
|
|
|
|
return -1;
|
2005-11-22 00:25:50 +01:00
|
|
|
}
|
2017-10-17 10:16:22 +02:00
|
|
|
g_free(cur_mon->mon_cpu_path);
|
|
|
|
cur_mon->mon_cpu_path = object_get_canonical_path(OBJECT(cpu));
|
2013-02-15 17:01:09 +01:00
|
|
|
return 0;
|
2005-11-22 00:25:50 +01:00
|
|
|
}
|
|
|
|
|
2018-06-08 05:55:07 +02:00
|
|
|
/* Callers must hold BQL. */
|
2018-02-16 17:08:41 +01:00
|
|
|
static CPUState *mon_get_cpu_sync(bool synchronize)
|
2005-11-22 00:25:50 +01:00
|
|
|
{
|
2017-10-17 10:16:22 +02:00
|
|
|
CPUState *cpu;
|
|
|
|
|
|
|
|
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 13:12:35 +01:00
|
|
|
if (!first_cpu) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-09-21 07:29:26 +02:00
|
|
|
monitor_set_cpu(first_cpu->cpu_index);
|
2017-10-17 10:16:22 +02:00
|
|
|
cpu = first_cpu;
|
2005-11-22 00:25:50 +01:00
|
|
|
}
|
2018-02-16 17:08:41 +01:00
|
|
|
if (synchronize) {
|
|
|
|
cpu_synchronize_state(cpu);
|
|
|
|
}
|
2017-10-17 10:16:22 +02:00
|
|
|
return cpu;
|
2015-05-24 23:20:40 +02:00
|
|
|
}
|
|
|
|
|
2018-02-16 17:08:41 +01:00
|
|
|
CPUState *mon_get_cpu(void)
|
|
|
|
{
|
|
|
|
return mon_get_cpu_sync(true);
|
|
|
|
}
|
|
|
|
|
2015-09-10 17:38:59 +02:00
|
|
|
CPUArchState *mon_get_cpu_env(void)
|
2015-05-24 23:20:40 +02:00
|
|
|
{
|
2017-01-13 13:12:35 +01:00
|
|
|
CPUState *cs = mon_get_cpu();
|
|
|
|
|
|
|
|
return cs ? cs->env_ptr : NULL;
|
2005-11-22 00:25:50 +01:00
|
|
|
}
|
|
|
|
|
2011-10-24 14:53:44 +02:00
|
|
|
int monitor_get_cpu_index(void)
|
|
|
|
{
|
2018-02-16 17:08:41 +01:00
|
|
|
CPUState *cs = mon_get_cpu_sync(false);
|
2017-01-13 13:12:35 +01:00
|
|
|
|
|
|
|
return cs ? cs->cpu_index : UNASSIGNED_CPU_INDEX;
|
2011-10-24 14:53:44 +02:00
|
|
|
}
|
|
|
|
|
2015-02-06 14:18:24 +01:00
|
|
|
static void hmp_info_registers(Monitor *mon, const QDict *qdict)
|
2004-04-04 14:57:25 +02:00
|
|
|
{
|
2017-06-08 07:41:16 +02:00
|
|
|
bool all_cpus = qdict_get_try_bool(qdict, "cpustate_all", false);
|
|
|
|
CPUState *cs;
|
2017-01-13 13:12:35 +01:00
|
|
|
|
2017-06-08 07:41:16 +02:00
|
|
|
if (all_cpus) {
|
|
|
|
CPU_FOREACH(cs) {
|
|
|
|
monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index);
|
2019-04-17 21:18:02 +02:00
|
|
|
cpu_dump_state(cs, NULL, CPU_DUMP_FPU);
|
2017-06-08 07:41:16 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cs = mon_get_cpu();
|
|
|
|
|
|
|
|
if (!cs) {
|
|
|
|
monitor_printf(mon, "No CPU available\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-04-17 21:18:02 +02:00
|
|
|
cpu_dump_state(cs, NULL, CPU_DUMP_FPU);
|
2017-01-13 13:12:35 +01:00
|
|
|
}
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
|
|
|
|
2012-09-17 13:42:41 +02:00
|
|
|
#ifdef CONFIG_TCG
|
2015-02-06 14:18:24 +01:00
|
|
|
static void hmp_info_jit(Monitor *mon, const QDict *qdict)
|
2005-01-26 23:00:47 +01:00
|
|
|
{
|
2017-04-26 06:11:47 +02:00
|
|
|
if (!tcg_enabled()) {
|
|
|
|
error_report("JIT information is only available with accel=tcg");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-04-17 21:17:52 +02:00
|
|
|
dump_exec_info();
|
2019-04-17 21:17:53 +02:00
|
|
|
dump_drift_info();
|
2005-01-26 23:00:47 +01:00
|
|
|
}
|
|
|
|
|
2015-02-06 14:18:24 +01:00
|
|
|
static void hmp_info_opcount(Monitor *mon, const QDict *qdict)
|
2014-11-02 09:04:18 +01:00
|
|
|
{
|
2019-04-17 21:17:51 +02:00
|
|
|
dump_opcount_info();
|
2014-11-02 09:04:18 +01:00
|
|
|
}
|
2012-09-17 13:42:41 +02:00
|
|
|
#endif
|
2014-11-02 09:04:18 +01:00
|
|
|
|
2017-08-08 19:54:42 +02: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 21:17:54 +02:00
|
|
|
qsp_report(max, sort_by, coalesce);
|
2017-08-08 19:54:42 +02:00
|
|
|
}
|
|
|
|
|
2015-02-06 14:18:24 +01:00
|
|
|
static void hmp_info_history(Monitor *mon, const QDict *qdict)
|
2004-04-04 15:07:25 +02:00
|
|
|
{
|
|
|
|
int i;
|
2004-08-01 23:52:19 +02:00
|
|
|
const char *str;
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2009-03-06 00:01:51 +01:00
|
|
|
if (!mon->rs)
|
|
|
|
return;
|
2004-08-01 23:52:19 +02:00
|
|
|
i = 0;
|
|
|
|
for(;;) {
|
2009-03-06 00:01:42 +01:00
|
|
|
str = readline_get_history(mon->rs, i);
|
2004-08-01 23:52:19 +02:00
|
|
|
if (!str)
|
|
|
|
break;
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "%d: '%s'\n", i, str);
|
2004-10-09 19:32:58 +02:00
|
|
|
i++;
|
2004-04-04 15:07:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-06 14:18:24 +01:00
|
|
|
static void hmp_info_cpustats(Monitor *mon, const QDict *qdict)
|
2007-03-07 09:32:30 +01:00
|
|
|
{
|
2017-01-13 13:12:35 +01:00
|
|
|
CPUState *cs = mon_get_cpu();
|
|
|
|
|
|
|
|
if (!cs) {
|
|
|
|
monitor_printf(mon, "No CPU available\n");
|
|
|
|
return;
|
|
|
|
}
|
2019-04-17 21:18:00 +02:00
|
|
|
cpu_dump_statistics(cs, 0);
|
2007-03-07 09:32:30 +01:00
|
|
|
}
|
|
|
|
|
2015-02-06 14:18:24 +01:00
|
|
|
static void hmp_info_trace_events(Monitor *mon, const QDict *qdict)
|
2010-06-24 13:34:53 +02:00
|
|
|
{
|
2016-07-11 12:53:51 +02:00
|
|
|
const char *name = qdict_get_try_str(qdict, "name");
|
2016-07-11 12:53:57 +02:00
|
|
|
bool has_vcpu = qdict_haskey(qdict, "vcpu");
|
|
|
|
int vcpu = qdict_get_try_int(qdict, "vcpu", 0);
|
2016-07-11 12:53:51 +02:00
|
|
|
TraceEventInfoList *events;
|
2014-08-25 13:20:03 +02:00
|
|
|
TraceEventInfoList *elem;
|
2016-07-11 12:53:51 +02:00
|
|
|
Error *local_err = NULL;
|
|
|
|
|
|
|
|
if (name == NULL) {
|
|
|
|
name = "*";
|
|
|
|
}
|
2016-07-11 12:53:57 +02:00
|
|
|
if (vcpu < 0) {
|
|
|
|
monitor_printf(mon, "argument vcpu must be positive");
|
|
|
|
return;
|
|
|
|
}
|
2016-07-11 12:53:51 +02:00
|
|
|
|
2016-07-11 12:53:57 +02:00
|
|
|
events = qmp_trace_event_get_state(name, has_vcpu, vcpu, &local_err);
|
2016-07-11 12:53:51 +02:00
|
|
|
if (local_err) {
|
|
|
|
error_report_err(local_err);
|
|
|
|
return;
|
|
|
|
}
|
2014-08-25 13:20:03 +02: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 13:34:53 +02:00
|
|
|
}
|
|
|
|
|
2015-03-05 17:29:02 +01: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 13:28:21 +02:00
|
|
|
{
|
|
|
|
if (strcmp(protocol, "spice") == 0) {
|
2015-03-05 17:29:02 +01:00
|
|
|
if (!qemu_using_spice(errp)) {
|
|
|
|
return;
|
2010-04-23 13:28:21 +02:00
|
|
|
}
|
|
|
|
|
2015-03-05 17:29:02 +01:00
|
|
|
if (!has_port && !has_tls_port) {
|
2015-03-17 11:54:50 +01:00
|
|
|
error_setg(errp, QERR_MISSING_PARAMETER, "port/tls-port");
|
2015-03-05 17:29:02 +01:00
|
|
|
return;
|
2012-03-18 08:42:39 +01:00
|
|
|
}
|
|
|
|
|
2015-03-05 17:29:02 +01:00
|
|
|
if (qemu_spice_migrate_info(hostname,
|
|
|
|
has_port ? port : -1,
|
|
|
|
has_tls_port ? tls_port : -1,
|
|
|
|
cert_subject)) {
|
2015-03-17 11:54:50 +01:00
|
|
|
error_setg(errp, QERR_UNDEFINED_ERROR);
|
2015-03-05 17:29:02 +01:00
|
|
|
return;
|
2010-04-23 13:28:21 +02:00
|
|
|
}
|
2015-03-05 17:29:02 +01:00
|
|
|
return;
|
2010-04-23 13:28:21 +02:00
|
|
|
}
|
|
|
|
|
2015-03-17 11:54:50 +01:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "protocol", "spice");
|
2010-04-23 13:28:21 +02: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 13:55:43 +01:00
|
|
|
static void hmp_logfile(Monitor *mon, const QDict *qdict)
|
2007-06-30 15:53:24 +02:00
|
|
|
{
|
2016-06-15 19:27:16 +02:00
|
|
|
Error *err = NULL;
|
|
|
|
|
|
|
|
qemu_set_log_filename(qdict_get_str(qdict, "filename"), &err);
|
|
|
|
if (err) {
|
|
|
|
error_report_err(err);
|
|
|
|
}
|
2007-06-30 15:53:24 +02: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 13:55:43 +01:00
|
|
|
static void hmp_log(Monitor *mon, const QDict *qdict)
|
2004-03-21 18:06:25 +01:00
|
|
|
{
|
|
|
|
int mask;
|
2009-08-28 20:27:13 +02:00
|
|
|
const char *items = qdict_get_str(qdict, "items");
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2004-04-04 14:57:25 +02:00
|
|
|
if (!strcmp(items, "none")) {
|
2004-03-21 18:06:25 +01:00
|
|
|
mask = 0;
|
|
|
|
} else {
|
2013-02-11 17:41:22 +01:00
|
|
|
mask = qemu_str_to_log_mask(items);
|
2004-03-21 18:06:25 +01:00
|
|
|
if (!mask) {
|
2009-03-06 00:01:23 +01:00
|
|
|
help_cmd(mon, "log");
|
2004-03-21 18:06:25 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2013-02-11 17:41:23 +01:00
|
|
|
qemu_set_log(mask);
|
2004-03-21 18:06:25 +01: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 13:55:43 +01:00
|
|
|
static void hmp_singlestep(Monitor *mon, const QDict *qdict)
|
2009-04-05 22:08:59 +02:00
|
|
|
{
|
2009-08-28 20:27:13 +02:00
|
|
|
const char *option = qdict_get_try_str(qdict, "option");
|
2009-04-05 22:08:59 +02: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 13:55:43 +01:00
|
|
|
static void hmp_gdbserver(Monitor *mon, const QDict *qdict)
|
2009-04-05 20:43:41 +02:00
|
|
|
{
|
2009-08-28 20:27:13 +02:00
|
|
|
const char *device = qdict_get_try_str(qdict, "device");
|
2009-04-05 20:43:41 +02: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 19:05:53 +01:00
|
|
|
monitor_printf(mon, "Disabled gdbserver\n");
|
2004-03-31 21:00:16 +02:00
|
|
|
} else {
|
2009-04-05 20:43:41 +02:00
|
|
|
monitor_printf(mon, "Waiting for gdb connection on device '%s'\n",
|
|
|
|
device);
|
2004-03-31 21:00:16 +02: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 13:55:43 +01:00
|
|
|
static void hmp_watchdog_action(Monitor *mon, const QDict *qdict)
|
2009-04-25 14:56:19 +02:00
|
|
|
{
|
2009-08-28 20:27:13 +02:00
|
|
|
const char *action = qdict_get_str(qdict, "action");
|
2009-04-25 14:56:19 +02:00
|
|
|
if (select_watchdog_action(action) == -1) {
|
|
|
|
monitor_printf(mon, "Unknown watchdog action '%s'\n", action);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-06 00:01:23 +01:00
|
|
|
static void monitor_printc(Monitor *mon, int c)
|
2004-04-04 14:57:25 +02:00
|
|
|
{
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "'");
|
2004-04-04 14:57:25 +02:00
|
|
|
switch(c) {
|
|
|
|
case '\'':
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "\\'");
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case '\\':
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "\\\\");
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case '\n':
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "\\n");
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case '\r':
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "\\r");
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (c >= 32 && c <= 126) {
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "%c", c);
|
2004-04-04 14:57:25 +02:00
|
|
|
} else {
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "\\x%02x", c);
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "'");
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
|
|
|
|
2009-03-06 00:01:23 +01:00
|
|
|
static void memory_dump(Monitor *mon, int count, int format, int wsize,
|
2012-10-23 12:30:10 +02:00
|
|
|
hwaddr addr, int is_physical)
|
2004-04-04 14:57:25 +02:00
|
|
|
{
|
2010-01-12 21:27:43 +01:00
|
|
|
int l, line_size, i, max_digits, len;
|
2004-04-04 14:57:25 +02:00
|
|
|
uint8_t buf[16];
|
|
|
|
uint64_t v;
|
2017-01-13 13:12:35 +01: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 14:57:25 +02:00
|
|
|
|
|
|
|
if (format == 'i') {
|
2017-09-14 17:38:35 +02:00
|
|
|
monitor_disas(mon, cs, addr, count, is_physical);
|
2004-04-04 14:57:25 +02: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 13:04:16 +02:00
|
|
|
max_digits = DIV_ROUND_UP(wsize * 8, 3);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case 'x':
|
|
|
|
max_digits = (wsize * 8) / 4;
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
case 'd':
|
2017-06-22 13:04:16 +02:00
|
|
|
max_digits = DIV_ROUND_UP(wsize * 8 * 10, 33);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
wsize = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (len > 0) {
|
2007-09-24 20:39:04 +02:00
|
|
|
if (is_physical)
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, TARGET_FMT_plx ":", addr);
|
2007-09-24 20:39:04 +02:00
|
|
|
else
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, TARGET_FMT_lx ":", (target_ulong)addr);
|
2004-04-04 14:57:25 +02:00
|
|
|
l = len;
|
|
|
|
if (l > line_size)
|
|
|
|
l = line_size;
|
|
|
|
if (is_physical) {
|
2018-12-14 14:30:49 +01: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 14:57:25 +02:00
|
|
|
} else {
|
2017-01-13 13:12:35 +01:00
|
|
|
if (cpu_memory_rw_debug(cs, addr, buf, l, 0) < 0) {
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, " Cannot access memory\n");
|
2008-08-18 16:00:20 +02:00
|
|
|
break;
|
|
|
|
}
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
2007-09-16 23:08:06 +02:00
|
|
|
i = 0;
|
2004-04-04 14:57:25 +02:00
|
|
|
while (i < l) {
|
|
|
|
switch(wsize) {
|
|
|
|
default:
|
|
|
|
case 1:
|
2015-01-20 16:19:32 +01:00
|
|
|
v = ldub_p(buf + i);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2015-01-20 16:19:32 +01:00
|
|
|
v = lduw_p(buf + i);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case 4:
|
2015-01-20 16:19:32 +01:00
|
|
|
v = (uint32_t)ldl_p(buf + i);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case 8:
|
2015-01-20 16:19:32 +01:00
|
|
|
v = ldq_p(buf + i);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
}
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, " ");
|
2004-04-04 14:57:25 +02:00
|
|
|
switch(format) {
|
|
|
|
case 'o':
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "%#*" PRIo64, max_digits, v);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case 'x':
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "0x%0*" PRIx64, max_digits, v);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case 'u':
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "%*" PRIu64, max_digits, v);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case 'd':
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "%*" PRId64, max_digits, v);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case 'c':
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printc(mon, v);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
i += wsize;
|
|
|
|
}
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "\n");
|
2004-04-04 14:57:25 +02: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 13:55:43 +01:00
|
|
|
static void hmp_memory_dump(Monitor *mon, const QDict *qdict)
|
2004-04-04 14:57:25 +02:00
|
|
|
{
|
2009-08-28 20:27:17 +02: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-06 00:01:23 +01:00
|
|
|
memory_dump(mon, count, format, size, addr, 0);
|
2004-04-04 14:57:25 +02: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 13:55:43 +01:00
|
|
|
static void hmp_physical_memory_dump(Monitor *mon, const QDict *qdict)
|
2004-04-04 14:57:25 +02:00
|
|
|
{
|
2009-08-28 20:27:17 +02: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 12:30:10 +02:00
|
|
|
hwaddr addr = qdict_get_int(qdict, "addr");
|
2009-08-28 20:27:17 +02:00
|
|
|
|
2009-03-06 00:01:23 +01:00
|
|
|
memory_dump(mon, count, format, size, addr, 1);
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
|
|
|
|
2017-04-20 15:30:58 +02: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 17:26:52 +02: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 20:56:20 +02:00
|
|
|
gpa = cpu_get_phys_page_attrs_debug(cs, addr & TARGET_PAGE_MASK, &attrs);
|
2019-04-12 17:26:52 +02: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 15:30:58 +02: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;
|
|
|
|
uintptr_t pagesize = getpagesize();
|
|
|
|
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 20:27:17 +02:00
|
|
|
static void do_print(Monitor *mon, const QDict *qdict)
|
2004-04-04 14:57:25 +02:00
|
|
|
{
|
2009-08-28 20:27:17 +02:00
|
|
|
int format = qdict_get_int(qdict, "format");
|
2012-10-23 12:30:10 +02:00
|
|
|
hwaddr val = qdict_get_int(qdict, "val");
|
2009-08-28 20:27:17 +02:00
|
|
|
|
2004-04-04 14:57:25 +02:00
|
|
|
switch(format) {
|
|
|
|
case 'o':
|
2012-10-23 12:30:10 +02:00
|
|
|
monitor_printf(mon, "%#" HWADDR_PRIo, val);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case 'x':
|
2012-10-23 12:30:10 +02:00
|
|
|
monitor_printf(mon, "%#" HWADDR_PRIx, val);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case 'u':
|
2012-10-23 12:30:10 +02:00
|
|
|
monitor_printf(mon, "%" HWADDR_PRIu, val);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case 'd':
|
2012-10-23 12:30:10 +02:00
|
|
|
monitor_printf(mon, "%" HWADDR_PRId, val);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case 'c':
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printc(mon, val);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
}
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "\n");
|
2004-04-04 14:57:25 +02: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 13:55:43 +01:00
|
|
|
static void hmp_sum(Monitor *mon, const QDict *qdict)
|
2005-06-04 22:15:57 +02:00
|
|
|
{
|
|
|
|
uint32_t addr;
|
|
|
|
uint16_t sum;
|
2009-08-28 20:27:14 +02:00
|
|
|
uint32_t start = qdict_get_int(qdict, "start");
|
|
|
|
uint32_t size = qdict_get_int(qdict, "size");
|
2005-06-04 22:15:57 +02: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 17:49:24 +02:00
|
|
|
uint8_t val = address_space_ldub(&address_space_memory, addr,
|
|
|
|
MEMTXATTRS_UNSPECIFIED, NULL);
|
2005-06-04 22:15:57 +02:00
|
|
|
/* BSD sum algorithm ('sum' Unix command) */
|
|
|
|
sum = (sum >> 1) | (sum << 15);
|
2011-04-10 18:23:39 +02:00
|
|
|
sum += val;
|
2005-06-04 22:15:57 +02:00
|
|
|
}
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "%05d\n", sum);
|
2005-06-04 22:15:57 +02:00
|
|
|
}
|
|
|
|
|
2006-07-15 00:03:35 +02: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 13:55:43 +01:00
|
|
|
static void hmp_mouse_move(Monitor *mon, const QDict *qdict)
|
2006-07-15 00:03:35 +02:00
|
|
|
{
|
2013-12-04 15:02:28 +01:00
|
|
|
int dx, dy, dz, button;
|
2009-08-28 20:27:15 +02: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 15:02:28 +01:00
|
|
|
|
2006-07-15 00:03:35 +02:00
|
|
|
dx = strtol(dx_str, NULL, 0);
|
|
|
|
dy = strtol(dy_str, NULL, 0);
|
2013-12-04 15:02:28 +01:00
|
|
|
qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx);
|
|
|
|
qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy);
|
|
|
|
|
|
|
|
if (dz_str) {
|
2006-07-15 00:03:35 +02:00
|
|
|
dz = strtol(dz_str, NULL, 0);
|
2013-12-04 15:02:28 +01:00
|
|
|
if (dz != 0) {
|
2016-01-12 12:14:12 +01:00
|
|
|
button = (dz > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN;
|
2013-12-04 15:02:28 +01: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-15 00:03:35 +02: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 13:55:43 +01:00
|
|
|
static void hmp_mouse_button(Monitor *mon, const QDict *qdict)
|
2006-07-15 00:03:35 +02: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 09:52:57 +01:00
|
|
|
static uint32_t bmap[INPUT_BUTTON__MAX] = {
|
2013-12-04 15:02:28 +01:00
|
|
|
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
|
|
|
|
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
|
|
|
|
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
|
|
|
|
};
|
2009-08-28 20:27:13 +02:00
|
|
|
int button_state = qdict_get_int(qdict, "button_state");
|
2013-12-04 15:02:28 +01: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-15 00:03:35 +02: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 13:55:43 +01:00
|
|
|
static void hmp_ioport_read(Monitor *mon, const QDict *qdict)
|
2004-06-08 02:55:58 +02:00
|
|
|
{
|
2009-08-28 20:27:18 +02: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 02:55:58 +02:00
|
|
|
uint32_t val;
|
|
|
|
int suffix;
|
|
|
|
|
|
|
|
if (has_index) {
|
2009-08-28 20:27:18 +02:00
|
|
|
int index = qdict_get_int(qdict, "index");
|
2009-09-20 18:05:47 +02:00
|
|
|
cpu_outb(addr & IOPORTS_MASK, index & 0xff);
|
2004-06-08 02:55:58 +02:00
|
|
|
addr++;
|
|
|
|
}
|
|
|
|
addr &= 0xffff;
|
|
|
|
|
|
|
|
switch(size) {
|
|
|
|
default:
|
|
|
|
case 1:
|
2009-09-20 18:05:47 +02:00
|
|
|
val = cpu_inb(addr);
|
2004-06-08 02:55:58 +02:00
|
|
|
suffix = 'b';
|
|
|
|
break;
|
|
|
|
case 2:
|
2009-09-20 18:05:47 +02:00
|
|
|
val = cpu_inw(addr);
|
2004-06-08 02:55:58 +02:00
|
|
|
suffix = 'w';
|
|
|
|
break;
|
|
|
|
case 4:
|
2009-09-20 18:05:47 +02:00
|
|
|
val = cpu_inl(addr);
|
2004-06-08 02:55:58 +02:00
|
|
|
suffix = 'l';
|
|
|
|
break;
|
|
|
|
}
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "port%c[0x%04x] = %#0*x\n",
|
|
|
|
suffix, addr, size * 2, val);
|
2004-06-08 02:55:58 +02:00
|
|
|
}
|
2004-06-04 13:06:21 +02: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 13:55:43 +01:00
|
|
|
static void hmp_ioport_write(Monitor *mon, const QDict *qdict)
|
2009-07-14 10:20:11 +02:00
|
|
|
{
|
2009-08-28 20:27:17 +02: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 10:20:11 +02:00
|
|
|
addr &= IOPORTS_MASK;
|
|
|
|
|
|
|
|
switch (size) {
|
|
|
|
default:
|
|
|
|
case 1:
|
2009-09-20 18:05:47 +02:00
|
|
|
cpu_outb(addr, val);
|
2009-07-14 10:20:11 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2009-09-20 18:05:47 +02:00
|
|
|
cpu_outw(addr, val);
|
2009-07-14 10:20:11 +02:00
|
|
|
break;
|
|
|
|
case 4:
|
2009-09-20 18:05:47 +02:00
|
|
|
cpu_outl(addr, val);
|
2009-07-14 10:20:11 +02: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 13:55:43 +01:00
|
|
|
static void hmp_boot_set(Monitor *mon, const QDict *qdict)
|
2008-05-04 22:11:34 +02:00
|
|
|
{
|
2014-12-03 19:20:58 +01:00
|
|
|
Error *local_err = NULL;
|
2009-08-28 20:27:13 +02:00
|
|
|
const char *bootdevice = qdict_get_str(qdict, "bootdevice");
|
2008-05-04 22:11:34 +02:00
|
|
|
|
2014-12-03 19:20:58 +01: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 16:35:06 +01:00
|
|
|
error_report_err(local_err);
|
2008-05-04 22:11:34 +02:00
|
|
|
} else {
|
2014-12-03 19:20:58 +01:00
|
|
|
monitor_printf(mon, "boot device list now set to %s\n", bootdevice);
|
2008-05-04 22:11:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-06 14:18:24 +01:00
|
|
|
static void hmp_info_mtree(Monitor *mon, const QDict *qdict)
|
2011-09-11 22:22:05 +02:00
|
|
|
{
|
2017-01-16 09:40:05 +01:00
|
|
|
bool flatview = qdict_get_try_bool(qdict, "flatview", false);
|
2017-09-21 10:51:06 +02:00
|
|
|
bool dispatch_tree = qdict_get_try_bool(qdict, "dispatch_tree", false);
|
2018-06-04 05:25:11 +02:00
|
|
|
bool owner = qdict_get_try_bool(qdict, "owner", false);
|
2017-01-16 09:40:05 +01:00
|
|
|
|
2019-04-17 21:17:56 +02:00
|
|
|
mtree_info(flatview, dispatch_tree, owner);
|
2011-09-11 22:22:05 +02:00
|
|
|
}
|
|
|
|
|
2015-02-06 14:18:24 +01:00
|
|
|
static void hmp_info_numa(Monitor *mon, const QDict *qdict)
|
2009-04-22 00:30:47 +02:00
|
|
|
{
|
2009-04-22 22:20:29 +02:00
|
|
|
int i;
|
2017-08-29 17:30:20 +02:00
|
|
|
NumaNodeMem *node_mem;
|
2017-05-30 18:23:59 +02:00
|
|
|
CpuInfoList *cpu_list, *cpu;
|
2009-04-22 00:30:47 +02:00
|
|
|
|
2017-05-30 18:23:59 +02:00
|
|
|
cpu_list = qmp_query_cpus(&error_abort);
|
2017-08-29 17:30:20 +02:00
|
|
|
node_mem = g_new0(NumaNodeMem, nb_numa_nodes);
|
|
|
|
|
2014-11-04 12:49:30 +01:00
|
|
|
query_numa_node_mem(node_mem);
|
2009-04-22 00:30:47 +02:00
|
|
|
monitor_printf(mon, "%d nodes\n", nb_numa_nodes);
|
|
|
|
for (i = 0; i < nb_numa_nodes; i++) {
|
|
|
|
monitor_printf(mon, "node %d cpus:", i);
|
2017-05-30 18:23:59 +02:00
|
|
|
for (cpu = cpu_list; cpu; cpu = cpu->next) {
|
|
|
|
if (cpu->value->has_props && cpu->value->props->has_node_id &&
|
|
|
|
cpu->value->props->node_id == i) {
|
|
|
|
monitor_printf(mon, " %" PRIi64, cpu->value->CPU);
|
2009-04-22 00:30:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
monitor_printf(mon, "node %d size: %" PRId64 " MB\n", i,
|
2017-08-29 17:30:20 +02:00
|
|
|
node_mem[i].node_mem >> 20);
|
|
|
|
monitor_printf(mon, "node %d plugged: %" PRId64 " MB\n", i,
|
|
|
|
node_mem[i].node_plugged_mem >> 20);
|
2009-04-22 00:30:47 +02:00
|
|
|
}
|
2017-05-30 18:23:59 +02:00
|
|
|
qapi_free_CpuInfoList(cpu_list);
|
2014-11-04 12:49:30 +01:00
|
|
|
g_free(node_mem);
|
2009-04-22 00:30:47 +02:00
|
|
|
}
|
|
|
|
|
2006-02-08 23:40:15 +01:00
|
|
|
#ifdef CONFIG_PROFILER
|
|
|
|
|
2009-09-30 14:09:52 +02:00
|
|
|
int64_t dev_time;
|
|
|
|
|
2015-02-06 14:18:24 +01:00
|
|
|
static void hmp_info_profile(Monitor *mon, const QDict *qdict)
|
2006-02-08 23:40:15 +01:00
|
|
|
{
|
2018-10-10 16:48:53 +02: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-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "async time %" PRId64 " (%0.3f)\n",
|
2016-03-21 17:02:30 +01:00
|
|
|
dev_time, dev_time / (double)NANOSECONDS_PER_SECOND);
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "qemu time %" PRId64 " (%0.3f)\n",
|
2018-10-10 16:48:53 +02:00
|
|
|
delta, delta / (double)NANOSECONDS_PER_SECOND);
|
|
|
|
last_cpu_exec_time = cpu_exec_time;
|
2006-02-08 23:40:15 +01:00
|
|
|
dev_time = 0;
|
|
|
|
}
|
|
|
|
#else
|
2015-02-06 14:18:24 +01:00
|
|
|
static void hmp_info_profile(Monitor *mon, const QDict *qdict)
|
2006-02-08 23:40:15 +01:00
|
|
|
{
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "Internal profiler not compiled\n");
|
2006-02-08 23:40:15 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-07-16 20:57:03 +02:00
|
|
|
/* Capture support */
|
2009-09-12 09:36:22 +02:00
|
|
|
static QLIST_HEAD (capture_list_head, CaptureState) capture_head;
|
2006-07-16 20:57:03 +02:00
|
|
|
|
2015-02-06 14:18:24 +01:00
|
|
|
static void hmp_info_capture(Monitor *mon, const QDict *qdict)
|
2006-07-16 20:57:03 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
CaptureState *s;
|
|
|
|
|
|
|
|
for (s = capture_head.lh_first, i = 0; s; s = s->entries.le_next, ++i) {
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "[%d]: ", i);
|
2006-07-16 20:57:03 +02: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 13:55:43 +01:00
|
|
|
static void hmp_stopcapture(Monitor *mon, const QDict *qdict)
|
2006-07-16 20:57:03 +02:00
|
|
|
{
|
|
|
|
int i;
|
2009-08-28 20:27:13 +02:00
|
|
|
int n = qdict_get_int(qdict, "n");
|
2006-07-16 20:57:03 +02: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 09:36:22 +02:00
|
|
|
QLIST_REMOVE (s, entries);
|
2011-08-21 05:09:37 +02:00
|
|
|
g_free (s);
|
2006-07-16 20:57:03 +02: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 13:55:43 +01:00
|
|
|
static void hmp_wavcapture(Monitor *mon, const QDict *qdict)
|
2009-08-28 20:27:19 +02:00
|
|
|
{
|
|
|
|
const char *path = qdict_get_str(qdict, "path");
|
|
|
|
int has_freq = qdict_haskey(qdict, "freq");
|
|
|
|
int freq = qdict_get_try_int(qdict, "freq", -1);
|
|
|
|
int has_bits = qdict_haskey(qdict, "bits");
|
|
|
|
int bits = qdict_get_try_int(qdict, "bits", -1);
|
|
|
|
int has_channels = qdict_haskey(qdict, "nchannels");
|
|
|
|
int nchannels = qdict_get_try_int(qdict, "nchannels", -1);
|
2006-07-16 20:57:03 +02:00
|
|
|
CaptureState *s;
|
|
|
|
|
2011-08-21 05:09:37 +02:00
|
|
|
s = g_malloc0 (sizeof (*s));
|
2006-07-16 20:57:03 +02:00
|
|
|
|
|
|
|
freq = has_freq ? freq : 44100;
|
|
|
|
bits = has_bits ? bits : 16;
|
|
|
|
nchannels = has_channels ? nchannels : 2;
|
|
|
|
|
|
|
|
if (wav_start_capture (s, path, freq, bits, nchannels)) {
|
2011-01-21 11:53:55 +01:00
|
|
|
monitor_printf(mon, "Failed to add wave capture\n");
|
2011-08-21 05:09:37 +02:00
|
|
|
g_free (s);
|
2011-01-21 11:53:55 +01:00
|
|
|
return;
|
2006-07-16 20:57:03 +02:00
|
|
|
}
|
2009-09-12 09:36:22 +02:00
|
|
|
QLIST_INSERT_HEAD (&capture_head, s, entries);
|
2006-07-16 20:57:03 +02:00
|
|
|
}
|
|
|
|
|
2016-02-18 19:40:24 +01: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 21:27:37 +01:00
|
|
|
{
|
2016-02-18 19:40:24 +01: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 21:27:37 +01:00
|
|
|
|
2016-02-18 19:40:24 +01:00
|
|
|
container = object_get_objects_root();
|
|
|
|
obj = object_resolve_path_component(container, name);
|
|
|
|
if (!obj) {
|
2009-06-25 08:22:08 +02:00
|
|
|
monitor_printf(mon, "acl: unknown list '%s'\n", name);
|
2016-02-18 19:40:24 +01: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 21:27:37 +01:00
|
|
|
}
|
2016-02-18 19:40:24 +01:00
|
|
|
|
|
|
|
return QAUTHZ_LIST(obj);
|
2009-06-25 08:22:08 +02:00
|
|
|
}
|
|
|
|
|
2019-02-27 15:57:55 +01: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 13:55:43 +01:00
|
|
|
static void hmp_acl_show(Monitor *mon, const QDict *qdict)
|
2009-06-25 08:22:08 +02:00
|
|
|
{
|
2009-08-28 20:27:13 +02:00
|
|
|
const char *aclname = qdict_get_str(qdict, "aclname");
|
2016-02-18 19:40:24 +01:00
|
|
|
QAuthZList *auth = find_auth(mon, aclname);
|
|
|
|
QAuthZListRuleList *rules;
|
|
|
|
size_t i = 0;
|
|
|
|
|
2019-02-27 15:57:55 +01:00
|
|
|
hmp_warn_acl();
|
|
|
|
|
2016-02-18 19:40:24 +01: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 08:22:08 +02: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 13:55:43 +01:00
|
|
|
static void hmp_acl_reset(Monitor *mon, const QDict *qdict)
|
2009-06-25 08:22:08 +02:00
|
|
|
{
|
2009-08-28 20:27:13 +02:00
|
|
|
const char *aclname = qdict_get_str(qdict, "aclname");
|
2016-02-18 19:40:24 +01:00
|
|
|
QAuthZList *auth = find_auth(mon, aclname);
|
2009-06-25 08:22:08 +02:00
|
|
|
|
2019-02-27 15:57:55 +01:00
|
|
|
hmp_warn_acl();
|
|
|
|
|
2016-02-18 19:40:24 +01:00
|
|
|
if (!auth) {
|
|
|
|
return;
|
2009-06-25 08:22:08 +02:00
|
|
|
}
|
2016-02-18 19:40:24 +01: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 08:22:08 +02: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 13:55:43 +01:00
|
|
|
static void hmp_acl_policy(Monitor *mon, const QDict *qdict)
|
2009-06-25 08:22:08 +02:00
|
|
|
{
|
2009-08-28 20:27:14 +02:00
|
|
|
const char *aclname = qdict_get_str(qdict, "aclname");
|
|
|
|
const char *policy = qdict_get_str(qdict, "policy");
|
2016-02-18 19:40:24 +01:00
|
|
|
QAuthZList *auth = find_auth(mon, aclname);
|
|
|
|
int val;
|
|
|
|
Error *err = NULL;
|
2009-03-06 21:27:40 +01:00
|
|
|
|
2019-02-27 15:57:55 +01:00
|
|
|
hmp_warn_acl();
|
|
|
|
|
2016-02-18 19:40:24 +01: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 21:27:40 +01:00
|
|
|
monitor_printf(mon, "acl: policy set to 'allow'\n");
|
|
|
|
} else {
|
2016-02-18 19:40:24 +01:00
|
|
|
monitor_printf(mon, "acl: policy set to 'deny'\n");
|
2009-03-06 21:27:40 +01:00
|
|
|
}
|
2009-06-25 08:22:08 +02:00
|
|
|
}
|
|
|
|
}
|
2009-03-06 21:27:40 +01:00
|
|
|
|
2016-02-18 19:40:24 +01: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 13:55:43 +01:00
|
|
|
static void hmp_acl_add(Monitor *mon, const QDict *qdict)
|
2009-06-25 08:22:08 +02:00
|
|
|
{
|
2009-08-28 20:27:17 +02:00
|
|
|
const char *aclname = qdict_get_str(qdict, "aclname");
|
|
|
|
const char *match = qdict_get_str(qdict, "match");
|
2016-02-18 19:40:24 +01:00
|
|
|
const char *policystr = qdict_get_str(qdict, "policy");
|
2009-08-28 20:27:17 +02:00
|
|
|
int has_index = qdict_haskey(qdict, "index");
|
|
|
|
int index = qdict_get_try_int(qdict, "index", -1);
|
2016-02-18 19:40:24 +01:00
|
|
|
QAuthZList *auth = find_auth(mon, aclname);
|
|
|
|
Error *err = NULL;
|
|
|
|
QAuthZListPolicy policy;
|
|
|
|
QAuthZListFormat format;
|
|
|
|
size_t i = 0;
|
|
|
|
|
2019-02-27 15:57:55 +01:00
|
|
|
hmp_warn_acl();
|
|
|
|
|
2016-02-18 19:40:24 +01: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 08:22:08 +02:00
|
|
|
}
|
|
|
|
}
|
2009-03-06 21:27:40 +01: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 13:55:43 +01:00
|
|
|
static void hmp_acl_remove(Monitor *mon, const QDict *qdict)
|
2009-06-25 08:22:08 +02:00
|
|
|
{
|
2009-08-28 20:27:14 +02:00
|
|
|
const char *aclname = qdict_get_str(qdict, "aclname");
|
|
|
|
const char *match = qdict_get_str(qdict, "match");
|
2016-02-18 19:40:24 +01:00
|
|
|
QAuthZList *auth = find_auth(mon, aclname);
|
|
|
|
ssize_t i = 0;
|
2009-03-06 21:27:40 +01:00
|
|
|
|
2019-02-27 15:57:55 +01:00
|
|
|
hmp_warn_acl();
|
|
|
|
|
2016-02-18 19:40:24 +01: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 21:27:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-22 20:36:09 +02:00
|
|
|
void qmp_getfd(const char *fdname, Error **errp)
|
2009-07-22 10:11:40 +02:00
|
|
|
{
|
2009-10-01 23:12:16 +02:00
|
|
|
mon_fd_t *monfd;
|
2018-06-08 05:55:06 +02:00
|
|
|
int fd, tmp_fd;
|
2009-07-22 10:11:40 +02:00
|
|
|
|
2016-10-22 11:52:55 +02:00
|
|
|
fd = qemu_chr_fe_get_msgfd(&cur_mon->chr);
|
2009-07-22 10:11:40 +02:00
|
|
|
if (fd == -1) {
|
2015-03-17 11:54:50 +01:00
|
|
|
error_setg(errp, QERR_FD_NOT_SUPPLIED);
|
2012-06-22 20:36:09 +02:00
|
|
|
return;
|
2009-07-22 10:11:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (qemu_isdigit(fdname[0])) {
|
2014-04-24 13:58:18 +02:00
|
|
|
close(fd);
|
2015-03-17 11:54:50 +01:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdname",
|
|
|
|
"a name not starting with a digit");
|
2012-06-22 20:36:09 +02:00
|
|
|
return;
|
2009-07-22 10:11:40 +02:00
|
|
|
}
|
|
|
|
|
2018-06-08 05:55:06 +02:00
|
|
|
qemu_mutex_lock(&cur_mon->mon_lock);
|
2012-06-22 20:36:09 +02:00
|
|
|
QLIST_FOREACH(monfd, &cur_mon->fds, next) {
|
2009-07-22 10:11:40 +02:00
|
|
|
if (strcmp(monfd->name, fdname) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-06-08 05:55:06 +02:00
|
|
|
tmp_fd = monfd->fd;
|
2009-07-22 10:11:40 +02:00
|
|
|
monfd->fd = fd;
|
2018-06-08 05:55:06 +02:00
|
|
|
qemu_mutex_unlock(&cur_mon->mon_lock);
|
2018-07-03 10:53:57 +02:00
|
|
|
/* Make sure close() is outside critical section */
|
2018-06-08 05:55:06 +02:00
|
|
|
close(tmp_fd);
|
2012-06-22 20:36:09 +02:00
|
|
|
return;
|
2009-07-22 10:11:40 +02:00
|
|
|
}
|
|
|
|
|
2011-08-21 05:09:37 +02:00
|
|
|
monfd = g_malloc0(sizeof(mon_fd_t));
|
|
|
|
monfd->name = g_strdup(fdname);
|
2009-07-22 10:11:40 +02:00
|
|
|
monfd->fd = fd;
|
|
|
|
|
2012-06-22 20:36:09 +02:00
|
|
|
QLIST_INSERT_HEAD(&cur_mon->fds, monfd, next);
|
2018-06-08 05:55:06 +02:00
|
|
|
qemu_mutex_unlock(&cur_mon->mon_lock);
|
2009-07-22 10:11:40 +02:00
|
|
|
}
|
|
|
|
|
2012-06-22 20:36:09 +02:00
|
|
|
void qmp_closefd(const char *fdname, Error **errp)
|
2009-07-22 10:11:40 +02:00
|
|
|
{
|
2009-10-01 23:12:16 +02:00
|
|
|
mon_fd_t *monfd;
|
2018-06-08 05:55:06 +02:00
|
|
|
int tmp_fd;
|
2009-07-22 10:11:40 +02:00
|
|
|
|
2018-06-08 05:55:06 +02:00
|
|
|
qemu_mutex_lock(&cur_mon->mon_lock);
|
2012-06-22 20:36:09 +02:00
|
|
|
QLIST_FOREACH(monfd, &cur_mon->fds, next) {
|
2009-07-22 10:11:40 +02:00
|
|
|
if (strcmp(monfd->name, fdname) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-09-12 09:36:22 +02:00
|
|
|
QLIST_REMOVE(monfd, next);
|
2018-06-08 05:55:06 +02:00
|
|
|
tmp_fd = monfd->fd;
|
2011-08-21 05:09:37 +02:00
|
|
|
g_free(monfd->name);
|
|
|
|
g_free(monfd);
|
2018-06-08 05:55:06 +02:00
|
|
|
qemu_mutex_unlock(&cur_mon->mon_lock);
|
2018-07-03 10:53:57 +02:00
|
|
|
/* Make sure close() is outside critical section */
|
2018-06-08 05:55:06 +02:00
|
|
|
close(tmp_fd);
|
2012-06-22 20:36:09 +02:00
|
|
|
return;
|
2009-07-22 10:11:40 +02:00
|
|
|
}
|
|
|
|
|
2018-06-08 05:55:06 +02:00
|
|
|
qemu_mutex_unlock(&cur_mon->mon_lock);
|
2015-03-17 11:54:50 +01:00
|
|
|
error_setg(errp, QERR_FD_NOT_FOUND, fdname);
|
2009-07-22 10:11:40 +02:00
|
|
|
}
|
|
|
|
|
2012-09-20 16:50:32 +02:00
|
|
|
int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
|
2009-07-22 10:11:41 +02:00
|
|
|
{
|
2009-10-01 23:12:16 +02:00
|
|
|
mon_fd_t *monfd;
|
2009-07-22 10:11:41 +02:00
|
|
|
|
2018-06-08 05:55:06 +02:00
|
|
|
qemu_mutex_lock(&mon->mon_lock);
|
2009-09-12 09:36:22 +02:00
|
|
|
QLIST_FOREACH(monfd, &mon->fds, next) {
|
2009-07-22 10:11:41 +02:00
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (strcmp(monfd->name, fdname) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = monfd->fd;
|
|
|
|
|
|
|
|
/* caller takes ownership of fd */
|
2009-09-12 09:36:22 +02:00
|
|
|
QLIST_REMOVE(monfd, next);
|
2011-08-21 05:09:37 +02:00
|
|
|
g_free(monfd->name);
|
|
|
|
g_free(monfd);
|
2018-06-08 05:55:06 +02:00
|
|
|
qemu_mutex_unlock(&mon->mon_lock);
|
2009-07-22 10:11:41 +02:00
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2018-06-08 05:55:06 +02:00
|
|
|
qemu_mutex_unlock(&mon->mon_lock);
|
2012-09-20 16:50:32 +02:00
|
|
|
error_setg(errp, "File descriptor named '%s' has not been found", fdname);
|
2009-07-22 10:11:41 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-08-14 22:43:43 +02: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 21:19:33 +02:00
|
|
|
if ((mon_fdset_fd->removed ||
|
|
|
|
(QLIST_EMPTY(&mon_fdset->dup_fds) && mon_refcount == 0)) &&
|
|
|
|
runstate_is_running()) {
|
2012-08-14 22:43:43 +02: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 22:43:47 +02:00
|
|
|
if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) {
|
2012-08-14 22:43:43 +02:00
|
|
|
QLIST_REMOVE(mon_fdset, next);
|
|
|
|
g_free(mon_fdset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-14 22:43:48 +02:00
|
|
|
static void monitor_fdsets_cleanup(void)
|
|
|
|
{
|
|
|
|
MonFdset *mon_fdset;
|
|
|
|
MonFdset *mon_fdset_next;
|
|
|
|
|
2018-06-08 05:55:11 +02:00
|
|
|
qemu_mutex_lock(&mon_fdsets_lock);
|
2012-08-14 22:43:48 +02:00
|
|
|
QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) {
|
|
|
|
monitor_fdset_cleanup(mon_fdset);
|
|
|
|
}
|
2018-06-08 05:55:11 +02:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-08-14 22:43:48 +02:00
|
|
|
}
|
|
|
|
|
2012-08-14 22:43:43 +02: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 11:52:55 +02:00
|
|
|
fd = qemu_chr_fe_get_msgfd(&mon->chr);
|
2012-08-14 22:43:43 +02:00
|
|
|
if (fd == -1) {
|
2015-03-17 11:54:50 +01:00
|
|
|
error_setg(errp, QERR_FD_NOT_SUPPLIED);
|
2012-08-14 22:43:43 +02:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-10-18 21:19:32 +02:00
|
|
|
fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id,
|
|
|
|
has_opaque, opaque, errp);
|
|
|
|
if (fdinfo) {
|
|
|
|
return fdinfo;
|
2012-08-14 22:43:43 +02: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 05:55:11 +02:00
|
|
|
qemu_mutex_lock(&mon_fdsets_lock);
|
2012-08-14 22:43:43 +02: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 05:55:11 +02:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-08-14 22:43:43 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
error:
|
2018-06-08 05:55:11 +02:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-08-14 22:43:43 +02: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 11:54:50 +01:00
|
|
|
error_setg(errp, QERR_FD_NOT_FOUND, fd_str);
|
2012-08-14 22:43:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
FdsetInfoList *qmp_query_fdsets(Error **errp)
|
|
|
|
{
|
|
|
|
MonFdset *mon_fdset;
|
|
|
|
MonFdsetFd *mon_fdset_fd;
|
|
|
|
FdsetInfoList *fdset_list = NULL;
|
|
|
|
|
2018-06-08 05:55:11 +02:00
|
|
|
qemu_mutex_lock(&mon_fdsets_lock);
|
2012-08-14 22:43:43 +02: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 05:55:11 +02:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-08-14 22:43:43 +02:00
|
|
|
|
|
|
|
return fdset_list;
|
|
|
|
}
|
|
|
|
|
2012-10-18 21:19:32 +02: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 05:55:11 +02:00
|
|
|
qemu_mutex_lock(&mon_fdsets_lock);
|
2012-10-18 21:19:32 +02: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 11:54:50 +01:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id",
|
|
|
|
"a non-negative value");
|
2018-06-08 05:55:11 +02:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-10-18 21:19:32 +02: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 05:55:11 +02:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-10-18 21:19:32 +02:00
|
|
|
return fdinfo;
|
|
|
|
}
|
|
|
|
|
2012-08-14 22:43:47 +02:00
|
|
|
int monitor_fdset_get_fd(int64_t fdset_id, int flags)
|
|
|
|
{
|
2018-06-08 05:55:11 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
return -ENOENT;
|
|
|
|
#else
|
2012-08-14 22:43:47 +02:00
|
|
|
MonFdset *mon_fdset;
|
|
|
|
MonFdsetFd *mon_fdset_fd;
|
|
|
|
int mon_fd_flags;
|
2018-06-08 05:55:11 +02:00
|
|
|
int ret;
|
2012-08-14 22:43:47 +02:00
|
|
|
|
2018-06-08 05:55:11 +02:00
|
|
|
qemu_mutex_lock(&mon_fdsets_lock);
|
2012-08-14 22:43:47 +02: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 05:55:11 +02:00
|
|
|
ret = -errno;
|
|
|
|
goto out;
|
2012-08-14 22:43:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) {
|
2018-06-08 05:55:11 +02:00
|
|
|
ret = mon_fdset_fd->fd;
|
|
|
|
goto out;
|
2012-08-14 22:43:47 +02:00
|
|
|
}
|
|
|
|
}
|
2018-06-08 05:55:11 +02:00
|
|
|
ret = -EACCES;
|
|
|
|
goto out;
|
2012-08-14 22:43:47 +02:00
|
|
|
}
|
2018-06-08 05:55:11 +02:00
|
|
|
ret = -ENOENT;
|
2012-08-14 22:43:47 +02:00
|
|
|
|
2018-06-08 05:55:11 +02:00
|
|
|
out:
|
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
|
|
|
return ret;
|
|
|
|
#endif
|
2012-08-14 22:43:47 +02: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 05:55:11 +02:00
|
|
|
qemu_mutex_lock(&mon_fdsets_lock);
|
2012-08-14 22:43:47 +02: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 05:55:11 +02:00
|
|
|
goto err;
|
2012-08-14 22:43:47 +02: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 05:55:11 +02:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-08-14 22:43:47 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2018-06-08 05:55:11 +02:00
|
|
|
|
|
|
|
err:
|
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-08-14 22:43:47 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove)
|
|
|
|
{
|
|
|
|
MonFdset *mon_fdset;
|
|
|
|
MonFdsetFd *mon_fdset_fd_dup;
|
|
|
|
|
2018-06-08 05:55:11 +02:00
|
|
|
qemu_mutex_lock(&mon_fdsets_lock);
|
2012-08-14 22:43:47 +02: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);
|
|
|
|
if (QLIST_EMPTY(&mon_fdset->dup_fds)) {
|
|
|
|
monitor_fdset_cleanup(mon_fdset);
|
|
|
|
}
|
2018-06-08 05:55:11 +02:00
|
|
|
goto err;
|
2014-08-17 11:45:17 +02:00
|
|
|
} else {
|
2018-06-08 05:55:11 +02:00
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2014-08-17 11:45:17 +02:00
|
|
|
return mon_fdset->id;
|
2012-08-14 22:43:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-06-08 05:55:11 +02:00
|
|
|
|
|
|
|
err:
|
|
|
|
qemu_mutex_unlock(&mon_fdsets_lock);
|
2012-08-14 22:43:47 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int monitor_fdset_dup_fd_find(int dup_fd)
|
|
|
|
{
|
|
|
|
return monitor_fdset_dup_fd_find_remove(dup_fd, false);
|
|
|
|
}
|
|
|
|
|
2014-08-17 11:45:17 +02:00
|
|
|
void monitor_fdset_dup_fd_remove(int dup_fd)
|
2012-08-14 22:43:47 +02:00
|
|
|
{
|
2014-08-17 11:45:17 +02:00
|
|
|
monitor_fdset_dup_fd_find_remove(dup_fd, true);
|
2012-08-14 22:43:47 +02:00
|
|
|
}
|
|
|
|
|
2015-02-09 14:03:19 +01:00
|
|
|
int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp)
|
2014-04-10 10:24:31 +02:00
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
Error *local_err = NULL;
|
2012-08-21 22:52:07 +02:00
|
|
|
|
2014-04-10 10:24:31 +02:00
|
|
|
if (!qemu_isdigit(fdname[0]) && mon) {
|
2012-09-20 16:50:32 +02:00
|
|
|
fd = monitor_get_fd(mon, fdname, &local_err);
|
2014-04-10 10:24:31 +02:00
|
|
|
} else {
|
|
|
|
fd = qemu_parse_fd(fdname);
|
2012-08-21 22:52:07 +02:00
|
|
|
if (fd == -1) {
|
2014-04-10 10:24:31 +02:00
|
|
|
error_setg(&local_err, "Invalid file descriptor number '%s'",
|
|
|
|
fdname);
|
2012-08-21 22:52:07 +02:00
|
|
|
}
|
2014-04-10 10:24:31 +02:00
|
|
|
}
|
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
assert(fd == -1);
|
2012-08-21 22:52:07 +02:00
|
|
|
} else {
|
2014-04-10 10:24:31 +02:00
|
|
|
assert(fd != -1);
|
2012-08-21 22:52:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2010-09-30 21:00:22 +02:00
|
|
|
/* Please update hmp-commands.hx when adding or changing commands */
|
2011-10-12 05:32:41 +02:00
|
|
|
static mon_cmd_t info_cmds[] = {
|
2015-09-10 17:38:58 +02:00
|
|
|
#include "hmp-commands-info.h"
|
|
|
|
{ NULL, NULL, },
|
2004-03-14 22:38:27 +01:00
|
|
|
};
|
|
|
|
|
2013-01-14 07:06:28 +01:00
|
|
|
/* mon_cmds and info_cmds would be sorted at runtime */
|
|
|
|
static mon_cmd_t mon_cmds[] = {
|
|
|
|
#include "hmp-commands.h"
|
|
|
|
{ NULL, NULL, },
|
|
|
|
};
|
|
|
|
|
2004-04-04 14:57:25 +02:00
|
|
|
/*******************************************************************/
|
|
|
|
|
|
|
|
static const char *pch;
|
2013-02-20 16:21:09 +01:00
|
|
|
static sigjmp_buf expr_env;
|
2004-04-04 14:57:25 +02:00
|
|
|
|
|
|
|
|
2013-08-22 21:30:09 +02:00
|
|
|
static void GCC_FMT_ATTR(2, 3) QEMU_NORETURN
|
|
|
|
expr_error(Monitor *mon, const char *fmt, ...)
|
2004-03-14 22:38:27 +01:00
|
|
|
{
|
2013-08-20 04:58:21 +02:00
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
monitor_vprintf(mon, fmt, ap);
|
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
va_end(ap);
|
2013-02-20 16:21:09 +01:00
|
|
|
siglongjmp(expr_env, 1);
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
|
|
|
|
2010-01-20 13:07:30 +01:00
|
|
|
/* return 0 if OK, -1 if not found */
|
2005-02-10 23:00:52 +01:00
|
|
|
static int get_monitor_def(target_long *pval, const char *name)
|
2004-04-04 14:57:25 +02:00
|
|
|
{
|
2015-09-10 17:38:59 +02:00
|
|
|
const MonitorDef *md = target_monitor_defs();
|
2017-01-13 13:12:35 +01:00
|
|
|
CPUState *cs = mon_get_cpu();
|
2005-02-10 23:00:52 +01:00
|
|
|
void *ptr;
|
2015-11-12 04:44:23 +01:00
|
|
|
uint64_t tmp = 0;
|
|
|
|
int ret;
|
2005-02-10 23:00:52 +01:00
|
|
|
|
2017-01-13 13:12:35 +01:00
|
|
|
if (cs == NULL || md == NULL) {
|
2015-09-10 17:38:59 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(; md->name != NULL; md++) {
|
2004-04-04 14:57:25 +02:00
|
|
|
if (compare_cmd(name, md->name)) {
|
|
|
|
if (md->get_value) {
|
2004-10-01 00:22:08 +02:00
|
|
|
*pval = md->get_value(md, md->offset);
|
2004-04-04 14:57:25 +02:00
|
|
|
} else {
|
2015-05-24 23:20:40 +02:00
|
|
|
CPUArchState *env = mon_get_cpu_env();
|
2005-11-22 00:25:50 +01:00
|
|
|
ptr = (uint8_t *)env + md->offset;
|
2005-02-10 23:00:52 +01: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 14:57:25 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2015-11-12 04:44:23 +01:00
|
|
|
|
2017-01-13 13:12:35 +01:00
|
|
|
ret = target_get_monitor_def(cs, name, &tmp);
|
2015-11-12 04:44:23 +01:00
|
|
|
if (!ret) {
|
|
|
|
*pval = (target_long) tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void next(void)
|
|
|
|
{
|
2009-07-31 23:16:51 +02:00
|
|
|
if (*pch != '\0') {
|
2004-04-04 14:57:25 +02:00
|
|
|
pch++;
|
2008-11-16 14:53:32 +01:00
|
|
|
while (qemu_isspace(*pch))
|
2004-04-04 14:57:25 +02:00
|
|
|
pch++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-06 00:01:23 +01:00
|
|
|
static int64_t expr_sum(Monitor *mon);
|
2004-04-04 14:57:25 +02:00
|
|
|
|
2009-03-06 00:01:23 +01:00
|
|
|
static int64_t expr_unary(Monitor *mon)
|
2004-04-04 14:57:25 +02:00
|
|
|
{
|
2007-09-25 19:28:42 +02:00
|
|
|
int64_t n;
|
2004-04-04 14:57:25 +02:00
|
|
|
char *p;
|
2005-11-22 00:25:50 +01:00
|
|
|
int ret;
|
2004-04-04 14:57:25 +02:00
|
|
|
|
|
|
|
switch(*pch) {
|
|
|
|
case '+':
|
|
|
|
next();
|
2009-03-06 00:01:23 +01:00
|
|
|
n = expr_unary(mon);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
next();
|
2009-03-06 00:01:23 +01:00
|
|
|
n = -expr_unary(mon);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case '~':
|
|
|
|
next();
|
2009-03-06 00:01:23 +01:00
|
|
|
n = ~expr_unary(mon);
|
2004-04-04 14:57:25 +02:00
|
|
|
break;
|
|
|
|
case '(':
|
|
|
|
next();
|
2009-03-06 00:01:23 +01:00
|
|
|
n = expr_sum(mon);
|
2004-04-04 14:57:25 +02:00
|
|
|
if (*pch != ')') {
|
2009-03-06 00:01:23 +01:00
|
|
|
expr_error(mon, "')' expected");
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
|
|
|
next();
|
|
|
|
break;
|
2004-07-14 19:21:37 +02:00
|
|
|
case '\'':
|
|
|
|
pch++;
|
|
|
|
if (*pch == '\0')
|
2009-03-06 00:01:23 +01:00
|
|
|
expr_error(mon, "character constant expected");
|
2004-07-14 19:21:37 +02:00
|
|
|
n = *pch;
|
|
|
|
pch++;
|
|
|
|
if (*pch != '\'')
|
2009-03-06 00:01:23 +01:00
|
|
|
expr_error(mon, "missing terminating \' character");
|
2004-07-14 19:21:37 +02:00
|
|
|
next();
|
|
|
|
break;
|
2004-04-04 14:57:25 +02:00
|
|
|
case '$':
|
|
|
|
{
|
|
|
|
char buf[128], *q;
|
2007-12-17 04:15:52 +01:00
|
|
|
target_long reg=0;
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2004-04-04 14:57:25 +02:00
|
|
|
pch++;
|
|
|
|
q = buf;
|
|
|
|
while ((*pch >= 'a' && *pch <= 'z') ||
|
|
|
|
(*pch >= 'A' && *pch <= 'Z') ||
|
|
|
|
(*pch >= '0' && *pch <= '9') ||
|
2004-04-25 20:54:52 +02:00
|
|
|
*pch == '_' || *pch == '.') {
|
2004-04-04 14:57:25 +02:00
|
|
|
if ((q - buf) < sizeof(buf) - 1)
|
|
|
|
*q++ = *pch;
|
|
|
|
pch++;
|
|
|
|
}
|
2008-11-16 14:53:32 +01:00
|
|
|
while (qemu_isspace(*pch))
|
2004-04-04 14:57:25 +02:00
|
|
|
pch++;
|
|
|
|
*q = 0;
|
2007-09-24 20:39:04 +02:00
|
|
|
ret = get_monitor_def(®, buf);
|
2010-01-20 13:07:30 +01:00
|
|
|
if (ret < 0)
|
2009-03-06 00:01:23 +01:00
|
|
|
expr_error(mon, "unknown register");
|
2007-09-24 20:39:04 +02:00
|
|
|
n = reg;
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '\0':
|
2009-03-06 00:01:23 +01:00
|
|
|
expr_error(mon, "unexpected end of expression");
|
2004-04-04 14:57:25 +02:00
|
|
|
n = 0;
|
|
|
|
break;
|
|
|
|
default:
|
2012-04-26 21:48:41 +02:00
|
|
|
errno = 0;
|
2006-06-25 20:28:12 +02:00
|
|
|
n = strtoull(pch, &p, 0);
|
2012-04-26 21:48:41 +02:00
|
|
|
if (errno == ERANGE) {
|
|
|
|
expr_error(mon, "number too large");
|
|
|
|
}
|
2004-04-04 14:57:25 +02:00
|
|
|
if (pch == p) {
|
2013-08-20 04:58:21 +02:00
|
|
|
expr_error(mon, "invalid char '%c' in expression", *p);
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
|
|
|
pch = p;
|
2008-11-16 14:53:32 +01:00
|
|
|
while (qemu_isspace(*pch))
|
2004-04-04 14:57:25 +02:00
|
|
|
pch++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-06 00:01:23 +01:00
|
|
|
static int64_t expr_prod(Monitor *mon)
|
2004-04-04 14:57:25 +02:00
|
|
|
{
|
2007-09-25 19:28:42 +02:00
|
|
|
int64_t val, val2;
|
2005-02-10 23:00:52 +01:00
|
|
|
int op;
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2009-03-06 00:01:23 +01:00
|
|
|
val = expr_unary(mon);
|
2004-04-04 14:57:25 +02:00
|
|
|
for(;;) {
|
|
|
|
op = *pch;
|
|
|
|
if (op != '*' && op != '/' && op != '%')
|
|
|
|
break;
|
|
|
|
next();
|
2009-03-06 00:01:23 +01:00
|
|
|
val2 = expr_unary(mon);
|
2004-04-04 14:57:25 +02:00
|
|
|
switch(op) {
|
|
|
|
default:
|
|
|
|
case '*':
|
|
|
|
val *= val2;
|
|
|
|
break;
|
|
|
|
case '/':
|
|
|
|
case '%':
|
2007-09-16 23:08:06 +02:00
|
|
|
if (val2 == 0)
|
2009-03-06 00:01:23 +01:00
|
|
|
expr_error(mon, "division by zero");
|
2004-04-04 14:57:25 +02:00
|
|
|
if (op == '/')
|
|
|
|
val /= val2;
|
|
|
|
else
|
|
|
|
val %= val2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2009-03-06 00:01:23 +01:00
|
|
|
static int64_t expr_logic(Monitor *mon)
|
2004-04-04 14:57:25 +02:00
|
|
|
{
|
2007-09-25 19:28:42 +02:00
|
|
|
int64_t val, val2;
|
2005-02-10 23:00:52 +01:00
|
|
|
int op;
|
2004-04-04 14:57:25 +02:00
|
|
|
|
2009-03-06 00:01:23 +01:00
|
|
|
val = expr_prod(mon);
|
2004-04-04 14:57:25 +02:00
|
|
|
for(;;) {
|
|
|
|
op = *pch;
|
|
|
|
if (op != '&' && op != '|' && op != '^')
|
|
|
|
break;
|
|
|
|
next();
|
2009-03-06 00:01:23 +01:00
|
|
|
val2 = expr_prod(mon);
|
2004-04-04 14:57:25 +02:00
|
|
|
switch(op) {
|
|
|
|
default:
|
|
|
|
case '&':
|
|
|
|
val &= val2;
|
|
|
|
break;
|
|
|
|
case '|':
|
|
|
|
val |= val2;
|
|
|
|
break;
|
|
|
|
case '^':
|
|
|
|
val ^= val2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2009-03-06 00:01:23 +01:00
|
|
|
static int64_t expr_sum(Monitor *mon)
|
2004-04-04 14:57:25 +02:00
|
|
|
{
|
2007-09-25 19:28:42 +02:00
|
|
|
int64_t val, val2;
|
2005-02-10 23:00:52 +01:00
|
|
|
int op;
|
2004-04-04 14:57:25 +02:00
|
|
|
|
2009-03-06 00:01:23 +01:00
|
|
|
val = expr_logic(mon);
|
2004-04-04 14:57:25 +02:00
|
|
|
for(;;) {
|
|
|
|
op = *pch;
|
|
|
|
if (op != '+' && op != '-')
|
|
|
|
break;
|
|
|
|
next();
|
2009-03-06 00:01:23 +01:00
|
|
|
val2 = expr_logic(mon);
|
2004-04-04 14:57:25 +02:00
|
|
|
if (op == '+')
|
|
|
|
val += val2;
|
|
|
|
else
|
|
|
|
val -= val2;
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2009-03-06 00:01:23 +01:00
|
|
|
static int get_expr(Monitor *mon, int64_t *pval, const char **pp)
|
2004-04-04 14:57:25 +02:00
|
|
|
{
|
|
|
|
pch = *pp;
|
2013-02-20 16:21:09 +01:00
|
|
|
if (sigsetjmp(expr_env, 0)) {
|
2004-04-04 14:57:25 +02:00
|
|
|
*pp = pch;
|
|
|
|
return -1;
|
|
|
|
}
|
2008-11-16 14:53:32 +01:00
|
|
|
while (qemu_isspace(*pch))
|
2004-04-04 14:57:25 +02:00
|
|
|
pch++;
|
2009-03-06 00:01:23 +01:00
|
|
|
*pval = expr_sum(mon);
|
2004-04-04 14:57:25 +02:00
|
|
|
*pp = pch;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-01-25 14:23:03 +01:00
|
|
|
static int get_double(Monitor *mon, double *pval, const char **pp)
|
|
|
|
{
|
|
|
|
const char *p = *pp;
|
|
|
|
char *tailp;
|
|
|
|
double d;
|
|
|
|
|
|
|
|
d = strtod(p, &tailp);
|
|
|
|
if (tailp == p) {
|
|
|
|
monitor_printf(mon, "Number expected\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (d != d || d - d != 0) {
|
|
|
|
/* NaN or infinity */
|
|
|
|
monitor_printf(mon, "Bad number\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
*pval = d;
|
|
|
|
*pp = tailp;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-06-09 23:21:30 +02:00
|
|
|
/*
|
|
|
|
* Store the command-name in cmdname, and return a pointer to
|
|
|
|
* the remaining of the command string.
|
|
|
|
*/
|
|
|
|
static const char *get_command_name(const char *cmdline,
|
|
|
|
char *cmdname, size_t nlen)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
const char *p, *pstart;
|
|
|
|
|
|
|
|
p = cmdline;
|
|
|
|
while (qemu_isspace(*p))
|
|
|
|
p++;
|
|
|
|
if (*p == '\0')
|
|
|
|
return NULL;
|
|
|
|
pstart = p;
|
|
|
|
while (*p != '\0' && *p != '/' && !qemu_isspace(*p))
|
|
|
|
p++;
|
|
|
|
len = p - pstart;
|
|
|
|
if (len > nlen - 1)
|
|
|
|
len = nlen - 1;
|
|
|
|
memcpy(cmdname, pstart, len);
|
|
|
|
cmdname[len] = '\0';
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
monitor: New format for handlers argument types
Current handlers argument types, as defined in qemu-monitor.hx file,
are a sequence of chars where each one represents one argument type
of the command handler. The number of chars is also used to know how
many arguments a given handler accepts.
This commit defines a new format, which makes mandatory the use of
a name for each argument.
For example, do_eject() command handler is currently defined as:
{ "eject", "-fB", do_eject, ... }
With the new format it becomes:
{ "eject", "force:-f,filename:B", do_eject, ... }
This way the Monitor will be capable of setting up a dictionary, using
each argument's name as the key and the argument itself as the value.
This commit also adds two new functions: key_get_info() and
next_arg_type(), both are used to parse the new format.
Currently key_get_info() consumes the 'key' part of the new format and
discards it, this way the current parsing code is not affected by this
change.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-08-28 20:27:09 +02:00
|
|
|
/**
|
|
|
|
* Read key of 'type' into 'key' and return the current
|
|
|
|
* 'type' pointer.
|
|
|
|
*/
|
|
|
|
static char *key_get_info(const char *type, char **key)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
char *p, *str;
|
|
|
|
|
|
|
|
if (*type == ',')
|
|
|
|
type++;
|
|
|
|
|
|
|
|
p = strchr(type, ':');
|
|
|
|
if (!p) {
|
|
|
|
*key = NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
len = p - type;
|
|
|
|
|
2011-08-21 05:09:37 +02:00
|
|
|
str = g_malloc(len + 1);
|
monitor: New format for handlers argument types
Current handlers argument types, as defined in qemu-monitor.hx file,
are a sequence of chars where each one represents one argument type
of the command handler. The number of chars is also used to know how
many arguments a given handler accepts.
This commit defines a new format, which makes mandatory the use of
a name for each argument.
For example, do_eject() command handler is currently defined as:
{ "eject", "-fB", do_eject, ... }
With the new format it becomes:
{ "eject", "force:-f,filename:B", do_eject, ... }
This way the Monitor will be capable of setting up a dictionary, using
each argument's name as the key and the argument itself as the value.
This commit also adds two new functions: key_get_info() and
next_arg_type(), both are used to parse the new format.
Currently key_get_info() consumes the 'key' part of the new format and
discards it, this way the current parsing code is not affected by this
change.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-08-28 20:27:09 +02:00
|
|
|
memcpy(str, type, len);
|
|
|
|
str[len] = '\0';
|
|
|
|
|
|
|
|
*key = str;
|
|
|
|
return ++p;
|
|
|
|
}
|
|
|
|
|
2004-04-04 14:57:25 +02:00
|
|
|
static int default_fmt_format = 'x';
|
|
|
|
static int default_fmt_size = 4;
|
|
|
|
|
2009-11-02 14:41:13 +01:00
|
|
|
static int is_valid_option(const char *c, const char *typestr)
|
|
|
|
{
|
|
|
|
char option[3];
|
|
|
|
|
|
|
|
option[0] = '-';
|
|
|
|
option[1] = *c;
|
|
|
|
option[2] = '\0';
|
|
|
|
|
|
|
|
typestr = strstr(typestr, option);
|
|
|
|
return (typestr != NULL);
|
|
|
|
}
|
|
|
|
|
2010-09-13 18:17:58 +02:00
|
|
|
static const mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table,
|
|
|
|
const char *cmdname)
|
2009-11-27 01:58:54 +01:00
|
|
|
{
|
|
|
|
const mon_cmd_t *cmd;
|
|
|
|
|
2010-09-13 18:17:58 +02:00
|
|
|
for (cmd = disp_table; cmd->name != NULL; cmd++) {
|
2009-11-27 01:58:54 +01:00
|
|
|
if (compare_cmd(cmdname, cmd->name)) {
|
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-01-14 07:06:27 +01:00
|
|
|
/*
|
2015-06-04 00:38:08 +02:00
|
|
|
* Parse command name from @cmdp according to command table @table.
|
|
|
|
* If blank, return NULL.
|
|
|
|
* Else, if no valid command can be found, report to @mon, and return
|
|
|
|
* NULL.
|
|
|
|
* Else, change @cmdp to point right behind the name, and return its
|
|
|
|
* command table entry.
|
|
|
|
* Do not assume the return value points into @table! It doesn't when
|
|
|
|
* the command is found in a sub-command table.
|
2013-01-14 07:06:27 +01:00
|
|
|
*/
|
2009-10-01 23:12:16 +02:00
|
|
|
static const mon_cmd_t *monitor_parse_command(Monitor *mon,
|
2017-08-17 12:42:16 +02:00
|
|
|
const char *cmdp_start,
|
2015-06-04 00:38:08 +02:00
|
|
|
const char **cmdp,
|
|
|
|
mon_cmd_t *table)
|
2004-04-04 14:57:25 +02:00
|
|
|
{
|
2015-06-04 00:38:08 +02:00
|
|
|
const char *p;
|
2009-10-01 23:12:16 +02:00
|
|
|
const mon_cmd_t *cmd;
|
2004-04-04 14:57:25 +02:00
|
|
|
char cmdname[256];
|
2004-03-14 22:38:27 +01:00
|
|
|
|
2004-04-04 14:57:25 +02:00
|
|
|
/* extract the command name */
|
2015-06-04 00:38:08 +02:00
|
|
|
p = get_command_name(*cmdp, cmdname, sizeof(cmdname));
|
2009-06-09 23:21:30 +02:00
|
|
|
if (!p)
|
2009-08-28 20:27:22 +02:00
|
|
|
return NULL;
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2013-01-14 07:06:27 +01:00
|
|
|
cmd = search_dispatch_table(table, cmdname);
|
2009-11-27 01:58:54 +01:00
|
|
|
if (!cmd) {
|
2013-01-14 07:06:27 +01:00
|
|
|
monitor_printf(mon, "unknown command: '%.*s'\n",
|
2017-08-17 12:42:16 +02:00
|
|
|
(int)(p - cmdp_start), cmdp_start);
|
2009-08-28 20:27:22 +02:00
|
|
|
return NULL;
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
2018-06-20 17:39:41 +02:00
|
|
|
if (runstate_check(RUN_STATE_PRECONFIG) && !cmd_can_preconfig(cmd)) {
|
|
|
|
monitor_printf(mon, "Command '%.*s' not available with -preconfig "
|
|
|
|
"until after exit_preconfig.\n",
|
|
|
|
(int)(p - cmdp_start), cmdp_start);
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-04-04 14:57:25 +02:00
|
|
|
|
2013-01-14 07:06:27 +01:00
|
|
|
/* filter out following useless space */
|
|
|
|
while (qemu_isspace(*p)) {
|
|
|
|
p++;
|
|
|
|
}
|
2015-06-04 00:38:08 +02:00
|
|
|
|
|
|
|
*cmdp = p;
|
2013-01-14 07:06:27 +01:00
|
|
|
/* search sub command */
|
2015-06-04 00:38:08 +02:00
|
|
|
if (cmd->sub_table != NULL && *p != '\0') {
|
2017-08-17 12:42:16 +02:00
|
|
|
return monitor_parse_command(mon, cmdp_start, cmdp, cmd->sub_table);
|
2013-01-14 07:06:27 +01:00
|
|
|
}
|
|
|
|
|
2015-06-04 00:38:08 +02:00
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse arguments for @cmd.
|
|
|
|
* If it can't be parsed, report to @mon, and return NULL.
|
|
|
|
* Else, insert command arguments into a QDict, and return it.
|
|
|
|
* Note: On success, caller has to free the QDict structure.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static QDict *monitor_parse_arguments(Monitor *mon,
|
|
|
|
const char **endp,
|
|
|
|
const mon_cmd_t *cmd)
|
|
|
|
{
|
|
|
|
const char *typestr;
|
|
|
|
char *key;
|
|
|
|
int c;
|
|
|
|
const char *p = *endp;
|
|
|
|
char buf[1024];
|
|
|
|
QDict *qdict = qdict_new();
|
|
|
|
|
2004-04-04 14:57:25 +02:00
|
|
|
/* parse the parameters */
|
|
|
|
typestr = cmd->args_type;
|
2004-03-14 22:38:27 +01:00
|
|
|
for(;;) {
|
monitor: New format for handlers argument types
Current handlers argument types, as defined in qemu-monitor.hx file,
are a sequence of chars where each one represents one argument type
of the command handler. The number of chars is also used to know how
many arguments a given handler accepts.
This commit defines a new format, which makes mandatory the use of
a name for each argument.
For example, do_eject() command handler is currently defined as:
{ "eject", "-fB", do_eject, ... }
With the new format it becomes:
{ "eject", "force:-f,filename:B", do_eject, ... }
This way the Monitor will be capable of setting up a dictionary, using
each argument's name as the key and the argument itself as the value.
This commit also adds two new functions: key_get_info() and
next_arg_type(), both are used to parse the new format.
Currently key_get_info() consumes the 'key' part of the new format and
discards it, this way the current parsing code is not affected by this
change.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-08-28 20:27:09 +02:00
|
|
|
typestr = key_get_info(typestr, &key);
|
|
|
|
if (!typestr)
|
2004-03-14 22:38:27 +01:00
|
|
|
break;
|
monitor: New format for handlers argument types
Current handlers argument types, as defined in qemu-monitor.hx file,
are a sequence of chars where each one represents one argument type
of the command handler. The number of chars is also used to know how
many arguments a given handler accepts.
This commit defines a new format, which makes mandatory the use of
a name for each argument.
For example, do_eject() command handler is currently defined as:
{ "eject", "-fB", do_eject, ... }
With the new format it becomes:
{ "eject", "force:-f,filename:B", do_eject, ... }
This way the Monitor will be capable of setting up a dictionary, using
each argument's name as the key and the argument itself as the value.
This commit also adds two new functions: key_get_info() and
next_arg_type(), both are used to parse the new format.
Currently key_get_info() consumes the 'key' part of the new format and
discards it, this way the current parsing code is not affected by this
change.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-08-28 20:27:09 +02:00
|
|
|
c = *typestr;
|
2004-04-04 14:57:25 +02:00
|
|
|
typestr++;
|
|
|
|
switch(c) {
|
|
|
|
case 'F':
|
2004-07-14 19:21:37 +02:00
|
|
|
case 'B':
|
2004-04-04 14:57:25 +02:00
|
|
|
case 's':
|
|
|
|
{
|
|
|
|
int ret;
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2008-11-16 14:53:32 +01:00
|
|
|
while (qemu_isspace(*p))
|
2004-04-04 14:57:25 +02:00
|
|
|
p++;
|
|
|
|
if (*typestr == '?') {
|
|
|
|
typestr++;
|
|
|
|
if (*p == '\0') {
|
|
|
|
/* no optional string: NULL argument */
|
2009-08-28 20:27:25 +02:00
|
|
|
break;
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret = get_str(buf, sizeof(buf), &p);
|
|
|
|
if (ret < 0) {
|
2004-07-14 19:21:37 +02:00
|
|
|
switch(c) {
|
|
|
|
case 'F':
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "%s: filename expected\n",
|
2015-06-04 00:38:08 +02:00
|
|
|
cmd->name);
|
2004-07-14 19:21:37 +02:00
|
|
|
break;
|
|
|
|
case 'B':
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "%s: block device name expected\n",
|
2015-06-04 00:38:08 +02:00
|
|
|
cmd->name);
|
2004-07-14 19:21:37 +02:00
|
|
|
break;
|
|
|
|
default:
|
2015-06-04 00:38:08 +02:00
|
|
|
monitor_printf(mon, "%s: string expected\n", cmd->name);
|
2004-07-14 19:21:37 +02:00
|
|
|
break;
|
|
|
|
}
|
2004-04-04 14:57:25 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
2017-04-27 23:58:17 +02:00
|
|
|
qdict_put_str(qdict, key, buf);
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
2004-03-14 22:38:27 +01:00
|
|
|
break;
|
2010-02-10 20:24:35 +01:00
|
|
|
case 'O':
|
|
|
|
{
|
|
|
|
QemuOptsList *opts_list;
|
|
|
|
QemuOpts *opts;
|
|
|
|
|
|
|
|
opts_list = qemu_find_opts(key);
|
|
|
|
if (!opts_list || opts_list->desc->name) {
|
|
|
|
goto bad_type;
|
|
|
|
}
|
|
|
|
while (qemu_isspace(*p)) {
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (!*p)
|
|
|
|
break;
|
|
|
|
if (get_str(buf, sizeof(buf), &p) < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
QemuOpts: Wean off qerror_report_err()
qerror_report_err() is a transitional interface to help with
converting existing monitor commands to QMP. It should not be used
elsewhere.
The only remaining user in qemu-option.c is qemu_opts_parse(). Is it
used in QMP context? If not, we can simply replace
qerror_report_err() by error_report_err().
The uses in qemu-img.c, qemu-io.c, qemu-nbd.c and under tests/ are
clearly not in QMP context.
The uses in vl.c aren't either, because the only QMP command handlers
there are qmp_query_status() and qmp_query_machines(), and they don't
call it.
Remaining uses:
* drive_def(): Command line -drive and such, HMP drive_add and pci_add
* hmp_chardev_add(): HMP chardev-add
* monitor_parse_command(): HMP core
* tmp_config_parse(): Command line -tpmdev
* net_host_device_add(): HMP host_net_add
* net_client_parse(): Command line -net and -netdev
* qemu_global_option(): Command line -global
* vnc_parse_func(): Command line -display, -vnc, default display, HMP
change, QMP change. Bummer.
* qemu_pci_hot_add_nic(): HMP pci_add
* usb_net_init(): Command line -usbdevice, HMP usb_add
Propagate errors through qemu_opts_parse(). Create a convenience
function qemu_opts_parse_noisily() that passes errors to
error_report_err(). Switch all non-QMP users outside tests to it.
That leaves vnc_parse_func(). Propagate errors through it. Since I'm
touching it anyway, rename it to vnc_parse().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-02-13 12:50:26 +01:00
|
|
|
opts = qemu_opts_parse_noisily(opts_list, buf, true);
|
2010-02-10 20:24:35 +01:00
|
|
|
if (!opts) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
qemu_opts_to_qdict(opts, qdict);
|
|
|
|
qemu_opts_del(opts);
|
|
|
|
}
|
|
|
|
break;
|
2004-04-04 14:57:25 +02:00
|
|
|
case '/':
|
|
|
|
{
|
|
|
|
int count, format, size;
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2008-11-16 14:53:32 +01:00
|
|
|
while (qemu_isspace(*p))
|
2004-04-04 14:57:25 +02:00
|
|
|
p++;
|
|
|
|
if (*p == '/') {
|
|
|
|
/* format found */
|
|
|
|
p++;
|
|
|
|
count = 1;
|
2008-11-16 14:53:32 +01:00
|
|
|
if (qemu_isdigit(*p)) {
|
2004-04-04 14:57:25 +02:00
|
|
|
count = 0;
|
2008-11-16 14:53:32 +01:00
|
|
|
while (qemu_isdigit(*p)) {
|
2004-04-04 14:57:25 +02:00
|
|
|
count = count * 10 + (*p - '0');
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
size = -1;
|
|
|
|
format = -1;
|
|
|
|
for(;;) {
|
|
|
|
switch(*p) {
|
|
|
|
case 'o':
|
|
|
|
case 'd':
|
|
|
|
case 'u':
|
|
|
|
case 'x':
|
|
|
|
case 'i':
|
|
|
|
case 'c':
|
|
|
|
format = *p++;
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
size = 1;
|
|
|
|
p++;
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
size = 2;
|
|
|
|
p++;
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
size = 4;
|
|
|
|
p++;
|
|
|
|
break;
|
|
|
|
case 'g':
|
|
|
|
case 'L':
|
|
|
|
size = 8;
|
|
|
|
p++;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
next:
|
2008-11-16 14:53:32 +01:00
|
|
|
if (*p != '\0' && !qemu_isspace(*p)) {
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "invalid char in format: '%c'\n",
|
|
|
|
*p);
|
2004-04-04 14:57:25 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
if (format < 0)
|
|
|
|
format = default_fmt_format;
|
2004-04-25 20:05:08 +02:00
|
|
|
if (format != 'i') {
|
|
|
|
/* for 'i', not specifying a size gives -1 as size */
|
|
|
|
if (size < 0)
|
|
|
|
size = default_fmt_size;
|
2008-10-01 23:45:51 +02:00
|
|
|
default_fmt_size = size;
|
2004-04-25 20:05:08 +02:00
|
|
|
}
|
2004-04-04 14:57:25 +02:00
|
|
|
default_fmt_format = format;
|
|
|
|
} else {
|
|
|
|
count = 1;
|
|
|
|
format = default_fmt_format;
|
2004-04-25 20:05:08 +02:00
|
|
|
if (format != 'i') {
|
|
|
|
size = default_fmt_size;
|
|
|
|
} else {
|
|
|
|
size = -1;
|
|
|
|
}
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
2017-04-27 23:58:17 +02:00
|
|
|
qdict_put_int(qdict, "count", count);
|
|
|
|
qdict_put_int(qdict, "format", format);
|
|
|
|
qdict_put_int(qdict, "size", size);
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
2004-03-14 22:38:27 +01:00
|
|
|
break;
|
2004-04-04 14:57:25 +02:00
|
|
|
case 'i':
|
2005-02-10 23:00:52 +01:00
|
|
|
case 'l':
|
2009-12-18 16:25:04 +01:00
|
|
|
case 'M':
|
2004-04-04 14:57:25 +02:00
|
|
|
{
|
2007-09-25 19:28:42 +02:00
|
|
|
int64_t val;
|
2007-09-24 20:39:04 +02:00
|
|
|
|
2008-11-16 14:53:32 +01:00
|
|
|
while (qemu_isspace(*p))
|
2004-04-04 14:57:25 +02:00
|
|
|
p++;
|
2004-06-08 02:55:58 +02:00
|
|
|
if (*typestr == '?' || *typestr == '.') {
|
|
|
|
if (*typestr == '?') {
|
2009-08-28 20:27:25 +02:00
|
|
|
if (*p == '\0') {
|
|
|
|
typestr++;
|
|
|
|
break;
|
|
|
|
}
|
2004-06-08 02:55:58 +02:00
|
|
|
} else {
|
|
|
|
if (*p == '.') {
|
|
|
|
p++;
|
2008-11-16 14:53:32 +01:00
|
|
|
while (qemu_isspace(*p))
|
2004-06-08 02:55:58 +02:00
|
|
|
p++;
|
|
|
|
} else {
|
2009-08-28 20:27:25 +02:00
|
|
|
typestr++;
|
|
|
|
break;
|
2004-06-08 02:55:58 +02:00
|
|
|
}
|
|
|
|
}
|
2006-07-15 00:03:35 +02:00
|
|
|
typestr++;
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
2009-03-06 00:01:23 +01:00
|
|
|
if (get_expr(mon, &val, &p))
|
2004-04-04 14:57:25 +02:00
|
|
|
goto fail;
|
2009-08-28 20:27:26 +02:00
|
|
|
/* Check if 'i' is greater than 32-bit */
|
|
|
|
if ((c == 'i') && ((val >> 32) & 0xffffffff)) {
|
2015-06-04 00:38:08 +02:00
|
|
|
monitor_printf(mon, "\'%s\' has failed: ", cmd->name);
|
2009-08-28 20:27:26 +02:00
|
|
|
monitor_printf(mon, "integer is for 32-bit values\n");
|
|
|
|
goto fail;
|
2009-12-18 16:25:04 +01:00
|
|
|
} else if (c == 'M') {
|
2012-04-26 22:34:30 +02:00
|
|
|
if (val < 0) {
|
|
|
|
monitor_printf(mon, "enter a positive value\n");
|
|
|
|
goto fail;
|
|
|
|
}
|
2018-06-25 14:42:34 +02:00
|
|
|
val *= MiB;
|
2009-08-28 20:27:26 +02:00
|
|
|
}
|
2017-04-27 23:58:17 +02:00
|
|
|
qdict_put_int(qdict, key, val);
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
|
|
|
break;
|
2010-10-21 17:15:47 +02:00
|
|
|
case 'o':
|
|
|
|
{
|
2017-02-21 21:14:06 +01:00
|
|
|
int ret;
|
2017-02-21 21:14:07 +01:00
|
|
|
uint64_t val;
|
2018-11-21 17:44:14 +01:00
|
|
|
const char *end;
|
2010-10-21 17:15:47 +02:00
|
|
|
|
|
|
|
while (qemu_isspace(*p)) {
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (*typestr == '?') {
|
|
|
|
typestr++;
|
|
|
|
if (*p == '\0') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-02-21 21:14:06 +01:00
|
|
|
ret = qemu_strtosz_MiB(p, &end, &val);
|
2017-02-21 21:14:07 +01:00
|
|
|
if (ret < 0 || val > INT64_MAX) {
|
2010-10-21 17:15:47 +02:00
|
|
|
monitor_printf(mon, "invalid size\n");
|
|
|
|
goto fail;
|
|
|
|
}
|
2017-04-27 23:58:17 +02:00
|
|
|
qdict_put_int(qdict, key, val);
|
2010-10-21 17:15:47 +02:00
|
|
|
p = end;
|
|
|
|
}
|
|
|
|
break;
|
2010-01-25 14:23:06 +01:00
|
|
|
case 'T':
|
2010-01-25 14:23:03 +01:00
|
|
|
{
|
|
|
|
double val;
|
|
|
|
|
|
|
|
while (qemu_isspace(*p))
|
|
|
|
p++;
|
|
|
|
if (*typestr == '?') {
|
|
|
|
typestr++;
|
|
|
|
if (*p == '\0') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (get_double(mon, &val, &p) < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2010-10-21 17:15:49 +02:00
|
|
|
if (p[0] && p[1] == 's') {
|
2010-01-25 14:23:06 +01:00
|
|
|
switch (*p) {
|
|
|
|
case 'm':
|
|
|
|
val /= 1e3; p += 2; break;
|
|
|
|
case 'u':
|
|
|
|
val /= 1e6; p += 2; break;
|
|
|
|
case 'n':
|
|
|
|
val /= 1e9; p += 2; break;
|
|
|
|
}
|
|
|
|
}
|
2010-01-25 14:23:03 +01:00
|
|
|
if (*p && !qemu_isspace(*p)) {
|
|
|
|
monitor_printf(mon, "Unknown unit suffix\n");
|
|
|
|
goto fail;
|
|
|
|
}
|
2017-06-07 18:35:58 +02:00
|
|
|
qdict_put(qdict, key, qnum_from_double(val));
|
2010-01-25 14:23:03 +01:00
|
|
|
}
|
|
|
|
break;
|
2010-03-26 09:07:09 +01:00
|
|
|
case 'b':
|
|
|
|
{
|
|
|
|
const char *beg;
|
2015-05-16 00:24:59 +02:00
|
|
|
bool val;
|
2010-03-26 09:07:09 +01:00
|
|
|
|
|
|
|
while (qemu_isspace(*p)) {
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
beg = p;
|
|
|
|
while (qemu_isgraph(*p)) {
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (p - beg == 2 && !memcmp(beg, "on", p - beg)) {
|
2015-05-16 00:24:59 +02:00
|
|
|
val = true;
|
2010-03-26 09:07:09 +01:00
|
|
|
} else if (p - beg == 3 && !memcmp(beg, "off", p - beg)) {
|
2015-05-16 00:24:59 +02:00
|
|
|
val = false;
|
2010-03-26 09:07:09 +01:00
|
|
|
} else {
|
|
|
|
monitor_printf(mon, "Expected 'on' or 'off'\n");
|
|
|
|
goto fail;
|
|
|
|
}
|
2017-04-27 23:58:17 +02:00
|
|
|
qdict_put_bool(qdict, key, val);
|
2010-03-26 09:07:09 +01:00
|
|
|
}
|
|
|
|
break;
|
2004-04-04 14:57:25 +02:00
|
|
|
case '-':
|
|
|
|
{
|
2009-11-02 14:41:13 +01:00
|
|
|
const char *tmp = p;
|
Monitor: handle optional '-' arg as a bool
Historically, user monitor arguments beginning with '-' (eg. '-f')
were passed as integers down to handlers.
I've maintained this behavior in the new monitor because we didn't
have a boolean type at the very beginning of QMP. Today we have it
and this behavior is causing trouble to QMP's argument checker.
This commit fixes the problem by doing the following changes:
1. User Monitor
Before: the optional arg was represented as a QInt, we'd pass 1
down to handlers if the user specified the argument or
0 otherwise
This commit: the optional arg is represented as a QBool, we pass
true down to handlers if the user specified the
argument, otherwise _nothing_ is passed
2. QMP
Before: the client was required to pass the arg as QBool, but we'd
convert it to QInt internally. If the argument wasn't passed,
we'd pass 0 down
This commit: still require a QBool, but doesn't do any conversion and
doesn't pass any default value
3. Convert existing handlers (do_eject()/do_migrate()) to the new way
Before: Both handlers would expect a QInt value, either 0 or 1
This commit: Change the handlers to accept a QBool, they handle the
following cases:
A) true is passed: the option is enabled
B) false is passed: the option is disabled
C) nothing is passed: option not specified, use
default behavior
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2010-05-28 20:25:24 +02:00
|
|
|
int skip_key = 0;
|
2004-04-04 14:57:25 +02:00
|
|
|
/* option */
|
2007-09-17 10:09:54 +02:00
|
|
|
|
2004-04-04 14:57:25 +02:00
|
|
|
c = *typestr++;
|
|
|
|
if (c == '\0')
|
|
|
|
goto bad_type;
|
2008-11-16 14:53:32 +01:00
|
|
|
while (qemu_isspace(*p))
|
2004-04-04 14:57:25 +02:00
|
|
|
p++;
|
|
|
|
if (*p == '-') {
|
|
|
|
p++;
|
2009-11-02 14:41:13 +01:00
|
|
|
if(c != *p) {
|
|
|
|
if(!is_valid_option(p, typestr)) {
|
|
|
|
|
|
|
|
monitor_printf(mon, "%s: unsupported option -%c\n",
|
2015-06-04 00:38:08 +02:00
|
|
|
cmd->name, *p);
|
2009-11-02 14:41:13 +01:00
|
|
|
goto fail;
|
|
|
|
} else {
|
|
|
|
skip_key = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(skip_key) {
|
|
|
|
p = tmp;
|
|
|
|
} else {
|
Monitor: handle optional '-' arg as a bool
Historically, user monitor arguments beginning with '-' (eg. '-f')
were passed as integers down to handlers.
I've maintained this behavior in the new monitor because we didn't
have a boolean type at the very beginning of QMP. Today we have it
and this behavior is causing trouble to QMP's argument checker.
This commit fixes the problem by doing the following changes:
1. User Monitor
Before: the optional arg was represented as a QInt, we'd pass 1
down to handlers if the user specified the argument or
0 otherwise
This commit: the optional arg is represented as a QBool, we pass
true down to handlers if the user specified the
argument, otherwise _nothing_ is passed
2. QMP
Before: the client was required to pass the arg as QBool, but we'd
convert it to QInt internally. If the argument wasn't passed,
we'd pass 0 down
This commit: still require a QBool, but doesn't do any conversion and
doesn't pass any default value
3. Convert existing handlers (do_eject()/do_migrate()) to the new way
Before: Both handlers would expect a QInt value, either 0 or 1
This commit: Change the handlers to accept a QBool, they handle the
following cases:
A) true is passed: the option is enabled
B) false is passed: the option is disabled
C) nothing is passed: option not specified, use
default behavior
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2010-05-28 20:25:24 +02:00
|
|
|
/* has option */
|
2009-11-02 14:41:13 +01:00
|
|
|
p++;
|
2017-04-27 23:58:17 +02:00
|
|
|
qdict_put_bool(qdict, key, true);
|
2004-04-04 14:57:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2013-08-27 14:38:26 +02:00
|
|
|
case 'S':
|
|
|
|
{
|
|
|
|
/* package all remaining string */
|
|
|
|
int len;
|
|
|
|
|
|
|
|
while (qemu_isspace(*p)) {
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (*typestr == '?') {
|
|
|
|
typestr++;
|
|
|
|
if (*p == '\0') {
|
|
|
|
/* no remaining string: NULL argument */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
len = strlen(p);
|
|
|
|
if (len <= 0) {
|
|
|
|
monitor_printf(mon, "%s: string expected\n",
|
2015-06-04 00:38:08 +02:00
|
|
|
cmd->name);
|
2015-06-04 00:38:10 +02:00
|
|
|
goto fail;
|
2013-08-27 14:38:26 +02:00
|
|
|
}
|
2017-04-27 23:58:17 +02:00
|
|
|
qdict_put_str(qdict, key, p);
|
2013-08-27 14:38:26 +02:00
|
|
|
p += len;
|
|
|
|
}
|
|
|
|
break;
|
2004-04-04 14:57:25 +02:00
|
|
|
default:
|
|
|
|
bad_type:
|
2015-06-04 00:38:08 +02:00
|
|
|
monitor_printf(mon, "%s: unknown type '%c'\n", cmd->name, c);
|
2004-04-04 14:57:25 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
2011-08-21 05:09:37 +02:00
|
|
|
g_free(key);
|
monitor: New format for handlers argument types
Current handlers argument types, as defined in qemu-monitor.hx file,
are a sequence of chars where each one represents one argument type
of the command handler. The number of chars is also used to know how
many arguments a given handler accepts.
This commit defines a new format, which makes mandatory the use of
a name for each argument.
For example, do_eject() command handler is currently defined as:
{ "eject", "-fB", do_eject, ... }
With the new format it becomes:
{ "eject", "force:-f,filename:B", do_eject, ... }
This way the Monitor will be capable of setting up a dictionary, using
each argument's name as the key and the argument itself as the value.
This commit also adds two new functions: key_get_info() and
next_arg_type(), both are used to parse the new format.
Currently key_get_info() consumes the 'key' part of the new format and
discards it, this way the current parsing code is not affected by this
change.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-08-28 20:27:09 +02:00
|
|
|
key = NULL;
|
2004-03-14 22:38:27 +01:00
|
|
|
}
|
2004-04-04 14:57:25 +02:00
|
|
|
/* check that all arguments were parsed */
|
2008-11-16 14:53:32 +01:00
|
|
|
while (qemu_isspace(*p))
|
2004-04-04 14:57:25 +02:00
|
|
|
p++;
|
|
|
|
if (*p != '\0') {
|
2009-03-06 00:01:23 +01:00
|
|
|
monitor_printf(mon, "%s: extraneous characters at the end of line\n",
|
2015-06-04 00:38:08 +02:00
|
|
|
cmd->name);
|
2004-04-04 14:57:25 +02:00
|
|
|
goto fail;
|
2004-03-14 22:38:27 +01:00
|
|
|
}
|
2004-04-04 14:57:25 +02:00
|
|
|
|
2015-06-04 00:38:08 +02:00
|
|
|
return qdict;
|
2009-08-14 10:36:06 +02:00
|
|
|
|
2009-08-28 20:27:22 +02:00
|
|
|
fail:
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(qdict);
|
2011-08-21 05:09:37 +02:00
|
|
|
g_free(key);
|
2009-08-28 20:27:22 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-03-06 19:12:36 +01:00
|
|
|
static void handle_hmp_command(Monitor *mon, const char *cmdline)
|
2009-08-28 20:27:22 +02:00
|
|
|
{
|
|
|
|
QDict *qdict;
|
2009-10-01 23:12:16 +02:00
|
|
|
const mon_cmd_t *cmd;
|
2018-05-07 16:30:54 +02:00
|
|
|
const char *cmd_start = cmdline;
|
2009-08-28 20:27:22 +02:00
|
|
|
|
2017-06-05 12:42:15 +02:00
|
|
|
trace_handle_hmp_command(mon, cmdline);
|
|
|
|
|
2017-08-17 12:42:16 +02:00
|
|
|
cmd = monitor_parse_command(mon, cmdline, &cmdline, mon->cmd_table);
|
2015-06-04 00:38:08 +02:00
|
|
|
if (!cmd) {
|
|
|
|
return;
|
|
|
|
}
|
2009-08-28 20:27:22 +02:00
|
|
|
|
2015-06-04 00:38:08 +02:00
|
|
|
qdict = monitor_parse_arguments(mon, &cmdline, cmd);
|
|
|
|
if (!qdict) {
|
2018-05-07 16:30:54 +02:00
|
|
|
while (cmdline > cmd_start && qemu_isspace(cmdline[-1])) {
|
|
|
|
cmdline--;
|
|
|
|
}
|
|
|
|
monitor_printf(mon, "Try \"help %.*s\" for more information\n",
|
|
|
|
(int)(cmdline - cmd_start), cmd_start);
|
2015-06-04 00:38:08 +02:00
|
|
|
return;
|
2009-08-28 20:27:22 +02:00
|
|
|
}
|
|
|
|
|
2016-09-12 11:19:06 +02:00
|
|
|
cmd->cmd(mon, qdict);
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(qdict);
|
2004-03-14 22:38:27 +01:00
|
|
|
}
|
|
|
|
|
2013-08-27 14:38:13 +02:00
|
|
|
static void cmd_completion(Monitor *mon, const char *name, const char *list)
|
2004-07-14 19:21:37 +02:00
|
|
|
{
|
|
|
|
const char *p, *pstart;
|
|
|
|
char cmd[128];
|
|
|
|
int len;
|
|
|
|
|
|
|
|
p = list;
|
|
|
|
for(;;) {
|
|
|
|
pstart = p;
|
2018-06-29 12:32:10 +02:00
|
|
|
p = qemu_strchrnul(p, '|');
|
2004-07-14 19:21:37 +02:00
|
|
|
len = p - pstart;
|
|
|
|
if (len > sizeof(cmd) - 2)
|
|
|
|
len = sizeof(cmd) - 2;
|
|
|
|
memcpy(cmd, pstart, len);
|
|
|
|
cmd[len] = '\0';
|
|
|
|
if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) {
|
2013-08-27 14:38:13 +02:00
|
|
|
readline_add_completion(mon->rs, cmd);
|
2004-07-14 19:21:37 +02:00
|
|
|
}
|
|
|
|
if (*p == '\0')
|
|
|
|
break;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-27 14:38:14 +02:00
|
|
|
static void file_completion(Monitor *mon, const char *input)
|
2004-07-14 19:21:37 +02:00
|
|
|
{
|
|
|
|
DIR *ffs;
|
|
|
|
struct dirent *d;
|
|
|
|
char path[1024];
|
|
|
|
char file[1024], file_prefix[1024];
|
|
|
|
int input_path_len;
|
|
|
|
const char *p;
|
|
|
|
|
2007-09-16 23:08:06 +02:00
|
|
|
p = strrchr(input, '/');
|
2004-07-14 19:21:37 +02:00
|
|
|
if (!p) {
|
|
|
|
input_path_len = 0;
|
|
|
|
pstrcpy(file_prefix, sizeof(file_prefix), input);
|
2008-08-21 19:58:08 +02:00
|
|
|
pstrcpy(path, sizeof(path), ".");
|
2004-07-14 19:21:37 +02:00
|
|
|
} else {
|
|
|
|
input_path_len = p - input + 1;
|
|
|
|
memcpy(path, input, input_path_len);
|
|
|
|
if (input_path_len > sizeof(path) - 1)
|
|
|
|
input_path_len = sizeof(path) - 1;
|
|
|
|
path[input_path_len] = '\0';
|
|
|
|
pstrcpy(file_prefix, sizeof(file_prefix), p + 1);
|
|
|
|
}
|
2015-06-04 00:38:07 +02:00
|
|
|
|
2004-07-14 19:21:37 +02:00
|
|
|
ffs = opendir(path);
|
|
|
|
if (!ffs)
|
|
|
|
return;
|
|
|
|
for(;;) {
|
|
|
|
struct stat sb;
|
|
|
|
d = readdir(ffs);
|
|
|
|
if (!d)
|
|
|
|
break;
|
2010-10-20 11:00:01 +02:00
|
|
|
|
|
|
|
if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2004-07-14 19:21:37 +02:00
|
|
|
if (strstart(d->d_name, file_prefix, NULL)) {
|
|
|
|
memcpy(file, input, input_path_len);
|
2008-08-21 19:58:08 +02:00
|
|
|
if (input_path_len < sizeof(file))
|
|
|
|
pstrcpy(file + input_path_len, sizeof(file) - input_path_len,
|
|
|
|
d->d_name);
|
2004-07-14 19:21:37 +02:00
|
|
|
/* stat the file to find out if it's a directory.
|
|
|
|
* In that case add a slash to speed up typing long paths
|
|
|
|
*/
|
2011-11-16 15:43:47 +01:00
|
|
|
if (stat(file, &sb) == 0 && S_ISDIR(sb.st_mode)) {
|
2008-08-21 19:58:08 +02:00
|
|
|
pstrcat(file, sizeof(file), "/");
|
2011-11-16 15:43:47 +01:00
|
|
|
}
|
2013-08-27 14:38:14 +02:00
|
|
|
readline_add_completion(mon->rs, file);
|
2004-07-14 19:21:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
closedir(ffs);
|
|
|
|
}
|
|
|
|
|
monitor: New format for handlers argument types
Current handlers argument types, as defined in qemu-monitor.hx file,
are a sequence of chars where each one represents one argument type
of the command handler. The number of chars is also used to know how
many arguments a given handler accepts.
This commit defines a new format, which makes mandatory the use of
a name for each argument.
For example, do_eject() command handler is currently defined as:
{ "eject", "-fB", do_eject, ... }
With the new format it becomes:
{ "eject", "force:-f,filename:B", do_eject, ... }
This way the Monitor will be capable of setting up a dictionary, using
each argument's name as the key and the argument itself as the value.
This commit also adds two new functions: key_get_info() and
next_arg_type(), both are used to parse the new format.
Currently key_get_info() consumes the 'key' part of the new format and
discards it, this way the current parsing code is not affected by this
change.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-08-28 20:27:09 +02:00
|
|
|
static const char *next_arg_type(const char *typestr)
|
|
|
|
{
|
|
|
|
const char *p = strchr(typestr, ':');
|
|
|
|
return (p != NULL ? ++p : typestr);
|
|
|
|
}
|
|
|
|
|
2014-05-08 00:41:30 +02: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-08 00:41:29 +02: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-08 00:41:31 +02: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 10:46:06 +02:00
|
|
|
for (i = 0; i < NET_CLIENT_DRIVER__MAX; i++) {
|
2017-08-24 10:46:08 +02:00
|
|
|
add_completion_option(rs, str, NetClientDriver_str(i));
|
2014-05-08 00:41:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-13 17:25:07 +02:00
|
|
|
void device_add_completion(ReadLineState *rs, int nb_args, const char *str)
|
2014-02-06 23:30:11 +01:00
|
|
|
{
|
|
|
|
GSList *list, *elt;
|
|
|
|
size_t len;
|
|
|
|
|
2014-04-13 17:25:07 +02:00
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-06 23:30:11 +01: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 17:25:07 +02:00
|
|
|
|
2017-05-03 22:35:44 +02:00
|
|
|
if (dc->user_creatable
|
2014-04-13 17:25:07 +02:00
|
|
|
&& !strncmp(name, str, len)) {
|
2014-02-06 23:30:11 +01:00
|
|
|
readline_add_completion(rs, name);
|
|
|
|
}
|
|
|
|
elt = elt->next;
|
|
|
|
}
|
|
|
|
g_slist_free(list);
|
|
|
|
}
|
|
|
|
|
2014-04-13 17:25:06 +02:00
|
|
|
void object_add_completion(ReadLineState *rs, int nb_args, const char *str)
|
2014-02-06 23:30:13 +01:00
|
|
|
{
|
|
|
|
GSList *list, *elt;
|
|
|
|
size_t len;
|
|
|
|
|
2014-04-13 17:25:06 +02:00
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-06 23:30:13 +01: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);
|
|
|
|
}
|
|
|
|
|
2014-10-21 13:46:05 +02:00
|
|
|
static void peripheral_device_del_completion(ReadLineState *rs,
|
|
|
|
const char *str, size_t len)
|
|
|
|
{
|
2014-11-26 12:50:01 +01:00
|
|
|
Object *peripheral = container_get(qdev_get_machine(), "/peripheral");
|
|
|
|
GSList *list, *item;
|
2014-10-21 13:46:05 +02:00
|
|
|
|
2014-11-26 12:50:01 +01:00
|
|
|
list = qdev_build_hotpluggable_device_list(peripheral);
|
|
|
|
if (!list) {
|
2014-10-21 13:46:05 +02: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-08 00:41:28 +02: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-28 00:39:30 +02: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 14:20:22 +01:00
|
|
|
Chardev *chr = qemu_chr_find(chr_info->label);
|
2016-12-07 16:39:10 +01:00
|
|
|
if (chr && CHARDEV_IS_RINGBUF(chr)) {
|
2014-05-28 00:39:30 +02: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 17:25:07 +02: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 13:46:05 +02:00
|
|
|
peripheral_device_del_completion(rs, str, len);
|
2014-04-13 17:25:07 +02:00
|
|
|
}
|
|
|
|
|
2014-04-13 17:25:06 +02:00
|
|
|
void object_del_completion(ReadLineState *rs, int nb_args, const char *str)
|
2014-02-06 23:30:12 +01:00
|
|
|
{
|
|
|
|
ObjectPropertyInfoList *list, *start;
|
|
|
|
size_t len;
|
|
|
|
|
2014-04-13 17:25:06 +02:00
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
2014-02-06 23:30:12 +01: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-08 00:41:27 +02: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 09:52:57 +01:00
|
|
|
for (i = 0; i < Q_KEY_CODE__MAX; i++) {
|
2017-08-24 10:46:08 +02:00
|
|
|
if (!strncmp(str, QKeyCode_str(i), len)) {
|
|
|
|
readline_add_completion(rs, QKeyCode_str(i));
|
2014-05-08 00:41:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-08 00:41:30 +02: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 08:21:38 +02:00
|
|
|
NetClientState *ncs[MAX_QUEUE_NUM];
|
2014-05-08 00:41:30 +02: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 05:50:23 +02:00
|
|
|
NET_CLIENT_DRIVER_NONE,
|
2015-04-23 08:21:38 +02:00
|
|
|
MAX_QUEUE_NUM);
|
2015-04-23 08:21:39 +02:00
|
|
|
for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
|
2014-05-08 00:41:30 +02: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-08 00:41:32 +02:00
|
|
|
void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
|
|
|
int len, count, i;
|
2015-04-23 08:21:38 +02:00
|
|
|
NetClientState *ncs[MAX_QUEUE_NUM];
|
2014-05-08 00:41:32 +02: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 05:50:23 +02:00
|
|
|
count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_DRIVER_NIC,
|
2015-04-23 08:21:38 +02:00
|
|
|
MAX_QUEUE_NUM);
|
2015-04-23 08:21:39 +02:00
|
|
|
for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
|
2014-05-08 00:41:32 +02: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 12:53:51 +02: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 15:35:43 +02: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 12:53:51 +02:00
|
|
|
}
|
2016-10-04 15:35:43 +02:00
|
|
|
g_free(pattern);
|
2016-07-11 12:53:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-14 12:27:43 +02: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 15:35:43 +02: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 12:27:43 +02:00
|
|
|
} else if (nb_args == 3) {
|
|
|
|
add_completion_option(rs, str, "on");
|
|
|
|
add_completion_option(rs, str, "off");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-28 00:39:31 +02:00
|
|
|
void watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str)
|
|
|
|
{
|
2014-07-30 00:22:40 +02:00
|
|
|
int i;
|
|
|
|
|
2014-05-28 00:39:31 +02:00
|
|
|
if (nb_args != 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
readline_set_completion_index(rs, strlen(str));
|
2017-09-07 10:05:24 +02:00
|
|
|
for (i = 0; i < WATCHDOG_ACTION__MAX; i++) {
|
|
|
|
add_completion_option(rs, str, WatchdogAction_str(i));
|
2014-07-30 00:22:40 +02:00
|
|
|
}
|
2014-05-28 00:39:31 +02:00
|
|
|
}
|
|
|
|
|
2014-05-28 00:39:32 +02: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 09:52:57 +01:00
|
|
|
for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
|
2017-08-24 10:46:08 +02:00
|
|
|
const char *name = MigrationCapability_str(i);
|
2014-05-28 00:39:32 +02: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 09:32:29 +01: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 09:52:57 +01:00
|
|
|
for (i = 0; i < MIGRATION_PARAMETER__MAX; i++) {
|
2017-08-24 10:46:08 +02:00
|
|
|
const char *name = MigrationParameter_str(i);
|
2015-03-23 09:32:29 +01:00
|
|
|
if (!strncmp(str, name, len)) {
|
|
|
|
readline_add_completion(rs, name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-28 00:39:37 +02:00
|
|
|
static void vm_completion(ReadLineState *rs, const char *str)
|
|
|
|
{
|
|
|
|
size_t len;
|
2016-03-22 18:58:50 +01:00
|
|
|
BlockDriverState *bs;
|
2016-05-20 18:49:07 +02:00
|
|
|
BdrvNextIterator it;
|
2014-05-28 00:39:37 +02:00
|
|
|
|
|
|
|
len = strlen(str);
|
|
|
|
readline_set_completion_index(rs, len);
|
2016-03-22 18:58:50 +01:00
|
|
|
|
2016-05-20 18:49:07 +02:00
|
|
|
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
|
2014-05-28 00:39:37 +02:00
|
|
|
SnapshotInfoList *snapshots, *snapshot;
|
2015-11-04 18:19:42 +01:00
|
|
|
AioContext *ctx = bdrv_get_aio_context(bs);
|
|
|
|
bool ok = false;
|
2014-05-28 00:39:37 +02:00
|
|
|
|
2015-11-04 18:19:42 +01:00
|
|
|
aio_context_acquire(ctx);
|
|
|
|
if (bdrv_can_snapshot(bs)) {
|
|
|
|
ok = bdrv_query_snapshot_info_list(bs, &snapshots, NULL) == 0;
|
2014-05-28 00:39:37 +02:00
|
|
|
}
|
2015-11-04 18:19:42 +01:00
|
|
|
aio_context_release(ctx);
|
|
|
|
if (!ok) {
|
2014-05-28 00:39:37 +02:00
|
|
|
continue;
|
|
|
|
}
|
2015-11-04 18:19:42 +01:00
|
|
|
|
2014-05-28 00:39:37 +02: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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-27 14:38:24 +02:00
|
|
|
static void monitor_find_completion_by_table(Monitor *mon,
|
|
|
|
const mon_cmd_t *cmd_table,
|
|
|
|
char **args,
|
|
|
|
int nb_args)
|
2004-07-14 19:21:37 +02:00
|
|
|
{
|
|
|
|
const char *cmdname;
|
2013-08-27 14:38:24 +02:00
|
|
|
int i;
|
2018-02-13 13:51:43 +01:00
|
|
|
const char *ptype, *old_ptype, *str, *name;
|
2009-10-01 23:12:16 +02:00
|
|
|
const mon_cmd_t *cmd;
|
2016-03-16 19:54:29 +01:00
|
|
|
BlockBackend *blk = NULL;
|
2004-07-14 19:21:37 +02:00
|
|
|
|
|
|
|
if (nb_args <= 1) {
|
|
|
|
/* command completion */
|
|
|
|
if (nb_args == 0)
|
|
|
|
cmdname = "";
|
|
|
|
else
|
|
|
|
cmdname = args[0];
|
2013-08-27 14:38:16 +02:00
|
|
|
readline_set_completion_index(mon->rs, strlen(cmdname));
|
2013-08-27 14:38:24 +02:00
|
|
|
for (cmd = cmd_table; cmd->name != NULL; cmd++) {
|
2018-06-20 17:39:43 +02:00
|
|
|
if (!runstate_check(RUN_STATE_PRECONFIG) ||
|
|
|
|
cmd_can_preconfig(cmd)) {
|
|
|
|
cmd_completion(mon, cmdname, cmd->name);
|
|
|
|
}
|
2004-07-14 19:21:37 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* find the command */
|
2013-08-27 14:38:24 +02:00
|
|
|
for (cmd = cmd_table; cmd->name != NULL; cmd++) {
|
2018-06-20 17:39:43 +02:00
|
|
|
if (compare_cmd(args[0], cmd->name) &&
|
|
|
|
(!runstate_check(RUN_STATE_PRECONFIG) ||
|
|
|
|
cmd_can_preconfig(cmd))) {
|
2010-06-16 00:38:33 +02:00
|
|
|
break;
|
|
|
|
}
|
2004-07-14 19:21:37 +02:00
|
|
|
}
|
2010-06-16 00:38:33 +02:00
|
|
|
if (!cmd->name) {
|
2013-08-27 14:38:24 +02:00
|
|
|
return;
|
2010-06-16 00:38:33 +02:00
|
|
|
}
|
|
|
|
|
2013-08-27 14:38:25 +02:00
|
|
|
if (cmd->sub_table) {
|
|
|
|
/* do the job again */
|
2015-03-08 19:30:01 +01:00
|
|
|
monitor_find_completion_by_table(mon, cmd->sub_table,
|
|
|
|
&args[1], nb_args - 1);
|
|
|
|
return;
|
2013-08-27 14:38:25 +02:00
|
|
|
}
|
2014-04-13 17:25:06 +02:00
|
|
|
if (cmd->command_completion) {
|
2015-03-08 19:30:01 +01:00
|
|
|
cmd->command_completion(mon->rs, nb_args, args[nb_args - 1]);
|
|
|
|
return;
|
2014-04-13 17:25:06 +02:00
|
|
|
}
|
2013-08-27 14:38:25 +02:00
|
|
|
|
monitor: New format for handlers argument types
Current handlers argument types, as defined in qemu-monitor.hx file,
are a sequence of chars where each one represents one argument type
of the command handler. The number of chars is also used to know how
many arguments a given handler accepts.
This commit defines a new format, which makes mandatory the use of
a name for each argument.
For example, do_eject() command handler is currently defined as:
{ "eject", "-fB", do_eject, ... }
With the new format it becomes:
{ "eject", "force:-f,filename:B", do_eject, ... }
This way the Monitor will be capable of setting up a dictionary, using
each argument's name as the key and the argument itself as the value.
This commit also adds two new functions: key_get_info() and
next_arg_type(), both are used to parse the new format.
Currently key_get_info() consumes the 'key' part of the new format and
discards it, this way the current parsing code is not affected by this
change.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-08-28 20:27:09 +02:00
|
|
|
ptype = next_arg_type(cmd->args_type);
|
2004-07-14 19:21:37 +02:00
|
|
|
for(i = 0; i < nb_args - 2; i++) {
|
|
|
|
if (*ptype != '\0') {
|
monitor: New format for handlers argument types
Current handlers argument types, as defined in qemu-monitor.hx file,
are a sequence of chars where each one represents one argument type
of the command handler. The number of chars is also used to know how
many arguments a given handler accepts.
This commit defines a new format, which makes mandatory the use of
a name for each argument.
For example, do_eject() command handler is currently defined as:
{ "eject", "-fB", do_eject, ... }
With the new format it becomes:
{ "eject", "force:-f,filename:B", do_eject, ... }
This way the Monitor will be capable of setting up a dictionary, using
each argument's name as the key and the argument itself as the value.
This commit also adds two new functions: key_get_info() and
next_arg_type(), both are used to parse the new format.
Currently key_get_info() consumes the 'key' part of the new format and
discards it, this way the current parsing code is not affected by this
change.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-08-28 20:27:09 +02:00
|
|
|
ptype = next_arg_type(ptype);
|
2004-07-14 19:21:37 +02:00
|
|
|
while (*ptype == '?')
|
monitor: New format for handlers argument types
Current handlers argument types, as defined in qemu-monitor.hx file,
are a sequence of chars where each one represents one argument type
of the command handler. The number of chars is also used to know how
many arguments a given handler accepts.
This commit defines a new format, which makes mandatory the use of
a name for each argument.
For example, do_eject() command handler is currently defined as:
{ "eject", "-fB", do_eject, ... }
With the new format it becomes:
{ "eject", "force:-f,filename:B", do_eject, ... }
This way the Monitor will be capable of setting up a dictionary, using
each argument's name as the key and the argument itself as the value.
This commit also adds two new functions: key_get_info() and
next_arg_type(), both are used to parse the new format.
Currently key_get_info() consumes the 'key' part of the new format and
discards it, this way the current parsing code is not affected by this
change.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-08-28 20:27:09 +02:00
|
|
|
ptype = next_arg_type(ptype);
|
2004-07-14 19:21:37 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
str = args[nb_args - 1];
|
2018-02-13 13:51:43 +01:00
|
|
|
old_ptype = NULL;
|
|
|
|
while (*ptype == '-' && old_ptype != ptype) {
|
|
|
|
old_ptype = ptype;
|
2010-06-16 00:38:34 +02:00
|
|
|
ptype = next_arg_type(ptype);
|
2009-08-23 22:10:28 +02:00
|
|
|
}
|
2004-07-14 19:21:37 +02:00
|
|
|
switch(*ptype) {
|
|
|
|
case 'F':
|
|
|
|
/* file completion */
|
2013-08-27 14:38:16 +02:00
|
|
|
readline_set_completion_index(mon->rs, strlen(str));
|
2013-08-27 14:38:14 +02:00
|
|
|
file_completion(mon, str);
|
2004-07-14 19:21:37 +02:00
|
|
|
break;
|
|
|
|
case 'B':
|
|
|
|
/* block device name completion */
|
2013-08-27 14:38:15 +02:00
|
|
|
readline_set_completion_index(mon->rs, strlen(str));
|
2016-03-16 19:54:29 +01:00
|
|
|
while ((blk = blk_next(blk)) != NULL) {
|
|
|
|
name = blk_name(blk);
|
2014-10-07 13:59:10 +02:00
|
|
|
if (str[0] == '\0' ||
|
|
|
|
!strncmp(name, str, strlen(str))) {
|
|
|
|
readline_add_completion(mon->rs, name);
|
|
|
|
}
|
|
|
|
}
|
2004-07-14 19:21:37 +02:00
|
|
|
break;
|
2004-10-09 20:08:01 +02:00
|
|
|
case 's':
|
2013-08-27 14:38:26 +02:00
|
|
|
case 'S':
|
2014-05-08 00:41:27 +02:00
|
|
|
if (!strcmp(cmd->name, "help|?")) {
|
2013-08-27 14:38:27 +02:00
|
|
|
monitor_find_completion_by_table(mon, cmd_table,
|
|
|
|
&args[1], nb_args - 1);
|
2004-10-09 20:08:01 +02:00
|
|
|
}
|
|
|
|
break;
|
2004-07-14 19:21:37 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-08-27 14:38:24 +02:00
|
|
|
}
|
|
|
|
|
2013-11-14 11:54:14 +01:00
|
|
|
static void monitor_find_completion(void *opaque,
|
2013-08-27 14:38:24 +02:00
|
|
|
const char *cmdline)
|
|
|
|
{
|
2013-11-14 11:54:14 +01:00
|
|
|
Monitor *mon = opaque;
|
2013-08-27 14:38:24 +02:00
|
|
|
char *args[MAX_ARGS];
|
|
|
|
int nb_args, len;
|
|
|
|
|
|
|
|
/* 1. parse the cmdline */
|
|
|
|
if (parse_cmdline(cmdline, &nb_args, args) < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if the line ends with a space, it means we want to complete the
|
|
|
|
next arg */
|
|
|
|
len = strlen(cmdline);
|
|
|
|
if (len > 0 && qemu_isspace(cmdline[len - 1])) {
|
|
|
|
if (nb_args >= MAX_ARGS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
args[nb_args++] = g_strdup("");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 2. auto complete according to args */
|
|
|
|
monitor_find_completion_by_table(mon, mon->cmd_table, args, nb_args);
|
2010-06-16 00:38:33 +02:00
|
|
|
|
|
|
|
cleanup:
|
2013-08-27 14:38:22 +02:00
|
|
|
free_cmdline_args(args, nb_args);
|
2004-07-14 19:21:37 +02:00
|
|
|
}
|
|
|
|
|
2009-03-06 00:01:42 +01:00
|
|
|
static int monitor_can_read(void *opaque)
|
2004-03-14 22:38:27 +01:00
|
|
|
{
|
2009-03-06 00:01:42 +01:00
|
|
|
Monitor *mon = opaque;
|
|
|
|
|
2018-03-09 09:59:55 +01:00
|
|
|
return !atomic_mb_read(&mon->suspend_cnt);
|
2004-03-14 22:38:27 +01:00
|
|
|
}
|
|
|
|
|
2018-03-09 09:59:54 +01:00
|
|
|
/*
|
2018-07-03 10:53:52 +02:00
|
|
|
* Emit QMP response @rsp with ID @id to @mon.
|
|
|
|
* Null @rsp can only happen for commands with QCO_NO_SUCCESS_RESP.
|
|
|
|
* Nothing is emitted then.
|
2018-03-09 09:59:54 +01:00
|
|
|
*/
|
2019-02-20 16:42:53 +01:00
|
|
|
static void monitor_qmp_respond(Monitor *mon, QDict *rsp)
|
2018-03-09 09:59:54 +01:00
|
|
|
{
|
|
|
|
if (rsp) {
|
2018-08-29 15:40:36 +02:00
|
|
|
qmp_send_response(mon, rsp);
|
2018-03-09 09:59:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-20 16:42:53 +01:00
|
|
|
static void monitor_qmp_dispatch(Monitor *mon, QObject *req)
|
2009-11-27 01:59:01 +01:00
|
|
|
{
|
2018-07-03 10:53:41 +02:00
|
|
|
Monitor *old_mon;
|
2018-07-03 10:53:49 +02:00
|
|
|
QDict *rsp;
|
2018-07-03 10:53:43 +02:00
|
|
|
QDict *error;
|
2017-06-05 12:42:16 +02:00
|
|
|
|
2018-03-09 09:59:49 +01:00
|
|
|
old_mon = cur_mon;
|
|
|
|
cur_mon = mon;
|
|
|
|
|
2018-07-03 10:53:37 +02:00
|
|
|
rsp = qmp_dispatch(mon->qmp.commands, req, qmp_oob_enabled(mon));
|
2009-11-27 01:59:01 +01:00
|
|
|
|
2018-03-09 09:59:49 +01:00
|
|
|
cur_mon = old_mon;
|
|
|
|
|
2018-07-03 10:53:43 +02:00
|
|
|
if (mon->qmp.commands == &qmp_cap_negotiation_commands) {
|
2018-07-03 10:53:49 +02:00
|
|
|
error = qdict_get_qdict(rsp, "error");
|
2018-07-03 10:53:43 +02:00
|
|
|
if (error
|
|
|
|
&& !g_strcmp0(qdict_get_try_str(error, "class"),
|
|
|
|
QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) {
|
|
|
|
/* Provide a more useful error message */
|
|
|
|
qdict_del(error, "desc");
|
|
|
|
qdict_put_str(error, "desc", "Expecting capabilities negotiation"
|
|
|
|
" with 'qmp_capabilities'");
|
|
|
|
}
|
2018-03-09 09:59:57 +01:00
|
|
|
}
|
2009-11-27 01:59:01 +01:00
|
|
|
|
2019-02-20 16:42:53 +01:00
|
|
|
monitor_qmp_respond(mon, rsp);
|
2018-07-03 10:53:52 +02:00
|
|
|
qobject_unref(rsp);
|
2009-11-27 01:59:01 +01:00
|
|
|
}
|
|
|
|
|
2018-03-09 09:59:57 +01:00
|
|
|
/*
|
2018-07-03 10:53:57 +02:00
|
|
|
* Pop a QMP request from a monitor request queue.
|
|
|
|
* Return the request, or NULL all request queues are empty.
|
2018-03-09 09:59:57 +01:00
|
|
|
* We are using round-robin fashion to pop the request, to avoid
|
|
|
|
* processing commands only on a very busy monitor. To achieve that,
|
|
|
|
* when we process one request on a specific monitor, we put that
|
|
|
|
* monitor to the end of mon_list queue.
|
monitor: Suspend monitor instead dropping commands
When a QMP client sends in-band commands more quickly that we can
process them, we can either queue them without limit (QUEUE), drop
commands when the queue is full (DROP), or suspend receiving commands
when the queue is full (SUSPEND). None of them is ideal:
* QUEUE lets a misbehaving client make QEMU eat memory without bounds.
Not such a hot idea.
* With DROP, the client has to cope with dropped in-band commands. To
inform the client, we send a COMMAND_DROPPED event then. The event is
flawed by design in two ways: it's ambiguous (see commit d621cfe0a17),
and it brings back the "eat memory without bounds" problem.
* With SUSPEND, the client has to manage the flow of in-band commands to
keep the monitor available for out-of-band commands.
We currently DROP. Switch to SUSPEND.
Managing the flow of in-band commands to keep the monitor available for
out-of-band commands isn't really hard: just count the number of
"outstanding" in-band commands (commands sent minus replies received),
and if it exceeds the limit, hold back additional ones until it drops
below the limit again.
Note that we need to be careful pairing the suspend with a resume, or
else the monitor will hang, possibly forever. And here since we need to
make sure both:
(1) popping request from the req queue, and
(2) reading length of the req queue
will be in the same critical section, we let the pop function take the
corresponding queue lock when there is a request, then we release the
lock from the caller.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20181009062718.1914-2-peterx@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-10-09 08:27:13 +02:00
|
|
|
*
|
|
|
|
* Note: if the function returned with non-NULL, then the caller will
|
|
|
|
* be with mon->qmp.qmp_queue_lock held, and the caller is responsible
|
|
|
|
* to release it.
|
2018-03-09 09:59:57 +01:00
|
|
|
*/
|
monitor: Suspend monitor instead dropping commands
When a QMP client sends in-band commands more quickly that we can
process them, we can either queue them without limit (QUEUE), drop
commands when the queue is full (DROP), or suspend receiving commands
when the queue is full (SUSPEND). None of them is ideal:
* QUEUE lets a misbehaving client make QEMU eat memory without bounds.
Not such a hot idea.
* With DROP, the client has to cope with dropped in-band commands. To
inform the client, we send a COMMAND_DROPPED event then. The event is
flawed by design in two ways: it's ambiguous (see commit d621cfe0a17),
and it brings back the "eat memory without bounds" problem.
* With SUSPEND, the client has to manage the flow of in-band commands to
keep the monitor available for out-of-band commands.
We currently DROP. Switch to SUSPEND.
Managing the flow of in-band commands to keep the monitor available for
out-of-band commands isn't really hard: just count the number of
"outstanding" in-band commands (commands sent minus replies received),
and if it exceeds the limit, hold back additional ones until it drops
below the limit again.
Note that we need to be careful pairing the suspend with a resume, or
else the monitor will hang, possibly forever. And here since we need to
make sure both:
(1) popping request from the req queue, and
(2) reading length of the req queue
will be in the same critical section, we let the pop function take the
corresponding queue lock when there is a request, then we release the
lock from the caller.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20181009062718.1914-2-peterx@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-10-09 08:27:13 +02:00
|
|
|
static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
|
2018-03-09 09:59:57 +01:00
|
|
|
{
|
|
|
|
QMPRequest *req_obj = NULL;
|
|
|
|
Monitor *mon;
|
|
|
|
|
|
|
|
qemu_mutex_lock(&monitor_lock);
|
|
|
|
|
|
|
|
QTAILQ_FOREACH(mon, &mon_list, entry) {
|
|
|
|
qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
|
|
|
|
req_obj = g_queue_pop_head(mon->qmp.qmp_requests);
|
|
|
|
if (req_obj) {
|
monitor: Suspend monitor instead dropping commands
When a QMP client sends in-band commands more quickly that we can
process them, we can either queue them without limit (QUEUE), drop
commands when the queue is full (DROP), or suspend receiving commands
when the queue is full (SUSPEND). None of them is ideal:
* QUEUE lets a misbehaving client make QEMU eat memory without bounds.
Not such a hot idea.
* With DROP, the client has to cope with dropped in-band commands. To
inform the client, we send a COMMAND_DROPPED event then. The event is
flawed by design in two ways: it's ambiguous (see commit d621cfe0a17),
and it brings back the "eat memory without bounds" problem.
* With SUSPEND, the client has to manage the flow of in-band commands to
keep the monitor available for out-of-band commands.
We currently DROP. Switch to SUSPEND.
Managing the flow of in-band commands to keep the monitor available for
out-of-band commands isn't really hard: just count the number of
"outstanding" in-band commands (commands sent minus replies received),
and if it exceeds the limit, hold back additional ones until it drops
below the limit again.
Note that we need to be careful pairing the suspend with a resume, or
else the monitor will hang, possibly forever. And here since we need to
make sure both:
(1) popping request from the req queue, and
(2) reading length of the req queue
will be in the same critical section, we let the pop function take the
corresponding queue lock when there is a request, then we release the
lock from the caller.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20181009062718.1914-2-peterx@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-10-09 08:27:13 +02:00
|
|
|
/* With the lock of corresponding queue held */
|
2018-03-09 09:59:57 +01:00
|
|
|
break;
|
|
|
|
}
|
monitor: Suspend monitor instead dropping commands
When a QMP client sends in-band commands more quickly that we can
process them, we can either queue them without limit (QUEUE), drop
commands when the queue is full (DROP), or suspend receiving commands
when the queue is full (SUSPEND). None of them is ideal:
* QUEUE lets a misbehaving client make QEMU eat memory without bounds.
Not such a hot idea.
* With DROP, the client has to cope with dropped in-band commands. To
inform the client, we send a COMMAND_DROPPED event then. The event is
flawed by design in two ways: it's ambiguous (see commit d621cfe0a17),
and it brings back the "eat memory without bounds" problem.
* With SUSPEND, the client has to manage the flow of in-band commands to
keep the monitor available for out-of-band commands.
We currently DROP. Switch to SUSPEND.
Managing the flow of in-band commands to keep the monitor available for
out-of-band commands isn't really hard: just count the number of
"outstanding" in-band commands (commands sent minus replies received),
and if it exceeds the limit, hold back additional ones until it drops
below the limit again.
Note that we need to be careful pairing the suspend with a resume, or
else the monitor will hang, possibly forever. And here since we need to
make sure both:
(1) popping request from the req queue, and
(2) reading length of the req queue
will be in the same critical section, we let the pop function take the
corresponding queue lock when there is a request, then we release the
lock from the caller.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20181009062718.1914-2-peterx@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-10-09 08:27:13 +02:00
|
|
|
qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
|
2018-03-09 09:59:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (req_obj) {
|
|
|
|
/*
|
|
|
|
* We found one request on the monitor. Degrade this monitor's
|
|
|
|
* priority to lowest by re-inserting it to end of queue.
|
|
|
|
*/
|
|
|
|
QTAILQ_REMOVE(&mon_list, mon, entry);
|
|
|
|
QTAILQ_INSERT_TAIL(&mon_list, mon, entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
qemu_mutex_unlock(&monitor_lock);
|
|
|
|
|
|
|
|
return req_obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void monitor_qmp_bh_dispatcher(void *data)
|
|
|
|
{
|
monitor: Suspend monitor instead dropping commands
When a QMP client sends in-band commands more quickly that we can
process them, we can either queue them without limit (QUEUE), drop
commands when the queue is full (DROP), or suspend receiving commands
when the queue is full (SUSPEND). None of them is ideal:
* QUEUE lets a misbehaving client make QEMU eat memory without bounds.
Not such a hot idea.
* With DROP, the client has to cope with dropped in-band commands. To
inform the client, we send a COMMAND_DROPPED event then. The event is
flawed by design in two ways: it's ambiguous (see commit d621cfe0a17),
and it brings back the "eat memory without bounds" problem.
* With SUSPEND, the client has to manage the flow of in-band commands to
keep the monitor available for out-of-band commands.
We currently DROP. Switch to SUSPEND.
Managing the flow of in-band commands to keep the monitor available for
out-of-band commands isn't really hard: just count the number of
"outstanding" in-band commands (commands sent minus replies received),
and if it exceeds the limit, hold back additional ones until it drops
below the limit again.
Note that we need to be careful pairing the suspend with a resume, or
else the monitor will hang, possibly forever. And here since we need to
make sure both:
(1) popping request from the req queue, and
(2) reading length of the req queue
will be in the same critical section, we let the pop function take the
corresponding queue lock when there is a request, then we release the
lock from the caller.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20181009062718.1914-2-peterx@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-10-09 08:27:13 +02:00
|
|
|
QMPRequest *req_obj = monitor_qmp_requests_pop_any_with_lock();
|
2018-07-03 10:53:52 +02:00
|
|
|
QDict *rsp;
|
2018-08-29 15:40:37 +02:00
|
|
|
bool need_resume;
|
monitor: Suspend monitor instead dropping commands
When a QMP client sends in-band commands more quickly that we can
process them, we can either queue them without limit (QUEUE), drop
commands when the queue is full (DROP), or suspend receiving commands
when the queue is full (SUSPEND). None of them is ideal:
* QUEUE lets a misbehaving client make QEMU eat memory without bounds.
Not such a hot idea.
* With DROP, the client has to cope with dropped in-band commands. To
inform the client, we send a COMMAND_DROPPED event then. The event is
flawed by design in two ways: it's ambiguous (see commit d621cfe0a17),
and it brings back the "eat memory without bounds" problem.
* With SUSPEND, the client has to manage the flow of in-band commands to
keep the monitor available for out-of-band commands.
We currently DROP. Switch to SUSPEND.
Managing the flow of in-band commands to keep the monitor available for
out-of-band commands isn't really hard: just count the number of
"outstanding" in-band commands (commands sent minus replies received),
and if it exceeds the limit, hold back additional ones until it drops
below the limit again.
Note that we need to be careful pairing the suspend with a resume, or
else the monitor will hang, possibly forever. And here since we need to
make sure both:
(1) popping request from the req queue, and
(2) reading length of the req queue
will be in the same critical section, we let the pop function take the
corresponding queue lock when there is a request, then we release the
lock from the caller.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20181009062718.1914-2-peterx@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-10-09 08:27:13 +02:00
|
|
|
Monitor *mon;
|
2018-03-09 09:59:57 +01:00
|
|
|
|
2018-07-03 10:53:41 +02:00
|
|
|
if (!req_obj) {
|
|
|
|
return;
|
2018-03-09 09:59:57 +01:00
|
|
|
}
|
2018-07-03 10:53:41 +02:00
|
|
|
|
monitor: Suspend monitor instead dropping commands
When a QMP client sends in-band commands more quickly that we can
process them, we can either queue them without limit (QUEUE), drop
commands when the queue is full (DROP), or suspend receiving commands
when the queue is full (SUSPEND). None of them is ideal:
* QUEUE lets a misbehaving client make QEMU eat memory without bounds.
Not such a hot idea.
* With DROP, the client has to cope with dropped in-band commands. To
inform the client, we send a COMMAND_DROPPED event then. The event is
flawed by design in two ways: it's ambiguous (see commit d621cfe0a17),
and it brings back the "eat memory without bounds" problem.
* With SUSPEND, the client has to manage the flow of in-band commands to
keep the monitor available for out-of-band commands.
We currently DROP. Switch to SUSPEND.
Managing the flow of in-band commands to keep the monitor available for
out-of-band commands isn't really hard: just count the number of
"outstanding" in-band commands (commands sent minus replies received),
and if it exceeds the limit, hold back additional ones until it drops
below the limit again.
Note that we need to be careful pairing the suspend with a resume, or
else the monitor will hang, possibly forever. And here since we need to
make sure both:
(1) popping request from the req queue, and
(2) reading length of the req queue
will be in the same critical section, we let the pop function take the
corresponding queue lock when there is a request, then we release the
lock from the caller.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20181009062718.1914-2-peterx@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-10-09 08:27:13 +02:00
|
|
|
mon = req_obj->mon;
|
2018-08-29 15:40:37 +02:00
|
|
|
/* qmp_oob_enabled() might change after "qmp_capabilities" */
|
monitor: Suspend monitor instead dropping commands
When a QMP client sends in-band commands more quickly that we can
process them, we can either queue them without limit (QUEUE), drop
commands when the queue is full (DROP), or suspend receiving commands
when the queue is full (SUSPEND). None of them is ideal:
* QUEUE lets a misbehaving client make QEMU eat memory without bounds.
Not such a hot idea.
* With DROP, the client has to cope with dropped in-band commands. To
inform the client, we send a COMMAND_DROPPED event then. The event is
flawed by design in two ways: it's ambiguous (see commit d621cfe0a17),
and it brings back the "eat memory without bounds" problem.
* With SUSPEND, the client has to manage the flow of in-band commands to
keep the monitor available for out-of-band commands.
We currently DROP. Switch to SUSPEND.
Managing the flow of in-band commands to keep the monitor available for
out-of-band commands isn't really hard: just count the number of
"outstanding" in-band commands (commands sent minus replies received),
and if it exceeds the limit, hold back additional ones until it drops
below the limit again.
Note that we need to be careful pairing the suspend with a resume, or
else the monitor will hang, possibly forever. And here since we need to
make sure both:
(1) popping request from the req queue, and
(2) reading length of the req queue
will be in the same critical section, we let the pop function take the
corresponding queue lock when there is a request, then we release the
lock from the caller.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20181009062718.1914-2-peterx@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-10-09 08:27:13 +02:00
|
|
|
need_resume = !qmp_oob_enabled(mon) ||
|
|
|
|
mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
|
|
|
|
qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
|
2018-07-03 10:53:44 +02:00
|
|
|
if (req_obj->req) {
|
2019-02-20 16:42:53 +01:00
|
|
|
QDict *qdict = qobject_to(QDict, req_obj->req);
|
|
|
|
QObject *id = qdict ? qdict_get(qdict, "id") : NULL;
|
|
|
|
trace_monitor_qmp_cmd_in_band(qobject_get_try_str(id) ?: "");
|
|
|
|
monitor_qmp_dispatch(mon, req_obj->req);
|
2018-07-03 10:53:44 +02:00
|
|
|
} else {
|
|
|
|
assert(req_obj->err);
|
2018-07-03 10:53:52 +02:00
|
|
|
rsp = qmp_error_response(req_obj->err);
|
2018-07-05 18:42:01 +02:00
|
|
|
req_obj->err = NULL;
|
2019-02-20 16:42:53 +01:00
|
|
|
monitor_qmp_respond(mon, rsp);
|
2018-07-03 10:53:52 +02:00
|
|
|
qobject_unref(rsp);
|
2018-07-03 10:53:44 +02:00
|
|
|
}
|
|
|
|
|
2018-08-29 15:40:37 +02:00
|
|
|
if (need_resume) {
|
2018-07-03 10:53:41 +02:00
|
|
|
/* Pairs with the monitor_suspend() in handle_qmp_command() */
|
monitor: Suspend monitor instead dropping commands
When a QMP client sends in-band commands more quickly that we can
process them, we can either queue them without limit (QUEUE), drop
commands when the queue is full (DROP), or suspend receiving commands
when the queue is full (SUSPEND). None of them is ideal:
* QUEUE lets a misbehaving client make QEMU eat memory without bounds.
Not such a hot idea.
* With DROP, the client has to cope with dropped in-band commands. To
inform the client, we send a COMMAND_DROPPED event then. The event is
flawed by design in two ways: it's ambiguous (see commit d621cfe0a17),
and it brings back the "eat memory without bounds" problem.
* With SUSPEND, the client has to manage the flow of in-band commands to
keep the monitor available for out-of-band commands.
We currently DROP. Switch to SUSPEND.
Managing the flow of in-band commands to keep the monitor available for
out-of-band commands isn't really hard: just count the number of
"outstanding" in-band commands (commands sent minus replies received),
and if it exceeds the limit, hold back additional ones until it drops
below the limit again.
Note that we need to be careful pairing the suspend with a resume, or
else the monitor will hang, possibly forever. And here since we need to
make sure both:
(1) popping request from the req queue, and
(2) reading length of the req queue
will be in the same critical section, we let the pop function take the
corresponding queue lock when there is a request, then we release the
lock from the caller.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20181009062718.1914-2-peterx@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-10-09 08:27:13 +02:00
|
|
|
monitor_resume(mon);
|
2018-03-09 09:59:57 +01:00
|
|
|
}
|
2018-07-03 10:53:41 +02:00
|
|
|
qmp_request_free(req_obj);
|
|
|
|
|
|
|
|
/* Reschedule instead of looping so the main loop stays responsive */
|
2018-07-03 10:53:46 +02:00
|
|
|
qemu_bh_schedule(qmp_dispatcher_bh);
|
2018-03-09 09:59:57 +01:00
|
|
|
}
|
|
|
|
|
2018-08-23 18:40:01 +02:00
|
|
|
static void handle_qmp_command(void *opaque, QObject *req, Error *err)
|
2018-03-09 09:59:57 +01:00
|
|
|
{
|
2018-08-23 18:40:01 +02:00
|
|
|
Monitor *mon = opaque;
|
|
|
|
QObject *id = NULL;
|
2018-07-03 10:53:35 +02:00
|
|
|
QDict *qdict;
|
2018-03-09 09:59:57 +01:00
|
|
|
QMPRequest *req_obj;
|
|
|
|
|
2018-08-23 18:40:06 +02:00
|
|
|
assert(!req != !err);
|
2018-03-11 03:38:05 +01:00
|
|
|
|
2018-07-03 10:53:35 +02:00
|
|
|
qdict = qobject_to(QDict, req);
|
|
|
|
if (qdict) {
|
2019-02-20 16:42:53 +01:00
|
|
|
id = qdict_get(qdict, "id");
|
2018-07-03 10:53:35 +02:00
|
|
|
} /* else will fail qmp_dispatch() */
|
2018-03-09 09:59:57 +01:00
|
|
|
|
2018-07-16 11:10:12 +02:00
|
|
|
if (req && trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) {
|
2018-07-03 10:53:39 +02:00
|
|
|
QString *req_json = qobject_to_json(req);
|
|
|
|
trace_handle_qmp_command(mon, qstring_get_str(req_json));
|
|
|
|
qobject_unref(req_json);
|
2018-03-11 03:38:05 +01:00
|
|
|
}
|
|
|
|
|
2018-07-03 10:53:43 +02:00
|
|
|
if (qdict && qmp_is_oob(qdict)) {
|
2018-07-03 10:53:57 +02:00
|
|
|
/* OOB commands are executed immediately */
|
2019-02-20 16:42:53 +01:00
|
|
|
trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(id) ?: "");
|
|
|
|
monitor_qmp_dispatch(mon, req);
|
2018-08-09 13:44:16 +02:00
|
|
|
qobject_unref(req);
|
2018-03-11 03:38:05 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-03-09 09:59:57 +01:00
|
|
|
req_obj = g_new0(QMPRequest, 1);
|
|
|
|
req_obj->mon = mon;
|
|
|
|
req_obj->req = req;
|
2018-07-03 10:53:44 +02:00
|
|
|
req_obj->err = err;
|
2018-03-09 09:59:57 +01:00
|
|
|
|
2018-03-09 09:59:59 +01:00
|
|
|
/* Protect qmp_requests and fetching its length. */
|
|
|
|
qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
|
|
|
|
|
2018-03-09 09:59:57 +01:00
|
|
|
/*
|
monitor: Suspend monitor instead dropping commands
When a QMP client sends in-band commands more quickly that we can
process them, we can either queue them without limit (QUEUE), drop
commands when the queue is full (DROP), or suspend receiving commands
when the queue is full (SUSPEND). None of them is ideal:
* QUEUE lets a misbehaving client make QEMU eat memory without bounds.
Not such a hot idea.
* With DROP, the client has to cope with dropped in-band commands. To
inform the client, we send a COMMAND_DROPPED event then. The event is
flawed by design in two ways: it's ambiguous (see commit d621cfe0a17),
and it brings back the "eat memory without bounds" problem.
* With SUSPEND, the client has to manage the flow of in-band commands to
keep the monitor available for out-of-band commands.
We currently DROP. Switch to SUSPEND.
Managing the flow of in-band commands to keep the monitor available for
out-of-band commands isn't really hard: just count the number of
"outstanding" in-band commands (commands sent minus replies received),
and if it exceeds the limit, hold back additional ones until it drops
below the limit again.
Note that we need to be careful pairing the suspend with a resume, or
else the monitor will hang, possibly forever. And here since we need to
make sure both:
(1) popping request from the req queue, and
(2) reading length of the req queue
will be in the same critical section, we let the pop function take the
corresponding queue lock when there is a request, then we release the
lock from the caller.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20181009062718.1914-2-peterx@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-10-09 08:27:13 +02:00
|
|
|
* Suspend the monitor when we can't queue more requests after
|
|
|
|
* this one. Dequeuing in monitor_qmp_bh_dispatcher() will resume
|
|
|
|
* it. Note that when OOB is disabled, we queue at most one
|
|
|
|
* command, for backward compatibility.
|
2018-03-09 09:59:57 +01:00
|
|
|
*/
|
monitor: Suspend monitor instead dropping commands
When a QMP client sends in-band commands more quickly that we can
process them, we can either queue them without limit (QUEUE), drop
commands when the queue is full (DROP), or suspend receiving commands
when the queue is full (SUSPEND). None of them is ideal:
* QUEUE lets a misbehaving client make QEMU eat memory without bounds.
Not such a hot idea.
* With DROP, the client has to cope with dropped in-band commands. To
inform the client, we send a COMMAND_DROPPED event then. The event is
flawed by design in two ways: it's ambiguous (see commit d621cfe0a17),
and it brings back the "eat memory without bounds" problem.
* With SUSPEND, the client has to manage the flow of in-band commands to
keep the monitor available for out-of-band commands.
We currently DROP. Switch to SUSPEND.
Managing the flow of in-band commands to keep the monitor available for
out-of-band commands isn't really hard: just count the number of
"outstanding" in-band commands (commands sent minus replies received),
and if it exceeds the limit, hold back additional ones until it drops
below the limit again.
Note that we need to be careful pairing the suspend with a resume, or
else the monitor will hang, possibly forever. And here since we need to
make sure both:
(1) popping request from the req queue, and
(2) reading length of the req queue
will be in the same critical section, we let the pop function take the
corresponding queue lock when there is a request, then we release the
lock from the caller.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20181009062718.1914-2-peterx@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-10-09 08:27:13 +02:00
|
|
|
if (!qmp_oob_enabled(mon) ||
|
|
|
|
mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
|
2018-03-09 09:59:57 +01:00
|
|
|
monitor_suspend(mon);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Put the request to the end of queue so that requests will be
|
2019-02-20 16:42:53 +01:00
|
|
|
* handled in time order. Ownership for req_obj, req,
|
2018-03-09 09:59:57 +01:00
|
|
|
* etc. will be delivered to the handler side.
|
|
|
|
*/
|
monitor: Suspend monitor instead dropping commands
When a QMP client sends in-band commands more quickly that we can
process them, we can either queue them without limit (QUEUE), drop
commands when the queue is full (DROP), or suspend receiving commands
when the queue is full (SUSPEND). None of them is ideal:
* QUEUE lets a misbehaving client make QEMU eat memory without bounds.
Not such a hot idea.
* With DROP, the client has to cope with dropped in-band commands. To
inform the client, we send a COMMAND_DROPPED event then. The event is
flawed by design in two ways: it's ambiguous (see commit d621cfe0a17),
and it brings back the "eat memory without bounds" problem.
* With SUSPEND, the client has to manage the flow of in-band commands to
keep the monitor available for out-of-band commands.
We currently DROP. Switch to SUSPEND.
Managing the flow of in-band commands to keep the monitor available for
out-of-band commands isn't really hard: just count the number of
"outstanding" in-band commands (commands sent minus replies received),
and if it exceeds the limit, hold back additional ones until it drops
below the limit again.
Note that we need to be careful pairing the suspend with a resume, or
else the monitor will hang, possibly forever. And here since we need to
make sure both:
(1) popping request from the req queue, and
(2) reading length of the req queue
will be in the same critical section, we let the pop function take the
corresponding queue lock when there is a request, then we release the
lock from the caller.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20181009062718.1914-2-peterx@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-10-09 08:27:13 +02:00
|
|
|
assert(mon->qmp.qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX);
|
2018-03-09 09:59:57 +01:00
|
|
|
g_queue_push_tail(mon->qmp.qmp_requests, req_obj);
|
|
|
|
qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
|
|
|
|
|
|
|
|
/* Kick the dispatcher routine */
|
2018-07-03 10:53:46 +02:00
|
|
|
qemu_bh_schedule(qmp_dispatcher_bh);
|
2018-03-09 09:59:57 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 19:20:51 +01:00
|
|
|
static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size)
|
2009-11-27 01:58:58 +01:00
|
|
|
{
|
2018-03-09 09:59:49 +01:00
|
|
|
Monitor *mon = opaque;
|
2009-11-27 01:58:58 +01:00
|
|
|
|
2018-03-09 09:59:49 +01:00
|
|
|
json_message_parser_feed(&mon->qmp.parser, (const char *) buf, size);
|
2009-11-27 01:58:58 +01:00
|
|
|
}
|
|
|
|
|
2009-03-06 00:01:42 +01:00
|
|
|
static void monitor_read(void *opaque, const uint8_t *buf, int size)
|
2004-03-14 22:38:27 +01:00
|
|
|
{
|
2009-03-06 00:01:42 +01:00
|
|
|
Monitor *old_mon = cur_mon;
|
2004-08-01 23:52:19 +02:00
|
|
|
int i;
|
2009-03-06 00:01:23 +01:00
|
|
|
|
2009-03-06 00:01:42 +01:00
|
|
|
cur_mon = opaque;
|
|
|
|
|
2009-03-06 00:01:51 +01:00
|
|
|
if (cur_mon->rs) {
|
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
readline_handle_byte(cur_mon->rs, buf[i]);
|
|
|
|
} else {
|
|
|
|
if (size == 0 || buf[size - 1] != 0)
|
|
|
|
monitor_printf(cur_mon, "corrupted command\n");
|
|
|
|
else
|
2015-03-06 19:12:36 +01:00
|
|
|
handle_hmp_command(cur_mon, (char *)buf);
|
2009-03-06 00:01:51 +01:00
|
|
|
}
|
2004-03-14 22:38:27 +01:00
|
|
|
|
2009-03-06 00:01:42 +01:00
|
|
|
cur_mon = old_mon;
|
|
|
|
}
|
2008-10-06 15:52:44 +02:00
|
|
|
|
2013-11-14 11:54:14 +01:00
|
|
|
static void monitor_command_cb(void *opaque, const char *cmdline,
|
|
|
|
void *readline_opaque)
|
2004-04-04 15:07:25 +02:00
|
|
|
{
|
2013-11-14 11:54:14 +01:00
|
|
|
Monitor *mon = opaque;
|
|
|
|
|
2009-03-06 00:01:42 +01:00
|
|
|
monitor_suspend(mon);
|
2015-03-06 19:12:36 +01:00
|
|
|
handle_hmp_command(mon, cmdline);
|
2009-03-06 00:01:42 +01:00
|
|
|
monitor_resume(mon);
|
2008-10-06 15:52:44 +02:00
|
|
|
}
|
|
|
|
|
2009-03-06 00:01:51 +01:00
|
|
|
int monitor_suspend(Monitor *mon)
|
2008-10-06 15:52:44 +02:00
|
|
|
{
|
2018-03-09 09:59:56 +01:00
|
|
|
if (monitor_is_hmp_non_interactive(mon)) {
|
2009-03-06 00:01:51 +01:00
|
|
|
return -ENOTTY;
|
2018-03-09 09:59:56 +01:00
|
|
|
}
|
|
|
|
|
2018-03-09 09:59:55 +01:00
|
|
|
atomic_inc(&mon->suspend_cnt);
|
2018-03-09 09:59:56 +01:00
|
|
|
|
2018-12-05 21:37:32 +01:00
|
|
|
if (mon->use_io_thread) {
|
2018-03-09 09:59:56 +01:00
|
|
|
/*
|
2018-07-03 10:53:28 +02:00
|
|
|
* Kick I/O thread to make sure this takes effect. It'll be
|
2018-03-09 09:59:56 +01:00
|
|
|
* evaluated again in prepare() of the watch object.
|
|
|
|
*/
|
2018-07-03 10:53:46 +02:00
|
|
|
aio_notify(iothread_get_aio_context(mon_iothread));
|
2018-03-09 09:59:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
trace_monitor_suspend(mon, 1);
|
2009-03-06 00:01:51 +01:00
|
|
|
return 0;
|
2008-10-06 15:52:44 +02:00
|
|
|
}
|
|
|
|
|
2018-12-05 21:37:32 +01:00
|
|
|
static void monitor_accept_input(void *opaque)
|
|
|
|
{
|
|
|
|
Monitor *mon = opaque;
|
|
|
|
|
|
|
|
qemu_chr_fe_accept_input(&mon->chr);
|
|
|
|
}
|
|
|
|
|
2009-03-06 00:01:23 +01:00
|
|
|
void monitor_resume(Monitor *mon)
|
2008-10-06 15:52:44 +02:00
|
|
|
{
|
2018-03-09 09:59:56 +01:00
|
|
|
if (monitor_is_hmp_non_interactive(mon)) {
|
2009-03-06 00:01:51 +01:00
|
|
|
return;
|
2018-03-09 09:59:56 +01:00
|
|
|
}
|
|
|
|
|
2018-03-09 09:59:55 +01:00
|
|
|
if (atomic_dec_fetch(&mon->suspend_cnt) == 0) {
|
2018-12-05 21:37:32 +01:00
|
|
|
AioContext *ctx;
|
|
|
|
|
|
|
|
if (mon->use_io_thread) {
|
|
|
|
ctx = iothread_get_aio_context(mon_iothread);
|
2018-03-09 09:59:56 +01:00
|
|
|
} else {
|
2018-12-05 21:37:32 +01:00
|
|
|
ctx = qemu_get_aio_context();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!monitor_is_qmp(mon)) {
|
2018-03-09 09:59:56 +01:00
|
|
|
assert(mon->rs);
|
|
|
|
readline_show_prompt(mon->rs);
|
|
|
|
}
|
2018-12-05 21:37:32 +01:00
|
|
|
|
|
|
|
aio_bh_schedule_oneshot(ctx, monitor_accept_input, mon);
|
2018-03-09 09:59:55 +01:00
|
|
|
}
|
2018-12-05 21:37:32 +01:00
|
|
|
|
2018-03-09 09:59:56 +01:00
|
|
|
trace_monitor_suspend(mon, -1);
|
2004-04-04 15:07:25 +02:00
|
|
|
}
|
|
|
|
|
2018-07-03 10:53:51 +02:00
|
|
|
static QDict *qmp_greeting(Monitor *mon)
|
2010-02-04 21:10:04 +01: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 09:59:53 +01:00
|
|
|
QList *cap_list = qlist_new();
|
2011-08-26 22:38:13 +02:00
|
|
|
QObject *ver = NULL;
|
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 09:59:53 +01:00
|
|
|
QMPCapability cap;
|
2010-02-04 21:10:04 +01:00
|
|
|
|
2015-09-16 13:06:19 +02:00
|
|
|
qmp_marshal_query_version(NULL, &ver, NULL);
|
2016-09-12 11:19:04 +02: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 09:59:53 +01:00
|
|
|
for (cap = 0; cap < QMP_CAPABILITY__MAX; cap++) {
|
2018-07-03 10:53:56 +02:00
|
|
|
if (mon->qmp.capab_offered[cap]) {
|
|
|
|
qlist_append_str(cap_list, QMPCapability_str(cap));
|
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 09:59:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-03 10:53:51 +02:00
|
|
|
return qdict_from_jsonf_nofail(
|
|
|
|
"{'QMP': {'version': %p, 'capabilities': %p}}",
|
|
|
|
ver, cap_list);
|
2010-02-04 21:10:04 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 19:20:51 +01:00
|
|
|
static void monitor_qmp_event(void *opaque, int event)
|
2009-11-27 01:58:58 +01:00
|
|
|
{
|
2018-07-03 10:53:51 +02:00
|
|
|
QDict *data;
|
2010-02-08 20:01:30 +01:00
|
|
|
Monitor *mon = opaque;
|
2009-11-27 01:58:58 +01:00
|
|
|
|
2010-02-08 20:01:30 +01:00
|
|
|
switch (event) {
|
|
|
|
case CHR_EVENT_OPENED:
|
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 13:32:27 +01:00
|
|
|
mon->qmp.commands = &qmp_cap_negotiation_commands;
|
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 09:59:53 +01:00
|
|
|
monitor_qmp_caps_reset(mon);
|
2018-07-03 10:53:51 +02:00
|
|
|
data = qmp_greeting(mon);
|
2018-08-29 15:40:36 +02:00
|
|
|
qmp_send_response(mon, data);
|
2018-04-19 17:01:43 +02:00
|
|
|
qobject_unref(data);
|
2012-08-14 22:43:48 +02:00
|
|
|
mon_refcount++;
|
2010-02-08 20:01:30 +01:00
|
|
|
break;
|
|
|
|
case CHR_EVENT_CLOSED:
|
monitor: flush qmp responses when CLOSED
Previously we clean up the queues when we got CLOSED event. It was used
to make sure we won't send leftover replies/events of a old client to a
new client which makes perfect sense. However this will also drop the
replies/events even if the output port of the previous chardev backend
is still open, which can lead to missing of the last replies/events.
Now this patch does an extra operation to flush the response queue
before cleaning up.
In most cases, a QMP session will be based on a bidirectional channel (a
TCP port, for example, we read/write to the same socket handle), so in
port and out port of the backend chardev are fundamentally the same
port. In these cases, it does not really matter much on whether we'll
flush the response queue since flushing will fail anyway. However there
can be cases where in & out ports of the QMP monitor's backend chardev
are separated. Here is an example:
cat $QMP_COMMANDS | qemu -qmp stdio ... | filter_commands
In this case, the backend is fd-typed, and it is connected to stdio
where in port is stdin and out port is stdout. Now if we drop all the
events on the response queue then filter_command process might miss some
events that it might expect. The thing is that, when stdin closes,
stdout might still be there alive!
In practice, I encountered SHUTDOWN event missing when running test with
iotest 087 with Out-Of-Band enabled. Here is one of the ways that this
can happen (after "quit" command is executed and QEMU quits the main
loop):
1. [main thread] QEMU queues a SHUTDOWN event into response queue.
2. "cat" terminates (to distinguish it from the animal, I quote it).
3. [monitor iothread] QEMU's monitor iothread reads EOF from stdin.
4. [monitor iothread] QEMU's monitor iothread calls the CLOSED event
hook for the monitor, which will destroy the response queue of the
monitor, then the SHUTDOWN event is dropped.
5. [main thread] QEMU's main thread cleans up the monitors in
monitor_cleanup(). When trying to flush pending responses, it sees
nothing. SHUTDOWN is lost forever.
Note that before the monitor iothread was introduced, step [4]/[5] could
never happen since the main loop was the only place to detect the EOF
event of stdin and run the CLOSED event hooks. Now things can happen in
parallel in the iothread.
Without this patch, iotest 087 will have ~10% chance to miss the
SHUTDOWN event and fail when with Out-Of-Band enabled:
--- /home/peterx/git/qemu/tests/qemu-iotests/087.out
+++ /home/peterx/git/qemu/bin/tests/qemu-iotests/087.out.bad
@@ -8,7 +8,6 @@
{"return": {}}
{"error": {"class": "GenericError", "desc": "'node-name' must be
specified for the root node"}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
=== Duplicate ID ===
@@ -53,7 +52,6 @@
{"return": {}}
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
This patch fixes the problem.
Fixes: 6d2d563f8c ("qmp: cleanup qmp queues properly", 2018-03-27)
Suggested-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20180620073223.31964-4-peterx@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Commit message and a comment touched up]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-06-20 09:32:19 +02:00
|
|
|
/*
|
|
|
|
* Note: this is only useful when the output of the chardev
|
|
|
|
* backend is still open. For example, when the backend is
|
|
|
|
* stdio, it's possible that stdout is still open when stdin
|
|
|
|
* is closed.
|
|
|
|
*/
|
2018-03-26 08:38:55 +02:00
|
|
|
monitor_qmp_cleanup_queues(mon);
|
2015-03-06 19:35:59 +01:00
|
|
|
json_message_parser_destroy(&mon->qmp.parser);
|
2018-08-23 18:40:01 +02:00
|
|
|
json_message_parser_init(&mon->qmp.parser, handle_qmp_command,
|
|
|
|
mon, NULL);
|
2012-08-14 22:43:48 +02:00
|
|
|
mon_refcount--;
|
|
|
|
monitor_fdsets_cleanup();
|
2010-02-08 20:01:30 +01:00
|
|
|
break;
|
2009-11-27 01:58:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-06 00:01:42 +01:00
|
|
|
static void monitor_event(void *opaque, int event)
|
2007-01-05 23:01:59 +01:00
|
|
|
{
|
2009-03-06 00:01:23 +01:00
|
|
|
Monitor *mon = opaque;
|
|
|
|
|
2009-03-06 00:01:47 +01:00
|
|
|
switch (event) {
|
|
|
|
case CHR_EVENT_MUX_IN:
|
2018-06-08 05:55:05 +02:00
|
|
|
qemu_mutex_lock(&mon->mon_lock);
|
2009-09-10 10:58:54 +02:00
|
|
|
mon->mux_out = 0;
|
2018-06-08 05:55:05 +02:00
|
|
|
qemu_mutex_unlock(&mon->mon_lock);
|
2009-09-10 10:58:54 +02:00
|
|
|
if (mon->reset_seen) {
|
|
|
|
readline_restart(mon->rs);
|
|
|
|
monitor_resume(mon);
|
|
|
|
monitor_flush(mon);
|
|
|
|
} else {
|
2018-03-09 09:59:55 +01:00
|
|
|
atomic_mb_set(&mon->suspend_cnt, 0);
|
2009-09-10 10:58:54 +02:00
|
|
|
}
|
2009-03-06 00:01:47 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CHR_EVENT_MUX_OUT:
|
2009-09-10 10:58:54 +02:00
|
|
|
if (mon->reset_seen) {
|
2018-03-09 09:59:55 +01:00
|
|
|
if (atomic_mb_read(&mon->suspend_cnt) == 0) {
|
2009-09-10 10:58:54 +02:00
|
|
|
monitor_printf(mon, "\n");
|
|
|
|
}
|
|
|
|
monitor_flush(mon);
|
|
|
|
monitor_suspend(mon);
|
|
|
|
} else {
|
2018-03-09 09:59:55 +01:00
|
|
|
atomic_inc(&mon->suspend_cnt);
|
2009-09-10 10:58:54 +02:00
|
|
|
}
|
2018-06-08 05:55:05 +02:00
|
|
|
qemu_mutex_lock(&mon->mon_lock);
|
2009-09-10 10:58:54 +02:00
|
|
|
mon->mux_out = 1;
|
2018-06-08 05:55:05 +02:00
|
|
|
qemu_mutex_unlock(&mon->mon_lock);
|
2009-03-06 00:01:47 +01:00
|
|
|
break;
|
2007-01-05 23:01:59 +01:00
|
|
|
|
2009-10-07 15:01:16 +02:00
|
|
|
case CHR_EVENT_OPENED:
|
2009-03-06 00:01:47 +01:00
|
|
|
monitor_printf(mon, "QEMU %s monitor - type 'help' for more "
|
|
|
|
"information\n", QEMU_VERSION);
|
2009-09-10 10:58:54 +02:00
|
|
|
if (!mon->mux_out) {
|
2014-09-15 14:34:57 +02:00
|
|
|
readline_restart(mon->rs);
|
2009-03-06 00:01:47 +01:00
|
|
|
readline_show_prompt(mon->rs);
|
2009-09-10 10:58:54 +02:00
|
|
|
}
|
|
|
|
mon->reset_seen = 1;
|
2012-08-14 22:43:48 +02:00
|
|
|
mon_refcount++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CHR_EVENT_CLOSED:
|
|
|
|
mon_refcount--;
|
|
|
|
monitor_fdsets_cleanup();
|
2009-03-06 00:01:47 +01:00
|
|
|
break;
|
|
|
|
}
|
2007-01-05 23:01:59 +01:00
|
|
|
}
|
|
|
|
|
2011-10-12 05:32:41 +02:00
|
|
|
static int
|
|
|
|
compare_mon_cmd(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
return strcmp(((const mon_cmd_t *)a)->name,
|
|
|
|
((const mon_cmd_t *)b)->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sortcmdlist(void)
|
|
|
|
{
|
|
|
|
int array_num;
|
|
|
|
int elem_size = sizeof(mon_cmd_t);
|
|
|
|
|
|
|
|
array_num = sizeof(mon_cmds)/elem_size-1;
|
|
|
|
qsort((void *)mon_cmds, array_num, elem_size, compare_mon_cmd);
|
|
|
|
|
|
|
|
array_num = sizeof(info_cmds)/elem_size-1;
|
|
|
|
qsort((void *)info_cmds, array_num, elem_size, compare_mon_cmd);
|
|
|
|
}
|
|
|
|
|
2018-03-09 09:59:52 +01:00
|
|
|
static void monitor_iothread_init(void)
|
|
|
|
{
|
2018-07-03 10:53:46 +02:00
|
|
|
mon_iothread = iothread_create("mon_iothread", &error_abort);
|
2018-03-09 09:59:52 +01:00
|
|
|
}
|
|
|
|
|
2018-03-09 09:59:50 +01:00
|
|
|
void monitor_init_globals(void)
|
|
|
|
{
|
|
|
|
monitor_init_qmp_commands();
|
|
|
|
monitor_qapi_event_init();
|
|
|
|
sortcmdlist();
|
|
|
|
qemu_mutex_init(&monitor_lock);
|
2018-06-08 05:55:11 +02:00
|
|
|
qemu_mutex_init(&mon_fdsets_lock);
|
2018-09-25 10:15:07 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The dispatcher BH must run in the main loop thread, since we
|
|
|
|
* have commands assuming that context. It would be nice to get
|
|
|
|
* rid of those assumptions.
|
|
|
|
*/
|
|
|
|
qmp_dispatcher_bh = aio_bh_new(iohandler_get_aio_context(),
|
|
|
|
monitor_qmp_bh_dispatcher,
|
|
|
|
NULL);
|
2018-03-09 09:59:50 +01:00
|
|
|
}
|
|
|
|
|
2013-11-14 11:54:14 +01:00
|
|
|
/* These functions just adapt the readline interface in a typesafe way. We
|
|
|
|
* could cast function pointers but that discards compiler checks.
|
|
|
|
*/
|
2014-01-25 18:18:23 +01:00
|
|
|
static void GCC_FMT_ATTR(2, 3) monitor_readline_printf(void *opaque,
|
|
|
|
const char *fmt, ...)
|
2013-11-14 11:54:14 +01:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
monitor_vprintf(opaque, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void monitor_readline_flush(void *opaque)
|
|
|
|
{
|
|
|
|
monitor_flush(opaque);
|
|
|
|
}
|
|
|
|
|
2016-10-24 18:31:02 +02:00
|
|
|
/*
|
2019-04-17 21:06:41 +02:00
|
|
|
* Print to current monitor if we have one, else to stderr.
|
2016-10-24 18:31:02 +02:00
|
|
|
*/
|
2019-04-17 21:06:41 +02:00
|
|
|
int error_vprintf(const char *fmt, va_list ap)
|
2016-10-24 18:31:02 +02:00
|
|
|
{
|
|
|
|
if (cur_mon && !monitor_cur_is_qmp()) {
|
2019-04-17 21:06:36 +02:00
|
|
|
return monitor_vprintf(cur_mon, fmt, ap);
|
2016-10-24 18:31:02 +02:00
|
|
|
}
|
2019-04-17 21:06:41 +02:00
|
|
|
return vfprintf(stderr, fmt, ap);
|
2018-09-07 09:45:39 +02:00
|
|
|
}
|
|
|
|
|
2019-04-17 21:06:36 +02:00
|
|
|
int error_vprintf_unless_qmp(const char *fmt, va_list ap)
|
2016-10-24 18:31:02 +02:00
|
|
|
{
|
2019-04-17 21:06:36 +02:00
|
|
|
if (!cur_mon) {
|
|
|
|
return vfprintf(stderr, fmt, ap);
|
2016-10-24 18:31:02 +02:00
|
|
|
}
|
2019-04-17 21:06:36 +02:00
|
|
|
if (!monitor_cur_is_qmp()) {
|
|
|
|
return monitor_vprintf(cur_mon, fmt, ap);
|
|
|
|
}
|
|
|
|
return -1;
|
2016-10-24 18:31:02 +02:00
|
|
|
}
|
|
|
|
|
2018-03-09 09:59:52 +01:00
|
|
|
static void monitor_list_append(Monitor *mon)
|
|
|
|
{
|
|
|
|
qemu_mutex_lock(&monitor_lock);
|
2018-12-05 21:37:36 +01:00
|
|
|
/*
|
|
|
|
* This prevents inserting new monitors during monitor_cleanup().
|
|
|
|
* A cleaner solution would involve the main thread telling other
|
|
|
|
* threads to terminate, waiting for their termination.
|
|
|
|
*/
|
|
|
|
if (!monitor_destroyed) {
|
|
|
|
QTAILQ_INSERT_HEAD(&mon_list, mon, entry);
|
|
|
|
mon = NULL;
|
|
|
|
}
|
2018-03-09 09:59:52 +01:00
|
|
|
qemu_mutex_unlock(&monitor_lock);
|
2018-12-05 21:37:36 +01:00
|
|
|
|
|
|
|
if (mon) {
|
|
|
|
monitor_data_destroy(mon);
|
|
|
|
g_free(mon);
|
|
|
|
}
|
2018-03-09 09:59:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void monitor_qmp_setup_handlers_bh(void *opaque)
|
|
|
|
{
|
|
|
|
Monitor *mon = opaque;
|
|
|
|
GMainContext *context;
|
|
|
|
|
2018-08-15 15:37:35 +02:00
|
|
|
assert(mon->use_io_thread);
|
2018-12-05 21:37:31 +01:00
|
|
|
context = iothread_get_g_main_context(mon_iothread);
|
2018-08-15 15:37:35 +02:00
|
|
|
assert(context);
|
2018-03-09 09:59:52 +01:00
|
|
|
qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_qmp_read,
|
|
|
|
monitor_qmp_event, NULL, mon, context, true);
|
|
|
|
monitor_list_append(mon);
|
|
|
|
}
|
|
|
|
|
2016-12-07 14:20:22 +01:00
|
|
|
void monitor_init(Chardev *chr, int flags)
|
2004-04-04 15:07:25 +02:00
|
|
|
{
|
2018-03-09 09:59:50 +01:00
|
|
|
Monitor *mon = g_malloc(sizeof(*mon));
|
2018-03-26 08:38:56 +02:00
|
|
|
bool use_readline = flags & MONITOR_USE_READLINE;
|
2009-03-06 00:01:29 +01:00
|
|
|
|
2018-10-09 08:27:15 +02:00
|
|
|
/* Note: we run QMP monitor in I/O thread when @chr supports that */
|
|
|
|
monitor_data_init(mon, false,
|
|
|
|
(flags & MONITOR_USE_CONTROL)
|
|
|
|
&& qemu_chr_has_feature(chr,
|
|
|
|
QEMU_CHAR_FEATURE_GCONTEXT));
|
2007-02-18 18:04:49 +01:00
|
|
|
|
2016-10-22 11:52:52 +02:00
|
|
|
qemu_chr_fe_init(&mon->chr, chr, &error_abort);
|
2009-03-06 00:01:42 +01:00
|
|
|
mon->flags = flags;
|
2018-03-26 08:38:56 +02:00
|
|
|
if (use_readline) {
|
2013-11-14 11:54:14 +01:00
|
|
|
mon->rs = readline_init(monitor_readline_printf,
|
|
|
|
monitor_readline_flush,
|
|
|
|
mon,
|
|
|
|
monitor_find_completion);
|
2009-03-06 00:01:51 +01:00
|
|
|
monitor_read_command(mon, 0);
|
|
|
|
}
|
2009-03-06 00:01:29 +01:00
|
|
|
|
2015-03-06 19:56:38 +01:00
|
|
|
if (monitor_is_qmp(mon)) {
|
2016-10-22 11:52:55 +02:00
|
|
|
qemu_chr_fe_set_echo(&mon->chr, true);
|
2018-08-23 18:40:01 +02:00
|
|
|
json_message_parser_init(&mon->qmp.parser, handle_qmp_command,
|
|
|
|
mon, NULL);
|
2018-07-03 10:53:45 +02:00
|
|
|
if (mon->use_io_thread) {
|
2018-03-09 09:59:52 +01:00
|
|
|
/*
|
|
|
|
* Make sure the old iowatch is gone. It's possible when
|
|
|
|
* e.g. the chardev is in client mode, with wait=on.
|
|
|
|
*/
|
|
|
|
remove_fd_in_watch(chr);
|
|
|
|
/*
|
|
|
|
* We can't call qemu_chr_fe_set_handlers() directly here
|
2018-07-03 10:53:57 +02:00
|
|
|
* since chardev might be running in the monitor I/O
|
|
|
|
* thread. Schedule a bottom half.
|
2018-03-09 09:59:52 +01:00
|
|
|
*/
|
2018-12-05 21:37:31 +01:00
|
|
|
aio_bh_schedule_oneshot(iothread_get_aio_context(mon_iothread),
|
2018-03-09 09:59:52 +01:00
|
|
|
monitor_qmp_setup_handlers_bh, mon);
|
2018-07-03 10:53:57 +02:00
|
|
|
/* The bottom half will add @mon to @mon_list */
|
2018-03-09 09:59:52 +01:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read,
|
|
|
|
monitor_qmp_read, monitor_qmp_event,
|
|
|
|
NULL, mon, NULL, true);
|
|
|
|
}
|
2009-11-27 01:58:58 +01:00
|
|
|
} else {
|
2016-10-22 11:52:55 +02:00
|
|
|
qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_read,
|
2017-07-06 14:08:49 +02:00
|
|
|
monitor_event, NULL, mon, NULL, true);
|
2009-11-27 01:58:58 +01:00
|
|
|
}
|
2009-03-06 00:01:29 +01:00
|
|
|
|
2018-03-09 09:59:52 +01:00
|
|
|
monitor_list_append(mon);
|
2004-04-04 15:07:25 +02:00
|
|
|
}
|
|
|
|
|
monitor: fix crash when leaving qemu with spice audio
Since aa5cb7f5e, the chardevs are being cleaned up when leaving
qemu. However, the monitor has still references to them, which may
lead to crashes when running atexit() and trying to send monitor
events:
#0 0x00007fffdb18f6f5 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007fffdb1912fa in __GI_abort () at abort.c:89
#2 0x0000555555c263e7 in error_exit (err=22, msg=0x555555d47980 <__func__.13537> "qemu_mutex_lock") at util/qemu-thread-posix.c:39
#3 0x0000555555c26488 in qemu_mutex_lock (mutex=0x5555567a2420) at util/qemu-thread-posix.c:66
#4 0x00005555558c52db in qemu_chr_fe_write (s=0x5555567a2420, buf=0x55555740dc40 "{\"timestamp\": {\"seconds\": 1470041716, \"microseconds\": 989699}, \"event\": \"SPICE_DISCONNECTED\", \"data\": {\"server\": {\"port\": \"5900\", \"family\": \"ipv4\", \"host\": \"127.0.0.1\"}, \"client\": {\"port\": \"40272\", \"f"..., len=240) at qemu-char.c:280
#5 0x0000555555787cad in monitor_flush_locked (mon=0x5555567bd9e0) at /home/elmarco/src/qemu/monitor.c:311
#6 0x0000555555787e46 in monitor_puts (mon=0x5555567bd9e0, str=0x5555567a44ef "") at /home/elmarco/src/qemu/monitor.c:353
#7 0x00005555557880fe in monitor_json_emitter (mon=0x5555567bd9e0, data=0x5555567c73a0) at /home/elmarco/src/qemu/monitor.c:401
#8 0x00005555557882d2 in monitor_qapi_event_emit (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x5555567c73a0) at /home/elmarco/src/qemu/monitor.c:472
#9 0x000055555578838f in monitor_qapi_event_queue (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x5555567c73a0, errp=0x7fffffffca88) at /home/elmarco/src/qemu/monitor.c:497
#10 0x0000555555c15541 in qapi_event_send_spice_disconnected (server=0x5555571139d0, client=0x5555570d0db0, errp=0x5555566c0428 <error_abort>) at qapi-event.c:1038
#11 0x0000555555b11bc6 in channel_event (event=3, info=0x5555570d6c00) at ui/spice-core.c:248
#12 0x00007fffdcc9983a in adapter_channel_event (event=3, info=0x5555570d6c00) at reds.c:120
#13 0x00007fffdcc99a25 in reds_handle_channel_event (reds=0x5555567a9d60, event=3, info=0x5555570d6c00) at reds.c:324
#14 0x00007fffdcc7d4c4 in main_dispatcher_self_handle_channel_event (self=0x5555567b28b0, event=3, info=0x5555570d6c00) at main-dispatcher.c:175
#15 0x00007fffdcc7d5b1 in main_dispatcher_channel_event (self=0x5555567b28b0, event=3, info=0x5555570d6c00) at main-dispatcher.c:194
#16 0x00007fffdcca7674 in reds_stream_push_channel_event (s=0x5555570d9910, event=3) at reds-stream.c:354
#17 0x00007fffdcca749b in reds_stream_free (s=0x5555570d9910) at reds-stream.c:323
#18 0x00007fffdccb5dad in snd_disconnect_channel (channel=0x5555576a89a0) at sound.c:229
#19 0x00007fffdccb9e57 in snd_detach_common (worker=0x555557739720) at sound.c:1589
#20 0x00007fffdccb9f0e in snd_detach_playback (sin=0x5555569fe3f8) at sound.c:1602
#21 0x00007fffdcca3373 in spice_server_remove_interface (sin=0x5555569fe3f8) at reds.c:3387
#22 0x00005555558ff6e2 in line_out_fini (hw=0x5555569fe370) at audio/spiceaudio.c:152
#23 0x00005555558f909e in audio_atexit () at audio/audio.c:1754
#24 0x00007fffdb1941e8 in __run_exit_handlers (status=0, listp=0x7fffdb5175d8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true) at exit.c:82
#25 0x00007fffdb194235 in __GI_exit (status=<optimized out>) at exit.c:104
#26 0x00007fffdb17b738 in __libc_start_main (main=0x5555558d7874 <main>, argc=67, argv=0x7fffffffcf48, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffcf38) at ../csu/libc-start.c:323
Add a monitor_cleanup() functions to remove all the monitors before
cleaning up the chardev. Note that we are "losing" some events that
used to be sent during atexit().
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20160801112343.29082-2-marcandre.lureau@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-08-01 13:23:42 +02:00
|
|
|
void monitor_cleanup(void)
|
|
|
|
{
|
2018-03-09 09:59:52 +01:00
|
|
|
/*
|
2018-07-03 10:53:28 +02:00
|
|
|
* We need to explicitly stop the I/O thread (but not destroy it),
|
2018-07-03 10:53:57 +02:00
|
|
|
* clean up the monitor resources, then destroy the I/O thread since
|
2018-03-09 09:59:52 +01:00
|
|
|
* we need to unregister from chardev below in
|
|
|
|
* monitor_data_destroy(), and chardev is not thread-safe yet
|
|
|
|
*/
|
2018-09-25 10:15:07 +02:00
|
|
|
if (mon_iothread) {
|
|
|
|
iothread_stop(mon_iothread);
|
|
|
|
}
|
2018-03-09 09:59:52 +01:00
|
|
|
|
2018-07-03 10:53:57 +02:00
|
|
|
/* Flush output buffers and destroy monitors */
|
monitor: fix crash when leaving qemu with spice audio
Since aa5cb7f5e, the chardevs are being cleaned up when leaving
qemu. However, the monitor has still references to them, which may
lead to crashes when running atexit() and trying to send monitor
events:
#0 0x00007fffdb18f6f5 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007fffdb1912fa in __GI_abort () at abort.c:89
#2 0x0000555555c263e7 in error_exit (err=22, msg=0x555555d47980 <__func__.13537> "qemu_mutex_lock") at util/qemu-thread-posix.c:39
#3 0x0000555555c26488 in qemu_mutex_lock (mutex=0x5555567a2420) at util/qemu-thread-posix.c:66
#4 0x00005555558c52db in qemu_chr_fe_write (s=0x5555567a2420, buf=0x55555740dc40 "{\"timestamp\": {\"seconds\": 1470041716, \"microseconds\": 989699}, \"event\": \"SPICE_DISCONNECTED\", \"data\": {\"server\": {\"port\": \"5900\", \"family\": \"ipv4\", \"host\": \"127.0.0.1\"}, \"client\": {\"port\": \"40272\", \"f"..., len=240) at qemu-char.c:280
#5 0x0000555555787cad in monitor_flush_locked (mon=0x5555567bd9e0) at /home/elmarco/src/qemu/monitor.c:311
#6 0x0000555555787e46 in monitor_puts (mon=0x5555567bd9e0, str=0x5555567a44ef "") at /home/elmarco/src/qemu/monitor.c:353
#7 0x00005555557880fe in monitor_json_emitter (mon=0x5555567bd9e0, data=0x5555567c73a0) at /home/elmarco/src/qemu/monitor.c:401
#8 0x00005555557882d2 in monitor_qapi_event_emit (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x5555567c73a0) at /home/elmarco/src/qemu/monitor.c:472
#9 0x000055555578838f in monitor_qapi_event_queue (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x5555567c73a0, errp=0x7fffffffca88) at /home/elmarco/src/qemu/monitor.c:497
#10 0x0000555555c15541 in qapi_event_send_spice_disconnected (server=0x5555571139d0, client=0x5555570d0db0, errp=0x5555566c0428 <error_abort>) at qapi-event.c:1038
#11 0x0000555555b11bc6 in channel_event (event=3, info=0x5555570d6c00) at ui/spice-core.c:248
#12 0x00007fffdcc9983a in adapter_channel_event (event=3, info=0x5555570d6c00) at reds.c:120
#13 0x00007fffdcc99a25 in reds_handle_channel_event (reds=0x5555567a9d60, event=3, info=0x5555570d6c00) at reds.c:324
#14 0x00007fffdcc7d4c4 in main_dispatcher_self_handle_channel_event (self=0x5555567b28b0, event=3, info=0x5555570d6c00) at main-dispatcher.c:175
#15 0x00007fffdcc7d5b1 in main_dispatcher_channel_event (self=0x5555567b28b0, event=3, info=0x5555570d6c00) at main-dispatcher.c:194
#16 0x00007fffdcca7674 in reds_stream_push_channel_event (s=0x5555570d9910, event=3) at reds-stream.c:354
#17 0x00007fffdcca749b in reds_stream_free (s=0x5555570d9910) at reds-stream.c:323
#18 0x00007fffdccb5dad in snd_disconnect_channel (channel=0x5555576a89a0) at sound.c:229
#19 0x00007fffdccb9e57 in snd_detach_common (worker=0x555557739720) at sound.c:1589
#20 0x00007fffdccb9f0e in snd_detach_playback (sin=0x5555569fe3f8) at sound.c:1602
#21 0x00007fffdcca3373 in spice_server_remove_interface (sin=0x5555569fe3f8) at reds.c:3387
#22 0x00005555558ff6e2 in line_out_fini (hw=0x5555569fe370) at audio/spiceaudio.c:152
#23 0x00005555558f909e in audio_atexit () at audio/audio.c:1754
#24 0x00007fffdb1941e8 in __run_exit_handlers (status=0, listp=0x7fffdb5175d8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true) at exit.c:82
#25 0x00007fffdb194235 in __GI_exit (status=<optimized out>) at exit.c:104
#26 0x00007fffdb17b738 in __libc_start_main (main=0x5555558d7874 <main>, argc=67, argv=0x7fffffffcf48, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffcf38) at ../csu/libc-start.c:323
Add a monitor_cleanup() functions to remove all the monitors before
cleaning up the chardev. Note that we are "losing" some events that
used to be sent during atexit().
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20160801112343.29082-2-marcandre.lureau@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-08-01 13:23:42 +02:00
|
|
|
qemu_mutex_lock(&monitor_lock);
|
2018-12-05 21:37:36 +01:00
|
|
|
monitor_destroyed = true;
|
2018-12-28 14:40:41 +01:00
|
|
|
while (!QTAILQ_EMPTY(&mon_list)) {
|
|
|
|
Monitor *mon = QTAILQ_FIRST(&mon_list);
|
2018-03-09 09:59:51 +01:00
|
|
|
QTAILQ_REMOVE(&mon_list, mon, entry);
|
monitor: avoid potential dead-lock when cleaning up
When a monitor is connected to a Spice chardev, the monitor cleanup
can dead-lock:
#0 0x00007f43446637fd in __lll_lock_wait () at /lib64/libpthread.so.0
#1 0x00007f434465ccf4 in pthread_mutex_lock () at /lib64/libpthread.so.0
#2 0x0000556dd79f22ba in qemu_mutex_lock_impl (mutex=0x556dd81c9220 <monitor_lock>, file=0x556dd7ae3648 "/home/elmarco/src/qq/monitor.c", line=645) at /home/elmarco/src/qq/util/qemu-thread-posix.c:66
#3 0x0000556dd7431bd5 in monitor_qapi_event_queue (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x556dd9abc850, errp=0x7fffb7bbddd8) at /home/elmarco/src/qq/monitor.c:645
#4 0x0000556dd79d476b in qapi_event_send_spice_disconnected (server=0x556dd98ee760, client=0x556ddaaa8560, errp=0x556dd82180d0 <error_abort>) at qapi/qapi-events-ui.c:149
#5 0x0000556dd7870fc1 in channel_event (event=3, info=0x556ddad1b590) at /home/elmarco/src/qq/ui/spice-core.c:235
#6 0x00007f434560a6bb in reds_handle_channel_event (reds=<optimized out>, event=3, info=0x556ddad1b590) at reds.c:316
#7 0x00007f43455f393b in main_dispatcher_self_handle_channel_event (info=0x556ddad1b590, event=3, self=0x556dd9a7d8c0) at main-dispatcher.c:197
#8 0x00007f43455f393b in main_dispatcher_channel_event (self=0x556dd9a7d8c0, event=event@entry=3, info=0x556ddad1b590) at main-dispatcher.c:197
#9 0x00007f4345612833 in red_stream_push_channel_event (s=s@entry=0x556ddae2ef40, event=event@entry=3) at red-stream.c:414
#10 0x00007f434561286b in red_stream_free (s=0x556ddae2ef40) at red-stream.c:388
#11 0x00007f43455f9ddc in red_channel_client_finalize (object=0x556dd9bb21a0) at red-channel-client.c:347
#12 0x00007f434b5f9fb9 in g_object_unref () at /lib64/libgobject-2.0.so.0
#13 0x00007f43455fc212 in red_channel_client_push (rcc=0x556dd9bb21a0) at red-channel-client.c:1341
#14 0x0000556dd76081ba in spice_port_set_fe_open (chr=0x556dd9925e20, fe_open=0) at /home/elmarco/src/qq/chardev/spice.c:241
#15 0x0000556dd796d74a in qemu_chr_fe_set_open (be=0x556dd9a37c00, fe_open=0) at /home/elmarco/src/qq/chardev/char-fe.c:340
#16 0x0000556dd796d4d9 in qemu_chr_fe_set_handlers (b=0x556dd9a37c00, fd_can_read=0x0, fd_read=0x0, fd_event=0x0, be_change=0x0, opaque=0x0, context=0x0, set_open=true) at /home/elmarco/src/qq/chardev/char-fe.c:280
#17 0x0000556dd796d359 in qemu_chr_fe_deinit (b=0x556dd9a37c00, del=false) at /home/elmarco/src/qq/chardev/char-fe.c:233
#18 0x0000556dd7432240 in monitor_data_destroy (mon=0x556dd9a37c00) at /home/elmarco/src/qq/monitor.c:786
#19 0x0000556dd743b968 in monitor_cleanup () at /home/elmarco/src/qq/monitor.c:4683
#20 0x0000556dd75ce776 in main (argc=3, argv=0x7fffb7bbe458, envp=0x7fffb7bbe478) at /home/elmarco/src/qq/vl.c:4660
Because spice code tries to emit a "disconnected" signal on the
monitors. Fix this dead-lock by releasing the monitor lock for
flush/destroy.
monitor_lock protects mon_list, monitor_qapi_event_state and
monitor_destroyed. monitor_flush() and monitor_data_destroy() don't
access any of those variables.
monitor_cleanup()'s loop is safe because it uses
QTAILQ_FOREACH_SAFE(), and no further monitor can be added after
calling monitor_cleanup() thanks to monitor_destroyed check in
monitor_list_append().
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20181205203737.9011-8-marcandre.lureau@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-12-05 21:37:37 +01:00
|
|
|
/* Permit QAPI event emission from character frontend release */
|
|
|
|
qemu_mutex_unlock(&monitor_lock);
|
2018-03-09 10:00:02 +01:00
|
|
|
monitor_flush(mon);
|
monitor: fix crash when leaving qemu with spice audio
Since aa5cb7f5e, the chardevs are being cleaned up when leaving
qemu. However, the monitor has still references to them, which may
lead to crashes when running atexit() and trying to send monitor
events:
#0 0x00007fffdb18f6f5 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007fffdb1912fa in __GI_abort () at abort.c:89
#2 0x0000555555c263e7 in error_exit (err=22, msg=0x555555d47980 <__func__.13537> "qemu_mutex_lock") at util/qemu-thread-posix.c:39
#3 0x0000555555c26488 in qemu_mutex_lock (mutex=0x5555567a2420) at util/qemu-thread-posix.c:66
#4 0x00005555558c52db in qemu_chr_fe_write (s=0x5555567a2420, buf=0x55555740dc40 "{\"timestamp\": {\"seconds\": 1470041716, \"microseconds\": 989699}, \"event\": \"SPICE_DISCONNECTED\", \"data\": {\"server\": {\"port\": \"5900\", \"family\": \"ipv4\", \"host\": \"127.0.0.1\"}, \"client\": {\"port\": \"40272\", \"f"..., len=240) at qemu-char.c:280
#5 0x0000555555787cad in monitor_flush_locked (mon=0x5555567bd9e0) at /home/elmarco/src/qemu/monitor.c:311
#6 0x0000555555787e46 in monitor_puts (mon=0x5555567bd9e0, str=0x5555567a44ef "") at /home/elmarco/src/qemu/monitor.c:353
#7 0x00005555557880fe in monitor_json_emitter (mon=0x5555567bd9e0, data=0x5555567c73a0) at /home/elmarco/src/qemu/monitor.c:401
#8 0x00005555557882d2 in monitor_qapi_event_emit (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x5555567c73a0) at /home/elmarco/src/qemu/monitor.c:472
#9 0x000055555578838f in monitor_qapi_event_queue (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x5555567c73a0, errp=0x7fffffffca88) at /home/elmarco/src/qemu/monitor.c:497
#10 0x0000555555c15541 in qapi_event_send_spice_disconnected (server=0x5555571139d0, client=0x5555570d0db0, errp=0x5555566c0428 <error_abort>) at qapi-event.c:1038
#11 0x0000555555b11bc6 in channel_event (event=3, info=0x5555570d6c00) at ui/spice-core.c:248
#12 0x00007fffdcc9983a in adapter_channel_event (event=3, info=0x5555570d6c00) at reds.c:120
#13 0x00007fffdcc99a25 in reds_handle_channel_event (reds=0x5555567a9d60, event=3, info=0x5555570d6c00) at reds.c:324
#14 0x00007fffdcc7d4c4 in main_dispatcher_self_handle_channel_event (self=0x5555567b28b0, event=3, info=0x5555570d6c00) at main-dispatcher.c:175
#15 0x00007fffdcc7d5b1 in main_dispatcher_channel_event (self=0x5555567b28b0, event=3, info=0x5555570d6c00) at main-dispatcher.c:194
#16 0x00007fffdcca7674 in reds_stream_push_channel_event (s=0x5555570d9910, event=3) at reds-stream.c:354
#17 0x00007fffdcca749b in reds_stream_free (s=0x5555570d9910) at reds-stream.c:323
#18 0x00007fffdccb5dad in snd_disconnect_channel (channel=0x5555576a89a0) at sound.c:229
#19 0x00007fffdccb9e57 in snd_detach_common (worker=0x555557739720) at sound.c:1589
#20 0x00007fffdccb9f0e in snd_detach_playback (sin=0x5555569fe3f8) at sound.c:1602
#21 0x00007fffdcca3373 in spice_server_remove_interface (sin=0x5555569fe3f8) at reds.c:3387
#22 0x00005555558ff6e2 in line_out_fini (hw=0x5555569fe370) at audio/spiceaudio.c:152
#23 0x00005555558f909e in audio_atexit () at audio/audio.c:1754
#24 0x00007fffdb1941e8 in __run_exit_handlers (status=0, listp=0x7fffdb5175d8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true) at exit.c:82
#25 0x00007fffdb194235 in __GI_exit (status=<optimized out>) at exit.c:104
#26 0x00007fffdb17b738 in __libc_start_main (main=0x5555558d7874 <main>, argc=67, argv=0x7fffffffcf48, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffcf38) at ../csu/libc-start.c:323
Add a monitor_cleanup() functions to remove all the monitors before
cleaning up the chardev. Note that we are "losing" some events that
used to be sent during atexit().
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20160801112343.29082-2-marcandre.lureau@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-08-01 13:23:42 +02:00
|
|
|
monitor_data_destroy(mon);
|
monitor: avoid potential dead-lock when cleaning up
When a monitor is connected to a Spice chardev, the monitor cleanup
can dead-lock:
#0 0x00007f43446637fd in __lll_lock_wait () at /lib64/libpthread.so.0
#1 0x00007f434465ccf4 in pthread_mutex_lock () at /lib64/libpthread.so.0
#2 0x0000556dd79f22ba in qemu_mutex_lock_impl (mutex=0x556dd81c9220 <monitor_lock>, file=0x556dd7ae3648 "/home/elmarco/src/qq/monitor.c", line=645) at /home/elmarco/src/qq/util/qemu-thread-posix.c:66
#3 0x0000556dd7431bd5 in monitor_qapi_event_queue (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x556dd9abc850, errp=0x7fffb7bbddd8) at /home/elmarco/src/qq/monitor.c:645
#4 0x0000556dd79d476b in qapi_event_send_spice_disconnected (server=0x556dd98ee760, client=0x556ddaaa8560, errp=0x556dd82180d0 <error_abort>) at qapi/qapi-events-ui.c:149
#5 0x0000556dd7870fc1 in channel_event (event=3, info=0x556ddad1b590) at /home/elmarco/src/qq/ui/spice-core.c:235
#6 0x00007f434560a6bb in reds_handle_channel_event (reds=<optimized out>, event=3, info=0x556ddad1b590) at reds.c:316
#7 0x00007f43455f393b in main_dispatcher_self_handle_channel_event (info=0x556ddad1b590, event=3, self=0x556dd9a7d8c0) at main-dispatcher.c:197
#8 0x00007f43455f393b in main_dispatcher_channel_event (self=0x556dd9a7d8c0, event=event@entry=3, info=0x556ddad1b590) at main-dispatcher.c:197
#9 0x00007f4345612833 in red_stream_push_channel_event (s=s@entry=0x556ddae2ef40, event=event@entry=3) at red-stream.c:414
#10 0x00007f434561286b in red_stream_free (s=0x556ddae2ef40) at red-stream.c:388
#11 0x00007f43455f9ddc in red_channel_client_finalize (object=0x556dd9bb21a0) at red-channel-client.c:347
#12 0x00007f434b5f9fb9 in g_object_unref () at /lib64/libgobject-2.0.so.0
#13 0x00007f43455fc212 in red_channel_client_push (rcc=0x556dd9bb21a0) at red-channel-client.c:1341
#14 0x0000556dd76081ba in spice_port_set_fe_open (chr=0x556dd9925e20, fe_open=0) at /home/elmarco/src/qq/chardev/spice.c:241
#15 0x0000556dd796d74a in qemu_chr_fe_set_open (be=0x556dd9a37c00, fe_open=0) at /home/elmarco/src/qq/chardev/char-fe.c:340
#16 0x0000556dd796d4d9 in qemu_chr_fe_set_handlers (b=0x556dd9a37c00, fd_can_read=0x0, fd_read=0x0, fd_event=0x0, be_change=0x0, opaque=0x0, context=0x0, set_open=true) at /home/elmarco/src/qq/chardev/char-fe.c:280
#17 0x0000556dd796d359 in qemu_chr_fe_deinit (b=0x556dd9a37c00, del=false) at /home/elmarco/src/qq/chardev/char-fe.c:233
#18 0x0000556dd7432240 in monitor_data_destroy (mon=0x556dd9a37c00) at /home/elmarco/src/qq/monitor.c:786
#19 0x0000556dd743b968 in monitor_cleanup () at /home/elmarco/src/qq/monitor.c:4683
#20 0x0000556dd75ce776 in main (argc=3, argv=0x7fffb7bbe458, envp=0x7fffb7bbe478) at /home/elmarco/src/qq/vl.c:4660
Because spice code tries to emit a "disconnected" signal on the
monitors. Fix this dead-lock by releasing the monitor lock for
flush/destroy.
monitor_lock protects mon_list, monitor_qapi_event_state and
monitor_destroyed. monitor_flush() and monitor_data_destroy() don't
access any of those variables.
monitor_cleanup()'s loop is safe because it uses
QTAILQ_FOREACH_SAFE(), and no further monitor can be added after
calling monitor_cleanup() thanks to monitor_destroyed check in
monitor_list_append().
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20181205203737.9011-8-marcandre.lureau@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-12-05 21:37:37 +01:00
|
|
|
qemu_mutex_lock(&monitor_lock);
|
monitor: fix crash when leaving qemu with spice audio
Since aa5cb7f5e, the chardevs are being cleaned up when leaving
qemu. However, the monitor has still references to them, which may
lead to crashes when running atexit() and trying to send monitor
events:
#0 0x00007fffdb18f6f5 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007fffdb1912fa in __GI_abort () at abort.c:89
#2 0x0000555555c263e7 in error_exit (err=22, msg=0x555555d47980 <__func__.13537> "qemu_mutex_lock") at util/qemu-thread-posix.c:39
#3 0x0000555555c26488 in qemu_mutex_lock (mutex=0x5555567a2420) at util/qemu-thread-posix.c:66
#4 0x00005555558c52db in qemu_chr_fe_write (s=0x5555567a2420, buf=0x55555740dc40 "{\"timestamp\": {\"seconds\": 1470041716, \"microseconds\": 989699}, \"event\": \"SPICE_DISCONNECTED\", \"data\": {\"server\": {\"port\": \"5900\", \"family\": \"ipv4\", \"host\": \"127.0.0.1\"}, \"client\": {\"port\": \"40272\", \"f"..., len=240) at qemu-char.c:280
#5 0x0000555555787cad in monitor_flush_locked (mon=0x5555567bd9e0) at /home/elmarco/src/qemu/monitor.c:311
#6 0x0000555555787e46 in monitor_puts (mon=0x5555567bd9e0, str=0x5555567a44ef "") at /home/elmarco/src/qemu/monitor.c:353
#7 0x00005555557880fe in monitor_json_emitter (mon=0x5555567bd9e0, data=0x5555567c73a0) at /home/elmarco/src/qemu/monitor.c:401
#8 0x00005555557882d2 in monitor_qapi_event_emit (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x5555567c73a0) at /home/elmarco/src/qemu/monitor.c:472
#9 0x000055555578838f in monitor_qapi_event_queue (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x5555567c73a0, errp=0x7fffffffca88) at /home/elmarco/src/qemu/monitor.c:497
#10 0x0000555555c15541 in qapi_event_send_spice_disconnected (server=0x5555571139d0, client=0x5555570d0db0, errp=0x5555566c0428 <error_abort>) at qapi-event.c:1038
#11 0x0000555555b11bc6 in channel_event (event=3, info=0x5555570d6c00) at ui/spice-core.c:248
#12 0x00007fffdcc9983a in adapter_channel_event (event=3, info=0x5555570d6c00) at reds.c:120
#13 0x00007fffdcc99a25 in reds_handle_channel_event (reds=0x5555567a9d60, event=3, info=0x5555570d6c00) at reds.c:324
#14 0x00007fffdcc7d4c4 in main_dispatcher_self_handle_channel_event (self=0x5555567b28b0, event=3, info=0x5555570d6c00) at main-dispatcher.c:175
#15 0x00007fffdcc7d5b1 in main_dispatcher_channel_event (self=0x5555567b28b0, event=3, info=0x5555570d6c00) at main-dispatcher.c:194
#16 0x00007fffdcca7674 in reds_stream_push_channel_event (s=0x5555570d9910, event=3) at reds-stream.c:354
#17 0x00007fffdcca749b in reds_stream_free (s=0x5555570d9910) at reds-stream.c:323
#18 0x00007fffdccb5dad in snd_disconnect_channel (channel=0x5555576a89a0) at sound.c:229
#19 0x00007fffdccb9e57 in snd_detach_common (worker=0x555557739720) at sound.c:1589
#20 0x00007fffdccb9f0e in snd_detach_playback (sin=0x5555569fe3f8) at sound.c:1602
#21 0x00007fffdcca3373 in spice_server_remove_interface (sin=0x5555569fe3f8) at reds.c:3387
#22 0x00005555558ff6e2 in line_out_fini (hw=0x5555569fe370) at audio/spiceaudio.c:152
#23 0x00005555558f909e in audio_atexit () at audio/audio.c:1754
#24 0x00007fffdb1941e8 in __run_exit_handlers (status=0, listp=0x7fffdb5175d8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true) at exit.c:82
#25 0x00007fffdb194235 in __GI_exit (status=<optimized out>) at exit.c:104
#26 0x00007fffdb17b738 in __libc_start_main (main=0x5555558d7874 <main>, argc=67, argv=0x7fffffffcf48, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffcf38) at ../csu/libc-start.c:323
Add a monitor_cleanup() functions to remove all the monitors before
cleaning up the chardev. Note that we are "losing" some events that
used to be sent during atexit().
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20160801112343.29082-2-marcandre.lureau@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-08-01 13:23:42 +02:00
|
|
|
g_free(mon);
|
|
|
|
}
|
|
|
|
qemu_mutex_unlock(&monitor_lock);
|
2018-03-09 09:59:52 +01:00
|
|
|
|
2018-07-03 10:53:28 +02:00
|
|
|
/* QEMUBHs needs to be deleted before destroying the I/O thread */
|
2018-07-03 10:53:46 +02:00
|
|
|
qemu_bh_delete(qmp_dispatcher_bh);
|
|
|
|
qmp_dispatcher_bh = NULL;
|
2018-09-25 10:15:07 +02:00
|
|
|
if (mon_iothread) {
|
|
|
|
iothread_destroy(mon_iothread);
|
|
|
|
mon_iothread = NULL;
|
|
|
|
}
|
monitor: fix crash when leaving qemu with spice audio
Since aa5cb7f5e, the chardevs are being cleaned up when leaving
qemu. However, the monitor has still references to them, which may
lead to crashes when running atexit() and trying to send monitor
events:
#0 0x00007fffdb18f6f5 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007fffdb1912fa in __GI_abort () at abort.c:89
#2 0x0000555555c263e7 in error_exit (err=22, msg=0x555555d47980 <__func__.13537> "qemu_mutex_lock") at util/qemu-thread-posix.c:39
#3 0x0000555555c26488 in qemu_mutex_lock (mutex=0x5555567a2420) at util/qemu-thread-posix.c:66
#4 0x00005555558c52db in qemu_chr_fe_write (s=0x5555567a2420, buf=0x55555740dc40 "{\"timestamp\": {\"seconds\": 1470041716, \"microseconds\": 989699}, \"event\": \"SPICE_DISCONNECTED\", \"data\": {\"server\": {\"port\": \"5900\", \"family\": \"ipv4\", \"host\": \"127.0.0.1\"}, \"client\": {\"port\": \"40272\", \"f"..., len=240) at qemu-char.c:280
#5 0x0000555555787cad in monitor_flush_locked (mon=0x5555567bd9e0) at /home/elmarco/src/qemu/monitor.c:311
#6 0x0000555555787e46 in monitor_puts (mon=0x5555567bd9e0, str=0x5555567a44ef "") at /home/elmarco/src/qemu/monitor.c:353
#7 0x00005555557880fe in monitor_json_emitter (mon=0x5555567bd9e0, data=0x5555567c73a0) at /home/elmarco/src/qemu/monitor.c:401
#8 0x00005555557882d2 in monitor_qapi_event_emit (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x5555567c73a0) at /home/elmarco/src/qemu/monitor.c:472
#9 0x000055555578838f in monitor_qapi_event_queue (event=QAPI_EVENT_SPICE_DISCONNECTED, qdict=0x5555567c73a0, errp=0x7fffffffca88) at /home/elmarco/src/qemu/monitor.c:497
#10 0x0000555555c15541 in qapi_event_send_spice_disconnected (server=0x5555571139d0, client=0x5555570d0db0, errp=0x5555566c0428 <error_abort>) at qapi-event.c:1038
#11 0x0000555555b11bc6 in channel_event (event=3, info=0x5555570d6c00) at ui/spice-core.c:248
#12 0x00007fffdcc9983a in adapter_channel_event (event=3, info=0x5555570d6c00) at reds.c:120
#13 0x00007fffdcc99a25 in reds_handle_channel_event (reds=0x5555567a9d60, event=3, info=0x5555570d6c00) at reds.c:324
#14 0x00007fffdcc7d4c4 in main_dispatcher_self_handle_channel_event (self=0x5555567b28b0, event=3, info=0x5555570d6c00) at main-dispatcher.c:175
#15 0x00007fffdcc7d5b1 in main_dispatcher_channel_event (self=0x5555567b28b0, event=3, info=0x5555570d6c00) at main-dispatcher.c:194
#16 0x00007fffdcca7674 in reds_stream_push_channel_event (s=0x5555570d9910, event=3) at reds-stream.c:354
#17 0x00007fffdcca749b in reds_stream_free (s=0x5555570d9910) at reds-stream.c:323
#18 0x00007fffdccb5dad in snd_disconnect_channel (channel=0x5555576a89a0) at sound.c:229
#19 0x00007fffdccb9e57 in snd_detach_common (worker=0x555557739720) at sound.c:1589
#20 0x00007fffdccb9f0e in snd_detach_playback (sin=0x5555569fe3f8) at sound.c:1602
#21 0x00007fffdcca3373 in spice_server_remove_interface (sin=0x5555569fe3f8) at reds.c:3387
#22 0x00005555558ff6e2 in line_out_fini (hw=0x5555569fe370) at audio/spiceaudio.c:152
#23 0x00005555558f909e in audio_atexit () at audio/audio.c:1754
#24 0x00007fffdb1941e8 in __run_exit_handlers (status=0, listp=0x7fffdb5175d8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true) at exit.c:82
#25 0x00007fffdb194235 in __GI_exit (status=<optimized out>) at exit.c:104
#26 0x00007fffdb17b738 in __libc_start_main (main=0x5555558d7874 <main>, argc=67, argv=0x7fffffffcf48, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffcf38) at ../csu/libc-start.c:323
Add a monitor_cleanup() functions to remove all the monitors before
cleaning up the chardev. Note that we are "losing" some events that
used to be sent during atexit().
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20160801112343.29082-2-marcandre.lureau@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-08-01 13:23:42 +02:00
|
|
|
}
|
|
|
|
|
2012-11-26 16:03:42 +01:00
|
|
|
QemuOptsList qemu_mon_opts = {
|
|
|
|
.name = "mon",
|
|
|
|
.implied_opt_name = "chardev",
|
|
|
|
.head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
|
|
|
|
.desc = {
|
|
|
|
{
|
|
|
|
.name = "mode",
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
},{
|
|
|
|
.name = "chardev",
|
|
|
|
.type = QEMU_OPT_STRING,
|
|
|
|
},{
|
|
|
|
.name = "pretty",
|
|
|
|
.type = QEMU_OPT_BOOL,
|
|
|
|
},
|
|
|
|
{ /* end of list */ }
|
|
|
|
},
|
|
|
|
};
|
2014-06-24 23:55:11 +02:00
|
|
|
|
2016-06-10 02:59:06 +02:00
|
|
|
HotpluggableCPUList *qmp_query_hotpluggable_cpus(Error **errp)
|
|
|
|
{
|
|
|
|
MachineState *ms = MACHINE(qdev_get_machine());
|
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
|
|
|
|
2017-02-10 11:20:57 +01:00
|
|
|
if (!mc->has_hotpluggable_cpus) {
|
2016-06-10 02:59:06 +02:00
|
|
|
error_setg(errp, QERR_FEATURE_DISABLED, "query-hotpluggable-cpus");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-02-10 11:20:57 +01:00
|
|
|
return machine_query_hotpluggable_cpus(ms);
|
2016-06-10 02:59:06 +02:00
|
|
|
}
|