Devel
Threads by month
- ----- 2026 -----
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
November 2009
- 68 participants
- 193 discussions
Attached is a fully functional version of the node device udev based
backend, incorporating all the feedback from earlier revisions. I broke
the new capability fields out into a separate patch per Dan's
suggestion, and I have also included a patch removing the DevKit backend.
Dave
>From e95f0c84ff50c4d8736750e93b70b901c7a246ad Mon Sep 17 00:00:00 2001
From: David Allan <dallan(a)redhat.com>
Date: Fri, 16 Oct 2009 16:52:40 -0400
Subject: [PATCH 1/3] Add several fields to node device capabilities
---
src/conf/node_device_conf.c | 22 ++++++++++++++++++++++
src/conf/node_device_conf.h | 7 +++++++
2 files changed, 29 insertions(+), 0 deletions(-)
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index c2c5a44..87f441d 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -248,6 +248,12 @@ char *virNodeDeviceDefFormat(virConnectPtr conn,
if (data->system.product_name)
virBufferEscapeString(&buf, " <product>%s</product>\n",
data->system.product_name);
+ if (data->system.dmi_devpath)
+ virBufferEscapeString(&buf, " <dmi_devpath>%s</dmi_devpath>\n",
+ data->system.dmi_devpath);
+ if (data->system.description)
+ virBufferEscapeString(&buf, " <description>%s</description>\n",
+ data->system.description);
virBufferAddLit(&buf, " <hardware>\n");
if (data->system.hardware.vendor_name)
virBufferEscapeString(&buf, " <vendor>%s</vendor>\n",
@@ -325,6 +331,9 @@ char *virNodeDeviceDefFormat(virConnectPtr conn,
data->usb_if.subclass);
virBufferVSprintf(&buf, " <protocol>%d</protocol>\n",
data->usb_if.protocol);
+ if (data->usb_if.interface_name)
+ virBufferVSprintf(&buf, " <interface_name>%s</interface_name>\n",
+ data->usb_if.interface_name);
if (data->usb_if.description)
virBufferVSprintf(&buf, " <description>%s</description>\n",
data->usb_if.description);
@@ -394,10 +403,20 @@ char *virNodeDeviceDefFormat(virConnectPtr conn,
"</media_available>\n", avl ? 1 : 0);
virBufferVSprintf(&buf, " <media_size>%llu</media_size>\n",
data->storage.removable_media_size);
+ virBufferVSprintf(&buf, " <logical_block_size>%llu"
+ "</logical_block_size>\n",
+ data->storage.logical_block_size);
+ virBufferVSprintf(&buf, " <num_blocks>%llu</num_blocks>\n",
+ data->storage.num_blocks);
virBufferAddLit(&buf, " </capability>\n");
} else {
virBufferVSprintf(&buf, " <size>%llu</size>\n",
data->storage.size);
+ virBufferVSprintf(&buf, " <logical_block_size>%llu"
+ "</logical_block_size>\n",
+ data->storage.logical_block_size);
+ virBufferVSprintf(&buf, " <num_blocks>%llu</num_blocks>\n",
+ data->storage.num_blocks);
}
if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE)
virBufferAddLit(&buf,
@@ -1310,6 +1329,8 @@ void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
switch (caps->type) {
case VIR_NODE_DEV_CAP_SYSTEM:
VIR_FREE(data->system.product_name);
+ VIR_FREE(data->system.dmi_devpath);
+ VIR_FREE(data->system.description);
VIR_FREE(data->system.hardware.vendor_name);
VIR_FREE(data->system.hardware.version);
VIR_FREE(data->system.hardware.serial);
@@ -1326,6 +1347,7 @@ void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps)
VIR_FREE(data->usb_dev.vendor_name);
break;
case VIR_NODE_DEV_CAP_USB_INTERFACE:
+ VIR_FREE(data->usb_if.interface_name);
VIR_FREE(data->usb_if.description);
break;
case VIR_NODE_DEV_CAP_NET:
diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
index a7bb6c6..f70184d 100644
--- a/src/conf/node_device_conf.h
+++ b/src/conf/node_device_conf.h
@@ -82,6 +82,8 @@ struct _virNodeDevCapsDef {
union _virNodeDevCapData {
struct {
char *product_name;
+ char *description;
+ char *dmi_devpath;
struct {
char *vendor_name;
char *version;
@@ -101,6 +103,7 @@ struct _virNodeDevCapsDef {
unsigned function;
unsigned product;
unsigned vendor;
+ unsigned class;
char *product_name;
char *vendor_name;
} pci_dev;
@@ -117,10 +120,12 @@ struct _virNodeDevCapsDef {
unsigned _class; /* "class" is reserved in C */
unsigned subclass;
unsigned protocol;
+ char *interface_name;
char *description;
} usb_if;
struct {
char *address;
+ unsigned address_len;
char *ifname;
enum virNodeDevNetCapType subtype; /* LAST -> no subtype */
} net;
@@ -139,6 +144,8 @@ struct _virNodeDevCapsDef {
} scsi;
struct {
unsigned long long size;
+ unsigned long long num_blocks;
+ unsigned long long logical_block_size;
unsigned long long removable_media_size;
char *block;
char *bus;
--
1.6.4.4
>From d8f4ac6806a8f55e4f9fa9c4af3e0c89aa4d0074 Mon Sep 17 00:00:00 2001
From: David Allan <dallan(a)redhat.com>
Date: Fri, 16 Oct 2009 10:09:01 -0400
Subject: [PATCH 2/3] Implement a node device backend using libudev.
Monitoring for addition and removal of devices is implemented.
There is a lot of detail work in this code, so we should try to get people running it on a wide variety of hardware so we can shake out the differences in implementation between the HAL and libudev backends.
I have moved the new fields in the node device capabilities to a separate patch.
This version contains changes per all the feedback I've received on earlier versions.
---
configure.in | 47 +-
daemon/libvirtd.c | 3 +-
po/POTFILES.in | 3 +-
src/Makefile.am | 16 +-
src/node_device/node_device_driver.c | 12 +-
src/node_device/node_device_driver.h | 22 +
src/node_device/node_device_hal.h | 19 -
...evice_hal_linux.c => node_device_linux_sysfs.c} | 0
src/node_device/node_device_udev.c | 1142 ++++++++++++++++++++
src/node_device/node_device_udev.h | 32 +
src/util/util.c | 28 +
src/util/util.h | 3 +
tools/virsh.c | 10 +-
13 files changed, 1306 insertions(+), 31 deletions(-)
rename src/node_device/{node_device_hal_linux.c => node_device_linux_sysfs.c} (100%)
create mode 100644 src/node_device/node_device_udev.c
create mode 100644 src/node_device/node_device_udev.h
diff --git a/configure.in b/configure.in
index 2f9db72..25ed55f 100644
--- a/configure.in
+++ b/configure.in
@@ -1640,7 +1640,7 @@ test "$enable_shared" = no && lt_cv_objdir=.
LV_LIBTOOL_OBJDIR=${lt_cv_objdir-.}
AC_SUBST([LV_LIBTOOL_OBJDIR])
-dnl HAL or DeviceKit library for host device enumeration
+dnl HAL, DeviceKit, or libudev library for host device enumeration
HAL_REQUIRED=0.0
HAL_CFLAGS=
HAL_LIBS=
@@ -1734,8 +1734,46 @@ AM_CONDITIONAL([HAVE_DEVKIT], [test "x$with_devkit" = "xyes"])
AC_SUBST([DEVKIT_CFLAGS])
AC_SUBST([DEVKIT_LIBS])
+UDEV_REQUIRED=143
+UDEV_CFLAGS=
+UDEV_LIBS=
+AC_ARG_WITH([udev],
+ [ --with-udev use libudev for host device enumeration],
+ [],
+ [with_udev=check])
+
+if test "$with_libvirtd" = "no" ; then
+ with_udev=no
+fi
+if test "x$with_udev" = "xyes" -o "x$with_udev" = "xcheck"; then
+ PKG_CHECK_MODULES(UDEV, libudev >= $UDEV_REQUIRED,
+ [with_udev=yes], [
+ if test "x$with_udev" = "xcheck" ; then
+ with_udev=no
+ else
+ AC_MSG_ERROR(
+ [You must install udev-devel >= $UDEV_REQUIRED to compile libvirt])
+ fi
+ ])
+ if test "x$with_udev" = "xyes" ; then
+ AC_DEFINE_UNQUOTED([HAVE_UDEV], 1,
+ [use UDEV for host device enumeration])
+
+ old_CFLAGS=$CFLAGS
+ old_LDFLAGS=$LDFLAGS
+ CFLAGS="$CFLAGS $UDEV_CFLAGS"
+ LDFLAGS="$LDFLAGS $UDEV_LIBS"
+ AC_CHECK_FUNCS([udev_new],,[with_udev=no])
+ CFLAGS="$old_CFLAGS"
+ LDFLAGS="$old_LDFLAGS"
+ fi
+fi
+AM_CONDITIONAL([HAVE_UDEV], [test "x$with_udev" = "xyes"])
+AC_SUBST([UDEV_CFLAGS])
+AC_SUBST([UDEV_LIBS])
+
with_nodedev=no;
-if test "$with_devkit" = "yes" -o "$with_hal" = "yes";
+if test "$with_devkit" = "yes" -o "$with_hal" = "yes" -o "$with_udev" = "yes";
then
with_nodedev=yes
AC_DEFINE_UNQUOTED([WITH_NODE_DEVICES], 1, [with node device driver])
@@ -1900,6 +1938,11 @@ AC_MSG_NOTICE([ devkit: $DEVKIT_CFLAGS $DEVKIT_LIBS])
else
AC_MSG_NOTICE([ devkit: no])
fi
+if test "$with_udev" = "yes" ; then
+AC_MSG_NOTICE([ udev: $UDEV_CFLAGS $UDEV_LIBS])
+else
+AC_MSG_NOTICE([ udev: no])
+fi
if test "$with_netcf" = "yes" ; then
AC_MSG_NOTICE([ netcf: $NETCF_CFLAGS $NETCF_LIBS])
else
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 02bd287..d8d6c00 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -833,8 +833,7 @@ static struct qemud_server *qemudInitialize(int sigread) {
#ifdef WITH_STORAGE_DIR
storageRegister();
#endif
-#if defined(WITH_NODE_DEVICES) && \
- (defined(HAVE_HAL) || defined(HAVE_DEVKIT))
+#if defined(WITH_NODE_DEVICES)
nodedevRegister();
#endif
secretRegister();
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1a12a39..4561e55 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -17,7 +17,8 @@ src/lxc/lxc_controller.c
src/lxc/lxc_driver.c
src/network/bridge_driver.c
src/node_device/node_device_driver.c
-src/node_device/node_device_hal_linux.c
+src/node_device/node_device_linux_sysfs.c
+src/node_device/node_device_udev.c
src/nodeinfo.c
src/opennebula/one_conf.c
src/opennebula/one_driver.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 8e27ea7..11da07b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -254,16 +254,20 @@ SECURITY_DRIVER_APPARMOR_SOURCES = \
NODE_DEVICE_DRIVER_SOURCES = \
- node_device/node_device_driver.c node_device/node_device_driver.h
+ node_device/node_device_driver.c \
+ node_device/node_device_driver.h \
+ node_device/node_device_linux_sysfs.c
NODE_DEVICE_DRIVER_HAL_SOURCES = \
node_device/node_device_hal.c \
- node_device/node_device_hal.h \
- node_device/node_device_hal_linux.c
+ node_device/node_device_hal.h
NODE_DEVICE_DRIVER_DEVKIT_SOURCES = \
node_device/node_device_devkit.c
+NODE_DEVICE_DRIVER_UDEV_SOURCES = \
+ node_device/node_device_udev.c
+
#########################
#
@@ -642,6 +646,11 @@ 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 HAVE_UDEV
+libvirt_driver_nodedev_la_SOURCES += $(NODE_DEVICE_DRIVER_UDEV_SOURCES)
+libvirt_driver_nodedev_la_CFLAGS += $(UDEV_CFLAGS)
+libvirt_driver_nodedev_la_LDFLAGS += $(UDEV_LIBS)
+endif
if WITH_DRIVER_MODULES
libvirt_driver_nodedev_la_LDFLAGS += -module -avoid-version
@@ -691,6 +700,7 @@ EXTRA_DIST += \
$(NODE_DEVICE_DRIVER_SOURCES) \
$(NODE_DEVICE_DRIVER_HAL_SOURCES) \
$(NODE_DEVICE_DRIVER_DEVKIT_SOURCES) \
+ $(NODE_DEVICE_DRIVER_UDEV_SOURCES) \
$(SECURITY_DRIVER_SELINUX_SOURCES) \
$(SECURITY_DRIVER_APPARMOR_SOURCES) \
$(SECRET_DRIVER_SOURCES) \
diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c
index f33ff48..c139907 100644
--- a/src/node_device/node_device_driver.c
+++ b/src/node_device/node_device_driver.c
@@ -70,7 +70,10 @@ static int update_caps(virNodeDeviceObjPtr dev)
}
-#ifdef __linux__
+#if defined (__linux__) && defined (HAVE_HAL)
+/* Under libudev changes to the driver name should be picked up as
+ * "change" events, so we don't call update driver name unless we're
+ * using the HAL backend. */
static int update_driver_name(virConnectPtr conn,
virNodeDeviceObjPtr dev)
{
@@ -658,10 +661,10 @@ void registerCommonNodeFuncs(virDeviceMonitorPtr driver)
int nodedevRegister(void) {
-#if defined(HAVE_HAL) && defined(HAVE_DEVKIT)
+#if defined(HAVE_HAL) && defined(HAVE_UDEV)
/* Register only one of these two - they conflict */
if (halNodeRegister() == -1)
- return devkitNodeRegister();
+ return udevNodeRegister();
return 0;
#else
#ifdef HAVE_HAL
@@ -670,5 +673,8 @@ int nodedevRegister(void) {
#ifdef HAVE_DEVKIT
return devkitNodeRegister();
#endif
+#ifdef HAVE_UDEV
+ return udevNodeRegister();
+#endif
#endif
}
diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h
index db01624..5be0781 100644
--- a/src/node_device/node_device_driver.h
+++ b/src/node_device/node_device_driver.h
@@ -45,6 +45,9 @@ int halNodeRegister(void);
#ifdef HAVE_DEVKIT
int devkitNodeRegister(void);
#endif
+#ifdef HAVE_UDEV
+int udevNodeRegister(void);
+#endif
void nodeDeviceLock(virDeviceMonitorStatePtr driver);
void nodeDeviceUnlock(virDeviceMonitorStatePtr driver);
@@ -53,4 +56,23 @@ void registerCommonNodeFuncs(virDeviceMonitorPtr mon);
int nodedevRegister(void);
+#ifdef __linux__
+
+#define check_fc_host(d) check_fc_host_linux(d)
+int check_fc_host_linux(union _virNodeDevCapData *d);
+
+#define check_vport_capable(d) check_vport_capable_linux(d)
+int check_vport_capable_linux(union _virNodeDevCapData *d);
+
+#define read_wwn(host, file, wwn) read_wwn_linux(host, file, wwn)
+int read_wwn_linux(int host, const char *file, char **wwn);
+
+#else /* __linux__ */
+
+#define check_fc_host(d)
+#define check_vport_capable(d)
+#define read_wwn(host, file, wwn)
+
+#endif /* __linux__ */
+
#endif /* __VIR_NODE_DEVICE_H__ */
diff --git a/src/node_device/node_device_hal.h b/src/node_device/node_device_hal.h
index c859fe3..8ac8a35 100644
--- a/src/node_device/node_device_hal.h
+++ b/src/node_device/node_device_hal.h
@@ -22,23 +22,4 @@
#ifndef __VIR_NODE_DEVICE_HAL_H__
#define __VIR_NODE_DEVICE_HAL_H__
-#ifdef __linux__
-
-#define check_fc_host(d) check_fc_host_linux(d)
-int check_fc_host_linux(union _virNodeDevCapData *d);
-
-#define check_vport_capable(d) check_vport_capable_linux(d)
-int check_vport_capable_linux(union _virNodeDevCapData *d);
-
-#define read_wwn(host, file, wwn) read_wwn_linux(host, file, wwn)
-int read_wwn_linux(int host, const char *file, char **wwn);
-
-#else /* __linux__ */
-
-#define check_fc_host(d)
-#define check_vport_capable(d)
-#define read_wwn(host, file, wwn)
-
-#endif /* __linux__ */
-
#endif /* __VIR_NODE_DEVICE_HAL_H__ */
diff --git a/src/node_device/node_device_hal_linux.c b/src/node_device/node_device_linux_sysfs.c
similarity index 100%
rename from src/node_device/node_device_hal_linux.c
rename to src/node_device/node_device_linux_sysfs.c
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
new file mode 100644
index 0000000..10f45aa
--- /dev/null
+++ b/src/node_device/node_device_udev.c
@@ -0,0 +1,1142 @@
+/*
+ * node_device_udev.c: node device enumeration - libudev implementation
+ *
+ * Copyright (C) 2009 Red Hat
+ *
+ * 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: Dave Allan <dallan(a)redhat.com>
+ */
+
+#include <config.h>
+#include <libudev.h>
+
+#include "node_device_udev.h"
+#include "virterror_internal.h"
+#include "node_device_conf.h"
+#include "node_device_driver.h"
+#include "driver.h"
+#include "datatypes.h"
+#include "logging.h"
+#include "memory.h"
+#include "uuid.h"
+#include "util.h"
+#include "buf.h"
+#include "daemon/event.h"
+
+#define VIR_FROM_THIS VIR_FROM_NODEDEV
+
+static virDeviceMonitorStatePtr driverState = NULL;
+
+/* This function allocates memory from the heap for the property
+ * value. That memory must be later freed by some other code. */
+static int udevGetDeviceProperty(struct udev_device *udev_device,
+ const char *property_key,
+ char **property_value)
+{
+ const char *udev_value = NULL;
+ int ret = PROPERTY_FOUND;
+
+ udev_value = udev_device_get_property_value(udev_device, property_key);
+ if (udev_value == NULL) {
+ VIR_INFO(_("udev reports device '%s' does not have property '%s'"),
+ udev_device_get_sysname(udev_device), property_key);
+ ret = PROPERTY_MISSING;
+ goto out;
+ }
+
+ /* If this allocation is changed, the comment at the beginning
+ * of the function must also be changed. */
+ *property_value = strdup(udev_value);
+ if (*property_value == NULL) {
+ VIR_ERROR(_("Failed to allocate memory for "
+ "property '%s' on device '%s'"),
+ property_key, udev_device_get_sysname(udev_device));
+ virReportOOMError(NULL);
+ ret = PROPERTY_ERROR;
+ }
+
+out:
+ return ret;
+}
+
+
+static int udevGetStringProperty(struct udev_device *udev_device,
+ const char *property_key,
+ char **value)
+{
+ return udevGetDeviceProperty(udev_device, property_key, value);
+}
+
+
+static int udevGetIntProperty(struct udev_device *udev_device,
+ const char *property_key,
+ int *value,
+ int base)
+{
+ char *udev_value = NULL;
+ int ret = PROPERTY_FOUND;
+
+ ret = udevGetDeviceProperty(udev_device, property_key, &udev_value);
+
+ if (ret == PROPERTY_FOUND) {
+ if (virStrToLong_i(udev_value, NULL, base, value) != 0) {
+ ret = PROPERTY_ERROR;
+ }
+ }
+
+ VIR_FREE(udev_value);
+ return ret;
+}
+
+
+static int udevGetUintProperty(struct udev_device *udev_device,
+ const char *property_key,
+ unsigned int *value,
+ int base)
+{
+ char *udev_value = NULL;
+ int ret = PROPERTY_FOUND;
+
+ ret = udevGetDeviceProperty(udev_device, property_key, &udev_value);
+
+ if (ret == PROPERTY_FOUND) {
+ if (virStrToLong_ui(udev_value, NULL, base, value) != 0) {
+ ret = PROPERTY_ERROR;
+ }
+ }
+
+ VIR_FREE(udev_value);
+ return ret;
+}
+
+
+/* This function allocates memory from the heap for the attr value.
+ * That memory must be later freed by some other code. */
+static int udevGetStringSysfsAttr(struct udev_device *udev_device,
+ const char *attr_name,
+ char **value)
+{
+ const char *udev_value = NULL;
+ int ret = PROPERTY_FOUND;
+
+ udev_value = udev_device_get_sysattr_value(udev_device, attr_name);
+
+ if (udev_value != NULL) {
+ *value = strdup(udev_value);
+ if (*value == NULL) {
+ VIR_ERROR(_("Failed to allocate memory for "
+ "attribute '%s' on device '%s'"),
+ attr_name, udev_device_get_sysname(udev_device));
+ virReportOOMError(NULL);
+ ret = PROPERTY_ERROR;
+ }
+ } else {
+ ret = PROPERTY_MISSING;
+ }
+
+ return ret;
+}
+
+
+static int udevGetIntSysfsAttr(struct udev_device *udev_device,
+ const char *attr_name,
+ int *value,
+ int base)
+{
+ const char *udev_value = NULL;
+ int ret = PROPERTY_FOUND;
+
+ udev_value = udev_device_get_sysattr_value(udev_device, attr_name);
+
+ if (udev_value != NULL) {
+ if (virStrToLong_i(udev_value, NULL, base, value) != 0) {
+ ret = PROPERTY_ERROR;
+ }
+ } else {
+ ret = PROPERTY_MISSING;
+ }
+
+ return ret;
+}
+
+
+static int udevGetUintSysfsAttr(struct udev_device *udev_device,
+ const char *attr_name,
+ unsigned int *value,
+ int base)
+{
+ const char *udev_value = NULL;
+ int ret = PROPERTY_FOUND;
+
+ udev_value = udev_device_get_sysattr_value(udev_device, attr_name);
+
+ if (udev_value != NULL) {
+ if (virStrToLong_ui(udev_value, NULL, base, value) != 0) {
+ ret = PROPERTY_ERROR;
+ }
+ } else {
+ ret = PROPERTY_MISSING;
+ }
+
+ return ret;
+}
+
+
+static int udevGetUint64SysfsAttr(struct udev_device *udev_device,
+ const char *attr_name,
+ uint64_t *value)
+{
+ const char *udev_value = NULL;
+ int ret = PROPERTY_FOUND;
+
+ udev_value = udev_device_get_sysattr_value(udev_device, attr_name);
+
+ if (udev_value != NULL) {
+ if (virStrToLong_ull(udev_value, NULL, 0, value) != 0) {
+ ret = PROPERTY_ERROR;
+ }
+ } else {
+ ret = PROPERTY_MISSING;
+ }
+
+ return ret;
+}
+
+
+static void udevLogFunction(struct udev *udev ATTRIBUTE_UNUSED,
+ int priority ATTRIBUTE_UNUSED,
+ const char *file,
+ int line,
+ const char *fn,
+ const char *fmt,
+ va_list args)
+{
+ VIR_ERROR_INT(file, fn, line, fmt, args);
+}
+
+
+static int udevProcessPCI(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ const char *devpath = NULL;
+ union _virNodeDevCapData *data = &def->caps->data;
+ int ret = -1;
+
+ devpath = udev_device_get_devpath(device);
+
+ char *p = strrchr(devpath, '/');
+
+ if ((p == NULL) || (virStrToLong_ui(p+1,
+ &p,
+ 16,
+ &data->pci_dev.domain) == -1)) {
+ goto out;
+ }
+
+ if ((p == NULL) || (virStrToLong_ui(p+1,
+ &p,
+ 16,
+ &data->pci_dev.bus) == -1)) {
+ goto out;
+ }
+
+ if ((p == NULL) || (virStrToLong_ui(p+1,
+ &p,
+ 16,
+ &data->pci_dev.slot) == -1)) {
+ goto out;
+ }
+
+ if ((p == NULL) || (virStrToLong_ui(p+1,
+ &p,
+ 16,
+ &data->pci_dev.function) == -1)) {
+ goto out;
+ }
+
+ if (udevGetUintSysfsAttr(device,
+ "vendor",
+ &data->pci_dev.vendor,
+ 0) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ if (udevGetUintSysfsAttr(device, "product", &data->pci_dev.product, 0)
+ == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ /* FIXME: to do the vendor name and product name, we have to
+ * parse /usr/share/hwdata/pci.ids. Look in hal/hald/ids.c
+ */
+
+ ret = 0;
+
+out:
+ return ret;
+}
+
+
+static int udevProcessUSBDevice(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ union _virNodeDevCapData *data = &def->caps->data;
+ int ret = 0;
+
+ if (udevGetUintProperty(device,
+ "BUSNUM",
+ &data->usb_dev.bus,
+ 0) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ if (udevGetUintProperty(device,
+ "DEVNUM",
+ &data->usb_dev.device,
+ 0) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ if (udevGetUintProperty(device,
+ "ID_VENDOR_ID",
+ &data->usb_dev.vendor,
+ 16) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ if (udevGetStringProperty(device,
+ "ID_VENDOR",
+ &data->usb_dev.vendor_name) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ if (udevGetUintProperty(device,
+ "ID_MODEL_ID",
+ &data->usb_dev.product,
+ 0) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ if (udevGetStringProperty(device,
+ "ID_MODEL",
+ &data->usb_dev.product_name) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+
+/* XXX Is 10 the correct base for the Number/Class/SubClass/Protocol
+ * conversions? */
+static int udevProcessUSBInterface(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ int ret = 0;
+ union _virNodeDevCapData *data = &def->caps->data;
+
+ if (udevGetStringProperty(device,
+ "INTERFACE",
+ &data->usb_if.interface_name) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ if (udevGetUintSysfsAttr(device,
+ "bInterfaceNumber",
+ &data->usb_if.number,
+ 10) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ if (udevGetUintSysfsAttr(device,
+ "bInterfaceClass",
+ &data->usb_if._class,
+ 10) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ if (udevGetUintSysfsAttr(device,
+ "bInterfaceSubClass",
+ &data->usb_if.subclass,
+ 10) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ if (udevGetUintSysfsAttr(device,
+ "bInterfaceProtocol",
+ &data->usb_if.protocol,
+ 10) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ return ret;
+}
+
+
+static int udevProcessNetworkInterface(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ union _virNodeDevCapData *data = &def->caps->data;
+ int ret = 0;
+
+ if (udevGetStringSysfsAttr(device,
+ "address",
+ &data->net.address) == PROPERTY_ERROR) {
+ goto out;
+ }
+ if (udevGetUintSysfsAttr(device,
+ "addr_len",
+ &data->net.address_len,
+ 0) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+
+static int udevProcessSCSIHost(struct udev_device *device ATTRIBUTE_UNUSED,
+ virNodeDeviceDefPtr def)
+{
+ int ret = 0;
+ union _virNodeDevCapData *data = &def->caps->data;
+ char *filename = NULL;
+
+ filename = basename(def->name);
+
+ if (STRPREFIX(filename, "host")) {
+ /* XXX There's really no better way to get the host #? */
+ ret = virStrToLong_ui(filename + strlen("host"),
+ NULL,
+ 0,
+ &data->scsi_host.host);
+ check_fc_host(&def->caps->data);
+ check_vport_capable(&def->caps->data);
+ }
+
+ return ret;
+}
+
+
+static int udevProcessSCSIDevice(struct udev_device *device ATTRIBUTE_UNUSED,
+ virNodeDeviceDefPtr def)
+{
+ int ret = 0;
+ union _virNodeDevCapData *data = &def->caps->data;
+ char *filename = NULL, *p = NULL;
+
+ filename = basename(def->name);
+
+ virStrToLong_ui(filename, &p, 10, &data->scsi.host);
+ virStrToLong_ui(p+1, &p, 10, &data->scsi.bus);
+ virStrToLong_ui(p+1, &p, 10, &data->scsi.target);
+ virStrToLong_ui(p+1, &p, 10, &data->scsi.lun);
+
+ return ret;
+}
+
+
+static int udevProcessDisk(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ union _virNodeDevCapData *data = &def->caps->data;
+ int ret = 0;
+
+ data->storage.drive_type = strdup("disk");
+ if (data->storage.drive_type == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+ if (udevGetUint64SysfsAttr(device,
+ "size",
+ &data->storage.num_blocks) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ if (udevGetUint64SysfsAttr(device,
+ "queue/logical_block_size",
+ &data->storage.logical_block_size)
+ == PROPERTY_ERROR) {
+ goto out;
+ }
+
+
+ data->storage.size = data->storage.num_blocks *
+ data->storage.logical_block_size;
+
+out:
+ return ret;
+}
+
+
+static int udevProcessCDROM(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ union _virNodeDevCapData *data = &def->caps->data;
+ int tmp_int = 0, ret = 0;
+
+ if ((udevGetIntSysfsAttr(device, "removable", &tmp_int, 0) == PROPERTY_FOUND) &&
+ (tmp_int == 1)) {
+ def->caps->data.storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE;
+ }
+
+ if ((udevGetIntProperty(device, "ID_CDROM_MEDIA", &tmp_int, 0)
+ == PROPERTY_FOUND) && (tmp_int == 1)) {
+
+ def->caps->data.storage.flags |=
+ VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE;
+
+ if (udevGetUint64SysfsAttr(device,
+ "size",
+ &data->storage.num_blocks) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ if (udevGetUint64SysfsAttr(device,
+ "queue/logical_block_size",
+ &data->storage.logical_block_size) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ /* XXX This calculation is wrong for the qemu virtual cdrom
+ * which reports the size in 512 byte blocks, but the logical
+ * block size as 2048. I don't have a physical cdrom on a
+ * devel system to see how they behave. */
+ def->caps->data.storage.removable_media_size =
+ def->caps->data.storage.num_blocks *
+ def->caps->data.storage.logical_block_size;
+ }
+
+out:
+ return ret;
+}
+
+
+/* This function exists to deal with the case in which a driver does
+ * not provide a device type in the usual place, but udev told us it's
+ * a storage device, and we can make a good guess at what kind of
+ * storage device it is from other information that is provided. */
+static int udevKludgeStorageType(virNodeDeviceDefPtr def)
+{
+ int ret = -1;
+
+ if (STRPREFIX(def->caps->data.storage.block, "/dev/vd")) {
+ /* virtio disk */
+ def->caps->data.storage.drive_type = strdup("disk");
+ if (def->caps->data.storage.drive_type != NULL) {
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+
+static void udevStripSpaces(char *s)
+{
+ if (s == NULL) {
+ return;
+ }
+
+ while (virFileStripSuffix(s, " ")) {
+ /* do nothing */
+ ;
+ }
+
+ return;
+}
+
+
+static int udevProcessStorage(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ union _virNodeDevCapData *data = &def->caps->data;
+ int ret = -1;
+
+ data->storage.block = strdup(udev_device_get_devnode(device));
+ if (udevGetStringProperty(device,
+ "DEVNAME",
+ &data->storage.block) == PROPERTY_ERROR) {
+ goto out;
+ }
+ if (udevGetStringProperty(device,
+ "ID_BUS",
+ &data->storage.bus) == PROPERTY_ERROR) {
+ goto out;
+ }
+ if (udevGetStringProperty(device,
+ "ID_SERIAL",
+ &data->storage.serial) == PROPERTY_ERROR) {
+ goto out;
+ }
+ if (udevGetStringSysfsAttr(device,
+ "device/vendor",
+ &data->storage.vendor) == PROPERTY_ERROR) {
+ goto out;
+ }
+ udevStripSpaces(def->caps->data.storage.vendor);
+ if (udevGetStringSysfsAttr(device,
+ "device/model",
+ &data->storage.model) == PROPERTY_ERROR) {
+ goto out;
+ }
+ udevStripSpaces(def->caps->data.storage.model);
+ /* There is no equivalent of the hotpluggable property in libudev,
+ * but storage is going toward a world in which hotpluggable is
+ * expected, so I don't see a problem with not having a property
+ * for it. */
+
+ if (udevGetStringProperty(device,
+ "ID_TYPE",
+ &data->storage.drive_type) != 0) {
+ /* If udev doesn't have it, perhaps we can guess it. */
+ if (udevKludgeStorageType(def) != 0) {
+ goto out;
+ }
+ }
+
+ /* NB: drive_type has changed from HAL; now it's "cd" instead of "cdrom" */
+ if (STREQ(def->caps->data.storage.drive_type, "cd")) {
+ ret = udevProcessCDROM(device, def);
+ } else if (STREQ(def->caps->data.storage.drive_type, "disk")) {
+ ret = udevProcessDisk(device, def);
+ } else {
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+
+static int udevSetDeviceType(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ union _virNodeDevCapData *data = NULL;
+ const char *devtype = NULL;
+ int ret = 0;
+
+ if (VIR_ALLOC(def->caps) != 0) {
+ ret = -1;
+ goto out;
+ }
+
+ data = &def->caps->data;
+
+ devtype = udev_device_get_devtype(device);
+
+ if (udevGetUintProperty(device,
+ "PCI_CLASS",
+ &data->pci_dev.class,
+ 0) == PROPERTY_FOUND) {
+ def->caps->type = VIR_NODE_DEV_CAP_PCI_DEV;
+ goto out;
+ }
+
+ if (devtype != NULL && STREQ(devtype, "usb_device")) {
+ def->caps->type = VIR_NODE_DEV_CAP_USB_DEV;
+ goto out;
+ }
+
+ if (devtype != NULL && STREQ(devtype, "usb_interface")) {
+ def->caps->type = VIR_NODE_DEV_CAP_USB_INTERFACE;
+ goto out;
+ }
+
+ /* XXX Do some network interfaces set the device type property? */
+ if (udevGetStringProperty(device,
+ "INTERFACE",
+ &data->net.ifname) == PROPERTY_FOUND) {
+ def->caps->type = VIR_NODE_DEV_CAP_NET;
+ goto out;
+ }
+
+ if (devtype != NULL && STREQ(devtype, "scsi_host")) {
+ def->caps->type = VIR_NODE_DEV_CAP_SCSI_HOST;
+ goto out;
+ }
+
+ if (devtype != NULL && STREQ(devtype, "scsi_device")) {
+ def->caps->type = VIR_NODE_DEV_CAP_SCSI;
+ goto out;
+ }
+
+ if (devtype != NULL && STREQ(devtype, "disk")) {
+ def->caps->type = VIR_NODE_DEV_CAP_STORAGE;
+ goto out;
+ }
+
+ ret = -1;
+
+out:
+ return ret;
+}
+
+
+static int udevGetDeviceDetails(struct udev_device *device,
+ virNodeDeviceDefPtr def)
+{
+ int ret = 0;
+
+ switch (def->caps->type) {
+ case VIR_NODE_DEV_CAP_SYSTEM:
+ /* There's no libudev equivalent of system, so ignore it. */
+ break;
+ case VIR_NODE_DEV_CAP_PCI_DEV:
+ ret = udevProcessPCI(device, def);
+ break;
+ case VIR_NODE_DEV_CAP_USB_DEV:
+ ret = udevProcessUSBDevice(device, def);
+ break;
+ case VIR_NODE_DEV_CAP_USB_INTERFACE:
+ ret = udevProcessUSBInterface(device, def);
+ break;
+ case VIR_NODE_DEV_CAP_NET:
+ ret = udevProcessNetworkInterface(device, def);
+ break;
+ case VIR_NODE_DEV_CAP_SCSI_HOST:
+ ret = udevProcessSCSIHost(device, def);
+ break;
+ case VIR_NODE_DEV_CAP_SCSI:
+ ret = udevProcessSCSIDevice(device, def);
+ break;
+ case VIR_NODE_DEV_CAP_STORAGE:
+ ret = udevProcessStorage(device, def);
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+
+static int udevRemoveOneDevice(struct udev_device *device)
+{
+ virNodeDeviceObjPtr dev = NULL;
+ const char *name = NULL;
+ int ret = 0;
+
+ name = udev_device_get_syspath(device);
+
+ dev = virNodeDeviceFindByName(&driverState->devs, name);
+ if (dev != NULL) {
+ virNodeDeviceObjRemove(&driverState->devs, dev);
+ } else {
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int udevAddOneDevice(struct udev_device *device)
+{
+ virNodeDeviceDefPtr def = NULL;
+ struct udev_device *parent = NULL;
+ virNodeDeviceObjPtr dev = NULL;
+ const char *parent_name = NULL;
+ int ret = -1;
+
+ if (VIR_ALLOC(def) != 0) {
+ goto out;
+ }
+
+ def->name = strdup(udev_device_get_syspath(device));
+ if (udevGetStringProperty(device,
+ "DRIVER",
+ &def->driver) == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ parent = udev_device_get_parent(device);
+ if (parent != NULL) {
+ parent_name = udev_device_get_syspath(parent);
+ if (parent_name != NULL) {
+ def->parent = strdup(parent_name);
+ }
+ }
+
+ if (udevSetDeviceType(device, def) == 0) {
+ ret = udevGetDeviceDetails(device, def);
+ }
+
+ if (ret == 0) {
+ dev = virNodeDeviceAssignDef(NULL, &driverState->devs, def);
+ dev->devicePath = strdup(udev_device_get_devpath(device));
+ virNodeDeviceObjUnlock(dev);
+ } else {
+ virNodeDeviceDefFree(def);
+ }
+
+out:
+ return ret;
+}
+
+
+static int udevProcessDeviceListEntry(struct udev *udev,
+ struct udev_list_entry *list_entry)
+{
+ struct udev_device *device;
+ const char *name = NULL;
+ int ret = -1;
+
+ name = udev_list_entry_get_name(list_entry);
+
+ device = udev_device_new_from_syspath(udev, name);
+ if (device != NULL) {
+ udevAddOneDevice(device);
+ udev_device_unref(device);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+
+static int udevEnumerateDevices(struct udev *udev)
+{
+ struct udev_enumerate *udev_enumerate = NULL;
+ struct udev_list_entry *list_entry = NULL;
+ const char *name = NULL;
+ int ret = 0;
+
+ udev_enumerate = udev_enumerate_new(udev);
+
+ ret = udev_enumerate_scan_devices(udev_enumerate);
+ if (0 != ret) {
+ VIR_ERROR("udev scan devices returned %d\n", ret);
+ goto out;
+ }
+
+ udev_list_entry_foreach(list_entry,
+ udev_enumerate_get_list_entry(udev_enumerate)) {
+
+ udevProcessDeviceListEntry(udev, list_entry);
+ name = udev_list_entry_get_name(list_entry);
+ }
+
+out:
+ udev_enumerate_unref(udev_enumerate);
+ return ret;
+}
+
+
+static int udevDeviceMonitorShutdown(void)
+{
+ int ret = 0;
+
+ struct udev_monitor *udev_monitor = NULL;
+ struct udev *udev = NULL;
+
+ if (driverState) {
+
+ nodeDeviceLock(driverState);
+ udev_monitor = DRV_STATE_UDEV_MONITOR(driverState);
+
+ if (udev_monitor != NULL) {
+ udev = udev_monitor_get_udev(udev_monitor);
+ udev_monitor_unref(udev_monitor);
+ }
+
+ if (udev != NULL) {
+ udev_unref(udev);
+ }
+
+ virNodeDeviceObjListFree(&driverState->devs);
+ nodeDeviceUnlock(driverState);
+ virMutexDestroy(&driverState->lock);
+ VIR_FREE(driverState);
+
+ } else {
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static void udevEventHandleCallback(int watch ATTRIBUTE_UNUSED,
+ int fd,
+ int events ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED)
+{
+ struct udev_device *device = NULL;
+ struct udev_monitor *udev_monitor = DRV_STATE_UDEV_MONITOR(driverState);
+ const char *action = NULL;
+
+ if (fd != udev_monitor_get_fd(udev_monitor)) {
+ goto out;
+ }
+
+ device = udev_monitor_receive_device(udev_monitor);
+ if (device == NULL) {
+ goto out;
+ }
+
+ action = udev_device_get_action(device);
+
+ if (STREQ(action, "add") || STREQ(action, "change")) {
+ udevAddOneDevice(device);
+ goto out;
+ }
+
+ if (STREQ(action, "remove")) {
+ udevRemoveOneDevice(device);
+ goto out;
+ }
+
+out:
+ return;
+}
+
+
+static int udevSetupSystemDev(void)
+{
+ virNodeDeviceDefPtr def = NULL;
+ virNodeDeviceObjPtr dev = NULL;
+ struct udev *udev = NULL;
+ struct udev_device *device = NULL;
+ union _virNodeDevCapData *data = NULL;
+ char *tmp = NULL;
+ int ret = -1;
+
+ if (VIR_ALLOC(def) != 0) {
+ goto out;
+ }
+
+ def->name = strdup("computer");
+ if (def->name == NULL) {
+ goto out;
+ }
+
+ if (VIR_ALLOC(def->caps) != 0) {
+ goto out;
+ }
+
+ udev = udev_monitor_get_udev(DRV_STATE_UDEV_MONITOR(driverState));
+ device = udev_device_new_from_syspath(udev, DMI_DEVPATH);
+ if (device == NULL) {
+ goto out;
+ }
+
+ data = &def->caps->data;
+
+ data->system.dmi_devpath = strdup(DMI_DEVPATH);
+ data->system.description = strdup(SYSTEM_DESCRIPTION);
+
+ if (udevGetStringSysfsAttr(device,
+ "product_name",
+ &data->system.product_name) == PROPERTY_ERROR) {
+ goto out;
+ }
+ if (udevGetStringSysfsAttr(device,
+ "sys_vendor",
+ &data->system.hardware.vendor_name)
+ == PROPERTY_ERROR) {
+ goto out;
+ }
+ if (udevGetStringSysfsAttr(device,
+ "product_version",
+ &data->system.hardware.version)
+ == PROPERTY_ERROR) {
+ goto out;
+ }
+ if (udevGetStringSysfsAttr(device,
+ "product_serial",
+ &data->system.hardware.serial)
+ == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ if (udevGetStringSysfsAttr(device,
+ "product_uuid",
+ &tmp) == PROPERTY_ERROR) {
+ goto out;
+ }
+ virUUIDParse(tmp, def->caps->data.system.hardware.uuid);
+ VIR_FREE(tmp);
+
+ if (udevGetStringSysfsAttr(device,
+ "bios_vendor",
+ &data->system.firmware.vendor_name)
+ == PROPERTY_ERROR) {
+ goto out;
+ }
+ if (udevGetStringSysfsAttr(device,
+ "bios_version",
+ &data->system.firmware.version)
+ == PROPERTY_ERROR) {
+ goto out;
+ }
+ if (udevGetStringSysfsAttr(device,
+ "bios_date",
+ &data->system.firmware.release_date)
+ == PROPERTY_ERROR) {
+ goto out;
+ }
+
+ udev_device_unref(device);
+
+ dev = virNodeDeviceAssignDef(NULL, &driverState->devs, def);
+ virNodeDeviceObjUnlock(dev);
+
+ ret = 0;
+
+out:
+ return ret;
+}
+
+static int udevDeviceMonitorStartup(int privileged ATTRIBUTE_UNUSED)
+{
+ struct udev *udev = NULL;
+ struct udev_monitor *udev_monitor = NULL;
+ int ret = 0;
+
+ if (VIR_ALLOC(driverState) < 0) {
+ ret = -1;
+ goto out;
+ }
+
+ if (virMutexInit(&driverState->lock) < 0) {
+ VIR_FREE(driverState);
+ ret = -1;
+ goto out;
+ }
+
+ nodeDeviceLock(driverState);
+
+ /*
+ * http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/libudev-udev.h…
+ *
+ * indicates no return value other than success, so we don't check
+ * its return value.
+ */
+ udev = udev_new();
+ udev_set_log_fn(udev, udevLogFunction);
+
+ udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
+ if (udev_monitor == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+ udev_monitor_enable_receiving(udev_monitor);
+
+ /* udev can be retrieved from udev_monitor */
+ driverState->privateData = udev_monitor;
+ nodeDeviceUnlock(driverState);
+
+ /* We register the monitor with the event callback so we are
+ * notified by udev of device changes before we enumerate existing
+ * devices because libvirt will simply recreate the device if we
+ * try to register it twice, i.e., if the device appears between
+ * the time we register the callback and the time we begin
+ * enumeration. The alternative is to register the callback after
+ * we enumerate, in which case we will fail to create any devices
+ * that appear while the enumeration is taking place. */
+ if (virEventAddHandleImpl(udev_monitor_get_fd(udev_monitor),
+ VIR_EVENT_HANDLE_READABLE,
+ udevEventHandleCallback,
+ NULL, NULL) == -1) {
+ ret = -1;
+ goto out;
+ }
+
+ /* Create a fictional 'computer' device to root the device tree. */
+ if (udevSetupSystemDev() != 0) {
+ ret = -1;
+ goto out;
+ }
+
+ /* Populate with known devices */
+
+ if (udevEnumerateDevices(udev) != 0) {
+ ret = -1;
+ goto out;
+ }
+
+out:
+ if (ret == -1) {
+ udevDeviceMonitorShutdown();
+ }
+ return ret;
+}
+
+
+static int udevDeviceMonitorReload(void)
+{
+ return 0;
+}
+
+
+static int udevDeviceMonitorActive(void)
+{
+ /* Always ready to deal with a shutdown */
+ return 0;
+}
+
+
+static virDrvOpenStatus udevNodeDrvOpen(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 udevNodeDrvClose(virConnectPtr conn)
+{
+ conn->devMonPrivateData = NULL;
+ return 0;
+}
+
+static virDeviceMonitor udevDeviceMonitor = {
+ .name = "udevDeviceMonitor",
+ .open = udevNodeDrvOpen,
+ .close = udevNodeDrvClose,
+};
+
+static virStateDriver udevStateDriver = {
+ .initialize = udevDeviceMonitorStartup,
+ .cleanup = udevDeviceMonitorShutdown,
+ .reload = udevDeviceMonitorReload,
+ .active = udevDeviceMonitorActive,
+};
+
+int udevNodeRegister(void)
+{
+ VIR_ERROR0("Registering udev node device backend\n");
+
+ registerCommonNodeFuncs(&udevDeviceMonitor);
+ if (virRegisterDeviceMonitor(&udevDeviceMonitor) < 0) {
+ return -1;
+ }
+
+ return virRegisterStateDriver(&udevStateDriver);
+}
diff --git a/src/node_device/node_device_udev.h b/src/node_device/node_device_udev.h
new file mode 100644
index 0000000..d950106
--- /dev/null
+++ b/src/node_device/node_device_udev.h
@@ -0,0 +1,32 @@
+/*
+ * node_device_udev.h: node device enumeration - libudev implementation
+ *
+ * Copyright (C) 2009 Red Hat
+ *
+ * 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: Dave Allan <dallan(a)redhat.com>
+ */
+
+#include <libudev.h>
+#include <stdint.h>
+
+#define SYSFS_DATA_SIZE 4096
+#define DRV_STATE_UDEV_MONITOR(ds) ((struct udev_monitor *)((ds)->privateData))
+#define DMI_DEVPATH "/sys/devices/virtual/dmi/id"
+#define SYSTEM_DESCRIPTION "fictional device to root the node device tree"
+#define PROPERTY_FOUND 0
+#define PROPERTY_MISSING 1
+#define PROPERTY_ERROR -1
diff --git a/src/util/util.c b/src/util/util.c
index 98f8a14..f63bd39 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -2114,3 +2114,31 @@ void virFileWaitForDevices(virConnectPtr conn)
void virFileWaitForDevices(virConnectPtr conn ATTRIBUTE_UNUSED) {}
#endif
#endif
+
+int virBuildPathInternal(char **path, ...)
+{
+ char *path_component = NULL;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ va_list ap;
+ int ret = 0;
+
+ va_start(ap, *path);
+
+ path_component = va_arg(ap, char *);
+ virBufferAdd(&buf, path_component, -1);
+
+ while ((path_component = va_arg(ap, char *)) != NULL)
+ {
+ virBufferAddChar(&buf, '/');
+ virBufferAdd(&buf, path_component, -1);
+ }
+
+ va_end(ap);
+
+ *path = virBufferContentAndReset(&buf);
+ if (*path == NULL) {
+ ret = -1;
+ }
+
+ return ret;
+}
diff --git a/src/util/util.h b/src/util/util.h
index 8679636..da410e1 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -248,4 +248,7 @@ char *virFileFindMountPoint(const char *type);
void virFileWaitForDevices(virConnectPtr conn);
+#define virBuildPath(path, ...) virBuildPathInternal(path, __VA_ARGS__, NULL)
+int virBuildPathInternal(char **path, ...) __attribute__ ((sentinel));
+
#endif /* __VIR_UTIL_H__ */
diff --git a/tools/virsh.c b/tools/virsh.c
index 6b93405..19a2eb1 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -5790,9 +5790,17 @@ cmdNodeListDevices (vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
char **parents = vshMalloc(ctl, sizeof(char *) * num_devices);
for (i = 0; i < num_devices; i++) {
virNodeDevicePtr dev = virNodeDeviceLookupByName(ctl->conn, devices[i]);
+ virNodeDevicePtr parent_dev = NULL;
+
if (dev && STRNEQ(devices[i], "computer")) {
const char *parent = virNodeDeviceGetParent(dev);
- parents[i] = parent ? strdup(parent) : NULL;
+ parent_dev = virNodeDeviceLookupByName(ctl->conn, parent);
+ if (parent_dev) {
+ parents[i] = strdup(parent);
+ } else {
+ parents[i] = strdup("computer");
+ }
+ virNodeDeviceFree(parent_dev);
} else {
parents[i] = NULL;
}
--
1.6.4.4
>From cc3644b71d042ff394c9540a9f364752484f63a8 Mon Sep 17 00:00:00 2001
From: David Allan <dallan(a)redhat.com>
Date: Fri, 16 Oct 2009 14:36:07 -0400
Subject: [PATCH 3/3] Remove DevKit node device backend
---
configure.in | 61 +-----
src/Makefile.am | 9 -
src/node_device/node_device_devkit.c | 446 ----------------------------------
src/node_device/node_device_driver.c | 3 -
src/node_device/node_device_driver.h | 3 -
5 files changed, 1 insertions(+), 521 deletions(-)
delete mode 100644 src/node_device/node_device_devkit.c
diff --git a/configure.in b/configure.in
index 25ed55f..3d05d9b 100644
--- a/configure.in
+++ b/configure.in
@@ -1680,60 +1680,6 @@ 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])
-
UDEV_REQUIRED=143
UDEV_CFLAGS=
UDEV_LIBS=
@@ -1773,7 +1719,7 @@ AC_SUBST([UDEV_CFLAGS])
AC_SUBST([UDEV_LIBS])
with_nodedev=no;
-if test "$with_devkit" = "yes" -o "$with_hal" = "yes" -o "$with_udev" = "yes";
+if test "$with_hal" = "yes" -o "$with_udev" = "yes";
then
with_nodedev=yes
AC_DEFINE_UNQUOTED([WITH_NODE_DEVICES], 1, [with node device driver])
@@ -1933,11 +1879,6 @@ 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
if test "$with_udev" = "yes" ; then
AC_MSG_NOTICE([ udev: $UDEV_CFLAGS $UDEV_LIBS])
else
diff --git a/src/Makefile.am b/src/Makefile.am
index 11da07b..cd05c28 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -262,9 +262,6 @@ NODE_DEVICE_DRIVER_HAL_SOURCES = \
node_device/node_device_hal.c \
node_device/node_device_hal.h
-NODE_DEVICE_DRIVER_DEVKIT_SOURCES = \
- node_device/node_device_devkit.c
-
NODE_DEVICE_DRIVER_UDEV_SOURCES = \
node_device/node_device_udev.c
@@ -641,11 +638,6 @@ 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 HAVE_UDEV
libvirt_driver_nodedev_la_SOURCES += $(NODE_DEVICE_DRIVER_UDEV_SOURCES)
libvirt_driver_nodedev_la_CFLAGS += $(UDEV_CFLAGS)
@@ -699,7 +691,6 @@ EXTRA_DIST += \
$(STORAGE_DRIVER_DISK_SOURCES) \
$(NODE_DEVICE_DRIVER_SOURCES) \
$(NODE_DEVICE_DRIVER_HAL_SOURCES) \
- $(NODE_DEVICE_DRIVER_DEVKIT_SOURCES) \
$(NODE_DEVICE_DRIVER_UDEV_SOURCES) \
$(SECURITY_DRIVER_SELINUX_SOURCES) \
$(SECURITY_DRIVER_APPARMOR_SOURCES) \
diff --git a/src/node_device/node_device_devkit.c b/src/node_device/node_device_devkit.c
deleted file mode 100644
index a6c7941..0000000
--- a/src/node_device/node_device_devkit.c
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * 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(a)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 "logging.h"
-
-#include "node_device.h"
-
-/*
- * Host device enumeration (DeviceKit implementation)
- */
-
-static virDeviceMonitorStatePtr driverState;
-
-#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 *ifname;
-
- if (sysfs_path == NULL)
- return -1;
- ifname = strrchr(sysfs_path, '/');
- if (!ifname || !*ifname || !*(++ifname))
- return -1;
- if ((d->net.ifname = strdup(ifname)) == NULL)
- return -1;
-
- d->net.subtype = VIR_NODE_DEV_CAP_NET_LAST;
-
- return 0;
-}
-
-
-static int gather_storage_cap(DevkitDevice *dkdev,
- union _virNodeDevCapData *d)
-{
- const char *device = devkit_device_get_device_file(dkdev);
-
- if (device && ((d->storage.block = 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_STORAGE, gather_storage_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;
- virNodeDeviceDefPtr def = 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(def) < 0)
- goto failure;
-
- if ((def->name = strdup(name)) == NULL)
- goto failure;
-
- // TODO: Find device parent, if any
-
- rv = gather_capabilities(dkdev, &def->caps);
- if (rv != 0) goto failure;
-
- nodeDeviceLock(driverState);
- dev = virNodeDeviceAssignDef(NULL,
- &driverState->devs,
- def);
-
- if (!dev) {
- nodeDeviceUnlock(driverState);
- goto failure;
- }
-
- dev->privateData = dkdev;
- dev->privateFree = NULL; /* XXX some free func needed ? */
- virNodeDeviceObjUnlock(dev);
-
- nodeDeviceUnlock(driverState);
-
- return;
-
- failure:
- DEBUG("FAILED TO ADD dev %s", name);
- if (def)
- virNodeDeviceDefFree(def);
-}
-
-
-static int devkitDeviceMonitorStartup(int privileged ATTRIBUTE_UNUSED)
-{
- 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;
-
- if (virMutexInit(&driverState->lock) < 0) {
- VIR_FREE(driverState);
- return -1;
- }
-
- 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;
-
- nodeDeviceLock(driverState);
- devkit_client = DRV_STATE_DKCLIENT(driverState);
- virNodeDeviceObjListFree(&driverState->devs);
- if (devkit_client)
- g_object_unref(devkit_client);
- nodeDeviceUnlock(driverState);
- virMutexDestroy(&driveState->lock);
- VIR_FREE(driverState);
- return 0;
- }
- return -1;
-}
-
-
-static int devkitDeviceMonitorReload(void)
-{
- /* XXX This isn't thread safe because its free'ing the thing
- * we're locking */
- (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);
-}
diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c
index c139907..cddd994 100644
--- a/src/node_device/node_device_driver.c
+++ b/src/node_device/node_device_driver.c
@@ -670,9 +670,6 @@ int nodedevRegister(void) {
#ifdef HAVE_HAL
return halNodeRegister();
#endif
-#ifdef HAVE_DEVKIT
- return devkitNodeRegister();
-#endif
#ifdef HAVE_UDEV
return udevNodeRegister();
#endif
diff --git a/src/node_device/node_device_driver.h b/src/node_device/node_device_driver.h
index 5be0781..4f0822c 100644
--- a/src/node_device/node_device_driver.h
+++ b/src/node_device/node_device_driver.h
@@ -42,9 +42,6 @@
#ifdef HAVE_HAL
int halNodeRegister(void);
#endif
-#ifdef HAVE_DEVKIT
-int devkitNodeRegister(void);
-#endif
#ifdef HAVE_UDEV
int udevNodeRegister(void);
#endif
--
1.6.4.4
5
12
[libvirt] [PATCH] Remove capng_lock() call when spawning LXC container init process
by Daniel P. Berrange 13 Nov '09
by Daniel P. Berrange 13 Nov '09
13 Nov '09
The capng_lock() call sets the SECURE_NO_SETUID_FIXUP and SECURE_NOROOT
bits on the process. This prevents the kernel granting capabilities to
processes with an effective UID of 0, or with setuid programs. This is
not actually what we want in the container init process. It should be
allowed to run setuid processes & keep capabilities when root. All that
is required is masking a handful of dangerous capabilities from the
bounding set.
* src/lxc/lxc_container.c: Remove bogus capng_lock() call.
---
src/lxc/lxc_container.c | 11 +++++------
1 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index c77d099..023d553 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -694,12 +694,11 @@ static int lxcContainerDropCapabilities(void)
return -1;
}
- /* Need to prevent them regaining any caps on exec */
- if ((ret = capng_lock()) < 0) {
- lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
- _("Failed to lock capabilities: %d"), ret);
- return -1;
- }
+ /* We do not need to call capng_lock() in this case. The bounding
+ * set restriction will prevent them reacquiring sys_boot/module/time,
+ * etc which is all that matters for the container. Once inside the
+ * container it is fine for SECURE_NOROOT / SECURE_NO_SETUID_FIXUP to
+ * be unmasked - they can never escape the bounding set. */
#else
VIR_WARN0(_("libcap-ng support not compiled in, unable to clear capabilities"));
--
1.6.2.5
2
1
Hi,
I have a question about interface script (e.g., qemu-ifup) for qemu/kvm.
qemu/kvm is dropped its all capabilities by libcap-ng before executed.
So the script that is executed by qemu/kvm will fail if it executes
privileged operations which are usual jobs of it.
It means we cannot use <script> anymore? or I'm missing something?
I think executing the script in libvirtd after creating a tap and before
dropping capabilities would be a solution for that issue. Am I wrong?
Thanks,
ozaki-r
2
2
Hi all,
The attached patch adds a new API call for retrieving the libvirt
version used by a connection: virConnectGetLibvirtVersion. Without this,
there is currently no way to determine the libvirt version of a remote
qemu connection for example. This info can be useful for feature
detection/enabling/disabling.
As an example, virt-install may want to use the AC97 sound device as
the default sound model for new VMs. However, this was only added to
libvirt's white list in 0.6.0, while the other models have been
available since 0.4.3. If installing a remote guest, virt-install will
want to ensure that the remote libvirtd is >= 0.6.0. Granted, the remote
version could have backported the AC97 patch and virt-install would be
incorrect, but better to be overly restrictive than to blindly specify
AC97 and have guest creation bomb out.
The 'correct' way to handle the above issue would be some combination of
dropping internal whitelists from libvirt and generating them from info
reported by the hypervisor, and advertising the available values in the
capabilities XML. However I think this API addition makes things more
manageable with little downside until a proper solution is implemented.
Thanks,
Cole
3
4
12 Nov '09
>>>import libvirt
>>>con=libvirt.open('xen:///')
>> libvirt.getVersion()
7002
>>>dom=con.defineXML('<domain type="xen"><name>rtiago_test2</name><clock offset="utc"/><vcpu>8</vcpu><on_poweroff>restart</on_poweroff><devices><disk device="disk" type="file"><source file="/images/SLC-4-x86.img"/><driver name="file"/><target bus="xen" dev="xvda1"/></disk><console tty="/dev/pts/2" type="pty"><source path="/dev/pts/2"/><target port="0"/></console></devices><on_crash>restart</on_crash><currentMemory>300000</currentMemory><memory>300000</memory><on_reboot>restart</on_reboot><os><kernel>/root/vmlinuz</kernel><initrd>/root/initrd.img</initrd><type>linux</type><root>/dev/xvda1 ro</root><cmdline>rtiago</cmdline></os></domain>')
>>> dom.create()
>>>0
>>> dom.destroy()
>>> 0
>>> dom.create()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/usr/lib64/python2.4/site-packages/libvirt.py", line 287, in create
if ret == -1: raise libvirtError ('virDomainCreate() failed', dom=self)
libvirt.libvirtError: Unknown failure
Every call to create will raise the same exception, It only works if I do a new connection to the
hypervisor. Is there an workaround??
2
1
Normally, when you migrate a domain from host A to host B,
the domain on host A remains defined but shutoff and the domain
on host B remains running but is a "transient". Add a new
flag to virDomainMigrate() to allow the original domain to be
undefined on source host A, and a new flag to virDomainMigrate() to
allow the new domain to be persisted on the destination host B.
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
include/libvirt/libvirt.h.in | 2 ++
src/libvirt.c | 4 ++++
src/qemu/qemu_driver.c | 34 ++++++++++++++++++++++++++++++++--
tools/virsh.c | 8 ++++++++
4 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index f51a565..6186d4e 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -339,6 +339,8 @@ typedef enum {
VIR_MIGRATE_LIVE = (1 << 0), /* live migration */
VIR_MIGRATE_PEER2PEER = (1 << 1), /* direct source -> dest host control channel */
VIR_MIGRATE_TUNNELLED = (1 << 2), /* tunnel migration data over libvirtd connection */
+ VIR_MIGRATE_PERSIST_DEST = (1 << 3), /* persist the VM on the destination */
+ VIR_MIGRATE_UNDEFINE_SOURCE = (1 << 4), /* undefine the VM on the source */
} virDomainMigrateFlags;
/* Domain migration. */
diff --git a/src/libvirt.c b/src/libvirt.c
index b14942d..92a1eaa 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -3128,6 +3128,10 @@ virDomainMigrateDirect (virDomainPtr domain,
* VIR_MIGRATE_LIVE Do not pause the VM during migration
* VIR_MIGRATE_PEER2PEER Direct connection between source & destination hosts
* VIR_MIGRATE_TUNNELLED Tunnel migration data over the libvirt RPC channel
+ * VIR_MIGRATE_PERSIST_DEST If the migration is successful, persist the domain
+ * on the destination host.
+ * VIR_MIGRATE_UNDEFINE_SOURCE If the migration is successful, undefine the
+ * domain on the source host.
*
* VIR_MIGRATE_TUNNELLED requires that VIR_MIGRATE_PEER2PEER be set.
* Applications using the VIR_MIGRATE_PEER2PEER flag will probably
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 3812f91..ba5694e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6848,7 +6848,8 @@ qemudDomainMigratePerform (virDomainPtr dom,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
- if (!vm->persistent) {
+ if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) {
+ virDomainDeleteConfig(dom->conn, driver->configDir, driver->autostartDir, vm);
virDomainRemoveInactive(&driver->domains, vm);
vm = NULL;
}
@@ -6886,13 +6887,14 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn,
const char *cookie ATTRIBUTE_UNUSED,
int cookielen ATTRIBUTE_UNUSED,
const char *uri ATTRIBUTE_UNUSED,
- unsigned long flags ATTRIBUTE_UNUSED,
+ unsigned long flags,
int retcode)
{
struct qemud_driver *driver = dconn->privateData;
virDomainObjPtr vm;
virDomainPtr dom = NULL;
virDomainEventPtr event = NULL;
+ int newVM = 1;
qemuDriverLock(driver);
vm = virDomainFindByName(&driver->domains, dname);
@@ -6906,6 +6908,34 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn,
* object, but if no, clean up the empty qemu process.
*/
if (retcode == 0) {
+ if (flags & VIR_MIGRATE_PERSIST_DEST) {
+ if (vm->persistent)
+ newVM = 0;
+ vm->persistent = 1;
+
+ if (virDomainSaveConfig(dconn, driver->configDir, vm->def) < 0) {
+ /* Hmpf. Migration was successful, but making it persistent
+ * was not. If we report successful, then when this domain
+ * shuts down, management tools are in for a surprise. On the
+ * other hand, if we report failure, then the management tools
+ * might try to restart the domain on the source side, even
+ * though the domain is actually running on the destination.
+ * Return a NULL dom pointer, and hope that this is a rare
+ * situation and management tools are smart.
+ */
+ vm = NULL;
+ goto cleanup;
+ }
+
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_DEFINED,
+ newVM ?
+ VIR_DOMAIN_EVENT_DEFINED_ADDED :
+ VIR_DOMAIN_EVENT_DEFINED_UPDATED);
+ if (event)
+ qemuDomainEventQueue(driver, event);
+
+ }
dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
/* run 'cont' on the destination, which allows migration on qemu
diff --git a/tools/virsh.c b/tools/virsh.c
index 46c5454..47122d5 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -2465,6 +2465,8 @@ static const vshCmdOptDef opts_migrate[] = {
{"p2p", VSH_OT_BOOL, 0, gettext_noop("peer-2-peer migration")},
{"direct", VSH_OT_BOOL, 0, gettext_noop("direct migration")},
{"tunnelled", VSH_OT_BOOL, 0, gettext_noop("tunnelled migration")},
+ {"persistent", VSH_OT_BOOL, 0, gettext_noop("persist VM on destination")},
+ {"undefinesource", VSH_OT_BOOL, 0, gettext_noop("undefine VM on source")},
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")},
{"desturi", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("connection URI of the destination host")},
{"migrateuri", VSH_OT_DATA, 0, gettext_noop("migration URI, usually can be omitted")},
@@ -2504,6 +2506,12 @@ cmdMigrate (vshControl *ctl, const vshCmd *cmd)
if (vshCommandOptBool (cmd, "tunnelled"))
flags |= VIR_MIGRATE_TUNNELLED;
+ if (vshCommandOptBool (cmd, "persistent"))
+ flags |= VIR_MIGRATE_PERSIST_DEST;
+
+ if (vshCommandOptBool (cmd, "undefinesource"))
+ flags |= VIR_MIGRATE_UNDEFINE_SOURCE;
+
if ((flags & VIR_MIGRATE_PEER2PEER) ||
vshCommandOptBool (cmd, "direct")) {
/* For peer2peer migration or direct migration we only expect one URI
--
1.6.0.6
3
10
Hi All,
I have just added support for SATA Disks in virDomainDiskBus and the patch for
same is as below.
Regards,
Pritesh
2
3
[libvirt] [PATCH] LXC implement missing lxcDomainInterfaceStats (domifstat)
by Ryota Ozaki 12 Nov '09
by Ryota Ozaki 12 Nov '09
12 Nov '09
Most part of code is just copied from qemu_driver.c.
* src/lxc/lxc_driver.c: add lxcDomainInterfaceStats
---
src/lxc/lxc_driver.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 61 insertions(+), 1 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index a917a46..542b382 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -48,6 +48,7 @@
#include "event.h"
#include "nodeinfo.h"
#include "uuid.h"
+#include "stats_linux.h"
#define VIR_FROM_THIS VIR_FROM_LXC
@@ -1939,6 +1940,65 @@ cleanup:
return ret;
}
+#ifdef __linux__
+static int
+lxcDomainInterfaceStats(virDomainPtr dom,
+ const char *path,
+ struct _virDomainInterfaceStats *stats)
+{
+ lxc_driver_t *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int i;
+ int ret = -1;
+
+ lxcDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ lxcDriverUnlock(driver);
+
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ lxcError(dom->conn, dom, VIR_ERR_NO_DOMAIN,
+ _("No domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (!virDomainObjIsActive(vm)) {
+ lxcError(dom->conn, dom, VIR_ERR_OPERATION_INVALID,
+ "%s", _("Domain is not running"));
+ goto cleanup;
+ }
+
+ /* Check the path is one of the domain's network interfaces. */
+ for (i = 0 ; i < vm->def->nnets ; i++) {
+ if (vm->def->nets[i]->ifname &&
+ STREQ(vm->def->nets[i]->ifname, path)) {
+ ret = 0;
+ break;
+ }
+ }
+
+ if (ret == 0)
+ ret = linuxDomainInterfaceStats(dom->conn, path, stats);
+ else
+ lxcError(dom->conn, dom, VIR_ERR_INVALID_ARG,
+ _("Invalid path, '%s' is not a known interface"), path);
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+#else
+static int
+lxcDomainInterfaceStats(virDomainPtr dom,
+ const char *path ATTRIBUTE_UNUSED,
+ struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
+ lxcError(dom->conn, dom, VIR_ERR_NO_SUPPORT, "%s", __FUNCTION__);
+ return -1;
+}
+#endif
+
static int lxcDomainGetAutostart(virDomainPtr dom,
int *autostart) {
lxc_driver_t *driver = dom->conn->privateData;
@@ -2308,7 +2368,7 @@ static virDriver lxcDriver = {
NULL, /* domainMigratePerform */
NULL, /* domainMigrateFinish */
NULL, /* domainBlockStats */
- NULL, /* domainInterfaceStats */
+ lxcDomainInterfaceStats, /* domainInterfaceStats */
NULL, /* domainBlockPeek */
NULL, /* domainMemoryPeek */
nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
--
1.6.2.5
3
2
Hi,
everything is in the subject. I'm running Debian SID with libvirt-bin
0.7.2-3 and virt-manager 0.8.0-2.
I had 4 VMs created manually some times ago (Lenny, Ubuntu 9.04, W2k and
XPHome) which I migrate to libvirt. Both Linux are booting well, both
Windows not: they start but suddenly reboot.
On W2K I see the white starting bannier increasing on the bottom off the
screen, and when done, reboot.
On XPh at the time where the booting Windows screen should appear, VM
restart. The I get the famous "Windows hasn't shutdown clearly, do you
want to start in safe mode ... aso)
On both systems, after first fail reboot, I can try and try again,
always the same. If I stared VMs manually, no problem!
My start script -which started without any problem my XPHome VM- is:
#!/bin/bash
AUDIO="es1370"
VGA="std"
sudo /usr/bin/kvm -localtime -cdrom /dev/scd0 -boot c -hda
/media/XP/vdisk.img -hdb /media/XP/vdisk1.img -m 512 -soundhw $AUDIO
-vga $VGA\
-net nic,vlan=0 -net vde,vlan=0,sock=/var/run/vde.ctl -usb -smb
public -monitor tcp:127.0.0.1:32011,server,nowait &
The XML file for the same VM which fail on boot is:
<domain type='kvm'>
<name>XPHome</name>
<uuid>26e5de74-0841-c4b3-4cc1-e0df0f93cb31</uuid>
<memory>524288</memory>
<currentMemory>524288</currentMemory>
<vcpu>1</vcpu>
<os>
<type arch='x86_64' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<pae/>
</features>
<clock offset='localtime'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>/usr/bin/kvm</emulator>
<disk type='file' device='disk'>
<source file='/media/XP/vdisk.img'/>
<target dev='hda' bus='ide'/>
</disk>
<disk type='file' device='disk'>
<source file='/media/XP/vdisk1.img'/>
<target dev='hdb' bus='ide'/>
</disk>
<disk type='block' device='cdrom'>
<source dev='/dev/cdrom'/>
<target dev='hdc' bus='ide'/>
<readonly/>
</disk>
<interface type='bridge'>
<mac address='54:52:00:7a:ee:01'/>
<source bridge='virbr2'/>
</interface>
<serial type='pty'>
<source path='/dev/pts/6'/>
<target port='0'/>
</serial>
<console type='pty' tty='/dev/pts/6'>
<source path='/dev/pts/6'/>
<target port='0'/>
</console>
<input type='tablet' bus='usb'/>
<input type='mouse' bus='ps2'/>
<graphics type='vnc' port='-1' autoport='yes' keymap='en-us'/>
<sound model='es1370'/>
<video>
<model type='cirrus' vram='9216' heads='1'/>
</video>
</devices>
</domain>
~>qemu-img info /media/XP/vdisk.img
image: /media/XP/vdisk.img
file format: raw
virtual size: 6.0G (6442450944 bytes)
disk size: 5.8G
~>qemu-img info /media/XP/vdisk1.img
image: /media/XP/vdisk1.img
file format: raw
virtual size: 2.0G (2147483648 bytes)
disk size: 268M
The disk image from all Linux VMs are also raw.
On another server I installed from scratch on LVM partition an XPPro
Windows VM without any problem.
Thanks for any hint.
Regards
--
Daniel
2
4
[libvirt] [PATCH] Fix save and restore with non-privileged guests and SELinux
by Daniel P. Berrange 12 Nov '09
by Daniel P. Berrange 12 Nov '09
12 Nov '09
When running qemu:///system instance, libvirtd runs as root,
but QEMU may optionally be configured to run non-root. When
then saving a guest to a state file, the file is initially
created as root, and thus QEMU cannot write to it. It is also
missing labelling required to allow access via SELinux.
* src/qemu/qemu_driver.c: Set ownership on save image before
running migrate command in virDomainSave impl. Call out to
security driver to set save image labelling
* src/security/security_driver.h: Add driver APIs for setting
and restoring saved state file labelling
* src/security/security_selinux.c: Implement saved state file
labelling for SELinux
---
src/qemu/qemu_driver.c | 35 ++++++++++++++++++++++++++++++++---
src/security/security_driver.h | 7 +++++++
src/security/security_selinux.c | 23 +++++++++++++++++++++++
3 files changed, 62 insertions(+), 3 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 30003e6..b023902 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3347,6 +3347,7 @@ static int qemudDomainSave(virDomainPtr dom,
char *xml = NULL;
struct qemud_save_header header;
int ret = -1;
+ int rc;
virDomainEventPtr event = NULL;
memset(&header, 0, sizeof(header));
@@ -3435,11 +3436,24 @@ static int qemudDomainSave(virDomainPtr dom,
}
fd = -1;
+ if (driver->privileged &&
+ chown(path, driver->user, driver->group) < 0) {
+ virReportSystemError(NULL, errno,
+ _("unable to set ownership of '%s' to user %d:%d"),
+ path, driver->user, driver->group);
+ goto endjob;
+ }
+
+ if (driver->securityDriver &&
+ driver->securityDriver->domainSetSavedStateLabel &&
+ driver->securityDriver->domainSetSavedStateLabel(dom->conn, vm, path) == -1)
+ goto endjob;
+
if (header.compressed == QEMUD_SAVE_FORMAT_RAW) {
const char *args[] = { "cat", NULL };
qemuDomainObjPrivatePtr priv = vm->privateData;
qemuDomainObjEnterMonitor(vm);
- ret = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
+ rc = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
qemuDomainObjExitMonitor(vm);
} else {
const char *prog = qemudSaveCompressionTypeToString(header.compressed);
@@ -3450,13 +3464,28 @@ static int qemudDomainSave(virDomainPtr dom,
NULL
};
qemuDomainObjEnterMonitor(vm);
- ret = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
+ rc = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
qemuDomainObjExitMonitor(vm);
}
- if (ret < 0)
+ if (rc < 0)
goto endjob;
+ if (driver->privileged &&
+ chown(path, 0, 0) < 0) {
+ virReportSystemError(NULL, errno,
+ _("unable to set ownership of '%s' to user %d:%d"),
+ path, 0, 0);
+ goto endjob;
+ }
+
+ if (driver->securityDriver &&
+ driver->securityDriver->domainRestoreSavedStateLabel &&
+ driver->securityDriver->domainRestoreSavedStateLabel(dom->conn, path) == -1)
+ goto endjob;
+
+ ret = 0;
+
/* Shut it down */
qemudShutdownVMDaemon(dom->conn, driver, vm);
event = virDomainEventNewFromObj(vm,
diff --git a/src/security/security_driver.h b/src/security/security_driver.h
index fde2978..5514962 100644
--- a/src/security/security_driver.h
+++ b/src/security/security_driver.h
@@ -42,6 +42,11 @@ typedef int (*virSecurityDomainRestoreHostdevLabel) (virConnectPtr conn,
typedef int (*virSecurityDomainSetHostdevLabel) (virConnectPtr conn,
virDomainObjPtr vm,
virDomainHostdevDefPtr dev);
+typedef int (*virSecurityDomainSetSavedStateLabel) (virConnectPtr conn,
+ virDomainObjPtr vm,
+ const char *savefile);
+typedef int (*virSecurityDomainRestoreSavedStateLabel) (virConnectPtr conn,
+ const char *savefile);
typedef int (*virSecurityDomainGenLabel) (virConnectPtr conn,
virDomainObjPtr sec);
typedef int (*virSecurityDomainReserveLabel) (virConnectPtr conn,
@@ -71,6 +76,8 @@ struct _virSecurityDriver {
virSecurityDomainRestoreLabel domainRestoreSecurityLabel;
virSecurityDomainRestoreHostdevLabel domainRestoreSecurityHostdevLabel;
virSecurityDomainSetHostdevLabel domainSetSecurityHostdevLabel;
+ virSecurityDomainSetSavedStateLabel domainSetSavedStateLabel;
+ virSecurityDomainRestoreSavedStateLabel domainRestoreSavedStateLabel;
/*
* This is internally managed driver state and should only be accessed
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 0e31077..bd838e6 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -523,6 +523,7 @@ done:
return ret;
}
+
static int
SELinuxRestoreSecurityPCILabel(virConnectPtr conn,
pciDevice *dev ATTRIBUTE_UNUSED,
@@ -623,6 +624,26 @@ SELinuxRestoreSecurityLabel(virConnectPtr conn,
return rc;
}
+
+static int
+SELinuxSetSavedStateLabel(virConnectPtr conn,
+ virDomainObjPtr vm,
+ const char *savefile)
+{
+ const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
+
+ return SELinuxSetFilecon(conn, savefile, secdef->imagelabel);
+}
+
+
+static int
+SELinuxRestoreSavedStateLabel(virConnectPtr conn,
+ const char *savefile)
+{
+ return SELinuxRestoreSecurityFileLabel(conn, savefile);
+}
+
+
static int
SELinuxSecurityVerify(virConnectPtr conn, virDomainDefPtr def)
{
@@ -692,4 +713,6 @@ virSecurityDriver virSELinuxSecurityDriver = {
.domainSetSecurityLabel = SELinuxSetSecurityLabel,
.domainSetSecurityHostdevLabel = SELinuxSetSecurityHostdevLabel,
.domainRestoreSecurityHostdevLabel = SELinuxRestoreSecurityHostdevLabel,
+ .domainSetSavedStateLabel = SELinuxSetSavedStateLabel,
+ .domainRestoreSavedStateLabel = SELinuxRestoreSavedStateLabel,
};
--
1.6.2.5
3
3