コード例 #1
0
ファイル: inspect-fs-unix.c プロジェクト: jadbox/libguestfs
/* Try several methods to determine the hostname from a Linux or
 * FreeBSD guest.  Note that type and distro have been set, so we can
 * use that information to direct the search.
 */
static int
check_hostname_unix (guestfs_h *g, struct inspect_fs *fs)
{
  switch (fs->type) {
  case OS_TYPE_LINUX:
  case OS_TYPE_HURD:
    /* Red Hat-derived would be in /etc/sysconfig/network or
     * /etc/hostname (RHEL 7+, F18+).  Debian-derived in the file
     * /etc/hostname.  Very old Debian and SUSE use /etc/HOSTNAME.
     * It's best to just look for each of these files in turn, rather
     * than try anything clever based on distro.
     */
    if (guestfs_is_file (g, "/etc/HOSTNAME")) {
      fs->hostname = guestfs___first_line_of_file (g, "/etc/HOSTNAME");
      if (fs->hostname == NULL)
        return -1;
      if (STREQ (fs->hostname, "")) {
        free (fs->hostname);
        fs->hostname = NULL;
      }
    }

    if (!fs->hostname && guestfs_is_file (g, "/etc/hostname")) {
      fs->hostname = guestfs___first_line_of_file (g, "/etc/hostname");
      if (fs->hostname == NULL)
        return -1;
      if (STREQ (fs->hostname, "")) {
        free (fs->hostname);
        fs->hostname = NULL;
      }
    }

    if (!fs->hostname && guestfs_is_file (g, "/etc/sysconfig/network")) {
      const char *configfiles[] = { "/etc/sysconfig/network", NULL };
      if (inspect_with_augeas (g, fs, configfiles,
                               check_hostname_redhat) == -1)
        return -1;
    }
    break;

  case OS_TYPE_FREEBSD:
  case OS_TYPE_NETBSD:
    /* /etc/rc.conf contains the hostname, but there is no Augeas lens
     * for this file.
     */
    if (guestfs_is_file (g, "/etc/rc.conf")) {
      if (check_hostname_freebsd (g, fs) == -1)
        return -1;
    }
    break;

  case OS_TYPE_WINDOWS: /* not here, see check_windows_system_registry */
  case OS_TYPE_DOS:
  case OS_TYPE_OPENBSD:
  case OS_TYPE_UNKNOWN:
    /* nothing */;
  }

  return 0;
}
コード例 #2
0
/* There are several sources we might use:
 * - /ProgramData/Microsoft/Windows Live/WLive48x48.png
 * - w-brand.png (in a very long directory name)
 * - /Windows/System32/slui.exe --type=14 group icon #2
 */
static char *
icon_windows_8 (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
{
  CLEANUP_FREE char *filename_case = NULL;
  CLEANUP_FREE char *filename_downloaded = NULL;
  int r;
  char *ret;

  filename_case = guestfs___case_sensitive_path_silently
    (g, "/ProgramData/Microsoft/Windows Live/WLive48x48.png");
  if (filename_case == NULL)
    return NOT_FOUND; /* Not an error since a parent dir might not exist. */

  guestfs_push_error_handler (g, NULL, NULL);
  r = guestfs_is_file (g, filename_case);
  guestfs_pop_error_handler (g);
  if (r == -1)
    return NULL;
  if (r == 0)
    return NOT_FOUND;

  filename_downloaded = guestfs___download_to_tmp (g, fs, filename_case,
                                                   "wlive48x48.png", 8192);
  if (filename_downloaded == NULL)
    return NOT_FOUND;

  if (read_whole_file (g, filename_downloaded, &ret, size_r) == -1)
    return NULL;

  return ret;
}
コード例 #3
0
ファイル: inspect-fs-unix.c プロジェクト: jadbox/libguestfs
static void
check_architecture (guestfs_h *g, struct inspect_fs *fs)
{
  const char *binaries[] =
    { "/bin/bash", "/bin/ls", "/bin/echo", "/bin/rm", "/bin/sh" };
  size_t i;
  char *arch;

  for (i = 0; i < sizeof binaries / sizeof binaries[0]; ++i) {
    if (guestfs_is_file (g, binaries[i]) > 0) {
      /* Ignore errors from file_architecture call. */
      guestfs_push_error_handler (g, NULL, NULL);
      arch = guestfs_file_architecture (g, binaries[i]);
      guestfs_pop_error_handler (g);

      if (arch) {
        /* String will be owned by handle, freed by
         * guestfs___free_inspect_info.
         */
        fs->arch = arch;
        break;
      }
    }
  }
}
コード例 #4
0
ファイル: inspect-fs-cd.c プロジェクト: msmhrt/libguestfs
/* The currently mounted device is very likely to be an installer. */
int
guestfs___check_installer_root (guestfs_h *g, struct inspect_fs *fs)
{
  /* The presence of certain files indicates a live CD.
   *
   * XXX Fedora netinst contains a ~120MB squashfs called
   * /images/install.img.  However this is not a live CD (unlike the
   * Fedora live CDs which contain the same, but larger file).  We
   * need to unpack this and look inside to tell the difference.
   */
  if (guestfs_is_file (g, "/casper/filesystem.squashfs") > 0)
    fs->is_live_disk = 1;

  /* Debian/Ubuntu. */
  if (guestfs_is_file (g, "/.disk/info") > 0) {
    if (check_debian_installer_root (g, fs) == -1)
      return -1;
  }

  /* Fedora CDs and DVD (not netinst). */
  else if (guestfs_is_file (g, "/.treeinfo") > 0) {
    if (check_fedora_installer_root (g, fs) == -1)
      return -1;
  }

  /* FreeDOS install CD. */
  else if (guestfs_is_file (g, "/freedos/freedos.ico") > 0 &&
           guestfs_is_file (g, "/setup.bat") > 0) {
    fs->type = OS_TYPE_DOS;
    fs->distro = OS_DISTRO_FREEDOS;
    fs->arch = safe_strdup (g, "i386");
  }

  /* Linux with /isolinux/isolinux.cfg (note that non-Linux can use
   * ISOLINUX too, eg. FreeDOS).
   */
  else if (guestfs_is_file (g, "/isolinux/isolinux.cfg") > 0) {
    if (check_isolinux_installer_root (g, fs) == -1)
      return -1;
  }

  /* Windows 2003 64 bit */
  else if (guestfs_is_file (g, "/amd64/txtsetup.sif") > 0) {
    fs->arch = safe_strdup (g, "x86_64");
    if (check_w2k3_installer_root (g, fs, "/amd64/txtsetup.sif") == -1)
      return -1;
  }

  /* Windows 2003 32 bit */
  else if (guestfs_is_file (g, "/i386/txtsetup.sif") > 0) {
    fs->arch = safe_strdup (g, "i386");
    if (check_w2k3_installer_root (g, fs, "/i386/txtsetup.sif") == -1)
      return -1;
  }

  return 0;
}
コード例 #5
0
int
guestfs_int_is_file_nocase (guestfs_h *g, const char *path)
{
  CLEANUP_FREE char *p = NULL;
  int r;

  p = guestfs_int_case_sensitive_path_silently (g, path);
  if (!p)
    return 0;
  r = guestfs_is_file (g, p);
  return r > 0;
}
コード例 #6
0
static char *
icon_windows_7 (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
{
  CLEANUP_FREE char *filename = NULL;
  CLEANUP_FREE char *filename_case = NULL;
  CLEANUP_FREE char *filename_downloaded = NULL;
  CLEANUP_FREE char *pngfile = NULL;
  CLEANUP_CMD_CLOSE struct command *cmd = guestfs___new_command (g);
  int r;
  char *ret;

  /* Download %systemroot%\explorer.exe */
  filename = safe_asprintf (g, "%s/explorer.exe", fs->windows_systemroot);
  filename_case = guestfs_case_sensitive_path (g, filename);
  if (filename_case == NULL)
    return NULL;

  guestfs_push_error_handler (g, NULL, NULL);
  r = guestfs_is_file (g, filename_case);
  guestfs_pop_error_handler (g);
  if (r == -1)
    return NULL;
  if (r == 0)
    return NOT_FOUND;

  filename_downloaded = guestfs___download_to_tmp (g, fs, filename_case,
                                                   "explorer.exe",
                                                   MAX_WINDOWS_EXPLORER_SIZE);
  if (filename_downloaded == NULL)
    return NOT_FOUND;

  pngfile = safe_asprintf (g, "%s/windows-7-icon.png", g->tmpdir);

  guestfs___cmd_add_string_unquoted (cmd, WRESTOOL " -x --type=2 --name=6801 ");
  guestfs___cmd_add_string_quoted   (cmd, filename_downloaded);
  guestfs___cmd_add_string_unquoted (cmd,
                                     " | " BMPTOPNM " | "
                                     PAMCUT " -bottom 54 | "
                                     PNMTOPNG " > ");
  guestfs___cmd_add_string_quoted   (cmd, pngfile);
  r = guestfs___cmd_run (cmd);
  if (r == -1)
    return NULL;
  if (!WIFEXITED (r) || WEXITSTATUS (r) != 0)
    return NOT_FOUND;

  if (read_whole_file (g, pngfile, &ret, size_r) == -1)
    return NULL;

  return ret;
}
コード例 #7
0
ファイル: inspect_fs_cd.c プロジェクト: mdbooth/libguestfs
/* Debian/Ubuntu install disks are easy ...
 *
 * These files are added by the debian-cd program, and it is worth
 * looking at the source code to determine exact values, in
 * particular '/usr/share/debian-cd/tools/start_new_disc'
 *
 * XXX Architecture?  We could parse it out of the product name
 * string, but that seems quite hairy.  We could look for the names
 * of packages.  Also note that some Debian install disks are
 * multiarch.
 */
static int
check_debian_installer_root (guestfs_h *g, struct inspect_fs *fs)
{
  fs->product_name = guestfs___first_line_of_file (g, "/.disk/info");
  if (!fs->product_name)
    return -1;

  fs->type = OS_TYPE_LINUX;
  if (STRPREFIX (fs->product_name, "Ubuntu"))
    fs->distro = OS_DISTRO_UBUNTU;
  else if (STRPREFIX (fs->product_name, "Debian"))
    fs->distro = OS_DISTRO_DEBIAN;

  (void) guestfs___parse_major_minor (g, fs);

  if (guestfs_is_file (g, "/.disk/cd_type") > 0) {
    char *cd_type = guestfs___first_line_of_file (g, "/.disk/cd_type");
    if (!cd_type)
      return -1;

    if (STRPREFIX (cd_type, "dvd/single") ||
        STRPREFIX (cd_type, "full_cd/single")) {
      fs->is_multipart_disk = 0;
      fs->is_netinst_disk = 0;
    }
    else if (STRPREFIX (cd_type, "dvd") ||
             STRPREFIX (cd_type, "full_cd")) {
      fs->is_multipart_disk = 1;
      fs->is_netinst_disk = 0;
    }
    else if (STRPREFIX (cd_type, "not_complete")) {
      fs->is_multipart_disk = 0;
      fs->is_netinst_disk = 1;
    }

    free (cd_type);
  }

  return 0;
}
コード例 #8
0
static int
check_filesystem (guestfs_h *g, const char *mountable,
                  const struct guestfs_internal_mountable *m,
                  int whole_device)
{
  int partnum = -1, nr_partitions = -1;
  /* Not CLEANUP_FREE, as it will be cleaned up with inspection info */
  char *windows_systemroot = NULL;

  extend_fses (g);

  if (!whole_device && m->im_type == MOUNTABLE_DEVICE &&
      guestfs_int_is_partition (g, m->im_device)) {
    if (get_partition_context (g, m->im_device,
                               &partnum, &nr_partitions) == -1)
      return -1;
  }

  struct inspect_fs *fs = &g->fses[g->nr_fses-1];

  fs->mountable = safe_strdup (g, mountable);

  /* Optimize some of the tests by avoiding multiple tests of the same thing. */
  const int is_dir_etc = guestfs_is_dir (g, "/etc") > 0;
  const int is_dir_bin = guestfs_is_dir (g, "/bin") > 0;
  const 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 ||
      guestfs_is_file (g, "/grub2/grub.cfg") > 0)
    ;
  /* FreeBSD root? */
  else if (is_dir_etc &&
           is_dir_bin &&
           guestfs_is_file (g, "/etc/freebsd-update.conf") > 0 &&
           guestfs_is_file (g, "/etc/fstab") > 0) {
    fs->role = OS_ROLE_ROOT;
    fs->format = OS_FORMAT_INSTALLED;
    if (guestfs_int_check_freebsd_root (g, fs) == -1)
      return -1;
  }
  /* NetBSD root? */
  else if (is_dir_etc &&
           is_dir_bin &&
           guestfs_is_file (g, "/netbsd") > 0 &&
           guestfs_is_file (g, "/etc/fstab") > 0 &&
           guestfs_is_file (g, "/etc/release") > 0) {
    fs->role = OS_ROLE_ROOT;
    fs->format = OS_FORMAT_INSTALLED;
    if (guestfs_int_check_netbsd_root (g, fs) == -1)
      return -1;
  }
  /* OpenBSD root? */
  else if (is_dir_etc &&
           is_dir_bin &&
           guestfs_is_file (g, "/bsd") > 0 &&
           guestfs_is_file (g, "/etc/fstab") > 0 &&
           guestfs_is_file (g, "/etc/motd") > 0) {
    fs->role = OS_ROLE_ROOT;
    fs->format = OS_FORMAT_INSTALLED;
    if (guestfs_int_check_openbsd_root (g, fs) == -1)
      return -1;
  }
  /* Hurd root? */
  else if (guestfs_is_file (g, "/hurd/console") > 0 &&
           guestfs_is_file (g, "/hurd/hello") > 0 &&
           guestfs_is_file (g, "/hurd/null") > 0) {
    fs->role = OS_ROLE_ROOT;
    fs->format = OS_FORMAT_INSTALLED; /* XXX could be more specific */
    if (guestfs_int_check_hurd_root (g, fs) == -1)
      return -1;
  }
  /* Minix root? */
  else if (is_dir_etc &&
           is_dir_bin &&
           guestfs_is_file (g, "/service/vm") > 0 &&
           guestfs_is_file (g, "/etc/fstab") > 0 &&
           guestfs_is_file (g, "/etc/version") > 0) {
    fs->role = OS_ROLE_ROOT;
    fs->format = OS_FORMAT_INSTALLED;
    if (guestfs_int_check_minix_root (g, fs) == -1)
      return -1;
  }
  /* Linux root? */
  else if (is_dir_etc &&
           (is_dir_bin ||
            is_symlink_to (g, "/bin", "usr/bin") > 0) &&
           (guestfs_is_file (g, "/etc/fstab") > 0 ||
            guestfs_is_file (g, "/etc/hosts") > 0)) {
    fs->role = OS_ROLE_ROOT;
    fs->format = OS_FORMAT_INSTALLED;
    if (guestfs_int_check_linux_root (g, fs) == -1)
      return -1;
  }
  /* CoreOS root? */
  else if (is_dir_etc &&
           guestfs_is_dir (g, "/root") > 0 &&
           guestfs_is_dir (g, "/home") > 0 &&
           guestfs_is_dir (g, "/usr") > 0 &&
           guestfs_is_file (g, "/etc/coreos/update.conf") > 0) {
    fs->role = OS_ROLE_ROOT;
    fs->format = OS_FORMAT_INSTALLED;
    if (guestfs_int_check_coreos_root (g, fs) == -1)
      return -1;
  }
  /* Linux /usr/local? */
  else if (is_dir_etc &&
           is_dir_bin &&
           is_dir_share &&
           guestfs_is_dir (g, "/local") == 0 &&
           guestfs_is_file (g, "/etc/fstab") == 0)
    ;
  /* Linux /usr? */
  else if (is_dir_etc &&
           is_dir_bin &&
           is_dir_share &&
           guestfs_is_dir (g, "/local") > 0 &&
           guestfs_is_file (g, "/etc/fstab") == 0) {
    if (guestfs_int_check_linux_usr (g, fs) == -1)
      return -1;
  }
  /* CoreOS /usr? */
  else if (is_dir_bin &&
           is_dir_share &&
           guestfs_is_dir (g, "/local") > 0 &&
           guestfs_is_dir (g, "/share/coreos") > 0) {
    if (guestfs_int_check_coreos_usr (g, fs) == -1)
      return -1;
  }
  /* Linux /var? */
  else if (guestfs_is_dir (g, "/log") > 0 &&
           guestfs_is_dir (g, "/run") > 0 &&
           guestfs_is_dir (g, "/spool") > 0)
    ;
  /* Windows root? */
  else if ((windows_systemroot = guestfs_int_get_windows_systemroot (g)) != NULL)
    {
      fs->role = OS_ROLE_ROOT;
      fs->format = OS_FORMAT_INSTALLED;
      if (guestfs_int_check_windows_root (g, fs, windows_systemroot) == -1)
	return -1;
    }
  /* Windows volume with installed applications (but not root)? */
  else if (guestfs_int_is_dir_nocase (g, "/System Volume Information") > 0 &&
           guestfs_int_is_dir_nocase (g, "/Program Files") > 0)
    ;
  /* Windows volume (but not root)? */
  else if (guestfs_int_is_dir_nocase (g, "/System Volume Information") > 0)
    ;
  /* FreeDOS? */
  else if (guestfs_int_is_dir_nocase (g, "/FDOS") > 0 &&
           guestfs_int_is_file_nocase (g, "/FDOS/FREEDOS.BSS") > 0) {
    fs->role = OS_ROLE_ROOT;
    fs->format = OS_FORMAT_INSTALLED;
    fs->type = OS_TYPE_DOS;
    fs->distro = OS_DISTRO_FREEDOS;
    /* FreeDOS is a mix of 16 and 32 bit, but assume it requires a
     * 32 bit i386 processor.
     */
    fs->arch = safe_strdup (g, "i386");
  }
  /* Install CD/disk?
   *
   * Note that we checked (above) for an install ISO, but there are
   * other types of install image (eg. USB keys) which that check
   * wouldn't have picked up.
   *
   * Skip these checks if it's not a whole device (eg. CD) or the
   * first partition (eg. bootable USB key).
   */
  else if ((whole_device || (partnum == 1 && nr_partitions == 1)) &&
           (guestfs_is_file (g, "/isolinux/isolinux.cfg") > 0 ||
            guestfs_is_dir (g, "/EFI/BOOT") > 0 ||
            guestfs_is_file (g, "/images/install.img") > 0 ||
            guestfs_is_dir (g, "/.disk") > 0 ||
            guestfs_is_file (g, "/.discinfo") > 0 ||
            guestfs_is_file (g, "/i386/txtsetup.sif") > 0 ||
            guestfs_is_file (g, "/amd64/txtsetup.sif") > 0 ||
            guestfs_is_file (g, "/freedos/freedos.ico") > 0 ||
            guestfs_is_file (g, "/boot/loader.rc") > 0)) {
    fs->role = OS_ROLE_ROOT;
    fs->format = OS_FORMAT_INSTALLER;
    if (guestfs_int_check_installer_root (g, fs) == -1)
      return -1;
  }

  /* The above code should have set fs->type and fs->distro fields, so
   * we can now guess the package management system.
   */
  guestfs_int_check_package_format (g, fs);
  guestfs_int_check_package_management (g, fs);

  return 0;
}
コード例 #9
0
ファイル: copy.c プロジェクト: msmhrt/libguestfs
int
run_copy_out (const char *cmd, size_t argc, char *argv[])
{
    if (argc < 2) {
        fprintf (stderr,
                 _("use 'copy-out <remote> [<remote>...] <localdir>' to copy files out of the image\n"));
        return -1;
    }

    /* Local directory is always the last arg. */
    const char *local = argv[argc-1];
    int nr_remotes = argc-1;

    struct stat statbuf;
    if (stat (local, &statbuf) == -1 ||
            ! (S_ISDIR (statbuf.st_mode))) {
        fprintf (stderr, _("copy-out: target '%s' is not a directory\n"), local);
        return -1;
    }

    /* Download each remote one at a time using tar-out. */
    int i, r;
    for (i = 0; i < nr_remotes; ++i) {
        char *remote = argv[i];

        /* Allow win:... prefix on remotes. */
        remote = win_prefix (remote);
        if (remote == NULL)
            return -1;

        /* If the remote is a file, download it.  If it's a directory,
         * create the directory in local first before using tar-out.
         */
        r = guestfs_is_file (g, remote);
        if (r == -1) {
            free (remote);
            return -1;
        }
        if (r == 1) {               /* is file */
            char buf[PATH_MAX];
            const char *basename;
            if (split_path (buf, sizeof buf, remote, NULL, &basename) == -1) {
                free (remote);
                return -1;
            }

            char filename[PATH_MAX];
            snprintf (filename, sizeof filename, "%s/%s", local, basename);
            if (guestfs_download (g, remote, filename) == -1) {
                free (remote);
                return -1;
            }
        }
        else {                      /* not a regular file */
            r = guestfs_is_dir (g, remote);
            if (r == -1) {
                free (remote);
                return -1;
            }

            if (r == 0) {
                fprintf (stderr, _("copy-out: '%s' is not a file or directory\n"),
                         remote);
                free (remote);
                return -1;
            }

            char buf[PATH_MAX];
            const char *basename;
            if (split_path (buf, sizeof buf, remote, NULL, &basename) == -1) {
                free (remote);
                return -1;
            }

            struct fd_pid fdpid = make_tar_output (local, basename);
            if (fdpid.fd == -1) {
                free (remote);
                return -1;
            }

            char fdbuf[64];
            snprintf (fdbuf, sizeof fdbuf, "/dev/fd/%d", fdpid.fd);

            int r = guestfs_tar_out (g, remote, fdbuf);

            if (close (fdpid.fd) == -1) {
                perror ("close (tar-output subprocess)");
                free (remote);
                r = -1;
            }

            int status;
            if (waitpid (fdpid.pid, &status, 0) == -1) {
                perror ("wait (tar-output subprocess)");
                free (remote);
                return -1;
            }
            if (!(WIFEXITED (status) && WEXITSTATUS (status) == 0)) {
                free (remote);
                return -1;
            }

            if (r == -1) {
                free (remote);
                return -1;
            }
        }

        free (remote);
    }

    return 0;
}
コード例 #10
0
static int
check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
{
  int r;
  size_t len = strlen (fs->windows_systemroot) + 64;
  char system[len];
  snprintf (system, len, "%s/system32/config/system",
            fs->windows_systemroot);

  CLEANUP_FREE char *system_path = guestfs_case_sensitive_path (g, system);
  if (!system_path)
    return -1;

  r = guestfs_is_file (g, system_path);
  if (r == -1)
    return -1;
  /* If the system hive doesn't exist, just accept that we cannot
   * find hostname etc.
   */
  if (r == 0)
    return 0;

  int ret = -1;
  int64_t root, node, value;
  CLEANUP_FREE_HIVEX_VALUE_LIST struct guestfs_hivex_value_list *values = NULL;
  CLEANUP_FREE_HIVEX_VALUE_LIST struct guestfs_hivex_value_list *values2 = NULL;
  int32_t dword;
  size_t i, count;
  CLEANUP_FREE void *buf = NULL;
  size_t buflen;
  const char *hivepath[] =
    { NULL /* current control set */, "Services", "Tcpip", "Parameters" };

  if (guestfs_hivex_open (g, system_path,
                          GUESTFS_HIVEX_OPEN_VERBOSE, g->verbose, -1) == -1)
    goto out;

  root = guestfs_hivex_root (g);
  if (root == 0)
    goto out;

  /* Get the CurrentControlSet. */
  node = guestfs_hivex_node_get_child (g, root, "Select");
  if (node == -1)
    goto out;

  if (node == 0) {
    error (g, "hivex: could not locate HKLM\\SYSTEM\\Select");
    goto out;
  }

  value = guestfs_hivex_node_get_value (g, node, "Current");
  if (value == -1)
    goto out;

  if (value == 0) {
    error (g, "hivex: HKLM\\System\\Select Default entry not found");
    goto out;
  }

  /* XXX Should check the type. */
  buf = guestfs_hivex_value_value (g, value, &buflen);
  if (buflen != 4) {
    error (g, "hivex: HKLM\\System\\Select\\Current expected to be DWORD");
    goto out;
  }
  dword = le32toh (*(int32_t *)buf);
  fs->windows_current_control_set = safe_asprintf (g, "ControlSet%03d", dword);

  /* Get the drive mappings.
   * This page explains the contents of HKLM\System\MountedDevices:
   * http://www.goodells.net/multiboot/partsigs.shtml
   */
  node = guestfs_hivex_node_get_child (g, root, "MountedDevices");
  if (node == -1)
    goto out;

  if (node == 0)
    /* Not found: skip getting drive letter mappings (RHBZ#803664). */
    goto skip_drive_letter_mappings;

  values = guestfs_hivex_node_values (g, node);

  /* Count how many DOS drive letter mappings there are.  This doesn't
   * ignore removable devices, so it overestimates, but that doesn't
   * matter because it just means we'll allocate a few bytes extra.
   */
  for (i = count = 0; i < values->len; ++i) {
    CLEANUP_FREE char *key =
      guestfs_hivex_value_key (g, values->val[i].hivex_value_h);
    if (key == NULL)
      goto out;
    if (STRCASEEQLEN (key, "\\DosDevices\\", 12) &&
        c_isalpha (key[12]) && key[13] == ':')
      count++;
  }

  fs->drive_mappings = safe_calloc (g, 2*count + 1, sizeof (char *));

  for (i = count = 0; i < values->len; ++i) {
    int64_t v = values->val[i].hivex_value_h;
    CLEANUP_FREE char *key = guestfs_hivex_value_key (g, v);
    if (key == NULL)
      goto out;
    if (STRCASEEQLEN (key, "\\DosDevices\\", 12) &&
        c_isalpha (key[12]) && key[13] == ':') {
      /* Get the binary value.  Is it a fixed disk? */
      CLEANUP_FREE char *blob = NULL;
      char *device;
      size_t len;
      int64_t type;

      type = guestfs_hivex_value_type (g, v);
      blob = guestfs_hivex_value_value (g, v, &len);
      if (blob != NULL && type == 3 && len == 12) {
        /* Try to map the blob to a known disk and partition. */
        device = map_registry_disk_blob (g, blob);
        if (device != NULL) {
          fs->drive_mappings[count++] = safe_strndup (g, &key[12], 1);
          fs->drive_mappings[count++] = device;
        }
      }
    }
  }

 skip_drive_letter_mappings:;
  /* Get the hostname. */
  hivepath[0] = fs->windows_current_control_set;
  for (node = root, i = 0;
       node > 0 && i < sizeof hivepath / sizeof hivepath[0];
       ++i) {
    node = guestfs_hivex_node_get_child (g, node, hivepath[i]);
  }

  if (node == -1)
    goto out;

  if (node == 0) {
    perrorf (g, "hivex: cannot locate HKLM\\SYSTEM\\%s\\Services\\Tcpip\\Parameters",
             fs->windows_current_control_set);
    goto out;
  }

  values2 = guestfs_hivex_node_values (g, node);
  if (values2 == NULL)
    goto out;

  for (i = 0; i < values2->len; ++i) {
    int64_t v = values2->val[i].hivex_value_h;
    CLEANUP_FREE char *key = guestfs_hivex_value_key (g, v);
    if (key == NULL)
      goto out;

    if (STRCASEEQ (key, "Hostname")) {
      fs->hostname = guestfs_hivex_value_utf8 (g, v);
      if (!fs->hostname)
        goto out;
    }
    /* many other interesting fields here ... */
  }

  ret = 0;

 out:
  guestfs_hivex_close (g);

  return ret;
}
コード例 #11
0
/* At the moment, pull just the ProductName and version numbers from
 * the registry.  In future there is a case for making many more
 * registry fields available to callers.
 */
static int
check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs)
{
  int ret = -1;
  int r;

  size_t len = strlen (fs->windows_systemroot) + 64;
  char software[len];
  snprintf (software, len, "%s/system32/config/software",
            fs->windows_systemroot);

  CLEANUP_FREE char *software_path = guestfs_case_sensitive_path (g, software);
  if (!software_path)
    return -1;

  r = guestfs_is_file (g, software_path);
  if (r == -1)
    return -1;
  /* If the software hive doesn't exist, just accept that we cannot
   * find product_name etc.
   */
  if (r == 0)
    return 0;

  int64_t node;
  const char *hivepath[] =
    { "Microsoft", "Windows NT", "CurrentVersion" };
  size_t i;
  CLEANUP_FREE_HIVEX_VALUE_LIST struct guestfs_hivex_value_list *values = NULL;

  if (guestfs_hivex_open (g, software_path,
                          GUESTFS_HIVEX_OPEN_VERBOSE, g->verbose, -1) == -1)
    return -1;

  node = guestfs_hivex_root (g);
  for (i = 0; node > 0 && i < sizeof hivepath / sizeof hivepath[0]; ++i)
    node = guestfs_hivex_node_get_child (g, node, hivepath[i]);

  if (node == -1)
    goto out;

  if (node == 0) {
    perrorf (g, "hivex: cannot locate HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
    goto out;
  }

  values = guestfs_hivex_node_values (g, node);

  for (i = 0; i < values->len; ++i) {
    int64_t value = values->val[i].hivex_value_h;
    CLEANUP_FREE char *key = guestfs_hivex_value_key (g, value);
    if (key == NULL)
      goto out;

    if (STRCASEEQ (key, "ProductName")) {
      fs->product_name = guestfs_hivex_value_utf8 (g, value);
      if (!fs->product_name)
        goto out;
    }
    else if (STRCASEEQ (key, "CurrentVersion")) {
      CLEANUP_FREE char *version = guestfs_hivex_value_utf8 (g, value);
      if (!version)
        goto out;
      char *major, *minor;
      if (match2 (g, version, re_windows_version, &major, &minor)) {
        fs->major_version = guestfs___parse_unsigned_int (g, major);
        free (major);
        if (fs->major_version == -1) {
          free (minor);
          goto out;
        }
        fs->minor_version = guestfs___parse_unsigned_int (g, minor);
        free (minor);
        if (fs->minor_version == -1)
          goto out;
      }
    }
    else if (STRCASEEQ (key, "InstallationType")) {
      fs->product_variant = guestfs_hivex_value_utf8 (g, value);
      if (!fs->product_variant)
        goto out;
    }
  }

  ret = 0;

 out:
  guestfs_hivex_close (g);

  return ret;
}
コード例 #12
0
char *
guestfs___get_windows_systemroot (guestfs_h *g)
{
  /* Check a predefined list of common windows system root locations */
  static const char *systemroots[] =
    { "/windows", "/winnt", "/win32", "/win", NULL };

  for (size_t i = 0; i < sizeof systemroots / sizeof systemroots[0]; ++i) {
    char *systemroot =
      guestfs___case_sensitive_path_silently (g, systemroots[i]);
    if (!systemroot)
      continue;

    if (is_systemroot (g, systemroot)) {
      debug (g, "windows %%SYSTEMROOT%% = %s", systemroot);

      return systemroot;
    } else {
      free (systemroot);
    }
  }

  /* If the fs contains boot.ini, check it for non-standard
   * systemroot locations */
  CLEANUP_FREE char *boot_ini_path =
    guestfs___case_sensitive_path_silently (g, "/boot.ini");
  if (boot_ini_path && guestfs_is_file (g, boot_ini_path) > 0) {
    CLEANUP_FREE_STRING_LIST char **boot_ini =
      guestfs_read_lines (g, boot_ini_path);
    if (!boot_ini) {
      debug (g, "error reading %s", boot_ini_path);
      return NULL;
    }

    int found_os = 0;
    for (char **i = boot_ini; *i != NULL; i++) {
      CLEANUP_FREE char *controller_type = NULL;
      CLEANUP_FREE char *controller = NULL;
      CLEANUP_FREE char *disk = NULL;
      CLEANUP_FREE char *rdisk = NULL;
      CLEANUP_FREE char *partition = NULL;
      CLEANUP_FREE char *path = NULL;

      char *line = *i;

      if (!found_os) {
        if (match (g, line, re_boot_ini_os_header)) {
          found_os = 1;
          continue;
        }
      }

      /* See http://support.microsoft.com/kb/102873 for a discussion
       * of what this line means */
      if (match6 (g, line, re_boot_ini_os, &controller_type,
                  &controller, &disk, &rdisk, &partition, &path))
      {
        /* The Windows system root may be on any disk. However, there
         * are currently (at least) 2 practical problems preventing us
         * from locating it on another disk:
         *
         * 1. We don't have enough metadata about the disks we were
         * given to know if what controller they were on and what
         * index they had.
         *
         * 2. The way inspection of filesystems currently works, we
         * can't mark another filesystem, which we may have already
         * inspected, to be inspected for a specific Windows system
         * root.
         *
         * Solving 1 properly would require a new API at a minimum. We
         * might be able to fudge something practical without this,
         * though, e.g. by looking at the <partition>th partition of
         * every disk for the specific windows root.
         *
         * Solving 2 would probably require a significant refactoring
         * of the way filesystems are inspected. We should probably do
         * this some time.
         *
         * For the moment, we ignore all partition information and
         * assume the system root is on the current partition. In
         * practice, this will normally be correct.
         */

        /* Swap backslashes for forward slashes in the system root
         * path */
        for (char *j = path; *j != '\0'; j++) {
          if (*j == '\\') *j = '/';
        }

        char *systemroot = guestfs___case_sensitive_path_silently (g, path);
        if (systemroot && is_systemroot (g, systemroot)) {
          debug (g, "windows %%SYSTEMROOT%% = %s", systemroot);

          return systemroot;
        } else {
          free (systemroot);
        }
      }
    }
  }

  return NULL; /* not found */
}
コード例 #13
0
ファイル: inspect-vm.c プロジェクト: AlphaStaxLLC/libguestfs
int
main (int argc, char *argv[])
{
  guestfs_h *g;
  const char *disk;
  char **roots, *root, *str, **mountpoints, **lines;
  size_t i, j;

  if (argc != 2) {
    fprintf (stderr, "usage: inspect_vm disk.img\n");
    exit (EXIT_FAILURE);
  }
  disk = argv[1];

  g = guestfs_create ();
  if (g == NULL) {
    perror ("failed to create libguestfs handle");
    exit (EXIT_FAILURE);
  }

  /* Attach the disk image read-only to libguestfs. */
  if (guestfs_add_drive_opts (g, disk,
			      /* GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw", */
			      GUESTFS_ADD_DRIVE_OPTS_READONLY, 1,
			      -1) /* this marks end of optional arguments */
      == -1)
    exit (EXIT_FAILURE);

  /* Run the libguestfs back-end. */
  if (guestfs_launch (g) == -1)
    exit (EXIT_FAILURE);

  /* Ask libguestfs to inspect for operating systems. */
  roots = guestfs_inspect_os (g);
  if (roots == NULL)
    exit (EXIT_FAILURE);
  if (roots[0] == NULL) {
    fprintf (stderr, "inspect_vm: no operating systems found\n");
    exit (EXIT_FAILURE);
  }

  for (j = 0; roots[j] != NULL; ++j) {
    root = roots[j];

    printf ("Root device: %s\n", root);

    /* Print basic information about the operating system. */
    str = guestfs_inspect_get_product_name (g, root);
    if (str)
      printf ("  Product name: %s\n", str);
    free (str);

    printf ("  Version:      %d.%d\n",
            guestfs_inspect_get_major_version (g, root),
            guestfs_inspect_get_minor_version (g, root));

    str = guestfs_inspect_get_type (g, root);
    if (str)
      printf ("  Type:         %s\n", str);
    free (str);
    str = guestfs_inspect_get_distro (g, root);
    if (str)
      printf ("  Distro:       %s\n", str);
    free (str);

    /* Mount up the disks, like guestfish -i.
     *
     * Sort keys by length, shortest first, so that we end up
     * mounting the filesystems in the correct order.
     */
    mountpoints = guestfs_inspect_get_mountpoints (g, root);
    if (mountpoints == NULL)
      exit (EXIT_FAILURE);

    qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *),
           compare_keys_len);
    for (i = 0; mountpoints[i] != NULL; i += 2) {
      /* Ignore failures from this call, since bogus entries can
       * appear in the guest's /etc/fstab.
       */
      guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]);
      free (mountpoints[i]);
      free (mountpoints[i+1]);
    }
    free (mountpoints);

    /* If /etc/issue.net file exists, print up to 3 lines. */
    if (guestfs_is_file (g, "/etc/issue.net") > 0) {
      printf ("--- /etc/issue.net ---\n");
      lines = guestfs_head_n (g, 3, "/etc/issue.net");
      if (lines == NULL)
        exit (EXIT_FAILURE);
      for (i = 0; lines[i] != NULL; ++i) {
        printf ("%s\n", lines[i]);
        free (lines[i]);
      }
      free (lines);
    }

    /* Unmount everything. */
    if (guestfs_umount_all (g) == -1)
      exit (EXIT_FAILURE);

    free (root);
  }
  free (roots);

  guestfs_close (g);

  exit (EXIT_SUCCESS);
}
コード例 #14
0
/* At the moment, pull just the ProductName and version numbers from
 * the registry.  In future there is a case for making many more
 * registry fields available to callers.
 */
static int
check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs)
{
  int ret = -1;
  int r;

  CLEANUP_FREE char *software =
    safe_asprintf (g, "%s/system32/config/software", fs->windows_systemroot);

  CLEANUP_FREE char *software_path = guestfs_case_sensitive_path (g, software);
  if (!software_path)
    return -1;

  r = guestfs_is_file (g, software_path);
  if (r == -1)
    return -1;
  /* If the software hive doesn't exist, just accept that we cannot
   * find product_name etc.
   */
  if (r == 0)
    return 0;

  int64_t node;
  const char *hivepath[] =
    { "Microsoft", "Windows NT", "CurrentVersion" };
  size_t i;
  CLEANUP_FREE_HIVEX_VALUE_LIST struct guestfs_hivex_value_list *values = NULL;
  bool ignore_currentversion = false;

  if (guestfs_hivex_open (g, software_path,
                          GUESTFS_HIVEX_OPEN_VERBOSE, g->verbose, -1) == -1)
    return -1;

  node = guestfs_hivex_root (g);
  for (i = 0; node > 0 && i < sizeof hivepath / sizeof hivepath[0]; ++i)
    node = guestfs_hivex_node_get_child (g, node, hivepath[i]);

  if (node == -1)
    goto out;

  if (node == 0) {
    perrorf (g, "hivex: cannot locate HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
    goto out;
  }

  values = guestfs_hivex_node_values (g, node);

  for (i = 0; i < values->len; ++i) {
    int64_t value = values->val[i].hivex_value_h;
    CLEANUP_FREE char *key = guestfs_hivex_value_key (g, value);
    if (key == NULL)
      goto out;

    if (STRCASEEQ (key, "ProductName")) {
      fs->product_name = guestfs_hivex_value_utf8 (g, value);
      if (!fs->product_name)
        goto out;
    }
    else if (STRCASEEQ (key, "CurrentMajorVersionNumber")) {
      size_t vsize;
      int64_t vtype = guestfs_hivex_value_type (g, value);
      CLEANUP_FREE char *vbuf = guestfs_hivex_value_value (g, value, &vsize);

      if (vbuf == NULL)
        goto out;
      if (vtype != 4 || vsize != 4) {
        error (g, "hivex: expected CurrentVersion\\%s to be a DWORD field",
               "CurrentMajorVersionNumber");
        goto out;
      }

      fs->version.v_major = le32toh (*(int32_t *)vbuf);

      /* Ignore CurrentVersion if we see it after this key. */
      ignore_currentversion = true;
    }
    else if (STRCASEEQ (key, "CurrentMinorVersionNumber")) {
      size_t vsize;
      int64_t vtype = guestfs_hivex_value_type (g, value);
      CLEANUP_FREE char *vbuf = guestfs_hivex_value_value (g, value, &vsize);

      if (vbuf == NULL)
        goto out;
      if (vtype != 4 || vsize != 4) {
        error (g, "hivex: expected CurrentVersion\\%s to be a DWORD field",
               "CurrentMinorVersionNumber");
        goto out;
      }

      fs->version.v_minor = le32toh (*(int32_t *)vbuf);

      /* Ignore CurrentVersion if we see it after this key. */
      ignore_currentversion = true;
    }
    else if (!ignore_currentversion && STRCASEEQ (key, "CurrentVersion")) {
      CLEANUP_FREE char *version = guestfs_hivex_value_utf8 (g, value);
      if (!version)
        goto out;
      if (guestfs_int_version_from_x_y_re (g, &fs->version, version,
                                           re_windows_version) == -1)
        goto out;
    }
    else if (STRCASEEQ (key, "InstallationType")) {
      fs->product_variant = guestfs_hivex_value_utf8 (g, value);
      if (!fs->product_variant)
        goto out;
    }
  }

  ret = 0;

 out:
  guestfs_hivex_close (g);

  return ret;
}
コード例 #15
0
ファイル: copy-in-out.c プロジェクト: AlphaStaxLLC/libguestfs
int
guestfs_impl_copy_out (guestfs_h *g,
                       const char *remotepath, const char *localdir)
{
  struct stat statbuf;
  int r;

  if (stat (localdir, &statbuf) == -1 ||
      ! (S_ISDIR (statbuf.st_mode))) {
    error (g, _("target '%s' is not a directory"), localdir);
    return -1;
  }

  /* If the remote is a file, download it.  If it's a directory,
   * create the directory in localdir first before using tar-out.
   */
  r = guestfs_is_file (g, remotepath);
  if (r == -1)
    return -1;

  if (r == 1) {               /* is file */
    CLEANUP_FREE char *filename = NULL;
    size_t buf_len = strlen (remotepath) + 1;
    CLEANUP_FREE char *buf = safe_malloc (g, buf_len);
    const char *basename;

    if (split_path (g, buf, buf_len, remotepath, NULL, &basename) == -1)
      return -1;

    if (asprintf (&filename, "%s/%s", localdir, basename) == -1) {
      perrorf (g, "asprintf");
      return -1;
    }
    if (guestfs_download (g, remotepath, filename) == -1)
      return -1;
  } else {                    /* not a regular file */
    CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g);
    struct copy_out_child_data data;
    char fdbuf[64];
    int fd;

    r = guestfs_is_dir (g, remotepath);
    if (r == -1)
      return -1;

    if (r == 0) {
      error (g, _("'%s' is not a file or directory"), remotepath);
      return -1;
    }

    size_t buf_len = strlen (remotepath) + 1;
    CLEANUP_FREE char *buf = safe_malloc (g, buf_len);
    const char *basename;
    if (split_path (g, buf, buf_len, remotepath, NULL, &basename) == -1)
      return -1;

    /* RHBZ#845522: If remotepath == "/" then basename would be an empty
     * string.  Replace it with "." so that make_tar_output writes
     * to "localdir/."
     */
    if (STREQ (basename, ""))
      basename = ".";

    data.localdir = localdir;
    data.basename = basename;

    guestfs_int_cmd_set_child_callback (cmd, &child_setup, &data);

    guestfs_int_cmd_add_arg (cmd, "tar");
    guestfs_int_cmd_add_arg (cmd, "-xf");
    guestfs_int_cmd_add_arg (cmd, "-");

    guestfs_int_cmd_clear_capture_errors (cmd);

    fd = guestfs_int_cmd_pipe_run (cmd, "w");
    if (fd == -1)
      return -1;

    snprintf (fdbuf, sizeof fdbuf, "/dev/fd/%d", fd);

    r = guestfs_tar_out (g, remotepath, fdbuf);

    if (close (fd) == -1) {
      perrorf (g, "close (tar-output subprocess)");
      return -1;
    }

    r = guestfs_int_cmd_pipe_wait (cmd);
    if (r == -1)
      return -1;
    if (!WIFEXITED (r) || WEXITSTATUS (r) != 0) {
      CLEANUP_FREE char *errors = guestfs_int_cmd_get_pipe_errors (cmd);
      if (errors == NULL)
        return -1;
      error (g, "tar subprocess failed: %s", errors);
      return -1;
    }
  }

  return 0;
}
コード例 #16
0
ファイル: inspect-fs.c プロジェクト: DanLipsitt/libguestfs
static int
check_filesystem (guestfs_h *g, const char *mountable,
                  const struct guestfs_internal_mountable *m,
                  int whole_device)
{
  /* Not CLEANUP_FREE, as it will be cleaned up with inspection info */
  char *windows_systemroot = NULL;

  if (extend_fses (g) == -1)
    return -1;

  int partnum = -1;
  if (!whole_device && m->im_type == MOUNTABLE_DEVICE) {
    guestfs_push_error_handler (g, NULL, NULL);
    partnum = guestfs_part_to_partnum (g, m->im_device);
    guestfs_pop_error_handler (g);
  }

  struct inspect_fs *fs = &g->fses[g->nr_fses-1];

  fs->mountable = safe_strdup (g, mountable);

  /* 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 ||
      guestfs_is_file (g, "/grub2/grub.cfg") > 0)
    ;
  /* FreeBSD root? */
  else if (is_dir_etc &&
           is_dir_bin &&
           guestfs_is_file (g, "/etc/freebsd-update.conf") > 0 &&
           guestfs_is_file (g, "/etc/fstab") > 0) {
    /* Ignore /dev/sda1 which is a shadow of the real root filesystem
     * that is probably /dev/sda5 (see:
     * http://www.freebsd.org/doc/handbook/disk-organization.html)
     */
    if (m->im_type == MOUNTABLE_DEVICE &&
        match (g, m->im_device, re_first_partition))
      return 0;

    fs->is_root = 1;
    fs->format = OS_FORMAT_INSTALLED;
    if (guestfs___check_freebsd_root (g, fs) == -1)
      return -1;
  }
  else if (is_dir_etc &&
           is_dir_bin &&
           guestfs_is_file (g, "/etc/fstab") > 0 &&
           guestfs_is_file (g, "/etc/release") > 0) {
    /* Ignore /dev/sda1 which is a shadow of the real root filesystem
     * that is probably /dev/sda5 (see:
     * http://www.freebsd.org/doc/handbook/disk-organization.html)
     */
    if (m->im_type == MOUNTABLE_DEVICE &&
        match (g, m->im_device, re_first_partition))
      return 0;

    fs->is_root = 1;
    fs->format = OS_FORMAT_INSTALLED;
    if (guestfs___check_netbsd_root (g, fs) == -1)
      return -1;
  }
  /* Hurd root? */
  else if (guestfs_is_file (g, "/hurd/console") > 0 &&
           guestfs_is_file (g, "/hurd/hello") > 0 &&
           guestfs_is_file (g, "/hurd/null") > 0) {
    fs->is_root = 1;
    fs->format = OS_FORMAT_INSTALLED; /* XXX could be more specific */
    if (guestfs___check_hurd_root (g, fs) == -1)
      return -1;
  }
  /* Linux root? */
  else if (is_dir_etc &&
           (is_dir_bin ||
            (guestfs_is_symlink (g, "/bin") > 0 &&
             guestfs_is_dir (g, "/usr/bin") > 0)) &&
           guestfs_is_file (g, "/etc/fstab") > 0) {
    fs->is_root = 1;
    fs->format = OS_FORMAT_INSTALLED;
    if (guestfs___check_linux_root (g, fs) == -1)
      return -1;
  }
  /* Linux /usr/local? */
  else if (is_dir_etc &&
           is_dir_bin &&
           is_dir_share &&
           guestfs_is_dir (g, "/local") == 0 &&
           guestfs_is_file (g, "/etc/fstab") == 0)
    ;
  /* Linux /usr? */
  else if (is_dir_etc &&
           is_dir_bin &&
           is_dir_share &&
           guestfs_is_dir (g, "/local") > 0 &&
           guestfs_is_file (g, "/etc/fstab") == 0)
    ;
  /* Linux /var? */
  else if (guestfs_is_dir (g, "/log") > 0 &&
           guestfs_is_dir (g, "/run") > 0 &&
           guestfs_is_dir (g, "/spool") > 0)
    ;
  /* Windows root? */
  else if ((windows_systemroot = guestfs___get_windows_systemroot (g)) != NULL)
  {
    fs->is_root = 1;
    fs->format = OS_FORMAT_INSTALLED;
    if (guestfs___check_windows_root (g, fs, windows_systemroot) == -1)
      return -1;
  }
  /* Windows volume with installed applications (but not root)? */
  else if (guestfs___is_dir_nocase (g, "/System Volume Information") > 0 &&
           guestfs___is_dir_nocase (g, "/Program Files") > 0)
    ;
  /* Windows volume (but not root)? */
  else if (guestfs___is_dir_nocase (g, "/System Volume Information") > 0)
    ;
  /* FreeDOS? */
  else if (guestfs___is_dir_nocase (g, "/FDOS") > 0 &&
           guestfs___is_file_nocase (g, "/FDOS/FREEDOS.BSS") > 0) {
    fs->is_root = 1;
    fs->format = OS_FORMAT_INSTALLED;
    fs->type = OS_TYPE_DOS;
    fs->distro = OS_DISTRO_FREEDOS;
    /* FreeDOS is a mix of 16 and 32 bit, but assume it requires a
     * 32 bit i386 processor.
     */
    fs->arch = safe_strdup (g, "i386");
  }
  /* Install CD/disk?
   *
   * Note that we checked (above) for an install ISO, but there are
   * other types of install image (eg. USB keys) which that check
   * wouldn't have picked up.
   *
   * Skip these checks if it's not a whole device (eg. CD) or the
   * first partition (eg. bootable USB key).
   */
  else if ((whole_device || partnum == 1) &&
           (guestfs_is_file (g, "/isolinux/isolinux.cfg") > 0 ||
            guestfs_is_dir (g, "/EFI/BOOT") > 0 ||
            guestfs_is_file (g, "/images/install.img") > 0 ||
            guestfs_is_dir (g, "/.disk") > 0 ||
            guestfs_is_file (g, "/.discinfo") > 0 ||
            guestfs_is_file (g, "/i386/txtsetup.sif") > 0 ||
            guestfs_is_file (g, "/amd64/txtsetup.sif") > 0 ||
            guestfs_is_file (g, "/freedos/freedos.ico") > 0 ||
            guestfs_is_file (g, "/boot/loader.rc") > 0)) {
    fs->is_root = 1;
    fs->format = OS_FORMAT_INSTALLER;
    if (guestfs___check_installer_root (g, fs) == -1)
      return -1;
  }

  /* The above code should have set fs->type and fs->distro fields, so
   * we can now guess the package management system.
   */
  guestfs___check_package_format (g, fs);
  guestfs___check_package_management (g, fs);

  return 0;
}