[Libvirt-cim] [PATCH 2 of 6] Add domain information store utilities

Dan Smith danms at us.ibm.com
Mon Jun 23 19:10:51 UTC 2008


# HG changeset patch
# User Dan Smith <danms at 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 at 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 at 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 at 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 at 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:
+ */




More information about the Libvirt-cim mailing list