1 /* $OpenBSD: gpt.c,v 1.83 2022/09/15 15:05:58 krw Exp $ */ 2 /* 3 * Copyright (c) 2015 Markus Muller <mmu@grummel.net> 4 * Copyright (c) 2015 Kenneth R Westerback <krw@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> /* DEV_BSIZE */ 20 #include <sys/disklabel.h> 21 #include <sys/dkio.h> 22 #include <sys/ioctl.h> 23 24 #include <ctype.h> 25 #include <err.h> 26 #include <stdio.h> 27 #include <stdint.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <uuid.h> 31 32 #include "part.h" 33 #include "disk.h" 34 #include "mbr.h" 35 #include "misc.h" 36 #include "gpt.h" 37 38 #ifdef DEBUG 39 #define DPRINTF(x...) printf(x) 40 #else 41 #define DPRINTF(x...) 42 #endif 43 44 struct mbr gmbr; 45 struct gpt_header gh; 46 struct gpt_partition gp[NGPTPARTITIONS]; 47 48 struct gpt_partition **sort_gpt(void); 49 int lba_start_cmp(const void *e1, const void *e2); 50 int lba_free(uint64_t *, uint64_t *); 51 int add_partition(const uint8_t *, const char *, uint64_t); 52 int find_partition(const uint8_t *); 53 int get_header(const uint64_t); 54 int get_partition_table(void); 55 int init_gh(void); 56 int init_gp(const int); 57 uint32_t crc32(const u_char *, const uint32_t); 58 int protective_mbr(const struct mbr *); 59 int gpt_chk_mbr(struct dos_partition *, uint64_t); 60 void string_to_name(const unsigned int, const char *); 61 const char *name_to_string(const unsigned int); 62 63 void 64 string_to_name(const unsigned int pn, const char *ch) 65 { 66 unsigned int i; 67 68 memset(gp[pn].gp_name, 0, sizeof(gp[pn].gp_name)); 69 70 for (i = 0; i < sizeof(gp[pn].gp_name) && ch[i] != '\0'; i++) 71 gp[pn].gp_name[i] = htole16((unsigned int)ch[i]); 72 } 73 74 const char * 75 name_to_string(const unsigned int pn) 76 { 77 static char name[GPTPARTNAMESIZE + 1]; 78 unsigned int i; 79 80 memset(name, 0, sizeof(name)); 81 82 for (i = 0; i < sizeof(name) && gp[pn].gp_name[i] != 0; i++) 83 name[i] = letoh16(gp[pn].gp_name[i]) & 0x7F; 84 85 return name; 86 } 87 88 /* 89 * Return the index into dp[] of the EFI GPT (0xEE) partition, or -1 if no such 90 * partition exists. 91 * 92 * Taken from kern/subr_disk.c. 93 * 94 */ 95 int 96 gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize) 97 { 98 struct dos_partition *dp2; 99 int efi, eficnt, found, i; 100 uint32_t psize; 101 102 found = efi = eficnt = 0; 103 for (dp2 = dp, i = 0; i < NDOSPART; i++, dp2++) { 104 if (dp2->dp_typ == DOSPTYP_UNUSED) 105 continue; 106 found++; 107 if (dp2->dp_typ != DOSPTYP_EFI) 108 continue; 109 if (letoh32(dp2->dp_start) != GPTSECTOR) 110 continue; 111 psize = letoh32(dp2->dp_size); 112 if (psize <= (dsize - GPTSECTOR) || psize == UINT32_MAX) { 113 efi = i; 114 eficnt++; 115 } 116 } 117 if (found == 1 && eficnt == 1) 118 return efi; 119 120 return -1; 121 } 122 123 int 124 protective_mbr(const struct mbr *mbr) 125 { 126 struct dos_partition dp[NDOSPART], dos_partition; 127 int i; 128 129 if (mbr->mbr_lba_self != 0) 130 return -1; 131 132 for (i = 0; i < NDOSPART; i++) { 133 PRT_make(&mbr->mbr_prt[i], mbr->mbr_lba_self, 134 mbr->mbr_lba_firstembr, &dos_partition); 135 memcpy(&dp[i], &dos_partition, sizeof(dp[i])); 136 } 137 138 return gpt_chk_mbr(dp, DL_GETDSIZE(&dl)); 139 } 140 141 int 142 get_header(const uint64_t sector) 143 { 144 struct gpt_header legh; 145 uint64_t gpbytes, gpsectors, lba_end; 146 147 if (DISK_readbytes(&legh, sector, sizeof(legh))) 148 return -1; 149 150 gh.gh_sig = letoh64(legh.gh_sig); 151 if (gh.gh_sig != GPTSIGNATURE) { 152 DPRINTF("gpt signature: expected 0x%llx, got 0x%llx\n", 153 GPTSIGNATURE, gh.gh_sig); 154 return -1; 155 } 156 157 gh.gh_rev = letoh32(legh.gh_rev); 158 if (gh.gh_rev != GPTREVISION) { 159 DPRINTF("gpt revision: expected 0x%x, got 0x%x\n", 160 GPTREVISION, gh.gh_rev); 161 return -1; 162 } 163 164 gh.gh_lba_self = letoh64(legh.gh_lba_self); 165 if (gh.gh_lba_self != sector) { 166 DPRINTF("gpt self lba: expected %llu, got %llu\n", 167 sector, gh.gh_lba_self); 168 return -1; 169 } 170 171 gh.gh_size = letoh32(legh.gh_size); 172 if (gh.gh_size != GPTMINHDRSIZE) { 173 DPRINTF("gpt header size: expected %u, got %u\n", 174 GPTMINHDRSIZE, gh.gh_size); 175 return -1; 176 } 177 178 gh.gh_part_size = letoh32(legh.gh_part_size); 179 if (gh.gh_part_size != GPTMINPARTSIZE) { 180 DPRINTF("gpt partition size: expected %u, got %u\n", 181 GPTMINPARTSIZE, gh.gh_part_size); 182 return -1; 183 } 184 185 if ((dl.d_secsize % gh.gh_part_size) != 0) { 186 DPRINTF("gpt sector size %% partition size (%u %% %u) != 0\n", 187 dl.d_secsize, gh.gh_part_size); 188 return -1; 189 } 190 191 gh.gh_part_num = letoh32(legh.gh_part_num); 192 if (gh.gh_part_num > NGPTPARTITIONS) { 193 DPRINTF("gpt partition count: expected <= %u, got %u\n", 194 NGPTPARTITIONS, gh.gh_part_num); 195 return -1; 196 } 197 198 gh.gh_csum = letoh32(legh.gh_csum); 199 legh.gh_csum = 0; 200 legh.gh_csum = crc32((unsigned char *)&legh, gh.gh_size); 201 if (legh.gh_csum != gh.gh_csum) { 202 DPRINTF("gpt header checksum: expected 0x%x, got 0x%x\n", 203 legh.gh_csum, gh.gh_csum); 204 /* Accept wrong-endian checksum. */ 205 if (swap32(legh.gh_csum) != gh.gh_csum) 206 return -1; 207 } 208 209 gpbytes = gh.gh_part_num * gh.gh_part_size; 210 gpsectors = (gpbytes + dl.d_secsize - 1) / dl.d_secsize; 211 lba_end = DL_GETDSIZE(&dl) - gpsectors - 2; 212 213 gh.gh_lba_end = letoh64(legh.gh_lba_end); 214 if (gh.gh_lba_end > lba_end) { 215 DPRINTF("gpt last usable LBA: reduced from %llu to %llu\n", 216 gh.gh_lba_end, lba_end); 217 gh.gh_lba_end = lba_end; 218 } 219 220 gh.gh_lba_start = letoh64(legh.gh_lba_start); 221 if (gh.gh_lba_start >= gh.gh_lba_end) { 222 DPRINTF("gpt first usable LBA: expected < %llu, got %llu\n", 223 gh.gh_lba_end, gh.gh_lba_start); 224 return -1; 225 } 226 227 gh.gh_part_lba = letoh64(legh.gh_part_lba); 228 if (gh.gh_lba_self == GPTSECTOR) { 229 if (gh.gh_part_lba <= GPTSECTOR) { 230 DPRINTF("gpt partition entries start: expected > %u, " 231 "got %llu\n", GPTSECTOR, gh.gh_part_lba); 232 return -1; 233 } 234 if (gh.gh_part_lba + gpsectors > gh.gh_lba_start) { 235 DPRINTF("gpt partition entries end: expected < %llu, " 236 "got %llu\n", gh.gh_lba_start, 237 gh.gh_part_lba + gpsectors); 238 return -1; 239 } 240 } else { 241 if (gh.gh_part_lba <= gh.gh_lba_end) { 242 DPRINTF("gpt partition entries start: expected > %llu, " 243 "got %llu\n", gh.gh_lba_end, gh.gh_part_lba); 244 return -1; 245 } 246 if (gh.gh_part_lba + gpsectors > gh.gh_lba_self) { 247 DPRINTF("gpt partition entries end: expected < %llu, " 248 "got %llu\n", gh.gh_lba_self, 249 gh.gh_part_lba + gpsectors); 250 return -1; 251 } 252 } 253 254 gh.gh_lba_alt = letoh32(legh.gh_lba_alt); 255 gh.gh_part_csum = letoh32(legh.gh_part_csum); 256 gh.gh_rsvd = letoh32(legh.gh_rsvd); /* Should always be 0. */ 257 uuid_dec_le(&legh.gh_guid, &gh.gh_guid); 258 259 return 0; 260 } 261 262 int 263 get_partition_table(void) 264 { 265 struct gpt_partition *legp; 266 uint64_t gpbytes; 267 unsigned int pn; 268 int rslt = -1; 269 uint32_t gh_part_csum; 270 271 DPRINTF("gpt partition table being read from LBA %llu\n", 272 gh.gh_part_lba); 273 274 gpbytes = gh.gh_part_num * gh.gh_part_size; 275 276 legp = calloc(1, gpbytes); 277 if (legp == NULL) 278 err(1, "legp"); 279 280 if (DISK_readbytes(legp, gh.gh_part_lba, gpbytes)) 281 goto done; 282 gh_part_csum = crc32((unsigned char *)legp, gpbytes); 283 284 if (gh_part_csum != gh.gh_part_csum) { 285 DPRINTF("gpt partition table checksum: expected 0x%x, " 286 "got 0x%x\n", gh.gh_part_csum, gh_part_csum); 287 /* Accept wrong-endian checksum. */ 288 if (swap32(gh_part_csum) != gh.gh_part_csum) 289 goto done; 290 } 291 292 memset(&gp, 0, sizeof(gp)); 293 for (pn = 0; pn < gh.gh_part_num; pn++) { 294 uuid_dec_le(&legp[pn].gp_type, &gp[pn].gp_type); 295 uuid_dec_le(&legp[pn].gp_guid, &gp[pn].gp_guid); 296 gp[pn].gp_lba_start = letoh64(legp[pn].gp_lba_start); 297 gp[pn].gp_lba_end = letoh64(legp[pn].gp_lba_end); 298 gp[pn].gp_attrs = letoh64(legp[pn].gp_attrs); 299 memcpy(gp[pn].gp_name, legp[pn].gp_name, 300 sizeof(gp[pn].gp_name)); 301 } 302 rslt = 0; 303 304 done: 305 free(legp); 306 return rslt; 307 } 308 309 int 310 GPT_read(const int which) 311 { 312 int error; 313 314 error = MBR_read(0, 0, &gmbr); 315 if (error) 316 goto done; 317 error = protective_mbr(&gmbr); 318 if (error == -1) 319 goto done; 320 321 switch (which) { 322 case PRIMARYGPT: 323 error = get_header(GPTSECTOR); 324 break; 325 case SECONDARYGPT: 326 error = get_header(DL_GETDSIZE(&dl) - 1); 327 break; 328 case ANYGPT: 329 error = get_header(GPTSECTOR); 330 if (error != 0 || get_partition_table() != 0) 331 error = get_header(DL_GETDSIZE(&dl) - 1); 332 break; 333 default: 334 return -1; 335 } 336 337 if (error == 0) 338 error = get_partition_table(); 339 340 done: 341 if (error != 0) { 342 /* No valid GPT found. Zap any artifacts. */ 343 memset(&gmbr, 0, sizeof(gmbr)); 344 memset(&gh, 0, sizeof(gh)); 345 memset(&gp, 0, sizeof(gp)); 346 } 347 348 return error; 349 } 350 351 void 352 GPT_print(const char *units, const int verbosity) 353 { 354 const struct unit_type *ut; 355 const int secsize = dl.d_secsize; 356 char *guidstr = NULL; 357 double size; 358 unsigned int pn; 359 uint32_t status; 360 361 #ifdef DEBUG 362 char *p; 363 uint64_t sig; 364 unsigned int i; 365 366 sig = htole64(gh.gh_sig); 367 p = (char *)&sig; 368 369 printf("gh_sig : "); 370 for (i = 0; i < sizeof(sig); i++) 371 printf("%c", isprint((unsigned char)p[i]) ? p[i] : '?'); 372 printf(" ("); 373 for (i = 0; i < sizeof(sig); i++) { 374 printf("%02x", p[i]); 375 if ((i + 1) < sizeof(sig)) 376 printf(":"); 377 } 378 printf(")\n"); 379 printf("gh_rev : %u\n", gh.gh_rev); 380 printf("gh_size : %u (%zd)\n", gh.gh_size, sizeof(gh)); 381 printf("gh_csum : 0x%x\n", gh.gh_csum); 382 printf("gh_rsvd : %u\n", gh.gh_rsvd); 383 printf("gh_lba_self : %llu\n", gh.gh_lba_self); 384 printf("gh_lba_alt : %llu\n", gh.gh_lba_alt); 385 printf("gh_lba_start : %llu\n", gh.gh_lba_start); 386 printf("gh_lba_end : %llu\n", gh.gh_lba_end); 387 p = NULL; 388 uuid_to_string(&gh.gh_guid, &p, &status); 389 printf("gh_gh_guid : %s\n", (status == uuid_s_ok) ? p : "<invalid>"); 390 free(p); 391 printf("gh_gh_part_lba : %llu\n", gh.gh_part_lba); 392 printf("gh_gh_part_num : %u (%zu)\n", gh.gh_part_num, nitems(gp)); 393 printf("gh_gh_part_size: %u (%zu)\n", gh.gh_part_size, sizeof(gp[0])); 394 printf("gh_gh_part_csum: 0x%x\n", gh.gh_part_csum); 395 printf("\n"); 396 #endif /* DEBUG */ 397 398 size = units_size(units, DL_GETDSIZE(&dl), &ut); 399 printf("Disk: %s Usable LBA: %llu to %llu [%.0f ", 400 disk.dk_name, gh.gh_lba_start, gh.gh_lba_end, size); 401 if (ut->ut_conversion == 0 && secsize != DEV_BSIZE) 402 printf("%d-byte ", secsize); 403 printf("%s]\n", ut->ut_lname); 404 405 if (verbosity == VERBOSE) { 406 printf("GUID: "); 407 uuid_to_string(&gh.gh_guid, &guidstr, &status); 408 if (status == uuid_s_ok) 409 printf("%s\n", guidstr); 410 else 411 printf("<invalid header GUID>\n"); 412 free(guidstr); 413 } 414 415 GPT_print_parthdr(verbosity); 416 for (pn = 0; pn < gh.gh_part_num; pn++) { 417 if (uuid_is_nil(&gp[pn].gp_type, NULL)) 418 continue; 419 GPT_print_part(pn, units, verbosity); 420 } 421 } 422 423 void 424 GPT_print_parthdr(const int verbosity) 425 { 426 printf(" #: type " 427 " [ start: size ]\n"); 428 if (verbosity == VERBOSE) 429 printf(" guid name\n"); 430 printf("--------------------------------------------------------" 431 "----------------\n"); 432 } 433 434 void 435 GPT_print_part(const unsigned int pn, const char *units, const int verbosity) 436 { 437 const uint8_t gpt_uuid_msdos[] = GPT_UUID_MSDOS; 438 const struct unit_type *ut; 439 struct uuid uuid; 440 char *guidstr = NULL; 441 double size; 442 uint64_t attrs, end, start; 443 uint32_t status; 444 445 start = gp[pn].gp_lba_start; 446 end = gp[pn].gp_lba_end; 447 size = units_size(units, (start > end) ? 0 : end - start + 1, &ut); 448 449 printf(" %3u: %-36s [%12lld: %12.0f%s]\n", pn, 450 PRT_uuid_to_sname(&gp[pn].gp_type), start, size, ut->ut_abbr); 451 452 if (verbosity == VERBOSE) { 453 uuid_to_string(&gp[pn].gp_guid, &guidstr, &status); 454 if (status != uuid_s_ok) 455 printf(" <invalid partition guid> "); 456 else 457 printf(" %-36s ", guidstr); 458 printf("%-36s\n", name_to_string(pn)); 459 free(guidstr); 460 attrs = gp[pn].gp_attrs; 461 if (attrs) { 462 printf(" Attributes: (0x%016llx) ", attrs); 463 if (attrs & GPTPARTATTR_REQUIRED) 464 printf("Required " ); 465 if (attrs & GPTPARTATTR_IGNORE) 466 printf("Ignore "); 467 if (attrs & GPTPARTATTR_BOOTABLE) 468 printf("Bootable "); 469 uuid_dec_be(gpt_uuid_msdos, &uuid); 470 if (uuid_compare(&uuid, &gp[pn].gp_type, NULL) == 0) { 471 if (attrs & GPTPARTATTR_MS_READONLY) 472 printf("ReadOnly " ); 473 if (attrs & GPTPARTATTR_MS_SHADOW) 474 printf("Shadow "); 475 if (attrs & GPTPARTATTR_MS_HIDDEN) 476 printf("Hidden "); 477 if (attrs & GPTPARTATTR_MS_NOAUTOMOUNT) 478 printf("NoAutoMount "); 479 } 480 printf("\n"); 481 } 482 } 483 484 if (start > end) 485 printf("partition %u first LBA is > last LBA\n", pn); 486 if (start < gh.gh_lba_start || end > gh.gh_lba_end) 487 printf("partition %u extends beyond usable LBA range of %s\n", 488 pn, disk.dk_name); 489 } 490 491 int 492 find_partition(const uint8_t *beuuid) 493 { 494 struct uuid uuid; 495 unsigned int pn; 496 497 uuid_dec_be(beuuid, &uuid); 498 499 for (pn = 0; pn < gh.gh_part_num; pn++) { 500 if (uuid_compare(&gp[pn].gp_type, &uuid, NULL) == 0) 501 return pn; 502 } 503 return -1; 504 } 505 506 int 507 add_partition(const uint8_t *beuuid, const char *name, uint64_t sectors) 508 { 509 struct uuid uuid; 510 int rslt; 511 uint64_t end, freesectors, start; 512 uint32_t status, pn; 513 514 uuid_dec_be(beuuid, &uuid); 515 516 for (pn = 0; pn < gh.gh_part_num; pn++) { 517 if (uuid_is_nil(&gp[pn].gp_type, NULL)) 518 break; 519 } 520 if (pn == gh.gh_part_num) 521 goto done; 522 523 rslt = lba_free(&start, &end); 524 if (rslt == -1) 525 goto done; 526 527 if (start % BLOCKALIGNMENT) 528 start += (BLOCKALIGNMENT - start % BLOCKALIGNMENT); 529 if (start >= end) 530 goto done; 531 532 freesectors = end - start + 1; 533 534 if (sectors == 0) 535 sectors = freesectors; 536 537 if (freesectors < sectors) 538 goto done; 539 else if (freesectors > sectors) 540 end = start + sectors - 1; 541 542 gp[pn].gp_type = uuid; 543 gp[pn].gp_lba_start = start; 544 gp[pn].gp_lba_end = end; 545 string_to_name(pn, name); 546 547 uuid_create(&gp[pn].gp_guid, &status); 548 if (status == uuid_s_ok) 549 return 0; 550 551 done: 552 if (pn != gh.gh_part_num) 553 memset(&gp[pn], 0, sizeof(gp[pn])); 554 printf("unable to add %s\n", name); 555 return -1; 556 } 557 558 int 559 init_gh(void) 560 { 561 struct gpt_header oldgh; 562 const int secsize = dl.d_secsize; 563 int needed; 564 uint32_t status; 565 566 memcpy(&oldgh, &gh, sizeof(oldgh)); 567 memset(&gh, 0, sizeof(gh)); 568 memset(&gmbr, 0, sizeof(gmbr)); 569 570 /* XXX Do we need the boot code? UEFI spec & Apple says no. */ 571 memcpy(gmbr.mbr_code, default_dmbr.dmbr_boot, sizeof(gmbr.mbr_code)); 572 gmbr.mbr_prt[0].prt_id = DOSPTYP_EFI; 573 gmbr.mbr_prt[0].prt_bs = 1; 574 gmbr.mbr_prt[0].prt_ns = UINT32_MAX; 575 gmbr.mbr_signature = DOSMBR_SIGNATURE; 576 577 needed = sizeof(gp) / secsize + 2; 578 579 if (needed % BLOCKALIGNMENT) 580 needed += (needed - (needed % BLOCKALIGNMENT)); 581 582 gh.gh_sig = GPTSIGNATURE; 583 gh.gh_rev = GPTREVISION; 584 gh.gh_size = GPTMINHDRSIZE; 585 gh.gh_csum = 0; 586 gh.gh_rsvd = 0; 587 gh.gh_lba_self = 1; 588 gh.gh_lba_alt = DL_GETDSIZE(&dl) - 1; 589 gh.gh_lba_start = needed; 590 gh.gh_lba_end = DL_GETDSIZE(&dl) - needed; 591 uuid_create(&gh.gh_guid, &status); 592 if (status != uuid_s_ok) { 593 memcpy(&gh, &oldgh, sizeof(gh)); 594 return -1; 595 } 596 gh.gh_part_lba = 2; 597 gh.gh_part_num = NGPTPARTITIONS; 598 gh.gh_part_size = GPTMINPARTSIZE; 599 gh.gh_part_csum = 0; 600 601 return 0; 602 } 603 604 int 605 init_gp(const int how) 606 { 607 struct gpt_partition oldgp[NGPTPARTITIONS]; 608 const uint8_t gpt_uuid_efi_system[] = GPT_UUID_EFI_SYSTEM; 609 const uint8_t gpt_uuid_openbsd[] = GPT_UUID_OPENBSD; 610 uint64_t prt_ns; 611 int pn, rslt; 612 613 memcpy(&oldgp, &gp, sizeof(oldgp)); 614 if (how == GHANDGP) 615 memset(&gp, 0, sizeof(gp)); 616 else { 617 for (pn = 0; pn < gh.gh_part_num; pn++) { 618 if (PRT_protected_guid(&gp[pn].gp_type) || 619 (gp[pn].gp_attrs & GPTPARTATTR_REQUIRED)) 620 continue; 621 memset(&gp[pn], 0, sizeof(gp[pn])); 622 } 623 } 624 625 rslt = 0; 626 if (disk.dk_bootprt.prt_ns > 0) { 627 pn = find_partition(gpt_uuid_efi_system); 628 if (pn == -1) { 629 rslt = add_partition(gpt_uuid_efi_system, 630 "EFI System Area", disk.dk_bootprt.prt_ns); 631 } else { 632 prt_ns = gp[pn].gp_lba_end - gp[pn].gp_lba_start + 1; 633 if (prt_ns < disk.dk_bootprt.prt_ns) { 634 printf("EFI System Area < %llu sectors\n", 635 disk.dk_bootprt.prt_ns); 636 rslt = -1; 637 } 638 } 639 } 640 if (rslt == 0) 641 rslt = add_partition(gpt_uuid_openbsd, "OpenBSD Area", 0); 642 643 if (rslt != 0) 644 memcpy(&gp, &oldgp, sizeof(gp)); 645 646 return rslt; 647 } 648 649 int 650 GPT_init(const int how) 651 { 652 int rslt = 0; 653 654 if (how == GHANDGP) 655 rslt = init_gh(); 656 if (rslt == 0) 657 rslt = init_gp(how); 658 659 return rslt; 660 } 661 662 void 663 GPT_zap_headers(void) 664 { 665 struct gpt_header legh; 666 667 if (DISK_readbytes(&legh, GPTSECTOR, sizeof(legh))) 668 return; 669 670 if (letoh64(legh.gh_sig) == GPTSIGNATURE) { 671 memset(&legh, 0, sizeof(legh)); 672 if (DISK_writebytes(&legh, GPTSECTOR, sizeof(legh))) 673 DPRINTF("Unable to zap GPT header @ sector %d", 674 GPTSECTOR); 675 } 676 677 if (DISK_readbytes(&legh, DL_GETDSIZE(&dl) - 1, sizeof(legh))) 678 return; 679 680 if (letoh64(legh.gh_sig) == GPTSIGNATURE) { 681 memset(&legh, 0, GPTMINHDRSIZE); 682 if (DISK_writebytes(&legh, DL_GETDSIZE(&dl) - 1, sizeof(legh))) 683 DPRINTF("Unable to zap GPT header @ sector %llu", 684 DL_GETDSIZE(&dl) - 1); 685 } 686 } 687 688 int 689 GPT_write(void) 690 { 691 struct gpt_header legh; 692 struct gpt_partition *legp; 693 uint64_t altgh, altgp; 694 uint64_t gpbytes, gpsectors; 695 unsigned int pn; 696 int rslt = -1; 697 698 if (MBR_write(&gmbr)) 699 return -1; 700 701 gpbytes = gh.gh_part_num * gh.gh_part_size; 702 gpsectors = (gpbytes + dl.d_secsize - 1) / dl.d_secsize; 703 704 altgh = DL_GETDSIZE(&dl) - 1; 705 altgp = altgh - gpsectors; 706 707 legh.gh_sig = htole64(GPTSIGNATURE); 708 legh.gh_rev = htole32(GPTREVISION); 709 legh.gh_size = htole32(GPTMINHDRSIZE); 710 legh.gh_rsvd = 0; 711 legh.gh_lba_self = htole64(GPTSECTOR); 712 legh.gh_lba_alt = htole64(altgh); 713 legh.gh_lba_start = htole64(gh.gh_lba_start); 714 legh.gh_lba_end = htole64(gh.gh_lba_end); 715 uuid_enc_le(&legh.gh_guid, &gh.gh_guid); 716 legh.gh_part_lba = htole64(GPTSECTOR + 1); 717 legh.gh_part_num = htole32(gh.gh_part_num); 718 legh.gh_part_size = htole32(GPTMINPARTSIZE); 719 720 legp = calloc(1, gpbytes); 721 if (legp == NULL) 722 err(1, "legp"); 723 724 for (pn = 0; pn < gh.gh_part_num; pn++) { 725 uuid_enc_le(&legp[pn].gp_type, &gp[pn].gp_type); 726 uuid_enc_le(&legp[pn].gp_guid, &gp[pn].gp_guid); 727 legp[pn].gp_lba_start = htole64(gp[pn].gp_lba_start); 728 legp[pn].gp_lba_end = htole64(gp[pn].gp_lba_end); 729 legp[pn].gp_attrs = htole64(gp[pn].gp_attrs); 730 memcpy(legp[pn].gp_name, gp[pn].gp_name, 731 sizeof(legp[pn].gp_name)); 732 } 733 legh.gh_part_csum = htole32(crc32((unsigned char *)legp, gpbytes)); 734 legh.gh_csum = 0; 735 legh.gh_csum = htole32(crc32((unsigned char *)&legh, gh.gh_size)); 736 737 if (DISK_writebytes(&legh, GPTSECTOR, gh.gh_size) || 738 DISK_writebytes(legp, GPTSECTOR + 1, gpbytes)) 739 goto done; 740 741 legh.gh_lba_self = htole64(altgh); 742 legh.gh_lba_alt = htole64(GPTSECTOR); 743 legh.gh_part_lba = htole64(altgp); 744 legh.gh_csum = 0; 745 legh.gh_csum = htole32(crc32((unsigned char *)&legh, gh.gh_size)); 746 747 if (DISK_writebytes(&legh, altgh, gh.gh_size) || 748 DISK_writebytes(&gp, altgp, gpbytes)) 749 goto done; 750 751 /* Refresh in-kernel disklabel from the updated disk information. */ 752 if (ioctl(disk.dk_fd, DIOCRLDINFO, 0) == -1) 753 warn("DIOCRLDINFO"); 754 rslt = 0; 755 756 done: 757 free(legp); 758 return rslt; 759 } 760 761 int 762 gp_lba_start_cmp(const void *e1, const void *e2) 763 { 764 struct gpt_partition *p1 = *(struct gpt_partition **)e1; 765 struct gpt_partition *p2 = *(struct gpt_partition **)e2; 766 uint64_t o1; 767 uint64_t o2; 768 769 o1 = p1->gp_lba_start; 770 o2 = p2->gp_lba_start; 771 772 if (o1 < o2) 773 return -1; 774 else if (o1 > o2) 775 return 1; 776 else 777 return 0; 778 } 779 780 struct gpt_partition ** 781 sort_gpt(void) 782 { 783 static struct gpt_partition *sgp[NGPTPARTITIONS+2]; 784 unsigned int i, pn; 785 786 memset(sgp, 0, sizeof(sgp)); 787 788 i = 0; 789 for (pn = 0; pn < gh.gh_part_num; pn++) { 790 if (gp[pn].gp_lba_start >= gh.gh_lba_start) 791 sgp[i++] = &gp[pn]; 792 } 793 794 if (i > 1) { 795 if (mergesort(sgp, i, sizeof(sgp[0]), gp_lba_start_cmp) == -1) { 796 printf("unable to sort gpt by lba start\n"); 797 return NULL; 798 } 799 } 800 801 return sgp; 802 } 803 804 int 805 lba_free(uint64_t *start, uint64_t *end) 806 { 807 struct gpt_partition **sgp; 808 uint64_t bs, bigbs, nextbs, ns; 809 unsigned int i; 810 811 sgp = sort_gpt(); 812 if (sgp == NULL) 813 return -1; 814 815 bs = gh.gh_lba_start; 816 ns = gh.gh_lba_end - bs + 1; 817 818 if (sgp[0] != NULL) { 819 bigbs = bs; 820 ns = 0; 821 for (i = 0; sgp[i] != NULL; i++) { 822 nextbs = sgp[i]->gp_lba_start; 823 if (bs < nextbs && ns < nextbs - bs) { 824 ns = nextbs - bs; 825 bigbs = bs; 826 } 827 bs = sgp[i]->gp_lba_end + 1; 828 } 829 nextbs = gh.gh_lba_end + 1; 830 if (bs < nextbs && ns < nextbs - bs) { 831 ns = nextbs - bs; 832 bigbs = bs; 833 } 834 bs = bigbs; 835 } 836 837 if (ns == 0) 838 return -1; 839 840 if (start != NULL) 841 *start = bs; 842 if (end != NULL) 843 *end = bs + ns - 1; 844 845 return 0; 846 } 847 848 int 849 GPT_get_lba_start(const unsigned int pn) 850 { 851 uint64_t bs; 852 unsigned int i; 853 int rslt; 854 855 bs = gh.gh_lba_start; 856 857 if (gp[pn].gp_lba_start >= bs) { 858 bs = gp[pn].gp_lba_start; 859 } else { 860 rslt = lba_free(&bs, NULL); 861 if (rslt == -1) { 862 printf("no space for partition %u\n", pn); 863 return -1; 864 } 865 } 866 867 bs = getuint64("Partition offset", bs, gh.gh_lba_start, gh.gh_lba_end); 868 for (i = 0; i < gh.gh_part_num; i++) { 869 if (i == pn) 870 continue; 871 if (bs >= gp[i].gp_lba_start && bs <= gp[i].gp_lba_end) { 872 printf("partition %u can't start inside partition %u\n", 873 pn, i); 874 return -1; 875 } 876 } 877 878 gp[pn].gp_lba_start = bs; 879 880 return 0; 881 } 882 883 int 884 GPT_get_lba_end(const unsigned int pn) 885 { 886 struct gpt_partition **sgp; 887 uint64_t bs, nextbs, ns; 888 unsigned int i; 889 890 sgp = sort_gpt(); 891 if (sgp == NULL) 892 return -1; 893 894 bs = gp[pn].gp_lba_start; 895 ns = gh.gh_lba_end - bs + 1; 896 for (i = 0; sgp[i] != NULL; i++) { 897 nextbs = sgp[i]->gp_lba_start; 898 if (nextbs > bs) { 899 ns = nextbs - bs; 900 break; 901 } 902 } 903 ns = getuint64("Partition size", ns, 1, ns); 904 905 gp[pn].gp_lba_end = bs + ns - 1; 906 907 return 0; 908 } 909 910 int 911 GPT_get_name(const unsigned int pn) 912 { 913 char name[GPTPARTNAMESIZE + 1]; 914 915 printf("Partition name: [%s] ", name_to_string(pn)); 916 string_from_line(name, sizeof(name), UNTRIMMED); 917 918 switch (strlen(name)) { 919 case 0: 920 break; 921 case GPTPARTNAMESIZE: 922 printf("partition name must be < %d characters\n", 923 GPTPARTNAMESIZE); 924 return -1; 925 default: 926 string_to_name(pn, name); 927 break; 928 } 929 930 return 0; 931 } 932 933 /* 934 * Adapted from Hacker's Delight crc32b(). 935 * 936 * To quote http://www.hackersdelight.org/permissions.htm : 937 * 938 * "You are free to use, copy, and distribute any of the code on 939 * this web site, whether modified by you or not. You need not give 940 * attribution. This includes the algorithms (some of which appear 941 * in Hacker's Delight), the Hacker's Assistant, and any code submitted 942 * by readers. Submitters implicitly agree to this." 943 */ 944 uint32_t 945 crc32(const u_char *buf, const uint32_t size) 946 { 947 int j; 948 uint32_t i, byte, crc, mask; 949 950 crc = 0xFFFFFFFF; 951 952 for (i = 0; i < size; i++) { 953 byte = buf[i]; /* Get next byte. */ 954 crc = crc ^ byte; 955 for (j = 7; j >= 0; j--) { /* Do eight times. */ 956 mask = -(crc & 1); 957 crc = (crc >> 1) ^ (0xEDB88320 & mask); 958 } 959 } 960 961 return ~crc; 962 } 963