xref: /reactos/sdk/tools/isohybrid/isohybrid.c (revision cdf90707)
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.
5  *
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.
8  *
9  * Copyright (C) 2010 P J P <pj.pandit@yahoo.co.in>
10  *
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.
15  *
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.
20  *
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>.
23  *
24  */
25 
26 #define _FILE_OFFSET_BITS 64
27 //#include <err.h>
28 #include <time.h>
29 #include <ctype.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 //#include <alloca.h>
33 //#include <getopt.h>
34 #include <signal.h>
35 #include <stdlib.h>
36 #include <string.h>
37 //#include <unistd.h>
38 #include <sys/stat.h>
39 //#include <inttypes.h>
40 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
41 #include <uuid/uuid.h>
42 #endif
43 
44 #include "isohybrid.h"
45 #include "reactos_support_code.h"
46 
47 char *prog = NULL;
48 extern int opterr, optind;
49 struct stat isostat;
50 unsigned int padding = 0;
51 
52 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
53 uuid_t disk_uuid, part_uuid, iso_uuid;
54 #endif
55 
56 uint8_t mode = 0;
57 enum { VERBOSE = 1 , EFI = 2 , MAC = 4};
58 
59 /* user options */
60 uint32_t head = 64;             /* 1 <= head <= 256 */
61 uint32_t sector = 32;           /* 1 <= sector <= 63  */
62 
63 uint32_t entry = 0;             /* partition number: 1 <= entry <= 4 */
64 uint32_t offset = 0;            /* partition offset: 0 <= offset <= 64 */
65 uint32_t type = 0x17;           /* partition type: 0 <= type <= 255 */
66 uint32_t id = 0;                /* MBR: 0 <= id <= 0xFFFFFFFF(4294967296) */
67 
68 uint8_t hd0 = 0;                /* 0 <= hd0 <= 2 */
69 uint8_t partok = 0;             /* 0 <= partok <= 1 */
70 
71 char mbr_template_path[1024] = {0};   /* Path to MBR template */
72 
73 uint16_t ve[16];
74 uint32_t catoffset = 0;
75 uint32_t c = 0, cc = 0, cs = 0;
76 
77 uint32_t psize = 0, isosize = 0;
78 
79 /* boot catalogue parameters */
80 uint32_t de_lba = 0;
81 uint16_t de_seg = 0, de_count = 0, de_mbz2 = 0;
82 uint8_t de_boot = 0, de_media = 0, de_sys = 0, de_mbz1 = 0;
83 uint32_t efi_lba = 0, mac_lba = 0;
84 uint16_t efi_count = 0, mac_count = 0;
85 uint8_t efi_boot = 0, efi_media = 0, efi_sys = 0;
86 
87 int apm_parts = 3;
88 
89 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
90 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 };
91 
92 uuid_t efi_system_partition = {0xC1, 0x2A, 0x73, 0x28, 0xF8, 0x1F, 0x11, 0xD2, 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B};
93 uuid_t basic_partition = {0xEB,0xD0,0xA0,0xA2,0xB9,0xE5,0x44,0x33,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7};
94 uuid_t hfs_partition = {0x48, 0x46, 0x53, 0x00, 0x00, 0x00, 0x11, 0xAA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC};
95 #endif
96 
97 uint32_t crc_tab[256] =
98 {
99     0, 0x77073096, 0xEE0E612C, 0x990951BA,
100     0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
101     0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
102     0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
103     0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
104     0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
105     0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
106     0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
107     0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
108     0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
109     0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
110     0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
111     0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
112     0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
113     0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
114     0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
115     0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
116     0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
117     0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
118     0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
119     0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
120     0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
121     0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
122     0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
123     0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
124     0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
125     0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
126     0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
127     0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
128     0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
129     0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
130     0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
131     0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
132     0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
133     0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
134     0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
135     0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
136     0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
137     0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
138     0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
139     0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
140     0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
141     0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
142     0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
143     0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
144     0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
145     0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
146     0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
147     0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
148     0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
149     0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
150     0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
151     0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
152     0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
153     0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
154     0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
155     0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
156     0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
157     0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
158     0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
159     0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
160     0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
161     0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
162     0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
163 };
164 
165 struct iso_primary_descriptor {
166     uint8_t ignore [80];
167     uint32_t size;
168     uint8_t ignore2 [44];
169     uint16_t block_size;
170 };
171 
172 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
173 struct gpt_header {
174     uint64_t signature;
175     uint32_t revision;
176     uint32_t headerSize;
177     uint32_t headerCRC;
178     uint32_t reserved;
179     uint64_t currentLBA;
180     uint64_t backupLBA;
181     uint64_t firstUsableLBA;
182     uint64_t lastUsableLBA;
183     uuid_t diskGUID;
184     uint64_t partitionEntriesLBA;
185     uint32_t numParts;
186     uint32_t sizeOfPartitionEntries;
187     uint32_t partitionEntriesCRC;
188     uint8_t reserved2[420];
189 };
190 
191 struct gpt_part_header {
192     uuid_t partTypeGUID;
193     uuid_t partGUID;
194     uint64_t firstLBA;
195     uint64_t lastLBA;
196     uint64_t attributes;
197     uint16_t name[36];
198 };
199 
200 #define APM_OFFSET 2048
201 
202 struct apple_part_header {
203     uint16_t        signature;      /* expected to be MAC_PARTITION_MAGIC */
204     uint16_t        res1;
205     uint32_t        map_count;      /* # blocks in partition map */
206     uint32_t        start_block;    /* absolute starting block # of partition */
207     uint32_t        block_count;    /* number of blocks in partition */
208     char            name[32];       /* partition name */
209     char            type[32];       /* string type description */
210     uint32_t        data_start;     /* rel block # of first data block */
211     uint32_t        data_count;     /* number of data blocks */
212     uint32_t        status;         /* partition status bits */
213     uint32_t        boot_start;
214     uint32_t        boot_count;
215     uint32_t        boot_load;
216     uint32_t        boot_load2;
217     uint32_t        boot_entry;
218     uint32_t        boot_entry2;
219     uint32_t        boot_cksum;
220     char            processor[16];  /* Contains 680x0, x=0,2,3,4; or empty */
221     uint32_t        driver_sig;
222     char            _padding[372];
223 };
224 #endif
225 
226 
227 void
228 usage(void)
229 {
230     printf("Usage: %s [OPTIONS] <boot.iso>\n", prog);
231 }
232 
233 
234 void
235 printh(void)
236 {
237 #define FMT "%-20s %s\n"
238 
239     usage();
240 
241     printf("\n");
242     printf("Options:\n");
243     printf(FMT, "   -h <X>", "Number of geometry heads (default 64)");
244     printf(FMT, "   -s <X>", "Number of geometry sectors (default 32)");
245     printf(FMT, "   -e --entry", "Specify partition entry number (1-4)");
246     printf(FMT, "   -o --offset", "Specify partition offset (default 0)");
247     printf(FMT, "   -t --type", "Specify partition type (default 0x17)");
248     printf(FMT, "   -i --id", "Specify MBR ID (default random)");
249 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
250     printf(FMT, "   -u --uefi", "Build EFI bootable image");
251     printf(FMT, "   -m --mac", "Add AFP table support");
252 #endif
253     printf(FMT, "   -b --mbr <PATH>", "Load MBR from PATH");
254 
255     printf("\n");
256     printf(FMT, "   --forcehd0", "Assume we are loaded as disk ID 0");
257     printf(FMT, "   --ctrlhd0", "Assume disk ID 0 if the Ctrl key is pressed");
258     printf(FMT, "   --partok", "Allow booting from within a partition");
259 
260     printf("\n");
261     printf(FMT, "   -? --help", "Display this help");
262     printf(FMT, "   -v --verbose", "Display verbose output");
263     printf(FMT, "   -V --version", "Display version information");
264 
265     printf("\n");
266     printf("Report bugs to <pj.pandit@yahoo.co.in>\n");
267 }
268 
269 
270 int
271 check_option(int argc, char *argv[])
272 {
273     char *err = NULL;
274     int n = 0, ind = 0;
275 
276     const char optstr[] = ":h:s:e:o:t:i:b:umfcp?vV";
277     struct option lopt[] = \
278     {
279         { "entry", required_argument, NULL, 'e' },
280         { "offset", required_argument, NULL, 'o' },
281         { "type", required_argument, NULL, 't' },
282         { "id", required_argument, NULL, 'i' },
283 
284         { "forcehd0", no_argument, NULL, 'f' },
285         { "ctrlhd0", no_argument, NULL, 'c' },
286         { "partok", no_argument, NULL, 'p'},
287 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
288 	{ "uefi", no_argument, NULL, 'u'},
289 	{ "mac", no_argument, NULL, 'm'},
290 #endif
291         { "mbr", required_argument, NULL, 'b' },
292 
293         { "help", no_argument, NULL, '?' },
294         { "verbose", no_argument, NULL, 'v' },
295         { "version", no_argument, NULL, 'V' },
296 
297         { 0, 0, 0, 0 }
298     };
299 
300     opterr = mode = 0;
301     while ((n = getopt_long_only(argc, argv, optstr, lopt, &ind)) != -1)
302     {
303         switch (n)
304         {
305         case 'h':
306             head = strtoul(optarg, &err, 0);
307             if (head < 1 || head > 256)
308                 errx(1, "invalid head: `%s', 1 <= head <= 256", optarg);
309             break;
310 
311         case 's':
312             sector = strtoul(optarg, &err, 0);
313             if (sector < 1 || sector > 63)
314                 errx(1, "invalid sector: `%s', 1 <= sector <= 63", optarg);
315             break;
316 
317         case 'e':
318             entry = strtoul(optarg, &err, 0);
319             if (entry < 1 || entry > 4)
320                 errx(1, "invalid entry: `%s', 1 <= entry <= 4", optarg);
321 	    if (mode & MAC || mode & EFI)
322 		errx(1, "setting an entry is unsupported with EFI or Mac");
323             break;
324 
325         case 'o':
326             offset = strtoul(optarg, &err, 0);
327             if (*err || offset > 64)
328                 errx(1, "invalid offset: `%s', 0 <= offset <= 64", optarg);
329             break;
330 
331         case 't':
332             type = strtoul(optarg, &err, 0);
333             if (*err || type > 255)
334                 errx(1, "invalid type: `%s', 0 <= type <= 255", optarg);
335             break;
336 
337         case 'i':
338             id = strtoul(optarg, &err, 0);
339             if (*err)
340                 errx(1, "invalid id: `%s'", optarg);
341             break;
342 
343         case 'f':
344             hd0 = 1;
345             break;
346 
347         case 'c':
348             hd0 = 2;
349             break;
350 
351         case 'p':
352             partok = 1;
353             break;
354 
355 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
356 	case 'u':
357 	    mode |= EFI;
358 	    if (entry)
359 		errx(1, "setting an entry is unsupported with EFI or Mac");
360 	    break;
361 
362 	case 'm':
363 	    mode |= MAC;
364 	    if (entry)
365 		errx(1, "setting an entry is unsupported with EFI or Mac");
366 	    break;
367 #endif
368 
369 	case 'b':
370             if (strlen(optarg) >= sizeof(mbr_template_path))
371                 errx(1, "--mbr : Path too long");
372             strcpy(mbr_template_path, optarg);
373             break;
374 
375         case 'v':
376             mode |= VERBOSE;
377             break;
378 
379         case 'V':
380             printf("%s version %s\n", prog, VERSION);
381             exit(0);
382 
383         case ':':
384             errx(1, "option `-%c' takes an argument", optopt);
385 
386         default:
387         case '?':
388             if (optopt)
389                 errx(1, "invalid option `-%c', see --help", optopt);
390 
391             printh();
392             exit(0);
393         }
394     }
395 
396     return optind;
397 }
398 
399 uint16_t
400 bendian_short(const uint16_t s)
401 {
402     uint16_t r = 1;
403 
404     if (!*(uint8_t *)&r)
405         return s;
406 
407     r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
408 
409     return r;
410 }
411 
412 
413 uint32_t
414 bendian_int(const uint32_t s)
415 {
416     uint32_t r = 1;
417 
418     if (!*(uint8_t *)&r)
419         return s;
420 
421     r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
422         | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
423 
424     return r;
425 }
426 
427 uint16_t
428 lendian_short(const uint16_t s)
429 {
430     uint16_t r = 1;
431 
432     if (*(uint8_t *)&r)
433         return s;
434 
435     r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
436 
437     return r;
438 }
439 
440 
441 uint32_t
442 lendian_int(const uint32_t s)
443 {
444     uint32_t r = 1;
445 
446     if (*(uint8_t *)&r)
447         return s;
448 
449     r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
450         | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
451 
452     return r;
453 }
454 
455 uint64_t
456 lendian_64(const uint64_t s)
457 {
458 	uint64_t r = 1;
459 
460 	if (*(uint8_t *)&r)
461 		return s;
462 
463        r = (s & 0x00000000000000FFull) << 56 | (s & 0xFF00000000000000ull) >> 56
464             | (s & 0x000000000000FF00ull) << 40 | (s & 0x00FF000000000000ull) >> 40
465             | (s & 0x0000000000FF0000ull) << 24 | (s & 0x0000FF0000000000ull) >> 24
466             | (s & 0x00000000FF000000ull) << 8 | (s & 0x000000FF00000000ull) >> 8;
467 
468 	return r;
469 }
470 
471 
472 int
473 check_banner(const uint8_t *buf)
474 {
475     static const char banner[] = "\0CD001\1EL TORITO SPECIFICATION\0\0\0\0" \
476         "\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" \
477         "\0\0\0\0\0";
478 
479     if (!buf || memcmp(buf, banner, sizeof(banner) - 1))
480         return 1;
481 
482     buf += sizeof(banner) - 1;
483     memcpy(&catoffset, buf, sizeof(catoffset));
484 
485     catoffset = lendian_int(catoffset);
486 
487     return 0;
488 }
489 
490 
491 int
492 check_catalogue(const uint8_t *buf)
493 {
494     int i = 0;
495 
496     for (i = 0, cs = 0; i < 16; i++)
497     {
498         ve[i] = 0;
499         memcpy(&ve[i], buf, sizeof(ve[i]));
500 
501         ve[i] = lendian_short(ve[i]);
502 
503         buf += 2;
504         cs += ve[i];
505 
506         if (mode & VERBOSE)
507             printf("ve[%d]: %d, cs: %d\n", i, ve[i], cs);
508     }
509     if ((ve[0] != 0x0001) || (ve[15] != 0xAA55) || (cs & 0xFFFF))
510         return 1;
511 
512     return 0;
513 }
514 
515 
516 int
517 read_catalogue(const uint8_t *buf)
518 {
519     memcpy(&de_boot, buf++, 1);
520     memcpy(&de_media, buf++, 1);
521 
522     memcpy(&de_seg, buf, 2);
523     de_seg = lendian_short(de_seg);
524     buf += 2;
525 
526     memcpy(&de_sys, buf++, 1);
527     memcpy(&de_mbz1, buf++, 1);
528 
529     memcpy(&de_count, buf, 2);
530     de_count = lendian_short(de_count);
531     buf += 2;
532 
533     memcpy(&de_lba, buf, 4);
534     de_lba = lendian_int(de_lba);
535     buf += 4;
536 
537     memcpy(&de_mbz2, buf, 2);
538     de_mbz2 = lendian_short(de_mbz2);
539     buf += 2;
540 
541     if (de_boot != 0x88 || de_media != 0
542         || (de_seg != 0 && de_seg != 0x7C0) || de_count != 4)
543         return 1;
544 
545     return 0;
546 }
547 
548 
549 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
550 int
551 read_efi_section(const uint8_t *buf)
552 {
553 	unsigned char header_indicator;
554 	unsigned char platform_id;
555 	short count;
556 
557 	memcpy(&header_indicator, buf++, 1);
558 	memcpy(&platform_id, buf++, 1);
559 
560 	memcpy(&count, buf, 2);
561 	count = lendian_short(count);
562 	buf += 2;
563 
564 	if (platform_id == 0xef)
565 		return 0;
566 
567 	return 1;
568 }
569 
570 int
571 read_efi_catalogue(const uint8_t *buf, uint16_t *count, uint32_t *lba)
572 {
573     buf += 6;
574 
575     memcpy(count, buf, 2);
576     *count = lendian_short(*count);
577     buf += 2;
578 
579     memcpy(lba, buf, 4);
580     *lba = lendian_int(*lba);
581     buf += 6;
582 
583     return 0;
584 }
585 #endif
586 
587 
588 void
589 display_catalogue(void)
590 {
591     printf("de_boot: %hhu\n", de_boot);
592     printf("de_media: %hhu\n", de_media);
593     printf("de_seg: %hu\n", de_seg);
594     printf("de_sys: %hhu\n", de_sys);
595     printf("de_mbz1: %hhu\n", de_mbz1);
596     printf("de_count: %hu\n", de_count);
597     printf("de_lba: %u\n", de_lba);
598     printf("de_mbz2: %hu\n", de_mbz2);
599 }
600 
601 
602 void
603 read_mbr_template(char *path, uint8_t *mbr)
604 {
605     FILE *fp;
606     size_t ret;
607 
608     fp = fopen(path, "rb");
609     if (fp == NULL)
610         err(1, "could not open MBR template file `%s'", path);
611     clearerr(fp);
612     ret = fread(mbr, 1, MBRSIZE, fp);
613     if (ferror(fp) || ret != MBRSIZE)
614         err(1, "error while reading MBR template file `%s'", path);
615     fclose(fp);
616 }
617 
618 
619 size_t
620 initialise_mbr(uint8_t *mbr)
621 {
622     int i = 0;
623     uint32_t tmp = 0;
624     uint8_t ptype = 0, *rbm = mbr;
625     uint8_t bhead = 0, bsect = 0, bcyle = 0;
626     uint8_t ehead = 0, esect = 0, ecyle = 0;
627 
628 #ifndef ISOHYBRID_C_STANDALONE
629     extern unsigned char isohdpfx[][MBRSIZE];
630 #endif
631 
632     if (mbr_template_path[0]) {
633         read_mbr_template(mbr_template_path, mbr);
634     } else {
635 
636 #ifdef ISOHYBRID_C_STANDALONE
637 
638         err(1, "This is a standalone binary. You must specify --mbr. E.g with /usr/lib/syslinux/isohdpfx.bin");
639 
640 #else
641 
642         memcpy(mbr, &isohdpfx[hd0 + 3 * partok], MBRSIZE);
643 
644 #endif /* ! ISOHYBRID_C_STANDALONE */
645 
646     }
647 
648 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
649     if (mode & MAC) {
650 	memcpy(mbr, afp_header, sizeof(afp_header));
651     }
652 #endif
653 
654     if (!entry)
655 	entry = 1;
656 
657 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
658     if (mode & EFI)
659 	type = 0;
660 #endif
661 
662     mbr += MBRSIZE;                                 /* offset 432 */
663 
664     tmp = lendian_int(de_lba * 4);
665     memcpy(mbr, &tmp, sizeof(tmp));
666     mbr += sizeof(tmp);                             /* offset 436 */
667 
668     tmp = 0;
669     memcpy(mbr, &tmp, sizeof(tmp));
670     mbr += sizeof(tmp);                             /* offset 440 */
671 
672     tmp = lendian_int(id);
673     memcpy(mbr, &tmp, sizeof(tmp));
674     mbr += sizeof(tmp);                             /* offset 444 */
675 
676     mbr[0] = '\0';
677     mbr[1] = '\0';
678     mbr += 2;                                       /* offset 446 */
679 
680     ptype = type;
681     psize = c * head * sector - offset;
682 
683     bhead = (offset / sector) % head;
684     bsect = (offset % sector) + 1;
685     bcyle = offset / (head * sector);
686 
687     bsect += (bcyle & 0x300) >> 2;
688     bcyle  &= 0xFF;
689 
690     ehead = head - 1;
691     esect = sector + (((cc - 1) & 0x300) >> 2);
692     ecyle = (cc - 1) & 0xFF;
693 
694     for (i = 1; i <= 4; i++)
695     {
696         memset(mbr, 0, 16);
697         if (i == entry)
698         {
699             mbr[0] = 0x80;
700             mbr[1] = bhead;
701             mbr[2] = bsect;
702             mbr[3] = bcyle;
703             mbr[4] = ptype;
704             mbr[5] = ehead;
705             mbr[6] = esect;
706             mbr[7] = ecyle;
707 
708             tmp = lendian_int(offset);
709             memcpy(&mbr[8], &tmp, sizeof(tmp));
710 
711             tmp = lendian_int(psize);
712             memcpy(&mbr[12], &tmp, sizeof(tmp));
713         }
714 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
715         if (i == 2 && (mode & EFI))
716         {
717             mbr[0] = 0x0;
718             mbr[1] = 0xfe;
719             mbr[2] = 0xff;
720             mbr[3] = 0xff;
721             mbr[4] = 0xef;
722             mbr[5] = 0xfe;
723             mbr[6] = 0xff;
724             mbr[7] = 0xff;
725 
726             tmp = lendian_int(efi_lba * 4);
727             memcpy(&mbr[8], &tmp, sizeof(tmp));
728 
729             tmp = lendian_int(efi_count);
730             memcpy(&mbr[12], &tmp, sizeof(tmp));
731         }
732         if (i == 3 && (mode & MAC))
733         {
734             mbr[0] = 0x0;
735             mbr[1] = 0xfe;
736             mbr[2] = 0xff;
737             mbr[3] = 0xff;
738             mbr[4] = 0x0;
739             mbr[5] = 0xfe;
740             mbr[6] = 0xff;
741             mbr[7] = 0xff;
742 
743             tmp = lendian_int(mac_lba * 4);
744             memcpy(&mbr[8], &tmp, sizeof(tmp));
745 
746             tmp = lendian_int(mac_count);
747             memcpy(&mbr[12], &tmp, sizeof(tmp));
748         }
749 #endif
750         mbr += 16;
751     }
752     mbr[0] = 0x55;
753     mbr[1] = 0xAA;
754     mbr += 2;
755 
756     return mbr - rbm;
757 }
758 
759 void
760 display_mbr(const uint8_t *mbr, size_t len)
761 {
762     unsigned char c = 0;
763     unsigned int i = 0, j = 0;
764 
765     printf("sizeof(MBR): %zu bytes\n", len);
766     for (i = 0; i < len; i++)
767     {
768         if (!(i % 16))
769             printf("%04d ", i);
770 
771         if (!(i % 8))
772             printf(" ");
773 
774         c = mbr[i];
775         printf("%02x ", c);
776 
777         if (!((i + 1) % 16))
778         {
779             printf(" |");
780             for (; j <= i; j++)
781                 printf("%c", isprint(mbr[j]) ? mbr[j] : '.');
782             printf("|\n");
783         }
784     }
785 }
786 
787 
788 uint32_t chksum_crc32 (unsigned char *block, unsigned int length)
789 {
790 	register unsigned long crc;
791 	unsigned long i;
792 
793 	crc = 0xFFFFFFFF;
794 	for (i = 0; i < length; i++)
795 	{
796 		crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
797 	}
798 	return (crc ^ 0xFFFFFFFF);
799 }
800 
801 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
802 void
803 reverse_uuid(uuid_t uuid)
804 {
805 	uint8_t t, *p = (uint8_t *)uuid;
806 
807 	t = p[0]; p[0] = p[3]; p[3] = t;
808 	t = p[1]; p[1] = p[2]; p[2] = t;
809 	t = p[4]; p[4] = p[5]; p[5] = t;
810 	t = p[6]; p[6] = p[7]; p[7] = t;
811 }
812 #endif
813 
814 static uint16_t *
815 ascii_to_utf16le(uint16_t *dst, const char *src)
816 {
817     uint8_t *p = (uint8_t *)dst;
818     char c;
819 
820     do {
821 	c = *src++;
822 	*p++ = c;
823 	*p++ = 0;
824     } while (c);
825 
826     return (uint16_t *)p;
827 }
828 
829 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
830 void
831 initialise_gpt(uint8_t *gpt, uint32_t current, uint32_t alternate, int primary)
832 {
833     struct gpt_header *header = (struct gpt_header *)gpt;
834     struct gpt_part_header *part;
835     int hole = 0;
836     int gptsize = 128 / 4 + 2;
837 
838     if (mac_lba) {
839 	/* 2048 bytes per partition, plus round to 2048 boundary */
840 	hole = (apm_parts * 4) + 2;
841     }
842 
843     if (primary) {
844 	uuid_generate(disk_uuid);
845 	reverse_uuid(disk_uuid);
846     }
847 
848     header->signature = lendian_64(0x5452415020494645ull);
849     header->revision = lendian_int(0x010000);
850     header->headerSize = lendian_int(0x5c);
851     header->currentLBA = lendian_64(current);
852     header->backupLBA = lendian_64(alternate);
853     header->firstUsableLBA = lendian_64(gptsize + hole);
854     header->lastUsableLBA = lendian_64((isostat.st_size + padding)/512 -
855 				       gptsize);
856     if (primary)
857 	header->partitionEntriesLBA = lendian_64(0x02 + hole);
858     else
859 	header->partitionEntriesLBA = lendian_64(current - (128 / 4));
860     header->numParts = lendian_int(0x80);
861     header->sizeOfPartitionEntries = lendian_int(0x80);
862     memcpy(header->diskGUID, disk_uuid, sizeof(uuid_t));
863 
864     if (primary)
865 	gpt += sizeof(struct gpt_header) + hole * 512;
866     else
867 	gpt -= header->sizeOfPartitionEntries * header->numParts;
868 
869     part = (struct gpt_part_header *)gpt;
870     if (primary) {
871 	uuid_generate(part_uuid);
872 	uuid_generate(iso_uuid);
873 	reverse_uuid(part_uuid);
874 	reverse_uuid(iso_uuid);
875     }
876 
877     memcpy(part->partGUID, iso_uuid, sizeof(uuid_t));
878     memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t));
879     part->firstLBA = lendian_64(0);
880     part->lastLBA = lendian_64(psize - 1);
881     ascii_to_utf16le(part->name, "ISOHybrid ISO");
882 
883     gpt += sizeof(struct gpt_part_header);
884     part++;
885 
886     memcpy(part->partGUID, part_uuid, sizeof(uuid_t));
887     memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t));
888     part->firstLBA = lendian_64(efi_lba * 4);
889     part->lastLBA = lendian_64(part->firstLBA + efi_count - 1);
890     ascii_to_utf16le(part->name, "ISOHybrid");
891 
892     gpt += sizeof(struct gpt_part_header);
893 
894     if (mac_lba) {
895 	gpt += sizeof(struct gpt_part_header);
896 
897 	part++;
898 
899 	memcpy(part->partGUID, part_uuid, sizeof(uuid_t));
900 	memcpy(part->partTypeGUID, hfs_partition, sizeof(uuid_t));
901 	part->firstLBA = lendian_64(mac_lba * 4);
902 	part->lastLBA = lendian_64(part->firstLBA + mac_count - 1);
903 	ascii_to_utf16le(part->name, "ISOHybrid");
904 
905 	part--;
906     }
907 
908     part--;
909 
910     header->partitionEntriesCRC = lendian_int (chksum_crc32((uint8_t *)part,
911 			   header->numParts * header->sizeOfPartitionEntries));
912 
913     header->headerCRC = lendian_int(chksum_crc32((uint8_t *)header,
914 						 header->headerSize));
915 }
916 
917 void
918 initialise_apm(uint8_t *gpt, uint32_t start)
919 {
920     struct apple_part_header *part = (struct apple_part_header *)gpt;
921 
922     part->signature = bendian_short(0x504d);
923     part->map_count = bendian_int(apm_parts);
924     part->start_block = bendian_int(1);
925     part->block_count = bendian_int(4);
926     strcpy(part->name, "Apple");
927     strcpy(part->type, "Apple_partition_map");
928     part->data_start = bendian_int(0);
929     part->data_count = bendian_int(10);
930     part->status = bendian_int(0x03);
931 
932     part = (struct apple_part_header *)(gpt + 2048);
933 
934     part->signature = bendian_short(0x504d);
935     part->map_count = bendian_int(3);
936     part->start_block = bendian_int(efi_lba);
937     part->block_count = bendian_int(efi_count / 4);
938     strcpy(part->name, "EFI");
939     strcpy(part->type, "Apple_HFS");
940     part->data_start = bendian_int(0);
941     part->data_count = bendian_int(efi_count / 4);
942     part->status = bendian_int(0x33);
943 
944     part = (struct apple_part_header *)(gpt + 4096);
945 
946     if (mac_lba)
947     {
948 	part->signature = bendian_short(0x504d);
949 	part->map_count = bendian_int(3);
950 	part->start_block = bendian_int(mac_lba);
951 	part->block_count = bendian_int(mac_count / 4);
952 	strcpy(part->name, "EFI");
953 	strcpy(part->type, "Apple_HFS");
954 	part->data_start = bendian_int(0);
955 	part->data_count = bendian_int(mac_count / 4);
956 	part->status = bendian_int(0x33);
957     } else {
958 	part->signature = bendian_short(0x504d);
959 	part->map_count = bendian_int(3);
960 	part->start_block = bendian_int((start/2048) + 10);
961 	part->block_count = bendian_int(efi_lba - start/2048 - 10);
962 	strcpy(part->name, "ISO");
963 	strcpy(part->type, "Apple_Free");
964 	part->data_start = bendian_int(0);
965 	part->data_count = bendian_int(efi_lba - start/2048 - 10);
966 	part->status = bendian_int(0x01);
967     }
968 }
969 #endif
970 
971 int
972 main(int argc, char *argv[])
973 {
974     int i = 0;
975     FILE *fp = NULL;
976     uint8_t *buf = NULL, *bufz = NULL;
977     int cylsize = 0, frac = 0;
978     size_t mbr_size;
979 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
980     size_t orig_gpt_size, free_space, gpt_size;
981 #endif
982     struct iso_primary_descriptor descriptor;
983 
984     prog = strcpy(alloca(strlen(argv[0]) + 1), argv[0]);
985     i = check_option(argc, argv);
986     argc -= i;
987     argv += i;
988 
989     if (!argc)
990     {
991         usage();
992         return 1;
993     }
994 
995 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
996     if ((mode & EFI) && offset)
997 	errx(1, "%s: --offset is invalid with UEFI images\n", argv[0]);
998 #endif
999 
1000     srand((unsigned int)time(NULL) << (getppid() << getpid()));
1001 
1002     if (!(fp = fopen(argv[0], "rb+")))
1003         err(1, "could not open file `%s'", argv[0]);
1004 
1005     if (fseeko(fp, (off_t) (16 << 11), SEEK_SET))
1006         err(1, "%s: seek error - 0", argv[0]);
1007 
1008     if (fread(&descriptor, sizeof(char), sizeof(descriptor), fp) != sizeof(descriptor))
1009         err(1, "%s: read error - 0", argv[0]);
1010 
1011     if (fseeko(fp, (off_t) 17 * 2048, SEEK_SET))
1012         err(1, "%s: seek error - 1", argv[0]);
1013 
1014     bufz = buf = calloc(BUFSIZE, sizeof(char));
1015     if (fread(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE)
1016         err(1, "%s", argv[0]);
1017 
1018     if (check_banner(buf))
1019         errx(1, "%s: could not find boot record", argv[0]);
1020 
1021     if (mode & VERBOSE)
1022         printf("catalogue offset: %d\n", catoffset);
1023 
1024     if (fseeko(fp, ((off_t) catoffset) * 2048, SEEK_SET))
1025         err(1, "%s: seek error - 2", argv[0]);
1026 
1027     buf = bufz;
1028     memset(buf, 0, BUFSIZE);
1029     if (fread(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE)
1030         err(1, "%s", argv[0]);
1031 
1032     if (check_catalogue(buf))
1033         errx(1, "%s: invalid boot catalogue", argv[0]);
1034 
1035     buf += sizeof(ve);
1036     if (read_catalogue(buf))
1037         errx(1, "%s: unexpected boot catalogue parameters", argv[0]);
1038 
1039     if (mode & VERBOSE)
1040         display_catalogue();
1041 
1042     buf += 32;
1043 
1044 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
1045     if (mode & EFI)
1046     {
1047 	if (!read_efi_section(buf)) {
1048 	    buf += 32;
1049 	    if (!read_efi_catalogue(buf, &efi_count, &efi_lba) && efi_lba) {
1050 		offset = 0;
1051 	    } else {
1052 		errx(1, "%s: invalid efi catalogue", argv[0]);
1053 	    }
1054 	} else {
1055 	    errx(1, "%s: unable to find efi image", argv[0]);
1056 	}
1057     }
1058 #endif
1059 
1060     buf += 32;
1061 
1062 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
1063     if (mode & MAC)
1064     {
1065 	if (!read_efi_section(buf)) {
1066 	    buf += 32;
1067 	    if (!read_efi_catalogue(buf, &mac_count, &mac_lba) && mac_lba) {
1068 		offset = 0;
1069 	    } else {
1070 		errx(1, "%s: invalid efi catalogue", argv[0]);
1071 	    }
1072 	} else {
1073 	    errx(1, "%s: unable to find mac efi image", argv[0]);
1074 	}
1075     }
1076 #endif
1077 
1078     if (fseeko(fp, (((off_t) de_lba) * 2048 + 0x40), SEEK_SET))
1079         err(1, "%s: seek error - 3", argv[0]);
1080 
1081     buf = bufz;
1082     memset(buf, 0, BUFSIZE);
1083     if (fread(buf, sizeof(char), 4, fp) != 4)
1084         err(1, "%s", argv[0]);
1085 
1086     if (memcmp(buf, "\xFB\xC0\x78\x70", 4))
1087         errx(1, "%s: boot loader does not have an isolinux.bin hybrid " \
1088                  "signature. Note that isolinux-debug.bin does not support " \
1089                  "hybrid booting", argv[0]);
1090 
1091     if (stat(argv[0], &isostat))
1092         err(1, "%s", argv[0]);
1093 
1094     isosize = lendian_int(descriptor.size) * lendian_short(descriptor.block_size);
1095 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
1096     free_space = isostat.st_size - isosize;
1097 #endif
1098 
1099     cylsize = head * sector * 512;
1100     frac = isostat.st_size % cylsize;
1101     padding = (frac > 0) ? cylsize - frac : 0;
1102 
1103     if (mode & VERBOSE)
1104         printf("imgsize: %zu, padding: %d\n", (size_t)isostat.st_size, padding);
1105 
1106     cc = c = ( isostat.st_size + padding) / cylsize;
1107     if (c > 1024)
1108     {
1109         warnx("Warning: more than 1024 cylinders: %d", c);
1110         warnx("Not all BIOSes will be able to boot this device");
1111         cc = 1024;
1112     }
1113 
1114     if (!id)
1115     {
1116         if (fseeko(fp, (off_t) 440, SEEK_SET))
1117             err(1, "%s: seek error - 4", argv[0]);
1118 
1119 	if (fread(&id, 1, 4, fp) != 4)
1120 	    err(1, "%s: read error", argv[0]);
1121 
1122         id = lendian_int(id);
1123         if (!id)
1124         {
1125             if (mode & VERBOSE)
1126                 printf("random ");
1127             id = rand();
1128         }
1129     }
1130     if (mode & VERBOSE)
1131         printf("id: %u\n", id);
1132 
1133     buf = bufz;
1134     memset(buf, 0, BUFSIZE);
1135     mbr_size = initialise_mbr(buf);
1136 
1137     if (mode & VERBOSE)
1138         display_mbr(buf, mbr_size);
1139 
1140     if (fseeko(fp, (off_t) 0, SEEK_SET))
1141         err(1, "%s: seek error - 5", argv[0]);
1142 
1143     if (fwrite(buf, sizeof(char), mbr_size, fp) != mbr_size)
1144         err(1, "%s: write error - 1", argv[0]);
1145 
1146 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
1147     if (efi_lba) {
1148 	reverse_uuid(basic_partition);
1149 	reverse_uuid(hfs_partition);
1150 
1151 	/* 512 byte header, 128 entries of 128 bytes */
1152 	orig_gpt_size = gpt_size = 512 + (128 * 128);
1153 
1154 	/* Leave space for the APM if necessary */
1155 	if (mac_lba)
1156 	    gpt_size += (4 * 2048);
1157 
1158 	buf = calloc(gpt_size, sizeof(char));
1159 	memset(buf, 0, gpt_size);
1160 
1161 	/*
1162 	 * We need to ensure that we have enough space for the secondary GPT.
1163 	 * Unlike the primary, this doesn't need a hole for the APM. We still
1164 	 * want to be 1MB aligned so just bump the padding by a megabyte.
1165 	 */
1166 	if (free_space < orig_gpt_size && padding < orig_gpt_size) {
1167 	    padding += 1024 * 1024;
1168 	}
1169 
1170 	/*
1171 	 * Determine the size of the ISO filesystem. This will define the size
1172 	 * of the partition that covers it.
1173 	 */
1174 	psize = isosize / 512;
1175 
1176 	/*
1177 	 * Primary GPT starts at sector 1, secondary GPT starts at 1 sector
1178 	 * before the end of the image
1179 	 */
1180 	initialise_gpt(buf, 1, (isostat.st_size + padding - 512) / 512, 1);
1181 
1182 	if (fseeko(fp, (off_t) 512, SEEK_SET))
1183 	    err(1, "%s: seek error - 6", argv[0]);
1184 
1185 	if (fwrite(buf, sizeof(char), gpt_size, fp) != gpt_size)
1186 	    err(1, "%s: write error - 2", argv[0]);
1187     }
1188 
1189     if (mac_lba)
1190     {
1191 	/* Apple partition entries filling 2048 bytes each */
1192 	int apm_size = apm_parts * 2048;
1193 
1194 	buf = realloc(buf, apm_size);
1195 	memset(buf, 0, apm_size);
1196 
1197 	initialise_apm(buf, APM_OFFSET);
1198 
1199 	fseeko(fp, (off_t) APM_OFFSET, SEEK_SET);
1200 	fwrite(buf, sizeof(char), apm_size, fp);
1201     }
1202 #endif
1203 
1204     if (padding)
1205     {
1206         if (fsync(fileno(fp)))
1207             err(1, "%s: could not synchronise", argv[0]);
1208 
1209         if (ftruncate(fileno(fp), isostat.st_size + padding))
1210             err(1, "%s: could not add padding bytes", argv[0]);
1211     }
1212 
1213 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
1214     if (efi_lba) {
1215 	buf = realloc(buf, orig_gpt_size);
1216 	memset(buf, 0, orig_gpt_size);
1217 
1218 	buf += orig_gpt_size - sizeof(struct gpt_header);
1219 
1220 	initialise_gpt(buf, (isostat.st_size + padding - 512) / 512, 1, 0);
1221 
1222 	/* Shift back far enough to write the 128 GPT entries */
1223 	buf -= 128 * sizeof(struct gpt_part_header);
1224 
1225 	/*
1226 	 * Seek far enough back that the gpt header is 512 bytes before the
1227 	 * end of the image
1228 	 */
1229 
1230 	if (fseeko(fp, (isostat.st_size + padding) - orig_gpt_size, SEEK_SET))
1231 	    err(1, "%s: seek error - 8", argv[0]);
1232 
1233 	if (fwrite(buf, sizeof(char), orig_gpt_size, fp) != orig_gpt_size)
1234 	    err(1, "%s: write error - 4", argv[0]);
1235     }
1236 #endif
1237 
1238     free(buf);
1239     fclose(fp);
1240 
1241     return 0;
1242 }
1243