2 * isohybrid.c: Post process an ISO 9660 image generated with mkisofs or
3 * genisoimage to allow - hybrid booting - as a CD-ROM or as a hard
6 * This is based on the original Perl script written by H. Peter Anvin. The
7 * rewrite in C is to avoid dependency on Perl on a system under installation.
9 * Copyright (C) 2010 P J P <pj.pandit@yahoo.co.in>
11 * isohybrid is a free software; you can redistribute it and/or modify it
12 * under the terms of GNU General Public License as published by Free Software
13 * Foundation; either version 2 of the license, or (at your option) any later
16 * isohybrid is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
21 * You should have received a copy of the GNU General Public License along
22 * with isohybrid; if not, see: <http://www.gnu.org/licenses>.
39 #include <uuid/uuid.h>
41 #include "isohybrid.h"
44 extern int opterr, optind;
46 unsigned int padding = 0;
48 uuid_t disk_uuid, part_uuid, iso_uuid;
51 enum { VERBOSE = 1 , EFI = 2 , MAC = 4};
54 uint16_t head = 64; /* 1 <= head <= 256 */
55 uint8_t sector = 32; /* 1 <= sector <= 63 */
57 uint8_t entry = 1; /* partition number: 1 <= entry <= 4 */
58 uint8_t offset = 0; /* partition offset: 0 <= offset <= 64 */
59 uint16_t type = 0x17; /* partition type: 0 <= type <= 255 */
60 uint32_t id = 0; /* MBR: 0 <= id <= 0xFFFFFFFF(4294967296) */
62 uint8_t hd0 = 0; /* 0 <= hd0 <= 2 */
63 uint8_t partok = 0; /* 0 <= partok <= 1 */
66 uint32_t catoffset = 0;
67 uint32_t c = 0, cc = 0, cs = 0;
69 uint32_t psize = 0, isosize = 0;
71 /* boot catalogue parameters */
73 uint16_t de_seg = 0, de_count = 0, de_mbz2 = 0;
74 uint8_t de_boot = 0, de_media = 0, de_sys = 0, de_mbz1 = 0;
75 uint32_t efi_lba = 0, mac_lba = 0;
76 uint16_t efi_count = 0, mac_count = 0;
77 uint8_t efi_boot = 0, efi_media = 0, efi_sys = 0;
81 uint8_t afp_header[] = { 0x45, 0x52, 0x08, 0x00, 0x00, 0x00, 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
83 uuid_t efi_system_partition = {0xC1, 0x2A, 0x73, 0x28, 0xF8, 0x1F, 0x11, 0xD2, 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B};
84 uuid_t basic_partition = {0xEB,0xD0,0xA0,0xA2,0xB9,0xE5,0x44,0x33,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7};
85 uuid_t hfs_partition = {0x48, 0x46, 0x53, 0x00, 0x00, 0x00, 0x11, 0xAA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC};
87 uint32_t crc_tab[256] =
89 0, 0x77073096, 0xEE0E612C, 0x990951BA,
90 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
91 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
92 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
93 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
94 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
95 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
96 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
97 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
98 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
99 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
100 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
101 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
102 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
103 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
104 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
105 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
106 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
107 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
108 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
109 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
110 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
111 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
112 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
113 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
114 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
115 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
116 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
117 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
118 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
119 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
120 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
121 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
122 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
123 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
124 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
125 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
126 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
127 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
128 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
129 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
130 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
131 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
132 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
133 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
134 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
135 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
136 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
137 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
138 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
139 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
140 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
141 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
142 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
143 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
144 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
145 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
146 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
147 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
148 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
149 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
150 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
151 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
152 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
155 struct iso_primary_descriptor {
158 uint8_t ignore2 [44];
170 uint64_t firstUsableLBA;
171 uint64_t lastUsableLBA;
173 uint64_t partitionEntriesLBA;
175 uint32_t sizeOfPartitionEntries;
176 uint32_t partitionEntriesCRC;
177 uint8_t reserved2[420];
180 struct gpt_part_header {
189 #define APM_OFFSET 2048
191 struct apple_part_header {
192 uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */
194 uint32_t map_count; /* # blocks in partition map */
195 uint32_t start_block; /* absolute starting block # of partition */
196 uint32_t block_count; /* number of blocks in partition */
197 char name[32]; /* partition name */
198 char type[32]; /* string type description */
199 uint32_t data_start; /* rel block # of first data block */
200 uint32_t data_count; /* number of data blocks */
201 uint32_t status; /* partition status bits */
207 uint32_t boot_entry2;
209 char processor[16]; /* Contains 680x0, x=0,2,3,4; or empty */
218 printf("Usage: %s [OPTIONS] <boot.iso>\n", prog);
225 #define FMT "%-18s %s\n"
230 printf("Options:\n");
231 printf(FMT, " -h <X>", "Number of default geometry heads");
232 printf(FMT, " -s <X>", "Number of default geometry sectors");
233 printf(FMT, " -e --entry", "Specify partition entry number (1-4)");
234 printf(FMT, " -o --offset", "Specify partition offset (default 0)");
235 printf(FMT, " -t --type", "Specify partition type (default 0x17)");
236 printf(FMT, " -i --id", "Specify MBR ID (default random)");
237 printf(FMT, " -u --uefi", "Build EFI bootable image");
238 printf(FMT, " -m --mac", "Add AFP table support");
241 printf(FMT, " --forcehd0", "Assume we are loaded as disk ID 0");
242 printf(FMT, " --ctrlhd0", "Assume disk ID 0 if the Ctrl key is pressed");
243 printf(FMT, " --partok", "Allow booting from within a partition");
246 printf(FMT, " -? --help", "Display this help");
247 printf(FMT, " -v --verbose", "Display verbose output");
248 printf(FMT, " -V --version", "Display version information");
251 printf("Report bugs to <pj.pandit@yahoo.co.in>\n");
256 check_option(int argc, char *argv[])
261 const char optstr[] = ":h:s:e:o:t:i:fcp?vV";
262 struct option lopt[] = \
264 { "entry", required_argument, NULL, 'e' },
265 { "offset", required_argument, NULL, 'o' },
266 { "type", required_argument, NULL, 't' },
267 { "id", required_argument, NULL, 'i' },
269 { "forcehd0", no_argument, NULL, 'f' },
270 { "ctrlhd0", no_argument, NULL, 'c' },
271 { "partok", no_argument, NULL, 'p'},
272 { "uefi", no_argument, NULL, 'u'},
273 { "mac", no_argument, NULL, 'm'},
275 { "help", no_argument, NULL, '?' },
276 { "verbose", no_argument, NULL, 'v' },
277 { "version", no_argument, NULL, 'V' },
283 while ((n = getopt_long_only(argc, argv, optstr, lopt, &ind)) != -1)
288 head = strtoul(optarg, &err, 0);
289 if (head < 1 || head > 256)
290 errx(1, "invalid head: `%s', 1 <= head <= 256", optarg);
294 sector = strtoul(optarg, &err, 0);
295 if (sector < 1 || sector > 63)
296 errx(1, "invalid sector: `%s', 1 <= sector <= 63", optarg);
300 entry = strtoul(optarg, &err, 0);
301 if (entry < 1 || entry > 4)
302 errx(1, "invalid entry: `%s', 1 <= entry <= 4", optarg);
306 offset = strtoul(optarg, &err, 0);
307 if (*err || offset > 64)
308 errx(1, "invalid offset: `%s', 0 <= offset <= 64", optarg);
312 type = strtoul(optarg, &err, 0);
313 if (*err || type > 255)
314 errx(1, "invalid type: `%s', 0 <= type <= 255", optarg);
318 id = strtoul(optarg, &err, 0);
320 errx(1, "invalid id: `%s'", optarg);
348 printf("%s version %s\n", prog, VERSION);
352 errx(1, "option `-%c' takes an argument", optopt);
357 errx(1, "invalid option `-%c', see --help", optopt);
368 bendian_short(const uint16_t s)
375 r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
382 bendian_int(const uint32_t s)
389 r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
390 | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
396 lendian_short(const uint16_t s)
403 r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
410 lendian_int(const uint32_t s)
417 r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
418 | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
424 lendian_64(const uint64_t s)
431 r = (s & 0x00000000000000FF) << 56 | (s & 0xFF00000000000000) >> 56
432 | (s & 0x000000000000FF00) << 40 | (s & 0x00FF000000000000) >> 40
433 | (s & 0x0000000000FF0000) << 24 | (s & 0x0000FF0000000000) >> 24
434 | (s & 0x00000000FF000000) << 8 | (s & 0x000000FF00000000) >> 8;
441 check_banner(const uint8_t *buf)
443 static const char banner[] = "\0CD001\1EL TORITO SPECIFICATION\0\0\0\0" \
444 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
447 if (!buf || memcmp(buf, banner, sizeof(banner) - 1))
450 buf += sizeof(banner) - 1;
451 memcpy(&catoffset, buf, sizeof(catoffset));
453 catoffset = lendian_int(catoffset);
460 check_catalogue(const uint8_t *buf)
464 for (i = 0, cs = 0; i < 16; i++)
467 memcpy(&ve[i], buf, sizeof(ve[i]));
469 ve[i] = lendian_short(ve[i]);
475 printf("ve[%d]: %d, cs: %d\n", i, ve[i], cs);
477 if ((ve[0] != 0x0001) || (ve[15] != 0xAA55) || (cs & 0xFFFF))
485 read_catalogue(const uint8_t *buf)
487 memcpy(&de_boot, buf++, 1);
488 memcpy(&de_media, buf++, 1);
490 memcpy(&de_seg, buf, 2);
491 de_seg = lendian_short(de_seg);
494 memcpy(&de_sys, buf++, 1);
495 memcpy(&de_mbz1, buf++, 1);
497 memcpy(&de_count, buf, 2);
498 de_count = lendian_short(de_count);
501 memcpy(&de_lba, buf, 4);
502 de_lba = lendian_int(de_lba);
505 memcpy(&de_mbz2, buf, 2);
506 de_mbz2 = lendian_short(de_mbz2);
509 if (de_boot != 0x88 || de_media != 0
510 || (de_seg != 0 && de_seg != 0x7C0) || de_count != 4)
518 read_efi_section(const uint8_t *buf)
520 unsigned char header_indicator;
521 unsigned char platform_id;
524 memcpy(&header_indicator, buf++, 1);
525 memcpy(&platform_id, buf++, 1);
527 memcpy(&count, buf, 2);
528 count = lendian_short(count);
531 if (platform_id == 0xef)
538 read_efi_catalogue(const uint8_t *buf, uint16_t *count, uint32_t *lba)
542 memcpy(count, buf, 2);
543 *count = lendian_short(*count);
547 *lba = lendian_int(*lba);
555 display_catalogue(void)
557 printf("de_boot: %hhu\n", de_boot);
558 printf("de_media: %hhu\n", de_media);
559 printf("de_seg: %hu\n", de_seg);
560 printf("de_sys: %hhu\n", de_sys);
561 printf("de_mbz1: %hhu\n", de_mbz1);
562 printf("de_count: %hu\n", de_count);
563 printf("de_lba: %u\n", de_lba);
564 printf("de_mbz2: %hu\n", de_mbz2);
568 initialise_mbr(uint8_t *mbr)
572 uint8_t ptype = 0, *rbm = mbr;
573 uint8_t bhead = 0, bsect = 0, bcyle = 0;
574 uint8_t ehead = 0, esect = 0, ecyle = 0;
576 extern unsigned char isohdpfx[][MBRSIZE];
578 memcpy(mbr, &isohdpfx[hd0 + 3 * partok], MBRSIZE);
581 memcpy(mbr, afp_header, sizeof(afp_header));
584 mbr += MBRSIZE; /* offset 432 */
586 tmp = lendian_int(de_lba * 4);
587 memcpy(mbr, &tmp, sizeof(tmp));
588 mbr += sizeof(tmp); /* offset 436 */
591 memcpy(mbr, &tmp, sizeof(tmp));
592 mbr += sizeof(tmp); /* offset 440 */
594 tmp = lendian_int(id);
595 memcpy(mbr, &tmp, sizeof(tmp));
596 mbr += sizeof(tmp); /* offset 444 */
600 mbr += 2; /* offset 446 */
603 psize = c * head * sector - offset;
605 bhead = (offset / sector) % head;
606 bsect = (offset % sector) + 1;
607 bcyle = offset / (head * sector);
609 bsect += (bcyle & 0x300) >> 2;
613 esect = sector + (((cc - 1) & 0x300) >> 2);
614 ecyle = (cc - 1) & 0xFF;
616 for (i = 1; i <= 4; i++)
630 tmp = lendian_int(offset);
631 memcpy(&mbr[8], &tmp, sizeof(tmp));
633 tmp = lendian_int(psize);
634 memcpy(&mbr[12], &tmp, sizeof(tmp));
646 display_mbr(const uint8_t *mbr, size_t len)
649 unsigned int i = 0, j = 0;
651 printf("sizeof(MBR): %zu bytes\n", len);
652 for (i = 0; i < len; i++)
667 printf("%c", isprint(mbr[j]) ? mbr[j] : '.');
674 uint32_t chksum_crc32 (unsigned char *block, unsigned int length)
676 register unsigned long crc;
680 for (i = 0; i < length; i++)
682 crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
684 return (crc ^ 0xFFFFFFFF);
688 reverse_uuid(uuid_t uuid)
690 uint8_t t, *p = (uint8_t *)uuid;
692 t = p[0]; p[0] = p[3]; p[3] = t;
693 t = p[1]; p[1] = p[2]; p[2] = t;
694 t = p[4]; p[4] = p[5]; p[5] = t;
695 t = p[6]; p[6] = p[7]; p[7] = t;
699 initialise_gpt(uint8_t *gpt, uint32_t current, uint32_t alternate, int primary)
701 struct gpt_header *header = (struct gpt_header *)gpt;
702 struct gpt_part_header *part;
704 int gptsize = 128 / 4 + 2;
707 /* 2048 bytes per partition, plus round to 2048 boundary */
708 hole = (apm_parts * 4) + 2;
712 uuid_generate(disk_uuid);
713 reverse_uuid(disk_uuid);
716 header->signature = lendian_64(0x5452415020494645);
717 header->revision = lendian_int(0x010000);
718 header->headerSize = lendian_int(0x5c);
719 header->currentLBA = lendian_64(current);
720 header->backupLBA = lendian_64(alternate);
721 header->firstUsableLBA = lendian_64(gptsize + hole);
722 header->lastUsableLBA = lendian_64((isostat.st_size + padding)/512 -
725 header->partitionEntriesLBA = lendian_64(0x02 + hole);
727 header->partitionEntriesLBA = lendian_64(current - (128 / 4));
728 header->numParts = lendian_int(0x80);
729 header->sizeOfPartitionEntries = lendian_int(0x80);
730 memcpy(header->diskGUID, disk_uuid, sizeof(uuid_t));
733 gpt += sizeof(struct gpt_header) + hole * 512;
735 gpt -= header->sizeOfPartitionEntries * header->numParts;
737 part = (struct gpt_part_header *)gpt;
739 uuid_generate(part_uuid);
740 uuid_generate(iso_uuid);
741 reverse_uuid(part_uuid);
742 reverse_uuid(iso_uuid);
745 memcpy(part->partGUID, iso_uuid, sizeof(uuid_t));
746 memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t));
747 part->firstLBA = lendian_64(0);
748 part->lastLBA = lendian_64(psize);
749 memcpy(part->name, "ISOHybrid ISO", 28);
751 gpt += sizeof(struct gpt_part_header);
754 memcpy(part->partGUID, part_uuid, sizeof(uuid_t));
755 memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t));
756 part->firstLBA = lendian_64(efi_lba * 4);
757 part->lastLBA = lendian_64(part->firstLBA + efi_count - 1);
758 memcpy(part->name, "ISOHybrid", 20);
760 gpt += sizeof(struct gpt_part_header);
763 gpt += sizeof(struct gpt_part_header);
767 memcpy(part->partGUID, part_uuid, sizeof(uuid_t));
768 memcpy(part->partTypeGUID, hfs_partition, sizeof(uuid_t));
769 part->firstLBA = lendian_64(mac_lba * 4);
770 part->lastLBA = lendian_64(part->firstLBA + mac_count - 1);
771 memcpy(part->name, "ISOHybrid", 20);
778 header->partitionEntriesCRC = lendian_int (chksum_crc32((uint8_t *)part,
779 header->numParts * header->sizeOfPartitionEntries));
781 header->headerCRC = lendian_int(chksum_crc32((uint8_t *)header,
782 header->headerSize));
786 initialise_apm(uint8_t *gpt, uint32_t start)
788 struct apple_part_header *part = (struct apple_part_header *)gpt;
790 part->signature = bendian_short(0x504d);
791 part->map_count = bendian_int(apm_parts);
792 part->start_block = bendian_int(1);
793 part->block_count = bendian_int(0x10);
794 strcpy(part->name, "Apple");
795 strcpy(part->type, "Apple_partition_map");
796 part->data_start = bendian_int(0);
797 part->data_count = bendian_int(10);
798 part->status = bendian_int(0x03);
800 part = (struct apple_part_header *)(gpt + 2048);
802 part->signature = bendian_short(0x504d);
803 part->map_count = bendian_int(3);
804 part->start_block = bendian_int(efi_lba);
805 part->block_count = bendian_int(efi_count);
806 strcpy(part->name, "EFI");
807 strcpy(part->type, "Apple_HFS");
808 part->data_start = bendian_int(0);
809 part->data_count = bendian_int(efi_count);
810 part->status = bendian_int(0x33);
812 part = (struct apple_part_header *)(gpt + 4096);
816 part->signature = bendian_short(0x504d);
817 part->map_count = bendian_int(3);
818 part->start_block = bendian_int(mac_lba);
819 part->block_count = bendian_int(mac_count);
820 strcpy(part->name, "EFI");
821 strcpy(part->type, "Apple_HFS");
822 part->data_start = bendian_int(0);
823 part->data_count = bendian_int(mac_count);
824 part->status = bendian_int(0x33);
826 part->signature = bendian_short(0x504d);
827 part->map_count = bendian_int(3);
828 part->start_block = bendian_int((start/2048) + 10);
829 part->block_count = bendian_int(efi_lba - start/2048 - 10);
830 strcpy(part->name, "ISO");
831 strcpy(part->type, "Apple_Free");
832 part->data_start = bendian_int(0);
833 part->data_count = bendian_int(efi_lba - start/2048 - 10);
834 part->status = bendian_int(0x01);
839 main(int argc, char *argv[])
843 uint8_t *buf = NULL, *bufz = NULL;
844 int cylsize = 0, frac = 0;
845 size_t orig_gpt_size, free_space, gpt_size;
846 struct iso_primary_descriptor descriptor;
848 prog = strcpy(alloca(strlen(argv[0]) + 1), argv[0]);
849 i = check_option(argc, argv);
859 if ((mode & EFI) && offset)
860 errx(1, "%s: --offset is invalid with UEFI images\n", argv[0]);
862 srand(time(NULL) << (getppid() << getpid()));
864 if (!(fp = fopen(argv[0], "r+")))
865 err(1, "could not open file `%s'", argv[0]);
867 if (fseek(fp, (16 << 11), SEEK_SET))
868 err(1, "%s: seek error - 0", argv[0]);
870 if (fread(&descriptor, sizeof(char), sizeof(descriptor), fp) != sizeof(descriptor))
871 err(1, "%s: read error - 0", argv[0]);
873 if (fseek(fp, 17 * 2048, SEEK_SET))
874 err(1, "%s: seek error - 1", argv[0]);
876 bufz = buf = calloc(BUFSIZE, sizeof(char));
877 if (fread(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE)
878 err(1, "%s", argv[0]);
880 if (check_banner(buf))
881 errx(1, "%s: could not find boot record", argv[0]);
884 printf("catalogue offset: %d\n", catoffset);
886 if (fseek(fp, catoffset * 2048, SEEK_SET))
887 err(1, "%s: seek error - 2", argv[0]);
890 memset(buf, 0, BUFSIZE);
891 if (fread(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE)
892 err(1, "%s", argv[0]);
894 if (check_catalogue(buf))
895 errx(1, "%s: invalid boot catalogue", argv[0]);
898 if (read_catalogue(buf))
899 errx(1, "%s: unexpected boot catalogue parameters", argv[0]);
908 if (!read_efi_section(buf)) {
910 if (!read_efi_catalogue(buf, &efi_count, &efi_lba) && efi_lba) {
914 errx(1, "%s: invalid efi catalogue", argv[0]);
917 errx(1, "%s: unable to find efi image", argv[0]);
925 if (!read_efi_section(buf)) {
927 if (!read_efi_catalogue(buf, &mac_count, &mac_lba) && mac_lba) {
931 errx(1, "%s: invalid efi catalogue", argv[0]);
934 errx(1, "%s: unable to find mac efi image", argv[0]);
938 if (fseek(fp, (de_lba * 2048 + 0x40), SEEK_SET))
939 err(1, "%s: seek error - 3", argv[0]);
942 memset(buf, 0, BUFSIZE);
943 if (fread(buf, sizeof(char), 4, fp) != 4)
944 err(1, "%s", argv[0]);
946 if (memcmp(buf, "\xFB\xC0\x78\x70", 4))
947 errx(1, "%s: boot loader does not have an isolinux.bin hybrid " \
948 "signature. Note that isolinux-debug.bin does not support " \
949 "hybrid booting", argv[0]);
951 if (stat(argv[0], &isostat))
952 err(1, "%s", argv[0]);
954 isosize = lendian_int(descriptor.size) * lendian_short(descriptor.block_size);
955 free_space = isostat.st_size - isosize;
957 cylsize = head * sector * 512;
958 frac = isostat.st_size % cylsize;
959 padding = (frac > 0) ? cylsize - frac : 0;
962 printf("imgsize: %zu, padding: %d\n", (size_t)isostat.st_size, padding);
964 cc = c = ( isostat.st_size + padding) / cylsize;
967 warnx("Warning: more than 1024 cylinders: %d", c);
968 warnx("Not all BIOSes will be able to boot this device");
974 if (fseek(fp, 440, SEEK_SET))
975 err(1, "%s: seek error - 4", argv[0]);
977 if (fread(&id, 1, 4, fp) != 4)
978 err(1, "%s: read error", argv[0]);
980 id = lendian_int(id);
989 printf("id: %u\n", id);
992 memset(buf, 0, BUFSIZE);
993 i = initialise_mbr(buf);
998 if (fseek(fp, 0, SEEK_SET))
999 err(1, "%s: seek error - 5", argv[0]);
1001 if (fwrite(buf, sizeof(char), i, fp) != (size_t)i)
1002 err(1, "%s: write error - 1", argv[0]);
1005 reverse_uuid(basic_partition);
1006 reverse_uuid(hfs_partition);
1008 /* 512 byte header, 128 entries of 128 bytes */
1009 orig_gpt_size = gpt_size = 512 + (128 * 128);
1011 /* Leave space for the APM if necessary */
1013 gpt_size += (4 * 2048);
1015 buf = calloc(gpt_size, sizeof(char));
1016 memset(buf, 0, gpt_size);
1019 * We need to ensure that we have enough space for the secondary GPT.
1020 * Unlike the primary, this doesn't need a hole for the APM. We still
1021 * want to be 1MB aligned so just bump the padding by a megabyte.
1023 if (free_space < orig_gpt_size && padding < orig_gpt_size) {
1024 padding += 1024 * 1024;
1028 * Determine the size of the ISO filesystem. This will define the size
1029 * of the partition that covers it.
1031 psize = isosize / 512;
1034 * Primary GPT starts at sector 1, secondary GPT starts at 1 sector
1035 * before the end of the image
1037 initialise_gpt(buf, 1, (isostat.st_size + padding - 1024) / 512, 1);
1039 if (fseek(fp, 512, SEEK_SET))
1040 err(1, "%s: seek error - 6", argv[0]);
1042 if (fwrite(buf, sizeof(char), gpt_size, fp) != (size_t)gpt_size)
1043 err(1, "%s: write error - 2", argv[0]);
1048 /* Apple partition entries filling 2048 bytes each */
1049 int apm_size = apm_parts * 2048;
1051 buf = realloc(buf, apm_size);
1052 memset(buf, 0, apm_size);
1054 initialise_apm(buf, APM_OFFSET);
1056 fseek(fp, APM_OFFSET, SEEK_SET);
1057 fwrite(buf, sizeof(char), apm_size, fp);
1062 if (fsync(fileno(fp)))
1063 err(1, "%s: could not synchronise", argv[0]);
1065 if (ftruncate(fileno(fp), isostat.st_size + padding))
1066 err(1, "%s: could not add padding bytes", argv[0]);
1070 buf = realloc(buf, orig_gpt_size);
1071 memset(buf, 0, orig_gpt_size);
1073 buf += orig_gpt_size - sizeof(struct gpt_header);
1075 initialise_gpt(buf, (isostat.st_size + padding - 1024) / 512, 1, 0);
1077 /* Shift back far enough to write the 128 GPT entries */
1078 buf -= 128 * sizeof(struct gpt_part_header);
1081 * Seek far enough back that the gpt header is 512 bytes before the
1085 if (fseek(fp, (isostat.st_size + padding) - orig_gpt_size - 512,
1087 err(1, "%s: seek error - 8", argv[0]);
1089 if (fwrite(buf, sizeof(char), orig_gpt_size, fp) != orig_gpt_size)
1090 err(1, "%s: write error - 4", argv[0]);