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