2 * Copyright (C) 2010 Red Hat Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 #include <libvirt/libvirt.h>
27 #include <libvirt/virterror.h>
31 #include <libxml/xpath.h>
32 #include <libxml/parser.h>
33 #include <libxml/tree.h>
36 #define GUESTFS_PRIVATE_FOR_EACH_DISK 1
39 #include "guestfs-internal.h"
40 #include "guestfs-internal-actions.h"
41 #include "guestfs_protocol.h"
43 #if defined(HAVE_LIBVIRT) && defined(HAVE_LIBXML2)
45 static void init_libxml2 (void) __attribute__((constructor));
50 /* I am told that you don't really need to call virInitialize ... */
57 ignore_errors (void *ignore, virErrorPtr ignore2)
62 struct guestfs___add_libvirt_dom_argv {
64 #define GUESTFS___ADD_LIBVIRT_DOM_READONLY_BITMASK (UINT64_C(1)<<0)
66 #define GUESTFS___ADD_LIBVIRT_DOM_IFACE_BITMASK (UINT64_C(1)<<1)
68 #define GUESTFS___ADD_LIBVIRT_DOM_LIVE_BITMASK (UINT64_C(1)<<2)
70 #define GUESTFS___ADD_LIBVIRT_DOM_READONLYDISK_BITMASK (UINT64_C(1)<<3)
71 const char *readonlydisk;
74 static int guestfs___add_libvirt_dom (guestfs_h *g, virDomainPtr dom, const struct guestfs___add_libvirt_dom_argv *optargs);
77 guestfs__add_domain (guestfs_h *g, const char *domain_name,
78 const struct guestfs_add_domain_argv *optargs)
81 virConnectPtr conn = NULL;
82 virDomainPtr dom = NULL;
84 const char *libvirturi;
88 const char *readonlydisk;
90 struct guestfs___add_libvirt_dom_argv optargs2 = { .bitmask = 0 };
92 libvirturi = optargs->bitmask & GUESTFS_ADD_DOMAIN_LIBVIRTURI_BITMASK
93 ? optargs->libvirturi : NULL;
94 readonly = optargs->bitmask & GUESTFS_ADD_DOMAIN_READONLY_BITMASK
95 ? optargs->readonly : 0;
96 iface = optargs->bitmask & GUESTFS_ADD_DOMAIN_IFACE_BITMASK
97 ? optargs->iface : NULL;
98 live = optargs->bitmask & GUESTFS_ADD_DOMAIN_LIVE_BITMASK
100 allowuuid = optargs->bitmask & GUESTFS_ADD_DOMAIN_ALLOWUUID_BITMASK
101 ? optargs->allowuuid : 0;
102 readonlydisk = optargs->bitmask & GUESTFS_ADD_DOMAIN_READONLYDISK_BITMASK
103 ? optargs->readonlydisk : NULL;
105 if (live && readonly) {
106 error (g, _("you cannot set both live and readonly flags"));
110 /* Connect to libvirt, find the domain. */
111 conn = virConnectOpenReadOnly (libvirturi);
113 err = virGetLastError ();
114 error (g, _("could not connect to libvirt (code %d, domain %d): %s"),
115 err->code, err->domain, err->message);
119 /* Suppress default behaviour of printing errors to stderr. Note
120 * you can't set this to NULL to ignore errors; setting it to NULL
121 * restores the default error handler ...
123 virConnSetErrorFunc (conn, NULL, ignore_errors);
125 /* Try UUID first. */
127 dom = virDomainLookupByUUIDString (conn, domain_name);
129 /* Try ordinary domain name. */
131 dom = virDomainLookupByName (conn, domain_name);
134 err = virGetLastError ();
135 error (g, _("no libvirt domain called '%s': %s"),
136 domain_name, err->message);
141 optargs2.bitmask |= GUESTFS___ADD_LIBVIRT_DOM_READONLY_BITMASK;
142 optargs2.readonly = readonly;
145 optargs2.bitmask |= GUESTFS___ADD_LIBVIRT_DOM_IFACE_BITMASK;
146 optargs2.iface = iface;
149 optargs2.bitmask |= GUESTFS___ADD_LIBVIRT_DOM_LIVE_BITMASK;
150 optargs2.live = live;
153 optargs2.bitmask |= GUESTFS___ADD_LIBVIRT_DOM_READONLYDISK_BITMASK;
154 optargs2.readonlydisk = readonlydisk;
157 r = guestfs___add_libvirt_dom (g, dom, &optargs2);
160 if (dom) virDomainFree (dom);
161 if (conn) virConnectClose (conn);
166 /* This function is also used in virt-df to avoid having all that
167 * stupid XPath code repeated. This is something that libvirt should
170 * The callback function 'f' is called once for each disk.
172 * Returns number of disks, or -1 if there was an error.
175 guestfs___for_each_disk (guestfs_h *g,
177 int (*f) (guestfs_h *g,
178 const char *filename, const char *format,
183 int i, nr_added = 0, r = -1;
185 xmlDocPtr doc = NULL;
186 xmlXPathContextPtr xpathCtx = NULL;
187 xmlXPathObjectPtr xpathObj = NULL;
191 xml = virDomainGetXMLDesc (dom, 0);
194 err = virGetLastError ();
195 error (g, _("error reading libvirt XML information: %s"),
200 /* Now the horrible task of parsing out the fields we need from the XML.
201 * http://www.xmlsoft.org/examples/xpath1.c
203 doc = xmlParseMemory (xml, strlen (xml));
205 error (g, _("unable to parse XML information returned by libvirt"));
209 xpathCtx = xmlXPathNewContext (doc);
210 if (xpathCtx == NULL) {
211 error (g, _("unable to create new XPath context"));
215 /* This gives us a set of all the <disk> nodes. */
216 xpathObj = xmlXPathEvalExpression (BAD_CAST "//devices/disk", xpathCtx);
217 if (xpathObj == NULL) {
218 error (g, _("unable to evaluate XPath expression"));
222 xmlNodeSetPtr nodes = xpathObj->nodesetval;
223 for (i = 0; i < nodes->nodeNr; ++i) {
224 xmlXPathObjectPtr xptype;
226 /* Change the context to the current <disk> node.
227 * DV advises to reset this before each search since older versions of
228 * libxml2 might overwrite it.
230 xpathCtx->node = nodes->nodeTab[i];
232 /* Filename can be in <source dev=..> or <source file=..> attribute.
233 * Check the <disk type=..> attribute first to find out which one.
235 xptype = xmlXPathEvalExpression (BAD_CAST "./@type", xpathCtx);
236 if (xptype == NULL ||
237 xptype->nodesetval == NULL ||
238 xptype->nodesetval->nodeNr == 0) {
239 xmlXPathFreeObject (xptype);
240 continue; /* no type attribute, skip it */
242 assert (xptype->nodesetval->nodeTab[0]);
243 assert (xptype->nodesetval->nodeTab[0]->type == XML_ATTRIBUTE_NODE);
244 xmlAttrPtr attr = (xmlAttrPtr) xptype->nodesetval->nodeTab[0];
245 char *type = (char *) xmlNodeListGetString (doc, attr->children, 1);
246 xmlXPathFreeObject (xptype);
248 xmlXPathObjectPtr xpfilename;
250 if (STREQ (type, "file")) { /* type = "file" so look at source/@file */
253 xpathCtx->node = nodes->nodeTab[i];
254 xpfilename = xmlXPathEvalExpression (BAD_CAST "./source/@file", xpathCtx);
255 if (xpfilename == NULL ||
256 xpfilename->nodesetval == NULL ||
257 xpfilename->nodesetval->nodeNr == 0) {
258 xmlXPathFreeObject (xpfilename);
259 continue; /* disk filename not found, skip this */
261 } else if (STREQ (type, "block")) { /* type = "block", use source/@dev */
264 xpathCtx->node = nodes->nodeTab[i];
265 xpfilename = xmlXPathEvalExpression (BAD_CAST "./source/@dev", xpathCtx);
266 if (xpfilename == NULL ||
267 xpfilename->nodesetval == NULL ||
268 xpfilename->nodesetval->nodeNr == 0) {
269 xmlXPathFreeObject (xpfilename);
270 continue; /* disk filename not found, skip this */
274 continue; /* type <> "file" or "block", skip it */
277 assert (xpfilename->nodesetval->nodeTab[0]);
278 assert (xpfilename->nodesetval->nodeTab[0]->type == XML_ATTRIBUTE_NODE);
279 attr = (xmlAttrPtr) xpfilename->nodesetval->nodeTab[0];
280 char *filename = (char *) xmlNodeListGetString (doc, attr->children, 1);
282 /* Get the disk format (may not be set). */
283 xmlXPathObjectPtr xpformat;
285 xpathCtx->node = nodes->nodeTab[i];
286 xpformat = xmlXPathEvalExpression (BAD_CAST "./driver/@type", xpathCtx);
288 if (xpformat != NULL &&
289 xpformat->nodesetval &&
290 xpformat->nodesetval->nodeNr > 0) {
291 assert (xpformat->nodesetval->nodeTab[0]);
292 assert (xpformat->nodesetval->nodeTab[0]->type == XML_ATTRIBUTE_NODE);
293 attr = (xmlAttrPtr) xpformat->nodesetval->nodeTab[0];
294 format = (char *) xmlNodeListGetString (doc, attr->children, 1);
297 /* Get the <readonly/> flag. */
298 xmlXPathObjectPtr xpreadonly;
300 xpathCtx->node = nodes->nodeTab[i];
301 xpreadonly = xmlXPathEvalExpression (BAD_CAST "./readonly", xpathCtx);
303 if (xpreadonly != NULL &&
304 xpreadonly->nodesetval &&
305 xpreadonly->nodesetval->nodeNr > 0)
310 t = f (g, filename, format, readonly, data);
316 xmlXPathFreeObject (xpfilename);
317 xmlXPathFreeObject (xpformat);
318 xmlXPathFreeObject (xpreadonly);
327 error (g, _("libvirt domain has no disks"));
336 if (xpathObj) xmlXPathFreeObject (xpathObj);
337 if (xpathCtx) xmlXPathFreeContext (xpathCtx);
338 if (doc) xmlFreeDoc (doc);
343 /* This was proposed as an external API, but it's not quite baked yet. */
345 static int add_disk (guestfs_h *g, const char *filename, const char *format, int readonly, void *data);
346 static int connect_live (guestfs_h *g, virDomainPtr dom);
355 struct add_disk_data {
357 enum readonlydisk readonlydisk;
358 /* Other args to pass through to add_drive_opts. */
359 struct guestfs_add_drive_opts_argv optargs;
363 guestfs___add_libvirt_dom (guestfs_h *g, virDomainPtr dom,
364 const struct guestfs___add_libvirt_dom_argv *optargs)
371 /* Default for back-compat reasons: */
372 enum readonlydisk readonlydisk = readonlydisk_write;
375 optargs->bitmask & GUESTFS___ADD_LIBVIRT_DOM_READONLY_BITMASK
376 ? optargs->readonly : 0;
378 optargs->bitmask & GUESTFS___ADD_LIBVIRT_DOM_IFACE_BITMASK
379 ? optargs->iface : NULL;
381 optargs->bitmask & GUESTFS___ADD_LIBVIRT_DOM_LIVE_BITMASK
384 if ((optargs->bitmask & GUESTFS___ADD_LIBVIRT_DOM_READONLYDISK_BITMASK)) {
385 if (STREQ (optargs->readonlydisk, "error"))
386 readonlydisk = readonlydisk_error;
387 else if (STREQ (optargs->readonlydisk, "read"))
388 readonlydisk = readonlydisk_read;
389 else if (STREQ (optargs->readonlydisk, "write"))
390 readonlydisk = readonlydisk_write;
391 else if (STREQ (optargs->readonlydisk, "ignore"))
392 readonlydisk = readonlydisk_ignore;
394 error (g, _("unknown readonlydisk parameter"));
399 if (live && readonly) {
400 error (g, _("you cannot set both live and readonly flags"));
409 if (virDomainGetInfo (dom, &info) == -1) {
410 err = virGetLastError ();
411 error (g, _("error getting domain info: %s"), err->message);
414 vm_running = info.state != VIR_DOMAIN_SHUTOFF;
417 /* If the caller specified the 'live' flag, then they want us to
418 * try to connect to guestfsd if the domain is running. Note
419 * that live readonly connections are not possible.
422 return connect_live (g, dom);
424 /* Dangerous to modify the disks of a running VM. */
425 error (g, _("error: domain is a live virtual machine.\n"
426 "Writing to the disks of a running virtual machine can cause disk corruption.\n"
427 "Either use read-only access, or if the guest is running the guestfsd daemon\n"
428 "specify live access. In most libguestfs tools these options are --ro or\n"
429 "--live respectively. Consult the documentation for further information."));
435 struct add_disk_data data;
436 data.optargs.bitmask = 0;
437 data.readonly = readonly;
438 data.readonlydisk = readonlydisk;
440 data.optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_IFACE_BITMASK;
441 data.optargs.iface = iface;
444 /* Checkpoint the command line around the operation so that either
445 * all disks are added or none are added.
447 struct drive **cp = guestfs___checkpoint_drives (g);
448 r = guestfs___for_each_disk (g, dom, add_disk, &data);
450 guestfs___rollback_drives (g, cp);
456 add_disk (guestfs_h *g,
457 const char *filename, const char *format, int readonly_in_xml,
460 struct add_disk_data *data = datavp;
461 /* Copy whole struct so we can make local changes: */
462 struct guestfs_add_drive_opts_argv optargs = data->optargs;
463 int readonly, error = 0, skip = 0;
465 if (readonly_in_xml) { /* <readonly/> appears in the XML */
466 if (data->readonly) { /* asked to add disk read-only */
467 switch (data->readonlydisk) {
468 case readonlydisk_error: readonly = 1; break;
469 case readonlydisk_read: readonly = 1; break;
470 case readonlydisk_write: readonly = 1; break;
471 case readonlydisk_ignore: skip = 1; break;
474 } else { /* asked to add disk for read/write */
475 switch (data->readonlydisk) {
476 case readonlydisk_error: error = 1; break;
477 case readonlydisk_read: readonly = 1; break;
478 case readonlydisk_write: readonly = 0; break;
479 case readonlydisk_ignore: skip = 1; break;
483 } else /* no <readonly/> in XML */
484 readonly = data->readonly;
490 error (g, _("%s: disk is marked <readonly/> in libvirt XML, and readonlydisk was set to \"error\""),
495 optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_READONLY_BITMASK;
496 optargs.readonly = readonly;
499 optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
500 optargs.format = format;
503 return guestfs__add_drive_opts (g, filename, &optargs);
507 connect_live (guestfs_h *g, virDomainPtr dom)
511 xmlDocPtr doc = NULL;
512 xmlXPathContextPtr xpathCtx = NULL;
513 xmlXPathObjectPtr xpathObj = NULL;
516 char *attach_method = NULL;
519 xml = virDomainGetXMLDesc (dom, 0);
522 err = virGetLastError ();
523 error (g, _("error reading libvirt XML information: %s"),
528 /* Parse XML to document. */
529 doc = xmlParseMemory (xml, strlen (xml));
531 error (g, _("unable to parse XML information returned by libvirt"));
535 xpathCtx = xmlXPathNewContext (doc);
536 if (xpathCtx == NULL) {
537 error (g, _("unable to create new XPath context"));
541 /* This gives us a set of all the <channel> nodes related to the
542 * guestfsd virtio-serial channel.
544 xpathObj = xmlXPathEvalExpression (BAD_CAST
545 "//devices/channel[@type=\"unix\" and "
546 "./source/@mode=\"bind\" and "
547 "./source/@path and "
548 "./target/@type=\"virtio\" and "
549 "./target/@name=\"org.libguestfs.channel.0\"]",
551 if (xpathObj == NULL) {
552 error (g, _("unable to evaluate XPath expression"));
556 xmlNodeSetPtr nodes = xpathObj->nodesetval;
557 for (i = 0; i < nodes->nodeNr; ++i) {
558 xmlXPathObjectPtr xppath;
560 /* See note in function above. */
561 xpathCtx->node = nodes->nodeTab[i];
563 /* The path is in <source path=..> attribute. */
564 xppath = xmlXPathEvalExpression (BAD_CAST "./source/@path", xpathCtx);
565 if (xppath == NULL ||
566 xppath->nodesetval == NULL ||
567 xppath->nodesetval->nodeNr == 0) {
568 xmlXPathFreeObject (xppath);
569 continue; /* no type attribute, skip it */
571 assert (xppath->nodesetval->nodeTab[0]);
572 assert (xppath->nodesetval->nodeTab[0]->type == XML_ATTRIBUTE_NODE);
573 xmlAttrPtr attr = (xmlAttrPtr) xppath->nodesetval->nodeTab[0];
574 path = (char *) xmlNodeListGetString (doc, attr->children, 1);
575 xmlXPathFreeObject (xppath);
580 error (g, _("this guest has no libvirt <channel> definition for guestfsd\n"
581 "See ATTACHING TO RUNNING DAEMONS in guestfs(3) for further information."));
586 attach_method = safe_malloc (g, strlen (path) + 5 + 1);
587 strcpy (attach_method, "unix:");
588 strcat (attach_method, path);
589 r = guestfs_set_attach_method (g, attach_method);
593 free (attach_method);
595 if (xpathObj) xmlXPathFreeObject (xpathObj);
596 if (xpathCtx) xmlXPathFreeContext (xpathCtx);
597 if (doc) xmlFreeDoc (doc);
602 #else /* no libvirt or libxml2 at compile time */
604 #define NOT_IMPL(r) \
605 error (g, _("add-domain API not available since this version of libguestfs was compiled without libvirt or libxml2")); \
609 guestfs__add_domain (guestfs_h *g, const char *dom,
610 const struct guestfs_add_domain_argv *optargs)
615 #endif /* no libvirt or libxml2 at compile time */