daemon: debug segv correct use of dereferencing NULL.
[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 #define GUESTFS___ADD_LIBVIRT_DOM_READONLYDISK_BITMASK (UINT64_C(1)<<3)
71   const char *readonlydisk;
72 };
73
74 static int guestfs___add_libvirt_dom (guestfs_h *g, virDomainPtr dom, const struct guestfs___add_libvirt_dom_argv *optargs);
75
76 int
77 guestfs__add_domain (guestfs_h *g, const char *domain_name,
78                      const struct guestfs_add_domain_argv *optargs)
79 {
80   virErrorPtr err;
81   virConnectPtr conn = NULL;
82   virDomainPtr dom = NULL;
83   int r = -1;
84   const char *libvirturi;
85   int readonly;
86   int live;
87   int allowuuid;
88   const char *readonlydisk;
89   const char *iface;
90   struct guestfs___add_libvirt_dom_argv optargs2 = { .bitmask = 0 };
91
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
99          ? optargs->live : 0;
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;
104
105   if (live && readonly) {
106     error (g, _("you cannot set both live and readonly flags"));
107     return -1;
108   }
109
110   /* Connect to libvirt, find the domain. */
111   conn = virConnectOpenReadOnly (libvirturi);
112   if (!conn) {
113     err = virGetLastError ();
114     error (g, _("could not connect to libvirt (code %d, domain %d): %s"),
115            err->code, err->domain, err->message);
116     goto cleanup;
117   }
118
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 ...
122    */
123   virConnSetErrorFunc (conn, NULL, ignore_errors);
124
125   /* Try UUID first. */
126   if (allowuuid)
127     dom = virDomainLookupByUUIDString (conn, domain_name);
128
129   /* Try ordinary domain name. */
130   if (!dom)
131     dom = virDomainLookupByName (conn, domain_name);
132
133   if (!dom) {
134     err = virGetLastError ();
135     error (g, _("no libvirt domain called '%s': %s"),
136            domain_name, err->message);
137     goto cleanup;
138   }
139
140   if (readonly) {
141     optargs2.bitmask |= GUESTFS___ADD_LIBVIRT_DOM_READONLY_BITMASK;
142     optargs2.readonly = readonly;
143   }
144   if (iface) {
145     optargs2.bitmask |= GUESTFS___ADD_LIBVIRT_DOM_IFACE_BITMASK;
146     optargs2.iface = iface;
147   }
148   if (live) {
149     optargs2.bitmask |= GUESTFS___ADD_LIBVIRT_DOM_LIVE_BITMASK;
150     optargs2.live = live;
151   }
152   if (readonlydisk) {
153     optargs2.bitmask |= GUESTFS___ADD_LIBVIRT_DOM_READONLYDISK_BITMASK;
154     optargs2.readonlydisk = readonlydisk;
155   }
156
157   r = guestfs___add_libvirt_dom (g, dom, &optargs2);
158
159  cleanup:
160   if (dom) virDomainFree (dom);
161   if (conn) virConnectClose (conn);
162
163   return r;
164 }
165
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
168  * really provide.
169  *
170  * The callback function 'f' is called once for each disk.
171  *
172  * Returns number of disks, or -1 if there was an error.
173  */
174 int
175 guestfs___for_each_disk (guestfs_h *g,
176                          virDomainPtr dom,
177                          int (*f) (guestfs_h *g,
178                                    const char *filename, const char *format,
179                                    int readonly,
180                                    void *data),
181                          void *data)
182 {
183   int i, nr_added = 0, r = -1;
184   virErrorPtr err;
185   xmlDocPtr doc = NULL;
186   xmlXPathContextPtr xpathCtx = NULL;
187   xmlXPathObjectPtr xpathObj = NULL;
188   char *xml = NULL;
189
190   /* Domain XML. */
191   xml = virDomainGetXMLDesc (dom, 0);
192
193   if (!xml) {
194     err = virGetLastError ();
195     error (g, _("error reading libvirt XML information: %s"),
196            err->message);
197     goto cleanup;
198   }
199
200   /* Now the horrible task of parsing out the fields we need from the XML.
201    * http://www.xmlsoft.org/examples/xpath1.c
202    */
203   doc = xmlParseMemory (xml, strlen (xml));
204   if (doc == NULL) {
205     error (g, _("unable to parse XML information returned by libvirt"));
206     goto cleanup;
207   }
208
209   xpathCtx = xmlXPathNewContext (doc);
210   if (xpathCtx == NULL) {
211     error (g, _("unable to create new XPath context"));
212     goto cleanup;
213   }
214
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"));
219     goto cleanup;
220   }
221
222   xmlNodeSetPtr nodes = xpathObj->nodesetval;
223   for (i = 0; i < nodes->nodeNr; ++i) {
224     xmlXPathObjectPtr xptype;
225
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.
229      */
230     xpathCtx->node = nodes->nodeTab[i];
231
232     /* Filename can be in <source dev=..> or <source file=..> attribute.
233      * Check the <disk type=..> attribute first to find out which one.
234      */
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 */
241     }
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);
247
248     xmlXPathObjectPtr xpfilename;
249
250     if (STREQ (type, "file")) { /* type = "file" so look at source/@file */
251       free (type);
252
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 */
260       }
261     } else if (STREQ (type, "block")) { /* type = "block", use source/@dev */
262       free (type);
263
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 */
271       }
272     } else {
273       free (type);
274       continue;               /* type <> "file" or "block", skip it */
275     }
276
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);
281
282     /* Get the disk format (may not be set). */
283     xmlXPathObjectPtr xpformat;
284
285     xpathCtx->node = nodes->nodeTab[i];
286     xpformat = xmlXPathEvalExpression (BAD_CAST "./driver/@type", xpathCtx);
287     char *format = NULL;
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);
295     }
296
297     /* Get the <readonly/> flag. */
298     xmlXPathObjectPtr xpreadonly;
299
300     xpathCtx->node = nodes->nodeTab[i];
301     xpreadonly = xmlXPathEvalExpression (BAD_CAST "./readonly", xpathCtx);
302     int readonly = 0;
303     if (xpreadonly != NULL &&
304         xpreadonly->nodesetval &&
305         xpreadonly->nodesetval->nodeNr > 0)
306       readonly = 1;
307
308     int t;
309     if (f)
310       t = f (g, filename, format, readonly, data);
311     else
312       t = 0;
313
314     xmlFree (filename);
315     xmlFree (format);
316     xmlXPathFreeObject (xpfilename);
317     xmlXPathFreeObject (xpformat);
318     xmlXPathFreeObject (xpreadonly);
319
320     if (t == -1)
321       goto cleanup;
322
323     nr_added++;
324   }
325
326   if (nr_added == 0) {
327     error (g, _("libvirt domain has no disks"));
328     goto cleanup;
329   }
330
331   /* Successful. */
332   r = nr_added;
333
334  cleanup:
335   free (xml);
336   if (xpathObj) xmlXPathFreeObject (xpathObj);
337   if (xpathCtx) xmlXPathFreeContext (xpathCtx);
338   if (doc) xmlFreeDoc (doc);
339
340   return r;
341 }
342
343 /* This was proposed as an external API, but it's not quite baked yet. */
344
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);
347
348 enum readonlydisk {
349   readonlydisk_error,
350   readonlydisk_read,
351   readonlydisk_write,
352   readonlydisk_ignore,
353 };
354
355 struct add_disk_data {
356   int readonly;
357   enum readonlydisk readonlydisk;
358   /* Other args to pass through to add_drive_opts. */
359   struct guestfs_add_drive_opts_argv optargs;
360 };
361
362 static int
363 guestfs___add_libvirt_dom (guestfs_h *g, virDomainPtr dom,
364                            const struct guestfs___add_libvirt_dom_argv *optargs)
365 {
366   size_t cmdline_pos;
367   int r;
368   int readonly;
369   const char *iface;
370   int live;
371   /* Default for back-compat reasons: */
372   enum readonlydisk readonlydisk = readonlydisk_write;
373
374   readonly =
375     optargs->bitmask & GUESTFS___ADD_LIBVIRT_DOM_READONLY_BITMASK
376     ? optargs->readonly : 0;
377   iface =
378     optargs->bitmask & GUESTFS___ADD_LIBVIRT_DOM_IFACE_BITMASK
379     ? optargs->iface : NULL;
380   live =
381     optargs->bitmask & GUESTFS___ADD_LIBVIRT_DOM_LIVE_BITMASK
382     ? optargs->live : 0;
383
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;
393     else {
394       error (g, _("unknown readonlydisk parameter"));
395       return -1;
396     }
397   }
398
399   if (live && readonly) {
400     error (g, _("you cannot set both live and readonly flags"));
401     return -1;
402   }
403
404   if (!readonly) {
405     virDomainInfo info;
406     virErrorPtr err;
407     int vm_running;
408
409     if (virDomainGetInfo (dom, &info) == -1) {
410       err = virGetLastError ();
411       error (g, _("error getting domain info: %s"), err->message);
412       return -1;
413     }
414     vm_running = info.state != VIR_DOMAIN_SHUTOFF;
415
416     if (vm_running) {
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.
420        */
421       if (live)
422         return connect_live (g, dom);
423
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."));
430       return -1;
431     }
432   }
433
434   /* Add the disks. */
435   struct add_disk_data data;
436   data.optargs.bitmask = 0;
437   data.readonly = readonly;
438   data.readonlydisk = readonlydisk;
439   if (iface) {
440     data.optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_IFACE_BITMASK;
441     data.optargs.iface = iface;
442   }
443
444   /* Checkpoint the command line around the operation so that either
445    * all disks are added or none are added.
446    */
447   struct drive **cp = guestfs___checkpoint_drives (g);
448   r = guestfs___for_each_disk (g, dom, add_disk, &data);
449   if (r == -1)
450     guestfs___rollback_drives (g, cp);
451
452   return r;
453 }
454
455 static int
456 add_disk (guestfs_h *g,
457           const char *filename, const char *format, int readonly_in_xml,
458           void *datavp)
459 {
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;
464
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;
472       default: abort ();
473       }
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;
480       default: abort ();
481       }
482     }
483   } else                        /* no <readonly/> in XML */
484     readonly = data->readonly;
485
486   if (skip)
487     return 0;
488
489   if (error) {
490     error (g, _("%s: disk is marked <readonly/> in libvirt XML, and readonlydisk was set to \"error\""),
491            filename);
492     return -1;
493   }
494
495   optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_READONLY_BITMASK;
496   optargs.readonly = readonly;
497
498   if (format) {
499     optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
500     optargs.format = format;
501   }
502
503   return guestfs__add_drive_opts (g, filename, &optargs);
504 }
505
506 static int
507 connect_live (guestfs_h *g, virDomainPtr dom)
508 {
509   int i, r = -1;
510   virErrorPtr err;
511   xmlDocPtr doc = NULL;
512   xmlXPathContextPtr xpathCtx = NULL;
513   xmlXPathObjectPtr xpathObj = NULL;
514   char *xml = NULL;
515   char *path = NULL;
516   char *attach_method = NULL;
517
518   /* Domain XML. */
519   xml = virDomainGetXMLDesc (dom, 0);
520
521   if (!xml) {
522     err = virGetLastError ();
523     error (g, _("error reading libvirt XML information: %s"),
524            err->message);
525     goto cleanup;
526   }
527
528   /* Parse XML to document. */
529   doc = xmlParseMemory (xml, strlen (xml));
530   if (doc == NULL) {
531     error (g, _("unable to parse XML information returned by libvirt"));
532     goto cleanup;
533   }
534
535   xpathCtx = xmlXPathNewContext (doc);
536   if (xpathCtx == NULL) {
537     error (g, _("unable to create new XPath context"));
538     goto cleanup;
539   }
540
541   /* This gives us a set of all the <channel> nodes related to the
542    * guestfsd virtio-serial channel.
543    */
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\"]",
550                                      xpathCtx);
551   if (xpathObj == NULL) {
552     error (g, _("unable to evaluate XPath expression"));
553     goto cleanup;
554   }
555
556   xmlNodeSetPtr nodes = xpathObj->nodesetval;
557   for (i = 0; i < nodes->nodeNr; ++i) {
558     xmlXPathObjectPtr xppath;
559
560     /* See note in function above. */
561     xpathCtx->node = nodes->nodeTab[i];
562
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 */
570     }
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);
576     break;
577   }
578
579   if (path == NULL) {
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."));
582     goto cleanup;
583   }
584
585   /* Got a path. */
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);
590
591  cleanup:
592   free (path);
593   free (attach_method);
594   free (xml);
595   if (xpathObj) xmlXPathFreeObject (xpathObj);
596   if (xpathCtx) xmlXPathFreeContext (xpathCtx);
597   if (doc) xmlFreeDoc (doc);
598
599   return r;
600 }
601
602 #else /* no libvirt or libxml2 at compile time */
603
604 #define NOT_IMPL(r)                                                     \
605   error (g, _("add-domain API not available since this version of libguestfs was compiled without libvirt or libxml2")); \
606   return r
607
608 int
609 guestfs__add_domain (guestfs_h *g, const char *dom,
610                      const struct guestfs_add_domain_argv *optargs)
611 {
612   NOT_IMPL(-1);
613 }
614
615 #endif /* no libvirt or libxml2 at compile time */