cd48888687a6251197f30f7d81b0f233184dfbb9
[libguestfs.git] / src / virt.c
1 /* libguestfs
2  * Copyright (C) 2010 Red Hat Inc.
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <assert.h>
24
25 #ifdef HAVE_LIBVIRT
26 #include <libvirt/libvirt.h>
27 #include <libvirt/virterror.h>
28 #endif
29
30 #ifdef HAVE_LIBXML2
31 #include <libxml/xpath.h>
32 #include <libxml/parser.h>
33 #include <libxml/tree.h>
34 #endif
35
36 #define GUESTFS_PRIVATE_FOR_EACH_DISK 1
37
38 #include "guestfs.h"
39 #include "guestfs-internal.h"
40 #include "guestfs-internal-actions.h"
41 #include "guestfs_protocol.h"
42
43 #if defined(HAVE_LIBVIRT) && defined(HAVE_LIBXML2)
44
45 static void init_libxml2 (void) __attribute__((constructor));
46
47 static void
48 init_libxml2 (void)
49 {
50   /* I am told that you don't really need to call virInitialize ... */
51
52   xmlInitParser ();
53   LIBXML_TEST_VERSION;
54 }
55
56 static void
57 ignore_errors (void *ignore, virErrorPtr ignore2)
58 {
59   /* empty */
60 }
61
62 struct guestfs___add_libvirt_dom_argv {
63   uint64_t bitmask;
64 #define GUESTFS___ADD_LIBVIRT_DOM_READONLY_BITMASK (UINT64_C(1)<<0)
65   int readonly;
66 #define GUESTFS___ADD_LIBVIRT_DOM_IFACE_BITMASK (UINT64_C(1)<<1)
67   const char *iface;
68 #define GUESTFS___ADD_LIBVIRT_DOM_LIVE_BITMASK (UINT64_C(1)<<2)
69   int live;
70 };
71
72 static int guestfs___add_libvirt_dom (guestfs_h *g, virDomainPtr dom, const struct guestfs___add_libvirt_dom_argv *optargs);
73
74 int
75 guestfs__add_domain (guestfs_h *g, const char *domain_name,
76                      const struct guestfs_add_domain_argv *optargs)
77 {
78   virErrorPtr err;
79   virConnectPtr conn = NULL;
80   virDomainPtr dom = NULL;
81   int r = -1;
82   const char *libvirturi;
83   int readonly;
84   int live;
85   const char *iface;
86   struct guestfs___add_libvirt_dom_argv optargs2 = { .bitmask = 0 };
87
88   libvirturi = optargs->bitmask & GUESTFS_ADD_DOMAIN_LIBVIRTURI_BITMASK
89                ? optargs->libvirturi : NULL;
90   readonly = optargs->bitmask & GUESTFS_ADD_DOMAIN_READONLY_BITMASK
91              ? optargs->readonly : 0;
92   iface = optargs->bitmask & GUESTFS_ADD_DOMAIN_IFACE_BITMASK
93           ? optargs->iface : NULL;
94   live = optargs->bitmask & GUESTFS_ADD_DOMAIN_LIVE_BITMASK
95          ? optargs->live : 0;
96
97   if (live && readonly) {
98     error (g, _("you cannot set both live and readonly flags"));
99     return -1;
100   }
101
102   /* Connect to libvirt, find the domain. */
103   conn = virConnectOpenReadOnly (libvirturi);
104   if (!conn) {
105     err = virGetLastError ();
106     error (g, _("could not connect to libvirt (code %d, domain %d): %s"),
107            err->code, err->domain, err->message);
108     goto cleanup;
109   }
110
111   /* Suppress default behaviour of printing errors to stderr.  Note
112    * you can't set this to NULL to ignore errors; setting it to NULL
113    * restores the default error handler ...
114    */
115   virConnSetErrorFunc (conn, NULL, ignore_errors);
116
117   dom = virDomainLookupByName (conn, domain_name);
118   if (!dom) {
119     err = virGetLastError ();
120     error (g, _("no libvirt domain called '%s': %s"),
121            domain_name, err->message);
122     goto cleanup;
123   }
124
125   if (readonly) {
126     optargs2.bitmask |= GUESTFS___ADD_LIBVIRT_DOM_READONLY_BITMASK;
127     optargs2.readonly = readonly;
128   }
129   if (iface) {
130     optargs2.bitmask |= GUESTFS___ADD_LIBVIRT_DOM_IFACE_BITMASK;
131     optargs2.iface = iface;
132   }
133   if (live) {
134     optargs2.bitmask |= GUESTFS___ADD_LIBVIRT_DOM_LIVE_BITMASK;
135     optargs2.live = live;
136   }
137
138   r = guestfs___add_libvirt_dom (g, dom, &optargs2);
139
140  cleanup:
141   if (dom) virDomainFree (dom);
142   if (conn) virConnectClose (conn);
143
144   return r;
145 }
146
147 /* This function is also used in virt-df to avoid having all that
148  * stupid XPath code repeated.  This is something that libvirt should
149  * really provide.
150  *
151  * The callback function 'f' is called once for each disk.
152  *
153  * Returns number of disks, or -1 if there was an error.
154  */
155 int
156 guestfs___for_each_disk (guestfs_h *g,
157                          virDomainPtr dom,
158                          int (*f) (guestfs_h *g,
159                                    const char *filename, const char *format,
160                                    void *data),
161                          void *data)
162 {
163   int i, nr_added = 0, r = -1;
164   virErrorPtr err;
165   xmlDocPtr doc = NULL;
166   xmlXPathContextPtr xpathCtx = NULL;
167   xmlXPathObjectPtr xpathObj = NULL;
168   char *xml = NULL;
169
170   /* Domain XML. */
171   xml = virDomainGetXMLDesc (dom, 0);
172
173   if (!xml) {
174     err = virGetLastError ();
175     error (g, _("error reading libvirt XML information: %s"),
176            err->message);
177     goto cleanup;
178   }
179
180   /* Now the horrible task of parsing out the fields we need from the XML.
181    * http://www.xmlsoft.org/examples/xpath1.c
182    */
183   doc = xmlParseMemory (xml, strlen (xml));
184   if (doc == NULL) {
185     error (g, _("unable to parse XML information returned by libvirt"));
186     goto cleanup;
187   }
188
189   xpathCtx = xmlXPathNewContext (doc);
190   if (xpathCtx == NULL) {
191     error (g, _("unable to create new XPath context"));
192     goto cleanup;
193   }
194
195   /* This gives us a set of all the <disk> nodes. */
196   xpathObj = xmlXPathEvalExpression (BAD_CAST "//devices/disk", xpathCtx);
197   if (xpathObj == NULL) {
198     error (g, _("unable to evaluate XPath expression"));
199     goto cleanup;
200   }
201
202   xmlNodeSetPtr nodes = xpathObj->nodesetval;
203   for (i = 0; i < nodes->nodeNr; ++i) {
204     xmlXPathObjectPtr xptype;
205
206     /* Change the context to the current <disk> node.
207      * DV advises to reset this before each search since older versions of
208      * libxml2 might overwrite it.
209      */
210     xpathCtx->node = nodes->nodeTab[i];
211
212     /* Filename can be in <source dev=..> or <source file=..> attribute.
213      * Check the <disk type=..> attribute first to find out which one.
214      */
215     xptype = xmlXPathEvalExpression (BAD_CAST "./@type", xpathCtx);
216     if (xptype == NULL ||
217         xptype->nodesetval == NULL ||
218         xptype->nodesetval->nodeNr == 0) {
219       xmlXPathFreeObject (xptype);
220       continue;                 /* no type attribute, skip it */
221     }
222     assert (xptype->nodesetval->nodeTab[0]);
223     assert (xptype->nodesetval->nodeTab[0]->type == XML_ATTRIBUTE_NODE);
224     xmlAttrPtr attr = (xmlAttrPtr) xptype->nodesetval->nodeTab[0];
225     char *type = (char *) xmlNodeListGetString (doc, attr->children, 1);
226     xmlXPathFreeObject (xptype);
227
228     xmlXPathObjectPtr xpfilename;
229
230     if (STREQ (type, "file")) { /* type = "file" so look at source/@file */
231       free (type);
232
233       xpathCtx->node = nodes->nodeTab[i];
234       xpfilename = xmlXPathEvalExpression (BAD_CAST "./source/@file", xpathCtx);
235       if (xpfilename == NULL ||
236           xpfilename->nodesetval == NULL ||
237           xpfilename->nodesetval->nodeNr == 0) {
238         xmlXPathFreeObject (xpfilename);
239         continue;             /* disk filename not found, skip this */
240       }
241     } else if (STREQ (type, "block")) { /* type = "block", use source/@dev */
242       free (type);
243
244       xpathCtx->node = nodes->nodeTab[i];
245       xpfilename = xmlXPathEvalExpression (BAD_CAST "./source/@dev", xpathCtx);
246       if (xpfilename == NULL ||
247           xpfilename->nodesetval == NULL ||
248           xpfilename->nodesetval->nodeNr == 0) {
249         xmlXPathFreeObject (xpfilename);
250         continue;             /* disk filename not found, skip this */
251       }
252     } else {
253       free (type);
254       continue;               /* type <> "file" or "block", skip it */
255     }
256
257     assert (xpfilename->nodesetval->nodeTab[0]);
258     assert (xpfilename->nodesetval->nodeTab[0]->type == XML_ATTRIBUTE_NODE);
259     attr = (xmlAttrPtr) xpfilename->nodesetval->nodeTab[0];
260     char *filename = (char *) xmlNodeListGetString (doc, attr->children, 1);
261
262     /* Get the disk format (may not be set). */
263     xmlXPathObjectPtr xpformat;
264
265     xpathCtx->node = nodes->nodeTab[i];
266     xpformat = xmlXPathEvalExpression (BAD_CAST "./driver/@type", xpathCtx);
267     char *format = NULL;
268     if (xpformat != NULL &&
269         xpformat->nodesetval &&
270         xpformat->nodesetval->nodeNr > 0) {
271       assert (xpformat->nodesetval->nodeTab[0]);
272       assert (xpformat->nodesetval->nodeTab[0]->type == XML_ATTRIBUTE_NODE);
273       attr = (xmlAttrPtr) xpformat->nodesetval->nodeTab[0];
274       format = (char *) xmlNodeListGetString (doc, attr->children, 1);
275     }
276
277     int t;
278     if (f)
279       t = f (g, filename, format, data);
280     else
281       t = 0;
282
283     xmlFree (filename);
284     xmlFree (format);
285     xmlXPathFreeObject (xpfilename);
286     xmlXPathFreeObject (xpformat);
287
288     if (t == -1)
289       goto cleanup;
290
291     nr_added++;
292   }
293
294   if (nr_added == 0) {
295     error (g, _("libvirt domain has no disks"));
296     goto cleanup;
297   }
298
299   /* Successful. */
300   r = nr_added;
301
302  cleanup:
303   free (xml);
304   if (xpathObj) xmlXPathFreeObject (xpathObj);
305   if (xpathCtx) xmlXPathFreeContext (xpathCtx);
306   if (doc) xmlFreeDoc (doc);
307
308   return r;
309 }
310
311 /* This was proposed as an external API, but it's not quite baked yet. */
312
313 static int add_disk (guestfs_h *g, const char *filename, const char *format, void *optargs_vp);
314 static int connect_live (guestfs_h *g, virDomainPtr dom);
315
316 static int
317 guestfs___add_libvirt_dom (guestfs_h *g, virDomainPtr dom,
318                            const struct guestfs___add_libvirt_dom_argv *optargs)
319 {
320   size_t cmdline_pos;
321   int r;
322   int readonly;
323   const char *iface;
324   int live;
325
326   readonly =
327     optargs->bitmask & GUESTFS___ADD_LIBVIRT_DOM_READONLY_BITMASK
328     ? optargs->readonly : 0;
329   iface =
330     optargs->bitmask & GUESTFS___ADD_LIBVIRT_DOM_IFACE_BITMASK
331     ? optargs->iface : NULL;
332   live =
333     optargs->bitmask & GUESTFS___ADD_LIBVIRT_DOM_LIVE_BITMASK
334     ? optargs->live : 0;
335
336   if (live && readonly) {
337     error (g, _("you cannot set both live and readonly flags"));
338     return -1;
339   }
340
341   if (!readonly) {
342     virDomainInfo info;
343     virErrorPtr err;
344     int vm_running;
345
346     if (virDomainGetInfo (dom, &info) == -1) {
347       err = virGetLastError ();
348       error (g, _("error getting domain info: %s"), err->message);
349       return -1;
350     }
351     vm_running = info.state != VIR_DOMAIN_SHUTOFF;
352
353     if (vm_running) {
354       /* If the caller specified the 'live' flag, then they want us to
355        * try to connect to guestfsd if the domain is running.  Note
356        * that live readonly connections are not possible.
357        */
358       if (live)
359         return connect_live (g, dom);
360
361       /* Dangerous to modify the disks of a running VM. */
362       error (g, _("error: domain is a live virtual machine.\n"
363                   "Writing to the disks of a running virtual machine can cause disk corruption.\n"
364                   "Either use read-only access, or if the guest is running the guestfsd daemon\n"
365                   "specify live access.  In most libguestfs tools these options are --ro or\n"
366                   "--live respectively.  Consult the documentation for further information."));
367       return -1;
368     }
369   }
370
371   /* Add the disks. */
372   struct guestfs_add_drive_opts_argv optargs2 = { .bitmask = 0 };
373   if (readonly) {
374     optargs2.bitmask |= GUESTFS_ADD_DRIVE_OPTS_READONLY_BITMASK;
375     optargs2.readonly = readonly;
376   }
377   if (iface) {
378     optargs2.bitmask |= GUESTFS_ADD_DRIVE_OPTS_IFACE_BITMASK;
379     optargs2.iface = iface;
380   }
381
382   /* Checkpoint the command line around the operation so that either
383    * all disks are added or none are added.
384    */
385   cmdline_pos = guestfs___checkpoint_cmdline (g);
386   r = guestfs___for_each_disk (g, dom, add_disk, &optargs2);
387   if (r == -1)
388     guestfs___rollback_cmdline (g, cmdline_pos);
389
390   return r;
391 }
392
393 static int
394 add_disk (guestfs_h *g, const char *filename, const char *format,
395           void *optargs_vp)
396 {
397   struct guestfs_add_drive_opts_argv *optargs = optargs_vp;
398
399   if (format) {
400     optargs->bitmask |= GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
401     optargs->format = format;
402   } else
403     optargs->bitmask &= ~GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
404
405   return guestfs__add_drive_opts (g, filename, optargs);
406 }
407
408 static int
409 connect_live (guestfs_h *g, virDomainPtr dom)
410 {
411   int i, r = -1;
412   virErrorPtr err;
413   xmlDocPtr doc = NULL;
414   xmlXPathContextPtr xpathCtx = NULL;
415   xmlXPathObjectPtr xpathObj = NULL;
416   char *xml = NULL;
417   char *path = NULL;
418   char *attach_method = NULL;
419
420   /* Domain XML. */
421   xml = virDomainGetXMLDesc (dom, 0);
422
423   if (!xml) {
424     err = virGetLastError ();
425     error (g, _("error reading libvirt XML information: %s"),
426            err->message);
427     goto cleanup;
428   }
429
430   /* Parse XML to document. */
431   doc = xmlParseMemory (xml, strlen (xml));
432   if (doc == NULL) {
433     error (g, _("unable to parse XML information returned by libvirt"));
434     goto cleanup;
435   }
436
437   xpathCtx = xmlXPathNewContext (doc);
438   if (xpathCtx == NULL) {
439     error (g, _("unable to create new XPath context"));
440     goto cleanup;
441   }
442
443   /* This gives us a set of all the <channel> nodes related to the
444    * guestfsd virtio-serial channel.
445    */
446   xpathObj = xmlXPathEvalExpression (BAD_CAST
447       "//devices/channel[@type=\"unix\" and "
448                         "./source/@mode=\"bind\" and "
449                         "./source/@path and "
450                         "./target/@type=\"virtio\" and "
451                         "./target/@name=\"org.libguestfs.channel.0\"]",
452                                      xpathCtx);
453   if (xpathObj == NULL) {
454     error (g, _("unable to evaluate XPath expression"));
455     goto cleanup;
456   }
457
458   xmlNodeSetPtr nodes = xpathObj->nodesetval;
459   for (i = 0; i < nodes->nodeNr; ++i) {
460     xmlXPathObjectPtr xppath;
461
462     /* See note in function above. */
463     xpathCtx->node = nodes->nodeTab[i];
464
465     /* The path is in <source path=..> attribute. */
466     xppath = xmlXPathEvalExpression (BAD_CAST "./source/@path", xpathCtx);
467     if (xppath == NULL ||
468         xppath->nodesetval == NULL ||
469         xppath->nodesetval->nodeNr == 0) {
470       xmlXPathFreeObject (xppath);
471       continue;                 /* no type attribute, skip it */
472     }
473     assert (xppath->nodesetval->nodeTab[0]);
474     assert (xppath->nodesetval->nodeTab[0]->type == XML_ATTRIBUTE_NODE);
475     xmlAttrPtr attr = (xmlAttrPtr) xppath->nodesetval->nodeTab[0];
476     path = (char *) xmlNodeListGetString (doc, attr->children, 1);
477     xmlXPathFreeObject (xppath);
478     break;
479   }
480
481   if (path == NULL) {
482     error (g, _("this guest has no libvirt <channel> definition for guestfsd\n"
483                 "See ATTACHING TO RUNNING DAEMONS in guestfs(3) for further information."));
484     goto cleanup;
485   }
486
487   /* Got a path. */
488   attach_method = safe_malloc (g, strlen (path) + 5 + 1);
489   strcpy (attach_method, "unix:");
490   strcat (attach_method, path);
491   r = guestfs_set_attach_method (g, attach_method);
492
493  cleanup:
494   free (path);
495   free (attach_method);
496   free (xml);
497   if (xpathObj) xmlXPathFreeObject (xpathObj);
498   if (xpathCtx) xmlXPathFreeContext (xpathCtx);
499   if (doc) xmlFreeDoc (doc);
500
501   return r;
502 }
503
504 #else /* no libvirt or libxml2 at compile time */
505
506 #define NOT_IMPL(r)                                                     \
507   error (g, _("add-domain API not available since this version of libguestfs was compiled without libvirt or libxml2")); \
508   return r
509
510 int
511 guestfs__add_domain (guestfs_h *g, const char *dom,
512                      const struct guestfs_add_domain_argv *optargs)
513 {
514   NOT_IMPL(-1);
515 }
516
517 #endif /* no libvirt or libxml2 at compile time */