Devel
Threads by month
- ----- 2026 -----
- April
- March
- February
- 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
- 38 participants
- 40204 discussions
[libvirt] [PATCH 1/2] libvirt/qemu : allow persistent modification of disks via A(De)ttachDeviceFlags
by KAMEZAWA Hiroyuki 24 Feb '11
by KAMEZAWA Hiroyuki 24 Feb '11
24 Feb '11
Sorry, pervious mail was sent to wrong list...
==
>From 030135224dd6563af0fb8615dc6a4b8e6084410d Mon Sep 17 00:00:00 2001
From: KAMEZAWA Hiroyuki <kamezawa(a)bluextal.(none)>
Date: Wed, 23 Feb 2011 15:25:26 +0900
Subject: [PATCH 1/2] libvirt/qemu : support attach/detach-disk --persistent
Now, only Xen supports 'virsh attach/detach-disk XXXX --persistent',
modifying inactive domain definition via virsh.
This patch adds a support for qemu. With this patch,
virsh attach/detach-disk --persistent works well with qemu.
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu(a)jp.fujitsu.com>
---
src/qemu/qemu_driver.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 163 insertions(+), 7 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0f25a2a..703f86a 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4082,16 +4082,174 @@ cleanup:
return ret;
}
+static int qemuDomainFindDiskByName(virDomainDefPtr vmdef, const char *name)
+{
+ virDomainDiskDefPtr vdisk;
+ int i;
+
+ for (i = 0; i < vmdef->ndisks; i++) {
+ vdisk = vmdef->disks[i];
+ if (!strcmp(vdisk->dst, name))
+ return i;
+ }
+ return -1;
+}
+/*
+ * Attach a device given by XML, the change will be persistent
+ * and domain XML definition file is updated.
+ */
+static int qemuDomainAttachDevicePersistent(virDomainDefPtr vmdef,
+ virDomainDeviceDefPtr newdev)
+{
+ virDomainDiskDefPtr disk;
+
+ /* At first, check device confliction */
+ switch(newdev->type) {
+ case VIR_DOMAIN_DEVICE_DISK:
+ disk = newdev->data.disk;
+ if (qemuDomainFindDiskByName(vmdef, disk->dst) >= 0) {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("target %s already exists."), disk->dst);
+ return -1;
+ }
+
+ if (virDomainDiskInsert(vmdef, disk)) {
+ virReportOOMError();
+ return -1;
+ }
+ if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+ /*
+ * Address/Drive information is NULL. If virtio, PCI address
+ * shoule be fixed. Other devices as IDE, SCSI...will get ID
+ * automatically
+ */
+ qemuDomainAssignPCIAddresses(vmdef);
+
+ }
+ newdev->data.disk = NULL;
+ break;
+ default:
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("Sorry, the device is not suppored for now"));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int qemuDomainDetachDevicePersistent(virDomainDefPtr vmdef,
+ virDomainDeviceDefPtr device)
+{
+ int x;
+ virDomainDiskDefPtr disk;
+
+ switch(device->type) {
+ case VIR_DOMAIN_DEVICE_DISK:
+ disk = device->data.disk;
+ x = qemuDomainFindDiskByName(vmdef, disk->dst);
+ if (x < 0) {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("target %s doesn't exist."), disk->dst);
+ return -1;
+ }
+ virDomainDiskRemove(vmdef, x);
+ break;
+ default:
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("Sorry, the device is not suppored for now"));
+ return -1;
+ }
+ return 0;
+}
+
+static int qemuDomainModifyDevicePersistent(virDomainPtr dom,
+ const char *xml,
+ unsigned int attach)
+{
+ struct qemud_driver *driver;
+ virDomainDeviceDefPtr device;
+ virDomainDefPtr vmdef;
+ virDomainObjPtr vm;
+ int ret = -1;
+
+ if (!dom || !dom->conn || !dom->name || !xml) {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("internal error : %s"), __FUNCTION__);
+ return -1;
+ }
+
+ if (dom->conn->flags & VIR_CONNECT_RO)
+ return -1;
+
+ driver = dom->conn->privateData;
+ qemuDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ qemuReportError(VIR_ERR_NO_DOMAIN, _("cannot find domain '%s'"),
+ dom->name);
+ goto unlock_out;
+ }
+
+ if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0) {
+ /*
+ * For now, just allow updating inactive domains. Further development
+ * will allow updating both active domain and its config file at
+ * the same time.
+ */
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("cannot update alive domain : %s"), __FUNCTION__);
+ goto endjob;
+ }
+ vmdef = virDomainObjGetPersistentDef(driver->caps, vm);
+
+ if (!vmdef)
+ goto endjob;
+
+ device = virDomainDeviceDefParse(driver->caps,
+ vmdef, xml, VIR_DOMAIN_XML_INACTIVE);
+ if (!device)
+ goto endjob;
+
+ if (attach) {
+ ret = qemuDomainAttachDevicePersistent(vmdef, device);
+ if (ret < 0)
+ goto out;
+ } else {
+ ret = qemuDomainDetachDevicePersistent(vmdef, device);
+ if (ret < 0)
+ goto out;
+ }
+ ret = virDomainSaveConfig(driver->configDir, vmdef);
+
+out:
+ virDomainDeviceDefFree(device);
+endjob:
+ if (qemuDomainObjEndJob(vm) == 0)
+ vm = NULL;
+ if (vm)
+ virDomainObjUnlock(vm);
+ /* Note: insert of newdev is done by copy */
+unlock_out:
+ qemuDriverUnlock(driver);
+ return ret;
+}
+
static int qemudDomainAttachDeviceFlags(virDomainPtr dom,
const char *xml,
unsigned int flags) {
if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
- qemuReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("cannot modify the persistent configuration of a domain"));
- return -1;
+ /*
+ * Because we can't update the live guest and XML
+ * in atomic, limiting modification as only-acrive and
+ * only-inactive. Need some idea to update both at the same time.
+ */
+ return qemuDomainModifyDevicePersistent(dom, xml, 1);
}
- return qemudDomainAttachDevice(dom, xml);
+ if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE)
+ return qemudDomainAttachDevice(dom, xml);
+
+ return -1;
}
@@ -4304,9 +4462,7 @@ static int qemudDomainDetachDeviceFlags(virDomainPtr dom,
const char *xml,
unsigned int flags) {
if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
- qemuReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("cannot modify the persistent configuration of a domain"));
- return -1;
+ return qemuDomainModifyDevicePersistent(dom, xml, 0);
}
return qemudDomainDetachDevice(dom, xml);
--
1.7.1
2
3
[libvirt] [PATCH] Allow hash tables to use generic pointers as keys
by Daniel P. Berrange 23 Feb '11
by Daniel P. Berrange 23 Feb '11
23 Feb '11
Relax the restriction that the hash table key must be a string
by allowing an arbitrary hash code generator + comparison func
to be provided
* util/hash.c, util/hash.h: Allow any pointer as a key
* internal.h: Include stdbool.h as standard.
* conf/domain_conf.c, conf/domain_conf.c,
conf/nwfilter_params.c, nwfilter/nwfilter_gentech_driver.c,
nwfilter/nwfilter_gentech_driver.h, nwfilter/nwfilter_learnipaddr.c,
qemu/qemu_command.c, qemu/qemu_driver.c,
qemu/qemu_process.c, uml/uml_driver.c,
xen/xm_internal.c: s/char */void */ in hash callbacks
---
src/conf/domain_conf.c | 24 ++++----
src/conf/nwfilter_params.c | 12 ++--
src/internal.h | 1 +
src/lxc/lxc_driver.c | 4 +-
src/nwfilter/nwfilter_gentech_driver.c | 2 +-
src/nwfilter/nwfilter_gentech_driver.h | 2 +-
src/nwfilter/nwfilter_learnipaddr.c | 4 +-
src/qemu/qemu_command.c | 2 +-
src/qemu/qemu_driver.c | 8 ++--
src/qemu/qemu_process.c | 4 +-
src/uml/uml_driver.c | 4 +-
src/util/hash.c | 92 +++++++++++++++++++++++---------
src/util/hash.h | 24 ++++++---
src/xen/xm_internal.c | 8 ++--
14 files changed, 122 insertions(+), 69 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b97c1f0..651e2dc 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -392,7 +392,7 @@ VIR_ENUM_IMPL(virDomainTimerMode, VIR_DOMAIN_TIMER_MODE_LAST,
#define VIR_DOMAIN_XML_READ_FLAGS VIR_DOMAIN_XML_INACTIVE
static void
-virDomainObjListDeallocator(void *payload, const char *name ATTRIBUTE_UNUSED)
+virDomainObjListDeallocator(void *payload, const void *name ATTRIBUTE_UNUSED)
{
virDomainObjPtr obj = payload;
virDomainObjLock(obj);
@@ -416,7 +416,7 @@ void virDomainObjListDeinit(virDomainObjListPtr doms)
static int virDomainObjListSearchID(const void *payload,
- const char *name ATTRIBUTE_UNUSED,
+ const void *name ATTRIBUTE_UNUSED,
const void *data)
{
virDomainObjPtr obj = (virDomainObjPtr)payload;
@@ -457,7 +457,7 @@ virDomainObjPtr virDomainFindByUUID(const virDomainObjListPtr doms,
}
static int virDomainObjListSearchName(const void *payload,
- const char *name ATTRIBUTE_UNUSED,
+ const void *name ATTRIBUTE_UNUSED,
const void *data)
{
virDomainObjPtr obj = (virDomainObjPtr)payload;
@@ -8435,7 +8435,7 @@ void virDomainObjUnlock(virDomainObjPtr obj)
}
-static void virDomainObjListCountActive(void *payload, const char *name ATTRIBUTE_UNUSED, void *data)
+static void virDomainObjListCountActive(void *payload, const void *name ATTRIBUTE_UNUSED, void *data)
{
virDomainObjPtr obj = payload;
int *count = data;
@@ -8445,7 +8445,7 @@ static void virDomainObjListCountActive(void *payload, const char *name ATTRIBUT
virDomainObjUnlock(obj);
}
-static void virDomainObjListCountInactive(void *payload, const char *name ATTRIBUTE_UNUSED, void *data)
+static void virDomainObjListCountInactive(void *payload, const void *name ATTRIBUTE_UNUSED, void *data)
{
virDomainObjPtr obj = payload;
int *count = data;
@@ -8471,7 +8471,7 @@ struct virDomainIDData {
int *ids;
};
-static void virDomainObjListCopyActiveIDs(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
+static void virDomainObjListCopyActiveIDs(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
{
virDomainObjPtr obj = payload;
struct virDomainIDData *data = opaque;
@@ -8497,7 +8497,7 @@ struct virDomainNameData {
char **const names;
};
-static void virDomainObjListCopyInactiveNames(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
+static void virDomainObjListCopyInactiveNames(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
{
virDomainObjPtr obj = payload;
struct virDomainNameData *data = opaque;
@@ -8754,7 +8754,7 @@ virDomainSnapshotObjPtr virDomainSnapshotAssignDef(virDomainSnapshotObjListPtr s
/* Snapshot Obj List functions */
static void
virDomainSnapshotObjListDeallocator(void *payload,
- const char *name ATTRIBUTE_UNUSED)
+ const void *name ATTRIBUTE_UNUSED)
{
virDomainSnapshotObjPtr obj = payload;
@@ -8783,7 +8783,7 @@ struct virDomainSnapshotNameData {
};
static void virDomainSnapshotObjListCopyNames(void *payload,
- const char *name ATTRIBUTE_UNUSED,
+ const void *name ATTRIBUTE_UNUSED,
void *opaque)
{
virDomainSnapshotObjPtr obj = payload;
@@ -8821,7 +8821,7 @@ cleanup:
}
static void virDomainSnapshotObjListCount(void *payload ATTRIBUTE_UNUSED,
- const char *name ATTRIBUTE_UNUSED,
+ const void *name ATTRIBUTE_UNUSED,
void *data)
{
int *count = data;
@@ -8839,7 +8839,7 @@ int virDomainSnapshotObjListNum(virDomainSnapshotObjListPtr snapshots)
}
static int virDomainSnapshotObjListSearchName(const void *payload,
- const char *name ATTRIBUTE_UNUSED,
+ const void *name ATTRIBUTE_UNUSED,
const void *data)
{
virDomainSnapshotObjPtr obj = (virDomainSnapshotObjPtr)payload;
@@ -8870,7 +8870,7 @@ struct snapshot_has_children {
};
static void virDomainSnapshotCountChildren(void *payload,
- const char *name ATTRIBUTE_UNUSED,
+ const void *name ATTRIBUTE_UNUSED,
void *data)
{
virDomainSnapshotObjPtr obj = payload;
diff --git a/src/conf/nwfilter_params.c b/src/conf/nwfilter_params.c
index cd94b30..fbd42cd 100644
--- a/src/conf/nwfilter_params.c
+++ b/src/conf/nwfilter_params.c
@@ -35,7 +35,7 @@
#define VIR_FROM_THIS VIR_FROM_NWFILTER
static void
-hashDealloc(void *payload, const char *name ATTRIBUTE_UNUSED)
+hashDealloc(void *payload, const void *name ATTRIBUTE_UNUSED)
{
VIR_FREE(payload);
}
@@ -157,7 +157,7 @@ struct addToTableStruct {
static void
-addToTable(void *payload, const char *name, void *data)
+addToTable(void *payload, const void *name, void *data)
{
struct addToTableStruct *atts = (struct addToTableStruct *)data;
char *val;
@@ -172,10 +172,10 @@ addToTable(void *payload, const char *name, void *data)
return;
}
- if (virNWFilterHashTablePut(atts->target, name, val, 1) != 0) {
+ if (virNWFilterHashTablePut(atts->target, (const char *)name, val, 1) != 0) {
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
_("Could not put variable '%s' into hashmap"),
- name);
+ (const char *)name);
atts->errOccurred = 1;
VIR_FREE(val);
}
@@ -265,13 +265,13 @@ struct formatterParam {
static void
-_formatParameterAttrs(void *payload, const char *name, void *data)
+_formatParameterAttrs(void *payload, const void *name, void *data)
{
struct formatterParam *fp = (struct formatterParam *)data;
virBufferVSprintf(fp->buf, "%s<parameter name='%s' value='%s'/>\n",
fp->indent,
- name,
+ (const char *)name,
(char *)payload);
}
diff --git a/src/internal.h b/src/internal.h
index e263684..be97801 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -8,6 +8,7 @@
# include <errno.h>
# include <limits.h>
# include <verify.h>
+# include <stdbool.h>
# if STATIC_ANALYSIS
# undef NDEBUG /* Don't let a prior NDEBUG definition cause trouble. */
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index a17b0b6..625777a 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -1968,7 +1968,7 @@ struct lxcAutostartData {
};
static void
-lxcAutostartDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
+lxcAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
{
virDomainObjPtr vm = payload;
const struct lxcAutostartData *data = opaque;
@@ -2015,7 +2015,7 @@ lxcAutostartConfigs(lxc_driver_t *driver) {
}
static void
-lxcReconnectVM(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
+lxcReconnectVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
{
virDomainObjPtr vm = payload;
lxc_driver_t *driver = opaque;
diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter_gentech_driver.c
index d81aac8..facad13 100644
--- a/src/nwfilter/nwfilter_gentech_driver.c
+++ b/src/nwfilter/nwfilter_gentech_driver.c
@@ -1012,7 +1012,7 @@ virNWFilterTeardownFilter(const virDomainNetDefPtr net)
void
virNWFilterDomainFWUpdateCB(void *payload,
- const char *name ATTRIBUTE_UNUSED,
+ const void *name ATTRIBUTE_UNUSED,
void *data)
{
virDomainObjPtr obj = payload;
diff --git a/src/nwfilter/nwfilter_gentech_driver.h b/src/nwfilter/nwfilter_gentech_driver.h
index 271bf85..fa86030 100644
--- a/src/nwfilter/nwfilter_gentech_driver.h
+++ b/src/nwfilter/nwfilter_gentech_driver.h
@@ -64,7 +64,7 @@ virNWFilterHashTablePtr virNWFilterCreateVarHashmap(char *macaddr,
char *ipaddr);
void virNWFilterDomainFWUpdateCB(void *payload,
- const char *name ATTRIBUTE_UNUSED,
+ const void *name,
void *data);
#endif
diff --git a/src/nwfilter/nwfilter_learnipaddr.c b/src/nwfilter/nwfilter_learnipaddr.c
index 8bd7b50..0e0370a 100644
--- a/src/nwfilter/nwfilter_learnipaddr.c
+++ b/src/nwfilter/nwfilter_learnipaddr.c
@@ -189,7 +189,7 @@ virNWFilterLockIface(const char *ifname) {
static void
-freeIfaceLock(void *payload, const char *name ATTRIBUTE_UNUSED) {
+freeIfaceLock(void *payload, const void *name ATTRIBUTE_UNUSED) {
VIR_FREE(payload);
}
@@ -287,7 +287,7 @@ virNWFilterLookupLearnReq(int ifindex) {
static void
-freeLearnReqEntry(void *payload, const char *name ATTRIBUTE_UNUSED) {
+freeLearnReqEntry(void *payload, const void *name ATTRIBUTE_UNUSED) {
virNWFilterIPAddrLearnReqFree(payload);
}
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index a41859c..e68a698 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -747,7 +747,7 @@ cleanup:
static void
qemuDomainPCIAddressSetFreeEntry(void *payload,
- const char *name ATTRIBUTE_UNUSED)
+ const void *name ATTRIBUTE_UNUSED)
{
VIR_FREE(payload);
}
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0f25a2a..fa96094 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -133,7 +133,7 @@ struct qemuAutostartData {
};
static void
-qemuAutostartDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
+qemuAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
{
virDomainObjPtr vm = payload;
struct qemuAutostartData *data = opaque;
@@ -273,7 +273,7 @@ err_exit:
}
static void qemuDomainSnapshotLoad(void *payload,
- const char *name ATTRIBUTE_UNUSED,
+ const void *name ATTRIBUTE_UNUSED,
void *data)
{
virDomainObjPtr vm = (virDomainObjPtr)payload;
@@ -6502,7 +6502,7 @@ struct snap_remove {
};
static void qemuDomainSnapshotDiscardChildren(void *payload,
- const char *name ATTRIBUTE_UNUSED,
+ const void *name ATTRIBUTE_UNUSED,
void *data)
{
virDomainSnapshotObjPtr snap = payload;
@@ -6533,7 +6533,7 @@ struct snap_reparent {
static void
qemuDomainSnapshotReparentChildren(void *payload,
- const char *name ATTRIBUTE_UNUSED,
+ const void *name ATTRIBUTE_UNUSED,
void *data)
{
virDomainSnapshotObjPtr snap = payload;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 9c5ea63..e418c37 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -949,7 +949,7 @@ qemuProcessFindCharDevicePTYs(virDomainObjPtr vm,
return 0;
}
-static void qemuProcessFreePtyPath(void *payload, const char *name ATTRIBUTE_UNUSED)
+static void qemuProcessFreePtyPath(void *payload, const void *name ATTRIBUTE_UNUSED)
{
VIR_FREE(payload);
}
@@ -1783,7 +1783,7 @@ struct qemuProcessReconnectData {
* and re-reserve the security labels in use
*/
static void
-qemuProcessReconnect(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
+qemuProcessReconnect(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
{
virDomainObjPtr obj = payload;
struct qemuProcessReconnectData *data = opaque;
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
index 2af8002..7cacadb 100644
--- a/src/uml/uml_driver.c
+++ b/src/uml/uml_driver.c
@@ -149,7 +149,7 @@ struct umlAutostartData {
};
static void
-umlAutostartDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
+umlAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
{
virDomainObjPtr vm = payload;
const struct umlAutostartData *data = opaque;
@@ -508,7 +508,7 @@ umlActive(void) {
}
static void
-umlShutdownOneVM(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaque)
+umlShutdownOneVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
{
virDomainObjPtr dom = payload;
struct uml_driver *driver = opaque;
diff --git a/src/util/hash.c b/src/util/hash.c
index d7950b9..aa658d4 100644
--- a/src/util/hash.c
+++ b/src/util/hash.c
@@ -43,7 +43,7 @@ typedef struct _virHashEntry virHashEntry;
typedef virHashEntry *virHashEntryPtr;
struct _virHashEntry {
struct _virHashEntry *next;
- char *name;
+ void *name;
void *payload;
int valid;
};
@@ -56,25 +56,48 @@ struct _virHashTable {
int size;
int nbElems;
virHashDeallocator f;
+ virHashCode code;
+ virHashEqual equal;
+ virHashCopy copy;
+ virHashRelease release;
};
-/*
- * virHashComputeKey:
- * Calculate the hash key
- */
-static unsigned long
-virHashComputeKey(virHashTablePtr table, const char *name)
+static unsigned long virHashStrCode(const void *name)
{
+ const char *str = name;
unsigned long value = 0L;
char ch;
- if (name != NULL) {
- value += 30 * (*name);
- while ((ch = *name++) != 0) {
+ if (str != NULL) {
+ value += 30 * (*str);
+ while ((ch = *str++) != 0) {
value =
value ^ ((value << 5) + (value >> 3) + (unsigned long) ch);
}
}
+ return value;
+}
+
+static bool virHashStrEqual(const void *namea, const void *nameb)
+{
+ return strcmp(namea, nameb) == 0 ? true : false;
+}
+
+static void *virHashStrCopy(const void *name)
+{
+ return strdup(name);
+}
+
+static void virHashStrRelease(void *name)
+{
+ VIR_FREE(name);
+}
+
+
+static unsigned long
+virHashComputeKey(virHashTablePtr table, const void *name)
+{
+ unsigned long value = table->code(name);
return (value % table->size);
}
@@ -87,8 +110,9 @@ virHashComputeKey(virHashTablePtr table, const char *name)
*
* Returns the newly created object, or NULL if an error occured.
*/
-virHashTablePtr
-virHashCreate(int size, virHashDeallocator deallocator)
+virHashTablePtr virHashCreateFull(int size, virHashDeallocator deallocator,
+ virHashCode code, virHashEqual equal,
+ virHashCopy copy, virHashRelease release)
{
virHashTablePtr table = NULL;
@@ -103,6 +127,10 @@ virHashCreate(int size, virHashDeallocator deallocator)
table->size = size;
table->nbElems = 0;
table->f = deallocator;
+ table->code = code;
+ table->equal = equal;
+ table->copy = copy;
+ table->release = release;
if (VIR_ALLOC_N(table->table, size) < 0) {
virReportOOMError();
VIR_FREE(table);
@@ -112,6 +140,17 @@ virHashCreate(int size, virHashDeallocator deallocator)
return table;
}
+virHashTablePtr
+virHashCreate(int size, virHashDeallocator deallocator)
+{
+ return virHashCreateFull(size,
+ deallocator,
+ virHashStrCode,
+ virHashStrEqual,
+ virHashStrCopy,
+ virHashStrRelease);
+}
+
/**
* virHashGrow:
* @table: the hash table
@@ -232,7 +271,8 @@ virHashFree(virHashTablePtr table)
next = iter->next;
if ((table->f != NULL) && (iter->payload != NULL))
table->f(iter->payload, iter->name);
- VIR_FREE(iter->name);
+ if (table->release)
+ table->release(iter->name);
iter->payload = NULL;
if (!inside_table)
VIR_FREE(iter);
@@ -247,7 +287,7 @@ virHashFree(virHashTablePtr table)
}
static int
-virHashAddOrUpdateEntry(virHashTablePtr table, const char *name,
+virHashAddOrUpdateEntry(virHashTablePtr table, const void *name,
void *userdata, virHashDeallocator f,
bool is_update)
{
@@ -270,13 +310,13 @@ virHashAddOrUpdateEntry(virHashTablePtr table, const char *name,
} else {
for (insert = &(table->table[key]); insert->next != NULL;
insert = insert->next) {
- if (STREQ(insert->name, name)) {
+ if (table->equal(insert->name, name)) {
found = true;
break;
}
len++;
}
- if (STREQ(insert->name, name))
+ if (table->equal(insert->name, name))
found = true;
}
@@ -300,7 +340,7 @@ virHashAddOrUpdateEntry(virHashTablePtr table, const char *name,
}
}
- new_name = strdup(name);
+ new_name = table->copy(name);
if (new_name == NULL) {
virReportOOMError();
if (insert != NULL)
@@ -335,7 +375,7 @@ virHashAddOrUpdateEntry(virHashTablePtr table, const char *name,
* Returns 0 the addition succeeded and -1 in case of error.
*/
int
-virHashAddEntry(virHashTablePtr table, const char *name, void *userdata)
+virHashAddEntry(virHashTablePtr table, const void *name, void *userdata)
{
return virHashAddOrUpdateEntry(table, name, userdata, NULL, false);
}
@@ -354,7 +394,7 @@ virHashAddEntry(virHashTablePtr table, const char *name, void *userdata)
* Returns 0 the addition succeeded and -1 in case of error.
*/
int
-virHashUpdateEntry(virHashTablePtr table, const char *name,
+virHashUpdateEntry(virHashTablePtr table, const void *name,
void *userdata, virHashDeallocator f)
{
return virHashAddOrUpdateEntry(table, name, userdata, f, true);
@@ -370,7 +410,7 @@ virHashUpdateEntry(virHashTablePtr table, const char *name,
* Returns the a pointer to the userdata
*/
void *
-virHashLookup(virHashTablePtr table, const char *name)
+virHashLookup(virHashTablePtr table, const void *name)
{
unsigned long key;
virHashEntryPtr entry;
@@ -383,7 +423,7 @@ virHashLookup(virHashTablePtr table, const char *name)
if (table->table[key].valid == 0)
return (NULL);
for (entry = &(table->table[key]); entry != NULL; entry = entry->next) {
- if (STREQ(entry->name, name))
+ if (table->equal(entry->name, name))
return (entry->payload);
}
return (NULL);
@@ -419,7 +459,7 @@ virHashSize(virHashTablePtr table)
* Returns 0 if the removal succeeded and -1 in case of error or not found.
*/
int
-virHashRemoveEntry(virHashTablePtr table, const char *name,
+virHashRemoveEntry(virHashTablePtr table, const void *name,
virHashDeallocator f)
{
unsigned long key;
@@ -435,11 +475,12 @@ virHashRemoveEntry(virHashTablePtr table, const char *name,
} else {
for (entry = &(table->table[key]); entry != NULL;
entry = entry->next) {
- if (STREQ(entry->name, name)) {
+ if (table->equal(entry->name, name)) {
if ((f != NULL) && (entry->payload != NULL))
f(entry->payload, entry->name);
entry->payload = NULL;
- VIR_FREE(entry->name);
+ if (table->release)
+ table->release(entry->name);
if (prev) {
prev->next = entry->next;
VIR_FREE(entry);
@@ -523,7 +564,8 @@ int virHashRemoveSet(virHashTablePtr table, virHashSearcher iter, virHashDealloc
if (iter(entry->payload, entry->name, data)) {
count++;
f(entry->payload, entry->name);
- VIR_FREE(entry->name);
+ if (table->release)
+ table->release(entry->name);
table->nbElems--;
if (prev) {
prev->next = entry->next;
diff --git a/src/util/hash.h b/src/util/hash.h
index cf08e1a..6316fd9 100644
--- a/src/util/hash.h
+++ b/src/util/hash.h
@@ -29,7 +29,7 @@ typedef virHashTable *virHashTablePtr;
*
* Callback to free data from a hash.
*/
-typedef void (*virHashDeallocator) (void *payload, const char *name);
+typedef void (*virHashDeallocator) (void *payload, const void *name);
/**
* virHashIterator:
* @payload: the data in the hash
@@ -38,7 +38,7 @@ typedef void (*virHashDeallocator) (void *payload, const char *name);
*
* Callback to process a hash entry during iteration
*/
-typedef void (*virHashIterator) (void *payload, const char *name, void *data);
+typedef void (*virHashIterator) (void *payload, const void *name, void *data);
/**
* virHashSearcher
* @payload: the data in the hash
@@ -49,13 +49,23 @@ typedef void (*virHashIterator) (void *payload, const char *name, void *data);
* Returns 1 if the hash entry is desired, 0 to move
* to next entry
*/
-typedef int (*virHashSearcher) (const void *payload, const char *name,
+typedef int (*virHashSearcher) (const void *payload, const void *name,
const void *data);
+typedef unsigned long (*virHashCode)(const void *name);
+typedef bool (*virHashEqual)(const void *namea, const void *nameb);
+typedef void *(*virHashCopy)(const void *name);
+typedef void (*virHashRelease)(void *name);
+
/*
* Constructor and destructor.
*/
virHashTablePtr virHashCreate(int size, virHashDeallocator f);
+virHashTablePtr virHashCreateFull(int size, virHashDeallocator f,
+ virHashCode code,
+ virHashEqual equal,
+ virHashCopy copy,
+ virHashRelease release);
void virHashFree(virHashTablePtr table);
int virHashSize(virHashTablePtr table);
@@ -63,21 +73,21 @@ int virHashSize(virHashTablePtr table);
* Add a new entry to the hash table.
*/
int virHashAddEntry(virHashTablePtr table,
- const char *name, void *userdata);
+ const void *name, void *userdata);
int virHashUpdateEntry(virHashTablePtr table,
- const char *name,
+ const void *name,
void *userdata, virHashDeallocator f);
/*
* Remove an entry from the hash table.
*/
int virHashRemoveEntry(virHashTablePtr table,
- const char *name, virHashDeallocator f);
+ const void *name, virHashDeallocator f);
/*
* Retrieve the userdata.
*/
-void *virHashLookup(virHashTablePtr table, const char *name);
+void *virHashLookup(virHashTablePtr table, const void *name);
/*
diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c
index 27cc387..fe7e533 100644
--- a/src/xen/xm_internal.c
+++ b/src/xen/xm_internal.c
@@ -139,7 +139,7 @@ static int xenInotifyActive(virConnectPtr conn)
/* Release memory associated with a cached config object */
-static void xenXMConfigFree(void *payload, const char *key ATTRIBUTE_UNUSED) {
+static void xenXMConfigFree(void *payload, const void *key ATTRIBUTE_UNUSED) {
xenXMConfCachePtr entry = (xenXMConfCachePtr)payload;
virDomainDefFree(entry->def);
VIR_FREE(entry);
@@ -151,7 +151,7 @@ struct xenXMConfigReaperData {
};
/* Remove any configs which were not refreshed recently */
-static int xenXMConfigReaper(const void *payload, const char *key ATTRIBUTE_UNUSED, const void *data) {
+static int xenXMConfigReaper(const void *payload, const void *key ATTRIBUTE_UNUSED, const void *data) {
const struct xenXMConfigReaperData *args = data;
xenXMConfCachePtr entry = (xenXMConfCachePtr)payload;
@@ -938,7 +938,7 @@ cleanup:
/*
* Hash table iterator to search for a domain based on UUID
*/
-static int xenXMDomainSearchForUUID(const void *payload, const char *name ATTRIBUTE_UNUSED, const void *data) {
+static int xenXMDomainSearchForUUID(const void *payload, const void *name ATTRIBUTE_UNUSED, const void *data) {
const unsigned char *wantuuid = (const unsigned char *)data;
const xenXMConfCachePtr entry = (const xenXMConfCachePtr)payload;
@@ -1235,7 +1235,7 @@ struct xenXMListIteratorContext {
char ** names;
};
-static void xenXMListIterator(void *payload ATTRIBUTE_UNUSED, const char *name, void *data) {
+static void xenXMListIterator(void *payload ATTRIBUTE_UNUSED, const void *name, void *data) {
struct xenXMListIteratorContext *ctx = data;
virDomainPtr dom = NULL;
--
1.7.4
3
3
23 Feb '11
Using the 'personality(2)' system call, we can make a container
on an x86_64 host appear to be i686. Likewise for most other
Linux 64bit arches.
* src/lxc/lxc_conf.c: Fill in 32bit capabilities for x86_64 hosts
* src/lxc/lxc_container.h, src/lxc/lxc_container.c: Add API to
check if an arch has a 32bit alternative
* src/lxc/lxc_controller.c: Set the process personality when
starting guest
---
src/lxc/lxc_conf.c | 25 ++++++++++++++++++++++++-
src/lxc/lxc_container.c | 21 +++++++++++++++++++++
src/lxc/lxc_container.h | 2 ++
src/lxc/lxc_controller.c | 26 ++++++++++++++++++++++++--
4 files changed, 71 insertions(+), 3 deletions(-)
diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c
index 59d1161..226a57e 100644
--- a/src/lxc/lxc_conf.c
+++ b/src/lxc/lxc_conf.c
@@ -36,6 +36,7 @@
#include "logging.h"
#include "uuid.h"
#include "configmake.h"
+#include "lxc_container.h"
#define VIR_FROM_THIS VIR_FROM_LXC
@@ -45,6 +46,7 @@ virCapsPtr lxcCapsInit(void)
struct utsname utsname;
virCapsPtr caps;
virCapsGuestPtr guest;
+ const char *altArch;
uname(&utsname);
@@ -73,7 +75,7 @@ virCapsPtr lxcCapsInit(void)
if ((guest = virCapabilitiesAddGuest(caps,
"exe",
utsname.machine,
- sizeof(int) == 4 ? 32 : 8,
+ sizeof(void*) == 4 ? 32 : 64,
LIBEXECDIR "/libvirt_lxc",
NULL,
0,
@@ -88,6 +90,27 @@ virCapsPtr lxcCapsInit(void)
NULL) == NULL)
goto error;
+ /* On 64-bit hosts, we can use personality() to request a 32bit process */
+ if ((altArch = lxcContainerGetAlt32bitArch(utsname.machine)) != NULL) {
+ if ((guest = virCapabilitiesAddGuest(caps,
+ "exe",
+ altArch,
+ 32,
+ LIBEXECDIR "/libvirt_lxc",
+ NULL,
+ 0,
+ NULL)) == NULL)
+ goto error;
+
+ if (virCapabilitiesAddGuestDomain(guest,
+ "lxc",
+ NULL,
+ NULL,
+ 0,
+ NULL) == NULL)
+ goto error;
+ }
+
/* LXC Requires an emulator in the XML */
virCapabilitiesSetEmulatorRequired(caps);
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 269dc97..9830b71 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -837,6 +837,27 @@ static int userns_supported(void)
#endif
}
+const char *lxcContainerGetAlt32bitArch(const char *arch)
+{
+ /* Any Linux 64bit arch which has a 32bit
+ * personality available should be listed here */
+ if (STREQ(arch, "x86_64"))
+ return "i686";
+ if (STREQ(arch, "s390x"))
+ return "s390";
+ if (STREQ(arch, "ppc64"))
+ return "ppc";
+ if (STREQ(arch, "parisc64"))
+ return "parisc";
+ if (STREQ(arch, "sparc64"))
+ return "sparc";
+ if (STREQ(arch, "mips64"))
+ return "mips";
+
+ return NULL;
+}
+
+
/**
* lxcContainerStart:
* @def: pointer to virtual machine structure
diff --git a/src/lxc/lxc_container.h b/src/lxc/lxc_container.h
index 75c8836..5e08d45 100644
--- a/src/lxc/lxc_container.h
+++ b/src/lxc/lxc_container.h
@@ -55,4 +55,6 @@ int lxcContainerStart(virDomainDefPtr def,
int lxcContainerAvailable(int features);
+const char *lxcContainerGetAlt32bitArch(const char *arch);
+
#endif /* LXC_CONTAINER_H */
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index 28cbe57..61e21c3 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2010 Red Hat, Inc.
- * Copyright IBM Corp. 2008
+ * Copyright (C) 2010 Red Hat, Inc. Copyright IBM Corp. 2008
*
* lxc_controller.c: linux container process controller
*
@@ -29,6 +28,8 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
+#include <sys/utsname.h>
+#include <sys/personality.h>
#include <unistd.h>
#include <paths.h>
#include <errno.h>
@@ -565,6 +566,25 @@ static int lxcControllerCleanupInterfaces(unsigned int nveths,
return 0;
}
+static int lxcSetPersonality(virDomainDefPtr def)
+{
+ struct utsname utsname;
+ const char *altArch;
+
+ uname(&utsname);
+
+ altArch = lxcContainerGetAlt32bitArch(utsname.machine);
+ if (altArch &&
+ STREQ(def->os.arch, altArch)) {
+ if (personality(PER_LINUX32) < 0) {
+ virReportSystemError(errno, _("Unable to request personality for %s on %s"),
+ altArch, utsname.machine);
+ return -1;
+ }
+ }
+ return 0;
+}
+
#ifndef MS_REC
# define MS_REC 16384
#endif
@@ -684,6 +704,8 @@ lxcControllerRun(virDomainDefPtr def,
}
}
+ if (lxcSetPersonality(def) < 0)
+ goto cleanup;
if ((container = lxcContainerStart(def,
nveths,
--
1.7.4
2
1
[libvirt] [PATCH] Put <stdbool.h> into internal.h so it is available everywhere
by Daniel P. Berrange 23 Feb '11
by Daniel P. Berrange 23 Feb '11
23 Feb '11
Remove the <stdbool.h> header from all source files / headers
and just put it into internal.h
* src/internal.h: Add <stdbool.h>
---
daemon/dispatch.c | 1 -
src/conf/capabilities.h | 2 --
src/conf/nwfilter_conf.h | 1 -
src/conf/storage_encryption_conf.h | 1 -
src/driver.h | 1 -
src/esx/esx_util.h | 2 --
src/fdstream.h | 1 -
src/internal.h | 1 +
src/lxc/lxc_driver.c | 1 -
src/lxc/veth.c | 1 -
src/nodeinfo.c | 1 -
src/opennebula/one_driver.c | 1 -
src/qemu/qemu_conf.h | 1 -
src/qemu/qemu_driver.c | 1 -
src/qemu/qemu_hotplug.h | 2 --
src/secret/secret_driver.c | 1 -
src/security/security_apparmor.c | 1 -
src/security/virt-aa-helper.c | 1 -
src/storage/storage_backend.h | 1 -
src/storage/storage_backend_fs.c | 1 -
src/util/bitmap.h | 1 -
src/util/cgroup.c | 1 -
src/util/command.c | 1 -
src/util/files.h | 1 -
src/util/hash.c | 1 -
src/util/network.h | 1 -
src/util/storage_file.h | 1 -
src/util/threadpool.c | 2 --
src/util/threads.h | 2 --
src/util/util.h | 1 -
src/util/virtaudit.h | 1 -
src/vbox/vbox_XPCOMCGlue.c | 1 -
src/vbox/vbox_tmpl.c | 1 -
src/vmx/vmx.h | 2 --
src/xen/xend_internal.c | 1 -
src/xen/xend_internal.h | 1 -
tests/nwfilterxml2xmltest.c | 1 -
tests/qemuargv2xmltest.c | 1 -
tests/qemuxml2argvtest.c | 1 -
tools/console.c | 1 -
40 files changed, 1 insertions(+), 45 deletions(-)
diff --git a/daemon/dispatch.c b/daemon/dispatch.c
index 3397a00..dc3b48a 100644
--- a/daemon/dispatch.c
+++ b/daemon/dispatch.c
@@ -26,7 +26,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
-#include <stdbool.h>
#include "dispatch.h"
#include "remote.h"
diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h
index 759265d..96bf0a2 100644
--- a/src/conf/capabilities.h
+++ b/src/conf/capabilities.h
@@ -24,8 +24,6 @@
#ifndef __VIR_CAPABILITIES_H
# define __VIR_CAPABILITIES_H
-# include <stdbool.h>
-
# include "internal.h"
# include "util.h"
# include "buf.h"
diff --git a/src/conf/nwfilter_conf.h b/src/conf/nwfilter_conf.h
index 5db4658..40da8c3 100644
--- a/src/conf/nwfilter_conf.h
+++ b/src/conf/nwfilter_conf.h
@@ -28,7 +28,6 @@
# include <stdint.h>
# include <stddef.h>
-# include <stdbool.h>
# include "internal.h"
diff --git a/src/conf/storage_encryption_conf.h b/src/conf/storage_encryption_conf.h
index c722cc6..fa5f3cb 100644
--- a/src/conf/storage_encryption_conf.h
+++ b/src/conf/storage_encryption_conf.h
@@ -27,7 +27,6 @@
# include "buf.h"
# include "util.h"
-# include <stdbool.h>
# include <libxml/tree.h>
enum virStorageEncryptionSecretType {
diff --git a/src/driver.h b/src/driver.h
index 7451004..c65a4b9 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -7,7 +7,6 @@
# define __VIR_DRIVER_H__
# include "config.h"
-# include <stdbool.h>
# include <libxml/uri.h>
diff --git a/src/esx/esx_util.h b/src/esx/esx_util.h
index 4cbf9b7..d00e28a 100644
--- a/src/esx/esx_util.h
+++ b/src/esx/esx_util.h
@@ -1,4 +1,3 @@
-
/*
* esx_util.h: utility functions for the VMware ESX driver
*
@@ -23,7 +22,6 @@
#ifndef __ESX_UTIL_H__
# define __ESX_UTIL_H__
-# include <stdbool.h>
# include <libxml/uri.h>
# include "internal.h"
diff --git a/src/fdstream.h b/src/fdstream.h
index f8d22d5..53cbaa7 100644
--- a/src/fdstream.h
+++ b/src/fdstream.h
@@ -24,7 +24,6 @@
# define __VIR_FDSTREAM_H_
# include "internal.h"
-# include <stdbool.h>
int virFDStreamOpen(virStreamPtr st,
int fd);
diff --git a/src/internal.h b/src/internal.h
index e263684..be97801 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -8,6 +8,7 @@
# include <errno.h>
# include <limits.h>
# include <verify.h>
+# include <stdbool.h>
# if STATIC_ANALYSIS
# undef NDEBUG /* Don't let a prior NDEBUG definition cause trouble. */
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index a17b0b6..70e74d5 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -27,7 +27,6 @@
#include <fcntl.h>
#include <sched.h>
#include <sys/utsname.h>
-#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
diff --git a/src/lxc/veth.c b/src/lxc/veth.c
index 78e011e..65ff5d8 100644
--- a/src/lxc/veth.c
+++ b/src/lxc/veth.c
@@ -13,7 +13,6 @@
#include <config.h>
#include <string.h>
-#include <stdbool.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index f4ea36e..5d40aca 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -23,7 +23,6 @@
#include <config.h>
-#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
diff --git a/src/opennebula/one_driver.c b/src/opennebula/one_driver.c
index 75d7b9a..a0654e2 100644
--- a/src/opennebula/one_driver.c
+++ b/src/opennebula/one_driver.c
@@ -25,7 +25,6 @@
#include <fcntl.h>
#include <sched.h>
#include <sys/utsname.h>
-#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index af1be2e..7c6fde7 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -25,7 +25,6 @@
# define __QEMUD_CONF_H
# include <config.h>
-# include <stdbool.h>
# include "ebtables.h"
# include "internal.h"
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 8b15a3e..0baff56 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -29,7 +29,6 @@
#include <dirent.h>
#include <limits.h>
#include <string.h>
-#include <stdbool.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index 217785d..1c96444 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -24,8 +24,6 @@
#ifndef __QEMU_HOTPLUG_H__
# define __QEMU_HOTPLUG_H__
-# include <stdbool.h>
-
# include "qemu_conf.h"
# include "domain_conf.h"
diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c
index c5a876b..5ca5006 100644
--- a/src/secret/secret_driver.c
+++ b/src/secret/secret_driver.c
@@ -24,7 +24,6 @@
#include <dirent.h>
#include <fcntl.h>
-#include <stdbool.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index 7dc01ac..deb4181 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -23,7 +23,6 @@
#include <errno.h>
#include <unistd.h>
#include <wait.h>
-#include <stdbool.h>
#include "internal.h"
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
index b91cf98..77df514 100644
--- a/src/security/virt-aa-helper.c
+++ b/src/security/virt-aa-helper.c
@@ -24,7 +24,6 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <getopt.h>
-#include <stdbool.h>
#include <sys/utsname.h>
#include <locale.h>
diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h
index 6f395c7..65cbd7e 100644
--- a/src/storage/storage_backend.h
+++ b/src/storage/storage_backend.h
@@ -25,7 +25,6 @@
# define __VIR_STORAGE_BACKEND_H__
# include <stdint.h>
-# include <stdbool.h>
# include "internal.h"
# include "storage_conf.h"
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index ff39d48..c33fb05 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -26,7 +26,6 @@
#include <sys/statvfs.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <stdbool.h>
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
diff --git a/src/util/bitmap.h b/src/util/bitmap.h
index 08515d1..0541112 100644
--- a/src/util/bitmap.h
+++ b/src/util/bitmap.h
@@ -25,7 +25,6 @@
# include "internal.h"
-# include <stdbool.h>
# include <sys/types.h>
diff --git a/src/util/cgroup.c b/src/util/cgroup.c
index b71eef9..a1299aa 100644
--- a/src/util/cgroup.c
+++ b/src/util/cgroup.c
@@ -20,7 +20,6 @@
#include <string.h>
#include <errno.h>
#include <stdlib.h>
-#include <stdbool.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <libgen.h>
diff --git a/src/util/command.c b/src/util/command.c
index 0d5cb79..ff2bd46 100644
--- a/src/util/command.c
+++ b/src/util/command.c
@@ -23,7 +23,6 @@
#include <poll.h>
#include <stdarg.h>
-#include <stdbool.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
diff --git a/src/util/files.h b/src/util/files.h
index 744ba93..5137fb3 100644
--- a/src/util/files.h
+++ b/src/util/files.h
@@ -26,7 +26,6 @@
#ifndef __VIR_FILES_H_
# define __VIR_FILES_H_
-# include <stdbool.h>
# include <stdio.h>
# include "internal.h"
diff --git a/src/util/hash.c b/src/util/hash.c
index d7950b9..3ab73dd 100644
--- a/src/util/hash.c
+++ b/src/util/hash.c
@@ -22,7 +22,6 @@
#include <config.h>
#include <string.h>
-#include <stdbool.h>
#include <stdlib.h>
#include "virterror_internal.h"
diff --git a/src/util/network.h b/src/util/network.h
index 0b43bf6..ed0b78c 100644
--- a/src/util/network.h
+++ b/src/util/network.h
@@ -19,7 +19,6 @@
# include <sys/un.h>
# endif
# include <netdb.h>
-# include <stdbool.h>
# include <netinet/in.h>
typedef struct {
diff --git a/src/util/storage_file.h b/src/util/storage_file.h
index 04c1bb2..f1bdd02 100644
--- a/src/util/storage_file.h
+++ b/src/util/storage_file.h
@@ -25,7 +25,6 @@
# define __VIR_STORAGE_FILE_H__
# include "util.h"
-# include <stdbool.h>
enum virStorageFileFormat {
VIR_STORAGE_FILE_AUTO_SAFE = -2,
diff --git a/src/util/threadpool.c b/src/util/threadpool.c
index 1213862..8217591 100644
--- a/src/util/threadpool.c
+++ b/src/util/threadpool.c
@@ -25,8 +25,6 @@
#include <config.h>
-#include <stdbool.h>
-
#include "threadpool.h"
#include "memory.h"
#include "threads.h"
diff --git a/src/util/threads.h b/src/util/threads.h
index 35e319e..c129301 100644
--- a/src/util/threads.h
+++ b/src/util/threads.h
@@ -22,8 +22,6 @@
#ifndef __THREADS_H_
# define __THREADS_H_
-# include <stdbool.h>
-
# include "internal.h"
typedef struct virMutex virMutex;
diff --git a/src/util/util.h b/src/util/util.h
index c822174..5f6473c 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -31,7 +31,6 @@
# include <sys/select.h>
# include <sys/types.h>
# include <stdarg.h>
-# include <stdbool.h>
# ifndef MIN
# define MIN(a, b) ((a) < (b) ? (a) : (b))
diff --git a/src/util/virtaudit.h b/src/util/virtaudit.h
index 6c4deeb..a558a17 100644
--- a/src/util/virtaudit.h
+++ b/src/util/virtaudit.h
@@ -24,7 +24,6 @@
# define __LIBVIRT_AUDIT_H__
# include "internal.h"
-# include <stdbool.h>
enum virAuditRecordType {
VIR_AUDIT_RECORD_MACHINE_CONTROL,
diff --git a/src/vbox/vbox_XPCOMCGlue.c b/src/vbox/vbox_XPCOMCGlue.c
index fbe210c..0caeef9 100644
--- a/src/vbox/vbox_XPCOMCGlue.c
+++ b/src/vbox/vbox_XPCOMCGlue.c
@@ -34,7 +34,6 @@
#include <stdlib.h>
#include <dlfcn.h>
-#include <stdbool.h>
#include "vbox_XPCOMCGlue.h"
#include "internal.h"
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
index 1c4e46f..8848cc0 100644
--- a/src/vbox/vbox_tmpl.c
+++ b/src/vbox/vbox_tmpl.c
@@ -35,7 +35,6 @@
#include <config.h>
#include <sys/utsname.h>
-#include <stdbool.h>
#include <unistd.h>
#include "internal.h"
diff --git a/src/vmx/vmx.h b/src/vmx/vmx.h
index c317108..4d54660 100644
--- a/src/vmx/vmx.h
+++ b/src/vmx/vmx.h
@@ -23,8 +23,6 @@
#ifndef __VIR_VMX_H__
# define __VIR_VMX_H__
-# include <stdbool.h>
-
# include "internal.h"
# include "conf.h"
# include "domain_conf.h"
diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
index e811b86..bfaed65 100644
--- a/src/xen/xend_internal.c
+++ b/src/xen/xend_internal.c
@@ -21,7 +21,6 @@
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
-#include <stdbool.h>
#include <math.h>
#include <stdarg.h>
#include <netinet/in.h>
diff --git a/src/xen/xend_internal.h b/src/xen/xend_internal.h
index c90c572..805cf91 100644
--- a/src/xen/xend_internal.h
+++ b/src/xen/xend_internal.h
@@ -18,7 +18,6 @@
# include <sys/types.h>
# include <stdint.h>
-# include <stdbool.h>
# include <libxml/uri.h>
# include "internal.h"
diff --git a/tests/nwfilterxml2xmltest.c b/tests/nwfilterxml2xmltest.c
index 9cad913..575177a 100644
--- a/tests/nwfilterxml2xmltest.c
+++ b/tests/nwfilterxml2xmltest.c
@@ -4,7 +4,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
-#include <stdbool.h>
#include <sys/types.h>
#include <fcntl.h>
diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c
index 7499ba0..cfcd824 100644
--- a/tests/qemuargv2xmltest.c
+++ b/tests/qemuargv2xmltest.c
@@ -4,7 +4,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
-#include <stdbool.h>
#include <sys/types.h>
#include <fcntl.h>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 4817d51..a026473 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -4,7 +4,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
-#include <stdbool.h>
#include <sys/types.h>
#include <fcntl.h>
diff --git a/tools/console.c b/tools/console.c
index e126320..224cf03 100644
--- a/tools/console.c
+++ b/tools/console.c
@@ -34,7 +34,6 @@
# include <errno.h>
# include <unistd.h>
# include <signal.h>
-# include <stdbool.h>
# include "internal.h"
# include "console.h"
--
1.7.4
2
3
[libvirt] [PATCH] virsh: Make <mac> required when device-detaching interface
by Michal Privoznik 23 Feb '11
by Michal Privoznik 23 Feb '11
23 Feb '11
Problem is, if user does not specify mac address in input XML,
we generate a random one, which is why device-detach fails giving
a confusing error message. Therefore <mac> needs to be required.
---
tools/virsh.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 46 insertions(+), 11 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 2837e0f..dfb48d2 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -8580,9 +8580,12 @@ cmdDetachDevice(vshControl *ctl, const vshCmd *cmd)
virDomainPtr dom;
char *from;
char *buffer;
- int ret = TRUE;
+ int ret = FALSE;
int found;
unsigned int flags;
+ xmlDocPtr xml = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+ int mac_cnt;
if (!vshConnectionUsability(ctl, ctl->conn))
return FALSE;
@@ -8592,14 +8595,41 @@ cmdDetachDevice(vshControl *ctl, const vshCmd *cmd)
from = vshCommandOptString(cmd, "file", &found);
if (!found) {
- virDomainFree(dom);
- return FALSE;
+ goto cleanup;
}
if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
virshReportError(ctl);
- virDomainFree(dom);
- return FALSE;
+ goto cleanup;
+ }
+
+ xml = xmlReadDoc((const xmlChar *) buffer, "interface.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOWARNING);
+
+ if (!xml) {
+ vshError(ctl, "%s", _("input XML is not valid"));
+ goto cleanup;
+ }
+
+ ctxt = xmlXPathNewContext(xml);
+ mac_cnt = virXPathNodeSet("/interface/mac", ctxt, NULL);
+
+ switch(mac_cnt) {
+ case 1:
+ break;
+
+ case 0:
+ case -1:
+ vshError(ctl, "%s", _("You must specify mac address in xml file"));
+ goto cleanup;
+ break;
+
+ default:
+ vshError(ctl, "%s", _("You must specify exactly one mac address in"
+ " xml file"));
+ goto cleanup;
+ break;
}
if (vshCommandOptBool(cmd, "persistent")) {
@@ -8610,18 +8640,23 @@ cmdDetachDevice(vshControl *ctl, const vshCmd *cmd)
} else {
ret = virDomainDetachDevice(dom, buffer);
}
- VIR_FREE(buffer);
if (ret < 0) {
+ ret = FALSE;
vshError(ctl, _("Failed to detach device from %s"), from);
- virDomainFree(dom);
- return FALSE;
- } else {
- vshPrint(ctl, "%s", _("Device detached successfully\n"));
+ goto cleanup;
}
+ vshPrint(ctl, "%s", _("Device detached successfully\n"));
+ ret = TRUE;
+
+cleanup:
+ xmlXPathFreeContext(ctxt);
+ if (xml)
+ xmlFreeDoc(xml);
+ VIR_FREE(buffer);
virDomainFree(dom);
- return TRUE;
+ return ret;
}
--
1.7.4
5
4
Here's the latest version of a libxenlight driver for libvirt.
I've added a per-domain libxl_ctx in addition to the driver wide
context. The former is stored in virDomainObject privateData and used
for operations on the domain. The latter is stored in driver private
data and is used for non-domain related libxl calls, e.g. getVersion,
getNodeInfo, etc. This approach was suggested by Ian Jackson and
Stefano Stabellini and appears to be working much better than a single,
driver wide libxl_ctx. I no longer have the restart issues described in
the first patch posting [1].
Your review and comments are much appreciated!
Thanks,
Jim
[1] https://www.redhat.com/archives/libvir-list/2011-February/msg00409.html
3
3
[libvirt] [RFC] virt-disk : a command line tool for modify domain XML's disk of inactive domains.
by KAMEZAWA Hiroyuki 23 Feb '11
by KAMEZAWA Hiroyuki 23 Feb '11
23 Feb '11
Hi, now, with qemu, virsh attach-disk doesn't work with inactive disks and
we need to edit XML with virsh edit.
IIUC, libvirt and virsh is designed as it is.
But I want to modify domain XML via commandline tools
- for middleware, which modify domains by scripting.
- for concsoles, where curses can't work correctly.
- for me, I can't remember XML definition detaisl ;)
So, I write one.
Following script is a script for modify domain XML and allows
- add disks
- delete disks
- show list of disks
I think most of elements defined in http://libvirt.org/formatdomain.html#elementsDisks
is supported. But I'm an only qemu user and didn't test with Xen and other VMs.
What I wanted to hear opinions as 'RFC' is
- Can this be shipped with libvirt as one of a tool ? (with more documents)
(If so, we'll write other scripts for cpu,network,memory,etc...)
- If not, what is the best way other than making this as my house script ?
I'm grad if this is shipped with libvirt is because catching new definition
of XML is easy.
- Doesn't this one work with your environment ?
Example)
[root@bluextal pydom]# ./virt-disk.py --domain Guest02 --virtio --source /dev/iscsi_lvm/disk02
Name : vdb
Device Type : block
Media Type : disk
Bus Type : virtio
Driver Name : qemu
Driver Type : raw
Driver Cache : default
ReadWrite : ReadWrite
Source : /dev/iscsi_lvm/disk02
Address: : AutoFill
Add this device Y/N ? y
[root@bluextal pydom]# virsh dumpxml Guest02
<domain type='kvm'>
.....
<disk type='block' device='disk'>
<driver name='qemu' type='raw'/>
<source dev='/dev/iscsi_lvm/disk02'/>
<target dev='vdb' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</disk>
==
Thanks,
-Kame
==
#!/usr/bin/python
#
#
# 'virt-disk' is a command for maintaining disk entities in XML description
# of libvirt's VM definition. Default vm assumes 'qemu'
#
# Copyright (C) 2011 Fujitsu LTD.
#
# KAMEZAWA Hiroyuki <kamezawa.hiroyu(a)jp.fujitsu.com>
#
# Usage:
#
# Brief help is
# %virt-disk --help
#
# When you want to see list of disks of domain
# %virt-disk --domain <domain name> --list
#
# When you want to remove 'vdb'
# %virt-disk --domain <domain name> --delete vdb
#
# When you want to add block device as virtio block device.
# %virt-disk --domain <domain name> --virtio --source /dev/to/mydisk
#
# When you want to add an IDE cdrom
# %virt-disk --domain <domain name> --ide --media cdrom
# --source /path/to/ISO.img
#
# When you want to add a network image as virtio disk.
# %virt-disk --domain <domain name> --type network --protocol sheepdog
# --host address:port --source resource_name --virtio
#
# This commad does
#
# - parse options.
# - connect libvirt and get domain xml
# - add all devices to disks[] List.
# - add all pci address to PCIS[] List
# - create new BlockDevice object with regard to options.
# - create a XML entry of device
# - insert and save it.
#
import xml.dom
import xml.dom.minidom
import os
import stat
import sys
import libvirt
import re,string
from xml.dom import Node
from optparse import OptionParser,OptionGroup
PCIS = []
disks = []
class Address :
pci = []
drive = []
def __init__(self, type) :
self.type = type
self.domain = None
self.bus = None
self.slot = None
self.function = None
self.controller = None
self.function = None
if type == 'pci' :
PCIS.append(self)
class BlockDevice :
def __init__(self) :
self.type = None
self.media = None
self.driver_cache = None
self.driver_name = None
self.driver_type = None
self.driver_error_policy = None
self.driver_io = None
self.source = None
self.protocol = None
self.protocol_addr = None
self.protocol_port = None
self.target_dev = None
self.target_bus = None
self.readonly = False
self.address_type = None
self.address_bus = ''
self.address_domain = ''
self.address_function = ''
self.address_slot = ''
self.address_controller= ''
self.address_unit=''
self.boot_order = None
self.shareable = False
self.serial = None
self.encrypt_format = None
self.encrypt_type = None
self.encrypt_uuid = None
def get_attr(self, name, attr) :
x = name.getAttribute(attr)
if x == '' :
return None
return x
def find_element(self, ent, name) :
for member in ent.childNodes :
if member.nodeName == name :
return member
return None
def parse_info(self, name) :
# parsing <disk .....
self.type = self.get_attr(name, 'type')
self.media = self.get_attr(name, 'device')
# parsing <driver ....
driver = self.find_element(name, 'driver')
if driver != None :
self.driver_name = self.get_attr(driver, 'name')
if self.driver_name == 'qemu' :
self.driver_type = self.get_attr(driver, 'type')
self.driver_cache = self.get_attr(driver, 'cache')
self.driver_error_policy =\
self.get_attr(driver, 'error_policy')
self.driver_io = self.get_attr(driver, 'io')
# parsing <source
source = self.find_element(name, 'source')
if source != None :
self.source = self.get_attr(source, 'dev')
if self.source == None :
self.source = self.get_attr(source, 'file')
if self.source == None :
self.protocol = self.get_attr(source, 'protocol')
self.source = self.get_attr(source, 'name')
else :
self.source = None
#
# check protocol and host, port
#
if self.protocol != None :
source = self.find_element(name, 'source')
host = self.find_element(source, 'host')
if host != None :
self.protocol_host = self.get_attr(host, 'host')
self.protocol_port = self.get_attr(host, 'port')
# parsing <target
target = self.find_element(name, 'target')
if target != None :
self.target_dev = self.get_attr(target, 'dev')
self.target_bus = self.get_attr(target, 'bus')
# check readonly
if self.find_element(name, 'readonly') != None :
self.readonly = True
# check shareable
if self.find_element(name, 'shareable') != None:
self.shareable = True
# check boot order
boot = self.find_element(name, 'boot')
if boot != None :
self.boot_order = self.get_attr(boot, 'order')
# check shareable
if self.find_element(name, 'shareable') != None :
self.shareable = True
# check address
address = self.find_element(name, 'address')
if address != None :
self.address_type = self.get_attr(address, 'type')
if self.address_type == 'pci' :
self.address_bus = self.get_attr(address, 'bus')
self.address_slot = self.get_attr(address, 'slot')
self.address_function = self.get_attr(address, 'function')
self.address_domain = self.get_attr(address, 'domain')
elif self.address_type == 'drive' :
self.address_bus = self.get_attr(address, 'bus')
self.address_controller = self.get_attr(address, 'controller')
self.address_unit = self.get_attr(address, 'unit')
# check serial ID
serial = self.find_element(name, 'serial')
if serial != None :
for member in serial.childNodes :
if member.nodeType == Node.TEXT_NODE :
self.serial = member.data
# check encryption
encrypt = self.find_element(name, 'encryption')
if encrypt != None :
self.encrypt_format = self.get_attr(encrypt, 'format')
sec = self.find_element(encrypt, 'secret')
if sec != None :
self.encrypt_type = self.get_attr(sec, 'type')
self.encrypt_uuid = self.get_attr(sec, 'uuid')
return True
def show_ent(self, name, value) :
if value != None :
print '%-16s:\t%s' %(name, value)
def show(self) :
self.show_ent('Name', self.target_dev)
self.show_ent('Device Type', self.type)
self.show_ent('Media Type', self.media)
self.show_ent('Bus Type', self.target_bus)
self.show_ent('Driver Name', self.driver_name)
self.show_ent('Driver Type', self.driver_type)
self.show_ent('Driver Cache', self.driver_cache)
self.show_ent('Driver I/O', self.driver_io)
self.show_ent('Error Policy', self.driver_error_policy)
if self.readonly :
self.show_ent('ReadWrite', 'ReadOnly')
else :
self.show_ent('ReadWrite', 'ReadWrite')
if self.shareable :
self.show_ent('Shareable', 'Yes')
self.show_ent('Device Boot Order',self.boot_order)
self.show_ent('Protocol', self.protocol)
self.show_ent('Hostname', self.protocol_addr)
self.show_ent('Port', self.protocol_port)
self.show_ent('Source', self.source)
if self.address_type == None :
self.show_ent('Address:', 'AutoFill')
elif self.address_type == 'pci' :
x = '%s/%s/%s' %\
(self.address_bus, self.address_slot, self.address_function)
self.show_ent('PCI Address', x)
elif self.address_type == 'drive' :
x = '%s/%s/%s'\
%(self.address_controller, self.address_bus, self.address_unit)
self.show_ent('Drive Index', x)
if self.serial != None :
self.show_ent('Serial', self.serial)
if self.encrypt_format != None :
self.show_ent('Encryption', self.encrypt_format)
self.show_ent(' Type', self.encrypt_type)
self.show_ent(' UUID', self.encrypt_uuid)
def is_block_device(node) :
if node.nodeName == 'disk' :
return True
return False
def parse_address(addr) :
type = addr.getAttribute('type')
ent = Address(type)
if ent.type == 'pci' :
ent.bus = addr.getAttribute('bus')
ent.slot = addr.getAttribute('slot')
ent.function = addr.getAttribute('function')
ent.domain = addr.getAttribute('domain')
elif ent.type == 'drive' :
ent.controller = addr.getAttribute('controller')
ent.bus = addr.getAttribute('bus')
ent.unit = addr.getAttribute('unit')
# Nothing happens
return True
def check_pci_conflict(bus, slot, function) :
sloti = int(slot, 16)
for addr in PCIS :
if int(addr.slot, 16) == sloti :
return True
return False
def get_free_pci_slot(devname) :
for i in range(3, 31) : #qemu allows only 32 slots
x = str(i)
if not check_pci_conflict('0x00', x, '0x00') :
slot = '0x%02x'%(i)
return ['0x00', slot, '0x00']
return []
def check_get_free_scsi_slot(index) :
addr = scsi_index_to_addr(index)
conflict = False
for disk in disks :
if disk.target_device != scsi:
continue
if disk.target_controller == addr[0] and\
disk.target_bus == addr[1] and\
disk.target_units == addr[2] :
conflict = True
break
if conflict == False:
return addr
return []
def check_drive_conflict(type, controller, bus, unit) :
for addr in drives :
conflict = False
for disk in disks :
if disk.target_bus != 'type' :
continue
if disk.address_controller == controller and\
disk.address_bus == bus and\
disk.address_unit == unit :
conflict = True
break
return conflict
return True
def check_device_conflict(devices, name) :
for dev in devices :
if dev.target_dev == name :
return True
return False
def gen_scsi_name_from_index(index) :
name = 'sd'
if index < 26 :
name = name + chr(ord('a') + index)
elif index < (26 + (26 * 26)) :
x = index / 26 - 1
y = index % 26
name = name + chr(ord('a') + x)
name = name + chr(ord('a') + y)
else :
x = (index / 26 - 1) / 26 - 1
y = (index / 26 - 1) % 26
x = index % 26
name = name + chr(ord('a') + x)
name = name + chr(ord('a') + y)
name = name + chr(ord('a') + z)
return name
def gen_device_name(devices, head) :
if head == 'hd' :
for x in 'abcd' :
name = 'hd' + x
if not check_device_conflict(devices, name) :
return name
if head == 'vd' :
for x in range(0, 26) :
name = head + chr(ord('a') + x)
if not check_device_conflict(devices, name) :
return name
if head == 'sd' :
for index in range(0, 18278) :
name = gen_scsi_name_from_index(index)
if not check_device_conflict(devices, name) :
return name
return None
#
# Commandline Parser
# Using optparse package. Deafault value is below.
#
usage='usage:%prog --domain Domain <options>....'
parser = OptionParser(usage)
def help_choice(help, list, default) :
help = help + " "
help = help + ",".join(list)
if (default == True) :
help = help + " default: %default"
return help
parser.add_option('-c', '--connect', action='store',
type='string', dest='connect_uri', help='libvirtd connect URI')
parser.add_option('-d', '--domain', action='store',
type='string',dest="domain",
help='domain name.')
parser.add_option('-l', '--list', action='store_true', dest='show_list',
help='see device list')
parser.add_option('--delete', action='store', dest='delete', type='string'
, help='remove device')
#
# 'block' or 'file' can be detected by --source option.
#
typeChoices=('block','file','network','dir')
parser.add_option('--type', choices=typeChoices, dest='type', type='choice',
help=help_choice('device type:', typeChoices, False))
mediaChoices=('disk','cdrom')
parser.add_option('--media', choices=mediaChoices,
type='choice',dest="media",
help=help_choice('media type:', mediaChoices, True))
parser.add_option('--source', action='store', type='string', dest='source',
help='select source file/device to be shown as disk')
protocolChoices=('nbd','rbd', 'sheepdog')
parser.add_option('--protocol', choices=protocolChoices,
type='choice', dest='protocol',
help=help_choice('netdisk protocol:', protocolChoices, False))
parser.add_option('--host', action='store', type='string', dest='host',
help='<host:port> for rbd and sheepdog, network devices')
parser.add_option('--devname', action='store', type='string', dest='devname',
help='device name to be shown to guest(auto at default)')
qemu_group = OptionGroup(parser, "Qemu Options")
qemuFormatChoices=('raw','bochs','qcow2','qed')
qemu_group.add_option('--qemu_disk_format', choices=qemuFormatChoices,
type='choice', dest='qemu_format',
help=help_choice('disk format(qemu):',qemuFormatChoices, True))
ioChoices=('threads','native')
qemu_group.add_option('--io',choices=ioChoices, type='choice', dest='io',
help=help_choice('io option(qemu):', ioChoices, False))
cacheChoices=('none','writeback','writethrough','default')
qemu_group.add_option('--cache', choices=cacheChoices, type='choice',
dest='cache', help=help_choice('cache policy:(qemu)', cacheChoices, True))
errorChoices=('stop','ignore','enospace')
parser.add_option('--error_policy', choices=errorChoices, type='choice',
dest='error_policy',
help=help_choice('error policy:', errorChoices, False))
xen_group = OptionGroup(parser, "Xen Options")
xenDriverChoices=('tap','tap2','phy','file')
xen_group.add_option('--driver', choices=xenDriverChoices,
type='choice', dest='driver_name',
help=help_choice('Xen driver type:', xenDriverChoices, False))
xen_group.add_option('--aio', action='store_true',
dest='xen_aio', help='using Xen aio driver')
parser.add_option('--virtio', action='store_true',
dest='virtio', help='create a virtio device')
parser.add_option('--readonly', action='store_true',
dest='readonly', help='attach device as read only')
parser.add_option('--scsi', action='store_true',
dest='scsi', help='create a scsi device')
parser.add_option('--ide', action='store_true',
dest='ide', help='create a ide device')
parser.add_option('--pci', action='store', dest='pci', type='string',
help='customize pci resource by hand as bus:slot:function')
parser.add_option('--drive_id', action='store', dest='drive_id', type='string',
help='customize ide/scsi resource ID as controller:bus:unit')
parser.add_option('--yes', action='store_true', dest='yes',
help='don\'t ask before save')
parser.add_option('--nosave', action='store_true', dest='nosave',
help='show created device XML instead of saving.')
parser.add_option('--boot_order', action='store', dest='boot_order',
type='int', help='boot order of the device', metavar='Num')
parser.add_option('--shareable', action='store_true', dest='shareable',
help='the device can be shareable between device')
parser.add_option('--serial', action='store', dest='serial',
type='string', help='optional serial ID of the device')
EncChoices = ['qcow']
qemu_group.add_option('--encryption_format', choices=EncChoices,
type='choice', dest='encryption_format',
metavar='qcow', help='Only \"qcow\" is supported')
EncTypeChoices =['passphrase']
qemu_group.add_option('--encryption_type', choices=EncTypeChoices,
type='choice', dest='encryption_type',
help=help_choice('encription_type', EncTypeChoices, True))
qemu_group.add_option('--encryption_uuid', action='store',
metavar='UUID', dest='encryption_uuid',
help='UUID for encrypted deivce')
parser.add_option_group(qemu_group)
parser.add_option_group(xen_group)
parser.set_defaults(list=False, media='disk')
parser.set_defaults(qemu_format='raw', cache='default', media='disk')
parser.set_defaults(virtio=False, readonly=False, scsi=False, ide=False)
parser.set_defaults(xen_aio=False,)
parser.set_defaults(yes=False)
(options, args) = parser.parse_args(sys.argv)
#
# Confirm domain XML is not updated since we opened it.
#
def check_domain_unchanged(origin, domain):
if origin != domain.XMLDesc(0) :
print 'Domain file may be updated while we open'
print 'please retry'
exit(1)
#
# Connect libvirt and get domain information.
#
if options.domain == None :
print 'please specify domain to be modified'
exit(1)
try :
conn = libvirt.open(options.connect_uri)
except:
print 'Can\'t connect libvirt with URI %s'%(options.connect_uri)
exit(1)
conn_uri = conn.getURI()
info = re.split(':/', conn_uri)
# From the name of connection URI, we detect vmname.
vmname = info[0]
# domain look up.
domain = conn.lookupByName(options.domain)
if domain == None:
print 'Can\'t find domain %s' %(options.domain)
exit(1)
# read XML description.
origin = domain.XMLDesc(0)
dom = xml.dom.minidom.parseString(domain.XMLDesc(0))
# At 1st, we need to find <device> block.
names = dom.getElementsByTagName('devices')
if (names == None) :
print '<device> element not found in %s\n' % filename
exit(1)
for devices in names :
if devices.hasChildNodes() :
for name in devices.childNodes :
if (is_block_device(name)) :
disk = BlockDevice()
disk.parse_info(name)
disks.append(disk)
if name.hasChildNodes() :
for elem in name.childNodes :
if elem.nodeName == 'address' :
addr = parse_address(elem)
#
# Show List.
#
if options.show_list == True :
for disk in disks :
disk.show()
print ''
exit(0)
# delete is easy.
if options.delete != None :
disk = None
for name in devices.childNodes :
if (not is_block_device(name)) :
continue
disk = BlockDevice()
disk.parse_info(name)
if disk.target_dev == options.delete :
devices.removeChild(name)
break
disk = None
if disk == None :
print 'no such device %s'%(options.delete)
exit(1)
if not options.yes :
print 'You\'ll delete this device!'
disk.show()
x = raw_input('Really delete Y/N ? ')
if x != 'Y' and x != 'y' :
exit(0)
str = dom.toxml()
check_domain_unchanged(origin, domain)
conn.defineXML(str)
exit(1)
#
# Build a newdisk information from command line options
# and default values.
#
newdisk = BlockDevice()
if options.type != None :
newdisk.type = options.type
newdisk.media = options.media
#
# qemu only has a drive name as 'qemu'. 'type' and 'cache' are selectable.
#
if vmname == 'qemu' :
newdisk.driver_name = 'qemu'
newdisk.driver_type = options.qemu_format
if options.cache == None :
newdisk.driver_cache = 'default'
else :
newdisk.driver_cache = options.cache
else : # Xen can select drive name.
newdisk.driver_name = options.driver_name
if options.xen_aio == True :
newdisk.driver_type = 'aio'
if options.error_policy != None :
newdisk.driver_error_policy = options.error_policy
if options.io != None :
newdisk.io = options.io
# Make readonly if crdom is specified.
if options.media == 'cdrom' or options.readonly == True:
newdisk.readonly = True;
# Check Device Name and detect device bus from device name.
if options.devname != None :
if re.match('vd[a-z]', options.devname) :
newdisk.target_dev = options.devname
newdisk.target_bus = 'virtio'
elif re.match('hd[a-d]', options.devname) :
newdisk.target_dev = options.devname
newdisk.target_bus = 'ide'
elif re.match('sd[a-z]', options.devname) :
newdisk.target_dev = options.devname
newdisk.target_bus = 'scsi'
else :
newdisk.target_dev = options.devname
#
# Define device name automatically with regard to the bus.
#
if options.virtio == True :
newdisk.target_bus = 'virtio'
if options.devname == None:
newdisk.target_dev = gen_device_name(disks, 'vd')
if newdisk.target_dev == None:
print 'failed to define virtio drive name as vd*'
print 'please define by hand with --devname'
exit(1)
elif options.ide == True :
newdisk.target_bus = 'ide'
if options.devname == None:
newdisk.target_dev = gen_device_name(disks, 'hd')
if newdisk.target_dev == None :
print 'failed to define ide drive name as hd*'
print 'please define by hand with --devname'
exit(1)
elif options.scsi == True :
newdisk.target_bus = 'scsi'
if options.devname == None:
newdisk.target_dev = gen_device_name(disks, 'sd')
if newdisk.target_dev == None :
print 'failed to define scsi drive name as sd*'
print 'please define by hand with --devname'
exit(1)
#
# If we can't detelct target bus, retrun error.
#
if newdisk.target_bus == None :
print 'need to specify device name or target bus for drive'
exit(1)
#
# If there is a device with the same name, error.
#
if check_device_conflict(disks, newdisk.target_dev) :
print 'device name conflicts %s' %(newdisk.target_dev)
print 'please specify an other name with --devname'
#
# Handle 'source' type.
#
if options.source != None and options.protocol == None:
# No network case. check local FS.
# Only absolute path is allowed.
if options.source[0] != '/' :
print 'please use absolute path for source %s:' %(options.source)
exit(1)
try:
mode = os.stat(options.source)[stat.ST_MODE]
except:
print 'can\'t handle file %s' %(options.source)
exit(1)
#
# check 'file' and 'block'
#
newdisk.source = options.source
if stat.S_ISREG(mode) != 0:
if newdisk.type == None :
newdisk.type = 'file'
if newdisk.type != 'file' :
print '%s specified in --source is file' %(options.source)
exit(1)
if stat.S_ISBLK(mode) != 0 :
if newdisk.type == None :
newdisk.type = 'block'
if newdisk.type != 'block' :
print '%s specified in --source is blkdev' %(options.source)
exit(1)
if newdisk.type == None :
print 'can\'t detect source type %s'%(options.source)
elif options.type == 'network' :
if options.protocol == None :
print 'need to select protocol for network drive.'
exit(1)
newdisk.protocol = options.protocol
if options.source == None :
print 'source name for network should be privded --soruce'
exit(1)
newdisk.source = options.source
if not re.match('[0-9a-zA-z\._-]+:[0-9]+', options.host) :
print 'host should be specified in address:port manner'
exit(1)
(addr, port) = re.split(':', options.host)
newdisk.protocol_addr = addr
newdisk.protocol_port = port
if options.media != 'cdrom' and options.source == None :
print 'you need to specify source if not cdrom'
exit(1)
#
# Define PCI/IDE/SCSI drive address.
# (Usually, all this will be defined automatically.)
#
# format check
if options.pci != None :
if options.drive_id != None :
print 'pci address and drive-id cannot be set at the same time'
exit(1)
if not re.match("0x[0-9a-f]+:0x[0-9a-f]+:0x[0-9-a-f]", options.pci) :
print 'bad pci address ',options.pci
print '0xXX:0xXX:0xXX is expected',options.pci
exit(1)
if options.drive_id != None :
if not re.match("[0-9]+:[0-9]+:[0-9]+", options.drive_id) :
print 'bad drive_id address', options.drive_id
exit(1)
# define BUS ID.
#
# In this case, device name should meet bus ID(especially IDE),
# which the user specified. The user should specify device
# name by himself.
#
if options.pci != None or options.drive_id != None :
if options.devname == None :
print 'We recommend that --drive_id should be used with --devname',
print 'device name <-> drive ID relationship is at random, now'
if options.pci != None :
pci = re.split(':', options.pci)
if '0x00' != pci[0] :
print 'only bus 0x00 can be used in pci'
exit(1)
if check_pci_conflict(pci[0], pci[1], pci[2]) :
print 'bus %s conflicts' % (options.pci)
newdisk.address_type = 'pci'
newdisk.address_bus = pci[0]
newdisk.address_slot = pci[1]
newdisk.address_function = pci[2]
elif options.drive_id != None :
drive = re.split(':', options.drive_id)
if options.ide == True :
if check_drive_conflict('ide', drive[0],drive[1],drive[2]) :
print 'drive %s conflicts' % (options.drive_id)
else :
if check_drive_conflict('scsi',drive[0], drive[1], drive[2]) :
print 'drive %s conflicts' % (options.drive_id)
newdisk.address_type = 'drive'
newdisk.address_controller = drive[0]
newdisk.address_bus = drive[1]
newdisk.address_unit = drive[2]
if options.boot_order != None :
newdisk.boot_order = str(options.boot_order)
if options.shareable == True:
newdisk.shareab;e = True
if options.serial != None :
newdisk.serial = options.serial
#
# Handle encryption
#
if options.encryption_format != None :
if options.encryption_type == None or\
options.encryption_uuid == None :
print 'encryption passphrase or UUID is not specified'
exit(1)
newdisk.encrypt_format = options.encryption_format
newdisk.encrypt_type = options.encryption_type
newdisk.encrypt_uuid = options.encryption_uuid
#
# Okay, we got all required information. Show the newdisk.
#
if options.yes != True :
newdisk.show()
#
# Build XML from 'newdisk'
#
def append_attribute(doc, elem, attr, value) :
x = doc.createAttribute(attr)
elem.setAttributeNode(x)
elem.setAttribute(attr, value)
def append_text(doc, elem, text) :
x = doc.createTextNode(text)
elem.appendChild(x)
def append_element(doc, parent, name, level) :
append_text(doc, parent, '\n')
while level > 0 :
append_text(doc, parent, ' ')
level = level - 1
element = doc.createElement(name)
parent.appendChild(element)
return element
# <disk ....
element = dom.createElement('disk')
append_attribute(dom, element, 'device', newdisk.media)
append_attribute(dom, element, 'type', newdisk.type)
#
# <driver ...
#
child = append_element(dom, element, 'driver', 3)
append_attribute(dom, child, 'name', newdisk.driver_name)
append_attribute(dom, child, 'type', newdisk.driver_type)
if newdisk.driver_cache != None :
append_attribute(dom, child, 'cache', newdisk.driver_cache)
if newdisk.driver_error_policy != None :
append_attribute(dom, child, 'error_policy', newdisk.driver_error_policy)
if newdisk.driver_io != None :
append_attribute(dom, child, 'io', newdisk.driver_io)
#
# <source....
#
if newdisk.type == 'file' and newdisk.source != None:
child = append_element(dom, element, 'source', 3)
append_attribute(dom, child, 'file', options.source)
elif newdisk.type == 'block' and newdisk.source != None:
child = append_element(dom, element, 'source', 3)
append_attribute(dom, child, 'dev', options.source)
elif newdisk.type == 'network' and newdisk.protocol != None:
child = append_element(dom, element, 'source', 3)
append_attribute(dom, child, 'protocol', options.protocol)
append_attribute(dom, child, 'name', options.source)
host = append_element(dom, child, 'host', 4)
address = re.split(':',options.host)
append_attribute(dom, host, 'name', address[0])
append_attribute(dom, host, 'port', address[1])
#
# <target....
#
child = append_element(dom, element, 'target', 3)
append_attribute(dom, child, 'dev', newdisk.target_dev)
append_attribute(dom, child, 'bus', newdisk.target_bus)
#
# <address.....
# libvirt will do auto-fill in typical case.
#
if newdisk.address_type != None :
child = append_element(dom, element, 'address', 3)
append_attribute(dom, child, 'type', newdisk.address_type)
if newdisk.address_type == 'pci' :
append_attribute(dom, child, 'bus', newdisk.address_bus)
append_attribute(dom, child, 'slot', newdisk.address_slot)
append_attribute(dom, child, 'function', newdisk.address_function)
append_attribute(dom, child, 'domain', '0x0000')
elif newdisk.address_type == 'drive' :
append_attribute(dom, child, 'controller', newdisk.address_controller)
append_attribute(dom, child, 'unit', newdisk.address_unit)
append_attribute(dom, child, 'bus', newdisk.address_bus)
append_attribute(dom, child, 'domain', '0x0000')
#
# <readonly
#
if newdisk.readonly == True:
append_element(dom, element, 'readonly', 3)
#
# <shareable
#
if newdisk.shareable == True:
append_element(dom, element, 'readonly', 3)
#
# <boot
#
if newdisk.boot_order != None:
child = append_element(dom, element, 'boot', 3)
append_attribute(dom, child, 'order', newdisk.boot_order)
#
# <serial
#
if newdisk.serial != None:
child = append_element(dom, element, 'serial', 3)
append_text(dom, child, newdisk.serial)
#
# <encryption
#
if newdisk.encrypt_format != None :
child = append_element(dom, element, 'encryption', 3)
append_attribute(dom, child, 'format', newdisk.encrypt_format)
secret = append_element(dom, child, 'secret', 4)
append_attribute(dom, secret, 'type', newdisk.encrypt_type)
append_attribute(dom, secret, 'uuid', newdisk.encrypt_uuid)
append_text(dom, child, '\n')
# indent for </disk>
append_text(dom, element, '\n')
append_text(dom, element, ' ')
if options.nosave == True :
print ''
print element.toxml('utf-8')
exit(0)
#
# Insert newdisk to the tail of disks.
#
for devices in names :
if not devices.hasChildNodes() :
continue
for name in devices.childNodes :
if name.nodeName == 'controller' :
break
if name == None :
append_text(dom, devices, ' ')
x = dom.createTextNode('\n')
devices.appendChild(element)
devices.insertBefore(x, name)
else:
devices.insertBefore(element, name)
x = dom.createTextNode('\n ')
devices.insertBefore(x, name)
if not options.yes :
x = raw_input('Add this device Y/N ? ')
if x != 'y' and x != 'Y' :
exit(1)
str = dom.toxml('utf-8')
check_domain_unchanged(origin, domain)
try:
conn.defineXML(str)
except:
print 'Failed'
3
14
The virFileAbsPath was not taking into account the '/' directory
separator when allocating memory for combining cwd + path. Convert
to use virAsprintf to avoid this type of bug completely.
* src/util/util.c: Convert virFileAbsPath to use virAsprintf
---
src/util/util.c | 19 ++++++-------------
1 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c
index 965e96d..452f592 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -1990,30 +1990,23 @@ cleanup:
int virFileAbsPath(const char *path, char **abspath)
{
char *buf;
- int cwdlen;
if (path[0] == '/') {
- buf = strdup(path);
- if (buf == NULL)
- return(-1);
+ if (!(*abspath = strdup(path)))
+ return -1;
} else {
buf = getcwd(NULL, 0);
if (buf == NULL)
- return(-1);
+ return -1;
- cwdlen = strlen(buf);
- /* cwdlen includes the null terminator */
- if (VIR_REALLOC_N(buf, cwdlen + strlen(path) + 1) < 0) {
+ if (virAsprintf(abspath, "%s/%s", buf, path) < 0) {
VIR_FREE(buf);
errno = ENOMEM;
- return(-1);
+ return -1;
}
-
- buf[cwdlen] = '/';
- strcpy(&buf[cwdlen + 1], path);
+ VIR_FREE(buf);
}
- *abspath = buf;
return 0;
}
--
1.7.4
2
2
The virFileAbsPath was not taking into account the '/' directory
separator when allocating memory for combining cwd + path. Convert
to use virAsprintf to avoid this type of bug completely.
* src/util/util.c: Convert virFileAbsPath to use virAsprintf
---
src/util/util.c | 19 ++++++-------------
1 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c
index 965e96d..452f592 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -1990,30 +1990,23 @@ cleanup:
int virFileAbsPath(const char *path, char **abspath)
{
char *buf;
- int cwdlen;
if (path[0] == '/') {
- buf = strdup(path);
- if (buf == NULL)
- return(-1);
+ if (!(*abspath = strdup(path)))
+ return -1;
} else {
buf = getcwd(NULL, 0);
if (buf == NULL)
- return(-1);
+ return -1;
- cwdlen = strlen(buf);
- /* cwdlen includes the null terminator */
- if (VIR_REALLOC_N(buf, cwdlen + strlen(path) + 1) < 0) {
+ if (virAsprintf(abspath, "%s/%s", buf, path) < 0) {
VIR_FREE(buf);
errno = ENOMEM;
- return(-1);
+ return -1;
}
-
- buf[cwdlen] = '/';
- strcpy(&buf[cwdlen + 1], path);
+ VIR_FREE(buf);
}
- *abspath = buf;
return 0;
}
--
1.7.4
2
1
In a couple of commands virsh catches & ignores errors, but fails
to reset last_error. Thus the error is ignored, but still reported
to the user.
* tools/virsh.c: Reset last_error if ignoring an error
---
tools/virsh.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 2837e0f..62fca17 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -2122,6 +2122,9 @@ cmdDominfo(vshControl *ctl, const vshCmd *cmd)
if (last_error->code != VIR_ERR_NO_SUPPORT) {
virDomainFree(dom);
return FALSE;
+ } else {
+ virFreeError(last_error);
+ last_error = NULL;
}
} else {
/* Only print something if a security model is active */
@@ -2498,6 +2501,8 @@ cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
if (!tmp || virStrToLong_i(tmp + 1, &tmp, 10, &count) < 0)
count = -1;
}
+ virFreeError(last_error);
+ last_error = NULL;
VIR_FREE(xml);
}
--
1.7.4
2
1