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