dd78c79a4fad3a81f2613f209ade37af00afc613
[reactos.git] / reactos / sdk / tools / isohybrid / isohybrid.c
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 uint16_t head = 64; /* 1 <= head <= 256 */
61 uint8_t sector = 32; /* 1 <= sector <= 63 */
62
63 uint8_t entry = 0; /* partition number: 1 <= entry <= 4 */
64 uint8_t offset = 0; /* partition offset: 0 <= offset <= 64 */
65 uint16_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 int 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 int
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 orig_gpt_size, free_space, gpt_size;
979 struct iso_primary_descriptor descriptor;
980
981 prog = strcpy(alloca(strlen(argv[0]) + 1), argv[0]);
982 i = check_option(argc, argv);
983 argc -= i;
984 argv += i;
985
986 if (!argc)
987 {
988 usage();
989 return 1;
990 }
991
992 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
993 if ((mode & EFI) && offset)
994 errx(1, "%s: --offset is invalid with UEFI images\n", argv[0]);
995 #endif
996
997 srand(time(NULL) << (getppid() << getpid()));
998
999 if (!(fp = fopen(argv[0], "rb+")))
1000 err(1, "could not open file `%s'", argv[0]);
1001
1002 if (fseeko(fp, (off_t) (16 << 11), SEEK_SET))
1003 err(1, "%s: seek error - 0", argv[0]);
1004
1005 if (fread(&descriptor, sizeof(char), sizeof(descriptor), fp) != sizeof(descriptor))
1006 err(1, "%s: read error - 0", argv[0]);
1007
1008 if (fseeko(fp, (off_t) 17 * 2048, SEEK_SET))
1009 err(1, "%s: seek error - 1", argv[0]);
1010
1011 bufz = buf = calloc(BUFSIZE, sizeof(char));
1012 if (fread(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE)
1013 err(1, "%s", argv[0]);
1014
1015 if (check_banner(buf))
1016 errx(1, "%s: could not find boot record", argv[0]);
1017
1018 if (mode & VERBOSE)
1019 printf("catalogue offset: %d\n", catoffset);
1020
1021 if (fseeko(fp, ((off_t) catoffset) * 2048, SEEK_SET))
1022 err(1, "%s: seek error - 2", argv[0]);
1023
1024 buf = bufz;
1025 memset(buf, 0, BUFSIZE);
1026 if (fread(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE)
1027 err(1, "%s", argv[0]);
1028
1029 if (check_catalogue(buf))
1030 errx(1, "%s: invalid boot catalogue", argv[0]);
1031
1032 buf += sizeof(ve);
1033 if (read_catalogue(buf))
1034 errx(1, "%s: unexpected boot catalogue parameters", argv[0]);
1035
1036 if (mode & VERBOSE)
1037 display_catalogue();
1038
1039 buf += 32;
1040
1041 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
1042 if (mode & EFI)
1043 {
1044 if (!read_efi_section(buf)) {
1045 buf += 32;
1046 if (!read_efi_catalogue(buf, &efi_count, &efi_lba) && efi_lba) {
1047 offset = 0;
1048 } else {
1049 errx(1, "%s: invalid efi catalogue", argv[0]);
1050 }
1051 } else {
1052 errx(1, "%s: unable to find efi image", argv[0]);
1053 }
1054 }
1055 #endif
1056
1057 buf += 32;
1058
1059 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
1060 if (mode & MAC)
1061 {
1062 if (!read_efi_section(buf)) {
1063 buf += 32;
1064 if (!read_efi_catalogue(buf, &mac_count, &mac_lba) && mac_lba) {
1065 offset = 0;
1066 } else {
1067 errx(1, "%s: invalid efi catalogue", argv[0]);
1068 }
1069 } else {
1070 errx(1, "%s: unable to find mac efi image", argv[0]);
1071 }
1072 }
1073 #endif
1074
1075 if (fseeko(fp, (((off_t) de_lba) * 2048 + 0x40), SEEK_SET))
1076 err(1, "%s: seek error - 3", argv[0]);
1077
1078 buf = bufz;
1079 memset(buf, 0, BUFSIZE);
1080 if (fread(buf, sizeof(char), 4, fp) != 4)
1081 err(1, "%s", argv[0]);
1082
1083 if (memcmp(buf, "\xFB\xC0\x78\x70", 4))
1084 errx(1, "%s: boot loader does not have an isolinux.bin hybrid " \
1085 "signature. Note that isolinux-debug.bin does not support " \
1086 "hybrid booting", argv[0]);
1087
1088 if (stat(argv[0], &isostat))
1089 err(1, "%s", argv[0]);
1090
1091 isosize = lendian_int(descriptor.size) * lendian_short(descriptor.block_size);
1092 free_space = isostat.st_size - isosize;
1093
1094 cylsize = head * sector * 512;
1095 frac = isostat.st_size % cylsize;
1096 padding = (frac > 0) ? cylsize - frac : 0;
1097
1098 if (mode & VERBOSE)
1099 printf("imgsize: %zu, padding: %d\n", (size_t)isostat.st_size, padding);
1100
1101 cc = c = ( isostat.st_size + padding) / cylsize;
1102 if (c > 1024)
1103 {
1104 warnx("Warning: more than 1024 cylinders: %d", c);
1105 warnx("Not all BIOSes will be able to boot this device");
1106 cc = 1024;
1107 }
1108
1109 if (!id)
1110 {
1111 if (fseeko(fp, (off_t) 440, SEEK_SET))
1112 err(1, "%s: seek error - 4", argv[0]);
1113
1114 if (fread(&id, 1, 4, fp) != 4)
1115 err(1, "%s: read error", argv[0]);
1116
1117 id = lendian_int(id);
1118 if (!id)
1119 {
1120 if (mode & VERBOSE)
1121 printf("random ");
1122 id = rand();
1123 }
1124 }
1125 if (mode & VERBOSE)
1126 printf("id: %u\n", id);
1127
1128 buf = bufz;
1129 memset(buf, 0, BUFSIZE);
1130 i = initialise_mbr(buf);
1131
1132 if (mode & VERBOSE)
1133 display_mbr(buf, i);
1134
1135 if (fseeko(fp, (off_t) 0, SEEK_SET))
1136 err(1, "%s: seek error - 5", argv[0]);
1137
1138 if (fwrite(buf, sizeof(char), i, fp) != (size_t)i)
1139 err(1, "%s: write error - 1", argv[0]);
1140
1141 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
1142 if (efi_lba) {
1143 reverse_uuid(basic_partition);
1144 reverse_uuid(hfs_partition);
1145
1146 /* 512 byte header, 128 entries of 128 bytes */
1147 orig_gpt_size = gpt_size = 512 + (128 * 128);
1148
1149 /* Leave space for the APM if necessary */
1150 if (mac_lba)
1151 gpt_size += (4 * 2048);
1152
1153 buf = calloc(gpt_size, sizeof(char));
1154 memset(buf, 0, gpt_size);
1155
1156 /*
1157 * We need to ensure that we have enough space for the secondary GPT.
1158 * Unlike the primary, this doesn't need a hole for the APM. We still
1159 * want to be 1MB aligned so just bump the padding by a megabyte.
1160 */
1161 if (free_space < orig_gpt_size && padding < orig_gpt_size) {
1162 padding += 1024 * 1024;
1163 }
1164
1165 /*
1166 * Determine the size of the ISO filesystem. This will define the size
1167 * of the partition that covers it.
1168 */
1169 psize = isosize / 512;
1170
1171 /*
1172 * Primary GPT starts at sector 1, secondary GPT starts at 1 sector
1173 * before the end of the image
1174 */
1175 initialise_gpt(buf, 1, (isostat.st_size + padding - 512) / 512, 1);
1176
1177 if (fseeko(fp, (off_t) 512, SEEK_SET))
1178 err(1, "%s: seek error - 6", argv[0]);
1179
1180 if (fwrite(buf, sizeof(char), gpt_size, fp) != (size_t)gpt_size)
1181 err(1, "%s: write error - 2", argv[0]);
1182 }
1183
1184 if (mac_lba)
1185 {
1186 /* Apple partition entries filling 2048 bytes each */
1187 int apm_size = apm_parts * 2048;
1188
1189 buf = realloc(buf, apm_size);
1190 memset(buf, 0, apm_size);
1191
1192 initialise_apm(buf, APM_OFFSET);
1193
1194 fseeko(fp, (off_t) APM_OFFSET, SEEK_SET);
1195 fwrite(buf, sizeof(char), apm_size, fp);
1196 }
1197 #endif
1198
1199 if (padding)
1200 {
1201 if (fsync(fileno(fp)))
1202 err(1, "%s: could not synchronise", argv[0]);
1203
1204 if (ftruncate(fileno(fp), isostat.st_size + padding))
1205 err(1, "%s: could not add padding bytes", argv[0]);
1206 }
1207
1208 #ifdef REACTOS_ISOHYBRID_EFI_MAC_SUPPORT
1209 if (efi_lba) {
1210 buf = realloc(buf, orig_gpt_size);
1211 memset(buf, 0, orig_gpt_size);
1212
1213 buf += orig_gpt_size - sizeof(struct gpt_header);
1214
1215 initialise_gpt(buf, (isostat.st_size + padding - 512) / 512, 1, 0);
1216
1217 /* Shift back far enough to write the 128 GPT entries */
1218 buf -= 128 * sizeof(struct gpt_part_header);
1219
1220 /*
1221 * Seek far enough back that the gpt header is 512 bytes before the
1222 * end of the image
1223 */
1224
1225 if (fseeko(fp, (isostat.st_size + padding) - orig_gpt_size, SEEK_SET))
1226 err(1, "%s: seek error - 8", argv[0]);
1227
1228 if (fwrite(buf, sizeof(char), orig_gpt_size, fp) != orig_gpt_size)
1229 err(1, "%s: write error - 4", argv[0]);
1230 }
1231 #endif
1232
1233 free(buf);
1234 fclose(fp);
1235
1236 return 0;
1237 }