• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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