Esempio n. 1
0
static void
do_output_blockdevs (void)
{
  size_t i;

  CLEANUP_FREE_STRING_LIST char **devices = guestfs_list_devices (g);
  if (devices == NULL)
    exit (EXIT_FAILURE);

  for (i = 0; devices[i] != NULL; ++i) {
    int64_t size = -1;
    CLEANUP_FREE_STRING_LIST char **parents = NULL;
    CLEANUP_FREE char *dev;

    dev = guestfs_canonical_device_name (g, devices[i]);
    if (!dev)
      exit (EXIT_FAILURE);

    if ((columns & COLUMN_SIZE)) {
      size = guestfs_blockdev_getsize64 (g, devices[i]);
      if (size == -1)
        exit (EXIT_FAILURE);
    }

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

    write_row (dev, "device",
               NULL, NULL, -1, size, parents, NULL);
  }
}
Esempio n. 2
0
/* Perform 'df' operation on the domain(s) given in the list. */
static void
multi_df (struct domain *domains, size_t n, size_t *errors_r)
{
  size_t i;
  size_t nd;
  size_t count;
  int r;
  char **devices;
  char **domain_devices;

  /* Add all the disks to the handle (since they were added in reverse
   * order, we must add them here in reverse too).
   */
  for (i = 0, count = 0; i < n; ++i)
    count += add_disks_to_handle_reverse (domains[i].disks, errors_r);
  if (count == 0)
    return;

  /* Launch the handle. */
  if (guestfs_launch (g) == -1)
    exit (EXIT_FAILURE);

  devices = guestfs_list_devices (g);
  if (devices == NULL)
    exit (EXIT_FAILURE);

  for (i = 0, nd = 0; i < n; ++i) {
    /* Find out how many non-failed disks this domain has. */
    count = count_non_failed_disks (domains[i].disks);
    if (count == 0)
      continue;

    /* Duplicate the devices into a separate list for convenience.
     * Note this doesn't duplicate the strings themselves.
     */
    domain_devices = duplicate_first_n (&devices[nd], count);

    r = df_on_handle (domains[i].name, domains[i].uuid, domain_devices, nd);
    nd += count;
    free (domain_devices);

    /* Something broke in df_on_handle.  Give up on the remaining
     * devices for this handle, but keep going on the next handle.
     */
    if (r == -1) {
      (*errors_r)++;
      break;
    }
  }

  for (i = 0; devices[i] != NULL; ++i)
    free (devices[i]);
  free (devices);

  /* Reset the handle. */
  reset_guestfs_handle ();
}
Esempio n. 3
0
/* Perform 'df' operation on the domain(s) given in the list. */
static void
multi_df (struct domain *domains, size_t n)
{
  size_t i;
  size_t nd;
  int r;
  char **devices;

  /* Add all the disks to the handle (since they were added in reverse
   * order, we must add them here in reverse too).
   */
  for (i = 0; i < n; ++i)
    add_disks_to_handle_reverse (domains[i].disks);

  /* Launch the handle. */
  if (guestfs_launch (g) == -1)
    exit (EXIT_FAILURE);

  devices = guestfs_list_devices (g);
  if (devices == NULL)
    exit (EXIT_FAILURE);

  /* Check the number of disks we think we added is the same as the
   * number of devices returned by libguestfs.
   */
  nd = 0;
  for (i = 0; i < n; ++i)
    nd += domains[i].nr_disks;
  assert (nd == count_strings (devices));

  nd = 0;
  for (i = 0; i < n; ++i) {
    /* So that &devices[nd] is a NULL-terminated list of strings. */
    char *p = devices[nd + domains[i].nr_disks];
    devices[nd + domains[i].nr_disks] = NULL;

    r = df_on_handle (domains[i].name, domains[i].uuid, &devices[nd], nd);

    /* Restore devices to original. */
    devices[nd + domains[i].nr_disks] = p;
    nd += domains[i].nr_disks;

    /* Something broke in df_on_handle.  Give up on the remaining
     * devices for this handle, but keep going on the next handle.
     */
    if (r == -1)
      break;
  }

  for (i = 0; devices[i] != NULL; ++i)
    free (devices[i]);
  free (devices);

  /* Reset the handle. */
  reset_guestfs_handle ();
}
/* Windows Registry HKLM\SYSTEM\MountedDevices uses a blob of data
 * to store partitions.  This blob is described here:
 * http://www.goodells.net/multiboot/partsigs.shtml
 * The following function maps this blob to a libguestfs partition
 * name, if possible.
 */
static char *
map_registry_disk_blob (guestfs_h *g, const void *blob)
{
  CLEANUP_FREE_STRING_LIST char **devices = NULL;
  CLEANUP_FREE_PARTITION_LIST struct guestfs_partition_list *partitions = NULL;
  size_t i, j, len;
  uint64_t part_offset;

  /* First 4 bytes are the disk ID.  Search all devices to find the
   * disk with this disk ID.
   */
  devices = guestfs_list_devices (g);
  if (devices == NULL)
    return NULL;

  for (i = 0; devices[i] != NULL; ++i) {
    /* Read the disk ID. */
    CLEANUP_FREE char *diskid =
      guestfs_pread_device (g, devices[i], 4, 0x01b8, &len);
    if (diskid == NULL)
      continue;
    if (len < 4)
      continue;
    if (memcmp (diskid, blob, 4) == 0) /* found it */
      goto found_disk;
  }
  return NULL;

 found_disk:
  /* Next 8 bytes are the offset of the partition in bytes(!) given as
   * a 64 bit little endian number.  Luckily it's easy to get the
   * partition byte offset from guestfs_part_list.
   */
  memcpy (&part_offset, (char *) blob + 4, sizeof (part_offset));
  part_offset = le64toh (part_offset);

  partitions = guestfs_part_list (g, devices[i]);
  if (partitions == NULL)
    return NULL;

  for (j = 0; j < partitions->len; ++j) {
    if (partitions->val[j].part_start == part_offset) /* found it */
      goto found_partition;
  }
  return NULL;

 found_partition:
  /* Construct the full device name. */
  return safe_asprintf (g, "%s%d", devices[i], partitions->val[j].part_num);
}
Esempio n. 5
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;
}
Esempio n. 6
0
static void
test_block_device (void)
{
  int fd;
  char tmpfile[] = "/tmp/speedtestXXXXXX";
  CLEANUP_FREE char **devices = NULL;
  char *r;
  const char *argv[4];
  int t = max_time_override > 0 ? max_time_override : TEST_BLOCK_DEVICE_TIME;
  char tbuf[64];
  int64_t bytes_written, bytes_read;

  if (!block_device_write && !block_device_read)
    return;

  snprintf (tbuf, sizeof tbuf, "%d", t);

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

  /* Create a fully allocated backing file.  Note we are not testing
   * the speed of allocation on the host.
   */
  fd = mkstemp (tmpfile);
  if (fd == -1)
    error (EXIT_FAILURE, errno, "mkstemp: %s", tmpfile);
  close (fd);

  if (guestfs_disk_create (g, tmpfile, "raw",
                           INT64_C (1024*1024*1024),
                           GUESTFS_DISK_CREATE_PREALLOCATION, "full",
                           -1) == -1)
    exit (EXIT_FAILURE);

  if (guestfs_add_drive (g, tmpfile) == -1)
    exit (EXIT_FAILURE);

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

  devices = guestfs_list_devices (g);
  if (devices == NULL)
    exit (EXIT_FAILURE);
  if (devices[0] == NULL) {
    fprintf (stderr, "%s: expected guestfs_list_devices to return at least 1 device\n",
             guestfs_int_program_name);
    exit (EXIT_FAILURE);
  }

  if (block_device_write) {
    /* Test write speed. */
    argv[0] = devices[0];
    argv[1] = "w";
    argv[2] = tbuf;
    argv[3] = NULL;
    r = guestfs_debug (g, "device_speed", (char **) argv);
    if (r == NULL)
      exit (EXIT_FAILURE);

    if (sscanf (r, "%" SCNi64, &bytes_written) != 1) {
      fprintf (stderr, "%s: could not parse device_speed output\n",
               guestfs_int_program_name);
      exit (EXIT_FAILURE);
    }

    print_rate ("block device writes:", bytes_written / t);
  }

  if (block_device_read) {
    /* Test read speed. */
    argv[0] = devices[0];
    argv[1] = "r";
    argv[2] = tbuf;
    argv[3] = NULL;
    r = guestfs_debug (g, "device_speed", (char **) argv);
    if (r == NULL)
      exit (EXIT_FAILURE);

    if (sscanf (r, "%" SCNi64, &bytes_read) != 1) {
      fprintf (stderr, "%s: could not parse device_speed output\n",
               guestfs_int_program_name);
      exit (EXIT_FAILURE);
    }

    print_rate ("block device reads:", bytes_read / t);
  }

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

  guestfs_close (g);

  /* Remove temporary file. */
  unlink (tmpfile);
}
Esempio n. 7
0
void
scan (size_t *worst_alignment, const char *prefix)
{
  char **devices, *p;
  size_t i, j;
  size_t alignment;
  uint64_t start;
  struct guestfs_partition_list *parts;

  devices = guestfs_list_devices (g);
  if (devices == NULL)
    exit (EXIT_FAILURE);

  for (i = 0; devices[i] != NULL; ++i) {
    parts = guestfs_part_list (g, devices[i]);
    if (parts == NULL)
      exit (EXIT_FAILURE);

    /* Canonicalize the name of the device for printing. */
    p = guestfs_canonical_device_name (g, devices[i]);
    if (p == NULL)
      exit (EXIT_FAILURE);
    free (devices[i]);
    devices[i] = p;

    for (j = 0; j < parts->len; ++j) {
      /* Start offset of the partition in bytes. */
      start = parts->val[j].part_start;

      if (!quiet) {
        if (prefix)
          printf ("%s:", prefix);

        printf ("%s%d %12" PRIu64 " ",
                devices[i], (int) parts->val[j].part_num, start);
      }

      /* What's the alignment? */
      if (start == 0)           /* Probably not possible, but anyway. */
        alignment = 64;
      else
        for (alignment = 0; (start & 1) == 0; alignment++, start /= 2)
          ;

      if (!quiet) {
        if (alignment < 10)
          printf ("%12" PRIu64 "    ", UINT64_C(1) << alignment);
        else if (alignment < 64)
          printf ("%12" PRIu64 "K   ", UINT64_C(1) << (alignment - 10));
        else
          printf ("- ");
      }

      if (alignment < *worst_alignment)
        *worst_alignment = alignment;

      if (alignment < 12) {     /* Bad in general: < 4K alignment */
        if (!quiet)
          printf ("bad (%s)\n", _("alignment < 4K"));
      } else if (alignment < 16) { /* Bad on NetApps: < 64K alignment */
        if (!quiet)
          printf ("bad (%s)\n", _("alignment < 64K"));
      } else {
        if (!quiet)
          printf ("ok\n");
      }
    }

    guestfs_free_partition_list (parts);
    free (devices[i]);
  }
  free (devices);
}
Esempio n. 8
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 (const char *name, const char *uuid, char **devices, int offset)
{
  int ret = -1;
  size_t i;
  char **fses = NULL;
  int free_devices = 0, is_lv;

  if (verbose) {
    fprintf (stderr, "df_on_handle %s devices=", name);
    if (devices) {
      fputc ('[', stderr);
      for (i = 0; devices[i] != NULL; ++i) {
        if (i > 0)
          fputc (' ', stderr);
        fputs (devices[i], stderr);
      }
      fputc (']', stderr);
    }
    else
      fprintf (stderr, "null");
    fputc ('\n', stderr);
  }

  if (devices == NULL) {
    devices = guestfs_list_devices (g);
    if (devices == NULL)
      goto cleanup;
    free_devices = 1;
  } else {
    /* Mask LVM for just the devices in the set. */
    if (guestfs_lvm_set_filter (g, devices) == -1)
      goto cleanup;
  }

  /* list-filesystems will return filesystems on every device ... */
  fses = guestfs_list_filesystems (g);
  if (fses == NULL)
    goto cleanup;

  /* ... so we need to filter out only the devices we are interested in. */
  for (i = 0; fses[i] != NULL; i += 2) {
    if (STRNEQ (fses[i+1], "") &&
        STRNEQ (fses[i+1], "swap") &&
        STRNEQ (fses[i+1], "unknown")) {
      is_lv = guestfs_is_lv (g, fses[i]);
      if (is_lv > 0)        /* LVs are OK because of the LVM filter */
        try_df (name, uuid, fses[i], -1);
      else if (is_lv == 0) {
        if (find_dev_in_devices (fses[i], devices))
          try_df (name, uuid, fses[i], offset);
      }
    }
  }

  ret = 0;

 cleanup:
  if (fses) {
    for (i = 0; fses[i] != NULL; ++i)
      free (fses[i]);
    free (fses);
  }

  if (free_devices) {
    for (i = 0; devices[i] != NULL; ++i)
      free (devices[i]);
    free (devices);
  }

  return ret;
}
Esempio n. 9
0
char *
complete_dest_paths_generator (const char *text, int state)
{
#ifdef HAVE_LIBREADLINE

  static size_t len, index;
  static struct word *words = NULL;
  static size_t nr_words = 0;
  guestfs_error_handler_cb old_error_cb;
  void *old_error_cb_data;

  /* Temporarily replace the error handler so that messages don't
   * get printed to stderr while we are issuing commands.
   */
#define SAVE_ERROR_CB							\
  old_error_cb = guestfs_get_error_handler (g, &old_error_cb_data);	\
  guestfs_set_error_handler (g, NULL, NULL);

  /* Restore error handler. */
#define RESTORE_ERROR_CB						\
  guestfs_set_error_handler (g, old_error_cb, old_error_cb_data);

  if (!state) {
    char **strs;

    len = strlen (text);
    index = 0;

    if (words) free_words (words, nr_words);

    words = NULL;
    nr_words = 0;

    SAVE_ERROR_CB

/* Silently do nothing if an allocation fails */
#define APPEND_STRS_AND_FREE						\
  do {									\
    if (strs) {								\
      size_t i;								\
      size_t n = count_strings (strs);					\
                                                                        \
      if ( n > 0 && ! xalloc_oversized (nr_words + n, sizeof (struct word))) { \
        struct word *w;							\
        w = realloc (words, sizeof (struct word) * (nr_words + n));	\
                                                                        \
        if (w == NULL) {						\
          free_words (words, nr_words);					\
          words = NULL;							\
          nr_words = 0;							\
        } else {							\
          words = w;							\
          for (i = 0; i < n; ++i) {					\
            words[nr_words].name = strs[i];				\
            words[nr_words].is_dir = 0;					\
            nr_words++;							\
          }								\
        }								\
      }									\
      free (strs);							\
    }									\
  } while (0)

    /* Is it a device? */
    if (len < 5 || STREQLEN (text, "/dev/", 5)) {
      /* Get a list of everything that can possibly begin with /dev/ */
      strs = guestfs_list_devices (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_list_partitions (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_lvs (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_list_dm_devices (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_list_md_devices (g);
      APPEND_STRS_AND_FREE;
    }

    if (len < 1 || text[0] == '/') {
      /* If we've got a partial path already, we need to list everything
       * in that directory, otherwise list everything in /
       */
      char *p, *dir;
      struct guestfs_dirent_list *dirents;

      p = strrchr (text, '/');
      dir = p && p > text ? strndup (text, p - text) : strdup ("/");
      if (dir) {
        dirents = guestfs_readdir (g, dir);

        /* Prepend directory to names before adding them to the list
         * of words.
         */
        if (dirents) {
          size_t i;

          for (i = 0; i < dirents->len; ++i) {
            int err;

            if (STRNEQ (dirents->val[i].name, ".") &&
                STRNEQ (dirents->val[i].name, "..")) {
              if (STREQ (dir, "/"))
                err = asprintf (&p, "/%s", dirents->val[i].name);
              else
                err = asprintf (&p, "%s/%s", dir, dirents->val[i].name);
              if (err >= 0) {
                if (!xalloc_oversized (nr_words+1, sizeof (struct word))) {
                  struct word *w;

                  w = realloc (words, sizeof (struct word) * (nr_words+1));
                  if (w == NULL) {
                    free_words (words, nr_words);
                    words = NULL;
                    nr_words = 0;
                  }
                  else {
                    words = w;
                    words[nr_words].name = p;
                    words[nr_words].is_dir = dirents->val[i].ftyp == 'd';
                    nr_words++;
                  }
                }
              }
            }
          }

          guestfs_free_dirent_list (dirents);
        }
      }
    }

    /* else ...  In theory we could complete other things here such as VG
     * names.  At the moment we don't do that.
     */

    RESTORE_ERROR_CB
  }
Esempio n. 10
0
/* Returns 0 on success, 1 if we need to retry. */
static int
do_format (void)
{
  char **devices;
  size_t i;
  int ret;

  devices = guestfs_list_devices (g);
  if (devices == NULL)
    exit (EXIT_FAILURE);

  /* Erase the disks. */
  if (!wipe) {
    for (i = 0; devices[i] != NULL; ++i) {
      /* erase the filesystem signatures on each device */
      if (have_wipefs && guestfs_wipefs (g, devices[i]) == -1)
        exit (EXIT_FAILURE);
      /* Then erase the partition table on each device. */
      if (guestfs_zero (g, devices[i]) == -1)
        exit (EXIT_FAILURE);
    }
  }
  else /* wipe */ {
    for (i = 0; devices[i] != NULL; ++i) {
      if (guestfs_zero_device (g, devices[i]) == -1)
        exit (EXIT_FAILURE);
    }
  }

  if (do_rescan (devices)) {
    ret = 1; /* which means, reopen the handle and retry */
    goto out;
  }

  /* Format each disk. */
  for (i = 0; devices[i] != NULL; ++i) {
    char *dev = devices[i];
    int free_dev = 0;

    if (partition) {
      const char *ptype = partition;
      int64_t dev_size;

      /* If partition has the magic value "DEFAULT", choose either MBR or GPT.*/
      if (STREQ (partition, "DEFAULT")) {
        dev_size = guestfs_blockdev_getsize64 (g, devices[i]);
        if (dev_size == -1)
          exit (EXIT_FAILURE);
        ptype = dev_size < INT64_C(2)*1024*1024*1024*1024 ? "mbr" : "gpt";
      }

      if (guestfs_part_disk (g, devices[i], ptype) == -1)
        exit (EXIT_FAILURE);
      if (asprintf (&dev, "%s1", devices[i]) == -1) {
        perror ("asprintf");
        exit (EXIT_FAILURE);
      }
      free_dev = 1;
    }

    if (vg && lv) {
      char *devs[2] = { dev, NULL };

      if (guestfs_pvcreate (g, dev) == -1)
        exit (EXIT_FAILURE);

      if (guestfs_vgcreate (g, vg, devs) == -1)
        exit (EXIT_FAILURE);

      if (guestfs_lvcreate_free (g, lv, vg, 100) == -1)
        exit (EXIT_FAILURE);

      if (free_dev)
        free (dev);
      if (asprintf (&dev, "/dev/%s/%s", vg, lv) == -1) {
        perror ("asprintf");
        exit (EXIT_FAILURE);
      }
      free_dev = 1;
    }

    if (filesystem) {
      if (guestfs_mkfs_opts (g, filesystem, dev, -1) == -1)
        exit (EXIT_FAILURE);
    }

    if (free_dev)
      free (dev);
  }

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

  ret = 0;

 out:
  /* Free device list. */
  for (i = 0; devices[i] != NULL; ++i)
    free (devices[i]);
  free (devices);

  return ret;
}
Esempio n. 11
0
char *
complete_dest_paths_generator (const char *text, int state)
{
#ifdef HAVE_LIBREADLINE

  static size_t len, index;
  static struct word *words = NULL;
  static size_t nr_words = 0;

  if (!state) {
    char **strs;

    len = strlen (text);
    index = 0;

    if (words) free_words (words, nr_words);

    words = NULL;
    nr_words = 0;

    guestfs_push_error_handler (g, NULL, NULL);

/* Silently do nothing if an allocation fails */
#define APPEND_STRS_AND_FREE						\
  do {									\
    if (strs) {								\
      size_t i;								\
      size_t n = count_strings (strs);					\
                                                                        \
      if ( n > 0 && ! xalloc_oversized (nr_words + n, sizeof (struct word))) { \
        struct word *w;							\
        w = realloc (words, sizeof (struct word) * (nr_words + n));	\
                                                                        \
        if (w == NULL) {						\
          free_words (words, nr_words);					\
          words = NULL;							\
          nr_words = 0;							\
        } else {							\
          words = w;							\
          for (i = 0; i < n; ++i) {					\
            words[nr_words].name = strs[i];				\
            words[nr_words].is_dir = 0;					\
            nr_words++;							\
          }								\
        }								\
      }									\
      free (strs);							\
    }									\
  } while (0)

    /* Is it a device? */
    if (len < 5 || STREQLEN (text, "/dev/", 5)) {
      /* Get a list of everything that can possibly begin with /dev/ */
      strs = guestfs_list_devices (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_list_partitions (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_lvs (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_list_dm_devices (g);
      APPEND_STRS_AND_FREE;

      strs = guestfs_list_md_devices (g);
      APPEND_STRS_AND_FREE;
    }

    if (len < 1 || text[0] == '/') {
      /* If we've got a partial path already, we need to list everything
       * in that directory, otherwise list everything in /
       */
      char *p, *dir;
      struct guestfs_dirent_list *dirents;

      p = strrchr (text, '/');
      dir = p && p > text ? strndup (text, p - text) : strdup ("/");
      if (dir) {
        dirents = guestfs_readdir (g, dir);

        /* Prepend directory to names before adding them to the list
         * of words.
         */
        if (dirents) {
          size_t i;

          for (i = 0; i < dirents->len; ++i) {
            int err;

            if (STRNEQ (dirents->val[i].name, ".") &&
                STRNEQ (dirents->val[i].name, "..")) {
              if (STREQ (dir, "/"))
                err = asprintf (&p, "/%s", dirents->val[i].name);
              else
                err = asprintf (&p, "%s/%s", dir, dirents->val[i].name);
              if (err >= 0) {
                if (!xalloc_oversized (nr_words+1, sizeof (struct word))) {
                  struct word *w;

                  w = realloc (words, sizeof (struct word) * (nr_words+1));
                  if (w == NULL) {
                    free_words (words, nr_words);
                    words = NULL;
                    nr_words = 0;
                  }
                  else {
                    words = w;
                    words[nr_words].name = p;
                    words[nr_words].is_dir = dirents->val[i].ftyp == 'd';
                    nr_words++;
                  }
                }
              }
            }
          }

          guestfs_free_dirent_list (dirents);
        }
      }
    }

    /* else ...  In theory we could complete other things here such as VG
     * names.  At the moment we don't do that.
     */

    guestfs_pop_error_handler (g);
  }

  /* This inhibits ordinary (local filename) completion. */
  rl_attempted_completion_over = 1;

  /* Sort the words so the list is stable over multiple calls. */
  if (words)
    qsort (words, nr_words, sizeof (struct word), compare_words);

  /* Complete the string. */
  while (index < nr_words) {
    struct word *word;

    word = &words[index];
    index++;

    /* Whether we should match case insensitively here or not is
     * determined by the value of the completion-ignore-case readline
     * variable.  Default to case insensitive.  (See: RHBZ#582993).
     */
    char *cic_var = rl_variable_value ("completion-ignore-case");
    int cic = 1;
    if (cic_var && STREQ (cic_var, "off"))
      cic = 0;

    int matches =
      cic ? STRCASEEQLEN (word->name, text, len)
          : STREQLEN (word->name, text, len);

    if (matches) {
      if (word->is_dir)
        rl_completion_append_character = '/';

      return strdup (word->name);
    }
  }

#endif /* HAVE_LIBREADLINE */

  return NULL;
}
Esempio n. 12
0
static int
scan (guestfs_h *g, const char *prefix, FILE *fp)
{
  size_t i, j;
  size_t alignment;
  uint64_t start;
  int err;

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

  for (i = 0; devices[i] != NULL; ++i) {
    CLEANUP_FREE char *name = NULL;

    CLEANUP_FREE_PARTITION_LIST struct guestfs_partition_list *parts =
      guestfs_part_list (g, devices[i]);
    if (parts == NULL)
      return -1;

    /* Canonicalize the name of the device for printing. */
    name = guestfs_canonical_device_name (g, devices[i]);
    if (name == NULL)
      return -1;

    for (j = 0; j < parts->len; ++j) {
      /* Start offset of the partition in bytes. */
      start = parts->val[j].part_start;

      if (!quiet) {
        if (prefix)
          fprintf (fp, "%s:", prefix);

        fprintf (fp, "%s%d %12" PRIu64 " ",
                 name, (int) parts->val[j].part_num, start);
      }

      /* What's the alignment? */
      if (start == 0)           /* Probably not possible, but anyway. */
        alignment = 64;
      else
        for (alignment = 0; (start & 1) == 0; alignment++, start /= 2)
          ;

      if (!quiet) {
        if (alignment < 10)
          fprintf (fp, "%12" PRIu64 "    ", UINT64_C(1) << alignment);
        else if (alignment < 64)
          fprintf (fp, "%12" PRIu64 "K   ", UINT64_C(1) << (alignment - 10));
        else
          fprintf (fp, "- ");
      }

      err = pthread_mutex_lock (&worst_alignment_mutex);
      assert (err == 0);
      if (alignment < worst_alignment)
        worst_alignment = alignment;
      err = pthread_mutex_unlock (&worst_alignment_mutex);
      assert (err == 0);

      if (alignment < 12) {     /* Bad in general: < 4K alignment */
        if (!quiet)
          fprintf (fp, "bad (%s)\n", _("alignment < 4K"));
      } else if (alignment < 16) { /* Bad on NetApps: < 64K alignment */
        if (!quiet)
          fprintf (fp, "bad (%s)\n", _("alignment < 64K"));
      } else {
        if (!quiet)
          fprintf (fp, "ok\n");
      }
    }
  }

  return 0;
}
Esempio n. 13
0
/* Returns 0 on success, 1 if we need to retry. */
static int
do_format (void)
{
  size_t i;

  CLEANUP_FREE_STRING_LIST char **devices =
    guestfs_list_devices (g);
  if (devices == NULL)
    exit (EXIT_FAILURE);

  /* Erase the disks. */
  if (!wipe) {
    for (i = 0; devices[i] != NULL; ++i) {
      /* erase the filesystem signatures on each device */
      if (have_wipefs && guestfs_wipefs (g, devices[i]) == -1)
        exit (EXIT_FAILURE);
      /* Then erase the partition table on each device. */
      if (guestfs_zero (g, devices[i]) == -1)
        exit (EXIT_FAILURE);
    }
  }
  else /* wipe */ {
    for (i = 0; devices[i] != NULL; ++i) {
      if (guestfs_zero_device (g, devices[i]) == -1)
        exit (EXIT_FAILURE);
    }
  }

  /* Send TRIM/UNMAP to all block devices, to give back the space to
   * the host.  However don't fail if this doesn't work.
   */
  guestfs_push_error_handler (g, NULL, NULL);
  for (i = 0; devices[i] != NULL; ++i)
    guestfs_blkdiscard (g, devices[i]);
  guestfs_pop_error_handler (g);

  if (do_rescan (devices))
    return 1; /* which means, reopen the handle and retry */

  /* Format each disk. */
  for (i = 0; devices[i] != NULL; ++i) {
    char *dev = devices[i];
    int free_dev = 0;

    if (partition) {
      const char *ptype = partition;
      int64_t dev_size;

      /* If partition has the magic value "DEFAULT", choose either MBR or GPT.*/
      if (STREQ (partition, "DEFAULT")) {
        dev_size = guestfs_blockdev_getsize64 (g, devices[i]);
        if (dev_size == -1)
          exit (EXIT_FAILURE);
        ptype = dev_size < INT64_C(2)*1024*1024*1024*1024 ? "mbr" : "gpt";
      }

      if (guestfs_part_disk (g, devices[i], ptype) == -1)
        exit (EXIT_FAILURE);
      if (asprintf (&dev, "%s1", devices[i]) == -1) {
        perror ("asprintf");
        exit (EXIT_FAILURE);
      }
      free_dev = 1;

      /* Set the partition type byte appropriately, otherwise Windows
       * won't see the filesystem (RHBZ#1000428).
       */
      if (STREQ (ptype, "mbr") || STREQ (ptype, "msdos")) {
        int mbr_id = 0;

        if (vg && lv)
          mbr_id = 0x8e;
        else if (filesystem) {
          if (STREQ (filesystem, "msdos"))
            mbr_id = 0x01;
          else if (STREQ (filesystem, "fat") || STREQ (filesystem, "vfat"))
            mbr_id = 0x0b;
          else if (STREQ (filesystem, "ntfs"))
            mbr_id = 0x07;
          else if (STRPREFIX (filesystem, "ext"))
            mbr_id = 0x83;
          else if (STREQ (filesystem, "minix"))
            mbr_id = 0x81;
        }

        if (mbr_id > 0)
          guestfs_part_set_mbr_id (g, devices[i], 1, mbr_id);
      }
    }

    if (vg && lv) {
      char *devs[2] = { dev, NULL };

      if (guestfs_pvcreate (g, dev) == -1)
        exit (EXIT_FAILURE);

      if (guestfs_vgcreate (g, vg, devs) == -1)
        exit (EXIT_FAILURE);

      if (guestfs_lvcreate_free (g, lv, vg, 100) == -1)
        exit (EXIT_FAILURE);

      if (free_dev)
        free (dev);
      if (asprintf (&dev, "/dev/%s/%s", vg, lv) == -1) {
        perror ("asprintf");
        exit (EXIT_FAILURE);
      }
      free_dev = 1;
    }

    if (filesystem) {
      if (guestfs_mkfs_opts (g, filesystem, dev, -1) == -1)
        exit (EXIT_FAILURE);

      if (label) {
        if (guestfs_set_label (g, dev, label) == -1)
          exit (EXIT_FAILURE);
      }
    }

    if (free_dev)
      free (dev);
  }

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

  return 0;
}