Index: src/usr.sbin/installboot/Makefile
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/installboot/Makefile,v
retrieving revision 1.10
diff -u -r1.10 Makefile
--- src/usr.sbin/installboot/Makefile	2002/04/11 07:56:13	1.10
+++ src/usr.sbin/installboot/Makefile	2002/04/17 04:02:48
@@ -2,14 +2,15 @@
 #
 
 PROG=	installboot
-SRCS=	installboot.c sum.c machines.c \
-	alpha.c pmax.c sparc64.c vax.c
+SRCS=	installboot.c sum.c machines.c fstypes.c ffs.c ffs_bswap.c \
+	alpha.c pmax.c sparc64.c sun68k.c vax.c
 MAN=	installboot.8
 
 WARNS?=	3
 
-CPPFLAGS+=	-I${.CURDIR}
-.PATH:		${.CURDIR}/arch
+UFSSRC=		${.CURDIR}/../../sys/ufs
+CPPFLAGS+=	-I${.CURDIR} -I${.CURDIR}/../..
+.PATH:		${.CURDIR}/arch ${UFSSRC}/ffs
 
 .ifndef HOSTPROG
 # list of MACHINEs to enable the compat symlink /usr/mdec/installboot
Index: src/usr.sbin/installboot/installboot.8
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/installboot/installboot.8,v
retrieving revision 1.8
diff -u -r1.8 installboot.8
--- src/usr.sbin/installboot/installboot.8	2002/04/12 06:50:41	1.8
+++ src/usr.sbin/installboot/installboot.8	2002/04/17 04:02:48
@@ -171,6 +171,7 @@
 .Sy alpha ,
 .Sy pmax ,
 .Sy sparc64 ,
+.Sy sun2 ,
 .Sy vax
 .Ed
 .
@@ -337,6 +338,7 @@
 back-ends:
 Simon Burge (pmax),
 Chris Demetriou (alpha),
+Matthew Fredette (sun2),
 Matthew Green (sparc64),
 Ross Harvey (alpha),
 and
Index: src/usr.sbin/installboot/installboot.c
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/installboot/installboot.c,v
retrieving revision 1.5
diff -u -r1.5 installboot.c
--- src/usr.sbin/installboot/installboot.c	2002/04/12 06:50:41	1.5
+++ src/usr.sbin/installboot/installboot.c	2002/04/17 04:02:48
@@ -56,6 +56,7 @@
 
 int		main(int, char *[]);
 static	int	getmachine(ib_params *, const char *, const char *);
+static	int	getfstype(ib_params *, const char *, const char *);
 static	void	usage(void);
 
 static	ib_params	installboot_params;
@@ -118,7 +119,8 @@
 			break;
 
 		case 't':
-			params->fstype = optarg;	// XXX: validate?
+			if (! getfstype(params, optarg, "-t"))
+				exit(1);
 			break;
 
 		case 'v':
@@ -146,7 +148,6 @@
 		if (! getmachine(params, utsname.machine, "uname()"))
 			exit(1);
 	}
-	// XXX: set default params->fstype
 
 	params->filesystem = argv[0];
 	if (params->flags & IB_NOWRITE) {
@@ -159,6 +160,19 @@
 	if ((params->fsfd = open(params->filesystem, mode, 0600)) == -1)
 		err(1, "Opening file system `%s' read-%s",
 		    params->filesystem, op);
+	if (params->fstype != NULL) {
+		if (! params->fstype->match(params))
+			err(1, "File system `%s' is not of type %s",
+			    params->filesystem, params->fstype->name);
+	} else {
+		params->fstype = &fstypes[0];
+		while (params->fstype->name != NULL &&
+			! params->fstype->match(params))
+			params->fstype++;
+		if (params->fstype->name == NULL)
+			err(1, "File system `%s' is of an unknown type",
+			    params->filesystem);
+	}
 
 	if (argc >= 2) {
 		params->stage1 = argv[1];
@@ -286,6 +300,34 @@
 			fputs("\n", stderr);
 	}
 	if ((i % MACHS_PER_LINE) != 0)
+		fputs("\n", stderr);
+	return (0);
+}
+
+static int
+getfstype(ib_params *param, const char *fstype, const char *provider)
+{
+	int	i;
+
+	assert(param != NULL);
+	assert(fstype != NULL);
+
+	for (i = 0; fstypes[i].name != NULL; i++) {
+		if (strcmp(fstypes[i].name, fstype) == 0) {
+			param->fstype = &fstypes[i];
+			return (1);
+		}
+	}
+	warnx("Invalid file system type `%s' from %s", fstype, provider);
+	warnx("Supported file system types are:");
+#define FSTYPES_PER_LINE	10
+	for (i = 0; fstypes[i].name != NULL; i++) {
+		fputs((i % FSTYPES_PER_LINE) ? ", " : "\t", stderr);
+		fputs(fstypes[i].name, stderr);
+		if ((i % FSTYPES_PER_LINE) == (FSTYPES_PER_LINE - 1))
+			fputs("\n", stderr);
+	}
+	if ((i % FSTYPES_PER_LINE) != 0)
 		fputs("\n", stderr);
 	return (0);
 }
Index: src/usr.sbin/installboot/installboot.h
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/installboot/installboot.h,v
retrieving revision 1.4
diff -u -r1.4 installboot.h
--- src/usr.sbin/installboot/installboot.h	2002/04/12 06:50:41	1.4
+++ src/usr.sbin/installboot/installboot.h	2002/04/17 04:02:48
@@ -59,7 +59,7 @@
 typedef struct {
 	ib_flags	 flags;
 	struct ib_mach	*machine;
-	const char	*fstype;	// XXX replace with struct *?
+	struct ib_fs	*fstype;
 	const char	*filesystem;
 	int		 fsfd;
 	const char	*stage1;
@@ -68,6 +68,11 @@
 	long		 startblock;
 } ib_params;
 
+typedef struct {
+	long		db;
+	long		blksize;
+} ib_block;
+
 struct ib_mach {
 	const char	*name;
 	int		(*parseopt)	(ib_params *, const char *);
@@ -75,8 +80,15 @@
 	int		(*clearboot)	(ib_params *);
 };
 
+struct ib_fs {
+	const char	*name;
+	int		(*match)	(ib_params *);
+	int		(*findstage2)	(ib_params *, long *, ib_block *);
+};
 
 extern struct ib_mach machines[];
+
+extern struct ib_fs fstypes[];
 
 int		parseoptionflag(ib_params *, const char *, ib_flags);
 u_int16_t	compute_sunsum(const u_int16_t *);
Index: src/usr.sbin/installboot/machines.c
===================================================================
RCS file: /cvsroot/basesrc/usr.sbin/installboot/machines.c,v
retrieving revision 1.5
diff -u -r1.5 machines.c
--- src/usr.sbin/installboot/machines.c	2002/04/11 07:56:13	1.5
+++ src/usr.sbin/installboot/machines.c	2002/04/17 04:02:48
@@ -47,6 +47,8 @@
 int pmax_clearboot(ib_params *);
 int sparc64_setboot(ib_params *);
 int sparc64_clearboot(ib_params *);
+int sun68k_setboot(ib_params *);
+int sun68k_clearboot(ib_params *);
 int vax_parseopt(ib_params *, const char *);
 int vax_setboot(ib_params *);
 int vax_clearboot(ib_params *);
@@ -57,6 +59,7 @@
 	{ "pmax",	pmax_parseopt,	pmax_setboot,	pmax_clearboot },
 	{ "shark",	no_parseopt,	no_setboot,	no_clearboot },
 	{ "sparc64",	no_parseopt,	sparc64_setboot, sparc64_clearboot },
+	{ "sun2",	no_parseopt,	sun68k_setboot,	sun68k_clearboot },
 	{ "vax",	vax_parseopt,	vax_setboot,	vax_clearboot },
 	{ 0, 0, 0, 0 },
 };
--- /dev/null	Tue Mar 12 14:00:23 2002
+++ src/usr.sbin/installboot/fstypes.c	Tue Apr 16 03:46:39 2002
@@ -0,0 +1,48 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Fredette.
+ *
+ * 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.
+ */
+
+#include <sys/types.h>
+#include "installboot.h"
+
+int ffs_match(ib_params *);
+int ffs_findstage2(ib_params *, long *, ib_block *);
+
+struct ib_fs fstypes[] = {
+	{ "ffs", ffs_match, ffs_findstage2 },
+	{ 0, 0, 0 }
+};
--- /dev/null	Tue Mar 12 14:00:23 2002
+++ src/usr.sbin/installboot/ffs.c	Tue Apr 16 17:44:22 2002
@@ -0,0 +1,352 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Fredette.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#if defined(__RCSID) && !defined(__lint)
+__RCSID("$NetBSD$");
+#endif	/* !__lint */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#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 "installboot.h"
+
+#undef DIRBLKSIZ
+
+#include <ufs/ufs/dinode.h>
+#include <ufs/ufs/dir.h>
+#include <ufs/ffs/fs.h>
+#include <ufs/ffs/ffs_extern.h>
+#include <ufs/ufs/ufs_bswap.h>
+
+int ffs_match(ib_params *);
+int ffs_findstage2(ib_params *, long *, ib_block *);
+
+/* This reads a disk block from the filesystem. */
+static int
+ffs_read_disk_block(ib_params *params, int32_t blkno, int size, char *blk)
+{
+	int rv;
+
+	assert(params->filesystem != NULL);
+	assert(params->fsfd != -1);
+	assert(blkno > 0);
+	assert(size > 0);
+	assert(blk != NULL);
+
+	rv = pread(params->fsfd, blk, size, blkno * DEV_BSIZE);
+	if (rv == -1) {
+		warn("Reading block %d in `%s'", blkno, params->filesystem);
+		return (0);
+	} else if (rv != size) {
+		warnx("Reading block %d in `%s': short read", blkno,
+		    params->filesystem);
+		return (0);
+	}
+
+	return (1);
+}
+
+/*
+ * This iterates over the data blocks belonging to an inode,
+ * making a callback each iteration with the disk block number
+ * and the size.
+ */
+static int
+ffs_find_disk_blocks(ib_params *params, u_int32_t ino, 
+	int (*callback)(ib_params *, void *, long, long, int), void *state)
+{
+	char sbbuf[SBSIZE];
+	struct fs *fs;
+	int needswap;
+	char inodebuf[MAXBSIZE];
+	struct dinode *inode;
+#define LEVELS 4
+	struct {
+		ufs_daddr_t *blknums;
+		unsigned long blkcount;
+		char diskbuf[MAXBSIZE];
+	} level[LEVELS];
+	int level_i;
+	ufs_daddr_t blk, lblk, nblk;
+	int rv;
+
+	/* Read the superblock. */
+	if (! ffs_read_disk_block(params, SBLOCK, SBSIZE, sbbuf))
+		return (0);
+	fs = (struct fs *)sbbuf;
+	needswap = 0;
+	if (fs->fs_magic == htole32(FS_MAGIC)) {
+#if BYTE_ORDER == BIG_ENDIAN
+		needswap = 1;
+#endif
+	} else if (fs->fs_magic == htobe32(FS_MAGIC)) {
+#if BYTE_ORDER == LITTLE_ENDIAN
+		needswap = 1;
+#endif
+	} else
+		return (0);
+	if (needswap)
+		ffs_sb_swap(fs, fs);
+
+	/* Sanity check the superblock. */
+	if (fs->fs_magic != FS_MAGIC) {
+		warnx("Bad superblock magic number in `%s'",
+		    params->filesystem);
+		return (0);
+	}
+	if (fs->fs_inopb <= 0) {
+		warnx("Bad inopb %d in superblock in `%s'",
+		    fs->fs_inopb, params->filesystem);
+		return (0);
+	}
+
+	/* Read the inode. */
+	if (! ffs_read_disk_block(params, fsbtodb(fs, ino_to_fsba(fs, ino)),
+		fs->fs_bsize, inodebuf))
+		return (0);
+	inode = (struct dinode *)inodebuf;
+	inode += ino_to_fsbo(fs, ino);
+	if (needswap)
+		ffs_dinode_swap(inode, inode);
+
+	/* Get the block count and initialize for our block walk. */
+	nblk = howmany(inode->di_size, fs->fs_bsize);
+	lblk = 0;
+	level_i = 0;
+	level[0].blknums = &inode->di_db[0];
+	level[0].blkcount = NDADDR;
+	level[1].blknums = &inode->di_ib[0];
+	level[1].blkcount = 1;
+	level[2].blknums = &inode->di_ib[1];
+	level[2].blkcount = 1;
+	level[3].blknums = &inode->di_ib[2];
+	level[3].blkcount = 1;
+
+	/* Walk the data blocks. */
+	while (nblk > 0) {
+
+		/*
+		 * If there are no more blocks at this indirection 
+		 * level, move up one indirection level and loop.
+		 */
+		if (level[level_i].blkcount == 0) {
+			if (++level_i == LEVELS)
+				break;
+			continue;
+		}
+
+		/* Get the next block at this level. */
+		blk = *(level[level_i].blknums++);
+		level[level_i].blkcount--;
+		if (needswap)
+			blk = bswap32(blk);
+
+#if 0
+		fprintf(stderr, "ino %lu blk %lu level %d\n", ino, blk, 
+		    level_i);
+#endif
+
+		/*
+		 * If we're not at the direct level, descend one
+		 * level, read in that level's new block list, 
+		 * and loop.
+		 */
+		if (level_i > 0) {
+			level_i--;
+			if (blk == 0)
+				memset(level[level_i].diskbuf, 0, MAXBSIZE);
+			else if (! ffs_read_disk_block(params, 
+				fsbtodb(fs, blk),
+				fs->fs_bsize, level[level_i].diskbuf))
+				return (0);
+			level[level_i].blknums = 
+				(ufs_daddr_t *)level[level_i].diskbuf;
+			level[level_i].blkcount = NINDIR(fs);
+			continue;
+		}
+
+		/* blk is the next direct level block. */
+#if 0
+		fprintf(stderr, "ino %lu db %lu blksize %lu\n", ino, 
+		    fsbtodb(fs, blk), dblksize(fs, inode, lblk));
+#endif
+		rv = (*callback)(params, state, 
+		    fsbtodb(fs, blk), dblksize(fs, inode, lblk), needswap);
+		lblk++;
+		nblk--;
+		if (rv != 1)
+			return (rv);
+	}
+
+	if (nblk != 0) {
+		warnx("Inode %d in `%s' ran out of blocks?", ino,
+		    params->filesystem);
+		return (0);
+	}
+
+	return (1);
+}
+
+/*
+ * This callback reads a block of the root directory, 
+ * searches for an entry for the secondary bootstrap,
+ * and saves the inode number if one is found.
+ */
+static int
+ffs_findstage2_ino(ib_params *params, void *_ino, 
+	long blk, long blksize, int needswap)
+{
+	char dirbuf[MAXBSIZE];
+	struct direct *de, *ede;
+	u_int32_t ino;
+
+	/* Skip directory holes. */
+	if (blk == 0)
+		return (1);
+
+	/* Read the directory block. */
+	if (! ffs_read_disk_block(params, blk, blksize, dirbuf))
+		return (0);
+
+	/* Loop over the directory entries. */
+	de = (struct direct *)&dirbuf[0];
+	ede = (struct direct *)&dirbuf[blksize];
+	while (de < ede) {
+		ino = de->d_ino;
+		if (needswap) {
+			ino = bswap32(ino);
+			de->d_reclen = bswap16(de->d_reclen);
+		}
+		if (ino != 0 && strcmp(de->d_name, params->stage2) == 0) {
+			*((u_int32_t *)_ino) = ino;
+			return (2);
+		}
+		de = (struct direct *)((char *)de + de->d_reclen);
+	}
+
+	return (1);
+}
+
+struct findblks_state {
+	long maxblk;
+	long nblk;
+	ib_block *blocks;
+};
+
+/* This callback records the blocks of the secondary bootstrap. */
+static int
+ffs_findstage2_blocks(ib_params *params, void *_state,
+	long blk, long blksize, int needswap)
+{
+	struct findblks_state *state = _state;
+
+	if (state->nblk == state->maxblk) {
+		warnx("Secondary bootstrap `%s' has too many blocks " \
+		    "(max %ld)\n", params->stage2, state->maxblk);
+		return (0);
+	}
+	state->blocks[state->nblk].db = blk;
+	state->blocks[state->nblk].blksize = blksize;
+	state->nblk++;
+	return (1);
+}
+
+	/* publically visible functions */
+
+int
+ffs_match(ib_params *params)
+{
+	char sbbuf[SBSIZE];
+	struct fs *fs;
+
+	/* Read and check the superblock. */
+	if (! ffs_read_disk_block(params, SBLOCK, SBSIZE, sbbuf))
+		return (0);
+	fs = (struct fs *)sbbuf;
+	if (fs->fs_magic == htole32(FS_MAGIC) ||
+	    fs->fs_magic == htobe32(FS_MAGIC))
+		return (1);
+
+	return (0);
+}
+
+int
+ffs_findstage2(ib_params *params, long *maxblk, ib_block *blocks)
+{
+	int rv;
+	u_int32_t ino;
+	struct findblks_state state;
+
+	assert (params->stage2 != NULL);
+
+	/* The secondary bootstrap must be clearly in /. */
+	if (params->stage2[0] == '/')
+		params->stage2++;
+	if (strchr(params->stage2, '/') != NULL) {
+		warnx("The secondary bootstrap `%s' must be in /",
+		    params->stage2);
+		return (0);
+	}
+
+	/* Get the inode number of the secondary bootstrap. */
+	rv = ffs_find_disk_blocks(params, ROOTINO, ffs_findstage2_ino, &ino);
+	if (rv != 2)
+		return (0);
+
+	/* Record the disk blocks of the secondary bootstrap. */
+	state.maxblk = *maxblk;
+	state.nblk = 0;
+	state.blocks = blocks;
+	rv = ffs_find_disk_blocks(params, ino, ffs_findstage2_blocks, &state);
+	if (! rv)
+		return (0);
+
+	*maxblk = state.nblk;
+	return (1);
+}
--- /dev/null	Tue Mar 12 14:00:23 2002
+++ src/usr.sbin/installboot/arch/sun68k.c	Tue Apr 16 17:44:02 2002
@@ -0,0 +1,314 @@
+/*	$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.
+ */
+
+/*
+ * Copyright (c) 2002 Matthew R. Green
+ * 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.
+ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Paul Kranenburg.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#if defined(__RCSID) && !defined(__lint)
+__RCSID("$NetBSD$");
+#endif	/* !__lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "installboot.h"
+
+#include <sys/arch/sun68k/stand/libsa/bbinfo.h>
+
+int	sun68k_setboot(ib_params *);
+int	sun68k_clearboot(ib_params *);
+
+#define SUN68K_BOOT_BLOCK_OFFSET	DEV_BSIZE
+#define SUN68K_BOOT_BLOCK_BLOCKSIZE	DEV_BSIZE
+#define SUN68K_BOOT_BLOCK_MAX_SIZE	(DEV_BSIZE * 15)
+
+int
+sun68k_clearboot(ib_params *params)
+{
+	char	bb[SUN68K_BOOT_BLOCK_MAX_SIZE];
+	ssize_t	rv;
+
+	assert(params != NULL);
+	assert(params->fsfd != -1);
+	assert(params->filesystem != NULL);
+
+	if (params->flags & IB_STARTBLOCK) {
+		warnx("Can't use `-b bno' with `-c'");
+		return (0);
+	}
+	/* first check that it _could_ exist here */
+	rv = pread(params->fsfd, &bb, sizeof bb, SUN68K_BOOT_BLOCK_OFFSET);
+	if (rv == -1) {
+		warn("Reading `%s'", params->filesystem);
+		return (0);
+	} else if (rv != sizeof bb) {
+		warnx("Reading `%s': short read", params->filesystem);
+		return (0);
+	}
+
+	/* now clear it out to nothing */
+	memset(&bb, 0, sizeof bb);
+
+	if (params->flags & IB_VERBOSE)
+		printf("%slearing boot block\n",
+		    (params->flags & IB_NOWRITE) ? "Not c" : "C");
+	if (params->flags & IB_NOWRITE)
+		return (1);
+
+	rv = pwrite(params->fsfd, &bb, sizeof(bb), SUN68K_BOOT_BLOCK_OFFSET);
+	if (rv == -1) {
+		warn("Writing `%s'", params->filesystem);
+		return (0);
+	} else if (rv != sizeof(bb)) {
+		warnx("Writing `%s': short write", params->filesystem);
+		return (0);
+	}
+
+	return (1);
+}
+
+int
+sun68k_setboot(ib_params *params)
+{
+	struct stat	bootstrapsb;
+	char		bb[SUN68K_BOOT_BLOCK_MAX_SIZE];
+	int		startblock, retval;
+	ssize_t		rv;
+	size_t		bbi;
+	struct bbinfo	*bbinfop;	/* bbinfo in prototype image */
+	long		maxblk, nblk, blk_i;
+	ib_block	*blocks = NULL;
+
+	assert(params != NULL);
+	assert(params->fsfd != -1);
+	assert(params->filesystem != NULL);
+	assert(params->fstype != NULL);
+	assert(params->s1fd != -1);
+	assert(params->stage1 != NULL);
+
+	if (params->stage2 == NULL) {
+		warnx("You must provide a secondary bootstrap");
+		return (0);
+	}
+
+	retval = 0;
+
+	if (fstat(params->s1fd, &bootstrapsb) == -1) {
+		warn("Examining `%s'", params->stage1);
+		goto done;
+	}
+	if (!S_ISREG(bootstrapsb.st_mode)) {
+		warnx("`%s' must be a regular file", params->stage1);
+		goto done;
+	}
+	if (bootstrapsb.st_size > sizeof bb) {
+		warnx("`%s' cannot be larger than %d bytes",
+		    params->stage1, sizeof bb);
+		goto done;
+	}
+
+	memset(&bb, 0, SUN68K_BOOT_BLOCK_MAX_SIZE);
+	rv = read(params->s1fd, &bb, sizeof bb);
+	if (rv == -1) {
+		warn("Reading `%s'", params->stage1);
+		goto done;
+	}
+
+	/*
+	 * Quick sanity check that the bootstrap given
+	 * is *not* an ELF executable.
+	 */
+	if (memcmp(bb + 1, "ELF", strlen("ELF")) == 0) {
+		warn("`%s' is an ELF executable; need raw binary", 
+		    params->stage1);
+		goto done;
+	}
+
+	/* Look for the bbinfo structure. */
+	for (bbi = 0; bbi < sizeof bb; bbi += sizeof(uint32_t)) {
+		bbinfop = (void *) (bb + bbi);
+		if (memcmp(bbinfop->bbi_magic, BBINFO_MAGIC,
+			    BBINFO_MAGICSIZE) == 0)
+			break;
+	}
+	if (bbi >= sizeof bb) {
+		warn("`%s' does not have a bbinfo structure\n", 
+		    params->stage1);
+		goto done;
+	}
+	maxblk = be32toh(bbinfop->bbi_block_count);
+
+	/* Allocate space for our block list. */
+	blocks = malloc(sizeof(*blocks) * maxblk);
+	if (blocks == NULL) {
+		warn("Allocating %lu bytes", 
+		    (unsigned long) sizeof(*blocks) * maxblk);
+		goto done;
+	}
+
+	/* Collect the blocks for the secondary bootstrap. */
+	nblk = maxblk;
+	if (! params->fstype->findstage2(params, &nblk, blocks))
+		goto done;
+	if (nblk == 0) {
+		warnx("Secondary bootstrap `%s' is empty",
+		   params->stage2);
+		goto done;
+	}
+
+	/* Save those blocks in the primary bootstrap. */
+	bbinfop->bbi_block_count = htobe32(nblk);
+	bbinfop->bbi_block_size = htobe32(blocks[0].blksize);
+	for (blk_i = 0; blk_i < nblk; blk_i++) {
+		bbinfop->bbi_block_table[blk_i] = 
+		    htobe32(blocks[blk_i].db);
+		if (blocks[blk_i].blksize < blocks[0].blksize &&
+		    blk_i + 1 != nblk) {
+			warnx("Secondary bootstrap `%s' blocks do not have " \
+			    "a uniform size\n", params->stage2);
+			goto done;
+		}
+	}
+
+	if (params->flags & IB_STARTBLOCK)
+		startblock = params->startblock;
+	else
+		startblock = SUN68K_BOOT_BLOCK_OFFSET /
+		    SUN68K_BOOT_BLOCK_BLOCKSIZE;
+
+	if (params->flags & IB_VERBOSE) {
+		printf("Bootstrap start sector: %#x\n", startblock);
+		printf("Bootstrap byte count:   %#x\n", (unsigned)rv);
+		printf("Bootstrap block table:  %ld entries avail, %ld used:",
+		    maxblk, nblk);
+		for (blk_i = 0; blk_i < nblk; blk_i++)
+			printf(" %ld", blocks[blk_i].db);
+		printf("\n%sriting bootstrap\n",
+		    (params->flags & IB_NOWRITE) ? "Not w" : "W");
+	}
+	if (params->flags & IB_NOWRITE) {
+		retval = 1;
+		goto done;
+	}
+
+	rv = pwrite(params->fsfd, &bb, SUN68K_BOOT_BLOCK_MAX_SIZE,
+	    startblock * SUN68K_BOOT_BLOCK_BLOCKSIZE);
+	if (rv == -1) {
+		warn("Writing `%s'", params->filesystem);
+		goto done;
+	} else if (rv != SUN68K_BOOT_BLOCK_MAX_SIZE) {
+		warnx("Writing `%s': short write", params->filesystem);
+		goto done;
+	} else
+		retval = 1;
+
+ done:
+	if (blocks != NULL)
+		free (blocks);
+	return (retval);
+}
