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 |