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
44char *prog = NULL;
45extern int opterr, optind;
46struct stat isostat;
47unsigned int padding = 0;
48
49uuid_t disk_uuid, part_uuid, iso_uuid;
50
51uint8_t mode = 0;
52enum { VERBOSE = 1 , EFI = 2 , MAC = 4};
53
54/* user options */
55uint16_t head = 64;             /* 1 <= head <= 256 */
56uint8_t sector = 32;            /* 1 <= sector <= 63  */
57
58uint8_t entry = 0;              /* partition number: 1 <= entry <= 4 */
59uint8_t offset = 0;             /* partition offset: 0 <= offset <= 64 */
60uint16_t type = 0x17;           /* partition type: 0 <= type <= 255 */
61uint32_t id = 0;                /* MBR: 0 <= id <= 0xFFFFFFFF(4294967296) */
62
63uint8_t hd0 = 0;                /* 0 <= hd0 <= 2 */
64uint8_t partok = 0;             /* 0 <= partok <= 1 */
65
66char mbr_template_path[1024] = {0};   /* Path to MBR template */
67
68uint16_t ve[16];
69uint32_t catoffset = 0;
70uint32_t c = 0, cc = 0, cs = 0;
71
72uint32_t psize = 0, isosize = 0;
73
74/* boot catalogue parameters */
75uint32_t de_lba = 0;
76uint16_t de_seg = 0, de_count = 0, de_mbz2 = 0;
77uint8_t de_boot = 0, de_media = 0, de_sys = 0, de_mbz1 = 0;
78uint32_t efi_lba = 0, mac_lba = 0;
79uint16_t efi_count = 0, mac_count = 0;
80uint8_t efi_boot = 0, efi_media = 0, efi_sys = 0;
81
82int apm_parts = 3;
83
84uint8_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
86uuid_t efi_system_partition = {0xC1, 0x2A, 0x73, 0x28, 0xF8, 0x1F, 0x11, 0xD2, 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B};
87uuid_t basic_partition = {0xEB,0xD0,0xA0,0xA2,0xB9,0xE5,0x44,0x33,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7};
88uuid_t hfs_partition = {0x48, 0x46, 0x53, 0x00, 0x00, 0x00, 0x11, 0xAA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC};
89
90uint32_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
158struct iso_primary_descriptor {
159    uint8_t ignore [80];
160    uint32_t size;
161    uint8_t ignore2 [44];
162    uint16_t block_size;
163};
164
165struct 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
183struct 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
194struct 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
218void
219usage(void)
220{
221    printf("Usage: %s [OPTIONS] <boot.iso>\n", prog);
222}
223
224
225void
226printh(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
259int
260check_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
384uint16_t
385bendian_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
398uint32_t
399bendian_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
412uint16_t
413lendian_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
426uint32_t
427lendian_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
440uint64_t
441lendian_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
457int
458check_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
476int
477check_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
501int
502read_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
534int
535read_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
554int
555read_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
571void
572display_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
585void
586read_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
602int
603initialise_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
736void
737display_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
765uint32_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
778void
779reverse_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
789static uint16_t *
790ascii_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
804void
805initialise_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
891void
892initialise_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
944int
945main(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