1*b7c9a52eSkrw /* $OpenBSD: gpt.c,v 1.95 2024/12/24 21:34:23 krw Exp $ */ 21cd24417Skrw /* 31cd24417Skrw * Copyright (c) 2015 Markus Muller <mmu@grummel.net> 41cd24417Skrw * Copyright (c) 2015 Kenneth R Westerback <krw@openbsd.org> 51cd24417Skrw * 61cd24417Skrw * Permission to use, copy, modify, and distribute this software for any 71cd24417Skrw * purpose with or without fee is hereby granted, provided that the above 81cd24417Skrw * copyright notice and this permission notice appear in all copies. 91cd24417Skrw * 101cd24417Skrw * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 111cd24417Skrw * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 121cd24417Skrw * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 131cd24417Skrw * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 141cd24417Skrw * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 151cd24417Skrw * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 161cd24417Skrw * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 171cd24417Skrw */ 181cd24417Skrw 19729290c0Skrw #include <sys/param.h> /* DEV_BSIZE */ 201cd24417Skrw #include <sys/disklabel.h> 211cd24417Skrw #include <sys/dkio.h> 221cd24417Skrw #include <sys/ioctl.h> 23729290c0Skrw 242cdacd27Skrw #include <ctype.h> 25605b5690Skrw #include <err.h> 26fba7235cSkrw #include <stdio.h> 27dfcac45eSkrw #include <stdint.h> 281cd24417Skrw #include <stdlib.h> 291cd24417Skrw #include <string.h> 301cd24417Skrw #include <uuid.h> 311cd24417Skrw 32199eafeaSkrw #include "part.h" 331cd24417Skrw #include "disk.h" 34afd1db78Skrw #include "mbr.h" 351cd24417Skrw #include "misc.h" 361cd24417Skrw #include "gpt.h" 371cd24417Skrw 38fba7235cSkrw #ifdef DEBUG 39fba7235cSkrw #define DPRINTF(x...) printf(x) 40fba7235cSkrw #else 41fba7235cSkrw #define DPRINTF(x...) 42fba7235cSkrw #endif 43fba7235cSkrw 44dfcac45eSkrw struct mbr gmbr; 451cd24417Skrw struct gpt_header gh; 461cd24417Skrw struct gpt_partition gp[NGPTPARTITIONS]; 471cd24417Skrw 488c6d22aeSkrw const struct gpt_partition * const *sort_gpt(void); 4938678f29Skrw int lba_free(uint64_t *, uint64_t *); 50534ba684Skrw int add_partition(const uint8_t *, const char *, uint64_t); 5165deb39bSkrw int find_partition(const uint8_t *); 520cd9e2afSkrw int get_header(const uint64_t); 53032115fcSkrw int get_partition_table(void); 544b0ba6ccSkrw int init_gh(void); 55199eafeaSkrw int init_gp(const int); 56543185b3Skrw uint32_t crc32(const u_char *, const uint32_t); 57dfcac45eSkrw int protective_mbr(const struct mbr *); 58dfcac45eSkrw int gpt_chk_mbr(struct dos_partition *, uint64_t); 59a66d82b0Skrw void string_to_name(const unsigned int, const char *); 60a66d82b0Skrw const char *name_to_string(const unsigned int); 61a66d82b0Skrw 62a66d82b0Skrw void 63a66d82b0Skrw string_to_name(const unsigned int pn, const char *ch) 64a66d82b0Skrw { 65a66d82b0Skrw unsigned int i; 66a66d82b0Skrw 67a66d82b0Skrw memset(gp[pn].gp_name, 0, sizeof(gp[pn].gp_name)); 68a66d82b0Skrw 69*b7c9a52eSkrw for (i = 0; i < nitems(gp[pn].gp_name) && ch[i] != '\0'; i++) 70a66d82b0Skrw gp[pn].gp_name[i] = htole16((unsigned int)ch[i]); 71a66d82b0Skrw } 72a66d82b0Skrw 73a66d82b0Skrw const char * 74a66d82b0Skrw name_to_string(const unsigned int pn) 75a66d82b0Skrw { 76a66d82b0Skrw static char name[GPTPARTNAMESIZE + 1]; 77a66d82b0Skrw unsigned int i; 78a66d82b0Skrw 7944612db3Skrw for (i = 0; i < GPTPARTNAMESIZE && gp[pn].gp_name[i] != 0; i++) 80a66d82b0Skrw name[i] = letoh16(gp[pn].gp_name[i]) & 0x7F; 8144612db3Skrw name[i] = '\0'; 82a66d82b0Skrw 83a66d82b0Skrw return name; 84a66d82b0Skrw } 85dfcac45eSkrw 86dfcac45eSkrw /* 87dfcac45eSkrw * Return the index into dp[] of the EFI GPT (0xEE) partition, or -1 if no such 88dfcac45eSkrw * partition exists. 89dfcac45eSkrw * 90dfcac45eSkrw * Taken from kern/subr_disk.c. 91dfcac45eSkrw * 92dfcac45eSkrw */ 93dfcac45eSkrw int 94dfcac45eSkrw gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize) 95dfcac45eSkrw { 96dfcac45eSkrw struct dos_partition *dp2; 97dfcac45eSkrw int efi, eficnt, found, i; 98dfcac45eSkrw uint32_t psize; 99dfcac45eSkrw 100dfcac45eSkrw found = efi = eficnt = 0; 101dfcac45eSkrw for (dp2 = dp, i = 0; i < NDOSPART; i++, dp2++) { 102dfcac45eSkrw if (dp2->dp_typ == DOSPTYP_UNUSED) 103dfcac45eSkrw continue; 104dfcac45eSkrw found++; 105dfcac45eSkrw if (dp2->dp_typ != DOSPTYP_EFI) 106dfcac45eSkrw continue; 107dfcac45eSkrw if (letoh32(dp2->dp_start) != GPTSECTOR) 108dfcac45eSkrw continue; 109dfcac45eSkrw psize = letoh32(dp2->dp_size); 110dfcac45eSkrw if (psize <= (dsize - GPTSECTOR) || psize == UINT32_MAX) { 111dfcac45eSkrw efi = i; 112dfcac45eSkrw eficnt++; 113dfcac45eSkrw } 114dfcac45eSkrw } 115dfcac45eSkrw if (found == 1 && eficnt == 1) 116dfcac45eSkrw return efi; 117dfcac45eSkrw 118dfcac45eSkrw return -1; 119dfcac45eSkrw } 120dfcac45eSkrw 121dfcac45eSkrw int 122dfcac45eSkrw protective_mbr(const struct mbr *mbr) 123dfcac45eSkrw { 124dfcac45eSkrw struct dos_partition dp[NDOSPART], dos_partition; 125c5431474Skrw unsigned int i; 126dfcac45eSkrw 127dfcac45eSkrw if (mbr->mbr_lba_self != 0) 128dfcac45eSkrw return -1; 129dfcac45eSkrw 130c5431474Skrw for (i = 0; i < nitems(dp); i++) { 131c5431474Skrw memset(&dos_partition, 0, sizeof(dos_partition)); 132c5431474Skrw if (i < nitems(mbr->mbr_prt)) 133614d0f20Skrw PRT_prt_to_dp(&mbr->mbr_prt[i], mbr->mbr_lba_self, 13499e0469cSkrw mbr->mbr_lba_firstembr, &dos_partition); 135dfcac45eSkrw memcpy(&dp[i], &dos_partition, sizeof(dp[i])); 136dfcac45eSkrw } 137dfcac45eSkrw 138dfcac45eSkrw return gpt_chk_mbr(dp, DL_GETDSIZE(&dl)); 139dfcac45eSkrw } 140c2d03168Skrw 1411cd24417Skrw int 1420cd9e2afSkrw get_header(const uint64_t sector) 143fba7235cSkrw { 144ad6c5e72Skrw struct gpt_header legh; 145b7307f09Skrw uint64_t gpbytes, gpsectors, lba_end; 146fba7235cSkrw 147adf35c80Skrw if (DISK_readbytes(&legh, sector, sizeof(legh))) 14839351f7aSkrw return -1; 149fba7235cSkrw 150ad6c5e72Skrw gh.gh_sig = letoh64(legh.gh_sig); 151ad6c5e72Skrw if (gh.gh_sig != GPTSIGNATURE) { 152fba7235cSkrw DPRINTF("gpt signature: expected 0x%llx, got 0x%llx\n", 153ad6c5e72Skrw GPTSIGNATURE, gh.gh_sig); 15439351f7aSkrw return -1; 155fba7235cSkrw } 156fba7235cSkrw 157ad6c5e72Skrw gh.gh_rev = letoh32(legh.gh_rev); 158ad6c5e72Skrw if (gh.gh_rev != GPTREVISION) { 159fba7235cSkrw DPRINTF("gpt revision: expected 0x%x, got 0x%x\n", 160ad6c5e72Skrw GPTREVISION, gh.gh_rev); 16139351f7aSkrw return -1; 162fba7235cSkrw } 163fba7235cSkrw 164ad6c5e72Skrw gh.gh_lba_self = letoh64(legh.gh_lba_self); 165ad6c5e72Skrw if (gh.gh_lba_self != sector) { 1660cd9e2afSkrw DPRINTF("gpt self lba: expected %llu, got %llu\n", 167ad6c5e72Skrw sector, gh.gh_lba_self); 16839351f7aSkrw return -1; 169fba7235cSkrw } 170fba7235cSkrw 171ad6c5e72Skrw gh.gh_size = letoh32(legh.gh_size); 172ad6c5e72Skrw if (gh.gh_size != GPTMINHDRSIZE) { 173fba7235cSkrw DPRINTF("gpt header size: expected %u, got %u\n", 174ad6c5e72Skrw GPTMINHDRSIZE, gh.gh_size); 17539351f7aSkrw return -1; 176fba7235cSkrw } 177fba7235cSkrw 178ad6c5e72Skrw gh.gh_part_size = letoh32(legh.gh_part_size); 179ad6c5e72Skrw if (gh.gh_part_size != GPTMINPARTSIZE) { 180fba7235cSkrw DPRINTF("gpt partition size: expected %u, got %u\n", 181ad6c5e72Skrw GPTMINPARTSIZE, gh.gh_part_size); 18239351f7aSkrw return -1; 183fba7235cSkrw } 184fba7235cSkrw 185ad6c5e72Skrw if ((dl.d_secsize % gh.gh_part_size) != 0) { 1866c525197Skrw DPRINTF("gpt sector size %% partition size (%u %% %u) != 0\n", 187ad6c5e72Skrw dl.d_secsize, gh.gh_part_size); 1886c525197Skrw return -1; 1896c525197Skrw } 1906c525197Skrw 191ad6c5e72Skrw gh.gh_part_num = letoh32(legh.gh_part_num); 192ad6c5e72Skrw if (gh.gh_part_num > NGPTPARTITIONS) { 193fba7235cSkrw DPRINTF("gpt partition count: expected <= %u, got %u\n", 194ad6c5e72Skrw NGPTPARTITIONS, gh.gh_part_num); 19539351f7aSkrw return -1; 196fba7235cSkrw } 197fba7235cSkrw 198ad6c5e72Skrw gh.gh_csum = letoh32(legh.gh_csum); 199ad6c5e72Skrw legh.gh_csum = 0; 200ad6c5e72Skrw legh.gh_csum = crc32((unsigned char *)&legh, gh.gh_size); 201ad6c5e72Skrw if (legh.gh_csum != gh.gh_csum) { 202fba7235cSkrw DPRINTF("gpt header checksum: expected 0x%x, got 0x%x\n", 203ad6c5e72Skrw legh.gh_csum, gh.gh_csum); 2044b0a6a04Skrw /* Accept wrong-endian checksum. */ 205ad6c5e72Skrw if (swap32(legh.gh_csum) != gh.gh_csum) 20639351f7aSkrw return -1; 207fba7235cSkrw } 208fba7235cSkrw 209ad6c5e72Skrw gpbytes = gh.gh_part_num * gh.gh_part_size; 210b7307f09Skrw gpsectors = (gpbytes + dl.d_secsize - 1) / dl.d_secsize; 211b7307f09Skrw lba_end = DL_GETDSIZE(&dl) - gpsectors - 2; 212ad6c5e72Skrw 213ad6c5e72Skrw gh.gh_lba_end = letoh64(legh.gh_lba_end); 214ad6c5e72Skrw if (gh.gh_lba_end > lba_end) { 2157345db1eSkrw DPRINTF("gpt last usable LBA: reduced from %llu to %llu\n", 216ad6c5e72Skrw gh.gh_lba_end, lba_end); 217ad6c5e72Skrw gh.gh_lba_end = lba_end; 218fba7235cSkrw } 219fba7235cSkrw 220ad6c5e72Skrw gh.gh_lba_start = letoh64(legh.gh_lba_start); 221ad6c5e72Skrw if (gh.gh_lba_start >= gh.gh_lba_end) { 222fba7235cSkrw DPRINTF("gpt first usable LBA: expected < %llu, got %llu\n", 223ad6c5e72Skrw gh.gh_lba_end, gh.gh_lba_start); 22439351f7aSkrw return -1; 225fba7235cSkrw } 226fba7235cSkrw 227ad6c5e72Skrw gh.gh_part_lba = letoh64(legh.gh_part_lba); 228ef761e99Skrw if (gh.gh_lba_self == GPTSECTOR) { 229ef761e99Skrw if (gh.gh_part_lba <= GPTSECTOR) { 230ef761e99Skrw DPRINTF("gpt partition entries start: expected > %u, " 231ef761e99Skrw "got %llu\n", GPTSECTOR, gh.gh_part_lba); 23239351f7aSkrw return -1; 233fba7235cSkrw } 234ef761e99Skrw if (gh.gh_part_lba + gpsectors > gh.gh_lba_start) { 235ef761e99Skrw DPRINTF("gpt partition entries end: expected < %llu, " 236ef761e99Skrw "got %llu\n", gh.gh_lba_start, 237ef761e99Skrw gh.gh_part_lba + gpsectors); 23839351f7aSkrw return -1; 239fba7235cSkrw } 240ef761e99Skrw } else { 241ef761e99Skrw if (gh.gh_part_lba <= gh.gh_lba_end) { 242ef761e99Skrw DPRINTF("gpt partition entries start: expected > %llu, " 243ef761e99Skrw "got %llu\n", gh.gh_lba_end, gh.gh_part_lba); 244ef761e99Skrw return -1; 245ef761e99Skrw } 246ef761e99Skrw if (gh.gh_part_lba + gpsectors > gh.gh_lba_self) { 247ef761e99Skrw DPRINTF("gpt partition entries end: expected < %llu, " 248ef761e99Skrw "got %llu\n", gh.gh_lba_self, 249ef761e99Skrw gh.gh_part_lba + gpsectors); 250ef761e99Skrw return -1; 251ef761e99Skrw } 252ef761e99Skrw } 253ad6c5e72Skrw 254ad6c5e72Skrw gh.gh_lba_alt = letoh32(legh.gh_lba_alt); 255ad6c5e72Skrw gh.gh_part_csum = letoh32(legh.gh_part_csum); 256ad6c5e72Skrw gh.gh_rsvd = letoh32(legh.gh_rsvd); /* Should always be 0. */ 257ad6c5e72Skrw uuid_dec_le(&legh.gh_guid, &gh.gh_guid); 258ad6c5e72Skrw 2592a536aa2Skrw return 0; 260fba7235cSkrw } 261fba7235cSkrw 262fba7235cSkrw int 263032115fcSkrw get_partition_table(void) 264fba7235cSkrw { 2652de77560Skrw struct gpt_partition *legp; 266adf35c80Skrw uint64_t gpbytes; 2672de77560Skrw unsigned int pn; 2682de77560Skrw int rslt = -1; 2696c525197Skrw uint32_t gh_part_csum; 270fba7235cSkrw 271fba7235cSkrw DPRINTF("gpt partition table being read from LBA %llu\n", 272ad6c5e72Skrw gh.gh_part_lba); 273fba7235cSkrw 274ad6c5e72Skrw gpbytes = gh.gh_part_num * gh.gh_part_size; 275fba7235cSkrw 2762de77560Skrw legp = calloc(1, gpbytes); 2772de77560Skrw if (legp == NULL) 2782de77560Skrw err(1, "legp"); 279fba7235cSkrw 2802de77560Skrw if (DISK_readbytes(legp, gh.gh_part_lba, gpbytes)) 2812de77560Skrw goto done; 2822de77560Skrw gh_part_csum = crc32((unsigned char *)legp, gpbytes); 2832de77560Skrw 2844b0a6a04Skrw if (gh_part_csum != gh.gh_part_csum) { 285461ffcadSkrw DPRINTF("gpt partition table checksum: expected 0x%x, " 286ad6c5e72Skrw "got 0x%x\n", gh.gh_part_csum, gh_part_csum); 2874b0a6a04Skrw /* Accept wrong-endian checksum. */ 2884b0a6a04Skrw if (swap32(gh_part_csum) != gh.gh_part_csum) 2892de77560Skrw goto done; 290fba7235cSkrw } 291fba7235cSkrw 2922de77560Skrw memset(&gp, 0, sizeof(gp)); 2932de77560Skrw for (pn = 0; pn < gh.gh_part_num; pn++) { 2942de77560Skrw uuid_dec_le(&legp[pn].gp_type, &gp[pn].gp_type); 2952de77560Skrw uuid_dec_le(&legp[pn].gp_guid, &gp[pn].gp_guid); 2962de77560Skrw gp[pn].gp_lba_start = letoh64(legp[pn].gp_lba_start); 2972de77560Skrw gp[pn].gp_lba_end = letoh64(legp[pn].gp_lba_end); 2982de77560Skrw gp[pn].gp_attrs = letoh64(legp[pn].gp_attrs); 2992de77560Skrw memcpy(gp[pn].gp_name, legp[pn].gp_name, 3002de77560Skrw sizeof(gp[pn].gp_name)); 3012de77560Skrw } 3022de77560Skrw rslt = 0; 3032de77560Skrw 3042de77560Skrw done: 3052de77560Skrw free(legp); 3062de77560Skrw return rslt; 307fba7235cSkrw } 308fba7235cSkrw 309afd1db78Skrw int 310859be6c9Skrw GPT_read(const int which) 311fba7235cSkrw { 312afd1db78Skrw int error; 313afd1db78Skrw 314dfcac45eSkrw error = MBR_read(0, 0, &gmbr); 315afd1db78Skrw if (error) 316afd1db78Skrw goto done; 31742cf3a9bSkrw error = protective_mbr(&gmbr); 31842cf3a9bSkrw if (error == -1) 31942cf3a9bSkrw goto done; 320fba7235cSkrw 321dcd4cc8aSkrw switch (which) { 322dcd4cc8aSkrw case PRIMARYGPT: 323afd1db78Skrw error = get_header(GPTSECTOR); 324dcd4cc8aSkrw break; 325dcd4cc8aSkrw case SECONDARYGPT: 326afd1db78Skrw error = get_header(DL_GETDSIZE(&dl) - 1); 327dcd4cc8aSkrw break; 328dcd4cc8aSkrw case ANYGPT: 329afd1db78Skrw error = get_header(GPTSECTOR); 330afd1db78Skrw if (error != 0 || get_partition_table() != 0) 331afd1db78Skrw error = get_header(DL_GETDSIZE(&dl) - 1); 332dcd4cc8aSkrw break; 333dcd4cc8aSkrw default: 334afd1db78Skrw return -1; 335dcd4cc8aSkrw } 336dcd4cc8aSkrw 337afd1db78Skrw if (error == 0) 338afd1db78Skrw error = get_partition_table(); 339fba7235cSkrw 340afd1db78Skrw done: 341afd1db78Skrw if (error != 0) { 3420df3379fSkrw /* No valid GPT found. Zap any artifacts. */ 343dfcac45eSkrw memset(&gmbr, 0, sizeof(gmbr)); 3440df3379fSkrw memset(&gh, 0, sizeof(gh)); 3450df3379fSkrw memset(&gp, 0, sizeof(gp)); 346fba7235cSkrw } 347afd1db78Skrw 348afd1db78Skrw return error; 349dcd4cc8aSkrw } 350fba7235cSkrw 351fba7235cSkrw void 352859be6c9Skrw GPT_print(const char *units, const int verbosity) 353fba7235cSkrw { 3543e9b7d6bSkrw const struct unit_type *ut; 3553e9b7d6bSkrw const int secsize = dl.d_secsize; 356fba7235cSkrw char *guidstr = NULL; 357fba7235cSkrw double size; 358db53e521Skrw unsigned int pn; 359351f0068Skrw uint32_t status; 360fba7235cSkrw 3612cdacd27Skrw #ifdef DEBUG 3622cdacd27Skrw char *p; 363e42a96d8Skrw uint64_t sig; 364db53e521Skrw unsigned int i; 3652cdacd27Skrw 366ad6c5e72Skrw sig = htole64(gh.gh_sig); 367ad6c5e72Skrw p = (char *)&sig; 3682cdacd27Skrw 3692cdacd27Skrw printf("gh_sig : "); 370ad6c5e72Skrw for (i = 0; i < sizeof(sig); i++) 3712cdacd27Skrw printf("%c", isprint((unsigned char)p[i]) ? p[i] : '?'); 3722cdacd27Skrw printf(" ("); 373ad6c5e72Skrw for (i = 0; i < sizeof(sig); i++) { 3742cdacd27Skrw printf("%02x", p[i]); 375ad6c5e72Skrw if ((i + 1) < sizeof(sig)) 3762cdacd27Skrw printf(":"); 3772cdacd27Skrw } 3782cdacd27Skrw printf(")\n"); 379ad6c5e72Skrw printf("gh_rev : %u\n", gh.gh_rev); 380ad6c5e72Skrw printf("gh_size : %u (%zd)\n", gh.gh_size, sizeof(gh)); 381ad6c5e72Skrw printf("gh_csum : 0x%x\n", gh.gh_csum); 382ad6c5e72Skrw printf("gh_rsvd : %u\n", gh.gh_rsvd); 383ad6c5e72Skrw printf("gh_lba_self : %llu\n", gh.gh_lba_self); 384ad6c5e72Skrw printf("gh_lba_alt : %llu\n", gh.gh_lba_alt); 385ad6c5e72Skrw printf("gh_lba_start : %llu\n", gh.gh_lba_start); 386ad6c5e72Skrw printf("gh_lba_end : %llu\n", gh.gh_lba_end); 3872cdacd27Skrw p = NULL; 3882cdacd27Skrw uuid_to_string(&gh.gh_guid, &p, &status); 3892cdacd27Skrw printf("gh_gh_guid : %s\n", (status == uuid_s_ok) ? p : "<invalid>"); 3902cdacd27Skrw free(p); 391ad6c5e72Skrw printf("gh_gh_part_lba : %llu\n", gh.gh_part_lba); 392ad6c5e72Skrw printf("gh_gh_part_num : %u (%zu)\n", gh.gh_part_num, nitems(gp)); 393ad6c5e72Skrw printf("gh_gh_part_size: %u (%zu)\n", gh.gh_part_size, sizeof(gp[0])); 394ad6c5e72Skrw printf("gh_gh_part_csum: 0x%x\n", gh.gh_part_csum); 3952cdacd27Skrw printf("\n"); 3962cdacd27Skrw #endif /* DEBUG */ 3972cdacd27Skrw 3983e9b7d6bSkrw size = units_size(units, DL_GETDSIZE(&dl), &ut); 39977db81deSkrw printf("Disk: %s Usable LBA: %llu to %llu [%.0f ", 400ad6c5e72Skrw disk.dk_name, gh.gh_lba_start, gh.gh_lba_end, size); 4013e9b7d6bSkrw if (ut->ut_conversion == 0 && secsize != DEV_BSIZE) 402fba7235cSkrw printf("%d-byte ", secsize); 4033e9b7d6bSkrw printf("%s]\n", ut->ut_lname); 404fba7235cSkrw 4053bbc645fSkrw if (verbosity == VERBOSE) { 40677db81deSkrw printf("GUID: "); 407ad6c5e72Skrw uuid_to_string(&gh.gh_guid, &guidstr, &status); 40877db81deSkrw if (status == uuid_s_ok) 40977db81deSkrw printf("%s\n", guidstr); 41077db81deSkrw else 41177db81deSkrw printf("<invalid header GUID>\n"); 41277db81deSkrw free(guidstr); 41377db81deSkrw } 414fba7235cSkrw 41577db81deSkrw GPT_print_parthdr(verbosity); 4162de77560Skrw for (pn = 0; pn < gh.gh_part_num; pn++) { 4172de77560Skrw if (uuid_is_nil(&gp[pn].gp_type, NULL)) 418fba7235cSkrw continue; 4192de77560Skrw GPT_print_part(pn, units, verbosity); 420fba7235cSkrw } 421fba7235cSkrw } 422fba7235cSkrw 423fba7235cSkrw void 424859be6c9Skrw GPT_print_parthdr(const int verbosity) 425fba7235cSkrw { 42677db81deSkrw printf(" #: type " 42777db81deSkrw " [ start: size ]\n"); 4283bbc645fSkrw if (verbosity == VERBOSE) 42977db81deSkrw printf(" guid name\n"); 43077db81deSkrw printf("--------------------------------------------------------" 43177db81deSkrw "----------------\n"); 432fba7235cSkrw } 433fba7235cSkrw 434fba7235cSkrw void 435eea9397aSkrw GPT_print_part(const unsigned int pn, const char *units, const int verbosity) 436fba7235cSkrw { 4373e9b7d6bSkrw const struct unit_type *ut; 438fba7235cSkrw char *guidstr = NULL; 439fba7235cSkrw double size; 44095a0034fSkrw uint64_t attrs, end, start; 441351f0068Skrw uint32_t status; 442fba7235cSkrw 443ccf52da1Skrw start = gp[pn].gp_lba_start; 444ccf52da1Skrw end = gp[pn].gp_lba_end; 445ccf52da1Skrw size = units_size(units, (start > end) ? 0 : end - start + 1, &ut); 446ccf52da1Skrw 44795a0034fSkrw printf(" %3u: %-36s [%12lld: %12.0f%s]\n", pn, 448d8f6db85Skrw PRT_uuid_to_desc(&gp[pn].gp_type), start, size, ut->ut_abbr); 449fba7235cSkrw 4503bbc645fSkrw if (verbosity == VERBOSE) { 4512de77560Skrw uuid_to_string(&gp[pn].gp_guid, &guidstr, &status); 452fba7235cSkrw if (status != uuid_s_ok) 453fba7235cSkrw printf(" <invalid partition guid> "); 454fba7235cSkrw else 45577db81deSkrw printf(" %-36s ", guidstr); 4568f546ed6Skrw printf("%s\n", name_to_string(pn)); 457fba7235cSkrw free(guidstr); 45895a0034fSkrw attrs = gp[pn].gp_attrs; 45995a0034fSkrw if (attrs) { 46095a0034fSkrw printf(" Attributes: (0x%016llx) ", attrs); 46195a0034fSkrw if (attrs & GPTPARTATTR_REQUIRED) 46295a0034fSkrw printf("Required " ); 46395a0034fSkrw if (attrs & GPTPARTATTR_IGNORE) 46495a0034fSkrw printf("Ignore "); 46595a0034fSkrw if (attrs & GPTPARTATTR_BOOTABLE) 46695a0034fSkrw printf("Bootable "); 4675f095273Skrw if (attrs & GPTPARTATTR_MS_READONLY) 468d0f0c904Skrw printf("MSReadOnly " ); 4695f095273Skrw if (attrs & GPTPARTATTR_MS_SHADOW) 470d0f0c904Skrw printf("MSShadow "); 4715f095273Skrw if (attrs & GPTPARTATTR_MS_HIDDEN) 472d0f0c904Skrw printf("MSHidden "); 4735f095273Skrw if (attrs & GPTPARTATTR_MS_NOAUTOMOUNT) 474d0f0c904Skrw printf("MSNoAutoMount "); 47595a0034fSkrw printf("\n"); 47695a0034fSkrw } 47777db81deSkrw } 478ccf52da1Skrw 479c4840cb2Skrw if (uuid_is_nil(&gp[pn].gp_type, NULL) == 0) { 480ccf52da1Skrw if (start > end) 481ccf52da1Skrw printf("partition %u first LBA is > last LBA\n", pn); 482ccf52da1Skrw if (start < gh.gh_lba_start || end > gh.gh_lba_end) 483c4840cb2Skrw printf("partition %u extends beyond usable LBA range " 484c4840cb2Skrw "of %s\n", pn, disk.dk_name); 485c4840cb2Skrw } 486fba7235cSkrw } 487fba7235cSkrw 488fba7235cSkrw int 48965deb39bSkrw find_partition(const uint8_t *beuuid) 49065deb39bSkrw { 4912de77560Skrw struct uuid uuid; 4926c98a3deSkrw unsigned int pn; 49365deb39bSkrw 49465deb39bSkrw uuid_dec_be(beuuid, &uuid); 49565deb39bSkrw 4966c98a3deSkrw for (pn = 0; pn < gh.gh_part_num; pn++) { 4972de77560Skrw if (uuid_compare(&gp[pn].gp_type, &uuid, NULL) == 0) 49865deb39bSkrw return pn; 49965deb39bSkrw } 50065deb39bSkrw return -1; 50165deb39bSkrw } 50265deb39bSkrw 50365deb39bSkrw int 504534ba684Skrw add_partition(const uint8_t *beuuid, const char *name, uint64_t sectors) 505534ba684Skrw { 5062de77560Skrw struct uuid uuid; 507534ba684Skrw int rslt; 5085ef2e3e1Skrw uint64_t end, freesectors, start; 5096c98a3deSkrw uint32_t status, pn; 510534ba684Skrw 511534ba684Skrw uuid_dec_be(beuuid, &uuid); 512534ba684Skrw 5136c98a3deSkrw for (pn = 0; pn < gh.gh_part_num; pn++) { 514534ba684Skrw if (uuid_is_nil(&gp[pn].gp_type, NULL)) 515534ba684Skrw break; 516534ba684Skrw } 5176c98a3deSkrw if (pn == gh.gh_part_num) 518534ba684Skrw goto done; 519534ba684Skrw 520534ba684Skrw rslt = lba_free(&start, &end); 521534ba684Skrw if (rslt == -1) 522534ba684Skrw goto done; 523534ba684Skrw 524893a2455Skrw if (start % BLOCKALIGNMENT) 525893a2455Skrw start += (BLOCKALIGNMENT - start % BLOCKALIGNMENT); 526534ba684Skrw if (start >= end) 527534ba684Skrw goto done; 528534ba684Skrw 529534ba684Skrw freesectors = end - start + 1; 530534ba684Skrw 531534ba684Skrw if (sectors == 0) 532534ba684Skrw sectors = freesectors; 533534ba684Skrw 534534ba684Skrw if (freesectors < sectors) 535534ba684Skrw goto done; 536534ba684Skrw else if (freesectors > sectors) 537534ba684Skrw end = start + sectors - 1; 538534ba684Skrw 5392de77560Skrw gp[pn].gp_type = uuid; 5402de77560Skrw gp[pn].gp_lba_start = start; 5412de77560Skrw gp[pn].gp_lba_end = end; 542a66d82b0Skrw string_to_name(pn, name); 543534ba684Skrw 5442de77560Skrw uuid_create(&gp[pn].gp_guid, &status); 5452de77560Skrw if (status == uuid_s_ok) 546534ba684Skrw return 0; 547534ba684Skrw 548534ba684Skrw done: 5496c98a3deSkrw if (pn != gh.gh_part_num) 550534ba684Skrw memset(&gp[pn], 0, sizeof(gp[pn])); 551534ba684Skrw printf("unable to add %s\n", name); 55239351f7aSkrw return -1; 553534ba684Skrw } 554534ba684Skrw 555534ba684Skrw int 5564b0ba6ccSkrw init_gh(void) 5571cd24417Skrw { 5584b0ba6ccSkrw struct gpt_header oldgh; 5591629ab0bSkrw const int secsize = dl.d_secsize; 5604b0ba6ccSkrw int needed; 5611cd24417Skrw uint32_t status; 5621cd24417Skrw 5634b0ba6ccSkrw memcpy(&oldgh, &gh, sizeof(oldgh)); 564f0d03845Skrw memset(&gh, 0, sizeof(gh)); 565dfcac45eSkrw memset(&gmbr, 0, sizeof(gmbr)); 566dfcac45eSkrw 567dfcac45eSkrw /* XXX Do we need the boot code? UEFI spec & Apple says no. */ 568f43a9f23Skrw memcpy(gmbr.mbr_code, default_dmbr.dmbr_boot, sizeof(gmbr.mbr_code)); 569dfcac45eSkrw gmbr.mbr_prt[0].prt_id = DOSPTYP_EFI; 570dfcac45eSkrw gmbr.mbr_prt[0].prt_bs = 1; 571dfcac45eSkrw gmbr.mbr_prt[0].prt_ns = UINT32_MAX; 572dfcac45eSkrw gmbr.mbr_signature = DOSMBR_SIGNATURE; 5731cd24417Skrw 5746bbd8ae9Skrw needed = sizeof(gp) / secsize + 2; 5754b0ba6ccSkrw 576893a2455Skrw if (needed % BLOCKALIGNMENT) 577893a2455Skrw needed += (needed - (needed % BLOCKALIGNMENT)); 5781cd24417Skrw 579ad6c5e72Skrw gh.gh_sig = GPTSIGNATURE; 580ad6c5e72Skrw gh.gh_rev = GPTREVISION; 581ad6c5e72Skrw gh.gh_size = GPTMINHDRSIZE; 5821cd24417Skrw gh.gh_csum = 0; 5831cd24417Skrw gh.gh_rsvd = 0; 584ad6c5e72Skrw gh.gh_lba_self = 1; 585ad6c5e72Skrw gh.gh_lba_alt = DL_GETDSIZE(&dl) - 1; 586ad6c5e72Skrw gh.gh_lba_start = needed; 587ad6c5e72Skrw gh.gh_lba_end = DL_GETDSIZE(&dl) - needed; 588ad6c5e72Skrw uuid_create(&gh.gh_guid, &status); 5894b0ba6ccSkrw if (status != uuid_s_ok) { 5904b0ba6ccSkrw memcpy(&gh, &oldgh, sizeof(gh)); 59139351f7aSkrw return -1; 5924b0ba6ccSkrw } 593ad6c5e72Skrw gh.gh_part_lba = 2; 594ad6c5e72Skrw gh.gh_part_num = NGPTPARTITIONS; 595ad6c5e72Skrw gh.gh_part_size = GPTMINPARTSIZE; 596ad6c5e72Skrw gh.gh_part_csum = 0; 5974b0ba6ccSkrw 5984b0ba6ccSkrw return 0; 5994b0ba6ccSkrw } 6004b0ba6ccSkrw 6014b0ba6ccSkrw int 602199eafeaSkrw init_gp(const int how) 6034b0ba6ccSkrw { 6048c10a749Skrw struct gpt_partition oldgp[NGPTPARTITIONS]; 6054b0ba6ccSkrw const uint8_t gpt_uuid_efi_system[] = GPT_UUID_EFI_SYSTEM; 6064b0ba6ccSkrw const uint8_t gpt_uuid_openbsd[] = GPT_UUID_OPENBSD; 60765deb39bSkrw uint64_t prt_ns; 60895e8765cSkrw int pn, rslt; 6094b0ba6ccSkrw 6104b0ba6ccSkrw memcpy(&oldgp, &gp, sizeof(oldgp)); 611c2fbfd6dSkrw if (how == GHANDGP) 612f0d03845Skrw memset(&gp, 0, sizeof(gp)); 61395e8765cSkrw else { 614ad6c5e72Skrw for (pn = 0; pn < gh.gh_part_num; pn++) { 615490259bdSkrw if (PRT_protected_uuid(&gp[pn].gp_type) || 61695a0034fSkrw (gp[pn].gp_attrs & GPTPARTATTR_REQUIRED)) 61795e8765cSkrw continue; 61895e8765cSkrw memset(&gp[pn], 0, sizeof(gp[pn])); 61995e8765cSkrw } 62095e8765cSkrw } 6211cd24417Skrw 622534ba684Skrw rslt = 0; 623199eafeaSkrw if (disk.dk_bootprt.prt_ns > 0) { 62465deb39bSkrw pn = find_partition(gpt_uuid_efi_system); 62565deb39bSkrw if (pn == -1) { 62665deb39bSkrw rslt = add_partition(gpt_uuid_efi_system, 62765deb39bSkrw "EFI System Area", disk.dk_bootprt.prt_ns); 62865deb39bSkrw } else { 62965deb39bSkrw prt_ns = gp[pn].gp_lba_end - gp[pn].gp_lba_start + 1; 63065deb39bSkrw if (prt_ns < disk.dk_bootprt.prt_ns) { 63165deb39bSkrw printf("EFI System Area < %llu sectors\n", 632199eafeaSkrw disk.dk_bootprt.prt_ns); 63365deb39bSkrw rslt = -1; 63465deb39bSkrw } 63565deb39bSkrw } 6361cd24417Skrw } 637534ba684Skrw if (rslt == 0) 638534ba684Skrw rslt = add_partition(gpt_uuid_openbsd, "OpenBSD Area", 0); 639fba7235cSkrw 6404b0ba6ccSkrw if (rslt != 0) 6414b0ba6ccSkrw memcpy(&gp, &oldgp, sizeof(gp)); 6424b0ba6ccSkrw 6434b0ba6ccSkrw return rslt; 6444b0ba6ccSkrw } 6454b0ba6ccSkrw 6464b0ba6ccSkrw int 647199eafeaSkrw GPT_init(const int how) 6484b0ba6ccSkrw { 649c2fbfd6dSkrw int rslt = 0; 6504b0ba6ccSkrw 651c2fbfd6dSkrw if (how == GHANDGP) 6524b0ba6ccSkrw rslt = init_gh(); 6534b0ba6ccSkrw if (rslt == 0) 654199eafeaSkrw rslt = init_gp(how); 6554b0ba6ccSkrw 656534ba684Skrw return rslt; 6571cd24417Skrw } 6581cd24417Skrw 659c94b0391Skrw void 660c94b0391Skrw GPT_zap_headers(void) 661c94b0391Skrw { 662adf35c80Skrw struct gpt_header legh; 663c94b0391Skrw 664adf35c80Skrw if (DISK_readbytes(&legh, GPTSECTOR, sizeof(legh))) 665c94b0391Skrw return; 666c94b0391Skrw 667adf35c80Skrw if (letoh64(legh.gh_sig) == GPTSIGNATURE) { 668adf35c80Skrw memset(&legh, 0, sizeof(legh)); 669adf35c80Skrw if (DISK_writebytes(&legh, GPTSECTOR, sizeof(legh))) 670605b5690Skrw DPRINTF("Unable to zap GPT header @ sector %d", 671605b5690Skrw GPTSECTOR); 672c94b0391Skrw } 673c94b0391Skrw 674adf35c80Skrw if (DISK_readbytes(&legh, DL_GETDSIZE(&dl) - 1, sizeof(legh))) 675c94b0391Skrw return; 676c94b0391Skrw 677adf35c80Skrw if (letoh64(legh.gh_sig) == GPTSIGNATURE) { 678adf35c80Skrw memset(&legh, 0, GPTMINHDRSIZE); 679adf35c80Skrw if (DISK_writebytes(&legh, DL_GETDSIZE(&dl) - 1, sizeof(legh))) 680605b5690Skrw DPRINTF("Unable to zap GPT header @ sector %llu", 681605b5690Skrw DL_GETDSIZE(&dl) - 1); 682c94b0391Skrw } 683c94b0391Skrw } 684c94b0391Skrw 6851cd24417Skrw int 6860468c08fSkrw GPT_write(void) 6871cd24417Skrw { 688ad6c5e72Skrw struct gpt_header legh; 6892de77560Skrw struct gpt_partition *legp; 690ad6c5e72Skrw uint64_t altgh, altgp; 691605b5690Skrw uint64_t gpbytes, gpsectors; 6922de77560Skrw unsigned int pn; 6932de77560Skrw int rslt = -1; 6941cd24417Skrw 695605b5690Skrw if (MBR_write(&gmbr)) 696605b5690Skrw return -1; 697dfcac45eSkrw 698ad6c5e72Skrw gpbytes = gh.gh_part_num * gh.gh_part_size; 699b7307f09Skrw gpsectors = (gpbytes + dl.d_secsize - 1) / dl.d_secsize; 700153ceb9cSkrw 7011cd24417Skrw altgh = DL_GETDSIZE(&dl) - 1; 702605b5690Skrw altgp = altgh - gpsectors; 7031cd24417Skrw 704ad6c5e72Skrw legh.gh_sig = htole64(GPTSIGNATURE); 705ad6c5e72Skrw legh.gh_rev = htole32(GPTREVISION); 706ad6c5e72Skrw legh.gh_size = htole32(GPTMINHDRSIZE); 707ad6c5e72Skrw legh.gh_rsvd = 0; 708ad6c5e72Skrw legh.gh_lba_self = htole64(GPTSECTOR); 709ad6c5e72Skrw legh.gh_lba_alt = htole64(altgh); 710ad6c5e72Skrw legh.gh_lba_start = htole64(gh.gh_lba_start); 711ad6c5e72Skrw legh.gh_lba_end = htole64(gh.gh_lba_end); 712ad6c5e72Skrw uuid_enc_le(&legh.gh_guid, &gh.gh_guid); 713ad6c5e72Skrw legh.gh_part_lba = htole64(GPTSECTOR + 1); 714ad6c5e72Skrw legh.gh_part_num = htole32(gh.gh_part_num); 715ad6c5e72Skrw legh.gh_part_size = htole32(GPTMINPARTSIZE); 7162de77560Skrw 7172de77560Skrw legp = calloc(1, gpbytes); 7182de77560Skrw if (legp == NULL) 7192de77560Skrw err(1, "legp"); 7202de77560Skrw 7212de77560Skrw for (pn = 0; pn < gh.gh_part_num; pn++) { 7222de77560Skrw uuid_enc_le(&legp[pn].gp_type, &gp[pn].gp_type); 7232de77560Skrw uuid_enc_le(&legp[pn].gp_guid, &gp[pn].gp_guid); 7242de77560Skrw legp[pn].gp_lba_start = htole64(gp[pn].gp_lba_start); 7252de77560Skrw legp[pn].gp_lba_end = htole64(gp[pn].gp_lba_end); 7262de77560Skrw legp[pn].gp_attrs = htole64(gp[pn].gp_attrs); 7272de77560Skrw memcpy(legp[pn].gp_name, gp[pn].gp_name, 7282de77560Skrw sizeof(legp[pn].gp_name)); 7292de77560Skrw } 7302de77560Skrw legh.gh_part_csum = htole32(crc32((unsigned char *)legp, gpbytes)); 7312de77560Skrw legh.gh_csum = 0; 732ad6c5e72Skrw legh.gh_csum = htole32(crc32((unsigned char *)&legh, gh.gh_size)); 733adf35c80Skrw 734adf35c80Skrw if (DISK_writebytes(&legh, GPTSECTOR, gh.gh_size) || 7352de77560Skrw DISK_writebytes(legp, GPTSECTOR + 1, gpbytes)) 7362de77560Skrw goto done; 7371cd24417Skrw 738ad6c5e72Skrw legh.gh_lba_self = htole64(altgh); 739ad6c5e72Skrw legh.gh_lba_alt = htole64(GPTSECTOR); 740ad6c5e72Skrw legh.gh_part_lba = htole64(altgp); 741ad6c5e72Skrw legh.gh_csum = 0; 742ad6c5e72Skrw legh.gh_csum = htole32(crc32((unsigned char *)&legh, gh.gh_size)); 7431cd24417Skrw 744adf35c80Skrw if (DISK_writebytes(&legh, altgh, gh.gh_size) || 745adf35c80Skrw DISK_writebytes(&gp, altgp, gpbytes)) 7462de77560Skrw goto done; 7471cd24417Skrw 74834be3939Skrw /* Refresh in-kernel disklabel from the updated disk information. */ 749605b5690Skrw if (ioctl(disk.dk_fd, DIOCRLDINFO, 0) == -1) 750605b5690Skrw warn("DIOCRLDINFO"); 7512de77560Skrw rslt = 0; 75234be3939Skrw 7532de77560Skrw done: 7542de77560Skrw free(legp); 7552de77560Skrw return rslt; 7561cd24417Skrw } 757c2d03168Skrw 758c2d03168Skrw int 759c2d03168Skrw gp_lba_start_cmp(const void *e1, const void *e2) 760c2d03168Skrw { 761c2d03168Skrw struct gpt_partition *p1 = *(struct gpt_partition **)e1; 762c2d03168Skrw struct gpt_partition *p2 = *(struct gpt_partition **)e2; 763b87d3542Skrw uint64_t o1; 764b87d3542Skrw uint64_t o2; 765c2d03168Skrw 7662de77560Skrw o1 = p1->gp_lba_start; 7672de77560Skrw o2 = p2->gp_lba_start; 768c2d03168Skrw 769c2d03168Skrw if (o1 < o2) 770c2d03168Skrw return -1; 771c2d03168Skrw else if (o1 > o2) 772c2d03168Skrw return 1; 773c2d03168Skrw else 774c2d03168Skrw return 0; 775c2d03168Skrw } 776c2d03168Skrw 7778c6d22aeSkrw const struct gpt_partition * const * 778c2d03168Skrw sort_gpt(void) 779c2d03168Skrw { 7808c6d22aeSkrw static const struct gpt_partition *sgp[NGPTPARTITIONS+2]; 7812de77560Skrw unsigned int i, pn; 782c2d03168Skrw 783c2d03168Skrw memset(sgp, 0, sizeof(sgp)); 784c2d03168Skrw 7852de77560Skrw i = 0; 7862de77560Skrw for (pn = 0; pn < gh.gh_part_num; pn++) { 7872de77560Skrw if (gp[pn].gp_lba_start >= gh.gh_lba_start) 7882de77560Skrw sgp[i++] = &gp[pn]; 789c2d03168Skrw } 790c2d03168Skrw 7912de77560Skrw if (i > 1) { 7922de77560Skrw if (mergesort(sgp, i, sizeof(sgp[0]), gp_lba_start_cmp) == -1) { 793c2d03168Skrw printf("unable to sort gpt by lba start\n"); 794c2d03168Skrw return NULL; 795c2d03168Skrw } 796c2d03168Skrw } 797c2d03168Skrw 7982a536aa2Skrw return sgp; 799c2d03168Skrw } 800c2d03168Skrw 801c2d03168Skrw int 80238678f29Skrw lba_free(uint64_t *start, uint64_t *end) 803c2d03168Skrw { 8048c6d22aeSkrw const struct gpt_partition * const *sgp; 805c2d03168Skrw uint64_t bs, bigbs, nextbs, ns; 806c2d03168Skrw unsigned int i; 807c2d03168Skrw 808c2d03168Skrw sgp = sort_gpt(); 809c2d03168Skrw if (sgp == NULL) 810c2d03168Skrw return -1; 81138678f29Skrw 812ad6c5e72Skrw bs = gh.gh_lba_start; 813ad6c5e72Skrw ns = gh.gh_lba_end - bs + 1; 81438678f29Skrw 815c2d03168Skrw if (sgp[0] != NULL) { 816c2d03168Skrw bigbs = bs; 817c2d03168Skrw ns = 0; 818c2d03168Skrw for (i = 0; sgp[i] != NULL; i++) { 8192de77560Skrw nextbs = sgp[i]->gp_lba_start; 820c2d03168Skrw if (bs < nextbs && ns < nextbs - bs) { 821c2d03168Skrw ns = nextbs - bs; 822c2d03168Skrw bigbs = bs; 823c2d03168Skrw } 8242de77560Skrw bs = sgp[i]->gp_lba_end + 1; 825c2d03168Skrw } 826ad6c5e72Skrw nextbs = gh.gh_lba_end + 1; 827c2d03168Skrw if (bs < nextbs && ns < nextbs - bs) { 828c2d03168Skrw ns = nextbs - bs; 829c2d03168Skrw bigbs = bs; 830c2d03168Skrw } 831c2d03168Skrw bs = bigbs; 832c2d03168Skrw } 83338678f29Skrw 83438678f29Skrw if (ns == 0) 83538678f29Skrw return -1; 83638678f29Skrw 83738678f29Skrw if (start != NULL) 83838678f29Skrw *start = bs; 83938678f29Skrw if (end != NULL) 84038678f29Skrw *end = bs + ns - 1; 84138678f29Skrw 84238678f29Skrw return 0; 84338678f29Skrw } 84438678f29Skrw 84538678f29Skrw int 846859be6c9Skrw GPT_get_lba_start(const unsigned int pn) 84738678f29Skrw { 84838678f29Skrw uint64_t bs; 84938678f29Skrw unsigned int i; 85038678f29Skrw int rslt; 85138678f29Skrw 852ad6c5e72Skrw bs = gh.gh_lba_start; 85338678f29Skrw 8542de77560Skrw if (gp[pn].gp_lba_start >= bs) { 8552de77560Skrw bs = gp[pn].gp_lba_start; 85638678f29Skrw } else { 85738678f29Skrw rslt = lba_free(&bs, NULL); 858965f1a17Skrw if (rslt == -1) { 859965f1a17Skrw printf("no space for partition %u\n", pn); 86038678f29Skrw return -1; 861c2d03168Skrw } 862965f1a17Skrw } 863c2d03168Skrw 864ad6c5e72Skrw bs = getuint64("Partition offset", bs, gh.gh_lba_start, gh.gh_lba_end); 865ad6c5e72Skrw for (i = 0; i < gh.gh_part_num; i++) { 866c2d03168Skrw if (i == pn) 867c2d03168Skrw continue; 8682de77560Skrw if (bs >= gp[i].gp_lba_start && bs <= gp[i].gp_lba_end) { 869c2d03168Skrw printf("partition %u can't start inside partition %u\n", 870c2d03168Skrw pn, i); 871c2d03168Skrw return -1; 872c2d03168Skrw } 873c2d03168Skrw } 874c2d03168Skrw 8752de77560Skrw gp[pn].gp_lba_start = bs; 876c2d03168Skrw 877c2d03168Skrw return 0; 878c2d03168Skrw } 879c2d03168Skrw 880c2d03168Skrw int 881859be6c9Skrw GPT_get_lba_end(const unsigned int pn) 882c2d03168Skrw { 8838c6d22aeSkrw const struct gpt_partition * const *sgp; 884c2d03168Skrw uint64_t bs, nextbs, ns; 885c2d03168Skrw unsigned int i; 886c2d03168Skrw 887c2d03168Skrw sgp = sort_gpt(); 888c2d03168Skrw if (sgp == NULL) 889c2d03168Skrw return -1; 890c2d03168Skrw 8912de77560Skrw bs = gp[pn].gp_lba_start; 892ad6c5e72Skrw ns = gh.gh_lba_end - bs + 1; 893c2d03168Skrw for (i = 0; sgp[i] != NULL; i++) { 8942de77560Skrw nextbs = sgp[i]->gp_lba_start; 895c2d03168Skrw if (nextbs > bs) { 896c2d03168Skrw ns = nextbs - bs; 897c2d03168Skrw break; 898c2d03168Skrw } 899c2d03168Skrw } 900c2d03168Skrw ns = getuint64("Partition size", ns, 1, ns); 901c2d03168Skrw 9022de77560Skrw gp[pn].gp_lba_end = bs + ns - 1; 903c2d03168Skrw 904c2d03168Skrw return 0; 905c2d03168Skrw } 906543185b3Skrw 907a66d82b0Skrw int 908a66d82b0Skrw GPT_get_name(const unsigned int pn) 909a66d82b0Skrw { 910a66d82b0Skrw char name[GPTPARTNAMESIZE + 1]; 911a66d82b0Skrw 912a66d82b0Skrw printf("Partition name: [%s] ", name_to_string(pn)); 913a66d82b0Skrw string_from_line(name, sizeof(name), UNTRIMMED); 914a66d82b0Skrw 915a66d82b0Skrw switch (strlen(name)) { 916a66d82b0Skrw case 0: 917a66d82b0Skrw break; 918a66d82b0Skrw case GPTPARTNAMESIZE: 919a66d82b0Skrw printf("partition name must be < %d characters\n", 920a66d82b0Skrw GPTPARTNAMESIZE); 921a66d82b0Skrw return -1; 922a66d82b0Skrw default: 923a66d82b0Skrw string_to_name(pn, name); 924a66d82b0Skrw break; 925a66d82b0Skrw } 926a66d82b0Skrw 927a66d82b0Skrw return 0; 928a66d82b0Skrw } 929a66d82b0Skrw 930543185b3Skrw /* 931543185b3Skrw * Adapted from Hacker's Delight crc32b(). 932543185b3Skrw * 933543185b3Skrw * To quote http://www.hackersdelight.org/permissions.htm : 934543185b3Skrw * 935543185b3Skrw * "You are free to use, copy, and distribute any of the code on 936543185b3Skrw * this web site, whether modified by you or not. You need not give 937543185b3Skrw * attribution. This includes the algorithms (some of which appear 938543185b3Skrw * in Hacker's Delight), the Hacker's Assistant, and any code submitted 939543185b3Skrw * by readers. Submitters implicitly agree to this." 940543185b3Skrw */ 941543185b3Skrw uint32_t 942543185b3Skrw crc32(const u_char *buf, const uint32_t size) 943543185b3Skrw { 944543185b3Skrw int j; 945543185b3Skrw uint32_t i, byte, crc, mask; 946543185b3Skrw 947543185b3Skrw crc = 0xFFFFFFFF; 948543185b3Skrw 949543185b3Skrw for (i = 0; i < size; i++) { 950543185b3Skrw byte = buf[i]; /* Get next byte. */ 951543185b3Skrw crc = crc ^ byte; 952543185b3Skrw for (j = 7; j >= 0; j--) { /* Do eight times. */ 953543185b3Skrw mask = -(crc & 1); 954543185b3Skrw crc = (crc >> 1) ^ (0xEDB88320 & mask); 955543185b3Skrw } 956543185b3Skrw } 957543185b3Skrw 958543185b3Skrw return ~crc; 959543185b3Skrw } 960