OLD | NEW |
(Empty) | |
| 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; |
| 39 int partition = 0; |
| 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; |
| 48 uint64_t raw_value = 0; |
| 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; |
| 60 int index; |
| 61 |
| 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 |
| 201 int max_part = GetNumberOfEntries(&drive.gpt); |
| 202 if (partition) { |
| 203 if (partition > max_part) { |
| 204 Error("invalid partition number: %d\n", partition); |
| 205 goto bad; |
| 206 } |
| 207 index = partition - 1; |
| 208 entry = GetEntry(&drive.gpt, PRIMARY, index); |
| 209 } else { |
| 210 // find next empty partition |
| 211 for (index = 0; index < max_part; index++) { |
| 212 entry = GetEntry(&drive.gpt, PRIMARY, index); |
| 213 if (IsZero(&entry->type)) { |
| 214 partition = index + 1; |
| 215 break; |
| 216 } |
| 217 } |
| 218 if (index >= max_part) { |
| 219 Error("no unused partitions available\n"); |
| 220 goto bad; |
| 221 } |
| 222 } |
| 223 |
| 224 // New partitions must specify type, begin, and size. |
| 225 if (IsZero(&entry->type)) { |
| 226 if (!set_begin || !set_size || !set_type) { |
| 227 Error("-t, -b, and -s options are required for new partitions\n"); |
| 228 goto bad; |
| 229 } |
| 230 if (IsZero(&type_guid)) { |
| 231 Error("New partitions must have a type other than \"unused\"\n"); |
| 232 goto bad; |
| 233 } |
| 234 if (!set_unique) |
| 235 uuid_generate((uint8_t *)&entry->unique); |
| 236 } |
| 237 |
| 238 if (set_begin) |
| 239 entry->starting_lba = begin; |
| 240 if (set_size) |
| 241 entry->ending_lba = begin + size - 1; |
| 242 if (set_type) |
| 243 memcpy(&entry->type, &type_guid, sizeof(Guid)); |
| 244 if (set_unique) |
| 245 memcpy(&entry->unique, &unique_guid, sizeof(Guid)); |
| 246 if (label) { |
| 247 uint16_t buf[128]; |
| 248 UTF8ToUTF16((uint8_t *)label, buf); |
| 249 memcpy(entry->name, buf, sizeof(entry->name)); |
| 250 } |
| 251 if (set_raw) { |
| 252 entry->attributes = raw_value; |
| 253 } else { |
| 254 if (set_successful) |
| 255 SetSuccessful(&drive.gpt, PRIMARY, index, successful); |
| 256 if (set_tries) |
| 257 SetTries(&drive.gpt, PRIMARY, index, tries); |
| 258 if (set_priority) |
| 259 SetPriority(&drive.gpt, PRIMARY, index, priority); |
| 260 } |
| 261 |
| 262 RepairEntries(&drive.gpt, MASK_PRIMARY); |
| 263 RepairHeader(&drive.gpt, MASK_PRIMARY); |
| 264 |
| 265 drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 | |
| 266 GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2); |
| 267 UpdateCrc(&drive.gpt); |
| 268 |
| 269 |
| 270 // Write it all out |
| 271 return DriveClose(&drive, 1); |
| 272 |
| 273 bad: |
| 274 (void) DriveClose(&drive, 0); |
| 275 return CGPT_FAILED; |
| 276 } |
OLD | NEW |