When listening for a subset of monitor events, it can be tedious
to register for each event name in series; nicer is to register
for multiple events in one go. Implement a flag to use regex
interpretation of the event filter.
While at it, prove how much I hate the shift key, by adding a
way to filter for 'shutdown' instead of 'SHUTDOWN'. :)
* include/libvirt/libvirt-qemu.h
(virConnectDomainQemuMonitorEventRegisterFlags): New enum.
* src/libvirt-qemu.c (virConnectDomainQemuMonitorEventRegister):
Document flags.
* tools/virsh-domain.c (cmdQemuMonitorEvent): Expose them.
* tools/virsh.pod (qemu-monitor-event): Document this.
* src/conf/domain_event.c
(virDomainQemuMonitorEventStateRegisterID): Add flags.
(virDomainQemuMonitorEventFilter): Handle regex, and optimize
client side.
(virDomainQemuMonitorEventCleanup): Clean up regex.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
include/libvirt/libvirt-qemu.h | 10 ++++++++++
src/conf/domain_event.c | 45 +++++++++++++++++++++++++++++++++++++-----
src/libvirt-qemu.c | 11 +++++++----
tools/virsh-domain.c | 13 ++++++++++++
tools/virsh.pod | 5 ++++-
5 files changed, 74 insertions(+), 10 deletions(-)
diff --git a/include/libvirt/libvirt-qemu.h b/include/libvirt/libvirt-qemu.h
index ed6d3d2..0c5d650 100644
--- a/include/libvirt/libvirt-qemu.h
+++ b/include/libvirt/libvirt-qemu.h
@@ -76,6 +76,16 @@ typedef void (*virConnectDomainQemuMonitorEventCallback)(virConnectPtr
conn,
const char *details,
void *opaque);
+
+typedef enum {
+ /* Event filter is a regex rather than a literal string */
+ VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX = (1 << 0),
+
+ /* Event filter is case insensitive */
+ VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE = (1 << 1),
+} virConnectDomainQemuMonitorEventRegisterFlags;
+
+
int virConnectDomainQemuMonitorEventRegister(virConnectPtr conn,
virDomainPtr dom,
const char *event,
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index a2880fd..ac41d2b 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -24,6 +24,8 @@
#include <config.h>
+#include <regex.h>
+
#include "domain_event.h"
#include "object_event.h"
#include "object_event_private.h"
@@ -1389,6 +1391,8 @@ error:
* deregisters. */
struct virDomainQemuMonitorEventData {
char *event;
+ regex_t regex;
+ unsigned int flags;
void *opaque;
virFreeCallback freecb;
};
@@ -1608,6 +1612,12 @@ virDomainQemuMonitorEventFilter(virConnectPtr conn
ATTRIBUTE_UNUSED,
monitorEvent = (virDomainQemuMonitorEventPtr) event;
+ if (data->flags == -1)
+ return true;
+ if (data->flags & VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX)
+ return regexec(&data->regex, monitorEvent->event, 0, NULL, 0) == 0;
+ if (data->flags & VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE)
+ return STRCASEEQ(monitorEvent->event, data->event);
return STREQ(monitorEvent->event, data->event);
}
@@ -1618,6 +1628,8 @@ virDomainQemuMonitorEventCleanup(void *opaque)
virDomainQemuMonitorEventData *data = opaque;
VIR_FREE(data->event);
+ if (data->flags & VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX)
+ regfree(&data->regex);
if (data->freecb)
(data->freecb)(data->opaque);
VIR_FREE(data);
@@ -1633,7 +1645,8 @@ virDomainQemuMonitorEventCleanup(void *opaque)
* @cb: function to invoke when event occurs
* @opaque: data blob to pass to callback
* @freecb: callback to free @opaque
- * @flags: -1 for client, or set of registration flags on server
+ * @flags: -1 for client, valid virConnectDomainQemuMonitorEventRegisterFlags
+ * for server
* @callbackID: filled with callback ID
*
* Register the function @cb with connection @conn, from @state, for
@@ -1659,12 +1672,34 @@ virDomainQemuMonitorEventStateRegisterID(virConnectPtr conn,
return -1;
if (flags != -1)
- virCheckFlags(0, -1);
+ virCheckFlags(VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX |
+ VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE,
+ -1);
if (VIR_ALLOC(data) < 0)
return -1;
- if (VIR_STRDUP(data->event, event) < 0) {
- VIR_FREE(data);
- return -1;
+ data->flags = flags;
+ if (flags != -1) {
+ int rflags = REG_NOSUB;
+
+ if (flags & VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE)
+ rflags |= REG_ICASE;
+ if (flags & VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX) {
+ int err = regcomp(&data->regex, event, rflags);
+
+ if (err) {
+ char error[100];
+ regerror(err, &data->regex, error, sizeof(error));
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("failed to compile regex '%s': %s"),
+ event, error);
+ regfree(&data->regex);
+ VIR_FREE(data);
+ return -1;
+ }
+ } else if (VIR_STRDUP(data->event, event) < 0) {
+ VIR_FREE(data);
+ return -1;
+ }
}
data->opaque = opaque;
data->freecb = freecb;
diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c
index e5c6311..0876d52 100644
--- a/src/libvirt-qemu.c
+++ b/src/libvirt-qemu.c
@@ -225,7 +225,7 @@ error:
* @cb: callback to the function handling monitor events
* @opaque: opaque data to pass on to the callback
* @freecb: optional function to deallocate opaque when not used anymore
- * @flags: extra flags; not used yet, so callers should always pass 0
+ * @flags: bitwise-OR of virConnectDomainQemuMonitorEventRegisterFlags
*
* This API is QEMU specific, so it will only work with hypervisor
* connections to the QEMU driver.
@@ -240,9 +240,12 @@ error:
* is non-NULL, then only the specific domain will be monitored.
*
* If @event is NULL, then all monitor events will be reported. If @event is
- * non-NULL, then only the specific monitor event will be reported. @flags
- * is currently unused, but in the future may support a flag for passing
- * @event as a glob instead of a literal name to match a category of events.
+ * non-NULL, then only specific monitor events will be reported. @flags
+ * controls how the filtering is performed: 0 requests an exact match, while
+ * VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX states that @event
+ * is a basic regular expression. Additionally, including
+ * VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE lets @event match
+ * case-insensitively.
*
* The virDomainPtr object handle passed into the callback upon delivery
* of an event is only valid for the duration of execution of the callback.
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index a5808d8..3287e2e 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -7979,6 +7979,14 @@ static const vshCmdOptDef opts_qemu_monitor_event[] = {
.type = VSH_OT_INT,
.help = N_("timeout seconds")
},
+ {.name = "regex",
+ .type = VSH_OT_BOOL,
+ .help = N_("treat event as a regex rather than literal filter")
+ },
+ {.name = "no-case",
+ .type = VSH_OT_BOOL,
+ .help = N_("treat event case-insensitively")
+ },
{.name = NULL}
};
@@ -7993,6 +8001,11 @@ cmdQemuMonitorEvent(vshControl *ctl, const vshCmd *cmd)
const char *event = NULL;
vshQemuEventData data;
+ if (vshCommandOptBool(cmd, "regex"))
+ flags |= VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX;
+ if (vshCommandOptBool(cmd, "no-case"))
+ flags |= VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE;
+
data.ctl = ctl;
data.loop = vshCommandOptBool(cmd, "loop");
data.pretty = vshCommandOptBool(cmd, "pretty");
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 35acd96..72eff77 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -3370,12 +3370,15 @@ failed. And when I<--block> is given, the command waits
forever with blocking
timeout.
=item B<qemu-monitor-event> [I<domain>] [I<--event>
I<event-name>] [I<--loop>]
-[I<--timeout> I<seconds>] [I<--pretty>]
+[I<--timeout> I<seconds>] [I<--pretty>] [I<--regex>]
[I<--no-case>]
Wait for arbitrary QEMU monitor events to occur, and print out the
details of events as they happen. The events can optionally be filtered
by I<domain> or I<event-name>. The 'query-events' QMP command can
be
used via I<qemu-monitor-command> to learn what events are supported.
+If I<--regex> is used, I<event-name> is a basic regular expression
+instead of a literal string. If I<--no-case> is used, I<event-name>
+will match case-insensitively.
By default, this command is one-shot, and returns success once an event
occurs; you can send SIGINT (usually via C<Ctrl-C>) to quit immediately.
--
1.8.5.3