Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(930)

Side by Side Diff: utility/cgpt/cgpt.c

Issue 2719008: Nearly complete rewrite of cgpt tool. (Closed) Base URL: ssh://git@chromiumos-git//vboot_reference.git
Patch Set: Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « utility/cgpt/cgpt.h ('k') | utility/cgpt/cgpt_add_modify_delete.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 * Utility for ChromeOS-specific GPT partitions, Please see corresponding .c
6 * files for more details.
7 */
8 /* To compile on host without compatility to BSD, we include
9 * endian.h under chroot. */
10 #define _BSD_SOURCE
11 #include "endian.h"
12
13 #define __USE_LARGEFILE64
14 #define __USE_FILE_OFFSET64
15 #define _LARGEFILE64_SOURCE
16 #include "cgpt.h"
17 #include "cgpt_tofix.h"
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <getopt.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/ioctl.h>
26 #include <sys/mount.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include "cgptlib_internal.h"
31 #include "utility.h"
32
33 /* For usage print */
34 const char* progname;
35
36 /* Lists all command here. */
37 struct {
38 const char *name;
39 int (*fp)(int argc, char *argv[]);
40 const char *comment;
41 } cmds[] = {
42 {"add", CgptAdm, "Add a partition to drive"},
43 {"delete", CgptAdm, "Delete a partition on drive"},
44 {"modify", CgptAdm, "Modify the partition on drive"},
45 {"attribute", CgptAttribute, "Update GPT attribute bits "
46 "(for ChromeOS kernel entry only)"},
47 {"dev", CgptDev, "Developper mode"},
48 {"repair", CgptRepair, "Repair primary and secondary headers and tables"},
49 {"show", CgptShow, "Show partition details"},
50 };
51
52 /* Shows main menu. If 'message' is non-NULL, shows it as header. Then, this
53 * traverses cmds[] and shows supported commands and their comments. */
54 void Usage(const char *message) {
55 int i;
56
57 if (message) printf("%s\n", message);
58 printf("Usage: %s COMMAND [OPTIONS]\n\n"
59 "Supported COMMANDs:\n\n",
60 progname);
61 for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
62 printf(" %-10s %s\n", cmds[i].name, cmds[i].comment);
63 }
64 printf("\nFor more detailed usage, use %s COMMAND --help.\n\n", progname);
65 }
66
67 /* GUID conversion functions. Accepted format:
68 *
69 * "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
70 *
71 * Returns CGPT_OK if parsing is successful; otherwise CGPT_FAILED.
72 */
73 int StrToGuid(const char *str, Guid *guid) {
74 uint32_t time_low, time_mid, time_high_and_version;
75
76 if (11 > sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
77 &time_low,
78 (unsigned int *)&time_mid,
79 (unsigned int *)&time_high_and_version,
80 (unsigned int *)&guid->u.Uuid.clock_seq_high_and_reserved,
81 (unsigned int *)&guid->u.Uuid.clock_seq_low,
82 (unsigned int *)&guid->u.Uuid.node[0],
83 (unsigned int *)&guid->u.Uuid.node[1],
84 (unsigned int *)&guid->u.Uuid.node[2],
85 (unsigned int *)&guid->u.Uuid.node[3],
86 (unsigned int *)&guid->u.Uuid.node[4],
87 (unsigned int *)&guid->u.Uuid.node[5])) return CGPT_FAILED;
88
89 guid->u.Uuid.time_low = htole32(time_low);
90 guid->u.Uuid.time_mid = htole16(time_mid);
91 guid->u.Uuid.time_high_and_version = htole16(time_high_and_version);
92
93 return CGPT_OK;
94 }
95
96 void GuidToStr(const Guid *guid, char *str) {
97 sprintf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
98 le32toh(guid->u.Uuid.time_low), le16toh(guid->u.Uuid.time_mid),
99 le16toh(guid->u.Uuid.time_high_and_version),
100 guid->u.Uuid.clock_seq_high_and_reserved, guid->u.Uuid.clock_seq_low,
101 guid->u.Uuid.node[0], guid->u.Uuid.node[1], guid->u.Uuid.node[2],
102 guid->u.Uuid.node[3], guid->u.Uuid.node[4], guid->u.Uuid.node[5]);
103 }
104
105 /* Convert UTF16 string to UTF8. Rewritten from gpt utility.
106 * Caller must prepare enough space for UTF8. The rough estimation is:
107 *
108 * utf8 length = bytecount(utf16) * 1.5
109 */
110 #define SIZEOF_GPTENTRY_NAME 36 /* sizeof(GptEntry.name[]) */
111 void UTF16ToUTF8(const uint16_t *utf16, uint8_t *utf8)
112 {
113 size_t s8idx, s16idx, s16len;
114 uint32_t utfchar;
115 unsigned int next_utf16;
116
117 for (s16len = 0; s16len < SIZEOF_GPTENTRY_NAME && utf16[s16len]; ++s16len);
118
119 *utf8 = s8idx = s16idx = 0;
120 while (s16idx < s16len) {
121 utfchar = le16toh(utf16[s16idx++]);
122 if ((utfchar & 0xf800) == 0xd800) {
123 next_utf16 = le16toh(utf16[s16idx]);
124 if ((utfchar & 0x400) != 0 || (next_utf16 & 0xfc00) != 0xdc00)
125 utfchar = 0xfffd;
126 else
127 s16idx++;
128 }
129 if (utfchar < 0x80) {
130 utf8[s8idx++] = utfchar;
131 } else if (utfchar < 0x800) {
132 utf8[s8idx++] = 0xc0 | (utfchar >> 6);
133 utf8[s8idx++] = 0x80 | (utfchar & 0x3f);
134 } else if (utfchar < 0x10000) {
135 utf8[s8idx++] = 0xe0 | (utfchar >> 12);
136 utf8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
137 utf8[s8idx++] = 0x80 | (utfchar & 0x3f);
138 } else if (utfchar < 0x200000) {
139 utf8[s8idx++] = 0xf0 | (utfchar >> 18);
140 utf8[s8idx++] = 0x80 | ((utfchar >> 12) & 0x3f);
141 utf8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
142 utf8[s8idx++] = 0x80 | (utfchar & 0x3f);
143 }
144 }
145 utf8[s8idx++] = 0;
146 }
147
148 /* Convert UTF8 string to UTF16. Rewritten from gpt utility.
149 * Caller must prepare enough space for UTF16. The conservative estimation is:
150 *
151 * utf16 bytecount = bytecount(utf8) / 3 * 4
152 */
153 void UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16)
154 {
155 size_t s16idx, s8idx, s8len;
156 uint32_t utfchar;
157 unsigned int c, utfbytes;
158
159 for (s8len = 0; utf8[s8len]; ++s8len);
160
161 s8idx = s16idx = 0;
162 utfbytes = 0;
163 do {
164 c = utf8[s8idx++];
165 if ((c & 0xc0) != 0x80) {
166 /* Initial characters. */
167 if (utfbytes != 0) {
168 /* Incomplete encoding. */
169 utf16[s16idx++] = 0xfffd;
170 }
171 if ((c & 0xf8) == 0xf0) {
172 utfchar = c & 0x07;
173 utfbytes = 3;
174 } else if ((c & 0xf0) == 0xe0) {
175 utfchar = c & 0x0f;
176 utfbytes = 2;
177 } else if ((c & 0xe0) == 0xc0) {
178 utfchar = c & 0x1f;
179 utfbytes = 1;
180 } else {
181 utfchar = c & 0x7f;
182 utfbytes = 0;
183 }
184 } else {
185 /* Followup characters. */
186 if (utfbytes > 0) {
187 utfchar = (utfchar << 6) + (c & 0x3f);
188 utfbytes--;
189 } else if (utfbytes == 0)
190 utfbytes = -1;
191 utfchar = 0xfffd;
192 }
193 if (utfbytes == 0) {
194 if (utfchar >= 0x10000) {
195 utf16[s16idx++] = htole16(0xd800 | ((utfchar>>10)-0x40));
196 if (s16idx >= SIZEOF_GPTENTRY_NAME) break;
197 utf16[s16idx++] = htole16(0xdc00 | (utfchar & 0x3ff));
198 } else {
199 utf16[s16idx++] = htole16(utfchar);
200 }
201 }
202 } while (c != 0 && s16idx < SIZEOF_GPTENTRY_NAME);
203 if (s16idx < SIZEOF_GPTENTRY_NAME)
204 utf16[s16idx++] = 0;
205 }
206
207 struct {
208 Guid type;
209 char *name;
210 char *description;
211 } supported_types[] = {
212 {GPT_ENT_TYPE_UNUSED, "unused", "Unused partition"},
213 {GPT_ENT_TYPE_EFI, "efi", "EFI System Partition"},
214 {GPT_ENT_TYPE_CHROMEOS_KERNEL, "croskern", "ChromeOS kernel"},
215 {GPT_ENT_TYPE_CHROMEOS_ROOTFS, "crosroot", "ChromeOS rootfs"},
216 {GPT_ENT_TYPE_CHROMEOS_RESERVED, "crosresv", "ChromeOS reserved"},
217 {GPT_ENT_TYPE_LINUX_DATA, "data", "Linux data"},
218 };
219
220 /* Resolves human-readable GPT type.
221 * Returns CGPT_OK if found.
222 * Returns CGPT_FAILED if no known type found. */
223 int ResolveType(const Guid *type, char *buf) {
224 int i;
225 for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
226 if (!Memcmp(type, &supported_types[i].type, sizeof(Guid))) {
227 strcpy(buf, supported_types[i].description);
228 return CGPT_OK;
229 }
230 }
231 return CGPT_FAILED;
232 }
233
234 int SupportedType(const char *name, Guid *type) {
235 int i;
236 for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
237 if (!strcmp(name, supported_types[i].name)) {
238 Memcpy(type, &supported_types[i].type, sizeof(Guid));
239 return CGPT_OK;
240 }
241 }
242 return CGPT_FAILED;
243 }
244
245 void PrintTypes(void) {
246 int i;
247 printf("\n* For --type option, you can use the following alias, "
248 "instead of hex values:\n");
249 for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
250 printf(" %-10s %s\n", supported_types[i].name,
251 supported_types[i].description);
252 }
253 printf("\n");
254 }
255
256 /* Loads sectors from 'fd'.
257 * *buf is pointed to an allocated memory when returned, and should be
258 * freed by cgpt_close().
259 *
260 * fd -- file descriptot.
261 * buf -- pointer to buffer pointer
262 * sector -- offset of starting sector (in sectors)
263 * sector_bytes -- bytes per sector
264 * sector_count -- number of sectors to load
265 *
266 * Returns CGPT_OK for successful. Aborts if any error occurs.
267 */
268 int Load(const int fd, uint8_t **buf,
269 const uint64_t sector,
270 const uint64_t sector_bytes,
271 const uint64_t sector_count) {
272 int count; /* byte count to read */
273 int nread;
274
275 assert(buf);
276 count = sector_bytes * sector_count;
277 *buf = Malloc(count);
278 assert(*buf);
279
280 if (-1 == lseek64(fd, sector * sector_bytes, SEEK_SET))
281 goto error_free;
282
283 nread = read(fd, *buf, count);
284 if (nread < count)
285 goto error_free;
286
287 return CGPT_OK;
288
289 error_free:
290 Free(*buf);
291 *buf = 0;
292 abort();
293 }
294
295 /* Saves sectors to 'fd'.
296 *
297 * fd -- file descriptot.
298 * buf -- pointer to buffer
299 * sector -- starting sector offset
300 * sector_bytes -- bytes per sector
301 * sector_count -- number of sector to save
302 *
303 * Returns CGPT_OK for successful, CGPT_FAILED for failed.
304 */
305 int Save(const int fd, const uint8_t *buf,
306 const uint64_t sector,
307 const uint64_t sector_bytes,
308 const uint64_t sector_count) {
309 int count; /* byte count to write */
310 int nwrote;
311
312 assert(buf);
313 count = sector_bytes * sector_count;
314
315 if (-1 == lseek64(fd, sector * sector_bytes, SEEK_SET))
316 return CGPT_FAILED;
317
318 nwrote = write(fd, buf, count);
319 if (nwrote < count)
320 return CGPT_FAILED;
321
322 return CGPT_OK;
323 }
324
325 int CheckValid(const struct drive *drive) {
326 if ((drive->gpt.valid_headers != MASK_BOTH) ||
327 (drive->gpt.valid_entries != MASK_BOTH)) {
328 printf("\n[ERROR] any of GPT header/entries is invalid, "
329 "please run '%s repair' first\n", progname);
330 return CGPT_FAILED;
331 }
332 return CGPT_OK;
333 }
334
335 /* Opens a block device (a regular file works well too).
336 *
337 * Returns CGPT_FAILED if any error happens.
338 * Returns CGPT_OK if success and information are stored in 'drive'. */
339 int DriveOpen(const char *drive_path, struct drive *drive) {
340 struct stat stat;
341 int gpt_retval;
342
343 assert(drive_path);
344 assert(drive);
345
346 Memset(drive, 0, sizeof(struct drive));
347 drive->fd = open(drive_path, O_RDWR | O_LARGEFILE);
348 if (drive->fd == -1) {
349 printf("[ERROR] Cannot open drive file [%s]: %s\n",
350 drive_path, strerror(errno));
351 return CGPT_FAILED;
352 }
353
354 if (fstat(drive->fd, &stat) == -1) {
355 goto error_close;
356 }
357 if ((stat.st_mode & S_IFMT) != S_IFREG) {
358 if (ioctl(drive->fd, BLKGETSIZE64, &drive->size) < 0) {
359 printf("[ERROR] Cannot get sector size from drive file [%s]: %s\n",
360 drive_path, strerror(errno));
361 goto error_close;
362 }
363 if (ioctl(drive->fd, BLKSSZGET, &drive->gpt.sector_bytes) < 0) {
364 printf("[ERROR] Cannot get drive size from drive file [%s]: %s\n",
365 drive_path, strerror(errno));
366 goto error_close;
367 }
368 } else {
369 drive->gpt.sector_bytes = 512; /* bytes */
370 drive->size = stat.st_size;
371 }
372 if (drive->size % drive->gpt.sector_bytes) {
373 printf("[ERROR] Media size (%llu) is not the multiple of sector size(%d)\n",
374 (long long unsigned int)drive->size, drive->gpt.sector_bytes);
375 goto error_close;
376 }
377 drive->gpt.drive_sectors = drive->size / drive->gpt.sector_bytes;
378
379 Load(drive->fd, &drive->gpt.primary_header, GPT_PMBR_SECTOR,
380 drive->gpt.sector_bytes, GPT_HEADER_SECTOR);
381 Load(drive->fd, &drive->gpt.secondary_header,
382 drive->gpt.drive_sectors - GPT_PMBR_SECTOR,
383 drive->gpt.sector_bytes, GPT_HEADER_SECTOR);
384 Load(drive->fd, &drive->gpt.primary_entries,
385 GPT_PMBR_SECTOR + GPT_HEADER_SECTOR,
386 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS);
387 Load(drive->fd, &drive->gpt.secondary_entries,
388 drive->gpt.drive_sectors - GPT_HEADER_SECTOR - GPT_ENTRIES_SECTORS,
389 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS);
390
391 if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive->gpt))) {
392 printf("[ERROR] GptSanityCheck(): %s\n", GptError(gpt_retval));
393 goto error_close;
394 }
395
396 drive->inited = 1;
397
398 return CGPT_OK;
399
400 error_close:
401 close(drive->fd);
402 return CGPT_FAILED;
403 }
404
405 int DriveClose(struct drive *drive) {
406 if (drive->inited) {
407 if (drive->gpt.modified & GPT_MODIFIED_HEADER1)
408 assert(CGPT_OK ==
409 Save(drive->fd, drive->gpt.primary_header, GPT_PMBR_SECTOR,
410 drive->gpt.sector_bytes, GPT_HEADER_SECTOR));
411 if (drive->gpt.modified & GPT_MODIFIED_HEADER2)
412 assert(CGPT_OK ==
413 Save(drive->fd, drive->gpt.secondary_header,
414 drive->gpt.drive_sectors - GPT_PMBR_SECTOR,
415 drive->gpt.sector_bytes, GPT_HEADER_SECTOR));
416 if (drive->gpt.modified & GPT_MODIFIED_ENTRIES1)
417 assert(CGPT_OK ==
418 Save(drive->fd, drive->gpt.primary_entries,
419 GPT_PMBR_SECTOR + GPT_HEADER_SECTOR,
420 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS));
421 if (drive->gpt.modified & GPT_MODIFIED_ENTRIES2)
422 assert(CGPT_OK ==
423 Save(drive->fd, drive->gpt.secondary_entries,
424 drive->gpt.drive_sectors - GPT_HEADER_SECTOR -
425 GPT_ENTRIES_SECTORS,
426 drive->gpt.sector_bytes, GPT_ENTRIES_SECTORS));
427
428 close(drive->fd);
429 }
430
431 Free(drive->gpt.primary_header);
432 drive->gpt.primary_header = 0;
433 Free(drive->gpt.primary_entries);
434 drive->gpt.primary_entries = 0;
435 Free(drive->gpt.secondary_header);
436 drive->gpt.secondary_header = 0;
437 Free(drive->gpt.secondary_entries);
438 drive->gpt.secondary_entries = 0;
439
440 drive->inited = 0;
441 return CGPT_OK;
442 }
443
444 int main(int argc, char *argv[]) {
445 char *cmd;
446 int i;
447
448 progname = argv[0];
449 cmd = argv[optind++];
450 for (i = 0; i < sizeof(cmds)/sizeof(cmds[0]); ++i) {
451 if (cmd && !strcmp(cmds[i].name, cmd))
452 return cmds[i].fp(argc, argv);
453 }
454
455 Usage(0);
456 return CGPT_FAILED;
457 }
OLDNEW
« no previous file with comments | « utility/cgpt/cgpt.h ('k') | utility/cgpt/cgpt_add_modify_delete.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698