From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> The policy kit and HAL node device drivers both require a DBus connection. The HAL device code further requires that the DBus connection is integrated with the event loop and provides such glue logic itself. The forthcoming FirewallD integration also requires a dbus connection with event loop integration. Thus we need to pull the current event loop glue out of the HAL driver. Thus we create src/util/virdbus.{c,h} files. This contains just one method virDBusGetSystemBus() which obtains a handle to the single shared system bus instance, with event glue automagically setup. --- .gitignore | 6 +- configure.ac | 37 ++++++- daemon/Makefile.am | 3 +- daemon/libvirtd.c | 4 - daemon/remote.c | 8 +- include/libvirt/virterror.h | 1 + src/Makefile.am | 13 +-- src/libvirt_dbus.syms | 2 - src/node_device/node_device_hal.c | 143 ++------------------------ src/rpc/virnetserver.c | 40 -------- src/rpc/virnetserver.h | 8 -- src/util/virdbus.c | 201 +++++++++++++++++++++++++++++++++++++ src/util/virdbus.h | 34 ++++++ src/util/virterror.c | 3 + 14 files changed, 296 insertions(+), 207 deletions(-) delete mode 100644 src/libvirt_dbus.syms create mode 100644 src/util/virdbus.c create mode 100644 src/util/virdbus.h diff --git a/.gitignore b/.gitignore index 5aa9c9b..14a21d0 100644 --- a/.gitignore +++ b/.gitignore @@ -48,12 +48,12 @@ /daemon/*_dispatch.h /daemon/libvirt_qemud /daemon/libvirtd -/daemon/libvirtd.init -/daemon/libvirtd.service /daemon/libvirtd*.logrotate /daemon/libvirtd.8 /daemon/libvirtd.8.in +/daemon/libvirtd.init /daemon/libvirtd.pod +/daemon/libvirtd.service /docs/devhelp/libvirt.devhelp /docs/hvsupport.html.in /docs/libvirt-api.xml @@ -118,6 +118,7 @@ /tests/eventtest /tests/hashtest /tests/jsontest +/tests/libvirtdconftest /tests/networkxml2argvtest /tests/nodeinfotest /tests/nwfilterxml2xmltest @@ -150,7 +151,6 @@ /tests/vmx2xmltest /tests/xencapstest /tests/xmconfigtest -/tests/libvirtdconftest /tools/*.[18] /tools/libvirt-guests.init /tools/virsh diff --git a/configure.ac b/configure.ac index 3f5b3ff..f49b620 100644 --- a/configure.ac +++ b/configure.ac @@ -74,6 +74,7 @@ LIBPCAP_REQUIRED="1.0.0" LIBNL_REQUIRED="1.1" LIBSSH2_REQUIRED="1.0" LIBBLKID_REQUIRED="2.17" +DBUS_REQUIRED="1.0.0" dnl Checks for C compiler. AC_PROG_CC @@ -1099,6 +1100,36 @@ AC_SUBST([SANLOCK_CFLAGS]) AC_SUBST([SANLOCK_LIBS]) +dnl DBus library +DBUS_CFLAGS= +DBUS_LIBS= +AC_ARG_WITH([dbus], + AC_HELP_STRING([--with-dbus], [enable communication with DBus @<:@default=check@:>@]), + [], + [with_dbus=check]) +if test "$with_dbus" = "yes" || test "$with_dbus" = "check" ; then + PKG_CHECK_MODULES(DBUS, dbus-1 >= $DBUS_REQUIRED, + [with_dbus=yes], [ + if test "$with_dbus" = "check" ; then + with_dbus=no + else + AC_MSG_ERROR([You must install DBus >= $DBUS_REQUIRED to compile libvirt]) + fi]) +fi + +if test "$with_dbus" = "yes" ; then + AC_DEFINE_UNQUOTED([HAVE_DBUS], 1, [enable communication with DBus]) + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$LIBS $DBUS_LIBS" + CFLAGS="$CFLAGS $DBUS_CFLAGS" + AC_CHECK_FUNCS([dbus_watch_get_unix_fd]) + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + + dnl PolicyKit library POLKIT_CFLAGS= POLKIT_LIBS= @@ -1109,7 +1140,6 @@ AC_ARG_WITH([polkit], [with_polkit=check]) with_polkit0=no -with_dbus=no with_polkit1=no if test "x$with_polkit" = "xyes" || test "x$with_polkit" = "xcheck"; then dnl Check for new polkit first - just a binary @@ -1138,8 +1168,6 @@ if test "x$with_polkit" = "xyes" || test "x$with_polkit" = "xcheck"; then [use PolicyKit for UNIX socket access checks]) AC_DEFINE_UNQUOTED([HAVE_POLKIT0], 1, [use PolicyKit for UNIX socket access checks]) - AC_DEFINE_UNQUOTED([HAVE_DBUS], 1, - [use DBus for PolicyKit]) old_CFLAGS=$CFLAGS old_LIBS=$LIBS @@ -1154,13 +1182,11 @@ if test "x$with_polkit" = "xyes" || test "x$with_polkit" = "xcheck"; then AC_DEFINE_UNQUOTED([POLKIT_AUTH],["$POLKIT_AUTH"],[Location of polkit-auth program]) fi with_polkit0="yes" - with_dbus="yes" fi fi fi AM_CONDITIONAL([HAVE_POLKIT], [test "x$with_polkit" = "xyes"]) AM_CONDITIONAL([HAVE_POLKIT0], [test "x$with_polkit0" = "xyes"]) -AM_CONDITIONAL([HAVE_DBUS], [test "x$with_dbus" = "xyes"]) AM_CONDITIONAL([HAVE_POLKIT1], [test "x$with_polkit1" = "xyes"]) AC_SUBST([POLKIT_CFLAGS]) AC_SUBST([POLKIT_LIBS]) @@ -2413,7 +2439,6 @@ if test "x$with_hal" = "xyes" || test "x$with_hal" = "xcheck"; then CFLAGS="$CFLAGS $HAL_CFLAGS" LIBS="$LIBS $HAL_LIBS" AC_CHECK_FUNCS([libhal_get_all_devices],,[with_hal=no]) - AC_CHECK_FUNCS([dbus_watch_get_unix_fd]) CFLAGS="$old_CFLAGS" LIBS="$old_LIBS" fi diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 5d9f5d7..24cce8f 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -94,7 +94,7 @@ libvirtd_SOURCES = $(DAEMON_SOURCES) #-D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_POSIX_C_SOURCE=199506L libvirtd_CFLAGS = \ $(LIBXML_CFLAGS) $(GNUTLS_CFLAGS) $(SASL_CFLAGS) \ - $(XDR_CFLAGS) $(POLKIT_CFLAGS) \ + $(XDR_CFLAGS) $(POLKIT_CFLAGS) $(DBUS_CFLAGS) \ $(WARN_CFLAGS) \ $(COVERAGE_CFLAGS) \ -DQEMUD_PID_FILE="\"$(QEMUD_PID_FILE)\"" \ @@ -108,6 +108,7 @@ libvirtd_LDADD = \ $(LIBXML_LIBS) \ $(GNUTLS_LIBS) \ $(SASL_LIBS) \ + $(DBUS_LIBS) \ $(POLKIT_LIBS) if WITH_DTRACE_PROBES diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index ce931d4..b098f6a 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -812,7 +812,6 @@ int main(int argc, char **argv) { struct daemonConfig *config; bool privileged = geteuid() == 0 ? true : false; bool implicit_conf = false; - bool use_polkit_dbus; char *run_dir = NULL; mode_t old_umask; @@ -1008,8 +1007,6 @@ int main(int argc, char **argv) { goto cleanup; } - use_polkit_dbus = config->auth_unix_rw == REMOTE_AUTH_POLKIT || - config->auth_unix_ro == REMOTE_AUTH_POLKIT; if (!(srv = virNetServerNew(config->min_workers, config->max_workers, config->prio_workers, @@ -1018,7 +1015,6 @@ int main(int argc, char **argv) { config->keepalive_count, !!config->keepalive_required, config->mdns_adv ? config->mdns_name : NULL, - use_polkit_dbus, remoteClientInitHook))) { ret = VIR_DAEMON_ERR_INIT; goto cleanup; diff --git a/daemon/remote.c b/daemon/remote.c index b71ffa2..16a8a05 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -45,7 +45,7 @@ #include "virnetserver.h" #include "virfile.h" #include "virtypedparam.h" - +#include "virdbus.h" #include "remote_protocol.h" #include "qemu_protocol.h" @@ -2672,6 +2672,7 @@ remoteDispatchAuthPolkit(virNetServerPtr server, char *ident = NULL; struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + DBusConnection *sysbus; virMutexLock(&priv->lock); @@ -2697,10 +2698,13 @@ remoteDispatchAuthPolkit(virNetServerPtr server, goto authfail; } + if (!(sysbus = virDBusGetSystemBus())) + goto authfail; + VIR_INFO("Checking PID %lld running as %d", (long long) callerPid, callerUid); dbus_error_init(&err); - if (!(pkcaller = polkit_caller_new_from_pid(virNetServerGetDBusConn(server), + if (!(pkcaller = polkit_caller_new_from_pid(sysbus, callerPid, &err))) { VIR_ERROR(_("Failed to lookup policy kit caller: %s"), err.message); dbus_error_free(&err); diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index e04d29e..cda15ff 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -87,6 +87,7 @@ typedef enum { VIR_FROM_CAPABILITIES = 44, /* Error from capabilities */ VIR_FROM_URI = 45, /* Error from URI handling */ VIR_FROM_AUTH = 46, /* Error from auth handling */ + VIR_FROM_DBUS = 47, /* Error from DBus */ } virErrorDomain; diff --git a/src/Makefile.am b/src/Makefile.am index a2aae9d..b8a19b4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -88,6 +88,7 @@ UTIL_SOURCES = \ util/virtypedparam.c util/virtypedparam.h \ util/xml.c util/xml.h \ util/virterror.c util/virterror_internal.h \ + util/virdbus.c util/virdbus.h \ util/virhash.c util/virhash.h \ util/virhashcode.c util/virhashcode.h \ util/virkeycode.c util/virkeycode.h \ @@ -574,10 +575,11 @@ libvirt_la_BUILT_LIBADD = libvirt_util.la libvirt_util_la_SOURCES = \ $(UTIL_SOURCES) libvirt_util_la_CFLAGS = $(CAPNG_CFLAGS) $(YAJL_CFLAGS) $(LIBNL_CFLAGS) \ - $(AM_CFLAGS) $(AUDIT_CFLAGS) $(DEVMAPPER_CFLAGS) + $(AM_CFLAGS) $(AUDIT_CFLAGS) $(DEVMAPPER_CFLAGS) \ + $(DBUS_CFLAGS) libvirt_util_la_LIBADD = $(CAPNG_LIBS) $(YAJL_LIBS) $(LIBNL_LIBS) \ $(THREAD_LIBS) $(AUDIT_LIBS) $(DEVMAPPER_LIBS) \ - $(RT_LIBS) + $(RT_LIBS) $(DBUS_LIBS) noinst_LTLIBRARIES += libvirt_conf.la @@ -1198,10 +1200,6 @@ if WITH_LINUX USED_SYM_FILES += libvirt_linux.syms endif -if HAVE_DBUS -USED_SYM_FILES += libvirt_dbus.syms -endif - if WITH_LIBVIRTD USED_SYM_FILES += libvirt_daemon.syms endif @@ -1525,7 +1523,7 @@ libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(AM_LDFLAGS) libvirt_lxc_LDADD = $(CAPNG_LIBS) $(YAJL_LIBS) \ $(LIBXML_LIBS) $(NUMACTL_LIBS) $(THREAD_LIBS) \ $(LIBNL_LIBS) $(AUDIT_LIBS) $(DEVMAPPER_LIBS) \ - $(RT_LIBS) \ + $(RT_LIBS) $(DBUS_LIBS) \ ../gnulib/lib/libgnu.la if WITH_DTRACE_PROBES libvirt_lxc_LDADD += probes.o @@ -1542,6 +1540,7 @@ libvirt_lxc_CFLAGS = \ $(CAPNG_CFLAGS) \ $(YAJL_CFLAGS) \ $(AUDIT_CFLAGS) \ + $(DBUS_CFLAGS) \ -I$(top_srcdir)/src/conf \ $(AM_CFLAGS) if HAVE_LIBBLKID diff --git a/src/libvirt_dbus.syms b/src/libvirt_dbus.syms deleted file mode 100644 index a460ec5..0000000 --- a/src/libvirt_dbus.syms +++ /dev/null @@ -1,2 +0,0 @@ -# virnetserver.h -virNetServerGetDBusConn; diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index a028886..dd14271 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -39,6 +39,7 @@ #include "logging.h" #include "node_device_driver.h" #include "ignore-value.h" +#include "virdbus.h" #define VIR_FROM_THIS VIR_FROM_NODEDEV @@ -586,124 +587,15 @@ static void device_prop_modified(LibHalContext *ctx ATTRIBUTE_UNUSED, } -static void dbus_watch_callback(int fdatch ATTRIBUTE_UNUSED, - int fd ATTRIBUTE_UNUSED, - int events, void *opaque) -{ - DBusWatch *watch = opaque; - LibHalContext *hal_ctx; - DBusConnection *dbus_conn; - int dbus_flags = 0; - - if (events & VIR_EVENT_HANDLE_READABLE) - dbus_flags |= DBUS_WATCH_READABLE; - if (events & VIR_EVENT_HANDLE_WRITABLE) - dbus_flags |= DBUS_WATCH_WRITABLE; - if (events & VIR_EVENT_HANDLE_ERROR) - dbus_flags |= DBUS_WATCH_ERROR; - if (events & VIR_EVENT_HANDLE_HANGUP) - dbus_flags |= DBUS_WATCH_HANGUP; - - (void)dbus_watch_handle(watch, dbus_flags); - - nodeDeviceLock(driverState); - hal_ctx = DRV_STATE_HAL_CTX(driverState); - dbus_conn = libhal_ctx_get_dbus_connection(hal_ctx); - nodeDeviceUnlock(driverState); - while (dbus_connection_dispatch(dbus_conn) == DBUS_DISPATCH_DATA_REMAINS) - /* keep dispatching while data remains */; -} - - -static int xlate_dbus_watch_flags(int dbus_flags) -{ - unsigned int flags = 0; - if (dbus_flags & DBUS_WATCH_READABLE) - flags |= VIR_EVENT_HANDLE_READABLE; - if (dbus_flags & DBUS_WATCH_WRITABLE) - flags |= VIR_EVENT_HANDLE_WRITABLE; - if (dbus_flags & DBUS_WATCH_ERROR) - flags |= VIR_EVENT_HANDLE_ERROR; - if (dbus_flags & DBUS_WATCH_HANGUP) - flags |= VIR_EVENT_HANDLE_HANGUP; - return flags; -} - - -struct nodeDeviceWatchInfo -{ - int watch; -}; - -static void nodeDeviceWatchFree(void *data) { - struct nodeDeviceWatchInfo *info = data; - VIR_FREE(info); -} - -static dbus_bool_t add_dbus_watch(DBusWatch *watch, - void *data ATTRIBUTE_UNUSED) -{ - int flags = 0; - int fd; - struct nodeDeviceWatchInfo *info; - - if (VIR_ALLOC(info) < 0) - return 0; - - if (dbus_watch_get_enabled(watch)) - flags = xlate_dbus_watch_flags(dbus_watch_get_flags(watch)); - -#if HAVE_DBUS_WATCH_GET_UNIX_FD - fd = dbus_watch_get_unix_fd(watch); -#else - fd = dbus_watch_get_fd(watch); -#endif - info->watch = virEventAddHandle(fd, flags, dbus_watch_callback, - watch, NULL); - if (info->watch < 0) { - VIR_FREE(info); - return 0; - } - dbus_watch_set_data(watch, info, nodeDeviceWatchFree); - - return 1; -} - - -static void remove_dbus_watch(DBusWatch *watch, - void *data ATTRIBUTE_UNUSED) -{ - struct nodeDeviceWatchInfo *info; - - info = dbus_watch_get_data(watch); - - (void)virEventRemoveHandle(info->watch); -} - - -static void toggle_dbus_watch(DBusWatch *watch, - void *data ATTRIBUTE_UNUSED) -{ - int flags = 0; - struct nodeDeviceWatchInfo *info; - - if (dbus_watch_get_enabled(watch)) - flags = xlate_dbus_watch_flags(dbus_watch_get_flags(watch)); - - info = dbus_watch_get_data(watch); - - (void)virEventUpdateHandle(info->watch, flags); -} static int halDeviceMonitorStartup(int privileged ATTRIBUTE_UNUSED) { LibHalContext *hal_ctx = NULL; - DBusConnection *dbus_conn = NULL; - DBusError err; char **udi = NULL; int num_devs, i; int ret = -1; + DBusConnection *sysbus; /* Ensure caps_tbl is sorted by capability name */ qsort(caps_tbl, ARRAY_CARDINALITY(caps_tbl), sizeof(caps_tbl[0]), @@ -718,26 +610,19 @@ static int halDeviceMonitorStartup(int privileged ATTRIBUTE_UNUSED) } nodeDeviceLock(driverState); - /* Allocate and initialize a new HAL context */ - dbus_connection_set_change_sigpipe(FALSE); - dbus_threads_init_default(); + if (!(sysbus == virDBusGetSystemBus())) { + virErrorPtr err = virGetLastError(); + VIR_ERROR(_("DBus not available, disabling HAL driver: %s", + err->message)); + ret = 0; + goto failure; + } - dbus_error_init(&err); hal_ctx = libhal_ctx_new(); if (hal_ctx == NULL) { VIR_ERROR(_("libhal_ctx_new returned NULL")); goto failure; } - dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); - if (dbus_conn == NULL) { - VIR_ERROR(_("dbus_bus_get failed")); - /* We don't want to show a fatal error here, - otherwise entire libvirtd shuts down when - D-Bus isn't running */ - ret = 0; - goto failure; - } - dbus_connection_set_exit_on_disconnect(dbus_conn, FALSE); if (!libhal_ctx_set_dbus_connection(hal_ctx, dbus_conn)) { VIR_ERROR(_("libhal_ctx_set_dbus_connection failed")); @@ -752,16 +637,6 @@ static int halDeviceMonitorStartup(int privileged ATTRIBUTE_UNUSED) goto failure; } - /* Register dbus watch callbacks */ - if (!dbus_connection_set_watch_functions(dbus_conn, - add_dbus_watch, - remove_dbus_watch, - toggle_dbus_watch, - NULL, NULL)) { - VIR_ERROR(_("dbus_connection_set_watch_functions failed")); - goto failure; - } - /* Populate with known devices */ driverState->privateData = hal_ctx; diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index f761e6b..3965fc2 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -39,9 +39,6 @@ #if HAVE_AVAHI # include "virnetservermdns.h" #endif -#if HAVE_DBUS -# include <dbus/dbus.h> -#endif #define VIR_FROM_THIS VIR_FROM_RPC #define virNetError(code, ...) \ @@ -88,10 +85,6 @@ struct _virNetServer { virNetServerMDNSGroupPtr mdnsGroup; #endif -#if HAVE_DBUS - DBusConnection *sysbus; -#endif - size_t nservices; virNetServerServicePtr *services; @@ -311,7 +304,6 @@ virNetServerPtr virNetServerNew(size_t min_workers, unsigned int keepaliveCount, bool keepaliveRequired, const char *mdnsGroupName, - bool connectDBus ATTRIBUTE_UNUSED, virNetServerClientInitHook clientInitHook) { virNetServerPtr srv; @@ -353,25 +345,6 @@ virNetServerPtr virNetServerNew(size_t min_workers, } #endif -#if HAVE_DBUS - if (connectDBus) { - DBusError derr; - - dbus_connection_set_change_sigpipe(FALSE); - dbus_threads_init_default(); - - dbus_error_init(&derr); - srv->sysbus = dbus_bus_get(DBUS_BUS_SYSTEM, &derr); - if (!(srv->sysbus)) { - VIR_ERROR(_("Failed to connect to system bus for PolicyKit auth: %s"), - derr.message); - dbus_error_free(&derr); - goto error; - } - dbus_connection_set_exit_on_disconnect(srv->sysbus, FALSE); - } -#endif - if (virMutexInit(&srv->lock) < 0) { virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot initialize mutex")); @@ -429,14 +402,6 @@ bool virNetServerIsPrivileged(virNetServerPtr srv) } -#if HAVE_DBUS -DBusConnection* virNetServerGetDBusConn(virNetServerPtr srv) -{ - return srv->sysbus; -} -#endif - - void virNetServerAutoShutdown(virNetServerPtr srv, unsigned int timeout, virNetServerAutoShutdownFunc func, @@ -828,11 +793,6 @@ void virNetServerFree(virNetServerPtr srv) virNetServerMDNSFree(srv->mdns); #endif -#if HAVE_DBUS - if (srv->sysbus) - dbus_connection_unref(srv->sysbus); -#endif - virNetServerUnlock(srv); virMutexDestroy(&srv->lock); VIR_FREE(srv); diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h index a04ffdd..0ebe00e 100644 --- a/src/rpc/virnetserver.h +++ b/src/rpc/virnetserver.h @@ -25,9 +25,6 @@ # define __VIR_NET_SERVER_H__ # include <signal.h> -# if HAVE_DBUS -# include <dbus/dbus.h> -# endif # include "virnettlscontext.h" # include "virnetserverprogram.h" @@ -45,7 +42,6 @@ virNetServerPtr virNetServerNew(size_t min_workers, unsigned int keepaliveCount, bool keepaliveRequired, const char *mdnsGroupName, - bool connectDBus, virNetServerClientInitHook clientInitHook); typedef int (*virNetServerAutoShutdownFunc)(virNetServerPtr srv, void *opaque); @@ -54,10 +50,6 @@ void virNetServerRef(virNetServerPtr srv); bool virNetServerIsPrivileged(virNetServerPtr srv); -# if HAVE_DBUS -DBusConnection* virNetServerGetDBusConn(virNetServerPtr srv); -# endif - void virNetServerAutoShutdown(virNetServerPtr srv, unsigned int timeout, virNetServerAutoShutdownFunc func, diff --git a/src/util/virdbus.c b/src/util/virdbus.c new file mode 100644 index 0000000..badfe8c --- /dev/null +++ b/src/util/virdbus.c @@ -0,0 +1,201 @@ +/* + * virdbus.c: helper for using DBus + * + * Copyright (C) 2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> + +#include "virdbus.h" +#include "memory.h" +#include "virterror_internal.h" +#include "logging.h" +#include "threads.h" + +#define VIR_FROM_THIS VIR_FROM_DBUS + +#define virDBusReportError(code, ...) \ + virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +#ifdef HAVE_DBUS + +static DBusConnection *systembus = NULL; +static virOnceControl once = VIR_ONCE_CONTROL_INITIALIZER; +static DBusError dbuserr; + +static dbus_bool_t virDBusAddWatch(DBusWatch *watch, void *data); +static void virDBusRemoveWatch(DBusWatch *watch, void *data); +static void virDBusToggleWatch(DBusWatch *watch, void *data); + +static void virDBusSystemBusInit(void) +{ + /* Allocate and initialize a new HAL context */ + dbus_connection_set_change_sigpipe(FALSE); + dbus_threads_init_default(); + + dbus_error_init(&dbuserr); + if (!(systembus = dbus_bus_get(DBUS_BUS_SYSTEM, &dbuserr))) + return; + + dbus_connection_set_exit_on_disconnect(systembus, FALSE); + + /* Register dbus watch callbacks */ + if (!dbus_connection_set_watch_functions(systembus, + virDBusAddWatch, + virDBusRemoveWatch, + virDBusToggleWatch, + NULL, NULL)) { + systembus = NULL; + return; + } +} + + +DBusConnection *virDBusGetSystemBus(void) +{ + if (virOnce(&once, virDBusSystemBusInit) < 0) { + virDBusReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to run one time DBus initializer")); + return NULL; + } + + if (!systembus) { + virDBusReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to get DBus system bus connection: %s"), + dbuserr.message ? dbuserr.message : "watch setup failed"); + return NULL; + } + + return systembus; +} + + +static void virDBusWatchCallback(int fdatch ATTRIBUTE_UNUSED, + int fd ATTRIBUTE_UNUSED, + int events, void *opaque) +{ + DBusWatch *watch = opaque; + int dbus_flags = 0; + + if (events & VIR_EVENT_HANDLE_READABLE) + dbus_flags |= DBUS_WATCH_READABLE; + if (events & VIR_EVENT_HANDLE_WRITABLE) + dbus_flags |= DBUS_WATCH_WRITABLE; + if (events & VIR_EVENT_HANDLE_ERROR) + dbus_flags |= DBUS_WATCH_ERROR; + if (events & VIR_EVENT_HANDLE_HANGUP) + dbus_flags |= DBUS_WATCH_HANGUP; + + (void)dbus_watch_handle(watch, dbus_flags); + + while (dbus_connection_dispatch(systembus) == DBUS_DISPATCH_DATA_REMAINS) + /* keep dispatching while data remains */; +} + + +static int virDBusTranslateWatchFlags(int dbus_flags) +{ + unsigned int flags = 0; + if (dbus_flags & DBUS_WATCH_READABLE) + flags |= VIR_EVENT_HANDLE_READABLE; + if (dbus_flags & DBUS_WATCH_WRITABLE) + flags |= VIR_EVENT_HANDLE_WRITABLE; + if (dbus_flags & DBUS_WATCH_ERROR) + flags |= VIR_EVENT_HANDLE_ERROR; + if (dbus_flags & DBUS_WATCH_HANGUP) + flags |= VIR_EVENT_HANDLE_HANGUP; + return flags; +} + + +struct virDBusWatch +{ + int watch; +}; + +static void virDBusWatchFree(void *data) { + struct virDBusWatch *info = data; + VIR_FREE(info); +} + +static dbus_bool_t virDBusAddWatch(DBusWatch *watch, + void *data ATTRIBUTE_UNUSED) +{ + int flags = 0; + int fd; + struct virDBusWatch *info; + + if (VIR_ALLOC(info) < 0) + return 0; + + if (dbus_watch_get_enabled(watch)) + flags = virDBusTranslateWatchFlags(dbus_watch_get_flags(watch)); + +# if HAVE_DBUS_WATCH_GET_UNIX_FD + fd = dbus_watch_get_unix_fd(watch); +# else + fd = dbus_watch_get_fd(watch); +# endif + info->watch = virEventAddHandle(fd, flags, + virDBusWatchCallback, + watch, NULL); + if (info->watch < 0) { + VIR_FREE(info); + return 0; + } + dbus_watch_set_data(watch, info, virDBusWatchFree); + + return 1; +} + + +static void virDBusRemoveWatch(DBusWatch *watch, + void *data ATTRIBUTE_UNUSED) +{ + struct virDBusWatch *info; + + info = dbus_watch_get_data(watch); + + (void)virEventRemoveHandle(info->watch); +} + + +static void virDBusToggleWatch(DBusWatch *watch, + void *data ATTRIBUTE_UNUSED) +{ + int flags = 0; + struct virDBusWatch *info; + + if (dbus_watch_get_enabled(watch)) + flags = virDBusTranslateWatchFlags(dbus_watch_get_flags(watch)); + + info = dbus_watch_get_data(watch); + + (void)virEventUpdateHandle(info->watch, flags); +} + +#else /* ! HAVE_DBUS */ +DBusConnection *virDBusGetSystemBus(void) +{ + virDBusReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("DBus support not compiled into this binary")); + return NULL; +} + +#endif /* ! HAVE_DBUS */ diff --git a/src/util/virdbus.h b/src/util/virdbus.h new file mode 100644 index 0000000..7d9ec8f --- /dev/null +++ b/src/util/virdbus.h @@ -0,0 +1,34 @@ +/* + * virdbus.h: helper for using DBus + * + * Copyright (C) 2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __VIR_DBUS_H__ +# define __VIR_DBUS_H__ + +# ifdef HAVE_DBUS +# include <dbus/dbus.h> +# else +# define DBusConnection void +# endif +# include "internal.h" + +DBusConnection *virDBusGetSystemBus(void); + +#endif /* __VIR_DBUS_H__ */ diff --git a/src/util/virterror.c b/src/util/virterror.c index ff9a36f..de45bb0 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -184,6 +184,9 @@ static const char *virErrorDomainName(virErrorDomain domain) { case VIR_FROM_AUTH: dom = "Auth "; break; + case VIR_FROM_DBUS: + dom = "DBus "; + break; } return dom; } -- 1.7.7.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list