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