xref: /dflybsd-src/usr.sbin/makefs/cd9660/cd9660_eltorito.c (revision 811c20360d3976dd91a7d45accefc6ccb109f33b)
15978408cSSascha Wildner /*	$NetBSD: cd9660_eltorito.c,v 1.23 2018/03/28 06:48:55 nonaka Exp $	*/
25978408cSSascha Wildner 
35978408cSSascha Wildner /*-
45978408cSSascha Wildner  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
55978408cSSascha Wildner  *
65978408cSSascha Wildner  * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
75978408cSSascha Wildner  * Perez-Rathke and Ram Vedam.  All rights reserved.
85978408cSSascha Wildner  *
95978408cSSascha Wildner  * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
105978408cSSascha Wildner  * Alan Perez-Rathke and Ram Vedam.
115978408cSSascha Wildner  *
125978408cSSascha Wildner  * Redistribution and use in source and binary forms, with or
135978408cSSascha Wildner  * without modification, are permitted provided that the following
145978408cSSascha Wildner  * conditions are met:
155978408cSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
165978408cSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
175978408cSSascha Wildner  * 2. Redistributions in binary form must reproduce the above
185978408cSSascha Wildner  *    copyright notice, this list of conditions and the following
195978408cSSascha Wildner  *    disclaimer in the documentation and/or other materials provided
205978408cSSascha Wildner  *    with the distribution.
215978408cSSascha Wildner  *
225978408cSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
235978408cSSascha Wildner  * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
245978408cSSascha Wildner  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
255978408cSSascha Wildner  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
265978408cSSascha Wildner  * DISCLAIMED.  IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
275978408cSSascha Wildner  * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
285978408cSSascha Wildner  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
295978408cSSascha Wildner  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
305978408cSSascha Wildner  * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
315978408cSSascha Wildner  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
325978408cSSascha Wildner  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
335978408cSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
345978408cSSascha Wildner  * OF SUCH DAMAGE.
35*811c2036SSascha Wildner  *
36*811c2036SSascha Wildner  * $FreeBSD: head/usr.sbin/makefs/cd9660/cd9660_eltorito.c 331843 2018-03-31 15:04:41Z benno $
375978408cSSascha Wildner  */
385978408cSSascha Wildner 
395978408cSSascha Wildner #include "cd9660.h"
405978408cSSascha Wildner #include "cd9660_eltorito.h"
415978408cSSascha Wildner #include <util.h>
425978408cSSascha Wildner 
435978408cSSascha Wildner #ifdef DEBUG
445978408cSSascha Wildner #define	ELTORITO_DPRINTF(__x)	printf __x
455978408cSSascha Wildner #else
465978408cSSascha Wildner #define	ELTORITO_DPRINTF(__x)
475978408cSSascha Wildner #endif
485978408cSSascha Wildner 
495978408cSSascha Wildner #include <util.h>
505978408cSSascha Wildner 
515978408cSSascha Wildner static struct boot_catalog_entry *cd9660_init_boot_catalog_entry(void);
525978408cSSascha Wildner static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char);
535978408cSSascha Wildner static struct boot_catalog_entry *cd9660_boot_setup_default_entry(
545978408cSSascha Wildner     struct cd9660_boot_image *);
555978408cSSascha Wildner static struct boot_catalog_entry *cd9660_boot_setup_section_head(char);
565978408cSSascha Wildner #if 0
575978408cSSascha Wildner static u_char cd9660_boot_get_system_type(struct cd9660_boot_image *);
585978408cSSascha Wildner #endif
595978408cSSascha Wildner 
605978408cSSascha Wildner static struct cd9660_boot_image *default_boot_image;
615978408cSSascha Wildner 
625978408cSSascha Wildner int
cd9660_add_boot_disk(iso9660_disk * diskStructure,const char * boot_info)635978408cSSascha Wildner cd9660_add_boot_disk(iso9660_disk *diskStructure, const char *boot_info)
645978408cSSascha Wildner {
655978408cSSascha Wildner 	struct stat stbuf;
665978408cSSascha Wildner 	const char *mode_msg;
675978408cSSascha Wildner 	char *temp;
685978408cSSascha Wildner 	char *sysname;
695978408cSSascha Wildner 	char *filename;
705978408cSSascha Wildner 	struct cd9660_boot_image *new_image, *tmp_image;
715978408cSSascha Wildner 
725978408cSSascha Wildner 	assert(boot_info != NULL);
735978408cSSascha Wildner 
745978408cSSascha Wildner 	if (*boot_info == '\0') {
755978408cSSascha Wildner 		warnx("Error: Boot disk information must be in the "
765978408cSSascha Wildner 		      "format 'system;filename'");
775978408cSSascha Wildner 		return 0;
785978408cSSascha Wildner 	}
795978408cSSascha Wildner 
805978408cSSascha Wildner 	/* First decode the boot information */
815978408cSSascha Wildner 	temp = estrdup(boot_info);
825978408cSSascha Wildner 
835978408cSSascha Wildner 	sysname = temp;
845978408cSSascha Wildner 	filename = strchr(sysname, ';');
855978408cSSascha Wildner 	if (filename == NULL) {
865978408cSSascha Wildner 		warnx("supply boot disk information in the format "
875978408cSSascha Wildner 		    "'system;filename'");
885978408cSSascha Wildner 		free(temp);
895978408cSSascha Wildner 		return 0;
905978408cSSascha Wildner 	}
915978408cSSascha Wildner 
925978408cSSascha Wildner 	*filename++ = '\0';
935978408cSSascha Wildner 
945978408cSSascha Wildner 	if (diskStructure->verbose_level > 0) {
955978408cSSascha Wildner 		printf("Found bootdisk with system %s, and filename %s\n",
965978408cSSascha Wildner 		    sysname, filename);
975978408cSSascha Wildner 	}
985978408cSSascha Wildner 	new_image = ecalloc(1, sizeof(*new_image));
995978408cSSascha Wildner 	new_image->loadSegment = 0;	/* default for now */
1005978408cSSascha Wildner 
1015978408cSSascha Wildner 	/* Decode System */
1025978408cSSascha Wildner 	if (strcmp(sysname, "i386") == 0)
1035978408cSSascha Wildner 		new_image->system = ET_SYS_X86;
1045978408cSSascha Wildner 	else if (strcmp(sysname, "powerpc") == 0)
1055978408cSSascha Wildner 		new_image->system = ET_SYS_PPC;
1065978408cSSascha Wildner 	else if (strcmp(sysname, "macppc") == 0 ||
1075978408cSSascha Wildner 	         strcmp(sysname, "mac68k") == 0)
1085978408cSSascha Wildner 		new_image->system = ET_SYS_MAC;
1095978408cSSascha Wildner 	else {
1105978408cSSascha Wildner 		warnx("boot disk system must be "
1115978408cSSascha Wildner 		      "i386, powerpc, macppc, or mac68k");
1125978408cSSascha Wildner 		free(temp);
1135978408cSSascha Wildner 		free(new_image);
1145978408cSSascha Wildner 		return 0;
1155978408cSSascha Wildner 	}
1165978408cSSascha Wildner 
1175978408cSSascha Wildner 
1185978408cSSascha Wildner 	new_image->filename = estrdup(filename);
1195978408cSSascha Wildner 
1205978408cSSascha Wildner 	free(temp);
1215978408cSSascha Wildner 
1225978408cSSascha Wildner 	/* Get information about the file */
1235978408cSSascha Wildner 	if (lstat(new_image->filename, &stbuf) == -1)
1245978408cSSascha Wildner 		err(EXIT_FAILURE, "%s: lstat(\"%s\")", __func__,
1255978408cSSascha Wildner 		    new_image->filename);
1265978408cSSascha Wildner 
1275978408cSSascha Wildner 	switch (stbuf.st_size) {
1285978408cSSascha Wildner 	case 1440 * 1024:
1295978408cSSascha Wildner 		new_image->targetMode = ET_MEDIA_144FDD;
1305978408cSSascha Wildner 		mode_msg = "Assigned boot image to 1.44 emulation mode";
1315978408cSSascha Wildner 		break;
1325978408cSSascha Wildner 	case 1200 * 1024:
1335978408cSSascha Wildner 		new_image->targetMode = ET_MEDIA_12FDD;
1345978408cSSascha Wildner 		mode_msg = "Assigned boot image to 1.2 emulation mode";
1355978408cSSascha Wildner 		break;
1365978408cSSascha Wildner 	case 2880 * 1024:
1375978408cSSascha Wildner 		new_image->targetMode = ET_MEDIA_288FDD;
1385978408cSSascha Wildner 		mode_msg = "Assigned boot image to 2.88 emulation mode";
1395978408cSSascha Wildner 		break;
1405978408cSSascha Wildner 	default:
1415978408cSSascha Wildner 		new_image->targetMode = ET_MEDIA_NOEM;
1425978408cSSascha Wildner 		mode_msg = "Assigned boot image to no emulation mode";
1435978408cSSascha Wildner 		break;
1445978408cSSascha Wildner 	}
1455978408cSSascha Wildner 
1465978408cSSascha Wildner 	if (diskStructure->verbose_level > 0)
1475978408cSSascha Wildner 		printf("%s\n", mode_msg);
1485978408cSSascha Wildner 
1495978408cSSascha Wildner 	new_image->size = stbuf.st_size;
1505978408cSSascha Wildner 	new_image->num_sectors =
1515978408cSSascha Wildner 	    howmany(new_image->size, diskStructure->sectorSize) *
1525978408cSSascha Wildner 	    howmany(diskStructure->sectorSize, 512);
1535978408cSSascha Wildner 	if (diskStructure->verbose_level > 0) {
1545978408cSSascha Wildner 		printf("New image has size %d, uses %d 512-byte sectors\n",
1555978408cSSascha Wildner 		    new_image->size, new_image->num_sectors);
1565978408cSSascha Wildner 	}
1575978408cSSascha Wildner 	new_image->sector = -1;
1585978408cSSascha Wildner 	/* Bootable by default */
1595978408cSSascha Wildner 	new_image->bootable = ET_BOOTABLE;
1605978408cSSascha Wildner 	/* Add boot disk */
1615978408cSSascha Wildner 
1625978408cSSascha Wildner 	/* Group images for the same platform together. */
1635978408cSSascha Wildner 	TAILQ_FOREACH(tmp_image, &diskStructure->boot_images, image_list) {
1645978408cSSascha Wildner 		if (tmp_image->system != new_image->system)
1655978408cSSascha Wildner 			break;
1665978408cSSascha Wildner 	}
1675978408cSSascha Wildner 
1685978408cSSascha Wildner 	if (tmp_image == NULL) {
1695978408cSSascha Wildner 		TAILQ_INSERT_HEAD(&diskStructure->boot_images, new_image,
1705978408cSSascha Wildner 		    image_list);
1715978408cSSascha Wildner 	} else
1725978408cSSascha Wildner 		TAILQ_INSERT_BEFORE(tmp_image, new_image, image_list);
1735978408cSSascha Wildner 
1745978408cSSascha Wildner 	new_image->serialno = diskStructure->image_serialno++;
1755978408cSSascha Wildner 
1765978408cSSascha Wildner 	new_image->platform_id = new_image->system;
1775978408cSSascha Wildner 
1785978408cSSascha Wildner 	/* TODO : Need to do anything about the boot image in the tree? */
1795978408cSSascha Wildner 	diskStructure->is_bootable = 1;
1805978408cSSascha Wildner 
1815978408cSSascha Wildner 	/* First boot image is initial/default entry. */
1825978408cSSascha Wildner 	if (default_boot_image == NULL)
1835978408cSSascha Wildner 		default_boot_image = new_image;
1845978408cSSascha Wildner 
1855978408cSSascha Wildner 	return 1;
1865978408cSSascha Wildner }
1875978408cSSascha Wildner 
1885978408cSSascha Wildner int
cd9660_eltorito_add_boot_option(iso9660_disk * diskStructure,const char * option_string,const char * value)1895978408cSSascha Wildner cd9660_eltorito_add_boot_option(iso9660_disk *diskStructure,
1905978408cSSascha Wildner     const char *option_string, const char *value)
1915978408cSSascha Wildner {
1925978408cSSascha Wildner 	char *eptr;
1935978408cSSascha Wildner 	struct cd9660_boot_image *image;
1945978408cSSascha Wildner 
1955978408cSSascha Wildner 	assert(option_string != NULL);
1965978408cSSascha Wildner 
1975978408cSSascha Wildner 	/* Find the last image added */
1985978408cSSascha Wildner 	TAILQ_FOREACH(image, &diskStructure->boot_images, image_list) {
1995978408cSSascha Wildner 		if (image->serialno + 1 == diskStructure->image_serialno)
2005978408cSSascha Wildner 			break;
2015978408cSSascha Wildner 	}
2025978408cSSascha Wildner 	if (image == NULL)
2035978408cSSascha Wildner 		errx(EXIT_FAILURE, "Attempted to add boot option, "
2045978408cSSascha Wildner 		    "but no boot images have been specified");
2055978408cSSascha Wildner 
2065978408cSSascha Wildner 	if (strcmp(option_string, "no-emul-boot") == 0) {
2075978408cSSascha Wildner 		image->targetMode = ET_MEDIA_NOEM;
2085978408cSSascha Wildner 	} else if (strcmp(option_string, "no-boot") == 0) {
2095978408cSSascha Wildner 		image->bootable = ET_NOT_BOOTABLE;
2105978408cSSascha Wildner 	} else if (strcmp(option_string, "hard-disk-boot") == 0) {
2115978408cSSascha Wildner 		image->targetMode = ET_MEDIA_HDD;
2125978408cSSascha Wildner 	} else if (strcmp(option_string, "boot-load-segment") == 0) {
2135978408cSSascha Wildner 		image->loadSegment = strtoul(value, &eptr, 16);
2145978408cSSascha Wildner 		if (eptr == value || *eptr != '\0' || errno != ERANGE) {
2155978408cSSascha Wildner 			warn("%s: strtoul", __func__);
2165978408cSSascha Wildner 			return 0;
2175978408cSSascha Wildner 		}
2185978408cSSascha Wildner 	} else if (strcmp(option_string, "platformid") == 0) {
2195978408cSSascha Wildner 		if (strcmp(value, "efi") == 0)
2205978408cSSascha Wildner 			image->platform_id = ET_SYS_EFI;
2215978408cSSascha Wildner 		else {
2225978408cSSascha Wildner 			warn("%s: unknown platform: %s", __func__, value);
2235978408cSSascha Wildner 			return 0;
2245978408cSSascha Wildner 		}
2255978408cSSascha Wildner 	} else {
2265978408cSSascha Wildner 		return 0;
2275978408cSSascha Wildner 	}
2285978408cSSascha Wildner 	return 1;
2295978408cSSascha Wildner }
2305978408cSSascha Wildner 
2315978408cSSascha Wildner static struct boot_catalog_entry *
cd9660_init_boot_catalog_entry(void)2325978408cSSascha Wildner cd9660_init_boot_catalog_entry(void)
2335978408cSSascha Wildner {
2345978408cSSascha Wildner 	return ecalloc(1, sizeof(struct boot_catalog_entry));
2355978408cSSascha Wildner }
2365978408cSSascha Wildner 
2375978408cSSascha Wildner static struct boot_catalog_entry *
cd9660_boot_setup_validation_entry(char sys)2385978408cSSascha Wildner cd9660_boot_setup_validation_entry(char sys)
2395978408cSSascha Wildner {
2405978408cSSascha Wildner 	struct boot_catalog_entry *entry;
2415978408cSSascha Wildner 	boot_catalog_validation_entry *ve;
2425978408cSSascha Wildner 	int16_t checksum;
2435978408cSSascha Wildner 	unsigned char *csptr;
2445978408cSSascha Wildner 	size_t i;
2455978408cSSascha Wildner 	entry = cd9660_init_boot_catalog_entry();
2465978408cSSascha Wildner 
2475978408cSSascha Wildner 	entry->entry_type = ET_ENTRY_VE;
2485978408cSSascha Wildner 	ve = &entry->entry_data.VE;
2495978408cSSascha Wildner 
2505978408cSSascha Wildner 	ve->header_id[0] = 1;
2515978408cSSascha Wildner 	ve->platform_id[0] = sys;
2525978408cSSascha Wildner 	ve->key[0] = 0x55;
2535978408cSSascha Wildner 	ve->key[1] = 0xAA;
2545978408cSSascha Wildner 
2555978408cSSascha Wildner 	/* Calculate checksum */
2565978408cSSascha Wildner 	checksum = 0;
2575978408cSSascha Wildner 	cd9660_721(0, ve->checksum);
2585978408cSSascha Wildner 	csptr = (unsigned char*)ve;
2595978408cSSascha Wildner 	for (i = 0; i < sizeof(*ve); i += 2) {
2605978408cSSascha Wildner 		checksum += (int16_t)csptr[i];
2615978408cSSascha Wildner 		checksum += 256 * (int16_t)csptr[i + 1];
2625978408cSSascha Wildner 	}
2635978408cSSascha Wildner 	checksum = -checksum;
2645978408cSSascha Wildner 	cd9660_721(checksum, ve->checksum);
2655978408cSSascha Wildner 
2665978408cSSascha Wildner         ELTORITO_DPRINTF(("%s: header_id %d, platform_id %d, key[0] %d, key[1] %d, "
2675978408cSSascha Wildner 	    "checksum %04x\n", __func__, ve->header_id[0], ve->platform_id[0],
2685978408cSSascha Wildner 	    ve->key[0], ve->key[1], checksum));
2695978408cSSascha Wildner 	return entry;
2705978408cSSascha Wildner }
2715978408cSSascha Wildner 
2725978408cSSascha Wildner static struct boot_catalog_entry *
cd9660_boot_setup_default_entry(struct cd9660_boot_image * disk)2735978408cSSascha Wildner cd9660_boot_setup_default_entry(struct cd9660_boot_image *disk)
2745978408cSSascha Wildner {
2755978408cSSascha Wildner 	struct boot_catalog_entry *default_entry;
2765978408cSSascha Wildner 	boot_catalog_initial_entry *ie;
2775978408cSSascha Wildner 
2785978408cSSascha Wildner 	default_entry = cd9660_init_boot_catalog_entry();
2795978408cSSascha Wildner 	if (default_entry == NULL)
2805978408cSSascha Wildner 		return NULL;
2815978408cSSascha Wildner 
2825978408cSSascha Wildner 	default_entry->entry_type = ET_ENTRY_IE;
2835978408cSSascha Wildner 	ie = &default_entry->entry_data.IE;
2845978408cSSascha Wildner 
2855978408cSSascha Wildner 	ie->boot_indicator[0] = disk->bootable;
2865978408cSSascha Wildner 	ie->media_type[0] = disk->targetMode;
2875978408cSSascha Wildner 	cd9660_721(disk->loadSegment, ie->load_segment);
2885978408cSSascha Wildner 	ie->system_type[0] = disk->system;
2895978408cSSascha Wildner 	cd9660_721(disk->num_sectors, ie->sector_count);
2905978408cSSascha Wildner 	cd9660_731(disk->sector, ie->load_rba);
2915978408cSSascha Wildner 
2925978408cSSascha Wildner 	ELTORITO_DPRINTF(("%s: boot indicator %d, media type %d, "
2935978408cSSascha Wildner 	    "load segment %04x, system type %d, sector count %d, "
2945978408cSSascha Wildner 	    "load rba %d\n", __func__, ie->boot_indicator[0],
2955978408cSSascha Wildner 	    ie->media_type[0], disk->loadSegment, ie->system_type[0],
2965978408cSSascha Wildner 	    disk->num_sectors, disk->sector));
2975978408cSSascha Wildner 	return default_entry;
2985978408cSSascha Wildner }
2995978408cSSascha Wildner 
3005978408cSSascha Wildner static struct boot_catalog_entry *
cd9660_boot_setup_section_head(char platform)3015978408cSSascha Wildner cd9660_boot_setup_section_head(char platform)
3025978408cSSascha Wildner {
3035978408cSSascha Wildner 	struct boot_catalog_entry *entry;
3045978408cSSascha Wildner 	boot_catalog_section_header *sh;
3055978408cSSascha Wildner 
3065978408cSSascha Wildner 	entry = cd9660_init_boot_catalog_entry();
3075978408cSSascha Wildner 	if (entry == NULL)
3085978408cSSascha Wildner 		return NULL;
3095978408cSSascha Wildner 
3105978408cSSascha Wildner 	entry->entry_type = ET_ENTRY_SH;
3115978408cSSascha Wildner 	sh = &entry->entry_data.SH;
3125978408cSSascha Wildner 	/*
3135978408cSSascha Wildner 	 * More by default.
3145978408cSSascha Wildner 	 * The last one will manually be set to ET_SECTION_HEADER_LAST
3155978408cSSascha Wildner 	 */
3165978408cSSascha Wildner 	sh->header_indicator[0] = ET_SECTION_HEADER_MORE;
3175978408cSSascha Wildner 	sh->platform_id[0] = platform;
3185978408cSSascha Wildner 	sh->num_section_entries[0] = 0;
3195978408cSSascha Wildner 	return entry;
3205978408cSSascha Wildner }
3215978408cSSascha Wildner 
3225978408cSSascha Wildner static struct boot_catalog_entry *
cd9660_boot_setup_section_entry(struct cd9660_boot_image * disk)3235978408cSSascha Wildner cd9660_boot_setup_section_entry(struct cd9660_boot_image *disk)
3245978408cSSascha Wildner {
3255978408cSSascha Wildner 	struct boot_catalog_entry *entry;
3265978408cSSascha Wildner 	boot_catalog_section_entry *se;
3275978408cSSascha Wildner 	if ((entry = cd9660_init_boot_catalog_entry()) == NULL)
3285978408cSSascha Wildner 		return NULL;
3295978408cSSascha Wildner 
3305978408cSSascha Wildner 	entry->entry_type = ET_ENTRY_SE;
3315978408cSSascha Wildner 	se = &entry->entry_data.SE;
3325978408cSSascha Wildner 
3335978408cSSascha Wildner 	se->boot_indicator[0] = ET_BOOTABLE;
3345978408cSSascha Wildner 	se->media_type[0] = disk->targetMode;
3355978408cSSascha Wildner 	cd9660_721(disk->loadSegment, se->load_segment);
3365978408cSSascha Wildner 	cd9660_721(disk->num_sectors, se->sector_count);
3375978408cSSascha Wildner 	cd9660_731(disk->sector, se->load_rba);
3385978408cSSascha Wildner 	return entry;
3395978408cSSascha Wildner }
3405978408cSSascha Wildner 
3415978408cSSascha Wildner #if 0
3425978408cSSascha Wildner static u_char
3435978408cSSascha Wildner cd9660_boot_get_system_type(struct cd9660_boot_image *disk)
3445978408cSSascha Wildner {
3455978408cSSascha Wildner 	/*
3465978408cSSascha Wildner 		For hard drive booting, we need to examine the MBR to figure
3475978408cSSascha Wildner 		out what the partition type is
3485978408cSSascha Wildner 	*/
3495978408cSSascha Wildner 	return 0;
3505978408cSSascha Wildner }
3515978408cSSascha Wildner #endif
3525978408cSSascha Wildner 
3535978408cSSascha Wildner /*
3545978408cSSascha Wildner  * Set up the BVD, Boot catalog, and the boot entries, but do no writing
3555978408cSSascha Wildner  */
3565978408cSSascha Wildner int
cd9660_setup_boot(iso9660_disk * diskStructure,int first_sector)3575978408cSSascha Wildner cd9660_setup_boot(iso9660_disk *diskStructure, int first_sector)
3585978408cSSascha Wildner {
3595978408cSSascha Wildner 	int sector;
3605978408cSSascha Wildner 	int used_sectors;
3615978408cSSascha Wildner 	int num_entries = 0;
3625978408cSSascha Wildner 	int catalog_sectors;
3635978408cSSascha Wildner 	struct boot_catalog_entry *x86_head, *mac_head, *ppc_head, *efi_head,
3645978408cSSascha Wildner 		*valid_entry, *default_entry, *temp, *head, **headp, *next;
3655978408cSSascha Wildner 	struct cd9660_boot_image *tmp_disk;
3665978408cSSascha Wildner 
3675978408cSSascha Wildner 	headp = NULL;
3685978408cSSascha Wildner 	x86_head = mac_head = ppc_head = efi_head = NULL;
3695978408cSSascha Wildner 
3705978408cSSascha Wildner 	/* If there are no boot disks, don't bother building boot information */
3715978408cSSascha Wildner 	if (TAILQ_EMPTY(&diskStructure->boot_images))
3725978408cSSascha Wildner 		return 0;
3735978408cSSascha Wildner 
3745978408cSSascha Wildner 	/* Point to catalog: For now assume it consumes one sector */
3755978408cSSascha Wildner 	ELTORITO_DPRINTF(("Boot catalog will go in sector %d\n", first_sector));
3765978408cSSascha Wildner 	diskStructure->boot_catalog_sector = first_sector;
3775978408cSSascha Wildner 	cd9660_bothendian_dword(first_sector,
3785978408cSSascha Wildner 		diskStructure->boot_descriptor->boot_catalog_pointer);
3795978408cSSascha Wildner 
3805978408cSSascha Wildner 	/* Step 1: Generate boot catalog */
3815978408cSSascha Wildner 	/* Step 1a: Validation entry */
3825978408cSSascha Wildner 	valid_entry = cd9660_boot_setup_validation_entry(ET_SYS_X86);
3835978408cSSascha Wildner 	if (valid_entry == NULL)
3845978408cSSascha Wildner 		return -1;
3855978408cSSascha Wildner 
3865978408cSSascha Wildner 	/*
3875978408cSSascha Wildner 	 * Count how many boot images there are,
3885978408cSSascha Wildner 	 * and how many sectors they consume.
3895978408cSSascha Wildner 	 */
3905978408cSSascha Wildner 	num_entries = 1;
3915978408cSSascha Wildner 	used_sectors = 0;
3925978408cSSascha Wildner 
3935978408cSSascha Wildner 	TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) {
3945978408cSSascha Wildner 		used_sectors += tmp_disk->num_sectors;
3955978408cSSascha Wildner 
3965978408cSSascha Wildner 		/* One default entry per image */
3975978408cSSascha Wildner 		num_entries++;
3985978408cSSascha Wildner 	}
3995978408cSSascha Wildner 	catalog_sectors = howmany(num_entries * 0x20, diskStructure->sectorSize);
4005978408cSSascha Wildner 	used_sectors += catalog_sectors;
4015978408cSSascha Wildner 
4025978408cSSascha Wildner 	if (diskStructure->verbose_level > 0) {
4035978408cSSascha Wildner 		printf("%s: there will be %i entries consuming %i sectors. "
4045978408cSSascha Wildner 		       "Catalog is %i sectors\n", __func__, num_entries,
4055978408cSSascha Wildner 		       used_sectors, catalog_sectors);
4065978408cSSascha Wildner 	}
4075978408cSSascha Wildner 
4085978408cSSascha Wildner 	/* Populate sector numbers */
4095978408cSSascha Wildner 	sector = first_sector + catalog_sectors;
4105978408cSSascha Wildner 	TAILQ_FOREACH(tmp_disk, &diskStructure->boot_images, image_list) {
4115978408cSSascha Wildner 		tmp_disk->sector = sector;
4125978408cSSascha Wildner 		sector += tmp_disk->num_sectors /
4135978408cSSascha Wildner 		    (diskStructure->sectorSize / 512);
4145978408cSSascha Wildner 	}
4155978408cSSascha Wildner 
4165978408cSSascha Wildner 	LIST_INSERT_HEAD(&diskStructure->boot_entries, valid_entry, ll_struct);
4175978408cSSascha Wildner 
4185978408cSSascha Wildner 	/* Step 1b: Initial/default entry */
4195978408cSSascha Wildner 	/* TODO : PARAM */
4205978408cSSascha Wildner 	if (default_boot_image != NULL) {
4215978408cSSascha Wildner 		struct cd9660_boot_image *tcbi;
4225978408cSSascha Wildner 		TAILQ_FOREACH(tcbi, &diskStructure->boot_images, image_list) {
4235978408cSSascha Wildner 			if (tcbi == default_boot_image) {
4245978408cSSascha Wildner 				tmp_disk = tcbi;
4255978408cSSascha Wildner 				break;
4265978408cSSascha Wildner 			}
4275978408cSSascha Wildner 		}
4285978408cSSascha Wildner 	}
4295978408cSSascha Wildner 	if (tmp_disk == NULL)
4305978408cSSascha Wildner 		tmp_disk = TAILQ_FIRST(&diskStructure->boot_images);
4315978408cSSascha Wildner 	default_entry = cd9660_boot_setup_default_entry(tmp_disk);
4325978408cSSascha Wildner 	if (default_entry == NULL) {
4335978408cSSascha Wildner 		warnx("Error: memory allocation failed in cd9660_setup_boot");
4345978408cSSascha Wildner 		return -1;
4355978408cSSascha Wildner 	}
4365978408cSSascha Wildner 
4375978408cSSascha Wildner 	LIST_INSERT_AFTER(valid_entry, default_entry, ll_struct);
4385978408cSSascha Wildner 
4395978408cSSascha Wildner 	/* Todo: multiple default entries? */
4405978408cSSascha Wildner 
4415978408cSSascha Wildner 	tmp_disk = TAILQ_FIRST(&diskStructure->boot_images);
4425978408cSSascha Wildner 
4435978408cSSascha Wildner 	head = NULL;
4445978408cSSascha Wildner 	temp = default_entry;
4455978408cSSascha Wildner 
4465978408cSSascha Wildner 	/* If multiple boot images are given : */
4475978408cSSascha Wildner 	for (; tmp_disk != NULL; tmp_disk = TAILQ_NEXT(tmp_disk, image_list)) {
4485978408cSSascha Wildner 		if (tmp_disk == default_boot_image)
4495978408cSSascha Wildner 			continue;
4505978408cSSascha Wildner 
4515978408cSSascha Wildner 		/* Step 2: Section header */
4525978408cSSascha Wildner 		switch (tmp_disk->platform_id) {
4535978408cSSascha Wildner 		case ET_SYS_X86:
4545978408cSSascha Wildner 			headp = &x86_head;
4555978408cSSascha Wildner 			break;
4565978408cSSascha Wildner 		case ET_SYS_PPC:
4575978408cSSascha Wildner 			headp = &ppc_head;
4585978408cSSascha Wildner 			break;
4595978408cSSascha Wildner 		case ET_SYS_MAC:
4605978408cSSascha Wildner 			headp = &mac_head;
4615978408cSSascha Wildner 			break;
4625978408cSSascha Wildner 		case ET_SYS_EFI:
4635978408cSSascha Wildner 			headp = &efi_head;
4645978408cSSascha Wildner 			break;
4655978408cSSascha Wildner 		default:
4665978408cSSascha Wildner 			warnx("%s: internal error: unknown system type",
4675978408cSSascha Wildner 			    __func__);
4685978408cSSascha Wildner 			return -1;
4695978408cSSascha Wildner 		}
4705978408cSSascha Wildner 
4715978408cSSascha Wildner 		if (*headp == NULL) {
4725978408cSSascha Wildner 			head =
4735978408cSSascha Wildner 			  cd9660_boot_setup_section_head(tmp_disk->platform_id);
4745978408cSSascha Wildner 			if (head == NULL) {
4755978408cSSascha Wildner 				warnx("Error: memory allocation failed in "
4765978408cSSascha Wildner 				      "cd9660_setup_boot");
4775978408cSSascha Wildner 				return -1;
4785978408cSSascha Wildner 			}
4795978408cSSascha Wildner 			LIST_INSERT_AFTER(default_entry, head, ll_struct);
4805978408cSSascha Wildner 			*headp = head;
4815978408cSSascha Wildner 		} else
4825978408cSSascha Wildner 			head = *headp;
4835978408cSSascha Wildner 
4845978408cSSascha Wildner 		head->entry_data.SH.num_section_entries[0]++;
4855978408cSSascha Wildner 
4865978408cSSascha Wildner 		/* Step 2a: Section entry and extensions */
4875978408cSSascha Wildner 		temp = cd9660_boot_setup_section_entry(tmp_disk);
4885978408cSSascha Wildner 		if (temp == NULL) {
4895978408cSSascha Wildner 			warn("%s: cd9660_boot_setup_section_entry", __func__);
4905978408cSSascha Wildner 			return -1;
4915978408cSSascha Wildner 		}
4925978408cSSascha Wildner 
4935978408cSSascha Wildner 		while ((next = LIST_NEXT(head, ll_struct)) != NULL &&
4945978408cSSascha Wildner 		       next->entry_type == ET_ENTRY_SE)
4955978408cSSascha Wildner 			head = next;
4965978408cSSascha Wildner 
4975978408cSSascha Wildner 		LIST_INSERT_AFTER(head, temp, ll_struct);
4985978408cSSascha Wildner 	}
4995978408cSSascha Wildner 
5005978408cSSascha Wildner 	/* Find the last Section Header entry and mark it as the last. */
5015978408cSSascha Wildner 	head = NULL;
5025978408cSSascha Wildner 	LIST_FOREACH(next, &diskStructure->boot_entries, ll_struct) {
5035978408cSSascha Wildner 		if (next->entry_type == ET_ENTRY_SH)
5045978408cSSascha Wildner 			head = next;
5055978408cSSascha Wildner 	}
5065978408cSSascha Wildner 	if (head != NULL)
5075978408cSSascha Wildner 		head->entry_data.SH.header_indicator[0] = ET_SECTION_HEADER_LAST;
5085978408cSSascha Wildner 
5095978408cSSascha Wildner 	/* TODO: Remaining boot disks when implemented */
5105978408cSSascha Wildner 
5115978408cSSascha Wildner 	return first_sector + used_sectors;
5125978408cSSascha Wildner }
5135978408cSSascha Wildner 
5145978408cSSascha Wildner int
cd9660_setup_boot_volume_descriptor(iso9660_disk * diskStructure,volume_descriptor * bvd)5155978408cSSascha Wildner cd9660_setup_boot_volume_descriptor(iso9660_disk *diskStructure,
5165978408cSSascha Wildner     volume_descriptor *bvd)
5175978408cSSascha Wildner {
5185978408cSSascha Wildner 	boot_volume_descriptor *bvdData =
5195978408cSSascha Wildner 	    (boot_volume_descriptor*)bvd->volumeDescriptorData;
5205978408cSSascha Wildner 
5215978408cSSascha Wildner 	bvdData->boot_record_indicator[0] = ISO_VOLUME_DESCRIPTOR_BOOT;
5225978408cSSascha Wildner 	memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
5235978408cSSascha Wildner 	bvdData->version[0] = 1;
5245978408cSSascha Wildner 	memcpy(bvdData->boot_system_identifier, ET_ID, 23);
5255978408cSSascha Wildner 	memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
5265978408cSSascha Wildner 	diskStructure->boot_descriptor =
5275978408cSSascha Wildner 	    (boot_volume_descriptor*) bvd->volumeDescriptorData;
5285978408cSSascha Wildner 	return 1;
5295978408cSSascha Wildner }
5305978408cSSascha Wildner 
5315978408cSSascha Wildner static int
cd9660_write_mbr_partition_entry(FILE * fd,int idx,off_t sector_start,off_t nsectors,int type)5325978408cSSascha Wildner cd9660_write_mbr_partition_entry(FILE *fd, int idx, off_t sector_start,
5335978408cSSascha Wildner     off_t nsectors, int type)
5345978408cSSascha Wildner {
5355978408cSSascha Wildner 	uint8_t val;
5365978408cSSascha Wildner 	uint32_t lba;
5375978408cSSascha Wildner 
5385978408cSSascha Wildner 	if (fseeko(fd, (off_t)(idx) * 16 + 0x1be, SEEK_SET) == -1)
5395978408cSSascha Wildner 		err(1, "fseeko");
5405978408cSSascha Wildner 
5415978408cSSascha Wildner 	val = 0x80; /* Bootable */
5425978408cSSascha Wildner 	fwrite(&val, sizeof(val), 1, fd);
5435978408cSSascha Wildner 
5445978408cSSascha Wildner 	val = 0xff; /* CHS begin */
5455978408cSSascha Wildner 	fwrite(&val, sizeof(val), 1, fd);
5465978408cSSascha Wildner 	fwrite(&val, sizeof(val), 1, fd);
5475978408cSSascha Wildner 	fwrite(&val, sizeof(val), 1, fd);
5485978408cSSascha Wildner 
5495978408cSSascha Wildner 	val = type; /* Part type */
5505978408cSSascha Wildner 	fwrite(&val, sizeof(val), 1, fd);
5515978408cSSascha Wildner 
5525978408cSSascha Wildner 	val = 0xff; /* CHS end */
5535978408cSSascha Wildner 	fwrite(&val, sizeof(val), 1, fd);
5545978408cSSascha Wildner 	fwrite(&val, sizeof(val), 1, fd);
5555978408cSSascha Wildner 	fwrite(&val, sizeof(val), 1, fd);
5565978408cSSascha Wildner 
5575978408cSSascha Wildner 	/* LBA extent */
5585978408cSSascha Wildner 	lba = htole32(sector_start);
5595978408cSSascha Wildner 	fwrite(&lba, sizeof(lba), 1, fd);
5605978408cSSascha Wildner 	lba = htole32(nsectors);
5615978408cSSascha Wildner 	fwrite(&lba, sizeof(lba), 1, fd);
5625978408cSSascha Wildner 
5635978408cSSascha Wildner 	return 0;
5645978408cSSascha Wildner }
5655978408cSSascha Wildner 
5665978408cSSascha Wildner 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)5675978408cSSascha Wildner cd9660_write_apm_partition_entry(FILE *fd, int idx, int total_partitions,
5685978408cSSascha Wildner     off_t sector_start, off_t nsectors, off_t sector_size,
5695978408cSSascha Wildner     const char *part_name, const char *part_type)
5705978408cSSascha Wildner {
5715978408cSSascha Wildner 	uint32_t apm32, part_status;
5725978408cSSascha Wildner 	uint16_t apm16;
5735978408cSSascha Wildner 
5745978408cSSascha Wildner 	/* See Apple Tech Note 1189 for the details about the pmPartStatus
5755978408cSSascha Wildner 	 * flags.
5765978408cSSascha Wildner 	 * Below the flags which are default:
5775978408cSSascha Wildner 	 * - IsValid     0x01
5785978408cSSascha Wildner 	 * - IsAllocated 0x02
5795978408cSSascha Wildner 	 * - IsReadable  0x10
5805978408cSSascha Wildner 	 * - IsWritable  0x20
5815978408cSSascha Wildner 	 */
5825978408cSSascha Wildner 	part_status = 0x01 | 0x02 | 0x10 | 0x20;
5835978408cSSascha Wildner 
5845978408cSSascha Wildner 	if (fseeko(fd, (off_t)(idx + 1) * sector_size, SEEK_SET) == -1)
5855978408cSSascha Wildner 		err(1, "fseeko");
5865978408cSSascha Wildner 
5875978408cSSascha Wildner 	/* Signature */
5885978408cSSascha Wildner 	apm16 = htobe16(0x504d);
5895978408cSSascha Wildner 	fwrite(&apm16, sizeof(apm16), 1, fd);
5905978408cSSascha Wildner 	apm16 = 0;
5915978408cSSascha Wildner 	fwrite(&apm16, sizeof(apm16), 1, fd);
5925978408cSSascha Wildner 
5935978408cSSascha Wildner 	/* Total number of partitions */
5945978408cSSascha Wildner 	apm32 = htobe32(total_partitions);
5955978408cSSascha Wildner 	fwrite(&apm32, sizeof(apm32), 1, fd);
5965978408cSSascha Wildner 	/* Bounds */
5975978408cSSascha Wildner 	apm32 = htobe32(sector_start);
5985978408cSSascha Wildner 	fwrite(&apm32, sizeof(apm32), 1, fd);
5995978408cSSascha Wildner 	apm32 = htobe32(nsectors);
6005978408cSSascha Wildner 	fwrite(&apm32, sizeof(apm32), 1, fd);
6015978408cSSascha Wildner 
6025978408cSSascha Wildner 	fwrite(part_name, strlen(part_name) + 1, 1, fd);
6035978408cSSascha Wildner 	fseek(fd, 32 - strlen(part_name) - 1, SEEK_CUR);
6045978408cSSascha Wildner 	fwrite(part_type, strlen(part_type) + 1, 1, fd);
6055978408cSSascha Wildner 	fseek(fd, 32 - strlen(part_type) - 1, SEEK_CUR);
6065978408cSSascha Wildner 
6075978408cSSascha Wildner 	apm32 = 0;
6085978408cSSascha Wildner 	/* pmLgDataStart */
6095978408cSSascha Wildner 	fwrite(&apm32, sizeof(apm32), 1, fd);
6105978408cSSascha Wildner 	/* pmDataCnt */
6115978408cSSascha Wildner 	apm32 = htobe32(nsectors);
6125978408cSSascha Wildner 	fwrite(&apm32, sizeof(apm32), 1, fd);
6135978408cSSascha Wildner 	/* pmPartStatus */
6145978408cSSascha Wildner 	apm32 = htobe32(part_status);
6155978408cSSascha Wildner 	fwrite(&apm32, sizeof(apm32), 1, fd);
6165978408cSSascha Wildner 
6175978408cSSascha Wildner 	return 0;
6185978408cSSascha Wildner }
6195978408cSSascha Wildner 
6205978408cSSascha Wildner int
cd9660_write_boot(iso9660_disk * diskStructure,FILE * fd)6215978408cSSascha Wildner cd9660_write_boot(iso9660_disk *diskStructure, FILE *fd)
6225978408cSSascha Wildner {
6235978408cSSascha Wildner 	struct boot_catalog_entry *e;
6245978408cSSascha Wildner 	struct cd9660_boot_image *t;
6255978408cSSascha Wildner 	int apm_partitions = 0;
6265978408cSSascha Wildner 	int mbr_partitions = 0;
6275978408cSSascha Wildner 
6285978408cSSascha Wildner 	/* write boot catalog */
6295978408cSSascha Wildner 	if (fseeko(fd, (off_t)diskStructure->boot_catalog_sector *
6305978408cSSascha Wildner 	    diskStructure->sectorSize, SEEK_SET) == -1)
6315978408cSSascha Wildner 		err(1, "fseeko");
6325978408cSSascha Wildner 
6335978408cSSascha Wildner 	if (diskStructure->verbose_level > 0) {
6345978408cSSascha Wildner 		printf("Writing boot catalog to sector %" PRId64 "\n",
6355978408cSSascha Wildner 		    diskStructure->boot_catalog_sector);
6365978408cSSascha Wildner 	}
6375978408cSSascha Wildner 	LIST_FOREACH(e, &diskStructure->boot_entries, ll_struct) {
6385978408cSSascha Wildner 		if (diskStructure->verbose_level > 0) {
6395978408cSSascha Wildner 			printf("Writing catalog entry of type %d\n",
6405978408cSSascha Wildner 			    e->entry_type);
6415978408cSSascha Wildner 		}
6425978408cSSascha Wildner 		/*
6435978408cSSascha Wildner 		 * It doesn't matter which one gets written
6445978408cSSascha Wildner 		 * since they are the same size
6455978408cSSascha Wildner 		 */
6465978408cSSascha Wildner 		fwrite(&(e->entry_data.VE), 1, 32, fd);
6475978408cSSascha Wildner 	}
6485978408cSSascha Wildner 	if (diskStructure->verbose_level > 0)
6495978408cSSascha Wildner 		printf("Finished writing boot catalog\n");
6505978408cSSascha Wildner 
6515978408cSSascha Wildner 	/* copy boot images */
6525978408cSSascha Wildner 	TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
6535978408cSSascha Wildner 		if (diskStructure->verbose_level > 0) {
6545978408cSSascha Wildner 			printf("Writing boot image from %s to sectors %d\n",
6555978408cSSascha Wildner 			    t->filename, t->sector);
6565978408cSSascha Wildner 		}
6575978408cSSascha Wildner 		cd9660_copy_file(diskStructure, fd, t->sector, t->filename);
6585978408cSSascha Wildner 
6595978408cSSascha Wildner 		if (t->system == ET_SYS_MAC)
6605978408cSSascha Wildner 			apm_partitions++;
6615978408cSSascha Wildner 		if (t->system == ET_SYS_PPC)
6625978408cSSascha Wildner 			mbr_partitions++;
6635978408cSSascha Wildner 	}
6645978408cSSascha Wildner 
6655978408cSSascha Wildner 	/* some systems need partition tables as well */
6665978408cSSascha Wildner 	if (mbr_partitions > 0 || diskStructure->chrp_boot) {
6675978408cSSascha Wildner 		uint16_t sig;
6685978408cSSascha Wildner 
6695978408cSSascha Wildner 		fseek(fd, 0x1fe, SEEK_SET);
6705978408cSSascha Wildner 		sig = htole16(0xaa55);
6715978408cSSascha Wildner 		fwrite(&sig, sizeof(sig), 1, fd);
6725978408cSSascha Wildner 
6735978408cSSascha Wildner 		mbr_partitions = 0;
6745978408cSSascha Wildner 
6755978408cSSascha Wildner 		/* Write ISO9660 descriptor, enclosing the whole disk */
6765978408cSSascha Wildner 		if (diskStructure->chrp_boot)
6775978408cSSascha Wildner 			cd9660_write_mbr_partition_entry(fd, mbr_partitions++,
6785978408cSSascha Wildner 			    0, diskStructure->totalSectors *
6795978408cSSascha Wildner 			    (diskStructure->sectorSize / 512), 0x96);
6805978408cSSascha Wildner 
6815978408cSSascha Wildner 		/* Write all partition entries */
6825978408cSSascha Wildner 		TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
6835978408cSSascha Wildner 			if (t->system != ET_SYS_PPC)
6845978408cSSascha Wildner 				continue;
6855978408cSSascha Wildner 			cd9660_write_mbr_partition_entry(fd, mbr_partitions++,
6865978408cSSascha Wildner 			    t->sector * (diskStructure->sectorSize / 512),
6875978408cSSascha Wildner 			    t->num_sectors * (diskStructure->sectorSize / 512),
6885978408cSSascha Wildner 			    0x41 /* PReP Boot */);
6895978408cSSascha Wildner 		}
6905978408cSSascha Wildner 	}
6915978408cSSascha Wildner 
6925978408cSSascha Wildner 	if (apm_partitions > 0) {
6935978408cSSascha Wildner 		/* Write DDR and global APM info */
6945978408cSSascha Wildner 		uint32_t apm32;
6955978408cSSascha Wildner 		uint16_t apm16;
6965978408cSSascha Wildner 		int total_parts;
6975978408cSSascha Wildner 
6985978408cSSascha Wildner 		fseek(fd, 0, SEEK_SET);
6995978408cSSascha Wildner 		apm16 = htobe16(0x4552);
7005978408cSSascha Wildner 		fwrite(&apm16, sizeof(apm16), 1, fd);
7015978408cSSascha Wildner 		/* Device block size */
7025978408cSSascha Wildner 		apm16 = htobe16(512);
7035978408cSSascha Wildner 		fwrite(&apm16, sizeof(apm16), 1, fd);
7045978408cSSascha Wildner 		/* Device block count */
7055978408cSSascha Wildner 		apm32 = htobe32(diskStructure->totalSectors *
7065978408cSSascha Wildner 		    (diskStructure->sectorSize / 512));
7075978408cSSascha Wildner 		fwrite(&apm32, sizeof(apm32), 1, fd);
7085978408cSSascha Wildner 		/* Device type/id */
7095978408cSSascha Wildner 		apm16 = htobe16(1);
7105978408cSSascha Wildner 		fwrite(&apm16, sizeof(apm16), 1, fd);
7115978408cSSascha Wildner 		fwrite(&apm16, sizeof(apm16), 1, fd);
7125978408cSSascha Wildner 
7135978408cSSascha Wildner 		/* Count total needed entries */
7145978408cSSascha Wildner 		total_parts = 2 + apm_partitions; /* Self + ISO9660 */
7155978408cSSascha Wildner 
7165978408cSSascha Wildner 		/* Write self-descriptor */
7175978408cSSascha Wildner 		cd9660_write_apm_partition_entry(fd, 0, total_parts, 1,
7185978408cSSascha Wildner 		    total_parts, 512, "Apple", "Apple_partition_map");
7195978408cSSascha Wildner 
7205978408cSSascha Wildner 		/* Write all partition entries */
7215978408cSSascha Wildner 		apm_partitions = 0;
7225978408cSSascha Wildner 		TAILQ_FOREACH(t, &diskStructure->boot_images, image_list) {
7235978408cSSascha Wildner 			if (t->system != ET_SYS_MAC)
7245978408cSSascha Wildner 				continue;
7255978408cSSascha Wildner 
7265978408cSSascha Wildner 			cd9660_write_apm_partition_entry(fd,
7275978408cSSascha Wildner 			    1 + apm_partitions++, total_parts,
7285978408cSSascha Wildner 			    t->sector * (diskStructure->sectorSize / 512),
7295978408cSSascha Wildner 			    t->num_sectors * (diskStructure->sectorSize / 512),
7305978408cSSascha Wildner 			    512, "CD Boot", "Apple_Bootstrap");
7315978408cSSascha Wildner 		}
7325978408cSSascha Wildner 
7335978408cSSascha Wildner 		/* Write ISO9660 descriptor, enclosing the whole disk */
7345978408cSSascha Wildner 		cd9660_write_apm_partition_entry(fd, 2 + apm_partitions,
7355978408cSSascha Wildner 		    total_parts, 0, diskStructure->totalSectors *
7365978408cSSascha Wildner 		    (diskStructure->sectorSize / 512), 512, "ISO9660",
7375978408cSSascha Wildner 		    "CD_ROM_Mode_1");
7385978408cSSascha Wildner 	}
7395978408cSSascha Wildner 
7405978408cSSascha Wildner 	return 0;
7415978408cSSascha Wildner }
742