inspect: Simplify Windows root heuristic code.
[libguestfs.git] / src / inspect.c
index 8b21026..09ef2b1 100644 (file)
@@ -1,5 +1,5 @@
 /* libguestfs
- * Copyright (C) 2010 Red Hat Inc.
+ * Copyright (C) 2010-2011 Red Hat Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 
 #if defined(HAVE_PCRE) && defined(HAVE_HIVEX)
 
+/* Some limits on what we will read, for safety. */
+
+/* Small text configuration files.
+ *
+ * The upper limit is for general files that we grep or download.  The
+ * largest such file is probably "txtsetup.sif" from Windows CDs
+ * (~500K).  This number has to be larger than any legitimate file and
+ * smaller than the protocol message size.
+ *
+ * The lower limit is for files parsed by Augeas on the daemon side,
+ * where Augeas is running in reduced memory and can potentially
+ * create a lot of metadata so we really need to be careful about
+ * those.
+ */
+#define MAX_SMALL_FILE_SIZE    (2 * 1000 * 1000)
+#define MAX_AUGEAS_FILE_SIZE        (100 * 1000)
+
+/* Maximum Windows Registry hive that we will download to /tmp.  Some
+ * registries can be legitimately very large.
+ */
+#define MAX_REGISTRY_SIZE    (100 * 1000 * 1000)
+
+/* Maximum RPM or dpkg database we will download to /tmp. */
+#define MAX_PKG_DB_SIZE       (10 * 1000 * 1000)
+
 /* Compile all the regular expressions once when the shared library is
  * loaded.  PCRE is thread safe so we're supposedly OK here if
  * multiple threads call into the libguestfs API functions below
@@ -81,11 +106,11 @@ compile_regexps (void)
 
   COMPILE (re_fedora, "Fedora release (\\d+)", 0);
   COMPILE (re_rhel_old,
-           "(?:Red Hat Enterprise Linux|CentOS|Scientific Linux).*release (\\d+).*Update (\\d+)", 0);
+           "(?:Red Hat|CentOS|Scientific Linux).*release (\\d+).*Update (\\d+)", 0);
   COMPILE (re_rhel,
-           "(?:Red Hat Enterprise Linux|CentOS|Scientific Linux).*release (\\d+)\\.(\\d+)", 0);
+           "(?:Red Hat|CentOS|Scientific Linux).*release (\\d+)\\.(\\d+)", 0);
   COMPILE (re_rhel_no_minor,
-           "(?:Red Hat Enterprise Linux|CentOS|Scientific Linux).*release (\\d+)", 0);
+           "(?:Red Hat|CentOS|Scientific Linux).*release (\\d+)", 0);
   COMPILE (re_major_minor, "(\\d+)\\.(\\d+)", 0);
   COMPILE (re_aug_seq, "/\\d+$", 0);
   COMPILE (re_xdev, "^/dev/(?:h|s|v|xv)d([a-z]\\d*)$", 0);
@@ -204,6 +229,8 @@ static int check_windows_arch (guestfs_h *g, struct inspect_fs *fs);
 static int check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs);
 static int check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs);
 static char *resolve_windows_path_silently (guestfs_h *g, const char *);
+static int is_file_nocase (guestfs_h *g, const char *);
+static int is_dir_nocase (guestfs_h *g, const char *);
 static int extend_fses (guestfs_h *g);
 static int parse_unsigned_int (guestfs_h *g, const char *str);
 static int add_fstab_entry (guestfs_h *g, struct inspect_fs *fs,
@@ -327,17 +354,13 @@ check_filesystem (guestfs_h *g, const char *device)
            guestfs_is_dir (g, "/spool") > 0)
     fs->content = FS_CONTENT_LINUX_VAR;
   /* Windows root? */
-  else if (guestfs_is_file (g, "/AUTOEXEC.BAT") > 0 ||
-           guestfs_is_file (g, "/autoexec.bat") > 0 ||
-           guestfs_is_dir (g, "/Program Files") > 0 ||
-           guestfs_is_dir (g, "/WINDOWS") > 0 ||
-           guestfs_is_dir (g, "/Windows") > 0 ||
-           guestfs_is_dir (g, "/windows") > 0 ||
-           guestfs_is_dir (g, "/WIN32") > 0 ||
-           guestfs_is_dir (g, "/Win32") > 0 ||
-           guestfs_is_dir (g, "/WINNT") > 0 ||
-           guestfs_is_file (g, "/boot.ini") > 0 ||
-           guestfs_is_file (g, "/ntldr") > 0) {
+  else if (is_file_nocase (g, "/AUTOEXEC.BAT") > 0 ||
+           is_dir_nocase (g, "/Program Files") > 0 ||
+           is_dir_nocase (g, "/WINDOWS") > 0 ||
+           is_dir_nocase (g, "/WIN32") > 0 ||
+           is_dir_nocase (g, "/WINNT") > 0 ||
+           is_file_nocase (g, "/boot.ini") > 0 ||
+           is_file_nocase (g, "/ntldr") > 0) {
     fs->is_root = 1;
     fs->content = FS_CONTENT_WINDOWS_ROOT;
     if (check_windows_root (g, fs) == -1)
@@ -417,7 +440,7 @@ parse_lsb_release (guestfs_h *g, struct inspect_fs *fs)
   if (size == -1)
     /* guestfs_filesize failed and has already set error in handle */
     return -1;
-  if (size > 1000000) {
+  if (size > MAX_SMALL_FILE_SIZE) {
     error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
            filename, size);
     return -1;
@@ -609,8 +632,6 @@ check_linux_root (guestfs_h *g, struct inspect_fs *fs)
 static int
 check_freebsd_root (guestfs_h *g, struct inspect_fs *fs)
 {
-  int r;
-
   fs->type = OS_TYPE_FREEBSD;
 
   /* FreeBSD has no authoritative version file.  The version number is
@@ -673,8 +694,6 @@ check_architecture (guestfs_h *g, struct inspect_fs *fs)
 static int
 check_hostname_unix (guestfs_h *g, struct inspect_fs *fs)
 {
-  char **lines;
-
   switch (fs->type) {
   case OS_TYPE_LINUX:
     /* Red Hat-derived would be in /etc/sysconfig/network, and
@@ -757,7 +776,7 @@ check_hostname_freebsd (guestfs_h *g, struct inspect_fs *fs)
   if (size == -1)
     /* guestfs_filesize failed and has already set error in handle */
     return -1;
-  if (size > 1000000) {
+  if (size > MAX_SMALL_FILE_SIZE) {
     error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
            filename, size);
     return -1;
@@ -1080,7 +1099,8 @@ check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs)
   hive_h *h = NULL;
   hive_value_h *values = NULL;
 
-  if (download_to_tmp (g, software_path, software_local, 100000000) == -1)
+  if (download_to_tmp (g, software_path, software_local,
+                       MAX_REGISTRY_SIZE) == -1)
     goto out;
 
   h = hivex_open (software_local, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
@@ -1188,7 +1208,7 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
   hive_h *h = NULL;
   hive_value_h *values = NULL;
 
-  if (download_to_tmp (g, system_path, system_local, 100000000) == -1)
+  if (download_to_tmp (g, system_path, system_local, MAX_REGISTRY_SIZE) == -1)
     goto out;
 
   h = hivex_open (system_local, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
@@ -1262,6 +1282,34 @@ resolve_windows_path_silently (guestfs_h *g, const char *path)
 }
 
 static int
+is_file_nocase (guestfs_h *g, const char *path)
+{
+  char *p;
+  int r;
+
+  p = resolve_windows_path_silently (g, path);
+  if (!p)
+    return 0;
+  r = guestfs_is_file (g, p);
+  free (p);
+  return r > 0;
+}
+
+static int
+is_dir_nocase (guestfs_h *g, const char *path)
+{
+  char *p;
+  int r;
+
+  p = resolve_windows_path_silently (g, path);
+  if (!p)
+    return 0;
+  r = guestfs_is_dir (g, p);
+  free (p);
+  return r > 0;
+}
+
+static int
 extend_fses (guestfs_h *g)
 {
   size_t n = g->nr_fses + 1;
@@ -1739,7 +1787,7 @@ list_applications_rpm (guestfs_h *g, struct inspect_fs *fs)
 {
   TMP_TEMPLATE_ON_STACK (tmpfile);
 
-  if (download_to_tmp (g, "/var/lib/rpm/Name", tmpfile, 10000000) == -1)
+  if (download_to_tmp (g, "/var/lib/rpm/Name", tmpfile, MAX_PKG_DB_SIZE) == -1)
     return NULL;
 
   struct guestfs_application_list *apps = NULL, *ret = NULL;
@@ -1841,7 +1889,8 @@ list_applications_deb (guestfs_h *g, struct inspect_fs *fs)
 {
   TMP_TEMPLATE_ON_STACK (tmpfile);
 
-  if (download_to_tmp (g, "/var/lib/dpkg/status", tmpfile, 10000000) == -1)
+  if (download_to_tmp (g, "/var/lib/dpkg/status", tmpfile,
+                       MAX_PKG_DB_SIZE) == -1)
     return NULL;
 
   struct guestfs_application_list *apps = NULL, *ret = NULL;
@@ -1953,7 +2002,8 @@ list_applications_windows (guestfs_h *g, struct inspect_fs *fs)
   hive_h *h = NULL;
   hive_node_h *children = NULL;
 
-  if (download_to_tmp (g, software_path, software_local, 100000000) == -1)
+  if (download_to_tmp (g, software_path, software_local,
+                       MAX_REGISTRY_SIZE) == -1)
     goto out;
 
   h = hivex_open (software_local, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
@@ -2172,7 +2222,7 @@ inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char *filename,
   if (size == -1)
     /* guestfs_filesize failed and has already set error in handle */
     return -1;
-  if (size > 100000) {
+  if (size > MAX_AUGEAS_FILE_SIZE) {
     error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
            filename, size);
     return -1;
@@ -2222,7 +2272,7 @@ first_line_of_file (guestfs_h *g, const char *filename)
   if (size == -1)
     /* guestfs_filesize failed and has already set error in handle */
     return NULL;
-  if (size > 1000000) {
+  if (size > MAX_SMALL_FILE_SIZE) {
     error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
            filename, size);
     return NULL;
@@ -2342,6 +2392,30 @@ guestfs__inspect_list_applications (guestfs_h *g, const char *root)
   NOT_IMPL(NULL);
 }
 
+char *
+guestfs__inspect_get_format (guestfs_h *g, const char *root)
+{
+  NOT_IMPL(NULL);
+}
+
+int
+guestfs__inspect_is_live (guestfs_h *g, const char *root)
+{
+  NOT_IMPL(-1);
+}
+
+int
+guestfs__inspect_is_netinst (guestfs_h *g, const char *root)
+{
+  NOT_IMPL(-1);
+}
+
+int
+guestfs__inspect_is_multipart (guestfs_h *g, const char *root)
+{
+  NOT_IMPL(-1);
+}
+
 #endif /* no PCRE or hivex at compile time */
 
 void