Exemple #1
0
int CgptSetAttributes(CgptAddParams *params) {
  struct drive drive;

  if (params == NULL)
    return CGPT_FAILED;

  if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR))
    return CGPT_FAILED;

  if (CgptCheckAddValidity(&drive)) {
    goto bad;
  }

  if (params->partition == 0 ||
      params->partition >= GetNumberOfEntries(&drive)) {
    Error("invalid partition number: %d\n", params->partition);
    goto bad;
  }

  SetEntryAttributes(&drive, params->partition - 1, params);

  UpdateAllEntries(&drive);

  // Write it all out.
  return DriveClose(&drive, 1);

bad:
  DriveClose(&drive, 0);
  return CGPT_FAILED;
}
Exemple #2
0
int CgptAdd(CgptAddParams *params) {
  struct drive drive;

  GptEntry *entry, backup;
  uint32_t index;
  int rv;

  if (params == NULL)
    return CGPT_FAILED;

  if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR))
    return CGPT_FAILED;

  if (CgptCheckAddValidity(&drive)) {
    goto bad;
  }

  if (CgptGetUnusedPartition(&drive, &index, params)) {
    goto bad;
  }

  entry = GetEntry(&drive.gpt, PRIMARY, index);
  memcpy(&backup, entry, sizeof(backup));

  if (SetEntryAttributes(&drive, index, params) ||
      GptSetEntryAttributes(&drive, index, params)) {
    memcpy(entry, &backup, sizeof(*entry));
    goto bad;
  }

  UpdateAllEntries(&drive);

  rv = CheckEntries((GptEntry*)drive.gpt.primary_entries,
                    (GptHeader*)drive.gpt.primary_header);

  if (0 != rv) {
    // If the modified entry is illegal, recover it and return error.
    memcpy(entry, &backup, sizeof(*entry));
    Error("%s\n", GptErrorText(rv));
    Error(DumpCgptAddParams(params));
    goto bad;
  }

  // Write it all out.
  return DriveClose(&drive, 1);

bad:
  DriveClose(&drive, 0);
  return CGPT_FAILED;
}
int CgptNext(CgptNextParams *params) {
  struct drive drive;
  GptEntry *entry;
  char tmp[64];
  int tries;
  next_index = -1;
  int gpt_retval;

  if (params == NULL)
    return CGPT_FAILED;

  if (params->drive_name) {
    do_search(params);
  } else {
    scan_real_devs(params);
  }

  if (strlen(next_file_name) < 0) {
    return CGPT_FAILED;
  }

  if (DriveOpen(next_file_name, &drive, 0, O_RDWR) == CGPT_OK) {
    if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
      Error("GptSanityCheck() returned %d: %s\n",
            gpt_retval, GptError(gpt_retval));
      return CGPT_FAILED;
    }

    // Decrement tries if we selected on that criteria
    tries = GetTries(&drive, PRIMARY, next_index);
    if (tries > 0) {
      tries--;
    }
    SetTries(&drive, PRIMARY, next_index, tries);

    // Print out the next disk to go!
    entry = GetEntry(&drive.gpt, ANY_VALID, next_index);
    GuidToStrLower(&entry->unique, tmp, sizeof(tmp));
    printf("%s\n", tmp);

    // Write it all out
    UpdateAllEntries(&drive);
    return DriveClose(&drive, 1);
  }

  return 1;
}
/* Resize the partition and notify the kernel.
 * returns:
 *   CGPT_OK for resize successful or nothing to do
 *   CGPT_FAILED on error
 */
static int resize_partition(CgptResizeParams *params, blkid_dev dev) {
  char *disk_devname;
  struct drive drive;
  GptHeader *header;
  GptEntry *entry;
  int gpt_retval, entry_index, entry_count;
  uint64_t free_bytes, last_free_lba, entry_size_lba;

  if ((disk_devname = dev_to_wholedevname(dev)) == NULL) {
    Error("Failed to find whole disk device for %s\n", blkid_dev_devname(dev));
    return CGPT_FAILED;
  }

  if (DriveOpen(disk_devname, &drive, 0, O_RDWR) != CGPT_OK) {
    free(disk_devname);
    return CGPT_FAILED;
  }

  free(disk_devname);

  if (CGPT_OK != ReadPMBR(&drive)) {
    Error("Unable to read PMBR\n");
    goto nope;
  }

  if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
    Error("GptSanityCheck() returned %d: %s\n",
          gpt_retval, GptError(gpt_retval));
    goto nope;
  }

  // If either table is bad fix it! (likely if disk was extended)
  GptRepair(&drive.gpt);

  header = (GptHeader*)drive.gpt.primary_header;
  last_free_lba = header->last_usable_lba;
  entry_count = GetNumberOfEntries(&drive);
  entry_index = dev_to_partno(dev) - 1;
  if (entry_index < 0 || entry_index >= entry_count) {
    Error("Kernel and GPT disagree on the number of partitions!\n");
    goto nope;
  }
  entry = GetEntry(&drive.gpt, PRIMARY, entry_index);

  // Scan entire table to determine if entry can grow.
  for (int i = 0; i < entry_count; i++) {
    GptEntry *other = GetEntry(&drive.gpt, PRIMARY, i);

    if (GuidIsZero(&other->type))
      continue;

    if (other->starting_lba > entry->ending_lba &&
        other->starting_lba - 1 < last_free_lba) {
      last_free_lba = other->starting_lba - 1;
    }
  }

  // Exit without doing anything if the size is too small
  free_bytes = (last_free_lba - entry->ending_lba) * drive.gpt.sector_bytes;
  if (entry->ending_lba >= last_free_lba ||
      free_bytes < params->min_resize_bytes) {
    if (DriveClose(&drive, 0) != CGPT_OK)
      return CGPT_FAILED;
    else
      return CGPT_OK;
  }

  // Update and test partition table in memory
  entry->ending_lba = last_free_lba;
  entry_size_lba = entry->ending_lba - entry->starting_lba;
  UpdateAllEntries(&drive);
  gpt_retval = CheckEntries((GptEntry*)drive.gpt.primary_entries,
                            (GptHeader*)drive.gpt.primary_header);
  if (gpt_retval != GPT_SUCCESS) {
    Error("CheckEntries() returned %d: %s\n",
          gpt_retval, GptError(gpt_retval));
    goto nope;
  }

  // Notify kernel of new partition size via an ioctl.
  if (blkpg_resize_partition(drive.fd, dev_to_partno(dev),
                             entry->starting_lba * drive.gpt.sector_bytes,
                             entry_size_lba * drive.gpt.sector_bytes) < 0) {
    Error("Failed to notify kernel of new partition size: %s\n"
          "Leaving existing partition table in place.\n", strerror(errno));
    goto nope;
  }

  UpdatePMBR(&drive, PRIMARY);
  if (WritePMBR(&drive) != CGPT_OK) {
    Error("Failed to write legacy MBR.\n");
    goto nope;
  }

  // Whew! we made it! Flush to disk.
  return DriveClose(&drive, 1);

nope:
  DriveClose(&drive, 0);
  return CGPT_FAILED;
}
Exemple #5
0
int CgptPrioritize(CgptPrioritizeParams *params) {
  struct drive drive;

  int priority;

  int gpt_retval;
  uint32_t index;
  uint32_t max_part;
  int num_root;
  int i,j;
  group_list_t *groups;

  if (params == NULL)
    return CGPT_FAILED;

  if (CGPT_OK != DriveOpen(params->drive_name, &drive, 0, O_RDWR))
    return CGPT_FAILED;

  if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
    Error("GptSanityCheck() returned %d: %s\n",
          gpt_retval, GptError(gpt_retval));
    return CGPT_FAILED;
  }

  max_part = GetNumberOfEntries(&drive);

  if (params->set_partition) {
    if (params->set_partition < 1 || params->set_partition > max_part) {
      Error("invalid partition number: %d (must be between 1 and %d\n",
            params->set_partition, max_part);
      goto bad;
    }
    index = params->set_partition - 1;
    // it must be a kernel
    if (!IsRoot(&drive, PRIMARY, index) && !IsMarker(&drive, PRIMARY, index)) {
      Error("partition %d is not a valid root\n", params->set_partition);
      goto bad;
    }
  }

  // How many kernel partitions do I have?
  num_root = 0;
  for (i = 0; i < max_part; i++) {
    if (IsRoot(&drive, PRIMARY, i) || IsMarker(&drive, PRIMARY, i))
      num_root++;
  }

  if (num_root) {
    // Determine the current priority groups
    groups = NewGroupList(num_root);
    for (i = 0; i < max_part; i++) {
      if (!IsRoot(&drive, PRIMARY, i) && !IsMarker(&drive, PRIMARY, i))
        continue;

      priority = GetPriority(&drive, PRIMARY, i);

      // Is this partition special?
      if (params->set_partition && (i+1 == params->set_partition)) {
        params->orig_priority = priority;  // remember the original priority
        if (params->set_friends)
          AddToGroup(groups, priority, i); // we'll move them all later
        else
          AddToGroup(groups, 99, i);       // move only this one
      } else {
        AddToGroup(groups, priority, i);   // just remember
      }
    }

    // If we're including friends, then change the original group priority
    if (params->set_partition && params->set_friends) {
      ChangeGroup(groups, params->orig_priority, 99);
    }

    // Sorting gives the new order. Now we just need to reassign the
    // priorities.
    SortGroups(groups);

    // We'll never lower anything to zero, so if the last group is priority zero
    // we can ignore it.
    i = groups->num_groups;
    if (groups->group[i-1].priority == 0)
      groups->num_groups--;

    // Where do we start?
    if (params->max_priority)
      priority = params->max_priority;
    else
      priority = groups->num_groups > 15 ? 15 : groups->num_groups;

    // Figure out what the new values should be
    for (i=0; i<groups->num_groups; i++) {
      groups->group[i].priority = priority;
      if (priority > 1)
        priority--;
    }

    // Now apply the ranking to the GPT
    for (i=0; i<groups->num_groups; i++)
      for (j=0; j<groups->group[i].num_parts; j++)
        SetPriority(&drive, PRIMARY,
                    groups->group[i].part[j], groups->group[i].priority);

    FreeGroups(groups);
  }

  // Write it all out
  UpdateAllEntries(&drive);

  return DriveClose(&drive, 1);

bad:
  (void) DriveClose(&drive, 0);
  return CGPT_FAILED;
}