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