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