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