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