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 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <getopt.h> 12 #ifndef HAVE_MACOS 13 #include <linux/major.h> 14 #include <mtd/mtd-user.h> 15 #endif 16 #include <stdarg.h> 17 #include <stdint.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <sys/ioctl.h> 22 #include <sys/mount.h> 23 #include <sys/stat.h> 24 #include <sys/types.h> 25 #include <unistd.h> 26 27 #include "cgpt.h" 28 #include "cgptlib_internal.h" 29 #include "crc32.h" 30 #include "vboot_host.h" 31 32 static const char kErrorTag[] = "ERROR"; 33 static const char kWarningTag[] = "WARNING"; 34 35 static void LogToStderr(const char *tag, const char *format, va_list ap) { 36 fprintf(stderr, "%s: ", tag); 37 vfprintf(stderr, format, ap); 38 } 39 40 void Error(const char *format, ...) { 41 va_list ap; 42 va_start(ap, format); 43 LogToStderr(kErrorTag, format, ap); 44 va_end(ap); 45 } 46 47 void Warning(const char *format, ...) { 48 va_list ap; 49 va_start(ap, format); 50 LogToStderr(kWarningTag, format, ap); 51 va_end(ap); 52 } 53 54 int CheckValid(const struct drive *drive) { 55 if ((drive->gpt.valid_headers != MASK_BOTH) || 56 (drive->gpt.valid_entries != MASK_BOTH)) { 57 Warning("One of the GPT headers/entries is invalid\n\n"); 58 return CGPT_FAILED; 59 } 60 return CGPT_OK; 61 } 62 63 int Load(struct drive *drive, uint8_t **buf, 64 const uint64_t sector, 65 const uint64_t sector_bytes, 66 const uint64_t sector_count) { 67 int count; /* byte count to read */ 68 int nread; 69 70 require(buf); 71 if (!sector_count || !sector_bytes) { 72 Error("%s() failed at line %d: sector_count=%d, sector_bytes=%d\n", 73 __FUNCTION__, __LINE__, sector_count, sector_bytes); 74 return CGPT_FAILED; 75 } 76 /* Make sure that sector_bytes * sector_count doesn't roll over. */ 77 if (sector_bytes > (UINT64_MAX / sector_count)) { 78 Error("%s() failed at line %d: sector_count=%d, sector_bytes=%d\n", 79 __FUNCTION__, __LINE__, sector_count, sector_bytes); 80 return CGPT_FAILED; 81 } 82 count = sector_bytes * sector_count; 83 *buf = malloc(count); 84 require(*buf); 85 86 if (-1 == lseek(drive->fd, sector * sector_bytes, SEEK_SET)) { 87 Error("Can't seek: %s\n", strerror(errno)); 88 goto error_free; 89 } 90 91 nread = read(drive->fd, *buf, count); 92 if (nread < count) { 93 Error("Can't read enough: %d, not %d\n", nread, count); 94 goto error_free; 95 } 96 97 return CGPT_OK; 98 99 error_free: 100 free(*buf); 101 *buf = 0; 102 return CGPT_FAILED; 103 } 104 105 106 int ReadPMBR(struct drive *drive) { 107 if (-1 == lseek(drive->fd, 0, SEEK_SET)) 108 return CGPT_FAILED; 109 110 int nread = read(drive->fd, &drive->pmbr, sizeof(struct pmbr)); 111 if (nread != sizeof(struct pmbr)) 112 return CGPT_FAILED; 113 114 return CGPT_OK; 115 } 116 117 int WritePMBR(struct drive *drive) { 118 if (-1 == lseek(drive->fd, 0, SEEK_SET)) 119 return CGPT_FAILED; 120 121 int nwrote = write(drive->fd, &drive->pmbr, sizeof(struct pmbr)); 122 if (nwrote != sizeof(struct pmbr)) 123 return CGPT_FAILED; 124 125 return CGPT_OK; 126 } 127 128 int Save(struct drive *drive, const uint8_t *buf, 129 const uint64_t sector, 130 const uint64_t sector_bytes, 131 const uint64_t sector_count) { 132 int count; /* byte count to write */ 133 int nwrote; 134 135 require(buf); 136 count = sector_bytes * sector_count; 137 138 if (-1 == lseek(drive->fd, sector * sector_bytes, SEEK_SET)) 139 return CGPT_FAILED; 140 141 nwrote = write(drive->fd, buf, count); 142 if (nwrote < count) 143 return CGPT_FAILED; 144 145 return CGPT_OK; 146 } 147 148 static int GptLoad(struct drive *drive, uint32_t sector_bytes) { 149 drive->gpt.sector_bytes = sector_bytes; 150 if (drive->size % drive->gpt.sector_bytes) { 151 Error("Media size (%llu) is not a multiple of sector size(%d)\n", 152 (long long unsigned int)drive->size, drive->gpt.sector_bytes); 153 return -1; 154 } 155 drive->gpt.streaming_drive_sectors = drive->size / drive->gpt.sector_bytes; 156 157 /* TODO(namnguyen): Remove this and totally trust gpt_drive_sectors. */ 158 if (!(drive->gpt.flags & GPT_FLAG_EXTERNAL)) { 159 drive->gpt.gpt_drive_sectors = drive->gpt.streaming_drive_sectors; 160 } /* Else, we trust gpt.gpt_drive_sectors. */ 161 162 // Read the data. 163 if (CGPT_OK != Load(drive, &drive->gpt.primary_header, 164 GPT_PMBR_SECTORS, 165 drive->gpt.sector_bytes, GPT_HEADER_SECTORS)) { 166 Error("Cannot read primary GPT header\n"); 167 return -1; 168 } 169 if (CGPT_OK != Load(drive, &drive->gpt.secondary_header, 170 drive->gpt.gpt_drive_sectors - GPT_PMBR_SECTORS, 171 drive->gpt.sector_bytes, GPT_HEADER_SECTORS)) { 172 Error("Cannot read secondary GPT header\n"); 173 return -1; 174 } 175 GptHeader* primary_header = (GptHeader*)drive->gpt.primary_header; 176 if (CheckHeader(primary_header, 0, drive->gpt.streaming_drive_sectors, 177 drive->gpt.gpt_drive_sectors, 178 drive->gpt.flags) == 0) { 179 if (CGPT_OK != Load(drive, &drive->gpt.primary_entries, 180 primary_header->entries_lba, 181 drive->gpt.sector_bytes, 182 CalculateEntriesSectors(primary_header))) { 183 Error("Cannot read primary partition entry array\n"); 184 return -1; 185 } 186 } else { 187 Warning("Primary GPT header is invalid\n"); 188 } 189 GptHeader* secondary_header = (GptHeader*)drive->gpt.secondary_header; 190 if (CheckHeader(secondary_header, 1, drive->gpt.streaming_drive_sectors, 191 drive->gpt.gpt_drive_sectors, 192 drive->gpt.flags) == 0) { 193 if (CGPT_OK != Load(drive, &drive->gpt.secondary_entries, 194 secondary_header->entries_lba, 195 drive->gpt.sector_bytes, 196 CalculateEntriesSectors(secondary_header))) { 197 Error("Cannot read secondary partition entry array\n"); 198 return -1; 199 } 200 } else { 201 Warning("Secondary GPT header is invalid\n"); 202 } 203 return 0; 204 } 205 206 static int GptSave(struct drive *drive) { 207 int errors = 0; 208 if (drive->gpt.modified & GPT_MODIFIED_HEADER1) { 209 if (CGPT_OK != Save(drive, drive->gpt.primary_header, 210 GPT_PMBR_SECTORS, 211 drive->gpt.sector_bytes, GPT_HEADER_SECTORS)) { 212 errors++; 213 Error("Cannot write primary header: %s\n", strerror(errno)); 214 } 215 } 216 217 if (drive->gpt.modified & GPT_MODIFIED_HEADER2) { 218 if(CGPT_OK != Save(drive, drive->gpt.secondary_header, 219 drive->gpt.gpt_drive_sectors - GPT_PMBR_SECTORS, 220 drive->gpt.sector_bytes, GPT_HEADER_SECTORS)) { 221 errors++; 222 Error("Cannot write secondary header: %s\n", strerror(errno)); 223 } 224 } 225 GptHeader* primary_header = (GptHeader*)drive->gpt.primary_header; 226 if (drive->gpt.modified & GPT_MODIFIED_ENTRIES1) { 227 if (CGPT_OK != Save(drive, drive->gpt.primary_entries, 228 primary_header->entries_lba, 229 drive->gpt.sector_bytes, 230 CalculateEntriesSectors(primary_header))) { 231 errors++; 232 Error("Cannot write primary entries: %s\n", strerror(errno)); 233 } 234 } 235 GptHeader* secondary_header = (GptHeader*)drive->gpt.secondary_header; 236 if (drive->gpt.modified & GPT_MODIFIED_ENTRIES2) { 237 if (CGPT_OK != Save(drive, drive->gpt.secondary_entries, 238 secondary_header->entries_lba, 239 drive->gpt.sector_bytes, 240 CalculateEntriesSectors(secondary_header))) { 241 errors++; 242 Error("Cannot write secondary entries: %s\n", strerror(errno)); 243 } 244 } 245 246 if (drive->gpt.primary_header) 247 free(drive->gpt.primary_header); 248 drive->gpt.primary_header = 0; 249 if (drive->gpt.primary_entries) 250 free(drive->gpt.primary_entries); 251 drive->gpt.primary_entries = 0; 252 if (drive->gpt.secondary_header) 253 free(drive->gpt.secondary_header); 254 drive->gpt.secondary_header = 0; 255 if (drive->gpt.secondary_entries) 256 free(drive->gpt.secondary_entries); 257 drive->gpt.secondary_entries = 0; 258 return errors ? -1 : 0; 259 } 260 261 /* 262 * Query drive size and bytes per sector. Return zero on success. On error, 263 * -1 is returned and errno is set appropriately. 264 */ 265 static int ObtainDriveSize(int fd, uint64_t* size, uint32_t* sector_bytes) { 266 struct stat stat; 267 if (fstat(fd, &stat) == -1) { 268 return -1; 269 } 270 #ifndef HAVE_MACOS 271 if ((stat.st_mode & S_IFMT) != S_IFREG) { 272 if (ioctl(fd, BLKGETSIZE64, size) < 0) { 273 return -1; 274 } 275 if (ioctl(fd, BLKSSZGET, sector_bytes) < 0) { 276 return -1; 277 } 278 } else { 279 *sector_bytes = 512; /* bytes */ 280 *size = stat.st_size; 281 } 282 #else 283 *sector_bytes = 512; /* bytes */ 284 *size = stat.st_size; 285 #endif 286 return 0; 287 } 288 289 int DriveOpen(const char *drive_path, struct drive *drive, int mode, 290 uint64_t drive_size) { 291 uint32_t sector_bytes; 292 293 require(drive_path); 294 require(drive); 295 296 // Clear struct for proper error handling. 297 memset(drive, 0, sizeof(struct drive)); 298 299 drive->fd = open(drive_path, mode | 300 #ifndef HAVE_MACOS 301 O_LARGEFILE | 302 #endif 303 O_NOFOLLOW); 304 if (drive->fd == -1) { 305 Error("Can't open %s: %s\n", drive_path, strerror(errno)); 306 return CGPT_FAILED; 307 } 308 309 sector_bytes = 512; 310 uint64_t gpt_drive_size; 311 if (ObtainDriveSize(drive->fd, &gpt_drive_size, §or_bytes) != 0) { 312 Error("Can't get drive size and bytes per sector for %s: %s\n", 313 drive_path, strerror(errno)); 314 goto error_close; 315 } 316 317 drive->gpt.gpt_drive_sectors = gpt_drive_size / sector_bytes; 318 if (drive_size == 0) { 319 drive->size = gpt_drive_size; 320 drive->gpt.flags = 0; 321 } else { 322 drive->size = drive_size; 323 drive->gpt.flags = GPT_FLAG_EXTERNAL; 324 } 325 326 327 if (GptLoad(drive, sector_bytes)) { 328 goto error_close; 329 } 330 331 // We just load the data. Caller must validate it. 332 return CGPT_OK; 333 334 error_close: 335 (void) DriveClose(drive, 0); 336 return CGPT_FAILED; 337 } 338 339 340 int DriveClose(struct drive *drive, int update_as_needed) { 341 int errors = 0; 342 343 if (update_as_needed) { 344 if (GptSave(drive)) { 345 errors++; 346 } 347 } 348 349 // Sync early! Only sync file descriptor here, and leave the whole system sync 350 // outside cgpt because whole system sync would trigger tons of disk accesses 351 // and timeout tests. 352 fsync(drive->fd); 353 354 close(drive->fd); 355 356 return errors ? CGPT_FAILED : CGPT_OK; 357 } 358 359 360 /* GUID conversion functions. Accepted format: 361 * 362 * "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" 363 * 364 * Returns CGPT_OK if parsing is successful; otherwise CGPT_FAILED. 365 */ 366 int StrToGuid(const char *str, Guid *guid) { 367 uint32_t time_low; 368 uint16_t time_mid; 369 uint16_t time_high_and_version; 370 unsigned int chunk[11]; 371 372 if (11 != sscanf(str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", 373 chunk+0, 374 chunk+1, 375 chunk+2, 376 chunk+3, 377 chunk+4, 378 chunk+5, 379 chunk+6, 380 chunk+7, 381 chunk+8, 382 chunk+9, 383 chunk+10)) { 384 printf("FAILED\n"); 385 return CGPT_FAILED; 386 } 387 388 time_low = chunk[0] & 0xffffffff; 389 time_mid = chunk[1] & 0xffff; 390 time_high_and_version = chunk[2] & 0xffff; 391 392 guid->u.Uuid.time_low = htole32(time_low); 393 guid->u.Uuid.time_mid = htole16(time_mid); 394 guid->u.Uuid.time_high_and_version = htole16(time_high_and_version); 395 396 guid->u.Uuid.clock_seq_high_and_reserved = chunk[3] & 0xff; 397 guid->u.Uuid.clock_seq_low = chunk[4] & 0xff; 398 guid->u.Uuid.node[0] = chunk[5] & 0xff; 399 guid->u.Uuid.node[1] = chunk[6] & 0xff; 400 guid->u.Uuid.node[2] = chunk[7] & 0xff; 401 guid->u.Uuid.node[3] = chunk[8] & 0xff; 402 guid->u.Uuid.node[4] = chunk[9] & 0xff; 403 guid->u.Uuid.node[5] = chunk[10] & 0xff; 404 405 return CGPT_OK; 406 } 407 void GuidToStr(const Guid *guid, char *str, unsigned int buflen) { 408 require(buflen >= GUID_STRLEN); 409 require(snprintf(str, buflen, 410 "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", 411 le32toh(guid->u.Uuid.time_low), 412 le16toh(guid->u.Uuid.time_mid), 413 le16toh(guid->u.Uuid.time_high_and_version), 414 guid->u.Uuid.clock_seq_high_and_reserved, 415 guid->u.Uuid.clock_seq_low, 416 guid->u.Uuid.node[0], guid->u.Uuid.node[1], 417 guid->u.Uuid.node[2], guid->u.Uuid.node[3], 418 guid->u.Uuid.node[4], guid->u.Uuid.node[5]) == GUID_STRLEN-1); 419 } 420 421 /* Convert possibly unterminated UTF16 string to UTF8. 422 * Caller must prepare enough space for UTF8, which could be up to 423 * twice the byte length of UTF16 string plus the terminating '\0'. 424 * See the following table for encoding lengths. 425 * 426 * Code point UTF16 UTF8 427 * 0x0000-0x007F 2 bytes 1 byte 428 * 0x0080-0x07FF 2 bytes 2 bytes 429 * 0x0800-0xFFFF 2 bytes 3 bytes 430 * 0x10000-0x10FFFF 4 bytes 4 bytes 431 * 432 * This function uses a simple state meachine to convert UTF-16 char(s) to 433 * a code point. Once a code point is parsed out, the state machine throws 434 * out sequencial UTF-8 chars in one time. 435 * 436 * Return: CGPT_OK --- all character are converted successfully. 437 * CGPT_FAILED --- convert error, i.e. output buffer is too short. 438 */ 439 int UTF16ToUTF8(const uint16_t *utf16, unsigned int maxinput, 440 uint8_t *utf8, unsigned int maxoutput) 441 { 442 size_t s16idx, s8idx; 443 uint32_t code_point = 0; 444 int code_point_ready = 1; // code point is ready to output. 445 int retval = CGPT_OK; 446 447 if (!utf16 || !maxinput || !utf8 || !maxoutput) 448 return CGPT_FAILED; 449 450 maxoutput--; /* plan for termination now */ 451 452 for (s16idx = s8idx = 0; 453 s16idx < maxinput && utf16[s16idx] && maxoutput; 454 s16idx++) { 455 uint16_t codeunit = le16toh(utf16[s16idx]); 456 457 if (code_point_ready) { 458 if (codeunit >= 0xD800 && codeunit <= 0xDBFF) { 459 /* high surrogate, need the low surrogate. */ 460 code_point_ready = 0; 461 code_point = (codeunit & 0x03FF) + 0x0040; 462 } else { 463 /* BMP char, output it. */ 464 code_point = codeunit; 465 } 466 } else { 467 /* expect the low surrogate */ 468 if (codeunit >= 0xDC00 && codeunit <= 0xDFFF) { 469 code_point = (code_point << 10) | (codeunit & 0x03FF); 470 code_point_ready = 1; 471 } else { 472 /* the second code unit is NOT the low surrogate. Unexpected. */ 473 code_point_ready = 0; 474 retval = CGPT_FAILED; 475 break; 476 } 477 } 478 479 /* If UTF code point is ready, output it. */ 480 if (code_point_ready) { 481 require(code_point <= 0x10FFFF); 482 if (code_point <= 0x7F && maxoutput >= 1) { 483 maxoutput -= 1; 484 utf8[s8idx++] = code_point & 0x7F; 485 } else if (code_point <= 0x7FF && maxoutput >= 2) { 486 maxoutput -= 2; 487 utf8[s8idx++] = 0xC0 | (code_point >> 6); 488 utf8[s8idx++] = 0x80 | (code_point & 0x3F); 489 } else if (code_point <= 0xFFFF && maxoutput >= 3) { 490 maxoutput -= 3; 491 utf8[s8idx++] = 0xE0 | (code_point >> 12); 492 utf8[s8idx++] = 0x80 | ((code_point >> 6) & 0x3F); 493 utf8[s8idx++] = 0x80 | (code_point & 0x3F); 494 } else if (code_point <= 0x10FFFF && maxoutput >= 4) { 495 maxoutput -= 4; 496 utf8[s8idx++] = 0xF0 | (code_point >> 18); 497 utf8[s8idx++] = 0x80 | ((code_point >> 12) & 0x3F); 498 utf8[s8idx++] = 0x80 | ((code_point >> 6) & 0x3F); 499 utf8[s8idx++] = 0x80 | (code_point & 0x3F); 500 } else { 501 /* buffer underrun */ 502 retval = CGPT_FAILED; 503 break; 504 } 505 } 506 } 507 utf8[s8idx++] = 0; 508 return retval; 509 } 510 511 /* Convert UTF8 string to UTF16. The UTF8 string must be null-terminated. 512 * Caller must prepare enough space for UTF16, including a terminating 0x0000. 513 * See the following table for encoding lengths. In any case, the caller 514 * just needs to prepare the byte length of UTF8 plus the terminating 0x0000. 515 * 516 * Code point UTF16 UTF8 517 * 0x0000-0x007F 2 bytes 1 byte 518 * 0x0080-0x07FF 2 bytes 2 bytes 519 * 0x0800-0xFFFF 2 bytes 3 bytes 520 * 0x10000-0x10FFFF 4 bytes 4 bytes 521 * 522 * This function converts UTF8 chars to a code point first. Then, convrts it 523 * to UTF16 code unit(s). 524 * 525 * Return: CGPT_OK --- all character are converted successfully. 526 * CGPT_FAILED --- convert error, i.e. output buffer is too short. 527 */ 528 int UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16, unsigned int maxoutput) 529 { 530 size_t s16idx, s8idx; 531 uint32_t code_point = 0; 532 unsigned int expected_units = 1; 533 unsigned int decoded_units = 1; 534 int retval = CGPT_OK; 535 536 if (!utf8 || !utf16 || !maxoutput) 537 return CGPT_FAILED; 538 539 maxoutput--; /* plan for termination */ 540 541 for (s8idx = s16idx = 0; 542 utf8[s8idx] && maxoutput; 543 s8idx++) { 544 uint8_t code_unit; 545 code_unit = utf8[s8idx]; 546 547 if (expected_units != decoded_units) { 548 /* Trailing bytes of multi-byte character */ 549 if ((code_unit & 0xC0) == 0x80) { 550 code_point = (code_point << 6) | (code_unit & 0x3F); 551 ++decoded_units; 552 } else { 553 /* Unexpected code unit. */ 554 retval = CGPT_FAILED; 555 break; 556 } 557 } else { 558 /* parsing a new code point. */ 559 decoded_units = 1; 560 if (code_unit <= 0x7F) { 561 code_point = code_unit; 562 expected_units = 1; 563 } else if (code_unit <= 0xBF) { 564 /* 0x80-0xBF must NOT be the heading byte unit of a new code point. */ 565 retval = CGPT_FAILED; 566 break; 567 } else if (code_unit >= 0xC2 && code_unit <= 0xDF) { 568 code_point = code_unit & 0x1F; 569 expected_units = 2; 570 } else if (code_unit >= 0xE0 && code_unit <= 0xEF) { 571 code_point = code_unit & 0x0F; 572 expected_units = 3; 573 } else if (code_unit >= 0xF0 && code_unit <= 0xF4) { 574 code_point = code_unit & 0x07; 575 expected_units = 4; 576 } else { 577 /* illegal code unit: 0xC0-0xC1, 0xF5-0xFF */ 578 retval = CGPT_FAILED; 579 break; 580 } 581 } 582 583 /* If no more unit is needed, output the UTF16 unit(s). */ 584 if ((retval == CGPT_OK) && 585 (expected_units == decoded_units)) { 586 /* Check if the encoding is the shortest possible UTF-8 sequence. */ 587 switch (expected_units) { 588 case 2: 589 if (code_point <= 0x7F) retval = CGPT_FAILED; 590 break; 591 case 3: 592 if (code_point <= 0x7FF) retval = CGPT_FAILED; 593 break; 594 case 4: 595 if (code_point <= 0xFFFF) retval = CGPT_FAILED; 596 break; 597 } 598 if (retval == CGPT_FAILED) break; /* leave immediately */ 599 600 if ((code_point <= 0xD7FF) || 601 (code_point >= 0xE000 && code_point <= 0xFFFF)) { 602 utf16[s16idx++] = code_point; 603 maxoutput -= 1; 604 } else if (code_point >= 0x10000 && code_point <= 0x10FFFF && 605 maxoutput >= 2) { 606 utf16[s16idx++] = 0xD800 | ((code_point >> 10) - 0x0040); 607 utf16[s16idx++] = 0xDC00 | (code_point & 0x03FF); 608 maxoutput -= 2; 609 } else { 610 /* Three possibilities fall into here. Both are failure cases. 611 * a. surrogate pair (non-BMP characters; 0xD800~0xDFFF) 612 * b. invalid code point > 0x10FFFF 613 * c. buffer underrun 614 */ 615 retval = CGPT_FAILED; 616 break; 617 } 618 } 619 } 620 621 /* A null-terminator shows up before the UTF8 sequence ends. */ 622 if (expected_units != decoded_units) { 623 retval = CGPT_FAILED; 624 } 625 626 utf16[s16idx++] = 0; 627 return retval; 628 } 629 630 /* global types to compare against */ 631 const Guid guid_chromeos_firmware = GPT_ENT_TYPE_CHROMEOS_FIRMWARE; 632 const Guid guid_chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL; 633 const Guid guid_chromeos_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS; 634 const Guid guid_linux_data = GPT_ENT_TYPE_LINUX_DATA; 635 const Guid guid_chromeos_reserved = GPT_ENT_TYPE_CHROMEOS_RESERVED; 636 const Guid guid_efi = GPT_ENT_TYPE_EFI; 637 const Guid guid_unused = GPT_ENT_TYPE_UNUSED; 638 639 const static struct { 640 const Guid *type; 641 char *name; 642 char *description; 643 } supported_types[] = { 644 {&guid_chromeos_firmware, "firmware", "ChromeOS firmware"}, 645 {&guid_chromeos_kernel, "kernel", "ChromeOS kernel"}, 646 {&guid_chromeos_rootfs, "rootfs", "ChromeOS rootfs"}, 647 {&guid_linux_data, "data", "Linux data"}, 648 {&guid_chromeos_reserved, "reserved", "ChromeOS reserved"}, 649 {&guid_efi, "efi", "EFI System Partition"}, 650 {&guid_unused, "unused", "Unused (nonexistent) partition"}, 651 }; 652 653 /* Resolves human-readable GPT type. 654 * Returns CGPT_OK if found. 655 * Returns CGPT_FAILED if no known type found. */ 656 int ResolveType(const Guid *type, char *buf) { 657 int i; 658 for (i = 0; i < ARRAY_COUNT(supported_types); ++i) { 659 if (!memcmp(type, supported_types[i].type, sizeof(Guid))) { 660 strcpy(buf, supported_types[i].description); 661 return CGPT_OK; 662 } 663 } 664 return CGPT_FAILED; 665 } 666 667 int SupportedType(const char *name, Guid *type) { 668 int i; 669 for (i = 0; i < ARRAY_COUNT(supported_types); ++i) { 670 if (!strcmp(name, supported_types[i].name)) { 671 memcpy(type, supported_types[i].type, sizeof(Guid)); 672 return CGPT_OK; 673 } 674 } 675 return CGPT_FAILED; 676 } 677 678 void PrintTypes(void) { 679 int i; 680 printf("The partition type may also be given as one of these aliases:\n\n"); 681 for (i = 0; i < ARRAY_COUNT(supported_types); ++i) { 682 printf(" %-10s %s\n", supported_types[i].name, 683 supported_types[i].description); 684 } 685 printf("\n"); 686 } 687 688 static GptHeader* GetGptHeader(const GptData *gpt) { 689 if (gpt->valid_headers & MASK_PRIMARY) 690 return (GptHeader*)gpt->primary_header; 691 else if (gpt->valid_headers & MASK_SECONDARY) 692 return (GptHeader*)gpt->secondary_header; 693 else 694 return 0; 695 } 696 697 uint32_t GetNumberOfEntries(const struct drive *drive) { 698 GptHeader *header = GetGptHeader(&drive->gpt); 699 if (!header) 700 return 0; 701 return header->number_of_entries; 702 } 703 704 705 GptEntry *GetEntry(GptData *gpt, int secondary, uint32_t entry_index) { 706 GptHeader *header = GetGptHeader(gpt); 707 uint8_t *entries; 708 uint32_t stride = header->size_of_entry; 709 require(stride); 710 require(entry_index < header->number_of_entries); 711 712 if (secondary == PRIMARY) { 713 entries = gpt->primary_entries; 714 } else if (secondary == SECONDARY) { 715 entries = gpt->secondary_entries; 716 } else { /* ANY_VALID */ 717 require(secondary == ANY_VALID); 718 if (gpt->valid_entries & MASK_PRIMARY) { 719 entries = gpt->primary_entries; 720 } else { 721 require(gpt->valid_entries & MASK_SECONDARY); 722 entries = gpt->secondary_entries; 723 } 724 } 725 726 return (GptEntry*)(&entries[stride * entry_index]); 727 } 728 729 void SetPriority(struct drive *drive, int secondary, uint32_t entry_index, 730 int priority) { 731 require(priority >= 0 && priority <= CGPT_ATTRIBUTE_MAX_PRIORITY); 732 GptEntry *entry; 733 entry = GetEntry(&drive->gpt, secondary, entry_index); 734 SetEntryPriority(entry, priority); 735 } 736 737 int GetPriority(struct drive *drive, int secondary, uint32_t entry_index) { 738 GptEntry *entry; 739 entry = GetEntry(&drive->gpt, secondary, entry_index); 740 return GetEntryPriority(entry); 741 } 742 743 void SetTries(struct drive *drive, int secondary, uint32_t entry_index, 744 int tries) { 745 require(tries >= 0 && tries <= CGPT_ATTRIBUTE_MAX_TRIES); 746 GptEntry *entry; 747 entry = GetEntry(&drive->gpt, secondary, entry_index); 748 SetEntryTries(entry, tries); 749 } 750 751 int GetTries(struct drive *drive, int secondary, uint32_t entry_index) { 752 GptEntry *entry; 753 entry = GetEntry(&drive->gpt, secondary, entry_index); 754 return GetEntryTries(entry); 755 } 756 757 void SetSuccessful(struct drive *drive, int secondary, uint32_t entry_index, 758 int success) { 759 require(success >= 0 && success <= CGPT_ATTRIBUTE_MAX_SUCCESSFUL); 760 GptEntry *entry; 761 entry = GetEntry(&drive->gpt, secondary, entry_index); 762 SetEntrySuccessful(entry, success); 763 } 764 765 int GetSuccessful(struct drive *drive, int secondary, uint32_t entry_index) { 766 GptEntry *entry; 767 entry = GetEntry(&drive->gpt, secondary, entry_index); 768 return GetEntrySuccessful(entry); 769 } 770 771 void SetRaw(struct drive *drive, int secondary, uint32_t entry_index, 772 uint32_t raw) { 773 GptEntry *entry; 774 entry = GetEntry(&drive->gpt, secondary, entry_index); 775 entry->attrs.fields.gpt_att = (uint16_t)raw; 776 } 777 778 void UpdateAllEntries(struct drive *drive) { 779 RepairEntries(&drive->gpt, MASK_PRIMARY); 780 RepairHeader(&drive->gpt, MASK_PRIMARY); 781 782 drive->gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 | 783 GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2); 784 UpdateCrc(&drive->gpt); 785 } 786 787 int IsUnused(struct drive *drive, int secondary, uint32_t index) { 788 GptEntry *entry; 789 entry = GetEntry(&drive->gpt, secondary, index); 790 return GuidIsZero(&entry->type); 791 } 792 793 int IsKernel(struct drive *drive, int secondary, uint32_t index) { 794 GptEntry *entry; 795 entry = GetEntry(&drive->gpt, secondary, index); 796 return GuidEqual(&entry->type, &guid_chromeos_kernel); 797 } 798 799 800 #define TOSTRING(A) #A 801 const char *GptError(int errnum) { 802 const char *error_string[] = { 803 TOSTRING(GPT_SUCCESS), 804 TOSTRING(GPT_ERROR_NO_VALID_KERNEL), 805 TOSTRING(GPT_ERROR_INVALID_HEADERS), 806 TOSTRING(GPT_ERROR_INVALID_ENTRIES), 807 TOSTRING(GPT_ERROR_INVALID_SECTOR_SIZE), 808 TOSTRING(GPT_ERROR_INVALID_SECTOR_NUMBER), 809 TOSTRING(GPT_ERROR_INVALID_UPDATE_TYPE) 810 }; 811 if (errnum < 0 || errnum >= ARRAY_COUNT(error_string)) 812 return "<illegal value>"; 813 return error_string[errnum]; 814 } 815 816 /* Update CRC value if necessary. */ 817 void UpdateCrc(GptData *gpt) { 818 GptHeader *primary_header, *secondary_header; 819 820 primary_header = (GptHeader*)gpt->primary_header; 821 secondary_header = (GptHeader*)gpt->secondary_header; 822 823 if (gpt->modified & GPT_MODIFIED_ENTRIES1 && 824 memcmp(primary_header, GPT_HEADER_SIGNATURE2, 825 GPT_HEADER_SIGNATURE_SIZE)) { 826 size_t entries_size = primary_header->size_of_entry * 827 primary_header->number_of_entries; 828 primary_header->entries_crc32 = 829 Crc32(gpt->primary_entries, entries_size); 830 } 831 if (gpt->modified & GPT_MODIFIED_ENTRIES2) { 832 size_t entries_size = secondary_header->size_of_entry * 833 secondary_header->number_of_entries; 834 secondary_header->entries_crc32 = 835 Crc32(gpt->secondary_entries, entries_size); 836 } 837 if (gpt->modified & GPT_MODIFIED_HEADER1) { 838 primary_header->header_crc32 = 0; 839 primary_header->header_crc32 = Crc32( 840 (const uint8_t *)primary_header, sizeof(GptHeader)); 841 } 842 if (gpt->modified & GPT_MODIFIED_HEADER2) { 843 secondary_header->header_crc32 = 0; 844 secondary_header->header_crc32 = Crc32( 845 (const uint8_t *)secondary_header, sizeof(GptHeader)); 846 } 847 } 848 /* Two headers are NOT bitwise identical. For example, my_lba pointers to header 849 * itself so that my_lba in primary and secondary is definitely different. 850 * Only the following fields should be identical. 851 * 852 * first_usable_lba 853 * last_usable_lba 854 * number_of_entries 855 * size_of_entry 856 * disk_uuid 857 * 858 * If any of above field are not matched, overwrite secondary with primary since 859 * we always trust primary. 860 * If any one of header is invalid, copy from another. */ 861 int IsSynonymous(const GptHeader* a, const GptHeader* b) { 862 if ((a->first_usable_lba == b->first_usable_lba) && 863 (a->last_usable_lba == b->last_usable_lba) && 864 (a->number_of_entries == b->number_of_entries) && 865 (a->size_of_entry == b->size_of_entry) && 866 (!memcmp(&a->disk_uuid, &b->disk_uuid, sizeof(Guid)))) 867 return 1; 868 return 0; 869 } 870 871 /* Primary entries and secondary entries should be bitwise identical. 872 * If two entries tables are valid, compare them. If not the same, 873 * overwrites secondary with primary (primary always has higher priority), 874 * and marks secondary as modified. 875 * If only one is valid, overwrites invalid one. 876 * If all are invalid, does nothing. 877 * This function returns bit masks for GptData.modified field. 878 * Note that CRC is NOT re-computed in this function. 879 */ 880 uint8_t RepairEntries(GptData *gpt, const uint32_t valid_entries) { 881 /* If we have an alternate GPT header signature, don't overwrite 882 * the secondary GPT with the primary one as that might wipe the 883 * partition table. Also don't overwrite the primary one with the 884 * secondary one as that will stop Windows from booting. */ 885 GptHeader* h = (GptHeader*)(gpt->primary_header); 886 if (!memcmp(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE)) 887 return 0; 888 889 if (gpt->valid_headers & MASK_PRIMARY) { 890 h = (GptHeader*)gpt->primary_header; 891 } else if (gpt->valid_headers & MASK_SECONDARY) { 892 h = (GptHeader*)gpt->secondary_header; 893 } else { 894 /* We cannot trust any header, don't update entries. */ 895 return 0; 896 } 897 898 size_t entries_size = h->number_of_entries * h->size_of_entry; 899 if (valid_entries == MASK_BOTH) { 900 if (memcmp(gpt->primary_entries, gpt->secondary_entries, entries_size)) { 901 memcpy(gpt->secondary_entries, gpt->primary_entries, entries_size); 902 return GPT_MODIFIED_ENTRIES2; 903 } 904 } else if (valid_entries == MASK_PRIMARY) { 905 memcpy(gpt->secondary_entries, gpt->primary_entries, entries_size); 906 return GPT_MODIFIED_ENTRIES2; 907 } else if (valid_entries == MASK_SECONDARY) { 908 memcpy(gpt->primary_entries, gpt->secondary_entries, entries_size); 909 return GPT_MODIFIED_ENTRIES1; 910 } 911 912 return 0; 913 } 914 915 /* The above five fields are shared between primary and secondary headers. 916 * We can recover one header from another through copying those fields. */ 917 void CopySynonymousParts(GptHeader* target, const GptHeader* source) { 918 target->first_usable_lba = source->first_usable_lba; 919 target->last_usable_lba = source->last_usable_lba; 920 target->number_of_entries = source->number_of_entries; 921 target->size_of_entry = source->size_of_entry; 922 memcpy(&target->disk_uuid, &source->disk_uuid, sizeof(Guid)); 923 } 924 925 /* This function repairs primary and secondary headers if possible. 926 * If both headers are valid (CRC32 is correct) but 927 * a) indicate inconsistent usable LBA ranges, 928 * b) inconsistent partition entry size and number, 929 * c) inconsistent disk_uuid, 930 * we will use the primary header to overwrite secondary header. 931 * If primary is invalid (CRC32 is wrong), then we repair it from secondary. 932 * If secondary is invalid (CRC32 is wrong), then we repair it from primary. 933 * This function returns the bitmasks for modified header. 934 * Note that CRC value is NOT re-computed in this function. UpdateCrc() will 935 * do it later. 936 */ 937 uint8_t RepairHeader(GptData *gpt, const uint32_t valid_headers) { 938 GptHeader *primary_header, *secondary_header; 939 940 primary_header = (GptHeader*)gpt->primary_header; 941 secondary_header = (GptHeader*)gpt->secondary_header; 942 943 if (valid_headers == MASK_BOTH) { 944 if (!IsSynonymous(primary_header, secondary_header)) { 945 CopySynonymousParts(secondary_header, primary_header); 946 return GPT_MODIFIED_HEADER2; 947 } 948 } else if (valid_headers == MASK_PRIMARY) { 949 memcpy(secondary_header, primary_header, sizeof(GptHeader)); 950 secondary_header->my_lba = gpt->gpt_drive_sectors - 1; /* the last sector */ 951 secondary_header->alternate_lba = primary_header->my_lba; 952 secondary_header->entries_lba = secondary_header->my_lba - 953 CalculateEntriesSectors(primary_header); 954 return GPT_MODIFIED_HEADER2; 955 } else if (valid_headers == MASK_SECONDARY) { 956 memcpy(primary_header, secondary_header, sizeof(GptHeader)); 957 primary_header->my_lba = GPT_PMBR_SECTORS; /* the second sector on drive */ 958 primary_header->alternate_lba = secondary_header->my_lba; 959 /* TODO (namnguyen): Preserve (header, entries) padding space. */ 960 primary_header->entries_lba = primary_header->my_lba + GPT_HEADER_SECTORS; 961 return GPT_MODIFIED_HEADER1; 962 } 963 964 return 0; 965 } 966 967 int CgptGetNumNonEmptyPartitions(CgptShowParams *params) { 968 struct drive drive; 969 int gpt_retval; 970 int retval; 971 972 if (params == NULL) 973 return CGPT_FAILED; 974 975 if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDONLY, 976 params->drive_size)) 977 return CGPT_FAILED; 978 979 if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) { 980 Error("GptSanityCheck() returned %d: %s\n", 981 gpt_retval, GptError(gpt_retval)); 982 retval = CGPT_FAILED; 983 goto done; 984 } 985 986 params->num_partitions = 0; 987 int numEntries = GetNumberOfEntries(&drive); 988 int i; 989 for(i = 0; i < numEntries; i++) { 990 GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, i); 991 if (GuidIsZero(&entry->type)) 992 continue; 993 994 params->num_partitions++; 995 } 996 997 retval = CGPT_OK; 998 999 done: 1000 DriveClose(&drive, 0); 1001 return retval; 1002 } 1003 1004 int GuidEqual(const Guid *guid1, const Guid *guid2) { 1005 return (0 == memcmp(guid1, guid2, sizeof(Guid))); 1006 } 1007 1008 int GuidIsZero(const Guid *gp) { 1009 return GuidEqual(gp, &guid_unused); 1010 } 1011 1012 void PMBRToStr(struct pmbr *pmbr, char *str, unsigned int buflen) { 1013 char buf[GUID_STRLEN]; 1014 if (GuidIsZero(&pmbr->boot_guid)) { 1015 require(snprintf(str, buflen, "PMBR") < buflen); 1016 } else { 1017 GuidToStr(&pmbr->boot_guid, buf, sizeof(buf)); 1018 require(snprintf(str, buflen, "PMBR (Boot GUID: %s)", buf) < buflen); 1019 } 1020 } 1021 1022 /* Optional */ 1023 int __GenerateGuid(Guid *newguid) { return CGPT_FAILED; }; 1024 #ifndef HAVE_MACOS 1025 int GenerateGuid(Guid *newguid) __attribute__((weak, alias("__GenerateGuid"))); 1026 #endif 1027