| 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 * Update GPT attribute bits. | |
| 6 */ | |
| 7 #include <getopt.h> | |
| 8 #include <stdio.h> | |
| 9 #include <stdlib.h> | |
| 10 #include "cgpt.h" | |
| 11 #include "cgptlib_internal.h" | |
| 12 #include "cgpt_tofix.h" | |
| 13 #include "utility.h" | |
| 14 | |
| 15 static struct number_range | |
| 16 range_127_0 = {127, 0}; | |
| 17 | |
| 18 /* Integers to store parsed argument. */ | |
| 19 static int help, partition, begin_lba, size_lba; | |
| 20 static char type[128], unique[128], name[128]; | |
| 21 | |
| 22 /* The structure for getopt_long(). When you add/delete any line, please refine | |
| 23 * attribute_comments[] and third parameter of getopt_long() too. */ | |
| 24 static struct option adm_options[] = { | |
| 25 {.name = "help", .has_arg = no_argument, .flag = 0, .val = 'h'}, | |
| 26 {.name = "partition", .has_arg = required_argument, .flag = 0, .val = 'i'}, | |
| 27 #if 0//FIXME | |
| 28 {.name = "bad", .has_arg = required_argument, .flag = 0, .val = 'b'}, | |
| 29 {.name = "successful", .has_arg = required_argument, .flag = 0, .val = 's'}, | |
| 30 {.name = "tries", .has_arg = required_argument, .flag = 0, .val = 't'}, | |
| 31 {.name = "priority", .has_arg = required_argument, .flag = 0, .val = 'p'}, | |
| 32 #endif | |
| 33 {.name = "type", .has_arg = required_argument, .flag = 0, .val = 't'}, | |
| 34 {.name = "unique", .has_arg = required_argument, .flag = 0, .val = 'u'}, | |
| 35 {.name = "begin", .has_arg = required_argument, .flag = 0, .val = 'b'}, | |
| 36 {.name = "size", .has_arg = required_argument, .flag = 0, .val = 's'}, | |
| 37 {.name = "name", .has_arg = required_argument, .flag = 0, .val = 'n'}, | |
| 38 { /* last element, which should be zero. */ } | |
| 39 }; | |
| 40 | |
| 41 /* Extra information than struct option, please update this structure if you | |
| 42 * add/remove any line in attribute_options[]. */ | |
| 43 static struct option_details adm_options_details[] = { | |
| 44 /* help */ | |
| 45 { .comment = "print this help", | |
| 46 .validator = AssignTrue, | |
| 47 .valid_range = 0, | |
| 48 .parsed = &help}, | |
| 49 /* partition */ | |
| 50 { .comment = "partition number (MUST HAVE)", | |
| 51 .validator = InNumberRange, | |
| 52 .valid_range = &range_127_0, | |
| 53 .parsed = &partition}, | |
| 54 #if 0//FIXME | |
| 55 /* bad */ | |
| 56 { .comment = "mark partition bad", | |
| 57 .validator = InNumberRange, | |
| 58 .valid_range = &range_1_0, | |
| 59 .parsed = &bad}, | |
| 60 /* successful */ | |
| 61 { .comment = "mark partition successful", | |
| 62 .validator = InNumberRange, | |
| 63 .valid_range = &range_1_0, | |
| 64 .parsed = &successful}, | |
| 65 /* tries */ | |
| 66 { .comment = "tries", | |
| 67 .validator = InNumberRange, | |
| 68 .valid_range = &range_15_0, | |
| 69 .parsed = &tries}, | |
| 70 /* priority */ | |
| 71 { .comment = "priority to boot", | |
| 72 .validator = InNumberRange, | |
| 73 .valid_range = &range_15_0, | |
| 74 .parsed = &priority}, | |
| 75 #endif | |
| 76 /* type */ | |
| 77 { .comment = "Partition Type (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)", | |
| 78 .validator = CopyString, | |
| 79 .valid_range = (void*)sizeof(type), | |
| 80 .parsed = &type}, | |
| 81 /* uuid */ | |
| 82 { .comment = "Partition UUID (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)", | |
| 83 .validator = CopyString, | |
| 84 .valid_range = (void*)sizeof(unique), | |
| 85 .parsed = &unique}, | |
| 86 /* start */ | |
| 87 { .comment = "starting LBA", | |
| 88 .validator = InNumberRange, | |
| 89 .valid_range = 0, | |
| 90 .parsed = &begin_lba}, | |
| 91 /* end */ | |
| 92 { .comment = "ending LBA", | |
| 93 .validator = InNumberRange, | |
| 94 .valid_range = 0, | |
| 95 .parsed = &size_lba}, | |
| 96 /* name */ | |
| 97 { .comment = "Partition name", | |
| 98 .validator = CopyString, | |
| 99 .valid_range = (void*)sizeof(name), | |
| 100 .parsed = &name}, | |
| 101 { /* last element, which should be zero. */ } | |
| 102 }; | |
| 103 | |
| 104 void AdmHelp() { | |
| 105 printf("\nUsage: %s {add|delete|modify} [OPTIONS] device_name\n\n", progname); | |
| 106 ShowOptions(adm_options, adm_options_details, ARRAY_COUNT(adm_options)); | |
| 107 PrintTypes(); | |
| 108 printf("\n"); | |
| 109 } | |
| 110 | |
| 111 enum { | |
| 112 ADD, | |
| 113 DELETE, | |
| 114 MODIFY, | |
| 115 } command; | |
| 116 | |
| 117 /* Parses all options (and validates them), then opens the drive and sets | |
| 118 * corresponding bits in GPT entry. */ | |
| 119 int CgptAdm(int argc, char *argv[]) { | |
| 120 struct drive drive; | |
| 121 char *cmd; | |
| 122 GptEntry *entry; | |
| 123 Guid type_guid, unique_guid; | |
| 124 int dirty = 0; | |
| 125 | |
| 126 /* I know this is NOT the perfect place to put code to make options[] and | |
| 127 * details[] are synced. But this is the best place we have right now since C | |
| 128 * preprocessor doesn't know sizeof() for #if directive. */ | |
| 129 assert(ARRAY_COUNT(adm_options) == | |
| 130 ARRAY_COUNT(adm_options_details)); | |
| 131 | |
| 132 cmd = argv[optind - 1]; | |
| 133 if (!strcmp("add", cmd)) command = ADD; | |
| 134 else if (!strcmp("delete", cmd)) command = DELETE; | |
| 135 else if (!strcmp("modify", cmd)) command = MODIFY; | |
| 136 | |
| 137 #if 0//FIXME | |
| 138 help = partition = bad = successful = tries = priority = | |
| 139 #endif | |
| 140 help = partition = begin_lba = size_lba = NOT_INITED; | |
| 141 type[0] = '\0'; | |
| 142 unique[0] = '\0'; | |
| 143 name[0] = '\0'; | |
| 144 | |
| 145 if (CGPT_OK != HandleOptions(argc, argv, | |
| 146 "hi:t:u:b:s:n:", | |
| 147 ARRAY_COUNT(adm_options), | |
| 148 adm_options, | |
| 149 adm_options_details)) | |
| 150 return CGPT_FAILED; | |
| 151 if (help != NOT_INITED) { | |
| 152 AdmHelp(); | |
| 153 return CGPT_FAILED; | |
| 154 } | |
| 155 | |
| 156 if (CGPT_OK != OpenDriveInLastArgument(argc, argv, &drive)) | |
| 157 return CGPT_FAILED; | |
| 158 | |
| 159 if (CheckValid(&drive) != CGPT_OK) goto error_close; | |
| 160 | |
| 161 if (partition == NOT_INITED) { | |
| 162 printf("[ERROR] Please provide partition number with --partition or -i.\n"); | |
| 163 goto error_close; | |
| 164 } | |
| 165 | |
| 166 entry = GetEntry(&drive.gpt, PRIMARY, partition); | |
| 167 /* check before really doing something. */ | |
| 168 switch (command) { | |
| 169 case ADD: | |
| 170 if (NonZeroGuid(&entry->type)) { | |
| 171 printf("[ERROR] partition %d is not free, use '%s modify' instead.\n", | |
| 172 partition, progname); | |
| 173 goto error_close; | |
| 174 } | |
| 175 if (type[0] == '\0') { | |
| 176 printf("* You must give a type with '--type' or '-t'.\n"); | |
| 177 PrintTypes(); | |
| 178 goto error_close; | |
| 179 } | |
| 180 if (begin_lba == NOT_INITED) { | |
| 181 printf("* You didn't give the begin LBA, use '--begin' to specify.\n"); | |
| 182 goto error_close; | |
| 183 } | |
| 184 if (size_lba == NOT_INITED) { | |
| 185 printf("* You didn't give size, use '--size' to specify.\n"); | |
| 186 goto error_close; | |
| 187 } | |
| 188 break; | |
| 189 case DELETE: | |
| 190 if (!NonZeroGuid(&entry->type)) { | |
| 191 printf("[ERROR] partition %d is free already.\n", partition); | |
| 192 goto error_close; | |
| 193 } | |
| 194 break; | |
| 195 case MODIFY: | |
| 196 if (!NonZeroGuid(&entry->type)) { | |
| 197 printf("[ERROR] partition %d is free, use '%s add' first.\n", | |
| 198 partition, progname); | |
| 199 goto error_close; | |
| 200 } | |
| 201 break; | |
| 202 } | |
| 203 | |
| 204 #if 0 //FIXME | |
| 205 if (bad != NOT_INITED) | |
| 206 SetBad(&drive.gpt, PRIMARY, partition, bad); | |
| 207 if (successful != NOT_INITED) | |
| 208 SetSuccessful(&drive.gpt, PRIMARY, partition, successful); | |
| 209 if (tries != NOT_INITED) | |
| 210 SetTries(&drive.gpt, PRIMARY, partition, tries); | |
| 211 if (priority != NOT_INITED) | |
| 212 SetPriority(&drive.gpt, PRIMARY, partition, priority); | |
| 213 #endif | |
| 214 if (type[0]) { | |
| 215 if (CGPT_OK != SupportedType(type, &type_guid) && | |
| 216 CGPT_OK != StrToGuid(type, &type_guid)) { | |
| 217 printf("[ERROR] You didn't give a valid type [%s]\n", type); | |
| 218 goto error_close; | |
| 219 } | |
| 220 Memcpy(&entry->type, &type_guid, sizeof(Guid)); | |
| 221 ++dirty; | |
| 222 } | |
| 223 if (unique[0]) { | |
| 224 if (CGPT_OK != StrToGuid(unique, &unique_guid)) { | |
| 225 printf("[ERROR] You didn't give a valid UUID [%s]\n", unique); | |
| 226 goto error_close; | |
| 227 } | |
| 228 Memcpy(&entry->unique, &unique_guid, sizeof(Guid)); | |
| 229 ++dirty; | |
| 230 } | |
| 231 if (begin_lba != NOT_INITED) { | |
| 232 entry->starting_lba = begin_lba; | |
| 233 ++dirty; | |
| 234 } | |
| 235 if (size_lba != NOT_INITED) { | |
| 236 entry->ending_lba = entry->starting_lba + size_lba - 1; | |
| 237 ++dirty; | |
| 238 } | |
| 239 if (name[0]) { | |
| 240 UTF8ToUTF16((uint8_t*)name, entry->name); | |
| 241 ++dirty; | |
| 242 } | |
| 243 | |
| 244 if (command == DELETE) { | |
| 245 Memcpy(&entry->type, &guid_unused, sizeof(Guid)); | |
| 246 } | |
| 247 | |
| 248 if (dirty) { | |
| 249 uint32_t valid_entries; | |
| 250 | |
| 251 valid_entries = drive.gpt.valid_entries; | |
| 252 if ((valid_entries != CheckValidEntries(&drive.gpt)) || | |
| 253 (valid_entries != CheckOverlappedPartition(&drive.gpt))) { | |
| 254 printf("\n[ERROR] Your change makes GPT invalid (or worse). " | |
| 255 "Please check your arguments.\n\n"); | |
| 256 drive.gpt.modified = 0; /* DriveClose() won't update hard drive. */ | |
| 257 goto error_close; | |
| 258 } | |
| 259 | |
| 260 /* Claims primary is good, then secondary will be overwritten. */ | |
| 261 RepairEntries(&drive.gpt, MASK_PRIMARY); | |
| 262 RepairHeader(&drive.gpt, MASK_PRIMARY); | |
| 263 | |
| 264 /* Forces headers and entries are modified so that CRC32 will be | |
| 265 * re-calculated and headers and entries will be updated to drive. */ | |
| 266 drive.gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 | | |
| 267 GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2); | |
| 268 UpdateCrc(&drive.gpt); | |
| 269 } | |
| 270 DriveClose(&drive); | |
| 271 return CGPT_OK; | |
| 272 | |
| 273 error_close: | |
| 274 DriveClose(&drive); | |
| 275 return CGPT_FAILED; | |
| 276 } | |
| OLD | NEW |