2012-04-19 14:34:35 +00:00
|
|
|
/*
|
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2012-04-19 14:34:35 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "virdbus.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2012-12-13 15:49:48 +00:00
|
|
|
#include "virthread.h"
|
2012-04-19 14:34:35 +00:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_DBUS
|
|
|
|
|
2012-09-20 14:05:39 +00:00
|
|
|
#ifdef WITH_DBUS
|
2012-04-19 14:34:35 +00:00
|
|
|
|
|
|
|
static DBusConnection *systembus = NULL;
|
2012-10-31 19:03:49 +00:00
|
|
|
static DBusConnection *sessionbus = NULL;
|
|
|
|
static virOnceControl systemonce = VIR_ONCE_CONTROL_INITIALIZER;
|
|
|
|
static virOnceControl sessiononce = VIR_ONCE_CONTROL_INITIALIZER;
|
|
|
|
static DBusError systemdbuserr;
|
|
|
|
static DBusError sessiondbuserr;
|
2012-04-19 14:34:35 +00:00
|
|
|
|
|
|
|
static dbus_bool_t virDBusAddWatch(DBusWatch *watch, void *data);
|
|
|
|
static void virDBusRemoveWatch(DBusWatch *watch, void *data);
|
|
|
|
static void virDBusToggleWatch(DBusWatch *watch, void *data);
|
|
|
|
|
2012-10-31 19:03:49 +00:00
|
|
|
static DBusConnection *virDBusBusInit(DBusBusType type, DBusError *dbuserr)
|
2012-04-19 14:34:35 +00:00
|
|
|
{
|
2012-10-31 19:03:49 +00:00
|
|
|
DBusConnection *bus;
|
|
|
|
|
2012-04-19 14:34:35 +00:00
|
|
|
/* Allocate and initialize a new HAL context */
|
|
|
|
dbus_connection_set_change_sigpipe(FALSE);
|
|
|
|
dbus_threads_init_default();
|
|
|
|
|
2012-10-31 19:03:49 +00:00
|
|
|
dbus_error_init(dbuserr);
|
|
|
|
if (!(bus = dbus_bus_get(type, dbuserr)))
|
|
|
|
return NULL;
|
2012-04-19 14:34:35 +00:00
|
|
|
|
2012-10-31 19:03:49 +00:00
|
|
|
dbus_connection_set_exit_on_disconnect(bus, FALSE);
|
2012-04-19 14:34:35 +00:00
|
|
|
|
|
|
|
/* Register dbus watch callbacks */
|
2012-10-31 19:03:49 +00:00
|
|
|
if (!dbus_connection_set_watch_functions(bus,
|
2012-04-19 14:34:35 +00:00
|
|
|
virDBusAddWatch,
|
|
|
|
virDBusRemoveWatch,
|
|
|
|
virDBusToggleWatch,
|
2012-10-31 19:03:49 +00:00
|
|
|
bus, NULL)) {
|
|
|
|
return NULL;
|
2012-04-19 14:34:35 +00:00
|
|
|
}
|
2012-10-31 19:03:49 +00:00
|
|
|
return bus;
|
2012-04-19 14:34:35 +00:00
|
|
|
}
|
|
|
|
|
2012-10-31 19:03:49 +00:00
|
|
|
static void virDBusSystemBusInit(void)
|
|
|
|
{
|
|
|
|
systembus = virDBusBusInit(DBUS_BUS_SYSTEM, &systemdbuserr);
|
|
|
|
}
|
2012-04-19 14:34:35 +00:00
|
|
|
|
|
|
|
DBusConnection *virDBusGetSystemBus(void)
|
|
|
|
{
|
2012-10-31 19:03:49 +00:00
|
|
|
if (virOnce(&systemonce, virDBusSystemBusInit) < 0) {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unable to run one time DBus initializer"));
|
2012-04-19 14:34:35 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!systembus) {
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to get DBus system bus connection: %s"),
|
2012-10-31 19:03:49 +00:00
|
|
|
systemdbuserr.message ? systemdbuserr.message : "watch setup failed");
|
2012-04-19 14:34:35 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return systembus;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-31 19:03:49 +00:00
|
|
|
static void virDBusSessionBusInit(void)
|
|
|
|
{
|
|
|
|
sessionbus = virDBusBusInit(DBUS_BUS_SESSION, &sessiondbuserr);
|
|
|
|
}
|
|
|
|
|
|
|
|
DBusConnection *virDBusGetSessionBus(void)
|
|
|
|
{
|
|
|
|
if (virOnce(&sessiononce, virDBusSessionBusInit) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unable to run one time DBus initializer"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sessionbus) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unable to get DBus session bus connection: %s"),
|
|
|
|
sessiondbuserr.message ? sessiondbuserr.message : "watch setup failed");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sessionbus;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct virDBusWatch
|
|
|
|
{
|
|
|
|
int watch;
|
|
|
|
DBusConnection *bus;
|
|
|
|
};
|
|
|
|
|
2012-04-19 14:34:35 +00:00
|
|
|
static void virDBusWatchCallback(int fdatch ATTRIBUTE_UNUSED,
|
|
|
|
int fd ATTRIBUTE_UNUSED,
|
|
|
|
int events, void *opaque)
|
|
|
|
{
|
|
|
|
DBusWatch *watch = opaque;
|
2012-10-31 19:03:49 +00:00
|
|
|
struct virDBusWatch *info;
|
2012-04-19 14:34:35 +00:00
|
|
|
int dbus_flags = 0;
|
|
|
|
|
2012-10-31 19:03:49 +00:00
|
|
|
info = dbus_watch_get_data(watch);
|
|
|
|
|
2012-04-19 14:34:35 +00:00
|
|
|
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);
|
|
|
|
|
2012-10-31 19:03:49 +00:00
|
|
|
while (dbus_connection_dispatch(info->bus) == DBUS_DISPATCH_DATA_REMAINS)
|
2012-04-19 14:34:35 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void virDBusWatchFree(void *data) {
|
|
|
|
struct virDBusWatch *info = data;
|
|
|
|
VIR_FREE(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
static dbus_bool_t virDBusAddWatch(DBusWatch *watch,
|
2012-10-31 19:03:49 +00:00
|
|
|
void *data)
|
2012-04-19 14:34:35 +00:00
|
|
|
{
|
|
|
|
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
|
2012-10-31 19:03:49 +00:00
|
|
|
info->bus = (DBusConnection *)data;
|
2012-04-19 14:34:35 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2012-09-20 14:05:39 +00:00
|
|
|
#else /* ! WITH_DBUS */
|
2012-04-19 14:34:35 +00:00
|
|
|
DBusConnection *virDBusGetSystemBus(void)
|
|
|
|
{
|
2012-07-18 10:26:24 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("DBus support not compiled into this binary"));
|
2012-04-19 14:34:35 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-10-31 19:03:49 +00:00
|
|
|
DBusConnection *virDBusGetSessionBus(void)
|
|
|
|
{
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("DBus support not compiled into this binary"));
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-09-20 14:05:39 +00:00
|
|
|
#endif /* ! WITH_DBUS */
|