fish: Use core add-domain API to implement '-d' option.
authorRichard Jones <rjones@redhat.com>
Tue, 9 Nov 2010 18:56:00 +0000 (18:56 +0000)
committerRichard W.M. Jones <rjones@redhat.com>
Thu, 11 Nov 2010 11:24:13 +0000 (11:24 +0000)
This also makes libxml2 and libvirt into optional dependencies.
If they are missing then the core API will print an error, as
will the '-d' option to guestfish.

README
configure.ac
fish/Makefile.am
fish/virt.c
fuse/Makefile.am
regressions/test-guestfish-d.sh

diff --git a/README b/README
index 8b88b98..65e22cb 100644 (file)
--- a/README
+++ b/README
@@ -51,9 +51,9 @@ Requirements
 
 - libmagic (the library that corresponds to the 'file' command) (optional)
 
-- libvirt
+- libvirt (optional)
 
-- libxml2
+- libxml2 (optional)
 
 - Augeas (http://augeas.net/) (optional)
 
index e7761c9..67b1309 100644 (file)
@@ -445,11 +445,6 @@ AC_CHECK_LIB([magic],[magic_file],
         ],
         [AC_MSG_WARN([libmagic not found, some core features will be disabled])])
 
-dnl libvirt (required)
-PKG_CHECK_MODULES([LIBVIRT], [libvirt])
-AC_SUBST([LIBVIRT_CFLAGS])
-AC_SUBST([LIBVIRT_LIBS])
-
 dnl Check for PCRE (highly recommended)
 PKG_CHECK_MODULES([PCRE], [libpcre],
         [AC_SUBST([PCRE_CFLAGS])
@@ -458,11 +453,21 @@ PKG_CHECK_MODULES([PCRE], [libpcre],
         ],
         [AC_MSG_WARN([PCRE not found, some core features will be disabled])])
 
-dnl libxml2 (required)
-PKG_CHECK_MODULES([LIBXML2], [libxml-2.0])
-AC_SUBST([LIBXML2_CFLAGS])
-AC_SUBST([LIBXML2_LIBS])
+dnl libvirt (highly recommended)
+PKG_CHECK_MODULES([LIBVIRT], [libvirt],
+        [AC_SUBST([LIBVIRT_CFLAGS])
+         AC_SUBST([LIBVIRT_LIBS])
+         AC_DEFINE([HAVE_LIBVIRT],[1],[libvirt found at compile time.])
+        ],
+        [AC_MSG_WARN([libvirt not found, some core features will be disabled])])
 
+dnl libxml2 (highly recommended)
+PKG_CHECK_MODULES([LIBXML2], [libxml-2.0],
+        [AC_SUBST([LIBXML2_CFLAGS])
+         AC_SUBST([LIBXML2_LIBS])
+         AC_DEFINE([HAVE_LIBXML2],[1],[libxml2 found at compile time.])
+        ],
+        [AC_MSG_WARN([libxml2 not found, some core features will be disabled])])
 
 dnl hivex library (highly recommended)
 dnl This used to be a part of libguestfs, but was spun off into its
index dadda91..6debdce 100644 (file)
@@ -103,11 +103,9 @@ guestfish_CFLAGS = \
        -DGUESTFS_DEFAULT_PATH='"$(libdir)/guestfs"' \
        -DLOCALEBASEDIR=\""$(datadir)/locale"\" \
        -I$(srcdir)/../gnulib/lib -I../gnulib/lib \
-       $(LIBVIRT_CFLAGS) $(LIBXML2_CFLAGS) \
        $(WARN_CFLAGS) $(WERROR_CFLAGS)
 
 guestfish_LDADD = \
-       $(LIBVIRT_LIBS) $(LIBXML2_LIBS) \
        $(top_builddir)/src/libguestfs.la $(LIBREADLINE) -lm
 
 # Make guestfish use the convenience libraries.
index 728f9c2..13a6d12 100644 (file)
 #include <string.h>
 #include <assert.h>
 
-#include <libvirt/libvirt.h>
-#include <libvirt/virterror.h>
-
-#include <libxml/xpath.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-
 #include "guestfs.h"
 
 #include "options.h"
 
 /* Implements the guts of the '-d' option.
- *
- * Note that we have to observe the '--ro' flag in two respects: by
- * adding the drives read-only if the flag is set, and by restricting
- * guests to shut down ones unless '--ro' is set.
- *
  * Returns the number of drives added (> 0), or -1 for failure.
  */
 int
 add_libvirt_drives (const char *guest)
 {
-  static int initialized = 0;
-  if (!initialized) {
-    initialized = 1;
-
-    if (virInitialize () == -1)
-      return -1;
-
-    xmlInitParser ();
-    LIBXML_TEST_VERSION;
-  }
-
-  int r = -1, nr_added = 0, i;
-  virErrorPtr err;
-  virConnectPtr conn = NULL;
-  virDomainPtr dom = NULL;
-  xmlDocPtr doc = NULL;
-  xmlXPathContextPtr xpathCtx = NULL;
-  xmlXPathObjectPtr xpathObj = NULL;
-  char *xml = NULL;
-
-  /* Connect to libvirt, find the domain. */
-  conn = virConnectOpenReadOnly (libvirt_uri);
-  if (!conn) {
-    err = virGetLastError ();
-    fprintf (stderr, _("%s: could not connect to libvirt (code %d, domain %d): %s\n"),
-             program_name, err->code, err->domain, err->message);
-    goto cleanup;
-  }
-
-  dom = virDomainLookupByName (conn, guest);
-  if (!dom) {
-    err = virConnGetLastError (conn);
-    fprintf (stderr, _("%s: no libvirt domain called '%s': %s\n"),
-             program_name, guest, err->message);
-    goto cleanup;
-  }
-  if (!read_only) {
-    virDomainInfo info;
-    if (virDomainGetInfo (dom, &info) == -1) {
-      err = virConnGetLastError (conn);
-      fprintf (stderr, _("%s: error getting domain info about '%s': %s\n"),
-               program_name, guest, err->message);
-      goto cleanup;
-    }
-    if (info.state != VIR_DOMAIN_SHUTOFF) {
-      fprintf (stderr, _("%s: error: '%s' is a live virtual machine.\nYou must use '--ro' because write access to a running virtual machine can\ncause disk corruption.\n"),
-               program_name, guest);
-      goto cleanup;
-    }
-  }
-
-  /* Domain XML. */
-  xml = virDomainGetXMLDesc (dom, 0);
-
-  if (!xml) {
-    err = virConnGetLastError (conn);
-    fprintf (stderr, _("%s: error reading libvirt XML information about '%s': %s\n"),
-             program_name, guest, err->message);
-    goto cleanup;
-  }
-
-  /* Now the horrible task of parsing out the fields we need from the XML.
-   * http://www.xmlsoft.org/examples/xpath1.c
-   */
-  doc = xmlParseMemory (xml, strlen (xml));
-  if (doc == NULL) {
-    fprintf (stderr, _("%s: unable to parse XML information returned by libvirt\n"),
-             program_name);
-    goto cleanup;
-  }
+  struct guestfs_add_domain_argv optargs = { .bitmask = 0 };
 
-  xpathCtx = xmlXPathNewContext (doc);
-  if (xpathCtx == NULL) {
-    fprintf (stderr, _("%s: unable to create new XPath context\n"),
-             program_name);
-    goto cleanup;
+  if (libvirt_uri) {
+    optargs.bitmask |= GUESTFS_ADD_DOMAIN_LIBVIRTURI_BITMASK;
+    optargs.libvirturi = libvirt_uri;
   }
-
-  /* This gives us a set of all the <disk> nodes. */
-  xpathObj = xmlXPathEvalExpression (BAD_CAST "//devices/disk", xpathCtx);
-  if (xpathObj == NULL) {
-    fprintf (stderr, _("%s: unable to evaluate XPath expression\n"),
-             program_name);
-    goto cleanup;
+  if (read_only) {
+    optargs.bitmask |= GUESTFS_ADD_DOMAIN_READONLY_BITMASK;
+    optargs.readonly = 1;
   }
 
-  xmlNodeSetPtr nodes = xpathObj->nodesetval;
-  for (i = 0; i < nodes->nodeNr; ++i) {
-    xmlXPathObjectPtr xpfilename;
-    xmlXPathObjectPtr xpformat;
-
-    /* Change the context to the current <disk> node.
-     * DV advises to reset this before each search since older versions of
-     * libxml2 might overwrite it.
-     */
-    xpathCtx->node = nodes->nodeTab[i];
-
-    /* Filename can be in <source dev=..> or <source file=..> attribute. */
-    xpfilename = xmlXPathEvalExpression (BAD_CAST "./source/@dev", xpathCtx);
-    if (xpfilename == NULL ||
-        xpfilename->nodesetval == NULL ||
-        xpfilename->nodesetval->nodeNr == 0) {
-      xmlXPathFreeObject (xpfilename);
-      xpathCtx->node = nodes->nodeTab[i];
-      xpfilename = xmlXPathEvalExpression (BAD_CAST "./source/@file", xpathCtx);
-      if (xpfilename == NULL ||
-          xpfilename->nodesetval == NULL ||
-          xpfilename->nodesetval->nodeNr == 0) {
-        xmlXPathFreeObject (xpfilename);
-        continue;               /* disk filename not found, skip this */
-      }
-    }
-
-    assert (xpfilename->nodesetval->nodeTab[0]);
-    assert (xpfilename->nodesetval->nodeTab[0]->type == XML_ATTRIBUTE_NODE);
-    xmlAttrPtr attr = (xmlAttrPtr) xpfilename->nodesetval->nodeTab[0];
-    char *filename = (char *) xmlNodeListGetString (doc, attr->children, 1);
-
-    /* Get the disk format (may not be set). */
-    xpathCtx->node = nodes->nodeTab[i];
-    xpformat = xmlXPathEvalExpression (BAD_CAST "./driver/@type", xpathCtx);
-    char *format = NULL;
-    if (xpformat != NULL &&
-        xpformat->nodesetval &&
-        xpformat->nodesetval->nodeNr > 0) {
-      assert (xpformat->nodesetval->nodeTab[0]);
-      assert (xpformat->nodesetval->nodeTab[0]->type == XML_ATTRIBUTE_NODE);
-      attr = (xmlAttrPtr) xpformat->nodesetval->nodeTab[0];
-      format = (char *) xmlNodeListGetString (doc, attr->children, 1);
-    }
-
-    /* Add the disk, with optional format. */
-    struct guestfs_add_drive_opts_argv optargs = { .bitmask = 0 };
-    if (read_only) {
-      optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_READONLY_BITMASK;
-      optargs.readonly = read_only;
-    }
-    if (format) {
-      optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
-      optargs.format = format;
-    }
-
-    int t = guestfs_add_drive_opts_argv (g, filename, &optargs);
-
-    xmlFree (filename);
-    xmlFree (format);
-    xmlXPathFreeObject (xpfilename);
-    xmlXPathFreeObject (xpformat);
-
-    if (t == -1)
-      goto cleanup;
-
-    nr_added++;
-  }
-
-  if (nr_added == 0) {
-    fprintf (stderr, _("%s: libvirt domain '%s' has no disks\n"),
-             program_name, guest);
-    goto cleanup;
-  }
-
-  /* Successful. */
-  r = nr_added;
-
-cleanup:
-  free (xml);
-  if (xpathObj) xmlXPathFreeObject (xpathObj);
-  if (xpathCtx) xmlXPathFreeContext (xpathCtx);
-  if (doc) xmlFreeDoc (doc);
-  if (dom) virDomainFree (dom);
-  if (conn) virConnectClose (conn);
-
-  return r;
+  return guestfs_add_domain_argv (g, guest, &optargs);
 }
index ab63584..0a1d9da 100644 (file)
@@ -45,12 +45,11 @@ guestmount_CFLAGS = \
        -I$(srcdir)/../gnulib/lib -I../gnulib/lib \
        -DGUESTFS_DEFAULT_PATH='"$(libdir)/guestfs"' \
        -DLOCALEBASEDIR=\""$(datadir)/locale"\" \
-       $(FUSE_CFLAGS) $(LIBVIRT_CFLAGS) $(LIBXML2_CFLAGS) \
+       $(FUSE_CFLAGS) \
        $(WARN_CFLAGS) $(WERROR_CFLAGS)
 
 guestmount_LDADD = \
        $(FUSE_LIBS) -lulockmgr \
-       $(LIBVIRT_LIBS) $(LIBXML2_LIBS) \
        $(top_builddir)/src/libguestfs.la \
        ../gnulib/lib/libgnu.la
 
index be20748..7fc5251 100755 (executable)
@@ -56,11 +56,11 @@ cat > test.xml <<EOF
 </node>
 EOF
 
-../fish/guestfish -c "test://$cwd/test.xml" --ro -d guest -x \
-  </dev/null >test.out 2>&1
-grep -sq '^add_drive.*test1.img.*readonly:true' test.out
-! grep -sq '^add_drive.*test1.img.*format' test.out
-grep -sq '^add_drive.*test2.img.*readonly:true.*format:raw' test.out
-grep -sq '^add_drive.*test3.img.*readonly:true.*format:qcow2' test.out
+../fish/guestfish -c "test://$cwd/test.xml" --ro -d guest \
+  debug-cmdline </dev/null >test.out
+grep -sq "test1.img.*snapshot=on" test.out
+! grep -sq "test1.img.*format" test.out
+grep -sq "test2.img.*snapshot=on.*format=raw" test.out
+grep -sq "test3.img.*snapshot=on.*format=qcow2" test.out
 
 rm -f test1.img test2.img test3.img test.xml test.out