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