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