ldlinux: Allow a held shift key to override UI as well as DEFAULT
[syslinux.git] / utils / isohybrid.c
blob410bb606374e19cb9e71c69d29508c2025104943
1 /*
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
4 * disk.
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
14 * version.
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
19 * more details.
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>.
26 #include <err.h>
27 #include <time.h>
28 #include <ctype.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <alloca.h>
32 #include <getopt.h>
33 #include <signal.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <sys/stat.h>
38 #include <inttypes.h>
39 #include <uuid/uuid.h>
41 #include "isohybrid.h"
43 char *prog = NULL;
44 extern int opterr, optind;
45 struct stat isostat;
46 unsigned int padding = 0;
48 uuid_t disk_uuid, part_uuid, iso_uuid;
50 uint8_t mode = 0;
51 enum { VERBOSE = 1 , EFI = 2 , MAC = 4};
53 /* user options */
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 */
65 uint16_t ve[16];
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 */
72 uint32_t de_lba = 0;
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;
79 int apm_parts = 3;
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 {
156 uint8_t ignore [80];
157 uint32_t size;
158 uint8_t ignore2 [44];
159 uint16_t block_size;
162 struct gpt_header {
163 uint64_t signature;
164 uint32_t revision;
165 uint32_t headerSize;
166 uint32_t headerCRC;
167 uint32_t reserved;
168 uint64_t currentLBA;
169 uint64_t backupLBA;
170 uint64_t firstUsableLBA;
171 uint64_t lastUsableLBA;
172 uuid_t diskGUID;
173 uint64_t partitionEntriesLBA;
174 uint32_t numParts;
175 uint32_t sizeOfPartitionEntries;
176 uint32_t partitionEntriesCRC;
177 uint8_t reserved2[420];
180 struct gpt_part_header {
181 uuid_t partTypeGUID;
182 uuid_t partGUID;
183 uint64_t firstLBA;
184 uint64_t lastLBA;
185 uint64_t attributes;
186 uint16_t name[36];
189 #define APM_OFFSET 2048
191 struct apple_part_header {
192 uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */
193 uint16_t res1;
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 */
202 uint32_t boot_start;
203 uint32_t boot_count;
204 uint32_t boot_load;
205 uint32_t boot_load2;
206 uint32_t boot_entry;
207 uint32_t boot_entry2;
208 uint32_t boot_cksum;
209 char processor[16]; /* Contains 680x0, x=0,2,3,4; or empty */
210 uint32_t driver_sig;
211 char _padding[372];
215 void
216 usage(void)
218 printf("Usage: %s [OPTIONS] <boot.iso>\n", prog);
222 void
223 printh(void)
225 #define FMT "%-18s %s\n"
227 usage();
229 printf("\n");
230 printf("Options:\n");
231 printf(FMT, " -h <X>", "Number of geometry heads (default 64)");
232 printf(FMT, " -s <X>", "Number of geometry sectors (default 32)");
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");
240 printf("\n");
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");
245 printf("\n");
246 printf(FMT, " -? --help", "Display this help");
247 printf(FMT, " -v --verbose", "Display verbose output");
248 printf(FMT, " -V --version", "Display version information");
250 printf("\n");
251 printf("Report bugs to <pj.pandit@yahoo.co.in>\n");
256 check_option(int argc, char *argv[])
258 char *err = NULL;
259 int n = 0, ind = 0;
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' },
279 { 0, 0, 0, 0 }
282 opterr = mode = 0;
283 while ((n = getopt_long_only(argc, argv, optstr, lopt, &ind)) != -1)
285 switch (n)
287 case 'h':
288 head = strtoul(optarg, &err, 0);
289 if (head < 1 || head > 256)
290 errx(1, "invalid head: `%s', 1 <= head <= 256", optarg);
291 break;
293 case 's':
294 sector = strtoul(optarg, &err, 0);
295 if (sector < 1 || sector > 63)
296 errx(1, "invalid sector: `%s', 1 <= sector <= 63", optarg);
297 break;
299 case 'e':
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");
305 break;
307 case 'o':
308 offset = strtoul(optarg, &err, 0);
309 if (*err || offset > 64)
310 errx(1, "invalid offset: `%s', 0 <= offset <= 64", optarg);
311 break;
313 case 't':
314 type = strtoul(optarg, &err, 0);
315 if (*err || type > 255)
316 errx(1, "invalid type: `%s', 0 <= type <= 255", optarg);
317 break;
319 case 'i':
320 id = strtoul(optarg, &err, 0);
321 if (*err)
322 errx(1, "invalid id: `%s'", optarg);
323 break;
325 case 'f':
326 hd0 = 1;
327 break;
329 case 'c':
330 hd0 = 2;
331 break;
333 case 'p':
334 partok = 1;
335 break;
337 case 'u':
338 mode |= EFI;
339 if (entry)
340 errx(1, "setting an entry is unsupported with EFI or Mac");
341 break;
343 case 'm':
344 mode |= MAC;
345 if (entry)
346 errx(1, "setting an entry is unsupported with EFI or Mac");
347 break;
349 case 'v':
350 mode |= VERBOSE;
351 break;
353 case 'V':
354 printf("%s version %s\n", prog, VERSION);
355 exit(0);
357 case ':':
358 errx(1, "option `-%c' takes an argument", optopt);
360 default:
361 case '?':
362 if (optopt)
363 errx(1, "invalid option `-%c', see --help", optopt);
365 printh();
366 exit(0);
370 return optind;
373 uint16_t
374 bendian_short(const uint16_t s)
376 uint16_t r = 1;
378 if (!*(uint8_t *)&r)
379 return s;
381 r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
383 return r;
387 uint32_t
388 bendian_int(const uint32_t s)
390 uint32_t r = 1;
392 if (!*(uint8_t *)&r)
393 return s;
395 r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
396 | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
398 return r;
401 uint16_t
402 lendian_short(const uint16_t s)
404 uint16_t r = 1;
406 if (*(uint8_t *)&r)
407 return s;
409 r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
411 return r;
415 uint32_t
416 lendian_int(const uint32_t s)
418 uint32_t r = 1;
420 if (*(uint8_t *)&r)
421 return s;
423 r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
424 | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
426 return r;
429 uint64_t
430 lendian_64(const uint64_t s)
432 uint64_t r = 1;
434 if (*(uint8_t *)&r)
435 return s;
437 r = (s & 0x00000000000000FFull) << 56 | (s & 0xFF00000000000000ull) >> 56
438 | (s & 0x000000000000FF00ull) << 40 | (s & 0x00FF000000000000ull) >> 40
439 | (s & 0x0000000000FF0000ull) << 24 | (s & 0x0000FF0000000000ull) >> 24
440 | (s & 0x00000000FF000000ull) << 8 | (s & 0x000000FF00000000ull) >> 8;
442 return r;
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" \
451 "\0\0\0\0\0";
453 if (!buf || memcmp(buf, banner, sizeof(banner) - 1))
454 return 1;
456 buf += sizeof(banner) - 1;
457 memcpy(&catoffset, buf, sizeof(catoffset));
459 catoffset = lendian_int(catoffset);
461 return 0;
466 check_catalogue(const uint8_t *buf)
468 int i = 0;
470 for (i = 0, cs = 0; i < 16; i++)
472 ve[i] = 0;
473 memcpy(&ve[i], buf, sizeof(ve[i]));
475 ve[i] = lendian_short(ve[i]);
477 buf += 2;
478 cs += ve[i];
480 if (mode & VERBOSE)
481 printf("ve[%d]: %d, cs: %d\n", i, ve[i], cs);
483 if ((ve[0] != 0x0001) || (ve[15] != 0xAA55) || (cs & 0xFFFF))
484 return 1;
486 return 0;
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);
498 buf += 2;
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);
505 buf += 2;
507 memcpy(&de_lba, buf, 4);
508 de_lba = lendian_int(de_lba);
509 buf += 4;
511 memcpy(&de_mbz2, buf, 2);
512 de_mbz2 = lendian_short(de_mbz2);
513 buf += 2;
515 if (de_boot != 0x88 || de_media != 0
516 || (de_seg != 0 && de_seg != 0x7C0) || de_count != 4)
517 return 1;
519 return 0;
524 read_efi_section(const uint8_t *buf)
526 unsigned char header_indicator;
527 unsigned char platform_id;
528 short count;
530 memcpy(&header_indicator, buf++, 1);
531 memcpy(&platform_id, buf++, 1);
533 memcpy(&count, buf, 2);
534 count = lendian_short(count);
535 buf += 2;
537 if (platform_id == 0xef)
538 return 0;
540 return 1;
544 read_efi_catalogue(const uint8_t *buf, uint16_t *count, uint32_t *lba)
546 buf += 6;
548 memcpy(count, buf, 2);
549 *count = lendian_short(*count);
550 buf += 2;
552 memcpy(lba, buf, 4);
553 *lba = lendian_int(*lba);
554 buf += 6;
556 return 0;
560 void
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)
576 int i = 0;
577 uint32_t tmp = 0;
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);
586 if (mode & MAC) {
587 memcpy(mbr, afp_header, sizeof(afp_header));
590 if (!entry)
591 entry = 1;
593 if (mode & EFI)
594 type = 0;
596 mbr += MBRSIZE; /* offset 432 */
598 tmp = lendian_int(de_lba * 4);
599 memcpy(mbr, &tmp, sizeof(tmp));
600 mbr += sizeof(tmp); /* offset 436 */
602 tmp = 0;
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 */
610 mbr[0] = '\0';
611 mbr[1] = '\0';
612 mbr += 2; /* offset 446 */
614 ptype = type;
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;
622 bcyle &= 0xFF;
624 ehead = head - 1;
625 esect = sector + (((cc - 1) & 0x300) >> 2);
626 ecyle = (cc - 1) & 0xFF;
628 for (i = 1; i <= 4; i++)
630 memset(mbr, 0, 16);
631 if (i == entry)
633 mbr[0] = 0x80;
634 mbr[1] = bhead;
635 mbr[2] = bsect;
636 mbr[3] = bcyle;
637 mbr[4] = ptype;
638 mbr[5] = ehead;
639 mbr[6] = esect;
640 mbr[7] = ecyle;
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))
650 mbr[0] = 0x0;
651 mbr[1] = 0xfe;
652 mbr[2] = 0xff;
653 mbr[3] = 0xff;
654 mbr[4] = 0xef;
655 mbr[5] = 0xfe;
656 mbr[6] = 0xff;
657 mbr[7] = 0xff;
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))
667 mbr[0] = 0x0;
668 mbr[1] = 0xfe;
669 mbr[2] = 0xff;
670 mbr[3] = 0xff;
671 mbr[4] = 0x0;
672 mbr[5] = 0xfe;
673 mbr[6] = 0xff;
674 mbr[7] = 0xff;
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));
682 mbr += 16;
684 mbr[0] = 0x55;
685 mbr[1] = 0xAA;
686 mbr += 2;
688 return mbr - rbm;
691 void
692 display_mbr(const uint8_t *mbr, size_t len)
694 unsigned char c = 0;
695 unsigned int i = 0, j = 0;
697 printf("sizeof(MBR): %zu bytes\n", len);
698 for (i = 0; i < len; i++)
700 if (!(i % 16))
701 printf("%04d ", i);
703 if (!(i % 8))
704 printf(" ");
706 c = mbr[i];
707 printf("%02x ", c);
709 if (!((i + 1) % 16))
711 printf(" |");
712 for (; j <= i; j++)
713 printf("%c", isprint(mbr[j]) ? mbr[j] : '.');
714 printf("|\n");
720 uint32_t chksum_crc32 (unsigned char *block, unsigned int length)
722 register unsigned long crc;
723 unsigned long i;
725 crc = 0xFFFFFFFF;
726 for (i = 0; i < length; i++)
728 crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
730 return (crc ^ 0xFFFFFFFF);
733 void
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;
744 void
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;
749 int hole = 0;
750 int gptsize = 128 / 4 + 2;
752 if (mac_lba) {
753 /* 2048 bytes per partition, plus round to 2048 boundary */
754 hole = (apm_parts * 4) + 2;
757 if (primary) {
758 uuid_generate(disk_uuid);
759 reverse_uuid(disk_uuid);
762 header->signature = lendian_64(0x5452415020494645ull);
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 -
769 gptsize);
770 if (primary)
771 header->partitionEntriesLBA = lendian_64(0x02 + hole);
772 else
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));
778 if (primary)
779 gpt += sizeof(struct gpt_header) + hole * 512;
780 else
781 gpt -= header->sizeOfPartitionEntries * header->numParts;
783 part = (struct gpt_part_header *)gpt;
784 if (primary) {
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);
798 part++;
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);
808 if (mac_lba) {
809 gpt += sizeof(struct gpt_part_header);
811 part++;
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);
819 part--;
822 part--;
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));
831 void
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);
860 if (mac_lba)
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);
871 } else {
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[])
887 int i = 0;
888 FILE *fp = NULL;
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);
896 argc -= i;
897 argv += i;
899 if (!argc)
901 usage();
902 return 1;
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]);
929 if (mode & VERBOSE)
930 printf("catalogue offset: %d\n", catoffset);
932 if (fseek(fp, catoffset * 2048, SEEK_SET))
933 err(1, "%s: seek error - 2", argv[0]);
935 buf = bufz;
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]);
943 buf += sizeof(ve);
944 if (read_catalogue(buf))
945 errx(1, "%s: unexpected boot catalogue parameters", argv[0]);
947 if (mode & VERBOSE)
948 display_catalogue();
950 buf += 32;
952 if (mode & EFI)
954 if (!read_efi_section(buf)) {
955 buf += 32;
956 if (!read_efi_catalogue(buf, &efi_count, &efi_lba) && efi_lba) {
957 offset = 0;
958 } else {
959 errx(1, "%s: invalid efi catalogue", argv[0]);
961 } else {
962 errx(1, "%s: unable to find efi image", argv[0]);
966 buf += 32;
968 if (mode & MAC)
970 if (!read_efi_section(buf)) {
971 buf += 32;
972 if (!read_efi_catalogue(buf, &mac_count, &mac_lba) && mac_lba) {
973 offset = 0;
974 } else {
975 errx(1, "%s: invalid efi catalogue", argv[0]);
977 } else {
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]);
985 buf = bufz;
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;
1005 if (mode & VERBOSE)
1006 printf("imgsize: %zu, padding: %d\n", (size_t)isostat.st_size, padding);
1008 cc = c = ( isostat.st_size + padding) / cylsize;
1009 if (c > 1024)
1011 warnx("Warning: more than 1024 cylinders: %d", c);
1012 warnx("Not all BIOSes will be able to boot this device");
1013 cc = 1024;
1016 if (!id)
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);
1025 if (!id)
1027 if (mode & VERBOSE)
1028 printf("random ");
1029 id = rand();
1032 if (mode & VERBOSE)
1033 printf("id: %u\n", id);
1035 buf = bufz;
1036 memset(buf, 0, BUFSIZE);
1037 i = initialise_mbr(buf);
1039 if (mode & VERBOSE)
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]);
1048 if (efi_lba) {
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 */
1056 if (mac_lba)
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]);
1090 if (mac_lba)
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);
1104 if (padding)
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]);
1113 if (efi_lba) {
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
1126 * end of the image
1129 if (fseek(fp, (isostat.st_size + padding) - orig_gpt_size - 512,
1130 SEEK_SET))
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]);
1137 free(buf);
1138 fclose(fp);
1140 return 0;