-/* guestfish - the filesystem interactive shell
+/* libguestfs - guestfish and guestmount shared option parsing
* Copyright (C) 2010 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
#include <string.h>
#include <assert.h>
-#include <libvirt/libvirt.h>
-#include <libvirt/virterror.h>
+#include "guestfs.h"
-#include <libxml/xpath.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-
-#include "fish.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, _("guestfish: could not connect to libvirt (code %d, domain %d): %s\n"),
- err->code, err->domain, err->message);
- goto cleanup;
- }
-
- dom = virDomainLookupByName (conn, guest);
- if (!dom) {
- err = virConnGetLastError (conn);
- fprintf (stderr, _("guestfish: no libvirt domain called '%s': %s\n"),
- guest, err->message);
- goto cleanup;
- }
- if (!read_only) {
- virDomainInfo info;
- if (virDomainGetInfo (dom, &info) == -1) {
- err = virConnGetLastError (conn);
- fprintf (stderr, _("guestfish: error getting domain info about '%s': %s\n"),
- guest, err->message);
- goto cleanup;
- }
- if (info.state != VIR_DOMAIN_SHUTOFF) {
- fprintf (stderr, _("guestfish: error: '%s' is a live virtual machine.\nYou must use '--ro' because write access to a running virtual machine can\ncause disk corruption.\n"),
- guest);
- goto cleanup;
- }
- }
+ struct guestfs_add_domain_argv optargs = { .bitmask = 0 };
- /* Domain XML. */
- xml = virDomainGetXMLDesc (dom, 0);
-
- if (!xml) {
- err = virConnGetLastError (conn);
- fprintf (stderr, _("guestfish: error reading libvirt XML information about '%s': %s\n"),
- guest, err->message);
- goto cleanup;
+ if (libvirt_uri) {
+ optargs.bitmask |= GUESTFS_ADD_DOMAIN_LIBVIRTURI_BITMASK;
+ optargs.libvirturi = libvirt_uri;
}
-
- /* 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, _("guestfish: unable to parse XML information returned by libvirt\n"));
- goto cleanup;
+ if (read_only) {
+ optargs.bitmask |= GUESTFS_ADD_DOMAIN_READONLY_BITMASK;
+ optargs.readonly = 1;
}
-
- xpathCtx = xmlXPathNewContext (doc);
- if (xpathCtx == NULL) {
- fprintf (stderr, _("guestfish: unable to create new XPath context\n"));
- goto cleanup;
+ if (live) {
+ optargs.bitmask |= GUESTFS_ADD_DOMAIN_LIVE_BITMASK;
+ optargs.live = 1;
}
- /* This gives us a set of all the <disk> nodes. */
- xpathObj = xmlXPathEvalExpression (BAD_CAST "//devices/disk", xpathCtx);
- if (xpathObj == NULL) {
- fprintf (stderr, _("guestfish: unable to evaluate XPath expression\n"));
- goto cleanup;
- }
-
- 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, _("guestfish: libvirt domain '%s' has no disks\n"),
- 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);
+ optargs.bitmask |= GUESTFS_ADD_DOMAIN_ALLOWUUID_BITMASK;
+ optargs.allowuuid = 1;
- return r;
+ return guestfs_add_domain_argv (g, guest, &optargs);
}