示例#1
0
/* Use vfs-type to look for a filesystem of some sort on 'dev'.
 * Apart from some types which we ignore, add the result to the
 * 'ret' string list.
 */
static int
check_with_vfs_type (guestfs_h *g, const char *device, struct stringsbuf *sb)
{
  const char *v;
  CLEANUP_FREE char *vfs_type = NULL;

  guestfs_push_error_handler (g, NULL, NULL);
  vfs_type = guestfs_vfs_type (g, device);
  guestfs_pop_error_handler (g);

  if (!vfs_type)
    v = "unknown";
  else if (STREQ (vfs_type, ""))
    v = "unknown";
  else if (STREQ (vfs_type, "btrfs")) {
    CLEANUP_FREE_BTRFSSUBVOLUME_LIST struct guestfs_btrfssubvolume_list *vols =
      guestfs_btrfs_subvolume_list (g, device);

    if (vols == NULL)
      return -1;

    for (size_t i = 0; i < vols->len; i++) {
      struct guestfs_btrfssubvolume *this = &vols->val[i];
      guestfs___add_sprintf (g, sb,
                             "btrfsvol:%s/%s",
                             device, this->btrfssubvolume_path);
      guestfs___add_string (g, sb, "btrfs");
    }

    v = vfs_type;
  }
示例#2
0
/* Use vfs-type to look for a filesystem of some sort on 'dev'.
 * Apart from some types which we ignore, add the result to the
 * 'ret' string list.
 */
static void
check_with_vfs_type (guestfs_h *g, const char *device,
                     char ***ret, size_t *ret_size)
{
  char *v;
  char *vfs_type;

  guestfs_push_error_handler (g, NULL, NULL);
  vfs_type = guestfs_vfs_type (g, device);
  guestfs_pop_error_handler (g);

  if (!vfs_type)
    v = safe_strdup (g, "unknown");
  else if (STREQ (vfs_type, "")) {
    v = safe_strdup (g, "unknown");
    free (vfs_type);
  }
  else if (STREQ (vfs_type, "btrfs")) {
    CLEANUP_FREE_BTRFSSUBVOLUME_LIST struct guestfs_btrfssubvolume_list *vols =
      guestfs_btrfs_subvolume_list (g, device);

    for (size_t i = 0; i < vols->len; i++) {
      struct guestfs_btrfssubvolume *this = &vols->val[i];
      char *mountable = safe_asprintf (g, "btrfsvol:%s/%s",
                                       device, this->btrfssubvolume_path);
      add_vfs (g, mountable, safe_strdup (g, "btrfs"), ret, ret_size);
    }

    v = vfs_type;
  }
/* 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;
}
示例#4
0
int
run_supported (const char *cmd, size_t argc, char *argv[])
{
  /* As a side-effect this also checks that we've called 'launch'. */
  CLEANUP_FREE_STRING_LIST char **groups = guestfs_available_all_groups (g);
  if (groups == NULL)
    return -1;

  /* Temporarily replace the error handler so that messages don't get
   * printed to stderr while we are issuing commands.
   */
  guestfs_push_error_handler (g, NULL, NULL);

  /* Work out the max string length of any group name. */
  size_t i;
  size_t len = 0;
  for (i = 0; groups[i] != NULL; ++i) {
    size_t l = strlen (groups[i]);
    if (l > len)
      len = l;
  }

  for (i = 0; groups[i] != NULL; ++i) {
    char *gg[] = { groups[i], NULL };
    int r = guestfs_available (g, gg);
    const char *str = r == 0 ? _("yes") : _("no");

    printf ("%*s %s\n", (int) len, groups[i], str);
  }

  /* Restore error handler. */
  guestfs_pop_error_handler (g);

  return 0;
}
示例#5
0
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;
      }
    }
  }
}
示例#6
0
static void
output_filesystems (xmlTextWriterPtr xo, char *root)
{
  char *str;
  size_t i;

  CLEANUP_FREE_STRING_LIST char **filesystems =
    guestfs_inspect_get_filesystems (g, root);
  if (filesystems == NULL)
    exit (EXIT_FAILURE);

  /* Sort by name so the output is stable. */
  qsort (filesystems, guestfs_int_count_strings (filesystems), sizeof (char *),
         compare_keys);

  XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "filesystems"));

  for (i = 0; filesystems[i] != NULL; ++i) {
    str = guestfs_canonical_device_name (g, filesystems[i]);
    if (!str)
      exit (EXIT_FAILURE);

    XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "filesystem"));
    XMLERROR (-1,
              xmlTextWriterWriteAttribute (xo, BAD_CAST "dev", BAD_CAST str));
    free (str);

    guestfs_push_error_handler (g, NULL, NULL);

    str = guestfs_vfs_type (g, filesystems[i]);
    if (str && str[0])
      XMLERROR (-1,
                xmlTextWriterWriteElement (xo, BAD_CAST "type",
                                           BAD_CAST str));
    free (str);

    str = guestfs_vfs_label (g, filesystems[i]);
    if (str && str[0])
      XMLERROR (-1,
                xmlTextWriterWriteElement (xo, BAD_CAST "label",
                                           BAD_CAST str));
    free (str);

    str = guestfs_vfs_uuid (g, filesystems[i]);
    if (str && str[0])
      XMLERROR (-1,
                xmlTextWriterWriteElement (xo, BAD_CAST "uuid",
                                           BAD_CAST str));
    free (str);

    guestfs_pop_error_handler (g);

    XMLERROR (-1, xmlTextWriterEndElement (xo));
  }

  XMLERROR (-1, xmlTextWriterEndElement (xo));
}
示例#7
0
static int
do_log (void)
{
  CLEANUP_FREE_STRING_LIST char **roots = NULL;
  char *root;
  CLEANUP_FREE char *type = NULL;
  CLEANUP_FREE_STRING_LIST char **journal_files = NULL;

  /* Get root mountpoint.  fish/inspect.c guarantees the assertions
   * below.
   */
  roots = guestfs_inspect_get_roots (g);
  assert (roots);
  assert (roots[0] != NULL);
  assert (roots[1] == NULL);
  root = roots[0];

  type = guestfs_inspect_get_type (g, root);
  if (!type)
    return -1;

  /* Windows needs special handling. */
  if (STREQ (type, "windows")) {
    if (guestfs_inspect_get_major_version (g, root) >= 6)
      return do_log_windows_evtx ();

    fprintf (stderr,
             _("%s: Windows Event Log for pre-Vista guests is not supported.\n"),
             guestfs_int_program_name);
    return -1;
  }

  /* systemd journal? */
  guestfs_push_error_handler (g, NULL, NULL);
  journal_files = guestfs_ls (g, JOURNAL_DIR);
  guestfs_pop_error_handler (g);
  if (STREQ (type, "linux") &&
      journal_files != NULL && journal_files[0] != NULL)
    return do_log_journal ();

  /* Regular /var/log text files with different names. */
  if (STRNEQ (type, "windows")) {
    const char *logfiles[] = { "/var/log/syslog", "/var/log/messages", NULL };
    size_t i;

    for (i = 0; logfiles[i] != NULL; ++i) {
      if (guestfs_is_file_opts (g, logfiles[i],
                                GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1,
                                -1) == 1)
        return do_log_text_file (logfiles[i]);
    }
  }

  /* Otherwise, there are no log files.  Hmm, is this right? XXX */
  return 0;
}
/* NB: This function DOES NOT test for the existence of the file.  It
 * will return non-NULL even if the file/directory does not exist.
 * You have to call guestfs_is_file{,_opts} etc.
 */
char *
guestfs___case_sensitive_path_silently (guestfs_h *g, const char *path)
{
  char *ret;

  guestfs_push_error_handler (g, NULL, NULL);
  ret = guestfs_case_sensitive_path (g, path);
  guestfs_pop_error_handler (g);

  return ret;
}
/* Check that the named file 'filename' is a PNG file and is reasonable.
 * If it is, download and return it.
 */
static char *
get_png (guestfs_h *g, struct inspect_fs *fs, const char *filename,
         size_t *size_r, size_t max_size)
{
  char *ret;
  CLEANUP_FREE char *real = NULL;
  CLEANUP_FREE char *type = NULL;
  CLEANUP_FREE char *local = NULL;
  int r, w, h;

  r = guestfs_is_file_opts (g, filename,
                            GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1);
  if (r == -1)
    return NULL; /* a real error */
  if (r == 0)
    return NOT_FOUND;

  /* Resolve the path, in case it's a symbolic link (as in RHEL 7). */
  guestfs_push_error_handler (g, NULL, NULL);
  real = guestfs_realpath (g, filename);
  guestfs_pop_error_handler (g);
  if (real == NULL)
    return NOT_FOUND; /* could just be a broken link */

  /* Check the file type and geometry. */
  type = guestfs_file (g, real);
  if (!type)
    return NOT_FOUND;

  if (!STRPREFIX (type, "PNG image data, "))
    return NOT_FOUND;
  if (sscanf (&type[16], "%d x %d", &w, &h) != 2)
    return NOT_FOUND;
  if (w < 16 || h < 16 || w > 1024 || h > 1024)
    return NOT_FOUND;

  /* Define a maximum reasonable size based on the geometry.  This
   * also limits the maximum we allocate below to around 4 MB.
   */
  if (max_size == 0)
    max_size = 4 * w * h;

  local = guestfs___download_to_tmp (g, fs, real, "icon", max_size);
  if (!local)
    return NOT_FOUND;

  /* Successfully passed checks and downloaded.  Read it into memory. */
  if (read_whole_file (g, local, &ret, size_r) == -1)
    return NULL;

  return ret;
}
示例#10
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;
}
示例#11
0
int
main (int argc, char *argv[])
{
  guestfs_h *g;
  size_t i;
  int lengths[] = { 0, 1, 1024,
                    GUESTFS_ERROR_LEN-2, GUESTFS_ERROR_LEN-1,
                    GUESTFS_ERROR_LEN, GUESTFS_ERROR_LEN+1,
                    GUESTFS_ERROR_LEN+2,
                    GUESTFS_ERROR_LEN*2, -1 };
  char len_s[64];
  char *args[2];

  g = guestfs_create ();
  if (g == NULL) {
    perror ("guestfs_create");
    exit (EXIT_FAILURE);
  }

  if (guestfs_add_drive (g, "/dev/null") == -1)
    exit (EXIT_FAILURE);

  if (guestfs_launch (g) == -1)
    exit (EXIT_FAILURE);

  guestfs_push_error_handler (g, NULL, NULL);

  for (i = 0; lengths[i] != -1; ++i) {
    snprintf (len_s, sizeof len_s, "%d", lengths[i]);
    args[0] = len_s;
    args[1] = NULL;

    if (guestfs_debug (g, "error", args) != NULL) {
      fprintf (stderr, "%s: unexpected return value from 'debug error'\n",
               argv[0]);
      exit (EXIT_FAILURE);
    }
    /* EROFS is a magic value returned by debug_error in the daemon. */
    if (guestfs_last_errno (g) != EROFS) {
      fprintf (stderr, "%s: unexpected error from 'debug error': %s\n",
               argv[0], guestfs_last_error (g));
      exit (EXIT_FAILURE);
    }
    /* else OK */
  }

  guestfs_pop_error_handler (g);
  guestfs_close (g);
  exit (EXIT_SUCCESS);
}
示例#12
0
static int
feature_available (guestfs_h *g, const char *feature)
{
  /* If there's an error we should ignore it, so to do that we have to
   * temporarily replace the error handler with a null one.
   */
  guestfs_push_error_handler (g, NULL, NULL);

  const char *groups[] = { feature, NULL };
  int r = guestfs_available (g, (char * const *) groups);

  guestfs_pop_error_handler (g);

  return r == 0 ? 1 : 0;
}
示例#13
0
/* Since we want this function to be robust against very bad failure
 * cases (hello, https://bugzilla.kernel.org/show_bug.cgi?id=18792) it
 * won't exit on guestfs failures.
 */
int
df_on_handle (guestfs_h *g, const char *name, const char *uuid, FILE *fp)
{
  size_t i;
  CLEANUP_FREE_STRING_LIST char **devices = NULL;
  CLEANUP_FREE_STRING_LIST char **fses = NULL;

  if (verbose)
    fprintf (stderr, "df_on_handle: %s\n", name);

  devices = guestfs_list_devices (g);
  if (devices == NULL)
    return -1;

  fses = guestfs_list_filesystems (g);
  if (fses == NULL)
    return -1;

  for (i = 0; fses[i] != NULL; i += 2) {
    if (STRNEQ (fses[i+1], "") &&
        STRNEQ (fses[i+1], "swap") &&
        STRNEQ (fses[i+1], "unknown")) {
      const char *dev = fses[i];
      CLEANUP_FREE_STATVFS struct guestfs_statvfs *stat = NULL;

      if (verbose)
        fprintf (stderr, "df_on_handle: %s dev %s\n", name, dev);

      /* Try mounting and stating the device.  This might reasonably
       * fail, so don't show errors.
       */
      guestfs_push_error_handler (g, NULL, NULL);

      if (guestfs_mount_ro (g, dev, "/") == 0) {
        stat = guestfs_statvfs (g, "/");
        guestfs_umount_all (g);
      }

      guestfs_pop_error_handler (g);

      if (stat)
        print_stat (fp, name, uuid, dev, stat);
    }
  }

  return 0;
}
示例#14
0
int
guestfs_impl_mount_local_run (guestfs_h *g)
{
  int r, mounted;

  gl_lock_lock (mount_local_lock);
  mounted = g->localmountpoint != NULL;
  gl_lock_unlock (mount_local_lock);

  if (!mounted) {
    error (g, _("you must call guestfs_mount_local first"));
    return -1;
  }

  /* Test if root is mounted.  We do this by using a side-effect of
   * guestfs_exists (which is that it calls NEED_ROOT).
   */
  guestfs_push_error_handler (g, NULL, NULL);
  r = guestfs_exists (g, "/");
  guestfs_pop_error_handler (g);
  if (r == -1) {
    error (g, _("you must call 'guestfs_mount' first to mount a filesystem on '/'.\nNote: '%s' is still mounted.  Use 'guestunmount %s' to clean up."),
           g->localmountpoint, g->localmountpoint);
    return -1;
  }

  debug (g, "%s: entering fuse_loop", __func__);

  /* Enter the main loop. */
  r = fuse_loop (g->fuse);
  if (r != 0)
    perrorf (g, _("fuse_loop: %s"), g->localmountpoint);

  debug (g, "%s: leaving fuse_loop", __func__);

  guestfs_int_free_fuse (g);
  gl_lock_lock (mount_local_lock);
  g->localmountpoint = NULL;
  gl_lock_unlock (mount_local_lock);

  /* By inspection, I found that fuse_loop only returns 0 or -1, but
   * don't rely on this in future.
   */
  return r == 0 ? 0 : -1;
}
示例#15
0
/* Parse the hostname from /etc/sysconfig/network.  This must be
 * called from the inspect_with_augeas wrapper.  Note that F18+ and
 * RHEL7+ use /etc/hostname just like Debian.
 */
static int
check_hostname_redhat (guestfs_h *g, struct inspect_fs *fs)
{
  char *hostname;

  /* Errors here are not fatal (RHBZ#726739), since it could be
   * just missing HOSTNAME field in the file.
   */
  guestfs_push_error_handler (g, NULL, NULL);
  hostname = guestfs_aug_get (g, "/files/etc/sysconfig/network/HOSTNAME");
  guestfs_pop_error_handler (g);

  /* This is freed by guestfs___free_inspect_info.  Note that hostname
   * could be NULL because we ignored errors above.
   */
  fs->hostname = hostname;
  return 0;
}
示例#16
0
static int
copy_attributes (const char *src, const char *dest)
{
  CLEANUP_FREE_STAT struct guestfs_stat *stat = NULL;
  const char *linuxxattrs[] = { "linuxxattrs", NULL };
  int has_linuxxattrs;
  CLEANUP_FREE char *selinux_context = NULL;
  size_t selinux_context_size;

  has_linuxxattrs = guestfs_feature_available (g, (char **) linuxxattrs);

  /* Get the mode. */
  stat = guestfs_stat (g, src);
  if (stat == NULL)
    return -1;

  /* Get the SELinux context.  XXX Should we copy over other extended
   * attributes too?
   */
  if (has_linuxxattrs) {
    guestfs_push_error_handler (g, NULL, NULL);

    selinux_context = guestfs_getxattr (g, src, "security.selinux",
                                        &selinux_context_size);
    /* selinux_context could be NULL.  This isn't an error. */

    guestfs_pop_error_handler (g);
  }

  /* Set the permissions (inc. sticky and set*id bits), UID, GID. */
  if (guestfs_chmod (g, stat->mode & 07777, dest) == -1)
    return -1;
  if (guestfs_chown (g, stat->uid, stat->gid, dest) == -1)
    return -1;

  /* Set the SELinux context. */
  if (has_linuxxattrs && selinux_context) {
    if (guestfs_setxattr (g, "security.selinux", selinux_context,
                          (int) selinux_context_size, dest) == -1)
      return -1;
  }

  return 0;
}
示例#17
0
static void
output_drive_mappings (xmlTextWriterPtr xo, char *root)
{
  CLEANUP_FREE_STRING_LIST char **drive_mappings = NULL;
  char *str;
  size_t i;

  guestfs_push_error_handler (g, NULL, NULL);
  drive_mappings = guestfs_inspect_get_drive_mappings (g, root);
  guestfs_pop_error_handler (g);
  if (drive_mappings == NULL)
    return;

  if (drive_mappings[0] == NULL)
    return;

  /* Sort by key. */
  qsort (drive_mappings,
         guestfs_int_count_strings (drive_mappings) / 2, 2 * sizeof (char *),
         compare_keys_nocase);

  XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "drive_mappings"));

  for (i = 0; drive_mappings[i] != NULL; i += 2) {
    str = guestfs_canonical_device_name (g, drive_mappings[i+1]);
    if (!str)
      exit (EXIT_FAILURE);

    XMLERROR (-1,
              xmlTextWriterStartElement (xo, BAD_CAST "drive_mapping"));
    XMLERROR (-1,
              xmlTextWriterWriteAttribute (xo, BAD_CAST "name",
                                           BAD_CAST drive_mappings[i]));
    XMLERROR (-1,
              xmlTextWriterWriteString (xo, BAD_CAST str));
    XMLERROR (-1, xmlTextWriterEndElement (xo));

    free (str);
  }

  XMLERROR (-1, xmlTextWriterEndElement (xo));
}
示例#18
0
static int
get_mbr_id (const char *dev, const char *parent_name)
{
  CLEANUP_FREE char *parttype = NULL;
  int mbr_id = -1, partnum;

  guestfs_push_error_handler (g, NULL, NULL);

  parttype = guestfs_part_get_parttype (g, parent_name);

  if (parttype && STREQ (parttype, "msdos")) {
    partnum = guestfs_part_to_partnum (g, dev);
    if (partnum >= 0)
      mbr_id = guestfs_part_get_mbr_id (g, parent_name, partnum);
  }

  guestfs_pop_error_handler (g);

  return mbr_id;
}
示例#19
0
/* Rescan everything so the kernel knows that there are no partition
 * tables, VGs etc.  Returns 0 on success, 1 if we need to retry.
 */
static int
do_rescan (char **devices)
{
  size_t i;
  size_t errors = 0;

  guestfs_push_error_handler (g, NULL, NULL);

  for (i = 0; devices[i] != NULL; ++i) {
    if (guestfs_blockdev_rereadpt (g, devices[i]) == -1)
      errors++;
  }

  if (guestfs_vgscan (g) == -1)
    errors++;

  guestfs_pop_error_handler (g);

  return errors ? 1 : 0;
}
示例#20
0
/* Use vfs-type to look for a filesystem of some sort on 'dev'.
 * Apart from some types which we ignore, add the result to the
 * 'ret' string list.
 */
static int
check_with_vfs_type (guestfs_h *g, const char *device, struct stringsbuf *sb)
{
  const char *v;
  CLEANUP_FREE char *vfs_type = NULL;

  guestfs_push_error_handler (g, NULL, NULL);
  vfs_type = guestfs_vfs_type (g, device);
  guestfs_pop_error_handler (g);

  if (!vfs_type)
    v = "unknown";
  else if (STREQ (vfs_type, ""))
    v = "unknown";
  else if (STREQ (vfs_type, "btrfs")) {
    CLEANUP_FREE_BTRFSSUBVOLUME_LIST struct guestfs_btrfssubvolume_list *vols =
      guestfs_btrfs_subvolume_list (g, device);

    if (vols == NULL)
      return -1;

    int64_t default_volume = guestfs_btrfs_subvolume_get_default (g, device);

    for (size_t i = 0; i < vols->len; i++) {
      struct guestfs_btrfssubvolume *this = &vols->val[i];

      /* Ignore the default subvolume.  We get it by simply mounting
       * the whole device of this btrfs filesystem.
       */
      if (this->btrfssubvolume_id == (uint64_t) default_volume)
        continue;

      guestfs_int_add_sprintf (g, sb,
			       "btrfsvol:%s/%s",
			       device, this->btrfssubvolume_path);
      guestfs_int_add_string (g, sb, "btrfs");
    }

    v = vfs_type;
  }
示例#21
0
/* If we found a filesystem on the parent device then ignore the
 * partitions within.
 */
static int
parent_device_already_probed (guestfs_h *g, const char *partition)
{
    char *device;
    size_t i;

    guestfs_push_error_handler (g, NULL, NULL);
    device = guestfs_part_to_dev (g, partition);
    guestfs_pop_error_handler (g);
    if (!device)
        return 0;

    for (i = 0; i < g->nr_fses; ++i) {
        if (STREQ (device, g->fses[i].device)) {
            free (device);
            return 1;
        }
    }

    free (device);
    return 0;
}
示例#22
0
文件: handle.c 项目: myyyy/libguestfs
/* This is a convenience function, but we might consider exporting
 * it as an API in future.
 */
int
guestfs_int_get_backend_setting_bool (guestfs_h *g, const char *name)
{
  CLEANUP_FREE char *value = NULL;
  int b;

  guestfs_push_error_handler (g, NULL, NULL);
  value = guestfs_get_backend_setting (g, name);
  guestfs_pop_error_handler (g);

  if (value == NULL && guestfs_last_errno (g) == ESRCH)
    return 0;

  if (value == NULL)
    return -1;

  b = guestfs_int_is_true (value);
  if (b == -1)
    return -1;

  return b;
}
示例#23
0
/* This is called for whole block devices.  See if the device is an
 * ISO and we are able to read the ISO info from it.  In that case,
 * try using libosinfo to map from the volume ID and other strings
 * directly to the operating system type.
 */
int
guestfs_int_check_installer_iso (guestfs_h *g, struct inspect_fs *fs,
				 const char *device)
{
  CLEANUP_FREE_ISOINFO struct guestfs_isoinfo *isoinfo = NULL;
  const struct osinfo *osinfo;
  int r;

  guestfs_push_error_handler (g, NULL, NULL);
  isoinfo = guestfs_isoinfo_device (g, device);
  guestfs_pop_error_handler (g);
  if (!isoinfo)
    return 0;

  r = guestfs_int_osinfo_map (g, isoinfo, &osinfo);
  if (r == -1)                  /* Fatal error. */
    return -1;
  if (r == 0)                   /* Could not locate any matching ISO. */
    return 0;

  /* Otherwise we matched an ISO, so fill in the fs fields. */
  fs->mountable = safe_strdup (g, device);
  fs->role = OS_ROLE_ROOT;
  if (osinfo->is_installer)
    fs->format = OS_FORMAT_INSTALLER;
  fs->type = osinfo->type;
  fs->distro = osinfo->distro;
  fs->product_name =
    osinfo->product_name ? safe_strdup (g, osinfo->product_name) : NULL;
  guestfs_int_version_from_values (&fs->version, osinfo->major_version,
                                   osinfo->minor_version, 0);
  fs->arch = osinfo->arch ? safe_strdup (g, osinfo->arch) : NULL;
  fs->is_live_disk = osinfo->is_live_disk;

  guestfs_int_check_package_format (g, fs);
  guestfs_int_check_package_management (g, fs);

  return 1;
}
示例#24
0
int
main (int argc, char *argv[])
{
    guestfs_h *g;
    int fd, r;
    char tempdir[] = "/tmp/mlXXXXXX";
    pid_t pid;
    char *shell, *p;

    if (argc != 2) {
        usage ();
        exit (EXIT_FAILURE);
    }

    printf ("\n"
            "This is the 'mount-local' demonstration program.  Follow the\n"
            "instructions on screen.\n"
            "\n"
            "Creating and formatting the disk image, please wait a moment ...\n");
    fflush (stdout);

    /* Create the output disk image: raw sparse. */
    fd = open (argv[1], O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644);
    if (fd == -1) {
        perror (argv[1]);
        exit (EXIT_FAILURE);
    }
    if (ftruncate (fd, SIZE_MB * 1024 * 1024) == -1) {
        perror ("truncate");
        close (fd);
        exit (EXIT_FAILURE);
    }
    if (close (fd) == -1) {
        perror ("close");
        exit (EXIT_FAILURE);
    }

    /* Guestfs handle. */
    g = guestfs_create ();
    if (g == NULL) {
        perror ("could not create libguestfs handle");
        exit (EXIT_FAILURE);
    }

    /* Create the disk image and format it with a partition and a filesystem. */
    if (guestfs_add_drive_opts (g, argv[1],
                                GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
                                -1) == -1)
        exit (EXIT_FAILURE);

    if (guestfs_launch (g) == -1)
        exit (EXIT_FAILURE);

    if (guestfs_part_disk (g, "/dev/sda", "mbr") == -1)
        exit (EXIT_FAILURE);

    if (guestfs_mkfs (g, "ext2", "/dev/sda1") == -1)
        exit (EXIT_FAILURE);

    /* Mount the empty filesystem. */
    if (guestfs_mount_options (g, MOUNT_OPTIONS, "/dev/sda1", "/") == -1)
        exit (EXIT_FAILURE);

    /* Create a file in the new filesystem. */
    if (guestfs_touch (g, "/PUT_FILES_AND_DIRECTORIES_HERE") == -1)
        exit (EXIT_FAILURE);

    /* Create a temporary mount directory. */
    if (mkdtemp (tempdir) == NULL) {
        perror ("mkdtemp");
        exit (EXIT_FAILURE);
    }

    /* Mount the filesystem. */
    if (guestfs_mount_local (g, tempdir, -1) == -1)
        exit (EXIT_FAILURE);

    /* Fork the shell for the user. */
    pid = fork ();
    if (pid == -1) {
        perror ("fork");
        exit (EXIT_FAILURE);
    }

    if (pid == 0) {               /* Child. */
        if (chdir (tempdir) == -1) {
            perror (tempdir);
            _exit (EXIT_FAILURE);
        }

        printf ("\n"
                "The *current directory* is a FUSE filesystem backed by the disk\n"
                "image which is managed by libguestfs.  Any files or directories\n"
                "you copy into here (up to %d MB) will be saved into the disk\n"
                "image.  You can also delete files, create certain special files\n"
                "and so on.\n"
                "\n"
                "When you have finished adding files, hit ^D or type 'exit' to\n"
                "exit the shell and return to the mount-local program.\n"
                "\n",
                SIZE_MB);

        shell = getenv ("SHELL");
        if (!shell)
            r = system ("/bin/sh");
        else {
            /* Set a magic prompt.  We only know how to do this for bash. */
            p = strrchr (shell, '/');
            if (p && strcmp (p+1, "bash") == 0) {
                size_t len = 64 + strlen (shell);
                char buf[len];

                snprintf (buf, len, "PS1='mount-local-shell> ' %s --norc -i", shell);
                r = system (buf);
            } else
                r = system (shell);
        }
        if (r == -1) {
            fprintf (stderr, "error: failed to run sub-shell (%s) "
                     "(is $SHELL set correctly?)\n",
                     shell);
            //FALLTHROUGH
        }

        chdir ("/");
        guestfs_umount_local (g, GUESTFS_UMOUNT_LOCAL_RETRY, 1, -1);
        _exit (EXIT_SUCCESS);
    }

    /* Note that we are *not* waiting for the child yet.  We want to
     * run the FUSE code in parallel with the subshell.
     */

    /* We're going to hide libguestfs errors here, but in a real program
     * you would probably want to log them somewhere.
     */
    guestfs_push_error_handler (g, NULL, NULL);

    /* Now run the FUSE thread. */
    if (guestfs_mount_local_run (g) == -1)
        exit (EXIT_FAILURE);

    guestfs_pop_error_handler (g);

    waitpid (pid, NULL, 0);

    /* Shutdown the handle explicitly so write errors can be detected. */
    if (guestfs_shutdown (g) == -1)
        exit (EXIT_FAILURE);

    guestfs_close (g);

    printf ("\n"
            "Any files or directories that you copied in have been saved into\n"
            "the disk image called '%s'.\n"
            "\n"
            "Try opening the disk image with guestfish to see those files:\n"
            "\n"
            "  guestfish -a %s -m /dev/sda1\n"
            "\n",
            argv[1], argv[1]);

    exit (EXIT_SUCCESS);
}
示例#25
0
static void *
start_thread (void *vi)
{
  guestfs_h *g;
  int r, thread_id = *(int *)vi;
  const char *error;

  g = guestfs_create ();
  if (g == NULL) {
    perror ("guestfs_create");
    *(int *)vi = -1;
    pthread_exit (vi);
  }

  if (guestfs_add_drive_opts (g, "/dev/null",
                              GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
                              GUESTFS_ADD_DRIVE_OPTS_READONLY, 1,
                              -1) == -1) {
    *(int *)vi = -1;
    pthread_exit (vi);
  }

  /* Fake out qemu. */
  if (guestfs_set_qemu (g, "/bin/true") == -1) {
    *(int *)vi = -1;
    pthread_exit (vi);
  }

  /* Wait for the other threads to finish starting up. */
  r = pthread_barrier_wait (&barrier);
  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) {
    fprintf (stderr, "pthread_barrier_wait: [thread %d]: %s\n",
             thread_id, strerror (r));
    *(int *)vi = -1;
    pthread_exit (vi);
  }

  /* Launch the handle.  Because of the faked out qemu, we expect this
   * will fail with "child process died unexpectedly".  We are
   * interested in other failures.
   */
  guestfs_push_error_handler (g, NULL, NULL);
  r = guestfs_launch (g);
  error = guestfs_last_error (g);

  if (r == 0) { /* This should NOT happen. */
    fprintf (stderr, "rhbz790721: [thread %d]: "
             "strangeness in test: expected launch to fail, but it didn't!\n",
             thread_id);
    *(int *)vi = -1;
    pthread_exit (vi);
  }

  if (error == NULL) { /* This also should NOT happen. */
    fprintf (stderr, "rhbz790721: [thread %d]: "
             "strangeness in test: no error message!\n",
             thread_id);
    *(int *)vi = -1;
    pthread_exit (vi);
  }

  /* If this happens, it indicates a bug/race in the appliance
   * building code which is what this regression test is designed to
   * spot.
   */
  if (STRNEQ (error, "child process died unexpectedly")) {
    fprintf (stderr, "rhbz790721: [thread %d]: error: %s\n", thread_id, error);
    *(int *)vi = -1;
    pthread_exit (vi);
  }

  guestfs_pop_error_handler (g);

  /* Close the handle. */
  guestfs_close (g);

  *(int *)vi = 0;
  pthread_exit (vi);
}
示例#26
0
static int
do_make_fs (const char *input, const char *output_str)
{
  const char *dev, *options;
  CLEANUP_UNLINK_FREE char *output = NULL;
  uint64_t estimate, size;
  struct guestfs_disk_create_argv optargs;
  CLEANUP_FREE char *ifmt = NULL;
  CLEANUP_FREE char *ifile = NULL;
  pid_t pid;
  int status, fd;

  /* Use of CLEANUP_UNLINK_FREE *output ensures the output file is
   * deleted unless we successfully reach the end of this function.
   */
  output = strdup (output_str);
  if (output == NULL) {
    perror ("strdup");
    return -1;
  }

  /* Input.  What is it?  Estimate how much space it will need. */
  if (estimate_input (input, &estimate, &ifmt) == -1)
    return -1;

  if (verbose) {
    fprintf (stderr, "input format = %s\n", ifmt);
    fprintf (stderr, "estimate = %" PRIu64 " bytes "
             "(%" PRIu64 " 1K blocks, %" PRIu64 " 4K blocks)\n",
             estimate, estimate / 1024, estimate / 4096);
  }

  estimate += 256 * 1024;       /* For superblocks &c. */

  if (STRPREFIX (type, "ext") && type[3] >= '3') {
    /* For ext3+, add some more for the journal. */
    estimate += 1024 * 1024;
  }

  else if (STREQ (type, "ntfs")) {
    estimate += 4 * 1024 * 1024; /* NTFS journal. */
  }

  else if (STREQ (type, "btrfs")) {
    /* For BTRFS, the minimum metadata allocation is 256MB, with data
     * additional to that.  Note that we disable data and metadata
     * duplication below.
     */
    estimate += 256 * 1024 * 1024;
  }

  /* Add 10%, see above. */
  estimate *= 1.10;

  /* Calculate the output size. */
  if (size_str == NULL)
    size = estimate;
  else
    if (parse_size (size_str, estimate, &size) == -1)
      return -1;

  /* Create the output disk. */
  optargs.bitmask = 0;
  if (STREQ (format, "qcow2")) {
    optargs.bitmask |= GUESTFS_DISK_CREATE_PREALLOCATION_BITMASK;
    optargs.preallocation = "metadata";
  }
  if (guestfs_disk_create_argv (g, output, format, size, &optargs) == -1)
    return -1;

  if (guestfs_add_drive_opts (g, output,
                              GUESTFS_ADD_DRIVE_OPTS_FORMAT, format,
                              -1) == -1)
    return -1;

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

  if (check_ntfs_available () == -1)
    return -1;

  /* Partition the disk. */
  dev = "/dev/sda";
  if (partition) {
    int mbr_id = 0;

    if (STREQ (partition, ""))
      partition = "mbr";

    if (guestfs_part_disk (g, dev, partition) == -1)
      return -1;

    dev = "/dev/sda1";

    /* Set the partition type byte if it's MBR and the filesystem type
     * is one that we know about.
     */
    if (STREQ (partition, "mbr") || STREQ (partition, "msdos")) {
      if (STREQ (type, "msdos"))
        /* According to Wikipedia.  However I have not actually tried this. */
        mbr_id = 0x1;
      else if (STREQ (type, "vfat") || STREQ (type, "fat"))
        mbr_id = 0xb;
      else if (STREQ (type, "ntfs"))
        mbr_id = 0x7;
      else if (STRPREFIX (type, "ext"))
        mbr_id = 0x83;
      else if (STREQ (type, "minix"))
        mbr_id = 0x81;
    }
    if (mbr_id != 0) {
      if (guestfs_part_set_mbr_id (g, "/dev/sda", 1, mbr_id) == -1)
        return -1;
    }
  }

  if (verbose)
    fprintf (stderr, "creating %s filesystem on %s ...\n", type, dev);

  /* Create the filesystem. */
  if (STRNEQ (type, "btrfs")) {
    int r;
    struct guestfs_mkfs_opts_argv optargs = { .bitmask = 0 };

    if (label) {
      optargs.label = label;
      optargs.bitmask |= GUESTFS_MKFS_OPTS_LABEL_BITMASK;
    }

    guestfs_push_error_handler (g, NULL, NULL);
    r = guestfs_mkfs_opts_argv (g, type, dev, &optargs);
    guestfs_pop_error_handler (g);

    if (r == -1) {
      /* Provide more guidance in the error message (RHBZ#823883). */
      fprintf (stderr, "%s: 'mkfs' (create filesystem) operation failed: %s\n",
               guestfs_int_program_name, guestfs_last_error (g));
      if (STREQ (type, "fat"))
        fprintf (stderr, "Instead of 'fat', try 'vfat' (long filenames) or 'msdos' (short filenames).\n");
      else
        fprintf (stderr, "Is '%s' a correct filesystem type?\n", type);

      return -1;
    }
  }
  else {
示例#27
0
static void
output_root (xmlTextWriterPtr xo, char *root)
{
  char *str;
  int i, r;
  char buf[32];
  char *canonical_root;
  size_t size;

  XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "operatingsystem"));

  canonical_root = guestfs_canonical_device_name (g, root);
  if (canonical_root == NULL)
    exit (EXIT_FAILURE);
  XMLERROR (-1,
	    xmlTextWriterWriteElement (xo, BAD_CAST "root", BAD_CAST canonical_root));
  free (canonical_root);

  str = guestfs_inspect_get_type (g, root);
  if (!str) exit (EXIT_FAILURE);
  if (STRNEQ (str, "unknown"))
    XMLERROR (-1,
	      xmlTextWriterWriteElement (xo, BAD_CAST "name", BAD_CAST str));
  free (str);

  str = guestfs_inspect_get_arch (g, root);
  if (!str) exit (EXIT_FAILURE);
  if (STRNEQ (str, "unknown"))
    XMLERROR (-1,
	      xmlTextWriterWriteElement (xo, BAD_CAST "arch", BAD_CAST str));
  free (str);

  str = guestfs_inspect_get_distro (g, root);
  if (!str) exit (EXIT_FAILURE);
  if (STRNEQ (str, "unknown"))
    XMLERROR (-1,
	      xmlTextWriterWriteElement (xo, BAD_CAST "distro", BAD_CAST str));
  free (str);

  str = guestfs_inspect_get_product_name (g, root);
  if (!str) exit (EXIT_FAILURE);
  if (STRNEQ (str, "unknown"))
    XMLERROR (-1,
	      xmlTextWriterWriteElement (xo, BAD_CAST "product_name", BAD_CAST str));
  free (str);

  str = guestfs_inspect_get_product_variant (g, root);
  if (!str) exit (EXIT_FAILURE);
  if (STRNEQ (str, "unknown"))
    XMLERROR (-1,
	      xmlTextWriterWriteElement (xo, BAD_CAST "product_variant", BAD_CAST str));
  free (str);

  i = guestfs_inspect_get_major_version (g, root);
  snprintf (buf, sizeof buf, "%d", i);
  XMLERROR (-1,
	    xmlTextWriterWriteElement (xo, BAD_CAST "major_version", BAD_CAST buf));
  i = guestfs_inspect_get_minor_version (g, root);
  snprintf (buf, sizeof buf, "%d", i);
  XMLERROR (-1,
	    xmlTextWriterWriteElement (xo, BAD_CAST "minor_version", BAD_CAST buf));

  str = guestfs_inspect_get_package_format (g, root);
  if (!str) exit (EXIT_FAILURE);
  if (STRNEQ (str, "unknown"))
    XMLERROR (-1,
	      xmlTextWriterWriteElement (xo, BAD_CAST "package_format", BAD_CAST str));
  free (str);

  str = guestfs_inspect_get_package_management (g, root);
  if (!str) exit (EXIT_FAILURE);
  if (STRNEQ (str, "unknown"))
    XMLERROR (-1,
	      xmlTextWriterWriteElement (xo, BAD_CAST "package_management",
					 BAD_CAST str));
  free (str);

  /* inspect-get-windows-systemroot will fail with non-windows guests,
   * or if the systemroot could not be determined for a windows guest.
   * Disable error output around this call.
   */
  guestfs_push_error_handler (g, NULL, NULL);
  str = guestfs_inspect_get_windows_systemroot (g, root);
  if (str)
    XMLERROR (-1,
              xmlTextWriterWriteElement (xo, BAD_CAST "windows_systemroot",
                                         BAD_CAST str));
  free (str);
  str = guestfs_inspect_get_windows_current_control_set (g, root);
  if (str)
    XMLERROR (-1,
              xmlTextWriterWriteElement (xo, BAD_CAST "windows_current_control_set",
                                         BAD_CAST str));
  free (str);
  guestfs_pop_error_handler (g);

  str = guestfs_inspect_get_hostname (g, root);
  if (!str) exit (EXIT_FAILURE);
  if (STRNEQ (str, "unknown"))
    XMLERROR (-1,
	      xmlTextWriterWriteElement (xo, BAD_CAST "hostname",
					 BAD_CAST str));
  free (str);

  str = guestfs_inspect_get_format (g, root);
  if (!str) exit (EXIT_FAILURE);
  if (STRNEQ (str, "unknown"))
    XMLERROR (-1,
	      xmlTextWriterWriteElement (xo, BAD_CAST "format",
					 BAD_CAST str));
  free (str);

  r = guestfs_inspect_is_live (g, root);
  if (r > 0) {
    XMLERROR (-1,
              xmlTextWriterStartElement (xo, BAD_CAST "live"));
    XMLERROR (-1, xmlTextWriterEndElement (xo));
  }

  r = guestfs_inspect_is_netinst (g, root);
  if (r > 0) {
    XMLERROR (-1,
              xmlTextWriterStartElement (xo, BAD_CAST "netinst"));
    XMLERROR (-1, xmlTextWriterEndElement (xo));
  }

  r = guestfs_inspect_is_multipart (g, root);
  if (r > 0) {
    XMLERROR (-1,
              xmlTextWriterStartElement (xo, BAD_CAST "multipart"));
    XMLERROR (-1, xmlTextWriterEndElement (xo));
  }

  output_mountpoints (xo, root);

  output_filesystems (xo, root);

  output_drive_mappings (xo, root);

  /* We need to mount everything up in order to read out the list of
   * applications and the icon, ie. everything below this point.
   */
  inspect_mount_root (g, root);

  output_applications (xo, root);

  /* Don't return favicon.  RHEL 7 and Fedora have crappy 16x16
   * favicons in the base distro.
   */
  str = guestfs_inspect_get_icon (g, root, &size,
                                  GUESTFS_INSPECT_GET_ICON_FAVICON, 0,
                                  -1);
  if (!str) exit (EXIT_FAILURE);
  if (size > 0) {
    XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "icon"));
    XMLERROR (-1, xmlTextWriterWriteBase64 (xo, str, 0, size));
    XMLERROR (-1, xmlTextWriterEndElement (xo));
  }
  /* Note we must free (str) even if size == 0, because that indicates
   * there was no icon.
   */
  free (str);

  /* Unmount (see inspect_mount_root above). */
  if (guestfs_umount_all (g) == -1)
    exit (EXIT_FAILURE);

  XMLERROR (-1, xmlTextWriterEndElement (xo));
}
示例#28
0
static void
do_output_filesystems (void)
{
  size_t i;

  CLEANUP_FREE_STRING_LIST char **fses = guestfs_list_filesystems (g);
  if (fses == NULL)
    exit (EXIT_FAILURE);

  for (i = 0; fses[i] != NULL; i += 2) {
    CLEANUP_FREE char *dev = NULL, *vfs_label = NULL, *vfs_uuid = NULL;
    CLEANUP_FREE_STRING_LIST char **parents = NULL;
    int64_t size = -1;

    /* Skip swap and unknown, unless --extra flag was given. */
    if (!(output & OUTPUT_FILESYSTEMS_EXTRA) &&
        (STREQ (fses[i+1], "swap") || STREQ (fses[i+1], "unknown")))
      continue;

    dev = guestfs_canonical_device_name (g, fses[i]);
    if (dev == NULL)
      exit (EXIT_FAILURE);

    /* Only bother to look these up if we will be displaying them,
     * otherwise pass them as NULL.
     */
    if ((columns & COLUMN_VFS_LABEL)) {
      guestfs_push_error_handler (g, NULL, NULL);
      vfs_label = guestfs_vfs_label (g, fses[i]);
      guestfs_pop_error_handler (g);
      if (vfs_label == NULL) {
        vfs_label = strdup ("");
        if (!vfs_label) {
          perror ("strdup");
          exit (EXIT_FAILURE);
        }
      }
    }
    if ((columns & COLUMN_UUID)) {
      guestfs_push_error_handler (g, NULL, NULL);
      vfs_uuid = guestfs_vfs_uuid (g, fses[i]);
      guestfs_pop_error_handler (g);
      if (vfs_uuid == NULL) {
        vfs_uuid = strdup ("");
        if (!vfs_uuid) {
          perror ("strdup");
          exit (EXIT_FAILURE);
        }
      }
    }
    if ((columns & COLUMN_SIZE)) {
      size = guestfs_blockdev_getsize64 (g, fses[i]);
      if (size == -1)
        exit (EXIT_FAILURE);
    }

    if (is_md (fses[i]))
      parents = parents_of_md (fses[i]);
    else
      parents = no_parents ();

    write_row (dev, "filesystem",
               fses[i+1], vfs_label, -1, size, parents, vfs_uuid);
  }
}
示例#29
0
/* Find out if 'device' contains a filesystem.  If it does, add
 * another entry in g->fses.
 */
int
guestfs_int_check_for_filesystem_on (guestfs_h *g, const char *mountable)
{
  CLEANUP_FREE char *vfs_type = NULL;
  int is_swap, r;
  struct inspect_fs *fs;
  CLEANUP_FREE_INTERNAL_MOUNTABLE struct guestfs_internal_mountable *m = NULL;
  int whole_device = 0;

  /* Get vfs-type in order to check if it's a Linux(?) swap device.
   * If there's an error we should ignore it, so to do that we have to
   * temporarily replace the error handler with a null one.
   */
  guestfs_push_error_handler (g, NULL, NULL);
  vfs_type = guestfs_vfs_type (g, mountable);
  guestfs_pop_error_handler (g);

  is_swap = vfs_type && STREQ (vfs_type, "swap");
  debug (g, "check_for_filesystem_on: %s (%s)",
         mountable, vfs_type ? vfs_type : "failed to get vfs type");

  if (is_swap) {
    extend_fses (g);
    fs = &g->fses[g->nr_fses-1];
    fs->mountable = safe_strdup (g, mountable);
    return 0;
  }

  m = guestfs_internal_parse_mountable (g, mountable);
  if (m == NULL)
    return -1;

  /* If it's a whole device, see if it is an install ISO. */
  if (m->im_type == MOUNTABLE_DEVICE) {
    whole_device = guestfs_is_whole_device (g, m->im_device);
    if (whole_device == -1) {
      return -1;
    }
  }

  if (whole_device) {
    extend_fses (g);
    fs = &g->fses[g->nr_fses-1];

    r = guestfs_int_check_installer_iso (g, fs, m->im_device);
    if (r == -1) {              /* Fatal error. */
      g->nr_fses--;
      return -1;
    }
    if (r > 0)                  /* Found something. */
      return 0;

    /* Didn't find anything.  Fall through ... */
    g->nr_fses--;
  }

  /* Try mounting the device.  As above, ignore errors. */
  guestfs_push_error_handler (g, NULL, NULL);
  if (vfs_type && STREQ (vfs_type, "ufs")) { /* Hack for the *BSDs. */
    /* FreeBSD fs is a variant of ufs called ufs2 ... */
    r = guestfs_mount_vfs (g, "ro,ufstype=ufs2", "ufs", mountable, "/");
    if (r == -1)
      /* while NetBSD and OpenBSD use another variant labeled 44bsd */
      r = guestfs_mount_vfs (g, "ro,ufstype=44bsd", "ufs", mountable, "/");
  } else {
    r = guestfs_mount_ro (g, mountable, "/");
  }
  guestfs_pop_error_handler (g);
  if (r == -1)
    return 0;

  /* Do the rest of the checks. */
  r = check_filesystem (g, mountable, m, whole_device);

  /* Unmount the filesystem. */
  if (guestfs_umount_all (g) == -1)
    return -1;

  return r;
}
示例#30
0
static void
test_virtio_serial (void)
{
  int fd, r, eh;
  char tmpfile[] = "/tmp/speedtestXXXXXX";
  struct sigaction sa, old_sa;

  if (!virtio_serial_upload && !virtio_serial_download)
    return;

  /* Create a sparse file.  We could upload from /dev/zero, but we
   * won't get progress messages because libguestfs tests if the
   * source file is a regular file.
   */
  fd = mkstemp (tmpfile);
  if (fd == -1)
    error (EXIT_FAILURE, errno, "mkstemp: %s", tmpfile);
  if (ftruncate (fd, TEST_SERIAL_MAX_SIZE) == -1)
    error (EXIT_FAILURE, errno, "ftruncate");
  if (close (fd) == -1)
    error (EXIT_FAILURE, errno, "close");

  g = guestfs_create ();
  if (!g)
    error (EXIT_FAILURE, errno, "guestfs_create");

  if (guestfs_add_drive_scratch (g, INT64_C (100*1024*1024), -1) == -1)
    exit (EXIT_FAILURE);

  if (guestfs_launch (g) == -1)
    exit (EXIT_FAILURE);

  /* Make and mount a filesystem which will be used by the download test. */
  if (guestfs_mkfs (g, "ext4", "/dev/sda") == -1)
    exit (EXIT_FAILURE);
  if (guestfs_mount (g, "/dev/sda", "/") == -1)
    exit (EXIT_FAILURE);

  /* Time out the upload after TEST_SERIAL_MAX_TIME seconds have passed. */
  memset (&sa, 0, sizeof sa);
  sa.sa_handler = stop_transfer;
  sa.sa_flags = SA_RESTART;
  sigaction (SIGALRM, &sa, &old_sa);

  /* Get progress messages, which will tell us how much data has been
   * transferred.
   */
  eh = guestfs_set_event_callback (g, progress_cb, GUESTFS_EVENT_PROGRESS,
                                   0, NULL);
  if (eh == -1)
    exit (EXIT_FAILURE);

  if (virtio_serial_upload) {
    gettimeofday (&start, NULL);
    rate = -1;
    operation = "upload";
    alarm (max_time_override > 0 ? max_time_override : TEST_SERIAL_MAX_TIME);

    /* For the upload test, upload the sparse file to /dev/null in the
     * appliance.  Hopefully this is mostly testing just virtio-serial.
     */
    guestfs_push_error_handler (g, NULL, NULL);
    r = guestfs_upload (g, tmpfile, "/dev/null");
    alarm (0);
    unlink (tmpfile);
    guestfs_pop_error_handler (g);

    /* It's possible that the upload will finish before the alarm fires,
     * or that the upload will be stopped by the alarm.
     */
    if (r == -1 && guestfs_last_errno (g) != EINTR) {
      fprintf (stderr,
               "%s: expecting upload command to return EINTR\n%s\n",
               guestfs_int_program_name, guestfs_last_error (g));
      exit (EXIT_FAILURE);
    }

    if (rate == -1) {
    rate_error:
      fprintf (stderr, "%s: internal error: progress callback was not called! (r=%d, errno=%d)\n",
               guestfs_int_program_name,
               r, guestfs_last_errno (g));
      exit (EXIT_FAILURE);
    }

    print_rate ("virtio-serial upload rate:", rate);
  }

  if (virtio_serial_download) {
    /* For the download test, download a sparse file within the
     * appliance to /dev/null on the host.
     */
    if (guestfs_touch (g, "/sparse") == -1)
      exit (EXIT_FAILURE);
    if (guestfs_truncate_size (g, "/sparse", TEST_SERIAL_MAX_SIZE) == -1)
      exit (EXIT_FAILURE);

    gettimeofday (&start, NULL);
    rate = -1;
    operation = "download";
    alarm (max_time_override > 0 ? max_time_override : TEST_SERIAL_MAX_TIME);
    guestfs_push_error_handler (g, NULL, NULL);
    r = guestfs_download (g, "/sparse", "/dev/null");
    alarm (0);
    guestfs_pop_error_handler (g);

    if (r == -1 && guestfs_last_errno (g) != EINTR) {
      fprintf (stderr,
               "%s: expecting download command to return EINTR\n%s\n",
               guestfs_int_program_name, guestfs_last_error (g));
      exit (EXIT_FAILURE);
    }

    if (rate == -1)
      goto rate_error;

    print_rate ("virtio-serial download rate:", rate);
  }

  if (guestfs_shutdown (g) == -1)
    exit (EXIT_FAILURE);

  guestfs_close (g);

  /* Restore SIGALRM signal handler. */
  sigaction (SIGALRM, &old_sa, NULL);
}