From nobody Sun Feb 8 22:57:50 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) client-ip=170.10.129.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1646229360; cv=none; d=zohomail.com; s=zohoarc; b=CFptdiVumoQHZnuJ4BeeMRwfhF0mSDovzNUlH1qwTXupb6CXkxHSx1rGtus5PDgtmdU/rBaDnz8PjrN/kQfYWC68GVF5DAs1ItPAAm9795fZl4FToGK+oSo6e3qQmNbMxLsxklj5Nx4rD6OAihm7dRiD3fpoR4eNpwfvoS5/nIM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1646229360; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=By2BmARVPxpQ47B8oNMn4IkrCf1rDtqrgmrOf5IKjiI=; b=N0GrJqLZ/HHXX5RzGIPdCsgZUAAF9uV+uIIdqAolZdGks6Ce5axgFfnwIkgfd+BoZneqKAaNx5aeZFoI0VAduWBJtL38eE+OokhDfEngd8CREekccdt+GhI/8GM4QLc1CmLqP1P4mk4NaZQNgGHesANoYOtMlhwTdAIu7AruACg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by mx.zohomail.com with SMTPS id 1646229360978719.0746105382369; Wed, 2 Mar 2022 05:56:00 -0800 (PST) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-163-uDvQ9oM4NkuoJ84bRyZTrw-1; Wed, 02 Mar 2022 08:55:58 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 3C9885220; Wed, 2 Mar 2022 13:55:53 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 199B779900; Wed, 2 Mar 2022 13:55:53 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id DF1C04EE45; Wed, 2 Mar 2022 13:55:52 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 222DtgE1017474 for ; Wed, 2 Mar 2022 08:55:42 -0500 Received: by smtp.corp.redhat.com (Postfix) id 46A4E17B7D; Wed, 2 Mar 2022 13:55:42 +0000 (UTC) Received: from speedmetal.redhat.com (unknown [10.40.208.30]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2A43883581 for ; Wed, 2 Mar 2022 13:55:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1646229359; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=By2BmARVPxpQ47B8oNMn4IkrCf1rDtqrgmrOf5IKjiI=; b=T9XymkkE14tlJ0CJoVQLywh7833q0YBOqOn2Xj+TXWBy0+XwgWUt/bBuYEMuWFZDZc5wU+ UjdmPk+GfoMrsPEPgFRb5GgLsKr8Zm+eYtNy49oJ2XAXzy7fVRs1GPISfGSAlcI5hkw4la AO0FzsOI6hqgfR1Fhldh/hyO3jgifWQ= X-MC-Unique: uDvQ9oM4NkuoJ84bRyZTrw-1 From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 09/23] virsh: Move 'cmdEvent' and all of it's machinery to virsh-domain-event.c Date: Wed, 2 Mar 2022 14:55:08 +0100 Message-Id: <3fa9d193c98b8833ae49de483e2159d4dc985f1c.1646229194.git.pkrempa@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-loop: libvir-list@redhat.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1646229362530100005 Content-Type: text/plain; charset="utf-8" 'cmdEvent' along with all the helper functions it needs is ~950 LOC. Move it out from virsh-domain.c to virsh-domain-event.c along with the completer function so that the new module doesn't have to expose any new types. Semantically this creates a new category in 'virsh help' but all other behaviour stays the same. Signed-off-by: Peter Krempa Reviewed-by: J=C3=A1n Tomko --- po/POTFILES.in | 1 + tools/meson.build | 1 + tools/virsh-completer-domain.c | 19 - tools/virsh-completer-domain.h | 5 - tools/virsh-domain-event.c | 1007 ++++++++++++++++++++++++++++++++ tools/virsh-domain-event.h | 23 + tools/virsh-domain.c | 946 ------------------------------ tools/virsh.c | 2 + tools/virsh.h | 1 + 9 files changed, 1035 insertions(+), 970 deletions(-) create mode 100644 tools/virsh-domain-event.c create mode 100644 tools/virsh-domain-event.h 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 =3D 0; - g_auto(GStrv) tmp =3D NULL; - - virCheckFlags(0, NULL); - - tmp =3D g_new0(char *, VIR_DOMAIN_EVENT_ID_LAST + 1); - - for (i =3D 0; i < VIR_DOMAIN_EVENT_ID_LAST; i++) - tmp[i] =3D 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 =3D 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 =3D NULL; + switch ((virDomainEventType) event) { + case VIR_DOMAIN_EVENT_DEFINED: + str =3D virshDomainEventDefinedTypeToString(detail); + break; + case VIR_DOMAIN_EVENT_UNDEFINED: + str =3D virshDomainEventUndefinedTypeToString(detail); + break; + case VIR_DOMAIN_EVENT_STARTED: + str =3D virshDomainEventStartedTypeToString(detail); + break; + case VIR_DOMAIN_EVENT_SUSPENDED: + str =3D virshDomainEventSuspendedTypeToString(detail); + break; + case VIR_DOMAIN_EVENT_RESUMED: + str =3D virshDomainEventResumedTypeToString(detail); + break; + case VIR_DOMAIN_EVENT_STOPPED: + str =3D virshDomainEventStoppedTypeToString(detail); + break; + case VIR_DOMAIN_EVENT_SHUTDOWN: + str =3D virshDomainEventShutdownTypeToString(detail); + break; + case VIR_DOMAIN_EVENT_PMSUSPENDED: + str =3D virshDomainEventPMSuspendedTypeToString(detail); + break; + case VIR_DOMAIN_EVENT_CRASHED: + str =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D NULL; + + if (!(msg =3D virBufferContentAndReset(buf))) + return; + + if (!data->loop && *data->count) + return; + + if (data->timestamp) { + char timestamp[VIR_TIME_STRING_BUFLEN]; + + if (virTimeStringNowRaw(timestamp) < 0) + timestamp[0] =3D '\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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 0; i < subject->nidentity; i++) { + virBufferAsprintf(&buf, "\t%s=3D%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 =3D 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 =3D 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 =3D 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 =3D 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 =3D VIR_BUFFER_INITIALIZER; + + virBufferAsprintf(&buf, _("event 'balloon-change' for domain '%s': %ll= uKiB\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 =3D 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 =3D 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 =3D VIR_BUFFER_INITIALIZER; + size_t i; + char *value; + + virBufferAsprintf(&buf, _("event 'tunable' for domain '%s':\n"), + virDomainGetName(dom)); + for (i =3D 0; i < nparams; i++) { + value =3D 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 =3D VIR_BUFFER_INITIALIZER; + + virBufferAsprintf(&buf, _("event 'agent-lifecycle' for domain '%s': st= ate: " + "'%s' reason: '%s'\n"), + virDomainGetName(dom), + UNKNOWNSTR(virshEventAgentLifecycleStateTypeToString= (state)), + UNKNOWNSTR(virshEventAgentLifecycleReasonTypeToStrin= g(reason))); + virshEventPrint(opaque, &buf); +} + +static void +virshEventMigrationIterationPrint(virConnectPtr conn G_GNUC_UNUSED, + virDomainPtr dom, + int iteration, + void *opaque) +{ + g_auto(virBuffer) buf =3D 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 =3D VIR_BUFFER_INITIALIZER; + size_t i; + + virBufferAsprintf(&buf, _("event 'job-completed' for domain '%s':\n"), + virDomainGetName(dom)); + for (i =3D 0; i < nparams; i++) { + g_autofree char *value =3D 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 =3D 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 =3D VIR_BUFFER_INITIALIZER; + + virBufferAsprintf(&buf, _("event 'metadata-change' for domain '%s': ty= pe %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 =3D 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 =3D VIR_BUFFER_INITIALIZER; + + virBufferAsprintf(&buf, _("event 'memory-failure' for domain '%s':\n" + "recipient: %s\naction: %s\n"), + virDomainGetName(dom), + UNKNOWNSTR(virshEventMemoryFailureRecipientTypeTypeT= oString(recipient)), + UNKNOWNSTR(virshEventMemoryFailureActionTypeTypeToSt= ring(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 =3D 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[] =3D { + { "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 =3D=3D G_N_ELEMENTS(virshDomainEv= entCallbacks)); + + +static char ** +virshDomainEventNameCompleter(vshControl *ctl G_GNUC_UNUSED, + const vshCmd *cmd G_GNUC_UNUSED, + unsigned int flags) +{ + size_t i =3D 0; + g_auto(GStrv) tmp =3D NULL; + + virCheckFlags(0, NULL); + + tmp =3D g_new0(char *, VIR_DOMAIN_EVENT_ID_LAST + 1); + + for (i =3D 0; i < VIR_DOMAIN_EVENT_ID_LAST; i++) + tmp[i] =3D g_strdup(virshDomainEventCallbacks[i].name); + + return g_steal_pointer(&tmp); +} + + +static const vshCmdInfo info_event[] =3D { + {.name =3D "help", + .data =3D N_("Domain Events") + }, + {.name =3D "desc", + .data =3D N_("List event types, or wait for domain events to occur") + }, + {.name =3D NULL} +}; + +static const vshCmdOptDef opts_event[] =3D { + VIRSH_COMMON_OPT_DOMAIN_OT_STRING(N_("filter by domain name, id or uui= d"), + 0, 0), + {.name =3D "event", + .type =3D VSH_OT_STRING, + .completer =3D virshDomainEventNameCompleter, + .help =3D N_("which event type to wait for") + }, + {.name =3D "all", + .type =3D VSH_OT_BOOL, + .help =3D N_("wait for all events instead of just one type") + }, + {.name =3D "loop", + .type =3D VSH_OT_BOOL, + .help =3D N_("loop until timeout or interrupt, rather than one-shot") + }, + {.name =3D "timeout", + .type =3D VSH_OT_INT, + .help =3D N_("timeout seconds") + }, + {.name =3D "list", + .type =3D VSH_OT_BOOL, + .help =3D N_("list valid event types") + }, + {.name =3D "timestamp", + .type =3D VSH_OT_BOOL, + .help =3D N_("show timestamp for each printed event") + }, + {.name =3D NULL} +}; + +static bool +cmdEvent(vshControl *ctl, const vshCmd *cmd) +{ + g_autoptr(virshDomain) dom =3D NULL; + bool ret =3D false; + int timeout =3D 0; + virshDomEventData *data =3D NULL; + size_t i; + const char *eventName =3D NULL; + int event =3D -1; + bool all =3D vshCommandOptBool(cmd, "all"); + bool loop =3D vshCommandOptBool(cmd, "loop"); + bool timestamp =3D vshCommandOptBool(cmd, "timestamp"); + int count =3D 0; + virshControl *priv =3D ctl->privData; + + VSH_EXCLUSIVE_OPTIONS("all", "event"); + VSH_EXCLUSIVE_OPTIONS("list", "all"); + VSH_EXCLUSIVE_OPTIONS("list", "event"); + + if (vshCommandOptBool(cmd, "list")) { + for (event =3D 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 =3D 0; event < VIR_DOMAIN_EVENT_ID_LAST; event++) + if (STREQ(eventName, virshDomainEventCallbacks[event].name)) + break; + if (event =3D=3D 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 =3D g_new0(virshDomEventData, VIR_DOMAIN_EVENT_ID_LAST); + for (i =3D 0; i < VIR_DOMAIN_EVENT_ID_LAST; i++) { + data[i].ctl =3D ctl; + data[i].loop =3D loop; + data[i].count =3D &count; + data[i].timestamp =3D timestamp; + data[i].cb =3D &virshDomainEventCallbacks[i]; + data[i].id =3D -1; + } + } else { + data =3D g_new0(virshDomEventData, 1); + data[0].ctl =3D ctl; + data[0].loop =3D vshCommandOptBool(cmd, "loop"); + data[0].count =3D &count; + data[0].timestamp =3D timestamp; + data[0].cb =3D &virshDomainEventCallbacks[event]; + data[0].id =3D -1; + } + if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0) + goto cleanup; + + if (vshCommandOptBool(cmd, "domain")) + if (!(dom =3D virshCommandOptDomain(ctl, cmd, NULL))) + goto cleanup; + + if (vshEventStart(ctl, timeout) < 0) + goto cleanup; + + for (i =3D 0; i < (all ? VIR_DOMAIN_EVENT_ID_LAST : 1); i++) { + if ((data[i].id =3D virConnectDomainEventRegisterAny(priv->conn, d= om, + 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 =3D true; + + cleanup: + vshEventCleanup(ctl); + if (data) { + for (i =3D 0; i < (all ? VIR_DOMAIN_EVENT_ID_LAST : 1); i++) { + if (data[i].id >=3D 0 && + virConnectDomainEventDeregisterAny(priv->conn, data[i].id)= < 0) + ret =3D false; + } + VIR_FREE(data); + } + return ret; +} + + +const vshCmdDef domEventCmds[] =3D { + {.name =3D "event", + .handler =3D cmdEvent, + .opts =3D opts_event, + .info =3D info_event, + .flags =3D 0 + }, + {.name =3D 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 =3D 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 =3D NULL; - switch ((virDomainEventType) event) { - case VIR_DOMAIN_EVENT_DEFINED: - str =3D virshDomainEventDefinedTypeToString(detail); - break; - case VIR_DOMAIN_EVENT_UNDEFINED: - str =3D virshDomainEventUndefinedTypeToString(detail); - break; - case VIR_DOMAIN_EVENT_STARTED: - str =3D virshDomainEventStartedTypeToString(detail); - break; - case VIR_DOMAIN_EVENT_SUSPENDED: - str =3D virshDomainEventSuspendedTypeToString(detail); - break; - case VIR_DOMAIN_EVENT_RESUMED: - str =3D virshDomainEventResumedTypeToString(detail); - break; - case VIR_DOMAIN_EVENT_STOPPED: - str =3D virshDomainEventStoppedTypeToString(detail); - break; - case VIR_DOMAIN_EVENT_SHUTDOWN: - str =3D virshDomainEventShutdownTypeToString(detail); - break; - case VIR_DOMAIN_EVENT_PMSUSPENDED: - str =3D virshDomainEventPMSuspendedTypeToString(detail); - break; - case VIR_DOMAIN_EVENT_CRASHED: - str =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D NULL; - - if (!(msg =3D virBufferContentAndReset(buf))) - return; - - if (!data->loop && *data->count) - return; - - if (data->timestamp) { - char timestamp[VIR_TIME_STRING_BUFLEN]; - - if (virTimeStringNowRaw(timestamp) < 0) - timestamp[0] =3D '\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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 0; i < subject->nidentity; i++) { - virBufferAsprintf(&buf, "\t%s=3D%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 =3D 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 =3D 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 =3D 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 =3D 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 =3D VIR_BUFFER_INITIALIZER; - - virBufferAsprintf(&buf, _("event 'balloon-change' for domain '%s': %ll= uKiB\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 =3D 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 =3D 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 =3D VIR_BUFFER_INITIALIZER; - size_t i; - char *value; - - virBufferAsprintf(&buf, _("event 'tunable' for domain '%s':\n"), - virDomainGetName(dom)); - for (i =3D 0; i < nparams; i++) { - value =3D 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 =3D VIR_BUFFER_INITIALIZER; - - virBufferAsprintf(&buf, _("event 'agent-lifecycle' for domain '%s': st= ate: " - "'%s' reason: '%s'\n"), - virDomainGetName(dom), - UNKNOWNSTR(virshEventAgentLifecycleStateTypeToString= (state)), - UNKNOWNSTR(virshEventAgentLifecycleReasonTypeToStrin= g(reason))); - virshEventPrint(opaque, &buf); -} - -static void -virshEventMigrationIterationPrint(virConnectPtr conn G_GNUC_UNUSED, - virDomainPtr dom, - int iteration, - void *opaque) -{ - g_auto(virBuffer) buf =3D 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 =3D VIR_BUFFER_INITIALIZER; - size_t i; - - virBufferAsprintf(&buf, _("event 'job-completed' for domain '%s':\n"), - virDomainGetName(dom)); - for (i =3D 0; i < nparams; i++) { - g_autofree char *value =3D 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 =3D 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 =3D VIR_BUFFER_INITIALIZER; - - virBufferAsprintf(&buf, _("event 'metadata-change' for domain '%s': ty= pe %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 =3D 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 =3D VIR_BUFFER_INITIALIZER; - - virBufferAsprintf(&buf, _("event 'memory-failure' for domain '%s':\n" - "recipient: %s\naction: %s\n"), - virDomainGetName(dom), - UNKNOWNSTR(virshEventMemoryFailureRecipientTypeTypeT= oString(recipient)), - UNKNOWNSTR(virshEventMemoryFailureActionTypeTypeToSt= ring(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 =3D 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[] =3D { - { "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 =3D=3D G_N_ELEMENTS(virshDomainEv= entCallbacks)); - -static const vshCmdInfo info_event[] =3D { - {.name =3D "help", - .data =3D N_("Domain Events") - }, - {.name =3D "desc", - .data =3D N_("List event types, or wait for domain events to occur") - }, - {.name =3D NULL} -}; - -static const vshCmdOptDef opts_event[] =3D { - VIRSH_COMMON_OPT_DOMAIN_OT_STRING(N_("filter by domain name, id or uui= d"), - 0, 0), - {.name =3D "event", - .type =3D VSH_OT_STRING, - .completer =3D virshDomainEventNameCompleter, - .help =3D N_("which event type to wait for") - }, - {.name =3D "all", - .type =3D VSH_OT_BOOL, - .help =3D N_("wait for all events instead of just one type") - }, - {.name =3D "loop", - .type =3D VSH_OT_BOOL, - .help =3D N_("loop until timeout or interrupt, rather than one-shot") - }, - {.name =3D "timeout", - .type =3D VSH_OT_INT, - .help =3D N_("timeout seconds") - }, - {.name =3D "list", - .type =3D VSH_OT_BOOL, - .help =3D N_("list valid event types") - }, - {.name =3D "timestamp", - .type =3D VSH_OT_BOOL, - .help =3D N_("show timestamp for each printed event") - }, - {.name =3D NULL} -}; - -static bool -cmdEvent(vshControl *ctl, const vshCmd *cmd) -{ - g_autoptr(virshDomain) dom =3D NULL; - bool ret =3D false; - int timeout =3D 0; - virshDomEventData *data =3D NULL; - size_t i; - const char *eventName =3D NULL; - int event =3D -1; - bool all =3D vshCommandOptBool(cmd, "all"); - bool loop =3D vshCommandOptBool(cmd, "loop"); - bool timestamp =3D vshCommandOptBool(cmd, "timestamp"); - int count =3D 0; - virshControl *priv =3D ctl->privData; - - VSH_EXCLUSIVE_OPTIONS("all", "event"); - VSH_EXCLUSIVE_OPTIONS("list", "all"); - VSH_EXCLUSIVE_OPTIONS("list", "event"); - - if (vshCommandOptBool(cmd, "list")) { - for (event =3D 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 =3D 0; event < VIR_DOMAIN_EVENT_ID_LAST; event++) - if (STREQ(eventName, virshDomainEventCallbacks[event].name)) - break; - if (event =3D=3D 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 =3D g_new0(virshDomEventData, VIR_DOMAIN_EVENT_ID_LAST); - for (i =3D 0; i < VIR_DOMAIN_EVENT_ID_LAST; i++) { - data[i].ctl =3D ctl; - data[i].loop =3D loop; - data[i].count =3D &count; - data[i].timestamp =3D timestamp; - data[i].cb =3D &virshDomainEventCallbacks[i]; - data[i].id =3D -1; - } - } else { - data =3D g_new0(virshDomEventData, 1); - data[0].ctl =3D ctl; - data[0].loop =3D vshCommandOptBool(cmd, "loop"); - data[0].count =3D &count; - data[0].timestamp =3D timestamp; - data[0].cb =3D &virshDomainEventCallbacks[event]; - data[0].id =3D -1; - } - if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0) - goto cleanup; - - if (vshCommandOptBool(cmd, "domain")) - if (!(dom =3D virshCommandOptDomain(ctl, cmd, NULL))) - goto cleanup; - - if (vshEventStart(ctl, timeout) < 0) - goto cleanup; - - for (i =3D 0; i < (all ? VIR_DOMAIN_EVENT_ID_LAST : 1); i++) { - if ((data[i].id =3D virConnectDomainEventRegisterAny(priv->conn, d= om, - 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 =3D true; - - cleanup: - vshEventCleanup(ctl); - if (data) { - for (i =3D 0; i < (all ? VIR_DOMAIN_EVENT_ID_LAST : 1); i++) { - if (data[i].id >=3D 0 && - virConnectDomainEventDeregisterAny(priv->conn, data[i].id)= < 0) - ret =3D false; - } - VIR_FREE(data); - } - return ret; -} - - /* * "change-media" command */ @@ -14851,12 +13911,6 @@ const vshCmdDef domManagementCmds[] =3D { .info =3D info_edit, .flags =3D 0 }, - {.name =3D "event", - .handler =3D cmdEvent, - .opts =3D opts_event, - .info =3D info_event, - .flags =3D 0 - }, {.name =3D "get-user-sshkeys", .handler =3D cmdGetUserSSHKeys, .opts =3D 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[] =3D { static const vshCmdGrp cmdGroups[] =3D { {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" --=20 2.35.1