inspect: Optimize root filesystem check.
[libguestfs.git] / src / inspect.c
index 2b61a75..2f543b5 100644 (file)
@@ -197,6 +197,8 @@ static int parse_unsigned_int (guestfs_h *g, const char *str);
 static int add_fstab_entry (guestfs_h *g, struct inspect_fs *fs,
                             const char *spec, const char *mp);
 static char *resolve_fstab_device (guestfs_h *g, const char *spec);
+static void check_package_format (guestfs_h *g, struct inspect_fs *fs);
+static void check_package_management (guestfs_h *g, struct inspect_fs *fs);
 
 static int
 check_for_filesystem_on (guestfs_h *g, const char *device)
@@ -255,13 +257,18 @@ check_filesystem (guestfs_h *g, const char *device)
   fs->device = safe_strdup (g, device);
   fs->is_mountable = 1;
 
+  /* Optimize some of the tests by avoiding multiple tests of the same thing. */
+  int is_dir_etc = guestfs_is_dir (g, "/etc") > 0;
+  int is_dir_bin = guestfs_is_dir (g, "/bin") > 0;
+  int is_dir_share = guestfs_is_dir (g, "/share") > 0;
+
   /* Grub /boot? */
   if (guestfs_is_file (g, "/grub/menu.lst") > 0 ||
       guestfs_is_file (g, "/grub/grub.conf") > 0)
     fs->content = FS_CONTENT_LINUX_BOOT;
   /* Linux root? */
-  else if (guestfs_is_dir (g, "/etc") > 0 &&
-           guestfs_is_dir (g, "/bin") > 0 &&
+  else if (is_dir_etc &&
+           is_dir_bin &&
            guestfs_is_file (g, "/etc/fstab") > 0) {
     fs->is_root = 1;
     fs->content = FS_CONTENT_LINUX_ROOT;
@@ -269,16 +276,16 @@ check_filesystem (guestfs_h *g, const char *device)
       return -1;
   }
   /* Linux /usr/local? */
-  else if (guestfs_is_dir (g, "/etc") > 0 &&
-           guestfs_is_dir (g, "/bin") > 0 &&
-           guestfs_is_dir (g, "/share") > 0 &&
+  else if (is_dir_etc &&
+           is_dir_bin &&
+           is_dir_share &&
            guestfs_exists (g, "/local") == 0 &&
            guestfs_is_file (g, "/etc/fstab") == 0)
     fs->content = FS_CONTENT_LINUX_USR_LOCAL;
   /* Linux /usr? */
-  else if (guestfs_is_dir (g, "/etc") > 0 &&
-           guestfs_is_dir (g, "/bin") > 0 &&
-           guestfs_is_dir (g, "/share") > 0 &&
+  else if (is_dir_etc &&
+           is_dir_bin &&
+           is_dir_share &&
            guestfs_exists (g, "/local") > 0 &&
            guestfs_is_file (g, "/etc/fstab") == 0)
     fs->content = FS_CONTENT_LINUX_USR;
@@ -516,6 +523,10 @@ check_linux_root (guestfs_h *g, struct inspect_fs *fs)
 
  skip_release_checks:;
 
+  /* If distro test above was successful, work out the package format. */
+  check_package_format (g, fs);
+  check_package_management (g, fs);
+
   /* Determine the architecture. */
   const char *binaries[] =
     { "/bin/bash", "/bin/ls", "/bin/echo", "/bin/rm", "/bin/sh" };
@@ -776,6 +787,9 @@ check_windows_root (guestfs_h *g, struct inspect_fs *fs)
   if (check_windows_registry (g, fs) == -1)
     return -1;
 
+  check_package_format (g, fs);
+  check_package_management (g, fs);
+
   return 0;
 }
 
@@ -972,6 +986,84 @@ parse_unsigned_int (guestfs_h *g, const char *str)
   return ret;
 }
 
+/* At the moment, package format and package management is just a
+ * simple function of the distro and major_version fields, so these
+ * can never return an error.  We might be cleverer in future.
+ */
+static void
+check_package_format (guestfs_h *g, struct inspect_fs *fs)
+{
+  switch (fs->distro) {
+  case OS_DISTRO_FEDORA:
+  case OS_DISTRO_MEEGO:
+  case OS_DISTRO_REDHAT_BASED:
+  case OS_DISTRO_RHEL:
+    fs->package_format = OS_PACKAGE_FORMAT_RPM;
+    break;
+
+  case OS_DISTRO_DEBIAN:
+  case OS_DISTRO_UBUNTU:
+    fs->package_format = OS_PACKAGE_FORMAT_DEB;
+    break;
+
+  case OS_DISTRO_ARCHLINUX:
+    fs->package_format = OS_PACKAGE_FORMAT_PACMAN;
+    break;
+  case OS_DISTRO_GENTOO:
+    fs->package_format = OS_PACKAGE_FORMAT_EBUILD;
+    break;
+  case OS_DISTRO_PARDUS:
+    fs->package_format = OS_PACKAGE_FORMAT_PISI;
+    break;
+
+  case OS_DISTRO_WINDOWS:
+  case OS_DISTRO_UNKNOWN:
+  default:
+    fs->package_format = OS_PACKAGE_FORMAT_UNKNOWN;
+    break;
+  }
+}
+
+static void
+check_package_management (guestfs_h *g, struct inspect_fs *fs)
+{
+  switch (fs->distro) {
+  case OS_DISTRO_FEDORA:
+  case OS_DISTRO_MEEGO:
+    fs->package_management = OS_PACKAGE_MANAGEMENT_YUM;
+    break;
+
+  case OS_DISTRO_REDHAT_BASED:
+  case OS_DISTRO_RHEL:
+    if (fs->major_version >= 5)
+      fs->package_management = OS_PACKAGE_MANAGEMENT_YUM;
+    else
+      fs->package_management = OS_PACKAGE_MANAGEMENT_UP2DATE;
+    break;
+
+  case OS_DISTRO_DEBIAN:
+  case OS_DISTRO_UBUNTU:
+    fs->package_management = OS_PACKAGE_MANAGEMENT_APT;
+    break;
+
+  case OS_DISTRO_ARCHLINUX:
+    fs->package_management = OS_PACKAGE_MANAGEMENT_PACMAN;
+    break;
+  case OS_DISTRO_GENTOO:
+    fs->package_management = OS_PACKAGE_MANAGEMENT_PORTAGE;
+    break;
+  case OS_DISTRO_PARDUS:
+    fs->package_management = OS_PACKAGE_MANAGEMENT_PISI;
+    break;
+
+  case OS_DISTRO_WINDOWS:
+  case OS_DISTRO_UNKNOWN:
+  default:
+    fs->package_management = OS_PACKAGE_MANAGEMENT_UNKNOWN;
+    break;
+  }
+}
+
 static struct inspect_fs *
 search_for_root (guestfs_h *g, const char *root)
 {
@@ -1194,6 +1286,53 @@ guestfs__inspect_get_filesystems (guestfs_h *g, const char *root)
   return ret;
 }
 
+char *
+guestfs__inspect_get_package_format (guestfs_h *g, const char *root)
+{
+  struct inspect_fs *fs = search_for_root (g, root);
+  if (!fs)
+    return NULL;
+
+  char *ret;
+  switch (fs->package_format) {
+  case OS_PACKAGE_FORMAT_RPM: ret = safe_strdup (g, "rpm"); break;
+  case OS_PACKAGE_FORMAT_DEB: ret = safe_strdup (g, "deb"); break;
+  case OS_PACKAGE_FORMAT_PACMAN: ret = safe_strdup (g, "pacman"); break;
+  case OS_PACKAGE_FORMAT_EBUILD: ret = safe_strdup (g, "ebuild"); break;
+  case OS_PACKAGE_FORMAT_PISI: ret = safe_strdup (g, "pisi"); break;
+  case OS_PACKAGE_FORMAT_UNKNOWN:
+  default:
+    ret = safe_strdup (g, "unknown");
+    break;
+  }
+
+  return ret;
+}
+
+char *
+guestfs__inspect_get_package_management (guestfs_h *g, const char *root)
+{
+  struct inspect_fs *fs = search_for_root (g, root);
+  if (!fs)
+    return NULL;
+
+  char *ret;
+  switch (fs->package_management) {
+  case OS_PACKAGE_MANAGEMENT_YUM: ret = safe_strdup (g, "yum"); break;
+  case OS_PACKAGE_MANAGEMENT_UP2DATE: ret = safe_strdup (g, "up2date"); break;
+  case OS_PACKAGE_MANAGEMENT_APT: ret = safe_strdup (g, "apt"); break;
+  case OS_PACKAGE_MANAGEMENT_PACMAN: ret = safe_strdup (g, "pacman"); break;
+  case OS_PACKAGE_MANAGEMENT_PORTAGE: ret = safe_strdup (g, "portage"); break;
+  case OS_PACKAGE_MANAGEMENT_PISI: ret = safe_strdup (g, "pisi"); break;
+  case OS_PACKAGE_MANAGEMENT_UNKNOWN:
+  default:
+    ret = safe_strdup (g, "unknown");
+    break;
+  }
+
+  return ret;
+}
+
 #else /* no PCRE or hivex at compile time */
 
 /* XXX These functions should be in an optgroup. */
@@ -1268,6 +1407,18 @@ guestfs__inspect_get_filesystems (guestfs_h *g, const char *root)
   NOT_IMPL(NULL);
 }
 
+char *
+guestfs__inspect_get_package_format (guestfs_h *g, const char *root)
+{
+  NOT_IMPL(NULL);
+}
+
+char *
+guestfs__inspect_get_package_management (guestfs_h *g, const char *root)
+{
+  NOT_IMPL(NULL);
+}
+
 #endif /* no PCRE or hivex at compile time */
 
 void
@@ -1380,4 +1531,29 @@ guestfs___match2 (guestfs_h *g, const char *str, const pcre *re,
   return 1;
 }
 
+/* Match a regular expression which contains exactly three captures. */
+int
+guestfs___match3 (guestfs_h *g, const char *str, const pcre *re,
+                  char **ret1, char **ret2, char **ret3)
+{
+  size_t len = strlen (str);
+  int vec[30], r;
+
+  r = pcre_exec (re, NULL, str, len, 0, 0, vec, 30);
+  if (r == PCRE_ERROR_NOMATCH)
+    return 0;
+  if (r != 4) {
+    /* Internal error -- should not happen. */
+    fprintf (stderr, "libguestfs: %s: %s: internal error: pcre_exec returned unexpected error code %d when matching against the string \"%s\"\n",
+             __FILE__, __func__, r, str);
+    return 0;
+  }
+
+  *ret1 = safe_strndup (g, &str[vec[2]], vec[3]-vec[2]);
+  *ret2 = safe_strndup (g, &str[vec[4]], vec[5]-vec[4]);
+  *ret3 = safe_strndup (g, &str[vec[6]], vec[7]-vec[6]);
+
+  return 1;
+}
+
 #endif /* HAVE_PCRE */