Merge remote-tracking branch 'genec/diag-geodsp-perl-for-hpa'
[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 = 0;              /* 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             if (mode & MAC || mode & EFI)
304                 errx(1, "setting an entry is unsupported with EFI or Mac");
305             break;
306
307         case 'o':
308             offset = strtoul(optarg, &err, 0);
309             if (*err || offset > 64)
310                 errx(1, "invalid offset: `%s', 0 <= offset <= 64", optarg);
311             break;
312
313         case 't':
314             type = strtoul(optarg, &err, 0);
315             if (*err || type > 255)
316                 errx(1, "invalid type: `%s', 0 <= type <= 255", optarg);
317             break;
318
319         case 'i':
320             id = strtoul(optarg, &err, 0);
321             if (*err)
322                 errx(1, "invalid id: `%s'", optarg);
323             break;
324
325         case 'f':
326             hd0 = 1;
327             break;
328
329         case 'c':
330             hd0 = 2;
331             break;
332
333         case 'p':
334             partok = 1;
335             break;
336
337         case 'u':
338             mode |= EFI;
339             if (entry)
340                 errx(1, "setting an entry is unsupported with EFI or Mac");
341             break;
342
343         case 'm':
344             mode |= MAC;
345             if (entry)
346                 errx(1, "setting an entry is unsupported with EFI or Mac");
347             break;
348
349         case 'v':
350             mode |= VERBOSE;
351             break;
352
353         case 'V':
354             printf("%s version %s\n", prog, VERSION);
355             exit(0);
356
357         case ':':
358             errx(1, "option `-%c' takes an argument", optopt);
359
360         default:
361         case '?':
362             if (optopt)
363                 errx(1, "invalid option `-%c', see --help", optopt);
364
365             printh();
366             exit(0);
367         }
368     }
369
370     return optind;
371 }
372
373 uint16_t
374 bendian_short(const uint16_t s)
375 {
376     uint16_t r = 1;
377
378     if (!*(uint8_t *)&r)
379         return s;
380
381     r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
382
383     return r;
384 }
385
386
387 uint32_t
388 bendian_int(const uint32_t s)
389 {
390     uint32_t r = 1;
391
392     if (!*(uint8_t *)&r)
393         return s;
394
395     r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
396         | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
397
398     return r;
399 }
400
401 uint16_t
402 lendian_short(const uint16_t s)
403 {
404     uint16_t r = 1;
405
406     if (*(uint8_t *)&r)
407         return s;
408
409     r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
410
411     return r;
412 }
413
414
415 uint32_t
416 lendian_int(const uint32_t s)
417 {
418     uint32_t r = 1;
419
420     if (*(uint8_t *)&r)
421         return s;
422
423     r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
424         | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
425
426     return r;
427 }
428
429 uint64_t
430 lendian_64(const uint64_t s)
431 {
432         uint64_t r = 1;
433
434         if (*(uint8_t *)&r)
435                 return s;
436
437         r = (s & 0x00000000000000FF) << 56 | (s & 0xFF00000000000000) >> 56
438              | (s & 0x000000000000FF00) << 40 | (s & 0x00FF000000000000) >> 40
439              | (s & 0x0000000000FF0000) << 24 | (s & 0x0000FF0000000000) >> 24
440              | (s & 0x00000000FF000000) << 8 | (s & 0x000000FF00000000) >> 8;
441
442         return r;
443 }
444
445
446 int
447 check_banner(const uint8_t *buf)
448 {
449     static const char banner[] = "\0CD001\1EL TORITO SPECIFICATION\0\0\0\0" \
450         "\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" \
451         "\0\0\0\0\0";
452
453     if (!buf || memcmp(buf, banner, sizeof(banner) - 1))
454         return 1;
455
456     buf += sizeof(banner) - 1;
457     memcpy(&catoffset, buf, sizeof(catoffset));
458
459     catoffset = lendian_int(catoffset);
460
461     return 0;
462 }
463
464
465 int
466 check_catalogue(const uint8_t *buf)
467 {
468     int i = 0;
469
470     for (i = 0, cs = 0; i < 16; i++)
471     {
472         ve[i] = 0;
473         memcpy(&ve[i], buf, sizeof(ve[i]));
474
475         ve[i] = lendian_short(ve[i]);
476
477         buf += 2;
478         cs += ve[i];
479
480         if (mode & VERBOSE)
481             printf("ve[%d]: %d, cs: %d\n", i, ve[i], cs);
482     }
483     if ((ve[0] != 0x0001) || (ve[15] != 0xAA55) || (cs & 0xFFFF))
484         return 1;
485
486     return 0;
487 }
488
489
490 int
491 read_catalogue(const uint8_t *buf)
492 {
493     memcpy(&de_boot, buf++, 1);
494     memcpy(&de_media, buf++, 1);
495
496     memcpy(&de_seg, buf, 2);
497     de_seg = lendian_short(de_seg);
498     buf += 2;
499
500     memcpy(&de_sys, buf++, 1);
501     memcpy(&de_mbz1, buf++, 1);
502
503     memcpy(&de_count, buf, 2);
504     de_count = lendian_short(de_count);
505     buf += 2;
506
507     memcpy(&de_lba, buf, 4);
508     de_lba = lendian_int(de_lba);
509     buf += 4;
510
511     memcpy(&de_mbz2, buf, 2);
512     de_mbz2 = lendian_short(de_mbz2);
513     buf += 2;
514
515     if (de_boot != 0x88 || de_media != 0
516         || (de_seg != 0 && de_seg != 0x7C0) || de_count != 4)
517         return 1;
518
519     return 0;
520 }
521
522
523 int
524 read_efi_section(const uint8_t *buf)
525 {
526         unsigned char header_indicator;
527         unsigned char platform_id;
528         short count;
529
530         memcpy(&header_indicator, buf++, 1);
531         memcpy(&platform_id, buf++, 1);
532
533         memcpy(&count, buf, 2);
534         count = lendian_short(count);
535         buf += 2;
536
537         if (platform_id == 0xef)
538                 return 0;
539
540         return 1;
541 }
542
543 int
544 read_efi_catalogue(const uint8_t *buf, uint16_t *count, uint32_t *lba)
545 {
546     buf += 6;
547
548     memcpy(count, buf, 2);
549     *count = lendian_short(*count);
550     buf += 2;
551
552     memcpy(lba, buf, 4);
553     *lba = lendian_int(*lba);
554     buf += 6;
555
556     return 0;
557 }
558
559
560 void
561 display_catalogue(void)
562 {
563     printf("de_boot: %hhu\n", de_boot);
564     printf("de_media: %hhu\n", de_media);
565     printf("de_seg: %hu\n", de_seg);
566     printf("de_sys: %hhu\n", de_sys);
567     printf("de_mbz1: %hhu\n", de_mbz1);
568     printf("de_count: %hu\n", de_count);
569     printf("de_lba: %u\n", de_lba);
570     printf("de_mbz2: %hu\n", de_mbz2);
571 }
572
573 int
574 initialise_mbr(uint8_t *mbr)
575 {
576     int i = 0;
577     uint32_t tmp = 0;
578     uint8_t ptype = 0, *rbm = mbr;
579     uint8_t bhead = 0, bsect = 0, bcyle = 0;
580     uint8_t ehead = 0, esect = 0, ecyle = 0;
581
582     extern unsigned char isohdpfx[][MBRSIZE];
583
584     memcpy(mbr, &isohdpfx[hd0 + 3 * partok], MBRSIZE);
585
586     if (mode & MAC) {
587         memcpy(mbr, afp_header, sizeof(afp_header));
588     }
589
590     if (!entry)
591         entry = 1;
592
593     if (mode & EFI)
594         type = 0;
595
596     mbr += MBRSIZE;                                 /* offset 432 */
597
598     tmp = lendian_int(de_lba * 4);
599     memcpy(mbr, &tmp, sizeof(tmp));
600     mbr += sizeof(tmp);                             /* offset 436 */
601
602     tmp = 0;
603     memcpy(mbr, &tmp, sizeof(tmp));
604     mbr += sizeof(tmp);                             /* offset 440 */
605
606     tmp = lendian_int(id);
607     memcpy(mbr, &tmp, sizeof(tmp));
608     mbr += sizeof(tmp);                             /* offset 444 */
609
610     mbr[0] = '\0';
611     mbr[1] = '\0';
612     mbr += 2;                                       /* offset 446 */
613
614     ptype = type;
615     psize = c * head * sector - offset;
616
617     bhead = (offset / sector) % head;
618     bsect = (offset % sector) + 1;
619     bcyle = offset / (head * sector);
620
621     bsect += (bcyle & 0x300) >> 2;
622     bcyle  &= 0xFF;
623
624     ehead = head - 1;
625     esect = sector + (((cc - 1) & 0x300) >> 2);
626     ecyle = (cc - 1) & 0xFF;
627
628     for (i = 1; i <= 4; i++)
629     {
630         memset(mbr, 0, 16);
631         if (i == entry)
632         {
633             mbr[0] = 0x80;
634             mbr[1] = bhead;
635             mbr[2] = bsect;
636             mbr[3] = bcyle;
637             mbr[4] = ptype;
638             mbr[5] = ehead;
639             mbr[6] = esect;
640             mbr[7] = ecyle;
641
642             tmp = lendian_int(offset);
643             memcpy(&mbr[8], &tmp, sizeof(tmp));
644
645             tmp = lendian_int(psize);
646             memcpy(&mbr[12], &tmp, sizeof(tmp));
647         }
648         if (i == 2 && (mode & EFI))
649         {
650             mbr[0] = 0x0;
651             mbr[1] = 0xfe;
652             mbr[2] = 0xff;
653             mbr[3] = 0xff;
654             mbr[4] = 0xef;
655             mbr[5] = 0xfe;
656             mbr[6] = 0xff;
657             mbr[7] = 0xff;
658
659             tmp = lendian_int(efi_lba * 4);
660             memcpy(&mbr[8], &tmp, sizeof(tmp));
661
662             tmp = lendian_int(efi_count);
663             memcpy(&mbr[12], &tmp, sizeof(tmp));
664         }
665         if (i == 3 && (mode & MAC))
666         {
667             mbr[0] = 0x0;
668             mbr[1] = 0xfe;
669             mbr[2] = 0xff;
670             mbr[3] = 0xff;
671             mbr[4] = 0x0;
672             mbr[5] = 0xfe;
673             mbr[6] = 0xff;
674             mbr[7] = 0xff;
675
676             tmp = lendian_int(mac_lba * 4);
677             memcpy(&mbr[8], &tmp, sizeof(tmp));
678
679             tmp = lendian_int(mac_count);
680             memcpy(&mbr[12], &tmp, sizeof(tmp));
681         }
682         mbr += 16;
683     }
684     mbr[0] = 0x55;
685     mbr[1] = 0xAA;
686     mbr += 2;
687
688     return mbr - rbm;
689 }
690
691 void
692 display_mbr(const uint8_t *mbr, size_t len)
693 {
694     unsigned char c = 0;
695     unsigned int i = 0, j = 0;
696
697     printf("sizeof(MBR): %zu bytes\n", len);
698     for (i = 0; i < len; i++)
699     {
700         if (!(i % 16))
701             printf("%04d ", i);
702
703         if (!(i % 8))
704             printf(" ");
705
706         c = mbr[i];
707         printf("%02x ", c);
708
709         if (!((i + 1) % 16))
710         {
711             printf(" |");
712             for (; j <= i; j++)
713                 printf("%c", isprint(mbr[j]) ? mbr[j] : '.');
714             printf("|\n");
715         }
716     }
717 }
718
719
720 uint32_t chksum_crc32 (unsigned char *block, unsigned int length)
721 {
722         register unsigned long crc;
723         unsigned long i;
724
725         crc = 0xFFFFFFFF;
726         for (i = 0; i < length; i++)
727         {
728                 crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
729         }
730         return (crc ^ 0xFFFFFFFF);
731 }
732
733 void
734 reverse_uuid(uuid_t uuid)
735 {
736         uint8_t t, *p = (uint8_t *)uuid;
737
738         t = p[0]; p[0] = p[3]; p[3] = t;
739         t = p[1]; p[1] = p[2]; p[2] = t;
740         t = p[4]; p[4] = p[5]; p[5] = t;
741         t = p[6]; p[6] = p[7]; p[7] = t;
742 }
743
744 void
745 initialise_gpt(uint8_t *gpt, uint32_t current, uint32_t alternate, int primary)
746 {
747     struct gpt_header *header = (struct gpt_header *)gpt;
748     struct gpt_part_header *part;
749     int hole = 0;
750     int gptsize = 128 / 4 + 2;
751
752     if (mac_lba) {
753         /* 2048 bytes per partition, plus round to 2048 boundary */
754         hole = (apm_parts * 4) + 2;
755     }
756
757     if (primary) {
758         uuid_generate(disk_uuid);
759         reverse_uuid(disk_uuid);
760     }
761
762     header->signature = lendian_64(0x5452415020494645);
763     header->revision = lendian_int(0x010000);
764     header->headerSize = lendian_int(0x5c);
765     header->currentLBA = lendian_64(current);
766     header->backupLBA = lendian_64(alternate);
767     header->firstUsableLBA = lendian_64(gptsize + hole);
768     header->lastUsableLBA = lendian_64((isostat.st_size + padding)/512 -
769                                        gptsize);
770     if (primary)
771         header->partitionEntriesLBA = lendian_64(0x02 + hole);
772     else
773         header->partitionEntriesLBA = lendian_64(current - (128 / 4));
774     header->numParts = lendian_int(0x80);
775     header->sizeOfPartitionEntries = lendian_int(0x80);
776     memcpy(header->diskGUID, disk_uuid, sizeof(uuid_t));
777
778     if (primary)
779         gpt += sizeof(struct gpt_header) + hole * 512;
780     else
781         gpt -= header->sizeOfPartitionEntries * header->numParts;
782
783     part = (struct gpt_part_header *)gpt;
784     if (primary) {
785         uuid_generate(part_uuid);
786         uuid_generate(iso_uuid);
787         reverse_uuid(part_uuid);
788         reverse_uuid(iso_uuid);
789     }
790
791     memcpy(part->partGUID, iso_uuid, sizeof(uuid_t));
792     memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t));
793     part->firstLBA = lendian_64(0);
794     part->lastLBA = lendian_64(psize);
795     memcpy(part->name, "ISOHybrid ISO", 28);
796
797     gpt += sizeof(struct gpt_part_header);
798     part++;
799
800     memcpy(part->partGUID, part_uuid, sizeof(uuid_t));
801     memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t));
802     part->firstLBA = lendian_64(efi_lba * 4);
803     part->lastLBA = lendian_64(part->firstLBA + efi_count - 1);
804     memcpy(part->name, "ISOHybrid", 20);
805
806     gpt += sizeof(struct gpt_part_header);
807
808     if (mac_lba) {
809         gpt += sizeof(struct gpt_part_header);
810
811         part++;
812
813         memcpy(part->partGUID, part_uuid, sizeof(uuid_t));
814         memcpy(part->partTypeGUID, hfs_partition, sizeof(uuid_t));
815         part->firstLBA = lendian_64(mac_lba * 4);
816         part->lastLBA = lendian_64(part->firstLBA + mac_count - 1);
817         memcpy(part->name, "ISOHybrid", 20);
818
819         part--;
820     }
821
822     part--;
823
824     header->partitionEntriesCRC = lendian_int (chksum_crc32((uint8_t *)part,
825                            header->numParts * header->sizeOfPartitionEntries));
826
827     header->headerCRC = lendian_int(chksum_crc32((uint8_t *)header,
828                                                  header->headerSize));
829 }
830
831 void
832 initialise_apm(uint8_t *gpt, uint32_t start)
833 {
834     struct apple_part_header *part = (struct apple_part_header *)gpt;
835
836     part->signature = bendian_short(0x504d);
837     part->map_count = bendian_int(apm_parts);
838     part->start_block = bendian_int(1);
839     part->block_count = bendian_int(0x10);
840     strcpy(part->name, "Apple");
841     strcpy(part->type, "Apple_partition_map");
842     part->data_start = bendian_int(0);
843     part->data_count = bendian_int(10);
844     part->status = bendian_int(0x03);
845
846     part = (struct apple_part_header *)(gpt + 2048);
847
848     part->signature = bendian_short(0x504d);
849     part->map_count = bendian_int(3);
850     part->start_block = bendian_int(efi_lba);
851     part->block_count = bendian_int(efi_count);
852     strcpy(part->name, "EFI");
853     strcpy(part->type, "Apple_HFS");
854     part->data_start = bendian_int(0);
855     part->data_count = bendian_int(efi_count);
856     part->status = bendian_int(0x33);
857
858     part = (struct apple_part_header *)(gpt + 4096);
859
860     if (mac_lba)
861     {
862         part->signature = bendian_short(0x504d);
863         part->map_count = bendian_int(3);
864         part->start_block = bendian_int(mac_lba);
865         part->block_count = bendian_int(mac_count);
866         strcpy(part->name, "EFI");
867         strcpy(part->type, "Apple_HFS");
868         part->data_start = bendian_int(0);
869         part->data_count = bendian_int(mac_count);
870         part->status = bendian_int(0x33);
871     } else {
872         part->signature = bendian_short(0x504d);
873         part->map_count = bendian_int(3);
874         part->start_block = bendian_int((start/2048) + 10);
875         part->block_count = bendian_int(efi_lba - start/2048 - 10);
876         strcpy(part->name, "ISO");
877         strcpy(part->type, "Apple_Free");
878         part->data_start = bendian_int(0);
879         part->data_count = bendian_int(efi_lba - start/2048 - 10);
880         part->status = bendian_int(0x01);
881     }
882 }
883
884 int
885 main(int argc, char *argv[])
886 {
887     int i = 0;
888     FILE *fp = NULL;
889     uint8_t *buf = NULL, *bufz = NULL;
890     int cylsize = 0, frac = 0;
891     size_t orig_gpt_size, free_space, gpt_size;
892     struct iso_primary_descriptor descriptor;
893
894     prog = strcpy(alloca(strlen(argv[0]) + 1), argv[0]);
895     i = check_option(argc, argv);
896     argc -= i;
897     argv += i;
898
899     if (!argc)
900     {
901         usage();
902         return 1;
903     }
904
905     if ((mode & EFI) && offset)
906         errx(1, "%s: --offset is invalid with UEFI images\n", argv[0]);
907
908     srand(time(NULL) << (getppid() << getpid()));
909
910     if (!(fp = fopen(argv[0], "r+")))
911         err(1, "could not open file `%s'", argv[0]);
912
913     if (fseek(fp, (16 << 11), SEEK_SET))
914         err(1, "%s: seek error - 0", argv[0]);
915
916     if (fread(&descriptor, sizeof(char), sizeof(descriptor), fp) != sizeof(descriptor))
917         err(1, "%s: read error - 0", argv[0]);
918
919     if (fseek(fp, 17 * 2048, SEEK_SET))
920         err(1, "%s: seek error - 1", argv[0]);
921
922     bufz = buf = calloc(BUFSIZE, sizeof(char));
923     if (fread(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE)
924         err(1, "%s", argv[0]);
925
926     if (check_banner(buf))
927         errx(1, "%s: could not find boot record", argv[0]);
928
929     if (mode & VERBOSE)
930         printf("catalogue offset: %d\n", catoffset);
931
932     if (fseek(fp, catoffset * 2048, SEEK_SET))
933         err(1, "%s: seek error - 2", argv[0]);
934
935     buf = bufz;
936     memset(buf, 0, BUFSIZE);
937     if (fread(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE)
938         err(1, "%s", argv[0]);
939
940     if (check_catalogue(buf))
941         errx(1, "%s: invalid boot catalogue", argv[0]);
942
943     buf += sizeof(ve);
944     if (read_catalogue(buf))
945         errx(1, "%s: unexpected boot catalogue parameters", argv[0]);
946
947     if (mode & VERBOSE)
948         display_catalogue();
949
950     buf += 32;
951
952     if (mode & EFI)
953     {
954         if (!read_efi_section(buf)) {
955             buf += 32;
956             if (!read_efi_catalogue(buf, &efi_count, &efi_lba) && efi_lba) {
957                 offset = 0;
958             } else {
959                 errx(1, "%s: invalid efi catalogue", argv[0]);
960             }
961         } else {
962             errx(1, "%s: unable to find efi image", argv[0]);
963         }
964     }
965
966     buf += 32;
967
968     if (mode & MAC)
969     {
970         if (!read_efi_section(buf)) {
971             buf += 32;
972             if (!read_efi_catalogue(buf, &mac_count, &mac_lba) && mac_lba) {
973                 offset = 0;
974             } else {
975                 errx(1, "%s: invalid efi catalogue", argv[0]);
976             }
977         } else {
978             errx(1, "%s: unable to find mac efi image", argv[0]);
979         }
980     }
981
982     if (fseek(fp, (de_lba * 2048 + 0x40), SEEK_SET))
983         err(1, "%s: seek error - 3", argv[0]);
984
985     buf = bufz;
986     memset(buf, 0, BUFSIZE);
987     if (fread(buf, sizeof(char), 4, fp) != 4)
988         err(1, "%s", argv[0]);
989
990     if (memcmp(buf, "\xFB\xC0\x78\x70", 4))
991         errx(1, "%s: boot loader does not have an isolinux.bin hybrid " \
992                  "signature. Note that isolinux-debug.bin does not support " \
993                  "hybrid booting", argv[0]);
994
995     if (stat(argv[0], &isostat))
996         err(1, "%s", argv[0]);
997
998     isosize = lendian_int(descriptor.size) * lendian_short(descriptor.block_size);
999     free_space = isostat.st_size - isosize;
1000
1001     cylsize = head * sector * 512;
1002     frac = isostat.st_size % cylsize;
1003     padding = (frac > 0) ? cylsize - frac : 0;
1004
1005     if (mode & VERBOSE)
1006         printf("imgsize: %zu, padding: %d\n", (size_t)isostat.st_size, padding);
1007
1008     cc = c = ( isostat.st_size + padding) / cylsize;
1009     if (c > 1024)
1010     {
1011         warnx("Warning: more than 1024 cylinders: %d", c);
1012         warnx("Not all BIOSes will be able to boot this device");
1013         cc = 1024;
1014     }
1015
1016     if (!id)
1017     {
1018         if (fseek(fp, 440, SEEK_SET))
1019             err(1, "%s: seek error - 4", argv[0]);
1020
1021         if (fread(&id, 1, 4, fp) != 4)
1022             err(1, "%s: read error", argv[0]);
1023
1024         id = lendian_int(id);
1025         if (!id)
1026         {
1027             if (mode & VERBOSE)
1028                 printf("random ");
1029             id = rand();
1030         }
1031     }
1032     if (mode & VERBOSE)
1033         printf("id: %u\n", id);
1034
1035     buf = bufz;
1036     memset(buf, 0, BUFSIZE);
1037     i = initialise_mbr(buf);
1038
1039     if (mode & VERBOSE)
1040         display_mbr(buf, i);
1041
1042     if (fseek(fp, 0, SEEK_SET))
1043         err(1, "%s: seek error - 5", argv[0]);
1044
1045     if (fwrite(buf, sizeof(char), i, fp) != (size_t)i)
1046         err(1, "%s: write error - 1", argv[0]);
1047
1048     if (efi_lba) {
1049         reverse_uuid(basic_partition);
1050         reverse_uuid(hfs_partition);
1051
1052         /* 512 byte header, 128 entries of 128 bytes */
1053         orig_gpt_size = gpt_size = 512 + (128 * 128);
1054
1055         /* Leave space for the APM if necessary */
1056         if (mac_lba)
1057             gpt_size += (4 * 2048);
1058
1059         buf = calloc(gpt_size, sizeof(char));
1060         memset(buf, 0, gpt_size);
1061
1062         /*
1063          * We need to ensure that we have enough space for the secondary GPT.
1064          * Unlike the primary, this doesn't need a hole for the APM. We still
1065          * want to be 1MB aligned so just bump the padding by a megabyte.
1066          */
1067         if (free_space < orig_gpt_size && padding < orig_gpt_size) {
1068             padding += 1024 * 1024;
1069         }
1070
1071         /*
1072          * Determine the size of the ISO filesystem. This will define the size
1073          * of the partition that covers it.
1074          */
1075         psize = isosize / 512;
1076
1077         /*
1078          * Primary GPT starts at sector 1, secondary GPT starts at 1 sector
1079          * before the end of the image
1080          */
1081         initialise_gpt(buf, 1, (isostat.st_size + padding - 1024) / 512, 1);
1082
1083         if (fseek(fp, 512, SEEK_SET))
1084             err(1, "%s: seek error - 6", argv[0]);
1085
1086         if (fwrite(buf, sizeof(char), gpt_size, fp) != (size_t)gpt_size)
1087             err(1, "%s: write error - 2", argv[0]);
1088     }
1089
1090     if (mac_lba)
1091     {
1092         /* Apple partition entries filling 2048 bytes each */
1093         int apm_size = apm_parts * 2048;
1094
1095         buf = realloc(buf, apm_size);
1096         memset(buf, 0, apm_size);
1097
1098         initialise_apm(buf, APM_OFFSET);
1099
1100         fseek(fp, APM_OFFSET, SEEK_SET);
1101         fwrite(buf, sizeof(char), apm_size, fp);
1102     }
1103
1104     if (padding)
1105     {
1106         if (fsync(fileno(fp)))
1107             err(1, "%s: could not synchronise", argv[0]);
1108
1109         if (ftruncate(fileno(fp), isostat.st_size + padding))
1110             err(1, "%s: could not add padding bytes", argv[0]);
1111     }
1112
1113     if (efi_lba) {
1114         buf = realloc(buf, orig_gpt_size);
1115         memset(buf, 0, orig_gpt_size);
1116
1117         buf += orig_gpt_size - sizeof(struct gpt_header);
1118
1119         initialise_gpt(buf, (isostat.st_size + padding - 1024) / 512, 1, 0);
1120
1121         /* Shift back far enough to write the 128 GPT entries */
1122         buf -= 128 * sizeof(struct gpt_part_header);
1123
1124         /*
1125          * Seek far enough back that the gpt header is 512 bytes before the
1126          * end of the image
1127          */
1128
1129         if (fseek(fp, (isostat.st_size + padding) - orig_gpt_size - 512,
1130                   SEEK_SET))
1131             err(1, "%s: seek error - 8", argv[0]);
1132
1133         if (fwrite(buf, sizeof(char), orig_gpt_size, fp) != orig_gpt_size)
1134             err(1, "%s: write error - 4", argv[0]);
1135     }
1136
1137     free(buf);
1138     fclose(fp);
1139
1140     return 0;
1141 }