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