
# HG changeset patch # User Dan Smith <danms@us.ibm.com> # Date 1213804832 25200 # Node ID 491abbe7867c50c66ce0cd3af41f169bf32dc8fb # Parent 74b34a49b99a5bef18be26c85e1f2c76c09822ca Add domain information store utilities This sets up a very simple XML file in /etc/libvirt/cim that can store some key=value attributes for a domain. The included test is a very simple example and exercise of the code, and should probably be improved a bit before moving on. Signed-off-by: Dan Smith <danms@us.ibm.com> diff -r 74b34a49b99a -r 491abbe7867c libxkutil/Makefile.am --- a/libxkutil/Makefile.am Mon Jun 16 13:22:22 2008 -0700 +++ b/libxkutil/Makefile.am Wed Jun 18 09:00:32 2008 -0700 @@ -4,14 +4,14 @@ CFLAGS += $(CFLAGS_STRICT) -noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h +noinst_HEADERS = cs_util.h misc_util.h device_parsing.h xmlgen.h infostore.h lib_LTLIBRARIES = libxkutil.la AM_LDFLAGS = -lvirt -luuid libxkutil_la_SOURCES = cs_util_instance.c misc_util.c device_parsing.c \ - xmlgen.c + xmlgen.c infostore.c noinst_PROGRAMS = xml_parse_test diff -r 74b34a49b99a -r 491abbe7867c libxkutil/infostore.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxkutil/infostore.c Wed Jun 18 09:00:32 2008 -0700 @@ -0,0 +1,372 @@ +/* + * Copyright IBM Corp. 2008 + * + * Authors: + * Dan Smith <danms@us.ibm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <inttypes.h> +#include <sys/file.h> + +#include <libvirt/libvirt.h> +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/xmlsave.h> +#include <libxml/tree.h> + +#include <libcmpiutil/libcmpiutil.h> +#include <config.h> + +#include "infostore.h" + +struct infostore_ctx { + xmlDocPtr doc; + xmlNodePtr root; + xmlXPathContextPtr xpathctx; + int fd; +}; + +static void infostore_cleanup_ctx(struct infostore_ctx *ctx) +{ + xmlXPathFreeContext(ctx->xpathctx); + xmlFreeDoc(ctx->doc); + close(ctx->fd); + + free(ctx); +} + +static char *_make_filename(const char *type, const char *name) +{ + int ret; + char *path; + + ret = asprintf(&path, "%s/%s_%s", + INFO_STORE, + type, + name); + if (ret == -1) { + CU_DEBUG("Failed to asprintf() path to info store"); + path = NULL; + } + + return path; +} + +static char *make_filename(virDomainPtr dom) +{ + virConnectPtr conn; + char *path = NULL; + + conn = virDomainGetConnect(dom); + if (conn == NULL) { + CU_DEBUG("Domain has no libvirt connection"); + goto out; + } + + path = _make_filename(virConnectGetType(conn), + virDomainGetName(dom)); + + CU_DEBUG("Path is %s", path); + + out: + return path; +} + +static xmlDocPtr parse_xml(int fd) +{ + xmlParserCtxtPtr ctx = NULL; + xmlDocPtr doc = NULL; + + ctx = xmlNewParserCtxt(); + if (ctx == NULL) + goto err; + + doc = xmlCtxtReadFd(ctx, + fd, + "foo", + NULL, + XML_PARSE_NOWARNING | XML_PARSE_NONET); + if (doc == NULL) + goto err; + + return doc; + err: + xmlFreeDoc(doc); + xmlFreeParserCtxt(ctx); + + return NULL; +} + +static xmlDocPtr new_xml(void) +{ + xmlDocPtr doc = NULL; + xmlNodePtr root = NULL; + + doc = xmlNewDoc(BAD_CAST "1.0"); + if (doc == NULL) { + CU_DEBUG("Failed to create new XML document"); + goto err; + } + + root = xmlNewNode(NULL, BAD_CAST "dominfo"); + if (root == NULL) { + CU_DEBUG("Failed top create new root node"); + goto err; + } + + xmlDocSetRootElement(doc, root); + + return doc; + err: + xmlFreeDoc(doc); + + return NULL; +} + +static bool save_xml(struct infostore_ctx *ctx) +{ + xmlSaveCtxtPtr save = NULL; + long size = 0; + + lseek(ctx->fd, 0, SEEK_SET); + + save = xmlSaveToFd(ctx->fd, NULL, 0); + if (save == NULL) { + CU_DEBUG("Failed to allocate save context"); + goto out; + } + + size = xmlSaveDoc(save, ctx->doc); + + xmlSaveClose(save); + + out: + return size >= 0; +} + +struct infostore_ctx *infostore_open(virDomainPtr dom) +{ + struct infostore_ctx *isc; + struct stat s; + char *filename = NULL; + + isc = calloc(1, sizeof(*isc)); + if (isc == NULL) { + CU_DEBUG("Unable to allocate domain_details struct"); + return NULL; + } + + filename = make_filename(dom); + if (filename == NULL) + goto err; + + isc->fd = open(filename, O_RDWR|O_CREAT, 0600); + if (isc->fd < 0) { + CU_DEBUG("Unable to open `%s': %m", filename); + goto err; + } + + if (flock(isc->fd, LOCK_EX) != 0) { + CU_DEBUG("Failed to lock infostore"); + goto err; + } + + fstat(isc->fd, &s); + if (s.st_size == 0) + isc->doc = new_xml(); + else + isc->doc = parse_xml(isc->fd); + + if (isc->doc == NULL) { + CU_DEBUG("Failed to parse XML"); + goto err; + } + + isc->root = xmlDocGetRootElement(isc->doc); + if (isc->root == NULL) { + CU_DEBUG("Failed to parse XML"); + goto err; + } + + if (!xmlStrEqual(isc->root->name, BAD_CAST "dominfo")) { + CU_DEBUG("XML does not start with <dominfo>"); + goto err; + } + + isc->xpathctx = xmlXPathNewContext(isc->doc); + if (isc->xpathctx == NULL) { + CU_DEBUG("Failed to allocate XPath context"); + goto err; + } + + free(filename); + + return isc; + + err: + infostore_cleanup_ctx(isc); + free(filename); + + return NULL; +} + +void infostore_close(struct infostore_ctx *ctx) +{ + if (ctx == NULL) + return; + + save_xml(ctx); + infostore_cleanup_ctx(ctx); +} + +void infostore_delete(const char *type, const char *name) +{ + char *path = NULL; + + path = _make_filename(type, name); + if (path == NULL) + return; + + unlink(path); + + free(path); +} + +static xmlXPathObjectPtr xpath_query(struct infostore_ctx *ctx, const char *key) +{ + char *path = NULL; + xmlXPathObjectPtr result = NULL; + + if (asprintf(&path, "/dominfo/%s[1]", key) == -1) { + CU_DEBUG("Failed to alloc path string"); + goto out; + } + + result = xmlXPathEval(BAD_CAST path, ctx->xpathctx); + if ((result->type != XPATH_NODESET) || + (xmlXPathNodeSetGetLength(result->nodesetval) < 1)) { + xmlXPathFreeObject(result); + result = NULL; + } + out: + free(path); + + return result; +} + +static char *xpath_query_string(struct infostore_ctx *ctx, const char *key) +{ + xmlXPathObjectPtr result; + char *val = NULL; + + result = xpath_query(ctx, key); + if (result != NULL) + val = (char *)xmlXPathCastToString(result); + + xmlXPathFreeObject(result); + + return val; +} + +static bool xpath_set_string(struct infostore_ctx *ctx, + const char *key, + const char *val) +{ + xmlXPathObjectPtr result = NULL; + xmlNodePtr node = NULL; + + result = xpath_query(ctx, key); + if (result == NULL) { + CU_DEBUG("Creating new node %s=%s", key, val); + node = xmlNewDocNode(ctx->doc, NULL, BAD_CAST key, NULL); + xmlAddChild(ctx->root, node); + } else { + node = result->nodesetval->nodeTab[0]; + } + + if (node == NULL) { + CU_DEBUG("Failed to update node for `%s'", key); + goto out; + } + + xmlNodeSetContent(node, BAD_CAST val); + out: + xmlXPathFreeObject(result); + + return node != NULL; +} + +uint64_t infostore_get_u64(struct infostore_ctx *ctx, const char *key) +{ + char *sval = NULL; + uint64_t val = 0; + + sval = xpath_query_string(ctx, key); + if (sval == NULL) + goto out; + + if (sscanf((const char *)sval, "%" SCNu64, &val) != 1) { + CU_DEBUG("Failed to parse u64 for %s (%s)", key, sval); + goto out; + } + out: + free(sval); + + return val; +} + +bool infostore_set_u64(struct infostore_ctx *ctx, const char *key, uint64_t val) +{ + char *sval = NULL; + + if (asprintf(&sval, "%" PRIu64, val) == -1) { + CU_DEBUG("Failed to format u64 string"); + sval = NULL; + goto out; + } + + xpath_set_string(ctx, key, sval); + out: + free(sval); + + return false; +} + +char *infostore_get_str(struct infostore_ctx *ctx, const char *key) +{ + return xpath_query_string(ctx, key); +} + +bool infostore_set_str(struct infostore_ctx *ctx, + const char *key, const char * val) +{ + return xpath_set_string(ctx, key, val); +} + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ diff -r 74b34a49b99a -r 491abbe7867c libxkutil/infostore.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxkutil/infostore.h Wed Jun 18 09:00:32 2008 -0700 @@ -0,0 +1,54 @@ +/* + * Copyright IBM Corp. 2008 + * + * Authors: + * Dan Smith <danms@us.ibm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __INFOSTORE_H +#define __INFOSTORE_H + +#include <stdint.h> +#include <stdbool.h> +#include <libvirt/libvirt.h> + +struct infostore_ctx; + +struct infostore_ctx *infostore_open(virDomainPtr dom); +void infostore_close(struct infostore_ctx *ctx); +void infostore_delete(const char *type, const char *name); + +uint64_t infostore_get_u64(struct infostore_ctx *ctx, const char *key); +bool infostore_set_u64(struct infostore_ctx *ctx, + const char *key, uint64_t val); + +char *infostore_get_str(struct infostore_ctx *ctx, const char *key); +bool infostore_set_str(struct infostore_ctx *ctx, + const char *key, const char * val); + + +#endif + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ diff -r 74b34a49b99a -r 491abbe7867c libxkutil/tests/Makefile.am --- a/libxkutil/tests/Makefile.am Mon Jun 16 13:22:22 2008 -0700 +++ b/libxkutil/tests/Makefile.am Wed Jun 18 09:00:32 2008 -0700 @@ -1,10 +1,10 @@ # Copyright IBM Corp. 2007 -TESTS = xml_tag.test xml_devices.test xmlgen.test xml_dominfo.test +TESTS = xml_tag.test xml_devices.test xmlgen.test xml_dominfo.test infostore.test CFLAGS += -g %.test: %.c - $(CC) -o $@ $^ $(CFLAGS) -lvirt `xml2-config --libs` + $(CC) -o $@ $^ $(CFLAGS) -lvirt `xml2-config --libs` -L../.libs -lxkutil clean-local: rm -f *.test diff -r 74b34a49b99a -r 491abbe7867c libxkutil/tests/infostore.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libxkutil/tests/infostore.c Wed Jun 18 09:00:32 2008 -0700 @@ -0,0 +1,80 @@ +/* + * Copyright IBM Corp. 2008 + * + * Authors: + * Dan Smith <danms@us.ibm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <inttypes.h> + +#include <libvirt/libvirt.h> + +#include "../infostore.h" + +int main(int argc, char **argv) +{ + struct infostore_ctx *ctx = NULL; + virConnectPtr conn = NULL; + virDomainPtr dom = NULL; + + if (argc != 2) { + printf("Usage: %s <domain>\n", argv[0]); + return 1; + } + + conn = virConnectOpen(NULL); + if (conn == NULL) { + printf("Unable to open connection\n"); + goto out; + } + + dom = virDomainLookupByName(conn, argv[1]); + if (dom == NULL) { + printf("Unable to lookup domain `%s'\n", argv[1]); + goto out; + } + + ctx = infostore_open(dom); + if (ctx == NULL) { + printf("Unable to open infostore for `%s'\n", argv[1]); + goto out; + } + + printf("Foo: %" PRIu64 "\n", infostore_get_u64(ctx, "foo")); + + infostore_set_u64(ctx, "foo", 321); + infostore_set_u64(ctx, "bar", 987); + printf("Should be (null): %s\n", infostore_get_str(ctx, "baz")); + + out: + infostore_close(ctx); + virDomainFree(dom); + virConnectClose(conn); + + return 0; +} + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */