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 = 0; /* 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);
303 if (mode & MAC || mode & EFI)
304 errx(1, "setting an entry is unsupported with EFI or Mac");
308 offset = strtoul(optarg, &err, 0);
309 if (*err || offset > 64)
310 errx(1, "invalid offset: `%s', 0 <= offset <= 64", optarg);
314 type = strtoul(optarg, &err, 0);
315 if (*err || type > 255)
316 errx(1, "invalid type: `%s', 0 <= type <= 255", optarg);
320 id = strtoul(optarg, &err, 0);
322 errx(1, "invalid id: `%s'", optarg);
340 errx(1, "setting an entry is unsupported with EFI or Mac");
346 errx(1, "setting an entry is unsupported with EFI or Mac");
354 printf("%s version %s\n", prog, VERSION);
358 errx(1, "option `-%c' takes an argument", optopt);
363 errx(1, "invalid option `-%c', see --help", optopt);
374 bendian_short(const uint16_t s)
381 r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
388 bendian_int(const uint32_t s)
395 r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
396 | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
402 lendian_short(const uint16_t s)
409 r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
416 lendian_int(const uint32_t s)
423 r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
424 | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
430 lendian_64(const uint64_t s)
437 r = (s & 0x00000000000000FF) << 56 | (s & 0xFF00000000000000) >> 56
438 | (s & 0x000000000000FF00) << 40 | (s & 0x00FF000000000000) >> 40
439 | (s & 0x0000000000FF0000) << 24 | (s & 0x0000FF0000000000) >> 24
440 | (s & 0x00000000FF000000) << 8 | (s & 0x000000FF00000000) >> 8;
447 check_banner(const uint8_t *buf)
449 static const char banner[] = "\0CD001\1EL TORITO SPECIFICATION\0\0\0\0" \
450 "\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" \
453 if (!buf || memcmp(buf, banner, sizeof(banner) - 1))
456 buf += sizeof(banner) - 1;
457 memcpy(&catoffset, buf, sizeof(catoffset));
459 catoffset = lendian_int(catoffset);
466 check_catalogue(const uint8_t *buf)
470 for (i = 0, cs = 0; i < 16; i++)
473 memcpy(&ve[i], buf, sizeof(ve[i]));
475 ve[i] = lendian_short(ve[i]);
481 printf("ve[%d]: %d, cs: %d\n", i, ve[i], cs);
483 if ((ve[0] != 0x0001) || (ve[15] != 0xAA55) || (cs & 0xFFFF))
491 read_catalogue(const uint8_t *buf)
493 memcpy(&de_boot, buf++, 1);
494 memcpy(&de_media, buf++, 1);
496 memcpy(&de_seg, buf, 2);
497 de_seg = lendian_short(de_seg);
500 memcpy(&de_sys, buf++, 1);
501 memcpy(&de_mbz1, buf++, 1);
503 memcpy(&de_count, buf, 2);
504 de_count = lendian_short(de_count);
507 memcpy(&de_lba, buf, 4);
508 de_lba = lendian_int(de_lba);
511 memcpy(&de_mbz2, buf, 2);
512 de_mbz2 = lendian_short(de_mbz2);
515 if (de_boot != 0x88 || de_media != 0
516 || (de_seg != 0 && de_seg != 0x7C0) || de_count != 4)
524 read_efi_section(const uint8_t *buf)
526 unsigned char header_indicator;
527 unsigned char platform_id;
530 memcpy(&header_indicator, buf++, 1);
531 memcpy(&platform_id, buf++, 1);
533 memcpy(&count, buf, 2);
534 count = lendian_short(count);
537 if (platform_id == 0xef)
544 read_efi_catalogue(const uint8_t *buf, uint16_t *count, uint32_t *lba)
548 memcpy(count, buf, 2);
549 *count = lendian_short(*count);
553 *lba = lendian_int(*lba);
561 display_catalogue(void)
563 printf("de_boot: %hhu\n", de_boot);
564 printf("de_media: %hhu\n", de_media);
565 printf("de_seg: %hu\n", de_seg);
566 printf("de_sys: %hhu\n", de_sys);
567 printf("de_mbz1: %hhu\n", de_mbz1);
568 printf("de_count: %hu\n", de_count);
569 printf("de_lba: %u\n", de_lba);
570 printf("de_mbz2: %hu\n", de_mbz2);
574 initialise_mbr(uint8_t *mbr)
578 uint8_t ptype = 0, *rbm = mbr;
579 uint8_t bhead = 0, bsect = 0, bcyle = 0;
580 uint8_t ehead = 0, esect = 0, ecyle = 0;
582 extern unsigned char isohdpfx[][MBRSIZE];
584 memcpy(mbr, &isohdpfx[hd0 + 3 * partok], MBRSIZE);
587 memcpy(mbr, afp_header, sizeof(afp_header));
596 mbr += MBRSIZE; /* offset 432 */
598 tmp = lendian_int(de_lba * 4);
599 memcpy(mbr, &tmp, sizeof(tmp));
600 mbr += sizeof(tmp); /* offset 436 */
603 memcpy(mbr, &tmp, sizeof(tmp));
604 mbr += sizeof(tmp); /* offset 440 */
606 tmp = lendian_int(id);
607 memcpy(mbr, &tmp, sizeof(tmp));
608 mbr += sizeof(tmp); /* offset 444 */
612 mbr += 2; /* offset 446 */
615 psize = c * head * sector - offset;
617 bhead = (offset / sector) % head;
618 bsect = (offset % sector) + 1;
619 bcyle = offset / (head * sector);
621 bsect += (bcyle & 0x300) >> 2;
625 esect = sector + (((cc - 1) & 0x300) >> 2);
626 ecyle = (cc - 1) & 0xFF;
628 for (i = 1; i <= 4; i++)
642 tmp = lendian_int(offset);
643 memcpy(&mbr[8], &tmp, sizeof(tmp));
645 tmp = lendian_int(psize);
646 memcpy(&mbr[12], &tmp, sizeof(tmp));
648 if (i == 2 && (mode & EFI))
659 tmp = lendian_int(efi_lba * 4);
660 memcpy(&mbr[8], &tmp, sizeof(tmp));
662 tmp = lendian_int(efi_count);
663 memcpy(&mbr[12], &tmp, sizeof(tmp));
665 if (i == 3 && (mode & MAC))
676 tmp = lendian_int(mac_lba * 4);
677 memcpy(&mbr[8], &tmp, sizeof(tmp));
679 tmp = lendian_int(mac_count);
680 memcpy(&mbr[12], &tmp, sizeof(tmp));
692 display_mbr(const uint8_t *mbr, size_t len)
695 unsigned int i = 0, j = 0;
697 printf("sizeof(MBR): %zu bytes\n", len);
698 for (i = 0; i < len; i++)
713 printf("%c", isprint(mbr[j]) ? mbr[j] : '.');
720 uint32_t chksum_crc32 (unsigned char *block, unsigned int length)
722 register unsigned long crc;
726 for (i = 0; i < length; i++)
728 crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
730 return (crc ^ 0xFFFFFFFF);
734 reverse_uuid(uuid_t uuid)
736 uint8_t t, *p = (uint8_t *)uuid;
738 t = p[0]; p[0] = p[3]; p[3] = t;
739 t = p[1]; p[1] = p[2]; p[2] = t;
740 t = p[4]; p[4] = p[5]; p[5] = t;
741 t = p[6]; p[6] = p[7]; p[7] = t;
745 initialise_gpt(uint8_t *gpt, uint32_t current, uint32_t alternate, int primary)
747 struct gpt_header *header = (struct gpt_header *)gpt;
748 struct gpt_part_header *part;
750 int gptsize = 128 / 4 + 2;
753 /* 2048 bytes per partition, plus round to 2048 boundary */
754 hole = (apm_parts * 4) + 2;
758 uuid_generate(disk_uuid);
759 reverse_uuid(disk_uuid);
762 header->signature = lendian_64(0x5452415020494645);
763 header->revision = lendian_int(0x010000);
764 header->headerSize = lendian_int(0x5c);
765 header->currentLBA = lendian_64(current);
766 header->backupLBA = lendian_64(alternate);
767 header->firstUsableLBA = lendian_64(gptsize + hole);
768 header->lastUsableLBA = lendian_64((isostat.st_size + padding)/512 -
771 header->partitionEntriesLBA = lendian_64(0x02 + hole);
773 header->partitionEntriesLBA = lendian_64(current - (128 / 4));
774 header->numParts = lendian_int(0x80);
775 header->sizeOfPartitionEntries = lendian_int(0x80);
776 memcpy(header->diskGUID, disk_uuid, sizeof(uuid_t));
779 gpt += sizeof(struct gpt_header) + hole * 512;
781 gpt -= header->sizeOfPartitionEntries * header->numParts;
783 part = (struct gpt_part_header *)gpt;
785 uuid_generate(part_uuid);
786 uuid_generate(iso_uuid);
787 reverse_uuid(part_uuid);
788 reverse_uuid(iso_uuid);
791 memcpy(part->partGUID, iso_uuid, sizeof(uuid_t));
792 memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t));
793 part->firstLBA = lendian_64(0);
794 part->lastLBA = lendian_64(psize);
795 memcpy(part->name, "ISOHybrid ISO", 28);
797 gpt += sizeof(struct gpt_part_header);
800 memcpy(part->partGUID, part_uuid, sizeof(uuid_t));
801 memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t));
802 part->firstLBA = lendian_64(efi_lba * 4);
803 part->lastLBA = lendian_64(part->firstLBA + efi_count - 1);
804 memcpy(part->name, "ISOHybrid", 20);
806 gpt += sizeof(struct gpt_part_header);
809 gpt += sizeof(struct gpt_part_header);
813 memcpy(part->partGUID, part_uuid, sizeof(uuid_t));
814 memcpy(part->partTypeGUID, hfs_partition, sizeof(uuid_t));
815 part->firstLBA = lendian_64(mac_lba * 4);
816 part->lastLBA = lendian_64(part->firstLBA + mac_count - 1);
817 memcpy(part->name, "ISOHybrid", 20);
824 header->partitionEntriesCRC = lendian_int (chksum_crc32((uint8_t *)part,
825 header->numParts * header->sizeOfPartitionEntries));
827 header->headerCRC = lendian_int(chksum_crc32((uint8_t *)header,
828 header->headerSize));
832 initialise_apm(uint8_t *gpt, uint32_t start)
834 struct apple_part_header *part = (struct apple_part_header *)gpt;
836 part->signature = bendian_short(0x504d);
837 part->map_count = bendian_int(apm_parts);
838 part->start_block = bendian_int(1);
839 part->block_count = bendian_int(0x10);
840 strcpy(part->name, "Apple");
841 strcpy(part->type, "Apple_partition_map");
842 part->data_start = bendian_int(0);
843 part->data_count = bendian_int(10);
844 part->status = bendian_int(0x03);
846 part = (struct apple_part_header *)(gpt + 2048);
848 part->signature = bendian_short(0x504d);
849 part->map_count = bendian_int(3);
850 part->start_block = bendian_int(efi_lba);
851 part->block_count = bendian_int(efi_count);
852 strcpy(part->name, "EFI");
853 strcpy(part->type, "Apple_HFS");
854 part->data_start = bendian_int(0);
855 part->data_count = bendian_int(efi_count);
856 part->status = bendian_int(0x33);
858 part = (struct apple_part_header *)(gpt + 4096);
862 part->signature = bendian_short(0x504d);
863 part->map_count = bendian_int(3);
864 part->start_block = bendian_int(mac_lba);
865 part->block_count = bendian_int(mac_count);
866 strcpy(part->name, "EFI");
867 strcpy(part->type, "Apple_HFS");
868 part->data_start = bendian_int(0);
869 part->data_count = bendian_int(mac_count);
870 part->status = bendian_int(0x33);
872 part->signature = bendian_short(0x504d);
873 part->map_count = bendian_int(3);
874 part->start_block = bendian_int((start/2048) + 10);
875 part->block_count = bendian_int(efi_lba - start/2048 - 10);
876 strcpy(part->name, "ISO");
877 strcpy(part->type, "Apple_Free");
878 part->data_start = bendian_int(0);
879 part->data_count = bendian_int(efi_lba - start/2048 - 10);
880 part->status = bendian_int(0x01);
885 main(int argc, char *argv[])
889 uint8_t *buf = NULL, *bufz = NULL;
890 int cylsize = 0, frac = 0;
891 size_t orig_gpt_size, free_space, gpt_size;
892 struct iso_primary_descriptor descriptor;
894 prog = strcpy(alloca(strlen(argv[0]) + 1), argv[0]);
895 i = check_option(argc, argv);
905 if ((mode & EFI) && offset)
906 errx(1, "%s: --offset is invalid with UEFI images\n", argv[0]);
908 srand(time(NULL) << (getppid() << getpid()));
910 if (!(fp = fopen(argv[0], "r+")))
911 err(1, "could not open file `%s'", argv[0]);
913 if (fseek(fp, (16 << 11), SEEK_SET))
914 err(1, "%s: seek error - 0", argv[0]);
916 if (fread(&descriptor, sizeof(char), sizeof(descriptor), fp) != sizeof(descriptor))
917 err(1, "%s: read error - 0", argv[0]);
919 if (fseek(fp, 17 * 2048, SEEK_SET))
920 err(1, "%s: seek error - 1", argv[0]);
922 bufz = buf = calloc(BUFSIZE, sizeof(char));
923 if (fread(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE)
924 err(1, "%s", argv[0]);
926 if (check_banner(buf))
927 errx(1, "%s: could not find boot record", argv[0]);
930 printf("catalogue offset: %d\n", catoffset);
932 if (fseek(fp, catoffset * 2048, SEEK_SET))
933 err(1, "%s: seek error - 2", argv[0]);
936 memset(buf, 0, BUFSIZE);
937 if (fread(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE)
938 err(1, "%s", argv[0]);
940 if (check_catalogue(buf))
941 errx(1, "%s: invalid boot catalogue", argv[0]);
944 if (read_catalogue(buf))
945 errx(1, "%s: unexpected boot catalogue parameters", argv[0]);
954 if (!read_efi_section(buf)) {
956 if (!read_efi_catalogue(buf, &efi_count, &efi_lba) && efi_lba) {
959 errx(1, "%s: invalid efi catalogue", argv[0]);
962 errx(1, "%s: unable to find efi image", argv[0]);
970 if (!read_efi_section(buf)) {
972 if (!read_efi_catalogue(buf, &mac_count, &mac_lba) && mac_lba) {
975 errx(1, "%s: invalid efi catalogue", argv[0]);
978 errx(1, "%s: unable to find mac efi image", argv[0]);
982 if (fseek(fp, (de_lba * 2048 + 0x40), SEEK_SET))
983 err(1, "%s: seek error - 3", argv[0]);
986 memset(buf, 0, BUFSIZE);
987 if (fread(buf, sizeof(char), 4, fp) != 4)
988 err(1, "%s", argv[0]);
990 if (memcmp(buf, "\xFB\xC0\x78\x70", 4))
991 errx(1, "%s: boot loader does not have an isolinux.bin hybrid " \
992 "signature. Note that isolinux-debug.bin does not support " \
993 "hybrid booting", argv[0]);
995 if (stat(argv[0], &isostat))
996 err(1, "%s", argv[0]);
998 isosize = lendian_int(descriptor.size) * lendian_short(descriptor.block_size);
999 free_space = isostat.st_size - isosize;
1001 cylsize = head * sector * 512;
1002 frac = isostat.st_size % cylsize;
1003 padding = (frac > 0) ? cylsize - frac : 0;
1006 printf("imgsize: %zu, padding: %d\n", (size_t)isostat.st_size, padding);
1008 cc = c = ( isostat.st_size + padding) / cylsize;
1011 warnx("Warning: more than 1024 cylinders: %d", c);
1012 warnx("Not all BIOSes will be able to boot this device");
1018 if (fseek(fp, 440, SEEK_SET))
1019 err(1, "%s: seek error - 4", argv[0]);
1021 if (fread(&id, 1, 4, fp) != 4)
1022 err(1, "%s: read error", argv[0]);
1024 id = lendian_int(id);
1033 printf("id: %u\n", id);
1036 memset(buf, 0, BUFSIZE);
1037 i = initialise_mbr(buf);
1040 display_mbr(buf, i);
1042 if (fseek(fp, 0, SEEK_SET))
1043 err(1, "%s: seek error - 5", argv[0]);
1045 if (fwrite(buf, sizeof(char), i, fp) != (size_t)i)
1046 err(1, "%s: write error - 1", argv[0]);
1049 reverse_uuid(basic_partition);
1050 reverse_uuid(hfs_partition);
1052 /* 512 byte header, 128 entries of 128 bytes */
1053 orig_gpt_size = gpt_size = 512 + (128 * 128);
1055 /* Leave space for the APM if necessary */
1057 gpt_size += (4 * 2048);
1059 buf = calloc(gpt_size, sizeof(char));
1060 memset(buf, 0, gpt_size);
1063 * We need to ensure that we have enough space for the secondary GPT.
1064 * Unlike the primary, this doesn't need a hole for the APM. We still
1065 * want to be 1MB aligned so just bump the padding by a megabyte.
1067 if (free_space < orig_gpt_size && padding < orig_gpt_size) {
1068 padding += 1024 * 1024;
1072 * Determine the size of the ISO filesystem. This will define the size
1073 * of the partition that covers it.
1075 psize = isosize / 512;
1078 * Primary GPT starts at sector 1, secondary GPT starts at 1 sector
1079 * before the end of the image
1081 initialise_gpt(buf, 1, (isostat.st_size + padding - 1024) / 512, 1);
1083 if (fseek(fp, 512, SEEK_SET))
1084 err(1, "%s: seek error - 6", argv[0]);
1086 if (fwrite(buf, sizeof(char), gpt_size, fp) != (size_t)gpt_size)
1087 err(1, "%s: write error - 2", argv[0]);
1092 /* Apple partition entries filling 2048 bytes each */
1093 int apm_size = apm_parts * 2048;
1095 buf = realloc(buf, apm_size);
1096 memset(buf, 0, apm_size);
1098 initialise_apm(buf, APM_OFFSET);
1100 fseek(fp, APM_OFFSET, SEEK_SET);
1101 fwrite(buf, sizeof(char), apm_size, fp);
1106 if (fsync(fileno(fp)))
1107 err(1, "%s: could not synchronise", argv[0]);
1109 if (ftruncate(fileno(fp), isostat.st_size + padding))
1110 err(1, "%s: could not add padding bytes", argv[0]);
1114 buf = realloc(buf, orig_gpt_size);
1115 memset(buf, 0, orig_gpt_size);
1117 buf += orig_gpt_size - sizeof(struct gpt_header);
1119 initialise_gpt(buf, (isostat.st_size + padding - 1024) / 512, 1, 0);
1121 /* Shift back far enough to write the 128 GPT entries */
1122 buf -= 128 * sizeof(struct gpt_part_header);
1125 * Seek far enough back that the gpt header is 512 bytes before the
1129 if (fseek(fp, (isostat.st_size + padding) - orig_gpt_size - 512,
1131 err(1, "%s: seek error - 8", argv[0]);
1133 if (fwrite(buf, sizeof(char), orig_gpt_size, fp) != orig_gpt_size)
1134 err(1, "%s: write error - 4", argv[0]);