diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1fd3afdd6f..0d9adb0758 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -354,6 +354,7 @@
@SRCDIR@tools/virsh-checkpoint.c
@SRCDIR@tools/virsh-completer-host.c
@SRCDIR@tools/virsh-console.c
+@SRCDIR@tools/virsh-domain-event.c
@SRCDIR@tools/virsh-domain-monitor.c
@SRCDIR@tools/virsh-domain.c
@SRCDIR@tools/virsh-edit.c
diff --git a/tools/meson.build b/tools/meson.build
index f4b4a16c29..ac714e6425 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -174,6 +174,7 @@ executable(
'virsh-completer-volume.c',
'virsh-console.c',
'virsh-domain.c',
+ 'virsh-domain-event.c',
'virsh-domain-monitor.c',
'virsh-host.c',
'virsh-interface.c',
diff --git a/tools/virsh-completer-domain.c b/tools/virsh-completer-domain.c
index 321c47ef65..250dd8b21a 100644
--- a/tools/virsh-completer-domain.c
+++ b/tools/virsh-completer-domain.c
@@ -357,25 +357,6 @@ virshDomainBlockjobBaseTopCompleter(vshControl *ctl,
return ret;
}
-char **
-virshDomainEventNameCompleter(vshControl *ctl G_GNUC_UNUSED,
- const vshCmd *cmd G_GNUC_UNUSED,
- unsigned int flags)
-{
- size_t i = 0;
- g_auto(GStrv) tmp = NULL;
-
- virCheckFlags(0, NULL);
-
- tmp = g_new0(char *, VIR_DOMAIN_EVENT_ID_LAST + 1);
-
- for (i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i++)
- tmp[i] = g_strdup(virshDomainEventCallbacks[i].name);
-
- return g_steal_pointer(&tmp);
-}
-
-
char **
virshDomainInterfaceStateCompleter(vshControl *ctl,
const vshCmd *cmd,
diff --git a/tools/virsh-completer-domain.h b/tools/virsh-completer-domain.h
index 044c675842..27cf963912 100644
--- a/tools/virsh-completer-domain.h
+++ b/tools/virsh-completer-domain.h
@@ -41,11 +41,6 @@ virshDomainDiskTargetCompleter(vshControl *ctl,
const vshCmd *cmd,
unsigned int flags);
-char **
-virshDomainEventNameCompleter(vshControl *ctl,
- const vshCmd *cmd,
- unsigned int flags);
-
char **
virshDomainInterfaceStateCompleter(vshControl *ctl,
const vshCmd *cmd,
diff --git a/tools/virsh-domain-event.c b/tools/virsh-domain-event.c
new file mode 100644
index 0000000000..51571dffad
--- /dev/null
+++ b/tools/virsh-domain-event.c
@@ -0,0 +1,1007 @@
+/*
+ * virsh-domain-event.c: Domain event listening commands
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ */
+
+#include
+#include "virsh-domain-event.h"
+#include "virsh-util.h"
+
+#include "internal.h"
+#include "viralloc.h"
+#include "virenum.h"
+#include "virutil.h"
+#include "virtime.h"
+#include "virtypedparam.h"
+
+/*
+ * "event" command
+ */
+
+VIR_ENUM_DECL(virshDomainEvent);
+VIR_ENUM_IMPL(virshDomainEvent,
+ VIR_DOMAIN_EVENT_LAST,
+ N_("Defined"),
+ N_("Undefined"),
+ N_("Started"),
+ N_("Suspended"),
+ N_("Resumed"),
+ N_("Stopped"),
+ N_("Shutdown"),
+ N_("PMSuspended"),
+ N_("Crashed"));
+
+static const char *
+virshDomainEventToString(int event)
+{
+ const char *str = virshDomainEventTypeToString(event);
+ return str ? _(str) : _("unknown");
+}
+
+VIR_ENUM_DECL(virshDomainEventDefined);
+VIR_ENUM_IMPL(virshDomainEventDefined,
+ VIR_DOMAIN_EVENT_DEFINED_LAST,
+ N_("Added"),
+ N_("Updated"),
+ N_("Renamed"),
+ N_("Snapshot"));
+
+VIR_ENUM_DECL(virshDomainEventUndefined);
+VIR_ENUM_IMPL(virshDomainEventUndefined,
+ VIR_DOMAIN_EVENT_UNDEFINED_LAST,
+ N_("Removed"),
+ N_("Renamed"));
+
+VIR_ENUM_DECL(virshDomainEventStarted);
+VIR_ENUM_IMPL(virshDomainEventStarted,
+ VIR_DOMAIN_EVENT_STARTED_LAST,
+ N_("Booted"),
+ N_("Migrated"),
+ N_("Restored"),
+ N_("Snapshot"),
+ N_("Event wakeup"));
+
+VIR_ENUM_DECL(virshDomainEventSuspended);
+VIR_ENUM_IMPL(virshDomainEventSuspended,
+ VIR_DOMAIN_EVENT_SUSPENDED_LAST,
+ N_("Paused"),
+ N_("Migrated"),
+ N_("I/O Error"),
+ N_("Watchdog"),
+ N_("Restored"),
+ N_("Snapshot"),
+ N_("API error"),
+ N_("Post-copy"),
+ N_("Post-copy Error"));
+
+VIR_ENUM_DECL(virshDomainEventResumed);
+VIR_ENUM_IMPL(virshDomainEventResumed,
+ VIR_DOMAIN_EVENT_RESUMED_LAST,
+ N_("Unpaused"),
+ N_("Migrated"),
+ N_("Snapshot"),
+ N_("Post-copy"));
+
+VIR_ENUM_DECL(virshDomainEventStopped);
+VIR_ENUM_IMPL(virshDomainEventStopped,
+ VIR_DOMAIN_EVENT_STOPPED_LAST,
+ N_("Shutdown"),
+ N_("Destroyed"),
+ N_("Crashed"),
+ N_("Migrated"),
+ N_("Saved"),
+ N_("Failed"),
+ N_("Snapshot"));
+
+VIR_ENUM_DECL(virshDomainEventShutdown);
+VIR_ENUM_IMPL(virshDomainEventShutdown,
+ VIR_DOMAIN_EVENT_SHUTDOWN_LAST,
+ N_("Finished"),
+ N_("Finished after guest request"),
+ N_("Finished after host request"));
+
+VIR_ENUM_DECL(virshDomainEventPMSuspended);
+VIR_ENUM_IMPL(virshDomainEventPMSuspended,
+ VIR_DOMAIN_EVENT_PMSUSPENDED_LAST,
+ N_("Memory"),
+ N_("Disk"));
+
+VIR_ENUM_DECL(virshDomainEventCrashed);
+VIR_ENUM_IMPL(virshDomainEventCrashed,
+ VIR_DOMAIN_EVENT_CRASHED_LAST,
+ N_("Panicked"),
+ N_("Crashloaded"));
+
+static const char *
+virshDomainEventDetailToString(int event, int detail)
+{
+ const char *str = NULL;
+ switch ((virDomainEventType) event) {
+ case VIR_DOMAIN_EVENT_DEFINED:
+ str = virshDomainEventDefinedTypeToString(detail);
+ break;
+ case VIR_DOMAIN_EVENT_UNDEFINED:
+ str = virshDomainEventUndefinedTypeToString(detail);
+ break;
+ case VIR_DOMAIN_EVENT_STARTED:
+ str = virshDomainEventStartedTypeToString(detail);
+ break;
+ case VIR_DOMAIN_EVENT_SUSPENDED:
+ str = virshDomainEventSuspendedTypeToString(detail);
+ break;
+ case VIR_DOMAIN_EVENT_RESUMED:
+ str = virshDomainEventResumedTypeToString(detail);
+ break;
+ case VIR_DOMAIN_EVENT_STOPPED:
+ str = virshDomainEventStoppedTypeToString(detail);
+ break;
+ case VIR_DOMAIN_EVENT_SHUTDOWN:
+ str = virshDomainEventShutdownTypeToString(detail);
+ break;
+ case VIR_DOMAIN_EVENT_PMSUSPENDED:
+ str = virshDomainEventPMSuspendedTypeToString(detail);
+ break;
+ case VIR_DOMAIN_EVENT_CRASHED:
+ str = virshDomainEventCrashedTypeToString(detail);
+ break;
+ case VIR_DOMAIN_EVENT_LAST:
+ break;
+ }
+ return str ? _(str) : _("unknown");
+}
+
+VIR_ENUM_DECL(virshDomainEventWatchdog);
+VIR_ENUM_IMPL(virshDomainEventWatchdog,
+ VIR_DOMAIN_EVENT_WATCHDOG_LAST,
+ N_("none"),
+ N_("pause"),
+ N_("reset"),
+ N_("poweroff"),
+ N_("shutdown"),
+ N_("debug"),
+ N_("inject-nmi"));
+
+static const char *
+virshDomainEventWatchdogToString(int action)
+{
+ const char *str = virshDomainEventWatchdogTypeToString(action);
+ return str ? _(str) : _("unknown");
+}
+
+VIR_ENUM_DECL(virshDomainEventIOError);
+VIR_ENUM_IMPL(virshDomainEventIOError,
+ VIR_DOMAIN_EVENT_IO_ERROR_LAST,
+ N_("none"),
+ N_("pause"),
+ N_("report"));
+
+static const char *
+virshDomainEventIOErrorToString(int action)
+{
+ const char *str = virshDomainEventIOErrorTypeToString(action);
+ return str ? _(str) : _("unknown");
+}
+
+VIR_ENUM_DECL(virshGraphicsPhase);
+VIR_ENUM_IMPL(virshGraphicsPhase,
+ VIR_DOMAIN_EVENT_GRAPHICS_LAST,
+ N_("connect"),
+ N_("initialize"),
+ N_("disconnect"));
+
+static const char *
+virshGraphicsPhaseToString(int phase)
+{
+ const char *str = virshGraphicsPhaseTypeToString(phase);
+ return str ? _(str) : _("unknown");
+}
+
+VIR_ENUM_DECL(virshGraphicsAddress);
+VIR_ENUM_IMPL(virshGraphicsAddress,
+ VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_LAST,
+ N_("IPv4"),
+ N_("IPv6"),
+ N_("unix"));
+
+static const char *
+virshGraphicsAddressToString(int family)
+{
+ const char *str = virshGraphicsAddressTypeToString(family);
+ return str ? _(str) : _("unknown");
+}
+
+VIR_ENUM_DECL(virshDomainBlockJobStatus);
+VIR_ENUM_IMPL(virshDomainBlockJobStatus,
+ VIR_DOMAIN_BLOCK_JOB_LAST,
+ N_("completed"),
+ N_("failed"),
+ N_("canceled"),
+ N_("ready"));
+
+static const char *
+virshDomainBlockJobStatusToString(int status)
+{
+ const char *str = virshDomainBlockJobStatusTypeToString(status);
+ return str ? _(str) : _("unknown");
+}
+
+VIR_ENUM_DECL(virshDomainEventDiskChange);
+VIR_ENUM_IMPL(virshDomainEventDiskChange,
+ VIR_DOMAIN_EVENT_DISK_CHANGE_LAST,
+ N_("changed"),
+ N_("dropped"));
+
+static const char *
+virshDomainEventDiskChangeToString(int reason)
+{
+ const char *str = virshDomainEventDiskChangeTypeToString(reason);
+ return str ? _(str) : _("unknown");
+}
+
+VIR_ENUM_DECL(virshDomainEventTrayChange);
+VIR_ENUM_IMPL(virshDomainEventTrayChange,
+ VIR_DOMAIN_EVENT_TRAY_CHANGE_LAST,
+ N_("opened"),
+ N_("closed"));
+
+static const char *
+virshDomainEventTrayChangeToString(int reason)
+{
+ const char *str = virshDomainEventTrayChangeTypeToString(reason);
+ return str ? _(str) : _("unknown");
+}
+
+
+struct virshDomainEventCallback {
+ const char *name;
+ virConnectDomainEventGenericCallback cb;
+};
+typedef struct virshDomainEventCallback virshDomainEventCallback;
+
+
+struct virshDomEventData {
+ vshControl *ctl;
+ bool loop;
+ int *count;
+ bool timestamp;
+ virshDomainEventCallback *cb;
+ int id;
+};
+typedef struct virshDomEventData virshDomEventData;
+
+/**
+ * virshEventPrint:
+ *
+ * @data: opaque data passed to all event callbacks
+ * @buf: string buffer describing the event
+ *
+ * Print the event description found in @buf and update virshDomEventData.
+ *
+ * This function resets @buf and frees all memory consumed by its content.
+ */
+static void
+virshEventPrint(virshDomEventData *data,
+ virBuffer *buf)
+{
+ g_autofree char *msg = NULL;
+
+ if (!(msg = virBufferContentAndReset(buf)))
+ return;
+
+ if (!data->loop && *data->count)
+ return;
+
+ if (data->timestamp) {
+ char timestamp[VIR_TIME_STRING_BUFLEN];
+
+ if (virTimeStringNowRaw(timestamp) < 0)
+ timestamp[0] = '\0';
+
+ vshPrint(data->ctl, "%s: %s", timestamp, msg);
+ } else {
+ vshPrint(data->ctl, "%s", msg);
+ }
+
+ (*data->count)++;
+ if (!data->loop)
+ vshEventDone(data->ctl);
+}
+
+static void
+virshEventGenericPrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event '%s' for domain '%s'\n"),
+ ((virshDomEventData *) opaque)->cb->name,
+ virDomainGetName(dom));
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventLifecyclePrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ int event,
+ int detail,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'lifecycle' for domain '%s': %s %s\n"),
+ virDomainGetName(dom),
+ virshDomainEventToString(event),
+ virshDomainEventDetailToString(event, detail));
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventRTCChangePrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ long long utcoffset,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'rtc-change' for domain '%s': %lld\n"),
+ virDomainGetName(dom),
+ utcoffset);
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventWatchdogPrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ int action,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'watchdog' for domain '%s': %s\n"),
+ virDomainGetName(dom),
+ virshDomainEventWatchdogToString(action));
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventIOErrorPrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ const char *srcPath,
+ const char *devAlias,
+ int action,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'io-error' for domain '%s': %s (%s) %s\n"),
+ virDomainGetName(dom),
+ srcPath,
+ devAlias,
+ virshDomainEventIOErrorToString(action));
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventGraphicsPrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ int phase,
+ const virDomainEventGraphicsAddress *local,
+ const virDomainEventGraphicsAddress *remote,
+ const char *authScheme,
+ const virDomainEventGraphicsSubject *subject,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+ size_t i;
+
+ virBufferAsprintf(&buf, _("event 'graphics' for domain '%s': "
+ "%s local[%s %s %s] remote[%s %s %s] %s\n"),
+ virDomainGetName(dom),
+ virshGraphicsPhaseToString(phase),
+ virshGraphicsAddressToString(local->family),
+ local->node,
+ local->service,
+ virshGraphicsAddressToString(remote->family),
+ remote->node,
+ remote->service,
+ authScheme);
+ for (i = 0; i < subject->nidentity; i++) {
+ virBufferAsprintf(&buf, "\t%s=%s\n",
+ subject->identities[i].type,
+ subject->identities[i].name);
+ }
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventIOErrorReasonPrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ const char *srcPath,
+ const char *devAlias,
+ int action,
+ const char *reason,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'io-error-reason' for domain '%s': "
+ "%s (%s) %s due to %s\n"),
+ virDomainGetName(dom),
+ srcPath,
+ devAlias,
+ virshDomainEventIOErrorToString(action),
+ reason);
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventBlockJobPrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ const char *disk,
+ int type,
+ int status,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event '%s' for domain '%s': %s for %s %s\n"),
+ ((virshDomEventData *) opaque)->cb->name,
+ virDomainGetName(dom),
+ virshDomainBlockJobToString(type),
+ disk,
+ virshDomainBlockJobStatusToString(status));
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventDiskChangePrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ const char *oldSrc,
+ const char *newSrc,
+ const char *alias,
+ int reason,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'disk-change' for domain '%s' disk %s: "
+ "%s -> %s: %s\n"),
+ virDomainGetName(dom),
+ alias,
+ NULLSTR(oldSrc),
+ NULLSTR(newSrc),
+ virshDomainEventDiskChangeToString(reason));
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventTrayChangePrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ const char *alias,
+ int reason,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'tray-change' for domain '%s' disk %s: %s\n"),
+ virDomainGetName(dom),
+ alias,
+ virshDomainEventTrayChangeToString(reason));
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventPMChangePrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ int reason G_GNUC_UNUSED,
+ void *opaque)
+{
+ /* As long as libvirt.h doesn't define any reasons, we might as
+ * well treat all PM state changes as generic events. */
+ virshEventGenericPrint(conn, dom, opaque);
+}
+
+static void
+virshEventBalloonChangePrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ unsigned long long actual,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'balloon-change' for domain '%s': %lluKiB\n"),
+ virDomainGetName(dom),
+ actual);
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventDeviceRemovedPrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ const char *alias,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'device-removed' for domain '%s': %s\n"),
+ virDomainGetName(dom),
+ alias);
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventDeviceAddedPrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ const char *alias,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'device-added' for domain '%s': %s\n"),
+ virDomainGetName(dom),
+ alias);
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventTunablePrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ virTypedParameterPtr params,
+ int nparams,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+ size_t i;
+ char *value;
+
+ virBufferAsprintf(&buf, _("event 'tunable' for domain '%s':\n"),
+ virDomainGetName(dom));
+ for (i = 0; i < nparams; i++) {
+ value = virTypedParameterToString(¶ms[i]);
+ if (value) {
+ virBufferAsprintf(&buf, "\t%s: %s\n", params[i].field, value);
+ VIR_FREE(value);
+ }
+ }
+ virshEventPrint(opaque, &buf);
+}
+
+VIR_ENUM_DECL(virshEventAgentLifecycleState);
+VIR_ENUM_IMPL(virshEventAgentLifecycleState,
+ VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_STATE_LAST,
+ N_("unknown"),
+ N_("connected"),
+ N_("disconnected"));
+
+VIR_ENUM_DECL(virshEventAgentLifecycleReason);
+VIR_ENUM_IMPL(virshEventAgentLifecycleReason,
+ VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_LAST,
+ N_("unknown"),
+ N_("domain started"),
+ N_("channel event"));
+
+#define UNKNOWNSTR(str) (str ? str : N_("unsupported value"))
+static void
+virshEventAgentLifecyclePrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ int state,
+ int reason,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'agent-lifecycle' for domain '%s': state: "
+ "'%s' reason: '%s'\n"),
+ virDomainGetName(dom),
+ UNKNOWNSTR(virshEventAgentLifecycleStateTypeToString(state)),
+ UNKNOWNSTR(virshEventAgentLifecycleReasonTypeToString(reason)));
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventMigrationIterationPrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ int iteration,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'migration-iteration' for domain '%s': "
+ "iteration: '%d'\n"),
+ virDomainGetName(dom),
+ iteration);
+
+ virshEventPrint(opaque, &buf);
+}
+
+static void
+virshEventJobCompletedPrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ virTypedParameterPtr params,
+ int nparams,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+ size_t i;
+
+ virBufferAsprintf(&buf, _("event 'job-completed' for domain '%s':\n"),
+ virDomainGetName(dom));
+ for (i = 0; i < nparams; i++) {
+ g_autofree char *value = virTypedParameterToString(¶ms[i]);
+ if (value)
+ virBufferAsprintf(&buf, "\t%s: %s\n", params[i].field, value);
+ }
+ virshEventPrint(opaque, &buf);
+}
+
+
+static void
+virshEventDeviceRemovalFailedPrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ const char *alias,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'device-removal-failed' for domain '%s': %s\n"),
+ virDomainGetName(dom),
+ alias);
+ virshEventPrint(opaque, &buf);
+}
+
+VIR_ENUM_DECL(virshEventMetadataChangeType);
+VIR_ENUM_IMPL(virshEventMetadataChangeType,
+ VIR_DOMAIN_METADATA_LAST,
+ N_("description"),
+ N_("title"),
+ N_("element"));
+
+static void
+virshEventMetadataChangePrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ int type,
+ const char *nsuri,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'metadata-change' for domain '%s': type %s, uri %s\n"),
+ virDomainGetName(dom),
+ UNKNOWNSTR(virshEventMetadataChangeTypeTypeToString(type)),
+ NULLSTR(nsuri));
+ virshEventPrint(opaque, &buf);
+}
+
+
+static void
+virshEventBlockThresholdPrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ const char *dev,
+ const char *path,
+ unsigned long long threshold,
+ unsigned long long excess,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'block-threshold' for domain '%s': "
+ "dev: %s(%s) %llu %llu\n"),
+ virDomainGetName(dom),
+ dev, NULLSTR(path), threshold, excess);
+ virshEventPrint(opaque, &buf);
+}
+
+
+VIR_ENUM_DECL(virshEventMemoryFailureRecipientType);
+VIR_ENUM_IMPL(virshEventMemoryFailureRecipientType,
+ VIR_DOMAIN_EVENT_MEMORY_FAILURE_RECIPIENT_LAST,
+ N_("hypervisor"),
+ N_("guest"));
+
+VIR_ENUM_DECL(virshEventMemoryFailureActionType);
+VIR_ENUM_IMPL(virshEventMemoryFailureActionType,
+ VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_LAST,
+ N_("ignore"),
+ N_("inject"),
+ N_("fatal"),
+ N_("reset"));
+
+static void
+virshEventMemoryFailurePrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ int recipient,
+ int action,
+ unsigned int flags,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'memory-failure' for domain '%s':\n"
+ "recipient: %s\naction: %s\n"),
+ virDomainGetName(dom),
+ UNKNOWNSTR(virshEventMemoryFailureRecipientTypeTypeToString(recipient)),
+ UNKNOWNSTR(virshEventMemoryFailureActionTypeTypeToString(action)));
+ virBufferAsprintf(&buf, _("flags:\n"
+ "\taction required: %d\n\trecursive: %d\n"),
+ !!(flags & VIR_DOMAIN_MEMORY_FAILURE_ACTION_REQUIRED),
+ !!(flags & VIR_DOMAIN_MEMORY_FAILURE_RECURSIVE));
+
+ virshEventPrint(opaque, &buf);
+}
+
+
+static void
+virshEventMemoryDeviceSizeChangePrint(virConnectPtr conn G_GNUC_UNUSED,
+ virDomainPtr dom,
+ const char *alias,
+ unsigned long long size,
+ void *opaque)
+{
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf,
+ _("event 'memory-device-size-change' for domain '%s':\n"
+ "alias: %s\nsize: %llu\n"),
+ virDomainGetName(dom), alias, size);
+
+ virshEventPrint(opaque, &buf);
+}
+
+
+virshDomainEventCallback virshDomainEventCallbacks[] = {
+ { "lifecycle",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventLifecyclePrint), },
+ { "reboot", virshEventGenericPrint, },
+ { "rtc-change",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventRTCChangePrint), },
+ { "watchdog",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventWatchdogPrint), },
+ { "io-error",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventIOErrorPrint), },
+ { "graphics",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventGraphicsPrint), },
+ { "io-error-reason",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventIOErrorReasonPrint), },
+ { "control-error", virshEventGenericPrint, },
+ { "block-job",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockJobPrint), },
+ { "disk-change",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventDiskChangePrint), },
+ { "tray-change",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventTrayChangePrint), },
+ { "pm-wakeup",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventPMChangePrint), },
+ { "pm-suspend",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventPMChangePrint), },
+ { "balloon-change",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventBalloonChangePrint), },
+ { "pm-suspend-disk",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventPMChangePrint), },
+ { "device-removed",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventDeviceRemovedPrint), },
+ { "block-job-2",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockJobPrint), },
+ { "tunable",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventTunablePrint), },
+ { "agent-lifecycle",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventAgentLifecyclePrint), },
+ { "device-added",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventDeviceAddedPrint), },
+ { "migration-iteration",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventMigrationIterationPrint), },
+ { "job-completed",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventJobCompletedPrint), },
+ { "device-removal-failed",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventDeviceRemovalFailedPrint), },
+ { "metadata-change",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventMetadataChangePrint), },
+ { "block-threshold",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockThresholdPrint), },
+ { "memory-failure",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventMemoryFailurePrint), },
+ { "memory-device-size-change",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventMemoryDeviceSizeChangePrint), },
+};
+G_STATIC_ASSERT(VIR_DOMAIN_EVENT_ID_LAST == G_N_ELEMENTS(virshDomainEventCallbacks));
+
+
+static char **
+virshDomainEventNameCompleter(vshControl *ctl G_GNUC_UNUSED,
+ const vshCmd *cmd G_GNUC_UNUSED,
+ unsigned int flags)
+{
+ size_t i = 0;
+ g_auto(GStrv) tmp = NULL;
+
+ virCheckFlags(0, NULL);
+
+ tmp = g_new0(char *, VIR_DOMAIN_EVENT_ID_LAST + 1);
+
+ for (i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i++)
+ tmp[i] = g_strdup(virshDomainEventCallbacks[i].name);
+
+ return g_steal_pointer(&tmp);
+}
+
+
+static const vshCmdInfo info_event[] = {
+ {.name = "help",
+ .data = N_("Domain Events")
+ },
+ {.name = "desc",
+ .data = N_("List event types, or wait for domain events to occur")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_event[] = {
+ VIRSH_COMMON_OPT_DOMAIN_OT_STRING(N_("filter by domain name, id or uuid"),
+ 0, 0),
+ {.name = "event",
+ .type = VSH_OT_STRING,
+ .completer = virshDomainEventNameCompleter,
+ .help = N_("which event type to wait for")
+ },
+ {.name = "all",
+ .type = VSH_OT_BOOL,
+ .help = N_("wait for all events instead of just one type")
+ },
+ {.name = "loop",
+ .type = VSH_OT_BOOL,
+ .help = N_("loop until timeout or interrupt, rather than one-shot")
+ },
+ {.name = "timeout",
+ .type = VSH_OT_INT,
+ .help = N_("timeout seconds")
+ },
+ {.name = "list",
+ .type = VSH_OT_BOOL,
+ .help = N_("list valid event types")
+ },
+ {.name = "timestamp",
+ .type = VSH_OT_BOOL,
+ .help = N_("show timestamp for each printed event")
+ },
+ {.name = NULL}
+};
+
+static bool
+cmdEvent(vshControl *ctl, const vshCmd *cmd)
+{
+ g_autoptr(virshDomain) dom = NULL;
+ bool ret = false;
+ int timeout = 0;
+ virshDomEventData *data = NULL;
+ size_t i;
+ const char *eventName = NULL;
+ int event = -1;
+ bool all = vshCommandOptBool(cmd, "all");
+ bool loop = vshCommandOptBool(cmd, "loop");
+ bool timestamp = vshCommandOptBool(cmd, "timestamp");
+ int count = 0;
+ virshControl *priv = ctl->privData;
+
+ VSH_EXCLUSIVE_OPTIONS("all", "event");
+ VSH_EXCLUSIVE_OPTIONS("list", "all");
+ VSH_EXCLUSIVE_OPTIONS("list", "event");
+
+ if (vshCommandOptBool(cmd, "list")) {
+ for (event = 0; event < VIR_DOMAIN_EVENT_ID_LAST; event++)
+ vshPrint(ctl, "%s\n", virshDomainEventCallbacks[event].name);
+ return true;
+ }
+
+ if (vshCommandOptStringReq(ctl, cmd, "event", &eventName) < 0)
+ return false;
+ if (eventName) {
+ for (event = 0; event < VIR_DOMAIN_EVENT_ID_LAST; event++)
+ if (STREQ(eventName, virshDomainEventCallbacks[event].name))
+ break;
+ if (event == VIR_DOMAIN_EVENT_ID_LAST) {
+ vshError(ctl, _("unknown event type %s"), eventName);
+ return false;
+ }
+ } else if (!all) {
+ vshError(ctl, "%s",
+ _("one of --list, --all, or --event is required"));
+ return false;
+ }
+
+ if (all) {
+ data = g_new0(virshDomEventData, VIR_DOMAIN_EVENT_ID_LAST);
+ for (i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i++) {
+ data[i].ctl = ctl;
+ data[i].loop = loop;
+ data[i].count = &count;
+ data[i].timestamp = timestamp;
+ data[i].cb = &virshDomainEventCallbacks[i];
+ data[i].id = -1;
+ }
+ } else {
+ data = g_new0(virshDomEventData, 1);
+ data[0].ctl = ctl;
+ data[0].loop = vshCommandOptBool(cmd, "loop");
+ data[0].count = &count;
+ data[0].timestamp = timestamp;
+ data[0].cb = &virshDomainEventCallbacks[event];
+ data[0].id = -1;
+ }
+ if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
+ goto cleanup;
+
+ if (vshCommandOptBool(cmd, "domain"))
+ if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+ goto cleanup;
+
+ if (vshEventStart(ctl, timeout) < 0)
+ goto cleanup;
+
+ for (i = 0; i < (all ? VIR_DOMAIN_EVENT_ID_LAST : 1); i++) {
+ if ((data[i].id = virConnectDomainEventRegisterAny(priv->conn, dom,
+ all ? i : event,
+ data[i].cb->cb,
+ &data[i],
+ NULL)) < 0) {
+ /* When registering for all events: if the first
+ * registration succeeds, silently ignore failures on all
+ * later registrations on the assumption that the server
+ * is older and didn't know quite as many events. */
+ if (i)
+ vshResetLibvirtError();
+ else
+ goto cleanup;
+ }
+ }
+ switch (vshEventWait(ctl)) {
+ case VSH_EVENT_INTERRUPT:
+ vshPrint(ctl, "%s", _("event loop interrupted\n"));
+ break;
+ case VSH_EVENT_TIMEOUT:
+ vshPrint(ctl, "%s", _("event loop timed out\n"));
+ break;
+ case VSH_EVENT_DONE:
+ break;
+ default:
+ goto cleanup;
+ }
+ vshPrint(ctl, _("events received: %d\n"), count);
+ if (count)
+ ret = true;
+
+ cleanup:
+ vshEventCleanup(ctl);
+ if (data) {
+ for (i = 0; i < (all ? VIR_DOMAIN_EVENT_ID_LAST : 1); i++) {
+ if (data[i].id >= 0 &&
+ virConnectDomainEventDeregisterAny(priv->conn, data[i].id) < 0)
+ ret = false;
+ }
+ VIR_FREE(data);
+ }
+ return ret;
+}
+
+
+const vshCmdDef domEventCmds[] = {
+ {.name = "event",
+ .handler = cmdEvent,
+ .opts = opts_event,
+ .info = info_event,
+ .flags = 0
+ },
+ {.name = NULL}
+};
diff --git a/tools/virsh-domain-event.h b/tools/virsh-domain-event.h
new file mode 100644
index 0000000000..dd96ef21ac
--- /dev/null
+++ b/tools/virsh-domain-event.h
@@ -0,0 +1,23 @@
+/*
+ * virsh-domain-event.h: Commands for domain events
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ */
+
+#pragma once
+
+#include "virsh.h"
+
+extern const vshCmdDef domEventCmds[];
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 9c304dbf78..dc6e3b5020 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -12887,946 +12887,6 @@ cmdEdit(vshControl *ctl, const vshCmd *cmd)
}
-/*
- * "event" command
- */
-VIR_ENUM_DECL(virshDomainEvent);
-VIR_ENUM_IMPL(virshDomainEvent,
- VIR_DOMAIN_EVENT_LAST,
- N_("Defined"),
- N_("Undefined"),
- N_("Started"),
- N_("Suspended"),
- N_("Resumed"),
- N_("Stopped"),
- N_("Shutdown"),
- N_("PMSuspended"),
- N_("Crashed"));
-
-static const char *
-virshDomainEventToString(int event)
-{
- const char *str = virshDomainEventTypeToString(event);
- return str ? _(str) : _("unknown");
-}
-
-VIR_ENUM_DECL(virshDomainEventDefined);
-VIR_ENUM_IMPL(virshDomainEventDefined,
- VIR_DOMAIN_EVENT_DEFINED_LAST,
- N_("Added"),
- N_("Updated"),
- N_("Renamed"),
- N_("Snapshot"));
-
-VIR_ENUM_DECL(virshDomainEventUndefined);
-VIR_ENUM_IMPL(virshDomainEventUndefined,
- VIR_DOMAIN_EVENT_UNDEFINED_LAST,
- N_("Removed"),
- N_("Renamed"));
-
-VIR_ENUM_DECL(virshDomainEventStarted);
-VIR_ENUM_IMPL(virshDomainEventStarted,
- VIR_DOMAIN_EVENT_STARTED_LAST,
- N_("Booted"),
- N_("Migrated"),
- N_("Restored"),
- N_("Snapshot"),
- N_("Event wakeup"));
-
-VIR_ENUM_DECL(virshDomainEventSuspended);
-VIR_ENUM_IMPL(virshDomainEventSuspended,
- VIR_DOMAIN_EVENT_SUSPENDED_LAST,
- N_("Paused"),
- N_("Migrated"),
- N_("I/O Error"),
- N_("Watchdog"),
- N_("Restored"),
- N_("Snapshot"),
- N_("API error"),
- N_("Post-copy"),
- N_("Post-copy Error"));
-
-VIR_ENUM_DECL(virshDomainEventResumed);
-VIR_ENUM_IMPL(virshDomainEventResumed,
- VIR_DOMAIN_EVENT_RESUMED_LAST,
- N_("Unpaused"),
- N_("Migrated"),
- N_("Snapshot"),
- N_("Post-copy"));
-
-VIR_ENUM_DECL(virshDomainEventStopped);
-VIR_ENUM_IMPL(virshDomainEventStopped,
- VIR_DOMAIN_EVENT_STOPPED_LAST,
- N_("Shutdown"),
- N_("Destroyed"),
- N_("Crashed"),
- N_("Migrated"),
- N_("Saved"),
- N_("Failed"),
- N_("Snapshot"));
-
-VIR_ENUM_DECL(virshDomainEventShutdown);
-VIR_ENUM_IMPL(virshDomainEventShutdown,
- VIR_DOMAIN_EVENT_SHUTDOWN_LAST,
- N_("Finished"),
- N_("Finished after guest request"),
- N_("Finished after host request"));
-
-VIR_ENUM_DECL(virshDomainEventPMSuspended);
-VIR_ENUM_IMPL(virshDomainEventPMSuspended,
- VIR_DOMAIN_EVENT_PMSUSPENDED_LAST,
- N_("Memory"),
- N_("Disk"));
-
-VIR_ENUM_DECL(virshDomainEventCrashed);
-VIR_ENUM_IMPL(virshDomainEventCrashed,
- VIR_DOMAIN_EVENT_CRASHED_LAST,
- N_("Panicked"),
- N_("Crashloaded"));
-
-static const char *
-virshDomainEventDetailToString(int event, int detail)
-{
- const char *str = NULL;
- switch ((virDomainEventType) event) {
- case VIR_DOMAIN_EVENT_DEFINED:
- str = virshDomainEventDefinedTypeToString(detail);
- break;
- case VIR_DOMAIN_EVENT_UNDEFINED:
- str = virshDomainEventUndefinedTypeToString(detail);
- break;
- case VIR_DOMAIN_EVENT_STARTED:
- str = virshDomainEventStartedTypeToString(detail);
- break;
- case VIR_DOMAIN_EVENT_SUSPENDED:
- str = virshDomainEventSuspendedTypeToString(detail);
- break;
- case VIR_DOMAIN_EVENT_RESUMED:
- str = virshDomainEventResumedTypeToString(detail);
- break;
- case VIR_DOMAIN_EVENT_STOPPED:
- str = virshDomainEventStoppedTypeToString(detail);
- break;
- case VIR_DOMAIN_EVENT_SHUTDOWN:
- str = virshDomainEventShutdownTypeToString(detail);
- break;
- case VIR_DOMAIN_EVENT_PMSUSPENDED:
- str = virshDomainEventPMSuspendedTypeToString(detail);
- break;
- case VIR_DOMAIN_EVENT_CRASHED:
- str = virshDomainEventCrashedTypeToString(detail);
- break;
- case VIR_DOMAIN_EVENT_LAST:
- break;
- }
- return str ? _(str) : _("unknown");
-}
-
-VIR_ENUM_DECL(virshDomainEventWatchdog);
-VIR_ENUM_IMPL(virshDomainEventWatchdog,
- VIR_DOMAIN_EVENT_WATCHDOG_LAST,
- N_("none"),
- N_("pause"),
- N_("reset"),
- N_("poweroff"),
- N_("shutdown"),
- N_("debug"),
- N_("inject-nmi"));
-
-static const char *
-virshDomainEventWatchdogToString(int action)
-{
- const char *str = virshDomainEventWatchdogTypeToString(action);
- return str ? _(str) : _("unknown");
-}
-
-VIR_ENUM_DECL(virshDomainEventIOError);
-VIR_ENUM_IMPL(virshDomainEventIOError,
- VIR_DOMAIN_EVENT_IO_ERROR_LAST,
- N_("none"),
- N_("pause"),
- N_("report"));
-
-static const char *
-virshDomainEventIOErrorToString(int action)
-{
- const char *str = virshDomainEventIOErrorTypeToString(action);
- return str ? _(str) : _("unknown");
-}
-
-VIR_ENUM_DECL(virshGraphicsPhase);
-VIR_ENUM_IMPL(virshGraphicsPhase,
- VIR_DOMAIN_EVENT_GRAPHICS_LAST,
- N_("connect"),
- N_("initialize"),
- N_("disconnect"));
-
-static const char *
-virshGraphicsPhaseToString(int phase)
-{
- const char *str = virshGraphicsPhaseTypeToString(phase);
- return str ? _(str) : _("unknown");
-}
-
-VIR_ENUM_DECL(virshGraphicsAddress);
-VIR_ENUM_IMPL(virshGraphicsAddress,
- VIR_DOMAIN_EVENT_GRAPHICS_ADDRESS_LAST,
- N_("IPv4"),
- N_("IPv6"),
- N_("unix"));
-
-static const char *
-virshGraphicsAddressToString(int family)
-{
- const char *str = virshGraphicsAddressTypeToString(family);
- return str ? _(str) : _("unknown");
-}
-
-VIR_ENUM_DECL(virshDomainBlockJobStatus);
-VIR_ENUM_IMPL(virshDomainBlockJobStatus,
- VIR_DOMAIN_BLOCK_JOB_LAST,
- N_("completed"),
- N_("failed"),
- N_("canceled"),
- N_("ready"));
-
-static const char *
-virshDomainBlockJobStatusToString(int status)
-{
- const char *str = virshDomainBlockJobStatusTypeToString(status);
- return str ? _(str) : _("unknown");
-}
-
-VIR_ENUM_DECL(virshDomainEventDiskChange);
-VIR_ENUM_IMPL(virshDomainEventDiskChange,
- VIR_DOMAIN_EVENT_DISK_CHANGE_LAST,
- N_("changed"),
- N_("dropped"));
-
-static const char *
-virshDomainEventDiskChangeToString(int reason)
-{
- const char *str = virshDomainEventDiskChangeTypeToString(reason);
- return str ? _(str) : _("unknown");
-}
-
-VIR_ENUM_DECL(virshDomainEventTrayChange);
-VIR_ENUM_IMPL(virshDomainEventTrayChange,
- VIR_DOMAIN_EVENT_TRAY_CHANGE_LAST,
- N_("opened"),
- N_("closed"));
-
-static const char *
-virshDomainEventTrayChangeToString(int reason)
-{
- const char *str = virshDomainEventTrayChangeTypeToString(reason);
- return str ? _(str) : _("unknown");
-}
-
-struct virshDomEventData {
- vshControl *ctl;
- bool loop;
- int *count;
- bool timestamp;
- virshDomainEventCallback *cb;
- int id;
-};
-typedef struct virshDomEventData virshDomEventData;
-
-/**
- * virshEventPrint:
- *
- * @data: opaque data passed to all event callbacks
- * @buf: string buffer describing the event
- *
- * Print the event description found in @buf and update virshDomEventData.
- *
- * This function resets @buf and frees all memory consumed by its content.
- */
-static void
-virshEventPrint(virshDomEventData *data,
- virBuffer *buf)
-{
- g_autofree char *msg = NULL;
-
- if (!(msg = virBufferContentAndReset(buf)))
- return;
-
- if (!data->loop && *data->count)
- return;
-
- if (data->timestamp) {
- char timestamp[VIR_TIME_STRING_BUFLEN];
-
- if (virTimeStringNowRaw(timestamp) < 0)
- timestamp[0] = '\0';
-
- vshPrint(data->ctl, "%s: %s", timestamp, msg);
- } else {
- vshPrint(data->ctl, "%s", msg);
- }
-
- (*data->count)++;
- if (!data->loop)
- vshEventDone(data->ctl);
-}
-
-static void
-virshEventGenericPrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event '%s' for domain '%s'\n"),
- ((virshDomEventData *) opaque)->cb->name,
- virDomainGetName(dom));
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventLifecyclePrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- int event,
- int detail,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'lifecycle' for domain '%s': %s %s\n"),
- virDomainGetName(dom),
- virshDomainEventToString(event),
- virshDomainEventDetailToString(event, detail));
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventRTCChangePrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- long long utcoffset,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'rtc-change' for domain '%s': %lld\n"),
- virDomainGetName(dom),
- utcoffset);
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventWatchdogPrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- int action,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'watchdog' for domain '%s': %s\n"),
- virDomainGetName(dom),
- virshDomainEventWatchdogToString(action));
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventIOErrorPrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- const char *srcPath,
- const char *devAlias,
- int action,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'io-error' for domain '%s': %s (%s) %s\n"),
- virDomainGetName(dom),
- srcPath,
- devAlias,
- virshDomainEventIOErrorToString(action));
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventGraphicsPrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- int phase,
- const virDomainEventGraphicsAddress *local,
- const virDomainEventGraphicsAddress *remote,
- const char *authScheme,
- const virDomainEventGraphicsSubject *subject,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
- size_t i;
-
- virBufferAsprintf(&buf, _("event 'graphics' for domain '%s': "
- "%s local[%s %s %s] remote[%s %s %s] %s\n"),
- virDomainGetName(dom),
- virshGraphicsPhaseToString(phase),
- virshGraphicsAddressToString(local->family),
- local->node,
- local->service,
- virshGraphicsAddressToString(remote->family),
- remote->node,
- remote->service,
- authScheme);
- for (i = 0; i < subject->nidentity; i++) {
- virBufferAsprintf(&buf, "\t%s=%s\n",
- subject->identities[i].type,
- subject->identities[i].name);
- }
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventIOErrorReasonPrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- const char *srcPath,
- const char *devAlias,
- int action,
- const char *reason,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'io-error-reason' for domain '%s': "
- "%s (%s) %s due to %s\n"),
- virDomainGetName(dom),
- srcPath,
- devAlias,
- virshDomainEventIOErrorToString(action),
- reason);
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventBlockJobPrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- const char *disk,
- int type,
- int status,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event '%s' for domain '%s': %s for %s %s\n"),
- ((virshDomEventData *) opaque)->cb->name,
- virDomainGetName(dom),
- virshDomainBlockJobToString(type),
- disk,
- virshDomainBlockJobStatusToString(status));
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventDiskChangePrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- const char *oldSrc,
- const char *newSrc,
- const char *alias,
- int reason,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'disk-change' for domain '%s' disk %s: "
- "%s -> %s: %s\n"),
- virDomainGetName(dom),
- alias,
- NULLSTR(oldSrc),
- NULLSTR(newSrc),
- virshDomainEventDiskChangeToString(reason));
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventTrayChangePrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- const char *alias,
- int reason,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'tray-change' for domain '%s' disk %s: %s\n"),
- virDomainGetName(dom),
- alias,
- virshDomainEventTrayChangeToString(reason));
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventPMChangePrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- int reason G_GNUC_UNUSED,
- void *opaque)
-{
- /* As long as libvirt.h doesn't define any reasons, we might as
- * well treat all PM state changes as generic events. */
- virshEventGenericPrint(conn, dom, opaque);
-}
-
-static void
-virshEventBalloonChangePrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- unsigned long long actual,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'balloon-change' for domain '%s': %lluKiB\n"),
- virDomainGetName(dom),
- actual);
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventDeviceRemovedPrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- const char *alias,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'device-removed' for domain '%s': %s\n"),
- virDomainGetName(dom),
- alias);
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventDeviceAddedPrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- const char *alias,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'device-added' for domain '%s': %s\n"),
- virDomainGetName(dom),
- alias);
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventTunablePrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- virTypedParameterPtr params,
- int nparams,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
- size_t i;
- char *value;
-
- virBufferAsprintf(&buf, _("event 'tunable' for domain '%s':\n"),
- virDomainGetName(dom));
- for (i = 0; i < nparams; i++) {
- value = virTypedParameterToString(¶ms[i]);
- if (value) {
- virBufferAsprintf(&buf, "\t%s: %s\n", params[i].field, value);
- VIR_FREE(value);
- }
- }
- virshEventPrint(opaque, &buf);
-}
-
-VIR_ENUM_DECL(virshEventAgentLifecycleState);
-VIR_ENUM_IMPL(virshEventAgentLifecycleState,
- VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_STATE_LAST,
- N_("unknown"),
- N_("connected"),
- N_("disconnected"));
-
-VIR_ENUM_DECL(virshEventAgentLifecycleReason);
-VIR_ENUM_IMPL(virshEventAgentLifecycleReason,
- VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_LAST,
- N_("unknown"),
- N_("domain started"),
- N_("channel event"));
-
-#define UNKNOWNSTR(str) (str ? str : N_("unsupported value"))
-static void
-virshEventAgentLifecyclePrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- int state,
- int reason,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'agent-lifecycle' for domain '%s': state: "
- "'%s' reason: '%s'\n"),
- virDomainGetName(dom),
- UNKNOWNSTR(virshEventAgentLifecycleStateTypeToString(state)),
- UNKNOWNSTR(virshEventAgentLifecycleReasonTypeToString(reason)));
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventMigrationIterationPrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- int iteration,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'migration-iteration' for domain '%s': "
- "iteration: '%d'\n"),
- virDomainGetName(dom),
- iteration);
-
- virshEventPrint(opaque, &buf);
-}
-
-static void
-virshEventJobCompletedPrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- virTypedParameterPtr params,
- int nparams,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
- size_t i;
-
- virBufferAsprintf(&buf, _("event 'job-completed' for domain '%s':\n"),
- virDomainGetName(dom));
- for (i = 0; i < nparams; i++) {
- g_autofree char *value = virTypedParameterToString(¶ms[i]);
- if (value)
- virBufferAsprintf(&buf, "\t%s: %s\n", params[i].field, value);
- }
- virshEventPrint(opaque, &buf);
-}
-
-
-static void
-virshEventDeviceRemovalFailedPrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- const char *alias,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'device-removal-failed' for domain '%s': %s\n"),
- virDomainGetName(dom),
- alias);
- virshEventPrint(opaque, &buf);
-}
-
-VIR_ENUM_DECL(virshEventMetadataChangeType);
-VIR_ENUM_IMPL(virshEventMetadataChangeType,
- VIR_DOMAIN_METADATA_LAST,
- N_("description"),
- N_("title"),
- N_("element"));
-
-static void
-virshEventMetadataChangePrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- int type,
- const char *nsuri,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'metadata-change' for domain '%s': type %s, uri %s\n"),
- virDomainGetName(dom),
- UNKNOWNSTR(virshEventMetadataChangeTypeTypeToString(type)),
- NULLSTR(nsuri));
- virshEventPrint(opaque, &buf);
-}
-
-
-static void
-virshEventBlockThresholdPrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- const char *dev,
- const char *path,
- unsigned long long threshold,
- unsigned long long excess,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'block-threshold' for domain '%s': "
- "dev: %s(%s) %llu %llu\n"),
- virDomainGetName(dom),
- dev, NULLSTR(path), threshold, excess);
- virshEventPrint(opaque, &buf);
-}
-
-
-VIR_ENUM_DECL(virshEventMemoryFailureRecipientType);
-VIR_ENUM_IMPL(virshEventMemoryFailureRecipientType,
- VIR_DOMAIN_EVENT_MEMORY_FAILURE_RECIPIENT_LAST,
- N_("hypervisor"),
- N_("guest"));
-
-VIR_ENUM_DECL(virshEventMemoryFailureActionType);
-VIR_ENUM_IMPL(virshEventMemoryFailureActionType,
- VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_LAST,
- N_("ignore"),
- N_("inject"),
- N_("fatal"),
- N_("reset"));
-
-static void
-virshEventMemoryFailurePrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- int recipient,
- int action,
- unsigned int flags,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf, _("event 'memory-failure' for domain '%s':\n"
- "recipient: %s\naction: %s\n"),
- virDomainGetName(dom),
- UNKNOWNSTR(virshEventMemoryFailureRecipientTypeTypeToString(recipient)),
- UNKNOWNSTR(virshEventMemoryFailureActionTypeTypeToString(action)));
- virBufferAsprintf(&buf, _("flags:\n"
- "\taction required: %d\n\trecursive: %d\n"),
- !!(flags & VIR_DOMAIN_MEMORY_FAILURE_ACTION_REQUIRED),
- !!(flags & VIR_DOMAIN_MEMORY_FAILURE_RECURSIVE));
-
- virshEventPrint(opaque, &buf);
-}
-
-
-static void
-virshEventMemoryDeviceSizeChangePrint(virConnectPtr conn G_GNUC_UNUSED,
- virDomainPtr dom,
- const char *alias,
- unsigned long long size,
- void *opaque)
-{
- g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
-
- virBufferAsprintf(&buf,
- _("event 'memory-device-size-change' for domain '%s':\n"
- "alias: %s\nsize: %llu\n"),
- virDomainGetName(dom), alias, size);
-
- virshEventPrint(opaque, &buf);
-}
-
-
-virshDomainEventCallback virshDomainEventCallbacks[] = {
- { "lifecycle",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventLifecyclePrint), },
- { "reboot", virshEventGenericPrint, },
- { "rtc-change",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventRTCChangePrint), },
- { "watchdog",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventWatchdogPrint), },
- { "io-error",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventIOErrorPrint), },
- { "graphics",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventGraphicsPrint), },
- { "io-error-reason",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventIOErrorReasonPrint), },
- { "control-error", virshEventGenericPrint, },
- { "block-job",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockJobPrint), },
- { "disk-change",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventDiskChangePrint), },
- { "tray-change",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventTrayChangePrint), },
- { "pm-wakeup",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventPMChangePrint), },
- { "pm-suspend",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventPMChangePrint), },
- { "balloon-change",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventBalloonChangePrint), },
- { "pm-suspend-disk",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventPMChangePrint), },
- { "device-removed",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventDeviceRemovedPrint), },
- { "block-job-2",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockJobPrint), },
- { "tunable",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventTunablePrint), },
- { "agent-lifecycle",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventAgentLifecyclePrint), },
- { "device-added",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventDeviceAddedPrint), },
- { "migration-iteration",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventMigrationIterationPrint), },
- { "job-completed",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventJobCompletedPrint), },
- { "device-removal-failed",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventDeviceRemovalFailedPrint), },
- { "metadata-change",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventMetadataChangePrint), },
- { "block-threshold",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventBlockThresholdPrint), },
- { "memory-failure",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventMemoryFailurePrint), },
- { "memory-device-size-change",
- VIR_DOMAIN_EVENT_CALLBACK(virshEventMemoryDeviceSizeChangePrint), },
-};
-G_STATIC_ASSERT(VIR_DOMAIN_EVENT_ID_LAST == G_N_ELEMENTS(virshDomainEventCallbacks));
-
-static const vshCmdInfo info_event[] = {
- {.name = "help",
- .data = N_("Domain Events")
- },
- {.name = "desc",
- .data = N_("List event types, or wait for domain events to occur")
- },
- {.name = NULL}
-};
-
-static const vshCmdOptDef opts_event[] = {
- VIRSH_COMMON_OPT_DOMAIN_OT_STRING(N_("filter by domain name, id or uuid"),
- 0, 0),
- {.name = "event",
- .type = VSH_OT_STRING,
- .completer = virshDomainEventNameCompleter,
- .help = N_("which event type to wait for")
- },
- {.name = "all",
- .type = VSH_OT_BOOL,
- .help = N_("wait for all events instead of just one type")
- },
- {.name = "loop",
- .type = VSH_OT_BOOL,
- .help = N_("loop until timeout or interrupt, rather than one-shot")
- },
- {.name = "timeout",
- .type = VSH_OT_INT,
- .help = N_("timeout seconds")
- },
- {.name = "list",
- .type = VSH_OT_BOOL,
- .help = N_("list valid event types")
- },
- {.name = "timestamp",
- .type = VSH_OT_BOOL,
- .help = N_("show timestamp for each printed event")
- },
- {.name = NULL}
-};
-
-static bool
-cmdEvent(vshControl *ctl, const vshCmd *cmd)
-{
- g_autoptr(virshDomain) dom = NULL;
- bool ret = false;
- int timeout = 0;
- virshDomEventData *data = NULL;
- size_t i;
- const char *eventName = NULL;
- int event = -1;
- bool all = vshCommandOptBool(cmd, "all");
- bool loop = vshCommandOptBool(cmd, "loop");
- bool timestamp = vshCommandOptBool(cmd, "timestamp");
- int count = 0;
- virshControl *priv = ctl->privData;
-
- VSH_EXCLUSIVE_OPTIONS("all", "event");
- VSH_EXCLUSIVE_OPTIONS("list", "all");
- VSH_EXCLUSIVE_OPTIONS("list", "event");
-
- if (vshCommandOptBool(cmd, "list")) {
- for (event = 0; event < VIR_DOMAIN_EVENT_ID_LAST; event++)
- vshPrint(ctl, "%s\n", virshDomainEventCallbacks[event].name);
- return true;
- }
-
- if (vshCommandOptStringReq(ctl, cmd, "event", &eventName) < 0)
- return false;
- if (eventName) {
- for (event = 0; event < VIR_DOMAIN_EVENT_ID_LAST; event++)
- if (STREQ(eventName, virshDomainEventCallbacks[event].name))
- break;
- if (event == VIR_DOMAIN_EVENT_ID_LAST) {
- vshError(ctl, _("unknown event type %s"), eventName);
- return false;
- }
- } else if (!all) {
- vshError(ctl, "%s",
- _("one of --list, --all, or --event is required"));
- return false;
- }
-
- if (all) {
- data = g_new0(virshDomEventData, VIR_DOMAIN_EVENT_ID_LAST);
- for (i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i++) {
- data[i].ctl = ctl;
- data[i].loop = loop;
- data[i].count = &count;
- data[i].timestamp = timestamp;
- data[i].cb = &virshDomainEventCallbacks[i];
- data[i].id = -1;
- }
- } else {
- data = g_new0(virshDomEventData, 1);
- data[0].ctl = ctl;
- data[0].loop = vshCommandOptBool(cmd, "loop");
- data[0].count = &count;
- data[0].timestamp = timestamp;
- data[0].cb = &virshDomainEventCallbacks[event];
- data[0].id = -1;
- }
- if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
- goto cleanup;
-
- if (vshCommandOptBool(cmd, "domain"))
- if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
- goto cleanup;
-
- if (vshEventStart(ctl, timeout) < 0)
- goto cleanup;
-
- for (i = 0; i < (all ? VIR_DOMAIN_EVENT_ID_LAST : 1); i++) {
- if ((data[i].id = virConnectDomainEventRegisterAny(priv->conn, dom,
- all ? i : event,
- data[i].cb->cb,
- &data[i],
- NULL)) < 0) {
- /* When registering for all events: if the first
- * registration succeeds, silently ignore failures on all
- * later registrations on the assumption that the server
- * is older and didn't know quite as many events. */
- if (i)
- vshResetLibvirtError();
- else
- goto cleanup;
- }
- }
- switch (vshEventWait(ctl)) {
- case VSH_EVENT_INTERRUPT:
- vshPrint(ctl, "%s", _("event loop interrupted\n"));
- break;
- case VSH_EVENT_TIMEOUT:
- vshPrint(ctl, "%s", _("event loop timed out\n"));
- break;
- case VSH_EVENT_DONE:
- break;
- default:
- goto cleanup;
- }
- vshPrint(ctl, _("events received: %d\n"), count);
- if (count)
- ret = true;
-
- cleanup:
- vshEventCleanup(ctl);
- if (data) {
- for (i = 0; i < (all ? VIR_DOMAIN_EVENT_ID_LAST : 1); i++) {
- if (data[i].id >= 0 &&
- virConnectDomainEventDeregisterAny(priv->conn, data[i].id) < 0)
- ret = false;
- }
- VIR_FREE(data);
- }
- return ret;
-}
-
-
/*
* "change-media" command
*/
@@ -14851,12 +13911,6 @@ const vshCmdDef domManagementCmds[] = {
.info = info_edit,
.flags = 0
},
- {.name = "event",
- .handler = cmdEvent,
- .opts = opts_event,
- .info = info_event,
- .flags = 0
- },
{.name = "get-user-sshkeys",
.handler = cmdGetUserSSHKeys,
.opts = opts_get_user_sshkeys,
diff --git a/tools/virsh.c b/tools/virsh.c
index 64e0700fcd..f7adb90be8 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -45,6 +45,7 @@
#include "virsh-checkpoint.h"
#include "virsh-console.h"
#include "virsh-domain.h"
+#include "virsh-domain-event.h"
#include "virsh-domain-monitor.h"
#include "virsh-host.h"
#include "virsh-interface.h"
@@ -814,6 +815,7 @@ static const vshCmdDef virshCmds[] = {
static const vshCmdGrp cmdGroups[] = {
{VIRSH_CMD_GRP_DOM_MANAGEMENT, "domain", domManagementCmds},
{VIRSH_CMD_GRP_DOM_MONITORING, "monitor", domMonitoringCmds},
+ {VIRSH_CMD_GRP_DOM_EVENTS, "events", domEventCmds},
{VIRSH_CMD_GRP_HOST_AND_HV, "host", hostAndHypervisorCmds},
{VIRSH_CMD_GRP_CHECKPOINT, "checkpoint", checkpointCmds},
{VIRSH_CMD_GRP_IFACE, "interface", ifaceCmds},
diff --git a/tools/virsh.h b/tools/virsh.h
index cacd54db57..d7a60b135d 100644
--- a/tools/virsh.h
+++ b/tools/virsh.h
@@ -41,6 +41,7 @@
#define VIRSH_CMD_GRP_CHECKPOINT "Checkpoint"
#define VIRSH_CMD_GRP_DOM_MANAGEMENT "Domain Management"
#define VIRSH_CMD_GRP_DOM_MONITORING "Domain Monitoring"
+#define VIRSH_CMD_GRP_DOM_EVENTS "Domain Events"
#define VIRSH_CMD_GRP_STORAGE_POOL "Storage Pool"
#define VIRSH_CMD_GRP_STORAGE_VOL "Storage Volume"
#define VIRSH_CMD_GRP_NETWORK "Networking"