[libvirt] [PATCH] maint: Make ctags work out of the box
by Jiri Denemark
The .ctags file specifies default options for ctags so that it does not
ignore libvirt.h.in and ignores uninteresting files. As a result, you
can just run "ctags" and navigating to a public API won't get you to a
useless entry in api.html.
---
.ctags | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 .ctags
diff --git a/.ctags b/.ctags
new file mode 100644
index 0000000..75e9753
--- /dev/null
+++ b/.ctags
@@ -0,0 +1,5 @@
+--recurse
+--exclude=*.orig
+--exclude=*.html
+--exclude=*.html.in
+--langmap=c:+.h.in
--
1.8.3.2
11 years, 4 months
[libvirt] [PATCH] esx: Support for disk-only and quiescing snapshots.
by Geoff Hickey
Add support for creating disk-only (no memory) snapshots in esx, and
for quiescing the VM before taking the snapshot. The VMware API
supports these operations directly, so adding support to libvirt is
just a matter of setting the flags correctly when calling
VMware. VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY and
VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE are now valid flags for esx.
---
src/esx/esx_driver.c | 14 ++++++++++----
1 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index fbe43c2..d69576d 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -4209,9 +4209,14 @@ esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
esxVI_TaskInfoState taskInfoState;
char *taskInfoErrorMessage = NULL;
virDomainSnapshotPtr snapshot = NULL;
+ bool diskOnly = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) != 0;
+ bool quiesce = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) != 0;
- /* ESX has no snapshot metadata, so this flag is trivial. */
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
+ /* ESX supports disk-only and quiesced snapshots, but has no snapshot *
+ * metadata. */
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
+ VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
+ VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
if (esxVI_EnsureSession(priv->primary) < 0) {
return NULL;
@@ -4249,8 +4254,9 @@ esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
if (esxVI_CreateSnapshot_Task(priv->primary, virtualMachine->obj,
def->name, def->description,
- esxVI_Boolean_True,
- esxVI_Boolean_False, &task) < 0 ||
+ diskOnly ? esxVI_Boolean_False : esxVI_Boolean_True,
+ quiesce ? esxVI_Boolean_True : esxVI_Boolean_False,
+ &task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
esxVI_Occurrence_RequiredItem,
priv->parsedUri->autoAnswer, &taskInfoState,
--
1.7.1
11 years, 4 months
Re: [libvirt] [PATCH] add console support in libxl
by Jim Fehlig
Bamvor Jian Zhang wrote:
> Hi, Jim
>
> thanks your reply. one comment below.
>
> >>>已写入 "Jim Fehlig <jfehlig(a)suse.com>"> On 07/04/2013 05:58 AM, Bamvor Jian Zhang wrote:
>
>> BTW, do all of these types work with Xen? I've only tested with type 'pty',
>>
>> which works fine with both pv and hvm guests.
>>
> i only test the pty type too. lots of type is introduced in 2b84e445(Add libxenlight driver), i add the missing type compare with qemu driver. maybe it will be used in future. for now, only pty is needed for my console patch.
>
I found some time today to test type={unix,tcp,file,udp} and they seem
to work fine with Xen 4.3, but HVM guests only. I suppose that is
expected since qemu is not being used for serial ports for PV guests.
Can you fix all my previous comments, rebase the patch, and send a V2?
Oh, and one more thing...
> @@ -4739,6 +4857,7 @@ static virDriver libxlDriver = {
> .domainManagedSave = libxlDomainManagedSave, /* 0.9.2 */
> .domainHasManagedSaveImage = libxlDomainHasManagedSaveImage, /* 0.9.2 */
> .domainManagedSaveRemove = libxlDomainManagedSaveRemove, /* 0.9.2 */
> + .domainOpenConsole = libxlDomainOpenConsole, /* 1.0.8 */
> .domainIsActive = libxlDomainIsActive, /* 0.9.0 */
> .domainIsPersistent = libxlDomainIsPersistent, /* 0.9.0 */
> .domainIsUpdated = libxlDomainIsUpdated, /* 0.9.0 */
AFAIK, the next release will be 1.1.1.
Regards,
Jim
11 years, 4 months
[libvirt] xen: Add interface versions for Xen 4.3
by Stefan Bader
I tried to follow previous changes. This worked for me using Xen-4.3
and the xm stack (I know rather deprecated but as long as one can get
it working, still).
-Stefan
---
>From 4c36fb22f01689472f6e170a8df6e08fd8c27a42 Mon Sep 17 00:00:00 2001
From: Stefan Bader <stefan.bader(a)canonical.com>
Date: Mon, 15 Jul 2013 19:25:23 +0200
Subject: [PATCH] xen: Add interface versions for Xen 4.3
Xen 4.3 changes sysctl version to 0xA and domctl version to 0x9. Update
the hypervisor driver to work with those.
Signed-off-by: Stefan Bader <stefan.bader(a)canonical.com>
---
src/xen/xen_hypervisor.c | 129 ++++++++++++++++++++++++++++++++++------------
1 file changed, 97 insertions(+), 32 deletions(-)
diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c
index 39e641e..ff92556 100644
--- a/src/xen/xen_hypervisor.c
+++ b/src/xen/xen_hypervisor.c
@@ -271,6 +271,24 @@ struct xen_v2d8_getdomaininfo {
};
typedef struct xen_v2d8_getdomaininfo xen_v2d8_getdomaininfo;
+struct xen_v2d9_getdomaininfo {
+ domid_t domain; /* the domain number */
+ uint32_t flags; /* flags, see before */
+ uint64_t tot_pages ALIGN_64; /* total number of pages used */
+ uint64_t max_pages ALIGN_64; /* maximum number of pages allowed */
+ uint64_t outstanding_pages ALIGN_64;
+ uint64_t shr_pages ALIGN_64; /* number of shared pages */
+ uint64_t paged_pages ALIGN_64; /* number of paged pages */
+ uint64_t shared_info_frame ALIGN_64; /* MFN of shared_info struct */
+ uint64_t cpu_time ALIGN_64; /* CPU time used */
+ uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */
+ uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */
+ uint32_t ssidref;
+ xen_domain_handle_t handle;
+ uint32_t cpupool;
+};
+typedef struct xen_v2d9_getdomaininfo xen_v2d9_getdomaininfo;
+
union xen_getdomaininfo {
struct xen_v0_getdomaininfo v0;
struct xen_v2_getdomaininfo v2;
@@ -278,6 +296,7 @@ union xen_getdomaininfo {
struct xen_v2d6_getdomaininfo v2d6;
struct xen_v2d7_getdomaininfo v2d7;
struct xen_v2d8_getdomaininfo v2d8;
+ struct xen_v2d9_getdomaininfo v2d9;
};
typedef union xen_getdomaininfo xen_getdomaininfo;
@@ -288,6 +307,7 @@ union xen_getdomaininfolist {
struct xen_v2d6_getdomaininfo *v2d6;
struct xen_v2d7_getdomaininfo *v2d7;
struct xen_v2d8_getdomaininfo *v2d8;
+ struct xen_v2d8_getdomaininfo *v2d9;
};
typedef union xen_getdomaininfolist xen_getdomaininfolist;
@@ -325,7 +345,9 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
#define XEN_GETDOMAININFOLIST_ALLOC(domlist, size) \
(hv_versions.hypervisor < 2 ? \
(VIR_ALLOC_N(domlist.v0, (size)) == 0) : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ (VIR_ALLOC_N(domlist.v2d9, (size)) == 0) : \
+ (hv_versions.dom_interface == 8 ? \
(VIR_ALLOC_N(domlist.v2d8, (size)) == 0) : \
(hv_versions.dom_interface == 7 ? \
(VIR_ALLOC_N(domlist.v2d7, (size)) == 0) : \
@@ -333,12 +355,14 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
(VIR_ALLOC_N(domlist.v2d6, (size)) == 0) : \
(hv_versions.dom_interface == 5 ? \
(VIR_ALLOC_N(domlist.v2d5, (size)) == 0) : \
- (VIR_ALLOC_N(domlist.v2, (size)) == 0))))))
+ (VIR_ALLOC_N(domlist.v2, (size)) == 0)))))))
#define XEN_GETDOMAININFOLIST_FREE(domlist) \
(hv_versions.hypervisor < 2 ? \
VIR_FREE(domlist.v0) : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ VIR_FREE(domlist.v2d9) : \
+ (hv_versions.dom_interface == 8 ? \
VIR_FREE(domlist.v2d8) : \
(hv_versions.dom_interface == 7 ? \
VIR_FREE(domlist.v2d7) : \
@@ -346,12 +370,14 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
VIR_FREE(domlist.v2d6) : \
(hv_versions.dom_interface == 5 ? \
VIR_FREE(domlist.v2d5) : \
- VIR_FREE(domlist.v2))))))
+ VIR_FREE(domlist.v2)))))))
#define XEN_GETDOMAININFOLIST_CLEAR(domlist, size) \
(hv_versions.hypervisor < 2 ? \
memset(domlist.v0, 0, sizeof(*domlist.v0) * size) : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ memset(domlist.v2d9, 0, sizeof(*domlist.v2d9) * size) : \
+ (hv_versions.dom_interface == 8 ? \
memset(domlist.v2d8, 0, sizeof(*domlist.v2d8) * size) : \
(hv_versions.dom_interface == 7 ? \
memset(domlist.v2d7, 0, sizeof(*domlist.v2d7) * size) : \
@@ -359,12 +385,14 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
memset(domlist.v2d6, 0, sizeof(*domlist.v2d6) * size) : \
(hv_versions.dom_interface == 5 ? \
memset(domlist.v2d5, 0, sizeof(*domlist.v2d5) * size) : \
- memset(domlist.v2, 0, sizeof(*domlist.v2) * size))))))
+ memset(domlist.v2, 0, sizeof(*domlist.v2) * size)))))))
#define XEN_GETDOMAININFOLIST_DOMAIN(domlist, n) \
(hv_versions.hypervisor < 2 ? \
domlist.v0[n].domain : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ domlist.v2d9[n].domain : \
+ (hv_versions.dom_interface == 8 ? \
domlist.v2d8[n].domain : \
(hv_versions.dom_interface == 7 ? \
domlist.v2d7[n].domain : \
@@ -372,12 +400,14 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
domlist.v2d6[n].domain : \
(hv_versions.dom_interface == 5 ? \
domlist.v2d5[n].domain : \
- domlist.v2[n].domain)))))
+ domlist.v2[n].domain))))))
#define XEN_GETDOMAININFOLIST_UUID(domlist, n) \
(hv_versions.hypervisor < 2 ? \
domlist.v0[n].handle : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ domlist.v2d9[n].handle : \
+ (hv_versions.dom_interface == 8 ? \
domlist.v2d8[n].handle : \
(hv_versions.dom_interface == 7 ? \
domlist.v2d7[n].handle : \
@@ -385,12 +415,14 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
domlist.v2d6[n].handle : \
(hv_versions.dom_interface == 5 ? \
domlist.v2d5[n].handle : \
- domlist.v2[n].handle)))))
+ domlist.v2[n].handle))))))
#define XEN_GETDOMAININFOLIST_DATA(domlist) \
(hv_versions.hypervisor < 2 ? \
(void*)(domlist->v0) : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ (void*)(domlist->v2d9) : \
+ (hv_versions.dom_interface == 8 ? \
(void*)(domlist->v2d8) : \
(hv_versions.dom_interface == 7 ? \
(void*)(domlist->v2d7) : \
@@ -398,12 +430,14 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
(void*)(domlist->v2d6) : \
(hv_versions.dom_interface == 5 ? \
(void*)(domlist->v2d5) : \
- (void*)(domlist->v2))))))
+ (void*)(domlist->v2)))))))
#define XEN_GETDOMAININFO_SIZE \
(hv_versions.hypervisor < 2 ? \
sizeof(xen_v0_getdomaininfo) : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ sizeof(xen_v2d9_getdomaininfo) : \
+ (hv_versions.dom_interface == 8 ? \
sizeof(xen_v2d8_getdomaininfo) : \
(hv_versions.dom_interface == 7 ? \
sizeof(xen_v2d7_getdomaininfo) : \
@@ -411,12 +445,14 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
sizeof(xen_v2d6_getdomaininfo) : \
(hv_versions.dom_interface == 5 ? \
sizeof(xen_v2d5_getdomaininfo) : \
- sizeof(xen_v2_getdomaininfo))))))
+ sizeof(xen_v2_getdomaininfo)))))))
#define XEN_GETDOMAININFO_CLEAR(dominfo) \
(hv_versions.hypervisor < 2 ? \
memset(&(dominfo.v0), 0, sizeof(xen_v0_getdomaininfo)) : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ memset(&(dominfo.v2d9), 0, sizeof(xen_v2d9_getdomaininfo)) : \
+ (hv_versions.dom_interface == 8 ? \
memset(&(dominfo.v2d8), 0, sizeof(xen_v2d8_getdomaininfo)) : \
(hv_versions.dom_interface == 7 ? \
memset(&(dominfo.v2d7), 0, sizeof(xen_v2d7_getdomaininfo)) : \
@@ -424,12 +460,14 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
memset(&(dominfo.v2d6), 0, sizeof(xen_v2d6_getdomaininfo)) : \
(hv_versions.dom_interface == 5 ? \
memset(&(dominfo.v2d5), 0, sizeof(xen_v2d5_getdomaininfo)) : \
- memset(&(dominfo.v2), 0, sizeof(xen_v2_getdomaininfo)))))))
+ memset(&(dominfo.v2), 0, sizeof(xen_v2_getdomaininfo))))))))
#define XEN_GETDOMAININFO_DOMAIN(dominfo) \
(hv_versions.hypervisor < 2 ? \
dominfo.v0.domain : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ dominfo.v2d9.domain : \
+ (hv_versions.dom_interface == 8 ? \
dominfo.v2d8.domain : \
(hv_versions.dom_interface == 7 ? \
dominfo.v2d7.domain : \
@@ -437,12 +475,14 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
dominfo.v2d6.domain : \
(hv_versions.dom_interface == 5 ? \
dominfo.v2d5.domain : \
- dominfo.v2.domain)))))
+ dominfo.v2.domain))))))
#define XEN_GETDOMAININFO_CPUTIME(dominfo) \
(hv_versions.hypervisor < 2 ? \
dominfo.v0.cpu_time : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ dominfo.v2d9.cpu_time : \
+ (hv_versions.dom_interface == 8 ? \
dominfo.v2d8.cpu_time : \
(hv_versions.dom_interface == 7 ? \
dominfo.v2d7.cpu_time : \
@@ -450,13 +490,15 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
dominfo.v2d6.cpu_time : \
(hv_versions.dom_interface == 5 ? \
dominfo.v2d5.cpu_time : \
- dominfo.v2.cpu_time)))))
+ dominfo.v2.cpu_time))))))
#define XEN_GETDOMAININFO_CPUCOUNT(dominfo) \
(hv_versions.hypervisor < 2 ? \
dominfo.v0.nr_online_vcpus : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ dominfo.v2d9.nr_online_vcpus : \
+ (hv_versions.dom_interface == 8 ? \
dominfo.v2d8.nr_online_vcpus : \
(hv_versions.dom_interface == 7 ? \
dominfo.v2d7.nr_online_vcpus : \
@@ -464,12 +506,14 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
dominfo.v2d6.nr_online_vcpus : \
(hv_versions.dom_interface == 5 ? \
dominfo.v2d5.nr_online_vcpus : \
- dominfo.v2.nr_online_vcpus)))))
+ dominfo.v2.nr_online_vcpus))))))
#define XEN_GETDOMAININFO_MAXCPUID(dominfo) \
(hv_versions.hypervisor < 2 ? \
dominfo.v0.max_vcpu_id : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ dominfo.v2d9.max_vcpu_id : \
+ (hv_versions.dom_interface == 8 ? \
dominfo.v2d8.max_vcpu_id : \
(hv_versions.dom_interface == 7 ? \
dominfo.v2d7.max_vcpu_id : \
@@ -477,12 +521,14 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
dominfo.v2d6.max_vcpu_id : \
(hv_versions.dom_interface == 5 ? \
dominfo.v2d5.max_vcpu_id : \
- dominfo.v2.max_vcpu_id)))))
+ dominfo.v2.max_vcpu_id))))))
#define XEN_GETDOMAININFO_FLAGS(dominfo) \
(hv_versions.hypervisor < 2 ? \
dominfo.v0.flags : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ dominfo.v2d9.flags : \
+ (hv_versions.dom_interface == 8 ? \
dominfo.v2d8.flags : \
(hv_versions.dom_interface == 7 ? \
dominfo.v2d7.flags : \
@@ -490,12 +536,14 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
dominfo.v2d6.flags : \
(hv_versions.dom_interface == 5 ? \
dominfo.v2d5.flags : \
- dominfo.v2.flags)))))
+ dominfo.v2.flags))))))
#define XEN_GETDOMAININFO_TOT_PAGES(dominfo) \
(hv_versions.hypervisor < 2 ? \
dominfo.v0.tot_pages : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ dominfo.v2d9.tot_pages : \
+ (hv_versions.dom_interface == 8 ? \
dominfo.v2d8.tot_pages : \
(hv_versions.dom_interface == 7 ? \
dominfo.v2d7.tot_pages : \
@@ -503,12 +551,14 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
dominfo.v2d6.tot_pages : \
(hv_versions.dom_interface == 5 ? \
dominfo.v2d5.tot_pages : \
- dominfo.v2.tot_pages)))))
+ dominfo.v2.tot_pages))))))
#define XEN_GETDOMAININFO_MAX_PAGES(dominfo) \
(hv_versions.hypervisor < 2 ? \
dominfo.v0.max_pages : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ dominfo.v2d9.max_pages : \
+ (hv_versions.dom_interface == 8 ? \
dominfo.v2d8.max_pages : \
(hv_versions.dom_interface == 7 ? \
dominfo.v2d7.max_pages : \
@@ -516,12 +566,14 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
dominfo.v2d6.max_pages : \
(hv_versions.dom_interface == 5 ? \
dominfo.v2d5.max_pages : \
- dominfo.v2.max_pages)))))
+ dominfo.v2.max_pages))))))
#define XEN_GETDOMAININFO_UUID(dominfo) \
(hv_versions.hypervisor < 2 ? \
dominfo.v0.handle : \
- (hv_versions.dom_interface >= 8 ? \
+ (hv_versions.dom_interface >= 9 ? \
+ dominfo.v2d9.handle : \
+ (hv_versions.dom_interface == 8 ? \
dominfo.v2d8.handle : \
(hv_versions.dom_interface == 7 ? \
dominfo.v2d7.handle : \
@@ -529,7 +581,7 @@ typedef struct xen_v2s5_availheap xen_v2s5_availheap;
dominfo.v2d6.handle : \
(hv_versions.dom_interface == 5 ? \
dominfo.v2d5.handle : \
- dominfo.v2.handle)))))
+ dominfo.v2.handle))))))
static int
@@ -1916,6 +1968,19 @@ xenHypervisorInit(struct xenHypervisorVersions *override_versions)
}
}
+ /* Xen 4.3
+ * sysctl version A -> xen-4.3 release
+ * domctl version 9 -> xen-4.3 release
+ */
+ hv_versions.sys_interface = 0xA; /* XEN_SYSCTL_INTERFACE_VERSION */
+ if (virXen_getdomaininfo(fd, 0, &info) == 1) {
+ hv_versions.dom_interface = 0x9; /* XEN_DOMCTL_INTERFACE_VERSION */
+ if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0) {
+ VIR_DEBUG("Using hypervisor call v2, sys verA dom ver9");
+ goto done;
+ }
+ }
+
hv_versions.hypervisor = 1;
hv_versions.sys_interface = -1;
if (virXen_getdomaininfo(fd, 0, &info) == 1) {
--
1.7.9.5
11 years, 4 months
[libvirt] [PATCH] esx: Support for disk-only and quiescing snapshots.
by Geoff Hickey
Add support for creating disk-only (no memory) snapshots in esx, and
for quiescing the VM before taking the snapshot. The VMware API
supports these operations directly, so adding support to libvirt is
just a matter of setting the flags correctly when calling
VMware. VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY and
VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE are now valid flags for esx.
---
src/esx/esx_driver.c | 14 ++++++++++----
1 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index fbe43c2..d69576d 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -4209,9 +4209,14 @@ esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
esxVI_TaskInfoState taskInfoState;
char *taskInfoErrorMessage = NULL;
virDomainSnapshotPtr snapshot = NULL;
+ bool diskOnly = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) != 0;
+ bool quiesce = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) != 0;
- /* ESX has no snapshot metadata, so this flag is trivial. */
- virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
+ /* ESX supports disk-only and quiesced snapshots, but has no snapshot *
+ * metadata. */
+ virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
+ VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
+ VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
if (esxVI_EnsureSession(priv->primary) < 0) {
return NULL;
@@ -4249,8 +4254,9 @@ esxDomainSnapshotCreateXML(virDomainPtr domain, const char *xmlDesc,
if (esxVI_CreateSnapshot_Task(priv->primary, virtualMachine->obj,
def->name, def->description,
- esxVI_Boolean_True,
- esxVI_Boolean_False, &task) < 0 ||
+ diskOnly ? esxVI_Boolean_False : esxVI_Boolean_True,
+ quiesce ? esxVI_Boolean_True : esxVI_Boolean_False,
+ &task) < 0 ||
esxVI_WaitForTaskCompletion(priv->primary, task, domain->uuid,
esxVI_Occurrence_RequiredItem,
priv->parsedUri->autoAnswer, &taskInfoState,
--
1.7.1
11 years, 4 months
[libvirt] [PATCH] Introduce virDBusCallMethod & virDBusMessageRead methods
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
Doing DBus method calls using libdbus.so is tedious in the
extreme. systemd developers came up with a nice high level
API for DBus method calls (sd_bus_call_method). While
systemd doesn't use libdbus.so, their API design can easily
be ported to libdbus.so.
This patch thus introduces methods virDBusCallMethod &
virDBusMessageRead, which are based on the code used for
sd_bus_call_method and sd_bus_message_read. This code in
systemd is under the LGPLv2+, so we're license compatible.
This code is probably pretty unintelligible unless you are
familiar with the DBus type system. So I added some API
docs trying to explain how to use them, as well as test
cases to validate that I didn't screw up the adaptation
from the original systemd code.
NB: this is being done as a pre-requisite to updating
libvirt's cgroups code to talk to systemd via DBus.
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
.gitignore | 1 +
src/libvirt_private.syms | 4 +
src/util/virdbus.c | 958 ++++++++++++++++++++++++++++++++++++++++++++++-
src/util/virdbus.h | 11 +
src/util/virdbuspriv.h | 43 +++
tests/Makefile.am | 6 +
tests/virdbustest.c | 391 +++++++++++++++++++
7 files changed, 1413 insertions(+), 1 deletion(-)
create mode 100644 src/util/virdbuspriv.h
create mode 100644 tests/virdbustest.c
diff --git a/.gitignore b/.gitignore
index 3efc2e4..851c6e4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -191,6 +191,7 @@
/tests/virbitmaptest
/tests/virbuftest
/tests/vircgrouptest
+/tests/virdbustest
/tests/virdrivermoduletest
/tests/virendiantest
/tests/virhashtest
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0ab7632..f337637 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1269,8 +1269,12 @@ virConfWriteMem;
# util/virdbus.h
+virDBusCallMethod;
virDBusGetSessionBus;
virDBusGetSystemBus;
+virDBusMessageDecode;
+virDBusMessageEncode;
+virDBusMessageRead;
# util/virdnsmasq.h
diff --git a/src/util/virdbus.c b/src/util/virdbus.c
index 52b6ca9..8c2c783 100644
--- a/src/util/virdbus.c
+++ b/src/util/virdbus.c
@@ -21,11 +21,12 @@
#include <config.h>
-#include "virdbus.h"
+#include "virdbuspriv.h"
#include "viralloc.h"
#include "virerror.h"
#include "virlog.h"
#include "virthread.h"
+#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_DBUS
@@ -223,6 +224,940 @@ static void virDBusToggleWatch(DBusWatch *watch,
(void)virEventUpdateHandle(info->watch, flags);
}
+# define VIR_DBUS_TYPE_STACK_MAX_DEPTH 32
+
+static const char virDBusBasicTypes[] = {
+ DBUS_TYPE_BYTE,
+ DBUS_TYPE_BOOLEAN,
+ DBUS_TYPE_INT16,
+ DBUS_TYPE_UINT16,
+ DBUS_TYPE_INT32,
+ DBUS_TYPE_UINT32,
+ DBUS_TYPE_INT64,
+ DBUS_TYPE_UINT64,
+ DBUS_TYPE_DOUBLE,
+ DBUS_TYPE_STRING,
+ DBUS_TYPE_OBJECT_PATH,
+ DBUS_TYPE_SIGNATURE,
+ DBUS_TYPE_UNIX_FD
+};
+
+static bool virDBusIsBasicType(char c) {
+ return !!memchr(virDBusBasicTypes, c, ARRAY_CARDINALITY(virDBusBasicTypes));
+}
+
+/*
+ * All code related to virDBusMessageIterEncode and
+ * virDBusMessageIterDecode is derived from systemd
+ * bus_message_append_ap()/message_read_ap() in
+ * bus-message.c under the terms of the LGPLv2+
+ */
+static int
+virDBusSignatureLengthInternal(const char *s,
+ bool allowDict,
+ unsigned arrayDepth,
+ unsigned structDepth,
+ size_t *l)
+{
+ if (virDBusIsBasicType(*s) || *s == DBUS_TYPE_VARIANT) {
+ *l = 1;
+ return 0;
+ }
+
+ if (*s == DBUS_TYPE_ARRAY) {
+ size_t t;
+
+ if (arrayDepth >= VIR_DBUS_TYPE_STACK_MAX_DEPTH) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Signature '%s' too deeply nested"),
+ s);
+ return -1;
+ }
+
+ if (virDBusSignatureLengthInternal(s + 1, true, arrayDepth+1, structDepth, &t) < 0)
+ return -1;
+
+ *l = t + 1;
+ return 0;
+ }
+
+ if (*s == DBUS_STRUCT_BEGIN_CHAR) {
+ const char *p = s + 1;
+
+ if (structDepth >= VIR_DBUS_TYPE_STACK_MAX_DEPTH) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Signature '%s' too deeply nested"),
+ s);
+ return -1;
+ }
+
+ while (*p != DBUS_STRUCT_END_CHAR) {
+ size_t t;
+
+ if (virDBusSignatureLengthInternal(p, false, arrayDepth, structDepth+1, &t) < 0)
+ return -1;
+
+ p += t;
+ }
+
+ *l = p - s + 1;
+ return 0;
+ }
+
+ if (*s == DBUS_DICT_ENTRY_BEGIN_CHAR && allowDict) {
+ const char *p = s + 1;
+ unsigned n = 0;
+ if (structDepth >= VIR_DBUS_TYPE_STACK_MAX_DEPTH) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Signature '%s' too deeply nested"),
+ s);
+ return -1;
+ }
+
+ while (*p != DBUS_DICT_ENTRY_END_CHAR) {
+ size_t t;
+
+ if (n == 0 && !virDBusIsBasicType(*p)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Dict entry in signature '%s' must be a basic type"),
+ s);
+ return -1;
+ }
+
+ if (virDBusSignatureLengthInternal(p, false, arrayDepth, structDepth+1, &t) < 0)
+ return -1;
+
+ p += t;
+ n++;
+ }
+
+ if (n != 2) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Dict entry in signature '%s' is wrong size"),
+ s);
+ return -1;
+ }
+
+ *l = p - s + 1;
+ return 0;
+ }
+
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unexpected signature '%s'"), s);
+ return -1;
+}
+
+
+static int virDBusSignatureLength(const char *s, size_t *l)
+{
+ return virDBusSignatureLengthInternal(s, true, 0, 0, l);
+}
+
+
+
+/* Ideally, we'd just call ourselves recursively on every
+ * complex type. However, the state of a va_list that is
+ * passed to a function is undefined after that function
+ * returns. This means we need to docode the va_list linearly
+ * in a single stackframe. We hence implement our own
+ * home-grown stack in an array. */
+
+typedef struct _virDBusTypeStack virDBusTypeStack;
+struct _virDBusTypeStack {
+ const char *types;
+ size_t nstruct;
+ size_t narray;
+ DBusMessageIter *iter;
+};
+
+static int virDBusTypeStackPush(virDBusTypeStack **stack,
+ size_t *nstack,
+ DBusMessageIter *iter,
+ const char *types,
+ size_t nstruct,
+ size_t narray)
+{
+ if (*nstack >= VIR_DBUS_TYPE_STACK_MAX_DEPTH) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("DBus type too deeply nested"));
+ return -1;
+ }
+
+ if (VIR_EXPAND_N(*stack, *nstack, 1) < 0)
+ return -1;
+
+ (*stack)[(*nstack) - 1].iter = iter;
+ (*stack)[(*nstack) - 1].types = types;
+ (*stack)[(*nstack) - 1].nstruct = nstruct;
+ (*stack)[(*nstack) - 1].narray = narray;
+ VIR_DEBUG("Pushed '%s'", types);
+ return 0;
+}
+
+
+static int virDBusTypeStackPop(virDBusTypeStack **stack,
+ size_t *nstack,
+ DBusMessageIter **iter,
+ const char **types,
+ size_t *nstruct,
+ size_t *narray)
+{
+ if (*nstack == 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("DBus type stack is empty"));
+ return -1;
+ }
+
+ *iter = (*stack)[(*nstack) - 1].iter;
+ *types = (*stack)[(*nstack) - 1].types;
+ *nstruct = (*stack)[(*nstack) - 1].nstruct;
+ *narray = (*stack)[(*nstack) - 1].narray;
+ VIR_DEBUG("Popped '%s'", *types);
+ VIR_SHRINK_N(*stack, *nstack, 1);
+
+ return 0;
+}
+
+
+static void virDBusTypeStackFree(virDBusTypeStack **stack,
+ size_t *nstack)
+{
+ size_t i;
+ /* The iter in the first level of the stack is the
+ * root iter which must not be freed
+ */
+ for (i = 1; i < *nstack; i++) {
+ VIR_FREE((*stack)[i].iter);
+ }
+ VIR_FREE(*stack);
+}
+
+
+# define SET_NEXT_VAL(dbustype, vargtype, sigtype) \
+ do { \
+ dbustype x = (dbustype)va_arg(args, vargtype); \
+ if (!dbus_message_iter_append_basic(iter, sigtype, &x)) { \
+ virReportError(VIR_ERR_INTERNAL_ERROR, \
+ _("Cannot append basic type %s"), #vargtype); \
+ goto cleanup; \
+ } \
+ } while (0)
+
+static int
+virDBusMessageIterEncode(DBusMessageIter *rootiter,
+ const char *types,
+ va_list args)
+{
+ int ret = -1;
+ size_t narray;
+ size_t nstruct;
+ virDBusTypeStack *stack = NULL;
+ size_t nstack = 0;
+ size_t siglen;
+ char *contsig = NULL;
+ const char *vsig;
+ DBusMessageIter *newiter = NULL;
+ DBusMessageIter *iter = rootiter;
+
+ VIR_DEBUG("rootiter=%p types=%s", rootiter, types);
+
+ if (!types)
+ return 0;
+
+ narray = (size_t)-1;
+ nstruct = strlen(types);
+
+ for (;;) {
+ const char *t;
+
+ VIR_DEBUG("Loop stack=%zu array=%zu struct=%zu type='%s'",
+ nstack, narray, nstruct, types);
+ if (narray == 0 ||
+ (narray == (size_t)-1 &&
+ nstruct == 0)) {
+ DBusMessageIter *thisiter = iter;
+ VIR_DEBUG("Popping iter=%p", iter);
+ if (nstack == 0)
+ break;
+ if (virDBusTypeStackPop(&stack, &nstack, &iter,
+ &types, &nstruct, &narray) < 0)
+ goto cleanup;
+ VIR_DEBUG("Popped iter=%p", iter);
+
+ if (!dbus_message_iter_close_container(iter, thisiter)) {
+ if (thisiter != rootiter)
+ VIR_FREE(thisiter);
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot close container iterator"));
+ goto cleanup;
+ }
+ if (thisiter != rootiter)
+ VIR_FREE(thisiter);
+ continue;
+ }
+
+ t = types;
+ if (narray != (size_t)-1) {
+ narray--;
+ } else {
+ types++;
+ nstruct--;
+ }
+
+ switch (*t) {
+ case DBUS_TYPE_BYTE:
+ SET_NEXT_VAL(unsigned char, int, *t);
+ break;
+
+ case DBUS_TYPE_BOOLEAN:
+ SET_NEXT_VAL(dbus_bool_t, int, *t);
+ break;
+
+ case DBUS_TYPE_INT16:
+ SET_NEXT_VAL(dbus_int16_t, int, *t);
+ break;
+
+ case DBUS_TYPE_UINT16:
+ SET_NEXT_VAL(dbus_uint16_t, unsigned int, *t);
+ break;
+
+ case DBUS_TYPE_INT32:
+ SET_NEXT_VAL(dbus_int32_t, int, *t);
+ break;
+
+ case DBUS_TYPE_UINT32:
+ SET_NEXT_VAL(dbus_uint32_t, unsigned int, *t);
+ break;
+
+ case DBUS_TYPE_INT64:
+ SET_NEXT_VAL(dbus_int64_t, long long, *t);
+ break;
+
+ case DBUS_TYPE_UINT64:
+ SET_NEXT_VAL(dbus_uint64_t, unsigned long long, *t);
+ break;
+
+ case DBUS_TYPE_DOUBLE:
+ SET_NEXT_VAL(double, double, *t);
+ break;
+
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ SET_NEXT_VAL(char *, char *, *t);
+ break;
+
+ case DBUS_TYPE_ARRAY:
+ if (virDBusSignatureLength(t + 1, &siglen) < 0)
+ goto cleanup;
+
+ if (VIR_STRNDUP(contsig, t + 1, siglen) < 0)
+ goto cleanup;
+
+ if (narray == (size_t)-1) {
+ types += siglen;
+ nstruct -= siglen;
+ }
+
+ if (VIR_ALLOC(newiter) < 0)
+ goto cleanup;
+ VIR_DEBUG("Contsig '%s' '%zu'", contsig, siglen);
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ contsig, newiter))
+ goto cleanup;
+ if (virDBusTypeStackPush(&stack, &nstack,
+ iter, types,
+ nstruct, narray) < 0)
+ goto cleanup;
+ VIR_FREE(contsig);
+ iter = newiter;
+ newiter = NULL;
+ types = t + 1;
+ nstruct = siglen;
+ narray = va_arg(args, size_t);
+ break;
+
+ case DBUS_TYPE_VARIANT:
+ vsig = va_arg(args, const char *);
+ if (!vsig) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing variant type signature"));
+ goto cleanup;
+ }
+ if (VIR_ALLOC(newiter) < 0)
+ goto cleanup;
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ vsig, newiter))
+ goto cleanup;
+ if (virDBusTypeStackPush(&stack, &nstack,
+ iter, types,
+ nstruct, narray) < 0)
+ goto cleanup;
+ iter = newiter;
+ newiter = NULL;
+ types = vsig;
+ nstruct = strlen(types);
+ narray = (size_t)-1;
+ break;
+
+ case DBUS_STRUCT_BEGIN_CHAR:
+ case DBUS_DICT_ENTRY_BEGIN_CHAR:
+ if (virDBusSignatureLength(t, &siglen) < 0)
+ goto cleanup;
+
+ if (VIR_STRNDUP(contsig, t + 1, siglen - 1) < 0)
+ goto cleanup;
+
+ if (VIR_ALLOC(newiter) < 0)
+ goto cleanup;
+ VIR_DEBUG("Contsig '%s' '%zu'", contsig, siglen);
+ if (!dbus_message_iter_open_container(iter,
+ *t == DBUS_STRUCT_BEGIN_CHAR ?
+ DBUS_TYPE_STRUCT : DBUS_TYPE_DICT_ENTRY,
+ NULL, newiter))
+ goto cleanup;
+ if (narray == (size_t)-1) {
+ types += siglen - 1;
+ nstruct -= siglen - 1;
+ }
+
+ if (virDBusTypeStackPush(&stack, &nstack,
+ iter, types,
+ nstruct, narray) < 0)
+ goto cleanup;
+ VIR_FREE(contsig);
+ iter = newiter;
+ newiter = NULL;
+ types = t + 1;
+ nstruct = siglen - 2;
+ narray = (size_t)-1;
+
+ break;
+
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown type in signature '%s'"),
+ types);
+ }
+ }
+
+ ret = 0;
+
+cleanup:
+ virDBusTypeStackFree(&stack, &nstack);
+ VIR_FREE(contsig);
+ VIR_FREE(newiter);
+ return ret;
+}
+# undef SET_NEXT_VAL
+
+
+# define GET_NEXT_VAL(dbustype, vargtype) \
+ do { \
+ dbustype *x = (dbustype *)va_arg(args, vargtype *); \
+ dbus_message_iter_get_basic(iter, x); \
+ } while (0)
+
+
+static int
+virDBusMessageIterDecode(DBusMessageIter *rootiter,
+ const char *types,
+ va_list args)
+{
+ int ret = -1;
+ size_t narray;
+ size_t nstruct;
+ virDBusTypeStack *stack = NULL;
+ size_t nstack = 0;
+ size_t siglen;
+ char *contsig = NULL;
+ const char *vsig;
+ DBusMessageIter *newiter = NULL;
+ DBusMessageIter *iter = rootiter;
+
+ VIR_DEBUG("rootiter=%p types=%s", rootiter, types);
+
+ if (!types)
+ return 0;
+
+ narray = (size_t)-1;
+ nstruct = strlen(types);
+
+ for (;;) {
+ const char *t;
+ bool advanceiter = true;
+
+ VIR_DEBUG("Loop stack=%zu array=%zu struct=%zu type='%s'",
+ nstack, narray, nstruct, types);
+ if (narray == 0 ||
+ (narray == (size_t)-1 &&
+ nstruct == 0)) {
+ DBusMessageIter *thisiter = iter;
+ VIR_DEBUG("Popping iter=%p", iter);
+ if (nstack == 0)
+ break;
+ if (virDBusTypeStackPop(&stack, &nstack, &iter,
+ &types, &nstruct, &narray) < 0)
+ goto cleanup;
+ VIR_DEBUG("Popped iter=%p types=%s", iter, types);
+ if (thisiter != rootiter)
+ VIR_FREE(thisiter);
+ if (!(narray == 0 ||
+ (narray == (size_t)-1 &&
+ nstruct == 0)) &&
+ !dbus_message_iter_next(iter)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Not enough fields in message for signature"));
+ goto cleanup;
+ }
+ continue;
+ }
+
+ t = types;
+ if (narray != (size_t)-1) {
+ narray--;
+ } else {
+ types++;
+ nstruct--;
+ }
+
+ switch (*t) {
+ case DBUS_TYPE_BYTE:
+ GET_NEXT_VAL(unsigned char, int);
+ break;
+
+ case DBUS_TYPE_BOOLEAN:
+ GET_NEXT_VAL(dbus_bool_t, int);
+ break;
+
+ case DBUS_TYPE_INT16:
+ GET_NEXT_VAL(dbus_int16_t, int);
+ break;
+
+ case DBUS_TYPE_UINT16:
+ GET_NEXT_VAL(dbus_uint16_t, unsigned int);
+ break;
+
+ case DBUS_TYPE_INT32:
+ GET_NEXT_VAL(dbus_uint32_t, int);
+ break;
+
+ case DBUS_TYPE_UINT32:
+ GET_NEXT_VAL(dbus_uint32_t, unsigned int);
+ break;
+
+ case DBUS_TYPE_INT64:
+ GET_NEXT_VAL(dbus_uint64_t, long long);
+ break;
+
+ case DBUS_TYPE_UINT64:
+ GET_NEXT_VAL(dbus_uint64_t, unsigned long long);
+ break;
+
+ case DBUS_TYPE_DOUBLE:
+ GET_NEXT_VAL(double, double);
+ break;
+
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ do {
+ char **x = (char **)va_arg(args, char **);
+ char *s;
+ dbus_message_iter_get_basic(iter, &s);
+ if (VIR_STRDUP(*x, s) < 0)
+ goto cleanup;
+ } while (0);
+ break;
+
+ case DBUS_TYPE_ARRAY:
+ advanceiter = false;
+ if (virDBusSignatureLength(t + 1, &siglen) < 0)
+ goto cleanup;
+
+ if (VIR_STRNDUP(contsig, t + 1, siglen) < 0)
+ goto cleanup;
+
+ if (narray == (size_t)-1) {
+ types += siglen;
+ nstruct -= siglen;
+ }
+
+ if (VIR_ALLOC(newiter) < 0)
+ goto cleanup;
+ VIR_DEBUG("Contsig '%s' '%zu' '%s'", contsig, siglen, types);
+ dbus_message_iter_recurse(iter, newiter);
+ if (virDBusTypeStackPush(&stack, &nstack,
+ iter, types,
+ nstruct, narray) < 0)
+ goto cleanup;
+ VIR_FREE(contsig);
+ iter = newiter;
+ newiter = NULL;
+ types = t + 1;
+ nstruct = siglen;
+ narray = va_arg(args, size_t);
+ break;
+
+ case DBUS_TYPE_VARIANT:
+ advanceiter = false;
+ vsig = va_arg(args, const char *);
+ if (!vsig) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing variant type signature"));
+ goto cleanup;
+ }
+ if (VIR_ALLOC(newiter) < 0)
+ goto cleanup;
+ dbus_message_iter_recurse(iter, newiter);
+ if (virDBusTypeStackPush(&stack, &nstack,
+ iter, types,
+ nstruct, narray) < 0) {
+ VIR_DEBUG("Push failed");
+ goto cleanup;
+ }
+ iter = newiter;
+ newiter = NULL;
+ types = vsig;
+ nstruct = strlen(types);
+ narray = (size_t)-1;
+ break;
+
+ case DBUS_STRUCT_BEGIN_CHAR:
+ case DBUS_DICT_ENTRY_BEGIN_CHAR:
+ advanceiter = false;
+ if (virDBusSignatureLength(t, &siglen) < 0)
+ goto cleanup;
+
+ if (VIR_STRNDUP(contsig, t + 1, siglen - 1) < 0)
+ goto cleanup;
+
+ if (VIR_ALLOC(newiter) < 0)
+ goto cleanup;
+ VIR_DEBUG("Contsig '%s' '%zu'", contsig, siglen);
+ dbus_message_iter_recurse(iter, newiter);
+ if (narray == (size_t)-1) {
+ types += siglen - 1;
+ nstruct -= siglen - 1;
+ }
+
+ if (virDBusTypeStackPush(&stack, &nstack,
+ iter, types,
+ nstruct, narray) < 0)
+ goto cleanup;
+ VIR_FREE(contsig);
+ iter = newiter;
+ newiter = NULL;
+ types = t + 1;
+ nstruct = siglen - 2;
+ narray = (size_t)-1;
+
+ break;
+
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown type in signature '%s'"),
+ types);
+ }
+
+ VIR_DEBUG("After stack=%zu array=%zu struct=%zu type='%s'",
+ nstack, narray, nstruct, types);
+ if (advanceiter &&
+ !(narray == 0 ||
+ (narray == (size_t)-1 &&
+ nstruct == 0)) &&
+ !dbus_message_iter_next(iter)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Not enough fields in message for signature"));
+ goto cleanup;
+ }
+ }
+
+ if (dbus_message_iter_has_next(iter)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Too many fields in message for signature"));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virDBusTypeStackFree(&stack, &nstack);
+ VIR_FREE(contsig);
+ VIR_FREE(newiter);
+ return ret;
+}
+# undef GET_NEXT_VAL
+
+int
+virDBusMessageEncodeArgs(DBusMessage* msg,
+ const char *types,
+ va_list args)
+{
+ DBusMessageIter iter;
+ int ret = -1;
+
+ memset(&iter, 0, sizeof(iter));
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ ret = virDBusMessageIterEncode(&iter, types, args);
+
+ return ret;
+}
+
+
+int virDBusMessageDecodeArgs(DBusMessage* msg,
+ const char *types,
+ va_list args)
+{
+ DBusMessageIter iter;
+ int ret = -1;
+
+ if (!dbus_message_iter_init(msg, &iter)) {
+ if (*types != '\0') {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("No args present for signature %s"),
+ types);
+ } else {
+ ret = 0;
+ }
+ goto cleanup;
+ }
+
+ ret = virDBusMessageIterDecode(&iter, types, args);
+
+cleanup:
+ return ret;
+}
+
+
+int virDBusMessageEncode(DBusMessage* msg,
+ const char *types,
+ ...)
+{
+ int ret;
+ va_list args;
+ va_start(args, types);
+ ret = virDBusMessageEncodeArgs(msg, types, args);
+ va_end(args);
+ return ret;
+}
+
+
+int virDBusMessageDecode(DBusMessage* msg,
+ const char *types,
+ ...)
+{
+ int ret;
+ va_list args;
+ va_start(args, types);
+ ret = virDBusMessageDecodeArgs(msg, types, args);
+ va_end(args);
+ return ret;
+}
+
+/**
+ * @conn: a DBus connection
+ * @replyout: pointer to receive reply message, or NULL
+ * @destination: bus identifier of the target service
+ * @path: object path of the target service
+ * @interface: the interface of the object
+ * @member: the name of the method in the interface
+ * @types: type signature for following method arguments
+ * @...: method arguments
+ *
+ * This invokes a method on a remote service on the
+ * DBus bus @conn. The @destination, @path, @interface
+ * and @member parameters identify the object method to
+ * be invoked. The optional @replyout parameter will be
+ * filled with any reply to the method call. The
+ * virDBusMethodReply method can be used to decode the
+ * return values.
+ *
+ * The @types parameter is a DBus signature describing
+ * the method call parameters which will be provided
+ * as variadic args. Each character in @types must
+ * correspond to one of the following DBus codes for
+ * basic types:
+ *
+ * 'y' - 8-bit byte, promoted to an 'int'
+ * 'b' - bool value, promoted to an 'int'
+ * 'n' - 16-bit signed integer, promoted to an 'int'
+ * 'q' - 16-bit unsigned integer, promoted to an 'int'
+ * 'i' - 32-bit signed integer, passed as an 'int'
+ * 'u' - 32-bit unsigned integer, passed as an 'int'
+ * 'x' - 64-bit signed integer, passed as a 'long long'
+ * 't' - 64-bit unsigned integer, passed as an 'unsigned long long'
+ * 'd' - 8-byte floating point, passed as a 'double'
+ * 's' - NULL terminated string, in UTF-8
+ * 'o' - NULL terminated string, representing a valid object path
+ * 'g' - NULL terminated string, representing a valid type signature
+ *
+ * or use one of the compound types
+ *
+ * 'a' - array of values
+ * 'v' - a variadic type.
+ * '(' - start of a struct
+ * ')' - end of a struct
+ * '{' - start of a dictionary entry (pair of types)
+ * '}' - start of a dictionary entry (pair of types)
+ *
+ * Passing values in variadic args for basic types is
+ * simple, the value is just passed directly using the
+ * corresponding C type listed against the type code
+ * above. Note how any integer value smaller than an
+ * 'int' is promoted to an 'int' by the C rules for
+ * variadic args.
+ *
+ * Passing values in variadic args for compound types
+ * requires a little further explanation.
+ *
+ * - Variant: the first arg is a string containing
+ * the type signature for the values to be stored
+ * inside the variant. This is then followed by
+ * the values corresponding to the type signature
+ * in the normal manner.
+ *
+ * - Array: when 'a' appears in a type signature, it
+ * must be followed by a single type describing the
+ * array element type. For example 'as' is an array
+ * of strings. 'a(is)' is an array of structs, each
+ * struct containing an int and a string.
+ *
+ * The first variadic arg for an array, is an 'int'
+ * specifying the number of elements in the array.
+ * This is then followed by the values for the array
+ *
+ * - Struct: when a '(' appears in a type signature,
+ * it must be followed by one or more types describing
+ * the elements in the array, terminated by a ')'.
+ *
+ * - Dict entry: when a '{' appears in a type signature it
+ * must be followed by exactly two types, one describing
+ * the type of the hash key, the other describing the
+ * type of the hash entry. The hash key type must be
+ * a basic type, not a compound type.
+ *
+ * Example signatures, with their corresponding variadic
+ * args:
+ *
+ * - "biiss" - some basic types
+ *
+ * (true, 7, 42, "hello", "world")
+ *
+ * - "as" - an array with a basic type element
+ *
+ * (3, "one", "two", "three")
+ *
+ * - "a(is)" - an array with a struct element
+ *
+ * (3, 1, "one", 2, "two", 3, "three")
+ *
+ * - "svs" - some basic types with a variant as an int
+ *
+ * ("hello", "i", 3, "world")
+ *
+ * - "svs" - some basic types with a variant as an array of ints
+ *
+ * ("hello", "ai", 4, 1, 2, 3, 4, "world")
+ *
+ * - "a{ss}" - a hash table (aka array + dict entry)
+ *
+ * (3, "title", "Mr", "forename", "Joe", "surname", "Bloggs")
+ *
+ * - "a{sv}" - a hash table (aka array + dict entry)
+ *
+ * (3, "email", "s", "joe(a)blogs.com", "age", "i", 35,
+ * "address", "as", 3, "Some house", "Some road", "some city")
+ */
+
+int virDBusCallMethod(DBusConnection *conn,
+ DBusMessage **replyout,
+ const char *destination,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *types, ...)
+{
+ DBusMessage *call = NULL;
+ DBusMessage *reply = NULL;
+ DBusError error;
+ int ret = -1;
+ va_list args;
+
+ dbus_error_init(&error);
+
+ if (!(call = dbus_message_new_method_call(destination,
+ path,
+ interface,
+ member))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ va_start(args, types);
+ ret = virDBusMessageEncodeArgs(call, types, args);
+ va_end(args);
+ if (ret < 0)
+ goto cleanup;
+
+ ret = -1;
+
+ if (!(reply = dbus_connection_send_with_reply_and_block(conn,
+ call,
+ 30 * 1000,
+ &error))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Cannot send to %s.%s on path %s with interface %s: %s"),
+ destination, member, path, interface, NULLSTR(error.message));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ dbus_error_free(&error);
+ if (call)
+ dbus_message_unref(call);
+ if (reply) {
+ if (ret == 0 && replyout)
+ *replyout = reply;
+ else
+ dbus_message_unref(reply);
+ }
+ return ret;
+}
+
+
+/**
+ * virDBusMessageRead:
+ * @msg: the reply to decode
+ * @types: type signature for following return values
+ * @...: pointers in which to store return values
+ *
+ * The @types type signature is the same format as
+ * that used for the virDBusCallMethod. The difference
+ * is that each variadic parameter must be a pointer to
+ * be filled with the values. eg instead of passing an
+ * 'int', pass an 'int *'.
+ *
+ */
+int virDBusMessageRead(DBusMessage *msg,
+ const char *types, ...)
+{
+ va_list args;
+ int ret;
+
+ va_start(args, types);
+ ret = virDBusMessageDecodeArgs(msg, types, args);
+ va_end(args);
+
+ dbus_message_unref(msg);
+ return ret;
+}
+
+
#else /* ! WITH_DBUS */
DBusConnection *virDBusGetSystemBus(void)
{
@@ -237,4 +1172,25 @@ DBusConnection *virDBusGetSessionBus(void)
"%s", _("DBus support not compiled into this binary"));
return NULL;
}
+
+int virDBusCallMethod(DBusConnection *conn ATTRIBUTE_UNUSED,
+ const char *destination ATTRIBUTE_UNUSED,
+ const char *path ATTRIBUTE_UNUSED,
+ const char *interface ATTRIBUTE_UNUSED,
+ const char *member ATTRIBUTE_UNUSED,
+ const char *types ATTRIBUTE_UNUSED, ...)
+{
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("DBus support not compiled into this binary"));
+ return -1;
+}
+
+int virDBusMessageRead(DBusMessage *msg ATTRIBUTE_UNUSED,
+ const char *types ATTRIBUTE_UNUSED, ...)
+{
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("DBus support not compiled into this binary"));
+ return -1;
+}
+
#endif /* ! WITH_DBUS */
diff --git a/src/util/virdbus.h b/src/util/virdbus.h
index a73e293..69a32d8 100644
--- a/src/util/virdbus.h
+++ b/src/util/virdbus.h
@@ -27,10 +27,21 @@
# include <dbus/dbus.h>
# else
# define DBusConnection void
+# define DBusMesssage void
# endif
# include "internal.h"
DBusConnection *virDBusGetSystemBus(void);
DBusConnection *virDBusGetSessionBus(void);
+int virDBusCallMethod(DBusConnection *conn,
+ DBusMessage **reply,
+ const char *destination,
+ const char *path,
+ const char *interface,
+ const char *member,
+ const char *types, ...);
+int virDBusMessageRead(DBusMessage *msg,
+ const char *types, ...);
+
#endif /* __VIR_DBUS_H__ */
diff --git a/src/util/virdbuspriv.h b/src/util/virdbuspriv.h
new file mode 100644
index 0000000..751536f
--- /dev/null
+++ b/src/util/virdbuspriv.h
@@ -0,0 +1,43 @@
+/*
+ * virdbuspriv.h: internal APIs for testing DBus code
+ *
+ * Copyright (C) 2012-2013 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VIR_DBUS_PRIV_H__
+# define __VIR_DBUS_PRIV_H__
+
+# include "virdbus.h"
+
+int virDBusMessageEncodeArgs(DBusMessage* msg,
+ const char *types,
+ va_list args);
+
+int virDBusMessageDecodeArgs(DBusMessage* msg,
+ const char *types,
+ va_list args);
+
+int virDBusMessageEncode(DBusMessage* msg,
+ const char *types,
+ ...);
+
+int virDBusMessageDecode(DBusMessage* msg,
+ const char *types,
+ ...);
+
+#endif /* __VIR_DBUS_PRIV_H__ */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4c49151..9eaa9d8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -116,6 +116,7 @@ test_programs = virshtest sockettest \
virauthconfigtest \
virbitmaptest \
vircgrouptest \
+ virdbustest \
virendiantest \
viridentitytest \
virkeycodetest \
@@ -637,6 +638,11 @@ vircgroupmock_la_CFLAGS = $(AM_CFLAGS)
vircgroupmock_la_LDFLAGS = -module -avoid-version \
-rpath /evil/libtool/hack/to/force/shared/lib/creation
+virdbustest_SOURCES = \
+ virdbustest.c testutils.h testutils.c
+virdbustest_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
+virdbustest_LDADD = $(LDADDS)
+
viruritest_SOURCES = \
viruritest.c testutils.h testutils.c
diff --git a/tests/virdbustest.c b/tests/virdbustest.c
new file mode 100644
index 0000000..13cd8cf
--- /dev/null
+++ b/tests/virdbustest.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include "virdbuspriv.h"
+#include "virlog.h"
+#include "testutils.h"
+
+#define VERIFY(t, a, b, f) \
+ do { \
+ VIR_DEBUG("Compare " t " '" f "' to '" f "'", a, b); \
+ if (a != b) { \
+ fprintf(stderr, "Failed to round-trip " t " '" f "' to '" f "'\n", a, b); \
+ goto cleanup; \
+ } \
+ } while (0)
+
+#define VERIFY_STR(t, a, b, f) \
+ do { \
+ VIR_DEBUG("Compare " t " '" f "' to '" f "'", a, b); \
+ if (STRNEQ(a, b)) { \
+ fprintf(stderr, "Failed to round-trip " t " '" f "' to '" f "'\n", a, b); \
+ goto cleanup; \
+ } \
+ } while (0)
+
+static int testMessageSimple(const void *args ATTRIBUTE_UNUSED)
+{
+ DBusMessage *msg = NULL;
+ int ret = -1;
+ unsigned char in_byte = 200, out_byte = 0;
+ bool in_bool = true, out_bool = false;
+ int in_int16 = 12000, out_int16 = 0;
+ unsigned int in_uint16 = 32000, out_uint16 = 0;
+ int in_int32 = 100000000, out_int32 = 0;
+ unsigned int in_uint32 = 200000000, out_uint32 = 0;
+ long long in_int64 = 1000000000000, out_int64 = 0;
+ unsigned long long in_uint64 = 2000000000000, out_uint64 = 0;
+ double in_double = 3.14159265359, out_double = 0;;
+ const char *in_string = "Hello World";
+ char *out_string = NULL;
+ const char *in_objectpath = "/org/libvirt/test";
+ char *out_objectpath = NULL;
+ const char *in_signature = "ybnqiuxtdsog";
+ char *out_signature = NULL;
+
+ if (!(msg = dbus_message_new_method_call("org.libvirt.test",
+ "/org/libvirt/test",
+ "org.libvirt.test.astrochicken",
+ "cluck"))) {
+ VIR_DEBUG("Failed to allocate method call");
+ goto cleanup;
+ }
+
+ if (virDBusMessageEncode(msg,
+ "ybnqiuxtdsog",
+ in_byte, in_bool,
+ in_int16, in_uint16,
+ in_int32, in_uint32,
+ in_int64, in_uint64,
+ in_double, in_string,
+ in_objectpath, in_signature) < 0) {
+ VIR_DEBUG("Failed to encode arguments");
+ goto cleanup;
+ }
+
+ if (virDBusMessageDecode(msg,
+ "ybnqiuxtdsog",
+ &out_byte, &out_bool,
+ &out_int16, &out_uint16,
+ &out_int32, &out_uint32,
+ &out_int64, &out_uint64,
+ &out_double, &out_string,
+ &out_objectpath, &out_signature) < 0) {
+ VIR_DEBUG("Failed to decode arguments");
+ goto cleanup;
+ }
+
+ VERIFY("byte", in_byte, out_byte, "%d");
+ VERIFY("bool", in_bool, out_bool, "%d");
+ VERIFY("int16", in_int16, out_int16, "%d");
+ VERIFY("uint16", in_int16, out_int16, "%d");
+ VERIFY("int32", in_int32, out_int32, "%d");
+ VERIFY("uint32", in_int32, out_int32, "%d");
+ VERIFY("int64", in_int64, out_int64, "%lld");
+ VERIFY("uint64", in_int64, out_int64, "%lld");
+ VERIFY("double", in_double, out_double, "%lf");
+ VERIFY_STR("string", in_string, out_string, "%s");
+ VERIFY_STR("objectpath", in_objectpath, out_objectpath, "%s");
+ VERIFY_STR("signature", in_signature, out_signature, "%s");
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(out_string);
+ VIR_FREE(out_signature);
+ VIR_FREE(out_objectpath);
+ dbus_message_unref(msg);
+ return ret;
+}
+
+
+static int testMessageVariant(const void *args ATTRIBUTE_UNUSED)
+{
+ DBusMessage *msg = NULL;
+ int ret = -1;
+ const char *in_str1 = "Hello";
+ int in_int32 = 100000000, out_int32 = 0;
+ const char *in_str2 = "World";
+ char *out_str1 = NULL, *out_str2 = NULL;
+
+ if (!(msg = dbus_message_new_method_call("org.libvirt.test",
+ "/org/libvirt/test",
+ "org.libvirt.test.astrochicken",
+ "cluck"))) {
+ VIR_DEBUG("Failed to allocate method call");
+ goto cleanup;
+ }
+
+ if (virDBusMessageEncode(msg,
+ "svs",
+ in_str1,
+ "i", in_int32,
+ in_str2) < 0) {
+ VIR_DEBUG("Failed to encode arguments");
+ goto cleanup;
+ }
+
+ if (virDBusMessageDecode(msg,
+ "svs",
+ &out_str1,
+ "i", &out_int32,
+ &out_str2) < 0) {
+ VIR_DEBUG("Failed to decode arguments");
+ goto cleanup;
+ }
+
+
+ VERIFY_STR("str1", in_str1, out_str1, "%s");
+ VERIFY("int32", in_int32, out_int32, "%d");
+ VERIFY_STR("str2", in_str2, out_str2, "%s");
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(out_str1);
+ VIR_FREE(out_str2);
+ dbus_message_unref(msg);
+ return ret;
+}
+
+static int testMessageArray(const void *args ATTRIBUTE_UNUSED)
+{
+ DBusMessage *msg = NULL;
+ int ret = -1;
+ const char *in_str1 = "Hello";
+ size_t arraylen = 3;
+ int in_int32a = 100000000, out_int32a = 0;
+ int in_int32b = 200000000, out_int32b = 0;
+ int in_int32c = 300000000, out_int32c = 0;
+ const char *in_str2 = "World";
+ char *out_str1 = NULL, *out_str2 = NULL;
+
+ if (!(msg = dbus_message_new_method_call("org.libvirt.test",
+ "/org/libvirt/test",
+ "org.libvirt.test.astrochicken",
+ "cluck"))) {
+ VIR_DEBUG("Failed to allocate method call");
+ goto cleanup;
+ }
+
+ if (virDBusMessageEncode(msg,
+ "sais",
+ in_str1,
+ arraylen, in_int32a, in_int32b, in_int32c,
+ in_str2) < 0) {
+ VIR_DEBUG("Failed to encode arguments");
+ goto cleanup;
+ }
+
+ if (virDBusMessageDecode(msg,
+ "sais",
+ &out_str1,
+ arraylen, &out_int32a, &out_int32b, &out_int32c,
+ &out_str2) < 0) {
+ VIR_DEBUG("Failed to decode arguments");
+ goto cleanup;
+ }
+
+
+ VERIFY_STR("str1", in_str1, out_str1, "%s");
+ VERIFY("int32a", in_int32a, out_int32a, "%d");
+ VERIFY("int32b", in_int32b, out_int32b, "%d");
+ VERIFY("int32c", in_int32c, out_int32c, "%d");
+ VERIFY_STR("str2", in_str2, out_str2, "%s");
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(out_str1);
+ VIR_FREE(out_str2);
+ dbus_message_unref(msg);
+ return ret;
+}
+
+static int testMessageStruct(const void *args ATTRIBUTE_UNUSED)
+{
+ DBusMessage *msg = NULL;
+ int ret = -1;
+ unsigned char in_byte = 200, out_byte = 0;
+ bool in_bool = true, out_bool = false;
+ int in_int16 = 12000, out_int16 = 0;
+ unsigned int in_uint16 = 32000, out_uint16 = 0;
+ int in_int32 = 100000000, out_int32 = 0;
+ unsigned int in_uint32 = 200000000, out_uint32 = 0;
+ long long in_int64 = 1000000000000, out_int64 = 0;
+ unsigned long long in_uint64 = 2000000000000, out_uint64 = 0;
+ double in_double = 3.14159265359, out_double = 0;;
+ const char *in_string = "Hello World";
+ char *out_string = NULL;
+ const char *in_objectpath = "/org/libvirt/test";
+ char *out_objectpath = NULL;
+ const char *in_signature = "ybnqiuxtdsog";
+ char *out_signature = NULL;
+
+ if (!(msg = dbus_message_new_method_call("org.libvirt.test",
+ "/org/libvirt/test",
+ "org.libvirt.test.astrochicken",
+ "cluck"))) {
+ VIR_DEBUG("Failed to allocate method call");
+ goto cleanup;
+ }
+
+ if (virDBusMessageEncode(msg,
+ "ybn(qiuxtds)og",
+ in_byte, in_bool,
+ in_int16, in_uint16,
+ in_int32, in_uint32,
+ in_int64, in_uint64,
+ in_double, in_string,
+ in_objectpath, in_signature) < 0) {
+ VIR_DEBUG("Failed to encode arguments");
+ goto cleanup;
+ }
+
+ if (virDBusMessageDecode(msg,
+ "ybn(qiuxtds)og",
+ &out_byte, &out_bool,
+ &out_int16, &out_uint16,
+ &out_int32, &out_uint32,
+ &out_int64, &out_uint64,
+ &out_double, &out_string,
+ &out_objectpath, &out_signature) < 0) {
+ VIR_DEBUG("Failed to decode arguments");
+ goto cleanup;
+ }
+
+ VERIFY("byte", in_byte, out_byte, "%d");
+ VERIFY("bool", in_bool, out_bool, "%d");
+ VERIFY("int16", in_int16, out_int16, "%d");
+ VERIFY("uint16", in_int16, out_int16, "%d");
+ VERIFY("int32", in_int32, out_int32, "%d");
+ VERIFY("uint32", in_int32, out_int32, "%d");
+ VERIFY("int64", in_int64, out_int64, "%lld");
+ VERIFY("uint64", in_int64, out_int64, "%lld");
+ VERIFY("double", in_double, out_double, "%lf");
+ VERIFY_STR("string", in_string, out_string, "%s");
+ VERIFY_STR("objectpath", in_objectpath, out_objectpath, "%s");
+ VERIFY_STR("signature", in_signature, out_signature, "%s");
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(out_string);
+ VIR_FREE(out_signature);
+ VIR_FREE(out_objectpath);
+ dbus_message_unref(msg);
+ return ret;
+}
+
+
+static int testMessageDict(const void *args ATTRIBUTE_UNUSED)
+{
+ DBusMessage *msg = NULL;
+ int ret = -1;
+ const char *in_str1 = "Hello";
+ size_t arraylen = 3;
+ int in_int32a = 100000000, out_int32a = 0;
+ const char *in_key1 = "turnover";
+ int in_int32b = 200000000, out_int32b = 0;
+ const char *in_key2 = "revenue";
+ int in_int32c = 300000000, out_int32c = 0;
+ const char *in_key3 = "debt";
+ const char *in_str2 = "World";
+ char *out_str1 = NULL, *out_str2 = NULL;
+ char *out_key1 = NULL, *out_key2 = NULL, *out_key3 = NULL;
+
+ if (!(msg = dbus_message_new_method_call("org.libvirt.test",
+ "/org/libvirt/test",
+ "org.libvirt.test.astrochicken",
+ "cluck"))) {
+ VIR_DEBUG("Failed to allocate method call");
+ goto cleanup;
+ }
+
+ if (virDBusMessageEncode(msg,
+ "sa{si}s",
+ in_str1,
+ arraylen,
+ in_key1, in_int32a,
+ in_key2, in_int32b,
+ in_key3, in_int32c,
+ in_str2) < 0) {
+ VIR_DEBUG("Failed to encode arguments");
+ goto cleanup;
+ }
+
+ if (virDBusMessageDecode(msg,
+ "sa{si}s",
+ &out_str1,
+ arraylen,
+ &out_key1, &out_int32a,
+ &out_key2, &out_int32b,
+ &out_key3, &out_int32c,
+ &out_str2) < 0) {
+ VIR_DEBUG("Failed to decode arguments");
+ goto cleanup;
+ }
+
+
+ VERIFY_STR("str1", in_str1, out_str1, "%s");
+ VERIFY("int32a", in_int32a, out_int32a, "%d");
+ VERIFY("int32b", in_int32b, out_int32b, "%d");
+ VERIFY("int32c", in_int32c, out_int32c, "%d");
+ VERIFY_STR("key1", in_key1, out_key1, "%s");
+ VERIFY_STR("key1", in_key2, out_key2, "%s");
+ VERIFY_STR("key1", in_key3, out_key3, "%s");
+ VERIFY_STR("str2", in_str2, out_str2, "%s");
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(out_str1);
+ VIR_FREE(out_str2);
+ VIR_FREE(out_key1);
+ VIR_FREE(out_key2);
+ VIR_FREE(out_key3);
+ dbus_message_unref(msg);
+ return ret;
+}
+
+
+static int
+mymain(void)
+{
+ int ret = 0;
+
+ if (virtTestRun("Test message simple ", 1, testMessageSimple, NULL) < 0)
+ ret = -1;
+ if (virtTestRun("Test message variant ", 1, testMessageVariant, NULL) < 0)
+ ret = -1;
+ if (virtTestRun("Test message array ", 1, testMessageArray, NULL) < 0)
+ ret = -1;
+ if (virtTestRun("Test message struct ", 1, testMessageStruct, NULL) < 0)
+ ret = -1;
+ if (virtTestRun("Test message dict ", 1, testMessageDict, NULL) < 0)
+ ret = -1;
+ return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+VIRT_TEST_MAIN(mymain)
--
1.8.1.4
11 years, 4 months
[libvirt] [PATCH v2] cgroup: reuse buffer for getline
by Ján Tomko
Reuse the buffer for getline and track buffer allocation
separately from the string length to prevent unlikely
out-of-bounds memory access.
This fixes the following leak that happened when zero bytes were read:
==404== 120 bytes in 1 blocks are definitely lost in loss record 1,344 of 1,671
==404== at 0x4C2C71B: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==404== by 0x906F862: getdelim (iogetdelim.c:68)
==404== by 0x52A48FB: virCgroupPartitionNeedsEscaping (vircgroup.c:1136)
==404== by 0x52A0FB4: virCgroupPartitionEscape (vircgroup.c:1171)
==404== by 0x52A0EA4: virCgroupNewDomainPartition (vircgroup.c:1450)
---
v1: cgroup: Free line even if no characters were read
https://www.redhat.com/archives/libvir-list/2013-July/msg01030.html
src/util/vircgroup.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
index 5a98393..9dfe98d 100644
--- a/src/util/vircgroup.c
+++ b/src/util/vircgroup.c
@@ -1098,13 +1098,13 @@ cleanup:
#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
static int virCgroupPartitionNeedsEscaping(const char *path)
{
FILE *fp = NULL;
int ret = 0;
char *line = NULL;
- size_t len;
+ size_t buflen;
/* If it starts with 'cgroup.' or a '_' of any
* of the controller names from /proc/cgroups,
* then we must prefix a '_'
*/
if (STRPREFIX(path, "cgroup."))
@@ -1130,37 +1130,37 @@ static int virCgroupPartitionNeedsEscaping(const char *path)
* cpuacct 3 48 1
* memory 4 4 1
* devices 5 4 1
* freezer 6 4 1
* net_cls 7 1 1
*/
- while (getline(&line, &len, fp) > 0) {
- if (STRPREFIX(line, "#subsys_name")) {
- VIR_FREE(line);
+ while (getline(&line, &buflen, fp) > 0) {
+ char *tmp;
+ size_t len;
+
+ if (STRPREFIX(line, "#subsys_name"))
continue;
- }
- char *tmp = strchr(line, ' ');
- if (tmp)
- *tmp = '\0';
+
+ tmp = strchrnul(line, ' ');
+ *tmp = '\0';
len = tmp - line;
if (STRPREFIX(path, line) &&
path[len] == '.') {
ret = 1;
- VIR_FREE(line);
goto cleanup;
}
- VIR_FREE(line);
}
if (ferror(fp)) {
ret = -EIO;
goto cleanup;
}
cleanup:
+ VIR_FREE(line);
VIR_FORCE_FCLOSE(fp);
return ret;
}
static int virCgroupPartitionEscape(char **path)
{
--
1.8.1.5
11 years, 4 months
[libvirt] [PATCH] lxc_container: Don't call virGetGroupList during exec
by Michal Privoznik
Commit 75c1256 states that virGetGroupList must not be called
between fork and exec, then commit ee777e99 promptly violated
that for lxc.
Patch originally posted by Eric Blake <eblake(a)redhat.com>.
---
src/lxc/lxc_container.c | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index b51d7a2..37d2ba6 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -351,24 +351,18 @@ int lxcContainerWaitForContinue(int control)
*/
static int lxcContainerSetID(virDomainDefPtr def)
{
- gid_t *groups;
- int ngroups;
-
/* Only call virSetUIDGID when user namespace is enabled
* for this container. And user namespace is only enabled
* when nuidmap&ngidmap is not zero */
VIR_DEBUG("Set UID/GID to 0/0");
if (def->idmap.nuidmap &&
- ((ngroups = virGetGroupList(0, 0, &groups) < 0) ||
- virSetUIDGID(0, 0, groups, ngroups) < 0)) {
+ virSetUIDGID(0, 0, groups, ngroups) < 0) {
virReportSystemError(errno, "%s",
_("setuid or setgid failed"));
- VIR_FREE(groups);
return -1;
}
- VIR_FREE(groups);
return 0;
}
--
1.8.1.5
11 years, 4 months
[libvirt] [PATCH] qemu_conf: Properly mark driver->config as self-locking APIs
by Michal Privoznik
Since a9e97e0c we don't require driver->config, or
virQEMUDriverGetConfig() to be called with locked QEMU driver. In fact,
calling it with the driver locked would cause deadlock. Hence, the
annotation to the struct field is not right.
---
src/qemu/qemu_conf.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 8229cfc..fd5cc57 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -160,8 +160,7 @@ struct _virQEMUDriverConfig {
struct _virQEMUDriver {
virMutex lock;
- /* Require lock to get reference on 'config',
- * then lockless thereafter */
+ /* Immutable pointer, self-locking APIs */
virQEMUDriverConfigPtr config;
/* Immutable pointer, self-locking APIs */
--
1.8.1.5
11 years, 4 months
[libvirt] [PATCH RFC] lib: Forbid guest interaction with RO connections in virDomainGetVcpusFlags
by Peter Krempa
Don't allow guest agent interaction by read-only connections as the
agent may be mailicious.
---
src/libvirt.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/libvirt.c b/src/libvirt.c
index 0cdac0d..f064f32 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -9891,6 +9891,12 @@ virDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
return -1;
}
+ if (flags & VIR_DOMAIN_VCPU_GUEST &&
+ domain->conn->flags & VIR_CONNECT_RO) {
+ virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+ goto error;
+ }
+
/* At most one of these two flags should be set. */
if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
(flags & VIR_DOMAIN_AFFECT_CONFIG)) {
--
1.8.3.2
11 years, 4 months