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