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