Beispiel #1
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 {
Beispiel #2
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;
}