[libvirt] [dbus PATCH 00/18] rewrite to use libdbus and some other fixes

The first 15 patches fixes some issues and bugs and cleanups the code. Patch 16 introduces support for libdbus and a lot of helper functions. Patch 17 switches the code to use libdbus instead of sd-bus and drops all sd-bus related code. Patch 18 introduces threading so every message is processed by separate thread. Pavel Hrdina (18): util: rename VIR_ATTR_UNUSED util: there is no need to mark cleanup functions as inline util: introduce VIRT_DBUS_ERROR_INTERFACE connect: introduce VIRT_DBUS_CONNECT_INTERFACE domain: introduce VIRT_DBUS_DOMAIN_INTERFACE events: fix signal message for TrayChange event events: fix function names for TrayChange and DiskChange events main: error out if signal handler is not registered main: fix error message spec: don't use hard-coded system_user maint: fix coding style maint: cleanup includes domain: ensure connection to libvirt connect: parse message arguments as first thing domain: create a helper function to get a domain object introduce support for libdbus library switch from sd-bus to libdbus main: introduce threads to process the dbus messages README | 2 +- configure.ac | 16 +- data/Makefile.am | 7 + data/org.libvirt.Connect.xml | 56 ++ data/org.libvirt.Domain.xml | 51 ++ libvirt-dbus.spec.in | 16 +- src/Makefile.am | 15 +- src/connect.c | 240 ++++----- src/connect.h | 44 +- src/dbus.c | 1226 ++++++++++++++++++++++++++++++++++++++++++ src/dbus.h | 158 ++++++ src/domain.c | 642 ++++++++++------------ src/domain.h | 5 +- src/events.c | 150 +++--- src/events.h | 3 - src/main.c | 208 ++++--- src/util.c | 310 ++++++++--- src/util.h | 82 ++- test/Makefile.am | 3 +- test/travis-run | 2 +- 20 files changed, 2446 insertions(+), 790 deletions(-) create mode 100644 data/org.libvirt.Connect.xml create mode 100644 data/org.libvirt.Domain.xml create mode 100644 src/dbus.c create mode 100644 src/dbus.h -- 2.14.3

The correct prefix is VIRT. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/connect.c | 8 +++--- src/domain.c | 78 +++++++++++++++++++++++++++++------------------------------ src/events.c | 12 ++++----- src/main.c | 12 ++++----- src/util.h | 3 ++- 5 files changed, 57 insertions(+), 56 deletions(-) diff --git a/src/connect.c b/src/connect.c index 360f922..b44d247 100644 --- a/src/connect.c +++ b/src/connect.c @@ -17,8 +17,8 @@ static int virtDBusConnectCredType[] = { }; static int -virtDBusConnectAuthCallback(virConnectCredentialPtr cred VIR_ATTR_UNUSED, - unsigned int ncred VIR_ATTR_UNUSED, +virtDBusConnectAuthCallback(virConnectCredentialPtr cred VIRT_ATTR_UNUSED, + unsigned int ncred VIRT_ATTR_UNUSED, void *cbdata) { sd_bus_error *error = cbdata; @@ -78,8 +78,8 @@ virtDBusConnectOpen(virtDBusConnect *connect, } static int -virtDBusConnectEnumarateDomains(sd_bus *bus VIR_ATTR_UNUSED, - const char *path VIR_ATTR_UNUSED, +virtDBusConnectEnumarateDomains(sd_bus *bus VIRT_ATTR_UNUSED, + const char *path VIRT_ATTR_UNUSED, void *userdata, char ***nodes, sd_bus_error *error) diff --git a/src/domain.c b/src/domain.c index 33ed2b3..ebcd142 100644 --- a/src/domain.c +++ b/src/domain.c @@ -5,13 +5,13 @@ #include <stdio.h> static int -virtDBusDomainGetName(sd_bus *bus VIR_ATTR_UNUSED, +virtDBusDomainGetName(sd_bus *bus VIRT_ATTR_UNUSED, const char *path, - const char *interface VIR_ATTR_UNUSED, - const char *property VIR_ATTR_UNUSED, + const char *interface VIRT_ATTR_UNUSED, + const char *property VIRT_ATTR_UNUSED, sd_bus_message *reply, void *userdata, - sd_bus_error *error VIR_ATTR_UNUSED) + sd_bus_error *error VIRT_ATTR_UNUSED) { virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; @@ -30,13 +30,13 @@ virtDBusDomainGetName(sd_bus *bus VIR_ATTR_UNUSED, } static int -virtDBusDomainGetUUID(sd_bus *bus VIR_ATTR_UNUSED, +virtDBusDomainGetUUID(sd_bus *bus VIRT_ATTR_UNUSED, const char *path, - const char *interface VIR_ATTR_UNUSED, - const char *property VIR_ATTR_UNUSED, + const char *interface VIRT_ATTR_UNUSED, + const char *property VIRT_ATTR_UNUSED, sd_bus_message *reply, void *userdata, - sd_bus_error *error VIR_ATTR_UNUSED) + sd_bus_error *error VIRT_ATTR_UNUSED) { virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; @@ -53,13 +53,13 @@ virtDBusDomainGetUUID(sd_bus *bus VIR_ATTR_UNUSED, } static int -virtDBusDomainGetId(sd_bus *bus VIR_ATTR_UNUSED, +virtDBusDomainGetId(sd_bus *bus VIRT_ATTR_UNUSED, const char *path, - const char *interface VIR_ATTR_UNUSED, - const char *property VIR_ATTR_UNUSED, + const char *interface VIRT_ATTR_UNUSED, + const char *property VIRT_ATTR_UNUSED, sd_bus_message *reply, void *userdata, - sd_bus_error *error VIR_ATTR_UNUSED) + sd_bus_error *error VIRT_ATTR_UNUSED) { virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; @@ -73,13 +73,13 @@ virtDBusDomainGetId(sd_bus *bus VIR_ATTR_UNUSED, } static int -virtDBusDomainGetVcpus(sd_bus *bus VIR_ATTR_UNUSED, +virtDBusDomainGetVcpus(sd_bus *bus VIRT_ATTR_UNUSED, const char *path, - const char *interface VIR_ATTR_UNUSED, - const char *property VIR_ATTR_UNUSED, + const char *interface VIRT_ATTR_UNUSED, + const char *property VIRT_ATTR_UNUSED, sd_bus_message *reply, void *userdata, - sd_bus_error *error VIR_ATTR_UNUSED) + sd_bus_error *error VIRT_ATTR_UNUSED) { virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; @@ -93,13 +93,13 @@ virtDBusDomainGetVcpus(sd_bus *bus VIR_ATTR_UNUSED, } static int -virtDBusDomainGetOsType(sd_bus *bus VIR_ATTR_UNUSED, +virtDBusDomainGetOsType(sd_bus *bus VIRT_ATTR_UNUSED, const char *path, - const char *interface VIR_ATTR_UNUSED, - const char *property VIR_ATTR_UNUSED, + const char *interface VIRT_ATTR_UNUSED, + const char *property VIRT_ATTR_UNUSED, sd_bus_message *reply, void *userdata, - sd_bus_error *error VIR_ATTR_UNUSED) + sd_bus_error *error VIRT_ATTR_UNUSED) { virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; @@ -118,13 +118,13 @@ virtDBusDomainGetOsType(sd_bus *bus VIR_ATTR_UNUSED, } static int -virtDBusDomainGetActive(sd_bus *bus VIR_ATTR_UNUSED, +virtDBusDomainGetActive(sd_bus *bus VIRT_ATTR_UNUSED, const char *path, - const char *interface VIR_ATTR_UNUSED, - const char *property VIR_ATTR_UNUSED, + const char *interface VIRT_ATTR_UNUSED, + const char *property VIRT_ATTR_UNUSED, sd_bus_message *reply, void *userdata, - sd_bus_error *error VIR_ATTR_UNUSED) + sd_bus_error *error VIRT_ATTR_UNUSED) { virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; @@ -143,13 +143,13 @@ virtDBusDomainGetActive(sd_bus *bus VIR_ATTR_UNUSED, } static int -virtDBusDomainGetPersistent(sd_bus *bus VIR_ATTR_UNUSED, +virtDBusDomainGetPersistent(sd_bus *bus VIRT_ATTR_UNUSED, const char *path, - const char *interface VIR_ATTR_UNUSED, - const char *property VIR_ATTR_UNUSED, + const char *interface VIRT_ATTR_UNUSED, + const char *property VIRT_ATTR_UNUSED, sd_bus_message *reply, void *userdata, - sd_bus_error *error VIR_ATTR_UNUSED) + sd_bus_error *error VIRT_ATTR_UNUSED) { virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; @@ -168,13 +168,13 @@ virtDBusDomainGetPersistent(sd_bus *bus VIR_ATTR_UNUSED, } static int -virtDBusDomainGetState(sd_bus *bus VIR_ATTR_UNUSED, +virtDBusDomainGetState(sd_bus *bus VIRT_ATTR_UNUSED, const char *path, - const char *interface VIR_ATTR_UNUSED, - const char *property VIR_ATTR_UNUSED, + const char *interface VIRT_ATTR_UNUSED, + const char *property VIRT_ATTR_UNUSED, sd_bus_message *reply, void *userdata, - sd_bus_error *error VIR_ATTR_UNUSED) + sd_bus_error *error VIRT_ATTR_UNUSED) { virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; @@ -220,13 +220,13 @@ virtDBusDomainGetState(sd_bus *bus VIR_ATTR_UNUSED, } static int -virtDBusDomainGetAutostart(sd_bus *bus VIR_ATTR_UNUSED, +virtDBusDomainGetAutostart(sd_bus *bus VIRT_ATTR_UNUSED, const char *path, - const char *interface VIR_ATTR_UNUSED, - const char *property VIR_ATTR_UNUSED, + const char *interface VIRT_ATTR_UNUSED, + const char *property VIRT_ATTR_UNUSED, sd_bus_message *reply, void *userdata, - sd_bus_error *error VIR_ATTR_UNUSED) + sd_bus_error *error VIRT_ATTR_UNUSED) { virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; @@ -522,12 +522,12 @@ static const sd_bus_vtable virt_domain_vtable[] = { }; static int -virtDBusDomainLookup(sd_bus *bus VIR_ATTR_UNUSED, +virtDBusDomainLookup(sd_bus *bus VIRT_ATTR_UNUSED, const char *path, - const char *interface VIR_ATTR_UNUSED, + const char *interface VIRT_ATTR_UNUSED, void *userdata, void **found, - sd_bus_error *error VIR_ATTR_UNUSED) + sd_bus_error *error VIRT_ATTR_UNUSED) { virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilFreep) char *name = NULL; diff --git a/src/events.c b/src/events.c index 05d5940..ca1418b 100644 --- a/src/events.c +++ b/src/events.c @@ -6,10 +6,10 @@ #include <systemd/sd-bus.h> static int -virtDBusEventsDomainLifecycle(virConnectPtr connection VIR_ATTR_UNUSED, +virtDBusEventsDomainLifecycle(virConnectPtr connection VIRT_ATTR_UNUSED, virDomainPtr domain, int event, - int detail VIR_ATTR_UNUSED, + int detail VIRT_ATTR_UNUSED, void *opaque) { virtDBusConnect *connect = opaque; @@ -70,7 +70,7 @@ virtDBusEventsDomainLifecycle(virConnectPtr connection VIR_ATTR_UNUSED, } static int -virtDBusEventsDomainDeviceAdded(virConnectPtr connection VIR_ATTR_UNUSED, +virtDBusEventsDomainDeviceAdded(virConnectPtr connection VIRT_ATTR_UNUSED, virDomainPtr domain, const char *device, void *opaque) @@ -98,7 +98,7 @@ virtDBusEventsDomainDeviceAdded(virConnectPtr connection VIR_ATTR_UNUSED, } static int -virtDBusEventsDomainDeviceRemoved(virConnectPtr connection VIR_ATTR_UNUSED, +virtDBusEventsDomainDeviceRemoved(virConnectPtr connection VIRT_ATTR_UNUSED, virDomainPtr domain, const char *device, void *opaque) @@ -126,7 +126,7 @@ virtDBusEventsDomainDeviceRemoved(virConnectPtr connection VIR_ATTR_UNUSED, } static int -virtDBusEventsDomainDiskChange(virConnectPtr connection VIR_ATTR_UNUSED, +virtDBusEventsDomainDiskChange(virConnectPtr connection VIRT_ATTR_UNUSED, virDomainPtr domain, const char *device, int reason, @@ -168,7 +168,7 @@ virtDBusEventsDomainDiskChange(virConnectPtr connection VIR_ATTR_UNUSED, } static int -virtDBusEventsDomainTrayChange(virConnectPtr connection VIR_ATTR_UNUSED, +virtDBusEventsDomainTrayChange(virConnectPtr connection VIRT_ATTR_UNUSED, virDomainPtr domain, const char *old_src_path, const char *new_src_path, diff --git a/src/main.c b/src/main.c index d41970a..e0f9434 100644 --- a/src/main.c +++ b/src/main.c @@ -55,18 +55,18 @@ virtDBusVirEventRemoveHandlep(int *watchp) } static void -virtDBusHandleSignal(int watch VIR_ATTR_UNUSED, - int fd VIR_ATTR_UNUSED, - int events VIR_ATTR_UNUSED, - void *opaque VIR_ATTR_UNUSED) +virtDBusHandleSignal(int watch VIRT_ATTR_UNUSED, + int fd VIRT_ATTR_UNUSED, + int events VIRT_ATTR_UNUSED, + void *opaque VIRT_ATTR_UNUSED) { loop_status = -ECANCELED; } static void virtDBusHandleBusEvent(int watch, - int fd VIR_ATTR_UNUSED, - int events VIR_ATTR_UNUSED, + int fd VIRT_ATTR_UNUSED, + int events VIRT_ATTR_UNUSED, void *opaque) { sd_bus *bus = opaque; diff --git a/src/util.h b/src/util.h index fcbcf8e..9779d29 100644 --- a/src/util.h +++ b/src/util.h @@ -6,7 +6,8 @@ #include <unistd.h> #define _cleanup_(_x) __attribute__((__cleanup__(_x))) -#define VIR_ATTR_UNUSED __attribute__((__unused__)) + +#define VIRT_ATTR_UNUSED __attribute__((__unused__)) #define VIRT_N_ELEMENTS(array) (sizeof(array) / sizeof(*(array))) -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:31PM +0100, Pavel Hrdina wrote:
The correct prefix is VIRT.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/connect.c | 8 +++--- src/domain.c | 78 +++++++++++++++++++++++++++++------------------------------ src/events.c | 12 ++++----- src/main.c | 12 ++++----- src/util.h | 3 ++- 5 files changed, 57 insertions(+), 56 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/util.c | 34 ++++++++++++++++++++++++++++++++++ src/util.h | 38 ++++++++------------------------------ 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/src/util.c b/src/util.c index d0649fa..962eaab 100644 --- a/src/util.c +++ b/src/util.c @@ -104,6 +104,40 @@ virtDBusUtilVirDomainFromBusPath(virConnectPtr connection, return virDomainLookupByUUIDString(connection, name); } +void +virtDBusUtilFreep(void *p) +{ + free(*(void **)p); +} + +void +virtDBusUtilClosep(int *fdp) +{ + if (*fdp >= 0) + close(*fdp); +} + +void +virtDBusUtilStrvFreep(void *p) +{ + char **strv = *(char ***)p; + + if (strv == NULL) + return; + + for (unsigned i = 0; strv[i] != NULL; i++) + free(strv[i]); + + free(strv); +} + +void +virtDBusUtilVirDomainFreep(virDomainPtr *domainp) +{ + if (*domainp) + virDomainFree(*domainp); +} + void virtDBusUtilVirDomainListFreep(virDomainPtr **domainsp) { diff --git a/src/util.h b/src/util.h index 9779d29..a772ffe 100644 --- a/src/util.h +++ b/src/util.h @@ -33,39 +33,17 @@ virtDBusUtilVirDomainFromBusPath(virConnectPtr connection, const char *path, const char *domainPath); -static inline void -virtDBusUtilFreep(void *p) -{ - free(*(void **)p); -} - -static inline void -virtDBusUtilClosep(int *fdp) -{ - if (*fdp >= 0) - close(*fdp); -} - -static inline void -virtDBusUtilStrvFreep(void *p) -{ - char **strv = *(char ***)p; - - if (strv == NULL) - return; +void +virtDBusUtilFreep(void *p); - for (unsigned i = 0; strv[i] != NULL; i += 1) - free(strv[i]); +void +virtDBusUtilClosep(int *fdp); - free(strv); -} +void +virtDBusUtilStrvFreep(void *p); -static inline void -virtDBusUtilVirDomainFreep(virDomainPtr *domainp) -{ - if (*domainp) - virDomainFree(*domainp); -} +void +virtDBusUtilVirDomainFreep(virDomainPtr *domainp); void virtDBusUtilVirDomainListFreep(virDomainPtr **domainsp); -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:32PM +0100, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/util.c | 34 ++++++++++++++++++++++++++++++++++ src/util.h | 38 ++++++++------------------------------ 2 files changed, 42 insertions(+), 30 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
-static inline void -virtDBusUtilVirDomainFreep(virDomainPtr *domainp) -{ - if (*domainp) - virDomainFree(*domainp); -} +void +virtDBusUtilVirDomainFreep(virDomainPtr *domainp);
I wonder if we should consider adding these convenience APIs to the official libvirt API. What you're doing here would be needed in any C app that relies on clenaup functions. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/util.c | 4 ++-- src/util.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/util.c b/src/util.c index 962eaab..3e6be4e 100644 --- a/src/util.c +++ b/src/util.c @@ -66,14 +66,14 @@ virtDBusUtilSetLastVirtError(sd_bus_error *error) if (!vir_error) return 0; - return sd_bus_error_set(error, "org.libvirt.Error", vir_error->message); + return sd_bus_error_set(error, VIRT_DBUS_ERROR_INTERFACE, vir_error->message); } int virtDBusUtilSetError(sd_bus_error *error, const char *message) { - return sd_bus_error_set(error, "org.libvirt.Error", message); + return sd_bus_error_set(error, VIRT_DBUS_ERROR_INTERFACE, message); } char * diff --git a/src/util.h b/src/util.h index a772ffe..c92674f 100644 --- a/src/util.h +++ b/src/util.h @@ -5,6 +5,8 @@ #include <systemd/sd-bus.h> #include <unistd.h> +#define VIRT_DBUS_ERROR_INTERFACE "org.libvirt.Error" + #define _cleanup_(_x) __attribute__((__cleanup__(_x))) #define VIRT_ATTR_UNUSED __attribute__((__unused__)) -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:33PM +0100, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/util.c | 4 ++-- src/util.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

This also fixes the one wrong interface name in events.c. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/connect.c | 2 +- src/connect.h | 2 ++ src/events.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/connect.c b/src/connect.c index b44d247..45fb2ae 100644 --- a/src/connect.c +++ b/src/connect.c @@ -258,7 +258,7 @@ virtDBusConnectNew(virtDBusConnect **connectp, r = sd_bus_add_object_vtable(connect->bus, NULL, connect->connectPath, - "org.libvirt.Connect", + VIRT_DBUS_CONNECT_INTERFACE, virt_connect_vtable, connect); if (r < 0) diff --git a/src/connect.h b/src/connect.h index 46e8c9a..9078ae7 100644 --- a/src/connect.h +++ b/src/connect.h @@ -5,6 +5,8 @@ #include <libvirt/libvirt.h> #include <systemd/sd-bus.h> +#define VIRT_DBUS_CONNECT_INTERFACE "org.libvirt.Connect" + struct virtDBusConnect { sd_bus *bus; const char *uri; diff --git a/src/events.c b/src/events.c index ca1418b..eee068c 100644 --- a/src/events.c +++ b/src/events.c @@ -54,7 +54,7 @@ virtDBusEventsDomainLifecycle(virConnectPtr connection VIRT_ATTR_UNUSED, r = sd_bus_message_new_signal(connect->bus, &message, connect->connectPath, - "org.libvirt.connect", + VIRT_DBUS_CONNECT_INTERFACE, signal); if (r < 0) return r; -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:34PM +0100, Pavel Hrdina wrote:
This also fixes the one wrong interface name in events.c.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/connect.c | 2 +- src/connect.h | 2 ++ src/events.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/domain.c | 2 +- src/domain.h | 2 ++ src/events.c | 8 ++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/domain.c b/src/domain.c index ebcd142..850ea4a 100644 --- a/src/domain.c +++ b/src/domain.c @@ -573,7 +573,7 @@ virtDBusDomainRegister(virtDBusConnect *connect, return sd_bus_add_fallback_vtable(bus, NULL, connect->domainPath, - "org.libvirt.Domain", + VIRT_DBUS_DOMAIN_INTERFACE, virt_domain_vtable, virtDBusDomainLookup, connect); diff --git a/src/domain.h b/src/domain.h index adadc6a..5ce592c 100644 --- a/src/domain.h +++ b/src/domain.h @@ -5,6 +5,8 @@ #include <libvirt/libvirt.h> #include <systemd/sd-bus.h> +#define VIRT_DBUS_DOMAIN_INTERFACE "org.libvirt.Domain" + int virtDBusDomainRegister(virtDBusConnect *connect, sd_bus *bus); diff --git a/src/events.c b/src/events.c index eee068c..681441d 100644 --- a/src/events.c +++ b/src/events.c @@ -85,7 +85,7 @@ virtDBusEventsDomainDeviceAdded(virConnectPtr connection VIRT_ATTR_UNUSED, r = sd_bus_message_new_signal(connect->bus, &message, path, - "org.libvirt.Domain", + VIRT_DBUS_DOMAIN_INTERFACE, "DeviceAdded"); if (r < 0) return r; @@ -113,7 +113,7 @@ virtDBusEventsDomainDeviceRemoved(virConnectPtr connection VIRT_ATTR_UNUSED, r = sd_bus_message_new_signal(connect->bus, &message, path, - "org.libvirt.Domain", + VIRT_DBUS_DOMAIN_INTERFACE, "DeviceRemoved"); if (r < 0) return r; @@ -143,7 +143,7 @@ virtDBusEventsDomainDiskChange(virConnectPtr connection VIRT_ATTR_UNUSED, r = sd_bus_message_new_signal(connect->bus, &message, path, - "org.libvirt.Domain", + VIRT_DBUS_DOMAIN_INTERFACE, "TrayChange"); if (r < 0) return r; @@ -187,7 +187,7 @@ virtDBusEventsDomainTrayChange(virConnectPtr connection VIRT_ATTR_UNUSED, r = sd_bus_message_new_signal(connect->bus, &message, path, - "org.libvirt.Domain", + VIRT_DBUS_DOMAIN_INTERFACE, "DiskChange"); if (r < 0) return r; -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:35PM +0100, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/domain.c | 2 +- src/domain.h | 2 ++ src/events.c | 8 ++++---- 3 files changed, 7 insertions(+), 5 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

The reply contains only two strings. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/events.c b/src/events.c index 681441d..420fe63 100644 --- a/src/events.c +++ b/src/events.c @@ -160,7 +160,7 @@ virtDBusEventsDomainDiskChange(virConnectPtr connection VIRT_ATTR_UNUSED, break; } - r = sd_bus_message_append(message, "ssss", device, reasonstr); + r = sd_bus_message_append(message, "ss", device, reasonstr); if (r < 0) return r; -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:36PM +0100, Pavel Hrdina wrote:
The reply contains only two strings.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/events.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/events.c b/src/events.c index 420fe63..0ece3ab 100644 --- a/src/events.c +++ b/src/events.c @@ -126,7 +126,7 @@ virtDBusEventsDomainDeviceRemoved(virConnectPtr connection VIRT_ATTR_UNUSED, } static int -virtDBusEventsDomainDiskChange(virConnectPtr connection VIRT_ATTR_UNUSED, +virtDBusEventsDomainTrayChange(virConnectPtr connection VIRT_ATTR_UNUSED, virDomainPtr domain, const char *device, int reason, @@ -168,7 +168,7 @@ virtDBusEventsDomainDiskChange(virConnectPtr connection VIRT_ATTR_UNUSED, } static int -virtDBusEventsDomainTrayChange(virConnectPtr connection VIRT_ATTR_UNUSED, +virtDBusEventsDomainDiskChange(virConnectPtr connection VIRT_ATTR_UNUSED, virDomainPtr domain, const char *old_src_path, const char *new_src_path, @@ -243,10 +243,10 @@ virtDBusEventsRegister(virtDBusConnect *connect) virtDBusEventsRegisterEvent(connect, VIR_DOMAIN_EVENT_ID_DISK_CHANGE, - VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainTrayChange)); + VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainDiskChange)); virtDBusEventsRegisterEvent(connect, VIR_DOMAIN_EVENT_ID_TRAY_CHANGE, - VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainDiskChange)); + VIR_DOMAIN_EVENT_CALLBACK(virtDBusEventsDomainTrayChange)); } -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:37PM +0100, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/events.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.c b/src/main.c index e0f9434..c4ad1e3 100644 --- a/src/main.c +++ b/src/main.c @@ -219,6 +219,10 @@ main(int argc, char *argv[]) virtDBusHandleSignal, NULL, NULL); + if (signal_watch < 0) { + fprintf(stderr, "Failed to register signal handler.\n"); + return EXIT_FAILURE; + } while (loop_status >= 0) virEventRunDefaultImpl(); -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:38PM +0100, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/main.c | 4 ++++ 1 file changed, 4 insertions(+)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index c4ad1e3..5dca7fb 100644 --- a/src/main.c +++ b/src/main.c @@ -198,7 +198,7 @@ main(int argc, char *argv[]) r = virtDBusConnectNew(&connect[i], bus, drivers[i].uri, drivers[i].object); if (r < 0) { - fprintf(stderr, "Failed to register libvirt connection."); + fprintf(stderr, "Failed to register libvirt connection.\n"); return EXIT_FAILURE; } } -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:39PM +0100, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- libvirt-dbus.spec.in | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libvirt-dbus.spec.in b/libvirt-dbus.spec.in index 572300f..87f20d4 100644 --- a/libvirt-dbus.spec.in +++ b/libvirt-dbus.spec.in @@ -2,6 +2,7 @@ %define libvirt_version @LIBVIRT_REQUIRED@ %define systemd_version @SYSTEMD_REQUIRED@ +%define system_user @SYSTEM_USER@ Name: @PACKAGE@ Version: @VERSION@ @@ -39,10 +40,10 @@ rm -rf $RPM_BUILD_ROOT rm -rf $RPM_BUILD_ROOT %pre -getent group libvirtdbus >/dev/null || groupadd -r libvirtdbus -getent passwd libvirtdbus >/dev/null || \ - useradd -r -g libvirtdbus -d / -s /sbin/nologin \ - -c "Libvirt DBus bridge" libvirtdbus +getent group %{system_user} >/dev/null || groupadd -r %{system_user} +getent passwd %{system_user} >/dev/null || \ + useradd -r -g %{system_user} -d / -s /sbin/nologin \ + -c "Libvirt DBus bridge" %{system_user} exit 0 %files -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:40PM +0100, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- libvirt-dbus.spec.in | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/connect.h | 21 ++++++++++++++------- src/domain.c | 1 + src/util.c | 42 +++++++++++++++++++++--------------------- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/connect.h b/src/connect.h index 9078ae7..1086bc6 100644 --- a/src/connect.h +++ b/src/connect.h @@ -20,10 +20,17 @@ struct virtDBusConnect { }; typedef struct virtDBusConnect virtDBusConnect; -int virtDBusConnectNew(virtDBusConnect **connectp, - sd_bus *bus, - const char *uri, - const char *connectPath); -virtDBusConnect *virtDBusConnectFree(virtDBusConnect *connect); -void virtDBusConnectFreep(virtDBusConnect **connectp); -void virtDBusConnectListFree(virtDBusConnect ***connectList); +int +virtDBusConnectNew(virtDBusConnect **connectp, + sd_bus *bus, + const char *uri, + const char *connectPath); + +virtDBusConnect * +virtDBusConnectFree(virtDBusConnect *connect); + +void +virtDBusConnectFreep(virtDBusConnect **connectp); + +void +virtDBusConnectListFree(virtDBusConnect ***connectList); diff --git a/src/domain.c b/src/domain.c index 850ea4a..c9365a4 100644 --- a/src/domain.c +++ b/src/domain.c @@ -1,4 +1,5 @@ #define _GNU_SOURCE + #include "domain.h" #include "util.h" diff --git a/src/util.c b/src/util.c index 3e6be4e..0d4d0e3 100644 --- a/src/util.c +++ b/src/util.c @@ -23,27 +23,27 @@ virtDBusUtilMessageAppendTypedParameters(sd_bus_message *message, return r; switch (parameters[i].type) { - case VIR_TYPED_PARAM_INT: - r = sd_bus_message_append(message, "v", "i", parameters[i].value.i); - break; - case VIR_TYPED_PARAM_UINT: - r = sd_bus_message_append(message, "v", "u", parameters[i].value.ui); - break; - case VIR_TYPED_PARAM_LLONG: - r = sd_bus_message_append(message, "v", "x", parameters[i].value.l); - break; - case VIR_TYPED_PARAM_ULLONG: - r = sd_bus_message_append(message, "v", "t", parameters[i].value.ul); - break; - case VIR_TYPED_PARAM_DOUBLE: - r = sd_bus_message_append(message, "v", "d", parameters[i].value.d); - break; - case VIR_TYPED_PARAM_BOOLEAN: - r = sd_bus_message_append(message, "v", "b", parameters[i].value.b); - break; - case VIR_TYPED_PARAM_STRING: - r = sd_bus_message_append(message, "v", "s", parameters[i].value.s); - break; + case VIR_TYPED_PARAM_INT: + r = sd_bus_message_append(message, "v", "i", parameters[i].value.i); + break; + case VIR_TYPED_PARAM_UINT: + r = sd_bus_message_append(message, "v", "u", parameters[i].value.ui); + break; + case VIR_TYPED_PARAM_LLONG: + r = sd_bus_message_append(message, "v", "x", parameters[i].value.l); + break; + case VIR_TYPED_PARAM_ULLONG: + r = sd_bus_message_append(message, "v", "t", parameters[i].value.ul); + break; + case VIR_TYPED_PARAM_DOUBLE: + r = sd_bus_message_append(message, "v", "d", parameters[i].value.d); + break; + case VIR_TYPED_PARAM_BOOLEAN: + r = sd_bus_message_append(message, "v", "b", parameters[i].value.b); + break; + case VIR_TYPED_PARAM_STRING: + r = sd_bus_message_append(message, "v", "s", parameters[i].value.s); + break; } if (r < 0) -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:41PM +0100, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/connect.h | 21 ++++++++++++++------- src/domain.c | 1 + src/util.c | 42 +++++++++++++++++++++--------------------- 3 files changed, 36 insertions(+), 28 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/connect.c | 1 - src/domain.c | 1 + src/domain.h | 1 - src/events.c | 1 + src/events.h | 3 --- src/main.c | 2 ++ src/util.c | 2 ++ src/util.h | 2 -- 8 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/connect.c b/src/connect.c index 45fb2ae..e93111f 100644 --- a/src/connect.c +++ b/src/connect.c @@ -3,7 +3,6 @@ #include "connect.h" #include "util.h" -#include <errno.h> #include <stdbool.h> #include <stdlib.h> diff --git a/src/domain.c b/src/domain.c index c9365a4..8e6489a 100644 --- a/src/domain.c +++ b/src/domain.c @@ -3,6 +3,7 @@ #include "domain.h" #include "util.h" +#include <libvirt/libvirt.h> #include <stdio.h> static int diff --git a/src/domain.h b/src/domain.h index 5ce592c..03a29ed 100644 --- a/src/domain.h +++ b/src/domain.h @@ -2,7 +2,6 @@ #include "connect.h" -#include <libvirt/libvirt.h> #include <systemd/sd-bus.h> #define VIRT_DBUS_DOMAIN_INTERFACE "org.libvirt.Domain" diff --git a/src/events.c b/src/events.c index 0ece3ab..c45acd7 100644 --- a/src/events.c +++ b/src/events.c @@ -3,6 +3,7 @@ #include "util.h" #include <assert.h> +#include <libvirt/libvirt.h> #include <systemd/sd-bus.h> static int diff --git a/src/events.h b/src/events.h index f588c85..c234c55 100644 --- a/src/events.h +++ b/src/events.h @@ -2,8 +2,5 @@ #include "connect.h" -#include <libvirt/libvirt.h> - - void virtDBusEventsRegister(virtDBusConnect *connect); diff --git a/src/main.c b/src/main.c index 5dca7fb..6f11aab 100644 --- a/src/main.c +++ b/src/main.c @@ -8,8 +8,10 @@ #include <poll.h> #include <stdbool.h> #include <stdio.h> +#include <stdlib.h> #include <sys/signalfd.h> #include <systemd/sd-bus.h> +#include <unistd.h> static int loop_status; diff --git a/src/util.c b/src/util.c index 0d4d0e3..9042a0f 100644 --- a/src/util.c +++ b/src/util.c @@ -1,6 +1,8 @@ #include "util.h" #include <libvirt/virterror.h> +#include <stdlib.h> +#include <unistd.h> int virtDBusUtilMessageAppendTypedParameters(sd_bus_message *message, diff --git a/src/util.h b/src/util.h index c92674f..2a6f7e2 100644 --- a/src/util.h +++ b/src/util.h @@ -1,9 +1,7 @@ #pragma once #include <libvirt/libvirt.h> -#include <stdlib.h> #include <systemd/sd-bus.h> -#include <unistd.h> #define VIRT_DBUS_ERROR_INTERFACE "org.libvirt.Error" -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:42PM +0100, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/connect.c | 1 - src/domain.c | 1 + src/domain.h | 1 - src/events.c | 1 + src/events.h | 3 --- src/main.c | 2 ++ src/util.c | 2 ++ src/util.h | 2 -- 8 files changed, 6 insertions(+), 7 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Fixes an bug that was introduced by <8e24f602>. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/connect.c | 2 +- src/connect.h | 4 ++++ src/domain.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/connect.c b/src/connect.c index e93111f..b31f08e 100644 --- a/src/connect.c +++ b/src/connect.c @@ -53,7 +53,7 @@ virtDBusConnectClose(virtDBusConnect *connect, connect->connection = NULL; } -static int +int virtDBusConnectOpen(virtDBusConnect *connect, sd_bus_error *error) { diff --git a/src/connect.h b/src/connect.h index 1086bc6..9e5f533 100644 --- a/src/connect.h +++ b/src/connect.h @@ -26,6 +26,10 @@ virtDBusConnectNew(virtDBusConnect **connectp, const char *uri, const char *connectPath); +int +virtDBusConnectOpen(virtDBusConnect *connect, + sd_bus_error *error); + virtDBusConnect * virtDBusConnectFree(virtDBusConnect *connect); diff --git a/src/domain.c b/src/domain.c index 8e6489a..3df9113 100644 --- a/src/domain.c +++ b/src/domain.c @@ -19,6 +19,9 @@ virtDBusDomainGetName(sd_bus *bus VIRT_ATTR_UNUSED, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; const char *name = ""; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, connect->domainPath); if (domain == NULL) @@ -44,6 +47,9 @@ virtDBusDomainGetUUID(sd_bus *bus VIRT_ATTR_UNUSED, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; char uuid[VIR_UUID_STRING_BUFLEN] = ""; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, connect->domainPath); if (domain == NULL) @@ -66,6 +72,9 @@ virtDBusDomainGetId(sd_bus *bus VIRT_ATTR_UNUSED, virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, connect->domainPath); if (domain == NULL) @@ -86,6 +95,9 @@ virtDBusDomainGetVcpus(sd_bus *bus VIRT_ATTR_UNUSED, virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, connect->domainPath); if (domain == NULL) @@ -107,6 +119,9 @@ virtDBusDomainGetOsType(sd_bus *bus VIRT_ATTR_UNUSED, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; _cleanup_(virtDBusUtilFreep) char *os_type = NULL; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, connect->domainPath); if (domain == NULL) @@ -132,6 +147,9 @@ virtDBusDomainGetActive(sd_bus *bus VIRT_ATTR_UNUSED, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int active; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, connect->domainPath); if (domain == NULL) @@ -157,6 +175,9 @@ virtDBusDomainGetPersistent(sd_bus *bus VIRT_ATTR_UNUSED, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int persistent; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, connect->domainPath); if (domain == NULL) @@ -183,6 +204,9 @@ virtDBusDomainGetState(sd_bus *bus VIRT_ATTR_UNUSED, int state = 0; const char *string; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, connect->domainPath); if (domain == NULL) @@ -234,6 +258,9 @@ virtDBusDomainGetAutostart(sd_bus *bus VIRT_ATTR_UNUSED, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int autostart = 0; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, connect->domainPath); if (domain == NULL) @@ -255,6 +282,9 @@ virtDBusDomainGetXMLDesc(sd_bus_message *message, uint32_t flags; int r; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, sd_bus_message_get_path(message), connect->domainPath); @@ -300,6 +330,9 @@ virtDBusDomainGetStats(sd_bus_message *message, if (r < 0) return r; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, sd_bus_message_get_path(message), connect->domainPath); @@ -336,6 +369,9 @@ virtDBusDomainShutdown(sd_bus_message *message, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int r; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, sd_bus_message_get_path(message), connect->domainPath); @@ -362,6 +398,9 @@ virtDBusDomainDestroy(sd_bus_message *message, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int r; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, sd_bus_message_get_path(message), connect->domainPath); @@ -393,6 +432,9 @@ virtDBusDomainReboot(sd_bus_message *message, if (r < 0) return r; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, sd_bus_message_get_path(message), connect->domainPath); @@ -424,6 +466,9 @@ virtDBusDomainReset(sd_bus_message *message, if (r < 0) return r; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, sd_bus_message_get_path(message), connect->domainPath); @@ -450,6 +495,9 @@ virtDBusDomainCreate(sd_bus_message *message, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int r; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, sd_bus_message_get_path(message), connect->domainPath); @@ -476,6 +524,9 @@ virtDBusDomainUndefine(sd_bus_message *message, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int r; + if (virtDBusConnectOpen(connect, error) < 0) + return -1; + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, sd_bus_message_get_path(message), connect->domainPath); -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:43PM +0100, Pavel Hrdina wrote:
Fixes an bug that was introduced by <8e24f602>.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/connect.c | 2 +- src/connect.h | 4 ++++ src/domain.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

There is no need to open connection if parsing arguments fails. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/connect.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/connect.c b/src/connect.c index b31f08e..695fc0d 100644 --- a/src/connect.c +++ b/src/connect.c @@ -120,11 +120,11 @@ virtDBusConnectListDomains(sd_bus_message *message, uint32_t flags; int r; - r = virtDBusConnectOpen(connect, error); + r = sd_bus_message_read(message, "u", &flags); if (r < 0) return r; - r = sd_bus_message_read(message, "u", &flags); + r = virtDBusConnectOpen(connect, error); if (r < 0) return r; @@ -170,11 +170,11 @@ virtDBusConnectCreateXML(sd_bus_message *message, _cleanup_(virtDBusUtilFreep) char *path = NULL; int r; - r = virtDBusConnectOpen(connect, error); + r = sd_bus_message_read(message, "su", &xml, &flags); if (r < 0) return r; - r = sd_bus_message_read(message, "su", &xml, &flags); + r = virtDBusConnectOpen(connect, error); if (r < 0) return r; @@ -198,11 +198,11 @@ virtDBusConnectDefineXML(sd_bus_message *message, _cleanup_(virtDBusUtilFreep) char *path = NULL; int r; - r = virtDBusConnectOpen(connect, error); + r = sd_bus_message_read(message, "s", &xml); if (r < 0) return r; - r = sd_bus_message_read(message, "s", &xml); + r = virtDBusConnectOpen(connect, error); if (r < 0) return r; -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:44PM +0100, Pavel Hrdina wrote:
There is no need to open connection if parsing arguments fails.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/connect.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

This is called for every API, create a function for it. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/domain.c | 220 ++++++++++++++++++++--------------------------------------- 1 file changed, 75 insertions(+), 145 deletions(-) diff --git a/src/domain.c b/src/domain.c index 3df9113..f68a3a0 100644 --- a/src/domain.c +++ b/src/domain.c @@ -6,6 +6,28 @@ #include <libvirt/libvirt.h> #include <stdio.h> +static virDomainPtr +virtDBusDomainGetVirDomain(virtDBusConnect *connect, + const char *path, + sd_bus_error *error) +{ + virDomainPtr domain; + + if (virtDBusConnectOpen(connect, error) < 0) + return NULL; + + domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, + connect->domainPath); + if (domain == NULL) { + sd_bus_error_setf(error, + SD_BUS_ERROR_UNKNOWN_OBJECT, + "Unknown object '%s'.", path); + return NULL; + } + + return domain; +} + static int virtDBusDomainGetName(sd_bus *bus VIRT_ATTR_UNUSED, const char *path, @@ -19,13 +41,9 @@ virtDBusDomainGetName(sd_bus *bus VIRT_ATTR_UNUSED, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; const char *name = ""; - if (virtDBusConnectOpen(connect, error) < 0) - return -1; - - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, - connect->domainPath); + domain = virtDBusDomainGetVirDomain(connect, path, error); if (domain == NULL) - return sd_bus_message_append(reply, "s", ""); + return -1; name = virDomainGetName(domain); if (name == NULL) @@ -47,13 +65,9 @@ virtDBusDomainGetUUID(sd_bus *bus VIRT_ATTR_UNUSED, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; char uuid[VIR_UUID_STRING_BUFLEN] = ""; - if (virtDBusConnectOpen(connect, error) < 0) - return -1; - - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, - connect->domainPath); + domain = virtDBusDomainGetVirDomain(connect, path, error); if (domain == NULL) - return sd_bus_message_append(reply, "s", ""); + return -1; virDomainGetUUIDString(domain, uuid); @@ -72,13 +86,9 @@ virtDBusDomainGetId(sd_bus *bus VIRT_ATTR_UNUSED, virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; - if (virtDBusConnectOpen(connect, error) < 0) - return -1; - - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, - connect->domainPath); + domain = virtDBusDomainGetVirDomain(connect, path, error); if (domain == NULL) - return sd_bus_message_append(reply, "u", 0); + return -1; return sd_bus_message_append(reply, "u", virDomainGetID(domain)); } @@ -95,13 +105,9 @@ virtDBusDomainGetVcpus(sd_bus *bus VIRT_ATTR_UNUSED, virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; - if (virtDBusConnectOpen(connect, error) < 0) - return -1; - - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, - connect->domainPath); + domain = virtDBusDomainGetVirDomain(connect, path, error); if (domain == NULL) - return sd_bus_message_append(reply, "u", 0); + return -1; return sd_bus_message_append(reply, "u", virDomainGetVcpusFlags(domain, VIR_DOMAIN_VCPU_CURRENT)); } @@ -119,13 +125,9 @@ virtDBusDomainGetOsType(sd_bus *bus VIRT_ATTR_UNUSED, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; _cleanup_(virtDBusUtilFreep) char *os_type = NULL; - if (virtDBusConnectOpen(connect, error) < 0) - return -1; - - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, - connect->domainPath); + domain = virtDBusDomainGetVirDomain(connect, path, error); if (domain == NULL) - return sd_bus_message_append(reply, "s", ""); + return -1; os_type = virDomainGetOSType(domain); if (os_type == NULL) @@ -147,13 +149,9 @@ virtDBusDomainGetActive(sd_bus *bus VIRT_ATTR_UNUSED, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int active; - if (virtDBusConnectOpen(connect, error) < 0) - return -1; - - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, - connect->domainPath); + domain = virtDBusDomainGetVirDomain(connect, path, error); if (domain == NULL) - return sd_bus_message_append(reply, "b", 0); + return -1; active = virDomainIsActive(domain); if (active < 0) @@ -175,13 +173,9 @@ virtDBusDomainGetPersistent(sd_bus *bus VIRT_ATTR_UNUSED, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int persistent; - if (virtDBusConnectOpen(connect, error) < 0) - return -1; - - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, - connect->domainPath); + domain = virtDBusDomainGetVirDomain(connect, path, error); if (domain == NULL) - return sd_bus_message_append(reply, "b", 0); + return -1; persistent = virDomainIsPersistent(domain); if (persistent < 0) @@ -204,13 +198,9 @@ virtDBusDomainGetState(sd_bus *bus VIRT_ATTR_UNUSED, int state = 0; const char *string; - if (virtDBusConnectOpen(connect, error) < 0) - return -1; - - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, - connect->domainPath); + domain = virtDBusDomainGetVirDomain(connect, path, error); if (domain == NULL) - return sd_bus_message_append(reply, "s", ""); + return -1; virDomainGetState(domain, &state, NULL, 0); @@ -258,13 +248,9 @@ virtDBusDomainGetAutostart(sd_bus *bus VIRT_ATTR_UNUSED, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int autostart = 0; - if (virtDBusConnectOpen(connect, error) < 0) - return -1; - - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, - connect->domainPath); + domain = virtDBusDomainGetVirDomain(connect, path, error); if (domain == NULL) - return sd_bus_message_append(reply, "b", 0); + return -1; virDomainGetAutostart(domain, &autostart); @@ -282,23 +268,16 @@ virtDBusDomainGetXMLDesc(sd_bus_message *message, uint32_t flags; int r; - if (virtDBusConnectOpen(connect, error) < 0) - return -1; - - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, - sd_bus_message_get_path(message), - connect->domainPath); - if (domain == NULL) { - return sd_bus_reply_method_errorf(message, - SD_BUS_ERROR_UNKNOWN_OBJECT, - "Unknown object '%s'.", - sd_bus_message_get_path(message)); - } - r = sd_bus_message_read(message, "u", &flags); if (r < 0) return r; + domain = virtDBusDomainGetVirDomain(connect, + sd_bus_message_get_path(message), + error); + if (domain == NULL) + return -1; + description = virDomainGetXMLDesc(domain, flags); if (!description) return virtDBusUtilSetLastVirtError(error); @@ -330,19 +309,12 @@ virtDBusDomainGetStats(sd_bus_message *message, if (r < 0) return r; - if (virtDBusConnectOpen(connect, error) < 0) + domain = virtDBusDomainGetVirDomain(connect, + sd_bus_message_get_path(message), + error); + if (domain == NULL) return -1; - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, - sd_bus_message_get_path(message), - connect->domainPath); - if (domain == NULL) { - return sd_bus_reply_method_errorf(message, - SD_BUS_ERROR_UNKNOWN_OBJECT, - "Unknown object '%s'.", - sd_bus_message_get_path(message)); - } - domains[0] = domain; domains[1] = NULL; @@ -369,19 +341,12 @@ virtDBusDomainShutdown(sd_bus_message *message, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int r; - if (virtDBusConnectOpen(connect, error) < 0) + domain = virtDBusDomainGetVirDomain(connect, + sd_bus_message_get_path(message), + error); + if (domain == NULL) return -1; - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, - sd_bus_message_get_path(message), - connect->domainPath); - if (domain == NULL) { - return sd_bus_reply_method_errorf(message, - SD_BUS_ERROR_UNKNOWN_OBJECT, - "Unknown object '%s'.", - sd_bus_message_get_path(message)); - } - r = virDomainShutdown(domain); if (r < 0) return virtDBusUtilSetLastVirtError(error); @@ -398,19 +363,12 @@ virtDBusDomainDestroy(sd_bus_message *message, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int r; - if (virtDBusConnectOpen(connect, error) < 0) + domain = virtDBusDomainGetVirDomain(connect, + sd_bus_message_get_path(message), + error); + if (domain == NULL) return -1; - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, - sd_bus_message_get_path(message), - connect->domainPath); - if (domain == NULL) { - return sd_bus_reply_method_errorf(message, - SD_BUS_ERROR_UNKNOWN_OBJECT, - "Unknown object '%s'.", - sd_bus_message_get_path(message)); - } - r = virDomainDestroy(domain); if (r < 0) return virtDBusUtilSetLastVirtError(error); @@ -432,19 +390,12 @@ virtDBusDomainReboot(sd_bus_message *message, if (r < 0) return r; - if (virtDBusConnectOpen(connect, error) < 0) + domain = virtDBusDomainGetVirDomain(connect, + sd_bus_message_get_path(message), + error); + if (domain == NULL) return -1; - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, - sd_bus_message_get_path(message), - connect->domainPath); - if (domain == NULL) { - return sd_bus_reply_method_errorf(message, - SD_BUS_ERROR_UNKNOWN_OBJECT, - "Unknown object '%s'.", - sd_bus_message_get_path(message)); - } - r = virDomainReboot(domain, flags); if (r < 0) return virtDBusUtilSetLastVirtError(error); @@ -466,19 +417,12 @@ virtDBusDomainReset(sd_bus_message *message, if (r < 0) return r; - if (virtDBusConnectOpen(connect, error) < 0) + domain = virtDBusDomainGetVirDomain(connect, + sd_bus_message_get_path(message), + error); + if (domain == NULL) return -1; - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, - sd_bus_message_get_path(message), - connect->domainPath); - if (domain == NULL) { - return sd_bus_reply_method_errorf(message, - SD_BUS_ERROR_UNKNOWN_OBJECT, - "Unknown object '%s'.", - sd_bus_message_get_path(message)); - } - r = virDomainReset(domain, flags); if (r < 0) return virtDBusUtilSetLastVirtError(error); @@ -495,19 +439,12 @@ virtDBusDomainCreate(sd_bus_message *message, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int r; - if (virtDBusConnectOpen(connect, error) < 0) + domain = virtDBusDomainGetVirDomain(connect, + sd_bus_message_get_path(message), + error); + if (domain == NULL) return -1; - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, - sd_bus_message_get_path(message), - connect->domainPath); - if (domain == NULL) { - return sd_bus_reply_method_errorf(message, - SD_BUS_ERROR_UNKNOWN_OBJECT, - "Unknown object '%s'.", - sd_bus_message_get_path(message)); - } - r = virDomainCreate(domain); if (r < 0) return virtDBusUtilSetLastVirtError(error); @@ -524,19 +461,12 @@ virtDBusDomainUndefine(sd_bus_message *message, _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int r; - if (virtDBusConnectOpen(connect, error) < 0) + domain = virtDBusDomainGetVirDomain(connect, + sd_bus_message_get_path(message), + error); + if (domain == NULL) return -1; - domain = virtDBusUtilVirDomainFromBusPath(connect->connection, - sd_bus_message_get_path(message), - connect->domainPath); - if (domain == NULL) { - return sd_bus_reply_method_errorf(message, - SD_BUS_ERROR_UNKNOWN_OBJECT, - "Unknown object '%s'.", - sd_bus_message_get_path(message)); - } - r = virDomainUndefine(domain); if (r < 0) return virtDBusUtilSetLastVirtError(error); @@ -594,7 +524,7 @@ virtDBusDomainLookup(sd_bus *bus VIRT_ATTR_UNUSED, if (*name == '\0') return 0; - domain = virDomainLookupByUUIDString(connect->connection, name); + domain = virtDBusDomainGetVirDomain(connect, path, error); if (!domain) return 0; -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:45PM +0100, Pavel Hrdina wrote:
This is called for every API, create a function for it.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/domain.c | 220 ++++++++++++++++++++--------------------------------------- 1 file changed, 75 insertions(+), 145 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

We will switch to libdbus library because the systemd sd-bus implementation is not thread safe. Processing messages in threads is essential since Libvirt API can take some significant amount of time to return and that would block the whole libvirt-dbus daemon. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- README | 1 + configure.ac | 13 + data/Makefile.am | 5 + libvirt-dbus.spec.in | 3 + src/Makefile.am | 11 +- src/dbus.c | 1226 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/dbus.h | 158 +++++++ src/domain.c | 8 - src/util.c | 131 +++++- src/util.h | 11 + test/Makefile.am | 3 +- test/travis-run | 2 +- 12 files changed, 1554 insertions(+), 18 deletions(-) create mode 100644 src/dbus.c create mode 100644 src/dbus.h diff --git a/README b/README index 754d957..242c9ba 100644 --- a/README +++ b/README @@ -57,6 +57,7 @@ raised in future releases based on this distro build target policy. The packages required to build libvirt-dbus are - systemd-211 + - dbus - libvirt Patches submissions diff --git a/configure.ac b/configure.ac index aef3d37..c8dcf04 100644 --- a/configure.ac +++ b/configure.ac @@ -13,8 +13,10 @@ AM_SILENT_RULES([yes]) LIBVIRT_REQUIRED=1.2.8 SYSTEMD_REQUIRED=211 +DBUS_REQUIRED=1.10.24 AC_SUBST([LIBVIRT_REQUIRED]) dnl used in the .spec file AC_SUBST([SYSTEMD_REQUIRED]) dnl used in the .spec file +AC_SUBST([DBUS_REQUIRED]) dnl used in the .spec file LIBVIRT_DBUS_MAJOR_VERSION=`echo $VERSION | awk -F. '{print $1}'` LIBVIRT_DBUS_MINOR_VERSION=`echo $VERSION | awk -F. '{print $2}'` @@ -35,6 +37,7 @@ AM_PROG_CC_C_O PKG_CHECK_MODULES(LIBVIRT, libvirt >= $LIBVIRT_REQUIRED) PKG_CHECK_MODULES(SYSTEMD, libsystemd >= $SYSTEMD_REQUIRED) +PKG_CHECK_MODULES(DBUS, dbus-1 >= $DBUS_REQUIRED) LIBVIRT_COMPILE_WARNINGS LIBVIRT_LINKER_RELRO @@ -70,6 +73,16 @@ else fi AC_SUBST(DBUS_SYSTEM_POLICIES_DIR) +AC_ARG_WITH(dbus-interfaces, + [AC_HELP_STRING([--with-dbus-interfaces=<dir>], + [where D-BUS interfaces directory is])]) +if ! test -z "$with_dbus_interfaces" ; then + DBUS_INTERFACES_DIR="with_dbus_interfaces" +else + DBUS_INTERFACES_DIR="$datadir/dbus-1/interfaces" +fi +AC_SUBST(DBUS_INTERFACES_DIR) + LIBVIRT_ARG_WITH([SYSTEM_USER], [username to run system instance as], ['libvirtdbus']) SYSTEM_USER=$with_system_user diff --git a/data/Makefile.am b/data/Makefile.am index 9a53305..a886687 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -18,11 +18,16 @@ polkit_files = \ polkitdir = $(sysconfdir)/polkit-1/rules.d polkit_DATA = $(polkit_files:.rules.in=.rules) +interfaces_files = +interfacesdir = $(DBUS_INTERFACES_DIR) +interfaces_DATA = $(interfaces_files) + EXTRA_DIST = \ $(service_in_files) \ $(system_service_in_files) \ $(system_policy_files) \ $(polkit_files) \ + $(interfaces_files) \ $(NULL) CLEANFILES = \ diff --git a/libvirt-dbus.spec.in b/libvirt-dbus.spec.in index 87f20d4..512f4fc 100644 --- a/libvirt-dbus.spec.in +++ b/libvirt-dbus.spec.in @@ -2,6 +2,7 @@ %define libvirt_version @LIBVIRT_REQUIRED@ %define systemd_version @SYSTEMD_REQUIRED@ +%define dbus_version @DBUS_REQUIRED@ %define system_user @SYSTEM_USER@ Name: @PACKAGE@ @@ -16,9 +17,11 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: libvirt-devel >= %{libvirt_version} BuildRequires: systemd-devel >= %{systemd_version} +BuildRequires: dbus-devel >= %{dbus_version} Requires: libvirt-libs >= %{libvirt_version} Requires: systemd-libs >= %{systemd_version} +Requires: dbus-libs >= %{dbus_version} Requires(pre): shadow-utils diff --git a/src/Makefile.am b/src/Makefile.am index 1a5b50b..1f0d990 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,12 +1,16 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src +AM_CPPFLAGS += \ + -DVIRT_DBUS_INTERFACES_DIR=\"$(DBUS_INTERFACES_DIR)\" + DAEMON_SOURCES = \ main.c \ connect.c connect.h \ util.c util.h \ domain.c domain.h \ - events.c events.h + events.c events.h \ + dbus.c dbus.h EXTRA_DIST = \ $(DAEMON_SOURCES) @@ -19,6 +23,7 @@ libvirt_dbus_SOURCES = $(DAEMON_SOURCES) libvirt_dbus_CFLAGS = \ $(SYSTEMD_CFLAGS) \ $(LIBVIRT_CFLAGS) \ + $(DBUS_CFLAGS) \ $(WARN_CFLAGS) \ $(PIE_CFLAGS) \ $(NULL) @@ -26,10 +31,12 @@ libvirt_dbus_CFLAGS = \ libvirt_dbus_LDFLAGS = \ $(SYSTEMD_LDFLAGS) \ $(LIBVIRT_LDFLAGS) \ + $(DBUS_LDFLAGS) \ $(RELRO_LDFLAGS) \ $(PID_LDFLAGS) \ $(NULL) libvirt_dbus_LDADD = \ $(SYSTEMD_LIBS) \ - $(LIBVIRT_LIBS) + $(LIBVIRT_LIBS) \ + $(DBUS_LIBS) diff --git a/src/dbus.c b/src/dbus.c new file mode 100644 index 0000000..327ae12 --- /dev/null +++ b/src/dbus.c @@ -0,0 +1,1226 @@ +#define _GNU_SOURCE + +#include "dbus.h" +#include "util.h" + +#include <libvirt/virterror.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +struct _virtDBusMessage { + DBusMessage *message; + DBusConnection *bus; + DBusError *error; + DBusMessageIter **stack; + size_t items; + size_t size; +}; + +struct _virtDBusObject { + char *path; + const char **introspectXML; + const char *interface; + virtDBusObjectType type; + virtDBusPropertyHandlers *properties; + virtDBusMethodHandlers *methods; + void *data; +}; + +static int +virtDBusGetLibvirtEvents(DBusWatch *watch) +{ + unsigned int events; + int virt_events = 0; + + events = dbus_watch_get_flags(watch); + + if (events & DBUS_WATCH_READABLE) + virt_events |= VIR_EVENT_HANDLE_READABLE; + + if (events & DBUS_WATCH_WRITABLE) + virt_events |= VIR_EVENT_HANDLE_WRITABLE; + + return virt_events; +} + +static unsigned int +virtDBusGetBusEvents(int virt_events) +{ + unsigned int events = 0; + + if (virt_events & VIR_EVENT_HANDLE_READABLE) + events |= DBUS_WATCH_READABLE; + + if (virt_events & VIR_EVENT_HANDLE_WRITABLE) + events |= DBUS_WATCH_WRITABLE; + + return events; +} + +static void +virtDBusHandleBusEvent(int watch VIRT_ATTR_UNUSED, + int fd VIRT_ATTR_UNUSED, + int events, + void *opaque) +{ + dbus_watch_handle(opaque, virtDBusGetBusEvents(events)); +} + +static void +virtDBusHandleBusTimeout(int timer VIRT_ATTR_UNUSED, + void *opaque) +{ + dbus_timeout_handle(opaque); +} + +static dbus_bool_t +virtDBusWatchUpdate(DBusWatch *watch) +{ + _cleanup_(virtDBusUtilFreep) int *busWatch = dbus_watch_get_data(watch); + dbus_bool_t enabled = dbus_watch_get_enabled(watch); + + if (enabled && !busWatch) { + busWatch = calloc(1, sizeof(int)); + if (!busWatch) + return FALSE; + + *busWatch = virEventAddHandle(dbus_watch_get_unix_fd(watch), + virtDBusGetLibvirtEvents(watch), + virtDBusHandleBusEvent, + watch, + NULL); + if (*busWatch < 0) + return FALSE; + + dbus_watch_set_data(watch, busWatch, free); + } else if (!enabled && busWatch != NULL) { + virEventRemoveHandle(*busWatch); + dbus_watch_set_data(watch, NULL, NULL); + } else if (busWatch) { + virEventUpdateHandle(*busWatch, virtDBusGetLibvirtEvents(watch)); + } + + busWatch = NULL; + return TRUE; +} + +static dbus_bool_t +virtDBusAddWatch(DBusWatch *watch, + void *data VIRT_ATTR_UNUSED) +{ + return virtDBusWatchUpdate(watch); +} + +static void +virtDBusUpdateWatch(DBusWatch *watch, + void *data VIRT_ATTR_UNUSED) +{ + virtDBusWatchUpdate(watch); +} + +static void +virtDBusRemoveWatch(DBusWatch *watch, + void *data VIRT_ATTR_UNUSED) +{ + int *busWatch; + + busWatch = dbus_watch_get_data(watch); + if (busWatch) + virEventRemoveHandle(*busWatch); + + dbus_watch_set_data(watch, NULL, NULL); +} + +static dbus_bool_t +virtDBusTimeoutUpdate(DBusTimeout *timeout) +{ + _cleanup_(virtDBusUtilFreep) int *busTimeout = dbus_timeout_get_data(timeout); + dbus_bool_t enabled = dbus_timeout_get_enabled(timeout); + + if (enabled && !busTimeout) { + busTimeout = calloc(1, sizeof(int)); + if (!busTimeout) + return FALSE; + + *busTimeout = virEventAddTimeout(dbus_timeout_get_interval(timeout), + virtDBusHandleBusTimeout, + timeout, + NULL); + if (*busTimeout < 0) + return FALSE; + + dbus_timeout_set_data(timeout, busTimeout, free); + } else if (!enabled && busTimeout != NULL) { + virEventRemoveTimeout(*busTimeout); + dbus_timeout_set_data(timeout, NULL, NULL); + } else if (busTimeout) { + virEventUpdateTimeout(*busTimeout, dbus_timeout_get_interval(timeout)); + } + + busTimeout = NULL; + return TRUE; +} + +static dbus_bool_t +virtDBusAddTimeout(DBusTimeout *timeout, + void *data VIRT_ATTR_UNUSED) +{ + return virtDBusTimeoutUpdate(timeout); +} + +static void +virtDBusUpdateTimeout(DBusTimeout *timeout, + void *data VIRT_ATTR_UNUSED) +{ + virtDBusTimeoutUpdate(timeout); +} + +static void +virtDBusRemoveTimeout(DBusTimeout *timeout, + void *data VIRT_ATTR_UNUSED) +{ + int *busTimeout; + + busTimeout = dbus_timeout_get_data(timeout); + if (busTimeout) + virEventRemoveTimeout(*busTimeout); + + dbus_timeout_set_data(timeout, NULL, NULL); +} + +/** + * virtDBusConnectionOpen: + * @busType which bus type to use for D-Bus connection + * @name name of the service to register + * + * Opens a D-Bus connection and registers necessary callbacks + * into Libvirt event loop. + * + * Returns D-Bus connection on success, NULL on failure. The returned + * connection needs to be freed and closed using virtDBusConnectionClose(). + */ +DBusConnection * +virtDBusConnectionOpen(DBusBusType busType, + const char *name) +{ + _cleanup_(dbus_error_free) DBusError error = DBUS_ERROR_INIT; + _cleanup_(virtDBusConnectionClose) DBusConnection *bus = NULL; + DBusConnection *ret; + int r; + + if (!dbus_threads_init(NULL)) { + fprintf(stderr, "Failed to initialize dbus threads.\n"); + return NULL; + } + + bus = dbus_bus_get_private(busType, &error); + + if (!bus) { + fprintf(stderr, "Failed to connect to session bus: %s\n", error.message); + return NULL; + } + + r = dbus_bus_request_name(bus, name, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error); + if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + fprintf(stderr, "Failed to acquire service name: %s\n", error.message); + return NULL; + } + + if (!dbus_connection_set_watch_functions(bus, virtDBusAddWatch, + virtDBusRemoveWatch, + virtDBusUpdateWatch, + dbus_connection_ref(bus), + (DBusFreeFunction)dbus_connection_unref)) { + fprintf(stderr, "Failed to register watch functions.\n"); + return NULL; + } + + if (!dbus_connection_set_timeout_functions(bus, virtDBusAddTimeout, + virtDBusRemoveTimeout, + virtDBusUpdateTimeout, + dbus_connection_ref(bus), + (DBusFreeFunction)dbus_connection_unref)) { + fprintf(stderr, "Failed to register timeout functions.\n"); + return NULL; + } + + VIRT_STEAL_PTR(ret, bus); + return ret; +} + +static int +virtDBusObjectListExpand(virtDBusObjectList *objectList, + size_t len) +{ + virtDBusObject **newList; + + newList = reallocarray(objectList->objects, + objectList->len + len, + sizeof(virtDBusObject *)); + if (!newList) + return -1; + + objectList->objects = newList; + objectList->len += len; + return 0; +} + +/** + * virtDBusObjectListRegister: + * @objectList a list of objects + * @path object path of object preffix, depends on @type + * @introspectXML where to store object interface XML + * @interface name of the interface + * @type whether the @path is an object or prefix of an object + * @properties pointer to structure that lists all properties, can be NULL + * @methods pointer to structure that lists all methods, can be NULL + * @data user data that are passed to properties or methods handlers + * + * Registers a D-Bus object that we need to handle. + * + * Returns 0 on success, -1 on failure. + */ +int +virtDBusObjectListRegister(virtDBusObjectList *objectList, + const char *path, + const char **introspectXML, + const char *interface, + virtDBusObjectType type, + virtDBusPropertyHandlers *properties, + virtDBusMethodHandlers *methods, + void *data) +{ + _cleanup_(virtDBusObjectFreep) virtDBusObject *newObject = NULL; + + if (!objectList) + return -1; + + newObject = calloc(1, sizeof(virtDBusObject)); + if (!newObject) + return -1; + + newObject->path = strdup(path); + if (!newObject->path) + return -1; + + newObject->introspectXML = introspectXML; + newObject->interface = interface; + newObject->type = type; + newObject->properties = properties; + newObject->methods = methods; + newObject->data = data; + + if (virtDBusObjectListExpand(objectList, 1) < 0) + return -1; + + objectList->objects[objectList->len -1] = newObject; + newObject = NULL; + + return 0; +} + +static void +virtDBusMessageUnref(DBusMessage **messagep) +{ + if (*messagep) + dbus_message_unref(*messagep); +} + +static void +virtDBusMessageIterFreep(DBusMessageIter **iterp) +{ + if (*iterp) + free(*iterp); +} + +static DBusMessageIter * +virtDBusMessageIterPop(virtDBusMessage *msg) +{ + DBusMessageIter *iter; + size_t pos; + + if (msg->items == 0) + return NULL; + + pos = msg->items - 1; + + VIRT_STEAL_PTR(iter, msg->stack[pos]); + + msg->items -= 1; + + return iter; +} + +static DBusMessageIter * +virtDBusMessageIterPeek(virtDBusMessage *msg) +{ + if (msg->items == 0) + return NULL; + + return msg->stack[msg->items - 1]; +} + +static int +virtDBusMessageIterPush(virtDBusMessage *msg, + DBusMessageIter *iter) +{ + DBusMessageIter **newStack = NULL; + + if (msg->items >= msg->size) { + newStack = reallocarray(msg->stack, msg->items + 1, + sizeof(DBusMessageIter *)); + if (!newStack) + return -1; + + msg->stack = newStack; + msg->size += 1; + } + + msg->stack[msg->items] = iter; + msg->items += 1; + + return 0; +} + +static virtDBusMessage * +virtDBusMessageNew(DBusMessage *message, + DBusConnection *bus, + DBusError *error) +{ + _cleanup_(virtDBusMessageFreep) virtDBusMessage *new = NULL; + _cleanup_(virtDBusMessageIterFreep) DBusMessageIter *iter = NULL; + virtDBusMessage *ret; + + new = calloc(1, sizeof(virtDBusMessage)); + if (!new) + return NULL; + + new->message = dbus_message_ref(message); + new->bus = bus; + new->error = error; + + iter = calloc(1, sizeof(DBusMessageIter)); + if (!iter) + return NULL; + + dbus_message_iter_init(new->message, iter); + + if (virtDBusMessageIterPush(new, iter) < 0) + return NULL; + + iter = NULL; + + VIRT_STEAL_PTR(ret, new); + return ret; +} + +/** + * virtDBusMessageMethodReturn: + * @msg: D-Bus message that we would like to reply to. + * + * Creates a new D-Bus message that will be send as reply to a method call. + * + * Returns new D-Bus message on success, NULL on failure. The returned + * message needs to be freed using virtDBusMessageFreep(). + */ +virtDBusMessage * +virtDBusMessageMethodReturn(virtDBusMessage *msg) +{ + _cleanup_(virtDBusMessageFreep) virtDBusMessage *new = NULL; + _cleanup_(virtDBusMessageIterFreep) DBusMessageIter *iter = NULL; + virtDBusMessage *ret; + + new = calloc(1, sizeof(virtDBusMessage)); + if (!new) + return NULL; + + new->message = dbus_message_new_method_return(msg->message); + if (!new->message) + return NULL; + + new->bus = msg->bus; + new->error = msg->error; + + iter = calloc(1, sizeof(DBusMessageIter)); + if (!iter) + return NULL; + + dbus_message_iter_init_append(new->message, iter); + + if (virtDBusMessageIterPush(new, iter) < 0) + return NULL; + + iter = NULL; + + VIRT_STEAL_PTR(ret, new); + return ret; +} + +/** + * virtDBusMessageNewSignal: + * @bus: D-Bus connection where we want to send the signal to + * @path: an object path to which this signal is related + * @interface: interface of the object + * @signal: a signal name + * + * Creates a new D-Bus message that will be send to specified D-Bus + * connection as a signal. + * + * Returns new D-Bus message on success, NULL on failure. The returned + * message needs to be freed using virtDBusMessageFreep(). + */ +virtDBusMessage * +virtDBusMessageNewSignal(DBusConnection *bus, + const char *path, + const char *interface, + const char *signal) +{ + _cleanup_(virtDBusMessageFreep) virtDBusMessage *new = NULL; + _cleanup_(virtDBusMessageIterFreep) DBusMessageIter *iter = NULL; + virtDBusMessage *ret; + + new = calloc(1, sizeof(virtDBusMessage)); + if (!new) + return NULL; + + new->message = dbus_message_new_signal(path, interface, signal); + if (!new->message) + return NULL; + + new->bus = bus; + + iter = calloc(1, sizeof(DBusMessageIter)); + if (!iter) + return NULL; + + dbus_message_iter_init_append(new->message, iter); + + if (virtDBusMessageIterPush(new, iter) < 0) + return NULL; + + iter = NULL; + + VIRT_STEAL_PTR(ret, new); + return ret; +} + +/** + * virtDBusMessageAppendBasic: + * @msg: D-Bus reply message where to append the @value + * @type: type of the appended @value + * @value: pointer to a variable where the value is stored + * + * Appends a basic value into the reply message. + * + * Returns 0 on success, -1 on failure. + */ +int +virtDBusMessageAppendBasic(virtDBusMessage *msg, + int type, + const void *value) +{ + DBusMessageIter *iter = virtDBusMessageIterPeek(msg); + + if (!iter) + return -1; + + if (!dbus_message_iter_append_basic(iter, type, value)) + return -1; + + return 0; +} + +/** + * virtDBusMessageReadBasic: + * @msg: D-Bus message that we would like to parse + * @type: type of the value the we expect to read + * @value: pointer to a variable where we want to store the @value + * + * Reads a basic value from incoming D-Bus message and stores it + * into provided variable. + * + * Returns 0 on success if there is no value left for reading, + * 1 on success if value was read and -1 on failure. If used + * to read values from array 0 indicates that there are no other + * values left in the array. + */ +int +virtDBusMessageReadBasic(virtDBusMessage *msg, + int type, + void *value) +{ + DBusMessageIter *iter = virtDBusMessageIterPeek(msg); + int msgType; + + if (!iter) + return -1; + + msgType = dbus_message_iter_get_arg_type(iter); + if (msg->items > 1 && msgType == DBUS_TYPE_INVALID) + return 0; + + if (msgType != type) { + return virtDBusMessageSetError(msg, DBUS_ERROR_INVALID_ARGS, + "Expecting argument of type '%c', " + "but is actually of type '%c'.", + type, msgType); + } + + dbus_message_iter_get_basic(iter, value); + + dbus_message_iter_next(iter); + + return 1; +} + +/** + * virtDBusMessageOpenContainer: + * @msg: D-Bus reply message where to create a new container + * @type: type of the container that we are about to create + * @sig: signature of the container's content + * + * Creates a new container in the reply message, this needs to be + * followed by virtDBusMessageCloseContainer() when all values + * were written into it. + * + * Returns 0 on success, -1 on failure. + */ +int +virtDBusMessageOpenContainer(virtDBusMessage *msg, + int type, + const char *sig) +{ + DBusMessageIter *iter = virtDBusMessageIterPeek(msg); + _cleanup_(virtDBusMessageIterFreep) DBusMessageIter *cont = NULL; + + if (!iter) + return -1; + + cont = calloc(1, sizeof(DBusMessageIter)); + if (!cont) + return -1; + + if (!dbus_message_iter_open_container(iter, type, sig, cont)) + return -1; + + if (virtDBusMessageIterPush(msg, cont) < 0) + return -1; + + cont = NULL; + + return 0; +} + +/** + * virtDBusMessageEnterContainer: + * @msg: D-Bus message that we would like to parse + * @type: type of the container the we expect to read + * @sig: signature of the container's content + * + * Enters into a container from the message that we are parsing. + * When we are done reading the container we need to leave it using + * virtDBusMessageExitContainer(). + * + * Returns 0 on success if there is no container left for reading, + * 1 on success if container was entered and -1 on failure. If used + * to enter into container from array 0 indicates that there are no + * other containers left in the array. + */ +int +virtDBusMessageEnterContainer(virtDBusMessage *msg, + int type, + const char *sig) +{ + DBusMessageIter *iter = virtDBusMessageIterPeek(msg); + _cleanup_(virtDBusMessageIterFreep) DBusMessageIter *cont = NULL; + _cleanup_(virtDBusUtilFreep) char *msgSig = NULL; + int msgType; + + if (!iter) + return -1; + + msgType = dbus_message_iter_get_arg_type(iter); + if (msg->items > 1 && msgType == DBUS_TYPE_INVALID) + return 0; + + if (msgType != type) { + return virtDBusMessageSetError(msg, DBUS_ERROR_INVALID_ARGS, + "Expecting argument of type '%c', " + "but is actually of type '%c'.", + type, msgType); + } + + + cont = calloc(1, sizeof(DBusMessageIter)); + if (!cont) + return -1; + + dbus_message_iter_recurse(iter, cont); + + msgSig = dbus_message_iter_get_signature(cont); + + if (strcmp(sig, msgSig) != 0) { + return virtDBusMessageSetError(msg, DBUS_ERROR_INVALID_ARGS, + "Invalid container signature '%s', " + "expected signature '%s'.", + sig, msgSig); + } + + if (virtDBusMessageIterPush(msg, cont) < 0) + return -1; + + cont = NULL; + + return 1; +} + +/** + * virtDBusMessageCloseContainer: + * @msg: D-Bus reply message where we are done creating new container + * + * Closes a newly created container in a reply message. + * + * Returns 0 on success, -1 on failure. + */ +int +virtDBusMessageCloseContainer(virtDBusMessage *msg) +{ + _cleanup_(virtDBusMessageIterFreep) DBusMessageIter *cont = virtDBusMessageIterPop(msg); + DBusMessageIter *iter = virtDBusMessageIterPeek(msg); + + if (!cont || !iter) + return -1; + + if (!dbus_message_iter_close_container(iter, cont)) + return -1; + + return 0; +} + +/** + * virtDBusMessageExitContainer: + * @msg: D-Bus message that we are currently parsing + * + * Leaves a container that was opened for parsing. + * + * Returns 0 on success, -1 on failure. + */ +int +virtDBusMessageExitContainer(virtDBusMessage *msg) +{ + _cleanup_(virtDBusMessageIterFreep) DBusMessageIter *cont = virtDBusMessageIterPop(msg); + DBusMessageIter *iter = virtDBusMessageIterPeek(msg); + + if (!cont || !iter) + return -1; + + dbus_message_iter_next(iter); + + return 0; +} + +/** + * virtDBusMessagePeekType: + * @msg: D-Bus message that we are currently parsing + * @type: pointer to a variable where to store the value type + * + * Gets a @type of a first value stored in a container. This is + * mainly used get a type of a value stored in VARIANT container. + * + * Returns 0 on success, -1 on failure. + */ +int +virtDBusMessagePeekType(virtDBusMessage *msg, + int *type) +{ + DBusMessageIter *iter = virtDBusMessageIterPeek(msg); + DBusMessageIter cont; + int msgType; + + if (!iter) + return -1; + + msgType = dbus_message_iter_get_arg_type(iter); + if (msgType != DBUS_TYPE_ARRAY && + msgType != DBUS_TYPE_VARIANT && + msgType != DBUS_TYPE_STRUCT && + msgType != DBUS_TYPE_DICT_ENTRY) { + return virtDBusMessageSetError(msg, DBUS_ERROR_INVALID_ARGS, + "Expecting container type, " + "but is actually of type '%c'.", + msgType); + } + + dbus_message_iter_recurse(iter, &cont); + *type = dbus_message_iter_get_arg_type(&cont); + + return 0; +} + +/** + * virtDBusMessageAppendVariant: + * @msg: D-Bus reply message where to append the variant value + * @type: type of the value stored in variant container + * @sig: signature of the value stored in variant container + * @value: pointer to a variable where the @value is stored + * + * Appends a variant container together with the value into the + * reply message. + * + * Returns 0 on success, -1 on failure. + */ +int +virtDBusMessageAppendVariant(virtDBusMessage *msg, + int type, + const char *sig, + const void *value) +{ + if (virtDBusMessageOpenContainer(msg, DBUS_TYPE_VARIANT, sig) < 0) + return -1; + + if (virtDBusMessageAppendBasic(msg, type, value) < 0) + return -1; + + return virtDBusMessageCloseContainer(msg); +} + +/** + * virtDBusMessageReadVariant: + * @msg: D-Bus message that we are currently parsing + * @type: expected type of the @value stored in variant + * @sig: signature of the expected @value + * @value: pointer to a variable where to store the @value + * + * Reads a variant container together with the value from incoming + * message. It is necessary to know the value stored in the variant, + * virtDBusMessagePeekType() can be used to get the type. + * + * Returns 0 on success if there is no variant left for reading, + * 1 on success if variant was read and -1 on failure. If used + * to read variant value from array 0 indicates that there are no + * other variants left in the array. + */ +int +virtDBusMessageReadVariant(virtDBusMessage *msg, + int type, + const char *sig, + void *value) +{ + int r; + + r = virtDBusMessageEnterContainer(msg, DBUS_TYPE_VARIANT, sig); + if (r < 0) + return -1; + if (r == 0) + return 0; + + if (virtDBusMessageReadBasic(msg, type, value) < 0) + return -1; + + return virtDBusMessageExitContainer(msg); +} + +const char * +virtDBusMessageGetPath(virtDBusMessage *msg) +{ + if (msg && msg->message) + return dbus_message_get_path(msg->message); + return NULL; +} + +const char * +virtDBusMessageGetInterface(virtDBusMessage *msg) +{ + if (msg && msg->message) + return dbus_message_get_interface(msg->message); + return NULL; +} + +const char * +virtDBusMessageGetMember(virtDBusMessage *msg) +{ + if (msg && msg->message) + return dbus_message_get_member(msg->message); + return NULL; +} + +int +virtDBusMessageGetType(virtDBusMessage *msg) +{ + if (msg && msg->message) + return dbus_message_get_type(msg->message); + return -1; +} + +int +virtDBusMessageSetError(virtDBusMessage *msg, + const char *name, + const char *format, + ...) +{ + _cleanup_(virtDBusUtilFreep) char *error = NULL; + va_list ap; + int r; + + if (!msg->error) + return -1; + + va_start(ap, format); + r = vasprintf(&error, format, ap); + va_end(ap); + if (r < 0) + return -1; + + dbus_set_error(msg->error, name, "%s", error); + + return -1; +} + +int +virtDBusSendMessage(virtDBusMessage *msg) +{ + dbus_connection_send(msg->bus, msg->message, NULL); + return 0; +} + +int +virtDBusSendEmptyMessage(virtDBusMessage *msg) +{ + _cleanup_(virtDBusMessageFreep) virtDBusMessage *reply = NULL; + + reply = virtDBusMessageMethodReturn(msg); + if (!reply) + return -1; + + return virtDBusSendMessage(reply); +} + +static int +virtDBusHandleIntrospect(virtDBusMessage *msg, + virtDBusObject *object) +{ + _cleanup_(virtDBusMessageFreep) virtDBusMessage *reply = NULL; + + if (!*object->introspectXML) + *object->introspectXML = virtDBusUtilLoadIntrospect(object->interface); + + if (!*object->introspectXML) { + return virtDBusMessageSetError(msg, DBUS_ERROR_FILE_NOT_FOUND, + "missing introspect data"); + } + + reply = virtDBusMessageMethodReturn(msg); + if (!reply) + return -1; + + if (virtDBusMessageAppendBasic(reply, DBUS_TYPE_STRING, + object->introspectXML) < 0) + return -1; + + virtDBusSendMessage(reply); + return 0; +} + +static int +virtDBusHandlePropertyGet(virtDBusMessage *msg, + virtDBusObject *object) +{ + _cleanup_(virtDBusMessageFreep) virtDBusMessage *reply = NULL; + virtDBusPropertyGetHandler callback = NULL; + const char *property; + const char *interface; + + if (virtDBusMessageReadBasic(msg, DBUS_TYPE_STRING, &interface) < 0) + return -1; + + if (virtDBusMessageReadBasic(msg, DBUS_TYPE_STRING, &property) < 0) + return -1; + + for (int i = 0; object->properties[i].property != NULL; i++) { + if (strcmp(object->properties[i].property, property) == 0) { + callback = object->properties[i].get; + break; + } + } + + if (!callback) { + return virtDBusMessageSetError(msg, DBUS_ERROR_UNKNOWN_PROPERTY, + "unknown property '%s'", property); + } + + reply = virtDBusMessageMethodReturn(msg); + if (!reply) + return -1; + + if (callback(reply, msg, interface, property, object->data) < 0) + return -1; + + virtDBusSendMessage(reply); + return 0; +} + +static int +virtDBusHandlePropertySet(virtDBusMessage *msg, + virtDBusObject *object) +{ + _cleanup_(virtDBusMessageFreep) virtDBusMessage *reply = NULL; + virtDBusPropertySetHandler callback = NULL; + const char *property; + const char *interface; + + if (virtDBusMessageReadBasic(msg, DBUS_TYPE_STRING, &interface) < 0) + return -1; + + if (virtDBusMessageReadBasic(msg, DBUS_TYPE_STRING, &property) < 0) + return -1; + + + for (int i = 0; object->properties[i].property != NULL; i++) { + if (strcmp(object->properties[i].property, property) == 0) { + callback = object->properties[i].set; + break; + } + } + + if (!callback) { + return virtDBusMessageSetError(msg, DBUS_ERROR_UNKNOWN_PROPERTY, + "unknown property '%s'", property); + } + + if (callback(msg, interface, property, object->data) < 0) + return -1; + + reply = virtDBusMessageMethodReturn(msg); + if (!reply) + return -1; + + virtDBusSendMessage(reply); + return 0; +} + +static int +virtDBusHandlePropertyGetAll(virtDBusMessage *msg, + virtDBusObject *object) +{ + _cleanup_(virtDBusMessageFreep) virtDBusMessage *reply = NULL; + const char *interface; + + if (virtDBusMessageReadBasic(msg, DBUS_TYPE_STRING, &interface) < 0) + return -1; + + reply = virtDBusMessageMethodReturn(msg); + if (!reply) + return -1; + + if (virtDBusMessageOpenContainer(reply, DBUS_TYPE_ARRAY, "{sv}") < 0) + return -1; + + for (int i = 0; object->properties[i].property != NULL; i++) { + if (virtDBusMessageOpenContainer(reply, DBUS_TYPE_DICT_ENTRY, NULL) < 0) + return -1; + + if (virtDBusMessageAppendBasic(reply, DBUS_TYPE_STRING, + &object->properties[i].property) < 0) { + return -1; + } + + if (object->properties[i].get(reply, msg, interface, + object->properties[i].property, + object->data) < 0) { + return -1; + } + + if (virtDBusMessageCloseContainer(reply) < 0) + return -1; + } + + if (virtDBusMessageCloseContainer(reply) < 0) + return -1; + + virtDBusSendMessage(reply); + return 0; +} + +static int +virtDBusHandleProperty(virtDBusMessage *msg, + virtDBusObject *object) +{ + const char *member = virtDBusMessageGetMember(msg); + + if (strcmp(member, "Get") == 0) { + return virtDBusHandlePropertyGet(msg, object); + } else if (strcmp(member, "Set") == 0) { + return virtDBusHandlePropertySet(msg, object); + } else if (strcmp(member, "GetAll") == 0) { + return virtDBusHandlePropertyGetAll(msg, object); + } else { + return virtDBusMessageSetError(msg, DBUS_ERROR_UNKNOWN_METHOD, + "unknown method '%s'", member); + } +} + +static int +virtDBusHandleMethod(virtDBusMessage *msg, + virtDBusObject *object) +{ + const char *member = virtDBusMessageGetMember(msg); + const char *msgSig = dbus_message_get_signature(msg->message); + virtDBusMethodHandlers *handle = NULL; + + for (int i = 0; object->methods[i].method != NULL; i++) { + if (strcmp(member, object->methods[i].method) == 0) { + handle = (object->methods) + i; + break; + } + } + + if (!handle) { + return virtDBusMessageSetError(msg, DBUS_ERROR_UNKNOWN_METHOD, + "unknown method '%s'", member); + } + + if (strcmp(handle->signature, msgSig) != 0) + return virtDBusMessageSetError(msg, DBUS_ERROR_INVALID_ARGS, + "Invalid message signature '%s', " + "expected signature '%s'.", + msgSig, handle->signature); + return handle->callback(msg, object->data); +} + +static int +virtDBusHandleError(virtDBusMessage *msg) +{ + _cleanup_(virtDBusMessageUnref) DBusMessage *reply = NULL; + + if (!dbus_error_is_set(msg->error)) + return -1; + + reply = dbus_message_new_error(msg->message, + msg->error->name, + msg->error->message); + if (!reply) + return -1; + + dbus_connection_send(msg->bus, reply, NULL); + return 1; +} + +int +virtDBusDispatchMessage(DBusConnection *bus, + virtDBusObjectList *objectList) +{ + _cleanup_(virtDBusMessageUnref) DBusMessage *message = NULL; + _cleanup_(virtDBusMessageFreep) virtDBusMessage *msg = NULL; + _cleanup_(dbus_error_free) DBusError error = DBUS_ERROR_INIT; + virtDBusObject *object = NULL; + const char *path; + const char *interface; + int r; + + message = dbus_connection_pop_message(bus); + if (!message) + return 0; + + if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_METHOD_CALL) + return 1; + + msg = virtDBusMessageNew(message, bus, &error); + if (!msg) + return -1; + + path = virtDBusMessageGetPath(msg); + + for (int i = 0; i < objectList->len; i++) { + virtDBusObject *tmpObject = objectList->objects[i]; + if ((tmpObject->type == VIRT_DBUS_OBJECT_TYPE_MATCH && + strcmp(path, tmpObject->path) == 0) || + (tmpObject->type == VIRT_DBUS_OBJECT_TYPE_PREFIX && + strstr(path, tmpObject->path) != NULL)) { + object = tmpObject; + break; + } + } + + if (!object) { + virtDBusMessageSetError(msg, DBUS_ERROR_UNKNOWN_OBJECT, + "invalid object '%s'", path); + return virtDBusHandleError(msg); + } + + interface = virtDBusMessageGetInterface(msg); + if (!interface) { + virtDBusMessageSetError(msg, DBUS_ERROR_UNKNOWN_INTERFACE, + "missing interface"); + return virtDBusHandleError(msg); + } + + if (strcmp(interface, DBUS_INTERFACE_INTROSPECTABLE) == 0) { + r = virtDBusHandleIntrospect(msg, object); + } else if (strcmp(interface, DBUS_INTERFACE_PROPERTIES) == 0) { + r = virtDBusHandleProperty(msg, object); + } else if (strcmp(interface, object->interface) == 0) { + r = virtDBusHandleMethod(msg, object); + } else { + virtDBusMessageSetError(msg, DBUS_ERROR_UNKNOWN_INTERFACE, + "invalid interface '%s'", interface); + return virtDBusHandleError(msg); + } + + if (r < 0) { + return virtDBusHandleError(msg); + } + + return 1; +} + +void +virtDBusMessageFreep(virtDBusMessage **msgp) +{ + if (*msgp) { + virtDBusMessage *msg = *msgp; + + for (int i = 0; i < msg->items; i++) { + if (msg->stack[i]) + free(msg->stack[i]); + } + free(msg->stack); + + if (msg->message) + dbus_message_unref(msg->message); + + free(*msgp); + } +} + +void +virtDBusConnectionClose(DBusConnection **bus) +{ + if (*bus) { + dbus_connection_close(*bus); + dbus_connection_unref(*bus); + } +} + +static void +virtDBusObjectFree(virtDBusObject *object) +{ + free(object->path); + free(object); +} + +void +virtDBusObjectFreep(virtDBusObject **objectp) +{ + if (*objectp) + virtDBusObjectFree(*objectp); +} + +void +virtDBusObjectListFree(virtDBusObjectList *list) +{ + for (int i = 0; i < list->len; i++) + virtDBusObjectFree(list->objects[i]); + free(list->objects); +} diff --git a/src/dbus.h b/src/dbus.h new file mode 100644 index 0000000..14d15d2 --- /dev/null +++ b/src/dbus.h @@ -0,0 +1,158 @@ +#pragma once + +#define VIR_ENUM_SENTINELS + +#include <dbus/dbus.h> +#include <libvirt/libvirt.h> + +typedef struct _virtDBusMessage virtDBusMessage; + +typedef int +(*virtDBusPropertyGetHandler)(virtDBusMessage *reply, + virtDBusMessage *msg, + const char *interface, + const char *property, + void *data); + +typedef int +(*virtDBusPropertySetHandler)(virtDBusMessage *msg, + const char *interface, + const char *property, + void *data); + +struct _virtDBusPropertyHandlers { + const char *property; + virtDBusPropertyGetHandler get; + virtDBusPropertySetHandler set; +}; +typedef struct _virtDBusPropertyHandlers virtDBusPropertyHandlers; + +typedef int +(*virtDBusMethodHandler)(virtDBusMessage* msg, + void *data); + +struct _virtDBusMethodHandlers { + const char *method; + const char *signature; + virtDBusMethodHandler callback; +}; +typedef struct _virtDBusMethodHandlers virtDBusMethodHandlers; + +typedef struct _virtDBusObject virtDBusObject; + +struct _virtDBusObjectList { + virtDBusObject **objects; + size_t len; +}; +typedef struct _virtDBusObjectList virtDBusObjectList; + +DBusConnection * +virtDBusConnectionOpen(DBusBusType busType, + const char *name); + +typedef enum { + VIRT_DBUS_OBJECT_TYPE_MATCH, + VIRT_DBUS_OBJECT_TYPE_PREFIX, +} virtDBusObjectType; + +int +virtDBusObjectListRegister(virtDBusObjectList *objectList, + const char *path, + const char **introspectXML, + const char *interface, + virtDBusObjectType type, + virtDBusPropertyHandlers *properties, + virtDBusMethodHandlers *methods, + void *data); + +int +virtDBusDispatchMessage(DBusConnection *bus, + virtDBusObjectList *objectList); + +virtDBusMessage * +virtDBusMessageMethodReturn(virtDBusMessage *msg); + +virtDBusMessage * +virtDBusMessageNewSignal(DBusConnection *bus, + const char *path, + const char *interface, + const char *signal); + +int +virtDBusMessageAppendBasic(virtDBusMessage *msg, + int type, + const void *value); + +int +virtDBusMessageReadBasic(virtDBusMessage *msg, + int type, + void *value); + +int +virtDBusMessageOpenContainer(virtDBusMessage *msg, + int type, + const char *sig); + +int +virtDBusMessageCloseContainer(virtDBusMessage *msg); + +int +virtDBusMessageEnterContainer(virtDBusMessage *msg, + int type, + const char *sig); + +int +virtDBusMessageExitContainer(virtDBusMessage *msg); + +int +virtDBusMessagePeekType(virtDBusMessage *msg, + int *type); + +int +virtDBusMessageAppendVariant(virtDBusMessage *msg, + int type, + const char *sig, + const void *value); + +int +virtDBusMessageReadVariant(virtDBusMessage *msg, + int type, + const char *sig, + void *value); + +const char * +virtDBusMessageGetPath(virtDBusMessage *msg); + +const char * +virtDBusMessageGetInterface(virtDBusMessage *msg); + +const char * +virtDBusMessageGetMember(virtDBusMessage *msg); + +int +virtDBusMessageGetType(virtDBusMessage *msg); + +int +virtDBusMessageSetError(virtDBusMessage *msg, + const char *name, + const char *format, + ...) + __attribute__ ((format (printf, 3, 4))); + +int +virtDBusSendMessage(virtDBusMessage *msg); + +int +virtDBusSendEmptyMessage(virtDBusMessage *msg); + +void +virtDBusMessageFreep(virtDBusMessage **msgp); + +void +virtDBusConnectionClose(DBusConnection **bus); + +void +virtDBusObjectFreep(virtDBusObject **objectp); + +void +virtDBusObjectListFree(virtDBusObjectList *list); diff --git a/src/domain.c b/src/domain.c index f68a3a0..daff32d 100644 --- a/src/domain.c +++ b/src/domain.c @@ -515,14 +515,6 @@ virtDBusDomainLookup(sd_bus *bus VIRT_ATTR_UNUSED, virtDBusConnect *connect = userdata; _cleanup_(virtDBusUtilFreep) char *name = NULL; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; - int r; - - r = sd_bus_path_decode(path, connect->domainPath, &name); - if (r < 0) - return r; - - if (*name == '\0') - return 0; domain = virtDBusDomainGetVirDomain(connect, path, error); if (!domain) diff --git a/src/util.c b/src/util.c index 9042a0f..b6919fb 100644 --- a/src/util.c +++ b/src/util.c @@ -1,9 +1,18 @@ +#define _GNU_SOURCE + #include "util.h" +#include <fcntl.h> #include <libvirt/virterror.h> +#include <stdio.h> #include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> #include <unistd.h> +#define VIRT_UTIL_READ_BLOCK_SIZE 1024 +#define VIRT_UTIL_FILE_LIMIT 1024 * 1024 + int virtDBusUtilMessageAppendTypedParameters(sd_bus_message *message, virTypedParameterPtr parameters, @@ -78,15 +87,125 @@ virtDBusUtilSetError(sd_bus_error *error, return sd_bus_error_set(error, VIRT_DBUS_ERROR_INTERFACE, message); } +char * +virtDBusUtilReadFile(const char *filename) +{ + _cleanup_(virtDBusUtilFreep) char *data = NULL; + _cleanup_(virtDBusUtilClosep) int fd = -1; + char buf[VIRT_UTIL_READ_BLOCK_SIZE]; + char *ret; + size_t len = 0; + ssize_t readlen; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return NULL; + + while ((readlen = read(fd, buf, VIRT_UTIL_READ_BLOCK_SIZE)) > 0) { + len += readlen; + + if (len > VIRT_UTIL_FILE_LIMIT) + return NULL; + + data = realloc(data, len + 1); + if (!data) + return NULL; + + memcpy(data+len-readlen, buf, readlen); + } + + if (readlen < 0 || !data) + return NULL; + + data[len] = 0; + VIRT_STEAL_PTR(ret, data); + return ret; +} + +static const char *dbusInterfacePrefix = NULL; + +char * +virtDBusUtilLoadIntrospect(const char *interface) +{ + _cleanup_(virtDBusUtilFreep) char *path = NULL; + + if (!dbusInterfacePrefix) { + dbusInterfacePrefix = getenv("VIRT_DBUS_INTERFACES_DIR"); + if (!dbusInterfacePrefix) + dbusInterfacePrefix = VIRT_DBUS_INTERFACES_DIR; + } + + if (asprintf(&path, "%s/%s.xml", dbusInterfacePrefix, interface) < 0) + return NULL; + + return virtDBusUtilReadFile(path); +} + +static char * +virtDBusUtilEncodeUUID(const char *uuid) +{ + char *newUuid = NULL; + size_t uuidLen = strlen(uuid); + int i; + + newUuid = calloc(uuidLen + 2, sizeof(char)); + if (!newUuid) + return NULL; + + newUuid[0] = '_'; + + for (i = 0; i < uuidLen; i++) { + if (uuid[i] == '-') + newUuid[i + 1] = '_'; + else + newUuid[i + 1] = uuid[i]; + } + + newUuid[i + 1] = 0; + + return newUuid; +} + +static char * +virtDBusUtilDecodeUUID(const char *uuidEsc) +{ + char *uuid = NULL; + size_t uuidLen = strlen(uuidEsc); + int i; + + if (uuidEsc[0] != '_') + return NULL; + + uuid = calloc(uuidLen, sizeof(char)); + if (!uuid) + return NULL; + + for (i = 1; i < uuidLen; i++) { + if (uuidEsc[i] == '_') + uuid[i - 1] = '-'; + else + uuid[i - 1] = uuidEsc[i]; + } + + uuid[uuidLen -1] = 0; + + return uuid; +} + char * virtDBusUtilBusPathForVirDomain(virDomainPtr domain, const char *domainPath) { char *path = NULL; + _cleanup_(virtDBusUtilFreep) char *uuidEsc = NULL; char uuid[VIR_UUID_STRING_BUFLEN] = ""; virDomainGetUUIDString(domain, uuid); - sd_bus_path_encode(domainPath, uuid, &path); + + uuidEsc = virtDBusUtilEncodeUUID(uuid); + + if (asprintf(&path, "%s/%s", domainPath, uuidEsc) < 0) + return NULL; return path; } @@ -96,14 +215,14 @@ virtDBusUtilVirDomainFromBusPath(virConnectPtr connection, const char *path, const char *domainPath) { - _cleanup_(virtDBusUtilFreep) char *name = NULL; - int r; + _cleanup_(virtDBusUtilFreep) char *uuid = NULL; + size_t prefixLen = strlen(domainPath) + 1; - r = sd_bus_path_decode(path, domainPath, &name); - if (r < 0) + uuid = virtDBusUtilDecodeUUID(path+prefixLen); + if (!uuid) return NULL; - return virDomainLookupByUUIDString(connection, name); + return virDomainLookupByUUIDString(connection, uuid); } void diff --git a/src/util.h b/src/util.h index 2a6f7e2..c42d2cc 100644 --- a/src/util.h +++ b/src/util.h @@ -11,6 +11,11 @@ #define VIRT_N_ELEMENTS(array) (sizeof(array) / sizeof(*(array))) +#define VIRT_STEAL_PTR(dest, src) \ + do { \ + (dest) = (src); \ + (src) = NULL; \ + } while(0) int virtDBusUtilMessageAppendTypedParameters(sd_bus_message *message, @@ -24,6 +29,12 @@ int virtDBusUtilSetError(sd_bus_error *error, const char *message); +char * +virtDBusUtilReadFile(const char *filename); + +char * +virtDBusUtilLoadIntrospect(const char *interface); + char * virtDBusUtilBusPathForVirDomain(virDomainPtr domain, const char *domainPath); diff --git a/test/Makefile.am b/test/Makefile.am index 4651d08..d3997f3 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -13,4 +13,5 @@ EXTRA_DIST = \ travis-run TESTS_ENVIRONMENT = \ - abs_top_builddir=$(abs_top_builddir) + abs_top_builddir=$(abs_top_builddir) \ + VIRT_DBUS_INTERFACES_DIR=$(abs_top_srcdir)/data diff --git a/test/travis-run b/test/travis-run index 482b286..47fe70c 100755 --- a/test/travis-run +++ b/test/travis-run @@ -22,7 +22,7 @@ sudo chroot "$CHROOT" << EOF set -ex # install build deps apt-get update -apt-get install -y dh-autoreconf pkg-config libvirt-dev libsystemd-dev libtool python3-gi python3-dbus dbus +apt-get install -y dh-autoreconf pkg-config libvirt-dev libsystemd-dev libdbus-1-dev libtool python3-gi python3-dbus dbus # run build and tests as user chown -R buildd:buildd /build -- 2.14.3

On Mon, Mar 12, 2018 at 05:21:46PM +0100, Pavel Hrdina wrote:
We will switch to libdbus library because the systemd sd-bus implementation is not thread safe.
Hmmm, libdbus.so isn't all that great with threads either. It has had countless bugs in its thread support over the years to the extent that DBus maintainers have actively discouraged people from using it. GLib didn't even try to use it and wrote new bindings straight to the socket protocol for this reason. Personally I think it would be worth considering using glib for libvirt-dbus. As well as getting access to a nicer DBus binding, you get to take advantage of higher level APIs that GLib provides compared to STDC / POSIX. The only real downside of using GLib is abort-on-OOM behaviour, but I don't think that's an issue for libvirt-dbus as its just an API shim layer. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On Mon, Mar 12, 2018 at 04:30:30PM +0000, Daniel P. Berrangé wrote:
On Mon, Mar 12, 2018 at 05:21:46PM +0100, Pavel Hrdina wrote:
We will switch to libdbus library because the systemd sd-bus implementation is not thread safe.
Hmmm, libdbus.so isn't all that great with threads either. It has had countless bugs in its thread support over the years to the extent that DBus maintainers have actively discouraged people from using it. GLib didn't even try to use it and wrote new bindings straight to the socket protocol for this reason.
They still claim it in their documentation that you should use different API if possible but if you really want to you can use libdbus directly but the only drawback from that claim is that the API is low-level and hard to use. Another claim from their documentation is that DBusConnection is thread safe which is the only thing that libvirt-dbus requires to be thread safe, they specifically say that DBusMessage doesn't have any thread locks, but that's also OK since the DBusMessage will live only in one thread. I don't have any experience using libdbus (except this one) so if threading is still not reliable and safe then it would be probably better to use different API. I've done some research about libdbus before using it and yes, there ware some articles that it was broken in the past, however nothing recent.
Personally I think it would be worth considering using glib for libvirt-dbus. As well as getting access to a nicer DBus binding, you get to take advantage of higher level APIs that GLib provides compared to STDC / POSIX. The only real downside of using GLib is abort-on-OOM behaviour, but I don't think that's an issue for libvirt-dbus as its just an API shim layer.
I personally don't like GLib that much, but I can give it a try and prepare alternative patches with GLib. Pavel

On Tue, Mar 13, 2018 at 09:39:13AM +0100, Pavel Hrdina wrote:
On Mon, Mar 12, 2018 at 04:30:30PM +0000, Daniel P. Berrangé wrote:
On Mon, Mar 12, 2018 at 05:21:46PM +0100, Pavel Hrdina wrote:
We will switch to libdbus library because the systemd sd-bus implementation is not thread safe.
Hmmm, libdbus.so isn't all that great with threads either. It has had countless bugs in its thread support over the years to the extent that DBus maintainers have actively discouraged people from using it. GLib didn't even try to use it and wrote new bindings straight to the socket protocol for this reason.
They still claim it in their documentation that you should use different API if possible but if you really want to you can use libdbus directly but the only drawback from that claim is that the API is low-level and hard to use.
Yes, it is certainly low level - when I wrote the Perl binding I ended up creating a much higher level wrapper around libdbus to make it easier to use - similar to how GLib GIO DBus has the low level and high level APIs. One deals with messages, the other deals with objects and methods/properties.
Another claim from their documentation is that DBusConnection is thread safe which is the only thing that libvirt-dbus requires to be thread safe, they specifically say that DBusMessage doesn't have any thread locks, but that's also OK since the DBusMessage will live only in one thread.
I don't have any experience using libdbus (except this one) so if threading is still not reliable and safe then it would be probably better to use different API. I've done some research about libdbus before using it and yes, there ware some articles that it was broken in the past, however nothing recent.
Yeah, most recent I can find is https://bugs.freedesktop.org/show_bug.cgi?id=54972 which suggest the core problems were all solved, but the bug is not marked as fixed so I'm unclear what issues remain.
Personally I think it would be worth considering using glib for libvirt-dbus. As well as getting access to a nicer DBus binding, you get to take advantage of higher level APIs that GLib provides compared to STDC / POSIX. The only real downside of using GLib is abort-on-OOM behaviour, but I don't think that's an issue for libvirt-dbus as its just an API shim layer.
I personally don't like GLib that much, but I can give it a try and prepare alternative patches with GLib.
On second glance I'm unclear the recommended way to deal with GLib DBus APIs when you have long running APIs to invoke. I get the feeling that you would end up using GTask to spawn single-use threads to execute the API call, but keeping all dbus interaction in the main thread. This would likely make it desirable to use the libvirt-gobject library at the same time to get easier access to async libvirt API execution. I've copied you on a mail to the DBus mailing list to see if we can get some guidance from people with more up2date knowledge than me, since I've not been actively involved in dbus community for a little while now. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On Tue, Mar 13, 2018 at 10:07:58AM +0000, Daniel P. Berrangé wrote:
On Tue, Mar 13, 2018 at 09:39:13AM +0100, Pavel Hrdina wrote:
On Mon, Mar 12, 2018 at 04:30:30PM +0000, Daniel P. Berrangé wrote:
On Mon, Mar 12, 2018 at 05:21:46PM +0100, Pavel Hrdina wrote:
We will switch to libdbus library because the systemd sd-bus implementation is not thread safe.
Hmmm, libdbus.so isn't all that great with threads either. It has had countless bugs in its thread support over the years to the extent that DBus maintainers have actively discouraged people from using it. GLib didn't even try to use it and wrote new bindings straight to the socket protocol for this reason.
They still claim it in their documentation that you should use different API if possible but if you really want to you can use libdbus directly but the only drawback from that claim is that the API is low-level and hard to use.
Yes, it is certainly low level - when I wrote the Perl binding I ended up creating a much higher level wrapper around libdbus to make it easier to use - similar to how GLib GIO DBus has the low level and high level APIs. One deals with messages, the other deals with objects and methods/properties.
Another claim from their documentation is that DBusConnection is thread safe which is the only thing that libvirt-dbus requires to be thread safe, they specifically say that DBusMessage doesn't have any thread locks, but that's also OK since the DBusMessage will live only in one thread.
I don't have any experience using libdbus (except this one) so if threading is still not reliable and safe then it would be probably better to use different API. I've done some research about libdbus before using it and yes, there ware some articles that it was broken in the past, however nothing recent.
Yeah, most recent I can find is
https://bugs.freedesktop.org/show_bug.cgi?id=54972
which suggest the core problems were all solved, but the bug is not marked as fixed so I'm unclear what issues remain.
Personally I think it would be worth considering using glib for libvirt-dbus. As well as getting access to a nicer DBus binding, you get to take advantage of higher level APIs that GLib provides compared to STDC / POSIX. The only real downside of using GLib is abort-on-OOM behaviour, but I don't think that's an issue for libvirt-dbus as its just an API shim layer.
I personally don't like GLib that much, but I can give it a try and prepare alternative patches with GLib.
On second glance I'm unclear the recommended way to deal with GLib DBus APIs when you have long running APIs to invoke. I get the feeling that you would end up using GTask to spawn single-use threads to execute the API call, but keeping all dbus interaction in the main thread. This would likely make it desirable to use the libvirt-gobject library at the same time to get easier access to async libvirt API execution.
I've copied you on a mail to the DBus mailing list to see if we can get some guidance from people with more up2date knowledge than me, since I've not been actively involved in dbus community for a little while now.
Unfortunately it appears you were not CC'd on the reply, but also, for sake of archives, here is the thread: https://lists.freedesktop.org/archives/dbus/2018-March/017425.html This comment is exactly the kind of thing I was concerned about: "fd.o#102839 was a bug in code that was already meant to be thread-safe since at least 2005, and was previously fixed in 2005, 2006, and twice in 2010. I think the fact that we are still finding bugs in the locking model in 2018 should tell you something!" Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

This removes all the systemd sd-bus code. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- README | 1 - configure.ac | 3 - data/Makefile.am | 4 +- data/org.libvirt.Connect.xml | 56 +++++ data/org.libvirt.Domain.xml | 51 +++++ libvirt-dbus.spec.in | 4 +- src/Makefile.am | 3 - src/connect.c | 221 ++++++++----------- src/connect.h | 16 +- src/domain.c | 513 +++++++++++++++++++------------------------ src/domain.h | 4 +- src/events.c | 133 +++++------ src/main.c | 100 +++------ src/util.c | 87 ++++---- src/util.h | 15 +- test/travis-run | 2 +- 16 files changed, 586 insertions(+), 627 deletions(-) create mode 100644 data/org.libvirt.Connect.xml create mode 100644 data/org.libvirt.Domain.xml diff --git a/README b/README index 242c9ba..518217f 100644 --- a/README +++ b/README @@ -56,7 +56,6 @@ raised in future releases based on this distro build target policy. The packages required to build libvirt-dbus are - - systemd-211 - dbus - libvirt diff --git a/configure.ac b/configure.ac index c8dcf04..8836c6f 100644 --- a/configure.ac +++ b/configure.ac @@ -12,10 +12,8 @@ AC_USE_SYSTEM_EXTENSIONS AM_SILENT_RULES([yes]) LIBVIRT_REQUIRED=1.2.8 -SYSTEMD_REQUIRED=211 DBUS_REQUIRED=1.10.24 AC_SUBST([LIBVIRT_REQUIRED]) dnl used in the .spec file -AC_SUBST([SYSTEMD_REQUIRED]) dnl used in the .spec file AC_SUBST([DBUS_REQUIRED]) dnl used in the .spec file LIBVIRT_DBUS_MAJOR_VERSION=`echo $VERSION | awk -F. '{print $1}'` @@ -36,7 +34,6 @@ AC_PROG_MKDIR_P AM_PROG_CC_C_O PKG_CHECK_MODULES(LIBVIRT, libvirt >= $LIBVIRT_REQUIRED) -PKG_CHECK_MODULES(SYSTEMD, libsystemd >= $SYSTEMD_REQUIRED) PKG_CHECK_MODULES(DBUS, dbus-1 >= $DBUS_REQUIRED) LIBVIRT_COMPILE_WARNINGS diff --git a/data/Makefile.am b/data/Makefile.am index a886687..dd60713 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -18,7 +18,9 @@ polkit_files = \ polkitdir = $(sysconfdir)/polkit-1/rules.d polkit_DATA = $(polkit_files:.rules.in=.rules) -interfaces_files = +interfaces_files = \ + org.libvirt.Connect.xml \ + org.libvirt.Domain.xml interfacesdir = $(DBUS_INTERFACES_DIR) interfaces_DATA = $(interfaces_files) diff --git a/data/org.libvirt.Connect.xml b/data/org.libvirt.Connect.xml new file mode 100644 index 0000000..a40ce1d --- /dev/null +++ b/data/org.libvirt.Connect.xml @@ -0,0 +1,56 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" +"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> + +<node name="/org/libvirt/connect"> + <interface name="org.libvirt.Connect"> + <method name="CreateXML"> + <arg name="xml" type="s" direction="in"/> + <arg name="flags" type="u" direction="in"/> + <arg name="domain" type="o" direction="out"/> + </method> + <method name="DefineXML"> + <arg name="xml" type="s" direction="in"/> + <arg name="domain" type="o" direction="out"/> + </method> + <method name="ListDomains"> + <arg name="flags" type="u" direction="in"/> + <arg name="domains" type="ao" direction="out"/> + </method> + <signal name="DomainCrashed"> + <arg name="reason" type="s"/> + <arg name="domain" type="o"/> + </signal> + <signal name="DomainDefined"> + <arg name="reason" type="s"/> + <arg name="domain" type="o"/> + </signal> + <signal name="DomainPMSuspended"> + <arg name="reason" type="s"/> + <arg name="domain" type="o"/> + </signal> + <signal name="DomainResumed"> + <arg name="reason" type="s"/> + <arg name="domain" type="o"/> + </signal> + <signal name="DomainShutdown"> + <arg name="reason" type="s"/> + <arg name="domain" type="o"/> + </signal> + <signal name="DomainStarted"> + <arg name="reason" type="s"/> + <arg name="domain" type="o"/> + </signal> + <signal name="DomainStopped"> + <arg name="reason" type="s"/> + <arg name="domain" type="o"/> + </signal> + <signal name="DomainSuspended"> + <arg name="reason" type="s"/> + <arg name="domain" type="o"/> + </signal> + <signal name="DomainUndefined"> + <arg name="reason" type="s"/> + <arg name="domain" type="o"/> + </signal> + </interface> +</node> diff --git a/data/org.libvirt.Domain.xml b/data/org.libvirt.Domain.xml new file mode 100644 index 0000000..48bf40f --- /dev/null +++ b/data/org.libvirt.Domain.xml @@ -0,0 +1,51 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" +"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> + +<node name="/org/libvirt/domain"> + <interface name="org.libvirt.Domain"> + <property name="Name" type="s" access="read"/> + <property name="UUID" type="s" access="read"/> + <property name="Id" type="u" access="read"/> + <property name="Vcpus" type="u" access="read"/> + <property name="OSType" type="s" access="read"/> + <property name="Active" type="b" access="read"/> + <property name="Persistent" type="b" access="read"/> + <property name="State" type="s" access="read"/> + <property name="Autostart" type="b" access="read"/> + <method name="GetXMLDesc"> + <arg name="flags" type="u" direction="in"/> + <arg name="xml" type="s" direction="out"/> + </method> + <method name="GetStats"> + <arg name="stats" type="u" direction="in"/> + <arg name="flags" type="u" direction="in"/> + <arg name="records" type="a{sv}" direction="out"/> + </method> + <method name="Shutdown"/> + <method name="Destroy"/> + <method name="Reboot"> + <arg name="flags" type="u" direction="in"/> + </method> + <method name="Reset"> + <arg name="flags" type="u" direction="in"/> + </method> + <method name="Create"/> + <method name="Undefine"/> + <signal name="DeviceAdded"> + <arg name="device" type="s"/> + </signal> + <signal name="DeviceRemoved"> + <arg name="device" type="s"/> + </signal> + <signal name="DiskChange"> + <arg name="oldSrcPath" type="s"/> + <arg name="newSrcPath" type="s"/> + <arg name="device" type="s"/> + <arg name="reason" type="s"/> + </signal> + <signal name="TrayChange"> + <arg name="device" type="s"/> + <arg name="reason" type="s"/> + </signal> + </interface> +</node> diff --git a/libvirt-dbus.spec.in b/libvirt-dbus.spec.in index 512f4fc..d458d71 100644 --- a/libvirt-dbus.spec.in +++ b/libvirt-dbus.spec.in @@ -1,7 +1,6 @@ # -*- rpm-spec -*- %define libvirt_version @LIBVIRT_REQUIRED@ -%define systemd_version @SYSTEMD_REQUIRED@ %define dbus_version @DBUS_REQUIRED@ %define system_user @SYSTEM_USER@ @@ -16,11 +15,9 @@ Source0: ftp://libvirt.org/libvirt/dbus/%{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: libvirt-devel >= %{libvirt_version} -BuildRequires: systemd-devel >= %{systemd_version} BuildRequires: dbus-devel >= %{dbus_version} Requires: libvirt-libs >= %{libvirt_version} -Requires: systemd-libs >= %{systemd_version} Requires: dbus-libs >= %{dbus_version} Requires(pre): shadow-utils @@ -57,5 +54,6 @@ exit 0 %{_datadir}/dbus-1/services/org.libvirt.service %{_datadir}/dbus-1/system-services/org.libvirt.service %{_datadir}/dbus-1/system.d/org.libvirt.conf +%{_datadir}/dbus-1/interfaces/org.libvirt.*.xml %changelog diff --git a/src/Makefile.am b/src/Makefile.am index 1f0d990..9e23f1b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,7 +21,6 @@ bin_PROGRAMS = libvirt-dbus libvirt_dbus_SOURCES = $(DAEMON_SOURCES) libvirt_dbus_CFLAGS = \ - $(SYSTEMD_CFLAGS) \ $(LIBVIRT_CFLAGS) \ $(DBUS_CFLAGS) \ $(WARN_CFLAGS) \ @@ -29,7 +28,6 @@ libvirt_dbus_CFLAGS = \ $(NULL) libvirt_dbus_LDFLAGS = \ - $(SYSTEMD_LDFLAGS) \ $(LIBVIRT_LDFLAGS) \ $(DBUS_LDFLAGS) \ $(RELRO_LDFLAGS) \ @@ -37,6 +35,5 @@ libvirt_dbus_LDFLAGS = \ $(NULL) libvirt_dbus_LDADD = \ - $(SYSTEMD_LIBS) \ $(LIBVIRT_LIBS) \ $(DBUS_LIBS) diff --git a/src/connect.c b/src/connect.c index 695fc0d..2fe305f 100644 --- a/src/connect.c +++ b/src/connect.c @@ -1,9 +1,11 @@ +#include "dbus.h" #include "domain.h" #include "events.h" #include "connect.h" #include "util.h" #include <stdbool.h> +#include <stdint.h> #include <stdlib.h> static int virtDBusConnectCredType[] = { @@ -15,16 +17,18 @@ static int virtDBusConnectCredType[] = { VIR_CRED_EXTERNAL, }; +static const char *introspectXML = NULL; + static int virtDBusConnectAuthCallback(virConnectCredentialPtr cred VIRT_ATTR_UNUSED, unsigned int ncred VIRT_ATTR_UNUSED, void *cbdata) { - sd_bus_error *error = cbdata; + virtDBusMessage *msg = cbdata; - return virtDBusUtilSetError(error, - "Interactive authentication is not supported. " - "Use client configuration file for libvirt."); + return virtDBusMessageSetError(msg, VIRT_DBUS_ERROR_INTERFACE, + "Interactive authentication is not supported. " + "Use client configuration file for libvirt."); } static virConnectAuth virtDBusConnectAuth = { @@ -38,7 +42,6 @@ static void virtDBusConnectClose(virtDBusConnect *connect, bool deregisterEvents) { - for (int i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i += 1) { if (connect->callback_ids[i] >= 0) { if (deregisterEvents) { @@ -55,7 +58,7 @@ virtDBusConnectClose(virtDBusConnect *connect, int virtDBusConnectOpen(virtDBusConnect *connect, - sd_bus_error *error) + virtDBusMessage *msg) { if (connect->connection) { if (virConnectIsAlive(connect->connection)) @@ -64,12 +67,12 @@ virtDBusConnectOpen(virtDBusConnect *connect, virtDBusConnectClose(connect, false); } - virtDBusConnectAuth.cbdata = error; + virtDBusConnectAuth.cbdata = msg; connect->connection = virConnectOpenAuth(connect->uri, &virtDBusConnectAuth, 0); if (!connect->connection) - return virtDBusUtilSetLastVirtError(error); + return virtDBusUtilSetLastVirtError(msg); virtDBusEventsRegister(connect); @@ -77,68 +80,29 @@ virtDBusConnectOpen(virtDBusConnect *connect, } static int -virtDBusConnectEnumarateDomains(sd_bus *bus VIRT_ATTR_UNUSED, - const char *path VIRT_ATTR_UNUSED, - void *userdata, - char ***nodes, - sd_bus_error *error) -{ - virtDBusConnect *connect = userdata; - _cleanup_(virtDBusUtilVirDomainListFreep) virDomainPtr *domains = NULL; - _cleanup_(virtDBusUtilStrvFreep) char **paths = NULL; - int n_domains; - int r; - - r = virtDBusConnectOpen(connect, error); - if (r < 0) - return r; - - n_domains = virConnectListAllDomains(connect->connection, &domains, 0); - if (n_domains < 0) - return virtDBusUtilSetLastVirtError(error); - - paths = calloc(n_domains + 1, sizeof(char *)); - - for (int i = 0; i < n_domains; i += 1) - paths[i] = virtDBusUtilBusPathForVirDomain(domains[i], - connect->domainPath); - - *nodes = paths; - paths = NULL; - - return 0; -} - -static int -virtDBusConnectListDomains(sd_bus_message *message, - void *userdata, - sd_bus_error *error) +virtDBusConnectListDomains(virtDBusMessage *msg, + void *data) { - virtDBusConnect *connect = userdata; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + virtDBusConnect *connect = data; + _cleanup_(virtDBusMessageFreep) virtDBusMessage *reply = NULL; _cleanup_(virtDBusUtilVirDomainListFreep) virDomainPtr *domains = NULL; uint32_t flags; - int r; - r = sd_bus_message_read(message, "u", &flags); - if (r < 0) - return r; + if (virtDBusMessageReadBasic(msg, DBUS_TYPE_UINT32, &flags) < 0) + return -1; - r = virtDBusConnectOpen(connect, error); - if (r < 0) - return r; + if (virtDBusConnectOpen(connect, msg) < 0) + return -1; - r = virConnectListAllDomains(connect->connection, &domains, flags); - if (r < 0) - return virtDBusUtilSetLastVirtError(error); + if (virConnectListAllDomains(connect->connection, &domains, flags) < 0) + return virtDBusUtilSetLastVirtError(msg); - r = sd_bus_message_new_method_return(message, &reply); - if (r < 0) - return r; + reply = virtDBusMessageMethodReturn(msg); + if (!reply) + return -1; - r = sd_bus_message_open_container(reply, 'a', "o"); - if (r < 0) - return r; + if (virtDBusMessageOpenContainer(reply, DBUS_TYPE_ARRAY, "o") < 0) + return -1; for (int i = 0; domains[i] != NULL; i += 1) { _cleanup_(virtDBusUtilFreep) char *path = NULL; @@ -146,125 +110,120 @@ virtDBusConnectListDomains(sd_bus_message *message, path = virtDBusUtilBusPathForVirDomain(domains[i], connect->domainPath); - r = sd_bus_message_append(reply, "o", path); - if (r < 0) - return r; + if (virtDBusMessageAppendBasic(reply, DBUS_TYPE_OBJECT_PATH, &path) < 0) + return -1; } - r = sd_bus_message_close_container(reply); - if (r < 0) - return r; + if (virtDBusMessageCloseContainer(reply) < 0) + return -1; - return sd_bus_send(NULL, reply, NULL); + return virtDBusSendMessage(reply); } static int -virtDBusConnectCreateXML(sd_bus_message *message, - void *userdata, - sd_bus_error *error) +virtDBusConnectCreateXML(virtDBusMessage *msg, + void *data) { - virtDBusConnect *connect = userdata; - const char *xml; - uint32_t flags; + virtDBusConnect *connect = data; + _cleanup_(virtDBusMessageFreep) virtDBusMessage *reply = NULL; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; _cleanup_(virtDBusUtilFreep) char *path = NULL; - int r; + const char *xml; + uint32_t flags; - r = sd_bus_message_read(message, "su", &xml, &flags); - if (r < 0) - return r; + if (virtDBusMessageReadBasic(msg, DBUS_TYPE_STRING, &xml) < 0) + return -1; - r = virtDBusConnectOpen(connect, error); - if (r < 0) - return r; + if (virtDBusMessageReadBasic(msg, DBUS_TYPE_UINT32, &flags) < 0) + return -1; + + if (virtDBusConnectOpen(connect, msg) < 0) + return -1; domain = virDomainCreateXML(connect->connection, xml, flags); if (!domain) - return virtDBusUtilSetLastVirtError(error); + return virtDBusUtilSetLastVirtError(msg); path = virtDBusUtilBusPathForVirDomain(domain, connect->domainPath); - return sd_bus_reply_method_return(message, "o", path); + reply = virtDBusMessageMethodReturn(msg); + if (!reply) + return -1; + + if (virtDBusMessageAppendBasic(reply, DBUS_TYPE_OBJECT_PATH, &path) < 0) + return -1; + + return virtDBusSendMessage(reply); } static int -virtDBusConnectDefineXML(sd_bus_message *message, - void *userdata, - sd_bus_error *error) +virtDBusConnectDefineXML(virtDBusMessage *msg, + void *data) { - virtDBusConnect *connect = userdata; - const char *xml; + virtDBusConnect *connect = data; + _cleanup_(virtDBusMessageFreep) virtDBusMessage *reply = NULL; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; _cleanup_(virtDBusUtilFreep) char *path = NULL; - int r; + const char *xml; - r = sd_bus_message_read(message, "s", &xml); - if (r < 0) - return r; + if (virtDBusMessageReadBasic(msg, DBUS_TYPE_STRING, &xml) < 0) + return -1; - r = virtDBusConnectOpen(connect, error); - if (r < 0) - return r; + if (virtDBusConnectOpen(connect, msg) < 0) + return -1; domain = virDomainDefineXML(connect->connection, xml); if (!domain) - return virtDBusUtilSetLastVirtError(error); + return virtDBusUtilSetLastVirtError(msg); path = virtDBusUtilBusPathForVirDomain(domain, connect->domainPath); - return sd_bus_reply_method_return(message, "o", path); -} - -static const sd_bus_vtable virt_connect_vtable[] = { - SD_BUS_VTABLE_START(0), + reply = virtDBusMessageMethodReturn(msg); + if (!reply) + return -1; - SD_BUS_METHOD("ListDomains", "u", "ao", virtDBusConnectListDomains, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("CreateXML", "su", "o", virtDBusConnectCreateXML, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("DefineXML", "s", "o", virtDBusConnectDefineXML, SD_BUS_VTABLE_UNPRIVILEGED), + if (virtDBusMessageAppendBasic(reply, DBUS_TYPE_OBJECT_PATH, &path) < 0) + return -1; - SD_BUS_SIGNAL("DomainDefined", "so", 0), - SD_BUS_SIGNAL("DomainUndefined", "so", 0), - SD_BUS_SIGNAL("DomainStarted", "so", 0), - SD_BUS_SIGNAL("DomainSuspended", "so", 0), - SD_BUS_SIGNAL("DomainResumed", "so", 0), - SD_BUS_SIGNAL("DomainStopped", "so", 0), - SD_BUS_SIGNAL("DomainShutdown", "so", 0), - SD_BUS_SIGNAL("DomainPMSuspended", "so", 0), - SD_BUS_SIGNAL("DomainCrashed", "so", 0), + return virtDBusSendMessage(reply); +} - SD_BUS_VTABLE_END +static virtDBusMethodHandlers virtDBusConnectMethods[] = { + { "CreateXML", "su", virtDBusConnectCreateXML }, + { "DefineXML", "s", virtDBusConnectDefineXML }, + { "ListDomains", "u", virtDBusConnectListDomains }, + { NULL, NULL, NULL }, }; int virtDBusConnectNew(virtDBusConnect **connectp, - sd_bus *bus, + virtDBusObjectList *objectList, + DBusConnection *bus, const char *uri, const char *connectPath) { _cleanup_(virtDBusConnectFreep) virtDBusConnect *connect = NULL; - int r; connect = calloc(1, sizeof(virtDBusConnect)); for (int i = 0; i < VIR_DOMAIN_EVENT_ID_LAST; i += 1) connect->callback_ids[i] = -1; - connect->bus = sd_bus_ref(bus); + connect->bus = dbus_connection_ref(bus); connect->uri = uri; connect->connectPath = connectPath; - connect->enumerateDomains = virtDBusConnectEnumarateDomains; - - r = sd_bus_add_object_vtable(connect->bus, - NULL, - connect->connectPath, - VIRT_DBUS_CONNECT_INTERFACE, - virt_connect_vtable, - connect); - if (r < 0) - return r; + if (virtDBusObjectListRegister(objectList, + connect->connectPath, + &introspectXML, + VIRT_DBUS_CONNECT_INTERFACE, + VIRT_DBUS_OBJECT_TYPE_MATCH, + NULL, + virtDBusConnectMethods, + connect) < 0) + return -1; - if ((r = virtDBusDomainRegister(connect, bus) < 0)) - return r; + if (virtDBusDomainRegister(connect, objectList) < 0) + return -1; *connectp = connect; connect = NULL; @@ -276,7 +235,7 @@ virtDBusConnect * virtDBusConnectFree(virtDBusConnect *connect) { if (connect->bus) - sd_bus_unref(connect->bus); + dbus_connection_unref(connect->bus); if (connect->connection) virtDBusConnectClose(connect, true); diff --git a/src/connect.h b/src/connect.h index 9e5f533..e685b41 100644 --- a/src/connect.h +++ b/src/connect.h @@ -2,37 +2,37 @@ #define VIR_ENUM_SENTINELS +#include <dbus/dbus.h> #include <libvirt/libvirt.h> -#include <systemd/sd-bus.h> #define VIRT_DBUS_CONNECT_INTERFACE "org.libvirt.Connect" -struct virtDBusConnect { - sd_bus *bus; +struct _virtDBusConnect { + DBusConnection *bus; const char *uri; const char *connectPath; char *domainPath; virConnectPtr connection; - sd_bus_node_enumerator_t enumerateDomains; - int callback_ids[VIR_DOMAIN_EVENT_ID_LAST]; }; -typedef struct virtDBusConnect virtDBusConnect; +typedef struct _virtDBusConnect virtDBusConnect; int virtDBusConnectNew(virtDBusConnect **connectp, - sd_bus *bus, + virtDBusObjectList *objectList, + DBusConnection *bus, const char *uri, const char *connectPath); int virtDBusConnectOpen(virtDBusConnect *connect, - sd_bus_error *error); + virtDBusMessage *msg); virtDBusConnect * virtDBusConnectFree(virtDBusConnect *connect); + void virtDBusConnectFreep(virtDBusConnect **connectp); diff --git a/src/domain.c b/src/domain.c index daff32d..394be33 100644 --- a/src/domain.c +++ b/src/domain.c @@ -1,27 +1,31 @@ #define _GNU_SOURCE +#include "dbus.h" #include "domain.h" #include "util.h" #include <libvirt/libvirt.h> #include <stdio.h> +#include <stdint.h> +#include <string.h> + +static const char *introspectXML = NULL; static virDomainPtr virtDBusDomainGetVirDomain(virtDBusConnect *connect, - const char *path, - sd_bus_error *error) + virtDBusMessage *msg) { virDomainPtr domain; + const char *path = virtDBusMessageGetPath(msg); - if (virtDBusConnectOpen(connect, error) < 0) + if (virtDBusConnectOpen(connect, msg) < 0) return NULL; domain = virtDBusUtilVirDomainFromBusPath(connect->connection, path, connect->domainPath); - if (domain == NULL) { - sd_bus_error_setf(error, - SD_BUS_ERROR_UNKNOWN_OBJECT, - "Unknown object '%s'.", path); + if (!domain) { + virtDBusMessageSetError(msg, DBUS_ERROR_UNKNOWN_OBJECT, + "invalid domain object '%s'", path); return NULL; } @@ -29,177 +33,177 @@ virtDBusDomainGetVirDomain(virtDBusConnect *connect, } static int -virtDBusDomainGetName(sd_bus *bus VIRT_ATTR_UNUSED, - const char *path, +virtDBusDomainGetName(virtDBusMessage *reply, + virtDBusMessage *msg, const char *interface VIRT_ATTR_UNUSED, const char *property VIRT_ATTR_UNUSED, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error VIRT_ATTR_UNUSED) + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; - const char *name = ""; + const char *name = NULL; - domain = virtDBusDomainGetVirDomain(connect, path, error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; name = virDomainGetName(domain); - if (name == NULL) - return sd_bus_message_append(reply, "s", ""); + if (!name) + name = ""; - return sd_bus_message_append(reply, "s", name); + return virtDBusMessageAppendVariant(reply, DBUS_TYPE_STRING, + "s", &name); } static int -virtDBusDomainGetUUID(sd_bus *bus VIRT_ATTR_UNUSED, - const char *path, +virtDBusDomainGetUUID(virtDBusMessage *reply, + virtDBusMessage *msg, const char *interface VIRT_ATTR_UNUSED, const char *property VIRT_ATTR_UNUSED, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error VIRT_ATTR_UNUSED) + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; char uuid[VIR_UUID_STRING_BUFLEN] = ""; + char *tmp; - domain = virtDBusDomainGetVirDomain(connect, path, error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; virDomainGetUUIDString(domain, uuid); + tmp = uuid; - return sd_bus_message_append(reply, "s", uuid); + return virtDBusMessageAppendVariant(reply, DBUS_TYPE_STRING, + "s", &tmp); } static int -virtDBusDomainGetId(sd_bus *bus VIRT_ATTR_UNUSED, - const char *path, +virtDBusDomainGetId(virtDBusMessage *reply, + virtDBusMessage *msg, const char *interface VIRT_ATTR_UNUSED, const char *property VIRT_ATTR_UNUSED, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error VIRT_ATTR_UNUSED) + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; + unsigned int id; - domain = virtDBusDomainGetVirDomain(connect, path, error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; - return sd_bus_message_append(reply, "u", virDomainGetID(domain)); + id = virDomainGetID(domain); + + return virtDBusMessageAppendVariant(reply, DBUS_TYPE_UINT32, + "u", &id); } static int -virtDBusDomainGetVcpus(sd_bus *bus VIRT_ATTR_UNUSED, - const char *path, +virtDBusDomainGetVcpus(virtDBusMessage *reply, + virtDBusMessage *msg, const char *interface VIRT_ATTR_UNUSED, const char *property VIRT_ATTR_UNUSED, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error VIRT_ATTR_UNUSED) + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; + int vcpus; - domain = virtDBusDomainGetVirDomain(connect, path, error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; - return sd_bus_message_append(reply, "u", virDomainGetVcpusFlags(domain, VIR_DOMAIN_VCPU_CURRENT)); + vcpus = virDomainGetVcpusFlags(domain, VIR_DOMAIN_VCPU_CURRENT); + + return virtDBusMessageAppendVariant(reply, DBUS_TYPE_UINT32, + "u", &vcpus); } static int -virtDBusDomainGetOsType(sd_bus *bus VIRT_ATTR_UNUSED, - const char *path, +virtDBusDomainGetOsType(virtDBusMessage *reply, + virtDBusMessage *msg, const char *interface VIRT_ATTR_UNUSED, const char *property VIRT_ATTR_UNUSED, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error VIRT_ATTR_UNUSED) + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; _cleanup_(virtDBusUtilFreep) char *os_type = NULL; - domain = virtDBusDomainGetVirDomain(connect, path, error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; os_type = virDomainGetOSType(domain); - if (os_type == NULL) - return sd_bus_message_append(reply, "s", ""); + if (!os_type) + return virtDBusMessageAppendVariant(reply, DBUS_TYPE_STRING, + "s", &""); - return sd_bus_message_append(reply, "s", os_type); + return virtDBusMessageAppendVariant(reply, DBUS_TYPE_STRING, + "s", &os_type); } static int -virtDBusDomainGetActive(sd_bus *bus VIRT_ATTR_UNUSED, - const char *path, +virtDBusDomainGetActive(virtDBusMessage *reply, + virtDBusMessage *msg, const char *interface VIRT_ATTR_UNUSED, const char *property VIRT_ATTR_UNUSED, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error VIRT_ATTR_UNUSED) + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int active; - domain = virtDBusDomainGetVirDomain(connect, path, error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; active = virDomainIsActive(domain); if (active < 0) - return sd_bus_message_append(reply, "b", 0); + active = 0; - return sd_bus_message_append(reply, "b", active); + return virtDBusMessageAppendVariant(reply, DBUS_TYPE_BOOLEAN, + "b", &active); } static int -virtDBusDomainGetPersistent(sd_bus *bus VIRT_ATTR_UNUSED, - const char *path, +virtDBusDomainGetPersistent(virtDBusMessage *reply, + virtDBusMessage *msg, const char *interface VIRT_ATTR_UNUSED, const char *property VIRT_ATTR_UNUSED, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error VIRT_ATTR_UNUSED) + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int persistent; - domain = virtDBusDomainGetVirDomain(connect, path, error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; persistent = virDomainIsPersistent(domain); if (persistent < 0) - return sd_bus_message_append(reply, "b", 0); + persistent = 0; - return sd_bus_message_append(reply, "b", persistent); + return virtDBusMessageAppendVariant(reply, DBUS_TYPE_BOOLEAN, + "b", &persistent); } static int -virtDBusDomainGetState(sd_bus *bus VIRT_ATTR_UNUSED, - const char *path, +virtDBusDomainGetState(virtDBusMessage *reply, + virtDBusMessage *msg, const char *interface VIRT_ATTR_UNUSED, const char *property VIRT_ATTR_UNUSED, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error VIRT_ATTR_UNUSED) + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int state = 0; const char *string; - domain = virtDBusDomainGetVirDomain(connect, path, error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; virDomainGetState(domain, &state, NULL, 0); @@ -232,57 +236,60 @@ virtDBusDomainGetState(sd_bus *bus VIRT_ATTR_UNUSED, break; } - return sd_bus_message_append(reply, "s", string); + return virtDBusMessageAppendVariant(reply, DBUS_TYPE_STRING, + "s", &string); } static int -virtDBusDomainGetAutostart(sd_bus *bus VIRT_ATTR_UNUSED, - const char *path, +virtDBusDomainGetAutostart(virtDBusMessage *reply, + virtDBusMessage *msg, const char *interface VIRT_ATTR_UNUSED, const char *property VIRT_ATTR_UNUSED, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error VIRT_ATTR_UNUSED) + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; int autostart = 0; - domain = virtDBusDomainGetVirDomain(connect, path, error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; virDomainGetAutostart(domain, &autostart); - return sd_bus_message_append(reply, "b", autostart); + return virtDBusMessageAppendVariant(reply, DBUS_TYPE_BOOLEAN, + "b", &autostart); } static int -virtDBusDomainGetXMLDesc(sd_bus_message *message, - void *userdata, - sd_bus_error *error) +virtDBusDomainGetXMLDesc(virtDBusMessage *msg, + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; + _cleanup_(virtDBusMessageFreep) virtDBusMessage *reply = NULL; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; _cleanup_(virtDBusUtilFreep) char *description = NULL; uint32_t flags; - int r; - r = sd_bus_message_read(message, "u", &flags); - if (r < 0) - return r; + if (virtDBusMessageReadBasic(msg, DBUS_TYPE_UINT32, &flags) < 0) + return -1; - domain = virtDBusDomainGetVirDomain(connect, - sd_bus_message_get_path(message), - error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; description = virDomainGetXMLDesc(domain, flags); if (!description) - return virtDBusUtilSetLastVirtError(error); + return virtDBusUtilSetLastVirtError(msg); + + reply = virtDBusMessageMethodReturn(msg); + if (!reply) + return -1; + + if (virtDBusMessageAppendBasic(reply, DBUS_TYPE_STRING, &description) < 0) + return -1; - return sd_bus_reply_method_return(message, "s", description); + return virtDBusSendMessage(reply); } static void @@ -293,263 +300,195 @@ virtDBusDomainStatsRecordListFreep(virDomainStatsRecordPtr **statsp) } static int -virtDBusDomainGetStats(sd_bus_message *message, - void *userdata, - sd_bus_error *error) +virtDBusDomainGetStats(virtDBusMessage *msg, + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; + _cleanup_(virtDBusMessageFreep) virtDBusMessage *reply = NULL; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; - virDomainPtr domains[2]; _cleanup_(virtDBusDomainStatsRecordListFreep) virDomainStatsRecordPtr *records = NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + virDomainPtr domains[2]; uint32_t flags, stats; - int r; - r = sd_bus_message_read(message, "uu", &stats, &flags); - if (r < 0) - return r; + if (virtDBusMessageReadBasic(msg, DBUS_TYPE_UINT32, &stats) < 0) + return -1; + + if (virtDBusMessageReadBasic(msg, DBUS_TYPE_UINT32, &flags) < 0) + return -1; - domain = virtDBusDomainGetVirDomain(connect, - sd_bus_message_get_path(message), - error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; domains[0] = domain; domains[1] = NULL; if (virDomainListGetStats(domains, stats, &records, flags) != 1) - return virtDBusUtilSetLastVirtError(error); + return virtDBusUtilSetLastVirtError(msg); - r = sd_bus_message_new_method_return(message, &reply); - if (r < 0) - return r; + reply = virtDBusMessageMethodReturn(msg); + if (!reply) + return -1; - r = virtDBusUtilMessageAppendTypedParameters(reply, records[0]->params, records[0]->nparams); - if (r < 0) - return r; + if (virtDBusUtilMessageAppendTypedParameters(reply, + records[0]->params, + records[0]->nparams) < 0) + return -1; - return sd_bus_send(NULL, reply, NULL); + return virtDBusSendMessage(reply); } static int -virtDBusDomainShutdown(sd_bus_message *message, - void *userdata, - sd_bus_error *error) +virtDBusDomainShutdown(virtDBusMessage *msg, + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; - int r; - domain = virtDBusDomainGetVirDomain(connect, - sd_bus_message_get_path(message), - error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; - r = virDomainShutdown(domain); - if (r < 0) - return virtDBusUtilSetLastVirtError(error); + if (virDomainShutdown(domain) < 0) + return virtDBusUtilSetLastVirtError(msg); - return sd_bus_reply_method_return(message, ""); + return virtDBusSendEmptyMessage(msg); } static int -virtDBusDomainDestroy(sd_bus_message *message, - void *userdata, - sd_bus_error *error) +virtDBusDomainDestroy(virtDBusMessage *msg, + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; - int r; - domain = virtDBusDomainGetVirDomain(connect, - sd_bus_message_get_path(message), - error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; - r = virDomainDestroy(domain); - if (r < 0) - return virtDBusUtilSetLastVirtError(error); + if (virDomainDestroy(domain) < 0) + return virtDBusUtilSetLastVirtError(msg); - return sd_bus_reply_method_return(message, ""); + return virtDBusSendEmptyMessage(msg); } static int -virtDBusDomainReboot(sd_bus_message *message, - void *userdata, - sd_bus_error *error) +virtDBusDomainReboot(virtDBusMessage *msg, + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; uint32_t flags; - int r; - r = sd_bus_message_read(message, "u", &flags); - if (r < 0) - return r; + if (virtDBusMessageReadBasic(msg, DBUS_TYPE_UINT32, &flags) < 0) + return -1; - domain = virtDBusDomainGetVirDomain(connect, - sd_bus_message_get_path(message), - error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; - r = virDomainReboot(domain, flags); - if (r < 0) - return virtDBusUtilSetLastVirtError(error); + if (virDomainReboot(domain, flags) < 0) + return virtDBusUtilSetLastVirtError(msg); - return sd_bus_reply_method_return(message, ""); + return virtDBusSendEmptyMessage(msg); } static int -virtDBusDomainReset(sd_bus_message *message, - void *userdata, - sd_bus_error *error) +virtDBusDomainReset(virtDBusMessage *msg, + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; uint32_t flags; - int r; - r = sd_bus_message_read(message, "u", &flags); - if (r < 0) - return r; + if (virtDBusMessageReadBasic(msg, DBUS_TYPE_UINT32, &flags) < 0) + return -1; - domain = virtDBusDomainGetVirDomain(connect, - sd_bus_message_get_path(message), - error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; - r = virDomainReset(domain, flags); - if (r < 0) - return virtDBusUtilSetLastVirtError(error); + if (virDomainReset(domain, flags) < 0) + return virtDBusUtilSetLastVirtError(msg); - return sd_bus_reply_method_return(message, ""); + return virtDBusSendEmptyMessage(msg); } static int -virtDBusDomainCreate(sd_bus_message *message, - void *userdata, - sd_bus_error *error) +virtDBusDomainCreate(virtDBusMessage *msg, + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; - int r; - domain = virtDBusDomainGetVirDomain(connect, - sd_bus_message_get_path(message), - error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; - r = virDomainCreate(domain); - if (r < 0) - return virtDBusUtilSetLastVirtError(error); + if (virDomainCreate(domain) < 0) + return virtDBusUtilSetLastVirtError(msg); - return sd_bus_reply_method_return(message, ""); + return virtDBusSendEmptyMessage(msg); } static int -virtDBusDomainUndefine(sd_bus_message *message, - void *userdata, - sd_bus_error *error) +virtDBusDomainUndefine(virtDBusMessage *msg, + void *data) { - virtDBusConnect *connect = userdata; + virtDBusConnect *connect = data; _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; - int r; - domain = virtDBusDomainGetVirDomain(connect, - sd_bus_message_get_path(message), - error); - if (domain == NULL) + domain = virtDBusDomainGetVirDomain(connect, msg); + if (!domain) return -1; - r = virDomainUndefine(domain); - if (r < 0) - return virtDBusUtilSetLastVirtError(error); + if (virDomainUndefine(domain) < 0) + return virtDBusUtilSetLastVirtError(msg); - return sd_bus_reply_method_return(message, ""); + return virtDBusSendEmptyMessage(msg); } -static const sd_bus_vtable virt_domain_vtable[] = { - SD_BUS_VTABLE_START(0), - - SD_BUS_PROPERTY("Name", "s", virtDBusDomainGetName, 0, 0), - SD_BUS_PROPERTY("UUID", "s", virtDBusDomainGetUUID, 0, 0), - SD_BUS_PROPERTY("Id", "u", virtDBusDomainGetId, 0, 0), - SD_BUS_PROPERTY("Vcpus", "u", virtDBusDomainGetVcpus, 0, 0), - SD_BUS_PROPERTY("OSType", "s", virtDBusDomainGetOsType, 0, 0), - SD_BUS_PROPERTY("Active", "b", virtDBusDomainGetActive, 0, 0), - SD_BUS_PROPERTY("Persistent", "b", virtDBusDomainGetPersistent, 0, 0), - SD_BUS_PROPERTY("State", "s", virtDBusDomainGetState, 0, 0), - SD_BUS_PROPERTY("Autostart", "b", virtDBusDomainGetAutostart, 0, 0), - - SD_BUS_METHOD("GetXMLDesc", "u", "s", virtDBusDomainGetXMLDesc, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("GetStats", "uu", "a{sv}", virtDBusDomainGetStats, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("Shutdown", "", "", virtDBusDomainShutdown, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("Destroy", "", "", virtDBusDomainDestroy, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("Reboot", "u", "", virtDBusDomainReboot, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("Reset", "u", "", virtDBusDomainReset, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("Create", "", "", virtDBusDomainCreate, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("Undefine", "", "", virtDBusDomainUndefine, SD_BUS_VTABLE_UNPRIVILEGED), - - SD_BUS_SIGNAL("DeviceAdded", "s", 0), - SD_BUS_SIGNAL("DeviceRemoved", "s", 0), - SD_BUS_SIGNAL("DiskChange", "ssss", 0), - SD_BUS_SIGNAL("TrayChange", "ss", 0), - - SD_BUS_VTABLE_END +static virtDBusPropertyHandlers virtDBusDomainProperties[] = { + { "Name", virtDBusDomainGetName, NULL }, + { "UUID", virtDBusDomainGetUUID, NULL }, + { "Id", virtDBusDomainGetId, NULL }, + { "Vcpus", virtDBusDomainGetVcpus, NULL }, + { "OSType", virtDBusDomainGetOsType, NULL }, + { "Active", virtDBusDomainGetActive, NULL }, + { "Persistent", virtDBusDomainGetPersistent, NULL }, + { "State", virtDBusDomainGetState, NULL }, + { "Autostart", virtDBusDomainGetAutostart, NULL }, + { NULL, NULL, NULL }, }; -static int -virtDBusDomainLookup(sd_bus *bus VIRT_ATTR_UNUSED, - const char *path, - const char *interface VIRT_ATTR_UNUSED, - void *userdata, - void **found, - sd_bus_error *error VIRT_ATTR_UNUSED) -{ - virtDBusConnect *connect = userdata; - _cleanup_(virtDBusUtilFreep) char *name = NULL; - _cleanup_(virtDBusUtilVirDomainFreep) virDomainPtr domain = NULL; - - domain = virtDBusDomainGetVirDomain(connect, path, error); - if (!domain) - return 0; - - /* - * There's no way to unref the pointer we're returning here. So, - * return the connect object and look up the domain again in the - * domain_* callbacks. - */ - *found = connect; - - return 1; -} +static virtDBusMethodHandlers virtDBusDomainMethods[] = { + { "GetXMLDesc", "u", virtDBusDomainGetXMLDesc }, + { "GetStats", "u", virtDBusDomainGetStats }, + { "Shutdown", "", virtDBusDomainShutdown }, + { "Destroy", "", virtDBusDomainDestroy }, + { "Reboot", "u", virtDBusDomainReboot }, + { "Reset", "u", virtDBusDomainReset }, + { "Create", "", virtDBusDomainCreate }, + { "Undefine", "", virtDBusDomainUndefine }, + { NULL, NULL, NULL }, +}; int virtDBusDomainRegister(virtDBusConnect *connect, - sd_bus *bus) + virtDBusObjectList *objectList) { - int r; - - r = asprintf(&connect->domainPath, "%s/domain", connect->connectPath); - if (r < 0) - return r; - - r = sd_bus_add_node_enumerator(bus, NULL, connect->domainPath, - connect->enumerateDomains, connect); - if (r < 0) - return r; - - return sd_bus_add_fallback_vtable(bus, - NULL, - connect->domainPath, - VIRT_DBUS_DOMAIN_INTERFACE, - virt_domain_vtable, - virtDBusDomainLookup, - connect); + if (asprintf(&connect->domainPath, "%s/domain", connect->connectPath) < 0) + return -1; + + if (virtDBusObjectListRegister(objectList, + connect->domainPath, + &introspectXML, + VIRT_DBUS_DOMAIN_INTERFACE, + VIRT_DBUS_OBJECT_TYPE_PREFIX, + virtDBusDomainProperties, + virtDBusDomainMethods, + connect) < 0) + return -1; + + return 0; } diff --git a/src/domain.h b/src/domain.h index 03a29ed..45db0f5 100644 --- a/src/domain.h +++ b/src/domain.h @@ -2,10 +2,8 @@ #include "connect.h" -#include <systemd/sd-bus.h> - #define VIRT_DBUS_DOMAIN_INTERFACE "org.libvirt.Domain" int virtDBusDomainRegister(virtDBusConnect *connect, - sd_bus *bus); + virtDBusObjectList *objectList); diff --git a/src/events.c b/src/events.c index c45acd7..8368a30 100644 --- a/src/events.c +++ b/src/events.c @@ -1,10 +1,10 @@ +#include "dbus.h" #include "domain.h" #include "events.h" #include "util.h" #include <assert.h> #include <libvirt/libvirt.h> -#include <systemd/sd-bus.h> static int virtDBusEventsDomainLifecycle(virConnectPtr connection VIRT_ATTR_UNUSED, @@ -14,11 +14,10 @@ virtDBusEventsDomainLifecycle(virConnectPtr connection VIRT_ATTR_UNUSED, void *opaque) { virtDBusConnect *connect = opaque; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL; + _cleanup_(virtDBusMessageFreep) virtDBusMessage *msg = NULL; const char *signal = NULL; const char *name; _cleanup_(virtDBusUtilFreep) char *path = NULL; - int r; switch (event) { case VIR_DOMAIN_EVENT_DEFINED: @@ -52,22 +51,23 @@ virtDBusEventsDomainLifecycle(virConnectPtr connection VIRT_ATTR_UNUSED, return 0; } - r = sd_bus_message_new_signal(connect->bus, - &message, - connect->connectPath, - VIRT_DBUS_CONNECT_INTERFACE, - signal); - if (r < 0) - return r; + msg = virtDBusMessageNewSignal(connect->bus, + connect->connectPath, + VIRT_DBUS_CONNECT_INTERFACE, + signal); + if (!msg) + return -1; name = virDomainGetName(domain); path = virtDBusUtilBusPathForVirDomain(domain, connect->domainPath); - r = sd_bus_message_append(message, "so", name ? : "", path); - if (r < 0) - return r; + if (virtDBusMessageAppendBasic(msg, DBUS_TYPE_STRING, &name) < 0) + return -1; - return sd_bus_send(connect->bus, message, NULL); + if (virtDBusMessageAppendBasic(msg, DBUS_TYPE_OBJECT_PATH, &path) < 0) + return -1; + + return virtDBusSendMessage(msg); } static int @@ -77,25 +77,22 @@ virtDBusEventsDomainDeviceAdded(virConnectPtr connection VIRT_ATTR_UNUSED, void *opaque) { virtDBusConnect *connect = opaque; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL; + _cleanup_(virtDBusMessageFreep) virtDBusMessage *msg = NULL; _cleanup_(virtDBusUtilFreep) char *path = NULL; - int r; path = virtDBusUtilBusPathForVirDomain(domain, connect->domainPath); - r = sd_bus_message_new_signal(connect->bus, - &message, - path, - VIRT_DBUS_DOMAIN_INTERFACE, - "DeviceAdded"); - if (r < 0) - return r; + msg = virtDBusMessageNewSignal(connect->bus, + path, + VIRT_DBUS_DOMAIN_INTERFACE, + "DeviceAdded"); + if (!msg) + return -1; - r = sd_bus_message_append(message, "s", device); - if (r < 0) - return r; + if (virtDBusMessageAppendBasic(msg, DBUS_TYPE_STRING, &device) < 0) + return -1; - return sd_bus_send(connect->bus, message, NULL); + return virtDBusSendMessage(msg); } static int @@ -105,25 +102,23 @@ virtDBusEventsDomainDeviceRemoved(virConnectPtr connection VIRT_ATTR_UNUSED, void *opaque) { virtDBusConnect *connect = opaque; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL; + _cleanup_(virtDBusMessageFreep) virtDBusMessage *msg = NULL; _cleanup_(virtDBusUtilFreep) char *path = NULL; - int r; path = virtDBusUtilBusPathForVirDomain(domain, connect->domainPath); - r = sd_bus_message_new_signal(connect->bus, - &message, - path, - VIRT_DBUS_DOMAIN_INTERFACE, - "DeviceRemoved"); - if (r < 0) - return r; + msg = virtDBusMessageNewSignal(connect->bus, + path, + VIRT_DBUS_DOMAIN_INTERFACE, + "DeviceRemoved"); + + if (!msg) + return -1; - r = sd_bus_message_append(message, "s", device); - if (r < 0) - return r; + if (virtDBusMessageAppendBasic(msg, DBUS_TYPE_STRING, &device) < 0) + return -1; - return sd_bus_send(connect->bus, message, NULL); + return virtDBusSendMessage(msg); } static int @@ -134,20 +129,18 @@ virtDBusEventsDomainTrayChange(virConnectPtr connection VIRT_ATTR_UNUSED, void *opaque) { virtDBusConnect *connect = opaque; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL; + _cleanup_(virtDBusMessageFreep) virtDBusMessage *msg = NULL; _cleanup_(virtDBusUtilFreep) char *path = NULL; const char *reasonstr; - int r; path = virtDBusUtilBusPathForVirDomain(domain, connect->domainPath); - r = sd_bus_message_new_signal(connect->bus, - &message, - path, - VIRT_DBUS_DOMAIN_INTERFACE, - "TrayChange"); - if (r < 0) - return r; + msg = virtDBusMessageNewSignal(connect->bus, + path, + VIRT_DBUS_DOMAIN_INTERFACE, + "TrayChange"); + if (!msg) + return -1; switch (reason) { case VIR_DOMAIN_EVENT_TRAY_CHANGE_OPEN: @@ -161,11 +154,13 @@ virtDBusEventsDomainTrayChange(virConnectPtr connection VIRT_ATTR_UNUSED, break; } - r = sd_bus_message_append(message, "ss", device, reasonstr); - if (r < 0) - return r; + if (virtDBusMessageAppendBasic(msg, DBUS_TYPE_STRING, &device) < 0) + return -1; + + if (virtDBusMessageAppendBasic(msg, DBUS_TYPE_STRING, &reasonstr) < 0) + return -1; - return sd_bus_send(connect->bus, message, NULL); + return virtDBusSendMessage(msg); } static int @@ -178,20 +173,18 @@ virtDBusEventsDomainDiskChange(virConnectPtr connection VIRT_ATTR_UNUSED, void *opaque) { virtDBusConnect *connect = opaque; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL; + _cleanup_(virtDBusMessageFreep) virtDBusMessage *msg = NULL; _cleanup_(virtDBusUtilFreep) char *path = NULL; const char *reasonstr; - int r; path = virtDBusUtilBusPathForVirDomain(domain, connect->domainPath); - r = sd_bus_message_new_signal(connect->bus, - &message, - path, - VIRT_DBUS_DOMAIN_INTERFACE, - "DiskChange"); - if (r < 0) - return r; + msg = virtDBusMessageNewSignal(connect->bus, + path, + VIRT_DBUS_DOMAIN_INTERFACE, + "DiskChange"); + if (!msg) + return -1; switch (reason) { case VIR_DOMAIN_EVENT_DISK_CHANGE_MISSING_ON_START: @@ -205,11 +198,19 @@ virtDBusEventsDomainDiskChange(virConnectPtr connection VIRT_ATTR_UNUSED, break; } - r = sd_bus_message_append(message, "ssss", old_src_path, new_src_path, device, reasonstr); - if (r < 0) - return r; + if (virtDBusMessageAppendBasic(msg, DBUS_TYPE_STRING, &old_src_path) < 0) + return -1; + + if (virtDBusMessageAppendBasic(msg, DBUS_TYPE_STRING, &new_src_path) < 0) + return -1; + + if (virtDBusMessageAppendBasic(msg, DBUS_TYPE_STRING, &device) < 0) + return -1; + + if (virtDBusMessageAppendBasic(msg, DBUS_TYPE_STRING, &reasonstr) < 0) + return -1; - return sd_bus_send(connect->bus, message, NULL); + return virtDBusSendMessage(msg); } static void diff --git a/src/main.c b/src/main.c index 6f11aab..bef5dcc 100644 --- a/src/main.c +++ b/src/main.c @@ -1,44 +1,31 @@ #include "config.h" +#include "dbus.h" #include "connect.h" +#include "domain.h" #include "util.h" #include <errno.h> #include <getopt.h> #include <poll.h> +#include <signal.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/signalfd.h> -#include <systemd/sd-bus.h> #include <unistd.h> -static int loop_status; +static int loop_status = 0; static int -virtDBusGetLibvirtEvents(sd_bus *bus) -{ - int events; - int virt_events = 0; - - events = sd_bus_get_events(bus); - - if (events & POLLIN) - virt_events |= VIR_EVENT_HANDLE_READABLE; - - if (events & POLLOUT) - virt_events |= VIR_EVENT_HANDLE_WRITABLE; - - return virt_events; -} - -static int -virtDBusProcessEvents(sd_bus *bus) +virtDBusProcessEvents(DBusConnection *bus, + virtDBusObjectList *objectList) { for (;;) { int r; - r = sd_bus_process(bus, NULL); + r = virtDBusDispatchMessage(bus, objectList); if (r < 0) return r; @@ -65,22 +52,6 @@ virtDBusHandleSignal(int watch VIRT_ATTR_UNUSED, loop_status = -ECANCELED; } -static void -virtDBusHandleBusEvent(int watch, - int fd VIRT_ATTR_UNUSED, - int events VIRT_ATTR_UNUSED, - void *opaque) -{ - sd_bus *bus = opaque; - - loop_status = virtDBusProcessEvents(bus); - - if (loop_status < 0) - return; - - virEventUpdateHandle(watch, virtDBusGetLibvirtEvents(bus)); -} - struct virtDBusDriver { const char *uri; const char *object; @@ -123,23 +94,23 @@ main(int argc, char *argv[]) {} }; - bool system_bus; + DBusBusType busType; const struct virtDBusDriver *drivers = NULL; int ndrivers = 0; - _cleanup_(virtDBusConnectListFree) virtDBusConnect **connect = NULL; - _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_(virtDBusConnectListFree) virtDBusConnect **connectList = NULL; + _cleanup_(virtDBusObjectListFree) virtDBusObjectList objectList = { 0 }; + _cleanup_(virtDBusConnectionClose) DBusConnection *bus = NULL; _cleanup_(virtDBusUtilClosep) int signal_fd = -1; - _cleanup_(virtDBusVirEventRemoveHandlep) int bus_watch = -1; _cleanup_(virtDBusVirEventRemoveHandlep) int signal_watch = -1; sigset_t mask; int c; int r; if (geteuid() == 0) { - system_bus = true; + busType = DBUS_BUS_SYSTEM; } else { - system_bus = false; + busType = DBUS_BUS_SESSION; } while ((c = getopt_long(argc, argv, "hc:", options, NULL)) >= 0) { @@ -155,11 +126,11 @@ main(int argc, char *argv[]) return 0; case ARG_SYSTEM: - system_bus = true; + busType = DBUS_BUS_SYSTEM; break; case ARG_SESSION: - system_bus = false; + busType = DBUS_BUS_SESSION; break; default: @@ -174,19 +145,11 @@ main(int argc, char *argv[]) virEventRegisterDefaultImpl(); - r = system_bus ? sd_bus_open_system(&bus) : sd_bus_open_user(&bus); - if (r < 0) { - fprintf(stderr, "Failed to connect to session bus: %s\n", strerror(-r)); + bus = virtDBusConnectionOpen(busType, "org.libvirt"); + if (!bus) return EXIT_FAILURE; - } - - r = sd_bus_request_name(bus, "org.libvirt", 0); - if (r < 0) { - fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-r)); - return EXIT_FAILURE; - } - if (system_bus) { + if (busType == DBUS_BUS_SYSTEM) { drivers = systemDrivers; ndrivers = VIRT_N_ELEMENTS(systemDrivers); } else { @@ -194,10 +157,10 @@ main(int argc, char *argv[]) ndrivers = VIRT_N_ELEMENTS(sessionDrivers); } - connect = calloc(ndrivers + 1, sizeof(virtDBusConnect *)); + connectList = calloc(ndrivers + 1, sizeof(virtDBusConnect *)); for (int i = 0; i < ndrivers; i += 1) { - r = virtDBusConnectNew(&connect[i], bus, + r = virtDBusConnectNew(&connectList[i], &objectList, bus, drivers[i].uri, drivers[i].object); if (r < 0) { fprintf(stderr, "Failed to register libvirt connection.\n"); @@ -205,16 +168,6 @@ main(int argc, char *argv[]) } } - r = virtDBusProcessEvents(bus); - if (r < 0) - return EXIT_FAILURE; - - bus_watch = virEventAddHandle(sd_bus_get_fd(bus), - virtDBusGetLibvirtEvents(bus), - virtDBusHandleBusEvent, - bus, - NULL); - signal_fd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC); signal_watch = virEventAddHandle(signal_fd, VIR_EVENT_HANDLE_READABLE, @@ -226,9 +179,18 @@ main(int argc, char *argv[]) return EXIT_FAILURE; } - while (loop_status >= 0) + r = virtDBusProcessEvents(bus, &objectList); + if (r < 0) + return EXIT_FAILURE; + + while (loop_status >= 0) { virEventRunDefaultImpl(); + r = virtDBusProcessEvents(bus, &objectList); + if (r < 0) + return EXIT_FAILURE; + } + if (loop_status < 0 && loop_status != -ECANCELED) { fprintf(stderr, "Error: %s\n", strerror(-loop_status)); return EXIT_FAILURE; diff --git a/src/util.c b/src/util.c index b6919fb..6f8b7be 100644 --- a/src/util.c +++ b/src/util.c @@ -6,6 +6,7 @@ #include <libvirt/virterror.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> @@ -14,77 +15,79 @@ #define VIRT_UTIL_FILE_LIMIT 1024 * 1024 int -virtDBusUtilMessageAppendTypedParameters(sd_bus_message *message, - virTypedParameterPtr parameters, - int n_parameters) +virtDBusUtilMessageAppendTypedParameters(virtDBusMessage *msg, + virTypedParameterPtr params, + int nparams) { - int r; + if (virtDBusMessageOpenContainer(msg, DBUS_TYPE_ARRAY, "{sv}") < 0) + return -1; - r = sd_bus_message_open_container(message, 'a', "{sv}"); - if (r < 0) - return r; + for (int i = 0; i < nparams; i += 1) { + if (virtDBusMessageOpenContainer(msg, DBUS_TYPE_DICT_ENTRY, NULL) < 0) + return -1; - for (int i = 0; i < n_parameters; i += 1) { - r = sd_bus_message_open_container(message, SD_BUS_TYPE_DICT_ENTRY, "sv"); - if (r < 0) - return r; + if (virtDBusMessageAppendBasic(msg, DBUS_TYPE_STRING, ¶ms[i].field) < 0) + return -1; - r = sd_bus_message_append(message, "s", parameters[i].field); - if (r < 0) - return r; - - switch (parameters[i].type) { + switch (params[i].type) { case VIR_TYPED_PARAM_INT: - r = sd_bus_message_append(message, "v", "i", parameters[i].value.i); + if (virtDBusMessageAppendVariant(msg, DBUS_TYPE_INT32, + "i", ¶ms[i].value.i) < 0) + return -1; break; case VIR_TYPED_PARAM_UINT: - r = sd_bus_message_append(message, "v", "u", parameters[i].value.ui); + if (virtDBusMessageAppendVariant(msg, DBUS_TYPE_UINT32, + "u", ¶ms[i].value.ui) < 0) + return -1; break; case VIR_TYPED_PARAM_LLONG: - r = sd_bus_message_append(message, "v", "x", parameters[i].value.l); + if (virtDBusMessageAppendVariant(msg, DBUS_TYPE_INT64, + "x", ¶ms[i].value.l) < 0) + return -1; break; case VIR_TYPED_PARAM_ULLONG: - r = sd_bus_message_append(message, "v", "t", parameters[i].value.ul); + if (virtDBusMessageAppendVariant(msg, DBUS_TYPE_UINT64, + "t", ¶ms[i].value.ul) < 0) + return -1; break; case VIR_TYPED_PARAM_DOUBLE: - r = sd_bus_message_append(message, "v", "d", parameters[i].value.d); + if (virtDBusMessageAppendVariant(msg, DBUS_TYPE_DOUBLE, + "d", ¶ms[i].value.d) < 0) + return -1; break; case VIR_TYPED_PARAM_BOOLEAN: - r = sd_bus_message_append(message, "v", "b", parameters[i].value.b); + if (virtDBusMessageAppendVariant(msg, DBUS_TYPE_BOOLEAN, + "b", ¶ms[i].value.b) < 0) + return -1; break; case VIR_TYPED_PARAM_STRING: - r = sd_bus_message_append(message, "v", "s", parameters[i].value.s); + if (virtDBusMessageAppendVariant(msg, DBUS_TYPE_STRING, + "s", ¶ms[i].value.s) < 0) + return -1; break; } - if (r < 0) - return r; - - r = sd_bus_message_close_container(message); - if (r < 0) - return r; + if (virtDBusMessageCloseContainer(msg) < 0) + return -1; } - return sd_bus_message_close_container(message); + return virtDBusMessageCloseContainer(msg); } int -virtDBusUtilSetLastVirtError(sd_bus_error *error) +virtDBusUtilSetLastVirtError(virtDBusMessage *msg) { - virErrorPtr vir_error; + virErrorPtr virError; - vir_error = virGetLastError(); - if (!vir_error) - return 0; + virError = virGetLastError(); - return sd_bus_error_set(error, VIRT_DBUS_ERROR_INTERFACE, vir_error->message); -} + if (!virError) { + return virtDBusMessageSetError(msg, VIRT_DBUS_ERROR_INTERFACE, + "unknown error"); + } -int -virtDBusUtilSetError(sd_bus_error *error, - const char *message) -{ - return sd_bus_error_set(error, VIRT_DBUS_ERROR_INTERFACE, message); + return virtDBusMessageSetError(msg, VIRT_DBUS_ERROR_INTERFACE, "%s", + virError->message); } char * diff --git a/src/util.h b/src/util.h index c42d2cc..16c54df 100644 --- a/src/util.h +++ b/src/util.h @@ -1,7 +1,8 @@ #pragma once +#include "dbus.h" + #include <libvirt/libvirt.h> -#include <systemd/sd-bus.h> #define VIRT_DBUS_ERROR_INTERFACE "org.libvirt.Error" @@ -18,16 +19,12 @@ } while(0) int -virtDBusUtilMessageAppendTypedParameters(sd_bus_message *message, - virTypedParameterPtr parameters, - int n_parameters); - -int -virtDBusUtilSetLastVirtError(sd_bus_error *error); +virtDBusUtilMessageAppendTypedParameters(virtDBusMessage *msg, + virTypedParameterPtr params, + int nparams); int -virtDBusUtilSetError(sd_bus_error *error, - const char *message); +virtDBusUtilSetLastVirtError(virtDBusMessage *msg); char * virtDBusUtilReadFile(const char *filename); diff --git a/test/travis-run b/test/travis-run index 47fe70c..7c96609 100755 --- a/test/travis-run +++ b/test/travis-run @@ -22,7 +22,7 @@ sudo chroot "$CHROOT" << EOF set -ex # install build deps apt-get update -apt-get install -y dh-autoreconf pkg-config libvirt-dev libsystemd-dev libdbus-1-dev libtool python3-gi python3-dbus dbus +apt-get install -y dh-autoreconf pkg-config libvirt-dev libdbus-1-dev libtool python3-gi python3-dbus dbus # run build and tests as user chown -R buildd:buildd /build -- 2.14.3

This implements very simple thread pool to process dbus messages in separate threads. We don't need to handle queue for messages because dbus does that for us. The default thread count will be currently 4 and it is also configurable via --threads parameter for the libvirt-dbus daemon. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/Makefile.am | 1 + src/connect.c | 14 +++++++ src/connect.h | 3 ++ src/main.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++------- src/util.c | 28 ++++++++++++++ src/util.h | 9 +++++ 6 files changed, 159 insertions(+), 14 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 9e23f1b..73bbfd9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -32,6 +32,7 @@ libvirt_dbus_LDFLAGS = \ $(DBUS_LDFLAGS) \ $(RELRO_LDFLAGS) \ $(PID_LDFLAGS) \ + -lpthread \ $(NULL) libvirt_dbus_LDADD = \ diff --git a/src/connect.c b/src/connect.c index 2fe305f..41aba5f 100644 --- a/src/connect.c +++ b/src/connect.c @@ -56,10 +56,21 @@ virtDBusConnectClose(virtDBusConnect *connect, connect->connection = NULL; } +static void +virtDBusConnectUnlock(pthread_mutex_t **lock) +{ + if (lock) + pthread_mutex_unlock(*lock); +} + int virtDBusConnectOpen(virtDBusConnect *connect, virtDBusMessage *msg) { + _cleanup_(virtDBusConnectUnlock) pthread_mutex_t *lock = &connect->lock; + + pthread_mutex_lock(lock); + if (connect->connection) { if (virConnectIsAlive(connect->connection)) return 0; @@ -212,6 +223,9 @@ virtDBusConnectNew(virtDBusConnect **connectp, connect->uri = uri; connect->connectPath = connectPath; + if (virtDBusUtilMutexInit(&connect->lock) != 0) + return -1; + if (virtDBusObjectListRegister(objectList, connect->connectPath, &introspectXML, diff --git a/src/connect.h b/src/connect.h index e685b41..c6026c9 100644 --- a/src/connect.h +++ b/src/connect.h @@ -4,10 +4,13 @@ #include <dbus/dbus.h> #include <libvirt/libvirt.h> +#include <pthread.h> #define VIRT_DBUS_CONNECT_INTERFACE "org.libvirt.Connect" struct _virtDBusConnect { + pthread_mutex_t lock; + DBusConnection *bus; const char *uri; const char *connectPath; diff --git a/src/main.c b/src/main.c index bef5dcc..1808620 100644 --- a/src/main.c +++ b/src/main.c @@ -8,6 +8,7 @@ #include <errno.h> #include <getopt.h> #include <poll.h> +#include <pthread.h> #include <signal.h> #include <stdbool.h> #include <stdio.h> @@ -16,21 +17,98 @@ #include <sys/signalfd.h> #include <unistd.h> +#define VIRT_DBUS_THREADS 4 + static int loop_status = 0; +static pthread_mutex_t loopStatusLock = PTHREAD_MUTEX_INITIALIZER; + +static int +virtDBusLoopStatusGet(void) +{ + int ret; + pthread_mutex_lock(&loopStatusLock); + ret = loop_status; + pthread_mutex_unlock(&loopStatusLock); + return ret; +} + +static void +virtDBusLoopStatusSet(int val) +{ + pthread_mutex_lock(&loopStatusLock); + loop_status = val; + pthread_mutex_unlock(&loopStatusLock); +} + +struct _virtDBusDispatchData { + DBusConnection *bus; + virtDBusObjectList *objectList; +}; + +static pthread_cond_t threadLoopCond; +static pthread_mutex_t threadLoopLock; static int virtDBusProcessEvents(DBusConnection *bus, virtDBusObjectList *objectList) { for (;;) { - int r; + int r; - r = virtDBusDispatchMessage(bus, objectList); - if (r < 0) - return r; + r = virtDBusDispatchMessage(bus, objectList); + if (r < 0) + return r; - if (r == 0) - break; + if (r == 0) + break; + } + + return 0; +} + +static void * +virtDBusDispatchThread(void *opaque) +{ + struct _virtDBusDispatchData *data = opaque; + + while(true) { + if (pthread_cond_wait(&threadLoopCond, &threadLoopLock) != 0) { + virtDBusLoopStatusSet(errno); + return NULL; + } + if (virtDBusLoopStatusGet() != 0) + return NULL; + + if (virtDBusProcessEvents(data->bus, data->objectList) < 0) { + virtDBusLoopStatusSet(-ENOMEM); + return NULL; + } + } + + return NULL; +} + +static void +virtDBusDispatch(void) +{ + pthread_cond_broadcast(&threadLoopCond); +} + +static int +virtDBusStartThreads(struct _virtDBusDispatchData *data, + int threads) +{ + if (pthread_cond_init(&threadLoopCond, NULL) != 0) + return -1; + + if (virtDBusUtilMutexInit(&threadLoopLock) != 0) + return -1; + + for (int i = 0; i < threads; i++) { + pthread_t thread; + + if (pthread_create(&thread, NULL, virtDBusDispatchThread, data) != 0) + return -1; } return 0; @@ -49,7 +127,7 @@ virtDBusHandleSignal(int watch VIRT_ATTR_UNUSED, int events VIRT_ATTR_UNUSED, void *opaque VIRT_ATTR_UNUSED) { - loop_status = -ECANCELED; + virtDBusLoopStatusSet(-ECANCELED); } struct virtDBusDriver { @@ -91,6 +169,7 @@ main(int argc, char *argv[]) { "help", no_argument, NULL, 'h' }, { "system", no_argument, NULL, ARG_SYSTEM }, { "session", no_argument, NULL, ARG_SESSION }, + { "threads", required_argument, NULL, 't' }, {} }; @@ -106,6 +185,7 @@ main(int argc, char *argv[]) sigset_t mask; int c; int r; + int threads = VIRT_DBUS_THREADS; if (geteuid() == 0) { busType = DBUS_BUS_SYSTEM; @@ -113,7 +193,7 @@ main(int argc, char *argv[]) busType = DBUS_BUS_SESSION; } - while ((c = getopt_long(argc, argv, "hc:", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "ht:", options, NULL)) >= 0) { switch (c) { case 'h': printf("Usage: %s [OPTIONS]\n", program_invocation_short_name); @@ -123,8 +203,16 @@ main(int argc, char *argv[]) printf(" -h, --help Display this help text and exit\n"); printf(" --session Connect to the session bus\n"); printf(" --system Connect to the system bus\n"); + printf(" -t, --threads Configure count of worker threads\n"); return 0; + case 't': + if (virtDBusUtilStrToInt(optarg, 10, &threads) < 0) { + fprintf(stderr, "Failed to parse --threads.\n"); + return EXIT_FAILURE; + } + break; + case ARG_SYSTEM: busType = DBUS_BUS_SYSTEM; break; @@ -179,11 +267,13 @@ main(int argc, char *argv[]) return EXIT_FAILURE; } - r = virtDBusProcessEvents(bus, &objectList); - if (r < 0) - return EXIT_FAILURE; + struct _virtDBusDispatchData data = { bus, &objectList }; + + virtDBusStartThreads(&data, threads); + + virtDBusDispatch(); - while (loop_status >= 0) { + while ((r = virtDBusLoopStatusGet()) >= 0) { virEventRunDefaultImpl(); r = virtDBusProcessEvents(bus, &objectList); @@ -191,8 +281,8 @@ main(int argc, char *argv[]) return EXIT_FAILURE; } - if (loop_status < 0 && loop_status != -ECANCELED) { - fprintf(stderr, "Error: %s\n", strerror(-loop_status)); + if (r < 0 && r != -ECANCELED) { + fprintf(stderr, "Error: %s\n", strerror(-r)); return EXIT_FAILURE; } diff --git a/src/util.c b/src/util.c index 6f8b7be..fe9e023 100644 --- a/src/util.c +++ b/src/util.c @@ -2,6 +2,7 @@ #include "util.h" +#include <errno.h> #include <fcntl.h> #include <libvirt/virterror.h> #include <stdio.h> @@ -90,6 +91,33 @@ virtDBusUtilSetLastVirtError(virtDBusMessage *msg) virError->message); } +int +virtDBusUtilMutexInit(pthread_mutex_t *mutex) +{ + _cleanup_(pthread_mutexattr_destroy) pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); + return pthread_mutex_init(mutex, &attr); +} + +int +virtDBusUtilStrToInt(char const *string, + int base, + int *result) +{ + long int val; + char *ptr; + + errno = 0; + val = strtol(string, &ptr, base); + if (errno != 0 || *ptr != 0 || ptr == string || (int) val != val) + return -1; + + *result = val; + return 0; +} + char * virtDBusUtilReadFile(const char *filename) { diff --git a/src/util.h b/src/util.h index 16c54df..afb118c 100644 --- a/src/util.h +++ b/src/util.h @@ -3,6 +3,7 @@ #include "dbus.h" #include <libvirt/libvirt.h> +#include <pthread.h> #define VIRT_DBUS_ERROR_INTERFACE "org.libvirt.Error" @@ -26,6 +27,14 @@ virtDBusUtilMessageAppendTypedParameters(virtDBusMessage *msg, int virtDBusUtilSetLastVirtError(virtDBusMessage *msg); +int +virtDBusUtilMutexInit(pthread_mutex_t *mutex); + +int +virtDBusUtilStrToInt(char const *string, + int base, + int *result); + char * virtDBusUtilReadFile(const char *filename); -- 2.14.3
participants (2)
-
Daniel P. Berrangé
-
Pavel Hrdina