1 /* $OpenBSD: gpt.c,v 1.91 2023/05/17 12:59:37 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 const struct gpt_partition * const *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 unsigned int i; 128 129 if (mbr->mbr_lba_self != 0) 130 return -1; 131 132 for (i = 0; i < nitems(dp); i++) { 133 memset(&dos_partition, 0, sizeof(dos_partition)); 134 if (i < nitems(mbr->mbr_prt)) 135 PRT_prt_to_dp(&mbr->mbr_prt[i], mbr->mbr_lba_self, 136 mbr->mbr_lba_firstembr, &dos_partition); 137 memcpy(&dp[i], &dos_partition, sizeof(dp[i])); 138 } 139 140 return gpt_chk_mbr(dp, DL_GETDSIZE(&dl)); 141 } 142 143 int 144 get_header(const uint64_t sector) 145 { 146 struct gpt_header legh; 147 uint64_t gpbytes, gpsectors, lba_end; 148 149 if (DISK_readbytes(&legh, sector, sizeof(legh))) 150 return -1; 151 152 gh.gh_sig = letoh64(legh.gh_sig); 153 if (gh.gh_sig != GPTSIGNATURE) { 154 DPRINTF("gpt signature: expected 0x%llx, got 0x%llx\n", 155 GPTSIGNATURE, gh.gh_sig); 156 return -1; 157 } 158 159 gh.gh_rev = letoh32(legh.gh_rev); 160 if (gh.gh_rev != GPTREVISION) { 161 DPRINTF("gpt revision: expected 0x%x, got 0x%x\n", 162 GPTREVISION, gh.gh_rev); 163 return -1; 164 } 165 166 gh.gh_lba_self = letoh64(legh.gh_lba_self); 167 if (gh.gh_lba_self != sector) { 168 DPRINTF("gpt self lba: expected %llu, got %llu\n", 169 sector, gh.gh_lba_self); 170 return -1; 171 } 172 173 gh.gh_size = letoh32(legh.gh_size); 174 if (gh.gh_size != GPTMINHDRSIZE) { 175 DPRINTF("gpt header size: expected %u, got %u\n", 176 GPTMINHDRSIZE, gh.gh_size); 177 return -1; 178 } 179 180 gh.gh_part_size = letoh32(legh.gh_part_size); 181 if (gh.gh_part_size != GPTMINPARTSIZE) { 182 DPRINTF("gpt partition size: expected %u, got %u\n", 183 GPTMINPARTSIZE, gh.gh_part_size); 184 return -1; 185 } 186 187 if ((dl.d_secsize % gh.gh_part_size) != 0) { 188 DPRINTF("gpt sector size %% partition size (%u %% %u) != 0\n", 189 dl.d_secsize, gh.gh_part_size); 190 return -1; 191 } 192 193 gh.gh_part_num = letoh32(legh.gh_part_num); 194 if (gh.gh_part_num > NGPTPARTITIONS) { 195 DPRINTF("gpt partition count: expected <= %u, got %u\n", 196 NGPTPARTITIONS, gh.gh_part_num); 197 return -1; 198 } 199 200 gh.gh_csum = letoh32(legh.gh_csum); 201 legh.gh_csum = 0; 202 legh.gh_csum = crc32((unsigned char *)&legh, gh.gh_size); 203 if (legh.gh_csum != gh.gh_csum) { 204 DPRINTF("gpt header checksum: expected 0x%x, got 0x%x\n", 205 legh.gh_csum, gh.gh_csum); 206 /* Accept wrong-endian checksum. */ 207 if (swap32(legh.gh_csum) != gh.gh_csum) 208 return -1; 209 } 210 211 gpbytes = gh.gh_part_num * gh.gh_part_size; 212 gpsectors = (gpbytes + dl.d_secsize - 1) / dl.d_secsize; 213 lba_end = DL_GETDSIZE(&dl) - gpsectors - 2; 214 215 gh.gh_lba_end = letoh64(legh.gh_lba_end); 216 if (gh.gh_lba_end > lba_end) { 217 DPRINTF("gpt last usable LBA: reduced from %llu to %llu\n", 218 gh.gh_lba_end, lba_end); 219 gh.gh_lba_end = lba_end; 220 } 221 222 gh.gh_lba_start = letoh64(legh.gh_lba_start); 223 if (gh.gh_lba_start >= gh.gh_lba_end) { 224 DPRINTF("gpt first usable LBA: expected < %llu, got %llu\n", 225 gh.gh_lba_end, gh.gh_lba_start); 226 return -1; 227 } 228 229 gh.gh_part_lba = letoh64(legh.gh_part_lba); 230 if (gh.gh_lba_self == GPTSECTOR) { 231 if (gh.gh_part_lba <= GPTSECTOR) { 232 DPRINTF("gpt partition entries start: expected > %u, " 233 "got %llu\n", GPTSECTOR, gh.gh_part_lba); 234 return -1; 235 } 236 if (gh.gh_part_lba + gpsectors > gh.gh_lba_start) { 237 DPRINTF("gpt partition entries end: expected < %llu, " 238 "got %llu\n", gh.gh_lba_start, 239 gh.gh_part_lba + gpsectors); 240 return -1; 241 } 242 } else { 243 if (gh.gh_part_lba <= gh.gh_lba_end) { 244 DPRINTF("gpt partition entries start: expected > %llu, " 245 "got %llu\n", gh.gh_lba_end, gh.gh_part_lba); 246 return -1; 247 } 248 if (gh.gh_part_lba + gpsectors > gh.gh_lba_self) { 249 DPRINTF("gpt partition entries end: expected < %llu, " 250 "got %llu\n", gh.gh_lba_self, 251 gh.gh_part_lba + gpsectors); 252 return -1; 253 } 254 } 255 256 gh.gh_lba_alt = letoh32(legh.gh_lba_alt); 257 gh.gh_part_csum = letoh32(legh.gh_part_csum); 258 gh.gh_rsvd = letoh32(legh.gh_rsvd); /* Should always be 0. */ 259 uuid_dec_le(&legh.gh_guid, &gh.gh_guid); 260 261 return 0; 262 } 263 264 int 265 get_partition_table(void) 266 { 267 struct gpt_partition *legp; 268 uint64_t gpbytes; 269 unsigned int pn; 270 int rslt = -1; 271 uint32_t gh_part_csum; 272 273 DPRINTF("gpt partition table being read from LBA %llu\n", 274 gh.gh_part_lba); 275 276 gpbytes = gh.gh_part_num * gh.gh_part_size; 277 278 legp = calloc(1, gpbytes); 279 if (legp == NULL) 280 err(1, "legp"); 281 282 if (DISK_readbytes(legp, gh.gh_part_lba, gpbytes)) 283 goto done; 284 gh_part_csum = crc32((unsigned char *)legp, gpbytes); 285 286 if (gh_part_csum != gh.gh_part_csum) { 287 DPRINTF("gpt partition table checksum: expected 0x%x, " 288 "got 0x%x\n", gh.gh_part_csum, gh_part_csum); 289 /* Accept wrong-endian checksum. */ 290 if (swap32(gh_part_csum) != gh.gh_part_csum) 291 goto done; 292 } 293 294 memset(&gp, 0, sizeof(gp)); 295 for (pn = 0; pn < gh.gh_part_num; pn++) { 296 uuid_dec_le(&legp[pn].gp_type, &gp[pn].gp_type); 297 uuid_dec_le(&legp[pn].gp_guid, &gp[pn].gp_guid); 298 gp[pn].gp_lba_start = letoh64(legp[pn].gp_lba_start); 299 gp[pn].gp_lba_end = letoh64(legp[pn].gp_lba_end); 300 gp[pn].gp_attrs = letoh64(legp[pn].gp_attrs); 301 memcpy(gp[pn].gp_name, legp[pn].gp_name, 302 sizeof(gp[pn].gp_name)); 303 } 304 rslt = 0; 305 306 done: 307 free(legp); 308 return rslt; 309 } 310 311 int 312 GPT_read(const int which) 313 { 314 int error; 315 316 error = MBR_read(0, 0, &gmbr); 317 if (error) 318 goto done; 319 error = protective_mbr(&gmbr); 320 if (error == -1) 321 goto done; 322 323 switch (which) { 324 case PRIMARYGPT: 325 error = get_header(GPTSECTOR); 326 break; 327 case SECONDARYGPT: 328 error = get_header(DL_GETDSIZE(&dl) - 1); 329 break; 330 case ANYGPT: 331 error = get_header(GPTSECTOR); 332 if (error != 0 || get_partition_table() != 0) 333 error = get_header(DL_GETDSIZE(&dl) - 1); 334 break; 335 default: 336 return -1; 337 } 338 339 if (error == 0) 340 error = get_partition_table(); 341 342 done: 343 if (error != 0) { 344 /* No valid GPT found. Zap any artifacts. */ 345 memset(&gmbr, 0, sizeof(gmbr)); 346 memset(&gh, 0, sizeof(gh)); 347 memset(&gp, 0, sizeof(gp)); 348 } 349 350 return error; 351 } 352 353 void 354 GPT_print(const char *units, const int verbosity) 355 { 356 const struct unit_type *ut; 357 const int secsize = dl.d_secsize; 358 char *guidstr = NULL; 359 double size; 360 unsigned int pn; 361 uint32_t status; 362 363 #ifdef DEBUG 364 char *p; 365 uint64_t sig; 366 unsigned int i; 367 368 sig = htole64(gh.gh_sig); 369 p = (char *)&sig; 370 371 printf("gh_sig : "); 372 for (i = 0; i < sizeof(sig); i++) 373 printf("%c", isprint((unsigned char)p[i]) ? p[i] : '?'); 374 printf(" ("); 375 for (i = 0; i < sizeof(sig); i++) { 376 printf("%02x", p[i]); 377 if ((i + 1) < sizeof(sig)) 378 printf(":"); 379 } 380 printf(")\n"); 381 printf("gh_rev : %u\n", gh.gh_rev); 382 printf("gh_size : %u (%zd)\n", gh.gh_size, sizeof(gh)); 383 printf("gh_csum : 0x%x\n", gh.gh_csum); 384 printf("gh_rsvd : %u\n", gh.gh_rsvd); 385 printf("gh_lba_self : %llu\n", gh.gh_lba_self); 386 printf("gh_lba_alt : %llu\n", gh.gh_lba_alt); 387 printf("gh_lba_start : %llu\n", gh.gh_lba_start); 388 printf("gh_lba_end : %llu\n", gh.gh_lba_end); 389 p = NULL; 390 uuid_to_string(&gh.gh_guid, &p, &status); 391 printf("gh_gh_guid : %s\n", (status == uuid_s_ok) ? p : "<invalid>"); 392 free(p); 393 printf("gh_gh_part_lba : %llu\n", gh.gh_part_lba); 394 printf("gh_gh_part_num : %u (%zu)\n", gh.gh_part_num, nitems(gp)); 395 printf("gh_gh_part_size: %u (%zu)\n", gh.gh_part_size, sizeof(gp[0])); 396 printf("gh_gh_part_csum: 0x%x\n", gh.gh_part_csum); 397 printf("\n"); 398 #endif /* DEBUG */ 399 400 size = units_size(units, DL_GETDSIZE(&dl), &ut); 401 printf("Disk: %s Usable LBA: %llu to %llu [%.0f ", 402 disk.dk_name, gh.gh_lba_start, gh.gh_lba_end, size); 403 if (ut->ut_conversion == 0 && secsize != DEV_BSIZE) 404 printf("%d-byte ", secsize); 405 printf("%s]\n", ut->ut_lname); 406 407 if (verbosity == VERBOSE) { 408 printf("GUID: "); 409 uuid_to_string(&gh.gh_guid, &guidstr, &status); 410 if (status == uuid_s_ok) 411 printf("%s\n", guidstr); 412 else 413 printf("<invalid header GUID>\n"); 414 free(guidstr); 415 } 416 417 GPT_print_parthdr(verbosity); 418 for (pn = 0; pn < gh.gh_part_num; pn++) { 419 if (uuid_is_nil(&gp[pn].gp_type, NULL)) 420 continue; 421 GPT_print_part(pn, units, verbosity); 422 } 423 } 424 425 void 426 GPT_print_parthdr(const int verbosity) 427 { 428 printf(" #: type " 429 " [ start: size ]\n"); 430 if (verbosity == VERBOSE) 431 printf(" guid name\n"); 432 printf("--------------------------------------------------------" 433 "----------------\n"); 434 } 435 436 void 437 GPT_print_part(const unsigned int pn, const char *units, const int verbosity) 438 { 439 const struct unit_type *ut; 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_desc(&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 if (attrs & GPTPARTATTR_MS_READONLY) 470 printf("MSReadOnly " ); 471 if (attrs & GPTPARTATTR_MS_SHADOW) 472 printf("MSShadow "); 473 if (attrs & GPTPARTATTR_MS_HIDDEN) 474 printf("MSHidden "); 475 if (attrs & GPTPARTATTR_MS_NOAUTOMOUNT) 476 printf("MSNoAutoMount "); 477 printf("\n"); 478 } 479 } 480 481 if (uuid_is_nil(&gp[pn].gp_type, NULL) == 0) { 482 if (start > end) 483 printf("partition %u first LBA is > last LBA\n", pn); 484 if (start < gh.gh_lba_start || end > gh.gh_lba_end) 485 printf("partition %u extends beyond usable LBA range " 486 "of %s\n", pn, disk.dk_name); 487 } 488 } 489 490 int 491 find_partition(const uint8_t *beuuid) 492 { 493 struct uuid uuid; 494 unsigned int pn; 495 496 uuid_dec_be(beuuid, &uuid); 497 498 for (pn = 0; pn < gh.gh_part_num; pn++) { 499 if (uuid_compare(&gp[pn].gp_type, &uuid, NULL) == 0) 500 return pn; 501 } 502 return -1; 503 } 504 505 int 506 add_partition(const uint8_t *beuuid, const char *name, uint64_t sectors) 507 { 508 struct uuid uuid; 509 int rslt; 510 uint64_t end, freesectors, start; 511 uint32_t status, pn; 512 513 uuid_dec_be(beuuid, &uuid); 514 515 for (pn = 0; pn < gh.gh_part_num; pn++) { 516 if (uuid_is_nil(&gp[pn].gp_type, NULL)) 517 break; 518 } 519 if (pn == gh.gh_part_num) 520 goto done; 521 522 rslt = lba_free(&start, &end); 523 if (rslt == -1) 524 goto done; 525 526 if (start % BLOCKALIGNMENT) 527 start += (BLOCKALIGNMENT - start % BLOCKALIGNMENT); 528 if (start >= end) 529 goto done; 530 531 freesectors = end - start + 1; 532 533 if (sectors == 0) 534 sectors = freesectors; 535 536 if (freesectors < sectors) 537 goto done; 538 else if (freesectors > sectors) 539 end = start + sectors - 1; 540 541 gp[pn].gp_type = uuid; 542 gp[pn].gp_lba_start = start; 543 gp[pn].gp_lba_end = end; 544 string_to_name(pn, name); 545 546 uuid_create(&gp[pn].gp_guid, &status); 547 if (status == uuid_s_ok) 548 return 0; 549 550 done: 551 if (pn != gh.gh_part_num) 552 memset(&gp[pn], 0, sizeof(gp[pn])); 553 printf("unable to add %s\n", name); 554 return -1; 555 } 556 557 int 558 init_gh(void) 559 { 560 struct gpt_header oldgh; 561 const int secsize = dl.d_secsize; 562 int needed; 563 uint32_t status; 564 565 memcpy(&oldgh, &gh, sizeof(oldgh)); 566 memset(&gh, 0, sizeof(gh)); 567 memset(&gmbr, 0, sizeof(gmbr)); 568 569 /* XXX Do we need the boot code? UEFI spec & Apple says no. */ 570 memcpy(gmbr.mbr_code, default_dmbr.dmbr_boot, sizeof(gmbr.mbr_code)); 571 gmbr.mbr_prt[0].prt_id = DOSPTYP_EFI; 572 gmbr.mbr_prt[0].prt_bs = 1; 573 gmbr.mbr_prt[0].prt_ns = UINT32_MAX; 574 gmbr.mbr_signature = DOSMBR_SIGNATURE; 575 576 needed = sizeof(gp) / secsize + 2; 577 578 if (needed % BLOCKALIGNMENT) 579 needed += (needed - (needed % BLOCKALIGNMENT)); 580 581 gh.gh_sig = GPTSIGNATURE; 582 gh.gh_rev = GPTREVISION; 583 gh.gh_size = GPTMINHDRSIZE; 584 gh.gh_csum = 0; 585 gh.gh_rsvd = 0; 586 gh.gh_lba_self = 1; 587 gh.gh_lba_alt = DL_GETDSIZE(&dl) - 1; 588 gh.gh_lba_start = needed; 589 gh.gh_lba_end = DL_GETDSIZE(&dl) - needed; 590 uuid_create(&gh.gh_guid, &status); 591 if (status != uuid_s_ok) { 592 memcpy(&gh, &oldgh, sizeof(gh)); 593 return -1; 594 } 595 gh.gh_part_lba = 2; 596 gh.gh_part_num = NGPTPARTITIONS; 597 gh.gh_part_size = GPTMINPARTSIZE; 598 gh.gh_part_csum = 0; 599 600 return 0; 601 } 602 603 int 604 init_gp(const int how) 605 { 606 struct gpt_partition oldgp[NGPTPARTITIONS]; 607 const uint8_t gpt_uuid_efi_system[] = GPT_UUID_EFI_SYSTEM; 608 const uint8_t gpt_uuid_openbsd[] = GPT_UUID_OPENBSD; 609 uint64_t prt_ns; 610 int pn, rslt; 611 612 memcpy(&oldgp, &gp, sizeof(oldgp)); 613 if (how == GHANDGP) 614 memset(&gp, 0, sizeof(gp)); 615 else { 616 for (pn = 0; pn < gh.gh_part_num; pn++) { 617 if (PRT_protected_uuid(&gp[pn].gp_type) || 618 (gp[pn].gp_attrs & GPTPARTATTR_REQUIRED)) 619 continue; 620 memset(&gp[pn], 0, sizeof(gp[pn])); 621 } 622 } 623 624 rslt = 0; 625 if (disk.dk_bootprt.prt_ns > 0) { 626 pn = find_partition(gpt_uuid_efi_system); 627 if (pn == -1) { 628 rslt = add_partition(gpt_uuid_efi_system, 629 "EFI System Area", disk.dk_bootprt.prt_ns); 630 } else { 631 prt_ns = gp[pn].gp_lba_end - gp[pn].gp_lba_start + 1; 632 if (prt_ns < disk.dk_bootprt.prt_ns) { 633 printf("EFI System Area < %llu sectors\n", 634 disk.dk_bootprt.prt_ns); 635 rslt = -1; 636 } 637 } 638 } 639 if (rslt == 0) 640 rslt = add_partition(gpt_uuid_openbsd, "OpenBSD Area", 0); 641 642 if (rslt != 0) 643 memcpy(&gp, &oldgp, sizeof(gp)); 644 645 return rslt; 646 } 647 648 int 649 GPT_init(const int how) 650 { 651 int rslt = 0; 652 653 if (how == GHANDGP) 654 rslt = init_gh(); 655 if (rslt == 0) 656 rslt = init_gp(how); 657 658 return rslt; 659 } 660 661 void 662 GPT_zap_headers(void) 663 { 664 struct gpt_header legh; 665 666 if (DISK_readbytes(&legh, GPTSECTOR, sizeof(legh))) 667 return; 668 669 if (letoh64(legh.gh_sig) == GPTSIGNATURE) { 670 memset(&legh, 0, sizeof(legh)); 671 if (DISK_writebytes(&legh, GPTSECTOR, sizeof(legh))) 672 DPRINTF("Unable to zap GPT header @ sector %d", 673 GPTSECTOR); 674 } 675 676 if (DISK_readbytes(&legh, DL_GETDSIZE(&dl) - 1, sizeof(legh))) 677 return; 678 679 if (letoh64(legh.gh_sig) == GPTSIGNATURE) { 680 memset(&legh, 0, GPTMINHDRSIZE); 681 if (DISK_writebytes(&legh, DL_GETDSIZE(&dl) - 1, sizeof(legh))) 682 DPRINTF("Unable to zap GPT header @ sector %llu", 683 DL_GETDSIZE(&dl) - 1); 684 } 685 } 686 687 int 688 GPT_write(void) 689 { 690 struct gpt_header legh; 691 struct gpt_partition *legp; 692 uint64_t altgh, altgp; 693 uint64_t gpbytes, gpsectors; 694 unsigned int pn; 695 int rslt = -1; 696 697 if (MBR_write(&gmbr)) 698 return -1; 699 700 gpbytes = gh.gh_part_num * gh.gh_part_size; 701 gpsectors = (gpbytes + dl.d_secsize - 1) / dl.d_secsize; 702 703 altgh = DL_GETDSIZE(&dl) - 1; 704 altgp = altgh - gpsectors; 705 706 legh.gh_sig = htole64(GPTSIGNATURE); 707 legh.gh_rev = htole32(GPTREVISION); 708 legh.gh_size = htole32(GPTMINHDRSIZE); 709 legh.gh_rsvd = 0; 710 legh.gh_lba_self = htole64(GPTSECTOR); 711 legh.gh_lba_alt = htole64(altgh); 712 legh.gh_lba_start = htole64(gh.gh_lba_start); 713 legh.gh_lba_end = htole64(gh.gh_lba_end); 714 uuid_enc_le(&legh.gh_guid, &gh.gh_guid); 715 legh.gh_part_lba = htole64(GPTSECTOR + 1); 716 legh.gh_part_num = htole32(gh.gh_part_num); 717 legh.gh_part_size = htole32(GPTMINPARTSIZE); 718 719 legp = calloc(1, gpbytes); 720 if (legp == NULL) 721 err(1, "legp"); 722 723 for (pn = 0; pn < gh.gh_part_num; pn++) { 724 uuid_enc_le(&legp[pn].gp_type, &gp[pn].gp_type); 725 uuid_enc_le(&legp[pn].gp_guid, &gp[pn].gp_guid); 726 legp[pn].gp_lba_start = htole64(gp[pn].gp_lba_start); 727 legp[pn].gp_lba_end = htole64(gp[pn].gp_lba_end); 728 legp[pn].gp_attrs = htole64(gp[pn].gp_attrs); 729 memcpy(legp[pn].gp_name, gp[pn].gp_name, 730 sizeof(legp[pn].gp_name)); 731 } 732 legh.gh_part_csum = htole32(crc32((unsigned char *)legp, gpbytes)); 733 legh.gh_csum = 0; 734 legh.gh_csum = htole32(crc32((unsigned char *)&legh, gh.gh_size)); 735 736 if (DISK_writebytes(&legh, GPTSECTOR, gh.gh_size) || 737 DISK_writebytes(legp, GPTSECTOR + 1, gpbytes)) 738 goto done; 739 740 legh.gh_lba_self = htole64(altgh); 741 legh.gh_lba_alt = htole64(GPTSECTOR); 742 legh.gh_part_lba = htole64(altgp); 743 legh.gh_csum = 0; 744 legh.gh_csum = htole32(crc32((unsigned char *)&legh, gh.gh_size)); 745 746 if (DISK_writebytes(&legh, altgh, gh.gh_size) || 747 DISK_writebytes(&gp, altgp, gpbytes)) 748 goto done; 749 750 /* Refresh in-kernel disklabel from the updated disk information. */ 751 if (ioctl(disk.dk_fd, DIOCRLDINFO, 0) == -1) 752 warn("DIOCRLDINFO"); 753 rslt = 0; 754 755 done: 756 free(legp); 757 return rslt; 758 } 759 760 int 761 gp_lba_start_cmp(const void *e1, const void *e2) 762 { 763 struct gpt_partition *p1 = *(struct gpt_partition **)e1; 764 struct gpt_partition *p2 = *(struct gpt_partition **)e2; 765 uint64_t o1; 766 uint64_t o2; 767 768 o1 = p1->gp_lba_start; 769 o2 = p2->gp_lba_start; 770 771 if (o1 < o2) 772 return -1; 773 else if (o1 > o2) 774 return 1; 775 else 776 return 0; 777 } 778 779 const struct gpt_partition * const * 780 sort_gpt(void) 781 { 782 static const struct gpt_partition *sgp[NGPTPARTITIONS+2]; 783 unsigned int i, pn; 784 785 memset(sgp, 0, sizeof(sgp)); 786 787 i = 0; 788 for (pn = 0; pn < gh.gh_part_num; pn++) { 789 if (gp[pn].gp_lba_start >= gh.gh_lba_start) 790 sgp[i++] = &gp[pn]; 791 } 792 793 if (i > 1) { 794 if (mergesort(sgp, i, sizeof(sgp[0]), gp_lba_start_cmp) == -1) { 795 printf("unable to sort gpt by lba start\n"); 796 return NULL; 797 } 798 } 799 800 return sgp; 801 } 802 803 int 804 lba_free(uint64_t *start, uint64_t *end) 805 { 806 const struct gpt_partition * const *sgp; 807 uint64_t bs, bigbs, nextbs, ns; 808 unsigned int i; 809 810 sgp = sort_gpt(); 811 if (sgp == NULL) 812 return -1; 813 814 bs = gh.gh_lba_start; 815 ns = gh.gh_lba_end - bs + 1; 816 817 if (sgp[0] != NULL) { 818 bigbs = bs; 819 ns = 0; 820 for (i = 0; sgp[i] != NULL; i++) { 821 nextbs = sgp[i]->gp_lba_start; 822 if (bs < nextbs && ns < nextbs - bs) { 823 ns = nextbs - bs; 824 bigbs = bs; 825 } 826 bs = sgp[i]->gp_lba_end + 1; 827 } 828 nextbs = gh.gh_lba_end + 1; 829 if (bs < nextbs && ns < nextbs - bs) { 830 ns = nextbs - bs; 831 bigbs = bs; 832 } 833 bs = bigbs; 834 } 835 836 if (ns == 0) 837 return -1; 838 839 if (start != NULL) 840 *start = bs; 841 if (end != NULL) 842 *end = bs + ns - 1; 843 844 return 0; 845 } 846 847 int 848 GPT_get_lba_start(const unsigned int pn) 849 { 850 uint64_t bs; 851 unsigned int i; 852 int rslt; 853 854 bs = gh.gh_lba_start; 855 856 if (gp[pn].gp_lba_start >= bs) { 857 bs = gp[pn].gp_lba_start; 858 } else { 859 rslt = lba_free(&bs, NULL); 860 if (rslt == -1) { 861 printf("no space for partition %u\n", pn); 862 return -1; 863 } 864 } 865 866 bs = getuint64("Partition offset", bs, gh.gh_lba_start, gh.gh_lba_end); 867 for (i = 0; i < gh.gh_part_num; i++) { 868 if (i == pn) 869 continue; 870 if (bs >= gp[i].gp_lba_start && bs <= gp[i].gp_lba_end) { 871 printf("partition %u can't start inside partition %u\n", 872 pn, i); 873 return -1; 874 } 875 } 876 877 gp[pn].gp_lba_start = bs; 878 879 return 0; 880 } 881 882 int 883 GPT_get_lba_end(const unsigned int pn) 884 { 885 const struct gpt_partition * const *sgp; 886 uint64_t bs, nextbs, ns; 887 unsigned int i; 888 889 sgp = sort_gpt(); 890 if (sgp == NULL) 891 return -1; 892 893 bs = gp[pn].gp_lba_start; 894 ns = gh.gh_lba_end - bs + 1; 895 for (i = 0; sgp[i] != NULL; i++) { 896 nextbs = sgp[i]->gp_lba_start; 897 if (nextbs > bs) { 898 ns = nextbs - bs; 899 break; 900 } 901 } 902 ns = getuint64("Partition size", ns, 1, ns); 903 904 gp[pn].gp_lba_end = bs + ns - 1; 905 906 return 0; 907 } 908 909 int 910 GPT_get_name(const unsigned int pn) 911 { 912 char name[GPTPARTNAMESIZE + 1]; 913 914 printf("Partition name: [%s] ", name_to_string(pn)); 915 string_from_line(name, sizeof(name), UNTRIMMED); 916 917 switch (strlen(name)) { 918 case 0: 919 break; 920 case GPTPARTNAMESIZE: 921 printf("partition name must be < %d characters\n", 922 GPTPARTNAMESIZE); 923 return -1; 924 default: 925 string_to_name(pn, name); 926 break; 927 } 928 929 return 0; 930 } 931 932 /* 933 * Adapted from Hacker's Delight crc32b(). 934 * 935 * To quote http://www.hackersdelight.org/permissions.htm : 936 * 937 * "You are free to use, copy, and distribute any of the code on 938 * this web site, whether modified by you or not. You need not give 939 * attribution. This includes the algorithms (some of which appear 940 * in Hacker's Delight), the Hacker's Assistant, and any code submitted 941 * by readers. Submitters implicitly agree to this." 942 */ 943 uint32_t 944 crc32(const u_char *buf, const uint32_t size) 945 { 946 int j; 947 uint32_t i, byte, crc, mask; 948 949 crc = 0xFFFFFFFF; 950 951 for (i = 0; i < size; i++) { 952 byte = buf[i]; /* Get next byte. */ 953 crc = crc ^ byte; 954 for (j = 7; j >= 0; j--) { /* Do eight times. */ 955 mask = -(crc & 1); 956 crc = (crc >> 1) ^ (0xEDB88320 & mask); 957 } 958 } 959 960 return ~crc; 961 } 962