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