1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * ptgen - partition table generator 4 * Copyright (C) 2006 by Felix Fietkau <nbd@nbd.name> 5 * 6 * uses parts of afdisk 7 * Copyright (C) 2002 by David Roetzel <david@roetzel.de> 8 * 9 * UUID/GUID definition stolen from kernel/include/uapi/linux/uuid.h 10 * Copyright (C) 2010, Intel Corp. Huang Ying <ying.huang@intel.com> 11 */ 12 13 #include <byteswap.h> 14 #include <sys/types.h> 15 #include <sys/stat.h> 16 #include <string.h> 17 #include <unistd.h> 18 #include <stdlib.h> 19 #include <stdio.h> 20 #include <stdint.h> 21 #include <stdbool.h> 22 #include <ctype.h> 23 #include <inttypes.h> 24 #include <fcntl.h> 25 #include <stdint.h> 26 #include "cyg_crc.h" 27 28 #if __BYTE_ORDER == __BIG_ENDIAN 29 #define cpu_to_le16(x) bswap_16(x) 30 #define cpu_to_le32(x) bswap_32(x) 31 #define cpu_to_le64(x) bswap_64(x) 32 #elif __BYTE_ORDER == __LITTLE_ENDIAN 33 #define cpu_to_le16(x) (x) 34 #define cpu_to_le32(x) (x) 35 #define cpu_to_le64(x) (x) 36 #else 37 #error unknown endianness! 38 #endif 39 40 #define swap(a, b) \ 41 do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) 42 43 #define BIT(_x) (1UL << (_x)) 44 45 typedef struct { 46 uint8_t b[16]; 47 } guid_t; 48 49 #define GUID_INIT(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ 50 ((guid_t) \ 51 {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ 52 (b) & 0xff, ((b) >> 8) & 0xff, \ 53 (c) & 0xff, ((c) >> 8) & 0xff, \ 54 (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) 55 56 #define GUID_STRING_LENGTH 36 57 58 #define GPT_SIGNATURE 0x5452415020494645ULL 59 #define GPT_REVISION 0x00010000 60 61 #define GUID_PARTITION_SYSTEM \ 62 GUID_INIT( 0xC12A7328, 0xF81F, 0x11d2, \ 63 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B) 64 65 #define GUID_PARTITION_BASIC_DATA \ 66 GUID_INIT( 0xEBD0A0A2, 0xB9E5, 0x4433, \ 67 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7) 68 69 #define GUID_PARTITION_BIOS_BOOT \ 70 GUID_INIT( 0x21686148, 0x6449, 0x6E6F, \ 71 0x74, 0x4E, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49) 72 73 #define GUID_PARTITION_CHROME_OS_KERNEL \ 74 GUID_INIT( 0xFE3A2A5D, 0x4F32, 0x41A7, \ 75 0xB7, 0x25, 0xAC, 0xCC, 0x32, 0x85, 0xA3, 0x09) 76 77 #define GUID_PARTITION_LINUX_FIT_GUID \ 78 GUID_INIT( 0xcae9be83, 0xb15f, 0x49cc, \ 79 0x86, 0x3f, 0x08, 0x1b, 0x74, 0x4a, 0x2d, 0x93) 80 81 #define GUID_PARTITION_LINUX_FS_GUID \ 82 GUID_INIT( 0x0fc63daf, 0x8483, 0x4772, \ 83 0x8e, 0x79, 0x3d, 0x69, 0xd8, 0x47, 0x7d, 0xe4) 84 85 #define GUID_PARTITION_SIFIVE_SPL \ 86 GUID_INIT( 0x5b193300, 0xfc78, 0x40cd, \ 87 0x80, 0x02, 0xe8, 0x6c, 0x45, 0x58, 0x0b, 0x47) 88 89 #define GUID_PARTITION_SIFIVE_UBOOT \ 90 GUID_INIT( 0x2e54b353, 0x1271, 0x4842, \ 91 0x80, 0x6f, 0xe4, 0x36, 0xd6, 0xaf, 0x69, 0x85) 92 93 #define GPT_HEADER_SIZE 92 94 #define GPT_ENTRY_SIZE 128 95 #define GPT_ENTRY_MAX 128 96 #define GPT_ENTRY_NAME_SIZE 72 97 #define GPT_SIZE GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE 98 99 #define GPT_ATTR_PLAT_REQUIRED BIT(0) 100 #define GPT_ATTR_EFI_IGNORE BIT(1) 101 #define GPT_ATTR_LEGACY_BOOT BIT(2) 102 103 #define GPT_HEADER_SECTOR 1 104 #define GPT_FIRST_ENTRY_SECTOR 2 105 106 #define MBR_ENTRY_MAX 4 107 #define MBR_DISK_SIGNATURE_OFFSET 440 108 #define MBR_PARTITION_ENTRY_OFFSET 446 109 #define MBR_BOOT_SIGNATURE_OFFSET 510 110 111 #define DISK_SECTOR_SIZE 512 112 113 /* Partition table entry */ 114 struct pte { 115 uint8_t active; 116 uint8_t chs_start[3]; 117 uint8_t type; 118 uint8_t chs_end[3]; 119 uint32_t start; 120 uint32_t length; 121 }; 122 123 struct partinfo { 124 unsigned long long actual_start; 125 unsigned long long start; 126 unsigned long long size; 127 int type; 128 int hybrid; 129 char *name; 130 short int required; 131 bool has_guid; 132 guid_t guid; 133 uint64_t gattr; /* GPT partition attributes */ 134 }; 135 136 /* GPT Partition table header */ 137 struct gpth { 138 uint64_t signature; 139 uint32_t revision; 140 uint32_t size; 141 uint32_t crc32; 142 uint32_t reserved; 143 uint64_t self; 144 uint64_t alternate; 145 uint64_t first_usable; 146 uint64_t last_usable; 147 guid_t disk_guid; 148 uint64_t first_entry; 149 uint32_t entry_num; 150 uint32_t entry_size; 151 uint32_t entry_crc32; 152 } __attribute__((packed)); 153 154 /* GPT Partition table entry */ 155 struct gpte { 156 guid_t type; 157 guid_t guid; 158 uint64_t start; 159 uint64_t end; 160 uint64_t attr; 161 char name[GPT_ENTRY_NAME_SIZE]; 162 } __attribute__((packed)); 163 164 165 int verbose = 0; 166 int active = 1; 167 int heads = -1; 168 int sectors = -1; 169 int kb_align = 0; 170 bool ignore_null_sized_partition = false; 171 bool use_guid_partition_table = false; 172 struct partinfo parts[GPT_ENTRY_MAX]; 173 char *filename = NULL; 174 175 int gpt_split_image = false; 176 int gpt_alternate = false; 177 uint64_t gpt_first_entry_sector = GPT_FIRST_ENTRY_SECTOR; 178 uint64_t gpt_last_usable_sector = 0; 179 180 /* 181 * parse the size argument, which is either 182 * a simple number (K assumed) or 183 * K, M or G 184 * 185 * returns the size in KByte 186 */ 187 static long long to_kbytes(const char *string) 188 { 189 int exp = 0; 190 long long result; 191 char *end; 192 193 result = strtoull(string, &end, 0); 194 switch (tolower(*end)) { 195 case 'k' : 196 case '\0' : exp = 0; break; 197 case 'm' : exp = 1; break; 198 case 'g' : exp = 2; break; 199 default: return 0; 200 } 201 202 if (*end) 203 end++; 204 205 if (*end) { 206 fputs("garbage after end of number\n", stderr); 207 return 0; 208 } 209 210 /* result: number * 1024^(exp) */ 211 return result * (1 << (10 * exp)); 212 } 213 214 /* convert the sector number into a CHS value for the partition table */ 215 static void to_chs(long sect, unsigned char chs[3]) 216 { 217 int c,h,s; 218 219 s = (sect % sectors) + 1; 220 sect = sect / sectors; 221 h = sect % heads; 222 sect = sect / heads; 223 c = sect; 224 225 chs[0] = h; 226 chs[1] = s | ((c >> 2) & 0xC0); 227 chs[2] = c & 0xFF; 228 229 return; 230 } 231 232 /* round the sector number up to the next cylinder */ 233 static inline unsigned long round_to_cyl(long sect) 234 { 235 int cyl_size = heads * sectors; 236 237 return sect + cyl_size - (sect % cyl_size); 238 } 239 240 /* round the sector number up to the kb_align boundary */ 241 static inline unsigned long round_to_kb(long sect) { 242 return ((sect - 1) / kb_align + 1) * kb_align; 243 } 244 245 /* Compute a CRC for guid partition table */ 246 static inline unsigned long gpt_crc32(void *buf, unsigned long len) 247 { 248 return cyg_crc32_accumulate(~0L, buf, len) ^ ~0L; 249 } 250 251 /* Parse a guid string to guid_t struct */ 252 static inline int guid_parse(char *buf, guid_t *guid) 253 { 254 char b[4] = {0}; 255 char *p = buf; 256 unsigned i = 0; 257 if (strnlen(buf, GUID_STRING_LENGTH) != GUID_STRING_LENGTH) 258 return -1; 259 for (i = 0; i < sizeof(guid_t); i++) { 260 if (*p == '-') 261 p++; 262 if (*p == '\0') 263 return -1; 264 memcpy(b, p, 2); 265 guid->b[i] = strtol(b, 0, 16); 266 p += 2; 267 } 268 swap(guid->b[0], guid->b[3]); 269 swap(guid->b[1], guid->b[2]); 270 swap(guid->b[4], guid->b[5]); 271 swap(guid->b[6], guid->b[7]); 272 return 0; 273 } 274 275 /* 276 * Map GPT partition types to partition GUIDs. 277 * NB: not all GPT partition types have an equivalent MBR type. 278 */ 279 static inline bool parse_gpt_parttype(const char *type, struct partinfo *part) 280 { 281 if (!strcmp(type, "cros_kernel")) { 282 part->has_guid = true; 283 part->guid = GUID_PARTITION_CHROME_OS_KERNEL; 284 /* Default attributes: bootable kernel. */ 285 part->gattr = (1ULL << 48) | /* priority=1 */ 286 (1ULL << 56); /* success=1 */ 287 return true; 288 } 289 290 if (!strcmp(type, "sifiveu_spl")) { 291 part->has_guid = true; 292 part->guid = GUID_PARTITION_SIFIVE_SPL; 293 return true; 294 } 295 296 if (!strcmp(type, "sifiveu_uboot")) { 297 part->has_guid = true; 298 part->guid = GUID_PARTITION_SIFIVE_UBOOT; 299 return true; 300 } 301 302 return false; 303 } 304 305 /* init an utf-16 string from utf-8 string */ 306 static inline void init_utf16(char *str, uint16_t *buf, unsigned bufsize) 307 { 308 unsigned i, n = 0; 309 for (i = 0; i < bufsize; i++) { 310 if (str[n] == 0x00) { 311 buf[i] = 0x00; 312 return ; 313 } else if ((str[n] & 0x80) == 0x00) {//0xxxxxxx 314 buf[i] = cpu_to_le16(str[n++]); 315 } else if ((str[n] & 0xE0) == 0xC0) {//110xxxxx 316 buf[i] = cpu_to_le16((str[n] & 0x1F) << 6 | (str[n + 1] & 0x3F)); 317 n += 2; 318 } else if ((str[n] & 0xF0) == 0xE0) {//1110xxxx 319 buf[i] = cpu_to_le16((str[n] & 0x0F) << 12 | (str[n + 1] & 0x3F) << 6 | (str[n + 2] & 0x3F)); 320 n += 3; 321 } else { 322 buf[i] = cpu_to_le16('?'); 323 n++; 324 } 325 } 326 } 327 328 /* check the partition sizes and write the partition table */ 329 static int gen_ptable(uint32_t signature, int nr) 330 { 331 struct pte pte[MBR_ENTRY_MAX]; 332 unsigned long long start, len, sect = 0; 333 int i, fd, ret = -1; 334 335 memset(pte, 0, sizeof(struct pte) * MBR_ENTRY_MAX); 336 for (i = 0; i < nr; i++) { 337 if (!parts[i].size) { 338 if (ignore_null_sized_partition) 339 continue; 340 fprintf(stderr, "Invalid size in partition %d!\n", i); 341 return ret; 342 } 343 344 pte[i].active = ((i + 1) == active) ? 0x80 : 0; 345 pte[i].type = parts[i].type; 346 347 start = sect + sectors; 348 if (parts[i].start != 0) { 349 if (parts[i].start * 2 < start) { 350 fprintf(stderr, "Invalid start %lld for partition %d!\n", 351 parts[i].start, i); 352 return ret; 353 } 354 start = parts[i].start * 2; 355 } else if (kb_align != 0) { 356 start = round_to_kb(start); 357 } 358 pte[i].start = cpu_to_le32(start); 359 360 sect = start + parts[i].size * 2; 361 if (kb_align == 0) 362 sect = round_to_cyl(sect); 363 pte[i].length = cpu_to_le32(len = sect - start); 364 365 to_chs(start, pte[i].chs_start); 366 to_chs(start + len - 1, pte[i].chs_end); 367 368 if (verbose) 369 fprintf(stderr, "Partition %d: start=%lld, end=%lld, size=%lld\n", 370 i, 371 start * DISK_SECTOR_SIZE, 372 (start + len) * DISK_SECTOR_SIZE, 373 len * DISK_SECTOR_SIZE); 374 printf("%lld\n", start * DISK_SECTOR_SIZE); 375 printf("%lld\n", len * DISK_SECTOR_SIZE); 376 } 377 378 if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { 379 fprintf(stderr, "Can't open output file '%s'\n",filename); 380 return ret; 381 } 382 383 lseek(fd, MBR_DISK_SIGNATURE_OFFSET, SEEK_SET); 384 if (write(fd, &signature, sizeof(signature)) != sizeof(signature)) { 385 fputs("write failed.\n", stderr); 386 goto fail; 387 } 388 389 lseek(fd, MBR_PARTITION_ENTRY_OFFSET, SEEK_SET); 390 if (write(fd, pte, sizeof(struct pte) * MBR_ENTRY_MAX) != sizeof(struct pte) * MBR_ENTRY_MAX) { 391 fputs("write failed.\n", stderr); 392 goto fail; 393 } 394 lseek(fd, MBR_BOOT_SIGNATURE_OFFSET, SEEK_SET); 395 if (write(fd, "\x55\xaa", 2) != 2) { 396 fputs("write failed.\n", stderr); 397 goto fail; 398 } 399 400 ret = 0; 401 fail: 402 close(fd); 403 return ret; 404 } 405 406 /* check the partition sizes and write the guid partition table */ 407 static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr) 408 { 409 struct pte pte[MBR_ENTRY_MAX]; 410 struct gpth gpth = { 411 .signature = cpu_to_le64(GPT_SIGNATURE), 412 .revision = cpu_to_le32(GPT_REVISION), 413 .size = cpu_to_le32(GPT_HEADER_SIZE), 414 .self = cpu_to_le64(GPT_HEADER_SECTOR), 415 .first_usable = cpu_to_le64(gpt_first_entry_sector + GPT_SIZE), 416 .first_entry = cpu_to_le64(gpt_first_entry_sector), 417 .disk_guid = guid, 418 .entry_num = cpu_to_le32(GPT_ENTRY_MAX), 419 .entry_size = cpu_to_le32(GPT_ENTRY_SIZE), 420 }; 421 struct gpte gpte[GPT_ENTRY_MAX]; 422 uint64_t start, end; 423 uint64_t sect = GPT_SIZE + gpt_first_entry_sector; 424 int fd, ret = -1; 425 unsigned i, pmbr = 1; 426 char img_name[strlen(filename) + 20]; 427 428 memset(pte, 0, sizeof(struct pte) * MBR_ENTRY_MAX); 429 memset(gpte, 0, GPT_ENTRY_SIZE * GPT_ENTRY_MAX); 430 for (i = 0; i < nr; i++) { 431 if (!parts[i].size) { 432 if (ignore_null_sized_partition) 433 continue; 434 fprintf(stderr, "Invalid size in partition %d!\n", i); 435 return ret; 436 } 437 start = sect; 438 if (parts[i].start != 0) { 439 if (parts[i].start * 2 < start) { 440 fprintf(stderr, "Invalid start %lld for partition %d!\n", 441 parts[i].start, i); 442 return ret; 443 } 444 start = parts[i].start * 2; 445 } else if (kb_align != 0) { 446 start = round_to_kb(start); 447 } 448 if ((gpt_last_usable_sector > 0) && 449 (start + parts[i].size * 2 > gpt_last_usable_sector + 1)) { 450 fprintf(stderr, "Partition %d ends after last usable sector %ld\n", 451 i, gpt_last_usable_sector); 452 return ret; 453 } 454 parts[i].actual_start = start; 455 gpte[i].start = cpu_to_le64(start); 456 457 sect = start + parts[i].size * 2; 458 gpte[i].end = cpu_to_le64(sect -1); 459 gpte[i].guid = guid; 460 gpte[i].guid.b[sizeof(guid_t) -1] += i + 1; 461 gpte[i].type = parts[i].guid; 462 463 if (parts[i].hybrid && pmbr < MBR_ENTRY_MAX) { 464 pte[pmbr].active = ((i + 1) == active) ? 0x80 : 0; 465 pte[pmbr].type = parts[i].type; 466 pte[pmbr].start = cpu_to_le32(start); 467 pte[pmbr].length = cpu_to_le32(sect - start); 468 to_chs(start, pte[1].chs_start); 469 to_chs(sect - 1, pte[1].chs_end); 470 pmbr++; 471 } 472 gpte[i].attr = parts[i].gattr; 473 474 if (parts[i].name) 475 init_utf16(parts[i].name, (uint16_t *)gpte[i].name, GPT_ENTRY_NAME_SIZE / sizeof(uint16_t)); 476 477 if ((i + 1) == (unsigned)active) 478 gpte[i].attr |= GPT_ATTR_LEGACY_BOOT; 479 480 if (parts[i].required) 481 gpte[i].attr |= GPT_ATTR_PLAT_REQUIRED; 482 483 if (verbose) 484 fprintf(stderr, "Partition %d: start=%" PRIu64 ", end=%" PRIu64 ", size=%" PRIu64 "\n", 485 i, 486 start * DISK_SECTOR_SIZE, sect * DISK_SECTOR_SIZE, 487 (sect - start) * DISK_SECTOR_SIZE); 488 printf("%" PRIu64 "\n", start * DISK_SECTOR_SIZE); 489 printf("%" PRIu64 "\n", (sect - start) * DISK_SECTOR_SIZE); 490 } 491 492 if (parts[0].actual_start > GPT_FIRST_ENTRY_SECTOR + GPT_SIZE) { 493 gpte[GPT_ENTRY_MAX - 1].start = cpu_to_le64(gpt_first_entry_sector + GPT_SIZE); 494 gpte[GPT_ENTRY_MAX - 1].end = cpu_to_le64(parts[0].actual_start - 1); 495 gpte[GPT_ENTRY_MAX - 1].type = GUID_PARTITION_BIOS_BOOT; 496 gpte[GPT_ENTRY_MAX - 1].guid = guid; 497 gpte[GPT_ENTRY_MAX - 1].guid.b[sizeof(guid_t) -1] += GPT_ENTRY_MAX; 498 } 499 500 if (gpt_last_usable_sector == 0) 501 gpt_last_usable_sector = sect - 1; 502 503 end = gpt_last_usable_sector + GPT_SIZE + 1; 504 505 pte[0].type = 0xEE; 506 pte[0].start = cpu_to_le32(GPT_HEADER_SECTOR); 507 pte[0].length = cpu_to_le32(end + 1 - GPT_HEADER_SECTOR); 508 to_chs(GPT_HEADER_SECTOR, pte[0].chs_start); 509 to_chs(end, pte[0].chs_end); 510 511 gpth.last_usable = cpu_to_le64(gpt_last_usable_sector); 512 gpth.alternate = cpu_to_le64(end); 513 gpth.entry_crc32 = cpu_to_le32(gpt_crc32(gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX)); 514 gpth.crc32 = cpu_to_le32(gpt_crc32((char *)&gpth, GPT_HEADER_SIZE)); 515 516 if (verbose) 517 fprintf(stderr, "PartitionEntryLBA=%" PRIu64 ", FirstUsableLBA=%" PRIu64 ", LastUsableLBA=%" PRIu64 "\n", 518 gpt_first_entry_sector, gpt_first_entry_sector + GPT_SIZE, gpt_last_usable_sector); 519 520 if (!gpt_split_image) 521 strcpy(img_name, filename); 522 else 523 snprintf(img_name, sizeof(img_name), "%s.start", filename); 524 525 if ((fd = open(img_name, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { 526 fprintf(stderr, "Can't open output file '%s'\n",img_name); 527 return ret; 528 } 529 530 lseek(fd, MBR_DISK_SIGNATURE_OFFSET, SEEK_SET); 531 if (write(fd, &signature, sizeof(signature)) != sizeof(signature)) { 532 fputs("write failed.\n", stderr); 533 goto fail; 534 } 535 536 lseek(fd, MBR_PARTITION_ENTRY_OFFSET, SEEK_SET); 537 if (write(fd, pte, sizeof(struct pte) * MBR_ENTRY_MAX) != sizeof(struct pte) * MBR_ENTRY_MAX) { 538 fputs("write failed.\n", stderr); 539 goto fail; 540 } 541 542 lseek(fd, MBR_BOOT_SIGNATURE_OFFSET, SEEK_SET); 543 if (write(fd, "\x55\xaa", 2) != 2) { 544 fputs("write failed.\n", stderr); 545 goto fail; 546 } 547 548 if (write(fd, &gpth, GPT_HEADER_SIZE) != GPT_HEADER_SIZE) { 549 fputs("write failed.\n", stderr); 550 goto fail; 551 } 552 553 lseek(fd, 2 * DISK_SECTOR_SIZE - 1, SEEK_SET); 554 if (write(fd, "\x00", 1) != 1) { 555 fputs("write failed.\n", stderr); 556 goto fail; 557 } 558 559 if (!gpt_split_image || (gpt_first_entry_sector == GPT_FIRST_ENTRY_SECTOR)) { 560 lseek(fd, gpt_first_entry_sector * DISK_SECTOR_SIZE, SEEK_SET); 561 } else { 562 close(fd); 563 564 snprintf(img_name, sizeof(img_name), "%s.entry", filename); 565 if ((fd = open(img_name, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { 566 fprintf(stderr, "Can't open output file '%s'\n",img_name); 567 return ret; 568 } 569 } 570 571 if (write(fd, &gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX) != GPT_ENTRY_SIZE * GPT_ENTRY_MAX) { 572 fputs("write failed.\n", stderr); 573 goto fail; 574 } 575 576 if (gpt_alternate) { 577 /* The alternate partition table (We omit it by default) */ 578 swap(gpth.self, gpth.alternate); 579 gpth.first_entry = cpu_to_le64(end - GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE), 580 gpth.crc32 = 0; 581 gpth.crc32 = cpu_to_le32(gpt_crc32(&gpth, GPT_HEADER_SIZE)); 582 583 if (!gpt_split_image) { 584 lseek(fd, end * DISK_SECTOR_SIZE - GPT_ENTRY_SIZE * GPT_ENTRY_MAX, SEEK_SET); 585 } else { 586 close(fd); 587 588 end = GPT_SIZE; 589 snprintf(img_name, sizeof(img_name), "%s.end", filename); 590 if ((fd = open(img_name, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { 591 fprintf(stderr, "Can't open output file '%s'\n",img_name); 592 return ret; 593 } 594 } 595 596 if (write(fd, &gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX) != GPT_ENTRY_SIZE * GPT_ENTRY_MAX) { 597 fputs("write failed.\n", stderr); 598 goto fail; 599 } 600 601 lseek(fd, end * DISK_SECTOR_SIZE, SEEK_SET); 602 if (write(fd, &gpth, GPT_HEADER_SIZE) != GPT_HEADER_SIZE) { 603 fputs("write failed.\n", stderr); 604 goto fail; 605 } 606 lseek(fd, (end + 1) * DISK_SECTOR_SIZE -1, SEEK_SET); 607 if (write(fd, "\x00", 1) != 1) { 608 fputs("write failed.\n", stderr); 609 goto fail; 610 } 611 } 612 613 ret = 0; 614 fail: 615 close(fd); 616 return ret; 617 } 618 619 static void usage(char *prog) 620 { 621 fprintf(stderr, "Usage: %s [-v] [-n] [-b] [-g] -h <heads> -s <sectors> -o <outputfile>\n" 622 " [-a <part number>] [-l <align kB>] [-G <guid>]\n" 623 " [-e <gpt_entry_offset>] [-d <gpt_disk_size>]\n" 624 " [[-t <type> | -T <GPT part type>] [-r] [-N <name>] -p <size>[@<start>]...] \n", prog); 625 626 exit(EXIT_FAILURE); 627 } 628 629 static guid_t type_to_guid_and_name(unsigned char type, char **name) 630 { 631 guid_t guid = GUID_PARTITION_BASIC_DATA; 632 633 switch (type) { 634 case 0xef: 635 if(*name == NULL) 636 *name = "EFI System Partition"; 637 guid = GUID_PARTITION_SYSTEM; 638 break; 639 case 0x83: 640 guid = GUID_PARTITION_LINUX_FS_GUID; 641 break; 642 case 0x2e: 643 guid = GUID_PARTITION_LINUX_FIT_GUID; 644 break; 645 } 646 647 return guid; 648 } 649 650 int main (int argc, char **argv) 651 { 652 unsigned char type = 0x83; 653 char *p; 654 int ch; 655 int part = 0; 656 char *name = NULL; 657 unsigned short int hybrid = 0, required = 0; 658 uint64_t total_sectors; 659 uint32_t signature = 0x5452574F; /* 'OWRT' */ 660 guid_t guid = GUID_INIT( signature, 0x2211, 0x4433, \ 661 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0x00); 662 663 while ((ch = getopt(argc, argv, "h:s:p:a:t:T:o:vnbHN:gl:rS:G:e:d:")) != -1) { 664 switch (ch) { 665 case 'o': 666 filename = optarg; 667 break; 668 case 'v': 669 verbose++; 670 break; 671 case 'n': 672 ignore_null_sized_partition = true; 673 break; 674 case 'g': 675 use_guid_partition_table = 1; 676 break; 677 case 'H': 678 hybrid = 1; 679 break; 680 case 'e': 681 /* based on DISK_SECTOR_SIZE = 512 */ 682 gpt_first_entry_sector = 2 * to_kbytes(optarg); 683 if (gpt_first_entry_sector < GPT_FIRST_ENTRY_SECTOR) { 684 fprintf(stderr, "GPT First Entry offset must not be smaller than %d KBytes\n", 685 GPT_FIRST_ENTRY_SECTOR / 2); 686 exit(EXIT_FAILURE); 687 } 688 break; 689 case 'd': 690 /* 691 * Zero disk_size is specially allowed. It means: find a disk size 692 * on the base of provided partitions list. 693 * 694 * based on DISK_SECTOR_SIZE = 512 695 */ 696 gpt_alternate = true; 697 total_sectors = 2 * to_kbytes(optarg); 698 if (total_sectors != 0) { 699 if (total_sectors <= 2 * GPT_SIZE + 3) { 700 fprintf(stderr, "GPT disk size must be larger than %d KBytes\n", 701 (2 * GPT_SIZE + 3) * DISK_SECTOR_SIZE / 1024); 702 exit(EXIT_FAILURE); 703 } 704 gpt_last_usable_sector = total_sectors - GPT_SIZE - 2; 705 } 706 break; 707 case 'b': 708 gpt_alternate = true; 709 gpt_split_image = true; 710 break; 711 case 'h': 712 heads = (int)strtoul(optarg, NULL, 0); 713 break; 714 case 's': 715 sectors = (int)strtoul(optarg, NULL, 0); 716 break; 717 case 'p': 718 if (part > GPT_ENTRY_MAX - 1 || (!use_guid_partition_table && part > 3)) { 719 fputs("Too many partitions\n", stderr); 720 exit(EXIT_FAILURE); 721 } 722 p = strchr(optarg, '@'); 723 if (p) { 724 *(p++) = 0; 725 parts[part].start = to_kbytes(p); 726 } 727 if (!parts[part].has_guid) 728 parts[part].guid = type_to_guid_and_name(type, &name); 729 730 parts[part].size = to_kbytes(optarg); 731 parts[part].required = required; 732 parts[part].name = name; 733 parts[part].hybrid = hybrid; 734 fprintf(stderr, "part %lld %lld\n", parts[part].start, parts[part].size); 735 parts[part++].type = type; 736 /* 737 * reset 'name','required' and 'hybrid' 738 * 'type' is deliberately inherited from the previous delcaration 739 */ 740 name = NULL; 741 required = 0; 742 hybrid = 0; 743 break; 744 case 'N': 745 name = optarg; 746 break; 747 case 'r': 748 required = 1; 749 break; 750 case 't': 751 type = (char)strtoul(optarg, NULL, 16); 752 break; 753 case 'a': 754 active = (int)strtoul(optarg, NULL, 0); 755 break; 756 case 'l': 757 kb_align = (int)strtoul(optarg, NULL, 0) * 2; 758 break; 759 case 'S': 760 signature = strtoul(optarg, NULL, 0); 761 break; 762 case 'T': 763 if (!parse_gpt_parttype(optarg, &parts[part])) { 764 fprintf(stderr, 765 "Invalid GPT partition type \"%s\"\n", 766 optarg); 767 exit(EXIT_FAILURE); 768 } 769 break; 770 case 'G': 771 if (guid_parse(optarg, &guid)) { 772 fputs("Invalid guid string\n", stderr); 773 exit(EXIT_FAILURE); 774 } 775 break; 776 case '?': 777 default: 778 usage(argv[0]); 779 } 780 } 781 argc -= optind; 782 if (argc || (!use_guid_partition_table && ((heads <= 0) || (sectors <= 0))) || !filename) 783 usage(argv[0]); 784 785 if ((use_guid_partition_table && active > GPT_ENTRY_MAX) || 786 (!use_guid_partition_table && active > MBR_ENTRY_MAX) || 787 active < 0) 788 active = 0; 789 790 if (use_guid_partition_table) { 791 heads = 254; 792 sectors = 63; 793 return gen_gptable(signature, guid, part) ? EXIT_FAILURE : EXIT_SUCCESS; 794 } 795 796 return gen_ptable(signature, part) ? EXIT_FAILURE : EXIT_SUCCESS; 797 } 798
This page was automatically generated by LXR 0.3.1. • OpenWrt