[libvirt] [PATCH] make: Fix 'make syntax-check' failing.
by Peter Krempa
Commit 2a0d75e5 added file python/libvirt-qemu-override.c that contains
code that does not pass "make syntax-check". This patch adds an
exception for this file and the check.
prohibit_always_true_header_tests
python/libvirt-qemu-override.c:17:#undef HAVE_PTHREAD_H
maint.mk: do not test the above HAVE_<header>_H symbol(s);
with the corresponding gnulib module, they are always true
make: *** [sc_prohibit_always_true_header_tests] Error 1
---
cfg.mk | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/cfg.mk b/cfg.mk
index 1bd9891..39eb49e 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -689,7 +689,7 @@ exclude_file_name_regexp--sc_prohibit_VIR_ERR_NO_MEMORY = \
exclude_file_name_regexp--sc_prohibit_access_xok = ^src/util/util\.c$$
exclude_file_name_regexp--sc_prohibit_always_true_header_tests = \
- ^python/(libvirt-override|typewrappers)\.c$$
+ ^python/(libvirt-override|libvirt-qemu-override|typewrappers)\.c$$
exclude_file_name_regexp--sc_prohibit_asprintf = \
^(bootstrap.conf$$|src/util/util\.c$$|examples/domain-events/events-c/event-test\.c$$)
--
1.7.3.4
13 years, 2 months
[libvirt] [PATCH] xml: Clean up rest of virtual XML document names for XML strings
by Peter Krempa
Commit 498d783387389bfd74437bf84374583f5a3d3bf6 cleans up some of
virtual file names for parsing strings in memory. This patch cleans up
(hopefuly) the rest forgotten by the first patch.
---
src/conf/domain_conf.c | 4 ++--
src/conf/interface_conf.c | 2 +-
src/conf/network_conf.c | 2 +-
src/conf/node_device_conf.c | 2 +-
src/conf/nwfilter_conf.c | 2 +-
src/conf/secret_conf.c | 2 +-
src/conf/storage_conf.c | 6 +++---
src/cpu/cpu.c | 4 ++--
src/esx/esx_vi.c | 2 +-
src/qemu/qemu_migration.c | 2 +-
10 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 11755fe..886aa53 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -5739,7 +5739,7 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
xmlXPathContextPtr ctxt = NULL;
virDomainDeviceDefPtr dev = NULL;
- if (!(xml = virXMLParseStringCtxt(xmlStr, "device.xml", &ctxt))) {
+ if (!(xml = virXMLParseStringCtxt(xmlStr, _("(device definition)"), &ctxt))) {
goto error;
}
node = ctxt->node;
@@ -11573,7 +11573,7 @@ virDomainSnapshotDefParseString(const char *xmlStr,
int active;
char *tmp;
- xml = virXMLParseCtxt(NULL, xmlStr, "domainsnapshot.xml", &ctxt);
+ xml = virXMLParseCtxt(NULL, xmlStr, _("(domain snapshot)"), &ctxt);
if (!xml) {
return NULL;
}
diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c
index 10377e7..d320c81 100644
--- a/src/conf/interface_conf.c
+++ b/src/conf/interface_conf.c
@@ -864,7 +864,7 @@ virInterfaceDefParse(const char *xmlStr,
xmlDocPtr xml;
virInterfaceDefPtr def = NULL;
- if ((xml = virXMLParse(filename, xmlStr, "interface.xml"))) {
+ if ((xml = virXMLParse(filename, xmlStr, _("(interface definition)")))) {
def = virInterfaceDefParseNode(xml, xmlDocGetRootElement(xml));
xmlFreeDoc(xml);
}
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index e055094..487d28c 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -1084,7 +1084,7 @@ virNetworkDefParse(const char *xmlStr,
xmlDocPtr xml;
virNetworkDefPtr def = NULL;
- if ((xml = virXMLParse(filename, xmlStr, "network.xml"))) {
+ if ((xml = virXMLParse(filename, xmlStr, _("(network definition)")))) {
def = virNetworkDefParseNode(xml, xmlDocGetRootElement(xml));
xmlFreeDoc(xml);
}
diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
index 6b0ef50..b584356 100644
--- a/src/conf/node_device_conf.c
+++ b/src/conf/node_device_conf.c
@@ -1231,7 +1231,7 @@ virNodeDeviceDefParse(const char *str,
xmlDocPtr xml;
virNodeDeviceDefPtr def = NULL;
- if ((xml = virXMLParse(filename, str, "device.xml"))) {
+ if ((xml = virXMLParse(filename, str, _("(node device definition)")))) {
def = virNodeDeviceDefParseNode(xml, xmlDocGetRootElement(xml), create);
xmlFreeDoc(xml);
}
diff --git a/src/conf/nwfilter_conf.c b/src/conf/nwfilter_conf.c
index 04bfa22..035f7e4 100644
--- a/src/conf/nwfilter_conf.c
+++ b/src/conf/nwfilter_conf.c
@@ -2119,7 +2119,7 @@ virNWFilterDefParse(virConnectPtr conn ATTRIBUTE_UNUSED,
virNWFilterDefPtr def = NULL;
xmlDocPtr xml;
- if ((xml = virXMLParse(filename, xmlStr, "nwfilter.xml"))) {
+ if ((xml = virXMLParse(filename, xmlStr, _("(nwfilter definition")))) {
def = virNWFilterDefParseNode(xml, xmlDocGetRootElement(xml));
xmlFreeDoc(xml);
}
diff --git a/src/conf/secret_conf.c b/src/conf/secret_conf.c
index 105afbe..39b20bf 100644
--- a/src/conf/secret_conf.c
+++ b/src/conf/secret_conf.c
@@ -195,7 +195,7 @@ virSecretDefParse(const char *xmlStr,
xmlDocPtr xml;
virSecretDefPtr ret = NULL;
- if ((xml = virXMLParse(filename, xmlStr, "secret.xml"))) {
+ if ((xml = virXMLParse(filename, xmlStr, _("(definition of secret)")))) {
ret = secretXMLParseNode(xml, xmlDocGetRootElement(xml));
xmlFreeDoc(xml);
}
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index 1e7da69..2279a20 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -505,7 +505,7 @@ virStoragePoolDefParseSourceString(const char *srcSpec,
xmlXPathContextPtr xpath_ctxt = NULL;
virStoragePoolSourcePtr def = NULL, ret = NULL;
- if (!(doc = virXMLParseStringCtxt(srcSpec, "srcSpec.xml", &xpath_ctxt))) {
+ if (!(doc = virXMLParseStringCtxt(srcSpec, _("(storage source specification)"), &xpath_ctxt))) {
goto cleanup;
}
@@ -765,7 +765,7 @@ virStoragePoolDefParse(const char *xmlStr,
virStoragePoolDefPtr ret = NULL;
xmlDocPtr xml;
- if ((xml = virXMLParse(filename, xmlStr, "storage.xml"))) {
+ if ((xml = virXMLParse(filename, xmlStr, _("(storage pool definition)")))) {
ret = virStoragePoolDefParseNode(xml, xmlDocGetRootElement(xml));
xmlFreeDoc(xml);
}
@@ -1146,7 +1146,7 @@ virStorageVolDefParse(virStoragePoolDefPtr pool,
virStorageVolDefPtr ret = NULL;
xmlDocPtr xml;
- if ((xml = virXMLParse(filename, xmlStr, "storage.xml"))) {
+ if ((xml = virXMLParse(filename, xmlStr, _("(storage volume definition)")))) {
ret = virStorageVolDefParseNode(pool, xml, xmlDocGetRootElement(xml));
xmlFreeDoc(xml);
}
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
index b47f078..5158bb8 100644
--- a/src/cpu/cpu.c
+++ b/src/cpu/cpu.c
@@ -76,7 +76,7 @@ cpuCompareXML(virCPUDefPtr host,
VIR_DEBUG("host=%p, xml=%s", host, NULLSTR(xml));
- if (!(doc = virXMLParseStringCtxt(xml, "cpu.xml", &ctxt)))
+ if (!(doc = virXMLParseStringCtxt(xml, _("(CPU definition)"), &ctxt)))
goto cleanup;
cpu = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_AUTO);
@@ -304,7 +304,7 @@ cpuBaselineXML(const char **xmlCPUs,
goto no_memory;
for (i = 0; i < ncpus; i++) {
- if (!(doc = virXMLParseStringCtxt(xmlCPUs[i], "cpu.xml", &ctxt)))
+ if (!(doc = virXMLParseStringCtxt(xmlCPUs[i], _("(CPU definition)"), &ctxt)))
goto error;
cpus[i] = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_HOST);
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index f4033eb..2d9890c 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -911,7 +911,7 @@ esxVI_Context_Execute(esxVI_Context *ctx, const char *methodName,
if ((*response)->responseCode == 500 || (*response)->responseCode == 200) {
(*response)->document = virXMLParseStringCtxt((*response)->content,
- "esx.xml",
+ _("(esx execute response)"),
&xpathContext);
if ((*response)->document == NULL) {
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index f849d05..42324b0 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -603,7 +603,7 @@ qemuMigrationCookieXMLParseStr(qemuMigrationCookiePtr mig,
VIR_DEBUG("xml=%s", NULLSTR(xml));
- if (!(doc = virXMLParseStringCtxt(xml, "qemumigration.xml", &ctxt)))
+ if (!(doc = virXMLParseStringCtxt(xml, _("(qemu migration cookie)"), &ctxt)))
goto cleanup;
ret = qemuMigrationCookieXMLParse(mig, ctxt, flags);
--
1.7.3.4
13 years, 2 months
[libvirt] libvirt on Android
by Stefan Scheglmann
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi,
i am new to this list and i am wondering if anybody already tried to
port libvirt to android via ndk. To be able to implement a virt-manager
like app for android based systems.
Greets & thx
Stefan
- --
Stefan Scheglmann
WeST Research Group
University of Koblenz-Landau
Universitaetsstrasse 1
D-56070 Koblenz
Tel.: + 49 261 287 2718
Fax: + 49 261 287 100 2718
schegi(a)uni-koblenz.de
http://west.uni-koblenz.de
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iQEcBAEBAgAGBQJOcKU3AAoJEIaCIv/n5qljS7YIAJ4QG95COQf2wq+ujzOSLtkf
gEbfKVACJo6sVIj/hcqhCCWuwsljk/Fc9vGE43oBTCjs7pk5OW5ama5A8C2VIXn6
aLWm/KIWSezciVtr4GNliQ4DDcSzC6OKgiE1dNWkDf3+J+x3NpGeUNE3nlSvRBUg
QmOqky1XF1CmduMPiAmqR/5mKOJS2imfPBtAF50sWx1pDemYbV2u32GAdntQRuy+
vDhD78KLmI2sRZi3jYLblFpaFKoG2Movu1QxhmVBJFe/lxaqtr25iwnoUdVIxHFU
scki3ybMWBosTm7Na5mvCKE1MeFg+6/ZoswpUHJb5F2gN4v3byLcSOEgJtnNWig=
=aDzr
-----END PGP SIGNATURE-----
13 years, 2 months
[libvirt] [PATCH RFC v2] virsh: Add option to undefine storage with domains
by Peter Krempa
Add an option for virsh undefine command, to remove associated storage
volumes while undefining a domain. This patch alows the user to remove
associated (libvirt managed ) storage volumes while undefining a domain.
The new option --storage for the undefine command takes a string
argument that consists of comma separated list of target volumes to be
undefined. Each of the volumes is removed from the domain definition and
afterwards removed from storage pools.
If a volume is not part of a storage pool, the user is warned to remove
the volume in question himself.
Option --wipe-storage may be specified along with this, that ensures
the image is wiped before removing.
---
tools/virsh.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/virsh.pod | 12 ++++
2 files changed, 179 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 3b060bf..67125c9 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -1858,6 +1858,9 @@ static const vshCmdInfo info_undefine[] = {
static const vshCmdOptDef opts_undefine[] = {
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name or uuid")},
{"managed-save", VSH_OT_BOOL, 0, N_("remove domain managed state file")},
+ {"storage", VSH_OT_DATA, VSH_OFLAG_NONE,
+ N_("remove associated storage volumes (comma separated list of targets) (see domblklist)")},
+ {"wipe-storage", VSH_OT_BOOL, VSH_OFLAG_NONE, N_("wipe data on the removed volumes")},
{"snapshots-metadata", VSH_OT_BOOL, 0,
N_("remove all domain snapshot metadata, if inactive")},
{NULL, 0, 0, NULL}
@@ -1874,6 +1877,8 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd)
/* User-requested actions. */
bool managed_save = vshCommandOptBool(cmd, "managed-save");
bool snapshots_metadata = vshCommandOptBool(cmd, "snapshots-metadata");
+ bool wipe_storage = vshCommandOptBool(cmd, "wipe-storage");
+ bool remove_volumes = false;
/* Positive if these items exist. */
int has_managed_save = 0;
int has_snapshots_metadata = 0;
@@ -1883,6 +1888,25 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd)
bool snapshots_safe = false;
int rc = -1;
int running;
+ /* list of volumes to remove along with this domain */
+ const char *volumes_arg = NULL;
+ char *volumes = NULL;
+ const char *volume;
+ char *saveptr = NULL;
+ char *def = NULL;
+ char *xpath_str = NULL;
+ char *volume_path = NULL;
+ char *device_desc = NULL;
+ xmlNodePtr node = NULL;
+ xmlXPathContextPtr ctxt_dom = NULL;
+ xmlXPathContextPtr ctxt_dev = NULL;
+ xmlBufferPtr xml_buf = NULL;
+ xmlDocPtr xml_dom = NULL;
+ xmlDocPtr xml_dev = NULL;
+ virStorageVolPtr vol = NULL;
+ bool wipe_failed;
+
+ virBuffer xpath = VIR_BUFFER_INITIALIZER;
if (managed_save) {
flags |= VIR_DOMAIN_UNDEFINE_MANAGED_SAVE;
@@ -1893,12 +1917,19 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd)
snapshots_safe = true;
}
+
if (!vshConnectionUsability(ctl, ctl->conn))
return false;
if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
return false;
+ /* check if a string that should contain list of volumes to remove is present */
+ if (vshCommandOptString(cmd, "storage", &volumes_arg) > 0) {
+ remove_volumes = true;
+ volumes = vshStrdup(ctl, volumes_arg);
+ }
+
/* Do some flag manipulation. The goal here is to disable bits
* from flags to reduce the likelihood of a server rejecting
* unknown flag bits, as well as to track conditions which are
@@ -1961,6 +1992,138 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd)
snapshots_safe = true;
}
+ /* try to undefine storage volumes associated with this domain, if it's requested */
+ if (remove_volumes) {
+ if (running) {
+ vshError(ctl, _("Refusing to remove storage for running domain"));
+ goto cleanup;
+ }
+
+ /* check if managed save is being removed, as the domain removal
+ * might fail and leave it without storage */
+ if (has_managed_save && !managed_save) {
+ vshError(ctl, "%s",
+ _("Refusing to undefine with storage volumes while domain managed save "
+ "image exists"));
+ goto cleanup;
+ }
+
+ /* get domain description */
+ if (!(def = virDomainGetXMLDesc(dom, 0)))
+ goto cleanup;
+
+ xml_dom = virXMLParseStringCtxt(def, _("(domain definition)"), &ctxt_dom);
+ VIR_FREE(def);
+
+ if (!xml_dom)
+ goto cleanup;
+
+ xml_buf = xmlBufferCreate();
+ if (!xml_buf)
+ goto cleanup;
+
+ /* tokenize the string of devices to remove */
+ volume = strtok_r(volumes, ",", &saveptr);
+
+ while (volume) {
+
+ /* find and try to remove each volume selected by the user */
+ virBufferAsprintf(&xpath, "/domain/devices/disk[target[@dev='%s']]", volume);
+ xpath_str = virBufferContentAndReset(&xpath);
+
+ node = virXPathNode(xpath_str, ctxt_dom);
+ VIR_FREE(xpath_str);
+ if (!node) {
+ vshPrint(ctl, _("Volume %s not found. Skipping\n"), volume);
+ goto next_volume;
+ }
+
+ xmlBufferEmpty(xml_buf);
+
+ /* dump and detatch the device from persistent conf. */
+
+ if (xmlNodeDump(xml_buf, xml_dom, node, 0, 0) < 0) {
+ vshError(ctl, _("Failed to create device description"));
+ goto cleanup;
+ }
+
+ device_desc = (char *) xmlBufferContent(xml_buf);
+
+ if (virDomainDetachDeviceFlags(dom, device_desc, VIR_DOMAIN_AFFECT_CURRENT) < 0) {
+ vshError(ctl,
+ _("Failed to remove storage device '%s' from definition. "
+ "If domain undefinition fails, this domain may remain inconsistent"),
+ volume);
+ }
+
+ xml_dev = virXMLParseStringCtxt(device_desc,
+ _("(storage volume definition)"),
+ &ctxt_dev);
+
+ /* find the target and lookup the image in storage pools */
+ if (!xml_dev)
+ goto cleanup;
+
+ volume_path = virXPathString("string(//disk/source/@file"
+ "| //disk/source/@dev"
+ "| //disk/source/@dir"
+ "| //disk/source/@name)", ctxt_dev);
+
+ if (!volume_path) {
+ vshPrint(ctl,
+ _("Virtual storage device '%s' has no associated volume. Skipping."),
+ volume);
+ goto next_volume;
+ }
+
+ vol = virStorageVolLookupByPath(ctl->conn, volume_path);
+
+ if (!vol) {
+ vshPrint(ctl,
+ _("Storage volume '%s' is not managed by libvirt. Remove it manualy.\n"),
+ volume_path);
+ goto next_volume;
+ }
+
+ wipe_failed = false;
+
+ /* wipe the volume */
+ if (wipe_storage) {
+ vshPrint(ctl, _("Wiping volume '%s' ... "), volume_path);
+ if (virStorageVolWipe(vol, 0) < 0) {
+ vshPrint(ctl, _("Failed!\n"));
+ wipe_failed = true;
+ } else {
+ vshPrint(ctl, _("Done.\n"));
+ }
+ }
+
+
+ /* delete the volume */
+ if (wipe_failed || virStorageVolDelete(vol, 0) < 0) {
+ vshError(ctl,
+ _("Failed to remove storage volume '%s'. Remove it manualy."),
+ volume_path);
+ } else {
+ vshPrint(ctl, _("Volume '%s' deleted.\n"), volume_path);
+ }
+
+
+next_volume:
+ VIR_FREE(volume_path);
+ if (vol)
+ virStorageVolFree(vol);
+ vol = NULL;
+ xmlXPathFreeContext(ctxt_dev);
+ ctxt_dev = NULL;
+ xmlFreeDoc(xml_dev);
+ xml_dev = NULL;
+
+ volume = strtok_r(NULL, ",", &saveptr);
+ }
+ /* domain's storage removed */
+ }
+
/* Generally we want to try the new API first. However, while
* virDomainUndefineFlags was introduced at the same time as
* VIR_DOMAIN_UNDEFINE_MANAGED_SAVE in 0.9.4, the
@@ -2013,6 +2176,10 @@ out:
}
cleanup:
+ xmlFreeDoc(xml_dom);
+ xmlBufferFree(xml_buf);
+ xmlXPathFreeContext(ctxt_dom);
+ VIR_FREE(volumes);
virDomainFree(dom);
return ret;
}
diff --git a/tools/virsh.pod b/tools/virsh.pod
index e82567d..87a1e7d 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1067,6 +1067,7 @@ Output the device used for the TTY console of the domain. If the information
is not available the processes will provide an exit code of 1.
=item B<undefine> I<domain-id> [I<--managed-save>] [I<--snapshots-metadata]
+[I<--storage volumes>] [I<--wipe-storage>]
Undefine a domain. If the domain is running, this converts it to a
transient domain, without stopping it. If the domain is inactive,
@@ -1082,6 +1083,17 @@ domain. Without the flag, attempts to undefine an inactive domain with
snapshot metadata will fail. If the domain is active, this flag is
ignored.
+The I<--storage> flag takes a parameter volumes, that is a comma separated
+list of volume target names of storage volumes to be removed along with
+the undefined domain. This operation is valid only for a inactive domain.
+If one or more of the operations while removing disk storage fail, the
+domain may still be undefined and some volumes may remain undeleted.
+(See B<domblklist> for list of target names associated to a domain).
+Example: --storage vda,vdb,vdc
+
+The Flag I<--wipe-storage> specifies, that the storage volumes should be
+wiped before removal.
+
NOTE: For an inactive domain, the domain name or UUID must be used as the
I<domain-id>.
--
1.7.3.4
13 years, 2 months
[libvirt] [PATCH 1/2] Add VIR_TYPED_PARAM_STRING
by Hu Tao
---
daemon/remote.c | 15 +++++++++++++++
include/libvirt/libvirt.h.in | 4 +++-
src/remote/remote_driver.c | 15 +++++++++++++++
src/remote/remote_protocol.x | 2 ++
4 files changed, 35 insertions(+), 1 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index 0f088c6..afceab7 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -615,6 +615,13 @@ remoteSerializeTypedParameters(virTypedParameterPtr params,
case VIR_TYPED_PARAM_BOOLEAN:
val[i].value.remote_typed_param_value_u.b = params[i].value.b;
break;
+ case VIR_TYPED_PARAM_STRING:
+ val[i].value.remote_typed_param_value_u.s = strdup(params[i].value.s);
+ if (val[i].value.remote_typed_param_value_u.s == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ break;
default:
virNetError(VIR_ERR_RPC, _("unknown parameter type: %d"),
params[i].type);
@@ -693,6 +700,14 @@ remoteDeserializeTypedParameters(remote_typed_param *args_params_val,
params[i].value.b =
args_params_val[i].value.remote_typed_param_value_u.b;
break;
+ case VIR_TYPED_PARAM_STRING:
+ params[i].value.s =
+ strdup(args_params_val[i].value.remote_typed_param_value_u.s);
+ if (params[i].value.s == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ break;
default:
virNetError(VIR_ERR_INTERNAL_ERROR, _("unknown parameter type: %d"),
params[i].type);
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 53a2f7d..da2080e 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -481,7 +481,8 @@ typedef enum {
VIR_TYPED_PARAM_LLONG = 3, /* long long case */
VIR_TYPED_PARAM_ULLONG = 4, /* unsigned long long case */
VIR_TYPED_PARAM_DOUBLE = 5, /* double case */
- VIR_TYPED_PARAM_BOOLEAN = 6 /* boolean(character) case */
+ VIR_TYPED_PARAM_BOOLEAN = 6, /* boolean(character) case */
+ VIR_TYPED_PARAM_STRING = 7 /* string case */
} virTypedParameterType;
/**
@@ -512,6 +513,7 @@ struct _virTypedParameter {
unsigned long long int ul; /* type is ULLONG */
double d; /* type is DOUBLE */
char b; /* type is BOOLEAN */
+ char *s; /* type is STRING */
} value; /* parameter value */
};
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 603d589..8f9d09c 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -1276,6 +1276,13 @@ remoteSerializeTypedParameters(virTypedParameterPtr params,
case VIR_TYPED_PARAM_BOOLEAN:
val[i].value.remote_typed_param_value_u.b = params[i].value.b;
break;
+ case VIR_TYPED_PARAM_STRING:
+ val[i].value.remote_typed_param_value_u.s = strdup(params[i].value.s);
+ if (val[i].value.remote_typed_param_value_u.s == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ break;
default:
remoteError(VIR_ERR_RPC, _("unknown parameter type: %d"),
params[i].type);
@@ -1347,6 +1354,14 @@ remoteDeserializeTypedParameters(remote_typed_param *ret_params_val,
params[i].value.b =
ret_params_val[i].value.remote_typed_param_value_u.b;
break;
+ case VIR_TYPED_PARAM_STRING:
+ params[i].value.s =
+ strdup(ret_params_val[i].value.remote_typed_param_value_u.s);
+ if (params[i].value.s == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ break;
default:
remoteError(VIR_ERR_RPC, _("unknown parameter type: %d"),
params[i].type);
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 8f68808..c22a566 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -314,6 +314,8 @@ union remote_typed_param_value switch (int type) {
double d;
case VIR_TYPED_PARAM_BOOLEAN:
int b;
+ case VIR_TYPED_PARAM_STRING:
+ remote_nonnull_string s;
};
struct remote_typed_param {
--
1.7.3.1
13 years, 2 months
[libvirt] [PATCH v3] virsh: Increase device-detach intelligence
by Michal Privoznik
From: Michal Prívozník <mprivozn(a)redhat.com>
Up to now users have to give a full XML description on input when
device-detaching. If they omitted something it lead to unclear
error messages (like generated MAC wasn't found, etc.).
With this patch users can specify only those information which
specify one device sufficiently precise. Remaining information is
completed from domain.
---
diff to v2:
-rebase to current HEAD
diff to v1:
-rebase to current HEAD
-add a little bit comments
tools/virsh.c | 266 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 250 insertions(+), 16 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 1ad84a2..aae8e4e 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -10351,6 +10351,226 @@ cmdAttachDevice(vshControl *ctl, const vshCmd *cmd)
return true;
}
+/**
+ * Check if n1 is superset of n2, meaning n1 contains all elements and
+ * attributes as n2 at lest. Including children.
+ * @n1 first node
+ * @n2 second node
+ * return 1 in case n1 covers n2, 0 otherwise.
+ */
+static int
+vshNodeIsSuperset(xmlNodePtr n1, xmlNodePtr n2) {
+ xmlNodePtr child1, child2;
+ xmlAttrPtr attr1, attr2;
+ int found;
+
+ if (!n1 && !n2)
+ return 1;
+
+ if (!n1 || !n2)
+ return 0;
+
+ if (!xmlStrEqual(n1->name, n2->name))
+ return 0;
+
+ /* Iterate over n2 attributes and check if n1 contains them*/
+ attr2 = n2->properties;
+ while (attr2) {
+ if (attr2->type == XML_ATTRIBUTE_NODE) {
+ attr1 = n1->properties;
+ found = 0;
+ while (attr1) {
+ if (xmlStrEqual(attr1->name, attr2->name)) {
+ found = 1;
+ break;
+ }
+ attr1 = attr1->next;
+ }
+ if (!found)
+ return 0;
+ if (!xmlStrEqual(BAD_CAST virXMLPropString(n1, (const char *) attr1->name),
+ BAD_CAST virXMLPropString(n2, (const char *) attr2->name)))
+ return 0;
+ }
+ attr2 = attr2->next;
+ }
+
+ /* and now iterate over n2 children */
+ child2 = n2->children;
+ while (child2) {
+ if (child2->type == XML_ELEMENT_NODE) {
+ child1 = n1->children;
+ found = 0;
+ while (child1) {
+ if (child1->type == XML_ELEMENT_NODE &&
+ xmlStrEqual(child1->name, child2->name)) {
+ found = 1;
+ break;
+ }
+ child1 = child1->next;
+ }
+ if (!found)
+ return 0;
+ if (!vshNodeIsSuperset(child1, child2))
+ return 0;
+ }
+ child2 = child2->next;
+ }
+
+ return 1;
+}
+
+/**
+ * To given domain and (probably incomplete) device XML specification try to
+ * find such device in domain and complete missing parts. This is however
+ * possible when given device XML is sufficiently precise so it addresses only
+ * one device.
+ * @ctl vshControl for error messages printing
+ * @dom domain
+ * @oldXML device XML before
+ * @newXML and after completion
+ * Returns -2 when no such device exists in domain, -3 when given XML selects many
+ * (is too ambiguous), 0 in case of success. Otherwise returns -1. @newXML
+ * is touched only in case of success.
+ */
+static int
+vshCompleteXMLFromDomain(vshControl *ctl, virDomainPtr dom, char *oldXML,
+ char **newXML) {
+ int funcRet = -1;
+ char *domXML = NULL;
+ xmlDocPtr domDoc = NULL, devDoc = NULL;
+ xmlNodePtr node = NULL;
+ xmlXPathContextPtr domCtxt = NULL, devCtxt = NULL;
+ xmlNodePtr *devices = NULL;
+ xmlSaveCtxtPtr sctxt = NULL;
+ int devices_size;
+ char *xpath;
+ xmlBufferPtr buf = NULL;
+
+ if (!(domXML = virDomainGetXMLDesc(dom, 0))) {
+ vshError(ctl, _("couldn't get XML description of domain %s"),
+ virDomainGetName(dom));
+ goto cleanup;
+ }
+
+ if (!(domDoc = xmlReadDoc(BAD_CAST domXML, "domain.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+ vshError(ctl, "%s", _("could not parse domain XML"));
+ goto cleanup;
+ }
+
+ if (!(devDoc = xmlReadDoc(BAD_CAST oldXML, "device.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+ vshError(ctl, "%s", _("could not parse device XML"));
+ goto cleanup;
+ }
+
+ node = xmlDocGetRootElement(domDoc);
+ if (!node) {
+ vshError(ctl, "%s", _("failed to get domain root element"));
+ goto cleanup;
+ }
+
+ domCtxt = xmlXPathNewContext(domDoc);
+ if (!domCtxt) {
+ vshError(ctl, "%s", _("failed to create context on domain XML"));
+ goto cleanup;
+ }
+ domCtxt->node = node;
+
+ node = xmlDocGetRootElement(devDoc);
+ if (!node) {
+ vshError(ctl, "%s", _("failed to get device root element"));
+ goto cleanup;
+ }
+
+ devCtxt = xmlXPathNewContext(devDoc);
+ if (!devCtxt) {
+ vshError(ctl, "%s", _("failed to create context on device XML"));
+ goto cleanup;
+ }
+ devCtxt->node = node;
+
+ buf = xmlBufferCreate();
+ if (!buf) {
+ vshError(ctl, "%s", _("out of memory"));
+ goto cleanup;
+ }
+
+ xmlBufferCat(buf, BAD_CAST "/domain/devices/");
+ xmlBufferCat(buf, node->name);
+ xpath = (char *) xmlBufferContent(buf);
+ /* Get all possible devices */
+ devices_size = virXPathNodeSet(xpath, domCtxt, &devices);
+ xmlBufferEmpty(buf);
+
+ if (devices_size < 0) {
+ /* error */
+ vshError(ctl, "%s", _("error when selecting nodes"));
+ goto cleanup;
+ } else if (devices_size == 0) {
+ /* no such device */
+ funcRet = -2;
+ goto cleanup;
+ }
+
+ /* and refine */
+ int i = 0;
+ while (i < devices_size) {
+ if (!vshNodeIsSuperset(devices[i], node)) {
+ if (devices_size == 1) {
+ VIR_FREE(devices);
+ devices_size = 0;
+ } else {
+ memmove(devices + i, devices + i + 1,
+ sizeof(*devices) * (devices_size-i-1));
+ devices_size--;
+ if (VIR_REALLOC_N(devices, devices_size) < 0) {
+ /* ignore, harmless */
+ }
+ }
+ } else {
+ i++;
+ }
+ }
+
+ if (!devices_size) {
+ /* no such device */
+ funcRet = -2;
+ goto cleanup;
+ } else if (devices_size > 1) {
+ /* ambiguous */
+ funcRet = -3;
+ goto cleanup;
+ }
+
+ if (newXML) {
+ sctxt = xmlSaveToBuffer(buf, NULL, 0);
+ if (!sctxt) {
+ vshError(ctl, "%s", _("failed to create document saving context"));
+ goto cleanup;
+ }
+
+ xmlSaveTree(sctxt, devices[0]);
+ xmlSaveClose(sctxt);
+ *newXML = (char *) xmlBufferContent(buf);
+ buf->content = NULL;
+ }
+
+ funcRet = 0;
+
+cleanup:
+ xmlBufferFree(buf);
+ VIR_FREE(devices);
+ xmlXPathFreeContext(devCtxt);
+ xmlXPathFreeContext(domCtxt);
+ xmlFreeDoc(devDoc);
+ xmlFreeDoc(domDoc);
+ VIR_FREE(domXML);
+ return funcRet;
+}
/*
* "detach-device" command
@@ -10371,10 +10591,11 @@ static const vshCmdOptDef opts_detach_device[] = {
static bool
cmdDetachDevice(vshControl *ctl, const vshCmd *cmd)
{
- virDomainPtr dom;
+ virDomainPtr dom = NULL;
const char *from = NULL;
- char *buffer;
+ char *buffer = NULL, *new_buffer = NULL;
int ret;
+ bool funcRet = false;
unsigned int flags;
if (!vshConnectionUsability(ctl, ctl->conn))
@@ -10383,37 +10604,50 @@ cmdDetachDevice(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return false;
- if (vshCommandOptString(cmd, "file", &from) <= 0) {
- virDomainFree(dom);
- return false;
- }
+ if (vshCommandOptString(cmd, "file", &from) <= 0)
+ goto cleanup;
if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
virshReportError(ctl);
- virDomainFree(dom);
- return false;
+ goto cleanup;
+ }
+
+ ret = vshCompleteXMLFromDomain(ctl, dom, buffer, &new_buffer);
+ if (ret < 0) {
+ if (ret == -2) {
+ vshError(ctl, _("no such device in %s"), virDomainGetName(dom));
+ } else if (ret == -3) {
+ vshError(ctl, "%s", _("given XML selects too many devices. "
+ "Please, be more specific"));
+ } else {
+ /* vshCompleteXMLFromDomain() already printed error message,
+ * so nothing to do here. */
+ }
+ goto cleanup;
}
if (vshCommandOptBool(cmd, "persistent")) {
flags = VIR_DOMAIN_AFFECT_CONFIG;
if (virDomainIsActive(dom) == 1)
flags |= VIR_DOMAIN_AFFECT_LIVE;
- ret = virDomainDetachDeviceFlags(dom, buffer, flags);
+ ret = virDomainDetachDeviceFlags(dom, new_buffer, flags);
} else {
- ret = virDomainDetachDevice(dom, buffer);
+ ret = virDomainDetachDevice(dom, new_buffer);
}
- VIR_FREE(buffer);
if (ret < 0) {
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"));
+ funcRet = true;
+
+cleanup:
+ VIR_FREE(new_buffer);
+ VIR_FREE(buffer);
virDomainFree(dom);
- return true;
+ return funcRet;
}
--
1.7.3.4
13 years, 2 months
[libvirt] [PATCH] snapshot: fix double free issue for qemuImgBinary value in qemu_driver
by Guannan Ren
*src/qemu/qemu_driver.c: in qemuDomainSnapshotForEachQcow()
it will free up the memory of qemu_driver->qemuImgBinary in the
cleanup tag which leads to the garbage value of qemuImgBinary and
libvirtd crash when running "virsh snapshot-create" command next time.
---
src/qemu/qemu_driver.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b94d1c4..bbe113f 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1735,7 +1735,7 @@ qemuDomainSnapshotForEachQcow2(struct qemud_driver *driver,
ret = skipped ? 1 : 0;
cleanup:
- VIR_FREE(qemuimgarg[0]);
+ qemuimgarg[0] = NULL;
return ret;
}
--
1.7.1
13 years, 2 months
[libvirt] [PATCH] Do not log invalid operations in libvirtd logs
by Daniel Veillard
This is a bit painful for example when starting virt-manager
it tends to clutter libvirtd.log with invalid operation on cpu pinning
for defined but not running domains. A priori those kind of errors
don't indicate an error when executing the command but on a precondition
for running the API, and honnestly while the application should report
it, logging it as an error in libvirtd.log is not really useful,
Related bug: https://bugzilla.redhat.com/show_bug.cgi?id=590807
Daniel
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 1a9fd82..c708ff7 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -357,6 +357,7 @@ static int daemonErrorLogFilter(virErrorPtr err, int priority)
case VIR_ERR_NO_NWFILTER:
case VIR_ERR_NO_SECRET:
case VIR_ERR_NO_DOMAIN_SNAPSHOT:
+ case VIR_ERR_OPERATION_INVALID:
return VIR_LOG_DEBUG;
}
--
Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
daniel(a)veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
13 years, 2 months
[libvirt] [PATCH v5] virsh: Add more human-friendly output of domblkstat command
by Peter Krempa
Users of virsh complain that output of the domblkstat command
is not intuitive enough. This patch adds explanation of fields
returned by this command to the help section for domblkstat and
the man page of virsh. Also a switch --human is added for
domblkstat that prints the fields with more descriptive
texts.
This patch also fixes "error: unknown procedure: 243" while
communicating with an old libvirtd.
https://bugzilla.redhat.com/show_bug.cgi?id=731656
Changes to v4:
- Fields are printed in order established by previous versions
- Fix translation macros
- Run old api unconditionaly (while comunicating with old libvirtd
"error: unknown procedure: 243" occured)
- Remove redundant field description from command help and add reference
to man page.
- Fix formating (unnecessary space after function name)
- Fix man page, mentioning that fields may be missig.
Changes to v3:
- Add units to duration values
- Add missing write doc/stranslation
- Add translation from new api names to legacy names used in previous
versions in virsh
Changes to v2:
- Modify for new fields in virDomainBlockStatsFlags
Changes to v1:
- Rebase to current head
---
tools/virsh.c | 234 +++++++++++++++++++++++++++++++++++++++++++------------
tools/virsh.pod | 20 +++++-
2 files changed, 204 insertions(+), 50 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 3b060bf..766c9be 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -369,6 +369,8 @@ static const char *vshDomainStateReasonToString(int state, int reason);
static const char *vshDomainControlStateToString(int state);
static const char *vshDomainVcpuStateToString(int state);
static bool vshConnectionUsability(vshControl *ctl, virConnectPtr conn);
+static virTypedParameterPtr vshFindTypedParamByName(const char *name, virTypedParameterPtr list, int count);
+static char *vshGetTypedParamValue(vshControl *ctl, virTypedParameterPtr item);
static char *editWriteToTempFile (vshControl *ctl, const char *doc);
static int editFile (vshControl *ctl, const char *filename);
@@ -1054,16 +1056,37 @@ cleanup:
*/
static const vshCmdInfo info_domblkstat[] = {
{"help", N_("get device block stats for a domain")},
- {"desc", N_("Get device block stats for a running domain.")},
+ {"desc", N_("Get device block stats for a running domain. See man page or use --human for explanation of fields\n\n")},
{NULL,NULL}
};
static const vshCmdOptDef opts_domblkstat[] = {
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
{"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")},
+ {"human", VSH_OT_BOOL, 0, N_("print a more human readable output")},
{NULL, 0, 0, NULL}
};
+struct _domblkstat_sequence {
+ const char *field; /* field name */
+ const char *legacy; /* legacy name from previous releases */
+ const char *human; /* human-friendly explanation */
+};
+
+/* sequence of values for output to honor legacy format from previous versions */
+static const struct _domblkstat_sequence domblkstat_output[] = {
+ { VIR_DOMAIN_BLOCK_STATS_READ_REQ, "rd_req", N_("number of read operations: ") }, /* 0 */
+ { VIR_DOMAIN_BLOCK_STATS_READ_BYTES, NULL, N_("number of read bytes: ") }, /* 1 */
+ { VIR_DOMAIN_BLOCK_STATS_WRITE_REQ, "wr_req", N_("number of write operations: ") }, /* 2 */
+ { VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES, NULL, N_("number of bytes written: ") }, /* 3 */
+ { VIR_DOMAIN_BLOCK_STATS_ERRS, NULL, N_("error count: ") }, /* 4 */
+ { VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ, NULL, N_("number of flush operations: ") }, /* 5 */
+ { VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES, NULL, N_("total duration of reads (ns): ") }, /* 6 */
+ { VIR_DOMAIN_BLOCK_STATS_WRITE_TOTAL_TIMES, NULL, N_("total duration of writes (ns): ") }, /* 7 */
+ { VIR_DOMAIN_BLOCK_STATS_FLUSH_TOTAL_TIMES, NULL, N_("total duration of flushes (ns):") }, /* 8 */
+ { NULL, NULL, NULL }
+};
+
static bool
cmdDomblkstat (vshControl *ctl, const vshCmd *cmd)
{
@@ -1071,8 +1094,13 @@ cmdDomblkstat (vshControl *ctl, const vshCmd *cmd)
const char *name = NULL, *device = NULL;
struct _virDomainBlockStats stats;
virTypedParameterPtr params = NULL;
+ virTypedParameterPtr par = NULL;
+ char *value = NULL;
+ const char *field = NULL;
int rc, nparams = 0;
+ int i = 0;
bool ret = false;
+ bool human = vshCommandOptBool(cmd, "human"); /* enable human readable output */
if (!vshConnectionUsability (ctl, ctl->conn))
return false;
@@ -1090,76 +1118,105 @@ cmdDomblkstat (vshControl *ctl, const vshCmd *cmd)
* then.
*/
if (rc < 0) {
- if (last_error->code != VIR_ERR_NO_SUPPORT) {
- virshReportError(ctl);
+ /* try the older api, if the newer returns an error */
+ virFreeError(last_error);
+ last_error = NULL;
+
+ if (virDomainBlockStats (dom, device, &stats,
+ sizeof stats) == -1) {
+ vshError(ctl, _("Failed to get block stats %s %s"),
+ name, device);
goto cleanup;
- } else {
- virFreeError(last_error);
- last_error = NULL;
+ }
- if (virDomainBlockStats (dom, device, &stats,
- sizeof stats) == -1) {
- vshError(ctl, _("Failed to get block stats %s %s"),
- name, device);
- goto cleanup;
- }
+ if (human) {
+ /* human friendly output */
+ vshPrint(ctl, N_("Device: %s\n"), device);
if (stats.rd_req >= 0)
- vshPrint (ctl, "%s rd_req %lld\n", device, stats.rd_req);
+ vshPrint(ctl, "%s %lld\n", _(domblkstat_output[0].human), stats.rd_req);
if (stats.rd_bytes >= 0)
- vshPrint (ctl, "%s rd_bytes %lld\n", device, stats.rd_bytes);
+ vshPrint(ctl, "%s %lld\n", _(domblkstat_output[1].human), stats.rd_bytes);
if (stats.wr_req >= 0)
- vshPrint (ctl, "%s wr_req %lld\n", device, stats.wr_req);
+ vshPrint(ctl, "%s %lld\n", _(domblkstat_output[2].human), stats.wr_req);
if (stats.wr_bytes >= 0)
- vshPrint (ctl, "%s wr_bytes %lld\n", device, stats.wr_bytes);
+ vshPrint(ctl, "%s %lld\n", _(domblkstat_output[3].human), stats.wr_bytes);
if (stats.errs >= 0)
- vshPrint (ctl, "%s errs %lld\n", device, stats.errs);
+ vshPrint(ctl, "%s %lld\n", _(domblkstat_output[4].human), stats.errs);
+ } else {
+
+ if (stats.rd_req >= 0)
+ vshPrint(ctl, "%s rd_req %lld\n", device, stats.rd_req);
+
+ if (stats.rd_bytes >= 0)
+ vshPrint(ctl, "%s rd_bytes %lld\n", device, stats.rd_bytes);
+
+ if (stats.wr_req >= 0)
+ vshPrint(ctl, "%s wr_req %lld\n", device, stats.wr_req);
+
+ if (stats.wr_bytes >= 0)
+ vshPrint(ctl, "%s wr_bytes %lld\n", device, stats.wr_bytes);
+
+ if (stats.errs >= 0)
+ vshPrint(ctl, "%s errs %lld\n", device, stats.errs);
}
} else {
- params = vshMalloc(ctl, sizeof(*params) * nparams);
- memset(params, 0, sizeof(*params) * nparams);
+ params = vshCalloc(ctl, nparams, sizeof(*params));
if (virDomainBlockStatsFlags (dom, device, params, &nparams, 0) < 0) {
vshError(ctl, _("Failed to get block stats %s %s"), name, device);
goto cleanup;
}
- int i;
- /* XXX: The output sequence will be different. */
+ /* set for prettier output */
+ if (human) {
+ vshPrint(ctl, N_("Device: %s\n"), device);
+ device = "";
+ }
+
+ /* at first print all known values in desired order */
+ for (i = 0; domblkstat_output[i].field != NULL; i++) {
+ if (!(par = vshFindTypedParamByName(domblkstat_output[i].field,
+ params,
+ nparams)))
+ continue;
+
+ if (!(value = vshGetTypedParamValue(ctl, par)))
+ continue;
+
+ /* to print other not supported fields, mark the already printed */
+ par->field[0] = '\0'; /* set the name to empty string */
+
+ /* print the value */
+ field = NULL;
+
+ if (human)
+ field = _(domblkstat_output[i].human);
+ else
+ field = domblkstat_output[i].legacy;
+
+ if (!field)
+ field = domblkstat_output[i].field;
+
+ vshPrint(ctl, "%s %s %s\n", device, field, value);
+
+ VIR_FREE(value);
+ }
+
+ /* go through the fields again, looking for fields that were not printed*/
for (i = 0; i < nparams; i++) {
- switch(params[i].type) {
- case VIR_TYPED_PARAM_INT:
- vshPrint (ctl, "%s %s %d\n", device,
- params[i].field, params[i].value.i);
- break;
- case VIR_TYPED_PARAM_UINT:
- vshPrint (ctl, "%s %s %u\n", device,
- params[i].field, params[i].value.ui);
- break;
- case VIR_TYPED_PARAM_LLONG:
- vshPrint (ctl, "%s %s %lld\n", device,
- params[i].field, params[i].value.l);
- break;
- case VIR_TYPED_PARAM_ULLONG:
- vshPrint (ctl, "%s %s %llu\n", device,
- params[i].field, params[i].value.ul);
- break;
- case VIR_TYPED_PARAM_DOUBLE:
- vshPrint (ctl, "%s %s %f\n", device,
- params[i].field, params[i].value.d);
- break;
- case VIR_TYPED_PARAM_BOOLEAN:
- vshPrint (ctl, "%s %s %s\n", device,
- params[i].field, params[i].value.b ? _("yes") : _("no"));
- break;
- default:
- vshError(ctl, _("unimplemented block statistics parameter type"));
- }
+ if (strlen(params[i].field) == 0)
+ continue;
+ if (!(value = vshGetTypedParamValue(ctl, params+i)))
+ continue;
+
+ vshPrint(ctl, "%s %s %s\n", device, params[i].field, value);
+ VIR_FREE(value);
}
}
@@ -15185,6 +15242,85 @@ vshDomainStateReasonToString(int state, int reason)
return N_("unknown");
}
+static char *
+vshGetTypedParamValue(vshControl *ctl, virTypedParameterPtr item)
+{
+ int size = 0;
+ char *str = NULL;
+
+ if (!ctl || !item)
+ return NULL;
+
+ switch(item->type) {
+ case VIR_TYPED_PARAM_INT:
+ size = snprintf(NULL, 0, "%d", item->value.i);
+ str = vshMalloc(ctl, size+1);
+ snprintf(str, size+1, "%d", item->value.i);
+ return str;
+ break;
+
+ case VIR_TYPED_PARAM_UINT:
+ size = snprintf(NULL, 0, "%u", item->value.ui);
+ str = vshMalloc(ctl, size+1);
+ snprintf(str, size+1, "%u", item->value.ui);
+ return str;
+ break;
+
+ case VIR_TYPED_PARAM_LLONG:
+ size = snprintf(NULL, 0, "%lld", item->value.l);
+ str = vshMalloc(ctl, size+1);
+ snprintf(str, size+1, "%lld", item->value.l);
+ return str;
+ break;
+
+ case VIR_TYPED_PARAM_ULLONG:
+ size = snprintf(NULL, 0, "%llu", item->value.ul);
+ str = vshMalloc(ctl, size+1);
+ snprintf(str, size+1, "%llu", item->value.ul);
+ return str;
+ break;
+
+ case VIR_TYPED_PARAM_DOUBLE:
+ size = snprintf(NULL, 0, "%f", item->value.d);
+ str = vshMalloc(ctl, size+1);
+ snprintf(str, size+1, "%f", item->value.d);
+ return str;
+ break;
+
+ case VIR_TYPED_PARAM_BOOLEAN:
+ size = snprintf(NULL, 0, "%s", item->value.b ? _("yes") : _("no"));
+ str = vshMalloc(ctl, size+1);
+ snprintf(str, size+1, "%s", item->value.b ? _("yes") : _("no"));
+ return str;
+ break;
+
+ default:
+ vshError(ctl, _("unimplemented block statistics parameter type"));
+ }
+
+ return NULL;
+}
+
+static virTypedParameterPtr
+vshFindTypedParamByName(const char *name, virTypedParameterPtr list, int count)
+{
+ int i = count;
+ virTypedParameterPtr found = list;
+
+ if (!list || !name)
+ return NULL;
+
+ while (i-- > 0) {
+ if (STREQ(name, found->field))
+ return found;
+
+ found++; /* go to next struct in array */
+ }
+
+ /* not found */
+ return NULL;
+}
+
static const char *
vshDomainControlStateToString(int state)
{
diff --git a/tools/virsh.pod b/tools/virsh.pod
index e82567d..519e60b 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -501,13 +501,31 @@ be lost once the guest stops running, but the snapshot contents still
exist, and a new domain with the same name and UUID can restore the
snapshot metadata with B<snapshot-create>.
-=item B<domblkstat> I<domain> I<block-device>
+=item B<domblkstat> I<domain> I<block-device> [I<--human>]
Get device block stats for a running domain. A I<block-device> corresponds
to a unique target name (<target dev='name'/>) or source file (<source
file='name'/>) for one of the disk devices attached to I<domain> (see
also B<domblklist> for listing these names).
+Use I<--human> for a more human readable output.
+
+Availabilty of these fields depends on hypervisor. Unsupported fields are
+missing from the output. Other fields may appear if comunicating with a newer
+version of libvirtd.
+
+B<Explanation of fields> (fields appear in the folowing order):
+ rd_req - count of read operations
+ rd_bytes - count of read bytes
+ wr_req - count of write operations
+ wr_bytes - count of written bytes
+ errs - error count
+ flush_operations - count of flush operations
+ rd_total_times - total time read operations took (ns)
+ wr_total_times - total time write operations took (ns)
+ flush_total_times - total time flush operations took (ns)
+ <-- other fields provided by hypervisor -->
+
=item B<domifstat> I<domain> I<interface-device>
Get network interface stats for a running domain.
--
1.7.3.4
13 years, 2 months
[libvirt] lvm backed storage
by Serge Hallyn
Hi,
When lvm.conf has 'command_names = 1', then all results are prefixed with
the command name. This confuses libvirt which does not ignore those. I
thought fixing that would be a simple case of detecting those conditions
at virStorageBackendLogicalMakeVol() and friends, but I was wrong - those
functions are not getting called at all when command_names=1. I'll keep
nosing around, but it seemed prudent to ping the list and ask what you
think would be the cleanest way to handle this case?
thanks,
-serge
13 years, 2 months