dmi: check both the AC and ID flags at the same time
[syslinux.git] / utils / isohybrid.c
bloba9e38d4ddc4113d55ff53f8a7ba117e52c9112d9
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.
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.
9 * Copyright (C) 2010 P J P <pj.pandit@yahoo.co.in>
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.
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.
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>.
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>
42 #include "isohybrid.h"
44 char *prog = NULL;
45 extern int opterr, optind;
46 struct stat isostat;
47 unsigned int padding = 0;
49 uuid_t disk_uuid, part_uuid, iso_uuid;
51 uint8_t mode = 0;
52 enum { VERBOSE = 1 , EFI = 2 , MAC = 4};
54 /* user options */
55 uint16_t head = 64; /* 1 <= head <= 256 */
56 uint8_t sector = 32; /* 1 <= sector <= 63 */
58 uint8_t entry = 0; /* partition number: 1 <= entry <= 4 */
59 uint8_t offset = 0; /* partition offset: 0 <= offset <= 64 */
60 uint16_t type = 0x17; /* partition type: 0 <= type <= 255 */
61 uint32_t id = 0; /* MBR: 0 <= id <= 0xFFFFFFFF(4294967296) */
63 uint8_t hd0 = 0; /* 0 <= hd0 <= 2 */
64 uint8_t partok = 0; /* 0 <= partok <= 1 */
66 char mbr_template_path[1024] = {0}; /* Path to MBR template */
68 uint16_t ve[16];
69 uint32_t catoffset = 0;
70 uint32_t c = 0, cc = 0, cs = 0;
72 uint32_t psize = 0, isosize = 0;
74 /* boot catalogue parameters */
75 uint32_t de_lba = 0;
76 uint16_t de_seg = 0, de_count = 0, de_mbz2 = 0;
77 uint8_t de_boot = 0, de_media = 0, de_sys = 0, de_mbz1 = 0;
78 uint32_t efi_lba = 0, mac_lba = 0;
79 uint16_t efi_count = 0, mac_count = 0;
80 uint8_t efi_boot = 0, efi_media = 0, efi_sys = 0;
82 int apm_parts = 3;
84 uint8_t afp_header[] = { 0x45, 0x52, 0x08, 0x00, 0x00, 0x00, 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
86 uuid_t efi_system_partition = {0xC1, 0x2A, 0x73, 0x28, 0xF8, 0x1F, 0x11, 0xD2, 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B};
87 uuid_t basic_partition = {0xEB,0xD0,0xA0,0xA2,0xB9,0xE5,0x44,0x33,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7};
88 uuid_t hfs_partition = {0x48, 0x46, 0x53, 0x00, 0x00, 0x00, 0x11, 0xAA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC};
90 uint32_t crc_tab[256] =
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
158 struct iso_primary_descriptor {
159 uint8_t ignore [80];
160 uint32_t size;
161 uint8_t ignore2 [44];
162 uint16_t block_size;
165 struct gpt_header {
166 uint64_t signature;
167 uint32_t revision;
168 uint32_t headerSize;
169 uint32_t headerCRC;
170 uint32_t reserved;
171 uint64_t currentLBA;
172 uint64_t backupLBA;
173 uint64_t firstUsableLBA;
174 uint64_t lastUsableLBA;
175 uuid_t diskGUID;
176 uint64_t partitionEntriesLBA;
177 uint32_t numParts;
178 uint32_t sizeOfPartitionEntries;
179 uint32_t partitionEntriesCRC;
180 uint8_t reserved2[420];
183 struct gpt_part_header {
184 uuid_t partTypeGUID;
185 uuid_t partGUID;
186 uint64_t firstLBA;
187 uint64_t lastLBA;
188 uint64_t attributes;
189 uint16_t name[36];
192 #define APM_OFFSET 2048
194 struct apple_part_header {
195 uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */
196 uint16_t res1;
197 uint32_t map_count; /* # blocks in partition map */
198 uint32_t start_block; /* absolute starting block # of partition */
199 uint32_t block_count; /* number of blocks in partition */
200 char name[32]; /* partition name */
201 char type[32]; /* string type description */
202 uint32_t data_start; /* rel block # of first data block */
203 uint32_t data_count; /* number of data blocks */
204 uint32_t status; /* partition status bits */
205 uint32_t boot_start;
206 uint32_t boot_count;
207 uint32_t boot_load;
208 uint32_t boot_load2;
209 uint32_t boot_entry;
210 uint32_t boot_entry2;
211 uint32_t boot_cksum;
212 char processor[16]; /* Contains 680x0, x=0,2,3,4; or empty */
213 uint32_t driver_sig;
214 char _padding[372];
218 void
219 usage(void)
221 printf("Usage: %s [OPTIONS] <boot.iso>\n", prog);
225 void
226 printh(void)
228 #define FMT "%-20s %s\n"
230 usage();
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");
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");
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");
254 printf("\n");
255 printf("Report bugs to <pj.pandit@yahoo.co.in>\n");
260 check_option(int argc, char *argv[])
262 char *err = NULL;
263 int n = 0, ind = 0;
265 const char optstr[] = ":h:s:e:o:t:i:b:umfcp?vV";
266 struct option lopt[] = \
268 { "entry", required_argument, NULL, 'e' },
269 { "offset", required_argument, NULL, 'o' },
270 { "type", required_argument, NULL, 't' },
271 { "id", required_argument, NULL, 'i' },
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' },
280 { "help", no_argument, NULL, '?' },
281 { "verbose", no_argument, NULL, 'v' },
282 { "version", no_argument, NULL, 'V' },
284 { 0, 0, 0, 0 }
287 opterr = mode = 0;
288 while ((n = getopt_long_only(argc, argv, optstr, lopt, &ind)) != -1)
290 switch (n)
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;
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;
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;
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;
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;
324 case 'i':
325 id = strtoul(optarg, &err, 0);
326 if (*err)
327 errx(1, "invalid id: `%s'", optarg);
328 break;
330 case 'f':
331 hd0 = 1;
332 break;
334 case 'c':
335 hd0 = 2;
336 break;
338 case 'p':
339 partok = 1;
340 break;
342 case 'u':
343 mode |= EFI;
344 if (entry)
345 errx(1, "setting an entry is unsupported with EFI or Mac");
346 break;
348 case 'm':
349 mode |= MAC;
350 if (entry)
351 errx(1, "setting an entry is unsupported with EFI or Mac");
352 break;
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;
360 case 'v':
361 mode |= VERBOSE;
362 break;
364 case 'V':
365 printf("%s version %s\n", prog, VERSION);
366 exit(0);
368 case ':':
369 errx(1, "option `-%c' takes an argument", optopt);
371 default:
372 case '?':
373 if (optopt)
374 errx(1, "invalid option `-%c', see --help", optopt);
376 printh();
377 exit(0);
381 return optind;
384 uint16_t
385 bendian_short(const uint16_t s)
387 uint16_t r = 1;
389 if (!*(uint8_t *)&r)
390 return s;
392 r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
394 return r;
398 uint32_t
399 bendian_int(const uint32_t s)
401 uint32_t r = 1;
403 if (!*(uint8_t *)&r)
404 return s;
406 r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
407 | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
409 return r;
412 uint16_t
413 lendian_short(const uint16_t s)
415 uint16_t r = 1;
417 if (*(uint8_t *)&r)
418 return s;
420 r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
422 return r;
426 uint32_t
427 lendian_int(const uint32_t s)
429 uint32_t r = 1;
431 if (*(uint8_t *)&r)
432 return s;
434 r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
435 | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
437 return r;
440 uint64_t
441 lendian_64(const uint64_t s)
443 uint64_t r = 1;
445 if (*(uint8_t *)&r)
446 return s;
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;
453 return r;
458 check_banner(const uint8_t *buf)
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";
464 if (!buf || memcmp(buf, banner, sizeof(banner) - 1))
465 return 1;
467 buf += sizeof(banner) - 1;
468 memcpy(&catoffset, buf, sizeof(catoffset));
470 catoffset = lendian_int(catoffset);
472 return 0;
477 check_catalogue(const uint8_t *buf)
479 int i = 0;
481 for (i = 0, cs = 0; i < 16; i++)
483 ve[i] = 0;
484 memcpy(&ve[i], buf, sizeof(ve[i]));
486 ve[i] = lendian_short(ve[i]);
488 buf += 2;
489 cs += ve[i];
491 if (mode & VERBOSE)
492 printf("ve[%d]: %d, cs: %d\n", i, ve[i], cs);
494 if ((ve[0] != 0x0001) || (ve[15] != 0xAA55) || (cs & 0xFFFF))
495 return 1;
497 return 0;
502 read_catalogue(const uint8_t *buf)
504 memcpy(&de_boot, buf++, 1);
505 memcpy(&de_media, buf++, 1);
507 memcpy(&de_seg, buf, 2);
508 de_seg = lendian_short(de_seg);
509 buf += 2;
511 memcpy(&de_sys, buf++, 1);
512 memcpy(&de_mbz1, buf++, 1);
514 memcpy(&de_count, buf, 2);
515 de_count = lendian_short(de_count);
516 buf += 2;
518 memcpy(&de_lba, buf, 4);
519 de_lba = lendian_int(de_lba);
520 buf += 4;
522 memcpy(&de_mbz2, buf, 2);
523 de_mbz2 = lendian_short(de_mbz2);
524 buf += 2;
526 if (de_boot != 0x88 || de_media != 0
527 || (de_seg != 0 && de_seg != 0x7C0) || de_count != 4)
528 return 1;
530 return 0;
535 read_efi_section(const uint8_t *buf)
537 unsigned char header_indicator;
538 unsigned char platform_id;
539 short count;
541 memcpy(&header_indicator, buf++, 1);
542 memcpy(&platform_id, buf++, 1);
544 memcpy(&count, buf, 2);
545 count = lendian_short(count);
546 buf += 2;
548 if (platform_id == 0xef)
549 return 0;
551 return 1;
555 read_efi_catalogue(const uint8_t *buf, uint16_t *count, uint32_t *lba)
557 buf += 6;
559 memcpy(count, buf, 2);
560 *count = lendian_short(*count);
561 buf += 2;
563 memcpy(lba, buf, 4);
564 *lba = lendian_int(*lba);
565 buf += 6;
567 return 0;
571 void
572 display_catalogue(void)
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);
585 void
586 read_mbr_template(char *path, uint8_t *mbr)
588 FILE *fp;
589 int ret;
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);
603 initialise_mbr(uint8_t *mbr)
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;
611 #ifndef ISOHYBRID_C_STANDALONE
612 extern unsigned char isohdpfx[][MBRSIZE];
613 #endif
615 if (mbr_template_path[0]) {
616 read_mbr_template(mbr_template_path, mbr);
617 } else {
619 #ifdef ISOHYBRID_C_STANDALONE
621 err(1, "This is a standalone binary. You must specify --mbr. E.g with /usr/lib/syslinux/isohdpfx.bin");
623 #else
625 memcpy(mbr, &isohdpfx[hd0 + 3 * partok], MBRSIZE);
627 #endif /* ! ISOHYBRID_C_STANDALONE */
631 if (mode & MAC) {
632 memcpy(mbr, afp_header, sizeof(afp_header));
635 if (!entry)
636 entry = 1;
638 if (mode & EFI)
639 type = 0;
641 mbr += MBRSIZE; /* offset 432 */
643 tmp = lendian_int(de_lba * 4);
644 memcpy(mbr, &tmp, sizeof(tmp));
645 mbr += sizeof(tmp); /* offset 436 */
647 tmp = 0;
648 memcpy(mbr, &tmp, sizeof(tmp));
649 mbr += sizeof(tmp); /* offset 440 */
651 tmp = lendian_int(id);
652 memcpy(mbr, &tmp, sizeof(tmp));
653 mbr += sizeof(tmp); /* offset 444 */
655 mbr[0] = '\0';
656 mbr[1] = '\0';
657 mbr += 2; /* offset 446 */
659 ptype = type;
660 psize = c * head * sector - offset;
662 bhead = (offset / sector) % head;
663 bsect = (offset % sector) + 1;
664 bcyle = offset / (head * sector);
666 bsect += (bcyle & 0x300) >> 2;
667 bcyle &= 0xFF;
669 ehead = head - 1;
670 esect = sector + (((cc - 1) & 0x300) >> 2);
671 ecyle = (cc - 1) & 0xFF;
673 for (i = 1; i <= 4; i++)
675 memset(mbr, 0, 16);
676 if (i == entry)
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;
687 tmp = lendian_int(offset);
688 memcpy(&mbr[8], &tmp, sizeof(tmp));
690 tmp = lendian_int(psize);
691 memcpy(&mbr[12], &tmp, sizeof(tmp));
693 if (i == 2 && (mode & EFI))
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;
704 tmp = lendian_int(efi_lba * 4);
705 memcpy(&mbr[8], &tmp, sizeof(tmp));
707 tmp = lendian_int(efi_count);
708 memcpy(&mbr[12], &tmp, sizeof(tmp));
710 if (i == 3 && (mode & MAC))
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;
721 tmp = lendian_int(mac_lba * 4);
722 memcpy(&mbr[8], &tmp, sizeof(tmp));
724 tmp = lendian_int(mac_count);
725 memcpy(&mbr[12], &tmp, sizeof(tmp));
727 mbr += 16;
729 mbr[0] = 0x55;
730 mbr[1] = 0xAA;
731 mbr += 2;
733 return mbr - rbm;
736 void
737 display_mbr(const uint8_t *mbr, size_t len)
739 unsigned char c = 0;
740 unsigned int i = 0, j = 0;
742 printf("sizeof(MBR): %zu bytes\n", len);
743 for (i = 0; i < len; i++)
745 if (!(i % 16))
746 printf("%04d ", i);
748 if (!(i % 8))
749 printf(" ");
751 c = mbr[i];
752 printf("%02x ", c);
754 if (!((i + 1) % 16))
756 printf(" |");
757 for (; j <= i; j++)
758 printf("%c", isprint(mbr[j]) ? mbr[j] : '.');
759 printf("|\n");
765 uint32_t chksum_crc32 (unsigned char *block, unsigned int length)
767 register unsigned long crc;
768 unsigned long i;
770 crc = 0xFFFFFFFF;
771 for (i = 0; i < length; i++)
773 crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
775 return (crc ^ 0xFFFFFFFF);
778 void
779 reverse_uuid(uuid_t uuid)
781 uint8_t t, *p = (uint8_t *)uuid;
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;
789 static uint16_t *
790 ascii_to_utf16le(uint16_t *dst, const char *src)
792 uint8_t *p = (uint8_t *)dst;
793 char c;
795 do {
796 c = *src++;
797 *p++ = c;
798 *p++ = 0;
799 } while (c);
801 return (uint16_t *)p;
804 void
805 initialise_gpt(uint8_t *gpt, uint32_t current, uint32_t alternate, int primary)
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;
812 if (mac_lba) {
813 /* 2048 bytes per partition, plus round to 2048 boundary */
814 hole = (apm_parts * 4) + 2;
817 if (primary) {
818 uuid_generate(disk_uuid);
819 reverse_uuid(disk_uuid);
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));
838 if (primary)
839 gpt += sizeof(struct gpt_header) + hole * 512;
840 else
841 gpt -= header->sizeOfPartitionEntries * header->numParts;
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);
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");
857 gpt += sizeof(struct gpt_part_header);
858 part++;
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");
866 gpt += sizeof(struct gpt_part_header);
868 if (mac_lba) {
869 gpt += sizeof(struct gpt_part_header);
871 part++;
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");
879 part--;
882 part--;
884 header->partitionEntriesCRC = lendian_int (chksum_crc32((uint8_t *)part,
885 header->numParts * header->sizeOfPartitionEntries));
887 header->headerCRC = lendian_int(chksum_crc32((uint8_t *)header,
888 header->headerSize));
891 void
892 initialise_apm(uint8_t *gpt, uint32_t start)
894 struct apple_part_header *part = (struct apple_part_header *)gpt;
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);
906 part = (struct apple_part_header *)(gpt + 2048);
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);
918 part = (struct apple_part_header *)(gpt + 4096);
920 if (mac_lba)
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);
945 main(int argc, char *argv[])
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;
954 prog = strcpy(alloca(strlen(argv[0]) + 1), argv[0]);
955 i = check_option(argc, argv);
956 argc -= i;
957 argv += i;
959 if (!argc)
961 usage();
962 return 1;
965 if ((mode & EFI) && offset)
966 errx(1, "%s: --offset is invalid with UEFI images\n", argv[0]);
968 srand(time(NULL) << (getppid() << getpid()));
970 if (!(fp = fopen(argv[0], "rb+")))
971 err(1, "could not open file `%s'", argv[0]);
973 if (fseeko(fp, (off_t) (16 << 11), SEEK_SET))
974 err(1, "%s: seek error - 0", argv[0]);
976 if (fread(&descriptor, sizeof(char), sizeof(descriptor), fp) != sizeof(descriptor))
977 err(1, "%s: read error - 0", argv[0]);
979 if (fseeko(fp, (off_t) 17 * 2048, SEEK_SET))
980 err(1, "%s: seek error - 1", argv[0]);
982 bufz = buf = calloc(BUFSIZE, sizeof(char));
983 if (fread(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE)
984 err(1, "%s", argv[0]);
986 if (check_banner(buf))
987 errx(1, "%s: could not find boot record", argv[0]);
989 if (mode & VERBOSE)
990 printf("catalogue offset: %d\n", catoffset);
992 if (fseeko(fp, ((off_t) catoffset) * 2048, SEEK_SET))
993 err(1, "%s: seek error - 2", argv[0]);
995 buf = bufz;
996 memset(buf, 0, BUFSIZE);
997 if (fread(buf, sizeof(char), BUFSIZE, fp) != BUFSIZE)
998 err(1, "%s", argv[0]);
1000 if (check_catalogue(buf))
1001 errx(1, "%s: invalid boot catalogue", argv[0]);
1003 buf += sizeof(ve);
1004 if (read_catalogue(buf))
1005 errx(1, "%s: unexpected boot catalogue parameters", argv[0]);
1007 if (mode & VERBOSE)
1008 display_catalogue();
1010 buf += 32;
1012 if (mode & EFI)
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]);
1021 } else {
1022 errx(1, "%s: unable to find efi image", argv[0]);
1026 buf += 32;
1028 if (mode & MAC)
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]);
1037 } else {
1038 errx(1, "%s: unable to find mac efi image", argv[0]);
1042 if (fseeko(fp, (((off_t) de_lba) * 2048 + 0x40), SEEK_SET))
1043 err(1, "%s: seek error - 3", argv[0]);
1045 buf = bufz;
1046 memset(buf, 0, BUFSIZE);
1047 if (fread(buf, sizeof(char), 4, fp) != 4)
1048 err(1, "%s", argv[0]);
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]);
1055 if (stat(argv[0], &isostat))
1056 err(1, "%s", argv[0]);
1058 isosize = lendian_int(descriptor.size) * lendian_short(descriptor.block_size);
1059 free_space = isostat.st_size - isosize;
1061 cylsize = head * sector * 512;
1062 frac = isostat.st_size % cylsize;
1063 padding = (frac > 0) ? cylsize - frac : 0;
1065 if (mode & VERBOSE)
1066 printf("imgsize: %zu, padding: %d\n", (size_t)isostat.st_size, padding);
1068 cc = c = ( isostat.st_size + padding) / cylsize;
1069 if (c > 1024)
1071 warnx("Warning: more than 1024 cylinders: %d", c);
1072 warnx("Not all BIOSes will be able to boot this device");
1073 cc = 1024;
1076 if (!id)
1078 if (fseeko(fp, (off_t) 440, SEEK_SET))
1079 err(1, "%s: seek error - 4", argv[0]);
1081 if (fread(&id, 1, 4, fp) != 4)
1082 err(1, "%s: read error", argv[0]);
1084 id = lendian_int(id);
1085 if (!id)
1087 if (mode & VERBOSE)
1088 printf("random ");
1089 id = rand();
1092 if (mode & VERBOSE)
1093 printf("id: %u\n", id);
1095 buf = bufz;
1096 memset(buf, 0, BUFSIZE);
1097 i = initialise_mbr(buf);
1099 if (mode & VERBOSE)
1100 display_mbr(buf, i);
1102 if (fseeko(fp, (off_t) 0, SEEK_SET))
1103 err(1, "%s: seek error - 5", argv[0]);
1105 if (fwrite(buf, sizeof(char), i, fp) != (size_t)i)
1106 err(1, "%s: write error - 1", argv[0]);
1108 if (efi_lba) {
1109 reverse_uuid(basic_partition);
1110 reverse_uuid(hfs_partition);
1112 /* 512 byte header, 128 entries of 128 bytes */
1113 orig_gpt_size = gpt_size = 512 + (128 * 128);
1115 /* Leave space for the APM if necessary */
1116 if (mac_lba)
1117 gpt_size += (4 * 2048);
1119 buf = calloc(gpt_size, sizeof(char));
1120 memset(buf, 0, gpt_size);
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.
1127 if (free_space < orig_gpt_size && padding < orig_gpt_size) {
1128 padding += 1024 * 1024;
1132 * Determine the size of the ISO filesystem. This will define the size
1133 * of the partition that covers it.
1135 psize = isosize / 512;
1138 * Primary GPT starts at sector 1, secondary GPT starts at 1 sector
1139 * before the end of the image
1141 initialise_gpt(buf, 1, (isostat.st_size + padding - 512) / 512, 1);
1143 if (fseeko(fp, (off_t) 512, SEEK_SET))
1144 err(1, "%s: seek error - 6", argv[0]);
1146 if (fwrite(buf, sizeof(char), gpt_size, fp) != (size_t)gpt_size)
1147 err(1, "%s: write error - 2", argv[0]);
1150 if (mac_lba)
1152 /* Apple partition entries filling 2048 bytes each */
1153 int apm_size = apm_parts * 2048;
1155 buf = realloc(buf, apm_size);
1156 memset(buf, 0, apm_size);
1158 initialise_apm(buf, APM_OFFSET);
1160 fseeko(fp, (off_t) APM_OFFSET, SEEK_SET);
1161 fwrite(buf, sizeof(char), apm_size, fp);
1164 if (padding)
1166 if (fsync(fileno(fp)))
1167 err(1, "%s: could not synchronise", argv[0]);
1169 if (ftruncate(fileno(fp), isostat.st_size + padding))
1170 err(1, "%s: could not add padding bytes", argv[0]);
1173 if (efi_lba) {
1174 buf = realloc(buf, orig_gpt_size);
1175 memset(buf, 0, orig_gpt_size);
1177 buf += orig_gpt_size - sizeof(struct gpt_header);
1179 initialise_gpt(buf, (isostat.st_size + padding - 512) / 512, 1, 0);
1181 /* Shift back far enough to write the 128 GPT entries */
1182 buf -= 128 * sizeof(struct gpt_part_header);
1185 * Seek far enough back that the gpt header is 512 bytes before the
1186 * end of the image
1189 if (fseeko(fp, (isostat.st_size + padding) - orig_gpt_size, SEEK_SET))
1190 err(1, "%s: seek error - 8", argv[0]);
1192 if (fwrite(buf, sizeof(char), orig_gpt_size, fp) != orig_gpt_size)
1193 err(1, "%s: write error - 4", argv[0]);
1196 free(buf);
1197 fclose(fp);
1199 return 0;