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