From 16ff741ff017456806183da4d03555d0172bef63 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Tue, 13 Dec 2005 16:22:05 +0000 Subject: [PATCH] * include/libvir.h src/Makefile.am src/internal.h src/libvir.c src/libvir_sym.version src/virsh.c src/xml.c: started working on the XML dump, added a dumpxml virsh version and a bit of infrastructure code. Found a way to detect dead ID from xenstore data. Daniel --- ChangeLog | 8 ++ include/libvir.h | 2 + src/Makefile.am | 3 +- src/internal.h | 50 ++++++++++++ src/libvir.c | 47 +++-------- src/libvir_sym.version | 1 + src/virsh.c | 51 ++++++++++++ src/xml.c | 173 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 297 insertions(+), 38 deletions(-) create mode 100644 src/xml.c diff --git a/ChangeLog b/ChangeLog index 14f2f11042..c7b6a3ad77 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Tue Dec 13 17:20:11 CET 2005 Daniel Veillard + + * include/libvir.h src/Makefile.am src/internal.h src/libvir.c + src/libvir_sym.version src/virsh.c src/xml.c: started working on + the XML dump, added a dumpxml virsh version and a bit of + infrastructure code. Found a way to detect dead ID from xenstore + data. + Mon Dec 12 14:21:18 CET 2005 Daniel Veillard * src/libvir.c src/xen_internal.c src/xen_internal.h: completing the diff --git a/include/libvir.h b/include/libvir.h index c47720acdf..c8bbe5df56 100644 --- a/include/libvir.h +++ b/include/libvir.h @@ -174,6 +174,8 @@ int virDomainResume (virDomainPtr domain); */ int virDomainGetInfo (virDomainPtr domain, virDomainInfoPtr info); +char * virDomainGetXMLDesc (virDomainPtr domain, + int flags); /* * Dynamic control of domains diff --git a/src/Makefile.am b/src/Makefile.am index 62e723fc47..5abb20f9d3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,7 +14,8 @@ libvir_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libvir_sym.version \ libvir_la_SOURCES = \ libvir.c internal.h \ hash.c hash.h \ - xen_internal.c xen_internal.h + xen_internal.c xen_internal.h \ + xml.c noinst_PROGRAMS=virsh diff --git a/src/internal.h b/src/internal.h index 4591e8b5de..af3963805c 100644 --- a/src/internal.h +++ b/src/internal.h @@ -5,6 +5,9 @@ #ifndef __VIR_INTERNAL_H__ #define __VIR_INTERNAL_H__ +#include "hash.h" +#include "libvir.h" + #ifdef __cplusplus extern "C" { #endif @@ -34,6 +37,53 @@ extern "C" { fprintf(stderr, "Unimplemented block at %s:%d\n", \ __FILE__, __LINE__); +/** + * VIR_CONNECT_MAGIC: + * + * magic value used to protect the API when pointers to connection structures + * are passed down by the uers. + */ +#define VIR_CONNECT_MAGIC 0x4F23DEAD + +/** + * VIR_DOMAIN_MAGIC: + * + * magic value used to protect the API when pointers to domain structures + * are passed down by the uers. + */ +#define VIR_DOMAIN_MAGIC 0xDEAD4321 + +/* + * Flags for Xen connections + */ +#define VIR_CONNECT_RO 1 + +/** + * _virConnect: + * + * Internal structure associated to a connection + */ +struct _virConnect { + unsigned int magic; /* specific value to check */ + int handle; /* internal handle used for hypercall */ + struct xs_handle *xshandle; /* handle to talk to the xenstore */ + virHashTablePtr domains; /* hash table for known domains */ + int flags; /* a set of connection flags */ +}; + +/** + * _virDomain: + * + * Internal structure associated to a domain + */ +struct _virDomain { + unsigned int magic; /* specific value to check */ + virConnectPtr conn; /* pointer back to the connection */ + char *name; /* the domain external name */ + char *path; /* the domain internal path */ + int handle; /* internal handle for the dmonain ID */ +}; + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/libvir.c b/src/libvir.c index 4a8c97bdad..07ad35495e 100644 --- a/src/libvir.c +++ b/src/libvir.c @@ -28,41 +28,6 @@ * - memory wrappers for malloc/free ? */ -#define VIR_CONNECT_MAGIC 0x4F23DEAD - -/* - * Flags for Xen connections - */ -#define VIR_CONNECT_RO 1 - -/** - * _virConnect: - * - * Internal structure associated to a connection - */ -struct _virConnect { - unsigned int magic; /* specific value to check */ - int handle; /* internal handle used for hypercall */ - struct xs_handle *xshandle; /* handle to talk to the xenstore */ - virHashTablePtr domains; /* hash table for known domains */ - int flags; /* a set of connection flags */ -}; - -#define VIR_DOMAIN_MAGIC 0xDEAD4321 - -/** - * _virDomain: - * - * Internal structure associated to a domain - */ -struct _virDomain { - unsigned int magic; /* specific value to check */ - virConnectPtr conn; /* pointer back to the connection */ - char *name; /* the domain external name */ - char *path; /* the domain internal path */ - int handle; /* internal handle for the dmonain ID */ -}; - /** * virGetVersion: * @libVer: return value for the library version (OUT) @@ -396,6 +361,8 @@ virConnectNumOfDomains(virConnectPtr conn) { * @flags: an optional set of virDomainFlags * * Launch a new Linux guest domain + * Not implemented yet. Very likely to be modified in order to express + * hardware informations in a convenient way. * * Returns a new domain object or NULL in case of failure */ @@ -531,6 +498,11 @@ virDomainLookupByID(virConnectPtr conn, int id) { ret->handle = id; ret->path = path; ret->name = virDomainDoStoreQuery(ret, "name"); + if (ret->name == NULL) { + free(path); + free(ret); + return(NULL); + } return(ret); } @@ -540,7 +512,7 @@ virDomainLookupByID(virConnectPtr conn, int id) { * @conn: pointer to the hypervisor connection * @name: name for the domain * - * Try to lookup a domain on the given hypervisor + * Try to lookup a domain on the given hypervisor based on its name. * * Returns a new domain object or NULL in case of failure */ @@ -807,7 +779,7 @@ virDomainSetMaxMemory(virDomainPtr domain, unsigned long memory) { /** * virDomainGetInfo: - * @domain: a domain object or NULL + * @domain: a domain object * @info: pointer to a virDomainInfo structure allocated by the user * * Extract information about a domain. Note that if the connection @@ -904,3 +876,4 @@ virDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) { } return(0); } + diff --git a/src/libvir_sym.version b/src/libvir_sym.version index ead0d41ec3..e62bdee777 100644 --- a/src/libvir_sym.version +++ b/src/libvir_sym.version @@ -19,6 +19,7 @@ virDomainResume; virDomainSetMaxMemory; virDomainSuspend; + virDomainGetXMLDesc; virGetVersion; local: *; }; diff --git a/src/virsh.c b/src/virsh.c index 41f6b9338c..6ae8eafc88 100644 --- a/src/virsh.c +++ b/src/virsh.c @@ -578,6 +578,56 @@ cmdDinfo(vshControl *ctl, vshCmd *cmd) { return ret; } +/* + * "dumpxml" command + */ +static vshCmdInfo info_dumpxml[] = { + { "syntax", "dumpxml [--id | --name ]" }, + { "help", "domain information in XML" }, + { "desc", "Ouput the domain informations as an XML dump to stdout" }, + { NULL, NULL } +}; + +static vshCmdOptDef opts_dumpxml[] = { + { "name", VSH_OT_STRING, 0, "domain name" }, + { "id", VSH_OT_INT, 0, "domain id" }, + { NULL, 0, 0, NULL } +}; + +static int +cmdDumpXML(vshControl *ctl, vshCmd *cmd) { + virDomainPtr dom; + int found, ret = TRUE; + char *name = vshCommandOptString(cmd, "name", NULL); + int id = vshCommandOptInt(cmd, "id", &found); + char *dump; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (found) { + if (!(dom = virDomainLookupByID(ctl->conn, id))) + vshError(ctl, FALSE, "failed to get domain '%d'", id); + } else { + if (!(dom = virDomainLookupByName(ctl->conn, name))) + vshError(ctl, FALSE, "failed to get domain '%s'", name); + } + + if (!dom) + return FALSE; + + dump = virDomainGetXMLDesc(dom, 0); + if (dump != NULL) { + printf("%s", dump); + free(dump); + } else { + ret = FALSE; + } + + virDomainFree(dom); + return ret; +} + /* * "nameof" command */ @@ -750,6 +800,7 @@ cmdQuit(vshControl *ctl, vshCmd *cmd ATTRIBUTE_UNUSED) { static vshCmdDef commands[] = { { "connect", cmdConnect, opts_connect, info_connect }, { "dinfo", cmdDinfo, opts_dinfo, info_dinfo }, + { "dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml }, { "dstate", cmdDstate, opts_dstate, info_dstate }, { "suspend", cmdSuspend, opts_suspend, info_suspend }, { "resume", cmdResume, opts_resume, info_resume }, diff --git a/src/xml.c b/src/xml.c new file mode 100644 index 0000000000..9887da83e1 --- /dev/null +++ b/src/xml.c @@ -0,0 +1,173 @@ +/* + * xml.c: XML based interfaces for the libvir library + * + * Copyright (C) 2005 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Daniel Veillard + */ + +#include "libvir.h" + +#include +#include +#include +#include +#include +#include "internal.h" +#include "hash.h" + +/** + * virBuffer: + * + * A buffer structure. + */ +typedef struct _virBuffer virBuffer; +typedef virBuffer *virBufferPtr; +struct _virBuffer { + char *content; /* The buffer content UTF8 */ + unsigned int use; /* The buffer size used */ + unsigned int size; /* The buffer size */ +}; + +/** + * virBufferGrow: + * @buf: the buffer + * @len: the minimum free size to allocate + * + * Grow the available space of an XML buffer. + * + * Returns the new available space or -1 in case of error + */ +static int +virBufferGrow(virBufferPtr buf, unsigned int len) { + int size; + char *newbuf; + + if (buf == NULL) return(-1); + if (len + buf->use < buf->size) return(0); + + size = buf->use + len + 1000; + + newbuf = (char *) realloc(buf->content, size); + if (newbuf == NULL) { + return(-1); + } + buf->content = newbuf; + buf->size = size; + return(buf->size - buf->use); +} + +/** + * virBufferAdd: + * @buf: the buffer to dump + * @str: the string + * @len: the number of bytes to add + * + * Add a string range to an XML buffer. if len == -1, the length of + * str is recomputed to the full string. + * + * Returns 0 successful, -1 in case of internal or API error. + */ +static int +virBufferAdd(virBufferPtr buf, const char *str, int len) { + unsigned int needSize; + + if ((str == NULL) || (buf == NULL)) { + return -1; + } + if (len == 0) return 0; + + if (len < 0) + len = strlen(str); + + needSize = buf->use + len + 2; + if (needSize > buf->size){ + if (!virBufferGrow(buf, needSize)){ + return(-1); + } + } + + memmove(&buf->content[buf->use], str, len); + buf->use += len; + buf->content[buf->use] = 0; + return(0); +} + +/** + * virBufferVSprintf: + * @buf: the buffer to dump + * @format: the format + * @argptr: the variable list of arguments + * + * Do a formatted print to an XML buffer. + * + * Returns 0 successful, -1 in case of internal or API error. + */ +static int +virBufferVSprintf(virBufferPtr buf, const char *format, ...) { + int size, count; + va_list locarg, argptr; + + if ((format == NULL) || (buf == NULL)) { + return(-1); + } + size = buf->size - buf->use - 1; + va_start(argptr, format); + va_copy(locarg, argptr); + while (((count = vsnprintf(&buf->content[buf->use], size, format, + locarg)) < 0) || (count >= size - 1)) { + buf->content[buf->use] = 0; + va_end(locarg); + if (virBufferGrow(buf, 1000) < 0) { + return(-1); + } + size = buf->size - buf->use - 1; + va_copy(locarg, argptr); + } + va_end(locarg); + buf->use += count; + buf->content[buf->use] = 0; + return(0); +} + +/** + * virDomainGetXMLDesc: + * @domain: a domain object + * @flags: and OR'ed set of extraction flags, not used yet + * + * Provide an XML description of the domain. NOTE: this API is subject + * to changes. + * + * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error. + * the caller must free() the returned value. + */ +char * +virDomainGetXMLDesc(virDomainPtr domain, int flags) { + char *ret = NULL; + virBuffer buf; + virDomainInfo info; + + if ((domain == NULL) || (domain->magic != VIR_DOMAIN_MAGIC) || + (flags != 0)) + return(NULL); + + if (virDomainGetInfo(domain, &info) < 0) + return(NULL); + + ret = malloc(1000); + if (ret == NULL) + return(NULL); + buf.content = ret; + buf.size = 1000; + buf.use = 0; + + virBufferVSprintf(&buf, "\n", + virDomainGetID(domain)); + virBufferVSprintf(&buf, " %s\n", virDomainGetName(domain)); + virBufferAdd(&buf, "\n", 10); + + buf.content[buf.use] = 0; + return(ret); +}