New API: inspect-get-windows-current-control-set
[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 <string.h>
27 #include <sys/stat.h>
28 #include <errno.h>
29
30 #ifdef HAVE_PCRE
31 #include <pcre.h>
32 #endif
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_PCRE) && defined(HAVE_HIVEX)
48
49 /* Some limits on what we will read, for safety. */
50
51 /* Small text configuration files.
52  *
53  * The upper limit is for general files that we grep or download.  The
54  * largest such file is probably "txtsetup.sif" from Windows CDs
55  * (~500K).  This number has to be larger than any legitimate file and
56  * smaller than the protocol message size.
57  *
58  * The lower limit is for files parsed by Augeas on the daemon side,
59  * where Augeas is running in reduced memory and can potentially
60  * create a lot of metadata so we really need to be careful about
61  * those.
62  */
63 #define MAX_SMALL_FILE_SIZE    (2 * 1000 * 1000)
64 #define MAX_AUGEAS_FILE_SIZE        (100 * 1000)
65
66 /* Maximum Windows Registry hive that we will download to /tmp.  Some
67  * registries can be legitimately very large.
68  */
69 #define MAX_REGISTRY_SIZE    (100 * 1000 * 1000)
70
71 /* Maximum RPM or dpkg database we will download to /tmp. */
72 #define MAX_PKG_DB_SIZE       (10 * 1000 * 1000)
73
74 /* Compile all the regular expressions once when the shared library is
75  * loaded.  PCRE is thread safe so we're supposedly OK here if
76  * multiple threads call into the libguestfs API functions below
77  * simultaneously.
78  */
79 static pcre *re_fedora;
80 static pcre *re_rhel_old;
81 static pcre *re_rhel;
82 static pcre *re_rhel_no_minor;
83 static pcre *re_major_minor;
84 static pcre *re_aug_seq;
85 static pcre *re_xdev;
86 static pcre *re_first_partition;
87 static pcre *re_freebsd;
88 static pcre *re_windows_version;
89
90 static void compile_regexps (void) __attribute__((constructor));
91 static void free_regexps (void) __attribute__((destructor));
92
93 static void
94 compile_regexps (void)
95 {
96   const char *err;
97   int offset;
98
99 #define COMPILE(re,pattern,options)                                     \
100   do {                                                                  \
101     re = pcre_compile ((pattern), (options), &err, &offset, NULL);      \
102     if (re == NULL) {                                                   \
103       ignore_value (write (2, err, strlen (err)));                      \
104       abort ();                                                         \
105     }                                                                   \
106   } while (0)
107
108   COMPILE (re_fedora, "Fedora release (\\d+)", 0);
109   COMPILE (re_rhel_old,
110            "(?:Red Hat|CentOS|Scientific Linux).*release (\\d+).*Update (\\d+)", 0);
111   COMPILE (re_rhel,
112            "(?:Red Hat|CentOS|Scientific Linux).*release (\\d+)\\.(\\d+)", 0);
113   COMPILE (re_rhel_no_minor,
114            "(?:Red Hat|CentOS|Scientific Linux).*release (\\d+)", 0);
115   COMPILE (re_major_minor, "(\\d+)\\.(\\d+)", 0);
116   COMPILE (re_aug_seq, "/\\d+$", 0);
117   COMPILE (re_xdev, "^/dev/(?:h|s|v|xv)d([a-z]\\d*)$", 0);
118   COMPILE (re_first_partition, "^/dev/(?:h|s|v)d.1$", 0);
119   COMPILE (re_freebsd, "^/dev/ad(\\d+)s(\\d+)([a-z])$", 0);
120   COMPILE (re_windows_version, "^(\\d+)\\.(\\d+)", 0);
121 }
122
123 static void
124 free_regexps (void)
125 {
126   pcre_free (re_fedora);
127   pcre_free (re_rhel_old);
128   pcre_free (re_rhel);
129   pcre_free (re_rhel_no_minor);
130   pcre_free (re_major_minor);
131   pcre_free (re_aug_seq);
132   pcre_free (re_xdev);
133   pcre_free (re_first_partition);
134   pcre_free (re_freebsd);
135   pcre_free (re_windows_version);
136 }
137
138 /* The main inspection code. */
139 static int check_for_filesystem_on (guestfs_h *g, const char *device, int is_block, int is_partnum);
140
141 char **
142 guestfs__inspect_os (guestfs_h *g)
143 {
144   /* Remove any information previously stored in the handle. */
145   guestfs___free_inspect_info (g);
146
147   if (guestfs_umount_all (g) == -1)
148     return NULL;
149
150   /* Iterate over all possible devices.  Try to mount each
151    * (read-only).  Examine ones which contain filesystems and add that
152    * information to the handle.
153    */
154   /* Look to see if any devices directly contain filesystems (RHBZ#590167). */
155   char **devices;
156   devices = guestfs_list_devices (g);
157   if (devices == NULL)
158     return NULL;
159
160   size_t i;
161   for (i = 0; devices[i] != NULL; ++i) {
162     if (check_for_filesystem_on (g, devices[i], 1, 0) == -1) {
163       guestfs___free_string_list (devices);
164       guestfs___free_inspect_info (g);
165       return NULL;
166     }
167   }
168   guestfs___free_string_list (devices);
169
170   /* Look at all partitions. */
171   char **partitions;
172   partitions = guestfs_list_partitions (g);
173   if (partitions == NULL) {
174     guestfs___free_inspect_info (g);
175     return NULL;
176   }
177
178   for (i = 0; partitions[i] != NULL; ++i) {
179     if (check_for_filesystem_on (g, partitions[i], 0, i+1) == -1) {
180       guestfs___free_string_list (partitions);
181       guestfs___free_inspect_info (g);
182       return NULL;
183     }
184   }
185   guestfs___free_string_list (partitions);
186
187   /* Look at all LVs. */
188   if (guestfs___feature_available (g, "lvm2")) {
189     char **lvs;
190     lvs = guestfs_lvs (g);
191     if (lvs == NULL) {
192       guestfs___free_inspect_info (g);
193       return NULL;
194     }
195
196     for (i = 0; lvs[i] != NULL; ++i) {
197       if (check_for_filesystem_on (g, lvs[i], 0, 0) == -1) {
198         guestfs___free_string_list (lvs);
199         guestfs___free_inspect_info (g);
200         return NULL;
201       }
202     }
203     guestfs___free_string_list (lvs);
204   }
205
206   /* At this point we have, in the handle, a list of all filesystems
207    * found and data about each one.  Now we assemble the list of
208    * filesystems which are root devices and return that to the user.
209    * Fall through to guestfs__inspect_get_roots to do that.
210    */
211   char **ret = guestfs__inspect_get_roots (g);
212   if (ret == NULL)
213     guestfs___free_inspect_info (g);
214   return ret;
215 }
216
217 /* Find out if 'device' contains a filesystem.  If it does, add
218  * another entry in g->fses.
219  */
220 static int check_filesystem (guestfs_h *g, const char *device, int is_block, int is_partnum);
221 static int check_linux_root (guestfs_h *g, struct inspect_fs *fs);
222 static int check_freebsd_root (guestfs_h *g, struct inspect_fs *fs);
223 static int check_installer_root (guestfs_h *g, struct inspect_fs *fs);
224 static void check_architecture (guestfs_h *g, struct inspect_fs *fs);
225 static int check_hostname_unix (guestfs_h *g, struct inspect_fs *fs);
226 static int check_hostname_redhat (guestfs_h *g, struct inspect_fs *fs);
227 static int check_hostname_freebsd (guestfs_h *g, struct inspect_fs *fs);
228 static int check_fstab (guestfs_h *g, struct inspect_fs *fs);
229 static int check_windows_root (guestfs_h *g, struct inspect_fs *fs);
230 static int check_windows_arch (guestfs_h *g, struct inspect_fs *fs);
231 static int check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs);
232 static int check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs);
233 static char *case_sensitive_path_silently (guestfs_h *g, const char *);
234 static int is_file_nocase (guestfs_h *g, const char *);
235 static int is_dir_nocase (guestfs_h *g, const char *);
236 static int extend_fses (guestfs_h *g);
237 static int parse_unsigned_int (guestfs_h *g, const char *str);
238 static int parse_unsigned_int_ignore_trailing (guestfs_h *g, const char *str);
239 static int add_fstab_entry (guestfs_h *g, struct inspect_fs *fs,
240                             const char *spec, const char *mp);
241 static char *resolve_fstab_device (guestfs_h *g, const char *spec);
242 static void check_package_format (guestfs_h *g, struct inspect_fs *fs);
243 static void check_package_management (guestfs_h *g, struct inspect_fs *fs);
244 static int download_to_tmp (guestfs_h *g, const char *filename, char *localtmp, int64_t max_size);
245 static int inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char *filename, int (*f) (guestfs_h *, struct inspect_fs *));
246 static char *first_line_of_file (guestfs_h *g, const char *filename);
247 static int first_egrep_of_file (guestfs_h *g, const char *filename, const char *eregex, int iflag, char **ret);
248
249 static int
250 check_for_filesystem_on (guestfs_h *g, const char *device,
251                          int is_block, int is_partnum)
252 {
253   /* Get vfs-type in order to check if it's a Linux(?) swap device.
254    * If there's an error we should ignore it, so to do that we have to
255    * temporarily replace the error handler with a null one.
256    */
257   guestfs_error_handler_cb old_error_cb = g->error_cb;
258   g->error_cb = NULL;
259   char *vfs_type = guestfs_vfs_type (g, device);
260   g->error_cb = old_error_cb;
261
262   int is_swap = vfs_type && STREQ (vfs_type, "swap");
263
264   debug (g, "check_for_filesystem_on: %s %d %d (%s)",
265          device, is_block, is_partnum,
266          vfs_type ? vfs_type : "failed to get vfs type");
267
268   if (is_swap) {
269     free (vfs_type);
270     if (extend_fses (g) == -1)
271       return -1;
272     g->fses[g->nr_fses-1].is_swap = 1;
273     return 0;
274   }
275
276   /* Try mounting the device.  As above, ignore errors. */
277   g->error_cb = NULL;
278   int r = guestfs_mount_ro (g, device, "/");
279   if (r == -1 && vfs_type && STREQ (vfs_type, "ufs")) /* Hack for the *BSDs. */
280     r = guestfs_mount_vfs (g, "ro,ufstype=ufs2", "ufs", device, "/");
281   free (vfs_type);
282   g->error_cb = old_error_cb;
283   if (r == -1)
284     return 0;
285
286   /* Do the rest of the checks. */
287   r = check_filesystem (g, device, is_block, is_partnum);
288
289   /* Unmount the filesystem. */
290   if (guestfs_umount_all (g) == -1)
291     return -1;
292
293   return r;
294 }
295
296 /* is_block and is_partnum are just hints: is_block is true if the
297  * filesystem is a whole block device (eg. /dev/sda).  is_partnum
298  * is > 0 if the filesystem is a direct partition, and in this case
299  * it is the partition number counting from 1
300  * (eg. /dev/sda1 => is_partnum == 1).
301  */
302 static int
303 check_filesystem (guestfs_h *g, const char *device,
304                   int is_block, int is_partnum)
305 {
306   if (extend_fses (g) == -1)
307     return -1;
308
309   struct inspect_fs *fs = &g->fses[g->nr_fses-1];
310
311   fs->device = safe_strdup (g, device);
312   fs->is_mountable = 1;
313
314   /* Optimize some of the tests by avoiding multiple tests of the same thing. */
315   int is_dir_etc = guestfs_is_dir (g, "/etc") > 0;
316   int is_dir_bin = guestfs_is_dir (g, "/bin") > 0;
317   int is_dir_share = guestfs_is_dir (g, "/share") > 0;
318
319   /* Grub /boot? */
320   if (guestfs_is_file (g, "/grub/menu.lst") > 0 ||
321       guestfs_is_file (g, "/grub/grub.conf") > 0)
322     fs->content = FS_CONTENT_LINUX_BOOT;
323   /* FreeBSD root? */
324   else if (is_dir_etc &&
325            is_dir_bin &&
326            guestfs_is_file (g, "/etc/freebsd-update.conf") > 0 &&
327            guestfs_is_file (g, "/etc/fstab") > 0) {
328     /* Ignore /dev/sda1 which is a shadow of the real root filesystem
329      * that is probably /dev/sda5 (see:
330      * http://www.freebsd.org/doc/handbook/disk-organization.html)
331      */
332     if (match (g, device, re_first_partition))
333       return 0;
334
335     fs->is_root = 1;
336     fs->content = FS_CONTENT_FREEBSD_ROOT;
337     fs->format = OS_FORMAT_INSTALLED;
338     if (check_freebsd_root (g, fs) == -1)
339       return -1;
340   }
341   /* Linux root? */
342   else if (is_dir_etc &&
343            is_dir_bin &&
344            guestfs_is_file (g, "/etc/fstab") > 0) {
345     fs->is_root = 1;
346     fs->content = FS_CONTENT_LINUX_ROOT;
347     fs->format = OS_FORMAT_INSTALLED;
348     if (check_linux_root (g, fs) == -1)
349       return -1;
350   }
351   /* Linux /usr/local? */
352   else if (is_dir_etc &&
353            is_dir_bin &&
354            is_dir_share &&
355            guestfs_exists (g, "/local") == 0 &&
356            guestfs_is_file (g, "/etc/fstab") == 0)
357     fs->content = FS_CONTENT_LINUX_USR_LOCAL;
358   /* Linux /usr? */
359   else if (is_dir_etc &&
360            is_dir_bin &&
361            is_dir_share &&
362            guestfs_exists (g, "/local") > 0 &&
363            guestfs_is_file (g, "/etc/fstab") == 0)
364     fs->content = FS_CONTENT_LINUX_USR;
365   /* Linux /var? */
366   else if (guestfs_is_dir (g, "/log") > 0 &&
367            guestfs_is_dir (g, "/run") > 0 &&
368            guestfs_is_dir (g, "/spool") > 0)
369     fs->content = FS_CONTENT_LINUX_VAR;
370   /* Windows root?
371    * Note that if a Windows guest has multiple disks and applications
372    * are installed on those other disks, then those other disks will
373    * contain "/Program Files" and "/System Volume Information".  Those
374    * would *not* be Windows root disks.  (RHBZ#674130)
375    */
376   else if (is_file_nocase (g, "/AUTOEXEC.BAT") > 0 ||
377            is_dir_nocase (g, "/WINDOWS") > 0 ||
378            is_dir_nocase (g, "/WIN32") > 0 ||
379            is_dir_nocase (g, "/WINNT") > 0 ||
380            is_file_nocase (g, "/boot.ini") > 0 ||
381            is_file_nocase (g, "/ntldr") > 0) {
382     fs->is_root = 1;
383     fs->content = FS_CONTENT_WINDOWS_ROOT;
384     fs->format = OS_FORMAT_INSTALLED;
385     if (check_windows_root (g, fs) == -1)
386       return -1;
387   }
388   /* Windows volume with installed applications (but not root)? */
389   else if (is_dir_nocase (g, "/System Volume Information") > 0 &&
390            is_dir_nocase (g, "/Program Files") > 0)
391     fs->content = FS_CONTENT_WINDOWS_VOLUME_WITH_APPS;
392   /* Windows volume (but not root)? */
393   else if (is_dir_nocase (g, "/System Volume Information") > 0)
394     fs->content = FS_CONTENT_WINDOWS_VOLUME;
395   /* Install CD/disk?  Skip these checks if it's not a whole device
396    * (eg. CD) or the first partition (eg. bootable USB key).
397    */
398   else if ((is_block || is_partnum == 1) &&
399            (guestfs_is_file (g, "/isolinux/isolinux.cfg") > 0 ||
400             guestfs_is_dir (g, "/EFI/BOOT") > 0 ||
401             guestfs_is_file (g, "/images/install.img") > 0 ||
402             guestfs_is_dir (g, "/.disk") > 0 ||
403             guestfs_is_file (g, "/.discinfo") > 0 ||
404             guestfs_is_file (g, "/i386/txtsetup.sif") > 0 ||
405             guestfs_is_file (g, "/amd64/txtsetup.sif")) > 0) {
406     fs->is_root = 1;
407     fs->content = FS_CONTENT_INSTALLER;
408     fs->format = OS_FORMAT_INSTALLER;
409     if (check_installer_root (g, fs) == -1)
410       return -1;
411   }
412
413   return 0;
414 }
415
416 /* Set fs->product_name to the first line of the release file. */
417 static int
418 parse_release_file (guestfs_h *g, struct inspect_fs *fs,
419                     const char *release_filename)
420 {
421   fs->product_name = first_line_of_file (g, release_filename);
422   if (fs->product_name == NULL)
423     return -1;
424   return 0;
425 }
426
427 /* Parse generic MAJOR.MINOR from the fs->product_name string. */
428 static int
429 parse_major_minor (guestfs_h *g, struct inspect_fs *fs)
430 {
431   char *major, *minor;
432
433   if (match2 (g, fs->product_name, re_major_minor, &major, &minor)) {
434     fs->major_version = parse_unsigned_int (g, major);
435     free (major);
436     if (fs->major_version == -1) {
437       free (minor);
438       return -1;
439     }
440     fs->minor_version = parse_unsigned_int (g, minor);
441     free (minor);
442     if (fs->minor_version == -1)
443       return -1;
444   }
445   return 0;
446 }
447
448 /* Ubuntu has /etc/lsb-release containing:
449  *   DISTRIB_ID=Ubuntu                                # Distro
450  *   DISTRIB_RELEASE=10.04                            # Version
451  *   DISTRIB_CODENAME=lucid
452  *   DISTRIB_DESCRIPTION="Ubuntu 10.04.1 LTS"         # Product name
453  *
454  * [Ubuntu-derived ...] Linux Mint was found to have this:
455  *   DISTRIB_ID=LinuxMint
456  *   DISTRIB_RELEASE=10
457  *   DISTRIB_CODENAME=julia
458  *   DISTRIB_DESCRIPTION="Linux Mint 10 Julia"
459  * Linux Mint also has /etc/linuxmint/info with more information,
460  * but we can use the LSB file.
461  *
462  * Mandriva has:
463  *   LSB_VERSION=lsb-4.0-amd64:lsb-4.0-noarch
464  *   DISTRIB_ID=MandrivaLinux
465  *   DISTRIB_RELEASE=2010.1
466  *   DISTRIB_CODENAME=Henry_Farman
467  *   DISTRIB_DESCRIPTION="Mandriva Linux 2010.1"
468  * Mandriva also has a normal release file called /etc/mandriva-release.
469  */
470 static int
471 parse_lsb_release (guestfs_h *g, struct inspect_fs *fs)
472 {
473   const char *filename = "/etc/lsb-release";
474   int64_t size;
475   char **lines;
476   size_t i;
477   int r = 0;
478
479   /* Don't trust guestfs_head_n not to break with very large files.
480    * Check the file size is something reasonable first.
481    */
482   size = guestfs_filesize (g, filename);
483   if (size == -1)
484     /* guestfs_filesize failed and has already set error in handle */
485     return -1;
486   if (size > MAX_SMALL_FILE_SIZE) {
487     error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
488            filename, size);
489     return -1;
490   }
491
492   lines = guestfs_head_n (g, 10, filename);
493   if (lines == NULL)
494     return -1;
495
496   for (i = 0; lines[i] != NULL; ++i) {
497     if (fs->distro == 0 &&
498         STREQ (lines[i], "DISTRIB_ID=Ubuntu")) {
499       fs->distro = OS_DISTRO_UBUNTU;
500       r = 1;
501     }
502     else if (fs->distro == 0 &&
503              STREQ (lines[i], "DISTRIB_ID=LinuxMint")) {
504       fs->distro = OS_DISTRO_LINUX_MINT;
505       r = 1;
506     }
507     else if (fs->distro == 0 &&
508              STREQ (lines[i], "DISTRIB_ID=MandrivaLinux")) {
509       fs->distro = OS_DISTRO_MANDRIVA;
510       r = 1;
511     }
512     else if (STRPREFIX (lines[i], "DISTRIB_RELEASE=")) {
513       char *major, *minor;
514       if (match2 (g, &lines[i][16], re_major_minor, &major, &minor)) {
515         fs->major_version = parse_unsigned_int (g, major);
516         free (major);
517         if (fs->major_version == -1) {
518           free (minor);
519           guestfs___free_string_list (lines);
520           return -1;
521         }
522         fs->minor_version = parse_unsigned_int (g, minor);
523         free (minor);
524         if (fs->minor_version == -1) {
525           guestfs___free_string_list (lines);
526           return -1;
527         }
528       }
529     }
530     else if (fs->product_name == NULL &&
531              (STRPREFIX (lines[i], "DISTRIB_DESCRIPTION=\"") ||
532               STRPREFIX (lines[i], "DISTRIB_DESCRIPTION='"))) {
533       size_t len = strlen (lines[i]) - 21 - 1;
534       fs->product_name = safe_strndup (g, &lines[i][21], len);
535       r = 1;
536     }
537     else if (fs->product_name == NULL &&
538              STRPREFIX (lines[i], "DISTRIB_DESCRIPTION=")) {
539       size_t len = strlen (lines[i]) - 20;
540       fs->product_name = safe_strndup (g, &lines[i][20], len);
541       r = 1;
542     }
543   }
544
545   guestfs___free_string_list (lines);
546   return r;
547 }
548
549 /* The currently mounted device is known to be a Linux root.  Try to
550  * determine from this the distro, version, etc.  Also parse
551  * /etc/fstab to determine the arrangement of mountpoints and
552  * associated devices.
553  */
554 static int
555 check_linux_root (guestfs_h *g, struct inspect_fs *fs)
556 {
557   int r;
558
559   fs->type = OS_TYPE_LINUX;
560
561   if (guestfs_exists (g, "/etc/lsb-release") > 0) {
562     r = parse_lsb_release (g, fs);
563     if (r == -1)        /* error */
564       return -1;
565     if (r == 1)         /* ok - detected the release from this file */
566       goto skip_release_checks;
567   }
568
569   if (guestfs_exists (g, "/etc/redhat-release") > 0) {
570     fs->distro = OS_DISTRO_REDHAT_BASED; /* Something generic Red Hat-like. */
571
572     if (parse_release_file (g, fs, "/etc/redhat-release") == -1)
573       return -1;
574
575     char *major, *minor;
576     if ((major = match1 (g, fs->product_name, re_fedora)) != NULL) {
577       fs->distro = OS_DISTRO_FEDORA;
578       fs->major_version = parse_unsigned_int (g, major);
579       free (major);
580       if (fs->major_version == -1)
581         return -1;
582     }
583     else if (match2 (g, fs->product_name, re_rhel_old, &major, &minor) ||
584              match2 (g, fs->product_name, re_rhel, &major, &minor)) {
585       fs->distro = OS_DISTRO_RHEL;
586       fs->major_version = parse_unsigned_int (g, major);
587       free (major);
588       if (fs->major_version == -1) {
589         free (minor);
590         return -1;
591       }
592       fs->minor_version = parse_unsigned_int (g, minor);
593       free (minor);
594       if (fs->minor_version == -1)
595         return -1;
596     }
597     else if ((major = match1 (g, fs->product_name, re_rhel_no_minor)) != NULL) {
598       fs->distro = OS_DISTRO_RHEL;
599       fs->major_version = parse_unsigned_int (g, major);
600       free (major);
601       if (fs->major_version == -1)
602         return -1;
603       fs->minor_version = 0;
604     }
605   }
606   else if (guestfs_exists (g, "/etc/debian_version") > 0) {
607     fs->distro = OS_DISTRO_DEBIAN;
608
609     if (parse_release_file (g, fs, "/etc/debian_version") == -1)
610       return -1;
611
612     if (parse_major_minor (g, fs) == -1)
613       return -1;
614   }
615   else if (guestfs_exists (g, "/etc/pardus-release") > 0) {
616     fs->distro = OS_DISTRO_PARDUS;
617
618     if (parse_release_file (g, fs, "/etc/pardus-release") == -1)
619       return -1;
620
621     if (parse_major_minor (g, fs) == -1)
622       return -1;
623   }
624   else if (guestfs_exists (g, "/etc/arch-release") > 0) {
625     fs->distro = OS_DISTRO_ARCHLINUX;
626
627     /* /etc/arch-release file is empty and I can't see a way to
628      * determine the actual release or product string.
629      */
630   }
631   else if (guestfs_exists (g, "/etc/gentoo-release") > 0) {
632     fs->distro = OS_DISTRO_GENTOO;
633
634     if (parse_release_file (g, fs, "/etc/gentoo-release") == -1)
635       return -1;
636
637     if (parse_major_minor (g, fs) == -1)
638       return -1;
639   }
640   else if (guestfs_exists (g, "/etc/meego-release") > 0) {
641     fs->distro = OS_DISTRO_MEEGO;
642
643     if (parse_release_file (g, fs, "/etc/meego-release") == -1)
644       return -1;
645
646     if (parse_major_minor (g, fs) == -1)
647       return -1;
648   }
649   else if (guestfs_exists (g, "/etc/slackware-version") > 0) {
650     fs->distro = OS_DISTRO_SLACKWARE;
651
652     if (parse_release_file (g, fs, "/etc/slackware-version") == -1)
653       return -1;
654
655     if (parse_major_minor (g, fs) == -1)
656       return -1;
657   }
658
659  skip_release_checks:;
660
661   /* If distro test above was successful, work out the package format. */
662   check_package_format (g, fs);
663   check_package_management (g, fs);
664
665   /* Determine the architecture. */
666   check_architecture (g, fs);
667
668   /* We already know /etc/fstab exists because it's part of the test
669    * for Linux root above.  We must now parse this file to determine
670    * which filesystems are used by the operating system and how they
671    * are mounted.
672    */
673   if (inspect_with_augeas (g, fs, "/etc/fstab", check_fstab) == -1)
674     return -1;
675
676   /* Determine hostname. */
677   if (check_hostname_unix (g, fs) == -1)
678     return -1;
679
680   return 0;
681 }
682
683 /* The currently mounted device is known to be a FreeBSD root. */
684 static int
685 check_freebsd_root (guestfs_h *g, struct inspect_fs *fs)
686 {
687   fs->type = OS_TYPE_FREEBSD;
688
689   /* FreeBSD has no authoritative version file.  The version number is
690    * in /etc/motd, which the system administrator might edit, but
691    * we'll use that anyway.
692    */
693
694   if (guestfs_exists (g, "/etc/motd") > 0) {
695     if (parse_release_file (g, fs, "/etc/motd") == -1)
696       return -1;
697
698     if (parse_major_minor (g, fs) == -1)
699       return -1;
700   }
701
702   /* Determine the architecture. */
703   check_architecture (g, fs);
704
705   /* We already know /etc/fstab exists because it's part of the test above. */
706   if (inspect_with_augeas (g, fs, "/etc/fstab", check_fstab) == -1)
707     return -1;
708
709   /* Determine hostname. */
710   if (check_hostname_unix (g, fs) == -1)
711     return -1;
712
713   return 0;
714 }
715
716 /* Debian/Ubuntu install disks are easy ...
717  *
718  * These files are added by the debian-cd program, and it is worth
719  * looking at the source code to determine exact values, in
720  * particular '/usr/share/debian-cd/tools/start_new_disc'
721  *
722  * XXX Architecture?  We could parse it out of the product name
723  * string, but that seems quite hairy.  We could look for the names
724  * of packages.  Also note that some Debian install disks are
725  * multiarch.
726  */
727 static int
728 check_debian_installer_root (guestfs_h *g, struct inspect_fs *fs)
729 {
730   fs->product_name = first_line_of_file (g, "/.disk/info");
731   if (!fs->product_name)
732     return -1;
733
734   fs->type = OS_TYPE_LINUX;
735   if (STRPREFIX (fs->product_name, "Ubuntu"))
736     fs->distro = OS_DISTRO_UBUNTU;
737   else if (STRPREFIX (fs->product_name, "Debian"))
738     fs->distro = OS_DISTRO_DEBIAN;
739
740   (void) parse_major_minor (g, fs);
741
742   if (guestfs_is_file (g, "/.disk/cd_type") > 0) {
743     char *cd_type = first_line_of_file (g, "/.disk/cd_type");
744     if (!cd_type)
745       return -1;
746
747     if (STRPREFIX (cd_type, "dvd/single") ||
748         STRPREFIX (cd_type, "full_cd/single")) {
749       fs->is_multipart_disk = 0;
750       fs->is_netinst_disk = 0;
751     }
752     else if (STRPREFIX (cd_type, "dvd") ||
753              STRPREFIX (cd_type, "full_cd")) {
754       fs->is_multipart_disk = 1;
755       fs->is_netinst_disk = 0;
756     }
757     else if (STRPREFIX (cd_type, "not_complete")) {
758       fs->is_multipart_disk = 0;
759       fs->is_netinst_disk = 1;
760     }
761
762     free (cd_type);
763   }
764
765   return 0;
766 }
767
768 /* Take string which must look like "key = value" and find the value.
769  * There may or may not be spaces before and after the equals sign.
770  * This function is used by both check_fedora_installer_root and
771  * check_w2k3_installer_root.
772  */
773 static const char *
774 find_value (const char *kv)
775 {
776   const char *p;
777
778   p = strchr (kv, '=');
779   if (!p)
780     abort ();
781
782   do {
783     ++p;
784   } while (c_isspace (*p));
785
786   return p;
787 }
788
789 /* Fedora CDs and DVD (not netinst).  The /.treeinfo file contains
790  * an initial section somewhat like this:
791  *
792  * [general]
793  * version = 14
794  * arch = x86_64
795  * family = Fedora
796  * variant = Fedora
797  * discnum = 1
798  * totaldiscs = 1
799  */
800 static int
801 check_fedora_installer_root (guestfs_h *g, struct inspect_fs *fs)
802 {
803   char *str;
804   const char *v;
805   int r;
806   int discnum = 0, totaldiscs = 0;
807
808   fs->type = OS_TYPE_LINUX;
809
810   r = first_egrep_of_file (g, "/.treeinfo",
811                            "^family = Fedora$", 0, &str);
812   if (r == -1)
813     return -1;
814   if (r > 0) {
815     fs->distro = OS_DISTRO_FEDORA;
816     free (str);
817   }
818
819   r = first_egrep_of_file (g, "/.treeinfo",
820                            "^family = Red Hat Enterprise Linux$", 0, &str);
821   if (r == -1)
822     return -1;
823   if (r > 0) {
824     fs->distro = OS_DISTRO_RHEL;
825     free (str);
826   }
827
828   /* XXX should do major.minor before this */
829   r = first_egrep_of_file (g, "/.treeinfo",
830                            "^version = [[:digit:]]+", 0, &str);
831   if (r == -1)
832     return -1;
833   if (r > 0) {
834     v = find_value (str);
835     fs->major_version = parse_unsigned_int_ignore_trailing (g, v);
836     free (str);
837     if (fs->major_version == -1)
838       return -1;
839   }
840
841   r = first_egrep_of_file (g, "/.treeinfo",
842                            "^arch = [-_[:alnum:]]+$", 0, &str);
843   if (r == -1)
844     return -1;
845   if (r > 0) {
846     v = find_value (str);
847     fs->arch = safe_strdup (g, v);
848     free (str);
849   }
850
851   r = first_egrep_of_file (g, "/.treeinfo",
852                            "^discnum = [[:digit:]]+$", 0, &str);
853   if (r == -1)
854     return -1;
855   if (r > 0) {
856     v = find_value (str);
857     discnum = parse_unsigned_int (g, v);
858     free (str);
859     if (discnum == -1)
860       return -1;
861   }
862
863   r = first_egrep_of_file (g, "/.treeinfo",
864                            "^totaldiscs = [[:digit:]]+$", 0, &str);
865   if (r == -1)
866     return -1;
867   if (r > 0) {
868     v = find_value (str);
869     totaldiscs = parse_unsigned_int (g, v);
870     free (str);
871     if (totaldiscs == -1)
872       return -1;
873   }
874
875   fs->is_multipart_disk = totaldiscs > 0;
876   /* and what about discnum? */
877
878   return 0;
879 }
880
881 /* Linux with /isolinux/isolinux.cfg.
882  *
883  * This file is not easily parsable so we have to do our best.
884  * Look for the "menu title" line which contains:
885  *   menu title Welcome to Fedora 14!   # since at least Fedora 10
886  *   menu title Welcome to Red Hat Enterprise Linux 6.0!
887  */
888 static int
889 check_isolinux_installer_root (guestfs_h *g, struct inspect_fs *fs)
890 {
891   char *str;
892   int r;
893
894   fs->type = OS_TYPE_LINUX;
895
896   r = first_egrep_of_file (g, "/isolinux/isolinux.cfg",
897                            "^menu title Welcome to Fedora [[:digit:]]+",
898                            0, &str);
899   if (r == -1)
900     return -1;
901   if (r > 0) {
902     fs->distro = OS_DISTRO_FEDORA;
903     fs->major_version = parse_unsigned_int_ignore_trailing (g, &str[29]);
904     free (str);
905     if (fs->major_version == -1)
906       return -1;
907   }
908
909   /* XXX parse major.minor */
910   r = first_egrep_of_file (g, "/isolinux/isolinux.cfg",
911                            "^menu title Welcome to Red Hat Enterprise Linux [[:digit:]]+",
912                            0, &str);
913   if (r == -1)
914     return -1;
915   if (r > 0) {
916     fs->distro = OS_DISTRO_RHEL;
917     fs->major_version = parse_unsigned_int_ignore_trailing (g, &str[47]);
918     free (str);
919     if (fs->major_version == -1)
920       return -1;
921   }
922
923   return 0;
924 }
925
926 /* Windows 2003 and similar versions.
927  *
928  * NB: txtsetup file contains Windows \r\n line endings, which guestfs_grep
929  * does not remove.  We have to remove them by hand here.
930  */
931 static void
932 trim_cr (char *str)
933 {
934   size_t n = strlen (str);
935   if (n > 0 && str[n-1] == '\r')
936     str[n-1] = '\0';
937 }
938
939 static void
940 trim_quot (char *str)
941 {
942   size_t n = strlen (str);
943   if (n > 0 && str[n-1] == '"')
944     str[n-1] = '\0';
945 }
946
947 static int
948 check_w2k3_installer_root (guestfs_h *g, struct inspect_fs *fs,
949                            const char *txtsetup)
950 {
951   char *str;
952   const char *v;
953   int r;
954
955   fs->type = OS_TYPE_WINDOWS;
956   fs->distro = OS_DISTRO_WINDOWS;
957
958   r = first_egrep_of_file (g, txtsetup,
959                            "^productname[[:space:]]*=[[:space:]]*\"", 1, &str);
960   if (r == -1)
961     return -1;
962   if (r > 0) {
963     trim_cr (str);
964     trim_quot (str);
965     v = find_value (str);
966     fs->product_name = safe_strdup (g, v+1);
967     free (str);
968   }
969
970   r = first_egrep_of_file (g, txtsetup,
971                            "^majorversion[[:space:]]*=[[:space:]]*[[:digit:]]+",
972                            1, &str);
973   if (r == -1)
974     return -1;
975   if (r > 0) {
976     trim_cr (str);
977     v = find_value (str);
978     fs->major_version = parse_unsigned_int_ignore_trailing (g, v);
979     free (str);
980     if (fs->major_version == -1)
981       return -1;
982   }
983
984   r = first_egrep_of_file (g, txtsetup,
985                            "^minorversion[[:space:]]*=[[:space:]]*[[:digit:]]+",
986                            1, &str);
987   if (r == -1)
988     return -1;
989   if (r > 0) {
990     trim_cr (str);
991     v = find_value (str);
992     fs->minor_version = parse_unsigned_int_ignore_trailing (g, v);
993     free (str);
994     if (fs->minor_version == -1)
995       return -1;
996   }
997
998   /* This is the windows systemroot that would be chosen on
999    * installation by default, although not necessarily the one that
1000    * the user will finally choose.
1001    */
1002   r = first_egrep_of_file (g, txtsetup, "^defaultpath[[:space:]]*=[[:space:]]*",
1003                            1, &str);
1004   if (r == -1)
1005     return -1;
1006   if (r > 0) {
1007     trim_cr (str);
1008     v = find_value (str);
1009     fs->windows_systemroot = safe_strdup (g, v);
1010     free (str);
1011   }
1012
1013   return 0;
1014 }
1015
1016 /* The currently mounted device is very likely to be an installer. */
1017 static int
1018 check_installer_root (guestfs_h *g, struct inspect_fs *fs)
1019 {
1020   /* The presence of certain files indicates a live CD.
1021    *
1022    * XXX Fedora netinst contains a ~120MB squashfs called
1023    * /images/install.img.  However this is not a live CD (unlike the
1024    * Fedora live CDs which contain the same, but larger file).  We
1025    * need to unpack this and look inside to tell the difference.
1026    */
1027   if (guestfs_is_file (g, "/casper/filesystem.squashfs") > 0)
1028     fs->is_live_disk = 1;
1029
1030   /* Debian/Ubuntu. */
1031   if (guestfs_is_file (g, "/.disk/info") > 0) {
1032     if (check_debian_installer_root (g, fs) == -1)
1033       return -1;
1034   }
1035
1036   /* Fedora CDs and DVD (not netinst). */
1037   else if (guestfs_is_file (g, "/.treeinfo") > 0) {
1038     if (check_fedora_installer_root (g, fs) == -1)
1039       return -1;
1040   }
1041
1042   /* Linux with /isolinux/isolinux.cfg. */
1043   else if (guestfs_is_file (g, "/isolinux/isolinux.cfg") > 0) {
1044     if (check_isolinux_installer_root (g, fs) == -1)
1045       return -1;
1046   }
1047
1048   /* Windows 2003 64 bit */
1049   else if (guestfs_is_file (g, "/amd64/txtsetup.sif") > 0) {
1050     fs->arch = safe_strdup (g, "x86_64");
1051     if (check_w2k3_installer_root (g, fs, "/amd64/txtsetup.sif") == -1)
1052       return -1;
1053   }
1054
1055   /* Windows 2003 32 bit */
1056   else if (guestfs_is_file (g, "/i386/txtsetup.sif") > 0) {
1057     fs->arch = safe_strdup (g, "i386");
1058     if (check_w2k3_installer_root (g, fs, "/i386/txtsetup.sif") == -1)
1059       return -1;
1060   }
1061
1062   return 0;
1063 }
1064
1065 static void
1066 check_architecture (guestfs_h *g, struct inspect_fs *fs)
1067 {
1068   const char *binaries[] =
1069     { "/bin/bash", "/bin/ls", "/bin/echo", "/bin/rm", "/bin/sh" };
1070   size_t i;
1071
1072   for (i = 0; i < sizeof binaries / sizeof binaries[0]; ++i) {
1073     if (guestfs_is_file (g, binaries[i]) > 0) {
1074       /* Ignore errors from file_architecture call. */
1075       guestfs_error_handler_cb old_error_cb = g->error_cb;
1076       g->error_cb = NULL;
1077       char *arch = guestfs_file_architecture (g, binaries[i]);
1078       g->error_cb = old_error_cb;
1079
1080       if (arch) {
1081         /* String will be owned by handle, freed by
1082          * guestfs___free_inspect_info.
1083          */
1084         fs->arch = arch;
1085         break;
1086       }
1087     }
1088   }
1089 }
1090
1091 /* Try several methods to determine the hostname from a Linux or
1092  * FreeBSD guest.  Note that type and distro have been set, so we can
1093  * use that information to direct the search.
1094  */
1095 static int
1096 check_hostname_unix (guestfs_h *g, struct inspect_fs *fs)
1097 {
1098   switch (fs->type) {
1099   case OS_TYPE_LINUX:
1100     /* Red Hat-derived would be in /etc/sysconfig/network, and
1101      * Debian-derived in the file /etc/hostname.  Very old Debian and
1102      * SUSE use /etc/HOSTNAME.  It's best to just look for each of
1103      * these files in turn, rather than try anything clever based on
1104      * distro.
1105      */
1106     if (guestfs_is_file (g, "/etc/HOSTNAME")) {
1107       fs->hostname = first_line_of_file (g, "/etc/HOSTNAME");
1108       if (fs->hostname == NULL)
1109         return -1;
1110     }
1111     else if (guestfs_is_file (g, "/etc/hostname")) {
1112       fs->hostname = first_line_of_file (g, "/etc/hostname");
1113       if (fs->hostname == NULL)
1114         return -1;
1115     }
1116     else if (guestfs_is_file (g, "/etc/sysconfig/network")) {
1117       if (inspect_with_augeas (g, fs, "/etc/sysconfig/network",
1118                                check_hostname_redhat) == -1)
1119         return -1;
1120     }
1121     break;
1122
1123   case OS_TYPE_FREEBSD:
1124     /* /etc/rc.conf contains the hostname, but there is no Augeas lens
1125      * for this file.
1126      */
1127     if (guestfs_is_file (g, "/etc/rc.conf")) {
1128       if (check_hostname_freebsd (g, fs) == -1)
1129         return -1;
1130     }
1131     break;
1132
1133   case OS_TYPE_WINDOWS: /* not here, see check_windows_system_registry */
1134   case OS_TYPE_UNKNOWN:
1135   default:
1136     /* nothing, keep GCC warnings happy */;
1137   }
1138
1139   return 0;
1140 }
1141
1142 /* Parse the hostname from /etc/sysconfig/network.  This must be called
1143  * from the inspect_with_augeas wrapper.
1144  */
1145 static int
1146 check_hostname_redhat (guestfs_h *g, struct inspect_fs *fs)
1147 {
1148   char *hostname;
1149
1150   hostname = guestfs_aug_get (g, "/files/etc/sysconfig/network/HOSTNAME");
1151   if (!hostname)
1152     return -1;
1153
1154   fs->hostname = hostname;  /* freed by guestfs___free_inspect_info */
1155   return 0;
1156 }
1157
1158 /* Parse the hostname from /etc/rc.conf.  On FreeBSD this file
1159  * contains comments, blank lines and:
1160  *   hostname="freebsd8.example.com"
1161  *   ifconfig_re0="DHCP"
1162  *   keymap="uk.iso"
1163  *   sshd_enable="YES"
1164  */
1165 static int
1166 check_hostname_freebsd (guestfs_h *g, struct inspect_fs *fs)
1167 {
1168   const char *filename = "/etc/rc.conf";
1169   int64_t size;
1170   char **lines;
1171   size_t i;
1172
1173   /* Don't trust guestfs_read_lines not to break with very large files.
1174    * Check the file size is something reasonable first.
1175    */
1176   size = guestfs_filesize (g, filename);
1177   if (size == -1)
1178     /* guestfs_filesize failed and has already set error in handle */
1179     return -1;
1180   if (size > MAX_SMALL_FILE_SIZE) {
1181     error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
1182            filename, size);
1183     return -1;
1184   }
1185
1186   lines = guestfs_read_lines (g, filename);
1187   if (lines == NULL)
1188     return -1;
1189
1190   for (i = 0; lines[i] != NULL; ++i) {
1191     if (STRPREFIX (lines[i], "hostname=\"") ||
1192         STRPREFIX (lines[i], "hostname='")) {
1193       size_t len = strlen (lines[i]) - 10 - 1;
1194       fs->hostname = safe_strndup (g, &lines[i][10], len);
1195       break;
1196     } else if (STRPREFIX (lines[i], "hostname=")) {
1197       size_t len = strlen (lines[i]) - 9;
1198       fs->hostname = safe_strndup (g, &lines[i][9], len);
1199       break;
1200     }
1201   }
1202
1203   guestfs___free_string_list (lines);
1204   return 0;
1205 }
1206
1207 static int
1208 check_fstab (guestfs_h *g, struct inspect_fs *fs)
1209 {
1210   char **lines = guestfs_aug_ls (g, "/files/etc/fstab");
1211   if (lines == NULL)
1212     return -1;
1213
1214   if (lines[0] == NULL) {
1215     error (g, _("could not parse /etc/fstab or empty file"));
1216     guestfs___free_string_list (lines);
1217     return -1;
1218   }
1219
1220   size_t i;
1221   char augpath[256];
1222   for (i = 0; lines[i] != NULL; ++i) {
1223     /* Ignore comments.  Only care about sequence lines which
1224      * match m{/\d+$}.
1225      */
1226     if (match (g, lines[i], re_aug_seq)) {
1227       snprintf (augpath, sizeof augpath, "%s/spec", lines[i]);
1228       char *spec = guestfs_aug_get (g, augpath);
1229       if (spec == NULL) {
1230         guestfs___free_string_list (lines);
1231         return -1;
1232       }
1233
1234       snprintf (augpath, sizeof augpath, "%s/file", lines[i]);
1235       char *mp = guestfs_aug_get (g, augpath);
1236       if (mp == NULL) {
1237         guestfs___free_string_list (lines);
1238         free (spec);
1239         return -1;
1240       }
1241
1242       int r = add_fstab_entry (g, fs, spec, mp);
1243       free (spec);
1244       free (mp);
1245
1246       if (r == -1) {
1247         guestfs___free_string_list (lines);
1248         return -1;
1249       }
1250     }
1251   }
1252
1253   guestfs___free_string_list (lines);
1254   return 0;
1255 }
1256
1257 /* Add a filesystem and possibly a mountpoint entry for
1258  * the root filesystem 'fs'.
1259  *
1260  * 'spec' is the fstab spec field, which might be a device name or a
1261  * pseudodevice or 'UUID=...' or 'LABEL=...'.
1262  *
1263  * 'mp' is the mount point, which could also be 'swap' or 'none'.
1264  */
1265 static int
1266 add_fstab_entry (guestfs_h *g, struct inspect_fs *fs,
1267                  const char *spec, const char *mp)
1268 {
1269   /* Ignore certain mountpoints. */
1270   if (STRPREFIX (mp, "/dev/") ||
1271       STREQ (mp, "/dev") ||
1272       STRPREFIX (mp, "/media/") ||
1273       STRPREFIX (mp, "/proc/") ||
1274       STREQ (mp, "/proc") ||
1275       STRPREFIX (mp, "/selinux/") ||
1276       STREQ (mp, "/selinux") ||
1277       STRPREFIX (mp, "/sys/") ||
1278       STREQ (mp, "/sys"))
1279     return 0;
1280
1281   /* Ignore /dev/fd (floppy disks) (RHBZ#642929) and CD-ROM drives. */
1282   if ((STRPREFIX (spec, "/dev/fd") && c_isdigit (spec[7])) ||
1283       STREQ (spec, "/dev/floppy") ||
1284       STREQ (spec, "/dev/cdrom"))
1285     return 0;
1286
1287   /* Resolve UUID= and LABEL= to the actual device. */
1288   char *device = NULL;
1289   if (STRPREFIX (spec, "UUID="))
1290     device = guestfs_findfs_uuid (g, &spec[5]);
1291   else if (STRPREFIX (spec, "LABEL="))
1292     device = guestfs_findfs_label (g, &spec[6]);
1293   /* Ignore "/.swap" (Pardus) and pseudo-devices like "tmpfs". */
1294   else if (STRPREFIX (spec, "/dev/"))
1295     /* Resolve guest block device names. */
1296     device = resolve_fstab_device (g, spec);
1297
1298   /* If we haven't resolved the device successfully by this point,
1299    * we don't care, just ignore it.
1300    */
1301   if (device == NULL)
1302     return 0;
1303
1304   char *mountpoint = safe_strdup (g, mp);
1305
1306   /* Add this to the fstab entry in 'fs'.
1307    * Note these are further filtered by guestfs_inspect_get_mountpoints
1308    * and guestfs_inspect_get_filesystems.
1309    */
1310   size_t n = fs->nr_fstab + 1;
1311   struct inspect_fstab_entry *p;
1312
1313   p = realloc (fs->fstab, n * sizeof (struct inspect_fstab_entry));
1314   if (p == NULL) {
1315     perrorf (g, "realloc");
1316     free (device);
1317     free (mountpoint);
1318     return -1;
1319   }
1320
1321   fs->fstab = p;
1322   fs->nr_fstab = n;
1323
1324   /* These are owned by the handle and freed by guestfs___free_inspect_info. */
1325   fs->fstab[n-1].device = device;
1326   fs->fstab[n-1].mountpoint = mountpoint;
1327
1328   debug (g, "fstab: device=%s mountpoint=%s", device, mountpoint);
1329
1330   return 0;
1331 }
1332
1333 /* Resolve block device name to the libguestfs device name, eg.
1334  * /dev/xvdb1 => /dev/vdb1; and /dev/mapper/VG-LV => /dev/VG/LV.  This
1335  * assumes that disks were added in the same order as they appear to
1336  * the real VM, which is a reasonable assumption to make.  Return
1337  * anything we don't recognize unchanged.
1338  */
1339 static char *
1340 resolve_fstab_device (guestfs_h *g, const char *spec)
1341 {
1342   char *a1;
1343   char *device = NULL;
1344   char *bsddisk, *bsdslice, *bsdpart;
1345
1346   if (STRPREFIX (spec, "/dev/mapper/")) {
1347     /* LVM2 does some strange munging on /dev/mapper paths for VGs and
1348      * LVs which contain '-' character:
1349      *
1350      * ><fs> lvcreate LV--test VG--test 32
1351      * ><fs> debug ls /dev/mapper
1352      * VG----test-LV----test
1353      *
1354      * This makes it impossible to reverse those paths directly, so
1355      * we have implemented lvm_canonical_lv_name in the daemon.
1356      */
1357     device = guestfs_lvm_canonical_lv_name (g, spec);
1358   }
1359   else if ((a1 = match1 (g, spec, re_xdev)) != NULL) {
1360     char **devices = guestfs_list_devices (g);
1361     if (devices == NULL)
1362       return NULL;
1363
1364     size_t count;
1365     for (count = 0; devices[count] != NULL; count++)
1366       ;
1367
1368     size_t i = a1[0] - 'a'; /* a1[0] is always [a-z] because of regex. */
1369     if (i < count) {
1370       size_t len = strlen (devices[i]) + strlen (a1) + 16;
1371       device = safe_malloc (g, len);
1372       snprintf (device, len, "%s%s", devices[i], &a1[1]);
1373     }
1374
1375     free (a1);
1376     guestfs___free_string_list (devices);
1377   }
1378   else if (match3 (g, spec, re_freebsd, &bsddisk, &bsdslice, &bsdpart)) {
1379     /* FreeBSD disks are organized quite differently.  See:
1380      * http://www.freebsd.org/doc/handbook/disk-organization.html
1381      * FreeBSD "partitions" are exposed as quasi-extended partitions
1382      * numbered from 5 in Linux.  I have no idea what happens when you
1383      * have multiple "slices" (the FreeBSD term for MBR partitions).
1384      */
1385     int disk = parse_unsigned_int (g, bsddisk);
1386     int slice = parse_unsigned_int (g, bsdslice);
1387     int part = bsdpart[0] - 'a' /* counting from 0 */;
1388     free (bsddisk);
1389     free (bsdslice);
1390     free (bsdpart);
1391
1392     if (disk == -1 || disk > 26 ||
1393         slice <= 0 || slice > 1 /* > 4 .. see comment above */ ||
1394         part < 0 || part >= 26)
1395       goto out;
1396
1397     device = safe_asprintf (g, "/dev/sd%c%d", disk + 'a', part + 5);
1398   }
1399
1400  out:
1401   /* Didn't match device pattern, return original spec unchanged. */
1402   if (device == NULL)
1403     device = safe_strdup (g, spec);
1404
1405   return device;
1406 }
1407
1408 /* XXX Handling of boot.ini in the Perl version was pretty broken.  It
1409  * essentially didn't do anything for modern Windows guests.
1410  * Therefore I've omitted all that code.
1411  */
1412 static int
1413 check_windows_root (guestfs_h *g, struct inspect_fs *fs)
1414 {
1415   fs->type = OS_TYPE_WINDOWS;
1416   fs->distro = OS_DISTRO_WINDOWS;
1417
1418   /* Try to find Windows systemroot using some common locations. */
1419   const char *systemroots[] =
1420     { "/windows", "/winnt", "/win32", "/win" };
1421   size_t i;
1422   char *systemroot = NULL;
1423   for (i = 0;
1424        systemroot == NULL && i < sizeof systemroots / sizeof systemroots[0];
1425        ++i) {
1426     systemroot = case_sensitive_path_silently (g, systemroots[i]);
1427   }
1428
1429   if (!systemroot) {
1430     error (g, _("cannot resolve Windows %%SYSTEMROOT%%"));
1431     return -1;
1432   }
1433
1434   debug (g, "windows %%SYSTEMROOT%% = %s", systemroot);
1435
1436   /* Freed by guestfs___free_inspect_info. */
1437   fs->windows_systemroot = systemroot;
1438
1439   if (check_windows_arch (g, fs) == -1)
1440     return -1;
1441
1442   /* Product name and version. */
1443   if (check_windows_software_registry (g, fs) == -1)
1444     return -1;
1445
1446   check_package_format (g, fs);
1447   check_package_management (g, fs);
1448
1449   /* Hostname. */
1450   if (check_windows_system_registry (g, fs) == -1)
1451     return -1;
1452
1453   return 0;
1454 }
1455
1456 static int
1457 check_windows_arch (guestfs_h *g, struct inspect_fs *fs)
1458 {
1459   size_t len = strlen (fs->windows_systemroot) + 32;
1460   char cmd_exe[len];
1461   snprintf (cmd_exe, len, "%s/system32/cmd.exe", fs->windows_systemroot);
1462
1463   char *cmd_exe_path = case_sensitive_path_silently (g, cmd_exe);
1464   if (!cmd_exe_path)
1465     return 0;
1466
1467   char *arch = guestfs_file_architecture (g, cmd_exe_path);
1468   free (cmd_exe_path);
1469
1470   if (arch)
1471     fs->arch = arch;        /* freed by guestfs___free_inspect_info */
1472
1473   return 0;
1474 }
1475
1476 /* At the moment, pull just the ProductName and version numbers from
1477  * the registry.  In future there is a case for making many more
1478  * registry fields available to callers.
1479  */
1480 static int
1481 check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs)
1482 {
1483   TMP_TEMPLATE_ON_STACK (software_local);
1484
1485   size_t len = strlen (fs->windows_systemroot) + 64;
1486   char software[len];
1487   snprintf (software, len, "%s/system32/config/software",
1488             fs->windows_systemroot);
1489
1490   char *software_path = case_sensitive_path_silently (g, software);
1491   if (!software_path)
1492     /* If the software hive doesn't exist, just accept that we cannot
1493      * find product_name etc.
1494      */
1495     return 0;
1496
1497   int ret = -1;
1498   hive_h *h = NULL;
1499   hive_value_h *values = NULL;
1500
1501   if (download_to_tmp (g, software_path, software_local,
1502                        MAX_REGISTRY_SIZE) == -1)
1503     goto out;
1504
1505   h = hivex_open (software_local, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
1506   if (h == NULL) {
1507     perrorf (g, "hivex_open");
1508     goto out;
1509   }
1510
1511   hive_node_h node = hivex_root (h);
1512   const char *hivepath[] =
1513     { "Microsoft", "Windows NT", "CurrentVersion" };
1514   size_t i;
1515   for (i = 0;
1516        node != 0 && i < sizeof hivepath / sizeof hivepath[0];
1517        ++i) {
1518     node = hivex_node_get_child (h, node, hivepath[i]);
1519   }
1520
1521   if (node == 0) {
1522     perrorf (g, "hivex: cannot locate HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
1523     goto out;
1524   }
1525
1526   values = hivex_node_values (h, node);
1527
1528   for (i = 0; values[i] != 0; ++i) {
1529     char *key = hivex_value_key (h, values[i]);
1530     if (key == NULL) {
1531       perrorf (g, "hivex_value_key");
1532       goto out;
1533     }
1534
1535     if (STRCASEEQ (key, "ProductName")) {
1536       fs->product_name = hivex_value_string (h, values[i]);
1537       if (!fs->product_name) {
1538         perrorf (g, "hivex_value_string");
1539         free (key);
1540         goto out;
1541       }
1542     }
1543     else if (STRCASEEQ (key, "CurrentVersion")) {
1544       char *version = hivex_value_string (h, values[i]);
1545       if (!version) {
1546         perrorf (g, "hivex_value_string");
1547         free (key);
1548         goto out;
1549       }
1550       char *major, *minor;
1551       if (match2 (g, version, re_windows_version, &major, &minor)) {
1552         fs->major_version = parse_unsigned_int (g, major);
1553         free (major);
1554         if (fs->major_version == -1) {
1555           free (minor);
1556           free (key);
1557           free (version);
1558           goto out;
1559         }
1560         fs->minor_version = parse_unsigned_int (g, minor);
1561         free (minor);
1562         if (fs->minor_version == -1) {
1563           free (key);
1564           free (version);
1565           goto out;
1566         }
1567       }
1568
1569       free (version);
1570     }
1571     else if (STRCASEEQ (key, "InstallationType")) {
1572       fs->product_variant = hivex_value_string (h, values[i]);
1573       if (!fs->product_variant) {
1574         perrorf (g, "hivex_value_string");
1575         free (key);
1576         goto out;
1577       }
1578     }
1579
1580     free (key);
1581   }
1582
1583   ret = 0;
1584
1585  out:
1586   if (h) hivex_close (h);
1587   free (values);
1588   free (software_path);
1589
1590   /* Free up the temporary file. */
1591   unlink (software_local);
1592 #undef software_local_len
1593
1594   return ret;
1595 }
1596
1597 static int
1598 check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
1599 {
1600   TMP_TEMPLATE_ON_STACK (system_local);
1601
1602   size_t len = strlen (fs->windows_systemroot) + 64;
1603   char system[len];
1604   snprintf (system, len, "%s/system32/config/system",
1605             fs->windows_systemroot);
1606
1607   char *system_path = case_sensitive_path_silently (g, system);
1608   if (!system_path)
1609     /* If the system hive doesn't exist, just accept that we cannot
1610      * find hostname etc.
1611      */
1612     return 0;
1613
1614   int ret = -1;
1615   hive_h *h = NULL;
1616   hive_node_h root, node;
1617   hive_value_h value, *values = NULL;
1618   int32_t dword;
1619   size_t i;
1620
1621   if (download_to_tmp (g, system_path, system_local, MAX_REGISTRY_SIZE) == -1)
1622     goto out;
1623
1624   h = hivex_open (system_local, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
1625   if (h == NULL) {
1626     perrorf (g, "hivex_open");
1627     goto out;
1628   }
1629
1630   root = hivex_root (h);
1631   if (root == 0) {
1632     perrorf (g, "hivex_root");
1633     goto out;
1634   }
1635
1636   /* Get the CurrentControlSet. */
1637   errno = 0;
1638   node = hivex_node_get_child (h, root, "Select");
1639   if (node == 0) {
1640     if (errno != 0)
1641       perrorf (g, "hivex_node_get_child");
1642     else
1643       error (g, "hivex: could not locate HKLM\\SYSTEM\\Select");
1644     goto out;
1645   }
1646
1647   errno = 0;
1648   value = hivex_node_get_value (h, node, "Current");
1649   if (value == 0) {
1650     if (errno != 0)
1651       perrorf (g, "hivex_node_get_value");
1652     else
1653       error (g, "hivex: HKLM\\System\\Select Default entry not found.");
1654     goto out;
1655   }
1656
1657   /* XXX Should check the type. */
1658   dword = hivex_value_dword (h, value);
1659   fs->windows_current_control_set = safe_asprintf (g, "ControlSet%03d", dword);
1660
1661   /* Get the hostname. */
1662   const char *hivepath[] =
1663     { fs->windows_current_control_set, "Services", "Tcpip", "Parameters" };
1664   for (node = root, i = 0;
1665        node != 0 && i < sizeof hivepath / sizeof hivepath[0];
1666        ++i) {
1667     node = hivex_node_get_child (h, node, hivepath[i]);
1668   }
1669
1670   if (node == 0) {
1671     perrorf (g, "hivex: cannot locate HKLM\\SYSTEM\\%s\\Services\\Tcpip\\Parameters",
1672              fs->windows_current_control_set);
1673     goto out;
1674   }
1675
1676   values = hivex_node_values (h, node);
1677
1678   for (i = 0; values[i] != 0; ++i) {
1679     char *key = hivex_value_key (h, values[i]);
1680     if (key == NULL) {
1681       perrorf (g, "hivex_value_key");
1682       goto out;
1683     }
1684
1685     if (STRCASEEQ (key, "Hostname")) {
1686       fs->hostname = hivex_value_string (h, values[i]);
1687       if (!fs->hostname) {
1688         perrorf (g, "hivex_value_string");
1689         free (key);
1690         goto out;
1691       }
1692     }
1693     /* many other interesting fields here ... */
1694
1695     free (key);
1696   }
1697
1698   ret = 0;
1699
1700  out:
1701   if (h) hivex_close (h);
1702   free (values);
1703   free (system_path);
1704
1705   /* Free up the temporary file. */
1706   unlink (system_local);
1707 #undef system_local_len
1708
1709   return ret;
1710 }
1711
1712 static char *
1713 case_sensitive_path_silently (guestfs_h *g, const char *path)
1714 {
1715   guestfs_error_handler_cb old_error_cb = g->error_cb;
1716   g->error_cb = NULL;
1717   char *ret = guestfs_case_sensitive_path (g, path);
1718   g->error_cb = old_error_cb;
1719   return ret;
1720 }
1721
1722 static int
1723 is_file_nocase (guestfs_h *g, const char *path)
1724 {
1725   char *p;
1726   int r;
1727
1728   p = case_sensitive_path_silently (g, path);
1729   if (!p)
1730     return 0;
1731   r = guestfs_is_file (g, p);
1732   free (p);
1733   return r > 0;
1734 }
1735
1736 static int
1737 is_dir_nocase (guestfs_h *g, const char *path)
1738 {
1739   char *p;
1740   int r;
1741
1742   p = case_sensitive_path_silently (g, path);
1743   if (!p)
1744     return 0;
1745   r = guestfs_is_dir (g, p);
1746   free (p);
1747   return r > 0;
1748 }
1749
1750 static int
1751 extend_fses (guestfs_h *g)
1752 {
1753   size_t n = g->nr_fses + 1;
1754   struct inspect_fs *p;
1755
1756   p = realloc (g->fses, n * sizeof (struct inspect_fs));
1757   if (p == NULL) {
1758     perrorf (g, "realloc");
1759     return -1;
1760   }
1761
1762   g->fses = p;
1763   g->nr_fses = n;
1764
1765   memset (&g->fses[n-1], 0, sizeof (struct inspect_fs));
1766
1767   return 0;
1768 }
1769
1770 /* Parse small, unsigned ints, as used in version numbers. */
1771 static int
1772 parse_unsigned_int (guestfs_h *g, const char *str)
1773 {
1774   long ret;
1775   int r = xstrtol (str, NULL, 10, &ret, "");
1776   if (r != LONGINT_OK) {
1777     error (g, _("could not parse integer in version number: %s"), str);
1778     return -1;
1779   }
1780   return ret;
1781 }
1782
1783 /* Like parse_unsigned_int, but ignore trailing stuff. */
1784 static int
1785 parse_unsigned_int_ignore_trailing (guestfs_h *g, const char *str)
1786 {
1787   long ret;
1788   int r = xstrtol (str, NULL, 10, &ret, NULL);
1789   if (r != LONGINT_OK) {
1790     error (g, _("could not parse integer in version number: %s"), str);
1791     return -1;
1792   }
1793   return ret;
1794 }
1795
1796 /* At the moment, package format and package management is just a
1797  * simple function of the distro and major_version fields, so these
1798  * can never return an error.  We might be cleverer in future.
1799  */
1800 static void
1801 check_package_format (guestfs_h *g, struct inspect_fs *fs)
1802 {
1803   switch (fs->distro) {
1804   case OS_DISTRO_FEDORA:
1805   case OS_DISTRO_MEEGO:
1806   case OS_DISTRO_REDHAT_BASED:
1807   case OS_DISTRO_RHEL:
1808   case OS_DISTRO_MANDRIVA:
1809     fs->package_format = OS_PACKAGE_FORMAT_RPM;
1810     break;
1811
1812   case OS_DISTRO_DEBIAN:
1813   case OS_DISTRO_UBUNTU:
1814   case OS_DISTRO_LINUX_MINT:
1815     fs->package_format = OS_PACKAGE_FORMAT_DEB;
1816     break;
1817
1818   case OS_DISTRO_ARCHLINUX:
1819     fs->package_format = OS_PACKAGE_FORMAT_PACMAN;
1820     break;
1821   case OS_DISTRO_GENTOO:
1822     fs->package_format = OS_PACKAGE_FORMAT_EBUILD;
1823     break;
1824   case OS_DISTRO_PARDUS:
1825     fs->package_format = OS_PACKAGE_FORMAT_PISI;
1826     break;
1827
1828   case OS_DISTRO_SLACKWARE:
1829   case OS_DISTRO_WINDOWS:
1830   case OS_DISTRO_UNKNOWN:
1831   default:
1832     fs->package_format = OS_PACKAGE_FORMAT_UNKNOWN;
1833     break;
1834   }
1835 }
1836
1837 static void
1838 check_package_management (guestfs_h *g, struct inspect_fs *fs)
1839 {
1840   switch (fs->distro) {
1841   case OS_DISTRO_FEDORA:
1842   case OS_DISTRO_MEEGO:
1843     fs->package_management = OS_PACKAGE_MANAGEMENT_YUM;
1844     break;
1845
1846   case OS_DISTRO_REDHAT_BASED:
1847   case OS_DISTRO_RHEL:
1848     if (fs->major_version >= 5)
1849       fs->package_management = OS_PACKAGE_MANAGEMENT_YUM;
1850     else
1851       fs->package_management = OS_PACKAGE_MANAGEMENT_UP2DATE;
1852     break;
1853
1854   case OS_DISTRO_DEBIAN:
1855   case OS_DISTRO_UBUNTU:
1856   case OS_DISTRO_LINUX_MINT:
1857     fs->package_management = OS_PACKAGE_MANAGEMENT_APT;
1858     break;
1859
1860   case OS_DISTRO_ARCHLINUX:
1861     fs->package_management = OS_PACKAGE_MANAGEMENT_PACMAN;
1862     break;
1863   case OS_DISTRO_GENTOO:
1864     fs->package_management = OS_PACKAGE_MANAGEMENT_PORTAGE;
1865     break;
1866   case OS_DISTRO_PARDUS:
1867     fs->package_management = OS_PACKAGE_MANAGEMENT_PISI;
1868     break;
1869   case OS_DISTRO_MANDRIVA:
1870     fs->package_management = OS_PACKAGE_MANAGEMENT_URPMI;
1871     break;
1872
1873   case OS_DISTRO_SLACKWARE:
1874   case OS_DISTRO_WINDOWS:
1875   case OS_DISTRO_UNKNOWN:
1876   default:
1877     fs->package_management = OS_PACKAGE_MANAGEMENT_UNKNOWN;
1878     break;
1879   }
1880 }
1881
1882 static struct inspect_fs *
1883 search_for_root (guestfs_h *g, const char *root)
1884 {
1885   if (g->nr_fses == 0) {
1886     error (g, _("no inspection data: call guestfs_inspect_os first"));
1887     return NULL;
1888   }
1889
1890   size_t i;
1891   struct inspect_fs *fs;
1892   for (i = 0; i < g->nr_fses; ++i) {
1893     fs = &g->fses[i];
1894     if (fs->is_root && STREQ (root, fs->device))
1895       return fs;
1896   }
1897
1898   error (g, _("%s: root device not found: only call this function with a root device previously returned by guestfs_inspect_os"),
1899          root);
1900   return NULL;
1901 }
1902
1903 char **
1904 guestfs__inspect_get_roots (guestfs_h *g)
1905 {
1906   /* NB. Doesn't matter if g->nr_fses == 0.  We just return an empty
1907    * list in this case.
1908    */
1909
1910   size_t i;
1911   size_t count = 0;
1912   for (i = 0; i < g->nr_fses; ++i)
1913     if (g->fses[i].is_root)
1914       count++;
1915
1916   char **ret = calloc (count+1, sizeof (char *));
1917   if (ret == NULL) {
1918     perrorf (g, "calloc");
1919     return NULL;
1920   }
1921
1922   count = 0;
1923   for (i = 0; i < g->nr_fses; ++i) {
1924     if (g->fses[i].is_root) {
1925       ret[count] = safe_strdup (g, g->fses[i].device);
1926       count++;
1927     }
1928   }
1929   ret[count] = NULL;
1930
1931   return ret;
1932 }
1933
1934 char *
1935 guestfs__inspect_get_type (guestfs_h *g, const char *root)
1936 {
1937   struct inspect_fs *fs = search_for_root (g, root);
1938   if (!fs)
1939     return NULL;
1940
1941   char *ret;
1942   switch (fs->type) {
1943   case OS_TYPE_LINUX: ret = safe_strdup (g, "linux"); break;
1944   case OS_TYPE_WINDOWS: ret = safe_strdup (g, "windows"); break;
1945   case OS_TYPE_FREEBSD: ret = safe_strdup (g, "freebsd"); break;
1946   case OS_TYPE_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break;
1947   }
1948
1949   return ret;
1950 }
1951
1952 char *
1953 guestfs__inspect_get_arch (guestfs_h *g, const char *root)
1954 {
1955   struct inspect_fs *fs = search_for_root (g, root);
1956   if (!fs)
1957     return NULL;
1958
1959   return safe_strdup (g, fs->arch ? : "unknown");
1960 }
1961
1962 char *
1963 guestfs__inspect_get_distro (guestfs_h *g, const char *root)
1964 {
1965   struct inspect_fs *fs = search_for_root (g, root);
1966   if (!fs)
1967     return NULL;
1968
1969   char *ret;
1970   switch (fs->distro) {
1971   case OS_DISTRO_ARCHLINUX: ret = safe_strdup (g, "archlinux"); break;
1972   case OS_DISTRO_DEBIAN: ret = safe_strdup (g, "debian"); break;
1973   case OS_DISTRO_FEDORA: ret = safe_strdup (g, "fedora"); break;
1974   case OS_DISTRO_GENTOO: ret = safe_strdup (g, "gentoo"); break;
1975   case OS_DISTRO_LINUX_MINT: ret = safe_strdup (g, "linuxmint"); break;
1976   case OS_DISTRO_MANDRIVA: ret = safe_strdup (g, "mandriva"); break;
1977   case OS_DISTRO_MEEGO: ret = safe_strdup (g, "meego"); break;
1978   case OS_DISTRO_PARDUS: ret = safe_strdup (g, "pardus"); break;
1979   case OS_DISTRO_REDHAT_BASED: ret = safe_strdup (g, "redhat-based"); break;
1980   case OS_DISTRO_RHEL: ret = safe_strdup (g, "rhel"); break;
1981   case OS_DISTRO_SLACKWARE: ret = safe_strdup (g, "slackware"); break;
1982   case OS_DISTRO_WINDOWS: ret = safe_strdup (g, "windows"); break;
1983   case OS_DISTRO_UBUNTU: ret = safe_strdup (g, "ubuntu"); break;
1984   case OS_DISTRO_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break;
1985   }
1986
1987   return ret;
1988 }
1989
1990 int
1991 guestfs__inspect_get_major_version (guestfs_h *g, const char *root)
1992 {
1993   struct inspect_fs *fs = search_for_root (g, root);
1994   if (!fs)
1995     return -1;
1996
1997   return fs->major_version;
1998 }
1999
2000 int
2001 guestfs__inspect_get_minor_version (guestfs_h *g, const char *root)
2002 {
2003   struct inspect_fs *fs = search_for_root (g, root);
2004   if (!fs)
2005     return -1;
2006
2007   return fs->minor_version;
2008 }
2009
2010 char *
2011 guestfs__inspect_get_product_name (guestfs_h *g, const char *root)
2012 {
2013   struct inspect_fs *fs = search_for_root (g, root);
2014   if (!fs)
2015     return NULL;
2016
2017   return safe_strdup (g, fs->product_name ? : "unknown");
2018 }
2019
2020 char *
2021 guestfs__inspect_get_product_variant (guestfs_h *g, const char *root)
2022 {
2023   struct inspect_fs *fs = search_for_root (g, root);
2024   if (!fs)
2025     return NULL;
2026
2027   return safe_strdup (g, fs->product_variant ? : "unknown");
2028 }
2029
2030 char *
2031 guestfs__inspect_get_windows_systemroot (guestfs_h *g, const char *root)
2032 {
2033   struct inspect_fs *fs = search_for_root (g, root);
2034   if (!fs)
2035     return NULL;
2036
2037   if (!fs->windows_systemroot) {
2038     error (g, _("not a Windows guest, or systemroot could not be determined"));
2039     return NULL;
2040   }
2041
2042   return safe_strdup (g, fs->windows_systemroot);
2043 }
2044
2045 char *
2046 guestfs__inspect_get_windows_current_control_set (guestfs_h *g,
2047                                                   const char *root)
2048 {
2049   struct inspect_fs *fs = search_for_root (g, root);
2050   if (!fs)
2051     return NULL;
2052
2053   if (!fs->windows_current_control_set) {
2054     error (g, _("not a Windows guest, or CurrentControlSet could not be determined"));
2055     return NULL;
2056   }
2057
2058   return safe_strdup (g, fs->windows_current_control_set);
2059 }
2060
2061 char *
2062 guestfs__inspect_get_format (guestfs_h *g, const char *root)
2063 {
2064   struct inspect_fs *fs = search_for_root (g, root);
2065   if (!fs)
2066     return NULL;
2067
2068   char *ret;
2069   switch (fs->format) {
2070   case OS_FORMAT_INSTALLED: ret = safe_strdup (g, "installed"); break;
2071   case OS_FORMAT_INSTALLER: ret = safe_strdup (g, "installer"); break;
2072   case OS_FORMAT_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break;
2073   }
2074
2075   return ret;
2076 }
2077
2078 int
2079 guestfs__inspect_is_live (guestfs_h *g, const char *root)
2080 {
2081   struct inspect_fs *fs = search_for_root (g, root);
2082   if (!fs)
2083     return -1;
2084
2085   return fs->is_live_disk;
2086 }
2087
2088 int
2089 guestfs__inspect_is_netinst (guestfs_h *g, const char *root)
2090 {
2091   struct inspect_fs *fs = search_for_root (g, root);
2092   if (!fs)
2093     return -1;
2094
2095   return fs->is_netinst_disk;
2096 }
2097
2098 int
2099 guestfs__inspect_is_multipart (guestfs_h *g, const char *root)
2100 {
2101   struct inspect_fs *fs = search_for_root (g, root);
2102   if (!fs)
2103     return -1;
2104
2105   return fs->is_multipart_disk;
2106 }
2107
2108 char **
2109 guestfs__inspect_get_mountpoints (guestfs_h *g, const char *root)
2110 {
2111   struct inspect_fs *fs = search_for_root (g, root);
2112   if (!fs)
2113     return NULL;
2114
2115   char **ret;
2116
2117   /* If no fstab information (Windows) return just the root. */
2118   if (fs->nr_fstab == 0) {
2119     ret = calloc (3, sizeof (char *));
2120     ret[0] = safe_strdup (g, "/");
2121     ret[1] = safe_strdup (g, root);
2122     ret[2] = NULL;
2123     return ret;
2124   }
2125
2126 #define CRITERION fs->fstab[i].mountpoint[0] == '/'
2127   size_t i, count = 0;
2128   for (i = 0; i < fs->nr_fstab; ++i)
2129     if (CRITERION)
2130       count++;
2131
2132   /* Hashtables have 2N+1 entries. */
2133   ret = calloc (2*count+1, sizeof (char *));
2134   if (ret == NULL) {
2135     perrorf (g, "calloc");
2136     return NULL;
2137   }
2138
2139   count = 0;
2140   for (i = 0; i < fs->nr_fstab; ++i)
2141     if (CRITERION) {
2142       ret[2*count] = safe_strdup (g, fs->fstab[i].mountpoint);
2143       ret[2*count+1] = safe_strdup (g, fs->fstab[i].device);
2144       count++;
2145     }
2146 #undef CRITERION
2147
2148   return ret;
2149 }
2150
2151 char **
2152 guestfs__inspect_get_filesystems (guestfs_h *g, const char *root)
2153 {
2154   struct inspect_fs *fs = search_for_root (g, root);
2155   if (!fs)
2156     return NULL;
2157
2158   char **ret;
2159
2160   /* If no fstab information (Windows) return just the root. */
2161   if (fs->nr_fstab == 0) {
2162     ret = calloc (2, sizeof (char *));
2163     ret[0] = safe_strdup (g, root);
2164     ret[1] = NULL;
2165     return ret;
2166   }
2167
2168   ret = calloc (fs->nr_fstab + 1, sizeof (char *));
2169   if (ret == NULL) {
2170     perrorf (g, "calloc");
2171     return NULL;
2172   }
2173
2174   size_t i;
2175   for (i = 0; i < fs->nr_fstab; ++i)
2176     ret[i] = safe_strdup (g, fs->fstab[i].device);
2177
2178   return ret;
2179 }
2180
2181 char *
2182 guestfs__inspect_get_package_format (guestfs_h *g, const char *root)
2183 {
2184   struct inspect_fs *fs = search_for_root (g, root);
2185   if (!fs)
2186     return NULL;
2187
2188   char *ret;
2189   switch (fs->package_format) {
2190   case OS_PACKAGE_FORMAT_RPM: ret = safe_strdup (g, "rpm"); break;
2191   case OS_PACKAGE_FORMAT_DEB: ret = safe_strdup (g, "deb"); break;
2192   case OS_PACKAGE_FORMAT_PACMAN: ret = safe_strdup (g, "pacman"); break;
2193   case OS_PACKAGE_FORMAT_EBUILD: ret = safe_strdup (g, "ebuild"); break;
2194   case OS_PACKAGE_FORMAT_PISI: ret = safe_strdup (g, "pisi"); break;
2195   case OS_PACKAGE_FORMAT_UNKNOWN:
2196   default:
2197     ret = safe_strdup (g, "unknown");
2198     break;
2199   }
2200
2201   return ret;
2202 }
2203
2204 char *
2205 guestfs__inspect_get_package_management (guestfs_h *g, const char *root)
2206 {
2207   struct inspect_fs *fs = search_for_root (g, root);
2208   if (!fs)
2209     return NULL;
2210
2211   char *ret;
2212   switch (fs->package_management) {
2213   case OS_PACKAGE_MANAGEMENT_YUM: ret = safe_strdup (g, "yum"); break;
2214   case OS_PACKAGE_MANAGEMENT_UP2DATE: ret = safe_strdup (g, "up2date"); break;
2215   case OS_PACKAGE_MANAGEMENT_APT: ret = safe_strdup (g, "apt"); break;
2216   case OS_PACKAGE_MANAGEMENT_PACMAN: ret = safe_strdup (g, "pacman"); break;
2217   case OS_PACKAGE_MANAGEMENT_PORTAGE: ret = safe_strdup (g, "portage"); break;
2218   case OS_PACKAGE_MANAGEMENT_PISI: ret = safe_strdup (g, "pisi"); break;
2219   case OS_PACKAGE_MANAGEMENT_URPMI: ret = safe_strdup (g, "urpmi"); break;
2220   case OS_PACKAGE_MANAGEMENT_UNKNOWN:
2221   default:
2222     ret = safe_strdup (g, "unknown");
2223     break;
2224   }
2225
2226   return ret;
2227 }
2228
2229 char *
2230 guestfs__inspect_get_hostname (guestfs_h *g, const char *root)
2231 {
2232   struct inspect_fs *fs = search_for_root (g, root);
2233   if (!fs)
2234     return NULL;
2235
2236   return safe_strdup (g, fs->hostname ? : "unknown");
2237 }
2238
2239 #ifdef DB_DUMP
2240 static struct guestfs_application_list *list_applications_rpm (guestfs_h *g, struct inspect_fs *fs);
2241 #endif
2242 static struct guestfs_application_list *list_applications_deb (guestfs_h *g, struct inspect_fs *fs);
2243 static struct guestfs_application_list *list_applications_windows (guestfs_h *g, struct inspect_fs *fs);
2244 static void add_application (guestfs_h *g, struct guestfs_application_list *, const char *name, const char *display_name, int32_t epoch, const char *version, const char *release, const char *install_path, const char *publisher, const char *url, const char *description);
2245 static void sort_applications (struct guestfs_application_list *);
2246
2247 /* Unlike the simple inspect-get-* calls, this one assumes that the
2248  * disks are mounted up, and reads files from the mounted disks.
2249  */
2250 struct guestfs_application_list *
2251 guestfs__inspect_list_applications (guestfs_h *g, const char *root)
2252 {
2253   struct inspect_fs *fs = search_for_root (g, root);
2254   if (!fs)
2255     return NULL;
2256
2257   struct guestfs_application_list *ret = NULL;
2258
2259   /* Presently we can only list applications for installed disks.  It
2260    * is possible in future to get lists of packages from installers.
2261    */
2262   if (fs->format == OS_FORMAT_INSTALLED) {
2263     switch (fs->type) {
2264     case OS_TYPE_LINUX:
2265       switch (fs->package_format) {
2266       case OS_PACKAGE_FORMAT_RPM:
2267 #ifdef DB_DUMP
2268         ret = list_applications_rpm (g, fs);
2269         if (ret == NULL)
2270           return NULL;
2271 #endif
2272         break;
2273
2274       case OS_PACKAGE_FORMAT_DEB:
2275         ret = list_applications_deb (g, fs);
2276         if (ret == NULL)
2277           return NULL;
2278         break;
2279
2280       case OS_PACKAGE_FORMAT_PACMAN:
2281       case OS_PACKAGE_FORMAT_EBUILD:
2282       case OS_PACKAGE_FORMAT_PISI:
2283       case OS_PACKAGE_FORMAT_UNKNOWN:
2284       default:
2285         /* nothing - keep GCC happy */;
2286       }
2287       break;
2288
2289     case OS_TYPE_WINDOWS:
2290       ret = list_applications_windows (g, fs);
2291       if (ret == NULL)
2292         return NULL;
2293       break;
2294
2295     case OS_TYPE_FREEBSD:
2296     case OS_TYPE_UNKNOWN:
2297     default:
2298       /* nothing - keep GCC happy */;
2299     }
2300   }
2301
2302   if (ret == NULL) {
2303     /* Don't know how to do inspection.  Not an error, return an
2304      * empty list.
2305      */
2306     ret = safe_malloc (g, sizeof *ret);
2307     ret->len = 0;
2308     ret->val = NULL;
2309   }
2310
2311   sort_applications (ret);
2312
2313   return ret;
2314 }
2315
2316 #ifdef DB_DUMP
2317 static struct guestfs_application_list *
2318 list_applications_rpm (guestfs_h *g, struct inspect_fs *fs)
2319 {
2320   TMP_TEMPLATE_ON_STACK (tmpfile);
2321
2322   if (download_to_tmp (g, "/var/lib/rpm/Name", tmpfile, MAX_PKG_DB_SIZE) == -1)
2323     return NULL;
2324
2325   struct guestfs_application_list *apps = NULL, *ret = NULL;
2326 #define cmd_len (strlen (tmpfile) + 64)
2327   char cmd[cmd_len];
2328   FILE *pp = NULL;
2329   char line[1024];
2330   size_t len;
2331
2332   snprintf (cmd, cmd_len, DB_DUMP " -p '%s'", tmpfile);
2333
2334   debug (g, "list_applications_rpm: %s", cmd);
2335
2336   pp = popen (cmd, "r");
2337   if (pp == NULL) {
2338     perrorf (g, "popen: %s", cmd);
2339     goto out;
2340   }
2341
2342   /* Ignore everything to end-of-header marker. */
2343   for (;;) {
2344     if (fgets (line, sizeof line, pp) == NULL) {
2345       error (g, _("unexpected end of output from db_dump command"));
2346       goto out;
2347     }
2348
2349     len = strlen (line);
2350     if (len > 0 && line[len-1] == '\n') {
2351       line[len-1] = '\0';
2352       len--;
2353     }
2354
2355     if (STREQ (line, "HEADER=END"))
2356       break;
2357   }
2358
2359   /* Allocate 'apps' list. */
2360   apps = safe_malloc (g, sizeof *apps);
2361   apps->len = 0;
2362   apps->val = NULL;
2363
2364   /* Read alternate lines until end of data marker. */
2365   for (;;) {
2366     if (fgets (line, sizeof line, pp) == NULL) {
2367       error (g, _("unexpected end of output from db_dump command"));
2368       goto out;
2369     }
2370
2371     len = strlen (line);
2372     if (len > 0 && line[len-1] == '\n') {
2373       line[len-1] = '\0';
2374       len--;
2375     }
2376
2377     if (STREQ (line, "DATA=END"))
2378       break;
2379
2380     char *p = line;
2381     if (len > 0 && line[0] == ' ')
2382       p = line+1;
2383     /* Ignore any application name that contains non-printable chars.
2384      * In the db_dump output these would be escaped with backslash, so
2385      * we can just ignore any such line.
2386      */
2387     if (strchr (p, '\\') == NULL)
2388       add_application (g, apps, p, "", 0, "", "", "", "", "", "");
2389
2390     /* Discard next line. */
2391     if (fgets (line, sizeof line, pp) == NULL) {
2392       error (g, _("unexpected end of output from db_dump command"));
2393       goto out;
2394     }
2395   }
2396
2397   /* Catch errors from the db_dump command. */
2398   if (pclose (pp) == -1) {
2399     perrorf (g, "pclose: %s", cmd);
2400     goto out;
2401   }
2402   pp = NULL;
2403
2404   ret = apps;
2405
2406  out:
2407   if (ret == NULL && apps != NULL)
2408     guestfs_free_application_list (apps);
2409   if (pp)
2410     pclose (pp);
2411   unlink (tmpfile);
2412 #undef cmd_len
2413
2414   return ret;
2415 }
2416 #endif /* defined DB_DUMP */
2417
2418 static struct guestfs_application_list *
2419 list_applications_deb (guestfs_h *g, struct inspect_fs *fs)
2420 {
2421   TMP_TEMPLATE_ON_STACK (tmpfile);
2422
2423   if (download_to_tmp (g, "/var/lib/dpkg/status", tmpfile,
2424                        MAX_PKG_DB_SIZE) == -1)
2425     return NULL;
2426
2427   struct guestfs_application_list *apps = NULL, *ret = NULL;
2428   FILE *fp = NULL;
2429   char line[1024];
2430   size_t len;
2431   char *name = NULL, *version = NULL, *release = NULL;
2432   int installed_flag = 0;
2433
2434   fp = fopen (tmpfile, "r");
2435   if (fp == NULL) {
2436     perrorf (g, "fopen: %s", tmpfile);
2437     goto out;
2438   }
2439
2440   /* Allocate 'apps' list. */
2441   apps = safe_malloc (g, sizeof *apps);
2442   apps->len = 0;
2443   apps->val = NULL;
2444
2445   /* Read the temporary file.  Each package entry is separated by
2446    * a blank line.
2447    * XXX Strictly speaking this is in mailbox header format, so it
2448    * would be possible for fields to spread across multiple lines,
2449    * although for the short fields that we are concerned about this is
2450    * unlikely and not seen in practice.
2451    */
2452   while (fgets (line, sizeof line, fp) != NULL) {
2453     len = strlen (line);
2454     if (len > 0 && line[len-1] == '\n') {
2455       line[len-1] = '\0';
2456       len--;
2457     }
2458
2459     if (STRPREFIX (line, "Package: ")) {
2460       free (name);
2461       name = safe_strdup (g, &line[9]);
2462     }
2463     else if (STRPREFIX (line, "Status: ")) {
2464       installed_flag = strstr (&line[8], "installed") != NULL;
2465     }
2466     else if (STRPREFIX (line, "Version: ")) {
2467       free (version);
2468       free (release);
2469       char *p = strchr (&line[9], '-');
2470       if (p) {
2471         *p = '\0';
2472         version = safe_strdup (g, &line[9]);
2473         release = safe_strdup (g, p+1);
2474       } else {
2475         version = safe_strdup (g, &line[9]);
2476         release = NULL;
2477       }
2478     }
2479     else if (STREQ (line, "")) {
2480       if (installed_flag && name && version)
2481         add_application (g, apps, name, "", 0, version, release ? : "",
2482                          "", "", "", "");
2483       free (name);
2484       free (version);
2485       free (release);
2486       name = version = release = NULL;
2487       installed_flag = 0;
2488     }
2489   }
2490
2491   if (fclose (fp) == -1) {
2492     perrorf (g, "fclose: %s", tmpfile);
2493     goto out;
2494   }
2495   fp = NULL;
2496
2497   ret = apps;
2498
2499  out:
2500   if (ret == NULL && apps != NULL)
2501     guestfs_free_application_list (apps);
2502   if (fp)
2503     fclose (fp);
2504   free (name);
2505   free (version);
2506   free (release);
2507   unlink (tmpfile);
2508   return ret;
2509 }
2510
2511 static void list_applications_windows_from_path (guestfs_h *g, hive_h *h, struct guestfs_application_list *apps, const char **path, size_t path_len);
2512
2513 static struct guestfs_application_list *
2514 list_applications_windows (guestfs_h *g, struct inspect_fs *fs)
2515 {
2516   TMP_TEMPLATE_ON_STACK (software_local);
2517
2518   /* XXX We already download the SOFTWARE hive when doing general
2519    * inspection.  We could avoid this second download of the same file
2520    * by caching these entries in the handle.
2521    */
2522   size_t len = strlen (fs->windows_systemroot) + 64;
2523   char software[len];
2524   snprintf (software, len, "%s/system32/config/software",
2525             fs->windows_systemroot);
2526
2527   char *software_path = case_sensitive_path_silently (g, software);
2528   if (!software_path)
2529     /* If the software hive doesn't exist, just accept that we cannot
2530      * find product_name etc.
2531      */
2532     return 0;
2533
2534   struct guestfs_application_list *ret = NULL;
2535   hive_h *h = NULL;
2536
2537   if (download_to_tmp (g, software_path, software_local,
2538                        MAX_REGISTRY_SIZE) == -1)
2539     goto out;
2540
2541   free (software_path);
2542   software_path = NULL;
2543
2544   h = hivex_open (software_local, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
2545   if (h == NULL) {
2546     perrorf (g, "hivex_open");
2547     goto out;
2548   }
2549
2550   /* Allocate apps list. */
2551   ret = safe_malloc (g, sizeof *ret);
2552   ret->len = 0;
2553   ret->val = NULL;
2554
2555   /* Ordinary native applications. */
2556   const char *hivepath[] =
2557     { "Microsoft", "Windows", "CurrentVersion", "Uninstall" };
2558   list_applications_windows_from_path (g, h, ret, hivepath,
2559                                        sizeof hivepath / sizeof hivepath[0]);
2560
2561   /* 32-bit emulated Windows apps running on the WOW64 emulator.
2562    * http://support.microsoft.com/kb/896459 (RHBZ#692545).
2563    */
2564   const char *hivepath2[] =
2565     { "WOW6432node", "Microsoft", "Windows", "CurrentVersion", "Uninstall" };
2566   list_applications_windows_from_path (g, h, ret, hivepath2,
2567                                        sizeof hivepath2 / sizeof hivepath2[0]);
2568
2569  out:
2570   if (h) hivex_close (h);
2571   free (software_path);
2572
2573   /* Delete the temporary file. */
2574   unlink (software_local);
2575 #undef software_local_len
2576
2577   return ret;
2578 }
2579
2580 static void
2581 list_applications_windows_from_path (guestfs_h *g, hive_h *h,
2582                                      struct guestfs_application_list *apps,
2583                                      const char **path, size_t path_len)
2584 {
2585   hive_node_h *children = NULL;
2586   hive_node_h node;
2587   size_t i;
2588
2589   node = hivex_root (h);
2590
2591   for (i = 0; node != 0 && i < path_len; ++i)
2592     node = hivex_node_get_child (h, node, path[i]);
2593
2594   if (node == 0)
2595     return;
2596
2597   children = hivex_node_children (h, node);
2598   if (children == NULL)
2599     return;
2600
2601   /* Consider any child node that has a DisplayName key.
2602    * See also:
2603    * http://nsis.sourceforge.net/Add_uninstall_information_to_Add/Remove_Programs#Optional_values
2604    */
2605   for (i = 0; children[i] != 0; ++i) {
2606     hive_value_h value;
2607     char *name = NULL;
2608     char *display_name = NULL;
2609     char *version = NULL;
2610     char *install_path = NULL;
2611     char *publisher = NULL;
2612     char *url = NULL;
2613     char *comments = NULL;
2614
2615     /* Use the node name as a proxy for the package name in Linux.  The
2616      * display name is not language-independent, so it cannot be used.
2617      */
2618     name = hivex_node_name (h, children[i]);
2619     if (name == NULL)
2620       continue;
2621
2622     value = hivex_node_get_value (h, children[i], "DisplayName");
2623     if (value) {
2624       display_name = hivex_value_string (h, value);
2625       if (display_name) {
2626         value = hivex_node_get_value (h, children[i], "DisplayVersion");
2627         if (value)
2628           version = hivex_value_string (h, value);
2629         value = hivex_node_get_value (h, children[i], "InstallLocation");
2630         if (value)
2631           install_path = hivex_value_string (h, value);
2632         value = hivex_node_get_value (h, children[i], "Publisher");
2633         if (value)
2634           publisher = hivex_value_string (h, value);
2635         value = hivex_node_get_value (h, children[i], "URLInfoAbout");
2636         if (value)
2637           url = hivex_value_string (h, value);
2638         value = hivex_node_get_value (h, children[i], "Comments");
2639         if (value)
2640           comments = hivex_value_string (h, value);
2641
2642         add_application (g, apps, name, display_name, 0,
2643                          version ? : "",
2644                          "",
2645                          install_path ? : "",
2646                          publisher ? : "",
2647                          url ? : "",
2648                          comments ? : "");
2649       }
2650     }
2651
2652     free (name);
2653     free (display_name);
2654     free (version);
2655     free (install_path);
2656     free (publisher);
2657     free (url);
2658     free (comments);
2659   }
2660
2661   free (children);
2662 }
2663
2664 static void
2665 add_application (guestfs_h *g, struct guestfs_application_list *apps,
2666                  const char *name, const char *display_name, int32_t epoch,
2667                  const char *version, const char *release,
2668                  const char *install_path,
2669                  const char *publisher, const char *url,
2670                  const char *description)
2671 {
2672   apps->len++;
2673   apps->val = safe_realloc (g, apps->val,
2674                             apps->len * sizeof (struct guestfs_application));
2675   apps->val[apps->len-1].app_name = safe_strdup (g, name);
2676   apps->val[apps->len-1].app_display_name = safe_strdup (g, display_name);
2677   apps->val[apps->len-1].app_epoch = epoch;
2678   apps->val[apps->len-1].app_version = safe_strdup (g, version);
2679   apps->val[apps->len-1].app_release = safe_strdup (g, release);
2680   apps->val[apps->len-1].app_install_path = safe_strdup (g, install_path);
2681   /* XXX Translated path is not implemented yet. */
2682   apps->val[apps->len-1].app_trans_path = safe_strdup (g, "");
2683   apps->val[apps->len-1].app_publisher = safe_strdup (g, publisher);
2684   apps->val[apps->len-1].app_url = safe_strdup (g, url);
2685   /* XXX The next two are not yet implemented for any package
2686    * format, but we could easily support them for rpm and deb.
2687    */
2688   apps->val[apps->len-1].app_source_package = safe_strdup (g, "");
2689   apps->val[apps->len-1].app_summary = safe_strdup (g, "");
2690   apps->val[apps->len-1].app_description = safe_strdup (g, description);
2691 }
2692
2693 /* Sort applications by name before returning the list. */
2694 static int
2695 compare_applications (const void *vp1, const void *vp2)
2696 {
2697   const struct guestfs_application *v1 = vp1;
2698   const struct guestfs_application *v2 = vp2;
2699
2700   return strcmp (v1->app_name, v2->app_name);
2701 }
2702
2703 static void
2704 sort_applications (struct guestfs_application_list *apps)
2705 {
2706   if (apps && apps->val)
2707     qsort (apps->val, apps->len, sizeof (struct guestfs_application),
2708            compare_applications);
2709 }
2710
2711 /* Download to a guest file to a local temporary file.  Refuse to
2712  * download the guest file if it is larger than max_size.  The caller
2713  * is responsible for deleting the temporary file after use.
2714  */
2715 static int
2716 download_to_tmp (guestfs_h *g, const char *filename,
2717                  char *localtmp, int64_t max_size)
2718 {
2719   int fd;
2720   char buf[32];
2721   int64_t size;
2722
2723   size = guestfs_filesize (g, filename);
2724   if (size == -1)
2725     /* guestfs_filesize failed and has already set error in handle */
2726     return -1;
2727   if (size > max_size) {
2728     error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
2729            filename, size);
2730     return -1;
2731   }
2732
2733   fd = mkstemp (localtmp);
2734   if (fd == -1) {
2735     perrorf (g, "mkstemp");
2736     return -1;
2737   }
2738
2739   snprintf (buf, sizeof buf, "/dev/fd/%d", fd);
2740
2741   if (guestfs_download (g, filename, buf) == -1) {
2742     close (fd);
2743     unlink (localtmp);
2744     return -1;
2745   }
2746
2747   if (close (fd) == -1) {
2748     perrorf (g, "close: %s", localtmp);
2749     unlink (localtmp);
2750     return -1;
2751   }
2752
2753   return 0;
2754 }
2755
2756 /* Call 'f' with Augeas opened and having parsed 'filename' (this file
2757  * must exist).  As a security measure, this bails if the file is too
2758  * large for a reasonable configuration file.  After the call to 'f'
2759  * Augeas is closed.
2760  */
2761 static int
2762 inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char *filename,
2763                      int (*f) (guestfs_h *, struct inspect_fs *))
2764 {
2765   /* Security: Refuse to do this if filename is too large. */
2766   int64_t size = guestfs_filesize (g, filename);
2767   if (size == -1)
2768     /* guestfs_filesize failed and has already set error in handle */
2769     return -1;
2770   if (size > MAX_AUGEAS_FILE_SIZE) {
2771     error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
2772            filename, size);
2773     return -1;
2774   }
2775
2776   /* If !feature_available (g, "augeas") then the next call will fail.
2777    * Arguably we might want to fall back to a non-Augeas method in
2778    * this case.
2779    */
2780   if (guestfs_aug_init (g, "/", 16|32) == -1)
2781     return -1;
2782
2783   int r = -1;
2784
2785   /* Tell Augeas to only load one file (thanks Raphaël Pinson). */
2786   char buf[strlen (filename) + 64];
2787   snprintf (buf, strlen (filename) + 64, "/augeas/load//incl[. != \"%s\"]",
2788             filename);
2789   if (guestfs_aug_rm (g, buf) == -1)
2790     goto out;
2791
2792   if (guestfs_aug_load (g) == -1)
2793     goto out;
2794
2795   r = f (g, fs);
2796
2797  out:
2798   guestfs_aug_close (g);
2799
2800   return r;
2801 }
2802
2803 /* Get the first line of a small file, without any trailing newline
2804  * character.
2805  */
2806 static char *
2807 first_line_of_file (guestfs_h *g, const char *filename)
2808 {
2809   char **lines;
2810   int64_t size;
2811   char *ret;
2812
2813   /* Don't trust guestfs_head_n not to break with very large files.
2814    * Check the file size is something reasonable first.
2815    */
2816   size = guestfs_filesize (g, filename);
2817   if (size == -1)
2818     /* guestfs_filesize failed and has already set error in handle */
2819     return NULL;
2820   if (size > MAX_SMALL_FILE_SIZE) {
2821     error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
2822            filename, size);
2823     return NULL;
2824   }
2825
2826   lines = guestfs_head_n (g, 1, filename);
2827   if (lines == NULL)
2828     return NULL;
2829   if (lines[0] == NULL) {
2830     error (g, _("%s: file is empty"), filename);
2831     guestfs___free_string_list (lines);
2832     return NULL;
2833   }
2834   /* lines[1] should be NULL because of '1' argument above ... */
2835
2836   ret = lines[0];               /* caller frees */
2837   free (lines);                 /* free the array */
2838
2839   return ret;
2840 }
2841
2842 /* Get the first matching line (using guestfs_egrep{,i}) of a small file,
2843  * without any trailing newline character.
2844  *
2845  * Returns: 1 = returned a line (in *ret)
2846  *          0 = no match
2847  *          -1 = error
2848  */
2849 static int
2850 first_egrep_of_file (guestfs_h *g, const char *filename,
2851                      const char *eregex, int iflag, char **ret)
2852 {
2853   char **lines;
2854   int64_t size;
2855   size_t i;
2856
2857   /* Don't trust guestfs_egrep not to break with very large files.
2858    * Check the file size is something reasonable first.
2859    */
2860   size = guestfs_filesize (g, filename);
2861   if (size == -1)
2862     /* guestfs_filesize failed and has already set error in handle */
2863     return -1;
2864   if (size > MAX_SMALL_FILE_SIZE) {
2865     error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
2866            filename, size);
2867     return -1;
2868   }
2869
2870   lines = (!iflag ? guestfs_egrep : guestfs_egrepi) (g, eregex, filename);
2871   if (lines == NULL)
2872     return -1;
2873   if (lines[0] == NULL) {
2874     guestfs___free_string_list (lines);
2875     return 0;
2876   }
2877
2878   *ret = lines[0];              /* caller frees */
2879
2880   /* free up any other matches and the array itself */
2881   for (i = 1; lines[i] != NULL; ++i)
2882     free (lines[i]);
2883   free (lines);
2884
2885   return 1;
2886 }
2887
2888 #else /* no PCRE or hivex at compile time */
2889
2890 /* XXX These functions should be in an optgroup. */
2891
2892 #define NOT_IMPL(r)                                                     \
2893   error (g, _("inspection API not available since this version of libguestfs was compiled without PCRE or hivex libraries")); \
2894   return r
2895
2896 char **
2897 guestfs__inspect_os (guestfs_h *g)
2898 {
2899   NOT_IMPL(NULL);
2900 }
2901
2902 char **
2903 guestfs__inspect_get_roots (guestfs_h *g)
2904 {
2905   NOT_IMPL(NULL);
2906 }
2907
2908 char *
2909 guestfs__inspect_get_type (guestfs_h *g, const char *root)
2910 {
2911   NOT_IMPL(NULL);
2912 }
2913
2914 char *
2915 guestfs__inspect_get_arch (guestfs_h *g, const char *root)
2916 {
2917   NOT_IMPL(NULL);
2918 }
2919
2920 char *
2921 guestfs__inspect_get_distro (guestfs_h *g, const char *root)
2922 {
2923   NOT_IMPL(NULL);
2924 }
2925
2926 int
2927 guestfs__inspect_get_major_version (guestfs_h *g, const char *root)
2928 {
2929   NOT_IMPL(-1);
2930 }
2931
2932 int
2933 guestfs__inspect_get_minor_version (guestfs_h *g, const char *root)
2934 {
2935   NOT_IMPL(-1);
2936 }
2937
2938 char *
2939 guestfs__inspect_get_product_name (guestfs_h *g, const char *root)
2940 {
2941   NOT_IMPL(NULL);
2942 }
2943
2944 char *
2945 guestfs__inspect_get_product_variant (guestfs_h *g, const char *root)
2946 {
2947   NOT_IMPL(NULL);
2948 }
2949
2950 char *
2951 guestfs__inspect_get_windows_systemroot (guestfs_h *g, const char *root)
2952 {
2953   NOT_IMPL(NULL);
2954 }
2955
2956 char *
2957 guestfs__inspect_get_windows_current_control_set (guestfs_h *g,
2958                                                   const char *root)
2959 {
2960   NOT_IMPL(NULL);
2961 }
2962
2963 char **
2964 guestfs__inspect_get_mountpoints (guestfs_h *g, const char *root)
2965 {
2966   NOT_IMPL(NULL);
2967 }
2968
2969 char **
2970 guestfs__inspect_get_filesystems (guestfs_h *g, const char *root)
2971 {
2972   NOT_IMPL(NULL);
2973 }
2974
2975 char *
2976 guestfs__inspect_get_package_format (guestfs_h *g, const char *root)
2977 {
2978   NOT_IMPL(NULL);
2979 }
2980
2981 char *
2982 guestfs__inspect_get_package_management (guestfs_h *g, const char *root)
2983 {
2984   NOT_IMPL(NULL);
2985 }
2986
2987 char *
2988 guestfs__inspect_get_hostname (guestfs_h *g, const char *root)
2989 {
2990   NOT_IMPL(NULL);
2991 }
2992
2993 struct guestfs_application_list *
2994 guestfs__inspect_list_applications (guestfs_h *g, const char *root)
2995 {
2996   NOT_IMPL(NULL);
2997 }
2998
2999 char *
3000 guestfs__inspect_get_format (guestfs_h *g, const char *root)
3001 {
3002   NOT_IMPL(NULL);
3003 }
3004
3005 int
3006 guestfs__inspect_is_live (guestfs_h *g, const char *root)
3007 {
3008   NOT_IMPL(-1);
3009 }
3010
3011 int
3012 guestfs__inspect_is_netinst (guestfs_h *g, const char *root)
3013 {
3014   NOT_IMPL(-1);
3015 }
3016
3017 int
3018 guestfs__inspect_is_multipart (guestfs_h *g, const char *root)
3019 {
3020   NOT_IMPL(-1);
3021 }
3022
3023 #endif /* no PCRE or hivex at compile time */
3024
3025 void
3026 guestfs___free_inspect_info (guestfs_h *g)
3027 {
3028   size_t i;
3029   for (i = 0; i < g->nr_fses; ++i) {
3030     free (g->fses[i].device);
3031     free (g->fses[i].product_name);
3032     free (g->fses[i].product_variant);
3033     free (g->fses[i].arch);
3034     free (g->fses[i].hostname);
3035     free (g->fses[i].windows_systemroot);
3036     free (g->fses[i].windows_current_control_set);
3037     size_t j;
3038     for (j = 0; j < g->fses[i].nr_fstab; ++j) {
3039       free (g->fses[i].fstab[j].device);
3040       free (g->fses[i].fstab[j].mountpoint);
3041     }
3042     free (g->fses[i].fstab);
3043   }
3044   free (g->fses);
3045   g->nr_fses = 0;
3046   g->fses = NULL;
3047 }
3048
3049 /* In the Perl code this is a public function. */
3050 int
3051 guestfs___feature_available (guestfs_h *g, const char *feature)
3052 {
3053   /* If there's an error we should ignore it, so to do that we have to
3054    * temporarily replace the error handler with a null one.
3055    */
3056   guestfs_error_handler_cb old_error_cb = g->error_cb;
3057   g->error_cb = NULL;
3058
3059   const char *groups[] = { feature, NULL };
3060   int r = guestfs_available (g, (char * const *) groups);
3061
3062   g->error_cb = old_error_cb;
3063
3064   return r == 0 ? 1 : 0;
3065 }
3066
3067 #ifdef HAVE_PCRE
3068
3069 /* Match a regular expression which contains no captures.  Returns
3070  * true if it matches or false if it doesn't.
3071  */
3072 int
3073 guestfs___match (guestfs_h *g, const char *str, const pcre *re)
3074 {
3075   size_t len = strlen (str);
3076   int vec[30], r;
3077
3078   r = pcre_exec (re, NULL, str, len, 0, 0, vec, sizeof vec / sizeof vec[0]);
3079   if (r == PCRE_ERROR_NOMATCH)
3080     return 0;
3081   if (r != 1) {
3082     /* Internal error -- should not happen. */
3083     warning (g, "%s: %s: pcre_exec returned unexpected error code %d when matching against the string \"%s\"\n",
3084              __FILE__, __func__, r, str);
3085     return 0;
3086   }
3087
3088   return 1;
3089 }
3090
3091 /* Match a regular expression which contains exactly one capture.  If
3092  * the string matches, return the capture, otherwise return NULL.  The
3093  * caller must free the result.
3094  */
3095 char *
3096 guestfs___match1 (guestfs_h *g, const char *str, const pcre *re)
3097 {
3098   size_t len = strlen (str);
3099   int vec[30], r;
3100
3101   r = pcre_exec (re, NULL, str, len, 0, 0, vec, sizeof vec / sizeof vec[0]);
3102   if (r == PCRE_ERROR_NOMATCH)
3103     return NULL;
3104   if (r != 2) {
3105     /* Internal error -- should not happen. */
3106     warning (g, "%s: %s: internal error: pcre_exec returned unexpected error code %d when matching against the string \"%s\"",
3107              __FILE__, __func__, r, str);
3108     return NULL;
3109   }
3110
3111   return safe_strndup (g, &str[vec[2]], vec[3]-vec[2]);
3112 }
3113
3114 /* Match a regular expression which contains exactly two captures. */
3115 int
3116 guestfs___match2 (guestfs_h *g, const char *str, const pcre *re,
3117                   char **ret1, char **ret2)
3118 {
3119   size_t len = strlen (str);
3120   int vec[30], r;
3121
3122   r = pcre_exec (re, NULL, str, len, 0, 0, vec, 30);
3123   if (r == PCRE_ERROR_NOMATCH)
3124     return 0;
3125   if (r != 3) {
3126     /* Internal error -- should not happen. */
3127     warning (g, "%s: %s: internal error: pcre_exec returned unexpected error code %d when matching against the string \"%s\"",
3128              __FILE__, __func__, r, str);
3129     return 0;
3130   }
3131
3132   *ret1 = safe_strndup (g, &str[vec[2]], vec[3]-vec[2]);
3133   *ret2 = safe_strndup (g, &str[vec[4]], vec[5]-vec[4]);
3134
3135   return 1;
3136 }
3137
3138 /* Match a regular expression which contains exactly three captures. */
3139 int
3140 guestfs___match3 (guestfs_h *g, const char *str, const pcre *re,
3141                   char **ret1, char **ret2, char **ret3)
3142 {
3143   size_t len = strlen (str);
3144   int vec[30], r;
3145
3146   r = pcre_exec (re, NULL, str, len, 0, 0, vec, 30);
3147   if (r == PCRE_ERROR_NOMATCH)
3148     return 0;
3149   if (r != 4) {
3150     /* Internal error -- should not happen. */
3151     warning (g, "%s: %s: internal error: pcre_exec returned unexpected error code %d when matching against the string \"%s\"",
3152              __FILE__, __func__, r, str);
3153     return 0;
3154   }
3155
3156   *ret1 = safe_strndup (g, &str[vec[2]], vec[3]-vec[2]);
3157   *ret2 = safe_strndup (g, &str[vec[4]], vec[5]-vec[4]);
3158   *ret3 = safe_strndup (g, &str[vec[6]], vec[7]-vec[6]);
3159
3160   return 1;
3161 }
3162
3163 #endif /* HAVE_PCRE */