# HG changeset patch
# User Dan Smith <danms(a)us.ibm.com>
# Date 1214248231 25200
# Node ID cee13699488177020c8050cd9e4311d74d394b2c
# Parent 3f95e5cf96d586b7315516421e7eac66ed0fef86
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.
Changes:
- Fix inconsistent false return
- Fix missing free of XML parsing context
Signed-off-by: Dan Smith <danms(a)us.ibm.com>
diff -r 3f95e5cf96d5 -r cee136994881 libxkutil/Makefile.am
--- a/libxkutil/Makefile.am Mon Jun 23 12:10:07 2008 -0700
+++ b/libxkutil/Makefile.am Mon Jun 23 12:10:31 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 3f95e5cf96d5 -r cee136994881 libxkutil/infostore.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libxkutil/infostore.c Mon Jun 23 12:10:31 2008 -0700
@@ -0,0 +1,374 @@
+/*
+ * Copyright IBM Corp. 2008
+ *
+ * Authors:
+ * Dan Smith <danms(a)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;
+
+ xmlFreeParserCtxt(ctx);
+
+ 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 3f95e5cf96d5 -r cee136994881 libxkutil/infostore.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libxkutil/infostore.h Mon Jun 23 12:10:31 2008 -0700
@@ -0,0 +1,54 @@
+/*
+ * Copyright IBM Corp. 2008
+ *
+ * Authors:
+ * Dan Smith <danms(a)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 3f95e5cf96d5 -r cee136994881 libxkutil/tests/Makefile.am
--- a/libxkutil/tests/Makefile.am Mon Jun 23 12:10:07 2008 -0700
+++ b/libxkutil/tests/Makefile.am Mon Jun 23 12:10:31 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 3f95e5cf96d5 -r cee136994881 libxkutil/tests/infostore.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libxkutil/tests/infostore.c Mon Jun 23 12:10:31 2008 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright IBM Corp. 2008
+ *
+ * Authors:
+ * Dan Smith <danms(a)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:
+ */