| Index: cgpt/cmd_add.c
|
| diff --git a/cgpt/cmd_add.c b/cgpt/cmd_add.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..18a0285e8143fd1ae8c701ed8213c90c0f9c42d9
|
| --- /dev/null
|
| +++ b/cgpt/cmd_add.c
|
| @@ -0,0 +1,276 @@
|
| +// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "cgpt.h"
|
| +
|
| +#include <getopt.h>
|
| +#include <stdio.h>
|
| +#include <stdlib.h>
|
| +#include <string.h>
|
| +#include <uuid/uuid.h>
|
| +
|
| +#include "cgptlib_internal.h"
|
| +
|
| +static void Usage(void)
|
| +{
|
| + printf("\nUsage: %s add [OPTIONS] DRIVE\n\n"
|
| + "Add, edit, or remove a partition entry.\n\n"
|
| + "Options:\n"
|
| + " -i NUM Specify partition (default is next available)\n"
|
| + " -b NUM Beginning sector\n"
|
| + " -s NUM Size in sectors\n"
|
| + " -t GUID Partition Type GUID\n"
|
| + " -u GUID Partition Unique ID\n"
|
| + " -l LABEL Label\n"
|
| + " -S NUM set Successful flag (0|1)\n"
|
| + " -T NUM set Tries flag (0-15)\n"
|
| + " -P NUM set Priority flag (0-15)\n"
|
| + " -A NUM set raw 64-bit attribute value\n"
|
| + "\n"
|
| + "Use the -i option to modify an existing partition.\n"
|
| + "The -b, -s, and -t options must be given for new partitions.\n"
|
| + "\n", progname);
|
| + PrintTypes();
|
| +}
|
| +
|
| +int cmd_add(int argc, char *argv[]) {
|
| + struct drive drive;
|
| + int partition = 0;
|
| + uint64_t begin = 0;
|
| + uint64_t size = 0;
|
| + Guid type_guid;
|
| + Guid unique_guid;
|
| + char *label = 0;
|
| + int successful = 0;
|
| + int tries = 0;
|
| + int priority = 0;
|
| + uint64_t raw_value = 0;
|
| + int set_begin = 0;
|
| + int set_size = 0;
|
| + int set_type = 0;
|
| + int set_unique = 0;
|
| + int set_successful = 0;
|
| + int set_tries = 0;
|
| + int set_priority = 0;
|
| + int set_raw = 0;
|
| +
|
| + int gpt_retval;
|
| + GptEntry *entry;
|
| + int index;
|
| +
|
| + int c;
|
| + int errorcnt = 0;
|
| + char *e = 0;
|
| +
|
| + opterr = 0; // quiet, you
|
| + while ((c=getopt(argc, argv, ":hi:b:s:t:u:l:S:T:P:A:")) != -1)
|
| + {
|
| + switch (c)
|
| + {
|
| + case 'i':
|
| + partition = (uint32_t)strtoul(optarg, &e, 0);
|
| + if (!*optarg || (e && *e))
|
| + {
|
| + Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
| + errorcnt++;
|
| + }
|
| + break;
|
| + case 'b':
|
| + set_begin = 1;
|
| + begin = strtoull(optarg, &e, 0);
|
| + if (!*optarg || (e && *e))
|
| + {
|
| + Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
| + errorcnt++;
|
| + }
|
| + break;
|
| + case 's':
|
| + set_size = 1;
|
| + size = strtoull(optarg, &e, 0);
|
| + if (!*optarg || (e && *e))
|
| + {
|
| + Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
| + errorcnt++;
|
| + }
|
| + break;
|
| + case 't':
|
| + set_type = 1;
|
| + if (CGPT_OK != SupportedType(optarg, &type_guid) &&
|
| + CGPT_OK != StrToGuid(optarg, &type_guid)) {
|
| + Error("invalid argument to -%c: %s\n", c, optarg);
|
| + errorcnt++;
|
| + }
|
| + break;
|
| + case 'u':
|
| + set_unique = 1;
|
| + if (CGPT_OK != StrToGuid(optarg, &unique_guid)) {
|
| + Error("invalid argument to -%c: %s\n", c, optarg);
|
| + errorcnt++;
|
| + }
|
| + break;
|
| + case 'l':
|
| + label = optarg;
|
| + break;
|
| + case 'S':
|
| + set_successful = 1;
|
| + successful = (uint32_t)strtoul(optarg, &e, 0);
|
| + if (!*optarg || (e && *e))
|
| + {
|
| + Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
| + errorcnt++;
|
| + }
|
| + if (successful < 0 || successful > 1) {
|
| + Error("value for -%c must be between 0 and 1", c);
|
| + errorcnt++;
|
| + }
|
| + break;
|
| + case 'T':
|
| + set_tries = 1;
|
| + tries = (uint32_t)strtoul(optarg, &e, 0);
|
| + if (!*optarg || (e && *e))
|
| + {
|
| + fprintf(stderr, "%s: invalid argument to -%c: \"%s\"\n",
|
| + progname, c, optarg);
|
| + errorcnt++;
|
| + }
|
| + if (tries < 0 || tries > 15) {
|
| + Error("value for -%c must be between 0 and 15", c);
|
| + errorcnt++;
|
| + }
|
| + break;
|
| + case 'P':
|
| + set_priority = 1;
|
| + priority = (uint32_t)strtoul(optarg, &e, 0);
|
| + if (!*optarg || (e && *e))
|
| + {
|
| + Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
| + errorcnt++;
|
| + }
|
| + if (priority < 0 || priority > 15) {
|
| + Error("value for -%c must be between 0 and 15", c);
|
| + errorcnt++;
|
| + }
|
| + break;
|
| + case 'A':
|
| + set_raw = 1;
|
| + raw_value = strtoull(optarg, &e, 0);
|
| + if (!*optarg || (e && *e))
|
| + {
|
| + Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
| + errorcnt++;
|
| + }
|
| + break;
|
| +
|
| + case 'h':
|
| + Usage();
|
| + return CGPT_OK;
|
| + case '?':
|
| + Error("unrecognized option: -%c\n", optopt);
|
| + errorcnt++;
|
| + break;
|
| + case ':':
|
| + Error("missing argument to -%c\n", optopt);
|
| + errorcnt++;
|
| + break;
|
| + default:
|
| + errorcnt++;
|
| + break;
|
| + }
|
| + }
|
| + if (errorcnt)
|
| + {
|
| + Usage();
|
| + return CGPT_FAILED;
|
| + }
|
| +
|
| + if (optind >= argc) {
|
| + Error("missing drive argument\n");
|
| + return CGPT_FAILED;
|
| + }
|
| +
|
| + if (CGPT_OK != DriveOpen(argv[optind], &drive))
|
| + 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;
|
| + }
|
| +
|
| + int max_part = GetNumberOfEntries(&drive.gpt);
|
| + if (partition) {
|
| + if (partition > max_part) {
|
| + Error("invalid partition number: %d\n", partition);
|
| + goto bad;
|
| + }
|
| + index = partition - 1;
|
| + entry = GetEntry(&drive.gpt, PRIMARY, index);
|
| + } else {
|
| + // find next empty partition
|
| + for (index = 0; index < max_part; index++) {
|
| + entry = GetEntry(&drive.gpt, PRIMARY, index);
|
| + if (IsZero(&entry->type)) {
|
| + partition = index + 1;
|
| + break;
|
| + }
|
| + }
|
| + if (index >= max_part) {
|
| + Error("no unused partitions available\n");
|
| + goto bad;
|
| + }
|
| + }
|
| +
|
| + // New partitions must specify type, begin, and size.
|
| + if (IsZero(&entry->type)) {
|
| + if (!set_begin || !set_size || !set_type) {
|
| + Error("-t, -b, and -s options are required for new partitions\n");
|
| + goto bad;
|
| + }
|
| + if (IsZero(&type_guid)) {
|
| + Error("New partitions must have a type other than \"unused\"\n");
|
| + goto bad;
|
| + }
|
| + if (!set_unique)
|
| + uuid_generate((uint8_t *)&entry->unique);
|
| + }
|
| +
|
| + if (set_begin)
|
| + entry->starting_lba = begin;
|
| + if (set_size)
|
| + entry->ending_lba = begin + size - 1;
|
| + if (set_type)
|
| + memcpy(&entry->type, &type_guid, sizeof(Guid));
|
| + if (set_unique)
|
| + memcpy(&entry->unique, &unique_guid, sizeof(Guid));
|
| + if (label) {
|
| + uint16_t buf[128];
|
| + UTF8ToUTF16((uint8_t *)label, buf);
|
| + memcpy(entry->name, buf, sizeof(entry->name));
|
| + }
|
| + if (set_raw) {
|
| + entry->attributes = raw_value;
|
| + } else {
|
| + if (set_successful)
|
| + SetSuccessful(&drive.gpt, PRIMARY, index, successful);
|
| + if (set_tries)
|
| + SetTries(&drive.gpt, PRIMARY, index, tries);
|
| + if (set_priority)
|
| + SetPriority(&drive.gpt, PRIMARY, index, priority);
|
| + }
|
| +
|
| + RepairEntries(&drive.gpt, MASK_PRIMARY);
|
| + RepairHeader(&drive.gpt, MASK_PRIMARY);
|
| +
|
| + drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
|
| + GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
|
| + UpdateCrc(&drive.gpt);
|
| +
|
| +
|
| + // Write it all out
|
| + return DriveClose(&drive, 1);
|
| +
|
| +bad:
|
| + (void) DriveClose(&drive, 0);
|
| + return CGPT_FAILED;
|
| +}
|
|
|