Ejemplo n.º 1
0
int
guestfs_int_is_dir_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_dir (g, p);
  return r > 0;
}
Ejemplo n.º 2
0
int
guestfs_impl_copy_in (guestfs_h *g, const char *localpath, const char *remotedir)
{
  CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g);
  int fd;
  int r;
  char fdbuf[64];
  size_t buf_len = strlen (localpath) + 1;
  char buf[buf_len];
  const char *dirname, *basename;

  int remote_is_dir = guestfs_is_dir (g, remotedir);
  if (remote_is_dir == -1)
    return -1;

  if (!remote_is_dir) {
    error (g, _("target '%s' is not a directory"), remotedir);
    return -1;
  }

  if (split_path (g, buf, buf_len, localpath, &dirname, &basename) == -1)
    return -1;

  guestfs_int_cmd_add_arg (cmd, "tar");
  if (dirname) {
    guestfs_int_cmd_add_arg (cmd, "-C");
    guestfs_int_cmd_add_arg (cmd, dirname);
  }
  guestfs_int_cmd_add_arg (cmd, "-cf");
  guestfs_int_cmd_add_arg (cmd, "-");
  guestfs_int_cmd_add_arg (cmd, basename);

  r = guestfs_int_cmd_run_async (cmd, NULL, NULL, &fd, NULL);
  if (r == -1)
    return -1;

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

  r = guestfs_tar_in (g, fdbuf, remotedir);

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

  r = guestfs_int_cmd_wait (cmd);
  if (r == -1)
    return -1;
  if (!(WIFEXITED (r) && WEXITSTATUS (r) == 0))
    return -1;

  return 0;
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
0
int
run_copy_in (const char *cmd, size_t argc, char *argv[])
{
    if (argc < 2) {
        fprintf (stderr,
                 _("use 'copy-in <local> [<local>...] <remotedir>' to copy files into the image\n"));
        return -1;
    }

    /* Remote directory is always the last arg. */
    char *remote = argv[argc-1];

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

    int nr_locals = argc-1;

    int remote_is_dir = guestfs_is_dir (g, remote);
    if (remote_is_dir == -1) {
        free (remote);
        return -1;
    }

    if (!remote_is_dir) {
        fprintf (stderr, _("copy-in: target '%s' is not a directory\n"), remote);
        free (remote);
        return -1;
    }

    /* Upload each local one at a time using tar-in. */
    int i;
    for (i = 0; i < nr_locals; ++i) {
        struct fd_pid fdpid = make_tar_from_local (argv[i]);
        if (fdpid.fd == -1) {
            free (remote);
            return -1;
        }

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

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

        if (close (fdpid.fd) == -1) {
            perror ("close (tar-from-local subprocess)");
            r = -1;
        }

        int status;
        if (waitpid (fdpid.pid, &status, 0) == -1) {
            perror ("wait (tar-from-local 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;
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
int
guestfs_impl_copy_in (guestfs_h *g,
                      const char *localpath, const char *remotedir)
{
  CLEANUP_CMD_CLOSE struct command *cmd = guestfs_int_new_command (g);
  int fd;
  int r;
  char fdbuf[64];
  size_t buf_len = strlen (localpath) + 1;
  CLEANUP_FREE char *buf = safe_malloc (g, buf_len);
  const char *dirname, *basename;
  struct stat statbuf;

  if (stat (localpath, &statbuf) == -1) {
    error (g, _("source '%s' does not exist (or cannot be read)"), localpath);
    return -1;
  }

  int remote_is_dir = guestfs_is_dir (g, remotedir);
  if (remote_is_dir == -1)
    return -1;

  if (!remote_is_dir) {
    error (g, _("target '%s' is not a directory"), remotedir);
    return -1;
  }

  if (split_path (g, buf, buf_len, localpath, &dirname, &basename) == -1)
    return -1;

  guestfs_int_cmd_add_arg (cmd, "tar");
  if (dirname) {
    guestfs_int_cmd_add_arg (cmd, "-C");
    guestfs_int_cmd_add_arg (cmd, dirname);
  }
  guestfs_int_cmd_add_arg (cmd, "-cf");
  guestfs_int_cmd_add_arg (cmd, "-");
  guestfs_int_cmd_add_arg (cmd, basename);

  guestfs_int_cmd_clear_capture_errors (cmd);

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

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

  r = guestfs_tar_in (g, fdbuf, remotedir);

  if (close (fd) == -1) {
    perrorf (g, "close (tar 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;
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
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;
}