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