Subject: toolchain/30245: macppccd.iso build fixes for OF2 machines
To: None <toolchain-manager@netbsd.org, gnats-admin@netbsd.org,>
From: None <tsutsui@ceres.dti.ne.jp>
List: netbsd-bugs
Date: 05/16/2005 15:24:00
>Number:         30245
>Category:       toolchain
>Synopsis:       macppccd.iso build fixes for OF2 machines
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    toolchain-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon May 16 15:24:00 +0000 2005
>Originator:     Izumi Tsutsui
>Release:        NetBSD 2.0, but not changed in -current
>Organization:
>Environment:
Creating CD-ROM images tested on:
System: NetBSD mirage 3.99.3 
Architecture: i386
Machine: i386
>Description:
macppccd.iso image doesn't boot on Openfirmware 2.0 (and probably 1.0.5)
machines because it uses pre-compiled binary which includes old bootxx.
It causes version mismatch against newer ofwboot whose load address
has been changed from 0x600000 to 0xe00000, as mentioned in the
following post:
http://mail-index.netbsd.org/port-macppc/2004/12/14/0020.html

Furthermore, there is no sources of pre-compiled
distrib/cdrom/macppc_installboot/bootxx.raw.uue binary,
and distrib/cdrom/Makefile contains an awful magic number
around line 409:
---
.if !empty(BASE_PORTS.${image}:Mmacppc)
	@blknum=$$((`ls -l $@ | awk '{print $$5}'` / 512)) && \
	${MACPPC_IBOOTDIR}/macppc_installboot $@ $$blknum 756
	dd if=${EXTFILEDIR}/macppc.ofwboot bs=64k count=1 conv=sync >>$@ 2>/dev/null
.endif
---

>How-To-Repeat:
Boot macppccd.iso in 2.0 on Openfirmware 2.0 machines:
http://mail-index.netbsd.org/port-macppc/2004/12/16/0000.html

>Fix:
Pre-compiled macppcboot.raw in distrib/cdrom/macppc_installboot
contains info about apple partition maps and data in HFS part,
and it is passed to mkisofs as -boot-hfs-file options.
Pre-compiled bootxx.raw binary is embedded into macppcboot.raw
binary by mkmacppcboot program. After mkisofs creates hybrid image
with -boot-hfs-file options, macppc_installboot appends ofwboot
after the image and patches bootxx in the image to specify location
of appended ofwboot. The magic number is used to specify address
to be patched, so we can't change current bootxx binary unless
the method used by current macppc_installboot is changed.

The attached patch includes following fixes:
- Prepare `macppc_mkhfsboot' program to create bootfile for
  -boot-hfs-file option of mkisofs. This is mostly based on the method
  used by -current macppc_installboot/mkmacppcboot.c, but this one
  does not require bootxx binary. It just prepare space for bootxx,
  which will be filled by macppc_installboot later.
- Change macppc_installboot to use a method to search bootxx address
  to be patched with info about secondary boot like MI installboot(8).
  It checks *_BBINFO_MAGIC text in the image rather than using a magic
  number embedded in Makefile directly.
- Change macppc_installboot to read bootxx file and write patched one
  into the image (as mentioned above).
- Also change macppc_installboot to search secondary boot file
  from iso9660 file system in the image rather than appended one
  after the image. These are also the methods used by MI installboot(8).

It may be worth to integrate these features into MI installboot(8),
but it will be done later.
There are some ugly hacks, and there is no Rock Ridge or Joliet extension
support. I'm also afraid it won't compile on non-NetBSD systems.


Index: Makefile
===================================================================
RCS file: /cvsroot/src/distrib/cdrom/Makefile,v
retrieving revision 1.24
diff -u -r1.24 Makefile
--- Makefile	20 Jan 2005 08:05:55 -0000	1.24
+++ Makefile	15 May 2005 17:08:03 -0000
@@ -58,7 +58,7 @@
 SUBDIR=
 
 .if !empty(ALL_PORTS:Mmacppc)
-SUBDIR+=	macppc_installboot
+SUBDIR+=	macppc_mkboothfs macppc_installboot
 .endif
 
 .if !empty(SUBDIR)
@@ -77,6 +77,7 @@
 VAX_IBOOT?=	${TOOL_INSTALLBOOT} -m vax -o sunsum,append
 .if !empty(ALL_PORTS:Mmacppc)
 MACPPC_IBOOTDIR!= cd ${.CURDIR}/macppc_installboot && ${PRINTOBJDIR}
+MACPPC_MKBOOTHFSDIR!= cd ${.CURDIR}/macppc_mkboothfs && ${PRINTOBJDIR}
 .endif
 
 RSYNC_SITE?=	rsync://rsync.NetBSD.org/NetBSD/${RELEASENAME}/
@@ -228,7 +229,7 @@
 .if !empty(ports:Mmacppc)
 MKISOFS_ARGS.${image}+=	-hfs -part -hide-hfs-list ${.CURDIR}/hide-hfs.lst \
 	--macbin -map ${.CURDIR}/hfsmap.lst \
-	-boot-hfs-file ${MACPPC_IBOOTDIR}/macppcboot.raw
+	-boot-hfs-file ${MACPPC_MKBOOTHFSDIR}/boothfs
 .elif defined(USE_APPLE_ISO) || !empty(ports:Mmac68k)
 MKISOFS_ARGS.${image}+=	-apple --macbin -map ${.CURDIR}/hfsmap.lst
 .endif
@@ -358,15 +359,17 @@
 # 1. Size the image produced by mkisofs.
 # 2. Add images added by distrib/common/sunbootcd.sh by rounding to a 320k
 #    boundary and adding each Sun image rounded to a 320k boundary.
-# 3. Add 64k if macppc is included (ofwboot munged to one 64k block).
-# 4. Add bootfile sizes rounded up to 512 bytes for pmax and vax.
-# 5. Round up to a 32k boundary, then add another 32k for TAO padding.
+# 3. Add bootfile sizes rounded up to 512 bytes for pmax and vax.
+# 4. Round up to a 32k boundary, then add another 32k for TAO padding.
 
 .if !empty(BASE_PORTS.${image}:Mmacppc)
-size-${image}: all-macppc_installboot
+size-${image}: all-macppc_mkboothfs all-macppc_installboot
 .endif
 
 size-${image}: stage-${image} extfileprep fileprep-${image}
+.if !empty(BASE_PORTS.${image}:Mmacppc)
+	${MACPPC_MKBOOTHFSDIR}/macppc_mkboothfs ${MACPPC_MKBOOTHFSDIR}/boothfs
+.endif
 	@size=$$((`cd ${STAGEDIR}/${image} && ${MKISOFS} ${MKISOFS_ARGS} ${MKISOFS_ARGS.${image}} -print-size . 2>&1 | tee /dev/stderr | sed '/=/!d;s/^[^=]*=//'` * 2048)) && \
 	if [ "${SUN_BOOT_ARGS.${image}}" != "" ]; then \
 		size=$$(($$(($$size + 327679)) / 327680 * 327680)) && \
@@ -376,9 +379,6 @@
 			size=$$(($$size + $$(($$(($$bfsize + 327679)) / 327680 * 327680)))); \
 		done; \
 	fi && \
-	if [ "${BASE_PORTS.${image}:Mmacppc}" != "" ]; then \
-		size=$$(($$size + 65536)); \
-	fi && \
 	if [ "${BASE_PORTS.${image}:Mpmax}" != "" ]; then \
 		size=$$(($$size + $$(($$((`ls -l ${BOOTFILE.pmax} | awk '{print $$5}'` + 511)) / 512 * 512)))); \
 	fi && \
@@ -405,9 +405,8 @@
 	    ${.TARGET} ${SUN_BOOT_ARGS.${image}}
 .endif
 .if !empty(BASE_PORTS.${image}:Mmacppc)
-	@blknum=$$((`ls -l $@ | awk '{print $$5}'` / 512)) && \
-	${MACPPC_IBOOTDIR}/macppc_installboot $@ $$blknum 756
-	dd if=${EXTFILEDIR}/macppc.ofwboot bs=64k count=1 conv=sync >>$@ 2>/dev/null
+	${MACPPC_IBOOTDIR}/macppc_installboot \
+	    $@ ${EXTFILEDIR}/macppc.bootxx /ofwboot
 .endif
 .if !empty(BASE_PORTS.${image}:Mpmax)
 	${PMAX_IBOOT} $@ ${BOOTFILE.pmax}
Index: NetBSD-2.0.mk
===================================================================
RCS file: /cvsroot/src/distrib/cdrom/NetBSD-2.0.mk,v
retrieving revision 1.2
diff -u -r1.2 NetBSD-2.0.mk
--- NetBSD-2.0.mk	6 Dec 2004 08:29:25 -0000	1.2
+++ NetBSD-2.0.mk	15 May 2005 17:08:03 -0000
@@ -23,8 +23,10 @@
 INTFILES.amd64=		boot.amd64:amd64/installation/floppy/boot-big.fs,link
 
 # macppc has external bootblock generation tool
-EXTFILES.macppc=	macppc.ofwboot:macppc/binary/sets/base.tgz,./usr/mdec/ofwboot
+EXTFILES.macppc=	macppc.bootxx:macppc/binary/sets/base.tgz,./usr/mdec/bootxx \
+			macppc.ofwboot:macppc/binary/sets/base.tgz,./usr/mdec/ofwboot
 INTFILES.macppc=	ofwboot.xcf:macppc/installation/ofwboot.xcf,link \
+			ofwboot:macppc/binary/sets/base.tgz,./usr/mdec/ofwboot \
 			netbsd.macppc:macppc/binary/kernel/netbsd-INSTALL.gz,link
 
 # BOOTFILE.pmax is absolute
Index: NetBSD-current.mk
===================================================================
RCS file: /cvsroot/src/distrib/cdrom/NetBSD-current.mk,v
retrieving revision 1.2
diff -u -r1.2 NetBSD-current.mk
--- NetBSD-current.mk	6 Dec 2004 20:05:10 -0000	1.2
+++ NetBSD-current.mk	15 May 2005 17:08:03 -0000
@@ -23,8 +23,10 @@
 INTFILES.amd64=		boot.amd64:amd64/installation/floppy/boot-big.fs,link
 
 # macppc has external bootblock generation tool
-EXTFILES.macppc=	macppc.ofwboot:macppc/binary/sets/base.tgz,./usr/mdec/ofwboot
+EXTFILES.macppc=	macppc.bootxx:macppc/binary/sets/base.tgz,./usr/mdec/bootxx \
+			macppc.ofwboot:macppc/binary/sets/base.tgz,./usr/mdec/ofwboot
 INTFILES.macppc=	ofwboot.xcf:macppc/installation/ofwboot.xcf,link \
+			ofwboot:macppc/binary/sets/base.tgz,./usr/mdec/ofwboot \
 			netbsd.macppc:macppc/binary/kernel/netbsd-INSTALL.gz,link
 
 # BOOTFILE.pmax is absolute
Index: macppc_installboot/Makefile
===================================================================
RCS file: /cvsroot/src/distrib/cdrom/macppc_installboot/Makefile,v
retrieving revision 1.5
diff -u -r1.5 Makefile
--- macppc_installboot/Makefile	19 Mar 2004 08:07:28 -0000	1.5
+++ macppc_installboot/Makefile	15 May 2005 17:08:03 -0000
@@ -1,23 +1,10 @@
-#	$NetBSD: Makefile,v 1.5 2004/03/19 08:07:28 jmc Exp $
+#	$NetBSD$
 
+HOSTPROG=	macppc_installboot
+SRCS=		installboot.c cd9660.c cd9660_util.c
 NOMAN=	# defined
 
-.include <bsd.own.mk>
+HOST_CPPFLAGS+=	-I${.CURDIR} -I${NETBSDSRCDIR}/sys
+#HOST_CPPFLAGS+=	-DDEBUG
 
-HOSTPROG=		macppc_installboot
-HOST_CPPFLAGS+=	-I${NETBSDSRCDIR}/sys/arch
-UUDECODE_FILES=	bootxx.raw macppcboot.raw
-
-CLEANFILES+=	mkmacppcboot
-
-all: macppcboot.raw
-
-.include <bsd.files.mk>
 .include <bsd.hostprog.mk>
-
-mkmacppcboot: mkmacppcboot.c
-	${LINK.c} -o ${.TARGET} ${.ALLSRC}
-
-regen: mkmacppcboot bootxx.raw.uue
-	./mkmacppcboot <${.CURDIR}/bootxx.raw | \
-	    uuencode macppcboot.raw > macppcboot.raw.uue
--- /dev/null	2005-05-16 01:55:08.000000000 +0900
+++ macppc_installboot/cd9660.c	2005-05-16 01:53:06.000000000 +0900
@@ -0,0 +1,236 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (C) 2005 Izumi Tsutsui
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if defined(__RCSID) && !defined(__lint)
+__RCSID("$NetBSD$");
+#endif	/* !__lint */
+
+#include <sys/param.h>
+#include <sys/dirent.h>
+
+#if !HAVE_NBTOOL_CONFIG_H
+#include <sys/mount.h>
+#endif
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <fs/cd9660/iso.h>
+
+#include "installboot.h"
+
+#define roundup(x, y)	((((x)+((y)-1))/(y))*(y))
+#define MAXLEN		16
+
+
+int
+cd9660_match(ib_params *params)
+{
+	int rv, blocksize;
+	struct iso_primary_descriptor ipd;
+
+	assert(params != NULL);
+	assert(params->fstype != NULL);
+	assert(params->fsfd != -1);
+
+	rv = pread(params->fsfd, &ipd, sizeof(ipd),
+	    ISO_DEFAULT_BLOCK_SIZE * 16);
+	if (rv == -1) {
+		warn("Reading primary descriptor in `%s'", params->filesystem);
+		return 0;
+	} else if (rv != sizeof(ipd)) {
+		warnx("Reading primary descriptor in `%s': short read",
+		   params->filesystem);
+		return 0;
+	}
+
+	if (ipd.type[0] != ISO_VD_PRIMARY ||
+	    strncmp(ipd.id, ISO_STANDARD_ID, sizeof(ipd.id)) != 0 ||
+	    ipd.version[0] != 1) {
+		warnx("Filesystem `%s' is not ISO9660 format",
+		   params->filesystem);
+		return 0;
+	}
+
+	blocksize = isonum_723((char *)ipd.logical_block_size);
+	if (blocksize != ISO_DEFAULT_BLOCK_SIZE) {
+		warnx("Invalid blocksize %d in `%s'",
+		    blocksize, params->filesystem);
+		return 0;
+	}
+
+	params->fstype->blocksize = blocksize;
+	params->fstype->needswap = 0;
+
+	return 1;
+}
+
+int
+cd9660_findstage2(ib_params *params, uint32_t *maxblk, ib_block *blocks)
+{
+	uint8_t buf[ISO_DEFAULT_BLOCK_SIZE];
+	char name[MAXNAMLEN];
+	char *ofwboot;
+	off_t loc;
+	int rv, blocksize, found, i;
+	struct iso_primary_descriptor ipd;
+	struct iso_directory_record *idr;
+
+	assert(params != NULL);
+	assert(params->stage2 != NULL);
+	assert(maxblk != NULL);
+	assert(blocks != NULL);
+
+#if 0
+	if (params->flags & IB_STAGE2START)
+		return hardcode_stage2(params, maxblk, blocks);
+#endif
+
+	/* The secondary bootstrap must be clearly in /. */
+	strlcpy(name, params->stage2, MAXNAMLEN);
+	ofwboot = name;
+	if (ofwboot[0] == '/')
+		ofwboot++;
+	if (strchr(ofwboot, '/') != NULL) {
+		warnx("The secondary bootstrap `%s' must be in / "
+		    "on filesystem `%s'", params->stage2, params->filesystem);
+		return 0;
+	}
+	if (strchr(ofwboot, '.') == NULL) {
+		/*
+		 * XXX should fix isofncmp()?
+		 */
+		strlcat(ofwboot, ".", MAXNAMLEN);
+	}
+
+	rv = pread(params->fsfd, &ipd, sizeof(ipd),
+	    ISO_DEFAULT_BLOCK_SIZE * 16);
+	if (rv == -1) {
+		warn("Reading primary descriptor in `%s'", params->filesystem);
+		return 0;
+	} else if (rv != sizeof(ipd)) {
+		warnx("Reading primary descriptor in `%s': short read",
+		   params->filesystem);
+		return 0;
+	}
+	blocksize = isonum_723((char *)ipd.logical_block_size);
+
+	idr = (void *)ipd.root_directory_record;
+	loc = (off_t)isonum_733(idr->extent) * blocksize;
+	rv = pread(params->fsfd, buf, blocksize, loc);
+	if (rv == -1) {
+		warn("Reading root directory record in `%s'",
+		    params->filesystem);
+		return 0;
+	} else if (rv != sizeof(ipd)) {
+		warnx("Reading root directory record in `%s': short read",
+		   params->filesystem);
+		return 0;
+	}
+
+	found = 0;
+	for (i = 0; i < blocksize - sizeof(struct iso_directory_record);
+	    i += (u_char)idr->length[0]) {
+		idr = (void *)&buf[i];
+
+#ifdef DEBUG
+		printf("i = %d, idr->length[0] = %3d\n",
+		    i, (u_char)idr->length[0]);
+#endif
+		/* check end of entries */
+		if (idr->length[0] == 0) {
+#ifdef DEBUG
+		printf("end of entries\n");
+#endif
+			break;
+		}
+
+		if (idr->flags[0] & 2) {
+			/* skip directory entries */
+#ifdef DEBUG
+			printf("skip directory entry\n");
+#endif
+			continue;
+		}
+		if (idr->name_len[0] == 1 &&
+		    (idr->name[0] == 0 || idr->name[0] == 1)) {
+			/* skip "." and ".." */
+#ifdef DEBUG
+			printf("skip dot dot\n");
+#endif
+			continue;
+		}
+#ifdef DEBUG
+		{
+			int j;
+
+			printf("filename:");
+			for (j = 0; j < isonum_711(idr->name_len); j++)
+				printf("%c", idr->name[j]);
+			printf("\n");
+		}
+#endif
+		if (isofncmp(ofwboot, strlen(ofwboot),
+		    idr->name, isonum_711(idr->name_len), 0) == 0) {
+			found = 1;
+			/* ISO filesystem always has contiguous file blocks */
+			blocks[0].block = (int64_t)isonum_733(idr->extent);
+			/* XXX bootxx assumes blocksize is 512 */
+			blocks[0].block *= blocksize / 512;
+			blocks[0].blocksize =
+			    roundup(isonum_733(idr->size), blocksize);
+			*maxblk = 1;
+#ifdef DEBUG
+			printf("block = %ld, blocksize = %ld\n",
+			    (long)blocks[0].block, blocks[0].blocksize);
+#endif
+			break;
+		}
+	}
+
+	if (found = 0) {
+		warnx("Can't find secondary bootstrap `%s' in filesystem `%s'",
+		    params->stage2, params->filesystem);
+		return 0;
+	}
+
+	return 1;
+}
--- /dev/null	2005-05-16 01:55:08.000000000 +0900
+++ macppc_installboot/cd9660_util.c	2005-05-16 01:53:06.000000000 +0900
@@ -0,0 +1,236 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley
+ * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
+ * Support code is derived from software contributed to Berkeley
+ * by Atsushi Murai (amurai@spec.co.jp).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)cd9660_util.c	8.3 (Berkeley) 12/5/94
+ */
+
+/* from NetBSD: cd9660_util.c,v 1.5 2004/12/28 01:12:26 jdolecek Exp */
+
+
+#include <assert.h>
+#include <sys/param.h>
+#include <sys/dirent.h>
+
+#include <fs/cd9660/iso.h>
+#define KASSERT(x)	assert(x)	/* XXX for <fs/unicode.h> */
+#include <fs/unicode.h>
+
+#include "installboot.h"
+
+static int isochar(const u_char *, const u_char *, int, uint16_t *);
+static uint16_t wget(const u_char **, size_t *, int);
+static int wput(u_char *, size_t, uint16_t, int);
+
+int cd9660_utf8_joliet = 1;
+
+/*
+ * Get one character out of an iso filename
+ * Return number of bytes consumed
+ */
+int
+isochar(const u_char *isofn, const u_char *isoend, int joliet_level,
+    uint16_t *c)
+{
+
+	*c = isofn[0];
+	if (joliet_level == 0 || isofn + 1 == isoend) {
+		/* (00) and (01) are one byte in Joliet, too */
+		return 1;
+	}
+
+	if (cd9660_utf8_joliet) {
+		*c = (*c << 8) + isofn[1];
+	} else {
+		/* characters outside ISO-8859-1 subset replaced with '?' */
+		if (*c != 0)
+			*c = '?';
+		else
+			*c = isofn[1];
+	}
+
+	return 2;
+}
+
+/*
+ * translate and compare a filename
+ * Note: Version number plus ';' may be omitted.
+ */
+int
+isofncmp(const u_char *fn, size_t fnlen, const u_char *isofn, size_t isolen,
+    int joliet_level)
+{
+	int i, j;
+	uint16_t fc, ic;
+	const u_char *isoend = isofn + isolen;
+
+#ifdef DEBUG
+	printf("fn = %s, fnlen = %d, isofn = %s, isolen = %d\n",
+	    fn, fnlen, isofn, isolen);
+#endif
+
+	while (fnlen > 0) {
+		fc = wget(&fn, &fnlen, joliet_level);
+
+		if (isofn == isoend)
+			return fc;
+		isofn += isochar(isofn, isoend, joliet_level, &ic);
+		if (ic == ';') {
+			switch (fc) {
+			default:
+				return fc;
+			case 0:
+				return 0;
+			case ';':
+				break;
+			}
+			fn++;
+			for (i = 0; --fnlen >= 0; i = i * 10 + *fn++ - '0') {
+				if (*fn < '0' || *fn > '9') {
+					return -1;
+				}
+			}
+			for (j = 0; isofn != isoend; j = j * 10 + ic - '0')
+				isofn += isochar(isofn, isoend,
+						 joliet_level, &ic);
+			return i - j;
+		}
+		if (ic != fc) {
+			if (ic >= 'A' && ic <= 'Z') {
+				if (ic + ('a' - 'A') != fc) {
+					if (fc >= 'a' && fc <= 'z')
+						fc -= 'a' - 'A';
+
+					return (int)fc - (int)ic;
+				}
+			} else
+				return (int)fc - (int)ic;
+		}
+	}
+	if (isofn != isoend) {
+		isofn += isochar(isofn, isoend, joliet_level, &ic);
+		switch (ic) {
+		default:
+			return -1;
+		case '.':
+			if (isofn != isoend) {
+				isochar(isofn, isoend, joliet_level, &ic);
+				if (ic == ';')
+					return 0;
+			}
+			return -1;
+		case ';':
+			return 0;
+		}
+	}
+	return 0;
+}
+
+/*
+ * translate a filename
+ */
+void
+isofntrans(u_char *infn, int infnlen, u_char *outfn, u_short *outfnlen,
+    int original, int casetrans, int assoc, int joliet_level)
+{
+	int fnidx = 0;
+	u_char *infnend = infn + infnlen;
+	uint16_t c;
+	int sz;
+
+	if (assoc) {
+		*outfn++ = ASSOCCHAR;
+		fnidx++;
+	}
+
+	for(; infn != infnend; fnidx += sz) {
+		infn += isochar(infn, infnend, joliet_level, &c);
+
+		if (casetrans && joliet_level == 0 && c >= 'A' && c <= 'Z')
+			c = c + ('a' - 'A');
+		else if (!original && c == ';') {
+			if (fnidx > 0 && outfn[-1] == '.')
+				fnidx--;
+			break;
+		}
+
+		sz = wput(outfn, MAXNAMLEN - fnidx, c, joliet_level);
+		if (sz == 0) {
+			/* not enough space to write the character */
+			if (fnidx < MAXNAMLEN) {
+				*outfn = '?';
+				fnidx++;
+			}
+			break;
+		}
+		outfn += sz;
+	}
+	*outfnlen = fnidx;
+}
+
+static uint16_t
+wget(const u_char **str, size_t *sz, int joliet_level)
+{
+	if (joliet_level > 0 && cd9660_utf8_joliet) {
+		/* decode UTF-8 sequence */
+		return wget_utf8((const char **) str, sz);
+	} else {
+		/*
+		 * Raw 8-bit characters without any conversion. For Joliet,
+		 * this effectively assumes provided file name is using
+		 * ISO-8859-1 subset.
+		 */
+		uint16_t c = *str[0];
+		(*str)++;
+
+		return c;
+	}
+}
+
+static int
+wput(u_char *s, size_t n, uint16_t c, int joliet_level)
+{
+	if (joliet_level > 0 && cd9660_utf8_joliet) {
+		/* Store Joliet file name encoded into UTF-8 */
+		return wput_utf8((char *)s, n, c);
+	} else {
+		/*
+		 * Store raw 8-bit characters without any conversion.
+		 * For Joliet case, this filters the Unicode characters
+		 * to ISO-8859-1 subset.
+		 */
+		*s = (u_char)c;
+		return 1;
+	}
+}
--- /dev/null	2005-05-16 22:45:24.000000000 +0900
+++ macppc_installboot/installboot.c	2005-05-16 01:53:06.000000000 +0900
@@ -0,0 +1,215 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (C) 2005 Izumi Tsutsui
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "installboot.h"
+
+#define BSIZE		512
+#define MAX_SB_SIZE	(64 * 1024)	/* XXX */
+#define roundup(x, y)	((((x)+((y)-1))/(y))*(y))
+
+static	void usage(void);
+
+static	ib_params	installboot_params;
+
+int
+main(int argc, char **argv)
+{
+	ib_params *params;
+	uint8_t *bb;
+	struct apple_part_map_entry pme;
+	size_t bbi;
+	struct shared_bbinfo *bbinfop;
+	off_t partoff;
+	uint32_t nblk, maxblk, blk_i;
+	int rv;
+	ib_block *blocks;
+
+	setprogname(argv[0]);
+	params = &installboot_params;
+	memset(params, 0, sizeof(*params));
+	params->fsfd = -1;
+	params->s1fd = -1;
+
+	if (argc != 4)
+		usage();
+
+	params->filesystem = argv[1];
+
+	if ((params->fsfd = open(params->filesystem, O_RDWR, 0600)) == -1)
+		err(1, "Opening file system `%s' read", params->filesystem);
+	if (fstat(params->fsfd, &params->fsstat) == -1)
+		err(1, "Examining file system `%s'", params->filesystem);
+#ifdef DEBUG
+	printf("file system: %s, %ld bytes\n",
+	    params->filesystem, (long)params->fsstat.st_size);
+#endif
+
+	/*
+	 * Find space for primary boot from the second (NetBSD_BootBlock)
+	 * partition.
+	 */
+	if (pread(params->fsfd, &pme, sizeof pme, BSIZE * 2) != sizeof(pme))
+		err(1, "read pme from file system `%s'", params->filesystem);
+
+	if (strcmp(pme.pmPartName, "NetBSD_BootBlock"))
+		err(1, "invalid partition map in file system `%s'",
+		    params->filesystem);
+
+	/* pmPyPartStart is written by mkisofs */
+	partoff = BSIZE * be32toh(pme.pmPyPartStart);
+
+#ifdef DEBUG
+	printf("NetBSD partition offset = %ld\n", (long)partoff);
+#endif
+
+	params->stage1 = argv[2];
+
+	if ((params->s1fd = open(params->stage1, O_RDONLY, 0600)) == -1)
+		err(1, "Opening primary bootstrap `%s'", params->stage1);
+	if (fstat(params->s1fd, &params->s1stat) == -1)
+		err(1, "Examining primary bootstrap `%s'", params->stage1);
+	if (!S_ISREG(params->s1stat.st_mode))
+		err(1, "`%s' must be a regular file", params->stage1);
+
+	if (params->s1stat.st_size > MACPPC_BOOT_BLOCK_MAX_SIZE)
+		err(1, "primary bootrap `%s' too large (%ld bytes)",
+		    params->stage1, (long)params->s1stat.st_size);
+
+#ifdef DEBUG
+	printf("primary boot: %s, %ld bytes\n",
+	    params->stage1, (long)params->s1stat.st_size);
+#endif
+
+	params->stage2 = argv[3];
+
+	bb = malloc(MACPPC_BOOT_BLOCK_MAX_SIZE);
+	if (bb == NULL)
+		err(1, "Allocating %ul bytes for bbinfo");
+
+	memset(bb, 0, sizeof(bb));
+	rv = read(params->s1fd, bb, params->s1stat.st_size);
+
+	if (rv == -1)
+		err(1, "Reading `%s'", params->stage1);
+
+	if (memcmp(bb + 1, "ELF", strlen("ELF")) == 0) {
+		warnx("`%s' is an ELF executable; need raw binary",
+		    params->stage1);
+	}
+
+	/* look for the bbinfo structure */
+	for (bbi = 0; bbi < MACPPC_BOOT_BLOCK_MAX_SIZE;
+	    bbi += sizeof(uint32_t)) {
+		bbinfop = (void *)(bb + bbi);
+		if (memcmp(bbinfop->bbi_magic, MACPPC_BBINFO_MAGIC,
+		    sizeof(bbinfop->bbi_magic)) == 0) {
+#ifdef DEBUG
+			printf("magic found: %s\n", bbinfop->bbi_magic);
+#endif
+			break;
+		}
+	}
+	if (bbi >= MACPPC_BOOT_BLOCK_MAX_SIZE)
+		err(1, "bbinfo structure not found in `%s'", params->stage1);
+
+	maxblk = be32toh(bbinfop->bbi_block_count);
+	if (maxblk == 0 ||
+	    maxblk > (MACPPC_BOOT_BLOCK_MAX_SIZE / sizeof(uint32_t)))
+		err(1, "bbinfo structure in `%s' has preposterous size `%u'",
+		    params->stage1, maxblk);
+	
+	blocks = malloc(sizeof(*blocks) * maxblk);
+	if (blocks == NULL) {
+		err(1, "Allocating %lu bytes for blocks",
+		    (unsigned long)sizeof(*blocks) * maxblk);
+	}
+
+	if (S_ISREG(params->fsstat.st_mode)) {
+		if (fsync(params->fsfd) == -1)
+			err(1, "Synchronising file system `%s'",
+			    params->filesystem);
+	}
+
+	nblk = maxblk;
+	if (!cd9660_findstage2(params, &nblk, blocks)) {
+		exit(1);
+	}
+
+	bbinfop->bbi_block_count = htobe32(nblk);
+	bbinfop->bbi_block_size = htobe32(blocks[0].blocksize);
+	for (blk_i = 0; blk_i < nblk; blk_i++) {
+		bbinfop->bbi_block_table[blk_i] = htobe32(blocks[blk_i].block);
+		if (blocks[blk_i].blocksize < blocks[0].blocksize &&
+		    blk_i + 1 != nblk) {
+			warnx("Secondary bootstrap `%s' blocks do not have "
+			    "a uniform size", params->stage2);
+			exit(1);
+		}
+	}
+
+	/* XXX no write option */
+
+	if (pwrite(params->fsfd, bb, MACPPC_BOOT_BLOCK_MAX_SIZE, partoff) !=
+	    MACPPC_BOOT_BLOCK_MAX_SIZE)
+		err(1, "write bootblock");
+
+	if (S_ISREG(params->fsstat.st_mode)) {
+		if (fsync(params->fsfd) == -1)
+			err(1, "Synchronising file system `%s'",
+			    params->filesystem);
+	}
+
+	free(bb);
+
+	if (close(params->fsfd) == -1)
+		err(1, "Closing file system `%s'", params->filesystem);
+	if (close(params->s1fd) == -1)
+		err(1, "Closing primary bootstrap `%s'", params->stage1);
+
+	return 0;
+}
+
+static void
+usage(void)
+{
+	const char *prog;
+
+	prog = getprogname();
+	fprintf(stderr, "usage: %s hybrid-cd-image primary secondary\n", prog);
+	exit(1);
+}
--- /dev/null	2005-05-16 01:55:08.000000000 +0900
+++ macppc_installboot/installboot.h	2005-05-16 01:53:06.000000000 +0900
@@ -0,0 +1,145 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn of Wasabi Systems.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef	_INSTALLBOOT_H
+#define	_INSTALLBOOT_H
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#include "../../sys/sys/bootblock.h"
+#else
+#include <sys/bootblock.h>
+#include <sys/endian.h>
+#endif
+
+#include <sys/stat.h>
+#include <stdint.h>
+
+typedef enum {
+				/* flags from global options */
+	IB_VERBOSE =	1<<0,		/* verbose operation */
+	IB_NOWRITE =	1<<1,		/* don't write */
+	IB_CLEAR =	1<<2,		/* clear boot block */
+
+				/* flags from -o options */
+	IB_ALPHASUM =	1<<8,		/* set Alpha checksum */
+	IB_APPEND =	1<<9,		/* append stage 1 to EO(regular)F */
+	IB_SUNSUM =	1<<10,		/* set Sun checksum */
+	IB_STAGE1START=	1<<11,		/* start block for stage 1 provided */
+	IB_STAGE2START=	1<<12,		/* start block for stage 2 provided */
+	IB_COMMAND = 	1<<13,		/* Amiga commandline option */
+	IB_RESETVIDEO =	1<<14,		/* i386 reset video */
+	IB_CONSOLE =	1<<15,		/* i386 console */
+	IB_CONSPEED =	1<<16,		/* i386 console baud rate */
+	IB_TIMEOUT =	1<<17,		/* i386 boot timeout */
+	IB_PASSWORD =	1<<18,		/* i386 boot password */
+	IB_KEYMAP = 	1<<19,		/* i386 console keymap */
+	IB_CONSADDR = 	1<<20,		/* i386 console io address */
+} ib_flags;
+
+typedef struct {
+	ib_flags	 flags;		/* flags (see above) */
+	struct ib_mach	*machine;	/* machine details (see below) */
+	struct ib_fs	*fstype;	/* file system details (see below) */
+	const char	*filesystem;	/* name of target file system */
+	int		 fsfd;		/*  open fd to filesystem */
+	struct stat	 fsstat;	/*  fstat(2) of fsfd */
+	const char	*stage1;	/* name of stage1 bootstrap */
+	int		 s1fd;		/*  open fd to stage1 */
+	struct stat	 s1stat;	/*  fstat(2) of s1fd */
+	uint64_t	 s1start;	/*  start block of stage1 */
+	const char	*stage2;	/* name of stage2 bootstrap */
+	uint64_t	 s2start;	/*  start block of stage2 */
+		/* parsed -o option=value data */
+	const char	*command;	/* name of command string */
+	const char	*console;	/* name of console */
+	int		 conspeed;	/* console baud rate */
+	int		 consaddr;	/* console io address */
+	const char	*password;	/* boot password */
+	int		 timeout;	/* interactive boot timeout */
+	const char	*keymap;	/* keyboard translations */
+} ib_params;
+
+typedef struct {
+	uint64_t	block;
+	uint32_t	blocksize;
+} ib_block;
+
+struct ib_mach {
+	const char	*name;
+	int		(*setboot)	(ib_params *);
+	int		(*clearboot)	(ib_params *);
+	ib_flags	valid_flags;
+};
+
+struct ib_fs {
+		/* compile time parameters */
+	const char	*name;
+	int		(*match)	(ib_params *);
+	int		(*findstage2)	(ib_params *, uint32_t *, ib_block *);
+		/* run time fs specific parameters */
+	uint32_t	 blocksize;
+	uint32_t	 needswap;
+	off_t		sblockloc;	/* location of superblock */
+};
+
+typedef enum {
+	BBINFO_BIG_ENDIAN =	0,
+	BBINFO_LITTLE_ENDIAN =	1,
+} bbinfo_endian;
+
+struct bbinfo_params {
+	const char	*magic;		/* magic string to look for */
+	uint32_t	offset;		/* offset to write start of stage1 */
+	uint32_t	blocksize;	/* blocksize of stage1 */
+	uint32_t	maxsize;	/* max size of stage1 */
+	uint32_t	headeroffset;	/*
+					 * header offset (relative to offset)
+					 * to read stage1 into
+					 */
+	bbinfo_endian	endian;
+};
+
+int		cd9660_match(ib_params *);
+int		cd9660_findstage2(ib_params *, uint32_t *, ib_block *);
+
+int	isofncmp(const u_char *, size_t, const u_char *, size_t, int);
+void	isofntrans(u_char *, int, u_char *, u_short *, int, int, int, int);
+
+
+#endif	/* _INSTALLBOOT_H */
--- /dev/null	2005-05-16 01:55:08.000000000 +0900
+++ macppc_mkboothfs/Makefile	2005-05-14 23:39:25.000000000 +0900
@@ -0,0 +1,9 @@
+#	$NetBSD$
+
+HOSTPROG=	macppc_mkboothfs
+SRCS=		mkboothfs.c
+NOMAN=		# defined
+
+CLEANFILES+=	boothfs
+
+.include <bsd.hostprog.mk>
--- /dev/null	2005-05-16 01:55:08.000000000 +0900
+++ macppc_mkboothfs/mkboothfs.c	2005-05-15 04:14:22.000000000 +0900
@@ -0,0 +1,152 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (C) 2005 Izumi Tsutsui
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#include "../../sys/sys/bootblock.h"
+#else
+#include <sys/bootblock.h>
+#endif
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define BSIZE		512
+#define BUFSIZE		(8 * 1024)
+
+static void usage(void);
+
+/*
+ * Creates a file for use by mkisofs's -boot-hfs-file.
+ */
+
+int
+main(int argc, char **argv)
+{
+	char *boothfs;
+	int ifd, ofd;
+	struct apple_drvr_map dm;
+	struct apple_part_map_entry pme;
+	char *buf;
+
+	if (argc != 2)
+		usage();
+
+	boothfs = argv[1];
+
+	buf = malloc(BUFSIZE);
+	if (buf == NULL)
+		err(1, "malloc write buffer");
+
+	/* create output boot-hfs-file */
+	if ((ofd = open(boothfs, O_CREAT | O_TRUNC | O_WRONLY, 0644)) == -1)
+		err(1, "create output boot-hfs-file `%s'", boothfs);
+	
+	/*
+	 * Populate 18 byte driver map header in the first 512 byte block
+	 */
+	memset(&dm, 0, sizeof dm);
+	dm.sbSig = htobe16(APPLE_DRVR_MAP_MAGIC);
+	dm.sbBlockSize = htobe16(2048);
+	dm.sbBlkCount = htobe32(333000);	/* XXX */
+	dm.sbDevType = htobe16(1);
+	dm.sbDevID = htobe16(1);
+	dm.sbData = 0;
+	dm.sbDrvrCount = 0;
+
+	memset(buf, 0, BSIZE);
+	memcpy(buf, &dm, sizeof dm);
+	write(ofd, buf, BSIZE);
+
+	/*
+	 * Write 2048-byte/sector map in the second 512 byte block
+	 */
+	memset(&pme, 0, sizeof pme);
+	pme.pmSig = htobe16(APPLE_PART_MAP_ENTRY_MAGIC);
+	pme.pmPartBlkCnt = pme.pmDataCnt = htobe32(1);
+	strcpy(pme.pmPartName, "NetBSD_BootBlock");
+	strcpy(pme.pmPartType, "Apple_Driver");
+	pme.pmPartStatus = htobe32(0x03b);
+	pme.pmBootSize = htobe32(MACPPC_BOOT_BLOCK_MAX_SIZE);
+	pme.pmBootLoad = pme.pmBootEntry = htobe32(0x4000);
+	strcpy(pme.pmProcessor, "PowerPC");
+
+	memset(buf, 0, BSIZE);
+	memcpy(buf, &pme, sizeof pme);
+	write(ofd, buf, BSIZE);
+
+	/*
+	 * Write 512-byte/sector map in the third 512 byte block
+	 */
+	pme.pmPartBlkCnt = pme.pmDataCnt = htobe32(4);
+	memset(buf, 0, BSIZE);
+	memcpy(buf, &pme, sizeof pme);
+	write(ofd, buf, BSIZE);
+
+	/*
+	 * Placeholder for 2048 byte padding
+	 */
+	memset(buf, 0, BSIZE);
+	write(ofd, buf, BSIZE);
+
+	/*
+	 * Placeholder for NetBSD bootblock
+	 */
+	memset(buf, 0, MACPPC_BOOT_BLOCK_MAX_SIZE);
+	write(ofd, buf, MACPPC_BOOT_BLOCK_MAX_SIZE);
+
+	/*
+	 * Prepare HFS "bootblock"; enough to pacify mkisofs.
+	 */
+	memset(buf, 0, BSIZE * 2);
+	buf[0] = 0x4c;
+	buf[1] = 0x4b;
+	if (write(ofd, buf, BSIZE * 2) != BSIZE * 2)
+		err(1, "write boot-hfs-file `%s'", boothfs);
+ 
+	free(buf);
+	close(ofd);
+	return 0;
+}
+
+static void
+usage(void)
+{
+	const char *prog;
+
+	prog = getprogname();
+	fprintf(stderr, "usage: %s boot-hfs-file\n", prog);
+	exit(1);
+}