1 /* $NetBSD: cd9660_eltorito.c,v 1.20 2013/01/28 21:03:28 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan 5 * Perez-Rathke and Ram Vedam. All rights reserved. 6 * 7 * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys, 8 * Alan Perez-Rathke and Ram Vedam. 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer in the documentation and/or other materials provided 18 * with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN 21 * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN 25 * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 28 * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 29 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 32 * OF SUCH DAMAGE. 33 */ 34 35 36 #include "cd9660.h" 37 #include "cd9660_eltorito.h" 38 #include <sys/bootblock.h> 39 #include <util.h> 40 41 #include <sys/cdefs.h> 42 #if defined(__RCSID) && !defined(__lint) 43 __RCSID("$NetBSD: cd9660_eltorito.c,v 1.20 2013/01/28 21:03:28 christos Exp $"); 44 #endif /* !__lint */ 45 46 #ifdef DEBUG 47 #define ELTORITO_DPRINTF(__x) printf __x 48 #else 49 #define ELTORITO_DPRINTF(__x) 50 #endif 51 52 #include <util.h> 53 54 static struct boot_catalog_entry *cd9660_init_boot_catalog_entry(void); 55 static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char); 56 static struct boot_catalog_entry *cd9660_boot_setup_default_entry( 57 struct cd9660_boot_image *); 58 static struct boot_catalog_entry *cd9660_boot_setup_section_head(char); 59 static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char); 60 #if 0 61 static u_char cd9660_boot_get_system_type(struct cd9660_boot_image *); 62 #endif 63 64 int 65 cd9660_add_boot_disk(iso9660_disk *diskStructure, const char *boot_info) 66 { 67 struct stat stbuf; 68 const char *mode_msg; 69 char *temp; 70 char *sysname; 71 char *filename; 72 struct cd9660_boot_image *new_image, *tmp_image; 73 74 assert(boot_info != NULL); 75 76 if (*boot_info == '\0') { 77 warnx("Error: Boot disk information must be in the " 78 "format 'system;filename'"); 79 return 0; 80 } 81 82 /* First decode the boot information */ 83 temp = estrdup(boot_info); 84 85 sysname = temp; 86 filename = strchr(sysname, ';'); 87 if (filename == NULL) { 88 warnx("supply boot disk information in the format " 89 "'system;filename'"); 90 free(temp); 91 return 0; 92 } 93 94 *filename++ = '\0'; 95 96 if (diskStructure->verbose_level > 0) { 97 printf("Found bootdisk with system %s, and filename %s\n", 98 sysname, filename); 99 } 100 new_image = ecalloc(1, sizeof(*new_image)); 101 new_image->loadSegment = 0; /* default for now */ 102 103 /* Decode System */ 104 if (strcmp(sysname, "i386") == 0) 105 new_image->system = ET_SYS_X86; 106 else if (strcmp(sysname, "powerpc") == 0) 107 new_image->system = ET_SYS_PPC; 108 else if (strcmp(sysname, "macppc") == 0 || 109 strcmp(sysname, "mac68k") == 0) 110 new_image->system = ET_SYS_MAC; 111 else { 112 warnx("boot disk system must be " 113 "i386, powerpc, macppc, or mac68k"); 114 free(temp); 115 free(new_image); 116 return 0; 117 } 118 119 120 new_image->filename = estrdup(filename); 121 122 free(temp); 123 124 /* Get information about the file */ 125 if (lstat(new_image->filename, &stbuf) == -1) 126 err(EXIT_FAILURE, "%s: lstat(\"%s\")", __func__, 127 new_image->filename); 128 129 switch (stbuf.st_size) { 130 case 1440 * 1024: 131 new_image->targetMode = ET_MEDIA_144FDD; 132 mode_msg = "Assigned boot image to 1.44 emulation mode"; 133 break; 134 case 1200 * 1024: 135 new_image->targetMode = ET_MEDIA_12FDD; 136 mode_msg = "Assigned boot image to 1.2 emulation mode"; 137 break; 138 case 2880 * 1024: 139 new_image->targetMode = ET_MEDIA_288FDD; 140 mode_msg = "Assigned boot image to 2.88 emulation mode"; 141 break; 142 default: 143 new_image->targetMode = ET_MEDIA_NOEM; 144 mode_msg = "Assigned boot image to no emulation mode"; 145 break; 146 } 147 148 if (diskStructure->verbose_level > 0) 149 printf("%s\n", mode_msg); 150 151 new_image->size = stbuf.st_size; 152 new_image->num_sectors = 153 howmany(new_image->size, diskStructure->sectorSize) * 154 howmany(diskStructure->sectorSize, 512); 155 if (diskStructure->verbose_level > 0) { 156 printf("New image has size %d, uses %d 512-byte sectors\n", 157 new_image->size, new_image->num_sectors); 158 } 159 new_image->sector = -1; 160 /* Bootable by default */ 161 new_image->bootable = ET_BOOTABLE; 162 /* Add boot disk */ 163 164 /* Group images for the same platform together. */ 165 TAILQ_FOREACH(tmp_image, &diskStructure->boot_images, image_list) { 166 if (tmp_image->system != new_image->system) 167 break; 168 } 169 170 if (tmp_image == NULL) { 171 TAILQ_INSERT_HEAD(&diskStructure->boot_images, new_image, 172 image_list); 173 } else 174 TAILQ_INSERT_BEFORE(tmp_image, new_image, image_list); 175 176 new_image->serialno = diskStructure->image_serialno++; 177 178 /* TODO : Need to do anything about the boot image in the tree? */ 179 diskStructure->is_bootable = 1; 180 181 return 1; 182 } 183 184 int 185 cd9660_eltorito_add_boot_option(iso9660_disk *diskStructure, 186 const char *option_string, const char *value) 187 { 188 char *eptr; 189 struct cd9660_boot_image *image; 190 191 assert(option_string != NULL); 192 193 /* Find the last image added */ 194 TAILQ_FOREACH(image, &diskStructure->boot_images, image_list) { 195 if (image->serialno + 1 == diskStructure->image_serialno) 196 break; 197 } 198 if (image == NULL) 199 errx(EXIT_FAILURE, "Attempted to add boot option, " 200 "but no boot images have been specified"); 201 202 if (strcmp(option_string, "no-emul-boot") == 0) { 203 image->targetMode = ET_MEDIA_NOEM; 204 } else if (strcmp(option_string, "no-boot") == 0) { 205 image->bootable = ET_NOT_BOOTABLE; 206 } else if (strcmp(option_string, "hard-disk-boot") == 0) { 207 image->targetMode = ET_MEDIA_HDD; 208 } else if (strcmp(option_string, "boot-load-segment") == 0) { 209 image->loadSegment = strtoul(value, &eptr, 16); 210 if (eptr == value || *eptr != '\0' || errno != ERANGE) { 211 warn("%s: strtoul", __func__); 212 return 0; 213 } 214 } else { 215 return 0; 216 } 217 return 1; 218 } 219 220 static struct boot_catalog_entry * 221 cd9660_init_boot_catalog_entry(void) 222 { 223 return ecalloc(1, sizeof(struct boot_catalog_entry)); 224 } 225 226 static struct boot_catalog_entry * 227 cd9660_boot_setup_validation_entry(char sys) 228 { 229 struct boot_catalog_entry *entry; 230 boot_catalog_validation_entry *ve; 231 int16_t checksum; 232 unsigned char *csptr; 233 size_t i; 234 entry = cd9660_init_boot_catalog_entry(); 235 236 ve = &entry->entry_data.VE; 237 238 ve->header_id[0] = 1; 239 ve->platform_id[0] = sys; 240 ve->key[0] = 0x55; 241 ve->key[1] = 0xAA; 242 243 /* Calculate checksum */ 244 checksum = 0; 245 cd9660_721(0, ve->checksum); 246 csptr = (unsigned char*)ve; 247 for (i = 0; i < sizeof(*ve); i += 2) { 248 checksum += (int16_t)csptr[i]; 249 checksum += 256 * (int16_t)csptr[i + 1]; 250 } 251 checksum = -checksum; 252 cd9660_721(checksum, ve->checksum); 253 254 ELTORITO_DPRINTF(("%s: header_id %d, platform_id %d, key[0] %d, key[1] %d, " 255 "checksum %04x\n", __func__, ve->header_id[0], ve->platform_id[0], 256 ve->key[0], ve->key[1], checksum)); 257 return entry; 258 } 259 260 static struct boot_catalog_entry * 261 cd9660_boot_setup_default_entry(struct cd9660_boot_image *disk) 262 { 263 struct boot_catalog_entry *default_entry; 264 boot_catalog_initial_entry *ie; 265 266 default_entry = cd9660_init_boot_catalog_entry(); 267 if (default_entry == NULL) 268 return NULL; 269 270 ie = &default_entry->entry_data.IE; 271 272 ie->boot_indicator[0] = disk->bootable; 273 ie->media_type[0] = disk->targetMode; 274 cd9660_721(disk->loadSegment, ie->load_segment); 275 ie->system_type[0] = disk->system; 276 cd9660_721(disk->num_sectors, ie->sector_count); 277 cd9660_731(disk->sector, ie->load_rba); 278 279 ELTORITO_DPRINTF(("%s: boot indicator %d, media type %d, " 280 "load segment %04x, system type %d, sector count %d, " 281 "load rba %d\n", __func__, ie->boot_indicator[0], 282 ie->media_type[0], disk->loadSegment, ie->system_type[0], 283 disk->num_sectors, disk->sector)); 284 return default_entry; 285 } 286 287 static struct boot_catalog_entry * 288 cd9660_boot_setup_section_head(char platform) 289 { 290 struct boot_catalog_entry *entry; 291 boot_catalog_section_header *sh; 292 293 entry = cd9660_init_boot_catalog_entry(); 294 if (entry == NULL) 295 return NULL; 296 297 sh = &entry->entry_data.SH; 298 /* More by default. The last one will manually be set to 0x91 */ 299 sh->header_indicator[0] = ET_SECTION_HEADER_MORE; 300 sh->platform_id[0] = platform; 301 sh->num_section_entries[0] = 0; 302 return entry; 303 } 304 305 static struct boot_catalog_entry * 306 cd9660_boot_setup_section_entry(struct cd9660_boot_image *disk) 307 { 308 struct boot_catalog_entry *entry; 309 boot_catalog_section_entry *se; 310 if ((entry = cd9660_init_boot_catalog_entry()) == NULL) 311 return NULL; 312 313 se = &entry->entry_data.SE; 314 315 se->boot_indicator[0] = ET_BOOTABLE; 316 se->media_type[0] = disk->targetMode; 317 cd9660_721(disk->loadSegment, se->load_segment); 318 cd9660_721(disk->num_sectors, se->sector_count); 319 cd9660_731(disk->sector, se->load_rba); 320 return entry; 321 } 322 323 #if 0 324 static u_char 325 cd9660_boot_get_system_type(struct cd9660_boot_image *disk) 326 { 327 /* 328 For hard drive booting, we need to examine the MBR to figure 329 out what the partition type is 330 */ 331 return 0; 332 } 333 #endif 334 335 /* 336 * Set up the BVD, Boot catalog, and the boot entries, but do no writing 337 */ 338 int 339 cd9660_setup_boot(iso9660_disk *diskStructure, int first_sector) 340 { 341 int sector; 342 int used_sectors; 343 int num_entries = 0; 344 int catalog_sectors; 345 struct boot_catalog_entry *x86_head, *mac_head, *ppc_head, 346 *valid_entry, *default_entry, *temp, *head, **headp, *next; 347 struct cd9660_boot_image *tmp_disk; 348 349 headp = NULL; 350 x86_head = mac_head = ppc_head = NULL; 351 352 /* If there are no boot disks, don't bother building boot information */ 353 if (TAILQ_EMPTY(&diskStructure->boot_images)) 354 return 0; 355 356 /* Point to catalog: For now assume it consumes one sector */ 357 ELTORITO_DPRINTF(("Boot catalog will go in sector %d\n", first_sector)); 358 diskStructure->boot_catalog_sector = first_sector; 359 cd9660_bothendian_dword(first_sector, 360 diskStructure->boot_descriptor->boot_catalog_pointer); 361 362 /* Step 1: Generate boot catalog */ 363 /* Step 1a: Validation entry */ 364 valid_entry = cd9660_boot_setup_validation_entry(ET_SYS_X86); 365 if (valid_entry == NULL) 366 return -1; 367 368 /* 369 * Count how many boot images there are, 370 * and how many sectors they consume. 371 */ 372 num_entries = 1; 373 used_sectors = 0; 374 375 TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) { 376 used_sectors += tmp_disk->num_sectors; 377 378 /* One default entry per image */ 379 num_entries++; 380 } 381 catalog_sectors = howmany(num_entries * 0x20, diskStructure->sectorSize); 382 used_sectors += catalog_sectors; 383 384 if (diskStructure->verbose_level > 0) { 385 printf("%s: there will be %i entries consuming %i sectors. " 386 "Catalog is %i sectors\n", __func__, num_entries, 387 used_sectors, catalog_sectors); 388 } 389 390 /* Populate sector numbers */ 391 sector = first_sector + catalog_sectors; 392 TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) { 393 tmp_disk->sector = sector; 394 sector += tmp_disk->num_sectors; 395 } 396 397 LIST_INSERT_HEAD(&diskStructure->boot_entries, valid_entry, ll_struct); 398 399 /* Step 1b: Initial/default entry */ 400 /* TODO : PARAM */ 401 tmp_disk = TAILQ_FIRST(&diskStructure->boot_images); 402 default_entry = cd9660_boot_setup_default_entry(tmp_disk); 403 if (default_entry == NULL) { 404 warnx("Error: memory allocation failed in cd9660_setup_boot"); 405 return -1; 406 } 407 408 LIST_INSERT_AFTER(valid_entry, default_entry, ll_struct); 409 410 /* Todo: multiple default entries? */ 411 412 tmp_disk = TAILQ_NEXT(tmp_disk, image_list); 413 414 temp = default_entry; 415 416 /* If multiple boot images are given : */ 417 while (tmp_disk != NULL) { 418 /* Step 2: Section header */ 419 switch (tmp_disk->system) { 420 case ET_SYS_X86: 421 headp = &x86_head; 422 break; 423 case ET_SYS_PPC: 424 headp = &ppc_head; 425 break; 426 case ET_SYS_MAC: 427 headp = &mac_head; 428 break; 429 default: 430 warnx("%s: internal error: unknown system type", 431 __func__); 432 return -1; 433 } 434 435 if (*headp == NULL) { 436 head = 437 cd9660_boot_setup_section_head(tmp_disk->system); 438 if (head == NULL) { 439 warnx("Error: memory allocation failed in " 440 "cd9660_setup_boot"); 441 return -1; 442 } 443 LIST_INSERT_AFTER(default_entry, head, ll_struct); 444 *headp = head; 445 } else 446 head = *headp; 447 448 head->entry_data.SH.num_section_entries[0]++; 449 450 /* Step 2a: Section entry and extensions */ 451 temp = cd9660_boot_setup_section_entry(tmp_disk); 452 if (temp == NULL) { 453 warn("%s: cd9660_boot_setup_section_entry", __func__); 454 return -1; 455 } 456 457 while ((next = LIST_NEXT(head, ll_struct)) != NULL && 458 next->entry_type == ET_ENTRY_SE) 459 head = next; 460 461 LIST_INSERT_AFTER(head, temp, ll_struct); 462 tmp_disk = TAILQ_NEXT(tmp_disk, image_list); 463 } 464 465 /* TODO: Remaining boot disks when implemented */ 466 467 return first_sector + used_sectors; 468 } 469 470 int 471 cd9660_setup_boot_volume_descriptor(iso9660_disk *diskStructure, 472 volume_descriptor *bvd) 473 { 474 boot_volume_descriptor *bvdData = 475 (boot_volume_descriptor*)bvd->volumeDescriptorData; 476 477 bvdData->boot_record_indicator[0] = ISO_VOLUME_DESCRIPTOR_BOOT; 478 memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5); 479 bvdData->version[0] = 1; 480 memcpy(bvdData->boot_system_identifier, ET_ID, 23); 481 memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5); 482 diskStructure->boot_descriptor = 483 (boot_volume_descriptor*) bvd->volumeDescriptorData; 484 return 1; 485 } 486 487 static int 488 cd9660_write_mbr_partition_entry(FILE *fd, int idx, off_t sector_start, 489 off_t nsectors, int type) 490 { 491 uint8_t val; 492 uint32_t lba; 493 494 if (fseeko(fd, (off_t)(idx) * 16 + 0x1be, SEEK_SET) == -1) 495 err(1, "fseeko"); 496 497 val = 0x80; /* Bootable */ 498 fwrite(&val, sizeof(val), 1, fd); 499 500 val = 0xff; /* CHS begin */ 501 fwrite(&val, sizeof(val), 1, fd); 502 fwrite(&val, sizeof(val), 1, fd); 503 fwrite(&val, sizeof(val), 1, fd); 504 505 val = type; /* Part type */ 506 fwrite(&val, sizeof(val), 1, fd); 507 508 val = 0xff; /* CHS end */ 509 fwrite(&val, sizeof(val), 1, fd); 510 fwrite(&val, sizeof(val), 1, fd); 511 fwrite(&val, sizeof(val), 1, fd); 512 513 /* LBA extent */ 514 lba = htole32(sector_start); 515 fwrite(&lba, sizeof(lba), 1, fd); 516 lba = htole32(nsectors); 517 fwrite(&lba, sizeof(lba), 1, fd); 518 519 return 0; 520 } 521 522 static int 523 cd9660_write_apm_partition_entry(FILE *fd, int idx, int total_partitions, 524 off_t sector_start, off_t nsectors, off_t sector_size, 525 const char *part_name, const char *part_type) 526 { 527 uint32_t apm32, part_status; 528 uint16_t apm16; 529 530 /* See Apple Tech Note 1189 for the details about the pmPartStatus 531 * flags. 532 * Below the flags which are default: 533 * - IsValid 0x01 534 * - IsAllocated 0x02 535 * - IsReadable 0x10 536 * - IsWritable 0x20 537 */ 538 part_status = APPLE_PS_VALID | APPLE_PS_ALLOCATED | APPLE_PS_READABLE | 539 APPLE_PS_WRITABLE; 540 541 if (fseeko(fd, (off_t)(idx + 1) * sector_size, SEEK_SET) == -1) 542 err(1, "fseeko"); 543 544 /* Signature */ 545 apm16 = htobe16(0x504d); 546 fwrite(&apm16, sizeof(apm16), 1, fd); 547 apm16 = 0; 548 fwrite(&apm16, sizeof(apm16), 1, fd); 549 550 /* Total number of partitions */ 551 apm32 = htobe32(total_partitions); 552 fwrite(&apm32, sizeof(apm32), 1, fd); 553 /* Bounds */ 554 apm32 = htobe32(sector_start); 555 fwrite(&apm32, sizeof(apm32), 1, fd); 556 apm32 = htobe32(nsectors); 557 fwrite(&apm32, sizeof(apm32), 1, fd); 558 559 fwrite(part_name, strlen(part_name) + 1, 1, fd); 560 fseek(fd, 32 - strlen(part_name) - 1, SEEK_CUR); 561 fwrite(part_type, strlen(part_type) + 1, 1, fd); 562 fseek(fd, 32 - strlen(part_type) - 1, SEEK_CUR); 563 564 apm32 = 0; 565 /* pmLgDataStart */ 566 fwrite(&apm32, sizeof(apm32), 1, fd); 567 /* pmDataCnt */ 568 apm32 = htobe32(nsectors); 569 fwrite(&apm32, sizeof(apm32), 1, fd); 570 /* pmPartStatus */ 571 apm32 = htobe32(part_status); 572 fwrite(&apm32, sizeof(apm32), 1, fd); 573 574 return 0; 575 } 576 577 int 578 cd9660_write_boot(iso9660_disk *diskStructure, FILE *fd) 579 { 580 struct boot_catalog_entry *e; 581 struct cd9660_boot_image *t; 582 int apm_partitions = 0; 583 int mbr_partitions = 0; 584 585 /* write boot catalog */ 586 if (fseeko(fd, (off_t)diskStructure->boot_catalog_sector * 587 diskStructure->sectorSize, SEEK_SET) == -1) 588 err(1, "fseeko"); 589 590 if (diskStructure->verbose_level > 0) { 591 printf("Writing boot catalog to sector %" PRId64 "\n", 592 diskStructure->boot_catalog_sector); 593 } 594 LIST_FOREACH(e, &diskStructure->boot_entries, ll_struct) { 595 if (diskStructure->verbose_level > 0) { 596 printf("Writing catalog entry of type %d\n", 597 e->entry_type); 598 } 599 /* 600 * It doesnt matter which one gets written 601 * since they are the same size 602 */ 603 fwrite(&(e->entry_data.VE), 1, 32, fd); 604 } 605 if (diskStructure->verbose_level > 0) 606 printf("Finished writing boot catalog\n"); 607 608 /* copy boot images */ 609 TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) { 610 if (diskStructure->verbose_level > 0) { 611 printf("Writing boot image from %s to sectors %d\n", 612 t->filename, t->sector); 613 } 614 cd9660_copy_file(diskStructure, fd, t->sector, t->filename); 615 616 if (t->system == ET_SYS_MAC) 617 apm_partitions++; 618 if (t->system == ET_SYS_PPC) 619 mbr_partitions++; 620 } 621 622 /* some systems need partition tables as well */ 623 if (mbr_partitions > 0 || diskStructure->chrp_boot) { 624 uint16_t sig; 625 626 fseek(fd, 0x1fe, SEEK_SET); 627 sig = htole16(0xaa55); 628 fwrite(&sig, sizeof(sig), 1, fd); 629 630 mbr_partitions = 0; 631 632 /* Write ISO9660 descriptor, enclosing the whole disk */ 633 if (diskStructure->chrp_boot) 634 cd9660_write_mbr_partition_entry(fd, mbr_partitions++, 635 0, diskStructure->totalSectors * 636 (diskStructure->sectorSize / 512), 0x96); 637 638 /* Write all partition entries */ 639 TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) { 640 if (t->system != ET_SYS_PPC) 641 continue; 642 cd9660_write_mbr_partition_entry(fd, mbr_partitions++, 643 t->sector * (diskStructure->sectorSize / 512), 644 t->num_sectors * (diskStructure->sectorSize / 512), 645 0x41 /* PReP Boot */); 646 } 647 } 648 649 if (apm_partitions > 0) { 650 /* Write DDR and global APM info */ 651 uint32_t apm32; 652 uint16_t apm16; 653 int total_parts; 654 655 fseek(fd, 0, SEEK_SET); 656 apm16 = htobe16(0x4552); 657 fwrite(&apm16, sizeof(apm16), 1, fd); 658 /* Device block size */ 659 apm16 = htobe16(512); 660 fwrite(&apm16, sizeof(apm16), 1, fd); 661 /* Device block count */ 662 apm32 = htobe32(diskStructure->totalSectors * 663 (diskStructure->sectorSize / 512)); 664 fwrite(&apm32, sizeof(apm32), 1, fd); 665 /* Device type/id */ 666 apm16 = htobe16(1); 667 fwrite(&apm16, sizeof(apm16), 1, fd); 668 fwrite(&apm16, sizeof(apm16), 1, fd); 669 670 /* Count total needed entries */ 671 total_parts = 2 + apm_partitions; /* Self + ISO9660 */ 672 673 /* Write self-descriptor */ 674 cd9660_write_apm_partition_entry(fd, 0, total_parts, 1, 675 total_parts, 512, "Apple", "Apple_partition_map"); 676 677 /* Write all partition entries */ 678 apm_partitions = 0; 679 TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) { 680 if (t->system != ET_SYS_MAC) 681 continue; 682 683 cd9660_write_apm_partition_entry(fd, 684 1 + apm_partitions++, total_parts, 685 t->sector * (diskStructure->sectorSize / 512), 686 t->num_sectors * (diskStructure->sectorSize / 512), 687 512, "CD Boot", "Apple_Bootstrap"); 688 } 689 690 /* Write ISO9660 descriptor, enclosing the whole disk */ 691 cd9660_write_apm_partition_entry(fd, 2 + apm_partitions, 692 total_parts, 0, diskStructure->totalSectors * 693 (diskStructure->sectorSize / 512), 512, "ISO9660", 694 "CD_ROM_Mode_1"); 695 } 696 697 return 0; 698 } 699