e49cb1f1edfd78217099bc59e402896805048aa5
[libguestfs.git] / src / inspect.c
1 /* libguestfs
2  * Copyright (C) 2010-2011 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 <stdint.h>
24 #include <inttypes.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <errno.h>
30 #include <endian.h>
31
32 #include <pcre.h>
33
34 #ifdef HAVE_HIVEX
35 #include <hivex.h>
36 #endif
37
38 #include "c-ctype.h"
39 #include "ignore-value.h"
40 #include "xstrtol.h"
41
42 #include "guestfs.h"
43 #include "guestfs-internal.h"
44 #include "guestfs-internal-actions.h"
45 #include "guestfs_protocol.h"
46
47 #if defined(HAVE_HIVEX)
48
49 /* The main inspection code. */
50 char **
51 guestfs__inspect_os (guestfs_h *g)
52 {
53   /* Remove any information previously stored in the handle. */
54   guestfs___free_inspect_info (g);
55
56   if (guestfs_umount_all (g) == -1)
57     return NULL;
58
59   /* Iterate over all possible devices.  Try to mount each
60    * (read-only).  Examine ones which contain filesystems and add that
61    * information to the handle.
62    */
63   /* Look to see if any devices directly contain filesystems (RHBZ#590167). */
64   char **devices = guestfs_list_devices (g);
65   if (devices == NULL)
66     return NULL;
67
68   size_t i;
69   for (i = 0; devices[i] != NULL; ++i) {
70     if (guestfs___check_for_filesystem_on (g, devices[i], 1, 0) == -1) {
71       guestfs___free_string_list (devices);
72       guestfs___free_inspect_info (g);
73       return NULL;
74     }
75   }
76   guestfs___free_string_list (devices);
77
78   /* Look at all partitions. */
79   char **partitions = guestfs_list_partitions (g);
80   if (partitions == NULL) {
81     guestfs___free_inspect_info (g);
82     return NULL;
83   }
84
85   for (i = 0; partitions[i] != NULL; ++i) {
86     if (guestfs___check_for_filesystem_on (g, partitions[i], 0, i+1) == -1) {
87       guestfs___free_string_list (partitions);
88       guestfs___free_inspect_info (g);
89       return NULL;
90     }
91   }
92   guestfs___free_string_list (partitions);
93
94   /* Look at all LVs. */
95   if (guestfs___feature_available (g, "lvm2")) {
96     char **lvs;
97     lvs = guestfs_lvs (g);
98     if (lvs == NULL) {
99       guestfs___free_inspect_info (g);
100       return NULL;
101     }
102
103     for (i = 0; lvs[i] != NULL; ++i) {
104       if (guestfs___check_for_filesystem_on (g, lvs[i], 0, 0) == -1) {
105         guestfs___free_string_list (lvs);
106         guestfs___free_inspect_info (g);
107         return NULL;
108       }
109     }
110     guestfs___free_string_list (lvs);
111   }
112
113   /* At this point we have, in the handle, a list of all filesystems
114    * found and data about each one.  Now we assemble the list of
115    * filesystems which are root devices and return that to the user.
116    * Fall through to guestfs__inspect_get_roots to do that.
117    */
118   char **ret = guestfs__inspect_get_roots (g);
119   if (ret == NULL)
120     guestfs___free_inspect_info (g);
121   return ret;
122 }
123
124 static int
125 compare_strings (const void *vp1, const void *vp2)
126 {
127   const char *s1 = * (char * const *) vp1;
128   const char *s2 = * (char * const *) vp2;
129
130   return strcmp (s1, s2);
131 }
132
133 char **
134 guestfs__inspect_get_roots (guestfs_h *g)
135 {
136   /* NB. Doesn't matter if g->nr_fses == 0.  We just return an empty
137    * list in this case.
138    */
139
140   size_t i;
141   size_t count = 0;
142   for (i = 0; i < g->nr_fses; ++i)
143     if (g->fses[i].is_root)
144       count++;
145
146   char **ret = calloc (count+1, sizeof (char *));
147   if (ret == NULL) {
148     perrorf (g, "calloc");
149     return NULL;
150   }
151
152   count = 0;
153   for (i = 0; i < g->nr_fses; ++i) {
154     if (g->fses[i].is_root) {
155       ret[count] = safe_strdup (g, g->fses[i].device);
156       count++;
157     }
158   }
159   ret[count] = NULL;
160
161   qsort (ret, count, sizeof (char *), compare_strings);
162
163   return ret;
164 }
165
166 char *
167 guestfs__inspect_get_type (guestfs_h *g, const char *root)
168 {
169   struct inspect_fs *fs = guestfs___search_for_root (g, root);
170   if (!fs)
171     return NULL;
172
173   char *ret;
174   switch (fs->type) {
175   case OS_TYPE_FREEBSD: ret = safe_strdup (g, "freebsd"); break;
176   case OS_TYPE_LINUX: ret = safe_strdup (g, "linux"); break;
177   case OS_TYPE_NETBSD: ret = safe_strdup (g, "netbsd"); break;
178   case OS_TYPE_WINDOWS: ret = safe_strdup (g, "windows"); break;
179   case OS_TYPE_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break;
180   }
181
182   return ret;
183 }
184
185 char *
186 guestfs__inspect_get_arch (guestfs_h *g, const char *root)
187 {
188   struct inspect_fs *fs = guestfs___search_for_root (g, root);
189   if (!fs)
190     return NULL;
191
192   return safe_strdup (g, fs->arch ? : "unknown");
193 }
194
195 char *
196 guestfs__inspect_get_distro (guestfs_h *g, const char *root)
197 {
198   struct inspect_fs *fs = guestfs___search_for_root (g, root);
199   if (!fs)
200     return NULL;
201
202   char *ret;
203   switch (fs->distro) {
204   case OS_DISTRO_ARCHLINUX: ret = safe_strdup (g, "archlinux"); break;
205   case OS_DISTRO_CENTOS: ret = safe_strdup (g, "centos"); break;
206   case OS_DISTRO_DEBIAN: ret = safe_strdup (g, "debian"); break;
207   case OS_DISTRO_FEDORA: ret = safe_strdup (g, "fedora"); break;
208   case OS_DISTRO_GENTOO: ret = safe_strdup (g, "gentoo"); break;
209   case OS_DISTRO_LINUX_MINT: ret = safe_strdup (g, "linuxmint"); break;
210   case OS_DISTRO_MAGEIA: ret = safe_strdup (g, "mageia"); break;
211   case OS_DISTRO_MANDRIVA: ret = safe_strdup (g, "mandriva"); break;
212   case OS_DISTRO_MEEGO: ret = safe_strdup (g, "meego"); break;
213   case OS_DISTRO_OPENSUSE: ret = safe_strdup (g, "opensuse"); break;
214   case OS_DISTRO_PARDUS: ret = safe_strdup (g, "pardus"); break;
215   case OS_DISTRO_REDHAT_BASED: ret = safe_strdup (g, "redhat-based"); break;
216   case OS_DISTRO_RHEL: ret = safe_strdup (g, "rhel"); break;
217   case OS_DISTRO_SCIENTIFIC_LINUX: ret = safe_strdup (g, "scientificlinux"); break;
218   case OS_DISTRO_SLACKWARE: ret = safe_strdup (g, "slackware"); break;
219   case OS_DISTRO_TTYLINUX: ret = safe_strdup (g, "ttylinux"); break;
220   case OS_DISTRO_WINDOWS: ret = safe_strdup (g, "windows"); break;
221   case OS_DISTRO_UBUNTU: ret = safe_strdup (g, "ubuntu"); break;
222   case OS_DISTRO_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break;
223   }
224
225   return ret;
226 }
227
228 int
229 guestfs__inspect_get_major_version (guestfs_h *g, const char *root)
230 {
231   struct inspect_fs *fs = guestfs___search_for_root (g, root);
232   if (!fs)
233     return -1;
234
235   return fs->major_version;
236 }
237
238 int
239 guestfs__inspect_get_minor_version (guestfs_h *g, const char *root)
240 {
241   struct inspect_fs *fs = guestfs___search_for_root (g, root);
242   if (!fs)
243     return -1;
244
245   return fs->minor_version;
246 }
247
248 char *
249 guestfs__inspect_get_product_name (guestfs_h *g, const char *root)
250 {
251   struct inspect_fs *fs = guestfs___search_for_root (g, root);
252   if (!fs)
253     return NULL;
254
255   return safe_strdup (g, fs->product_name ? : "unknown");
256 }
257
258 char *
259 guestfs__inspect_get_product_variant (guestfs_h *g, const char *root)
260 {
261   struct inspect_fs *fs = guestfs___search_for_root (g, root);
262   if (!fs)
263     return NULL;
264
265   return safe_strdup (g, fs->product_variant ? : "unknown");
266 }
267
268 char *
269 guestfs__inspect_get_windows_systemroot (guestfs_h *g, const char *root)
270 {
271   struct inspect_fs *fs = guestfs___search_for_root (g, root);
272   if (!fs)
273     return NULL;
274
275   if (!fs->windows_systemroot) {
276     error (g, _("not a Windows guest, or systemroot could not be determined"));
277     return NULL;
278   }
279
280   return safe_strdup (g, fs->windows_systemroot);
281 }
282
283 char *
284 guestfs__inspect_get_windows_current_control_set (guestfs_h *g,
285                                                   const char *root)
286 {
287   struct inspect_fs *fs = guestfs___search_for_root (g, root);
288   if (!fs)
289     return NULL;
290
291   if (!fs->windows_current_control_set) {
292     error (g, _("not a Windows guest, or CurrentControlSet could not be determined"));
293     return NULL;
294   }
295
296   return safe_strdup (g, fs->windows_current_control_set);
297 }
298
299 char *
300 guestfs__inspect_get_format (guestfs_h *g, const char *root)
301 {
302   struct inspect_fs *fs = guestfs___search_for_root (g, root);
303   if (!fs)
304     return NULL;
305
306   char *ret;
307   switch (fs->format) {
308   case OS_FORMAT_INSTALLED: ret = safe_strdup (g, "installed"); break;
309   case OS_FORMAT_INSTALLER: ret = safe_strdup (g, "installer"); break;
310   case OS_FORMAT_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break;
311   }
312
313   return ret;
314 }
315
316 int
317 guestfs__inspect_is_live (guestfs_h *g, const char *root)
318 {
319   struct inspect_fs *fs = guestfs___search_for_root (g, root);
320   if (!fs)
321     return -1;
322
323   return fs->is_live_disk;
324 }
325
326 int
327 guestfs__inspect_is_netinst (guestfs_h *g, const char *root)
328 {
329   struct inspect_fs *fs = guestfs___search_for_root (g, root);
330   if (!fs)
331     return -1;
332
333   return fs->is_netinst_disk;
334 }
335
336 int
337 guestfs__inspect_is_multipart (guestfs_h *g, const char *root)
338 {
339   struct inspect_fs *fs = guestfs___search_for_root (g, root);
340   if (!fs)
341     return -1;
342
343   return fs->is_multipart_disk;
344 }
345
346 char **
347 guestfs__inspect_get_mountpoints (guestfs_h *g, const char *root)
348 {
349   struct inspect_fs *fs = guestfs___search_for_root (g, root);
350   if (!fs)
351     return NULL;
352
353   char **ret;
354
355   /* If no fstab information (Windows) return just the root. */
356   if (fs->nr_fstab == 0) {
357     ret = calloc (3, sizeof (char *));
358     ret[0] = safe_strdup (g, "/");
359     ret[1] = safe_strdup (g, root);
360     ret[2] = NULL;
361     return ret;
362   }
363
364 #define CRITERION fs->fstab[i].mountpoint[0] == '/'
365   size_t i, count = 0;
366   for (i = 0; i < fs->nr_fstab; ++i)
367     if (CRITERION)
368       count++;
369
370   /* Hashtables have 2N+1 entries. */
371   ret = calloc (2*count+1, sizeof (char *));
372   if (ret == NULL) {
373     perrorf (g, "calloc");
374     return NULL;
375   }
376
377   count = 0;
378   for (i = 0; i < fs->nr_fstab; ++i)
379     if (CRITERION) {
380       ret[2*count] = safe_strdup (g, fs->fstab[i].mountpoint);
381       ret[2*count+1] = safe_strdup (g, fs->fstab[i].device);
382       count++;
383     }
384 #undef CRITERION
385
386   return ret;
387 }
388
389 char **
390 guestfs__inspect_get_filesystems (guestfs_h *g, const char *root)
391 {
392   struct inspect_fs *fs = guestfs___search_for_root (g, root);
393   if (!fs)
394     return NULL;
395
396   char **ret;
397
398   /* If no fstab information (Windows) return just the root. */
399   if (fs->nr_fstab == 0) {
400     ret = calloc (2, sizeof (char *));
401     ret[0] = safe_strdup (g, root);
402     ret[1] = NULL;
403     return ret;
404   }
405
406   ret = calloc (fs->nr_fstab + 1, sizeof (char *));
407   if (ret == NULL) {
408     perrorf (g, "calloc");
409     return NULL;
410   }
411
412   size_t i;
413   for (i = 0; i < fs->nr_fstab; ++i)
414     ret[i] = safe_strdup (g, fs->fstab[i].device);
415
416   return ret;
417 }
418
419 char **
420 guestfs__inspect_get_drive_mappings (guestfs_h *g, const char *root)
421 {
422   char **ret;
423   size_t i, count;
424   struct inspect_fs *fs;
425
426   fs = guestfs___search_for_root (g, root);
427   if (!fs)
428     return NULL;
429
430   /* If no drive mappings, return an empty hashtable. */
431   if (!fs->drive_mappings)
432     count = 0;
433   else {
434     for (count = 0; fs->drive_mappings[count] != NULL; count++)
435       ;
436   }
437
438   ret = calloc (count+1, sizeof (char *));
439   if (ret == NULL) {
440     perrorf (g, "calloc");
441     return NULL;
442   }
443
444   /* We need to make a deep copy of the hashtable since the caller
445    * will free it.
446    */
447   for (i = 0; i < count; ++i)
448     ret[i] = safe_strdup (g, fs->drive_mappings[i]);
449
450   ret[count] = NULL;
451
452   return ret;
453 }
454
455 char *
456 guestfs__inspect_get_package_format (guestfs_h *g, const char *root)
457 {
458   struct inspect_fs *fs = guestfs___search_for_root (g, root);
459   if (!fs)
460     return NULL;
461
462   char *ret;
463   switch (fs->package_format) {
464   case OS_PACKAGE_FORMAT_RPM: ret = safe_strdup (g, "rpm"); break;
465   case OS_PACKAGE_FORMAT_DEB: ret = safe_strdup (g, "deb"); break;
466   case OS_PACKAGE_FORMAT_PACMAN: ret = safe_strdup (g, "pacman"); break;
467   case OS_PACKAGE_FORMAT_EBUILD: ret = safe_strdup (g, "ebuild"); break;
468   case OS_PACKAGE_FORMAT_PISI: ret = safe_strdup (g, "pisi"); break;
469   case OS_PACKAGE_FORMAT_PKGSRC: ret = safe_strdup (g, "pkgsrc"); break;
470   case OS_PACKAGE_FORMAT_UNKNOWN:
471   default:
472     ret = safe_strdup (g, "unknown");
473     break;
474   }
475
476   return ret;
477 }
478
479 char *
480 guestfs__inspect_get_package_management (guestfs_h *g, const char *root)
481 {
482   struct inspect_fs *fs = guestfs___search_for_root (g, root);
483   if (!fs)
484     return NULL;
485
486   char *ret;
487   switch (fs->package_management) {
488   case OS_PACKAGE_MANAGEMENT_YUM: ret = safe_strdup (g, "yum"); break;
489   case OS_PACKAGE_MANAGEMENT_UP2DATE: ret = safe_strdup (g, "up2date"); break;
490   case OS_PACKAGE_MANAGEMENT_APT: ret = safe_strdup (g, "apt"); break;
491   case OS_PACKAGE_MANAGEMENT_PACMAN: ret = safe_strdup (g, "pacman"); break;
492   case OS_PACKAGE_MANAGEMENT_PORTAGE: ret = safe_strdup (g, "portage"); break;
493   case OS_PACKAGE_MANAGEMENT_PISI: ret = safe_strdup (g, "pisi"); break;
494   case OS_PACKAGE_MANAGEMENT_URPMI: ret = safe_strdup (g, "urpmi"); break;
495   case OS_PACKAGE_MANAGEMENT_ZYPPER: ret = safe_strdup (g, "zypper"); break;
496   case OS_PACKAGE_MANAGEMENT_UNKNOWN:
497   default:
498     ret = safe_strdup (g, "unknown");
499     break;
500   }
501
502   return ret;
503 }
504
505 char *
506 guestfs__inspect_get_hostname (guestfs_h *g, const char *root)
507 {
508   struct inspect_fs *fs = guestfs___search_for_root (g, root);
509   if (!fs)
510     return NULL;
511
512   return safe_strdup (g, fs->hostname ? : "unknown");
513 }
514
515 #else /* no hivex at compile time */
516
517 /* XXX These functions should be in an optgroup. */
518
519 #define NOT_IMPL(r)                                                     \
520   error (g, _("inspection API not available since this version of libguestfs was compiled without the hivex library")); \
521   return r
522
523 char **
524 guestfs__inspect_os (guestfs_h *g)
525 {
526   NOT_IMPL(NULL);
527 }
528
529 char **
530 guestfs__inspect_get_roots (guestfs_h *g)
531 {
532   NOT_IMPL(NULL);
533 }
534
535 char *
536 guestfs__inspect_get_type (guestfs_h *g, const char *root)
537 {
538   NOT_IMPL(NULL);
539 }
540
541 char *
542 guestfs__inspect_get_arch (guestfs_h *g, const char *root)
543 {
544   NOT_IMPL(NULL);
545 }
546
547 char *
548 guestfs__inspect_get_distro (guestfs_h *g, const char *root)
549 {
550   NOT_IMPL(NULL);
551 }
552
553 int
554 guestfs__inspect_get_major_version (guestfs_h *g, const char *root)
555 {
556   NOT_IMPL(-1);
557 }
558
559 int
560 guestfs__inspect_get_minor_version (guestfs_h *g, const char *root)
561 {
562   NOT_IMPL(-1);
563 }
564
565 char *
566 guestfs__inspect_get_product_name (guestfs_h *g, const char *root)
567 {
568   NOT_IMPL(NULL);
569 }
570
571 char *
572 guestfs__inspect_get_product_variant (guestfs_h *g, const char *root)
573 {
574   NOT_IMPL(NULL);
575 }
576
577 char *
578 guestfs__inspect_get_windows_systemroot (guestfs_h *g, const char *root)
579 {
580   NOT_IMPL(NULL);
581 }
582
583 char *
584 guestfs__inspect_get_windows_current_control_set (guestfs_h *g,
585                                                   const char *root)
586 {
587   NOT_IMPL(NULL);
588 }
589
590 char **
591 guestfs__inspect_get_mountpoints (guestfs_h *g, const char *root)
592 {
593   NOT_IMPL(NULL);
594 }
595
596 char **
597 guestfs__inspect_get_filesystems (guestfs_h *g, const char *root)
598 {
599   NOT_IMPL(NULL);
600 }
601
602 char **
603 guestfs__inspect_get_drive_mappings (guestfs_h *g, const char *root)
604 {
605   NOT_IMPL(NULL);
606 }
607
608 char *
609 guestfs__inspect_get_package_format (guestfs_h *g, const char *root)
610 {
611   NOT_IMPL(NULL);
612 }
613
614 char *
615 guestfs__inspect_get_package_management (guestfs_h *g, const char *root)
616 {
617   NOT_IMPL(NULL);
618 }
619
620 char *
621 guestfs__inspect_get_hostname (guestfs_h *g, const char *root)
622 {
623   NOT_IMPL(NULL);
624 }
625
626 char *
627 guestfs__inspect_get_format (guestfs_h *g, const char *root)
628 {
629   NOT_IMPL(NULL);
630 }
631
632 int
633 guestfs__inspect_is_live (guestfs_h *g, const char *root)
634 {
635   NOT_IMPL(-1);
636 }
637
638 int
639 guestfs__inspect_is_netinst (guestfs_h *g, const char *root)
640 {
641   NOT_IMPL(-1);
642 }
643
644 int
645 guestfs__inspect_is_multipart (guestfs_h *g, const char *root)
646 {
647   NOT_IMPL(-1);
648 }
649
650 #endif /* no hivex at compile time */
651
652 void
653 guestfs___free_inspect_info (guestfs_h *g)
654 {
655   size_t i;
656   for (i = 0; i < g->nr_fses; ++i) {
657     free (g->fses[i].device);
658     free (g->fses[i].product_name);
659     free (g->fses[i].product_variant);
660     free (g->fses[i].arch);
661     free (g->fses[i].hostname);
662     free (g->fses[i].windows_systemroot);
663     free (g->fses[i].windows_current_control_set);
664     size_t j;
665     for (j = 0; j < g->fses[i].nr_fstab; ++j) {
666       free (g->fses[i].fstab[j].device);
667       free (g->fses[i].fstab[j].mountpoint);
668     }
669     free (g->fses[i].fstab);
670     if (g->fses[i].drive_mappings)
671       guestfs___free_string_list (g->fses[i].drive_mappings);
672   }
673   free (g->fses);
674   g->nr_fses = 0;
675   g->fses = NULL;
676 }
677
678 /* In the Perl code this is a public function. */
679 int
680 guestfs___feature_available (guestfs_h *g, const char *feature)
681 {
682   /* If there's an error we should ignore it, so to do that we have to
683    * temporarily replace the error handler with a null one.
684    */
685   guestfs_error_handler_cb old_error_cb = g->error_cb;
686   g->error_cb = NULL;
687
688   const char *groups[] = { feature, NULL };
689   int r = guestfs_available (g, (char * const *) groups);
690
691   g->error_cb = old_error_cb;
692
693   return r == 0 ? 1 : 0;
694 }
695
696 /* Download a guest file to a local temporary file.  The file is
697  * cached in the temporary directory, and is not downloaded again.
698  *
699  * The name of the temporary (downloaded) file is returned.  The
700  * caller must free the pointer, but does *not* need to delete the
701  * temporary file.  It will be deleted when the handle is closed.
702  *
703  * Refuse to download the guest file if it is larger than max_size.
704  * On this and other errors, NULL is returned.
705  *
706  * There is actually one cache per 'struct inspect_fs *' in order
707  * to handle the case of multiple roots.
708  */
709 char *
710 guestfs___download_to_tmp (guestfs_h *g, struct inspect_fs *fs,
711                            const char *filename,
712                            const char *basename, int64_t max_size)
713 {
714   char *r;
715   int fd;
716   char devfd[32];
717   int64_t size;
718
719   /* Make the basename unique by prefixing it with the fs number. */
720   if (asprintf (&r, "%s/%td-%s", g->tmpdir, fs - g->fses, basename) == -1) {
721     perrorf (g, "asprintf");
722     return NULL;
723   }
724
725   /* If the file has already been downloaded, return. */
726   if (access (r, R_OK) == 0)
727     return r;
728
729   /* Check size of remote file. */
730   size = guestfs_filesize (g, filename);
731   if (size == -1)
732     /* guestfs_filesize failed and has already set error in handle */
733     goto error;
734   if (size > max_size) {
735     error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
736            filename, size);
737     goto error;
738   }
739
740   fd = open (r, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0600);
741   if (fd == -1) {
742     perrorf (g, "open: %s", r);
743     goto error;
744   }
745
746   snprintf (devfd, sizeof devfd, "/dev/fd/%d", fd);
747
748   if (guestfs_download (g, filename, devfd) == -1) {
749     unlink (r);
750     close (fd);
751     goto error;
752   }
753
754   if (close (fd) == -1) {
755     perrorf (g, "close: %s", r);
756     unlink (r);
757     goto error;
758   }
759
760   return r;
761
762  error:
763   free (r);
764   return NULL;
765 }
766
767 struct inspect_fs *
768 guestfs___search_for_root (guestfs_h *g, const char *root)
769 {
770   if (g->nr_fses == 0) {
771     error (g, _("no inspection data: call guestfs_inspect_os first"));
772     return NULL;
773   }
774
775   size_t i;
776   struct inspect_fs *fs;
777   for (i = 0; i < g->nr_fses; ++i) {
778     fs = &g->fses[i];
779     if (fs->is_root && STREQ (root, fs->device))
780       return fs;
781   }
782
783   error (g, _("%s: root device not found: only call this function with a root device previously returned by guestfs_inspect_os"),
784          root);
785   return NULL;
786 }