Bill Richardson | f1372d9 | 2010-06-11 09:15:55 -0700 | [diff] [blame] | 1 | // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "cgpt.h" |
| 6 | |
| 7 | #include <getopt.h> |
| 8 | #include <stdio.h> |
| 9 | #include <stdlib.h> |
| 10 | #include <string.h> |
| 11 | #include <uuid/uuid.h> |
| 12 | |
| 13 | #include "cgptlib_internal.h" |
| 14 | |
| 15 | static void Usage(void) |
| 16 | { |
| 17 | printf("\nUsage: %s add [OPTIONS] DRIVE\n\n" |
| 18 | "Add, edit, or remove a partition entry.\n\n" |
| 19 | "Options:\n" |
| 20 | " -i NUM Specify partition (default is next available)\n" |
| 21 | " -b NUM Beginning sector\n" |
| 22 | " -s NUM Size in sectors\n" |
| 23 | " -t GUID Partition Type GUID\n" |
| 24 | " -u GUID Partition Unique ID\n" |
| 25 | " -l LABEL Label\n" |
| 26 | " -S NUM set Successful flag (0|1)\n" |
| 27 | " -T NUM set Tries flag (0-15)\n" |
| 28 | " -P NUM set Priority flag (0-15)\n" |
| 29 | " -A NUM set raw 64-bit attribute value\n" |
| 30 | "\n" |
| 31 | "Use the -i option to modify an existing partition.\n" |
| 32 | "The -b, -s, and -t options must be given for new partitions.\n" |
| 33 | "\n", progname); |
| 34 | PrintTypes(); |
| 35 | } |
| 36 | |
| 37 | int cmd_add(int argc, char *argv[]) { |
| 38 | struct drive drive; |
Bill Richardson | c4e92af | 2010-10-12 07:33:15 -0700 | [diff] [blame] | 39 | uint32_t partition = 0; |
Bill Richardson | f1372d9 | 2010-06-11 09:15:55 -0700 | [diff] [blame] | 40 | uint64_t begin = 0; |
| 41 | uint64_t size = 0; |
| 42 | Guid type_guid; |
| 43 | Guid unique_guid; |
| 44 | char *label = 0; |
| 45 | int successful = 0; |
| 46 | int tries = 0; |
| 47 | int priority = 0; |
vbendeb | f7a45cc | 2010-06-21 08:44:16 -0700 | [diff] [blame] | 48 | uint16_t raw_value = 0; |
Bill Richardson | f1372d9 | 2010-06-11 09:15:55 -0700 | [diff] [blame] | 49 | int set_begin = 0; |
| 50 | int set_size = 0; |
| 51 | int set_type = 0; |
| 52 | int set_unique = 0; |
| 53 | int set_successful = 0; |
| 54 | int set_tries = 0; |
| 55 | int set_priority = 0; |
| 56 | int set_raw = 0; |
| 57 | |
| 58 | int gpt_retval; |
| 59 | GptEntry *entry; |
Bill Richardson | c4e92af | 2010-10-12 07:33:15 -0700 | [diff] [blame] | 60 | uint32_t index; |
| 61 | |
Bill Richardson | f1372d9 | 2010-06-11 09:15:55 -0700 | [diff] [blame] | 62 | int c; |
| 63 | int errorcnt = 0; |
| 64 | char *e = 0; |
| 65 | |
| 66 | opterr = 0; // quiet, you |
| 67 | while ((c=getopt(argc, argv, ":hi:b:s:t:u:l:S:T:P:A:")) != -1) |
| 68 | { |
| 69 | switch (c) |
| 70 | { |
| 71 | case 'i': |
| 72 | partition = (uint32_t)strtoul(optarg, &e, 0); |
| 73 | if (!*optarg || (e && *e)) |
| 74 | { |
| 75 | Error("invalid argument to -%c: \"%s\"\n", c, optarg); |
| 76 | errorcnt++; |
| 77 | } |
| 78 | break; |
| 79 | case 'b': |
| 80 | set_begin = 1; |
| 81 | begin = strtoull(optarg, &e, 0); |
| 82 | if (!*optarg || (e && *e)) |
| 83 | { |
| 84 | Error("invalid argument to -%c: \"%s\"\n", c, optarg); |
| 85 | errorcnt++; |
| 86 | } |
| 87 | break; |
| 88 | case 's': |
| 89 | set_size = 1; |
| 90 | size = strtoull(optarg, &e, 0); |
| 91 | if (!*optarg || (e && *e)) |
| 92 | { |
| 93 | Error("invalid argument to -%c: \"%s\"\n", c, optarg); |
| 94 | errorcnt++; |
| 95 | } |
| 96 | break; |
| 97 | case 't': |
| 98 | set_type = 1; |
| 99 | if (CGPT_OK != SupportedType(optarg, &type_guid) && |
| 100 | CGPT_OK != StrToGuid(optarg, &type_guid)) { |
| 101 | Error("invalid argument to -%c: %s\n", c, optarg); |
| 102 | errorcnt++; |
| 103 | } |
| 104 | break; |
| 105 | case 'u': |
| 106 | set_unique = 1; |
| 107 | if (CGPT_OK != StrToGuid(optarg, &unique_guid)) { |
| 108 | Error("invalid argument to -%c: %s\n", c, optarg); |
| 109 | errorcnt++; |
| 110 | } |
| 111 | break; |
| 112 | case 'l': |
| 113 | label = optarg; |
| 114 | break; |
| 115 | case 'S': |
| 116 | set_successful = 1; |
| 117 | successful = (uint32_t)strtoul(optarg, &e, 0); |
| 118 | if (!*optarg || (e && *e)) |
| 119 | { |
| 120 | Error("invalid argument to -%c: \"%s\"\n", c, optarg); |
| 121 | errorcnt++; |
| 122 | } |
| 123 | if (successful < 0 || successful > 1) { |
| 124 | Error("value for -%c must be between 0 and 1", c); |
| 125 | errorcnt++; |
| 126 | } |
| 127 | break; |
| 128 | case 'T': |
| 129 | set_tries = 1; |
| 130 | tries = (uint32_t)strtoul(optarg, &e, 0); |
| 131 | if (!*optarg || (e && *e)) |
| 132 | { |
| 133 | fprintf(stderr, "%s: invalid argument to -%c: \"%s\"\n", |
| 134 | progname, c, optarg); |
| 135 | errorcnt++; |
| 136 | } |
| 137 | if (tries < 0 || tries > 15) { |
| 138 | Error("value for -%c must be between 0 and 15", c); |
| 139 | errorcnt++; |
| 140 | } |
| 141 | break; |
| 142 | case 'P': |
| 143 | set_priority = 1; |
| 144 | priority = (uint32_t)strtoul(optarg, &e, 0); |
| 145 | if (!*optarg || (e && *e)) |
| 146 | { |
| 147 | Error("invalid argument to -%c: \"%s\"\n", c, optarg); |
| 148 | errorcnt++; |
| 149 | } |
| 150 | if (priority < 0 || priority > 15) { |
| 151 | Error("value for -%c must be between 0 and 15", c); |
| 152 | errorcnt++; |
| 153 | } |
| 154 | break; |
| 155 | case 'A': |
| 156 | set_raw = 1; |
| 157 | raw_value = strtoull(optarg, &e, 0); |
| 158 | if (!*optarg || (e && *e)) |
| 159 | { |
| 160 | Error("invalid argument to -%c: \"%s\"\n", c, optarg); |
| 161 | errorcnt++; |
| 162 | } |
| 163 | break; |
| 164 | |
| 165 | case 'h': |
| 166 | Usage(); |
| 167 | return CGPT_OK; |
| 168 | case '?': |
| 169 | Error("unrecognized option: -%c\n", optopt); |
| 170 | errorcnt++; |
| 171 | break; |
| 172 | case ':': |
| 173 | Error("missing argument to -%c\n", optopt); |
| 174 | errorcnt++; |
| 175 | break; |
| 176 | default: |
| 177 | errorcnt++; |
| 178 | break; |
| 179 | } |
| 180 | } |
| 181 | if (errorcnt) |
| 182 | { |
| 183 | Usage(); |
| 184 | return CGPT_FAILED; |
| 185 | } |
| 186 | |
| 187 | if (optind >= argc) { |
| 188 | Error("missing drive argument\n"); |
| 189 | return CGPT_FAILED; |
| 190 | } |
| 191 | |
| 192 | if (CGPT_OK != DriveOpen(argv[optind], &drive)) |
| 193 | return CGPT_FAILED; |
| 194 | |
| 195 | if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) { |
| 196 | Error("GptSanityCheck() returned %d: %s\n", |
| 197 | gpt_retval, GptError(gpt_retval)); |
| 198 | return CGPT_FAILED; |
| 199 | } |
| 200 | |
Louis Yung-Chieh Lo | 2b23c02 | 2010-11-18 09:53:10 +0800 | [diff] [blame] | 201 | if (((drive.gpt.valid_headers & MASK_BOTH) != MASK_BOTH) || |
| 202 | ((drive.gpt.valid_entries & MASK_BOTH) != MASK_BOTH)) { |
| 203 | Error("one of the GPT header/entries is invalid.\n" |
| 204 | "please run 'cgpt repair' before adding anything.\n"); |
| 205 | return CGPT_FAILED; |
| 206 | } |
| 207 | |
Bill Richardson | c4e92af | 2010-10-12 07:33:15 -0700 | [diff] [blame] | 208 | uint32_t max_part = GetNumberOfEntries(&drive.gpt); |
Bill Richardson | f1372d9 | 2010-06-11 09:15:55 -0700 | [diff] [blame] | 209 | if (partition) { |
| 210 | if (partition > max_part) { |
| 211 | Error("invalid partition number: %d\n", partition); |
| 212 | goto bad; |
| 213 | } |
| 214 | index = partition - 1; |
| 215 | entry = GetEntry(&drive.gpt, PRIMARY, index); |
| 216 | } else { |
| 217 | // find next empty partition |
| 218 | for (index = 0; index < max_part; index++) { |
| 219 | entry = GetEntry(&drive.gpt, PRIMARY, index); |
| 220 | if (IsZero(&entry->type)) { |
| 221 | partition = index + 1; |
| 222 | break; |
| 223 | } |
| 224 | } |
| 225 | if (index >= max_part) { |
| 226 | Error("no unused partitions available\n"); |
| 227 | goto bad; |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | // New partitions must specify type, begin, and size. |
| 232 | if (IsZero(&entry->type)) { |
| 233 | if (!set_begin || !set_size || !set_type) { |
| 234 | Error("-t, -b, and -s options are required for new partitions\n"); |
| 235 | goto bad; |
| 236 | } |
| 237 | if (IsZero(&type_guid)) { |
| 238 | Error("New partitions must have a type other than \"unused\"\n"); |
| 239 | goto bad; |
| 240 | } |
| 241 | if (!set_unique) |
| 242 | uuid_generate((uint8_t *)&entry->unique); |
| 243 | } |
| 244 | |
| 245 | if (set_begin) |
| 246 | entry->starting_lba = begin; |
| 247 | if (set_size) |
| 248 | entry->ending_lba = begin + size - 1; |
| 249 | if (set_type) |
| 250 | memcpy(&entry->type, &type_guid, sizeof(Guid)); |
| 251 | if (set_unique) |
| 252 | memcpy(&entry->unique, &unique_guid, sizeof(Guid)); |
| 253 | if (label) { |
Louis Yung-Chieh Lo | 500b3c2 | 2010-11-22 18:19:11 +0800 | [diff] [blame] | 254 | if (CGPT_OK != UTF8ToUTF16((uint8_t *)label, entry->name, |
| 255 | sizeof(entry->name) / sizeof(entry->name[0]))) { |
| 256 | Error("The label cannot be converted to UTF16.\n"); |
| 257 | goto bad; |
| 258 | } |
Bill Richardson | f1372d9 | 2010-06-11 09:15:55 -0700 | [diff] [blame] | 259 | } |
| 260 | if (set_raw) { |
vbendeb | f7a45cc | 2010-06-21 08:44:16 -0700 | [diff] [blame] | 261 | entry->attrs.fields.gpt_att = raw_value; |
Bill Richardson | f1372d9 | 2010-06-11 09:15:55 -0700 | [diff] [blame] | 262 | } else { |
| 263 | if (set_successful) |
| 264 | SetSuccessful(&drive.gpt, PRIMARY, index, successful); |
| 265 | if (set_tries) |
| 266 | SetTries(&drive.gpt, PRIMARY, index, tries); |
| 267 | if (set_priority) |
| 268 | SetPriority(&drive.gpt, PRIMARY, index, priority); |
| 269 | } |
| 270 | |
| 271 | RepairEntries(&drive.gpt, MASK_PRIMARY); |
| 272 | RepairHeader(&drive.gpt, MASK_PRIMARY); |
| 273 | |
| 274 | drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 | |
| 275 | GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2); |
| 276 | UpdateCrc(&drive.gpt); |
| 277 | |
| 278 | |
| 279 | // Write it all out |
| 280 | return DriveClose(&drive, 1); |
| 281 | |
| 282 | bad: |
| 283 | (void) DriveClose(&drive, 0); |
| 284 | return CGPT_FAILED; |
| 285 | } |