mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-26 10:31:16 +00:00
Node device driver for HAL and DeviceKit (David Lively)
This commit is contained in:
parent
149322c530
commit
620d4be7ae
17
ChangeLog
17
ChangeLog
@ -1,3 +1,20 @@
|
|||||||
|
Fri Nov 21 12:23:14 BST 2008 Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
|
||||||
|
Primary internal driver for node devices with HAL (default)
|
||||||
|
and DeviceKit (optional, unfinished) (David Lively)
|
||||||
|
* configure.in: Probe for HAL & DeviceKit libraries
|
||||||
|
* po/POTFILES.in: Add new source files
|
||||||
|
* qemud/Makefile.am: Link to node device driver
|
||||||
|
* qemud/qemud.c: Load node device driver implementation
|
||||||
|
* src/Makefile.am: Buid node device drivers
|
||||||
|
* src/libvirt_sym.version.in: Export internal symbols needed
|
||||||
|
by node device driver
|
||||||
|
* src/node_device.c, src/node_device.h: Common driver
|
||||||
|
routines
|
||||||
|
* src/node_device_hal.c: HAL specific device routines
|
||||||
|
* src/node_device_devkit.c: DeviceKit specific routines
|
||||||
|
* src/node_device_conf.h: Add dbusWatch handle field
|
||||||
|
|
||||||
Fri Nov 21 12:20:14 BST 2008 Daniel P. Berrange <berrange@redhat.com>
|
Fri Nov 21 12:20:14 BST 2008 Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
|
||||||
* src/Makefile.am, src/node_device_conf.c, src/node_device_conf.h:
|
* src/Makefile.am, src/node_device_conf.c, src/node_device_conf.h:
|
||||||
|
112
configure.in
112
configure.in
@ -1105,6 +1105,108 @@ test "$enable_shared" = no && lt_cv_objdir=.
|
|||||||
LV_LIBTOOL_OBJDIR=${lt_cv_objdir-.}
|
LV_LIBTOOL_OBJDIR=${lt_cv_objdir-.}
|
||||||
AC_SUBST([LV_LIBTOOL_OBJDIR])
|
AC_SUBST([LV_LIBTOOL_OBJDIR])
|
||||||
|
|
||||||
|
dnl HAL or DeviceKit library for host device enumeration
|
||||||
|
HAL_REQUIRED=0.0
|
||||||
|
HAL_CFLAGS=
|
||||||
|
HAL_LIBS=
|
||||||
|
AC_ARG_WITH([hal],
|
||||||
|
[ --with-hal use HAL for host device enumeration],
|
||||||
|
[],
|
||||||
|
[with_hal=check])
|
||||||
|
|
||||||
|
if test "$with_libvirtd" = "no" ; then
|
||||||
|
with_hal=no
|
||||||
|
fi
|
||||||
|
if test "x$with_hal" = "xyes" -o "x$with_hal" = "xcheck"; then
|
||||||
|
PKG_CHECK_MODULES(HAL, hal >= $HAL_REQUIRED,
|
||||||
|
[with_hal=yes], [
|
||||||
|
if test "x$with_hal" = "xcheck" ; then
|
||||||
|
with_hal=no
|
||||||
|
else
|
||||||
|
AC_MSG_ERROR(
|
||||||
|
[You must install hal-devel >= $HAL_REQUIRED to compile libvirt])
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
if test "x$with_hal" = "xyes" ; then
|
||||||
|
AC_DEFINE_UNQUOTED([HAVE_HAL], 1,
|
||||||
|
[use HAL for host device enumeration])
|
||||||
|
|
||||||
|
old_CFLAGS=$CFLAGS
|
||||||
|
old_LDFLAGS=$LDFLAGS
|
||||||
|
CFLAGS="$CFLAGS $HAL_CFLAGS"
|
||||||
|
LDFLAGS="$LDFLAGS $HAL_LIBS"
|
||||||
|
AC_CHECK_FUNCS([libhal_get_all_devices],,[with_hal=no])
|
||||||
|
CFLAGS="$old_CFLAGS"
|
||||||
|
LDFLAGS="$old_LDFLAGS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL([HAVE_HAL], [test "x$with_hal" = "xyes"])
|
||||||
|
AC_SUBST([HAL_CFLAGS])
|
||||||
|
AC_SUBST([HAL_LIBS])
|
||||||
|
|
||||||
|
DEVKIT_REQUIRED=0.0
|
||||||
|
DEVKIT_CFLAGS=
|
||||||
|
DEVKIT_LIBS=
|
||||||
|
AC_ARG_WITH([devkit],
|
||||||
|
[ --with-devkit use DeviceKit for host device enumeration],
|
||||||
|
[],
|
||||||
|
[with_devkit=no])
|
||||||
|
|
||||||
|
if test "$with_libvirtd" = "no" ; then
|
||||||
|
with_devkit=no
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl Extra check needed while devkit pkg-config info missing glib2 dependency
|
||||||
|
PKG_CHECK_MODULES(GLIB2, glib-2.0 >= 0.0,,[
|
||||||
|
if test "x$with_devkit" = "xcheck"; then
|
||||||
|
with_devkit=no
|
||||||
|
elif test "x$with_devkit" = "xyes"; then
|
||||||
|
AC_MSG_ERROR([required package DeviceKit requires package glib-2.0])
|
||||||
|
fi])
|
||||||
|
|
||||||
|
if test "x$with_devkit" = "xyes" -o "x$with_devkit" = "xcheck"; then
|
||||||
|
PKG_CHECK_MODULES(DEVKIT, devkit-gobject >= $DEVKIT_REQUIRED,
|
||||||
|
[with_devkit=yes], [
|
||||||
|
if test "x$with_devkit" = "xcheck" ; then
|
||||||
|
with_devkit=no
|
||||||
|
else
|
||||||
|
AC_MSG_ERROR(
|
||||||
|
[You must install DeviceKit-devel >= $DEVKIT_REQUIRED to compile libvirt])
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
if test "x$with_devkit" = "xyes" ; then
|
||||||
|
AC_DEFINE_UNQUOTED([HAVE_DEVKIT], 1,
|
||||||
|
[use DeviceKit for host device enumeration])
|
||||||
|
|
||||||
|
dnl Add glib2 flags explicitly while devkit pkg-config info missing glib2 dependency
|
||||||
|
DEVKIT_CFLAGS="$GLIB2_CFLAGS $DEVKIT_CFLAGS"
|
||||||
|
DEVKIT_LIBS="$GLIB2_LIBS $DEVKIT_LIBS"
|
||||||
|
|
||||||
|
dnl Add more flags apparently required for devkit to work properly
|
||||||
|
DEVKIT_CFLAGS="$DEVKIT_CFLAGS -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT"
|
||||||
|
|
||||||
|
old_CFLAGS=$CFLAGS
|
||||||
|
old_LDFLAGS=$LDFLAGS
|
||||||
|
CFLAGS="$CFLAGS $DEVKIT_CFLAGS"
|
||||||
|
LDFLAGS="$LDFLAGS $DEVKIT_LIBS"
|
||||||
|
AC_CHECK_FUNCS([devkit_client_connect],,[with_devkit=no])
|
||||||
|
CFLAGS="$old_CFLAGS"
|
||||||
|
LDFLAGS="$old_LDFLAGS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL([HAVE_DEVKIT], [test "x$with_devkit" = "xyes"])
|
||||||
|
AC_SUBST([DEVKIT_CFLAGS])
|
||||||
|
AC_SUBST([DEVKIT_LIBS])
|
||||||
|
|
||||||
|
with_nodedev=no;
|
||||||
|
if test "$with_devkit" = "yes" -o "$with_hal" = "yes";
|
||||||
|
then
|
||||||
|
with_nodedev=yes
|
||||||
|
AC_DEFINE_UNQUOTED([WITH_NODE_DEVICES], 1, [with node device driver])
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL([WITH_NODE_DEVICES], [test "$with_nodedev" = "yes"])
|
||||||
|
|
||||||
|
|
||||||
# very annoying
|
# very annoying
|
||||||
rm -f COPYING
|
rm -f COPYING
|
||||||
cp COPYING.LIB COPYING
|
cp COPYING.LIB COPYING
|
||||||
@ -1196,6 +1298,16 @@ AC_MSG_NOTICE([ xen: $XEN_CFLAGS $XEN_LIBS])
|
|||||||
else
|
else
|
||||||
AC_MSG_NOTICE([ xen: no])
|
AC_MSG_NOTICE([ xen: no])
|
||||||
fi
|
fi
|
||||||
|
if test "$with_hal" = "yes" ; then
|
||||||
|
AC_MSG_NOTICE([ hal: $HAL_CFLAGS $HAL_LIBS])
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE([ hal: no])
|
||||||
|
fi
|
||||||
|
if test "$with_devkit" = "yes" ; then
|
||||||
|
AC_MSG_NOTICE([ devkit: $DEVKIT_CFLAGS $DEVKIT_LIBS])
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE([ devkit: no])
|
||||||
|
fi
|
||||||
AC_MSG_NOTICE([])
|
AC_MSG_NOTICE([])
|
||||||
AC_MSG_NOTICE([Test suite])
|
AC_MSG_NOTICE([Test suite])
|
||||||
AC_MSG_NOTICE([])
|
AC_MSG_NOTICE([])
|
||||||
|
@ -13,6 +13,7 @@ src/lxc_controller.c
|
|||||||
src/lxc_driver.c
|
src/lxc_driver.c
|
||||||
src/network_conf.c
|
src/network_conf.c
|
||||||
src/network_driver.c
|
src/network_driver.c
|
||||||
|
src/node_device.c
|
||||||
src/openvz_conf.c
|
src/openvz_conf.c
|
||||||
src/openvz_driver.c
|
src/openvz_driver.c
|
||||||
src/proxy_internal.c
|
src/proxy_internal.c
|
||||||
|
@ -111,6 +111,10 @@ endif
|
|||||||
if WITH_NETWORK
|
if WITH_NETWORK
|
||||||
libvirtd_LDADD += ../src/libvirt_driver_network.la
|
libvirtd_LDADD += ../src/libvirt_driver_network.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if WITH_NODE_DEVICES
|
||||||
|
libvirtd_LDADD += ../src/libvirt_driver_nodedev.la
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
libvirtd_LDADD += ../src/libvirt.la
|
libvirtd_LDADD += ../src/libvirt.la
|
||||||
|
@ -79,6 +79,9 @@
|
|||||||
#ifdef WITH_STORAGE_DIR
|
#ifdef WITH_STORAGE_DIR
|
||||||
#include "storage_driver.h"
|
#include "storage_driver.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef WITH_NODE_DEVICES
|
||||||
|
#include "node_device.h"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -763,6 +766,7 @@ static struct qemud_server *qemudInitialize(int sigread) {
|
|||||||
virDriverLoadModule("uml");
|
virDriverLoadModule("uml");
|
||||||
virDriverLoadModule("network");
|
virDriverLoadModule("network");
|
||||||
virDriverLoadModule("storage");
|
virDriverLoadModule("storage");
|
||||||
|
virDriverLoadModule("nodedev");
|
||||||
#else
|
#else
|
||||||
#ifdef WITH_QEMU
|
#ifdef WITH_QEMU
|
||||||
qemuRegister();
|
qemuRegister();
|
||||||
@ -779,6 +783,9 @@ static struct qemud_server *qemudInitialize(int sigread) {
|
|||||||
#ifdef WITH_STORAGE_DIR
|
#ifdef WITH_STORAGE_DIR
|
||||||
storageRegister();
|
storageRegister();
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(HAVE_HAL) || defined(HAVE_DEVKIT)
|
||||||
|
nodedevRegister();
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
virEventRegisterImpl(virEventAddHandleImpl,
|
virEventRegisterImpl(virEventAddHandleImpl,
|
||||||
|
@ -157,6 +157,14 @@ STORAGE_HELPER_DISK_SOURCES = \
|
|||||||
parthelper.c
|
parthelper.c
|
||||||
|
|
||||||
|
|
||||||
|
NODE_DEVICE_DRIVER_SOURCES = \
|
||||||
|
node_device.c node_device.h
|
||||||
|
|
||||||
|
NODE_DEVICE_DRIVER_HAL_SOURCES = \
|
||||||
|
node_device_hal.c
|
||||||
|
NODE_DEVICE_DRIVER_DEVKIT_SOURCES = \
|
||||||
|
node_device_devkit.c
|
||||||
|
|
||||||
|
|
||||||
#########################
|
#########################
|
||||||
#
|
#
|
||||||
@ -330,6 +338,36 @@ if WITH_STORAGE_DISK
|
|||||||
libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_DISK_SOURCES)
|
libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_DISK_SOURCES)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if WITH_NODE_DEVICES
|
||||||
|
# Needed to keep automake quiet about conditionals
|
||||||
|
if WITH_DRIVER_MODULES
|
||||||
|
mod_LTLIBRARIES += libvirt_driver_nodedev.la
|
||||||
|
else
|
||||||
|
noinst_LTLIBRARIES += libvirt_driver_nodedev.la
|
||||||
|
# Stateful, so linked to daemon instead
|
||||||
|
#libvirt_la_LIBADD += libvirt_driver_nodedev.la
|
||||||
|
endif
|
||||||
|
libvirt_driver_nodedev_la_SOURCES = $(NODE_DEVICE_DRIVER_SOURCES)
|
||||||
|
|
||||||
|
libvirt_driver_nodedev_la_CFLAGS =
|
||||||
|
libvirt_driver_nodedev_la_LDFLAGS =
|
||||||
|
if HAVE_HAL
|
||||||
|
libvirt_driver_nodedev_la_SOURCES += $(NODE_DEVICE_DRIVER_HAL_SOURCES)
|
||||||
|
libvirt_driver_nodedev_la_CFLAGS += $(HAL_CFLAGS)
|
||||||
|
libvirt_driver_nodedev_la_LDFLAGS += $(HAL_LIBS)
|
||||||
|
endif
|
||||||
|
if HAVE_DEVKIT
|
||||||
|
libvirt_driver_nodedev_la_SOURCES += $(NODE_DEVICE_DRIVER_DEVKIT_SOURCES)
|
||||||
|
libvirt_driver_nodedev_la_CFLAGS += $(DEVKIT_CFLAGS)
|
||||||
|
libvirt_driver_nodedev_la_LDFLAGS += $(DEVKIT_LIBS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if WITH_DRIVER_MODULES
|
||||||
|
libvirt_driver_nodedev_la_LDFLAGS += -module -avoid-version
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
# Add all conditional sources just in case...
|
# Add all conditional sources just in case...
|
||||||
EXTRA_DIST += \
|
EXTRA_DIST += \
|
||||||
$(TEST_DRIVER_SOURCES) \
|
$(TEST_DRIVER_SOURCES) \
|
||||||
@ -344,7 +382,10 @@ EXTRA_DIST += \
|
|||||||
$(STORAGE_DRIVER_FS_SOURCES) \
|
$(STORAGE_DRIVER_FS_SOURCES) \
|
||||||
$(STORAGE_DRIVER_LVM_SOURCES) \
|
$(STORAGE_DRIVER_LVM_SOURCES) \
|
||||||
$(STORAGE_DRIVER_ISCSI_SOURCES) \
|
$(STORAGE_DRIVER_ISCSI_SOURCES) \
|
||||||
$(STORAGE_DRIVER_DISK_SOURCES)
|
$(STORAGE_DRIVER_DISK_SOURCES) \
|
||||||
|
$(NODE_DEVICE_DRIVER_SOURCES) \
|
||||||
|
$(NODE_DEVICE_DRIVER_HAL_SOURCES) \
|
||||||
|
$(NODE_DEVICE_DRIVER_DEVKIT_SOURCES)
|
||||||
|
|
||||||
|
|
||||||
# Empty source list - it merely links a bunch of convenience libs together
|
# Empty source list - it merely links a bunch of convenience libs together
|
||||||
|
@ -327,6 +327,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
|
|||||||
virGetNetwork;
|
virGetNetwork;
|
||||||
virGetStoragePool;
|
virGetStoragePool;
|
||||||
virGetStorageVol;
|
virGetStorageVol;
|
||||||
|
virGetNodeDevice;
|
||||||
virUnrefDomain;
|
virUnrefDomain;
|
||||||
|
|
||||||
|
|
||||||
@ -451,6 +452,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
|
|||||||
virRegisterNetworkDriver;
|
virRegisterNetworkDriver;
|
||||||
virRegisterStateDriver;
|
virRegisterStateDriver;
|
||||||
virRegisterStorageDriver;
|
virRegisterStorageDriver;
|
||||||
|
virRegisterDeviceMonitor;
|
||||||
|
|
||||||
|
|
||||||
/* memory.h */
|
/* memory.h */
|
||||||
@ -481,6 +483,16 @@ LIBVIRT_PRIVATE_@VERSION@ {
|
|||||||
virNodeInfoPopulate;
|
virNodeInfoPopulate;
|
||||||
|
|
||||||
|
|
||||||
|
/* node_device_conf.h */
|
||||||
|
virNodeDeviceObjRemove;
|
||||||
|
virNodeDevCapTypeToString;
|
||||||
|
virNodeDeviceFindByName;
|
||||||
|
virNodeDeviceObjListFree;
|
||||||
|
virNodeDeviceDefFree;
|
||||||
|
virNodeDevCapsDefFree;
|
||||||
|
virNodeDeviceDefFormat;
|
||||||
|
|
||||||
|
|
||||||
/* qparams.h */
|
/* qparams.h */
|
||||||
qparam_get_query;
|
qparam_get_query;
|
||||||
qparam_query_parse;
|
qparam_query_parse;
|
||||||
@ -539,6 +551,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
|
|||||||
virStrToLong_i;
|
virStrToLong_i;
|
||||||
virStrToLong_ll;
|
virStrToLong_ll;
|
||||||
virStrToLong_ull;
|
virStrToLong_ull;
|
||||||
|
virStrToLong_ui;
|
||||||
virFileLinkPointsTo;
|
virFileLinkPointsTo;
|
||||||
saferead;
|
saferead;
|
||||||
safewrite;
|
safewrite;
|
||||||
@ -558,6 +571,7 @@ LIBVIRT_PRIVATE_@VERSION@ {
|
|||||||
virFileOpenTty;
|
virFileOpenTty;
|
||||||
virFileReadLimFD;
|
virFileReadLimFD;
|
||||||
virFileReadPid;
|
virFileReadPid;
|
||||||
|
virFileLinkPointsTo;
|
||||||
virParseNumber;
|
virParseNumber;
|
||||||
virRun;
|
virRun;
|
||||||
virSkipSpaces;
|
virSkipSpaces;
|
||||||
|
213
src/node_device.c
Normal file
213
src/node_device.c
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
* node_device.c: node device enumeration
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Virtual Iron Software, Inc.
|
||||||
|
* Copyright (C) 2008 David F. Lively
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* Author: David F. Lively <dlively@virtualiron.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "virterror_internal.h"
|
||||||
|
#include "datatypes.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
#include "node_device_conf.h"
|
||||||
|
#include "node_device.h"
|
||||||
|
|
||||||
|
static int dev_has_cap(const virNodeDeviceObjPtr dev, const char *cap)
|
||||||
|
{
|
||||||
|
virNodeDevCapsDefPtr caps = dev->def->caps;
|
||||||
|
while (caps) {
|
||||||
|
if (STREQ(cap, virNodeDevCapTypeToString(caps->type)))
|
||||||
|
return 1;
|
||||||
|
caps = caps->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int nodeNumOfDevices(virConnectPtr conn,
|
||||||
|
const char *cap,
|
||||||
|
unsigned int flags ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
virDeviceMonitorStatePtr driver = conn->devMonPrivateData;
|
||||||
|
int ndevs = 0;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < driver->devs.count; i++)
|
||||||
|
if ((cap == NULL) ||
|
||||||
|
dev_has_cap(driver->devs.objs[i], cap))
|
||||||
|
++ndevs;
|
||||||
|
|
||||||
|
return ndevs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nodeListDevices(virConnectPtr conn,
|
||||||
|
const char *cap,
|
||||||
|
char **const names, int maxnames,
|
||||||
|
unsigned int flags ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
virDeviceMonitorStatePtr driver = conn->devMonPrivateData;
|
||||||
|
int ndevs = 0;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < driver->devs.count && ndevs < maxnames; i++)
|
||||||
|
if (cap == NULL ||
|
||||||
|
dev_has_cap(driver->devs.objs[i], cap))
|
||||||
|
if ((names[ndevs++] = strdup(driver->devs.objs[i]->def->name)) == NULL)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
return ndevs;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
--ndevs;
|
||||||
|
while (--ndevs >= 0)
|
||||||
|
VIR_FREE(names[ndevs]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static virNodeDevicePtr nodeDeviceLookupByName(virConnectPtr conn,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
virDeviceMonitorStatePtr driver = conn->devMonPrivateData;
|
||||||
|
virNodeDeviceObjPtr obj = virNodeDeviceFindByName(&driver->devs, name);
|
||||||
|
|
||||||
|
if (!obj) {
|
||||||
|
virNodeDeviceReportError(conn, VIR_ERR_INVALID_NODE_DEVICE,
|
||||||
|
"%s", _("no node device with matching name"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return virGetNodeDevice(conn, name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *nodeDeviceDumpXML(virNodeDevicePtr dev,
|
||||||
|
unsigned int flags ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData;
|
||||||
|
virNodeDeviceObjPtr obj = virNodeDeviceFindByName(&driver->devs, dev->name);
|
||||||
|
|
||||||
|
if (!obj) {
|
||||||
|
virNodeDeviceReportError(dev->conn, VIR_ERR_INVALID_NODE_DEVICE,
|
||||||
|
"%s", _("no node device with matching name"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return virNodeDeviceDefFormat(dev->conn, obj->def);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *nodeDeviceGetParent(virNodeDevicePtr dev)
|
||||||
|
{
|
||||||
|
virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData;
|
||||||
|
virNodeDeviceObjPtr obj = virNodeDeviceFindByName(&driver->devs, dev->name);
|
||||||
|
|
||||||
|
if (!obj) {
|
||||||
|
virNodeDeviceReportError(dev->conn, VIR_ERR_INVALID_NODE_DEVICE,
|
||||||
|
"%s", _("no node device with matching name"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj->def->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int nodeDeviceNumOfCaps(virNodeDevicePtr dev)
|
||||||
|
{
|
||||||
|
virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData;
|
||||||
|
virNodeDeviceObjPtr obj = virNodeDeviceFindByName(&driver->devs, dev->name);
|
||||||
|
virNodeDevCapsDefPtr caps;
|
||||||
|
int ncaps = 0;
|
||||||
|
|
||||||
|
if (!obj) {
|
||||||
|
virNodeDeviceReportError(dev->conn, VIR_ERR_INVALID_NODE_DEVICE,
|
||||||
|
"%s", _("no node device with matching name"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (caps = obj->def->caps; caps; caps = caps->next)
|
||||||
|
++ncaps;
|
||||||
|
|
||||||
|
return ncaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
nodeDeviceListCaps(virNodeDevicePtr dev, char **const names, int maxnames)
|
||||||
|
{
|
||||||
|
virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData;
|
||||||
|
virNodeDeviceObjPtr obj = virNodeDeviceFindByName(&driver->devs, dev->name);
|
||||||
|
virNodeDevCapsDefPtr caps;
|
||||||
|
int ncaps = 0;
|
||||||
|
|
||||||
|
if (!obj) {
|
||||||
|
virNodeDeviceReportError(dev->conn, VIR_ERR_INVALID_NODE_DEVICE,
|
||||||
|
"%s", _("no node device with matching name"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (caps = obj->def->caps; caps && ncaps < maxnames; caps = caps->next) {
|
||||||
|
names[ncaps] = strdup(virNodeDevCapTypeToString(caps->type));
|
||||||
|
if (names[ncaps++] == NULL)
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ncaps;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
--ncaps;
|
||||||
|
while (--ncaps >= 0)
|
||||||
|
VIR_FREE(names[ncaps]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void registerCommonNodeFuncs(virDeviceMonitorPtr driver)
|
||||||
|
{
|
||||||
|
driver->numOfDevices = nodeNumOfDevices;
|
||||||
|
driver->listDevices = nodeListDevices;
|
||||||
|
driver->deviceLookupByName = nodeDeviceLookupByName;
|
||||||
|
driver->deviceDumpXML = nodeDeviceDumpXML;
|
||||||
|
driver->deviceGetParent = nodeDeviceGetParent;
|
||||||
|
driver->deviceNumOfCaps = nodeDeviceNumOfCaps;
|
||||||
|
driver->deviceListCaps = nodeDeviceListCaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int nodedevRegister(void) {
|
||||||
|
#if defined(HAVE_HAL) && defined(HAVE_DEVKIT)
|
||||||
|
/* Register only one of these two - they conflict */
|
||||||
|
if (halNodeRegister() == -1)
|
||||||
|
return devkitNodeRegister();
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
#ifdef HAVE_HAL
|
||||||
|
return halNodeRegister();
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_DEVKIT
|
||||||
|
return devkitNodeRegister();
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
41
src/node_device.h
Normal file
41
src/node_device.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* node_device.h: node device enumeration
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Virtual Iron Software, Inc.
|
||||||
|
* Copyright (C) 2008 David F. Lively
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* Author: David F. Lively <dlively@virtualiron.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VIR_NODE_DEVICE_H__
|
||||||
|
#define __VIR_NODE_DEVICE_H__
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
#include "driver.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_HAL
|
||||||
|
int halNodeRegister(void);
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_DEVKIT
|
||||||
|
int devkitNodeRegister(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void registerCommonNodeFuncs(virDeviceMonitorPtr mon);
|
||||||
|
|
||||||
|
int nodedevRegister(void);
|
||||||
|
|
||||||
|
#endif /* __VIR_NODE_DEVICE_H__ */
|
@ -161,6 +161,7 @@ struct _virNodeDeviceObjList {
|
|||||||
typedef struct _virDeviceMonitorState virDeviceMonitorState;
|
typedef struct _virDeviceMonitorState virDeviceMonitorState;
|
||||||
typedef virDeviceMonitorState *virDeviceMonitorStatePtr;
|
typedef virDeviceMonitorState *virDeviceMonitorStatePtr;
|
||||||
struct _virDeviceMonitorState {
|
struct _virDeviceMonitorState {
|
||||||
|
int dbusWatch;
|
||||||
virNodeDeviceObjList devs; /* currently-known devices */
|
virNodeDeviceObjList devs; /* currently-known devices */
|
||||||
void *privateData; /* driver-specific private data */
|
void *privateData; /* driver-specific private data */
|
||||||
};
|
};
|
||||||
|
429
src/node_device_devkit.c
Normal file
429
src/node_device_devkit.c
Normal file
@ -0,0 +1,429 @@
|
|||||||
|
/*
|
||||||
|
* node_device_devkit.c: node device enumeration - DeviceKit-based implementation
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Virtual Iron Software, Inc.
|
||||||
|
* Copyright (C) 2008 David F. Lively
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* Author: David F. Lively <dlively@virtualiron.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <devkit-gobject.h>
|
||||||
|
|
||||||
|
#include "node_device_conf.h"
|
||||||
|
#include "virterror_internal.h"
|
||||||
|
#include "driver.h"
|
||||||
|
#include "datatypes.h"
|
||||||
|
#include "event.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "uuid.h"
|
||||||
|
|
||||||
|
#include "node_device.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Host device enumeration (DeviceKit implementation)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static virDeviceMonitorStatePtr driverState;
|
||||||
|
|
||||||
|
#define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__)
|
||||||
|
#define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg)
|
||||||
|
|
||||||
|
#define CONN_DRV_STATE(conn) \
|
||||||
|
((virDeviceMonitorStatePtr)((conn)->devMonPrivateData))
|
||||||
|
#define DRV_STATE_DKCLIENT(ds) ((DevkitClient *)((ds)->privateData))
|
||||||
|
#define CONN_DKCLIENT(conn) DRV_STATE_DKCLIENT(CONN_DRV_STATE(conn))
|
||||||
|
|
||||||
|
#define NODE_DEV_DKDEV(obj) ((DevkitDevice *)((obj)->privateData)
|
||||||
|
|
||||||
|
static int get_str_prop(DevkitDevice *dkdev, const char *prop, char **val_p)
|
||||||
|
{
|
||||||
|
char *val = devkit_device_dup_property_as_str(dkdev, prop);
|
||||||
|
|
||||||
|
if (val) {
|
||||||
|
if (*val) {
|
||||||
|
*val_p = val;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
/* Treat empty strings as NULL values */
|
||||||
|
VIR_FREE(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static int get_int_prop(DevkitDevice *dkdev, const char *prop, int *val_p)
|
||||||
|
{
|
||||||
|
if (! devkit_device_has_property(dkdev, prop))
|
||||||
|
return -1;
|
||||||
|
*val_p = devkit_device_get_property_as_int(dkdev, prop);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_uint64_prop(DevkitDevice *dkdev, const char *prop,
|
||||||
|
unsigned long long *val_p)
|
||||||
|
{
|
||||||
|
if (! devkit_device_has_property(dkdev, prop))
|
||||||
|
return -1;
|
||||||
|
*val_p = devkit_device_get_property_as_uint64(dkdev, prop);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int gather_pci_cap(DevkitDevice *dkdev,
|
||||||
|
union _virNodeDevCapData *d)
|
||||||
|
{
|
||||||
|
const char *sysfs_path = devkit_device_get_native_path(dkdev);
|
||||||
|
|
||||||
|
if (sysfs_path != NULL) {
|
||||||
|
char *p = strrchr(sysfs_path, '/');
|
||||||
|
if (p) {
|
||||||
|
(void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.domain);
|
||||||
|
(void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.bus);
|
||||||
|
(void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.slot);
|
||||||
|
(void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_usb_cap(DevkitDevice *dkdev,
|
||||||
|
union _virNodeDevCapData *d)
|
||||||
|
{
|
||||||
|
(void)get_str_prop(dkdev, "ID_VENDOR", &d->usb_dev.vendor_name);
|
||||||
|
(void)get_str_prop(dkdev, "ID_MODEL", &d->usb_dev.product_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_net_cap(DevkitDevice *dkdev,
|
||||||
|
union _virNodeDevCapData *d)
|
||||||
|
{
|
||||||
|
const char *sysfs_path = devkit_device_get_native_path(dkdev);
|
||||||
|
const char *interface;
|
||||||
|
|
||||||
|
if (sysfs_path == NULL)
|
||||||
|
return -1;
|
||||||
|
interface = strrchr(sysfs_path, '/');
|
||||||
|
if (!interface || !*interface || !*(++interface))
|
||||||
|
return -1;
|
||||||
|
if ((d->net.interface = strdup(interface)) == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
d->net.subtype = VIR_NODE_DEV_CAP_NET_LAST;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_block_cap(DevkitDevice *dkdev,
|
||||||
|
union _virNodeDevCapData *d)
|
||||||
|
{
|
||||||
|
const char *device = devkit_device_get_device_file(dkdev);
|
||||||
|
|
||||||
|
if (device && ((d->block.device = strdup(device)) == NULL))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct _caps_tbl_entry {
|
||||||
|
const char *cap_name;
|
||||||
|
enum virNodeDevCapType type;
|
||||||
|
int (*gather_fn)(DevkitDevice *dkdev,
|
||||||
|
union _virNodeDevCapData *data);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _caps_tbl_entry caps_tbl_entry;
|
||||||
|
|
||||||
|
static caps_tbl_entry caps_tbl[] = {
|
||||||
|
{ "pci", VIR_NODE_DEV_CAP_PCI_DEV, gather_pci_cap },
|
||||||
|
{ "usb", VIR_NODE_DEV_CAP_USB_DEV, gather_usb_cap },
|
||||||
|
{ "net", VIR_NODE_DEV_CAP_NET, gather_net_cap },
|
||||||
|
{ "block", VIR_NODE_DEV_CAP_BLOCK, gather_block_cap },
|
||||||
|
// TODO: more caps!
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* qsort/bsearch string comparator */
|
||||||
|
static int cmpstringp(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
/* from man 3 qsort */
|
||||||
|
return strcmp(* (char * const *) p1, * (char * const *) p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_capability(DevkitDevice *dkdev,
|
||||||
|
const char *cap_name,
|
||||||
|
virNodeDevCapsDefPtr *caps_p)
|
||||||
|
{
|
||||||
|
size_t caps_tbl_len = sizeof(caps_tbl) / sizeof(caps_tbl[0]);
|
||||||
|
caps_tbl_entry *entry;
|
||||||
|
|
||||||
|
entry = bsearch(&cap_name, caps_tbl, caps_tbl_len,
|
||||||
|
sizeof(caps_tbl[0]), cmpstringp);
|
||||||
|
|
||||||
|
if (entry) {
|
||||||
|
virNodeDevCapsDefPtr caps;
|
||||||
|
if (VIR_ALLOC(caps) < 0)
|
||||||
|
return ENOMEM;
|
||||||
|
caps->type = entry->type;
|
||||||
|
if (entry->gather_fn) {
|
||||||
|
int rv = (*entry->gather_fn)(dkdev, &caps->data);
|
||||||
|
if (rv != 0) {
|
||||||
|
virNodeDevCapsDefFree(caps);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
caps->next = *caps_p;
|
||||||
|
*caps_p = caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_capabilities(DevkitDevice *dkdev,
|
||||||
|
virNodeDevCapsDefPtr *caps_p)
|
||||||
|
{
|
||||||
|
const char *subsys = devkit_device_get_subsystem(dkdev);
|
||||||
|
const char *bus_name = devkit_device_get_property(dkdev, "ID_BUS");
|
||||||
|
virNodeDevCapsDefPtr caps = NULL;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (subsys) {
|
||||||
|
rv = gather_capability(dkdev, subsys, &caps);
|
||||||
|
if (rv != 0) goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bus_name && (subsys == NULL || !STREQ(bus_name, subsys))) {
|
||||||
|
rv = gather_capability(dkdev, bus_name, &caps);
|
||||||
|
if (rv != 0) goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
*caps_p = caps;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
while (caps) {
|
||||||
|
virNodeDevCapsDefPtr next = caps->next;
|
||||||
|
virNodeDevCapsDefFree(caps);
|
||||||
|
caps = next;
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_create(void *_dkdev, void *_dkclient ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
DevkitDevice *dkdev = _dkdev;
|
||||||
|
const char *sysfs_path = devkit_device_get_native_path(dkdev);
|
||||||
|
virNodeDeviceObjPtr dev = NULL;
|
||||||
|
const char *name;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (sysfs_path == NULL)
|
||||||
|
/* Currently using basename(sysfs_path) as device name (key) */
|
||||||
|
return;
|
||||||
|
|
||||||
|
name = strrchr(sysfs_path, '/');
|
||||||
|
if (name == NULL)
|
||||||
|
name = sysfs_path;
|
||||||
|
else
|
||||||
|
++name;
|
||||||
|
|
||||||
|
if (VIR_ALLOC(dev) < 0 || VIR_ALLOC(dev->def) < 0)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
dev->privateData = dkdev;
|
||||||
|
|
||||||
|
if ((dev->def->name = strdup(name)) == NULL)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
// TODO: Find device parent, if any
|
||||||
|
|
||||||
|
rv = gather_capabilities(dkdev, &dev->def->caps);
|
||||||
|
if (rv != 0) goto failure;
|
||||||
|
|
||||||
|
if (VIR_REALLOC_N(driverState->devs.objs, driverState->devs.count + 1) < 0)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
driverState->devs.objs[driverState->devs.count++] = dev;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
DEBUG("FAILED TO ADD dev %s", name);
|
||||||
|
if (dev)
|
||||||
|
virNodeDeviceDefFree(dev->def);
|
||||||
|
VIR_FREE(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int devkitDeviceMonitorStartup(void)
|
||||||
|
{
|
||||||
|
size_t caps_tbl_len = sizeof(caps_tbl) / sizeof(caps_tbl[0]);
|
||||||
|
DevkitClient *devkit_client = NULL;
|
||||||
|
GError *err = NULL;
|
||||||
|
GList *devs;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Ensure caps_tbl is sorted by capability name */
|
||||||
|
qsort(caps_tbl, caps_tbl_len, sizeof(caps_tbl[0]), cmpstringp);
|
||||||
|
|
||||||
|
if (VIR_ALLOC(driverState) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// TODO: Is it really ok to call this multiple times??
|
||||||
|
// Is there something analogous to call on close?
|
||||||
|
g_type_init();
|
||||||
|
|
||||||
|
/* Get new devkit_client and connect to daemon */
|
||||||
|
devkit_client = devkit_client_new(NULL);
|
||||||
|
if (devkit_client == NULL) {
|
||||||
|
DEBUG0("devkit_client_new returned NULL");
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
if (!devkit_client_connect(devkit_client, &err)) {
|
||||||
|
DEBUG0("devkit_client_connect failed");
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Populate with known devices.
|
||||||
|
*
|
||||||
|
* This really should be:
|
||||||
|
devs = devkit_client_enumerate_by_subsystem(devkit_client, NULL, &err);
|
||||||
|
if (err) {
|
||||||
|
DEBUG0("devkit_client_enumerate_by_subsystem failed");
|
||||||
|
devs = NULL;
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
g_list_foreach(devs, dev_create, devkit_client);
|
||||||
|
* but devkit_client_enumerate_by_subsystem currently fails when the second
|
||||||
|
* arg is null (contrary to the API documentation). So the following code
|
||||||
|
* (from Dan B) works around this by listing devices per handled subsystem.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (i = 0 ; i < ARRAY_CARDINALITY(caps_tbl) ; i++) {
|
||||||
|
const char *caps[] = { caps_tbl[i].cap_name, NULL };
|
||||||
|
devs = devkit_client_enumerate_by_subsystem(devkit_client,
|
||||||
|
caps,
|
||||||
|
&err);
|
||||||
|
if (err) {
|
||||||
|
DEBUG0("devkit_client_enumerate_by_subsystem failed");
|
||||||
|
devs = NULL;
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
g_list_foreach(devs, dev_create, devkit_client);
|
||||||
|
}
|
||||||
|
|
||||||
|
driverState->privateData = devkit_client;
|
||||||
|
|
||||||
|
// TODO: Register to get DeviceKit events on device changes and
|
||||||
|
// coordinate updates with queries and other operations.
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
if (err) {
|
||||||
|
DEBUG("\terror[%d]: %s", err->code, err->message);
|
||||||
|
g_error_free(err);
|
||||||
|
}
|
||||||
|
if (devs) {
|
||||||
|
g_list_foreach(devs, (GFunc)g_object_unref, NULL);
|
||||||
|
g_list_free(devs);
|
||||||
|
}
|
||||||
|
if (devkit_client)
|
||||||
|
g_object_unref(devkit_client);
|
||||||
|
VIR_FREE(driverState);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int devkitDeviceMonitorShutdown(void)
|
||||||
|
{
|
||||||
|
if (driverState) {
|
||||||
|
DevkitClient *devkit_client = DRV_STATE_DKCLIENT(driverState);
|
||||||
|
virNodeDeviceObjListFree(&driverState->devs);
|
||||||
|
if (devkit_client)
|
||||||
|
g_object_unref(devkit_client);
|
||||||
|
VIR_FREE(driverState);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int devkitDeviceMonitorReload(void)
|
||||||
|
{
|
||||||
|
(void)devkitDeviceMonitorShutdown();
|
||||||
|
return devkitDeviceMonitorStartup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int devkitDeviceMonitorActive(void)
|
||||||
|
{
|
||||||
|
/* Always ready to deal with a shutdown */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static virDrvOpenStatus
|
||||||
|
devkitNodeDrvOpen(virConnectPtr conn,
|
||||||
|
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
||||||
|
int flags ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
if (driverState == NULL)
|
||||||
|
return VIR_DRV_OPEN_DECLINED;
|
||||||
|
|
||||||
|
conn->devMonPrivateData = driverState;
|
||||||
|
|
||||||
|
return VIR_DRV_OPEN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int devkitNodeDrvClose(virConnectPtr conn ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
conn->devMonPrivateData = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static virDeviceMonitor devkitDeviceMonitor = {
|
||||||
|
.name = "devkitDeviceMonitor",
|
||||||
|
.open = devkitNodeDrvOpen,
|
||||||
|
.close = devkitNodeDrvClose,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static virStateDriver devkitStateDriver = {
|
||||||
|
.initialize = devkitDeviceMonitorStartup,
|
||||||
|
.cleanup = devkitDeviceMonitorShutdown,
|
||||||
|
.reload = devkitDeviceMonitorReload,
|
||||||
|
.active = devkitDeviceMonitorActive,
|
||||||
|
};
|
||||||
|
|
||||||
|
int devkitNodeRegister(void)
|
||||||
|
{
|
||||||
|
registerCommonNodeFuncs(&devkitDeviceMonitor);
|
||||||
|
if (virRegisterDeviceMonitor(&devkitDeviceMonitor) < 0)
|
||||||
|
return -1;
|
||||||
|
return virRegisterStateDriver(&devkitStateDriver);
|
||||||
|
}
|
766
src/node_device_hal.c
Normal file
766
src/node_device_hal.c
Normal file
@ -0,0 +1,766 @@
|
|||||||
|
/*
|
||||||
|
* node_device_hal.c: node device enumeration - HAL-based implementation
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Virtual Iron Software, Inc.
|
||||||
|
* Copyright (C) 2008 David F. Lively
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* Author: David F. Lively <dlively@virtualiron.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <libhal.h>
|
||||||
|
|
||||||
|
#include "node_device_conf.h"
|
||||||
|
#include "virterror_internal.h"
|
||||||
|
#include "driver.h"
|
||||||
|
#include "datatypes.h"
|
||||||
|
#include "event.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "uuid.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "node_device.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Host device enumeration (HAL implementation)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static virDeviceMonitorStatePtr driverState;
|
||||||
|
|
||||||
|
#define CONN_DRV_STATE(conn) \
|
||||||
|
((virDeviceMonitorStatePtr)((conn)->devMonPrivateData))
|
||||||
|
#define DRV_STATE_HAL_CTX(ds) ((LibHalContext *)((ds)->privateData))
|
||||||
|
#define CONN_HAL_CTX(conn) DRV_STATE_HAL_CTX(CONN_DRV_STATE(conn))
|
||||||
|
|
||||||
|
#define NODE_DEV_UDI(obj) ((const char *)((obj)->privateData)
|
||||||
|
|
||||||
|
|
||||||
|
static const char *hal_name(const char *udi)
|
||||||
|
{
|
||||||
|
const char *name = strrchr(udi, '/');
|
||||||
|
if (name)
|
||||||
|
return name+1;
|
||||||
|
return udi;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int get_str_prop(LibHalContext *ctxt, const char *udi,
|
||||||
|
const char *prop, char **val_p)
|
||||||
|
{
|
||||||
|
char *val = libhal_device_get_property_string(ctxt, udi, prop, NULL);
|
||||||
|
|
||||||
|
if (val) {
|
||||||
|
if (*val) {
|
||||||
|
*val_p = val;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
/* Treat empty strings as NULL values */
|
||||||
|
VIR_FREE(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_int_prop(LibHalContext *ctxt, const char *udi,
|
||||||
|
const char *prop, int *val_p)
|
||||||
|
{
|
||||||
|
DBusError err;
|
||||||
|
int val;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
dbus_error_init(&err);
|
||||||
|
val = libhal_device_get_property_int(ctxt, udi, prop, &err);
|
||||||
|
rv = dbus_error_is_set(&err);
|
||||||
|
dbus_error_free(&err);
|
||||||
|
if (rv == 0)
|
||||||
|
*val_p = val;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_bool_prop(LibHalContext *ctxt, const char *udi,
|
||||||
|
const char *prop, int *val_p)
|
||||||
|
{
|
||||||
|
DBusError err;
|
||||||
|
int val;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
dbus_error_init(&err);
|
||||||
|
val = libhal_device_get_property_bool(ctxt, udi, prop, &err);
|
||||||
|
rv = dbus_error_is_set(&err);
|
||||||
|
dbus_error_free(&err);
|
||||||
|
if (rv == 0)
|
||||||
|
*val_p = val;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_uint64_prop(LibHalContext *ctxt, const char *udi,
|
||||||
|
const char *prop, unsigned long long *val_p)
|
||||||
|
{
|
||||||
|
DBusError err;
|
||||||
|
unsigned long long val;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
dbus_error_init(&err);
|
||||||
|
val = libhal_device_get_property_uint64(ctxt, udi, prop, &err);
|
||||||
|
rv = dbus_error_is_set(&err);
|
||||||
|
dbus_error_free(&err);
|
||||||
|
if (rv == 0)
|
||||||
|
*val_p = val;
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gather_pci_cap(LibHalContext *ctx, const char *udi,
|
||||||
|
union _virNodeDevCapData *d)
|
||||||
|
{
|
||||||
|
char *sysfs_path;
|
||||||
|
|
||||||
|
if (get_str_prop(ctx, udi, "pci.linux.sysfs_path", &sysfs_path) == 0) {
|
||||||
|
char *p = strrchr(sysfs_path, '/');
|
||||||
|
if (p) {
|
||||||
|
(void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.domain);
|
||||||
|
(void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.bus);
|
||||||
|
(void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.slot);
|
||||||
|
(void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function);
|
||||||
|
}
|
||||||
|
VIR_FREE(sysfs_path);
|
||||||
|
}
|
||||||
|
(void)get_int_prop(ctx, udi, "pci.vendor_id", (int *)&d->pci_dev.vendor);
|
||||||
|
if (get_str_prop(ctx, udi, "pci.vendor", &d->pci_dev.vendor_name) != 0)
|
||||||
|
(void)get_str_prop(ctx, udi, "info.vendor", &d->pci_dev.vendor_name);
|
||||||
|
(void)get_int_prop(ctx, udi, "pci.product_id", (int *)&d->pci_dev.product);
|
||||||
|
if (get_str_prop(ctx, udi, "pci.product", &d->pci_dev.product_name) != 0)
|
||||||
|
(void)get_str_prop(ctx, udi, "info.product", &d->pci_dev.product_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_usb_cap(LibHalContext *ctx, const char *udi,
|
||||||
|
union _virNodeDevCapData *d)
|
||||||
|
{
|
||||||
|
(void)get_int_prop(ctx, udi, "usb.interface.number",
|
||||||
|
(int *)&d->usb_if.number);
|
||||||
|
(void)get_int_prop(ctx, udi, "usb.interface.class",
|
||||||
|
(int *)&d->usb_if._class);
|
||||||
|
(void)get_int_prop(ctx, udi, "usb.interface.subclass",
|
||||||
|
(int *)&d->usb_if.subclass);
|
||||||
|
(void)get_int_prop(ctx, udi, "usb.interface.protocol",
|
||||||
|
(int *)&d->usb_if.protocol);
|
||||||
|
(void)get_str_prop(ctx, udi, "usb.interface.description",
|
||||||
|
&d->usb_if.description);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_usb_device_cap(LibHalContext *ctx, const char *udi,
|
||||||
|
union _virNodeDevCapData *d)
|
||||||
|
{
|
||||||
|
(void)get_int_prop(ctx, udi, "usb_device.bus_number",
|
||||||
|
(int *)&d->usb_dev.bus);
|
||||||
|
(void)get_int_prop(ctx, udi, "usb_device.linux.device_number",
|
||||||
|
(int *)&d->usb_dev.device);
|
||||||
|
(void)get_int_prop(ctx, udi, "usb_device.vendor_id",
|
||||||
|
(int *)&d->usb_dev.vendor);
|
||||||
|
if (get_str_prop(ctx, udi, "usb_device.vendor",
|
||||||
|
&d->usb_dev.vendor_name) != 0)
|
||||||
|
(void)get_str_prop(ctx, udi, "info.vendor", &d->usb_dev.vendor_name);
|
||||||
|
(void)get_int_prop(ctx, udi, "usb_device.product_id",
|
||||||
|
(int *)&d->usb_dev.product);
|
||||||
|
if (get_str_prop(ctx, udi, "usb_device.product",
|
||||||
|
&d->usb_dev.product_name) != 0)
|
||||||
|
(void)get_str_prop(ctx, udi, "info.product", &d->usb_dev.product_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_net_cap(LibHalContext *ctx, const char *udi,
|
||||||
|
union _virNodeDevCapData *d)
|
||||||
|
{
|
||||||
|
unsigned long long dummy;
|
||||||
|
(void)get_str_prop(ctx, udi, "net.interface", &d->net.interface);
|
||||||
|
(void)get_str_prop(ctx, udi, "net.address", &d->net.address);
|
||||||
|
if (get_uint64_prop(ctx, udi, "net.80203.mac_address",
|
||||||
|
&dummy) == 0)
|
||||||
|
d->net.subtype = VIR_NODE_DEV_CAP_NET_80203;
|
||||||
|
else if (get_uint64_prop(ctx, udi, "net.80211.mac_address",
|
||||||
|
&dummy) == 0)
|
||||||
|
d->net.subtype = VIR_NODE_DEV_CAP_NET_80211;
|
||||||
|
else
|
||||||
|
d->net.subtype = VIR_NODE_DEV_CAP_NET_LAST;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_block_cap(LibHalContext *ctx, const char *udi,
|
||||||
|
union _virNodeDevCapData *d)
|
||||||
|
{
|
||||||
|
(void)get_str_prop(ctx, udi, "block.device", &d->block.device);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_scsi_host_cap(LibHalContext *ctx, const char *udi,
|
||||||
|
union _virNodeDevCapData *d)
|
||||||
|
{
|
||||||
|
(void)get_int_prop(ctx, udi, "scsi_host.host", (int *)&d->scsi_host.host);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_scsi_cap(LibHalContext *ctx, const char *udi,
|
||||||
|
union _virNodeDevCapData *d)
|
||||||
|
{
|
||||||
|
(void)get_int_prop(ctx, udi, "scsi.host", (int *)&d->scsi.host);
|
||||||
|
(void)get_int_prop(ctx, udi, "scsi.bus", (int *)&d->scsi.bus);
|
||||||
|
(void)get_int_prop(ctx, udi, "scsi.target", (int *)&d->scsi.target);
|
||||||
|
(void)get_int_prop(ctx, udi, "scsi.lun", (int *)&d->scsi.lun);
|
||||||
|
(void)get_str_prop(ctx, udi, "scsi.type", &d->scsi.type);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_storage_cap(LibHalContext *ctx, const char *udi,
|
||||||
|
union _virNodeDevCapData *d)
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
(void)get_str_prop(ctx, udi, "storage.bus", &d->storage.bus);
|
||||||
|
(void)get_str_prop(ctx, udi, "storage.drive_type", &d->storage.drive_type);
|
||||||
|
(void)get_str_prop(ctx, udi, "storage.model", &d->storage.model);
|
||||||
|
(void)get_str_prop(ctx, udi, "storage.vendor", &d->storage.vendor);
|
||||||
|
if (get_bool_prop(ctx, udi, "storage.removable", &val) == 0 && val) {
|
||||||
|
d->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE;
|
||||||
|
if (get_bool_prop(ctx, udi,
|
||||||
|
"storage.removable.media_available", &val) && val) {
|
||||||
|
d->storage.flags |=
|
||||||
|
VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE;
|
||||||
|
(void)get_uint64_prop(ctx, udi, "storage.removable.media_size",
|
||||||
|
&d->storage.removable_media_size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(void)get_uint64_prop(ctx, udi, "storage.size", &d->storage.size);
|
||||||
|
}
|
||||||
|
if (get_bool_prop(ctx, udi, "storage.hotpluggable", &val) == 0 && val)
|
||||||
|
d->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_system_cap(LibHalContext *ctx, const char *udi,
|
||||||
|
union _virNodeDevCapData *d)
|
||||||
|
{
|
||||||
|
char *uuidstr;
|
||||||
|
|
||||||
|
(void)get_str_prop(ctx, udi, "system.product", &d->system.product_name);
|
||||||
|
(void)get_str_prop(ctx, udi, "system.hardware.vendor",
|
||||||
|
&d->system.hardware.vendor_name);
|
||||||
|
(void)get_str_prop(ctx, udi, "system.hardware.version",
|
||||||
|
&d->system.hardware.version);
|
||||||
|
(void)get_str_prop(ctx, udi, "system.hardware.serial",
|
||||||
|
&d->system.hardware.serial);
|
||||||
|
if (get_str_prop(ctx, udi, "system.hardware.uuid", &uuidstr) == 0) {
|
||||||
|
(void)virUUIDParse(uuidstr, d->system.hardware.uuid);
|
||||||
|
VIR_FREE(uuidstr);
|
||||||
|
}
|
||||||
|
(void)get_str_prop(ctx, udi, "system.firmware.vendor",
|
||||||
|
&d->system.firmware.vendor_name);
|
||||||
|
(void)get_str_prop(ctx, udi, "system.firmware.version",
|
||||||
|
&d->system.firmware.version);
|
||||||
|
(void)get_str_prop(ctx, udi, "system.firmware.release_date",
|
||||||
|
&d->system.firmware.release_date);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct _caps_tbl_entry {
|
||||||
|
const char *cap_name;
|
||||||
|
enum virNodeDevCapType type;
|
||||||
|
int (*gather_fn)(LibHalContext *ctx,
|
||||||
|
const char *udi,
|
||||||
|
union _virNodeDevCapData *data);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _caps_tbl_entry caps_tbl_entry;
|
||||||
|
|
||||||
|
static caps_tbl_entry caps_tbl[] = {
|
||||||
|
{ "system", VIR_NODE_DEV_CAP_SYSTEM, gather_system_cap },
|
||||||
|
{ "pci", VIR_NODE_DEV_CAP_PCI_DEV, gather_pci_cap },
|
||||||
|
{ "usb", VIR_NODE_DEV_CAP_USB_INTERFACE, gather_usb_cap },
|
||||||
|
{ "usb_device", VIR_NODE_DEV_CAP_USB_DEV, gather_usb_device_cap },
|
||||||
|
{ "net", VIR_NODE_DEV_CAP_NET, gather_net_cap },
|
||||||
|
{ "block", VIR_NODE_DEV_CAP_BLOCK, gather_block_cap },
|
||||||
|
{ "scsi_host", VIR_NODE_DEV_CAP_SCSI_HOST, gather_scsi_host_cap },
|
||||||
|
{ "scsi", VIR_NODE_DEV_CAP_SCSI, gather_scsi_cap },
|
||||||
|
{ "storage", VIR_NODE_DEV_CAP_STORAGE, gather_storage_cap },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* qsort/bsearch string comparator */
|
||||||
|
static int cmpstringp(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
/* from man 3 qsort */
|
||||||
|
return strcmp(* (char * const *) p1, * (char * const *) p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_capability(LibHalContext *ctx, const char *udi,
|
||||||
|
const char *cap_name,
|
||||||
|
virNodeDevCapsDefPtr *caps_p)
|
||||||
|
{
|
||||||
|
caps_tbl_entry *entry;
|
||||||
|
|
||||||
|
entry = bsearch(&cap_name, caps_tbl, ARRAY_CARDINALITY(caps_tbl),
|
||||||
|
sizeof(caps_tbl[0]), cmpstringp);
|
||||||
|
|
||||||
|
if (entry) {
|
||||||
|
virNodeDevCapsDefPtr caps;
|
||||||
|
if (VIR_ALLOC(caps) < 0)
|
||||||
|
return ENOMEM;
|
||||||
|
caps->type = entry->type;
|
||||||
|
if (entry->gather_fn) {
|
||||||
|
int rv = (*entry->gather_fn)(ctx, udi, &caps->data);
|
||||||
|
if (rv != 0) {
|
||||||
|
virNodeDevCapsDefFree(caps);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
caps->next = *caps_p;
|
||||||
|
*caps_p = caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gather_capabilities(LibHalContext *ctx, const char *udi,
|
||||||
|
virNodeDevCapsDefPtr *caps_p)
|
||||||
|
{
|
||||||
|
char *bus_name = NULL;
|
||||||
|
virNodeDevCapsDefPtr caps = NULL;
|
||||||
|
char **hal_cap_names;
|
||||||
|
int rv, i;
|
||||||
|
|
||||||
|
if (STREQ(udi, "/org/freedesktop/Hal/devices/computer")) {
|
||||||
|
rv = gather_capability(ctx, udi, "system", &caps);
|
||||||
|
if (rv != 0)
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_str_prop(ctx, udi, "info.subsystem", &bus_name) == 0) {
|
||||||
|
rv = gather_capability(ctx, udi, bus_name, &caps);
|
||||||
|
if (rv != 0)
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
hal_cap_names = libhal_device_get_property_strlist(ctx, udi,
|
||||||
|
"info.capabilities",
|
||||||
|
NULL);
|
||||||
|
if (hal_cap_names) {
|
||||||
|
for (i = 0; hal_cap_names[i]; i++) {
|
||||||
|
if (! (bus_name && STREQ(hal_cap_names[i], bus_name))) {
|
||||||
|
rv = gather_capability(ctx, udi, hal_cap_names[i], &caps);
|
||||||
|
if (rv != 0)
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; hal_cap_names[i]; i++)
|
||||||
|
VIR_FREE(hal_cap_names[i]);
|
||||||
|
VIR_FREE(hal_cap_names);
|
||||||
|
}
|
||||||
|
VIR_FREE(bus_name);
|
||||||
|
|
||||||
|
*caps_p = caps;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
VIR_FREE(bus_name);
|
||||||
|
if (hal_cap_names) {
|
||||||
|
for (i = 0; hal_cap_names[i]; i++)
|
||||||
|
VIR_FREE(hal_cap_names[i]);
|
||||||
|
VIR_FREE(hal_cap_names);
|
||||||
|
}
|
||||||
|
while (caps) {
|
||||||
|
virNodeDevCapsDefPtr next = caps->next;
|
||||||
|
virNodeDevCapsDefFree(caps);
|
||||||
|
caps = next;
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_udi(void *udi)
|
||||||
|
{
|
||||||
|
VIR_FREE(udi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_create(char *udi)
|
||||||
|
{
|
||||||
|
LibHalContext *ctx = DRV_STATE_HAL_CTX(driverState);
|
||||||
|
char *parent_key = NULL;
|
||||||
|
virNodeDeviceObjPtr dev;
|
||||||
|
const char *name = hal_name(udi);
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (VIR_ALLOC(dev) < 0 || VIR_ALLOC(dev->def) < 0)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
dev->privateData = udi;
|
||||||
|
dev->privateFree = free_udi;
|
||||||
|
|
||||||
|
if ((dev->def->name = strdup(name)) == NULL)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
if (get_str_prop(ctx, udi, "info.parent", &parent_key) == 0) {
|
||||||
|
dev->def->parent = strdup(hal_name(parent_key));
|
||||||
|
VIR_FREE(parent_key);
|
||||||
|
if (dev->def->parent == NULL)
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = gather_capabilities(ctx, udi, &dev->def->caps);
|
||||||
|
if (rv != 0) goto failure;
|
||||||
|
|
||||||
|
if (VIR_REALLOC_N(driverState->devs.objs, driverState->devs.count + 1) < 0)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
driverState->devs.objs[driverState->devs.count++] = dev;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
DEBUG("FAILED TO ADD dev %s", name);
|
||||||
|
if (dev)
|
||||||
|
virNodeDeviceDefFree(dev->def);
|
||||||
|
VIR_FREE(dev);
|
||||||
|
VIR_FREE(udi);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void device_added(LibHalContext *ctx ATTRIBUTE_UNUSED,
|
||||||
|
const char *udi)
|
||||||
|
{
|
||||||
|
DEBUG0(hal_name(udi));
|
||||||
|
dev_create(strdup(udi));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void device_removed(LibHalContext *ctx ATTRIBUTE_UNUSED,
|
||||||
|
const char *udi)
|
||||||
|
{
|
||||||
|
const char *name = hal_name(udi);
|
||||||
|
virNodeDeviceObjPtr dev = virNodeDeviceFindByName(&driverState->devs,name);
|
||||||
|
DEBUG0(name);
|
||||||
|
if (dev)
|
||||||
|
virNodeDeviceObjRemove(&driverState->devs, dev);
|
||||||
|
else
|
||||||
|
DEBUG("no device named %s", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void device_cap_added(LibHalContext *ctx,
|
||||||
|
const char *udi, const char *cap)
|
||||||
|
{
|
||||||
|
const char *name = hal_name(udi);
|
||||||
|
virNodeDeviceObjPtr dev = virNodeDeviceFindByName(&driverState->devs,name);
|
||||||
|
DEBUG("%s %s", cap, name);
|
||||||
|
if (dev)
|
||||||
|
(void)gather_capability(ctx, udi, cap, &dev->def->caps);
|
||||||
|
else
|
||||||
|
DEBUG("no device named %s", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void device_cap_lost(LibHalContext *ctx ATTRIBUTE_UNUSED,
|
||||||
|
const char *udi,
|
||||||
|
const char *cap)
|
||||||
|
{
|
||||||
|
const char *name = hal_name(udi);
|
||||||
|
virNodeDeviceObjPtr dev = virNodeDeviceFindByName(&driverState->devs,name);
|
||||||
|
DEBUG("%s %s", cap, name);
|
||||||
|
if (dev) {
|
||||||
|
/* Simply "rediscover" device -- incrementally handling changes
|
||||||
|
* to sub-capabilities (like net.80203) is nasty ... so avoid it.
|
||||||
|
*/
|
||||||
|
virNodeDeviceObjRemove(&driverState->devs, dev);
|
||||||
|
dev_create(strdup(udi));
|
||||||
|
} else
|
||||||
|
DEBUG("no device named %s", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void device_prop_modified(LibHalContext *ctx ATTRIBUTE_UNUSED,
|
||||||
|
const char *udi,
|
||||||
|
const char *key,
|
||||||
|
dbus_bool_t is_removed ATTRIBUTE_UNUSED,
|
||||||
|
dbus_bool_t is_added ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
const char *name = hal_name(udi);
|
||||||
|
virNodeDeviceObjPtr dev = virNodeDeviceFindByName(&driverState->devs,name);
|
||||||
|
DEBUG("%s %s", key, name);
|
||||||
|
if (dev) {
|
||||||
|
/* Simply "rediscover" device -- incrementally handling changes
|
||||||
|
* to properties (which are mapped into caps in very capability-
|
||||||
|
* specific ways) is nasty ... so avoid it.
|
||||||
|
*/
|
||||||
|
virNodeDeviceObjRemove(&driverState->devs, dev);
|
||||||
|
dev_create(strdup(udi));
|
||||||
|
} else
|
||||||
|
DEBUG("no device named %s", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void dbus_watch_callback(int fdatch ATTRIBUTE_UNUSED,
|
||||||
|
int fd ATTRIBUTE_UNUSED,
|
||||||
|
int events, void *opaque)
|
||||||
|
{
|
||||||
|
DBusWatch *watch = opaque;
|
||||||
|
LibHalContext *hal_ctx = DRV_STATE_HAL_CTX(driverState);
|
||||||
|
DBusConnection *dbus_conn = libhal_ctx_get_dbus_connection(hal_ctx);
|
||||||
|
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(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static dbus_bool_t add_dbus_watch(DBusWatch *watch,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
int flags = 0;
|
||||||
|
virDeviceMonitorStatePtr state = data;
|
||||||
|
|
||||||
|
if (dbus_watch_get_enabled(watch))
|
||||||
|
flags = xlate_dbus_watch_flags(dbus_watch_get_flags(watch));
|
||||||
|
|
||||||
|
if ((state->dbusWatch =
|
||||||
|
virEventAddHandle(dbus_watch_get_unix_fd(watch), flags,
|
||||||
|
dbus_watch_callback, watch, NULL)) < 0)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void remove_dbus_watch(DBusWatch *watch ATTRIBUTE_UNUSED,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
virDeviceMonitorStatePtr state = data;
|
||||||
|
|
||||||
|
(void)virEventRemoveHandle(state->dbusWatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void toggle_dbus_watch(DBusWatch *watch,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
int flags = 0;
|
||||||
|
virDeviceMonitorStatePtr state = data;
|
||||||
|
|
||||||
|
if (dbus_watch_get_enabled(watch))
|
||||||
|
flags = xlate_dbus_watch_flags(dbus_watch_get_flags(watch));
|
||||||
|
|
||||||
|
(void)virEventUpdateHandle(state->dbusWatch, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int halDeviceMonitorStartup(void)
|
||||||
|
{
|
||||||
|
LibHalContext *hal_ctx = NULL;
|
||||||
|
DBusConnection *dbus_conn = NULL;
|
||||||
|
DBusError err;
|
||||||
|
char **udi = NULL;
|
||||||
|
int num_devs, i;
|
||||||
|
|
||||||
|
/* Ensure caps_tbl is sorted by capability name */
|
||||||
|
qsort(caps_tbl, ARRAY_CARDINALITY(caps_tbl), sizeof(caps_tbl[0]),
|
||||||
|
cmpstringp);
|
||||||
|
|
||||||
|
if (VIR_ALLOC(driverState) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Allocate and initialize a new HAL context */
|
||||||
|
dbus_error_init(&err);
|
||||||
|
hal_ctx = libhal_ctx_new();
|
||||||
|
if (hal_ctx == NULL) {
|
||||||
|
fprintf(stderr, "%s: libhal_ctx_new returned NULL\n", __FUNCTION__);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
|
||||||
|
if (dbus_conn == NULL) {
|
||||||
|
fprintf(stderr, "%s: dbus_bus_get failed\n", __FUNCTION__);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
if (!libhal_ctx_set_dbus_connection(hal_ctx, dbus_conn)) {
|
||||||
|
fprintf(stderr, "%s: libhal_ctx_set_dbus_connection failed\n",
|
||||||
|
__FUNCTION__);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
if (!libhal_ctx_init(hal_ctx, &err)) {
|
||||||
|
fprintf(stderr, "%s: libhal_ctx_init failed\n", __FUNCTION__);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register dbus watch callbacks */
|
||||||
|
if (!dbus_connection_set_watch_functions(dbus_conn,
|
||||||
|
add_dbus_watch,
|
||||||
|
remove_dbus_watch,
|
||||||
|
toggle_dbus_watch,
|
||||||
|
driverState, NULL)) {
|
||||||
|
fprintf(stderr, "%s: dbus_connection_set_watch_functions failed\n",
|
||||||
|
__FUNCTION__);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register HAL event callbacks */
|
||||||
|
if (!libhal_ctx_set_device_added(hal_ctx, device_added) ||
|
||||||
|
!libhal_ctx_set_device_removed(hal_ctx, device_removed) ||
|
||||||
|
!libhal_ctx_set_device_new_capability(hal_ctx, device_cap_added) ||
|
||||||
|
!libhal_ctx_set_device_lost_capability(hal_ctx, device_cap_lost) ||
|
||||||
|
!libhal_ctx_set_device_property_modified(hal_ctx, device_prop_modified)) {
|
||||||
|
fprintf(stderr, "%s: setting up HAL callbacks failed\n", __FUNCTION__);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Populate with known devices */
|
||||||
|
driverState->privateData = hal_ctx;
|
||||||
|
udi = libhal_get_all_devices(hal_ctx, &num_devs, &err);
|
||||||
|
if (udi == NULL) {
|
||||||
|
fprintf(stderr, "%s: libhal_get_all_devices failed\n", __FUNCTION__);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
for (i = 0; i < num_devs; i++)
|
||||||
|
dev_create(udi[i]);
|
||||||
|
free(udi);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
if (dbus_error_is_set(&err)) {
|
||||||
|
fprintf(stderr, "\t%s: %s\n", err.name, err.message);
|
||||||
|
dbus_error_free(&err);
|
||||||
|
}
|
||||||
|
virNodeDeviceObjListFree(&driverState->devs);
|
||||||
|
if (hal_ctx)
|
||||||
|
(void)libhal_ctx_free(hal_ctx);
|
||||||
|
if (udi) {
|
||||||
|
for (i = 0; i < num_devs; i++)
|
||||||
|
free(udi[i]);
|
||||||
|
free(udi);
|
||||||
|
}
|
||||||
|
VIR_FREE(driverState);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int halDeviceMonitorShutdown(void)
|
||||||
|
{
|
||||||
|
if (driverState) {
|
||||||
|
LibHalContext *hal_ctx = DRV_STATE_HAL_CTX(driverState);
|
||||||
|
virNodeDeviceObjListFree(&driverState->devs);
|
||||||
|
(void)libhal_ctx_shutdown(hal_ctx, NULL);
|
||||||
|
(void)libhal_ctx_free(hal_ctx);
|
||||||
|
VIR_FREE(driverState);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int halDeviceMonitorReload(void)
|
||||||
|
{
|
||||||
|
(void)halDeviceMonitorShutdown();
|
||||||
|
return halDeviceMonitorStartup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int halDeviceMonitorActive(void)
|
||||||
|
{
|
||||||
|
/* Always ready to deal with a shutdown */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static virDrvOpenStatus halNodeDrvOpen(virConnectPtr conn,
|
||||||
|
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
|
||||||
|
int flags ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
if (driverState == NULL)
|
||||||
|
return VIR_DRV_OPEN_DECLINED;
|
||||||
|
|
||||||
|
conn->devMonPrivateData = driverState;
|
||||||
|
|
||||||
|
return VIR_DRV_OPEN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int halNodeDrvClose(virConnectPtr conn ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
conn->devMonPrivateData = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static virDeviceMonitor halDeviceMonitor = {
|
||||||
|
.name = "halDeviceMonitor",
|
||||||
|
.open = halNodeDrvOpen,
|
||||||
|
.close = halNodeDrvClose,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static virStateDriver halStateDriver = {
|
||||||
|
.initialize = halDeviceMonitorStartup,
|
||||||
|
.cleanup = halDeviceMonitorShutdown,
|
||||||
|
.reload = halDeviceMonitorReload,
|
||||||
|
.active = halDeviceMonitorActive,
|
||||||
|
};
|
||||||
|
|
||||||
|
int halNodeRegister(void)
|
||||||
|
{
|
||||||
|
registerCommonNodeFuncs(&halDeviceMonitor);
|
||||||
|
if (virRegisterDeviceMonitor(&halDeviceMonitor) < 0)
|
||||||
|
return -1;
|
||||||
|
return virRegisterStateDriver(&halStateDriver);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user